LLVM系列第二十七章:理解IRBuilder

系列文章目录

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源码中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);

(完整源码请参考:https://github.com/wuzhanglin/llvm-IR-examples/blob/main/07.ArithmeticStatement/HelloArithmeticStatement.cpp。)

其生成的IR代码如下(示例):

  %multiplyResult = mul i32 %a, 3
  ret i32 %multiplyResult

总结

本章,我们简单地分析了一下LLVM API中的IRBuilder的作用和用法。

References

  • https://clarazhang.gitbooks.io/compiler-f2017/content/llvmIRGen.html
  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: LLVM IRBuilder是一种代码生成工具,它被用于将代码转换成LLVM IR格式。这种工具可以帮助开发人员更容易地生成LLVM IR代码,从而提高代码生成的效率。LLVM IRBuilder提供了一种简单易用的API,可以让开发人员通过简单的几个步骤来构建LLVM IR代码。 使用LLVM IRBuilder可以轻松地构建LLVM IR函数、基本块、指令等。该工具可以自动地管理使用到的中间变量,并生成最终的LLVM IR代码。在使用LLVM IRBuilder时,开发人员只需要按照所需的指令顺序调用相应的API函数,即可自动生成对应的LLVM IR代码。这种方式使得代码生成更加容易,同时也能够减少开发人员编写代码的工作量,提高代码的可维护性。 总之,LLVM IRBuilder是一个强大的代码生成工具,它能够帮助开发人员更加高效地生成LLVM IR代码。使用这种工具能够使代码生成变得更加容易,从而为开发人员提供更多的时间和精力来处理其他方面的问题。 ### 回答2: LLVM IRBuilderLLVM工具链中的一个重要模块,它主要用于生成LLVM IR代码。LLVM IRBuilder提供了一组简单易用的API,使得开发人员能够以高级的方式来生成IR代码。通过使用LLVM IRBuilder,开发人员可以更加灵活地控制生成的IR代码,从而更容易地实现编译器优化和代码生成任务。 LLVM IRBuilder的核心API包括创建基本块、创建指令、创建值、将指令添加到基本块、以及跳转到其他基本块等。在使用LLVM IRBuilder时,开发人员只需要简单地调用这些API即可生成相应的IR代码。此外,LLVM IRBuilder还提供了一些高级API,例如根据类型创建值、创建内存操作指令、以及创建运行时库调用等。 总体而言,LLVM IRBuilderLLVM工具链中非常重要的一部分,它将LLVM IR代码的生成变得更加简单和易用。它对于开发高性能、高效的编译器和代码生成器非常有用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值