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

            Bug ID: 127563
           Summary: [D] false aliasing issue causing unnecessary reload
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: d
          Assignee: ibuclaw at gdcproject dot org
          Reporter: witold.baryluk+gcc at gmail dot com
  Target Milestone: ---

```
struct A {
    ubyte* head_;
    ubyte[] Append(ushort size) {
        *cast(ushort*)head_ = size;
        head_ += ushort.sizeof;
        auto p = head_[0 .. size];
        head_ += size;
        return p;
    }
}
```

gdc 17.0.0 (issues also present in older versions)

with -O3 -frelease -fstrict-aliasing -Wstrict-aliasing=3

for amd64 produces:

```
ubyte[] example.A.Append(ushort):
        mov     rax, QWORD PTR [rdi]
        mov     WORD PTR [rax], si
        mov     rax, QWORD PTR [rdi]    # reload here!
        movzx   esi, si
        add     rax, 2
        lea     rdx, [rax+rsi]
        mov     QWORD PTR [rdi], rdx
        mov     rdx, rax
        mov     rax, rsi
        ret
```


https://godbolt.org/z/W7nrvY99P

The link also shows that ldc / llvm has same issue of reloading the memory.

In gdc 9.2 to gdc 14.3, it is slightly different (better?) code, but still
reload is present:

```
ubyte[] example.A.Append(ushort):
        mov     rax, QWORD PTR [rdi]
        mov     WORD PTR [rax], si
        mov     rax, QWORD PTR [rdi]
        lea     rdx, [rax+2]
        movzx   eax, si
        lea     rcx, [rdx+rax]
        mov     QWORD PTR [rdi], rcx
        ret
```


C++ equivalent code has no such issues.

```
#include <cstdint>
#include <span>

struct A {
    std::uint8_t *head_;
    std::span<std::uint8_t> Append(std::uint16_t size) {
        *reinterpret_cast<std::uint16_t*>(head_) = size;
        head_ += sizeof(std::uint16_t);
        auto p = std::span<std::uint8_t>{head_, size};
        head_ += size;
        return p;
    }
};

std::span<std::uint8_t> f(A* a, std::uint16_t size) {
    return a->Append(size);
}
```

gives

```
"f(A*, unsigned short)":
        mov     rdx, QWORD PTR [rdi]
        movzx   eax, si
        mov     WORD PTR [rdx], si
        add     rdx, 2
        lea     rcx, [rdx+rax]
        xchg    rax, rdx
        mov     QWORD PTR [rdi], rcx
        ret
```





Simplified example with a standalone function:

```
void Append(ubyte** head_, ushort size) {
    *cast(ushort*)*head_ = 1;
    *head_ += ushort.sizeof;
    *cast(ushort*)*head_ = 2;
}
```

generates essentially the same issue:

```
void example.Append(ubyte**, ushort):
        mov     rax, QWORD PTR [rdi]
        mov     edx, 1
        mov     ecx, 2
        mov     WORD PTR [rax], dx
        mov     rax, QWORD PTR [rdi]
        lea     rdx, [rax+2]
        mov     QWORD PTR [rdi], rdx
        mov     WORD PTR [rax+2], cx
        ret
```

Reply via email to