diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/intrinsics/mod.rs | 24 | ||||
| -rw-r--r-- | src/intrinsics/simd.rs | 8 | ||||
| -rw-r--r-- | src/num.rs | 18 |
3 files changed, 26 insertions, 24 deletions
diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index 310d27c6dec..d76dfca7960 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -1019,39 +1019,23 @@ fn codegen_regular_intrinsic_call<'tcx>( ret.write_cvalue(fx, old); }; - // 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. minnumf32, (v a, v b) { - 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); - let val = fx.bcx.ins().select(a_is_nan, b, temp); + let val = crate::num::codegen_float_min(fx, a, b); let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32)); ret.write_cvalue(fx, val); }; minnumf64, (v a, v b) { - 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); - let val = fx.bcx.ins().select(a_is_nan, b, temp); + let val = crate::num::codegen_float_min(fx, a, b); let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64)); ret.write_cvalue(fx, val); }; maxnumf32, (v a, v b) { - 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); - let val = fx.bcx.ins().select(a_is_nan, b, temp); + let val = crate::num::codegen_float_max(fx, a, b); let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32)); ret.write_cvalue(fx, val); }; maxnumf64, (v a, v b) { - 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); - let val = fx.bcx.ins().select(a_is_nan, b, temp); + let val = crate::num::codegen_float_max(fx, a, b); let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64)); ret.write_cvalue(fx, val); }; diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index bc21d736166..25755f8c7ec 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -354,8 +354,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( _ => unreachable!("{:?}", lane_ty), } match intrinsic { - sym::simd_fmin => fx.bcx.ins().fmin(x_lane, y_lane), - sym::simd_fmax => fx.bcx.ins().fmax(x_lane, y_lane), + sym::simd_fmin => crate::num::codegen_float_min(fx, x_lane, y_lane), + sym::simd_fmax => crate::num::codegen_float_max(fx, x_lane, y_lane), _ => unreachable!(), } }); @@ -495,7 +495,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let lt = match ty.kind() { ty::Int(_) => fx.bcx.ins().icmp(IntCC::SignedLessThan, a, b), ty::Uint(_) => fx.bcx.ins().icmp(IntCC::UnsignedLessThan, a, b), - ty::Float(_) => fx.bcx.ins().fcmp(FloatCC::LessThan, a, b), + ty::Float(_) => return crate::num::codegen_float_min(fx, a, b), _ => unreachable!(), }; fx.bcx.ins().select(lt, a, b) @@ -512,7 +512,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let gt = match ty.kind() { ty::Int(_) => fx.bcx.ins().icmp(IntCC::SignedGreaterThan, a, b), ty::Uint(_) => fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, a, b), - ty::Float(_) => fx.bcx.ins().fcmp(FloatCC::GreaterThan, a, b), + ty::Float(_) => return crate::num::codegen_float_max(fx, a, b), _ => unreachable!(), }; fx.bcx.ins().select(gt, a, b) 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) +} |
