LLVM是很优秀的编译器,其支持多源语言,多后台,而且同程序整体和整个生命周期的分析、转换和优化。
1#include "llvm/Pass.h"
2#include "llvm/IR/Function.h"
3#include "llvm/IR/Module.h"
4#include "llvm/IR/BasicBlock.h"
5#include "llvm/IR/Instruction.h"
6#include "llvm/IR/Instructions.h"
7#include "llvm/Support/raw_ostream.h"
8
9 usingnamespace llvm;
10
11namespace
12{
13 struct BasicBlockName : publicModulePass
14 {
15 static char ID;
16 BasicBlockName():ModulePass(ID){}
17 virtual boolrunOnModule(Module &M)
18 {
19 for(Module::iterator Mit=M.begin(),Mite=M.end();Mit!=Mite;Mit++)
20 {
21 errs()<<"Function:"<<Mit->getName()<<"\n";
22 for(llvm::Function::iterator Fit =Mit->begin(),Fite = Mit->end();Fit!=Fite;Fit++)
23 {
24 llvm::BasicBlock* bb =Fit;
25 errs()<<"----BasicBlock:"<<bb->getName()<<"\n";
26 if(bb->size()>1)
27 {
28 for(BasicBlock::iteratorBit=bb->begin(),Bite=bb->end();Bit!=Bite;Bit++)
29 {
30 errs()<<"--------"<<Bit->getOperand(0)->getName()<<"| "
31 <<Bit->getOperand(0)->getValueName()<<" |"
32 <<Bit->getOperand(0)->getValueID()<<" |"
33 <<Bit->getOperand(0)->getNumUses()<<" ** end\n";
34 }
35 }
36 }
37 }
38 returnfalse;
39 }
40 };
41}
42
43 charBasicBlockName::ID = 0;
44 staticRegisterPass Y("BasicBlock","BBName",false,false);
1 #include "llvm/Pass.h"
2 #include "llvm/IR/Function.h"
3 #include "llvm/IR/Module.h"
4 #include "llvm/IR/BasicBlock.h"
5 #include "llvm/IR/Instruction.h"
6 #include "llvm/IR/Instructions.h"
7 #include"llvm/Support/raw_ostream.h"
8 #include"llvm/Transforms/Utils/Local.h"
9
10 using namespace llvm;
11
12 namespace
13 {
14
structDeleteInstruction : public BasicBlockPass
15
{
16
static char ID;
17
DeleteInstruction():BasicBlockPass(ID){}
18
19
virtual boolrunOnBasicBlock(BasicBlock &BB)
20
{
21
errs()<<"do nothing"<<"\n";
22
bool change = false;
23
intsign = 0;
24
intcount = 0;
25
errs()<<"Initilized erasecount:"<<count<<"\n";
26
for(BasicBlock::iterator DI = BB.begin();DI!=BB.end();)
27
{
28
Instruction *Inst = DI++;
29
if(isInstructionTriviallyDe
ad(Inst))
30
{
31
Inst->eraseFromParent();
32
change = true;
33
}
34
sign++;
35
count++;
36
}
37
errs()<<"Before erasecount:"<<count<<"\n";
38
count = 0;
39
for(BasicBlock::iterator DI =BB.begin();DI!=BB.end();)
40
{
41
DI++;
42
count++;
43
}
44
errs()<<"After erasecount:"<<count<<"\n";
45
return change;
46
return false;
47
}
48
};
49 }
50
51 charDeleteInstruction::ID = 0;
52 staticRegisterPass X("DeleteInstruction","DI",false,false);
LLVM 中间表示(Intermediaterepresentation,简称IR)作为LLVM的中间语言,对LLVM各种特性的支持有非常重要的作用。
有很多时候我们需要对LLVMIR进行分析,LLVM官方有文档:http://llvm.org/docs/WritingAnLLVMPass.html,其介绍了一个基本的步骤,和对其中一些常用的Pass的介绍,其中的实例很简单,只是简单地打印出函数的名字。
因此为了加深对Pass的学习,下面将分析两个实例:
1、写一个Pass打印出Module、Function、BasicBlock、变量的值或者一些一些属性。
1)所有的步骤都参见官方文档,在/llvm/lib/Transforms目录下面新建一个文件夹(以BasicBlockName为例),到该目录下面新建两个文件一个就是需要用到的BasicBlockName.cpp文件,另外一个就是Makefile。
还需要将新建的文件夹的名字加到
/llvm/lib/Transforms目录下面的Makefile里面
PARALLEL_DIRS的后面添加该文件名。
这样即可编辑cpp文件。
2)在cpp文件中添加如下代码:
3)对代码中进行解释:
第13行处定义了一个继承自ModulePass的BaiscBlockName结构体,17行是具体实现该函数功能,19、22、28分别针对不同的层次使用一个for循环遍历IR中的对象,代码中getName、getValue等函数得到需要的值然后打印出来即可。
4)需要到编译llvm的build文件夹下面make一下,就会在Release+Asserts/lib下面生成BasicBlockName.so文件,然后按照官方文档使用,opt-load ***/
BasicBlockName.so-BasicBlock test.bc > /dev/null 这样即可打印出对应的名字。
2、删除IR中一条未被使用的指令。
1)所有的步骤和上述一致,源代码如下所示:
2)代码解释:
因为对Instruction进行操作,所以只需要继承BasicBlockPass即可,29行对指令是否会被用到进行判断,判断函数来自第8行的头文件里面,31行删除就会删除未被使用的指令,由于目前还不知道怎么将修改后的保存到磁盘,所有在39新加了一个循环对删除后的指令进行计数,前后不一致则表示删除成功。
3)运行结果:
do nothing
Initilized erase count:0
Before erase count:11
After erase count:10
需要注意的是源程序中需要有变量未被初始化和使用,这里才会出现不同。