LLVM es un conjunto de tecnologías de compilación y cadena de herramientas [4] que se pueden utilizar para desarrollar un frontend para cualquier lenguaje de programación y un backend para cualquier arquitectura de conjunto de instrucciones . LLVM está diseñado en torno a una representación intermedia (IR) independiente del lenguaje que sirve como un lenguaje ensamblador portátil de alto nivel que se puede optimizar con una variedad de transformaciones en múltiples pasadas. [5] El nombre LLVM originalmente significaba Low Level Virtual Machine, aunque el proyecto se ha expandido y el nombre ya no es oficialmente un acrónimo .
LLVM está escrito en C++ y está diseñado para la optimización en tiempo de compilación , tiempo de enlace , tiempo de ejecución y "tiempo de inactividad". Originalmente implementado para C y C++, el diseño agnóstico del lenguaje de LLVM ha generado desde entonces una amplia variedad de interfaces: los lenguajes con compiladores que usan LLVM (o que no usan directamente LLVM pero pueden generar programas compilados como LLVM IR) incluyen ActionScript , Ada , C# para .NET , [6] [7] [8] Common Lisp , PicoLisp , Crystal , CUDA , D , Delphi , Dylan , Forth , [9] Fortran , FreeBASIC , Free Pascal , Halide , Haskell , Java bytecode , Julia , Kotlin , el lenguaje G de LabVIEW , [10] [11] Lua , Objective-C , OpenCL , [12] SQL y PLpgSQL de PostgreSQL , [13] Ruby , [14] Rust , [15] Scala , [16] [17] Swift , Xojo , y Zig .
El proyecto LLVM comenzó en 2000 en la Universidad de Illinois en Urbana-Champaign , bajo la dirección de Vikram Adve y Chris Lattner . LLVM se desarrolló originalmente como una infraestructura de investigación para investigar técnicas de compilación dinámica para lenguajes de programación estáticos y dinámicos . LLVM se lanzó bajo la Licencia de código abierto de la Universidad de Illinois/NCSA , [3] una licencia de software libre permisiva . En 2005, Apple Inc. contrató a Lattner y formó un equipo para trabajar en el sistema LLVM para varios usos dentro de los sistemas de desarrollo de Apple. [18] LLVM ha sido una parte integral de las herramientas de desarrollo Xcode de Apple para macOS e iOS desde Xcode 4 en 2011. [19]
En 2006, Lattner comenzó a trabajar en un nuevo proyecto llamado Clang . La combinación del frontend de Clang y el backend de LLVM se llama Clang/LLVM o simplemente Clang.
El nombre LLVM era originalmente un acrónimo de Low Level Virtual Machine . Sin embargo, el proyecto LLVM evolucionó hasta convertirse en un proyecto paraguas que tiene poca relación con lo que la mayoría de los desarrolladores actuales consideran una máquina virtual . Esto hizo que el acrónimo fuera "confuso" e "inapropiado", y desde 2011 LLVM "oficialmente ya no es un acrónimo", [20] sino una marca que se aplica al proyecto paraguas LLVM. [21] El proyecto abarca la representación intermedia (IR) de LLVM, el depurador de LLVM , la implementación de LLVM de la biblioteca estándar de C++ (con soporte completo de C++11 y C++14 [22] ), etc. LLVM es administrado por la Fundación LLVM. La ingeniera de compiladores Tanya Lattner se convirtió en su presidenta en 2014 [23] y ocupó el cargo a partir de marzo de 2024. [actualizar][ 24]
"Por el diseño e implementación de LLVM" , la Asociación para Maquinaria Computacional le otorgó a Vikram Adve, Chris Lattner y Evan Cheng el Premio al Sistema de Software ACM 2012. [25]
El proyecto estaba originalmente disponible bajo la licencia UIUC . Después del lanzamiento de la versión v9.0.0 en 2019, [26] LLVM cambió su licencia a la Licencia Apache 2.0 con Excepciones LLVM. [3] A noviembre de 2022, [actualizar]alrededor de 400 contribuciones no habían cambiado su licencia. [27] [28]
LLVM puede proporcionar las capas intermedias de un sistema de compilador completo, tomando el código de representación intermedia (IR) de un compilador y emitiendo un IR optimizado. Este nuevo IR puede luego convertirse y vincularse a un código de lenguaje ensamblador dependiente de la máquina para una plataforma de destino. LLVM puede aceptar el IR de la cadena de herramientas de GNU Compiler Collection (GCC) , lo que permite su uso con una amplia gama de interfaces de compilador existentes escritas para ese proyecto. LLVM también puede construirse con gcc después de la versión 7.5. [29]
LLVM también puede generar código de máquina reubicable en tiempo de compilación o de enlace o incluso código de máquina binario en tiempo de ejecución.
LLVM admite un conjunto de instrucciones y un sistema de tipos independientes del lenguaje . [5] Cada instrucción está en forma de asignación única estática (SSA), lo que significa que cada variable (llamada registro tipificado) se asigna una vez y luego se congela. Esto ayuda a simplificar el análisis de dependencias entre variables. LLVM permite que el código se compile estáticamente, como en el sistema GCC tradicional, o se deje para una compilación tardía desde el IR al código de máquina mediante la compilación justo a tiempo (JIT), similar a Java . El sistema de tipos consta de tipos básicos como números enteros o de punto flotante y cinco tipos derivados : punteros , matrices , vectores , estructuras y funciones . Una construcción de tipo en un lenguaje concreto se puede representar combinando estos tipos básicos en LLVM. Por ejemplo, una clase en C++ se puede representar mediante una mezcla de estructuras, funciones y matrices de punteros de función .
El compilador JIT de LLVM puede optimizar las ramas estáticas innecesarias de un programa en tiempo de ejecución y, por lo tanto, es útil para la evaluación parcial en casos en los que un programa tiene muchas opciones, la mayoría de las cuales se pueden determinar fácilmente como innecesarias en un entorno específico. Esta característica se utiliza en la canalización OpenGL de Mac OS X Leopard (v10.5) para brindar soporte para las características de hardware faltantes. [30]
El código gráfico dentro de la pila OpenGL se puede dejar en una representación intermedia y luego compilarlo cuando se ejecuta en la máquina de destino. En sistemas con unidades de procesamiento gráfico (GPU) de alta gama, el código resultante sigue siendo bastante fino, pasando las instrucciones a la GPU con cambios mínimos. En sistemas con GPU de gama baja, LLVM compilará procedimientos opcionales que se ejecutan en la unidad central de procesamiento (CPU) local que emulan instrucciones que la GPU no puede ejecutar internamente. LLVM mejoró el rendimiento en máquinas de gama baja que utilizan chipsets Intel GMA . Se desarrolló un sistema similar bajo el LLVMpipe de Gallium3D y se incorporó al shell de GNOME para permitir que se ejecutara sin un controlador de hardware 3D adecuado cargado. [31]
En 2011, los programas compilados por GCC superaron a los de LLVM en un 10%, en promedio. [32] [33] En 2013, phoronix informó que LLVM había alcanzado a GCC, compilando binarios de rendimiento aproximadamente igual. [34]
LLVM se ha convertido en un proyecto general que contiene múltiples componentes.
LLVM fue escrito originalmente para ser un reemplazo para el generador de código existente en la pila GCC, [35] y muchos de los frontends de GCC han sido modificados para trabajar con él, dando como resultado la suite LLVM-GCC ahora extinta. Las modificaciones generalmente involucran un paso IR de GIMPLE a LLVM para que los optimizadores y el generador de código de LLVM se puedan usar en lugar del sistema GIMPLE de GCC. Apple fue un usuario significativo de LLVM-GCC hasta Xcode 4.x (2013). [36] [37] Este uso del frontend de GCC se consideró principalmente una medida temporal, pero con la llegada de Clang y las ventajas de LLVM y la base de código modular y moderna de Clang (así como la velocidad de compilación), está prácticamente obsoleto.
LLVM actualmente [¿ a partir de? ] admite la compilación de Ada , C , C++ , D , Delphi , Fortran , Haskell , Julia , Objective-C , Rust y Swift mediante varias interfaces .
El interés generalizado en LLVM ha llevado a varios esfuerzos para desarrollar nuevas interfaces para muchos lenguajes. El que ha recibido más atención es Clang, un compilador más nuevo que soporta C, C++ y Objective-C. Clang, soportado principalmente por Apple, tiene como objetivo reemplazar el compilador C/Objective-C en el sistema GCC con un sistema que se integra más fácilmente con entornos de desarrollo integrados (IDE) y tiene un soporte más amplio para subprocesos múltiples . El soporte para directivas OpenMP se ha incluido en Clang desde la versión 3.8. [38]
El compilador Utrecht Haskell puede generar código para LLVM. Si bien el generador se encontraba en las primeras etapas de desarrollo, en muchos casos era más eficiente que el generador de código C. [39] El backend Glasgow Haskell Compiler (GHC) utiliza LLVM y logra una aceleración del 30 % del código compilado en relación con la compilación de código nativo a través de GHC o la generación de código C seguida de compilación, sin contar solo una de las muchas técnicas de optimización implementadas por GHC. [40]
Muchos otros componentes se encuentran en diversas etapas de desarrollo, incluidos, entre otros, el compilador Rust , una interfaz de código de bytes de Java , una interfaz de lenguaje intermedio común (CIL), la implementación MacRuby de Ruby 1.9, varias interfaces para Standard ML y un nuevo asignador de registros de coloración de gráficos . [ cita requerida ]
El núcleo de LLVM es la representación intermedia (IR), un lenguaje de programación de bajo nivel similar al lenguaje ensamblador. IR es un conjunto de instrucciones de computadora de conjunto reducido de instrucciones fuertemente tipado (RISC) que abstrae la mayoría de los detalles del objetivo. Por ejemplo, la convención de llamada se abstrae a través de instrucciones call
y ret
con argumentos explícitos. Además, en lugar de un conjunto fijo de registros, IR utiliza un conjunto infinito de temporales de la forma %0, %1, etc. LLVM admite tres formas equivalentes de IR: un formato de ensamblaje legible para humanos, [41] un formato en memoria adecuado para frontends y un formato de código de bits denso para serialización. Un programa simple "¡Hola, mundo!" en formato IR:
@.str = constante interna [ 14 x i8 ] c "Hola, mundo\0A\00" declarar i32 @printf ( ptr , ...) definir i32 @main ( i32 %argc , ptr %argv ) nounwind { entrada: %tmp1 = getelementptr [ 14 x i8 ], ptr @.str , i32 0 , i32 0 %tmp2 = llamar a i32 ( ptr , ...) @printf ( ptr %tmp1 ) nounwind ret i32 0 }
Las diferentes convenciones utilizadas y las características proporcionadas por los distintos objetivos significan que LLVM no puede producir verdaderamente un IR independiente del objetivo y redirigirlo sin romper algunas reglas establecidas. Se pueden encontrar ejemplos de dependencia del objetivo más allá de lo que se menciona explícitamente en la documentación en una propuesta de 2011 para "wordcode", una variante totalmente independiente del objetivo de LLVM IR destinada a la distribución en línea. [42] Un ejemplo más práctico es PNaCl . [43]
El proyecto LLVM también introduce otro tipo de representación intermedia denominada MLIR [44] que ayuda a construir una infraestructura de compilador reutilizable y extensible mediante el empleo de una arquitectura de complemento denominada Dialect. [45] Permite el uso de información de nivel superior sobre la estructura del programa en el proceso de optimización, incluida la compilación poliédrica .
En la versión 16, LLVM admite muchos conjuntos de instrucciones , incluidos IA-32 , x86-64 , ARM , Qualcomm Hexagon , LoongArch , M68K , MIPS , NVIDIA Parallel Thread Execution (PTX, también llamado NVPTX en la documentación de LLVM), PowerPC , AMD TeraScale , [46] las GPU AMD más recientes (también llamadas AMDGPU en la documentación de LLVM), [47] SPARC , z/Architecture (también llamado SystemZ en la documentación de LLVM) y XCore .
Algunas funciones no están disponibles en algunas plataformas. La mayoría de las funciones están presentes para IA-32, x86-64, z/Architecture, ARM y PowerPC. [48] RISC-V es compatible a partir de la versión 7.
En el pasado, LLVM también soportaba otros backends, total o parcialmente, incluyendo C backend, Cell SPU , mblaze (MicroBlaze) , [49] AMD R600, DEC/Compaq Alpha ( Alpha AXP ) [50] y Nios2 , [51] pero ese hardware está mayormente obsoleto, y los desarrolladores de LLVM decidieron que los costos de soporte y mantenimiento ya no estaban justificados. [ cita requerida ]
LLVM también admite WebAssembly como destino, lo que permite que los programas compilados se ejecuten en entornos habilitados para WebAssembly, como Google Chrome / Chromium , Firefox , Microsoft Edge , Apple Safari o WAVM. Los compiladores WebAssembly compatibles con LLVM generalmente admiten código fuente mayoritariamente sin modificar escrito en C, C++, D, Rust, Nim, Kotlin y varios otros lenguajes.
El subproyecto de código de máquina (MC) de LLVM es el marco de trabajo de LLVM para traducir instrucciones de máquina entre formatos textuales y código de máquina. Anteriormente, LLVM dependía del ensamblador del sistema, o de uno proporcionado por una cadena de herramientas, para traducir el ensamblador a código de máquina. El ensamblador integrado de LLVM MC es compatible con la mayoría de los objetivos de LLVM, incluidos IA-32, x86-64, ARM y ARM64. Para algunos objetivos, incluidos los diversos conjuntos de instrucciones MIPS, se puede utilizar la compatibilidad con el ensamblador integrado, pero aún se encuentra en la etapa beta. [ cita requerida ]
El subproyecto lld es un intento de desarrollar un enlazador integrado e independiente de la plataforma para LLVM. [52] lld tiene como objetivo eliminar la dependencia de un enlazador de terceros. A partir de mayo de 2017 [actualizar], lld admite ELF , PE/COFF , Mach-O y WebAssembly [53] en orden descendente de completitud. lld es más rápido que ambas versiones de GNU ld . [ cita requerida ]
A diferencia de los enlazadores GNU, lld tiene soporte integrado para optimización en tiempo de enlace (LTO). Esto permite una generación de código más rápida ya que evita el uso de un complemento enlazador, pero por otro lado prohíbe la interoperabilidad con otras versiones de LTO. [54]
El proyecto LLVM incluye una implementación de la biblioteca estándar de C++ denominada libc++, con doble licencia bajo la licencia MIT y la licencia UIUC . [55]
Desde la versión v9.0.0, se le cambió la licencia a la Licencia Apache 2.0 con excepciones LLVM. [3]
Esto implementa un conjunto de optimizaciones de localidad de caché, así como autoparalelismo y vectorización utilizando un modelo poliédrico . [56]
llvm-libc es una biblioteca estándar C incompleta, próxima a aparecer, independiente de ABI, diseñada por y para el proyecto LLVM. [57]
Debido a su licencia permisiva, muchos proveedores publican sus propios diapasones de LLVM. Esto está reconocido oficialmente por la documentación de LLVM, que sugiere no usar números de versión en las comprobaciones de características por este motivo. [58] Algunos de los proveedores incluyen:
RubyMotion
transforma el código fuente Ruby de su proyecto en ... código de máquina utilizando un compilador anticipado (AOT), basado en LLVM.
"LLVM" ya no es oficialmente un acrónimo. El acrónimo al que se amplió en el pasado resultó confuso e inapropiado casi desde el primer día. :) A medida que LLVM fue creciendo y abarcó otros subproyectos, se volvió aún menos útil y carente de sentido.
El nombre «LLVM» alguna vez fue un acrónimo, pero ahora es solo una marca para el proyecto general.
Tenga en cuenta que no se deben utilizar los números de versión de marketing para comprobar las características del lenguaje, ya que los distintos proveedores utilizan distintos esquemas de numeración. En su lugar, utilice las macros de comprobación de características.
La NVVM IR actual se basa en LLVM 5.0