Commit 3949c4a7 by Martin Jambor Committed by Martin Jambor

ipa-prop.h (enum ipa_lattice_type): Changed comments.

2010-08-05  Martin Jambor  <mjambor@suse.cz>

	* ipa-prop.h (enum ipa_lattice_type): Changed comments.
	(struct ipa_param_descriptor): New fields types and
	cannot_devirtualize.
	(ipa_param_cannot_devirtualize_p): New function.
	(ipa_param_types_vec_empty): Likewise.
	(ipa_make_edge_direct_to_target): Declare.
	* ipa-cp.c: Fixed first stage driver name in initial comment,
	described devirtualization there too.
	(ipcp_analyze_node): Call ipa_analyze_params_uses.
	(ipcp_print_all_lattices): Print devirtualization info.
	(ipa_set_param_cannot_devirtualize): New function.
	(ipcp_initialize_node_lattices): Set cannot_devirtualize when setting
	lattice to BOTTOM.
	(ipcp_init_stage): Merged into...
	(ipcp_generate_summary): ...its caller.
	(ipcp_change_tops_to_bottom): Also process type lists.
	(ipcp_add_param_type): New function.
	(ipcp_copy_types): Likewise.
	(ipcp_propagate_types): Likewise.
	(ipcp_propagate_stage): Also propagate types.
	(ipcp_need_redirect_p): Variable jump_func moved to its scope block.
	Also return true if propagated types require it.
	(ipcp_update_callgraph): Dump redirection info.
	(ipcp_process_devirtualization_opportunities): New function.
	(ipcp_const_param_count): Include known type information.
	(ipcp_insert_stage): Call ipcp_process_devirtualization_opportunities
	on new node.  Fixed formatting.
	* ipa-prop.c (make_edge_direct_to_target): Renamed to
	ipa_make_edge_direct_to_target and changed all callers.  Made
	externally visible.
	(ipa_node_duplication_hook): Duplicate types vector.
	* cgraphunit.c (cgraph_redirect_edge_call_stmt_to_callee): Also try to
	redirect outgoing calls for which we can't get a decl from the
	statement.  Check that we can get a decl from the call statement.
	* ipa-inline.c (inline_indirect_intraprocedural_analysis): Call
	ipa_analyze_params_uses only when ipa-cp is disabled.
	* tree-inline.c (get_indirect_callee_fndecl): Removed.
	(expand_call_inline): Do not call get_indirect_callee_fndecl.
	* params.def (PARAM_DEVIRT_TYPE_LIST_SIZE): New parameter.
	* Makefile.in (ipa-cp.o): Add gimple.h to dependencies.

	* testsuite/g++.dg/ipa/devirt-1.C: New test.
	* testsuite/g++.dg/ipa/devirt-2.C: Likewise.
	* testsuite/g++.dg/ipa/devirt-3.C: Likewise.
	* testsuite/g++.dg/ipa/devirt-4.C: Likewise.
	* testsuite/g++.dg/ipa/devirt-5.C: Likewise.
	* testsuite/gcc.dg/ipa/iinline-3.c: Likewise.

From-SVN: r162911
parent 4caa21a1
2010-08-05 Martin Jambor <mjambor@suse.cz>
* ipa-prop.h (enum ipa_lattice_type): Changed comments.
(struct ipa_param_descriptor): New fields types and
cannot_devirtualize.
(ipa_param_cannot_devirtualize_p): New function.
(ipa_param_types_vec_empty): Likewise.
(ipa_make_edge_direct_to_target): Declare.
* ipa-cp.c: Fixed first stage driver name in initial comment,
described devirtualization there too.
(ipcp_analyze_node): Call ipa_analyze_params_uses.
(ipcp_print_all_lattices): Print devirtualization info.
(ipa_set_param_cannot_devirtualize): New function.
(ipcp_initialize_node_lattices): Set cannot_devirtualize when setting
lattice to BOTTOM.
(ipcp_init_stage): Merged into...
(ipcp_generate_summary): ...its caller.
(ipcp_change_tops_to_bottom): Also process type lists.
(ipcp_add_param_type): New function.
(ipcp_copy_types): Likewise.
(ipcp_propagate_types): Likewise.
(ipcp_propagate_stage): Also propagate types.
(ipcp_need_redirect_p): Variable jump_func moved to its scope block.
Also return true if propagated types require it.
(ipcp_update_callgraph): Dump redirection info.
(ipcp_process_devirtualization_opportunities): New function.
(ipcp_const_param_count): Include known type information.
(ipcp_insert_stage): Call ipcp_process_devirtualization_opportunities
on new node. Fixed formatting.
* ipa-prop.c (make_edge_direct_to_target): Renamed to
ipa_make_edge_direct_to_target and changed all callers. Made
externally visible.
(ipa_node_duplication_hook): Duplicate types vector.
* cgraphunit.c (cgraph_redirect_edge_call_stmt_to_callee): Also try to
redirect outgoing calls for which we can't get a decl from the
statement. Check that we can get a decl from the call statement.
* ipa-inline.c (inline_indirect_intraprocedural_analysis): Call
ipa_analyze_params_uses only when ipa-cp is disabled.
* tree-inline.c (get_indirect_callee_fndecl): Removed.
(expand_call_inline): Do not call get_indirect_callee_fndecl.
* params.def (PARAM_DEVIRT_TYPE_LIST_SIZE): New parameter.
* Makefile.in (ipa-cp.o): Add gimple.h to dependencies.
2010-08-05 Uros Bizjak <ubizjak@gmail.com>
* expmed.c (expand_mult_const) <case alg_shift>: Expand shift into
......
......@@ -3013,7 +3013,7 @@ ipa-ref.o : ipa-ref.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
langhooks.h $(GGC_H) $(TARGET_H) $(CGRAPH_H) $(TREE_H) $(TARGET_H) \
$(TREE_FLOW_H) $(TM_H) $(TREE_PASS_H) $(FLAGS_H) $(TREE_H) $(GGC_H)
ipa-cp.o : ipa-cp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TREE_H) $(TARGET_H) $(CGRAPH_H) $(IPA_PROP_H) $(TREE_FLOW_H) \
$(TREE_H) $(TARGET_H) $(GIMPLE_H) $(CGRAPH_H) $(IPA_PROP_H) $(TREE_FLOW_H) \
$(TREE_PASS_H) $(FLAGS_H) $(TIMEVAR_H) $(DIAGNOSTIC_H) $(TREE_DUMP_H) \
$(TREE_INLINE_H) $(FIBHEAP_H) $(PARAMS_H) tree-pretty-print.h
ipa-split.o : ipa-split.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
......
......@@ -2362,14 +2362,18 @@ cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *e)
struct cgraph_node *node;
#endif
if (!decl || decl == e->callee->decl
if (e->indirect_unknown_callee
|| decl == e->callee->decl
/* Don't update call from same body alias to the real function. */
|| cgraph_get_node (decl) == cgraph_get_node (e->callee->decl))
|| (decl && cgraph_get_node (decl) == cgraph_get_node (e->callee->decl)))
return e->call_stmt;
#ifdef ENABLE_CHECKING
node = cgraph_get_node (decl);
gcc_assert (!node || !node->clone.combined_args_to_skip);
if (decl)
{
node = cgraph_get_node (decl);
gcc_assert (!node || !node->clone.combined_args_to_skip);
}
#endif
if (cgraph_dump_file)
......
......@@ -8731,6 +8731,12 @@ loop in the loop nest by a given number of iterations. The strip
length can be changed using the @option{loop-block-tile-size}
parameter. The default value is 51 iterations.
@item devirt-type-list-size
IPA-CP attempts to track all possible types passed to a function's
parameter in order to perform devirtualization.
@option{devirt-type-list-size} is the maximum number of types it
stores per a single formal parameter of a function.
@end table
@end table
......
......@@ -1430,8 +1430,8 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs,
/* If TARGET is an addr_expr of a function declaration, make it the destination
of an indirect edge IE and return the edge. Otherwise, return NULL. */
static struct cgraph_edge *
make_edge_direct_to_target (struct cgraph_edge *ie, tree target)
struct cgraph_edge *
ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target)
{
struct cgraph_node *callee;
......@@ -1484,7 +1484,7 @@ try_make_edge_direct_simple_call (struct cgraph_edge *ie,
else
return NULL;
return make_edge_direct_to_target (ie, target);
return ipa_make_edge_direct_to_target (ie, target);
}
/* Try to find a destination for indirect edge IE that corresponds to a
......@@ -1525,7 +1525,7 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
return NULL;
if (target)
return make_edge_direct_to_target (ie, target);
return ipa_make_edge_direct_to_target (ie, target);
else
return NULL;
}
......@@ -1794,7 +1794,7 @@ ipa_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst,
__attribute__((unused)) void *data)
{
struct ipa_node_params *old_info, *new_info;
int param_count;
int param_count, i;
ipa_check_create_node_params ();
old_info = IPA_NODE_REF (src);
......@@ -1805,8 +1805,15 @@ ipa_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst,
new_info->params = (struct ipa_param_descriptor *)
duplicate_array (old_info->params,
sizeof (struct ipa_param_descriptor) * param_count);
for (i = 0; i < param_count; i++)
new_info->params[i].types = VEC_copy (tree, heap,
old_info->params[i].types);
new_info->ipcp_orig_node = old_info->ipcp_orig_node;
new_info->count_scale = old_info->count_scale;
new_info->called_with_var_arguments = old_info->called_with_var_arguments;
new_info->uses_analysis_done = old_info->uses_analysis_done;
new_info->node_enqueued = old_info->node_enqueued;
}
/* Register our cgraph hooks if they are not already there. */
......
......@@ -133,11 +133,12 @@ struct GTY (()) ipa_jump_func
computed by the interprocedural stage of IPCP.
There are three main values of the lattice:
IPA_TOP - unknown,
IPA_BOTTOM - non constant,
IPA_BOTTOM - variable,
IPA_CONST_VALUE - simple scalar constant,
Cval of formal f will have a constant value if all callsites to this
function have the same constant value passed to f.
Integer and real constants are represented as IPA_CONST_VALUE. */
We also use this type to propagate types accross the call graph for the
purpose of devirtualization. In that case, IPA_CONST_VALUE denotes a known
type, rather than a constant. */
enum ipa_lattice_type
{
IPA_BOTTOM,
......@@ -161,8 +162,14 @@ struct ipa_param_descriptor
struct ipcp_lattice ipcp_lattice;
/* PARAM_DECL of this parameter. */
tree decl;
/* Vector of BINFOs of types that this argument might encounter. NULL
basically means a top value, bottom is marked by the cannot_devirtualize
flag below.*/
VEC (tree, heap) *types;
/* The parameter is used. */
unsigned used : 1;
/* Set when parameter type cannot be used for devirtualization. */
unsigned cannot_devirtualize : 1;
};
/* ipa_node_params stores information related to formal parameters of functions
......@@ -232,6 +239,25 @@ ipa_is_param_used (struct ipa_node_params *info, int i)
return info->params[i].used;
}
/* Return the cannot_devirtualize flag corresponding to the Ith formal
parameter of the function associated with INFO. The corresponding function
to set the flag is ipa_set_param_cannot_devirtualize. */
static inline bool
ipa_param_cannot_devirtualize_p (struct ipa_node_params *info, int i)
{
return info->params[i].cannot_devirtualize;
}
/* Return true iff the vector of possible types of the Ith formal parameter of
the function associated with INFO is empty. */
static inline bool
ipa_param_types_vec_empty (struct ipa_node_params *info, int i)
{
return info->params[i].types == NULL;
}
/* Flag this node as having callers with variable number of arguments. */
static inline void
......@@ -402,6 +428,10 @@ void ipa_initialize_node_params (struct cgraph_node *node);
bool ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
VEC (cgraph_edge_p, heap) **new_edges);
/* Indirect edge and binfo processing. */
struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree);
/* Debugging interface. */
void ipa_print_node_params (FILE *, struct cgraph_node *node);
void ipa_print_all_params (FILE *);
......
......@@ -832,6 +832,12 @@ DEFPARAM (PARAM_IPA_SRA_PTR_GROWTH_FACTOR,
"a pointer to an aggregate with",
2, 0, 0)
DEFPARAM (PARAM_DEVIRT_TYPE_LIST_SIZE,
"devirt-type-list-size",
"Maximum size of a type list associated with each parameter for "
"devirtualization",
8, 0, 0)
/*
Local variables:
mode:c
......
2010-08-05 Martin Jambor <mjambor@suse.cz>
* g++.dg/ipa/devirt-1.C: New test.
* g++.dg/ipa/devirt-2.C: Likewise.
* g++.dg/ipa/devirt-3.C: Likewise.
* g++.dg/ipa/devirt-4.C: Likewise.
* g++.dg/ipa/devirt-5.C: Likewise.
* gcc.dg/ipa/iinline-3.c: Likewise.
2010-08-05 Jie Zhang <jie@codesourcery.com>
PR tree-optimization/45144
......
/* Verify that simple virtual calls are converted to direct calls by ipa-cp. */
/* { dg-do run } */
/* { dg-options "-O3 -fno-early-inlining -fno-inline -fdump-ipa-cp -fdump-tree-optimized" } */
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;
}
static 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;
if (middleman (&b, get_input ()) != 3)
abort ();
return 0;
}
/* { dg-final { scan-ipa-dump "Discovered a virtual call to a known target.*B::foo" "cp" } } */
/* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "optimized"} } */
/* { dg-final { cleanup-ipa-dump "cp" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
/* Verify that simple virtual calls using this pointer are converted
to direct calls by ipa-cp. */
/* { dg-do run } */
/* { dg-options "-O3 -fno-early-inlining -fno-inline -fdump-ipa-cp" } */
extern "C" void abort (void);
class A
{
public:
int data;
virtual int foo (int i);
int middleman (int i)
{
return foo (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,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 (b.middleman (get_input ()) != 3)
abort ();
return 0;
}
/* { dg-final { scan-ipa-dump "Discovered a virtual call to a known target.*B::foo" "cp" } } */
/* { dg-final { cleanup-ipa-dump "cp" } } */
/* Verify that simple virtual calls on an object refrence are
converted to simple calls by ipa-cp. */
/* { dg-do run } */
/* { dg-options "-O3 -fno-early-inlining -fno-inline -fdump-ipa-cp -fdump-tree-optimized" } */
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;
}
static 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;
if (middleman (b, get_input ()) != 3)
abort ();
return 0;
}
/* { dg-final { scan-ipa-dump "Discovered a virtual call to a known target.*B::foo" "cp" } } */
/* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "optimized"} } */
/* { dg-final { cleanup-ipa-dump "cp" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
/* Verify that ipa-co can convert virtual calls to direct ones even
when a typecast to an ancestor is involved along the way. */
/* { dg-do run } */
/* { dg-options "-O3 -fno-early-inlining -fno-inline -fdump-ipa-cp -fdump-tree-optimized" } */
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,noclone)) get_input(void)
{
return 1;
}
static int middleman_1 (class A *obj, int i)
{
return obj->foo (i);
}
static int middleman_2 (class B *obj, int i)
{
return middleman_1 (obj, i);
}
int main (int argc, char *argv[])
{
class B b;
if (middleman_2 (&b, get_input ()) != 3)
abort ();
return 0;
}
/* { dg-final { scan-ipa-dump "Discovered a virtual call to a known target.*B::foo" "cp" } } */
/* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "optimized"} } */
/* { dg-final { cleanup-ipa-dump "cp" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
/* Verify that ipa-cp can convert simple virtual calls to a direct
ones even when a typecast to an ancestor is involved along the way
and that ancestor is not the first one with virtual functions. */
/* { dg-do run } */
/* { dg-options "-O3 -fno-early-inlining -fno-inline -fdump-ipa-cp -fdump-tree-optimized" } */
extern "C" void abort (void);
class Distraction
{
public:
float f;
double d;
Distraction ()
{
f = 8.3;
d = 10.2;
}
virtual float bar (float z);
};
class A
{
public:
int data;
virtual int foo (int i);
};
class B : public Distraction, public A
{
public:
virtual int foo (int i);
};
float Distraction::bar (float z)
{
f += z;
return f/2;
}
int A::foo (int i)
{
return i + 1;
}
int B::foo (int i)
{
return i + 2;
}
int __attribute__ ((noinline,noclone)) get_input(void)
{
return 1;
}
static int middleman_1 (class A *obj, int i)
{
return obj->foo (i);
}
static int middleman_2 (class B *obj, int i)
{
return middleman_1 (obj, i);
}
int main (int argc, char *argv[])
{
class B b;
if (middleman_2 (&b, get_input ()) != 3)
abort ();
return 0;
}
/* { dg-final { scan-ipa-dump "Discovered a virtual call to a known target.*B::foo" "cp" } } */
/* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "optimized"} } */
/* { dg-final { cleanup-ipa-dump "cp" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
/* Verify that call declarations are not redirected according to indirect
inlining edges too early. */
/* { dg-do run } */
/* { dg-options "-O3 -fno-early-inlining" } */
extern void abort (void);
int bar (int k)
{
return k+2;
}
int baz (int k)
{
return k+1;
}
static int foo (int (*p)(int), int i)
{
return p (i+1);
}
int (*g)(int) = baz;
int main (int argc, char *argv[])
{
if (foo (bar, 0) != 3)
abort ();
if (foo (g, 1) != 3)
abort ();
return 0;
}
......@@ -3707,20 +3707,6 @@ add_local_variables (struct function *callee, struct function *caller,
}
}
/* Fetch callee declaration from the call graph edge going from NODE and
associated with STMR call statement. Return NULL_TREE if not found. */
static tree
get_indirect_callee_fndecl (struct cgraph_node *node, gimple stmt)
{
struct cgraph_edge *cs;
cs = cgraph_edge (node, stmt);
if (cs && !cs->indirect_unknown_callee)
return cs->callee->decl;
return NULL_TREE;
}
/* If STMT is a GIMPLE_CALL, replace it with its inline expansion. */
static bool
......@@ -3754,11 +3740,7 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
If we cannot, then there is no hope of inlining the function. */
fn = gimple_call_fndecl (stmt);
if (!fn)
{
fn = get_indirect_callee_fndecl (id->dst_node, stmt);
if (!fn)
goto egress;
}
goto egress;
/* Turn forward declarations into real ones. */
fn = cgraph_node (fn)->decl;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment