编译器知识杂记31——LLVM TableGen Languag

2020-07-28  本文已影响0人  十八垧

TabelGen文档:https://llvm.org/docs/TableGen/
TableGen Language文档:TableGen Language IntroductionTableGen Language Reference

简单记录一下multiclass和defm的语法。

假设某处理器的3-address指令有如下两种格式:

前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的用法感觉挺绕的,可以结合该工具来辅助理解和开发。

十八垧

上一篇 下一篇

猜你喜欢

热点阅读