|
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