Los bucles sin sobrecarga son una característica de algunos conjuntos de instrucciones de procesador cuyo hardware puede repetir el cuerpo de un bucle automáticamente, en lugar de requerir instrucciones de software que consumen ciclos (y, por lo tanto, tiempo) para hacerlo. [1] [2] Los bucles sin sobrecarga son comunes en los procesadores de señales digitales y algunos conjuntos de instrucciones CISC .
En muchos conjuntos de instrucciones, un bucle debe implementarse mediante instrucciones para incrementar o decrementar un contador, verificar si se ha llegado al final del bucle y, en caso contrario, saltar al principio del bucle para que pueda repetirse. Aunque esto normalmente solo representa alrededor de 3 a 16 bytes de espacio para cada bucle, incluso esa pequeña cantidad podría ser significativa según el tamaño de las memorias caché de la CPU . Más significativo es que cada una de esas instrucciones lleva tiempo para ejecutarse, tiempo que no se dedica a realizar un trabajo útil.
La sobrecarga de un bucle de este tipo es evidente en comparación con un bucle completamente desenrollado , en el que el cuerpo del bucle se duplica exactamente tantas veces como se ejecutará. En ese caso, no se desperdicia espacio ni tiempo de ejecución en instrucciones para repetir el cuerpo del bucle. Sin embargo, la duplicación causada por el desenrollado del bucle puede aumentar significativamente el tamaño del código, y el tamaño más grande puede incluso afectar el tiempo de ejecución debido a errores de caché . (Por esta razón, es común desenrollar bucles solo parcialmente, como transformarlo en un bucle que realiza el trabajo de cuatro iteraciones en un paso antes de repetirse. Esto equilibra las ventajas del desenrollado con la sobrecarga de repetir el bucle). Además, desenrollar completamente un bucle solo es posible para un número limitado de bucles: aquellos cuyo número de iteraciones se conoce en tiempo de compilación .
Por ejemplo, el siguiente código C podría compilarse y optimizarse en el siguiente código ensamblador x86:
Los procesadores con bucles sin sobrecarga tienen instrucciones de máquina y registros para repetir automáticamente una o más instrucciones. Según las instrucciones disponibles, es posible que solo sean adecuadas para bucles controlados por conteo ("bucles for") en los que se puede calcular de antemano el número de iteraciones, o solo para bucles controlados por condiciones ("bucles while"), como operaciones en cadenas terminadas en cero .
En el conjunto de instrucciones PIC , las instrucciones REPEAT
y DO
implementan bucles de sobrecarga cero. [1] REPEAT
solo repite una única instrucción, mientras que DO
repite una cantidad específica de instrucciones siguientes.
Blackfin ofrece dos bucles sin sobrecarga. [3] Los bucles se pueden anidar; si ambos bucles de hardware están configurados con la misma dirección de "fin de bucle", el bucle 1 se comportará como el bucle interno y se repetirá, y el bucle 0 se comportará como el bucle externo y se repetirá solo si el bucle 1 no se repite.
Los bucles se controlan mediante los registros LTx
y LBx
( x
de 0 a 1) para establecer la parte superior e inferior del bucle (es decir, la primera y la última instrucción que se ejecutará, que pueden ser las mismas para un bucle con una sola instrucción) y LCx
para el conteo del bucle. El bucle se repite si LCx
es distinto de cero al final del bucle, en cuyo caso LCx
se decrementa.
Los registros de bucle se pueden configurar manualmente, pero esto consumiría típicamente 6 bytes para cargar los registros y 8-16 bytes para configurar los valores que se cargarán. Es más común usar la instrucción de configuración de bucle (representada en ensamblador como LOOP
con la pseudoinstrucción LOOP_BEGIN
y LOOP_END
, o en una sola línea como LSETUP
), que opcionalmente inicializa LCx
y establece LTx
y LBx
en los valores deseados. Esto solo requiere 4-6 bytes, pero solo puede establecer LTx
y LBx
dentro de un rango limitado en relación con donde se encuentra la instrucción de configuración de bucle.
P0 = matriz + 396 ; R0 = 100 ; LC0 = R0 ; LOOP my_loop LC0 ; // establece LT0 y LB0 LOOP_BEGIN my_loop ; // pseudo-instrucción; genera una etiqueta utilizada para calcular LT0 // LC0 no se puede escribir directamente en la memoria, // por lo que debemos usar un registro temporal. R0 += -1 ; // igualmente rápido y pequeño sería R0 = LC0 [ P0 -- ] = R0 ; LOOP_END my_loop ; // pseudo-instrucción; genera una etiqueta utilizada para calcular LB0
Los prefijos del lenguaje ensamblador x86 REP
implementan bucles sin sobrecarga para unas pocas instrucciones (a saber, MOVS/STOS/CMPS/LODS/SCAS
). [4] Según el prefijo y la instrucción, la instrucción se repetirá varias veces manteniendo (E)CX
el recuento de repeticiones o hasta que se encuentre una coincidencia (o no coincidencia) con AL/AX/EAX
o con DS:[(E)SI]
. Esto se puede utilizar para implementar algunos tipos de búsquedas y operaciones en cadenas terminadas en nulo .