core.intrinsics — Compiler intrinsics
The compiler-provided bridge between Verum code and CPU/runtime operations. Higher-level stdlib modules wrap these with safe APIs; this page enumerates the raw surface for runtime authors, driver writers, and micro-optimisation specialists.
~700 public intrinsics across 26 files, grouped by category.
| Category | File | Rough count |
|---|---|---|
| Arithmetic | arithmetic.vr | 100+ |
| Bitwise | bitwise.vr | 40+ |
| Float | float.vr | 100+ |
| Atomic | atomic.vr | 80+ |
| Memory | memory.vr | 50+ |
| Type info | type_info.vr | 10 |
| Conversion | conversion.vr | 40+ |
| Control | control.vr | 20 |
| Platform | platform.vr | 10 |
| SIMD | simd.vr | 10 |
| Tensor | tensor.vr | 70+ |
| GPU | gpu.vr | 50+ |
| Runtime | runtime/*.vr | 80+ |
| Low-level | lowlevel/*.vr | 90+ |
Annotations you will see:
@vbc_direct_lowering— VBC has a dedicated opcode.@llvm_only— only available when lowered to LLVM (not in the VBC interpreter).@requires_runtime— needs a specific runtime feature (threads, etc.).@inline(always)— compiler will always inline.@target_feature("…")— requires a specific CPU feature.
Declared but not implemented — 288 keys
The table below covers core/intrinsics/**, the canonical home. It is not
the whole picture: 288 distinct @intrinsic("verum.…") keys declared
across core/ have no implementation anywhere in crates/, and calling
one is a runtime trap on both tiers —
Panic: @intrinsic("verum.x25519.scalar_mult") is not implemented in this
build (called from scalar_mult); it has no registry entry, so there is no
value to return
That abort is deliberate and recent: an unregistered key used to lower to a
silent nil, which is how a signature routine could "succeed" and return
nothing. Refusing to fabricate a result is the correct behaviour; the gap it
reports is real.
The largest families, by declared-key count:
| Family | Keys | What it gates |
|---|---|---|
verum.crypto.* | 60 | accelerated digest/cipher backends |
verum.libm_deterministic.* | 42 | reproducible float maths (core.math.ieee754_deterministic) |
verum.compress.* | 17 | gzip / zstd / lz4 / brotli |
verum.quic.* | 17 | QUIC transport |
verum.tls.* | 17 | TLS record layer |
verum.k8s.* | 12 | Kubernetes client |
verum.p256.* | 12 | NIST P-256 |
verum.bpf.* | 11 | eBPF program loading |
verum.spiffe.* | 11 | SPIFFE identity |
verum.h3.* | 10 | HTTP/3 |
verum.pq.* | 9 | ML-KEM / ML-DSA |
verum.qpack.* | 9 | QPACK header compression |
The full list is a tracked artefact — scripts/ci/intrinsic_keys_unimplemented.txt
— frozen by a ratchet so the set cannot grow unnoticed, and a key leaves it
the moment something implements it. A second gate refuses to let a
documentation page call a primitive "Production" while its key is still on
that list.
What this means when reading the rest of this page. A module whose
surface is documented here can still be unreachable at run time if its
backend key is on that list: the documentation describes the declared
contract, the roster says which contracts have an implementation behind
them. Where a page knows its own backend is missing it says so in a banner
— ecc is the worked example.
Conformance status by submodule
Statuses follow the status convention; the
per-module deep findings live in core-tests/intrinsics/<module>/audit.md.
"Both tiers" means the suite passes under verum test --interp AND --aot.
| Submodule | Status | State |
|---|---|---|
arithmetic | ⚠️ partial | Interp green core (129 live). ARITH-PURE-BODY-1: the 14 historically-nil intrinsics (widening_mul, carrying_add, borrowing_sub, checked_shl/shr/rem/next_power_of_two, overflowing_neg/shl/shr, saturating_div, ilog10, leading_sign_bits, is_power_of_two) are now pure Verum bodies over the registered primitives — full 14-function battery green on the v20 bake. AOT sweep pending. |
bitwise | ✅ complete | Both tiers green (127/127). |
float | ⚠️ partial | Interp 85 live; 7 pins (roundeven/rint/nearbyint, minimum/maximum, is_subnormal/sign classify need opcodes); AOT libm cluster open (fneg/fms, hypot/cbrt/expm1/log1p/powi). |
memory | ⚠️ partial | Value-level operations and the raw-pointer bridge are covered. memcpy, memmove, memset, memcmp and secure_zero accept either an integer address or a pointer, and ptr_is_aligned_to is available. |
atomic | ⚠️ partial | Interp 30/30; AOT 25/30 (compare-and-swap (observed, succeeded) tuple under AOT — ATOMIC-CAS-AOT). |
type_info | ⚠️ partial | T.size/T.bits/… property surface complete both tiers (102 tests). The legacy meta-fn forms (size_of<T>(), align_of<T>()) are @deprecated and return 0 through every path — use the type-property syntax. |
conversion | ⚠️ partial | Endian byte results have representation failures in the interpreter and AOT; see byte conversion limitations. Float32 bit reinterpretation also has an AOT limitation. |
control | ⚠️ partial | Both tiers 36/36; 1 pin (generic expect<T> result mis-tag under arithmetic). |
platform | ✅ complete | Both tiers green. |
tensor | ⚠️ partial | The full surface runs under the interpreter with real CPU kernels, and its conformance suite passes with nothing skipped. The wire format every tensor intrinsic uses — [dst][mode?][arg-registers] — is now one authority shared by the emitter and the interpreter; an earlier audit found roughly thirty of seventy operations had drifted from it, which is why the op tables on this page are verified against the enums rather than maintained by hand. Ahead of time: the core operations (new, fill, from_slice, element access, binop, unop, matmul, reduce, reshape, transpose, softmax, clone) compile to real code; every other operation raises a runtime error naming itself rather than failing at link time. |
simd / gpu | ❔ undocumented | Neither surface is documented yet. simd is waiting on a name-resolution defect that makes intrinsic lookup non-deterministic, and on the splat and reduce operations landing; gpu is waiting on a correction to its operand shape and on its first conformance suite. Treat both as unavailable rather than as untested. |
lowlevel/* | ⚠️ partial | Arch files (x86_64/aarch64/kernel/mmio) audit-only (privileged/@llvm_only). The umbrella's cross-platform surface (CpuCapabilities, detect_capabilities(), SIMD width constants) is suite-covered; CFG-CONST-SELECT-1 pinned (@cfg on const items takes the fallback branch — MAX_SIMD_WIDTH = 128 on aarch64). |
runtime/tier,time,text,mem_raw,cbgr | ⚠️ partial | Full suites, interp green; see audits for per-module AOT residuals. |
runtime/sync | ⚠️ partial | Interpreter controls and targeted AOT checks under --exact cover the declared reference-tier and mutability signatures. |
runtime/os | ⚠️ partial | Unit + integration + property laws (round-trip identity over a UTF-8 domain, seek algebra, delete lifecycle) — 9/9 interp. |
runtime/io | ⚠️ partial | Unit + engine-algebra property laws (fd-free drift probes) — 6/6 interp. Registration surface belongs to the net suites. |
runtime/tls | ⚠️ partial | Slot algebra and absent-slot behaviour have regression controls: reading an absent slot returns a null pointer. |
runtime/scripting | ⚠️ partial | Interpreter controls cover outcome classification, sticky last_error_kind, globals, sandbox fuel and List marshaling. AOT reports failed outcome kind 4 because it has no compiler hook. |
runtime/async_ops / runtime/syscall | ❔ undocumented | Deliberate audit-only exceptions: async surface is conformance-tested at core-tests/async/intrinsics/; raw syscalls are a portability landmine (platform-specific numbers). |
mod umbrellas | ⚠️ partial | Explicit re-export lists pinned green. UMBRELLA-REEXPORT-RESOLVE-1: wildcard re-exports through umbrella brace-mounts resolve NONDETERMINISTICALLY per run (map-walk name index) — acceptance blocks committed in the suites. |
Open cross-cutting classes: MEM-PTR-DEREF-TIER0-1,
UMBRELLA-REEXPORT-RESOLVE-1, ARCHIVE-GENERIC-BODY-NIL-1 (baked generic
bodies vs local twins — fixed by SERIALIZE-STUB-IDENTITY-1/v20 for the
arithmetic battery; broader sweep pending), LITERAL-SIZED-ALIAS-COERCE-1
(bare Int literals vs USize/ISize params of baked free fns),
CFG-CONST-SELECT-1, INTERP-SWEEP-ISOLATION-1 (threads=16 cross-test
pollution).
Arithmetic
Generic arithmetic over T: Numeric. Multiple flavours cover
checked / wrapping / saturating / overflowing semantics.
// Basic
add<T>(a: T, b: T) -> T sub<T>(a, b) -> T mul<T>(a, b) -> T
div<T>(a, b) -> T rem<T>(a, b) -> T neg<T>(a) -> T
abs<T>(a) -> T signum<T>(a) -> T
// Checked — return Maybe<T>; None on overflow
checked_add<T>(a, b) -> Maybe<T> checked_sub / checked_mul / checked_div
checked_rem / checked_neg / checked_shl / checked_shr
// Overflow-reporting — returns (result, overflowed: Bool)
overflowing_add<T>(a, b) -> (T, Bool)
overflowing_sub / overflowing_mul / overflowing_neg
overflowing_shl / overflowing_shr
// Wrapping — modular arithmetic, no overflow
wrapping_add<T>(a, b) -> T wrapping_sub / wrapping_mul
wrapping_neg / wrapping_abs / wrapping_shl / wrapping_shr
// Saturating — clamp at T.MIN / T.MAX
saturating_add<T>(a, b) -> T saturating_sub / saturating_mul / saturating_div
saturating_neg / saturating_abs
// Comparison
eq<T>(a, b) -> Bool ne / lt / le / gt / ge
min<T>(a, b) -> T max<T>(a, b) -> T clamp<T>(x, lo, hi) -> T
// Wide arithmetic
widening_mul<T>(a, b) -> (T, T) // low, high
widening_mul_signed<T>(a, b) -> (T, T)
carrying_add<T>(a, b, carry: Bool) -> (T, Bool)
borrowing_sub<T>(a, b, borrow: Bool) -> (T, Bool)
// Utilities
leading_sign_bits<T>(a) -> Int
ilog2<T>(a) -> Int ilog10<T>(a) -> Int
is_power_of_two<T>(a) -> Bool
checked_next_power_of_two<T>(a) -> Maybe<T>
wrapping_next_power_of_two<T>(a) -> T
Width-specific variants (e.g. wrapping_add_u32, saturating_mul_u8)
are provided to avoid generic instantiation in hot paths.
Panic conditions on the trapping forms
The non-checked / non-wrapping / non-saturating operations
panic on the inputs below. Use the checked_* family to recover
without panicking.
| Op | Panics on (signed integer T) | Float behaviour |
|---|---|---|
add / sub / mul | overflow / underflow | IEEE 754 — saturates to ±inf |
div | b == 0; also T.MIN / -1 (mathematical result is unrepresentable) | x / 0.0 = ±inf; 0.0 / 0.0 = NaN |
rem | b == 0; T.MIN % -1 | IEEE 754 |
neg / abs | T.MIN (mathematical result ` | T.MIN |
wrapping_div / wrapping_rem | b == 0 (the T.MIN / -1 pair wraps instead of panicking) | n/a |
signum is total: returns -1 / 0 / 1 for ints; for float
NaN it returns NaN. add / sub / mul on unsigned T are the
ordinary modular operations on bit widths and never panic from
overflow.
Conformance status — arithmetic ⚠️ partial
Suite: core-tests/intrinsics/arithmetic/
(unit + property + integration + regression + audit.md).
106 live tests GREEN under --interp; 42 @ignore pins.
Verified (interp): add sub mul div rem neg abs
abs_signed signum; checked_add/sub/mul/div (+ _u64);
add_overflow sub_overflow mul_overflow and the
overflowing_add/sub/mul aliases; wrapping_add/sub/mul/neg/shl/shr
(Int) and the width-specific wrapping_*_u8/_i8/_u32;
saturating_mul/neg/abs and saturating_*_u8/_u16/_u32/_i32;
min max clamp; ilog2. Ring/order algebraic laws pinned by
the property suite.
Arithmetic lowering:
- Comparison wrappers
eq/ne/lt/le/gt/ge—emit_intrinsic_direct_opcodehad no arm for theEqI/NeI/LtI/LeI/GtI/GeIDirectOpcodes, so these Bool-returning wrappers fell through to aLoadNilfallback (nil stub). Now emitCmpI. GREEN. overflowing_add/sub/mul— added the missing registry aliases (they had no entry and silently lowered tonil). GREEN.checked_neg/checked_abswidth — the generic forms now emit thewidth=64, signed=1bytes the interpreter'sCheckedNeg/CheckedAbshandlers read (correct for AOT + direct@intrinsic+ fresh user wrapper). Still gated under the stdlib wrapper by the name-collision below.
Mounted-name resolution:
checked_neg/checked_abs+saturating_add/sub/neg/abs— bare-name collision FIXED. These were resolving to the unmountedcore.math.checked.*overloads (returningCheckedResult/nil) instead of the explicitly-mounted intrinsics versions, because resolution ranked candidates by argument type and a typedIntarg (Int.MAX) matched the concreteInt64signature. An explicitmount X.{name}now owns the bare name.SaturatingNeg/SaturatingAbswidth-byte emission was also fixed (exposed once the collision stopped masking it).
Open defects (pinned @ignore):
- (B) Missing registry entries —
is_power_of_two,checked_rem. Nolookup_intrinsicentry → archived body is aLoadNilstub. - (D) Nested-call dispatch —
mul(a, add(b,c)). The outer intrinsic is mis-computed as the inner one (a + b + cinstead ofa·(b+c)). ARITH-MISSING-INTRINSICS-1.overflowing_neg/shl/shr,wrapping_div/rem/abs,wrapping_next_power_of_two,widening_mul[_signed],carrying_add,borrowing_sub,checked_shl/shr,checked_next_power_of_two,ilog10,leading_sign_bits,saturating_divhave no registry/dispatch implementation yet.
Until (A)–(D) are fixed, prefer operator forms (==, <, +, *, …) and the
width-specific intrinsics (saturating_add_u32, …) over the generic free
functions.
Bitwise
bitand<T>(a, b) -> T bitor / bitxor
bitnot<T>(a) -> T
shl<T>(a, n: Int) -> T shr (arith) lshr (logical) ashr (arith)
rotl<T>(a, n) -> T rotr<T>(a, n) -> T
fshl<T>(a, b, n) -> T fshr<T>(a, b, n) -> T // funnel shift
clz<T>(a) -> Int // count leading zeros
ctz<T>(a) -> Int // count trailing zeros
popcnt<T>(a) -> Int // population count
leading_ones<T>(a) -> Int trailing_ones<T>(a) -> Int
bswap<T>(a) -> T bitreverse<T>(a) -> T
byte_swap_bits<T>(a) -> T
Sized variants: clz_u32, ctz_u64, popcnt_u64, etc.
All generic forms operate at 64-bit width (VBC integer Values are i64 at
runtime — same model as arithmetic). The _u32 count
variants are width-correct: clz_u32 subtracts the 32-bit carrier slack
(clz64(x) - 32) and ctz_u32 sets a guard bit (ctz64(x | 1<<32)) so an
all-zero word yields 32, not 64.
byte_swap_bits reverses the bit order within each byte (byte positions
unchanged) — the identity byte_swap_bits = bswap ∘ bitreverse. ashr
sign-extends; lshr zero-fills; the bare shr is arithmetic.
Conformance status — bitwise ✅ complete
Suite: core-tests/intrinsics/bitwise/
(unit + property + integration + regression + audit.md).
Both tiers GREEN via verum test: interp 127/127, AOT 127/127; 0 @ignore.
Every public function is exercised; Boolean-algebra laws (commutativity,
associativity, De Morgan, distributivity, idempotence) and bit-manip invariants
(involutions, popcnt-preservation, rotate-inverse) are pinned by the property
suite.
Bitwise lowering (registry, codegen, interpreter and LLVM):
bitnot/lshr/ashrreturnednil. The registry held only the semantic wrapper names (bitand…); the authoritative@intrinsicbody names (and/or/xor/not) and the logical/arithmetic right shifts were unregistered. Nowand/or/xor/not→Band/Bor/Bxor/Bnot,lshr→Ushr,ashr→Shr; the missingUshremit arm was added.clz_u32/ctz_u32ignored width (clz_u32(1)was63, not31). New width-correct inline sequences.byte_swap_bitswas unregistered. Newbswap ∘ bitreverseinline sequence.
Tier-1 (AOT): the bitwise suite passes 127/127 under verum test --aot.
This required a systemic compiler fix (SYSTEMIC-AOT-EAGER-CORE-1): the test
harness writes its merged file inside the core cog, and
load_project_modules was eager-loading the whole core crate as a project
— pulling unreachable stdlib modules into native codegen and aborting on
undefined leaf functions. In Normal build mode the stdlib core cog is now
served exclusively from the embedded precompiled archive and never
eager-compiled as a project, which unblocks AOT for every core-tests
suite.
Float
// Elementary
sqrt<T>(x) -> T cbrt / exp / expm1 / exp2 / exp10
log<T>(x) -> T log1p / log10 / log2
pow<T>(x, y) -> T powi<T>(x, n: Int) -> T
hypot<T>(x, y) -> T
// Rounding
floor<T>(x) -> T ceil / round / roundeven / trunc / nearbyint / rint
// Fused
fma<T>(a, b, c) -> T // single-rounded a*b+c
fms<T>(a, b, c) -> T // a*b-c
// Sign / magnitude
copysign<T>(mag, sign) -> T
minnum / maxnum // NaN-handling IEEE 754
minimum / maximum // signed-zero-aware
fmod / remquo fabs / fneg
// Trigonometry
sin / cos / tan / asin / acos / atan / atan2 / sincos
// Hyperbolic
sinh / cosh / tanh / asinh / acosh / atanh
// Classification
is_nan / is_inf / is_finite / is_normal / is_subnormal
is_sign_negative / is_sign_positive / is_infinite
IEEE 754 bit operations
f32_to_bits(f: Float32) -> UInt32 f32_from_bits(b: UInt32) -> Float32
f64_to_bits(f: Float64) -> UInt64 f64_from_bits(b: UInt64) -> Float64
f32_infinity() / f32_neg_infinity() / f32_nan()
f64_infinity() / f64_neg_infinity() / f64_nan()
infinity<T>() -> T nan<T>() -> T epsilon<T>() -> T
min_positive<T>() -> T max_float<T>() -> T
Runtime model: VBC floats are IEEE f64 (Float32 widens to f64 at runtime);
the generic forms are f64-natural and _f32/_f64 carry their width. Most
functions dispatch via a MathExtended opcode (~2 ns).
Conformance status — float ⚠️ partial
Suite: core-tests/intrinsics/float/
(unit + property + integration + regression + audit.md).
Green under the interpreter (a few @ignored pins); the AOT path has a tail of failures.
Fixes landed:
truncreturned its input unchanged — floattrunc<T>shared the bare@intrinsic("trunc")name with integerconversion.itrunc(which is a no-opMovat i64/f64 width). Routed floattruncto its dedicatedtrunc_f64(round toward zero).fneg→nil(andfmsgarbage) —fneghad no registry entry; aliased it to the polymorphicneg(PolyNeg, float-aware). Closesfneg+fms.epsilon/min_positive/max_float→nil— used unregistered@intrinsicnames; now plain IEEE-754 literals.
Open — interp (need new opcodes):
FLOAT-ROUNDMODES-1—roundeven/rint/nearbyint(round-half-to-even).FLOAT-MINMAX-1—minimum/maximum(IEEE 754-2019, NaN-propagating).FLOAT-CLASSIFY-1—is_subnormal/is_sign_negative/is_sign_positive.
Open — AOT only (FLOAT-AOT-LIBM-1, interp green): fneg/fms (the
PolyNeg AOT path doesn't negate floats) and the libm-backed
hypot/cbrt/expm1/log1p/powi (AOT lowering).
Atomic
type MemoryOrder is Relaxed | Acquire | Release | AcqRel | SeqCst;
const ORDERING_RELAXED: MemoryOrder;
const ORDERING_ACQUIRE: MemoryOrder;
const ORDERING_RELEASE: MemoryOrder;
const ORDERING_ACQ_REL: MemoryOrder;
const ORDERING_SEQ_CST: MemoryOrder;
// Generic
atomic_load<T>(ptr: *const T, order: MemoryOrder) -> T
atomic_store<T>(ptr: *mut T, value: T, order: MemoryOrder)
atomic_xchg<T>(ptr, value, order) -> T
atomic_cmpxchg<T>(ptr, current, new, success, failure) -> Result<T, T>
atomic_cmpxchg_weak<T>(...) -> Result<T, T>
atomic_add / atomic_sub / atomic_max / atomic_min / atomic_umax / atomic_umin
atomic_and / atomic_nand / atomic_or / atomic_xor
atomic_fence(order) compiler_fence(order)
VBC-direct width-specific primitives
atomic_load_u8/u16/u32/u64/i32/ptr(ptr, order)
atomic_store_u8/u16/u32/u64/i32/ptr(ptr, value, order)
atomic_cas_u32/u64/i32/ptr(ptr, old, new, s, f) -> Result<T, T>
atomic_fetch_add_u32/u64/u16(ptr, delta, order) -> T
atomic_fetch_sub_u32/u64
atomic_fetch_and_u32/u64/u16 atomic_fetch_or_u64 atomic_fetch_xor_u64
atomic_exchange_u32/u64/i32(ptr, new, order) -> T
Int-sized (platform-pointer-width)
atomic_load_int / atomic_store_int
atomic_cmpxchg_int / atomic_fetch_add_int
atomic_cas_* returns a (observed_value, succeeded) pair: on success
observed == expected and the new value is installed; on failure observed is
the current value and the cell is untouched. The ORDERING_* constants are the
UInt8 strength ladder (Relaxed=0 … SeqCst=4) the width-typed intrinsics
consume; the MemoryOrder ADT is the typed surface over them.
Conformance status — atomic ⚠️ partial
Suite: core-tests/intrinsics/atomic/
(unit + property + integration + regression + audit.md).
Green under the interpreter; roughly half the suite fails under AOT.
A single-threaded conformance test pins each operation's value semantics
(read-modify-write result + returned previous value) over a live atomic cell,
not inter-thread ordering. No atomic-intrinsic fix was needed — the full
operational surface (load/store, fetch_add/sub/and/or/xor, exchange,
compare-and-swap, fences) is correct under interp.
Open — AOT only (ATOMIC-AOT-RAWPTR-1): the 14 operational tests drive
atomic ops through a List.as_mut_ptr() raw pointer; that AOT raw-pointer /
List-backing path fails (even store/load), so it's the same family as the
byte-array AOT defect, not the atomic ops. The MemoryOrder ADT + ORDERING
constants + fences pass on both tiers. Inter-thread ordering semantics belong to
a concurrency suite (out of scope here).
Memory
// Bulk
memmove(dst: *mut Byte, src: *const Byte, n: Int)
memcpy(dst, src, n)
memset(dst, byte: Byte, n)
memcmp(a, b, n) -> Int
// Typed
copy<T>(dst: *mut T, src: *const T, count: Int)
copy_nonoverlapping<T>(dst, src, count) // UB if overlapping
swap<T>(a: *mut T, b: *mut T)
replace<T>(ptr: *mut T, value: T) -> T
forget<T>(value: T) // leak, no drop
transmute<S, D>(value: S) -> D // reinterpret bits
// Pointer
ptr_read<T>(p: *const T) -> T
ptr_read_unaligned<T>(p: *const T) -> T
ptr_read_volatile<T>(p: *const T) -> T
ptr_write<T>(p: *mut T, v: T)
ptr_write_unaligned<T>(p, v) ptr_write_volatile<T>(p, v)
ptr_write_bytes<T>(p: *mut T, byte: Byte, count: Int)
ptr_offset<T>(p: *const T, count: Int) -> *const T
ptr_offset_mut<T>(p: *mut T, count: Int) -> *mut T
ptr_add<T>(p, count) / ptr_sub<T>(p, count)
null_ptr<T>() -> *const T null_ptr_mut<T>() -> *mut T
ptr_is_null<T>(p) -> Bool
ptr_is_aligned<T>(p) -> Bool ptr_is_aligned_to<T>(p, align: Int) -> Bool
drop_in_place<T>(p: *mut T)
// Slice (unsafe)
slice_from_raw_parts<T>(p: *const T, len: Int) -> &[T]
slice_from_raw_parts_mut<T>(p: *mut T, len: Int) -> &mut [T]
slice_len<T>(s: &[T]) -> Int
slice_as_ptr<T>(s: &[T]) -> *const T
slice_as_mut_ptr<T>(s: &mut [T]) -> *mut T
slice_get_unchecked<T>(s: &[T], i: Int) -> &T
slice_get_unchecked_mut<T>(s: &mut [T], i: Int) -> &mut T
slice_subslice<T>(s: &[T], start, end) -> &[T]
slice_split_at<T>(s: &[T], at: Int) -> (&[T], &[T])
slice_split_at_mut<T>(s: &mut [T], at: Int) -> (&mut [T], &mut [T])
// Uninit
uninit<T>() -> MaybeUninit<T>
zeroed<T>() -> MaybeUninit<T>
maybe_uninit_is_init<T>(m: &MaybeUninit<T>) -> Bool
// Volatile
volatile_load<T>(p: *const T) -> T
volatile_store<T>(p: *mut T, v: T)
volatile_copy<T>(dst, src, count) volatile_set<T>(dst, v, count)
// Reference conversion
ptr_to_ref<T>(p: *const T) -> &T // UB if null
ptr_to_mut_ref<T>(p: *mut T) -> &mut T
Conformance status — memory ⚠️ partial
Suite: core-tests/intrinsics/memory/ (unit + regression + audit.md).
Value-level subset GREEN on BOTH tiers (interp 11/11 + AOT 11/11):
swap, replace, transmute, null_ptr/null_ptr_mut/ptr_is_null,
zeroed.
Fix landed: null_ptr/ptr_is_null returned nil — their registry
strategies (DirectOpcode(LoadI) with no immediate; DirectOpcode(EqI) with a
single operand) fell through to LoadNil. Now dedicated inline sequences
(LoadI 0 / LoadI 0 + CmpI eq).
Raw-pointer coverage: the surface has a focused
harness over a List-backing pointer (as_mut_ptr). ptr_read/ptr_write work
on AOT; ptr_offset/ptr_add/ptr_sub were fixed — they advanced by bytes
not elements, so ptr_offset(p, 1) landed mid-slot (every backing slot is an
8-byte NaN-boxed Value). The fix scales by the slot size on both tiers (AOT
lower_ptr_add/sub GEP over i64; interpreter offset × 8), validated AOT
v0=99 v1=20 v2=30 with no regression (conversion 59/60). Still deferred:
memcpy/memset/memcmp, slice_*, ptr_is_aligned, ptr_to_ref, uninit
(the full MEM-RAWPTR-HARNESS-1 both-tier surface); and an interpreter-tier
ptr_read defect — a deref of a calloc'd List-backing pointer hits the
identity-deref path (returns the pointer instead of *p); the AOT reads *p
correctly. Partly covered today by the mem and
base/memory suites (the CBGR safety layer).
Type info
// Deprecated (prefer T.size etc.)
size_of<T>() -> Int align_of<T>() -> Int stride_of<T>() -> Int
bits_of<T>() -> Int type_id<T>() -> UInt64 type_name<T>() -> Text
// Meta
needs_drop<T>() -> Bool min_align() -> Int
Replaced by the type-property syntax — T.size, T.alignment,
T.stride, T.bits, T.id, T.name.
Conversion
// Integer ↔ float
int_to_float<I, F>(x: I) -> F uint_to_float<U, F>(x: U) -> F
float_to_int<F, I>(x: F) -> I float_to_uint<F, U>(x: F) -> U
// Precision
fpext<S, D>(x: S) -> D fptrunc<S, D>(x: S) -> D
sext<S, D>(x: S) -> D zext<S, D>(x: S) -> D
itrunc<S, D>(x: S) -> D
// Bit-level reinterpret
bitcast<S, D>(x: S) -> D // size(S) == size(D)
// Byte layouts
to_le_bytes<T, const N: USize>(x: T) -> [Byte; N]
to_be_bytes<T, const N: USize>(x: T) -> [Byte; N]
to_ne_bytes<T, const N: USize>(x: T) -> [Byte; N]
from_le_bytes<T, const N: USize>(bytes: [Byte; N]) -> T
from_be_bytes<T, const N: USize>(bytes: [Byte; N]) -> T
from_ne_bytes<T, const N: USize>(bytes: [Byte; N]) -> T
// Width-specific: Int input/output, with arrays of 2, 4 or 8 bytes
to_le_bytes_2 / _4 / _8
to_be_bytes_2 / _4 / _8
from_le_bytes_2 / _4 / _8
from_be_bytes_2 / _4 / _8
// Endianness
to_le<T>(x) / to_be<T>(x) / from_le<T>(x) / from_be<T>(x)
// Convenience
int_to_bytes<T, const N: USize>(x: T) -> [Byte; N]
f32_to_bits(f) -> UInt32 f32_from_bits(b) -> Float32
f64_to_bits(f) -> UInt64 f64_from_bits(b) -> Float64
Runtime model: integer/float width is static-only (i64/f64 at runtime), so
the widening conversions (sext/zext/fpext) and narrowing ones
(itrunc/fptrunc) are value-preserving no-ops. The float↔int bit
reinterpretation is a real opcode (it is not a move in the Tier-0 NaN-boxed
representation), so use the size-typed f{32,64}_{to,from}_bits wrappers rather
than the generic unsafe bitcast<S, D>. to_le/from_le are no-ops on a
little-endian target; to_be/from_be byte-swap.
Conformance status — conversion ⚠️ partial
Suite: core-tests/intrinsics/conversion/
(unit + property + integration + regression + audit.md).
Byte conversion support depends on the selected numeric declaration and
execution backend. The declarations in
core/intrinsics/conversion.vr
specify result shapes; the selected producer also determines their storage.
Byte conversion limitations
Ordinary interpreter checks on macOS arm64 verify every output byte for these forms:
| Call and result binding | Interpreter |
|---|---|
UInt64.to_be_bytes(), inferred result type | Expected bytes pass, including indexed reads in a loop. |
UInt64.to_be_bytes() or UInt64.to_le_bytes(), explicit [Byte; 8] result | Expected bytes pass. |
Typed [Byte; 8] literal | Expected bytes pass. |
UInt16.to_be_bytes() with [Byte; 2], or UInt32.to_be_bytes() with [Byte; 4] | Expected bytes pass. |
AOT validation remains separate. Focused LLVM/JIT controls cover selected numeric bodies and array call-result storage, but do not establish complete AOT programs, reverse conversions or arbitrary function-boundary use. Native consumers with unproved storage retain the documented compilation refusals.
Fixed-size byte arrays do not have one universal storage layout. Selected
functions with identical array signatures can return packed or list-backed
values. Binding a result to [Byte; N] does not itself copy it into a
contiguous byte buffer. Neither a declared return type nor a passing element
check establishes a safe raw byte pointer for FFI. Follow the
byte-buffer contract
for the actual producer and consumer on the target backend.
Sha256.digest
also returns the expected digest for a known-answer input through the ordinary
interpreter, including its internal big-endian length conversion. Other hashes
and native digest execution need their own validation.
Float32 bit reinterpretation has a separate AOT limitation:
f32_to_bits and f32_from_bits can return 0 instead of the expected bit
pattern.
Control
trap() -> ! // abort — "should not execute"
unreachable() -> ! // UB hint
debugtrap() // breakpoint
nop() // no-op placeholder
assume(cond: Bool) // optimiser hint
likely(cond: Bool) -> Bool // branch prediction hint
unlikely(cond: Bool) -> Bool
expect<T>(value: T, expected: T) -> T
prefetch_read<T>(p: *const T)
prefetch_write<T>(p: *mut T)
panic(msg: Text) -> !
abort() -> ! // immediate; no unwinding
debug_assert(cond, msg)
unreachable_unchecked(msg) -> !
panic_impl(info: &PanicInfo) -> !
catch_unwind<T, F>(f: F) -> Result<T, PanicInfo>
random_float() -> Float // OS RNG
random_u64() -> UInt64
Conformance status — control ✅ value surface (both tiers)
Green on both the interpreter and AOT (one @ignored pin), via
core-tests/intrinsics/control/ (verum test).
The branch-hint intrinsics are semantically transparent — they steer the
optimiser but must return their primary operand unchanged: likely(c) /
unlikely(c) return c, and expect<T>(v, hint) returns v (the hint is
advisory only).
Fix landed (CONTROL-EXPECT-NIL): likely / unlikely / expect all
lower to @intrinsic("expect", value, hint), which had no registry entry —
so the name resolved to LoadNil and every branch-hint call returned nil.
Registered expect with the identity-Mov-of-first-argument inline sequence
(it returns the value and ignores the hint operand). Fixed on both tiers.
Verified green: branch-hint identity (Int / Bool / Text), nop() /
assume(true) / debug_assert(true) callable no-ops, random_float() ∈
[0.0, 1.0), random_u64() non-constant, and hints embedded in realistic
control flow (a likely hot loop, an unlikely rare branch) computing
identical results to the un-hinted form.
Known residual (@ignored): generic expect<T> returns the value with a
mis-tagged (boxed) representation — correct for compare/print/assign but
arithmetic on the result yields garbage (acc + expect(i*i, 0)); the
non-generic likely / unlikely are unaffected.
Not value-tested: the diverging Never-typed intrinsics (trap,
unreachable, panic, abort, unreachable_unchecked, panic_impl) and the
catch_unwind / prefetch_* surfaces (raw-pointer + unwinding harness) — see
core-tests/intrinsics/control/audit.md.
Platform
is_debug() -> Bool is_release() -> Bool
target_os() -> UInt8 // compact encoding, see platform.vr
target_arch() -> UInt8
target_pointer_width() -> UInt32
target_is_little_endian() -> Bool
target_has_atomic<T>() -> Bool
target_has_feature(feature: Text) -> Bool
rdtsc() -> UInt64 // x86_64
rdtscp() -> (UInt64, UInt32)
spin_hint() // pause / yield instruction
SIMD
Lane-level primitives. Higher-level API lives in simd.
simd_extract<V, T>(v: V, lane: Int) -> T
simd_insert<V, T>(v: V, lane: Int, value: T) -> V
simd_shuffle<V, const MASK: [UInt32]>(a: V, b: V) -> V
simd_reduce_add<V, T>(v: V) -> T
simd_reduce_mul<V, T>(v: V) -> T
simd_reduce_min<V, T>(v: V) -> T
simd_reduce_max<V, T>(v: V) -> T
simd_reduce_and<V, T>(v: V) -> T
simd_reduce_or<V, T>(v: V) -> T
simd_reduce_xor<V, T>(v: V) -> T
Tensor
Runtime tensor compute over opaque handles (Int at the surface
until the dedicated handle type lands). Backs
math.tensor and the autodiff stack. The interpreter executes real
CPU kernels (interpreter/tensor.rs; SVD/QR/eig/einsum/conv2d
included); Tier-1 lowers to verum_tensor_* IR bodies.
Wire contract. Every tensor intrinsic emits
TensorExtended with operands [dst][mode?][arg-registers…] — all
values arrive in registers, never as inline immediates, and the
operand-byte envelope (not the arm's reads) advances the instruction
stream. This is the single authority shared by the emitter, the
interpreter arms, and the AOT lowering.
Element dtypes (DTYPE_* constants)
Pass these to tensor_new / tensor_fill / tensor_from_slice /
tensor_cast — they mirror the runtime DType byte encoding:
| Constant | Id | Constant | Id | |
|---|---|---|---|---|
DTYPE_F32 | 0 | DTYPE_U64 | 8 | |
DTYPE_F64 | 1 | DTYPE_U32 | 9 | |
DTYPE_F16 | 2 | DTYPE_U16 | 10 | |
DTYPE_BF16 | 3 | DTYPE_U8 | 11 | |
DTYPE_I64 | 4 | DTYPE_BOOL | 12 | |
DTYPE_I32 | 5 | DTYPE_COMPLEX64 | 13 | |
DTYPE_I16 | 6 | DTYPE_COMPLEX128 | 14 | |
DTYPE_I8 | 7 |
Reads (tensor_get_scalar → Float) and writes (tensor_set_scalar,
fills, from_slice copies) are dtype-converting in both
directions, including F32 and integer tensors.
Op-code tables
tensor_unop op | op | op | ||
|---|---|---|---|---|
| 0 neg | 5 sin | 10 relu | ||
| 1 abs | 6 cos | 11 gelu | ||
| 2 sqrt | 7 tan | 12 silu | ||
| 3 exp | 8 tanh | 13 floor | ||
| 4 log | 9 sigmoid | 14 ceil |
tensor_binop: 0 add · 1 sub · 2 mul · 3 div · 4 pow · 5 mod ·
6 min · 7 max.
tensor_cmp: 0 eq · 1 ne · 2 lt · 3 le · 4 gt · 5 ge (Bool tensor).
tensor_reduce: 0 sum · 1 prod · 2 max · 3 min · 4 mean ·
5 var (axis < 0 reduces all).
tensor_cumulative: 0 sum · 1 prod.
The byte values are defined by TensorUnaryOp, TensorBinaryOp,
TensorReduceOp and CompareOp in the VBC instruction definitions.
Surface by group
// Creation // Factories
tensor_new(shape, dtype) tensor_arange(start, end, step)
tensor_fill(shape, value, dtype) tensor_linspace(start, end, steps)
tensor_from_slice(data, shape, d) tensor_eye(n)
tensor_from_array(data) tensor_rand(shape) / tensor_randn(shape)
tensor_clone(t) tensor_randint(low, high, shape)
// Shape // Indexing
tensor_reshape(t, shape) tensor_slice(t, ranges)
tensor_transpose(t) tensor_index(t, indices)
tensor_permute(t, perm) tensor_index_select(t, dim, idx)
tensor_squeeze(t) tensor_gather(t, dim, indices)
tensor_unsqueeze(t, dim) tensor_concat(tensors, dim) // List of handles
tensor_repeat(t, times) tensor_stack(tensors, dim) // List of handles
tensor_contiguous(t) tensor_split(t, chunks, dim) // → List
tensor_broadcast(t, shape)
// Element-wise // Linear algebra
tensor_binop(a, b, op) tensor_matmul / tensor_mm / tensor_mv
tensor_unop(t, op) tensor_bmm(a, b) tensor_dot(a, b)
tensor_cmp(a, b, op) tensor_outer(a, b)
tensor_where(cond, a, b) tensor_einsum(expr, tensors)
tensor_clamp(t, lo, hi) tensor_solve(a, b) tensor_tri_solve(a, b)
tensor_cast(t, dtype) tensor_inverse(t) tensor_det(t) → Float
tensor_masked_fill(t, mask, v) tensor_trace(t) → Float
tensor_lerp(a, b, w)
// Reductions // Normalisation
tensor_reduce(t, op, axis) tensor_softmax(t, axis) // per-lane
tensor_reduce_all(t, op) tensor_log_softmax(t, axis) // stable LSE
tensor_argmax(t, axis) // → I64 index TENSOR (axis<0 ⇒ flat global)
tensor_topk(t, k, axis) // → VALUES tensor, sorted desc
tensor_cumulative(t, op, axis) tensor_layer_norm(t, ns, w, b)
tensor_batch_norm(t, mean, var, w, b)
tensor_norm(t, p, dim) tensor_rms_norm(t, w)
// Convolutions (valid padding, stride 1)
tensor_conv(input, kernel) // 1-D operands auto-wrapped to NCHW
tensor_conv2d(input, kernel) // NCHW input, OIHW kernel
// Advanced
tensor_scatter(t, dim, indices, src) tensor_nonzero(t)
tensor_one_hot(indices, classes) tensor_fft(t)
tensor_flash_attention(q, k, v) // softmax(Q·Kᵀ/√dₖ)·V
Single-output contracts (until the multi-output surface lands)
The .vr surface returns ONE handle, so each decomposition returns
its documented primary factor: tensor_qr → Q,
tensor_svd → singular values, tensor_lu → U,
tensor_eig/tensor_eigh → eigenvalues, tensor_topk → values,
tensor_split/split_at → List of handles. The full multi-factor
surface is still being filled in.
Tier contract
- Interpreter (Tier 0) — full surface, real kernels;
conformance:
core-tests/intrinsics/tensor. - AOT (Tier 1) — the core group (
new/fill/from_slice/ element access/binop/unop/matmul/reduce/reshape/transpose/softmax/clone) has real IR bodies; every other op currently lowers to a loud runtime panic naming the op ("<op>: no Tier-1 lowering yet") rather than to a declared-but-undefined extern, so an unsupported op fails where you called it instead of at link time. Axis-honouring reduce and softmax are among those not yet lowered.
Open defects
| Limitation | What it means for you |
|---|---|
| Broadcasting returns nothing for a row-tile against a matrix | Expand the operand explicitly before the operation. |
det and trace answer through the wrong value channel | Their results are not usable; compute from a factorisation instead. |
Reduction and softmax ignore axis when compiled ahead of time | They reduce over everything. Under the interpreter axis is honoured. |
| A tensor handle carries no header | It renders as noise inside an f-string, and tensors are not reclaimed — a long-running loop grows. |
| Element access ignores the strides of a view | Read through the base tensor rather than through a view. |
| The script cache survives a change to the tensor wire format | Clear ~/.verum/script-cache after upgrading, or a stale body will run. |
GPU
Orchestration intrinsics used by math.gpu and @kernel.
// Device management
gpu_get_device() -> GpuDevice
gpu_set_device(id: Int)
gpu_device_reset()
gpu_mem_info() -> (free: Int, total: Int)
gpu_can_peer(a, b) -> Bool
gpu_enable_peer(a, b) / gpu_disable_peer(a, b)
// Allocation
gpu_malloc<T>(count: Int) -> GpuBuffer<T>
gpu_malloc_managed<T>(count: Int) -> GpuBuffer<T>
gpu_free(buf)
gpu_pin_memory<T>(host: *mut T, count) / gpu_unpin_memory
gpu_prefetch(buf, device_id)
// Transfers
gpu_memcpy(dst, src, bytes, kind: TransferKind)
gpu_memcpy_async(dst, src, bytes, kind, stream)
gpu_memcpy_h2d / d2h / d2d
gpu_memset / gpu_memset_async
// Streams & events
gpu_stream_create() gpu_stream_create_prio(priority)
gpu_stream_destroy(stream) gpu_stream_query(stream) -> Bool
gpu_stream_wait_event(stream, event)
gpu_sync(stream) / gpu_sync_all()
gpu_event_create() gpu_event_create_f()
gpu_event_destroy(event) gpu_event_record(event, stream)
gpu_event_sync(event) gpu_event_query(event) -> Bool
gpu_event_elapsed(start, stop) -> Float
// Kernel launch
gpu_launch(grid, block, kernel, args)
gpu_launch_coop(grid, block, kernel, args)
// Graph API (capture + replay)
gpu_graph_create() / gpu_graph_destroy
gpu_graph_begin(stream) / gpu_graph_end(stream)
gpu_graph_inst(graph) -> GpuExecutable
gpu_graph_launch(exec, stream)
// Enumeration
gpu_enumerate_cuda() -> List<GpuDevice>
gpu_enumerate_metal() -> List<GpuDevice>
gpu_enumerate_rocm() / vulkan()
// Profiling
gpu_marker_push(name: Text)
gpu_marker_pop()
Runtime
Intrinsics annotated @requires_runtime. See runtime
for configured flavours.
Async (runtime/async_ops.vr)
// Opaque handles
JoinHandleOpaque ExecutorHandle FutureHandle
SupervisorHandleOpaque ChildSpecOpaque ExecutionEnvOpaque
RecoveryContextOpaque CircuitBreakerOpaque AllocHandle
IODriverHandle SharedRegistryOpaque MiddlewareChainOpaque
SingleThreadExecutorOpaque
// Spawn & block
spawn_with_env<T>(future) -> JoinHandleOpaque
executor_spawn<T>(exec, future) -> JoinHandleOpaque
executor_block_on<T>(future) -> T
future_poll_sync<T>(future: &mut F) -> Maybe<T>
default_executor() -> ExecutorHandle
// Sleep
async_sleep_ms(ms: Int)
async_sleep_ns(ns: Int)
// Supervision
spawn_supervised(...) supervisor_log_escalation(...)
supervisor_set_parent(child, parent) exec_with_recovery(...)
// Globals
global_allocator() -> AllocHandle
default_io_driver() -> IODriverHandle
shared_registry_global() -> SharedRegistryOpaque
middleware_chain_empty() -> MiddlewareChainOpaque
single_thread_block_on<T>(future) -> T
// Recovery error type
type RecoveryError is
| MaxRetriesExceeded
| CircuitOpen
| Timeout
| InnerError(Error);
TLS (runtime/tls.vr)
tls_get_base() -> *mut Byte
tls_slot_get(slot: UInt8) -> *const Byte tls_slot_set(slot: UInt8, value: *const Byte)
tls_slot_clear(slot) tls_slot_has(slot) -> Bool
tls_frame_push() / tls_frame_pop()
tls_read_ptr<T>(slot) -> *const T tls_write_ptr<T>(slot, ptr)
tls_read_i32(slot) / tls_write_i32(slot, v)
tls_read_usize(slot) / tls_write_usize(slot, v)
Syscalls (runtime/syscall.vr)
syscall0(num) -> Int
syscall1(num, a0) -> Int
syscall2(num, a0, a1) -> Int
syscall3(num, a0, a1, a2) -> Int
syscall4(num, a0..a3) -> Int
syscall5(num, a0..a4) -> Int
syscall6(num, a0..a5) -> Int
Time (runtime/time.vr)
monotonic_nanos() -> UInt64
realtime_secs() -> Int64 realtime_nanos() -> UInt64
num_cpus() -> Int
sleep_ms(ms) / sleep_ns(ns)
Raw memory (runtime/mem_raw.vr)
Raw-address (Int-pointer) memory operations — the byte-granular layer
under core/intrinsics/memory.vr's typed pointers. Addresses are plain
integers (obtain one from cbgr_allocate or FFI); all offsets are BYTES.
memcpy(dst: Int, src: Int, n: Int) -> Int // non-overlapping
memmove(dst: Int, src: Int, n: Int) -> Int // overlap-safe
memset(dst: Int, value: Int, n: Int) -> Int // fills value % 256
memzero(dst: Int, n: Int) -> Int
memcmp(a: Int, b: Int, n: Int) -> Int // 0 / <0 / >0
strlen(s: Int) -> Int // to first NUL
strcmp(a: Int, b: Int) -> Int
load_byte(addr: Int) -> Int store_byte(addr: Int, value: Int) -> Int
load_i32(addr: Int) -> Int store_i32(addr: Int, value: Int) -> Int
load_i64(addr: Int) -> Int store_i64(addr: Int, value: Int) -> Int
Conformance: core-tests/intrinsics/runtime/mem_raw/ (overlap laws both
directions, first-NUL strlen, byte-granular addressing, platform-endianness
cross-check), driven over live cbgr_allocate blocks on both tiers.
Sync (runtime/sync.vr)
futex_wait(uaddr: *mut Int32, expected, timeout) -> Int
futex_wake(uaddr, n) -> Int futex_wake_one(uaddr) / futex_wake_all(uaddr)
spinlock_try_lock(uaddr) -> Bool
spinlock_lock(uaddr) spinlock_unlock(uaddr)
spinlock_is_locked(uaddr) -> Bool
spin_hint() spin_loop_hint()
memory_fence(order) compiler_fence(order)
CBGR (runtime/cbgr.vr)
// Validation — non-trapping (returns the verdict; ChkRef-style traps are
// the deref-site checks, not this API)
cbgr_validate<T>(reference: &T) -> Bool
cbgr_current_epoch() -> UInt64
cbgr_advance_epoch()
cbgr_get_generation(ptr: *const Byte) -> UInt32
// Public allocation bridge — user-pointer API over the 32-byte
// AllocationHeader model (size@0, align@4, generation@8, epoch@12,
// flags@20). Both tiers share the layout: AOT via the verum_cbgr_*
// runtime, the interpreter via a bit-identical implementation.
// Alignment is honoured up to 32 (power of two); 0 = failure.
cbgr_allocate(size: Int, align: Int) -> Int
cbgr_deallocate(user_ptr: Int) // no-op on 0
cbgr_realloc(user_ptr: Int, new_size: Int) -> Int // preserves min(old,new)
Text (runtime/text.vr)
text_from_static(s: &'static str) -> Text
text_byte_len(t: &Text) -> Int
text_parse_int(t: &Text) -> Result<Int, ParseError>
text_parse_float(t: &Text) -> Result<Float, ParseError>
int_to_text(n: Int) -> Text float_to_text(f: Float) -> Text
utf8_decode_char(bytes: *const Byte) -> (Char, Int)
utf8_decode_char_len(bytes: *const Byte) -> Int
char_encode_utf8(c: Char) -> (UInt32, Int)
char_is_alphabetic(c) / is_numeric / is_alphanumeric / is_whitespace / is_control
char_is_uppercase / is_lowercase
char_to_uppercase / to_lowercase
char_general_category(c) -> GeneralCategory
char_escape_debug(c) -> Text
Execution mode (runtime/mode.vr)
is_interpreted() -> Bool // true when running under the VBC interpreter
current_mode() -> ExecutionMode // Interpreter | Aot
get_tier() -> ExecutionTier // Tier0_Full | Tier1_Epoch |
// Tier2_Gen | Tier3_Unchecked
ExecutionTier is the CBGR safety tier of the current reference,
not the execution mode of the process. Execution mode is always one
of two values — Verum does not have a JIT.
Low-level (@llvm_only)
Direct hardware intrinsics. Not available in the VBC interpreter.
lowlevel/mod.vr
type CpuCapabilities is {
has_128bit_simd: Bool, has_256bit_simd: Bool, has_512bit_simd: Bool,
has_fma: Bool, has_aes: Bool, has_sha: Bool,
has_crc32: Bool, has_popcnt: Bool, has_lzcnt: Bool,
has_atomic_16b: Bool,
};
detect_capabilities() -> CpuCapabilities | |
const MAX_SIMD_WIDTH: Int | |
const PREFERRED_SIMD_WIDTH: Int |
lowlevel/x86_64.vr (x86_64 only)
type CpuFeatures is { has_sse3, ssse3, sse41, sse42, avx, avx2, avx512f,
avx512dq, avx512bw, avx512vl, fma, bmi1, bmi2,
popcnt, lzcnt, aes, pclmulqdq, sha, cx16 : Bool };
cpu_features() -> CpuFeatures
cpuid(leaf, subleaf) -> (UInt32, UInt32, UInt32, UInt32)
// SSE/SSE2
sqrtps(v: Vec4f) -> Vec4f rcpps(v) -> Vec4f rsqrtps(v) -> Vec4f
dpps<const MASK: UInt8>(a, b) -> Vec4f
// AVX/AVX2
haddps_256(a, b) phaddd(a, b) permd(a, indices)
gatherd_ps_256(base, indices, mask)
fmadd_ps_256(a, b, c) fmsub_ps_256(a, b, c)
// AVX-512
add_ps_512_mask(a, b, mask) fmadd_ps_512_mask(a, b, c, mask)
compress_ps_512(a, mask) / expand_ps_512(a, mask)
conflict_d_512(a)
// Bit manipulation
tzcnt / lzcnt / popcnt / bextr / pdep / pext
// Cryptographic
aesenc / aesenclast / aesdec
pclmulqdq<const IMM>(a, b)
sha256msg1 / sha256rnds2
// Privileged
rdmsr(reg) / wrmsr(reg, val)
read_cr0 / read_cr3 / write_cr3 / invlpg
// Timing / serialisation
rdtsc / rdtscp / mfence / lfence / sfence / pause
// Port I/O
inb(port) / outb(port, val) / inw / outw / inl / outl
lowlevel/aarch64.vr (aarch64 only)
// Every capability field carries the `has_` prefix, including the ones
// abbreviated here before; `sve_width` is the sole UInt32.
type Aarch64CpuFeatures is {
has_neon: Bool,
has_sve: Bool, has_sve2: Bool, sve_width: UInt32,
has_dotprod: Bool, has_fp16: Bool, has_bf16: Bool, has_i8mm: Bool,
has_sha256: Bool, has_sha512: Bool, has_aes: Bool, has_crc32: Bool,
has_lse: Bool, has_rdm: Bool,
};
type CpuFeatures is Aarch64CpuFeatures; // the portable alias
cpu_features() -> Aarch64CpuFeatures
// NEON float
vfmaq_f32(a, b, c) / vfmsq_f32(a, b, c)
vsqrtq_f32(v) vrecpeq_f32(v) vrsqrteq_f32(v) vrecpsq_f32(a, b)
vpaddq_f32(a, b) vmaxvq_f32(v) / vminvq_f32(v) / vaddvq_f32(v)
// NEON integer
vpaddq_s16 / vmlal_s16 / vabdq_s8 / vqtbl1q_u8 / vrev32q_u8 / vrev64q_u8
// Dot-product
vdotq_s32(a, b) / vdotq_u32(a, b)
// Cryptographic
vaeseq_u8 / vaesmcq_u8 / vaesdq_u8
vsha256hq_u32 / vsha256h2q_u32 / vsha256su0q_u32
vmull_p64
// LSE atomics
ldadd_i64 / swp_i64 / cas_i64
// System registers
read_id_aa64isar0_el1 / isar1 / pfr0
read_cntvct_el0 / cntfrq_el0
// Memory barriers
dmb_sy / dmb_ish / dmb_ishst / dmb_ishld
dsb_sy / isb
// Cache
dc_cvac / dc_civac / ic_ivau
// Hints
yield_cpu / wfi / wfe / sev
lowlevel/kernel.vr
// Startup entries
linux_x86_64_start() linux_aarch64_start()
baremetal_x86_64_start() baremetal_aarch64_start()
// Interrupt prologues / epilogues
x86_64_interrupt_prologue() / epilogue / error_prologue
aarch64_exception_prologue() / epilogue
Cross-references
- simd — high-level wrappers around SIMD intrinsics.
- math — libm, tensor, GPU layers built on these intrinsics.
- mem — CBGR uses the atomic + memory intrinsics.
- sys — syscall intrinsics drive platform operations.
- Language → attributes —
@llvm_only,@requires_runtime,@target_feature.