/* Subroutines for manipulating rtx's in semantically interesting ways.
Copyright (C) 1987, 1991, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GCC.
rtx x)
{
#ifndef POINTERS_EXTEND_UNSIGNED
+ gcc_assert (GET_MODE (x) == to_mode || GET_MODE (x) == VOIDmode);
return x;
#else /* defined(POINTERS_EXTEND_UNSIGNED) */
enum machine_mode from_mode;
x, POINTERS_EXTEND_UNSIGNED);
#endif /* defined(POINTERS_EXTEND_UNSIGNED) */
}
-
-/* Given a memory address or facsimile X, construct a new address,
- currently equivalent, that is stable: future stores won't change it.
-
- X must be composed of constants, register and memory references
- combined with addition, subtraction and multiplication:
- in other words, just what you can get from expand_expr if sum_ok is 1.
-
- Works by making copies of all regs and memory locations used
- by X and combining them the same way X does.
- You could also stabilize the reference to this address
- by copying the address to a register with copy_to_reg;
- but then you wouldn't get indexed addressing in the reference. */
-
-rtx
-copy_all_regs (rtx x)
-{
- if (REG_P (x))
- {
- if (REGNO (x) != FRAME_POINTER_REGNUM
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
- && REGNO (x) != HARD_FRAME_POINTER_REGNUM
-#endif
- )
- x = copy_to_reg (x);
- }
- else if (MEM_P (x))
- x = copy_to_reg (x);
- else if (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
- || GET_CODE (x) == MULT)
- {
- rtx op0 = copy_all_regs (XEXP (x, 0));
- rtx op1 = copy_all_regs (XEXP (x, 1));
- if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
- x = gen_rtx_fmt_ee (GET_CODE (x), Pmode, op0, op1);
- }
- return x;
-}
\f
/* Return something equivalent to X but valid as a memory address
for something of mode MODE. When X is not itself valid, this
return replace_equiv_address (ref, XEXP (ref, 0));
}
\f
-/* Return a modified copy of X with its memory address copied
- into a temporary register to protect it from side effects.
- If X is not a MEM, it is returned unchanged (and not copied).
- Perhaps even if it is a MEM, if there is no need to change it. */
-
-rtx
-stabilize (rtx x)
-{
- if (!MEM_P (x)
- || ! rtx_unstable_p (XEXP (x, 0)))
- return x;
-
- return
- replace_equiv_address (x, force_reg (Pmode, copy_all_regs (XEXP (x, 0))));
-}
-\f
/* Copy the value or contents of X to a new temp reg and return that reg. */
rtx
emit_stack_save (SAVE_NONLOCAL, &r_save, NULL_RTX);
}
\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 (void)
-{
- rtx insn;
-
- for (insn = get_insns (); insn; insn = NEXT_INSN(insn))
- {
- rtx note;
-
- if (!NONJUMP_INSN_P (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 is 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. */
- gcc_assert (GET_CODE (pat) == SET
- && SET_DEST (pat) == stack_pointer_rtx
- && GET_CODE (SET_SRC (pat)) == MINUS
- && XEXP (SET_SRC (pat), 0) == stack_pointer_rtx);
-
- /* 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;
-
- gcc_assert (srch);
-
- 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
allocate_dynamic_stack_space (rtx size, 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. */
avoid clobbering the reg save area. Note that the offset of
virtual_incoming_args_rtx includes the preallocated stack args space.
It would be no problem to clobber that, but it's on the wrong side
- of the old save area. */
- {
- rtx dynamic_offset
- = expand_binop (Pmode, sub_optab, virtual_stack_dynamic_rtx,
- stack_pointer_rtx, NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ of the old save area.
+
+ What used to happen is that, since we did not know for sure
+ whether setjmp() was invoked until after RTL generation, we
+ would use reg notes to store the "optimized" size and fix things
+ up later. These days we know this information before we ever
+ start building RTL so the reg notes are unnecessary. */
+ if (!current_function_calls_setjmp)
+ {
+ int align = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
- if (!current_function_calls_setjmp)
- {
- int align = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
-
- /* See optimize_save_area_alloca to understand what is being
- set up here. */
-
- /* ??? Code below assumes that the save area needs maximal
- alignment. This constraint may be too strong. */
- gcc_assert (PREFERRED_STACK_BOUNDARY == BIGGEST_ALIGNMENT);
-
- if (GET_CODE (size) == CONST_INT)
- {
- HOST_WIDE_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 (!register_operand (setjmpless_size, Pmode))
- setjmpless_size = force_reg (Pmode, setjmpless_size);
- }
+ /* ??? Code below assumes that the save area needs maximal
+ alignment. This constraint may be too strong. */
+ gcc_assert (PREFERRED_STACK_BOUNDARY == BIGGEST_ALIGNMENT);
- size = expand_binop (Pmode, add_optab, size, dynamic_offset,
- NULL_RTX, 1, OPTAB_LIB_WIDEN);
- }
+ if (GET_CODE (size) == CONST_INT)
+ {
+ HOST_WIDE_INT new = INTVAL (size) / align * align;
+
+ if (INTVAL (size) != new)
+ size = GEN_INT (new);
+ }
+ else
+ {
+ /* Since we know overflow is not possible, we avoid using
+ CEIL_DIV_EXPR and use TRUNC_DIV_EXPR instead. */
+ size = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, size,
+ GEN_INT (align), NULL_RTX, 1);
+ size = expand_mult (Pmode, size,
+ GEN_INT (align), NULL_RTX, 1);
+ }
+ }
+ else
+ {
+ rtx dynamic_offset
+ = expand_binop (Pmode, sub_optab, virtual_stack_dynamic_rtx,
+ stack_pointer_rtx, NULL_RTX, 1, OPTAB_LIB_WIDEN);
+
+ size = expand_binop (Pmode, add_optab, size, dynamic_offset,
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ }
#endif /* SETJMP_VIA_SAVE_AREA */
/* Round the size to a multiple of the required stack alignment.
}
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);
enum machine_mode tmpmode;
/* int_size_in_bytes can return -1. We don't need a check here
- since the value of bytes will be large enough that no mode
- will match and we will abort later in this function. */
+ since the value of bytes will then be large enough that no
+ mode will match anyway. */
for (tmpmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
tmpmode != VOIDmode;