Skip to main content

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