|
1 | | -use rustc_apfloat::{ieee::Single, Float as _}; |
| 1 | +use rustc_apfloat::ieee::Single; |
2 | 2 | use rustc_middle::mir; |
3 | 3 | use rustc_span::Symbol; |
4 | 4 | use rustc_target::spec::abi::Abi; |
5 | 5 |
|
6 | | -use rand::Rng as _; |
7 | | - |
8 | | -use super::{bin_op_simd_float_all, bin_op_simd_float_first, FloatBinOp}; |
| 6 | +use super::{ |
| 7 | + bin_op_simd_float_all, bin_op_simd_float_first, unary_op_ps, unary_op_ss, FloatBinOp, |
| 8 | + FloatUnaryOp, |
| 9 | +}; |
9 | 10 | use crate::*; |
10 | 11 | use shims::foreign_items::EmulateForeignItemResult; |
11 | 12 |
|
@@ -219,124 +220,3 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: |
219 | 220 | Ok(EmulateForeignItemResult::NeedsJumping) |
220 | 221 | } |
221 | 222 | } |
222 | | - |
223 | | -#[derive(Copy, Clone)] |
224 | | -enum FloatUnaryOp { |
225 | | - /// sqrt(x) |
226 | | - /// |
227 | | - /// <https://www.felixcloutier.com/x86/sqrtss> |
228 | | - /// <https://www.felixcloutier.com/x86/sqrtps> |
229 | | - Sqrt, |
230 | | - /// Approximation of 1/x |
231 | | - /// |
232 | | - /// <https://www.felixcloutier.com/x86/rcpss> |
233 | | - /// <https://www.felixcloutier.com/x86/rcpps> |
234 | | - Rcp, |
235 | | - /// Approximation of 1/sqrt(x) |
236 | | - /// |
237 | | - /// <https://www.felixcloutier.com/x86/rsqrtss> |
238 | | - /// <https://www.felixcloutier.com/x86/rsqrtps> |
239 | | - Rsqrt, |
240 | | -} |
241 | | - |
242 | | -/// Performs `which` scalar operation on `op` and returns the result. |
243 | | -#[allow(clippy::arithmetic_side_effects)] // floating point operations without side effects |
244 | | -fn unary_op_f32<'tcx>( |
245 | | - this: &mut crate::MiriInterpCx<'_, 'tcx>, |
246 | | - which: FloatUnaryOp, |
247 | | - op: &ImmTy<'tcx, Provenance>, |
248 | | -) -> InterpResult<'tcx, Scalar<Provenance>> { |
249 | | - match which { |
250 | | - FloatUnaryOp::Sqrt => { |
251 | | - let op = op.to_scalar(); |
252 | | - // FIXME using host floats |
253 | | - Ok(Scalar::from_u32(f32::from_bits(op.to_u32()?).sqrt().to_bits())) |
254 | | - } |
255 | | - FloatUnaryOp::Rcp => { |
256 | | - let op = op.to_scalar().to_f32()?; |
257 | | - let div = (Single::from_u128(1).value / op).value; |
258 | | - // Apply a relative error with a magnitude on the order of 2^-12 to simulate the |
259 | | - // inaccuracy of RCP. |
260 | | - let res = apply_random_float_error(this, div, -12); |
261 | | - Ok(Scalar::from_f32(res)) |
262 | | - } |
263 | | - FloatUnaryOp::Rsqrt => { |
264 | | - let op = op.to_scalar().to_u32()?; |
265 | | - // FIXME using host floats |
266 | | - let sqrt = Single::from_bits(f32::from_bits(op).sqrt().to_bits().into()); |
267 | | - let rsqrt = (Single::from_u128(1).value / sqrt).value; |
268 | | - // Apply a relative error with a magnitude on the order of 2^-12 to simulate the |
269 | | - // inaccuracy of RSQRT. |
270 | | - let res = apply_random_float_error(this, rsqrt, -12); |
271 | | - Ok(Scalar::from_f32(res)) |
272 | | - } |
273 | | - } |
274 | | -} |
275 | | - |
276 | | -/// Disturbes a floating-point result by a relative error on the order of (-2^scale, 2^scale). |
277 | | -#[allow(clippy::arithmetic_side_effects)] // floating point arithmetic cannot panic |
278 | | -fn apply_random_float_error<F: rustc_apfloat::Float>( |
279 | | - this: &mut crate::MiriInterpCx<'_, '_>, |
280 | | - val: F, |
281 | | - err_scale: i32, |
282 | | -) -> F { |
283 | | - let rng = this.machine.rng.get_mut(); |
284 | | - // generates rand(0, 2^64) * 2^(scale - 64) = rand(0, 1) * 2^scale |
285 | | - let err = |
286 | | - F::from_u128(rng.gen::<u64>().into()).value.scalbn(err_scale.checked_sub(64).unwrap()); |
287 | | - // give it a random sign |
288 | | - let err = if rng.gen::<bool>() { -err } else { err }; |
289 | | - // multiple the value with (1+err) |
290 | | - (val * (F::from_u128(1).value + err).value).value |
291 | | -} |
292 | | - |
293 | | -/// Performs `which` operation on the first component of `op` and copies |
294 | | -/// the other components. The result is stored in `dest`. |
295 | | -fn unary_op_ss<'tcx>( |
296 | | - this: &mut crate::MiriInterpCx<'_, 'tcx>, |
297 | | - which: FloatUnaryOp, |
298 | | - op: &OpTy<'tcx, Provenance>, |
299 | | - dest: &PlaceTy<'tcx, Provenance>, |
300 | | -) -> InterpResult<'tcx, ()> { |
301 | | - let (op, op_len) = this.operand_to_simd(op)?; |
302 | | - let (dest, dest_len) = this.place_to_simd(dest)?; |
303 | | - |
304 | | - assert_eq!(dest_len, op_len); |
305 | | - |
306 | | - let res0 = unary_op_f32(this, which, &this.read_immediate(&this.project_index(&op, 0)?)?)?; |
307 | | - this.write_scalar(res0, &this.project_index(&dest, 0)?)?; |
308 | | - |
309 | | - for i in 1..dest_len { |
310 | | - this.copy_op( |
311 | | - &this.project_index(&op, i)?, |
312 | | - &this.project_index(&dest, i)?, |
313 | | - /*allow_transmute*/ false, |
314 | | - )?; |
315 | | - } |
316 | | - |
317 | | - Ok(()) |
318 | | -} |
319 | | - |
320 | | -/// Performs `which` operation on each component of `op`, storing the |
321 | | -/// result is stored in `dest`. |
322 | | -fn unary_op_ps<'tcx>( |
323 | | - this: &mut crate::MiriInterpCx<'_, 'tcx>, |
324 | | - which: FloatUnaryOp, |
325 | | - op: &OpTy<'tcx, Provenance>, |
326 | | - dest: &PlaceTy<'tcx, Provenance>, |
327 | | -) -> InterpResult<'tcx, ()> { |
328 | | - let (op, op_len) = this.operand_to_simd(op)?; |
329 | | - let (dest, dest_len) = this.place_to_simd(dest)?; |
330 | | - |
331 | | - assert_eq!(dest_len, op_len); |
332 | | - |
333 | | - for i in 0..dest_len { |
334 | | - let op = this.read_immediate(&this.project_index(&op, i)?)?; |
335 | | - let dest = this.project_index(&dest, i)?; |
336 | | - |
337 | | - let res = unary_op_f32(this, which, &op)?; |
338 | | - this.write_scalar(res, &dest)?; |
339 | | - } |
340 | | - |
341 | | - Ok(()) |
342 | | -} |
0 commit comments