diff options
| author | bjorn3 <bjorn3@users.noreply.github.com> | 2022-03-25 20:24:47 +0100 |
|---|---|---|
| committer | bjorn3 <bjorn3@users.noreply.github.com> | 2022-03-25 20:25:11 +0100 |
| commit | 3c030e2425bb1fdb165ac87797076072ec991970 (patch) | |
| tree | 886f139db21d2f436586812bf834f2d72b4a7185 /src/num.rs | |
| parent | f3d97cce279fd2372aafec3761791b4110d70bf5 (diff) | |
| download | rust-3c030e2425bb1fdb165ac87797076072ec991970.tar.gz rust-3c030e2425bb1fdb165ac87797076072ec991970.zip | |
Fix NaN handling of simd float min and max operations
Diffstat (limited to 'src/num.rs')
| -rw-r--r-- | src/num.rs | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/src/num.rs b/src/num.rs index 545d390e269..4ce8adb182e 100644 --- a/src/num.rs +++ b/src/num.rs @@ -420,3 +420,21 @@ pub(crate) fn codegen_ptr_binop<'tcx>( CValue::by_val(fx.bcx.ins().bint(types::I8, res), fx.layout_of(fx.tcx.types.bool)) } } + +// In Rust floating point min and max don't propagate NaN. In Cranelift they do however. +// For this reason it is necessary to use `a.is_nan() ? b : (a >= b ? b : a)` for `minnumf*` +// and `a.is_nan() ? b : (a <= b ? b : a)` for `maxnumf*`. NaN checks are done by comparing +// a float against itself. Only in case of NaN is it not equal to itself. +pub(crate) fn codegen_float_min(fx: &mut FunctionCx<'_, '_, '_>, a: Value, b: Value) -> Value { + let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a); + let a_ge_b = fx.bcx.ins().fcmp(FloatCC::GreaterThanOrEqual, a, b); + let temp = fx.bcx.ins().select(a_ge_b, b, a); + fx.bcx.ins().select(a_is_nan, b, temp) +} + +pub(crate) fn codegen_float_max(fx: &mut FunctionCx<'_, '_, '_>, a: Value, b: Value) -> Value { + let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a); + let a_le_b = fx.bcx.ins().fcmp(FloatCC::LessThanOrEqual, a, b); + let temp = fx.bcx.ins().select(a_le_b, b, a); + fx.bcx.ins().select(a_is_nan, b, temp) +} |
