当前位置:网站首页>LLVM系列第二十七章:理解IRBuilder
LLVM系列第二十七章:理解IRBuilder
2022-08-02 14:07:00 【飞翼剑仆】
系列文章目录
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源码中IRBuilder这个类的理解,以备查阅。
How
我们先来看看IRBuilder是怎么用的(示例):
#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"
using namespace llvm;
int main(int argc, char* argv[])
{
LLVMContext context;
IRBuilder<> builder(context);
// Create a module
Module* module = new Module("HelloModule", context);
// Add a function
Type* int32Type = builder.getInt32Ty();
FunctionType* functionType = FunctionType::get(int32Type, false);
Function* function = Function::Create(functionType, GlobalValue::ExternalLinkage, "HelloFunction", module);
// Create a block
BasicBlock* block = BasicBlock::Create(context, "entry", function);
builder.SetInsertPoint(block);
// Add a return
ConstantInt* zero = builder.getInt32(0);
builder.CreateRet(zero);
// Print the IR
module->print(outs(), nullptr);
return 0;
}
其生成的IR代码如下(示例):
; ModuleID = 'HelloModule'
source_filename = "HelloModule"
define i32 @HelloFunction() {
entry:
ret i32 0
}
从以上例子可以看出来,使用IRBuilder之前需要初始化(示例):
IRBuilder<> builder(context);
注意到它是个模板类,这是具体定义(示例):
template <typename FolderTy = ConstantFolder,
typename InserterTy = IRBuilderDefaultInserter>
class IRBuilder : public IRBuilderBase {
...
};
我们用它来获取了一个整数类型(示例):
Type* int32Type = builder.getInt32Ty();
我们还用它来创建了一个return指令(示例):
// Create a block
BasicBlock* block = BasicBlock::Create(context, "entry", function);
builder.SetInsertPoint(block);
// Add a return
ConstantInt* zero = builder.getInt32(0);
builder.CreateRet(zero);
具体来说,以上代码创建了一个代码块(Basic Block),并向代码块中插入了一个return语句,它返回了整数0。
Why
IRBuilder的作用其实比较纯粹,它的存在就是为了让我们方便快捷地创建IR指令(Instruction)。
注意,IRBuilder并不是全能的,它并没有把所有与创建IR有关的API都集成进来。如果要使用其它未集成的API,可以在创建好指令之后,直接对指令进行操作,比如直接调用LoadInst::setVolatile()等各种Instruction的成员函数。
所以,就算没有IRBuilder,我们照样能用LLVM提供的“原始的”C++ API来创建出所有的Instruction。使用IRBuilder,只是能让我们用稍微少点的代码且稍微快捷一点地创建出Instruction而已。
What
由以上可以看出,IRBuilder就是一个工具,它提供了一套统一的API,以便用户用来创建IR指令(Instruction),并插入到代码块中。插入的位置可以是在代码块的结尾处,也可以是在代码块中的其它位置。当每次插入Intruction之后,IRBuilder都会更新并记录下新的插入点,以便下一次能插到正确的位置。
另外,IRBuilder还能用来方便地创建数学运算指令,包括整数和float等数学运算指令。
从前面的例子程序及其描述中,我们已经知道IRBuilder是个模板类(示例):
template <typename FolderTy = ConstantFolder,
typename InserterTy = IRBuilderDefaultInserter>
class IRBuilder : public IRBuilderBase {
...
};
第一个模板参数指定了用于创建常量的工具类(Folder)。如果未指定,则默认创建的是一个“最简折叠常量”(Minimally Folded Constant),可以简单地理解为常量表达式的最终结果。
第二个模板参数指定了用于插入Instruction的工具类(Inserter)。它就像一个钩子(Hook),是用户定制过的用来插入Instruction的Hook。它在每次IRBuilder向代码块中插入新的Instruction的时候调用。如果未指定,则默认使用IRBuilderDefaultInserter,这个Hook指定了“每次插入的位置总是当前最新的插入点”,即没有做位置上的偏移或跳跃。IRBuilderDefaultInserter的源代码如下(示例):
class IRBuilderDefaultInserter {
public:
virtual ~IRBuilderDefaultInserter();
virtual void InsertHelper(Instruction *I, const Twine &Name,
BasicBlock *BB,
BasicBlock::iterator InsertPt) const {
if (BB) BB->getInstList().insert(InsertPt, I);
I->setName(Name);
}
};
IRBuilder的工作方式是,首先指定当前代码块,然后逐指令插入(如调用 IRBuilder.CreateAdd 插入一条加法指令)。当完成了一个代码块后,通过IRBuilder.SetInsertPoint() 更改当前代码块。IRBuilder在其内部记录了当前的代码块(BasicBlock),以及当前代码块中的当前指令。每次插入新的指令时,总是在当前指令的后面插入。
如果一条指令会生成一个结果(即一个新的静态单赋值 Static Single Assignment 变量),则意味着IRBuilder.CreateXxxx()就有一个返回值。该返回值的类型为 llvm::Value,可以用于代表这个SSA变量。如以下代码创建了一条加法指令,并把其结果用在return指令中(示例):
Value* arg1 = function->getArg(0);
ConstantInt* three = builder.getInt32(3);
Value* result = builder.CreateMul(arg1, three, "multiplyResult");
builder.CreateRet(result);
其生成的IR代码如下(示例):
%multiplyResult = mul i32 %a, 3
ret i32 %multiplyResult
总结
本章,我们简单地分析了一下LLVM API中的IRBuilder的作用和用法。
References
- https://clarazhang.gitbooks.io/compiler-f2017/content/llvmIRGen.html
边栏推荐
猜你喜欢
随机推荐
Redis database related commands
Redis数据库相关指令
C语言一维数组练习——将m个元素移动到数组尾部
UIWindow的makeKeyAndVisible不调用rootviewController 的viewDidLoad的问题
我理解的学习金字塔
什么是闭包?闭包的作用?闭包的应用?有什么缺点?
YOLOv7 uses cloud GPU to train its own dataset
Cannot figure out how to save this field into database. You can consider adding a type converter for
C语言字符串——关于指针
绕过正则实现SQL注入
C语言日记 5、7setprecision()问题
St. Regis Takeaway Notes - Lecture 05 Getting Started with Redis
6.如何使用CardView制作卡片布局效果
CTF-XSS
LLVM系列第二十六章:理解LLVMContext
spark优化
Introduction and use of Haystack
MySQL知识总结 (三) 索引
标签加id 和 加号 两个文本框 和一个var 赋值
Enhanced Apktool reverse artifact









