FPGA開発日記

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

LLVMのバックエンドを作るための第一歩 (24. ポインタのサポート)

LLVM IRでポインタのサポートをする。ポインタをサポートするためには、該当するシンボルに対するアドレスを計算するというIRを追加する必要がある。これを、EffectiveAddressというクラスで追加する。

  • llvm-myriscvx/lib/Target/MYRISCVX/MYRISCVXInstrInfo.td
def mem_ea : Operand<iPTR> {
  let PrintMethod = "printMemOperandEA";
  let MIOperandInfo = (ops GPR, simm12);
  let EncoderMethod = "getMemEncoding";
}
class EffectiveAddress<string instr_asm, RegisterClass RC, Operand Mem> :
  MYRISCVX_I<0b0010011, 0b000, (outs RC:$ra), (ins Mem:$addr),
     instr_asm, [(set RC:$ra, addr:$addr)], IIAlu>;

このEffectiveAddressは、実際にはアドレス計算するためのaddi命令を生成している。addi命令により、スタックポインタからのオフセットで、アドレスを算出している。

def LEA_ADDI : EffectiveAddress<"addi\t$ra, $addr", GPR, mem_ea> {
  let isCodeGenOnly = 1;
}

例えば、以下のようなコードをコンパイルしてみる。

int test_local_pointer()
{
  int b = 3;

  int* p = &b;

  return *p;
}
./bin/clang -target mips-unknown-linux-gnu -c ../lbdex/input/ch7_1_localpointer.cpp -emit-llvm
./bin/llc -march=myriscvx32 -mcpu=simple32 -relocation-model=pic -filetype=asm ch7_1_localpointer.bc -o -
# %bb.0:                                # %entry
        addi    x2, x2, -8
        addi    x10, zero, 3
        sw      x10, 4(x2)
        addi    x10, x2, 4
        sw      x10, 0(x2)
        lw      x10, 0(x2)
        lw      x10, 0(x10)
        addi    x2, x2, 8
        ret     x1

読み解いていくと、まずはx10に3を格納する。それをスタックポインタ(x2)の2番目のスロットに格納する(4(x2))。

        addi    x10, zero, 3
        sw      x10, 4(x2)

次のaddix10bのポインタ&bを格納する。これには、さきほどのEffectiveAddressで作成したaddi命令を使用し、スタックの位置からのオフセットを計算して算出する。そして、そのポインタの値(=x10)をスタックポインタ(x2)の1番目のスロットに格納する。

        addi    x10, x2, 4
        sw      x10, 0(x2)

最後に、ポインタの値を返すために、ポインタ経由でロード命令を2回発行して、x10レジスタに格納する。

        lw      x10, 0(x2)
        lw      x10, 0(x10)
f:id:msyksphinz:20190615175107p:plain
スタックに格納されたポインタの配置