From 749aa96dabbb0fef0d81b382a49849186f907d95 Mon Sep 17 00:00:00 2001 From: Martin Jambor Date: Wed, 19 May 2010 13:49:36 +0200 Subject: ipa-prop.c (ipa_print_node_jump_functions): Print jump functions also for indirect edges. 2010-05-19 Martin Jambor * 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. * testsuite/g++.dg/ipa/ivinline-8.C: New test. * testsuite/gcc.dg/ipa/iinline-2.c: New test. From-SVN: r159559 --- gcc/ChangeLog | 17 +++ gcc/ipa-cp.c | 16 +-- gcc/ipa-inline.c | 17 +-- gcc/ipa-prop.c | 191 ++++++++++++++++++++++------------ gcc/ipa-prop.h | 2 +- gcc/testsuite/ChangeLog | 5 + gcc/testsuite/g++.dg/ipa/ivinline-8.C | 77 ++++++++++++++ gcc/testsuite/gcc.dg/ipa/iinline-2.c | 41 ++++++++ 8 files changed, 273 insertions(+), 93 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ipa/ivinline-8.C create mode 100644 gcc/testsuite/gcc.dg/ipa/iinline-2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 30ed7cb..c725ab9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2010-05-19 Martin Jambor + + * 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 * 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 f4aab5d..a1bfe0e 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 e1de7ce..12757f7 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 6437389..d977242 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 c142c03..110044e 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 135c9b2..237b3c1 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2010-05-19 Martin Jambor + + * g++.dg/ipa/ivinline-8.C: New test. + * gcc.dg/ipa/iinline-2.c: Likewise. + 2010-05-19 Daniel Franke 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 0000000..3bdf4c1 --- /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 0000000..117818d --- /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" } } */ -- cgit v1.1