LLVM jit和native

时间:2010-08-18 05:32:32

标签: clang llvm jit

我不明白LLVM JIT如何与正常的无JIT编译相关,文档也不好。

例如,假设我使用clang前端:

  1. 案例1:我使用clang / llvm将C文件编译为native。我理解的这个流程就像gcc流程 - 我得到了我的x86可执行文件并运行。
  2. 案例2:我编译成在LLVM JIT上运行的某种LLVM IR。在这种情况下,可执行文件包含LLVM运行时以在JIT上执行IR,或者它是如何工作的?
  3. 这两者之间的区别是什么? LLVM流程是否包括对JIT和非JIT的支持?我什么时候想使用JIT?对于像C这样的语言来说它是否有意义?

4 个答案:

答案 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

来自

的来源

Shared libraries with GCC on Linux

答案 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的任何用处都是我所说的我用它作为交叉编译器和本机编译器。

所以你的第一个案例就是前面,中间,结尾,你从源头开始并且得到一个二进制文件就完成了对你隐藏的过程。第二种情况是,如果我理解正面和中间,并停止一些代表中间的文件。然后中间到结束(特定目标处理器)可以在运行时及时发生。后端的差异,案例二的中间语言的实时执行可能与案例一的后端不同。