OSDN Git Service

2010-11-25 Basile Starynkevitch <basile@starynkevitch.net>
[pf3gnuchains/gcc-fork.git] / gcc / ipa-cp.c
index 354a404..33ed496 100644 (file)
@@ -327,7 +327,6 @@ ipcp_lattice_from_jfunc (struct ipa_node_params *info, struct ipcp_lattice *lat,
     {
       struct ipcp_lattice *caller_lat;
       tree t;
-      bool ok;
 
       caller_lat = ipcp_get_lattice (info, jfunc->value.ancestor.formal_id);
       lat->type = caller_lat->type;
@@ -340,16 +339,10 @@ ipcp_lattice_from_jfunc (struct ipa_node_params *info, struct ipcp_lattice *lat,
          return;
        }
       t = TREE_OPERAND (caller_lat->constant, 0);
-      ok = build_ref_for_offset (&t, TREE_TYPE (t),
-                                jfunc->value.ancestor.offset,
-                                jfunc->value.ancestor.type, false);
-      if (!ok)
-       {
-         lat->type = IPA_BOTTOM;
-         lat->constant = NULL_TREE;
-       }
-      else
-       lat->constant = build_fold_addr_expr (t);
+      t = build_ref_for_offset (EXPR_LOCATION (t), t,
+                               jfunc->value.ancestor.offset,
+                               jfunc->value.ancestor.type, NULL, false);
+      lat->constant = build_fold_addr_expr (t);
     }
   else
     lat->type = IPA_BOTTOM;
@@ -427,8 +420,11 @@ ipcp_versionable_function_p (struct cgraph_node *node)
 {
   struct cgraph_edge *edge;
 
-  /* There are a number of generic reasons functions cannot be versioned.  */
-  if (!node->local.versionable)
+  /* There are a number of generic reasons functions cannot be versioned.  We
+     also cannot remove parameters if there are type attributes such as fnspec
+     present.  */
+  if (!node->local.versionable
+      || TYPE_ATTRIBUTES (TREE_TYPE (node->decl)))
     return false;
 
   /* Removing arguments doesn't work if the function takes varargs
@@ -461,6 +457,15 @@ ipcp_cloning_candidate_p (struct cgraph_node *node)
   if (cgraph_only_called_directly_p (node) || !node->analyzed)
     return false;
 
+  /* When function address is taken, we are pretty sure it will be called in hidden way.  */
+  if (node->address_taken)
+    {
+      if (dump_file)
+        fprintf (dump_file, "Not considering %s for cloning; address is taken.\n",
+                cgraph_node_name (node));
+      return false;
+    }
+
   if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE)
     {
       if (dump_file)
@@ -565,7 +570,7 @@ ipcp_initialize_node_lattices (struct cgraph_node *node)
 
   if (ipa_is_called_with_var_arguments (info))
     type = IPA_BOTTOM;
-  else if (cgraph_only_called_directly_p (node))
+  else if (node->local.local)
     type = IPA_TOP;
   /* When cloning is allowed, we can assume that externally visible functions
      are not called.  We will compensate this by cloning later.  */
@@ -1269,6 +1274,49 @@ ipcp_const_param_count (struct cgraph_node *node)
   return const_param;
 }
 
+/* Given that a formal parameter of NODE given by INDEX is known to be constant
+   CST, try to find any indirect edges that can be made direct and make them
+   so.  Note that INDEX is the number the parameter at the time of analyzing
+   parameter uses and parameter removals should not be considered for it.  (In
+   fact, the parameter itself has just been removed.)  */
+
+static void
+ipcp_discover_new_direct_edges (struct cgraph_node *node, int index, tree cst)
+{
+  struct cgraph_edge *ie, *next_ie;
+
+  for (ie = node->indirect_calls; ie; ie = next_ie)
+    {
+      struct cgraph_indirect_call_info *ici = ie->indirect_info;
+
+      next_ie = ie->next_callee;
+      if (ici->param_index != index)
+       continue;
+
+      if (ici->polymorphic)
+       {
+         tree binfo;
+         HOST_WIDE_INT token;
+
+         if (TREE_CODE (cst) != ADDR_EXPR)
+           continue;
+
+         binfo = gimple_get_relevant_ref_binfo (TREE_OPERAND (cst, 0),
+                                                NULL_TREE);
+         if (!binfo)
+           continue;
+         gcc_assert (ie->indirect_info->anc_offset == 0);
+         token = ie->indirect_info->otr_token;
+         cst = gimple_fold_obj_type_ref_known_binfo (token, binfo);
+         if (!cst)
+           continue;
+       }
+
+      ipa_make_edge_direct_to_target (ie, cst);
+    }
+}
+
+
 /* Propagate the constant parameters found by ipcp_iterate_stage()
    to the function's code.  */
 static void
@@ -1390,7 +1438,8 @@ ipcp_insert_stage (void)
        node_callers++;
       redirect_callers = VEC_alloc (cgraph_edge_p, heap, node_callers);
       for (cs = node->callers; cs != NULL; cs = cs->next_caller)
-       VEC_quick_push (cgraph_edge_p, redirect_callers, cs);
+       if (!cs->indirect_inlining_edge)
+         VEC_quick_push (cgraph_edge_p, redirect_callers, cs);
 
       /* Redirecting all the callers of the node to the
          new versioned node.  */
@@ -1410,7 +1459,13 @@ ipcp_insert_stage (void)
                 cgraph_node_name (node), (int)growth, (int)new_size);
       ipcp_init_cloned_node (node, node1);
 
-      /* TODO: We can use indirect inlning info to produce new calls.  */
+      info = IPA_NODE_REF (node);
+      for (i = 0; i < count; i++)
+       {
+         struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
+         if (lat->type == IPA_CONST_VALUE)
+           ipcp_discover_new_direct_edges (node1, i, lat->constant);
+        }
 
       if (dump_file)
        dump_function_to_file (node1->decl, dump_file, dump_flags);