21

我不明白 LLVM JIT 与正常的无 JIT 编译有何关系,而且文档也不好。

例如假设我使用clang前端:

  1. 案例 1:我使用 clang/llvm 将 C 文件编译为本机。我理解的这个流程就像 gcc 流程——我得到了我的 x86 可执行文件并运行。
  2. 案例 2:我编译成某种在 LLVM JIT 上运行的 LLVM IR。在这种情况下,可执行文件包含 LLVM 运行时以在 JIT 上执行 IR,或者它是如何工作的?

这两者有什么区别,它们是否正确?LLVM 流是否包括对 JIT 和非 JIT 的支持?我什么时候想使用 JIT - 对于像 C 这样的语言,它是否有意义?

4

4 回答 4

34

您必须了解 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 编译器实现一种简单的语言。

于 2010-08-18T05:41:36.617 回答
27

首先,你得到 LLVM 字节码(LLVM IR):

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

其次,您使用 LLVM JIT:

lli test.bc

那运行程序。

然后,如果你想获得原生,你可以使用 LLVM 后端:

llc test.bc

从汇编输出:

as test.S
于 2010-09-19T00:50:12.103 回答
7

我正在采取步骤从 LLVM 社区的邮件消息中编译和运行 JIT 代码。

[LLVMdev] MCJIT 和万花筒教程

头文件:

// 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 位码:

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

并通过 jit(和 MCJIT)运行 LLVM 位码以获得所需的输出:

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

来源获得自

在 Linux 上与 GCC 共享库

于 2013-08-02T16:36:52.280 回答
2

大多数编译器都有前端、某种中间代码/结构和后端。当您使用 C 程序并使用 clang 并进行编译以得到一个可以运行的非 JIT x86 程序时,您仍然从前端到中间再到后端。gcc 也是如此,gcc 从前端到中间件和后端。Gccs 中间的东西不像 LLVM 那样开放和可用。

现在,关于 llvm 的一件有趣/有趣的事情是,你不能与其他人一起做,或者至少是 gcc,你可以获取所有源代码模块,将它们编译为 llvms 字节码,将它们合并到一个大字节码文件中,然后优化整个事情,而不是使用其他编译器获得的每个文件或每个函数优化,使用 llvm 您可以获得任何级别的部分以编译您喜欢的程序优化。然后您可以获取该字节码并使用 llc 将其导出到目标汇编程序。我通常是嵌入式的,所以我有我自己的启动代码,但理论上你应该能够获取该汇编文件并使用 gcc 编译并链接它并运行它。gcc myfile.s -o 我的文件。我想有一种方法可以让 llvm 工具做到这一点,而不必使用 binutils 或 gcc,但我没有花时间。

我喜欢 llvm 因为它总是一个交叉编译器,不像 gcc 你不必为每个目标编译一个新的并处理每个目标的细微差别。我不知道我对 JIT 有什么用就是我所说的我将它用作交叉编译器和本机编译器。

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

于 2010-08-20T00:44:00.337 回答