emit_insn (fcn (stack_pointer_rtx, sa));
}
\f
+#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.
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. */
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);
}
#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