Summary
The vsm3me.vv instruction (Zvksh, SM3 message expansion) is documented as a
reserved encoding when the destination register group (vd) overlaps the
first source register group (vs2). When compiling code that uses the
__riscv_vsm3me_vv_u32m1 / __riscv_vsm3me_vv_u32m4 intrinsics with GCC,
the compiler allocates the same physical vector register group for vd and
vs2, producing an encoding that traps as trap_illegal_instruction when
executed on Spike. This reproduces at both LMUL=1 and LMUL=4, so it does not
appear to be LMUL-specific.
#include <riscv_vector.h>
vuint32m1_t f(vuint32m1_t vs2, vuint32m1_t vs1, size_t vl) {
return __riscv_vsm3me_vv_u32m1(vs2, vs1, vl);
}
#include <riscv_vector.h>
vuint32m4_t f(vuint32m4_t vs2, vuint32m4_t vs1, size_t vl) {
return __riscv_vsm3me_vv_u32m4(vs2, vs1, vl);
}
Spec reference
Per the RISC-V Vector Crypto specification for vsm3me.vv
(https://docs.riscv.org/reference/isa/v20260120/unpriv/vector-crypto.html#insns-vsm3me),
the destination register group must not overlap the vs2 source register
group; an encoding where they overlap is reserved. Spike enforces this at
runtime (see require_vsm3_constraints in riscv-isa-sim, which checks
insn.rd() != insn.rs2()), so any such encoding traps.
Steps to reproduce
start.S
.section .text
.global _start
_start:
la sp, _stack_top
li t0, 0x200
csrs mstatus, t0
call main
1:
j 1b
.section .bss
.align 4
_stack_bottom:
.space 4096
_stack_top:
test.ld
ENTRY(_start)
SECTIONS
{
. = 0x80000000;
.text : { *(.text*) }
.rodata : { *(.rodata*) }
.data : { *(.data*) }
.bss : { *(.bss*) *(COMMON) }
}
test.c
#include <riscv_vector.h>
volatile uint32_t src1[8] = {1, 2, 3, 4, 5, 6, 7, 8};
volatile uint32_t src2[8] = {9, 10, 11, 12, 13, 14, 15, 16};
volatile uint32_t dst[8];
int main(void)
{
size_t vl = __riscv_vsetvl_e32m1(8);
vuint32m1_t vs1 = __riscv_vle32_v_u32m1((const uint32_t *)src1, vl);
vuint32m1_t vs2 = __riscv_vle32_v_u32m1((const uint32_t *)src2, vl);
vuint32m1_t vd = __riscv_vsm3me_vv_u32m1(vs2, vs1, vl);
__riscv_vse32_v_u32m1((uint32_t *)dst, vd, vl);
return 0;
}
Compile the test
riscv64-unknown-elf-gcc \
-march=rv64gcv_zvksh \
-mabi=lp64d \
-nostdlib \
-nostartfiles \
-mcmodel=medany \
-static \
-Wl,-Ttest.ld \
-o test.elf \
start.S test.c
Simulate with Spike
spike --isa=rv64gcv_zvksh --varch=vlen:2048,elen:64 -d -m0x80000000 test.elf
The compiler allocates vd == vs2. Spike traps with:
Additional notes
If I used inline assembly to use different vector registers for vd and vs2 then there was no trap:
test.c
#include <stdint.h>
volatile uint32_t src1[8] = {1,2,3,4,5,6,7,8};
volatile uint32_t src2[8] = {9,10,11,12,13,14,15,16};
volatile uint32_t dst[8];
int main(void)
{
asm volatile (
"vsetivli zero, 8, e32, m1, ta, ma\n\t"
"vle32.v v8, (%[src2])\n\t"
"vle32.v v16, (%[src1])\n\t"
"vsm3me.vv v24, v8, v16\n\t"
"vse32.v v24, (%[dst])\n\t"
:
: [src1] "r"(src1),
[src2] "r"(src2),
[dst] "r"(dst)
: "memory"
);
return 0;
}
Summary
The
vsm3me.vvinstruction (Zvksh, SM3 message expansion) is documented as areserved encoding when the destination register group (
vd) overlaps thefirst source register group (
vs2). When compiling code that uses the__riscv_vsm3me_vv_u32m1/__riscv_vsm3me_vv_u32m4intrinsics with GCC,the compiler allocates the same physical vector register group for
vdandvs2, producing an encoding that traps astrap_illegal_instructionwhenexecuted on Spike. This reproduces at both LMUL=1 and LMUL=4, so it does not
appear to be LMUL-specific.
Spec reference
Per the RISC-V Vector Crypto specification for
vsm3me.vv(https://docs.riscv.org/reference/isa/v20260120/unpriv/vector-crypto.html#insns-vsm3me),
the destination register group must not overlap the
vs2source registergroup; an encoding where they overlap is reserved. Spike enforces this at
runtime (see
require_vsm3_constraintsinriscv-isa-sim, which checksinsn.rd() != insn.rs2()), so any such encoding traps.Steps to reproduce
start.S
test.ld
test.c
Compile the test
Simulate with Spike
The compiler allocates
vd == vs2. Spike traps with:Additional notes
If I used inline assembly to use different vector registers for vd and vs2 then there was no trap:
test.c