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):

  1. Compile-time static conditional (#[cfg(target_feature = "avx2")]): Only active if the entire binary was compiled with -C target-feature=+avx2 or -C target-cpu=native.
  2. 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 checking std::arch::is_x86_feature_detected! or std::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