aboutsummaryrefslogtreecommitdiff
path: root/gcc/explow.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@tanya.rutgers.edu>1998-01-17 22:39:10 +0000
committerJeff Law <law@gcc.gnu.org>1998-01-17 15:39:10 -0700
commitc9ec4f99bcd101ef4266f5476498187f270859fa (patch)
tree1f934b95444c015d58fbf51e1ea0158ab47cbbea /gcc/explow.c
parentca097615db39da2a40bc790d6e8b7ebb0d620844 (diff)
downloadgcc-c9ec4f99bcd101ef4266f5476498187f270859fa.zip
gcc-c9ec4f99bcd101ef4266f5476498187f270859fa.tar.gz
gcc-c9ec4f99bcd101ef4266f5476498187f270859fa.tar.bz2
explow.c (optimize_save_area_alloca): New function for targets where SETJMP_VIA_SAVE_AREA is true.
* 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. CVS ---------------------------------------------------------------------- From-SVN: r17402
Diffstat (limited to 'gcc/explow.c')
-rw-r--r--gcc/explow.c133
1 files changed, 133 insertions, 0 deletions
diff --git a/gcc/explow.c b/gcc/explow.c
index e38c1e4..0fcc547 100644
--- a/gcc/explow.c
+++ b/gcc/explow.c
@@ -1004,6 +1004,86 @@ emit_stack_restore (save_level, sa, after)
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.
+
+ Note, one way this could happen if if SETJMP_VIA_SAVE_AREA
+ was defined on a machine where stacks grow towards higher
+ addresses.
+
+ Right now only supported port with stack that grow upward
+ is the HPPA and it does not define SETJMP_VIA_SAVE_AREA. */
+ 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.
@@ -1021,6 +1101,10 @@ allocate_dynamic_stack_space (size, target, known_align)
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. */
@@ -1074,6 +1158,45 @@ allocate_dynamic_stack_space (size, target, known_align)
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);
}
@@ -1145,6 +1268,16 @@ allocate_dynamic_stack_space (size, target, known_align)
#endif
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
emit_move_insn (target, virtual_stack_dynamic_rtx);
#endif