LLVM筆記(9) - 指令選擇(一) 概述


本文最初是基於對新員工培訓, 使其快速上手編譯器后端代碼而寫的入門簡介. 為方便閱讀又根據模塊細分為若干章, 內容以分析代碼為主, 偶爾也會穿插一些理論擴展.

什么是指令選擇

指令選擇(instruction selection)是將中間語言轉換成匯編或機器代碼的過程. 如果僅為單一語言在單一目標上實現指令選擇, 可以使用手工編碼的方法. 否則通過使用自動代碼生成器生成代碼, 編譯器開發人員只需負責修改不同目標的機器指令描述, 是更優選擇.

指令選擇需要考慮的問題

  1. 目標的寄存器, 尋址方式和指令體系結構
    目標的指令集與體系結構會影響指令選擇的方式. e.g. 在X86上給一個寄存器賦值32bit立即數地址只需要mov一條指令, 但像ARM與RISCV等架構只支持12bit的立即數加法, 需要更加復雜的方式實現同樣的移動語義. 根據codesize model的設置, RISCV可以使用lui + addi兩條指令實現(分別移動高20bit與低12bit), 或將地址保存到當前指令地址附近然后用addi + lw兩條指令實現(計算常量所在地址並訪問該地址).
  2. 軟件調用約定(calling convention)
    指令選擇必須考慮兼顧目標的ABI定義.
  3. 中間語言的結構和特征
    本質上中間語言對生成的代碼的正確性沒有影響, 然而中間語言的結構影響對自動代碼生成算法的設計.
  4. 轉化為機器代碼的方式
    略.

常見的指令選擇實現

常見的指令選擇實現可以參見經典書籍Survey on Instruction Selection(這塊內容以后有空單獨再介紹).

  1. 宏展開(macro expension)
  2. 樹覆蓋(tree covering)
  3. 有向圖覆蓋(DAG covering)

LLVM當前的指令選擇實現

LLVM在O0編譯時使用名為FastISel的指令選擇PASS, 在O2編譯時使用名為SelectionDAG的指令選擇PASS, 同時當前社區還在推進名為GlobalISel的指令選擇PASS(當前僅在AArch64上支持), 希望能替代SelectionDAG. 我們將首先介紹SelectionDAG(如未特殊說明, 下文介紹均默認為SelectionDAG), 然后會簡要介紹FastISel與GlobalISel, 並比較三者特點, 討論為什么要使用GlobalISel替換SelectionDAG.

什么是SelectionDAG

SelectionDAG是一種trees-on-DAGs的有向圖覆蓋實現, 編譯器開發人員通過編寫指令的樹匹配(tree pattern), 通過tablgen翻譯成完整的樹匹配代碼交由代碼生成器(matcher generator)處理, 后者采用貪婪的DAG-to-DAG策略將中端IR覆寫為機器指令描述.

SelectionDAG流程簡介

SelectionDAG由若干個優化組合而成, 其具體流程圖如下所示, 其中紅色節點表示數據(輸入的中間語言)的組成形式, 黑色節點表示處理模塊.

我們會依據SelectionDAG的流程依次分析每個步驟的目標, 實現方式以及在支持一個新架構時需要修改的注意點, 這里先簡要介紹各個模塊的作用:

  1. 上文提到SelectionDAG是基於DAG covering的指令選擇實現, 因此需要首先將輸入程序流的表示方式從IR轉換為DAG, 該過程又被稱做lowering. lowering會將IR節點一一的翻譯為DAG節點的同時也會處理調用約定, 使其遵守特定目標的ABI規范(這也是lowering名字的含義). 在lowering后程序流是以名為SDNode的節點組成的DAG.
  2. 根據特定目標所支持的指令集與寄存器結構, SelectionDAG將目標不支持的操作與數據類型轉換為合法的操作與數據類型, 這一步被稱作legalize. 另一方面對於其中產生的可以合並的操作被稱作combine. 可以看到legalize與combine執行了多次, 且legalize每次執行的內容都不一樣.
  3. 在combine和legalize之后是select步驟, 通過pattern match或手寫代碼的方式生成對應指令. 經過指令選擇后的程序流是以Machine Instruction為節點組成的DAG.
  4. 在早期的SelectionDAG實現里還考慮的了調度的優化, 然而現在LLVM已經支持了PreRA與PostRA的調度, 在此處調度優化並不重要, 本文暫不涉及, 關於調度的實現將在以后調度器實現分析中介紹.
  5. 指令選擇(步驟3)只是選出了對應的指令, 還需要將其重新覆寫為基於SSA格式的Machine Instruction描述, 為每條指令分配虛擬寄存器, 連接PHI節點.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM