Skip to main content

simd-tokens

Guides safe runtime CPU-feature dispatch in Rust with simd_tokens proof tokens and #[simd_entry] instead of is_x86_feature_detected! or is_aarch64_feature_detected! checks followed by unsafe calls. Use when writing or refactoring code that uses simd_tokens or #[target_feature] kernels, adding AVX2, AVX-512 or NEON dispatch with a scalar fallback, building SIMD backend traits or dispatch tables, or removing unsafe from SIMD code (e.g. to reach #![forbid(unsafe_code)]). Don't use for tuning kernel performance, choosing intrinsics, or benchmarking (use simd-optimizer).

Informações da origem

Repositório
google/simd_tokens
Última atividade na origem
16 de outubro de 2026 às 12:37
Idioma detectado do SKILL.md
inglês
Estrelas
1
Forks
0

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Explorador de arquivos
38 arquivos

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
simd-tokens
description
Guides safe runtime CPU-feature dispatch in Rust with simd_tokens proof tokens and #[simd_entry] instead of is_x86_feature_detected! or is_aarch64_feature_detected! checks followed by unsafe calls. Use when writing or refactoring code that uses simd_tokens or #[target_feature] kernels, adding AVX2, AVX-512 or NEON dispatch with a scalar fallback, building SIMD backend traits or dispatch tables, or removing unsafe from SIMD code (e.g. to reach #![forbid(unsafe_code)]). Don't use for tuning kernel performance, choosing intrinsics, or benchmarking (use simd-optimizer).
# Using `simd_tokens` Effectively `simd_tokens` provides zero-sized proof types (tokens) that prove CPU features are available at runtime, enabling safe dispatch of `#[target_feature]` functions without `unsafe`. Dependencies: `//security/ise_memory_safety/rust_simd/simd_tokens`, plus `//third_party/rust/safe_unaligned_simd/v0_2:safe_unaligned_simd` for safe loads and stores. ## Core Pattern 1. **Annotate kernel entrypoints with `#[simd_entry]`** and add a `token: impl SimdToken` parameter: ```rust use simd_tokens::{simd_entry, SimdToken}; #[simd_entry] #[target_feature(enable = "avx2")] pub fn transform(data: &mut [f32], token: impl SimdToken) { // ... SIMD intrinsics ... } ``` - Declare the function as safe `fn`, **not** `unsafe fn`: `#[simd_entry]` rejects an `unsafe fn` unless you write `#[simd_entry(still_unsafe)]`, which is only for functions with further safety preconditions (callers then still need `unsafe`). - By convention, place the token argument (`token: impl SimdToken`) as the last argument. - `#[simd_entry]` generates a safe wrapper whose token bound requires the matching feature trait (`SimdToken + Avx2`). 2. **Dispatch by checking tokens in descending capability order**: ```rust use simd_tokens::{Avx2Token, Sse2Token}; if let Some(token) = Avx2Token::try_new() { transform(data, token); // 100% safe — NO unsafe block! } else if let Some(token) = Sse2Token::try_new() { transform_sse2(data, token); } else { transform_scalar(data); } ``` 3. **Keep kernel bodies free of `unsafe`**: inside a `#[target_feature]` function, value-based intrinsics (`_mm256_add_ps`, `vaddq_f32`, ...) are safe to call. Only pointer-based loads and stores still need `unsafe`, so use the reference-based versions from `safe_unaligned_simd` and split slices with `as_chunks::<N>()` / `as_chunks_mut::<N>()`: ```rust use safe_unaligned_simd::x86_64::{_mm256_loadu_ps, _mm256_storeu_ps}; use simd_tokens::{simd_entry, SimdToken}; use std::arch::x86_64::{_mm256_mul_ps, _mm256_set1_ps}; #[simd_entry] #[target_feature(enable = "avx2")] pub fn scale(data: &mut [f32], factor: f32, token: impl SimdToken) { let factor_v = _mm256_set1_ps(factor); let (chunks, rest) = data.as_chunks_mut::<8>(); for chunk in chunks { let v = _mm256_mul_ps(_mm256_loadu_ps(chunk), factor_v); _mm256_storeu_ps(chunk, v); } for x in rest { *x *= factor; } } ``` With `#[simd_entry]` on the entry points and safe loads/stores in the bodies, a SIMD crate usually needs no `unsafe` at all: add `#![forbid(unsafe_code)]` so the compiler enforces it. 4. **Composing standalone entrypoints with `expose_raw_variant`**: If a kernel is **both** an external entrypoint (called with a token) and invoked internally by another kernel, use `#[simd_entry(expose_raw_variant)]`. This exposes a token-free `<fn>_raw` helper safe to call from matching `#[target_feature]` functions. (If a helper is *never* called with a token, do not use `#[simd_entry]` at all; see Antipatterns 3 and 4). -------------------------------------------------------------------------------- ## Antipatterns to Avoid ### 1. Check-then-Unsafe (Not using `#[simd_entry]`) ❌ **Antipattern**: Checking token presence (or storing a token in a struct) but leaving kernels as bare `#[target_feature]` functions called via `unsafe`: ```rust // ❌ WRONG: token checked, but call still requires unsafe! if let Some(_token) = Avx2Token::try_new() { unsafe { // SAFETY: token proved AVX2 exists process_avx2(data); } } ``` ✅ **Fix**: Add `token: impl SimdToken` and `#[simd_entry]` to the kernel. Pass the token to eliminate the `unsafe` block completely: ```rust // ✅ CORRECT: #[simd_entry] makes the call completely safe #[simd_entry] #[target_feature(enable = "avx2")] fn process_avx2(data: &mut [f32], token: impl SimdToken) { ... } if let Some(token) = Avx2Token::try_new() { process_avx2(data, token); // Safe! } ``` If using a backend struct or trait implementation, pass the token directly to the `#[simd_entry]` function (`*self` when the trait is implemented on the token itself, `self.0` for a wrapper like `struct Avx2Backend(Avx2Token)`) — never wrap the call in `unsafe`. Prefer implementing the trait on the token; the wrapper struct is unnecessary (see Antipattern 2). -------------------------------------------------------------------------------- ### 2. Manual Token Caching & Dispatch Tables ❌ **Antipattern**: Storing tokens or SIMD wrappers in `OnceLock`, `lazy_static`, or static variables to avoid re-checking CPU features: ```rust // ❌ WRONG: redundant caching overhead static AVX2_BACKEND: OnceLock<Avx2Backend> = OnceLock::new(); static AVX2_TOKEN: OnceLock<Option<Avx2Token>> = OnceLock::new(); ``` ✅ **Fix**: Call `<Token>::try_new()` directly at dispatch sites. - `try_new()` **already caches** the result internally using an atomic (`AtomicU8`). The first call detects features; subsequent calls are a single relaxed atomic load. - Tokens are **zero-sized types (ZST)** (`size_of::<Avx2Token>() == 0`) and implement `Copy`. Passing or creating them has zero heap and zero runtime memory cost. - Redundant `OnceLock` wrappers add synchronization overhead and boilerplate for no benefit. **Dispatch Tables & `&'static dyn Trait`**: For dynamic dispatch tables, implement the trait directly on the tokens and use `.as_static()`. This works for your crate's own trait even though the token types are defined in `simd_tokens` (the orphan rule allows implementing a local trait for a foreign type), so no wrapper struct and no `OnceLock` are needed: ```rust pub trait Backend { fn process(&self, data: &mut [f32]); } impl Backend for Avx2Token { #[inline(always)] fn process(&self, data: &mut [f32]) { process_avx2(data, *self); } } impl Backend for ScalarToken { #[inline(always)] fn process(&self, data: &mut [f32]) { process_scalar(data); } } pub fn get_backend() -> &'static dyn Backend { if let Some(token) = Avx2Token::try_new() { return token.as_static(); // &'static dyn Backend — zero alloc, zero locks! } ScalarToken.as_static() } ``` `token.as_static()` returns `&'static Self` directly. Because tokens are ZSTs and valid for the lifetime of the process, this requires no `OnceLock`, no `Box::leak`, no heap allocation, and no synchronization. -------------------------------------------------------------------------------- ### 3. Misusing `expose_raw_variant` on Pure Helpers ❌ **Antipattern**: Putting `#[simd_entry(expose_raw_variant)]` on internal helper functions that are never called with a token from the outside: ```rust // ❌ WRONG: helper is never called directly with a token! #[simd_entry(expose_raw_variant)] #[target_feature(enable = "avx2")] fn internal_butterfly(data: &mut [f32], _token: impl SimdToken) { ... } #[simd_entry] #[target_feature(enable = "avx2")] pub fn transform(data: &mut [f32], token: impl SimdToken) { internal_butterfly_raw(data); } ``` ✅ **Fix**: If a helper is never invoked directly with a token, it does **not** need `#[simd_entry]`. Keep it as a plain, safe `#[target_feature]` function: ```rust // ✅ CORRECT: internal helper is just a standard target_feature function #[inline] #[target_feature(enable = "avx2")] fn internal_butterfly(data: &mut [f32]) { ... } #[simd_entry] #[target_feature(enable = "avx2")] pub fn transform(data: &mut [f32], token: impl SimdToken) { internal_butterfly(data); // safe: the caller enables the same features } ``` Calling a safe `#[target_feature]` function needs no `unsafe` from a function that enables the same (or more) features, which a `#[simd_entry]` body does. Do not declare such helpers `unsafe fn` or wrap their calls in `unsafe`. Only use `expose_raw_variant` when a function is **both** an external token-entrypoint and called internally by another kernel. -------------------------------------------------------------------------------- ### 4. Non-`#[simd_entry]` Leaf Helpers: `#[inline(always)]` vs. `#[target_feature]` Choose inlining and feature annotations on non-`#[simd_entry]` leaf helpers based on whether the helper calls SIMD intrinsics: - **Pure-Rust leaf helpers (no intrinsics)**: For slice/chunk extraction, scalar math, or autovectorizable loops over `[T; N]`, use `#[inline(always)]` with **no** `#[target_feature]` and **no** `#[simd_entry]`. Because baseline features are a subset of every caller's features, the helper is safe to call from all contexts (`scalar`, `avx2`, `avx512`, `neon`), and LLVM inlines a copy into each caller to compile and vectorize under that caller's target features: ```rust // ✅ CORRECT: no intrinsics -> #[inline(always)], reusable everywhere #[inline(always)] fn mix_block(a: &[f32; 8], b: &[f32; 8]) -> [f32; 8] { std::array::from_fn(|i| a[i] + b[i]) } ``` - **Intrinsic-using leaf helpers (`core::arch` / `safe_unaligned_simd`)**: If a leaf calls *any* SIMD intrinsic — even baseline ones like `sse2` on `x86_64` or `neon` on `aarch64` — annotate it with **`#[inline]` + `#[target_feature(enable = "...")]`** (never `#[inline(always)]`): - ❌ Do **not** omit `#[target_feature]` and rely on `#[inline(always)]`: `rustc` checks `#[target_feature]` safety per-function before inlining, so calling any intrinsic without a matching `#[target_feature]` fails with `E0133` (even when the feature is enabled in the build config). Wrapping calls in `unsafe` inside a featureless safe `fn` is unsound and violates `#![forbid(unsafe_code)]`. - ❌ Do **not** combine `#[inline(always)]` with `#[target_feature]`: `rustc` currently rejects this combination as a hard error.
Ver no GitHub
Este SKILL.md e muito grande, entao o SkillsMP mostra aqui apenas a primeira secao. Ver no GitHub