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