OSDN Git Service

Revert accidental commit.
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-structalias.c
index 781eff3..8c9ed6c 100644 (file)
 #include "obstack.h"
 #include "bitmap.h"
 #include "flags.h"
-#include "rtl.h"
-#include "tm_p.h"
-#include "hard-reg-set.h"
 #include "basic-block.h"
 #include "output.h"
 #include "tree.h"
 #include "tree-flow.h"
 #include "tree-inline.h"
-#include "varray.h"
-#include "diagnostic.h"
+#include "diagnostic-core.h"
 #include "toplev.h"
 #include "gimple.h"
 #include "hashtab.h"
    keep the set of called functions for indirect calls.
 
    And probably more.  */
-
-static GTY ((if_marked ("tree_map_marked_p"), param_is (struct tree_map)))
+static GTY ((if_marked ("tree_map_marked_p"), param_is (struct heapvar_map)))
 htab_t heapvar_for_stmt;
 
 static bool use_field_sensitive = true;
@@ -275,6 +270,9 @@ struct variable_info
   /* True if this field may contain pointers.  */
   unsigned int may_have_pointers : 1;
 
+  /* True if this field has only restrict qualified pointers.  */
+  unsigned int only_restrict_pointers : 1;
+
   /* True if this represents a global variable.  */
   unsigned int is_global_var : 1;
 
@@ -381,7 +379,7 @@ heapvar_insert (tree from, unsigned HOST_WIDE_INT offset, tree to)
   struct heapvar_map *h;
   void **loc;
 
-  h = GGC_NEW (struct heapvar_map);
+  h = ggc_alloc_heapvar_map ();
   h->map.base.from = from;
   h->offset = offset;
   h->map.hash = heapvar_map_hash (h);
@@ -412,6 +410,7 @@ new_var_info (tree t, const char *name)
   ret->is_heap_var = false;
   ret->is_restrict_var = false;
   ret->may_have_pointers = true;
+  ret->only_restrict_pointers = false;
   ret->is_global_var = (t == NULL_TREE);
   ret->is_fn_info = false;
   if (t && DECL_P (t))
@@ -420,6 +419,8 @@ new_var_info (tree t, const char *name)
   ret->oldsolution = BITMAP_ALLOC (&oldpta_obstack);
   ret->next = NULL;
 
+  stats.total_vars++;
+
   VEC_safe_push (varinfo_t, heap, varmap, ret);
 
   return ret;
@@ -531,8 +532,9 @@ struct constraint_expr
 typedef struct constraint_expr ce_s;
 DEF_VEC_O(ce_s);
 DEF_VEC_ALLOC_O(ce_s, heap);
-static void get_constraint_for_1 (tree, VEC(ce_s, heap) **, bool);
+static void get_constraint_for_1 (tree, VEC(ce_s, heap) **, bool, bool);
 static void get_constraint_for (tree, VEC(ce_s, heap) **);
+static void get_constraint_for_rhs (tree, VEC(ce_s, heap) **);
 static void do_deref (VEC (ce_s, heap) **);
 
 /* Our set constraints are made up of two constraint expressions, one
@@ -714,7 +716,7 @@ void debug_sa_points_to_info (void);
 
 /* Print out constraint C to stderr.  */
 
-void
+DEBUG_FUNCTION void
 debug_constraint (constraint_t c)
 {
   dump_constraint (stderr, c);
@@ -733,7 +735,7 @@ dump_constraints (FILE *file, int from)
 
 /* Print out all constraints to stderr.  */
 
-void
+DEBUG_FUNCTION void
 debug_constraints (void)
 {
   dump_constraints (stderr, 0);
@@ -813,7 +815,7 @@ dump_constraint_graph (FILE *file)
   /* 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++)
+  FOR_EACH_VEC_ELT (constraint_t, constraints, i, c)
     if (c)
       dump_constraint_edge (file, c);
 
@@ -823,7 +825,7 @@ dump_constraint_graph (FILE *file)
 
 /* Print out the constraint graph to stderr.  */
 
-void
+DEBUG_FUNCTION void
 debug_constraint_graph (void)
 {
   dump_constraint_graph (stderr);
@@ -938,7 +940,7 @@ constraint_set_union (VEC(constraint_t,heap) **to,
   int i;
   constraint_t c;
 
-  for (i = 0; VEC_iterate (constraint_t, *from, i, c); i++)
+  FOR_EACH_VEC_ELT (constraint_t, *from, i, c)
     {
       if (constraint_vec_find (*to, *c) == NULL)
        {
@@ -1095,7 +1097,7 @@ merge_node_constraints (constraint_graph_t graph, unsigned int to,
   gcc_assert (find (from) == to);
 
   /* Move all complex constraints from src node into to node  */
-  for (i = 0; VEC_iterate (constraint_t, graph->complex[from], i, c); i++)
+  FOR_EACH_VEC_ELT (constraint_t, graph->complex[from], i, c)
     {
       /* In complex constraints for node src, we may have either
         a = *src, and *src = a, or an offseted constraint which are
@@ -1279,7 +1281,7 @@ build_pred_graph (void)
   for (j = 0; j < VEC_length (varinfo_t, varmap); j++)
     graph->indirect_cycles[j] = -1;
 
-  for (i = 0; VEC_iterate (constraint_t, constraints, i, c); i++)
+  FOR_EACH_VEC_ELT (constraint_t, constraints, i, c)
     {
       struct constraint_expr lhs = c->lhs;
       struct constraint_expr rhs = c->rhs;
@@ -1358,7 +1360,7 @@ build_succ_graph (void)
   unsigned i, t;
   constraint_t c;
 
-  for (i = 0; VEC_iterate (constraint_t, constraints, i, c); i++)
+  FOR_EACH_VEC_ELT (constraint_t, constraints, i, c)
     {
       struct constraint_expr lhs;
       struct constraint_expr rhs;
@@ -1706,7 +1708,8 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c,
             the set.  Use ESCAPED as representative instead.  */
          else if (v->id == escaped_id)
            flag |= bitmap_set_bit (sol, escaped_id);
-         else if (add_graph_edge (graph, lhs, t))
+         else if (v->may_have_pointers
+                  && add_graph_edge (graph, lhs, t))
            flag |= bitmap_ior_into (sol, get_varinfo (t)->solution);
 
          /* If the variable is not exactly at the requested offset
@@ -1745,6 +1748,7 @@ do_ds_constraint (constraint_t c, bitmap delta)
   unsigned int j;
   bitmap_iterator bi;
   HOST_WIDE_INT loff = c->lhs.offset;
+  bool escaped_p = false;
 
   /* Our IL does not allow this.  */
   gcc_assert (c->rhs.offset == 0);
@@ -1791,22 +1795,6 @@ do_ds_constraint (constraint_t c, bitmap delta)
       unsigned int t;
       HOST_WIDE_INT fieldoffset = v->offset + loff;
 
-      /* If v is a global variable then this is an escape point.  */
-      if (v->is_global_var)
-       {
-         t = find (escaped_id);
-         if (add_graph_edge (graph, t, rhs)
-             && bitmap_ior_into (get_varinfo (t)->solution, sol)
-             && !TEST_BIT (changed, t))
-           {
-             SET_BIT (changed, t);
-             changed_count++;
-           }
-       }
-
-      if (v->is_special_var)
-       continue;
-
       if (v->is_full_var)
        fieldoffset = v->offset;
       else if (loff != 0)
@@ -1819,6 +1807,25 @@ do_ds_constraint (constraint_t c, bitmap delta)
        {
          if (v->may_have_pointers)
            {
+             /* If v is a global variable then this is an escape point.  */
+             if (v->is_global_var
+                 && !escaped_p)
+               {
+                 t = find (escaped_id);
+                 if (add_graph_edge (graph, t, rhs)
+                     && bitmap_ior_into (get_varinfo (t)->solution, sol)
+                     && !TEST_BIT (changed, t))
+                   {
+                     SET_BIT (changed, t);
+                     changed_count++;
+                   }
+                 /* Enough to let rhs escape once.  */
+                 escaped_p = true;
+               }
+
+             if (v->is_special_var)
+               break;
+
              t = find (v->id);
              if (add_graph_edge (graph, t, rhs)
                  && bitmap_ior_into (get_varinfo (t)->solution, sol)
@@ -2431,7 +2438,7 @@ move_complex_constraints (constraint_graph_t graph)
   int i;
   constraint_t c;
 
-  for (i = 0; VEC_iterate (constraint_t, constraints, i, c); i++)
+  FOR_EACH_VEC_ELT (constraint_t, constraints, i, c)
     {
       if (c)
        {
@@ -2472,7 +2479,7 @@ rewrite_constraints (constraint_graph_t graph,
   for (j = 0; j < graph->size; j++)
     gcc_assert (find (j) == j);
 
-  for (i = 0; VEC_iterate (constraint_t, constraints, i, c); i++)
+  FOR_EACH_VEC_ELT (constraint_t, constraints, i, c)
     {
       struct constraint_expr lhs = c->lhs;
       struct constraint_expr rhs = c->rhs;
@@ -2648,7 +2655,7 @@ solve_graph (constraint_graph_t graph)
              solution_empty = bitmap_empty_p (solution);
 
              /* Process the complex constraints */
-             for (j = 0; VEC_iterate (constraint_t, complex, j, c); j++)
+             FOR_EACH_VEC_ELT (constraint_t, complex, j, c)
                {
                  /* XXX: This is going to unsort the constraints in
                     some cases, which will occasionally add duplicate
@@ -2749,10 +2756,14 @@ lookup_vi_for_tree (tree t)
 static const char *
 alias_get_name (tree decl)
 {
-  const char *res = get_name (decl);
+  const char *res;
   char *temp;
   int num_printed = 0;
 
+  if (DECL_ASSEMBLER_NAME_SET_P (decl))
+    res = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+  else
+    res= get_name (decl);
   if (res != NULL)
     return res;
 
@@ -2827,7 +2838,8 @@ get_constraint_for_ssa_var (tree t, VEC(ce_s, heap) **results, bool address_p)
   /* For parameters, get at the points-to set for the actual parm
      decl.  */
   if (TREE_CODE (t) == SSA_NAME
-      && TREE_CODE (SSA_NAME_VAR (t)) == PARM_DECL
+      && (TREE_CODE (SSA_NAME_VAR (t)) == PARM_DECL
+         || TREE_CODE (SSA_NAME_VAR (t)) == RESULT_DECL)
       && SSA_NAME_IS_DEFAULT_DEF (t))
     {
       get_constraint_for_ssa_var (SSA_NAME_VAR (t), results, address_p);
@@ -2885,6 +2897,16 @@ process_constraint (constraint_t t)
   /* ADDRESSOF on the lhs is invalid.  */
   gcc_assert (lhs.type != ADDRESSOF);
 
+  /* We shouldn't add constraints from things that cannot have pointers.
+     It's not completely trivial to avoid in the callers, so do it here.  */
+  if (rhs.type != ADDRESSOF
+      && !get_varinfo (rhs.var)->may_have_pointers)
+    return;
+
+  /* Likewise adding to the solution of a non-pointer var isn't useful.  */
+  if (!get_varinfo (lhs.var)->may_have_pointers)
+    return;
+
   /* This can happen in our IR with things like n->a = *p */
   if (rhs.type == DEREF && lhs.type == DEREF && rhs.var != anything_id)
     {
@@ -2909,28 +2931,6 @@ process_constraint (constraint_t t)
     }
 }
 
-/* Return true if T is a type that could contain pointers.  */
-
-static bool
-type_could_have_pointers (tree type)
-{
-  if (POINTER_TYPE_P (type))
-    return true;
-
-  if (TREE_CODE (type) == ARRAY_TYPE)
-    return type_could_have_pointers (TREE_TYPE (type));
-
-  return AGGREGATE_TYPE_P (type);
-}
-
-/* Return true if T is a variable of a type that could contain
-   pointers.  */
-
-static bool
-could_have_pointers (tree t)
-{
-  return type_could_have_pointers (TREE_TYPE (t));
-}
 
 /* Return the position, in bits, of FIELD_DECL from the beginning of its
    structure.  */
@@ -2963,7 +2963,7 @@ get_constraint_for_ptr_offset (tree ptr, tree offset,
      does not change the points-to solution.  */
   if (!use_field_sensitive)
     {
-      get_constraint_for (ptr, results);
+      get_constraint_for_rhs (ptr, results);
       return;
     }
 
@@ -2983,7 +2983,7 @@ get_constraint_for_ptr_offset (tree ptr, tree offset,
        rhsoffset = UNKNOWN_OFFSET;
     }
 
-  get_constraint_for (ptr, results);
+  get_constraint_for_rhs (ptr, results);
   if (rhsoffset == 0)
     return;
 
@@ -3061,11 +3061,13 @@ get_constraint_for_ptr_offset (tree ptr, tree offset,
 
 
 /* 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.  */
+   If address_p is true the result will be taken its address of.
+   If lhs_p is true then the constraint expression is assumed to be used
+   as the lhs.  */
 
 static void
 get_constraint_for_component_ref (tree t, VEC(ce_s, heap) **results,
-                                 bool address_p)
+                                 bool address_p, bool lhs_p)
 {
   tree orig_t = t;
   HOST_WIDE_INT bitsize = -1;
@@ -3078,7 +3080,8 @@ get_constraint_for_component_ref (tree t, VEC(ce_s, heap) **results,
      &0->a.b */
   forzero = t;
   while (handled_component_p (forzero)
-        || INDIRECT_REF_P (forzero))
+        || INDIRECT_REF_P (forzero)
+        || TREE_CODE (forzero) == MEM_REF)
     forzero = TREE_OPERAND (forzero, 0);
 
   if (CONSTANT_CLASS_P (forzero) && integer_zerop (forzero))
@@ -3092,11 +3095,34 @@ get_constraint_for_component_ref (tree t, VEC(ce_s, heap) **results,
       return;
     }
 
+  /* Handle type-punning through unions.  If we are extracting a pointer
+     from a union via a possibly type-punning access that pointer
+     points to anything, similar to a conversion of an integer to
+     a pointer.  */
+  if (!lhs_p)
+    {
+      tree u;
+      for (u = t;
+          TREE_CODE (u) == COMPONENT_REF || TREE_CODE (u) == ARRAY_REF;
+          u = TREE_OPERAND (u, 0))
+       if (TREE_CODE (u) == COMPONENT_REF
+           && TREE_CODE (TREE_TYPE (TREE_OPERAND (u, 0))) == UNION_TYPE)
+         {
+           struct constraint_expr temp;
+
+           temp.offset = 0;
+           temp.var = anything_id;
+           temp.type = ADDRESSOF;
+           VEC_safe_push (ce_s, heap, *results, &temp);
+           return;
+         }
+    }
+
   t = get_ref_base_and_extent (t, &bitpos, &bitsize, &bitmaxsize);
 
   /* 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);
+  get_constraint_for_1 (t, results, true, lhs_p);
   gcc_assert (VEC_length (ce_s, *results) == 1);
   result = VEC_last (ce_s, *results);
 
@@ -3145,13 +3171,19 @@ get_constraint_for_component_ref (tree t, VEC(ce_s, heap) **results,
              cexpr.var = curr->id;
              VEC_safe_push (ce_s, heap, *results, &cexpr);
            }
-         else
+         else if (VEC_length (ce_s, *results) == 0)
            /* 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));
+           /* Or accessing only padding via type-punning to a type
+              that has a filed just in padding space.  */
+           {
+             cexpr.type = SCALAR;
+             cexpr.var = anything_id;
+             cexpr.offset = 0;
+             VEC_safe_push (ce_s, heap, *results, &cexpr);
+           }
        }
       else if (bitmaxsize == 0)
        {
@@ -3170,10 +3202,11 @@ get_constraint_for_component_ref (tree t, VEC(ce_s, heap) **results,
         at most one subfiled of any variable.  */
       if (bitpos == -1
          || bitsize != bitmaxsize
-         || AGGREGATE_TYPE_P (TREE_TYPE (orig_t)))
+         || AGGREGATE_TYPE_P (TREE_TYPE (orig_t))
+         || result->offset == UNKNOWN_OFFSET)
        result->offset = UNKNOWN_OFFSET;
       else
-       result->offset = bitpos;
+       result->offset += bitpos;
     }
   else if (result->type == ADDRESSOF)
     {
@@ -3200,7 +3233,7 @@ do_deref (VEC (ce_s, heap) **constraints)
   struct constraint_expr *c;
   unsigned int i = 0;
 
-  for (i = 0; VEC_iterate (ce_s, *constraints, i, c); i++)
+  FOR_EACH_VEC_ELT (ce_s, *constraints, i, c)
     {
       if (c->type == SCALAR)
        c->type = DEREF;
@@ -3218,8 +3251,6 @@ do_deref (VEC (ce_s, heap) **constraints)
     }
 }
 
-static void get_constraint_for_1 (tree, VEC (ce_s, heap) **, bool);
-
 /* Given a tree T, return the constraint expression for taking the
    address of it.  */
 
@@ -3229,9 +3260,9 @@ get_constraint_for_address_of (tree t, VEC (ce_s, heap) **results)
   struct constraint_expr *c;
   unsigned int i;
 
-  get_constraint_for_1 (t, results, true);
+  get_constraint_for_1 (t, results, true, true);
 
-  for (i = 0; VEC_iterate (ce_s, *results, i, c); i++)
+  FOR_EACH_VEC_ELT (ce_s, *results, i, c)
     {
       if (c->type == DEREF)
        c->type = SCALAR;
@@ -3243,7 +3274,8 @@ get_constraint_for_address_of (tree t, VEC (ce_s, heap) **results)
 /* Given a tree T, return the constraint expression for it.  */
 
 static void
-get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p)
+get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p,
+                     bool lhs_p)
 {
   struct constraint_expr temp;
 
@@ -3260,14 +3292,18 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p)
      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))
-         /* The only valid CONSTRUCTORs in gimple with pointer typed
-            elements are zero-initializer.  */
-         || TREE_CODE (t) == CONSTRUCTOR))
-    {
-      temp.var = nothing_id;
+  if ((TREE_CODE (t) == INTEGER_CST
+       && integer_zerop (t))
+      /* The only valid CONSTRUCTORs in gimple with pointer typed
+        elements are zero-initializer.  But in IPA mode we also
+        process global initializers, so verify at least.  */
+      || (TREE_CODE (t) == CONSTRUCTOR
+         && CONSTRUCTOR_NELTS (t) == 0))
+    {
+      if (flag_delete_null_pointer_checks)
+       temp.var = nothing_id;
+      else
+       temp.var = nonlocal_id;
       temp.type = ADDRESSOF;
       temp.offset = 0;
       VEC_safe_push (ce_s, heap, *results, &temp);
@@ -3301,19 +3337,52 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p)
       {
        switch (TREE_CODE (t))
          {
-         case INDIRECT_REF:
+         case MEM_REF:
            {
-             get_constraint_for_1 (TREE_OPERAND (t, 0), results, address_p);
+             struct constraint_expr cs;
+             varinfo_t vi, curr;
+             tree off = double_int_to_tree (sizetype, mem_ref_offset (t));
+             get_constraint_for_ptr_offset (TREE_OPERAND (t, 0), off, results);
              do_deref (results);
+
+             /* If we are not taking the address then make sure to process
+                all subvariables we might access.  */
+             cs = *VEC_last (ce_s, *results);
+             if (address_p
+                 || cs.type != SCALAR)
+               return;
+
+             vi = get_varinfo (cs.var);
+             curr = vi->next;
+             if (!vi->is_full_var
+                 && curr)
+               {
+                 unsigned HOST_WIDE_INT size;
+                 if (host_integerp (TYPE_SIZE (TREE_TYPE (t)), 1))
+                   size = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (t)));
+                 else
+                   size = -1;
+                 for (; curr; curr = curr->next)
+                   {
+                     if (curr->offset - vi->offset < size)
+                       {
+                         cs.var = curr->id;
+                         VEC_safe_push (ce_s, heap, *results, &cs);
+                       }
+                     else
+                       break;
+                   }
+               }
              return;
            }
          case ARRAY_REF:
          case ARRAY_RANGE_REF:
          case COMPONENT_REF:
-           get_constraint_for_component_ref (t, results, address_p);
+           get_constraint_for_component_ref (t, results, address_p, lhs_p);
            return;
          case VIEW_CONVERT_EXPR:
-           get_constraint_for_1 (TREE_OPERAND (t, 0), results, address_p);
+           get_constraint_for_1 (TREE_OPERAND (t, 0), results, address_p,
+                                 lhs_p);
            return;
          /* We are missing handling for TARGET_MEM_REF here.  */
          default:;
@@ -3329,6 +3398,26 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p)
              get_constraint_for_ssa_var (t, results, address_p);
              return;
            }
+         case CONSTRUCTOR:
+           {
+             unsigned int i;
+             tree val;
+             VEC (ce_s, heap) *tmp = NULL;
+             FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (t), i, val)
+               {
+                 struct constraint_expr *rhsp;
+                 unsigned j;
+                 get_constraint_for_1 (val, &tmp, address_p, lhs_p);
+                 FOR_EACH_VEC_ELT (ce_s, tmp, j, rhsp)
+                   VEC_safe_push (ce_s, heap, *results, rhsp);
+                 VEC_truncate (ce_s, tmp, 0);
+               }
+             VEC_free (ce_s, heap, tmp);
+             /* We do not know whether the constructor was complete,
+                so technically we have to add &NOTHING or &ANYTHING
+                like we do for an empty constructor as well.  */
+             return;
+           }
          default:;
          }
        break;
@@ -3338,6 +3427,15 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p)
        get_constraint_for_ssa_var (t, results, address_p);
        return;
       }
+    case tcc_constant:
+      {
+       /* We cannot refer to automatic variables through constants.  */ 
+       temp.type = ADDRESSOF;
+       temp.var = nonlocal_id;
+       temp.offset = 0;
+       VEC_safe_push (ce_s, heap, *results, &temp);
+       return;
+      }
     default:;
     }
 
@@ -3355,7 +3453,18 @@ get_constraint_for (tree t, VEC (ce_s, heap) **results)
 {
   gcc_assert (VEC_length (ce_s, *results) == 0);
 
-  get_constraint_for_1 (t, results, false);
+  get_constraint_for_1 (t, results, false, true);
+}
+
+/* Given a gimple tree T, return the constraint expression vector for it
+   to be used as the rhs of a constraint.  */
+
+static void
+get_constraint_for_rhs (tree t, VEC (ce_s, heap) **results)
+{
+  gcc_assert (VEC_length (ce_s, *results) == 0);
+
+  get_constraint_for_1 (t, results, false, false);
 }
 
 
@@ -3371,17 +3480,17 @@ process_all_all_constraints (VEC (ce_s, heap) *lhsc, VEC (ce_s, heap) *rhsc)
   if (VEC_length (ce_s, lhsc) <= 1
       || VEC_length (ce_s, rhsc) <= 1)
     {
-      for (i = 0; VEC_iterate (ce_s, lhsc, i, lhsp); ++i)
-       for (j = 0; VEC_iterate (ce_s, rhsc, j, rhsp); ++j)
+      FOR_EACH_VEC_ELT (ce_s, lhsc, i, lhsp)
+       FOR_EACH_VEC_ELT (ce_s, rhsc, j, rhsp)
          process_constraint (new_constraint (*lhsp, *rhsp));
     }
   else
     {
       struct constraint_expr tmp;
       tmp = new_scalar_tmp_constraint_exp ("allalltmp");
-      for (i = 0; VEC_iterate (ce_s, rhsc, i, rhsp); ++i)
+      FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
        process_constraint (new_constraint (tmp, *rhsp));
-      for (i = 0; VEC_iterate (ce_s, lhsc, i, lhsp); ++i)
+      FOR_EACH_VEC_ELT (ce_s, lhsc, i, lhsp)
        process_constraint (new_constraint (*lhsp, tmp));
     }
 }
@@ -3397,7 +3506,7 @@ do_structure_copy (tree lhsop, tree rhsop)
   unsigned j;
 
   get_constraint_for (lhsop, &lhsc);
-  get_constraint_for (rhsop, &rhsc);
+  get_constraint_for_rhs (rhsop, &rhsc);
   lhsp = VEC_index (ce_s, lhsc, 0);
   rhsp = VEC_index (ce_s, rhsc, 0);
   if (lhsp->type == DEREF
@@ -3432,11 +3541,15 @@ do_structure_copy (tree lhsop, tree rhsop)
          lhsv = get_varinfo (lhsp->var);
          rhsv = get_varinfo (rhsp->var);
          if (lhsv->may_have_pointers
-             && ranges_overlap_p (lhsv->offset + rhsoffset, lhsv->size,
-                                  rhsv->offset + lhsoffset, rhsv->size))
+             && (lhsv->is_full_var
+                 || rhsv->is_full_var
+                 || ranges_overlap_p (lhsv->offset + rhsoffset, lhsv->size,
+                                      rhsv->offset + lhsoffset, rhsv->size)))
            process_constraint (new_constraint (*lhsp, *rhsp));
-         if (lhsv->offset + rhsoffset + lhsv->size
-             > rhsv->offset + lhsoffset + rhsv->size)
+         if (!rhsv->is_full_var
+             && (lhsv->is_full_var
+                 || (lhsv->offset + rhsoffset + lhsv->size
+                     > rhsv->offset + lhsoffset + rhsv->size)))
            {
              ++k;
              if (k >= VEC_length (ce_s, rhsc))
@@ -3453,12 +3566,11 @@ do_structure_copy (tree lhsop, tree rhsop)
   VEC_free (ce_s, heap, rhsc);
 }
 
-/* Create a constraint ID = OP.  */
+/* Create constraints ID = { rhsc }.  */
 
 static void
-make_constraint_to (unsigned id, tree op)
+make_constraints_to (unsigned id, VEC(ce_s, heap) *rhsc)
 {
-  VEC(ce_s, heap) *rhsc = NULL;
   struct constraint_expr *c;
   struct constraint_expr includes;
   unsigned int j;
@@ -3467,9 +3579,18 @@ make_constraint_to (unsigned id, tree op)
   includes.offset = 0;
   includes.type = SCALAR;
 
-  get_constraint_for (op, &rhsc);
-  for (j = 0; VEC_iterate (ce_s, rhsc, j, c); j++)
+  FOR_EACH_VEC_ELT (ce_s, rhsc, j, c)
     process_constraint (new_constraint (includes, *c));
+}
+
+/* Create a constraint ID = OP.  */
+
+static void
+make_constraint_to (unsigned id, tree op)
+{
+  VEC(ce_s, heap) *rhsc = NULL;
+  get_constraint_for_rhs (op, &rhsc);
+  make_constraints_to (id, rhsc);
   VEC_free (ce_s, heap, rhsc);
 }
 
@@ -3541,11 +3662,11 @@ make_transitive_closure_constraints (varinfo_t vi)
   process_constraint (new_constraint (lhs, rhs));
 }
 
-/* Create a new artificial heap variable with NAME and make a
-   constraint from it to LHS.  Return the created variable.  */
+/* Create a new artificial heap variable with NAME.
+   Return the created variable.  */
 
 static varinfo_t
-make_constraint_from_heapvar (varinfo_t lhs, const char *name)
+make_heapvar_for (varinfo_t lhs, const char *name)
 {
   varinfo_t vi;
   tree heapvar = heapvar_lookup (lhs->decl, lhs->offset);
@@ -3577,6 +3698,16 @@ make_constraint_from_heapvar (varinfo_t lhs, const char *name)
   vi->is_full_var = true;
   insert_vi_for_tree (heapvar, vi);
 
+  return vi;
+}
+
+/* Create a new artificial heap variable with NAME and make a
+   constraint from it to LHS.  Return the created variable.  */
+
+static varinfo_t
+make_constraint_from_heapvar (varinfo_t lhs, const char *name)
+{
+  varinfo_t vi = make_heapvar_for (lhs, name);
   make_constraint_from (lhs, vi->id);
 
   return vi;
@@ -3626,7 +3757,10 @@ get_function_part_constraint (varinfo_t fi, unsigned part)
   else if (TREE_CODE (fi->decl) == FUNCTION_DECL)
     {
       varinfo_t ai = first_vi_for_offset (fi, part);
-      c.var = ai ? ai->id : anything_id;
+      if (ai)
+       c.var = ai->id;
+      else
+       c.var = anything_id;
       c.offset = 0;
       c.type = SCALAR;
     }
@@ -3648,17 +3782,59 @@ handle_rhs_call (gimple stmt, VEC(ce_s, heap) **results)
 {
   struct constraint_expr rhsc;
   unsigned i;
+  bool returns_uses = false;
 
   for (i = 0; i < gimple_call_num_args (stmt); ++i)
     {
       tree arg = gimple_call_arg (stmt, i);
+      int flags = gimple_call_arg_flags (stmt, i);
 
-      /* Find those pointers being passed, and make sure they end up
-        pointing to anything.  */
-      if (could_have_pointers (arg))
+      /* If the argument is not used we can ignore it.  */
+      if (flags & EAF_UNUSED)
+       continue;
+
+      /* As we compute ESCAPED context-insensitive we do not gain
+         any precision with just EAF_NOCLOBBER but not EAF_NOESCAPE
+        set.  The argument would still get clobbered through the
+        escape solution.
+        ???  We might get away with less (and more precise) constraints
+        if using a temporary for transitively closing things.  */
+      if ((flags & EAF_NOCLOBBER)
+          && (flags & EAF_NOESCAPE))
+       {
+         varinfo_t uses = get_call_use_vi (stmt);
+         if (!(flags & EAF_DIRECT))
+           make_transitive_closure_constraints (uses);
+         make_constraint_to (uses->id, arg);
+         returns_uses = true;
+       }
+      else if (flags & EAF_NOESCAPE)
+       {
+         varinfo_t uses = get_call_use_vi (stmt);
+         varinfo_t clobbers = get_call_clobber_vi (stmt);
+         if (!(flags & EAF_DIRECT))
+           {
+             make_transitive_closure_constraints (uses);
+             make_transitive_closure_constraints (clobbers);
+           }
+         make_constraint_to (uses->id, arg);
+         make_constraint_to (clobbers->id, arg);
+         returns_uses = true;
+       }
+      else
        make_escape_constraint (arg);
     }
 
+  /* If we added to the calls uses solution make sure we account for
+     pointers to it to be returned.  */
+  if (returns_uses)
+    {
+      rhsc.var = get_call_use_vi (stmt)->id;
+      rhsc.offset = 0;
+      rhsc.type = SCALAR;
+      VEC_safe_push (ce_s, heap, *results, &rhsc);
+    }
+
   /* The static chain escapes as well.  */
   if (gimple_call_chain (stmt))
     make_escape_constraint (gimple_call_chain (stmt));
@@ -3674,7 +3850,7 @@ handle_rhs_call (gimple stmt, VEC(ce_s, heap) **results)
       lhsc.var = escaped_id;
       lhsc.offset = 0;
       lhsc.type = SCALAR;
-      for (i = 0; VEC_iterate (ce_s, tmpc, i, c); ++i)
+      FOR_EACH_VEC_ELT (ce_s, tmpc, i, c)
        process_constraint (new_constraint (lhsc, *c));
       VEC_free(ce_s, heap, tmpc);
     }
@@ -3691,44 +3867,63 @@ handle_rhs_call (gimple stmt, VEC(ce_s, heap) **results)
    the LHS point to global and escaped variables.  */
 
 static void
-handle_lhs_call (tree lhs, int flags, VEC(ce_s, heap) *rhsc, tree fndecl)
+handle_lhs_call (gimple stmt, tree lhs, int flags, VEC(ce_s, heap) *rhsc,
+                tree fndecl)
 {
   VEC(ce_s, heap) *lhsc = NULL;
 
   get_constraint_for (lhs, &lhsc);
-
-  if (flags & ECF_MALLOC)
+  /* If the store is to a global decl make sure to
+     add proper escape constraints.  */
+  lhs = get_base_address (lhs);
+  if (lhs
+      && DECL_P (lhs)
+      && is_global_var (lhs))
+    {
+      struct constraint_expr tmpc;
+      tmpc.var = escaped_id;
+      tmpc.offset = 0;
+      tmpc.type = SCALAR;
+      VEC_safe_push (ce_s, heap, lhsc, &tmpc);
+    }
+
+  /* If the call returns an argument unmodified override the rhs
+     constraints.  */
+  flags = gimple_call_return_flags (stmt);
+  if (flags & ERF_RETURNS_ARG
+      && (flags & ERF_RETURN_ARG_MASK) < gimple_call_num_args (stmt))
+    {
+      tree arg;
+      rhsc = NULL;
+      arg = gimple_call_arg (stmt, flags & ERF_RETURN_ARG_MASK);
+      get_constraint_for (arg, &rhsc);
+      process_all_all_constraints (lhsc, rhsc);
+      VEC_free (ce_s, heap, rhsc);
+    }
+  else if (flags & ERF_NOALIAS)
     {
       varinfo_t vi;
-      vi = make_constraint_from_heapvar (get_vi_for_tree (lhs), "HEAP");
+      struct constraint_expr tmpc;
+      rhsc = NULL;
+      vi = make_heapvar_for (get_vi_for_tree (lhs), "HEAP");
       /* We delay marking allocated storage global until we know if
          it escapes.  */
       DECL_EXTERNAL (vi->decl) = 0;
       vi->is_global_var = 0;
       /* If this is not a real malloc call assume the memory was
-         initialized and thus may point to global memory.  All
+        initialized and thus may point to global memory.  All
         builtin functions with the malloc attribute behave in a sane way.  */
       if (!fndecl
          || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
        make_constraint_from (vi, nonlocal_id);
+      tmpc.var = vi->id;
+      tmpc.offset = 0;
+      tmpc.type = ADDRESSOF;
+      VEC_safe_push (ce_s, heap, rhsc, &tmpc);
     }
-  else if (VEC_length (ce_s, rhsc) > 0)
-    {
-      /* If the store is to a global decl make sure to
-        add proper escape constraints.  */
-      lhs = get_base_address (lhs);
-      if (lhs
-         && DECL_P (lhs)
-         && is_global_var (lhs))
-       {
-         struct constraint_expr tmpc;
-         tmpc.var = escaped_id;
-         tmpc.offset = 0;
-         tmpc.type = SCALAR;
-         VEC_safe_push (ce_s, heap, lhsc, &tmpc);
-       }
-      process_all_all_constraints (lhsc, rhsc);
-    }
+
+  process_all_all_constraints (lhsc, rhsc);
+
   VEC_free (ce_s, heap, lhsc);
 }
 
@@ -3758,17 +3953,13 @@ handle_const_call (gimple stmt, VEC(ce_s, heap) **results)
   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;
-         unsigned i;
-         struct constraint_expr *argp;
-         get_constraint_for (arg, &argc);
-         for (i = 0; VEC_iterate (ce_s, argc, i, argp); ++i)
-           VEC_safe_push (ce_s, heap, *results, argp);
-         VEC_free(ce_s, heap, argc);
-       }
+      VEC(ce_s, heap) *argc = NULL;
+      unsigned i;
+      struct constraint_expr *argp;
+      get_constraint_for_rhs (arg, &argc);
+      FOR_EACH_VEC_ELT (ce_s, argc, i, argp)
+       VEC_safe_push (ce_s, heap, *results, argp);
+      VEC_free(ce_s, heap, argc);
     }
 
   /* May return addresses of globals.  */
@@ -3792,16 +3983,12 @@ handle_pure_call (gimple stmt, VEC(ce_s, heap) **results)
   for (i = 0; i < gimple_call_num_args (stmt); ++i)
     {
       tree arg = gimple_call_arg (stmt, i);
-
-      if (could_have_pointers (arg))
+      if (!uses)
        {
-         if (!uses)
-           {
-             uses = get_call_use_vi (stmt);
-             make_transitive_closure_constraints (uses);
-           }
-         make_constraint_to (uses->id, arg);
+         uses = get_call_use_vi (stmt);
+         make_transitive_closure_constraints (uses);
        }
+      make_constraint_to (uses->id, arg);
     }
 
   /* The static chain is used as well.  */
@@ -3851,7 +4038,8 @@ get_fi_for_callee (gimple call)
   if (TREE_CODE (decl) == SSA_NAME)
     {
       if (TREE_CODE (decl) == SSA_NAME
-         && TREE_CODE (SSA_NAME_VAR (decl)) == PARM_DECL
+         && (TREE_CODE (SSA_NAME_VAR (decl)) == PARM_DECL
+             || TREE_CODE (SSA_NAME_VAR (decl)) == RESULT_DECL)
          && SSA_NAME_IS_DEFAULT_DEF (decl))
        decl = SSA_NAME_VAR (decl);
       return get_vi_for_tree (decl);
@@ -3880,34 +4068,27 @@ find_func_aliases (gimple origt)
   /* Now build constraints expressions.  */
   if (gimple_code (t) == GIMPLE_PHI)
     {
-      gcc_assert (!AGGREGATE_TYPE_P (TREE_TYPE (gimple_phi_result (t))));
+      size_t i;
+      unsigned int j;
 
-      /* Only care about pointers and structures containing
-        pointers.  */
-      if (could_have_pointers (gimple_phi_result (t)))
+      /* For a phi node, assign all the arguments to
+        the result.  */
+      get_constraint_for (gimple_phi_result (t), &lhsc);
+      for (i = 0; i < gimple_phi_num_args (t); i++)
        {
-         size_t i;
-         unsigned int j;
+         tree strippedrhs = PHI_ARG_DEF (t, i);
 
-         /* For a phi node, assign all the arguments to
-            the result.  */
-         get_constraint_for (gimple_phi_result (t), &lhsc);
-         for (i = 0; i < gimple_phi_num_args (t); i++)
-           {
-             tree strippedrhs = PHI_ARG_DEF (t, i);
-
-             STRIP_NOPS (strippedrhs);
-             get_constraint_for (gimple_phi_arg_def (t, i), &rhsc);
+         STRIP_NOPS (strippedrhs);
+         get_constraint_for_rhs (gimple_phi_arg_def (t, i), &rhsc);
 
-             for (j = 0; VEC_iterate (ce_s, lhsc, j, c); j++)
+         FOR_EACH_VEC_ELT (ce_s, lhsc, j, c)
+           {
+             struct constraint_expr *c2;
+             while (VEC_length (ce_s, rhsc) > 0)
                {
-                 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);
-                   }
+                 c2 = VEC_last (ce_s, rhsc);
+                 process_constraint (new_constraint (*c, *c2));
+                 VEC_pop (ce_s, rhsc);
                }
            }
        }
@@ -4000,7 +4181,7 @@ find_func_aliases (gimple origt)
                  ac.var = integer_id;
                }
              ac.offset = 0;
-             for (i = 0; VEC_iterate (ce_s, lhsc, i, lhsp); ++i)
+             FOR_EACH_VEC_ELT (ce_s, lhsc, i, lhsp)
                process_constraint (new_constraint (*lhsp, ac));
              VEC_free (ce_s, heap, lhsc);
              return;
@@ -4046,7 +4227,7 @@ find_func_aliases (gimple origt)
                    {
                      lhs = get_function_part_constraint (nfi, fi_static_chain);
                      get_constraint_for (frame, &rhsc);
-                     for (i = 0; VEC_iterate (ce_s, rhsc, i, rhsp); ++i)
+                     FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
                        process_constraint (new_constraint (lhs, *rhsp));
                      VEC_free (ce_s, heap, rhsc);
 
@@ -4098,7 +4279,7 @@ find_func_aliases (gimple origt)
                  do_deref (&lhsc);
                  rhs = get_function_part_constraint (fi, ~0);
                  rhs.type = ADDRESSOF;
-                 for (i = 0; VEC_iterate (ce_s, lhsc, i, lhsp); ++i)
+                 FOR_EACH_VEC_ELT (ce_s, lhsc, i, lhsp)
                    process_constraint (new_constraint (*lhsp, rhs));
                  VEC_free (ce_s, heap, lhsc);
                  /* va_list is clobbered.  */
@@ -4110,6 +4291,25 @@ find_func_aliases (gimple origt)
          /* va_end doesn't have any effect that matters.  */
          case BUILT_IN_VA_END:
            return;
+         /* Alternate return.  Simply give up for now.  */
+         case BUILT_IN_RETURN:
+           {
+             fi = NULL;
+             if (!in_ipa_mode
+                 || !(fi = get_vi_for_tree (cfun->decl)))
+               make_constraint_from (get_varinfo (escaped_id), anything_id);
+             else if (in_ipa_mode
+                      && fi != NULL)
+               {
+                 struct constraint_expr lhs, rhs;
+                 lhs = get_function_part_constraint (fi, fi_result);
+                 rhs.var = anything_id;
+                 rhs.offset = 0;
+                 rhs.type = SCALAR;
+                 process_constraint (new_constraint (lhs, rhs));
+               }
+             return;
+           }
          /* printf-style functions may have hooks to set pointers to
             point to somewhere into the generated string.  Leave them
             for a later excercise...  */
@@ -4128,8 +4328,7 @@ find_func_aliases (gimple origt)
             of global memory but not of escaped memory.  */
          if (flags & (ECF_CONST|ECF_NOVOPS))
            {
-             if (gimple_call_lhs (t)
-                 && could_have_pointers (gimple_call_lhs (t)))
+             if (gimple_call_lhs (t))
                handle_const_call (t, &rhsc);
            }
          /* Pure functions can return addresses in and of memory
@@ -4139,9 +4338,8 @@ find_func_aliases (gimple origt)
            handle_pure_call (t, &rhsc);
          else
            handle_rhs_call (t, &rhsc);
-         if (gimple_call_lhs (t)
-             && could_have_pointers (gimple_call_lhs (t)))
-           handle_lhs_call (gimple_call_lhs (t), flags, rhsc, fndecl);
+         if (gimple_call_lhs (t))
+           handle_lhs_call (t, gimple_call_lhs (t), flags, rhsc, fndecl);
          VEC_free (ce_s, heap, rhsc);
        }
       else
@@ -4159,10 +4357,7 @@ find_func_aliases (gimple origt)
              struct constraint_expr *rhsp;
              tree arg = gimple_call_arg (t, j);
 
-             if (!could_have_pointers (arg))
-               continue;
-
-             get_constraint_for (arg, &rhsc);
+             get_constraint_for_rhs (arg, &rhsc);
              lhs = get_function_part_constraint (fi, fi_parm_base + j);
              while (VEC_length (ce_s, rhsc) != 0)
                {
@@ -4174,8 +4369,7 @@ find_func_aliases (gimple origt)
 
          /* If we are returning a value, assign it to the result.  */
          lhsop = gimple_call_lhs (t);
-         if (lhsop
-             && could_have_pointers (lhsop))
+         if (lhsop)
            {
              struct constraint_expr rhs;
              struct constraint_expr *lhsp;
@@ -4192,7 +4386,7 @@ find_func_aliases (gimple origt)
                  rhs = *VEC_index (ce_s, tem, 0);
                  VEC_free(ce_s, heap, tem);
                }
-             for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
+             FOR_EACH_VEC_ELT (ce_s, lhsc, j, lhsp)
                process_constraint (new_constraint (*lhsp, rhs));
            }
 
@@ -4207,7 +4401,7 @@ find_func_aliases (gimple origt)
 
              get_constraint_for_address_of (lhsop, &rhsc);
              lhs = get_function_part_constraint (fi, fi_result);
-             for (j = 0; VEC_iterate (ce_s, rhsc, j, rhsp); j++)
+             FOR_EACH_VEC_ELT (ce_s, rhsc, j, rhsp)
                process_constraint (new_constraint (lhs, *rhsp));
              VEC_free (ce_s, heap, rhsc);
            }
@@ -4220,7 +4414,7 @@ find_func_aliases (gimple origt)
 
              get_constraint_for (gimple_call_chain (t), &rhsc);
              lhs = get_function_part_constraint (fi, fi_static_chain);
-             for (j = 0; VEC_iterate (ce_s, rhsc, j, rhsp); j++)
+             FOR_EACH_VEC_ELT (ce_s, rhsc, j, rhsp)
                process_constraint (new_constraint (lhs, *rhsp));
            }
        }
@@ -4228,8 +4422,7 @@ find_func_aliases (gimple origt)
   /* 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)))
+  else if (is_gimple_assign (t))
     {
       /* Otherwise, just a regular assignment statement.  */
       tree lhsop = gimple_assign_lhs (t);
@@ -4239,23 +4432,39 @@ find_func_aliases (gimple origt)
        do_structure_copy (lhsop, rhsop);
       else
        {
-         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 (gimple_assign_rhs_code (t) == BIT_AND_EXPR
+                  && TREE_CODE (gimple_assign_rhs2 (t)) == INTEGER_CST)
+           {
+             /* Aligning a pointer via a BIT_AND_EXPR is offsetting
+                the pointer.  Handle it by offsetting it by UNKNOWN.  */
+             get_constraint_for_ptr_offset (gimple_assign_rhs1 (t),
+                                            NULL_TREE, &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);
+           get_constraint_for_rhs (rhsop, &rhsc);
          else
            {
-             temp.type = ADDRESSOF;
-             temp.var = anything_id;
-             temp.offset = 0;
-             VEC_safe_push (ce_s, heap, rhsc, &temp);
+             /* All other operations are merges.  */
+             VEC (ce_s, heap) *tmp = NULL;
+             struct constraint_expr *rhsp;
+             unsigned i, j;
+             get_constraint_for_rhs (gimple_assign_rhs1 (t), &rhsc);
+             for (i = 2; i < gimple_num_ops (t); ++i)
+               {
+                 get_constraint_for_rhs (gimple_op (t, i), &tmp);
+                 FOR_EACH_VEC_ELT (ce_s, tmp, j, rhsp)
+                   VEC_safe_push (ce_s, heap, rhsc, rhsp);
+                 VEC_truncate (ce_s, tmp, 0);
+               }
+             VEC_free (ce_s, heap, tmp);
            }
          process_all_all_constraints (lhsc, rhsc);
        }
@@ -4276,17 +4485,9 @@ find_func_aliases (gimple origt)
        make_constraint_from_restrict (get_vi_for_tree (lhsop),
                                       "CAST_RESTRICT");
     }
-  /* For conversions of pointers to non-pointers the pointer escapes.  */
-  else if (gimple_assign_cast_p (t)
-          && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (t)))
-          && !POINTER_TYPE_P (TREE_TYPE (gimple_assign_lhs (t))))
-    {
-      make_escape_constraint (gimple_assign_rhs1 (t));
-    }
   /* Handle escapes through return.  */
   else if (gimple_code (t) == GIMPLE_RETURN
-          && gimple_return_retval (t) != NULL_TREE
-          && could_have_pointers (gimple_return_retval (t)))
+          && gimple_return_retval (t) != NULL_TREE)
     {
       fi = NULL;
       if (!in_ipa_mode
@@ -4300,8 +4501,8 @@ find_func_aliases (gimple origt)
          unsigned i;
 
          lhs = get_function_part_constraint (fi, fi_result);
-         get_constraint_for (gimple_return_retval (t), &rhsc);
-         for (i = 0; VEC_iterate (ce_s, rhsc, i, rhsp); i++)
+         get_constraint_for_rhs (gimple_return_retval (t), &rhsc);
+         FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
            process_constraint (new_constraint (lhs, *rhsp));
        }
     }
@@ -4332,7 +4533,7 @@ find_func_aliases (gimple origt)
 
          /* The asm may read global memory, so outputs may point to
             any global memory.  */
-         if (op && could_have_pointers (op))
+         if (op)
            {
              VEC(ce_s, heap) *lhsc = NULL;
              struct constraint_expr rhsc, *lhsp;
@@ -4341,7 +4542,7 @@ find_func_aliases (gimple origt)
              rhsc.var = nonlocal_id;
              rhsc.offset = 0;
              rhsc.type = SCALAR;
-             for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
+             FOR_EACH_VEC_ELT (ce_s, lhsc, j, lhsp)
                process_constraint (new_constraint (*lhsp, rhsc));
              VEC_free (ce_s, heap, lhsc);
            }
@@ -4362,7 +4563,7 @@ find_func_aliases (gimple origt)
          /* Strictly we'd only need the constraint to ESCAPED if
             the asm clobbers memory, otherwise using something
             along the lines of per-call clobbers/uses would be enough.  */
-         else if (op && could_have_pointers (op))
+         else if (op)
            make_escape_constraint (op);
        }
     }
@@ -4381,9 +4582,9 @@ process_ipa_clobber (varinfo_t fi, tree ptr)
   VEC(ce_s, heap) *ptrc = NULL;
   struct constraint_expr *c, lhs;
   unsigned i;
-  get_constraint_for (ptr, &ptrc);
+  get_constraint_for_rhs (ptr, &ptrc);
   lhs = get_function_part_constraint (fi, fi_clobbers);
-  for (i = 0; VEC_iterate (ce_s, ptrc, i, c); i++)
+  FOR_EACH_VEC_ELT (ce_s, ptrc, i, c)
     process_constraint (new_constraint (lhs, *c));
   VEC_free (ce_s, heap, ptrc);
 }
@@ -4424,13 +4625,17 @@ find_func_clobbers (gimple origt)
        tem = TREE_OPERAND (tem, 0);
       if ((DECL_P (tem)
           && !auto_var_in_fn_p (tem, cfun->decl))
-         || INDIRECT_REF_P (tem))
+         || INDIRECT_REF_P (tem)
+         || (TREE_CODE (tem) == MEM_REF
+             && !(TREE_CODE (TREE_OPERAND (tem, 0)) == ADDR_EXPR
+                  && auto_var_in_fn_p
+                       (TREE_OPERAND (TREE_OPERAND (tem, 0), 0), cfun->decl))))
        {
          struct constraint_expr lhsc, *rhsp;
          unsigned i;
          lhsc = get_function_part_constraint (fi, fi_clobbers);
          get_constraint_for_address_of (lhs, &rhsc);
-         for (i = 0; VEC_iterate (ce_s, rhsc, i, rhsp); i++)
+         FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
            process_constraint (new_constraint (lhsc, *rhsp));
          VEC_free (ce_s, heap, rhsc);
        }
@@ -4448,13 +4653,17 @@ find_func_clobbers (gimple origt)
        tem = TREE_OPERAND (tem, 0);
       if ((DECL_P (tem)
           && !auto_var_in_fn_p (tem, cfun->decl))
-         || INDIRECT_REF_P (tem))
+         || INDIRECT_REF_P (tem)
+         || (TREE_CODE (tem) == MEM_REF
+             && !(TREE_CODE (TREE_OPERAND (tem, 0)) == ADDR_EXPR
+                  && auto_var_in_fn_p
+                       (TREE_OPERAND (TREE_OPERAND (tem, 0), 0), cfun->decl))))
        {
          struct constraint_expr lhs, *rhsp;
          unsigned i;
          lhs = get_function_part_constraint (fi, fi_uses);
          get_constraint_for_address_of (rhs, &rhsc);
-         for (i = 0; VEC_iterate (ce_s, rhsc, i, rhsp); i++)
+         FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
            process_constraint (new_constraint (lhs, *rhsp));
          VEC_free (ce_s, heap, rhsc);
        }
@@ -4494,12 +4703,12 @@ find_func_clobbers (gimple origt)
              struct constraint_expr *rhsp, *lhsp;
              get_constraint_for_ptr_offset (dest, NULL_TREE, &lhsc);
              lhs = get_function_part_constraint (fi, fi_clobbers);
-             for (i = 0; VEC_iterate (ce_s, lhsc, i, lhsp); i++)
+             FOR_EACH_VEC_ELT (ce_s, lhsc, i, lhsp)
                process_constraint (new_constraint (lhs, *lhsp));
              VEC_free (ce_s, heap, lhsc);
              get_constraint_for_ptr_offset (src, NULL_TREE, &rhsc);
              lhs = get_function_part_constraint (fi, fi_uses);
-             for (i = 0; VEC_iterate (ce_s, rhsc, i, rhsp); i++)
+             FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
                process_constraint (new_constraint (lhs, *rhsp));
              VEC_free (ce_s, heap, rhsc);
              return;
@@ -4513,7 +4722,7 @@ find_func_clobbers (gimple origt)
              ce_s *lhsp;
              get_constraint_for_ptr_offset (dest, NULL_TREE, &lhsc);
              lhs = get_function_part_constraint (fi, fi_clobbers);
-             for (i = 0; VEC_iterate (ce_s, lhsc, i, lhsp); i++)
+             FOR_EACH_VEC_ELT (ce_s, lhsc, i, lhsp)
                process_constraint (new_constraint (lhs, *lhsp));
              VEC_free (ce_s, heap, lhsc);
              return;
@@ -4582,7 +4791,7 @@ find_func_clobbers (gimple origt)
            continue;
 
          get_constraint_for_address_of (arg, &rhsc);
-         for (j = 0; VEC_iterate (ce_s, rhsc, j, rhsp); j++)
+         FOR_EACH_VEC_ELT (ce_s, rhsc, j, rhsp)
            process_constraint (new_constraint (lhs, *rhsp));
          VEC_free (ce_s, heap, rhsc);
        }
@@ -4708,19 +4917,6 @@ first_or_preceding_vi_for_offset (varinfo_t start,
 }
 
 
-/* Insert the varinfo FIELD into the field list for BASE, at the front
-   of the list.  */
-
-static void
-insert_into_field_list (varinfo_t base, varinfo_t field)
-{
-  varinfo_t prev = base;
-  varinfo_t curr = base->next;
-
-  field->next = curr;
-  prev->next = field;
-}
-
 /* This structure is used during pushing fields onto the fieldstack
    to track the offset of the field, since bitpos_of_field gives it
    relative to its immediate containing type, and we want it relative
@@ -4736,6 +4932,8 @@ struct fieldoff
 
   unsigned has_unknown_size : 1;
 
+  unsigned must_have_pointers : 1;
+
   unsigned may_have_pointers : 1;
 
   unsigned only_restrict_pointers : 1;
@@ -4772,10 +4970,7 @@ fieldoff_compare (const void *pa, const void *pb)
 static void
 sort_fieldstack (VEC(fieldoff_s,heap) *fieldstack)
 {
-  qsort (VEC_address (fieldoff_s, fieldstack),
-        VEC_length (fieldoff_s, fieldstack),
-        sizeof (fieldoff_s),
-        fieldoff_compare);
+  VEC_qsort (fieldoff_s, fieldstack, fieldoff_compare);
 }
 
 /* Return true if V is a tree that we can have subvars for.
@@ -4800,43 +4995,69 @@ var_can_have_subvars (const_tree v)
   return false;
 }
 
+/* Return true if T is a type that does contain pointers.  */
+
+static bool
+type_must_have_pointers (tree type)
+{
+  if (POINTER_TYPE_P (type))
+    return true;
+
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    return type_must_have_pointers (TREE_TYPE (type));
+
+  /* A function or method can have pointers as arguments, so track
+     those separately.  */
+  if (TREE_CODE (type) == FUNCTION_TYPE
+      || TREE_CODE (type) == METHOD_TYPE)
+    return true;
+
+  return false;
+}
+
+static bool
+field_must_have_pointers (tree t)
+{
+  return type_must_have_pointers (TREE_TYPE (t));
+}
+
 /* Given a TYPE, and a vector of field offsets FIELDSTACK, push all
    the fields of TYPE onto fieldstack, recording their offsets along
    the way.
 
    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.  */
+   Returns false if the caller is supposed to handle the field we
+   recursed for.  */
 
-static int
+static bool
 push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
                             HOST_WIDE_INT offset)
 {
   tree field;
-  int count = 0;
+  bool empty_p = true;
 
   if (TREE_CODE (type) != RECORD_TYPE)
-    return 0;
+    return false;
 
   /* If the vector of fields is growing too big, bail out early.
      Callers check for VEC_length <= MAX_FIELDS_FOR_FIELD_SENSITIVE, make
      sure this fails.  */
   if (VEC_length (fieldoff_s, *fieldstack) > MAX_FIELDS_FOR_FIELD_SENSITIVE)
-    return 0;
+    return false;
 
-  for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+  for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
     if (TREE_CODE (field) == FIELD_DECL)
       {
        bool push = false;
-       int pushed = 0;
        HOST_WIDE_INT foff = bitpos_of_field (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 + foff))
+       else if (!push_fields_onto_fieldstack
+                   (TREE_TYPE (field), fieldstack, offset + foff)
                 && (DECL_SIZE (field)
                     && !integer_zerop (DECL_SIZE (field))))
          /* Empty structures may have actual size, like in C++.  So
@@ -4848,6 +5069,7 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
          {
            fieldoff_s *pair = NULL;
            bool has_unknown_size = false;
+           bool must_have_pointers_p;
 
            if (!VEC_empty (fieldoff_s, *fieldstack))
              pair = VEC_last (fieldoff_s, *fieldstack);
@@ -4857,14 +5079,14 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
              has_unknown_size = true;
 
            /* If adjacent fields do not contain pointers merge them.  */
+           must_have_pointers_p = field_must_have_pointers (field);
            if (pair
-               && !pair->may_have_pointers
-               && !could_have_pointers (field)
-               && !pair->has_unknown_size
                && !has_unknown_size
+               && !must_have_pointers_p
+               && !pair->must_have_pointers
+               && !pair->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
@@ -4876,19 +5098,19 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
                  pair->size = TREE_INT_CST_LOW (DECL_SIZE (field));
                else
                  pair->size = -1;
-               pair->may_have_pointers = could_have_pointers (field);
+               pair->must_have_pointers = must_have_pointers_p;
+               pair->may_have_pointers = true;
                pair->only_restrict_pointers
                  = (!has_unknown_size
                     && POINTER_TYPE_P (TREE_TYPE (field))
                     && TYPE_RESTRICT (TREE_TYPE (field)));
-               count++;
              }
          }
-       else
-         count += pushed;
+
+       empty_p = false;
       }
 
-  return count;
+  return !empty_p;
 }
 
 /* Count the number of arguments DECL has, and set IS_VARARGS to true
@@ -4902,7 +5124,7 @@ count_num_arguments (tree decl, bool *is_varargs)
 
   /* Capture named arguments for K&R functions.  They do not
      have a prototype and thus no TYPE_ARG_TYPES.  */
-  for (t = DECL_ARGUMENTS (decl); t; t = TREE_CHAIN (t))
+  for (t = DECL_ARGUMENTS (decl); t; t = DECL_CHAIN (t))
     ++num;
 
   /* Check if the function has variadic arguments.  */
@@ -4918,7 +5140,7 @@ count_num_arguments (tree decl, bool *is_varargs)
 /* Creation function node for DECL, using NAME, and return the index
    of the variable we've created for the function.  */
 
-static unsigned int
+static varinfo_t
 create_function_info_for (tree decl, const char *name)
 {
   struct function *fn = DECL_STRUCT_FUNCTION (decl);
@@ -4940,8 +5162,6 @@ create_function_info_for (tree decl, const char *name)
     vi->fullsize = ~0;
   insert_vi_for_tree (vi->decl, vi);
 
-  stats.total_vars++;
-
   prev_vi = vi;
 
   /* Create a variable for things the function clobbers and one for
@@ -4964,7 +5184,6 @@ create_function_info_for (tree decl, const char *name)
       gcc_assert (prev_vi->offset < clobbervi->offset);
       prev_vi->next = clobbervi;
       prev_vi = clobbervi;
-      stats.total_vars++;
 
       asprintf (&tempname, "%s.use", name);
       newname = ggc_strdup (tempname);
@@ -4979,7 +5198,6 @@ create_function_info_for (tree decl, const char *name)
       gcc_assert (prev_vi->offset < usevi->offset);
       prev_vi->next = usevi;
       prev_vi = usevi;
-      stats.total_vars++;
     }
 
   /* And one for the static chain.  */
@@ -5002,7 +5220,6 @@ create_function_info_for (tree decl, const char *name)
       gcc_assert (prev_vi->offset < chainvi->offset);
       prev_vi->next = chainvi;
       prev_vi = chainvi;
-      stats.total_vars++;
       insert_vi_for_tree (fn->static_chain_decl, chainvi);
     }
 
@@ -5028,11 +5245,10 @@ create_function_info_for (tree decl, const char *name)
       resultvi->fullsize = vi->fullsize;
       resultvi->is_full_var = true;
       if (DECL_RESULT (decl))
-       resultvi->may_have_pointers = could_have_pointers (DECL_RESULT (decl));
+       resultvi->may_have_pointers = true;
       gcc_assert (prev_vi->offset < resultvi->offset);
       prev_vi->next = resultvi;
       prev_vi = resultvi;
-      stats.total_vars++;
       if (DECL_RESULT (decl))
        insert_vi_for_tree (DECL_RESULT (decl), resultvi);
     }
@@ -5059,15 +5275,14 @@ create_function_info_for (tree decl, const char *name)
       argvi->is_full_var = true;
       argvi->fullsize = vi->fullsize;
       if (arg)
-       argvi->may_have_pointers = could_have_pointers (arg);
+       argvi->may_have_pointers = true;
       gcc_assert (prev_vi->offset < argvi->offset);
       prev_vi->next = argvi;
       prev_vi = argvi;
-      stats.total_vars++;
       if (arg)
        {
          insert_vi_for_tree (arg, argvi);
-         arg = TREE_CHAIN (arg);
+         arg = DECL_CHAIN (arg);
        }
     }
 
@@ -5096,10 +5311,9 @@ create_function_info_for (tree decl, const char *name)
       gcc_assert (prev_vi->offset < argvi->offset);
       prev_vi->next = argvi;
       prev_vi = argvi;
-      stats.total_vars++;
     }
 
-  return vi->id;
+  return vi;
 }
 
 
@@ -5113,7 +5327,7 @@ check_for_overlaps (VEC (fieldoff_s,heap) *fieldstack)
   unsigned int i;
   HOST_WIDE_INT lastoffset = -1;
 
-  for (i = 0; VEC_iterate (fieldoff_s, fieldstack, i, fo); i++)
+  FOR_EACH_VEC_ELT (fieldoff_s, fieldstack, i, fo)
     {
       if (fo->offset == lastoffset)
        return true;
@@ -5126,48 +5340,135 @@ check_for_overlaps (VEC (fieldoff_s,heap) *fieldstack)
    This will also create any varinfo structures necessary for fields
    of DECL.  */
 
-static unsigned int
-create_variable_info_for (tree decl, const char *name)
+static varinfo_t
+create_variable_info_for_1 (tree decl, const char *name)
 {
-  varinfo_t vi;
+  varinfo_t vi, newvi;
   tree decl_type = TREE_TYPE (decl);
   tree declsize = DECL_P (decl) ? DECL_SIZE (decl) : TYPE_SIZE (decl_type);
   VEC (fieldoff_s,heap) *fieldstack = NULL;
+  fieldoff_s *fo;
+  unsigned int i;
 
-  if (var_can_have_subvars (decl) && use_field_sensitive)
-    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
-     fields.  */
-  vi = new_var_info (decl, name);
-  vi->offset = 0;
-  vi->may_have_pointers = could_have_pointers (decl);
   if (!declsize
       || !host_integerp (declsize, 1))
     {
-      vi->is_unknown_size_var = true;
-      vi->fullsize = ~0;
+      vi = new_var_info (decl, name);
+      vi->offset = 0;
       vi->size = ~0;
+      vi->fullsize = ~0;
+      vi->is_unknown_size_var = true;
+      vi->is_full_var = true;
+      vi->may_have_pointers = true;
+      return vi;
     }
-  else
+
+  /* Collect field information.  */
+  if (use_field_sensitive
+      && var_can_have_subvars (decl)
+      /* ???  Force us to not use subfields for global initializers
+        in IPA mode.  Else we'd have to parse arbitrary initializers.  */
+      && !(in_ipa_mode
+          && is_global_var (decl)
+          && DECL_INITIAL (decl)))
+    {
+      fieldoff_s *fo = NULL;
+      bool notokay = false;
+      unsigned int i;
+
+      push_fields_onto_fieldstack (decl_type, &fieldstack, 0);
+
+      for (i = 0; !notokay && VEC_iterate (fieldoff_s, fieldstack, i, fo); i++)
+       if (fo->has_unknown_size
+           || fo->offset < 0)
+         {
+           notokay = true;
+           break;
+         }
+
+      /* We can't sort them if we have a field with a variable sized type,
+        which will make notokay = true.  In that case, we are going to return
+        without creating varinfos for the fields anyway, so sorting them is a
+        waste to boot.  */
+      if (!notokay)
+       {
+         sort_fieldstack (fieldstack);
+         /* Due to some C++ FE issues, like PR 22488, we might end up
+            what appear to be overlapping fields even though they,
+            in reality, do not overlap.  Until the C++ FE is fixed,
+            we will simply disable field-sensitivity for these cases.  */
+         notokay = check_for_overlaps (fieldstack);
+       }
+
+      if (notokay)
+       VEC_free (fieldoff_s, heap, fieldstack);
+    }
+
+  /* If we didn't end up collecting sub-variables create a full
+     variable for the decl.  */
+  if (VEC_length (fieldoff_s, fieldstack) <= 1
+      || VEC_length (fieldoff_s, fieldstack) > MAX_FIELDS_FOR_FIELD_SENSITIVE)
     {
+      vi = new_var_info (decl, name);
+      vi->offset = 0;
+      vi->may_have_pointers = true;
       vi->fullsize = TREE_INT_CST_LOW (declsize);
       vi->size = vi->fullsize;
+      vi->is_full_var = true;
+      VEC_free (fieldoff_s, heap, fieldstack);
+      return vi;
     }
 
-  insert_vi_for_tree (vi->decl, vi);
+  vi = new_var_info (decl, name);
+  vi->fullsize = TREE_INT_CST_LOW (declsize);
+  for (i = 0, newvi = vi;
+       VEC_iterate (fieldoff_s, fieldstack, i, fo);
+       ++i, newvi = newvi->next)
+    {
+      const char *newname = "NULL";
+      char *tempname;
+
+      if (dump_file)
+       {
+         asprintf (&tempname, "%s." HOST_WIDE_INT_PRINT_DEC
+                   "+" HOST_WIDE_INT_PRINT_DEC, name, fo->offset, fo->size);
+         newname = ggc_strdup (tempname);
+         free (tempname);
+       }
+      newvi->name = newname;
+      newvi->offset = fo->offset;
+      newvi->size = fo->size;
+      newvi->fullsize = vi->fullsize;
+      newvi->may_have_pointers = fo->may_have_pointers;
+      newvi->only_restrict_pointers = fo->only_restrict_pointers;
+      if (i + 1 < VEC_length (fieldoff_s, fieldstack))
+       newvi->next = new_var_info (decl, name);
+    }
 
-  /* ???  The setting of vi->may_have_pointers is too conservative here
-     and may get refined below.  Thus we have superfluous constraints
-     here sometimes which triggers the commented assert in
-     dump_sa_points_to_info.  */
-  if (vi->is_global_var
-      && vi->may_have_pointers)
+  VEC_free (fieldoff_s, heap, fieldstack);
+
+  return vi;
+}
+
+static unsigned int
+create_variable_info_for (tree decl, const char *name)
+{
+  varinfo_t vi = create_variable_info_for_1 (decl, name);
+  unsigned int id = vi->id;
+
+  insert_vi_for_tree (decl, vi);
+
+  /* Create initial constraints for globals.  */
+  for (; vi; vi = vi->next)
     {
+      if (!vi->may_have_pointers
+         || !vi->is_global_var)
+       continue;
+
       /* Mark global restrict qualified pointers.  */
-      if (POINTER_TYPE_P (TREE_TYPE (decl))
-         && TYPE_RESTRICT (TREE_TYPE (decl)))
+      if ((POINTER_TYPE_P (TREE_TYPE (decl))
+          && TYPE_RESTRICT (TREE_TYPE (decl)))
+         || vi->only_restrict_pointers)
        make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
 
       /* For escaped variables initialize them from nonlocal.  */
@@ -5179,16 +5480,16 @@ create_variable_info_for (tree decl, const char *name)
         IPA mode generate constraints for it.  In non-IPA mode
         the initializer from nonlocal is all we need.  */
       if (in_ipa_mode
-         && DECL_INITIAL (vi->decl))
+         && DECL_INITIAL (decl))
        {
          VEC (ce_s, heap) *rhsc = NULL;
          struct constraint_expr lhs, *rhsp;
          unsigned i;
-         get_constraint_for (DECL_INITIAL (vi->decl), &rhsc);
+         get_constraint_for_rhs (DECL_INITIAL (decl), &rhsc);
          lhs.var = vi->id;
          lhs.offset = 0;
          lhs.type = SCALAR;
-         for (i = 0; VEC_iterate (ce_s, rhsc, i, rhsp); ++i)
+         FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
            process_constraint (new_constraint (lhs, *rhsp));
          /* If this is a variable that escapes from the unit
             the initializer escapes as well.  */
@@ -5197,114 +5498,14 @@ create_variable_info_for (tree decl, const char *name)
              lhs.var = escaped_id;
              lhs.offset = 0;
              lhs.type = SCALAR;
-             for (i = 0; VEC_iterate (ce_s, rhsc, i, rhsp); ++i)
+             FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
                process_constraint (new_constraint (lhs, *rhsp));
            }
          VEC_free (ce_s, heap, rhsc);
-         /* ???  Force us to not use subfields.  Else we'd have to parse
-            arbitrary initializers.  */
-         VEC_free (fieldoff_s, heap, fieldstack);
        }
     }
 
-  stats.total_vars++;
-  if (use_field_sensitive
-      && !vi->is_unknown_size_var
-      && var_can_have_subvars (decl)
-      && VEC_length (fieldoff_s, fieldstack) > 1
-      && VEC_length (fieldoff_s, fieldstack) <= MAX_FIELDS_FOR_FIELD_SENSITIVE)
-    {
-      fieldoff_s *fo = NULL;
-      bool notokay = false;
-      unsigned int i;
-
-      for (i = 0; !notokay && VEC_iterate (fieldoff_s, fieldstack, i, fo); i++)
-       {
-         if (fo->has_unknown_size
-             || fo->offset < 0)
-           {
-             notokay = true;
-             break;
-           }
-       }
-
-      /* We can't sort them if we have a field with a variable sized type,
-        which will make notokay = true.  In that case, we are going to return
-        without creating varinfos for the fields anyway, so sorting them is a
-        waste to boot.  */
-      if (!notokay)
-       {
-         sort_fieldstack (fieldstack);
-         /* Due to some C++ FE issues, like PR 22488, we might end up
-            what appear to be overlapping fields even though they,
-            in reality, do not overlap.  Until the C++ FE is fixed,
-            we will simply disable field-sensitivity for these cases.  */
-         notokay = check_for_overlaps (fieldstack);
-       }
-
-
-      if (VEC_length (fieldoff_s, fieldstack) != 0)
-       fo = VEC_index (fieldoff_s, fieldstack, 0);
-
-      if (fo == NULL || notokay)
-       {
-         vi->is_unknown_size_var = 1;
-         vi->fullsize = ~0;
-         vi->size = ~0;
-         vi->is_full_var = true;
-         VEC_free (fieldoff_s, heap, fieldstack);
-         return vi->id;
-       }
-
-      vi->size = fo->size;
-      vi->offset = fo->offset;
-      vi->may_have_pointers = fo->may_have_pointers;
-      if (vi->is_global_var
-         && vi->may_have_pointers)
-       {
-         if (fo->only_restrict_pointers)
-           make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
-       }
-      for (i = VEC_length (fieldoff_s, fieldstack) - 1;
-          i >= 1 && VEC_iterate (fieldoff_s, fieldstack, i, fo);
-          i--)
-       {
-         varinfo_t newvi;
-         const char *newname = "NULL";
-         char *tempname;
-
-         if (dump_file)
-           {
-             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, newname);
-         newvi->offset = fo->offset;
-         newvi->size = fo->size;
-         newvi->fullsize = vi->fullsize;
-         newvi->may_have_pointers = fo->may_have_pointers;
-         insert_into_field_list (vi, newvi);
-         if ((newvi->is_global_var || TREE_CODE (decl) == PARM_DECL)
-             && newvi->may_have_pointers)
-           {
-              if (fo->only_restrict_pointers)
-                make_constraint_from_restrict (newvi, "GLOBAL_RESTRICT");
-              if (newvi->is_global_var && !in_ipa_mode)
-                make_copy_constraint (newvi, nonlocal_id);
-           }
-
-         stats.total_vars++;
-       }
-    }
-  else
-    vi->is_full_var = true;
-
-  VEC_free (fieldoff_s, heap, fieldstack);
-
-  return vi->id;
+  return id;
 }
 
 /* Print out the points-to solution for VAR to FILE.  */
@@ -5333,7 +5534,7 @@ dump_solution_for_var (FILE *file, unsigned int var)
 
 /* Print the points-to solution for VAR to stdout.  */
 
-void
+DEBUG_FUNCTION void
 debug_solution_for_var (unsigned int var)
 {
   dump_solution_for_var (stdout, var);
@@ -5350,13 +5551,10 @@ intra_create_variable_infos (void)
   /* For each incoming pointer argument arg, create the constraint ARG
      = NONLOCAL or a dummy variable if it is a restrict qualified
      passed-by-reference argument.  */
-  for (t = DECL_ARGUMENTS (current_function_decl); t; t = TREE_CHAIN (t))
+  for (t = DECL_ARGUMENTS (current_function_decl); t; t = DECL_CHAIN (t))
     {
       varinfo_t p;
 
-      if (!could_have_pointers (t))
-       continue;
-
       /* For restrict qualified pointers to objects passed by
          reference build a real representative for the pointed-to object.  */
       if (DECL_BY_REFERENCE (t)
@@ -5390,8 +5588,12 @@ intra_create_variable_infos (void)
        }
 
       for (p = get_vi_for_tree (t); p; p = p->next)
-       if (p->may_have_pointers)
-         make_constraint_from (p, nonlocal_id);
+       {
+         if (p->may_have_pointers)
+           make_constraint_from (p, nonlocal_id);
+         if (p->only_restrict_pointers)
+           make_constraint_from_restrict (p, "PARM_RESTRICT");
+       }
       if (POINTER_TYPE_P (TREE_TYPE (t))
          && TYPE_RESTRICT (TREE_TYPE (t)))
        make_constraint_from_restrict (get_vi_for_tree (t), "PARM_RESTRICT");
@@ -5611,7 +5813,8 @@ find_what_p_points_to (tree p)
   /* For parameters, get at the points-to set for the actual parm
      decl.  */
   if (TREE_CODE (p) == SSA_NAME
-      && TREE_CODE (SSA_NAME_VAR (p)) == PARM_DECL
+      && (TREE_CODE (SSA_NAME_VAR (p)) == PARM_DECL
+         || TREE_CODE (SSA_NAME_VAR (p)) == RESULT_DECL)
       && SSA_NAME_IS_DEFAULT_DEF (p))
     lookup_p = SSA_NAME_VAR (p);
 
@@ -5677,6 +5880,17 @@ pt_solution_set (struct pt_solution *pt, bitmap vars,
   pt->vars_contains_restrict = vars_contains_restrict;
 }
 
+/* Set the points-to solution *PT to point only to the variable VAR.  */
+
+void
+pt_solution_set_var (struct pt_solution *pt, tree var)
+{
+  memset (pt, 0, sizeof (struct pt_solution));
+  pt->vars = BITMAP_GGC_ALLOC ();
+  bitmap_set_bit (pt->vars, DECL_UID (var));
+  pt->vars_contains_global = is_global_var (var);
+}
+
 /* Computes the union of the points-to solutions *DEST and *SRC and
    stores the result in *DEST.  This changes the points-to bitmap
    of *DEST and thus may not be used if that might be shared.
@@ -5930,7 +6144,7 @@ dump_sa_points_to_info (FILE *outfile)
 
 /* Debug points-to information to stderr.  */
 
-void
+DEBUG_FUNCTION void
 debug_sa_points_to_info (void)
 {
   dump_sa_points_to_info (stderr);
@@ -6306,7 +6520,7 @@ compute_points_to_sets (void)
   cfun->gimple_df->escaped.escaped = 0;
 
   /* Mark escaped HEAP variables as global.  */
-  for (i = 0; VEC_iterate (varinfo_t, varmap, i, vi); ++i)
+  FOR_EACH_VEC_ELT (varinfo_t, varmap, i, vi)
     if (vi->is_heap_var
        && !vi->is_restrict_var
        && !vi->is_global_var)
@@ -6521,7 +6735,7 @@ gate_ipa_pta (void)
   return (optimize
          && flag_ipa_pta
          /* Don't bother doing anything if the program has errors.  */
-         && !(errorcount || sorrycount));
+         && !seen_error ());
 }
 
 /* IPA PTA solutions for ESCAPED.  */
@@ -6544,6 +6758,9 @@ ipa_pta_execute (void)
   /* Build the constraints.  */
   for (node = cgraph_nodes; node; node = node->next)
     {
+      struct cgraph_node *alias;
+      varinfo_t vi;
+
       /* Nodes without a body are not interesting.  Especially do not
          visit clones at this point for now - we get duplicate decls
         there for inline clones at least.  */
@@ -6551,13 +6768,26 @@ ipa_pta_execute (void)
          || node->clone_of)
        continue;
 
-      create_function_info_for (node->decl,
-                               cgraph_node_name (node));
+      vi = create_function_info_for (node->decl,
+                                    alias_get_name (node->decl));
+
+      /* Associate the varinfo node with all aliases.  */
+      for (alias = node->same_body; alias; alias = alias->next)
+       insert_vi_for_tree (alias->decl, vi);
     }
 
   /* Create constraints for global variables and their initializers.  */
   for (var = varpool_nodes; var; var = var->next)
-    get_vi_for_tree (var->decl);
+    {
+      struct varpool_node *alias;
+      varinfo_t vi;
+
+      vi = get_vi_for_tree (var->decl);
+
+      /* Associate the varinfo node with all aliases.  */
+      for (alias = var->extra_name; alias; alias = alias->next)
+       insert_vi_for_tree (alias->decl, vi);
+    }
 
   if (dump_file)
     {
@@ -6580,9 +6810,14 @@ ipa_pta_execute (void)
        continue;
 
       if (dump_file)
-       fprintf (dump_file,
-                "Generating constraints for %s\n",
-                cgraph_node_name (node));
+       {
+         fprintf (dump_file,
+                  "Generating constraints for %s", cgraph_node_name (node));
+         if (DECL_ASSEMBLER_NAME_SET_P (node->decl))
+           fprintf (dump_file, " (%s)",
+                    IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl)));
+         fprintf (dump_file, "\n");
+       }
 
       func = DECL_STRUCT_FUNCTION (node->decl);
       old_func_decl = current_function_decl;
@@ -6663,7 +6898,7 @@ ipa_pta_execute (void)
       fn = DECL_STRUCT_FUNCTION (node->decl);
 
       /* Compute the points-to sets for pointer SSA_NAMEs.  */
-      for (i = 0; VEC_iterate (tree, fn->gimple_df->ssa_names, i, ptr); ++i)
+      FOR_EACH_VEC_ELT (tree, fn->gimple_df->ssa_names, i, ptr)
        {
          if (ptr
              && POINTER_TYPE_P (TREE_TYPE (ptr)))