RegisterInfo.td中RegisterClass的使用和定義
在 LLVM TableGen 中,RegisterClass 是用于定義寄存器類的基本類,其通用語法為:
def ClassName : RegisterClass<"Namespace", [ValueType], Size, RegisterList> {
// 可選屬性
let Property1 = Value1;
let Property2 = Value2;
// ...
}
- "Namespace": 寄存器類的命名空間,通常是目標(biāo)架構(gòu)名稱,比如:"ARM","Lanai"
- Size: 寄存器的大小(以位為單位),比如:32
- RegisterList: 寄存器列表,定義了寄存器類包含的寄存器及其分配順序,可以是(sequence "R%u", 0, 12)定義的一些列的列表或者手動(dòng)指定的寄存器。
后面的let中可以添加自定義的屬性,并設(shè)置值。
GPR(通用寄存器類),通用寄存器的主要作用包括:
寄存器分配:為寄存器分配器提供可用的寄存器池和分配順序
指令選擇:幫助指令選擇器確定哪些寄存器可以用于特定指令
約束處理:處理內(nèi)聯(lián)匯編中的寄存器約束
代碼生成:指導(dǎo)代碼生成器如何使用寄存器
調(diào)試信息:為調(diào)試信息生成提供寄存器信息
定義 GPR 的方法包括:
- 直接列出寄存器:如 (add R0, R1, R2, ...)
- 使用序列生成:如 (sequence "R%u", 0, 12) 生成 R0 到 R12
- 組合使用:如 (add (sequence "R%u", 0, 12), SP, LR, PC)
使用操作符:
add: 添加寄存器到列表
trunc: 截?cái)嗉拇嫫髁斜?br> shl: 左移寄存器列表
sequence: 生成寄存器序列
let 可以用于設(shè)置多種屬性
是可選的,屬性的數(shù)量沒有限制,常見的有:
- Size: 寄存器大小(以位為單位)
let Size = 32; - CopyCost: 復(fù)制寄存器的成本
let CopyCost = -1; // -1 表示不允許復(fù)制 - isAllocatable: 是否可分配
let isAllocatable = 0; // 0 表示不可分配 - AltOrders: 替代的寄存器分配順序
let AltOrders = [(add LR, GPR), (trunc GPR, 8), ...]; - AltOrderSelect: 選擇替代分配順序的函數(shù)
let AltOrderSelect = [{
return MF.getSubtarget<ARMSubtarget>().getGPRAllocationOrder(MF);
}]; - DiagnosticString: 診斷字符串
let DiagnosticString = "operand must be a register in range [r0, r15]"; - RegInfos: 寄存器信息
let RegInfos = GRLenRI;
這些屬性的具體值和可用性取決于目標(biāo)架構(gòu)和 LLVM 后端的實(shí)現(xiàn)。不同的架構(gòu)可能支持不同的屬性,或者對(duì)同一屬性有不同的解釋。
示例1
def GPR : GPRRegisterClass<(add (sequence "X%u", 10, 17),
(sequence "X%u", 5, 7),
(sequence "X%u", 28, 31),
(sequence "X%u", 8, 9),
(sequence "X%u", 18, 27),
(sequence "X%u", 0, 4))>;
這個(gè)定義使用了自定義的 GPRRegisterClass 類(不是標(biāo)準(zhǔn)的 RegisterClass),它通過多個(gè) sequence 指定了寄存器的分配順序。
沒有指定架構(gòu),每個(gè) sequence "X%u", Start, End 生成從 XStart 到 XEnd 的寄存器序列。
這個(gè)等價(jià)的生成C++代碼是什么,這幾個(gè)sequence的順序有什么約定嗎?
示例2
def GPR : RegisterClass<"LoongArch", [GRLenVT], 32, (add
// Argument registers (a0...a7)
(sequence "R%u", 4, 11),
// Temporary registers (t0...t8)
(sequence "R%u", 12, 20),
// Static register (s9/fp, s0...s8)
(sequence "R%u", 22, 31),
// Specials (r0, ra, tp, sp)
(sequence "R%u", 0, 3),
// Reserved (Non-allocatable)
R21
)> {
let RegInfos = GRLenRI;
}
命名空間為 "LoongArch"
可以保存 GRLenVT 類型的值(可能是根據(jù)架構(gòu)定義的變量類型)
寄存器大小為 32 位
按照功能分組寄存器:參數(shù)寄存器、臨時(shí)寄存器、靜態(tài)寄存器、特殊寄存器和保留寄存器
添加了 RegInfos 屬性,值為 GRLenRI(可能是與寄存器信息相關(guān)的定義)
示例3
def GPR : RegisterClass<"ARM", [i32], 32, (add (sequence "R%u", 0, 12),
SP, LR, PC)> {
let AltOrders = [(add LR, GPR), (trunc GPR, 8),
(add (trunc GPR, 8), R12, LR, (shl GPR, 8))];
let AltOrderSelect = [{
return MF.getSubtarget<ARMSubtarget>().getGPRAllocationOrder(MF);
}];
let DiagnosticString = "operand must be a register in range [r0, r15]";
}
包含從 R0 到 R12 的寄存器,以及 SP(堆棧指針)、LR(鏈接寄存器)和 PC(程序計(jì)數(shù)器)
定義了 AltOrders 和 AltOrderSelect 屬性,用于根據(jù)不同的子目標(biāo)選擇不同的寄存器分配順序
添加了 DiagnosticString 屬性,用于在寄存器使用不當(dāng)時(shí)提供錯(cuò)誤信息