llvm后端之tblgen寄存器信息
引言
llvm后端采用table-gen语法定义好目标指令描述信息后,可通过llvm-tblgen工具生成源码文件。以x86为例:
llvm-tblgen -gen-register-info X86.td -I ../../../include/ -o=X86GenRegisterInfo.inc
运行上述命令后就生成了x86的寄存器信息。主要内容如下:
- 基础枚举信息
1 基础枚举信息
- 首先,生成寄存器枚举:
enum {
NoRegister,
... ...
BH = 4,
BL = 5,
... ...
BX = 9,
... ...
EBX = 24,
... ...
HBX = 40,
... ...
RBX = 51,
... ...
NUM_TARGET_REGS
};
注: 以上枚举是按照td文件的寄存器定义名称生成,以AX为例,在td文件中有:
class X86Reg<string n, bits<16> Enc, list<Register> subregs = []> : Register<n> {
let Namespace = "X86";
let HWEncoding = Enc;
let SubRegs = subregs;
}
... ...
let SubRegIndices = [sub_8bit, sub_8bit_hi], CoveredBySubRegs = 1 in {
def AX : X86Reg<"ax", 0, [AL,AH]>;
def DX : X86Reg<"dx", 2, [DL,DH]>;
def CX : X86Reg<"cx", 1, [CL,CH]>;
def BX : X86Reg<"bx", 3, [BL,BH]>;
}
... ...
- 生成寄存器分类枚举:
enum {
GR8RegClassID = 0,
GRH8RegClassID = 1,
... ...
VR512_0_15RegClassID = 117,
};
注:以上枚举是按照td文件的寄存器分类定义名称生成,以GR8RegClassID为例,在td文件有定义:
def GR8 : RegisterClass<"X86", [i8], 8,
(add AL, CL, DL, AH, CH, DH, BL, BH, SIL, DIL, BPL, SPL,
R8B, R9B, R10B, R11B, R14B, R15B, R12B, R13B)> {
let AltOrders = [(sub GR8, AH, BH, CH, DH)];
let AltOrderSelect = [{
return MF.getSubtarget<X86Subtarget>().is64Bit();
}];
}
- 生成子寄存器索引枚举:
enum {
NoSubRegister,
sub_8bit, // 1
sub_8bit_hi, // 2
sub_8bit_hi_phony, // 3
sub_16bit, // 4
sub_16bit_hi, // 5
sub_32bit, // 6
sub_mask_0, // 7
sub_mask_1, // 8
sub_xmm, // 9
sub_ymm, // 10
NUM_TARGET_SUBREGS
};
注:以上枚举来源于td文件的定义如下:
let Namespace = "X86" in {
def sub_8bit : SubRegIndex<8>;
def sub_8bit_hi : SubRegIndex<8, 8>;
def sub_8bit_hi_phony : SubRegIndex<8, 8>;
def sub_16bit : SubRegIndex<16>;
def sub_16bit_hi : SubRegIndex<16, 16>;
def sub_32bit : SubRegIndex<32>;
def sub_xmm : SubRegIndex<128>;
def sub_ymm : SubRegIndex<256>;
def sub_mask_0 : SubRegIndex<-1>;
def sub_mask_1 : SubRegIndex<-1, -1>;
}
2 MC寄存器信息
2.1 寄存器基本信息
寄存器基本信息主要生成如下常量数组:
- MCPhysReg X86RegDiffLists[]
- LaneBitmask X86LaneMaskLists[]
- uint16_t X86SubRegIdxLists
- MCRegisterInfo::SubRegCoveredBits X86SubRegIdxRanges[]
- const char X86RegStrings[]
- MCRegisterDesc X86RegDesc[]
- MCPhysReg X86RegUnitRoots[][2]
以上数组的关系都是基于X86RegDesc为起点。在llvm源码中,MCRegisterDesc包含五个无符号整数的关键字段:
- Name:代表寄存器的名称;
- SubRegs:代表子寄存器列表,指向X86RegDiffLists中的索引值,从该索引往后直到遇到0,是求解子寄存器相应枚举的数字;
- SuperRegs:代表父寄存器,表示方式与SubRegs类似;
- SubRegIndices:代表子寄存器索引信息,与SubRegs类似,稍微不同的是指向X86SubRegIdxLists的索引值
- RegUnits:代表寄存器的寄存器硬件单元列表;
- RegUnitLaneMasks:
以16位BX寄存器为例,由于BX枚举值为9, 查找X86RegDesc[9],内容如下:
{ 1183, 317, 178, 0, 304, 2 },
注:1183为寄存器名字,字符串X86RegStrings数组中的子字符串&X86RegStrings[1183]刚好为“BX”
- 寻找子寄存器
查找X86RegDiffLists[317],得到如下内容:
/* 317 */ 65532, 65535, 0,
通过BX的枚举值9计算:9+(uint16)65532 = 5(即BL),用上一步结果5计算:5+(uint16)65535=4(即BH);
- 寻找子寄存器索引
查找X86SubRegIdxLists[0],得到内容:
/* 0 */ 1, 2, 0,
数字1,2是子寄存器索引枚举sub_8bit和sub_8bit_hi,索引范围为X86SubRegIdxRanges[1]和X86SubRegIdxRanges[2]。即BL为sub_8bit(Offset=0,Size=8)、BH为sub_8bit_hi(Offset=8,Size=8)。
- 寻找父寄存器
查找X86RegDiffLists[178],得到如下内容:
/* 177 */ 4, 15, 27, 0,
取得15和27两组值,通过BX的枚举值9计算:15+9 = 24(即EBX),用上一步结果5计算:24+27=51(即RBX);
- 寻找寄存器单元
计算scale = 304&0x0f = 0;然后查找查找X86RegDiffLists[304>>4] (即X86RegDiffLists[19]),得到如下内容:
/* 19 */ 2, 1, 0,
通过BX的枚举值9计算 9 * scale + 2 = 2 ,用上一步结果2 + 1 = 3。X86RegUnitRoots[2]为X86::BH、X86RegUnitRoots[3]为X86::BL。
注:并不是有多少个寄存器就有多少个寄存器单元,例如两个8位BL和BH组成了16位BX、两个16位BX和HBX组成了32位EBX、EBX扩展成64位RBX,有6个寄存器却只有X86::BL、X86::BH、X86::HBX三个寄存器单元
- 寻找寄存器单元LaneMask
查找X86LaneMaskLists[2],得出以LaneBitmask::getAll()结尾的内容如下:
/* 2 */ LaneBitmask(0x00000002), LaneBitmask(0x00000001), LaneBitmask::getAll(),
注:上述内容表示X86::BH和X86::BL对于的LaneMask。其生成规则是按枚举出现顺序将sub_8bit、sub_8bit_hi、sub_8bit_hi_phony、sub_16bit_hi、sub_32bit、sub_xmm、sub_ymm被设置为0x01、0x02、0x04、0x08、0x10、0x20、0x40。另外,sub_16bit比较特殊,它可以由sub_8bit、sub_8bit_hi、sub_8bit_hi_phony组合而成,所以设置为0x07(即0x01 | 0x02 | 0x04)
2.2 寄存器分类信息
寄存器分类信息包括:
- 寄存器分类所含寄存器枚举数组和BitMask
- const char X86RegClassStrings[]
- MCRegisterClass X86MCRegisterClasses[]
以上数组的关系都是基于X86MCRegisterClasses为中心组织起来。在llvm源码中,MCRegisterClass主要包含如下字段:
- RegsBegin:关于“寄存器分类所含寄存器枚举数组”的迭代器
- RegSet:关于“寄存器分类所含寄存器的BitMask”的bit序列
- NameIdx:寄存器分类名称在X86RegClassStrings的索引
- RegsSize:关于“寄存器分类所含寄存器枚举数组”的长度
- RegSetSize:关于“寄存器分类所含寄存器的BitMask”的bit序列长度
- ID:寄存器分类的枚举值
- CopyCost:寄存器分类的
- Allocatable:是否可以用于指令分配。
注:CopyCost和Allocatable来源于def RegisterClass的设置let CopyCost = … 和let isAllocatable = …
以X86::GR16RegClassID为例,由于X86::GR16RegClassID枚举值为6,查找X86MCRegisterClasses[6],内容如下:
{ GR16, GR16Bits, 179, 16, sizeof(GR16Bits), X86::GR16RegClassID, 1, true },