Writing LLVM Passを読んで、LLVMのPassの追加方法が少しわかったので、今度は別のPassを追加してみよう。
参考にしたのは以下のPDF資料。ここでは、BBinLoops
と呼ばれるPassを新たに作成している。
- Writing an LLVM Pass
https://www.inf.ed.ac.uk/teaching/courses/ct/19-20/slides/llvm-2-writing_pass.pdf
このPassは、関数内に入っているループを検出し、そのループ内に何個のBasicBlockが入っているかを検出する。
このときにループの解析は別のLoopInfo
Passを使って解析することになる。
この依存関係の記述方法を学ぶということになる。
llvm/lib/Transforms/BBinLoops/BBinLoops.cpp
struct BBinLoops : public FunctionPass { static char ID; // Pass identification, replacement for typeid BBinLoops(): FunctionPass(ID) {} void getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired<LoopInfoWrapperPass>(); AU.setPreservesAll(); } virtual bool runOnFunction (Function &F) { BBinLoopsCounter ++; LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo(); int loopCounter = 0; errs() << F.getName() + "\n"; for (LoopInfo::iterator i = LI.begin(), e = LI.end(); i != e; i++) { Loop *L = *i; int bbCounter = 0; loopCounter ++; for (Loop::block_iterator bb = L->block_begin(); bb != L->block_end(); ++bb) { bbCounter += 1; } errs() << "Loop "; errs() << loopCounter; errs() << ": #BBs = "; errs() << bbCounter; errs() << '\n'; } return false; } }; } char BBinLoops::ID = 0; static RegisterPass<BBinLoops> X("bbinLoops", "Counts basic block in loops");
まずポイントとなるのがgetAnalysisUsage
で、ここに依存関係を記述する。
LoopInfo
passに対する依存関係をaddRequired
に書けばよいのだが、どうも新しいPassManagerの影響でWrapperを被せたLoopInfoWrapperPass
を呼び出す必要があるようだ。これがないとLoopInfo
PassにIDが無いとエラーになる。
そして以下がLoopInfoの情報を使った実装となる。これはまだ未完成。ネストされたPassに対するループが実装できていない。
要点は、LoopInfo::iterator
を通じてLoopInfoからの情報を取得し、その中のBasicBlock
の数を数えているということ。これで一応所望の実装は出来るようになっている。
virtual bool runOnFunction (Function &F) { BBinLoopsCounter ++; LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo(); int loopCounter = 0; errs() << F.getName() + "\n"; for (LoopInfo::iterator i = LI.begin(), e = LI.end(); i != e; i++) { Loop *L = *i; int bbCounter = 0; loopCounter ++; for (Loop::block_iterator bb = L->block_begin(); bb != L->block_end(); ++bb) { bbCounter += 1; } errs() << "Loop "; errs() << loopCounter; errs() << ": #BBs = "; errs() << bbCounter; errs() << '\n'; } return false; }
以下のプログラムを使って試してみる。
int main (int argc, char **argv) { int i, j, t = 0; for (i = 0; i < 10; i++) { for (j = 0; j < 10; j++) { if ((i+j) % 7 == 0) { break; } else { t++; } } } printf ("%d\n", t); return 0; }
$ clang -O0 -emit-llvm loop_sample.c -c -o loop_sample.bc $ ../bin/opt -enable-new-pm=0 -f -load ../lib/LLVMBBinLoops.so --bbinLoops < ./loop_sample.bc --disable-output
main Loop 1: #BBs = 10
まだループのネストに対応していないけれども、とりあえず外周のループについては検出できた。次はこれを拡張していく。