LLVM es mas bajo nivel que el bitcode de Java o >NET (osea, no existe una maquina virtual que lo interprete).
Este es un ejemplo de LLVM:
http://llvm.org/docs/tutorial/
Si tenemos esta funcion en el front-end:
Código PHP:
def foo(a b) a*a + 2*a*b + b*b;
Esto es el LLVM IR (o lenguaje de bajo nivel de LLVM en formato texto "legible"):
Código PHP:
define double @foo(double %a, double %b) {
entry:
%multmp = fmul double %a, %a
%multmp1 = fmul double 2.000000e+00, %a
%multmp2 = fmul double %multmp1, %b
%addtmp = fadd double %multmp, %multmp2
%multmp3 = fmul double %b, %b
%addtmp4 = fadd double %addtmp, %multmp3
ret double %addtmp4
}
Y de alli LLVM genera un binario nativo. No es full multiplataforma porque LLVM es "compilador como infraestructura" lo que significa que tiene multiples front-ends (lenguajes) y back-ends (compiladores nativos). Por lo tanto, tiene back-end para x86, arm, CUDA (NVidia GPUs), etc.
En otras palabras, LLVM tiene un lenguaje (el "IR") que esta optimizado para que se puedan hacer analisis y optimizaciones antes de generar el assembler.
Esto es porque en compiladores, si quieres que el ejecutable sea mas rapido "Agregale otro pase al compilador"!.
PASCAL original era un compilador en 1 solo paso (por eso volaba). Todo lo hace en un solo "tiron".
La mayoria de los compiladores/interpretes tienen 3/4 pasos:
- Lexing
- Parsing
- Generar ASSEMBLER o BITCODE o Interpretar
Pero para poder hacer optimizaciones, se tiene que agregar otros pasos entre parsing y Generar/Interpretar
- Parsing
- Optimizar: PeepHole
- Optimizar: Constant folding
- Optimizar: ....
- Generar dataflow
- Eliminar variables
- ....
- Generar ASSEMBLER o BITCODE o Interpretar
LLVM esta hecho para poder agregar pasos en toda la cadena del compilador, y se puede decidir si se deja parte del trabajo a LLVM o se toma control casi total del cuento.
----
Ahora, porque LLVM es todo un ecosistema, se pueden integrar herramientas y tecnicas. Por ejemplo, se puede generar un nativo desde un front-end en python, cargar el codigo en memoria, cargar una DLL nativa y hacer el puente. Como un JIT.
---
Si a dia de hoy hay que hacer un compilador nativo, LLVM es 100% la respuesta.