基于LLVM 中间表示(IR)分析实例

LLVM是很优秀的编译器,其支持多源语言,多后台,而且同程序整体和整个生命周期的分析、转换和优化。
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文件中添加如下代码:
  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"
 
  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);
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)所有的步骤和上述一致,源代码如下所示:
  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"
 
  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);
2)代码解释:
因为对Instruction进行操作,所以只需要继承BasicBlockPass即可,29行对指令是否会被用到进行判断,判断函数来自第8行的头文件里面,31行删除就会删除未被使用的指令,由于目前还不知道怎么将修改后的保存到磁盘,所有在39新加了一个循环对删除后的指令进行计数,前后不一致则表示删除成功。
3)运行结果:
do nothing
Initilized erase count:0
Before erase count:11
After erase count:10
需要注意的是源程序中需要有变量未被初始化和使用,这里才会出现不同。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值