diff mbox

Fix PR55882

Message ID alpine.LNX.2.00.1301091254470.6889@zhemvz.fhfr.qr
State New
Headers show

Commit Message

Richard Biener Jan. 9, 2013, 11:58 a.m. UTC
This fixes PR55882 - set_mem_attributes_minus_bitpos misses to
account for the to-be applied bitpos when computing MEM_ALIGN.
It extracts alignment from 't' instead of &t - bitpos.

Bootstrapped and tested on x86_64-unknown-linux-gnu, bootstrap
and regtest running on mips.

Does this look sensible?

Thanks,
Richard.

2013-01-09  Richard Biener  <rguenther@suse.de>

	PR middle-end/55882
	* emit-rtl.c (set_mem_attributes_minus_bitpos): Correctly
	account for the to-be applied bitpos when computing alignment.

Comments

Eric Botcazou Jan. 9, 2013, 8:47 p.m. UTC | #1
> This fixes PR55882 - set_mem_attributes_minus_bitpos misses to
> account for the to-be applied bitpos when computing MEM_ALIGN.
> It extracts alignment from 't' instead of &t - bitpos.
> 
> Bootstrapped and tested on x86_64-unknown-linux-gnu, bootstrap
> and regtest running on mips.
> 
> Does this look sensible?

I'm not sure, bitpos isn't taken into account in the other cases when the 
alignment is computed.  adjust_address_1 is supposed to properly adjust the 
alignment by the time the offset is applied.
Richard Biener Jan. 10, 2013, 9:16 a.m. UTC | #2
On Wed, 9 Jan 2013, Eric Botcazou wrote:

> > This fixes PR55882 - set_mem_attributes_minus_bitpos misses to
> > account for the to-be applied bitpos when computing MEM_ALIGN.
> > It extracts alignment from 't' instead of &t - bitpos.
> > 
> > Bootstrapped and tested on x86_64-unknown-linux-gnu, bootstrap
> > and regtest running on mips.
> > 
> > Does this look sensible?
> 
> I'm not sure, bitpos isn't taken into account in the other cases when the 
> alignment is computed.  adjust_address_1 is supposed to properly adjust the 
> alignment by the time the offset is applied.

Yes, but alignment adjustment assumes the alignment is that of
the actual MEM, not that of the MEM_EXPR.  Thus, MEM_ALIGN is the
alignment of MEM_EXPR - MEM_OFFSET.

It's true that the other paths setting align_computed have the
same issue.  I can produce a followup (or preparatory patch)
that at least removes the code that is redundant.  For example

      /* If this is a decl, set the attributes of the MEM from it.  */
      if (DECL_P (t))
        {
          attrs.expr = t;
          attrs.offset_known_p = true;
          attrs.offset = 0;
          apply_bitpos = bitpos;
          new_size = DECL_SIZE_UNIT (t);
          attrs.align = DECL_ALIGN (t);
          align_computed = true;
        }

the alignment computation can be handled by the get_object_alignment
path just fine, no need to duplicate it here, likewise for the
CONSTANT_CLASS_P case.  The ARRAY_REF path is scary enough to
me (I'd rather drop it completely ... it's probably designed to
make more cases covered by nonoverlapping_component_refs_p?).
At least handling of DECL/COMPONENT_REF below the ARRAY_REFs
should be commonized - for example the COMPONENT_REF case

          else if (TREE_CODE (t2) == COMPONENT_REF)
            {
              attrs.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;
                }

doesn't adjust 't' nor does it compute alignment.  So it
clearly cannot be that MEM_ALIGN is supposed to be the
alignment of MEM_EXPR.

That is - the question boils down to _what_ should MEM_ALIGN
be the alignment of?  In all the rest of the compiler it surely
is the alignment of XEXP (mem, 0) - to make it differ from that
during a brief period of expand_assignment sounds fragile at least.

I'll try to simplify code paths without changing behavior first.

Thanks,
Richard.
Richard Biener Jan. 10, 2013, 10:04 a.m. UTC | #3
On Thu, 10 Jan 2013, Richard Biener wrote:

> On Wed, 9 Jan 2013, Eric Botcazou wrote:
> 
> > > This fixes PR55882 - set_mem_attributes_minus_bitpos misses to
> > > account for the to-be applied bitpos when computing MEM_ALIGN.
> > > It extracts alignment from 't' instead of &t - bitpos.
> > > 
> > > Bootstrapped and tested on x86_64-unknown-linux-gnu, bootstrap
> > > and regtest running on mips.
> > > 
> > > Does this look sensible?
> > 
> > I'm not sure, bitpos isn't taken into account in the other cases when the 
> > alignment is computed.  adjust_address_1 is supposed to properly adjust the 
> > alignment by the time the offset is applied.
> 
> Yes, but alignment adjustment assumes the alignment is that of
> the actual MEM, not that of the MEM_EXPR.  Thus, MEM_ALIGN is the
> alignment of MEM_EXPR - MEM_OFFSET.
> 
> It's true that the other paths setting align_computed have the
> same issue.  I can produce a followup (or preparatory patch)
> that at least removes the code that is redundant.  For example
> 
>       /* If this is a decl, set the attributes of the MEM from it.  */
>       if (DECL_P (t))
>         {
>           attrs.expr = t;
>           attrs.offset_known_p = true;
>           attrs.offset = 0;
>           apply_bitpos = bitpos;
>           new_size = DECL_SIZE_UNIT (t);
>           attrs.align = DECL_ALIGN (t);
>           align_computed = true;
>         }
> 
> the alignment computation can be handled by the get_object_alignment
> path just fine, no need to duplicate it here, likewise for the
> CONSTANT_CLASS_P case.  The ARRAY_REF path is scary enough to
> me (I'd rather drop it completely ... it's probably designed to
> make more cases covered by nonoverlapping_component_refs_p?).
> At least handling of DECL/COMPONENT_REF below the ARRAY_REFs
> should be commonized - for example the COMPONENT_REF case
> 
>           else if (TREE_CODE (t2) == COMPONENT_REF)
>             {
>               attrs.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;
>                 }
> 
> doesn't adjust 't' nor does it compute alignment.  So it
> clearly cannot be that MEM_ALIGN is supposed to be the
> alignment of MEM_EXPR.
> 
> That is - the question boils down to _what_ should MEM_ALIGN
> be the alignment of?  In all the rest of the compiler it surely
> is the alignment of XEXP (mem, 0) - to make it differ from that
> during a brief period of expand_assignment sounds fragile at least.
> 
> I'll try to simplify code paths without changing behavior first.

Going over this what's strange as well is that we adjust MEM_SIZE
with bitpos, too.  At least when the MEM has non-BLKmode this
means that MEMs mode and MEM_SIZE is inconsistent?  Or how do
a MEMs mode and MEM_SIZE relate?

I came up with the following patch that shouldn't change
behavior but which makes it easier to follow what happens
(it will also make bitpos handling with my alignment patch fix
consistent).

The patch moves attrs.align "precompute" into the !TYPE_P path
and for the &DECL / &CONSTANT align compute use get_object_alignment
which DTRT for it (it's still buggy because we later will use
MAX of this alignment and the "correct" alignment - but I didn't
want to change behavior here).

The patch removes explicit align computation on the DECL_P
and CONSTANT_CLASS_P paths because that's handled by
the get_object_alignment path in the same way.  That also
allows the ARRAY_REF base paths to be simplified and commonized
(the ARRAY_REF and then DECL_P path will get better align
computation this way, get_object_alignment has more elaborate
off_tree handling).

As followup I'd remove the MEM_REF/TARGET_MEM_REF alignment
"precompute" completely - it's buggy (due to the later use of MAX).
That is, consider the below as explanatory intermediate step,
any real patch would get rid of that "precompute" immediately
(and then probably not re-use anything we got from default or
pre-existing MEM_ATTRs but simply overwrite attrs.align.
See 2nd patch below.

Richard.

2013-01-10  Richard Biener  <rguenther@suse.de>

	* emit-rtl.c (set_mem_attributes_minus_bitpos): Move MEM_REF
	handling completely into the !TYPE_P handling part and use
	get_object_alignment for its alignment computation.  Always
	rely on get_object_alignment for final alignment computation.

Index: gcc/emit-rtl.c
===================================================================
*** gcc/emit-rtl.c	(revision 195079)
--- gcc/emit-rtl.c	(working copy)
*************** set_mem_attributes_minus_bitpos (rtx ref
*** 1641,1691 ****
    if (objectp || TREE_CODE (t) == INDIRECT_REF || TYPE_ALIGN_OK (type))
      attrs.align = MAX (attrs.align, TYPE_ALIGN (type));
  
-   else if (TREE_CODE (t) == MEM_REF)
-     {
-       tree op0 = TREE_OPERAND (t, 0);
-       if (TREE_CODE (op0) == ADDR_EXPR
- 	  && (DECL_P (TREE_OPERAND (op0, 0))
- 	      || CONSTANT_CLASS_P (TREE_OPERAND (op0, 0))))
- 	{
- 	  if (DECL_P (TREE_OPERAND (op0, 0)))
- 	    attrs.align = DECL_ALIGN (TREE_OPERAND (op0, 0));
- 	  else if (CONSTANT_CLASS_P (TREE_OPERAND (op0, 0)))
- 	    {
- 	      attrs.align = TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (op0, 0)));
- #ifdef CONSTANT_ALIGNMENT
- 	      attrs.align = CONSTANT_ALIGNMENT (TREE_OPERAND (op0, 0),
- 						attrs.align);
- #endif
- 	    }
- 	  if (TREE_INT_CST_LOW (TREE_OPERAND (t, 1)) != 0)
- 	    {
- 	      unsigned HOST_WIDE_INT ioff
- 		= TREE_INT_CST_LOW (TREE_OPERAND (t, 1));
- 	      unsigned HOST_WIDE_INT aoff = (ioff & -ioff) * BITS_PER_UNIT;
- 	      attrs.align = MIN (aoff, attrs.align);
- 	    }
- 	}
-       else
- 	/* ??? This isn't fully correct, we can't set the alignment from the
- 	   type in all cases.  */
- 	attrs.align = MAX (attrs.align, TYPE_ALIGN (type));
-     }
- 
-   else if (TREE_CODE (t) == TARGET_MEM_REF)
-     /* ??? This isn't fully correct, we can't set the alignment from the
-        type in all cases.  */
-     attrs.align = MAX (attrs.align, TYPE_ALIGN (type));
- 
    /* If the size is known, we can set that.  */
    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.  */
    if (! TYPE_P (t))
      {
        tree base;
-       bool align_computed = false;
  
        if (TREE_THIS_VOLATILE (t))
  	MEM_VOLATILE_P (ref) = 1;
--- 1641,1657 ----
    if (objectp || TREE_CODE (t) == INDIRECT_REF || TYPE_ALIGN_OK (type))
      attrs.align = MAX (attrs.align, TYPE_ALIGN (type));
  
    /* If the size is known, we can set that.  */
    tree new_size = TYPE_SIZE_UNIT (type);
  
+   /* The address-space is that of the type.  */
+   as = TYPE_ADDR_SPACE (type);
+ 
    /* If T is not a type, we may be able to deduce some more information about
       the expression.  */
    if (! TYPE_P (t))
      {
        tree base;
  
        if (TREE_THIS_VOLATILE (t))
  	MEM_VOLATILE_P (ref) = 1;
*************** set_mem_attributes_minus_bitpos (rtx ref
*** 1715,1720 ****
--- 1681,1687 ----
  	      && TREE_STATIC (base))
  	    MEM_READONLY_P (ref) = 1;
  
+ 	  /* Address-space information is on the base object.  */
  	  if (TREE_CODE (base) == MEM_REF
  	      || TREE_CODE (base) == TARGET_MEM_REF)
  	    as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (base,
*************** set_mem_attributes_minus_bitpos (rtx ref
*** 1722,1729 ****
  	  else
  	    as = TYPE_ADDR_SPACE (TREE_TYPE (base));
  	}
-       else
- 	as = TYPE_ADDR_SPACE (type);
  
        /* If this expression uses it's parent's alias set, mark it such
  	 that we won't change it.  */
--- 1689,1694 ----
*************** set_mem_attributes_minus_bitpos (rtx ref
*** 1738,1756 ****
  	  attrs.offset = 0;
  	  apply_bitpos = bitpos;
  	  new_size = DECL_SIZE_UNIT (t);
- 	  attrs.align = DECL_ALIGN (t);
- 	  align_computed = true;
  	}
  
!       /* If this is a constant, we know the alignment.  */
        else if (CONSTANT_CLASS_P (t))
! 	{
! 	  attrs.align = TYPE_ALIGN (type);
! #ifdef CONSTANT_ALIGNMENT
! 	  attrs.align = CONSTANT_ALIGNMENT (t, attrs.align);
! #endif
! 	  align_computed = true;
! 	}
  
        /* If this is a field reference, record it.  */
        else if (TREE_CODE (t) == COMPONENT_REF)
--- 1703,1713 ----
  	  attrs.offset = 0;
  	  apply_bitpos = bitpos;
  	  new_size = DECL_SIZE_UNIT (t);
  	}
  
!       /* ???  If we end up with a constant here do record a MEM_EXPR.  */
        else if (CONSTANT_CLASS_P (t))
! 	;
  
        /* If this is a field reference, record it.  */
        else if (TREE_CODE (t) == COMPONENT_REF)
*************** set_mem_attributes_minus_bitpos (rtx ref
*** 1795,1818 ****
  	    }
  	  while (TREE_CODE (t2) == ARRAY_REF);
  
! 	  if (DECL_P (t2))
! 	    {
! 	      attrs.expr = t2;
! 	      attrs.offset_known_p = false;
! 	      if (host_integerp (off_tree, 1))
! 		{
! 		  HOST_WIDE_INT ioff = tree_low_cst (off_tree, 1);
! 		  HOST_WIDE_INT aoff = (ioff & -ioff) * BITS_PER_UNIT;
! 		  attrs.align = DECL_ALIGN (t2);
! 		  if (aoff && (unsigned HOST_WIDE_INT) aoff < attrs.align)
! 	            attrs.align = aoff;
! 		  align_computed = true;
! 		  attrs.offset_known_p = true;
! 		  attrs.offset = ioff;
! 		  apply_bitpos = bitpos;
! 		}
! 	    }
! 	  else if (TREE_CODE (t2) == COMPONENT_REF)
  	    {
  	      attrs.expr = t2;
  	      attrs.offset_known_p = false;
--- 1752,1759 ----
  	    }
  	  while (TREE_CODE (t2) == ARRAY_REF);
  
! 	  if (DECL_P (t2)
! 	      || TREE_CODE (t2) == COMPONENT_REF)
  	    {
  	      attrs.expr = t2;
  	      attrs.offset_known_p = false;
*************** set_mem_attributes_minus_bitpos (rtx ref
*** 1822,1850 ****
  		  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?  */
  	    }
  	}
  
        /* If this is an indirect reference, record it.  */
        else if (TREE_CODE (t) == MEM_REF 
  	       || TREE_CODE (t) == TARGET_MEM_REF)
  	{
  	  attrs.expr = t;
  	  attrs.offset_known_p = true;
  	  attrs.offset = 0;
  	  apply_bitpos = bitpos;
  	}
  
!       if (!align_computed)
! 	{
! 	  unsigned int obj_align = get_object_alignment (t);
! 	  attrs.align = MAX (attrs.align, obj_align);
! 	}
      }
-   else
-     as = TYPE_ADDR_SPACE (type);
  
    if (host_integerp (new_size, 1))
      {
--- 1763,1813 ----
  		  attrs.offset = tree_low_cst (off_tree, 1);
  		  apply_bitpos = bitpos;
  		}
  	    }
+ 	  /* Else do not record a MEM_EXPR.  */
  	}
  
        /* If this is an indirect reference, record it.  */
        else if (TREE_CODE (t) == MEM_REF 
  	       || TREE_CODE (t) == TARGET_MEM_REF)
  	{
+ 	  if (TREE_CODE (t) == MEM_REF)
+ 	    {
+ 	      tree op0 = TREE_OPERAND (t, 0);
+ 	      if (TREE_CODE (op0) == ADDR_EXPR
+ 		  && (DECL_P (TREE_OPERAND (op0, 0))
+ 		      || CONSTANT_CLASS_P (TREE_OPERAND (op0, 0))))
+ 		{
+ 		  attrs.align = get_object_alignment (TREE_OPERAND (op0, 0));
+ 		  if (TREE_INT_CST_LOW (TREE_OPERAND (t, 1)) != 0)
+ 		    {
+ 		      unsigned HOST_WIDE_INT ioff
+ 			= TREE_INT_CST_LOW (TREE_OPERAND (t, 1));
+ 		      unsigned HOST_WIDE_INT aoff
+ 			= (ioff & -ioff) * BITS_PER_UNIT;
+ 		      attrs.align = MIN (aoff, attrs.align);
+ 		    }
+ 		}
+ 	      else
+ 		/* ??? This isn't fully correct, we can't set the alignment
+ 		   from the type in all cases.  */
+ 		attrs.align = MAX (attrs.align, TYPE_ALIGN (type));
+ 	    }
+ 
+ 	  else if (TREE_CODE (t) == TARGET_MEM_REF)
+ 	    /* ??? This isn't fully correct, we can't set the alignment from the
+ 	       type in all cases.  */
+ 	    attrs.align = MAX (attrs.align, TYPE_ALIGN (type));
+ 
  	  attrs.expr = t;
  	  attrs.offset_known_p = true;
  	  attrs.offset = 0;
  	  apply_bitpos = bitpos;
  	}
  
!       unsigned int obj_align = get_object_alignment (t);
!       attrs.align = MAX (attrs.align, obj_align);
      }
  
    if (host_integerp (new_size, 1))
      {



2013-01-10  Richard Biener  <rguenther@suse.de>

	* emit-rtl.c (set_mem_attributes_minus_bitpos): Remove
	alignment computations and rely on get_object_alignment
	for the !TYPE_P case.  Commonize DECL/COMPONENT_REF handling
	in the ARRAY_REF path.

Index: gcc/emit-rtl.c
===================================================================
*** gcc/emit-rtl.c	(revision 195079)
--- gcc/emit-rtl.c	(working copy)
*************** set_mem_attributes_minus_bitpos (rtx ref
*** 1641,1691 ****
    if (objectp || TREE_CODE (t) == INDIRECT_REF || TYPE_ALIGN_OK (type))
      attrs.align = MAX (attrs.align, TYPE_ALIGN (type));
  
-   else if (TREE_CODE (t) == MEM_REF)
-     {
-       tree op0 = TREE_OPERAND (t, 0);
-       if (TREE_CODE (op0) == ADDR_EXPR
- 	  && (DECL_P (TREE_OPERAND (op0, 0))
- 	      || CONSTANT_CLASS_P (TREE_OPERAND (op0, 0))))
- 	{
- 	  if (DECL_P (TREE_OPERAND (op0, 0)))
- 	    attrs.align = DECL_ALIGN (TREE_OPERAND (op0, 0));
- 	  else if (CONSTANT_CLASS_P (TREE_OPERAND (op0, 0)))
- 	    {
- 	      attrs.align = TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (op0, 0)));
- #ifdef CONSTANT_ALIGNMENT
- 	      attrs.align = CONSTANT_ALIGNMENT (TREE_OPERAND (op0, 0),
- 						attrs.align);
- #endif
- 	    }
- 	  if (TREE_INT_CST_LOW (TREE_OPERAND (t, 1)) != 0)
- 	    {
- 	      unsigned HOST_WIDE_INT ioff
- 		= TREE_INT_CST_LOW (TREE_OPERAND (t, 1));
- 	      unsigned HOST_WIDE_INT aoff = (ioff & -ioff) * BITS_PER_UNIT;
- 	      attrs.align = MIN (aoff, attrs.align);
- 	    }
- 	}
-       else
- 	/* ??? This isn't fully correct, we can't set the alignment from the
- 	   type in all cases.  */
- 	attrs.align = MAX (attrs.align, TYPE_ALIGN (type));
-     }
- 
-   else if (TREE_CODE (t) == TARGET_MEM_REF)
-     /* ??? This isn't fully correct, we can't set the alignment from the
-        type in all cases.  */
-     attrs.align = MAX (attrs.align, TYPE_ALIGN (type));
- 
    /* If the size is known, we can set that.  */
    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.  */
    if (! TYPE_P (t))
      {
        tree base;
-       bool align_computed = false;
  
        if (TREE_THIS_VOLATILE (t))
  	MEM_VOLATILE_P (ref) = 1;
--- 1641,1657 ----
    if (objectp || TREE_CODE (t) == INDIRECT_REF || TYPE_ALIGN_OK (type))
      attrs.align = MAX (attrs.align, TYPE_ALIGN (type));
  
    /* If the size is known, we can set that.  */
    tree new_size = TYPE_SIZE_UNIT (type);
  
+   /* The address-space is that of the type.  */
+   as = TYPE_ADDR_SPACE (type);
+ 
    /* If T is not a type, we may be able to deduce some more information about
       the expression.  */
    if (! TYPE_P (t))
      {
        tree base;
  
        if (TREE_THIS_VOLATILE (t))
  	MEM_VOLATILE_P (ref) = 1;
*************** set_mem_attributes_minus_bitpos (rtx ref
*** 1715,1720 ****
--- 1681,1687 ----
  	      && TREE_STATIC (base))
  	    MEM_READONLY_P (ref) = 1;
  
+ 	  /* Address-space information is on the base object.  */
  	  if (TREE_CODE (base) == MEM_REF
  	      || TREE_CODE (base) == TARGET_MEM_REF)
  	    as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (base,
*************** set_mem_attributes_minus_bitpos (rtx ref
*** 1722,1729 ****
  	  else
  	    as = TYPE_ADDR_SPACE (TREE_TYPE (base));
  	}
-       else
- 	as = TYPE_ADDR_SPACE (type);
  
        /* If this expression uses it's parent's alias set, mark it such
  	 that we won't change it.  */
--- 1689,1694 ----
*************** set_mem_attributes_minus_bitpos (rtx ref
*** 1738,1756 ****
  	  attrs.offset = 0;
  	  apply_bitpos = bitpos;
  	  new_size = DECL_SIZE_UNIT (t);
- 	  attrs.align = DECL_ALIGN (t);
- 	  align_computed = true;
  	}
  
!       /* If this is a constant, we know the alignment.  */
        else if (CONSTANT_CLASS_P (t))
! 	{
! 	  attrs.align = TYPE_ALIGN (type);
! #ifdef CONSTANT_ALIGNMENT
! 	  attrs.align = CONSTANT_ALIGNMENT (t, attrs.align);
! #endif
! 	  align_computed = true;
! 	}
  
        /* If this is a field reference, record it.  */
        else if (TREE_CODE (t) == COMPONENT_REF)
--- 1703,1713 ----
  	  attrs.offset = 0;
  	  apply_bitpos = bitpos;
  	  new_size = DECL_SIZE_UNIT (t);
  	}
  
!       /* ???  If we end up with a constant here do record a MEM_EXPR.  */
        else if (CONSTANT_CLASS_P (t))
! 	;
  
        /* If this is a field reference, record it.  */
        else if (TREE_CODE (t) == COMPONENT_REF)
*************** set_mem_attributes_minus_bitpos (rtx ref
*** 1795,1818 ****
  	    }
  	  while (TREE_CODE (t2) == ARRAY_REF);
  
! 	  if (DECL_P (t2))
! 	    {
! 	      attrs.expr = t2;
! 	      attrs.offset_known_p = false;
! 	      if (host_integerp (off_tree, 1))
! 		{
! 		  HOST_WIDE_INT ioff = tree_low_cst (off_tree, 1);
! 		  HOST_WIDE_INT aoff = (ioff & -ioff) * BITS_PER_UNIT;
! 		  attrs.align = DECL_ALIGN (t2);
! 		  if (aoff && (unsigned HOST_WIDE_INT) aoff < attrs.align)
! 	            attrs.align = aoff;
! 		  align_computed = true;
! 		  attrs.offset_known_p = true;
! 		  attrs.offset = ioff;
! 		  apply_bitpos = bitpos;
! 		}
! 	    }
! 	  else if (TREE_CODE (t2) == COMPONENT_REF)
  	    {
  	      attrs.expr = t2;
  	      attrs.offset_known_p = false;
--- 1752,1759 ----
  	    }
  	  while (TREE_CODE (t2) == ARRAY_REF);
  
! 	  if (DECL_P (t2)
! 	      || TREE_CODE (t2) == COMPONENT_REF)
  	    {
  	      attrs.expr = t2;
  	      attrs.offset_known_p = false;
*************** set_mem_attributes_minus_bitpos (rtx ref
*** 1822,1830 ****
  		  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?  */
  	    }
  	}
  
        /* If this is an indirect reference, record it.  */
--- 1763,1770 ----
  		  attrs.offset = tree_low_cst (off_tree, 1);
  		  apply_bitpos = bitpos;
  		}
  	    }
+ 	  /* Else do not record a MEM_EXPR.  */
  	}
  
        /* If this is an indirect reference, record it.  */
*************** set_mem_attributes_minus_bitpos (rtx ref
*** 1837,1850 ****
  	  apply_bitpos = bitpos;
  	}
  
!       if (!align_computed)
! 	{
! 	  unsigned int obj_align = get_object_alignment (t);
! 	  attrs.align = MAX (attrs.align, obj_align);
! 	}
      }
-   else
-     as = TYPE_ADDR_SPACE (type);
  
    if (host_integerp (new_size, 1))
      {
--- 1777,1784 ----
  	  apply_bitpos = bitpos;
  	}
  
!       attrs.align = get_object_alignment (t);
      }
  
    if (host_integerp (new_size, 1))
      {
Eric Botcazou Jan. 10, 2013, 12:22 p.m. UTC | #4
> Going over this what's strange as well is that we adjust MEM_SIZE
> with bitpos, too.  At least when the MEM has non-BLKmode this
> means that MEMs mode and MEM_SIZE is inconsistent?  Or how do
> a MEMs mode and MEM_SIZE relate?

Yes, the MEM attributes are incomplete/inconsistent between the call to 
set_mem_attributes_minus_bitpos and the subsequent adjustment by bitpos.
That's why only the final result should matter and need be correct.

Let me try to forge my own opinion on the PR before answering further.
Michael Matz Jan. 10, 2013, 1:24 p.m. UTC | #5
Hi,

On Thu, 10 Jan 2013, Eric Botcazou wrote:

> > Going over this what's strange as well is that we adjust MEM_SIZE
> > with bitpos, too.  At least when the MEM has non-BLKmode this
> > means that MEMs mode and MEM_SIZE is inconsistent?  Or how do
> > a MEMs mode and MEM_SIZE relate?
> 
> Yes, the MEM attributes are incomplete/inconsistent between the call to 
> set_mem_attributes_minus_bitpos and the subsequent adjustment by bitpos.

The problem with this intermediate inconsistency is that ...

> That's why only the final result should matter and need be correct.

... this can't be ensured anymore.  In some cases the inconsistency 
between the mem attributes and what XEXP(MEM, 0) represents can't be 
repaired by the later bitpos adjustments, or better it can be only be
repaired by falling back to the conservative side for e.g. the alignment, 
because we don't store enough information in the mem attributes to recover 
what was lost.

When briefly discussing this yesterday I suggested (without having the 
code in front of me) that it be best to simply set the mem attributes only 
at the very end, after having computed to final MEM address including all 
adjustments, instead of generating wrong mem attributes initially and 
hoping for the adjustments to make it come out right at the end.


Ciao,
Michael.
Eric Botcazou Jan. 10, 2013, 6:52 p.m. UTC | #6
> The problem with this intermediate inconsistency is that ...
> 
> > That's why only the final result should matter and need be correct.
> 
> ... this can't be ensured anymore.  In some cases the inconsistency
> between the mem attributes and what XEXP(MEM, 0) represents can't be
> repaired by the later bitpos adjustments, or better it can be only be
> repaired by falling back to the conservative side for e.g. the alignment,
> because we don't store enough information in the mem attributes to recover
> what was lost.

Indeed, looking at the history of the code shows that the alignment handling 
via MEM_REF and get_object_alignment is an afterthought.  Originally, it was 
set only in a few specific cases:

  /* We can set the alignment from the type if we are making an object,
     this is an INDIRECT_REF, or if TYPE_ALIGN_OK.  */

and also for DECL_P and CONSTANT_CLASS_P.  That was it, so this was actually 
the alignment of the base and disregarding BITPOS was fine.

> When briefly discussing this yesterday I suggested (without having the
> code in front of me) that it be best to simply set the mem attributes only
> at the very end, after having computed to final MEM address including all
> adjustments, instead of generating wrong mem attributes initially and
> hoping for the adjustments to make it come out right at the end.

Maybe, but for 4.7 (and probably 4.8) I think we should be conservative and 
only fix the problems recently introduced.

So, in the end, I think that we should go either for Richard's initial patch 
in this thread, possibly with a ??? comment along the lines of:

	/* ??? If we haven't computed the alignment yet, compute it now.  Note
	    that, if already computed above, the alignment is that of the base
	    object of T so it is OK to have disregarded BITPOS above.  However,
	    here we are using get_object_alignment_1 which returns the precise
	    alignment of T so we need to account for the BITPOS adjustment.  */
	if (!align_computed)

or for Richard's initial patch + the removal of the MEM_REF block (which is 
midway between Richard's initial patch and Richard's last patch).
Richard Biener Jan. 11, 2013, 10:24 a.m. UTC | #7
On Thu, 10 Jan 2013, Eric Botcazou wrote:

> > The problem with this intermediate inconsistency is that ...
> > 
> > > That's why only the final result should matter and need be correct.
> > 
> > ... this can't be ensured anymore.  In some cases the inconsistency
> > between the mem attributes and what XEXP(MEM, 0) represents can't be
> > repaired by the later bitpos adjustments, or better it can be only be
> > repaired by falling back to the conservative side for e.g. the alignment,
> > because we don't store enough information in the mem attributes to recover
> > what was lost.
> 
> Indeed, looking at the history of the code shows that the alignment handling 
> via MEM_REF and get_object_alignment is an afterthought.  Originally, it was 
> set only in a few specific cases:
> 
>   /* We can set the alignment from the type if we are making an object,
>      this is an INDIRECT_REF, or if TYPE_ALIGN_OK.  */
> 
> and also for DECL_P and CONSTANT_CLASS_P.  That was it, so this was actually 
> the alignment of the base and disregarding BITPOS was fine.

Yes, in these cases bitpos is zero.  It's wrong in the !align_computed
path and possibly in the ARRAY_REF -> DECL_P path (only not as
optimistic as it could be).

> > When briefly discussing this yesterday I suggested (without having the
> > code in front of me) that it be best to simply set the mem attributes only
> > at the very end, after having computed to final MEM address including all
> > adjustments, instead of generating wrong mem attributes initially and
> > hoping for the adjustments to make it come out right at the end.
> 
> Maybe, but for 4.7 (and probably 4.8) I think we should be conservative and 
> only fix the problems recently introduced.
> 
> So, in the end, I think that we should go either for Richard's initial patch 
> in this thread, possibly with a ??? comment along the lines of:
> 
> 	/* ??? If we haven't computed the alignment yet, compute it now.  Note
> 	    that, if already computed above, the alignment is that of the base
> 	    object of T so it is OK to have disregarded BITPOS above.  However,
> 	    here we are using get_object_alignment_1 which returns the precise
> 	    alignment of T so we need to account for the BITPOS adjustment.  */
> 	if (!align_computed)
> 
> or for Richard's initial patch + the removal of the MEM_REF block (which is 
> midway between Richard's initial patch and Richard's last patch).

Thus I'm preparing a patch that applies to both 4.7 and 4.8 at this
point, leaving some holes I see open (which are not to be closed in
the same way due to differences in behavior of get_object_alignment
on the 4.7 branch vs. trunk).

Bootstrap and regtest on x86_64-unknown-linux-gnu running, Eric,
can you give this a strict-align target testing on the 4.7 branch?
Martin, can you re-test this on sparc (it's slightly different again)?

I'm going to remove the MEM_REF block as a followup (we can't backport
that due to pessimizations this will cause due to different
get_object_alignment behavior - yet, unless we backport that change
as well), it's a source of wrong alignment as well, due to the
usage of MAX () - the get_object_alignment result will never shrink
alignment this way (and thus implicitely relies on attrs.align
being BITS_PER_UNIT when !align_computed).

The get_object_alignment behavior change is

2012-07-18  Richard Guenther  <rguenther@suse.de>

        * tree.h (get_object_or_type_alignment): Remove.
        * builtins.c (get_object_alignment_2): New function copied from
        get_object_alignment_1.  Take extra argument to indicate whether
        we take the address of EXP.  Rework to use type alignment 
information
        if not, and return whether the result is an approximation or not.
        (get_object_alignment_1): Wrap around get_object_alignment_2.
        (get_pointer_alignment_1): Call get_object_alignment_2 indicating
        we take the address.
        (get_object_or_type_alignment): Remove.
        * expr.c (expand_assignment): Call get_object_alignment.
        (expand_expr_real_1): Likewise.

and followups.

Thanks,
Richard.

2013-01-11  Richard Biener  <rguenther@suse.de>

	PR middle-end/55882
	* emit-rtl.c (set_mem_attributes_minus_bitpos): Correctly
	account for bitpos when computing alignment.

	* gcc.dg/torture/pr55882.c: New testcase.

Index: gcc/emit-rtl.c
===================================================================
*** gcc/emit-rtl.c	(revision 195102)
--- gcc/emit-rtl.c	(working copy)
*************** set_mem_attributes_minus_bitpos (rtx ref
*** 1839,1845 ****
  
        if (!align_computed)
  	{
! 	  unsigned int obj_align = get_object_alignment (t);
  	  attrs.align = MAX (attrs.align, obj_align);
  	}
      }
--- 1839,1850 ----
  
        if (!align_computed)
  	{
! 	  unsigned int obj_align;
! 	  unsigned HOST_WIDE_INT obj_bitpos;
! 	  get_object_alignment_1 (t, &obj_align, &obj_bitpos);
! 	  obj_bitpos = (obj_bitpos - bitpos) & (obj_align - 1);
! 	  if (obj_bitpos != 0)
! 	    obj_align = (obj_bitpos & -obj_bitpos);
  	  attrs.align = MAX (attrs.align, obj_align);
  	}
      }
Index: gcc/testsuite/gcc.dg/torture/pr55882.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr55882.c	(revision 0)
--- gcc/testsuite/gcc.dg/torture/pr55882.c	(working copy)
***************
*** 0 ****
--- 1,94 ----
+ /* { dg-do run } */
+ 
+ typedef enum
+ {
+   PVT_A = 0,
+   PVT_B = 1,
+   PVT_CONFIG = 2,
+   PVT_RESERVED3 = 3,
+ } T_CR_SELECT;
+ 
+ typedef enum
+ {
+   STD_ULOGIC_0 = 0,
+   STD_ULOGIC_1 = 1,
+ } STD_ULOGIC;
+ 
+ typedef struct
+ {
+   unsigned char rtp : 3;
+   unsigned char rtn : 3;
+ } C;
+ 
+ typedef struct
+ {
+   unsigned char nd;
+   unsigned char pd;
+   unsigned char rtn;
+   unsigned char rtp;
+ } A;
+ 
+ typedef struct
+ {
+   unsigned short reserved : 14;
+   unsigned char Z_rx_enable : 2;
+   A pvt;
+ } B;
+ 
+ typedef struct
+ {
+   B cr_dsclk_q3;
+   B cr_data_q3;
+   B cr_addr_q3;
+   B cr_cmd_q3;
+   B cr_pres_q3;
+   C cr_vref_q3[6];
+   unsigned char pres_disable;
+   unsigned char pres_drive_high;
+   unsigned char c_enab_120;
+   STD_ULOGIC clk_tximp;
+   STD_ULOGIC dqs_tximp;
+   STD_ULOGIC cmd_tximp;
+   STD_ULOGIC data_tximp;
+   STD_ULOGIC dqs_rxterm;
+   STD_ULOGIC data_rxterm;
+   T_CR_SELECT cr_clk_sel;
+   unsigned char cr_clk : 5;
+   T_CR_SELECT cr_dsclk_odd_sel;
+   unsigned char cr_dsclk_odd : 5;
+   T_CR_SELECT cr_dsclk_even_sel;
+   unsigned char cr_dsclk_even : 5;
+   T_CR_SELECT cr_data_sel;
+   unsigned char cr_data : 5;
+   T_CR_SELECT cr_vref_sel;
+   unsigned char cr_vref : 5;
+   T_CR_SELECT cr_others_sel;
+   unsigned char cr_others : 5;
+ } CONFIG;
+ 
+ typedef struct
+ {
+   unsigned char enable_monitor;
+   unsigned short step_out_pointer : 12;
+   unsigned short hold_out_pointer : 12;
+   unsigned short enable_wr_dqs : 12;
+   unsigned short use_alt_rd_dqs : 12;
+   CONFIG io_buf;
+ } mystruct;
+ 
+ unsigned short __attribute__((noinline,noclone))
+ testfunction(unsigned i)
+ {
+   mystruct dmfe[8];
+   dmfe[0].use_alt_rd_dqs = 1;
+   dmfe[i].use_alt_rd_dqs = 0;
+   return dmfe[0].use_alt_rd_dqs;
+ }
+ 
+ extern void abort (void);
+ int main ()
+ {
+   if (testfunction(0) != 0) 
+     abort ();
+   return 0;
+ }
Richard Biener Jan. 15, 2013, 12:48 p.m. UTC | #8
On Fri, 11 Jan 2013, Richard Biener wrote:

> On Thu, 10 Jan 2013, Eric Botcazou wrote:
> 
> > > The problem with this intermediate inconsistency is that ...
> > > 
> > > > That's why only the final result should matter and need be correct.
> > > 
> > > ... this can't be ensured anymore.  In some cases the inconsistency
> > > between the mem attributes and what XEXP(MEM, 0) represents can't be
> > > repaired by the later bitpos adjustments, or better it can be only be
> > > repaired by falling back to the conservative side for e.g. the alignment,
> > > because we don't store enough information in the mem attributes to recover
> > > what was lost.
> > 
> > Indeed, looking at the history of the code shows that the alignment handling 
> > via MEM_REF and get_object_alignment is an afterthought.  Originally, it was 
> > set only in a few specific cases:
> > 
> >   /* We can set the alignment from the type if we are making an object,
> >      this is an INDIRECT_REF, or if TYPE_ALIGN_OK.  */
> > 
> > and also for DECL_P and CONSTANT_CLASS_P.  That was it, so this was actually 
> > the alignment of the base and disregarding BITPOS was fine.
> 
> Yes, in these cases bitpos is zero.  It's wrong in the !align_computed
> path and possibly in the ARRAY_REF -> DECL_P path (only not as
> optimistic as it could be).
> 
> > > When briefly discussing this yesterday I suggested (without having the
> > > code in front of me) that it be best to simply set the mem attributes only
> > > at the very end, after having computed to final MEM address including all
> > > adjustments, instead of generating wrong mem attributes initially and
> > > hoping for the adjustments to make it come out right at the end.
> > 
> > Maybe, but for 4.7 (and probably 4.8) I think we should be conservative and 
> > only fix the problems recently introduced.
> > 
> > So, in the end, I think that we should go either for Richard's initial patch 
> > in this thread, possibly with a ??? comment along the lines of:
> > 
> > 	/* ??? If we haven't computed the alignment yet, compute it now.  Note
> > 	    that, if already computed above, the alignment is that of the base
> > 	    object of T so it is OK to have disregarded BITPOS above.  However,
> > 	    here we are using get_object_alignment_1 which returns the precise
> > 	    alignment of T so we need to account for the BITPOS adjustment.  */
> > 	if (!align_computed)
> > 
> > or for Richard's initial patch + the removal of the MEM_REF block (which is 
> > midway between Richard's initial patch and Richard's last patch).
> 
> Thus I'm preparing a patch that applies to both 4.7 and 4.8 at this
> point, leaving some holes I see open (which are not to be closed in
> the same way due to differences in behavior of get_object_alignment
> on the 4.7 branch vs. trunk).
> 
> Bootstrap and regtest on x86_64-unknown-linux-gnu running, Eric,
> can you give this a strict-align target testing on the 4.7 branch?
> Martin, can you re-test this on sparc (it's slightly different again)?
> 
> I'm going to remove the MEM_REF block as a followup (we can't backport
> that due to pessimizations this will cause due to different
> get_object_alignment behavior - yet, unless we backport that change
> as well), it's a source of wrong alignment as well, due to the
> usage of MAX () - the get_object_alignment result will never shrink
> alignment this way (and thus implicitely relies on attrs.align
> being BITS_PER_UNIT when !align_computed).
> 
> The get_object_alignment behavior change is
> 
> 2012-07-18  Richard Guenther  <rguenther@suse.de>
> 
>         * tree.h (get_object_or_type_alignment): Remove.
>         * builtins.c (get_object_alignment_2): New function copied from
>         get_object_alignment_1.  Take extra argument to indicate whether
>         we take the address of EXP.  Rework to use type alignment 
> information
>         if not, and return whether the result is an approximation or not.
>         (get_object_alignment_1): Wrap around get_object_alignment_2.
>         (get_pointer_alignment_1): Call get_object_alignment_2 indicating
>         we take the address.
>         (get_object_or_type_alignment): Remove.
>         * expr.c (expand_assignment): Call get_object_alignment.
>         (expand_expr_real_1): Likewise.
> 
> and followups.

I have applied the minimal fix to trunk now.  We retain the clearly
incorrect fact that the !align_computed path only ever increases
alignment (it's only ever set previously to either BITS_PER_UNIT
or via the MEM_REF block).  I will momentarily test a followup
removing that block for trunk.

Thanks,
Richard.

> Thanks,
> Richard.
> 
> 2013-01-11  Richard Biener  <rguenther@suse.de>
> 
> 	PR middle-end/55882
> 	* emit-rtl.c (set_mem_attributes_minus_bitpos): Correctly
> 	account for bitpos when computing alignment.
> 
> 	* gcc.dg/torture/pr55882.c: New testcase.
> 
> Index: gcc/emit-rtl.c
> ===================================================================
> *** gcc/emit-rtl.c	(revision 195102)
> --- gcc/emit-rtl.c	(working copy)
> *************** set_mem_attributes_minus_bitpos (rtx ref
> *** 1839,1845 ****
>   
>         if (!align_computed)
>   	{
> ! 	  unsigned int obj_align = get_object_alignment (t);
>   	  attrs.align = MAX (attrs.align, obj_align);
>   	}
>       }
> --- 1839,1850 ----
>   
>         if (!align_computed)
>   	{
> ! 	  unsigned int obj_align;
> ! 	  unsigned HOST_WIDE_INT obj_bitpos;
> ! 	  get_object_alignment_1 (t, &obj_align, &obj_bitpos);
> ! 	  obj_bitpos = (obj_bitpos - bitpos) & (obj_align - 1);
> ! 	  if (obj_bitpos != 0)
> ! 	    obj_align = (obj_bitpos & -obj_bitpos);
>   	  attrs.align = MAX (attrs.align, obj_align);
>   	}
>       }
> Index: gcc/testsuite/gcc.dg/torture/pr55882.c
> ===================================================================
> *** gcc/testsuite/gcc.dg/torture/pr55882.c	(revision 0)
> --- gcc/testsuite/gcc.dg/torture/pr55882.c	(working copy)
> ***************
> *** 0 ****
> --- 1,94 ----
> + /* { dg-do run } */
> + 
> + typedef enum
> + {
> +   PVT_A = 0,
> +   PVT_B = 1,
> +   PVT_CONFIG = 2,
> +   PVT_RESERVED3 = 3,
> + } T_CR_SELECT;
> + 
> + typedef enum
> + {
> +   STD_ULOGIC_0 = 0,
> +   STD_ULOGIC_1 = 1,
> + } STD_ULOGIC;
> + 
> + typedef struct
> + {
> +   unsigned char rtp : 3;
> +   unsigned char rtn : 3;
> + } C;
> + 
> + typedef struct
> + {
> +   unsigned char nd;
> +   unsigned char pd;
> +   unsigned char rtn;
> +   unsigned char rtp;
> + } A;
> + 
> + typedef struct
> + {
> +   unsigned short reserved : 14;
> +   unsigned char Z_rx_enable : 2;
> +   A pvt;
> + } B;
> + 
> + typedef struct
> + {
> +   B cr_dsclk_q3;
> +   B cr_data_q3;
> +   B cr_addr_q3;
> +   B cr_cmd_q3;
> +   B cr_pres_q3;
> +   C cr_vref_q3[6];
> +   unsigned char pres_disable;
> +   unsigned char pres_drive_high;
> +   unsigned char c_enab_120;
> +   STD_ULOGIC clk_tximp;
> +   STD_ULOGIC dqs_tximp;
> +   STD_ULOGIC cmd_tximp;
> +   STD_ULOGIC data_tximp;
> +   STD_ULOGIC dqs_rxterm;
> +   STD_ULOGIC data_rxterm;
> +   T_CR_SELECT cr_clk_sel;
> +   unsigned char cr_clk : 5;
> +   T_CR_SELECT cr_dsclk_odd_sel;
> +   unsigned char cr_dsclk_odd : 5;
> +   T_CR_SELECT cr_dsclk_even_sel;
> +   unsigned char cr_dsclk_even : 5;
> +   T_CR_SELECT cr_data_sel;
> +   unsigned char cr_data : 5;
> +   T_CR_SELECT cr_vref_sel;
> +   unsigned char cr_vref : 5;
> +   T_CR_SELECT cr_others_sel;
> +   unsigned char cr_others : 5;
> + } CONFIG;
> + 
> + typedef struct
> + {
> +   unsigned char enable_monitor;
> +   unsigned short step_out_pointer : 12;
> +   unsigned short hold_out_pointer : 12;
> +   unsigned short enable_wr_dqs : 12;
> +   unsigned short use_alt_rd_dqs : 12;
> +   CONFIG io_buf;
> + } mystruct;
> + 
> + unsigned short __attribute__((noinline,noclone))
> + testfunction(unsigned i)
> + {
> +   mystruct dmfe[8];
> +   dmfe[0].use_alt_rd_dqs = 1;
> +   dmfe[i].use_alt_rd_dqs = 0;
> +   return dmfe[0].use_alt_rd_dqs;
> + }
> + 
> + extern void abort (void);
> + int main ()
> + {
> +   if (testfunction(0) != 0) 
> +     abort ();
> +   return 0;
> + }
>
Eric Botcazou Jan. 15, 2013, 2:44 p.m. UTC | #9
> I have applied the minimal fix to trunk now.  We retain the clearly
> incorrect fact that the !align_computed path only ever increases
> alignment (it's only ever set previously to either BITS_PER_UNIT
> or via the MEM_REF block).  I will momentarily test a followup
> removing that block for trunk.

What do we do for the 4.7 branch?  The patch doesn't compile for it so I 
presume that there are one or more changes to be backported first?
diff mbox

Patch

Index: gcc/emit-rtl.c
===================================================================
--- gcc/emit-rtl.c	(revision 195014)
+++ gcc/emit-rtl.c	(working copy)
@@ -1839,7 +1839,12 @@  set_mem_attributes_minus_bitpos (rtx ref
 
       if (!align_computed)
 	{
-	  unsigned int obj_align = get_object_alignment (t);
+	  unsigned int obj_align;
+	  unsigned HOST_WIDE_INT obj_bitpos;
+	  get_object_alignment_1 (t, &obj_align, &obj_bitpos);
+	  obj_bitpos = (obj_bitpos - apply_bitpos) & (obj_align - 1);
+	  if (obj_bitpos != 0)
+	    obj_align = (obj_bitpos & -obj_bitpos);
 	  attrs.align = MAX (attrs.align, obj_align);
 	}
     }