duanqinjiao5244
2016-04-26 16:02
浏览 94
已采纳

JITed LLVM代码如何回调Go函数?

I'm writing code to generate LLVM bytecode from a custom VM bytecode using the LLVM Go bindings; the code is then JITed and executed in-process.

The custom VM bytecode has several operations that can't be implemented directly in LLVM, because they require changing external state; the functionality for these opcodes is implemented as Go functions.

There are excellent guides on getting started with generating LLVM bytecode from Go, but none address the issue of callbacks or exported functions. Is it possible to generate LLVM instructions to call back into the Go functions? If so, how?

I've tried the way described below by @arrowd, and it doesn't appear to work. Source code, adapted from Felix Angell's blog post:

package main

import (
    "C"
    "fmt"
    "llvm.org/llvm/final/bindings/go/llvm"
)

// export AddInts
func AddInts(arg1, arg2 int) int {
    return arg1 + arg2;
}

func main() {
    // setup our builder and module
    builder := llvm.NewBuilder()
    mod := llvm.NewModule("my_module")

    // create our function prologue
    main := llvm.FunctionType(llvm.Int32Type(), []llvm.Type{}, false)
    llvm.AddFunction(mod, "main", main)
    block := llvm.AddBasicBlock(mod.NamedFunction("main"), "entry")
    builder.SetInsertPoint(block, block.FirstInstruction())

    // int a = 32
    a := builder.CreateAlloca(llvm.Int32Type(), "a")
    builder.CreateStore(llvm.ConstInt(llvm.Int32Type(), 32, false), a)

    // int b = 16
    b := builder.CreateAlloca(llvm.Int32Type(), "b")
    builder.CreateStore(llvm.ConstInt(llvm.Int32Type(), 16, false), b)

    // return a + b
    bVal := builder.CreateLoad(b, "b_val")
    aVal := builder.CreateLoad(a, "a_val")
    addIntsType := llvm.FunctionType(llvm.Int32Type(), []llvm.Type{llvm.Int32Type(), llvm.Int32Type()}, false)
    addInts := llvm.AddFunction(mod, "AddInts", addIntsType)
    call := builder.CreateCall(addInts, []llvm.Value{aVal, bVal}, "AddInts")
    builder.CreateRet(call)

    // verify it's all good
    if ok := llvm.VerifyModule(mod, llvm.ReturnStatusAction); ok != nil {
        fmt.Println(ok.Error())
    }
    mod.Dump()

    // create our exe engine
    engine, err := llvm.NewExecutionEngine(mod)
    if err != nil {
        fmt.Println(err.Error())
    }

    // run the function!
    funcResult := engine.RunFunction(mod.NamedFunction("main"), []llvm.GenericValue{})
    fmt.Printf("%d
", funcResult.Int(false))
}

Returns:

; ModuleID = 'my_module'

define i32 @main() {
entry:
  %a = alloca i32
  store i32 32, i32* %a
  %b = alloca i32
  store i32 16, i32* %b
  %b_val = load i32* %b
  %a_val = load i32* %a
  %AddInts = call i32 @AddInts(i32 %a_val, i32 %b_val)
  ret i32 %AddInts
}

declare i32 @AddInts(i32, i32)
LLVM ERROR: Tried to execute an unknown external function: AddInts
exit status 1

2条回答 默认 最新

相关推荐 更多相似问题