mirror of git://gcc.gnu.org/git/gcc.git
ipa-cp.c (ipcp_process_devirtualization_opportunities): Devirtualize also according to actual contants.
2011-04-19 Martin Jambor <mjambor@suse.cz> * ipa-cp.c (ipcp_process_devirtualization_opportunities): Devirtualize also according to actual contants. * gimple-fold.c (gimple_extract_devirt_binfo_from_cst): New function. (gimple_fold_call): Use it. * gimple.h (gimple_extract_devirt_binfo_from_cst): Declare. * testsuite/g++.dg/opt/devirt1.C: Bump to -O2, remove XFAIL. * testsuite/g++.dg/opt/devirt2.C: New test. * testsuite/g++.dg/ipa/devirt-g-1.C: Likewise. From-SVN: r172719
This commit is contained in:
parent
9714ca7248
commit
49c471e3d8
|
@ -1,3 +1,11 @@
|
|||
2011-04-19 Martin Jambor <mjambor@suse.cz>
|
||||
|
||||
* ipa-cp.c (ipcp_process_devirtualization_opportunities): Devirtualize
|
||||
also according to actual contants.
|
||||
* gimple-fold.c (gimple_extract_devirt_binfo_from_cst): New function.
|
||||
(gimple_fold_call): Use it.
|
||||
* gimple.h (gimple_extract_devirt_binfo_from_cst): Declare.
|
||||
|
||||
2011-04-19 Martin Jambor <mjambor@suse.cz>
|
||||
|
||||
* ipa-prop.c (stmt_may_be_vtbl_ptr_store): Return false for scalar
|
||||
|
|
|
@ -1445,6 +1445,74 @@ gimple_adjust_this_by_delta (gimple_stmt_iterator *gsi, tree delta)
|
|||
gimple_call_set_arg (call_stmt, 0, tmp);
|
||||
}
|
||||
|
||||
/* Return a binfo to be used for devirtualization of calls based on an object
|
||||
represented by a declaration (i.e. a global or automatically allocated one)
|
||||
or NULL if it cannot be found or is not safe. CST is expected to be an
|
||||
ADDR_EXPR of such object or the function will return NULL. Currently it is
|
||||
safe to use such binfo only if it has no base binfo (i.e. no ancestors). */
|
||||
|
||||
tree
|
||||
gimple_extract_devirt_binfo_from_cst (tree cst)
|
||||
{
|
||||
HOST_WIDE_INT offset, size, max_size;
|
||||
tree base, type, expected_type, binfo;
|
||||
bool last_artificial = false;
|
||||
|
||||
if (!flag_devirtualize
|
||||
|| TREE_CODE (cst) != ADDR_EXPR
|
||||
|| TREE_CODE (TREE_TYPE (TREE_TYPE (cst))) != RECORD_TYPE)
|
||||
return NULL_TREE;
|
||||
|
||||
cst = TREE_OPERAND (cst, 0);
|
||||
expected_type = TREE_TYPE (cst);
|
||||
base = get_ref_base_and_extent (cst, &offset, &size, &max_size);
|
||||
type = TREE_TYPE (base);
|
||||
if (!DECL_P (base)
|
||||
|| max_size == -1
|
||||
|| max_size != size
|
||||
|| TREE_CODE (type) != RECORD_TYPE)
|
||||
return NULL_TREE;
|
||||
|
||||
/* Find the sub-object the constant actually refers to and mark whether it is
|
||||
an artificial one (as opposed to a user-defined one). */
|
||||
while (true)
|
||||
{
|
||||
HOST_WIDE_INT pos, size;
|
||||
tree fld;
|
||||
|
||||
if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (expected_type))
|
||||
break;
|
||||
if (offset < 0)
|
||||
return NULL_TREE;
|
||||
|
||||
for (fld = TYPE_FIELDS (type); fld; fld = DECL_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 || TREE_CODE (TREE_TYPE (fld)) != RECORD_TYPE)
|
||||
return NULL_TREE;
|
||||
|
||||
last_artificial = DECL_ARTIFICIAL (fld);
|
||||
type = TREE_TYPE (fld);
|
||||
offset -= pos;
|
||||
}
|
||||
/* Artifical sub-objects are ancestors, we do not want to use them for
|
||||
devirtualization, at least not here. */
|
||||
if (last_artificial)
|
||||
return NULL_TREE;
|
||||
binfo = TYPE_BINFO (type);
|
||||
if (!binfo || BINFO_N_BASE_BINFOS (binfo) > 0)
|
||||
return NULL_TREE;
|
||||
else
|
||||
return binfo;
|
||||
}
|
||||
|
||||
/* Attempt to fold a call statement referenced by the statement iterator GSI.
|
||||
The statement may be replaced by another statement, e.g., if the call
|
||||
simplifies to a constant value. Return true if any changes were made.
|
||||
|
@ -1473,10 +1541,27 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
|
|||
|
||||
/* Check for virtual calls that became direct calls. */
|
||||
callee = gimple_call_fn (stmt);
|
||||
if (TREE_CODE (callee) == OBJ_TYPE_REF
|
||||
&& gimple_call_addr_fndecl (OBJ_TYPE_REF_EXPR (callee)) != NULL_TREE)
|
||||
if (TREE_CODE (callee) == OBJ_TYPE_REF)
|
||||
{
|
||||
gimple_call_set_fn (stmt, OBJ_TYPE_REF_EXPR (callee));
|
||||
tree binfo, fndecl, delta, obj;
|
||||
HOST_WIDE_INT token;
|
||||
|
||||
if (gimple_call_addr_fndecl (OBJ_TYPE_REF_EXPR (callee)) != NULL_TREE)
|
||||
{
|
||||
gimple_call_set_fn (stmt, OBJ_TYPE_REF_EXPR (callee));
|
||||
return true;
|
||||
}
|
||||
|
||||
obj = OBJ_TYPE_REF_OBJECT (callee);
|
||||
binfo = gimple_extract_devirt_binfo_from_cst (obj);
|
||||
if (!binfo)
|
||||
return false;
|
||||
token = TREE_INT_CST_LOW (OBJ_TYPE_REF_TOKEN (callee));
|
||||
fndecl = gimple_get_virt_method_for_binfo (token, binfo, &delta, false);
|
||||
if (!fndecl)
|
||||
return false;
|
||||
gcc_assert (integer_zerop (delta));
|
||||
gimple_call_set_fndecl (stmt, fndecl);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -898,6 +898,7 @@ const char *gimple_decl_printable_name (tree, int);
|
|||
bool gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace);
|
||||
tree gimple_get_virt_method_for_binfo (HOST_WIDE_INT, tree, tree *, bool);
|
||||
void gimple_adjust_this_by_delta (gimple_stmt_iterator *, tree);
|
||||
tree gimple_extract_devirt_binfo_from_cst (tree);
|
||||
/* Returns true iff T is a valid GIMPLE statement. */
|
||||
extern bool is_gimple_stmt (tree);
|
||||
|
||||
|
|
74
gcc/ipa-cp.c
74
gcc/ipa-cp.c
|
@ -1246,51 +1246,71 @@ ipcp_process_devirtualization_opportunities (struct cgraph_node *node)
|
|||
|
||||
for (ie = node->indirect_calls; ie; ie = next_ie)
|
||||
{
|
||||
int param_index, types_count, j;
|
||||
int param_index;
|
||||
HOST_WIDE_INT token, anc_offset;
|
||||
tree target, delta, otr_type;
|
||||
struct ipcp_lattice *lat;
|
||||
|
||||
next_ie = ie->next_callee;
|
||||
if (!ie->indirect_info->polymorphic)
|
||||
continue;
|
||||
param_index = ie->indirect_info->param_index;
|
||||
if (param_index == -1
|
||||
|| ipa_param_cannot_devirtualize_p (info, param_index)
|
||||
|| ipa_param_types_vec_empty (info, param_index))
|
||||
if (param_index == -1)
|
||||
continue;
|
||||
|
||||
lat = ipcp_get_lattice (info, param_index);
|
||||
token = ie->indirect_info->otr_token;
|
||||
anc_offset = ie->indirect_info->anc_offset;
|
||||
otr_type = ie->indirect_info->otr_type;
|
||||
target = NULL_TREE;
|
||||
types_count = VEC_length (tree, info->params[param_index].types);
|
||||
for (j = 0; j < types_count; j++)
|
||||
if (lat->type == IPA_CONST_VALUE)
|
||||
{
|
||||
tree binfo = VEC_index (tree, info->params[param_index].types, j);
|
||||
tree d, t;
|
||||
|
||||
tree binfo = gimple_extract_devirt_binfo_from_cst (lat->constant);
|
||||
if (!binfo)
|
||||
continue;
|
||||
binfo = get_binfo_at_offset (binfo, anc_offset, otr_type);
|
||||
if (!binfo)
|
||||
{
|
||||
target = NULL_TREE;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
target = gimple_get_virt_method_for_binfo (token, binfo, &delta,
|
||||
false);
|
||||
}
|
||||
else
|
||||
{
|
||||
int types_count, j;
|
||||
|
||||
t = gimple_get_virt_method_for_binfo (token, binfo, &d, true);
|
||||
if (!t)
|
||||
if (ipa_param_cannot_devirtualize_p (info, param_index)
|
||||
|| ipa_param_types_vec_empty (info, param_index))
|
||||
continue;
|
||||
|
||||
types_count = VEC_length (tree, info->params[param_index].types);
|
||||
for (j = 0; j < types_count; j++)
|
||||
{
|
||||
target = NULL_TREE;
|
||||
break;
|
||||
}
|
||||
else if (!target)
|
||||
{
|
||||
target = t;
|
||||
delta = d;
|
||||
}
|
||||
else if (target != t || !tree_int_cst_equal (delta, d))
|
||||
{
|
||||
target = NULL_TREE;
|
||||
break;
|
||||
tree binfo = VEC_index (tree, info->params[param_index].types, j);
|
||||
tree d, t;
|
||||
|
||||
binfo = get_binfo_at_offset (binfo, anc_offset, otr_type);
|
||||
if (!binfo)
|
||||
{
|
||||
target = NULL_TREE;
|
||||
break;
|
||||
}
|
||||
|
||||
t = gimple_get_virt_method_for_binfo (token, binfo, &d, true);
|
||||
if (!t)
|
||||
{
|
||||
target = NULL_TREE;
|
||||
break;
|
||||
}
|
||||
else if (!target)
|
||||
{
|
||||
target = t;
|
||||
delta = d;
|
||||
}
|
||||
else if (target != t || !tree_int_cst_equal (delta, d))
|
||||
{
|
||||
target = NULL_TREE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2011-04-19 Martin Jambor <mjambor@suse.cz>
|
||||
|
||||
* g++.dg/opt/devirt1.C: Bump to -O2, remove XFAIL.
|
||||
* g++.dg/opt/devirt2.C: New test.
|
||||
* g++.dg/ipa/devirt-g-1.C: Likewise.
|
||||
|
||||
2011-04-19 Tobias Burnus <burnus@net-b.de>
|
||||
|
||||
PR fortran/48588
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
// { dg-do compile }
|
||||
// { dg-options "-O2 -fdump-ipa-cp -fdump-tree-optimized" }
|
||||
|
||||
struct S { S(); virtual void xyzzy(); void otherstuff(); };
|
||||
struct R { int a; S s; R(); };
|
||||
S s;
|
||||
R r;
|
||||
|
||||
void S::xyzzy ()
|
||||
{
|
||||
otherstuff ();
|
||||
otherstuff ();
|
||||
}
|
||||
|
||||
static void __attribute__ ((noinline)) foo(S *p) { p->xyzzy(); }
|
||||
void bar() {foo(&s); }
|
||||
|
||||
static void __attribute__ ((noinline)) foh(S *p) { p->xyzzy(); }
|
||||
void bah() {foh(&r.s); }
|
||||
|
||||
/* { dg-final { scan-ipa-dump "Discovered a virtual call to a known target.*S::xyzzy" "cp" } } */
|
||||
/* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "optimized"} } */
|
||||
/* { dg-final { cleanup-ipa-dump "cp" } } */
|
||||
/* { dg-final { cleanup-tree-dump "optimized" } } */
|
|
@ -1,6 +1,6 @@
|
|||
// { dg-do compile }
|
||||
// { dg-options "-O" }
|
||||
// { dg-final { scan-assembler "xyzzy" { xfail *-*-* } } }
|
||||
// { dg-options "-O2" }
|
||||
// { dg-final { scan-assembler "xyzzy" } }
|
||||
|
||||
struct S { S(); virtual void xyzzy(); };
|
||||
inline void foo(S *s) { s->xyzzy(); }
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
// { dg-do compile }
|
||||
// { dg-options "-O2" }
|
||||
// { dg-final { scan-assembler-times "xyzzy" 2 } }
|
||||
|
||||
struct S { S(); virtual void xyzzy(); };
|
||||
struct R { int a; S s; R(); };
|
||||
S s;
|
||||
R r;
|
||||
inline void foo(S *p) { p->xyzzy(); }
|
||||
void bar() {foo(&s);}
|
||||
void bah() {foo(&r.s);}
|
Loading…
Reference in New Issue