OSDN Git Service

2009-02-17 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-structalias.c
index 57a02a4..8f88796 100644 (file)
 #include "hard-reg-set.h"
 #include "basic-block.h"
 #include "output.h"
-#include "errors.h"
-#include "diagnostic.h"
 #include "tree.h"
 #include "c-common.h"
 #include "tree-flow.h"
 #include "tree-inline.h"
 #include "varray.h"
 #include "c-tree.h"
-#include "tree-gimple.h"
+#include "diagnostic.h"
+#include "toplev.h"
+#include "gimple.h"
 #include "hashtab.h"
 #include "function.h"
 #include "cgraph.h"
@@ -209,24 +209,6 @@ struct variable_info
   /* ID of this variable  */
   unsigned int id;
 
-  /* Name of this variable */
-  const char *name;
-
-  /* Tree that this variable is associated with.  */
-  tree decl;
-
-  /* Offset of this variable, in bits, from the base variable  */
-  unsigned HOST_WIDE_INT offset;
-
-  /* Size of the variable, in bits.  */
-  unsigned HOST_WIDE_INT size;
-
-  /* Full size of the base variable, in bits.  */
-  unsigned HOST_WIDE_INT fullsize;
-
-  /* A link to the variable for the next field in this structure.  */
-  struct variable_info *next;
-
   /* True if this is a variable created by the constraint analysis, such as
      heap variables and constraints we had to break up.  */
   unsigned int is_artificial_var:1;
@@ -238,8 +220,8 @@ struct variable_info
   /* True for variables whose size is not known or variable.  */
   unsigned int is_unknown_size_var:1;
 
-  /* True for variables that have unions somewhere in them.  */
-  unsigned int has_union: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;
@@ -248,20 +230,39 @@ struct variable_info
      variable.  This is used for C++ placement new.  */
   unsigned int no_tbaa_pruning : 1;
 
+  /* Variable id this was collapsed to due to type unsafety.  Zero if
+     this variable was not collapsed.  This should be unused completely
+     after build_succ_graph, or something is broken.  */
+  unsigned int collapsed_to;
+
+  /* A link to the variable for the next field in this structure.  */
+  struct variable_info *next;
+
+  /* Offset of this variable, in bits, from the base variable  */
+  unsigned HOST_WIDE_INT offset;
+
+  /* Size of the variable, in bits.  */
+  unsigned HOST_WIDE_INT size;
+
+  /* Full size of the base variable, in bits.  */
+  unsigned HOST_WIDE_INT fullsize;
+
+  /* Name of this variable */
+  const char *name;
+
+  /* Tree that this variable is associated with.  */
+  tree decl;
+
   /* Points-to set for this variable.  */
   bitmap solution;
 
   /* Old points-to set for this variable.  */
   bitmap oldsolution;
-
-  /* Variable id this was collapsed to due to type unsafety.  This
-     should be unused completely after build_succ_graph, or something
-     is broken.  */
-  struct variable_info *collapsed_to;
 };
 typedef struct variable_info *varinfo_t;
 
 static varinfo_t first_vi_for_offset (varinfo_t, unsigned HOST_WIDE_INT);
+static varinfo_t lookup_vi_for_tree (tree);
 
 /* Pool of variable info structures.  */
 static alloc_pool variable_info_pool;
@@ -289,8 +290,8 @@ get_varinfo_fc (unsigned int n)
 {
   varinfo_t v = VEC_index (varinfo_t, varmap, n);
 
-  if (v->collapsed_to)
-    return v->collapsed_to;
+  if (v->collapsed_to != 0)
+    return get_varinfo (v->collapsed_to);
   return v;
 }
 
@@ -375,7 +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->has_union = false;
+  ret->is_full_var = false;
   var = t;
   if (TREE_CODE (var) == SSA_NAME)
     var = SSA_NAME_VAR (var);
@@ -385,7 +386,7 @@ new_var_info (tree t, unsigned int id, const char *name)
   ret->solution = BITMAP_ALLOC (&pta_obstack);
   ret->oldsolution = BITMAP_ALLOC (&oldpta_obstack);
   ret->next = NULL;
-  ret->collapsed_to = NULL;
+  ret->collapsed_to = 0;
   return ret;
 }
 
@@ -505,16 +506,6 @@ struct constraint_graph
      taken.  Used for variable substitution.  */
   bitmap address_taken;
 
-  /* True if points_to bitmap for this node is stored in the hash
-     table.  */
-  sbitmap pt_used;
-
-  /* Number of incoming edges remaining to be processed by pointer
-     equivalence.
-     Used for variable substitution.  */
-  unsigned int *number_incoming;
-
-
   /* Vector of complex constraints for each graph node.  Complex
      constraints are those involving dereferences or offsets that are
      not 0.  */
@@ -623,6 +614,96 @@ debug_constraints (void)
   dump_constraints (stderr);
 }
 
+/* Print out to FILE the edge in the constraint graph that is created by
+   constraint c. The edge may have a label, depending on the type of
+   constraint that it represents. If complex1, e.g: a = *b, then the label
+   is "=*", if complex2, e.g: *a = b, then the label is "*=", if
+   complex with an offset, e.g: a = b + 8, then the label is "+".
+   Otherwise the edge has no label.  */
+
+void
+dump_constraint_edge (FILE *file, constraint_t c)
+{
+  if (c->rhs.type != ADDRESSOF)
+    {
+      const char *src = get_varinfo_fc (c->rhs.var)->name;
+      const char *dst = get_varinfo_fc (c->lhs.var)->name;
+      fprintf (file, "  \"%s\" -> \"%s\" ", src, dst);
+      /* Due to preprocessing of constraints, instructions like *a = *b are
+         illegal; thus, we do not have to handle such cases.  */
+      if (c->lhs.type == DEREF)
+        fprintf (file, " [ label=\"*=\" ] ;\n");
+      else if (c->rhs.type == DEREF)
+        fprintf (file, " [ label=\"=*\" ] ;\n");
+      else
+        {
+          /* We must check the case where the constraint is an offset.
+             In this case, it is treated as a complex constraint.  */
+          if (c->rhs.offset != c->lhs.offset)
+            fprintf (file, " [ label=\"+\" ] ;\n");
+          else
+            fprintf (file, " ;\n");
+        }
+    }
+}
+
+/* Print the constraint graph in dot format.  */
+
+void
+dump_constraint_graph (FILE *file)
+{
+  unsigned int i=0, size;
+  constraint_t c;
+
+  /* Only print the graph if it has already been initialized:  */
+  if (!graph)
+    return;
+
+  /* Print the constraints used to produce the constraint graph. The
+     constraints will be printed as comments in the dot file:  */
+  fprintf (file, "\n\n/* Constraints used in the constraint graph:\n");
+  dump_constraints (file);
+  fprintf (file, "*/\n");
+
+  /* Prints the header of the dot file:  */
+  fprintf (file, "\n\n// The constraint graph in dot format:\n");
+  fprintf (file, "strict digraph {\n");
+  fprintf (file, "  node [\n    shape = box\n  ]\n");
+  fprintf (file, "  edge [\n    fontsize = \"12\"\n  ]\n");
+  fprintf (file, "\n  // List of nodes in the constraint graph:\n");
+
+  /* The next lines print the nodes in the graph. In order to get the
+     number of nodes in the graph, we must choose the minimum between the
+     vector VEC (varinfo_t, varmap) and graph->size. If the graph has not
+     yet been initialized, then graph->size == 0, otherwise we must only
+     read nodes that have an entry in VEC (varinfo_t, varmap).  */
+  size = VEC_length (varinfo_t, varmap);
+  size = size < graph->size ? size : graph->size;
+  for (i = 0; i < size; i++)
+    {
+      const char *name = get_varinfo_fc (graph->rep[i])->name;
+      fprintf (file, "  \"%s\" ;\n", name);
+    }
+
+  /* Go over the list of constraints printing the edges in the constraint
+     graph.  */
+  fprintf (file, "\n  // The constraint edges:\n");
+  for (i = 0; VEC_iterate (constraint_t, constraints, i, c); i++)
+    if (c)
+      dump_constraint_edge (file, c);
+
+  /* Prints the tail of the dot file. By now, only the closing bracket.  */
+  fprintf (file, "}\n\n\n");
+}
+
+/* Print out the constraint graph to stderr.  */
+
+void
+debug_constraint_graph (void)
+{
+  dump_constraint_graph (stderr);
+}
+
 /* SOLVER FUNCTIONS
 
    The solver is a simple worklist solver, that works on the following
@@ -755,23 +836,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)->has_union
-              || 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);
        }
     }
 
@@ -904,11 +994,8 @@ add_implicit_graph_edge (constraint_graph_t graph, unsigned int to,
   if (!graph->implicit_preds[to])
     graph->implicit_preds[to] = BITMAP_ALLOC (&predbitmap_obstack);
 
-  if (!bitmap_bit_p (graph->implicit_preds[to], from))
-    {
-      stats.num_implicit_edges++;
-      bitmap_set_bit (graph->implicit_preds[to], from);
-    }
+  if (bitmap_set_bit (graph->implicit_preds[to], from))
+    stats.num_implicit_edges++;
 }
 
 /* Add a predecessor graph edge to GRAPH, going from TO to FROM if
@@ -921,8 +1008,7 @@ add_pred_graph_edge (constraint_graph_t graph, unsigned int to,
 {
   if (!graph->preds[to])
     graph->preds[to] = BITMAP_ALLOC (&predbitmap_obstack);
-  if (!bitmap_bit_p (graph->preds[to], from))
-    bitmap_set_bit (graph->preds[to], from);
+  bitmap_set_bit (graph->preds[to], from);
 }
 
 /* Add a graph edge to GRAPH, going from FROM to TO if
@@ -943,12 +1029,11 @@ add_graph_edge (constraint_graph_t graph, unsigned int to,
 
       if (!graph->succs[from])
        graph->succs[from] = BITMAP_ALLOC (&pta_obstack);
-      if (!bitmap_bit_p (graph->succs[from], to))
+      if (bitmap_set_bit (graph->succs[from], to))
        {
          r = true;
          if (to < FIRST_REF_NODE && from < FIRST_REF_NODE)
            stats.num_edges++;
-         bitmap_set_bit (graph->succs[from], to);
        }
       return r;
     }
@@ -1006,11 +1091,8 @@ build_pred_graph (void)
   graph->points_to = XCNEWVEC (bitmap, graph->size);
   graph->eq_rep = XNEWVEC (int, graph->size);
   graph->direct_nodes = sbitmap_alloc (graph->size);
-  graph->pt_used = sbitmap_alloc (graph->size);
   graph->address_taken = BITMAP_ALLOC (&predbitmap_obstack);
-  graph->number_incoming = XCNEWVEC (unsigned int, graph->size);
   sbitmap_zero (graph->direct_nodes);
-  sbitmap_zero (graph->pt_used);
 
   for (j = 0; j < FIRST_REF_NODE; j++)
     {
@@ -1047,6 +1129,8 @@ build_pred_graph (void)
        }
       else if (rhs.type == ADDRESSOF)
        {
+         varinfo_t v;
+
          /* x = &y */
          if (graph->points_to[lhsvar] == NULL)
            graph->points_to[lhsvar] = BITMAP_ALLOC (&predbitmap_obstack);
@@ -1059,7 +1143,19 @@ build_pred_graph (void)
          /* Implicitly, *x = y */
          add_implicit_graph_edge (graph, FIRST_REF_NODE + lhsvar, rhsvar);
 
+         /* All related variables are no longer direct nodes.  */
          RESET_BIT (graph->direct_nodes, rhsvar);
+         v = get_varinfo (rhsvar);
+         if (!v->is_full_var)
+           {
+             v = lookup_vi_for_tree (v->decl);
+             do
+               {
+                 RESET_BIT (graph->direct_nodes, v->id);
+                 v = v->next;
+               }
+             while (v != NULL);
+           }
          bitmap_set_bit (graph->address_taken, rhsvar);
        }
       else if (lhsvar > anything_id
@@ -1384,7 +1480,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;
@@ -1405,13 +1502,56 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c,
   unsigned int j;
   bitmap_iterator bi;
 
- if (bitmap_bit_p (delta, anything_id))
-   {
-     flag = !bitmap_bit_p (sol, anything_id);
-     if (flag)
-       bitmap_set_bit (sol, anything_id);
-     goto done;
-   }
+  /* For x = *ESCAPED and x = *CALLUSED we want to compute the
+     reachability set of the rhs var.  As a pointer to a sub-field
+     of a variable can also reach all other fields of the variable
+     we simply have to expand the solution to contain all sub-fields
+     if one sub-field is contained.  */
+  if (c->rhs.var == escaped_id
+      || c->rhs.var == callused_id)
+    {
+      bitmap vars = NULL;
+      /* In a first pass record all variables we need to add all
+         sub-fields off.  This avoids quadratic behavior.  */
+      EXECUTE_IF_SET_IN_BITMAP (delta, 0, j, bi)
+       {
+         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)
+               vars = BITMAP_ALLOC (NULL);
+             bitmap_set_bit (vars, v->id);
+           }
+       }
+      /* In the second pass now do the addition to the solution and
+         to speed up solving add it to the delta as well.  */
+      if (vars != NULL)
+       {
+         EXECUTE_IF_SET_IN_BITMAP (vars, 0, j, bi)
+           {
+             varinfo_t v = get_varinfo (j);
+             for (; v != NULL; v = v->next)
+               {
+                 if (bitmap_set_bit (sol, v->id))
+                   {
+                     flag = true;
+                     bitmap_set_bit (delta, v->id);
+                   }
+               }
+           }
+         BITMAP_FREE (vars);
+       }
+    }
+
+  if (bitmap_bit_p (delta, anything_id))
+    {
+      flag |= bitmap_set_bit (sol, anything_id);
+      goto done;
+    }
 
   /* For each variable j in delta (Sol(y)), add
      an edge in the graph from j to x, and union Sol(j) into Sol(x).  */
@@ -1425,6 +1565,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);
@@ -1436,13 +1577,9 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c,
          /* Merging the solution from ESCAPED needlessly increases
             the set.  Use ESCAPED as representative instead.
             Same for CALLUSED.  */
-         else if ((get_varinfo (t)->id == escaped_id
-                   || get_varinfo (t)->id == callused_id)
-                  && !bitmap_bit_p (sol, get_varinfo (t)->id))
-           {
-             bitmap_set_bit (sol, get_varinfo (t)->id);
-             flag = true;
-           }
+         else if (get_varinfo (t)->id == escaped_id
+                  || get_varinfo (t)->id == callused_id)
+           flag |= bitmap_set_bit (sol, get_varinfo (t)->id);
          else if (add_graph_edge (graph, lhs, t))
            flag |= bitmap_ior_into (sol, get_varinfo (t)->solution);
        }
@@ -1481,19 +1618,21 @@ 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_bit_p (get_varinfo (t)->solution, anything_id))
+        if (bitmap_set_bit (get_varinfo (t)->solution, anything_id)
+            && !TEST_BIT (changed, t))
           {
-            bitmap_set_bit (get_varinfo (t)->solution, anything_id);
-            if (!TEST_BIT (changed, t))
-              {
-                SET_BIT (changed, t);
-                changed_count++;
-              }
+            SET_BIT (changed, t);
+            changed_count++;
           }
        }
      return;
@@ -1512,20 +1651,23 @@ 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);
          tmp = get_varinfo (t)->solution;
 
-         if (set_union_with_increment (tmp, sol, 0))
+            if (add_graph_edge (graph, t, rhs))
            {
-             get_varinfo (t)->solution = tmp;
-             if (t == rhs)
-               sol = get_varinfo (rhs)->solution;
-             if (!TEST_BIT (changed, t))
+                if (bitmap_ior_into (get_varinfo (t)->solution, sol))
                {
-                 SET_BIT (changed, t);
-                 changed_count++;
+                    if (t == rhs)
+                      sol = get_varinfo (rhs)->solution;
+                    if (!TEST_BIT (changed, t))
+                      {
+                        SET_BIT (changed, t);
+                        changed_count++;
+                      }
                }
            }
        }
@@ -1869,11 +2011,6 @@ condense_visit (constraint_graph_t graph, struct scc_info *si, unsigned int n)
              bitmap_ior_into (graph->points_to[n],
                               graph->points_to[w]);
            }
-         EXECUTE_IF_IN_NONNULL_BITMAP (graph->preds[n], 0, i, bi)
-           {
-             unsigned int rep = si->node_mapping[i];
-             graph->number_incoming[rep]++;
-           }
        }
       SET_BIT (si->deleted, n);
     }
@@ -1902,21 +2039,10 @@ label_visit (constraint_graph_t graph, struct scc_info *si, unsigned int n)
 
       /* Skip unused edges  */
       if (w == n || graph->pointer_label[w] == 0)
-       {
-         graph->number_incoming[w]--;
-         continue;
-       }
+       continue;
+
       if (graph->points_to[w])
        bitmap_ior_into(graph->points_to[n], graph->points_to[w]);
-
-      /* If all incoming edges to w have been processed and
-        graph->points_to[w] was not stored in the hash table, we can
-        free it.  */
-      graph->number_incoming[w]--;
-      if (!graph->number_incoming[w] && !TEST_BIT (graph->pt_used, w))
-       {
-         BITMAP_FREE (graph->points_to[w]);
-       }
     }
   /* Indirect nodes get fresh variables.  */
   if (!TEST_BIT (graph->direct_nodes, n))
@@ -1928,7 +2054,6 @@ label_visit (constraint_graph_t graph, struct scc_info *si, unsigned int n)
                                               graph->points_to[n]);
       if (!label)
        {
-         SET_BIT (graph->pt_used, n);
          label = pointer_equiv_class++;
          equiv_class_add (pointer_equiv_class_table,
                           label, graph->points_to[n]);
@@ -2054,10 +2179,8 @@ free_var_substitution_info (struct scc_info *si)
   free (graph->loc_label);
   free (graph->pointed_by);
   free (graph->points_to);
-  free (graph->number_incoming);
   free (graph->eq_rep);
   sbitmap_free (graph->direct_nodes);
-  sbitmap_free (graph->pt_used);
   htab_delete (pointer_equiv_class_table);
   htab_delete (location_equiv_class_table);
   bitmap_obstack_release (&iteration_obstack);
@@ -2574,12 +2697,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;
@@ -2632,8 +2749,7 @@ could_have_pointers (tree t)
   tree type = TREE_TYPE (t);
 
   if (POINTER_TYPE_P (type)
-      || AGGREGATE_TYPE_P (type)
-      || TREE_CODE (type) == COMPLEX_TYPE)
+      || AGGREGATE_TYPE_P (type))
     return true;
 
   return false;
@@ -2642,16 +2758,129 @@ could_have_pointers (tree t)
 /* Return the position, in bits, of FIELD_DECL from the beginning of its
    structure.  */
 
-static unsigned HOST_WIDE_INT
+static HOST_WIDE_INT
 bitpos_of_field (const tree fdecl)
 {
 
-  if (TREE_CODE (DECL_FIELD_OFFSET (fdecl)) != INTEGER_CST
-      || TREE_CODE (DECL_FIELD_BIT_OFFSET (fdecl)) != INTEGER_CST)
+  if (!host_integerp (DECL_FIELD_OFFSET (fdecl), 0)
+      || !host_integerp (DECL_FIELD_BIT_OFFSET (fdecl), 0))
     return -1;
 
-  return (tree_low_cst (DECL_FIELD_OFFSET (fdecl), 1) * 8)
-        + tree_low_cst (DECL_FIELD_BIT_OFFSET (fdecl), 1);
+  return (TREE_INT_CST_LOW (DECL_FIELD_OFFSET (fdecl)) * 8
+         + TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (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;
+    }
 }
 
 
@@ -2691,15 +2920,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
@@ -2728,12 +2960,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)
        {
@@ -2801,8 +3046,14 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p)
      happens below, since it will fall into the default case. The only
      case we know something about an integer treated like a pointer is
      when it is the NULL pointer, and then we just say it points to
-     NULL.  */
-  if (TREE_CODE (t) == INTEGER_CST
+     NULL.
+
+     Do not do that if -fno-delete-null-pointer-checks though, because
+     in that case *NULL does not fail, so it _should_ alias *anything.
+     It is not worth adding a new option or renaming the existing one,
+     since this case is relatively obscure.  */
+  if (flag_delete_null_pointer_checks
+      && TREE_CODE (t) == INTEGER_CST
       && integer_zerop (t))
     {
       temp.var = nothing_id;
@@ -2825,7 +3076,6 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p)
   switch (TREE_CODE_CLASS (TREE_CODE (t)))
     {
     case tcc_expression:
-    case tcc_vl_exp:
       {
        switch (TREE_CODE (t))
          {
@@ -2847,54 +3097,9 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p)
              return;
            }
            break;
-         case CALL_EXPR:
-           /* XXX: In interprocedural mode, if we didn't have the
-              body, we would need to do *each pointer argument =
-              &ANYTHING added.  */
-           if (call_expr_flags (t) & (ECF_MALLOC | ECF_MAY_BE_ALLOCA))
-             {
-               varinfo_t vi;
-               tree heapvar = heapvar_lookup (t);
-
-               if (heapvar == NULL)
-                 {
-                   heapvar = create_tmp_var_raw (ptr_type_node, "HEAP");
-                   DECL_EXTERNAL (heapvar) = 1;
-                   get_var_ann (heapvar)->is_heapvar = 1;
-                   if (gimple_referenced_vars (cfun))
-                     add_referenced_var (heapvar);
-                   heapvar_insert (t, heapvar);
-                 }
-
-               temp.var = create_variable_info_for (heapvar,
-                                                    alias_get_name (heapvar));
-
-               vi = get_varinfo (temp.var);
-               vi->is_artificial_var = 1;
-               vi->is_heap_var = 1;
-               temp.type = ADDRESSOF;
-               temp.offset = 0;
-               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:
       {
@@ -2911,85 +3116,36 @@ 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;
-           }
-         }
-      }
-    case tcc_unary:
-      {
-       switch (TREE_CODE (t))
-         {
-         CASE_CONVERT:
-           {
-             tree op = TREE_OPERAND (t, 0);
-
-             /* Cast from non-pointer to pointers are bad news for us.
-                Anything else, we see through */
-             if (!(POINTER_TYPE_P (TREE_TYPE (t))
-                   && ! POINTER_TYPE_P (TREE_TYPE (op))))
-               {
-                 get_constraint_for_1 (op, results, address_p);
-                 return;
-               }
-
-             /* 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_exceptional:
       {
        switch (TREE_CODE (t))
          {
-         case PHI_NODE:
-           {
-             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.  */
@@ -3137,8 +3293,8 @@ collapse_rest_of_var (unsigned int var)
        fprintf (dump_file, "Type safety: Collapsing var %s into %s\n",
                 field->name, currvar->name);
 
-      gcc_assert (!field->collapsed_to);
-      field->collapsed_to = currvar;
+      gcc_assert (field->collapsed_to == 0);
+      field->collapsed_to = currvar->id;
     }
 
   currvar->next = NULL;
@@ -3249,8 +3405,8 @@ do_structure_copy (tree lhsop, tree rhsop)
        {
          if (!do_simple_structure_copy (lhs, rhs, MIN (lhssize, rhssize)))
            {
-             lhs.var = collapse_rest_of_var (lhs.var);
-             rhs.var = collapse_rest_of_var (rhs.var);
+             lhs.var = collapse_rest_of_var (get_varinfo_fc (lhs.var)->id);
+             rhs.var = collapse_rest_of_var (get_varinfo_fc (rhs.var)->id);
              lhs.offset = 0;
              rhs.offset = 0;
              lhs.type = SCALAR;
@@ -3275,80 +3431,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
@@ -3381,20 +3463,23 @@ make_escape_constraint (tree op)
    RHS.  */
 
 static void
-handle_rhs_call  (tree rhs)
+handle_rhs_call (gimple stmt)
 {
-  tree arg;
-  call_expr_arg_iterator iter;
+  unsigned i;
+
+  for (i = 0; i < gimple_call_num_args (stmt); ++i)
+    {
+      tree arg = gimple_call_arg (stmt, i);
 
-  FOR_EACH_CALL_EXPR_ARG (arg, iter, rhs)
-    /* Find those pointers being passed, and make sure they end up
-       pointing to anything.  */
-    if (could_have_pointers (arg))
-      make_escape_constraint (arg);
+      /* Find those pointers being passed, and make sure they end up
+        pointing to anything.  */
+      if (could_have_pointers (arg))
+       make_escape_constraint (arg);
+    }
 
   /* The static chain escapes as well.  */
-  if (CALL_EXPR_STATIC_CHAIN (rhs))
-    make_escape_constraint (CALL_EXPR_STATIC_CHAIN (rhs));
+  if (gimple_call_chain (stmt))
+    make_escape_constraint (gimple_call_chain (stmt));
 }
 
 /* For non-IPA mode, generate constraints necessary for a call
@@ -3449,22 +3534,20 @@ handle_lhs_call (tree lhs, int flags)
    const function that returns a pointer in the statement STMT.  */
 
 static void
-handle_const_call (tree stmt)
+handle_const_call (gimple stmt)
 {
-  tree lhs = GIMPLE_STMT_OPERAND (stmt, 0);
-  tree call = get_call_expr_in (stmt);
+  tree lhs = gimple_call_lhs (stmt);
   VEC(ce_s, heap) *lhsc = NULL;
   struct constraint_expr rhsc;
-  unsigned int j;
+  unsigned int j, k;
   struct constraint_expr *lhsp;
-  tree arg, tmpvar;
-  call_expr_arg_iterator iter;
+  tree tmpvar;
   struct constraint_expr tmpc;
 
   get_constraint_for (lhs, &lhsc);
 
   /* If this is a nested function then it can return anything.  */
-  if (CALL_EXPR_STATIC_CHAIN (call))
+  if (gimple_call_chain (stmt))
     {
       rhsc.var = anything_id;
       rhsc.offset = 0;
@@ -3489,18 +3572,22 @@ handle_const_call (tree stmt)
   process_constraint (new_constraint (tmpc, rhsc));
 
   /* May return arguments.  */
-  FOR_EACH_CALL_EXPR_ARG (arg, iter, call)
-    if (could_have_pointers (arg))
-      {
-       VEC(ce_s, heap) *argc = NULL;
-       struct constraint_expr *argp;
-       int i;
-
-       get_constraint_for (arg, &argc);
-       for (i = 0; VEC_iterate (ce_s, argc, i, argp); i++)
-         process_constraint (new_constraint (tmpc, *argp));
-       VEC_free (ce_s, heap, argc);
-      }
+  for (k = 0; k < gimple_call_num_args (stmt); ++k)
+    {
+      tree arg = gimple_call_arg (stmt, k);
+
+      if (could_have_pointers (arg))
+       {
+         VEC(ce_s, heap) *argc = NULL;
+         struct constraint_expr *argp;
+         int i;
+
+         get_constraint_for (arg, &argc);
+         for (i = 0; VEC_iterate (ce_s, argc, i, argp); i++)
+           process_constraint (new_constraint (tmpc, *argp));
+         VEC_free (ce_s, heap, argc);
+       }
+    }
 
   for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
     process_constraint (new_constraint (*lhsp, tmpc));
@@ -3512,28 +3599,30 @@ handle_const_call (tree stmt)
    pure function in statement STMT.  */
 
 static void
-handle_pure_call (tree stmt)
+handle_pure_call (gimple stmt)
 {
-  tree call = get_call_expr_in (stmt);
-  tree arg;
-  call_expr_arg_iterator iter;
+  unsigned i;
 
   /* Memory reached from pointer arguments is call-used.  */
-  FOR_EACH_CALL_EXPR_ARG (arg, iter, call)
-    if (could_have_pointers (arg))
-      make_constraint_to (callused_id, arg);
+  for (i = 0; i < gimple_call_num_args (stmt); ++i)
+    {
+      tree arg = gimple_call_arg (stmt, i);
+
+      if (could_have_pointers (arg))
+       make_constraint_to (callused_id, arg);
+    }
 
   /* The static chain is used as well.  */
-  if (CALL_EXPR_STATIC_CHAIN (call))
-    make_constraint_to (callused_id, CALL_EXPR_STATIC_CHAIN (call));
+  if (gimple_call_chain (stmt))
+    make_constraint_to (callused_id, gimple_call_chain (stmt));
 
   /* If the call returns a pointer it may point to reachable memory
      from the arguments.  Not so for malloc functions though.  */
-  if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
-      && could_have_pointers (GIMPLE_STMT_OPERAND (stmt, 0))
-      && !(call_expr_flags (call) & ECF_MALLOC))
+  if (gimple_call_lhs (stmt)
+      && could_have_pointers (gimple_call_lhs (stmt))
+      && !(gimple_call_flags (stmt) & ECF_MALLOC))
     {
-      tree lhs = GIMPLE_STMT_OPERAND (stmt, 0);
+      tree lhs = gimple_call_lhs (stmt);
       VEC(ce_s, heap) *lhsc = NULL;
       struct constraint_expr rhsc;
       struct constraint_expr *lhsp;
@@ -3542,7 +3631,7 @@ handle_pure_call (tree stmt)
       get_constraint_for (lhs, &lhsc);
 
       /* If this is a nested function then it can return anything.  */
-      if (CALL_EXPR_STATIC_CHAIN (call))
+      if (gimple_call_chain (stmt))
        {
          rhsc.var = anything_id;
          rhsc.offset = 0;
@@ -3570,40 +3659,37 @@ handle_pure_call (tree stmt)
    when building alias sets and computing alias grouping heuristics.  */
 
 static void
-find_func_aliases (tree origt)
+find_func_aliases (gimple origt)
 {
-  tree call, t = origt;
+  gimple t = origt;
   VEC(ce_s, heap) *lhsc = NULL;
   VEC(ce_s, heap) *rhsc = NULL;
   struct constraint_expr *c;
   enum escape_type stmt_escape_type;
 
-  if (TREE_CODE (t) == RETURN_EXPR && TREE_OPERAND (t, 0))
-    t = TREE_OPERAND (t, 0);
-
   /* Now build constraints expressions.  */
-  if (TREE_CODE (t) == PHI_NODE)
+  if (gimple_code (t) == GIMPLE_PHI)
     {
-      gcc_assert (!AGGREGATE_TYPE_P (TREE_TYPE (PHI_RESULT (t))));
+      gcc_assert (!AGGREGATE_TYPE_P (TREE_TYPE (gimple_phi_result (t))));
 
       /* Only care about pointers and structures containing
         pointers.  */
-      if (could_have_pointers (PHI_RESULT (t)))
+      if (could_have_pointers (gimple_phi_result (t)))
        {
-         int i;
+         size_t i;
          unsigned int j;
 
          /* For a phi node, assign all the arguments to
             the result.  */
-         get_constraint_for (PHI_RESULT (t), &lhsc);
-         for (i = 0; i < PHI_NUM_ARGS (t); i++)
+         get_constraint_for (gimple_phi_result (t), &lhsc);
+         for (i = 0; i < gimple_phi_num_args (t); i++)
            {
              tree rhstype;
              tree strippedrhs = PHI_ARG_DEF (t, i);
 
              STRIP_NOPS (strippedrhs);
              rhstype = TREE_TYPE (strippedrhs);
-             get_constraint_for (PHI_ARG_DEF (t, i), &rhsc);
+             get_constraint_for (gimple_phi_arg_def (t, i), &rhsc);
 
              for (j = 0; VEC_iterate (ce_s, lhsc, j, c); j++)
                {
@@ -3619,87 +3705,73 @@ find_func_aliases (tree origt)
        }
     }
   /* In IPA mode, we need to generate constraints to pass call
-     arguments through their calls.   There are two cases, either a
-     GIMPLE_MODIFY_STMT when we are returning a value, or just a plain
-     CALL_EXPR when we are not.
+     arguments through their calls.   There are two cases,
+     either a GIMPLE_CALL returning a value, or just a plain
+     GIMPLE_CALL when we are not.
 
      In non-ipa mode, we need to generate constraints for each
      pointer passed by address.  */
-  else if ((call = get_call_expr_in (t)) != NULL_TREE)
+  else if (is_gimple_call (t))
     {
-      int flags = call_expr_flags (call);
       if (!in_ipa_mode)
        {
+         int flags = gimple_call_flags (t);
+
          /* Const functions can return their arguments and addresses
             of global memory but not of escaped memory.  */
          if (flags & ECF_CONST)
            {
-             if (TREE_CODE (t) == GIMPLE_MODIFY_STMT
-                 && could_have_pointers (GIMPLE_STMT_OPERAND (t, 1)))
+             if (gimple_call_lhs (t)
+                 && could_have_pointers (gimple_call_lhs (t)))
                handle_const_call (t);
            }
+         /* Pure functions can return addresses in and of memory
+            reachable from their arguments, but they are not an escape
+            point for reachable memory of their arguments.  */
          else if (flags & ECF_PURE)
            {
              handle_pure_call (t);
-             if (TREE_CODE (t) == GIMPLE_MODIFY_STMT
-                 && could_have_pointers (GIMPLE_STMT_OPERAND (t, 1)))
-               handle_lhs_call (GIMPLE_STMT_OPERAND (t, 0), flags);
+             if (gimple_call_lhs (t)
+                 && could_have_pointers (gimple_call_lhs (t)))
+               handle_lhs_call (gimple_call_lhs (t), flags);
            }
-         /* Pure functions can return addresses in and of memory
-            reachable from their arguments, but they are not an escape
-            point for reachable memory of their arguments.  But as we
-            do not compute call-used memory separately we cannot do
-            something special here.  */
-         else if (TREE_CODE (t) == GIMPLE_MODIFY_STMT)
+         else
            {
-             handle_rhs_call (GIMPLE_STMT_OPERAND (t, 1));
-             if (could_have_pointers (GIMPLE_STMT_OPERAND (t, 1)))
-               handle_lhs_call (GIMPLE_STMT_OPERAND (t, 0), flags);
+             handle_rhs_call (t);
+             if (gimple_call_lhs (t)
+                 && could_have_pointers (gimple_call_lhs (t)))
+               handle_lhs_call (gimple_call_lhs (t), flags);
            }
-         else
-           handle_rhs_call (t);
        }
       else
        {
          tree lhsop;
-         tree rhsop;
-         tree arg;
-         call_expr_arg_iterator iter;
          varinfo_t fi;
          int i = 1;
+         size_t j;
          tree decl;
-         if (TREE_CODE (t) == GIMPLE_MODIFY_STMT)
-           {
-             lhsop = GIMPLE_STMT_OPERAND (t, 0);
-             rhsop = GIMPLE_STMT_OPERAND (t, 1);
-           }
-         else
-           {
-             lhsop = NULL;
-             rhsop = t;
-           }
-         decl = get_callee_fndecl (rhsop);
+
+         lhsop = gimple_call_lhs (t);
+         decl = gimple_call_fndecl (t);
 
          /* If we can directly resolve the function being called, do so.
             Otherwise, it must be some sort of indirect expression that
             we should still be able to handle.  */
          if (decl)
-           {
-             fi = get_vi_for_tree (decl);
-           }
+           fi = get_vi_for_tree (decl);
          else
            {
-             decl = CALL_EXPR_FN (rhsop);
+             decl = gimple_call_fn (t);
              fi = get_vi_for_tree (decl);
            }
 
          /* Assign all the passed arguments to the appropriate incoming
             parameters of the function.  */
-
-         FOR_EACH_CALL_EXPR_ARG (arg, iter, rhsop)
+         for (j = 0; j < gimple_call_num_args (t); j++)
            {
              struct constraint_expr lhs ;
              struct constraint_expr *rhsp;
+             tree arg = gimple_call_arg (t, j);
 
              get_constraint_for (arg, &rhsc);
              if (TREE_CODE (decl) != FUNCTION_DECL)
@@ -3748,97 +3820,54 @@ 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 (is_gimple_assign (t)
+          && could_have_pointers (gimple_assign_lhs (t)))
     {
-      tree lhsop = GIMPLE_STMT_OPERAND (t, 0);
-      tree rhsop = GIMPLE_STMT_OPERAND (t, 1);
-      int i;
+      /* Otherwise, just a regular assignment statement.  */
+      tree lhsop = gimple_assign_lhs (t);
+      tree rhsop = (gimple_num_ops (t) == 2) ? gimple_assign_rhs1 (t) : NULL;
 
-      if (AGGREGATE_TYPE_P (TREE_TYPE (lhsop))
-         && AGGREGATE_TYPE_P (TREE_TYPE (rhsop)))
-       {
-         do_structure_copy (lhsop, rhsop);
-       }
+      if (rhsop && 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;
+         struct constraint_expr temp;
+         get_constraint_for (lhsop, &lhsc);
+
+         if (gimple_assign_rhs_code (t) == POINTER_PLUS_EXPR)
+           get_constraint_for_ptr_offset (gimple_assign_rhs1 (t),
+                                          gimple_assign_rhs2 (t), &rhsc);
+         else if ((CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (t))
+                   && !(POINTER_TYPE_P (gimple_expr_type (t))
+                        && !POINTER_TYPE_P (TREE_TYPE (rhsop))))
+                  || gimple_assign_single_p (t))
+           get_constraint_for (rhsop, &rhsc);
+         else
            {
-             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;
+             temp.type = ADDRESSOF;
+             temp.var = anything_id;
+             temp.offset = 0;
+             VEC_safe_push (ce_s, heap, rhsc, &temp);
+           }
+         for (j = 0; VEC_iterate (ce_s, lhsc, j, c); j++)
+           {
+             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));
            }
        }
     }
-  else if (TREE_CODE (t) == CHANGE_DYNAMIC_TYPE_EXPR)
+  else if (gimple_code (t) == GIMPLE_CHANGE_DYNAMIC_TYPE)
     {
       unsigned int j;
 
-      get_constraint_for (CHANGE_DYNAMIC_TYPE_LOCATION (t), &lhsc);
+      get_constraint_for (gimple_cdt_location (t), &lhsc);
       for (j = 0; VEC_iterate (ce_s, lhsc, j, c); ++j)
        get_varinfo (c->var)->no_tbaa_pruning = true;
     }
@@ -3846,48 +3875,46 @@ find_func_aliases (tree origt)
   stmt_escape_type = is_escape_site (t);
   if (stmt_escape_type == ESCAPE_STORED_IN_GLOBAL)
     {
-      tree rhs;
-      gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
-      rhs = GIMPLE_STMT_OPERAND (t, 1);
-      if (TREE_CODE (rhs) == ADDR_EXPR)
+      gcc_assert (is_gimple_assign (t));
+      if (gimple_assign_rhs_code (t) == ADDR_EXPR)
        {
+         tree rhs = gimple_assign_rhs1 (t);
          tree base = get_base_address (TREE_OPERAND (rhs, 0));
          if (base
              && (!DECL_P (base)
                  || !is_global_var (base)))
            make_escape_constraint (rhs);
        }
-      else if (TREE_CODE (rhs) == SSA_NAME
-              && POINTER_TYPE_P (TREE_TYPE (rhs)))
-       make_escape_constraint (rhs);
-      else if (could_have_pointers (rhs))
-       make_escape_constraint (rhs);
+      else if (get_gimple_rhs_class (gimple_assign_rhs_code (t))
+              == GIMPLE_SINGLE_RHS)
+       {
+         if (could_have_pointers (gimple_assign_rhs1 (t)))
+           make_escape_constraint (gimple_assign_rhs1 (t));
+       }
+      else
+       gcc_unreachable ();
     }
   else if (stmt_escape_type == ESCAPE_BAD_CAST)
     {
-      tree rhs;
-      gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
-      rhs = GIMPLE_STMT_OPERAND (t, 1);
-      gcc_assert (CONVERT_EXPR_P (rhs)
-                 || TREE_CODE (rhs) == VIEW_CONVERT_EXPR);
-      rhs = TREE_OPERAND (rhs, 0);
-      make_escape_constraint (rhs);
+      gcc_assert (is_gimple_assign (t));
+      gcc_assert (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (t))
+                 || gimple_assign_rhs_code (t) == VIEW_CONVERT_EXPR);
+      make_escape_constraint (gimple_assign_rhs1 (t));
     }
   else if (stmt_escape_type == ESCAPE_TO_ASM)
     {
-      tree link;
-      int i;
-      for (i = 0, link = ASM_OUTPUTS (t); link; i++, link = TREE_CHAIN (link))
+      unsigned i;
+      for (i = 0; i < gimple_asm_noutputs (t); ++i)
        {
-         tree op = TREE_VALUE (link);
+         tree op = TREE_VALUE (gimple_asm_output_op (t, i));
          if (op && could_have_pointers (op))
            /* Strictly we'd only need the constraints from ESCAPED and
               NONLOCAL.  */
            make_escape_constraint (op);
        }
-      for (i = 0, link = ASM_INPUTS (t); link; i++, link = TREE_CHAIN (link))
+      for (i = 0; i < gimple_asm_ninputs (t); ++i)
        {
-         tree op = TREE_VALUE (link);
+         tree op = TREE_VALUE (gimple_asm_input_op (t, i));
          if (op && could_have_pointers (op))
            /* Strictly we'd only need the constraint to ESCAPED.  */
            make_escape_constraint (op);
@@ -3899,7 +3926,7 @@ find_func_aliases (tree origt)
      number of statements re-scanned.  It's not really necessary to
      re-scan *all* statements.  */
   if (!in_ipa_mode)
-    mark_stmt_modified (origt);
+    gimple_set_modified (origt, true);
   VEC_free (ce_s, heap, rhsc);
   VEC_free (ce_s, heap, lhsc);
 }
@@ -3977,17 +4004,15 @@ insert_into_field_list_sorted (varinfo_t base, varinfo_t field)
 
 struct fieldoff
 {
-  /* Type of the field.  */
-  tree type;
+  /* Offset from the base of the base containing object to this field.  */
+  HOST_WIDE_INT offset;
 
   /* Size, in bits, of the field.  */
-  tree size;
+  unsigned HOST_WIDE_INT size;
 
-  /* Field.  */
-  tree decl;
+  unsigned has_unknown_size : 1;
 
-  /* Offset from the base of the base containing object to this field.  */
-  HOST_WIDE_INT offset;  
+  unsigned may_have_pointers : 1;
 };
 typedef struct fieldoff fieldoff_s;
 
@@ -4008,10 +4033,10 @@ fieldoff_compare (const void *pa, const void *pb)
   else if (foa->offset > fob->offset)
     return 1;
 
-  foasize = TREE_INT_CST_LOW (foa->size);
-  fobsize = TREE_INT_CST_LOW (fob->size);
+  foasize = foa->size;
+  fobsize = fob->size;
   if (foasize < fobsize)
-    return - 1;
+    return -1;
   else if (foasize > fobsize)
     return 1;
   return 0;
@@ -4055,14 +4080,11 @@ var_can_have_subvars (const_tree v)
 
    OFFSET is used to keep track of the offset in this entire
    structure, rather than just the immediately containing structure.
-   Returns the number of fields pushed.
-
-   HAS_UNION is set to true if we find a union type as a field of
-   TYPE.  */
+   Returns the number of fields pushed.  */
 
 static int
 push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
-                            HOST_WIDE_INT offset, bool *has_union)
+                            HOST_WIDE_INT offset)
 {
   tree field;
   int count = 0;
@@ -4081,19 +4103,14 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
       {
        bool push = false;
        int pushed = 0;
+       HOST_WIDE_INT foff = bitpos_of_field (field);
 
-       if (has_union
-           && (TREE_CODE (TREE_TYPE (field)) == QUAL_UNION_TYPE
-               || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE))
-         *has_union = true;
-
-       if (!var_can_have_subvars (field))
+       if (!var_can_have_subvars (field)
+           || TREE_CODE (TREE_TYPE (field)) == QUAL_UNION_TYPE
+           || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
          push = true;
        else if (!(pushed = push_fields_onto_fieldstack
-                  (TREE_TYPE (field),
-                   fieldstack,
-                   offset + bitpos_of_field (field),
-                   has_union))
+                  (TREE_TYPE (field), fieldstack, offset + foff))
                 && (DECL_SIZE (field)
                     && !integer_zerop (DECL_SIZE (field))))
          /* Empty structures may have actual size, like in C++.  So
@@ -4103,14 +4120,39 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
 
        if (push)
          {
-           fieldoff_s *pair;
-
-           pair = VEC_safe_push (fieldoff_s, heap, *fieldstack, NULL);
-           pair->type = TREE_TYPE (field);
-           pair->size = DECL_SIZE (field);
-           pair->decl = field;
-           pair->offset = offset + bitpos_of_field (field);
-           count++;
+           fieldoff_s *pair = NULL;
+           bool has_unknown_size = false;
+
+           if (!VEC_empty (fieldoff_s, *fieldstack))
+             pair = VEC_last (fieldoff_s, *fieldstack);
+
+           if (!DECL_SIZE (field)
+               || !host_integerp (DECL_SIZE (field), 1))
+             has_unknown_size = true;
+
+           /* If adjacent fields do not contain pointers merge them.  */
+           if (pair
+               && !pair->may_have_pointers
+               && !could_have_pointers (field)
+               && !pair->has_unknown_size
+               && !has_unknown_size
+               && pair->offset + (HOST_WIDE_INT)pair->size == offset + foff)
+             {
+               pair = VEC_last (fieldoff_s, *fieldstack);
+               pair->size += TREE_INT_CST_LOW (DECL_SIZE (field));
+             }
+           else
+             {
+               pair = VEC_safe_push (fieldoff_s, heap, *fieldstack, NULL);
+               pair->offset = offset + foff;
+               pair->has_unknown_size = has_unknown_size;
+               if (!has_unknown_size)
+                 pair->size = TREE_INT_CST_LOW (DECL_SIZE (field));
+               else
+                 pair->size = -1;
+               pair->may_have_pointers = could_have_pointers (field);
+               count++;
+             }
          }
        else
          count += pushed;
@@ -4176,7 +4218,6 @@ create_function_info_for (tree decl, const char *name)
   vi = new_var_info (decl, index, name);
   vi->decl = decl;
   vi->offset = 0;
-  vi->has_union = 0;
   vi->size = 1;
   vi->fullsize = count_num_arguments (decl, &is_varargs) + 1;
   insert_vi_for_tree (vi->decl, vi);
@@ -4185,8 +4226,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;
@@ -4220,8 +4260,8 @@ 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;
-      argvi->has_union = false;
       insert_into_field_list_sorted (vi, argvi);
       stats.total_vars ++;
       if (arg)
@@ -4257,7 +4297,7 @@ create_function_info_for (tree decl, const char *name)
       resultvi->offset = i;
       resultvi->size = 1;
       resultvi->fullsize = vi->fullsize;
-      resultvi->has_union = false;
+      resultvi->is_full_var = true;
       insert_into_field_list_sorted (vi, resultvi);
       stats.total_vars ++;
       if (DECL_RESULT (decl))
@@ -4295,27 +4335,20 @@ create_variable_info_for (tree decl, const char *name)
 {
   unsigned int index = VEC_length (varinfo_t, varmap);
   varinfo_t vi;
-  tree decltype = TREE_TYPE (decl);
-  tree declsize = DECL_P (decl) ? DECL_SIZE (decl) : TYPE_SIZE (decltype);
-  bool notokay = false;
-  bool hasunion;
+  tree decl_type = TREE_TYPE (decl);
+  tree declsize = DECL_P (decl) ? DECL_SIZE (decl) : TYPE_SIZE (decl_type);
   bool is_global = DECL_P (decl) ? is_global_var (decl) : false;
   VEC (fieldoff_s,heap) *fieldstack = NULL;
 
   if (TREE_CODE (decl) == FUNCTION_DECL && in_ipa_mode)
     return create_function_info_for (decl, name);
 
-  hasunion = TREE_CODE (decltype) == UNION_TYPE
-            || TREE_CODE (decltype) == QUAL_UNION_TYPE;
-  if (var_can_have_subvars (decl) && use_field_sensitive && !hasunion)
-    {
-      push_fields_onto_fieldstack (decltype, &fieldstack, 0, &hasunion);
-      if (hasunion)
-       {
-         VEC_free (fieldoff_s, heap, fieldstack);
-         notokay = true;
-       }
-    }
+  if (var_can_have_subvars (decl) && use_field_sensitive
+      && (!var_ann (decl)
+         || var_ann (decl)->noalias_state == 0)
+      && (!var_ann (decl)
+         || !var_ann (decl)->is_heapvar))
+    push_fields_onto_fieldstack (decl_type, &fieldstack, 0);
 
   /* If the variable doesn't have subvars, we may end up needing to
      sort the field list and create fake variables for all the
@@ -4323,11 +4356,8 @@ create_variable_info_for (tree decl, const char *name)
   vi = new_var_info (decl, index, name);
   vi->decl = decl;
   vi->offset = 0;
-  vi->has_union = hasunion;
   if (!declsize
-      || TREE_CODE (declsize) != INTEGER_CST
-      || TREE_CODE (decltype) == UNION_TYPE
-      || TREE_CODE (decltype) == QUAL_UNION_TYPE)
+      || !host_integerp (declsize, 1))
     {
       vi->is_unknown_size_var = true;
       vi->fullsize = ~0;
@@ -4343,11 +4373,16 @@ create_variable_info_for (tree decl, const char *name)
   VEC_safe_push (varinfo_t, heap, varmap, vi);
   if (is_global && (!flag_whole_program || !in_ipa_mode)
       && could_have_pointers (decl))
-    make_constraint_from (vi, escaped_id);
+    {
+      if (var_ann (decl)
+         && var_ann (decl)->noalias_state == NO_ALIAS_ANYTHING)
+       make_constraint_from (vi, vi->id);
+      else
+       make_constraint_from (vi, escaped_id);
+    }
 
   stats.total_vars++;
   if (use_field_sensitive
-      && !notokay
       && !vi->is_unknown_size_var
       && var_can_have_subvars (decl)
       && VEC_length (fieldoff_s, fieldstack) > 1
@@ -4355,12 +4390,12 @@ create_variable_info_for (tree decl, const char *name)
     {
       unsigned int newindex = VEC_length (varinfo_t, varmap);
       fieldoff_s *fo = NULL;
+      bool notokay = false;
       unsigned int i;
 
       for (i = 0; !notokay && VEC_iterate (fieldoff_s, fieldstack, i, fo); i++)
        {
-         if (! fo->size
-             || TREE_CODE (fo->size) != INTEGER_CST
+         if (fo->has_unknown_size
              || fo->offset < 0)
            {
              notokay = true;
@@ -4391,11 +4426,12 @@ 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;
        }
 
-      vi->size = TREE_INT_CST_LOW (fo->size);
+      vi->size = fo->size;
       vi->offset = fo->offset;
       for (i = VEC_length (fieldoff_s, fieldstack) - 1;
           i >= 1 && VEC_iterate (fieldoff_s, fieldstack, i, fo);
@@ -4408,28 +4444,27 @@ create_variable_info_for (tree decl, const char *name)
          newindex = VEC_length (varinfo_t, varmap);
          if (dump_file)
            {
-             if (fo->decl)
-               asprintf (&tempname, "%s.%s",
-                         vi->name, alias_get_name (fo->decl));
-             else
-               asprintf (&tempname, "%s." HOST_WIDE_INT_PRINT_DEC,
-                         vi->name, fo->offset);
+             asprintf (&tempname, "%s." HOST_WIDE_INT_PRINT_DEC
+                       "+" HOST_WIDE_INT_PRINT_DEC,
+                       vi->name, fo->offset, fo->size);
              newname = ggc_strdup (tempname);
              free (tempname);
            }
          newvi = new_var_info (decl, newindex, newname);
          newvi->offset = fo->offset;
-         newvi->size = TREE_INT_CST_LOW (fo->size);
+         newvi->size = fo->size;
          newvi->fullsize = vi->fullsize;
          insert_into_field_list (vi, newvi);
          VEC_safe_push (varinfo_t, heap, varmap, newvi);
          if (is_global && (!flag_whole_program || !in_ipa_mode)
-             && (!fo->decl || could_have_pointers (fo->decl)))
+             && fo->may_have_pointers)
            make_constraint_from (newvi, escaped_id);
 
          stats.total_vars++;
        }
     }
+  else
+    vi->is_full_var = true;
 
   VEC_free (fieldoff_s, heap, fieldstack);
 
@@ -4515,6 +4550,7 @@ intra_create_variable_infos (void)
              heapvar_insert (t, heapvar);
 
              ann = get_var_ann (heapvar);
+             ann->is_heapvar = 1;
              if (flag_argument_noalias == 1)
                ann->noalias_state = NO_ALIAS;
              else if (flag_argument_noalias == 2)
@@ -4546,6 +4582,25 @@ intra_create_variable_infos (void)
            make_constraint_from (p, nonlocal_id);
        }
     }
+
+  /* Add a constraint for a result decl that is passed by reference.  */
+  if (DECL_RESULT (cfun->decl)
+      && DECL_BY_REFERENCE (DECL_RESULT (cfun->decl)))
+    {
+      varinfo_t p, result_vi = get_vi_for_tree (DECL_RESULT (cfun->decl));
+
+      for (p = result_vi; p; p = p->next)
+        make_constraint_from (p, nonlocal_id);
+    }
+
+  /* Add a constraint for the incoming static chain parameter.  */
+  if (cfun->static_chain_decl != NULL_TREE)
+    {
+      varinfo_t p, chain_vi = get_vi_for_tree (cfun->static_chain_decl);
+
+      for (p = chain_vi; p; p = p->next)
+       make_constraint_from (p, nonlocal_id);
+    }
 }
 
 /* Structure used to put solution bitmaps in a hashtable so they can
@@ -4625,14 +4680,15 @@ shared_bitmap_add (bitmap pt_vars)
    IS_DEREFED is true if PTR was directly dereferenced, which we use to
    help determine whether we are we are allowed to prune using TBAA.
    If NO_TBAA_PRUNING is true, we do not perform any TBAA pruning of
-   the from set.  */
+   the from set.  Returns the number of pruned variables.  */
 
-static void
+static unsigned
 set_uids_in_ptset (tree ptr, bitmap into, bitmap from, bool is_derefed,
                   bool no_tbaa_pruning)
 {
   unsigned int i;
   bitmap_iterator bi;
+  unsigned pruned = 0;
 
   gcc_assert (POINTER_TYPE_P (TREE_TYPE (ptr)));
 
@@ -4655,7 +4711,8 @@ set_uids_in_ptset (tree ptr, bitmap into, bitmap from, bool is_derefed,
             type-based pruning disabled.  */
          if (vi->is_artificial_var
              || !is_derefed
-             || no_tbaa_pruning)
+             || no_tbaa_pruning
+             || vi->no_tbaa_pruning)
            bitmap_set_bit (into, DECL_UID (vi->decl));
          else
            {
@@ -4665,66 +4722,100 @@ set_uids_in_ptset (tree ptr, bitmap into, bitmap from, bool is_derefed,
              if (may_alias_p (SSA_NAME_VAR (ptr), mem_alias_set,
                               vi->decl, var_alias_set, true))
                bitmap_set_bit (into, DECL_UID (vi->decl));
+             else
+               ++pruned;
            }
        }
     }
+
+  return pruned;
 }
 
 
 static bool have_alias_info = false;
 
-/* The list of SMT's that are in use by our pointer variables.  This
-   is the set of SMT's for all pointers that can point to anything.   */
-static bitmap used_smts;
+/* Emit a note for the pointer initialization point DEF.  */
 
-/* Due to the ordering of points-to set calculation and SMT
-   calculation being a bit co-dependent, we can't just calculate SMT
-   used info whenever we want, we have to calculate it around the time
-   that find_what_p_points_to is called.  */
+static void
+emit_pointer_definition (tree ptr, bitmap visited)
+{
+  gimple def = SSA_NAME_DEF_STMT (ptr);
+  if (gimple_code (def) == GIMPLE_PHI)
+    {
+      use_operand_p argp;
+      ssa_op_iter oi;
 
-/* Mark which SMT's are in use by points-to anything variables.  */
+      FOR_EACH_PHI_ARG (argp, def, oi, SSA_OP_USE)
+       {
+         tree arg = USE_FROM_PTR (argp);
+         if (TREE_CODE (arg) == SSA_NAME)
+           {
+             if (bitmap_set_bit (visited, SSA_NAME_VERSION (arg)))
+               emit_pointer_definition (arg, visited);
+           }
+         else
+           inform (0, "initialized from %qE", arg);
+       }
+    }
+  else if (!gimple_nop_p (def))
+    inform (gimple_location (def), "initialized from here");
+}
 
-void
-set_used_smts (void)
+/* Emit a strict aliasing warning for dereferencing the pointer PTR.  */
+
+static void
+emit_alias_warning (tree ptr)
 {
-  int i;
-  varinfo_t vi;
-  used_smts = BITMAP_ALLOC (&pta_obstack);
+  gimple use;
+  imm_use_iterator ui;
+  bool warned = false;
 
-  for (i = 0; VEC_iterate (varinfo_t, varmap, i, vi); i++)
+  FOR_EACH_IMM_USE_STMT (use, ui, ptr)
     {
-      tree var = vi->decl;
-      varinfo_t withsolution = get_varinfo (find (i));
-      tree smt;
-      var_ann_t va;
-      struct ptr_info_def *pi = NULL;
-
-      /* For parm decls, the pointer info may be under the default
-        def.  */
-      if (TREE_CODE (vi->decl) == PARM_DECL
-         && gimple_default_def (cfun, var))
-       pi = SSA_NAME_PTR_INFO (gimple_default_def (cfun, var));
-      else if (TREE_CODE (var) == SSA_NAME)
-       pi = SSA_NAME_PTR_INFO (var);
-
-      /* Skip the special variables and those that can't be aliased.  */
-      if (vi->is_special_var
-         || !SSA_VAR_P (var)
-         || (pi && !pi->memory_tag_needed)
-         || (TREE_CODE (var) == VAR_DECL && !may_be_aliased (var))
-         || !POINTER_TYPE_P (TREE_TYPE (var)))
-       continue;
-
-      if (TREE_CODE (var) == SSA_NAME)
-       var = SSA_NAME_VAR (var);
-
-      va = var_ann (var);
-      if (!va)
-       continue;
+      tree deref = NULL_TREE;
 
-      smt = va->symbol_mem_tag;
-      if (smt && bitmap_bit_p (withsolution->solution, anything_id))
-       bitmap_set_bit (used_smts, DECL_UID (smt));
+      if (gimple_has_lhs (use))
+       {
+         tree lhs = get_base_address (gimple_get_lhs (use));
+         if (lhs
+             && INDIRECT_REF_P (lhs)
+             && TREE_OPERAND (lhs, 0) == ptr)
+           deref = lhs;
+       }
+      if (gimple_assign_single_p (use))
+       {
+         tree rhs = get_base_address (gimple_assign_rhs1 (use));
+         if (rhs
+             && INDIRECT_REF_P (rhs)
+             && TREE_OPERAND (rhs, 0) == ptr)
+           deref = rhs;
+       }
+      else if (is_gimple_call (use))
+       {
+         unsigned i;
+         for (i = 0; i < gimple_call_num_args (use); ++i)
+           {
+             tree op = get_base_address (gimple_call_arg (use, i));
+             if (op
+                 && INDIRECT_REF_P (op)
+                 && TREE_OPERAND (op, 0) == ptr)
+               deref = op;
+           }
+       }
+      if (deref
+         && !TREE_NO_WARNING (deref))
+       {
+         TREE_NO_WARNING (deref) = 1;
+         warned |= warning_at (gimple_location (use), OPT_Wstrict_aliasing,
+                               "dereferencing pointer %qD does break "
+                               "strict-aliasing rules", SSA_NAME_VAR (ptr));
+       }
+    }
+  if (warned)
+    {
+      bitmap visited = BITMAP_ALLOC (NULL);
+      emit_pointer_definition (ptr, visited);
+      BITMAP_FREE (visited);
     }
 }
 
@@ -4772,7 +4863,7 @@ find_what_p_points_to (tree p)
       else
        {
          struct ptr_info_def *pi = get_ptr_info (p);
-         unsigned int i;
+         unsigned int i, pruned;
          bitmap_iterator bi;
          bool was_pt_anything = false;
          bitmap finished_solution;
@@ -4824,9 +4915,9 @@ find_what_p_points_to (tree p)
          finished_solution = BITMAP_GGC_ALLOC ();
          stats.points_to_sets_created++;
 
-         set_uids_in_ptset (p, finished_solution, vi->solution,
-                            pi->is_dereferenced,
-                            vi->no_tbaa_pruning);
+         pruned = set_uids_in_ptset (p, finished_solution, vi->solution,
+                                     pi->is_dereferenced,
+                                     vi->no_tbaa_pruning);
          result = shared_bitmap_lookup (finished_solution);
 
          if (!result)
@@ -4841,7 +4932,23 @@ find_what_p_points_to (tree p)
            }
 
          if (bitmap_empty_p (pi->pt_vars))
-           pi->pt_vars = NULL;
+           {
+             pi->pt_vars = NULL;
+             if (pruned > 0
+                 && !pi->pt_null
+                 && pi->is_dereferenced
+                 && warn_strict_aliasing > 0
+                 && !SSA_NAME_IS_DEFAULT_DEF (p))
+               {
+                 if (dump_file && dump_flags & TDF_DETAILS)
+                   {
+                     fprintf (dump_file, "alias warning for ");
+                     print_generic_expr (dump_file, p, 0);
+                     fprintf (dump_file, "\n");
+                   }
+                 emit_alias_warning (p);
+               }
+           }
 
          return true;
        }
@@ -5181,6 +5288,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);
@@ -5387,26 +5496,18 @@ compute_points_to_sets (void)
   /* Now walk all statements and derive aliases.  */
   FOR_EACH_BB (bb)
     {
-      block_stmt_iterator bsi;
-      tree phi;
+      gimple_stmt_iterator gsi;
 
-      for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
-       if (is_gimple_reg (PHI_RESULT (phi)))
-         find_func_aliases (phi);
-
-      for (bsi = bsi_start (bb); !bsi_end_p (bsi); )
+      for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
        {
-         tree stmt = bsi_stmt (bsi);
-
-         find_func_aliases (stmt);
+         gimple phi = gsi_stmt (gsi);
 
-         /* The information in CHANGE_DYNAMIC_TYPE_EXPR nodes has now
-            been captured, and we can remove them.  */
-         if (TREE_CODE (stmt) == CHANGE_DYNAMIC_TYPE_EXPR)
-           bsi_remove (&bsi, true);
-         else
-           bsi_next (&bsi);
+         if (is_gimple_reg (gimple_phi_result (phi)))
+           find_func_aliases (phi);
        }
+
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+       find_func_aliases (gsi_stmt (gsi));
     }
 
 
@@ -5439,6 +5540,10 @@ compute_points_to_sets (void)
   free_var_substitution_info (si);
 
   build_succ_graph ();
+
+  if (dump_file && (dump_flags & TDF_GRAPH))
+    dump_constraint_graph (dump_file);
+
   move_complex_constraints (graph);
 
   if (dump_file)
@@ -5507,8 +5612,7 @@ delete_points_to_sets (void)
 static bool
 gate_ipa_pta (void)
 {
-  return (flag_unit_at_a_time != 0
-         && flag_ipa_pta
+  return (flag_ipa_pta
          /* Don't bother doing anything if the program has errors.  */
          && !(errorcount || sorrycount));
 }
@@ -5556,22 +5660,19 @@ ipa_pta_execute (void)
 
          FOR_EACH_BB_FN (bb, func)
            {
-             block_stmt_iterator bsi;
-             tree phi;
+             gimple_stmt_iterator gsi;
 
-             for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+             for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
+                  gsi_next (&gsi))
                {
-                 if (is_gimple_reg (PHI_RESULT (phi)))
-                   {
-                     find_func_aliases (phi);
-                   }
-               }
+                 gimple phi = gsi_stmt (gsi);
 
-             for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
-               {
-                 tree stmt = bsi_stmt (bsi);
-                 find_func_aliases (stmt);
+                 if (is_gimple_reg (gimple_phi_result (phi)))
+                   find_func_aliases (phi);
                }
+
+             for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+               find_func_aliases (gsi_stmt (gsi));
            }
          current_function_decl = old_func_decl;
          pop_cfun ();
@@ -5657,5 +5758,4 @@ delete_alias_heapvars (void)
   heapvar_for_stmt = NULL;
 }
 
-
 #include "gt-tree-ssa-structalias.h"