LLVM使用其他Pass的結果


之前的工作一直集中在clang中,最近有點空閑時間,又重新熟悉了一下Pass的書寫過程。(參考LLVM CookBook和http://llvm.org/docs/WritingAnLLVMPass.html)

比如要實現一個基本的讀取函數名的Pass,比如FuncBlockCount.cpp

#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。

然后需要一個ID,其實這個ID不是特別關鍵,然后是注冊Pass,有4個參數,第一個是執行的時候調用的命令,第二個是介紹。

看起來非常簡單,就是三步:

1.寫一個帶有runOnxxx的類,這個類需要繼承至Pass

2. 給一個初始ID

3.注冊Pass

花幾分鍾讀一下代碼,其實發現最簡單的Pass其實就是這么簡單

寫好了代碼,下面介紹如何進行編譯和鏈接,由於現在llvm主要依靠cmake來生成Makefile文件,所以要想這個Pass能運行,需要在合適的地方寫CMakeList.txt文件。

這里,為了簡化,介紹最簡單的方式。在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的依賴,那么就會呈現類似的報錯信息

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM