Skip to content

RISCV fence and load order broken when function inlined twice #164194

@macdice

Description

@macdice
struct PgAioHandle {
    char x;
    int y;
};

static inline bool
f(struct PgAioHandle *ioh, int y, char *x)
{
    *x = ioh->x;
    __atomic_thread_fence(__ATOMIC_ACQUIRE);
    if (ioh->y != y)
      return false;
    return true;
}

bool
g(struct PgAioHandle *ioh, int y)
{
    char x;
    if (!f(ioh, y, &x))
        return false;
    if (!f(ioh, y, &x))
        return false;
    return x != 0;
}

If f() is inlined just once (ie commend out the second call), then we load ->x before ->y with a fence as expected:

        lbu     a2, 0(a0)
        fence   r, rw
        lw      a0, 4(a0)

If f() is inlined twice, then we get this:

        fence   r, rw
        lw      a2, 4(a0)
        bne     a2, a1, .LBB0_3
        fence   r, rw
        lw      a2, 4(a0)
        bne     a2, a1, .LBB0_3
        lbu     a0, 0(a0)

The lbu of ->x is on the wrong side of the fence, right? Happens with all Clang versions on godbolt with -O1 and above, but doesn't happen with GCC. (This is minimized from src/backend/storage/aio/aio.c in PostgreSQL.)

https://godbolt.org/z/En4xKcfWz

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions