> >may lead to wrong code. > > Can you try generating a testcase? > Because with equal vptr and voffset I can't see how that can happen unless > some pass extracts information from the pointer types without sanity checking > with the pointers and offsets.
I am not sure I can get a wrong code with current mainline, because for now you only substitute for the lookup done for speculative devirt and if we wrongly predict the thing to be __builtin_unreachable, we dispatch to usual virtual call. Once you get movement on calls it will be easier to do. OBJ_TYPE_REF is a wrapper around OBJ_TYPE_EXPR adding three extra parameters: - OBJ_TYPE_REF_OBJECT - OBJ_TYPE_REF_TOKEN - obj_type_ref_class which is computed from TREE_TYPE (obj_type_ref) itself. While two OBJ_TYPE_REFS with equivalent OBJ_TYPE_EXPR are kind of same expressions, they are optimized differently (just as if they was in different alias set). For that reason you need to match the type of obj_type_ref_class because that one is not matched by usless_type_conversion (it is a pointer to method of corresponding class type we are looking up) The following testcase: struct foo {virtual void bar(void) __attribute__ ((const));}; struct foobar {virtual void bar(void) __attribute__ ((const));}; void dojob(void *ptr, int t) { if (t) ((struct foo*)ptr)->bar(); else ((struct foobar*)ptr)->bar(); } produces void dojob(void*, int) (void * ptr, int t) { int (*__vtbl_ptr_type) () * _5; int (*__vtbl_ptr_type) () _6; int (*__vtbl_ptr_type) () * _8; int (*__vtbl_ptr_type) () _9; <bb 2>: if (t_2(D) != 0) goto <bb 3>; else goto <bb 4>; <bb 3>: _5 = MEM[(struct foo *)ptr_4(D)]._vptr.foo; _6 = *_5; OBJ_TYPE_REF(_6;(struct foo)ptr_4(D)->0) (ptr_4(D)); goto <bb 5>; <bb 4>: _8 = MEM[(struct foobar *)ptr_4(D)]._vptr.foobar; _9 = *_8; OBJ_TYPE_REF(_9;(struct foobar)ptr_4(D)->0) (ptr_4(D)); <bb 5>: return; } Now I would need to get some code movement done to get _5 and _6 moved and unified with _8 and _9 that we currently don't do. Still would feel safer if the equivalence predicate also checked that the type is the same. > >Or do you just substitute the operands of OBJ_TYPE_REF? > > No, I value number them. But yes, the type issue also crossed my mind. > Meanwhile testing revealed that I need to adjust gimple_expr_type to preserve > the type of the obj-type-ref, otherwise the devirt machinery ICEs (receiving > void *). That's also a reason we can't make obj-type-ref a ternary RHS. Yep, type of OBJ_TYPE_REF matters... > > >> Bootstrap & regtest running on x86_64-unknown-linux-gnu. > >> > >> Note that this does not (yet) substitute OBJ_TYPE_REFs in calls > >> with SSA names that have the same value - not sure if that would > >> be desired generally (does the devirt machinery cope with that?). > > > >This should work fine. > > OK. So with that substituting the direct call later should work as well. Great! > > Richard. Honza > > >> > >> Thanks, > >> Richard. > >> > >> 2015-12-03 Richard Biener <rguent...@suse.de> > >> > >> PR tree-optimization/64812 > >> * tree-ssa-sccvn.c (vn_get_stmt_kind): Handle OBJ_TYPE_REF. > >> (vn_nary_length_from_stmt): Likewise. > >> (init_vn_nary_op_from_stmt): Likewise. > >> * gimple-match-head.c (maybe_build_generic_op): Likewise. > >> * gimple-pretty-print.c (dump_unary_rhs): Likewise. > >> > >> * g++.dg/tree-ssa/ssa-fre-1.C: New testcase. > >> > >> Index: gcc/tree-ssa-sccvn.c > >> =================================================================== > >> *** gcc/tree-ssa-sccvn.c (revision 231221) > >> --- gcc/tree-ssa-sccvn.c (working copy) > >> *************** vn_get_stmt_kind (gimple *stmt) > >> *** 460,465 **** > >> --- 460,467 ---- > >> ? VN_CONSTANT : VN_REFERENCE); > >> else if (code == CONSTRUCTOR) > >> return VN_NARY; > >> + else if (code == OBJ_TYPE_REF) > >> + return VN_NARY; > >> return VN_NONE; > >> } > >> default: > >> *************** vn_nary_length_from_stmt (gimple *stmt) > >> *** 2479,2484 **** > >> --- 2481,2487 ---- > >> return 1; > >> > >> case BIT_FIELD_REF: > >> + case OBJ_TYPE_REF: > >> return 3; > >> > >> case CONSTRUCTOR: > >> *************** init_vn_nary_op_from_stmt (vn_nary_op_t > >> *** 2508,2513 **** > >> --- 2511,2517 ---- > >> break; > >> > >> case BIT_FIELD_REF: > >> + case OBJ_TYPE_REF: > >> vno->length = 3; > >> vno->op[0] = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0); > >> vno->op[1] = TREE_OPERAND (gimple_assign_rhs1 (stmt), 1); > >> Index: gcc/gimple-match-head.c > >> =================================================================== > >> *** gcc/gimple-match-head.c (revision 231221) > >> --- gcc/gimple-match-head.c (working copy) > >> *************** maybe_build_generic_op (enum tree_code c > >> *** 243,248 **** > >> --- 243,249 ---- > >> *op0 = build1 (code, type, *op0); > >> break; > >> case BIT_FIELD_REF: > >> + case OBJ_TYPE_REF: > >> *op0 = build3 (code, type, *op0, op1, op2); > >> break; > >> default:; > >> Index: gcc/gimple-pretty-print.c > >> =================================================================== > >> *** gcc/gimple-pretty-print.c (revision 231221) > >> --- gcc/gimple-pretty-print.c (working copy) > >> *************** dump_unary_rhs (pretty_printer *buffer, > >> *** 302,308 **** > >> || TREE_CODE_CLASS (rhs_code) == tcc_reference > >> || rhs_code == SSA_NAME > >> || rhs_code == ADDR_EXPR > >> ! || rhs_code == CONSTRUCTOR) > >> { > >> dump_generic_node (buffer, rhs, spc, flags, false); > >> break; > >> --- 302,309 ---- > >> || TREE_CODE_CLASS (rhs_code) == tcc_reference > >> || rhs_code == SSA_NAME > >> || rhs_code == ADDR_EXPR > >> ! || rhs_code == CONSTRUCTOR > >> ! || rhs_code == OBJ_TYPE_REF) > >> { > >> dump_generic_node (buffer, rhs, spc, flags, false); > >> break; > >> Index: gcc/testsuite/g++.dg/tree-ssa/ssa-fre-1.C > >> =================================================================== > >> *** gcc/testsuite/g++.dg/tree-ssa/ssa-fre-1.C (revision 0) > >> --- gcc/testsuite/g++.dg/tree-ssa/ssa-fre-1.C (working copy) > >> *************** > >> *** 0 **** > >> --- 1,44 ---- > >> + /* { dg-do compile } */ > >> + /* { dg-options "-O2 -fdump-tree-fre2" } */ > >> + > >> + template <class T> class A > >> + { > >> + T *p; > >> + > >> + public: > >> + A (T *p1) : p (p1) { p->acquire (); } > >> + }; > >> + > >> + class B > >> + { > >> + public: > >> + virtual void acquire (); > >> + }; > >> + class D : public B > >> + { > >> + }; > >> + class F : B > >> + { > >> + int mrContext; > >> + }; > >> + class WindowListenerMultiplexer : F, public D > >> + { > >> + void acquire () { acquire (); } > >> + }; > >> + class C > >> + { > >> + void createPeer () throw (); > >> + WindowListenerMultiplexer maWindowListeners; > >> + }; > >> + class FmXGridPeer > >> + { > >> + public: > >> + void addWindowListener (A<D>); > >> + } a; > >> + void > >> + C::createPeer () throw () > >> + { > >> + a.addWindowListener (&maWindowListeners); > >> + } > >> + > >> + /* { dg-final { scan-tree-dump-times "= OBJ_TYPE_REF" 1 "fre2" } } > >*/ >