]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR tree-optimization/56718 (Early inlining prevents type based devirtualization)
authorMartin Jambor <mjambor@suse.cz>
Fri, 19 Apr 2013 12:00:27 +0000 (14:00 +0200)
committerMartin Jambor <jamborm@gcc.gnu.org>
Fri, 19 Apr 2013 12:00:27 +0000 (14:00 +0200)
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

gcc/ChangeLog
gcc/Makefile.in
gcc/ipa-cp.c
gcc/ipa-prop.c
gcc/ipa-prop.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ipa/imm-devirt-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ipa/imm-devirt-2.C [new file with mode: 0644]
gcc/tree-ssa-pre.c

index b8c89cfc60d2276795176749426b2f8b8e06e0f4..43ed933b77a4eedcee345eeedf56528e179e5ae0 100644 (file)
@@ -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
index 109f8654a0e31df40bac3c057b9ab5ecfd61a9e4..a91224bae519eb4c8486908088765991d9dbf64e 100644 (file)
@@ -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) \
index 27aed3c368fef01ecb127a1a5ca822819d7ca81b..48521cfffbf380c4115c010b2c58ae86601dd410 100644 (file)
@@ -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);
        }
index 645bf5b243c86c68ece02e721c2d625dc36ba0e2..8d1363a786a0200e9c252d12018cd9a272790e65 100644 (file)
@@ -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
index 545ae1b68a6180d3ac41c74596d7c556eb00690e..5bc99be03b3a01065b47f3686a9f19c3d3943d42 100644 (file)
@@ -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 *);
index 159848624055dccfd84459434d40856189f54c9c..58b0fca12cef410fe0980511a0653c5458a8ec03 100644 (file)
@@ -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 (file)
index 0000000..32f7258
--- /dev/null
@@ -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 (file)
index 0000000..5bddc2f
--- /dev/null
@@ -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" } } */
index 798409afa82f7c6837c7e6374dc3eca4fcdbc7dd..345ebcceaad4e40f4ff6fa86c76a2412d62fb512 100644 (file)
@@ -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