about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRobin Kruppe <robin.kruppe@gmail.com>2017-10-15 21:37:09 +0200
committerRobin Kruppe <robin.kruppe@gmail.com>2017-11-07 20:13:19 +0100
commite999e7b8b2e35a495d6b9630ab987c0703c6ab48 (patch)
tree06b54716db8a56a305e9a83f20fb2e21ef3022f5
parent964ba2a6e731f79d99248d1f0e67eac17e69e368 (diff)
downloadrust-e999e7b8b2e35a495d6b9630ab987c0703c6ab48.tar.gz
rust-e999e7b8b2e35a495d6b9630ab987c0703c6ab48.zip
Extract (f32::MAX + 0.5 ULP) constant
-rw-r--r--src/librustc_const_math/float.rs8
-rw-r--r--src/librustc_trans/mir/constant.rs6
-rw-r--r--src/librustc_trans/mir/rvalue.rs7
3 files changed, 15 insertions, 6 deletions
diff --git a/src/librustc_const_math/float.rs b/src/librustc_const_math/float.rs
index b67048939e4..9d820ea8cbe 100644
--- a/src/librustc_const_math/float.rs
+++ b/src/librustc_const_math/float.rs
@@ -203,3 +203,11 @@ impl ::std::ops::Neg for ConstFloat {
         ConstFloat { bits, ty: self.ty }
     }
 }
+
+/// This is `f32::MAX + (0.5 ULP)` as an integer. Numbers greater or equal to this
+/// are rounded to infinity when converted to `f32`.
+///
+/// NB: Computed as maximum significand with an extra 1 bit added (for the half ULP)
+/// shifted by the maximum exponent (accounting for normalization).
+pub const MAX_F32_PLUS_HALF_ULP: u128 = ((1 << (Single::PRECISION + 1)) - 1)
+                                        << (Single::MAX_EXP - Single::PRECISION as i16);
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 7fff68abbbe..6b2342e4933 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -11,7 +11,7 @@
 use llvm::{self, ValueRef};
 use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind};
 use rustc_const_math::ConstInt::*;
-use rustc_const_math::{ConstInt, ConstMathErr};
+use rustc_const_math::{ConstInt, ConstMathErr, MAX_F32_PLUS_HALF_ULP};
 use rustc::hir::def_id::DefId;
 use rustc::infer::TransNormalize;
 use rustc::traits;
@@ -986,10 +986,10 @@ unsafe fn const_cast_int_to_float(ccx: &CrateContext,
         panic!("could not get z128 value of constant integer {:?}",
                Value(llval));
     });
-    // If this is an u128 cast and the value is > f32::MAX + 0.5 ULP, round up to infinity.
     if signed {
         llvm::LLVMConstSIToFP(llval, float_ty.to_ref())
-    } else if value >= 0xffffff80000000000000000000000000_u128 && float_ty.float_width() == 32 {
+    } else if float_ty.float_width() == 32 && value >= MAX_F32_PLUS_HALF_ULP {
+        // We're casting to f32 and the value is > f32::MAX + 0.5 ULP -> round up to infinity.
         let infinity_bits = C_u32(ccx, ieee::Single::INFINITY.to_bits() as u32);
         consts::bitcast(infinity_bits, float_ty)
     } else {
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index 1986689c77b..d16b2048c3f 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -16,6 +16,7 @@ use rustc::mir::tcx::LvalueTy;
 use rustc::mir;
 use rustc::middle::lang_items::ExchangeMallocFnLangItem;
 use rustc_apfloat::{ieee, Float, Status, Round};
+use rustc_const_math::MAX_F32_PLUS_HALF_ULP;
 use std::{u128, i128};
 
 use base;
@@ -827,9 +828,9 @@ fn cast_int_to_float(bcx: &Builder,
     // LLVM's uitofp produces undef in those cases, so we manually check for that case.
     let is_u128_to_f32 = !signed && int_ty.int_width() == 128 && float_ty.float_width() == 32;
     if is_u128_to_f32 && bcx.sess().opts.debugging_opts.saturating_float_casts {
-        // f32::MAX + 0.5 ULP as u128. All inputs greater or equal to this should be
-        // rounded to infinity, for everything else LLVM's uitofp works just fine.
-        let max = C_big_integral(int_ty, 0xffffff80000000000000000000000000_u128);
+        // All inputs greater or equal to (f32::MAX + 0.5 ULP) are rounded to infinity,
+        // and for everything else LLVM's uitofp works just fine.
+        let max = C_big_integral(int_ty, MAX_F32_PLUS_HALF_ULP);
         let overflow = bcx.icmp(llvm::IntUGE, x, max);
         let infinity_bits = C_u32(bcx.ccx, ieee::Single::INFINITY.to_bits() as u32);
         let infinity = consts::bitcast(infinity_bits, float_ty);