При компиляции с Clang 10.0.0 и текущим Clang-trunk, похоже, отсутствуют некоторые довольно очевидные возможности оптимизации:
struct A {
int x[16] {0}; // Everything zero init by default
int y[16] {0};
int z[16] {0};
};
int foo(A* a, A* b); // dummy function in external translation unit
// to block any constant folding and unused variable
// elimination, etc.
int func() {
A a[1024],b[1024]; // clang calls memset for each of a and b
// could be optimized to single call
foo(a,b);
for( int i = 0 ; i < 1024 ; i++ ) {
a[i] = b[i]; // clang calls memcpy here 1024 times with
// consecutive addresses, could be optimized
// to single call.
}
return foo(a,b);
}
Результат, сгенерированный Clang для x64 при -O3, выглядит следующим образом: https://godbolt.org/z/taKi4G
func(): # @func()
push r15
push r14
push rbx
sub rsp, 393216
lea r14, [rsp + 196608]
xor ebx, ebx
mov edx, 196608
mov rdi, r14
xor esi, esi
call memset
mov r15, rsp
mov edx, 196608
mov rdi, r15
xor esi, esi
call memset
mov rdi, r14
mov rsi, r15
call foo(A*, A*)
.LBB0_1: # =>This Inner Loop Header: Depth=1
lea rdi, [rsp + rbx]
add rdi, 196608
lea rsi, [rsp + rbx]
mov edx, 192
call memcpy
lea rdi, [rsp + rbx]
add rdi, 196800
lea rsi, [rsp + rbx]
add rsi, 192
mov edx, 192
call memcpy
add rbx, 384
cmp rbx, 196608
jne .LBB0_1
lea rdi, [rsp + 196608]
mov rsi, rsp
call foo(A*, A*)
add rsp, 393216
pop rbx
pop r14
pop r15
ret
Я думаю, что два вызова memset могут быть объединены в один memset, а 1024 вызова memcpy можно объединить, оставив один memset и один memcpy. Улучшение memset может быть незначительным, но я почти уверен, что один вызов memcpy будет значительно быстрее.
Я пытался убедить кого-то, что они не должны использовать mempcy и memset в своем коде для копирования и обнуления массивов инициализации структур POD, и должны просто использовать конструкторы и позволить компилятору обрабатывать это. Мой аргумент несколько развалился, когда я на самом деле посмотрел, что сгенерировало clang.
Это слияние как-то недействительно, или clang просто упускает трюк?
Изменить: я проверил по G CC 10, и, похоже, он выполняет большую работу, как я ожидал, но все еще не объединяет наборы мемов.