LLVM與C++程式碼的相互呼叫(全註釋)
阿新 • • 發佈:2019-01-14
一、在C++中呼叫LLVM編寫的IR函式
#include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/Function.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/IRBuilder.h" #include "llvm/ExecutionEngine/JIT.h" #include "llvm/Support/TargetSelect.h" #include "llvm/CodeGen/MachineCodeInfo.h" #include "llvm/Analysis/Verifier.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/IR/DerivedTypes.h" #include <iostream> /* 務必使用llvm-3.3 */ using namespace llvm; using namespace std; int main() { int x = 9; // 獲取LLVM上下文 LLVMContext &context = llvm::getGlobalContext(); //獲取LLVM Module,Module類似於一個完整的.cc檔案 Module *module = new Module("test", context); //獲取一個函式,如果這個函式已經宣告,獲取相應的函式指標,如果沒有,宣告 Function *f = cast<Function>(module->getOrInsertFunction("foo", Type::getInt32Ty(context), Type::getInt32Ty(context), NULL)); //建立一個程式碼塊,這個程式碼塊是之前宣告的函式foo的。程式碼塊就是C++中的 {} BasicBlock *BB = BasicBlock::Create(context, "entryBar", f); //建立LLVM Builder,Builder的作用就是輔助完成IR程式碼,這個builder用於在程式碼塊BB中完成IR IRBuilder<> builder(BB); //下面是foo中的主要邏輯:int ret=x;return ret; Value *ret = builder.getInt32(x); builder.CreateRet(ret); //這行程式碼的作用是引入初始化native,JIT會將IR編譯成當前主機可以執行的二進位制程式碼,而native中包含了當前主機的作業系統資訊 InitializeNativeTarget(); //建立執行JIT引擎,並將IR程式碼放入,也就是放入module(因為IR程式碼都在其中) ExecutionEngine *ee = EngineBuilder(module).setEngineKind(EngineKind::JIT).create(); //從執行引擎中獲取相應的函式指標,JIT即時編譯器後我們之前寫的IR函式可以通過函式指標獲取 void *barAddr = ee->getPointerToFunction(f); //將函式指標進行強轉 typedef int32_t (*FuncType)(int32_t); FuncType barFunc = (FuncType)barAddr; //正式呼叫經由JIT編譯後的IR函式 int64_t n = 9; cout << barFunc(n) << endl; return 0; }
二、在LLVM編寫的IR函式中呼叫C++程式碼
#include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/Function.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/IRBuilder.h" #include "llvm/ExecutionEngine/JIT.h" #include "llvm/Support/TargetSelect.h" #include "llvm/CodeGen/MachineCodeInfo.h" #include "llvm/Analysis/Verifier.h" #include <iostream> using namespace llvm; /* 務必使用llvm-3.3 */ int foo(int x) { return 2 * x; } int value = 10; int main() { LLVMContext &context = llvm::getGlobalContext(); Module *module = new Module("test", context); //在IR程式碼中宣告一個全域性變數 GlobalVariable *v = cast<GlobalVariable>(module->getOrInsertGlobal("value", Type::getInt32Ty(context))); //在IR中宣告一個函式,注意我們並不會在IR中定義foo,我們會將這個IR中宣告的函式對映到C++程式碼中的函式 Function *f = cast<Function>(module->getOrInsertFunction("foo", Type::getInt32Ty(context), Type::getInt32Ty(context), NULL)); //在IR中宣告一個函式bar,我們會用IR定義這個函式 Function *bar = cast<Function>(module->getOrInsertFunction("bar", Type::getInt32Ty(context), NULL)); //建立函式bar的程式碼塊 BasicBlock *entry = BasicBlock::Create(context, "entry", bar); IRBuilder<> builder(entry); //用一個區域性變數獲取全域性變數v的值 Value *v_IR = builder.CreateLoad(v); //呼叫函式foo Value *ret = builder.CreateCall(f, v_IR); //返回值 builder.CreateRet(ret); InitializeNativeTarget(); ExecutionEngine *ee = EngineBuilder(module).setEngineKind(EngineKind::JIT).create(); //將外部的C++程式碼中的全域性變數對映到IR程式碼中,IR程式碼中只有宣告 ee->addGlobalMapping(v, &value); //將外部的C++程式碼中的全域性函式對映到IR程式碼中,IR程式碼中只有宣告 ee->addGlobalMapping(f, (void *)foo); void *barAddr = ee->getPointerToFunction(bar); typedef int (*FuncType)(); FuncType barFunc = (FuncType)barAddr; std::cout << barFunc() << std::endl; return 0; }