https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110799

--- Comment #9 from Alexander Monakov <amonakov at gcc dot gnu.org> ---
(In reply to Tom de Vries from comment #7)
> Can you elaborate on what you consider a correct approach?

I think this optimization is incorrect and should be active only under -Ofast.

I can offer two arguments. First, even without considering correctness,
breaking TSan and Helgrind is a substantial QoI issue and we should consider
shielding -O2 users from that (otherwise they'll discover it the hard way,
curse at us, stick -fno-hoist-adjacent-loads in their build system and consider
switching to another compiler).

Second, I can upgrade the initial example to an actual miscompilation. The
upgrade is based on two considerations: the optimization works on
possibly-trapping accesses, and relies on types of memory references to decide
if it's safe, but it runs late where the types are not what they were in the C
source. Hence, the following example:

struct S {
        int a;
};
struct M {
        int a, b;
};

int f(struct S *p, int c, int d)
{
        int r;
        if (c)
                if (d)
                        r = p->a;
                else
                        r = ((struct M*)p)->a;
        else
                r = ((struct M*)p)->b;
        return r;
}

is miscompiled to

f:
        mov     eax, DWORD PTR [rdi+4]
        test    esi, esi
        cmovne  eax, DWORD PTR [rdi]
        ret

even though the original program never accesses beyond struct S if 'c && d'.
Phi-opt incorrectly performs hoisting after PRE collapses 'if (d) ... else
...'.

Reply via email to