Skip to content

Commit 7f05920

Browse files
authored
Merge pull request #627 from folkertdev/fix-unordered-compare
handle NaN in unordered comparisons
2 parents cb499a2 + c817210 commit 7f05920

File tree

3 files changed

+76
-2
lines changed

3 files changed

+76
-2
lines changed

Diff for: src/builder.rs

+44-1
Original file line numberDiff line numberDiff line change
@@ -1284,7 +1284,50 @@ 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+
let is_nan = self.context.new_binary_op(
1313+
self.location,
1314+
BinaryOp::LogicalOr,
1315+
self.cx.bool_type,
1316+
// compare a value to itself to check whether it is NaN
1317+
self.context.new_comparison(self.location, ComparisonOp::NotEquals, lhs, lhs),
1318+
self.context.new_comparison(self.location, ComparisonOp::NotEquals, rhs, rhs),
1319+
);
1320+
1321+
self.context.new_binary_op(
1322+
self.location,
1323+
BinaryOp::LogicalOr,
1324+
self.cx.bool_type,
1325+
is_nan,
1326+
cmp,
1327+
)
1328+
} else {
1329+
cmp
1330+
}
12881331
}
12891332

12901333
/* Miscellaneous instructions */

Diff for: tests/failing-ui-tests.txt

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ tests/ui/asm/x86_64/multiple-clobber-abi.rs
55
tests/ui/functions-closures/parallel-codegen-closures.rs
66
tests/ui/linkage-attr/linkage1.rs
77
tests/ui/lto/dylib-works.rs
8-
tests/ui/numbers-arithmetic/saturating-float-casts.rs
98
tests/ui/sepcomp/sepcomp-cci.rs
109
tests/ui/sepcomp/sepcomp-extern.rs
1110
tests/ui/sepcomp/sepcomp-fns-backwards.rs

Diff for: tests/run/float.rs

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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+
const EXPECTED: $ty = $expr;
18+
assert_eq!($expr, EXPECTED);
19+
}};
20+
}
21+
22+
check!(i32, (black_box(0.0f32) as i32));
23+
24+
check!(u64, (black_box(f32::NAN) as u64));
25+
check!(u128, (black_box(f32::NAN) as u128));
26+
27+
check!(i64, (black_box(f64::NAN) as i64));
28+
check!(u64, (black_box(f64::NAN) as u64));
29+
30+
check!(i16, (black_box(f32::MIN) as i16));
31+
check!(i16, (black_box(f32::MAX) as i16));
32+
}

0 commit comments

Comments
 (0)