Extract (f32::MAX + 0.5 ULP) constant
This commit is contained in:
parent
964ba2a6e7
commit
e999e7b8b2
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user