+2011-07-19 Richard Sandiford <rdsandiford@googlemail.com>
+
+ * doc/rtl.texi (MEM_OFFSET_KNOWN_P): Document.
+ (MEM_OFFSET): Change from returning an rtx to returning a
+ HOST_WIDE_INT.
+ * rtl.h (MEM_OFFSET_KNOWN_P): New macro.
+ (MEM_OFFSET): Return a HOST_WIDE_INT rather than an rtx.
+ * emit-rtl.h (set_mem_offset): Take a HOST_WIDE_INT rather than an rtx.
+ (clear_mem_offset): Declare.
+ * alias.c (ao_ref_from_mem): Adjust uses of MEM_OFFSET, using
+ MEM_OFFSET_KNOWN_P to test whether the offset is known, and
+ MEM_OFFSET to get a HOST_WIDE_INT offset.
+ (nonoverlapping_memrefs_p): Likewise. Adjust calls to...
+ (adjust_offset_for_component_ref): Take a bool "known_p"
+ parameter and a HOST_WIDE_INT "offset" parameter.
+ * builtins.c (get_memory_rtx): As for ao_ref_from_mem.
+ Adjust calls to set_mem_offset, passing a HOST_WIDE_INT rather
+ than an rtx. Use clear_mem_offset to clear the offset.
+ * cfgcleanup.c (merge_memattrs): Likewise.
+ * dwarf2out.c (tls_mem_loc_descriptor): Likewise.
+ * function.c (assign_parm_find_stack_rtl): Likewise.
+ (assign_parm_setup_stack): Likewise.
+ * print-rtl.c (print_rtx): Likewise.
+ * reload.c (find_reloads_subreg_address): Likewise.
+ * simplify-rtx.c (delegitimize_mem_from_attrs): Likewise.
+ * var-tracking.c (INT_MEM_OFFSET): Likewise.
+ * emit-rtl.c (set_reg_attrs_from_value): Likewise.
+ (get_mem_align_offset): Likewise.
+ (set_mem_offset): Take a HOST_WIDE_INT rather than an rtx.
+ (clear_mem_offset): New function.
+ * config/mips/mips.c (r10k_safe_mem_expr_p): Take a HOST_WIDE_INT
+ offset rather than an rtx. Assume both the expressio and offset
+ are available.
+ (r10k_needs_protection_p_1): Update accordingly, checking the
+ expression and offset availability here instead.
+
2011-07-19 Richard Sandiford <rdsandiford@googlemail.com>
* doc/rtl.texi (MEM_SIZE_KNOWN_P): Document.
static int aliases_everything_p (const_rtx);
static bool nonoverlapping_component_refs_p (const_tree, const_tree);
static tree decl_for_component_ref (tree);
-static rtx adjust_offset_for_component_ref (tree, rtx);
static int write_dependence_p (const_rtx, const_rtx, int);
static void memory_modified_1 (rtx, const_rtx, void *);
/* If MEM_OFFSET or MEM_SIZE are unknown we have to punt.
Keep points-to related information though. */
- if (!MEM_OFFSET (mem)
+ if (!MEM_OFFSET_KNOWN_P (mem)
|| !MEM_SIZE_KNOWN_P (mem))
{
ref->ref = NULL_TREE;
/* If the base decl is a parameter we can have negative MEM_OFFSET in
case of promoted subregs on bigendian targets. Trust the MEM_EXPR
here. */
- if (INTVAL (MEM_OFFSET (mem)) < 0
- && ((MEM_SIZE (mem) + INTVAL (MEM_OFFSET (mem)))
- * BITS_PER_UNIT) == ref->size)
+ if (MEM_OFFSET (mem) < 0
+ && (MEM_SIZE (mem) + MEM_OFFSET (mem)) * BITS_PER_UNIT == ref->size)
return true;
- ref->offset += INTVAL (MEM_OFFSET (mem)) * BITS_PER_UNIT;
+ ref->offset += MEM_OFFSET (mem) * BITS_PER_UNIT;
ref->size = MEM_SIZE (mem) * BITS_PER_UNIT;
/* The MEM may extend into adjacent fields, so adjust max_size if
return x && DECL_P (x) ? x : NULL_TREE;
}
-/* Walk up the COMPONENT_REF list and adjust OFFSET to compensate for the
- offset of the field reference. */
+/* Walk up the COMPONENT_REF list in X and adjust *OFFSET to compensate
+ for the offset of the field reference. *KNOWN_P says whether the
+ offset is known. */
-static rtx
-adjust_offset_for_component_ref (tree x, rtx offset)
+static void
+adjust_offset_for_component_ref (tree x, bool *known_p,
+ HOST_WIDE_INT *offset)
{
- HOST_WIDE_INT ioffset;
-
- if (! offset)
- return NULL_RTX;
-
- ioffset = INTVAL (offset);
+ if (!*known_p)
+ return;
do
{
- tree offset = component_ref_field_offset (x);
+ tree xoffset = component_ref_field_offset (x);
tree field = TREE_OPERAND (x, 1);
- if (! host_integerp (offset, 1))
- return NULL_RTX;
- ioffset += (tree_low_cst (offset, 1)
+ if (! host_integerp (xoffset, 1))
+ {
+ *known_p = false;
+ return;
+ }
+ *offset += (tree_low_cst (xoffset, 1)
+ (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
/ BITS_PER_UNIT));
x = TREE_OPERAND (x, 0);
}
while (x && TREE_CODE (x) == COMPONENT_REF);
-
- return GEN_INT (ioffset);
}
/* Return nonzero if we can determine the exprs corresponding to memrefs
tree exprx = MEM_EXPR (x), expry = MEM_EXPR (y);
rtx rtlx, rtly;
rtx basex, basey;
- rtx moffsetx, moffsety;
+ bool moffsetx_known_p, moffsety_known_p;
+ HOST_WIDE_INT moffsetx = 0, moffsety = 0;
HOST_WIDE_INT offsetx = 0, offsety = 0, sizex, sizey, tem;
/* Unless both have exprs, we can't tell anything. */
/* For spill-slot accesses make sure we have valid offsets. */
if ((exprx == get_spill_slot_decl (false)
- && ! MEM_OFFSET (x))
+ && ! MEM_OFFSET_KNOWN_P (x))
|| (expry == get_spill_slot_decl (false)
- && ! MEM_OFFSET (y)))
+ && ! MEM_OFFSET_KNOWN_P (y)))
return 0;
/* If both are field references, we may be able to determine something. */
/* If the field reference test failed, look at the DECLs involved. */
- moffsetx = MEM_OFFSET (x);
+ moffsetx_known_p = MEM_OFFSET_KNOWN_P (x);
+ if (moffsetx_known_p)
+ moffsetx = MEM_OFFSET (x);
if (TREE_CODE (exprx) == COMPONENT_REF)
{
tree t = decl_for_component_ref (exprx);
if (! t)
return 0;
- moffsetx = adjust_offset_for_component_ref (exprx, moffsetx);
+ adjust_offset_for_component_ref (exprx, &moffsetx_known_p, &moffsetx);
exprx = t;
}
- moffsety = MEM_OFFSET (y);
+ moffsety_known_p = MEM_OFFSET_KNOWN_P (y);
+ if (moffsety_known_p)
+ moffsety = MEM_OFFSET (y);
if (TREE_CODE (expry) == COMPONENT_REF)
{
tree t = decl_for_component_ref (expry);
if (! t)
return 0;
- moffsety = adjust_offset_for_component_ref (expry, moffsety);
+ adjust_offset_for_component_ref (expry, &moffsety_known_p, &moffsety);
expry = t;
}
/* If we have an offset for either memref, it can update the values computed
above. */
- if (moffsetx)
- offsetx += INTVAL (moffsetx), sizex -= INTVAL (moffsetx);
- if (moffsety)
- offsety += INTVAL (moffsety), sizey -= INTVAL (moffsety);
+ if (moffsetx_known_p)
+ offsetx += moffsetx, sizex -= moffsetx;
+ if (moffsety_known_p)
+ offsety += moffsety, sizey -= moffsety;
/* If a memref has both a size and an offset, we can use the smaller size.
We can't do this if the offset isn't known because we must view this
memref as being anywhere inside the DECL's MEM. */
- if (MEM_SIZE_KNOWN_P (x) && moffsetx)
+ if (MEM_SIZE_KNOWN_P (x) && moffsetx_known_p)
sizex = MEM_SIZE (x);
- if (MEM_SIZE_KNOWN_P (y) && moffsety)
+ if (MEM_SIZE_KNOWN_P (y) && moffsety_known_p)
sizey = MEM_SIZE (y);
/* Put the values of the memref with the lower offset in X's values. */
gcc_assert (TREE_CODE (inner) == COMPONENT_REF);
- if (MEM_OFFSET (mem)
- && CONST_INT_P (MEM_OFFSET (mem)))
- offset = INTVAL (MEM_OFFSET (mem));
+ if (MEM_OFFSET_KNOWN_P (mem))
+ offset = MEM_OFFSET (mem);
if (offset >= 0 && len && host_integerp (len, 0))
length = tree_low_cst (len, 0);
if (mem_expr != MEM_EXPR (mem))
{
set_mem_expr (mem, mem_expr);
- set_mem_offset (mem, offset >= 0 ? GEN_INT (offset) : NULL_RTX);
+ if (offset >= 0)
+ set_mem_offset (mem, offset);
+ else
+ clear_mem_offset (mem);
}
}
set_mem_alias_set (mem, 0);
{
set_mem_expr (x, 0);
set_mem_expr (y, 0);
- set_mem_offset (x, 0);
- set_mem_offset (y, 0);
+ clear_mem_offset (x);
+ clear_mem_offset (y);
}
- else if (MEM_OFFSET (x) != MEM_OFFSET (y))
+ else if (MEM_OFFSET_KNOWN_P (x) != MEM_OFFSET_KNOWN_P (y)
+ || (MEM_OFFSET_KNOWN_P (x)
+ && MEM_OFFSET (x) != MEM_OFFSET (y)))
{
- set_mem_offset (x, 0);
- set_mem_offset (y, 0);
+ clear_mem_offset (x);
+ clear_mem_offset (y);
}
if (MEM_SIZE_KNOWN_P (x) && MEM_SIZE_KNOWN_P (y))
a link-time-constant address. */
static bool
-r10k_safe_mem_expr_p (tree expr, rtx offset)
+r10k_safe_mem_expr_p (tree expr, HOST_WIDE_INT offset)
{
- if (expr == NULL_TREE
- || offset == NULL_RTX
- || !CONST_INT_P (offset)
- || INTVAL (offset) < 0
- || INTVAL (offset) >= int_size_in_bytes (TREE_TYPE (expr)))
+ if (offset < 0 || offset >= int_size_in_bytes (TREE_TYPE (expr)))
return false;
while (TREE_CODE (expr) == COMPONENT_REF)
if (!MEM_P (mem))
return 0;
- if (r10k_safe_mem_expr_p (MEM_EXPR (mem), MEM_OFFSET (mem)))
+ if (MEM_EXPR (mem)
+ && MEM_OFFSET_KNOWN_P (mem)
+ && r10k_safe_mem_expr_p (MEM_EXPR (mem), MEM_OFFSET (mem)))
return -1;
if (r10k_safe_address_p (XEXP (mem, 0), (rtx) data))
or another @code{COMPONENT_REF}, or null if there is no compile-time
object associated with the reference.
+@findex MEM_OFFSET_KNOWN_P
+@item MEM_OFFSET_KNOWN_P (@var{x})
+True if the offset of the memory reference from @code{MEM_EXPR} is known.
+@samp{MEM_OFFSET (@var{x})} provides the offset if so.
+
@findex MEM_OFFSET
@item MEM_OFFSET (@var{x})
-The offset from the start of @code{MEM_EXPR} as a @code{CONST_INT} rtx.
+The offset from the start of @code{MEM_EXPR}. The value is only valid if
+@samp{MEM_OFFSET_KNOWN_P (@var{x})} is true.
@findex MEM_SIZE_KNOWN_P
@item MEM_SIZE_KNOWN_P (@var{x})
tree base;
dw_loc_descr_ref loc_result;
- if (MEM_EXPR (mem) == NULL_TREE || MEM_OFFSET (mem) == NULL_RTX)
+ if (MEM_EXPR (mem) == NULL_TREE || !MEM_OFFSET_KNOWN_P (mem))
return NULL;
base = get_base_address (MEM_EXPR (mem));
if (loc_result == NULL)
return NULL;
- if (INTVAL (MEM_OFFSET (mem)))
- loc_descr_plus_const (&loc_result, INTVAL (MEM_OFFSET (mem)));
+ if (MEM_OFFSET (mem))
+ loc_descr_plus_const (&loc_result, MEM_OFFSET (mem));
return loc_result;
}
offset = byte_lowpart_offset (GET_MODE (reg), GET_MODE (x));
if (MEM_P (x))
{
- if (MEM_OFFSET (x) && CONST_INT_P (MEM_OFFSET (x)))
- REG_ATTRS (reg)
- = get_reg_attrs (MEM_EXPR (x), INTVAL (MEM_OFFSET (x)) + offset);
+ if (MEM_OFFSET_KNOWN_P (x))
+ REG_ATTRS (reg) = get_reg_attrs (MEM_EXPR (x),
+ MEM_OFFSET (x) + offset);
if (MEM_POINTER (x))
mark_reg_pointer (reg, 0);
}
unsigned HOST_WIDE_INT offset;
/* This function can't use
- if (!MEM_EXPR (mem) || !MEM_OFFSET (mem)
- || !CONST_INT_P (MEM_OFFSET (mem))
+ if (!MEM_EXPR (mem) || !MEM_OFFSET_KNOWN_P (mem)
|| (MAX (MEM_ALIGN (mem),
get_object_alignment (MEM_EXPR (mem), align))
< align))
return -1;
else
- return (- INTVAL (MEM_OFFSET (mem))) & (align / BITS_PER_UNIT - 1);
+ return (- 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
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)))
+ if (expr == NULL_TREE || !MEM_OFFSET_KNOWN_P (mem))
return -1;
- offset = INTVAL (MEM_OFFSET (mem));
+ offset = MEM_OFFSET (mem);
if (DECL_P (expr))
{
if (DECL_ALIGN (expr) < align)
/* Set the offset of MEM to OFFSET. */
void
-set_mem_offset (rtx mem, rtx offset)
+set_mem_offset (rtx mem, HOST_WIDE_INT offset)
{
struct mem_attrs attrs;
attrs = *get_mem_attrs (mem);
- attrs.offset = offset;
+ attrs.offset = GEN_INT (offset);
+ set_mem_attrs (mem, &attrs);
+}
+
+/* Clear the offset of MEM. */
+
+void
+clear_mem_offset (rtx mem)
+{
+ struct mem_attrs attrs;
+
+ attrs = *get_mem_attrs (mem);
+ attrs.offset = NULL_RTX;
set_mem_attrs (mem, &attrs);
}
extern void set_mem_expr (rtx, tree);
/* Set the offset for MEM to OFFSET. */
-extern void set_mem_offset (rtx, rtx);
+extern void set_mem_offset (rtx, HOST_WIDE_INT);
+
+/* Clear the offset recorded for MEM. */
+extern void clear_mem_offset (rtx);
/* Set the size for MEM to SIZE. */
extern void set_mem_size (rtx, HOST_WIDE_INT);
&& data->promoted_mode != DECL_MODE (parm))
{
set_mem_size (stack_parm, GET_MODE_SIZE (data->promoted_mode));
- if (MEM_EXPR (stack_parm) && MEM_OFFSET (stack_parm))
+ if (MEM_EXPR (stack_parm) && MEM_OFFSET_KNOWN_P (stack_parm))
{
int offset = subreg_lowpart_offset (DECL_MODE (parm),
data->promoted_mode);
if (offset)
- set_mem_offset (stack_parm,
- plus_constant (MEM_OFFSET (stack_parm),
- -offset));
+ set_mem_offset (stack_parm, MEM_OFFSET (stack_parm) - offset);
}
}
}
/* ??? This may need a big-endian conversion on sparc64. */
data->stack_parm
= adjust_address (data->stack_parm, data->nominal_mode, 0);
- if (offset && MEM_OFFSET (data->stack_parm))
+ if (offset && MEM_OFFSET_KNOWN_P (data->stack_parm))
set_mem_offset (data->stack_parm,
- plus_constant (MEM_OFFSET (data->stack_parm),
- offset));
+ MEM_OFFSET (data->stack_parm) + offset);
}
}
if (MEM_EXPR (in_rtx))
print_mem_expr (outfile, MEM_EXPR (in_rtx));
- if (MEM_OFFSET (in_rtx))
- fprintf (outfile, "+" HOST_WIDE_INT_PRINT_DEC,
- INTVAL (MEM_OFFSET (in_rtx)));
+ if (MEM_OFFSET_KNOWN_P (in_rtx))
+ fprintf (outfile, "+" HOST_WIDE_INT_PRINT_DEC, MEM_OFFSET (in_rtx));
if (MEM_SIZE_KNOWN_P (in_rtx))
fprintf (outfile, " S" HOST_WIDE_INT_PRINT_DEC, MEM_SIZE (in_rtx));
XEXP (tem, 0) = plus_constant (XEXP (tem, 0), offset);
PUT_MODE (tem, GET_MODE (x));
- if (MEM_OFFSET (tem))
- set_mem_offset (tem, plus_constant (MEM_OFFSET (tem), offset));
+ if (MEM_OFFSET_KNOWN_P (tem))
+ set_mem_offset (tem, MEM_OFFSET (tem) + offset);
if (MEM_SIZE_KNOWN_P (tem)
&& MEM_SIZE (tem) != (HOST_WIDE_INT) outer_size)
set_mem_size (tem, outer_size);
refer to part of a DECL. It may also be a COMPONENT_REF. */
#define MEM_EXPR(RTX) (get_mem_attrs (RTX)->expr)
-/* For a MEM rtx, the offset from the start of MEM_EXPR, if known, as a
- RTX that is always a CONST_INT. */
-#define MEM_OFFSET(RTX) (get_mem_attrs (RTX)->offset)
+/* For a MEM rtx, true if its MEM_OFFSET is known. */
+#define MEM_OFFSET_KNOWN_P(RTX) (get_mem_attrs (RTX)->offset != NULL_RTX)
+
+/* For a MEM rtx, the offset from the start of MEM_EXPR. */
+#define MEM_OFFSET(RTX) INTVAL (get_mem_attrs (RTX)->offset)
/* For a MEM rtx, the address space. */
#define MEM_ADDR_SPACE(RTX) (get_mem_attrs (RTX)->addrspace)
use their base addresses as equivalent. */
if (MEM_P (x)
&& MEM_EXPR (x)
- && MEM_OFFSET (x))
+ && MEM_OFFSET_KNOWN_P (x))
{
tree decl = MEM_EXPR (x);
enum machine_mode mode = GET_MODE (x);
{
rtx newx;
- offset += INTVAL (MEM_OFFSET (x));
+ offset += MEM_OFFSET (x);
newx = DECL_RTL (decl);
#define VTI(BB) ((variable_tracking_info) (BB)->aux)
/* Macro to access MEM_OFFSET as an HOST_WIDE_INT. Evaluates MEM twice. */
-#define INT_MEM_OFFSET(mem) (MEM_OFFSET (mem) ? INTVAL (MEM_OFFSET (mem)) : 0)
+#define INT_MEM_OFFSET(mem) (MEM_OFFSET_KNOWN_P (mem) ? MEM_OFFSET (mem) : 0)
/* Alloc pool for struct attrs_def. */
static alloc_pool attrs_pool;