Coverage Report

Created: 2026-08-14 08:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}