2010-08-18 18 views
18

No entiendo cómo LLVM JIT se relaciona con la compilación JIT normal y la documentación no es buena.jit LLVM y nativo

Por ejemplo supongamos que uso el extremo frontal clang:

  1. Caso 1: Compilo archivo C al nativo con sonido metálico/llvm. Este flujo que entiendo es como el flujo de gcc: obtengo mi ejecutable x86 y eso se ejecuta.
  2. Caso 2: compilo en algún tipo de LLVM IR que se ejecuta en LLVM JIT. En este caso, el archivo ejecutable contiene el tiempo de ejecución de LLVM para ejecutar el IR en JIT o ¿cómo funciona?

¿Cuál es la diferencia entre estos dos y son correctos? ¿El flujo de LLVM incluye soporte para JIT y no JIT? ¿Cuándo quiero usar JIT? ¿Tiene sentido para un lenguaje como C?

Respuesta

30

Tienes que entender que LLVM es una biblioteca que te ayuda a compilar compiladores. Clang es simplemente una interfaz para esta biblioteca.

Clang traduce el código C/C++ a LLVM IR y lo entrega a LLVM, que lo compila en código nativo.

LLVM también puede generar código nativo directamente en la memoria, que luego se puede llamar como una función normal. Por lo tanto, los casos 1 y 2. comparten la optimización de LLVM y la generación de código.

Entonces, ¿cómo se usa LLVM como compilador JIT? Usted crea una aplicación que genera algunos LLVM IR (en memoria), luego usa la biblioteca LLVM para generar código nativo (aún en la memoria). LLVM le devuelve un puntero al que puede llamar después. No hay clang involucrado.

Sin embargo, puede utilizar clang para traducir un código C en LLVM IR y cargarlo en su contexto JIT para usar las funciones.

ejemplos del mundo real:

También existe el tutorial Kaleidoscope que muestra cómo implementar un lenguaje sencillo con el compilador JIT.

+0

Así que para usar LLVM como JIT usted tiene que vincular en su aplicación, ¿verdad? ¿Hay aplicaciones que hacen eso? – zaharpopov

2

La mayoría de los compiladores tienen una interfaz, algunos códigos medios/estructuras de algún tipo, y el servidor. Cuando tomas tu programa C y usas clang y compilación de modo tal que terminas con un programa que no es JIT x86 y que puedes ejecutar, aún has pasado de frontend a middle to backend. Lo mismo ocurre con gcc, gcc va de frontend a un elemento central y un back-end. Lo central de Gccs no está muy abierto y se puede usar como LLVM.

Ahora una cosa que es divertida/interesante acerca de llvm, que no se puede hacer con otros, o al menos gcc, es que puedes tomar todos tus módulos de código fuente, compilarlos en llvms bytecode, unirlos en uno grande bytecode file, luego optimice todo, en lugar de optimización por archivo o por función que obtiene con otros compiladores, con llvm puede obtener cualquier nivel de optimización de programa parcial o compilado que desee. luego puede tomar ese bytecode y usar llc para exportarlo al ensamblador de destinos. Normalmente hago incrustado, así que tengo mi propio código de inicio, pero en teoría debería poder tomar ese archivo de ensamblador y compilar gcc y vincularlo y ejecutarlo. gcc myfile.s -o myfile.Imagino que hay una forma de obtener las herramientas de llvm para hacer esto y no tener que usar binutils o gcc, pero no me he tomado el tiempo.

Me gusta llvm porque siempre es un compilador cruzado, a diferencia de gcc no tienes que compilar uno nuevo para cada objetivo y lidiar con los matices para cada objetivo. No sé si tengo algún uso para JIT. Lo que digo es que lo uso como compilador cruzado y como compilador nativo.

Así que su primer caso es el frente, el medio, el final y el proceso está oculto para usted, comienza con la fuente y obtiene un binario, hecho. El segundo caso es si entiendo bien el frente y el medio y me detengo con un archivo que representa el medio. Luego, de medio a extremo (el procesador de destino específico) puede suceder justo a tiempo en el tiempo de ejecución. La diferencia en el back-end, la ejecución en tiempo real del lenguaje medio del caso dos, es probablemente diferente del backend del caso uno.

+4

tanto gcc como icc tienen un lto e ipo que "optimiza todo", por lo que no es una característica única de llvm. Además, llvm no es solo un "compilador cruzado", es un compilador que admite muchos objetivos en el binario único. Es un poco mejor que el simple compilador cruzado, es un compilador universal, funciona para cualquier objetivo. – osgx

+0

Me gusta el término "compilador universal". gracias por la actualización, no sabía que podía hacer que gcc hiciera eso, algo con lo que jugar algún día. –

22

En primer lugar, se obtiene LLVM código de bytes (LLVM IR):

clang -emit-llvm -S -o test.bc test.c 

En segundo lugar, se utiliza LLVM JIT:

lli test.bc 

que se ejecuta el programa.

Entonces, si desea obtener nativa, se utiliza LLVM backend:

llc test.bc 

Desde la salida de montaje:

as test.S 
5

estoy tomando los pasos necesarios para compilar y ejecutar el JIT'ed código de un mensaje de correo en la comunidad LLVM.

[LLVMdev] MCJIT and Kaleidoscope Tutorial

Archivo de cabecera:

// foo.h 
extern void foo(void); 

y la función de un simple foo() Función:

//foo.c 
#include <stdio.h> 
void foo(void) { 
    puts("Hello, I'm a shared library"); 
} 

Y la función principal:

//main.c 
#include <stdio.h> 
#include "foo.h" 
int main(void) { 
    puts("This is a shared library test..."); 
    foo(); 
    return 0; 
} 

La construcción de la biblioteca utilizando foo.c compartida:

gcc foo.c -shared -o libfoo.so -fPIC 

Generar el código binario LLVM para los principales.archivo c:

clang -Wall -c -emit-llvm -O3 main.c -o main.bc 

y ejecutar el código binario LLVM través JIT (y MCJIT) para obtener la salida deseada:

lli -load=./libfoo.so main.bc 
lli -use-mcjit -load=./libfoo.so main.bc 

También puede canalizar la salida de sonido metálico en lli:

clang -Wall -c -emit-llvm -O3 main.c -o - | lli -load=./libfoo.so 

Salida

This is a shared library test... 
Hello, I'm a shared library 

Fuente obt ained de

Shared libraries with GCC on Linux

Cuestiones relacionadas