Attributes and Conditional Compilation
Target Architecture Conditions
Target architecture conditions allow Rust code to specialize algorithms for specific CPU instruction sets (target_arch), register widths (target_pointer_width), byte orderings (target_endian), atomic lock-free widths (target_has_atomic), and vector SIMD extensions (target_feature).
Built-In CPU Architecture Predicates
| Predicate | Common Values | Use Case |
|---|---|---|
target_arch |
"x86_64", "aarch64", "x86", "arm", "riscv64", "wasm32" |
Selecting architecture-specific std::arch intrinsics or asm! blocks |
target_pointer_width |
"64", "32", "16" |
Choosing u64 vs. u32 bit-packing layouts based on usize width |
target_endian |
"little", "big" |
Zero-cost byte-slice casting when target endianness matches wire format |
target_has_atomic |
"8", "16", "32", "64", "128", "ptr" |
Checking whether the target CPU supports lock-free AtomicU64 (important on 32-bit embedded thumbv6m / riscv32i targets!) |
target_feature |
"avx2", "sse4.2", "aes", "neon", "simd128" |
Checking whether a CPU SIMD extension is enabled at compile time (-C target-feature=+avx2) |
Compile-Time vs. Runtime CPU Feature Dispatch (#[target_feature] and is_x86_feature_detected!)
There are two ways to use CPU SIMD extensions (such as avx2 on x86_64 or neon on aarch64):
- Compile-time static conditional (
#[cfg(target_feature = "avx2")]): Only active if the entire binary was compiled with-C target-feature=+avx2or-C target-cpu=native. - Runtime dynamic CPU dispatch (
#[target_feature(enable = "...")]): Compiles a specific unsafe function with the SIMD instruction set enabled even in a baseline binary, and selects it at runtime after checkingstd::arch::is_x86_feature_detected!orstd::arch::is_aarch64_feature_detected!:
Runtime SIMD Dispatch Flow:
pub fn sum_bytes(data: &[u8]) -> u64
|
+-- On x86_64: `is_x86_feature_detected!("avx2")`?
| Yes ---> Calls `#[target_feature(enable = "avx2")] unsafe fn sum_avx2`
| No ---> Calls portable fallback
|
+-- On aarch64: `#[cfg(target_feature = "neon")]` (enabled by default on AArch64!)
---> Calls NEON / portable auto-vectorized loop
fn describe_cpu_capabilities() {
#[cfg(target_arch = "aarch64")]
println!("CPU arch: aarch64 (NEON enabled at compile time = {})", cfg!(target_feature = "neon"));
#[cfg(target_arch = "x86_64")]
println!(
"CPU arch: x86_64 (AVX2 detected at runtime = {})",
std::arch::is_x86_feature_detected!("avx2")
);
#[cfg(target_has_atomic = "64")]
println!("64-bit hardware atomics (`AtomicU64`) are supported on this target");
println!(
"pointer width = {} bits, little-endian = {}",
usize::BITS,
cfg!(target_endian = "little")
);
}
fn main() {
describe_cpu_capabilities();
}
CPU arch: aarch64 (NEON enabled at compile time = true)
64-bit hardware atomics (`AtomicU64`) are supported on this target
pointer width = 64 bits, little-endian = true