td中RegisterClass的使用和定义

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 属性,用于在寄存器使用不当时提供错误信息

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容