LLVM

Compartir Imprimir Citar

LLVM es un conjunto de tecnologías de compilador y cadena de herramientas que se puede utilizar para desarrollar un front-end para cualquier lenguaje de programación y un back-end para cualquier arquitectura de conjunto de instrucciones. LLVM está diseñado en torno a una representación intermedia (IR) independiente del idioma que sirve como un lenguaje ensamblador portátil de alto nivel que se puede optimizar con una variedad de transformaciones en múltiples pasos.

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". Implementado originalmente para C y C++, el diseño independiente del lenguaje de LLVM ha generado desde entonces una amplia variedad de interfaces: lenguajes con compiladores que usan LLVM (o que no usan directamente LLVM pero pueden generar programas compilados como LLVM IR) incluyen ActionScript, Ada, C#, Common Lisp, PicoLisp, Crystal, CUDA, D, Delphi, Dylan, Forth, Fortran, Free Basic, Free Pascal, Graphical G, Halide, Haskell, Java bytecode, Julia, Kotlin, Lua, Objective-C, OpenCL, SQL de PostgreSQL y PLpgSQL, Ruby, Rust, Scala, Swift, XC, Xojo y Zig.

Historia

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, una licencia permisiva de software libre. 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. LLVM ha sido una parte integral de las herramientas de desarrollo Xcode de Apple para macOS e iOS desde Xcode 4.

En 2006, Lattner comenzó a trabajar en un nuevo proyecto llamado Clang. La combinación de Clang front-end y LLVM back-end se llama Clang/LLVM o simplemente Clang.

El nombre LLVM fue originalmente una sigla de Low Level Virtual Machine. Sin embargo, el proyecto LLVM se convirtió en un proyecto general que tiene poca relación con lo que la mayoría de los desarrolladores actuales consideran una máquina virtual. Como tal, el inicialismo era "confuso" e "inapropiado", y a partir de 2011 LLVM "oficialmente ya no es un acrónimo". Desde 2011, LLVM es una marca que se aplica al proyecto general de LLVM, que 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), etc. LLVM es administrado por la Fundación LLVM. Su presidente es el ingeniero compilador Tanya Lattner.

"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.

El proyecto estaba originalmente disponible bajo la licencia UIUC. Desde el lanzamiento de v9.0.0 en 2019, LLVM está en proceso de volver a obtener la licencia de Apache License 2.0 con excepciones de LLVM. Cuando se complete la renovación de la licencia, el proyecto estará disponible solo con la nueva licencia. Hasta entonces, las nuevas contribuciones tienen doble licencia y el proyecto permanece disponible bajo la licencia UIUC "heredada". A partir del 23 de marzo de 2022, había 650 personas cuyas contribuciones no han sido relicenciadas.

Características

LLVM puede proporcionar las capas intermedias de un sistema compilador completo, tomando el código de representación intermedia (IR) de un compilador y emitiendo un IR optimizado. Este nuevo IR se puede convertir y vincular 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 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 generar código de máquina reubicable en tiempo de compilación o tiempo 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.Cada instrucción está en forma de asignación única estática (SSA), lo que significa que cada variable (llamada registro escrito) 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 de forma estática, ya que está bajo el sistema GCC tradicional, o se deja para la compilación tardía desde el IR al código de la máquina a través de 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 coma 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 ramificaciones 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 proporcionar soporte para las funciones de hardware que faltan.

El código de gráficos dentro de la pila de OpenGL se puede dejar en representación intermedia y luego compilar cuando se ejecuta en la máquina de destino. En los sistemas con unidades de procesamiento de gráficos (GPU) de gama alta, 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 que 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 de GNOME para permitir que se ejecute sin un controlador de hardware 3D adecuado cargado.

Para el rendimiento en tiempo de ejecución de los programas compilados, GCC superó anteriormente a LLVM en un 10 % en promedio en 2011. Los resultados más recientes en 2013 indican que LLVM ahora se ha puesto al día con GCC en esta área y ahora está compilando archivos binarios de aproximadamente el mismo rendimiento.

Componentes

LLVM se ha convertido en un proyecto paraguas que contiene múltiples componentes.

Frente termina

LLVM se escribió originalmente para ser un reemplazo del generador de código existente en la pila de GCC, y muchas de las interfaces de GCC se modificaron para que funcionen con él, lo que resultó en la suite LLVM-GCC, ahora desaparecida. Las modificaciones generalmente involucran un paso IR de GIMPLE a LLVM para que los optimizadores y generadores de códigos LLVM puedan usarse en lugar del sistema GIMPLE de GCC. Apple fue un usuario importante de LLVM-GCC a través de Xcode 4.x (2013). Este uso de la interfaz de GCC se consideró principalmente como una medida temporal, pero con la llegada de Clang y las ventajas de LLVM y el código base moderno y modular de Clang (así como la velocidad de compilación), es en su mayoría obsoleto.

Actualmente, LLVM 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 una variedad de lenguajes. El que ha recibido más atención es Clang, un nuevo compilador compatible con 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 las directivas OpenMP se ha incluido en Clang desde la versión 3.8.

El compilador Utrecht Haskell puede generar código para LLVM. Aunque el generador se encuentra en las primeras etapas de desarrollo, en muchos casos ha sido más eficiente que el generador de código C. Hay un backend de Glasgow Haskell Compiler (GHC) que usa LLVM que logra un 30% de aceleración del código compilado en relación con la compilación de código nativo a través de GHC o generación de código C seguida de compilación, faltando solo una de las muchas técnicas de optimización implementadas por el GHC.

Muchos otros componentes se encuentran en varias etapas de desarrollo, incluidos, entre otros, el compilador Rust, un front-end de código de bytes de Java, un front-end de lenguaje intermedio común (CIL), la implementación MacRuby de Ruby 1.9, varios front-end para Standard ML, y un nuevo asignador de registros de coloreado de gráficos.

Representación intermedia

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 cálculo de conjunto de instrucciones reducido (RISC) fuertemente tipado que abstrae la mayoría de los detalles del objetivo. Por ejemplo, la convención de llamada se abstrae mediante instrucciones call y ret con argumentos explícitos. Además, en lugar de un conjunto fijo de registros, IR usa un conjunto infinito de registros temporales de la forma %0, %1, etc. LLVM admite tres formas equivalentes de IR: un formato de ensamblaje legible por humanos, un formato en memoria adecuado para interfaces y un formato de código de bits denso para la serialización. Un simple "¡Hola, mundo!" programa en formato IR:

@.str  =  constante interna  [ 14 x i8 ] c "hola, mundoA0"    

declarar  i32 @printf (i8 *,...) 

define  i32 @main (i32 % argc, i8 ** %argv) nounwind { entrada: %tmp1 = getelementptr [ 14 x i8 ], [ 14 x i8 ]* @.str, i32 0, i32 0 %tmp2 = call i32 (i8 *,...) @printf (i8 * %tmp1 ) sustantivo ret i32 0 }     

                 
              
      

Las diferentes convenciones utilizadas y las funciones proporcionadas por diferentes objetivos significan que LLVM no puede producir realmente 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 de LLVM IR totalmente independiente del objetivo destinada a la distribución en línea. Un ejemplo más práctico es PNaCl.

El proyecto LLVM también presenta otro tipo de representación intermedia llamada MLIR que ayuda a construir una infraestructura de compilador extensible y reutilizable mediante el empleo de una arquitectura de complemento denominada Dialect. 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.

Extremos traseros

En la versión 13, LLVM admite muchos conjuntos de instrucciones, incluidos IA-32, x86-64, ARM, Qualcomm Hexagon, MIPS, Nvidia Parallel Thread Execution (PTX; llamado NVPTX en la documentación de LLVM), PowerPC, AMD TeraScale, la mayoría de las GPU AMD recientes (llamado AMDGPU en la documentación de LLVM), SPARC, z/Architecture (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. 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), AMD R600, DEC/Compaq Alpha (Alpha AXP) y Nios2, pero ese hardware es en su mayoría obsoleto y los desarrolladores de LLVM decidió que los costos de soporte y mantenimiento ya no estaban justificados.

LLVM también es compatible con 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 suelen admitir 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 formas 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 ensamblado a código de máquina. El ensamblador integrado de LLVM MC es compatible con 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 usar el soporte de ensamblaje integrado, pero aún se encuentra en la etapa beta.

Enlazador

El subproyecto lld es un intento de desarrollar un enlazador integrado e independiente de la plataforma para LLVM. lld tiene como objetivo eliminar la dependencia de un enlazador de terceros. A partir de mayo de 2017, lld es compatible con ELF, PE/COFF, Mach-O y WebAssembly en orden descendente de integridad. lld es más rápido que las dos versiones de GNU ld.

A diferencia de los enlazadores GNU, lld tiene soporte integrado para la optimización del tiempo de enlace. Esto permite una generación de código más rápida ya que omite el uso de un complemento de enlace, pero por otro lado prohíbe la interoperabilidad con otras versiones de LTO.

Biblioteca estándar de C++

El proyecto LLVM incluye una implementación de la biblioteca estándar de C ++ llamada libc ++, con licencia dual bajo la licencia MIT y la licencia UIUC.

Desde v9.0.0, se volvió a otorgar la licencia de Apache License 2.0 con excepciones LLVM.

Polly

Esto implementa un conjunto de optimizaciones de localidad de caché, así como autoparalelismo y vectorización utilizando un modelo poliédrico.

Depurador

Biblioteca estándar de C

llvm-libc es una biblioteca estándar de C independiente de ABI, próxima e incompleta, diseñada por y para el proyecto LLVM.

Derivados

Debido a su licencia permisiva, muchos proveedores lanzan sus propias horquillas sintonizadas de LLVM. Esto está oficialmente reconocido por la documentación de LLVM, que sugiere no usar números de versión en las comprobaciones de funciones por este motivo. Algunos de los proveedores incluyen: