Commit b258210c by Martin Jambor Committed by Martin Jambor

cgraph.h (cgraph_indirect_call_info): New fields anc_offset, otr_token and polymorphic.

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

	* cgraph.h (cgraph_indirect_call_info): New fields anc_offset,
	otr_token and polymorphic.
	* cgraph.c (cgraph_create_indirect_edge): Inilialize the above fields.
	(cgraph_clone_edge): Copy the above fields.
	* tree.c (get_binfo_at_offset): New function.
	* tree.h (get_binfo_at_offset): Declare.
	* ipa-prop.h (enum jump_func_type): Added known_type jump function
	type, reordered items, updated comments.
	(union jump_func_value): Added base_type field, reordered fields.
	(enum ipa_lattice_type): Moved down in the file.
	(struct ipa_param_descriptor): New field polymorphic.
	(ipa_is_param_polymorphic): New function.
	* ipa-prop.c: Include gimple.h and gimple-fold.h.
	(ipa_print_node_jump_functions): Print known type jump functions.
	(compute_complex_pass_through): Renamed to...
	(compute_complex_assign_jump_func): this.
	(compute_complex_ancestor_jump_func): New function.
	(compute_known_type_jump_func): Likewise.
	(compute_scalar_jump_functions): Create known type and complex ancestor
	jump functions.
	(ipa_note_param_call): New parameter polymorphic, set the corresponding
	flag in the call note accordingly.
	(ipa_analyze_call_uses): Renamed to...
	(ipa_analyze_indirect_call_uses): this.  New parameter target, define
	variable var only in the block where it is used.
	(ipa_analyze_virtual_call_uses): New function.
	(ipa_analyze_call_uses): Likewise.
	(combine_known_type_and_ancestor_jfs): Likewise.
	(update_jump_functions_after_inlining): Implemented handling of a
	number of new jump function types combination.
	(print_edge_addition_message): Removed.
	(make_edge_direct_to_target): New function.
	(try_make_edge_direct_simple_call): Likewise.
	(try_make_edge_direct_virtual_call): Likewise.
	(update_call_notes_after_inlining): Renamed to...
	(update_indirect_edges_after_inlining): this.  Moved edge creation for
	indirect calls to try_make_edge_direct_simple_call, also calls
	try_make_edge_direct_virtual_call for virtual calls.
	(ipa_print_node_params): Changed the header message.
	(ipa_write_jump_function): Stream also known type jump functions.
	(ipa_read_jump_function): Likewise.
	(ipa_write_indirect_edge_info): Stream new fields in
	cgraph_indirect_call_info.
	(ipa_read_indirect_edge_info): Likewise.
	* Makefile.in (ipa-prop.o): Add dependency to GIMPLE_H and
	GIMPLE_FOLD_H.

	* testsuite/g++.dg/ipa/ivinline-1.C: New test.
	* testsuite/g++.dg/ipa/ivinline-2.C: New test.
	* testsuite/g++.dg/ipa/ivinline-3.C: New test.
	* testsuite/g++.dg/ipa/ivinline-4.C: New test.
	* testsuite/g++.dg/ipa/ivinline-5.C: New test.
	* testsuite/g++.dg/ipa/ivinline-6.C: New test.

From-SVN: r159507
parent d15bac21
2010-05-17 Martin Jambor <mjambor@suse.cz>
* cgraph.h (cgraph_indirect_call_info): New fields anc_offset,
otr_token and polymorphic.
* cgraph.c (cgraph_create_indirect_edge): Inilialize the above fields.
(cgraph_clone_edge): Copy the above fields.
* tree.c (get_binfo_at_offset): New function.
* tree.h (get_binfo_at_offset): Declare.
* ipa-prop.h (enum jump_func_type): Added known_type jump function
type, reordered items, updated comments.
(union jump_func_value): Added base_type field, reordered fields.
(enum ipa_lattice_type): Moved down in the file.
(struct ipa_param_descriptor): New field polymorphic.
(ipa_is_param_polymorphic): New function.
* ipa-prop.c: Include gimple.h and gimple-fold.h.
(ipa_print_node_jump_functions): Print known type jump functions.
(compute_complex_pass_through): Renamed to...
(compute_complex_assign_jump_func): this.
(compute_complex_ancestor_jump_func): New function.
(compute_known_type_jump_func): Likewise.
(compute_scalar_jump_functions): Create known type and complex ancestor
jump functions.
(ipa_note_param_call): New parameter polymorphic, set the corresponding
flag in the call note accordingly.
(ipa_analyze_call_uses): Renamed to...
(ipa_analyze_indirect_call_uses): this. New parameter target, define
variable var only in the block where it is used.
(ipa_analyze_virtual_call_uses): New function.
(ipa_analyze_call_uses): Likewise.
(combine_known_type_and_ancestor_jfs): Likewise.
(update_jump_functions_after_inlining): Implemented handling of a
number of new jump function types combination.
(print_edge_addition_message): Removed.
(make_edge_direct_to_target): New function.
(try_make_edge_direct_simple_call): Likewise.
(try_make_edge_direct_virtual_call): Likewise.
(update_call_notes_after_inlining): Renamed to...
(update_indirect_edges_after_inlining): this. Moved edge creation for
indirect calls to try_make_edge_direct_simple_call, also calls
try_make_edge_direct_virtual_call for virtual calls.
(ipa_print_node_params): Changed the header message.
(ipa_write_jump_function): Stream also known type jump functions.
(ipa_read_jump_function): Likewise.
(ipa_write_indirect_edge_info): Stream new fields in
cgraph_indirect_call_info.
(ipa_read_indirect_edge_info): Likewise.
* Makefile.in (ipa-prop.o): Add dependency to GIMPLE_H and
GIMPLE_FOLD_H.
2010-05-17 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
* config/i386/sol2.h (TARGET_SUN_TLS): Remove duplicate definition.
......
......@@ -2896,7 +2896,7 @@ ipa.o : ipa.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(CGRAPH_H) \
ipa-prop.o : ipa-prop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
langhooks.h $(GGC_H) $(TARGET_H) $(CGRAPH_H) $(IPA_PROP_H) $(DIAGNOSTIC_H) \
$(TREE_FLOW_H) $(TM_H) $(TREE_PASS_H) $(FLAGS_H) $(TREE_H) \
$(TREE_INLINE_H) $(TIMEVAR_H)
$(TREE_INLINE_H) $(GIMPLE_H) $(GIMPLE_FOLD_H) $(TIMEVAR_H)
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)
......
......@@ -1045,7 +1045,7 @@ cgraph_create_indirect_edge (struct cgraph_node *caller, gimple call_stmt,
edge->indirect_unknown_callee = 1;
initialize_inline_failed (edge);
edge->indirect_info = GGC_NEW (struct cgraph_indirect_call_info);
edge->indirect_info = GGC_CNEW (struct cgraph_indirect_call_info);
edge->indirect_info->param_index = -1;
edge->indirect_info->ecf_flags = ecf_flags;
......@@ -2026,7 +2026,7 @@ cgraph_clone_edge (struct cgraph_edge *e, struct cgraph_node *n,
e->indirect_info->ecf_flags,
count, freq,
e->loop_nest + loop_nest);
new_edge->indirect_info->param_index = e->indirect_info->param_index;
*new_edge->indirect_info = *e->indirect_info;
}
}
else
......
......@@ -378,10 +378,21 @@ typedef enum {
struct GTY(()) cgraph_indirect_call_info
{
/* Offset accumulated from ancestor jump functions of inlined call graph
edges. */
HOST_WIDE_INT anc_offset;
/* OBJ_TYPE_REF_TOKEN of a polymorphic call (if polymorphic is set). */
HOST_WIDE_INT otr_token;
/* Type of the object from OBJ_TYPE_REF_OBJECT. */
tree otr_type;
/* Index of the parameter that is called. */
int param_index;
/* ECF flags determined from the caller. */
int ecf_flags;
/* Set when the call is a virtual call with the parameter being the
associated object pointer rather than a simple direct call. */
unsigned polymorphic : 1;
};
struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"))) cgraph_edge {
......
......@@ -39,38 +39,40 @@ along with GCC; see the file COPYING3. If not see
argument.
Unknown - neither of the above.
IPA_JF_CONST_MEMBER_PTR stands for C++ member pointers, other constants are
represented with IPA_JF_CONST.
IPA_JF_CONST_MEMBER_PTR stands for C++ member pointers, it is a special
constant in this regard. Other constants are represented with IPA_JF_CONST.
IPA_JF_ANCESTOR is a special pass-through jump function, which means that
the result is an address of a part of the object pointed to by the formal
parameter to which the function refers. It is mainly intended to represent
getting addresses of of ancestor fields in C++
(e.g. &this_1(D)->D.1766.D.1756). Note that if the original pointer is
NULL, ancestor jump function must behave like a simple pass-through.
Other pass-through functions can either simply pass on an unchanged formal
parameter or can apply one simple binary operation to it (such jump
functions are called polynomial).
IPA_JF_KNOWN_TYPE is a special type of an "unknown" function that applies
only to pointer parameters. It means that even though we cannot prove that
the passed value is an interprocedural constant, we still know the exact
type of the containing object which may be valuable for devirtualization.
Jump functions are computed in ipa-prop.c by function
update_call_notes_after_inlining. Some information can be lost and jump
functions degraded accordingly when inlining, see
update_call_notes_after_inlining in the same file. */
In addition to "ordinary" pass through functions represented by
IPA_JF_PASS_THROUGH, IPA_JF_ANCESTOR represents getting addresses of of
ancestor fields in C++ (e.g. &this_1(D)->D.1766.D.1756). */
enum jump_func_type
{
IPA_JF_UNKNOWN = 0, /* newly allocated and zeroed jump functions default */
IPA_JF_CONST,
IPA_JF_CONST_MEMBER_PTR,
IPA_JF_PASS_THROUGH,
IPA_JF_ANCESTOR
IPA_JF_KNOWN_TYPE, /* represented by field base_binfo */
IPA_JF_CONST, /* represented by field costant */
IPA_JF_CONST_MEMBER_PTR, /* represented by field member_cst */
IPA_JF_PASS_THROUGH, /* represented by field pass_through */
IPA_JF_ANCESTOR /* represented by field ancestor */
};
/* All formal parameters in the program have a lattice associated with it
computed by the interprocedural stage of IPCP.
There are three main values of the lattice:
IPA_TOP - unknown,
IPA_BOTTOM - non constant,
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. */
enum ipa_lattice_type
{
IPA_BOTTOM,
IPA_CONST_VALUE,
IPA_TOP
};
/* Structure holding data required to describe a pass-through jump function. */
struct GTY(()) ipa_pass_through_data
......@@ -87,8 +89,8 @@ struct GTY(()) ipa_pass_through_data
enum tree_code operation;
};
/* Structure holding data required to describe and ancestor pass throu
funkci. */
/* Structure holding data required to describe an ancestor pass-through
jump function. */
struct GTY(()) ipa_ancestor_jf_data
{
......@@ -119,13 +121,30 @@ struct GTY (()) ipa_jump_func
functions and member_cst holds constant c++ member functions. */
union jump_func_value
{
tree GTY ((tag ("IPA_JF_KNOWN_TYPE"))) base_binfo;
tree GTY ((tag ("IPA_JF_CONST"))) constant;
struct ipa_member_ptr_cst GTY ((tag ("IPA_JF_CONST_MEMBER_PTR"))) member_cst;
struct ipa_pass_through_data GTY ((tag ("IPA_JF_PASS_THROUGH"))) pass_through;
struct ipa_ancestor_jf_data GTY ((tag ("IPA_JF_ANCESTOR"))) ancestor;
struct ipa_member_ptr_cst GTY ((tag ("IPA_JF_CONST_MEMBER_PTR"))) member_cst;
} GTY ((desc ("%1.type"))) value;
};
/* All formal parameters in the program have a lattice associated with it
computed by the interprocedural stage of IPCP.
There are three main values of the lattice:
IPA_TOP - unknown,
IPA_BOTTOM - non constant,
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. */
enum ipa_lattice_type
{
IPA_BOTTOM,
IPA_CONST_VALUE,
IPA_TOP
};
/* All formal parameters in the program have a cval computed by
the interprocedural stage of IPCP. See enum ipa_lattice_type for
the various types of lattices supported */
......
2010-05-17 Martin Jambor <mjambor@suse.cz>
* g++.dg/ipa/ivinline-1.C: New test.
* g++.dg/ipa/ivinline-2.C: New test.
* g++.dg/ipa/ivinline-3.C: New test.
* g++.dg/ipa/ivinline-4.C: New test.
* g++.dg/ipa/ivinline-5.C: New test.
* g++.dg/ipa/ivinline-6.C: New test.
2010-05-17 Dodji Seketeli <dodji@redhat.com>
Jason Merrill <jason@redhat.com>
......
/* Verify that simple virtual calls are inlined even without early
inlining. */
/* { 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 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 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 ()) != 3)
abort ();
return 0;
}
/* { dg-final { scan-ipa-dump "B::foo\[^\\n\]*inline copy in int main" "inline" } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */
/* Verify that simple virtual calls using this pointer are inlined
even without early inlining.. */
/* { 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 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 "B::foo\[^\\n\]*inline copy in int main" "inline" } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */
/* Verify that simple virtual calls on an object refrence are inlined
even without early inlining. */
/* { 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 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 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 ()) != 3)
abort ();
return 0;
}
/* { dg-final { scan-ipa-dump "B::foo\[^\\n\]*inline copy in int main" "inline" } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */
/* Verify that simple virtual calls are inlined even without early
inlining, even when a typecast to an ancestor is involved along the
way. */
/* { 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 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;
int i;
for (i = 0; i < get_input (); i++)
if (middleman_2 (&b, get_input ()) != 3)
abort ();
return 0;
}
/* { dg-final { scan-ipa-dump "B::foo\[^\\n\]*inline copy in int main" "inline" } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */
/* Verify that virtual call inlining does not pick a wrong method when
there is a user defined ancestor in an object. */
/* { 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 foo (int i);
};
class B : public A
{
public:
class A confusion;
virtual int foo (int i);
};
int A::foo (int i)
{
return i + 1;
}
int B::foo (int i)
{
return i + 2;
}
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, j = get_input ();
for (i = 0; i < j; i++)
if ((middleman (&b, j) + 100 * middleman (&b.confusion, j)) != 203)
abort ();
return 0;
}
/* { dg-final { scan-ipa-dump "A::foo\[^\\n\]*inline copy in int main" "inline" } } */
/* { dg-final { scan-ipa-dump "B::foo\[^\\n\]*inline copy in int main" "inline" } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */
/* Verify that virtual call inlining works also when it has to get the
type from an ipa invariant and that even in this case it does not
pick a wrong method when there is a user defined ancestor in an
object. */
/* { 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 foo (int i);
};
class B : public A
{
public:
class A confusion;
virtual int foo (int i);
};
int A::foo (int i)
{
return i + 1;
}
int B::foo (int i)
{
return i + 2;
}
int middleman (class A *obj, int i)
{
return obj->foo (i);
}
int __attribute__ ((noinline,noclone)) get_input(void)
{
return 1;
}
class B b;
int main (int argc, char *argv[])
{
int i, j = get_input ();
for (i = 0; i < j; i++)
if ((middleman (&b, j) + 100 * middleman (&b.confusion, j)) != 203)
abort ();
return 0;
}
/* { dg-final { scan-ipa-dump "A::foo\[^\\n\]*inline copy in int main" "inline" } } */
/* { dg-final { scan-ipa-dump "B::foo\[^\\n\]*inline copy in int main" "inline" } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */
/* Verify that simple virtual calls are inlined even without early
inlining, 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 -fdump-ipa-inline -fno-early-inlining -fno-ipa-cp" } */
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;
int i;
for (i = 0; i < get_input (); i++)
if (middleman_2 (&b, get_input ()) != 3)
abort ();
return 0;
}
/* { dg-final { scan-ipa-dump "B::foo\[^\\n\]*inline copy in int main" "inline" } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */
......@@ -10779,4 +10779,60 @@ lhd_gcc_personality (void)
return gcc_eh_personality_decl;
}
/* Try to find a base info of BINFO that would have its field decl at offset
OFFSET within the BINFO type and which is of EXPECTED_TYPE. If it can be
found, return, otherwise return NULL_TREE. */
tree
get_binfo_at_offset (tree binfo, HOST_WIDE_INT offset, tree expected_type)
{
tree type;
if (offset == 0)
return binfo;
type = TREE_TYPE (binfo);
while (offset > 0)
{
tree base_binfo, found_binfo;
HOST_WIDE_INT pos, size;
tree fld;
int i;
if (TREE_CODE (type) != RECORD_TYPE)
return NULL_TREE;
for (fld = TYPE_FIELDS (type); fld; fld = TREE_CHAIN (fld))
{
if (TREE_CODE (fld) != FIELD_DECL)
continue;
pos = int_bit_position (fld);
size = tree_low_cst (DECL_SIZE (fld), 1);
if (pos <= offset && (pos + size) > offset)
break;
}
if (!fld)
return NULL_TREE;
found_binfo = NULL_TREE;
for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
if (TREE_TYPE (base_binfo) == TREE_TYPE (fld))
{
found_binfo = base_binfo;
break;
}
if (!found_binfo)
return NULL_TREE;
type = TREE_TYPE (fld);
binfo = found_binfo;
offset -= pos;
}
if (type != expected_type)
return NULL_TREE;
return binfo;
}
#include "gt-tree.h"
......@@ -5073,6 +5073,8 @@ extern location_t tree_nonartificial_location (tree);
extern tree block_ultimate_origin (const_tree);
extern tree get_binfo_at_offset (tree, HOST_WIDE_INT, tree);
/* In tree-nested.c */
extern tree build_addr (tree, tree);
......
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