From e999e7b8b2e35a495d6b9630ab987c0703c6ab48 Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Sun, 15 Oct 2017 21:37:09 +0200 Subject: [PATCH] Extract (f32::MAX + 0.5 ULP) constant --- src/librustc_const_math/float.rs | 8 ++++++++ src/librustc_trans/mir/constant.rs | 6 +++--- src/librustc_trans/mir/rvalue.rs | 7 ++++--- 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);