td中寄存器定义方式

寄存器定义的基本语法和流程

1 寄存器类定义

所有架构都首先定义一个寄存器类,该类继承自 LLVM 的 Register 或其子类(如 RegisterWithSubRegs)。这个类定义了寄存器的通用属性。

class ArchReg<EncodingType Enc, string n, list<Register> subregs = [], 
             list<string> altNames = []> : Register<n, altNames> {
  let HWEncoding = Enc;
  let Namespace = "ArchName";
  let SubRegs = subregs;
  // 其他架构特定属性
}

编码(Encoding):
指定寄存器的硬件编码,类型可能是 bits<N>,其中 N 取决于架构(ARM 使用 16 位,CSKY 使用 6 位,Lanai 使用 5 位)
名称(Name):寄存器的汇编名称,类型为 string
命名空间(Namespace):
指定寄存器的命名空间,通常为架构的名称。
子寄存器(SubRegs):
指定寄存器的子寄存器,这些子寄存器将继承该寄存器的属性。类型为 list<Register>,默认值为空列表 []
别名(altNames):指定寄存器的替代名称列表,类型为 list<string>,默认值为空列表 []
其他架构特定属性:
根据架构的属性,可以添加其他属性,如子寄存器的索引等。

1.2 寄存器实例定义

定义了寄存器类后,各架构使用不同的方法创建具体的寄存器实例。

def RegName : ArchReg<Encoding, "Name", [SubRegs...]>, DwarfRegNum<[DebugNum]>;

所有寄存器实例都包含以下基本属性:
调试编号(DwarfRegNum):用于调试信息的寄存器编号,通过 DwarfRegNum<[DebugNum]> 指定
子寄存器索引(SubRegIndices):指定子寄存器的索引,通过 SubRegIndices = [sub_index1, sub_index2, ...] 指定
使用 foreach 循环:

foreach I = 0-11 in {
  // 32-bit Integer (alias to low part of 64-bit register).
  def W#I  : Wi<I,  "w"#I>,  DwarfRegNum<[I]>;
  // 64-bit Integer registers
  def R#I  : Ri<I,  "r"#I,  [!cast<Wi>("W"#I)]>,  DwarfRegNum<[I]>;
}

特殊寄存器定义模式:

let SubRegIndices = [sub_index...] in {
  def SpecialReg : ArchReg<Encoding, "Name", [SubRegs...]>, DwarfRegAlias<BaseReg>;
}

总结

不同架构的寄存器定义虽然有一些细节差异,但遵循共同的模式和流程:

  1. 定义架构特定的寄存器类,继承自 LLVM 的 Register 类
  2. 定义子寄存器索引,用于描述寄存器层次结构
  3. 创建寄存器实例,可以使用直接定义或 foreach 循环
  4. 定义寄存器类(RegisterClass),将寄存器分组用于代码生成
    这种模块化的定义方式使得 LLVM 能够支持多种不同的目标架构,同时保持代码的可维护性和一致性。每个架构可以根据自己的特定需求扩展或修改基本模式,但核心概念和结构保持一致。
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容