FPGA開発日記

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

オリジナルLLVMバックエンド実装をまとめる(26. LLVM IRをサポートするためのIntrinsicsのサポート2. )

前回の続き。

データのバイトスワップを行う。C言語では、__builtin_bswap16, __builtin_bswap32, __builtin_bswap64により取得することができる。 これらはそのまま命令に落とし込めないので、IRの生成を抑制する。

  • func_bswap.cpp
int test_bswap16() {
  volatile int a = 0x1234;
  int result = (__builtin_bswap16(a) ^ 0x3412);

  return result;
}

int test_bswap32() {
  volatile int a = 0x1234;
  int result = (__builtin_bswap32(a) ^ 0x34120000);

  return result;
}

int test_bswap64() {
  volatile int a = 0x1234;
  int result = (__builtin_bswap64(a) ^ 0x3412000000000000);

  return result;
}

int test_bswap() {
  int result = test_bswap16() + test_bswap32() + test_bswap64();

  return result;
}

これも、LLVM中間言語を生成してみる。

./bin/clang func_bswap.cpp -c -emit-llvm --target=riscv32-unknown-elf -o - | ./bin/llvm-dis -o -
define dso_local i32 @_Z12test_bswap16v() #0 {
entry:
  %a = alloca i32, align 4
  %result = alloca i32, align 4
  store volatile i32 4660, i32* %a, align 4
  %0 = load volatile i32, i32* %a, align 4
  %conv = trunc i32 %0 to i16
  %1 = call i16 @llvm.bswap.i16(i16 %conv)
  %conv1 = zext i16 %1 to i32
  %xor = xor i32 %conv1, 13330
  store i32 %xor, i32* %result, align 4
  %2 = load i32, i32* %result, align 4
  ret i32 %2
}
...
define dso_local i32 @_Z12test_bswap32v() #0 {
  entry:
  %1 = call i32 @llvm.bswap.i32(i32 %0)
}
...
define dso_local i32 @_Z12test_bswap64v() #0 {
entry:
  %1 = call i64 @llvm.bswap.i64(i64 %conv)
}

それぞれ、llvm.bswap.i16, llvm.bswap.i32, llvm.bswap.i64が呼ばれていることが分かる。 それぞれ、16ビット、32ビット、64ビットの長さでバイトスワップを行うノードである。

https://llvm.org/docs/LangRef.html#llvm-bswap-intrinsics

このノードも、直接命令として落とし込むことはできない。このノードは、setOperationAction()の設定で生成を禁止し、より一般的なノードへの置き換えを行う。

  • llvm-myriscvx80/lib/Target/MYRISCVX/MYRISCVXISelLowering.cpp
MYRISCVXTargetLowering::MYRISCVXTargetLowering(const MYRISCVXTargetMachine &TM,
                                               const MYRISCVXSubtarget &STI)
...
  setOperationAction(ISD::BSWAP, MVT::i16, Expand);
  setOperationAction(ISD::BSWAP, MVT::i32, Expand);
  setOperationAction(ISD::BSWAP, MVT::i64, Expand);
...
}

BSWAPのコンパイル結果である。バイトスワップの操作が展開されていることが分かる。

_Z12test_bswap16v:                      # @_Z12test_bswap16v

# %bb.0:                                # %entry
        addi    x2, x2, -8
        lui     x10, 1
        ori     x10, x10, 564
        sw      x10, 4(x2)
        lw      x10, 4(x2)
        slli    x11, x10, 8
        lui     x12, 4080
        and     x11, x11, x12
        slli    x10, x10, 24
        or      x10, x10, x11
        srli    x10, x10, 16
        lui     x11, 3
        ori     x11, x11, 1042
        xor     x10, x10, x11
        sw      x10, 0(x2)
        lw      x10, 0(x2)
        addi    x2, x2, 8
        ret
f:id:msyksphinz:20191017003130p:plain
bswap16で生成された命令によるバイトスワップの様子。