← board

Compiler intrinsics for hardware entropy (CPUID / RDRAND / RNDR / ESP RNG)

Why it belongs in the compiler, not the library

[[feature-random-library]] carries a hard design mandate: one elegant .pas file, no per-arch {$ifdef} soup. The per-target instruction mess is supposed to live behind intrinsics so the library reads as three one-line tier selections. Tiers 2 (getrandom/urandom) and 3 (xoshiro256**) satisfy that today because neither needs a special instruction. Tier 1 does, and that is the whole ask.

What is needed

target mechanism probe
x86-64 / i386 RDRAND (and optionally RDSEED) CPUID leaf 1 ECX bit 30; leaf 7 EBX bit 18 for RDSEED
aarch64 MRS of RNDR / RNDRRS ID_AA64ISAR0_EL1 RNDR field — FEAT_RNG is optional
arm32 none in user mode — (library stays on tier 2)
riscv32 Zkr is an M-mode CSR, not user-reachable — (tier 2)
ESP32 xtensa / riscv32 RNG data register (bare) or esp_random (IDF) always present on the SoC

Two landmines worth building into the intrinsic rather than leaving to callers:

Shape suggestion, matching how the library already dispatches (a proc-typed var chosen once in initialization):

function __pxxCpuHasHwRandom: Boolean;
function __pxxHwRandom64(var v: UInt64): Boolean;   { False = failed, try again/fall back }

Two entry points, everything arch-specific behind them.

Note on the ESP tier

ESP's RNG is only truly random with the RF/WiFi clock enabled. Whatever lands must not let the library claim CSPRNG quality in the bare profile without it — [[feature-random-library]] says so explicitly and the intrinsic should make the distinction reportable rather than assumed.

Gate

make test + self-host byte-identical; the probe reporting correctly on a CPU that HAS the instruction and on one that does not (qemu can model both); and test/lib_random.pas still producing its byte-identical seeded stream on every target — tier 1 must not perturb the deterministic path, which is seeded and by definition does not use hardware entropy.

Triage 2026-08-19 (Track D re-triage pass, pin v363)

Genuine feature, still wanted, unchanged. lib/rtl/random.pas still carries the tier-1 stub and still names this ticket in the comment (STUB: requires __rdrand/__cpuid compiler builtins … Falls to tier 2), so the library is still running one tier below its design. The dangling-reference problem the ticket was filed to fix is resolved — the ticket exists now — and the work behind it has not landed.

Resolution — x86-64 (2026-08-21)

Both entry points exist and work, with the ticket's exact suggested shape:

function __pxxCpuHasHwRandom: Boolean;
function __pxxHwRandom64(var v: UInt64): Boolean;   { False = failed, retry / fall back }

They live in the compiler's builtin unit and are pulled in by the name pre-scan in ParseProgram, so lib/rtl/random.pas needs neither a uses nor an {$ifdef} — which is the mandate this ticket exists to satisfy.

Both landmines are built in, as the ticket asked

Two assembler mnemonics, in both encoders

rdrand and rdseed were not in either assembler. Added to asmenc.inc (the asm ... end encoder) and asmtext.inc (EmitAsmX64), per that file's own rule that a mnemonic lands in both or the reason is written down. They are 0F C7 /6 and /7 — not part of the F6/F7 unary group, they share a two-byte opcode with cmpxchg8b keyed by the ext digit.

Verified byte-exact against GNU as, all seven forms including REX.B extended registers and the 32-bit encodings:

48 0f c7 f0  rdrand rax     0f c7 f0     rdrand eax
48 0f c7 f1  rdrand rcx     41 0f c7 f1  rdrand r9d
49 0f c7 f4  rdrand r12     48 0f c7 f8  rdseed rax
                            48 0f c7 fb  rdseed rbx

The 27-byte sequence as produces for those seven appears verbatim in a pxx binary compiled from the same seven lines.

Staged, and the other targets say so honestly

x86-64 only, which is what the ticket's per-arch note asked for. Every other target's __pxxCpuHasHwRandom answers False — and that is the correct answer, not a stub: arm32 and riscv32 have no user-mode instruction, aarch64's MRS RNDR needs the optional FEAT_RNG plus an ID_AA64ISAR0_EL1 probe and system-register support in the a64 assembler, and ESP's RNG register is Track S and is only truly random with the RF clock enabled. False routes the library to tier 2, which is exactly where those targets belong.

Not done here

Wiring lib/rtl/random.pas is a Track B change and is filed as [[feature-b-random-tier1-consume-the-hw-entropy-intrinsics]]. The library's tier-1 stub and its comment naming this ticket are still in place.

Gate

tools/gate.sh quick GREEN (self-host fixedpoint 110s). test/test_hw_random_intrinsics.pas: 3/3 on x86-64 (probe TRUE, 32/32 draws, values distinct) and 2/2 on i386 / arm32 / aarch64 / riscv32 (probe FALSE, 0 draws — the relationship holds in both directions, which is what the test asserts rather than the presence of the instruction). test/lib_random.pas and test/lib_randomstate.pas produce output byte-identical to pinned's — the seeded stream is untouched, as the ticket's gate required.

Log