forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathminisimd.rs
More file actions
226 lines (195 loc) · 6.37 KB
/
minisimd.rs
File metadata and controls
226 lines (195 loc) · 6.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
//! Auxiliary crate for tests that need SIMD types.
//!
//! Historically the tests just made their own, but projections into simd types
//! was banned by <https://github.com/rust-lang/compiler-team/issues/838>, which
//! breaks `derive(Clone)`, so this exists to give easily-usable types that can
//! be used without copy-pasting the definitions of the helpers everywhere.
//!
//! This makes no attempt to guard against ICEs. Using it with proper types
//! and such is your responsibility in the tests you write.
#![allow(unused)]
#![allow(non_camel_case_types)]
// FIXME: `cfg(minisimd_const)` is used to toggle use of const trait impls, which require a few
// nightly features. Remove this when `const_trait_impls`, `const_cmp` and `const_index` are
// stablilized.
#![allow(unexpected_cfgs)]
// The field is currently left `pub` for convenience in porting tests, many of
// which attempt to just construct it directly. That still works; it's just the
// `.0` projection that doesn't.
#[repr(simd)]
#[derive(Copy, Eq)]
pub struct Simd<T, const N: usize>(pub [T; N]);
impl<T: Copy, const N: usize> Clone for Simd<T, N> {
fn clone(&self) -> Self {
*self
}
}
impl<T: core::fmt::Debug, const N: usize> core::fmt::Debug for Simd<T, N> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
<[T; N] as core::fmt::Debug>::fmt(self.as_array(), f)
}
}
impl<T, const N: usize> Simd<T, N> {
pub const fn from_array(a: [T; N]) -> Self {
Simd(a)
}
pub const fn as_array(&self) -> &[T; N] {
let p: *const Self = self;
unsafe { &*p.cast::<[T; N]>() }
}
pub const fn into_array(self) -> [T; N]
where
T: Copy,
{
*self.as_array()
}
pub const fn splat(a: T) -> Self
where
T: Copy,
{
Self([a; N])
}
}
pub type u8x2 = Simd<u8, 2>;
pub type u8x4 = Simd<u8, 4>;
pub type u8x8 = Simd<u8, 8>;
pub type u8x16 = Simd<u8, 16>;
pub type u8x32 = Simd<u8, 32>;
pub type u8x64 = Simd<u8, 64>;
pub type u16x2 = Simd<u16, 2>;
pub type u16x4 = Simd<u16, 4>;
pub type u16x8 = Simd<u16, 8>;
pub type u16x16 = Simd<u16, 16>;
pub type u16x32 = Simd<u16, 32>;
pub type u32x2 = Simd<u32, 2>;
pub type u32x4 = Simd<u32, 4>;
pub type u32x8 = Simd<u32, 8>;
pub type u32x16 = Simd<u32, 16>;
pub type u64x2 = Simd<u64, 2>;
pub type u64x4 = Simd<u64, 4>;
pub type u64x8 = Simd<u64, 8>;
pub type u128x2 = Simd<u128, 2>;
pub type u128x4 = Simd<u128, 4>;
pub type i8x2 = Simd<i8, 2>;
pub type i8x4 = Simd<i8, 4>;
pub type i8x8 = Simd<i8, 8>;
pub type i8x16 = Simd<i8, 16>;
pub type i8x32 = Simd<i8, 32>;
pub type i8x64 = Simd<i8, 64>;
pub type i16x2 = Simd<i16, 2>;
pub type i16x4 = Simd<i16, 4>;
pub type i16x8 = Simd<i16, 8>;
pub type i16x16 = Simd<i16, 16>;
pub type i16x32 = Simd<i16, 32>;
pub type i32x2 = Simd<i32, 2>;
pub type i32x4 = Simd<i32, 4>;
pub type i32x8 = Simd<i32, 8>;
pub type i32x16 = Simd<i32, 16>;
pub type i64x2 = Simd<i64, 2>;
pub type i64x4 = Simd<i64, 4>;
pub type i64x8 = Simd<i64, 8>;
pub type i128x2 = Simd<i128, 2>;
pub type i128x4 = Simd<i128, 4>;
pub type usizex2 = Simd<usize, 2>;
pub type usizex4 = Simd<usize, 4>;
pub type usizex8 = Simd<usize, 8>;
pub type isizex2 = Simd<isize, 2>;
pub type isizex4 = Simd<isize, 4>;
pub type isizex8 = Simd<isize, 8>;
pub type f32x2 = Simd<f32, 2>;
pub type f32x4 = Simd<f32, 4>;
pub type f32x8 = Simd<f32, 8>;
pub type f32x16 = Simd<f32, 16>;
pub type f64x2 = Simd<f64, 2>;
pub type f64x4 = Simd<f64, 4>;
pub type f64x8 = Simd<f64, 8>;
// The field is currently left `pub` for convenience in porting tests, many of
// which attempt to just construct it directly. That still works; it's just the
// `.0` projection that doesn't.
#[repr(simd, packed)]
#[derive(Copy, Eq)]
pub struct PackedSimd<T, const N: usize>(pub [T; N]);
impl<T: Copy, const N: usize> Clone for PackedSimd<T, N> {
fn clone(&self) -> Self {
*self
}
}
impl<T: core::fmt::Debug, const N: usize> core::fmt::Debug for PackedSimd<T, N> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
<[T; N] as core::fmt::Debug>::fmt(self.as_array(), f)
}
}
impl<T, const N: usize> PackedSimd<T, N> {
pub const fn from_array(a: [T; N]) -> Self {
PackedSimd(a)
}
pub const fn as_array(&self) -> &[T; N] {
let p: *const Self = self;
unsafe { &*p.cast::<[T; N]>() }
}
pub const fn into_array(self) -> [T; N]
where
T: Copy,
{
*self.as_array()
}
pub const fn splat(a: T) -> Self
where
T: Copy,
{
Self([a; N])
}
}
// As `const_trait_impl` is a language feature with specialized syntax, we have to use them in a way
// such that it doesn't get parsed as Rust code unless `cfg(minisimd_const)` is on. The easiest way
// for that is a macro
macro_rules! impl_traits {
($($const_:ident)?) => {
impl<T: $([$const_])? PartialEq, const N: usize> $($const_)? PartialEq for Simd<T, N> {
fn eq(&self, other: &Self) -> bool {
self.as_array() == other.as_array()
}
}
impl<T, const N: usize> $($const_)? core::ops::Index<usize> for Simd<T, N> {
type Output = T;
fn index(&self, i: usize) -> &T {
&self.as_array()[i]
}
}
impl<T: $([$const_])? PartialEq, const N: usize> $($const_)? PartialEq for PackedSimd<T, N>
{
fn eq(&self, other: &Self) -> bool {
self.as_array() == other.as_array()
}
}
};
}
#[cfg(minisimd_const)]
impl_traits!(const);
#[cfg(not(minisimd_const))]
impl_traits!();
/// Version of `assert_eq` that ignores fancy runtime printing in const context.
/// FIXME: Remove once <https://github.com/rust-lang/rust/issues/119826> is fixed.
#[cfg(minisimd_const)]
#[macro_export]
macro_rules! assert_eq {
($left:expr, $right:expr $(,)?) => {
assert_eq!(
$left,
$right,
concat!("`", stringify!($left), "` == `", stringify!($right), "`")
);
};
($left:expr, $right:expr$(, $($arg:tt)+)?) => {
{
let left = $left;
let right = $right;
// type inference works better with the concrete type on the
// left, but humans work better with the expected on the
// right
assert!(right == left, $($($arg)*),*);
}
};
}
#[cfg(minisimd_const)]
use assert_eq;