@@ -32,14 +32,115 @@ where
32
32
}
33
33
}
34
34
35
- /// Checks if the right-hand side argument of a left- or right-shift would cause overflow.
36
- fn invalid_shift_rhs < T > ( rhs : T ) -> bool
37
- where
38
- T : Default + PartialOrd + core:: convert:: TryFrom < usize > ,
39
- <T as core:: convert:: TryFrom < usize > >:: Error : core:: fmt:: Debug ,
40
- {
41
- let bits_in_type = T :: try_from ( 8 * core:: mem:: size_of :: < T > ( ) ) . unwrap ( ) ;
42
- rhs < T :: default ( ) || rhs >= bits_in_type
35
+ /// SAFETY: This macro should not be used for anything except Shl or Shr, and passed the appropriate shift intrinsic.
36
+ /// It handles performing a bitand in addition to calling the shift operator, so that the result
37
+ /// is well-defined: LLVM can return a poison value if you shl, lshr, or ashr if rhs >= <Int>::BITS
38
+ /// At worst, this will maybe add another instruction and cycle,
39
+ /// at best, it may open up more optimization opportunities,
40
+ /// or simply be elided entirely, especially for SIMD ISAs which default to this.
41
+ ///
42
+ // FIXME: Consider implementing this in cg_llvm instead?
43
+ // 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 > {
46
+ fn $call: ident( self , rhs: Self ) -> Self :: Output {
47
+ unsafe { $simd_call: ident }
48
+ }
49
+ } ) => {
50
+ impl <const LANES : usize > $op for Simd <$int, LANES >
51
+ where
52
+ $int: SimdElement ,
53
+ LaneCount <LANES >: SupportedLaneCount ,
54
+ {
55
+ type Output = Self ;
56
+
57
+ #[ inline]
58
+ #[ must_use = "operator returns a new vector without mutating the inputs" ]
59
+ fn $call( self , rhs: Self ) -> Self :: Output {
60
+ unsafe {
61
+ $crate:: intrinsics:: $simd_call( self , rhs. bitand( Simd :: splat( <$int>:: BITS as $int - 1 ) ) )
62
+ }
63
+ }
64
+ }
65
+ } ;
66
+ }
67
+
68
+ macro_rules! wrap_bitshifts {
69
+ ( $( impl <const LANES : usize > ShiftOps for Simd <$int: ty, LANES > {
70
+ fn shl( self , rhs: Self ) -> Self :: Output ;
71
+ fn shr( self , rhs: Self ) -> Self :: Output ;
72
+ } ) * ) => {
73
+ $(
74
+ wrap_bitshift_inner! {
75
+ impl <const LANES : usize > Shl for Simd <$int, LANES > {
76
+ fn shl( self , rhs: Self ) -> Self :: Output {
77
+ unsafe { simd_shl }
78
+ }
79
+ }
80
+ }
81
+ wrap_bitshift_inner! {
82
+ impl <const LANES : usize > Shr for Simd <$int, LANES > {
83
+ fn shr( self , rhs: Self ) -> Self :: Output {
84
+ // This automatically monomorphizes to lshr or ashr, depending,
85
+ // so it's fine to use it for both UInts and SInts.
86
+ unsafe { simd_shr }
87
+ }
88
+ }
89
+ }
90
+ ) *
91
+ } ;
92
+ }
93
+
94
+ wrap_bitshifts ! {
95
+ impl <const LANES : usize > ShiftOps for Simd <i8 , LANES > {
96
+ fn shl( self , rhs: Self ) -> Self :: Output ;
97
+ fn shr( self , rhs: Self ) -> Self :: Output ;
98
+ }
99
+
100
+ impl <const LANES : usize > ShiftOps for Simd <i16 , LANES > {
101
+ fn shl( self , rhs: Self ) -> Self :: Output ;
102
+ fn shr( self , rhs: Self ) -> Self :: Output ;
103
+ }
104
+
105
+ impl <const LANES : usize > ShiftOps for Simd <i32 , LANES > {
106
+ fn shl( self , rhs: Self ) -> Self :: Output ;
107
+ fn shr( self , rhs: Self ) -> Self :: Output ;
108
+ }
109
+
110
+ impl <const LANES : usize > ShiftOps for Simd <i64 , LANES > {
111
+ fn shl( self , rhs: Self ) -> Self :: Output ;
112
+ fn shr( self , rhs: Self ) -> Self :: Output ;
113
+ }
114
+
115
+ impl <const LANES : usize > ShiftOps for Simd <isize , LANES > {
116
+ fn shl( self , rhs: Self ) -> Self :: Output ;
117
+ fn shr( self , rhs: Self ) -> Self :: Output ;
118
+ }
119
+
120
+ impl <const LANES : usize > ShiftOps for Simd <u8 , LANES > {
121
+ fn shl( self , rhs: Self ) -> Self :: Output ;
122
+ fn shr( self , rhs: Self ) -> Self :: Output ;
123
+ }
124
+
125
+ impl <const LANES : usize > ShiftOps for Simd <u16 , LANES > {
126
+ fn shl( self , rhs: Self ) -> Self :: Output ;
127
+ fn shr( self , rhs: Self ) -> Self :: Output ;
128
+ }
129
+
130
+ impl <const LANES : usize > ShiftOps for Simd <u32 , LANES > {
131
+ fn shl( self , rhs: Self ) -> Self :: Output ;
132
+ fn shr( self , rhs: Self ) -> Self :: Output ;
133
+ }
134
+
135
+ impl <const LANES : usize > ShiftOps for Simd <u64 , LANES > {
136
+ fn shl( self , rhs: Self ) -> Self :: Output ;
137
+ fn shr( self , rhs: Self ) -> Self :: Output ;
138
+ }
139
+
140
+ impl <const LANES : usize > ShiftOps for Simd <usize , LANES > {
141
+ fn shl( self , rhs: Self ) -> Self :: Output ;
142
+ fn shr( self , rhs: Self ) -> Self :: Output ;
143
+ }
43
144
}
44
145
45
146
/// Automatically implements operators over references in addition to the provided operator.
@@ -85,12 +186,6 @@ macro_rules! impl_op {
85
186
{ impl Rem for $scalar: ty } => {
86
187
impl_op! { @binary $scalar, Rem :: rem, simd_rem }
87
188
} ;
88
- { impl Shl for $scalar: ty } => {
89
- impl_op! { @binary $scalar, Shl :: shl, simd_shl }
90
- } ;
91
- { impl Shr for $scalar: ty } => {
92
- impl_op! { @binary $scalar, Shr :: shr, simd_shr }
93
- } ;
94
189
{ impl BitAnd for $scalar: ty } => {
95
190
impl_op! { @binary $scalar, BitAnd :: bitand, simd_and }
96
191
} ;
@@ -202,51 +297,6 @@ macro_rules! impl_unsigned_int_ops {
202
297
}
203
298
}
204
299
}
205
-
206
- // shifts panic on overflow
207
- impl_ref_ops! {
208
- impl <const LANES : usize > core:: ops:: Shl <Self > for Simd <$scalar, LANES >
209
- where
210
- LaneCount <LANES >: SupportedLaneCount ,
211
- {
212
- type Output = Self ;
213
-
214
- #[ inline]
215
- fn shl( self , rhs: Self ) -> Self :: Output {
216
- // TODO there is probably a better way of doing this
217
- if rhs. as_array( )
218
- . iter( )
219
- . copied( )
220
- . any( invalid_shift_rhs)
221
- {
222
- panic!( "attempt to shift left with overflow" ) ;
223
- }
224
- unsafe { intrinsics:: simd_shl( self , rhs) }
225
- }
226
- }
227
- }
228
-
229
- impl_ref_ops! {
230
- impl <const LANES : usize > core:: ops:: Shr <Self > for Simd <$scalar, LANES >
231
- where
232
- LaneCount <LANES >: SupportedLaneCount ,
233
- {
234
- type Output = Self ;
235
-
236
- #[ inline]
237
- fn shr( self , rhs: Self ) -> Self :: Output {
238
- // TODO there is probably a better way of doing this
239
- if rhs. as_array( )
240
- . iter( )
241
- . copied( )
242
- . any( invalid_shift_rhs)
243
- {
244
- panic!( "attempt to shift with overflow" ) ;
245
- }
246
- unsafe { intrinsics:: simd_shr( self , rhs) }
247
- }
248
- }
249
- }
250
300
) *
251
301
} ;
252
302
}
0 commit comments