@@ -1029,23 +1029,39 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
1029
1029
ret. write_cvalue( fx, old) ;
1030
1030
} ;
1031
1031
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.
1032
1036
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) ;
1034
1041
let val = CValue :: by_val( val, fx. layout_of( fx. tcx. types. f32 ) ) ;
1035
1042
ret. write_cvalue( fx, val) ;
1036
1043
} ;
1037
1044
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) ;
1039
1049
let val = CValue :: by_val( val, fx. layout_of( fx. tcx. types. f64 ) ) ;
1040
1050
ret. write_cvalue( fx, val) ;
1041
1051
} ;
1042
1052
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) ;
1044
1057
let val = CValue :: by_val( val, fx. layout_of( fx. tcx. types. f32 ) ) ;
1045
1058
ret. write_cvalue( fx, val) ;
1046
1059
} ;
1047
1060
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) ;
1049
1065
let val = CValue :: by_val( val, fx. layout_of( fx. tcx. types. f64 ) ) ;
1050
1066
ret. write_cvalue( fx, val) ;
1051
1067
} ;
0 commit comments