Но если мы предположим, что x
, y
и z
являются только целыми типами, есть ли разница в стоимости между A
и B
...
При условии, что A
и B
являются тривиальными типами одинакового размера, не должно быть никакой разницы в стоимости создания и копирования. Это связано с тем, что современные компиляторы реализуют объединение хранилищ :
-fstore-merging
Выполнение слияния узких хранилищ с последовательными адресами памяти. Этот проход объединяет смежные хранилища непосредственных значений, более узких, чем слово, в меньшее количество более широких хранилищ, чтобы уменьшить количество инструкций. Это включено по умолчанию на -O2
и выше, а также -Os
.
Пример кода:
#include <cstdint>
struct A {
std::int64_t x = 0;
std::int64_t y = 1;
};
struct B {
std::int64_t x = 0;
std::int32_t y = 1;
std::int32_t z = 2;
};
A f0(std::int64_t x, std::int64_t y) {
return {x, y};
}
B f1(std::int64_t x, std::int32_t y, std::int32_t z) {
return {x, y, z};
}
void g0(A);
void g1(B);
void h0(A a) { g0(a); }
void h1(B b) { g1(b); }
Здесь создается сборка для построения и копирования :
gcc-9.2 -O3 -std=gnu++17 -march=skylake
:
f0(long, long):
mov rax, rdi
mov rdx, rsi
ret
f1(long, int, int):
mov QWORD PTR [rsp-16], 0
mov QWORD PTR [rsp-24], rdi
vmovdqa xmm1, XMMWORD PTR [rsp-24]
vpinsrd xmm0, xmm1, esi, 2
vpinsrd xmm2, xmm0, edx, 3
vmovaps XMMWORD PTR [rsp-24], xmm2
mov rax, QWORD PTR [rsp-24]
mov rdx, QWORD PTR [rsp-16]
ret
h0(int, A):
mov rdi, rsi
mov rsi, rdx
jmp g0(A)
h1(int, B):
mov rdi, rsi
mov rsi, rdx
jmp g1(B)
clang-9.0 -O3 -std=gnu++17 -march=skylake
:
f0(long, long): # @f0(long, long)
mov rdx, rsi
mov rax, rdi
ret
f1(long, int, int): # @f1(long, int, int)
mov rax, rdi
shl rdx, 32
mov ecx, esi
or rdx, rcx
ret
h0(int, A): # @h0(int, A)
mov rdi, rsi
mov rsi, rdx
jmp g0(A) # TAILCALL
h1(int, B): # @h1(int, B)
mov rdi, rsi
mov rsi, rdx
jmp g1(B) # TAILCALL
Обратите внимание, как обе структуры передаются в регистрах в h0
и h1
.
Однако gcc
не выполняет код для построения B
, генерируя ненужные AVX
инструкции. Подано сообщение об ошибке .