LLVM IRBuilder and pass:1/2.通过llvm提供的api和IRBuilder生成LLVM-IR

本章及下一章介绍了如何通过C++、LLVM API将源代码转换为LLVM IR


1.模块Module

在LLVM IR的基本概念(构建中),模块是一个组合,它包含了其他更小的基本构件。比如,它可以包含的基本构件有全局变量、函数、数据结构等。

用LLVM创建模块之前,需要首先初始化LLVMContext,然后才能调用LLVM API,代码如下所示(实例):

//HelloModule.app

#include "llvm/IR/Module.h"
#include "llvm/IR/LLVMContext.h"

using namespace llvm;

int main(int argc, char* argv[])
{
	LLVMContext context;
	Module* module = new Module("HelloModule", context);
	
	module->print(outs(), nullptr);

	return 0;
}

1.1编译

clang++ -O3 HelloModule.cpp -o HelloModule `llvm-config --cflags --ldflags` `llvm-config --libs` `llvm-config --system-libs`

此时在当前路径下生成了一个HelloModule的可执行程序

1.2运行
运行HelloModule(示例):

./HelloModule

输出结果如下(示例):

; ModuleID = 'HelloModule'
source_filename = "HelloModule"

2.函数Function

要创建一个函数,我们需要用到其他的工具,比如llvm::Function、llvm::FunctionType等。我们知道,函数也是有类型的,而llvm::FunctionType就是用来创建函数类型的。创建函数之前,需要先创建函数类型,然后才能用llvm::Function来创建函数。

为了简单起见,我们假设这个函数没有返回值,即返回值为void,代码如下(示例):

//HelloFunction.cpp

#include "llvm/IR/Function.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"

using namespace llvm;

int main(int argc, char* argv[])
{
	LLVMContext context;

	//Create a module
	Module* module = new Module("helloModule", context);

	//Add a function
	Type* voidType = Type::getVoidTy(context);
	FunctionType* FunctionType = FunctionType::get(voidType, false);
	Function* function = Function::Create(functionType, GlobalValue::ExternalLinkage, "HelloFunction", module);
	//Print the IR 
	verifyFunction(*function);
	module->print(outs(), nullptr);
	
	return 0;
	
}

2.1编译

clang++ -O3 HelloFunction.cpp -o HelloFunction `llvm-config --cflags --ldflags` `llvm-config --libs` `llvm-config --system-libs`

此时在当前路径下生成了一个HelloFunction的可执行程序

2.2运行
运行HelloFunction(示例):

./HelloFunction

输出结果如下(示例):

; ModuleID = 'HelloModule'
source_filename = "HelloModule"

declare void @HelloFunction()

3.逻辑代码块Block

函数(Function)是由基本逻辑代码块(BasicBlock)——简称“代码块”组成。一个代码块有且只有一个起点和一个终点。代码块的起点是一个标签,它是整个代码块的标签(“entry:”),最后一条IR指令就是结束指令。

LLVM中的BasicBlock类,就是用来创建、使用、处理代码块的。当然,我们还可以使用LLVM提供的IR代码创建工具(类)IRBuilder,它能让我们更方便快捷的创建出代码块。

我们来来创建一个最简单的代码块(BasicBlock),示例代码如下:

//HelloBlock.cpp

#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"

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* voidType = Type::getVoidTy(context);
	FunctionType* functionType = FunctionType::get(voidType, false);
	Function* function = Function::Create(functionType, GlobalValue::ExternalLinkage, "HelloFunction", module);
	
	//Create a block
	BasicBlock* block = BasicBlock::Create(context, "entry", function);
	builder.SetInsertPoint(block);
	
	//Print the IR
	verifyFunction(*function);
	module->print(outs(), nullptr);
	
	return 0;
}

3.1编译

clang++ -O3 HelloBlock.cpp -o HelloBlock`llvm-config --cflags --ldflags` `llvm-config --libs` `llvm-config --system-libs`

此时在当前路径下生成了一个HelloBlock的可执行程序

3.2运行
运行HelloBlock(示例):

./HelloBlock

输出结果如下(示例):

; ModuleID = 'HelloModule'
source_filename = "HelloModule"

define void @HelloFunction() {
entry:
}

4.全局变量Global Variable

全局变量(Global Variable)是在一个模块(Module)之内全局可见的变量,也就是说模块内所有的函数都能用它。

LLVM提供了Module::getOrInsertGlobal()函数来创建全局变量,以及Module::getNamedGlobal()函数来找到一个全局变量。创建全局变量之后,我们可以配置它的属性,如链接类型、内存对齐模型等。

全局变量在链接的时候,到底是指向同一个全局变量,还是多个不同的全局变量,是由链接类型决定的。这里说的“多个不同的全局变量”,意思是其名称相同,但是有多个“分身”(可以简单的理解为copy、instance、实例等等),“分身之间互不影响”。

Column 1Column 2
ExternalLinkage模块外部可见的函数
AvailableExternallyLinkage只在查询而非代码生成的时候外部可见
LinkOnceAnyLinkage函数在链接(或内连inline)的时候仅保存一份实现
LinkOnceODRLinkage同上,但有些链接属性可以用类似的属性替换
WeakAnyLinkage函数在链接的时候仅保存一份实现(弱链接)
WeakODRLinkage同上,但有些链接属性可以用类似的属性替换
AppendingLinkage这是特殊的链接类型,只适用于全局数组
InternalLinkage链接时若发现有重命名的静态函数,则进行重命名
PrivateLinkage只做内部链接,但不会添加到符号表中
ExternalWeakLinkage外部弱链接
CommonLinkage由编译器(链接器)自动选择链接类型

有关于更详细的说明请参考LLVM官方文档Linkage Types

用llvm创建全局变量的示例代码如下:

#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.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 global variable
    module->getOrInsertGlobal("helloGlobalVariable", Type::getInt32Ty(context));
    GlobalVariable* globalVariable = module->getNamedGlobal("helloGlobalVariable");
    globalVariable->setLinkage(GlobalValue::CommonLinkage);
    globalVariable->setAlignment(MaybeAlign(4));

	//Add a function
	Type* voidType = Type::getVoidTy(context);
	FunctionType* functionType = FunctionType::get(voidType, false);
	Function* function = Function::Create(functionType, GlobalValue::ExternalLinkage, "HelloFunction", module);
	
	//Create a block
	BasicBlock* block = BasicBlock::Create(context, "entry", function);
	builder.SetInsertPoint(block);
	
	//Print the IR
	verifyFunction(*function);
	module->print(outs(), nullptr);
	
	return 0;
}

4.1编译

clang++ -O3 HelloGlobalVariable.cpp -o HelloGlobalVariable`llvm-config --cflags --ldflags` `llvm-config --libs` `llvm-config --system-libs`

此时在当前路径下生成了一个HelloGlobalVariable的可执行程序

4.2运行
运行HelloGlobalVariable(示例):

./HelloGlobalVariable

输出结果如下(示例):

; ModuleID = 'HelloModule'
source_filename = "HelloModule"

@helloGlobalVariable = common global i32, align 4

define void @HelloFunction() {
entry:
}

5.函数返回值return

我们来实现一个函数,并让它返回一个整数。比如0。在代码中,整数值0是一个常量,所以我们需要用到LLVM提供的Constant类。

// HelloReturn.cpp

#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.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 global variable
    module->getOrInsertGlobal("helloGlobalVariable", builder.getInt32Ty());
    GlobalVariable* globalVariable = module->getNamedGlobal("helloGlobalVariable");
    globalVariable->setLinkage(GlobalValue::CommonLinkage);
    globalVariable->setAlignment(MaybeAlign(4));

    // Add a function
    FunctionType* functionType = FunctionType::get(builder.getInt32Ty(), false);
    Function* function = Function::Create(functionType, GlobalValue::ExternalLinkage, "HelloFunction", module);

    // Create a block
    // 定义一个block,用于存储函数体的内容,但是函数体的内容构建是通过IRBuilder来实现的。
    BasicBlock* block = BasicBlock::Create(context, "entry", function);
    builder.SetInsertPoint(block);

    // Add a return
    ConstantInt* zero = builder.getInt32(0);
    builder.CreateRet(zero);

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

    return 0;
}

5.1编译

clang++ -O3 HelloReturn.cpp -o HelloReturn`llvm-config --cflags --ldflags` `llvm-config --libs` `llvm-config --system-libs`

此时在当前路径下生成了一个HelloGlobalVariable的可执行程序

5.2运行
运行HelloReturn(示例):

./HelloReturn

输出结果如下(示例):

; ModuleID = 'HelloModule'
source_filename = "HelloModule"

@helloGlobalVariable = common global i32, align 4

define i32 @HelloFunction() {
entry:
  ret i32 0
}

6.函数参数Function Arguments

我们来创建一个带有参数的函数

假定这个函数带有两个参数,它们的名称分别为a和b,类型均为32位整数型。代码如下(示例):

// HelloFunctionArguments.cpp

#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"

#include <vector>

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 global variable
    module->getOrInsertGlobal("helloGlobalVariable", builder.getInt32Ty());
    GlobalVariable* globalVariable = module->getNamedGlobal("helloGlobalVariable");
    globalVariable->setLinkage(GlobalValue::CommonLinkage);
    globalVariable->setAlignment(MaybeAlign(4));

    // Add a function with parameters
    std::vector<Type*> parameters(2, builder.getInt32Ty());
    FunctionType* functionType = FunctionType::get(builder.getInt32Ty(), parameters, false);
    Function* function = Function::Create(functionType, GlobalValue::ExternalLinkage, "HelloFunction", module);

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

    // 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
    verifyFunction(*function);
    module->print(outs(), nullptr);

    return 0;
}

6.1编译

clang++ -O3 HelloFunctionArguments.cpp -o HelloFunctionArguments`llvm-config --cflags --ldflags` `llvm-config --libs` `llvm-config --system-libs`

此时在当前路径下生成了一个HelloFunctionArguments的可执行程序

6.2运行
运行HelloFunctionArguments(示例):

./HelloFunctionArguments

输出结果如下(示例):

; ModuleID = 'HelloModule'
source_filename = "HelloModule"

@helloGlobalVariable = common global i32, align 4

define i32 @HelloFunction(i32 %a, i32 %b) {
entry:
  ret i32 0
}

总结

这里表明几个关系:

  • Module:包含一个至多个Function,全局变量等
    可以遍历Module得到Function
for (Module::iterator iter = M.begin(); iter != M.end(); iter++) {Function *F = &(*iter);
  • Function:包含若干个BasicBlock
  • BasicBlock:包含若干个instruction
  • instruction:指令,包含若干操作,value
  • value:大部分对象都可以看做是Value,如常量、参数、指令、函数等。

续下一章

参考1
参考2

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以参考下面的代码示例: ```c++ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/Function.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DIBuilder.h" using namespace llvm; namespace { class MyPass : public FunctionPass { public: static char ID; MyPass() : FunctionPass(ID) {} bool runOnFunction(Function &F) override { LLVMContext &Ctx = F.getContext(); Module *M = F.getParent(); // Get the DebugInfoFinder from the module DebugInfoFinder &DIFinder = M->getDebugInfoFinder(); // Get the debug location of the first instruction in the function Instruction *FirstInst = &*F.getEntryBlock().begin(); DebugLoc DL = FirstInst->getDebugLoc(); if (!DL) { // No debug location available return false; } // Get the file name from the debug location StringRef FileName = DL->getFilename(); // Create the new function Type *RetTy = Type::getVoidTy(Ctx); Type *ArgTy = Type::getInt8PtrTy(Ctx); FunctionType *FuncTy = FunctionType::get(RetTy, ArgTy, false); Function *NewFunc = Function::Create(FuncTy, GlobalValue::ExternalLinkage, "myfunc", M); // Create the entry basic block of the new function BasicBlock *BB = BasicBlock::Create(Ctx, "entry", NewFunc); // Insert a return instruction at the end of the basic block IRBuilder<> Builder(BB); Builder.CreateRetVoid(); // Set the debug location for the return instruction DIBuilder DIB(*M); DILocation *DIL = DIB.createFile(FileName, "."); Builder.SetCurrentDebugLocation(DIL->getLine(), 0, DIL); // Return true to indicate that the function was modified return true; } }; char MyPass::ID = 0; static RegisterPass<MyPass> X("mypass", "My custom pass", false, false); } // end anonymous namespace ``` 这个pass会遍历函数中的所有基本块,并在每个基本块的开头插入一个新函数。新函数的参数类型是`i8*`,返回类型是`void`。新函数不做任何操作,只是简单地返回。在创建新函数之后,我们使用`DIBuilder`类创建了一个新的调试位置,然后将该位置与新函数的返回指令相关联。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值