OSDN Git Service

* i386.md (UNSPEC_SSE_PROLOGUE_SAVE_LOW): New.
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-structalias.c
index 928dc04..ad4c10d 100644 (file)
@@ -275,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;
 
@@ -415,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))
@@ -424,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;
@@ -1712,8 +1706,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
@@ -1752,7 +1745,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);
@@ -1799,6 +1791,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)
@@ -1811,25 +1819,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)
@@ -2896,16 +2885,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)
     {
@@ -3285,10 +3264,8 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p)
       && ((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)))
+            elements are zero-initializer.  */
+         || TREE_CODE (t) == CONSTRUCTOR))
     {
       temp.var = nothing_id;
       temp.type = ADDRESSOF;
@@ -3426,19 +3403,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))
@@ -3649,10 +3614,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;
     }
@@ -4734,6 +4696,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
@@ -4819,37 +4794,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)
 {
   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)
+       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
@@ -4872,11 +4847,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
-               && !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
@@ -4893,13 +4869,14 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
                  = (!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
@@ -4951,6 +4928,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
@@ -4973,6 +4952,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);
@@ -4987,6 +4967,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.  */
@@ -5009,6 +4990,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);
     }
 
@@ -5038,6 +5020,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);
     }
@@ -5068,6 +5051,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);
@@ -5100,6 +5084,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++;
     }
 
   return vi->id;
@@ -5129,135 +5114,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);
-
-      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.  */
@@ -5269,12 +5167,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;
@@ -5291,10 +5189,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);
+       }
+    }
+
+  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 id;
+  return vi->id;
 }
 
 /* Print out the points-to solution for VAR to FILE.  */
@@ -5380,12 +5378,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");
@@ -5916,7 +5910,13 @@ dump_sa_points_to_info (FILE *outfile)
     {
       varinfo_t vi = get_varinfo (i);
       if (!vi->may_have_pointers)
-       continue;
+       {
+         gcc_assert (find (i) == i
+                     || !(vi = get_varinfo (find (i)))->may_have_pointers);
+         /* ???  See create_variable_info_for.
+            gcc_assert (bitmap_empty_p (vi->solution));  */
+         continue;
+       }
       dump_solution_for_var (outfile, i);
     }
 }
@@ -5955,8 +5955,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.  */