Я играю с LLVM 3.7
и хотел использовать новые возможности ORC. Но я занимаюсь этим уже несколько часов и до сих пор не понимаю, для чего нужен каждый слой, когда их использовать, как их составлять или, по крайней мере, минимальный набор вещей, которые мне нужны.
Прошел Kaleidoscope
учебник, но он не объясняет составные части, просто говорит, поместите это здесь и это здесь (плюс синтаксический анализ и т. д. отвлекает от основных битов LLVM). Хотя это здорово для начала, остается много пробелов. В LLVM есть много документов по разным вещам, но их так много, что это на самом деле граничит с ошеломлением. Такие вещи, как http://llvm.org/releases/3.7.0/docs/ProgrammersManual.html, но я не могу найти ничего, что объясняло бы, как все части сочетаются друг с другом. Еще более запутанным кажется наличие нескольких API для выполнения одной и той же задачи, учитывая MCJIT
и более новый ORC
API. Я видел пост Лэнга Хеймса, в котором объяснялось довольно много вещей. изменились после патча, который он разместил по этой ссылке.
Итак, для конкретного вопроса, как все эти слои сочетаются друг с другом? Когда я ранее использовал LLVM, я мог довольно легко ссылаться на функции C, используя "Как использовать JIT" в качестве основы, я попытался связать внешнюю функцию extern "C" double doIt
, но в итоге получил LLVM ERROR: Tried to execute an unknown external function: doIt
.
Посмотрите на этот пример ORC кажется, мне нужно настроить, где он ищет символы. Но TBH, пока я все еще качаюсь в этом, это в основном догадки. Вот что я получил:
#include "llvm/ADT/STLExtras.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/ExecutionEngine/Interpreter.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
#include "std.hpp"
using namespace llvm;
int main() {
InitializeNativeTarget();
LLVMContext Context;
// Create some module to put our function into it.
std::unique_ptr<Module> Owner = make_unique<Module>("test", Context);
Module *M = Owner.get();
// Create the add1 function entry and insert this entry into module M. The
// function will have a return type of "int" and take an argument of "int".
// The '0' terminates the list of argument types.
Function *Add1F = cast<Function>(M->getOrInsertFunction("add1", Type::getInt32Ty(Context), Type::getInt32Ty(Context), (Type *) 0));
// Add a basic block to the function. As before, it automatically inserts
// because of the last argument.
BasicBlock *BB = BasicBlock::Create(Context, "EntryBlock", Add1F);
// Create a basic block builder with default parameters. The builder will
// automatically append instructions to the basic block `BB'.
IRBuilder<> builder(BB);
// Get pointers to the constant `1'.
Value *One = builder.getInt32(1);
// Get pointers to the integer argument of the add1 function...
assert(Add1F->arg_begin() != Add1F->arg_end()); // Make sure there's an arg
Argument *ArgX = Add1F->arg_begin(); // Get the arg
ArgX->setName("AnArg"); // Give it a nice symbolic name for fun.
// Create the add instruction, inserting it into the end of BB.
Value *Add = builder.CreateAdd(One, ArgX);
// Create the return instruction and add it to the basic block
builder.CreateRet(Add);
// Now, function add1 is ready.
// Now we're going to create function `foo', which returns an int and takes no
// arguments.
Function *FooF = cast<Function>(M->getOrInsertFunction("foo", Type::getInt32Ty(Context), (Type *) 0));
// Add a basic block to the FooF function.
BB = BasicBlock::Create(Context, "EntryBlock", FooF);
// Tell the basic block builder to attach itself to the new basic block
builder.SetInsertPoint(BB);
// Get pointer to the constant `10'.
Value *Ten = builder.getInt32(10);
// Pass Ten to the call to Add1F
CallInst *Add1CallRes = builder.CreateCall(Add1F, Ten);
Add1CallRes->setTailCall(true);
// Create the return instruction and add it to the basic block.
builder.CreateRet(Add1CallRes);
std::vector<Type *> args;
args.push_back(Type::getDoubleTy(getGlobalContext()));
FunctionType *FT = FunctionType::get(Type::getDoubleTy(getGlobalContext()), args, false);
Function *F = Function::Create(FT, Function::ExternalLinkage, "doIt", Owner.get());
// Now we create the JIT.
ExecutionEngine *EE = EngineBuilder(std::move(Owner)).create();
outs() << "We just constructed this LLVM module:\n\n" << *M;
outs() << "\n\nRunning foo: ";
outs().flush();
// Call the `foo' function with no arguments:
std::vector<GenericValue> noargs;
GenericValue gv = EE->runFunction(FooF, noargs);
auto ax = EE->runFunction(F, noargs);
// Import result of execution:
outs() << "Result: " << gv.IntVal << "\n";
outs() << "Result 2: " << ax.IntVal << "\n";
delete EE;
llvm_shutdown();
return 0;
}
doIt
объявлено в std.hpp
.