ipa-prop.c (ipa_print_node_jump_functions): Print jump functions also for indirect edges.
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. * testsuite/g++.dg/ipa/ivinline-8.C: New test. * testsuite/gcc.dg/ipa/iinline-2.c: New test. From-SVN: r159559
This commit is contained in:
parent
c9018c71d3
commit
749aa96dab
8 changed files with 273 additions and 93 deletions
|
@ -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
|
||||
|
|
16
gcc/ipa-cp.c
16
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
191
gcc/ipa-prop.c
191
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++)
|
||||
for (cs = node->indirect_calls, i = 0; cs; cs = cs->next_callee, i++)
|
||||
{
|
||||
if (!ipa_edge_args_info_available_for_edge_p (cs))
|
||||
continue;
|
||||
|
||||
if (cs->call_stmt)
|
||||
{
|
||||
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");
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
|
77
gcc/testsuite/g++.dg/ipa/ivinline-8.C
Normal file
77
gcc/testsuite/g++.dg/ipa/ivinline-8.C
Normal file
|
@ -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" } } */
|
41
gcc/testsuite/gcc.dg/ipa/iinline-2.c
Normal file
41
gcc/testsuite/gcc.dg/ipa/iinline-2.c
Normal file
|
@ -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" } } */
|
Loading…
Add table
Reference in a new issue