Skip to main content

Overview

whatsapp-rust sets no -C target-feature in its own build. The crate is published to crates.io, so it cannot know what CPU it will run on. The flag has no runtime fallback: a binary built with a feature the CPU lacks does not degrade, it crashes on the first illegal instruction — SIGILL on Unix, STATUS_ILLEGAL_INSTRUCTION on Windows. If you control your own deployment target, you can trade that safety for fewer instructions executed yourself. Setting +bmi2,+avx2 measures at roughly a fifth fewer instructions (via callgrind, not wall-clock time) on the measured Signal encrypt paths — group and DM encryption; decryption is not separately benchmarked here.
This is opt-in for applications with a known deployment target, never a default. If you build without an explicit --target, every machine that will build or run your binary needs both features — see below.

Recommendation

.cargo/config.toml
If a target.<triple>.rustflags array for the same triple also exists in an ancestor directory’s config or in $CARGO_HOME/config.toml, Cargo joins the arrays across that hierarchy rather than replacing one with the other. What does not combine is the choice between rustflags sources. Cargo takes rustflags from exactly one of CARGO_ENCODED_RUSTFLAGS, RUSTFLAGS, target.<triple>.rustflags, or build.rustflags, in that priority order. So an invocation that sets RUSTFLAGS for any other reason silently discards the config entry above — merge the feature flags into that variable instead in that case.

Confirm every deployment target actually has both features

Check by feature bit, not by the CPU’s age or product name. Intel Silvermont and Goldmont, and AMD Jaguar and Puma, all lack one or both features — Goldmont and Puma despite being newer than Haswell — while other parts sold under the same Atom/Celeron/Pentium names do have both. Use an OS-filtered report, since a raw CPUID read can claim AVX2 is present when the OS hasn’t enabled the YMM state it needs. On Linux, /proc/cpuinfo is already OS-filtered:
On Windows or macOS, there’s no equivalent file to grep — check from Rust itself with is_x86_feature_detected!, which queries the OS-filtered feature set on every platform stdlib supports.

The build host needs the features too

A [target.x86_64-unknown-linux-gnu] rustflags entry reaches your build scripts and proc macros too, but only when you invoke cargo without an explicit --target — that’s when cargo unifies host and target compilation. -Ctarget-feature only tells LLVM it’s allowed to emit those instructions in code built for the host, not that any given build script or proc macro actually will — so if your builder is an older machine building for a newer fleet, the build itself may or may not fail, depending on what those host artifacts happen to contain. Either require both features on the builder, or pass --target x86_64-unknown-linux-gnu explicitly: that splits host tools from the target build, and the rustflags entry no longer reaches them.

Why not a library default

The failure mode is worse than a refusal to start. A load-time ISA check does exist in principle (glibc 2.33+‘s GNU_PROPERTY_X86_ISA_1_NEEDED), but -C target-feature doesn’t emit that property — so there’s no guaranteed check at startup. The process starts normally, passes its readiness probe, and traps whenever execution first reaches an emitted instruction, which can be well after boot and into live traffic. A clean startup is not evidence of compatibility. That’s an acceptable trade if you have a known, homogeneous fleet. It’s not one a published library can make on your behalf.

Measured impact

Instruction counts (Ir, via callgrind) on this repository’s own Signal benches, as a delta against a build with no target-feature set: The two flags are additive because they touch disjoint code: +bmi2 speeds up FieldElement51 arithmetic (LLVM emits mulx), while +avx2 vectorizes the constant-time fixed-base lookup table scan — a different function entirely. +adx was measured and rejected: it adds nothing over +bmi2 alone (0.0004% apart on a full send benchmark) while raising the CPU floor a generation, because FieldElement51’s limbs never form the carry chain adcx/adox would pay for. -Ctarget-cpu=native was measured and rejected too — on the measurement host it emitted AVX-512 that made the binary die under Valgrind-based profiling (including CodSpeed CI), and prior wall-clock A/B testing found it slower than the explicit +bmi2,+avx2 list on the same host family.

wasm32

For wasm32-unknown-unknown, the equivalent is -Ctarget-feature=+simd128. Whether you can use it depends on the runtimes you deploy to, not on any CPU: a module using v128 fails WebAssembly validation outright on an engine without the SIMD proposal. whatsapp-rust builds clean with the flag set. No wasm-side speed or size numbers are published here — this workspace declares no cdylib and has no wasm benchmark harness to measure one.