TabelGen文档:https://llvm.org/docs/TableGen/
TableGen Language文档:TableGen Language Introduction、TableGen Language Reference
简单记录一下multiclass和defm的语法。
假设某处理器的3-address指令有如下两种格式:
- reg = reg op reg
- reg = reg op imm
前2个操作数是寄存器,第3个操作数可能是寄存器,也可能是立即数。
看如下示例代码:
class inst<int opc, string asmstr, dag operandlist>;
multiclass ri_inst<int opc, string asmstr> {
def _rr : inst<opc, !strconcat(asmstr, " $dst, $src1, $src2"),
(ops GPR:$dst, GPR:$src1, GPR:$src2)>;
def _ri : inst<opc, !strconcat(asmstr, " $dst, $src1, $src2"),
(ops GPR:$dst, GPR:$src1, Imm:$src2)>;
}
// Instantiations of the ri_inst multiclass.
defm ADD : ri_inst<0b111, "add">;
defm SUB : ri_inst<0b101, "sub">;
multiclass ri_inst抽象了3-address指令,def _rr和def _ri分别定义上述两种指令格式。
defm实例化multiclass。以defm ADD为例,相当于定义了ADD_rr和ADD_ri两条指令(指令名字由defm后面的名字和multiclass中def后面的名字拼接组成)。
上述代码与下面的代码等价:
class inst<int opc, string asmstr, dag operandlist>;
class rrinst<int opc, string asmstr>
: inst<opc, !strconcat(asmstr, " $dst, $src1, $src2"),
(ops GPR:$dst, GPR:$src1, GPR:$src2)>;
class riinst<int opc, string asmstr>
: inst<opc, !strconcat(asmstr, " $dst, $src1, $src2"),
(ops GPR:$dst, GPR:$src1, Imm:$src2)>;
// Instantiations of the ri_inst multiclass.
def ADD_rr : rrinst<0b111, "add">;
def ADD_ri : riinst<0b111, "add">;
def SUB_rr : rrinst<0b101, "sub">;
def SUB_ri : riinst<0b101, "sub">;
defm还可以出现在multiclass内部,看一个更复杂的例子(多层multiclass实例化):
class Instruction<bits<4> opc, string Name> {
bits<4> opcode = opc;
string name = Name;
}
multiclass basic_r<bits<4> opc> {
def rr : Instruction<opc, "rr">;
def rm : Instruction<opc, "rm">;
}
multiclass basic_s<bits<4> opc> {
defm SS : basic_r<opc>;
defm SD : basic_r<opc>;
def X : Instruction<opc, "x">;
}
multiclass basic_p<bits<4> opc> {
defm PS : basic_r<opc>;
defm PD : basic_r<opc>;
def Y : Instruction<opc, "y">;
}
defm ADD : basic_s<0xf>, basic_p<0xf>;
上述代码定义了ADDSSrr、ADDSSrm、ADDSDrr、ADDSDrm、ADDX、ADDPSrr、ADDPSrm、ADDPDrr、ADDPDrm、ADDY。
// Results
def ADDSSrr { ...
def ADDSSrm { ...
def ADDSDrr { ...
def ADDSDrm { ...
def ADDX { ...
def ADDPSrr { ...
def ADDPSrm { ...
def ADDPDrr { ...
def ADDPDrm { ...
def ADDY { ...
defm语句中,分号后面的类列表中即可有multiclass,也可以有class。但至少要有一个multiclass,并且class list要在最后一个multiclass的后面。看示例:
class XD { bits<4> Prefix = 11; }
class XS { bits<4> Prefix = 12; }
class I<bits<4> op> {
bits<4> opcode = op;
}
multiclass R {
def rr : I<4>;
def rm : I<2>;
}
multiclass Y {
defm SS : R, XD;
defm SD : R, XS;
}
defm Instr : Y;
定义结果:
// Results
def InstrSSrr {
bits<4> opcode = { 0, 1, 0, 0 }; //4
bits<4> Prefix = { 1, 0, 1, 1 }; //11
}
def InstrSSrm {
bits<4> opcode = { 0, 0, 1, 0 }; //2
bits<4> Prefix = { 1, 0, 1, 1 }; //11
}
def InstrSDrr {
bits<4> opcode = { 0, 1, 0, 0 }; //4
bits<4> Prefix = { 1, 1, 0, 0 }; //12
}
def InstrSDrm {
bits<4> opcode = { 0, 0, 1, 0 }; //2
bits<4> Prefix = { 1, 1, 0, 0 }; //12
}
在最终的定义中,class中的field进行了合并。
llvm中有一个工具llvm-tblgen,可以用来查看td文件中定义的所有record。multiclass和defm的用法感觉挺绕的,可以结合该工具来辅助理解和开发。
十八垧
网友评论