
LLVMバックエンドを追加するにあたり、MYRISCVXアーキテクチャを定義するためのtdファイルを作成する必要がある。 tdファイルはLLVMのバックエンドを定義するためのDSLで、バックエンドを理解するためには避けては通れないものだ。
MYRISCVXInstrInfo.td
次に追加すべきは、MYRISCVXの命令を定義するためのMYRISCVXInstrInfo.tdだ。
MYRISCVXInstrInfo.td内には命令フォーマットを定義するためのMYRISCVXInstrFormats.tdを用意する必要がある。
lib/Target/MYRISCVX/MYRISCVXInstrFormats.td
// Generic MYRISCVX Format class MYRISCVXInst<dag outs, dag ins, string asmstr, list<dag> pattern, InstrItinClass itin, Format f>: Instruction { // Inst and Size: for tablegen(... -gen-emitter) and // tablegen(... -gen-disassembler) in CMakeLists.txt field bits<32> Inst; Format Form = f; let Namespace = "MYRISCVX"; let Size = 4; let OutOperandList = outs; let InOperandList = ins; let AsmString = asmstr; let Pattern = pattern; let Itinerary = itin; // // Attributes specific to MYRISCVX instructions... // bits<4> FormBits = Form.Value; // TSFlags layout should be kept in sync with MYRISCVXInstrInfo.h. let TSFlags{3-0} = FormBits; let DecoderNamespace = "MYRISCVX"; field bits<32> SoftFail = 0; }
MYRISCVXInstがベースのクラスになる。32ビットのフィールドInstを定義し、これが命令フィールドそのものになる。
OutOperandListはこの命令で書き込まれるレジスタのリスト、InOperandListはこの命令で読み込まれるレジスタのリストだ。
このオペランドリストを使用してデータフローを構築したり、レジスタ割り付けの解析を行う。
さらに、命令のニーモニックを格納するためにAsmStringを定義し、PatternはLLVM IRから命令を生成するために必要なパターンを格納する。
さて、ここから先はいよいよ命令フォーマットの定義氏をしていく。RISC-Vには、基本として以下の命令フォーマットが決められている。

ここでは、上記の6つの命令フォーマットについてクラスを作ればよいことになる。
それぞれ、上記で定義したMYRISCVXInstクラスを継承して定義する。

lib/Target/MYRISCVX/MYRISCVXInstrFormats.td
//===----------------------------------------------------------------------===//
// R-Type instruction class in MYRISCVX : <|opcode|funct7|funct3|rd|rs1|rs2|>
//===----------------------------------------------------------------------===//
class MYRISCVX_R<bits<7> opcode, bits<3> funct3, bits<7> funct7,
dag outs, dag ins, string asmstr,
list<dag> pattern, InstrItinClass itin>:
MYRISCVXInst<outs, ins, asmstr, pattern, itin, FrmR>
{
bits<5> rd;
bits<5> rs1;
bits<5> rs2;
let Inst{31-25} = funct7;
let Inst{24-20} = rs2;
let Inst{19-15} = rs1;
let Inst{14-12} = funct3;
let Inst{11-7} = rd;
let Inst{6-0} = opcode;
}
MYRISCVXInstを継承して、MYRISCVX_Rクラスを作成した。
引数としてopcode, funct3, func7を取る。
また、outs, insは使用すレジスタを指定し、データフローを構築する。
asmstrには命令のニーモニックを定義する。
rd, rs1, rs2を定義して、オペランドとして指定されるレジスタオペランドを作成する。
そして、MYRISCVXInstでインスタンスしたInst変数に対して、ビットフィールドを指定する形で値を設定する。
Inst{31-25}ならば、Inst変数の31ビットから25ビットまでの7ビットにfunct7が代入されるという意味になる。
lib/Target/MYRISCVX/MYRISCVXInstrFormats.td
MYRISCVX_Iは即値命令を扱うためのフォーマットだ。
//===----------------------------------------------------------------------===//
// I-Type instruction class in MYRISCVX : <|opcode|funct3|rd|rs1|imm12|>
//===----------------------------------------------------------------------===//
class MYRISCVX_I<bits<7> opcode, bits<3> funct3,
dag outs, dag ins, string asmstr, list<dag> pattern,
InstrItinClass itin>:
MYRISCVXInst<outs, ins, asmstr, pattern, itin, FrmI>
{
bits<5> rd;
bits<5> rs1;
bits<12> imm12;
let Inst{31-20} = imm12;
let Inst{19-15} = rs1;
let Inst{14-12} = funct3;
let Inst{11-7} = rd;
let Inst{6-0} = opcode;
}
lib/Target/MYRISCVX/MYRISCVXInstrFormats.td
MYRISCVX_Sはメモリストア命令を扱うためのフォーマットだ。
//===----------------------------------------------------------------------===//
// S-Type instruction class in MYRISCVX : <|opcode|rs2|rs1|width|offset>
//===----------------------------------------------------------------------===//
class MYRISCVX_S<bits<7> opcode, bits<3> funct3,
dag outs, dag ins, string asmstr, list<dag> pattern,
InstrItinClass itin>:
MYRISCVXInst<outs, ins, asmstr, pattern, itin, FrmS>
{
bits<5> rs2;
bits<5> rs1;
bits<12> simm12;
let Inst{31-25} = simm12{11-5};
let Inst{19-15} = rs1;
let Inst{24-20} = rs2;
let Inst{14-12} = funct3;
let Inst{11-7} = simm12{4-0};
let Inst{6-0} = opcode;
let DecoderMethod = "DecodeStore";
}
lib/Target/MYRISCVX/MYRISCVXInstrFormats.td
MYRISCVX_Uは即値生成命令(LUI命令やAUIPC命令など)を扱うためのフォーマットだ。
//===----------------------------------------------------------------------===//
// U-Type instruction class in MYRISCVX : <|opcode|rd|imm31-12>
//===----------------------------------------------------------------------===//
class MYRISCVX_U<bits<7> opcode,
dag outs, dag ins, string asmstr, list<dag> pattern,
InstrItinClass itin>:
MYRISCVXInst<outs, ins, asmstr, pattern, itin, FrmI>
{
bits<5> rd;
bits<20> imm20;
let Inst{31-12} = imm20;
let Inst{11-7} = rd;
let Inst{6-0} = opcode;
}
lib/Target/MYRISCVX/MYRISCVXInstrFormats.td
MYRISCVX_Bは条件分岐命令を扱うためのフォーマットだ。
//===----------------------------------------------------------------------===//
// B-Type instruction class in MYRISCVX : <|opcode|funct3|rs1|rs2|imm12|>
//===----------------------------------------------------------------------===//
class MYRISCVX_B<bits<7> opcode, bits<3> funct3,
dag outs, dag ins, string asmstr, list<dag> pattern,
InstrItinClass itin>:
MYRISCVXInst<outs, ins, asmstr, pattern, itin, FrmI>
{
bits<12> imm12;
bits<5> rs2;
bits<5> rs1;
let Inst{31} = imm12{11};
let Inst{30-25} = imm12{9-4};
let Inst{14-12} = funct3;
let Inst{11-8} = imm12{3-0};
let Inst{7} = imm12{10};
let Inst{6-0} = opcode;
}
lib/Target/MYRISCVX/MYRISCVXInstrFormats.td
MYRISCVX_Jは即値ジャンプ命令を扱うためのフォーマットだ。
//===----------------------------------------------------------------------===//
// J-Type instruction class in MYRISCVX : <|opcode|imm20|>
//===----------------------------------------------------------------------===//
class MYRISCVX_J<bits<7> opcode,
dag outs, dag ins, string asmstr, list<dag> pattern,
InstrItinClass itin>:
MYRISCVXInst<outs, ins, asmstr, pattern, itin, FrmI>
{
bits<20> imm20;
let Inst{31} = imm20{19};
let Inst{30-21} = imm20{9-0};
let Inst{20} = imm20{10};
let Inst{19-12} = imm20{18-11};
let Inst{6-0} = opcode;
}
Formatsを定義する
上記の命令区分に応じて、命令を区別するためのFormatsを定義する。
これはMYRISCVXInst内でTSFlagsに格納される。
lib/Target/MYRISCVX/MYRISCVXInstrFormats.td
// Format specifies the encoding used by the instruction. This is part of the
// ad-hoc solution used to emit machine instruction encodings by our machine
// code emitter.
class Format<bits<3> val> {
bits<3> Value = val;
}
def Pseudo : Format<0>;
def FrmR : Format<1>;
def FrmI : Format<2>;
def FrmS : Format<3>;
def FrmU : Format<4>;
def FrmB : Format<5>;
def FrmJ : Format<6>;