/* Analyze RTL for GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software
Foundation, Inc.
This file is part of GCC.
/* Similar to reg_set_between_p, but check all registers in X. Return 0
only if none of them are modified between START and END. Return 1 if
- X contains a MEM; this routine does usememory aliasing. */
+ X contains a MEM; this routine does use memory aliasing. */
int
modified_between_p (const_rtx x, const_rtx start, const_rtx end)
if (find_reg_note (insn, REG_EQUAL, NULL_RTX))
return 0;
- /* For now treat an insn with a REG_RETVAL note as a
- a special insn which should not be considered a no-op. */
- if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
- return 0;
-
if (GET_CODE (pat) == SET && set_noop_p (pat))
return 1;
return 0;
}
-/* Return true if INSN is a call to a pure function. */
+\f
+/* Add register note with kind KIND and datum DATUM to INSN. */
-int
-pure_call_p (const_rtx insn)
+void
+add_reg_note (rtx insn, enum reg_note kind, rtx datum)
{
- const_rtx link;
+ rtx note;
- if (!CALL_P (insn) || ! CONST_OR_PURE_CALL_P (insn))
- return 0;
-
- /* Look for the note that differentiates const and pure functions. */
- for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
+ switch (kind)
{
- rtx u, m;
+ case REG_CC_SETTER:
+ case REG_CC_USER:
+ case REG_LABEL_TARGET:
+ case REG_LABEL_OPERAND:
+ /* These types of register notes use an INSN_LIST rather than an
+ EXPR_LIST, so that copying is done right and dumps look
+ better. */
+ note = alloc_INSN_LIST (datum, REG_NOTES (insn));
+ PUT_REG_NOTE_KIND (note, kind);
+ break;
- if (GET_CODE (u = XEXP (link, 0)) == USE
- && MEM_P (m = XEXP (u, 0)) && GET_MODE (m) == BLKmode
- && GET_CODE (XEXP (m, 0)) == SCRATCH)
- return 1;
+ default:
+ note = alloc_EXPR_LIST (kind, datum, REG_NOTES (insn));
+ break;
}
- return 0;
+ REG_NOTES (insn) = note;
}
-\f
+
/* Remove register note NOTE from the REG_NOTES of INSN. */
void
if (GET_CODE (x) == SUBREG)
{
- rtx new = replace_rtx (SUBREG_REG (x), from, to);
+ rtx new_rtx = replace_rtx (SUBREG_REG (x), from, to);
- if (GET_CODE (new) == CONST_INT)
+ if (GET_CODE (new_rtx) == CONST_INT)
{
- x = simplify_subreg (GET_MODE (x), new,
+ x = simplify_subreg (GET_MODE (x), new_rtx,
GET_MODE (SUBREG_REG (x)),
SUBREG_BYTE (x));
gcc_assert (x);
}
else
- SUBREG_REG (x) = new;
+ SUBREG_REG (x) = new_rtx;
return x;
}
else if (GET_CODE (x) == ZERO_EXTEND)
{
- rtx new = replace_rtx (XEXP (x, 0), from, to);
+ rtx new_rtx = replace_rtx (XEXP (x, 0), from, to);
- if (GET_CODE (new) == CONST_INT)
+ if (GET_CODE (new_rtx) == CONST_INT)
{
x = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
- new, GET_MODE (XEXP (x, 0)));
+ new_rtx, GET_MODE (XEXP (x, 0)));
gcc_assert (x);
}
else
- XEXP (x, 0) = new;
+ XEXP (x, 0) = new_rtx;
return x;
}
return info.representable_p;
}
+/* Return the number of a YMODE register to which
+
+ (subreg:YMODE (reg:XMODE XREGNO) OFFSET)
+
+ can be simplified. Return -1 if the subreg can't be simplified.
+
+ XREGNO is a hard register number. */
+
+int
+simplify_subreg_regno (unsigned int xregno, enum machine_mode xmode,
+ unsigned int offset, enum machine_mode ymode)
+{
+ struct subreg_info info;
+ unsigned int yregno;
+
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ /* Give the backend a chance to disallow the mode change. */
+ if (GET_MODE_CLASS (xmode) != MODE_COMPLEX_INT
+ && GET_MODE_CLASS (xmode) != MODE_COMPLEX_FLOAT
+ && REG_CANNOT_CHANGE_MODE_P (xregno, xmode, ymode))
+ return -1;
+#endif
+
+ /* We shouldn't simplify stack-related registers. */
+ if ((!reload_completed || frame_pointer_needed)
+ && (xregno == FRAME_POINTER_REGNUM
+ || xregno == HARD_FRAME_POINTER_REGNUM))
+ return -1;
+
+ if (FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+ && xregno == ARG_POINTER_REGNUM)
+ return -1;
+
+ if (xregno == STACK_POINTER_REGNUM)
+ return -1;
+
+ /* Try to get the register offset. */
+ subreg_get_info (xregno, xmode, offset, ymode, &info);
+ if (!info.representable_p)
+ return -1;
+
+ /* Make sure that the offsetted register value is in range. */
+ yregno = xregno + info.offset;
+ if (!HARD_REGISTER_NUM_P (yregno))
+ return -1;
+
+ /* See whether (reg:YMODE YREGNO) is valid.
+
+ ??? We allow invalid registers if (reg:XMODE XREGNO) is also invalid.
+ This is a kludge to work around how float/complex arguments are passed
+ on 32-bit SPARC and should be fixed. */
+ if (!HARD_REGNO_MODE_OK (yregno, ymode)
+ && HARD_REGNO_MODE_OK (xregno, xmode))
+ return -1;
+
+ return (int) yregno;
+}
+
/* Return the final regno that a subreg expression refers to. */
unsigned int
subreg_regno (const_rtx x)
static void
parms_set (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data)
{
- struct parms_set_data *d = data;
+ struct parms_set_data *const d = (struct parms_set_data *) data;
if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER
&& TEST_HARD_REG_BIT (d->regs, REGNO (x)))
{
if (SET_DEST (set) == stack_pointer_rtx)
{
/* This CONST_CAST is okay because next_nonnote_insn just
- returns it's argument and we assign it to a const_rtx
+ returns its argument and we assign it to a const_rtx
variable. */
const_rtx i2 = next_nonnote_insn (CONST_CAST_RTX(insn));
if (i2 && keep_with_call_p (i2))
/* Return an estimate of the cost of computing rtx X.
One use is in cse, to decide which expression to keep in the hash table.
Another is in rtl generation, to pick the cheapest way to multiply.
- Other uses like the latter are expected in the future. */
+ Other uses like the latter are expected in the future.
+
+ SPEED parameter specify whether costs optimized for speed or size should
+ be returned. */
int
-rtx_cost (rtx x, enum rtx_code outer_code ATTRIBUTE_UNUSED)
+rtx_cost (rtx x, enum rtx_code outer_code ATTRIBUTE_UNUSED, bool speed)
{
int i, j;
enum rtx_code code;
break;
default:
- if (targetm.rtx_costs (x, code, outer_code, &total))
+ if (targetm.rtx_costs (x, code, outer_code, &total, speed))
return total;
break;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
if (fmt[i] == 'e')
- total += rtx_cost (XEXP (x, i), code);
+ total += rtx_cost (XEXP (x, i), code, speed);
else if (fmt[i] == 'E')
for (j = 0; j < XVECLEN (x, i); j++)
- total += rtx_cost (XVECEXP (x, i, j), code);
+ total += rtx_cost (XVECEXP (x, i, j), code, speed);
return total;
}
\f
/* Return cost of address expression X.
- Expect that X is properly formed address reference. */
+ Expect that X is properly formed address reference.
+
+ SPEED parameter specify whether costs optimized for speed or size should
+ be returned. */
int
-address_cost (rtx x, enum machine_mode mode)
+address_cost (rtx x, enum machine_mode mode, bool speed)
{
/* We may be asked for cost of various unusual addresses, such as operands
of push instruction. It is not worthwhile to complicate writing
if (!memory_address_p (mode, x))
return 1000;
- return targetm.address_cost (x);
+ return targetm.address_cost (x, speed);
}
/* If the target doesn't override, compute the cost as with arithmetic. */
int
-default_address_cost (rtx x)
+default_address_cost (rtx x, bool speed)
{
- return rtx_cost (x, MEM);
+ return rtx_cost (x, MEM, speed);
}
\f
enum rtx_code code;
unsigned int mode_width = GET_MODE_BITSIZE (mode);
- /* For floating-point values, assume all bits are needed. */
- if (FLOAT_MODE_P (GET_MODE (x)) || FLOAT_MODE_P (mode))
+ /* For floating-point and vector values, assume all bits are needed. */
+ if (FLOAT_MODE_P (GET_MODE (x)) || FLOAT_MODE_P (mode)
+ || VECTOR_MODE_P (GET_MODE (x)) || VECTOR_MODE_P (mode))
return nonzero;
/* If X is wider than MODE, use its mode instead. */
{
unsigned HOST_WIDE_INT nonzero_for_hook = nonzero;
- rtx new = rtl_hooks.reg_nonzero_bits (x, mode, known_x,
+ rtx new_rtx = rtl_hooks.reg_nonzero_bits (x, mode, known_x,
known_mode, known_ret,
&nonzero_for_hook);
- if (new)
- nonzero_for_hook &= cached_nonzero_bits (new, mode, known_x,
+ if (new_rtx)
+ nonzero_for_hook &= cached_nonzero_bits (new_rtx, mode, known_x,
known_mode, known_ret);
return nonzero_for_hook;
if (mode == VOIDmode)
mode = GET_MODE (x);
- if (mode == VOIDmode || FLOAT_MODE_P (mode) || FLOAT_MODE_P (GET_MODE (x)))
+ if (mode == VOIDmode || FLOAT_MODE_P (mode) || FLOAT_MODE_P (GET_MODE (x))
+ || VECTOR_MODE_P (GET_MODE (x)) || VECTOR_MODE_P (mode))
return 1;
/* For a smaller object, just ignore the high bits. */
{
unsigned int copies_for_hook = 1, copies = 1;
- rtx new = rtl_hooks.reg_num_sign_bit_copies (x, mode, known_x,
+ rtx new_rtx = rtl_hooks.reg_num_sign_bit_copies (x, mode, known_x,
known_mode, known_ret,
&copies_for_hook);
- if (new)
- copies = cached_num_sign_bit_copies (new, mode, known_x,
+ if (new_rtx)
+ copies = cached_num_sign_bit_copies (new_rtx, mode, known_x,
known_mode, known_ret);
if (copies > 1 || copies_for_hook > 1)
zero indicates an instruction pattern without a known cost. */
int
-insn_rtx_cost (rtx pat)
+insn_rtx_cost (rtx pat, bool speed)
{
int i, cost;
rtx set;
else
return 0;
- cost = rtx_cost (SET_SRC (set), SET);
+ cost = rtx_cost (SET_SRC (set), SET, speed);
return cost > 0 ? cost : COSTS_N_INSNS (1);
}