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> 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 * ipa-prop.c (stmt_may_be_vtbl_ptr_store): Return false for scalar
non-pointer assignments. non-pointer assignments.
......
...@@ -1445,6 +1445,74 @@ gimple_adjust_this_by_delta (gimple_stmt_iterator *gsi, tree delta) ...@@ -1445,6 +1445,74 @@ gimple_adjust_this_by_delta (gimple_stmt_iterator *gsi, tree delta)
gimple_call_set_arg (call_stmt, 0, tmp); 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. /* 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 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. 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) ...@@ -1473,10 +1541,27 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
/* Check for virtual calls that became direct calls. */ /* Check for virtual calls that became direct calls. */
callee = gimple_call_fn (stmt); callee = gimple_call_fn (stmt);
if (TREE_CODE (callee) == OBJ_TYPE_REF if (TREE_CODE (callee) == OBJ_TYPE_REF)
&& gimple_call_addr_fndecl (OBJ_TYPE_REF_EXPR (callee)) != NULL_TREE)
{ {
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; return true;
} }
......
...@@ -898,6 +898,7 @@ const char *gimple_decl_printable_name (tree, int); ...@@ -898,6 +898,7 @@ 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 *, bool); tree gimple_get_virt_method_for_binfo (HOST_WIDE_INT, tree, tree *, bool);
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);
/* Returns true iff T is a valid GIMPLE statement. */ /* Returns true iff T is a valid GIMPLE statement. */
extern bool is_gimple_stmt (tree); extern bool is_gimple_stmt (tree);
......
...@@ -1246,51 +1246,71 @@ ipcp_process_devirtualization_opportunities (struct cgraph_node *node) ...@@ -1246,51 +1246,71 @@ ipcp_process_devirtualization_opportunities (struct cgraph_node *node)
for (ie = node->indirect_calls; ie; ie = next_ie) for (ie = node->indirect_calls; ie; ie = next_ie)
{ {
int param_index, types_count, j; int param_index;
HOST_WIDE_INT token, anc_offset; HOST_WIDE_INT token, anc_offset;
tree target, delta, otr_type; tree target, delta, otr_type;
struct ipcp_lattice *lat;
next_ie = ie->next_callee; next_ie = ie->next_callee;
if (!ie->indirect_info->polymorphic) if (!ie->indirect_info->polymorphic)
continue; continue;
param_index = ie->indirect_info->param_index; param_index = ie->indirect_info->param_index;
if (param_index == -1 if (param_index == -1)
|| ipa_param_cannot_devirtualize_p (info, param_index)
|| ipa_param_types_vec_empty (info, param_index))
continue; continue;
lat = ipcp_get_lattice (info, param_index);
token = ie->indirect_info->otr_token; token = ie->indirect_info->otr_token;
anc_offset = ie->indirect_info->anc_offset; anc_offset = ie->indirect_info->anc_offset;
otr_type = ie->indirect_info->otr_type; otr_type = ie->indirect_info->otr_type;
target = NULL_TREE; target = NULL_TREE;
types_count = VEC_length (tree, info->params[param_index].types); if (lat->type == IPA_CONST_VALUE)
for (j = 0; j < types_count; j++)
{ {
tree binfo = VEC_index (tree, info->params[param_index].types, j); tree binfo = gimple_extract_devirt_binfo_from_cst (lat->constant);
tree d, t; if (!binfo)
continue;
binfo = get_binfo_at_offset (binfo, anc_offset, otr_type); binfo = get_binfo_at_offset (binfo, anc_offset, otr_type);
if (!binfo) if (!binfo)
{ continue;
target = NULL_TREE; target = gimple_get_virt_method_for_binfo (token, binfo, &delta,
break; false);
} }
else
{
int types_count, j;
t = gimple_get_virt_method_for_binfo (token, binfo, &d, true); if (ipa_param_cannot_devirtualize_p (info, param_index)
if (!t) || ipa_param_types_vec_empty (info, param_index))
{ continue;
target = NULL_TREE;
break; types_count = VEC_length (tree, info->params[param_index].types);
} for (j = 0; j < types_count; j++)
else if (!target)
{
target = t;
delta = d;
}
else if (target != t || !tree_int_cst_equal (delta, d))
{ {
target = NULL_TREE; tree binfo = VEC_index (tree, info->params[param_index].types, j);
break; 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> 2011-04-19 Tobias Burnus <burnus@net-b.de>
PR fortran/48588 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-do compile }
// { dg-options "-O" } // { dg-options "-O2" }
// { dg-final { scan-assembler "xyzzy" { xfail *-*-* } } } // { dg-final { scan-assembler "xyzzy" } }
struct S { S(); virtual void xyzzy(); }; struct S { S(); virtual void xyzzy(); };
inline void foo(S *s) { s->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