こちらの記事を読んで、LLVMのAutomatic Vectorizationが少しずつ使い物になっていることを知った。RISC-Vを例に採っているので、使えるようになっているのだろうか?
丸一日かけてLLVM13をビルドして、オプションを調整してベクトル拡張命令が出力されるのか確かめてみた。
このようなテストプログラムを使って確かめてみる。
vec_vec_add.c
void vector_add (int *c, int *a, int *b, const int N) { for (int i = 0; i < N; i++) { c[i] = a[i] + b[i]; } return; }
以下のバージョン番号で試行している。
$ clang --version clang version 13.0.0 (https://github.com/llvm/llvm-project.git a7cb951fa40df14d98c51059194ae42855b96a08) Target: x86_64-unknown-linux-gnu Thread model: posix
以下のコマンドでClangとLLCを動かして動作を確認した。
$ clang -O3 -march=rv64gcv0p10 -menable-experimental-extensions --target=riscv64-unknown-elf vec_vec_add.c -c -emit-llvm -o vec_vec_add.riscv64.static.bc $ llc -march=riscv64 -mattr=experimetal-v -disable-tail-calls -riscv-v-vector-bits-min=256 "--debug" -relocation-model=static -filetype=asm vec_vec_add.riscv64.static.bc -o vec_vec_add.riscv64.static.S
うーん、この時点ではまだベクトル関係のIRは出ていない。っていうかどの時点でLLVM-IRにベクトルの要素が入ってくるんだろう?
for.body: ; preds = %for.body.preheader, %for.body %indvars.iv = phi i64 [ 0, %for.body.preheader ], [ %indvars.iv.next, %for.body ] %arrayidx = getelementptr inbounds i32, i32* %a, i64 %indvars.iv %0 = load i32, i32* %arrayidx, align 4, !tbaa !4 %arrayidx2 = getelementptr inbounds i32, i32* %b, i64 %indvars.iv %1 = load i32, i32* %arrayidx2, align 4, !tbaa !4 %add = add nsw i32 %1, %0 %arrayidx4 = getelementptr inbounds i32, i32* %c, i64 %indvars.iv store i32 %add, i32* %arrayidx4, align 4, !tbaa !4 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 %exitcond.not = icmp eq i64 %indvars.iv.next, %wide.trip.count br i1 %exitcond.not, label %for.cond.cleanup, label %for.body, !llvm.loop !8
そして変換されたアセンブリコードにもベクトルっぽい要素は無かった。原因は何だろう?確認してみよう。
vector_add: # @vector_add # %bb.0: # %entry blez a3, .LBB0_3 # %bb.1: # %for.body.preheader slli a3, a3, 32 srli a3, a3, 32 .LBB0_2: # %for.body # =>This Inner Loop Header: Depth=1 lw a4, 0(a1) lw a5, 0(a2) add a4, a4, a5 sw a4, 0(a0) addi a0, a0, 4 addi a2, a2, 4 addi a3, a3, -1 addi a1, a1, 4 bnez a3, .LBB0_2