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
```