指令選擇¶
此階段將泛型機器指令轉換為等效的目標特定指令。它以由下而上的方式遍歷 MachineFunction
,在定義之前選擇使用,從而實現簡單的死碼消除。
API:指令選擇器¶
目標實現了 InstructionSelector
類別,其中包含目標特定的選擇邏輯。
實例由子目標提供,以便它可以通過子目標功能專門化選擇器(例如,向量選擇器覆蓋通用選擇器的一部分)。我們可能還希望通過 MachineFunction 對其進行參數化,以根據 optsize 等函數屬性啟用選擇器變體。
簡單的 API 包含
virtual bool select(MachineInstr &MI)
這個由目標提供的函數負責將一個可能是泛型的 MI 變異(或替換)為完全目標特定的等效項。它還負責將 gvregs 約束到適當的寄存器類別中,並通過 COPY 指令傳遞給寄存器分配器。
InstructionSelector
可以通過遍歷 vreg 運算元的使用-定義鏈,將其他指令摺疊到所選的 MI 中。由於 GlobalISel 是全域的,因此這種摺疊可以跨基本塊進行。
SelectionDAG 規則匯入¶
TableGen 將匯入 SelectionDAG 規則並提供以下函數來執行它們
bool selectImpl(MachineInstr &MI)
--stats
選項可用於確定成功匯入的規則的比例。使用它的最簡單方法是從 ninja -v
複製 -gen-globalisel
tablegen 命令並修改它。
類似地,--warn-on-skipped-patterns
選項可用於獲取規則未被匯入的原因。這可以用於關注最重要的拒絕原因。
PatLeaf 謂詞¶
無法匯入 PatLeafs,因為它們的 C++ 是根據 SDNode
物件實現的。處理立即數謂詞的 PatLeafs 應根據需要替換為 ImmLeaf
、IntImmLeaf
或 FPImmLeaf
。
其他 PatLeafs 沒有標準答案。一些標準謂詞已被烘焙到 TableGen 中,但通常不應該這樣做。
自定義 SDNodes¶
自定義 SDNodes 應使用 GINodeEquiv
映射到目標虛擬指令 (Target Pseudo)。這將導致指令選擇器導入它們,但您還需要確保在指令選擇器之前將目標虛擬指令引入 MIR。任何前面的過程都適用,但合法化器 (legalizer) 將是一個特別常見的選擇。
複雜模式 (ComplexPatterns)¶
複雜模式無法導入,因為它們的 C++ 是根據 SDNode
物件實現的。GlobalISel 版本應該使用 GIComplexOperandMatcher
定義,並使用 GIComplexPatternEquiv
映射到 ComplexPattern。
以下謂詞對於移植 ComplexPattern 很有用
isBaseWithConstantOffset() - 檢查 base+offset 結構
isOperandImmEqual() - 檢查特定的常數
isObviouslySafeToFold() - 檢查指令無法被 sink 並折疊到另一個指令中的原因。
C++ 實現有一些重點
不要在謂詞中修改 MIR
渲染器 lambda 應該透過值捕獲以避免使用已釋放的記憶體。它們將在謂詞返回後使用。
僅在渲染器 lambda 中建立指令。GlobalISel 不會清除您建立但未使用的事物。