32
32
}
33
33
}
34
34
35
+ macro_rules! unsafe_base_op {
36
+ ( $( impl <const LANES : usize > $op: ident for Simd <$scalar: ty, LANES > {
37
+ fn $call: ident( self , rhs: Self ) -> Self :: Output {
38
+ unsafe { $simd_call: ident }
39
+ }
40
+ } ) * ) => {
41
+ $( impl <const LANES : usize > $op for Simd <$scalar, LANES >
42
+ where
43
+ $scalar: SimdElement ,
44
+ LaneCount <LANES >: SupportedLaneCount ,
45
+ {
46
+ type Output = Self ;
47
+
48
+ #[ inline]
49
+ #[ must_use = "operator returns a new vector without mutating the inputs" ]
50
+ fn $call( self , rhs: Self ) -> Self :: Output {
51
+ unsafe { $crate:: intrinsics:: $simd_call( self , rhs) }
52
+ }
53
+ }
54
+ ) *
55
+ }
56
+ }
57
+
35
58
/// SAFETY: This macro should not be used for anything except Shl or Shr, and passed the appropriate shift intrinsic.
36
59
/// It handles performing a bitand in addition to calling the shift operator, so that the result
37
60
/// is well-defined: LLVM can return a poison value if you shl, lshr, or ashr if rhs >= <Int>::BITS
@@ -41,13 +64,13 @@ where
41
64
///
42
65
// FIXME: Consider implementing this in cg_llvm instead?
43
66
// cg_clif defaults to this, and scalar MIR shifts also default to wrapping
44
- macro_rules! wrap_bitshift_inner {
45
- ( impl <const LANES : usize > $op: ident for Simd <$int: ty, LANES > {
67
+ macro_rules! wrap_bitshift {
68
+ ( $ ( impl <const LANES : usize > $op: ident for Simd <$int: ty, LANES > {
46
69
fn $call: ident( self , rhs: Self ) -> Self :: Output {
47
70
unsafe { $simd_call: ident }
48
71
}
49
- } ) => {
50
- impl <const LANES : usize > $op for Simd <$int, LANES >
72
+ } ) * ) => {
73
+ $ ( impl <const LANES : usize > $op for Simd <$int, LANES >
51
74
where
52
75
$int: SimdElement ,
53
76
LaneCount <LANES >: SupportedLaneCount ,
@@ -61,24 +84,45 @@ macro_rules! wrap_bitshift_inner {
61
84
$crate:: intrinsics:: $simd_call( self , rhs. bitand( Simd :: splat( <$int>:: BITS as $int - 1 ) ) )
62
85
}
63
86
}
64
- }
87
+ } ) *
65
88
} ;
66
89
}
67
90
68
- macro_rules! wrap_bitshifts {
69
- ( $( impl <const LANES : usize > ShiftOps for Simd <$int: ty, LANES > {
91
+ macro_rules! bitops {
92
+ ( $( impl <const LANES : usize > BitOps for Simd <$int: ty, LANES > {
93
+ fn bitand( self , rhs: Self ) -> Self :: Output ;
94
+ fn bitor( self , rhs: Self ) -> Self :: Output ;
95
+ fn bitxor( self , rhs: Self ) -> Self :: Output ;
70
96
fn shl( self , rhs: Self ) -> Self :: Output ;
71
97
fn shr( self , rhs: Self ) -> Self :: Output ;
72
98
} ) * ) => {
73
99
$(
74
- wrap_bitshift_inner! {
100
+ unsafe_base_op!{
101
+ impl <const LANES : usize > BitAnd for Simd <$int, LANES > {
102
+ fn bitand( self , rhs: Self ) -> Self :: Output {
103
+ unsafe { simd_and }
104
+ }
105
+ }
106
+
107
+ impl <const LANES : usize > BitOr for Simd <$int, LANES > {
108
+ fn bitor( self , rhs: Self ) -> Self :: Output {
109
+ unsafe { simd_or }
110
+ }
111
+ }
112
+
113
+ impl <const LANES : usize > BitXor for Simd <$int, LANES > {
114
+ fn bitxor( self , rhs: Self ) -> Self :: Output {
115
+ unsafe { simd_xor }
116
+ }
117
+ }
118
+ }
119
+ wrap_bitshift! {
75
120
impl <const LANES : usize > Shl for Simd <$int, LANES > {
76
121
fn shl( self , rhs: Self ) -> Self :: Output {
77
122
unsafe { simd_shl }
78
123
}
79
124
}
80
- }
81
- wrap_bitshift_inner! {
125
+
82
126
impl <const LANES : usize > Shr for Simd <$int, LANES > {
83
127
fn shr( self , rhs: Self ) -> Self :: Output {
84
128
// This automatically monomorphizes to lshr or ashr, depending,
@@ -91,53 +135,86 @@ macro_rules! wrap_bitshifts {
91
135
} ;
92
136
}
93
137
94
- wrap_bitshifts ! {
95
- impl <const LANES : usize > ShiftOps for Simd <i8 , LANES > {
138
+ // Integers can always accept bitand, bitor, and bitxor.
139
+ // The only question is how to handle shifts >= <Int>::BITS?
140
+ // Our current solution uses wrapping logic.
141
+ bitops ! {
142
+ impl <const LANES : usize > BitOps for Simd <i8 , LANES > {
143
+ fn bitand( self , rhs: Self ) -> Self :: Output ;
144
+ fn bitor( self , rhs: Self ) -> Self :: Output ;
145
+ fn bitxor( self , rhs: Self ) -> Self :: Output ;
96
146
fn shl( self , rhs: Self ) -> Self :: Output ;
97
147
fn shr( self , rhs: Self ) -> Self :: Output ;
98
148
}
99
149
100
- impl <const LANES : usize > ShiftOps for Simd <i16 , LANES > {
150
+ impl <const LANES : usize > BitOps for Simd <i16 , LANES > {
151
+ fn bitand( self , rhs: Self ) -> Self :: Output ;
152
+ fn bitor( self , rhs: Self ) -> Self :: Output ;
153
+ fn bitxor( self , rhs: Self ) -> Self :: Output ;
101
154
fn shl( self , rhs: Self ) -> Self :: Output ;
102
155
fn shr( self , rhs: Self ) -> Self :: Output ;
103
156
}
104
157
105
- impl <const LANES : usize > ShiftOps for Simd <i32 , LANES > {
158
+ impl <const LANES : usize > BitOps for Simd <i32 , LANES > {
159
+ fn bitand( self , rhs: Self ) -> Self :: Output ;
160
+ fn bitor( self , rhs: Self ) -> Self :: Output ;
161
+ fn bitxor( self , rhs: Self ) -> Self :: Output ;
106
162
fn shl( self , rhs: Self ) -> Self :: Output ;
107
163
fn shr( self , rhs: Self ) -> Self :: Output ;
108
164
}
109
165
110
- impl <const LANES : usize > ShiftOps for Simd <i64 , LANES > {
166
+ impl <const LANES : usize > BitOps for Simd <i64 , LANES > {
167
+ fn bitand( self , rhs: Self ) -> Self :: Output ;
168
+ fn bitor( self , rhs: Self ) -> Self :: Output ;
169
+ fn bitxor( self , rhs: Self ) -> Self :: Output ;
111
170
fn shl( self , rhs: Self ) -> Self :: Output ;
112
171
fn shr( self , rhs: Self ) -> Self :: Output ;
113
172
}
114
173
115
- impl <const LANES : usize > ShiftOps for Simd <isize , LANES > {
174
+ impl <const LANES : usize > BitOps for Simd <isize , LANES > {
175
+ fn bitand( self , rhs: Self ) -> Self :: Output ;
176
+ fn bitor( self , rhs: Self ) -> Self :: Output ;
177
+ fn bitxor( self , rhs: Self ) -> Self :: Output ;
116
178
fn shl( self , rhs: Self ) -> Self :: Output ;
117
179
fn shr( self , rhs: Self ) -> Self :: Output ;
118
180
}
119
181
120
- impl <const LANES : usize > ShiftOps for Simd <u8 , LANES > {
182
+ impl <const LANES : usize > BitOps for Simd <u8 , LANES > {
183
+ fn bitand( self , rhs: Self ) -> Self :: Output ;
184
+ fn bitor( self , rhs: Self ) -> Self :: Output ;
185
+ fn bitxor( self , rhs: Self ) -> Self :: Output ;
121
186
fn shl( self , rhs: Self ) -> Self :: Output ;
122
187
fn shr( self , rhs: Self ) -> Self :: Output ;
123
188
}
124
189
125
- impl <const LANES : usize > ShiftOps for Simd <u16 , LANES > {
190
+ impl <const LANES : usize > BitOps for Simd <u16 , LANES > {
191
+ fn bitand( self , rhs: Self ) -> Self :: Output ;
192
+ fn bitor( self , rhs: Self ) -> Self :: Output ;
193
+ fn bitxor( self , rhs: Self ) -> Self :: Output ;
126
194
fn shl( self , rhs: Self ) -> Self :: Output ;
127
195
fn shr( self , rhs: Self ) -> Self :: Output ;
128
196
}
129
197
130
- impl <const LANES : usize > ShiftOps for Simd <u32 , LANES > {
198
+ impl <const LANES : usize > BitOps for Simd <u32 , LANES > {
199
+ fn bitand( self , rhs: Self ) -> Self :: Output ;
200
+ fn bitor( self , rhs: Self ) -> Self :: Output ;
201
+ fn bitxor( self , rhs: Self ) -> Self :: Output ;
131
202
fn shl( self , rhs: Self ) -> Self :: Output ;
132
203
fn shr( self , rhs: Self ) -> Self :: Output ;
133
204
}
134
205
135
- impl <const LANES : usize > ShiftOps for Simd <u64 , LANES > {
206
+ impl <const LANES : usize > BitOps for Simd <u64 , LANES > {
207
+ fn bitand( self , rhs: Self ) -> Self :: Output ;
208
+ fn bitor( self , rhs: Self ) -> Self :: Output ;
209
+ fn bitxor( self , rhs: Self ) -> Self :: Output ;
136
210
fn shl( self , rhs: Self ) -> Self :: Output ;
137
211
fn shr( self , rhs: Self ) -> Self :: Output ;
138
212
}
139
213
140
- impl <const LANES : usize > ShiftOps for Simd <usize , LANES > {
214
+ impl <const LANES : usize > BitOps for Simd <usize , LANES > {
215
+ fn bitand( self , rhs: Self ) -> Self :: Output ;
216
+ fn bitor( self , rhs: Self ) -> Self :: Output ;
217
+ fn bitxor( self , rhs: Self ) -> Self :: Output ;
141
218
fn shl( self , rhs: Self ) -> Self :: Output ;
142
219
fn shr( self , rhs: Self ) -> Self :: Output ;
143
220
}
@@ -186,15 +263,6 @@ macro_rules! impl_op {
186
263
{ impl Rem for $scalar: ty } => {
187
264
impl_op! { @binary $scalar, Rem :: rem, simd_rem }
188
265
} ;
189
- { impl BitAnd for $scalar: ty } => {
190
- impl_op! { @binary $scalar, BitAnd :: bitand, simd_and }
191
- } ;
192
- { impl BitOr for $scalar: ty } => {
193
- impl_op! { @binary $scalar, BitOr :: bitor, simd_or }
194
- } ;
195
- { impl BitXor for $scalar: ty } => {
196
- impl_op! { @binary $scalar, BitXor :: bitxor, simd_xor }
197
- } ;
198
266
199
267
// generic binary op with assignment when output is `Self`
200
268
{ @binary $scalar: ty, $trait: ident :: $trait_fn: ident, $intrinsic: ident } => {
@@ -236,9 +304,6 @@ macro_rules! impl_unsigned_int_ops {
236
304
impl_op! { impl Add for $scalar }
237
305
impl_op! { impl Sub for $scalar }
238
306
impl_op! { impl Mul for $scalar }
239
- impl_op! { impl BitAnd for $scalar }
240
- impl_op! { impl BitOr for $scalar }
241
- impl_op! { impl BitXor for $scalar }
242
307
243
308
// Integers panic on divide by 0
244
309
impl_ref_ops! {
0 commit comments