FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

LLVMに新しいPassを追加してみる試行 (依存関係のあるAnalysisを呼ぶ方法)

f:id:msyksphinz:20210922000636p:plain

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

まだループのネストに対応していないけれども、とりあえず外周のループについては検出できた。次はこれを拡張していく。