|
1 | 1 | use rustc_apfloat::ieee::Double; |
2 | | -use rustc_middle::ty::layout::LayoutOf as _; |
3 | | -use rustc_middle::ty::Ty; |
4 | 2 | use rustc_span::Symbol; |
5 | 3 | use rustc_target::spec::abi::Abi; |
6 | 4 |
|
7 | | -use super::{bin_op_simd_float_all, bin_op_simd_float_first, convert_float_to_int, FloatBinOp}; |
| 5 | +use super::{ |
| 6 | + bin_op_simd_float_all, bin_op_simd_float_first, convert_float_to_int, shift_simd_by_scalar, |
| 7 | + FloatBinOp, ShiftOp, |
| 8 | +}; |
8 | 9 | use crate::*; |
9 | 10 | use shims::foreign_items::EmulateForeignItemResult; |
10 | 11 |
|
@@ -109,156 +110,27 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: |
109 | 110 | this.write_scalar(Scalar::from_u64(res.into()), &dest)?; |
110 | 111 | } |
111 | 112 | } |
112 | | - // Used to implement the _mm_{sll,srl,sra}_epi16 functions. |
113 | | - // Shifts 16-bit packed integers in left by the amount in right. |
114 | | - // Both operands are vectors of 16-bit integers. However, right is |
115 | | - // interpreted as a single 64-bit integer (remaining bits are ignored). |
116 | | - // For logic shifts, when right is larger than 15, zero is produced. |
117 | | - // For arithmetic shifts, when right is larger than 15, the sign bit |
| 113 | + // Used to implement the _mm_{sll,srl,sra}_epi{16,32,64} functions |
| 114 | + // (except _mm_sra_epi64, which is not available in SSE2). |
| 115 | + // Shifts N-bit packed integers in left by the amount in right. |
| 116 | + // Both operands are 128-bit vectors. However, right is interpreted as |
| 117 | + // a single 64-bit integer (remaining bits are ignored). |
| 118 | + // For logic shifts, when right is larger than N - 1, zero is produced. |
| 119 | + // For arithmetic shifts, when right is larger than N - 1, the sign bit |
118 | 120 | // is copied to remaining bits. |
119 | | - "psll.w" | "psrl.w" | "psra.w" => { |
| 121 | + "psll.w" | "psrl.w" | "psra.w" | "psll.d" | "psrl.d" | "psra.d" | "psll.q" |
| 122 | + | "psrl.q" => { |
120 | 123 | let [left, right] = |
121 | 124 | this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; |
122 | 125 |
|
123 | | - let (left, left_len) = this.operand_to_simd(left)?; |
124 | | - let (right, right_len) = this.operand_to_simd(right)?; |
125 | | - let (dest, dest_len) = this.mplace_to_simd(dest)?; |
126 | | - |
127 | | - assert_eq!(dest_len, left_len); |
128 | | - assert_eq!(dest_len, right_len); |
129 | | - |
130 | | - enum ShiftOp { |
131 | | - Sll, |
132 | | - Srl, |
133 | | - Sra, |
134 | | - } |
135 | 126 | let which = match unprefixed_name { |
136 | | - "psll.w" => ShiftOp::Sll, |
137 | | - "psrl.w" => ShiftOp::Srl, |
138 | | - "psra.w" => ShiftOp::Sra, |
| 127 | + "psll.w" | "psll.d" | "psll.q" => ShiftOp::Left, |
| 128 | + "psrl.w" | "psrl.d" | "psrl.q" => ShiftOp::RightLogic, |
| 129 | + "psra.w" | "psra.d" => ShiftOp::RightArith, |
139 | 130 | _ => unreachable!(), |
140 | 131 | }; |
141 | 132 |
|
142 | | - // Get the 64-bit shift operand and convert it to the type expected |
143 | | - // by checked_{shl,shr} (u32). |
144 | | - // It is ok to saturate the value to u32::MAX because any value |
145 | | - // above 15 will produce the same result. |
146 | | - let shift = extract_first_u64(this, &right)?.try_into().unwrap_or(u32::MAX); |
147 | | - |
148 | | - for i in 0..dest_len { |
149 | | - let left = this.read_scalar(&this.project_index(&left, i)?)?.to_u16()?; |
150 | | - let dest = this.project_index(&dest, i)?; |
151 | | - |
152 | | - let res = match which { |
153 | | - ShiftOp::Sll => left.checked_shl(shift).unwrap_or(0), |
154 | | - ShiftOp::Srl => left.checked_shr(shift).unwrap_or(0), |
155 | | - #[allow(clippy::cast_possible_wrap, clippy::cast_sign_loss)] |
156 | | - ShiftOp::Sra => { |
157 | | - // Convert u16 to i16 to use arithmetic shift |
158 | | - let left = left as i16; |
159 | | - // Copy the sign bit to the remaining bits |
160 | | - left.checked_shr(shift).unwrap_or(left >> 15) as u16 |
161 | | - } |
162 | | - }; |
163 | | - |
164 | | - this.write_scalar(Scalar::from_u16(res), &dest)?; |
165 | | - } |
166 | | - } |
167 | | - // Used to implement the _mm_{sll,srl,sra}_epi32 functions. |
168 | | - // 32-bit equivalent to the shift functions above. |
169 | | - "psll.d" | "psrl.d" | "psra.d" => { |
170 | | - let [left, right] = |
171 | | - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; |
172 | | - |
173 | | - let (left, left_len) = this.operand_to_simd(left)?; |
174 | | - let (right, right_len) = this.operand_to_simd(right)?; |
175 | | - let (dest, dest_len) = this.mplace_to_simd(dest)?; |
176 | | - |
177 | | - assert_eq!(dest_len, left_len); |
178 | | - assert_eq!(dest_len, right_len); |
179 | | - |
180 | | - enum ShiftOp { |
181 | | - Sll, |
182 | | - Srl, |
183 | | - Sra, |
184 | | - } |
185 | | - let which = match unprefixed_name { |
186 | | - "psll.d" => ShiftOp::Sll, |
187 | | - "psrl.d" => ShiftOp::Srl, |
188 | | - "psra.d" => ShiftOp::Sra, |
189 | | - _ => unreachable!(), |
190 | | - }; |
191 | | - |
192 | | - // Get the 64-bit shift operand and convert it to the type expected |
193 | | - // by checked_{shl,shr} (u32). |
194 | | - // It is ok to saturate the value to u32::MAX because any value |
195 | | - // above 31 will produce the same result. |
196 | | - let shift = extract_first_u64(this, &right)?.try_into().unwrap_or(u32::MAX); |
197 | | - |
198 | | - for i in 0..dest_len { |
199 | | - let left = this.read_scalar(&this.project_index(&left, i)?)?.to_u32()?; |
200 | | - let dest = this.project_index(&dest, i)?; |
201 | | - |
202 | | - let res = match which { |
203 | | - ShiftOp::Sll => left.checked_shl(shift).unwrap_or(0), |
204 | | - ShiftOp::Srl => left.checked_shr(shift).unwrap_or(0), |
205 | | - #[allow(clippy::cast_possible_wrap, clippy::cast_sign_loss)] |
206 | | - ShiftOp::Sra => { |
207 | | - // Convert u32 to i32 to use arithmetic shift |
208 | | - let left = left as i32; |
209 | | - // Copy the sign bit to the remaining bits |
210 | | - left.checked_shr(shift).unwrap_or(left >> 31) as u32 |
211 | | - } |
212 | | - }; |
213 | | - |
214 | | - this.write_scalar(Scalar::from_u32(res), &dest)?; |
215 | | - } |
216 | | - } |
217 | | - // Used to implement the _mm_{sll,srl}_epi64 functions. |
218 | | - // 64-bit equivalent to the shift functions above, except _mm_sra_epi64, |
219 | | - // which is not available in SSE2. |
220 | | - "psll.q" | "psrl.q" => { |
221 | | - let [left, right] = |
222 | | - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; |
223 | | - |
224 | | - let (left, left_len) = this.operand_to_simd(left)?; |
225 | | - let (right, right_len) = this.operand_to_simd(right)?; |
226 | | - let (dest, dest_len) = this.mplace_to_simd(dest)?; |
227 | | - |
228 | | - assert_eq!(dest_len, left_len); |
229 | | - assert_eq!(dest_len, right_len); |
230 | | - |
231 | | - enum ShiftOp { |
232 | | - Sll, |
233 | | - Srl, |
234 | | - } |
235 | | - let which = match unprefixed_name { |
236 | | - "psll.q" => ShiftOp::Sll, |
237 | | - "psrl.q" => ShiftOp::Srl, |
238 | | - _ => unreachable!(), |
239 | | - }; |
240 | | - |
241 | | - // Get the 64-bit shift operand and convert it to the type expected |
242 | | - // by checked_{shl,shr} (u32). |
243 | | - // It is ok to saturate the value to u32::MAX because any value |
244 | | - // above 63 will produce the same result. |
245 | | - let shift = this |
246 | | - .read_scalar(&this.project_index(&right, 0)?)? |
247 | | - .to_u64()? |
248 | | - .try_into() |
249 | | - .unwrap_or(u32::MAX); |
250 | | - |
251 | | - for i in 0..dest_len { |
252 | | - let left = this.read_scalar(&this.project_index(&left, i)?)?.to_u64()?; |
253 | | - let dest = this.project_index(&dest, i)?; |
254 | | - |
255 | | - let res = match which { |
256 | | - ShiftOp::Sll => left.checked_shl(shift).unwrap_or(0), |
257 | | - ShiftOp::Srl => left.checked_shr(shift).unwrap_or(0), |
258 | | - }; |
259 | | - |
260 | | - this.write_scalar(Scalar::from_u64(res), &dest)?; |
261 | | - } |
| 133 | + shift_simd_by_scalar(this, left, right, which, dest)?; |
262 | 134 | } |
263 | 135 | // Used to implement the _mm_cvtps_epi32, _mm_cvttps_epi32, _mm_cvtpd_epi32 |
264 | 136 | // and _mm_cvttpd_epi32 functions. |
@@ -585,17 +457,3 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: |
585 | 457 | Ok(EmulateForeignItemResult::NeedsJumping) |
586 | 458 | } |
587 | 459 | } |
588 | | - |
589 | | -/// Takes a 128-bit vector, transmutes it to `[u64; 2]` and extracts |
590 | | -/// the first value. |
591 | | -fn extract_first_u64<'tcx>( |
592 | | - this: &crate::MiriInterpCx<'_, 'tcx>, |
593 | | - op: &MPlaceTy<'tcx, Provenance>, |
594 | | -) -> InterpResult<'tcx, u64> { |
595 | | - // Transmute vector to `[u64; 2]` |
596 | | - let u64_array_layout = this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u64, 2))?; |
597 | | - let op = op.transmute(u64_array_layout, this)?; |
598 | | - |
599 | | - // Get the first u64 from the array |
600 | | - this.read_scalar(&this.project_index(&op, 0)?)?.to_u64() |
601 | | -} |
0 commit comments