aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog17
-rw-r--r--gcc/ipa-cp.c16
-rw-r--r--gcc/ipa-inline.c17
-rw-r--r--gcc/ipa-prop.c191
-rw-r--r--gcc/ipa-prop.h2
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/ipa/ivinline-8.C77
-rw-r--r--gcc/testsuite/gcc.dg/ipa/iinline-2.c41
8 files changed, 273 insertions, 93 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 30ed7cb422b..c725ab9bc9b 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,20 @@
+2010-05-19 Martin Jambor <mjambor@suse.cz>
+
+ * ipa-prop.c (ipa_print_node_jump_functions): Print jump functions
+ also for indirect edges. Actual printing moved...
+ (ipa_print_node_jump_functions_for_edge): ...here.
+ (ipa_compute_jump_functions): Renamed to
+ ipa_compute_jump_functions_for_edge and made static.
+ (ipa_compute_jump_functions): New function.
+ (make_edge_direct_to_target): Check if the number of arguments on
+ the newly direct edge is the same as the number of parametrs of
+ the callee.
+ * ipa-cp.c (ipcp_init_stage): Most functionality moved to new
+ ipa_compute_jump_functions. Call ipa_analyze_params_uses.
+ * ipa-inline.c (inline_indirect_intraprocedural_analysis): Call
+ analysis functions unconditionally, call the new
+ ipa_analyze_params_uses on the node instead of every edge.
+
2010-05-19 Christian Borntraeger <borntraeger@de.ibm.com>
* tree-ssa-loop-prefetch.c (mem_ref_group, ar_data): Change step
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index f4aab5d2d89..a1bfe0e8701 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -614,7 +614,6 @@ static void
ipcp_init_stage (void)
{
struct cgraph_node *node;
- struct cgraph_edge *cs;
for (node = cgraph_nodes; node; node = node->next)
if (node->analyzed)
@@ -623,19 +622,10 @@ ipcp_init_stage (void)
{
if (!node->analyzed)
continue;
+
+ ipa_analyze_params_uses (node);
/* building jump functions */
- for (cs = node->callees; cs; cs = cs->next_callee)
- {
- /* We do not need to bother analyzing calls to unknown
- functions unless they may become known during lto/whopr. */
- if (!cs->callee->analyzed && !flag_lto && !flag_whopr)
- continue;
- ipa_count_arguments (cs);
- if (ipa_get_cs_argument_count (IPA_EDGE_REF (cs))
- != ipa_get_param_count (IPA_NODE_REF (cs->callee)))
- ipa_set_called_with_variable_arg (IPA_NODE_REF (cs->callee));
- ipa_compute_jump_functions (cs);
- }
+ ipa_compute_jump_functions (node);
}
}
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index e1de7ce25cc..12757f7a2a3 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -1971,21 +1971,10 @@ struct gimple_opt_pass pass_inline_parameters =
static void
inline_indirect_intraprocedural_analysis (struct cgraph_node *node)
{
- struct cgraph_edge *cs;
-
- if (!flag_ipa_cp)
- {
- ipa_initialize_node_params (node);
- ipa_detect_param_modifications (node);
- }
+ ipa_initialize_node_params (node);
+ ipa_detect_param_modifications (node);
ipa_analyze_params_uses (node);
-
- if (!flag_ipa_cp)
- for (cs = node->callees; cs; cs = cs->next_callee)
- {
- ipa_count_arguments (cs);
- ipa_compute_jump_functions (cs);
- }
+ ipa_compute_jump_functions (node);
if (dump_file)
{
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 6437389876e..d977242b5f0 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -304,16 +304,87 @@ ipa_count_arguments (struct cgraph_edge *cs)
ipa_set_cs_argument_count (IPA_EDGE_REF (cs), arg_num);
}
+/* Print the jump functions associated with call graph edge CS to file F. */
+
+static void
+ipa_print_node_jump_functions_for_edge (FILE *f, struct cgraph_edge *cs)
+{
+ int i, count;
+
+ count = ipa_get_cs_argument_count (IPA_EDGE_REF (cs));
+ for (i = 0; i < count; i++)
+ {
+ struct ipa_jump_func *jump_func;
+ enum jump_func_type type;
+
+ jump_func = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), i);
+ type = jump_func->type;
+
+ fprintf (f, " param %d: ", i);
+ if (type == IPA_JF_UNKNOWN)
+ fprintf (f, "UNKNOWN\n");
+ else if (type == IPA_JF_KNOWN_TYPE)
+ {
+ tree binfo_type = TREE_TYPE (jump_func->value.base_binfo);
+ fprintf (f, "KNOWN TYPE, type in binfo is: ");
+ print_generic_expr (f, binfo_type, 0);
+ fprintf (f, " (%u)\n", TYPE_UID (binfo_type));
+ }
+ else if (type == IPA_JF_CONST)
+ {
+ tree val = jump_func->value.constant;
+ fprintf (f, "CONST: ");
+ print_generic_expr (f, val, 0);
+ if (TREE_CODE (val) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (val, 0)) == CONST_DECL)
+ {
+ fprintf (f, " -> ");
+ print_generic_expr (f, DECL_INITIAL (TREE_OPERAND (val, 0)),
+ 0);
+ }
+ fprintf (f, "\n");
+ }
+ else if (type == IPA_JF_CONST_MEMBER_PTR)
+ {
+ fprintf (f, "CONST MEMBER PTR: ");
+ print_generic_expr (f, jump_func->value.member_cst.pfn, 0);
+ fprintf (f, ", ");
+ print_generic_expr (f, jump_func->value.member_cst.delta, 0);
+ fprintf (f, "\n");
+ }
+ else if (type == IPA_JF_PASS_THROUGH)
+ {
+ fprintf (f, "PASS THROUGH: ");
+ fprintf (f, "%d, op %s ",
+ jump_func->value.pass_through.formal_id,
+ tree_code_name[(int)
+ jump_func->value.pass_through.operation]);
+ if (jump_func->value.pass_through.operation != NOP_EXPR)
+ print_generic_expr (dump_file,
+ jump_func->value.pass_through.operand, 0);
+ fprintf (dump_file, "\n");
+ }
+ else if (type == IPA_JF_ANCESTOR)
+ {
+ fprintf (f, "ANCESTOR: ");
+ fprintf (f, "%d, offset "HOST_WIDE_INT_PRINT_DEC", ",
+ jump_func->value.ancestor.formal_id,
+ jump_func->value.ancestor.offset);
+ print_generic_expr (f, jump_func->value.ancestor.type, 0);
+ fprintf (dump_file, "\n");
+ }
+ }
+}
+
+
/* Print the jump functions of all arguments on all call graph edges going from
NODE to file F. */
void
ipa_print_node_jump_functions (FILE *f, struct cgraph_node *node)
{
- int i, count;
struct cgraph_edge *cs;
- struct ipa_jump_func *jump_func;
- enum jump_func_type type;
+ int i;
fprintf (f, " Jump functions of caller %s:\n", cgraph_node_name (node));
for (cs = node->callees; cs; cs = cs->next_callee)
@@ -321,69 +392,26 @@ ipa_print_node_jump_functions (FILE *f, struct cgraph_node *node)
if (!ipa_edge_args_info_available_for_edge_p (cs))
continue;
- fprintf (f, " callsite %s ", cgraph_node_name (node));
- fprintf (f, "-> %s :: \n", cgraph_node_name (cs->callee));
+ fprintf (f, " callsite %s/%i -> %s/%i : \n",
+ cgraph_node_name (node), node->uid,
+ cgraph_node_name (cs->callee), cs->callee->uid);
+ ipa_print_node_jump_functions_for_edge (f, cs);
+ }
- count = ipa_get_cs_argument_count (IPA_EDGE_REF (cs));
- for (i = 0; i < count; i++)
- {
- jump_func = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), i);
- type = jump_func->type;
+ for (cs = node->indirect_calls, i = 0; cs; cs = cs->next_callee, i++)
+ {
+ if (!ipa_edge_args_info_available_for_edge_p (cs))
+ continue;
- fprintf (f, " param %d: ", i);
- if (type == IPA_JF_UNKNOWN)
- fprintf (f, "UNKNOWN\n");
- else if (type == IPA_JF_KNOWN_TYPE)
- {
- tree binfo_type = TREE_TYPE (jump_func->value.base_binfo);
- fprintf (f, "KNOWN TYPE, type in binfo is: ");
- print_generic_expr (f, binfo_type, 0);
- fprintf (f, " (%u)\n", TYPE_UID (binfo_type));
- }
- else if (type == IPA_JF_CONST)
- {
- tree val = jump_func->value.constant;
- fprintf (f, "CONST: ");
- print_generic_expr (f, val, 0);
- if (TREE_CODE (val) == ADDR_EXPR
- && TREE_CODE (TREE_OPERAND (val, 0)) == CONST_DECL)
- {
- fprintf (f, " -> ");
- print_generic_expr (f, DECL_INITIAL (TREE_OPERAND (val, 0)),
- 0);
- }
- fprintf (f, "\n");
- }
- else if (type == IPA_JF_CONST_MEMBER_PTR)
- {
- fprintf (f, "CONST MEMBER PTR: ");
- print_generic_expr (f, jump_func->value.member_cst.pfn, 0);
- fprintf (f, ", ");
- print_generic_expr (f, jump_func->value.member_cst.delta, 0);
- fprintf (f, "\n");
- }
- else if (type == IPA_JF_PASS_THROUGH)
- {
- fprintf (f, "PASS THROUGH: ");
- fprintf (f, "%d, op %s ",
- jump_func->value.pass_through.formal_id,
- tree_code_name[(int)
- jump_func->value.pass_through.operation]);
- if (jump_func->value.pass_through.operation != NOP_EXPR)
- print_generic_expr (dump_file,
- jump_func->value.pass_through.operand, 0);
- fprintf (dump_file, "\n");
- }
- else if (type == IPA_JF_ANCESTOR)
- {
- fprintf (f, "ANCESTOR: ");
- fprintf (f, "%d, offset "HOST_WIDE_INT_PRINT_DEC", ",
- jump_func->value.ancestor.formal_id,
- jump_func->value.ancestor.offset);
- print_generic_expr (f, jump_func->value.ancestor.type, 0);
- fprintf (dump_file, "\n");
- }
+ if (cs->call_stmt)
+ {
+ fprintf (f, " indirect callsite %d for stmt ", i);
+ print_gimple_stmt (f, cs->call_stmt, 0, TDF_SLIM);
}
+ else
+ fprintf (f, " indirect callsite %d :\n", i);
+ ipa_print_node_jump_functions_for_edge (f, cs);
+
}
}
@@ -852,8 +880,8 @@ compute_cst_member_ptr_arguments (struct ipa_jump_func *functions,
information in the jump_functions array in the ipa_edge_args corresponding
to this callsite. */
-void
-ipa_compute_jump_functions (struct cgraph_edge *cs)
+static void
+ipa_compute_jump_functions_for_edge (struct cgraph_edge *cs)
{
struct ipa_node_params *info = IPA_NODE_REF (cs->caller);
struct ipa_edge_args *arguments = IPA_EDGE_REF (cs);
@@ -880,6 +908,34 @@ ipa_compute_jump_functions (struct cgraph_edge *cs)
compute_cst_member_ptr_arguments (arguments->jump_functions, call);
}
+/* Compute jump functions for all edges - both direct and indirect - outgoing
+ from NODE. Also count the actual arguments in the process. */
+
+void
+ipa_compute_jump_functions (struct cgraph_node *node)
+{
+ struct cgraph_edge *cs;
+
+ for (cs = node->callees; cs; cs = cs->next_callee)
+ {
+ /* We do not need to bother analyzing calls to unknown
+ functions unless they may become known during lto/whopr. */
+ if (!cs->callee->analyzed && !flag_lto && !flag_whopr)
+ continue;
+ ipa_count_arguments (cs);
+ if (ipa_get_cs_argument_count (IPA_EDGE_REF (cs))
+ != ipa_get_param_count (IPA_NODE_REF (cs->callee)))
+ ipa_set_called_with_variable_arg (IPA_NODE_REF (cs->callee));
+ ipa_compute_jump_functions_for_edge (cs);
+ }
+
+ for (cs = node->indirect_calls; cs; cs = cs->next_callee)
+ {
+ ipa_count_arguments (cs);
+ ipa_compute_jump_functions_for_edge (cs);
+ }
+}
+
/* If RHS looks like a rhs of a statement loading pfn from a member
pointer formal parameter, return the parameter, otherwise return
NULL. If USE_DELTA, then we look for a use of the delta field
@@ -1345,6 +1401,11 @@ make_edge_direct_to_target (struct cgraph_edge *ie, tree target)
else
fprintf (dump_file, "with uid %i\n", ie->lto_stmt_uid);
}
+
+ if (ipa_get_cs_argument_count (IPA_EDGE_REF (ie))
+ != ipa_get_param_count (IPA_NODE_REF (callee)))
+ ipa_set_called_with_variable_arg (IPA_NODE_REF (callee));
+
return ie;
}
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index c142c03db28..110044e4da4 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -413,7 +413,7 @@ ipa_push_func_to_list (struct ipa_func_list **wl, struct cgraph_node *node)
}
/* Callsite related calculations. */
-void ipa_compute_jump_functions (struct cgraph_edge *);
+void ipa_compute_jump_functions (struct cgraph_node *);
void ipa_count_arguments (struct cgraph_edge *);
/* Function formal parameters related computations. */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 135c9b2fc5d..237b3c18be1 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2010-05-19 Martin Jambor <mjambor@suse.cz>
+
+ * g++.dg/ipa/ivinline-8.C: New test.
+ * gcc.dg/ipa/iinline-2.c: Likewise.
+
2010-05-19 Daniel Franke <franke.daniel@gmail.com>
PR fortran/34505
diff --git a/gcc/testsuite/g++.dg/ipa/ivinline-8.C b/gcc/testsuite/g++.dg/ipa/ivinline-8.C
new file mode 100644
index 00000000000..3bdf4c15b2d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/ivinline-8.C
@@ -0,0 +1,77 @@
+/* Verify that virtual calls are inlined (ithout early inlining) even
+ when their caller is itself indirectly inlined. */
+/* { dg-do run } */
+/* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining -fno-ipa-cp" } */
+
+extern "C" void abort (void);
+
+class A
+{
+public:
+ int data;
+ virtual int bar (int i);
+ virtual int foo (int i);
+};
+
+class B : public A
+{
+public:
+ virtual int bar (int i);
+ virtual int foo (int i);
+};
+
+class C : public A
+{
+public:
+ virtual int foo (int i);
+};
+
+int A::bar (int i)
+{
+ return i + 100 * i;
+}
+
+int A::foo (int i)
+{
+ return bar (i) + 1;
+}
+
+int B::bar (int i)
+{
+ return i + 100 * (i + 2);
+}
+
+int B::foo (int i)
+{
+ return bar (i) + 2;
+}
+
+int C::foo (int i)
+{
+ return i + 3;
+}
+
+int middleman (class A *obj, int i)
+{
+ return obj->foo (i);
+}
+
+int __attribute__ ((noinline,noclone)) get_input(void)
+{
+ return 1;
+}
+
+int main (int argc, char *argv[])
+{
+ class B b;
+ int i;
+
+ for (i = 0; i < get_input (); i++)
+ if (middleman (&b, get_input ()) != 303)
+ abort ();
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "B::foo\[^\\n\]*inline copy in int main" "inline" } } */
+/* { dg-final { scan-ipa-dump "B::bar\[^\\n\]*inline copy in int main" "inline" } } */
+/* { dg-final { cleanup-ipa-dump "inline" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/iinline-2.c b/gcc/testsuite/gcc.dg/ipa/iinline-2.c
new file mode 100644
index 00000000000..117818d1645
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/iinline-2.c
@@ -0,0 +1,41 @@
+/* Verify that simple indirect calls are inlined even without early
+ inlining.. */
+/* { dg-do compile } */
+/* { dg-options "-O3 -c -fdump-ipa-inline -fno-early-inlining -fno-ipa-cp" } */
+
+extern void non_existent(int);
+
+int __attribute__ ((noinline,noclone)) get_input(void)
+{
+ return 1;
+}
+
+static void hooray ()
+{
+ non_existent (1);
+}
+
+static void hip2 (void (*g)())
+{
+ non_existent (2);
+ g ();
+}
+
+static void hip1 (void (*f)(void (*)()), void (*g)())
+{
+ non_existent (2);
+ f (g);
+}
+
+int main (int argc, int *argv[])
+{
+ int i;
+
+ for (i = 0; i < get_input (); i++)
+ hip1 (hip2, hooray);
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "hooray\[^\\n\]*inline copy in main" "inline" } } */
+/* { dg-final { scan-ipa-dump "hip2\[^\\n\]*inline copy in main" "inline" } } */
+/* { dg-final { cleanup-ipa-dump "inline" } } */