/* 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.
int width = GET_MODE_BITSIZE (mode);
/* You want to truncate to a _what_? */
- if (! SCALAR_INT_MODE_P (mode))
- abort ();
+ gcc_assert (SCALAR_INT_MODE_P (mode));
/* Canonicalize BImode to 0 and STORE_FLAG_VALUE. */
if (mode == BImode)
return c;
}
-/* Return an rtx for the sum of X and the integer C.
-
- This function should be used via the `plus_constant' macro. */
+/* Return an rtx for the sum of X and the integer C. */
rtx
-plus_constant_wide (rtx x, HOST_WIDE_INT c)
+plus_constant (rtx x, HOST_WIDE_INT c)
{
RTX_CODE code;
rtx y;
rtx
expr_size (tree exp)
{
- tree size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (lang_hooks.expr_size (exp), exp);
+ tree size;
+
+ if (TREE_CODE (exp) == WITH_SIZE_EXPR)
+ size = TREE_OPERAND (exp, 1);
+ else
+ size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (lang_hooks.expr_size (exp), exp);
return expand_expr (size, NULL_RTX, TYPE_MODE (sizetype), 0);
}
HOST_WIDE_INT
int_expr_size (tree exp)
{
- tree t = lang_hooks.expr_size (exp);
-
- if (t == 0
- || TREE_CODE (t) != INTEGER_CST
- || TREE_OVERFLOW (t)
- || TREE_INT_CST_HIGH (t) != 0
- /* If the result would appear negative, it's too big to represent. */
- || (HOST_WIDE_INT) TREE_INT_CST_LOW (t) < 0)
+ tree size;
+
+ if (TREE_CODE (exp) == WITH_SIZE_EXPR)
+ size = TREE_OPERAND (exp, 1);
+ else
+ size = lang_hooks.expr_size (exp);
+
+ if (size == 0 || !host_integerp (size, 0))
return -1;
- return TREE_INT_CST_LOW (t);
+ return tree_low_cst (size, 0);
}
\f
/* Return a copy of X in which all memory references
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
if (! cse_not_expected && CONSTANT_P (x) && CONSTANT_ADDRESS_P (x))
x = force_reg (Pmode, x);
- /* Accept a QUEUED that refers to a REG
- even though that isn't a valid address.
- On attempting to put this in an insn we will call protect_from_queue
- which will turn it into a REG, which is valid. */
- else if (GET_CODE (x) == QUEUED
- && REG_P (QUEUED_VAR (x)))
- ;
-
/* We get better cse by rejecting indirect addressing at this stage.
Let the combiner create indirect addresses where appropriate.
For now, generate the code so that the subexpressions useful to share
x = break_out_memory_refs (x);
/* At this point, any valid address is accepted. */
- GO_IF_LEGITIMATE_ADDRESS (mode, x, win);
+ if (memory_address_p (mode, x))
+ goto win;
/* If it was valid before but breaking out memory refs invalidated it,
use it the old way. */
return replace_equiv_address (ref, XEXP (ref, 0));
}
\f
-/* Given REF, either a MEM or a REG, and T, either the type of X or
- the expression corresponding to REF, set RTX_UNCHANGING_P if
- appropriate. */
-
-void
-maybe_set_unchanging (rtx ref, tree t)
-{
- /* We can set RTX_UNCHANGING_P from TREE_READONLY for decls whose
- initialization is only executed once, or whose initializer always
- has the same value. Currently we simplify this to PARM_DECLs in the
- first case, and decls with TREE_CONSTANT initializers in the second.
-
- We cannot do this for non-static aggregates, because of the double
- writes that can be generated by store_constructor, depending on the
- contents of the initializer. Yes, this does eliminate a good fraction
- of the number of uses of RTX_UNCHANGING_P for a language like Ada.
- It also eliminates a good quantity of bugs. Let this be incentive to
- eliminate RTX_UNCHANGING_P entirely in favor of a more reliable
- solution, perhaps based on alias sets. */
-
- if ((TREE_READONLY (t) && DECL_P (t)
- && (TREE_STATIC (t) || ! AGGREGATE_TYPE_P (TREE_TYPE (t)))
- && (TREE_CODE (t) == PARM_DECL
- || (DECL_INITIAL (t) && TREE_CONSTANT (DECL_INITIAL (t)))))
- || TREE_CODE_CLASS (TREE_CODE (t)) == 'c')
- RTX_UNCHANGING_P (ref) = 1;
-}
-\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
if (! general_operand (x, VOIDmode))
x = force_operand (x, temp);
- if (GET_MODE (x) != mode && GET_MODE (x) != VOIDmode)
- abort ();
+ gcc_assert (GET_MODE (x) == mode || GET_MODE (x) == VOIDmode);
if (x != temp)
emit_move_insn (temp, x);
return temp;
adjust_stack (rtx adjust)
{
rtx temp;
- adjust = protect_from_queue (adjust, 0);
if (adjust == const0_rtx)
return;
anti_adjust_stack (rtx adjust)
{
rtx temp;
- adjust = protect_from_queue (adjust, 0);
if (adjust == const0_rtx)
return;
/* Round the size of a block to be pushed up to the boundary required
by this machine. SIZE is the desired size, which need not be constant. */
-rtx
+static rtx
round_push (rtx size)
{
int align = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
rtx seq;
start_sequence ();
+ do_pending_stack_adjust ();
/* We must validize inside the sequence, to ensure that any instructions
created by the validize call also get moved to the right place. */
if (sa != 0)
}
else
{
+ do_pending_stack_adjust ();
if (sa != 0)
sa = validize_mem (sa);
emit_insn (fcn (sa, stack_pointer_rtx));
gen_rtx_MEM (BLKmode, stack_pointer_rtx)));
}
+ discard_pending_stack_adjust ();
+
if (after)
{
rtx seq;
first one is used for the frame pointer save; the rest are sized by
STACK_SAVEAREA_MODE. Create a reference to array index 1, the first
of the stack save area slots. */
- t_save = build (ARRAY_REF, ptr_type_node, cfun->nonlocal_goto_save_area,
- integer_one_node, NULL_TREE, NULL_TREE);
+ t_save = build4 (ARRAY_REF, ptr_type_node, cfun->nonlocal_goto_save_area,
+ integer_one_node, NULL_TREE, NULL_TREE);
r_save = expand_expr (t_save, NULL_RTX, VOIDmode, EXPAND_WRITE);
emit_stack_save (SAVE_NONLOCAL, &r_save, NULL_RTX);
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 ();
+ 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. */
if (XEXP (srch, 1) == note)
break;
- if (srch == NULL_RTX)
- abort ();
+ gcc_assert (srch);
XEXP (srch, 1) = XEXP (note, 1);
}
/* ??? Code below assumes that the save area needs maximal
alignment. This constraint may be too strong. */
- if (PREFERRED_STACK_BOUNDARY != BIGGEST_ALIGNMENT)
- abort ();
+ gcc_assert (PREFERRED_STACK_BOUNDARY == BIGGEST_ALIGNMENT);
if (GET_CODE (size) == CONST_INT)
{
/* We ought to be called always on the toplevel and stack ought to be aligned
properly. */
- if (stack_pointer_delta % (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT))
- abort ();
+ gcc_assert (!(stack_pointer_delta
+ % (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT)));
/* If needed, check that we have the required amount of stack. Take into
account what has already been checked. */
1, OPTAB_WIDEN);
#endif
- if (temp != test_addr)
- abort ();
+ gcc_assert (temp == test_addr);
emit_label (test_lab);
emit_cmp_and_jump_insns (test_addr, last_addr, CMP_OPCODE,
}
/* No suitable mode found. */
- if (tmpmode == VOIDmode)
- abort ();
+ gcc_assert (tmpmode != VOIDmode);
PUT_MODE (val, tmpmode);
}