FPGA開発日記

FPGAというより、コンピュータアーキテクチャかもね! カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages

LLVMのバックエンドを作るための第一歩 (20. 定数を生成させるパタンの追加)

f:id:msyksphinz:20190425001356p:plain

簡単な関数をコンパイルしてアセンブリ命令が出力できるようになったので、様々な命令をサポートしていきましょう。MYRISCVXに命令を追加して、生成できるコードの量を増やしていく。

基本的な算術演算から進めるのが良いと思う。 MYRISCVXに命令を追加することで、算術演算命令が生成できるようになる。

定数を生成させるパタンの追加

まず、算術演算命令を生成させる前に、テストなどで頻繁に出てくる定数を生成させるパタンをLLVMに追加する。 例えば、0x01234567という32ビット定数をレジスタに格納したい場合、MYRISCVXはどのように命令を生成すればよいのだろうか。

RISC-Vには、lui命令というものが定義されている。 lui命令は20ビットの即値オペランドを持ち、32ビットのうち上位の20ビットにオペランドの値を設定する。 さらに、ori命令は12ビットの即値オペランドを取ることができるので、まずは上位の20ビットを設定して、ori命令で下位の12ビットを設定すれば、任意の32ビット値を生成できると考えられる。

このルールをMYRISCVXInstrInfo.tdに追加すればよいことが分かる。 ここでは、以下の3つルールを追加する。

  • 12ビット以内に収まる符号付き定数 : immSExt12 は、以下のルールで表現される。
def immSExt12 : PatLeaf<(imm), [{ return isInt<12>(N->getSExtValue()); }]>;

これは、$zeroレジスタとのaddiで生成することができます。符号付きなので、addi命令を使う。

def : Pat<(i32 immSExt12:$in),
          (ADDI ZERO, imm:$in)>;
  • 12ビット以内に収まる符号なし定数 : immZExt12は、以下のルールで表現される。
def immZExt12 : PatLeaf<(imm), [{
  if (N->getValueType(0) == MVT::i32)
    return (uint32_t)N->getZExtValue() == (unsigned short)N->getZExtValue();
  else
    return (uint64_t)N->getZExtValue() == (unsigned short)N->getZExtValue();
}], LO12>;

これは、addiの代わりにoriを使用する。

def : Pat<(i32 immZExt12:$in),
          (ORI ZERO, imm:$in)>;
  • 下位12ビットが0の定数 : immLow12Zero は、以下のルールで表現される。
// Immediate can be loaded with LUi (32-bit int with lower 16-bit cleared).
def immLow12Zero : PatLeaf<(imm), [{
  int64_t Val = N->getSExtValue();
  return isInt<32>(Val) && !(Val & 0x0fff);
}]>;

これは、単純にlui命令だけで良いだろう。

def : Pat<(i32 immLow12Zero:$in),
          (LUI (HI20 imm:$in))>;
  • 32ビット整数 : immは、以下の手順で生成する。まずはlui命令で上位の20ビットを作り、次にoriで買いの12ビットを連結する。
def : Pat<(i32 imm:$imm),
          (ORI (LUI (HI20 imm:$imm)), (LO12 imm:$imm))>;
// Transformation Function - get the lower 12 bits.
def LO12 : SDNodeXForm<imm, [{
  return getImm(N, N->getZExtValue() & 0xfff);
}]>;

// Transformation Function - get the higher 20 bits.
def HI20 : SDNodeXForm<imm, [{
  return getImm(N, (N->getZExtValue() >> 12) & 0xfffff);
}]>;
f:id:msyksphinz:20190608010144p:plain
定数の生成方法