LLVM系列第二十八章:写一个JIT Hello World

系列文章目录

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系列第二十九章:写一个简单的常量加法“消除”工具(Pass)

flex&bison系列



前言

在此记录下基于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的实现:

  1. Legacy JIT (LLVM 1.0 - 3.5),引入了ExecutionEngine、延迟编译(lazy compilation),在当前进程中运行(in-process only),在 LLVM 3.5之后被移除了
  2. MCJIT (LLVM 2.9 - 现在),实现了ExecutionEngine,可编译链接多个目标(cross-target),不支持延迟编译
  3. 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代码如下(示例):

// Add.c

int Add(int a, int b)
{
    return a + b;
}

以下我们就来调用LLVM API生成IR代码,并调用ORC JIT对其进行编译执行(示例):

// HelloJIT.cpp

#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);

// Create a module to represent the following C function
//   int Add(int a, int b)
//   {
//       return a + b;
//   }
ThreadSafeModule CreateModule()
{
    auto context = std::make_unique<LLVMContext>();
    IRBuilder<> builder(*context);

    // Create a module
    auto module = std::make_unique<Module>("Add.c", *context);

    // Create a function that looks like:
    //   int Add(int a, int b)
    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());

    // Set arguments for the function
    function->getArg(0)->setName("a");
    function->getArg(1)->setName("b");

    // Create a block in the function
    BasicBlock* block = BasicBlock::Create(*context, "entry", function);
    builder.SetInsertPoint(block);

    // Create an instruction to add a and b:
    //   return a + b;
    Value* a = function->getArg(0);
    Value* b = function->getArg(1);
    Value* result = builder.CreateAdd(a, b, "result");
    builder.CreateRet(result);

    // Print the IR
    verifyFunction(*function);
    module->print(outs(), nullptr);

    return ThreadSafeModule(std::move(module), std::move(context));
}

// Compile and run the "Add()" function
int main(int argc, char* argv[])
{
    // Do initialization for JIT
    InitializeNativeTarget();
    InitializeNativeTargetAsmPrinter();

    // Create the JIT
    ExitOnError ExitOnErr;
    auto jit = ExitOnErr(LLJITBuilder().create());
    auto module = CreateModule();
    ExitOnErr(jit->addIRModule(std::move(module)));

    // Find the "Add()" function
    auto functionSymbol = ExitOnErr(jit->lookup("Add"));
    AddFunctionType add = (AddFunctionType)functionSymbol.getAddress();

    // Use the "Add()" function
    int result = add(12, 34);
    std::cout << "\n-----------------\n";
    std::cout << "Add(12, 34) = " << result << std::endl;

    return 0;
}

二、编译

用clang++进行编译(示例):

# Set up C++ standard library and header path
export SDKROOT=$(xcrun --sdk macosx --show-sdk-path)

# Compile
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代码。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值