### Operator Overloading Example Source: https://github.com/arduano/simdeez/blob/master/README.md SIMDeez supports operator overloading for common arithmetic operations, allowing for more idiomatic Rust code when working with SIMD vectors. ```rust let sum = va + vb; simulacrum *= simulacrum; ``` -------------------------------- ### Single Lane Access Example Source: https://github.com/arduano/simdeez/blob/master/README.md Developers can extract or set individual lanes (elements) within a SIMD vector using the index operator, similar to accessing elements in a standard array or vector. ```rust let v1 = v[1]; ``` -------------------------------- ### SIMD Intrinsic Naming Convention Source: https://github.com/arduano/simdeez/blob/master/README.md SIMDeez adopts familiar Intel intrinsic naming conventions, simplifying porting and usage. For example, Intel's `_mm_add_ps(a,b)` is exposed as `add_ps(a,b)` within SIMDeez. ```rust // Intel intrinsic: _mm_add_ps(a, b) // SIMDeez equivalent: add_ps(a, b) ``` -------------------------------- ### simdeez Macro Generated Functions Source: https://github.com/arduano/simdeez/blob/master/README.md The `simd_runtime_generate!` macro in simdeez automatically generates multiple versions of a function. This documentation outlines the typical functions produced, including a generic version, a scalar fallback, and optimized versions for specific instruction sets (SSE2, SSE41, AVX2, NEON, WASM SIMD), plus a runtime-selected best version. ```APIDOC simd_runtime_generate! macro output: - `distance`: The generic version of your function, parameterized by a SIMD trait. - `distance_scalar`: A scalar fallback implementation for CPUs without SIMD support or when SIMD is not beneficial. - `distance_sse2`: Optimized version using SSE2 instructions. - `distance_sse41`: Optimized version using SSE4.1 instructions. - `distance_avx2`: Optimized version using AVX2 instructions. - `distance_neon`: Optimized version using NEON instructions (for ARM processors). - `distance_wasm`: Optimized version for WebAssembly SIMD. - `distance_runtime_select`: A wrapper function that detects the CPU's capabilities at runtime and calls the fastest available implementation among the generated ones. Usage: Typically, you would call `distance_runtime_select()` to leverage the best performance automatically. Alternative Macro: `simd_compiletime_generate!` This macro produces two functions: - `distance`: The generic version. - `distance_compiletime`: The fastest version available based on the CPU features enabled at compile time via `target-features`. Manual Implementation: It is also possible to forgo the macros and manually implement each SIMD version, but this requires careful management of `target-features` and inlining. ``` -------------------------------- ### Rust SIMD Distance Calculation with simdeez Source: https://github.com/arduano/simdeez/blob/master/README.md This snippet shows how to use the `simd_runtime_generate!` macro from the simdeez crate to create a SIMD-accelerated distance function. It handles runtime feature detection to select the most efficient implementation for the target CPU, along with a scalar fallback. ```Rust use simdeez::{prelude::*, simd_runtime_generate}; use rand::prelude::* ; // If you want your SIMD function to use use runtime feature detection to call // the fastest available version, use the simd_runtime_generate macro: simd_runtime_generate!( fn distance(x1: &[f32], y1: &[f32], x2: &[f32], y2: &[f32]) -> Vec { let mut result: Vec = Vec::with_capacity(x1.len()); result.set_len(x1.len()); // for efficiency // Set each slice to the same length for iteration efficiency let mut x1 = &x1[..x1.len()]; let mut y1 = &y1[..x1.len()]; let mut x2 = &x2[..x1.len()]; let mut y2 = &y2[..x1.len()]; let mut res = &mut result[..x1.len()]; // Operations have to be done in terms of the vector width // so that it will work with any size vector. // the width of a vector type is provided as a constant // so the compiler is free to optimize it more. // Vf32::WIDTH is a constant, 4 when using SSE, 8 when using AVX2, etc while x1.len() >= S::Vf32::WIDTH { //load data from your vec into an SIMD value let xv1 = S::Vf32::load_from_slice(&x1); let yv1 = S::Vf32::load_from_slice(&y1); let xv2 = S::Vf32::load_from_slice(&x2); let yv2 = S::Vf32::load_from_slice(&y2); // Use the usual intrinsic syntax if you prefer let mut xdiff = xv1 - xv2; // Or use operater overloading if you like let mut ydiff = yv1 - yv2; xdiff *= xdiff; ydiff *= ydiff; let distance = (xdiff + ydiff).sqrt(); // Store the SIMD value into the result vec distance.copy_to_slice(res); // Move each slice to the next position x1 = &x1[S::Vf32::WIDTH..]; y1 = &y1[S::Vf32::WIDTH..]; x2 = &x2[S::Vf32::WIDTH..]; y2 = &y2[S::Vf32::WIDTH..]; res = &mut res[S::Vf32::WIDTH..]; } // (Optional) Compute the remaining elements. Not necessary if you are sure the length // of your data is always a multiple of the maximum S::Vf32_WIDTH you compile for (4 for SSE, 8 for AVX2, etc). // This can be asserted by putting `assert_eq!(x1.len(), 0);` here for i in 0..x1.len() { let mut xdiff = x1[i] - x2[i]; let mut ydiff = y1[i] - y2[i]; xdiff *= xdiff; ydiff *= ydiff; let distance = (xdiff + ydiff).sqrt(); res[i] = distance; } result } ); const SIZE: usize = 200; fn main() { let mut rng = rand::thread_rng(); let raw = (0..4) .map(|_i| (0..SIZE).map(|_j| rng.gen::()).collect::>()) .collect::>>(); let distances = distance( raw[0].as_slice(), raw[1].as_slice(), raw[2].as_slice(), raw[3].as_slice(), ); assert_eq!(distances.len(), SIZE); dbg!(distances); } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.