本章及下一章介绍了如何通过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 1 | Column 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,如常量、参数、指令、函数等。
续下一章