This fixes a missed optimization in the testcase in PR89698
where we fail to fold an access to a virtual table slot because
it is (int (*) ()) 0 - yes, an unfolded INTEGER_CST.  Callers
are not happy with this so the following makes sure to
return a properly folded constant via canonicalize_constructor_val.

This avoids the dynamic_cast<> runtime overhead in the testcase.

Bootstrap & regtest running on x86_64-unknown-linux-gnu, queued for GCC 
10.

Richard.

2019-03-14  Richard Biener  <rguent...@suse.de>

        PR tree-optimization/89698
        * gimple-fold.c (canonicalize_constructor_val): Early out
        for constants, handle unfolded INTEGER_CSTs as they appear in
        C++ virtual table ctors.

        * g++.dg/tree-ssa/pr89698.C: New testcase.

Index: gcc/gimple-fold.c
===================================================================
--- gcc/gimple-fold.c   (revision 269641)
+++ gcc/gimple-fold.c   (working copy)
@@ -207,6 +207,9 @@ create_tmp_reg_or_ssa_name (tree type, g
 tree
 canonicalize_constructor_val (tree cval, tree from_decl)
 {
+  if (CONSTANT_CLASS_P (cval))
+    return cval;
+
   tree orig_cval = cval;
   STRIP_NOPS (cval);
   if (TREE_CODE (cval) == POINTER_PLUS_EXPR
@@ -257,8 +260,15 @@ canonicalize_constructor_val (tree cval,
        cval = fold_convert (TREE_TYPE (orig_cval), cval);
       return cval;
     }
-  if (TREE_OVERFLOW_P (cval))
-    return drop_tree_overflow (cval);
+  /* In CONSTRUCTORs we may see unfolded constants like (int (*) ()) 0.  */
+  if (TREE_CODE (cval) == INTEGER_CST)
+    {
+      if (TREE_OVERFLOW_P (cval))
+       cval = drop_tree_overflow (cval);
+      if (!useless_type_conversion_p (TREE_TYPE (orig_cval), TREE_TYPE (cval)))
+       cval = fold_convert (TREE_TYPE (orig_cval), cval);
+      return cval;
+    }
   return orig_cval;
 }
 
Index: gcc/testsuite/g++.dg/tree-ssa/pr89698.C
===================================================================
--- gcc/testsuite/g++.dg/tree-ssa/pr89698.C     (nonexistent)
+++ gcc/testsuite/g++.dg/tree-ssa/pr89698.C     (working copy)
@@ -0,0 +1,29 @@
+// { dg-do compile }
+// { dg-options "-O -fdump-tree-fre1" }
+
+class A {
+    virtual void f(){};
+public:
+    int x;
+    A(int in): x(in) {};
+};
+
+class B: public A {
+public:
+    int y;
+    B(int in):A(in-1), y(in) {};
+};
+
+void bar(void *);
+void test()
+{
+  B b(2);
+  A* bp = &b;
+  void* vp = dynamic_cast<void*>(bp);
+  bar (vp);
+}
+
+// We should be able to constant fold from the virtual table
+// the offset added to bp for the dynamic cast and forward
+// &b to the argument of bar
+// { dg-final { scan-tree-dump "bar \\\(&b" "fre1" } }

Reply via email to