|
3 | 3 |
|
4 | 4 | //! Macros publicly exported
|
5 | 5 |
|
6 |
| -#![expect( |
7 |
| - missing_docs, |
8 |
| - reason = "TODO: https://github.com/linebender/fearless_simd/issues/40" |
9 |
| -)] |
10 |
| - |
| 6 | +/// Defines a new function which dispatches to a SIMD-generic function, enabling the correct |
| 7 | +/// target features. |
| 8 | +/// |
| 9 | +/// The `fn` token in the definition can be prefixed with a visibility (e.g. `pub`), |
| 10 | +/// to set the visibility of the outer function. |
| 11 | +/// We recommend that the implementation function remains private, and |
| 12 | +/// should only be called through the dispatch function. |
| 13 | +/// (The exact patterns for SIMD functions using Fearleess SIMD have not |
| 14 | +/// yet been designed/enumerated). |
| 15 | +/// |
| 16 | +/// The implementation function (which is outside of this macro) *should* have the |
| 17 | +/// `#[inline(always)]` attribute. |
| 18 | +/// There are likely to be severe performance consequences if this is not the case, as |
| 19 | +/// Rust will be unable to inline SIMD intrinsics in that case. |
| 20 | +/// |
| 21 | +/// The `fn` token in the definition can be prefixed with `unsafe`, to allow an unsafe inner function. |
| 22 | +/// The safety comment added by you in the call to `simd_dispatch` the function must have |
| 23 | +/// the preconditions required to call the inner function. |
| 24 | +/// |
| 25 | +/// # Examples |
| 26 | +/// |
| 27 | +/// ```rust |
| 28 | +/// use fearless_simd::{Simd, simd_dispatch}; |
| 29 | +/// |
| 30 | +/// #[inline(always)] |
| 31 | +/// fn sigmoid_impl<S: Simd>(simd: S, x: &[f32], out: &mut [f32]) { /* ... */ } |
| 32 | +/// |
| 33 | +/// simd_dispatch!(fn sigmoid(level, x: &[f32], out: &mut [f32]) = sigmoid_impl); |
| 34 | +/// ``` |
| 35 | +/// |
| 36 | +/// The signature of the generated function will be: |
| 37 | +/// |
| 38 | +/// ```rust |
| 39 | +/// use fearless_simd::Level; |
| 40 | +/// fn sigmoid(level: Level, x: &[f32], out: &mut [f32]) { /* ... */ } |
| 41 | +/// ``` |
11 | 42 | #[macro_export]
|
12 | 43 | macro_rules! simd_dispatch {
|
13 | 44 | (
|
14 | 45 | $( #[$meta:meta] )* $vis:vis
|
15 |
| - $func:ident ( level $( , $arg:ident : $ty:ty $(,)? )* ) $( -> $ret:ty )? |
| 46 | + unsafe fn $func:ident ( level $( , $arg:ident : $ty:ty $(,)? )* ) $( -> $ret:ty )? |
| 47 | + = $inner:ident |
| 48 | + ) => { |
| 49 | + simd_dispatch!{@impl => $(#[$meta])* $vis (unsafe) fn $func (level, $(,$arg:$ty,)*) $(->$ret)? = $inner} |
| 50 | + }; |
| 51 | + ( |
| 52 | + $( #[$meta:meta] )* $vis:vis |
| 53 | + fn $func:ident ( level $( , $arg:ident : $ty:ty $(,)? )* ) $( -> $ret:ty )? |
| 54 | + = $inner:ident |
| 55 | + ) => { |
| 56 | + simd_dispatch!{@impl => $(#[$meta])* $vis () fn $func (level $(,$arg:$ty)*) $(->$ret)? = $inner} |
| 57 | + }; |
| 58 | + ( |
| 59 | + @impl => $( #[$meta:meta] )* $vis:vis |
| 60 | + ($($unsafe: ident)?) fn $func:ident ( level $( , $arg:ident : $ty:ty $(,)? )* ) $( -> $ret:ty )? |
16 | 61 | = $inner:ident
|
17 | 62 | ) => {
|
18 | 63 | $( #[$meta] )* $vis
|
19 |
| - fn $func(level: $crate::Level $(, $arg: $ty )*) $( -> $ret )? { |
| 64 | + $($unsafe)? fn $func(level: $crate::Level $(, $arg: $ty )*) $( -> $ret )? { |
20 | 65 | #[cfg(target_arch = "aarch64")]
|
21 | 66 | #[target_feature(enable = "neon")]
|
22 | 67 | #[inline]
|
23 |
| - unsafe fn inner_neon(neon: $crate::aarch64::Neon $( , $arg: $ty )* ) $( -> $ret )? { |
24 |
| - $inner( neon $( , $arg )* ) |
| 68 | + $($unsafe)? fn inner_neon(neon: $crate::aarch64::Neon $( , $arg: $ty )* ) $( -> $ret )? { |
| 69 | + $($unsafe)? { |
| 70 | + $inner( neon $( , $arg )* ) |
| 71 | + } |
25 | 72 | }
|
26 | 73 | #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
|
27 | 74 | #[inline]
|
28 |
| - unsafe fn inner_wasm_simd128(simd128: $crate::wasm32::WasmSimd128 $( , $arg: $ty )* ) $( -> $ret )? { |
29 |
| - $inner( simd128 $( , $arg )* ) |
| 75 | + $($unsafe)? fn inner_wasm_simd128(simd128: $crate::wasm32::WasmSimd128 $( , $arg: $ty )* ) $( -> $ret )? { |
| 76 | + $($unsafe)? { |
| 77 | + $inner( simd128 $( , $arg )* ) |
| 78 | + } |
30 | 79 | }
|
31 | 80 | #[cfg(all(feature = "std", any(target_arch = "x86", target_arch = "x86_64")))]
|
32 | 81 | #[target_feature(enable = "sse4.2")]
|
33 | 82 | #[inline]
|
34 |
| - unsafe fn inner_sse4_2(sse4_2: $crate::x86::Sse4_2 $( , $arg: $ty )* ) $( -> $ret )? { |
35 |
| - $inner( sse4_2 $( , $arg )* ) |
| 83 | + $($unsafe)? fn inner_sse4_2(sse4_2: $crate::x86::Sse4_2 $( , $arg: $ty )* ) $( -> $ret )? { |
| 84 | + $($unsafe)? { |
| 85 | + $inner( sse4_2 $( , $arg )* ) |
| 86 | + } |
36 | 87 | }
|
37 | 88 | #[cfg(all(feature = "std", any(target_arch = "x86", target_arch = "x86_64")))]
|
38 | 89 | #[target_feature(enable = "avx2,fma")]
|
39 | 90 | #[inline]
|
40 |
| - unsafe fn inner_avx2(avx2: $crate::x86::Avx2 $( , $arg: $ty )* ) $( -> $ret )? { |
41 |
| - $inner( avx2 $( , $arg )* ) |
| 91 | + $($unsafe)? fn inner_avx2(avx2: $crate::x86::Avx2 $( , $arg: $ty )* ) $( -> $ret )? { |
| 92 | + $($unsafe)? { |
| 93 | + $inner( avx2 $( , $arg )* ) |
| 94 | + } |
42 | 95 | }
|
43 | 96 | match level {
|
44 | 97 | $crate::Level::Fallback(fb) => {
|
45 |
| - $inner(fb $( , $arg )* ) |
| 98 | + $($unsafe)? { |
| 99 | + $inner(fb $( , $arg )* ) |
| 100 | + } |
46 | 101 | },
|
47 | 102 | #[cfg(target_arch = "aarch64")]
|
48 | 103 | $crate::Level::Neon(neon) => unsafe { inner_neon (neon $( , $arg )* ) }
|
|
0 commit comments