aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMartin Jambor <mjambor@suse.cz>2013-04-19 14:00:27 +0200
committerMartin Jambor <jamborm@gcc.gnu.org>2013-04-19 14:00:27 +0200
commite248d83f4ba23139d1c24aac2d9b2caf9c67c206 (patch)
tree48a1cde54c03eeceeb5712488b900a74b29947ac /gcc
parent4891e8f8cdeb34ad392a8cf374ce9b8ee54a177f (diff)
downloadgcc-e248d83f4ba23139d1c24aac2d9b2caf9c67c206.zip
gcc-e248d83f4ba23139d1c24aac2d9b2caf9c67c206.tar.gz
gcc-e248d83f4ba23139d1c24aac2d9b2caf9c67c206.tar.bz2
re PR tree-optimization/56718 (Early inlining prevents type based devirtualization)
2013-04-19 Martin Jambor <mjambor@suse.cz> PR tree-optimization/56718 * ipa-cp.c (ipa_value_from_known_type_jfunc): Moved... * ipa-prop.c (ipa_binfo_from_known_type_jfunc): ...here, renamed and made public. Adjusted all callers. (ipa_intraprocedural_devirtualization): New function. * ipa-prop.h (ipa_binfo_from_known_type_jfunc): Declare. (ipa_intraprocedural_devirtualization): Likewise. * Makefile.in (tree-ssa-pre.o): Add ipa-prop.h to dependencies. testsuite/ * g++.dg/ipa/imm-devirt-1.C: New test. * g++.dg/ipa/imm-devirt-2.C: Likewise. From-SVN: r198088
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/Makefile.in3
-rw-r--r--gcc/ipa-cp.c18
-rw-r--r--gcc/ipa-prop.c38
-rw-r--r--gcc/ipa-prop.h2
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/g++.dg/ipa/imm-devirt-1.C62
-rw-r--r--gcc/testsuite/g++.dg/ipa/imm-devirt-2.C95
-rw-r--r--gcc/tree-ssa-pre.c11
9 files changed, 228 insertions, 18 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b8c89cf..43ed933 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,14 @@
+2013-04-19 Martin Jambor <mjambor@suse.cz>
+
+ PR tree-optimization/56718
+ * ipa-cp.c (ipa_value_from_known_type_jfunc): Moved...
+ * ipa-prop.c (ipa_binfo_from_known_type_jfunc): ...here, renamed
+ and made public. Adjusted all callers.
+ (ipa_intraprocedural_devirtualization): New function.
+ * ipa-prop.h (ipa_binfo_from_known_type_jfunc): Declare.
+ (ipa_intraprocedural_devirtualization): Likewise.
+ * Makefile.in (tree-ssa-pre.o): Add ipa-prop.h to dependencies.
+
2013-04-19 Richard Biener <rguenther@suse.de>
PR tree-optimization/57000
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 109f865..a91224b 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -2369,7 +2369,8 @@ tree-ssa-pre.o : tree-ssa-pre.c $(TREE_FLOW_H) $(CONFIG_H) \
$(TM_H) coretypes.h $(TREE_PASS_H) $(FLAGS_H) langhooks.h \
$(CFGLOOP_H) alloc-pool.h $(BASIC_BLOCK_H) $(BITMAP_H) $(HASH_TABLE_H) \
$(GIMPLE_H) $(TREE_INLINE_H) tree-iterator.h tree-ssa-sccvn.h $(PARAMS_H) \
- $(DBGCNT_H) tree-scalar-evolution.h $(GIMPLE_PRETTY_PRINT_H) domwalk.h
+ $(DBGCNT_H) tree-scalar-evolution.h $(GIMPLE_PRETTY_PRINT_H) domwalk.h \
+ $(IPA_PROP_H)
tree-ssa-sccvn.o : tree-ssa-sccvn.c $(TREE_FLOW_H) $(CONFIG_H) \
$(SYSTEM_H) $(TREE_H) $(DIAGNOSTIC_H) \
$(TM_H) coretypes.h $(DUMPFILE_H) $(FLAGS_H) $(CFGLOOP_H) \
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 27aed3c..48521cf 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -791,20 +791,6 @@ ipa_get_jf_ancestor_result (struct ipa_jump_func *jfunc, tree input)
return NULL_TREE;
}
-/* Extract the acual BINFO being described by JFUNC which must be a known type
- jump function. */
-
-static tree
-ipa_value_from_known_type_jfunc (struct ipa_jump_func *jfunc)
-{
- tree base_binfo = TYPE_BINFO (ipa_get_jf_known_type_base_type (jfunc));
- if (!base_binfo)
- return NULL_TREE;
- return get_binfo_at_offset (base_binfo,
- ipa_get_jf_known_type_offset (jfunc),
- ipa_get_jf_known_type_component_type (jfunc));
-}
-
/* Determine whether JFUNC evaluates to a known value (that is either a
constant or a binfo) and if so, return it. Otherwise return NULL. INFO
describes the caller node so that pass-through jump functions can be
@@ -816,7 +802,7 @@ ipa_value_from_jfunc (struct ipa_node_params *info, struct ipa_jump_func *jfunc)
if (jfunc->type == IPA_JF_CONST)
return ipa_get_jf_constant (jfunc);
else if (jfunc->type == IPA_JF_KNOWN_TYPE)
- return ipa_value_from_known_type_jfunc (jfunc);
+ return ipa_binfo_from_known_type_jfunc (jfunc);
else if (jfunc->type == IPA_JF_PASS_THROUGH
|| jfunc->type == IPA_JF_ANCESTOR)
{
@@ -1103,7 +1089,7 @@ propagate_scalar_accross_jump_function (struct cgraph_edge *cs,
if (jfunc->type == IPA_JF_KNOWN_TYPE)
{
- val = ipa_value_from_known_type_jfunc (jfunc);
+ val = ipa_binfo_from_known_type_jfunc (jfunc);
if (!val)
return set_lattice_contains_variable (dest_lat);
}
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 645bf5b..8d1363a 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -356,6 +356,20 @@ ipa_set_ancestor_jf (struct ipa_jump_func *jfunc, HOST_WIDE_INT offset,
jfunc->value.ancestor.agg_preserved = agg_preserved;
}
+/* Extract the acual BINFO being described by JFUNC which must be a known type
+ jump function. */
+
+tree
+ipa_binfo_from_known_type_jfunc (struct ipa_jump_func *jfunc)
+{
+ tree base_binfo = TYPE_BINFO (jfunc->value.known_type.base_type);
+ if (!base_binfo)
+ return NULL_TREE;
+ return get_binfo_at_offset (base_binfo,
+ jfunc->value.known_type.offset,
+ jfunc->value.known_type.component_type);
+}
+
/* Structure to be passed in between detect_type_change and
check_stmt_for_type_change. */
@@ -1957,6 +1971,30 @@ ipa_analyze_node (struct cgraph_node *node)
pop_cfun ();
}
+/* Given a statement CALL which must be a GIMPLE_CALL calling an OBJ_TYPE_REF
+ attempt a type-based devirtualization. If successful, return the
+ target function declaration, otherwise return NULL. */
+
+tree
+ipa_intraprocedural_devirtualization (gimple call)
+{
+ tree binfo, token, fndecl;
+ struct ipa_jump_func jfunc;
+ tree otr = gimple_call_fn (call);
+
+ jfunc.type = IPA_JF_UNKNOWN;
+ compute_known_type_jump_func (OBJ_TYPE_REF_OBJECT (otr), &jfunc,
+ call);
+ if (jfunc.type != IPA_JF_KNOWN_TYPE)
+ return NULL_TREE;
+ binfo = ipa_binfo_from_known_type_jfunc (&jfunc);
+ if (!binfo)
+ return NULL_TREE;
+ token = OBJ_TYPE_REF_TOKEN (otr);
+ fndecl = gimple_get_virt_method_for_binfo (tree_low_cst (token, 1),
+ binfo);
+ return fndecl;
+}
/* Update the jump function DST when the call graph edge corresponding to SRC is
is being inlined, knowing that DST is of type ancestor and src of known
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 545ae1b..5bc99be 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -507,6 +507,8 @@ tree ipa_get_indirect_edge_target (struct cgraph_edge *ie,
vec<tree> ,
vec<ipa_agg_jump_function_p> );
struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree);
+tree ipa_binfo_from_known_type_jfunc (struct ipa_jump_func *);
+tree ipa_intraprocedural_devirtualization (gimple);
/* Functions related to both. */
void ipa_analyze_node (struct cgraph_node *);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 1598486..58b0fca 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2013-04-19 Martin Jambor <mjambor@suse.cz>
+
+ PR tree-optimization/56718
+ * g++.dg/ipa/imm-devirt-1.C: New test.
+ * g++.dg/ipa/imm-devirt-2.C: Likewise.
+
2013-04-19 Richard Biener <rguenther@suse.de>
PR tree-optimization/57000
diff --git a/gcc/testsuite/g++.dg/ipa/imm-devirt-1.C b/gcc/testsuite/g++.dg/ipa/imm-devirt-1.C
new file mode 100644
index 0000000..32f7258
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/imm-devirt-1.C
@@ -0,0 +1,62 @@
+/* Verify that virtual calls are folded even early inlining puts them into one
+ function with the definition. */
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-fre1-details" } */
+
+extern "C" void abort (void);
+
+class A
+{
+public:
+ int data;
+ virtual int foo (int i);
+};
+
+
+class B : public A
+{
+public:
+ __attribute__ ((noinline)) B();
+ virtual int foo (int i);
+};
+
+int __attribute__ ((noinline)) A::foo (int i)
+{
+ return i + 1;
+}
+
+int __attribute__ ((noinline)) B::foo (int i)
+{
+ return i + 2;
+}
+
+int __attribute__ ((noinline,noclone)) get_input(void)
+{
+ return 1;
+}
+
+__attribute__ ((noinline)) B::B()
+{
+}
+
+static inline int middleman_1 (class A *obj, int i)
+{
+ return obj->foo (i);
+}
+
+static inline int middleman_2 (class B *obj, int i)
+{
+ return middleman_1 (obj, i);
+}
+
+int main (int argc, char *argv[])
+{
+ class B b;
+
+ if (middleman_2 (&b, get_input ()) != 3)
+ abort ();
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump "Replacing call target with foo" "fre1" } } */
+/* { dg-final { cleanup-tree-dump "fre1" } } */
diff --git a/gcc/testsuite/g++.dg/ipa/imm-devirt-2.C b/gcc/testsuite/g++.dg/ipa/imm-devirt-2.C
new file mode 100644
index 0000000..5bddc2f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/imm-devirt-2.C
@@ -0,0 +1,95 @@
+/* Verify that virtual calls are folded even early inlining puts them into one
+ function with the definition. */
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-fre1-details" } */
+
+extern "C" void abort (void);
+
+class Distraction
+{
+public:
+ float f;
+ double d;
+ Distraction ()
+ {
+ f = 8.3;
+ d = 10.2;
+ }
+ virtual float bar (float z);
+};
+
+class A
+{
+public:
+ int data;
+ virtual int foo (int i);
+};
+
+class B : public A
+{
+public:
+ int data_2;
+ virtual int foo (int i);
+ virtual int baz (int i);
+};
+
+
+class C : public Distraction, public B
+{
+public:
+ __attribute__ ((noinline)) C();
+ virtual int foo (int i);
+};
+
+float __attribute__ ((noinline)) Distraction::bar (float z)
+{
+ f += z;
+ return f/2;
+}
+
+int __attribute__ ((noinline)) A::foo (int i)
+{
+ return i + 1;
+}
+
+int __attribute__ ((noinline)) B::foo (int i)
+{
+ return i + 2;
+}
+
+int __attribute__ ((noinline)) B::baz (int i)
+{
+ return i * 15;
+}
+
+int __attribute__ ((noinline)) C::foo (int i)
+{
+ return i + 3;
+}
+
+int __attribute__ ((noinline,noclone)) get_input(void)
+{
+ return 1;
+}
+
+static inline int middleman (class A *obj, int i)
+{
+ return obj->foo (i);
+}
+
+__attribute__ ((noinline)) C::C()
+{
+}
+
+int main (int argc, char *argv[])
+{
+ class C c;
+
+ if (middleman (&c, get_input ()) != 4)
+ abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump "Replacing call target" "fre1" } } */
+/* { dg-final { cleanup-tree-dump "fre1" } } */
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index 798409a..345ebcc 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3. If not see
#include "params.h"
#include "dbgcnt.h"
#include "domwalk.h"
+#include "ipa-prop.h"
/* TODO:
@@ -4326,7 +4327,15 @@ eliminate_bb (dom_walk_data *, basic_block b)
fn = VN_INFO (orig_fn)->valnum;
else if (TREE_CODE (orig_fn) == OBJ_TYPE_REF
&& TREE_CODE (OBJ_TYPE_REF_EXPR (orig_fn)) == SSA_NAME)
- fn = VN_INFO (OBJ_TYPE_REF_EXPR (orig_fn))->valnum;
+ {
+ fn = VN_INFO (OBJ_TYPE_REF_EXPR (orig_fn))->valnum;
+ if (!gimple_call_addr_fndecl (fn))
+ {
+ fn = ipa_intraprocedural_devirtualization (stmt);
+ if (fn)
+ fn = build_fold_addr_expr (fn);
+ }
+ }
else
continue;
if (gimple_call_addr_fndecl (fn) != NULL_TREE