RISC-V Vector拡張のアセンブリを読み解く 異なる型同士の演算
以前と同様に、RVVのアセンブリを読み解いてみようと思う。今回は型の大きさが異なる同士の演算を見ていこうと思う。
C言語ソースコード
// Vectorization of Mixed Types #include <stdio.h> int foo(int *A, char *B, int n) { for (int i = 0; i < n; i++) { A[i] += 4 * B[i]; } return 0; } int main() { int n = 2001; int A[n]; char B[n]; for(int i = 0; i < n; i++) { A[i] = i; B[i] = i % 256; } foo(A, B, n); }
RVVアセンブリ
今回も関数のインライン化が行われているので、main関数の中だけを見れば良い。
.text .attribute 4, 16 .attribute 5, "rv64i2p0_m2p0_a2p0_f2p0_d2p0_c2p0_v1p0_zvl128b1p0_zvl32b1p0_zvl64b1p0" .file "test0.c" .globl foo .p2align 1 .type foo,@function foo: blez a2, .LBB0_9 slli a3, a2, 32 li a4, 8 srli a6, a3, 32 bgeu a2, a4, .LBB0_3 li a2, 0 j .LBB0_7 .LBB0_3: slli a2, a6, 2 add a2, a2, a0 add a3, a1, a6 sltu a3, a0, a3 sltu a2, a1, a2 and a3, a3, a2 li a2, 0 bnez a3, .LBB0_7 andi a2, a6, -8 mv a4, a2 mv a5, a0 mv a3, a1 .LBB0_5: vsetivli zero, 8, e8, mf4, ta, mu vle8.v v8, (a3) vsetvli zero, zero, e32, m1, ta, mu vle32.v v9, (a5) vzext.vf4 v10, v8 vsll.vi v8, v10, 2 vadd.vv v8, v8, v9 vse32.v v8, (a5) addi a3, a3, 8 addi a4, a4, -8 addi a5, a5, 32 bnez a4, .LBB0_5 beq a2, a6, .LBB0_9 .LBB0_7: slli a3, a2, 2 add a0, a0, a3 add a1, a1, a2 sub a2, a6, a2 .LBB0_8: lbu a3, 0(a1) lw a4, 0(a0) slliw a3, a3, 2 addw a3, a3, a4 sw a3, 0(a0) addi a0, a0, 4 addi a2, a2, -1 addi a1, a1, 1 bnez a2, .LBB0_8 .LBB0_9: li a0, 0 ret .Lfunc_end0: .size foo, .Lfunc_end0-foo .globl main .p2align 1 .type main,@function main: lui a0, 2 addiw a0, a0, 1824 sub sp, sp, a0 li a0, 0 addi a1, sp, 2044 vsetivli zero, 8, e8, mf4, ta, mu vid.v v8 vsetvli zero, zero, e32, m1, ta, mu vid.v v9 addi a2, sp, 11 li a3, 16 li a4, 2000 .LBB1_1: vsetvli zero, zero, e32, m1, ta, mu vadd.vi v10, v9, 8 // mf4=64bitにすることでintと同様に // 8つのデータを扱えるようになる。 // 8bitをオーバーした分は自動的に切り捨てられる vsetvli zero, zero, e8, mf4, ta, mu vadd.vi v11, v8, 8 addi a5, a1, -32 vse32.v v9, (a5) vse32.v v10, (a1) add a5, a2, a0 vse8.v v8, (a5) addi a5, a5, 8 vse8.v v11, (a5) addi a0, a0, 16 vsetvli zero, zero, e32, m1, ta, mu vadd.vx v9, v9, a3 // a3=16 vsetvli zero, zero, e8, mf4, ta, mu vadd.vx v8, v8, a3 // a3=16 addi a1, a1, 64 bne a0, a4, .LBB1_1 li a0, 0 lui a1, 2 addiw a2, a1, -192 addi a1, sp, 2012 add a3, a1, a2 li a2, 2000 sw a2, 0(a3) li a3, 208 sb a3, 2011(sp) addi a3, sp, 11 .LBB1_3: add a4, a3, a0 vsetvli zero, zero, e8, mf4, ta, mu vle8.v v8, (a4) vsetvli zero, zero, e32, m1, ta, mu vle32.v v9, (a1) // SEW/4のソースオペランドをゼロ拡張してSEW幅化し書き込む vzext.vf4 v10, v8 vsll.vi v8, v10, 2 vadd.vv v8, v8, v9 vse32.v v8, (a1) addi a0, a0, 8 addi a1, a1, 32 bne a0, a2, .LBB1_3 lbu a0, 2011(sp) lui a1, 2 addiw a1, a1, -192 addi a2, sp, 2012 add a1, a1, a2 lw a2, 0(a1) slliw a0, a0, 2 addw a0, a0, a2 sw a0, 0(a1) li a0, 0 lui a1, 2 addiw a1, a1, 1824 add sp, sp, a1 ret .Lfunc_end1: .size main, .Lfunc_end1-main .ident "clang version 14.0.0" .section ".note.GNU-stack","",@progbits .addrsig
気づいた点