一、常用指令
1.从源码生成.ll
clang main.c -emit-llvm -S -c -o main.ll
2.运行.ll
lli main.ll
3.编译汇编
llc main.ll
4.生成dot,得到可视化的DAG
llc -view-dag-combine1-dags main.ll
5.将源文件分别编译为LLVM二进制代码
clang -emit-llvm -c main.c -o main.bc
6.生成目标文件,通过系统链接器链接多个目标文件,生成可执行文件
llc -filetype=obj main.bc -o main.o
llc -filetype=obj sum.bc -o sum.o
clang main.o sum.o -o sum
7.使用优化器优化 IR/BC 代码,如将Store/Load优化为PHYNode
opt t.bc -o t.opt.bc -O3
llvm-dis t.opt.bc -o t.opt.ll
https://segmentfault.com/a/1190000002669213
https://blog.csdn.net/snsn1984/article/details/81041932
https://blog.csdn.net/qq_27885505/article/details/80366525
https://blog.csdn.net/ldzm_edu/article/details/50405182
二、一些规定
1.One interesting (and very important) aspect of the LLVM IR is that it requires all basic blocks to be “terminated” with a control flow instruction such as return or branch. This means that all control flow, including fall throughs must be made explicit in the LLVM IR.
2.The body code itself could consist of multiple blocks (e.g. if it contains an if/then/else or a for/in expression).
3.Unlike the C++ code, where the variable v could be either 0 or 1 or any other,but in the LLVM IR it has to be defined only once.
三、建议
1.细分变量,为变量设置标识符,这样可以使得IR代码中不会出现寄存器编号,增加代码的可读性。(IR代码不可以调试)
例如将builder.CreateStore(builder.CreateLoad(src_i), builder.CreateGEP(dst_ptr, builder.CreateLoad(output_length)));
优化为
Value *output_idx = builder.CreateLoad(output_length, "output_idx");
Value *output_ptr = builder.CreateGEP(dst_ptr, output_idx, "output_ptr");
builder.CreateStore(src_i_val, output_ptr);
四、代码清单
1.IR code
int main() {
LLVMContext &context = TheContext;
Module *module = new Module("module", context);
IRBuilder<> builder(context);
Constant* c = module->getOrInsertFunction("foo",
/*ret type*/ builder.getVoidTy(),
/*args*/ builder.getInt8PtrTy(),// src_ptr
builder.getInt8Ty(),// target
builder.getInt8PtrTy(),// dst_ptr
builder.getInt8Ty(),// input_length
builder.getInt8PtrTy()// output_length
);
Function *func = cast<Function>(c);
func->setCallingConv(CallingConv::C);
Function::arg_iterator it = func->arg_begin();
Value* src_ptr = it++;
Value* target = it++;
Value* dst_ptr = it++;
Value* input_length = it++;
Value* output_length = it++;
//BasicBlock *entry = BasicBlock::Create(context, "entry", func);
BasicBlock *initial_i = BasicBlock::Create(context, "InitialI", func);
BasicBlock *i_less_than_n = BasicBlock::Create(context, "IsIlessThanN", func);
BasicBlock *op1 = BasicBlock::Create(context, "Operation1", func);
BasicBlock *op2 = BasicBlock::Create(context, "Operation2", func);
BasicBlock *increase_i = BasicBlock::Create(context, "IncreaseI", func);
BasicBlock *ret = BasicBlock::Create(context, "Return", func);
/// 1.Store/Load method
// builder.SetInsertPoint(initial_i);
// AllocaInst *iptr = builder.CreateAlloca(builder.getInt8Ty(), nullptr, "iptr");
// builder.CreateStore(builder.getInt8(0), iptr);
// builder.CreateBr(i_less_than_n);
//
// builder.SetInsertPoint(i_less_than_n);
// Value* iLessThanN = builder.CreateICmpULT(builder.CreateLoad(iptr), input_length, "cmp");
// builder.CreateCondBr(iLessThanN, op1, ret);
//
// builder.SetInsertPoint(op1);
// Value* src_i = builder.CreateGEP(src_ptr, builder.CreateLoad(iptr), "src[i]");
// Value* srcGreaterThanTarget = builder.CreateICmpUGT(builder.CreateLoad(src_i), target, "IsSrcIGreaterThanTarget");
// builder.CreateCondBr(srcGreaterThanTarget, op2, increase_i);
//
// builder.SetInsertPoint(op2);
// builder.CreateStore(builder.CreateLoad(src_i), builder.CreateGEP(dst_ptr, builder.CreateLoad(output_length)));
// Value* new_output_length = builder.CreateAdd(builder.CreateLoad(output_length), builder.getInt8(1));
// builder.CreateStore(new_output_length, output_length);
// builder.CreateBr(increase_i);
//
// builder.SetInsertPoint(increase_i);
// Value* new_i = builder.CreateAdd(builder.CreateLoad(iptr), builder.getInt8(1), "new_i");
// builder.CreateStore(new_i, iptr);
// builder.CreateBr(i_less_than_n);
//
// builder.SetInsertPoint(ret);
// builder.CreateRetVoid();
/// 2.PHINode method
builder.SetInsertPoint(initial_i);
Value* i = builder.getInt8(0);
builder.CreateBr(i_less_than_n);
builder.SetInsertPoint(i_less_than_n);
PHINode* phi = builder.CreatePHI(builder.getInt8Ty(), 2, "phi");
Value* next_v = builder.CreateAdd(phi, builder.getInt8(1), "nextvar");
phi->addIncoming(i, initial_i);
phi->addIncoming(next_v, increase_i);
Value* iLessThanN = builder.CreateICmpULT(phi, input_length, "cmp");
builder.CreateCondBr(iLessThanN, op1, ret);
builder.SetInsertPoint(op1);
Value* src_i = builder.CreateGEP(src_ptr, phi, "src[i]");
Value* srcGreaterThanTarget = builder.CreateICmpUGT(builder.CreateLoad(src_i), target, "IsSrcIGreaterThanTarget");
builder.CreateCondBr(srcGreaterThanTarget, op2, increase_i);
builder.SetInsertPoint(op2);
builder.CreateStore(builder.CreateLoad(src_i), builder.CreateGEP(dst_ptr, builder.CreateLoad(output_length)));
Value* new_output_length = builder.CreateAdd(builder.CreateLoad(output_length), builder.getInt8(1));
builder.CreateStore(new_output_length, output_length);
builder.CreateBr(increase_i);
builder.SetInsertPoint(increase_i);
builder.CreateBr(i_less_than_n);
builder.SetInsertPoint(ret);
builder.CreateRetVoid();
/// Configuring the module
InitializeAllTargetInfos();
InitializeAllTargets();
InitializeAllTargetMCs();
InitializeAllAsmParsers();
InitializeAllAsmPrinters();
auto TargetTriple = sys::getDefaultTargetTriple();
module->setTargetTriple(TargetTriple);
std::string Error;
auto Target = TargetRegistry::lookupTarget(TargetTriple, Error);
if (!Target) {
std::cout << "No target\n";
errs() << Error;
return 1;
}
auto CPU = "generic";
TargetOptions opt;
auto RM = Optional<Reloc::Model>();
auto TheTargetMachine = Target->createTargetMachine(TargetTriple, CPU, "", opt, RM);
module->setDataLayout(TheTargetMachine->createDataLayout());
//module->dump();
/// Emit .o file
auto Filename = "output.o";
std::error_code EC;
raw_fd_ostream dest(Filename, EC, sys::fs::F_None);
if (EC) {
std::cout << "Could not open file\n";
errs() << "Could not open file: " << EC.message();
return 1;
}
legacy::PassManager pass;
auto FileType = TargetMachine::CGFT_ObjectFile;
if (TheTargetMachine->addPassesToEmitFile(pass, dest, FileType)) {
std::cout << "TheTargetMachine can't emit a file of this type\n";
errs() << "TheTargetMachine can't emit a file of this type";
return 1;
}
pass.run(*module);
dest.flush();
outs() << "Wrote " << Filename << "\n";
}
2.JIT code
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/GVN.h"
#include "../include/KaleidoscopeJIT.h"
#include <string>
#include <system_error>
#include <iostream>
using namespace llvm;
using namespace llvm::orc;
static LLVMContext context;
static IRBuilder<> builder(context);
static std::unique_ptr<Module> module;
static KaleidoscopeJIT::ModuleHandleT H;
static std::unique_ptr<KaleidoscopeJIT> TheJIT;
typedef void foo_type_t(int32_t *, int32_t, int32_t *, int32_t, int32_t *);
void buildFunction() {
typedef llvm::FunctionType *pType;
std::vector<llvm::Type *> func_arg_types;
func_arg_types.push_back(llvm::Type::getInt32PtrTy(context, 0));
func_arg_types.push_back(llvm::Type::getInt32Ty(context));
func_arg_types.push_back(llvm::Type::getInt32PtrTy(context, 0));
func_arg_types.push_back(llvm::Type::getInt32Ty(context));
func_arg_types.push_back(llvm::Type::getInt32PtrTy(context, 0));
pType func_type = llvm::FunctionType::get(llvm::Type::getVoidTy(context),
func_arg_types,
false);
llvm::Function *func = llvm::Function::Create(func_type, llvm::GlobalValue::ExternalLinkage, "foo", module.get());
func->setCallingConv(CallingConv::C);
Function::arg_iterator it = func->arg_begin();
it->setName("src_ptr");
Value *src_ptr = it++;
it->setName("target");
Value *target = it++;
it->setName("dst_ptr");
Value *dst_ptr = it++;
it->setName("input_length");
Value *input_length = it++;
it->setName("output_length");
Value *output_length = it;
BasicBlock *initial_i = BasicBlock::Create(context, "InitialI", func);
BasicBlock *i_less_than_n = BasicBlock::Create(context, "IsIlessThanN", func);
BasicBlock *op1 = BasicBlock::Create(context, "Operation1", func);
BasicBlock *op2 = BasicBlock::Create(context, "Operation2", func);
BasicBlock *increase_i = BasicBlock::Create(context, "IncreaseI", func);
BasicBlock *ret = BasicBlock::Create(context, "Return", func);
/// 1.Store/Load method
builder.SetInsertPoint(initial_i);
AllocaInst *idx = builder.CreateAlloca(builder.getInt32Ty(), nullptr, "idx");
builder.CreateStore(builder.getInt32(0), idx);
builder.CreateBr(i_less_than_n);
builder.SetInsertPoint(i_less_than_n);
Value *iLessThanN = builder.CreateICmpSLT(builder.CreateLoad(idx), input_length, "cmp");
builder.CreateCondBr(iLessThanN, op1, ret);
builder.SetInsertPoint(op1);
Value *src_i = builder.CreateGEP(src_ptr, builder.CreateLoad(idx), "src_i_ptr");
Value *src_i_val = builder.CreateLoad(src_i, "src_i_val");
Value *srcGreaterThanTarget = builder.CreateICmpSGT(src_i_val, target, "IsSrcIGreaterThanTarget");
builder.CreateCondBr(srcGreaterThanTarget, op2, increase_i);
builder.SetInsertPoint(op2);
Value *output_idx = builder.CreateLoad(output_length, "output_idx");
Value *output_ptr = builder.CreateGEP(dst_ptr, output_idx, "output_ptr");
builder.CreateStore(src_i_val, output_ptr);
output_idx = builder.CreateAdd(output_idx, builder.getInt32(1), "output_idx");
builder.CreateStore(output_idx, output_length);
builder.CreateBr(increase_i);
builder.SetInsertPoint(increase_i);
Value *next_idx = builder.CreateAdd(builder.CreateLoad(idx), builder.getInt32(1), "next_idx");
builder.CreateStore(next_idx, idx);
builder.CreateBr(i_less_than_n);
builder.SetInsertPoint(ret);
builder.CreateRetVoid();
/// 2.PHINode method
// builder.SetInsertPoint(initial_i);
// builder.CreateBr(i_less_than_n);
//
// builder.SetInsertPoint(i_less_than_n);
// PHINode *idx = builder.CreatePHI(builder.getInt32Ty(), 2, "idx");
//
// Value *iLessThanN = builder.CreateICmpSLT(idx, input_length, "cmp");
// builder.CreateCondBr(iLessThanN, op1, ret);
//
// builder.SetInsertPoint(op1);
// Value *src_i = builder.CreateGEP(src_ptr, idx, "src_i_ptr");
// Value *src_val = builder.CreateLoad(src_i,"src_i_val");
// Value *srcGreaterThanTarget = builder.CreateICmpSGT(src_val, target, "IsSrcIGreaterThanTarget");
// builder.CreateCondBr(srcGreaterThanTarget, op2, increase_i);
//
// builder.SetInsertPoint(op2);
// Value *output_idx = builder.CreateLoad(output_length,"output_idx");
// Value *output_ptr = builder.CreateGEP(dst_ptr,output_idx,"output_ptr");
// builder.CreateStore(src_val,output_ptr);
// output_idx = builder.CreateAdd(output_idx,builder.getInt32(1),"output_idx");
// builder.CreateStore(output_idx,output_length);
// builder.CreateBr(increase_i);
//
// builder.SetInsertPoint(increase_i);
// Value *next_v = builder.CreateAdd(idx, builder.getInt32(1), "nextvar");
// idx->addIncoming(builder.getInt32(0), initial_i);
// idx->addIncoming(next_v, increase_i);
//
// builder.CreateBr(i_less_than_n);
//
// builder.SetInsertPoint(ret);
// builder.CreateRetVoid();
}
foo_type_t *getFunctionPtr() {
InitializeNativeTarget();
InitializeNativeTargetAsmPrinter();
InitializeNativeTargetAsmParser();
TheJIT = llvm::make_unique<KaleidoscopeJIT>();
module = llvm::make_unique<Module>("module", context);
module->setDataLayout(TheJIT->getTargetMachine().createDataLayout());
buildFunction();
module->dump();
H = TheJIT->addModule(std::move(module));
auto ExprSymbol = TheJIT->findSymbol("foo");
if (!(ExprSymbol && "Function not found")) {
std::cout << "Error! Function not found\n";
}
auto FP = (foo_type_t *) (intptr_t) cantFail(ExprSymbol.getAddress());
return FP;
}
int main() {
int32_t src_ptr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
int32_t dst_ptr[10];
int32_t output_length = 0;
auto FP = getFunctionPtr();
FP(src_ptr, 5, dst_ptr, 10, &output_length);
for (int i = 0; i < output_length; ++i) {
std::cout << (int) dst_ptr[i] << "\n";
}
TheJIT->removeModule(H);
return 0;
}
3.optimize the specific pass Code
//set(LLVM_LINK_COMPONENTS Passes)
#include "llvm/Passes/PassBuilder.h"
void optimize() {
llvm::PassBuilder passBuilder;
llvm::LoopAnalysisManager loopAnalysisManager(true);
llvm::FunctionAnalysisManager functionAnalysisManager(true);
llvm::CGSCCAnalysisManager cGSCCAnalysisManager(true);
llvm::ModuleAnalysisManager moduleAnalysisManager(true);
passBuilder.registerModuleAnalyses(moduleAnalysisManager);
passBuilder.registerCGSCCAnalyses(cGSCCAnalysisManager);
passBuilder.registerFunctionAnalyses(functionAnalysisManager);
passBuilder.registerLoopAnalyses(loopAnalysisManager);
passBuilder.crossRegisterProxies(loopAnalysisManager,
functionAnalysisManager,
cGSCCAnalysisManager,
moduleAnalysisManager);
llvm::ModulePassManager
modulePassManager = passBuilder.buildPerModuleDefaultPipeline(llvm::PassBuilder::OptimizationLevel::O3);
modulePassManager.run(*module, moduleAnalysisManager);
}
4.Full Coding List (including the optimization method)
// toy.cpp
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/GVN.h"
#include "../include/KaleidoscopeJIT.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/AlwaysInliner.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include <string>
#include <system_error>
#include <iostream>
using namespace llvm;
using namespace llvm::orc;
static LLVMContext context;
static IRBuilder<> builder(context);
static std::unique_ptr<Module> module;
static KaleidoscopeJIT::ModuleHandleT H;
static std::unique_ptr<KaleidoscopeJIT> TheJIT;
typedef void foo_type_t(int32_t *, int32_t, int32_t *, int32_t, int32_t *);
void buildFunction() {
typedef llvm::FunctionType *pType;
std::vector<llvm::Type *> func_arg_types;
func_arg_types.push_back(llvm::Type::getInt32PtrTy(context, 0));
func_arg_types.push_back(llvm::Type::getInt32Ty(context));
func_arg_types.push_back(llvm::Type::getInt32PtrTy(context, 0));
func_arg_types.push_back(llvm::Type::getInt32Ty(context));
func_arg_types.push_back(llvm::Type::getInt32PtrTy(context, 0));
pType func_type = llvm::FunctionType::get(llvm::Type::getVoidTy(context),
func_arg_types,
false);
llvm::Function *func = llvm::Function::Create(func_type, llvm::GlobalValue::ExternalLinkage, "foo", module.get());
func->setCallingConv(CallingConv::C);
Function::arg_iterator it = func->arg_begin();
it->setName("src_ptr");
Value *src_ptr = it++;
it->setName("target");
Value *target = it++;
it->setName("dst_ptr");
Value *dst_ptr = it++;
it->setName("input_length");
Value *input_length = it++;
it->setName("output_length");
Value *output_length = it;
BasicBlock *initial_i = BasicBlock::Create(context, "InitialI", func);
BasicBlock *i_less_than_n = BasicBlock::Create(context, "IsIlessThanN", func);
BasicBlock *op1 = BasicBlock::Create(context, "Operation1", func);
BasicBlock *op2 = BasicBlock::Create(context, "Operation2", func);
BasicBlock *increase_i = BasicBlock::Create(context, "IncreaseI", func);
BasicBlock *ret = BasicBlock::Create(context, "Return", func);
builder.SetInsertPoint(initial_i);
AllocaInst *idx = builder.CreateAlloca(builder.getInt32Ty(), nullptr, "idx");
builder.CreateStore(builder.getInt32(0), idx);
builder.CreateBr(i_less_than_n);
builder.SetInsertPoint(i_less_than_n);
Value *iLessThanN = builder.CreateICmpSLT(builder.CreateLoad(idx), input_length, "cmp");
builder.CreateCondBr(iLessThanN, op1, ret);
builder.SetInsertPoint(op1);
Value *src_i = builder.CreateGEP(src_ptr, builder.CreateLoad(idx), "src_i_ptr");
Value *src_i_val = builder.CreateLoad(src_i, "src_i_val");
Value *srcGreaterThanTarget = builder.CreateICmpSGT(src_i_val, target, "IsSrcIGreaterThanTarget");
builder.CreateCondBr(srcGreaterThanTarget, op2, increase_i);
builder.SetInsertPoint(op2);
Value *output_idx = builder.CreateLoad(output_length, "output_idx");
Value *output_ptr = builder.CreateGEP(dst_ptr, output_idx, "output_ptr");
builder.CreateStore(src_i_val, output_ptr);
output_idx = builder.CreateAdd(output_idx, builder.getInt32(1), "output_idx");
builder.CreateStore(output_idx, output_length);
builder.CreateBr(increase_i);
builder.SetInsertPoint(increase_i);
Value *next_idx = builder.CreateAdd(builder.CreateLoad(idx), builder.getInt32(1), "next_idx");
builder.CreateStore(next_idx, idx);
builder.CreateBr(i_less_than_n);
builder.SetInsertPoint(ret);
builder.CreateRetVoid();
}
static void AddOptimizationPasses(legacy::PassManager &PM,
TargetMachine *TM) {
PassManagerBuilder PMB;
int OptLevel = 3;
int SizeLevel = 0;
PMB.OptLevel = OptLevel;
PMB.SizeLevel = SizeLevel;
PMB.Inliner = createFunctionInliningPass(OptLevel, SizeLevel, false);
PMB.DisableUnitAtATime = false;
PMB.DisableUnrollLoops = false;
PMB.LoopVectorize = true;
PMB.SLPVectorize = true;
if (TM) {
TM->adjustPassManager(PMB);
}
PMB.populateModulePassManager(PM);
}
foo_type_t *getFunctionPtr() {
InitializeNativeTarget();
InitializeNativeTargetAsmPrinter();
InitializeNativeTargetAsmParser();
TheJIT = llvm::make_unique<KaleidoscopeJIT>();
module = llvm::make_unique<Module>("module", context);
module->setDataLayout(TheJIT->getTargetMachine().createDataLayout());
buildFunction();
module->dump();
legacy::PassManager PM;
AddOptimizationPasses(PM, &(TheJIT->getTargetMachine()));
PM.run(*module);
std::cout << "\nAfter optimization...\n";
module->dump();
H = TheJIT->addModule(std::move(module));
auto ExprSymbol = TheJIT->findSymbol("foo");
if (!(ExprSymbol && "Function not found")) {
std::cout << "Error! Function not found\n";
}
auto FP = (foo_type_t *) (intptr_t) cantFail(ExprSymbol.getAddress());
return FP;
}
int main() {
int32_t src_ptr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
int32_t dst_ptr[10];
int32_t output_length = 0;
auto FP = getFunctionPtr();
FP(src_ptr, 5, dst_ptr, 10, &output_length);
for (int i = 0; i < output_length; ++i) {
std::cout << (int) dst_ptr[i] << "\n";
}
TheJIT->removeModule(H);
return 0;
}
//CmakeList
set(LLVM_LINK_COMPONENTS
# all
Analysis
Core
ExecutionEngine
InstCombine
Object
RuntimeDyld
ScalarOpts
Support
native
ipo
)
add_kaleidoscope_chapter(Kaleidoscope-Ch3
toy.cpp
)
//KaleidoscopeJIT.h
//===- KaleidoscopeJIT.h - A simple JIT for Kaleidoscope --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Contains a simple JIT definition for use in the kaleidoscope tutorials.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H
#define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H
#include "llvm/ADT/iterator_range.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/JITSymbol.h"
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Mangler.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
namespace llvm {
namespace orc {
class KaleidoscopeJIT {
public:
using ObjLayerT = RTDyldObjectLinkingLayer;
using CompileLayerT = IRCompileLayer<ObjLayerT, SimpleCompiler>;
using ModuleHandleT = CompileLayerT::ModuleHandleT;
KaleidoscopeJIT()
: TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()),
ObjectLayer([]() { return std::make_shared<SectionMemoryManager>(); }),
CompileLayer(ObjectLayer, SimpleCompiler(*TM)) {
llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr);
}
TargetMachine &getTargetMachine() { return *TM; }
ModuleHandleT addModule(std::unique_ptr<Module> M) {
// We need a memory manager to allocate memory and resolve symbols for this
// new module. Create one that resolves symbols by looking back into the
// JIT.
auto Resolver = createLambdaResolver(
[&](const std::string &Name) {
if (auto Sym = findMangledSymbol(Name))
return Sym;
return JITSymbol(nullptr);
},
[](const std::string &S) { return nullptr; });
auto H = cantFail(CompileLayer.addModule(std::move(M),
std::move(Resolver)));
ModuleHandles.push_back(H);
return H;
}
void removeModule(ModuleHandleT H) {
ModuleHandles.erase(find(ModuleHandles, H));
cantFail(CompileLayer.removeModule(H));
}
JITSymbol findSymbol(const std::string Name) {
return findMangledSymbol(mangle(Name));
}
private:
std::string mangle(const std::string &Name) {
std::string MangledName;
{
raw_string_ostream MangledNameStream(MangledName);
Mangler::getNameWithPrefix(MangledNameStream, Name, DL);
}
return MangledName;
}
JITSymbol findMangledSymbol(const std::string &Name) {
#ifdef LLVM_ON_WIN32
// The symbol lookup of ObjectLinkingLayer uses the SymbolRef::SF_Exported
// flag to decide whether a symbol will be visible or not, when we call
// IRCompileLayer::findSymbolIn with ExportedSymbolsOnly set to true.
//
// But for Windows COFF objects, this flag is currently never set.
// For a potential solution see: https://reviews.llvm.org/rL258665
// For now, we allow non-exported symbols on Windows as a workaround.
const bool ExportedSymbolsOnly = false;
#else
const bool ExportedSymbolsOnly = true;
#endif
// Search modules in reverse order: from last added to first added.
// This is the opposite of the usual search order for dlsym, but makes more
// sense in a REPL where we want to bind to the newest available definition.
for (auto H : make_range(ModuleHandles.rbegin(), ModuleHandles.rend()))
if (auto Sym = CompileLayer.findSymbolIn(H, Name, ExportedSymbolsOnly))
return Sym;
// If we can't find the symbol in the JIT, try looking in the host process.
if (auto SymAddr = RTDyldMemoryManager::getSymbolAddressInProcess(Name))
return JITSymbol(SymAddr, JITSymbolFlags::Exported);
#ifdef LLVM_ON_WIN32
// For Windows retry without "_" at beginning, as RTDyldMemoryManager uses
// GetProcAddress and standard libraries like msvcrt.dll use names
// with and without "_" (for example "_itoa" but "sin").
if (Name.length() > 2 && Name[0] == '_')
if (auto SymAddr =
RTDyldMemoryManager::getSymbolAddressInProcess(Name.substr(1)))
return JITSymbol(SymAddr, JITSymbolFlags::Exported);
#endif
return nullptr;
}
std::unique_ptr<TargetMachine> TM;
const DataLayout DL;
ObjLayerT ObjectLayer;
CompileLayerT CompileLayer;
std::vector<ModuleHandleT> ModuleHandles;
};
} // end namespace orc
} // end namespace llvm
#endif // LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H
5.debug
Function *get_printf(Module *mod) {
const char *fun_name = "printf";
Function *func = mod->getFunction(fun_name);
if (func == nullptr) {
FunctionType *func_type = FunctionType::get(
Type::getInt32Ty(mod->getContext()),
{Type::getInt8PtrTy(mod->getContext())},
true);
func = Function::Create(func_type, GlobalValue::ExternalLinkage, fun_name, mod);
}
return func;
}
void Debug(Value *val) {
auto printf_ptr = get_printf(module.get());
builder.CreateCall(printf_ptr,
{builder.CreateGlobalStringPtr("[Llvm Debug] value = %lx\n"), val});
}
五、参考
http://llvm.org/docs/
https://llvm.org/docs/tutorial/index.html
http://llvm.org/docs/DebuggingJITedCode.html
http://releases.llvm.org/2.6/docs/tutorial/JITTutorial2.html
http://releases.llvm.org/2.7/docs/UsingLibraries.html
https://stackoverflow.com/questions/31279623/llvm-optimization-using-c-api
debug
https://blog.csdn.net/adream307/article/details/83820543
网友评论