Cover image for ARM SVE/SVE2

ARM SVE/SVE2

Timeline

Timeline

2025-10-30

init

This article introduces the SVE/SVE2 scalable vector instruction set developed for high-performance computing and machine learning in the ARM architecture, discusses in detail its variable vector length programming model (VLA) and new register groups such as Z, P, and FFR, and summarizes unique programming patterns and core technologies including predicated instructions, gather loads and scatter stores, predicated loop control, and software speculation-based vector partitioning.

Reference documents:

SVE

Scalable Vector Extension

  • SVE-related manuals:
    • <<ARM Architecture Reference Manual Supplement, The Scalable Vector Extension>>
    • <<ARM A64 Instruction Set Architecture ARMv9, for Armv9-A architecture profile>>

Scalable Vector Instructions SVE/SVE2

  • SVE stands for Scalable Vector Extension
  • The first version was added in ARMv8.2, and the second version in ARMv9
  • SVE is a new vector instruction set developed for high-performance computing (HPC) and machine learning, serving as the next-generation SIMD instruction set implementation, andit is not a simple extension of the NEON instruction set
  • Many concepts in the SVE instruction set are similar to those in the NEON instruction set, such as vectors, lanes, and data elements
  • SVE introduces a new concept:Variable Vector Length Programming Model (Vector Length Agnostic,VLA)

SVE Registers

  • 32 new variable-length vector registers Z0 to Z31
  • 16 predicate registers P0~P15
  • First Fault predicate Register (FFR)
  • SVE control register ZCR_ELx

Set vector register length

Register typeNameQuantityLength per registerDescription
Z registersZ0–Z3132VL bitsVector data registers
P registersP0–P1516VL / 8 bitsPredicate registers (mask)
FFRFFR1VL / 8 bitsFirst-Fault Register

vector length is calledvector length

variable-length vector register

variable-length vector register
variable-length vector register

predicate register

predicate register
predicate register

SVE instruction syntax

  • SVE instruction format consists of opcode, destination register, predicate register, and input operands
1
LD1D {<Zt>.D}, <Pg>/Z, [<Xn|SP>, <Xm>, LSL #3]
1
ADD <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, <Zm>.<T>

SVE experimental environment

early Cortex-A cores

  • Cortex-A53 / A55 / A57 / A72 / A76 / A77 / A78
    • only supportsNEON(128-bit SIMD), does not support SVE or SVE2

QEMU

1
2
3
4
5
6
7
8
9
10
11
12
qemu-system-aarch64 -m 1024 -cpu max,sve=on,sve256=on -M virt,gic-version=3,its=on,iommu=smmuv3\
-nographic $SMP -kernel arch/arm64/boot/Image \
-append \"$kernel_arg $debug_arg $rootfs_arg $crash_arg $dyn_arg\"\
-drive if=none,file=$rootfs_image,id=hd0\
-device virtio-blk-device,drive=hd0\
--fsdev local,id=kmod_dev,path=./kmodules,security_model=none\
-device virtio-9p-pci,fsdev=kmod_dev,mount_tag=kmod_mount\
$DBG"


# compile, note that the -march=armv8-a+sve parameter must be added
gcc -g -march=armv8-a+sve -o hello hello_sve.S

SVE instruction
SVE instruction

SVE-specific programming mode 1: Predicate instructions

  • The SVE instruction set provides a governing predicate mechanism to support variable-length vector computation
  • Predicate instructions use the governing predicate mechanism to determine which data elements in the vector register are active. Only these active data elements are processed in predicate instructions; inactive data elements are not processed.
  • Example:

Governing predicate
Governing predicate

Merging predication and zeroing predication

  • Zeroing predication: In the destination vector register, the values of inactive data elements are filled with 0
  • Merging predication: In the destination vector register, the values of inactive data elements remain unchanged

Zeroing predication

Zeroing predication
Zeroing predication

Merging predication

Merging predication
Merging predication

SVE-specific programming mode 2: Gather-load and scatter-store

  • Supports gather-load and scatter-store modes
  • Gather-load and scatter-store refer to the ability toUse the value of each lane in the vector register as a base address or offset to achieve non-contiguous address loading and storing
  • The traditional NEON instruction set only supports linear address load and store operations.

Example: Gather load, loading values from multiple discrete addresses.

Gather load, loading values from multiple discrete addresses.
Gather load, loading values from multiple discrete addresses.

Scatter store

Scatter store
Scatter store

SVE-specific programming mode 3: Predicate-based loop control

  • Usingpredicate register Pninactive data elements as objects to implement loop control
  • PSTATE and NZCV status flags
  • The SVE instruction set provides the following groups of instructions related to loop control:
    • Instructions to initialize predicate registers, such as WHILELO, etc.
    • Instructions to increment element counts based on predicate constraints, such as INCB, etc.
    • Instructions that combine SVE condition opcodes with branch instructions to perform conditional branching, such as B.FIRST, etc.
    • Comparison instructions based on data elements, such as CMPEQ instruction, etc.
    • Loop termination instruction, such as BRKA instruction

PSTATE processor state and NZCV

  • The loop control method based on data elements can be organically combined with the processor state PSTATE
    • When SVE generates a prediction result, it updates the NZCV status flags of PSTATE
    • SVE instructions update the NZCV status flags of PSTATE based on the result of the predicate register or the FFR register
    • SVE instructions can also update the NZCV status flags of PSTATE based on the CTERMEQ/CTERMNE instructions

Processor status flags and SVE
Processor status flags and SVE

Initialize predicate register instruction

Similar to a C language while loop, given an initial value and a target value, using the number of data elements contained in a vector register as the step size, then traversing and initializing the data elements in the predicate register in an incrementing or decrementing manner

Initialize predicate register instruction
Initialize predicate register instruction

Taking whilelt as an example

1
whilelt  <pd>.<T>, <Rn>, <Rm>
  • <pd>: Destination predicate register (e.g., p0, p1)
  • <T>: Element type (e.g., .b, .h, .s, .d)
  • <Rn>: Starting index or count register
  • : end index or upper bound register
1
p[i] = (Rn + i*sizeof(T)/8 < Rm) ? 1 : 0
  • Starting from Rn, compare indices element by element;
  • As long as the current index is still “less than Rm”, set the correspondingpbit to 1;
  • Once exceeded, set to 0.
TypeElement bit widthIncrement per step (bytes)Example
.b8-bit11-byte aligned
.h16-bit22-byte aligned
.s32-bit44-byte aligned
.d64-bit88-byte aligned

Example

1
whilelt p0.b, xzr, x2
  • p0.b: b indicates that the number of register channels to be predicted is 8 bits wide
  • xzr is the starting value
  • x2 is the target value, incrementing from low to high until reaching x2 or until all values in the predicate register have been initialized

SVE condition opcode

SVE condition opcode
SVE condition opcode

Increment statistical count of data elements based on predicate constraints

Increment statistical count of data elements
Increment statistical count of data elements

Comparison instruction based on data elements as objects

Comparison instruction based on data elements as objects
Comparison instruction based on data elements as objects

Break loop instruction

  • BRKA instruction
1
BRKA <Pd>.B, <Pg>/<ZM>, <Pn>.B

break after

BRKA instruction
BRKA instruction

  • BRKB instruction
1
BRKB <Pd>.B, <Pg>/<ZM>, <Pn>.B

BRKB instruction
BRKB instruction

Experiment 2: Implement memcpy_1b() function using SVE instructions

Experiment 2
Experiment 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.global sve_ld1_test
// x0 = dest
// x1 = src
// x2 = size
sve_ld1_test:
mov x3, #0
// p0[i] = ((x3 + i) < x2) ? 1 : 0
whilelt p0.b, x3, x2
1:
// Use /z to avoid garbage values; all unloaded elements become 0
ld1b {z0.b}, p0/z, [x1, x3]
// Write all, no need for /z
st1b {z0.b}, p0, [x0, x3]
incb x3
whilelt p0.b,x3, x2
b.any 1b

ret

AssumeVLis 256, then p0 can describe at most 32 8-bit (B) count registers, so incb x3 will change x3 from 0 to 32 (32 bytes)

The instruction whilelt p0.b, x3, x2 sets p0.b to all 0s when x3=32

b.any means a branch is triggered as long as any element in the vector register is active

Experiment 3: Implement the memcpy_4b() function using SVE instructions

Experiment 3
Experiment 3

1
2
3
4
5
6
7
8
9
10
11
12
13
.global sve_ld1_test
sve_ld1_test:
lsr x2, x2, 2
mov x3, #0
whilelt p0.s, x3, x2
1:
ld1w {z0.s}, p0/z, [x1, x3, lsl 2]
st1w {z0.s}, p0, [x0, x3, lsl 2]
incw x3
whilelt p0.s, x3, x2
b.any 1b

ret

Process
Process

SVE-specific programming pattern 4: Software-based speculative vector partitioning

  • NEON does not support speculative load operations; SVE does
  • Challenge with speculative load operations: If some elements encounter a memory fault or access an invalid page during reading, it may be difficult to track which lane’s data read operation caused it
  • SVE introduces:
    • First-Fault predicate Register (FFR)
    • First-fault load instructions, such asLDFF1B

Example:

1
LDFF1D Z0.D, P0/Z, [Z1.D]

Using the value of each lane in the Z1.D register as the base address, load the element corresponding to that address into Z0

Using the value of each lane in the Z1.D register as the base address, load the element corresponding to that address into Z0
Using the value of each lane in the Z1.D register as the base address, load the element corresponding to that address into Z0

The third lane has an invalid address, directly mark it as a load failure without reporting to the CPU

SVE/SVE2 Instructions

  • SVE was introduced in ARMv8.2, and SVE2 was introduced in ARMv9
  • SVE/SVE2 Instruction Manual: <<Arm A64 Instruction Set Architecture Armv9, for Armv9-A architecture profile>>
  • The SVE instruction set contains hundreds of instructions, which can be divided into the following major categories
    • Load and store instructions and prefetch instructions
    • Vector move instructions
    • Integer arithmetic instructions
    • Bit manipulation instructions
    • Floating-point arithmetic instructions
    • Predicate operation instructions
    • Data element operation instructions
  • How to read the instruction manual:

Three types
Three types

Experiment 4: Case Study 1 - Using SVE Instructions to Optimize the strcmp Function

Experiment 4
Experiment 4

  • There are two difficulties in using SVE instructions to optimize strcmp():
    • Difficulty 1: The lengths of strings str1 and str2 are unknown. In C, the end of a string is determined by checking whether the character is ‘\0’. In vector operations, the SVE load instruction loads data from multiple lanes at once. If data beyond the end of the string is loaded, it will cause an illegal access, leading to program errors.
    • Difficulty 2: The tail handling problem
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
.global strcmp_sve
strcmp_sve:
ptrue p5.b // p5 = all-ones predicate register (with byte as element unit), used to indicate "process all byte lanes"
setffr // Initialize / clear the First-Fault Register (FFR) to prepare for fault-first loads

mov x5, #0 // x5 = byte offset index (starting from 0), used for offsetting both strings

l_loop:
ldff1b z0.b, p5/z, [x0, x5] // Perform fault-first byte load from (x0 + x5) into z0 (according to p5 lanes)
// If a fault such as an illegal access occurs, the FFR records the lanes that have been successfully loaded
ldff1b z1.b, p5/z, [x1, x5] // Similarly, load from (x1 + x5) into z1 (using fault-first as above)
rdffrs p7.b, p5/z // Read and clear the FFR, writing the "mask of successfully loaded lanes" into p7 (according to p5 lanes),
// so that we know how many lanes the two ldff1b instructions actually loaded successfully (if no fault, p7==p5)
b.nlast l_fault // If it is not the last block (i.e., a fault occurred or only part of the lanes were loaded), jump to l_fault to handle partial loading
// That is, if loading is interrupted or partially completed, the fault handling path must be taken

incb x5 // x5 += VL_bytes (increase offset by the current SVE vector length), prepare for the next full vector block
cmpeq p0.b, p5/z, z0.b, #0 // p0[i] = (z0[i] == 0) — detect if a NUL byte appears in s1
cmpne p1.b, p5/z, z0.b, z1.b // p1[i] = (z0[i] != z1[i]) — detect if the two string bytes differ
l_test:
orrs p4.b, p5/z, p0.b, p1.b // p4 = p0 OR p1; orrs also updates integer condition codes (NZ) for subsequent branches
// p4 indicates 'the termination condition (NUL or inequality) has been reached on this lane'
b.none l_loop // If no bit in p4 is true (i.e., none true), continue the loop to load the next vector block

l_retrun:
brkb p4.b, p5/z, p4.b // The purpose here is to process p4 into a form that facilitates extracting the 'first occurrence position'.
// A common practice is to place the bit to be extracted (the first true bit in the current block) into the last bit of the vector
// This allows the subsequent lasta instruction to directly extract the corresponding byte from that bit.

lasta w0, p4, z0.b // Extract the byte located by brkb from z0 into w0 (extracted into a 32-bit register)
// The function of lasta is to extract the corresponding element value based on the 'last active bit' of p4 (zero-extended or unsigned extended)
lasta w1, p4, z1.b // Same as above, extract the corresponding byte from z1 into w1
sub w0, w0, w1 // Calculate the difference w0 = (byte_from_z0) - (byte_from_z1), as the return value of strcmp
ret // return (return value in w0)

l_fault:
incp x5, p7.b // x5 += number of bytes successfully loaded (true bits indicated by p7, in bytes)
// Thus x5 points to the next position to process (the already processed part does not need to be read again)
setffr // Reinitialize/clear FFR to prepare for the next fault-first load
cmpeq p0.b, p7/z, z0.b, #0 // On the lanes just successfully loaded, compare whether z0 is 0 (only valid on lanes indicated by p7)
cmpne p1.b, p7/z, z0.b, z1.b // On the lanes just successfully loaded, compare whether z0 and z1 are not equal
b l_test // Jump back to the unified termination check (l_test will OR and decide whether to continue or go to the return path)

Procedure
Procedure

Case 5: RGB24 to BGR24

Case 5
Case 5

Case 6: 4×4 product matrix

Case 6
Case 6

Case 6
Case 6

Differences from Neon instructions

Differences from Neon instructions
Differences from Neon instructions

Differences in Neon instructions
Differences in Neon instructions

Summary: SVE instructions used above

  • whilelt/whilelo instructions
  • b.Any branch instructions
  • BRKA and BRKB instructions
  • LASTA instruction
  • LD1 and ST1 instructions
  • LD3 and ST3 instructions
  • FMLA instruction
  • INCB instructions
  • ld1ff1b instructions
  • Setffr and rdffrs instructions
  • Cmpeq and cmpne instructions
  • Mov instructions