On Wed, Mar 13, 2019 at 12:35 PM Richard Biener wrote:
>
>
> 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.
Applied as r270833.
Richard.
> Richard.
>
> 2019-03-14 Richard Biener
>
> 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 =
> + void* vp = dynamic_cast(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
> +// to the argument of bar
> +// { dg-final { scan-tree-dump "bar \\\(" "fre1" } }