Avoid using floating-point values in expand_fcvt_to_sint.
Compute the bound values for expand_fcvt_to_sint using bitwise integer arithmetic rather than floating-point arithmetic, to avoid relying on host floating point arithmetic.
This commit is contained in:
@@ -538,6 +538,17 @@ impl Ieee32 {
|
||||
Ieee32(exponent << t)
|
||||
}
|
||||
|
||||
/// Create an `Ieee32` number representing the greatest negative value
|
||||
/// not convertable from f32 to a signed integer with width n.
|
||||
pub fn fcvt_to_sint_negative_overflow<I: Into<i32>>(n: I) -> Ieee32 {
|
||||
let n = n.into();
|
||||
debug_assert!(n < 32);
|
||||
debug_assert!(23 + 1 - n < 32);
|
||||
Self::with_bits(
|
||||
(1u32 << (32 - 1)) | Self::pow2(n - 1).0 | (1u32 << (23 + 1 - n)),
|
||||
)
|
||||
}
|
||||
|
||||
/// Return self negated.
|
||||
pub fn neg(self) -> Ieee32 {
|
||||
Ieee32(self.0 ^ (1 << 31))
|
||||
@@ -590,6 +601,17 @@ impl Ieee64 {
|
||||
Ieee64(exponent << t)
|
||||
}
|
||||
|
||||
/// Create an `Ieee64` number representing the greatest negative value
|
||||
/// not convertable from f64 to a signed integer with width n.
|
||||
pub fn fcvt_to_sint_negative_overflow<I: Into<i64>>(n: I) -> Ieee64 {
|
||||
let n = n.into();
|
||||
debug_assert!(n < 64);
|
||||
debug_assert!(52 + 1 - n < 64);
|
||||
Self::with_bits(
|
||||
(1u64 << (64 - 1)) | Self::pow2(n - 1).0 | (1u64 << (52 + 1 - n)),
|
||||
)
|
||||
}
|
||||
|
||||
/// Return self negated.
|
||||
pub fn neg(self) -> Ieee64 {
|
||||
Ieee64(self.0 ^ (1 << 63))
|
||||
@@ -857,6 +879,15 @@ mod tests {
|
||||
assert_eq!(Ieee32::pow2(1).neg().to_string(), "-0x1.000000p1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fcvt_to_sint_negative_overflow_ieee32() {
|
||||
for n in &[8, 16] {
|
||||
assert_eq!(-((1u32 << (n - 1)) as f32) - 1.0, unsafe {
|
||||
mem::transmute(Ieee32::fcvt_to_sint_negative_overflow(*n))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_ieee64() {
|
||||
assert_eq!(Ieee64::with_float(0.0).to_string(), "0.0");
|
||||
@@ -985,4 +1016,13 @@ mod tests {
|
||||
|
||||
assert_eq!(Ieee64::pow2(1).neg().to_string(), "-0x1.0000000000000p1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fcvt_to_sint_negative_overflow_ieee64() {
|
||||
for n in &[8, 16, 32] {
|
||||
assert_eq!(-((1u64 << (n - 1)) as f64) - 1.0, unsafe {
|
||||
mem::transmute(Ieee64::fcvt_to_sint_negative_overflow(*n))
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,13 +376,22 @@ fn expand_fcvt_to_sint(
|
||||
let mut overflow_cc = FloatCC::LessThan;
|
||||
let output_bits = ty.lane_bits();
|
||||
let flimit = match xty {
|
||||
ir::types::F32 => pos.ins().f32const(Ieee32::pow2(output_bits - 1).neg()),
|
||||
// An f32 can represent `i16::min_value() - 1` exactly with precision to spare, so
|
||||
// there are values less than -2^(N-1) that convert correctly to INT_MIN.
|
||||
ir::types::F32 => {
|
||||
pos.ins().f32const(if output_bits < 32 {
|
||||
overflow_cc = FloatCC::LessThanOrEqual;
|
||||
Ieee32::fcvt_to_sint_negative_overflow(output_bits)
|
||||
} else {
|
||||
Ieee32::pow2(output_bits - 1).neg()
|
||||
})
|
||||
}
|
||||
ir::types::F64 => {
|
||||
// An f64 can represent `i32::min_value() - 1` exactly with precision to spare, so
|
||||
// there are values less than -2^(N-1) that convert correctly to INT_MIN.
|
||||
pos.ins().f64const(if output_bits < 64 {
|
||||
overflow_cc = FloatCC::LessThanOrEqual;
|
||||
Ieee64::with_float(-((1u64 << (output_bits - 1)) as f64) - 1.0)
|
||||
Ieee64::fcvt_to_sint_negative_overflow(output_bits)
|
||||
} else {
|
||||
Ieee64::pow2(output_bits - 1).neg()
|
||||
})
|
||||
@@ -394,8 +403,8 @@ fn expand_fcvt_to_sint(
|
||||
|
||||
// Finally, we could have a positive value that is too large.
|
||||
let fzero = match xty {
|
||||
ir::types::F32 => pos.ins().f32const(Ieee32::with_float(0.0)),
|
||||
ir::types::F64 => pos.ins().f64const(Ieee64::with_float(0.0)),
|
||||
ir::types::F32 => pos.ins().f32const(Ieee32::with_bits(0)),
|
||||
ir::types::F64 => pos.ins().f64const(Ieee64::with_bits(0)),
|
||||
_ => panic!("Can't convert {}", xty),
|
||||
};
|
||||
let overflow = pos.ins().fcmp(FloatCC::GreaterThanOrEqual, x, fzero);
|
||||
|
||||
Reference in New Issue
Block a user