Repost: alloca() optimization when SETJMP_VIA_SAVE_AREA
David S. Miller
davem@jenolan.rutgers.edu
Thu Oct 2 11:35:00 GMT 1997
The REG_NOTE's were already added by Jeffrey Law, if there are any
problems with the way the following is performed then please tell me
so I can work on making it more suitable.
Thu Oct 2 14:28:30 1997 David S. Miller <davem@tanya.rutgers.edu>
* explow.c (optimize_save_area_alloca): New function for targets
where SETJMP_VIA_SAVE_AREA is true.
(allocate_dynamic_stack_space): On SETJMP_VIA_SAVE_AREA targets,
compute the amount of stack space needed should we find later that
setjmp is never called by this function, stuff rtl for this inside
a REG_NOTE of the final SET of stack_pointer_rtx.
* toplev.c (rest_of_compilation): If SETJMP_VIA_SAVE_AREA and
current_function_calls_alloca, call optimize_save_area_alloca.
*** explow.c.~1~ Mon Aug 11 11:57:06 1997
--- explow.c Thu Oct 2 14:28:02 1997
***************
*** 978,983 ****
--- 978,1056 ----
emit_insn (fcn (stack_pointer_rtx, sa));
}
+ #ifdef SETJMP_VIA_SAVE_AREA
+ /* Optimize RTL generated by allocate_dynamic_stack_space for targets
+ where SETJMP_VIA_SAVE_AREA is true. The problem is that on these
+ platforms, the dynamic stack space used can corrupt the original
+ frame, thus causing a crash if a longjmp() unwinds to it. */
+
+ void
+ optimize_save_area_alloca (insns)
+ rtx insns;
+ {
+ rtx insn;
+
+ for (insn = insns; insn; insn = NEXT_INSN(insn))
+ {
+ rtx note;
+
+ if (GET_CODE (insn) != INSN)
+ continue;
+
+ for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
+ {
+ if (REG_NOTE_KIND (note) != REG_SAVE_AREA)
+ continue;
+
+ if (!current_function_calls_setjmp)
+ {
+ rtx pat = PATTERN (insn);
+
+ /* If we do not see the note in a pattern matching
+ these precise characteristics, we did something
+ entirely wrong in allocate_dynamic_stack_space(). */
+ if (GET_CODE (pat) != SET
+ || SET_DEST (pat) != stack_pointer_rtx
+ || GET_CODE (SET_SRC (pat)) != MINUS
+ || XEXP (SET_SRC (pat), 0) != stack_pointer_rtx)
+ abort();
+
+ /* This will now be transformed into a (set REG REG)
+ so we can just blow away all the other notes. */
+ XEXP (SET_SRC (pat), 1) = XEXP (note, 0);
+ REG_NOTES (insn) = NULL_RTX;
+ }
+ else
+ {
+ /* setjmp() was called, we must remove the REG_SAVE_AREA
+ note so that later passes do not get confused by its
+ presence. */
+ if (note == REG_NOTES (insn))
+ {
+ REG_NOTES (insn) = XEXP (note, 1);
+ }
+ else
+ {
+ rtx srch;
+
+ for (srch = REG_NOTES (insn); srch; srch = XEXP (srch, 1))
+ if (XEXP (srch, 1) == note)
+ break;
+
+ if (srch == NULL_RTX)
+ abort();
+
+ XEXP (srch, 1) = XEXP (note, 1);
+ }
+ }
+ /* Once we've seen the note of interest, we need not look at
+ the rest of them. */
+ break;
+ }
+ }
+ }
+ #endif /* SETJMP_VIA_SAVE_AREA */
+
/* Return an rtx representing the address of an area of memory dynamically
pushed on the stack. This region of memory is always aligned to
a multiple of BIGGEST_ALIGNMENT.
***************
*** 995,1000 ****
--- 1068,1077 ----
rtx target;
int known_align;
{
+ #ifdef SETJMP_VIA_SAVE_AREA
+ rtx setjmpless_size = NULL_RTX;
+ #endif
+
/* If we're asking for zero bytes, it doesn't matter what we point
to since we can't dereference it. But return a reasonable
address anyway. */
***************
*** 1048,1053 ****
--- 1125,1169 ----
rtx dynamic_offset
= expand_binop (Pmode, sub_optab, virtual_stack_dynamic_rtx,
stack_pointer_rtx, NULL_RTX, 1, OPTAB_LIB_WIDEN);
+
+ if (!current_function_calls_setjmp)
+ {
+ int align = STACK_BOUNDARY / BITS_PER_UNIT;
+
+ /* See optimize_save_area_alloca() to understand what is being
+ set up here. */
+
+ #if !defined(STACK_BOUNDARY) || !defined(MUST_ALIGN) || (STACK_BOUNDARY != BIGGEST_ALIGNMENT)
+ /* If anyone creates a target with these characteristics, let them
+ know that our optimization cannot work correctly in such a case. */
+ abort();
+ #endif
+
+ if (GET_CODE (size) == CONST_INT)
+ {
+ int new = INTVAL (size) / align * align;
+
+ if (INTVAL (size) != new)
+ setjmpless_size = GEN_INT (new);
+ else
+ setjmpless_size = size;
+ }
+ else
+ {
+ /* Since we know overflow is not possible, we avoid using
+ CEIL_DIV_EXPR and use TRUNC_DIV_EXPR instead. */
+ setjmpless_size = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, size,
+ GEN_INT (align), NULL_RTX, 1);
+ setjmpless_size = expand_mult (Pmode, setjmpless_size,
+ GEN_INT (align), NULL_RTX, 1);
+ }
+ /* Our optimization works based upon being able to perform a simple
+ transformation of this RTL into a (set REG REG) so make sure things
+ did in fact end up in a REG. */
+ if (!arith_operand (setjmpless_size, Pmode))
+ setjmpless_size = force_reg (Pmode, setjmpless_size);
+ }
+
size = expand_binop (Pmode, add_optab, size, dynamic_offset,
NULL_RTX, 1, OPTAB_LIB_WIDEN);
}
***************
*** 1117,1122 ****
--- 1233,1247 ----
{
size = convert_modes (Pmode, ptr_mode, size, 1);
anti_adjust_stack (size);
+ #ifdef SETJMP_VIA_SAVE_AREA
+ if (setjmpless_size != NULL_RTX)
+ {
+ rtx note_target = get_last_insn ();
+
+ REG_NOTES (note_target) = gen_rtx (EXPR_LIST, REG_SAVE_AREA,
+ setjmpless_size, REG_NOTES (note_target));
+ }
+ #endif /* SETJMP_VIA_SAVE_AREA */
}
#ifdef STACK_GROWS_DOWNWARD
*** toplev.c.~1~ Mon Sep 15 22:07:28 1997
--- toplev.c Thu Oct 2 14:28:24 1997
***************
*** 3152,3157 ****
--- 3152,3163 ----
unshare_all_rtl (insns);
+ #ifdef SETJMP_VIA_SAVE_AREA
+ /* This must be performed before virutal register instantiation. */
+ if (current_function_calls_alloca)
+ optimize_save_area_alloca (insns);
+ #endif
+
/* Instantiate all virtual registers. */
instantiate_virtual_regs (current_function_decl, get_insns ());
More information about the Gcc
mailing list