算子规范化
算子規范化
規范化是編譯器IR設計的重要組成部分:它使實現可靠的編譯器轉換和確定代碼中優劣的原因變得更加容易,并且使有關IR特定級別的目標的討論變得更加有趣。丹·高曼(Dan Gohman)寫了一篇文章 探討這些問題。如果不熟悉這些概念,則值得閱讀。
大多數編譯器都有規范化的遍歷,有時它們有很多不同的遍歷(例如LLVM中的instcombine,dag Combine等)。因為MLIR是一個多級IR,所以可以提供一個規范的基礎架構,并在它代表的許多不同IR中重用它。本文介紹了通用方法,執行全局規范化,并提供了一些內容,以捕獲特定于IR的規則以供參考。
總體設計
MLIR具有一次規范化遍歷,它以貪婪的方式迭代地應用規范化轉換,直到IR收斂為止。這些轉換由算子本身定義,允許每個語言一起定義自己的一組算子和規范化。
關于wrt規范化模式的一些重要事項:
? 模式的重復應用應收斂。不穩定或周期性的重寫將導致規范化器中的無限循環。
? 通常對重復算子時規范化,最好使用較少值的算子,因為某些模式僅在值具有單個用戶時才匹配。例如,通常最好將“ x + x”規范化為“ x * 2”,因為這樣可以將x的使用次數減少一半。
? 在可能的情況下,最好完全消除算子,例如折疊已知身份(例如“ x + 0 = x”),這總是好事。
在全局范圍內適用的規則
這些轉換適用于所有級別的IR:
? 消除無副作用,無用的算子。
? 不斷折疊-例如,“(addi 1,2)”到“ 3”。固定折疊鉤由算子指定。
? 將常量算子移動到可交換運算符的右側-例如,將“(addi 4,x)”移動到“(addi x,4)”。
? constant-like算子是唯一的,并被提升到第一父屏障區域的入口塊中。這是一個與上方隔離的區域,例如功能的輸入框,或者是通過shouldMaterializeInto方法標記為障礙的區域DialectFoldInterface。
定義Canonicalizations
有兩種定義規范的機制。 getCanonicalizationPatterns和fold。
用getCanonicalizationPatterns規范化
這種機制允許以RewritePatterns的形式提供規范化,這些規范化是 在C ++中強制性定義的,或者是聲明性地稱為 “聲明性重寫規則” 。模式重寫基礎結構允許表達許多不同類型的規范化。這些轉換可能很簡單,例如用移位替換乘法,甚至用無條件分支替換條件分支。
在 ODS中 ,算子可以設置該hasCanonicalizer位,生成getCanonicalizationPatterns方法的聲明。
def MyOp : … {
let hasCanonicalizer = 1;
}
然后可以在源文件中提供規范化模式:
void MyOp::getCanonicalizationPatterns(OwningRewritePatternList &patterns,
MLIRContext *context) {
patterns.insert<…>(…);
}
有關 定義算子重寫的信息,請參見 快速入門指南。
用規范化fold
該fold機制是有意限制的,但是功能強大的機制允許在整個編譯器的許多位置應用規范化。例如,canonicalizer pass外部,fold在所述內使用 語言轉換基礎結構 作為合法化機制,并且可以經由 OpBuilder::createOrFold用在任何地方直接調用OpBuilder。
fold具有不能創建任何新算子的限制,并且只能替換根算子。它允許就地更新算子,或返回一組預先存在的值(或屬性)來替換算子。這樣可以確保該fold方法是真正的“本地”轉換,并且可以在不需要模式重寫器的情況下調用該方法。
在 ODS中 ,算子可以設置該hasFolder位以生成fold方法的聲明。此方法采用不同的形式,具體取決于算子的結構。
def MyOp : … {
let hasFolder = 1;
}
如果算子只有一個結果,則將生成以下內容:
/// Implementations of this hook can only perform the following changes to the
/// operation:
///
/// 1. They can leave the operation alone and without changing the IR, and
/// return nullptr.
/// 2. They can mutate the operation in place, without changing anything else
/// in the IR. In this case, return the operation itself.
/// 3. They can return an existing value or attribute that can be used instead
/// of the operation. The caller will remove the operation and use that
/// result instead.
///
OpFoldResult MyOp::fold(ArrayRef operands) {
…
}
否則,將生成以下內容:
/// Implementations of this hook can only perform the following changes to the
/// operation:
///
/// 1. They can leave the operation alone and without changing the IR, and
/// return failure.
/// 2. They can mutate the operation in place, without changing anything else
/// in the IR. In this case, return success.
/// 3. They can return a list of existing values or attribute that can be used
/// instead of the operation. In this case, fill in the results list and
/// return success. The results list must correspond 1-1 with the results of
/// the operation, partial folding is not supported. The caller will remove
/// the operation and use those results instead.
///
LogicalResult MyOp::fold(ArrayRef operands,
SmallVectorImpl &results) {
…
}
在上面,為每種方法ArrayRef提供了一個與每個算子的常量屬性值相對應的。這些算子是實現ConstantLike特征的算子。如果任何一個算子不是常數,則將Attribute提供一個空值。例如,如果提供MYOP三個算子[ a,b,c],但只b是常量,那么operands將是以下形式的[屬性(),b值,屬性()]。
同樣在上面,使用OpFoldResult。此類表示折疊算子結果的可能結果:SSAValue或 Attribute(對于恒定結果)。如果Value提供了SSA ,則它必須 對應于現有值。該fold方法不允許生成new Value。Attribute返回值的形式沒有具體限制 ,但重要的是要確保Attribute 具體表示形式的Type一致性。
當fold算子上的鉤子算子不成功時,語言可以通過實現DialectFoldInterface和覆蓋折疊鉤子來提供后備功能。
從屬性生成常數
當一個fold方法返回aAttribute作為結果時,表示該結果是“常量”。Attribute是該值的常數表示。該fold方法的用戶(例如規范化過程)將采用這些Attributes,并在IR中實現常量算子來表示。為了實現這種實現,算子的語言必須實現materializeConstant鉤子。該鉤子接受一個Attribute 通常由返回的值,fold并產生實現該值的“類似常數”的算子。
在 ODS中 ,語言可以將hasConstantMaterializer位設置為生成materializeConstant方法的聲明。
def MyDialect_Dialect : … {
let hasConstantMaterializer = 1;
}
然后可以在源文件中實現常量:
/// Hook to materialize a single constant operation from a given attribute value
/// with the desired resultant type. This method should use the provided builder
/// to create the operation without changing the insertion position. The
/// generated operation is expected to be constant-like. On success, this hook
/// should return the value generated to represent the constant value.
/// Otherwise, it should return nullptr on failure.
Operation *MyDialect::materializeConstant(OpBuilder &builder, Attribute value,
Type type, Location loc) {
…
}
總結
- 上一篇: Pass Infrastructure基
- 下一篇: Pass Infrastructure基