以前的工做一直集中在clang中,最近有点空闲时间,又从新熟悉了一下Pass的书写过程。(参考LLVM CookBook和http://llvm.org/docs/WritingAnLLVMPass.html)html
好比要实现一个基本的读取函数名的Pass,好比FuncBlockCount.cppbash
#include "llvm/Pass.h" #include "llvm/IR/Function.h" #include "llvm/Support/raw_ostream.h" // ./opt load ../lib/FuncBlockCount.so -funcblockcount sample.ll using namespace llvm; namespace{ struct FuncBlockCount : public FunctionPass { static char ID; FuncBlockCount() : FunctionPass(ID) { } bool runOnFunction(Function& F) override { errs() << "Function" << F.getName() << '\n'; return false; } }; char FuncBlockCount::ID = 0; static RegisterPass<FuncBlockCount> X("funcblockcount", "Function Block Count", false, false); }
大概过程就是,实现一个类(在C++中,struct和class只是有一些访问控制的不一样,具体能够百度),这个类须要继承至各类Pass,通常都是从FunctionPass做为入口,若是你对全局信息有需求的话,建议能够考虑ASTModule。app
而后须要一个ID,其实这个ID不是特别关键,而后是注册Pass,有4个参数,第一个是执行的时候调用的命令,第二个是介绍。ide
看起来很是简单,就是三步:函数
1.写一个带有runOnxxx的类,这个类须要继承至Passoop
2. 给一个初始ID测试
3.注册Passui
花几分钟读一下代码,其实发现最简单的Pass其实就是这么简单spa
写好了代码,下面介绍如何进行编译和连接,因为如今llvm主要依靠cmake来生成Makefile文件,因此要想这个Pass能运行,须要在合适的地方写CMakeList.txt文件。debug
这里,为了简化,介绍最简单的方式。在your_src_dir/lib/Transforms/下,新建一个文件夹,我这里新建的是FuncBlockCount,若是一切都正常的话,下边通常会有Scalar,Vectorize,Hello等这几个文件夹
在Transforms目录下的CMakeLists.txt中添加
add_subdirectory(FuncBlockCount)
切换到新建的FuncBlockCount下,将刚才FuncBlockCount.cpp复制到下边,而后新建CMakeLists.txt,内容以下:
add_llvm_loadable_module( FuncBlockCount FuncBlockCount.cpp DEPENDS intrinsics_gen )
而后从新cmake,make就能够生成FuncBlockCount.so文件了
写一个简单的sample.c测试一下
int foo(int n, int m) { int sum = 0; sum = n + m; return sum; }
使用-emit-llvm生成ll文件
./clang -O0 -S -emit-llvm sample.c -o sample.ll
再用opt加载就能够了
./opt -load ../lib/FuncBlockCount.so -funcblockcount sample.ll
能够看到,成功的输出了
Functionfoo
这里,咱们已经成功地完成了一个Pass,下面咱们但愿能作一点有挑战的事情,在咱们的Pass中使用其余Pass,这里咱们使用LoopInfoWrapperPass,这是一个分析循环信息的Pass
在FuncBlockCount.cpp中插入
namespace { // Hello2 - The second implementation with getAnalysisUsage implemented. struct GetLoopInfo2 : public FunctionPass { static char ID; // Pass identification, replacement for typeid GetLoopInfo2() : FunctionPass(ID) {} bool runOnFunction(Function &F) override { LoopInfo *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo(); errs() <<"Function "<< F.getName() << '\n'; for(Loop *L : *LI) { countBlocksInLoop(L, 0); } return false; } // We don't modify the program, so we preserve all analyses. void countBlocksInLoop(Loop* L, unsigned nest) { unsigned num_Blocks = 0; Loop::block_iterator bb; for(bb = L->block_begin(); bb != L->block_end(); ++bb) { num_Blocks ++; } errs() << "Loop Level "<< nest << " has "<< num_Blocks<< " Blocks\n"; std::vector<Loop*> subLoops =L->getSubLoops(); Loop::iterator j, f; for(j = subLoops.begin(), f= subLoops.end();j!=f;++j) countBlocksInLoop(*j, nest+1); } void getAnalysisUsage(AnalysisUsage &AU) const override { AU.addRequired<LoopInfoWrapperPass>(); //AU.setPreservesAll(); } }; } char GetLoopInfo2::ID = 0; static RegisterPass<GetLoopInfo2> Y("getLoopInfo2", "Get LoopInfo2");
这里其余部分变化不大,对于结构方面,添加了一个新的函数getAnalysisUsage,这个函数重载了原来Pass中的对应函数,告诉Pass管理器,咱们的Pass依赖于LoopInfoWrapperPass
从新编译生成后,咱们新写一个测试例子,刚才的例子太简单了,都没有循环结构,彻底没法体现出这个Pass的做用
sample1.cpp
// ./opt load ../lib/FuncBlockCount.so -getLoopInfo2 sample1.ll int main(int argc, char** argv) { int i,j,k , t= 0; for(i=0; i< 10;i++) { for(j=0;j<10;j++) { for(k=0;k<10;k++) { t++; } } for(j=0;j<10;++j) { t++; } } for(i=0;i<20;i++) { for(j=0;j<20;j++) { t++; } } return t; }
生成sample1.ll文件后,使用以下命令
./opt -load ../lib/FuncBlockCount.so -getLoopInfo2 sample1.ll -disable-output -debug-pass=Structure
成功能够看到输出:
若是不使用调试pass的方式,就是去掉-debug-pass选项,只有
可是,若是你忘记了添加对LoopInfoWrapperPass的依赖,那么就会呈现相似的报错信息