FPGA開発日記

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

LLVMのバックエンドを作るための第一歩 (25. int32型以外のサポート)

f:id:msyksphinz:20190425001356p:plain

現在は、int型(32ビット整数)のみLLVM IRをサポートしているが、それ以外の型をサポートしたいと思う。32ビット整数、16ビット整数、8ビット整数、そしてBool型をサポートする。

これらの値をメモリアクセスするために、AlignedLoadを拡張して以下のノードを追加する。

  • llvm-myriscvx/lib/Target/MYRISCVX/MYRISCVXInstrInfo.td
// Load/Store PatFrags.
def load_a          : AlignedLoad<load>;
def sextloadi8_a    : AlignedLoad<sextloadi8>;
def zextloadi8_a    : AlignedLoad<zextloadi8>;
def sextloadi16_a   : AlignedLoad<sextloadi16>;
def zextloadi16_a   : AlignedLoad<zextloadi16>;
def extloadi16_a    : AlignedLoad<extloadi16>;

def store_a         : AlignedStore<store>;
def truncstorei8_a  : AlignedStore<truncstorei8>;
def truncstorei16_a : AlignedStore<truncstorei16>;

32ビット以外でも、16ビットと8ビットでロードストアをするためのノードを定義する。このノードを使って、ロード命令とストア命令を定義する。

/// Load and Store Instructions
///  aligned
defm LW     : LoadM32 <0b0000011, 0b010, "lw",  load_a>;
defm SW     : StoreM32<0b0100011, 0b010, "sw",  store_a>;
defm LB     : LoadM32 <0b0000011, 0b000, "lb",  sextloadi8_a>;
defm LBU    : LoadM32 <0b0000011, 0b100, "lbu", zextloadi8_a>;
defm SB     : StoreM32<0b0100011, 0b000, "sb",  truncstorei8_a>;
defm LH     : LoadM32 <0b0000011, 0b001, "lh",  sextloadi16_a>;
defm LHU    : LoadM32 <0b0000011, 0b101, "lhu", zextloadi16_a>;
defm SH     : StoreM32<0b0100011, 0b001, "sh",  truncstorei16_a>;

さらに、MYRISCVXのレジスタはi32型なので、charなどの符号なし整数からi32型へのロードができるように以下のパタンを追加する。

def : Pat<(i32 (zextloadi1  addr:$src)), (LBU addr:$src)>;
def : Pat<(i32 (zextloadi8  addr:$src)), (LBU addr:$src)>;
def : Pat<(i32 (zextloadi16 addr:$src)), (LHU addr:$src)>;

def : Pat<(i32 (sextloadi1  addr:$src)), (LB addr:$src)>;
def : Pat<(i32 (sextloadi8  addr:$src)), (LB addr:$src)>;
def : Pat<(i32 (sextloadi16 addr:$src)), (LH addr:$src)>;

def : Pat<(i32 (extloadi1  addr:$src)), (LBU addr:$src)>;
def : Pat<(i32 (extloadi8  addr:$src)), (LBU addr:$src)>;
def : Pat<(i32 (extloadi16 addr:$src)), (LHU addr:$src)>;

さらに、符号なしの値を拡張して32ビットの符号付整数に設定するためのパタンを追加する。

def : Pat<(sext_inreg GPR:$ra, i8),  (SRAI (SLLI GPR:$ra, 24), 24)>;
def : Pat<(sext_inreg GPR:$ra, i16), (SRAI (SLLI GPR:$ra, 16), 16)>;

それぞれ、8ビット符号なし数の場合は24ビット左シフトしたのちに、24ビット符号付右シフトする。 一方で、16ビット符号なし数の場合は16ビット左シフトしたのちに、16ビット符号付右シフトする。

これでリビルドを行い、以下のソースをコンパイルする。

#include <stdint.h>

int8_t test_int8_type ()
{
  volatile int8_t i8  = 0xab;
  int8_t i8_2 = i8 + 4;
  return i8_2;
}


uint8_t test_uint8_type ()
{
  volatile uint8_t  u8  = 0xab;
  uint8_t u8_2 = u8 + 4U;
  return u8_2;
}
./bin/clang -target mips-unknown-linux-gnu -c ../lbdex/input/ch7_1_other_type.cpp -emit-llvm
./bin/llc --debug -march=myriscvx32 -mcpu=simple32 -relocation-model=pic -filetype=asm ch7_1_other_type.bc -o -
_Z14test_int8_typev:
# %bb.0:                                # %entry
        addi    x2, x2, -8
        addi    x10, zero, 171
        sb      x10, 4(x2)
        lbu     x10, 4(x2)
        addi    x10, x10, 4
        slli    x10, x10, 24
        srai    x10, x10, 24
        addi    x2, x2, 8
        ret     x1

_Z15test_uint8_typev:
# %bb.0:                                # %entry
        addi    x2, x2, -8
        addi    x10, zero, 171
        sb      x10, 4(x2)
        lbu     x10, 4(x2)
        addi    x10, x10, 4
        andi    x10, x10, 255
        addi    x2, x2, 8
        ret     x1