===================================================================
@@ -1269,6 +1269,49 @@ ipcp_const_param_count (struct cgraph_no
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 +1433,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 +1454,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);
===================================================================
@@ -0,0 +1,65 @@
+/* Verify that simple virtual calls are inlined even without early
+ inlining. */
+/* { dg-do run } */
+/* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining" } */
+
+extern "C" void abort (void);
+
+class A
+{
+public:
+ int data;
+ virtual int foo (int i);
+};
+
+class B : public A
+{
+public:
+ virtual int foo (int i);
+};
+
+class C : public A
+{
+public:
+ virtual int foo (int i);
+};
+
+int A::foo (int i)
+{
+ return i + 1;
+}
+
+int B::foo (int i)
+{
+ return i + 2;
+}
+
+int C::foo (int i)
+{
+ return i + 3;
+}
+
+int __attribute__ ((noinline)) middleman (class A *obj, int i)
+{
+ return obj->foo (i);
+}
+
+int __attribute__ ((noinline,noclone)) get_input(void)
+{
+ return 1;
+}
+
+class B b;
+
+int main (int argc, char *argv[])
+{
+ int i;
+
+ for (i = 0; i < get_input (); i++)
+ if (middleman (&b, get_input ()) != 3)
+ abort ();
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "B::foo\[^\\n\]*inline copy in int.*middleman" "inline" } } */
+/* { dg-final { cleanup-ipa-dump "inline" } } */
===================================================================
@@ -0,0 +1,34 @@
+/* Verify that simple indirect calls are inlined even without early
+ inlining.. */
+/* { dg-do compile } */
+/* { dg-options "-O3 -c -fdump-ipa-inline -fno-early-inlining" } */
+
+extern void non_existent(int);
+extern void non_existent(int);
+
+static void hooray ()
+{
+ non_existent (1);
+}
+
+static void __attribute__ ((noinline)) hiphip (void (*f)())
+{
+ f ();
+}
+
+int __attribute__ ((noinline,noclone)) get_input(void)
+{
+ return 1;
+}
+
+int main (int argc, int *argv[])
+{
+ int i;
+
+ for (i = 0; i < get_input (); i++)
+ hiphip (hooray);
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "hooray\[^\\n\]*inline copy in hiphip.constprop" "inline" } } */
+/* { dg-final { cleanup-ipa-dump "inline" } } */