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" } }