From bee52153273af07da6c5f997a5820e36c19bf7c5 Mon Sep 17 00:00:00 2001 From: jamborm Date: Fri, 19 Apr 2013 12:00:27 +0000 Subject: [PATCH] 2013-04-19 Martin Jambor 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@198088 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 11 ++++ gcc/Makefile.in | 3 +- gcc/ipa-cp.c | 18 +------ gcc/ipa-prop.c | 38 +++++++++++++ gcc/ipa-prop.h | 2 + gcc/testsuite/ChangeLog | 6 +++ gcc/testsuite/g++.dg/ipa/imm-devirt-1.C | 62 +++++++++++++++++++++ gcc/testsuite/g++.dg/ipa/imm-devirt-2.C | 95 +++++++++++++++++++++++++++++++++ gcc/tree-ssa-pre.c | 11 +++- 9 files changed, 228 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ipa/imm-devirt-1.C create mode 100644 gcc/testsuite/g++.dg/ipa/imm-devirt-2.C 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 + + 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 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 , vec ); 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 + + 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 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 -- 2.7.4