LLVM es un conjunto de tecnologías de compilación y cadena de herramientas [4] que se pueden utilizar para desarrollar una interfaz 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 Máquina virtual de bajo nivel, aunque el proyecto se ha expandido y el nombre ya no es oficialmente una inicialización .
LLVM está escrito en C++ y está diseñado para optimizar el tiempo de compilación , el tiempo de enlace , el tiempo de ejecución y el "tiempo de inactividad". Implementado originalmente para C y C++, el diseño independiente 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 , código de bytes de Java , Julia , Kotlin , 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 NCSA/Universidad de Illinois , [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 diversos 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 de Clang frontend y LLVM backend se denomina Clang/LLVM o simplemente Clang.
El nombre LLVM era originalmente una inicial de Low Level Virtual Machine . Sin embargo, el proyecto LLVM evolucionó hasta convertirse en un proyecto general que tiene poca relación con lo que la mayoría de los desarrolladores actuales consideran una máquina virtual . Esto hizo que las iniciales fueran "confusas" e "inapropiadas", y desde 2011 LLVM "ya no es oficialmente un acrónimo", [20] sino una marca que se aplica al proyecto general de 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. Se administra LLVM por la Fundación LLVM. La ingeniera compiladora Tanya Lattner se convirtió en su presidenta en 2014 [23] y ocupó el cargo a partir de 2023 [actualizar]. [24]
"Por diseñar e implementar LLVM" , la Association for Computing Machinery otorgó a Vikram Adve, Chris Lattner y Evan Cheng el premio ACM Software System Award 2012 . [25]
El proyecto estaba originalmente disponible bajo la licencia UIUC . Después del lanzamiento de v9.0.0 en 2019, [26] LLVM volvió a obtener la licencia Apache 2.0 con excepciones de LLVM. [3] En noviembre de 2022, [actualizar]alrededor de 400 contribuciones no habían recibido nuevas licencias. [27] [28]
LLVM puede proporcionar las capas intermedias de un sistema compilador completo, tomando código de representación intermedia (IR) de un compilador y emitiendo un IR optimizado. Este nuevo IR luego se puede convertir y vincular a un código en lenguaje ensamblador dependiente de la máquina para una plataforma de destino. LLVM puede aceptar el IR de la cadena de herramientas de la Colección de compiladores GNU (GCC) , lo que permite utilizarlo con una amplia gama de interfaces de compilador existentes escritos para ese proyecto. LLVM también se puede compilar 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 idioma . [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 compilar el código estáticamente, como ocurre con el sistema GCC tradicional, o dejarlo 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 combinación de estructuras, funciones y matrices de punteros de función .
El compilador LLVM JIT 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 los casos en que un programa tiene muchas opciones, la mayoría de las cuales pueden determinarse fácilmente como innecesarias en un entorno específico. Esta función se utiliza en la canalización OpenGL de Mac OS X Leopard (v10.5) para brindar soporte para funciones de hardware faltantes. [30]
El código de gráficos dentro de la pila OpenGL se puede dejar en representación intermedia y luego compilarse cuando se ejecuta en la máquina de destino. En sistemas con unidades de procesamiento de gráficos (GPU) de alta gama , el código resultante sigue siendo bastante delgado y pasa 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 y emulan instrucciones que la GPU no puede ejecutar internamente. LLVM mejoró el rendimiento en máquinas de gama baja que utilizan conjuntos de chips Intel GMA . Se desarrolló un sistema similar bajo Gallium3D LLVMpipe y se incorporó al shell GNOME para permitir que se ejecute 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 aproximadamente el mismo rendimiento. [34]
LLVM se ha convertido en un proyecto general que contiene múltiples componentes.
LLVM se escribió originalmente para reemplazar el generador de código existente en la pila GCC, [35] y muchas de las interfaces de GCC se han modificado para funcionar con él, lo que resultó en la ahora desaparecida suite LLVM-GCC. Las modificaciones generalmente implican un paso IR de GIMPLE a LLVM para que se puedan usar optimizadores y codegen de LLVM en lugar del sistema GIMPLE de GCC. Apple fue un usuario importante de LLVM-GCC a través de Xcode 4.x (2013). [36] [37] Este uso de la interfaz GCC se consideró principalmente una medida temporal, pero con la llegada de Clang y las ventajas de LLVM y la base de código moderna y modular 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 utilizando varias interfaces .
El interés generalizado en LLVM ha dado lugar a varios esfuerzos para desarrollar nuevas interfaces para muchos idiomas. El que ha recibido más atención es Clang, un compilador más nuevo que admite C, C++ y Objective-C. Principalmente respaldado por Apple, Clang 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 . La compatibilidad con 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 del Glasgow Haskell Compiler (GHC) utiliza LLVM y logra una aceleración del 30% del código compilado en relación con el código nativo que se compila a través de GHC o generación de código C seguida de la compilación, faltando solo una de las muchas técnicas de optimización implementadas por el GHC. [40]
Muchos otros componentes se encuentran en varias 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 una Nuevo asignador de registros de coloración de gráficos . [ cita necesaria ]
El núcleo de LLVM es la representación intermedia (IR), un lenguaje de programación de bajo nivel similar al ensamblador. IR es un conjunto de instrucciones de computadora con 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 mediante call
instrucciones 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 ensamblador legible por humanos, [41] un formato en memoria formato adecuado para interfaces y un formato de código de bits denso para serialización. Un simple "¡Hola mundo!" programa en formato IR:
@.str = constante interna [ 14 x i8 ] c "Hola mundo\0A\00" declarar i32 @printf ( ptr , ...) define 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 ) sustantivo ret i32 0 }
Las diferentes convenciones utilizadas y las características proporcionadas por diferentes objetivos significan que LLVM no puede realmente producir un IR independiente del objetivo y reorientarlo 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 el PNaCl . [43]
El proyecto LLVM también introduce otro tipo de representación intermedia llamada MLIR [44] que ayuda a construir una infraestructura de compilador reutilizable y extensible mediante el empleo de una arquitectura de complemento llamada 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 denominado NVPTX en la documentación de LLVM), PowerPC , AMD TeraScale , [46] la mayoría de las GPU AMD recientes (también denominadas AMDGPU en la documentación de LLVM), [47] SPARC , z/Architecture (también denominada 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 admitía otros backends, total o parcialmente, incluidos C backend, Cell SPU , mblaze (MicroBlaze) , [49] AMD R600, DEC/Compaq Alpha ( Alpha AXP ) [50] y Nios2 , [51] pero ese hardware está en su mayor parte obsoleto y los desarrolladores de LLVM decidieron que los costos de soporte y mantenimiento ya no estaban justificados. [ cita necesaria ]
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 normalmente admiten principalmente código fuente 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 LLVM para traducir instrucciones de máquina entre formas textuales y código de máquina. Anteriormente, LLVM dependía del ensamblador del sistema, o uno proporcionado por una cadena de herramientas, para traducir el ensamblador a código de máquina. El ensamblador integrado de LLVM MC admite la mayoría de los objetivos LLVM, incluidos IA-32, x86-64, ARM y ARM64. Para algunos objetivos, incluidos los diversos conjuntos de instrucciones MIPS, se puede utilizar el soporte de ensamblaje integrado, pero aún se encuentra en la etapa beta. [ cita necesaria ]
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 integridad. lld es más rápido que ambas versiones de GNU ld . [ cita necesaria ]
A diferencia de los enlazadores GNU, lld tiene soporte integrado para optimización del tiempo de enlace (LTO). Esto permite una generación de código más rápida, ya que evita el uso de un complemento de vinculación, 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 v9.0.0, se le volvió a otorgar la licencia Apache 2.0 con excepciones LLVM. [3]
Esto implementa un conjunto de optimizaciones de la localidad de caché, así como autoparalelismo y vectorización utilizando un modelo poliédrico . [56]
llvm-libc es una biblioteca estándar C independiente de ABI, incompleta y de próxima aparición, diseñada por y para el proyecto LLVM. [57]
Debido a su licencia permisiva, muchos proveedores lanzan sus propios diapasones de LLVM. Esto lo reconoce oficialmente la documentación de LLVM, que sugiere no utilizar números de versión en las comprobaciones de funciones 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 [n] ... compilador adelantado (AOT), basado en LLVM.
'LLVM' ya no es oficialmente un acrónimo. El acrónimo que alguna vez se expandió también fue confuso e inapropiado casi desde el día 1. :) A medida que LLVM creció para abarcar otros subproyectos, se volvió aún menos útil y sin sentido.
El nombre 'LLVM' alguna vez fue un acrónimo, pero ahora es solo una marca para el proyecto general.
Tenga en cuenta que los números de versión de marketing no deben utilizarse para comprobar las características del idioma, ya que diferentes proveedores utilizan diferentes esquemas de numeración.
En su lugar, utilice las macros de comprobación de funciones.
El NVVM IR actual se basa en LLVM 5.0