IRTranslator

此階段將輸入的 LLVM-IR Function 轉譯為 通用機器碼 IR MachineFunction。這通常是直接轉譯,但偶爾會變得更複雜。例如

%2 = add i32 %0, %1

變成

%2:_(s32) = G_ADD %0:_(s32), %1:_(s32)

call i32 @puts(i8* %cast210)

則根據目標的 ABI 規則進行轉譯。

注意

目前實作的 LLVM 語言參考手冊 部分足以進行許多編譯,但並非 100% 完整。想要編譯包含一些較罕見功能的 LLVM-IR 的使用者可能需要實作轉譯。

目標內建函式

關於是否要為轉譯目標內建函式添加目標鉤子,已經有一些(非公開)的爭論。在參與討論的人中,普遍同意 IRTranslator 應該能夠以可自訂的方式降低目標內建函式,但在撰寫本文時,尚未進行任何實作。

轉譯函式呼叫

IRTranslator 還通過將呼叫、返回和參數降低到適當的物理寄存器使用和指令序列來實現 ABI 的呼叫約定。這是通過使用 CallLowering 介面實現的,該介面提供了一些目標應該實作的鉤子:lowerFormalArgumentslowerReturnlowerCall 等。

本質上,所有這些鉤子都需要找到一種方法,將參數/返回值在函式其餘部分使用的虛擬寄存器和 ABI 規定的物理寄存器或堆疊之間移動。這可能涉及將大型類型拆分為較小的類型、引入符號/零擴展等。為了在不同後端之間儘可能多地共用這些代碼,CallLowering 提供了一些輔助工具和介面

  • ArgInfo - 用於形式參數,但也用於返回值、實際參數和呼叫結果;包含 IR 類型、虛擬寄存器等資訊;大型值可能必須拆分為多個 ArgInfo 物件(CallLowering::splitToValueTypes 可以幫助完成此操作);

  • ValueAssigner」- 使用一個 CCAssignFn(通常由 TableGen 產生,請參閱呼叫慣例)來決定放置每個 ArgInfo(實體暫存器或堆疊)的位置;後端可以使用提供的 IncomingValueAssigner(用於形式參數和呼叫結果)和 OutgoingValueAssigner(用於實際參數和函式回傳值),但也可以將它們子類化;

  • ValueHandler」- 插入必要的指令,將每個值放到它應該在的位置;它具有用於將值賦值給暫存器或地址的純虛擬方法,以及許多其他輔助方法;

  • determineAndHandleAssignments」(或用於更精細的控制,determineAssignmentshandleAssignments)- 包含一些樣板程式碼,用於在一系列 ArgInfo 物件上叫用給定的 ValueAssignerValueHandler

聚合

注意

這一點自撰寫以來已有所變更,不再準確。在這次改進文件時,它沒有被更新,因為我沒有在程式碼庫的這個部分做太多工作,應該由更了解它的人來處理。

聚合被降低為多個虛擬暫存器,類似於 SelectionDAG 通過 GetValueVTs 的多個虛擬暫存器。

TODO:由於某些位是未定義的(填補),我們應該考慮使用額外的中繼資料來擴充表示(實際上是在虛擬暫存器上快取 computeKnownBits 資訊)。請參閱PR26161:[GlobalISel] 在 IR 到 MachineInstr 轉換過程中,聚合類型的值到虛擬暫存器

常數轉換

常數運算元被轉換為使用由 G_CONSTANTG_FCONSTANT 指令定義的虛擬暫存器。這些指令被放置在入口區塊中,以便它們可以受到連續 CSE 實作(CSEMIRBuilder)的影響。它們的除錯位置資訊被移除,以防止這混淆除錯器。

這樣做的好處是,它允許我們在指令選擇期間將常數摺疊到立即運算元中,同時仍然避免為昂貴的不可摺疊常數產生冗餘的實體化。但是,這可能會導致 -O0 管線中出現不必要的溢出和重新載入,因為這些虛擬暫存器可能具有很長的存活期。這可以通過在轉換器之後執行本地化器來減輕。