Skip to content

Commit c37f4d6

Browse files
committed
Move unary_op_* functions from shims::x86::sse module to shims::x86
1 parent f7af14b commit c37f4d6

File tree

2 files changed

+129
-125
lines changed

2 files changed

+129
-125
lines changed

src/tools/miri/src/shims/x86/mod.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
use rand::Rng as _;
2+
3+
use rustc_apfloat::{ieee::Single, Float as _};
14
use rustc_middle::{mir, ty};
25
use rustc_span::Symbol;
36
use rustc_target::abi::Size;
@@ -331,6 +334,127 @@ fn bin_op_simd_float_all<'tcx, F: rustc_apfloat::Float>(
331334
Ok(())
332335
}
333336

337+
#[derive(Copy, Clone)]
338+
enum FloatUnaryOp {
339+
/// sqrt(x)
340+
///
341+
/// <https://www.felixcloutier.com/x86/sqrtss>
342+
/// <https://www.felixcloutier.com/x86/sqrtps>
343+
Sqrt,
344+
/// Approximation of 1/x
345+
///
346+
/// <https://www.felixcloutier.com/x86/rcpss>
347+
/// <https://www.felixcloutier.com/x86/rcpps>
348+
Rcp,
349+
/// Approximation of 1/sqrt(x)
350+
///
351+
/// <https://www.felixcloutier.com/x86/rsqrtss>
352+
/// <https://www.felixcloutier.com/x86/rsqrtps>
353+
Rsqrt,
354+
}
355+
356+
/// Performs `which` scalar operation on `op` and returns the result.
357+
#[allow(clippy::arithmetic_side_effects)] // floating point operations without side effects
358+
fn unary_op_f32<'tcx>(
359+
this: &mut crate::MiriInterpCx<'_, 'tcx>,
360+
which: FloatUnaryOp,
361+
op: &ImmTy<'tcx, Provenance>,
362+
) -> InterpResult<'tcx, Scalar<Provenance>> {
363+
match which {
364+
FloatUnaryOp::Sqrt => {
365+
let op = op.to_scalar();
366+
// FIXME using host floats
367+
Ok(Scalar::from_u32(f32::from_bits(op.to_u32()?).sqrt().to_bits()))
368+
}
369+
FloatUnaryOp::Rcp => {
370+
let op = op.to_scalar().to_f32()?;
371+
let div = (Single::from_u128(1).value / op).value;
372+
// Apply a relative error with a magnitude on the order of 2^-12 to simulate the
373+
// inaccuracy of RCP.
374+
let res = apply_random_float_error(this, div, -12);
375+
Ok(Scalar::from_f32(res))
376+
}
377+
FloatUnaryOp::Rsqrt => {
378+
let op = op.to_scalar().to_u32()?;
379+
// FIXME using host floats
380+
let sqrt = Single::from_bits(f32::from_bits(op).sqrt().to_bits().into());
381+
let rsqrt = (Single::from_u128(1).value / sqrt).value;
382+
// Apply a relative error with a magnitude on the order of 2^-12 to simulate the
383+
// inaccuracy of RSQRT.
384+
let res = apply_random_float_error(this, rsqrt, -12);
385+
Ok(Scalar::from_f32(res))
386+
}
387+
}
388+
}
389+
390+
/// Disturbes a floating-point result by a relative error on the order of (-2^scale, 2^scale).
391+
#[allow(clippy::arithmetic_side_effects)] // floating point arithmetic cannot panic
392+
fn apply_random_float_error<F: rustc_apfloat::Float>(
393+
this: &mut crate::MiriInterpCx<'_, '_>,
394+
val: F,
395+
err_scale: i32,
396+
) -> F {
397+
let rng = this.machine.rng.get_mut();
398+
// generates rand(0, 2^64) * 2^(scale - 64) = rand(0, 1) * 2^scale
399+
let err =
400+
F::from_u128(rng.gen::<u64>().into()).value.scalbn(err_scale.checked_sub(64).unwrap());
401+
// give it a random sign
402+
let err = if rng.gen::<bool>() { -err } else { err };
403+
// multiple the value with (1+err)
404+
(val * (F::from_u128(1).value + err).value).value
405+
}
406+
407+
/// Performs `which` operation on the first component of `op` and copies
408+
/// the other components. The result is stored in `dest`.
409+
fn unary_op_ss<'tcx>(
410+
this: &mut crate::MiriInterpCx<'_, 'tcx>,
411+
which: FloatUnaryOp,
412+
op: &OpTy<'tcx, Provenance>,
413+
dest: &PlaceTy<'tcx, Provenance>,
414+
) -> InterpResult<'tcx, ()> {
415+
let (op, op_len) = this.operand_to_simd(op)?;
416+
let (dest, dest_len) = this.place_to_simd(dest)?;
417+
418+
assert_eq!(dest_len, op_len);
419+
420+
let res0 = unary_op_f32(this, which, &this.read_immediate(&this.project_index(&op, 0)?)?)?;
421+
this.write_scalar(res0, &this.project_index(&dest, 0)?)?;
422+
423+
for i in 1..dest_len {
424+
this.copy_op(
425+
&this.project_index(&op, i)?,
426+
&this.project_index(&dest, i)?,
427+
/*allow_transmute*/ false,
428+
)?;
429+
}
430+
431+
Ok(())
432+
}
433+
434+
/// Performs `which` operation on each component of `op`, storing the
435+
/// result is stored in `dest`.
436+
fn unary_op_ps<'tcx>(
437+
this: &mut crate::MiriInterpCx<'_, 'tcx>,
438+
which: FloatUnaryOp,
439+
op: &OpTy<'tcx, Provenance>,
440+
dest: &PlaceTy<'tcx, Provenance>,
441+
) -> InterpResult<'tcx, ()> {
442+
let (op, op_len) = this.operand_to_simd(op)?;
443+
let (dest, dest_len) = this.place_to_simd(dest)?;
444+
445+
assert_eq!(dest_len, op_len);
446+
447+
for i in 0..dest_len {
448+
let op = this.read_immediate(&this.project_index(&op, i)?)?;
449+
let dest = this.project_index(&dest, i)?;
450+
451+
let res = unary_op_f32(this, which, &op)?;
452+
this.write_scalar(res, &dest)?;
453+
}
454+
455+
Ok(())
456+
}
457+
334458
/// Converts each element of `op` from floating point to signed integer.
335459
///
336460
/// When the input value is NaN or out of range, fall back to minimum value.

src/tools/miri/src/shims/x86/sse.rs

Lines changed: 5 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
use rustc_apfloat::{ieee::Single, Float as _};
1+
use rustc_apfloat::ieee::Single;
22
use rustc_middle::mir;
33
use rustc_span::Symbol;
44
use rustc_target::spec::abi::Abi;
55

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+
};
910
use crate::*;
1011
use shims::foreign_items::EmulateForeignItemResult;
1112

@@ -219,124 +220,3 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
219220
Ok(EmulateForeignItemResult::NeedsJumping)
220221
}
221222
}
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

Comments
 (0)