OSDN Git Service

2010-04-20 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-structalias.c
index 6421c65..492907e 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"
@@ -272,9 +275,6 @@ 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;
 
@@ -412,7 +412,6 @@ 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))
@@ -421,8 +420,6 @@ new_var_info (tree t, const char *name)
   ret->oldsolution = BITMAP_ALLOC (&oldpta_obstack);
   ret->next = NULL;
 
-  stats.total_vars++;
-
   VEC_safe_push (varinfo_t, heap, varmap, ret);
 
   return ret;
@@ -1749,7 +1746,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);
@@ -1796,6 +1792,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)
@@ -1808,25 +1820,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)
@@ -2757,14 +2750,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;
 
@@ -2942,12 +2931,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);
 }
 
@@ -2957,11 +2940,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
@@ -3292,18 +3271,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);
@@ -3365,26 +3340,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;
@@ -3597,11 +3552,11 @@ make_transitive_closure_constraints (varinfo_t vi)
   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);
@@ -3633,16 +3588,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;
@@ -3692,10 +3637,7 @@ get_function_part_constraint (varinfo_t fi, unsigned part)
   else if (TREE_CODE (fi->decl) == FUNCTION_DECL)
     {
       varinfo_t ai = first_vi_for_offset (fi, part);
-      if (ai)
-       c.var = ai->id;
-      else
-       c.var = anything_id;
+      c.var = ai ? ai->id : anything_id;
       c.offset = 0;
       c.type = SCALAR;
     }
@@ -3717,61 +3659,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));
@@ -3804,63 +3702,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);
 }
 
@@ -4273,7 +4152,7 @@ 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
@@ -4307,7 +4186,7 @@ find_func_aliases (gimple origt)
          /* 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)))
+             && could_have_pointers (lhsop))
            {
              struct constraint_expr rhs;
              struct constraint_expr *lhsp;
@@ -4361,7 +4240,7 @@ find_func_aliases (gimple origt)
      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);
@@ -4840,6 +4719,19 @@ first_or_preceding_vi_for_offset (varinfo_t start,
 }
 
 
+/* Insert the varinfo FIELD into the field list for BASE, at the front
+   of the list.  */
+
+static void
+insert_into_field_list (varinfo_t base, varinfo_t field)
+{
+  varinfo_t prev = base;
+  varinfo_t curr = base->next;
+
+  field->next = curr;
+  prev->next = field;
+}
+
 /* This structure is used during pushing fields onto the fieldstack
    to track the offset of the field, since bitpos_of_field gives it
    relative to its immediate containing type, and we want it relative
@@ -4925,38 +4817,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
@@ -4979,12 +4870,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
@@ -4996,19 +4887,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
@@ -5038,7 +4929,7 @@ count_num_arguments (tree decl, bool *is_varargs)
 /* Creation function node for DECL, using NAME, and return the index
    of the variable we've created for the function.  */
 
-static varinfo_t
+static unsigned int
 create_function_info_for (tree decl, const char *name)
 {
   struct function *fn = DECL_STRUCT_FUNCTION (decl);
@@ -5060,6 +4951,8 @@ create_function_info_for (tree decl, const char *name)
     vi->fullsize = ~0;
   insert_vi_for_tree (vi->decl, vi);
 
+  stats.total_vars++;
+
   prev_vi = vi;
 
   /* Create a variable for things the function clobbers and one for
@@ -5082,6 +4975,7 @@ create_function_info_for (tree decl, const char *name)
       gcc_assert (prev_vi->offset < clobbervi->offset);
       prev_vi->next = clobbervi;
       prev_vi = clobbervi;
+      stats.total_vars++;
 
       asprintf (&tempname, "%s.use", name);
       newname = ggc_strdup (tempname);
@@ -5096,6 +4990,7 @@ create_function_info_for (tree decl, const char *name)
       gcc_assert (prev_vi->offset < usevi->offset);
       prev_vi->next = usevi;
       prev_vi = usevi;
+      stats.total_vars++;
     }
 
   /* And one for the static chain.  */
@@ -5118,6 +5013,7 @@ create_function_info_for (tree decl, const char *name)
       gcc_assert (prev_vi->offset < chainvi->offset);
       prev_vi->next = chainvi;
       prev_vi = chainvi;
+      stats.total_vars++;
       insert_vi_for_tree (fn->static_chain_decl, chainvi);
     }
 
@@ -5147,6 +5043,7 @@ create_function_info_for (tree decl, const char *name)
       gcc_assert (prev_vi->offset < resultvi->offset);
       prev_vi->next = resultvi;
       prev_vi = resultvi;
+      stats.total_vars++;
       if (DECL_RESULT (decl))
        insert_vi_for_tree (DECL_RESULT (decl), resultvi);
     }
@@ -5177,6 +5074,7 @@ create_function_info_for (tree decl, const char *name)
       gcc_assert (prev_vi->offset < argvi->offset);
       prev_vi->next = argvi;
       prev_vi = argvi;
+      stats.total_vars++;
       if (arg)
        {
          insert_vi_for_tree (arg, argvi);
@@ -5209,9 +5107,10 @@ create_function_info_for (tree decl, const char *name)
       gcc_assert (prev_vi->offset < argvi->offset);
       prev_vi->next = argvi;
       prev_vi = argvi;
+      stats.total_vars++;
     }
 
-  return vi;
+  return vi->id;
 }
 
 
@@ -5238,138 +5137,48 @@ 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;
-    }
-
-  /* Collect field information.  */
-  if (use_field_sensitive
-      && var_can_have_subvars (decl)
-      /* ???  Force us to not use subfields for global initializers
-        in IPA mode.  Else we'd have to parse arbitrary initializers.  */
-      && !(in_ipa_mode
-          && is_global_var (decl)
-          && DECL_INITIAL (decl)))
-    {
-      fieldoff_s *fo = NULL;
-      bool notokay = false;
-      unsigned int i;
-
-      push_fields_onto_fieldstack (decl_type, &fieldstack, 0,
-                                  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;
-         }
-
-      /* We can't sort them if we have a field with a variable sized type,
-        which will make notokay = true.  In that case, we are going to return
-        without creating varinfos for the fields anyway, so sorting them is a
-        waste to boot.  */
-      if (!notokay)
-       {
-         sort_fieldstack (fieldstack);
-         /* Due to some C++ FE issues, like PR 22488, we might end up
-            what appear to be overlapping fields even though they,
-            in reality, do not overlap.  Until the C++ FE is fixed,
-            we will simply disable field-sensitivity for these cases.  */
-         notokay = check_for_overlaps (fieldstack);
-       }
-
-      if (notokay)
-       VEC_free (fieldoff_s, heap, fieldstack);
+      vi->fullsize = ~0;
+      vi->size = ~0;
     }
-
-  /* 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)
+  else
     {
-      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;
-    }
-
-  vi = new_var_info (decl, name);
-  vi->fullsize = TREE_INT_CST_LOW (declsize);
-  for (i = 0, newvi = vi;
-       VEC_iterate (fieldoff_s, fieldstack, i, fo);
-       ++i, newvi = newvi->next)
-    {
-      const char *newname = "NULL";
-      char *tempname;
-
-      if (dump_file)
-       {
-         asprintf (&tempname, "%s." HOST_WIDE_INT_PRINT_DEC
-                   "+" HOST_WIDE_INT_PRINT_DEC, name, fo->offset, fo->size);
-         newname = ggc_strdup (tempname);
-         free (tempname);
-       }
-      newvi->name = newname;
-      newvi->offset = fo->offset;
-      newvi->size = fo->size;
-      newvi->fullsize = vi->fullsize;
-      newvi->may_have_pointers = fo->may_have_pointers;
-      newvi->only_restrict_pointers = fo->only_restrict_pointers;
-      if (i + 1 < VEC_length (fieldoff_s, fieldstack))
-       newvi->next = new_var_info (decl, name);
     }
 
-  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);
+  insert_vi_for_tree (vi->decl, vi);
 
-  /* Create initial constraints for globals.  */
-  for (; vi; vi = vi->next)
+  /* ???  The setting of vi->may_have_pointers is too conservative here
+     and may get refined below.  Thus we have superfluous constraints
+     here sometimes which triggers the commented assert in
+     dump_sa_points_to_info.  */
+  if (vi->is_global_var
+      && vi->may_have_pointers)
     {
-      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)
+      if (POINTER_TYPE_P (TREE_TYPE (decl))
+         && TYPE_RESTRICT (TREE_TYPE (decl)))
        make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
 
       /* For escaped variables initialize them from nonlocal.  */
@@ -5381,12 +5190,12 @@ create_variable_info_for (tree decl, const char *name)
         IPA mode generate constraints for it.  In non-IPA mode
         the initializer from nonlocal is all we need.  */
       if (in_ipa_mode
-         && DECL_INITIAL (decl))
+         && DECL_INITIAL (vi->decl))
        {
          VEC (ce_s, heap) *rhsc = NULL;
          struct constraint_expr lhs, *rhsp;
          unsigned i;
-         get_constraint_for (DECL_INITIAL (decl), &rhsc);
+         get_constraint_for (DECL_INITIAL (vi->decl), &rhsc);
          lhs.var = vi->id;
          lhs.offset = 0;
          lhs.type = SCALAR;
@@ -5403,10 +5212,110 @@ create_variable_info_for (tree decl, const char *name)
                process_constraint (new_constraint (lhs, *rhsp));
            }
          VEC_free (ce_s, heap, rhsc);
+         /* ???  Force us to not use subfields.  Else we'd have to parse
+            arbitrary initializers.  */
+         VEC_free (fieldoff_s, heap, fieldstack);
        }
     }
 
-  return id;
+  stats.total_vars++;
+  if (use_field_sensitive
+      && !vi->is_unknown_size_var
+      && var_can_have_subvars (decl)
+      && VEC_length (fieldoff_s, fieldstack) > 1
+      && VEC_length (fieldoff_s, fieldstack) <= MAX_FIELDS_FOR_FIELD_SENSITIVE)
+    {
+      fieldoff_s *fo = NULL;
+      bool notokay = false;
+      unsigned int i;
+
+      for (i = 0; !notokay && VEC_iterate (fieldoff_s, fieldstack, i, fo); i++)
+       {
+         if (fo->has_unknown_size
+             || fo->offset < 0)
+           {
+             notokay = true;
+             break;
+           }
+       }
+
+      /* We can't sort them if we have a field with a variable sized type,
+        which will make notokay = true.  In that case, we are going to return
+        without creating varinfos for the fields anyway, so sorting them is a
+        waste to boot.  */
+      if (!notokay)
+       {
+         sort_fieldstack (fieldstack);
+         /* Due to some C++ FE issues, like PR 22488, we might end up
+            what appear to be overlapping fields even though they,
+            in reality, do not overlap.  Until the C++ FE is fixed,
+            we will simply disable field-sensitivity for these cases.  */
+         notokay = check_for_overlaps (fieldstack);
+       }
+
+
+      if (VEC_length (fieldoff_s, fieldstack) != 0)
+       fo = VEC_index (fieldoff_s, fieldstack, 0);
+
+      if (fo == NULL || notokay)
+       {
+         vi->is_unknown_size_var = 1;
+         vi->fullsize = ~0;
+         vi->size = ~0;
+         vi->is_full_var = true;
+         VEC_free (fieldoff_s, heap, fieldstack);
+         return vi->id;
+       }
+
+      vi->size = fo->size;
+      vi->offset = fo->offset;
+      vi->may_have_pointers = fo->may_have_pointers;
+      if (vi->is_global_var
+         && vi->may_have_pointers)
+       {
+         if (fo->only_restrict_pointers)
+           make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
+       }
+      for (i = VEC_length (fieldoff_s, fieldstack) - 1;
+          i >= 1 && VEC_iterate (fieldoff_s, fieldstack, i, fo);
+          i--)
+       {
+         varinfo_t newvi;
+         const char *newname = "NULL";
+         char *tempname;
+
+         if (dump_file)
+           {
+             asprintf (&tempname, "%s." HOST_WIDE_INT_PRINT_DEC
+                       "+" HOST_WIDE_INT_PRINT_DEC,
+                       vi->name, fo->offset, fo->size);
+             newname = ggc_strdup (tempname);
+             free (tempname);
+           }
+         newvi = new_var_info (decl, newname);
+         newvi->offset = fo->offset;
+         newvi->size = fo->size;
+         newvi->fullsize = vi->fullsize;
+         newvi->may_have_pointers = fo->may_have_pointers;
+         insert_into_field_list (vi, newvi);
+         if ((newvi->is_global_var || TREE_CODE (decl) == PARM_DECL)
+             && newvi->may_have_pointers)
+           {
+              if (fo->only_restrict_pointers)
+                make_constraint_from_restrict (newvi, "GLOBAL_RESTRICT");
+              if (newvi->is_global_var && !in_ipa_mode)
+                make_copy_constraint (newvi, nonlocal_id);
+           }
+
+         stats.total_vars++;
+       }
+    }
+  else
+    vi->is_full_var = true;
+
+  VEC_free (fieldoff_s, heap, fieldstack);
+
+  return vi->id;
 }
 
 /* Print out the points-to solution for VAR to FILE.  */
@@ -5492,12 +5401,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");
@@ -6650,9 +6555,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.  */
@@ -6660,26 +6562,13 @@ 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_function_info_for (node->decl,
+                               cgraph_node_name (node));
     }
 
   /* 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);
-    }
+    get_vi_for_tree (var->decl);
 
   if (dump_file)
     {
@@ -6702,14 +6591,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;