This fixes the issue that SRA creates access replacements that cannot
represent all values that can be represented with the storage of the
access.  The simple thing to do is to create an access replacement
with a type that covers the whole access.

Of course there is the catch that we cannot do that (easily) for
bitfield accesses, so leave those alone for now.

Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk.

Richard.

2012-02-14  Richard Guenther  <rguent...@suse.de>

        PR tree-optimization/52244
        PR tree-optimization/51528
        * tree-sra.c (analyze_access_subtree): Only create INTEGER_TYPE
        replacements for integral types.

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

Index: gcc/tree-sra.c
===================================================================
*** gcc/tree-sra.c      (revision 184203)
--- gcc/tree-sra.c      (working copy)
*************** analyze_access_subtree (struct access *r
*** 2172,2182 ****
              && (root->grp_scalar_write || root->grp_assignment_write))))
      {
        bool new_integer_type;
!       if (TREE_CODE (root->type) == ENUMERAL_TYPE)
        {
          tree rt = root->type;
!         root->type = build_nonstandard_integer_type (TYPE_PRECISION (rt),
                                                       TYPE_UNSIGNED (rt));
          new_integer_type = true;
        }
        else
--- 2172,2192 ----
              && (root->grp_scalar_write || root->grp_assignment_write))))
      {
        bool new_integer_type;
!       /* Always create access replacements that cover the whole access.
!          For integral types this means the precision has to match.
!        Avoid assumptions based on the integral type kind, too.  */
!       if (INTEGRAL_TYPE_P (root->type)
!         && (TREE_CODE (root->type) != INTEGER_TYPE
!             || TYPE_PRECISION (root->type) != root->size)
!         /* But leave bitfield accesses alone.  */
!         && (root->offset % BITS_PER_UNIT) == 0)
        {
          tree rt = root->type;
!         root->type = build_nonstandard_integer_type (root->size,
                                                       TYPE_UNSIGNED (rt));
+         root->expr = build_ref_for_offset (UNKNOWN_LOCATION,
+                                            root->base, root->offset,
+                                            root->type, NULL, false);
          new_integer_type = true;
        }
        else
Index: gcc/testsuite/gcc.dg/torture/pr52244.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr52244.c      (revision 0)
--- gcc/testsuite/gcc.dg/torture/pr52244.c      (revision 0)
***************
*** 0 ****
--- 1,36 ----
+ /* { dg-do run } */
+ 
+ extern void abort (void);
+ 
+ typedef union u_r 
+ {
+   _Bool b;
+   unsigned char c;
+ } u_t;
+ 
+ u_t
+ bar (void)
+ {
+   u_t u;
+   u.c = 0x12;
+   return u;
+ }
+ 
+ u_t  __attribute__ ((noinline))
+ foo (void)
+ {
+   u_t u;
+ 
+   u.b = 1;
+   u = bar ();
+ 
+   return u;
+ }
+ 
+ int main (int argc, char **argv)
+ {
+   u_t u = foo ();
+   if (u.c != 0x12)
+     abort ();
+   return 0;
+ }

Reply via email to