LLVM

LLVM
Tipo de compilador
Desarrollador Vikram Adwe [d] y Chris Lattner [d]
Escrito en C++ [3] , C [4] y lenguaje ensamblador [4]
Sistema operativo multiplataforma
Primera edición 24 de octubre de 2003 [1]
ultima versión
Licencia Licencia abierta de la Universidad de Illinois [d] [5]yLicencia Apache 2.0[6]
Sitio web www.llvm.org
 Archivos multimedia en Wikimedia Commons

LLVM (anteriormente Low Level Virtual Machine [7] ) es un proyecto de infraestructura de software para crear compiladores y utilidades relacionadas . Consiste en un conjunto de compiladores de lenguajes de alto nivel (los llamados "frontends"), un sistema de optimización, interpretación y compilación en código máquina. La infraestructura se basa en un sistema de codificación de instrucciones de máquina independiente de la plataforma similar a RISC (código de bytes LLVM IR ), que es un ensamblador de alto nivel con el que funcionan varias transformaciones.

Escrito en C++, proporciona optimizaciones en las etapas de compilación, enlace y ejecución. Inicialmente, los compiladores para los lenguajes C y C ++ se implementaron en el proyecto utilizando el front-end de Clang , luego aparecieron front-end para muchos lenguajes, incluidos: ActionScript , Ada , C # [8] , Common Lisp , Crystal , CUDA , D , Delphi , Dylan, Fortran , lenguaje de programación gráfico G, Halide , Haskell , Java (código de bytes), JavaScript , Julia , Kotlin , Lua , Objective-C , lenguaje de sombreado OpenGL , Ruby , Rust , Scala , Swift , Xojo .

LLVM puede producir código nativo para una variedad de arquitecturas, incluidas ARM , x86 , x86-64 , PowerPC , MIPS , SPARC , RISC-V y más (incluidas las GPU de Nvidia y AMD ).

Algunos proyectos tienen sus propios compiladores LLVM (por ejemplo, la versión LLVM de GCC), otros utilizan el marco LLVM [9] , como el compilador Glasgow Haskell .

El desarrollo comenzó en 2000 en la Universidad de Illinois . A mediados de la década de 2010, LLVM se había generalizado en la industria: lo usaban, entre otros, Adobe , Apple y Google . En particular, el subsistema OpenGL en Mac OS X 10.5 se basa en LLVM, y el iPhone SDK usa el preprocesador GCC (frontend) con un backend LLVM. Apple y Google son uno de los principales patrocinadores del proyecto, y uno de los principales desarrolladores, Chris Lattner, trabaja en Apple desde hace 11 años (desde 2017 - en Tesla Motors [10] , desde 2020 - en el desarrollo de procesadores y microcontroladores basados ​​en la arquitectura RISC-V SiFive [11] ).

Características

LLVM se basa en una representación de código intermedio ( Representación intermedia, IR ), que se puede transformar durante la compilación, el enlace y la ejecución. A partir de esta representación, se genera código máquina optimizado para una variedad de plataformas, tanto estática como dinámicamente ( compilación JIT ). LLVM 9.0.0 admite la generación de código estático para x86 , x86-64 , ARM , PowerPC , SPARC , MIPS , RISC-V , Qualcomm Hexagon , NVPTX, SystemZ, Xcore. La compilación JIT (generación de código de máquina en tiempo de ejecución) es compatible con arquitecturas x86, x86_64, PowerPC, MIPS, SystemZ y parcialmente ARM [12] .

LLVM está escrito en C++ y ha sido portado a la mayoría de los sistemas tipo Unix y Windows . El sistema tiene una estructura modular, sus módulos individuales pueden integrarse en varios sistemas de software, puede expandirse con algoritmos de transformación adicionales y generadores de código para nuevas plataformas de hardware.

LLVM incluye un contenedor de API para OCaml .

Plataformas

LLVM es compatible con las siguientes plataformas:

Sistema operativo Arquitectura Compilador
linux x86 / AMD64 CCG , Clang
FreeBSD x86 / AMD64 CCG , Clang
OpenBSD x86 / AMD64 CCG , Clang
Mac OS X PowerPC CCG
Mac OS X x86 / AMD64 CCG , Clang
Solaris UltraSPARC CCG
Cygwin / Win32 x86 GCC 3.4.X, Binutils 2.15
MinGW / Win32 x86 GCC 3.4.X, Binutils 2.15

LLVM tiene soporte parcial para las siguientes plataformas:

Sistema operativo Arquitectura Compilador
AIX PowerPC CCG
linux PowerPC CCG
sistema operativo amigo m68k , PowerPC CCG
ventanas x86 MSVC

Tipos de datos

Tipos simples

Enteros de bitness arbitrario un poco de profundidad
  • i1 - valor booleano - 0 o 1
  • i32 - entero de 32 bits
  • i17
  • i256
  • No se admite la generación de código nativo para tipos de bits muy grandes. Pero para la representación intermedia, no hay restricciones.
  • Se considera que los números se representan en complemento a dos. No hay distinción entre enteros con signo y sin signo en el nivel de tipo: donde importa, son manejados por diferentes instrucciones.
Números de punto flotante float , double , tipos específicos de plataforma (por ejemplo, x86_fp80 )
valor vacío vacío

Tipos derivados

Punteros tipo de* i32* - puntero a entero de 32 bits
arreglos [número de elementos x tipo]
  • [10xi32]
  • [8x doble]
estructuras {i32, i32, doble}
Un vector es un tipo especial para simplificar operaciones SIMD .

El vector consta de 2 n valores de un tipo primitivo: entero o coma flotante.

<número de elementos x tipo> < 4 x flotante > - vector XMM
Funciones
  • i32 (i32, i32)
  • flotar ({ flotar, flotar }, { flotar, flotar })

El sistema de tipos admite la superposición/anidamiento, es decir, puede usar matrices multidimensionales, matrices de estructuras, punteros a estructuras y funciones, etc.

Operaciones

La mayoría de las instrucciones en LLVM toman dos argumentos (operando) y devuelven un valor (código de tres direcciones). Los valores se definen mediante un identificador de texto. Los valores locales tienen el prefijo %, y los valores globales tienen el prefijo @. Los valores locales también se denominan registros, y LLVM también se denomina máquina virtual con un número infinito de registros. Ejemplo:

%suma = suma i32 %n, 5 %diff = subdoble %a, %b %z = agregar <4 x float> %v1, %v2 ; suma por elementos %cond = icmp eq %x, %y ; Comparación de enteros. El resultado es de tipo i1. %éxito = llamar a i32 @puts(i8* %str)

El tipo de los operandos siempre se especifica explícitamente y determina sin ambigüedades el tipo del resultado. Los operandos de las instrucciones aritméticas deben ser del mismo tipo, pero las propias instrucciones están "sobrecargadas" para cualquier vector y tipo numérico.

LLVM admite un conjunto completo de operaciones aritméticas, operaciones lógicas bit a bit y operaciones de cambio, así como instrucciones especiales para trabajar con vectores.

LLVM IR está fuertemente tipado, por lo que hay operaciones de conversión que están codificadas explícitamente con instrucciones especiales. Un conjunto de 9 instrucciones cubre todas las conversiones posibles entre diferentes tipos numéricos: entero y coma flotante, con signo y sin signo, diferente longitud de bit, etc. Además, hay instrucciones para convertir entre números enteros y punteros, así como una instrucción universal para el tipo casting bitcast(responsable de la corrección de tales transformaciones recae en el programador).

Memoria

Además de los valores de registro, LLVM también tiene manejo de memoria. Los valores en la memoria son direccionados por punteros escritos . Puede acceder a la memoria usando dos instrucciones: loady store. Por ejemplo:

%x = cargar i32* %x.ptr ; carga el valor de tipo i32 en el puntero %x.ptr %tmp = agregar i32 %x, 5 ; añadir 5 almacenar i32 %tmp, i32* %x.ptr ; y poner de nuevo

La instrucción mallocse traduce en una llamada de la función del sistema del mismo nombre y asigna memoria en el montón , devolviendo un valor: un puntero de cierto tipo. Viene con instrucciones free.

%struct.ptr = malloc { doble, doble } %cadena = malloc i8, i32 %longitud %matriz = malloc [16 x i32] libre i8* %cadena

La instrucción allocaasigna memoria en la pila.

%x.ptr = asignar doble ; %x.ptr es de tipo doble* %matriz = asignación flotante, i32 8 ; ¡%array es de tipo float*, no [8 x float]!

La memoria asignada allocase libera automáticamente cuando la función sale usando las instrucciones reto unwind.

Operaciones con punteros

Para calcular las direcciones de elementos de arreglos, estructuras, etc. con la escritura correcta, se usa la instrucción getelementptr.

%matriz = asignar i32, i32 %tamaño %ptr = getelementptr i32* %matriz, i32 %index ; valor de tipo i32*

getelementptrsolo calcula la dirección, pero no accede a la memoria. La instrucción acepta un número arbitrario de índices y puede desreferenciar estructuras de cualquier anidamiento.

También hay instrucciones extractvaluey insertvalue. Se diferencian en getelementptrque no llevan un puntero a un tipo de dato agregado (matriz o estructura), sino el valor de este tipo en sí. extractvaluedevuelve el valor correspondiente del subelemento, pero insertvaluegenera un nuevo valor del tipo agregado.

%n = valor extraído { i32, [4 x i8*] } %s, 0 %tmp = agregar i32 %n, 1 %s.1 = valor de inserción { i32, [4 x i8*] } %s, i32 %tmp, 0

Notas

  1. Lattner K. ¡La versión LLVM 1.0 finalmente está disponible!
  2. Lanzamiento de LLVM 15.0.4 - 2022.
  3. El proyecto de código abierto llvm en Open Hub: página de idiomas - 2006.
  4. 1 2 El proyecto de código abierto llvm en Open Hub:  página de idiomas
  5. Licencia  _
  6. http://releases.llvm.org/9.0.0/LICENSE.TXT - 2019.
  7. LLVMdev: The name of LLVM Archivado el 3 de noviembre de 2016 en Wayback Machine , Chris Lattner (Apple), 2011-12-21 "'LLVM' oficialmente ya no es un acrónimo. El acrónimo que una vez expandió también era confuso e inapropiado casi desde el primer día”.
  8. LLILC . Consultado el 14 de abril de 2015. Archivado desde el original el 19 de mayo de 2019.
  9. Proyectos construidos con LLVM  . llvm. Consultado el 24 de mayo de 2018. Archivado desde el original el 24 de mayo de 2018.
  10. Bienvenido Chris Lattner | tesla _ Consultado el 11 de enero de 2017. Archivado desde el original el 11 de enero de 2017.
  11. El fundador de LLVM se une a SiFive . Consultado el 28 de enero de 2020. Archivado desde el original el 28 de enero de 2020.
  12. Generador de código independiente de destino de LLVM Archivado el 1 de mayo de 2021 en la sección Matriz de funciones de destino  de Wayback Machine

Literatura

Enlaces