Skip to content

Commit 61bcada

Browse files
committed
handle NaN in unordered comparisons
1 parent cb499a2 commit 61bcada

File tree

2 files changed

+78
-1
lines changed

2 files changed

+78
-1
lines changed

src/builder.rs

+47-1
Original file line numberDiff line numberDiff line change
@@ -1284,7 +1284,53 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
12841284
}
12851285

12861286
fn fcmp(&mut self, op: RealPredicate, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> {
1287-
self.context.new_comparison(self.location, op.to_gcc_comparison(), lhs, rhs)
1287+
// LLVM has a concept of "unordered compares", where eg ULT returns true if either the two
1288+
// arguments are unordered (i.e. either is NaN), or the lhs is less than the rhs. GCC does
1289+
// not natively have this concept, so in some cases we must manually handle NaNs
1290+
let must_handle_nan = match op {
1291+
RealPredicate::RealPredicateFalse => unreachable!(),
1292+
RealPredicate::RealOEQ => false,
1293+
RealPredicate::RealOGT => false,
1294+
RealPredicate::RealOGE => false,
1295+
RealPredicate::RealOLT => false,
1296+
RealPredicate::RealOLE => false,
1297+
RealPredicate::RealONE => false,
1298+
RealPredicate::RealORD => unreachable!(),
1299+
RealPredicate::RealUNO => unreachable!(),
1300+
RealPredicate::RealUEQ => false,
1301+
RealPredicate::RealUGT => true,
1302+
RealPredicate::RealUGE => true,
1303+
RealPredicate::RealULT => true,
1304+
RealPredicate::RealULE => true,
1305+
RealPredicate::RealUNE => false,
1306+
RealPredicate::RealPredicateTrue => unreachable!(),
1307+
};
1308+
1309+
let cmp = self.context.new_comparison(self.location, op.to_gcc_comparison(), lhs, rhs);
1310+
1311+
if must_handle_nan {
1312+
// compare a value to itself to check whether it is NaN
1313+
let is_nan_lhs = self.fcmp(RealPredicate::RealONE, lhs, lhs);
1314+
let is_nan_rhs = self.fcmp(RealPredicate::RealONE, rhs, rhs);
1315+
1316+
let is_nan = self.context.new_binary_op(
1317+
self.location,
1318+
BinaryOp::LogicalOr,
1319+
self.cx.bool_type,
1320+
is_nan_lhs,
1321+
is_nan_rhs,
1322+
);
1323+
1324+
self.context.new_binary_op(
1325+
self.location,
1326+
BinaryOp::LogicalOr,
1327+
self.cx.bool_type,
1328+
is_nan,
1329+
cmp,
1330+
)
1331+
} else {
1332+
cmp
1333+
}
12881334
}
12891335

12901336
/* Miscellaneous instructions */

tests/run/float.rs

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Compiler:
2+
//
3+
// Run-time:
4+
// status: 0
5+
6+
#![feature(const_black_box)]
7+
8+
/*
9+
* Code
10+
*/
11+
12+
fn main() {
13+
use std::hint::black_box;
14+
15+
macro_rules! check {
16+
($ty:ty, $expr:expr) => {
17+
{
18+
const EXPECTED: $ty = $expr;
19+
assert_eq!($expr, EXPECTED);
20+
}
21+
};
22+
}
23+
24+
check!(i32, (black_box(0.0f32) as i32));
25+
26+
check!(i64, (black_box(f64::NAN) as i64));
27+
check!(u64, (black_box(f64::NAN) as u64));
28+
29+
check!(i16, (black_box(f32::MIN) as i16));
30+
check!(i16, (black_box(f32::MAX) as i16));
31+
}

0 commit comments

Comments
 (0)