Commit 49c471e3 by Martin Jambor Committed by Martin Jambor

ipa-cp.c (ipcp_process_devirtualization_opportunities): Devirtualize also…

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
parent 9714ca72
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
non-pointer assignments.
......
......@@ -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);
......
......@@ -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)
{
target = NULL_TREE;
break;
}
else if (!target)
{
target = t;
delta = d;
}
else if (target != t || !tree_int_cst_equal (delta, d))
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;
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;
}
}
}
......
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
......
// { 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" } } */
// { 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(); }
......
// { 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);}
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