Implement fptoint_sat for f16 and f128
This commit is contained in:
parent
c2b8abd810
commit
458adbd66a
2 changed files with 23 additions and 14 deletions
|
|
@ -1873,32 +1873,33 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
||||||
// On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because
|
// On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because
|
||||||
// we're rounding towards zero, we just get float_ty::MAX (which is always an integer).
|
// we're rounding towards zero, we just get float_ty::MAX (which is always an integer).
|
||||||
// This already happens today with u128::MAX = 2^128 - 1 > f32::MAX.
|
// This already happens today with u128::MAX = 2^128 - 1 > f32::MAX.
|
||||||
let int_max = |signed: bool, int_width: u64| -> u128 {
|
fn int_max(signed: bool, int_width: u64) -> u128 {
|
||||||
let shift_amount = 128 - int_width;
|
let shift_amount = 128 - int_width;
|
||||||
if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount }
|
if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount }
|
||||||
};
|
}
|
||||||
let int_min = |signed: bool, int_width: u64| -> i128 {
|
fn int_min(signed: bool, int_width: u64) -> i128 {
|
||||||
if signed { i128::MIN >> (128 - int_width) } else { 0 }
|
if signed { i128::MIN >> (128 - int_width) } else { 0 }
|
||||||
};
|
}
|
||||||
|
|
||||||
let compute_clamp_bounds_single = |signed: bool, int_width: u64| -> (u128, u128) {
|
// TODO: rewrite using a generic function with <F: Float>.
|
||||||
|
let compute_clamp_bounds_half = |signed: bool, int_width: u64| -> (u128, u128) {
|
||||||
let rounded_min =
|
let rounded_min =
|
||||||
ieee::Single::from_i128_r(int_min(signed, int_width), Round::TowardZero);
|
ieee::Half::from_i128_r(int_min(signed, int_width), Round::TowardZero);
|
||||||
assert_eq!(rounded_min.status, Status::OK);
|
//assert_eq!(rounded_min.status, Status::OK);
|
||||||
let rounded_max =
|
let rounded_max =
|
||||||
ieee::Single::from_u128_r(int_max(signed, int_width), Round::TowardZero);
|
ieee::Half::from_u128_r(int_max(signed, int_width), Round::TowardZero);
|
||||||
assert!(rounded_max.value.is_finite());
|
assert!(rounded_max.value.is_finite());
|
||||||
(rounded_min.value.to_bits(), rounded_max.value.to_bits())
|
(rounded_min.value.to_bits(), rounded_max.value.to_bits())
|
||||||
};
|
};
|
||||||
let compute_clamp_bounds_double = |signed: bool, int_width: u64| -> (u128, u128) {
|
fn compute_clamp_bounds<F: Float>(signed: bool, int_width: u64) -> (u128, u128) {
|
||||||
let rounded_min =
|
let rounded_min =
|
||||||
ieee::Double::from_i128_r(int_min(signed, int_width), Round::TowardZero);
|
F::from_i128_r(int_min(signed, int_width), Round::TowardZero);
|
||||||
assert_eq!(rounded_min.status, Status::OK);
|
assert_eq!(rounded_min.status, Status::OK);
|
||||||
let rounded_max =
|
let rounded_max =
|
||||||
ieee::Double::from_u128_r(int_max(signed, int_width), Round::TowardZero);
|
F::from_u128_r(int_max(signed, int_width), Round::TowardZero);
|
||||||
assert!(rounded_max.value.is_finite());
|
assert!(rounded_max.value.is_finite());
|
||||||
(rounded_min.value.to_bits(), rounded_max.value.to_bits())
|
(rounded_min.value.to_bits(), rounded_max.value.to_bits())
|
||||||
};
|
}
|
||||||
// To implement saturation, we perform the following steps:
|
// To implement saturation, we perform the following steps:
|
||||||
//
|
//
|
||||||
// 1. Cast val to an integer with fpto[su]i. This may result in undef.
|
// 1. Cast val to an integer with fpto[su]i. This may result in undef.
|
||||||
|
|
@ -1928,15 +1929,19 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
||||||
|
|
||||||
let float_bits_to_llval = |bx: &mut Self, bits| {
|
let float_bits_to_llval = |bx: &mut Self, bits| {
|
||||||
let bits_llval = match float_width {
|
let bits_llval = match float_width {
|
||||||
|
16 => bx.cx().const_u16(bits as u16),
|
||||||
32 => bx.cx().const_u32(bits as u32),
|
32 => bx.cx().const_u32(bits as u32),
|
||||||
64 => bx.cx().const_u64(bits as u64),
|
64 => bx.cx().const_u64(bits as u64),
|
||||||
|
128 => bx.cx().const_u128(bits),
|
||||||
n => bug!("unsupported float width {}", n),
|
n => bug!("unsupported float width {}", n),
|
||||||
};
|
};
|
||||||
bx.bitcast(bits_llval, float_ty)
|
bx.bitcast(bits_llval, float_ty)
|
||||||
};
|
};
|
||||||
let (f_min, f_max) = match float_width {
|
let (f_min, f_max) = match float_width {
|
||||||
32 => compute_clamp_bounds_single(signed, int_width),
|
16 => compute_clamp_bounds_half(signed, int_width),
|
||||||
64 => compute_clamp_bounds_double(signed, int_width),
|
32 => compute_clamp_bounds::<ieee::Single>(signed, int_width),
|
||||||
|
64 => compute_clamp_bounds::<ieee::Double>(signed, int_width),
|
||||||
|
128 => compute_clamp_bounds::<ieee::Quad>(signed, int_width),
|
||||||
n => bug!("unsupported float width {}", n),
|
n => bug!("unsupported float width {}", n),
|
||||||
};
|
};
|
||||||
let f_min = float_bits_to_llval(self, f_min);
|
let f_min = float_bits_to_llval(self, f_min);
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
||||||
bytes_in_context(self, bytes)
|
bytes_in_context(self, bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn const_u16(&self, i: u16) -> RValue<'gcc> {
|
||||||
|
self.const_uint(self.type_u16(), i as u64)
|
||||||
|
}
|
||||||
|
|
||||||
fn global_string(&self, string: &str) -> LValue<'gcc> {
|
fn global_string(&self, string: &str) -> LValue<'gcc> {
|
||||||
// TODO(antoyo): handle non-null-terminated strings.
|
// TODO(antoyo): handle non-null-terminated strings.
|
||||||
let string = self.context.new_string_literal(string);
|
let string = self.context.new_string_literal(string);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue