es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Entendiendo el ensamblador no optimizado de GCC para la UB n = ++n + ++n – ¿por qué incrementar dos veces antes de desplazar?

Entiendo que este comportamiento es indefinido y nadie realmente escribe código como este. Sin embargo, tengo curiosidad por saber qué haría el compilador con este fragmento de código.

Compilé utilizando tanto clang como gcc para hacer una comparación. Sin optimizaciones. Aquí está el ensamblado generado por clang:

# clang -O0
movl    $3, -4(%rbp)
movl    -4(%rbp), %ecx
addl    $1, %ecx
movl    %ecx, -4(%rbp)
movl    -4(%rbp), %edx
addl    $1, %edx
movl    %edx, -4(%rbp)
addl    %edx, %ecx
movl    %ecx, -4(%rbp)

Está copiando el valor 3 en un registro, lo incrementa, luego copia este valor incrementado nuevamente y lo incrementa una vez más, luego suma (3+1) + (3+1+1). Esto parece bastante sencillo.

Sin embargo, tengo dificultades para entender lo que GCC está haciendo. Aquí está el ensamblado generado por GCC:

# gcc -O0
movl    $3, -4(%rbp)
addl    $1, -4(%rbp)
addl    $1, -4(%rbp)
sall    -4(%rbp)

Según entiendo, se incrementa dos veces y luego se hace un desplazamiento hacia la izquierda (sall), lo que significa multiplicar por 2.

Pensé que notaba que ++n es el mismo en ambos lados del operando, por lo que lo tomaba como un factor común. Sin embargo, en ese caso, ¿por qué lo incrementó dos veces?

La versión de Clang da 9 y GCC da10 (Cualquier resultado es aceptable, dado el comportamiento indefinido, pero eso confirma que el resultado final de la lógica interna de los compiladores fue realmente diferente).

¿Alguien puede explicar qué está tratando de lograr GCC aquí?

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Parece que el enfoque de GCC en este código es primero incrementar el valor de n dos veces, y luego desplazar el resultado hacia la izquierda en un bit (sall). Esto efectivamente duplica el valor de (3+1) + (3+1+1), resultando en 10 en lugar de 9.

    Es posible que la estrategia de optimización de GCC sea buscar patrones en el código y optimizar en función de esos patrones, en lugar de intentar interpretar el código de una manera más directa. En este caso, es posible que haya notado que ++n se repetía dos veces y lo optimizó de una manera que priorizaba una ejecución más rápida sobre el estrito cumplimiento del código original.

    Sin embargo, es importante tener en cuenta que dado que este código presenta un comportamiento indefinido, la salida resultante es no determinista y no se debe confiar en ella. Es mejor evitar escribir código como este y siempre asegurarse de que su código esté bien definido y predecible.

Comments are closed.