系列文章目录
LLVM系列第一章:编译LLVM源码 LLVM系列第二章:模块Module LLVM系列第三章:函数Function LLVM系列第四章:逻辑代码块Block LLVM系列第五章:全局变量Global Variable LLVM系列第六章:函数返回值Return LLVM系列第七章:函数参数Function Arguments LLVM系列第八章:算术运算语句Arithmetic Statement LLVM系列第九章:控制流语句if-else LLVM系列第十章:控制流语句if-else-phi LLVM系列第十一章:写一个Hello World LLVM系列第十二章:写一个简单的词法分析器Lexer LLVM系列第十三章:写一个简单的语法分析器Parser LLVM系列第十四章:写一个简单的语义分析器Semantic Analyzer LLVM系列第十五章:写一个简单的中间代码生成器IR Generator LLVM系列第十六章:写一个简单的编译器 LLVM系列第十七章:for循环 LLVM系列第十八章:写一个简单的IR处理流程Pass LLVM系列第十九章:写一个简单的Module Pass LLVM系列第二十章:写一个简单的Function Pass LLVM系列第二十一章:写一个简单的Loop Pass LLVM系列第二十二章:写一个简单的编译时函数调用统计器(Pass) LLVM系列第二十三章:写一个简单的运行时函数调用统计器(Pass) LLVM系列第二十四章:用Xcode编译调试LLVM源码 LLVM系列第二十五章:简单统计一下LLVM源码行数 LLVM系列第二十六章:理解LLVMContext LLVM系列第二十七章:理解IRBuilder LLVM系列第二十八章:写一个JIT Hello World
前言
在此记录下基于LLVM提供的ORC JIT引擎写一个简单的Hello World的过程,以备查阅。
开发环境的配置请参考第一章 《LLVM系列第一章:编译LLVM源码》。
ORC(On Request Compilation)是LLVM提供的新一代JIT引擎。JIT(Just In Time)也是一个程序,它在运行时,创建并执行了一些新的代码,而这些新代码并不是属于JIT程序本身的。以下是原英文解释:
Whenever a program, while running, creates and runs some new executable code which was not part of the program when it was stored on disk, it’s a JIT.
LLVM提供了三种JIT的实现:
- Legacy JIT (LLVM 1.0 - 3.5),引入了ExecutionEngine、延迟编译(lazy compilation),在当前进程中运行(in-process only),在 LLVM 3.5之后被移除了
- MCJIT (LLVM 2.9 - 现在),实现了ExecutionEngine,可编译链接多个目标(cross-target),不支持延迟编译
- ORC JIT (LLVM 3.7 - 现在),提供预先查询(forward looking) API,没有实现ExecutionEngine
本章我们就来写一个简单的Hello World,初步感受一下LLVM的ORC JIT引擎是什么样子的。
一、Hello JIT
为了简单起见,我们就用以下IR代码为例子,试着调用ORC JIT来编译并执行它:
; ModuleID = 'Add.c'
source_filename = "Add.c"
define i32 @Add(i32 %a, i32 %b) {
entry:
%result = add i32 %a, %b
ret i32 %result
}
其对应的C代码如下(示例):
int Add(int a, int b)
{
return a + b;
}
以下我们就来调用LLVM API生成IR代码,并调用ORC JIT对其进行编译执行(示例):
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
#include <iostream>
#include <utility>
#include <vector>
using namespace llvm;
using namespace llvm::orc;
typedef int (*AddFunctionType)(int, int);
ThreadSafeModule CreateModule()
{
auto context = std::make_unique<LLVMContext>();
IRBuilder<> builder(*context);
auto module = std::make_unique<Module>("Add.c", *context);
std::vector<Type*> parameters(2, builder.getInt32Ty());
FunctionType* functionType = FunctionType::get(builder.getInt32Ty(), parameters, false);
Function* function = Function::Create(functionType, GlobalValue::ExternalLinkage, "Add", module.get());
function->getArg(0)->setName("a");
function->getArg(1)->setName("b");
BasicBlock* block = BasicBlock::Create(*context, "entry", function);
builder.SetInsertPoint(block);
Value* a = function->getArg(0);
Value* b = function->getArg(1);
Value* result = builder.CreateAdd(a, b, "result");
builder.CreateRet(result);
verifyFunction(*function);
module->print(outs(), nullptr);
return ThreadSafeModule(std::move(module), std::move(context));
}
int main(int argc, char* argv[])
{
InitializeNativeTarget();
InitializeNativeTargetAsmPrinter();
ExitOnError ExitOnErr;
auto jit = ExitOnErr(LLJITBuilder().create());
auto module = CreateModule();
ExitOnErr(jit->addIRModule(std::move(module)));
auto functionSymbol = ExitOnErr(jit->lookup("Add"));
AddFunctionType add = (AddFunctionType)functionSymbol.getAddress();
int result = add(12, 34);
std::cout << "\n-----------------\n";
std::cout << "Add(12, 34) = " << result << std::endl;
return 0;
}
二、编译
用clang++进行编译(示例):
export SDKROOT=$(xcrun --sdk macosx --show-sdk-path)
clang++ -w -o HelloJIT `llvm-config --cxxflags --ldflags --system-libs --libs all` HelloJIT.cpp
以上命令会生成一个名为HelloJIT的可执行程序。
三、运行
运行HelloJIT(示例):
./HelloJIT
输出结果如下(示例):
; ModuleID = 'Add.c'
source_filename = "Add.c"
define i32 @Add(i32 %a, i32 %b) {
entry:
%add.result = add i32 %a, %b
ret i32 %add.result
}
-----------------
Add(12, 34) = 46
四、总结
我们利用LLVM提供的OCR JIT引擎,编译并执行了一段简单的IR代码。
|