Instruction
VSM4RNDS4
Performs four rounds of SM4 encryption in each 128-bit lane.
- Extensions
- Forms
- 10 (4 VEX, 6 EVEX)
- Data
- Intel XED v2026.08.23
VSM4RNDS4 runs four of the 32 rounds of SM4, the Chinese national block cipher with 128-bit blocks and keys that the IETF draft on this page’s sources describes. A block is four 32-bit words; each round replaces the oldest word X[i] with
X[i+4] = X[i] ^ T(X[i+1] ^ X[i+2] ^ X[i+3] ^ rk[i])
where T passes each byte through SM4’s S-box and then XORs the word with itself rotated left by 2, 10, 18 and 24 bits. VSM4RNDS4 takes the four words in its second operand, dword 0 the oldest, the four round keys rk[i] to rk[i+3] in its third, a register or memory, and writes X[i+4] to X[i+7] to the first. So eight instructions, each fed the next four round keys, encrypt a block, and the result of one is the input of the next.
Lanes and keys
- One block per 128-bit lane. The YMM form runs two blocks at once and the EVEX form on ZMM four, each lane with the round keys in the same lane of the third operand: several blocks of one message under one key, as in counter mode, or blocks under different keys.
- Decryption is the same instruction with the round keys in the opposite order, rk[31] first: SM4 decrypts with the same rounds. There is no separate decryption form, unlike AES’s AESDEC.
- The round keys come from software, computed once per key with VSM4KEY4.
After the last round SM4 outputs the four words in reverse order, X[35] to X[32], and the instruction leaves them X[32] to X[35] from dword 0 up, so a dword shuffle such as VPSHUFD with 1BH finishes the block. Each operation is on whole 32-bit words in the register’s little-endian order, while SM4 numbers bytes from the most significant, so code that loads blocks from memory byte-swaps each word first.
Where it runs
The VEX forms need AVX and the SM4 extension (CPUID leaf 7, subleaf 1,
EAX bit 2), which Intel’s extensions reference gives to Arrow Lake S,
Clearwater Forest and Diamond Rapids. The EVEX forms, which add ZMM and
registers 16 to 31 but no masking, need AVX10 as well: Diamond Rapids
and Nova Lake. Zen 5 has neither: all ten of its recorded cases, VEX and
EVEX, raised #UD. GCC 14 and Clang 23 compile _mm_sm4rnds4_epi32() and
_mm256_sm4rnds4_epi32() with -msm4; only Clang 23 has
_mm512_sm4rnds4_epi32(), with -msm4 -mavx10.2.
Forms
| Instruction | Encoding | Requires |
|---|---|---|
VSM4RNDS4 xmm, xmm, xmm
VSM4RNDS4_XMMu32_XMMu32_XMMu32 | VEX.128.F2.0F38.W0 DA /r | SM4 + AVX |
VSM4RNDS4 xmm, xmm, m128
VSM4RNDS4_XMMu32_XMMu32_MEMu32 | VEX.128.F2.0F38.W0 DA /r | SM4 + AVX |
VSM4RNDS4 ymm, ymm, ymm
VSM4RNDS4_YMMu32_YMMu32_YMMu32 | VEX.256.F2.0F38.W0 DA /r | SM4 + AVX |
VSM4RNDS4 ymm, ymm, m256
VSM4RNDS4_YMMu32_YMMu32_MEMu32 | VEX.256.F2.0F38.W0 DA /r | SM4 + AVX |
VSM4RNDS4 xmm, xmm, xmm
VSM4RNDS4_XMMu32_XMMu32_XMMu32_AVX512 | EVEX.128.F2.0F38.W0 DA /r | SM4 + AVX10 |
VSM4RNDS4 xmm, xmm, m128
VSM4RNDS4_XMMu32_XMMu32_MEMu32_AVX512 | EVEX.128.F2.0F38.W0 DA /r | SM4 + AVX10 |
VSM4RNDS4 ymm, ymm, ymm
VSM4RNDS4_YMMu32_YMMu32_YMMu32_AVX512 | EVEX.256.F2.0F38.W0 DA /r | SM4 + AVX10 |
VSM4RNDS4 ymm, ymm, m256
VSM4RNDS4_YMMu32_YMMu32_MEMu32_AVX512 | EVEX.256.F2.0F38.W0 DA /r | SM4 + AVX10 |
VSM4RNDS4 zmm, zmm, zmm
VSM4RNDS4_ZMMu32_ZMMu32_ZMMu32_AVX512 | EVEX.512.F2.0F38.W0 DA /r | SM4 + AVX10 |
VSM4RNDS4 zmm, zmm, m512
VSM4RNDS4_ZMMu32_ZMMu32_MEMu32_AVX512 | EVEX.512.F2.0F38.W0 DA /r | SM4 + AVX10 |
Operation
What the forms do, in pseudocode that our tests run against results recorded on real processors. How to read.
if not cpuid_leaf(7, 1)[0] >> 2 & 1:
fault(UD) # CPUID: no SM4
for i in range(VL // 128): # each lane:
a = ymm2.d[4 * i] # the block's
b = ymm2.d[4 * i + 1] # four words,
c = ymm2.d[4 * i + 2] # the first in
d = ymm2.d[4 * i + 3] # dword 0
for j in range(4): # src3: four rk
x = b ^ c ^ d ^ src3.d[4 * i + j]
x = a ^ sm4_l(sm4_sub_word(x))
ymm1.d[4 * i + j] = x # the next
a = b
b = c
c = d
d = x
# ymm1 is zeroed from bit VL upRun on AMD Zen 5 (EPYC 9645): 4 cases. Its cases ran where CPUID reported no SM4, and every one raised an exception.
if not cpuid_leaf(7, 1)[0] >> 2 & 1:
fault(UD) # CPUID: no SM4
if not cpuid_leaf(7, 1)[3] >> 19 & 1:
fault(UD) # CPUID: no AVX10
for i in range(VL // 128): # each lane:
a = zmm2.d[4 * i] # the block's
b = zmm2.d[4 * i + 1] # four words,
c = zmm2.d[4 * i + 2] # the first in
d = zmm2.d[4 * i + 3] # dword 0
for j in range(4): # src3: four rk
x = b ^ c ^ d ^ src3.d[4 * i + j]
x = a ^ sm4_l(sm4_sub_word(x))
zmm1.d[4 * i + j] = x # the next
a = b
b = c
c = d
d = x
# zmm1 is zeroed from bit VL upRun on AMD Zen 5 (EPYC 9645): 6 cases. Its cases ran where CPUID reported no SM4, and every one raised an exception.
Operands
| Operand | Kind | Action |
|---|---|---|
VSM4RNDS4 xmm, xmm, xmm/m128 VSM4RNDS4 ymm, ymm, ymm/m256 VSM4RNDS4 zmm, zmm, zmm/m512 | ||
xmm, ymm, zmm | explicit | write |
xmm, ymm, zmm | explicit | read |
xmm/m128, ymm/m256, zmm/m512 | explicit | read |
Flags
None: XED records no flag that the forms test or change.
Exceptions
The exception class is XED's name for the set of exception conditions that a form follows. How to read.
- VEX forms
avx-type-6- EVEX forms
AVX512-E6
Intrinsics
The C intrinsics of Clang 23.1.2 that compile to VSM4RNDS4, each with the form it compiles to and the Clang options it needs. The forms come from compiling every intrinsic and decoding the result with Intel XED; all intrinsics A–Z explains the method.
| Intrinsic | Compiles to |
|---|---|
_mm_sm4rnds4_epi32
__m128i _mm_sm4rnds4_epi32(__m128i A, __m128i B) |
|
_mm256_sm4rnds4_epi32
__m256i _mm256_sm4rnds4_epi32(__m256i A, __m256i B) |
|
_mm512_sm4rnds4_epi32
__m512i _mm512_sm4rnds4_epi32(__m512i __A, __m512i __B) |
|
CPUID and processors
Each form belongs to an XED ISA set. A form can be used when the processor reports every CPUID bit of one of its ISA set's alternatives.
| ISA set | CPUID | Processors |
|---|---|---|
SM4 | SM4 + AVX | Arrow Lake, Panther Lake, Nova Lake, Diamond Rapids, Clearwater Forest Note: Intel's extensions reference introduces these instructions with Arrow Lake S, and GCC's -march=arrowlake, which it selects for Arrow Lake H and U, leaves them out. |
SM4_128 | SM4 + AVX10 | Nova Lake, Diamond Rapids |
SM4_256 | Same as SM4_128 | Same as SM4_128 |
SM4_512 | Same as SM4_128 | Same as SM4_128 |
More SM4 instructions
Sources
- Intel XED v2026.08.23 (commit
0bcb6237345c): forms, encodings, operands, flags, exception classes, attributes, ISA sets, CPUID bits and chip model. - Clang's x86 intrinsic headers, LLVM 23.1.2 (commit
85ac56026243): the intrinsics, their signatures and doc comments, and the Clang of that release, which compiled each of them. - Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 2 (325383-093, September 2026): Volume 2C, page 5-763 (VSM4RNDS4)
- Intel Architecture Instruction Set Extensions and Future Features Programming Reference (319433-062, June 2026)
- IETF draft-ribose-cfrg-sm4-10: The SM4 Blockcipher Algorithm and Its Modes of Operations (April 2018)
The tables are derived from Intel XED, Copyright Intel Corporation, licensed under the Apache License 2.0; x86-64.net converted and reformatted them. The intrinsics and their signatures come from Clang, part of the LLVM Project, licensed under the Apache License 2.0 with LLVM Exceptions. The text is our own.