]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree-ssa-structalias.c (struct variable_info): Add is_full_var flag.
authorRichard Guenther <rguenther@suse.de>
Mon, 7 Jul 2008 15:48:23 +0000 (15:48 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Mon, 7 Jul 2008 15:48:23 +0000 (15:48 +0000)
2008-07-07  Richard Guenther  <rguenther@suse.de>

* tree-ssa-structalias.c (struct variable_info): Add is_full_var flag.
(new_var_info): Set it to false.
(solution_set_add): Correctly handle pointers outside a var and
inside a field.
(type_safe): Treat variables with is_full_var properly.
(do_sd_constraint): Likewise.
(do_ds_constraint): Likewise.
(process_constraint): Remove zeroing offset for !use_field_sensitive.
(get_constraint_for_ptr_offset): New function.
(get_constraint_for_component_ref): For addresses at least include
the last field of the variable.  Handle is_full_vars properly.
(get_constraint_for_1): Factor common code, handle POINTER_PLUS_EXPR.
(handle_ptr_arith): Remove.
(find_func_aliases): Simplify assignment handling.
(create_function_info_for): For parameter and result varinfos set
is_full_var flag.
(create_variable_info_for): Set is_full_var flag whenever we
just created a single varinfo for a decl.
(init_alias_vars): Initialize use_field_sensitive from
max-fields-for-field-sensitive parameter.

* gcc.dg/torture/pta-ptrarith-1.c: New testcase.
* gcc.dg/torture/pta-ptrarith-2.c: Likewise.
* gcc.dg/torture/ipa-pta-1.c: Likewise.

From-SVN: r137573

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/torture/ipa-pta-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/torture/pta-ptrarith-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/torture/pta-ptrarith-2.c [new file with mode: 0644]
gcc/tree-ssa-structalias.c

index 41b494dee92d996f5e0a896c5aed9e34f250fa9f..7faf0de305a19c3e75791ef4cfb712befd133770 100644 (file)
@@ -1,3 +1,26 @@
+2008-07-07  Richard Guenther  <rguenther@suse.de>
+
+       * tree-ssa-structalias.c (struct variable_info): Add is_full_var flag.
+       (new_var_info): Set it to false.
+       (solution_set_add): Correctly handle pointers outside a var and
+       inside a field.
+       (type_safe): Treat variables with is_full_var properly.
+       (do_sd_constraint): Likewise.
+       (do_ds_constraint): Likewise.
+       (process_constraint): Remove zeroing offset for !use_field_sensitive.
+       (get_constraint_for_ptr_offset): New function.
+       (get_constraint_for_component_ref): For addresses at least include
+       the last field of the variable.  Handle is_full_vars properly.
+       (get_constraint_for_1): Factor common code, handle POINTER_PLUS_EXPR.
+       (handle_ptr_arith): Remove.
+       (find_func_aliases): Simplify assignment handling.
+       (create_function_info_for): For parameter and result varinfos set
+       is_full_var flag.
+       (create_variable_info_for): Set is_full_var flag whenever we
+       just created a single varinfo for a decl.
+       (init_alias_vars): Initialize use_field_sensitive from
+       max-fields-for-field-sensitive parameter.
+
 2008-07-07  Richard Guenther  <rguenther@suse.de>
 
        PR tree-optimization/36713
index e8d7a599a0c69882aa2e2936c950f57acccbd553..b212e44c398150b5f986a7fbd11c24a8a31c0105 100644 (file)
@@ -1,3 +1,9 @@
+2008-07-07  Richard Guenther  <rguenther@suse.de>
+
+       * gcc.dg/torture/pta-ptrarith-1.c: New testcase.
+       * gcc.dg/torture/pta-ptrarith-2.c: Likewise.
+       * gcc.dg/torture/ipa-pta-1.c: Likewise.
+
 2008-07-07  Jakub Jelinek  <jakub@redhat.com>
 
        PR middle-end/36726
diff --git a/gcc/testsuite/gcc.dg/torture/ipa-pta-1.c b/gcc/testsuite/gcc.dg/torture/ipa-pta-1.c
new file mode 100644 (file)
index 0000000..c5adb25
--- /dev/null
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-fipa-pta -fdump-ipa-pta" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
+
+struct X { char x; char y; };
+
+void bar (char *p);
+
+void test1 (char a, char b, char c, char d, char e, char f, char g, char h)
+{
+  char *p = &a;
+  p++;
+  bar (p);
+}
+
+void test2 (struct X a, char b, char c, char d, char e, char f, char g, char h)
+{
+  char *p = &a.x;
+  p++;
+  bar (p);
+}
+
+void test3 (struct X a, char b, char c, char d, char e, char f, char g, char h)
+{
+  char *p = &a.y;
+  bar (p);
+}
+
+void test4 (int a, char b, char c, char d, char e, char f, char g, char h)
+{
+  char *p = (char *)&a;
+  p++;
+  p++;
+  p++;
+  p++;
+  bar (p);
+}
+
+/* { dg-final { scan-ipa-dump "bar.arg0 = { test4.arg0 test3.arg0 test2.arg0 test1.arg0 }" "pta" } } */
+/* { dg-final { cleanup-ipa-dump "pta" } } */
diff --git a/gcc/testsuite/gcc.dg/torture/pta-ptrarith-1.c b/gcc/testsuite/gcc.dg/torture/pta-ptrarith-1.c
new file mode 100644 (file)
index 0000000..2a8dc9e
--- /dev/null
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+/* { dg-options "-fdump-tree-alias" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
+
+struct Foo {
+  int *p;
+};
+
+void __attribute__((noinline))
+foo (void *p)
+{
+  struct Foo *f = (struct Foo *)p - 1;
+  *f->p = 0;
+}
+
+int bar (void)
+{
+  struct Foo f;
+  int i = 1;
+  f.p = &i;
+  foo (&f + 1);
+  return i;
+}
+extern void abort (void);
+int main()
+{
+  if (bar () != 0)
+    abort ();
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump "ESCAPED = { ESCAPED NONLOCAL f .* i }" "alias" } } */
+/* { dg-final { cleanup-tree-dump "alias" } } */
diff --git a/gcc/testsuite/gcc.dg/torture/pta-ptrarith-2.c b/gcc/testsuite/gcc.dg/torture/pta-ptrarith-2.c
new file mode 100644 (file)
index 0000000..fb5b2e1
--- /dev/null
@@ -0,0 +1,36 @@
+/* { dg-do run } */
+/* { dg-options "-fdump-tree-alias" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
+
+struct Foo {
+  int **p;
+  int **q;
+};
+
+int __attribute__((noinline))
+bar (void)
+{
+  struct Foo f;
+  int j, i = 1;
+  char *p;
+  int *x = &i;
+  int *y = &j;
+  f.p = &y;
+  f.q = &x;
+  p = (char *)&f;
+  for (j = 0; j < sizeof (int *); ++j)
+    p++;
+  return ***(int ***)p;
+}
+extern void abort (void);
+int main()
+{
+  if (bar () != 1)
+    abort ();
+  return 0;
+}
+
+/* In theory = { i } is the correct solution.  But it's not easy to scan
+   for that reliably, so just use what we create now.  */
+/* { dg-final { scan-tree-dump "= { i j }" "alias" } } */
+/* { dg-final { cleanup-tree-dump "alias" } } */
index 266538c8b601ecbb03e81030c6f3cc230818c0f0..6565d2c4b7dc4c57fd3c17177fbf149c9b1b9b5b 100644 (file)
@@ -220,6 +220,9 @@ struct variable_info
   /* True for variables whose size is not known or variable.  */
   unsigned int is_unknown_size_var:1;
 
+  /* True for (sub-)fields that represent a whole variable.  */
+  unsigned int is_full_var : 1;
+
   /* True if this is a heap variable.  */
   unsigned int is_heap_var:1;
 
@@ -373,6 +376,7 @@ new_var_info (tree t, unsigned int id, const char *name)
   ret->is_heap_var = false;
   ret->is_special_var = false;
   ret->is_unknown_size_var = false;
+  ret->is_full_var = false;
   var = t;
   if (TREE_CODE (var) == SSA_NAME)
     var = SSA_NAME_VAR (var);
@@ -752,22 +756,32 @@ solution_set_add (bitmap set, unsigned HOST_WIDE_INT offset)
 
   EXECUTE_IF_SET_IN_BITMAP (set, 0, i, bi)
     {
-      /* If this is a properly sized variable, only add offset if it's
-        less than end.  Otherwise, it is globbed to a single
-        variable.  */
+      varinfo_t vi = get_varinfo (i);
 
-      if ((get_varinfo (i)->offset + offset) < get_varinfo (i)->fullsize)
+      /* If this is a variable with just one field just set its bit
+         in the result.  */
+      if (vi->is_artificial_var
+         || vi->is_unknown_size_var
+         || vi->is_full_var)
+       bitmap_set_bit (result, i);
+      else
        {
-         unsigned HOST_WIDE_INT fieldoffset = get_varinfo (i)->offset + offset;
-         varinfo_t v = first_vi_for_offset (get_varinfo (i), fieldoffset);
+         unsigned HOST_WIDE_INT fieldoffset = vi->offset + offset;
+         varinfo_t v = first_vi_for_offset (vi, fieldoffset);
+         /* If the result is outside of the variable use the last field.  */
          if (!v)
-           continue;
+           {
+             v = vi;
+             while (v->next != NULL)
+               v = v->next;
+           }
          bitmap_set_bit (result, v->id);
-       }
-      else if (get_varinfo (i)->is_artificial_var
-              || get_varinfo (i)->is_unknown_size_var)
-       {
-         bitmap_set_bit (result, i);
+         /* If the result is not exactly at fieldoffset include the next
+            field as well.  See get_constraint_for_ptr_offset for more
+            rationale.  */
+         if (v->offset != fieldoffset
+             && v->next != NULL)
+           bitmap_set_bit (result, v->next->id);
        }
     }
 
@@ -1375,7 +1389,8 @@ type_safe (unsigned int n, unsigned HOST_WIDE_INT *offset)
      0.  */
   if (ninfo->is_special_var
       || ninfo->is_artificial_var
-      || ninfo->is_unknown_size_var)
+      || ninfo->is_unknown_size_var
+      || ninfo->is_full_var)
     {
       *offset = 0;
       return true;
@@ -1415,7 +1430,11 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c,
          sub-fields off.  This avoids quadratic behavior.  */
       EXECUTE_IF_SET_IN_BITMAP (delta, 0, j, bi)
        {
-         varinfo_t v = lookup_vi_for_tree (get_varinfo (j)->decl);
+         varinfo_t v = get_varinfo (j);
+         if (v->is_full_var)
+           continue;
+
+         v = lookup_vi_for_tree (v->decl);
          if (v->next != NULL)
            {
              if (vars == NULL)
@@ -1455,6 +1474,7 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c,
          unsigned int t;
 
          v = first_vi_for_offset (get_varinfo (j), fieldoffset);
+         /* If the access is outside of the variable we can ignore it.  */
          if (!v)
            continue;
          t = find (v->id);
@@ -1507,9 +1527,14 @@ do_ds_constraint (constraint_t c, bitmap delta)
         unsigned HOST_WIDE_INT fieldoffset = jvi->offset + loff;
         varinfo_t v;
 
-        v = first_vi_for_offset (get_varinfo (j), fieldoffset);
-        if (!v)
-          continue;
+        v = get_varinfo (j);
+        if (!v->is_full_var)
+          {
+            v = first_vi_for_offset (v, fieldoffset);
+            /* If the access is outside of the variable we can ignore it.  */
+            if (!v)
+              continue;
+          }
         t = find (v->id);
 
         if (bitmap_set_bit (get_varinfo (t)->solution, anything_id)
@@ -1535,6 +1560,7 @@ do_ds_constraint (constraint_t c, bitmap delta)
          bitmap tmp;
 
          v = first_vi_for_offset (get_varinfo (j), fieldoffset);
+         /* If the access is outside of the variable we can ignore it.  */
          if (!v)
            continue;
          t = find (v->id);
@@ -2597,12 +2623,6 @@ process_constraint (constraint_t t)
   gcc_assert (rhs.var < VEC_length (varinfo_t, varmap));
   gcc_assert (lhs.var < VEC_length (varinfo_t, varmap));
 
-  if (!use_field_sensitive)
-    {
-      t->rhs.offset = 0;
-      t->lhs.offset = 0;
-    }
-
   /* ANYTHING == ANYTHING is pointless.  */
   if (lhs.var == anything_id && rhs.var == anything_id)
     return;
@@ -2678,6 +2698,119 @@ bitpos_of_field (const tree fdecl)
 }
 
 
+/* Get constraint expressions for offsetting PTR by OFFSET.  Stores the
+   resulting constraint expressions in *RESULTS.  */
+
+static void
+get_constraint_for_ptr_offset (tree ptr, tree offset,
+                              VEC (ce_s, heap) **results)
+{
+  struct constraint_expr *c;
+  unsigned int j, n;
+  unsigned HOST_WIDE_INT rhsunitoffset, rhsoffset;
+
+  /* If we do not do field-sensitive PTA adding offsets to pointers
+     does not change the points-to solution.  */
+  if (!use_field_sensitive)
+    {
+      get_constraint_for (ptr, results);
+      return;
+    }
+
+  /* If the offset is not a non-negative integer constant that fits
+     in a HOST_WIDE_INT, we have to fall back to a conservative
+     solution which includes all sub-fields of all pointed-to
+     variables of ptr.
+     ???  As we do not have the ability to express this, fall back
+     to anything.  */
+  if (!host_integerp (offset, 1))
+    {
+      struct constraint_expr temp;
+      temp.var = anything_id;
+      temp.type = SCALAR;
+      temp.offset = 0;
+      VEC_safe_push (ce_s, heap, *results, &temp);
+      return;
+    }
+
+  /* Make sure the bit-offset also fits.  */
+  rhsunitoffset = TREE_INT_CST_LOW (offset);
+  rhsoffset = rhsunitoffset * BITS_PER_UNIT;
+  if (rhsunitoffset != rhsoffset / BITS_PER_UNIT)
+    {
+      struct constraint_expr temp;
+      temp.var = anything_id;
+      temp.type = SCALAR;
+      temp.offset = 0;
+      VEC_safe_push (ce_s, heap, *results, &temp);
+      return;
+    }
+
+  get_constraint_for (ptr, results);
+  if (rhsoffset == 0)
+    return;
+
+  /* As we are eventually appending to the solution do not use
+     VEC_iterate here.  */
+  n = VEC_length (ce_s, *results);
+  for (j = 0; j < n; j++)
+    {
+      varinfo_t curr;
+      c = VEC_index (ce_s, *results, j);
+      curr = get_varinfo (c->var);
+
+      if (c->type == ADDRESSOF
+         && !curr->is_full_var)
+       {
+         varinfo_t temp, curr = get_varinfo (c->var);
+
+         /* Search the sub-field which overlaps with the
+            pointed-to offset.  As we deal with positive offsets
+            only, we can start the search from the current variable.  */
+         temp = first_vi_for_offset (curr, curr->offset + rhsoffset);
+
+         /* 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 sub-field is such
+            a conservative result.
+            ???  If we always had a sub-field for &object + 1 then
+            we could represent this in a more precise way.  */
+         if (temp == NULL)
+           {
+             temp = curr;
+             while (temp->next != NULL)
+               temp = temp->next;
+             continue;
+           }
+
+         /* 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 != curr->offset + rhsoffset
+             && temp->next != NULL)
+           {
+             struct constraint_expr c2;
+             c2.var = temp->next->id;
+             c2.type = ADDRESSOF;
+             c2.offset = 0;
+             VEC_safe_push (ce_s, heap, *results, &c2);
+           }
+         c->var = temp->id;
+         c->offset = 0;
+       }
+      else if (c->type == ADDRESSOF
+              /* If this varinfo represents a full variable just use it.  */
+              && curr->is_full_var)
+       c->offset = 0;
+      else
+       c->offset = rhsoffset;
+    }
+}
+
+
 /* Given a COMPONENT_REF T, return the constraint_expr vector for it.
    If address_p is true the result will be taken its address of.  */
 
@@ -2714,15 +2847,18 @@ get_constraint_for_component_ref (tree t, VEC(ce_s, heap) **results,
   /* Pretend to take the address of the base, we'll take care of
      adding the required subset of sub-fields below.  */
   get_constraint_for_1 (t, results, true);
-  result = VEC_last (ce_s, *results);
-
   gcc_assert (VEC_length (ce_s, *results) == 1);
+  result = VEC_last (ce_s, *results);
 
   /* This can also happen due to weird offsetof type macros.  */
   if (TREE_CODE (t) != ADDR_EXPR && result->type == ADDRESSOF)
     result->type = SCALAR;
 
-  if (result->type == SCALAR)
+  if (result->type == SCALAR
+      && get_varinfo (result->var)->is_full_var)
+    /* For single-field vars do not bother about the offset.  */
+    result->offset = 0;
+  else if (result->type == SCALAR)
     {
       /* In languages like C, you can access one past the end of an
         array.  You aren't allowed to dereference it, so we can
@@ -2751,12 +2887,25 @@ get_constraint_for_component_ref (tree t, VEC(ce_s, heap) **results,
                    break;
                }
            }
-         /* assert that we found *some* field there. The user couldn't be
-            accessing *only* padding.  */
-         /* Still the user could access one past the end of an array
-            embedded in a struct resulting in accessing *only* padding.  */
-         gcc_assert (VEC_length (ce_s, *results) >= 1
-                     || ref_contains_array_ref (orig_t));
+         /* If we are going to take the address of this field then
+            to be able to compute reachability correctly add at least
+            the last field of the variable.  */
+         if (address_p
+             && VEC_length (ce_s, *results) == 0)
+           {
+             curr = get_varinfo (cexpr.var);
+             while (curr->next != NULL)
+               curr = curr->next;
+             cexpr.var = curr->id;
+             VEC_safe_push (ce_s, heap, *results, &cexpr);
+           }
+         else
+           /* Assert that we found *some* field there. The user couldn't be
+              accessing *only* padding.  */
+           /* Still the user could access one past the end of an array
+              embedded in a struct resulting in accessing *only* padding.  */
+           gcc_assert (VEC_length (ce_s, *results) >= 1
+                       || ref_contains_array_ref (orig_t));
        }
       else if (bitmaxsize == 0)
        {
@@ -2900,24 +3049,10 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p)
                VEC_safe_push (ce_s, heap, *results, &temp);
                return;
              }
-           else
-             {
-               temp.var = anything_id;
-               temp.type = SCALAR;
-               temp.offset = 0;
-               VEC_safe_push (ce_s, heap, *results, &temp);
-               return;
-             }
            break;
-         default:
-           {
-             temp.type = ADDRESSOF;
-             temp.var = anything_id;
-             temp.offset = 0;
-             VEC_safe_push (ce_s, heap, *results, &temp);
-             return;
-           }
+         default:;
          }
+       break;
       }
     case tcc_reference:
       {
@@ -2934,15 +3069,9 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p)
          case COMPONENT_REF:
            get_constraint_for_component_ref (t, results, address_p);
            return;
-         default:
-           {
-             temp.type = ADDRESSOF;
-             temp.var = anything_id;
-             temp.offset = 0;
-             VEC_safe_push (ce_s, heap, *results, &temp);
-             return;
-           }
+         default:;
          }
+       break;
       }
     case tcc_unary:
       {
@@ -2963,15 +3092,19 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p)
 
              /* FALLTHRU  */
            }
-         default:
-           {
-             temp.type = ADDRESSOF;
-             temp.var = anything_id;
-             temp.offset = 0;
-             VEC_safe_push (ce_s, heap, *results, &temp);
-             return;
-           }
+         default:;
          }
+       break;
+      }
+    case tcc_binary:
+      {
+       if (TREE_CODE (t) == POINTER_PLUS_EXPR)
+         {
+           get_constraint_for_ptr_offset (TREE_OPERAND (t, 0),
+                                          TREE_OPERAND (t, 1), results);
+           return;
+         }
+       break;
       }
     case tcc_exceptional:
       {
@@ -2982,37 +3115,28 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p)
              get_constraint_for_1 (PHI_RESULT (t), results, address_p);
              return;
            }
-           break;
          case SSA_NAME:
            {
              get_constraint_for_ssa_var (t, results, address_p);
              return;
            }
-           break;
-         default:
-           {
-             temp.type = ADDRESSOF;
-             temp.var = anything_id;
-             temp.offset = 0;
-             VEC_safe_push (ce_s, heap, *results, &temp);
-             return;
-           }
+         default:;
          }
+       break;
       }
     case tcc_declaration:
       {
        get_constraint_for_ssa_var (t, results, address_p);
        return;
       }
-    default:
-      {
-       temp.type = ADDRESSOF;
-       temp.var = anything_id;
-       temp.offset = 0;
-       VEC_safe_push (ce_s, heap, *results, &temp);
-       return;
-      }
+    default:;
     }
+
+  /* The default fallback is a constraint from anything.  */
+  temp.type = ADDRESSOF;
+  temp.var = anything_id;
+  temp.offset = 0;
+  VEC_safe_push (ce_s, heap, *results, &temp);
 }
 
 /* Given a gimple tree T, return the constraint expression vector for it.  */
@@ -3298,80 +3422,6 @@ do_structure_copy (tree lhsop, tree rhsop)
     }
 }
 
-
-/* Handle pointer arithmetic EXPR when creating aliasing constraints.
-   Expressions of the type PTR + CST can be handled in two ways:
-
-   1- If the constraint for PTR is ADDRESSOF for a non-structure
-      variable, then we can use it directly because adding or
-      subtracting a constant may not alter the original ADDRESSOF
-      constraint (i.e., pointer arithmetic may not legally go outside
-      an object's boundaries).
-
-   2- If the constraint for PTR is ADDRESSOF for a structure variable,
-      then if CST is a compile-time constant that can be used as an
-      offset, we can determine which sub-variable will be pointed-to
-      by the expression.
-
-   Return true if the expression is handled.  For any other kind of
-   expression, return false so that each operand can be added as a
-   separate constraint by the caller.  */
-
-static bool
-handle_ptr_arith (VEC (ce_s, heap) *lhsc, tree expr)
-{
-  tree op0, op1;
-  struct constraint_expr *c, *c2;
-  unsigned int i = 0;
-  unsigned int j = 0;
-  VEC (ce_s, heap) *temp = NULL;
-  unsigned HOST_WIDE_INT rhsunitoffset, rhsoffset;
-
-  if (TREE_CODE (expr) != POINTER_PLUS_EXPR)
-    return false;
-
-  op0 = TREE_OPERAND (expr, 0);
-  op1 = TREE_OPERAND (expr, 1);
-  gcc_assert (POINTER_TYPE_P (TREE_TYPE (op0)));
-
-  /* If the offset is not a non-negative integer constant that fits
-     in a HOST_WIDE_INT, we cannot handle it here.  */
-  if (!host_integerp (op1, 1))
-    return false;
-
-  /* Make sure the bit-offset also fits.  */
-  rhsunitoffset = TREE_INT_CST_LOW (op1);
-  rhsoffset = rhsunitoffset * BITS_PER_UNIT;
-  if (rhsunitoffset != rhsoffset / BITS_PER_UNIT)
-    return false;
-
-  get_constraint_for (op0, &temp);
-
-  for (i = 0; VEC_iterate (ce_s, lhsc, i, c); i++)
-    for (j = 0; VEC_iterate (ce_s, temp, j, c2); j++)
-      {
-       if (c2->type == ADDRESSOF && rhsoffset != 0)
-         {
-           varinfo_t temp = get_varinfo (c2->var);
-
-           /* An access one after the end of an array is valid,
-              so simply punt on accesses we cannot resolve.  */
-           temp = first_vi_for_offset (temp, rhsoffset);
-           if (temp == NULL)
-             continue;
-           c2->var = temp->id;
-           c2->offset = 0;
-         }
-       else
-         c2->offset = rhsoffset;
-       process_constraint (new_constraint (*c, *c2));
-      }
-
-  VEC_free (ce_s, heap, temp);
-
-  return true;
-}
-
 /* Create a constraint ID = OP.  */
 
 static void
@@ -3771,89 +3821,29 @@ find_func_aliases (tree origt)
            }
        }
     }
-  /* Otherwise, just a regular assignment statement.  */
-  else if (TREE_CODE (t) == GIMPLE_MODIFY_STMT)
+  /* Otherwise, just a regular assignment statement.  Only care about
+     operations with pointer result, others are dealt with as escape
+     points if they have pointer operands.  */
+  else if (TREE_CODE (t) == GIMPLE_MODIFY_STMT
+          && could_have_pointers (GIMPLE_STMT_OPERAND (t, 0)))
     {
       tree lhsop = GIMPLE_STMT_OPERAND (t, 0);
       tree rhsop = GIMPLE_STMT_OPERAND (t, 1);
-      int i;
 
-      if (AGGREGATE_TYPE_P (TREE_TYPE (lhsop))
-         && AGGREGATE_TYPE_P (TREE_TYPE (rhsop)))
-       {
-         do_structure_copy (lhsop, rhsop);
-       }
+      if (AGGREGATE_TYPE_P (TREE_TYPE (lhsop)))
+       do_structure_copy (lhsop, rhsop);
       else
        {
-         /* Only care about operations with pointers, structures
-            containing pointers, dereferences, and call expressions.  */
-         if (could_have_pointers (lhsop)
-             || TREE_CODE (rhsop) == CALL_EXPR)
+         unsigned int j;
+         get_constraint_for (lhsop, &lhsc);
+         get_constraint_for (rhsop, &rhsc);
+         for (j = 0; VEC_iterate (ce_s, lhsc, j, c); j++)
            {
-             get_constraint_for (lhsop, &lhsc);
-             switch (TREE_CODE_CLASS (TREE_CODE (rhsop)))
-               {
-                 /* RHS that consist of unary operations,
-                    exceptional types, or bare decls/constants, get
-                    handled directly by get_constraint_for.  */
-                 case tcc_reference:
-                 case tcc_declaration:
-                 case tcc_constant:
-                 case tcc_exceptional:
-                 case tcc_expression:
-                 case tcc_vl_exp:
-                 case tcc_unary:
-                     {
-                       unsigned int j;
-
-                       get_constraint_for (rhsop, &rhsc);
-                       for (j = 0; VEC_iterate (ce_s, lhsc, j, c); j++)
-                         {
-                           struct constraint_expr *c2;
-                           unsigned int k;
-
-                           for (k = 0; VEC_iterate (ce_s, rhsc, k, c2); k++)
-                             process_constraint (new_constraint (*c, *c2));
-                         }
-
-                     }
-                   break;
+             struct constraint_expr *c2;
+             unsigned int k;
 
-                 case tcc_binary:
-                     {
-                       /* For pointer arithmetic of the form
-                          PTR + CST, we can simply use PTR's
-                          constraint because pointer arithmetic is
-                          not allowed to go out of bounds.  */
-                       if (handle_ptr_arith (lhsc, rhsop))
-                         break;
-                     }
-                   /* FALLTHRU  */
-
-                 /* Otherwise, walk each operand.  Notice that we
-                    can't use the operand interface because we need
-                    to process expressions other than simple operands
-                    (e.g. INDIRECT_REF, ADDR_EXPR, CALL_EXPR).  */
-                 default:
-                   for (i = 0; i < TREE_OPERAND_LENGTH (rhsop); i++)
-                     {
-                       tree op = TREE_OPERAND (rhsop, i);
-                       unsigned int j;
-
-                       gcc_assert (VEC_length (ce_s, rhsc) == 0);
-                       get_constraint_for (op, &rhsc);
-                       for (j = 0; VEC_iterate (ce_s, lhsc, j, c); j++)
-                         {
-                           struct constraint_expr *c2;
-                           while (VEC_length (ce_s, rhsc) > 0)
-                             {
-                               c2 = VEC_last (ce_s, rhsc);
-                               process_constraint (new_constraint (*c, *c2));
-                               VEC_pop (ce_s, rhsc);
-                             }
-                         }
-                     }
-               }
+             for (k = 0; VEC_iterate (ce_s, rhsc, k, c2); k++)
+               process_constraint (new_constraint (*c, *c2));
            }
        }
     }
@@ -4222,8 +4212,7 @@ create_function_info_for (tree decl, const char *name)
   stats.total_vars++;
 
   /* If it's varargs, we don't know how many arguments it has, so we
-     can't do much.
-  */
+     can't do much.  */
   if (is_varargs)
     {
       vi->fullsize = ~0;
@@ -4257,6 +4246,7 @@ create_function_info_for (tree decl, const char *name)
       VEC_safe_push (varinfo_t, heap, varmap, argvi);
       argvi->offset = i;
       argvi->size = 1;
+      argvi->is_full_var = true;
       argvi->fullsize = vi->fullsize;
       insert_into_field_list_sorted (vi, argvi);
       stats.total_vars ++;
@@ -4293,6 +4283,7 @@ create_function_info_for (tree decl, const char *name)
       resultvi->offset = i;
       resultvi->size = 1;
       resultvi->fullsize = vi->fullsize;
+      resultvi->is_full_var = true;
       insert_into_field_list_sorted (vi, resultvi);
       stats.total_vars ++;
       if (DECL_RESULT (decl))
@@ -4411,6 +4402,7 @@ create_variable_info_for (tree decl, const char *name)
          vi->is_unknown_size_var = 1;
          vi->fullsize = ~0;
          vi->size = ~0;
+         vi->is_full_var = true;
          VEC_free (fieldoff_s, heap, fieldstack);
          return index;
        }
@@ -4447,6 +4439,8 @@ create_variable_info_for (tree decl, const char *name)
          stats.total_vars++;
        }
     }
+  else
+    vi->is_full_var = true;
 
   VEC_free (fieldoff_s, heap, fieldstack);
 
@@ -5198,6 +5192,8 @@ init_base_vars (void)
 static void
 init_alias_vars (void)
 {
+  use_field_sensitive = (MAX_FIELDS_FOR_FIELD_SENSITIVE > 1);
+
   bitmap_obstack_initialize (&pta_obstack);
   bitmap_obstack_initialize (&oldpta_obstack);
   bitmap_obstack_initialize (&predbitmap_obstack);