Comments
Patch
===================================================================
@@ -1569,7 +1569,7 @@ get_mem_align_offset (rtx mem, unsigned
set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
HOST_WIDE_INT bitpos)
{
- HOST_WIDE_INT apply_bitpos = 0;
+ tree expr = NULL_TREE;
tree type;
struct mem_attrs attrs, *defattrs, *refattrs;
addr_space_t as;
@@ -1679,11 +1679,7 @@ set_mem_attributes_minus_bitpos (rtx ref
attrs.align = MAX (attrs.align, TYPE_ALIGN (type));
/* If the size is known, we can set that. */
- if (TYPE_SIZE_UNIT (type) && host_integerp (TYPE_SIZE_UNIT (type), 1))
- {
- attrs.size_known_p = true;
- attrs.size = tree_low_cst (TYPE_SIZE_UNIT (type), 1);
- }
+ tree new_size = TYPE_SIZE_UNIT (type);
/* If T is not a type, we may be able to deduce some more information about
the expression. */
@@ -1738,17 +1734,10 @@ set_mem_attributes_minus_bitpos (rtx ref
/* If this is a decl, set the attributes of the MEM from it. */
if (DECL_P (t))
{
- attrs.expr = t;
+ expr = t;
attrs.offset_known_p = true;
attrs.offset = 0;
- apply_bitpos = bitpos;
- 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;
+ new_size = DECL_SIZE_UNIT (t);
attrs.align = DECL_ALIGN (t);
align_computed = true;
}
@@ -1770,10 +1759,9 @@ set_mem_attributes_minus_bitpos (rtx ref
else if (TREE_CODE (t) == COMPONENT_REF
&& ! DECL_BIT_FIELD (TREE_OPERAND (t, 1)))
{
- attrs.expr = t;
+ expr = t;
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? */
}
@@ -1812,7 +1800,7 @@ set_mem_attributes_minus_bitpos (rtx ref
if (DECL_P (t2))
{
- attrs.expr = t2;
+ expr = t2;
attrs.offset_known_p = false;
if (host_integerp (off_tree, 1))
{
@@ -1824,18 +1812,16 @@ set_mem_attributes_minus_bitpos (rtx ref
align_computed = true;
attrs.offset_known_p = true;
attrs.offset = ioff;
- apply_bitpos = bitpos;
}
}
else if (TREE_CODE (t2) == COMPONENT_REF)
{
- attrs.expr = t2;
+ expr = t2;
attrs.offset_known_p = false;
if (host_integerp (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
the size we got from the type? */
@@ -1846,10 +1832,9 @@ set_mem_attributes_minus_bitpos (rtx ref
else if (TREE_CODE (t) == MEM_REF
|| TREE_CODE (t) == TARGET_MEM_REF)
{
- attrs.expr = t;
+ expr = t;
attrs.offset_known_p = true;
attrs.offset = 0;
- apply_bitpos = bitpos;
}
if (!align_computed)
@@ -1861,17 +1846,22 @@ set_mem_attributes_minus_bitpos (rtx ref
else
as = TYPE_ADDR_SPACE (type);
- /* If we modified OFFSET based on T, then subtract the outstanding
- bit position offset. Similarly, increase the size of the accessed
- object to contain the negative offset. */
- if (apply_bitpos)
+ if (expr)
{
- 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;
+ attrs.expr = expr;
+ /* If we modified OFFSET based on T, then subtract the outstanding
+ bit position offset. */
+ if (attrs.offset_known_p)
+ attrs.offset -= bitpos / BITS_PER_UNIT;
}
-
+ if (host_integerp (new_size, 1))
+ {
+ attrs.size_known_p = true;
+ /* Include the outstanding bit offset in the size, so that the
+ initial reference includes the leading gap and T. */
+ attrs.size = tree_low_cst (new_size, 1) + bitpos / BITS_PER_UNIT;
+ }
+
/* Now set the attributes we computed above. */
attrs.addrspace = as;
set_mem_attrs (ref, &attrs);
While working on the insertion and extraction optabs, I came across some strange-looking behaviour relatd to set_mem_attributes_minus_bitpos. In gcc.c-torture/execute/20030714-1.c we have: struct RenderStyle { struct NonInheritedFlags { union { struct { unsigned int _display : 4; unsigned int _bg_repeat : 2; bool _bg_attachment : 1; unsigned int _overflow : 4 ; unsigned int _vertical_align : 4; unsigned int _clear : 2; EPosition _position : 2; EFloat _floating : 2; unsigned int _table_layout : 1; bool _flowAroundFloats :1; unsigned int _styleType : 3; bool _hasHover : 1; bool _hasActive : 1; bool _clipSpecified : 1; unsigned int _unicodeBidi : 2; int _unused : 1; } f; int _niflags; }; } noninherited_flags; }; ... RenderStyle g__style; ... g__style.noninherited_flags.f._position = FIXED; ... expand_assignment calls: if (MEM_P (to_rtx)) { /* If the field is at offset zero, we could have been given the DECL_RTX of the parent struct. Don't munge it. */ to_rtx = shallow_copy_rtx (to_rtx); set_mem_attributes_minus_bitpos (to_rtx, to, 0, bitpos); ... } where "to_rtx" is: (mem/c:SI (symbol_ref:DI ("g__style") [flags 0x4] <var_decl 0x7ffff6e4ee40 g__style>) [0 g__style+0 S4 A64]) and "to" is the component_ref. So far so good. But set_mem_attributes_minus_bitpos has: /* Default values from pre-existing memory attributes if present. */ refattrs = MEM_ATTRS (ref); if (refattrs) { /* ??? 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; } which of course applies in this case: we have a MEM for g__style. I would expect many calls from this site are for MEMs with an existing MEM_EXPR. So the new attributes also start out describing g__style. Then we have: /* If the size is known, we can set that. */ if (TYPE_SIZE_UNIT (type) && host_integerp (TYPE_SIZE_UNIT (type), 1)) { attrs.size_known_p = true; attrs.size = tree_low_cst (TYPE_SIZE_UNIT (type), 1); } which sets the size to 1 byte (because that's all the bitfield occupies). Then later: /* If this is a field reference and not a bit-field, record it. */ /* ??? 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 && ! DECL_BIT_FIELD (TREE_OPERAND (t, 1))) so we leave the offset and expr alone. The end result is: (mem/j/c:SI (symbol_ref:DI ("g__style") [flags 0x4] <var_decl 0x7ffff6e4ee40 g__style>) [0 g__style+0 S1 A64]) an SImode reference to the first byte (and only the first byte) of g__style. Then, when we apply adjust_bitfield_address, it looks like we're moving past the end of the region and so we drop the MEM_EXPR. In cases where set_mem_attributes_minus_bitpos does set MEM_EXPR based on the new tree, it also adds the bitpos to the size. But I think we should do that whenever we set the size based on the new tree, regardless of whether we were able to record a MEM_EXPR too. That said, this code has lots of ???s in it, so I'm not exactly confident about this change. Thoughts? Richard gcc/ * emit-rtl.c (set_mem_attributes_minus_bitpos): If setting the size based on the new tree, always include the bitpos in it.