Assembly (x86-64, AArch64, RISC-V) Module 10 – Floating point and SIMD
Vector-length-agnostic code: RVV, SVE and SME
Write loops that never name a vector width: vsetvli on RISC-V, whilelo predicates in SME streaming mode on Apple silicon, and a model of vl at four widths.
What you will learn
- Write a strip-mined RVV loop whose pass length comes from vsetvli
- Trace an SVE loop that uses whilelo predicates instead of a scalar tail
- Predict how many passes a loop takes from the vector length and the vl rule
- Explain the rules a function must follow around SME streaming mode
- Measure the vector length with rdsvl, cntw or vlenb
Before you start
What you’ll learn · Before you start
What you will learn
- Write a strip-mined RVV loop whose pass length comes from vsetvli
- Trace an SVE loop that uses whilelo predicates instead of a scalar tail
- Predict how many passes a loop takes from the vector length and the vl rule
- Explain the rules a function must follow around SME streaming mode
- Measure the vector length with rdsvl, cntw or vlenb
Before you start
On this page
The NEON loop of the previous lesson names four 32-bit lanes in every instruction, so 40 elements take 10 passes on any core, even one whose vector unit could take 16 at once. vector-length-agnostic code: Vector code that never states how many lanes a vector holds: every pass asks the hardware how many elements it may handle and moves on by that many, so one binary uses the full width of any core. code never names the width: each pass asks the hardware how many elements it may handle and moves on by that many, so one binary fills a 128-bit unit or a 2,048-bit one.
Two instruction sets work this way. RISC-V’s vector extension, RVV, returns the length of each pass from vsetvli,
and AArch64’s SVE marks the lanes still inside the array in a predicate. Apple silicon runs SVE instructions inside
SME’s streaming mode, where the run below adds 40 elements in 3 passes of 16, 16 and 8 lanes.
A vector-length-agnostic loop asks for its lanes on every pass
A fixed-width loop states its vector length: The width of a vector register on a given core, in bits or bytes. Fixed-width SIMD sets it in the instruction; SVE and the RISC-V V extension leave it to the implementation and let code read it at run time. in the code: .4s means four lanes, so
it runs n / 4 vector passes and a loop tail: The leftover iterations of a vector loop that handle fewer elements than one vector pass covers, usually run as a short scalar loop. More in “Your first SIMD loop” finishes the rest. A vector-length-agnostic loop
keeps the body but starts each pass by asking how many elements it may take, and ends it by moving the index on by
the answer. The last pass is simply shorter, so no tail exists, and a wider core runs the same instructions fewer
times.
Key idea
| Loop | Lanes a pass | Passes for 40 | Last elements |
|---|---|---|---|
| NEON, previous lesson | 4 | 10 | a scalar tail |
| SVE in streaming mode | 16 | 3 | a predicated pass of 8 |
| RVV at VLEN 512 (model) | 16 | 3 | a pass with vl 8 |
Code that needs the number can read it: cntw or rdvl on SVE, rdsvl for streaming mode and the vlenb
register on RVV.
Checkpoint
Check: Asking for the lanes on every pass
SVE marks the lanes still inside the array
whilelo p0.s, x5, x3 writes a predicate register: A register that marks which vector lanes an instruction acts on. SVE has p0 to p15, with one bit for each byte of a vector register, so a 32-bit lane has four bits and its lowest one counts; AVX-512 has the mask registers k0 to k7, one bit per lane. in which lane j is active while
i + j < n. Loads under p0 set the inactive lanes to zero and never fault on them, stores leave memory there
unwritten, incw moves i on by one vector of 32-bit lanes and b.first loops while lane 0 is active.
sve/vla_add.s
// A vector-length-agnostic int32 add: SVE instructions in SME streaming mode (AArch64, Apple silicon).
//
// uint64_t vla_add(int32_t *c, const int32_t *a, const int32_t *b, uint64_t n, uint64_t *active)
// c[i] = a[i] + b[i] for every i < n, nothing else in c is written;
// active[k] = how many lanes pass k used; the return value is the number of passes.
//
// No lane count appears in the loop. whilelo marks the lanes whose index is still below n, and
// incw moves i on by however many 32-bit lanes one vector holds on the machine that runs it.
// smstart and smstop reset the vector registers, so the callee-saved d8-d15 (AAPCS64) wait on the
// stack, and the pass count is in a general register before smstop.
.text
.p2align 2
.arch_extension sme
.arch_extension sve
.globl _vla_add
_vla_add:
stp d8, d9, [sp, #-64]!
stp d10, d11, [sp, #16]
stp d12, d13, [sp, #32]
stp d14, d15, [sp, #48]
smstart sm // streaming mode: SVE instructions are legal until smstop
mov x5, #0 // i: the first element of this pass
mov x6, #0 // passes so far
whilelo p0.s, x5, x3 // lane j is active while i + j < n
b.none 2f // no active lane (n = 0): no pass at all
1: ld1w {z0.s}, p0/z, [x1, x5, lsl #2] // active lanes of a; inactive lanes become 0
ld1w {z1.s}, p0/z, [x2, x5, lsl #2] // active lanes of b
add z0.s, z0.s, z1.s
st1w {z0.s}, p0, [x0, x5, lsl #2] // only the active lanes reach memory
cntp x7, p0, p0.s // the lanes this pass used
str x7, [x4, x6, lsl #3] // active[passes] = x7
add x6, x6, #1
incw x5 // i += the 32-bit lanes of one vector
whilelo p0.s, x5, x3 // the predicate for the next pass
b.first 1b // go on while lane 0 is active
2: smstop sm
ldp d14, d15, [sp, #48]
ldp d12, d13, [sp, #32]
ldp d10, d11, [sp, #16]
ldp d8, d9, [sp], #64
mov x0, x6
ret
// uint64_t svl_bytes(void): the streaming vector length in bytes. rdsvl needs no streaming mode.
.globl _svl_bytes
_svl_bytes:
rdsvl x0, #1
ret vla_main.c
// Runs vla_add (sve/vla_add.s) for six lengths and checks every element of c against a plain C loop,
// including the elements after n, which must keep the -1 the driver put there.
// Build: clang -O1 -o vla vla_main.c sve/vla_add.s
#include <stdint.h>
#include <stdio.h>
uint64_t vla_add(int32_t *c, const int32_t *a, const int32_t *b, uint64_t n, uint64_t *active);
uint64_t svl_bytes(void);
enum { MAX = 40 };
int main(void) {
int32_t a[MAX], b[MAX], c[MAX];
uint64_t active[MAX];
const uint64_t sizes[] = {0, 1, 10, 16, 17, 40};
for (int i = 0; i < MAX; i++) {
a[i] = i + 1;
b[i] = 100 * (i + 1);
}
uint64_t bytes = svl_bytes();
printf("streaming vector: %llu bytes = %llu lanes of 32 bits\n", (unsigned long long)bytes,
(unsigned long long)(bytes / 4));
printf(" n passes lanes per pass check\n");
for (unsigned k = 0; k < sizeof sizes / sizeof sizes[0]; k++) {
uint64_t n = sizes[k];
for (int i = 0; i < MAX; i++) c[i] = -1; // a store past n would show up here
uint64_t passes = vla_add(c, a, b, n, active);
int ok = 1;
for (uint64_t i = 0; i < MAX; i++) ok &= c[i] == (i < n ? a[i] + b[i] : -1);
char lanes[64] = "-";
int len = 0;
for (uint64_t p = 0; p < passes; p++)
len += snprintf(lanes + len, sizeof lanes - (size_t)len, p ? ", %llu" : "%llu",
(unsigned long long)active[p]);
printf("%3llu %6llu %-14s %s\n", (unsigned long long)n, (unsigned long long)passes, lanes,
ok ? "ok" : "WRONG");
}
return 0;
} Apple silicon runs these instructions only in SME’s streaming mode: A processor state that SME adds to AArch64, entered with smstart sm and left with smstop sm, in which SVE instructions run at a streaming vector length of its own. More in “SIMD concepts and CPU feature detection”, entered with
smstart sm and left with smstop sm. The mode has rules of its own: the switch resets the vector registers, so the
function saves d8 to d15 first, and NEON instructions are not allowed inside it on the host.
import pathlib
import sys
sys.path.insert(0, str(pathlib.Path(__file__).parent / "sessions"))
import session
# Build the streaming SVE add with its C driver and run it on Apple silicon (AArch64 macOS).
session.run("""
clang -O1 -o vla vla_main.c sve/vla_add.s
./vla
""") Output
$ clang -O1 -o vla vla_main.c sve/vla_add.s $ ./vla streaming vector: 64 bytes = 16 lanes of 32 bits n passes lanes per pass check 0 0 - ok 1 1 1 ok 10 1 10 ok 16 1 16 ok 17 2 16, 1 ok 40 3 16, 16, 8 ok
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 vla_add_session.py
The streaming vectors are 64 bytes, 16 lanes of 32 bits. Lengths up to 16 take one pass, 17 takes two (16 and 1) and
40 takes three. The driver fills c with -1 first, so a store past n would fail the check.
The drawing shows the whole scene; its 5 steps are listed below.
Every step as text
- whilelo builds the first mask. Before the loop, whilelo p0.s, x5, x3 tests i + j < n for every lane j. With i = 0 and n = 40 all 16 lanes pass, so p0 marks them all active. No instruction in the loop names the number 16.
- Pass 1 handles 16 elements. ld1w loads a[0] to a[15] and b[0] to b[15] under p0, add sums the 16 lanes and st1w stores them. cntp counts 16 active lanes, the first number in the 16, 16, 8 of the run.
- incw moves i on by one vector. incw x5 adds the number of 32-bit lanes in one vector, 16 on the host, so i becomes 16. whilelo again finds every lane below 40, and b.first sees lane 0 active and branches back.
- The last pass is partial. At i = 32 only lanes 0 to 7 satisfy i + j < 40. Lanes 8 to 15 are inactive: ld1w sets them to zero and cannot fault on them, and st1w leaves memory there unwritten. The pass handles 8 elements.
- No active lane ends the loop. incw makes i = 48. whilelo finds no lane below 40 and clears the First flag, so b.first falls through to smstop. Three passes in all, and every element of c matches the plain C sum.
Checkpoint
Check: SVE predicates and whilelo
RVV returns the pass length from vsetvli
vsetvli t0, a3, e32, m1, ta, ma gets a3, the elements still to do, asks for 32-bit elements and writes into t0
the length of this pass, vl. A pass holds at most VLMAX = LMUL × VLEN / SEW elements, where VLEN is the register
width the core was built with. The assembler refuses V instructions unless it is told the target has V.
# A vector-length-agnostic int32 add for RV64 with the V extension (Linux, LP64D).
#
# void vla_add(int32_t *c, const int32_t *a, const int32_t *b, size_t n)
# a0 = c, a1 = a, a2 = b, a3 = the elements still to add (the application vector length, AVL)
#
# Each pass starts with vsetvli, which returns in t0 how many elements this pass handles (vl).
# The code never states the register width: vl is at most VLMAX = LMUL * VLEN / SEW, where VLEN is
# the machine's vector register width. With n = 0, vl is 0, nothing is loaded or stored, and the
# loop ends after one pass that does nothing.
.text
.p2align 2
.globl vla_add
vla_add:
1: vsetvli t0, a3, e32, m1, ta, ma # 32-bit elements, one register per operand
vle32.v v0, (a1) # vl elements of a
vle32.v v1, (a2) # vl elements of b
vadd.vv v0, v0, v1
vse32.v v0, (a0) # vl sums into c
sub a3, a3, t0 # elements left
slli t1, t0, 2 # 4 bytes per element
add a1, a1, t1
add a2, a2, t1
add a0, a0, t1
bnez a3, 1b
ret import pathlib
import sys
sys.path.insert(0, str(pathlib.Path(__file__).parent / "sessions"))
import session
# RISC-V (RV64 with V, Linux): the assembler needs the extension named, then reads the loop back.
session.run("""
llvm-mc --triple=riscv64-linux-gnu -filetype=obj -o add.o riscv/vla_add.s 2>&1 | grep -m 1 -o "instruction requires the following: 'V'"
llvm-mc --triple=riscv64-linux-gnu -mattr=+v -filetype=obj -o add.o riscv/vla_add.s && echo "assembled"
llvm-objdump -d --mattr=+v add.o | sed -n '/<vla_add>:/,$p'
""") Output
$ llvm-mc --triple=riscv64-linux-gnu -filetype=obj -o add.o riscv/vla_add.s 2>&1 | grep -m 1 -o "instruction requires the following: 'V'"
instruction requires the following: 'V'
$ llvm-mc --triple=riscv64-linux-gnu -mattr=+v -filetype=obj -o add.o riscv/vla_add.s && echo "assembled"
assembled
$ llvm-objdump -d --mattr=+v add.o | sed -n '/<vla_add>:/,$p'
0000000000000000 <vla_add>:
0: 0d06f2d7 vsetvli t0, a3, e32, m1, ta, ma
4: 0205e007 vle32.v v0, (a1)
8: 02066087 vle32.v v1, (a2)
c: 02008057 vadd.vv v0, v0, v1
10: 02056027 vse32.v v0, (a0)
14: 405686b3 sub a3, a3, t0
18: 00229313 slli t1, t0, 0x2
1c: 006585b3 add a1, a1, t1
20: 00660633 add a2, a2, t1
24: 00650533 add a0, a0, t1
28: fc069ce3 bnez a3, 0x0 <vla_add>
2c: 00008067 ret
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 rvv_add_session.py
The specification sets vl to AVL, the elements left, when AVL ≤ VLMAX, and to VLMAX when AVL ≥ 2 × VLMAX. In
between, a core may pick any vl from half of AVL, rounded up, to VLMAX. The model below applies that rule to 40
elements at four widths; it models the specification and runs no RISC-V code.
"""How many elements each vsetvli pass gets, for 40 elements of 32 bits at four vector widths.
A model of the rule in the RISC-V V 1.0 specification ("Constraints on Setting vl"), not a run on RISC-V
hardware. With AVL elements left and VLMAX = LMUL * VLEN / SEW:
vl = AVL when AVL <= VLMAX
ceil(AVL / 2) <= vl <= VLMAX when VLMAX < AVL < 2 * VLMAX (the implementation chooses)
vl = VLMAX when AVL >= 2 * VLMAX
The model prints both ends of the choice and then tries every legal choice to count the passes.
"""
import math
N = 40 # elements to process
SEW = 32 # bits per element
LMUL = 1 # registers per operand
VLENS = (128, 256, 512, 1024) # register widths an implementation may have
def legal_vls(avl: int, vlmax: int) -> range:
"""Every vl the rule allows for this pass."""
if avl <= vlmax:
return range(avl, avl + 1)
if avl < 2 * vlmax:
return range(math.ceil(avl / 2), vlmax + 1)
return range(vlmax, vlmax + 1)
def passes(avl: int, vlmax: int, pick) -> list[int]:
"""The vl of every pass when the implementation picks with `pick` (min or max) each time."""
out = []
while avl > 0:
vl = pick(legal_vls(avl, vlmax))
out.append(vl)
avl -= vl
return out
def every_count(avl: int, vlmax: int) -> set[int]:
"""The pass counts over every sequence of legal choices."""
if avl == 0:
return {0}
return {1 + rest for vl in legal_vls(avl, vlmax) for rest in every_count(avl - vl, vlmax)}
def show(vls: list[int]) -> str:
return ", ".join(str(vl) for vl in vls)
print(f"n = {N} elements, SEW = {SEW}, LMUL = {LMUL}")
for vlen in VLENS:
vlmax = LMUL * vlen // SEW
widest = passes(N, vlmax, max)
even = passes(N, vlmax, min)
counts = every_count(N, vlmax)
print(f"VLEN {vlen:4}: VLMAX {vlmax:2}")
print(f" largest vl first: {show(widest)}")
print(f" smallest legal vl: {show(even)}")
print(f" passes with any legal choice: {sorted(counts)} (ceil(n / VLMAX) = {math.ceil(N / vlmax)})") Output
n = 40 elements, SEW = 32, LMUL = 1 VLEN 128: VLMAX 4 largest vl first: 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 smallest legal vl: 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 passes with any legal choice: [10] (ceil(n / VLMAX) = 10) VLEN 256: VLMAX 8 largest vl first: 8, 8, 8, 8, 8 smallest legal vl: 8, 8, 8, 8, 8 passes with any legal choice: [5] (ceil(n / VLMAX) = 5) VLEN 512: VLMAX 16 largest vl first: 16, 16, 8 smallest legal vl: 16, 12, 12 passes with any legal choice: [3] (ceil(n / VLMAX) = 3) VLEN 1024: VLMAX 32 largest vl first: 32, 8 smallest legal vl: 20, 20 passes with any legal choice: [2] (ceil(n / VLMAX) = 2)
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 vl_model.py
The pass count stays ceil(40 / VLMAX) whatever the core picks: 10, 5, 3 and 2. LMUL above 1
register grouping: Treating several consecutive vector registers as one operand. In the RISC-V V extension, LMUL sets how many registers form a group, so one instruction handles more elements in each pass. to lengthen each pass. The
tail and mask policy: The rule for vector elements an instruction does not compute: those past the vector length (the tail) and those its mask turns off. Undisturbed keeps their old values; agnostic lets the hardware keep them or fill them with all 1s. ta, ma let the hardware fill elements past vl, and
masked-off ones, with all 1s. Linux documents how it saves and controls this vector state for each thread.
Checkpoint
Check: vsetvli and the vl rule
Practise
Work on copies of the lesson’s files and write each prediction down before you run.
- In
vla_main.c, add 33 and 48 tosizes, raiseMAXto 48, and predict the passes and the lanes of each. - In
vl_model.py, setN = 100and predict the passes at VLEN 128 and at VLEN 512. - Set
LMUL = 2invl_model.pyand predict VLMAX and the passes at VLEN 256.
Practice that adapts to you
Practise this lesson
8 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.
SME streaming mode on Apple silicon, rule by rule Pro: opens with a Pro, Premium or Ultimate pass
Streaming mode is how Apple silicon runs SVE instructions, and it brings rules that a plain SVE core does not have. Each rule below is a recorded run on the host: how long a vector is, what traps, what a mode switch erases and what a predicated pass may touch.
In this part:
- Measuring the vector length inside and outside streaming mode
- Advanced SIMD inside streaming mode ends the process
- What a mode switch erases, reproduced
- Which side of a call switches the mode
- A predicated last pass next to a guard page
3 runnable examples (Python, S) · about 6 minutes
Opening this part with your pass…
This part opens with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so this part can’t be opened at the moment. The free part above stands on its own. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
RVV in depth: vtype fields, LMUL and loops checked at four widths Pro: opens with a Pro, Premium or Ultimate pass
The RVV add above used one register per operand and never looked at its policy bits. The sections below decode those fields, double the pass length with LMUL, check three classic loops at four vector widths, reproduce a bug that only narrow cores show and compare the three loop styles of this lesson.
In this part:
- What e32, m1, ta and ma tell the hardware
- LMUL 2 halves the passes
- Three loops checked at four widths
- A pointer bug that narrow cores show
- Choosing among NEON, streaming SVE and RVV
3 runnable examples (Python, S) · about 8 minutes
Opening this part with your pass…
This part opens with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so this part can’t be opened at the moment. The free part above stands on its own. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
Interview questions
Why does a vector-length-agnostic loop need no scalar tail?
Because every pass asks the hardware how many elements it may handle, and the last pass is simply told fewer. On
RVV, vsetvli returns vl = AVL once the elements left fit in one pass, so the last pass handles exactly what
remains. On SVE, whilelo marks only the lanes whose index is below n: loads give 0 in the other lanes and stores
skip them. In the recorded run, 40 elements on 16 lanes took passes of 16, 16 and 8 with no second loop.
Three longer questions follow the same loops into code that a team has to ship:
-
Mid to senior
A NEON loop is ported to streaming SVE on Apple silicon by putting smstart sm and smstop sm around it and rewriting its adds. It ends with SIGILL at once; once that is fixed, a caller finds that a double it kept in d8 has become 0. Explain both failures and the rules the fixed function follows.
-
Mid to staff
An RVV saxpy passes every test on a board with VLEN 1024 but gives wrong results on a VLEN 128 board that the team cannot reach. How do you find the bug without the narrow board, and how do you test vector-length-agnostic code so that a bug that depends on the width cannot hide?
-
Senior to staff
An RVV routine counts matching int32 values with vmseq.vx and vcpop.m after a vsetvli with ta, ma. A colleague fears that the agnostic tail of the mask can hold 1s and inflate the count. Is the fear justified for this code, and which change to the code would make it justified?
Flashcards · 5 cards
Recall it, then check
Say the answer to yourself before you look: recalling it is what makes it stick.
-
What makes a loop vector-length-agnostic?
Every iteration asks the hardware how many elements it may handle, handles them, and moves the index on by that number until nothing is left. One binary then uses the full width of any core.
-
How does SVE handle the last, partial vector of a loop?
whilelo builds a predicate marking only the lanes whose index is still below n. Loads give 0 in the other lanes and stores skip them, so no scalar tail is needed.
-
What does RVV's vsetvli return, and what happens on the last iteration?
vl, the number of elements this iteration will handle. Once the remaining count fits in one vector, vl equals it, so the last iteration handles exactly what remains.
-
A vector-length-agnostic loop adds 40 elements on a core with 16 lanes. How do the iterations split?
16, 16 and 8 lanes, three iterations and no second loop for the tail.
-
What does a predicate register do?
It marks which vector lanes an instruction acts on. SVE has p0 to p15, with one bit per byte of a vector register; AVX-512 has the mask registers k0 to k7, one bit per lane.
Key takeaways
- A vector-length-agnostic loop asks the hardware for the length of each pass and moves on by that many, so one binary fits any vector width.
- SVE’s
whilelobuilds a predicate of the lanes still inside the array, and inactive lanes never fault on a load and are never stored. - Apple silicon runs SVE instructions in SME streaming mode, where the recorded loop added 40 int32 values in passes of 16, 16 and 8 lanes.
- RVV’s
vsetvlireturnsvl, at most LMUL × VLEN / SEW, and any legal choice ofvlkeeps the pass count atceil(n / VLMAX).
Terms in this lesson
- predicate register
- A register that marks which vector lanes an instruction acts on. SVE has p0 to p15, with one bit for each byte of a vector register, so a 32-bit lane has four bits and its lowest one counts; AVX-512 has the mask registers k0 to k7, one bit per lane.
- register grouping
- Treating several consecutive vector registers as one operand. In the RISC-V V extension, LMUL sets how many registers form a group, so one instruction handles more elements in each pass.
- tail and mask policy
- The rule for vector elements an instruction does not compute: those past the vector length (the tail) and those its mask turns off. Undisturbed keeps their old values; agnostic lets the hardware keep them or fill them with all 1s.
- vector length
- The width of a vector register on a given core, in bits or bytes. Fixed-width SIMD sets it in the instruction; SVE and the RISC-V V extension leave it to the implementation and let code read it at run time.
- vector-length-agnostic code
- Vector code that never states how many lanes a vector holds: every pass asks the hardware how many elements it may handle and moves on by that many, so one binary uses the full width of any core.
References
- Arm A-profile A64 Instruction Set Architecture (WHILELO, LD1W, ST1W, INCW, CNTW, CNTP, RDSVL, SMSTART, SMSTOP, MSR immediate) (Arm Limited)
- Arm A64 shared pseudocode: SetPSTATE_SM and ResetSVEState (Arm Limited)
- RISC-V Ratified Specifications: Vector Extension V 1.0 (vtype, vsetvli, constraints on setting vl, vlenb) (RISC-V International)
- Procedure Call Standard for the Arm 64-bit Architecture (AAPCS64) (Arm Limited)
- Linux kernel documentation: Scalable Vector Extension support for AArch64 Linux (The Linux Kernel documentation)
- Linux kernel documentation: Scalable Matrix Extension support for AArch64 Linux (The Linux Kernel documentation)
- Linux kernel documentation: Vector Extension support for RISC-V Linux (The Linux Kernel documentation)
- Determining instruction set characteristics (Apple Inc.)
- macOS manual: signal(3) (Apple Inc.)
- LLVM Project: llvm-mc and llvm-objdump (The LLVM Project)
Report a problem with this lesson
Kept only in this browser. Your Learn progress