¿Por qué se asigna memoria de pila cuando no se usa?

14

Considere el siguiente ejemplo:

struct vector {
    int  size() const;
    bool empty() const;
};

bool vector::empty() const
{
    return size() == 0;
}

El código de ensamblaje generado para vector::empty(por clang, con optimizaciones):

push    rax
call    vector::size() const
test    eax, eax
sete    al
pop     rcx
ret

¿Por qué asigna espacio de pila? No se usa en absoluto. El pushy poppodría ser omitido. Las compilaciones optimizadas de MSVC y gcc también usan espacio de pila para esta función (ver en godbolt ), por lo que debe haber una razón.

Dr. Gut
fuente
77
¿Explicó el thisparámetro implícito ?
dan04
1
@Bob__: No. ¿Por qué debería hacerlo? vector::size()no está definido en el ejemplo para simular que no está en línea.
Dr. Gut
1
Entonces, ¿cómo podría un compilador optimizar algo que no sabe?
Bob__
1
@Bob__: Creo que conocer la implementación de vector::size()no es relevante para asignar o no asignar un marco de pila vector::empty(). En empty()esto solo se llama, sea lo que sea.
Dr. Gut
1
Bueno, estás llamando a una función que devuelve algo, necesitas espacio para eso (si no sabes nada mejor).
Bob__

Respuestas:

11

Asigna espacio de pila, por lo que la pila está alineada a 16 bytes. Es necesario, porque la dirección de retorno toma 8 bytes, por lo que se necesita un espacio adicional de 8 bytes para mantener la pila alineada de 16 bytes.

La alineación de los marcos de la pila se puede configurar con argumentos de línea de comandos para algunos compiladores.

  • MSVC : La documentación dice que la pila siempre está alineada con 16 bytes. Ningún argumento de línea de comando puede cambiar esto. El ejemplo de godbolt muestra que se restan 40 bytes rspal comienzo de la función, lo que significa que algo más también afecta esto.
  • Clang : la -mstack-alignmentopción especifica la alineación de la pila. Parece que el valor predeterminado es 16, aunque no está documentado. Si lo establece en 8, la asignación de la pila ( pushy pop) desaparece del código de ensamblado generado.
  • gcc : la -mpreferred-stack-boundaryopción especifica la alineación de la pila. Si el valor dado es N, significa 2 ^ N bytes de alineación. El valor predeterminado es 4, lo que significa 16 bytes. Si lo establece en 3 (es decir, 8 bytes), la asignación de la pila ( suby addpara rsp) desaparece del código de ensamblaje generado.

Echa un vistazo a godbolt .

geza
fuente
Es por eso que c ++ gurús, los expertos siempre han estado advirtiendo: miembros de venta struct / clase con el fin de la / las de mayor tamaño más largo al más pequeño ... sólo así sería correctamente eficiente
nonock
@geza: gracias. Investigué un poco para los otros dos compiladores y lo escribí a su respuesta. ¿Te gusta?
Dr. Gut
1
@ Dr.Gut: gracias, hiciste la respuesta mucho mejor y completa. Tenga en cuenta que la alineación de la pila generalmente se documenta en la ABI para el sistema (por ejemplo, para algunos sistemas, aquí están los documentos: github.com/hjl-tools/x86-psABI/wiki/X86-psABI ).
geza
@geza: gracias.
Dr. Gut