@@ -1029,23 +1029,39 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
10291029 ret. write_cvalue( fx, old) ;
10301030 } ;
10311031
1032+ // In Rust floating point min and max don't propagate NaN. In Cranelift they do however.
1033+ // For this reason it is necessary to use `a.is_nan() ? b : (a >= b ? b : a)` for `minnumf*`
1034+ // and `a.is_nan() ? b : (a <= b ? b : a)` for `maxnumf*`. NaN checks are done by comparing
1035+ // a float against itself. Only in case of NaN is it not equal to itself.
10321036 minnumf32, ( v a, v b) {
1033- let val = fx. bcx. ins( ) . fmin( a, b) ;
1037+ let a_is_nan = fx. bcx. ins( ) . fcmp( FloatCC :: NotEqual , a, a) ;
1038+ let a_ge_b = fx. bcx. ins( ) . fcmp( FloatCC :: GreaterThanOrEqual , a, b) ;
1039+ let temp = fx. bcx. ins( ) . select( a_ge_b, b, a) ;
1040+ let val = fx. bcx. ins( ) . select( a_is_nan, b, temp) ;
10341041 let val = CValue :: by_val( val, fx. layout_of( fx. tcx. types. f32 ) ) ;
10351042 ret. write_cvalue( fx, val) ;
10361043 } ;
10371044 minnumf64, ( v a, v b) {
1038- let val = fx. bcx. ins( ) . fmin( a, b) ;
1045+ let a_is_nan = fx. bcx. ins( ) . fcmp( FloatCC :: NotEqual , a, a) ;
1046+ let a_ge_b = fx. bcx. ins( ) . fcmp( FloatCC :: GreaterThanOrEqual , a, b) ;
1047+ let temp = fx. bcx. ins( ) . select( a_ge_b, b, a) ;
1048+ let val = fx. bcx. ins( ) . select( a_is_nan, b, temp) ;
10391049 let val = CValue :: by_val( val, fx. layout_of( fx. tcx. types. f64 ) ) ;
10401050 ret. write_cvalue( fx, val) ;
10411051 } ;
10421052 maxnumf32, ( v a, v b) {
1043- let val = fx. bcx. ins( ) . fmax( a, b) ;
1053+ let a_is_nan = fx. bcx. ins( ) . fcmp( FloatCC :: NotEqual , a, a) ;
1054+ let a_le_b = fx. bcx. ins( ) . fcmp( FloatCC :: LessThanOrEqual , a, b) ;
1055+ let temp = fx. bcx. ins( ) . select( a_le_b, b, a) ;
1056+ let val = fx. bcx. ins( ) . select( a_is_nan, b, temp) ;
10441057 let val = CValue :: by_val( val, fx. layout_of( fx. tcx. types. f32 ) ) ;
10451058 ret. write_cvalue( fx, val) ;
10461059 } ;
10471060 maxnumf64, ( v a, v b) {
1048- let val = fx. bcx. ins( ) . fmax( a, b) ;
1061+ let a_is_nan = fx. bcx. ins( ) . fcmp( FloatCC :: NotEqual , a, a) ;
1062+ let a_le_b = fx. bcx. ins( ) . fcmp( FloatCC :: LessThanOrEqual , a, b) ;
1063+ let temp = fx. bcx. ins( ) . select( a_le_b, b, a) ;
1064+ let val = fx. bcx. ins( ) . select( a_is_nan, b, temp) ;
10491065 let val = CValue :: by_val( val, fx. layout_of( fx. tcx. types. f64 ) ) ;
10501066 ret. write_cvalue( fx, val) ;
10511067 } ;
0 commit comments