@@ -32,14 +32,115 @@ where
3232 }
3333}
3434
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+ }
43144}
44145
45146/// Automatically implements operators over references in addition to the provided operator.
@@ -85,12 +186,6 @@ macro_rules! impl_op {
85186 { impl Rem for $scalar: ty } => {
86187 impl_op! { @binary $scalar, Rem :: rem, simd_rem }
87188 } ;
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- } ;
94189 { impl BitAnd for $scalar: ty } => {
95190 impl_op! { @binary $scalar, BitAnd :: bitand, simd_and }
96191 } ;
@@ -202,51 +297,6 @@ macro_rules! impl_unsigned_int_ops {
202297 }
203298 }
204299 }
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- }
250300 ) *
251301 } ;
252302}
0 commit comments