LLVM的ExecutionEngine :: runFunction将错误的参数传递给函数。为什么?

时间:2015-08-04 19:32:37

标签: c++ llvm

我通过实现自己的玩具语言来学习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

1 个答案:

答案 0 :(得分:0)

在使用MCJIT时调用runFunction确实存在问题,通过切换到解释器作为执行引擎,一切都按预期工作。可以看到问题here:其中只处理了返回类型和参数类型的某些组合。由于LLVM是在NDEBUG中编译的,因此最后的llvm_unreachable调用是removed and replaced by a hint that the code can't be reached(这应该以更好的方式处理,因为这可能是我可以在生成的函数中放置断点的原因)。