Path: blob/main/cranelift/codegen/src/ir/immediates.rs
3068 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};12use libm::Libm;13#[cfg(feature = "enable-serde")]14use serde_derive::{Deserialize, Serialize};1516/// Convert a type into a vector of bytes; all implementors in this file must use little-endian17/// orderings of bytes to match WebAssembly's little-endianness.18pub trait IntoBytes {19/// Return the little-endian byte representation of the implementing type.20fn into_bytes(self) -> Vec<u8>;21}2223impl IntoBytes for u8 {24fn into_bytes(self) -> Vec<u8> {25vec![self]26}27}2829impl IntoBytes for i8 {30fn into_bytes(self) -> Vec<u8> {31vec![self as u8]32}33}3435impl IntoBytes for i16 {36fn into_bytes(self) -> Vec<u8> {37self.to_le_bytes().to_vec()38}39}4041impl IntoBytes for i32 {42fn into_bytes(self) -> Vec<u8> {43self.to_le_bytes().to_vec()44}45}4647impl IntoBytes for Vec<u8> {48fn into_bytes(self) -> Vec<u8> {49self50}51}5253/// 64-bit immediate signed integer operand.54///55/// An `Imm64` operand can also be used to represent immediate values of smaller integer types by56/// sign-extending to `i64`.57#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]58#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]59pub struct Imm64(i64);6061impl Imm64 {62/// Create a new `Imm64` representing the signed number `x`.63pub fn new(x: i64) -> Self {64Self(x)65}6667/// Return self negated.68pub fn wrapping_neg(self) -> Self {69Self(self.0.wrapping_neg())70}7172/// Returns the value of this immediate.73pub fn bits(&self) -> i64 {74self.075}7677/// Mask this immediate to the given power-of-two bit width.78#[must_use]79pub(crate) fn mask_to_width(&self, bit_width: u32) -> Self {80debug_assert!(bit_width.is_power_of_two());8182if bit_width >= 64 {83return *self;84}8586let bit_width = i64::from(bit_width);87let mask = (1 << bit_width) - 1;88let masked = self.0 & mask;89Imm64(masked)90}9192/// Sign extend this immediate as if it were a signed integer of the given93/// power-of-two width.94#[must_use]95pub fn sign_extend_from_width(&self, bit_width: u32) -> Self {96debug_assert!(97bit_width.is_power_of_two(),98"{bit_width} is not a power of two"99);100101if bit_width >= 64 {102return *self;103}104105let bit_width = i64::from(bit_width);106let delta = 64 - bit_width;107let sign_extended = (self.0 << delta) >> delta;108Imm64(sign_extended)109}110111/// Zero extend this immediate as if it were an unsigned integer of the112/// given power-of-two width.113#[must_use]114pub fn zero_extend_from_width(&self, bit_width: u32) -> Self {115debug_assert!(116bit_width.is_power_of_two(),117"{bit_width} is not a power of two"118);119120if bit_width >= 64 {121return *self;122}123124let bit_width = u64::from(bit_width);125let delta = 64 - bit_width;126let zero_extended = (self.0.cast_unsigned() << delta) >> delta;127Imm64(zero_extended.cast_signed())128}129}130131impl From<Imm64> for i64 {132fn from(val: Imm64) -> i64 {133val.0134}135}136137impl IntoBytes for Imm64 {138fn into_bytes(self) -> Vec<u8> {139self.0.to_le_bytes().to_vec()140}141}142143impl From<i64> for Imm64 {144fn from(x: i64) -> Self {145Self(x)146}147}148149impl Display for Imm64 {150fn fmt(&self, f: &mut Formatter) -> fmt::Result {151let x = self.0;152if x < 10_000 {153// Use decimal for small and negative numbers.154write!(f, "{x}")155} else {156write_hex(x as u64, f)157}158}159}160161/// Parse a 64-bit signed number.162fn parse_i64(s: &str) -> Result<i64, &'static str> {163let negative = s.starts_with('-');164let s2 = if negative || s.starts_with('+') {165&s[1..]166} else {167s168};169170let mut value = parse_u64(s2)?;171172// We support the range-and-a-half from -2^63 .. 2^64-1.173if negative {174value = value.wrapping_neg();175// Don't allow large negative values to wrap around and become positive.176if value as i64 > 0 {177return Err("Negative number too small");178}179}180Ok(value as i64)181}182183impl FromStr for Imm64 {184type Err = &'static str;185186// Parse a decimal or hexadecimal `Imm64`, formatted as above.187fn from_str(s: &str) -> Result<Self, &'static str> {188parse_i64(s).map(Self::new)189}190}191192/// 64-bit immediate unsigned integer operand.193///194/// A `Uimm64` operand can also be used to represent immediate values of smaller integer types by195/// zero-extending to `i64`.196#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]197#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]198pub struct Uimm64(u64);199200impl Uimm64 {201/// Create a new `Uimm64` representing the unsigned number `x`.202pub fn new(x: u64) -> Self {203Self(x)204}205206/// Return self negated.207pub fn wrapping_neg(self) -> Self {208Self(self.0.wrapping_neg())209}210}211212impl From<Uimm64> for u64 {213fn from(val: Uimm64) -> u64 {214val.0215}216}217218impl From<u64> for Uimm64 {219fn from(x: u64) -> Self {220Self(x)221}222}223224/// Hexadecimal with a multiple of 4 digits and group separators:225///226/// 0xfff0227/// 0x0001_ffff228/// 0xffff_ffff_fff8_4400229///230fn write_hex(x: u64, f: &mut Formatter) -> fmt::Result {231let mut pos = (64 - x.leading_zeros() - 1) & 0xf0;232write!(f, "0x{:04x}", (x >> pos) & 0xffff)?;233while pos > 0 {234pos -= 16;235write!(f, "_{:04x}", (x >> pos) & 0xffff)?;236}237Ok(())238}239240impl Display for Uimm64 {241fn fmt(&self, f: &mut Formatter) -> fmt::Result {242let x = self.0;243if x < 10_000 {244// Use decimal for small numbers.245write!(f, "{x}")246} else {247write_hex(x, f)248}249}250}251252/// Parse a 64-bit unsigned number.253fn parse_u64(s: &str) -> Result<u64, &'static str> {254let mut value: u64 = 0;255let mut digits = 0;256257if s.starts_with("-0x") {258return Err("Invalid character in hexadecimal number");259} else if let Some(num) = s.strip_prefix("0x") {260// Hexadecimal.261for ch in num.chars() {262match ch.to_digit(16) {263Some(digit) => {264digits += 1;265if digits > 16 {266return Err("Too many hexadecimal digits");267}268// This can't overflow given the digit limit.269value = (value << 4) | u64::from(digit);270}271None => {272// Allow embedded underscores, but fail on anything else.273if ch != '_' {274return Err("Invalid character in hexadecimal number");275}276}277}278}279} else {280// Decimal number, possibly negative.281for ch in s.chars() {282match ch.to_digit(10) {283Some(digit) => {284digits += 1;285match value.checked_mul(10) {286None => return Err("Too large decimal number"),287Some(v) => value = v,288}289match value.checked_add(u64::from(digit)) {290None => return Err("Too large decimal number"),291Some(v) => value = v,292}293}294None => {295// Allow embedded underscores, but fail on anything else.296if ch != '_' {297return Err("Invalid character in decimal number");298}299}300}301}302}303304if digits == 0 {305return Err("No digits in number");306}307308Ok(value)309}310311impl FromStr for Uimm64 {312type Err = &'static str;313314// Parse a decimal or hexadecimal `Uimm64`, formatted as above.315fn from_str(s: &str) -> Result<Self, &'static str> {316parse_u64(s).map(Self::new)317}318}319320/// 8-bit unsigned integer immediate operand.321///322/// This is used to indicate lane indexes typically.323pub type Uimm8 = u8;324325/// A 32-bit unsigned integer immediate operand.326///327/// This is used to represent sizes of memory objects.328#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]329#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]330pub struct Uimm32(u32);331332impl From<Uimm32> for u32 {333fn from(val: Uimm32) -> u32 {334val.0335}336}337338impl From<Uimm32> for u64 {339fn from(val: Uimm32) -> u64 {340val.0.into()341}342}343344impl From<Uimm32> for i64 {345fn from(val: Uimm32) -> i64 {346i64::from(val.0)347}348}349350impl From<u32> for Uimm32 {351fn from(x: u32) -> Self {352Self(x)353}354}355356impl Display for Uimm32 {357fn fmt(&self, f: &mut Formatter) -> fmt::Result {358if self.0 < 10_000 {359write!(f, "{}", self.0)360} else {361write_hex(u64::from(self.0), f)362}363}364}365366impl FromStr for Uimm32 {367type Err = &'static str;368369// Parse a decimal or hexadecimal `Uimm32`, formatted as above.370fn from_str(s: &str) -> Result<Self, &'static str> {371parse_i64(s).and_then(|x| {372if 0 <= x && x <= i64::from(u32::MAX) {373Ok(Self(x as u32))374} else {375Err("Uimm32 out of range")376}377})378}379}380381/// A 128-bit immediate operand.382///383/// This is used as an immediate value in SIMD instructions.384#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]385#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]386pub struct V128Imm(pub [u8; 16]);387388impl V128Imm {389/// Iterate over the bytes in the constant.390pub fn bytes(&self) -> impl Iterator<Item = &u8> {391self.0.iter()392}393394/// Convert the immediate into a vector.395pub fn to_vec(self) -> Vec<u8> {396self.0.to_vec()397}398399/// Convert the immediate into a slice.400pub fn as_slice(&self) -> &[u8] {401&self.0[..]402}403}404405impl From<&[u8]> for V128Imm {406fn from(slice: &[u8]) -> Self {407assert_eq!(slice.len(), 16);408let mut buffer = [0; 16];409buffer.copy_from_slice(slice);410Self(buffer)411}412}413414impl From<u128> for V128Imm {415fn from(val: u128) -> Self {416V128Imm(val.to_le_bytes())417}418}419420/// 32-bit signed immediate offset.421///422/// This is used to encode an immediate offset for load/store instructions. All supported ISAs have423/// a maximum load/store offset that fits in an `i32`.424#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]425#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]426pub struct Offset32(i32);427428impl Offset32 {429/// Create a new `Offset32` representing the signed number `x`.430pub fn new(x: i32) -> Self {431Self(x)432}433434/// Create a new `Offset32` representing the signed number `x` if possible.435pub fn try_from_i64(x: i64) -> Option<Self> {436let x = i32::try_from(x).ok()?;437Some(Self::new(x))438}439440/// Add in the signed number `x` if possible.441pub fn try_add_i64(self, x: i64) -> Option<Self> {442let x = i32::try_from(x).ok()?;443let ret = self.0.checked_add(x)?;444Some(Self::new(ret))445}446}447448impl From<Offset32> for i32 {449fn from(val: Offset32) -> i32 {450val.0451}452}453454impl From<Offset32> for i64 {455fn from(val: Offset32) -> i64 {456i64::from(val.0)457}458}459460impl From<i32> for Offset32 {461fn from(x: i32) -> Self {462Self(x)463}464}465466impl From<u8> for Offset32 {467fn from(val: u8) -> Offset32 {468Self(val.into())469}470}471472impl Display for Offset32 {473fn fmt(&self, f: &mut Formatter) -> fmt::Result {474// 0 displays as an empty offset.475if self.0 == 0 {476return Ok(());477}478479// Always include a sign.480write!(f, "{}", if self.0 < 0 { '-' } else { '+' })?;481482let val = i64::from(self.0).abs();483if val < 10_000 {484write!(f, "{val}")485} else {486write_hex(val as u64, f)487}488}489}490491impl FromStr for Offset32 {492type Err = &'static str;493494// Parse a decimal or hexadecimal `Offset32`, formatted as above.495fn from_str(s: &str) -> Result<Self, &'static str> {496if !(s.starts_with('-') || s.starts_with('+')) {497return Err("Offset must begin with sign");498}499parse_i64(s).and_then(|x| {500if i64::from(i32::MIN) <= x && x <= i64::from(i32::MAX) {501Ok(Self::new(x as i32))502} else {503Err("Offset out of range")504}505})506}507}508509// FIXME(rust-lang/rust#83527): Replace with `${ignore()}` once it is stabilised.510macro_rules! ignore {511($($t:tt)*) => {};512}513514macro_rules! ieee_float {515(516name = $name:ident,517bits = $bits:literal,518significand_bits = $significand_bits:literal,519bits_ty = $bits_ty:ident,520float_ty = $float_ty:ident,521$(as_float = $as_float:ident,)?522$(rust_type_not_stable = $rust_type_not_stable:ident,)?523) => {524/// An IEEE525#[doc = concat!("binary", stringify!($bits))]526/// immediate floating point value, represented as a527#[doc = stringify!($bits_ty)]528/// containing the bit pattern.529///530/// We specifically avoid using a531#[doc = stringify!($float_ty)]532/// here since some architectures may silently alter floats.533/// See: <https://github.com/bytecodealliance/wasmtime/pull/2251#discussion_r498508646>534///535/// The [PartialEq] and [Hash] implementations are over the underlying bit pattern, but536/// [PartialOrd] respects IEEE754 semantics.537///538/// All bit patterns are allowed.539#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]540#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]541#[repr(C)]542pub struct $name {543bits: $bits_ty544}545546impl $name {547const BITS: u8 = $bits;548const SIGNIFICAND_BITS: u8 = $significand_bits;549const EXPONENT_BITS: u8 = Self::BITS - Self::SIGNIFICAND_BITS - 1;550const SIGN_MASK: $bits_ty = 1 << (Self::EXPONENT_BITS + Self::SIGNIFICAND_BITS);551const SIGNIFICAND_MASK: $bits_ty = $bits_ty::MAX >> (Self::EXPONENT_BITS + 1);552const EXPONENT_MASK: $bits_ty = !Self::SIGN_MASK & !Self::SIGNIFICAND_MASK;553/// The positive WebAssembly canonical NaN.554pub const NAN: Self = Self::with_bits(Self::EXPONENT_MASK | (1 << (Self::SIGNIFICAND_BITS - 1)));555556/// Create a new557#[doc = concat!("`", stringify!($name), "`")]558/// containing the bits of `bits`.559pub const fn with_bits(bits: $bits_ty) -> Self {560Self { bits }561}562563/// Get the bitwise representation.564pub fn bits(self) -> $bits_ty {565self.bits566}567568$(569/// Create a new570#[doc = concat!("`", stringify!($name), "`")]571/// representing the number `x`.572pub fn with_float(x: $float_ty) -> Self {573Self::with_bits(x.to_bits())574}575576/// Converts `self` to a Rust577#[doc = concat!("`", stringify!($float_ty), "`.")]578pub fn $as_float(self) -> $float_ty {579$float_ty::from_bits(self.bits())580}581)?582583/// Computes the absolute value of `self`.584pub fn abs(self) -> Self {585Self::with_bits(self.bits() & !Self::SIGN_MASK)586}587588/// Returns a number composed of the magnitude of `self` and the sign of `sign`.589pub fn copysign(self, sign: Self) -> Self {590Self::with_bits((self.bits() & !Self::SIGN_MASK) | (sign.bits() & Self::SIGN_MASK))591}592593/// Returns the minimum of `self` and `other`, following the WebAssembly/IEEE 754-2019 definition.594pub fn minimum(self, other: Self) -> Self {595// FIXME: Replace with Rust float method once it is stabilised.596if self.is_nan() || other.is_nan() {597Self::NAN598} else if self.is_zero() && other.is_zero() {599if self.is_negative() {600self601} else {602other603}604} else if self <= other {605self606} else {607other608}609}610611/// Returns the maximum of `self` and `other`, following the WebAssembly/IEEE 754-2019 definition.612pub fn maximum(self, other: Self) -> Self {613// FIXME: Replace with Rust float method once it is stabilised.614if self.is_nan() || other.is_nan() {615Self::NAN616} else if self.is_zero() && other.is_zero() {617if self.is_positive() {618self619} else {620other621}622} else if self >= other {623self624} else {625other626}627}628629/// Create an630#[doc = concat!("`", stringify!($name), "`")]631/// number representing `2.0^n`.632pub fn pow2<I: Into<i32>>(n: I) -> Self {633let n = n.into();634let w = Self::EXPONENT_BITS;635let t = Self::SIGNIFICAND_BITS;636let bias = (1 << (w - 1)) - 1;637let exponent = n + bias;638assert!(exponent > 0, "Underflow n={}", n);639assert!(exponent < (1 << w) + 1, "Overflow n={}", n);640Self::with_bits((exponent as $bits_ty) << t)641}642643/// Create an644#[doc = concat!("`", stringify!($name), "`")]645/// number representing the greatest negative value not convertible from646#[doc = concat!("`", stringify!($float_ty), "`")]647/// to a signed integer with width n.648pub fn fcvt_to_sint_negative_overflow<I: Into<i32>>(n: I) -> Self {649let n = n.into();650debug_assert!(n < i32::from(Self::BITS));651debug_assert!(i32::from(Self::SIGNIFICAND_BITS) + 1 - n < i32::from(Self::BITS));652Self::with_bits((1 << (Self::BITS - 1)) | Self::pow2(n - 1).bits() | (1 << (i32::from(Self::SIGNIFICAND_BITS) + 1 - n)))653}654655/// Check if the value is a NaN. For656#[doc = concat!("`", stringify!($name), "`,")]657/// this means checking that all the exponent bits are set and the significand is non-zero.658pub fn is_nan(self) -> bool {659self.abs().bits() > Self::EXPONENT_MASK660}661662/// Returns true if `self` has a negative sign, including 0.0, NaNs with positive sign bit and positive infinity.663pub fn is_positive(self) -> bool {664!self.is_negative()665}666667/// Returns true if `self` has a negative sign, including -0.0, NaNs with negative sign bit and negative infinity.668pub fn is_negative(self) -> bool {669self.bits() & Self::SIGN_MASK == Self::SIGN_MASK670}671672/// Returns `true` if `self` is positive or negative zero.673pub fn is_zero(self) -> bool {674self.abs().bits() == 0675}676677/// Returns `None` if `self` is a NaN and `Some(self)` otherwise.678pub fn non_nan(self) -> Option<Self> {679Some(self).filter(|f| !f.is_nan())680}681682$(683/// Returns the square root of `self`.684pub fn sqrt(self) -> Self {685Self::with_float(Libm::<$float_ty>::sqrt(self.$as_float()))686}687688/// Returns the smallest integer greater than or equal to `self`.689pub fn ceil(self) -> Self {690Self::with_float(Libm::<$float_ty>::ceil(self.$as_float()))691}692693/// Returns the largest integer less than or equal to `self`.694pub fn floor(self) -> Self {695Self::with_float(Libm::<$float_ty>::floor(self.$as_float()))696}697698/// Returns the integer part of `self`. This means that non-integer numbers are always truncated towards zero.699pub fn trunc(self) -> Self {700Self::with_float(Libm::<$float_ty>::trunc(self.$as_float()))701}702703/// Returns the nearest integer to `self`. Rounds half-way cases to the number704/// with an even least significant digit.705pub fn round_ties_even(self) -> Self {706Self::with_float(Libm::<$float_ty>::roundeven(self.$as_float()))707}708)?709}710711impl PartialOrd for $name {712fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {713$(self.$as_float().partial_cmp(&rhs.$as_float()))?714$(715ignore!($rust_type_not_stable);716// FIXME(#8312): Use builtin Rust comparisons once `f16` and `f128` support is stabalised.717if self.is_nan() || rhs.is_nan() {718// One of the floats is a NaN.719return None;720}721if self.is_zero() || rhs.is_zero() {722// Zeros are always equal regardless of sign.723return Some(Ordering::Equal);724}725let lhs_positive = self.is_positive();726let rhs_positive = rhs.is_positive();727if lhs_positive != rhs_positive {728// Different signs: negative < positive729return lhs_positive.partial_cmp(&rhs_positive);730}731// Finite or infinity will order correctly with an integer comparison of the bits.732if lhs_positive {733self.bits().partial_cmp(&rhs.bits())734} else {735// Reverse the comparison when both floats are negative.736rhs.bits().partial_cmp(&self.bits())737}738)?739}740}741742impl Display for $name {743fn fmt(&self, f: &mut Formatter) -> fmt::Result {744format_float(u128::from(self.bits()), Self::EXPONENT_BITS, Self::SIGNIFICAND_BITS, f)745}746}747748impl FromStr for $name {749type Err = &'static str;750751fn from_str(s: &str) -> Result<Self, &'static str> {752match parse_float(s, Self::EXPONENT_BITS, Self::SIGNIFICAND_BITS) {753Ok(b) => Ok(Self::with_bits(b.try_into().unwrap())),754Err(s) => Err(s),755}756}757}758759impl IntoBytes for $name {760fn into_bytes(self) -> Vec<u8> {761self.bits().to_le_bytes().to_vec()762}763}764765impl Neg for $name {766type Output = Self;767768fn neg(self) -> Self {769Self::with_bits(self.bits() ^ Self::SIGN_MASK)770}771}772773774775$(776impl From<$float_ty> for $name {777fn from(x: $float_ty) -> Self {778Self::with_float(x)779}780}781782impl Add for $name {783type Output = Self;784785fn add(self, rhs: Self) -> Self {786Self::with_float(self.$as_float() + rhs.$as_float())787}788}789790impl Sub for $name {791type Output = Self;792793fn sub(self, rhs: Self) -> Self {794Self::with_float(self.$as_float() - rhs.$as_float())795}796}797798impl Mul for $name {799type Output = Self;800801fn mul(self, rhs: Self) -> Self {802Self::with_float(self.$as_float() * rhs.$as_float())803}804}805806impl Div for $name {807type Output = Self;808809fn div(self, rhs: Self) -> Self::Output {810Self::with_float(self.$as_float() / rhs.$as_float())811}812}813)?814815impl BitAnd for $name {816type Output = Self;817818fn bitand(self, rhs: Self) -> Self {819Self::with_bits(self.bits() & rhs.bits())820}821}822823impl BitOr for $name {824type Output = Self;825826fn bitor(self, rhs: Self) -> Self {827Self::with_bits(self.bits() | rhs.bits())828}829}830831impl BitXor for $name {832type Output = Self;833834fn bitxor(self, rhs: Self) -> Self {835Self::with_bits(self.bits() ^ rhs.bits())836}837}838839impl Not for $name {840type Output = Self;841842fn not(self) -> Self {843Self::with_bits(!self.bits())844}845}846};847}848849ieee_float! {850name = Ieee16,851bits = 16,852significand_bits = 10,853bits_ty = u16,854float_ty = f16,855rust_type_not_stable = rust_type_not_stable,856}857858ieee_float! {859name = Ieee32,860bits = 32,861significand_bits = 23,862bits_ty = u32,863float_ty = f32,864as_float = as_f32,865}866867ieee_float! {868name = Ieee64,869bits = 64,870significand_bits = 52,871bits_ty = u64,872float_ty = f64,873as_float = as_f64,874}875876ieee_float! {877name = Ieee128,878bits = 128,879significand_bits = 112,880bits_ty = u128,881float_ty = f128,882rust_type_not_stable = rust_type_not_stable,883}884885/// Format a floating point number in a way that is reasonably human-readable, and that can be886/// converted back to binary without any rounding issues. The hexadecimal formatting of normal and887/// subnormal numbers is compatible with C99 and the `printf "%a"` format specifier. The NaN and Inf888/// formats are not supported by C99.889///890/// The encoding parameters are:891///892/// w - exponent field width in bits893/// t - trailing significand field width in bits894///895fn format_float(bits: u128, w: u8, t: u8, f: &mut Formatter) -> fmt::Result {896debug_assert!(w > 0 && w <= 16, "Invalid exponent range");897debug_assert!(1 + w + t <= 128, "Too large IEEE format for u128");898debug_assert!((t + w + 1).is_power_of_two(), "Unexpected IEEE format size");899900let max_e_bits = (1u128 << w) - 1;901let t_bits = bits & ((1u128 << t) - 1); // Trailing significand.902let e_bits = (bits >> t) & max_e_bits; // Biased exponent.903let sign_bit = (bits >> (w + t)) & 1;904905let bias: i32 = (1 << (w - 1)) - 1;906let e = e_bits as i32 - bias; // Unbiased exponent.907let emin = 1 - bias; // Minimum exponent.908909// How many hexadecimal digits are needed for the trailing significand?910let digits = (t + 3) / 4;911// Trailing significand left-aligned in `digits` hexadecimal digits.912let left_t_bits = t_bits << (4 * digits - t);913914// All formats share the leading sign.915if sign_bit != 0 {916write!(f, "-")?;917}918919if e_bits == 0 {920if t_bits == 0 {921// Zero.922write!(f, "0.0")923} else {924// Subnormal.925write!(926f,927"0x0.{0:01$x}p{2}",928left_t_bits,929usize::from(digits),930emin931)932}933} else if e_bits == max_e_bits {934// Always print a `+` or `-` sign for these special values.935// This makes them easier to parse as they can't be confused as identifiers.936if sign_bit == 0 {937write!(f, "+")?;938}939if t_bits == 0 {940// Infinity.941write!(f, "Inf")942} else {943// NaN.944let payload = t_bits & ((1 << (t - 1)) - 1);945if t_bits & (1 << (t - 1)) != 0 {946// Quiet NaN.947if payload != 0 {948write!(f, "NaN:0x{payload:x}")949} else {950write!(f, "NaN")951}952} else {953// Signaling NaN.954write!(f, "sNaN:0x{payload:x}")955}956}957} else {958// Normal number.959write!(f, "0x1.{0:01$x}p{2}", left_t_bits, usize::from(digits), e)960}961}962963/// Parse a float using the same format as `format_float` above.964///965/// The encoding parameters are:966///967/// w - exponent field width in bits968/// t - trailing significand field width in bits969///970fn parse_float(s: &str, w: u8, t: u8) -> Result<u128, &'static str> {971debug_assert!(w > 0 && w <= 16, "Invalid exponent range");972debug_assert!(1 + w + t <= 128, "Too large IEEE format for u128");973debug_assert!((t + w + 1).is_power_of_two(), "Unexpected IEEE format size");974975let (sign_bit, s2) = if let Some(num) = s.strip_prefix('-') {976(1u128 << (t + w), num)977} else if let Some(num) = s.strip_prefix('+') {978(0, num)979} else {980(0, s)981};982983if !s2.starts_with("0x") {984let max_e_bits = ((1u128 << w) - 1) << t;985let quiet_bit = 1u128 << (t - 1);986987// The only decimal encoding allowed is 0.988if s2 == "0.0" {989return Ok(sign_bit);990}991992if s2 == "Inf" {993// +/- infinity: e = max, t = 0.994return Ok(sign_bit | max_e_bits);995}996if s2 == "NaN" {997// Canonical quiet NaN: e = max, t = quiet.998return Ok(sign_bit | max_e_bits | quiet_bit);999}1000if let Some(nan) = s2.strip_prefix("NaN:0x") {1001// Quiet NaN with payload.1002return match u128::from_str_radix(nan, 16) {1003Ok(payload) if payload < quiet_bit => {1004Ok(sign_bit | max_e_bits | quiet_bit | payload)1005}1006_ => Err("Invalid NaN payload"),1007};1008}1009if let Some(nan) = s2.strip_prefix("sNaN:0x") {1010// Signaling NaN with payload.1011return match u128::from_str_radix(nan, 16) {1012Ok(payload) if 0 < payload && payload < quiet_bit => {1013Ok(sign_bit | max_e_bits | payload)1014}1015_ => Err("Invalid sNaN payload"),1016};1017}10181019return Err("Float must be hexadecimal");1020}1021let s3 = &s2[2..];10221023let mut digits = 0u8;1024let mut digits_before_period: Option<u8> = None;1025let mut significand = 0u128;1026let mut exponent = 0i32;10271028for (idx, ch) in s3.char_indices() {1029match ch {1030'.' => {1031// This is the radix point. There can only be one.1032if digits_before_period != None {1033return Err("Multiple radix points");1034} else {1035digits_before_period = Some(digits);1036}1037}1038'p' => {1039// The following exponent is a decimal number.1040let exp_str = &s3[1 + idx..];1041match exp_str.parse::<i16>() {1042Ok(e) => {1043exponent = i32::from(e);1044break;1045}1046Err(_) => return Err("Bad exponent"),1047}1048}1049_ => match ch.to_digit(16) {1050Some(digit) => {1051digits += 1;1052if digits > 32 {1053return Err("Too many digits");1054}1055significand = (significand << 4) | u128::from(digit);1056}1057None => return Err("Invalid character"),1058},1059}1060}10611062if digits == 0 {1063return Err("No digits");1064}10651066if significand == 0 {1067// This is +/- 0.0.1068return Ok(sign_bit);1069}10701071// Number of bits appearing after the radix point.1072match digits_before_period {1073None => {} // No radix point present.1074Some(d) => exponent -= 4 * i32::from(digits - d),1075};10761077// Normalize the significand and exponent.1078let significant_bits = (128 - significand.leading_zeros()) as u8;1079if significant_bits > t + 1 {1080let adjust = significant_bits - (t + 1);1081if significand & ((1u128 << adjust) - 1) != 0 {1082return Err("Too many significant bits");1083}1084// Adjust significand down.1085significand >>= adjust;1086exponent += i32::from(adjust);1087} else {1088let adjust = t + 1 - significant_bits;1089significand <<= adjust;1090exponent -= i32::from(adjust);1091}1092debug_assert_eq!(significand >> t, 1);10931094// Trailing significand excludes the high bit.1095let t_bits = significand & ((1 << t) - 1);10961097let max_exp = (1i32 << w) - 2;1098let bias: i32 = (1 << (w - 1)) - 1;1099exponent += bias + i32::from(t);11001101if exponent > max_exp {1102Err("Magnitude too large")1103} else if exponent > 0 {1104// This is a normal number.1105let e_bits = (exponent as u128) << t;1106Ok(sign_bit | e_bits | t_bits)1107} else if 1 - exponent <= i32::from(t) {1108// This is a subnormal number: e = 0, t = significand bits.1109// Renormalize significand for exponent = 1.1110let adjust = 1 - exponent;1111if significand & ((1u128 << adjust) - 1) != 0 {1112Err("Subnormal underflow")1113} else {1114significand >>= adjust;1115Ok(sign_bit | significand)1116}1117} else {1118Err("Magnitude too small")1119}1120}11211122#[cfg(test)]1123mod tests {1124use super::*;1125use alloc::string::ToString;1126use core::{f32, f64};11271128#[test]1129fn format_imm64() {1130assert_eq!(Imm64(0).to_string(), "0");1131assert_eq!(Imm64(9999).to_string(), "9999");1132assert_eq!(Imm64(10000).to_string(), "0x2710");1133assert_eq!(Imm64(-9999).to_string(), "-9999");1134assert_eq!(Imm64(-10000).to_string(), "-10000");1135assert_eq!(Imm64(0xffff).to_string(), "0xffff");1136assert_eq!(Imm64(0x10000).to_string(), "0x0001_0000");1137}11381139#[test]1140fn format_uimm64() {1141assert_eq!(Uimm64(0).to_string(), "0");1142assert_eq!(Uimm64(9999).to_string(), "9999");1143assert_eq!(Uimm64(10000).to_string(), "0x2710");1144assert_eq!(Uimm64(-9999i64 as u64).to_string(), "0xffff_ffff_ffff_d8f1");1145assert_eq!(1146Uimm64(-10000i64 as u64).to_string(),1147"0xffff_ffff_ffff_d8f0"1148);1149assert_eq!(Uimm64(0xffff).to_string(), "0xffff");1150assert_eq!(Uimm64(0x10000).to_string(), "0x0001_0000");1151}11521153// Verify that `text` can be parsed as a `T` into a value that displays as `want`.1154#[track_caller]1155fn parse_ok<T: FromStr + Display>(text: &str, want: &str)1156where1157<T as FromStr>::Err: Display,1158{1159match text.parse::<T>() {1160Err(s) => panic!("\"{text}\".parse() error: {s}"),1161Ok(x) => assert_eq!(x.to_string(), want),1162}1163}11641165// Verify that `text` fails to parse as `T` with the error `msg`.1166fn parse_err<T: FromStr + Display>(text: &str, msg: &str)1167where1168<T as FromStr>::Err: Display,1169{1170match text.parse::<T>() {1171Err(s) => assert_eq!(s.to_string(), msg),1172Ok(x) => panic!("Wanted Err({msg}), but got {x}"),1173}1174}11751176#[test]1177fn parse_imm64() {1178parse_ok::<Imm64>("0", "0");1179parse_ok::<Imm64>("1", "1");1180parse_ok::<Imm64>("-0", "0");1181parse_ok::<Imm64>("-1", "-1");1182parse_ok::<Imm64>("0x0", "0");1183parse_ok::<Imm64>("0xf", "15");1184parse_ok::<Imm64>("-0x9", "-9");11851186// Probe limits.1187parse_ok::<Imm64>("0xffffffff_ffffffff", "-1");1188parse_ok::<Imm64>("0x80000000_00000000", "-9223372036854775808");1189parse_ok::<Imm64>("-0x80000000_00000000", "-9223372036854775808");1190parse_err::<Imm64>("-0x80000000_00000001", "Negative number too small");1191parse_ok::<Imm64>("18446744073709551615", "-1");1192parse_ok::<Imm64>("-9223372036854775808", "-9223372036854775808");1193// Overflow both the `checked_add` and `checked_mul`.1194parse_err::<Imm64>("18446744073709551616", "Too large decimal number");1195parse_err::<Imm64>("184467440737095516100", "Too large decimal number");1196parse_err::<Imm64>("-9223372036854775809", "Negative number too small");11971198// Underscores are allowed where digits go.1199parse_ok::<Imm64>("0_0", "0");1200parse_ok::<Imm64>("-_10_0", "-100");1201parse_ok::<Imm64>("_10_", "10");1202parse_ok::<Imm64>("0x97_88_bb", "0x0097_88bb");1203parse_ok::<Imm64>("0x_97_", "151");12041205parse_err::<Imm64>("", "No digits in number");1206parse_err::<Imm64>("-", "No digits in number");1207parse_err::<Imm64>("_", "No digits in number");1208parse_err::<Imm64>("0x", "No digits in number");1209parse_err::<Imm64>("0x_", "No digits in number");1210parse_err::<Imm64>("-0x", "No digits in number");1211parse_err::<Imm64>(" ", "Invalid character in decimal number");1212parse_err::<Imm64>("0 ", "Invalid character in decimal number");1213parse_err::<Imm64>(" 0", "Invalid character in decimal number");1214parse_err::<Imm64>("--", "Invalid character in decimal number");1215parse_err::<Imm64>("-0x-", "Invalid character in hexadecimal number");1216parse_err::<Imm64>("abc", "Invalid character in decimal number");1217parse_err::<Imm64>("-abc", "Invalid character in decimal number");12181219// Hex count overflow.1220parse_err::<Imm64>("0x0_0000_0000_0000_0000", "Too many hexadecimal digits");1221}12221223#[test]1224fn parse_uimm64() {1225parse_ok::<Uimm64>("0", "0");1226parse_ok::<Uimm64>("1", "1");1227parse_ok::<Uimm64>("0x0", "0");1228parse_ok::<Uimm64>("0xf", "15");1229parse_ok::<Uimm64>("0xffffffff_fffffff7", "0xffff_ffff_ffff_fff7");12301231// Probe limits.1232parse_ok::<Uimm64>("0xffffffff_ffffffff", "0xffff_ffff_ffff_ffff");1233parse_ok::<Uimm64>("0x80000000_00000000", "0x8000_0000_0000_0000");1234parse_ok::<Uimm64>("18446744073709551615", "0xffff_ffff_ffff_ffff");1235// Overflow both the `checked_add` and `checked_mul`.1236parse_err::<Uimm64>("18446744073709551616", "Too large decimal number");1237parse_err::<Uimm64>("184467440737095516100", "Too large decimal number");12381239// Underscores are allowed where digits go.1240parse_ok::<Uimm64>("0_0", "0");1241parse_ok::<Uimm64>("_10_", "10");1242parse_ok::<Uimm64>("0x97_88_bb", "0x0097_88bb");1243parse_ok::<Uimm64>("0x_97_", "151");12441245parse_err::<Uimm64>("", "No digits in number");1246parse_err::<Uimm64>("_", "No digits in number");1247parse_err::<Uimm64>("0x", "No digits in number");1248parse_err::<Uimm64>("0x_", "No digits in number");1249parse_err::<Uimm64>("-", "Invalid character in decimal number");1250parse_err::<Uimm64>("-0x", "Invalid character in hexadecimal number");1251parse_err::<Uimm64>(" ", "Invalid character in decimal number");1252parse_err::<Uimm64>("0 ", "Invalid character in decimal number");1253parse_err::<Uimm64>(" 0", "Invalid character in decimal number");1254parse_err::<Uimm64>("--", "Invalid character in decimal number");1255parse_err::<Uimm64>("-0x-", "Invalid character in hexadecimal number");1256parse_err::<Uimm64>("-0", "Invalid character in decimal number");1257parse_err::<Uimm64>("-1", "Invalid character in decimal number");1258parse_err::<Uimm64>("abc", "Invalid character in decimal number");1259parse_err::<Uimm64>("-abc", "Invalid character in decimal number");12601261// Hex count overflow.1262parse_err::<Uimm64>("0x0_0000_0000_0000_0000", "Too many hexadecimal digits");1263}12641265#[test]1266fn format_offset32() {1267assert_eq!(Offset32(0).to_string(), "");1268assert_eq!(Offset32(1).to_string(), "+1");1269assert_eq!(Offset32(-1).to_string(), "-1");1270assert_eq!(Offset32(9999).to_string(), "+9999");1271assert_eq!(Offset32(10000).to_string(), "+0x2710");1272assert_eq!(Offset32(-9999).to_string(), "-9999");1273assert_eq!(Offset32(-10000).to_string(), "-0x2710");1274assert_eq!(Offset32(0xffff).to_string(), "+0xffff");1275assert_eq!(Offset32(0x10000).to_string(), "+0x0001_0000");1276}12771278#[test]1279fn parse_offset32() {1280parse_ok::<Offset32>("+0", "");1281parse_ok::<Offset32>("+1", "+1");1282parse_ok::<Offset32>("-0", "");1283parse_ok::<Offset32>("-1", "-1");1284parse_ok::<Offset32>("+0x0", "");1285parse_ok::<Offset32>("+0xf", "+15");1286parse_ok::<Offset32>("-0x9", "-9");1287parse_ok::<Offset32>("-0x8000_0000", "-0x8000_0000");12881289parse_err::<Offset32>("+0x8000_0000", "Offset out of range");1290}12911292#[test]1293fn format_ieee16() {1294assert_eq!(Ieee16::with_bits(0).to_string(), "0.0"); // 0.01295assert_eq!(Ieee16::with_bits(0x8000).to_string(), "-0.0"); // -0.01296assert_eq!(Ieee16::with_bits(0x3c00).to_string(), "0x1.000p0"); // 1.01297assert_eq!(Ieee16::with_bits(0x3e00).to_string(), "0x1.800p0"); // 1.51298assert_eq!(Ieee16::with_bits(0x3800).to_string(), "0x1.000p-1"); // 0.51299assert_eq!(1300Ieee16::with_bits(0x1400).to_string(), // `f16::EPSILON`1301"0x1.000p-10"1302);1303assert_eq!(1304Ieee16::with_bits(0xfbff).to_string(), // `f16::MIN`1305"-0x1.ffcp15"1306);1307assert_eq!(1308Ieee16::with_bits(0x7bff).to_string(), // `f16::MAX`1309"0x1.ffcp15"1310);1311// Smallest positive normal number.1312assert_eq!(1313Ieee16::with_bits(0x0400).to_string(), // `f16::MIN_POSITIVE`1314"0x1.000p-14"1315);1316// Subnormals.1317assert_eq!(1318Ieee16::with_bits(0x0200).to_string(), // `f16::MIN_POSITIVE / 2.0`1319"0x0.800p-14"1320);1321assert_eq!(1322Ieee16::with_bits(0x0001).to_string(), // `f16::MIN_POSITIVE * f16::EPSILON`1323"0x0.004p-14"1324);1325assert_eq!(1326Ieee16::with_bits(0x7c00).to_string(), // `f16::INFINITY`1327"+Inf"1328);1329assert_eq!(1330Ieee16::with_bits(0xfc00).to_string(), // `f16::NEG_INFINITY`1331"-Inf"1332);1333assert_eq!(1334Ieee16::with_bits(0x7e00).to_string(), // `f16::NAN`1335"+NaN"1336);1337assert_eq!(1338Ieee16::with_bits(0xfe00).to_string(), // `-f16::NAN`1339"-NaN"1340);1341// Construct some qNaNs with payloads.1342assert_eq!(Ieee16::with_bits(0x7e01).to_string(), "+NaN:0x1");1343assert_eq!(Ieee16::with_bits(0x7f01).to_string(), "+NaN:0x101");1344// Signaling NaNs.1345assert_eq!(Ieee16::with_bits(0x7c01).to_string(), "+sNaN:0x1");1346assert_eq!(Ieee16::with_bits(0x7d01).to_string(), "+sNaN:0x101");1347}13481349#[test]1350fn parse_ieee16() {1351parse_ok::<Ieee16>("0.0", "0.0");1352parse_ok::<Ieee16>("+0.0", "0.0");1353parse_ok::<Ieee16>("-0.0", "-0.0");1354parse_ok::<Ieee16>("0x0", "0.0");1355parse_ok::<Ieee16>("0x0.0", "0.0");1356parse_ok::<Ieee16>("0x.0", "0.0");1357parse_ok::<Ieee16>("0x0.", "0.0");1358parse_ok::<Ieee16>("0x1", "0x1.000p0");1359parse_ok::<Ieee16>("+0x1", "0x1.000p0");1360parse_ok::<Ieee16>("-0x1", "-0x1.000p0");1361parse_ok::<Ieee16>("0x10", "0x1.000p4");1362parse_ok::<Ieee16>("0x10.0", "0x1.000p4");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>("-0", "Float must be hexadecimal");1367parse_err::<Ieee16>(".", "Float must be hexadecimal");1368parse_err::<Ieee16>("", "Float must be hexadecimal");1369parse_err::<Ieee16>("-", "Float must be hexadecimal");1370parse_err::<Ieee16>("0x", "No digits");1371parse_err::<Ieee16>("0x..", "Multiple radix points");13721373// Check significant bits.1374parse_ok::<Ieee16>("0x0.ffe", "0x1.ffcp-1");1375parse_ok::<Ieee16>("0x1.ffc", "0x1.ffcp0");1376parse_ok::<Ieee16>("0x3.ff8", "0x1.ffcp1");1377parse_ok::<Ieee16>("0x7.ff", "0x1.ffcp2");1378parse_ok::<Ieee16>("0xf.fe", "0x1.ffcp3");1379parse_err::<Ieee16>("0x1.ffe", "Too many significant bits");1380parse_err::<Ieee16>("0x1.ffc00000000000000000000000000000", "Too many digits");13811382// Exponents.1383parse_ok::<Ieee16>("0x1p3", "0x1.000p3");1384parse_ok::<Ieee16>("0x1p-3", "0x1.000p-3");1385parse_ok::<Ieee16>("0x1.0p3", "0x1.000p3");1386parse_ok::<Ieee16>("0x2.0p3", "0x1.000p4");1387parse_ok::<Ieee16>("0x1.0p15", "0x1.000p15");1388parse_ok::<Ieee16>("0x1.0p-14", "0x1.000p-14");1389parse_ok::<Ieee16>("0x0.1p-10", "0x1.000p-14");1390parse_err::<Ieee16>("0x2.0p15", "Magnitude too large");13911392// Subnormals.1393parse_ok::<Ieee16>("0x1.0p-15", "0x0.800p-14");1394parse_ok::<Ieee16>("0x1.0p-24", "0x0.004p-14");1395parse_ok::<Ieee16>("0x0.004p-14", "0x0.004p-14");1396parse_err::<Ieee16>("0x0.102p-14", "Subnormal underflow");1397parse_err::<Ieee16>("0x1.8p-24", "Subnormal underflow");1398parse_err::<Ieee16>("0x1.0p-25", "Magnitude too small");13991400// NaNs and Infs.1401parse_ok::<Ieee16>("Inf", "+Inf");1402parse_ok::<Ieee16>("+Inf", "+Inf");1403parse_ok::<Ieee16>("-Inf", "-Inf");1404parse_ok::<Ieee16>("NaN", "+NaN");1405parse_ok::<Ieee16>("+NaN", "+NaN");1406parse_ok::<Ieee16>("-NaN", "-NaN");1407parse_ok::<Ieee16>("NaN:0x0", "+NaN");1408parse_err::<Ieee16>("NaN:", "Float must be hexadecimal");1409parse_err::<Ieee16>("NaN:0", "Float must be hexadecimal");1410parse_err::<Ieee16>("NaN:0x", "Invalid NaN payload");1411parse_ok::<Ieee16>("NaN:0x001", "+NaN:0x1");1412parse_ok::<Ieee16>("NaN:0x101", "+NaN:0x101");1413parse_err::<Ieee16>("NaN:0x301", "Invalid NaN payload");1414parse_ok::<Ieee16>("sNaN:0x1", "+sNaN:0x1");1415parse_err::<Ieee16>("sNaN:0x0", "Invalid sNaN payload");1416parse_ok::<Ieee16>("sNaN:0x101", "+sNaN:0x101");1417parse_err::<Ieee16>("sNaN:0x301", "Invalid sNaN payload");1418}14191420#[test]1421fn pow2_ieee16() {1422assert_eq!(Ieee16::pow2(0).to_string(), "0x1.000p0");1423assert_eq!(Ieee16::pow2(1).to_string(), "0x1.000p1");1424assert_eq!(Ieee16::pow2(-1).to_string(), "0x1.000p-1");1425assert_eq!(Ieee16::pow2(15).to_string(), "0x1.000p15");1426assert_eq!(Ieee16::pow2(-14).to_string(), "0x1.000p-14");14271428assert_eq!((-Ieee16::pow2(1)).to_string(), "-0x1.000p1");1429}14301431#[test]1432fn fcvt_to_sint_negative_overflow_ieee16() {1433// FIXME(#8312): Replace with commented out version once Rust f16 support is stabilised.1434// let n = 8;1435// assert_eq!(1436// -((1u16 << (n - 1)) as f16) - 1.0,1437// Ieee16::fcvt_to_sint_negative_overflow(n).as_f16()1438// );1439let n = 8;1440assert_eq!(1441"-0x1.020p7",1442Ieee16::fcvt_to_sint_negative_overflow(n).to_string()1443);1444}14451446#[test]1447fn format_ieee32() {1448assert_eq!(Ieee32::with_float(0.0).to_string(), "0.0");1449assert_eq!(Ieee32::with_float(-0.0).to_string(), "-0.0");1450assert_eq!(Ieee32::with_float(1.0).to_string(), "0x1.000000p0");1451assert_eq!(Ieee32::with_float(1.5).to_string(), "0x1.800000p0");1452assert_eq!(Ieee32::with_float(0.5).to_string(), "0x1.000000p-1");1453assert_eq!(1454Ieee32::with_float(f32::EPSILON).to_string(),1455"0x1.000000p-23"1456);1457assert_eq!(Ieee32::with_float(f32::MIN).to_string(), "-0x1.fffffep127");1458assert_eq!(Ieee32::with_float(f32::MAX).to_string(), "0x1.fffffep127");1459// Smallest positive normal number.1460assert_eq!(1461Ieee32::with_float(f32::MIN_POSITIVE).to_string(),1462"0x1.000000p-126"1463);1464// Subnormals.1465assert_eq!(1466Ieee32::with_float(f32::MIN_POSITIVE / 2.0).to_string(),1467"0x0.800000p-126"1468);1469assert_eq!(1470Ieee32::with_float(f32::MIN_POSITIVE * f32::EPSILON).to_string(),1471"0x0.000002p-126"1472);1473assert_eq!(Ieee32::with_float(f32::INFINITY).to_string(), "+Inf");1474assert_eq!(Ieee32::with_float(f32::NEG_INFINITY).to_string(), "-Inf");1475assert_eq!(Ieee32::with_float(f32::NAN).to_string(), "+NaN");1476assert_eq!(Ieee32::with_float(-f32::NAN).to_string(), "-NaN");1477// Construct some qNaNs with payloads.1478assert_eq!(Ieee32::with_bits(0x7fc00001).to_string(), "+NaN:0x1");1479assert_eq!(Ieee32::with_bits(0x7ff00001).to_string(), "+NaN:0x300001");1480// Signaling NaNs.1481assert_eq!(Ieee32::with_bits(0x7f800001).to_string(), "+sNaN:0x1");1482assert_eq!(Ieee32::with_bits(0x7fa00001).to_string(), "+sNaN:0x200001");1483}14841485#[test]1486fn parse_ieee32() {1487parse_ok::<Ieee32>("0.0", "0.0");1488parse_ok::<Ieee32>("+0.0", "0.0");1489parse_ok::<Ieee32>("-0.0", "-0.0");1490parse_ok::<Ieee32>("0x0", "0.0");1491parse_ok::<Ieee32>("0x0.0", "0.0");1492parse_ok::<Ieee32>("0x.0", "0.0");1493parse_ok::<Ieee32>("0x0.", "0.0");1494parse_ok::<Ieee32>("0x1", "0x1.000000p0");1495parse_ok::<Ieee32>("+0x1", "0x1.000000p0");1496parse_ok::<Ieee32>("-0x1", "-0x1.000000p0");1497parse_ok::<Ieee32>("0x10", "0x1.000000p4");1498parse_ok::<Ieee32>("0x10.0", "0x1.000000p4");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>("-0", "Float must be hexadecimal");1503parse_err::<Ieee32>(".", "Float must be hexadecimal");1504parse_err::<Ieee32>("", "Float must be hexadecimal");1505parse_err::<Ieee32>("-", "Float must be hexadecimal");1506parse_err::<Ieee32>("0x", "No digits");1507parse_err::<Ieee32>("0x..", "Multiple radix points");15081509// Check significant bits.1510parse_ok::<Ieee32>("0x0.ffffff", "0x1.fffffep-1");1511parse_ok::<Ieee32>("0x1.fffffe", "0x1.fffffep0");1512parse_ok::<Ieee32>("0x3.fffffc", "0x1.fffffep1");1513parse_ok::<Ieee32>("0x7.fffff8", "0x1.fffffep2");1514parse_ok::<Ieee32>("0xf.fffff0", "0x1.fffffep3");1515parse_err::<Ieee32>("0x1.ffffff", "Too many significant bits");1516parse_err::<Ieee32>("0x1.fffffe00000000000000000000000000", "Too many digits");15171518// Exponents.1519parse_ok::<Ieee32>("0x1p3", "0x1.000000p3");1520parse_ok::<Ieee32>("0x1p-3", "0x1.000000p-3");1521parse_ok::<Ieee32>("0x1.0p3", "0x1.000000p3");1522parse_ok::<Ieee32>("0x2.0p3", "0x1.000000p4");1523parse_ok::<Ieee32>("0x1.0p127", "0x1.000000p127");1524parse_ok::<Ieee32>("0x1.0p-126", "0x1.000000p-126");1525parse_ok::<Ieee32>("0x0.1p-122", "0x1.000000p-126");1526parse_err::<Ieee32>("0x2.0p127", "Magnitude too large");15271528// Subnormals.1529parse_ok::<Ieee32>("0x1.0p-127", "0x0.800000p-126");1530parse_ok::<Ieee32>("0x1.0p-149", "0x0.000002p-126");1531parse_ok::<Ieee32>("0x0.000002p-126", "0x0.000002p-126");1532parse_err::<Ieee32>("0x0.100001p-126", "Subnormal underflow");1533parse_err::<Ieee32>("0x1.8p-149", "Subnormal underflow");1534parse_err::<Ieee32>("0x1.0p-150", "Magnitude too small");15351536// NaNs and Infs.1537parse_ok::<Ieee32>("Inf", "+Inf");1538parse_ok::<Ieee32>("+Inf", "+Inf");1539parse_ok::<Ieee32>("-Inf", "-Inf");1540parse_ok::<Ieee32>("NaN", "+NaN");1541parse_ok::<Ieee32>("+NaN", "+NaN");1542parse_ok::<Ieee32>("-NaN", "-NaN");1543parse_ok::<Ieee32>("NaN:0x0", "+NaN");1544parse_err::<Ieee32>("NaN:", "Float must be hexadecimal");1545parse_err::<Ieee32>("NaN:0", "Float must be hexadecimal");1546parse_err::<Ieee32>("NaN:0x", "Invalid NaN payload");1547parse_ok::<Ieee32>("NaN:0x000001", "+NaN:0x1");1548parse_ok::<Ieee32>("NaN:0x300001", "+NaN:0x300001");1549parse_err::<Ieee32>("NaN:0x400001", "Invalid NaN payload");1550parse_ok::<Ieee32>("sNaN:0x1", "+sNaN:0x1");1551parse_err::<Ieee32>("sNaN:0x0", "Invalid sNaN payload");1552parse_ok::<Ieee32>("sNaN:0x200001", "+sNaN:0x200001");1553parse_err::<Ieee32>("sNaN:0x400001", "Invalid sNaN payload");1554}15551556#[test]1557fn pow2_ieee32() {1558assert_eq!(Ieee32::pow2(0).to_string(), "0x1.000000p0");1559assert_eq!(Ieee32::pow2(1).to_string(), "0x1.000000p1");1560assert_eq!(Ieee32::pow2(-1).to_string(), "0x1.000000p-1");1561assert_eq!(Ieee32::pow2(127).to_string(), "0x1.000000p127");1562assert_eq!(Ieee32::pow2(-126).to_string(), "0x1.000000p-126");15631564assert_eq!((-Ieee32::pow2(1)).to_string(), "-0x1.000000p1");1565}15661567#[test]1568fn fcvt_to_sint_negative_overflow_ieee32() {1569for n in [8, 16] {1570assert_eq!(1571-((1u32 << (n - 1)) as f32) - 1.0,1572Ieee32::fcvt_to_sint_negative_overflow(n).as_f32(),1573"n = {n}"1574);1575}1576}15771578#[test]1579fn format_ieee64() {1580assert_eq!(Ieee64::with_float(0.0).to_string(), "0.0");1581assert_eq!(Ieee64::with_float(-0.0).to_string(), "-0.0");1582assert_eq!(Ieee64::with_float(1.0).to_string(), "0x1.0000000000000p0");1583assert_eq!(Ieee64::with_float(1.5).to_string(), "0x1.8000000000000p0");1584assert_eq!(Ieee64::with_float(0.5).to_string(), "0x1.0000000000000p-1");1585assert_eq!(1586Ieee64::with_float(f64::EPSILON).to_string(),1587"0x1.0000000000000p-52"1588);1589assert_eq!(1590Ieee64::with_float(f64::MIN).to_string(),1591"-0x1.fffffffffffffp1023"1592);1593assert_eq!(1594Ieee64::with_float(f64::MAX).to_string(),1595"0x1.fffffffffffffp1023"1596);1597// Smallest positive normal number.1598assert_eq!(1599Ieee64::with_float(f64::MIN_POSITIVE).to_string(),1600"0x1.0000000000000p-1022"1601);1602// Subnormals.1603assert_eq!(1604Ieee64::with_float(f64::MIN_POSITIVE / 2.0).to_string(),1605"0x0.8000000000000p-1022"1606);1607assert_eq!(1608Ieee64::with_float(f64::MIN_POSITIVE * f64::EPSILON).to_string(),1609"0x0.0000000000001p-1022"1610);1611assert_eq!(Ieee64::with_float(f64::INFINITY).to_string(), "+Inf");1612assert_eq!(Ieee64::with_float(f64::NEG_INFINITY).to_string(), "-Inf");1613assert_eq!(Ieee64::with_float(f64::NAN).to_string(), "+NaN");1614assert_eq!(Ieee64::with_float(-f64::NAN).to_string(), "-NaN");1615// Construct some qNaNs with payloads.1616assert_eq!(1617Ieee64::with_bits(0x7ff8000000000001).to_string(),1618"+NaN:0x1"1619);1620assert_eq!(1621Ieee64::with_bits(0x7ffc000000000001).to_string(),1622"+NaN:0x4000000000001"1623);1624// Signaling NaNs.1625assert_eq!(1626Ieee64::with_bits(0x7ff0000000000001).to_string(),1627"+sNaN:0x1"1628);1629assert_eq!(1630Ieee64::with_bits(0x7ff4000000000001).to_string(),1631"+sNaN:0x4000000000001"1632);1633}16341635#[test]1636fn parse_ieee64() {1637parse_ok::<Ieee64>("0.0", "0.0");1638parse_ok::<Ieee64>("-0.0", "-0.0");1639parse_ok::<Ieee64>("0x0", "0.0");1640parse_ok::<Ieee64>("0x0.0", "0.0");1641parse_ok::<Ieee64>("0x.0", "0.0");1642parse_ok::<Ieee64>("0x0.", "0.0");1643parse_ok::<Ieee64>("0x1", "0x1.0000000000000p0");1644parse_ok::<Ieee64>("-0x1", "-0x1.0000000000000p0");1645parse_ok::<Ieee64>("0x10", "0x1.0000000000000p4");1646parse_ok::<Ieee64>("0x10.0", "0x1.0000000000000p4");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>("-0", "Float must be hexadecimal");1651parse_err::<Ieee64>(".", "Float must be hexadecimal");1652parse_err::<Ieee64>("", "Float must be hexadecimal");1653parse_err::<Ieee64>("-", "Float must be hexadecimal");1654parse_err::<Ieee64>("0x", "No digits");1655parse_err::<Ieee64>("0x..", "Multiple radix points");16561657// Check significant bits.1658parse_ok::<Ieee64>("0x0.fffffffffffff8", "0x1.fffffffffffffp-1");1659parse_ok::<Ieee64>("0x1.fffffffffffff", "0x1.fffffffffffffp0");1660parse_ok::<Ieee64>("0x3.ffffffffffffe", "0x1.fffffffffffffp1");1661parse_ok::<Ieee64>("0x7.ffffffffffffc", "0x1.fffffffffffffp2");1662parse_ok::<Ieee64>("0xf.ffffffffffff8", "0x1.fffffffffffffp3");1663parse_err::<Ieee64>("0x3.fffffffffffff", "Too many significant bits");1664parse_err::<Ieee64>("0x001.fffffe000000000000000000000000", "Too many digits");16651666// Exponents.1667parse_ok::<Ieee64>("0x1p3", "0x1.0000000000000p3");1668parse_ok::<Ieee64>("0x1p-3", "0x1.0000000000000p-3");1669parse_ok::<Ieee64>("0x1.0p3", "0x1.0000000000000p3");1670parse_ok::<Ieee64>("0x2.0p3", "0x1.0000000000000p4");1671parse_ok::<Ieee64>("0x1.0p1023", "0x1.0000000000000p1023");1672parse_ok::<Ieee64>("0x1.0p-1022", "0x1.0000000000000p-1022");1673parse_ok::<Ieee64>("0x0.1p-1018", "0x1.0000000000000p-1022");1674parse_err::<Ieee64>("0x2.0p1023", "Magnitude too large");16751676// Subnormals.1677parse_ok::<Ieee64>("0x1.0p-1023", "0x0.8000000000000p-1022");1678parse_ok::<Ieee64>("0x1.0p-1074", "0x0.0000000000001p-1022");1679parse_ok::<Ieee64>("0x0.0000000000001p-1022", "0x0.0000000000001p-1022");1680parse_err::<Ieee64>("0x0.10000000000008p-1022", "Subnormal underflow");1681parse_err::<Ieee64>("0x1.8p-1074", "Subnormal underflow");1682parse_err::<Ieee64>("0x1.0p-1075", "Magnitude too small");16831684// NaNs and Infs.1685parse_ok::<Ieee64>("Inf", "+Inf");1686parse_ok::<Ieee64>("-Inf", "-Inf");1687parse_ok::<Ieee64>("NaN", "+NaN");1688parse_ok::<Ieee64>("-NaN", "-NaN");1689parse_ok::<Ieee64>("NaN:0x0", "+NaN");1690parse_err::<Ieee64>("NaN:", "Float must be hexadecimal");1691parse_err::<Ieee64>("NaN:0", "Float must be hexadecimal");1692parse_err::<Ieee64>("NaN:0x", "Invalid NaN payload");1693parse_ok::<Ieee64>("NaN:0x000001", "+NaN:0x1");1694parse_ok::<Ieee64>("NaN:0x4000000000001", "+NaN:0x4000000000001");1695parse_err::<Ieee64>("NaN:0x8000000000001", "Invalid NaN payload");1696parse_ok::<Ieee64>("sNaN:0x1", "+sNaN:0x1");1697parse_err::<Ieee64>("sNaN:0x0", "Invalid sNaN payload");1698parse_ok::<Ieee64>("sNaN:0x4000000000001", "+sNaN:0x4000000000001");1699parse_err::<Ieee64>("sNaN:0x8000000000001", "Invalid sNaN payload");1700}17011702#[test]1703fn pow2_ieee64() {1704assert_eq!(Ieee64::pow2(0).to_string(), "0x1.0000000000000p0");1705assert_eq!(Ieee64::pow2(1).to_string(), "0x1.0000000000000p1");1706assert_eq!(Ieee64::pow2(-1).to_string(), "0x1.0000000000000p-1");1707assert_eq!(Ieee64::pow2(1023).to_string(), "0x1.0000000000000p1023");1708assert_eq!(Ieee64::pow2(-1022).to_string(), "0x1.0000000000000p-1022");17091710assert_eq!((-Ieee64::pow2(1)).to_string(), "-0x1.0000000000000p1");1711}17121713#[test]1714fn fcvt_to_sint_negative_overflow_ieee64() {1715for n in [8, 16, 32] {1716assert_eq!(1717-((1u64 << (n - 1)) as f64) - 1.0,1718Ieee64::fcvt_to_sint_negative_overflow(n).as_f64(),1719"n = {n}"1720);1721}1722}17231724#[test]1725fn format_ieee128() {1726assert_eq!(1727Ieee128::with_bits(0x00000000000000000000000000000000).to_string(), // 0.01728"0.0"1729);1730assert_eq!(1731Ieee128::with_bits(0x80000000000000000000000000000000).to_string(), // -0.01732"-0.0"1733);1734assert_eq!(1735Ieee128::with_bits(0x3fff0000000000000000000000000000).to_string(), // 1.01736"0x1.0000000000000000000000000000p0"1737);1738assert_eq!(1739Ieee128::with_bits(0x3fff8000000000000000000000000000).to_string(), // 1.51740"0x1.8000000000000000000000000000p0"1741);1742assert_eq!(1743Ieee128::with_bits(0x3ffe0000000000000000000000000000).to_string(), // 0.51744"0x1.0000000000000000000000000000p-1"1745);1746assert_eq!(1747Ieee128::with_bits(0x3f8f0000000000000000000000000000).to_string(), // `f128::EPSILON`1748"0x1.0000000000000000000000000000p-112"1749);1750assert_eq!(1751Ieee128::with_bits(0xfffeffffffffffffffffffffffffffff).to_string(), // `f128::MIN`1752"-0x1.ffffffffffffffffffffffffffffp16383"1753);1754assert_eq!(1755Ieee128::with_bits(0x7ffeffffffffffffffffffffffffffff).to_string(), // `f128::MAX`1756"0x1.ffffffffffffffffffffffffffffp16383"1757);1758// Smallest positive normal number.1759assert_eq!(1760Ieee128::with_bits(0x00010000000000000000000000000000).to_string(), // `f128::MIN_POSITIVE`1761"0x1.0000000000000000000000000000p-16382"1762);1763// Subnormals.1764assert_eq!(1765Ieee128::with_bits(0x00008000000000000000000000000000).to_string(), // `f128::MIN_POSITIVE / 2.0`1766"0x0.8000000000000000000000000000p-16382"1767);1768assert_eq!(1769Ieee128::with_bits(0x00000000000000000000000000000001).to_string(), // `f128::MIN_POSITIVE * f128::EPSILON`1770"0x0.0000000000000000000000000001p-16382"1771);1772assert_eq!(1773Ieee128::with_bits(0x7fff0000000000000000000000000000).to_string(), // `f128::INFINITY`1774"+Inf"1775);1776assert_eq!(1777Ieee128::with_bits(0xffff0000000000000000000000000000).to_string(), // `f128::NEG_INFINITY`1778"-Inf"1779);1780assert_eq!(1781Ieee128::with_bits(0x7fff8000000000000000000000000000).to_string(), // `f128::NAN`1782"+NaN"1783);1784assert_eq!(1785Ieee128::with_bits(0xffff8000000000000000000000000000).to_string(), // `-f128::NAN`1786"-NaN"1787);1788// Construct some qNaNs with payloads.1789assert_eq!(1790Ieee128::with_bits(0x7fff8000000000000000000000000001).to_string(),1791"+NaN:0x1"1792);1793assert_eq!(1794Ieee128::with_bits(0x7fffc000000000000000000000000001).to_string(),1795"+NaN:0x4000000000000000000000000001"1796);1797// Signaling NaNs.1798assert_eq!(1799Ieee128::with_bits(0x7fff0000000000000000000000000001).to_string(),1800"+sNaN:0x1"1801);1802assert_eq!(1803Ieee128::with_bits(0x7fff4000000000000000000000000001).to_string(),1804"+sNaN:0x4000000000000000000000000001"1805);1806}18071808#[test]1809fn parse_ieee128() {1810parse_ok::<Ieee128>("0.0", "0.0");1811parse_ok::<Ieee128>("-0.0", "-0.0");1812parse_ok::<Ieee128>("0x0", "0.0");1813parse_ok::<Ieee128>("0x0.0", "0.0");1814parse_ok::<Ieee128>("0x.0", "0.0");1815parse_ok::<Ieee128>("0x0.", "0.0");1816parse_ok::<Ieee128>("0x1", "0x1.0000000000000000000000000000p0");1817parse_ok::<Ieee128>("-0x1", "-0x1.0000000000000000000000000000p0");1818parse_ok::<Ieee128>("0x10", "0x1.0000000000000000000000000000p4");1819parse_ok::<Ieee128>("0x10.0", "0x1.0000000000000000000000000000p4");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>("-0", "Float must be hexadecimal");1824parse_err::<Ieee128>(".", "Float must be hexadecimal");1825parse_err::<Ieee128>("", "Float must be hexadecimal");1826parse_err::<Ieee128>("-", "Float must be hexadecimal");1827parse_err::<Ieee128>("0x", "No digits");1828parse_err::<Ieee128>("0x..", "Multiple radix points");18291830// Check significant bits.1831parse_ok::<Ieee128>(1832"0x0.ffffffffffffffffffffffffffff8",1833"0x1.ffffffffffffffffffffffffffffp-1",1834);1835parse_ok::<Ieee128>(1836"0x1.ffffffffffffffffffffffffffff",1837"0x1.ffffffffffffffffffffffffffffp0",1838);1839parse_ok::<Ieee128>(1840"0x3.fffffffffffffffffffffffffffe",1841"0x1.ffffffffffffffffffffffffffffp1",1842);1843parse_ok::<Ieee128>(1844"0x7.fffffffffffffffffffffffffffc",1845"0x1.ffffffffffffffffffffffffffffp2",1846);1847parse_ok::<Ieee128>(1848"0xf.fffffffffffffffffffffffffff8",1849"0x1.ffffffffffffffffffffffffffffp3",1850);1851parse_err::<Ieee128>(1852"0x3.ffffffffffffffffffffffffffff",1853"Too many significant bits",1854);1855parse_err::<Ieee128>("0x001.fffffe000000000000000000000000", "Too many digits");18561857// Exponents.1858parse_ok::<Ieee128>("0x1p3", "0x1.0000000000000000000000000000p3");1859parse_ok::<Ieee128>("0x1p-3", "0x1.0000000000000000000000000000p-3");1860parse_ok::<Ieee128>("0x1.0p3", "0x1.0000000000000000000000000000p3");1861parse_ok::<Ieee128>("0x2.0p3", "0x1.0000000000000000000000000000p4");1862parse_ok::<Ieee128>("0x1.0p16383", "0x1.0000000000000000000000000000p16383");1863parse_ok::<Ieee128>("0x1.0p-16382", "0x1.0000000000000000000000000000p-16382");1864parse_ok::<Ieee128>("0x0.1p-16378", "0x1.0000000000000000000000000000p-16382");1865parse_err::<Ieee128>("0x2.0p16383", "Magnitude too large");18661867// Subnormals.1868parse_ok::<Ieee128>("0x1.0p-16383", "0x0.8000000000000000000000000000p-16382");1869parse_ok::<Ieee128>("0x1.0p-16494", "0x0.0000000000000000000000000001p-16382");1870parse_ok::<Ieee128>(1871"0x0.0000000000000000000000000001p-16382",1872"0x0.0000000000000000000000000001p-16382",1873);1874parse_err::<Ieee128>(1875"0x0.10000000000000000000000000008p-16382",1876"Subnormal underflow",1877);1878parse_err::<Ieee128>("0x1.8p-16494", "Subnormal underflow");1879parse_err::<Ieee128>("0x1.0p-16495", "Magnitude too small");18801881// NaNs and Infs.1882parse_ok::<Ieee128>("Inf", "+Inf");1883parse_ok::<Ieee128>("-Inf", "-Inf");1884parse_ok::<Ieee128>("NaN", "+NaN");1885parse_ok::<Ieee128>("-NaN", "-NaN");1886parse_ok::<Ieee128>("NaN:0x0", "+NaN");1887parse_err::<Ieee128>("NaN:", "Float must be hexadecimal");1888parse_err::<Ieee128>("NaN:0", "Float must be hexadecimal");1889parse_err::<Ieee128>("NaN:0x", "Invalid NaN payload");1890parse_ok::<Ieee128>("NaN:0x000001", "+NaN:0x1");1891parse_ok::<Ieee128>(1892"NaN:0x4000000000000000000000000001",1893"+NaN:0x4000000000000000000000000001",1894);1895parse_err::<Ieee128>("NaN:0x8000000000000000000000000001", "Invalid NaN payload");1896parse_ok::<Ieee128>("sNaN:0x1", "+sNaN:0x1");1897parse_err::<Ieee128>("sNaN:0x0", "Invalid sNaN payload");1898parse_ok::<Ieee128>(1899"sNaN:0x4000000000000000000000000001",1900"+sNaN:0x4000000000000000000000000001",1901);1902parse_err::<Ieee128>(1903"sNaN:0x8000000000000000000000000001",1904"Invalid sNaN payload",1905);1906}19071908#[test]1909fn pow2_ieee128() {1910assert_eq!(1911Ieee128::pow2(0).to_string(),1912"0x1.0000000000000000000000000000p0"1913);1914assert_eq!(1915Ieee128::pow2(1).to_string(),1916"0x1.0000000000000000000000000000p1"1917);1918assert_eq!(1919Ieee128::pow2(-1).to_string(),1920"0x1.0000000000000000000000000000p-1"1921);1922assert_eq!(1923Ieee128::pow2(16383).to_string(),1924"0x1.0000000000000000000000000000p16383"1925);1926assert_eq!(1927Ieee128::pow2(-16382).to_string(),1928"0x1.0000000000000000000000000000p-16382"1929);19301931assert_eq!(1932(-Ieee128::pow2(1)).to_string(),1933"-0x1.0000000000000000000000000000p1"1934);1935}19361937#[test]1938fn fcvt_to_sint_negative_overflow_ieee128() {1939// FIXME(#8312): Replace with commented out version once Rust f128 support is stabilised.1940// for n in [8, 16, 32, 64] {1941// assert_eq!(1942// -((1u128 << (n - 1)) as f128) - 1.0,1943// Ieee128::fcvt_to_sint_negative_overflow(n).as_f128(),1944// "n = {n}"1945// );1946// }1947for (n, expected) in [1948(8, "-0x1.0200000000000000000000000000p7"),1949(16, "-0x1.0002000000000000000000000000p15"),1950(32, "-0x1.0000000200000000000000000000p31"),1951(64, "-0x1.0000000000000002000000000000p63"),1952] {1953assert_eq!(1954expected,1955Ieee128::fcvt_to_sint_negative_overflow(n).to_string(),1956"n = {n}"1957);1958}1959}1960}196119621963