FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

"Creating an LLVM Backend for the Cpu0 Architecture"をやってみる(1. Cpu0のアーキテクチャ)

f:id:msyksphinz:20181123225150p:plain

なんかLLVMのバックエンドの資料を読み漁るの、浮気ばっかりしているが面白そうな資料を見つけたのでこっちに浮気してしまった。

もともとはこっちをやろうとしたのだが、Step by Stepじゃないので根気が続かなくなってしまった。

Writing an LLVM Backend — LLVM 8 documentation

以下の資料は、Cpu0という独自のアーキテクチャ向けのLLVMバックエンドを作成するためのチュートリアルだ。

Cpu0は命令長32-bit、独自のアーキテクチャで、整数命令を備えている。 命令のフォーマットとしては以下の3種類を備えており、割り込みの定義も一応備わっている。

f:id:msyksphinz:20181121010447p:plain

LLVMのバックエンドを組み立てるためには以下のような情報が必要になるらしい。

  • 命令の情報 (InstInfo.td)
  • レジスタの情報 (RegisterInfo.td)
  • Calling Conventionの情報 (CallingConv.td)

が必要になるらしい。

で、命令フォーマットのベースになるのはCpu0InsntrFormats.tdに記述してある。

以下がベースになるCpu0Instクラス。

// Generic Cpu0 Format
class Cpu0Inst<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 = "Cpu0";

  let Size = 4;

  bits<8> Opcode = 0;

  // Top 8 bits are the 'opcode' field
  let Inst{31-24} = Opcode;

  let OutOperandList = outs;
  let InOperandList  = ins;

  let AsmString   = asmstr;
  let Pattern     = pattern;
  let Itinerary   = itin;

  //
  // Attributes specific to Cpu0 instructions...
  //
  bits<4> FormBits = Form.Value;

  // TSFlags layout should be kept in sync with Cpu0InstrInfo.h.
  let TSFlags{3-0}   = FormBits;

  let DecoderNamespace = "Cpu0";

  field bits<32> SoftFail = 0;
}

このクラスを継承する形で、3つのフォーマットを構成する、という理解でいいのかな?

class FL<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern,
         InstrItinClass itin>: Cpu0Inst<outs, ins, asmstr, pattern, itin, FrmL>
{
  bits<4>  ra;
  bits<4>  rb;
  bits<16> imm16;

  let Opcode = op;

  let Inst{23-20} = ra;
  let Inst{19-16} = rb;
  let Inst{15-0}  = imm16;
}

さらに、FLを継承する形でArithmetcLogicIクラス(これは1レジスタと1即値による演算命令)を作っており、最終的にADDiu命令が形成される。

// Arithmetic and logical instructions with 2 register operands.
class ArithLogicI<bits<8> op, string instr_asm, SDNode OpNode,
                  Operand Od, PatLeaf imm_type, RegisterClass RC> :
  FL<op, (outs GPROut:$ra), (ins RC:$rb, Od:$imm16),
     !strconcat(instr_asm, "\t$ra, $rb, $imm16"),
     [(set GPROut:$ra, (OpNode RC:$rb, imm_type:$imm16))], IIAlu> {
  let isReMaterializable = 1;
}
// IR "add" defined in include/llvm/Target/TargetSelectionDAG.td, line 315 (def add).
def ADDiu   : ArithLogicI<0x09, "addiu", add, simm16, immSExt16, CPURegs>;