Почему gcc заполняет весь массив нулями вместо оставшихся 96 целых чисел? Все ненулевые инициализаторы находятся в начале массива.
void *sink;
void bar() {
int a[100]{1,2,3,4};
sink = a; // a escapes the function
asm("":::"memory"); // and compiler memory barrier
// forces the compiler to materialize a[] in memory instead of optimizing away
}
MinGW8.1 и gcc9.2 оба создают asm вот так ( проводник компилятора Godbolt ).
# gcc9.2 -O3 -m32 -mno-sse
bar():
push edi # save call-preserved EDI which rep stos uses
xor eax, eax # eax=0
mov ecx, 100 # repeat-count = 100
sub esp, 400 # reserve 400 bytes on the stack
mov edi, esp # dst for rep stos
mov DWORD PTR sink, esp # sink = a
rep stosd # memset(a, 0, 400)
mov DWORD PTR [esp], 1 # then store the non-zero initializers
mov DWORD PTR [esp+4], 2 # over the zeroed part of the array
mov DWORD PTR [esp+8], 3
mov DWORD PTR [esp+12], 4
# memory barrier empty asm statement is here.
add esp, 400 # cleanup the stack
pop edi # and restore caller's EDI
ret
(с включенным SSE он скопирует все 4 инициализатора с загрузкой / хранением movdqa)
Почему GCC не делает lea edi, [esp+16]
и устанавливает (с rep stosd
) только последние 96 элементов, как это делает Кланг? Это пропущенная оптимизация или так эффективнее? (На самом деле звонит Clang memset
вместо того, чтобы вставлять rep stos
)
Примечание редактора: изначально вопрос содержал неоптимизированный вывод компилятора, который работал таким же образом, но неэффективный код -O0
ничего не доказывает. Но оказывается, что эта оптимизация пропущена GCC даже в -O3
.
Передача указателя на a
не встроенную функцию была бы другим способом заставить компилятор материализоваться a[]
, но в 32-битном коде, который приводит к значительному загромождению asm. (Аргументы стека приводят к толчкам, которые смешиваются с хранилищами в стеке для инициализации массива.)
Использование volatile a[100]{1,2,3,4}
получает GCC для создания, а затем скопировать массив, что безумие. Обычно volatile
полезно посмотреть, как компиляторы инициируют локальные переменные или размещают их в стеке.
.rodata
... Я не могу поверить, что копирование 400 байтов происходит быстрее, чем обнуление и установка 8 элементов.
-O3
(что и происходит). godbolt.org/z/rh_TNF
missed-optimization
ключевым словом.
a[0] = 0;
и тогдаa[0] = 1;
.