【LLVM】如何寫(xiě)一個(gè)pass

1.簡(jiǎn)介

LLVM pass是編譯器中很重要的部分育八,能夠?qū)Υa進(jìn)行轉(zhuǎn)化和優(yōu)化施蜜。所有pass都是Pass類的子類替裆,通過(guò)覆蓋Pass類的虛函數(shù)來(lái)實(shí)現(xiàn)功能,可繼承的類有ModulePass , CallGraphSCCPass, FunctionPass , LoopPass, RegionPass, BasicBlockPass填抬。詳見(jiàn)https://llvm.org/doxygen/classllvm_1_1Pass.html烛芬。

環(huán)境搭建參考:https://blog.csdn.net/l2563898960/article/details/82871826

本文參考:https://llvm.org/docs/WritingAnLLVMPass.html

2.寫(xiě)hello world pass

Hello pass用于打印出內(nèi)部函數(shù)的函數(shù)名,不會(huì)修改程序飒责,只是監(jiān)視作用蛀骇,Hello pass的源碼和文件在LLVM源碼的lib/Transforms/Hello目錄下。

(1)設(shè)置

首先读拆,配置和安裝LLVM擅憔;然后在LLVM源碼目錄下創(chuàng)建一個(gè)新目錄,這里假設(shè)你創(chuàng)建了lib/Transforms/Hello目錄檐晕;最后暑诸,設(shè)置build腳本,用于編譯新的pass辟灰。將以下代碼拷貝到lib/Transforms/Hello/CMakeLists.txt个榕。

add_llvm_library( LLVMHello MODULE
  Hello.cp

  PLUGIN_TOOL
  opt
  )

將以下行加入到lib/Transforms/CMakeLists.txt

add_subdirectory(Hello)

這個(gè)build腳本表示當(dāng)前目錄的Hello.cpp文件將被編譯和鏈接成共享對(duì)象$(LEVEL)/lib/LLVMHello.so,能被opt工具通過(guò)-load選項(xiàng)動(dòng)態(tài)加載芥喇。

(2)寫(xiě)Helllo.cpp

首先需要添加頭文件西采,因?yàn)樵趯?xiě) Pass,在函數(shù) Function上操作继控,且需要打印數(shù)據(jù)械馆。

#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"

接下來(lái)胖眷,include文件中的函數(shù)落在llvm命名空間。

using namespace llvm;

接下來(lái)霹崎,開(kāi)始一段匿名空間珊搀,匿名空間在c++中用到,c中采用static實(shí)現(xiàn)尾菇,定義在匿名空間中的變量只能在當(dāng)前文件可見(jiàn)境析。

namespace{

接下來(lái)定義pass,定義Hello類派诬,從FunctionPass類繼承過(guò)來(lái)劳淆,每次處理一個(gè)函數(shù)。

struct Hello : public FunctionPass {
static char ID;
Hello() : FunctionPass(ID) {}

聲明 runOnFunction 方法默赂,重寫(xiě)從 FunctionPass繼承來(lái)的同名虛函數(shù)憔儿。runOnFunction()就是以函數(shù)為單位進(jìn)行處理,LLVM會(huì)以一次一個(gè)function為單位放可,喂進(jìn)來(lái)給你處理,接下來(lái)就是將喂進(jìn)來(lái)的function的名字打印出來(lái)朝刊。

  bool runOnFunction(Function &F) override {
    errs() << "Hello: ";
    errs().write_escaped(F.getName()) << '\n';
    return false;
  }
}; // end of struct Hello
}  // end of anonymous namespace

初始化pass的ID耀里,LLVM使用ID地址來(lái)識(shí)別pass,所以所用初始值不重要拾氓。

char Hello::ID = 0;

最后冯挎,注冊(cè)Hello類,給一個(gè)命令行參數(shù)"hello"和一個(gè)名字"Hello World Pass"咙鞍,最后兩個(gè)參數(shù)描述它的行為:如果pass需要修改CFG則第3個(gè)參數(shù)設(shè)為true房官,若pass是一個(gè)analysis pass,例如dominator tree pass续滋,則第4個(gè)參數(shù)設(shè)為true翰守。

static RegisterPass<Hello> X("hello", "Hello World Pass",
                             false /* Only looks at CFG */,
                             false /* Analysis Pass */);

如果要將本pass注冊(cè)為現(xiàn)有流水線中的一步,則還需要一些擴(kuò)展疲酌。eg蜡峰,加到優(yōu)化步驟之前則用PassManagerBuilder::EP_EarlyAsPossible;加到優(yōu)化之后則用PassManagerBuilder::EP_FullLinkTimeOptimizationLast朗恳。

static llvm::RegisterStandardPasses Y(
    llvm::PassManagerBuilder::EP_EarlyAsPossible,
    [](const llvm::PassManagerBuilder &Builder,
        llvm::legacy::PassManagerBase &PM) { PM.add(new Hello()); });

整個(gè)代碼.cpp文件如下:

#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"

#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"

using namespace llvm;

namespace {
struct Hello : public FunctionPass {
  static char ID;
  Hello() : FunctionPass(ID) {}

  bool runOnFunction(Function &F) override {
    errs() << "Hello: ";
    errs().write_escaped(F.getName()) << '\n';
    return false;
  }
}; // end of struct Hello
}  // end of anonymous namespace

char Hello::ID = 0;
static RegisterPass<Hello> X("hello", "Hello World Pass",
                             false /* Only looks at CFG */,
                             false /* Analysis Pass */);
static llvm::RegisterStandardPasses Y(
    llvm::PassManagerBuilder::EP_EarlyAsPossible,
    [](const llvm::PassManagerBuilder &Builder,
        llvm::legacy::PassManagerBase &PM) { PM.add(new Hello()); });

在頂層LLVM根目錄下創(chuàng)建build目錄湿颅,在build目錄下先"cmake ../",再"make"即可生成lib/LLVMHello.so文件粥诫。

(3)使用opt運(yùn)行pass

生成共享目標(biāo)文件后油航,由于已經(jīng)通過(guò)RegisterPass注冊(cè)過(guò)了,所以可以使用opt命令通過(guò)你的pass運(yùn)行LLVM程序怀浆。首先參考Getting Started with the LLVM System編譯"Hello World"為bitcode文件(hello.bc)谊囚,通過(guò)以下命令運(yùn)行hello.bc("-load"表示加載pass庫(kù)):

$ opt -load lib/LLVMHello.so -hello < hello.bc > /dev/null
Hello: __main
Hello: puts
Hello: main

3.Pass類和需求

設(shè)計(jì)一個(gè)pass首先要考慮需要繼承哪一個(gè)類怕享,Hello World例子使用了FunctionPass類來(lái)實(shí)現(xiàn),接下來(lái)看看其它可用的類秒啦。

(1)ImmutablePass

這個(gè)類比較無(wú)聊熬粗,這個(gè)類用在不用運(yùn)行、不會(huì)改變狀態(tài)余境、不需要更新的pass驻呐,在轉(zhuǎn)化和分析中不常用到,但能提供當(dāng)前編譯器配置信息芳来。盡管這個(gè)類不常用到含末,但是能提供當(dāng)前被編譯的目標(biāo)機(jī)的信息,以及影響轉(zhuǎn)化的靜態(tài)信息即舌。

(2)ModulePass

最常用的一個(gè)類佣盒,使用該類表示將整個(gè)程序當(dāng)做一個(gè)單元,可以隨意引用函數(shù)主體顽聂,添加和移除函數(shù)肥惭。由于不知道ModulePass子類的行為,不能作優(yōu)化紊搪。

ModulePass可以使用函數(shù)級(jí)passes(如dominators蜜葱,函數(shù)級(jí)pass使用getAnalysis接口,也即getAnalysis<DominatorTree>(llvm::Function *)來(lái)提供獲取分析結(jié)果的一個(gè)函數(shù))耀石。寫(xiě)ModulePass時(shí)需要重寫(xiě)runOnModule函數(shù)牵囤,該函數(shù)完成pass的主要工作,如果原IR發(fā)生修改則返回True滞伟,如果只是分析揭鳞,則返回False。

(3)CallGraphSCCPass

在調(diào)用圖上從后往前遍歷程序梆奈。CallGraphSCCPass可以幫助構(gòu)建和遍歷調(diào)用圖野崇。CallGraphSCCPass子類需滿足的要求:只能監(jiān)控和修改當(dāng)前SCC、SCC的直接調(diào)用者和直接被調(diào)用者亩钟,不能監(jiān)控和修改其他Function舞骆;需要保存當(dāng)前CallGraph對(duì)象,顯示對(duì)代碼做了哪些修改径荔;不能從當(dāng)前Module添加/去除SCC督禽,但可以增減全局變量;調(diào)用runOnSCC之間能保持狀態(tài)(包括全局變量)总处。

需重寫(xiě)以下函數(shù):

  • doInitialization(CallGraph &):能做CallGraphSCCPass不允許的事情狈惫,如增減函數(shù)、獲取指向函數(shù)的指針。
  • runOnSCC:完成pass的主要工作胧谈。
  • doFinalization(CallGraph &):很少使用忆肾,在pass調(diào)用完runOnSCC之后才調(diào)用它。

(4) FunctionPass

FunctionPass處理程序中每個(gè)函數(shù)菱肖,并不依賴其他函數(shù)的結(jié)果客冈,F(xiàn)unctionPass不需要它們按特定順序執(zhí)行,不會(huì)修改外部函數(shù)稳强。

FunctionPass子類的要求:只能監(jiān)控和修改當(dāng)前被處理的Function场仲;不能從當(dāng)前Module增減Function、全局變量退疫;調(diào)用runOnFunction之間不能保持狀態(tài)(包括全局變量)渠缕。

需重寫(xiě)以下函數(shù):

  • doInitialization(Module &):能做FunctionPass不允許的事情,如增減函數(shù)褒繁、獲取指向函數(shù)的指針亦鳞。使用示例見(jiàn)LowerAllocations pass,該pass將malloc棒坏、free指令轉(zhuǎn)化為malloc()free()函數(shù)調(diào)用燕差,它使用doInitialization函數(shù)對(duì)mallocfree函數(shù)的索引,如果有需要坝冕,則往module添加prototypes徒探。
  • runOnFunction函數(shù):完成pass的主要工作,轉(zhuǎn)化或分析徽诲。
  • doFinalization(Module &)函數(shù):很少使用,在pass調(diào)用完runOnFunction之后才調(diào)用它吵血。

(5) LoopPass

LoopPass遍歷處理函數(shù)中的loop谎替,并不依賴函數(shù)中其他loop。遍歷時(shí)遇到嵌套循環(huán)蹋辅,最外面的循環(huán)最后處理钱贯。LoopPass的子類可以使用LPPassManager接口來(lái)更新loop。

如果把LoopPass的子類嵌入到main loop pass流水線中去運(yùn)行侦另,則需要保存其他loop pass需要用到的function分析秩命。LoopUtils.h提供了getLoopAnalysisUsage函數(shù),可以在子類的getAnalysisUsage重載中調(diào)用褒傅。

需重寫(xiě)以下函數(shù):

  • doInitialization(Loop *, LPPassManager &):可以使用LPPassManager接口來(lái)訪問(wèn)FunctionModule級(jí)分析信息弃锐。
  • runOnLoop:完成pass的主要工作,即代碼轉(zhuǎn)換或分析殿托。
  • doFinalization()

(6)RegionPass

LoopPass類似霹菊,但只處理函數(shù)中單入口單退出的區(qū)域。

需重寫(xiě)的函數(shù):

  • doInitialization(Region *, RGPassManager &):可以使用LPPassManager接口來(lái)訪問(wèn)FunctionModule級(jí)分析信息支竹。
  • runOnRegion
  • doFinalization()

(7)MachineFunctionPass類

是LLVM code generator的一部分旋廷,依賴機(jī)器類型鸠按。Code generator passes采用TargetMachine::addPassesToEmitFile來(lái)注冊(cè)和初始化,所以不能通過(guò)optbugpoint命令來(lái)運(yùn)行饶碘。MachineFunctionPass也屬于FunctionPass目尖,所以和FunctionPass的限制一樣,此外MachineFunctionPass還不能修改和創(chuàng)建 LLVM IR Instruction扎运、BasicBlock瑟曲、ArgumentFunction绪囱、GlobalVariable测蹲、GlobalAliasModule鬼吵,只能修改當(dāng)前正被處理的MachineFunction扣甲,調(diào)用runOnMachineFunction不能保持狀態(tài)。

需重寫(xiě)的函數(shù):

  • runOnMachineFunction(MachineFunction &MF)MachineFunctionPass的主入口點(diǎn)齿椅,完成pass主要工作琉挖。每遇到Module中的一個(gè)MachineFunction都調(diào)用runOnMachineFunction函數(shù)。

(8)pass注冊(cè)

前面Hello World pass已經(jīng)展示了如何注冊(cè)涣脚,采用RegisterPass調(diào)用示辈。

待實(shí)現(xiàn)的函數(shù):

  • print函數(shù):virtual void print(llvm::raw_ostream &O, const Module *M) const;

    用于打印分析結(jié)果,對(duì)于調(diào)試和展示該分析如何工作很有用遣蚀,使用opt的-analyze參數(shù)來(lái)調(diào)用此函數(shù)矾麻。llvm::raw_ostream參數(shù)確定了打印結(jié)果采用什么流,Module參數(shù)是指向程序的頂層模塊的指針芭梯,當(dāng)從調(diào)試器調(diào)用Pass::dump()時(shí)該指針可為NULL险耀。

  • pass之間的聯(lián)系:PassManager負(fù)責(zé)pass之間的聯(lián)系和依賴(決定執(zhí)行順序),每個(gè)pass可以聲明必須在它之前執(zhí)行的pass玖喘。如果某pass未實(shí)現(xiàn)getAnalysisUsage函數(shù)甩牺,則默認(rèn)沒(méi)有要預(yù)先執(zhí)行的pass。

  • getAnalysisUsagevirtual void getAnalysisUsage(AnalysisUsage &Info) const;

    實(shí)現(xiàn)時(shí)需用requiredinvalidated pass填充AnalysisUsage對(duì)象累奈,通過(guò)以下函數(shù)來(lái)實(shí)現(xiàn):

    • AnalysisUsage::addRequired<> & AnalysisUsage::addRequiredTransitive<>:定義必須在本pass之前執(zhí)行的pass贬派,如DominatorSetBreakCriticalEdges澎媒。有些分析需要和其他分析一起才能正常工作搞乏,如AliasAnalysis <AliasAnalysis>實(shí)現(xiàn)需要鏈接到其他分析pass,這時(shí)候要用到addRequiredTransitive函數(shù)戒努,而非addRequired函數(shù)(表示只要the requiring pass在運(yùn)行查描,過(guò)渡的required pass也要保持運(yùn)行)。
    • AnalysisUsage::addPreserved<>setPreservesAll表示pass不會(huì)修改LLVM程序;setPreservesCFG表示會(huì)修改指令但不會(huì)修改CFG或終止指令冬三;addPreserved適用于代碼轉(zhuǎn)換類的pass匀油,如BreakCriticalEdges

    getAnalysisUsage實(shí)現(xiàn)示例:

      // This example modifies the program, but does not modify the CFG
      void LICM::getAnalysisUsage(AnalysisUsage &AU) const {
        AU.setPreservesCFG();
        AU.addRequired<LoopInfoWrapperPass>();
      }
    
  • getAnalysis<>getAnalysisIfAvailable<>Pass::getAnalysis<>自動(dòng)從你實(shí)現(xiàn)的類中繼承勾笆,它使你能訪問(wèn)之前用getAnalysisUsage聲明的pass敌蚜,只需要1個(gè)參數(shù)來(lái)指定需要哪個(gè)pass類,然后返回對(duì)該pass的引用窝爪。

    例如:如果你試圖獲取一個(gè)沒(méi)在getAnalysisUsage中聲明的分析弛车,則會(huì)報(bào)錯(cuò)∑衙浚可在你的run*函數(shù)中調(diào)用它纷跛。

      bool LICM::runOnFunction(Function &F) {
        LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
        //...
      }
    

    還有個(gè)優(yōu)點(diǎn),該接口使你能在module級(jí)pass中使用函數(shù)級(jí)分析邀杏,例如:pass manager會(huì)在返回索引之前調(diào)用DominatorTree贫奠。

      bool ModuleLevelPass::runOnModule(Module &M) {
        //...
        DominatorTree &DT = getAnalysis<DominatorTree>(Func);
        //...
      }
    

    如果你的pass可以更新分析,可以使用getAnalysisIfAvailable方法望蜡,如果分析是active的則返回一個(gè)指針唤崭。

      if (DominatorSet *DS = getAnalysisIfAvailable<DominatorSet>()) {
        // A DominatorSet is active.  This code will update it.
      }
    

(9)實(shí)現(xiàn)Analysis Groups

說(shuō)明:有些復(fù)雜的分析,如流敏感脖律、上下文敏感的過(guò)程間分析需要很多分析配合一起實(shí)現(xiàn)谢肾。如果其他pass想使用Analysis groups,也需要調(diào)用AnalysisUsage::addRequired()Pass::getAnalysis()來(lái)獲取小泉,但使用PassManager更簡(jiǎn)單芦疏。Analysis group也需要使用RegisterAnalysisGroup來(lái)注冊(cè),并調(diào)用INITIALIZE_AG_PASS宏來(lái)整合微姊。示例可以看看AliasAnalysis酸茴。

  • RegisterAnalysisGroupRegisterAnalysisGroup用于注冊(cè)Analysis group,INITIALIZE_AG_PASS宏用于將pass實(shí)現(xiàn)添加到analysis group柒桑。

    static RegisterAnalysisGroup<AliasAnalysis> A("Alias Analysis");

    注冊(cè)完分析之后弊决,pass可以利用以下代碼來(lái)聲明有效的接口實(shí)現(xiàn):表示FancyAA類使用INITIALIZE_AG_PASS宏來(lái)注冊(cè)和整合到AliasAnalysis analysis group中噪舀。

      namespace {
        // Declare that we implement the AliasAnalysis interface
        INITIALIZE_AG_PASS(FancyAA, AliasAnalysis , "somefancyaa",
            "A more complex alias analysis implementation",
            false,  // Is CFG Only?
            true,   // Is Analysis?
            false); // Is default Analysis Group implementation?
      }
    

    以下代碼展示如何指定默認(rèn)的實(shí)現(xiàn)(由INITIALIZE_AG_PASS的最后一個(gè)參數(shù)確定)魁淳,一個(gè)Analysis Group必須有一個(gè)默認(rèn)實(shí)現(xiàn)(該默認(rèn)實(shí)現(xiàn)可以從ImmutablePass繼承),例如BasicAliasAnalysis就是該接口的默認(rèn)實(shí)現(xiàn)与倡。

(10)Pass Statistic

介紹:命令行加上-stats選項(xiàng)后界逛,就會(huì)在運(yùn)行的結(jié)尾打印數(shù)據(jù),詳情可參考Programmer's Manual中的Statistics section <Statistic>纺座。

PassManager功能PassManagerclass可以保證很多pass以正確的順序息拜、高效的運(yùn)行。

  • 1.共享分析結(jié)果:避免重復(fù)分析。PassManager可以追蹤所有分析結(jié)果的生存周期少欺,展示哪些分析已經(jīng)已經(jīng)完成并且可用喳瓣。
  • 2.pass流水化執(zhí)行:以高效的使用cache和內(nèi)存。具體來(lái)說(shuō)赞别,給定連續(xù)的FunctionPass畏陕,它將先對(duì)第1個(gè)函數(shù)執(zhí)行所有的FunctionPass,再對(duì)第2個(gè)函數(shù)執(zhí)行所有的FunctionPass仿滔,以此類推惠毁。一次只需計(jì)算1個(gè)DominatorSet,使cache更高效崎页,也有利于進(jìn)一步優(yōu)化鞠绰。

PassManager的有效性取決于開(kāi)發(fā)者提供的信息,也即pass的行為飒焦。例如蜈膨,如果開(kāi)發(fā)者不實(shí)現(xiàn)getAnalysisUsage方法,則該pass無(wú)法被其他pass使用荒给。

PassManager提供--debug-pass命令行選項(xiàng)丈挟,以對(duì)pass執(zhí)行過(guò)程進(jìn)行調(diào)試。如果想知道--debug-pass選項(xiàng)的變體志电,可使用opt -help-hidden命令查看曙咽。可以使用-debug-pass=Structure選項(xiàng)來(lái)查看指定pass如何與其他pass進(jìn)行交互的挑辆,例如:

# Hello World pass之后運(yùn)行g(shù)vn pass例朱、licm pass
$ opt -load lib/LLVMHello.so -gvn -licm --debug-pass=Structure < hello.bc > /dev/null
  ModulePass Manager
    FunctionPass Manager
      Dominator Tree Construction
      Basic Alias Analysis (stateless AA impl)
      Function Alias Analysis Results
      Memory Dependence Analysis
      Global Value Numbering
      Natural Loop Information
      Canonicalize natural loops
      Loop-Closed SSA Form Pass
      Basic Alias Analysis (stateless AA impl)
      Function Alias Analysis Results
      Scalar Evolution Analysis
      Loop Pass Manager
        Loop Invariant Code Motion
      Module Verifier
    Bitcode Writer

以上輸出結(jié)果顯示了pass創(chuàng)建時(shí)間。GVN pass使用了dominator tree信息鱼蝉,LICM pass使用了loop信息(loop信息也使用了dominator tree)洒嗤。LICM pass運(yùn)行完后,自動(dòng)運(yùn)行module verifier魁亦,它會(huì)使用dominator tree來(lái)檢查生成的LLVM code是否正確渔隶。注意:dominator tree只計(jì)算了一次,被3個(gè)pass共享洁奈。

# Hello World pass在gvn pass间唉、licm pass中間運(yùn)行
$ opt -load lib/LLVMHello.so -gvn -hello -licm --debug-pass=Structure < hello.bc > /dev/null
  ModulePass Manager
    FunctionPass Manager
      Dominator Tree Construction
      Basic Alias Analysis (stateless AA impl)
      Function Alias Analysis Results
      Memory Dependence Analysis
      Global Value Numbering
      Hello World Pass
      Dominator Tree Construction
      Natural Loop Information
      Canonicalize natural loops
      Loop-Closed SSA Form Pass
      Basic Alias Analysis (stateless AA impl)
      Function Alias Analysis Results
      Scalar Evolution Analysis
      Loop Pass Manager
        Loop Invariant Code Motion
      Module Verifier
    Bitcode Writer
  Hello: __main
  Hello: puts
  Hello: main

以上輸出結(jié)果顯示Hello World pass 終止了Dominator Tree pass,接下來(lái)的pass會(huì)再次調(diào)用Dominator Tree pass獲取dominator信息利术,為了修復(fù)這個(gè)問(wèn)題呈野,需實(shí)現(xiàn)getAnalysisUsage方法:

  // We don't modify the program, so we preserve all analyses
  void getAnalysisUsage(AnalysisUsage &AU) const override {
    AU.setPreservesAll();
  }
# 修復(fù)成功,dominator信息不會(huì)被計(jì)算兩次
$ opt -load lib/LLVMHello.so -gvn -hello -licm --debug-pass=Structure < hello.bc > /dev/null
  Pass Arguments:  -gvn -hello -licm
  ModulePass Manager
    FunctionPass Manager
      Dominator Tree Construction
      Basic Alias Analysis (stateless AA impl)
      Function Alias Analysis Results
      Memory Dependence Analysis
      Global Value Numbering
      Hello World Pass
      Natural Loop Information
      Canonicalize natural loops
      Loop-Closed SSA Form Pass
      Basic Alias Analysis (stateless AA impl)
      Function Alias Analysis Results
      Scalar Evolution Analysis
      Loop Pass Manager
        Loop Invariant Code Motion
      Module Verifier
    Bitcode Writer
  Hello: __main
  Hello: puts
  Hello: main

releaseMemory方法virtual void releaseMemory();——PassManager自動(dòng)確定何時(shí)開(kāi)始運(yùn)行分析印叁、分析結(jié)果保存多久被冒,如果不再用到了军掂,需要用releaseMemory釋放內(nèi)存。

(11)構(gòu)建pass 插件

LLVM提供了一種機(jī)制昨悼,可以在clang蝗锥、opt、bugpoint內(nèi)自動(dòng)注冊(cè)pass插件率触。首先要?jiǎng)?chuàng)建一個(gè)獨(dú)立的project玛追,添加到tools/,或者使用MonoRepo布局闲延,跟其他project并列痊剖。該project的CMakeLists.txt如下所示:

add_llvm_pass_plugin(Name source0.cpp)

該pass需為新的pass manager提供兩個(gè)入口點(diǎn),一個(gè)用來(lái)靜態(tài)注冊(cè)垒玲,一個(gè)用來(lái)動(dòng)態(tài)加載插件:

  • llvm::PassPluginLibraryInfo get##Name##PluginInfo();
  • extern "C" ::llvm::PassPluginLibraryInfo llvmGetPassPluginInfo() LLVM_ATTRIBUTE_WEAK;

pass插件默認(rèn)是動(dòng)態(tài)編譯和鏈接的陆馁,可以修改LLVM_${NAME}_LINK_INTO_TOOLS變量來(lái)修改,ON表示將該project靜態(tài)鏈接合愈《7罚可使用以下代碼來(lái)加載靜態(tài)鏈接的pass插件:

// fetch the declaration
#define HANDLE_EXTENSION(Ext) llvm::PassPluginLibraryInfo get##Ext##PluginInfo();
#include "llvm/Support/Extension.def"

[...]

// use them, PB is an llvm::PassBuilder instance
#define HANDLE_EXTENSION(Ext) get##Ext##PluginInfo().RegisterPassBuilderCallbacks(PB);
#include "llvm/Support/Extension.def"

(12)注冊(cè)可動(dòng)態(tài)加載的pass

pass注冊(cè)的主要機(jī)制是MachinePassRegistry類和MachinePassRegistryNode的子類。MachinePassRegistry實(shí)例用于保存MachinePassRegistryNode對(duì)象組成的list佛析,并且通過(guò)和命令行接口進(jìn)行通信益老,對(duì)MachinePassRegistryNode對(duì)象進(jìn)行增減。

MachinePassRegistryNode子類用于保存特定pass提供的信息寸莫,信息包含command line name, the command help string和用于創(chuàng)建pass實(shí)例的函數(shù)地址捺萌。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市膘茎,隨后出現(xiàn)的幾起案子桃纯,更是在濱河造成了極大的恐慌,老刑警劉巖披坏,帶你破解...
    沈念sama閱讀 212,080評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件态坦,死亡現(xiàn)場(chǎng)離奇詭異酪刀,居然都是意外死亡赔硫,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,422評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)倔撞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)帚屉,“玉大人谜诫,你說(shuō)我怎么就攤上這事′汤” “怎么了猜绣?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,630評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵灰殴,是天一觀的道長(zhǎng)敬特。 經(jīng)常有香客問(wèn)我掰邢,道長(zhǎng),這世上最難降的妖魔是什么伟阔? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,554評(píng)論 1 284
  • 正文 為了忘掉前任辣之,我火速辦了婚禮,結(jié)果婚禮上皱炉,老公的妹妹穿的比我還像新娘怀估。我一直安慰自己,他們只是感情好合搅,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,662評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布多搀。 她就那樣靜靜地躺著,像睡著了一般灾部。 火紅的嫁衣襯著肌膚如雪康铭。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,856評(píng)論 1 290
  • 那天赌髓,我揣著相機(jī)與錄音从藤,去河邊找鬼。 笑死锁蠕,一個(gè)胖子當(dāng)著我的面吹牛夷野,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播荣倾,決...
    沈念sama閱讀 39,014評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼悯搔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了舌仍?” 一聲冷哼從身側(cè)響起鳖孤,我...
    開(kāi)封第一講書(shū)人閱讀 37,752評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎抡笼,沒(méi)想到半個(gè)月后苏揣,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,212評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡推姻,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,541評(píng)論 2 327
  • 正文 我和宋清朗相戀三年平匈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片藏古。...
    茶點(diǎn)故事閱讀 38,687評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡增炭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拧晕,到底是詐尸還是另有隱情隙姿,我是刑警寧澤,帶...
    沈念sama閱讀 34,347評(píng)論 4 331
  • 正文 年R本政府宣布厂捞,位于F島的核電站输玷,受9級(jí)特大地震影響队丝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜欲鹏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,973評(píng)論 3 315
  • 文/蒙蒙 一机久、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧赔嚎,春花似錦膘盖、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,777評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至损晤,卻和暖如春践图,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背沉馆。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,006評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工码党, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人斥黑。 一個(gè)月前我還...
    沈念sama閱讀 46,406評(píng)論 2 360
  • 正文 我出身青樓揖盘,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親锌奴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子兽狭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,576評(píng)論 2 349