OSDN Git Service

2010-04-12 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-structalias.c
index a5a9634..e14b97a 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 "toplev.h"
 #include "gimple.h"
   TODO: We could handle unions, but to be honest, it's probably not
   worth the pain or slowdown.  */
 
-/* IPA-PTA optimizations possible.
-
-   When the indirect function called is ANYTHING we can add disambiguation
-   based on the function signatures (or simply the parameter count which
-   is the varinfo size).  We also do not need to consider functions that
-   do not have their address taken.
-
-   The is_global_var bit which marks escape points is overly conservative
-   in IPA mode.  Split it to is_escape_point and is_global_var - only
-   externally visible globals are escape points in IPA mode.  This is
-   also needed to fix the pt_solution_includes_global predicate
-   (and thus ptr_deref_may_alias_global_p).
-
-   The way we introduce DECL_PT_UID to avoid fixing up all points-to
-   sets in the translation unit when we copy a DECL during inlining
-   pessimizes precision.  The advantage is that the DECL_PT_UID keeps
-   compile-time and memory usage overhead low - the points-to sets
-   do not grow or get unshared as they would during a fixup phase.
-   An alternative solution is to delay IPA PTA until after all
-   inlining transformations have been applied.
-
-   The way we propagate clobber/use information isn't optimized.
-   It should use a new complex constraint that properly filters
-   out local variables of the callee (though that would make
-   the sets invalid after inlining).  OTOH we might as well
-   admit defeat to WHOPR and simply do all the clobber/use analysis
-   and propagation after PTA finished but before we threw away
-   points-to information for memory variables.  WHOPR and PTA
-   do not play along well anyway - the whole constraint solving
-   would need to be done in WPA phase and it will be very interesting
-   to apply the results to local SSA names during LTRANS phase.
-
-   We probably should compute a per-function unit-ESCAPE solution
-   propagating it simply like the clobber / uses solutions.  The
-   solution can go alongside the non-IPA espaced solution and be
-   used to query which vars escape the unit through a function.
-
-   We never put function decls in points-to sets so we do not
-   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)))
 htab_t heapvar_for_stmt;
 
@@ -271,15 +233,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;
 
-  /* True if this represents a IPA function info.  */
-  unsigned int is_fn_info : 1;
-
   /* A link to the variable for the next field in this structure.  */
   struct variable_info *next;
 
@@ -332,8 +288,8 @@ get_varinfo (unsigned int n)
 
 /* Static IDs for the special variables.  */
 enum { nothing_id = 0, anything_id = 1, readonly_id = 2,
-       escaped_id = 3, nonlocal_id = 4,
-       storedanything_id = 5, integer_id = 6 };
+       escaped_id = 3, nonlocal_id = 4, callused_id = 5,
+       storedanything_id = 6, integer_id = 7 };
 
 struct GTY(()) heapvar_map {
   struct tree_map map;
@@ -411,102 +367,18 @@ 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))
     ret->is_global_var = is_global_var (t);
   ret->solution = BITMAP_ALLOC (&pta_obstack);
   ret->oldsolution = BITMAP_ALLOC (&oldpta_obstack);
   ret->next = NULL;
 
-  stats.total_vars++;
-
   VEC_safe_push (varinfo_t, heap, varmap, ret);
 
   return ret;
 }
 
-
-/* A map mapping call statements to per-stmt variables for uses
-   and clobbers specific to the call.  */
-struct pointer_map_t *call_stmt_vars;
-
-/* Lookup or create the variable for the call statement CALL.  */
-
-static varinfo_t
-get_call_vi (gimple call)
-{
-  void **slot_p;
-  varinfo_t vi, vi2;
-
-  slot_p = pointer_map_insert (call_stmt_vars, call);
-  if (*slot_p)
-    return (varinfo_t) *slot_p;
-
-  vi = new_var_info (NULL_TREE, "CALLUSED");
-  vi->offset = 0;
-  vi->size = 1;
-  vi->fullsize = 2;
-  vi->is_full_var = true;
-
-  vi->next = vi2 = new_var_info (NULL_TREE, "CALLCLOBBERED");
-  vi2->offset = 1;
-  vi2->size = 1;
-  vi2->fullsize = 2;
-  vi2->is_full_var = true;
-
-  *slot_p = (void *) vi;
-  return vi;
-}
-
-/* Lookup the variable for the call statement CALL representing
-   the uses.  Returns NULL if there is nothing special about this call.  */
-
-static varinfo_t
-lookup_call_use_vi (gimple call)
-{
-  void **slot_p;
-
-  slot_p = pointer_map_contains (call_stmt_vars, call);
-  if (slot_p)
-    return (varinfo_t) *slot_p;
-
-  return NULL;
-}
-
-/* Lookup the variable for the call statement CALL representing
-   the clobbers.  Returns NULL if there is nothing special about this call.  */
-
-static varinfo_t
-lookup_call_clobber_vi (gimple call)
-{
-  varinfo_t uses = lookup_call_use_vi (call);
-  if (!uses)
-    return NULL;
-
-  return uses->next;
-}
-
-/* Lookup or create the variable for the call statement CALL representing
-   the uses.  */
-
-static varinfo_t
-get_call_use_vi (gimple call)
-{
-  return get_call_vi (call);
-}
-
-/* Lookup or create the variable for the call statement CALL representing
-   the clobbers.  */
-
-static varinfo_t ATTRIBUTE_UNUSED
-get_call_clobber_vi (gimple call)
-{
-  return get_call_vi (call)->next;
-}
-
-
 typedef enum {SCALAR, DEREF, ADDRESSOF} constraint_expr_type;
 
 /* An expression that appears in a constraint.  */
@@ -725,11 +597,11 @@ debug_constraint (constraint_t c)
 /* Print out all constraints to FILE */
 
 static void
-dump_constraints (FILE *file, int from)
+dump_constraints (FILE *file)
 {
   int i;
   constraint_t c;
-  for (i = from; VEC_iterate (constraint_t, constraints, i, c); i++)
+  for (i = 0; VEC_iterate (constraint_t, constraints, i, c); i++)
     dump_constraint (file, c);
 }
 
@@ -738,7 +610,7 @@ dump_constraints (FILE *file, int from)
 void
 debug_constraints (void)
 {
-  dump_constraints (stderr, 0);
+  dump_constraints (stderr);
 }
 
 /* Print out to FILE the edge in the constraint graph that is created by
@@ -789,7 +661,7 @@ dump_constraint_graph (FILE *file)
   /* 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, 0);
+  dump_constraints (file);
   fprintf (file, "*/\n");
 
   /* Prints the header of the dot file:  */
@@ -1708,8 +1580,7 @@ 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 (v->may_have_pointers
-                  && add_graph_edge (graph, lhs, t))
+         else if (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
@@ -1748,7 +1619,6 @@ 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);
@@ -1795,6 +1665,22 @@ 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)
@@ -1807,25 +1693,6 @@ 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)
@@ -2756,14 +2623,10 @@ lookup_vi_for_tree (tree t)
 static const char *
 alias_get_name (tree decl)
 {
-  const char *res;
+  const char *res = get_name (decl);
   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;
 
@@ -2896,16 +2759,6 @@ 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)
     {
@@ -2941,12 +2794,6 @@ type_could_have_pointers (tree type)
   if (TREE_CODE (type) == ARRAY_TYPE)
     return type_could_have_pointers (TREE_TYPE (type));
 
-  /* A function or method can consume pointers.
-     ???  We could be more precise here.  */
-  if (TREE_CODE (type) == FUNCTION_TYPE
-      || TREE_CODE (type) == METHOD_TYPE)
-    return true;
-
   return AGGREGATE_TYPE_P (type);
 }
 
@@ -2956,11 +2803,7 @@ type_could_have_pointers (tree type)
 static bool
 could_have_pointers (tree t)
 {
-  return (((TREE_CODE (t) == VAR_DECL
-           || TREE_CODE (t) == PARM_DECL
-           || TREE_CODE (t) == RESULT_DECL)
-          && (TREE_PUBLIC (t) || DECL_EXTERNAL (t) || TREE_ADDRESSABLE (t)))
-         || type_could_have_pointers (TREE_TYPE (t)));
+  return type_could_have_pointers (TREE_TYPE (t));
 }
 
 /* Return the position, in bits, of FIELD_DECL from the beginning of its
@@ -3291,18 +3134,14 @@ 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 ((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 = anything_id;
+  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;
       temp.type = ADDRESSOF;
       temp.offset = 0;
       VEC_safe_push (ce_s, heap, *results, &temp);
@@ -3364,26 +3203,6 @@ 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);
-                 for (j = 0; VEC_iterate (ce_s, tmp, j, rhsp); ++j)
-                   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;
@@ -3458,19 +3277,7 @@ do_structure_copy (tree lhsop, tree rhsop)
   if (lhsp->type == DEREF
       || (lhsp->type == ADDRESSOF && lhsp->var == anything_id)
       || rhsp->type == DEREF)
-    {
-      if (lhsp->type == DEREF)
-       {
-         gcc_assert (VEC_length (ce_s, lhsc) == 1);
-         lhsp->offset = UNKNOWN_OFFSET;
-       }
-      if (rhsp->type == DEREF)
-       {
-         gcc_assert (VEC_length (ce_s, rhsc) == 1);
-         rhsp->offset = UNKNOWN_OFFSET;
-       }
-      process_all_all_constraints (lhsc, rhsc);
-    }
+    process_all_all_constraints (lhsc, rhsc);
   else if (lhsp->type == SCALAR
           && (rhsp->type == SCALAR
               || rhsp->type == ADDRESSOF))
@@ -3570,37 +3377,11 @@ make_escape_constraint (tree op)
   make_constraint_to (escaped_id, op);
 }
 
-/* Add constraints to that the solution of VI is transitively closed.  */
-
-static void
-make_transitive_closure_constraints (varinfo_t vi)
-{
-  struct constraint_expr lhs, rhs;
-
-  /* VAR = *VAR;  */
-  lhs.type = SCALAR;
-  lhs.var = vi->id;
-  lhs.offset = 0;
-  rhs.type = DEREF;
-  rhs.var = vi->id;
-  rhs.offset = 0;
-  process_constraint (new_constraint (lhs, rhs));
-
-  /* VAR = VAR + UNKNOWN;  */
-  lhs.type = SCALAR;
-  lhs.var = vi->id;
-  lhs.offset = 0;
-  rhs.type = SCALAR;
-  rhs.var = vi->id;
-  rhs.offset = UNKNOWN_OFFSET;
-  process_constraint (new_constraint (lhs, rhs));
-}
-
-/* Create a new artificial heap variable with NAME.
-   Return the created variable.  */
+/* Create a new artificial heap variable with NAME and make a
+   constraint from it to LHS.  Return the created variable.  */
 
 static varinfo_t
-make_heapvar_for (varinfo_t lhs, const char *name)
+make_constraint_from_heapvar (varinfo_t lhs, const char *name)
 {
   varinfo_t vi;
   tree heapvar = heapvar_lookup (lhs->decl, lhs->offset);
@@ -3619,7 +3400,7 @@ make_heapvar_for (varinfo_t lhs, const char *name)
 
   /* For global vars we need to add a heapvar to the list of referenced
      vars of a different function than it was created for originally.  */
-  if (cfun && gimple_referenced_vars (cfun))
+  if (gimple_referenced_vars (cfun))
     add_referenced_var (heapvar);
 
   vi = new_var_info (heapvar, name);
@@ -3632,16 +3413,6 @@ make_heapvar_for (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;
@@ -3662,52 +3433,6 @@ make_constraint_from_restrict (varinfo_t lhs, const char *name)
   vi->may_have_pointers = 0;
 }
 
-/* In IPA mode there are varinfos for different aspects of reach
-   function designator.  One for the points-to set of the return
-   value, one for the variables that are clobbered by the function,
-   one for its uses and one for each parameter (including a single
-   glob for remaining variadic arguments).  */
-
-enum { fi_clobbers = 1, fi_uses = 2,
-       fi_static_chain = 3, fi_result = 4, fi_parm_base = 5 };
-
-/* Get a constraint for the requested part of a function designator FI
-   when operating in IPA mode.  */
-
-static struct constraint_expr
-get_function_part_constraint (varinfo_t fi, unsigned part)
-{
-  struct constraint_expr c;
-
-  gcc_assert (in_ipa_mode);
-
-  if (fi->id == anything_id)
-    {
-      /* ???  We probably should have a ANYFN special variable.  */
-      c.var = anything_id;
-      c.offset = 0;
-      c.type = SCALAR;
-    }
-  else if (TREE_CODE (fi->decl) == FUNCTION_DECL)
-    {
-      varinfo_t ai = first_vi_for_offset (fi, part);
-      if (ai)
-       c.var = ai->id;
-      else
-       c.var = anything_id;
-      c.offset = 0;
-      c.type = SCALAR;
-    }
-  else
-    {
-      c.var = fi->id;
-      c.offset = part;
-      c.type = DEREF;
-    }
-
-  return c;
-}
-
 /* For non-IPA mode, generate constraints necessary for a call on the
    RHS.  */
 
@@ -3716,61 +3441,17 @@ 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);
-
-      /* If the argument is not used or it does not contain pointers
-        we can ignore it.  */
-      if ((flags & EAF_UNUSED)
-         || !could_have_pointers (arg))
-       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
+      /* Find those pointers being passed, and make sure they end up
+        pointing to anything.  */
+      if (could_have_pointers (arg))
        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));
@@ -3803,63 +3484,44 @@ handle_rhs_call (gimple stmt, VEC(ce_s, heap) **results)
    the LHS point to global and escaped variables.  */
 
 static void
-handle_lhs_call (gimple stmt, tree lhs, int flags, VEC(ce_s, heap) *rhsc,
-                tree fndecl)
+handle_lhs_call (tree lhs, int flags, VEC(ce_s, heap) *rhsc, tree fndecl)
 {
   VEC(ce_s, heap) *lhsc = NULL;
 
   get_constraint_for (lhs, &lhsc);
-  /* 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)
+  if (flags & ECF_MALLOC)
     {
       varinfo_t vi;
-      struct constraint_expr tmpc;
-      rhsc = NULL;
-      vi = make_heapvar_for (get_vi_for_tree (lhs), "HEAP");
+      vi = make_constraint_from_heapvar (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);
     }
-
-  process_all_all_constraints (lhsc, rhsc);
-
+  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);
+    }
   VEC_free (ce_s, heap, lhsc);
 }
 
@@ -3876,10 +3538,8 @@ handle_const_call (gimple stmt, VEC(ce_s, heap) **results)
      as the static chain is concerned.  */
   if (gimple_call_chain (stmt))
     {
-      varinfo_t uses = get_call_use_vi (stmt);
-      make_transitive_closure_constraints (uses);
-      make_constraint_to (uses->id, gimple_call_chain (stmt));
-      rhsc.var = uses->id;
+      make_constraint_to (callused_id, gimple_call_chain (stmt));
+      rhsc.var = callused_id;
       rhsc.offset = 0;
       rhsc.type = SCALAR;
       VEC_safe_push (ce_s, heap, *results, &rhsc);
@@ -3917,7 +3577,7 @@ handle_pure_call (gimple stmt, VEC(ce_s, heap) **results)
 {
   struct constraint_expr rhsc;
   unsigned i;
-  varinfo_t uses = NULL;
+  bool need_callused = false;
 
   /* Memory reached from pointer arguments is call-used.  */
   for (i = 0; i < gimple_call_num_args (stmt); ++i)
@@ -3926,30 +3586,22 @@ handle_pure_call (gimple stmt, VEC(ce_s, heap) **results)
 
       if (could_have_pointers (arg))
        {
-         if (!uses)
-           {
-             uses = get_call_use_vi (stmt);
-             make_transitive_closure_constraints (uses);
-           }
-         make_constraint_to (uses->id, arg);
+         make_constraint_to (callused_id, arg);
+         need_callused = true;
        }
     }
 
   /* The static chain is used as well.  */
   if (gimple_call_chain (stmt))
     {
-      if (!uses)
-       {
-         uses = get_call_use_vi (stmt);
-         make_transitive_closure_constraints (uses);
-       }
-      make_constraint_to (uses->id, gimple_call_chain (stmt));
+      make_constraint_to (callused_id, gimple_call_chain (stmt));
+      need_callused = true;
     }
 
-  /* Pure functions may return call-used and nonlocal memory.  */
-  if (uses)
+  /* Pure functions may return callused and nonlocal memory.  */
+  if (need_callused)
     {
-      rhsc.var = uses->id;
+      rhsc.var = callused_id;
       rhsc.offset = 0;
       rhsc.type = SCALAR;
       VEC_safe_push (ce_s, heap, *results, &rhsc);
@@ -3960,40 +3612,6 @@ handle_pure_call (gimple stmt, VEC(ce_s, heap) **results)
   VEC_safe_push (ce_s, heap, *results, &rhsc);
 }
 
-
-/* Return the varinfo for the callee of CALL.  */
-
-static varinfo_t
-get_fi_for_callee (gimple call)
-{
-  tree decl;
-
-  /* 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.  */
-  decl = gimple_call_fndecl (call);
-  if (decl)
-    return get_vi_for_tree (decl);
-
-  decl = gimple_call_fn (call);
-  /* The function can be either an SSA name pointer or,
-     worse, an OBJ_TYPE_REF.  In this case we have no
-     clue and should be getting ANYFN (well, ANYTHING for now).  */
-  if (TREE_CODE (decl) == SSA_NAME)
-    {
-      if (TREE_CODE (decl) == SSA_NAME
-         && TREE_CODE (SSA_NAME_VAR (decl)) == PARM_DECL
-         && SSA_NAME_IS_DEFAULT_DEF (decl))
-       decl = SSA_NAME_VAR (decl);
-      return get_vi_for_tree (decl);
-    }
-  else if (TREE_CODE (decl) == INTEGER_CST
-          || TREE_CODE (decl) == OBJ_TYPE_REF)
-    return get_varinfo (anything_id);
-  else
-    gcc_unreachable ();
-}
-
 /* Walk statement T setting up aliasing constraints according to the
    references found in T.  This function is the main part of the
    constraint builder.  AI points to auxiliary alias information used
@@ -4006,7 +3624,6 @@ find_func_aliases (gimple origt)
   VEC(ce_s, heap) *lhsc = NULL;
   VEC(ce_s, heap) *rhsc = NULL;
   struct constraint_expr *c;
-  varinfo_t fi;
 
   /* Now build constraints expressions.  */
   if (gimple_code (t) == GIMPLE_PHI)
@@ -4159,88 +3776,6 @@ find_func_aliases (gimple origt)
          case BUILT_IN_REMQUOL:
          case BUILT_IN_FREE:
            return;
-         /* Trampolines are special - they set up passing the static
-            frame.  */
-         case BUILT_IN_INIT_TRAMPOLINE:
-           {
-             tree tramp = gimple_call_arg (t, 0);
-             tree nfunc = gimple_call_arg (t, 1);
-             tree frame = gimple_call_arg (t, 2);
-             unsigned i;
-             struct constraint_expr lhs, *rhsp;
-             if (in_ipa_mode)
-               {
-                 varinfo_t nfi = NULL;
-                 gcc_assert (TREE_CODE (nfunc) == ADDR_EXPR);
-                 nfi = lookup_vi_for_tree (TREE_OPERAND (nfunc, 0));
-                 if (nfi)
-                   {
-                     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)
-                       process_constraint (new_constraint (lhs, *rhsp));
-                     VEC_free (ce_s, heap, rhsc);
-
-                     /* Make the frame point to the function for
-                        the trampoline adjustment call.  */
-                     get_constraint_for (tramp, &lhsc);
-                     do_deref (&lhsc);
-                     get_constraint_for (nfunc, &rhsc);
-                     process_all_all_constraints (lhsc, rhsc);
-                     VEC_free (ce_s, heap, rhsc);
-                     VEC_free (ce_s, heap, lhsc);
-
-                     return;
-                   }
-               }
-             /* Else fallthru to generic handling which will let
-                the frame escape.  */
-             break;
-           }
-         case BUILT_IN_ADJUST_TRAMPOLINE:
-           {
-             tree tramp = gimple_call_arg (t, 0);
-             tree res = gimple_call_lhs (t);
-             if (in_ipa_mode && res)
-               {
-                 get_constraint_for (res, &lhsc);
-                 get_constraint_for (tramp, &rhsc);
-                 do_deref (&rhsc);
-                 process_all_all_constraints (lhsc, rhsc);
-                 VEC_free (ce_s, heap, rhsc);
-                 VEC_free (ce_s, heap, lhsc);
-               }
-             return;
-           }
-         /* Variadic argument handling needs to be handled in IPA
-            mode as well.  */
-         case BUILT_IN_VA_START:
-           {
-             if (in_ipa_mode)
-               {
-                 tree valist = gimple_call_arg (t, 0);
-                 struct constraint_expr rhs, *lhsp;
-                 unsigned i;
-                 /* The va_list gets access to pointers in variadic
-                    arguments.  */
-                 fi = lookup_vi_for_tree (cfun->decl);
-                 gcc_assert (fi != NULL);
-                 get_constraint_for (valist, &lhsc);
-                 do_deref (&lhsc);
-                 rhs = get_function_part_constraint (fi, ~0);
-                 rhs.type = ADDRESSOF;
-                 for (i = 0; VEC_iterate (ce_s, lhsc, i, lhsp); ++i)
-                   process_constraint (new_constraint (*lhsp, rhs));
-                 VEC_free (ce_s, heap, lhsc);
-                 /* va_list is clobbered.  */
-                 make_constraint_to (get_call_clobber_vi (t)->id, valist);
-                 return;
-               }
-             break;
-           }
-         /* va_end doesn't have any effect that matters.  */
-         case BUILT_IN_VA_END:
-           return;
          /* printf-style functions may have hooks to set pointers to
             point to somewhere into the generated string.  Leave them
             for a later excercise...  */
@@ -4249,8 +3784,7 @@ find_func_aliases (gimple origt)
          }
       if (!in_ipa_mode
          || (fndecl
-             && (!(fi = lookup_vi_for_tree (fndecl))
-                 || !fi->is_fn_info)))
+             && !lookup_vi_for_tree (fndecl)))
        {
          VEC(ce_s, heap) *rhsc = NULL;
          int flags = gimple_call_flags (t);
@@ -4272,15 +3806,30 @@ find_func_aliases (gimple origt)
            handle_rhs_call (t, &rhsc);
          if (gimple_call_lhs (t)
              && could_have_pointers (gimple_call_lhs (t)))
-           handle_lhs_call (t, gimple_call_lhs (t), flags, rhsc, fndecl);
+           handle_lhs_call (gimple_call_lhs (t), flags, rhsc, fndecl);
          VEC_free (ce_s, heap, rhsc);
        }
       else
        {
          tree lhsop;
-         unsigned j;
+         varinfo_t fi;
+         int i = 1;
+         size_t j;
+         tree decl;
+
+         lhsop = gimple_call_lhs (t);
+         decl = gimple_call_fndecl (t);
 
-         fi = get_fi_for_callee (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);
+         else
+           {
+             decl = gimple_call_fn (t);
+             fi = get_vi_for_tree (decl);
+           }
 
          /* Assign all the passed arguments to the appropriate incoming
             parameters of the function.  */
@@ -4290,77 +3839,58 @@ 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);
-             lhs = get_function_part_constraint (fi, fi_parm_base + j);
+             if (TREE_CODE (decl) != FUNCTION_DECL)
+               {
+                 lhs.type = DEREF;
+                 lhs.var = fi->id;
+                 lhs.offset = i;
+               }
+             else
+               {
+                 lhs.type = SCALAR;
+                 lhs.var = first_vi_for_offset (fi, i)->id;
+                 lhs.offset = 0;
+               }
              while (VEC_length (ce_s, rhsc) != 0)
                {
                  rhsp = VEC_last (ce_s, rhsc);
                  process_constraint (new_constraint (lhs, *rhsp));
                  VEC_pop (ce_s, rhsc);
                }
+             i++;
            }
 
          /* If we are returning a value, assign it to the result.  */
-         lhsop = gimple_call_lhs (t);
-         if (lhsop
-             && type_could_have_pointers (TREE_TYPE (lhsop)))
+         if (lhsop)
            {
              struct constraint_expr rhs;
              struct constraint_expr *lhsp;
+             unsigned int j = 0;
 
              get_constraint_for (lhsop, &lhsc);
-             rhs = get_function_part_constraint (fi, fi_result);
-             if (fndecl
-                 && DECL_RESULT (fndecl)
-                 && DECL_BY_REFERENCE (DECL_RESULT (fndecl)))
+             if (TREE_CODE (decl) != FUNCTION_DECL)
                {
-                 VEC(ce_s, heap) *tem = NULL;
-                 VEC_safe_push (ce_s, heap, tem, &rhs);
-                 do_deref (&tem);
-                 rhs = *VEC_index (ce_s, tem, 0);
-                 VEC_free(ce_s, heap, tem);
+                 rhs.type = DEREF;
+                 rhs.var = fi->id;
+                 rhs.offset = i;
+               }
+             else
+               {
+                 rhs.type = SCALAR;
+                 rhs.var = first_vi_for_offset (fi, i)->id;
+                 rhs.offset = 0;
                }
              for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
                process_constraint (new_constraint (*lhsp, rhs));
            }
-
-         /* If we pass the result decl by reference, honor that.  */
-         if (lhsop
-             && fndecl
-             && DECL_RESULT (fndecl)
-             && DECL_BY_REFERENCE (DECL_RESULT (fndecl)))
-           {
-             struct constraint_expr lhs;
-             struct constraint_expr *rhsp;
-
-             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++)
-               process_constraint (new_constraint (lhs, *rhsp));
-             VEC_free (ce_s, heap, rhsc);
-           }
-
-         /* If we use a static chain, pass it along.  */
-         if (gimple_call_chain (t))
-           {
-             struct constraint_expr lhs;
-             struct constraint_expr *rhsp;
-
-             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++)
-               process_constraint (new_constraint (lhs, *rhsp));
-           }
        }
     }
   /* 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)
-          && type_could_have_pointers (TREE_TYPE (gimple_assign_lhs (t))))
+          && could_have_pointers (gimple_assign_lhs (t)))
     {
       /* Otherwise, just a regular assignment statement.  */
       tree lhsop = gimple_assign_lhs (t);
@@ -4393,9 +3923,7 @@ find_func_aliases (gimple origt)
       /* If there is a store to a global variable the rhs escapes.  */
       if ((lhsop = get_base_address (lhsop)) != NULL_TREE
          && DECL_P (lhsop)
-         && is_global_var (lhsop)
-         && (!in_ipa_mode
-             || DECL_EXTERNAL (lhsop) || TREE_PUBLIC (lhsop)))
+         && is_global_var (lhsop))
        make_escape_constraint (rhsop);
       /* If this is a conversion of a non-restrict pointer to a
         restrict pointer track it with a new heapvar.  */
@@ -4419,22 +3947,7 @@ find_func_aliases (gimple origt)
           && gimple_return_retval (t) != NULL_TREE
           && could_have_pointers (gimple_return_retval (t)))
     {
-      fi = NULL;
-      if (!in_ipa_mode
-         || !(fi = get_vi_for_tree (cfun->decl)))
-       make_escape_constraint (gimple_return_retval (t));
-      else if (in_ipa_mode
-              && fi != NULL)
-       {
-         struct constraint_expr lhs ;
-         struct constraint_expr *rhsp;
-         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++)
-           process_constraint (new_constraint (lhs, *rhsp));
-       }
+      make_escape_constraint (gimple_return_retval (t));
     }
   /* Handle asms conservatively by adding escape constraints to everything.  */
   else if (gimple_code (t) == GIMPLE_ASM)
@@ -4491,8 +4004,8 @@ find_func_aliases (gimple origt)
          if (!allows_reg && allows_mem)
            make_escape_constraint (build_fold_addr_expr (op));
          /* 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.  */
+            the asm clobbers memory, otherwise using CALLUSED
+            would be enough.  */
          else if (op && could_have_pointers (op))
            make_escape_constraint (op);
        }
@@ -4503,297 +4016,20 @@ find_func_aliases (gimple origt)
 }
 
 
-/* Create a constraint adding to the clobber set of FI the memory
-   pointed to by PTR.  */
-
-static void
-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);
-  lhs = get_function_part_constraint (fi, fi_clobbers);
-  for (i = 0; VEC_iterate (ce_s, ptrc, i, c); i++)
-    process_constraint (new_constraint (lhs, *c));
-  VEC_free (ce_s, heap, ptrc);
-}
-
-/* Walk statement T setting up clobber and use constraints according to the
-   references found in T.  This function is a main part of the
-   IPA constraint builder.  */
+/* Find the first varinfo in the same variable as START that overlaps with
+   OFFSET.  Return NULL if we can't find one.  */
 
-static void
-find_func_clobbers (gimple origt)
+static varinfo_t
+first_vi_for_offset (varinfo_t start, unsigned HOST_WIDE_INT offset)
 {
-  gimple t = origt;
-  VEC(ce_s, heap) *lhsc = NULL;
-  VEC(ce_s, heap) *rhsc = NULL;
-  varinfo_t fi;
+  /* If the offset is outside of the variable, bail out.  */
+  if (offset >= start->fullsize)
+    return NULL;
 
-  /* Add constraints for clobbered/used in IPA mode.
-     We are not interested in what automatic variables are clobbered
-     or used as we only use the information in the caller to which
-     they do not escape.  */
-  gcc_assert (in_ipa_mode);
-
-  /* If the stmt refers to memory in any way it better had a VUSE.  */
-  if (gimple_vuse (t) == NULL_TREE)
-    return;
-
-  /* We'd better have function information for the current function.  */
-  fi = lookup_vi_for_tree (cfun->decl);
-  gcc_assert (fi != NULL);
-
-  /* Account for stores in assignments and calls.  */
-  if (gimple_vdef (t) != NULL_TREE
-      && gimple_has_lhs (t))
-    {
-      tree lhs = gimple_get_lhs (t);
-      tree tem = lhs;
-      while (handled_component_p (tem))
-       tem = TREE_OPERAND (tem, 0);
-      if ((DECL_P (tem)
-          && !auto_var_in_fn_p (tem, cfun->decl))
-         || INDIRECT_REF_P (tem))
-       {
-         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++)
-           process_constraint (new_constraint (lhsc, *rhsp));
-         VEC_free (ce_s, heap, rhsc);
-       }
-    }
-
-  /* Account for uses in assigments and returns.  */
-  if (gimple_assign_single_p (t)
-      || (gimple_code (t) == GIMPLE_RETURN
-         && gimple_return_retval (t) != NULL_TREE))
-    {
-      tree rhs = (gimple_assign_single_p (t)
-                 ? gimple_assign_rhs1 (t) : gimple_return_retval (t));
-      tree tem = rhs;
-      while (handled_component_p (tem))
-       tem = TREE_OPERAND (tem, 0);
-      if ((DECL_P (tem)
-          && !auto_var_in_fn_p (tem, cfun->decl))
-         || INDIRECT_REF_P (tem))
-       {
-         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++)
-           process_constraint (new_constraint (lhs, *rhsp));
-         VEC_free (ce_s, heap, rhsc);
-       }
-    }
-
-  if (is_gimple_call (t))
-    {
-      varinfo_t cfi = NULL;
-      tree decl = gimple_call_fndecl (t);
-      struct constraint_expr lhs, rhs;
-      unsigned i, j;
-
-      /* For builtins we do not have separate function info.  For those
-        we do not generate escapes for we have to generate clobbers/uses.  */
-      if (decl
-         && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
-       switch (DECL_FUNCTION_CODE (decl))
-         {
-         /* The following functions use and clobber memory pointed to
-            by their arguments.  */
-         case BUILT_IN_STRCPY:
-         case BUILT_IN_STRNCPY:
-         case BUILT_IN_BCOPY:
-         case BUILT_IN_MEMCPY:
-         case BUILT_IN_MEMMOVE:
-         case BUILT_IN_MEMPCPY:
-         case BUILT_IN_STPCPY:
-         case BUILT_IN_STPNCPY:
-         case BUILT_IN_STRCAT:
-         case BUILT_IN_STRNCAT:
-           {
-             tree dest = gimple_call_arg (t, (DECL_FUNCTION_CODE (decl)
-                                              == BUILT_IN_BCOPY ? 1 : 0));
-             tree src = gimple_call_arg (t, (DECL_FUNCTION_CODE (decl)
-                                             == BUILT_IN_BCOPY ? 0 : 1));
-             unsigned i;
-             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++)
-               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++)
-               process_constraint (new_constraint (lhs, *rhsp));
-             VEC_free (ce_s, heap, rhsc);
-             return;
-           }
-         /* The following function clobbers memory pointed to by
-            its argument.  */
-         case BUILT_IN_MEMSET:
-           {
-             tree dest = gimple_call_arg (t, 0);
-             unsigned i;
-             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++)
-               process_constraint (new_constraint (lhs, *lhsp));
-             VEC_free (ce_s, heap, lhsc);
-             return;
-           }
-         /* The following functions clobber their second and third
-            arguments.  */
-         case BUILT_IN_SINCOS:
-         case BUILT_IN_SINCOSF:
-         case BUILT_IN_SINCOSL:
-           {
-             process_ipa_clobber (fi, gimple_call_arg (t, 1));
-             process_ipa_clobber (fi, gimple_call_arg (t, 2));
-             return;
-           }
-         /* The following functions clobber their second argument.  */
-         case BUILT_IN_FREXP:
-         case BUILT_IN_FREXPF:
-         case BUILT_IN_FREXPL:
-         case BUILT_IN_LGAMMA_R:
-         case BUILT_IN_LGAMMAF_R:
-         case BUILT_IN_LGAMMAL_R:
-         case BUILT_IN_GAMMA_R:
-         case BUILT_IN_GAMMAF_R:
-         case BUILT_IN_GAMMAL_R:
-         case BUILT_IN_MODF:
-         case BUILT_IN_MODFF:
-         case BUILT_IN_MODFL:
-           {
-             process_ipa_clobber (fi, gimple_call_arg (t, 1));
-             return;
-           }
-         /* The following functions clobber their third argument.  */
-         case BUILT_IN_REMQUO:
-         case BUILT_IN_REMQUOF:
-         case BUILT_IN_REMQUOL:
-           {
-             process_ipa_clobber (fi, gimple_call_arg (t, 2));
-             return;
-           }
-         /* The following functions neither read nor clobber memory.  */
-         case BUILT_IN_FREE:
-           return;
-         /* Trampolines are of no interest to us.  */
-         case BUILT_IN_INIT_TRAMPOLINE:
-         case BUILT_IN_ADJUST_TRAMPOLINE:
-           return;
-         case BUILT_IN_VA_START:
-         case BUILT_IN_VA_END:
-           return;
-         /* printf-style functions may have hooks to set pointers to
-            point to somewhere into the generated string.  Leave them
-            for a later excercise...  */
-         default:
-           /* Fallthru to general call handling.  */;
-         }
-
-      /* Parameters passed by value are used.  */
-      lhs = get_function_part_constraint (fi, fi_uses);
-      for (i = 0; i < gimple_call_num_args (t); i++)
-       {
-         struct constraint_expr *rhsp;
-         tree arg = gimple_call_arg (t, i);
-
-         if (TREE_CODE (arg) == SSA_NAME
-             || is_gimple_min_invariant (arg))
-           continue;
-
-         get_constraint_for_address_of (arg, &rhsc);
-         for (j = 0; VEC_iterate (ce_s, rhsc, j, rhsp); j++)
-           process_constraint (new_constraint (lhs, *rhsp));
-         VEC_free (ce_s, heap, rhsc);
-       }
-
-      /* Build constraints for propagating clobbers/uses along the
-        callgraph edges.  */
-      cfi = get_fi_for_callee (t);
-      if (cfi->id == anything_id)
-       {
-         if (gimple_vdef (t))
-           make_constraint_from (first_vi_for_offset (fi, fi_clobbers),
-                                 anything_id);
-         make_constraint_from (first_vi_for_offset (fi, fi_uses),
-                               anything_id);
-         return;
-       }
-
-      /* For callees without function info (that's external functions),
-        ESCAPED is clobbered and used.  */
-      if (gimple_call_fndecl (t)
-         && !cfi->is_fn_info)
-       {
-         varinfo_t vi;
-
-         if (gimple_vdef (t))
-           make_copy_constraint (first_vi_for_offset (fi, fi_clobbers),
-                                 escaped_id);
-         make_copy_constraint (first_vi_for_offset (fi, fi_uses), escaped_id);
-
-         /* Also honor the call statement use/clobber info.  */
-         if ((vi = lookup_call_clobber_vi (t)) != NULL)
-           make_copy_constraint (first_vi_for_offset (fi, fi_clobbers),
-                                 vi->id);
-         if ((vi = lookup_call_use_vi (t)) != NULL)
-           make_copy_constraint (first_vi_for_offset (fi, fi_uses),
-                                 vi->id);
-         return;
-       }
-
-      /* Otherwise the caller clobbers and uses what the callee does.
-        ???  This should use a new complex constraint that filters
-        local variables of the callee.  */
-      if (gimple_vdef (t))
-       {
-         lhs = get_function_part_constraint (fi, fi_clobbers);
-         rhs = get_function_part_constraint (cfi, fi_clobbers);
-         process_constraint (new_constraint (lhs, rhs));
-       }
-      lhs = get_function_part_constraint (fi, fi_uses);
-      rhs = get_function_part_constraint (cfi, fi_uses);
-      process_constraint (new_constraint (lhs, rhs));
-    }
-  else if (gimple_code (t) == GIMPLE_ASM)
-    {
-      /* ???  Ick.  We can do better.  */
-      if (gimple_vdef (t))
-       make_constraint_from (first_vi_for_offset (fi, fi_clobbers),
-                             anything_id);
-      make_constraint_from (first_vi_for_offset (fi, fi_uses),
-                           anything_id);
-    }
-
-  VEC_free (ce_s, heap, rhsc);
-}
-
-
-/* Find the first varinfo in the same variable as START that overlaps with
-   OFFSET.  Return NULL if we can't find one.  */
-
-static varinfo_t
-first_vi_for_offset (varinfo_t start, unsigned HOST_WIDE_INT offset)
-{
-  /* If the offset is outside of the variable, bail out.  */
-  if (offset >= start->fullsize)
-    return NULL;
-
-  /* If we cannot reach offset from start, lookup the first field
-     and start from there.  */
-  if (start->offset > offset)
-    start = lookup_vi_for_tree (start->decl);
+  /* If we cannot reach offset from start, lookup the first field
+     and start from there.  */
+  if (start->offset > offset)
+    start = lookup_vi_for_tree (start->decl);
 
   while (start)
     {
@@ -4839,6 +4075,47 @@ 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;
+}
+
+/* Insert the varinfo FIELD into the field list for BASE, ordered by
+   offset.  */
+
+static void
+insert_into_field_list_sorted (varinfo_t base, varinfo_t field)
+{
+  varinfo_t prev = base;
+  varinfo_t curr = base->next;
+
+  if (curr == NULL)
+    {
+      prev->next = field;
+      field->next = NULL;
+    }
+  else
+    {
+      while (curr)
+       {
+         if (field->offset <= curr->offset)
+           break;
+         prev = curr;
+         curr = curr->next;
+       }
+      field->next = prev->next;
+      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
@@ -4924,38 +4201,37 @@ 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 false if the caller is supposed to handle the field we
-   recursed for.  */
+   Returns the number of fields pushed.  */
 
-static bool
+static int
 push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
-                            HOST_WIDE_INT offset, bool must_have_pointers_p)
+                            HOST_WIDE_INT offset)
 {
   tree field;
-  bool empty_p = true;
+  int count = 0;
 
   if (TREE_CODE (type) != RECORD_TYPE)
-    return false;
+    return 0;
 
   /* 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 false;
+    return 0;
 
   for (field = TYPE_FIELDS (type); field; field = TREE_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 (!push_fields_onto_fieldstack
-                   (TREE_TYPE (field), fieldstack, offset + foff,
-                    must_have_pointers_p)
+       else if (!(pushed = 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
@@ -4978,12 +4254,12 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
            /* 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
-               && !must_have_pointers_p
-               && !could_have_pointers (field))
+               && 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
@@ -4995,19 +4271,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
-                 = must_have_pointers_p || could_have_pointers (field);
+               pair->may_have_pointers = could_have_pointers (field);
                pair->only_restrict_pointers
                  = (!has_unknown_size
                     && POINTER_TYPE_P (TREE_TYPE (field))
                     && TYPE_RESTRICT (TREE_TYPE (field)));
+               count++;
              }
          }
-
-       empty_p = false;
+       else
+         count += pushed;
       }
 
-  return !empty_p;
+  return count;
 }
 
 /* Count the number of arguments DECL has, and set IS_VARARGS to true
@@ -5037,122 +4313,38 @@ 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 varinfo_t
+static unsigned int
 create_function_info_for (tree decl, const char *name)
 {
-  struct function *fn = DECL_STRUCT_FUNCTION (decl);
-  varinfo_t vi, prev_vi;
+  varinfo_t vi;
   tree arg;
   unsigned int i;
   bool is_varargs = false;
-  unsigned int num_args = count_num_arguments (decl, &is_varargs);
 
   /* Create the variable info.  */
 
   vi = new_var_info (decl, name);
   vi->offset = 0;
   vi->size = 1;
-  vi->fullsize = fi_parm_base + num_args;
-  vi->is_fn_info = 1;
-  vi->may_have_pointers = false;
-  if (is_varargs)
-    vi->fullsize = ~0;
+  vi->fullsize = count_num_arguments (decl, &is_varargs) + 1;
   insert_vi_for_tree (vi->decl, vi);
 
-  prev_vi = vi;
-
-  /* Create a variable for things the function clobbers and one for
-     things the function uses.  */
-    {
-      varinfo_t clobbervi, usevi;
-      const char *newname;
-      char *tempname;
-
-      asprintf (&tempname, "%s.clobber", name);
-      newname = ggc_strdup (tempname);
-      free (tempname);
-
-      clobbervi = new_var_info (NULL, newname);
-      clobbervi->offset = fi_clobbers;
-      clobbervi->size = 1;
-      clobbervi->fullsize = vi->fullsize;
-      clobbervi->is_full_var = true;
-      clobbervi->is_global_var = false;
-      gcc_assert (prev_vi->offset < clobbervi->offset);
-      prev_vi->next = clobbervi;
-      prev_vi = clobbervi;
-
-      asprintf (&tempname, "%s.use", name);
-      newname = ggc_strdup (tempname);
-      free (tempname);
-
-      usevi = new_var_info (NULL, newname);
-      usevi->offset = fi_uses;
-      usevi->size = 1;
-      usevi->fullsize = vi->fullsize;
-      usevi->is_full_var = true;
-      usevi->is_global_var = false;
-      gcc_assert (prev_vi->offset < usevi->offset);
-      prev_vi->next = usevi;
-      prev_vi = usevi;
-    }
+  stats.total_vars++;
 
-  /* And one for the static chain.  */
-  if (fn->static_chain_decl != NULL_TREE)
+  /* If it's varargs, we don't know how many arguments it has, so we
+     can't do much.  */
+  if (is_varargs)
     {
-      varinfo_t chainvi;
-      const char *newname;
-      char *tempname;
-
-      asprintf (&tempname, "%s.chain", name);
-      newname = ggc_strdup (tempname);
-      free (tempname);
-
-      chainvi = new_var_info (fn->static_chain_decl, newname);
-      chainvi->offset = fi_static_chain;
-      chainvi->size = 1;
-      chainvi->fullsize = vi->fullsize;
-      chainvi->is_full_var = true;
-      chainvi->is_global_var = false;
-      gcc_assert (prev_vi->offset < chainvi->offset);
-      prev_vi->next = chainvi;
-      prev_vi = chainvi;
-      insert_vi_for_tree (fn->static_chain_decl, chainvi);
+      vi->fullsize = ~0;
+      vi->size = ~0;
+      vi->is_unknown_size_var = true;
+      return vi->id;
     }
 
-  /* Create a variable for the return var.  */
-  if (DECL_RESULT (decl) != NULL
-      || !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl))))
-    {
-      varinfo_t resultvi;
-      const char *newname;
-      char *tempname;
-      tree resultdecl = decl;
-
-      if (DECL_RESULT (decl))
-       resultdecl = DECL_RESULT (decl);
-
-      asprintf (&tempname, "%s.result", name);
-      newname = ggc_strdup (tempname);
-      free (tempname);
-
-      resultvi = new_var_info (resultdecl, newname);
-      resultvi->offset = fi_result;
-      resultvi->size = 1;
-      resultvi->fullsize = vi->fullsize;
-      resultvi->is_full_var = true;
-      if (DECL_RESULT (decl))
-       resultvi->may_have_pointers = could_have_pointers (DECL_RESULT (decl));
-      gcc_assert (prev_vi->offset < resultvi->offset);
-      prev_vi->next = resultvi;
-      prev_vi = resultvi;
-      if (DECL_RESULT (decl))
-       insert_vi_for_tree (DECL_RESULT (decl), resultvi);
-    }
+  arg = DECL_ARGUMENTS (decl);
 
   /* Set up variables for each argument.  */
-  arg = DECL_ARGUMENTS (decl);
-  for (i = 0; i < num_args; i++)
+  for (i = 1; i < vi->fullsize; i++)
     {
       varinfo_t argvi;
       const char *newname;
@@ -5162,20 +4354,17 @@ create_function_info_for (tree decl, const char *name)
       if (arg)
        argdecl = arg;
 
-      asprintf (&tempname, "%s.arg%d", name, i);
+      asprintf (&tempname, "%s.arg%d", name, i-1);
       newname = ggc_strdup (tempname);
       free (tempname);
 
       argvi = new_var_info (argdecl, newname);
-      argvi->offset = fi_parm_base + i;
+      argvi->offset = i;
       argvi->size = 1;
       argvi->is_full_var = true;
       argvi->fullsize = vi->fullsize;
-      if (arg)
-       argvi->may_have_pointers = could_have_pointers (arg);
-      gcc_assert (prev_vi->offset < argvi->offset);
-      prev_vi->next = argvi;
-      prev_vi = argvi;
+      insert_into_field_list_sorted (vi, argvi);
+      stats.total_vars ++;
       if (arg)
        {
          insert_vi_for_tree (arg, argvi);
@@ -5183,34 +4372,36 @@ create_function_info_for (tree decl, const char *name)
        }
     }
 
-  /* Add one representative for all further args.  */
-  if (is_varargs)
+  /* Create a variable for the return var.  */
+  if (DECL_RESULT (decl) != NULL
+      || !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl))))
     {
-      varinfo_t argvi;
+      varinfo_t resultvi;
       const char *newname;
       char *tempname;
-      tree decl;
+      tree resultdecl = decl;
+
+      vi->fullsize ++;
 
-      asprintf (&tempname, "%s.varargs", name);
+      if (DECL_RESULT (decl))
+       resultdecl = DECL_RESULT (decl);
+
+      asprintf (&tempname, "%s.result", name);
       newname = ggc_strdup (tempname);
       free (tempname);
 
-      /* We need sth that can be pointed to for va_start.  */
-      decl = create_tmp_var_raw (ptr_type_node, name);
-      get_var_ann (decl);
-
-      argvi = new_var_info (decl, newname);
-      argvi->offset = fi_parm_base + num_args;
-      argvi->size = ~0;
-      argvi->is_full_var = true;
-      argvi->is_heap_var = true;
-      argvi->fullsize = vi->fullsize;
-      gcc_assert (prev_vi->offset < argvi->offset);
-      prev_vi->next = argvi;
-      prev_vi = argvi;
+      resultvi = new_var_info (resultdecl, newname);
+      resultvi->offset = i;
+      resultvi->size = 1;
+      resultvi->fullsize = vi->fullsize;
+      resultvi->is_full_var = true;
+      insert_into_field_list_sorted (vi, resultvi);
+      stats.total_vars ++;
+      if (DECL_RESULT (decl))
+       insert_vi_for_tree (DECL_RESULT (decl), resultvi);
     }
 
-  return vi;
+  return vi->id;
 }
 
 
@@ -5237,54 +4428,67 @@ check_for_overlaps (VEC (fieldoff_s,heap) *fieldstack)
    This will also create any varinfo structures necessary for fields
    of DECL.  */
 
-static varinfo_t
-create_variable_info_for_1 (tree decl, const char *name)
+static unsigned int
+create_variable_info_for (tree decl, const char *name)
 {
-  varinfo_t vi, newvi;
+  varinfo_t vi;
   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 = 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 = could_have_pointers (decl);
-      return vi;
+      vi->fullsize = ~0;
+      vi->size = ~0;
+    }
+  else
+    {
+      vi->fullsize = TREE_INT_CST_LOW (declsize);
+      vi->size = vi->fullsize;
+    }
+
+  insert_vi_for_tree (vi->decl, vi);
+  if (vi->is_global_var
+      && (!flag_whole_program || !in_ipa_mode)
+      && vi->may_have_pointers)
+    {
+      if (POINTER_TYPE_P (TREE_TYPE (decl))
+         && TYPE_RESTRICT (TREE_TYPE (decl)))
+       make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
+      make_copy_constraint (vi, nonlocal_id);
     }
 
-  /* Collect field information.  */
+  stats.total_vars++;
   if (use_field_sensitive
+      && !vi->is_unknown_size_var
       && 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)))
+      && 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;
 
-      push_fields_onto_fieldstack (decl_type, &fieldstack, 0,
-                                  TREE_PUBLIC (decl)
-                                  || DECL_EXTERNAL (decl)
-                                  || TREE_ADDRESSABLE (decl));
-
       for (i = 0; !notokay && VEC_iterate (fieldoff_s, fieldstack, i, fo); i++)
-       if (fo->has_unknown_size
-           || fo->offset < 0)
-         {
-           notokay = true;
-           break;
-         }
+       {
+         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
@@ -5300,112 +4504,70 @@ create_variable_info_for_1 (tree decl, const char *name)
          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 = could_have_pointers (decl);
-      vi->fullsize = TREE_INT_CST_LOW (declsize);
-      vi->size = vi->fullsize;
-      vi->is_full_var = true;
-      VEC_free (fieldoff_s, heap, fieldstack);
-      return vi;
-    }
+      if (VEC_length (fieldoff_s, fieldstack) != 0)
+       fo = VEC_index (fieldoff_s, fieldstack, 0);
 
-  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)
+      if (fo == NULL || notokay)
        {
-         asprintf (&tempname, "%s." HOST_WIDE_INT_PRINT_DEC
-                   "+" HOST_WIDE_INT_PRINT_DEC, name, fo->offset, fo->size);
-         newname = ggc_strdup (tempname);
-         free (tempname);
+         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;
        }
-      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);
-    }
 
-  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)))
-         || vi->only_restrict_pointers)
-       make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
-
-      /* For escaped variables initialize them from nonlocal.  */
-      if (!in_ipa_mode
-         || DECL_EXTERNAL (decl) || TREE_PUBLIC (decl))
-       make_copy_constraint (vi, nonlocal_id);
-
-      /* If this is a global variable with an initializer and we are in
-        IPA mode generate constraints for it.  In non-IPA mode
-        the initializer from nonlocal is all we need.  */
-      if (in_ipa_mode
-         && DECL_INITIAL (decl))
+      vi->size = fo->size;
+      vi->offset = fo->offset;
+      vi->may_have_pointers = fo->may_have_pointers;
+      if (vi->is_global_var
+         && (!flag_whole_program || !in_ipa_mode)
+         && vi->may_have_pointers)
        {
-         VEC (ce_s, heap) *rhsc = NULL;
-         struct constraint_expr lhs, *rhsp;
-         unsigned i;
-         get_constraint_for (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)
-           process_constraint (new_constraint (lhs, *rhsp));
-         /* If this is a variable that escapes from the unit
-            the initializer escapes as well.  */
-         if (DECL_EXTERNAL (decl) || TREE_PUBLIC (decl))
+         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)
            {
-             lhs.var = escaped_id;
-             lhs.offset = 0;
-             lhs.type = SCALAR;
-             for (i = 0; VEC_iterate (ce_s, rhsc, i, rhsp); ++i)
-               process_constraint (new_constraint (lhs, *rhsp));
+             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);
            }
-         VEC_free (ce_s, heap, rhsc);
+         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 id;
+  return vi->id;
 }
 
 /* Print out the points-to solution for VAR to FILE.  */
@@ -5417,19 +4579,20 @@ dump_solution_for_var (FILE *file, unsigned int var)
   unsigned int i;
   bitmap_iterator bi;
 
-  /* Dump the solution for unified vars anyway, this avoids difficulties
-     in scanning dumps in the testsuite.  */
-  fprintf (file, "%s = { ", vi->name);
-  vi = get_varinfo (find (var));
-  EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
-    fprintf (file, "%s ", get_varinfo (i)->name);
-  fprintf (file, "}");
-
-  /* But note when the variable was unified.  */
-  if (vi->id != var)
-    fprintf (file, " same as %s", vi->name);
-
-  fprintf (file, "\n");
+  if (find (var) != var)
+    {
+      varinfo_t vipt = get_varinfo (find (var));
+      fprintf (file, "%s = same as %s\n", vi->name, vipt->name);
+    }
+  else
+    {
+      fprintf (file, "%s = { ", vi->name);
+      EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
+       {
+         fprintf (file, "%s ", get_varinfo (i)->name);
+       }
+      fprintf (file, "}\n");
+    }
 }
 
 /* Print the points-to solution for VAR to stdout.  */
@@ -5491,12 +4654,8 @@ 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->only_restrict_pointers)
-           make_constraint_from_restrict (p, "PARM_RESTRICT");
-       }
+       if (p->may_have_pointers)
+         make_constraint_from (p, nonlocal_id);
       if (POINTER_TYPE_P (TREE_TYPE (t))
          && TYPE_RESTRICT (TREE_TYPE (t)))
        make_constraint_from_restrict (get_vi_for_tree (t), "PARM_RESTRICT");
@@ -5613,15 +4772,9 @@ set_uids_in_ptset (bitmap into, bitmap from, struct pt_solution *pt)
          || TREE_CODE (vi->decl) == PARM_DECL
          || TREE_CODE (vi->decl) == RESULT_DECL)
        {
-         /* If we are in IPA mode we will not recompute points-to
-            sets after inlining so make sure they stay valid.  */
-         if (in_ipa_mode
-             && !DECL_PT_UID_SET_P (vi->decl))
-           SET_DECL_PT_UID (vi->decl, DECL_UID (vi->decl));
-
          /* Add the decl to the points-to set.  Note that the points-to
             set contains global variables.  */
-         bitmap_set_bit (into, DECL_PT_UID (vi->decl));
+         bitmap_set_bit (into, DECL_UID (vi->decl));
          if (vi->is_global_var)
            pt->vars_contains_global = true;
        }
@@ -5657,12 +4810,9 @@ find_what_var_points_to (varinfo_t orig_vi, struct pt_solution *pt)
          if (vi->id == nothing_id)
            pt->null = 1;
          else if (vi->id == escaped_id)
-           {
-             if (in_ipa_mode)
-               pt->ipa_escaped = 1;
-             else
-               pt->escaped = 1;
-           }
+           pt->escaped = 1;
+         else if (vi->id == callused_id)
+           gcc_unreachable ();
          else if (vi->id == nonlocal_id)
            pt->nonlocal = 1;
          else if (vi->is_heap_var)
@@ -5768,53 +4918,30 @@ pt_solution_reset (struct pt_solution *pt)
 }
 
 /* Set the points-to solution *PT to point only to the variables
-   in VARS.  VARS_CONTAINS_GLOBAL specifies whether that contains
-   global variables and VARS_CONTAINS_RESTRICT specifies whether
-   it contains restrict tag variables.  */
+   in VARS.  */
 
 void
-pt_solution_set (struct pt_solution *pt, bitmap vars,
-                bool vars_contains_global, bool vars_contains_restrict)
+pt_solution_set (struct pt_solution *pt, bitmap vars)
 {
+  bitmap_iterator bi;
+  unsigned i;
+
   memset (pt, 0, sizeof (struct pt_solution));
   pt->vars = vars;
-  pt->vars_contains_global = vars_contains_global;
-  pt->vars_contains_restrict = vars_contains_restrict;
-}
-
-/* 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.
-   The points-to bitmap of *SRC and *DEST will not be shared after
-   this function if they were not before.  */
-
-static void
-pt_solution_ior_into (struct pt_solution *dest, struct pt_solution *src)
-{
-  dest->anything |= src->anything;
-  if (dest->anything)
+  EXECUTE_IF_SET_IN_BITMAP (vars, 0, i, bi)
     {
-      pt_solution_reset (dest);
-      return;
+      tree var = referenced_var_lookup (i);
+      if (is_global_var (var))
+       {
+         pt->vars_contains_global = true;
+         break;
+       }
     }
-
-  dest->nonlocal |= src->nonlocal;
-  dest->escaped |= src->escaped;
-  dest->ipa_escaped |= src->ipa_escaped;
-  dest->null |= src->null;
-  dest->vars_contains_global |= src->vars_contains_global;
-  dest->vars_contains_restrict |= src->vars_contains_restrict;
-  if (!src->vars)
-    return;
-
-  if (!dest->vars)
-    dest->vars = BITMAP_GGC_ALLOC ();
-  bitmap_ior_into (dest->vars, src->vars);
 }
 
 /* Return true if the points-to solution *PT is empty.  */
 
-bool
+static bool
 pt_solution_empty_p (struct pt_solution *pt)
 {
   if (pt->anything
@@ -5830,11 +4957,6 @@ pt_solution_empty_p (struct pt_solution *pt)
       && !pt_solution_empty_p (&cfun->gimple_df->escaped))
     return false;
 
-  /* If the solution includes ESCAPED, check if that is empty.  */
-  if (pt->ipa_escaped
-      && !pt_solution_empty_p (&ipa_escaped_pt))
-    return false;
-
   return true;
 }
 
@@ -5851,15 +4973,6 @@ pt_solution_includes_global (struct pt_solution *pt)
   if (pt->escaped)
     return pt_solution_includes_global (&cfun->gimple_df->escaped);
 
-  if (pt->ipa_escaped)
-    return pt_solution_includes_global (&ipa_escaped_pt);
-
-  /* ???  This predicate is not correct for the IPA-PTA solution
-     as we do not properly distinguish between unit escape points
-     and global variables.  */
-  if (cfun->gimple_df->ipa_pta)
-    return true;
-
   return false;
 }
 
@@ -5877,7 +4990,7 @@ pt_solution_includes_1 (struct pt_solution *pt, const_tree decl)
     return true;
 
   if (pt->vars
-      && bitmap_bit_p (pt->vars, DECL_PT_UID (decl)))
+      && bitmap_bit_p (pt->vars, DECL_UID (decl)))
     return true;
 
   /* If the solution includes ESCAPED, check it.  */
@@ -5885,11 +4998,6 @@ pt_solution_includes_1 (struct pt_solution *pt, const_tree decl)
       && pt_solution_includes_1 (&cfun->gimple_df->escaped, decl))
     return true;
 
-  /* If the solution includes ESCAPED, check it.  */
-  if (pt->ipa_escaped
-      && pt_solution_includes_1 (&ipa_escaped_pt, decl))
-    return true;
-
   return false;
 }
 
@@ -5940,25 +5048,6 @@ pt_solutions_intersect_1 (struct pt_solution *pt1, struct pt_solution *pt2)
        return true;
     }
 
-  /* Check the escaped solution if required.
-     ???  Do we need to check the local against the IPA escaped sets?  */
-  if ((pt1->ipa_escaped || pt2->ipa_escaped)
-      && !pt_solution_empty_p (&ipa_escaped_pt))
-    {
-      /* If both point to escaped memory and that solution
-        is not empty they alias.  */
-      if (pt1->ipa_escaped && pt2->ipa_escaped)
-       return true;
-
-      /* If either points to escaped memory see if the escaped solution
-        intersects with the other.  */
-      if ((pt1->ipa_escaped
-          && pt_solutions_intersect_1 (&ipa_escaped_pt, pt2))
-         || (pt2->ipa_escaped
-             && pt_solutions_intersect_1 (&ipa_escaped_pt, pt1)))
-       return true;
-    }
-
   /* Now both pointers alias if their points-to solution intersects.  */
   return (pt1->vars
          && pt2->vars
@@ -6024,12 +5113,7 @@ dump_sa_points_to_info (FILE *outfile)
     }
 
   for (i = 0; i < VEC_length (varinfo_t, varmap); i++)
-    {
-      varinfo_t vi = get_varinfo (i);
-      if (!vi->may_have_pointers)
-       continue;
-      dump_solution_for_var (outfile, i);
-    }
+    dump_solution_for_var (outfile, i);
 }
 
 
@@ -6054,6 +5138,7 @@ init_base_vars (void)
   varinfo_t var_readonly;
   varinfo_t var_escaped;
   varinfo_t var_nonlocal;
+  varinfo_t var_callused;
   varinfo_t var_storedanything;
   varinfo_t var_integer;
 
@@ -6066,8 +5151,6 @@ init_base_vars (void)
   var_nothing->size = ~0;
   var_nothing->fullsize = ~0;
   var_nothing->is_special_var = 1;
-  var_nothing->may_have_pointers = 0;
-  var_nothing->is_global_var = 0;
 
   /* Create the ANYTHING variable, used to represent that a variable
      points to some unknown piece of memory.  */
@@ -6182,6 +5265,35 @@ init_base_vars (void)
   rhs.offset = 0;
   process_constraint (new_constraint (lhs, rhs));
 
+  /* Create the CALLUSED variable, used to represent the set of call-used
+     memory.  */
+  var_callused = new_var_info (NULL_TREE, "CALLUSED");
+  gcc_assert (var_callused->id == callused_id);
+  var_callused->is_artificial_var = 1;
+  var_callused->offset = 0;
+  var_callused->size = ~0;
+  var_callused->fullsize = ~0;
+  var_callused->is_special_var = 0;
+
+  /* CALLUSED = *CALLUSED, because call-used is may-deref'd at calls, etc.  */
+  lhs.type = SCALAR;
+  lhs.var = callused_id;
+  lhs.offset = 0;
+  rhs.type = DEREF;
+  rhs.var = callused_id;
+  rhs.offset = 0;
+  process_constraint (new_constraint (lhs, rhs));
+
+  /* CALLUSED = CALLUSED + UNKNOWN, because if a sub-field is call-used the
+     whole variable is call-used.  */
+  lhs.type = SCALAR;
+  lhs.var = callused_id;
+  lhs.offset = 0;
+  rhs.type = SCALAR;
+  rhs.var = callused_id;
+  rhs.offset = UNKNOWN_OFFSET;
+  process_constraint (new_constraint (lhs, rhs));
+
   /* Create the STOREDANYTHING variable, used to represent the set of
      variables stored to *ANYTHING.  */
   var_storedanything = new_var_info (NULL_TREE, "STOREDANYTHING");
@@ -6232,7 +5344,6 @@ init_alias_vars (void)
   constraints = VEC_alloc (constraint_t, heap, 8);
   varmap = VEC_alloc (varinfo_t, heap, 8);
   vi_for_tree = pointer_map_create ();
-  call_stmt_vars = pointer_map_create ();
 
   memset (&stats, 0, sizeof (stats));
   shared_bitmap_table = htab_create (511, shared_bitmap_hash,
@@ -6304,6 +5415,12 @@ solve_constraints (void)
   struct scc_info *si;
 
   if (dump_file)
+    {
+      fprintf (dump_file, "Points-to analysis\n\nConstraints:\n\n");
+      dump_constraints (dump_file);
+    }
+
+  if (dump_file)
     fprintf (dump_file,
             "\nCollapsing static cycles and doing variable "
             "substitution\n");
@@ -6363,6 +5480,7 @@ compute_points_to_sets (void)
   basic_block bb;
   unsigned i;
   varinfo_t vi;
+  struct pt_solution callused;
 
   timevar_push (TV_TREE_PTA);
 
@@ -6371,7 +5489,7 @@ compute_points_to_sets (void)
 
   intra_create_variable_infos ();
 
-  /* Now walk all statements and build the constraint set.  */
+  /* Now walk all statements and derive aliases.  */
   FOR_EACH_BB (bb)
     {
       gimple_stmt_iterator gsi;
@@ -6392,18 +5510,14 @@ compute_points_to_sets (void)
        }
     }
 
-  if (dump_file)
-    {
-      fprintf (dump_file, "Points-to analysis\n\nConstraints:\n\n");
-      dump_constraints (dump_file, 0);
-    }
-
   /* From the constraints compute the points-to sets.  */
   solve_constraints ();
 
-  /* Compute the points-to set for ESCAPED used for call-clobber analysis.  */
+  /* Compute the points-to sets for ESCAPED and CALLUSED used for
+     call-clobber analysis.  */
   find_what_var_points_to (get_varinfo (escaped_id),
                           &cfun->gimple_df->escaped);
+  find_what_var_points_to (get_varinfo (callused_id), &callused);
 
   /* Make sure the ESCAPED solution (which is used as placeholder in
      other solutions) does not reference itself.  This simplifies
@@ -6442,11 +5556,11 @@ compute_points_to_sets (void)
          pt = gimple_call_use_set (stmt);
          if (gimple_call_flags (stmt) & ECF_CONST)
            memset (pt, 0, sizeof (struct pt_solution));
-         else if ((vi = lookup_call_use_vi (stmt)) != NULL)
+         else if (gimple_call_flags (stmt) & ECF_PURE)
            {
-             find_what_var_points_to (vi, pt);
-             /* Escaped (and thus nonlocal) variables are always
-                implicitly used by calls.  */
+             /* For const calls we should now be able to compute the
+                call-used set per function.  */
+             *pt = callused;
              /* ???  ESCAPED can be empty even though NONLOCAL
                 always escaped.  */
              pt->nonlocal = 1;
@@ -6454,8 +5568,6 @@ compute_points_to_sets (void)
            }
          else
            {
-             /* If there is nothing special about this call then
-                we have made everything that is used also escape.  */
              *pt = cfun->gimple_df->escaped;
              pt->nonlocal = 1;
            }
@@ -6463,20 +5575,8 @@ compute_points_to_sets (void)
          pt = gimple_call_clobber_set (stmt);
          if (gimple_call_flags (stmt) & (ECF_CONST|ECF_PURE|ECF_NOVOPS))
            memset (pt, 0, sizeof (struct pt_solution));
-         else if ((vi = lookup_call_clobber_vi (stmt)) != NULL)
-           {
-             find_what_var_points_to (vi, pt);
-             /* Escaped (and thus nonlocal) variables are always
-                implicitly clobbered by calls.  */
-             /* ???  ESCAPED can be empty even though NONLOCAL
-                always escaped.  */
-             pt->nonlocal = 1;
-             pt->escaped = 1;
-           }
          else
            {
-             /* If there is nothing special about this call then
-                we have made everything that is used also escape.  */
              *pt = cfun->gimple_df->escaped;
              pt->nonlocal = 1;
            }
@@ -6500,7 +5600,6 @@ delete_points_to_sets (void)
             stats.points_to_sets_created);
 
   pointer_map_destroy (vi_for_tree);
-  pointer_map_destroy (call_stmt_vars);
   bitmap_obstack_release (&pta_obstack);
   VEC_free (constraint_t, heap, constraints);
 
@@ -6528,23 +5627,6 @@ delete_points_to_sets (void)
 unsigned int
 compute_may_aliases (void)
 {
-  if (cfun->gimple_df->ipa_pta)
-    {
-      if (dump_file)
-       {
-         fprintf (dump_file, "\nNot re-computing points-to information "
-                  "because IPA points-to information is available.\n\n");
-
-         /* But still dump what we have remaining it.  */
-         dump_alias_info (dump_file);
-
-         if (dump_flags & TDF_DETAILS)
-           dump_referenced_vars (dump_file);
-       }
-
-      return 0;
-    }
-
   /* For each pointer P_i, determine the sets of variables that P_i may
      point-to.  Compute the reachability set of escaped and call-used
      variables.  */
@@ -6629,17 +5711,11 @@ gate_ipa_pta (void)
          && !(errorcount || sorrycount));
 }
 
-/* IPA PTA solutions for ESCAPED.  */
-struct pt_solution ipa_escaped_pt
-  = { true, false, false, false, false, false, false, NULL };
-
 /* Execute the driver for IPA PTA.  */
 static unsigned int
 ipa_pta_execute (void)
 {
   struct cgraph_node *node;
-  struct varpool_node *var;
-  int from;
 
   in_ipa_mode = 1;
 
@@ -6649,9 +5725,6 @@ 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.  */
@@ -6659,35 +5732,15 @@ ipa_pta_execute (void)
          || node->clone_of)
        continue;
 
-      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)
-    {
-      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);
-    }
+      /* It does not make sense to have graph edges into or out of
+         externally visible functions.  There is no extra information
+        we can gather from them.  */
+      if (node->local.externally_visible)
+       continue;
 
-  if (dump_file)
-    {
-      fprintf (dump_file,
-              "Generating constraints for global initializers\n\n");
-      dump_constraints (dump_file, 0);
-      fprintf (dump_file, "\n");
+      create_function_info_for (node->decl,
+                               cgraph_node_name (node));
     }
-  from = VEC_length (constraint_t, constraints);
 
   for (node = cgraph_nodes; node; node = node->next)
     {
@@ -6701,14 +5754,9 @@ ipa_pta_execute (void)
        continue;
 
       if (dump_file)
-       {
-         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");
-       }
+       fprintf (dump_file,
+                "Generating constraints for %s\n",
+                cgraph_node_name (node));
 
       func = DECL_STRUCT_FUNCTION (node->decl);
       old_func_decl = current_function_decl;
@@ -6740,204 +5788,16 @@ ipa_pta_execute (void)
              gimple stmt = gsi_stmt (gsi);
 
              find_func_aliases (stmt);
-             find_func_clobbers (stmt);
            }
        }
 
       current_function_decl = old_func_decl;
       pop_cfun ();
-
-      if (dump_file)
-       {
-         fprintf (dump_file, "\n");
-         dump_constraints (dump_file, from);
-         fprintf (dump_file, "\n");
-       }
-      from = VEC_length (constraint_t, constraints);
     }
 
   /* From the constraints compute the points-to sets.  */
   solve_constraints ();
 
-  /* Compute the global points-to sets for ESCAPED.
-     ???  Note that the computed escape set is not correct
-     for the whole unit as we fail to consider graph edges to
-     externally visible functions.  */
-  find_what_var_points_to (get_varinfo (escaped_id), &ipa_escaped_pt);
-
-  /* Make sure the ESCAPED solution (which is used as placeholder in
-     other solutions) does not reference itself.  This simplifies
-     points-to solution queries.  */
-  ipa_escaped_pt.ipa_escaped = 0;
-
-  /* Assign the points-to sets to the SSA names in the unit.  */
-  for (node = cgraph_nodes; node; node = node->next)
-    {
-      tree ptr;
-      struct function *fn;
-      unsigned i;
-      varinfo_t fi;
-      basic_block bb;
-      struct pt_solution uses, clobbers;
-      struct cgraph_edge *e;
-
-      /* Nodes without a body are not interesting.  */
-      if (!gimple_has_body_p (node->decl)
-         || node->clone_of)
-       continue;
-
-      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)
-       {
-         if (ptr
-             && POINTER_TYPE_P (TREE_TYPE (ptr)))
-           find_what_p_points_to (ptr);
-       }
-
-      /* Compute the call-use and call-clobber sets for all direct calls.  */
-      fi = lookup_vi_for_tree (node->decl);
-      gcc_assert (fi->is_fn_info);
-      find_what_var_points_to (first_vi_for_offset (fi, fi_clobbers),
-                              &clobbers);
-      find_what_var_points_to (first_vi_for_offset (fi, fi_uses), &uses);
-      for (e = node->callers; e; e = e->next_caller)
-       {
-         if (!e->call_stmt)
-           continue;
-
-         *gimple_call_clobber_set (e->call_stmt) = clobbers;
-         *gimple_call_use_set (e->call_stmt) = uses;
-       }
-
-      /* Compute the call-use and call-clobber sets for indirect calls
-        and calls to external functions.  */
-      FOR_EACH_BB_FN (bb, fn)
-       {
-         gimple_stmt_iterator gsi;
-
-         for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
-           {
-             gimple stmt = gsi_stmt (gsi);
-             struct pt_solution *pt;
-             varinfo_t vi;
-             tree decl;
-
-             if (!is_gimple_call (stmt))
-               continue;
-
-             /* Handle direct calls to external functions.  */
-             decl = gimple_call_fndecl (stmt);
-             if (decl
-                 && (!(fi = lookup_vi_for_tree (decl))
-                     || !fi->is_fn_info))
-               {
-                 pt = gimple_call_use_set (stmt);
-                 if (gimple_call_flags (stmt) & ECF_CONST)
-                   memset (pt, 0, sizeof (struct pt_solution));
-                 else if ((vi = lookup_call_use_vi (stmt)) != NULL)
-                   {
-                     find_what_var_points_to (vi, pt);
-                     /* Escaped (and thus nonlocal) variables are always
-                        implicitly used by calls.  */
-                     /* ???  ESCAPED can be empty even though NONLOCAL
-                        always escaped.  */
-                     pt->nonlocal = 1;
-                     pt->ipa_escaped = 1;
-                   }
-                 else
-                   {
-                     /* If there is nothing special about this call then
-                        we have made everything that is used also escape.  */
-                     *pt = ipa_escaped_pt;
-                     pt->nonlocal = 1;
-                   }
-
-                 pt = gimple_call_clobber_set (stmt);
-                 if (gimple_call_flags (stmt) & (ECF_CONST|ECF_PURE|ECF_NOVOPS))
-                   memset (pt, 0, sizeof (struct pt_solution));
-                 else if ((vi = lookup_call_clobber_vi (stmt)) != NULL)
-                   {
-                     find_what_var_points_to (vi, pt);
-                     /* Escaped (and thus nonlocal) variables are always
-                        implicitly clobbered by calls.  */
-                     /* ???  ESCAPED can be empty even though NONLOCAL
-                        always escaped.  */
-                     pt->nonlocal = 1;
-                     pt->ipa_escaped = 1;
-                   }
-                 else
-                   {
-                     /* If there is nothing special about this call then
-                        we have made everything that is used also escape.  */
-                     *pt = ipa_escaped_pt;
-                     pt->nonlocal = 1;
-                   }
-               }
-
-             /* Handle indirect calls.  */
-             if (!decl
-                 && (fi = get_fi_for_callee (stmt)))
-               {
-                 /* We need to accumulate all clobbers/uses of all possible
-                    callees.  */
-                 fi = get_varinfo (find (fi->id));
-                 /* If we cannot constrain the set of functions we'll end up
-                    calling we end up using/clobbering everything.  */
-                 if (bitmap_bit_p (fi->solution, anything_id)
-                     || bitmap_bit_p (fi->solution, nonlocal_id)
-                     || bitmap_bit_p (fi->solution, escaped_id))
-                   {
-                     pt_solution_reset (gimple_call_clobber_set (stmt));
-                     pt_solution_reset (gimple_call_use_set (stmt));
-                   }
-                 else
-                   {
-                     bitmap_iterator bi;
-                     unsigned i;
-                     struct pt_solution *uses, *clobbers;
-
-                     uses = gimple_call_use_set (stmt);
-                     clobbers = gimple_call_clobber_set (stmt);
-                     memset (uses, 0, sizeof (struct pt_solution));
-                     memset (clobbers, 0, sizeof (struct pt_solution));
-                     EXECUTE_IF_SET_IN_BITMAP (fi->solution, 0, i, bi)
-                       {
-                         struct pt_solution sol;
-
-                         vi = get_varinfo (i);
-                         if (!vi->is_fn_info)
-                           {
-                             /* ???  We could be more precise here?  */
-                             uses->nonlocal = 1;
-                             uses->ipa_escaped = 1;
-                             clobbers->nonlocal = 1;
-                             clobbers->ipa_escaped = 1;
-                             continue;
-                           }
-
-                         if (!uses->anything)
-                           {
-                             find_what_var_points_to
-                                 (first_vi_for_offset (vi, fi_uses), &sol);
-                             pt_solution_ior_into (uses, &sol);
-                           }
-                         if (!clobbers->anything)
-                           {
-                             find_what_var_points_to
-                                 (first_vi_for_offset (vi, fi_clobbers), &sol);
-                             pt_solution_ior_into (clobbers, &sol);
-                           }
-                       }
-                   }
-               }
-           }
-       }
-
-      fn->gimple_df->ipa_pta = true;
-    }
-
   delete_points_to_sets ();
 
   in_ipa_mode = 0;