This fixes offsetted constraint handling in the constraint builder
and the solver.  The existing code didn't consider non-equal-sized
fields and thus missed including all those that are overlapping
a offsetted variable.

Fixed like the following, bootstrapped and tested on 
x86_64-unknown-linux-gnu and applied to trunk sofar
(needs massaging to apply to 4.8 or 4.7).

[bah, points-to should support unit-testing - it's incredibly hard
to cover all bases - the testcases cover only two touched paths,
maybe time to revive and improve my -Otest idea...]

Richard.

2014-03-11  Richard Biener  <rguent...@suse.de>

        PR tree-optimization/60429
        PR tree-optimization/60485
        * tree-ssa-structalias.c (set_union_with_increment): Properly
        take into account all fields that overlap the shifted vars.
        (do_sd_constraint): Likewise.
        (do_ds_constraint): Likewise.
        (get_constraint_for_ptr_offset): Likewise.

        * gcc.dg/pr60485-1.c: New testcase.
        * gcc.dg/pr60485-2.c: Likewise.

Index: gcc/tree-ssa-structalias.c
===================================================================
*** gcc/tree-ssa-structalias.c  (revision 208448)
--- gcc/tree-ssa-structalias.c  (working copy)
*************** set_union_with_increment  (bitmap to, bi
*** 993,1015 ****
        changed |= bitmap_set_bit (to, i);
        else
        {
!         unsigned HOST_WIDE_INT fieldoffset = vi->offset + inc;
  
          /* If the offset makes the pointer point to before the
             variable use offset zero for the field lookup.  */
!         if (inc < 0
!             && fieldoffset > vi->offset)
!           fieldoffset = 0;
! 
!         vi = first_or_preceding_vi_for_offset (vi, fieldoffset);
! 
!         changed |= bitmap_set_bit (to, vi->id);
!         /* If the result is not exactly at fieldoffset include the next
!            field as well.  See get_constraint_for_ptr_offset for more
!            rationale.  */
!         if (vi->offset != fieldoffset
!             && vi->next != 0)
!           changed |= bitmap_set_bit (to, vi->next);
        }
      }
  
--- 993,1020 ----
        changed |= bitmap_set_bit (to, i);
        else
        {
!         HOST_WIDE_INT fieldoffset = vi->offset + inc;
!         unsigned HOST_WIDE_INT size = vi->size;
  
          /* If the offset makes the pointer point to before the
             variable use offset zero for the field lookup.  */
!         if (fieldoffset < 0)
!           vi = get_varinfo (vi->head);
!         else
!           vi = first_or_preceding_vi_for_offset (vi, fieldoffset);
! 
!         do
!           {
!             changed |= bitmap_set_bit (to, vi->id);
!             if (vi->is_full_var
!                 || vi->next == 0)
!               break;
! 
!             /* We have to include all fields that overlap the current field
!                shifted by inc.  */
!             vi = vi_next (vi);
!           }
!         while (vi->offset < fieldoffset + size);
        }
      }
  
*************** do_sd_constraint (constraint_graph_t gra
*** 1618,1633 ****
      {
        varinfo_t v = get_varinfo (j);
        HOST_WIDE_INT fieldoffset = v->offset + roffset;
        unsigned int t;
  
        if (v->is_full_var)
!       fieldoffset = v->offset;
        else if (roffset != 0)
!       v = first_vi_for_offset (v, fieldoffset);
!       /* If the access is outside of the variable we can ignore it.  */
!       if (!v)
!       continue;
  
        do
        {
          t = find (v->id);
--- 1623,1643 ----
      {
        varinfo_t v = get_varinfo (j);
        HOST_WIDE_INT fieldoffset = v->offset + roffset;
+       unsigned HOST_WIDE_INT size = v->size;
        unsigned int t;
  
        if (v->is_full_var)
!       ;
        else if (roffset != 0)
!       {
!         if (fieldoffset < 0)
!           v = get_varinfo (v->head);
!         else
!           v = first_or_preceding_vi_for_offset (v, fieldoffset);
!       }
  
+       /* We have to include all fields that overlap the current field
+        shifted by roffset.  */
        do
        {
          t = find (v->id);
*************** do_sd_constraint (constraint_graph_t gra
*** 1644,1659 ****
                   && add_graph_edge (graph, lhs, t))
            flag |= bitmap_ior_into (sol, get_varinfo (t)->solution);
  
!         /* If the variable is not exactly at the requested offset
!            we have to include the next one.  */
!         if (v->offset == (unsigned HOST_WIDE_INT)fieldoffset
              || v->next == 0)
            break;
  
          v = vi_next (v);
-         fieldoffset = v->offset;
        }
!       while (1);
      }
  
  done:
--- 1654,1666 ----
                   && add_graph_edge (graph, lhs, t))
            flag |= bitmap_ior_into (sol, get_varinfo (t)->solution);
  
!         if (v->is_full_var
              || v->next == 0)
            break;
  
          v = vi_next (v);
        }
!       while (v->offset < fieldoffset + size);
      }
  
  done:
*************** do_ds_constraint (constraint_t c, bitmap
*** 1716,1730 ****
        varinfo_t v = get_varinfo (j);
        unsigned int t;
        HOST_WIDE_INT fieldoffset = v->offset + loff;
  
        if (v->is_full_var)
!       fieldoffset = v->offset;
        else if (loff != 0)
!       v = first_vi_for_offset (v, fieldoffset);
!       /* If the access is outside of the variable we can ignore it.  */
!       if (!v)
!       continue;
  
        do
        {
          if (v->may_have_pointers)
--- 1723,1742 ----
        varinfo_t v = get_varinfo (j);
        unsigned int t;
        HOST_WIDE_INT fieldoffset = v->offset + loff;
+       unsigned HOST_WIDE_INT size = v->size;
  
        if (v->is_full_var)
!       ;
        else if (loff != 0)
!       {
!         if (fieldoffset < 0)
!           v = get_varinfo (v->head);
!         else
!           v = first_or_preceding_vi_for_offset (v, fieldoffset);
!       }
  
+       /* We have to include all fields that overlap the current field
+        shifted by loff.  */
        do
        {
          if (v->may_have_pointers)
*************** do_ds_constraint (constraint_t c, bitmap
*** 1750,1765 ****
                bitmap_set_bit (changed, t);
            }
  
!         /* If the variable is not exactly at the requested offset
!            we have to include the next one.  */
!         if (v->offset == (unsigned HOST_WIDE_INT)fieldoffset
              || v->next == 0)
            break;
  
          v = vi_next (v);
-         fieldoffset = v->offset;
        }
!       while (1);
      }
  }
  
--- 1762,1774 ----
                bitmap_set_bit (changed, t);
            }
  
!         if (v->is_full_var
              || v->next == 0)
            break;
  
          v = vi_next (v);
        }
!       while (v->offset < fieldoffset + size);
      }
  }
  
*************** get_constraint_for_ptr_offset (tree ptr,
*** 3109,3143 ****
          varinfo_t temp;
          unsigned HOST_WIDE_INT offset = curr->offset + rhsoffset;
  
!         /* Search the sub-field which overlaps with the
!            pointed-to offset.  If the result is outside of the variable
!            we have to provide a conservative result, as the variable is
!            still reachable from the resulting pointer (even though it
!            technically cannot point to anything).  The last and first
!            sub-fields are such conservative results.
!            ???  If we always had a sub-field for &object + 1 then
!            we could represent this in a more precise way.  */
          if (rhsoffset < 0
              && curr->offset < offset)
            offset = 0;
-         temp = first_or_preceding_vi_for_offset (curr, offset);
  
!         /* If the found variable is not exactly at the pointed to
!            result, we have to include the next variable in the
!            solution as well.  Otherwise two increments by offset / 2
!            do not result in the same or a conservative superset
!            solution.  */
!         if (temp->offset != offset
!             && temp->next != 0)
            {
              struct constraint_expr c2;
!             c2.var = temp->next;
              c2.type = ADDRESSOF;
              c2.offset = 0;
              results->safe_push (c2);
            }
-         c.var = temp->id;
-         c.offset = 0;
        }
        else
        c.offset = rhsoffset;
--- 3118,3147 ----
          varinfo_t temp;
          unsigned HOST_WIDE_INT offset = curr->offset + rhsoffset;
  
!         /* If curr->offset + rhsoffset is less than zero adjust it.  */
          if (rhsoffset < 0
              && curr->offset < offset)
            offset = 0;
  
!         /* We have to include all fields that overlap the current
!            field shifted by rhsoffset.  And we include at least
!            the last or the first field of the variable to represent
!            reachability of off-bound addresses, in particular &object + 1,
!            conservatively correct.  */
!         temp = first_or_preceding_vi_for_offset (curr, offset);
!         c.var = temp->id;
!         c.offset = 0;
!         temp = vi_next (temp);
!         while (temp
!                && temp->offset < offset + curr->size)
            {
              struct constraint_expr c2;
!             c2.var = temp->id;
              c2.type = ADDRESSOF;
              c2.offset = 0;
              results->safe_push (c2);
+             temp = vi_next (temp);
            }
        }
        else
        c.offset = rhsoffset;
Index: gcc/testsuite/gcc.dg/pr60485-1.c
===================================================================
*** gcc/testsuite/gcc.dg/pr60485-1.c    (revision 0)
--- gcc/testsuite/gcc.dg/pr60485-1.c    (working copy)
***************
*** 0 ****
--- 1,29 ----
+ /* { dg-do run } */
+ /* { dg-options "-O2" } */
+ 
+ extern void abort (void);
+ struct S {
+     int *i[4];
+     int *p1;
+     int *p2;
+     int *p3;
+     int *p4;
+ };
+ int **b;
+ int main()
+ {
+   int i = 1;
+   struct S s;
+   s.p3 = &i;
+   int **p;
+   if (b)
+     p = b;
+   else
+     p = &s.i[2];
+   p += 4;
+   if (!b)
+     **p = 0;
+   if (i != 0)
+     abort ();
+   return i;
+ }
Index: gcc/testsuite/gcc.dg/pr60485-2.c
===================================================================
*** gcc/testsuite/gcc.dg/pr60485-2.c    (revision 0)
--- gcc/testsuite/gcc.dg/pr60485-2.c    (working copy)
***************
*** 0 ****
--- 1,38 ----
+ /* { dg-do run } */
+ /* { dg-options "-O2" } */
+ 
+ extern void abort (void);
+ struct S {
+     int *i[4];
+     int *p1;
+     int *p2;
+     int *p3;
+     int *p4;
+     int **x;
+ };
+ int **b;
+ int main()
+ {
+   int i = 1;
+   struct S s;
+   s.p3 = &i;
+   int **p;
+   if (b)
+     p = b;
+   else
+     p = &s.i[2];
+   p += 4;
+   /* prevert fowrprop from creating an offsetted sd constraint and
+      preserve the pointer offsetting constraint.  */
+   s.x = p;
+   p = s.x;
+   if (!b)
+     {
+       int *z = *p;
+       /* z should point to i (and non-local/escaped).  */
+       *z = 0;
+     }
+   if (i != 0)
+     abort ();
+   return i;
+ }

Reply via email to