Issue #660: Decision: a target-cpu key, so a build can use the instructions of the machine it runs on

Open and answer this issue on GitHub.

decision · opened 2026-10-18 · updated 2026-10-18 · 0 comments

What this is about

A compiled program is machine code for a processor family: x86_64-linux code by default runs on every 64-bit x86 processor since 2003, so it may only use the instructions all of them have. Newer processors have wider vector instructions (AVX2, AVX-512 on x86; SVE on some ARM), popcnt, lzcnt, bmi2 and more. A compiler told the exact processor (“target-cpu”) may use them: a loop over bytes can handle 32 at a time instead of 16, a bit count is one instruction instead of a dozen.

[build.x86_64-linux]
opt-level = 3
target-cpu = "native"     # proposed: use everything the build machine has

Where the question comes from

The owner asked for the website to say that Nikaia is fast and hardware-optimised (facec91 rewrote the lead). Today it can honestly say optimised native machine code, not tuned to your processor: no build sets a target-cpu. crates/nikaia/src/sysroot.rs (Codegen) already names target-cpu as “the obvious next” key of [build.<target>] and makes any such key a dimension of the compiled std’s cache key by construction (ADR-021 D13’s obligation).

Today

What goes wrong if this is decided badly

How others do it

Options

A — a target-cpu key in [build.<target>], absent = baseline. Values as rustc spells them (native, x86-64-v3, neoverse-n1, …). Portable by default, opt-in speed; same as Rust, Go, C. nikaia build --target-cpu overrides it for one build, as --target does.

B — A, and absent = native for a build for the host machine (Zig’s choice), baseline for a cross build (--target differs from the host). The fastest program for someone who builds and runs on one machine, which is the script-like use the language aims at; a program copied to an older machine crashes.

C — A, and nikaia run uses native (it builds and runs on the same machine by definition, so it cannot hit the crash), while nikaia build stays baseline unless the key says otherwise.

Measurements owed before deciding

  1. benches/brc (1brc.nika against tuned.rs, both at the same level) at baseline, x86-64-v3 and native: instructions and mispredicts per row, the same output byte for byte.
  2. crates/nikaia/tests/measure.rs’s template and sparse-row workloads at baseline and x86-64-v3.
  3. Whether the cached std built with native differs per machine in a way the cache key must capture (it should key on the resolved CPU name, not the word native).

Recommendation

C: it gives nikaia run the full machine with no risk, keeps a built binary portable like every ahead-of-time toolchain except Zig, and the key (A) lets a deployment that knows its machines opt in. B’s crash on another machine is a bad first experience for exactly the user the language invites.

To build (written for C; adjusted once decided)

  1. Part III 13.3: target-cpu in [build.<target>], its values, absent = baseline for nikaia build, the machine’s own CPU for nikaia run; --target-cpu on build. ADR: a new record or a D of ADR-002/ADR-037, with the options above.
  2. sysroot::Codegen carries it; native is resolved to the CPU name (rustc --print target-cpus / -C target-cpu=native resolution) before it enters the cache key. Test: two builds with different values get two std entries; native on one machine reuses one entry.
  3. The generated Cargo.toml / RUSTFLAGS path and the fast-run rustc line both pass -C target-cpu. Test: nikaia run of a probe whose lowered binary uses popcnt for count_ones on a machine that has it (check the disassembly), and a nikaia build binary without the key does not.
  4. The measurements above in benches/brc/README.md and measure.rs, each row naming its CPU level.
  5. The website may then say tuned to your processor for nikaia run and for a build that asks for it.

Back to Open Issues