OSDN Git Service

2011-09-02 Vincent Celier <celier@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-structalias.c
index faf4f6a..d69f14c 100644 (file)
@@ -362,7 +362,7 @@ new_var_info (tree t, const char *name)
                          || (TREE_CODE (t) == VAR_DECL
                              && DECL_HARD_REGISTER (t)));
   ret->solution = BITMAP_ALLOC (&pta_obstack);
-  ret->oldsolution = BITMAP_ALLOC (&oldpta_obstack);
+  ret->oldsolution = NULL;
   ret->next = NULL;
 
   stats.total_vars++;
@@ -1504,13 +1504,12 @@ unify_nodes (constraint_graph_t graph, unsigned int to, unsigned int from,
        }
 
       BITMAP_FREE (get_varinfo (from)->solution);
-      BITMAP_FREE (get_varinfo (from)->oldsolution);
+      if (get_varinfo (from)->oldsolution)
+       BITMAP_FREE (get_varinfo (from)->oldsolution);
 
-      if (stats.iterations > 0)
-       {
-         BITMAP_FREE (get_varinfo (to)->oldsolution);
-         get_varinfo (to)->oldsolution = BITMAP_ALLOC (&oldpta_obstack);
-       }
+      if (stats.iterations > 0
+         && get_varinfo (to)->oldsolution)
+       BITMAP_FREE (get_varinfo (to)->oldsolution);
     }
   if (valid_graph_edge (graph, to, to))
     {
@@ -2544,18 +2543,27 @@ solve_graph (constraint_graph_t graph)
              constraint_t c;
              bitmap solution;
              VEC(constraint_t,heap) *complex = graph->complex[i];
+             varinfo_t vi = get_varinfo (i);
              bool solution_empty;
 
              /* Compute the changed set of solution bits.  */
-             bitmap_and_compl (pts, get_varinfo (i)->solution,
-                               get_varinfo (i)->oldsolution);
+             if (vi->oldsolution)
+               bitmap_and_compl (pts, vi->solution, vi->oldsolution);
+             else
+               bitmap_copy (pts, vi->solution);
 
              if (bitmap_empty_p (pts))
                continue;
 
-             bitmap_ior_into (get_varinfo (i)->oldsolution, pts);
+             if (vi->oldsolution)
+               bitmap_ior_into (vi->oldsolution, pts);
+             else
+               {
+                 vi->oldsolution = BITMAP_ALLOC (&oldpta_obstack);
+                 bitmap_copy (vi->oldsolution, pts);
+               }
 
-             solution = get_varinfo (i)->solution;
+             solution = vi->solution;
              solution_empty = bitmap_empty_p (solution);
 
              /* Process the complex constraints */
@@ -2746,6 +2754,18 @@ get_constraint_for_ssa_var (tree t, VEC(ce_s, heap) **results, bool address_p)
       return;
     }
 
+  /* For global variables resort to the alias target.  */
+  if (TREE_CODE (t) == VAR_DECL
+      && (TREE_STATIC (t) || DECL_EXTERNAL (t)))
+    {
+      struct varpool_node *node = varpool_get_node (t);
+      if (node && node->alias)
+       {
+         node = varpool_variable_node (node, NULL);
+         t = node->decl;
+       }
+    }
+
   vi = get_vi_for_tree (t);
   cexpr.var = vi->id;
   cexpr.type = SCALAR;
@@ -2856,7 +2876,7 @@ get_constraint_for_ptr_offset (tree ptr, tree offset,
 {
   struct constraint_expr c;
   unsigned int j, n;
-  HOST_WIDE_INT rhsunitoffset, rhsoffset;
+  HOST_WIDE_INT rhsoffset;
 
   /* If we do not do field-sensitive PTA adding offsets to pointers
      does not change the points-to solution.  */
@@ -2871,15 +2891,24 @@ get_constraint_for_ptr_offset (tree ptr, tree offset,
      solution which includes all sub-fields of all pointed-to
      variables of ptr.  */
   if (offset == NULL_TREE
-      || !host_integerp (offset, 0))
+      || TREE_CODE (offset) != INTEGER_CST)
     rhsoffset = UNKNOWN_OFFSET;
   else
     {
-      /* Make sure the bit-offset also fits.  */
-      rhsunitoffset = TREE_INT_CST_LOW (offset);
-      rhsoffset = rhsunitoffset * BITS_PER_UNIT;
-      if (rhsunitoffset != rhsoffset / BITS_PER_UNIT)
+      /* Sign-extend the offset.  */
+      double_int soffset
+       = double_int_sext (tree_to_double_int (offset),
+                          TYPE_PRECISION (TREE_TYPE (offset)));
+      if (!double_int_fits_in_shwi_p (soffset))
        rhsoffset = UNKNOWN_OFFSET;
+      else
+       {
+         /* Make sure the bit-offset also fits.  */
+         HOST_WIDE_INT rhsunitoffset = soffset.low;
+         rhsoffset = rhsunitoffset * BITS_PER_UNIT;
+         if (rhsunitoffset != rhsoffset / BITS_PER_UNIT)
+           rhsoffset = UNKNOWN_OFFSET;
+       }
     }
 
   get_constraint_for_rhs (ptr, results);
@@ -3240,15 +3269,24 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p,
            {
              struct constraint_expr cs;
              varinfo_t vi, curr;
-             tree off = double_int_to_tree (sizetype, mem_ref_offset (t));
-             get_constraint_for_ptr_offset (TREE_OPERAND (t, 0), off, results);
+             get_constraint_for_ptr_offset (TREE_OPERAND (t, 0),
+                                            TREE_OPERAND (t, 1), results);
              do_deref (results);
 
              /* If we are not taking the address then make sure to process
                 all subvariables we might access.  */
+             if (address_p)
+               return;
+
              cs = *VEC_last (ce_s, *results);
-             if (address_p
-                 || cs.type != SCALAR)
+             if (cs.type == DEREF)
+               {
+                 /* For dereferences this means we have to defer it
+                    to solving time.  */
+                 VEC_last (ce_s, *results)->offset = UNKNOWN_OFFSET;
+                 return;
+               }
+             if (cs.type != SCALAR)
                return;
 
              vi = get_varinfo (cs.var);
@@ -4001,7 +4039,9 @@ find_func_aliases_for_builtin_call (gimple t)
              get_constraint_for (res, &lhsc);
              if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMPCPY
                  || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPCPY
-                 || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPNCPY)
+                 || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPNCPY
+                 || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMPCPY_CHK
+                 || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPCPY_CHK)
                get_constraint_for_ptr_offset (dest, NULL_TREE, &rhsc);
              else
                get_constraint_for (dest, &rhsc);
@@ -4053,6 +4093,20 @@ find_func_aliases_for_builtin_call (gimple t)
          VEC_free (ce_s, heap, lhsc);
          return true;
        }
+      case BUILT_IN_ASSUME_ALIGNED:
+       {
+         tree res = gimple_call_lhs (t);
+         tree dest = gimple_call_arg (t, 0);
+         if (res != NULL_TREE)
+           {
+             get_constraint_for (res, &lhsc);
+             get_constraint_for (dest, &rhsc);
+             process_all_all_constraints (lhsc, rhsc);
+             VEC_free (ce_s, heap, lhsc);
+             VEC_free (ce_s, heap, rhsc);
+           }
+         return true;
+       }
       /* All the following functions do not return pointers, do not
         modify the points-to sets of memory reachable from their
         arguments and do not add to the ESCAPED solution.  */
@@ -4714,6 +4768,7 @@ find_func_clobbers (gimple origt)
              return;
            }
          /* The following functions neither read nor clobber memory.  */
+         case BUILT_IN_ASSUME_ALIGNED:
          case BUILT_IN_FREE:
            return;
          /* Trampolines are of no interest to us.  */
@@ -5421,6 +5476,9 @@ create_variable_info_for (tree decl, const char *name)
 
   insert_vi_for_tree (decl, vi);
 
+  if (TREE_CODE (decl) != VAR_DECL)
+    return id;
+
   /* Create initial constraints for globals.  */
   for (; vi; vi = vi->next)
     {
@@ -5434,37 +5492,44 @@ create_variable_info_for (tree decl, const char *name)
          || vi->only_restrict_pointers)
        make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
 
-      /* For escaped variables initialize them from nonlocal.  */
+      /* In non-IPA mode the initializer from nonlocal is all we need.  */
       if (!in_ipa_mode
-         || DECL_EXTERNAL (decl) || TREE_PUBLIC (decl))
+         || DECL_HARD_REGISTER (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))
+      else
        {
-         VEC (ce_s, heap) *rhsc = NULL;
-         struct constraint_expr lhs, *rhsp;
-         unsigned i;
-         get_constraint_for_rhs (DECL_INITIAL (decl), &rhsc);
-         lhs.var = vi->id;
-         lhs.offset = 0;
-         lhs.type = SCALAR;
-         FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
-           process_constraint (new_constraint (lhs, *rhsp));
-         /* If this is a variable that escapes from the unit
-            the initializer escapes as well.  */
-         if (DECL_EXTERNAL (decl) || TREE_PUBLIC (decl))
+         struct varpool_node *vnode = varpool_get_node (decl);
+
+         /* For escaped variables initialize them from nonlocal.  */
+         if (!varpool_all_refs_explicit_p (vnode))
+           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.  */
+         if (DECL_INITIAL (decl))
            {
-             lhs.var = escaped_id;
+             VEC (ce_s, heap) *rhsc = NULL;
+             struct constraint_expr lhs, *rhsp;
+             unsigned i;
+             get_constraint_for_rhs (DECL_INITIAL (decl), &rhsc);
+             lhs.var = vi->id;
              lhs.offset = 0;
              lhs.type = SCALAR;
              FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
                process_constraint (new_constraint (lhs, *rhsp));
+             /* If this is a variable that escapes from the unit
+                the initializer escapes as well.  */
+             if (!varpool_all_refs_explicit_p (vnode))
+               {
+                 lhs.var = escaped_id;
+                 lhs.offset = 0;
+                 lhs.type = SCALAR;
+                 FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
+                   process_constraint (new_constraint (lhs, *rhsp));
+               }
+             VEC_free (ce_s, heap, rhsc);
            }
-         VEC_free (ce_s, heap, rhsc);
        }
     }
 
@@ -5528,7 +5593,8 @@ intra_create_variable_infos (void)
          varinfo_t vi;
          tree heapvar = build_fake_var_decl (TREE_TYPE (TREE_TYPE (t)));
          DECL_EXTERNAL (heapvar) = 1;
-         vi = get_varinfo (create_variable_info_for (heapvar, "PARM_NOALIAS"));
+         vi = create_variable_info_for_1 (heapvar, "PARM_NOALIAS");
+         insert_vi_for_tree (heapvar, vi);
          lhsc.var = get_vi_for_tree (t)->id;
          lhsc.type = SCALAR;
          lhsc.offset = 0;
@@ -5537,6 +5603,13 @@ intra_create_variable_infos (void)
          rhsc.offset = 0;
          process_constraint (new_constraint (lhsc, rhsc));
          vi->is_restrict_var = 1;
+         for (; vi; vi = vi->next)
+           if (vi->may_have_pointers)
+             {
+               if (vi->only_restrict_pointers)
+                 make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
+               make_copy_constraint (vi, nonlocal_id);
+             }
          continue;
        }
 
@@ -6703,16 +6776,6 @@ associate_varinfo_to_alias (struct cgraph_node *node, void *data)
   return false;
 }
 
-/* Associate node with varinfo DATA. Worker for
-   varpool_for_node_and_aliases.  */
-static bool
-associate_varinfo_to_alias_1 (struct varpool_node *node, void *data)
-{
-  if (node->alias)
-    insert_vi_for_tree (node->decl, (varinfo_t)data);
-  return false;
-}
-
 /* Execute the driver for IPA PTA.  */
 static unsigned int
 ipa_pta_execute (void)
@@ -6725,6 +6788,12 @@ ipa_pta_execute (void)
 
   init_alias_vars ();
 
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      dump_cgraph (dump_file);
+      fprintf (dump_file, "\n");
+    }
+
   /* Build the constraints.  */
   for (node = cgraph_nodes; node; node = node->next)
     {
@@ -6732,10 +6801,11 @@ ipa_pta_execute (void)
       /* 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.  */
-      if (!cgraph_function_with_gimple_body_p (node)
-         || node->clone_of)
+      if (!cgraph_function_with_gimple_body_p (node))
        continue;
 
+      gcc_assert (!node->clone_of);
+
       vi = create_function_info_for (node->decl,
                                     alias_get_name (node->decl));
       cgraph_for_node_and_aliases (node, associate_varinfo_to_alias, vi, true);
@@ -6744,12 +6814,10 @@ ipa_pta_execute (void)
   /* Create constraints for global variables and their initializers.  */
   for (var = varpool_nodes; var; var = var->next)
     {
-      varinfo_t vi;
       if (var->alias)
        continue;
 
-      vi = get_vi_for_tree (var->decl);
-      varpool_for_node_and_aliases (var, associate_varinfo_to_alias_1, vi, true);
+      get_vi_for_tree (var->decl);
     }
 
   if (dump_file)
@@ -6768,8 +6836,7 @@ ipa_pta_execute (void)
       tree old_func_decl;
 
       /* Nodes without a body are not interesting.  */
-      if (!cgraph_function_with_gimple_body_p (node)
-         || node->clone_of)
+      if (!cgraph_function_with_gimple_body_p (node))
        continue;
 
       if (dump_file)
@@ -6787,11 +6854,14 @@ ipa_pta_execute (void)
       push_cfun (func);
       current_function_decl = node->decl;
 
-      if (node->local.externally_visible)
+      /* For externally visible or attribute used annotated functions use
+        local constraints for their arguments.
+        For local functions we see all callers and thus do not need initial
+        constraints for parameters.  */
+      if (node->reachable_from_other_partition
+         || node->local.externally_visible
+         || node->needed)
        {
-         /* For externally visible functions use local constraints for
-            their arguments.  For local functions we see all callers
-            and thus do not need initial constraints for parameters.  */
          intra_create_variable_infos ();
 
          /* We also need to make function return values escape.  Nothing
@@ -6877,8 +6947,7 @@ ipa_pta_execute (void)
       struct cgraph_edge *e;
 
       /* Nodes without a body are not interesting.  */
-      if (!cgraph_function_with_gimple_body_p (node)
-         || node->clone_of)
+      if (!cgraph_function_with_gimple_body_p (node))
        continue;
 
       fn = DECL_STRUCT_FUNCTION (node->decl);