关于优化:使用LLVM JIT编译lua包装的C函数?

Compile lua-wrapped C functions using LLVM JIT?

我已经将一些C函数编译为LLVM字节码。
现在,我想使Lua脚本引擎可以访问这些函数,然后将Lua脚本编译为本机代码。

我已经找到了使用llvm编译lua脚本的llvm-lua项目。
我现在想知道是否可以对从lua脚本调用的C函数执行jit编译和优化。

例如,我有以下两个C函数:

1
2
3
4
5
6
7
8
void func1() {
  for(int i = 1; i < 5; ++i)
    printf("hello from func1");
}
void func2() {
  for(int i = 1; i < 5; ++i)
    printf("hello from func2");
}

然后将它们暴露给Lua脚本引擎并运行如下的lua脚本:

1
2
func1()
func2()

然后我希望llvm-lua编译器对其进行优化,然后将其编译为与

1
2
3
4
for(int i = 1; i < 5; ++i) {
  printf("hello from func1");
  printf("hello from func2");
}

而不是

1
2
3
4
for(int i = 1; i < 5; ++i)
  printf("hello from func1");
for(int i = 1; i < 5; ++i)
  printf("hello from func2");

是否有可能实施?

干杯,

曼努埃尔


对于任何种类的复杂程序转换(例如您要在此处实现的转换),最好删除尽可能多的中间步骤,以增加复杂性。首先证明它适用于最简单的情况,然后逐步增加复杂性。对于您的特定问题,这可以转换为:尝试使所需的优化发生在纯C代码上,所有代码都在同一文件中,然后在纯C代码上不同文件中,等等。在较简单的情况下,那么就不太可能使它以所有其他复杂性为原始目标工作(并且通过逐步进行操作,您还将对遇到任何问题的可能原因有更好的了解) 。

如果您遵循上述建议,我非常有信心(尽管我没有尝试过),LLVM优化器不会完成您想要的优化,即使在最简单的情况下,将所有内容都放在一个C文件中并使用全面优化。原因是您期望优化程序更改代码的语义,因为不能保证两个连续的for循环具有与执行两个主体的单个for循环相同的副作用(可观察到的变化)按顺序进行(您提供的代码就是一个很好的例子)。为了使优化安全,编译器将必须能够保证(证明)有关从循环体执行的所有代码的副作用的各种属性。尽管不是不可能,但是在一般情况下,使用诸如C之类的不受控制的副作用的语言来进行操作极其困难,并且在大多数情况下,如果您跨越任何库边界(如您可能在此处所做的操作)都是不可行的,因为实际上,您没有一个统一的优化步骤(至少在理论上)可以考虑所有必要的代码。如果您真的想更深入地研究LLVM及其优化器框架,建议您先阅读这篇出色的文章,概述LLVM的动机和设计,然后找出优化器必须能够在单个代码中查看的代码。使其成为可能的步骤。

我建议您考虑一下让Lua编译为LLVM位代码并与C的LLVM位代码一起进行优化的动机。我敢肯定有正当理由,但是除非您绝对确信这是只有实现您目标的方法,我个人才会尝试其他方法。

可以说,您的主要动机是表现。正如安德鲁·Y(Andrew Y)已经提到的那样,我建议您对luajit有所了解。它使纯正的(体面编写的)Lua的性能接近于C,并且比标准Lua好很多倍,并且还包括一个外来功能接口(FFI),这可能会对您的问题有所帮助。从FFI页面:

The FFI library allows calling external C functions and using C data structures from pure Lua code.

The FFI library largely obviates the need to write tedious manual Lua/C bindings in C. No need to learn a separate binding language — it parses plain C declarations! These can be cut-n-pasted from C header files or reference manuals. It's up to the task of binding large libraries without the need for dealing with fragile binding generators.

The FFI library is tightly integrated into LuaJIT (it's not available as a separate module). The code generated by the JIT-compiler for accesses to C data structures from Lua code is on par with the code a C compiler would generate. Calls to C functions can be inlined in JIT-compiled code, unlike calls to functions bound via the classic Lua/C API.