Skip to main content

diskann_wide/arch/x86_64/v3/
conversion.rs

1/*
2 * Copyright (c) Microsoft Corporation.
3 * Licensed under the MIT license.
4 */
5
6// x86 intrinsics
7use std::arch::x86_64::*;
8
9use super::{f16x8, f16x16, f32x8, f32x16, i8x16, i16x8, i16x16, i32x8, u8x16, u32x8};
10use crate::{LoHi, SIMDCast, SIMDReinterpret, SplitJoin, helpers};
11
12/////////////////
13// Conversions //
14/////////////////
15
16// f16 to f32
17cfg_if::cfg_if! {
18    // Miri does not have built-in support for these intrinsics.
19    //
20    // So when we run under Miri, we need to use emulated conversion.
21    if #[cfg(not(miri))] {
22        helpers::unsafe_map_conversion!(f16x8, f32x8, _mm256_cvtph_ps, "f16c");
23        helpers::unsafe_map_cast!(
24            f32x8 => (half::f16, f16x8),
25            _mm256_cvtps_ph::<_MM_FROUND_TO_NEAREST_INT>,
26            "f16c"
27        );
28        helpers::unsafe_map_cast!(f16x8 => (f32, f32x8), _mm256_cvtph_ps, "f16c");
29    } else {
30        use crate::{SIMDVector, reference::ReferenceCast};
31
32        impl From<f16x8> for f32x8 {
33            fn from(value: f16x8) -> f32x8 {
34                let array = value.to_array();
35                let converted = array.map(|i| i.reference_cast());
36                f32x8::from_array(value.arch(), converted)
37            }
38        }
39
40        impl SIMDCast<f32> for f16x8 {
41            type Cast = f32x8;
42
43            fn simd_cast(self) -> f32x8 {
44                self.into()
45            }
46        }
47
48        impl SIMDCast<half::f16> for f32x8 {
49            type Cast = f16x8;
50
51            fn simd_cast(self) -> f16x8 {
52                let array = self.to_array();
53                let converted = array.map(|i| i.reference_cast());
54                f16x8::from_array(self.arch(), converted)
55            }
56        }
57    }
58}
59
60impl From<f16x16> for f32x16 {
61    #[inline(always)]
62    fn from(value: f16x16) -> f32x16 {
63        let LoHi { lo, hi } = value.split();
64        f32x16::new(lo.into(), hi.into())
65    }
66}
67
68impl SIMDCast<f32> for f16x16 {
69    type Cast = f32x16;
70    #[inline(always)]
71    fn simd_cast(self) -> f32x16 {
72        self.into()
73    }
74}
75
76impl SIMDCast<half::f16> for f32x16 {
77    type Cast = f16x16;
78    #[inline(always)]
79    fn simd_cast(self) -> f16x16 {
80        self.split().map(|x| -> f16x8 { x.simd_cast() }).join()
81    }
82}
83
84// i8 to i16
85helpers::unsafe_map_conversion!(i8x16, i16x16, _mm256_cvtepi8_epi16, "avx2");
86
87// u8 to i16
88helpers::unsafe_map_conversion!(u8x16, i16x16, _mm256_cvtepu8_epi16, "avx2");
89
90// i32 to f32
91helpers::unsafe_map_cast!(i32x8 => (f32, f32x8), _mm256_cvtepi32_ps, "avx");
92
93//////////////////
94// Reinterprets //
95//////////////////
96
97impl SIMDReinterpret<i16x16> for u32x8 {
98    fn reinterpret_simd(self) -> i16x16 {
99        i16x16(self.0)
100    }
101}
102
103impl SIMDReinterpret<u8x16> for i16x8 {
104    fn reinterpret_simd(self) -> u8x16 {
105        u8x16(self.0)
106    }
107}
108
109impl SIMDReinterpret<i16x8> for u8x16 {
110    fn reinterpret_simd(self) -> i16x8 {
111        i16x8(self.0)
112    }
113}
114
115///////////
116// Tests //
117///////////
118
119#[cfg(test)]
120mod test_x86_conversions {
121    use super::*;
122    use crate::{arch::x86_64::V3, test_utils};
123
124    // Lossless Conversions
125    #[cfg(not(miri))]
126    test_utils::ops::test_lossless_convert!(
127        f16x8 => f32x8, 0xa998182f02ff4d0d, V3::new_checked_uncached()
128    );
129
130    #[cfg(not(miri))]
131    test_utils::ops::test_lossless_convert!(
132        f16x16 => f32x16, 0xf63b356d1dfc1d52, V3::new_checked_uncached()
133    );
134
135    test_utils::ops::test_lossless_convert!(
136        i8x16 => i16x16, 0x84602159fb122584, V3::new_checked_uncached()
137    );
138    test_utils::ops::test_lossless_convert!(
139        u8x16 => i16x16, 0x5ba4b69df84ca568, V3::new_checked_uncached()
140    );
141
142    // Numeric Casts
143    test_utils::ops::test_cast!(f16x8 => f32x8, 0x37314659b022466a, V3::new_checked_uncached());
144    test_utils::ops::test_cast!(f16x16 => f32x16, 0xba8fe343fc9dbeff, V3::new_checked_uncached());
145
146    test_utils::ops::test_cast!(f32x8 => f16x8, 0x8386cb0a7091cc3b, V3::new_checked_uncached());
147    test_utils::ops::test_cast!(f32x16 => f16x16, 0x7b9c9afee7e6ac63, V3::new_checked_uncached());
148
149    test_utils::ops::test_cast!(i32x8 => f32x8, 0xde4fbf25c554b29e, V3::new_checked_uncached());
150}