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

            Bug ID: 113282
           Summary: RISC-V non-atomic union store/load reordering
           Product: gcc
           Version: 14.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: patrick at rivosinc dot com
  Target Milestone: ---

I'm not sure if this is a bug or a valid optimization. Posting this here to
educate myself :)

Testcase:
union {
  long c;
  int b;
} e;
int f;
int *g = &e.b;
long *h = &e.c;
int main() {
  *g = 1;
  if (*h == 1)
    return 0;
  else
    return 1;
}

risc-v -O2:
main:
        lui     a5,%hi(h)
        ld      a5,%lo(h)(a5)
        ld      a0,0(a5)
        lui     a5,%hi(g)
        ld      a5,%lo(g)(a5) << Load
        li      a4,1
        addi    a0,a0,-1
        snez    a0,a0
        sw      a4,0(a5) << Store pushed below the load
        ret
f:
        .zero   4
        .zero   4
e:
        .zero   8
h:
        .dword  e
g:
        .dword  e

My educated guess is that since the operations aren't marked as atomic, the
compiler is free to ignore the dependency and optimize the load before the
store. After marking the ops as atomic:
union {
  long c;
  int b;
} e;
int f;
int *g = &e.b;
long *h = &e.c;
int main() {
  __atomic_store_n(g, 1, __ATOMIC_RELAXED);
  if (__atomic_load_n(h, __ATOMIC_RELAXED) == 1)
    return 0;
  else
    return 1;
}

The problem goes away:
main:
        lui     a5,%hi(g)
        ld      a5,%lo(g)(a5)
        li      a4,1
        sw      a4,0(a5) << Store remains above the load
        lui     a5,%hi(h)
        ld      a5,%lo(h)(a5)
        ld      a0,0(a5) << Load
        addi    a0,a0,-1
        snez    a0,a0
        ret
f:
        .zero   4
        .zero   4
e:
        .zero   8
h:
        .dword  e
g:
        .dword  e

Is that a correct line of reasoning? On x86 this problem doesn't manifest so
it's also possibly a risc-v bug.

Reply via email to