crc32c and Prefetch Are Portable std; an Instruction of One Architecture Is a Safe Function of Its Backend ModuleStatus: Accepted (the direction; the API is decided by a record of its own)
Date: October 19, 2026
Answers: how a Nikaia program uses what the fastest hand-written programs
use - comparing 16 to 64 bytes in one instruction, a hash in one instruction,
gathering scattered bits, telling the memory system what comes next - without
unsafe and without the language core taking on an architecture
Related: ADR-296 D6 (hardware instructions leave the core;
assembly is a library DSL) and D12 (the grammar’s scans are word-at-a-time,
SIMD a layer above), ADR-320 D12 (a Bytes reads a word),
#692 (the CPU level a build targets), Part III 16
let semis = lanes.equal(';').first() // where is the next `;` in 16 bytes
let h = hash::crc32c(word) // a hash in one instruction
let digits = x86::pext(word, 0x0F000F0F) // the temperature's digits, no branch
prefetch(table, at) // the slot will be read next
A hand-written 1BRC program in Rust that uses these runs about 90 instructions a row, where the same algorithm without them runs 140 to 260. A Nikaia program can write none of them. ADR-296 D6 moved assembly into a backend DSL that is not built, and D12 rejected a SIMD construct in the core.
Vector128<T>, safe and portable; BitOperations.Crc32C;
Bmi2.ParallelBitExtract and Sse.Prefetch0, safe, x86 only, with an
IsSupported a program asks.std::simd. Swift: SIMD16<UInt8>. Zig: @Vector in the
core, @prefetch. Mojo: SIMD[DType, n].std::simd (unstable); core::arch (stable, unsafe).CRC32C, which the JIT accelerates.simd package; hash/crc32, accelerated.A portable, safe vector type in the standard library is what the systems
languages are adding; crc32c is a standard library’s in many; prefetch is a
portable hint in Zig and GCC; an instruction like pext is architecture
specific nearly everywhere.
crc32c and prefetch are std’s.std offers a vector of lanes (a fixed number of u8, and of wider integers),
loaded from a Bytes at a position and checked as the cut it reads, so a proof
drops the check (ADR-320 D7); comparisons that answer a mask; and the mask’s
first set lane. crc32c joins std’s hashing; a prefetch hint asks that
memory be brought close, means nothing to the program, and outside its buffer
does nothing. On every target each of them has a meaning: an instruction where
the target has one, a loop or nothing where it has not. They are a library’s,
not the core’s: ADR-296 D6 holds.
std::backend::x86, and its siblings for other architectures, offer such an
instruction as a function with a safe signature, x86::pext(x, mask). It can
be called only in a build for a CPU level that has it (the build command names
the level, --cpu, ADR-002 D6); elsewhere the call is refused at compile time, so a program
that wants to build for both writes the other path. No unsafe is written for
any of it.
ADR-296 D6’s backend DSL remains for what D1 and D2 do not offer. Neither D1 nor D2 waits for it.
Its first part, a search over a whole buffer, is ADR-375.
The type’s name and lane widths, the operations, the mask’s type, the module
of crc32c (D5), which instructions D2 offers first, and how a program asks which
level it was built for (D6), are decided after this, from a draft written against
the programs that need them.
crc32c is hash::crc32c(crc: u32, word: u64) -> u32, one step.It is the CRC-32C (the Castagnoli polynomial) of word’s eight bytes, lowest
first, continued from crc, without the inversions a checksum adds before
and after: the step SSE 4.2’s crc32 and ARMv8’s crc32cx take, so on those
targets it is one instruction, and elsewhere a table gives the same value. The
start value is the caller’s: a hash of two words is
hash::crc32c(a.truncating_u32(), b), a checksum starts from 0xFFFFFFFF
and inverts at the end. It is in hash, beside the hashing std already
does for maps.
Rejected: a checksum over a whole Bytes as the only form (a hash of a
word in a register would have to be written to memory first); the
inversions inside (a hash would pay two instructions for nothing); a value
that differs by target, an instruction’s where there is one and another
hash elsewhere (a program’s output would depend on the CPU level).
target::has, in a comptime.target::has(target::Instruction::Crc32c) is a bool: whether the CPU level the
program is built for (--cpu, ADR-002 D6) has that instruction. Its natural
place is a comptime, so that the choice is made while the program is built
and the path not taken is not in the binary:
comptime CRC_IN_ONE: bool = target::has(target::Instruction::Crc32c)
let h = if CRC_IN_ONE { hash::crc32c(a.truncating_u32(), b) } else { (a ^ b).wrapping_mul(K) }
A comptime runs on the machine that builds, but target::has answers for the
level the build names, not for that machine: without --cpu that is the
target’s baseline, where Crc32c is false on x86-64, and only --cpu=native
asks the machine that builds. Called at run time it gives the same answer, the level the binary
was built for, not the CPU it runs on. The first instructions are Crc32c
(SSE 4.2 on x86-64, crc on AArch64), Bmi2 and Avx2; another is added
when a program needs it.
cfg attribute (D6): a second language of conditions beside
comptime and if.cpu (D6): it reads as a question to the CPU the program
runs on; target is the build’s, as in Rust’s target_feature.@Vector): what ADR-296 D6 keeps out of
the core, and nothing a library type cannot be.D4’s list; a vector wider than the target’s widest register; floating-point lanes. </content> </invoke>