Path: blob/main/cranelift/codegen/src/ir/immediates.rs
1693 views
//! Immediate operands for Cranelift instructions1//!2//! This module defines the types of immediate operands that can appear on Cranelift instructions.3//! Each type here should have a corresponding definition in the4//! `cranelift-codegen/meta/src/shared/immediates` crate in the meta language.56use alloc::vec::Vec;7use core::cmp::Ordering;8use core::fmt::{self, Display, Formatter};9use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Sub};10use core::str::FromStr;11use core::{i32, u32};12#[cfg(feature = "enable-serde")]13use serde_derive::{Deserialize, Serialize};1415/// Convert a type into a vector of bytes; all implementors in this file must use little-endian16/// orderings of bytes to match WebAssembly's little-endianness.17pub trait IntoBytes {18/// Return the little-endian byte representation of the implementing type.19fn into_bytes(self) -> Vec<u8>;20}2122impl IntoBytes for u8 {23fn into_bytes(self) -> Vec<u8> {24vec![self]25}26}2728impl IntoBytes for i8 {29fn into_bytes(self) -> Vec<u8> {30vec![self as u8]31}32}3334impl IntoBytes for i16 {35fn into_bytes(self) -> Vec<u8> {36self.to_le_bytes().to_vec()37}38}3940impl IntoBytes for i32 {41fn into_bytes(self) -> Vec<u8> {42self.to_le_bytes().to_vec()43}44}4546impl IntoBytes for Vec<u8> {47fn into_bytes(self) -> Vec<u8> {48self49}50}5152/// 64-bit immediate signed integer operand.53///54/// An `Imm64` operand can also be used to represent immediate values of smaller integer types by55/// sign-extending to `i64`.56#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]57#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]58pub struct Imm64(i64);5960impl Imm64 {61/// Create a new `Imm64` representing the signed number `x`.62pub fn new(x: i64) -> Self {63Self(x)64}6566/// Return self negated.67pub fn wrapping_neg(self) -> Self {68Self(self.0.wrapping_neg())69}7071/// Returns the value of this immediate.72pub fn bits(&self) -> i64 {73self.074}7576/// Mask this immediate to the given power-of-two bit width.77#[must_use]78pub(crate) fn mask_to_width(&self, bit_width: u32) -> Self {79debug_assert!(bit_width.is_power_of_two());8081if bit_width >= 64 {82return *self;83}8485let bit_width = i64::from(bit_width);86let mask = (1 << bit_width) - 1;87let masked = self.0 & mask;88Imm64(masked)89}9091/// Sign extend this immediate as if it were a signed integer of the given92/// power-of-two width.93#[must_use]94pub fn sign_extend_from_width(&self, bit_width: u32) -> Self {95debug_assert!(96bit_width.is_power_of_two(),97"{bit_width} is not a power of two"98);99100if bit_width >= 64 {101return *self;102}103104let bit_width = i64::from(bit_width);105let delta = 64 - bit_width;106let sign_extended = (self.0 << delta) >> delta;107Imm64(sign_extended)108}109110/// Zero extend this immediate as if it were an unsigned integer of the111/// given power-of-two width.112#[must_use]113pub fn zero_extend_from_width(&self, bit_width: u32) -> Self {114debug_assert!(115bit_width.is_power_of_two(),116"{bit_width} is not a power of two"117);118119if bit_width >= 64 {120return *self;121}122123let bit_width = u64::from(bit_width);124let delta = 64 - bit_width;125let zero_extended = (self.0.cast_unsigned() << delta) >> delta;126Imm64(zero_extended.cast_signed())127}128}129130impl From<Imm64> for i64 {131fn from(val: Imm64) -> i64 {132val.0133}134}135136impl IntoBytes for Imm64 {137fn into_bytes(self) -> Vec<u8> {138self.0.to_le_bytes().to_vec()139}140}141142impl From<i64> for Imm64 {143fn from(x: i64) -> Self {144Self(x)145}146}147148impl Display for Imm64 {149fn fmt(&self, f: &mut Formatter) -> fmt::Result {150let x = self.0;151if x < 10_000 {152// Use decimal for small and negative numbers.153write!(f, "{x}")154} else {155write_hex(x as u64, f)156}157}158}159160/// Parse a 64-bit signed number.161fn parse_i64(s: &str) -> Result<i64, &'static str> {162let negative = s.starts_with('-');163let s2 = if negative || s.starts_with('+') {164&s[1..]165} else {166s167};168169let mut value = parse_u64(s2)?;170171// We support the range-and-a-half from -2^63 .. 2^64-1.172if negative {173value = value.wrapping_neg();174// Don't allow large negative values to wrap around and become positive.175if value as i64 > 0 {176return Err("Negative number too small");177}178}179Ok(value as i64)180}181182impl FromStr for Imm64 {183type Err = &'static str;184185// Parse a decimal or hexadecimal `Imm64`, formatted as above.186fn from_str(s: &str) -> Result<Self, &'static str> {187parse_i64(s).map(Self::new)188}189}190191/// 64-bit immediate unsigned integer operand.192///193/// A `Uimm64` operand can also be used to represent immediate values of smaller integer types by194/// zero-extending to `i64`.195#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]196#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]197pub struct Uimm64(u64);198199impl Uimm64 {200/// Create a new `Uimm64` representing the unsigned number `x`.201pub fn new(x: u64) -> Self {202Self(x)203}204205/// Return self negated.206pub fn wrapping_neg(self) -> Self {207Self(self.0.wrapping_neg())208}209}210211impl From<Uimm64> for u64 {212fn from(val: Uimm64) -> u64 {213val.0214}215}216217impl From<u64> for Uimm64 {218fn from(x: u64) -> Self {219Self(x)220}221}222223/// Hexadecimal with a multiple of 4 digits and group separators:224///225/// 0xfff0226/// 0x0001_ffff227/// 0xffff_ffff_fff8_4400228///229fn write_hex(x: u64, f: &mut Formatter) -> fmt::Result {230let mut pos = (64 - x.leading_zeros() - 1) & 0xf0;231write!(f, "0x{:04x}", (x >> pos) & 0xffff)?;232while pos > 0 {233pos -= 16;234write!(f, "_{:04x}", (x >> pos) & 0xffff)?;235}236Ok(())237}238239impl Display for Uimm64 {240fn fmt(&self, f: &mut Formatter) -> fmt::Result {241let x = self.0;242if x < 10_000 {243// Use decimal for small numbers.244write!(f, "{x}")245} else {246write_hex(x, f)247}248}249}250251/// Parse a 64-bit unsigned number.252fn parse_u64(s: &str) -> Result<u64, &'static str> {253let mut value: u64 = 0;254let mut digits = 0;255256if s.starts_with("-0x") {257return Err("Invalid character in hexadecimal number");258} else if let Some(num) = s.strip_prefix("0x") {259// Hexadecimal.260for ch in num.chars() {261match ch.to_digit(16) {262Some(digit) => {263digits += 1;264if digits > 16 {265return Err("Too many hexadecimal digits");266}267// This can't overflow given the digit limit.268value = (value << 4) | u64::from(digit);269}270None => {271// Allow embedded underscores, but fail on anything else.272if ch != '_' {273return Err("Invalid character in hexadecimal number");274}275}276}277}278} else {279// Decimal number, possibly negative.280for ch in s.chars() {281match ch.to_digit(10) {282Some(digit) => {283digits += 1;284match value.checked_mul(10) {285None => return Err("Too large decimal number"),286Some(v) => value = v,287}288match value.checked_add(u64::from(digit)) {289None => return Err("Too large decimal number"),290Some(v) => value = v,291}292}293None => {294// Allow embedded underscores, but fail on anything else.295if ch != '_' {296return Err("Invalid character in decimal number");297}298}299}300}301}302303if digits == 0 {304return Err("No digits in number");305}306307Ok(value)308}309310impl FromStr for Uimm64 {311type Err = &'static str;312313// Parse a decimal or hexadecimal `Uimm64`, formatted as above.314fn from_str(s: &str) -> Result<Self, &'static str> {315parse_u64(s).map(Self::new)316}317}318319/// 8-bit unsigned integer immediate operand.320///321/// This is used to indicate lane indexes typically.322pub type Uimm8 = u8;323324/// A 32-bit unsigned integer immediate operand.325///326/// This is used to represent sizes of memory objects.327#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]328#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]329pub struct Uimm32(u32);330331impl From<Uimm32> for u32 {332fn from(val: Uimm32) -> u32 {333val.0334}335}336337impl From<Uimm32> for u64 {338fn from(val: Uimm32) -> u64 {339val.0.into()340}341}342343impl From<Uimm32> for i64 {344fn from(val: Uimm32) -> i64 {345i64::from(val.0)346}347}348349impl From<u32> for Uimm32 {350fn from(x: u32) -> Self {351Self(x)352}353}354355impl Display for Uimm32 {356fn fmt(&self, f: &mut Formatter) -> fmt::Result {357if self.0 < 10_000 {358write!(f, "{}", self.0)359} else {360write_hex(u64::from(self.0), f)361}362}363}364365impl FromStr for Uimm32 {366type Err = &'static str;367368// Parse a decimal or hexadecimal `Uimm32`, formatted as above.369fn from_str(s: &str) -> Result<Self, &'static str> {370parse_i64(s).and_then(|x| {371if 0 <= x && x <= i64::from(u32::MAX) {372Ok(Self(x as u32))373} else {374Err("Uimm32 out of range")375}376})377}378}379380/// A 128-bit immediate operand.381///382/// This is used as an immediate value in SIMD instructions.383#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]384#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]385pub struct V128Imm(pub [u8; 16]);386387impl V128Imm {388/// Iterate over the bytes in the constant.389pub fn bytes(&self) -> impl Iterator<Item = &u8> {390self.0.iter()391}392393/// Convert the immediate into a vector.394pub fn to_vec(self) -> Vec<u8> {395self.0.to_vec()396}397398/// Convert the immediate into a slice.399pub fn as_slice(&self) -> &[u8] {400&self.0[..]401}402}403404impl From<&[u8]> for V128Imm {405fn from(slice: &[u8]) -> Self {406assert_eq!(slice.len(), 16);407let mut buffer = [0; 16];408buffer.copy_from_slice(slice);409Self(buffer)410}411}412413impl From<u128> for V128Imm {414fn from(val: u128) -> Self {415V128Imm(val.to_le_bytes())416}417}418419/// 32-bit signed immediate offset.420///421/// This is used to encode an immediate offset for load/store instructions. All supported ISAs have422/// a maximum load/store offset that fits in an `i32`.423#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]424#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]425pub struct Offset32(i32);426427impl Offset32 {428/// Create a new `Offset32` representing the signed number `x`.429pub fn new(x: i32) -> Self {430Self(x)431}432433/// Create a new `Offset32` representing the signed number `x` if possible.434pub fn try_from_i64(x: i64) -> Option<Self> {435let x = i32::try_from(x).ok()?;436Some(Self::new(x))437}438439/// Add in the signed number `x` if possible.440pub fn try_add_i64(self, x: i64) -> Option<Self> {441let x = i32::try_from(x).ok()?;442let ret = self.0.checked_add(x)?;443Some(Self::new(ret))444}445}446447impl From<Offset32> for i32 {448fn from(val: Offset32) -> i32 {449val.0450}451}452453impl From<Offset32> for i64 {454fn from(val: Offset32) -> i64 {455i64::from(val.0)456}457}458459impl From<i32> for Offset32 {460fn from(x: i32) -> Self {461Self(x)462}463}464465impl From<u8> for Offset32 {466fn from(val: u8) -> Offset32 {467Self(val.into())468}469}470471impl Display for Offset32 {472fn fmt(&self, f: &mut Formatter) -> fmt::Result {473// 0 displays as an empty offset.474if self.0 == 0 {475return Ok(());476}477478// Always include a sign.479write!(f, "{}", if self.0 < 0 { '-' } else { '+' })?;480481let val = i64::from(self.0).abs();482if val < 10_000 {483write!(f, "{val}")484} else {485write_hex(val as u64, f)486}487}488}489490impl FromStr for Offset32 {491type Err = &'static str;492493// Parse a decimal or hexadecimal `Offset32`, formatted as above.494fn from_str(s: &str) -> Result<Self, &'static str> {495if !(s.starts_with('-') || s.starts_with('+')) {496return Err("Offset must begin with sign");497}498parse_i64(s).and_then(|x| {499if i64::from(i32::MIN) <= x && x <= i64::from(i32::MAX) {500Ok(Self::new(x as i32))501} else {502Err("Offset out of range")503}504})505}506}507508// FIXME(rust-lang/rust#83527): Replace with `${ignore()}` once it is stabilised.509macro_rules! ignore {510($($t:tt)*) => {};511}512513macro_rules! ieee_float {514(515name = $name:ident,516bits = $bits:literal,517significand_bits = $significand_bits:literal,518bits_ty = $bits_ty:ident,519float_ty = $float_ty:ident,520$(as_float = $as_float:ident,)?521$(rust_type_not_stable = $rust_type_not_stable:ident,)?522) => {523/// An IEEE524#[doc = concat!("binary", stringify!($bits))]525/// immediate floating point value, represented as a526#[doc = stringify!($bits_ty)]527/// containing the bit pattern.528///529/// We specifically avoid using a530#[doc = stringify!($float_ty)]531/// here since some architectures may silently alter floats.532/// See: <https://github.com/bytecodealliance/wasmtime/pull/2251#discussion_r498508646>533///534/// The [PartialEq] and [Hash] implementations are over the underlying bit pattern, but535/// [PartialOrd] respects IEEE754 semantics.536///537/// All bit patterns are allowed.538#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]539#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]540#[repr(C)]541pub struct $name {542bits: $bits_ty543}544545impl $name {546const BITS: u8 = $bits;547const SIGNIFICAND_BITS: u8 = $significand_bits;548const EXPONENT_BITS: u8 = Self::BITS - Self::SIGNIFICAND_BITS - 1;549const SIGN_MASK: $bits_ty = 1 << (Self::EXPONENT_BITS + Self::SIGNIFICAND_BITS);550const SIGNIFICAND_MASK: $bits_ty = $bits_ty::MAX >> (Self::EXPONENT_BITS + 1);551const EXPONENT_MASK: $bits_ty = !Self::SIGN_MASK & !Self::SIGNIFICAND_MASK;552/// The positive WebAssembly canonical NaN.553pub const NAN: Self = Self::with_bits(Self::EXPONENT_MASK | (1 << (Self::SIGNIFICAND_BITS - 1)));554555/// Create a new556#[doc = concat!("`", stringify!($name), "`")]557/// containing the bits of `bits`.558pub const fn with_bits(bits: $bits_ty) -> Self {559Self { bits }560}561562/// Get the bitwise representation.563pub fn bits(self) -> $bits_ty {564self.bits565}566567$(568/// Create a new569#[doc = concat!("`", stringify!($name), "`")]570/// representing the number `x`.571pub fn with_float(x: $float_ty) -> Self {572Self::with_bits(x.to_bits())573}574575/// Converts `self` to a Rust576#[doc = concat!("`", stringify!($float_ty), "`.")]577pub fn $as_float(self) -> $float_ty {578$float_ty::from_bits(self.bits())579}580)?581582/// Computes the absolute value of `self`.583pub fn abs(self) -> Self {584Self::with_bits(self.bits() & !Self::SIGN_MASK)585}586587/// Returns a number composed of the magnitude of `self` and the sign of `sign`.588pub fn copysign(self, sign: Self) -> Self {589Self::with_bits((self.bits() & !Self::SIGN_MASK) | (sign.bits() & Self::SIGN_MASK))590}591592/// Returns the minimum of `self` and `other`, following the WebAssembly/IEEE 754-2019 definition.593pub fn minimum(self, other: Self) -> Self {594// FIXME: Replace with Rust float method once it is stabilised.595if self.is_nan() || other.is_nan() {596Self::NAN597} else if self.is_zero() && other.is_zero() {598if self.is_negative() {599self600} else {601other602}603} else if self <= other {604self605} else {606other607}608}609610/// Returns the maximum of `self` and `other`, following the WebAssembly/IEEE 754-2019 definition.611pub fn maximum(self, other: Self) -> Self {612// FIXME: Replace with Rust float method once it is stabilised.613if self.is_nan() || other.is_nan() {614Self::NAN615} else if self.is_zero() && other.is_zero() {616if self.is_positive() {617self618} else {619other620}621} else if self >= other {622self623} else {624other625}626}627628/// Create an629#[doc = concat!("`", stringify!($name), "`")]630/// number representing `2.0^n`.631pub fn pow2<I: Into<i32>>(n: I) -> Self {632let n = n.into();633let w = Self::EXPONENT_BITS;634let t = Self::SIGNIFICAND_BITS;635let bias = (1 << (w - 1)) - 1;636let exponent = n + bias;637assert!(exponent > 0, "Underflow n={}", n);638assert!(exponent < (1 << w) + 1, "Overflow n={}", n);639Self::with_bits((exponent as $bits_ty) << t)640}641642/// Create an643#[doc = concat!("`", stringify!($name), "`")]644/// number representing the greatest negative value not convertible from645#[doc = concat!("`", stringify!($float_ty), "`")]646/// to a signed integer with width n.647pub fn fcvt_to_sint_negative_overflow<I: Into<i32>>(n: I) -> Self {648let n = n.into();649debug_assert!(n < i32::from(Self::BITS));650debug_assert!(i32::from(Self::SIGNIFICAND_BITS) + 1 - n < i32::from(Self::BITS));651Self::with_bits((1 << (Self::BITS - 1)) | Self::pow2(n - 1).bits() | (1 << (i32::from(Self::SIGNIFICAND_BITS) + 1 - n)))652}653654/// Check if the value is a NaN. For655#[doc = concat!("`", stringify!($name), "`,")]656/// this means checking that all the exponent bits are set and the significand is non-zero.657pub fn is_nan(self) -> bool {658self.abs().bits() > Self::EXPONENT_MASK659}660661/// Returns true if `self` has a negative sign, including 0.0, NaNs with positive sign bit and positive infinity.662pub fn is_positive(self) -> bool {663!self.is_negative()664}665666/// Returns true if `self` has a negative sign, including -0.0, NaNs with negative sign bit and negative infinity.667pub fn is_negative(self) -> bool {668self.bits() & Self::SIGN_MASK == Self::SIGN_MASK669}670671/// Returns `true` if `self` is positive or negative zero.672pub fn is_zero(self) -> bool {673self.abs().bits() == 0674}675676/// Returns `None` if `self` is a NaN and `Some(self)` otherwise.677pub fn non_nan(self) -> Option<Self> {678Some(self).filter(|f| !f.is_nan())679}680681$(682/// Returns the square root of `self`.683pub fn sqrt(self) -> Self {684Self::with_float(self.$as_float().sqrt())685}686687/// Returns the smallest integer greater than or equal to `self`.688pub fn ceil(self) -> Self {689Self::with_float(self.$as_float().ceil())690}691692/// Returns the largest integer less than or equal to `self`.693pub fn floor(self) -> Self {694Self::with_float(self.$as_float().floor())695}696697/// Returns the integer part of `self`. This means that non-integer numbers are always truncated towards zero.698pub fn trunc(self) -> Self {699Self::with_float(self.$as_float().trunc())700}701702/// Returns the nearest integer to `self`. Rounds half-way cases to the number703/// with an even least significant digit.704pub fn round_ties_even(self) -> Self {705Self::with_float(self.$as_float().round_ties_even())706}707)?708}709710impl PartialOrd for $name {711fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {712$(self.$as_float().partial_cmp(&rhs.$as_float()))?713$(714ignore!($rust_type_not_stable);715// FIXME(#8312): Use builtin Rust comparisons once `f16` and `f128` support is stabalised.716if self.is_nan() || rhs.is_nan() {717// One of the floats is a NaN.718return None;719}720if self.is_zero() || rhs.is_zero() {721// Zeros are always equal regardless of sign.722return Some(Ordering::Equal);723}724let lhs_positive = self.is_positive();725let rhs_positive = rhs.is_positive();726if lhs_positive != rhs_positive {727// Different signs: negative < positive728return lhs_positive.partial_cmp(&rhs_positive);729}730// Finite or infinity will order correctly with an integer comparison of the bits.731if lhs_positive {732self.bits().partial_cmp(&rhs.bits())733} else {734// Reverse the comparison when both floats are negative.735rhs.bits().partial_cmp(&self.bits())736}737)?738}739}740741impl Display for $name {742fn fmt(&self, f: &mut Formatter) -> fmt::Result {743format_float(u128::from(self.bits()), Self::EXPONENT_BITS, Self::SIGNIFICAND_BITS, f)744}745}746747impl FromStr for $name {748type Err = &'static str;749750fn from_str(s: &str) -> Result<Self, &'static str> {751match parse_float(s, Self::EXPONENT_BITS, Self::SIGNIFICAND_BITS) {752Ok(b) => Ok(Self::with_bits(b.try_into().unwrap())),753Err(s) => Err(s),754}755}756}757758impl IntoBytes for $name {759fn into_bytes(self) -> Vec<u8> {760self.bits().to_le_bytes().to_vec()761}762}763764impl Neg for $name {765type Output = Self;766767fn neg(self) -> Self {768Self::with_bits(self.bits() ^ Self::SIGN_MASK)769}770}771772773774$(775impl From<$float_ty> for $name {776fn from(x: $float_ty) -> Self {777Self::with_float(x)778}779}780781impl Add for $name {782type Output = Self;783784fn add(self, rhs: Self) -> Self {785Self::with_float(self.$as_float() + rhs.$as_float())786}787}788789impl Sub for $name {790type Output = Self;791792fn sub(self, rhs: Self) -> Self {793Self::with_float(self.$as_float() - rhs.$as_float())794}795}796797impl Mul for $name {798type Output = Self;799800fn mul(self, rhs: Self) -> Self {801Self::with_float(self.$as_float() * rhs.$as_float())802}803}804805impl Div for $name {806type Output = Self;807808fn div(self, rhs: Self) -> Self::Output {809Self::with_float(self.$as_float() / rhs.$as_float())810}811}812)?813814impl BitAnd for $name {815type Output = Self;816817fn bitand(self, rhs: Self) -> Self {818Self::with_bits(self.bits() & rhs.bits())819}820}821822impl BitOr for $name {823type Output = Self;824825fn bitor(self, rhs: Self) -> Self {826Self::with_bits(self.bits() | rhs.bits())827}828}829830impl BitXor for $name {831type Output = Self;832833fn bitxor(self, rhs: Self) -> Self {834Self::with_bits(self.bits() ^ rhs.bits())835}836}837838impl Not for $name {839type Output = Self;840841fn not(self) -> Self {842Self::with_bits(!self.bits())843}844}845};846}847848ieee_float! {849name = Ieee16,850bits = 16,851significand_bits = 10,852bits_ty = u16,853float_ty = f16,854rust_type_not_stable = rust_type_not_stable,855}856857ieee_float! {858name = Ieee32,859bits = 32,860significand_bits = 23,861bits_ty = u32,862float_ty = f32,863as_float = as_f32,864}865866ieee_float! {867name = Ieee64,868bits = 64,869significand_bits = 52,870bits_ty = u64,871float_ty = f64,872as_float = as_f64,873}874875ieee_float! {876name = Ieee128,877bits = 128,878significand_bits = 112,879bits_ty = u128,880float_ty = f128,881rust_type_not_stable = rust_type_not_stable,882}883884/// Format a floating point number in a way that is reasonably human-readable, and that can be885/// converted back to binary without any rounding issues. The hexadecimal formatting of normal and886/// subnormal numbers is compatible with C99 and the `printf "%a"` format specifier. The NaN and Inf887/// formats are not supported by C99.888///889/// The encoding parameters are:890///891/// w - exponent field width in bits892/// t - trailing significand field width in bits893///894fn format_float(bits: u128, w: u8, t: u8, f: &mut Formatter) -> fmt::Result {895debug_assert!(w > 0 && w <= 16, "Invalid exponent range");896debug_assert!(1 + w + t <= 128, "Too large IEEE format for u128");897debug_assert!((t + w + 1).is_power_of_two(), "Unexpected IEEE format size");898899let max_e_bits = (1u128 << w) - 1;900let t_bits = bits & ((1u128 << t) - 1); // Trailing significand.901let e_bits = (bits >> t) & max_e_bits; // Biased exponent.902let sign_bit = (bits >> (w + t)) & 1;903904let bias: i32 = (1 << (w - 1)) - 1;905let e = e_bits as i32 - bias; // Unbiased exponent.906let emin = 1 - bias; // Minimum exponent.907908// How many hexadecimal digits are needed for the trailing significand?909let digits = (t + 3) / 4;910// Trailing significand left-aligned in `digits` hexadecimal digits.911let left_t_bits = t_bits << (4 * digits - t);912913// All formats share the leading sign.914if sign_bit != 0 {915write!(f, "-")?;916}917918if e_bits == 0 {919if t_bits == 0 {920// Zero.921write!(f, "0.0")922} else {923// Subnormal.924write!(925f,926"0x0.{0:01$x}p{2}",927left_t_bits,928usize::from(digits),929emin930)931}932} else if e_bits == max_e_bits {933// Always print a `+` or `-` sign for these special values.934// This makes them easier to parse as they can't be confused as identifiers.935if sign_bit == 0 {936write!(f, "+")?;937}938if t_bits == 0 {939// Infinity.940write!(f, "Inf")941} else {942// NaN.943let payload = t_bits & ((1 << (t - 1)) - 1);944if t_bits & (1 << (t - 1)) != 0 {945// Quiet NaN.946if payload != 0 {947write!(f, "NaN:0x{payload:x}")948} else {949write!(f, "NaN")950}951} else {952// Signaling NaN.953write!(f, "sNaN:0x{payload:x}")954}955}956} else {957// Normal number.958write!(f, "0x1.{0:01$x}p{2}", left_t_bits, usize::from(digits), e)959}960}961962/// Parse a float using the same format as `format_float` above.963///964/// The encoding parameters are:965///966/// w - exponent field width in bits967/// t - trailing significand field width in bits968///969fn parse_float(s: &str, w: u8, t: u8) -> Result<u128, &'static str> {970debug_assert!(w > 0 && w <= 16, "Invalid exponent range");971debug_assert!(1 + w + t <= 128, "Too large IEEE format for u128");972debug_assert!((t + w + 1).is_power_of_two(), "Unexpected IEEE format size");973974let (sign_bit, s2) = if let Some(num) = s.strip_prefix('-') {975(1u128 << (t + w), num)976} else if let Some(num) = s.strip_prefix('+') {977(0, num)978} else {979(0, s)980};981982if !s2.starts_with("0x") {983let max_e_bits = ((1u128 << w) - 1) << t;984let quiet_bit = 1u128 << (t - 1);985986// The only decimal encoding allowed is 0.987if s2 == "0.0" {988return Ok(sign_bit);989}990991if s2 == "Inf" {992// +/- infinity: e = max, t = 0.993return Ok(sign_bit | max_e_bits);994}995if s2 == "NaN" {996// Canonical quiet NaN: e = max, t = quiet.997return Ok(sign_bit | max_e_bits | quiet_bit);998}999if let Some(nan) = s2.strip_prefix("NaN:0x") {1000// Quiet NaN with payload.1001return match u128::from_str_radix(nan, 16) {1002Ok(payload) if payload < quiet_bit => {1003Ok(sign_bit | max_e_bits | quiet_bit | payload)1004}1005_ => Err("Invalid NaN payload"),1006};1007}1008if let Some(nan) = s2.strip_prefix("sNaN:0x") {1009// Signaling NaN with payload.1010return match u128::from_str_radix(nan, 16) {1011Ok(payload) if 0 < payload && payload < quiet_bit => {1012Ok(sign_bit | max_e_bits | payload)1013}1014_ => Err("Invalid sNaN payload"),1015};1016}10171018return Err("Float must be hexadecimal");1019}1020let s3 = &s2[2..];10211022let mut digits = 0u8;1023let mut digits_before_period: Option<u8> = None;1024let mut significand = 0u128;1025let mut exponent = 0i32;10261027for (idx, ch) in s3.char_indices() {1028match ch {1029'.' => {1030// This is the radix point. There can only be one.1031if digits_before_period != None {1032return Err("Multiple radix points");1033} else {1034digits_before_period = Some(digits);1035}1036}1037'p' => {1038// The following exponent is a decimal number.1039let exp_str = &s3[1 + idx..];1040match exp_str.parse::<i16>() {1041Ok(e) => {1042exponent = i32::from(e);1043break;1044}1045Err(_) => return Err("Bad exponent"),1046}1047}1048_ => match ch.to_digit(16) {1049Some(digit) => {1050digits += 1;1051if digits > 32 {1052return Err("Too many digits");1053}1054significand = (significand << 4) | u128::from(digit);1055}1056None => return Err("Invalid character"),1057},1058}1059}10601061if digits == 0 {1062return Err("No digits");1063}10641065if significand == 0 {1066// This is +/- 0.0.1067return Ok(sign_bit);1068}10691070// Number of bits appearing after the radix point.1071match digits_before_period {1072None => {} // No radix point present.1073Some(d) => exponent -= 4 * i32::from(digits - d),1074};10751076// Normalize the significand and exponent.1077let significant_bits = (128 - significand.leading_zeros()) as u8;1078if significant_bits > t + 1 {1079let adjust = significant_bits - (t + 1);1080if significand & ((1u128 << adjust) - 1) != 0 {1081return Err("Too many significant bits");1082}1083// Adjust significand down.1084significand >>= adjust;1085exponent += i32::from(adjust);1086} else {1087let adjust = t + 1 - significant_bits;1088significand <<= adjust;1089exponent -= i32::from(adjust);1090}1091debug_assert_eq!(significand >> t, 1);10921093// Trailing significand excludes the high bit.1094let t_bits = significand & ((1 << t) - 1);10951096let max_exp = (1i32 << w) - 2;1097let bias: i32 = (1 << (w - 1)) - 1;1098exponent += bias + i32::from(t);10991100if exponent > max_exp {1101Err("Magnitude too large")1102} else if exponent > 0 {1103// This is a normal number.1104let e_bits = (exponent as u128) << t;1105Ok(sign_bit | e_bits | t_bits)1106} else if 1 - exponent <= i32::from(t) {1107// This is a subnormal number: e = 0, t = significand bits.1108// Renormalize significand for exponent = 1.1109let adjust = 1 - exponent;1110if significand & ((1u128 << adjust) - 1) != 0 {1111Err("Subnormal underflow")1112} else {1113significand >>= adjust;1114Ok(sign_bit | significand)1115}1116} else {1117Err("Magnitude too small")1118}1119}11201121#[cfg(test)]1122mod tests {1123use super::*;1124use alloc::string::ToString;1125use core::{f32, f64};11261127#[test]1128fn format_imm64() {1129assert_eq!(Imm64(0).to_string(), "0");1130assert_eq!(Imm64(9999).to_string(), "9999");1131assert_eq!(Imm64(10000).to_string(), "0x2710");1132assert_eq!(Imm64(-9999).to_string(), "-9999");1133assert_eq!(Imm64(-10000).to_string(), "-10000");1134assert_eq!(Imm64(0xffff).to_string(), "0xffff");1135assert_eq!(Imm64(0x10000).to_string(), "0x0001_0000");1136}11371138#[test]1139fn format_uimm64() {1140assert_eq!(Uimm64(0).to_string(), "0");1141assert_eq!(Uimm64(9999).to_string(), "9999");1142assert_eq!(Uimm64(10000).to_string(), "0x2710");1143assert_eq!(Uimm64(-9999i64 as u64).to_string(), "0xffff_ffff_ffff_d8f1");1144assert_eq!(1145Uimm64(-10000i64 as u64).to_string(),1146"0xffff_ffff_ffff_d8f0"1147);1148assert_eq!(Uimm64(0xffff).to_string(), "0xffff");1149assert_eq!(Uimm64(0x10000).to_string(), "0x0001_0000");1150}11511152// Verify that `text` can be parsed as a `T` into a value that displays as `want`.1153#[track_caller]1154fn parse_ok<T: FromStr + Display>(text: &str, want: &str)1155where1156<T as FromStr>::Err: Display,1157{1158match text.parse::<T>() {1159Err(s) => panic!("\"{text}\".parse() error: {s}"),1160Ok(x) => assert_eq!(x.to_string(), want),1161}1162}11631164// Verify that `text` fails to parse as `T` with the error `msg`.1165fn parse_err<T: FromStr + Display>(text: &str, msg: &str)1166where1167<T as FromStr>::Err: Display,1168{1169match text.parse::<T>() {1170Err(s) => assert_eq!(s.to_string(), msg),1171Ok(x) => panic!("Wanted Err({msg}), but got {x}"),1172}1173}11741175#[test]1176fn parse_imm64() {1177parse_ok::<Imm64>("0", "0");1178parse_ok::<Imm64>("1", "1");1179parse_ok::<Imm64>("-0", "0");1180parse_ok::<Imm64>("-1", "-1");1181parse_ok::<Imm64>("0x0", "0");1182parse_ok::<Imm64>("0xf", "15");1183parse_ok::<Imm64>("-0x9", "-9");11841185// Probe limits.1186parse_ok::<Imm64>("0xffffffff_ffffffff", "-1");1187parse_ok::<Imm64>("0x80000000_00000000", "-9223372036854775808");1188parse_ok::<Imm64>("-0x80000000_00000000", "-9223372036854775808");1189parse_err::<Imm64>("-0x80000000_00000001", "Negative number too small");1190parse_ok::<Imm64>("18446744073709551615", "-1");1191parse_ok::<Imm64>("-9223372036854775808", "-9223372036854775808");1192// Overflow both the `checked_add` and `checked_mul`.1193parse_err::<Imm64>("18446744073709551616", "Too large decimal number");1194parse_err::<Imm64>("184467440737095516100", "Too large decimal number");1195parse_err::<Imm64>("-9223372036854775809", "Negative number too small");11961197// Underscores are allowed where digits go.1198parse_ok::<Imm64>("0_0", "0");1199parse_ok::<Imm64>("-_10_0", "-100");1200parse_ok::<Imm64>("_10_", "10");1201parse_ok::<Imm64>("0x97_88_bb", "0x0097_88bb");1202parse_ok::<Imm64>("0x_97_", "151");12031204parse_err::<Imm64>("", "No digits in number");1205parse_err::<Imm64>("-", "No digits in number");1206parse_err::<Imm64>("_", "No digits in number");1207parse_err::<Imm64>("0x", "No digits in number");1208parse_err::<Imm64>("0x_", "No digits in number");1209parse_err::<Imm64>("-0x", "No digits in number");1210parse_err::<Imm64>(" ", "Invalid character in decimal number");1211parse_err::<Imm64>("0 ", "Invalid character in decimal number");1212parse_err::<Imm64>(" 0", "Invalid character in decimal number");1213parse_err::<Imm64>("--", "Invalid character in decimal number");1214parse_err::<Imm64>("-0x-", "Invalid character in hexadecimal number");1215parse_err::<Imm64>("abc", "Invalid character in decimal number");1216parse_err::<Imm64>("-abc", "Invalid character in decimal number");12171218// Hex count overflow.1219parse_err::<Imm64>("0x0_0000_0000_0000_0000", "Too many hexadecimal digits");1220}12211222#[test]1223fn parse_uimm64() {1224parse_ok::<Uimm64>("0", "0");1225parse_ok::<Uimm64>("1", "1");1226parse_ok::<Uimm64>("0x0", "0");1227parse_ok::<Uimm64>("0xf", "15");1228parse_ok::<Uimm64>("0xffffffff_fffffff7", "0xffff_ffff_ffff_fff7");12291230// Probe limits.1231parse_ok::<Uimm64>("0xffffffff_ffffffff", "0xffff_ffff_ffff_ffff");1232parse_ok::<Uimm64>("0x80000000_00000000", "0x8000_0000_0000_0000");1233parse_ok::<Uimm64>("18446744073709551615", "0xffff_ffff_ffff_ffff");1234// Overflow both the `checked_add` and `checked_mul`.1235parse_err::<Uimm64>("18446744073709551616", "Too large decimal number");1236parse_err::<Uimm64>("184467440737095516100", "Too large decimal number");12371238// Underscores are allowed where digits go.1239parse_ok::<Uimm64>("0_0", "0");1240parse_ok::<Uimm64>("_10_", "10");1241parse_ok::<Uimm64>("0x97_88_bb", "0x0097_88bb");1242parse_ok::<Uimm64>("0x_97_", "151");12431244parse_err::<Uimm64>("", "No digits in number");1245parse_err::<Uimm64>("_", "No digits in number");1246parse_err::<Uimm64>("0x", "No digits in number");1247parse_err::<Uimm64>("0x_", "No digits in number");1248parse_err::<Uimm64>("-", "Invalid character in decimal number");1249parse_err::<Uimm64>("-0x", "Invalid character in hexadecimal number");1250parse_err::<Uimm64>(" ", "Invalid character in decimal number");1251parse_err::<Uimm64>("0 ", "Invalid character in decimal number");1252parse_err::<Uimm64>(" 0", "Invalid character in decimal number");1253parse_err::<Uimm64>("--", "Invalid character in decimal number");1254parse_err::<Uimm64>("-0x-", "Invalid character in hexadecimal number");1255parse_err::<Uimm64>("-0", "Invalid character in decimal number");1256parse_err::<Uimm64>("-1", "Invalid character in decimal number");1257parse_err::<Uimm64>("abc", "Invalid character in decimal number");1258parse_err::<Uimm64>("-abc", "Invalid character in decimal number");12591260// Hex count overflow.1261parse_err::<Uimm64>("0x0_0000_0000_0000_0000", "Too many hexadecimal digits");1262}12631264#[test]1265fn format_offset32() {1266assert_eq!(Offset32(0).to_string(), "");1267assert_eq!(Offset32(1).to_string(), "+1");1268assert_eq!(Offset32(-1).to_string(), "-1");1269assert_eq!(Offset32(9999).to_string(), "+9999");1270assert_eq!(Offset32(10000).to_string(), "+0x2710");1271assert_eq!(Offset32(-9999).to_string(), "-9999");1272assert_eq!(Offset32(-10000).to_string(), "-0x2710");1273assert_eq!(Offset32(0xffff).to_string(), "+0xffff");1274assert_eq!(Offset32(0x10000).to_string(), "+0x0001_0000");1275}12761277#[test]1278fn parse_offset32() {1279parse_ok::<Offset32>("+0", "");1280parse_ok::<Offset32>("+1", "+1");1281parse_ok::<Offset32>("-0", "");1282parse_ok::<Offset32>("-1", "-1");1283parse_ok::<Offset32>("+0x0", "");1284parse_ok::<Offset32>("+0xf", "+15");1285parse_ok::<Offset32>("-0x9", "-9");1286parse_ok::<Offset32>("-0x8000_0000", "-0x8000_0000");12871288parse_err::<Offset32>("+0x8000_0000", "Offset out of range");1289}12901291#[test]1292fn format_ieee16() {1293assert_eq!(Ieee16::with_bits(0).to_string(), "0.0"); // 0.01294assert_eq!(Ieee16::with_bits(0x8000).to_string(), "-0.0"); // -0.01295assert_eq!(Ieee16::with_bits(0x3c00).to_string(), "0x1.000p0"); // 1.01296assert_eq!(Ieee16::with_bits(0x3e00).to_string(), "0x1.800p0"); // 1.51297assert_eq!(Ieee16::with_bits(0x3800).to_string(), "0x1.000p-1"); // 0.51298assert_eq!(1299Ieee16::with_bits(0x1400).to_string(), // `f16::EPSILON`1300"0x1.000p-10"1301);1302assert_eq!(1303Ieee16::with_bits(0xfbff).to_string(), // `f16::MIN`1304"-0x1.ffcp15"1305);1306assert_eq!(1307Ieee16::with_bits(0x7bff).to_string(), // `f16::MAX`1308"0x1.ffcp15"1309);1310// Smallest positive normal number.1311assert_eq!(1312Ieee16::with_bits(0x0400).to_string(), // `f16::MIN_POSITIVE`1313"0x1.000p-14"1314);1315// Subnormals.1316assert_eq!(1317Ieee16::with_bits(0x0200).to_string(), // `f16::MIN_POSITIVE / 2.0`1318"0x0.800p-14"1319);1320assert_eq!(1321Ieee16::with_bits(0x0001).to_string(), // `f16::MIN_POSITIVE * f16::EPSILON`1322"0x0.004p-14"1323);1324assert_eq!(1325Ieee16::with_bits(0x7c00).to_string(), // `f16::INFINITY`1326"+Inf"1327);1328assert_eq!(1329Ieee16::with_bits(0xfc00).to_string(), // `f16::NEG_INFINITY`1330"-Inf"1331);1332assert_eq!(1333Ieee16::with_bits(0x7e00).to_string(), // `f16::NAN`1334"+NaN"1335);1336assert_eq!(1337Ieee16::with_bits(0xfe00).to_string(), // `-f16::NAN`1338"-NaN"1339);1340// Construct some qNaNs with payloads.1341assert_eq!(Ieee16::with_bits(0x7e01).to_string(), "+NaN:0x1");1342assert_eq!(Ieee16::with_bits(0x7f01).to_string(), "+NaN:0x101");1343// Signaling NaNs.1344assert_eq!(Ieee16::with_bits(0x7c01).to_string(), "+sNaN:0x1");1345assert_eq!(Ieee16::with_bits(0x7d01).to_string(), "+sNaN:0x101");1346}13471348#[test]1349fn parse_ieee16() {1350parse_ok::<Ieee16>("0.0", "0.0");1351parse_ok::<Ieee16>("+0.0", "0.0");1352parse_ok::<Ieee16>("-0.0", "-0.0");1353parse_ok::<Ieee16>("0x0", "0.0");1354parse_ok::<Ieee16>("0x0.0", "0.0");1355parse_ok::<Ieee16>("0x.0", "0.0");1356parse_ok::<Ieee16>("0x0.", "0.0");1357parse_ok::<Ieee16>("0x1", "0x1.000p0");1358parse_ok::<Ieee16>("+0x1", "0x1.000p0");1359parse_ok::<Ieee16>("-0x1", "-0x1.000p0");1360parse_ok::<Ieee16>("0x10", "0x1.000p4");1361parse_ok::<Ieee16>("0x10.0", "0x1.000p4");1362parse_err::<Ieee16>("0.", "Float must be hexadecimal");1363parse_err::<Ieee16>(".0", "Float must be hexadecimal");1364parse_err::<Ieee16>("0", "Float must be hexadecimal");1365parse_err::<Ieee16>("-0", "Float must be hexadecimal");1366parse_err::<Ieee16>(".", "Float must be hexadecimal");1367parse_err::<Ieee16>("", "Float must be hexadecimal");1368parse_err::<Ieee16>("-", "Float must be hexadecimal");1369parse_err::<Ieee16>("0x", "No digits");1370parse_err::<Ieee16>("0x..", "Multiple radix points");13711372// Check significant bits.1373parse_ok::<Ieee16>("0x0.ffe", "0x1.ffcp-1");1374parse_ok::<Ieee16>("0x1.ffc", "0x1.ffcp0");1375parse_ok::<Ieee16>("0x3.ff8", "0x1.ffcp1");1376parse_ok::<Ieee16>("0x7.ff", "0x1.ffcp2");1377parse_ok::<Ieee16>("0xf.fe", "0x1.ffcp3");1378parse_err::<Ieee16>("0x1.ffe", "Too many significant bits");1379parse_err::<Ieee16>("0x1.ffc00000000000000000000000000000", "Too many digits");13801381// Exponents.1382parse_ok::<Ieee16>("0x1p3", "0x1.000p3");1383parse_ok::<Ieee16>("0x1p-3", "0x1.000p-3");1384parse_ok::<Ieee16>("0x1.0p3", "0x1.000p3");1385parse_ok::<Ieee16>("0x2.0p3", "0x1.000p4");1386parse_ok::<Ieee16>("0x1.0p15", "0x1.000p15");1387parse_ok::<Ieee16>("0x1.0p-14", "0x1.000p-14");1388parse_ok::<Ieee16>("0x0.1p-10", "0x1.000p-14");1389parse_err::<Ieee16>("0x2.0p15", "Magnitude too large");13901391// Subnormals.1392parse_ok::<Ieee16>("0x1.0p-15", "0x0.800p-14");1393parse_ok::<Ieee16>("0x1.0p-24", "0x0.004p-14");1394parse_ok::<Ieee16>("0x0.004p-14", "0x0.004p-14");1395parse_err::<Ieee16>("0x0.102p-14", "Subnormal underflow");1396parse_err::<Ieee16>("0x1.8p-24", "Subnormal underflow");1397parse_err::<Ieee16>("0x1.0p-25", "Magnitude too small");13981399// NaNs and Infs.1400parse_ok::<Ieee16>("Inf", "+Inf");1401parse_ok::<Ieee16>("+Inf", "+Inf");1402parse_ok::<Ieee16>("-Inf", "-Inf");1403parse_ok::<Ieee16>("NaN", "+NaN");1404parse_ok::<Ieee16>("+NaN", "+NaN");1405parse_ok::<Ieee16>("-NaN", "-NaN");1406parse_ok::<Ieee16>("NaN:0x0", "+NaN");1407parse_err::<Ieee16>("NaN:", "Float must be hexadecimal");1408parse_err::<Ieee16>("NaN:0", "Float must be hexadecimal");1409parse_err::<Ieee16>("NaN:0x", "Invalid NaN payload");1410parse_ok::<Ieee16>("NaN:0x001", "+NaN:0x1");1411parse_ok::<Ieee16>("NaN:0x101", "+NaN:0x101");1412parse_err::<Ieee16>("NaN:0x301", "Invalid NaN payload");1413parse_ok::<Ieee16>("sNaN:0x1", "+sNaN:0x1");1414parse_err::<Ieee16>("sNaN:0x0", "Invalid sNaN payload");1415parse_ok::<Ieee16>("sNaN:0x101", "+sNaN:0x101");1416parse_err::<Ieee16>("sNaN:0x301", "Invalid sNaN payload");1417}14181419#[test]1420fn pow2_ieee16() {1421assert_eq!(Ieee16::pow2(0).to_string(), "0x1.000p0");1422assert_eq!(Ieee16::pow2(1).to_string(), "0x1.000p1");1423assert_eq!(Ieee16::pow2(-1).to_string(), "0x1.000p-1");1424assert_eq!(Ieee16::pow2(15).to_string(), "0x1.000p15");1425assert_eq!(Ieee16::pow2(-14).to_string(), "0x1.000p-14");14261427assert_eq!((-Ieee16::pow2(1)).to_string(), "-0x1.000p1");1428}14291430#[test]1431fn fcvt_to_sint_negative_overflow_ieee16() {1432// FIXME(#8312): Replace with commented out version once Rust f16 support is stabilised.1433// let n = 8;1434// assert_eq!(1435// -((1u16 << (n - 1)) as f16) - 1.0,1436// Ieee16::fcvt_to_sint_negative_overflow(n).as_f16()1437// );1438let n = 8;1439assert_eq!(1440"-0x1.020p7",1441Ieee16::fcvt_to_sint_negative_overflow(n).to_string()1442);1443}14441445#[test]1446fn format_ieee32() {1447assert_eq!(Ieee32::with_float(0.0).to_string(), "0.0");1448assert_eq!(Ieee32::with_float(-0.0).to_string(), "-0.0");1449assert_eq!(Ieee32::with_float(1.0).to_string(), "0x1.000000p0");1450assert_eq!(Ieee32::with_float(1.5).to_string(), "0x1.800000p0");1451assert_eq!(Ieee32::with_float(0.5).to_string(), "0x1.000000p-1");1452assert_eq!(1453Ieee32::with_float(f32::EPSILON).to_string(),1454"0x1.000000p-23"1455);1456assert_eq!(Ieee32::with_float(f32::MIN).to_string(), "-0x1.fffffep127");1457assert_eq!(Ieee32::with_float(f32::MAX).to_string(), "0x1.fffffep127");1458// Smallest positive normal number.1459assert_eq!(1460Ieee32::with_float(f32::MIN_POSITIVE).to_string(),1461"0x1.000000p-126"1462);1463// Subnormals.1464assert_eq!(1465Ieee32::with_float(f32::MIN_POSITIVE / 2.0).to_string(),1466"0x0.800000p-126"1467);1468assert_eq!(1469Ieee32::with_float(f32::MIN_POSITIVE * f32::EPSILON).to_string(),1470"0x0.000002p-126"1471);1472assert_eq!(Ieee32::with_float(f32::INFINITY).to_string(), "+Inf");1473assert_eq!(Ieee32::with_float(f32::NEG_INFINITY).to_string(), "-Inf");1474assert_eq!(Ieee32::with_float(f32::NAN).to_string(), "+NaN");1475assert_eq!(Ieee32::with_float(-f32::NAN).to_string(), "-NaN");1476// Construct some qNaNs with payloads.1477assert_eq!(Ieee32::with_bits(0x7fc00001).to_string(), "+NaN:0x1");1478assert_eq!(Ieee32::with_bits(0x7ff00001).to_string(), "+NaN:0x300001");1479// Signaling NaNs.1480assert_eq!(Ieee32::with_bits(0x7f800001).to_string(), "+sNaN:0x1");1481assert_eq!(Ieee32::with_bits(0x7fa00001).to_string(), "+sNaN:0x200001");1482}14831484#[test]1485fn parse_ieee32() {1486parse_ok::<Ieee32>("0.0", "0.0");1487parse_ok::<Ieee32>("+0.0", "0.0");1488parse_ok::<Ieee32>("-0.0", "-0.0");1489parse_ok::<Ieee32>("0x0", "0.0");1490parse_ok::<Ieee32>("0x0.0", "0.0");1491parse_ok::<Ieee32>("0x.0", "0.0");1492parse_ok::<Ieee32>("0x0.", "0.0");1493parse_ok::<Ieee32>("0x1", "0x1.000000p0");1494parse_ok::<Ieee32>("+0x1", "0x1.000000p0");1495parse_ok::<Ieee32>("-0x1", "-0x1.000000p0");1496parse_ok::<Ieee32>("0x10", "0x1.000000p4");1497parse_ok::<Ieee32>("0x10.0", "0x1.000000p4");1498parse_err::<Ieee32>("0.", "Float must be hexadecimal");1499parse_err::<Ieee32>(".0", "Float must be hexadecimal");1500parse_err::<Ieee32>("0", "Float must be hexadecimal");1501parse_err::<Ieee32>("-0", "Float must be hexadecimal");1502parse_err::<Ieee32>(".", "Float must be hexadecimal");1503parse_err::<Ieee32>("", "Float must be hexadecimal");1504parse_err::<Ieee32>("-", "Float must be hexadecimal");1505parse_err::<Ieee32>("0x", "No digits");1506parse_err::<Ieee32>("0x..", "Multiple radix points");15071508// Check significant bits.1509parse_ok::<Ieee32>("0x0.ffffff", "0x1.fffffep-1");1510parse_ok::<Ieee32>("0x1.fffffe", "0x1.fffffep0");1511parse_ok::<Ieee32>("0x3.fffffc", "0x1.fffffep1");1512parse_ok::<Ieee32>("0x7.fffff8", "0x1.fffffep2");1513parse_ok::<Ieee32>("0xf.fffff0", "0x1.fffffep3");1514parse_err::<Ieee32>("0x1.ffffff", "Too many significant bits");1515parse_err::<Ieee32>("0x1.fffffe00000000000000000000000000", "Too many digits");15161517// Exponents.1518parse_ok::<Ieee32>("0x1p3", "0x1.000000p3");1519parse_ok::<Ieee32>("0x1p-3", "0x1.000000p-3");1520parse_ok::<Ieee32>("0x1.0p3", "0x1.000000p3");1521parse_ok::<Ieee32>("0x2.0p3", "0x1.000000p4");1522parse_ok::<Ieee32>("0x1.0p127", "0x1.000000p127");1523parse_ok::<Ieee32>("0x1.0p-126", "0x1.000000p-126");1524parse_ok::<Ieee32>("0x0.1p-122", "0x1.000000p-126");1525parse_err::<Ieee32>("0x2.0p127", "Magnitude too large");15261527// Subnormals.1528parse_ok::<Ieee32>("0x1.0p-127", "0x0.800000p-126");1529parse_ok::<Ieee32>("0x1.0p-149", "0x0.000002p-126");1530parse_ok::<Ieee32>("0x0.000002p-126", "0x0.000002p-126");1531parse_err::<Ieee32>("0x0.100001p-126", "Subnormal underflow");1532parse_err::<Ieee32>("0x1.8p-149", "Subnormal underflow");1533parse_err::<Ieee32>("0x1.0p-150", "Magnitude too small");15341535// NaNs and Infs.1536parse_ok::<Ieee32>("Inf", "+Inf");1537parse_ok::<Ieee32>("+Inf", "+Inf");1538parse_ok::<Ieee32>("-Inf", "-Inf");1539parse_ok::<Ieee32>("NaN", "+NaN");1540parse_ok::<Ieee32>("+NaN", "+NaN");1541parse_ok::<Ieee32>("-NaN", "-NaN");1542parse_ok::<Ieee32>("NaN:0x0", "+NaN");1543parse_err::<Ieee32>("NaN:", "Float must be hexadecimal");1544parse_err::<Ieee32>("NaN:0", "Float must be hexadecimal");1545parse_err::<Ieee32>("NaN:0x", "Invalid NaN payload");1546parse_ok::<Ieee32>("NaN:0x000001", "+NaN:0x1");1547parse_ok::<Ieee32>("NaN:0x300001", "+NaN:0x300001");1548parse_err::<Ieee32>("NaN:0x400001", "Invalid NaN payload");1549parse_ok::<Ieee32>("sNaN:0x1", "+sNaN:0x1");1550parse_err::<Ieee32>("sNaN:0x0", "Invalid sNaN payload");1551parse_ok::<Ieee32>("sNaN:0x200001", "+sNaN:0x200001");1552parse_err::<Ieee32>("sNaN:0x400001", "Invalid sNaN payload");1553}15541555#[test]1556fn pow2_ieee32() {1557assert_eq!(Ieee32::pow2(0).to_string(), "0x1.000000p0");1558assert_eq!(Ieee32::pow2(1).to_string(), "0x1.000000p1");1559assert_eq!(Ieee32::pow2(-1).to_string(), "0x1.000000p-1");1560assert_eq!(Ieee32::pow2(127).to_string(), "0x1.000000p127");1561assert_eq!(Ieee32::pow2(-126).to_string(), "0x1.000000p-126");15621563assert_eq!((-Ieee32::pow2(1)).to_string(), "-0x1.000000p1");1564}15651566#[test]1567fn fcvt_to_sint_negative_overflow_ieee32() {1568for n in [8, 16] {1569assert_eq!(1570-((1u32 << (n - 1)) as f32) - 1.0,1571Ieee32::fcvt_to_sint_negative_overflow(n).as_f32(),1572"n = {n}"1573);1574}1575}15761577#[test]1578fn format_ieee64() {1579assert_eq!(Ieee64::with_float(0.0).to_string(), "0.0");1580assert_eq!(Ieee64::with_float(-0.0).to_string(), "-0.0");1581assert_eq!(Ieee64::with_float(1.0).to_string(), "0x1.0000000000000p0");1582assert_eq!(Ieee64::with_float(1.5).to_string(), "0x1.8000000000000p0");1583assert_eq!(Ieee64::with_float(0.5).to_string(), "0x1.0000000000000p-1");1584assert_eq!(1585Ieee64::with_float(f64::EPSILON).to_string(),1586"0x1.0000000000000p-52"1587);1588assert_eq!(1589Ieee64::with_float(f64::MIN).to_string(),1590"-0x1.fffffffffffffp1023"1591);1592assert_eq!(1593Ieee64::with_float(f64::MAX).to_string(),1594"0x1.fffffffffffffp1023"1595);1596// Smallest positive normal number.1597assert_eq!(1598Ieee64::with_float(f64::MIN_POSITIVE).to_string(),1599"0x1.0000000000000p-1022"1600);1601// Subnormals.1602assert_eq!(1603Ieee64::with_float(f64::MIN_POSITIVE / 2.0).to_string(),1604"0x0.8000000000000p-1022"1605);1606assert_eq!(1607Ieee64::with_float(f64::MIN_POSITIVE * f64::EPSILON).to_string(),1608"0x0.0000000000001p-1022"1609);1610assert_eq!(Ieee64::with_float(f64::INFINITY).to_string(), "+Inf");1611assert_eq!(Ieee64::with_float(f64::NEG_INFINITY).to_string(), "-Inf");1612assert_eq!(Ieee64::with_float(f64::NAN).to_string(), "+NaN");1613assert_eq!(Ieee64::with_float(-f64::NAN).to_string(), "-NaN");1614// Construct some qNaNs with payloads.1615assert_eq!(1616Ieee64::with_bits(0x7ff8000000000001).to_string(),1617"+NaN:0x1"1618);1619assert_eq!(1620Ieee64::with_bits(0x7ffc000000000001).to_string(),1621"+NaN:0x4000000000001"1622);1623// Signaling NaNs.1624assert_eq!(1625Ieee64::with_bits(0x7ff0000000000001).to_string(),1626"+sNaN:0x1"1627);1628assert_eq!(1629Ieee64::with_bits(0x7ff4000000000001).to_string(),1630"+sNaN:0x4000000000001"1631);1632}16331634#[test]1635fn parse_ieee64() {1636parse_ok::<Ieee64>("0.0", "0.0");1637parse_ok::<Ieee64>("-0.0", "-0.0");1638parse_ok::<Ieee64>("0x0", "0.0");1639parse_ok::<Ieee64>("0x0.0", "0.0");1640parse_ok::<Ieee64>("0x.0", "0.0");1641parse_ok::<Ieee64>("0x0.", "0.0");1642parse_ok::<Ieee64>("0x1", "0x1.0000000000000p0");1643parse_ok::<Ieee64>("-0x1", "-0x1.0000000000000p0");1644parse_ok::<Ieee64>("0x10", "0x1.0000000000000p4");1645parse_ok::<Ieee64>("0x10.0", "0x1.0000000000000p4");1646parse_err::<Ieee64>("0.", "Float must be hexadecimal");1647parse_err::<Ieee64>(".0", "Float must be hexadecimal");1648parse_err::<Ieee64>("0", "Float must be hexadecimal");1649parse_err::<Ieee64>("-0", "Float must be hexadecimal");1650parse_err::<Ieee64>(".", "Float must be hexadecimal");1651parse_err::<Ieee64>("", "Float must be hexadecimal");1652parse_err::<Ieee64>("-", "Float must be hexadecimal");1653parse_err::<Ieee64>("0x", "No digits");1654parse_err::<Ieee64>("0x..", "Multiple radix points");16551656// Check significant bits.1657parse_ok::<Ieee64>("0x0.fffffffffffff8", "0x1.fffffffffffffp-1");1658parse_ok::<Ieee64>("0x1.fffffffffffff", "0x1.fffffffffffffp0");1659parse_ok::<Ieee64>("0x3.ffffffffffffe", "0x1.fffffffffffffp1");1660parse_ok::<Ieee64>("0x7.ffffffffffffc", "0x1.fffffffffffffp2");1661parse_ok::<Ieee64>("0xf.ffffffffffff8", "0x1.fffffffffffffp3");1662parse_err::<Ieee64>("0x3.fffffffffffff", "Too many significant bits");1663parse_err::<Ieee64>("0x001.fffffe000000000000000000000000", "Too many digits");16641665// Exponents.1666parse_ok::<Ieee64>("0x1p3", "0x1.0000000000000p3");1667parse_ok::<Ieee64>("0x1p-3", "0x1.0000000000000p-3");1668parse_ok::<Ieee64>("0x1.0p3", "0x1.0000000000000p3");1669parse_ok::<Ieee64>("0x2.0p3", "0x1.0000000000000p4");1670parse_ok::<Ieee64>("0x1.0p1023", "0x1.0000000000000p1023");1671parse_ok::<Ieee64>("0x1.0p-1022", "0x1.0000000000000p-1022");1672parse_ok::<Ieee64>("0x0.1p-1018", "0x1.0000000000000p-1022");1673parse_err::<Ieee64>("0x2.0p1023", "Magnitude too large");16741675// Subnormals.1676parse_ok::<Ieee64>("0x1.0p-1023", "0x0.8000000000000p-1022");1677parse_ok::<Ieee64>("0x1.0p-1074", "0x0.0000000000001p-1022");1678parse_ok::<Ieee64>("0x0.0000000000001p-1022", "0x0.0000000000001p-1022");1679parse_err::<Ieee64>("0x0.10000000000008p-1022", "Subnormal underflow");1680parse_err::<Ieee64>("0x1.8p-1074", "Subnormal underflow");1681parse_err::<Ieee64>("0x1.0p-1075", "Magnitude too small");16821683// NaNs and Infs.1684parse_ok::<Ieee64>("Inf", "+Inf");1685parse_ok::<Ieee64>("-Inf", "-Inf");1686parse_ok::<Ieee64>("NaN", "+NaN");1687parse_ok::<Ieee64>("-NaN", "-NaN");1688parse_ok::<Ieee64>("NaN:0x0", "+NaN");1689parse_err::<Ieee64>("NaN:", "Float must be hexadecimal");1690parse_err::<Ieee64>("NaN:0", "Float must be hexadecimal");1691parse_err::<Ieee64>("NaN:0x", "Invalid NaN payload");1692parse_ok::<Ieee64>("NaN:0x000001", "+NaN:0x1");1693parse_ok::<Ieee64>("NaN:0x4000000000001", "+NaN:0x4000000000001");1694parse_err::<Ieee64>("NaN:0x8000000000001", "Invalid NaN payload");1695parse_ok::<Ieee64>("sNaN:0x1", "+sNaN:0x1");1696parse_err::<Ieee64>("sNaN:0x0", "Invalid sNaN payload");1697parse_ok::<Ieee64>("sNaN:0x4000000000001", "+sNaN:0x4000000000001");1698parse_err::<Ieee64>("sNaN:0x8000000000001", "Invalid sNaN payload");1699}17001701#[test]1702fn pow2_ieee64() {1703assert_eq!(Ieee64::pow2(0).to_string(), "0x1.0000000000000p0");1704assert_eq!(Ieee64::pow2(1).to_string(), "0x1.0000000000000p1");1705assert_eq!(Ieee64::pow2(-1).to_string(), "0x1.0000000000000p-1");1706assert_eq!(Ieee64::pow2(1023).to_string(), "0x1.0000000000000p1023");1707assert_eq!(Ieee64::pow2(-1022).to_string(), "0x1.0000000000000p-1022");17081709assert_eq!((-Ieee64::pow2(1)).to_string(), "-0x1.0000000000000p1");1710}17111712#[test]1713fn fcvt_to_sint_negative_overflow_ieee64() {1714for n in [8, 16, 32] {1715assert_eq!(1716-((1u64 << (n - 1)) as f64) - 1.0,1717Ieee64::fcvt_to_sint_negative_overflow(n).as_f64(),1718"n = {n}"1719);1720}1721}17221723#[test]1724fn format_ieee128() {1725assert_eq!(1726Ieee128::with_bits(0x00000000000000000000000000000000).to_string(), // 0.01727"0.0"1728);1729assert_eq!(1730Ieee128::with_bits(0x80000000000000000000000000000000).to_string(), // -0.01731"-0.0"1732);1733assert_eq!(1734Ieee128::with_bits(0x3fff0000000000000000000000000000).to_string(), // 1.01735"0x1.0000000000000000000000000000p0"1736);1737assert_eq!(1738Ieee128::with_bits(0x3fff8000000000000000000000000000).to_string(), // 1.51739"0x1.8000000000000000000000000000p0"1740);1741assert_eq!(1742Ieee128::with_bits(0x3ffe0000000000000000000000000000).to_string(), // 0.51743"0x1.0000000000000000000000000000p-1"1744);1745assert_eq!(1746Ieee128::with_bits(0x3f8f0000000000000000000000000000).to_string(), // `f128::EPSILON`1747"0x1.0000000000000000000000000000p-112"1748);1749assert_eq!(1750Ieee128::with_bits(0xfffeffffffffffffffffffffffffffff).to_string(), // `f128::MIN`1751"-0x1.ffffffffffffffffffffffffffffp16383"1752);1753assert_eq!(1754Ieee128::with_bits(0x7ffeffffffffffffffffffffffffffff).to_string(), // `f128::MAX`1755"0x1.ffffffffffffffffffffffffffffp16383"1756);1757// Smallest positive normal number.1758assert_eq!(1759Ieee128::with_bits(0x00010000000000000000000000000000).to_string(), // `f128::MIN_POSITIVE`1760"0x1.0000000000000000000000000000p-16382"1761);1762// Subnormals.1763assert_eq!(1764Ieee128::with_bits(0x00008000000000000000000000000000).to_string(), // `f128::MIN_POSITIVE / 2.0`1765"0x0.8000000000000000000000000000p-16382"1766);1767assert_eq!(1768Ieee128::with_bits(0x00000000000000000000000000000001).to_string(), // `f128::MIN_POSITIVE * f128::EPSILON`1769"0x0.0000000000000000000000000001p-16382"1770);1771assert_eq!(1772Ieee128::with_bits(0x7fff0000000000000000000000000000).to_string(), // `f128::INFINITY`1773"+Inf"1774);1775assert_eq!(1776Ieee128::with_bits(0xffff0000000000000000000000000000).to_string(), // `f128::NEG_INFINITY`1777"-Inf"1778);1779assert_eq!(1780Ieee128::with_bits(0x7fff8000000000000000000000000000).to_string(), // `f128::NAN`1781"+NaN"1782);1783assert_eq!(1784Ieee128::with_bits(0xffff8000000000000000000000000000).to_string(), // `-f128::NAN`1785"-NaN"1786);1787// Construct some qNaNs with payloads.1788assert_eq!(1789Ieee128::with_bits(0x7fff8000000000000000000000000001).to_string(),1790"+NaN:0x1"1791);1792assert_eq!(1793Ieee128::with_bits(0x7fffc000000000000000000000000001).to_string(),1794"+NaN:0x4000000000000000000000000001"1795);1796// Signaling NaNs.1797assert_eq!(1798Ieee128::with_bits(0x7fff0000000000000000000000000001).to_string(),1799"+sNaN:0x1"1800);1801assert_eq!(1802Ieee128::with_bits(0x7fff4000000000000000000000000001).to_string(),1803"+sNaN:0x4000000000000000000000000001"1804);1805}18061807#[test]1808fn parse_ieee128() {1809parse_ok::<Ieee128>("0.0", "0.0");1810parse_ok::<Ieee128>("-0.0", "-0.0");1811parse_ok::<Ieee128>("0x0", "0.0");1812parse_ok::<Ieee128>("0x0.0", "0.0");1813parse_ok::<Ieee128>("0x.0", "0.0");1814parse_ok::<Ieee128>("0x0.", "0.0");1815parse_ok::<Ieee128>("0x1", "0x1.0000000000000000000000000000p0");1816parse_ok::<Ieee128>("-0x1", "-0x1.0000000000000000000000000000p0");1817parse_ok::<Ieee128>("0x10", "0x1.0000000000000000000000000000p4");1818parse_ok::<Ieee128>("0x10.0", "0x1.0000000000000000000000000000p4");1819parse_err::<Ieee128>("0.", "Float must be hexadecimal");1820parse_err::<Ieee128>(".0", "Float must be hexadecimal");1821parse_err::<Ieee128>("0", "Float must be hexadecimal");1822parse_err::<Ieee128>("-0", "Float must be hexadecimal");1823parse_err::<Ieee128>(".", "Float must be hexadecimal");1824parse_err::<Ieee128>("", "Float must be hexadecimal");1825parse_err::<Ieee128>("-", "Float must be hexadecimal");1826parse_err::<Ieee128>("0x", "No digits");1827parse_err::<Ieee128>("0x..", "Multiple radix points");18281829// Check significant bits.1830parse_ok::<Ieee128>(1831"0x0.ffffffffffffffffffffffffffff8",1832"0x1.ffffffffffffffffffffffffffffp-1",1833);1834parse_ok::<Ieee128>(1835"0x1.ffffffffffffffffffffffffffff",1836"0x1.ffffffffffffffffffffffffffffp0",1837);1838parse_ok::<Ieee128>(1839"0x3.fffffffffffffffffffffffffffe",1840"0x1.ffffffffffffffffffffffffffffp1",1841);1842parse_ok::<Ieee128>(1843"0x7.fffffffffffffffffffffffffffc",1844"0x1.ffffffffffffffffffffffffffffp2",1845);1846parse_ok::<Ieee128>(1847"0xf.fffffffffffffffffffffffffff8",1848"0x1.ffffffffffffffffffffffffffffp3",1849);1850parse_err::<Ieee128>(1851"0x3.ffffffffffffffffffffffffffff",1852"Too many significant bits",1853);1854parse_err::<Ieee128>("0x001.fffffe000000000000000000000000", "Too many digits");18551856// Exponents.1857parse_ok::<Ieee128>("0x1p3", "0x1.0000000000000000000000000000p3");1858parse_ok::<Ieee128>("0x1p-3", "0x1.0000000000000000000000000000p-3");1859parse_ok::<Ieee128>("0x1.0p3", "0x1.0000000000000000000000000000p3");1860parse_ok::<Ieee128>("0x2.0p3", "0x1.0000000000000000000000000000p4");1861parse_ok::<Ieee128>("0x1.0p16383", "0x1.0000000000000000000000000000p16383");1862parse_ok::<Ieee128>("0x1.0p-16382", "0x1.0000000000000000000000000000p-16382");1863parse_ok::<Ieee128>("0x0.1p-16378", "0x1.0000000000000000000000000000p-16382");1864parse_err::<Ieee128>("0x2.0p16383", "Magnitude too large");18651866// Subnormals.1867parse_ok::<Ieee128>("0x1.0p-16383", "0x0.8000000000000000000000000000p-16382");1868parse_ok::<Ieee128>("0x1.0p-16494", "0x0.0000000000000000000000000001p-16382");1869parse_ok::<Ieee128>(1870"0x0.0000000000000000000000000001p-16382",1871"0x0.0000000000000000000000000001p-16382",1872);1873parse_err::<Ieee128>(1874"0x0.10000000000000000000000000008p-16382",1875"Subnormal underflow",1876);1877parse_err::<Ieee128>("0x1.8p-16494", "Subnormal underflow");1878parse_err::<Ieee128>("0x1.0p-16495", "Magnitude too small");18791880// NaNs and Infs.1881parse_ok::<Ieee128>("Inf", "+Inf");1882parse_ok::<Ieee128>("-Inf", "-Inf");1883parse_ok::<Ieee128>("NaN", "+NaN");1884parse_ok::<Ieee128>("-NaN", "-NaN");1885parse_ok::<Ieee128>("NaN:0x0", "+NaN");1886parse_err::<Ieee128>("NaN:", "Float must be hexadecimal");1887parse_err::<Ieee128>("NaN:0", "Float must be hexadecimal");1888parse_err::<Ieee128>("NaN:0x", "Invalid NaN payload");1889parse_ok::<Ieee128>("NaN:0x000001", "+NaN:0x1");1890parse_ok::<Ieee128>(1891"NaN:0x4000000000000000000000000001",1892"+NaN:0x4000000000000000000000000001",1893);1894parse_err::<Ieee128>("NaN:0x8000000000000000000000000001", "Invalid NaN payload");1895parse_ok::<Ieee128>("sNaN:0x1", "+sNaN:0x1");1896parse_err::<Ieee128>("sNaN:0x0", "Invalid sNaN payload");1897parse_ok::<Ieee128>(1898"sNaN:0x4000000000000000000000000001",1899"+sNaN:0x4000000000000000000000000001",1900);1901parse_err::<Ieee128>(1902"sNaN:0x8000000000000000000000000001",1903"Invalid sNaN payload",1904);1905}19061907#[test]1908fn pow2_ieee128() {1909assert_eq!(1910Ieee128::pow2(0).to_string(),1911"0x1.0000000000000000000000000000p0"1912);1913assert_eq!(1914Ieee128::pow2(1).to_string(),1915"0x1.0000000000000000000000000000p1"1916);1917assert_eq!(1918Ieee128::pow2(-1).to_string(),1919"0x1.0000000000000000000000000000p-1"1920);1921assert_eq!(1922Ieee128::pow2(16383).to_string(),1923"0x1.0000000000000000000000000000p16383"1924);1925assert_eq!(1926Ieee128::pow2(-16382).to_string(),1927"0x1.0000000000000000000000000000p-16382"1928);19291930assert_eq!(1931(-Ieee128::pow2(1)).to_string(),1932"-0x1.0000000000000000000000000000p1"1933);1934}19351936#[test]1937fn fcvt_to_sint_negative_overflow_ieee128() {1938// FIXME(#8312): Replace with commented out version once Rust f128 support is stabilised.1939// for n in [8, 16, 32, 64] {1940// assert_eq!(1941// -((1u128 << (n - 1)) as f128) - 1.0,1942// Ieee128::fcvt_to_sint_negative_overflow(n).as_f128(),1943// "n = {n}"1944// );1945// }1946for (n, expected) in [1947(8, "-0x1.0200000000000000000000000000p7"),1948(16, "-0x1.0002000000000000000000000000p15"),1949(32, "-0x1.0000000200000000000000000000p31"),1950(64, "-0x1.0000000000000002000000000000p63"),1951] {1952assert_eq!(1953expected,1954Ieee128::fcvt_to_sint_negative_overflow(n).to_string(),1955"n = {n}"1956);1957}1958}1959}196019611962