我不明白LLVM JIT如何与正常的无JIT编译相关,文档也不好。
例如,假设我使用clang
前端:
这两者之间的区别是什么? LLVM流程是否包括对JIT和非JIT的支持?我什么时候想使用JIT?对于像C这样的语言来说它是否有意义?
答案 0 :(得分:30)
您必须了解LLVM是一个可以帮助您构建编译器的库。 Clang只是这个图书馆的前端。
Clang将C / C ++代码转换为LLVM IR,并将其交给LLVM,后者将其编译为本机代码。
LLVM还能够直接在内存中生成本机代码,然后可以将其称为普通函数。所以情况1.和2.共享LLVM的优化和代码生成。
那么如何将LLVM用作JIT编译器?您构建一个生成一些LLVM IR(在内存中)的应用程序,然后使用LLVM库生成本机代码(仍在内存中)。 LLVM会向您发送指针,然后您可以调用它。没有铿锵声。
但是,您可以使用clang将一些C代码转换为LLVM IR并将其加载到JIT上下文中以使用这些函数。
真实世界的例子:
还有Kaleidoscope教程,展示了如何使用JIT编译器实现一种简单的语言。
答案 1 :(得分:26)
首先,您获得LLVM字节码(LLVM IR):
clang -emit-llvm -S -o test.bc test.c
其次,您使用LLVM JIT:
lli test.bc
运行程序。
然后,如果您希望获得本机,则使用LLVM后端:
llc test.bc
从汇编输出:
as test.S
答案 2 :(得分:6)
我正在采取步骤从LLVM社区的邮件消息中编译和运行JIT代码。
[LLVMdev] MCJIT and Kaleidoscope Tutorial
标题文件:
// foo.h
extern void foo(void);
和一个简单的foo()函数的函数:
//foo.c
#include <stdio.h>
void foo(void) {
puts("Hello, I'm a shared library");
}
主要功能:
//main.c
#include <stdio.h>
#include "foo.h"
int main(void) {
puts("This is a shared library test...");
foo();
return 0;
}
使用foo.c构建共享库:
gcc foo.c -shared -o libfoo.so -fPIC
为main.c文件生成LLVM bitcode:
clang -Wall -c -emit-llvm -O3 main.c -o main.bc
通过jit(和MCJIT)运行LLVM bitcode以获得所需的输出:
lli -load=./libfoo.so main.bc
lli -use-mcjit -load=./libfoo.so main.bc
您也可以将clang输出传递给lli:
clang -Wall -c -emit-llvm -O3 main.c -o - | lli -load=./libfoo.so
输出
This is a shared library test...
Hello, I'm a shared library
来自
的来源答案 3 :(得分:2)
大多数编译器都有一个前端,一些中间代码/某种结构,以及后端。当你使用你的C程序并使用clang和编译这样你最终得到一个你可以运行的非JIT x86程序时,你仍然从前端到中间到后端。同样适用于gcc,gcc从前端到中间和后端。 Gccs中间的东西并不像LLVM那样开放和可用。
现在有一件关于llvm有趣/有趣的事情,你不能与其他人一起做,或者至少是gcc,你可以把你所有的源代码模块,编译成llvms字节码,合并成一个大的字节码文件,然后优化整个事物,而不是每个文件或每个函数优化,你得到其他编译器,与llvm你可以获得任何级别的部分编译程序优化你喜欢。然后你可以使用该字节码并使用llc将其导出到目标汇编程序。我通常做嵌入式,所以我有自己的启动代码,但我理论上你应该能够获取该汇编程序文件并使用gcc编译并链接它并运行它。 gcc myfile.s -o myfile。我想有一种方法可以让llvm工具执行此操作而不必使用binutils或gcc,但我没有花时间。
我喜欢llvm,因为它总是一个交叉编译器,与gcc不同,你不必为每个目标编译一个新的目标并处理每个目标的细微差别。我不知道我对JIT的任何用处都是我所说的我用它作为交叉编译器和本机编译器。
所以你的第一个案例就是前面,中间,结尾,你从源头开始并且得到一个二进制文件就完成了对你隐藏的过程。第二种情况是,如果我理解正面和中间,并停止一些代表中间的文件。然后中间到结束(特定目标处理器)可以在运行时及时发生。后端的差异,案例二的中间语言的实时执行可能与案例一的后端不同。