分析Pass在实际不修改IR的情况下提供关于IR的更高级的信息,而这些信息可以被其他的分析Pass使用来计算其结果,只要一个分析的Pass计算得出了结果,这个计算结果可以被不同的Pass拿来多次使用,直到一个Pass改变了这个IR
我们先编写下我们需要去进行测试的代码
int func(int a,int b)
{
int sum=0;
int iter;
for (iter = 0; iter< a; iter++) {
int iter1;
for (iter1=0; iter<b; iter1++) {
sum+=iter>iter1 ? 1:0;
}
}
return sum;
}
然后我们去利用clang -c -emit-llvm testcode.c -o testcode.bc,去将其转换为.bc文件,也就是字节码文件
之后我们就开始进行编写分析Pass
#define DEBUG_TYPE "opcodeCounter"
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
using namespace llvm;
namespace {
//此分析Pass是在函数层级上使用的,作用于程序当中的每一个函数,因此,我们在声明CountOpcodes:public FunctionPass结构的时候基础了FunctionPass函数
struct CountOpcode:public FunctionPass
{
std::map<std::string,int>opcodeCounter;
static char ID;
CountOpcode() : FunctionPass(ID){}
virtual bool runOnFunction (Function &F)
{
llvm:outs() << "Function " <<F.getName() << '\n';
//第一层for循环遍历函数所有的基本块
for (Function::iterator bb = F.begin(), e=F.end();bb!=e;++bb ) {
//第二层for循环遍历基本块当中的每一条指令
for (BasicBlock::iterator i = bb->begin(),e=bb->end(); i!=e;++i) {
//判断在map当中有没有过指令,如果没有就直接设置为1
//使用find,返回的是被查找元素的位置,没有则返回map.end()
if (opcodeCounter.find(i->getOpcodeName())==opcodeCounter.end()) {
opcodeCounter[i->getOpcodeName()]=1;
}else
{
//有的就是加一
opcodeCounter[i->getOpcodeName()]+=1;
}
}
}
std::map<std::string,int>::iterator i = opcodeCounter.begin();
std::map<std::string,int>::iterator e = opcodeCounter.end();
//遍历输出
while(i!=e)
{
llvm::outs()<< i->first << ": "<<i->second << "\n";
i++;
}
llvm::outs()<<"\n";
opcodeCounter.clear();
//函数没有修改测试代码当中的任何东西,所以返回false
return false;
}
};
}
//注册Pass
char CountOpcode::ID = 0;
static RegisterPass<CountOpcode>X("opcodeCounter","Count number of opcode in a functions");
紧接着我们再通过下面的命令去生成.so动态库
g++ opcodeCount.cpp -fPIC -g -Wall -Wextra -std=c++11 `llvm-config --cppflags ` -shared -o opcodeCount.so
最后通过下面的命令进行链接
opt -load opcodeCount.so -opcodeCounter -disable-output testcode.bc
结果如下所示
Function func
add: 3
alloca: 5
br: 8
icmp: 3
load: 10
ret: 1
select: 1
store: 8