diff options
author | David S. Miller <davem@tanya.rutgers.edu> | 1998-01-17 22:39:10 +0000 |
---|---|---|
committer | Jeff Law <law@gcc.gnu.org> | 1998-01-17 15:39:10 -0700 |
commit | c9ec4f99bcd101ef4266f5476498187f270859fa (patch) | |
tree | 1f934b95444c015d58fbf51e1ea0158ab47cbbea /gcc/explow.c | |
parent | ca097615db39da2a40bc790d6e8b7ebb0d620844 (diff) | |
download | gcc-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.c | 133 |
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 |