以前的工做一直集中在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的依賴,那麼就會呈現相似的報錯信息