Pass Infrastructure基础架构(上)
Pass Infrastructure基礎架構(上)
Operation
Pass
- OperationPass
- Op-Specific
OperationPass - Op-Agnostic
Dependent
Dialects
Analysis
Management
Querying
Analyses
Preserving
Analyses
Pass
Failure
Pass
Manager
OpPassManager
Dynamic
Pass Pipelines
Instance
Specific Pass Options
Pass
Statistics
Pass
Registration
Pass
Pipeline Registration
Textual
Pass Pipeline Specification
Declarative
Pass Specification
Tablegen
Specification
Pass
Instrumentation
Standard
Instrumentations
Crash and
Failure Reproduction
Local
Reproducer Generation
pass代表了轉換和優化的基本基礎架構。本文檔概述了MLIR中的pass基礎結構以及如何使用它。
有關MLIR?及其核心方面(如IR結構和算子)的更多信息,請參見?MLIR規范。
有關?在MLIR中進行圖形重寫的快速入門,請參見?MLIR?Rewrites。如果轉換涉及模式匹配算子DAG,那么這是一個很好的起點。
算子pass
在MLIR中,抽象和轉換的主要單元是一個?運算?。這樣,pass管理器被設計為處理不同嵌套級別的算子實例。pass通行管理器的結構?和嵌套的概念將在下面詳細介紹。MLIR中的所有pass均源自OperationPass,并遵守以下限制;在多線程和其它高級方案中,任何不符合都會導致有問題的行為:
修改正在算子的當前之外引用或依賴的任何狀態。這包括在父塊中添加或刪除算子,更改屬性(取決于當前算子的規定)/當前算子數/結果/后繼對象。
修改另一個未嵌套在當前算子的狀態。
其它線程可能同時在這些算子上運行。
檢查同級算子的狀態。
其它線程可能正在并行修改這些算子。
允許檢查祖先/父項算子的狀態。
步長調用pass狀態runOnOperation保持可變的。傳遞可能在許多不同的算子上運行,而不能保證執行順序。
在進行多線程處理時,特定的傳遞實例甚至可能不會在IR內的所有算子上執行。因此,傳遞不應該依賴于所有算子上的運行。
保持任何全局可變狀態,例如源文件中的靜態變量。所有可變狀態都應pass傳遞實例來維護。
必須是可復制的
流程管理器可以創建流程的多個實例,以并行處理算子。
創建算子傳遞時,根據使用情況,有兩種不同的類型可供選擇:
OperationPass:特定于算子
在op-specific算子上傳遞給定算子類型明確的算子。此算子類型必須遵守pass管理器設置的限制,以執行pass。
要定義特定于算子通道,派生類必須遵守以下規定:
從CRTP類繼承,OperationPass并提供算子類型作為附加模板參數。
覆蓋void
runOnOperation()虛擬方法。
一個簡單的過程可能看起來像:
namespace {
/// Here
we utilize the CRTP PassWrapper utility class to provide some
///
necessary utility hooks. This is only necessary for passes defined directly
/// in
C++. Passes defined declaratively use a cleaner mechanism for providing
/// these
utilities.
struct MyFunctionPass : public PassWrapper<OperationPass,
MyFunctionPass> {
void runOnOperation() override {
// Get the
current FuncOp operation being operated on.
FuncOp f =
getOperation();
// Walk
the operations within the function.
f.walk([](Operation *inst) {
…
});
}
};
} // end anonymous namespace
///
Register this pass so that it can be built via from a textual pass pipeline.
/// (Pass
registration is discussed more below)
void registerMyPass() {
PassRegistration(
“flag-name-to-invoke-pass-via-mlir-opt”, “Pass
description here”);
}
OperationPass:不可知
op-agnostic pass,添加到通管理器的算子類型進行運算。這意味著這種類型的pass通道可以在幾種不同的算子類型上進行運算。通常使用算子接口?和?特征來存儲此類pass?。此類pass傳遞的示例包括“?常見子表達式消除”?和“?內聯”?。
要創建算子pass傳遞,派生類必須遵守以下規定:
從CRTP類繼承OperationPass。
覆蓋虛擬void
runOnOperation()方法。
一個簡單的過程可能看起來像:
/// Here
we utilize the CRTP PassWrapper utility class to provide some
///
necessary utility hooks. This is only necessary for passes defined directly
/// in
C++. Passes defined declaratively use a cleaner mechanism for providing
/// these
utilities.
struct MyOperationPass : public PassWrapper<OperationPass<>, MyOperationPass> {
void runOnOperation() override {
// Get the
current operation being operated on.
Operation *op =
getOperation();
…
}
};
從屬語言
必須先在MLIRContext中加載語言,然后才能從這些語言創建實體(算子,類型,屬性等)。在開始執行多線程傳遞管道之前,還必須加載語言。為此,可能無法保證已從其加載的語言創建實體的過程,必須pass重寫getDependentDialects()?方法并明確聲明此語言列表來表達。
分析管理
一個重要的概念,以及轉換過程,都是分析。這些在概念上與轉換過程相似,不同之處在于不修改特定算子的情況下計算信息。在MLIR中,分析不是pass而是pass獨立式類,這些類是按需延遲計算并緩存的,以避免不必要的重新計算。MLIR中的分析必須遵循以下條件:
提供一個采用Operation*的有效構造函數。
不得修改給定的算子。
分析可能會提供其它鉤子來控制各種行為:
bool isInvalidated(const
AnalysisManager::PreservedAnalyses &)
給定一個保留的分析集,如果該分析確實無效,則該分析返回true。如果沒有明確標記保留分析,但可以根據其它屬性(例如分析集)保留(或使之無效),則可以進行更精細的失效。
查詢分析
基OperationPass類提供用于查詢和保留當前正在處理的算子的分析的實用程序。
OperationPass自動提供以下實用程序來查詢分析:
getAnalysis<>
獲得當前算子的分析,并在必要時進行構建。
getCachedAnalysis<>
獲取當前算子的分析(如果已經存在)。
getCachedParentAnalysis<>
獲取給定父算子的分析(如果存在)。
getCachedChildAnalysis<>
對給定的子算子(如果存在)進行分析。
getChildAnalysis<>
對給定的子算子進行分析,并在必要時進行構造。
使用上面定義的示例pass傳遞,看一些示例:
/// An
interesting analysis.
struct MyOperationAnalysis {
// Compute
this analysis with the provided operation.
MyOperationAnalysis(Operation *op);
};
void MyOperationPass::runOnOperation()
{
// Query
MyOperationAnalysis for the current operation.
MyOperationAnalysis &myAnalysis =
getAnalysis();
// Query a
cached instance of MyOperationAnalysis for the current operation.
// It will
not be computed if it doesn’t exist.
auto optionalAnalysis =
getCachedAnalysis();
if (optionalAnalysis)
…
// Query a
cached instance of MyOperationAnalysis for the parent operation of
// the
current operation. It will not be computed if it doesn’t exist.
auto optionalAnalysis =
getCachedParentAnalysis();
if (optionalAnalysis)
…
}
保存分析
在pass查詢后構造的分析將被緩存,以避免不必要的計算(如果稍后再次請求)。為避免過時的分析,假定所有分析均pass傳遞而無效。為避免無效,過程必須專門標記已知保留的分析。
所有Pass類都會自動提供以下用于保留分析的實用程序:
markAllAnalysesPreserved
markAnalysesPreserved<>
void MyOperationPass::runOnOperation()
{
// Mark
all analyses as preserved. This is useful if a pass can guarantee
// that no
transformation was performed.
markAllAnalysesPreserved();
// Mark
specific analyses as preserved. This is used if some transformation
// was
performed, but some analyses were either unaffected or explicitly
//
preserved.
markAnalysesPreserved<MyAnalysis,
MyAnalyses…>();
}
pass失敗
允許MLIR中的傳遞正常失敗。如果pass的某些不變性被破壞,可能會使IR處于某種無效狀態,則可能發生這種情況。如果發生這種情況,signalPassFailure方法直接向pass管理器發出故障信號。如果pass指示執行時失敗,則管道中不會執行其它任何傳遞,并且頂級調用PassManager::run將返回failure。
void MyOperationPass::runOnOperation()
{
// Signal
failure on a broken invariant.
if (some_broken_invariant)
return signalPassFailure();
}
pass管理器
以上各節介紹了pass的不同類型及其不變性。本節介紹PassManager的概念,以及如何將其用于配置和計劃pass管道。與pass管理相關的主要類別有兩個,PassManager和和OpPassManager。?PassManager類作為頂層的入口點,并包含用于整個管道的各種配置。OpPassManager用于調度類會將以嵌套的一個特定的水平上運行。頂級?PassManager還用作OpPassManager。
OpPassManager
AnOpPassManager本質上是要在特定類型的算子上執行的過程的集合。此算子類型必須符合以下要求:
必須注冊并標記?IsolatedFromAbove?。
預期傳遞不會修改正在處理的當前算子或更高的算子。如果算子不是孤立的,則可能會無意間修改或遍歷不應該執行的算子的SSA使用列表。
將pass添加到pass管理器addPass。該pass必須是采用?op-specific與相同算子類型OpPassManager的op-agnosticpass,或者是pass。
一個OpPassManager通常被cretedOpPassManagerpassnest<>方法明確嵌套內其它現有管道。此方法采用嵌套通行管理器將要算子的算子類型。在頂層,a?PassManager充當OpPassManager。從這個意義上講,嵌套對應?于?IR區域內的?結構嵌套?。
例如,以下content.mlir:
module {
spv.module “Logical”
“GLSL450” {
func @foo() {
…
}
}
}
具有以下嵌套結構:
module
spv.module
function
下面是構造在上述結構上運行的管道的示例:
// Create
a top-level PassManager class. If an operation type is not
//
explicitly specific, the default is the builtin module operation.
PassManager
pm(ctx);
// Note:
We could also create the above PassManager this way.
PassManager
pm(ctx, /operationName=/“module”);
// Add a
pass on the top-level module operation.
pm.addPass(std::make_unique());
// Nest a
pass manager that operates on spirv.module operations nested
//
directly under the top-level module.
OpPassManager
&nestedModulePM = pm.nestspirv::ModuleOp();
nestedModulePM.addPass(std::make_unique());
// Nest a
pass manager that operates on functions within the nested SPIRV
// module.
OpPassManager
&nestedFunctionPM =
nestedModulePM.nest();
nestedFunctionPM.addPass(std::make_unique());
// Run the
pass manager on the top-level module.
ModuleOp m
= …;
if (failed(pm.run(m)))
… // One of the passes signaled a failure.
上面的過程管理器包含以下管道結構:
OpPassManager
MyModulePass
OpPassManagerspirv::ModuleOp
MySPIRVModulePass
OpPassManager
MyFunctionPass
然后,這些管道一次運行一次。這意味著,例如,給定FuncOp上的一系列連續傳遞,它將在第一個函數上全部執行,然后在第二個函數上全部執行,依此類推,直到整個程序都pass傳遞為止。這提供了幾個好處:
這改善了編譯器的緩存行為,因為它一次只連接一個功能函數,而不遍歷整個程序。
pass減少需要調度的作業數量以及提高每個作業的效率,這提高了多線程性能。整個函數管道可以在每個函數上異步運行。
動態pass管道
在某些情況下,在另一個遍歷中運行一個遍歷管道可能是有用的,以允許基于正在運行的當前算子的某些不變性進行配置或過濾。例如,?Inliner Pass?可能希望在進行內聯時,運行過程內pass簡化,以產生更好的成本模型,并提供更好的內聯。為了實現這一點,pass過程可以OpPassManagerpassLogicalResult Pass::runPipeline(OpPassManager &,
Operation *)方法對正在執行的當前算子或嵌套在當前算子內的任何算子進行任意運算。與頂級PassManager::run方法的結果類似,此方法返回動態管道是成功還是失敗。下面是一個簡單的示例:
void MyModulePass::runOnOperation()
{
ModuleOp module =
getOperation();
if (hasSomeSpecificProperty(module)) {
OpPassManager dynamicPM(“module”);
…; // Build the dynamic pipeline.
if (failed(runPipeline(dynamicPM, module)))
return signalPassFailure();
}
}
注意:盡管上面在runOnOperation方法中構造了動態管道?,但這不是必需的,并且應盡可能緩存管道,因為OpPassManager可以安全地復制該類。
每當pass管道以嵌套方式運行時,即當無法與主傳遞管道的其余部分一起靜態調度嵌套管道時,都應使用本節中描述的機制。更具體地說,PassManager通常不應在內構造a?Pass。使用runPipeline還可以確保將所有分析,?設備?和其它與過程管理器相關的組件與正在執行的動態管道集成在一起。
實例特定的pass選項
MLIR提供了一種內置的機制,用于指定配置其行為的選項。這些選項在遍歷構造時針對遍歷的每個實例獨立地進行解析。使用Option<>和?ListOption<>類定義選項,并遵循?LLVM命令行?標志定義規則。參見以下示例:
struct MyPass … {
/// Make
sure that we have a valid default constructor and copy constructor to
/// ensure
that the options are initialized properly.
MyPass() = default;
MyPass(const MyPass& pass) {}
/// Any
parameters after the description are forwarded to llvm:🆑:list and
///
llvm:🆑:opt respectively.
Option
exampleOption{*this, “flag-name”, llvm:🆑:desc("…")};
ListOption
exampleListOption{*this, “list-flag-name”,
llvm:🆑:desc("…")};
};
對于pass管道,PassPipelineRegistration模板采用其它模板參數作為可選的Option結構定義。該結構應繼承mlir::PassPipelineOptions并包含所需的管道選項。使用PassPipelineRegistration時,構造函數現在使用帶有簽名的函數,該函數void (OpPassManager &pm, const
MyPipelineOptions&)?應構造來自選項的傳遞,并將其傳遞給pm:
struct MyPipelineOptions : public PassPipelineOptions {
// The
structure of these options is the same as those for pass options.
Option
exampleOption{*this, “flag-name”, llvm:🆑:desc("…")};
ListOption
exampleListOption{*this, “list-flag-name”,
llvm:🆑:desc("…")};
};
void registerMyPasses() {
PassPipelineRegistration(
“example-pipeline”, “Run
an example pipeline.”,
[](OpPassManager &pm, const MyPipelineOptions &pipelineOptions) {
//
Initialize the pass manager.
});
}
傳遞統計信息
統計信息是跟蹤編譯器正在執行的算子以及各種轉換的有效性的一種方式。通常,查看特定轉換對特定輸入有什么影響以及觸發頻率有多有用。傳遞統計信息特定于每個傳遞實例,從而可以查看在傳遞管道內特定位置放置特定轉換的效果。例如,幫助回答諸如“如果我再次在這里運行CSE會怎樣?”之類的問題。
可以使用’Pass :: Statistic’類將統計信息添加到過程中。此類采用構造函數自變量:父傳遞,名稱和描述。此類的作用類似于算子無符號整數,并且可以相應地增加和更新。這些統計信息依賴于相同的基礎結構?llvm::Statistic?,因此具有相似的使用約束。收集的統計信息可以pass管理器以?編程方式pass?轉儲?PassManager::enableStatistics;或pass-pass-statistics和?-pass-statistics-display在命令行上。
一個例子如下所示:
struct MyPass … {
/// Make
sure that we have a valid default constructor and copy constructor to
/// ensure
that the options are initialized properly.
MyPass() = default;
MyPass(const MyPass& pass) {}
/// Define
the statistic to track during the execution of MyPass.
Statistic exampleStat{this, “exampleStat”, “An
example statistic”};
void runOnOperation() {
…
// Update
the statistic after some invariant was hit.
++exampleStat;
…
}
};
收集的統計信息可以匯總為兩種類型的視圖:
管道視圖,模擬了pass管理器的結構,這是默認視圖:
$ mlir-opt
-pass-pipeline=‘func(my-pass,my-pass)’ foo.mlir -pass-statistics
=-------------------------------------------------------------------------=
… Pass statistics
report …
=-------------------------------------------------------------------------=
‘func’ Pipeline
MyPass
(S) 15 exampleStat - An example statistic
VerifierPass
MyPass
(S)? 6
exampleStat - An example statistic
VerifierPass
VerifierPass
列表視圖匯總了特定遍歷所有實例的統計信息:
$ mlir-opt
-pass-pipeline=‘func(my-pass, my-pass)’ foo.mlir -pass-statistics
-pass-statistics-display=list
=-------------------------------------------------------------------------=
… Pass statistics
report …
=-------------------------------------------------------------------------=
MyPass
(S) 21 exampleStat - An example statistic
總結
以上是生活随笔為你收集整理的Pass Infrastructure基础架构(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 多级中间表示概述MLIR
- 下一篇: 算子规范化