Articulo de referencia

Movimiento de código

En informática , el movimiento de código , que incluye el movimiento de código (hoisting), el movimiento de código (sinking), el movimiento de código invariante a bucles y la fa...

En informática , el movimiento de código , que incluye el movimiento de código (hoisting), el movimiento de código (sinking), el movimiento de código invariante a bucles y la factorización de código), es un término general para cualquier proceso que mueva código dentro de un programa. Esto se suele hacer para mejorar el rendimiento y reducir el tamaño del programa, y ​​es una optimización común en la mayoría de los compiladores optimizadores .

Usos

La programación dinámica tiene una variedad de usos y beneficios, muchos de los cuales se superponen en su implementación.

Eliminación de operaciones no utilizadas/inútiles

Diagrama que muestra un compilador optimizador eliminando una llamada potencialmente inútil a la instrucción de ensamblaje "b" al relegarla a su punto de uso.

El hundimiento de código , también conocido como movimiento de código perezoso , es un término para una técnica que reduce las instrucciones desperdiciadas moviendo las instrucciones a las ramas en las que se utilizan: [ 1 ] Si una operación se ejecuta antes de una rama, y ​​solo una de las rutas de la rama utiliza el resultado de esa operación, entonces el hundimiento de código implica mover esa operación a la rama donde se utilizará.

Esta técnica es una forma de eliminación de código muerto en el sentido de que elimina el código cuando sus resultados se descartan o no se utilizan, pero a diferencia de la eliminación de código muerto, puede eliminar instrucciones inútiles incluso si existe un posible uso de los resultados de esa instrucción en una ruta de ejecución del código.

Reducir el tamaño del programa

Un diagrama que muestra la optimización del tamaño mediante la factorización del código, suponiendo que todas las operaciones no dependen de otras operaciones que se ejecutan antes.

La factorización de código es un término que describe una técnica de optimización de tamaño que fusiona las dependencias comunes en las ramas con la rama superior. [ 2 ] Al igual que la factorización de enteros descompone un número en sus formas más pequeñas posibles (como factores), la factorización de código transforma el código en la forma más pequeña posible, fusionando los "factores" comunes hasta que no queden duplicados.

Reducción de la dependencia y los bloqueos

Un ejemplo de cómo un compilador podría evitar bloqueos por dependencias en el código ensamblado mediante el movimiento del código, observando un gráfico de dependencias . Debido a los avances en la ejecución fuera de orden , la optimización podría no tener ningún beneficio en las CPU modernas.

El movimiento global del código , el movimiento local del código , la planificación del código , la planificación de instrucciones y el ascenso/descenso del código son términos que describen una técnica en la que las instrucciones se reorganizan (o "planifican") para mejorar la eficiencia de la ejecución dentro de la CPU. [ 3 ] [ 4 ] Las CPU modernas pueden planificar cinco o más instrucciones por ciclo de reloj. Sin embargo, una CPU no puede planificar una instrucción que dependa de datos de una instrucción que se esté ejecutando actualmente (o que aún no se haya ejecutado). Los compiladores intercalan las dependencias de manera que se maximice la cantidad de instrucciones que una CPU puede procesar en cualquier momento. [ 5 ]

En la arquitectura Intel Itanium , ya desaparecida, la instrucción de predicción de bifurcación (BRP) es elevada manualmente por el compilador por encima de las bifurcaciones para permitir que la CPU las ejecute inmediatamente. Itanium depende de la planificación de código adicional de la CPU para maximizar la eficiencia del procesador. [ 6 ]

Movimiento de código invariante de bucle

Diagrama que representa el movimiento del código invariante en bucles sobre un grafo de ejecución. Esto supone que D es invariante entre las ejecuciones de bucle.

El movimiento de código invariante de bucle es el proceso de trasladar código invariante de bucle a una posición fuera del bucle, lo que puede reducir el tiempo de ejecución del bucle al evitar que algunos cálculos se realicen dos veces para obtener el mismo resultado.

Ejemplos de compiladores

LLVM

LLVM tiene una pasada de hundimiento en su forma de asignación estática única. LLVM 15.0 no hundirá una operación si alguna de sus rutas de código incluye una instrucción de almacenamiento, o si puede lanzar un error. [ 7 ] Además, LLVM no hundirá una instrucción en un bucle.

GCC

La Colección de Compiladores GNU implementa el movimiento de código bajo el nombre de "factorización de código", con el propósito de reducir el tamaño de un programa compilado. [ 8 ] GCC moverá cualquier código hacia arriba o hacia abajo si "[no] invalida ninguna dependencia existente ni introduce otras nuevas". [ 9 ]

LuaJIT

LuaJIT utiliza el hundimiento de código bajo el nombre de "hundimiento de asignación" para reducir el tiempo que el código compilado dedica a asignar y recolectar objetos temporales dentro de un bucle. [ 10 ] El hundimiento de asignación mueve las asignaciones a rutas de ejecución donde el objeto asignado puede escapar del código en ejecución y, por lo tanto, requerirá asignación en el montón . Todas las asignaciones eliminadas se rellenan con reenvío de carga a almacenamiento a través de sus campos. [ 11 ]

Véase también

Referencias

  1. Craft, Michael; Offut, Jefferson (1994). "Uso de técnicas de optimización de compiladores para detectar mutantes equivalentes" . Software Testing, Verification & Reliability . 4 (3): 131– 154. doi : 10.1002/stvr.4370040303 . S2CID 35717348. Consultado el 25 de febrero de 2022 . 
  2. Lóki, Gábor, et al. "Factorización de código en GCC". Actas de la Cumbre de Desarrolladores de GCC de 2004. 2004.
  3. Fasse, Justus, et al. Transformaciones de código para aumentar las oportunidades de programación de prepaso en CompCert. Diss. Tesis de maestría en ciencias. Universidad Grenoble Alpes. https://www-verimag . imag. fr/~ boulme/CPP_2022/FASSE-Justus-MSc-Thesis_2021. pdf, 2021.
  4. Gupta, Rajiv (1998). "Un marco de trabajo de movimiento de código para la planificación global de instrucciones". Construcción de compiladores . Notas de clase en ciencias de la computación. Vol. 1383. págs. 219–233 . doi : 10.1007/BFb0026434 . ISBN   978-3-540-64304-3.
  5. Chang, Pohua P., et al. "La importancia de la planificación de código de prepaso para procesadores superescalares y supersegmentados." IEEE Transactions on Computers 44.3 (1995): 353-370.
  6. Sharangpani, H.; Arora, H. (septiembre de 2000). "Microarquitectura del procesador Itanium". IEEE Micro . 20 (5): 24– 43. doi : 10.1109/40.877948 . ISSN 1937-4143 . 
  7. "LLVM: lib/Transforms/Scalar/Sink.cpp Archivo fuente" . llvm.org . Consultado el 25 de febrero de 2022 .
  8. "Optimizaciones de factorización de código - Proyecto GNU" . gcc.gnu.org . Consultado el 25 de febrero de 2022 .
  9. "GCC Developer's Summit 2004 - Code Factoring.pdf" (PDF) . gnu.org . Consultado el 25 de febrero de 2022 .
  10. "Asignación de memoria en git HEAD - luajit - FreeLists" . www.freelists.org . Consultado el 25 de febrero de 2022 .
  11. "Optimización de hundimiento de asignación" . wiki.luajit.org .