¿Por qué gcc llena toda la matriz con ceros en lugar de solo los 96 enteros restantes? Los inicializadores distintos de cero están todos al inicio de la matriz.
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 y gcc9.2 hacen asm como este ( explorador del compilador 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
(con SSE habilitado, copiaría los 4 inicializadores con movdqa load / store)
¿Por qué GCC no hace lea edi, [esp+16]
y memset (con rep stosd
) solo los últimos 96 elementos, como lo hace Clang? ¿Es esta una optimización perdida, o es de alguna manera más eficiente hacerlo de esta manera? (Clang realmente llama en memset
lugar de en línea rep stos
)
Nota del editor: la pregunta originalmente tenía una salida del compilador no optimizada que funcionaba de la misma manera, pero un código ineficiente -O0
no prueba nada. Pero resulta que GCC echa de menos esta optimización incluso en -O3
.
Pasar un puntero a a
una función no en línea sería otra forma de forzar al compilador a materializarse a[]
, pero en un código de 32 bits que conduce a un desorden significativo del asm. (Los argumentos de pila dan como resultado empujes, que se mezclan con las tiendas en la pila para iniciar la matriz).
Usar volatile a[100]{1,2,3,4}
obtiene GCC para crear y luego copiar la matriz, que es una locura. Normalmente volatile
es bueno para ver cómo los compiladores inician las variables locales o las colocan en la pila.
.rodata
... No puedo creer que copiar 400 bytes sea más rápido que poner a cero y configurar 8 elementos.
-O3
(lo que sucede). godbolt.org/z/rh_TNF
missed-optimization
palabra clave.
a[0] = 0;
y luegoa[0] = 1;
.