Bug 106064 - Wrong code comparing two global zero-sized arrays
Summary: Wrong code comparing two global zero-sized arrays
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 12.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2022-06-23 12:36 UTC by Alex Coplan
Modified: 2022-07-08 17:02 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Alex Coplan 2022-06-23 12:36:49 UTC
For the following C code:

int a[0] = {};
int b[0] = {};
int f(void)
{
    return a != b;
}
int g(void)
{
    return (__UINTPTR_TYPE__)a != (__UINTPTR_TYPE__)b;
}

on AArch64 at -O2, we generate:

f:
        mov     w0, 1
        ret
g:
        mov     w0, 0
        ret

so f and g get optimized in contradictory ways. At least one of them must be wrong.
Comment 1 ktkachov 2022-06-23 16:21:11 UTC
This seems to have changed in the GCC 9 series. GCC 8.5 generates:
f():
        mov     w0, 1
        ret
g():
        mov     w0, 1
        ret
b:
a:

Tagging as a claimed wrong-code bug.
Comment 2 Mikael Pettersson 2022-06-24 09:56:48 UTC
Seems target-dependent. I can't reproduce on x86_64-linux-gnu or sparc64-linux-gnu: both compile f() to return 1 and g() to perform a runtime computation. But ppc64-linux-gnu and armv7l-linux-gnueabi behave as your aarch64 example: f() returns 1 and g() returns 0 (unconditionally, no runtime computations).
Comment 3 Andrew Pinski 2022-06-24 10:20:38 UTC
(In reply to Mikael Pettersson from comment #2)
> Seems target-dependent. I can't reproduce on x86_64-linux-gnu or
> sparc64-linux-gnu: both compile f() to return 1 and g() to perform a runtime
> computation. But ppc64-linux-gnu and armv7l-linux-gnueabi behave as your
> aarch64 example: f() returns 1 and g() returns 0 (unconditionally, no
> runtime computations).

Most likely section anchors is the cause of the difference between the targets.
The ones which implement section anchors return different values between the functions. Is suspect MIPS has similar behavior too.
Comment 4 Andrew Pinski 2022-06-24 10:21:42 UTC
(In reply to Andrew Pinski from comment #3)
> (In reply to Mikael Pettersson from comment #2)
> > Seems target-dependent. I can't reproduce on x86_64-linux-gnu or
> > sparc64-linux-gnu: both compile f() to return 1 and g() to perform a runtime
> > computation. But ppc64-linux-gnu and armv7l-linux-gnueabi behave as your
> > aarch64 example: f() returns 1 and g() returns 0 (unconditionally, no
> > runtime computations).
> 
> Most likely section anchors is the cause of the difference between the
> targets.
> The ones which implement section anchors return different values between the
> functions. Is suspect MIPS has similar behavior too.

It is also most likely why aarch64 changed between 8 and 9 too.
Comment 5 Alex Coplan 2022-06-24 10:28:32 UTC
Bisection shows this changed with r9-5411-g93aa3c4aca3647645cd5bce724f9d2126de4b5ea on AArch64:

commit 93aa3c4aca3647645cd5bce724f9d2126de4b5ea (refs/bisect/bad)
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Tue Jan 15 09:11:00 2019 +0100

    re PR tree-optimization/88775 (Optimize std::string assignment)

            PR tree-optimization/88775
            * match.pd (cmp (convert1?@2 addr@0) (convert2? addr@1)): Optimize
            equal == 0 equality pointer comparisons some more if compared in
            integral types and either one points to an automatic var and the
            other to a global, or we can prove at least one points to the middle
            or both point to start or both point to end.

            * gcc.dg/tree-ssa/pr88775-1.c: New test.
            * gcc.dg/tree-ssa/pr88775-2.c: New test.
Comment 6 Richard Biener 2022-06-24 10:30:52 UTC
Note whether a != b is probably undefined (but zero size objects are a GNU extension).
Comment 7 Alex Coplan 2022-06-24 10:34:10 UTC
(In reply to Richard Biener from comment #6)
> Note whether a != b is probably undefined (but zero size objects are a GNU
> extension).

Just to clarify, are you saying this is undefined specifically for zero size objects or undefined in general for distinct objects? I thought for the latter == and != were ok, but < and such were UB.
Comment 8 Jakub Jelinek 2022-06-24 10:50:12 UTC
The IMHO UB case is for a != b when one address is at the start of one object and the other address is at the end of another one, which for zero sized objects is more often because the start address is the same as end address.
For integral comparisons we try to be more conservative.
Comment 9 Alex Coplan 2022-06-27 10:15:36 UTC
So if f is UB, I suppose the question is whether the codegen for g is correct?
Comment 10 Jakub Jelinek 2022-06-27 10:19:12 UTC
IMHO it is.
Comment 11 Alex Coplan 2022-06-27 12:21:19 UTC
(In reply to Jakub Jelinek from comment #8)
> The IMHO UB case is for a != b when one address is at the start of one
> object and the other address is at the end of another one

Just to dig a little deeper on this, what makes this case UB? Is there something in the standard to this effect?
Comment 12 Richard Earnshaw 2022-06-27 14:18:15 UTC
(In reply to Alex Coplan from comment #11)
> (In reply to Jakub Jelinek from comment #8)
> > The IMHO UB case is for a != b when one address is at the start of one
> > object and the other address is at the end of another one
> 
> Just to dig a little deeper on this, what makes this case UB? Is there
> something in the standard to this effect?

As stated in #6, zero-sized objects are a GNU extension.  I guess that means we get to define what the behaviour should be :)
Comment 13 Alex Coplan 2022-06-27 14:25:29 UTC
(In reply to Richard Earnshaw from comment #12)
> (In reply to Alex Coplan from comment #11)
> > (In reply to Jakub Jelinek from comment #8)
> > > The IMHO UB case is for a != b when one address is at the start of one
> > > object and the other address is at the end of another one
> > 
> > Just to dig a little deeper on this, what makes this case UB? Is there
> > something in the standard to this effect?
> 
> As stated in #6, zero-sized objects are a GNU extension.  I guess that means
> we get to define what the behaviour should be :)

Sure, but Jakub's reply seemed to get at some underlying principle as opposed to just saying "zero-sized objects are a GNU extension and we declare this case to be undefined".
Comment 14 Alex Coplan 2022-07-08 17:02:26 UTC
Closing as invalid, then, given that (as Jakub says) f is UB and the codegen for g is correct.