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ì)malloc
和free
函數(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)Function
或Module
級(jí)分析信息弃锐。 -
runOnLoop
:完成pass的主要工作,即代碼轉(zhuǎn)換或分析殿托。 doFinalization()
(6)RegionPass
和LoopPass
類似霹菊,但只處理函數(shù)中單入口單退出的區(qū)域。
需重寫(xiě)的函數(shù):
-
doInitialization(Region *, RGPassManager &)
:可以使用LPPassManager
接口來(lái)訪問(wèn)Function
或Module
級(jí)分析信息支竹。 runOnRegion
doFinalization()
(7)MachineFunctionPass類
是LLVM code generator的一部分旋廷,依賴機(jī)器類型鸠按。Code generator passes采用TargetMachine::addPassesToEmitFile
來(lái)注冊(cè)和初始化,所以不能通過(guò)opt
或bugpoint
命令來(lái)運(yùn)行饶碘。MachineFunctionPass
也屬于FunctionPass
目尖,所以和FunctionPass
的限制一樣,此外MachineFunctionPass
還不能修改和創(chuàng)建 LLVM IR Instruction
扎运、BasicBlock
瑟曲、Argument
、Function
绪囱、GlobalVariable
测蹲、GlobalAlias
、Module
鬼吵,只能修改當(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。-
getAnalysisUsage
:virtual void getAnalysisUsage(AnalysisUsage &Info) const;
實(shí)現(xiàn)時(shí)需用
required
和invalidated
pass填充AnalysisUsage對(duì)象累奈,通過(guò)以下函數(shù)來(lái)實(shí)現(xiàn):-
AnalysisUsage::addRequired<>
&AnalysisUsage::addRequiredTransitive<>
:定義必須在本pass之前執(zhí)行的pass贬派,如DominatorSet
、BreakCriticalEdges
澎媒。有些分析需要和其他分析一起才能正常工作搞乏,如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酸茴。
-
RegisterAnalysisGroup
:RegisterAnalysisGroup
用于注冊(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功能:PassManager的class可以保證很多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ù)地址捺萌。