Skip to main content

arcane

Attribute Macro arcane 

Source
#[arcane]
Available on crate feature macros only.
Expand description

Mark a function as an arcane SIMD function.

This macro generates a safe wrapper around a #[target_feature] function. The token parameter type determines which CPU features are enabled.

§Expansion Modes

§Sibling (default)

Generates two functions at the same scope: a safe #[target_feature] sibling and a safe wrapper. self/Self work naturally since both functions share scope. Compatible with #![forbid(unsafe_code)].

#[arcane]
fn process(token: X64V3Token, data: &[f32; 8]) -> [f32; 8] { /* body */ }
// Expands to (x86_64 only):
#[cfg(target_arch = "x86_64")]
#[doc(hidden)]
#[target_feature(enable = "avx2,fma,...")]
fn __arcane_process(token: X64V3Token, data: &[f32; 8]) -> [f32; 8] { /* body */ }

#[cfg(target_arch = "x86_64")]
fn process(token: X64V3Token, data: &[f32; 8]) -> [f32; 8] {
    unsafe { __arcane_process(token, data) }
}

Methods work naturally:

impl MyType {
    #[arcane]
    fn compute(&self, token: X64V3Token) -> f32 {
        self.data.iter().sum()  // self/Self just work!
    }
}

§Nested (nested or _self = Type)

Generates a nested inner function inside the original. Required for trait impls (where sibling functions would fail) and when _self = Type is used.

impl SimdOps for MyType {
    #[arcane(_self = MyType)]
    fn compute(&self, token: X64V3Token) -> Self {
        // Use _self instead of self, Self replaced with MyType
        _self.data.iter().sum()
    }
}

§Cross-Architecture Behavior

Default (cfg-out): On the wrong architecture, the function is not emitted at all — no stub, no dead code. Code that references it must be cfg-gated.

With stub: Generates an unreachable!() stub on wrong architectures. Use when cross-arch dispatch references the function without cfg guards.

#[arcane(stub)]  // generates stub on wrong arch
fn process_neon(token: NeonToken, data: &[f32]) -> f32 { ... }

incant! is unaffected — it already cfg-gates dispatch calls by architecture.

§Token Parameter Forms

// Concrete token
#[arcane]
fn process(token: X64V3Token, data: &[f32; 8]) -> [f32; 8] { ... }

// impl Trait bound
#[arcane]
fn process(token: impl HasX64V2, data: &[f32; 8]) -> [f32; 8] { ... }

// Generic with inline or where-clause bounds
#[arcane]
fn process<T: HasX64V2>(token: T, data: &[f32; 8]) -> [f32; 8] { ... }

// Wildcard
#[arcane]
fn process(_: X64V3Token, data: &[f32; 8]) -> [f32; 8] { ... }

§Options

OptionEffect
stubGenerate unreachable!() stub on wrong architecture
nestedUse nested inner function instead of sibling
_self = TypeImplies nested, transforms self receiver, replaces Self
inline_alwaysUse #[inline(always)] (requires nightly)
import_intrinsicsAuto-import archmage::intrinsics::{arch}::* (includes safe memory ops)
import_magetypesAuto-import magetypes::simd::{ns}::* and magetypes::simd::backends::*

§Auto-Imports

import_intrinsics and import_magetypes inject use statements into the function body, eliminating boilerplate. The macro derives the architecture and namespace from the token type:

// Without auto-imports — lots of boilerplate:
use std::arch::x86_64::*;
use magetypes::simd::v3::*;

#[arcane]
fn process(token: X64V3Token, data: &[f32; 8]) -> f32 {
    let v = f32x8::load(token, data);
    let zero = _mm256_setzero_ps();
    // ...
}

// With auto-imports — clean:
#[arcane(import_intrinsics, import_magetypes)]
fn process(token: X64V3Token, data: &[f32; 8]) -> f32 {
    let v = f32x8::load(token, data);
    let zero = _mm256_setzero_ps();
    // ...
}

The namespace mapping is token-driven:

Tokenimport_intrinsicsimport_magetypes
X64V1..V3Tokenarchmage::intrinsics::x86_64::*magetypes::simd::v3::*
X64V4Tokenarchmage::intrinsics::x86_64::*magetypes::simd::v4::*
X64V4xTokenarchmage::intrinsics::x86_64::*magetypes::simd::v4x::*
NeonToken / ARMarchmage::intrinsics::aarch64::*magetypes::simd::neon::*
Wasm128Tokenarchmage::intrinsics::wasm32::*magetypes::simd::wasm128::*

Works with concrete tokens, impl Trait bounds, and generic parameters.

§Supported Tokens

  • x86_64: X64V2Token, X64V3Token/Desktop64, X64V4Token/Avx512Token/Server64, X64V4xToken, Avx512Fp16Token, X64CryptoToken, X64V3CryptoToken
  • ARM: NeonToken/Arm64, Arm64V2Token, Arm64V3Token, NeonAesToken, NeonSha3Token, NeonCrcToken
  • WASM: Wasm128Token

§Supported Trait Bounds

HasX64V2, HasX64V4, HasNeon, HasNeonAes, HasNeonSha3, HasArm64V2, HasArm64V3

#![feature(target_feature_inline_always)]

#[arcane(inline_always)]
fn fast_kernel(token: Avx2Token, data: &mut [f32]) {
    // Inner function will use #[inline(always)]
}