OSDN Git Service

2010-04-30 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-structalias.c
index c11d3b8..28bb0bb 100644 (file)
@@ -2759,14 +2759,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;
 
@@ -2944,12 +2940,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);
 }
 
@@ -2959,11 +2949,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
@@ -3294,18 +3280,16 @@ 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.  But in IPA mode we also
+            process global initializers, so verify at least.  */
+         || (TREE_CODE (t) == CONSTRUCTOR
+             && CONSTRUCTOR_NELTS (t) == 0)))
+    {
+      temp.var = nothing_id;
       temp.type = ADDRESSOF;
       temp.offset = 0;
       VEC_safe_push (ce_s, heap, *results, &temp);
@@ -3603,7 +3587,7 @@ make_transitive_closure_constraints (varinfo_t vi)
    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);
@@ -3635,16 +3619,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;
@@ -3694,7 +3668,10 @@ get_function_part_constraint (varinfo_t fi, unsigned part)
   else if (TREE_CODE (fi->decl) == FUNCTION_DECL)
     {
       varinfo_t ai = first_vi_for_offset (fi, part);
-      c.var = ai ? ai->id : anything_id;
+      if (ai)
+       c.var = ai->id;
+      else
+       c.var = anything_id;
       c.offset = 0;
       c.type = SCALAR;
     }
@@ -3716,61 +3693,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 +3736,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);
 }
 
@@ -4272,7 +4186,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
@@ -4360,7 +4274,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);
@@ -4815,36 +4729,29 @@ first_vi_for_offset (varinfo_t start, unsigned HOST_WIDE_INT offset)
    OFFSET.  If there is no such varinfo the varinfo directly preceding
    OFFSET is returned.  */
 
-static void
-process_ipa_clobber (varinfo_t fi, tree ptr)
+static varinfo_t
+first_or_preceding_vi_for_offset (varinfo_t start,
+                                 unsigned HOST_WIDE_INT offset)
 {
-  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);
-}
+  /* 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);
 
-/* 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.  */
+  /* We may not find a variable in the field list with the actual
+     offset when when we have glommed a structure to a variable.
+     In that case, however, offset should still be within the size
+     of the variable.
+     If we got beyond the offset we look for return the field
+     directly preceding offset which may be the last field.  */
+  while (start->next
+        && offset >= start->offset
+        && !((offset - start->offset) < start->size))
+    start = start->next;
 
-static void
-find_func_clobbers (gimple origt)
-{
-  gimple t = origt;
-  VEC(ce_s, heap) *lhsc = NULL;
-  VEC(ce_s, heap) *rhsc = NULL;
-  varinfo_t fi;
+  return start;
+}
 
-  /* 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);
 
 /* This structure is used during pushing fields onto the fieldstack
    to track the offset of the field, since bitpos_of_field gives it
@@ -4936,7 +4843,7 @@ var_can_have_subvars (const_tree v)
 
 static bool
 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;
@@ -4961,8 +4868,7 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
            || 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)
+                   (TREE_TYPE (field), fieldstack, offset + foff)
                 && (DECL_SIZE (field)
                     && !integer_zerop (DECL_SIZE (field))))
          /* Empty structures may have actual size, like in C++.  So
@@ -4988,7 +4894,6 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
                && !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->size += TREE_INT_CST_LOW (DECL_SIZE (field));
@@ -5002,8 +4907,7 @@ 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))
@@ -5044,7 +4948,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);
@@ -5088,7 +4992,6 @@ create_function_info_for (tree decl, const char *name)
       gcc_assert (prev_vi->offset < clobbervi->offset);
       prev_vi->next = clobbervi;
       prev_vi = clobbervi;
-      stats.total_vars++;
 
       asprintf (&tempname, "%s.use", name);
       newname = ggc_strdup (tempname);
@@ -5103,7 +5006,6 @@ create_function_info_for (tree decl, const char *name)
       gcc_assert (prev_vi->offset < usevi->offset);
       prev_vi->next = usevi;
       prev_vi = usevi;
-      stats.total_vars++;
     }
 
   /* And one for the static chain.  */
@@ -5126,7 +5028,6 @@ create_function_info_for (tree decl, const char *name)
       gcc_assert (prev_vi->offset < chainvi->offset);
       prev_vi->next = chainvi;
       prev_vi = chainvi;
-      stats.total_vars++;
       insert_vi_for_tree (fn->static_chain_decl, chainvi);
     }
 
@@ -5156,7 +5057,6 @@ 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);
     }
@@ -5187,7 +5087,6 @@ 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);
@@ -5220,10 +5119,9 @@ create_function_info_for (tree decl, const char *name)
       gcc_assert (prev_vi->offset < argvi->offset);
       prev_vi->next = argvi;
       prev_vi = argvi;
-      stats.total_vars++;
     }
 
-  return vi;
+  return vi->id;
 }
 
 
@@ -5266,62 +5164,11 @@ create_variable_info_for_1 (tree decl, const char *name)
       vi = new_var_info (decl, name);
       vi->offset = 0;
       vi->size = ~0;
-    }
-  else
-    {
-      vi->fullsize = TREE_INT_CST_LOW (declsize);
-      vi->size = vi->fullsize;
-    }
-
-  insert_vi_for_tree (vi->decl, vi);
-
-  /* ???  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)
-    {
-      /* Mark global restrict qualified 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.  */
-      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 (vi->decl))
-       {
-         VEC (ce_s, heap) *rhsc = NULL;
-         struct constraint_expr lhs, *rhsp;
-         unsigned i;
-         get_constraint_for (DECL_INITIAL (vi->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))
-           {
-             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));
-           }
-         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);
-       }
+      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.  */
@@ -5337,10 +5184,7 @@ create_variable_info_for_1 (tree decl, const char *name)
       bool notokay = false;
       unsigned int i;
 
-      push_fields_onto_fieldstack (decl_type, &fieldstack, 0,
-                                  TREE_PUBLIC (decl)
-                                  || DECL_EXTERNAL (decl)
-                                  || TREE_ADDRESSABLE (decl));
+      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
@@ -5392,10 +5236,7 @@ create_variable_info_for_1 (tree decl, const char *name)
       const char *newname = "NULL";
       char *tempname;
 
-      vi->offset = fo->offset;
-      vi->may_have_pointers = fo->may_have_pointers;
-      if (vi->is_global_var
-         && vi->may_have_pointers)
+      if (dump_file)
        {
          asprintf (&tempname, "%s." HOST_WIDE_INT_PRINT_DEC
                    "+" HOST_WIDE_INT_PRINT_DEC, name, fo->offset, fo->size);
@@ -6094,13 +5935,7 @@ dump_sa_points_to_info (FILE *outfile)
     {
       varinfo_t vi = get_varinfo (i);
       if (!vi->may_have_pointers)
-       {
-         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;
-       }
+       continue;
       dump_solution_for_var (outfile, i);
     }
 }
@@ -6722,9 +6557,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.  */
@@ -6761,14 +6593,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;