RISC-V環境でのベクトル化されたSIMD命令の実装と確認
この記事では、x86アーキテクチャのSIMD命令をRISC-V環境で動作させる方法を説明します。以下に示すコードは、x86のSIMD命令である_mm_add_pd
をRISC-Vのベクトル命令に置き換えたものです。
x86のSIMD命令
まず、x86のSIMD命令_mm_add_pd
の実装を示します。
extern __inline __m128d __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_add_pd(__m128d __A, __m128d __B) {
return (__m128d)((__v2df)__A + (__v2df)__B);
}
これをRISC-V環境で動作させるために、以下のようにコードを変更します。
RISC-V環境での実装
#include <stdio.h>
#include <stdlib.h>
#include <riscv_vector.h>
// __v2df
typedef double __v2df __attribute__ ((__vector_size__ (16)));
// __m128d
typedef __v2df __m128d;
// _mm_add_pd
__m128d _mm_add_pd(__m128d A, __m128d B) {
return (__m128d)((__v2df)A + (__v2df)B);
}
int main() {
__m128d a = {1.0, 2.0};
__m128d b = {3.0, 4.0};
__m128d c = _mm_add_pd(a, b);
printf("%f %f\n", c[0], c[1]);
return 0;
}
RISC-Vツールチェインのインストール
RISC-V環境での開発を始めるには、以下のコマンドでツールチェインをインストールします。
brew tap riscv-software-src/riscv
brew install riscv-tools
brew install riscv-isa-sim riscv-pk
brew install riscv-gnu-toolchain
echo 'export PATH="/opt/homebrew/opt/riscv-gnu-toolchain/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
LLVM/Clangのビルドとインストール
次に、LLVM/Clangをビルドしてインストールします。
git clone --depth=1 https://github.com/llvm/llvm-project.git
cd llvm-project
mkdir build
cd build
cmake -G "Ninja" \
-DLLVM_ENABLE_PROJECTS="clang;compiler-rt" \
-DLLVM_TARGETS_TO_BUILD="RISCV" \
-DCMAKE_BUILD_TYPE=Release \
../llvm
ninja
cd bin
echo "export PATH=`pwd`:\$PATH" >> ~/.zshrc
source ~/.zshrc
Clangのバージョン確認とコンパイル
Clangが正しくインストールされたか確認し、コードをコンパイルします。
clang -v
clang version 19.0.0git (https://github.com/llvm/llvm-project.git b77e734e4e6c8f5e016ba3ac49526862e6039482)
Target: riscv64-unknown-unknown-elf
Thread model: posix
export RISCV_SYSROOT=$(riscv64-unknown-elf-gcc --print-sysroot)
clang -target riscv64-unknown-elf -march=rv64gcv -mabi=lp64d -O3 test.c -c -s \
--sysroot=$RISCV_SYSROOT \
-I$RISCV_SYSROOT/include \
-L$RISCV_SYSROOT/lib \
-lc -lm -lclang_rt.builtins -Wimplicit-function-declaration -fvectorize -fslp-vectorize
アセンブリコードの確認
生成されたオブジェクトファイルを逆アセンブルし、ベクトル化された命令を確認します。
llvm-objdump -S test.o
出力されたアセンブリコードは以下の通りです:
test.o: file format elf64-littleriscv
Disassembly of section .text:
0000000000000000 <_mm_add_pd>:
0: cd817057 vsetivli zero, 0x2, e64, m1, ta, ma
4: 5e054457 vmv.v.x v8, a0
8: 3e85e457 vslide1down.vx v8, v8, a1
c: 5e0644d7 vmv.v.x v9, a2
10: 3e96e4d7 vslide1down.vx v9, v9, a3
14: 02849457 vfadd.vv v8, v8, v9
18: 42802557 vmv.x.s a0, v8
1c: 3e80b457 vslidedown.vi v8, v8, 0x1
20: 428025d7 vmv.x.s a1, v8
24: 8082 ret
0000000000000026 <main>:
26: 1141 addi sp, sp, -0x10
28: e406 sd ra, 0x8(sp)
2a: 00000537 lui a0, 0x0
2e: 00050513 mv a0, a0
32: 40100593 li a1, 0x401
36: 15d2 slli a1, a1, 0x34
38: 00803637 lui a2, 0x803
3c: 161e slli a2, a2, 0x27
3e: 00000097 auipc ra, 0x0
42: 000080e7 jalr ra <main+0x18>
46: 4501 li a0, 0x0
48: 60a2 ld ra, 0x8(sp)
4a: 0141 addi sp, sp, 0x10
4c: 8082 ret
ベクトル命令の解説
-
vsetivli
は、ベクトルレジスタの初期設定を行う命令です。 -
vmv.v.x
は、スカラー値をベクトルレジスタに移動する命令です。 -
vslide1down.vx
は、ベクトル要素をシフトする命令です。 -
vfadd.vv
は、ベクトル要素同士の浮動小数点加算を行う命令です。 -
vmv.x.s
は、ベクトルレジスタのスカラー要素をスカラー値に移動する命令です。 -
vslidedown.vi
は、ベクトル要素をシフトする命令です。
これらの命令が使用されていることから、ベクトル化されていることがわかります。
結論
_mm_add_pd
関数のアセンブリコードを見ると、ベクトル化が適用されていることが確認できます。vfadd.vv
命令などのベクトル命令が含まれているため、コードはベクトル化されています。これにより、RISC-V環境で効率的にSIMD命令を使用することができます。
以上が、x86のSIMD命令をRISC-V環境でベクトル化して動作させる方法の説明です。