← SEARCHABLE ARCHIVE
Assembly · 2026-05-12

Compilador para optimización de declaraciones

¿Bajo qué condiciones optimiza el compilador las declaraciones For?

INTERACTIVE READING MODE →

Los artículos escritos en este blog fueron creados con el objetivo de enseñar. Además, la información del artículo puede ser incorrecta, así que tenga cuidado.

Desde la perspectiva de la CPU, la instrucción JMP utilizada en la declaración For es: Debido a que la degradación del rendimiento ocurre cuando la canalización se interrumpe o falla la predicción de la rama, El compilador intenta no utilizar instrucciones JMP si se cumplen las condiciones.

  1. Cuando el número de iteraciones se confirma como una constante en el momento de la compilación.

Optimizable: for (int i = 0; i < 4; i++) (sabiendo que se repetirá 4 veces) Dificultad de optimización: for (int i = 0; i < n; i++) (si n es una variable determinada en tiempo de ejecución)

//código original
for (int i = 0; i < 3; i++) {
    arr[i] = 0;
}

//Después de la optimización del compilador
arr[0] = 0;
arr[1] = 0;
arr[2] = 0;

Lenguaje ensamblador antes de la optimización.

.L2:
    cmp     DWORD PTR [rbp-4], 2    ;Comparar si i < 3
    jg      .L3                     ;Si no se cumplen las condiciones, el bucle finaliza (salta a L3).
    mov     eax, DWORD PTR [rbp-4]
    cdqe
    mov     DWORD PTR [rbp-32+rax*4], 0 ;arr[i] = 0 asignación
    add     DWORD PTR [rbp-4], 1    ; i++
    jmp     .L2                     ;Salto incondicional hacia atrás al punto de inicio del bucle (.L2) (JMP)
.L3:

Lenguaje ensamblador optimizado

mov     DWORD PTR [rdi], 0      ; arr[0] = 0
mov     DWORD PTR [rdi+4], 0    ;arr[1] = 0 (+4 porque int tiene 4 bytes)
mov     DWORD PTR [rdi+8], 0    ;arr[2] = 0 (+8 porque int tiene 4 bytes)
  1. Cuando el resultado final se puede calcular por adelantado en el momento de la compilación.

Cuando la lógica dentro del bucle no depende de entradas y salidas externas, el valor del resultado se reemplaza por una constante.

//código original
int sum = 0;
for (int i = 1; i <= 100; i++) {
    sum += i;
}
return sum;

//Después de la optimización del compilador
//JMP ni siquiera realiza operaciones de suma en tiempo de ejecución.
return 5050;

Lenguaje ensamblador antes de la optimización.

.L5:
    cmp     DWORD PTR [rbp-4], 100  ;Comparar si i <= 100
    jg      .L6                     ;O terminar el ciclo
    mov     eax, DWORD PTR [rbp-4]
    add     DWORD PTR [rbp-8], eax  ; sum += i
    add     DWORD PTR [rbp-4], 1    ; i++
    jmp     .L5                     ;Volver al inicio del bucle (.L5) (JMP)
.L6:
    mov     eax, DWORD PTR [rbp-8]  ;Preparándose para devolver resultados

Lenguaje ensamblador después de la optimización.

mov     eax, 5050                   ;Inserte el valor del resultado calculado 5050 en el registro eax.
ret                                 ;regresar inmediatamente
  1. Cuando la longitud del código es corta incluso con la expansión del bucle.

Expandir un bucle como el código 1 se llama expansión de bucle o desenrollado de bucle. Si la longitud del código se vuelve demasiado larga debido a la expansión del bucle, es un desperdicio de la memoria caché de instrucciones de la CPU. Si el tamaño del código dentro del bucle no es pequeño, Loop Unrolling no está optimizado.

  1. Cuando no hay un flujo de control complejo dentro del bucle.

Hay una declaración break, continue, goto o compleja if-else dentro del bucle, o Si se incluye una llamada a una función externa, el compilador no expande el bucle descuidadamente.

Si hay una función de E/S como printf, Dado que debemos proteger los efectos secundarios que se muestran en la pantalla, honestamente ejecutamos JMP y llamamos a la función sin omitir el bucle.

Además, la opción de optimización del compilador debe estar activada para intentar la optimización como se indica arriba.