aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple-fold.c
diff options
context:
space:
mode:
authorMartin Jambor <mjambor@suse.cz>2011-04-19 18:35:33 +0200
committerMartin Jambor <jamborm@gcc.gnu.org>2011-04-19 18:35:33 +0200
commit49c471e3d8e5a505b20672f7029d07bb828cbe1b (patch)
treef6f04a6735e023b75b60f7849bf8007b8c56b69d /gcc/gimple-fold.c
parent9714ca724859e90773df206f552937ddc4da004c (diff)
downloadgcc-49c471e3d8e5a505b20672f7029d07bb828cbe1b.zip
gcc-49c471e3d8e5a505b20672f7029d07bb828cbe1b.tar.gz
gcc-49c471e3d8e5a505b20672f7029d07bb828cbe1b.tar.bz2
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
Diffstat (limited to 'gcc/gimple-fold.c')
-rw-r--r--gcc/gimple-fold.c91
1 files changed, 88 insertions, 3 deletions
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index a6e326b..8d3ab6e 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -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;
}