cgraph.h (cgraph_indirect_call_info): Removed field thunk_delta.
2011-09-02 Martin Jambor <mjambor@suse.cz> * cgraph.h (cgraph_indirect_call_info): Removed field thunk_delta. * gimple-fold.c (gimple_get_virt_method_for_binfo): Rewritten to use BINFO_VTABLE. Parameter delta removed, all callers updated. * tree.c (free_lang_data_in_binfo): Clear BINFO_VIRTUALs instead BINFO_VTABLE. * cgraph.c (cgraph_make_edge_direct): Removed parameter delta, updated all calls. * cgraphunit.c (cgraph_redirect_edge_call_stmt_to_callee): Removed handling of thunk_delta. * ipa-cp.c (get_indirect_edge_target): Removed parameter delta. (devirtualization_time_bonus): Do not handle thunk deltas. (ipcp_discover_new_direct_edges): Likewise. * ipa-prop.c (ipa_make_edge_direct_to_target): Likewise. (try_make_edge_direct_simple_call): Likewise. (try_make_edge_direct_virtual_call): Likewise. * lto-cgraph.c (output_cgraph_opt_summary_p): Likewise. Mark parameter set as unused. (output_edge_opt_summary): Likewise. Mark both parameters as unused. * lto-cgraph.c (output_cgraph_opt_summary_p): Likewise. Mark parameter set as unused. (output_edge_opt_summary): Likewise. Mark both parameters as unused. (input_edge_opt_summary): Likewise. * lto-streamer-out.c (lto_output_ts_binfo_tree_pointers): Do not stream BINFO_VIRTUALS at all. * lto-streamer-in.c (lto_input_ts_binfo_tree_pointers): Likewise. * testsuite/g++.dg/ipa/devirt-3.C: Added a distraction method. * testsuite/g++.dg/ipa/ivinline-7.C: Added a test for direct call discovery, xfailed test for inlining. * testsuite/g++.dg/ipa/ivinline-9.C: Likewise. From-SVN: r178472
This commit is contained in:
parent
5d882cc1da
commit
81fa35bd59
@ -1,3 +1,31 @@
|
|||||||
|
2011-09-02 Martin Jambor <mjambor@suse.cz>
|
||||||
|
|
||||||
|
* cgraph.h (cgraph_indirect_call_info): Removed field thunk_delta.
|
||||||
|
* gimple-fold.c (gimple_get_virt_method_for_binfo): Rewritten to use
|
||||||
|
BINFO_VTABLE. Parameter delta removed, all callers updated.
|
||||||
|
* tree.c (free_lang_data_in_binfo): Clear BINFO_VIRTUALs instead
|
||||||
|
BINFO_VTABLE.
|
||||||
|
* cgraph.c (cgraph_make_edge_direct): Removed parameter delta, updated
|
||||||
|
all calls.
|
||||||
|
* cgraphunit.c (cgraph_redirect_edge_call_stmt_to_callee): Removed
|
||||||
|
handling of thunk_delta.
|
||||||
|
* ipa-cp.c (get_indirect_edge_target): Removed parameter delta.
|
||||||
|
(devirtualization_time_bonus): Do not handle thunk deltas.
|
||||||
|
(ipcp_discover_new_direct_edges): Likewise.
|
||||||
|
* ipa-prop.c (ipa_make_edge_direct_to_target): Likewise.
|
||||||
|
(try_make_edge_direct_simple_call): Likewise.
|
||||||
|
(try_make_edge_direct_virtual_call): Likewise.
|
||||||
|
* lto-cgraph.c (output_cgraph_opt_summary_p): Likewise. Mark
|
||||||
|
parameter set as unused.
|
||||||
|
(output_edge_opt_summary): Likewise. Mark both parameters as unused.
|
||||||
|
* lto-cgraph.c (output_cgraph_opt_summary_p): Likewise. Mark
|
||||||
|
parameter set as unused.
|
||||||
|
(output_edge_opt_summary): Likewise. Mark both parameters as unused.
|
||||||
|
(input_edge_opt_summary): Likewise.
|
||||||
|
* lto-streamer-out.c (lto_output_ts_binfo_tree_pointers): Do not stream
|
||||||
|
BINFO_VIRTUALS at all.
|
||||||
|
* lto-streamer-in.c (lto_input_ts_binfo_tree_pointers): Likewise.
|
||||||
|
|
||||||
2011-09-02 Richard Guenther <rguenther@suse.de>
|
2011-09-02 Richard Guenther <rguenther@suse.de>
|
||||||
|
|
||||||
* tree-ssa-ccp.c (fold_builtin_alloca_for_var): Do not
|
* tree-ssa-ccp.c (fold_builtin_alloca_for_var): Do not
|
||||||
|
@ -835,7 +835,7 @@ cgraph_set_call_stmt (struct cgraph_edge *e, gimple new_stmt)
|
|||||||
struct cgraph_node *new_callee = cgraph_get_node (decl);
|
struct cgraph_node *new_callee = cgraph_get_node (decl);
|
||||||
|
|
||||||
gcc_checking_assert (new_callee);
|
gcc_checking_assert (new_callee);
|
||||||
cgraph_make_edge_direct (e, new_callee, 0);
|
cgraph_make_edge_direct (e, new_callee);
|
||||||
}
|
}
|
||||||
|
|
||||||
push_cfun (DECL_STRUCT_FUNCTION (e->caller->decl));
|
push_cfun (DECL_STRUCT_FUNCTION (e->caller->decl));
|
||||||
@ -1161,11 +1161,9 @@ cgraph_redirect_edge_callee (struct cgraph_edge *e, struct cgraph_node *n)
|
|||||||
pointer (first parameter) to compensate for skipping a thunk adjustment. */
|
pointer (first parameter) to compensate for skipping a thunk adjustment. */
|
||||||
|
|
||||||
void
|
void
|
||||||
cgraph_make_edge_direct (struct cgraph_edge *edge, struct cgraph_node *callee,
|
cgraph_make_edge_direct (struct cgraph_edge *edge, struct cgraph_node *callee)
|
||||||
HOST_WIDE_INT delta)
|
|
||||||
{
|
{
|
||||||
edge->indirect_unknown_callee = 0;
|
edge->indirect_unknown_callee = 0;
|
||||||
edge->indirect_info->thunk_delta = delta;
|
|
||||||
|
|
||||||
/* Get the edge out of the indirect edge list. */
|
/* Get the edge out of the indirect edge list. */
|
||||||
if (edge->prev_callee)
|
if (edge->prev_callee)
|
||||||
|
@ -314,9 +314,6 @@ struct GTY(()) cgraph_indirect_call_info
|
|||||||
HOST_WIDE_INT anc_offset;
|
HOST_WIDE_INT anc_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;
|
||||||
/* Delta by which must be added to this parameter to compensate for a skipped
|
|
||||||
this adjusting thunk. */
|
|
||||||
HOST_WIDE_INT thunk_delta;
|
|
||||||
/* Type of the object from OBJ_TYPE_REF_OBJECT. */
|
/* Type of the object from OBJ_TYPE_REF_OBJECT. */
|
||||||
tree otr_type;
|
tree otr_type;
|
||||||
/* Index of the parameter that is called. */
|
/* Index of the parameter that is called. */
|
||||||
@ -507,8 +504,7 @@ struct cgraph_node * cgraph_clone_node (struct cgraph_node *, tree, gcov_type,
|
|||||||
struct cgraph_node *cgraph_create_function_alias (tree, tree);
|
struct cgraph_node *cgraph_create_function_alias (tree, tree);
|
||||||
|
|
||||||
void cgraph_redirect_edge_callee (struct cgraph_edge *, struct cgraph_node *);
|
void cgraph_redirect_edge_callee (struct cgraph_edge *, struct cgraph_node *);
|
||||||
void cgraph_make_edge_direct (struct cgraph_edge *, struct cgraph_node *,
|
void cgraph_make_edge_direct (struct cgraph_edge *, struct cgraph_node *);
|
||||||
HOST_WIDE_INT);
|
|
||||||
bool cgraph_only_called_directly_p (struct cgraph_node *);
|
bool cgraph_only_called_directly_p (struct cgraph_node *);
|
||||||
|
|
||||||
struct cgraph_asm_node *cgraph_add_asm_node (tree);
|
struct cgraph_asm_node *cgraph_add_asm_node (tree);
|
||||||
|
@ -2367,7 +2367,6 @@ cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *e)
|
|||||||
tree decl = gimple_call_fndecl (e->call_stmt);
|
tree decl = gimple_call_fndecl (e->call_stmt);
|
||||||
gimple new_stmt;
|
gimple new_stmt;
|
||||||
gimple_stmt_iterator gsi;
|
gimple_stmt_iterator gsi;
|
||||||
bool gsi_computed = false;
|
|
||||||
#ifdef ENABLE_CHECKING
|
#ifdef ENABLE_CHECKING
|
||||||
struct cgraph_node *node;
|
struct cgraph_node *node;
|
||||||
#endif
|
#endif
|
||||||
@ -2398,21 +2397,6 @@ cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *e)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e->indirect_info &&
|
|
||||||
e->indirect_info->thunk_delta != 0
|
|
||||||
&& (!e->callee->clone.combined_args_to_skip
|
|
||||||
|| !bitmap_bit_p (e->callee->clone.combined_args_to_skip, 0)))
|
|
||||||
{
|
|
||||||
if (cgraph_dump_file)
|
|
||||||
fprintf (cgraph_dump_file, " Thunk delta is "
|
|
||||||
HOST_WIDE_INT_PRINT_DEC "\n", e->indirect_info->thunk_delta);
|
|
||||||
gsi = gsi_for_stmt (e->call_stmt);
|
|
||||||
gsi_computed = true;
|
|
||||||
gimple_adjust_this_by_delta (&gsi,
|
|
||||||
size_int (e->indirect_info->thunk_delta));
|
|
||||||
e->indirect_info->thunk_delta = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e->callee->clone.combined_args_to_skip)
|
if (e->callee->clone.combined_args_to_skip)
|
||||||
{
|
{
|
||||||
int lp_nr;
|
int lp_nr;
|
||||||
@ -2426,8 +2410,7 @@ cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *e)
|
|||||||
&& TREE_CODE (gimple_vdef (new_stmt)) == SSA_NAME)
|
&& TREE_CODE (gimple_vdef (new_stmt)) == SSA_NAME)
|
||||||
SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt;
|
SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt;
|
||||||
|
|
||||||
if (!gsi_computed)
|
gsi = gsi_for_stmt (e->call_stmt);
|
||||||
gsi = gsi_for_stmt (e->call_stmt);
|
|
||||||
gsi_replace (&gsi, new_stmt, false);
|
gsi_replace (&gsi, new_stmt, false);
|
||||||
/* We need to defer cleaning EH info on the new statement to
|
/* We need to defer cleaning EH info on the new statement to
|
||||||
fixup-cfg. We may not have dominator information at this point
|
fixup-cfg. We may not have dominator information at this point
|
||||||
|
@ -982,51 +982,6 @@ gimple_fold_builtin (gimple stmt)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return a declaration of a function which an OBJ_TYPE_REF references. TOKEN
|
|
||||||
is integer form of OBJ_TYPE_REF_TOKEN of the reference expression.
|
|
||||||
KNOWN_BINFO carries the binfo describing the true type of
|
|
||||||
OBJ_TYPE_REF_OBJECT(REF). If a call to the function must be accompanied
|
|
||||||
with a this adjustment, the constant which should be added to this pointer
|
|
||||||
is stored to *DELTA. If REFUSE_THUNKS is true, return NULL if the function
|
|
||||||
is a thunk (other than a this adjustment which is dealt with by DELTA). */
|
|
||||||
|
|
||||||
tree
|
|
||||||
gimple_get_virt_method_for_binfo (HOST_WIDE_INT token, tree known_binfo,
|
|
||||||
tree *delta)
|
|
||||||
{
|
|
||||||
HOST_WIDE_INT i;
|
|
||||||
tree v, fndecl;
|
|
||||||
|
|
||||||
v = BINFO_VIRTUALS (known_binfo);
|
|
||||||
/* If there is no virtual methods leave the OBJ_TYPE_REF alone. */
|
|
||||||
if (!v)
|
|
||||||
return NULL_TREE;
|
|
||||||
i = 0;
|
|
||||||
while (i != token)
|
|
||||||
{
|
|
||||||
i += (TARGET_VTABLE_USES_DESCRIPTORS
|
|
||||||
? TARGET_VTABLE_USES_DESCRIPTORS : 1);
|
|
||||||
v = TREE_CHAIN (v);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If BV_VCALL_INDEX is non-NULL, give up. */
|
|
||||||
if (TREE_TYPE (v))
|
|
||||||
return NULL_TREE;
|
|
||||||
|
|
||||||
fndecl = TREE_VALUE (v);
|
|
||||||
|
|
||||||
/* When cgraph node is missing and function is not public, we cannot
|
|
||||||
devirtualize. This can happen in WHOPR when the actual method
|
|
||||||
ends up in other partition, because we found devirtualization
|
|
||||||
possibility too late. */
|
|
||||||
if (!can_refer_decl_in_current_unit_p (TREE_VALUE (v)))
|
|
||||||
return NULL_TREE;
|
|
||||||
|
|
||||||
*delta = TREE_PURPOSE (v);
|
|
||||||
gcc_checking_assert (host_integerp (*delta, 0));
|
|
||||||
return fndecl;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Generate code adjusting the first parameter of a call statement determined
|
/* Generate code adjusting the first parameter of a call statement determined
|
||||||
by GSI by DELTA. */
|
by GSI by DELTA. */
|
||||||
|
|
||||||
@ -1149,7 +1104,7 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
|
|||||||
callee = gimple_call_fn (stmt);
|
callee = gimple_call_fn (stmt);
|
||||||
if (callee && TREE_CODE (callee) == OBJ_TYPE_REF)
|
if (callee && TREE_CODE (callee) == OBJ_TYPE_REF)
|
||||||
{
|
{
|
||||||
tree binfo, fndecl, delta, obj;
|
tree binfo, fndecl, obj;
|
||||||
HOST_WIDE_INT token;
|
HOST_WIDE_INT token;
|
||||||
|
|
||||||
if (gimple_call_addr_fndecl (OBJ_TYPE_REF_EXPR (callee)) != NULL_TREE)
|
if (gimple_call_addr_fndecl (OBJ_TYPE_REF_EXPR (callee)) != NULL_TREE)
|
||||||
@ -1163,10 +1118,9 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
|
|||||||
if (!binfo)
|
if (!binfo)
|
||||||
return false;
|
return false;
|
||||||
token = TREE_INT_CST_LOW (OBJ_TYPE_REF_TOKEN (callee));
|
token = TREE_INT_CST_LOW (OBJ_TYPE_REF_TOKEN (callee));
|
||||||
fndecl = gimple_get_virt_method_for_binfo (token, binfo, &delta);
|
fndecl = gimple_get_virt_method_for_binfo (token, binfo);
|
||||||
if (!fndecl)
|
if (!fndecl)
|
||||||
return false;
|
return false;
|
||||||
gcc_assert (integer_zerop (delta));
|
|
||||||
gimple_call_set_fndecl (stmt, fndecl);
|
gimple_call_set_fndecl (stmt, fndecl);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -3064,6 +3018,60 @@ fold_const_aggregate_ref (tree t)
|
|||||||
return fold_const_aggregate_ref_1 (t, NULL);
|
return fold_const_aggregate_ref_1 (t, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return a declaration of a function which an OBJ_TYPE_REF references. TOKEN
|
||||||
|
is integer form of OBJ_TYPE_REF_TOKEN of the reference expression.
|
||||||
|
KNOWN_BINFO carries the binfo describing the true type of
|
||||||
|
OBJ_TYPE_REF_OBJECT(REF). */
|
||||||
|
|
||||||
|
tree
|
||||||
|
gimple_get_virt_method_for_binfo (HOST_WIDE_INT token, tree known_binfo)
|
||||||
|
{
|
||||||
|
unsigned HOST_WIDE_INT offset, size;
|
||||||
|
tree v, fn;
|
||||||
|
|
||||||
|
v = BINFO_VTABLE (known_binfo);
|
||||||
|
/* If there is no virtual methods table, leave the OBJ_TYPE_REF alone. */
|
||||||
|
if (!v)
|
||||||
|
return NULL_TREE;
|
||||||
|
|
||||||
|
if (TREE_CODE (v) == POINTER_PLUS_EXPR)
|
||||||
|
{
|
||||||
|
offset = tree_low_cst (TREE_OPERAND (v, 1), 1) * BITS_PER_UNIT;
|
||||||
|
v = TREE_OPERAND (v, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
offset = 0;
|
||||||
|
|
||||||
|
if (TREE_CODE (v) != ADDR_EXPR)
|
||||||
|
return NULL_TREE;
|
||||||
|
v = TREE_OPERAND (v, 0);
|
||||||
|
|
||||||
|
if (TREE_CODE (v) != VAR_DECL
|
||||||
|
|| !DECL_VIRTUAL_P (v)
|
||||||
|
|| !DECL_INITIAL (v))
|
||||||
|
return NULL_TREE;
|
||||||
|
gcc_checking_assert (TREE_CODE (TREE_TYPE (v)) == ARRAY_TYPE);
|
||||||
|
size = tree_low_cst (TYPE_SIZE (TREE_TYPE (TREE_TYPE (v))), 1);
|
||||||
|
offset += token * size;
|
||||||
|
fn = fold_ctor_reference (TREE_TYPE (TREE_TYPE (v)), DECL_INITIAL (v),
|
||||||
|
offset, size);
|
||||||
|
if (!fn)
|
||||||
|
return NULL_TREE;
|
||||||
|
gcc_assert (TREE_CODE (fn) == ADDR_EXPR
|
||||||
|
|| TREE_CODE (fn) == FDESC_EXPR);
|
||||||
|
fn = TREE_OPERAND (fn, 0);
|
||||||
|
gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
|
||||||
|
|
||||||
|
/* When cgraph node is missing and function is not public, we cannot
|
||||||
|
devirtualize. This can happen in WHOPR when the actual method
|
||||||
|
ends up in other partition, because we found devirtualization
|
||||||
|
possibility too late. */
|
||||||
|
if (!can_refer_decl_in_current_unit_p (fn))
|
||||||
|
return NULL_TREE;
|
||||||
|
|
||||||
|
return fn;
|
||||||
|
}
|
||||||
|
|
||||||
/* Return true iff VAL is a gimple expression that is known to be
|
/* Return true iff VAL is a gimple expression that is known to be
|
||||||
non-negative. Restricted to floating-point inputs. */
|
non-negative. Restricted to floating-point inputs. */
|
||||||
|
|
||||||
|
@ -909,7 +909,7 @@ unsigned get_gimple_rhs_num_ops (enum tree_code);
|
|||||||
gimple gimple_alloc_stat (enum gimple_code, unsigned MEM_STAT_DECL);
|
gimple gimple_alloc_stat (enum gimple_code, unsigned MEM_STAT_DECL);
|
||||||
const char *gimple_decl_printable_name (tree, int);
|
const char *gimple_decl_printable_name (tree, int);
|
||||||
bool gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace);
|
bool gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace);
|
||||||
tree gimple_get_virt_method_for_binfo (HOST_WIDE_INT, tree, tree *);
|
tree gimple_get_virt_method_for_binfo (HOST_WIDE_INT, tree);
|
||||||
void gimple_adjust_this_by_delta (gimple_stmt_iterator *, tree);
|
void gimple_adjust_this_by_delta (gimple_stmt_iterator *, tree);
|
||||||
tree gimple_extract_devirt_binfo_from_cst (tree);
|
tree gimple_extract_devirt_binfo_from_cst (tree);
|
||||||
/* Returns true iff T is a valid GIMPLE statement. */
|
/* Returns true iff T is a valid GIMPLE statement. */
|
||||||
|
24
gcc/ipa-cp.c
24
gcc/ipa-cp.c
@ -1110,11 +1110,10 @@ propagate_constants_accross_call (struct cgraph_edge *cs)
|
|||||||
|
|
||||||
/* If an indirect edge IE can be turned into a direct one based on KNOWN_VALS
|
/* If an indirect edge IE can be turned into a direct one based on KNOWN_VALS
|
||||||
(which can contain both constants and binfos) or KNOWN_BINFOS (which can be
|
(which can contain both constants and binfos) or KNOWN_BINFOS (which can be
|
||||||
NULL) return the destination. If simple thunk delta must be applied too,
|
NULL) return the destination. */
|
||||||
store it to DELTA. */
|
|
||||||
|
|
||||||
static tree
|
static tree
|
||||||
get_indirect_edge_target (struct cgraph_edge *ie, tree *delta,
|
get_indirect_edge_target (struct cgraph_edge *ie,
|
||||||
VEC (tree, heap) *known_vals,
|
VEC (tree, heap) *known_vals,
|
||||||
VEC (tree, heap) *known_binfos)
|
VEC (tree, heap) *known_binfos)
|
||||||
{
|
{
|
||||||
@ -1132,10 +1131,7 @@ get_indirect_edge_target (struct cgraph_edge *ie, tree *delta,
|
|||||||
if (t &&
|
if (t &&
|
||||||
TREE_CODE (t) == ADDR_EXPR
|
TREE_CODE (t) == ADDR_EXPR
|
||||||
&& TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL)
|
&& TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL)
|
||||||
{
|
return TREE_OPERAND (t, 0);
|
||||||
*delta = NULL_TREE;
|
|
||||||
return TREE_OPERAND (t, 0);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
return NULL_TREE;
|
return NULL_TREE;
|
||||||
}
|
}
|
||||||
@ -1159,7 +1155,7 @@ get_indirect_edge_target (struct cgraph_edge *ie, tree *delta,
|
|||||||
binfo = get_binfo_at_offset (binfo, anc_offset, otr_type);
|
binfo = get_binfo_at_offset (binfo, anc_offset, otr_type);
|
||||||
if (!binfo)
|
if (!binfo)
|
||||||
return NULL_TREE;
|
return NULL_TREE;
|
||||||
return gimple_get_virt_method_for_binfo (token, binfo, delta);
|
return gimple_get_virt_method_for_binfo (token, binfo);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1168,7 +1164,7 @@ get_indirect_edge_target (struct cgraph_edge *ie, tree *delta,
|
|||||||
binfo = get_binfo_at_offset (t, anc_offset, otr_type);
|
binfo = get_binfo_at_offset (t, anc_offset, otr_type);
|
||||||
if (!binfo)
|
if (!binfo)
|
||||||
return NULL_TREE;
|
return NULL_TREE;
|
||||||
return gimple_get_virt_method_for_binfo (token, binfo, delta);
|
return gimple_get_virt_method_for_binfo (token, binfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1187,9 +1183,9 @@ devirtualization_time_bonus (struct cgraph_node *node,
|
|||||||
{
|
{
|
||||||
struct cgraph_node *callee;
|
struct cgraph_node *callee;
|
||||||
struct inline_summary *isummary;
|
struct inline_summary *isummary;
|
||||||
tree delta, target;
|
tree target;
|
||||||
|
|
||||||
target = get_indirect_edge_target (ie, &delta, known_csts, known_binfos);
|
target = get_indirect_edge_target (ie, known_csts, known_binfos);
|
||||||
if (!target)
|
if (!target)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -1674,12 +1670,12 @@ ipcp_discover_new_direct_edges (struct cgraph_node *node,
|
|||||||
|
|
||||||
for (ie = node->indirect_calls; ie; ie = next_ie)
|
for (ie = node->indirect_calls; ie; ie = next_ie)
|
||||||
{
|
{
|
||||||
tree delta, target;
|
tree target;
|
||||||
|
|
||||||
next_ie = ie->next_callee;
|
next_ie = ie->next_callee;
|
||||||
target = get_indirect_edge_target (ie, &delta, known_vals, NULL);
|
target = get_indirect_edge_target (ie, known_vals, NULL);
|
||||||
if (target)
|
if (target)
|
||||||
ipa_make_edge_direct_to_target (ie, target, delta);
|
ipa_make_edge_direct_to_target (ie, target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1614,12 +1614,10 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* If TARGET is an addr_expr of a function declaration, make it the destination
|
/* 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. Delta,
|
of an indirect edge IE and return the edge. Otherwise, return NULL. */
|
||||||
if non-NULL, is an integer constant that must be added to this pointer
|
|
||||||
(first parameter). */
|
|
||||||
|
|
||||||
struct cgraph_edge *
|
struct cgraph_edge *
|
||||||
ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target, tree delta)
|
ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target)
|
||||||
{
|
{
|
||||||
struct cgraph_node *callee;
|
struct cgraph_node *callee;
|
||||||
|
|
||||||
@ -1632,11 +1630,11 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target, tree delta)
|
|||||||
return NULL;
|
return NULL;
|
||||||
ipa_check_create_node_params ();
|
ipa_check_create_node_params ();
|
||||||
|
|
||||||
/* We can not make edges to inline clones. It is bug that someone removed the cgraph
|
/* We can not make edges to inline clones. It is bug that someone removed
|
||||||
node too early. */
|
the cgraph node too early. */
|
||||||
gcc_assert (!callee->global.inlined_to);
|
gcc_assert (!callee->global.inlined_to);
|
||||||
|
|
||||||
cgraph_make_edge_direct (ie, callee, delta ? tree_low_cst (delta, 0) : 0);
|
cgraph_make_edge_direct (ie, callee);
|
||||||
if (dump_file)
|
if (dump_file)
|
||||||
{
|
{
|
||||||
fprintf (dump_file, "ipa-prop: Discovered %s call to a known target "
|
fprintf (dump_file, "ipa-prop: Discovered %s call to a known target "
|
||||||
@ -1648,13 +1646,6 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target, tree delta)
|
|||||||
print_gimple_stmt (dump_file, ie->call_stmt, 2, TDF_SLIM);
|
print_gimple_stmt (dump_file, ie->call_stmt, 2, TDF_SLIM);
|
||||||
else
|
else
|
||||||
fprintf (dump_file, "with uid %i\n", ie->lto_stmt_uid);
|
fprintf (dump_file, "with uid %i\n", ie->lto_stmt_uid);
|
||||||
|
|
||||||
if (delta)
|
|
||||||
{
|
|
||||||
fprintf (dump_file, " Thunk delta is ");
|
|
||||||
print_generic_expr (dump_file, delta, 0);
|
|
||||||
fprintf (dump_file, "\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
callee = cgraph_function_or_thunk_node (callee, NULL);
|
callee = cgraph_function_or_thunk_node (callee, NULL);
|
||||||
|
|
||||||
@ -1683,7 +1674,7 @@ try_make_edge_direct_simple_call (struct cgraph_edge *ie,
|
|||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return ipa_make_edge_direct_to_target (ie, target, NULL_TREE);
|
return ipa_make_edge_direct_to_target (ie, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to find a destination for indirect edge IE that corresponds to a
|
/* Try to find a destination for indirect edge IE that corresponds to a
|
||||||
@ -1695,7 +1686,7 @@ static struct cgraph_edge *
|
|||||||
try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
|
try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
|
||||||
struct ipa_jump_func *jfunc)
|
struct ipa_jump_func *jfunc)
|
||||||
{
|
{
|
||||||
tree binfo, type, target, delta;
|
tree binfo, type, target;
|
||||||
HOST_WIDE_INT token;
|
HOST_WIDE_INT token;
|
||||||
|
|
||||||
if (jfunc->type == IPA_JF_KNOWN_TYPE)
|
if (jfunc->type == IPA_JF_KNOWN_TYPE)
|
||||||
@ -1710,12 +1701,12 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
|
|||||||
type = ie->indirect_info->otr_type;
|
type = ie->indirect_info->otr_type;
|
||||||
binfo = get_binfo_at_offset (binfo, ie->indirect_info->anc_offset, type);
|
binfo = get_binfo_at_offset (binfo, ie->indirect_info->anc_offset, type);
|
||||||
if (binfo)
|
if (binfo)
|
||||||
target = gimple_get_virt_method_for_binfo (token, binfo, &delta);
|
target = gimple_get_virt_method_for_binfo (token, binfo);
|
||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (target)
|
if (target)
|
||||||
return ipa_make_edge_direct_to_target (ie, target, delta);
|
return ipa_make_edge_direct_to_target (ie, target);
|
||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -367,8 +367,7 @@ bool ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
|
|||||||
VEC (cgraph_edge_p, heap) **new_edges);
|
VEC (cgraph_edge_p, heap) **new_edges);
|
||||||
|
|
||||||
/* Indirect edge and binfo processing. */
|
/* Indirect edge and binfo processing. */
|
||||||
struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree,
|
struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree);
|
||||||
tree);
|
|
||||||
|
|
||||||
/* Functions related to both. */
|
/* Functions related to both. */
|
||||||
void ipa_analyze_node (struct cgraph_node *);
|
void ipa_analyze_node (struct cgraph_node *);
|
||||||
|
@ -1501,22 +1501,9 @@ input_cgraph (void)
|
|||||||
/* True when we need optimization summary for NODE. */
|
/* True when we need optimization summary for NODE. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
output_cgraph_opt_summary_p (struct cgraph_node *node, cgraph_node_set set)
|
output_cgraph_opt_summary_p (struct cgraph_node *node,
|
||||||
|
cgraph_node_set set ATTRIBUTE_UNUSED)
|
||||||
{
|
{
|
||||||
struct cgraph_edge *e;
|
|
||||||
|
|
||||||
if (cgraph_node_in_set_p (node, set))
|
|
||||||
{
|
|
||||||
for (e = node->callees; e; e = e->next_callee)
|
|
||||||
if (e->indirect_info
|
|
||||||
&& e->indirect_info->thunk_delta != 0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
for (e = node->indirect_calls; e; e = e->next_callee)
|
|
||||||
if (e->indirect_info->thunk_delta != 0)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (node->clone_of
|
return (node->clone_of
|
||||||
&& (node->clone.tree_map
|
&& (node->clone.tree_map
|
||||||
|| node->clone.args_to_skip
|
|| node->clone.args_to_skip
|
||||||
@ -1525,13 +1512,9 @@ output_cgraph_opt_summary_p (struct cgraph_node *node, cgraph_node_set set)
|
|||||||
|
|
||||||
/* Output optimization summary for EDGE to OB. */
|
/* Output optimization summary for EDGE to OB. */
|
||||||
static void
|
static void
|
||||||
output_edge_opt_summary (struct output_block *ob,
|
output_edge_opt_summary (struct output_block *ob ATTRIBUTE_UNUSED,
|
||||||
struct cgraph_edge *edge)
|
struct cgraph_edge *edge ATTRIBUTE_UNUSED)
|
||||||
{
|
{
|
||||||
if (edge->indirect_info)
|
|
||||||
streamer_write_hwi (ob, edge->indirect_info->thunk_delta);
|
|
||||||
else
|
|
||||||
streamer_write_hwi (ob, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Output optimization summary for NODE to OB. */
|
/* Output optimization summary for NODE to OB. */
|
||||||
@ -1631,17 +1614,9 @@ output_cgraph_opt_summary (cgraph_node_set set)
|
|||||||
/* Input optimisation summary of EDGE. */
|
/* Input optimisation summary of EDGE. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
input_edge_opt_summary (struct cgraph_edge *edge,
|
input_edge_opt_summary (struct cgraph_edge *edge ATTRIBUTE_UNUSED,
|
||||||
struct lto_input_block *ib_main)
|
struct lto_input_block *ib_main ATTRIBUTE_UNUSED)
|
||||||
{
|
{
|
||||||
HOST_WIDE_INT thunk_delta;
|
|
||||||
thunk_delta = streamer_read_hwi (ib_main);
|
|
||||||
if (thunk_delta != 0)
|
|
||||||
{
|
|
||||||
gcc_assert (!edge->indirect_info);
|
|
||||||
edge->indirect_info = cgraph_allocate_init_indirect_info ();
|
|
||||||
edge->indirect_info->thunk_delta = thunk_delta;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Input optimisation summary of NODE. */
|
/* Input optimisation summary of NODE. */
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
|
2011-09-02 Martin Jambor <mjambor@suse.cz>
|
||||||
|
|
||||||
|
* g++.dg/ipa/devirt-3.C: Added a distraction method.
|
||||||
|
* g++.dg/ipa/ivinline-7.C: Added a test for direct call discovery,
|
||||||
|
xfailed test for inlining.
|
||||||
|
* g++.dg/ipa/ivinline-9.C: Likewise.
|
||||||
|
|
||||||
2011-09-01 Ira Rosen <ira.rosen@linaro.org>
|
2011-09-01 Ira Rosen <ira.rosen@linaro.org>
|
||||||
|
|
||||||
PR tree-optimization/50178
|
PR tree-optimization/50178
|
||||||
|
@ -9,6 +9,7 @@ class A
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
int data;
|
int data;
|
||||||
|
virtual float distraction (float f);
|
||||||
virtual int foo (int i);
|
virtual int foo (int i);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -24,6 +25,12 @@ public:
|
|||||||
virtual int foo (int i);
|
virtual int foo (int i);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
float A::distraction (float f)
|
||||||
|
{
|
||||||
|
f += 6.2;
|
||||||
|
return f/2;
|
||||||
|
}
|
||||||
|
|
||||||
int A::foo (int i)
|
int A::foo (int i)
|
||||||
{
|
{
|
||||||
return i + 1;
|
return i + 1;
|
||||||
|
@ -75,5 +75,6 @@ int main (int argc, char *argv[])
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* { dg-final { scan-ipa-dump "B::foo\[^\\n\]*inline copy in int main" "inline" } } */
|
/* { dg-final { scan-ipa-dump "Discovered a virtual call to a known target.*B::.*foo" "inline" } } */
|
||||||
|
/* { dg-final { scan-ipa-dump "B::foo\[^\\n\]*inline copy in int main" "inline" { xfail *-*-* } } } */
|
||||||
/* { dg-final { cleanup-ipa-dump "inline" } } */
|
/* { dg-final { cleanup-ipa-dump "inline" } } */
|
||||||
|
@ -89,5 +89,6 @@ int main (int argc, char *argv[])
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* { dg-final { scan-ipa-dump "B::foo\[^\\n\]*inline copy in int main" "inline" } } */
|
/* { dg-final { scan-ipa-dump "Discovered a virtual call to a known target.*B::.*foo" "inline" } } */
|
||||||
|
/* { dg-final { scan-ipa-dump "B::foo\[^\\n\]*inline copy in int main" "inline" { xfail *-*-* } } } */
|
||||||
/* { dg-final { cleanup-ipa-dump "inline" } } */
|
/* { dg-final { cleanup-ipa-dump "inline" } } */
|
||||||
|
@ -841,7 +841,6 @@ lto_input_ts_binfo_tree_pointers (struct lto_input_block *ib,
|
|||||||
|
|
||||||
BINFO_OFFSET (expr) = stream_read_tree (ib, data_in);
|
BINFO_OFFSET (expr) = stream_read_tree (ib, data_in);
|
||||||
BINFO_VTABLE (expr) = stream_read_tree (ib, data_in);
|
BINFO_VTABLE (expr) = stream_read_tree (ib, data_in);
|
||||||
BINFO_VIRTUALS (expr) = stream_read_tree (ib, data_in);
|
|
||||||
BINFO_VPTR_FIELD (expr) = stream_read_tree (ib, data_in);
|
BINFO_VPTR_FIELD (expr) = stream_read_tree (ib, data_in);
|
||||||
|
|
||||||
len = streamer_read_uhwi (ib);
|
len = streamer_read_uhwi (ib);
|
||||||
|
@ -701,11 +701,6 @@ write_ts_binfo_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
|
|||||||
|
|
||||||
stream_write_tree (ob, BINFO_OFFSET (expr), ref_p);
|
stream_write_tree (ob, BINFO_OFFSET (expr), ref_p);
|
||||||
stream_write_tree (ob, BINFO_VTABLE (expr), ref_p);
|
stream_write_tree (ob, BINFO_VTABLE (expr), ref_p);
|
||||||
/* BINFO_VIRTUALS is used to drive type based devirtualizatoin. It often links
|
|
||||||
together large portions of programs making it harder to partition. Becuase
|
|
||||||
devirtualization is interesting before inlining, only, there is no real
|
|
||||||
need to ship it into ltrans partition. */
|
|
||||||
stream_write_tree (ob, flag_wpa ? NULL : BINFO_VIRTUALS (expr), ref_p);
|
|
||||||
stream_write_tree (ob, BINFO_VPTR_FIELD (expr), ref_p);
|
stream_write_tree (ob, BINFO_VPTR_FIELD (expr), ref_p);
|
||||||
|
|
||||||
streamer_write_uhwi (ob, VEC_length (tree, BINFO_BASE_ACCESSES (expr)));
|
streamer_write_uhwi (ob, VEC_length (tree, BINFO_BASE_ACCESSES (expr)));
|
||||||
|
@ -4397,7 +4397,7 @@ free_lang_data_in_one_sizepos (tree *expr_p)
|
|||||||
|
|
||||||
|
|
||||||
/* Reset all the fields in a binfo node BINFO. We only keep
|
/* Reset all the fields in a binfo node BINFO. We only keep
|
||||||
BINFO_VIRTUALS, which is used by gimple_fold_obj_type_ref. */
|
BINFO_VTABLE, which is used by gimple_fold_obj_type_ref. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
free_lang_data_in_binfo (tree binfo)
|
free_lang_data_in_binfo (tree binfo)
|
||||||
@ -4407,7 +4407,7 @@ free_lang_data_in_binfo (tree binfo)
|
|||||||
|
|
||||||
gcc_assert (TREE_CODE (binfo) == TREE_BINFO);
|
gcc_assert (TREE_CODE (binfo) == TREE_BINFO);
|
||||||
|
|
||||||
BINFO_VTABLE (binfo) = NULL_TREE;
|
BINFO_VIRTUALS (binfo) = NULL_TREE;
|
||||||
BINFO_BASE_ACCESSES (binfo) = NULL;
|
BINFO_BASE_ACCESSES (binfo) = NULL;
|
||||||
BINFO_INHERITANCE_CHAIN (binfo) = NULL_TREE;
|
BINFO_INHERITANCE_CHAIN (binfo) = NULL_TREE;
|
||||||
BINFO_SUBVTT_INDEX (binfo) = NULL_TREE;
|
BINFO_SUBVTT_INDEX (binfo) = NULL_TREE;
|
||||||
|
Loading…
Reference in New Issue
Block a user