/* Emit RTL for the GCC expander.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of GCC.
/* Datastructures maintained for currently processed function in RTL form. */
-struct rtl_data rtl;
+struct rtl_data x_rtl;
/* Indexed by pseudo register number, gives the rtx for that pseudo.
Allocated in parallel with regno_pointer_align.
static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
htab_t const_fixed_htab;
-#define first_insn (rtl.emit.x_first_insn)
-#define last_insn (rtl.emit.x_last_insn)
-#define cur_insn_uid (rtl.emit.x_cur_insn_uid)
-#define last_location (rtl.emit.x_last_location)
-#define first_label_num (rtl.emit.x_first_label_num)
+#define first_insn (crtl->emit.x_first_insn)
+#define last_insn (crtl->emit.x_last_insn)
+#define cur_insn_uid (crtl->emit.x_cur_insn_uid)
+#define last_location (crtl->emit.x_last_location)
+#define first_label_num (crtl->emit.x_first_label_num)
static rtx make_call_insn_raw (rtx);
static rtx change_address_1 (rtx, enum machine_mode, rtx, int);
memcpy (*slot, &attrs, sizeof (mem_attrs));
}
- return *slot;
+ return (mem_attrs *) *slot;
}
/* Returns a hash code for X (which is a really a reg_attrs *). */
memcpy (*slot, &attrs, sizeof (reg_attrs));
}
- return *slot;
+ return (reg_attrs *) *slot;
}
{
rtx mem = gen_rtx_MEM (mode, addr);
MEM_NOTRAP_P (mem) = 1;
- if (!current_function_calls_alloca)
+ if (!cfun->calls_alloca)
set_mem_alias_set (mem, get_frame_alias_set ());
return mem;
}
subreg_lowpart_offset (mode, inmode));
}
\f
-/* gen_rtvec (n, [rt1, ..., rtn])
-**
-** This routine creates an rtvec and stores within it the
-** pointers to rtx's which are its arguments.
-*/
-/*VARARGS1*/
+/* Create an rtvec and stores within it the RTXen passed in the arguments. */
+
rtvec
gen_rtvec (int n, ...)
{
- int i, save_n;
- rtx *vector;
+ int i;
+ rtvec rt_val;
va_list p;
va_start (p, n);
+ /* Don't allocate an empty rtvec... */
if (n == 0)
- return NULL_RTVEC; /* Don't allocate an empty rtvec... */
+ return NULL_RTVEC;
- vector = alloca (n * sizeof (rtx));
+ rt_val = rtvec_alloc (n);
for (i = 0; i < n; i++)
- vector[i] = va_arg (p, rtx);
+ rt_val->elem[i] = va_arg (p, rtx);
- /* The definition of VA_* in K&R C causes `n' to go out of scope. */
- save_n = n;
va_end (p);
-
- return gen_rtvec_v (save_n, vector);
+ return rt_val;
}
rtvec
int i;
rtvec rt_val;
+ /* Don't allocate an empty rtvec... */
if (n == 0)
- return NULL_RTVEC; /* Don't allocate an empty rtvec... */
+ return NULL_RTVEC;
- rt_val = rtvec_alloc (n); /* Allocate an rtvec... */
+ rt_val = rtvec_alloc (n);
for (i = 0; i < n; i++)
rt_val->elem[i] = *argp++;
gen_reg_rtx (enum machine_mode mode)
{
rtx val;
+ unsigned int align = GET_MODE_ALIGNMENT (mode);
gcc_assert (can_create_pseudo_p ());
+ /* If a virtual register with bigger mode alignment is generated,
+ increase stack alignment estimation because it might be spilled
+ to stack later. */
+ if (SUPPORTS_STACK_ALIGNMENT
+ && crtl->stack_alignment_estimated < align
+ && !crtl->stack_realign_processed)
+ crtl->stack_alignment_estimated = align;
+
if (generating_concat_p
&& (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
|| GET_MODE_CLASS (mode) == MODE_COMPLEX_INT))
/* Make sure regno_pointer_align, and regno_reg_rtx are large
enough to have an element for this pseudo reg number. */
- if (reg_rtx_no == rtl.emit.regno_pointer_align_length)
+ if (reg_rtx_no == crtl->emit.regno_pointer_align_length)
{
- int old_size = rtl.emit.regno_pointer_align_length;
- char *new;
+ int old_size = crtl->emit.regno_pointer_align_length;
+ char *tmp;
rtx *new1;
- new = xrealloc (rtl.emit.regno_pointer_align, old_size * 2);
- memset (new + old_size, 0, old_size);
- rtl.emit.regno_pointer_align = (unsigned char *) new;
+ tmp = XRESIZEVEC (char, crtl->emit.regno_pointer_align, old_size * 2);
+ memset (tmp + old_size, 0, old_size);
+ crtl->emit.regno_pointer_align = (unsigned char *) tmp;
- new1 = ggc_realloc (regno_reg_rtx,
- old_size * 2 * sizeof (rtx));
+ new1 = GGC_RESIZEVEC (rtx, regno_reg_rtx, old_size * 2);
memset (new1 + old_size, 0, old_size * sizeof (rtx));
regno_reg_rtx = new1;
- rtl.emit.regno_pointer_align_length = old_size * 2;
+ crtl->emit.regno_pointer_align_length = old_size * 2;
}
val = gen_raw_REG (mode, reg_rtx_no);
to the REG_OFFSET. */
static void
-update_reg_offset (rtx new, rtx reg, int offset)
+update_reg_offset (rtx new_rtx, rtx reg, int offset)
{
- REG_ATTRS (new) = get_reg_attrs (REG_EXPR (reg),
+ REG_ATTRS (new_rtx) = get_reg_attrs (REG_EXPR (reg),
REG_OFFSET (reg) + offset);
}
gen_rtx_REG_offset (rtx reg, enum machine_mode mode, unsigned int regno,
int offset)
{
- rtx new = gen_rtx_REG (mode, regno);
+ rtx new_rtx = gen_rtx_REG (mode, regno);
- update_reg_offset (new, reg, offset);
- return new;
+ update_reg_offset (new_rtx, reg, offset);
+ return new_rtx;
}
/* Generate a new pseudo-register with the same attributes as REG, but
rtx
gen_reg_rtx_offset (rtx reg, enum machine_mode mode, int offset)
{
- rtx new = gen_reg_rtx (mode);
+ rtx new_rtx = gen_reg_rtx (mode);
- update_reg_offset (new, reg, offset);
- return new;
+ update_reg_offset (new_rtx, reg, offset);
+ return new_rtx;
}
/* Adjust REG in-place so that it has mode MODE. It is assumed that the
{
int offset;
+ /* Hard registers can be reused for multiple purposes within the same
+ function, so setting REG_ATTRS, REG_POINTER and REG_POINTER_ALIGN
+ on them is wrong. */
+ if (HARD_REGISTER_P (reg))
+ return;
+
offset = byte_lowpart_offset (GET_MODE (reg), GET_MODE (x));
- if (MEM_P (x) && MEM_OFFSET (x) && GET_CODE (MEM_OFFSET (x)) == CONST_INT)
- REG_ATTRS (reg)
- = get_reg_attrs (MEM_EXPR (x), INTVAL (MEM_OFFSET (x)) + offset);
- if (REG_P (x) && REG_ATTRS (x))
- update_reg_offset (reg, x, offset);
+ if (MEM_P (x))
+ {
+ if (MEM_OFFSET (x) && GET_CODE (MEM_OFFSET (x)) == CONST_INT)
+ REG_ATTRS (reg)
+ = get_reg_attrs (MEM_EXPR (x), INTVAL (MEM_OFFSET (x)) + offset);
+ if (MEM_POINTER (x))
+ mark_reg_pointer (reg, 0);
+ }
+ else if (REG_P (x))
+ {
+ if (REG_ATTRS (x))
+ update_reg_offset (reg, x, offset);
+ if (REG_POINTER (x))
+ mark_reg_pointer (reg, REGNO_POINTER_ALIGN (REGNO (x)));
+ }
+}
+
+/* Generate a REG rtx for a new pseudo register, copying the mode
+ and attributes from X. */
+
+rtx
+gen_reg_rtx_and_attrs (rtx x)
+{
+ rtx reg = gen_reg_rtx (GET_MODE (x));
+ set_reg_attrs_from_value (reg, x);
+ return reg;
}
/* Set the register attributes for registers contained in PARM_RTX.
/* If the rtx for label was created during the expansion of a nested
function, then first_label_num won't include this label number.
- Fix this now so that array indicies work later. */
+ Fix this now so that array indices work later. */
void
maybe_set_first_label_num (rtx x)
/* Form a new MEM at the requested address. */
if (MEM_P (op))
{
- rtx new = adjust_address_nv (op, word_mode, offset * UNITS_PER_WORD);
+ rtx new_rtx = adjust_address_nv (op, word_mode, offset * UNITS_PER_WORD);
if (! validate_address)
- return new;
+ return new_rtx;
else if (reload_completed)
{
- if (! strict_memory_address_p (word_mode, XEXP (new, 0)))
+ if (! strict_memory_address_p (word_mode, XEXP (new_rtx, 0)))
return 0;
}
else
- return replace_equiv_address (new, XEXP (new, 0));
+ return replace_equiv_address (new_rtx, XEXP (new_rtx, 0));
}
/* Rest can be handled by simplify_subreg. */
{
/* Now remove any conversions: they don't change what the underlying
object is. Likewise for SAVE_EXPR. */
- while (TREE_CODE (inner) == NOP_EXPR || TREE_CODE (inner) == CONVERT_EXPR
- || TREE_CODE (inner) == NON_LVALUE_EXPR
+ while (CONVERT_EXPR_P (inner)
|| TREE_CODE (inner) == VIEW_CONVERT_EXPR
|| TREE_CODE (inner) == SAVE_EXPR)
inner = TREE_OPERAND (inner, 0);
return 0;
}
-/* Given REF, a MEM, and T, either the type of X or the expression
+/* Return OFFSET if XEXP (MEM, 0) - OFFSET is known to be ALIGN
+ bits aligned for 0 <= OFFSET < ALIGN / BITS_PER_UNIT, or
+ -1 if not known. */
+
+int
+get_mem_align_offset (rtx mem, unsigned int align)
+{
+ tree expr;
+ unsigned HOST_WIDE_INT offset;
+
+ /* This function can't use
+ if (!MEM_EXPR (mem) || !MEM_OFFSET (mem)
+ || !CONST_INT_P (MEM_OFFSET (mem))
+ || (get_object_alignment (MEM_EXPR (mem), MEM_ALIGN (mem), align)
+ < align))
+ return -1;
+ else
+ return (- INTVAL (MEM_OFFSET (mem))) & (align / BITS_PER_UNIT - 1);
+ for two reasons:
+ - COMPONENT_REFs in MEM_EXPR can have NULL first operand,
+ for <variable>. get_inner_reference doesn't handle it and
+ even if it did, the alignment in that case needs to be determined
+ from DECL_FIELD_CONTEXT's TYPE_ALIGN.
+ - it would do suboptimal job for COMPONENT_REFs, even if MEM_EXPR
+ isn't sufficiently aligned, the object it is in might be. */
+ gcc_assert (MEM_P (mem));
+ expr = MEM_EXPR (mem);
+ if (expr == NULL_TREE
+ || MEM_OFFSET (mem) == NULL_RTX
+ || !CONST_INT_P (MEM_OFFSET (mem)))
+ return -1;
+
+ offset = INTVAL (MEM_OFFSET (mem));
+ if (DECL_P (expr))
+ {
+ if (DECL_ALIGN (expr) < align)
+ return -1;
+ }
+ else if (INDIRECT_REF_P (expr))
+ {
+ if (TYPE_ALIGN (TREE_TYPE (expr)) < (unsigned int) align)
+ return -1;
+ }
+ else if (TREE_CODE (expr) == COMPONENT_REF)
+ {
+ while (1)
+ {
+ tree inner = TREE_OPERAND (expr, 0);
+ tree field = TREE_OPERAND (expr, 1);
+ tree byte_offset = component_ref_field_offset (expr);
+ tree bit_offset = DECL_FIELD_BIT_OFFSET (field);
+
+ if (!byte_offset
+ || !host_integerp (byte_offset, 1)
+ || !host_integerp (bit_offset, 1))
+ return -1;
+
+ offset += tree_low_cst (byte_offset, 1);
+ offset += tree_low_cst (bit_offset, 1) / BITS_PER_UNIT;
+
+ if (inner == NULL_TREE)
+ {
+ if (TYPE_ALIGN (DECL_FIELD_CONTEXT (field))
+ < (unsigned int) align)
+ return -1;
+ break;
+ }
+ else if (DECL_P (inner))
+ {
+ if (DECL_ALIGN (inner) < align)
+ return -1;
+ break;
+ }
+ else if (TREE_CODE (inner) != COMPONENT_REF)
+ return -1;
+ expr = inner;
+ }
+ }
+ else
+ return -1;
+
+ return offset & ((align / BITS_PER_UNIT) - 1);
+}
+
+/* Given REF (a MEM) and T, either the type of X or the expression
corresponding to REF, set the memory attributes. OBJECTP is nonzero
if we are making a new object of this type. BITPOS is nonzero if
there is an offset outstanding on T that will be applied later. */
if (! TYPE_P (t))
{
tree base;
+ bool align_computed = false;
if (TREE_THIS_VOLATILE (t))
MEM_VOLATILE_P (ref) = 1;
/* Now remove any conversions: they don't change what the underlying
object is. Likewise for SAVE_EXPR. */
- while (TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR
- || TREE_CODE (t) == NON_LVALUE_EXPR
+ while (CONVERT_EXPR_P (t)
|| TREE_CODE (t) == VIEW_CONVERT_EXPR
|| TREE_CODE (t) == SAVE_EXPR)
t = TREE_OPERAND (t, 0);
&& host_integerp (DECL_SIZE_UNIT (t), 1)
? GEN_INT (tree_low_cst (DECL_SIZE_UNIT (t), 1)) : 0);
align = DECL_ALIGN (t);
+ align_computed = true;
}
/* If this is a constant, we know the alignment. */
#ifdef CONSTANT_ALIGNMENT
align = CONSTANT_ALIGNMENT (t, align);
#endif
+ align_computed = true;
}
/* If this is a field reference and not a bit-field, record it. */
- /* ??? There is some information that can be gleened from bit-fields,
+ /* ??? There is some information that can be gleaned from bit-fields,
such as the word offset in the structure that might be modified.
But skip it for now. */
else if (TREE_CODE (t) == COMPONENT_REF
align = DECL_ALIGN (t2);
if (aoff && (unsigned HOST_WIDE_INT) aoff < align)
align = aoff;
+ align_computed = true;
offset = GEN_INT (ioff);
apply_bitpos = bitpos;
}
expr = t;
offset = NULL;
}
+
+ if (!align_computed && !INDIRECT_REF_P (t))
+ {
+ unsigned int obj_align
+ = get_object_alignment (t, align, BIGGEST_ALIGNMENT);
+ align = MAX (align, obj_align);
+ }
}
/* If we modified OFFSET based on T, then subtract the outstanding
if (TREE_CODE (t) == ALIGN_INDIRECT_REF)
{
- /* Force EXPR and OFFSE to NULL, since we don't know exactly what
+ /* Force EXPR and OFFSET to NULL, since we don't know exactly what
we're overlapping. */
offset = NULL;
expr = NULL;
static rtx
change_address_1 (rtx memref, enum machine_mode mode, rtx addr, int validate)
{
- rtx new;
+ rtx new_rtx;
gcc_assert (MEM_P (memref));
if (mode == VOIDmode)
if (rtx_equal_p (addr, XEXP (memref, 0)) && mode == GET_MODE (memref))
return memref;
- new = gen_rtx_MEM (mode, addr);
- MEM_COPY_ATTRIBUTES (new, memref);
- return new;
+ new_rtx = gen_rtx_MEM (mode, addr);
+ MEM_COPY_ATTRIBUTES (new_rtx, memref);
+ return new_rtx;
}
/* Like change_address_1 with VALIDATE nonzero, but we are not saying in what
rtx
change_address (rtx memref, enum machine_mode mode, rtx addr)
{
- rtx new = change_address_1 (memref, mode, addr, 1), size;
- enum machine_mode mmode = GET_MODE (new);
+ rtx new_rtx = change_address_1 (memref, mode, addr, 1), size;
+ enum machine_mode mmode = GET_MODE (new_rtx);
unsigned int align;
size = mmode == BLKmode ? 0 : GEN_INT (GET_MODE_SIZE (mmode));
align = mmode == BLKmode ? BITS_PER_UNIT : GET_MODE_ALIGNMENT (mmode);
/* If there are no changes, just return the original memory reference. */
- if (new == memref)
+ if (new_rtx == memref)
{
if (MEM_ATTRS (memref) == 0
|| (MEM_EXPR (memref) == NULL
&& MEM_OFFSET (memref) == NULL
&& MEM_SIZE (memref) == size
&& MEM_ALIGN (memref) == align))
- return new;
+ return new_rtx;
- new = gen_rtx_MEM (mmode, XEXP (memref, 0));
- MEM_COPY_ATTRIBUTES (new, memref);
+ new_rtx = gen_rtx_MEM (mmode, XEXP (memref, 0));
+ MEM_COPY_ATTRIBUTES (new_rtx, memref);
}
- MEM_ATTRS (new)
+ MEM_ATTRS (new_rtx)
= get_mem_attrs (MEM_ALIAS_SET (memref), 0, 0, size, align, mmode);
- return new;
+ return new_rtx;
}
/* Return a memory reference like MEMREF, but with its mode changed
int validate, int adjust)
{
rtx addr = XEXP (memref, 0);
- rtx new;
+ rtx new_rtx;
rtx memoffset = MEM_OFFSET (memref);
rtx size = 0;
unsigned int memalign = MEM_ALIGN (memref);
+ int pbits;
/* If there are no changes, just return the original memory reference. */
if (mode == GET_MODE (memref) && !offset
(plus (plus reg reg) const_int) -- so do this always. */
addr = copy_rtx (addr);
+ /* Convert a possibly large offset to a signed value within the
+ range of the target address space. */
+ pbits = GET_MODE_BITSIZE (Pmode);
+ if (HOST_BITS_PER_WIDE_INT > pbits)
+ {
+ int shift = HOST_BITS_PER_WIDE_INT - pbits;
+ offset = (((HOST_WIDE_INT) ((unsigned HOST_WIDE_INT) offset << shift))
+ >> shift);
+ }
+
if (adjust)
{
/* If MEMREF is a LO_SUM and the offset is within the alignment of the
addr = plus_constant (addr, offset);
}
- new = change_address_1 (memref, mode, addr, validate);
+ new_rtx = change_address_1 (memref, mode, addr, validate);
+
+ /* If the address is a REG, change_address_1 rightfully returns memref,
+ but this would destroy memref's MEM_ATTRS. */
+ if (new_rtx == memref && offset != 0)
+ new_rtx = copy_rtx (new_rtx);
/* Compute the new values of the memory attributes due to this adjustment.
We add the offsets and update the alignment. */
(unsigned HOST_WIDE_INT) (offset & -offset) * BITS_PER_UNIT);
/* We can compute the size in a number of ways. */
- if (GET_MODE (new) != BLKmode)
- size = GEN_INT (GET_MODE_SIZE (GET_MODE (new)));
+ if (GET_MODE (new_rtx) != BLKmode)
+ size = GEN_INT (GET_MODE_SIZE (GET_MODE (new_rtx)));
else if (MEM_SIZE (memref))
size = plus_constant (MEM_SIZE (memref), -offset);
- MEM_ATTRS (new) = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_EXPR (memref),
- memoffset, size, memalign, GET_MODE (new));
+ MEM_ATTRS (new_rtx) = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_EXPR (memref),
+ memoffset, size, memalign, GET_MODE (new_rtx));
/* At some point, we should validate that this offset is within the object,
if all the appropriate values are known. */
- return new;
+ return new_rtx;
}
/* Return a memory reference like MEMREF, but with its mode changed
to MODE and its address changed to ADDR, which is assumed to be
- MEMREF offseted by OFFSET bytes. If VALIDATE is
+ MEMREF offset by OFFSET bytes. If VALIDATE is
nonzero, the memory address is forced to be valid. */
rtx
rtx
offset_address (rtx memref, rtx offset, unsigned HOST_WIDE_INT pow2)
{
- rtx new, addr = XEXP (memref, 0);
+ rtx new_rtx, addr = XEXP (memref, 0);
- new = simplify_gen_binary (PLUS, Pmode, addr, offset);
+ new_rtx = simplify_gen_binary (PLUS, Pmode, addr, offset);
/* At this point we don't know _why_ the address is invalid. It
could have secondary memory references, multiplies or anything.
being able to recognize the magic around pic_offset_table_rtx.
This stuff is fragile, and is yet another example of why it is
bad to expose PIC machinery too early. */
- if (! memory_address_p (GET_MODE (memref), new)
+ if (! memory_address_p (GET_MODE (memref), new_rtx)
&& GET_CODE (addr) == PLUS
&& XEXP (addr, 0) == pic_offset_table_rtx)
{
addr = force_reg (GET_MODE (addr), addr);
- new = simplify_gen_binary (PLUS, Pmode, addr, offset);
+ new_rtx = simplify_gen_binary (PLUS, Pmode, addr, offset);
}
- update_temp_slot_address (XEXP (memref, 0), new);
- new = change_address_1 (memref, VOIDmode, new, 1);
+ update_temp_slot_address (XEXP (memref, 0), new_rtx);
+ new_rtx = change_address_1 (memref, VOIDmode, new_rtx, 1);
/* If there are no changes, just return the original memory reference. */
- if (new == memref)
- return new;
+ if (new_rtx == memref)
+ return new_rtx;
/* Update the alignment to reflect the offset. Reset the offset, which
we don't know. */
- MEM_ATTRS (new)
+ MEM_ATTRS (new_rtx)
= get_mem_attrs (MEM_ALIAS_SET (memref), MEM_EXPR (memref), 0, 0,
MIN (MEM_ALIGN (memref), pow2 * BITS_PER_UNIT),
- GET_MODE (new));
- return new;
+ GET_MODE (new_rtx));
+ return new_rtx;
}
/* Return a memory reference like MEMREF, but with its address changed to
rtx
widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset)
{
- rtx new = adjust_address_1 (memref, mode, offset, 1, 1);
- tree expr = MEM_EXPR (new);
- rtx memoffset = MEM_OFFSET (new);
+ rtx new_rtx = adjust_address_1 (memref, mode, offset, 1, 1);
+ tree expr = MEM_EXPR (new_rtx);
+ rtx memoffset = MEM_OFFSET (new_rtx);
unsigned int size = GET_MODE_SIZE (mode);
/* If there are no changes, just return the original memory reference. */
- if (new == memref)
- return new;
+ if (new_rtx == memref)
+ return new_rtx;
/* If we don't know what offset we were at within the expression, then
we can't know if we've overstepped the bounds. */
/* The widened memory may alias other stuff, so zap the alias set. */
/* ??? Maybe use get_alias_set on any remaining expression. */
- MEM_ATTRS (new) = get_mem_attrs (0, expr, memoffset, GEN_INT (size),
- MEM_ALIGN (new), mode);
+ MEM_ATTRS (new_rtx) = get_mem_attrs (0, expr, memoffset, GEN_INT (size),
+ MEM_ALIGN (new_rtx), mode);
- return new;
+ return new_rtx;
+}
+\f
+/* A fake decl that is used as the MEM_EXPR of spill slots. */
+static GTY(()) tree spill_slot_decl;
+
+tree
+get_spill_slot_decl (bool force_build_p)
+{
+ tree d = spill_slot_decl;
+ rtx rd;
+
+ if (d || !force_build_p)
+ return d;
+
+ d = build_decl (VAR_DECL, get_identifier ("%sfp"), void_type_node);
+ DECL_ARTIFICIAL (d) = 1;
+ DECL_IGNORED_P (d) = 1;
+ TREE_USED (d) = 1;
+ TREE_THIS_NOTRAP (d) = 1;
+ spill_slot_decl = d;
+
+ rd = gen_rtx_MEM (BLKmode, frame_pointer_rtx);
+ MEM_NOTRAP_P (rd) = 1;
+ MEM_ATTRS (rd) = get_mem_attrs (new_alias_set (), d, const0_rtx,
+ NULL_RTX, 0, BLKmode);
+ SET_DECL_RTL (d, rd);
+
+ return d;
+}
+
+/* Given MEM, a result from assign_stack_local, fill in the memory
+ attributes as appropriate for a register allocator spill slot.
+ These slots are not aliasable by other memory. We arrange for
+ them all to use a single MEM_EXPR, so that the aliasing code can
+ work properly in the case of shared spill slots. */
+
+void
+set_mem_attrs_for_spill (rtx mem)
+{
+ alias_set_type alias;
+ rtx addr, offset;
+ tree expr;
+
+ expr = get_spill_slot_decl (true);
+ alias = MEM_ALIAS_SET (DECL_RTL (expr));
+
+ /* We expect the incoming memory to be of the form:
+ (mem:MODE (plus (reg sfp) (const_int offset)))
+ with perhaps the plus missing for offset = 0. */
+ addr = XEXP (mem, 0);
+ offset = const0_rtx;
+ if (GET_CODE (addr) == PLUS
+ && GET_CODE (XEXP (addr, 1)) == CONST_INT)
+ offset = XEXP (addr, 1);
+
+ MEM_ATTRS (mem) = get_mem_attrs (alias, expr, offset,
+ MEM_SIZE (mem), MEM_ALIGN (mem),
+ GET_MODE (mem));
+ MEM_NOTRAP_P (mem) = 1;
}
\f
/* Return a newly created CODE_LABEL rtx with a unique label number. */
if (NONJUMP_INSN_P (user) && GET_CODE (PATTERN (user)) == SEQUENCE)
user = XVECEXP (PATTERN (user), 0, 0);
- REG_NOTES (user) = gen_rtx_INSN_LIST (REG_CC_SETTER, insn,
- REG_NOTES (user));
- REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_CC_USER, user, REG_NOTES (insn));
+ add_reg_note (user, REG_CC_SETTER, insn);
+ add_reg_note (insn, REG_CC_USER, user);
}
/* Return the next insn that uses CC0 after INSN, which is assumed to
find_auto_inc (rtx *xp, void *data)
{
rtx x = *xp;
- rtx reg = data;
+ rtx reg = (rtx) data;
if (GET_RTX_CLASS (GET_CODE (x)) != RTX_AUTOINC)
return 0;
rtx before = PREV_INSN (trial);
rtx after = NEXT_INSN (trial);
int has_barrier = 0;
- rtx tem, note_retval, note_libcall;
- rtx note, seq;
+ rtx note, seq, tem;
int probability;
rtx insn_last, insn;
int njumps = 0;
is responsible for this step using
split_branch_probability variable. */
gcc_assert (njumps == 1);
- REG_NOTES (insn)
- = gen_rtx_EXPR_LIST (REG_BR_PROB,
- GEN_INT (probability),
- REG_NOTES (insn));
+ add_reg_note (insn, REG_BR_PROB, GEN_INT (probability));
}
}
}
if (CALL_P (insn)
|| (flag_non_call_exceptions && INSN_P (insn)
&& may_trap_p (PATTERN (insn))))
- REG_NOTES (insn)
- = gen_rtx_EXPR_LIST (REG_EH_REGION,
- XEXP (note, 0),
- REG_NOTES (insn));
+ add_reg_note (insn, REG_EH_REGION, XEXP (note, 0));
}
break;
for (insn = insn_last; insn != NULL_RTX; insn = PREV_INSN (insn))
{
if (CALL_P (insn))
- REG_NOTES (insn)
- = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
- XEXP (note, 0),
- REG_NOTES (insn));
+ add_reg_note (insn, REG_NOTE_KIND (note), XEXP (note, 0));
}
break;
for (insn = insn_last; insn != NULL_RTX; insn = PREV_INSN (insn))
{
if (JUMP_P (insn))
- REG_NOTES (insn)
- = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
- XEXP (note, 0),
- REG_NOTES (insn));
+ add_reg_note (insn, REG_NOTE_KIND (note), XEXP (note, 0));
}
break;
rtx reg = XEXP (note, 0);
if (!FIND_REG_INC_NOTE (insn, reg)
&& for_each_rtx (&PATTERN (insn), find_auto_inc, reg) > 0)
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, reg,
- REG_NOTES (insn));
+ add_reg_note (insn, REG_INC, reg);
}
break;
#endif
- case REG_LIBCALL:
- /* Relink the insns with REG_LIBCALL note and with REG_RETVAL note
- after split. */
- REG_NOTES (insn_last)
- = gen_rtx_INSN_LIST (REG_LIBCALL,
- XEXP (note, 0),
- REG_NOTES (insn_last));
-
- note_retval = find_reg_note (XEXP (note, 0), REG_RETVAL, NULL);
- XEXP (note_retval, 0) = insn_last;
- break;
-
- case REG_RETVAL:
- /* Relink the insns with REG_LIBCALL note and with REG_RETVAL note
- after split. */
- REG_NOTES (insn_last)
- = gen_rtx_INSN_LIST (REG_RETVAL,
- XEXP (note, 0),
- REG_NOTES (insn_last));
-
- note_libcall = find_reg_note (XEXP (note, 0), REG_LIBCALL, NULL);
- XEXP (note_libcall, 0) = insn_last;
- break;
-
default:
break;
}
/* Replace insn with an deleted instruction note. */
-void set_insn_deleted (rtx insn)
+void
+set_insn_deleted (rtx insn)
{
df_insn_delete (BLOCK_FOR_INSN (insn), INSN_UID (insn));
PUT_CODE (insn, NOTE);
if (after == last_insn)
last_insn = last;
+
return last;
}
return note;
}
+/* Emit a clobber of lvalue X. */
+
+rtx
+emit_clobber (rtx x)
+{
+ /* CONCATs should not appear in the insn stream. */
+ if (GET_CODE (x) == CONCAT)
+ {
+ emit_clobber (XEXP (x, 0));
+ return emit_clobber (XEXP (x, 1));
+ }
+ return emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
+}
+
+/* Return a sequence of insns to clobber lvalue X. */
+
+rtx
+gen_clobber (rtx x)
+{
+ rtx seq;
+
+ start_sequence ();
+ emit_clobber (x);
+ seq = get_insns ();
+ end_sequence ();
+ return seq;
+}
+
+/* Emit a use of rvalue X. */
+
+rtx
+emit_use (rtx x)
+{
+ /* CONCATs should not appear in the insn stream. */
+ if (GET_CODE (x) == CONCAT)
+ {
+ emit_use (XEXP (x, 0));
+ return emit_use (XEXP (x, 1));
+ }
+ return emit_insn (gen_rtx_USE (VOIDmode, x));
+}
+
+/* Return a sequence of insns to use rvalue X. */
+
+rtx
+gen_use (rtx x)
+{
+ rtx seq;
+
+ start_sequence ();
+ emit_use (x);
+ seq = get_insns ();
+ end_sequence ();
+ return seq;
+}
+
/* Cause next statement to emit a line note even if the line number
has not changed. */
set_unique_reg_note (rtx insn, enum reg_note kind, rtx datum)
{
rtx note = find_reg_note (insn, kind, NULL_RTX);
- rtx new_note = NULL;
switch (kind)
{
break;
}
- new_note = gen_rtx_EXPR_LIST (kind, datum, REG_NOTES (insn));
- REG_NOTES (insn) = new_note;
+ add_reg_note (insn, kind, datum);
switch (kind)
{
free_sequence_stack = tem->next;
}
else
- tem = ggc_alloc (sizeof (struct sequence_stack));
+ tem = GGC_NEW (struct sequence_stack);
tem->next = seq_stack;
tem->first = first_insn;
/* Init the tables that describe all the pseudo regs. */
- rtl.emit.regno_pointer_align_length = LAST_VIRTUAL_REGISTER + 101;
+ crtl->emit.regno_pointer_align_length = LAST_VIRTUAL_REGISTER + 101;
- rtl.emit.regno_pointer_align
- = xmalloc (rtl.emit.regno_pointer_align_length
- * sizeof (unsigned char));
+ crtl->emit.regno_pointer_align
+ = XCNEWVEC (unsigned char, crtl->emit.regno_pointer_align_length);
regno_reg_rtx
- = ggc_alloc (rtl.emit.regno_pointer_align_length * sizeof (rtx));
+ = GGC_NEWVEC (rtx, crtl->emit.regno_pointer_align_length);
/* Put copies of all the hard registers into regno_reg_rtx. */
memcpy (regno_reg_rtx,
rtx
emit_copy_of_insn_after (rtx insn, rtx after)
{
- rtx new;
- rtx note1, note2, link;
+ rtx new_rtx, link;
switch (GET_CODE (insn))
{
case INSN:
- new = emit_insn_after (copy_insn (PATTERN (insn)), after);
+ new_rtx = emit_insn_after (copy_insn (PATTERN (insn)), after);
break;
case JUMP_INSN:
- new = emit_jump_insn_after (copy_insn (PATTERN (insn)), after);
+ new_rtx = emit_jump_insn_after (copy_insn (PATTERN (insn)), after);
break;
case CALL_INSN:
- new = emit_call_insn_after (copy_insn (PATTERN (insn)), after);
+ new_rtx = emit_call_insn_after (copy_insn (PATTERN (insn)), after);
if (CALL_INSN_FUNCTION_USAGE (insn))
- CALL_INSN_FUNCTION_USAGE (new)
+ CALL_INSN_FUNCTION_USAGE (new_rtx)
= copy_insn (CALL_INSN_FUNCTION_USAGE (insn));
- SIBLING_CALL_P (new) = SIBLING_CALL_P (insn);
- CONST_OR_PURE_CALL_P (new) = CONST_OR_PURE_CALL_P (insn);
+ SIBLING_CALL_P (new_rtx) = SIBLING_CALL_P (insn);
+ RTL_CONST_CALL_P (new_rtx) = RTL_CONST_CALL_P (insn);
+ RTL_PURE_CALL_P (new_rtx) = RTL_PURE_CALL_P (insn);
+ RTL_LOOPING_CONST_OR_PURE_CALL_P (new_rtx)
+ = RTL_LOOPING_CONST_OR_PURE_CALL_P (insn);
break;
default:
}
/* Update LABEL_NUSES. */
- mark_jump_label (PATTERN (new), new, 0);
+ mark_jump_label (PATTERN (new_rtx), new_rtx, 0);
- INSN_LOCATOR (new) = INSN_LOCATOR (insn);
+ INSN_LOCATOR (new_rtx) = INSN_LOCATOR (insn);
/* If the old insn is frame related, then so is the new one. This is
primarily needed for IA-64 unwind info which marks epilogue insns,
which may be duplicated by the basic block reordering code. */
- RTX_FRAME_RELATED_P (new) = RTX_FRAME_RELATED_P (insn);
+ RTX_FRAME_RELATED_P (new_rtx) = RTX_FRAME_RELATED_P (insn);
/* Copy all REG_NOTES except REG_LABEL_OPERAND since mark_jump_label
will make them. REG_LABEL_TARGETs are created there too, but are
if (REG_NOTE_KIND (link) != REG_LABEL_OPERAND)
{
if (GET_CODE (link) == EXPR_LIST)
- REG_NOTES (new)
- = gen_rtx_EXPR_LIST (REG_NOTE_KIND (link),
- copy_insn_1 (XEXP (link, 0)), REG_NOTES (new));
+ add_reg_note (new_rtx, REG_NOTE_KIND (link),
+ copy_insn_1 (XEXP (link, 0)));
else
- REG_NOTES (new)
- = gen_rtx_INSN_LIST (REG_NOTE_KIND (link),
- XEXP (link, 0), REG_NOTES (new));
+ add_reg_note (new_rtx, REG_NOTE_KIND (link), XEXP (link, 0));
}
- /* Fix the libcall sequences. */
- if ((note1 = find_reg_note (new, REG_RETVAL, NULL_RTX)) != NULL)
- {
- rtx p = new;
- while ((note2 = find_reg_note (p, REG_LIBCALL, NULL_RTX)) == NULL)
- p = PREV_INSN (p);
- XEXP (note1, 0) = p;
- XEXP (note2, 0) = new;
- }
- INSN_CODE (new) = INSN_CODE (insn);
- return new;
+ INSN_CODE (new_rtx) = INSN_CODE (insn);
+ return new_rtx;
}
static GTY((deletable)) rtx hard_reg_clobbers [NUM_MACHINE_MODES][FIRST_PSEUDO_REGISTER];