cgraph.h (cgraph_indirect_call_info): Field anc_offse renamd to offset, updated all users.

2012-08-09  Martin Jambor  <mjambor@suse.cz>

	* cgraph.h (cgraph_indirect_call_info): Field anc_offse renamd to
	offset, updated all users.  New field agg_contents.
	* ipa-prop.h (jump_func_type): Removed IPA_JF_CONST_MEMBER_PTR.
	(ipa_pass_through_data): New field agg_preserved.
	(ipa_ancestor_jf_data): Likewise.
	(ipa_member_ptr_cst): Removed.
	(ipa_agg_jf_item): New type.
	(ipa_agg_jump_function): Likewise.
	(ipa_jump_func): New field agg.  Removed field member_cst.
	(ipa_get_jf_pass_through_agg_preserved): New function.
	(ipa_get_jf_ancestor_agg_preserved): Likewise.
	(ipa_get_jf_member_ptr_pfn): Removed.
	(ipa_find_agg_cst_for_param): Declare.
	(ipa_load_from_parm_agg): Likewise.
	* ipa-prop.c (param_analysis_info): Fields modified and
	visited_statements rename to parm_modified and parm_visited_statements
	respectively, added fields ref_modified, ref_visited_statements,
	pt_modified and pt_visited_statements.
	(ipa_print_node_jump_functions_for_edge): Do not dump const member
	functions.  Dump agg_preserved flags and aggregate jump functions.
	(ipa_set_jf_simple_pass_through): Set also agg_preserved.
	(ipa_set_ancestor_jf): Likewise.
	(ipa_set_jf_arith_pass_through): Clear agg_preserved.
	(ipa_set_jf_member_ptr_cst): Removed.
	(is_parm_modified_before_stmt): Logic reversed, renamed to
	parm_preserved_before_stmt_p.  Cache visited bitmap only for
	naked DECL parameters.  All callers updated.
	(load_from_unmodified_param): Allow NULL parms_ainfo.
	(parm_ref_data_preserved_p): New function.
	(parm_ref_data_pass_through_p): Likewise.
	(ipa_load_from_parm_agg_1): Likewise.
	(ipa_load_from_parm_agg): Likewise.
	(compute_complex_assign_jump_func): Check if aggregate contents are
	preserved.
	(compute_complex_ancestor_jump_func): Likewise.
	(compute_scalar_jump_functions): Removed.
	(type_like_member_ptr_p): Also check field position are known and
	sane.
	(compute_pass_through_member_ptrs): Removed.
	(determine_cst_member_ptr): Likewise.
	(ipa_known_agg_contents_list): New type.
	(determine_known_aggregate_parts): New function.
	(compute_cst_member_ptr_arguments): Removed.
	(ipa_compute_jump_functions_for_edge): Compute all kinds of jump
	functions (scalar, aggregate and member pointer).
	(ipa_get_member_ptr_load_param): Incorporate into
	ipa_get_stmt_member_ptr_load_param, also pass back an offset.
	(ipa_note_param_call): Clear agg_contents.
	(ipa_analyze_indirect_call_uses): Also look for simple pointers loaded
	from aggregates.  In such cases, store offset of the called field.
	(ipa_analyze_node): Initialize new fields of param_analysis_info.
	(update_jump_functions_after_inlining): Handle aggregate contents.
	(ipa_find_agg_cst_for_param): New function.
	(try_make_edge_direct_simple_call): Handle called aggregate values.
	(update_indirect_edges_after_inlining): Make sure aggregate preserving
	jump functions comply with type compatibility requirements.
	(ipa_edge_duplication_hook): Copy also aggregate jump functions.
	(ipa_write_jump_function): Stream agg_preserved flags and aggregate
	jump functions.  Do not stream member pointer constant jump functions.
	(ipa_read_jump_function): Likewise.
	(ipa_write_indirect_edge_info): Stream new cgraph_indirect_call_info
	fields.
	(ipa_read_indirect_edge_info): Likewise.

	* testsuite/gcc.dg/ipa/iinline-4.c: New test.
	* testsuite/gcc.dg/ipa/iinline-5.c: Likewise.
	* testsuite/gcc.dg/ipa/iinline-6.c: Likewise.
	* testsuite/gcc.dg/ipa/iinline-7.c: Likewise.
	* testsuite/gcc.dg/lto/20120723_0.c: Likewise.
	* testsuite/gcc.dg/lto/20120723_1.c: Likewise.

From-SVN: r190260
This commit is contained in:
Martin Jambor 2012-08-09 18:05:46 +02:00 committed by Martin Jambor
parent b67b3838e9
commit 8b7773a4ee
12 changed files with 1520 additions and 328 deletions

View File

@ -1,3 +1,69 @@
2012-08-09 Martin Jambor <mjambor@suse.cz>
* cgraph.h (cgraph_indirect_call_info): Field anc_offse renamd to
offset, updated all users. New field agg_contents.
* ipa-prop.h (jump_func_type): Removed IPA_JF_CONST_MEMBER_PTR.
(ipa_pass_through_data): New field agg_preserved.
(ipa_ancestor_jf_data): Likewise.
(ipa_member_ptr_cst): Removed.
(ipa_agg_jf_item): New type.
(ipa_agg_jump_function): Likewise.
(ipa_jump_func): New field agg. Removed field member_cst.
(ipa_get_jf_pass_through_agg_preserved): New function.
(ipa_get_jf_ancestor_agg_preserved): Likewise.
(ipa_get_jf_member_ptr_pfn): Removed.
(ipa_find_agg_cst_for_param): Declare.
(ipa_load_from_parm_agg): Likewise.
* ipa-prop.c (param_analysis_info): Fields modified and
visited_statements rename to parm_modified and parm_visited_statements
respectively, added fields ref_modified, ref_visited_statements,
pt_modified and pt_visited_statements.
(ipa_print_node_jump_functions_for_edge): Do not dump const member
functions. Dump agg_preserved flags and aggregate jump functions.
(ipa_set_jf_simple_pass_through): Set also agg_preserved.
(ipa_set_ancestor_jf): Likewise.
(ipa_set_jf_arith_pass_through): Clear agg_preserved.
(ipa_set_jf_member_ptr_cst): Removed.
(is_parm_modified_before_stmt): Logic reversed, renamed to
parm_preserved_before_stmt_p. Cache visited bitmap only for
naked DECL parameters. All callers updated.
(load_from_unmodified_param): Allow NULL parms_ainfo.
(parm_ref_data_preserved_p): New function.
(parm_ref_data_pass_through_p): Likewise.
(ipa_load_from_parm_agg_1): Likewise.
(ipa_load_from_parm_agg): Likewise.
(compute_complex_assign_jump_func): Check if aggregate contents are
preserved.
(compute_complex_ancestor_jump_func): Likewise.
(compute_scalar_jump_functions): Removed.
(type_like_member_ptr_p): Also check field position are known and
sane.
(compute_pass_through_member_ptrs): Removed.
(determine_cst_member_ptr): Likewise.
(ipa_known_agg_contents_list): New type.
(determine_known_aggregate_parts): New function.
(compute_cst_member_ptr_arguments): Removed.
(ipa_compute_jump_functions_for_edge): Compute all kinds of jump
functions (scalar, aggregate and member pointer).
(ipa_get_member_ptr_load_param): Incorporate into
ipa_get_stmt_member_ptr_load_param, also pass back an offset.
(ipa_note_param_call): Clear agg_contents.
(ipa_analyze_indirect_call_uses): Also look for simple pointers loaded
from aggregates. In such cases, store offset of the called field.
(ipa_analyze_node): Initialize new fields of param_analysis_info.
(update_jump_functions_after_inlining): Handle aggregate contents.
(ipa_find_agg_cst_for_param): New function.
(try_make_edge_direct_simple_call): Handle called aggregate values.
(update_indirect_edges_after_inlining): Make sure aggregate preserving
jump functions comply with type compatibility requirements.
(ipa_edge_duplication_hook): Copy also aggregate jump functions.
(ipa_write_jump_function): Stream agg_preserved flags and aggregate
jump functions. Do not stream member pointer constant jump functions.
(ipa_read_jump_function): Likewise.
(ipa_write_indirect_edge_info): Stream new cgraph_indirect_call_info
fields.
(ipa_read_indirect_edge_info): Likewise.
2012-08-09 Oleg Endo <olegendo@gcc.gnu.org> 2012-08-09 Oleg Endo <olegendo@gcc.gnu.org>
PR target/39423 PR target/39423

View File

@ -338,9 +338,11 @@ typedef enum cgraph_inline_failed_enum {
struct GTY(()) cgraph_indirect_call_info struct GTY(()) cgraph_indirect_call_info
{ {
/* Offset accumulated from ancestor jump functions of inlined call graph /* When polymorphic is set, this field contains offset where the object which
edges. */ was actually used in the polymorphic resides within a larger structure.
HOST_WIDE_INT anc_offset; If agg_contents is set, the field contains the offset within the aggregate
from which the address to call was loaded. */
HOST_WIDE_INT offset;
/* OBJ_TYPE_REF_TOKEN of a polymorphic call (if polymorphic is set). */ /* OBJ_TYPE_REF_TOKEN of a polymorphic call (if polymorphic is set). */
HOST_WIDE_INT otr_token; HOST_WIDE_INT otr_token;
/* Type of the object from OBJ_TYPE_REF_OBJECT. */ /* Type of the object from OBJ_TYPE_REF_OBJECT. */
@ -353,6 +355,12 @@ struct GTY(()) cgraph_indirect_call_info
/* Set when the call is a virtual call with the parameter being the /* Set when the call is a virtual call with the parameter being the
associated object pointer rather than a simple direct call. */ associated object pointer rather than a simple direct call. */
unsigned polymorphic : 1; unsigned polymorphic : 1;
/* Set when the call is a call of a pointer loaded from contents of an
aggregate at offset. */
unsigned agg_contents : 1;
/* When the previous bit is set, this one determines whether the destination
is loaded from a parameter passed by reference. */
unsigned by_ref : 1;
}; };
struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"))) cgraph_edge { struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"))) cgraph_edge {

View File

@ -1107,7 +1107,7 @@ ipa_get_indirect_edge_target (struct cgraph_edge *ie,
} }
token = ie->indirect_info->otr_token; token = ie->indirect_info->otr_token;
anc_offset = ie->indirect_info->anc_offset; anc_offset = ie->indirect_info->offset;
otr_type = ie->indirect_info->otr_type; otr_type = ie->indirect_info->otr_type;
t = VEC_index (tree, known_vals, param_index); t = VEC_index (tree, known_vals, param_index);

File diff suppressed because it is too large Load Diff

View File

@ -44,10 +44,6 @@ along with GCC; see the file COPYING3. If not see
argument. argument.
Unknown - neither of the above. Unknown - neither of the above.
IPA_JF_CONST_MEMBER_PTR stands for C++ member pointers, it is a special
constant in this regard because it is in fact a structure consisting of two
values. Other constants are represented with IPA_JF_CONST.
IPA_JF_ANCESTOR is a special pass-through jump function, which means that 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 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 parameter to which the function refers. It is mainly intended to represent
@ -74,7 +70,6 @@ enum jump_func_type
IPA_JF_UNKNOWN = 0, /* newly allocated and zeroed jump functions default */ IPA_JF_UNKNOWN = 0, /* newly allocated and zeroed jump functions default */
IPA_JF_KNOWN_TYPE, /* represented by field known_type */ IPA_JF_KNOWN_TYPE, /* represented by field known_type */
IPA_JF_CONST, /* represented by field costant */ 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_PASS_THROUGH, /* represented by field pass_through */
IPA_JF_ANCESTOR /* represented by field ancestor */ IPA_JF_ANCESTOR /* represented by field ancestor */
}; };
@ -104,6 +99,13 @@ struct GTY(()) ipa_pass_through_data
arithmetic operation where the caller's parameter is the first operand and arithmetic operation where the caller's parameter is the first operand and
operand field from this structure is the second one. */ operand field from this structure is the second one. */
enum tree_code operation; enum tree_code operation;
/* When the passed value is a pointer, it is set to true only when we are
certain that no write to the object it points to has occurred since the
caller functions started execution, except for changes noted in the
aggregate part of the jump function (see description of
ipa_agg_jump_function). The flag is used only when the operation is
NOP_EXPR. */
bool agg_preserved;
}; };
/* Structure holding data required to describe an ancestor pass-through /* Structure holding data required to describe an ancestor pass-through
@ -117,21 +119,56 @@ struct GTY(()) ipa_ancestor_jf_data
tree type; tree type;
/* Number of the caller's formal parameter being passed. */ /* Number of the caller's formal parameter being passed. */
int formal_id; int formal_id;
/* Flag with the same meaning like agg_preserve in ipa_pass_through_data. */
bool agg_preserved;
}; };
/* Structure holding a C++ member pointer constant. Holds a pointer to the /* An element in an aggegate part of a jump function describing a known value
method and delta offset. */ at a given offset. When it is part of a pass-through jump function with
struct GTY(()) ipa_member_ptr_cst agg_preserved set or an ancestor jump function with agg_preserved set, all
unlisted positions are assumed to be preserved but the value can be a type
node, which means that the particular piece (starting at offset and having
the size of the type) is clobbered with an unknown value. When
agg_preserved is false or the type of the containing jump function is
different, all unlisted parts are assumed to be unknown and all values must
fullfill is_gimple_ip_invariant. */
typedef struct GTY(()) ipa_agg_jf_item
{ {
tree pfn; /* The offset at which the known value is located within the aggregate. */
tree delta; HOST_WIDE_INT offset;
/* The known constant or type if this is a clobber. */
tree value;
} ipa_agg_jf_item_t;
DEF_VEC_O (ipa_agg_jf_item_t);
DEF_VEC_ALLOC_O (ipa_agg_jf_item_t, gc);
/* Aggregate jump function - i.e. description of contents of aggregates passed
either by reference or value. */
struct GTY(()) ipa_agg_jump_function
{
/* Description of the individual items. */
VEC (ipa_agg_jf_item_t, gc) *items;
/* True if the data was passed by reference (as opposed to by value). */
bool by_ref;
}; };
typedef struct ipa_agg_jump_function *ipa_agg_jump_function_p;
DEF_VEC_P (ipa_agg_jump_function_p);
DEF_VEC_ALLOC_P (ipa_agg_jump_function_p, heap);
/* A jump function for a callsite represents the values passed as actual /* A jump function for a callsite represents the values passed as actual
arguments of the callsite. See enum jump_func_type for the various arguments of the callsite. See enum jump_func_type for the various
types of jump functions supported. */ types of jump functions supported. */
typedef struct GTY (()) ipa_jump_func typedef struct GTY (()) ipa_jump_func
{ {
/* Aggregate contants description. See struct ipa_agg_jump_function and its
description. */
struct ipa_agg_jump_function agg;
enum jump_func_type type; enum jump_func_type type;
/* Represents a value of a jump function. pass_through is used only in jump /* Represents a value of a jump function. pass_through is used only in jump
function context. constant represents the actual constant in constant jump function context. constant represents the actual constant in constant jump
@ -140,7 +177,6 @@ typedef struct GTY (()) ipa_jump_func
{ {
struct ipa_known_type_data GTY ((tag ("IPA_JF_KNOWN_TYPE"))) known_type; struct ipa_known_type_data GTY ((tag ("IPA_JF_KNOWN_TYPE"))) known_type;
tree GTY ((tag ("IPA_JF_CONST"))) constant; 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_pass_through_data GTY ((tag ("IPA_JF_PASS_THROUGH"))) pass_through;
struct ipa_ancestor_jf_data GTY ((tag ("IPA_JF_ANCESTOR"))) ancestor; struct ipa_ancestor_jf_data GTY ((tag ("IPA_JF_ANCESTOR"))) ancestor;
} GTY ((desc ("%1.type"))) value; } GTY ((desc ("%1.type"))) value;
@ -214,6 +250,15 @@ ipa_get_jf_pass_through_operation (struct ipa_jump_func *jfunc)
return jfunc->value.pass_through.operation; return jfunc->value.pass_through.operation;
} }
/* Return the agg_preserved flag of a pass through jump functin JFUNC. */
static inline bool
ipa_get_jf_pass_through_agg_preserved (struct ipa_jump_func *jfunc)
{
gcc_checking_assert (jfunc->type == IPA_JF_PASS_THROUGH);
return jfunc->value.pass_through.agg_preserved;
}
/* Return the offset of an ancestor jump function JFUNC. */ /* Return the offset of an ancestor jump function JFUNC. */
static inline HOST_WIDE_INT static inline HOST_WIDE_INT
@ -242,13 +287,13 @@ ipa_get_jf_ancestor_formal_id (struct ipa_jump_func *jfunc)
return jfunc->value.ancestor.formal_id; return jfunc->value.ancestor.formal_id;
} }
/* Return the pfn part of a member pointer constant jump function JFUNC. */ /* Return the agg_preserved flag of an ancestor jump functin JFUNC. */
static inline tree static inline bool
ipa_get_jf_member_ptr_pfn (struct ipa_jump_func *jfunc) ipa_get_jf_ancestor_agg_preserved (struct ipa_jump_func *jfunc)
{ {
gcc_checking_assert (jfunc->type == IPA_JF_CONST_MEMBER_PTR); gcc_checking_assert (jfunc->type == IPA_JF_ANCESTOR);
return jfunc->value.member_cst.pfn; return jfunc->value.ancestor.agg_preserved;
} }
/* Summary describing a single formal parameter. */ /* Summary describing a single formal parameter. */
@ -456,6 +501,12 @@ struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree);
/* Functions related to both. */ /* Functions related to both. */
void ipa_analyze_node (struct cgraph_node *); void ipa_analyze_node (struct cgraph_node *);
/* Aggregate jump function related functions. */
tree ipa_find_agg_cst_for_param (struct ipa_agg_jump_function *, HOST_WIDE_INT,
bool);
bool ipa_load_from_parm_agg (struct ipa_node_params *, gimple, tree, int *,
HOST_WIDE_INT *, bool *);
/* Debugging interface. */ /* Debugging interface. */
void ipa_print_node_params (FILE *, struct cgraph_node *node); void ipa_print_node_params (FILE *, struct cgraph_node *node);
void ipa_print_all_params (FILE *); void ipa_print_all_params (FILE *);

View File

@ -1,3 +1,12 @@
2012-08-09 Martin Jambor <mjambor@suse.cz>
* gcc.dg/ipa/iinline-4.c: New test.
* gcc.dg/ipa/iinline-5.c: Likewise.
* gcc.dg/ipa/iinline-6.c: Likewise.
* gcc.dg/ipa/iinline-7.c: Likewise.
* gcc.dg/lto/20120723_0.c: Likewise.
* gcc.dg/lto/20120723_1.c: Likewise.
2012-08-09 Oleg Endo <olegendo@gcc.gnu.org> 2012-08-09 Oleg Endo <olegendo@gcc.gnu.org>
PR target/39423 PR target/39423

View File

@ -0,0 +1,221 @@
/* Verify that simple indirect calls are inlined even without early
inlining.. */
/* { dg-do compile } */
/* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining" } */
struct S
{
int i;
void (*f)(struct S *);
unsigned u;
};
struct U
{
struct U *next;
struct S s;
short a[8];
};
extern void non_existent(struct S *p, int);
/* ----- 1 ----- */
static void hooray1 (struct S *p)
{
non_existent (p, 1);
}
static void hiphip1 (struct S *p)
{
p->f (p);
}
int test1 (void)
{
struct S s;
s.i = 1234;
s.f = hooray1;
s.u = 1001;
hiphip1 (&s);
return 0;
}
/* ----- 2 ----- */
struct S *gp;
static void hooray2 (struct S *p)
{
non_existent (p, 2);
}
static void hip2 (struct S *p)
{
p->f (p);
}
static void hiphip2 (struct S *p)
{
hip2 (p);
}
int test2 (void)
{
struct S *p = gp;
p->i = 2341;
p->f = hooray2;
p->u = 1002;
hiphip2 (p);
return 0;
}
/* ----- 3 ----- */
static void hooray3 (struct S *p)
{
non_existent (p, 2);
}
static void hip3 (struct S *p)
{
p->f (p);
}
static __attribute__ ((flatten)) void hiphip3 (struct S *p)
{
hip3 (p);
}
int test3 (void)
{
struct S *p = gp;
p->i = 2341;
p->f = hooray3;
p->u = 1003;
hiphip3 (p);
return 0;
}
/* ----- 4 ----- */
static void hooray4 (struct S *p)
{
non_existent (p, 3);
}
static void hiphip4 (struct S s)
{
s.f (&s);
}
int test4(void)
{
struct S s;
s.i = 3412;
s.f = hooray4;
s.u = 1004;
hiphip4 (s);
return 0;
}
/* ----- 5 ----- */
struct U *gu;
static void hooray5 (struct S *p)
{
non_existent (p, 5);
}
static void hip5 (struct S *p)
{
p->f (p);
}
static void hiphip5 (struct U *u)
{
hip5 (&u->s);
}
int test5 (void)
{
struct U *u = gu;
u->next = u;
u->s.i = 9876;
u->s.f = hooray5;
u->s.u = 1005;
hiphip5 (u);
return 0;
}
/* ----- 6 ----- */
static void hooray6 (struct S *p)
{
non_existent (p, 6);
}
static void hip6 (struct S *p)
{
p->f (p);
}
static __attribute__ ((flatten)) void hiphip6 (struct U *u)
{
hip6 (&u->s);
}
int test6 (void)
{
struct U *u = gu;
u->next = u;
u->s.i = 9876;
u->s.f = hooray6;
u->s.u = 1006;
hiphip6 (u);
return 0;
}
/* ----- 7 ----- */
struct S **gdp;
static void hooray7 (struct S *p)
{
non_existent (p, 7);
}
static void hip7 (struct S *p)
{
p->f (p);
gdp = &p;
}
static void hiphip7 (struct S *p)
{
hip7 (p);
gdp = &p;
}
int test7 (void)
{
struct S *p = gp;
p->i = 7341;
p->f = hooray7;
p->u = 1007;
hiphip7 (p);
return 0;
}
/* { dg-final { scan-ipa-dump "hooray1\[^\\n\]*inline copy in test1" "inline" } } */
/* { dg-final { scan-ipa-dump "hooray2\[^\\n\]*inline copy in test2" "inline" } } */
/* { dg-final { scan-ipa-dump "hooray3\[^\\n\]*inline copy in test3" "inline" } } */
/* { dg-final { scan-ipa-dump "hooray4\[^\\n\]*inline copy in test4" "inline" } } */
/* { dg-final { scan-ipa-dump "hooray5\[^\\n\]*inline copy in test5" "inline" } } */
/* { dg-final { scan-ipa-dump "hooray6\[^\\n\]*inline copy in test6" "inline" } } */
/* { dg-final { scan-ipa-dump "hooray7\[^\\n\]*inline copy in test7" "inline" } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */

View File

@ -0,0 +1,124 @@
/* Verify that simple indirect calls are inlined even without early
inlining.. */
/* { dg-do run } */
/* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining" } */
extern void abort (void);
struct S
{
int i;
void (*f)(struct S *);
int j,k,l;
};
struct Z
{
unsigned u;
void (*f)(struct Z *, int);
struct Z *next;
};
static struct Z *gz;
static struct S *gs;
static int gr = 111;
char gc[1024];
static __attribute__ ((noinline, noclone)) struct S *
get_s (void)
{
return (struct S *) &gc;
}
static void wrong_target_1 (struct S *s)
{
abort ();
}
static void wrong_target_2 (struct S *s)
{
abort ();
}
static void wrong_target_3 (struct S *s)
{
abort ();
}
static void good_target (struct Z *z, int i)
{
gr = 0;
}
static void good_target_3 (struct S *s)
{
gr = 0;
}
static void g1 (struct S *s)
{
struct Z *z = (struct Z*) s;
z->f (z, 8);
}
static void f1 (struct S *s)
{
gz->f = good_target;
g1 (s);
}
static void g2 (struct Z *z)
{
z->f (z, 8);
}
static void f2 (struct S *s)
{
gz->f = good_target;
g2 ((struct Z*) s);
}
static void g3 (struct S *s)
{
s->f (s);
}
static void h3 (struct Z *z)
{
gs->f = good_target_3;
g3 ((struct S *) z);
}
static void f3 (struct S *s)
{
h3 ((struct Z*) s);
}
int main (int argc, char **argv)
{
struct S *s = get_s();
s->i = 5678;
s->f = wrong_target_1;
s->j = 1234;
gz = (struct Z *) s;
f1 (s);
s = get_s();
gz = (struct Z *) s;
s->i = 9999;
s->f = wrong_target_1;
f2 (s);
s = get_s();
gs = s;
s->i = 9999;
s->f = wrong_target_3;
f3 (s);
return gr;
}
/* { dg-final { scan-ipa-dump-not "wrong_target\[^\\n\]*inline copy in" "inline" } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */

View File

@ -0,0 +1,72 @@
/* Verify that simple indirect calls are inlined even without early
inlining.. */
/* { dg-do run } */
/* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining" } */
extern void abort (void);
struct S
{
int i;
void (*f)(struct S *);
int j,k,l;
};
struct Z
{
unsigned u;
void (*f)(struct Z *, int);
struct Z *next;
};
static struct S *gs;
static int gr = 111;
char gc[1024];
static __attribute__ ((noinline, noclone)) struct S *
get_s (void)
{
return (struct S *) &gc;
}
static void wrong_target (struct S *s)
{
abort ();
}
static void good_target (struct S *s)
{
gr = 0;
}
static void g1 (struct S *s)
{
s->f (s);
}
static void f2 (struct Z *z)
{
gs->f = good_target;
g1 ((struct S *) z);
}
static inline __attribute__ ((flatten)) void f1 (struct S *s)
{
f2 ((struct Z *) s);
}
int main (int argc, char **argv)
{
struct S *s = get_s();
s->i = 5678;
s->f = wrong_target;
s->j = 1234;
gs = s;
f1 (s);
return gr;
}
/* { dg-final { scan-ipa-dump-not "wrong_target\[^\\n\]*inline copy in" "inline" } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */

View File

@ -0,0 +1,157 @@
/* Verify that simple indirect calls are inlined even without early
inlining.. */
/* { dg-do run } */
/* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining" } */
extern void abort (void);
struct S
{
int i;
void (*f)(struct S *);
int j,k,l;
};
struct U
{
struct U *next;
struct S s;
short a[8];
};
struct Z
{
unsigned u;
void (*f)(struct Z *, int);
struct Z *next;
};
static struct Z *gz;
static struct U *gu;
static int gr = 111;
char gc[1024];
static __attribute__ ((noinline, noclone)) struct U *
get_u (void)
{
return (struct U *) &gc;
}
static void wrong_target_1 (struct S *s)
{
abort ();
}
static void wrong_target_2 (struct S *s)
{
abort ();
}
static void wrong_target_3 (struct S *s)
{
abort ();
}
static void wrong_target_4 (struct S *s)
{
abort ();
}
static void good_target (struct Z *z, int i)
{
gr = 0;
}
static void good_target_4 (struct S *s)
{
gr = 0;
}
static void g1 (struct S *s)
{
struct Z *z = (struct Z*) s;
z->f (z, 8);
}
static void f1 (struct U *u)
{
gz->f = good_target;
g1 (&u->s);
}
static void g2 (struct Z *z)
{
z->f (z, 8);
}
static void f2 (struct U *u)
{
gz->f = good_target;
g2 ((struct Z*) &u->s);
}
static void h3 (struct Z *z)
{
z->f (z, 8);
}
static void g3 (struct S *s)
{
h3 ((struct Z*) s);
}
static void f3 (struct U *u)
{
gz->f = good_target;
g3 (&u->s);
}
static void h4 (struct S *s)
{
s->f (s);
}
static void g4 (struct U *u)
{
h4 (&u->s);
}
static inline __attribute__ ((flatten)) void f4 (struct Z *z)
{
gu->s.f = good_target_4;
g4 ((struct U *) z);
}
int main (int argc, char **argv)
{
struct U *u = get_u ();
u->next = u;
u->s.i = 5678;
u->s.f = wrong_target_1;
u->s.j = 1234;
gz = (struct Z *) &u->s;
f1 (u);
u = get_u();
u->s.i = 9999;
u->s.f = wrong_target_2;
gz = (struct Z *) &u->s;
f2 (u);
u = get_u();
u->s.i = 9998;
u->s.f = wrong_target_3;
gz = (struct Z *) &u->s;
f3 (u);
u = get_u();
u->s.i = 9998;
u->s.f = wrong_target_4;
gu = u;
f4 ((struct Z *) u);
return gr;
}
/* { dg-final { scan-ipa-dump-not "wrong_target\[^\\n\]*inline copy in" "inline" } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */

View File

@ -0,0 +1,52 @@
/* Make sure that by reference and by value aggregate jump functions do not get
mixed up. */
/* { dg-lto-do run } */
/* { dg-lto-options {{-O3 -fno-early-inlining -flto}} } */
extern void abort (void);
struct S
{
int i;
void (*f)(struct S *);
int j;
};
struct E
{
struct S *p;
};
struct S *gs;
int gr = 111;
char gc[1024];
static __attribute__ ((noinline, noclone)) struct S *
get_s (void)
{
return (struct S *) &gc;
}
static void wrong_target (struct S *s)
{
abort ();
}
void bar (struct S *s)
{
s->f (s);
}
extern void foo (struct S *s);
int main (int argc, char **argv)
{
struct S *s = get_s();
gs = s;
s->i = 5678;
s->f = wrong_target;
s->j = 1234;
foo (s);
return gr;
}

View File

@ -0,0 +1,39 @@
/* Make sure that by reference and by value aggregate jump functions do not get
mixed up. */
extern void abort (void);
struct S
{
int i;
void (*f)(struct S *);
int j;
};
struct E
{
struct S *p;
};
extern struct S *gs;
extern int gr;
extern char gc[1024];
static __attribute__ ((noinline, noclone)) struct S *
get_s (void)
{
return (struct S *) &gc;
}
static void good_target (struct S *s)
{
gr = 0;
}
extern void bar (struct E e);
void foo (struct E e)
{
gs->f = good_target;
bar (e);
}