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

Reply via email to