https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128016
Bug ID: 128016
Summary: Extra pointer increment and copy when updating a
reference in a loop
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: adamant.pwn at gmail dot com
Target Milestone: ---
Created attachment 65896
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65896&action=edit
Decimal parser benchmark: source files and compiler configuration
GCC generates extra pointer arithmetic for sum_direct compared with sum_local.
Both sum a zero-terminated array and leave p at its terminator.
unsigned sum_direct(const unsigned*& p) {
unsigned sum = 0;
while (*p) sum += *p++;
return sum;
}
unsigned sum_local(const unsigned*& p) {
auto q = p;
unsigned sum = 0;
while (*q) sum += *q++;
p = q;
return sum;
}
Reproduces on x86-64 with GCC trunk 17.0.0 20261019 (Compiler Explorer,
revision 1f9dc1fbeb06):
g++ -std=c++23 -O2 -S -masm=intel repro.cpp
After loading and testing the first element, sum_direct generates:
add rax, 4
xor ecx, ecx
.L3:
mov rsi, rax
add rax, 4
add ecx, edx
mov edx, DWORD PTR [rax-4]
test edx, edx
jne .L3
mov QWORD PTR [rdi], rsi
sum_local initializes ecx before testing the first element, then uses:
.L9:
add rax, 4
add ecx, edx
mov edx, DWORD PTR [rax]
test edx, edx
jne .L9
.L8:
mov QWORD PTR [rdi], rax
sum_direct could use the same pointer update as sum_local, avoiding the extra
increment before the loop and the copy inside it.
The same difference occurs in the attached decimal parser. With GCC 16.2.1
20260810 on a Ryzen 9 7945HX, using a local cursor reduced parsing time for
five million nine-digit tokens from 19.51 to 18.87 ms (3.3%; medians of 31
interleaved runs). The sum example above showed no meaningful timing
difference.
The attachment contains reader.cpp, benchmark.cpp and local g++ -v output. The
benchmark prints parsing time in milliseconds and checks the result sum and
each final cursor:
g++ -std=c++23 -O2 benchmark.cpp reader.cpp -o direct
g++ -std=c++23 -O2 -DLOCAL benchmark.cpp reader.cpp -o local
taskset -c 12 ./direct 5000000
taskset -c 12 ./local 5000000
Both parser variants passed ASan/UBSan.