/rust/registry/src/index.crates.io-1949cf8c6b5b557f/diskann-wide-0.54.0/src/emulated.rs
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) Microsoft Corporation. |
3 | | * Licensed under the MIT license. |
4 | | */ |
5 | | |
6 | | use half::f16; |
7 | | |
8 | | use super::{ |
9 | | SplitJoin, SupportedLaneCount, ZipUnzip, |
10 | | arch::{self, emulated::Scalar}, |
11 | | bitmask::BitMask, |
12 | | constant::Const, |
13 | | reference::{ReferenceAbs, ReferenceCast, ReferenceScalarOps, ReferenceShifts, TreeReduce}, |
14 | | traits::{ |
15 | | ArrayType, SIMDAbs, SIMDCast, SIMDDotProduct, SIMDMask, SIMDMinMax, SIMDMulAdd, |
16 | | SIMDPartialEq, SIMDPartialOrd, SIMDReinterpret, SIMDSelect, SIMDSumTree, SIMDVector, |
17 | | }, |
18 | | }; |
19 | | |
20 | | /// An emulated SIMD vector. |
21 | | /// |
22 | | /// The emulated implementation behaves just like an intrinsic, but the APIs are implemented |
23 | | /// using loops over arrays rather than dispatching to platform specific instructions. |
24 | | /// |
25 | | /// The idea behind this type is that it can be used on architecture where explicit backend |
26 | | /// support has not been added, or when an architecture does not support a given type/length |
27 | | /// pair well. |
28 | | /// |
29 | | /// Furthermore, it can be used when developing new back-ends to provide fallback |
30 | | /// implementations. This allows new back-ends to be developed one piece at a time instead |
31 | | /// of all at once. |
32 | | /// |
33 | | /// NOTE: The alignment requirements of an emulated vector *will* be different than the |
34 | | /// alignment requirements of an actual intrinsic. |
35 | | /// |
36 | | /// Higher level code *must not* rely on alignments being compatible across architectures! |
37 | | #[derive(Debug, Clone, Copy)] |
38 | | pub struct Emulated<T, const N: usize, A = Scalar>(pub(crate) [T; N], A); |
39 | | |
40 | | impl<T, const N: usize, A> Emulated<T, N, A> { |
41 | 0 | pub fn from_arch_fn<F>(arch: A, f: F) -> Self |
42 | 0 | where |
43 | 0 | F: FnMut(usize) -> T, |
44 | | { |
45 | 0 | Self(core::array::from_fn(f), arch) |
46 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<half::binary16::f16, 1>>::from_arch_fn::<<diskann_wide::emulated::Emulated<half::binary16::f16, 1> as diskann_wide::traits::SIMDVector>::load_simd_first::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<half::binary16::f16, 8>>::from_arch_fn::<<diskann_wide::emulated::Emulated<half::binary16::f16, 8> as diskann_wide::traits::SIMDVector>::load_simd_first::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 1>>::from_arch_fn::<<diskann_wide::emulated::Emulated<f32, 1> as core::ops::arith::Add>::add::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 1>>::from_arch_fn::<<diskann_wide::emulated::Emulated<f32, 1> as core::ops::arith::Sub>::sub::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 1>>::from_arch_fn::<<diskann_wide::emulated::Emulated<f32, 1> as core::ops::arith::Mul>::mul::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4>>::from_arch_fn::<<diskann_wide::emulated::Emulated<f32, 4> as core::ops::arith::Add>::add::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4>>::from_arch_fn::<<diskann_wide::emulated::Emulated<f32, 4> as core::ops::arith::Sub>::sub::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4>>::from_arch_fn::<<diskann_wide::emulated::Emulated<f32, 4> as core::ops::arith::Mul>::mul::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4>>::from_arch_fn::<<diskann_wide::emulated::Emulated<f32, 4> as diskann_wide::traits::SIMDVector>::load_simd_first::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8>>::from_arch_fn::<<diskann_wide::emulated::Emulated<f32, 8> as core::ops::arith::Add>::add::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8>>::from_arch_fn::<<diskann_wide::emulated::Emulated<f32, 8> as core::ops::arith::Sub>::sub::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8>>::from_arch_fn::<<diskann_wide::emulated::Emulated<f32, 8> as diskann_wide::traits::SIMDMulAdd>::mul_add_simd::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8>>::from_arch_fn::<<diskann_wide::emulated::Emulated<f32, 8> as diskann_wide::traits::SIMDVector>::load_simd_first::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 1>>::from_arch_fn::<<diskann_wide::emulated::Emulated<i32, 1> as core::ops::arith::Add>::add::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 1>>::from_arch_fn::<<diskann_wide::emulated::Emulated<i32, 1> as core::ops::arith::Mul>::mul::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4>>::from_arch_fn::<<diskann_wide::emulated::Emulated<i32, 4> as core::ops::arith::Add>::add::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4>>::from_arch_fn::<<diskann_wide::emulated::Emulated<i32, 4> as core::ops::arith::Sub>::sub::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4>>::from_arch_fn::<<diskann_wide::emulated::Emulated<i32, 4> as core::ops::arith::Mul>::mul::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4>>::from_arch_fn::<<diskann_wide::emulated::Emulated<i32, 4> as diskann_wide::traits::SIMDMulAdd>::mul_add_simd::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<i8, 32>>::from_arch_fn::<<diskann_wide::emulated::Emulated<i8, 32> as core::ops::bit::Shl>::shl::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<i8, 32>>::from_arch_fn::<<diskann_wide::emulated::Emulated<i8, 32> as core::ops::bit::Shr>::shr::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<u8, 32>>::from_arch_fn::<<diskann_wide::emulated::Emulated<u8, 32> as core::ops::bit::Shl>::shl::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<u8, 32>>::from_arch_fn::<<diskann_wide::emulated::Emulated<u8, 32> as core::ops::bit::Shr>::shr::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 16>>::from_arch_fn::<<diskann_wide::emulated::Emulated<i16, 16> as core::ops::bit::Shl>::shl::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 16>>::from_arch_fn::<<diskann_wide::emulated::Emulated<i16, 16> as core::ops::bit::Shr>::shr::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<u64, 2>>::from_arch_fn::<<diskann_wide::emulated::Emulated<u64, 2> as core::ops::arith::Mul>::mul::{closure#0}>Unexecuted instantiation: <diskann_wide::emulated::Emulated<u64, 4>>::from_arch_fn::<<diskann_wide::emulated::Emulated<u64, 4> as core::ops::arith::Mul>::mul::{closure#0}> |
47 | | } |
48 | | |
49 | | impl<T, const N: usize, A> SIMDVector for Emulated<T, N, A> |
50 | | where |
51 | | T: Copy + std::fmt::Debug + Default, |
52 | | Const<N>: ArrayType<T, Type = [T; N]>, |
53 | | BitMask<N, A>: SIMDMask<Arch = A>, |
54 | | A: arch::Sealed, |
55 | | { |
56 | | type Arch = A; |
57 | | type Scalar = T; |
58 | | type Underlying = [T; N]; |
59 | | type ConstLanes = Const<N>; |
60 | | const LANES: usize = N; |
61 | | type Mask = BitMask<N, A>; |
62 | | |
63 | | /// The underlying behavior is emulated using loops and is not accelerated by back-end |
64 | | /// intrinsics. |
65 | | const EMULATED: bool = true; |
66 | | |
67 | | /// Return the Scalar architecture. |
68 | 0 | fn arch(self) -> A { |
69 | 0 | self.1 |
70 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as diskann_wide::traits::SIMDVector>::arch Unexecuted instantiation: <diskann_wide::emulated::Emulated<_, _, _> as diskann_wide::traits::SIMDVector>::arch |
71 | | |
72 | 0 | fn default(arch: A) -> Self { |
73 | 0 | Self([T::default(); N], arch) |
74 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 1> as diskann_wide::traits::SIMDVector>::default Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4> as diskann_wide::traits::SIMDVector>::default Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as diskann_wide::traits::SIMDVector>::default Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 1> as diskann_wide::traits::SIMDVector>::default Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4> as diskann_wide::traits::SIMDVector>::default Unexecuted instantiation: <diskann_wide::emulated::Emulated<_, _, _> as diskann_wide::traits::SIMDVector>::default |
75 | | |
76 | | /// Return the underlying array. |
77 | 0 | fn to_underlying(self) -> Self::Underlying { |
78 | 0 | self.0 |
79 | 0 | } |
80 | | |
81 | | /// Construct from the underlying array. |
82 | 0 | fn from_underlying(arch: A, repr: [T; N]) -> Self { |
83 | 0 | Self(repr, arch) |
84 | 0 | } |
85 | | |
86 | | /// Return the underlying array. |
87 | 0 | fn to_array(self) -> [T; N] { |
88 | 0 | self.0 |
89 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 1> as diskann_wide::traits::SIMDVector>::to_array Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 1> as diskann_wide::traits::SIMDVector>::to_array Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4> as diskann_wide::traits::SIMDVector>::to_array Unexecuted instantiation: <diskann_wide::emulated::Emulated<i8, 32> as diskann_wide::traits::SIMDVector>::to_array Unexecuted instantiation: <diskann_wide::emulated::Emulated<u8, 32> as diskann_wide::traits::SIMDVector>::to_array Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 16> as diskann_wide::traits::SIMDVector>::to_array Unexecuted instantiation: <diskann_wide::emulated::Emulated<u64, 2> as diskann_wide::traits::SIMDVector>::to_array Unexecuted instantiation: <diskann_wide::emulated::Emulated<u64, 4> as diskann_wide::traits::SIMDVector>::to_array |
90 | | |
91 | | /// Construct from the underlying array. |
92 | 0 | fn from_array(arch: A, x: [T; N]) -> Self { |
93 | 0 | Self(x, arch) |
94 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4> as diskann_wide::traits::SIMDVector>::from_array Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4> as diskann_wide::traits::SIMDVector>::from_array Unexecuted instantiation: <diskann_wide::emulated::Emulated<i8, 32> as diskann_wide::traits::SIMDVector>::from_array Unexecuted instantiation: <diskann_wide::emulated::Emulated<u8, 32> as diskann_wide::traits::SIMDVector>::from_array Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 16> as diskann_wide::traits::SIMDVector>::from_array Unexecuted instantiation: <diskann_wide::emulated::Emulated<u64, 2> as diskann_wide::traits::SIMDVector>::from_array Unexecuted instantiation: <diskann_wide::emulated::Emulated<u64, 4> as diskann_wide::traits::SIMDVector>::from_array |
95 | | |
96 | | /// Broadcast the provided scalar across all lanes. |
97 | 0 | fn splat(arch: A, value: Self::Scalar) -> Self { |
98 | 0 | Self([value; N], arch) |
99 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as diskann_wide::traits::SIMDVector>::splat Unexecuted instantiation: <diskann_wide::emulated::Emulated<_, _, _> as diskann_wide::traits::SIMDVector>::splat |
100 | | |
101 | | /// Load all the things. |
102 | | #[inline(always)] |
103 | 0 | unsafe fn load_simd(arch: A, ptr: *const T) -> Self { |
104 | | // SAFETY: The caller asserts that `ptr` is contiguously readable for `N` values. |
105 | 0 | Self( |
106 | 0 | unsafe { std::ptr::read_unaligned(ptr.cast::<[T; N]>()) }, |
107 | 0 | arch, |
108 | 0 | ) |
109 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as diskann_wide::traits::SIMDVector>::load_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<half::binary16::f16, 8> as diskann_wide::traits::SIMDVector>::load_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4> as diskann_wide::traits::SIMDVector>::load_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as diskann_wide::traits::SIMDVector>::load_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<half::binary16::f16, 1> as diskann_wide::traits::SIMDVector>::load_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<half::binary16::f16, 8> as diskann_wide::traits::SIMDVector>::load_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<i8, 1> as diskann_wide::traits::SIMDVector>::load_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<i8, 4> as diskann_wide::traits::SIMDVector>::load_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4> as diskann_wide::traits::SIMDVector>::load_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as diskann_wide::traits::SIMDVector>::load_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<u8, 1> as diskann_wide::traits::SIMDVector>::load_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<u8, 4> as diskann_wide::traits::SIMDVector>::load_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<_, _, _> as diskann_wide::traits::SIMDVector>::load_simd |
110 | | |
111 | | /// Only load values when the corresponding mask lane is set. |
112 | 0 | unsafe fn load_simd_masked_logical(arch: A, ptr: *const T, mask: Self::Mask) -> Self { |
113 | 0 | Self::from_arch_fn(arch, |i| { |
114 | 0 | if mask.get_unchecked(i) { |
115 | | // SAFETY: The caller ensures it's safe to access this offset from `ptr` |
116 | | // because the lane in `mask` is set. |
117 | 0 | unsafe { std::ptr::read_unaligned(ptr.add(i)) } |
118 | | } else { |
119 | 0 | T::default() |
120 | | } |
121 | 0 | }) |
122 | 0 | } |
123 | | |
124 | | /// Only load the first `first` items. Set the rest to zero. |
125 | | #[inline(always)] |
126 | 0 | unsafe fn load_simd_first(arch: A, ptr: *const T, first: usize) -> Self { |
127 | 0 | Self::from_arch_fn(arch, |i| { |
128 | 0 | if i < first { |
129 | | // SAFETY: The caller ensures it's safe to access the first `first` values |
130 | | // beginning at `ptr`. |
131 | 0 | unsafe { std::ptr::read_unaligned(ptr.add(i)) } |
132 | | } else { |
133 | 0 | T::default() |
134 | | } |
135 | 0 | }) Unexecuted instantiation: <diskann_wide::emulated::Emulated<half::binary16::f16, 1> as diskann_wide::traits::SIMDVector>::load_simd_first::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<half::binary16::f16, 8> as diskann_wide::traits::SIMDVector>::load_simd_first::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4> as diskann_wide::traits::SIMDVector>::load_simd_first::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as diskann_wide::traits::SIMDVector>::load_simd_first::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<_, _, _> as diskann_wide::traits::SIMDVector>::load_simd_first::{closure#0} |
136 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as diskann_wide::traits::SIMDVector>::load_simd_first Unexecuted instantiation: <diskann_wide::emulated::Emulated<half::binary16::f16, 8> as diskann_wide::traits::SIMDVector>::load_simd_first Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as diskann_wide::traits::SIMDVector>::load_simd_first Unexecuted instantiation: <diskann_wide::emulated::Emulated<half::binary16::f16, 1> as diskann_wide::traits::SIMDVector>::load_simd_first Unexecuted instantiation: <diskann_wide::emulated::Emulated<half::binary16::f16, 8> as diskann_wide::traits::SIMDVector>::load_simd_first Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4> as diskann_wide::traits::SIMDVector>::load_simd_first Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as diskann_wide::traits::SIMDVector>::load_simd_first Unexecuted instantiation: <diskann_wide::emulated::Emulated<_, _, _> as diskann_wide::traits::SIMDVector>::load_simd_first |
137 | | |
138 | | /// Store all the things. |
139 | | #[inline(always)] |
140 | 0 | unsafe fn store_simd(self, ptr: *mut T) { |
141 | | // SAFETY: The caller asserts that it is safe to write `N` contiguous values to `ptr`. |
142 | 0 | unsafe { ptr.cast::<[T; N]>().write_unaligned(self.0) } |
143 | 0 | } |
144 | | |
145 | | /// Only store values when the corresponding mask lane is set. |
146 | 0 | unsafe fn store_simd_masked_logical(self, ptr: *mut T, mask: Self::Mask) { |
147 | 0 | for (i, v) in self.0.iter().enumerate() { |
148 | 0 | if mask.get_unchecked(i) { |
149 | 0 | // SAFETY: The caller asserts it is safe to write to offsets with the |
150 | 0 | // corresponding bit mask set. |
151 | 0 | unsafe { ptr.add(i).write_unaligned(*v) }; |
152 | 0 | } |
153 | | } |
154 | 0 | } |
155 | | |
156 | | /// Only store the first `first` items. Set the rest to zero. |
157 | | #[inline(always)] |
158 | 0 | unsafe fn store_simd_first(self, ptr: *mut T, first: usize) { |
159 | 0 | for (i, v) in self.0.iter().enumerate().take(first) { |
160 | 0 | // SAFETY: The caller asserts it is safe to write to the first `first` offsets |
161 | 0 | // beginning at `ptr`. |
162 | 0 | unsafe { ptr.add(i).write_unaligned(*v) }; |
163 | 0 | } |
164 | 0 | } |
165 | | } |
166 | | |
167 | | /// Binary Ops |
168 | | impl<T, const N: usize, A> std::ops::Add for Emulated<T, N, A> |
169 | | where |
170 | | T: ReferenceScalarOps + Copy + std::fmt::Debug + std::default::Default, |
171 | | Const<N>: ArrayType<T>, |
172 | | { |
173 | | type Output = Self; |
174 | 0 | fn add(self, rhs: Self) -> Self { |
175 | 0 | Self::from_arch_fn(self.1, |i| self.0[i].expected_add_(rhs.0[i])) Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 1> as core::ops::arith::Add>::add::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4> as core::ops::arith::Add>::add::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as core::ops::arith::Add>::add::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 1> as core::ops::arith::Add>::add::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4> as core::ops::arith::Add>::add::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<_, _, _> as core::ops::arith::Add>::add::{closure#0} |
176 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 1> as core::ops::arith::Add>::add Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4> as core::ops::arith::Add>::add Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as core::ops::arith::Add>::add Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 1> as core::ops::arith::Add>::add Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4> as core::ops::arith::Add>::add Unexecuted instantiation: <diskann_wide::emulated::Emulated<_, _, _> as core::ops::arith::Add>::add |
177 | | } |
178 | | |
179 | | impl<T, const N: usize, A> std::ops::Sub for Emulated<T, N, A> |
180 | | where |
181 | | T: ReferenceScalarOps, |
182 | | { |
183 | | type Output = Self; |
184 | | |
185 | | #[inline(always)] |
186 | 0 | fn sub(self, rhs: Self) -> Self { |
187 | 0 | Self::from_arch_fn(self.1, |i| self.0[i].expected_sub_(rhs.0[i])) Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 1> as core::ops::arith::Sub>::sub::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4> as core::ops::arith::Sub>::sub::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as core::ops::arith::Sub>::sub::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4> as core::ops::arith::Sub>::sub::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<_, _, _> as core::ops::arith::Sub>::sub::{closure#0} |
188 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4> as core::ops::arith::Sub>::sub Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as core::ops::arith::Sub>::sub Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 1> as core::ops::arith::Sub>::sub Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4> as core::ops::arith::Sub>::sub Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as core::ops::arith::Sub>::sub Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4> as core::ops::arith::Sub>::sub Unexecuted instantiation: <diskann_wide::emulated::Emulated<_, _, _> as core::ops::arith::Sub>::sub |
189 | | } |
190 | | |
191 | | impl<T, const N: usize, A> std::ops::Mul for Emulated<T, N, A> |
192 | | where |
193 | | T: ReferenceScalarOps, |
194 | | { |
195 | | type Output = Self; |
196 | 0 | fn mul(self, rhs: Self) -> Self { |
197 | 0 | Self::from_arch_fn(self.1, |i| self.0[i].expected_mul_(rhs.0[i])) Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 1> as core::ops::arith::Mul>::mul::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4> as core::ops::arith::Mul>::mul::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 1> as core::ops::arith::Mul>::mul::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4> as core::ops::arith::Mul>::mul::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<u64, 2> as core::ops::arith::Mul>::mul::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<u64, 4> as core::ops::arith::Mul>::mul::{closure#0} |
198 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 1> as core::ops::arith::Mul>::mul Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4> as core::ops::arith::Mul>::mul Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 1> as core::ops::arith::Mul>::mul Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4> as core::ops::arith::Mul>::mul Unexecuted instantiation: <diskann_wide::emulated::Emulated<u64, 2> as core::ops::arith::Mul>::mul Unexecuted instantiation: <diskann_wide::emulated::Emulated<u64, 4> as core::ops::arith::Mul>::mul |
199 | | } |
200 | | |
201 | | /// MulAdd |
202 | | impl<T, const N: usize, A> SIMDMulAdd for Emulated<T, N, A> |
203 | | where |
204 | | T: ReferenceScalarOps, |
205 | | { |
206 | | #[inline(always)] |
207 | 0 | fn mul_add_simd(self, rhs: Self, accumulator: Self) -> Self { |
208 | 0 | Self::from_arch_fn(self.1, |i| { |
209 | 0 | self.0[i].expected_fma_(rhs.0[i], accumulator.0[i]) |
210 | 0 | }) Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as diskann_wide::traits::SIMDMulAdd>::mul_add_simd::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4> as diskann_wide::traits::SIMDMulAdd>::mul_add_simd::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<_, _, _> as diskann_wide::traits::SIMDMulAdd>::mul_add_simd::{closure#0} |
211 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as diskann_wide::traits::SIMDMulAdd>::mul_add_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as diskann_wide::traits::SIMDMulAdd>::mul_add_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4> as diskann_wide::traits::SIMDMulAdd>::mul_add_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<_, _, _> as diskann_wide::traits::SIMDMulAdd>::mul_add_simd |
212 | | } |
213 | | |
214 | | /// MinMax |
215 | | impl<T, const N: usize, A> SIMDMinMax for Emulated<T, N, A> |
216 | | where |
217 | | T: ReferenceScalarOps, |
218 | | { |
219 | | #[inline(always)] |
220 | 0 | fn min_simd(self, rhs: Self) -> Self { |
221 | 0 | Self::from_arch_fn(self.1, |i| self.0[i].expected_min_(rhs.0[i])) |
222 | 0 | } |
223 | | #[inline(always)] |
224 | 0 | fn max_simd(self, rhs: Self) -> Self { |
225 | 0 | Self::from_arch_fn(self.1, |i| self.0[i].expected_max_(rhs.0[i])) |
226 | 0 | } |
227 | | } |
228 | | |
229 | | /// Abs |
230 | | impl<T, const N: usize, A> SIMDAbs for Emulated<T, N, A> |
231 | | where |
232 | | T: ReferenceAbs, |
233 | | { |
234 | | #[inline(always)] |
235 | 0 | fn abs_simd(self) -> Self { |
236 | 0 | Self::from_arch_fn(self.1, |i| self.0[i].expected_abs_()) |
237 | 0 | } |
238 | | } |
239 | | |
240 | | /// SIMDPartialEq |
241 | | impl<T, const N: usize, A> SIMDPartialEq for Emulated<T, N, A> |
242 | | where |
243 | | T: PartialEq, |
244 | | Self: SIMDVector, |
245 | | { |
246 | | #[inline(always)] |
247 | 0 | fn eq_simd(self, other: Self) -> Self::Mask { |
248 | 0 | Self::Mask::from_fn(self.arch(), |i| self.0[i] == other.0[i]) |
249 | 0 | } |
250 | | |
251 | | #[inline(always)] |
252 | 0 | fn ne_simd(self, other: Self) -> Self::Mask { |
253 | 0 | Self::Mask::from_fn(self.arch(), |i| self.0[i] != other.0[i]) |
254 | 0 | } |
255 | | } |
256 | | |
257 | | /// SIMDPartialOrd |
258 | | impl<T, const N: usize, A> SIMDPartialOrd for Emulated<T, N, A> |
259 | | where |
260 | | T: PartialOrd, |
261 | | Self: SIMDVector, |
262 | | { |
263 | | #[inline(always)] |
264 | 0 | fn lt_simd(self, other: Self) -> Self::Mask { |
265 | 0 | Self::Mask::from_fn(self.arch(), |i| self.0[i] < other.0[i]) |
266 | 0 | } |
267 | | |
268 | | #[inline(always)] |
269 | 0 | fn le_simd(self, other: Self) -> Self::Mask { |
270 | 0 | Self::Mask::from_fn(self.arch(), |i| self.0[i] <= other.0[i]) |
271 | 0 | } |
272 | | |
273 | | #[inline(always)] |
274 | 0 | fn gt_simd(self, other: Self) -> Self::Mask { |
275 | 0 | Self::Mask::from_fn(self.arch(), |i| self.0[i] > other.0[i]) |
276 | 0 | } |
277 | | |
278 | | #[inline(always)] |
279 | 0 | fn ge_simd(self, other: Self) -> Self::Mask { |
280 | 0 | Self::Mask::from_fn(self.arch(), |i| self.0[i] >= other.0[i]) Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as diskann_wide::traits::SIMDPartialOrd>::ge_simd::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<_, _, _> as diskann_wide::traits::SIMDPartialOrd>::ge_simd::{closure#0} |
281 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as diskann_wide::traits::SIMDPartialOrd>::ge_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<_, _, _> as diskann_wide::traits::SIMDPartialOrd>::ge_simd |
282 | | } |
283 | | |
284 | | // Bit Ops |
285 | | impl<T, const N: usize, A> std::ops::BitAnd for Emulated<T, N, A> |
286 | | where |
287 | | T: std::ops::BitAnd<Output = T> + Copy, |
288 | | { |
289 | | type Output = Self; |
290 | | #[inline(always)] |
291 | 0 | fn bitand(self, other: Self) -> Self::Output { |
292 | 0 | Self::from_arch_fn(self.1, |i| self.0[i] & other.0[i]) |
293 | 0 | } |
294 | | } |
295 | | |
296 | | impl<T, const N: usize, A> std::ops::BitOr for Emulated<T, N, A> |
297 | | where |
298 | | T: std::ops::BitOr<Output = T> + Copy, |
299 | | { |
300 | | type Output = Self; |
301 | | #[inline(always)] |
302 | 0 | fn bitor(self, other: Self) -> Self::Output { |
303 | 0 | Self::from_arch_fn(self.1, |i| self.0[i] | other.0[i]) |
304 | 0 | } |
305 | | } |
306 | | |
307 | | impl<T, const N: usize, A> std::ops::BitXor for Emulated<T, N, A> |
308 | | where |
309 | | T: std::ops::BitXor<Output = T> + Copy, |
310 | | { |
311 | | type Output = Self; |
312 | | #[inline(always)] |
313 | 0 | fn bitxor(self, other: Self) -> Self::Output { |
314 | 0 | Self::from_arch_fn(self.1, |i| self.0[i] ^ other.0[i]) |
315 | 0 | } |
316 | | } |
317 | | |
318 | | impl<T, const N: usize, A> std::ops::Not for Emulated<T, N, A> |
319 | | where |
320 | | T: std::ops::Not<Output = T> + Copy, |
321 | | { |
322 | | type Output = Self; |
323 | | #[inline(always)] |
324 | 0 | fn not(self) -> Self::Output { |
325 | 0 | Self::from_arch_fn(self.1, |i| !self.0[i]) |
326 | 0 | } |
327 | | } |
328 | | |
329 | | impl<T, const N: usize, A> std::ops::Shl for Emulated<T, N, A> |
330 | | where |
331 | | T: ReferenceShifts, |
332 | | { |
333 | | type Output = Self; |
334 | | #[inline(always)] |
335 | 0 | fn shl(self, rhs: Self) -> Self::Output { |
336 | 0 | Self::from_arch_fn(self.1, |i| self.0[i].expected_shl_(rhs.0[i])) Unexecuted instantiation: <diskann_wide::emulated::Emulated<i8, 32> as core::ops::bit::Shl>::shl::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<u8, 32> as core::ops::bit::Shl>::shl::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 16> as core::ops::bit::Shl>::shl::{closure#0} |
337 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<i8, 32> as core::ops::bit::Shl>::shl Unexecuted instantiation: <diskann_wide::emulated::Emulated<u8, 32> as core::ops::bit::Shl>::shl Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 16> as core::ops::bit::Shl>::shl |
338 | | } |
339 | | |
340 | | impl<T, const N: usize, A> std::ops::Shl<T> for Emulated<T, N, A> |
341 | | where |
342 | | T: ReferenceShifts, |
343 | | { |
344 | | type Output = Self; |
345 | | #[inline(always)] |
346 | 0 | fn shl(self, rhs: T) -> Self::Output { |
347 | 0 | Self::from_arch_fn(self.1, |i| self.0[i].expected_shl_(rhs)) |
348 | 0 | } |
349 | | } |
350 | | |
351 | | impl<T, const N: usize, A> std::ops::Shr for Emulated<T, N, A> |
352 | | where |
353 | | T: ReferenceShifts, |
354 | | { |
355 | | type Output = Self; |
356 | | #[inline(always)] |
357 | 0 | fn shr(self, rhs: Self) -> Self::Output { |
358 | 0 | Self::from_arch_fn(self.1, |i| self.0[i].expected_shr_(rhs.0[i])) Unexecuted instantiation: <diskann_wide::emulated::Emulated<i8, 32> as core::ops::bit::Shr>::shr::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<u8, 32> as core::ops::bit::Shr>::shr::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 16> as core::ops::bit::Shr>::shr::{closure#0} |
359 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<i8, 32> as core::ops::bit::Shr>::shr Unexecuted instantiation: <diskann_wide::emulated::Emulated<u8, 32> as core::ops::bit::Shr>::shr Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 16> as core::ops::bit::Shr>::shr |
360 | | } |
361 | | |
362 | | impl<T, const N: usize, A> std::ops::Shr<T> for Emulated<T, N, A> |
363 | | where |
364 | | T: ReferenceShifts, |
365 | | { |
366 | | type Output = Self; |
367 | | #[inline(always)] |
368 | 0 | fn shr(self, rhs: T) -> Self::Output { |
369 | 0 | Self::from_arch_fn(self.1, |i| self.0[i].expected_shr_(rhs)) |
370 | 0 | } |
371 | | } |
372 | | |
373 | | ////////////////// |
374 | | // Dot Products // |
375 | | ////////////////// |
376 | | |
377 | | // i16 to i32 |
378 | | macro_rules! impl_simd_dot_product_i16_to_i32 { |
379 | | ($N:literal, $TwoN:literal) => { |
380 | | /// Promote intermediate values to `i32` and then perform accumulation. |
381 | | impl<A> SIMDDotProduct<Emulated<i16, $TwoN, A>> for Emulated<i32, $N, A> |
382 | | where |
383 | | A: arch::Sealed, |
384 | | { |
385 | 0 | fn dot_simd( |
386 | 0 | self, |
387 | 0 | left: Emulated<i16, $TwoN, A>, |
388 | 0 | right: Emulated<i16, $TwoN, A>, |
389 | 0 | ) -> Self { |
390 | 0 | self + Self::from_arch_fn(self.1, |i| { |
391 | 0 | let l0: i32 = left.0[2 * i].into(); |
392 | 0 | let l1: i32 = left.0[2 * i + 1].into(); |
393 | | |
394 | 0 | let r0: i32 = right.0[2 * i].into(); |
395 | 0 | let r1: i32 = right.0[2 * i + 1].into(); |
396 | 0 | l0.expected_fma_(r0, l1.expected_mul_(r1)) |
397 | 0 | }) Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<i16, 8, _>>>::dot_simd::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 8, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<i16, 16, _>>>::dot_simd::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 16, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<i16, 32, _>>>::dot_simd::{closure#0} |
398 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<i16, 8, _>>>::dot_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 8, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<i16, 16, _>>>::dot_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 16, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<i16, 32, _>>>::dot_simd |
399 | | } |
400 | | }; |
401 | | } |
402 | | |
403 | | //i8/u8 to i32 |
404 | | macro_rules! impl_simd_dot_product_iu8_to_i32 { |
405 | | ($N:literal, $TwoN:literal) => { |
406 | | /// Promote intermediate values to `i32` and then perform accumulation. |
407 | | impl<A> SIMDDotProduct<Emulated<u8, $TwoN, A>, Emulated<i8, $TwoN, A>> |
408 | | for Emulated<i32, $N, A> |
409 | | where |
410 | | A: arch::Sealed, |
411 | | { |
412 | 0 | fn dot_simd(self, left: Emulated<u8, $TwoN, A>, right: Emulated<i8, $TwoN, A>) -> Self { |
413 | 0 | self + Self::from_arch_fn(self.1, |i| { |
414 | 0 | let l0: i32 = left.0[4 * i].into(); |
415 | 0 | let l1: i32 = left.0[4 * i + 1].into(); |
416 | 0 | let l2: i32 = left.0[4 * i + 2].into(); |
417 | 0 | let l3: i32 = left.0[4 * i + 3].into(); |
418 | | |
419 | 0 | let r0: i32 = right.0[4 * i].into(); |
420 | 0 | let r1: i32 = right.0[4 * i + 1].into(); |
421 | 0 | let r2: i32 = right.0[4 * i + 2].into(); |
422 | 0 | let r3: i32 = right.0[4 * i + 3].into(); |
423 | | |
424 | 0 | let a = l0.expected_fma_(r0, l1.expected_mul_(r1)); |
425 | 0 | let b = l2.expected_fma_(r2, l3.expected_mul_(r3)); |
426 | 0 | a + b |
427 | 0 | }) Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<u8, 16, _>, diskann_wide::emulated::Emulated<i8, 16, _>>>::dot_simd::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 8, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<u8, 32, _>, diskann_wide::emulated::Emulated<i8, 32, _>>>::dot_simd::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 16, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<u8, 64, _>, diskann_wide::emulated::Emulated<i8, 64, _>>>::dot_simd::{closure#0} |
428 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<u8, 16, _>, diskann_wide::emulated::Emulated<i8, 16, _>>>::dot_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 8, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<u8, 32, _>, diskann_wide::emulated::Emulated<i8, 32, _>>>::dot_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 16, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<u8, 64, _>, diskann_wide::emulated::Emulated<i8, 64, _>>>::dot_simd |
429 | | } |
430 | | |
431 | | impl<A> SIMDDotProduct<Emulated<i8, $TwoN, A>, Emulated<u8, $TwoN, A>> |
432 | | for Emulated<i32, $N, A> |
433 | | where |
434 | | A: arch::Sealed, |
435 | | { |
436 | 0 | fn dot_simd(self, left: Emulated<i8, $TwoN, A>, right: Emulated<u8, $TwoN, A>) -> Self { |
437 | 0 | self.dot_simd(right, left) |
438 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<i8, 16, _>, diskann_wide::emulated::Emulated<u8, 16, _>>>::dot_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 8, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<i8, 32, _>, diskann_wide::emulated::Emulated<u8, 32, _>>>::dot_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 16, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<i8, 64, _>, diskann_wide::emulated::Emulated<u8, 64, _>>>::dot_simd |
439 | | } |
440 | | |
441 | | impl<A> SIMDDotProduct<Emulated<u8, $TwoN, A>, Emulated<u8, $TwoN, A>> |
442 | | for Emulated<u32, $N, A> |
443 | | where |
444 | | A: arch::Sealed, |
445 | | { |
446 | 0 | fn dot_simd(self, left: Emulated<u8, $TwoN, A>, right: Emulated<u8, $TwoN, A>) -> Self { |
447 | 0 | self + Self::from_arch_fn(self.1, |i| { |
448 | 0 | let l0: u32 = left.0[4 * i].into(); |
449 | 0 | let l1: u32 = left.0[4 * i + 1].into(); |
450 | 0 | let l2: u32 = left.0[4 * i + 2].into(); |
451 | 0 | let l3: u32 = left.0[4 * i + 3].into(); |
452 | | |
453 | 0 | let r0: u32 = right.0[4 * i].into(); |
454 | 0 | let r1: u32 = right.0[4 * i + 1].into(); |
455 | 0 | let r2: u32 = right.0[4 * i + 2].into(); |
456 | 0 | let r3: u32 = right.0[4 * i + 3].into(); |
457 | | |
458 | 0 | let a = l0.expected_fma_(r0, l1.expected_mul_(r1)); |
459 | 0 | let b = l2.expected_fma_(r2, l3.expected_mul_(r3)); |
460 | 0 | a + b |
461 | 0 | }) Unexecuted instantiation: <diskann_wide::emulated::Emulated<u32, 4, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<u8, 16, _>>>::dot_simd::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<u32, 8, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<u8, 32, _>>>::dot_simd::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<u32, 16, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<u8, 64, _>>>::dot_simd::{closure#0} |
462 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<u32, 4, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<u8, 16, _>>>::dot_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<u32, 8, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<u8, 32, _>>>::dot_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<u32, 16, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<u8, 64, _>>>::dot_simd |
463 | | } |
464 | | |
465 | | impl<A> SIMDDotProduct<Emulated<i8, $TwoN, A>, Emulated<i8, $TwoN, A>> |
466 | | for Emulated<i32, $N, A> |
467 | | where |
468 | | A: arch::Sealed, |
469 | | { |
470 | 0 | fn dot_simd(self, left: Emulated<i8, $TwoN, A>, right: Emulated<i8, $TwoN, A>) -> Self { |
471 | 0 | self + Self::from_arch_fn(self.1, |i| { |
472 | 0 | let l0: i32 = left.0[4 * i].into(); |
473 | 0 | let l1: i32 = left.0[4 * i + 1].into(); |
474 | 0 | let l2: i32 = left.0[4 * i + 2].into(); |
475 | 0 | let l3: i32 = left.0[4 * i + 3].into(); |
476 | | |
477 | 0 | let r0: i32 = right.0[4 * i].into(); |
478 | 0 | let r1: i32 = right.0[4 * i + 1].into(); |
479 | 0 | let r2: i32 = right.0[4 * i + 2].into(); |
480 | 0 | let r3: i32 = right.0[4 * i + 3].into(); |
481 | | |
482 | 0 | let a = l0.expected_fma_(r0, l1.expected_mul_(r1)); |
483 | 0 | let b = l2.expected_fma_(r2, l3.expected_mul_(r3)); |
484 | 0 | a + b |
485 | 0 | }) Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<i8, 16, _>>>::dot_simd::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 8, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<i8, 32, _>>>::dot_simd::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 16, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<i8, 64, _>>>::dot_simd::{closure#0} |
486 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<i8, 16, _>>>::dot_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 8, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<i8, 32, _>>>::dot_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 16, _> as diskann_wide::traits::SIMDDotProduct<diskann_wide::emulated::Emulated<i8, 64, _>>>::dot_simd |
487 | | } |
488 | | }; |
489 | | } |
490 | | |
491 | | impl_simd_dot_product_i16_to_i32!(4, 8); |
492 | | impl_simd_dot_product_i16_to_i32!(8, 16); |
493 | | impl_simd_dot_product_i16_to_i32!(16, 32); |
494 | | |
495 | | impl_simd_dot_product_iu8_to_i32!(4, 16); |
496 | | impl_simd_dot_product_iu8_to_i32!(8, 32); |
497 | | impl_simd_dot_product_iu8_to_i32!(16, 64); |
498 | | |
499 | | //////////// |
500 | | // Select // |
501 | | //////////// |
502 | | |
503 | | impl<T, const N: usize, A> SIMDSelect<Emulated<T, N, A>> for BitMask<N, A> |
504 | | where |
505 | | T: Copy, |
506 | | A: arch::Sealed, |
507 | | Const<N>: SupportedLaneCount, |
508 | | BitMask<N, A>: SIMDMask<Arch = A>, |
509 | | Emulated<T, N, A>: SIMDVector<Mask = BitMask<N, A>>, |
510 | | { |
511 | | #[inline(always)] |
512 | 0 | fn select(self, x: Emulated<T, N, A>, y: Emulated<T, N, A>) -> Emulated<T, N, A> { |
513 | 0 | Emulated::from_arch_fn(self.arch(), |i| { |
514 | 0 | if self.get_unchecked(i) { |
515 | 0 | x.0[i] |
516 | | } else { |
517 | 0 | y.0[i] |
518 | | } |
519 | 0 | }) |
520 | 0 | } |
521 | | } |
522 | | |
523 | | ///////////// |
524 | | // SumTree // |
525 | | ///////////// |
526 | | |
527 | | macro_rules! impl_sumtree { |
528 | | ($T:ty, $N:literal) => { |
529 | | impl<A> SIMDSumTree for Emulated<$T, $N, A> |
530 | | where |
531 | | A: arch::Sealed, |
532 | | { |
533 | | #[inline(always)] |
534 | 0 | fn sum_tree(self) -> $T { |
535 | 0 | self.0.tree_reduce(|x, y| x.expected_add_(y)) Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4> as diskann_wide::traits::SIMDSumTree>::sum_tree::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as diskann_wide::traits::SIMDSumTree>::sum_tree::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4> as diskann_wide::traits::SIMDSumTree>::sum_tree::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 2, _> as diskann_wide::traits::SIMDSumTree>::sum_tree::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4, _> as diskann_wide::traits::SIMDSumTree>::sum_tree::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8, _> as diskann_wide::traits::SIMDSumTree>::sum_tree::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 16, _> as diskann_wide::traits::SIMDSumTree>::sum_tree::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4, _> as diskann_wide::traits::SIMDSumTree>::sum_tree::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 8, _> as diskann_wide::traits::SIMDSumTree>::sum_tree::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 16, _> as diskann_wide::traits::SIMDSumTree>::sum_tree::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<u32, 4, _> as diskann_wide::traits::SIMDSumTree>::sum_tree::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<u32, 8, _> as diskann_wide::traits::SIMDSumTree>::sum_tree::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<u32, 16, _> as diskann_wide::traits::SIMDSumTree>::sum_tree::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 1, _> as diskann_wide::traits::SIMDSumTree>::sum_tree::{closure#0} |
536 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4> as diskann_wide::traits::SIMDSumTree>::sum_tree Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as diskann_wide::traits::SIMDSumTree>::sum_tree Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4> as diskann_wide::traits::SIMDSumTree>::sum_tree Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as diskann_wide::traits::SIMDSumTree>::sum_tree Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4> as diskann_wide::traits::SIMDSumTree>::sum_tree Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 1> as diskann_wide::traits::SIMDSumTree>::sum_tree Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 2, _> as diskann_wide::traits::SIMDSumTree>::sum_tree Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4, _> as diskann_wide::traits::SIMDSumTree>::sum_tree Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8, _> as diskann_wide::traits::SIMDSumTree>::sum_tree Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 16, _> as diskann_wide::traits::SIMDSumTree>::sum_tree Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4, _> as diskann_wide::traits::SIMDSumTree>::sum_tree Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 8, _> as diskann_wide::traits::SIMDSumTree>::sum_tree Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 16, _> as diskann_wide::traits::SIMDSumTree>::sum_tree Unexecuted instantiation: <diskann_wide::emulated::Emulated<u32, 4, _> as diskann_wide::traits::SIMDSumTree>::sum_tree Unexecuted instantiation: <diskann_wide::emulated::Emulated<u32, 8, _> as diskann_wide::traits::SIMDSumTree>::sum_tree Unexecuted instantiation: <diskann_wide::emulated::Emulated<u32, 16, _> as diskann_wide::traits::SIMDSumTree>::sum_tree Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 1, _> as diskann_wide::traits::SIMDSumTree>::sum_tree |
537 | | } |
538 | | }; |
539 | | ($T:ty, $($N:literal),* $(,)?) => { |
540 | | $(impl_sumtree!($T, $N);)* |
541 | | }; |
542 | | } |
543 | | |
544 | | impl_sumtree!(f32, 1, 2, 4, 8, 16); |
545 | | impl_sumtree!(i32, 4, 8, 16); |
546 | | impl_sumtree!(u32, 4, 8, 16); |
547 | | |
548 | | //////////////// |
549 | | // Conversion // |
550 | | //////////////// |
551 | | |
552 | | macro_rules! impl_from { |
553 | | (f16 => f32, $N:literal) => { |
554 | | impl<A> From<Emulated<f16, $N, A>> for Emulated<f32, $N, A> { |
555 | | #[inline(always)] |
556 | 0 | fn from(value: Emulated<f16, $N, A>) -> Self { |
557 | 0 | Emulated(value.0.map(|v| v.reference_cast()), value.1) Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 1> as core::convert::From<diskann_wide::emulated::Emulated<half::binary16::f16, 1>>>::from::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as core::convert::From<diskann_wide::emulated::Emulated<half::binary16::f16, 8>>>::from::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 1, _> as core::convert::From<diskann_wide::emulated::Emulated<half::binary16::f16, 1, _>>>::from::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 2, _> as core::convert::From<diskann_wide::emulated::Emulated<half::binary16::f16, 2, _>>>::from::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4, _> as core::convert::From<diskann_wide::emulated::Emulated<half::binary16::f16, 4, _>>>::from::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8, _> as core::convert::From<diskann_wide::emulated::Emulated<half::binary16::f16, 8, _>>>::from::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 16, _> as core::convert::From<diskann_wide::emulated::Emulated<half::binary16::f16, 16, _>>>::from::{closure#0} |
558 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 1> as core::convert::From<diskann_wide::emulated::Emulated<half::binary16::f16, 1>>>::from Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8> as core::convert::From<diskann_wide::emulated::Emulated<half::binary16::f16, 8>>>::from Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 1, _> as core::convert::From<diskann_wide::emulated::Emulated<half::binary16::f16, 1, _>>>::from Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 2, _> as core::convert::From<diskann_wide::emulated::Emulated<half::binary16::f16, 2, _>>>::from Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 4, _> as core::convert::From<diskann_wide::emulated::Emulated<half::binary16::f16, 4, _>>>::from Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8, _> as core::convert::From<diskann_wide::emulated::Emulated<half::binary16::f16, 8, _>>>::from Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 16, _> as core::convert::From<diskann_wide::emulated::Emulated<half::binary16::f16, 16, _>>>::from |
559 | | } |
560 | | }; |
561 | | ($from:ty => $to:ty, $N:literal) => { |
562 | | impl<A> From<Emulated<$from, $N, A>> for Emulated<$to, $N, A> { |
563 | | #[inline(always)] |
564 | 0 | fn from(value: Emulated<$from, $N, A>) -> Self { |
565 | 0 | Emulated(value.0.map(|v| v.into()), value.1) Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 1> as core::convert::From<diskann_wide::emulated::Emulated<i8, 1>>>::from::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4> as core::convert::From<diskann_wide::emulated::Emulated<i8, 4>>>::from::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 1> as core::convert::From<diskann_wide::emulated::Emulated<u8, 1>>>::from::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4> as core::convert::From<diskann_wide::emulated::Emulated<u8, 4>>>::from::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 16, _> as core::convert::From<diskann_wide::emulated::Emulated<u8, 16, _>>>::from::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 32, _> as core::convert::From<diskann_wide::emulated::Emulated<u8, 32, _>>>::from::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 16, _> as core::convert::From<diskann_wide::emulated::Emulated<i8, 16, _>>>::from::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 32, _> as core::convert::From<diskann_wide::emulated::Emulated<i8, 32, _>>>::from::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 1, _> as core::convert::From<diskann_wide::emulated::Emulated<i8, 1, _>>>::from::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4, _> as core::convert::From<diskann_wide::emulated::Emulated<i8, 4, _>>>::from::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 1, _> as core::convert::From<diskann_wide::emulated::Emulated<u8, 1, _>>>::from::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4, _> as core::convert::From<diskann_wide::emulated::Emulated<u8, 4, _>>>::from::{closure#0} |
566 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 1> as core::convert::From<diskann_wide::emulated::Emulated<i8, 1>>>::from Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4> as core::convert::From<diskann_wide::emulated::Emulated<i8, 4>>>::from Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 1> as core::convert::From<diskann_wide::emulated::Emulated<u8, 1>>>::from Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4> as core::convert::From<diskann_wide::emulated::Emulated<u8, 4>>>::from Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 16, _> as core::convert::From<diskann_wide::emulated::Emulated<u8, 16, _>>>::from Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 32, _> as core::convert::From<diskann_wide::emulated::Emulated<u8, 32, _>>>::from Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 16, _> as core::convert::From<diskann_wide::emulated::Emulated<i8, 16, _>>>::from Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 32, _> as core::convert::From<diskann_wide::emulated::Emulated<i8, 32, _>>>::from Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 1, _> as core::convert::From<diskann_wide::emulated::Emulated<i8, 1, _>>>::from Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4, _> as core::convert::From<diskann_wide::emulated::Emulated<i8, 4, _>>>::from Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 1, _> as core::convert::From<diskann_wide::emulated::Emulated<u8, 1, _>>>::from Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 4, _> as core::convert::From<diskann_wide::emulated::Emulated<u8, 4, _>>>::from |
567 | | } |
568 | | }; |
569 | | } |
570 | | |
571 | | impl_from!(f16 => f32, 1); |
572 | | impl_from!(f16 => f32, 2); |
573 | | impl_from!(f16 => f32, 4); |
574 | | impl_from!(f16 => f32, 8); |
575 | | impl_from!(f16 => f32, 16); |
576 | | |
577 | | impl_from!(u8 => i16, 16); |
578 | | impl_from!(u8 => i16, 32); |
579 | | |
580 | | impl_from!(i8 => i16, 16); |
581 | | impl_from!(i8 => i16, 32); |
582 | | |
583 | | impl_from!(i8 => i32, 1); |
584 | | impl_from!(i8 => i32, 4); |
585 | | |
586 | | impl_from!(u8 => i32, 1); |
587 | | impl_from!(u8 => i32, 4); |
588 | | |
589 | | ///////////////// |
590 | | // Reinterpret // |
591 | | ///////////////// |
592 | | |
593 | | macro_rules! impl_little_endian_transmute_cast { |
594 | | (<$from:ty, $Nfrom:literal> => <$to:ty, $Nto:literal>) => { |
595 | | #[cfg(target_endian = "little")] |
596 | | impl<A> SIMDReinterpret<Emulated<$to, $Nto, A>> for Emulated<$from, $Nfrom, A> |
597 | | where |
598 | | A: arch::Sealed, |
599 | | { |
600 | 0 | fn reinterpret_simd(self) -> Emulated<$to, $Nto, A> { |
601 | 0 | let array = self.0; |
602 | | // SAFETY: This is only ever instantiated with arrays of primitive |
603 | | // types that hold no resources, no padding, and are valid for all |
604 | | // possible bit-patterns. |
605 | 0 | let casted = unsafe { std::mem::transmute::<[$from; $Nfrom], [$to; $Nto]>(array) }; |
606 | 0 | Emulated(casted, self.1) |
607 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<u8, 16, _> as diskann_wide::traits::SIMDReinterpret<diskann_wide::emulated::Emulated<i16, 8, _>>>::reinterpret_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<u32, 16, _> as diskann_wide::traits::SIMDReinterpret<diskann_wide::emulated::Emulated<u8, 64, _>>>::reinterpret_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<u32, 16, _> as diskann_wide::traits::SIMDReinterpret<diskann_wide::emulated::Emulated<i8, 64, _>>>::reinterpret_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<u8, 64, _> as diskann_wide::traits::SIMDReinterpret<diskann_wide::emulated::Emulated<u32, 16, _>>>::reinterpret_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<i8, 64, _> as diskann_wide::traits::SIMDReinterpret<diskann_wide::emulated::Emulated<u32, 16, _>>>::reinterpret_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<u32, 8, _> as diskann_wide::traits::SIMDReinterpret<diskann_wide::emulated::Emulated<i16, 16, _>>>::reinterpret_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<u32, 16, _> as diskann_wide::traits::SIMDReinterpret<diskann_wide::emulated::Emulated<i16, 32, _>>>::reinterpret_simd Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 8, _> as diskann_wide::traits::SIMDReinterpret<diskann_wide::emulated::Emulated<u8, 16, _>>>::reinterpret_simd |
608 | | } |
609 | | }; |
610 | | } |
611 | | |
612 | | impl_little_endian_transmute_cast!(<u32, 8> => <i16, 16>); |
613 | | impl_little_endian_transmute_cast!(<u32, 16> => <i16, 32>); |
614 | | |
615 | | impl_little_endian_transmute_cast!(<i16, 8> => <u8, 16>); |
616 | | impl_little_endian_transmute_cast!(<u8, 16> => <i16, 8>); |
617 | | |
618 | | impl_little_endian_transmute_cast!(<u32, 16> => <u8, 64>); |
619 | | impl_little_endian_transmute_cast!(<u32, 16> => <i8, 64>); |
620 | | |
621 | | impl_little_endian_transmute_cast!(<u8, 64> => <u32, 16>); |
622 | | impl_little_endian_transmute_cast!(<i8, 64> => <u32, 16>); |
623 | | |
624 | | ///////////// |
625 | | // Casting // |
626 | | ///////////// |
627 | | |
628 | | macro_rules! impl_cast { |
629 | | ($from:ty => $to:ty, $N:literal) => { |
630 | | impl<A> SIMDCast<$to> for Emulated<$from, $N, A> |
631 | | where |
632 | | A: arch::Sealed, |
633 | | { |
634 | | type Cast = Emulated<$to, $N, A>; |
635 | | #[inline(always)] |
636 | 0 | fn simd_cast(self) -> Self::Cast { |
637 | 0 | Emulated::from_arch_fn(self.arch(), |i| self.0[i].reference_cast()) Unexecuted instantiation: <diskann_wide::emulated::Emulated<half::binary16::f16, 8, _> as diskann_wide::traits::SIMDCast<f32>>::simd_cast::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<half::binary16::f16, 16, _> as diskann_wide::traits::SIMDCast<f32>>::simd_cast::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8, _> as diskann_wide::traits::SIMDCast<half::binary16::f16>>::simd_cast::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 16, _> as diskann_wide::traits::SIMDCast<half::binary16::f16>>::simd_cast::{closure#0}Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 8, _> as diskann_wide::traits::SIMDCast<f32>>::simd_cast::{closure#0} |
638 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<half::binary16::f16, 8, _> as diskann_wide::traits::SIMDCast<f32>>::simd_cast Unexecuted instantiation: <diskann_wide::emulated::Emulated<half::binary16::f16, 16, _> as diskann_wide::traits::SIMDCast<f32>>::simd_cast Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8, _> as diskann_wide::traits::SIMDCast<half::binary16::f16>>::simd_cast Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 16, _> as diskann_wide::traits::SIMDCast<half::binary16::f16>>::simd_cast Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 8, _> as diskann_wide::traits::SIMDCast<f32>>::simd_cast |
639 | | } |
640 | | }; |
641 | | } |
642 | | |
643 | | impl_cast!(f16 => f32, 8); |
644 | | impl_cast!(f16 => f32, 16); |
645 | | |
646 | | impl_cast!(f32 => f16, 8); |
647 | | impl_cast!(f32 => f16, 16); |
648 | | |
649 | | impl_cast!(i32 => f32, 8); |
650 | | |
651 | | /////////////// |
652 | | // SplitJoin // |
653 | | /////////////// |
654 | | |
655 | | macro_rules! impl_splitjoin { |
656 | | ($type:ty, $N:literal => $N2:literal) => { |
657 | | impl<A> SplitJoin for Emulated<$type, $N, A> |
658 | | where |
659 | | A: Copy, |
660 | | { |
661 | | type Halved = Emulated<$type, $N2, A>; |
662 | | |
663 | | #[inline(always)] |
664 | 0 | fn split(self) -> $crate::LoHi<Self::Halved> { |
665 | 0 | let $crate::LoHi { lo, hi } = self.0.split(); |
666 | 0 | let arch = self.1; |
667 | 0 | $crate::LoHi::new(Emulated(lo, arch), Emulated(hi, arch)) |
668 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<i8, 32, _> as diskann_wide::splitjoin::SplitJoin>::split Unexecuted instantiation: <diskann_wide::emulated::Emulated<i8, 64, _> as diskann_wide::splitjoin::SplitJoin>::split Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 16, _> as diskann_wide::splitjoin::SplitJoin>::split Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 32, _> as diskann_wide::splitjoin::SplitJoin>::split Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 8, _> as diskann_wide::splitjoin::SplitJoin>::split Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 16, _> as diskann_wide::splitjoin::SplitJoin>::split Unexecuted instantiation: <diskann_wide::emulated::Emulated<u8, 32, _> as diskann_wide::splitjoin::SplitJoin>::split Unexecuted instantiation: <diskann_wide::emulated::Emulated<u8, 64, _> as diskann_wide::splitjoin::SplitJoin>::split Unexecuted instantiation: <diskann_wide::emulated::Emulated<u32, 8, _> as diskann_wide::splitjoin::SplitJoin>::split Unexecuted instantiation: <diskann_wide::emulated::Emulated<u32, 16, _> as diskann_wide::splitjoin::SplitJoin>::split Unexecuted instantiation: <diskann_wide::emulated::Emulated<u64, 4, _> as diskann_wide::splitjoin::SplitJoin>::split Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 16, _> as diskann_wide::splitjoin::SplitJoin>::split Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8, _> as diskann_wide::splitjoin::SplitJoin>::split Unexecuted instantiation: <diskann_wide::emulated::Emulated<half::binary16::f16, 16, _> as diskann_wide::splitjoin::SplitJoin>::split |
669 | | |
670 | | #[inline(always)] |
671 | 0 | fn join(lohi: $crate::LoHi<Self::Halved>) -> Self { |
672 | 0 | Self($crate::LoHi::new(lohi.lo.0, lohi.hi.0).join(), lohi.lo.1) |
673 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<i8, 32, _> as diskann_wide::splitjoin::SplitJoin>::join Unexecuted instantiation: <diskann_wide::emulated::Emulated<i8, 64, _> as diskann_wide::splitjoin::SplitJoin>::join Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 16, _> as diskann_wide::splitjoin::SplitJoin>::join Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 32, _> as diskann_wide::splitjoin::SplitJoin>::join Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 8, _> as diskann_wide::splitjoin::SplitJoin>::join Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 16, _> as diskann_wide::splitjoin::SplitJoin>::join Unexecuted instantiation: <diskann_wide::emulated::Emulated<u8, 32, _> as diskann_wide::splitjoin::SplitJoin>::join Unexecuted instantiation: <diskann_wide::emulated::Emulated<u8, 64, _> as diskann_wide::splitjoin::SplitJoin>::join Unexecuted instantiation: <diskann_wide::emulated::Emulated<u32, 8, _> as diskann_wide::splitjoin::SplitJoin>::join Unexecuted instantiation: <diskann_wide::emulated::Emulated<u32, 16, _> as diskann_wide::splitjoin::SplitJoin>::join Unexecuted instantiation: <diskann_wide::emulated::Emulated<u64, 4, _> as diskann_wide::splitjoin::SplitJoin>::join Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 16, _> as diskann_wide::splitjoin::SplitJoin>::join Unexecuted instantiation: <diskann_wide::emulated::Emulated<f32, 8, _> as diskann_wide::splitjoin::SplitJoin>::join Unexecuted instantiation: <diskann_wide::emulated::Emulated<half::binary16::f16, 16, _> as diskann_wide::splitjoin::SplitJoin>::join |
674 | | } |
675 | | }; |
676 | | } |
677 | | |
678 | | impl_splitjoin!(i8, 32 => 16); |
679 | | impl_splitjoin!(i8, 64 => 32); |
680 | | |
681 | | impl_splitjoin!(i16, 16 => 8); |
682 | | impl_splitjoin!(i16, 32 => 16); |
683 | | |
684 | | impl_splitjoin!(i32, 8 => 4); |
685 | | impl_splitjoin!(i32, 16 => 8); |
686 | | |
687 | | impl_splitjoin!(u8, 32 => 16); |
688 | | impl_splitjoin!(u8, 64 => 32); |
689 | | |
690 | | impl_splitjoin!(u32, 8 => 4); |
691 | | impl_splitjoin!(u32, 16 => 8); |
692 | | impl_splitjoin!(u64, 4 => 2); |
693 | | |
694 | | impl_splitjoin!(f32, 16 => 8); |
695 | | impl_splitjoin!(f32, 8 => 4); |
696 | | |
697 | | impl_splitjoin!(f16, 16 => 8); |
698 | | |
699 | | ////////////// |
700 | | // ZipUnzip // |
701 | | ////////////// |
702 | | |
703 | | macro_rules! array_zipunzip { |
704 | | ($N:literal) => { |
705 | | impl<T: Copy> crate::traits::ZipUnzip for [T; $N] { |
706 | | #[inline(always)] |
707 | 0 | fn zip(halves: $crate::LoHi<Self::Halved>) -> Self { |
708 | 0 | core::array::from_fn(|i| { |
709 | 0 | if i % 2 == 0 { |
710 | 0 | halves.lo[i / 2] |
711 | | } else { |
712 | 0 | halves.hi[i / 2] |
713 | | } |
714 | 0 | }) Unexecuted instantiation: <[_; 2] as diskann_wide::traits::ZipUnzip>::zip::{closure#0}Unexecuted instantiation: <[_; 4] as diskann_wide::traits::ZipUnzip>::zip::{closure#0}Unexecuted instantiation: <[_; 8] as diskann_wide::traits::ZipUnzip>::zip::{closure#0}Unexecuted instantiation: <[_; 16] as diskann_wide::traits::ZipUnzip>::zip::{closure#0}Unexecuted instantiation: <[_; 32] as diskann_wide::traits::ZipUnzip>::zip::{closure#0}Unexecuted instantiation: <[_; 64] as diskann_wide::traits::ZipUnzip>::zip::{closure#0} |
715 | 0 | } Unexecuted instantiation: <[_; 2] as diskann_wide::traits::ZipUnzip>::zip Unexecuted instantiation: <[_; 4] as diskann_wide::traits::ZipUnzip>::zip Unexecuted instantiation: <[_; 8] as diskann_wide::traits::ZipUnzip>::zip Unexecuted instantiation: <[_; 16] as diskann_wide::traits::ZipUnzip>::zip Unexecuted instantiation: <[_; 32] as diskann_wide::traits::ZipUnzip>::zip Unexecuted instantiation: <[_; 64] as diskann_wide::traits::ZipUnzip>::zip |
716 | | |
717 | | #[inline(always)] |
718 | 0 | fn unzip(self) -> $crate::LoHi<Self::Halved> { |
719 | | $crate::LoHi { |
720 | 0 | lo: core::array::from_fn(|i| self[2 * i]), Unexecuted instantiation: <[_; 2] as diskann_wide::traits::ZipUnzip>::unzip::{closure#0}Unexecuted instantiation: <[_; 4] as diskann_wide::traits::ZipUnzip>::unzip::{closure#0}Unexecuted instantiation: <[_; 8] as diskann_wide::traits::ZipUnzip>::unzip::{closure#0}Unexecuted instantiation: <[_; 16] as diskann_wide::traits::ZipUnzip>::unzip::{closure#0}Unexecuted instantiation: <[_; 32] as diskann_wide::traits::ZipUnzip>::unzip::{closure#0}Unexecuted instantiation: <[_; 64] as diskann_wide::traits::ZipUnzip>::unzip::{closure#0} |
721 | 0 | hi: core::array::from_fn(|i| self[2 * i + 1]), Unexecuted instantiation: <[_; 2] as diskann_wide::traits::ZipUnzip>::unzip::{closure#1}Unexecuted instantiation: <[_; 4] as diskann_wide::traits::ZipUnzip>::unzip::{closure#1}Unexecuted instantiation: <[_; 8] as diskann_wide::traits::ZipUnzip>::unzip::{closure#1}Unexecuted instantiation: <[_; 16] as diskann_wide::traits::ZipUnzip>::unzip::{closure#1}Unexecuted instantiation: <[_; 32] as diskann_wide::traits::ZipUnzip>::unzip::{closure#1}Unexecuted instantiation: <[_; 64] as diskann_wide::traits::ZipUnzip>::unzip::{closure#1} |
722 | | } |
723 | 0 | } Unexecuted instantiation: <[_; 2] as diskann_wide::traits::ZipUnzip>::unzip Unexecuted instantiation: <[_; 4] as diskann_wide::traits::ZipUnzip>::unzip Unexecuted instantiation: <[_; 8] as diskann_wide::traits::ZipUnzip>::unzip Unexecuted instantiation: <[_; 16] as diskann_wide::traits::ZipUnzip>::unzip Unexecuted instantiation: <[_; 32] as diskann_wide::traits::ZipUnzip>::unzip Unexecuted instantiation: <[_; 64] as diskann_wide::traits::ZipUnzip>::unzip |
724 | | } |
725 | | }; |
726 | | } |
727 | | |
728 | | array_zipunzip!(2); |
729 | | array_zipunzip!(4); |
730 | | array_zipunzip!(8); |
731 | | array_zipunzip!(16); |
732 | | array_zipunzip!(32); |
733 | | array_zipunzip!(64); |
734 | | |
735 | | macro_rules! impl_zipunzip { |
736 | | ($type:ty, $N:literal => $N2:literal) => { |
737 | | impl<A> ZipUnzip for Emulated<$type, $N, A> |
738 | | where |
739 | | A: Copy, |
740 | | { |
741 | | #[inline(always)] |
742 | 0 | fn zip(halves: $crate::LoHi<Self::Halved>) -> Self { |
743 | 0 | Self( |
744 | 0 | $crate::LoHi::new(halves.lo.0, halves.hi.0).zip(), |
745 | 0 | halves.lo.1, |
746 | 0 | ) |
747 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<i8, 32, _> as diskann_wide::traits::ZipUnzip>::zip Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 16, _> as diskann_wide::traits::ZipUnzip>::zip Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 8, _> as diskann_wide::traits::ZipUnzip>::zip Unexecuted instantiation: <diskann_wide::emulated::Emulated<u8, 32, _> as diskann_wide::traits::ZipUnzip>::zip Unexecuted instantiation: <diskann_wide::emulated::Emulated<u32, 8, _> as diskann_wide::traits::ZipUnzip>::zip Unexecuted instantiation: <diskann_wide::emulated::Emulated<half::binary16::f16, 16, _> as diskann_wide::traits::ZipUnzip>::zip |
748 | | |
749 | | #[inline(always)] |
750 | 0 | fn unzip(self) -> $crate::LoHi<Self::Halved> { |
751 | 0 | let $crate::LoHi { lo, hi } = self.0.unzip(); |
752 | 0 | let arch = self.1; |
753 | 0 | $crate::LoHi::new(Emulated(lo, arch), Emulated(hi, arch)) |
754 | 0 | } Unexecuted instantiation: <diskann_wide::emulated::Emulated<i8, 32, _> as diskann_wide::traits::ZipUnzip>::unzip Unexecuted instantiation: <diskann_wide::emulated::Emulated<i16, 16, _> as diskann_wide::traits::ZipUnzip>::unzip Unexecuted instantiation: <diskann_wide::emulated::Emulated<i32, 8, _> as diskann_wide::traits::ZipUnzip>::unzip Unexecuted instantiation: <diskann_wide::emulated::Emulated<u8, 32, _> as diskann_wide::traits::ZipUnzip>::unzip Unexecuted instantiation: <diskann_wide::emulated::Emulated<u32, 8, _> as diskann_wide::traits::ZipUnzip>::unzip Unexecuted instantiation: <diskann_wide::emulated::Emulated<half::binary16::f16, 16, _> as diskann_wide::traits::ZipUnzip>::unzip |
755 | | } |
756 | | }; |
757 | | } |
758 | | |
759 | | impl_zipunzip!(i8, 32 => 16); |
760 | | impl_zipunzip!(i16, 16 => 8); |
761 | | impl_zipunzip!(i32, 8 => 4); |
762 | | impl_zipunzip!(u8, 32 => 16); |
763 | | impl_zipunzip!(u32, 8 => 4); |
764 | | impl_zipunzip!(f16, 16 => 8); |
765 | | |
766 | | /////////// |
767 | | // Tests // |
768 | | /////////// |
769 | | |
770 | | #[cfg(test)] |
771 | | mod test_emulated { |
772 | | use half::f16; |
773 | | |
774 | | use super::*; |
775 | | use crate::{reference::ReferenceScalarOps, test_utils}; |
776 | | |
777 | | // Test loading logic - ensure that no out of bounds accesses are made. |
778 | | // In particular, this is meant to be run under `Miri` to ensure that our guarantees |
779 | | // regarding out-of-bounds accesses are honored. |
780 | | #[test] |
781 | | fn test_load() { |
782 | | // Floating Point |
783 | | #[cfg(not(miri))] // Miri does not have ph-to-ps conversion. |
784 | | test_utils::test_load_simd::<f16, 8, Emulated<f16, 8>>(Scalar); |
785 | | test_utils::test_load_simd::<f32, 4, Emulated<f32, 4>>(Scalar); |
786 | | test_utils::test_load_simd::<f32, 8, Emulated<f32, 8>>(Scalar); |
787 | | |
788 | | // Unsigned Integers |
789 | | test_utils::test_load_simd::<u8, 8, Emulated<u8, 8>>(Scalar); |
790 | | test_utils::test_load_simd::<u8, 16, Emulated<u8, 16>>(Scalar); |
791 | | |
792 | | test_utils::test_load_simd::<u16, 4, Emulated<u16, 4>>(Scalar); |
793 | | test_utils::test_load_simd::<u16, 8, Emulated<u16, 8>>(Scalar); |
794 | | test_utils::test_load_simd::<u16, 16, Emulated<u16, 16>>(Scalar); |
795 | | |
796 | | test_utils::test_load_simd::<u32, 2, Emulated<u32, 2>>(Scalar); |
797 | | test_utils::test_load_simd::<u32, 4, Emulated<u32, 4>>(Scalar); |
798 | | test_utils::test_load_simd::<u32, 8, Emulated<u32, 8>>(Scalar); |
799 | | |
800 | | // Signed Integers |
801 | | test_utils::test_load_simd::<i8, 8, Emulated<i8, 8>>(Scalar); |
802 | | test_utils::test_load_simd::<i8, 16, Emulated<i8, 16>>(Scalar); |
803 | | |
804 | | test_utils::test_load_simd::<i16, 4, Emulated<i16, 4>>(Scalar); |
805 | | test_utils::test_load_simd::<i16, 8, Emulated<i16, 8>>(Scalar); |
806 | | test_utils::test_load_simd::<i16, 16, Emulated<i16, 16>>(Scalar); |
807 | | |
808 | | test_utils::test_load_simd::<i32, 2, Emulated<i32, 2>>(Scalar); |
809 | | test_utils::test_load_simd::<i32, 4, Emulated<i32, 4>>(Scalar); |
810 | | test_utils::test_load_simd::<i32, 8, Emulated<i32, 8>>(Scalar); |
811 | | } |
812 | | |
813 | | #[test] |
814 | | fn test_store() { |
815 | | // Floating Point |
816 | | #[cfg(not(miri))] // Miri does not have ph-to-ps conversion. |
817 | | test_utils::test_store_simd::<f16, 8, Emulated<f16, 8>>(Scalar); |
818 | | test_utils::test_store_simd::<f32, 4, Emulated<f32, 4>>(Scalar); |
819 | | test_utils::test_store_simd::<f32, 8, Emulated<f32, 8>>(Scalar); |
820 | | |
821 | | // Unsigned Integers |
822 | | test_utils::test_store_simd::<u8, 8, Emulated<u8, 8>>(Scalar); |
823 | | test_utils::test_store_simd::<u8, 16, Emulated<u8, 16>>(Scalar); |
824 | | |
825 | | test_utils::test_store_simd::<u16, 4, Emulated<u16, 4>>(Scalar); |
826 | | test_utils::test_store_simd::<u16, 8, Emulated<u16, 8>>(Scalar); |
827 | | test_utils::test_store_simd::<u16, 16, Emulated<u16, 16>>(Scalar); |
828 | | |
829 | | test_utils::test_store_simd::<u32, 2, Emulated<u32, 2>>(Scalar); |
830 | | test_utils::test_store_simd::<u32, 4, Emulated<u32, 4>>(Scalar); |
831 | | test_utils::test_store_simd::<u32, 8, Emulated<u32, 8>>(Scalar); |
832 | | |
833 | | // Signed Integers |
834 | | test_utils::test_store_simd::<i8, 8, Emulated<i8, 8>>(Scalar); |
835 | | test_utils::test_store_simd::<i8, 16, Emulated<i8, 16>>(Scalar); |
836 | | |
837 | | test_utils::test_store_simd::<i16, 4, Emulated<i16, 4>>(Scalar); |
838 | | test_utils::test_store_simd::<i16, 8, Emulated<i16, 8>>(Scalar); |
839 | | test_utils::test_store_simd::<i16, 16, Emulated<i16, 16>>(Scalar); |
840 | | |
841 | | test_utils::test_store_simd::<i32, 2, Emulated<i32, 2>>(Scalar); |
842 | | test_utils::test_store_simd::<i32, 4, Emulated<i32, 4>>(Scalar); |
843 | | test_utils::test_store_simd::<i32, 8, Emulated<i32, 8>>(Scalar); |
844 | | } |
845 | | |
846 | | // Only test a subset of constructors as all `Emulated` have the same implementation. |
847 | | #[test] |
848 | | fn test_constructors() { |
849 | | test_utils::ops::test_splat::<u8, 64, Emulated<u8, 64>>(Scalar); |
850 | | let x = Emulated::<u32, 8>::default(Scalar); |
851 | | assert_eq!(x.to_underlying(), [0; 8]); |
852 | | |
853 | | let x = Emulated::<u32, 8>::from_underlying(Scalar, [1; 8]); |
854 | | assert_eq!(x.to_underlying(), [1; 8]); |
855 | | } |
856 | | |
857 | | // Wrap inside `Some` for compatibility with optional tests. |
858 | | const SC: Option<Scalar> = Some(Scalar); |
859 | | |
860 | | macro_rules! test_emulated { |
861 | | ($type:ty, $N:literal) => { |
862 | | test_utils::ops::test_add!(Emulated<$type, $N>, 0xba37c3f2cf666f87, SC); |
863 | | test_utils::ops::test_sub!(Emulated<$type, $N>, 0xeb755abd230e5d80, SC); |
864 | | test_utils::ops::test_mul!(Emulated<$type, $N>, 0x0a24ed76a54c3561, SC); |
865 | | test_utils::ops::test_fma!(Emulated<$type, $N>, 0xa906c44505abe9ca, SC); |
866 | | test_utils::ops::test_minmax!(Emulated<$type, $N>, 0x959522be5234d492, SC); |
867 | | |
868 | | test_utils::ops::test_cmp!(Emulated<$type, $N>, 0x9b58e6cbd8330c2d, SC); |
869 | | test_utils::ops::test_select!(Emulated<$type, $N>, 0x610aca3aa4d77c0a, SC); |
870 | | }; |
871 | | (unsigned, $type:ty, $N:literal) => { |
872 | | test_emulated!($type, $N); |
873 | | |
874 | | test_utils::ops::test_bitops!(Emulated<$type, $N>, 0x14fc7841e66bd162, SC); |
875 | | }; |
876 | | (signed, $type:ty, $N:literal) => { |
877 | | test_emulated!($type, $N); |
878 | | |
879 | | test_utils::ops::test_bitops!(Emulated<$type, $N>, 0x850435f89f86f3b0, SC); |
880 | | test_utils::ops::test_abs!(Emulated<$type, $N>, 0x1842a2b86dfd9ecb, SC); |
881 | | }; |
882 | | } |
883 | | |
884 | | // Emulated arithmetic. |
885 | | test_emulated!(f32, 1); |
886 | | test_emulated!(f32, 4); |
887 | | test_emulated!(f32, 8); |
888 | | test_emulated!(f32, 16); |
889 | | // test_emulated!(f64, 8); |
890 | | |
891 | | // unsigned integer |
892 | | test_emulated!(unsigned, u8, 16); |
893 | | |
894 | | test_emulated!(unsigned, u16, 16); |
895 | | test_emulated!(unsigned, u16, 32); |
896 | | |
897 | | test_emulated!(unsigned, u32, 1); |
898 | | test_emulated!(unsigned, u32, 4); |
899 | | test_emulated!(unsigned, u32, 8); |
900 | | test_emulated!(unsigned, u32, 16); |
901 | | |
902 | | test_emulated!(unsigned, u64, 2); |
903 | | test_emulated!(unsigned, u64, 4); |
904 | | test_emulated!(unsigned, u64, 8); |
905 | | test_emulated!(unsigned, u64, 16); |
906 | | |
907 | | // signed integer |
908 | | test_emulated!(signed, i8, 8); |
909 | | test_emulated!(signed, i8, 16); |
910 | | |
911 | | test_emulated!(signed, i16, 8); |
912 | | test_emulated!(signed, i16, 16); |
913 | | |
914 | | test_emulated!(signed, i32, 1); |
915 | | test_emulated!(signed, i32, 4); |
916 | | test_emulated!(signed, i32, 8); |
917 | | test_emulated!(signed, i32, 16); |
918 | | |
919 | | test_emulated!(signed, i64, 2); |
920 | | test_emulated!(signed, i64, 4); |
921 | | test_emulated!(signed, i64, 8); |
922 | | test_emulated!(signed, i64, 16); |
923 | | |
924 | | // Dot Products |
925 | | test_utils::dot_product::test_dot_product!( |
926 | | (Emulated<i16, 16>, Emulated<i16, 16>) => Emulated<i32, 8>, 0x3001f05604e96289, SC |
927 | | ); |
928 | | test_utils::dot_product::test_dot_product!( |
929 | | (Emulated<i16, 32>, Emulated<i16, 32>) => Emulated<i32, 16>, 0x137ce7a540d9b1a2, SC |
930 | | ); |
931 | | |
932 | | test_utils::dot_product::test_dot_product!( |
933 | | (Emulated<u8, 32>, Emulated<i8, 32>) => Emulated<i32, 8>, 0x3001f05604e96289, SC |
934 | | ); |
935 | | test_utils::dot_product::test_dot_product!( |
936 | | (Emulated<i8, 32>, Emulated<u8, 32>) => Emulated<i32, 8>, 0x3001f05604e96289, SC |
937 | | ); |
938 | | test_utils::dot_product::test_dot_product!( |
939 | | (Emulated<i8, 32>, Emulated<i8, 32>) => Emulated<i32, 8>, 0x3001f05604e96289, SC |
940 | | ); |
941 | | |
942 | | test_utils::dot_product::test_dot_product!( |
943 | | (Emulated<u8, 64>, Emulated<i8, 64>) => Emulated<i32, 16>, 0x3001f05604e96289, SC |
944 | | ); |
945 | | test_utils::dot_product::test_dot_product!( |
946 | | (Emulated<i8, 64>, Emulated<u8, 64>) => Emulated<i32, 16>, 0x3001f05604e96289, SC |
947 | | ); |
948 | | test_utils::dot_product::test_dot_product!( |
949 | | (Emulated<i8, 64>, Emulated<i8, 64>) => Emulated<i32, 16>, 0x3001f05604e96289, SC |
950 | | ); |
951 | | |
952 | | test_utils::dot_product::test_dot_product!( |
953 | | (Emulated<u8, 32>, Emulated<u8, 32>) => Emulated<u32, 8>, 0x3001f05604e96289, SC |
954 | | ); |
955 | | test_utils::dot_product::test_dot_product!( |
956 | | (Emulated<u8, 64>, Emulated<u8, 64>) => Emulated<u32, 16>, 0x3001f05604e96289, SC |
957 | | ); |
958 | | |
959 | | // reductions |
960 | | test_utils::ops::test_sumtree!(Emulated<f32, 1>, 0x410bad8207a8ccfc, SC); |
961 | | test_utils::ops::test_sumtree!(Emulated<f32, 2>, 0xf2fc4e4bbd193493, SC); |
962 | | test_utils::ops::test_sumtree!(Emulated<f32, 4>, 0x8034d5a0cd2be14d, SC); |
963 | | test_utils::ops::test_sumtree!(Emulated<f32, 8>, 0x0f075940b7e3732c, SC); |
964 | | test_utils::ops::test_sumtree!(Emulated<f32, 16>, 0x5b3cb860e3f02d3c, SC); |
965 | | |
966 | | test_utils::ops::test_sumtree!(Emulated<i32, 4>, 0xf8c38f70a807e9d2, SC); |
967 | | test_utils::ops::test_sumtree!(Emulated<i32, 8>, 0xf8aa4a7e7a273e80, SC); |
968 | | test_utils::ops::test_sumtree!(Emulated<i32, 16>, 0x8d1a467fe835a9c5, SC); |
969 | | |
970 | | test_utils::ops::test_sumtree!(Emulated<u32, 4>, 0x5e4cffc86a21e90d, SC); |
971 | | test_utils::ops::test_sumtree!(Emulated<u32, 8>, 0xf43f19adb43bc611, SC); |
972 | | test_utils::ops::test_sumtree!(Emulated<u32, 16>, 0xa43dfe10aa9de860, SC); |
973 | | |
974 | | ///////////////// |
975 | | // conversions // |
976 | | ///////////////// |
977 | | |
978 | | test_utils::ops::test_lossless_convert!( |
979 | | Emulated<i8, 16> => Emulated<i16, 16>, 0x1b4f08a8b741d565, SC |
980 | | ); |
981 | | test_utils::ops::test_lossless_convert!( |
982 | | Emulated<i8, 32> => Emulated<i16, 32>, 0xdf6f41eb836d4f46, SC |
983 | | ); |
984 | | |
985 | | test_utils::ops::test_lossless_convert!( |
986 | | Emulated<i8, 1> => Emulated<i32, 1>, 0x318ceec0e9798353, SC |
987 | | ); |
988 | | test_utils::ops::test_lossless_convert!( |
989 | | Emulated<i8, 4> => Emulated<i32, 4>, 0x9f5e1a437f7e7f3f, SC |
990 | | ); |
991 | | |
992 | | test_utils::ops::test_lossless_convert!( |
993 | | Emulated<u8, 16> => Emulated<i16, 16>, 0x96611521fed02f98, SC |
994 | | ); |
995 | | test_utils::ops::test_lossless_convert!( |
996 | | Emulated<u8, 32> => Emulated<i16, 32>, 0x6749d3aa94effa04, SC |
997 | | ); |
998 | | |
999 | | test_utils::ops::test_lossless_convert!( |
1000 | | Emulated<u8, 1> => Emulated<i32, 1>, 0x669cbd5c7bf6184e, SC |
1001 | | ); |
1002 | | test_utils::ops::test_lossless_convert!( |
1003 | | Emulated<u8, 4> => Emulated<i32, 4>, 0x75929494c5d333d0, SC |
1004 | | ); |
1005 | | |
1006 | | /////////// |
1007 | | // Casts // |
1008 | | /////////// |
1009 | | |
1010 | | test_utils::ops::test_cast!(Emulated<f16, 8> => Emulated<f32, 8>, 0x1e9e37b58fb3f1a8, SC); |
1011 | | test_utils::ops::test_cast!(Emulated<f16, 16> => Emulated<f32, 16>, 0xd2b068a9bf3f9d24, SC); |
1012 | | |
1013 | | test_utils::ops::test_cast!(Emulated<f32, 8> => Emulated<f16, 8>, 0xe9d2dd426d89699d, SC); |
1014 | | test_utils::ops::test_cast!(Emulated<f32, 16> => Emulated<f16, 16>, 0x2b637e21afd9ef6c, SC); |
1015 | | |
1016 | | test_utils::ops::test_cast!(Emulated<i32, 8> => Emulated<f32, 8>, 0x2b08e8ec7e49323b, SC); |
1017 | | |
1018 | | ////////////// |
1019 | | // ZipUnzip // |
1020 | | ////////////// |
1021 | | |
1022 | | test_utils::ops::test_zipunzip!(Emulated<i8, 32> => Emulated<i8, 16>, 0xa7c3e1f920b45d68, SC); |
1023 | | test_utils::ops::test_zipunzip!(Emulated<i16, 16> => Emulated<i16, 8>, 0x6b8d2f0e41c7a593, SC); |
1024 | | test_utils::ops::test_zipunzip!(Emulated<i32, 8> => Emulated<i32, 4>, 0x5f1a8c63d702be94, SC); |
1025 | | test_utils::ops::test_zipunzip!(Emulated<u8, 32> => Emulated<u8, 16>, 0x92d5f4a83e1b07c6, SC); |
1026 | | test_utils::ops::test_zipunzip!(Emulated<u32, 8> => Emulated<u32, 4>, 0xb6f30d8a52e4c197, SC); |
1027 | | test_utils::ops::test_zipunzip!(Emulated<f16, 16> => Emulated<f16, 8>, 0x8b4e6d1fa07c9253, SC); |
1028 | | } |