cranelift_codegen/ir/
immediates.rs

1//! Immediate operands for Cranelift instructions
2//!
3//! This module defines the types of immediate operands that can appear on Cranelift instructions.
4//! Each type here should have a corresponding definition in the
5//! `cranelift-codegen/meta/src/shared/immediates` crate in the meta language.
6
7use alloc::vec::Vec;
8use core::cmp::Ordering;
9use core::fmt::{self, Display, Formatter};
10use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Sub};
11use core::str::FromStr;
12use core::{i32, u32};
13use cranelift_entity::{Signed, Unsigned};
14#[cfg(feature = "enable-serde")]
15use serde_derive::{Deserialize, Serialize};
16
17/// Convert a type into a vector of bytes; all implementors in this file must use little-endian
18/// orderings of bytes to match WebAssembly's little-endianness.
19pub trait IntoBytes {
20    /// Return the little-endian byte representation of the implementing type.
21    fn into_bytes(self) -> Vec<u8>;
22}
23
24impl IntoBytes for u8 {
25    fn into_bytes(self) -> Vec<u8> {
26        vec![self]
27    }
28}
29
30impl IntoBytes for i8 {
31    fn into_bytes(self) -> Vec<u8> {
32        vec![self as u8]
33    }
34}
35
36impl IntoBytes for i16 {
37    fn into_bytes(self) -> Vec<u8> {
38        self.to_le_bytes().to_vec()
39    }
40}
41
42impl IntoBytes for i32 {
43    fn into_bytes(self) -> Vec<u8> {
44        self.to_le_bytes().to_vec()
45    }
46}
47
48impl IntoBytes for Vec<u8> {
49    fn into_bytes(self) -> Vec<u8> {
50        self
51    }
52}
53
54/// 64-bit immediate signed integer operand.
55///
56/// An `Imm64` operand can also be used to represent immediate values of smaller integer types by
57/// sign-extending to `i64`.
58#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
59#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
60pub struct Imm64(i64);
61
62impl Imm64 {
63    /// Create a new `Imm64` representing the signed number `x`.
64    pub fn new(x: i64) -> Self {
65        Self(x)
66    }
67
68    /// Return self negated.
69    pub fn wrapping_neg(self) -> Self {
70        Self(self.0.wrapping_neg())
71    }
72
73    /// Returns the value of this immediate.
74    pub fn bits(&self) -> i64 {
75        self.0
76    }
77
78    /// Mask this immediate to the given power-of-two bit width.
79    #[must_use]
80    pub(crate) fn mask_to_width(&self, bit_width: u32) -> Self {
81        debug_assert!(bit_width.is_power_of_two());
82
83        if bit_width >= 64 {
84            return *self;
85        }
86
87        let bit_width = i64::from(bit_width);
88        let mask = (1 << bit_width) - 1;
89        let masked = self.0 & mask;
90        Imm64(masked)
91    }
92
93    /// Sign extend this immediate as if it were a signed integer of the given
94    /// power-of-two width.
95    #[must_use]
96    pub fn sign_extend_from_width(&self, bit_width: u32) -> Self {
97        debug_assert!(
98            bit_width.is_power_of_two(),
99            "{bit_width} is not a power of two"
100        );
101
102        if bit_width >= 64 {
103            return *self;
104        }
105
106        let bit_width = i64::from(bit_width);
107        let delta = 64 - bit_width;
108        let sign_extended = (self.0 << delta) >> delta;
109        Imm64(sign_extended)
110    }
111
112    /// Zero extend this immediate as if it were an unsigned integer of the
113    /// given power-of-two width.
114    #[must_use]
115    pub fn zero_extend_from_width(&self, bit_width: u32) -> Self {
116        debug_assert!(
117            bit_width.is_power_of_two(),
118            "{bit_width} is not a power of two"
119        );
120
121        if bit_width >= 64 {
122            return *self;
123        }
124
125        let bit_width = u64::from(bit_width);
126        let delta = 64 - bit_width;
127        let zero_extended = (self.0.unsigned() << delta) >> delta;
128        Imm64(zero_extended.signed())
129    }
130}
131
132impl From<Imm64> for i64 {
133    fn from(val: Imm64) -> i64 {
134        val.0
135    }
136}
137
138impl IntoBytes for Imm64 {
139    fn into_bytes(self) -> Vec<u8> {
140        self.0.to_le_bytes().to_vec()
141    }
142}
143
144impl From<i64> for Imm64 {
145    fn from(x: i64) -> Self {
146        Self(x)
147    }
148}
149
150impl Display for Imm64 {
151    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
152        let x = self.0;
153        if x < 10_000 {
154            // Use decimal for small and negative numbers.
155            write!(f, "{x}")
156        } else {
157            write_hex(x as u64, f)
158        }
159    }
160}
161
162/// Parse a 64-bit signed number.
163fn parse_i64(s: &str) -> Result<i64, &'static str> {
164    let negative = s.starts_with('-');
165    let s2 = if negative || s.starts_with('+') {
166        &s[1..]
167    } else {
168        s
169    };
170
171    let mut value = parse_u64(s2)?;
172
173    // We support the range-and-a-half from -2^63 .. 2^64-1.
174    if negative {
175        value = value.wrapping_neg();
176        // Don't allow large negative values to wrap around and become positive.
177        if value as i64 > 0 {
178            return Err("Negative number too small");
179        }
180    }
181    Ok(value as i64)
182}
183
184impl FromStr for Imm64 {
185    type Err = &'static str;
186
187    // Parse a decimal or hexadecimal `Imm64`, formatted as above.
188    fn from_str(s: &str) -> Result<Self, &'static str> {
189        parse_i64(s).map(Self::new)
190    }
191}
192
193/// 64-bit immediate unsigned integer operand.
194///
195/// A `Uimm64` operand can also be used to represent immediate values of smaller integer types by
196/// zero-extending to `i64`.
197#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
198#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
199pub struct Uimm64(u64);
200
201impl Uimm64 {
202    /// Create a new `Uimm64` representing the unsigned number `x`.
203    pub fn new(x: u64) -> Self {
204        Self(x)
205    }
206
207    /// Return self negated.
208    pub fn wrapping_neg(self) -> Self {
209        Self(self.0.wrapping_neg())
210    }
211}
212
213impl From<Uimm64> for u64 {
214    fn from(val: Uimm64) -> u64 {
215        val.0
216    }
217}
218
219impl From<u64> for Uimm64 {
220    fn from(x: u64) -> Self {
221        Self(x)
222    }
223}
224
225/// Hexadecimal with a multiple of 4 digits and group separators:
226///
227///   0xfff0
228///   0x0001_ffff
229///   0xffff_ffff_fff8_4400
230///
231fn write_hex(x: u64, f: &mut Formatter) -> fmt::Result {
232    let mut pos = (64 - x.leading_zeros() - 1) & 0xf0;
233    write!(f, "0x{:04x}", (x >> pos) & 0xffff)?;
234    while pos > 0 {
235        pos -= 16;
236        write!(f, "_{:04x}", (x >> pos) & 0xffff)?;
237    }
238    Ok(())
239}
240
241impl Display for Uimm64 {
242    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
243        let x = self.0;
244        if x < 10_000 {
245            // Use decimal for small numbers.
246            write!(f, "{x}")
247        } else {
248            write_hex(x, f)
249        }
250    }
251}
252
253/// Parse a 64-bit unsigned number.
254fn parse_u64(s: &str) -> Result<u64, &'static str> {
255    let mut value: u64 = 0;
256    let mut digits = 0;
257
258    if s.starts_with("-0x") {
259        return Err("Invalid character in hexadecimal number");
260    } else if let Some(num) = s.strip_prefix("0x") {
261        // Hexadecimal.
262        for ch in num.chars() {
263            match ch.to_digit(16) {
264                Some(digit) => {
265                    digits += 1;
266                    if digits > 16 {
267                        return Err("Too many hexadecimal digits");
268                    }
269                    // This can't overflow given the digit limit.
270                    value = (value << 4) | u64::from(digit);
271                }
272                None => {
273                    // Allow embedded underscores, but fail on anything else.
274                    if ch != '_' {
275                        return Err("Invalid character in hexadecimal number");
276                    }
277                }
278            }
279        }
280    } else {
281        // Decimal number, possibly negative.
282        for ch in s.chars() {
283            match ch.to_digit(10) {
284                Some(digit) => {
285                    digits += 1;
286                    match value.checked_mul(10) {
287                        None => return Err("Too large decimal number"),
288                        Some(v) => value = v,
289                    }
290                    match value.checked_add(u64::from(digit)) {
291                        None => return Err("Too large decimal number"),
292                        Some(v) => value = v,
293                    }
294                }
295                None => {
296                    // Allow embedded underscores, but fail on anything else.
297                    if ch != '_' {
298                        return Err("Invalid character in decimal number");
299                    }
300                }
301            }
302        }
303    }
304
305    if digits == 0 {
306        return Err("No digits in number");
307    }
308
309    Ok(value)
310}
311
312impl FromStr for Uimm64 {
313    type Err = &'static str;
314
315    // Parse a decimal or hexadecimal `Uimm64`, formatted as above.
316    fn from_str(s: &str) -> Result<Self, &'static str> {
317        parse_u64(s).map(Self::new)
318    }
319}
320
321/// 8-bit unsigned integer immediate operand.
322///
323/// This is used to indicate lane indexes typically.
324pub type Uimm8 = u8;
325
326/// A 32-bit unsigned integer immediate operand.
327///
328/// This is used to represent sizes of memory objects.
329#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
330#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
331pub struct Uimm32(u32);
332
333impl From<Uimm32> for u32 {
334    fn from(val: Uimm32) -> u32 {
335        val.0
336    }
337}
338
339impl From<Uimm32> for u64 {
340    fn from(val: Uimm32) -> u64 {
341        val.0.into()
342    }
343}
344
345impl From<Uimm32> for i64 {
346    fn from(val: Uimm32) -> i64 {
347        i64::from(val.0)
348    }
349}
350
351impl From<u32> for Uimm32 {
352    fn from(x: u32) -> Self {
353        Self(x)
354    }
355}
356
357impl Display for Uimm32 {
358    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
359        if self.0 < 10_000 {
360            write!(f, "{}", self.0)
361        } else {
362            write_hex(u64::from(self.0), f)
363        }
364    }
365}
366
367impl FromStr for Uimm32 {
368    type Err = &'static str;
369
370    // Parse a decimal or hexadecimal `Uimm32`, formatted as above.
371    fn from_str(s: &str) -> Result<Self, &'static str> {
372        parse_i64(s).and_then(|x| {
373            if 0 <= x && x <= i64::from(u32::MAX) {
374                Ok(Self(x as u32))
375            } else {
376                Err("Uimm32 out of range")
377            }
378        })
379    }
380}
381
382/// A 128-bit immediate operand.
383///
384/// This is used as an immediate value in SIMD instructions.
385#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
386#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
387pub struct V128Imm(pub [u8; 16]);
388
389impl V128Imm {
390    /// Iterate over the bytes in the constant.
391    pub fn bytes(&self) -> impl Iterator<Item = &u8> {
392        self.0.iter()
393    }
394
395    /// Convert the immediate into a vector.
396    pub fn to_vec(self) -> Vec<u8> {
397        self.0.to_vec()
398    }
399
400    /// Convert the immediate into a slice.
401    pub fn as_slice(&self) -> &[u8] {
402        &self.0[..]
403    }
404}
405
406impl From<&[u8]> for V128Imm {
407    fn from(slice: &[u8]) -> Self {
408        assert_eq!(slice.len(), 16);
409        let mut buffer = [0; 16];
410        buffer.copy_from_slice(slice);
411        Self(buffer)
412    }
413}
414
415impl From<u128> for V128Imm {
416    fn from(val: u128) -> Self {
417        V128Imm(val.to_le_bytes())
418    }
419}
420
421/// 32-bit signed immediate offset.
422///
423/// This is used to encode an immediate offset for load/store instructions. All supported ISAs have
424/// a maximum load/store offset that fits in an `i32`.
425#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
426#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
427pub struct Offset32(i32);
428
429impl Offset32 {
430    /// Create a new `Offset32` representing the signed number `x`.
431    pub fn new(x: i32) -> Self {
432        Self(x)
433    }
434
435    /// Create a new `Offset32` representing the signed number `x` if possible.
436    pub fn try_from_i64(x: i64) -> Option<Self> {
437        let x = i32::try_from(x).ok()?;
438        Some(Self::new(x))
439    }
440
441    /// Add in the signed number `x` if possible.
442    pub fn try_add_i64(self, x: i64) -> Option<Self> {
443        let x = i32::try_from(x).ok()?;
444        let ret = self.0.checked_add(x)?;
445        Some(Self::new(ret))
446    }
447}
448
449impl From<Offset32> for i32 {
450    fn from(val: Offset32) -> i32 {
451        val.0
452    }
453}
454
455impl From<Offset32> for i64 {
456    fn from(val: Offset32) -> i64 {
457        i64::from(val.0)
458    }
459}
460
461impl From<i32> for Offset32 {
462    fn from(x: i32) -> Self {
463        Self(x)
464    }
465}
466
467impl From<u8> for Offset32 {
468    fn from(val: u8) -> Offset32 {
469        Self(val.into())
470    }
471}
472
473impl Display for Offset32 {
474    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
475        // 0 displays as an empty offset.
476        if self.0 == 0 {
477            return Ok(());
478        }
479
480        // Always include a sign.
481        write!(f, "{}", if self.0 < 0 { '-' } else { '+' })?;
482
483        let val = i64::from(self.0).abs();
484        if val < 10_000 {
485            write!(f, "{val}")
486        } else {
487            write_hex(val as u64, f)
488        }
489    }
490}
491
492impl FromStr for Offset32 {
493    type Err = &'static str;
494
495    // Parse a decimal or hexadecimal `Offset32`, formatted as above.
496    fn from_str(s: &str) -> Result<Self, &'static str> {
497        if !(s.starts_with('-') || s.starts_with('+')) {
498            return Err("Offset must begin with sign");
499        }
500        parse_i64(s).and_then(|x| {
501            if i64::from(i32::MIN) <= x && x <= i64::from(i32::MAX) {
502                Ok(Self::new(x as i32))
503            } else {
504                Err("Offset out of range")
505            }
506        })
507    }
508}
509
510// FIXME(rust-lang/rust#83527): Replace with `${ignore()}` once it is stabilised.
511macro_rules! ignore {
512    ($($t:tt)*) => {};
513}
514
515macro_rules! ieee_float {
516    (
517        name = $name:ident,
518        bits = $bits:literal,
519        significand_bits = $significand_bits:literal,
520        bits_ty = $bits_ty:ident,
521        float_ty = $float_ty:ident,
522        $(as_float = $as_float:ident,)?
523        $(rust_type_not_stable = $rust_type_not_stable:ident,)?
524    ) => {
525        /// An IEEE
526        #[doc = concat!("binary", stringify!($bits))]
527        /// immediate floating point value, represented as a
528        #[doc = stringify!($bits_ty)]
529        /// containing the bit pattern.
530        ///
531        /// We specifically avoid using a
532        #[doc = stringify!($float_ty)]
533        /// here since some architectures may silently alter floats.
534        /// See: <https://github.com/bytecodealliance/wasmtime/pull/2251#discussion_r498508646>
535        ///
536        /// The [PartialEq] and [Hash] implementations are over the underlying bit pattern, but
537        /// [PartialOrd] respects IEEE754 semantics.
538        ///
539        /// All bit patterns are allowed.
540        #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
541        #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
542        #[repr(C)]
543        pub struct $name {
544            bits: $bits_ty
545        }
546
547        impl $name {
548            const BITS: u8 = $bits;
549            const SIGNIFICAND_BITS: u8 = $significand_bits;
550            const EXPONENT_BITS: u8 = Self::BITS - Self::SIGNIFICAND_BITS - 1;
551            const SIGN_MASK: $bits_ty = 1 << (Self::EXPONENT_BITS + Self::SIGNIFICAND_BITS);
552            const SIGNIFICAND_MASK: $bits_ty = $bits_ty::MAX >> (Self::EXPONENT_BITS + 1);
553            const EXPONENT_MASK: $bits_ty = !Self::SIGN_MASK & !Self::SIGNIFICAND_MASK;
554            /// The positive WebAssembly canonical NaN.
555            pub const NAN: Self = Self::with_bits(Self::EXPONENT_MASK | (1 << (Self::SIGNIFICAND_BITS - 1)));
556
557            /// Create a new
558            #[doc = concat!("`", stringify!($name), "`")]
559            /// containing the bits of `bits`.
560            pub const fn with_bits(bits: $bits_ty) -> Self {
561                Self { bits }
562            }
563
564            /// Get the bitwise representation.
565            pub fn bits(self) -> $bits_ty {
566                self.bits
567            }
568
569            $(
570                /// Create a new
571                #[doc = concat!("`", stringify!($name), "`")]
572                /// representing the number `x`.
573                pub fn with_float(x: $float_ty) -> Self {
574                    Self::with_bits(x.to_bits())
575                }
576
577                /// Converts `self` to a Rust
578                #[doc = concat!("`", stringify!($float_ty), "`.")]
579                pub fn $as_float(self) -> $float_ty {
580                    $float_ty::from_bits(self.bits())
581                }
582            )?
583
584            /// Computes the absolute value of `self`.
585            pub fn abs(self) -> Self {
586                Self::with_bits(self.bits() & !Self::SIGN_MASK)
587            }
588
589            /// Returns a number composed of the magnitude of `self` and the sign of `sign`.
590            pub fn copysign(self, sign: Self) -> Self {
591                Self::with_bits((self.bits() & !Self::SIGN_MASK) | (sign.bits() & Self::SIGN_MASK))
592            }
593
594            /// Returns the minimum of `self` and `other`, following the WebAssembly/IEEE 754-2019 definition.
595            pub fn minimum(self, other: Self) -> Self {
596                // FIXME: Replace with Rust float method once it is stabilised.
597                if self.is_nan() || other.is_nan() {
598                    Self::NAN
599                } else if self.is_zero() && other.is_zero() {
600                    if self.is_negative() {
601                        self
602                    } else {
603                        other
604                    }
605                } else if self <= other {
606                    self
607                } else {
608                    other
609                }
610            }
611
612            /// Returns the maximum of `self` and `other`, following the WebAssembly/IEEE 754-2019 definition.
613            pub fn maximum(self, other: Self) -> Self {
614                // FIXME: Replace with Rust float method once it is stabilised.
615                if self.is_nan() || other.is_nan() {
616                    Self::NAN
617                } else if self.is_zero() && other.is_zero() {
618                    if self.is_positive() {
619                        self
620                    } else {
621                        other
622                    }
623                } else if self >= other {
624                    self
625                } else {
626                    other
627                }
628            }
629
630            /// Create an
631            #[doc = concat!("`", stringify!($name), "`")]
632            /// number representing `2.0^n`.
633            pub fn pow2<I: Into<i32>>(n: I) -> Self {
634                let n = n.into();
635                let w = Self::EXPONENT_BITS;
636                let t = Self::SIGNIFICAND_BITS;
637                let bias = (1 << (w - 1)) - 1;
638                let exponent = n + bias;
639                assert!(exponent > 0, "Underflow n={}", n);
640                assert!(exponent < (1 << w) + 1, "Overflow n={}", n);
641                Self::with_bits((exponent as $bits_ty) << t)
642            }
643
644            /// Create an
645            #[doc = concat!("`", stringify!($name), "`")]
646            /// number representing the greatest negative value not convertible from
647            #[doc = concat!("`", stringify!($float_ty), "`")]
648            /// to a signed integer with width n.
649            pub fn fcvt_to_sint_negative_overflow<I: Into<i32>>(n: I) -> Self {
650                let n = n.into();
651                debug_assert!(n < i32::from(Self::BITS));
652                debug_assert!(i32::from(Self::SIGNIFICAND_BITS) + 1 - n < i32::from(Self::BITS));
653                Self::with_bits((1 << (Self::BITS - 1)) | Self::pow2(n - 1).bits() | (1 << (i32::from(Self::SIGNIFICAND_BITS) + 1 - n)))
654            }
655
656            /// Check if the value is a NaN. For
657            #[doc = concat!("`", stringify!($name), "`,")]
658            /// this means checking that all the exponent bits are set and the significand is non-zero.
659            pub fn is_nan(self) -> bool {
660                self.abs().bits() > Self::EXPONENT_MASK
661            }
662
663            /// Returns true if `self` has a negative sign, including 0.0, NaNs with positive sign bit and positive infinity.
664            pub fn is_positive(self) -> bool {
665                !self.is_negative()
666            }
667
668            /// Returns true if `self` has a negative sign, including -0.0, NaNs with negative sign bit and negative infinity.
669            pub fn is_negative(self) -> bool {
670                self.bits() & Self::SIGN_MASK == Self::SIGN_MASK
671            }
672
673            /// Returns `true` if `self` is positive or negative zero.
674            pub fn is_zero(self) -> bool {
675                self.abs().bits() == 0
676            }
677
678            /// Returns `None` if `self` is a NaN and `Some(self)` otherwise.
679            pub fn non_nan(self) -> Option<Self> {
680                Some(self).filter(|f| !f.is_nan())
681            }
682
683            $(
684                /// Returns the square root of `self`.
685                pub fn sqrt(self) -> Self {
686                    Self::with_float(self.$as_float().sqrt())
687                }
688
689                /// Returns the smallest integer greater than or equal to `self`.
690                pub fn ceil(self) -> Self {
691                    Self::with_float(self.$as_float().ceil())
692                }
693
694                /// Returns the largest integer less than or equal to `self`.
695                pub fn floor(self) -> Self {
696                    Self::with_float(self.$as_float().floor())
697                }
698
699                /// Returns the integer part of `self`. This means that non-integer numbers are always truncated towards zero.
700                pub fn trunc(self) -> Self {
701                    Self::with_float(self.$as_float().trunc())
702                }
703
704                /// Returns the nearest integer to `self`. Rounds half-way cases to the number
705                /// with an even least significant digit.
706                pub fn round_ties_even(self) -> Self {
707                    Self::with_float(self.$as_float().round_ties_even())
708                }
709            )?
710        }
711
712        impl PartialOrd for $name {
713            fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
714                $(self.$as_float().partial_cmp(&rhs.$as_float()))?
715                $(
716                    ignore!($rust_type_not_stable);
717                    // FIXME(#8312): Use builtin Rust comparisons once `f16` and `f128` support is stabalised.
718                    if self.is_nan() || rhs.is_nan() {
719                        // One of the floats is a NaN.
720                        return None;
721                    }
722                    if self.is_zero() || rhs.is_zero() {
723                        // Zeros are always equal regardless of sign.
724                        return Some(Ordering::Equal);
725                    }
726                    let lhs_positive = self.is_positive();
727                    let rhs_positive = rhs.is_positive();
728                    if lhs_positive != rhs_positive {
729                        // Different signs: negative < positive
730                        return lhs_positive.partial_cmp(&rhs_positive);
731                    }
732                    // Finite or infinity will order correctly with an integer comparison of the bits.
733                    if lhs_positive {
734                        self.bits().partial_cmp(&rhs.bits())
735                    } else {
736                        // Reverse the comparison when both floats are negative.
737                        rhs.bits().partial_cmp(&self.bits())
738                    }
739                )?
740            }
741        }
742
743        impl Display for $name {
744            fn fmt(&self, f: &mut Formatter) -> fmt::Result {
745                format_float(u128::from(self.bits()), Self::EXPONENT_BITS, Self::SIGNIFICAND_BITS, f)
746            }
747        }
748
749        impl FromStr for $name {
750            type Err = &'static str;
751
752            fn from_str(s: &str) -> Result<Self, &'static str> {
753                match parse_float(s, Self::EXPONENT_BITS, Self::SIGNIFICAND_BITS) {
754                    Ok(b) => Ok(Self::with_bits(b.try_into().unwrap())),
755                    Err(s) => Err(s),
756                }
757            }
758        }
759
760        impl IntoBytes for $name {
761            fn into_bytes(self) -> Vec<u8> {
762                self.bits().to_le_bytes().to_vec()
763            }
764        }
765
766        impl Neg for $name {
767            type Output = Self;
768
769            fn neg(self) -> Self {
770                Self::with_bits(self.bits() ^ Self::SIGN_MASK)
771            }
772        }
773
774
775
776        $(
777            impl From<$float_ty> for $name {
778                fn from(x: $float_ty) -> Self {
779                    Self::with_float(x)
780                }
781            }
782
783            impl Add for $name {
784                type Output = Self;
785
786                fn add(self, rhs: Self) -> Self {
787                    Self::with_float(self.$as_float() + rhs.$as_float())
788                }
789            }
790
791            impl Sub for $name {
792                type Output = Self;
793
794                fn sub(self, rhs: Self) -> Self {
795                    Self::with_float(self.$as_float() - rhs.$as_float())
796                }
797            }
798
799            impl Mul for $name {
800                type Output = Self;
801
802                fn mul(self, rhs: Self) -> Self {
803                    Self::with_float(self.$as_float() * rhs.$as_float())
804                }
805            }
806
807            impl Div for $name {
808                type Output = Self;
809
810                fn div(self, rhs: Self) -> Self::Output {
811                    Self::with_float(self.$as_float() / rhs.$as_float())
812                }
813            }
814        )?
815
816        impl BitAnd for $name {
817            type Output = Self;
818
819            fn bitand(self, rhs: Self) -> Self {
820                Self::with_bits(self.bits() & rhs.bits())
821            }
822        }
823
824        impl BitOr for $name {
825            type Output = Self;
826
827            fn bitor(self, rhs: Self) -> Self {
828                Self::with_bits(self.bits() | rhs.bits())
829            }
830        }
831
832        impl BitXor for $name {
833            type Output = Self;
834
835            fn bitxor(self, rhs: Self) -> Self {
836                Self::with_bits(self.bits() ^ rhs.bits())
837            }
838        }
839
840        impl Not for $name {
841            type Output = Self;
842
843            fn not(self) -> Self {
844                Self::with_bits(!self.bits())
845            }
846        }
847    };
848}
849
850ieee_float! {
851    name = Ieee16,
852    bits = 16,
853    significand_bits = 10,
854    bits_ty = u16,
855    float_ty = f16,
856    rust_type_not_stable = rust_type_not_stable,
857}
858
859ieee_float! {
860    name = Ieee32,
861    bits = 32,
862    significand_bits = 23,
863    bits_ty = u32,
864    float_ty = f32,
865    as_float = as_f32,
866}
867
868ieee_float! {
869    name = Ieee64,
870    bits = 64,
871    significand_bits = 52,
872    bits_ty = u64,
873    float_ty = f64,
874    as_float = as_f64,
875}
876
877ieee_float! {
878    name = Ieee128,
879    bits = 128,
880    significand_bits = 112,
881    bits_ty = u128,
882    float_ty = f128,
883    rust_type_not_stable = rust_type_not_stable,
884}
885
886/// Format a floating point number in a way that is reasonably human-readable, and that can be
887/// converted back to binary without any rounding issues. The hexadecimal formatting of normal and
888/// subnormal numbers is compatible with C99 and the `printf "%a"` format specifier. The NaN and Inf
889/// formats are not supported by C99.
890///
891/// The encoding parameters are:
892///
893/// w - exponent field width in bits
894/// t - trailing significand field width in bits
895///
896fn format_float(bits: u128, w: u8, t: u8, f: &mut Formatter) -> fmt::Result {
897    debug_assert!(w > 0 && w <= 16, "Invalid exponent range");
898    debug_assert!(1 + w + t <= 128, "Too large IEEE format for u128");
899    debug_assert!((t + w + 1).is_power_of_two(), "Unexpected IEEE format size");
900
901    let max_e_bits = (1u128 << w) - 1;
902    let t_bits = bits & ((1u128 << t) - 1); // Trailing significand.
903    let e_bits = (bits >> t) & max_e_bits; // Biased exponent.
904    let sign_bit = (bits >> (w + t)) & 1;
905
906    let bias: i32 = (1 << (w - 1)) - 1;
907    let e = e_bits as i32 - bias; // Unbiased exponent.
908    let emin = 1 - bias; // Minimum exponent.
909
910    // How many hexadecimal digits are needed for the trailing significand?
911    let digits = (t + 3) / 4;
912    // Trailing significand left-aligned in `digits` hexadecimal digits.
913    let left_t_bits = t_bits << (4 * digits - t);
914
915    // All formats share the leading sign.
916    if sign_bit != 0 {
917        write!(f, "-")?;
918    }
919
920    if e_bits == 0 {
921        if t_bits == 0 {
922            // Zero.
923            write!(f, "0.0")
924        } else {
925            // Subnormal.
926            write!(
927                f,
928                "0x0.{0:01$x}p{2}",
929                left_t_bits,
930                usize::from(digits),
931                emin
932            )
933        }
934    } else if e_bits == max_e_bits {
935        // Always print a `+` or `-` sign for these special values.
936        // This makes them easier to parse as they can't be confused as identifiers.
937        if sign_bit == 0 {
938            write!(f, "+")?;
939        }
940        if t_bits == 0 {
941            // Infinity.
942            write!(f, "Inf")
943        } else {
944            // NaN.
945            let payload = t_bits & ((1 << (t - 1)) - 1);
946            if t_bits & (1 << (t - 1)) != 0 {
947                // Quiet NaN.
948                if payload != 0 {
949                    write!(f, "NaN:0x{payload:x}")
950                } else {
951                    write!(f, "NaN")
952                }
953            } else {
954                // Signaling NaN.
955                write!(f, "sNaN:0x{payload:x}")
956            }
957        }
958    } else {
959        // Normal number.
960        write!(f, "0x1.{0:01$x}p{2}", left_t_bits, usize::from(digits), e)
961    }
962}
963
964/// Parse a float using the same format as `format_float` above.
965///
966/// The encoding parameters are:
967///
968/// w - exponent field width in bits
969/// t - trailing significand field width in bits
970///
971fn parse_float(s: &str, w: u8, t: u8) -> Result<u128, &'static str> {
972    debug_assert!(w > 0 && w <= 16, "Invalid exponent range");
973    debug_assert!(1 + w + t <= 128, "Too large IEEE format for u128");
974    debug_assert!((t + w + 1).is_power_of_two(), "Unexpected IEEE format size");
975
976    let (sign_bit, s2) = if let Some(num) = s.strip_prefix('-') {
977        (1u128 << (t + w), num)
978    } else if let Some(num) = s.strip_prefix('+') {
979        (0, num)
980    } else {
981        (0, s)
982    };
983
984    if !s2.starts_with("0x") {
985        let max_e_bits = ((1u128 << w) - 1) << t;
986        let quiet_bit = 1u128 << (t - 1);
987
988        // The only decimal encoding allowed is 0.
989        if s2 == "0.0" {
990            return Ok(sign_bit);
991        }
992
993        if s2 == "Inf" {
994            // +/- infinity: e = max, t = 0.
995            return Ok(sign_bit | max_e_bits);
996        }
997        if s2 == "NaN" {
998            // Canonical quiet NaN: e = max, t = quiet.
999            return Ok(sign_bit | max_e_bits | quiet_bit);
1000        }
1001        if let Some(nan) = s2.strip_prefix("NaN:0x") {
1002            // Quiet NaN with payload.
1003            return match u128::from_str_radix(nan, 16) {
1004                Ok(payload) if payload < quiet_bit => {
1005                    Ok(sign_bit | max_e_bits | quiet_bit | payload)
1006                }
1007                _ => Err("Invalid NaN payload"),
1008            };
1009        }
1010        if let Some(nan) = s2.strip_prefix("sNaN:0x") {
1011            // Signaling NaN with payload.
1012            return match u128::from_str_radix(nan, 16) {
1013                Ok(payload) if 0 < payload && payload < quiet_bit => {
1014                    Ok(sign_bit | max_e_bits | payload)
1015                }
1016                _ => Err("Invalid sNaN payload"),
1017            };
1018        }
1019
1020        return Err("Float must be hexadecimal");
1021    }
1022    let s3 = &s2[2..];
1023
1024    let mut digits = 0u8;
1025    let mut digits_before_period: Option<u8> = None;
1026    let mut significand = 0u128;
1027    let mut exponent = 0i32;
1028
1029    for (idx, ch) in s3.char_indices() {
1030        match ch {
1031            '.' => {
1032                // This is the radix point. There can only be one.
1033                if digits_before_period != None {
1034                    return Err("Multiple radix points");
1035                } else {
1036                    digits_before_period = Some(digits);
1037                }
1038            }
1039            'p' => {
1040                // The following exponent is a decimal number.
1041                let exp_str = &s3[1 + idx..];
1042                match exp_str.parse::<i16>() {
1043                    Ok(e) => {
1044                        exponent = i32::from(e);
1045                        break;
1046                    }
1047                    Err(_) => return Err("Bad exponent"),
1048                }
1049            }
1050            _ => match ch.to_digit(16) {
1051                Some(digit) => {
1052                    digits += 1;
1053                    if digits > 32 {
1054                        return Err("Too many digits");
1055                    }
1056                    significand = (significand << 4) | u128::from(digit);
1057                }
1058                None => return Err("Invalid character"),
1059            },
1060        }
1061    }
1062
1063    if digits == 0 {
1064        return Err("No digits");
1065    }
1066
1067    if significand == 0 {
1068        // This is +/- 0.0.
1069        return Ok(sign_bit);
1070    }
1071
1072    // Number of bits appearing after the radix point.
1073    match digits_before_period {
1074        None => {} // No radix point present.
1075        Some(d) => exponent -= 4 * i32::from(digits - d),
1076    };
1077
1078    // Normalize the significand and exponent.
1079    let significant_bits = (128 - significand.leading_zeros()) as u8;
1080    if significant_bits > t + 1 {
1081        let adjust = significant_bits - (t + 1);
1082        if significand & ((1u128 << adjust) - 1) != 0 {
1083            return Err("Too many significant bits");
1084        }
1085        // Adjust significand down.
1086        significand >>= adjust;
1087        exponent += i32::from(adjust);
1088    } else {
1089        let adjust = t + 1 - significant_bits;
1090        significand <<= adjust;
1091        exponent -= i32::from(adjust);
1092    }
1093    debug_assert_eq!(significand >> t, 1);
1094
1095    // Trailing significand excludes the high bit.
1096    let t_bits = significand & ((1 << t) - 1);
1097
1098    let max_exp = (1i32 << w) - 2;
1099    let bias: i32 = (1 << (w - 1)) - 1;
1100    exponent += bias + i32::from(t);
1101
1102    if exponent > max_exp {
1103        Err("Magnitude too large")
1104    } else if exponent > 0 {
1105        // This is a normal number.
1106        let e_bits = (exponent as u128) << t;
1107        Ok(sign_bit | e_bits | t_bits)
1108    } else if 1 - exponent <= i32::from(t) {
1109        // This is a subnormal number: e = 0, t = significand bits.
1110        // Renormalize significand for exponent = 1.
1111        let adjust = 1 - exponent;
1112        if significand & ((1u128 << adjust) - 1) != 0 {
1113            Err("Subnormal underflow")
1114        } else {
1115            significand >>= adjust;
1116            Ok(sign_bit | significand)
1117        }
1118    } else {
1119        Err("Magnitude too small")
1120    }
1121}
1122
1123#[cfg(test)]
1124mod tests {
1125    use super::*;
1126    use alloc::string::ToString;
1127    use core::{f32, f64};
1128
1129    #[test]
1130    fn format_imm64() {
1131        assert_eq!(Imm64(0).to_string(), "0");
1132        assert_eq!(Imm64(9999).to_string(), "9999");
1133        assert_eq!(Imm64(10000).to_string(), "0x2710");
1134        assert_eq!(Imm64(-9999).to_string(), "-9999");
1135        assert_eq!(Imm64(-10000).to_string(), "-10000");
1136        assert_eq!(Imm64(0xffff).to_string(), "0xffff");
1137        assert_eq!(Imm64(0x10000).to_string(), "0x0001_0000");
1138    }
1139
1140    #[test]
1141    fn format_uimm64() {
1142        assert_eq!(Uimm64(0).to_string(), "0");
1143        assert_eq!(Uimm64(9999).to_string(), "9999");
1144        assert_eq!(Uimm64(10000).to_string(), "0x2710");
1145        assert_eq!(Uimm64(-9999i64 as u64).to_string(), "0xffff_ffff_ffff_d8f1");
1146        assert_eq!(
1147            Uimm64(-10000i64 as u64).to_string(),
1148            "0xffff_ffff_ffff_d8f0"
1149        );
1150        assert_eq!(Uimm64(0xffff).to_string(), "0xffff");
1151        assert_eq!(Uimm64(0x10000).to_string(), "0x0001_0000");
1152    }
1153
1154    // Verify that `text` can be parsed as a `T` into a value that displays as `want`.
1155    #[track_caller]
1156    fn parse_ok<T: FromStr + Display>(text: &str, want: &str)
1157    where
1158        <T as FromStr>::Err: Display,
1159    {
1160        match text.parse::<T>() {
1161            Err(s) => panic!("\"{text}\".parse() error: {s}"),
1162            Ok(x) => assert_eq!(x.to_string(), want),
1163        }
1164    }
1165
1166    // Verify that `text` fails to parse as `T` with the error `msg`.
1167    fn parse_err<T: FromStr + Display>(text: &str, msg: &str)
1168    where
1169        <T as FromStr>::Err: Display,
1170    {
1171        match text.parse::<T>() {
1172            Err(s) => assert_eq!(s.to_string(), msg),
1173            Ok(x) => panic!("Wanted Err({msg}), but got {x}"),
1174        }
1175    }
1176
1177    #[test]
1178    fn parse_imm64() {
1179        parse_ok::<Imm64>("0", "0");
1180        parse_ok::<Imm64>("1", "1");
1181        parse_ok::<Imm64>("-0", "0");
1182        parse_ok::<Imm64>("-1", "-1");
1183        parse_ok::<Imm64>("0x0", "0");
1184        parse_ok::<Imm64>("0xf", "15");
1185        parse_ok::<Imm64>("-0x9", "-9");
1186
1187        // Probe limits.
1188        parse_ok::<Imm64>("0xffffffff_ffffffff", "-1");
1189        parse_ok::<Imm64>("0x80000000_00000000", "-9223372036854775808");
1190        parse_ok::<Imm64>("-0x80000000_00000000", "-9223372036854775808");
1191        parse_err::<Imm64>("-0x80000000_00000001", "Negative number too small");
1192        parse_ok::<Imm64>("18446744073709551615", "-1");
1193        parse_ok::<Imm64>("-9223372036854775808", "-9223372036854775808");
1194        // Overflow both the `checked_add` and `checked_mul`.
1195        parse_err::<Imm64>("18446744073709551616", "Too large decimal number");
1196        parse_err::<Imm64>("184467440737095516100", "Too large decimal number");
1197        parse_err::<Imm64>("-9223372036854775809", "Negative number too small");
1198
1199        // Underscores are allowed where digits go.
1200        parse_ok::<Imm64>("0_0", "0");
1201        parse_ok::<Imm64>("-_10_0", "-100");
1202        parse_ok::<Imm64>("_10_", "10");
1203        parse_ok::<Imm64>("0x97_88_bb", "0x0097_88bb");
1204        parse_ok::<Imm64>("0x_97_", "151");
1205
1206        parse_err::<Imm64>("", "No digits in number");
1207        parse_err::<Imm64>("-", "No digits in number");
1208        parse_err::<Imm64>("_", "No digits in number");
1209        parse_err::<Imm64>("0x", "No digits in number");
1210        parse_err::<Imm64>("0x_", "No digits in number");
1211        parse_err::<Imm64>("-0x", "No digits in number");
1212        parse_err::<Imm64>(" ", "Invalid character in decimal number");
1213        parse_err::<Imm64>("0 ", "Invalid character in decimal number");
1214        parse_err::<Imm64>(" 0", "Invalid character in decimal number");
1215        parse_err::<Imm64>("--", "Invalid character in decimal number");
1216        parse_err::<Imm64>("-0x-", "Invalid character in hexadecimal number");
1217        parse_err::<Imm64>("abc", "Invalid character in decimal number");
1218        parse_err::<Imm64>("-abc", "Invalid character in decimal number");
1219
1220        // Hex count overflow.
1221        parse_err::<Imm64>("0x0_0000_0000_0000_0000", "Too many hexadecimal digits");
1222    }
1223
1224    #[test]
1225    fn parse_uimm64() {
1226        parse_ok::<Uimm64>("0", "0");
1227        parse_ok::<Uimm64>("1", "1");
1228        parse_ok::<Uimm64>("0x0", "0");
1229        parse_ok::<Uimm64>("0xf", "15");
1230        parse_ok::<Uimm64>("0xffffffff_fffffff7", "0xffff_ffff_ffff_fff7");
1231
1232        // Probe limits.
1233        parse_ok::<Uimm64>("0xffffffff_ffffffff", "0xffff_ffff_ffff_ffff");
1234        parse_ok::<Uimm64>("0x80000000_00000000", "0x8000_0000_0000_0000");
1235        parse_ok::<Uimm64>("18446744073709551615", "0xffff_ffff_ffff_ffff");
1236        // Overflow both the `checked_add` and `checked_mul`.
1237        parse_err::<Uimm64>("18446744073709551616", "Too large decimal number");
1238        parse_err::<Uimm64>("184467440737095516100", "Too large decimal number");
1239
1240        // Underscores are allowed where digits go.
1241        parse_ok::<Uimm64>("0_0", "0");
1242        parse_ok::<Uimm64>("_10_", "10");
1243        parse_ok::<Uimm64>("0x97_88_bb", "0x0097_88bb");
1244        parse_ok::<Uimm64>("0x_97_", "151");
1245
1246        parse_err::<Uimm64>("", "No digits in number");
1247        parse_err::<Uimm64>("_", "No digits in number");
1248        parse_err::<Uimm64>("0x", "No digits in number");
1249        parse_err::<Uimm64>("0x_", "No digits in number");
1250        parse_err::<Uimm64>("-", "Invalid character in decimal number");
1251        parse_err::<Uimm64>("-0x", "Invalid character in hexadecimal number");
1252        parse_err::<Uimm64>(" ", "Invalid character in decimal number");
1253        parse_err::<Uimm64>("0 ", "Invalid character in decimal number");
1254        parse_err::<Uimm64>(" 0", "Invalid character in decimal number");
1255        parse_err::<Uimm64>("--", "Invalid character in decimal number");
1256        parse_err::<Uimm64>("-0x-", "Invalid character in hexadecimal number");
1257        parse_err::<Uimm64>("-0", "Invalid character in decimal number");
1258        parse_err::<Uimm64>("-1", "Invalid character in decimal number");
1259        parse_err::<Uimm64>("abc", "Invalid character in decimal number");
1260        parse_err::<Uimm64>("-abc", "Invalid character in decimal number");
1261
1262        // Hex count overflow.
1263        parse_err::<Uimm64>("0x0_0000_0000_0000_0000", "Too many hexadecimal digits");
1264    }
1265
1266    #[test]
1267    fn format_offset32() {
1268        assert_eq!(Offset32(0).to_string(), "");
1269        assert_eq!(Offset32(1).to_string(), "+1");
1270        assert_eq!(Offset32(-1).to_string(), "-1");
1271        assert_eq!(Offset32(9999).to_string(), "+9999");
1272        assert_eq!(Offset32(10000).to_string(), "+0x2710");
1273        assert_eq!(Offset32(-9999).to_string(), "-9999");
1274        assert_eq!(Offset32(-10000).to_string(), "-0x2710");
1275        assert_eq!(Offset32(0xffff).to_string(), "+0xffff");
1276        assert_eq!(Offset32(0x10000).to_string(), "+0x0001_0000");
1277    }
1278
1279    #[test]
1280    fn parse_offset32() {
1281        parse_ok::<Offset32>("+0", "");
1282        parse_ok::<Offset32>("+1", "+1");
1283        parse_ok::<Offset32>("-0", "");
1284        parse_ok::<Offset32>("-1", "-1");
1285        parse_ok::<Offset32>("+0x0", "");
1286        parse_ok::<Offset32>("+0xf", "+15");
1287        parse_ok::<Offset32>("-0x9", "-9");
1288        parse_ok::<Offset32>("-0x8000_0000", "-0x8000_0000");
1289
1290        parse_err::<Offset32>("+0x8000_0000", "Offset out of range");
1291    }
1292
1293    #[test]
1294    fn format_ieee16() {
1295        assert_eq!(Ieee16::with_bits(0).to_string(), "0.0"); // 0.0
1296        assert_eq!(Ieee16::with_bits(0x8000).to_string(), "-0.0"); // -0.0
1297        assert_eq!(Ieee16::with_bits(0x3c00).to_string(), "0x1.000p0"); // 1.0
1298        assert_eq!(Ieee16::with_bits(0x3e00).to_string(), "0x1.800p0"); // 1.5
1299        assert_eq!(Ieee16::with_bits(0x3800).to_string(), "0x1.000p-1"); // 0.5
1300        assert_eq!(
1301            Ieee16::with_bits(0x1400).to_string(), // `f16::EPSILON`
1302            "0x1.000p-10"
1303        );
1304        assert_eq!(
1305            Ieee16::with_bits(0xfbff).to_string(), // `f16::MIN`
1306            "-0x1.ffcp15"
1307        );
1308        assert_eq!(
1309            Ieee16::with_bits(0x7bff).to_string(), // `f16::MAX`
1310            "0x1.ffcp15"
1311        );
1312        // Smallest positive normal number.
1313        assert_eq!(
1314            Ieee16::with_bits(0x0400).to_string(), // `f16::MIN_POSITIVE`
1315            "0x1.000p-14"
1316        );
1317        // Subnormals.
1318        assert_eq!(
1319            Ieee16::with_bits(0x0200).to_string(), // `f16::MIN_POSITIVE / 2.0`
1320            "0x0.800p-14"
1321        );
1322        assert_eq!(
1323            Ieee16::with_bits(0x0001).to_string(), // `f16::MIN_POSITIVE * f16::EPSILON`
1324            "0x0.004p-14"
1325        );
1326        assert_eq!(
1327            Ieee16::with_bits(0x7c00).to_string(), // `f16::INFINITY`
1328            "+Inf"
1329        );
1330        assert_eq!(
1331            Ieee16::with_bits(0xfc00).to_string(), // `f16::NEG_INFINITY`
1332            "-Inf"
1333        );
1334        assert_eq!(
1335            Ieee16::with_bits(0x7e00).to_string(), // `f16::NAN`
1336            "+NaN"
1337        );
1338        assert_eq!(
1339            Ieee16::with_bits(0xfe00).to_string(), // `-f16::NAN`
1340            "-NaN"
1341        );
1342        // Construct some qNaNs with payloads.
1343        assert_eq!(Ieee16::with_bits(0x7e01).to_string(), "+NaN:0x1");
1344        assert_eq!(Ieee16::with_bits(0x7f01).to_string(), "+NaN:0x101");
1345        // Signaling NaNs.
1346        assert_eq!(Ieee16::with_bits(0x7c01).to_string(), "+sNaN:0x1");
1347        assert_eq!(Ieee16::with_bits(0x7d01).to_string(), "+sNaN:0x101");
1348    }
1349
1350    #[test]
1351    fn parse_ieee16() {
1352        parse_ok::<Ieee16>("0.0", "0.0");
1353        parse_ok::<Ieee16>("+0.0", "0.0");
1354        parse_ok::<Ieee16>("-0.0", "-0.0");
1355        parse_ok::<Ieee16>("0x0", "0.0");
1356        parse_ok::<Ieee16>("0x0.0", "0.0");
1357        parse_ok::<Ieee16>("0x.0", "0.0");
1358        parse_ok::<Ieee16>("0x0.", "0.0");
1359        parse_ok::<Ieee16>("0x1", "0x1.000p0");
1360        parse_ok::<Ieee16>("+0x1", "0x1.000p0");
1361        parse_ok::<Ieee16>("-0x1", "-0x1.000p0");
1362        parse_ok::<Ieee16>("0x10", "0x1.000p4");
1363        parse_ok::<Ieee16>("0x10.0", "0x1.000p4");
1364        parse_err::<Ieee16>("0.", "Float must be hexadecimal");
1365        parse_err::<Ieee16>(".0", "Float must be hexadecimal");
1366        parse_err::<Ieee16>("0", "Float must be hexadecimal");
1367        parse_err::<Ieee16>("-0", "Float must be hexadecimal");
1368        parse_err::<Ieee16>(".", "Float must be hexadecimal");
1369        parse_err::<Ieee16>("", "Float must be hexadecimal");
1370        parse_err::<Ieee16>("-", "Float must be hexadecimal");
1371        parse_err::<Ieee16>("0x", "No digits");
1372        parse_err::<Ieee16>("0x..", "Multiple radix points");
1373
1374        // Check significant bits.
1375        parse_ok::<Ieee16>("0x0.ffe", "0x1.ffcp-1");
1376        parse_ok::<Ieee16>("0x1.ffc", "0x1.ffcp0");
1377        parse_ok::<Ieee16>("0x3.ff8", "0x1.ffcp1");
1378        parse_ok::<Ieee16>("0x7.ff", "0x1.ffcp2");
1379        parse_ok::<Ieee16>("0xf.fe", "0x1.ffcp3");
1380        parse_err::<Ieee16>("0x1.ffe", "Too many significant bits");
1381        parse_err::<Ieee16>("0x1.ffc00000000000000000000000000000", "Too many digits");
1382
1383        // Exponents.
1384        parse_ok::<Ieee16>("0x1p3", "0x1.000p3");
1385        parse_ok::<Ieee16>("0x1p-3", "0x1.000p-3");
1386        parse_ok::<Ieee16>("0x1.0p3", "0x1.000p3");
1387        parse_ok::<Ieee16>("0x2.0p3", "0x1.000p4");
1388        parse_ok::<Ieee16>("0x1.0p15", "0x1.000p15");
1389        parse_ok::<Ieee16>("0x1.0p-14", "0x1.000p-14");
1390        parse_ok::<Ieee16>("0x0.1p-10", "0x1.000p-14");
1391        parse_err::<Ieee16>("0x2.0p15", "Magnitude too large");
1392
1393        // Subnormals.
1394        parse_ok::<Ieee16>("0x1.0p-15", "0x0.800p-14");
1395        parse_ok::<Ieee16>("0x1.0p-24", "0x0.004p-14");
1396        parse_ok::<Ieee16>("0x0.004p-14", "0x0.004p-14");
1397        parse_err::<Ieee16>("0x0.102p-14", "Subnormal underflow");
1398        parse_err::<Ieee16>("0x1.8p-24", "Subnormal underflow");
1399        parse_err::<Ieee16>("0x1.0p-25", "Magnitude too small");
1400
1401        // NaNs and Infs.
1402        parse_ok::<Ieee16>("Inf", "+Inf");
1403        parse_ok::<Ieee16>("+Inf", "+Inf");
1404        parse_ok::<Ieee16>("-Inf", "-Inf");
1405        parse_ok::<Ieee16>("NaN", "+NaN");
1406        parse_ok::<Ieee16>("+NaN", "+NaN");
1407        parse_ok::<Ieee16>("-NaN", "-NaN");
1408        parse_ok::<Ieee16>("NaN:0x0", "+NaN");
1409        parse_err::<Ieee16>("NaN:", "Float must be hexadecimal");
1410        parse_err::<Ieee16>("NaN:0", "Float must be hexadecimal");
1411        parse_err::<Ieee16>("NaN:0x", "Invalid NaN payload");
1412        parse_ok::<Ieee16>("NaN:0x001", "+NaN:0x1");
1413        parse_ok::<Ieee16>("NaN:0x101", "+NaN:0x101");
1414        parse_err::<Ieee16>("NaN:0x301", "Invalid NaN payload");
1415        parse_ok::<Ieee16>("sNaN:0x1", "+sNaN:0x1");
1416        parse_err::<Ieee16>("sNaN:0x0", "Invalid sNaN payload");
1417        parse_ok::<Ieee16>("sNaN:0x101", "+sNaN:0x101");
1418        parse_err::<Ieee16>("sNaN:0x301", "Invalid sNaN payload");
1419    }
1420
1421    #[test]
1422    fn pow2_ieee16() {
1423        assert_eq!(Ieee16::pow2(0).to_string(), "0x1.000p0");
1424        assert_eq!(Ieee16::pow2(1).to_string(), "0x1.000p1");
1425        assert_eq!(Ieee16::pow2(-1).to_string(), "0x1.000p-1");
1426        assert_eq!(Ieee16::pow2(15).to_string(), "0x1.000p15");
1427        assert_eq!(Ieee16::pow2(-14).to_string(), "0x1.000p-14");
1428
1429        assert_eq!((-Ieee16::pow2(1)).to_string(), "-0x1.000p1");
1430    }
1431
1432    #[test]
1433    fn fcvt_to_sint_negative_overflow_ieee16() {
1434        // FIXME(#8312): Replace with commented out version once Rust f16 support is stabilised.
1435        // let n = 8;
1436        // assert_eq!(
1437        //     -((1u16 << (n - 1)) as f16) - 1.0,
1438        //     Ieee16::fcvt_to_sint_negative_overflow(n).as_f16()
1439        // );
1440        let n = 8;
1441        assert_eq!(
1442            "-0x1.020p7",
1443            Ieee16::fcvt_to_sint_negative_overflow(n).to_string()
1444        );
1445    }
1446
1447    #[test]
1448    fn format_ieee32() {
1449        assert_eq!(Ieee32::with_float(0.0).to_string(), "0.0");
1450        assert_eq!(Ieee32::with_float(-0.0).to_string(), "-0.0");
1451        assert_eq!(Ieee32::with_float(1.0).to_string(), "0x1.000000p0");
1452        assert_eq!(Ieee32::with_float(1.5).to_string(), "0x1.800000p0");
1453        assert_eq!(Ieee32::with_float(0.5).to_string(), "0x1.000000p-1");
1454        assert_eq!(
1455            Ieee32::with_float(f32::EPSILON).to_string(),
1456            "0x1.000000p-23"
1457        );
1458        assert_eq!(Ieee32::with_float(f32::MIN).to_string(), "-0x1.fffffep127");
1459        assert_eq!(Ieee32::with_float(f32::MAX).to_string(), "0x1.fffffep127");
1460        // Smallest positive normal number.
1461        assert_eq!(
1462            Ieee32::with_float(f32::MIN_POSITIVE).to_string(),
1463            "0x1.000000p-126"
1464        );
1465        // Subnormals.
1466        assert_eq!(
1467            Ieee32::with_float(f32::MIN_POSITIVE / 2.0).to_string(),
1468            "0x0.800000p-126"
1469        );
1470        assert_eq!(
1471            Ieee32::with_float(f32::MIN_POSITIVE * f32::EPSILON).to_string(),
1472            "0x0.000002p-126"
1473        );
1474        assert_eq!(Ieee32::with_float(f32::INFINITY).to_string(), "+Inf");
1475        assert_eq!(Ieee32::with_float(f32::NEG_INFINITY).to_string(), "-Inf");
1476        assert_eq!(Ieee32::with_float(f32::NAN).to_string(), "+NaN");
1477        assert_eq!(Ieee32::with_float(-f32::NAN).to_string(), "-NaN");
1478        // Construct some qNaNs with payloads.
1479        assert_eq!(Ieee32::with_bits(0x7fc00001).to_string(), "+NaN:0x1");
1480        assert_eq!(Ieee32::with_bits(0x7ff00001).to_string(), "+NaN:0x300001");
1481        // Signaling NaNs.
1482        assert_eq!(Ieee32::with_bits(0x7f800001).to_string(), "+sNaN:0x1");
1483        assert_eq!(Ieee32::with_bits(0x7fa00001).to_string(), "+sNaN:0x200001");
1484    }
1485
1486    #[test]
1487    fn parse_ieee32() {
1488        parse_ok::<Ieee32>("0.0", "0.0");
1489        parse_ok::<Ieee32>("+0.0", "0.0");
1490        parse_ok::<Ieee32>("-0.0", "-0.0");
1491        parse_ok::<Ieee32>("0x0", "0.0");
1492        parse_ok::<Ieee32>("0x0.0", "0.0");
1493        parse_ok::<Ieee32>("0x.0", "0.0");
1494        parse_ok::<Ieee32>("0x0.", "0.0");
1495        parse_ok::<Ieee32>("0x1", "0x1.000000p0");
1496        parse_ok::<Ieee32>("+0x1", "0x1.000000p0");
1497        parse_ok::<Ieee32>("-0x1", "-0x1.000000p0");
1498        parse_ok::<Ieee32>("0x10", "0x1.000000p4");
1499        parse_ok::<Ieee32>("0x10.0", "0x1.000000p4");
1500        parse_err::<Ieee32>("0.", "Float must be hexadecimal");
1501        parse_err::<Ieee32>(".0", "Float must be hexadecimal");
1502        parse_err::<Ieee32>("0", "Float must be hexadecimal");
1503        parse_err::<Ieee32>("-0", "Float must be hexadecimal");
1504        parse_err::<Ieee32>(".", "Float must be hexadecimal");
1505        parse_err::<Ieee32>("", "Float must be hexadecimal");
1506        parse_err::<Ieee32>("-", "Float must be hexadecimal");
1507        parse_err::<Ieee32>("0x", "No digits");
1508        parse_err::<Ieee32>("0x..", "Multiple radix points");
1509
1510        // Check significant bits.
1511        parse_ok::<Ieee32>("0x0.ffffff", "0x1.fffffep-1");
1512        parse_ok::<Ieee32>("0x1.fffffe", "0x1.fffffep0");
1513        parse_ok::<Ieee32>("0x3.fffffc", "0x1.fffffep1");
1514        parse_ok::<Ieee32>("0x7.fffff8", "0x1.fffffep2");
1515        parse_ok::<Ieee32>("0xf.fffff0", "0x1.fffffep3");
1516        parse_err::<Ieee32>("0x1.ffffff", "Too many significant bits");
1517        parse_err::<Ieee32>("0x1.fffffe00000000000000000000000000", "Too many digits");
1518
1519        // Exponents.
1520        parse_ok::<Ieee32>("0x1p3", "0x1.000000p3");
1521        parse_ok::<Ieee32>("0x1p-3", "0x1.000000p-3");
1522        parse_ok::<Ieee32>("0x1.0p3", "0x1.000000p3");
1523        parse_ok::<Ieee32>("0x2.0p3", "0x1.000000p4");
1524        parse_ok::<Ieee32>("0x1.0p127", "0x1.000000p127");
1525        parse_ok::<Ieee32>("0x1.0p-126", "0x1.000000p-126");
1526        parse_ok::<Ieee32>("0x0.1p-122", "0x1.000000p-126");
1527        parse_err::<Ieee32>("0x2.0p127", "Magnitude too large");
1528
1529        // Subnormals.
1530        parse_ok::<Ieee32>("0x1.0p-127", "0x0.800000p-126");
1531        parse_ok::<Ieee32>("0x1.0p-149", "0x0.000002p-126");
1532        parse_ok::<Ieee32>("0x0.000002p-126", "0x0.000002p-126");
1533        parse_err::<Ieee32>("0x0.100001p-126", "Subnormal underflow");
1534        parse_err::<Ieee32>("0x1.8p-149", "Subnormal underflow");
1535        parse_err::<Ieee32>("0x1.0p-150", "Magnitude too small");
1536
1537        // NaNs and Infs.
1538        parse_ok::<Ieee32>("Inf", "+Inf");
1539        parse_ok::<Ieee32>("+Inf", "+Inf");
1540        parse_ok::<Ieee32>("-Inf", "-Inf");
1541        parse_ok::<Ieee32>("NaN", "+NaN");
1542        parse_ok::<Ieee32>("+NaN", "+NaN");
1543        parse_ok::<Ieee32>("-NaN", "-NaN");
1544        parse_ok::<Ieee32>("NaN:0x0", "+NaN");
1545        parse_err::<Ieee32>("NaN:", "Float must be hexadecimal");
1546        parse_err::<Ieee32>("NaN:0", "Float must be hexadecimal");
1547        parse_err::<Ieee32>("NaN:0x", "Invalid NaN payload");
1548        parse_ok::<Ieee32>("NaN:0x000001", "+NaN:0x1");
1549        parse_ok::<Ieee32>("NaN:0x300001", "+NaN:0x300001");
1550        parse_err::<Ieee32>("NaN:0x400001", "Invalid NaN payload");
1551        parse_ok::<Ieee32>("sNaN:0x1", "+sNaN:0x1");
1552        parse_err::<Ieee32>("sNaN:0x0", "Invalid sNaN payload");
1553        parse_ok::<Ieee32>("sNaN:0x200001", "+sNaN:0x200001");
1554        parse_err::<Ieee32>("sNaN:0x400001", "Invalid sNaN payload");
1555    }
1556
1557    #[test]
1558    fn pow2_ieee32() {
1559        assert_eq!(Ieee32::pow2(0).to_string(), "0x1.000000p0");
1560        assert_eq!(Ieee32::pow2(1).to_string(), "0x1.000000p1");
1561        assert_eq!(Ieee32::pow2(-1).to_string(), "0x1.000000p-1");
1562        assert_eq!(Ieee32::pow2(127).to_string(), "0x1.000000p127");
1563        assert_eq!(Ieee32::pow2(-126).to_string(), "0x1.000000p-126");
1564
1565        assert_eq!((-Ieee32::pow2(1)).to_string(), "-0x1.000000p1");
1566    }
1567
1568    #[test]
1569    fn fcvt_to_sint_negative_overflow_ieee32() {
1570        for n in [8, 16] {
1571            assert_eq!(
1572                -((1u32 << (n - 1)) as f32) - 1.0,
1573                Ieee32::fcvt_to_sint_negative_overflow(n).as_f32(),
1574                "n = {n}"
1575            );
1576        }
1577    }
1578
1579    #[test]
1580    fn format_ieee64() {
1581        assert_eq!(Ieee64::with_float(0.0).to_string(), "0.0");
1582        assert_eq!(Ieee64::with_float(-0.0).to_string(), "-0.0");
1583        assert_eq!(Ieee64::with_float(1.0).to_string(), "0x1.0000000000000p0");
1584        assert_eq!(Ieee64::with_float(1.5).to_string(), "0x1.8000000000000p0");
1585        assert_eq!(Ieee64::with_float(0.5).to_string(), "0x1.0000000000000p-1");
1586        assert_eq!(
1587            Ieee64::with_float(f64::EPSILON).to_string(),
1588            "0x1.0000000000000p-52"
1589        );
1590        assert_eq!(
1591            Ieee64::with_float(f64::MIN).to_string(),
1592            "-0x1.fffffffffffffp1023"
1593        );
1594        assert_eq!(
1595            Ieee64::with_float(f64::MAX).to_string(),
1596            "0x1.fffffffffffffp1023"
1597        );
1598        // Smallest positive normal number.
1599        assert_eq!(
1600            Ieee64::with_float(f64::MIN_POSITIVE).to_string(),
1601            "0x1.0000000000000p-1022"
1602        );
1603        // Subnormals.
1604        assert_eq!(
1605            Ieee64::with_float(f64::MIN_POSITIVE / 2.0).to_string(),
1606            "0x0.8000000000000p-1022"
1607        );
1608        assert_eq!(
1609            Ieee64::with_float(f64::MIN_POSITIVE * f64::EPSILON).to_string(),
1610            "0x0.0000000000001p-1022"
1611        );
1612        assert_eq!(Ieee64::with_float(f64::INFINITY).to_string(), "+Inf");
1613        assert_eq!(Ieee64::with_float(f64::NEG_INFINITY).to_string(), "-Inf");
1614        assert_eq!(Ieee64::with_float(f64::NAN).to_string(), "+NaN");
1615        assert_eq!(Ieee64::with_float(-f64::NAN).to_string(), "-NaN");
1616        // Construct some qNaNs with payloads.
1617        assert_eq!(
1618            Ieee64::with_bits(0x7ff8000000000001).to_string(),
1619            "+NaN:0x1"
1620        );
1621        assert_eq!(
1622            Ieee64::with_bits(0x7ffc000000000001).to_string(),
1623            "+NaN:0x4000000000001"
1624        );
1625        // Signaling NaNs.
1626        assert_eq!(
1627            Ieee64::with_bits(0x7ff0000000000001).to_string(),
1628            "+sNaN:0x1"
1629        );
1630        assert_eq!(
1631            Ieee64::with_bits(0x7ff4000000000001).to_string(),
1632            "+sNaN:0x4000000000001"
1633        );
1634    }
1635
1636    #[test]
1637    fn parse_ieee64() {
1638        parse_ok::<Ieee64>("0.0", "0.0");
1639        parse_ok::<Ieee64>("-0.0", "-0.0");
1640        parse_ok::<Ieee64>("0x0", "0.0");
1641        parse_ok::<Ieee64>("0x0.0", "0.0");
1642        parse_ok::<Ieee64>("0x.0", "0.0");
1643        parse_ok::<Ieee64>("0x0.", "0.0");
1644        parse_ok::<Ieee64>("0x1", "0x1.0000000000000p0");
1645        parse_ok::<Ieee64>("-0x1", "-0x1.0000000000000p0");
1646        parse_ok::<Ieee64>("0x10", "0x1.0000000000000p4");
1647        parse_ok::<Ieee64>("0x10.0", "0x1.0000000000000p4");
1648        parse_err::<Ieee64>("0.", "Float must be hexadecimal");
1649        parse_err::<Ieee64>(".0", "Float must be hexadecimal");
1650        parse_err::<Ieee64>("0", "Float must be hexadecimal");
1651        parse_err::<Ieee64>("-0", "Float must be hexadecimal");
1652        parse_err::<Ieee64>(".", "Float must be hexadecimal");
1653        parse_err::<Ieee64>("", "Float must be hexadecimal");
1654        parse_err::<Ieee64>("-", "Float must be hexadecimal");
1655        parse_err::<Ieee64>("0x", "No digits");
1656        parse_err::<Ieee64>("0x..", "Multiple radix points");
1657
1658        // Check significant bits.
1659        parse_ok::<Ieee64>("0x0.fffffffffffff8", "0x1.fffffffffffffp-1");
1660        parse_ok::<Ieee64>("0x1.fffffffffffff", "0x1.fffffffffffffp0");
1661        parse_ok::<Ieee64>("0x3.ffffffffffffe", "0x1.fffffffffffffp1");
1662        parse_ok::<Ieee64>("0x7.ffffffffffffc", "0x1.fffffffffffffp2");
1663        parse_ok::<Ieee64>("0xf.ffffffffffff8", "0x1.fffffffffffffp3");
1664        parse_err::<Ieee64>("0x3.fffffffffffff", "Too many significant bits");
1665        parse_err::<Ieee64>("0x001.fffffe000000000000000000000000", "Too many digits");
1666
1667        // Exponents.
1668        parse_ok::<Ieee64>("0x1p3", "0x1.0000000000000p3");
1669        parse_ok::<Ieee64>("0x1p-3", "0x1.0000000000000p-3");
1670        parse_ok::<Ieee64>("0x1.0p3", "0x1.0000000000000p3");
1671        parse_ok::<Ieee64>("0x2.0p3", "0x1.0000000000000p4");
1672        parse_ok::<Ieee64>("0x1.0p1023", "0x1.0000000000000p1023");
1673        parse_ok::<Ieee64>("0x1.0p-1022", "0x1.0000000000000p-1022");
1674        parse_ok::<Ieee64>("0x0.1p-1018", "0x1.0000000000000p-1022");
1675        parse_err::<Ieee64>("0x2.0p1023", "Magnitude too large");
1676
1677        // Subnormals.
1678        parse_ok::<Ieee64>("0x1.0p-1023", "0x0.8000000000000p-1022");
1679        parse_ok::<Ieee64>("0x1.0p-1074", "0x0.0000000000001p-1022");
1680        parse_ok::<Ieee64>("0x0.0000000000001p-1022", "0x0.0000000000001p-1022");
1681        parse_err::<Ieee64>("0x0.10000000000008p-1022", "Subnormal underflow");
1682        parse_err::<Ieee64>("0x1.8p-1074", "Subnormal underflow");
1683        parse_err::<Ieee64>("0x1.0p-1075", "Magnitude too small");
1684
1685        // NaNs and Infs.
1686        parse_ok::<Ieee64>("Inf", "+Inf");
1687        parse_ok::<Ieee64>("-Inf", "-Inf");
1688        parse_ok::<Ieee64>("NaN", "+NaN");
1689        parse_ok::<Ieee64>("-NaN", "-NaN");
1690        parse_ok::<Ieee64>("NaN:0x0", "+NaN");
1691        parse_err::<Ieee64>("NaN:", "Float must be hexadecimal");
1692        parse_err::<Ieee64>("NaN:0", "Float must be hexadecimal");
1693        parse_err::<Ieee64>("NaN:0x", "Invalid NaN payload");
1694        parse_ok::<Ieee64>("NaN:0x000001", "+NaN:0x1");
1695        parse_ok::<Ieee64>("NaN:0x4000000000001", "+NaN:0x4000000000001");
1696        parse_err::<Ieee64>("NaN:0x8000000000001", "Invalid NaN payload");
1697        parse_ok::<Ieee64>("sNaN:0x1", "+sNaN:0x1");
1698        parse_err::<Ieee64>("sNaN:0x0", "Invalid sNaN payload");
1699        parse_ok::<Ieee64>("sNaN:0x4000000000001", "+sNaN:0x4000000000001");
1700        parse_err::<Ieee64>("sNaN:0x8000000000001", "Invalid sNaN payload");
1701    }
1702
1703    #[test]
1704    fn pow2_ieee64() {
1705        assert_eq!(Ieee64::pow2(0).to_string(), "0x1.0000000000000p0");
1706        assert_eq!(Ieee64::pow2(1).to_string(), "0x1.0000000000000p1");
1707        assert_eq!(Ieee64::pow2(-1).to_string(), "0x1.0000000000000p-1");
1708        assert_eq!(Ieee64::pow2(1023).to_string(), "0x1.0000000000000p1023");
1709        assert_eq!(Ieee64::pow2(-1022).to_string(), "0x1.0000000000000p-1022");
1710
1711        assert_eq!((-Ieee64::pow2(1)).to_string(), "-0x1.0000000000000p1");
1712    }
1713
1714    #[test]
1715    fn fcvt_to_sint_negative_overflow_ieee64() {
1716        for n in [8, 16, 32] {
1717            assert_eq!(
1718                -((1u64 << (n - 1)) as f64) - 1.0,
1719                Ieee64::fcvt_to_sint_negative_overflow(n).as_f64(),
1720                "n = {n}"
1721            );
1722        }
1723    }
1724
1725    #[test]
1726    fn format_ieee128() {
1727        assert_eq!(
1728            Ieee128::with_bits(0x00000000000000000000000000000000).to_string(), // 0.0
1729            "0.0"
1730        );
1731        assert_eq!(
1732            Ieee128::with_bits(0x80000000000000000000000000000000).to_string(), // -0.0
1733            "-0.0"
1734        );
1735        assert_eq!(
1736            Ieee128::with_bits(0x3fff0000000000000000000000000000).to_string(), // 1.0
1737            "0x1.0000000000000000000000000000p0"
1738        );
1739        assert_eq!(
1740            Ieee128::with_bits(0x3fff8000000000000000000000000000).to_string(), // 1.5
1741            "0x1.8000000000000000000000000000p0"
1742        );
1743        assert_eq!(
1744            Ieee128::with_bits(0x3ffe0000000000000000000000000000).to_string(), // 0.5
1745            "0x1.0000000000000000000000000000p-1"
1746        );
1747        assert_eq!(
1748            Ieee128::with_bits(0x3f8f0000000000000000000000000000).to_string(), // `f128::EPSILON`
1749            "0x1.0000000000000000000000000000p-112"
1750        );
1751        assert_eq!(
1752            Ieee128::with_bits(0xfffeffffffffffffffffffffffffffff).to_string(), // `f128::MIN`
1753            "-0x1.ffffffffffffffffffffffffffffp16383"
1754        );
1755        assert_eq!(
1756            Ieee128::with_bits(0x7ffeffffffffffffffffffffffffffff).to_string(), // `f128::MAX`
1757            "0x1.ffffffffffffffffffffffffffffp16383"
1758        );
1759        // Smallest positive normal number.
1760        assert_eq!(
1761            Ieee128::with_bits(0x00010000000000000000000000000000).to_string(), // `f128::MIN_POSITIVE`
1762            "0x1.0000000000000000000000000000p-16382"
1763        );
1764        // Subnormals.
1765        assert_eq!(
1766            Ieee128::with_bits(0x00008000000000000000000000000000).to_string(), // `f128::MIN_POSITIVE / 2.0`
1767            "0x0.8000000000000000000000000000p-16382"
1768        );
1769        assert_eq!(
1770            Ieee128::with_bits(0x00000000000000000000000000000001).to_string(), // `f128::MIN_POSITIVE * f128::EPSILON`
1771            "0x0.0000000000000000000000000001p-16382"
1772        );
1773        assert_eq!(
1774            Ieee128::with_bits(0x7fff0000000000000000000000000000).to_string(), // `f128::INFINITY`
1775            "+Inf"
1776        );
1777        assert_eq!(
1778            Ieee128::with_bits(0xffff0000000000000000000000000000).to_string(), // `f128::NEG_INFINITY`
1779            "-Inf"
1780        );
1781        assert_eq!(
1782            Ieee128::with_bits(0x7fff8000000000000000000000000000).to_string(), // `f128::NAN`
1783            "+NaN"
1784        );
1785        assert_eq!(
1786            Ieee128::with_bits(0xffff8000000000000000000000000000).to_string(), // `-f128::NAN`
1787            "-NaN"
1788        );
1789        // Construct some qNaNs with payloads.
1790        assert_eq!(
1791            Ieee128::with_bits(0x7fff8000000000000000000000000001).to_string(),
1792            "+NaN:0x1"
1793        );
1794        assert_eq!(
1795            Ieee128::with_bits(0x7fffc000000000000000000000000001).to_string(),
1796            "+NaN:0x4000000000000000000000000001"
1797        );
1798        // Signaling NaNs.
1799        assert_eq!(
1800            Ieee128::with_bits(0x7fff0000000000000000000000000001).to_string(),
1801            "+sNaN:0x1"
1802        );
1803        assert_eq!(
1804            Ieee128::with_bits(0x7fff4000000000000000000000000001).to_string(),
1805            "+sNaN:0x4000000000000000000000000001"
1806        );
1807    }
1808
1809    #[test]
1810    fn parse_ieee128() {
1811        parse_ok::<Ieee128>("0.0", "0.0");
1812        parse_ok::<Ieee128>("-0.0", "-0.0");
1813        parse_ok::<Ieee128>("0x0", "0.0");
1814        parse_ok::<Ieee128>("0x0.0", "0.0");
1815        parse_ok::<Ieee128>("0x.0", "0.0");
1816        parse_ok::<Ieee128>("0x0.", "0.0");
1817        parse_ok::<Ieee128>("0x1", "0x1.0000000000000000000000000000p0");
1818        parse_ok::<Ieee128>("-0x1", "-0x1.0000000000000000000000000000p0");
1819        parse_ok::<Ieee128>("0x10", "0x1.0000000000000000000000000000p4");
1820        parse_ok::<Ieee128>("0x10.0", "0x1.0000000000000000000000000000p4");
1821        parse_err::<Ieee128>("0.", "Float must be hexadecimal");
1822        parse_err::<Ieee128>(".0", "Float must be hexadecimal");
1823        parse_err::<Ieee128>("0", "Float must be hexadecimal");
1824        parse_err::<Ieee128>("-0", "Float must be hexadecimal");
1825        parse_err::<Ieee128>(".", "Float must be hexadecimal");
1826        parse_err::<Ieee128>("", "Float must be hexadecimal");
1827        parse_err::<Ieee128>("-", "Float must be hexadecimal");
1828        parse_err::<Ieee128>("0x", "No digits");
1829        parse_err::<Ieee128>("0x..", "Multiple radix points");
1830
1831        // Check significant bits.
1832        parse_ok::<Ieee128>(
1833            "0x0.ffffffffffffffffffffffffffff8",
1834            "0x1.ffffffffffffffffffffffffffffp-1",
1835        );
1836        parse_ok::<Ieee128>(
1837            "0x1.ffffffffffffffffffffffffffff",
1838            "0x1.ffffffffffffffffffffffffffffp0",
1839        );
1840        parse_ok::<Ieee128>(
1841            "0x3.fffffffffffffffffffffffffffe",
1842            "0x1.ffffffffffffffffffffffffffffp1",
1843        );
1844        parse_ok::<Ieee128>(
1845            "0x7.fffffffffffffffffffffffffffc",
1846            "0x1.ffffffffffffffffffffffffffffp2",
1847        );
1848        parse_ok::<Ieee128>(
1849            "0xf.fffffffffffffffffffffffffff8",
1850            "0x1.ffffffffffffffffffffffffffffp3",
1851        );
1852        parse_err::<Ieee128>(
1853            "0x3.ffffffffffffffffffffffffffff",
1854            "Too many significant bits",
1855        );
1856        parse_err::<Ieee128>("0x001.fffffe000000000000000000000000", "Too many digits");
1857
1858        // Exponents.
1859        parse_ok::<Ieee128>("0x1p3", "0x1.0000000000000000000000000000p3");
1860        parse_ok::<Ieee128>("0x1p-3", "0x1.0000000000000000000000000000p-3");
1861        parse_ok::<Ieee128>("0x1.0p3", "0x1.0000000000000000000000000000p3");
1862        parse_ok::<Ieee128>("0x2.0p3", "0x1.0000000000000000000000000000p4");
1863        parse_ok::<Ieee128>("0x1.0p16383", "0x1.0000000000000000000000000000p16383");
1864        parse_ok::<Ieee128>("0x1.0p-16382", "0x1.0000000000000000000000000000p-16382");
1865        parse_ok::<Ieee128>("0x0.1p-16378", "0x1.0000000000000000000000000000p-16382");
1866        parse_err::<Ieee128>("0x2.0p16383", "Magnitude too large");
1867
1868        // Subnormals.
1869        parse_ok::<Ieee128>("0x1.0p-16383", "0x0.8000000000000000000000000000p-16382");
1870        parse_ok::<Ieee128>("0x1.0p-16494", "0x0.0000000000000000000000000001p-16382");
1871        parse_ok::<Ieee128>(
1872            "0x0.0000000000000000000000000001p-16382",
1873            "0x0.0000000000000000000000000001p-16382",
1874        );
1875        parse_err::<Ieee128>(
1876            "0x0.10000000000000000000000000008p-16382",
1877            "Subnormal underflow",
1878        );
1879        parse_err::<Ieee128>("0x1.8p-16494", "Subnormal underflow");
1880        parse_err::<Ieee128>("0x1.0p-16495", "Magnitude too small");
1881
1882        // NaNs and Infs.
1883        parse_ok::<Ieee128>("Inf", "+Inf");
1884        parse_ok::<Ieee128>("-Inf", "-Inf");
1885        parse_ok::<Ieee128>("NaN", "+NaN");
1886        parse_ok::<Ieee128>("-NaN", "-NaN");
1887        parse_ok::<Ieee128>("NaN:0x0", "+NaN");
1888        parse_err::<Ieee128>("NaN:", "Float must be hexadecimal");
1889        parse_err::<Ieee128>("NaN:0", "Float must be hexadecimal");
1890        parse_err::<Ieee128>("NaN:0x", "Invalid NaN payload");
1891        parse_ok::<Ieee128>("NaN:0x000001", "+NaN:0x1");
1892        parse_ok::<Ieee128>(
1893            "NaN:0x4000000000000000000000000001",
1894            "+NaN:0x4000000000000000000000000001",
1895        );
1896        parse_err::<Ieee128>("NaN:0x8000000000000000000000000001", "Invalid NaN payload");
1897        parse_ok::<Ieee128>("sNaN:0x1", "+sNaN:0x1");
1898        parse_err::<Ieee128>("sNaN:0x0", "Invalid sNaN payload");
1899        parse_ok::<Ieee128>(
1900            "sNaN:0x4000000000000000000000000001",
1901            "+sNaN:0x4000000000000000000000000001",
1902        );
1903        parse_err::<Ieee128>(
1904            "sNaN:0x8000000000000000000000000001",
1905            "Invalid sNaN payload",
1906        );
1907    }
1908
1909    #[test]
1910    fn pow2_ieee128() {
1911        assert_eq!(
1912            Ieee128::pow2(0).to_string(),
1913            "0x1.0000000000000000000000000000p0"
1914        );
1915        assert_eq!(
1916            Ieee128::pow2(1).to_string(),
1917            "0x1.0000000000000000000000000000p1"
1918        );
1919        assert_eq!(
1920            Ieee128::pow2(-1).to_string(),
1921            "0x1.0000000000000000000000000000p-1"
1922        );
1923        assert_eq!(
1924            Ieee128::pow2(16383).to_string(),
1925            "0x1.0000000000000000000000000000p16383"
1926        );
1927        assert_eq!(
1928            Ieee128::pow2(-16382).to_string(),
1929            "0x1.0000000000000000000000000000p-16382"
1930        );
1931
1932        assert_eq!(
1933            (-Ieee128::pow2(1)).to_string(),
1934            "-0x1.0000000000000000000000000000p1"
1935        );
1936    }
1937
1938    #[test]
1939    fn fcvt_to_sint_negative_overflow_ieee128() {
1940        // FIXME(#8312): Replace with commented out version once Rust f128 support is stabilised.
1941        // for n in [8, 16, 32, 64] {
1942        //     assert_eq!(
1943        //         -((1u128 << (n - 1)) as f128) - 1.0,
1944        //         Ieee128::fcvt_to_sint_negative_overflow(n).as_f128(),
1945        //         "n = {n}"
1946        //     );
1947        // }
1948        for (n, expected) in [
1949            (8, "-0x1.0200000000000000000000000000p7"),
1950            (16, "-0x1.0002000000000000000000000000p15"),
1951            (32, "-0x1.0000000200000000000000000000p31"),
1952            (64, "-0x1.0000000000000002000000000000p63"),
1953        ] {
1954            assert_eq!(
1955                expected,
1956                Ieee128::fcvt_to_sint_negative_overflow(n).to_string(),
1957                "n = {n}"
1958            );
1959        }
1960    }
1961}