我通过实现自己的玩具语言来学习LLVM,现在我遇到了一个问题,当函数接受多个参数时,我无法调用生成的函数。以下是我迄今为止遇到的最简单的复制示例(对于带有两个参数并返回第二个参数的值的函数,未经优化的IR):
define i32 @Test_twoArg(i32 %a, i32 %b) {
entry:
%b2 = alloca i32
%a1 = alloca i32
%returnValue = alloca i32
store i32 %a, i32* %a1
store i32 %b, i32* %b2
%b3 = load i32* %b2, !dbg !8
store i32 %b3, i32* %returnValue, !dbg !8
br label %exit, !dbg !8
exit: ; preds = %entry
%returnValue4 = load i32* %returnValue, !dbg !9
ret i32 %returnValue4, !dbg !9
}
我的google-test代码如下所示,其中dump函数生成上面的输出:
TEST_F(BinaryOperatorTest, TwoArg) {
compileFunction("int twoArg(int a, int b) { return b; }");
ASSERT_NE((llvm::Module *)NULL, m_module);
llvm::Function *llvmFunction = m_module->getFunction("Test_twoArg");
ASSERT_NE((llvm::Function *)NULL, llvmFunction);
llvmFunction->dump();
std::vector<llvm::GenericValue> arguments(2);
arguments[0].IntVal = llvm::APInt(32, 11);
arguments[1].IntVal = llvm::APInt(32, 13);
llvm::GenericValue res
= m_executionEngine->runFunction(llvmFunction, arguments);
EXPECT_EQ(13, res.IntVal);
}
并且失败了:
binaryoperator_test.cpp:129: Failure
Value of: res.IntVal
Actual: 16-byte object <20-00 00-00 8B-7F 00-00 20-00 00-00 00-00 00-00>
Expected: 13
如果我将测试修改为只接受一个参数作为输入并返回该参数,那么它是有效的。我已经使用lldb检查生成的代码,它看起来有效(但不是最佳):
(lldb) disassemble
0x7ffff7ff4000 <Test_twoArg>: movl %edi, -0x8(%rsp)
0x7ffff7ff4004 <Test_twoArg+4>: movl %esi, -0x4(%rsp)
-> 0x7ffff7ff4008 <Test_twoArg+8>: movl %esi, -0xc(%rsp)
0x7ffff7ff400c <Test_twoArg+12>: movl -0xc(%rsp), %eax
0x7ffff7ff4010 <Test_twoArg+16>: retq
但寄存器值错误(%rsi
和%rdi
应包含11和13):
(lldb) register read
General Purpose Registers:
rax = 0x0000000000a48fef unittests`llvm::MCJIT::runFunction(llvm::Function*, std::vector<llvm::GenericValue, std::allocator<llvm::GenericValue> > const&) + 399
rbx = 0x00007fffffffdb70
rcx = 0x0000000000000000
rdx = 0xffffffffffc3469f
rdi = 0x0000000001229328
rsi = 0x0000000000000020
rbp = 0x0000000000000020
rsp = 0x00007fffffffda38
r8 = 0x0000000000000000
r9 = 0x0000000000000003
r10 = 0x0000000000000001
r11 = 0x0000000000000088
r12 = 0x00007ffff7ff4000 JIT(0x12526d0)`Test_twoArg at unittest.dw:1
r13 = 0x0000000001229328
r14 = 0x0000000001249690
r15 = 0x00007fffffffdb50
rip = 0x00007ffff7ff4008 JIT(0x12526d0)`Test_twoArg + 8 at unittest.dw:1
rflags = 0x0000000000000246
cs = 0x0000000000000033
fs = 0x0000000000000000
gs = 0x0000000000000000
ss = 0x000000000000002b
ds = 0x0000000000000000
es = 0x0000000000000000
所以看起来我以错误的方式调用runFunction但是我无法弄清楚这是一个LLVM错误怎么样?在Ubuntu上运行LLVM-3.6,x86-64。
更新 通过提取函数指针,我能够正确调用函数,所以这看起来更像是runFunction中的错误:
int (*function)(int, int) = (int (*)(int, int))m_executionEngine->getPointerToFunction(llvmFunction);
int resi = function(11, 13);
EXPECT_EQ(13, resi); // works
答案 0 :(得分:0)
在使用MCJIT时调用runFunction确实存在问题,通过切换到解释器作为执行引擎,一切都按预期工作。可以看到问题here:其中只处理了返回类型和参数类型的某些组合。由于LLVM是在NDEBUG中编译的,因此最后的llvm_unreachable调用是removed and replaced by a hint that the code can't be reached(这应该以更好的方式处理,因为这可能是我可以在生成的函数中放置断点的原因)。