RegisterInfo.td中RegisterClass的使用和定义
在 LLVM TableGen 中,RegisterClass 是用于定义寄存器类的基本类,其通用语法为:
def ClassName : RegisterClass<"Namespace", [ValueType], Size, RegisterList> {
// 可选属性
let Property1 = Value1;
let Property2 = Value2;
// ...
}
- "Namespace": 寄存器类的命名空间,通常是目标架构名称,比如:"ARM","Lanai"
- Size: 寄存器的大小(以位为单位),比如:32
- RegisterList: 寄存器列表,定义了寄存器类包含的寄存器及其分配顺序,可以是(sequence "R%u", 0, 12)定义的一些列的列表或者手动指定的寄存器。
后面的let中可以添加自定义的属性,并设置值。
GPR(通用寄存器类),通用寄存器的主要作用包括:
寄存器分配:为寄存器分配器提供可用的寄存器池和分配顺序
指令选择:帮助指令选择器确定哪些寄存器可以用于特定指令
约束处理:处理内联汇编中的寄存器约束
代码生成:指导代码生成器如何使用寄存器
调试信息:为调试信息生成提供寄存器信息
定义 GPR 的方法包括:
- 直接列出寄存器:如 (add R0, R1, R2, ...)
- 使用序列生成:如 (sequence "R%u", 0, 12) 生成 R0 到 R12
- 组合使用:如 (add (sequence "R%u", 0, 12), SP, LR, PC)
使用操作符:
add: 添加寄存器到列表
trunc: 截断寄存器列表
shl: 左移寄存器列表
sequence: 生成寄存器序列
let 可以用于设置多种属性
是可选的,属性的数量没有限制,常见的有:
- Size: 寄存器大小(以位为单位)
let Size = 32; - CopyCost: 复制寄存器的成本
let CopyCost = -1; // -1 表示不允许复制 - isAllocatable: 是否可分配
let isAllocatable = 0; // 0 表示不可分配 - AltOrders: 替代的寄存器分配顺序
let AltOrders = [(add LR, GPR), (trunc GPR, 8), ...]; - AltOrderSelect: 选择替代分配顺序的函数
let AltOrderSelect = [{
return MF.getSubtarget<ARMSubtarget>().getGPRAllocationOrder(MF);
}]; - DiagnosticString: 诊断字符串
let DiagnosticString = "operand must be a register in range [r0, r15]"; - RegInfos: 寄存器信息
let RegInfos = GRLenRI;
这些属性的具体值和可用性取决于目标架构和 LLVM 后端的实现。不同的架构可能支持不同的属性,或者对同一属性有不同的解释。
示例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))>;
这个定义使用了自定义的 GPRRegisterClass 类(不是标准的 RegisterClass),它通过多个 sequence 指定了寄存器的分配顺序。
没有指定架构,每个 sequence "X%u", Start, End 生成从 XStart 到 XEnd 的寄存器序列。
这个等价的生成C++代码是什么,这几个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 类型的值(可能是根据架构定义的变量类型)
寄存器大小为 32 位
按照功能分组寄存器:参数寄存器、临时寄存器、静态寄存器、特殊寄存器和保留寄存器
添加了 RegInfos 属性,值为 GRLenRI(可能是与寄存器信息相关的定义)
示例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(程序计数器)
定义了 AltOrders 和 AltOrderSelect 属性,用于根据不同的子目标选择不同的寄存器分配顺序
添加了 DiagnosticString 属性,用于在寄存器使用不当时提供错误信息