diff mbox

[5/5] Don't use rtxes in mem_attrs

Message ID 87wrfht1qn.fsf@firetop.home
State New
Headers show

Commit Message

Richard Sandiford July 17, 2011, 2:34 p.m. UTC
This patch replaces the rtxes in mem_attrs with (bool, HOST_WIDE_INT) pairs.
There's already room for the bools in the padding after "addrspace".
(There's room for one more bool after this patch; we could move to
bitfields if more are needed.)

The new structure is 8 bytes bigger when using a combination of a 32-bit
host and a need_64bit_hwint target.  In other cases it should be the same
as before, and will avoid some pointer chasing.  The question is whether
that's an acceptable trade-off or not.

Richard


gcc/
	* rtl.h (mem_attrs): Turn offset and size fields into HOST_WIDE_INTs.
	Add offset_known_p and size_known_p fields.
	(MEM_OFFSET_KNOWN_P): Update accordingly.
	(MEM_OFFSET, MEM_SIZE_KNOWN_P, MEM_SIZE): Likewise.
	* emit-rtl.c (mem_attrs_htab_hash): Update after mem_attrs changes.
	(mem_attrs_eq_p, set_mem_attributes_minus_bitpos, set_mem_offset)
	(clear_mem_offset, set_mem_size, clear_mem_size, change_address)
	(adjust_address_1, widen_memory_access, set_mem_attrs_for_spill)
	(init_emit_regs): Likewise.

Comments

Richard Biener July 18, 2011, 9:38 a.m. UTC | #1
On Sun, Jul 17, 2011 at 4:34 PM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> This patch replaces the rtxes in mem_attrs with (bool, HOST_WIDE_INT) pairs.
> There's already room for the bools in the padding after "addrspace".
> (There's room for one more bool after this patch; we could move to
> bitfields if more are needed.)
>
> The new structure is 8 bytes bigger when using a combination of a 32-bit
> host and a need_64bit_hwint target.  In other cases it should be the same
> as before, and will avoid some pointer chasing.  The question is whether
> that's an acceptable trade-off or not.

It sure is.

Ok.

Thanks,
Richard.

> Richard
>
>
> gcc/
>        * rtl.h (mem_attrs): Turn offset and size fields into HOST_WIDE_INTs.
>        Add offset_known_p and size_known_p fields.
>        (MEM_OFFSET_KNOWN_P): Update accordingly.
>        (MEM_OFFSET, MEM_SIZE_KNOWN_P, MEM_SIZE): Likewise.
>        * emit-rtl.c (mem_attrs_htab_hash): Update after mem_attrs changes.
>        (mem_attrs_eq_p, set_mem_attributes_minus_bitpos, set_mem_offset)
>        (clear_mem_offset, set_mem_size, clear_mem_size, change_address)
>        (adjust_address_1, widen_memory_access, set_mem_attrs_for_spill)
>        (init_emit_regs): Likewise.
>
> Index: gcc/rtl.h
> ===================================================================
> --- gcc/rtl.h   2011-07-17 11:40:14.000000000 +0100
> +++ gcc/rtl.h   2011-07-17 11:40:18.000000000 +0100
> @@ -136,19 +136,38 @@ typedef struct
>
>  /* Structure used to describe the attributes of a MEM.  These are hashed
>    so MEMs that the same attributes share a data structure.  This means
> -   they cannot be modified in place.  If any element is nonzero, it means
> -   the value of the corresponding attribute is unknown.  */
> -/* ALIGN and SIZE are the alignment and size of the MEM itself,
> -   while EXPR can describe a larger underlying object, which might have a
> -   stricter alignment; OFFSET is the offset of the MEM within that object.  */
> +   they cannot be modified in place.  */
>  typedef struct GTY(()) mem_attrs
>  {
> -  tree expr;                   /* expr corresponding to MEM.  */
> -  rtx offset;                  /* Offset from start of DECL, as CONST_INT.  */
> -  rtx size;                    /* Size in bytes, as a CONST_INT.  */
> -  alias_set_type alias;                /* Memory alias set.  */
> -  unsigned int align;          /* Alignment of MEM in bits.  */
> -  unsigned char addrspace;     /* Address space (0 for generic).  */
> +  /* The expression that the MEM accesses, or null if not known.
> +     This expression might be larger than the memory reference itself.
> +     (In other words, the MEM might access only part of the object.)  */
> +  tree expr;
> +
> +  /* The offset of the memory reference from the start of EXPR.
> +     Only valid if OFFSET_KNOWN_P.  */
> +  HOST_WIDE_INT offset;
> +
> +  /* The size of the memory reference in bytes.  Only valid if
> +     SIZE_KNOWN_P.  */
> +  HOST_WIDE_INT size;
> +
> +  /* The alias set of the memory reference.  */
> +  alias_set_type alias;
> +
> +  /* The alignment of the reference in bits.  Always a multiple of
> +     BITS_PER_UNIT.  Note that EXPR may have a stricter alignment
> +     than the memory reference itself.  */
> +  unsigned int align;
> +
> +  /* The address space that the memory reference uses.  */
> +  unsigned char addrspace;
> +
> +  /* True if OFFSET is known.  */
> +  bool offset_known_p;
> +
> +  /* True if SIZE is known.  */
> +  bool size_known_p;
>  } mem_attrs;
>
>  /* Structure used to describe the attributes of a REG in similar way as
> @@ -1303,19 +1322,19 @@ #define MEM_ALIAS_SET(RTX) (get_mem_attr
>  #define MEM_EXPR(RTX) (get_mem_attrs (RTX)->expr)
>
>  /* For a MEM rtx, true if its MEM_OFFSET is known.  */
> -#define MEM_OFFSET_KNOWN_P(RTX) (get_mem_attrs (RTX)->offset != NULL_RTX)
> +#define MEM_OFFSET_KNOWN_P(RTX) (get_mem_attrs (RTX)->offset_known_p)
>
>  /* For a MEM rtx, the offset from the start of MEM_EXPR.  */
> -#define MEM_OFFSET(RTX) INTVAL (get_mem_attrs (RTX)->offset)
> +#define MEM_OFFSET(RTX) (get_mem_attrs (RTX)->offset)
>
>  /* For a MEM rtx, the address space.  */
>  #define MEM_ADDR_SPACE(RTX) (get_mem_attrs (RTX)->addrspace)
>
>  /* For a MEM rtx, true if its MEM_SIZE is known.  */
> -#define MEM_SIZE_KNOWN_P(RTX) (get_mem_attrs (RTX)->size != NULL_RTX)
> +#define MEM_SIZE_KNOWN_P(RTX) (get_mem_attrs (RTX)->size_known_p)
>
>  /* For a MEM rtx, the size in bytes of the MEM.  */
> -#define MEM_SIZE(RTX) INTVAL (get_mem_attrs (RTX)->size)
> +#define MEM_SIZE(RTX) (get_mem_attrs (RTX)->size)
>
>  /* For a MEM rtx, the alignment in bits.  We can use the alignment of the
>    mode as a default when STRICT_ALIGNMENT, but not if not.  */
> Index: gcc/emit-rtl.c
> ===================================================================
> --- gcc/emit-rtl.c      2011-07-17 11:40:14.000000000 +0100
> +++ gcc/emit-rtl.c      2011-07-17 11:40:18.000000000 +0100
> @@ -256,8 +256,8 @@ mem_attrs_htab_hash (const void *x)
>
>   return (p->alias ^ (p->align * 1000)
>          ^ (p->addrspace * 4000)
> -         ^ ((p->offset ? INTVAL (p->offset) : 0) * 50000)
> -         ^ ((p->size ? INTVAL (p->size) : 0) * 2500000)
> +         ^ ((p->offset_known_p ? p->offset : 0) * 50000)
> +         ^ ((p->size_known_p ? p->size : 0) * 2500000)
>          ^ (size_t) iterative_hash_expr (p->expr, 0));
>  }
>
> @@ -266,8 +266,12 @@ mem_attrs_htab_hash (const void *x)
>  static bool
>  mem_attrs_eq_p (const struct mem_attrs *p, const struct mem_attrs *q)
>  {
> -  return (p->alias == q->alias && p->offset == q->offset
> -         && p->size == q->size && p->align == q->align
> +  return (p->alias == q->alias
> +         && p->offset_known_p == q->offset_known_p
> +         && (!p->offset_known_p || p->offset == q->offset)
> +         && p->size_known_p == q->size_known_p
> +         && (!p->size_known_p || p->size == q->size)
> +         && p->align == q->align
>          && p->addrspace == q->addrspace
>          && (p->expr == q->expr
>              || (p->expr != NULL_TREE && q->expr != NULL_TREE
> @@ -1585,7 +1589,9 @@ set_mem_attributes_minus_bitpos (rtx ref
>       /* ??? Can this ever happen?  Calling this routine on a MEM that
>         already carries memory attributes should probably be invalid.  */
>       attrs.expr = refattrs->expr;
> +      attrs.offset_known_p = refattrs->offset_known_p;
>       attrs.offset = refattrs->offset;
> +      attrs.size_known_p = refattrs->size_known_p;
>       attrs.size = refattrs->size;
>       attrs.align = refattrs->align;
>     }
> @@ -1595,9 +1601,10 @@ set_mem_attributes_minus_bitpos (rtx ref
>     {
>       defattrs = mode_mem_attrs[(int) GET_MODE (ref)];
>       gcc_assert (!defattrs->expr);
> -      gcc_assert (!defattrs->offset);
> +      gcc_assert (!defattrs->offset_known_p);
>
>       /* Respect mode size.  */
> +      attrs.size_known_p = defattrs->size_known_p;
>       attrs.size = defattrs->size;
>       /* ??? Is this really necessary?  We probably should always get
>         the size from the type below.  */
> @@ -1656,7 +1663,10 @@ set_mem_attributes_minus_bitpos (rtx ref
>
>   /* If the size is known, we can set that.  */
>   if (TYPE_SIZE_UNIT (type) && host_integerp (TYPE_SIZE_UNIT (type), 1))
> -    attrs.size = GEN_INT (tree_low_cst (TYPE_SIZE_UNIT (type), 1));
> +    {
> +      attrs.size_known_p = true;
> +      attrs.size = tree_low_cst (TYPE_SIZE_UNIT (type), 1);
> +    }
>
>   /* If T is not a type, we may be able to deduce some more information about
>      the expression.  */
> @@ -1694,11 +1704,16 @@ set_mem_attributes_minus_bitpos (rtx ref
>       if (DECL_P (t))
>        {
>          attrs.expr = t;
> -         attrs.offset = const0_rtx;
> +         attrs.offset_known_p = true;
> +         attrs.offset = 0;
>          apply_bitpos = bitpos;
> -         attrs.size = (DECL_SIZE_UNIT (t)
> -                       && host_integerp (DECL_SIZE_UNIT (t), 1)
> -                       ? GEN_INT (tree_low_cst (DECL_SIZE_UNIT (t), 1)) : 0);
> +         if (DECL_SIZE_UNIT (t) && host_integerp (DECL_SIZE_UNIT (t), 1))
> +           {
> +             attrs.size_known_p = true;
> +             attrs.size = tree_low_cst (DECL_SIZE_UNIT (t), 1);
> +           }
> +         else
> +           attrs.size_known_p = false;
>          attrs.align = DECL_ALIGN (t);
>          align_computed = true;
>        }
> @@ -1721,7 +1736,8 @@ set_mem_attributes_minus_bitpos (rtx ref
>               && ! DECL_BIT_FIELD (TREE_OPERAND (t, 1)))
>        {
>          attrs.expr = t;
> -         attrs.offset = const0_rtx;
> +         attrs.offset_known_p = true;
> +         attrs.offset = 0;
>          apply_bitpos = bitpos;
>          /* ??? Any reason the field size would be different than
>             the size we got from the type?  */
> @@ -1762,7 +1778,7 @@ set_mem_attributes_minus_bitpos (rtx ref
>          if (DECL_P (t2))
>            {
>              attrs.expr = t2;
> -             attrs.offset = NULL;
> +             attrs.offset_known_p = false;
>              if (host_integerp (off_tree, 1))
>                {
>                  HOST_WIDE_INT ioff = tree_low_cst (off_tree, 1);
> @@ -1771,17 +1787,19 @@ set_mem_attributes_minus_bitpos (rtx ref
>                  if (aoff && (unsigned HOST_WIDE_INT) aoff < attrs.align)
>                    attrs.align = aoff;
>                  align_computed = true;
> -                 attrs.offset = GEN_INT (ioff);
> +                 attrs.offset_known_p = true;
> +                 attrs.offset = ioff;
>                  apply_bitpos = bitpos;
>                }
>            }
>          else if (TREE_CODE (t2) == COMPONENT_REF)
>            {
>              attrs.expr = t2;
> -             attrs.offset = NULL;
> +             attrs.offset_known_p = false;
>              if (host_integerp (off_tree, 1))
>                {
> -                 attrs.offset = GEN_INT (tree_low_cst (off_tree, 1));
> +                 attrs.offset_known_p = true;
> +                 attrs.offset = tree_low_cst (off_tree, 1);
>                  apply_bitpos = bitpos;
>                }
>              /* ??? Any reason the field size would be different than
> @@ -1792,7 +1810,8 @@ set_mem_attributes_minus_bitpos (rtx ref
>          else if (TREE_CODE (t) == MEM_REF)
>            {
>              attrs.expr = t;
> -             attrs.offset = const0_rtx;
> +             attrs.offset_known_p = true;
> +             attrs.offset = 0;
>              apply_bitpos = bitpos;
>            }
>        }
> @@ -1802,7 +1821,8 @@ set_mem_attributes_minus_bitpos (rtx ref
>               || TREE_CODE (t) == TARGET_MEM_REF)
>        {
>          attrs.expr = t;
> -         attrs.offset = const0_rtx;
> +         attrs.offset_known_p = true;
> +         attrs.offset = 0;
>          apply_bitpos = bitpos;
>        }
>
> @@ -1818,10 +1838,10 @@ set_mem_attributes_minus_bitpos (rtx ref
>      object to contain the negative offset.  */
>   if (apply_bitpos)
>     {
> -      attrs.offset = plus_constant (attrs.offset,
> -                                   -(apply_bitpos / BITS_PER_UNIT));
> -      if (attrs.size)
> -       attrs.size = plus_constant (attrs.size, apply_bitpos / BITS_PER_UNIT);
> +      gcc_assert (attrs.offset_known_p);
> +      attrs.offset -= apply_bitpos / BITS_PER_UNIT;
> +      if (attrs.size_known_p)
> +       attrs.size += apply_bitpos / BITS_PER_UNIT;
>     }
>
>   /* Now set the attributes we computed above.  */
> @@ -1903,7 +1923,8 @@ set_mem_offset (rtx mem, HOST_WIDE_INT o
>   struct mem_attrs attrs;
>
>   attrs = *get_mem_attrs (mem);
> -  attrs.offset = GEN_INT (offset);
> +  attrs.offset_known_p = true;
> +  attrs.offset = offset;
>   set_mem_attrs (mem, &attrs);
>  }
>
> @@ -1915,7 +1936,7 @@ clear_mem_offset (rtx mem)
>   struct mem_attrs attrs;
>
>   attrs = *get_mem_attrs (mem);
> -  attrs.offset = NULL_RTX;
> +  attrs.offset_known_p = false;
>   set_mem_attrs (mem, &attrs);
>  }
>
> @@ -1927,7 +1948,8 @@ set_mem_size (rtx mem, HOST_WIDE_INT siz
>   struct mem_attrs attrs;
>
>   attrs = *get_mem_attrs (mem);
> -  attrs.size = GEN_INT (size);
> +  attrs.size_known_p = true;
> +  attrs.size = size;
>   set_mem_attrs (mem, &attrs);
>  }
>
> @@ -1939,7 +1961,7 @@ clear_mem_size (rtx mem)
>   struct mem_attrs attrs;
>
>   attrs = *get_mem_attrs (mem);
> -  attrs.size = NULL_RTX;
> +  attrs.size_known_p = false;
>   set_mem_attrs (mem, &attrs);
>  }
>
> @@ -1993,8 +2015,9 @@ change_address (rtx memref, enum machine
>
>   attrs = *get_mem_attrs (memref);
>   defattrs = mode_mem_attrs[(int) mmode];
> -  attrs.expr = defattrs->expr;
> -  attrs.offset = defattrs->offset;
> +  attrs.expr = NULL_TREE;
> +  attrs.offset_known_p = false;
> +  attrs.size_known_p = defattrs->size_known_p;
>   attrs.size = defattrs->size;
>   attrs.align = defattrs->align;
>
> @@ -2076,8 +2099,8 @@ adjust_address_1 (rtx memref, enum machi
>
>   /* Compute the new values of the memory attributes due to this adjustment.
>      We add the offsets and update the alignment.  */
> -  if (attrs.offset)
> -    attrs.offset = GEN_INT (offset + INTVAL (attrs.offset));
> +  if (attrs.offset_known_p)
> +    attrs.offset += offset;
>
>   /* Compute the new alignment by taking the MIN of the alignment and the
>      lowest-order set bit in OFFSET, but don't change the alignment if OFFSET
> @@ -2090,10 +2113,13 @@ adjust_address_1 (rtx memref, enum machi
>
>   /* We can compute the size in a number of ways.  */
>   defattrs = mode_mem_attrs[(int) GET_MODE (new_rtx)];
> -  if (defattrs->size)
> -    attrs.size = defattrs->size;
> -  else if (attrs.size)
> -    attrs.size = plus_constant (attrs.size, -offset);
> +  if (defattrs->size_known_p)
> +    {
> +      attrs.size_known_p = true;
> +      attrs.size = defattrs->size;
> +    }
> +  else if (attrs.size_known_p)
> +    attrs.size -= offset;
>
>   set_mem_attrs (new_rtx, &attrs);
>
> @@ -2124,7 +2150,7 @@ offset_address (rtx memref, rtx offset,
>  {
>   rtx new_rtx, addr = XEXP (memref, 0);
>   enum machine_mode address_mode;
> -  struct mem_attrs attrs;
> +  struct mem_attrs attrs, *defattrs;
>
>   attrs = *get_mem_attrs (memref);
>   address_mode = targetm.addr_space.address_mode (attrs.addrspace);
> @@ -2155,8 +2181,10 @@ offset_address (rtx memref, rtx offset,
>
>   /* Update the alignment to reflect the offset.  Reset the offset, which
>      we don't know.  */
> -  attrs.offset = 0;
> -  attrs.size = mode_mem_attrs[(int) GET_MODE (new_rtx)]->size;
> +  defattrs = mode_mem_attrs[(int) GET_MODE (new_rtx)];
> +  attrs.offset_known_p = false;
> +  attrs.size_known_p = defattrs->size_known_p;
> +  attrs.size = defattrs->size;
>   attrs.align = MIN (attrs.align, pow2 * BITS_PER_UNIT);
>   set_mem_attrs (new_rtx, &attrs);
>   return new_rtx;
> @@ -2204,7 +2232,7 @@ widen_memory_access (rtx memref, enum ma
>
>   /* If we don't know what offset we were at within the expression, then
>      we can't know if we've overstepped the bounds.  */
> -  if (! attrs.offset)
> +  if (! attrs.offset_known_p)
>     attrs.expr = NULL_TREE;
>
>   while (attrs.expr)
> @@ -2224,7 +2252,7 @@ widen_memory_access (rtx memref, enum ma
>             otherwise strip back to the containing structure.  */
>          if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST
>              && compare_tree_int (DECL_SIZE_UNIT (field), size) >= 0
> -             && INTVAL (attrs.offset) >= 0)
> +             && attrs.offset >= 0)
>            break;
>
>          if (! host_integerp (offset, 1))
> @@ -2234,18 +2262,16 @@ widen_memory_access (rtx memref, enum ma
>            }
>
>          attrs.expr = TREE_OPERAND (attrs.expr, 0);
> -         attrs.offset
> -           = (GEN_INT (INTVAL (attrs.offset)
> -                       + tree_low_cst (offset, 1)
> -                       + (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
> -                          / BITS_PER_UNIT)));
> +         attrs.offset += tree_low_cst (offset, 1);
> +         attrs.offset += (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
> +                          / BITS_PER_UNIT);
>        }
>       /* Similarly for the decl.  */
>       else if (DECL_P (attrs.expr)
>               && DECL_SIZE_UNIT (attrs.expr)
>               && TREE_CODE (DECL_SIZE_UNIT (attrs.expr)) == INTEGER_CST
>               && compare_tree_int (DECL_SIZE_UNIT (attrs.expr), size) >= 0
> -              && (! attrs.offset || INTVAL (attrs.offset) >= 0))
> +              && (! attrs.offset_known_p || attrs.offset >= 0))
>        break;
>       else
>        {
> @@ -2257,12 +2283,13 @@ widen_memory_access (rtx memref, enum ma
>     }
>
>   if (! attrs.expr)
> -    attrs.offset = NULL_RTX;
> +    attrs.offset_known_p = false;
>
>   /* The widened memory may alias other stuff, so zap the alias set.  */
>   /* ??? Maybe use get_alias_set on any remaining expression.  */
>   attrs.alias = 0;
> -  attrs.size = GEN_INT (size);
> +  attrs.size_known_p = true;
> +  attrs.size = size;
>   set_mem_attrs (new_rtx, &attrs);
>   return new_rtx;
>  }
> @@ -2319,10 +2346,11 @@ set_mem_attrs_for_spill (rtx mem)
>        (mem:MODE (plus (reg sfp) (const_int offset)))
>      with perhaps the plus missing for offset = 0.  */
>   addr = XEXP (mem, 0);
> -  attrs.offset = const0_rtx;
> +  attrs.offset_known_p = true;
> +  attrs.offset = 0;
>   if (GET_CODE (addr) == PLUS
>       && CONST_INT_P (XEXP (addr, 1)))
> -    attrs.offset = XEXP (addr, 1);
> +    attrs.offset = INTVAL (XEXP (addr, 1));
>
>   set_mem_attrs (mem, &attrs);
>   MEM_NOTRAP_P (mem) = 1;
> @@ -5522,7 +5550,8 @@ init_emit_regs (void)
>       attrs->addrspace = ADDR_SPACE_GENERIC;
>       if (mode != BLKmode)
>        {
> -         attrs->size = GEN_INT (GET_MODE_SIZE (mode));
> +         attrs->size_known_p = true;
> +         attrs->size = GET_MODE_SIZE (mode);
>          if (STRICT_ALIGNMENT)
>            attrs->align = GET_MODE_ALIGNMENT (mode);
>        }
>
diff mbox

Patch

Index: gcc/rtl.h
===================================================================
--- gcc/rtl.h	2011-07-17 11:40:14.000000000 +0100
+++ gcc/rtl.h	2011-07-17 11:40:18.000000000 +0100
@@ -136,19 +136,38 @@  typedef struct
 
 /* Structure used to describe the attributes of a MEM.  These are hashed
    so MEMs that the same attributes share a data structure.  This means
-   they cannot be modified in place.  If any element is nonzero, it means
-   the value of the corresponding attribute is unknown.  */
-/* ALIGN and SIZE are the alignment and size of the MEM itself,
-   while EXPR can describe a larger underlying object, which might have a
-   stricter alignment; OFFSET is the offset of the MEM within that object.  */
+   they cannot be modified in place.  */
 typedef struct GTY(()) mem_attrs
 {
-  tree expr;			/* expr corresponding to MEM.  */
-  rtx offset;			/* Offset from start of DECL, as CONST_INT.  */
-  rtx size;			/* Size in bytes, as a CONST_INT.  */
-  alias_set_type alias;		/* Memory alias set.  */
-  unsigned int align;		/* Alignment of MEM in bits.  */
-  unsigned char addrspace;	/* Address space (0 for generic).  */
+  /* The expression that the MEM accesses, or null if not known.
+     This expression might be larger than the memory reference itself.
+     (In other words, the MEM might access only part of the object.)  */
+  tree expr;
+
+  /* The offset of the memory reference from the start of EXPR.
+     Only valid if OFFSET_KNOWN_P.  */
+  HOST_WIDE_INT offset;
+
+  /* The size of the memory reference in bytes.  Only valid if
+     SIZE_KNOWN_P.  */
+  HOST_WIDE_INT size;
+
+  /* The alias set of the memory reference.  */
+  alias_set_type alias;
+
+  /* The alignment of the reference in bits.  Always a multiple of
+     BITS_PER_UNIT.  Note that EXPR may have a stricter alignment
+     than the memory reference itself.  */
+  unsigned int align;
+
+  /* The address space that the memory reference uses.  */
+  unsigned char addrspace;
+
+  /* True if OFFSET is known.  */
+  bool offset_known_p;
+
+  /* True if SIZE is known.  */
+  bool size_known_p;
 } mem_attrs;
 
 /* Structure used to describe the attributes of a REG in similar way as
@@ -1303,19 +1322,19 @@  #define MEM_ALIAS_SET(RTX) (get_mem_attr
 #define MEM_EXPR(RTX) (get_mem_attrs (RTX)->expr)
 
 /* For a MEM rtx, true if its MEM_OFFSET is known.  */
-#define MEM_OFFSET_KNOWN_P(RTX) (get_mem_attrs (RTX)->offset != NULL_RTX)
+#define MEM_OFFSET_KNOWN_P(RTX) (get_mem_attrs (RTX)->offset_known_p)
 
 /* For a MEM rtx, the offset from the start of MEM_EXPR.  */
-#define MEM_OFFSET(RTX) INTVAL (get_mem_attrs (RTX)->offset)
+#define MEM_OFFSET(RTX) (get_mem_attrs (RTX)->offset)
 
 /* For a MEM rtx, the address space.  */
 #define MEM_ADDR_SPACE(RTX) (get_mem_attrs (RTX)->addrspace)
 
 /* For a MEM rtx, true if its MEM_SIZE is known.  */
-#define MEM_SIZE_KNOWN_P(RTX) (get_mem_attrs (RTX)->size != NULL_RTX)
+#define MEM_SIZE_KNOWN_P(RTX) (get_mem_attrs (RTX)->size_known_p)
 
 /* For a MEM rtx, the size in bytes of the MEM.  */
-#define MEM_SIZE(RTX) INTVAL (get_mem_attrs (RTX)->size)
+#define MEM_SIZE(RTX) (get_mem_attrs (RTX)->size)
 
 /* For a MEM rtx, the alignment in bits.  We can use the alignment of the
    mode as a default when STRICT_ALIGNMENT, but not if not.  */
Index: gcc/emit-rtl.c
===================================================================
--- gcc/emit-rtl.c	2011-07-17 11:40:14.000000000 +0100
+++ gcc/emit-rtl.c	2011-07-17 11:40:18.000000000 +0100
@@ -256,8 +256,8 @@  mem_attrs_htab_hash (const void *x)
 
   return (p->alias ^ (p->align * 1000)
 	  ^ (p->addrspace * 4000)
-	  ^ ((p->offset ? INTVAL (p->offset) : 0) * 50000)
-	  ^ ((p->size ? INTVAL (p->size) : 0) * 2500000)
+	  ^ ((p->offset_known_p ? p->offset : 0) * 50000)
+	  ^ ((p->size_known_p ? p->size : 0) * 2500000)
 	  ^ (size_t) iterative_hash_expr (p->expr, 0));
 }
 
@@ -266,8 +266,12 @@  mem_attrs_htab_hash (const void *x)
 static bool
 mem_attrs_eq_p (const struct mem_attrs *p, const struct mem_attrs *q)
 {
-  return (p->alias == q->alias && p->offset == q->offset
-	  && p->size == q->size && p->align == q->align
+  return (p->alias == q->alias
+	  && p->offset_known_p == q->offset_known_p
+	  && (!p->offset_known_p || p->offset == q->offset)
+	  && p->size_known_p == q->size_known_p
+	  && (!p->size_known_p || p->size == q->size)
+	  && p->align == q->align
 	  && p->addrspace == q->addrspace
 	  && (p->expr == q->expr
 	      || (p->expr != NULL_TREE && q->expr != NULL_TREE
@@ -1585,7 +1589,9 @@  set_mem_attributes_minus_bitpos (rtx ref
       /* ??? Can this ever happen?  Calling this routine on a MEM that
 	 already carries memory attributes should probably be invalid.  */
       attrs.expr = refattrs->expr;
+      attrs.offset_known_p = refattrs->offset_known_p;
       attrs.offset = refattrs->offset;
+      attrs.size_known_p = refattrs->size_known_p;
       attrs.size = refattrs->size;
       attrs.align = refattrs->align;
     }
@@ -1595,9 +1601,10 @@  set_mem_attributes_minus_bitpos (rtx ref
     {
       defattrs = mode_mem_attrs[(int) GET_MODE (ref)];
       gcc_assert (!defattrs->expr);
-      gcc_assert (!defattrs->offset);
+      gcc_assert (!defattrs->offset_known_p);
 
       /* Respect mode size.  */
+      attrs.size_known_p = defattrs->size_known_p;
       attrs.size = defattrs->size;
       /* ??? Is this really necessary?  We probably should always get
 	 the size from the type below.  */
@@ -1656,7 +1663,10 @@  set_mem_attributes_minus_bitpos (rtx ref
 
   /* If the size is known, we can set that.  */
   if (TYPE_SIZE_UNIT (type) && host_integerp (TYPE_SIZE_UNIT (type), 1))
-    attrs.size = GEN_INT (tree_low_cst (TYPE_SIZE_UNIT (type), 1));
+    {
+      attrs.size_known_p = true;
+      attrs.size = tree_low_cst (TYPE_SIZE_UNIT (type), 1);
+    }
 
   /* If T is not a type, we may be able to deduce some more information about
      the expression.  */
@@ -1694,11 +1704,16 @@  set_mem_attributes_minus_bitpos (rtx ref
       if (DECL_P (t))
 	{
 	  attrs.expr = t;
-	  attrs.offset = const0_rtx;
+	  attrs.offset_known_p = true;
+	  attrs.offset = 0;
 	  apply_bitpos = bitpos;
-	  attrs.size = (DECL_SIZE_UNIT (t)
-			&& host_integerp (DECL_SIZE_UNIT (t), 1)
-			? GEN_INT (tree_low_cst (DECL_SIZE_UNIT (t), 1)) : 0);
+	  if (DECL_SIZE_UNIT (t) && host_integerp (DECL_SIZE_UNIT (t), 1))
+	    {
+	      attrs.size_known_p = true;
+	      attrs.size = tree_low_cst (DECL_SIZE_UNIT (t), 1);
+	    }
+	  else
+	    attrs.size_known_p = false;
 	  attrs.align = DECL_ALIGN (t);
 	  align_computed = true;
 	}
@@ -1721,7 +1736,8 @@  set_mem_attributes_minus_bitpos (rtx ref
 	       && ! DECL_BIT_FIELD (TREE_OPERAND (t, 1)))
 	{
 	  attrs.expr = t;
-	  attrs.offset = const0_rtx;
+	  attrs.offset_known_p = true;
+	  attrs.offset = 0;
 	  apply_bitpos = bitpos;
 	  /* ??? Any reason the field size would be different than
 	     the size we got from the type?  */
@@ -1762,7 +1778,7 @@  set_mem_attributes_minus_bitpos (rtx ref
 	  if (DECL_P (t2))
 	    {
 	      attrs.expr = t2;
-	      attrs.offset = NULL;
+	      attrs.offset_known_p = false;
 	      if (host_integerp (off_tree, 1))
 		{
 		  HOST_WIDE_INT ioff = tree_low_cst (off_tree, 1);
@@ -1771,17 +1787,19 @@  set_mem_attributes_minus_bitpos (rtx ref
 		  if (aoff && (unsigned HOST_WIDE_INT) aoff < attrs.align)
 	            attrs.align = aoff;
 		  align_computed = true;
-		  attrs.offset = GEN_INT (ioff);
+		  attrs.offset_known_p = true;
+		  attrs.offset = ioff;
 		  apply_bitpos = bitpos;
 		}
 	    }
 	  else if (TREE_CODE (t2) == COMPONENT_REF)
 	    {
 	      attrs.expr = t2;
-	      attrs.offset = NULL;
+	      attrs.offset_known_p = false;
 	      if (host_integerp (off_tree, 1))
 		{
-		  attrs.offset = GEN_INT (tree_low_cst (off_tree, 1));
+		  attrs.offset_known_p = true;
+		  attrs.offset = tree_low_cst (off_tree, 1);
 		  apply_bitpos = bitpos;
 		}
 	      /* ??? Any reason the field size would be different than
@@ -1792,7 +1810,8 @@  set_mem_attributes_minus_bitpos (rtx ref
 	  else if (TREE_CODE (t) == MEM_REF)
 	    {
 	      attrs.expr = t;
-	      attrs.offset = const0_rtx;
+	      attrs.offset_known_p = true;
+	      attrs.offset = 0;
 	      apply_bitpos = bitpos;
 	    }
 	}
@@ -1802,7 +1821,8 @@  set_mem_attributes_minus_bitpos (rtx ref
 	       || TREE_CODE (t) == TARGET_MEM_REF)
 	{
 	  attrs.expr = t;
-	  attrs.offset = const0_rtx;
+	  attrs.offset_known_p = true;
+	  attrs.offset = 0;
 	  apply_bitpos = bitpos;
 	}
 
@@ -1818,10 +1838,10 @@  set_mem_attributes_minus_bitpos (rtx ref
      object to contain the negative offset.  */
   if (apply_bitpos)
     {
-      attrs.offset = plus_constant (attrs.offset,
-				    -(apply_bitpos / BITS_PER_UNIT));
-      if (attrs.size)
-	attrs.size = plus_constant (attrs.size, apply_bitpos / BITS_PER_UNIT);
+      gcc_assert (attrs.offset_known_p);
+      attrs.offset -= apply_bitpos / BITS_PER_UNIT;
+      if (attrs.size_known_p)
+	attrs.size += apply_bitpos / BITS_PER_UNIT;
     }
 
   /* Now set the attributes we computed above.  */
@@ -1903,7 +1923,8 @@  set_mem_offset (rtx mem, HOST_WIDE_INT o
   struct mem_attrs attrs;
 
   attrs = *get_mem_attrs (mem);
-  attrs.offset = GEN_INT (offset);
+  attrs.offset_known_p = true;
+  attrs.offset = offset;
   set_mem_attrs (mem, &attrs);
 }
 
@@ -1915,7 +1936,7 @@  clear_mem_offset (rtx mem)
   struct mem_attrs attrs;
 
   attrs = *get_mem_attrs (mem);
-  attrs.offset = NULL_RTX;
+  attrs.offset_known_p = false;
   set_mem_attrs (mem, &attrs);
 }
 
@@ -1927,7 +1948,8 @@  set_mem_size (rtx mem, HOST_WIDE_INT siz
   struct mem_attrs attrs;
 
   attrs = *get_mem_attrs (mem);
-  attrs.size = GEN_INT (size);
+  attrs.size_known_p = true;
+  attrs.size = size;
   set_mem_attrs (mem, &attrs);
 }
 
@@ -1939,7 +1961,7 @@  clear_mem_size (rtx mem)
   struct mem_attrs attrs;
 
   attrs = *get_mem_attrs (mem);
-  attrs.size = NULL_RTX;
+  attrs.size_known_p = false;
   set_mem_attrs (mem, &attrs);
 }
 
@@ -1993,8 +2015,9 @@  change_address (rtx memref, enum machine
 
   attrs = *get_mem_attrs (memref);
   defattrs = mode_mem_attrs[(int) mmode];
-  attrs.expr = defattrs->expr;
-  attrs.offset = defattrs->offset;
+  attrs.expr = NULL_TREE;
+  attrs.offset_known_p = false;
+  attrs.size_known_p = defattrs->size_known_p;
   attrs.size = defattrs->size;
   attrs.align = defattrs->align;
 
@@ -2076,8 +2099,8 @@  adjust_address_1 (rtx memref, enum machi
 
   /* Compute the new values of the memory attributes due to this adjustment.
      We add the offsets and update the alignment.  */
-  if (attrs.offset)
-    attrs.offset = GEN_INT (offset + INTVAL (attrs.offset));
+  if (attrs.offset_known_p)
+    attrs.offset += offset;
 
   /* Compute the new alignment by taking the MIN of the alignment and the
      lowest-order set bit in OFFSET, but don't change the alignment if OFFSET
@@ -2090,10 +2113,13 @@  adjust_address_1 (rtx memref, enum machi
 
   /* We can compute the size in a number of ways.  */
   defattrs = mode_mem_attrs[(int) GET_MODE (new_rtx)];
-  if (defattrs->size)
-    attrs.size = defattrs->size;
-  else if (attrs.size)
-    attrs.size = plus_constant (attrs.size, -offset);
+  if (defattrs->size_known_p)
+    {
+      attrs.size_known_p = true;
+      attrs.size = defattrs->size;
+    }
+  else if (attrs.size_known_p)
+    attrs.size -= offset;
 
   set_mem_attrs (new_rtx, &attrs);
 
@@ -2124,7 +2150,7 @@  offset_address (rtx memref, rtx offset,
 {
   rtx new_rtx, addr = XEXP (memref, 0);
   enum machine_mode address_mode;
-  struct mem_attrs attrs;
+  struct mem_attrs attrs, *defattrs;
 
   attrs = *get_mem_attrs (memref);
   address_mode = targetm.addr_space.address_mode (attrs.addrspace);
@@ -2155,8 +2181,10 @@  offset_address (rtx memref, rtx offset,
 
   /* Update the alignment to reflect the offset.  Reset the offset, which
      we don't know.  */
-  attrs.offset = 0;
-  attrs.size = mode_mem_attrs[(int) GET_MODE (new_rtx)]->size;
+  defattrs = mode_mem_attrs[(int) GET_MODE (new_rtx)];
+  attrs.offset_known_p = false;
+  attrs.size_known_p = defattrs->size_known_p;
+  attrs.size = defattrs->size;
   attrs.align = MIN (attrs.align, pow2 * BITS_PER_UNIT);
   set_mem_attrs (new_rtx, &attrs);
   return new_rtx;
@@ -2204,7 +2232,7 @@  widen_memory_access (rtx memref, enum ma
 
   /* If we don't know what offset we were at within the expression, then
      we can't know if we've overstepped the bounds.  */
-  if (! attrs.offset)
+  if (! attrs.offset_known_p)
     attrs.expr = NULL_TREE;
 
   while (attrs.expr)
@@ -2224,7 +2252,7 @@  widen_memory_access (rtx memref, enum ma
 	     otherwise strip back to the containing structure.  */
 	  if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST
 	      && compare_tree_int (DECL_SIZE_UNIT (field), size) >= 0
-	      && INTVAL (attrs.offset) >= 0)
+	      && attrs.offset >= 0)
 	    break;
 
 	  if (! host_integerp (offset, 1))
@@ -2234,18 +2262,16 @@  widen_memory_access (rtx memref, enum ma
 	    }
 
 	  attrs.expr = TREE_OPERAND (attrs.expr, 0);
-	  attrs.offset
-	    = (GEN_INT (INTVAL (attrs.offset)
-			+ tree_low_cst (offset, 1)
-			+ (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
-			   / BITS_PER_UNIT)));
+	  attrs.offset += tree_low_cst (offset, 1);
+	  attrs.offset += (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
+			   / BITS_PER_UNIT);
 	}
       /* Similarly for the decl.  */
       else if (DECL_P (attrs.expr)
 	       && DECL_SIZE_UNIT (attrs.expr)
 	       && TREE_CODE (DECL_SIZE_UNIT (attrs.expr)) == INTEGER_CST
 	       && compare_tree_int (DECL_SIZE_UNIT (attrs.expr), size) >= 0
-	       && (! attrs.offset || INTVAL (attrs.offset) >= 0))
+	       && (! attrs.offset_known_p || attrs.offset >= 0))
 	break;
       else
 	{
@@ -2257,12 +2283,13 @@  widen_memory_access (rtx memref, enum ma
     }
 
   if (! attrs.expr)
-    attrs.offset = NULL_RTX;
+    attrs.offset_known_p = false;
 
   /* The widened memory may alias other stuff, so zap the alias set.  */
   /* ??? Maybe use get_alias_set on any remaining expression.  */
   attrs.alias = 0;
-  attrs.size = GEN_INT (size);
+  attrs.size_known_p = true;
+  attrs.size = size;
   set_mem_attrs (new_rtx, &attrs);
   return new_rtx;
 }
@@ -2319,10 +2346,11 @@  set_mem_attrs_for_spill (rtx mem)
 	(mem:MODE (plus (reg sfp) (const_int offset)))
      with perhaps the plus missing for offset = 0.  */
   addr = XEXP (mem, 0);
-  attrs.offset = const0_rtx;
+  attrs.offset_known_p = true;
+  attrs.offset = 0;
   if (GET_CODE (addr) == PLUS
       && CONST_INT_P (XEXP (addr, 1)))
-    attrs.offset = XEXP (addr, 1);
+    attrs.offset = INTVAL (XEXP (addr, 1));
 
   set_mem_attrs (mem, &attrs);
   MEM_NOTRAP_P (mem) = 1;
@@ -5522,7 +5550,8 @@  init_emit_regs (void)
       attrs->addrspace = ADDR_SPACE_GENERIC;
       if (mode != BLKmode)
 	{
-	  attrs->size = GEN_INT (GET_MODE_SIZE (mode));
+	  attrs->size_known_p = true;
+	  attrs->size = GET_MODE_SIZE (mode);
 	  if (STRICT_ALIGNMENT)
 	    attrs->align = GET_MODE_ALIGNMENT (mode);
 	}