https://gcc.gnu.org/bugzilla/show_bug.cgi?id=123214
Bug ID: 123214
Summary: Performance regression for std::optional
Product: gcc
Version: 15.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: kamkaz at windowslive dot com
Target Milestone: ---
In certain situations, parts of the std::optional seem to be moved to stack
from registers before being used.
#include <optional>
void fusroh(long&a, long&b, std::optional<long> c);
void dah(long&a, long&b, std::optional<long> c) {
if (c.has_value()) {
a += *c;
b += *c;
}
fusroh(a, b, c);
}
GCC generates:
dah(long&, long&, std::optional<long>):
mov QWORD PTR [rsp-24], rdx
mov QWORD PTR [rsp-16], rcx
cmp BYTE PTR [rsp-16], 0
je .L2
mov rax, QWORD PTR [rsp-24]
add QWORD PTR [rdi], rax
add QWORD PTR [rsi], rax
.L2:
mov rdx, QWORD PTR [rsp-24]
mov rcx, QWORD PTR [rsp-16]
jmp fusroh(long&, long&, std::optional<long>)
Clang generates:
dah(long&, long&, std::optional<long>):
test cl, 1
je .LBB0_2
add qword ptr [rdi], rdx
add qword ptr [rsi], rdx
.LBB0_2:
movzx ecx, cl
jmp fusroh(long&, long&, std::optional<long>)@PLT
In this scenario, both the flag and the value are moved to the stack before
being used. In some scenarios, only value gets moved to the stack. In yet other
ones, everything is processed in registers, as it should.
It seems to be a performance regression in GCC 9.1
I believe it to be of importance, as it might prevent certain code bases to
migrate from (const T*) "optional" parameters to std::optional