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:
Martin Jambor 2010-05-19 13:49:36 +02:00 committed by Martin Jambor
parent c9018c71d3
commit 749aa96dab
8 changed files with 273 additions and 93 deletions

View file

@ -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

View file

@ -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);
}
}

View file

@ -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)
{

View file

@ -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;
}

View file

@ -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. */

View file

@ -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

View 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" } } */

View 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" } } */