Richard Biener <rguent...@suse.de> writes: > Our beloved condition combining code to BIT_FIELD_REFs miscompiles > the testcase because it relies on operand_equal_p to detect equal > bases. For some reason that very same operand_equal_p is > treating any dereference of a pointer based on the same pointer > or decl the same - idependent on the actual type used for the > access (in this case, two different sized structs). Weirdly > it already checks alignment... > > The following patch makes operand_equal_p behave and more > in line with what it does for MEM_REF handling. > > Bootstrap & regtest running on x86_64-unknown-linux-gnu. > > Richard. > > 2019-03-14 Richard Biener <rguent...@suse.de> > > PR middle-end/89698 > * fold-const.c (operand_equal_p): For INDIRECT_REF check > that the access types are similar. > > * g++.dg/torture/pr89698.C: New testcase. > > Index: gcc/fold-const.c > =================================================================== > --- gcc/fold-const.c (revision 269641) > +++ gcc/fold-const.c (working copy) > @@ -3220,10 +3220,16 @@ operand_equal_p (const_tree arg0, const_ > switch (TREE_CODE (arg0)) > { > case INDIRECT_REF: > - if (!(flags & OEP_ADDRESS_OF) > - && (TYPE_ALIGN (TREE_TYPE (arg0)) > - != TYPE_ALIGN (TREE_TYPE (arg1)))) > - return 0; > + if (!(flags & OEP_ADDRESS_OF)) > + { > + if (TYPE_ALIGN (TREE_TYPE (arg0)) > + != TYPE_ALIGN (TREE_TYPE (arg1))) > + return 0; > + /* Verify that the access types are compatible. */ > + if (TYPE_MAIN_VARIANT (TREE_TYPE (arg0)) > + != TYPE_MAIN_VARIANT (TREE_TYPE (arg1))) > + return 0;
Question from the peanut gallery, sorry, but: why's TYPE_MAIN_VARIANT rather than types_compatible_p the right check here? E.g. if the dereferenced types are both pointers, but pointers to different types, wouldn't they normally be equivalent in gimple? Thanks, Richard > + } > flags &= ~OEP_ADDRESS_OF; > return OP_SAME (0); > > Index: gcc/testsuite/g++.dg/torture/pr89698.C > =================================================================== > --- gcc/testsuite/g++.dg/torture/pr89698.C (nonexistent) > +++ gcc/testsuite/g++.dg/torture/pr89698.C (working copy) > @@ -0,0 +1,28 @@ > +/* { dg-do run } */ > + > +extern "C" void abort (void); > + > +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) {}; > +}; > + > +int test(void) > +{ > + int res; > + B b(2); > + A* bp = &b; > + void* vp = dynamic_cast<void*>(bp); > + if (((A*)vp)->x == 1 && ((B*)vp)->y == 2) > + return 1; > + return 0; > +} > +int main() { if (test() != 1) abort (); return 0; }