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 
7 use alloc::vec::Vec;
8 use core::cmp::Ordering;
9 use core::fmt::{self, Display, Formatter};
10 use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Sub};
11 use core::str::FromStr;
12 use core::{i32, u32};
13 #[cfg(feature = "enable-serde")]
14 use 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.
18 pub trait IntoBytes {
19     /// Return the little-endian byte representation of the implementing type.
20     fn into_bytes(self) -> Vec<u8>;
21 }
22 
23 impl IntoBytes for u8 {
24     fn into_bytes(self) -> Vec<u8> {
25         vec![self]
26     }
27 }
28 
29 impl IntoBytes for i8 {
30     fn into_bytes(self) -> Vec<u8> {
31         vec![self as u8]
32     }
33 }
34 
35 impl IntoBytes for i16 {
36     fn into_bytes(self) -> Vec<u8> {
37         self.to_le_bytes().to_vec()
38     }
39 }
40 
41 impl IntoBytes for i32 {
42     fn into_bytes(self) -> Vec<u8> {
43         self.to_le_bytes().to_vec()
44     }
45 }
46 
47 impl 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))]
59 pub struct Imm64(i64);
60 
61 impl 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 
131 impl From<Imm64> for i64 {
132     fn from(val: Imm64) -> i64 {
133         val.0
134     }
135 }
136 
137 impl IntoBytes for Imm64 {
138     fn into_bytes(self) -> Vec<u8> {
139         self.0.to_le_bytes().to_vec()
140     }
141 }
142 
143 impl From<i64> for Imm64 {
144     fn from(x: i64) -> Self {
145         Self(x)
146     }
147 }
148 
149 impl 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.
162 fn 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 
183 impl 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))]
198 pub struct Uimm64(u64);
199 
200 impl 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 
212 impl From<Uimm64> for u64 {
213     fn from(val: Uimm64) -> u64 {
214         val.0
215     }
216 }
217 
218 impl 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 ///
230 fn 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 
240 impl 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.
253 fn 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 
311 impl 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.
323 pub 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))]
330 pub struct Uimm32(u32);
331 
332 impl From<Uimm32> for u32 {
333     fn from(val: Uimm32) -> u32 {
334         val.0
335     }
336 }
337 
338 impl From<Uimm32> for u64 {
339     fn from(val: Uimm32) -> u64 {
340         val.0.into()
341     }
342 }
343 
344 impl From<Uimm32> for i64 {
345     fn from(val: Uimm32) -> i64 {
346         i64::from(val.0)
347     }
348 }
349 
350 impl From<u32> for Uimm32 {
351     fn from(x: u32) -> Self {
352         Self(x)
353     }
354 }
355 
356 impl 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 
366 impl 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))]
386 pub struct V128Imm(pub [u8; 16]);
387 
388 impl 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 
405 impl 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 
414 impl 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))]
426 pub struct Offset32(i32);
427 
428 impl 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 
448 impl From<Offset32> for i32 {
449     fn from(val: Offset32) -> i32 {
450         val.0
451     }
452 }
453 
454 impl From<Offset32> for i64 {
455     fn from(val: Offset32) -> i64 {
456         i64::from(val.0)
457     }
458 }
459 
460 impl From<i32> for Offset32 {
461     fn from(x: i32) -> Self {
462         Self(x)
463     }
464 }
465 
466 impl From<u8> for Offset32 {
467     fn from(val: u8) -> Offset32 {
468         Self(val.into())
469     }
470 }
471 
472 impl 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 
491 impl 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.
510 macro_rules! ignore {
511     ($($t:tt)*) => {};
512 }
513 
514 macro_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(self.$as_float().sqrt())
686                 }
687 
688                 /// Returns the smallest integer greater than or equal to `self`.
689                 pub fn ceil(self) -> Self {
690                     Self::with_float(self.$as_float().ceil())
691                 }
692 
693                 /// Returns the largest integer less than or equal to `self`.
694                 pub fn floor(self) -> Self {
695                     Self::with_float(self.$as_float().floor())
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(self.$as_float().trunc())
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(self.$as_float().round_ties_even())
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 
849 ieee_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 
858 ieee_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 
867 ieee_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 
876 ieee_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 ///
895 fn 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 ///
970 fn 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)]
1123 mod tests {
1124     use super::*;
1125     use alloc::string::ToString;
1126     use core::{f32, f64};
1127 
1128     #[test]
1129     fn format_imm64() {
1130         assert_eq!(Imm64(0).to_string(), "0");
1131         assert_eq!(Imm64(9999).to_string(), "9999");
1132         assert_eq!(Imm64(10000).to_string(), "0x2710");
1133         assert_eq!(Imm64(-9999).to_string(), "-9999");
1134         assert_eq!(Imm64(-10000).to_string(), "-10000");
1135         assert_eq!(Imm64(0xffff).to_string(), "0xffff");
1136         assert_eq!(Imm64(0x10000).to_string(), "0x0001_0000");
1137     }
1138 
1139     #[test]
1140     fn format_uimm64() {
1141         assert_eq!(Uimm64(0).to_string(), "0");
1142         assert_eq!(Uimm64(9999).to_string(), "9999");
1143         assert_eq!(Uimm64(10000).to_string(), "0x2710");
1144         assert_eq!(Uimm64(-9999i64 as u64).to_string(), "0xffff_ffff_ffff_d8f1");
1145         assert_eq!(
1146             Uimm64(-10000i64 as u64).to_string(),
1147             "0xffff_ffff_ffff_d8f0"
1148         );
1149         assert_eq!(Uimm64(0xffff).to_string(), "0xffff");
1150         assert_eq!(Uimm64(0x10000).to_string(), "0x0001_0000");
1151     }
1152 
1153     // Verify that `text` can be parsed as a `T` into a value that displays as `want`.
1154     #[track_caller]
1155     fn parse_ok<T: FromStr + Display>(text: &str, want: &str)
1156     where
1157         <T as FromStr>::Err: Display,
1158     {
1159         match text.parse::<T>() {
1160             Err(s) => panic!("\"{text}\".parse() error: {s}"),
1161             Ok(x) => assert_eq!(x.to_string(), want),
1162         }
1163     }
1164 
1165     // Verify that `text` fails to parse as `T` with the error `msg`.
1166     fn parse_err<T: FromStr + Display>(text: &str, msg: &str)
1167     where
1168         <T as FromStr>::Err: Display,
1169     {
1170         match text.parse::<T>() {
1171             Err(s) => assert_eq!(s.to_string(), msg),
1172             Ok(x) => panic!("Wanted Err({msg}), but got {x}"),
1173         }
1174     }
1175 
1176     #[test]
1177     fn parse_imm64() {
1178         parse_ok::<Imm64>("0", "0");
1179         parse_ok::<Imm64>("1", "1");
1180         parse_ok::<Imm64>("-0", "0");
1181         parse_ok::<Imm64>("-1", "-1");
1182         parse_ok::<Imm64>("0x0", "0");
1183         parse_ok::<Imm64>("0xf", "15");
1184         parse_ok::<Imm64>("-0x9", "-9");
1185 
1186         // Probe limits.
1187         parse_ok::<Imm64>("0xffffffff_ffffffff", "-1");
1188         parse_ok::<Imm64>("0x80000000_00000000", "-9223372036854775808");
1189         parse_ok::<Imm64>("-0x80000000_00000000", "-9223372036854775808");
1190         parse_err::<Imm64>("-0x80000000_00000001", "Negative number too small");
1191         parse_ok::<Imm64>("18446744073709551615", "-1");
1192         parse_ok::<Imm64>("-9223372036854775808", "-9223372036854775808");
1193         // Overflow both the `checked_add` and `checked_mul`.
1194         parse_err::<Imm64>("18446744073709551616", "Too large decimal number");
1195         parse_err::<Imm64>("184467440737095516100", "Too large decimal number");
1196         parse_err::<Imm64>("-9223372036854775809", "Negative number too small");
1197 
1198         // Underscores are allowed where digits go.
1199         parse_ok::<Imm64>("0_0", "0");
1200         parse_ok::<Imm64>("-_10_0", "-100");
1201         parse_ok::<Imm64>("_10_", "10");
1202         parse_ok::<Imm64>("0x97_88_bb", "0x0097_88bb");
1203         parse_ok::<Imm64>("0x_97_", "151");
1204 
1205         parse_err::<Imm64>("", "No digits in number");
1206         parse_err::<Imm64>("-", "No digits in number");
1207         parse_err::<Imm64>("_", "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>("-0x", "No digits in number");
1211         parse_err::<Imm64>(" ", "Invalid character in decimal number");
1212         parse_err::<Imm64>("0 ", "Invalid character in decimal number");
1213         parse_err::<Imm64>(" 0", "Invalid character in decimal number");
1214         parse_err::<Imm64>("--", "Invalid character in decimal number");
1215         parse_err::<Imm64>("-0x-", "Invalid character in hexadecimal number");
1216         parse_err::<Imm64>("abc", "Invalid character in decimal number");
1217         parse_err::<Imm64>("-abc", "Invalid character in decimal number");
1218 
1219         // Hex count overflow.
1220         parse_err::<Imm64>("0x0_0000_0000_0000_0000", "Too many hexadecimal digits");
1221     }
1222 
1223     #[test]
1224     fn parse_uimm64() {
1225         parse_ok::<Uimm64>("0", "0");
1226         parse_ok::<Uimm64>("1", "1");
1227         parse_ok::<Uimm64>("0x0", "0");
1228         parse_ok::<Uimm64>("0xf", "15");
1229         parse_ok::<Uimm64>("0xffffffff_fffffff7", "0xffff_ffff_ffff_fff7");
1230 
1231         // Probe limits.
1232         parse_ok::<Uimm64>("0xffffffff_ffffffff", "0xffff_ffff_ffff_ffff");
1233         parse_ok::<Uimm64>("0x80000000_00000000", "0x8000_0000_0000_0000");
1234         parse_ok::<Uimm64>("18446744073709551615", "0xffff_ffff_ffff_ffff");
1235         // Overflow both the `checked_add` and `checked_mul`.
1236         parse_err::<Uimm64>("18446744073709551616", "Too large decimal number");
1237         parse_err::<Uimm64>("184467440737095516100", "Too large decimal number");
1238 
1239         // Underscores are allowed where digits go.
1240         parse_ok::<Uimm64>("0_0", "0");
1241         parse_ok::<Uimm64>("_10_", "10");
1242         parse_ok::<Uimm64>("0x97_88_bb", "0x0097_88bb");
1243         parse_ok::<Uimm64>("0x_97_", "151");
1244 
1245         parse_err::<Uimm64>("", "No digits in number");
1246         parse_err::<Uimm64>("_", "No digits in number");
1247         parse_err::<Uimm64>("0x", "No digits in number");
1248         parse_err::<Uimm64>("0x_", "No digits in number");
1249         parse_err::<Uimm64>("-", "Invalid character in decimal number");
1250         parse_err::<Uimm64>("-0x", "Invalid character in hexadecimal number");
1251         parse_err::<Uimm64>(" ", "Invalid character in decimal number");
1252         parse_err::<Uimm64>("0 ", "Invalid character in decimal number");
1253         parse_err::<Uimm64>(" 0", "Invalid character in decimal number");
1254         parse_err::<Uimm64>("--", "Invalid character in decimal number");
1255         parse_err::<Uimm64>("-0x-", "Invalid character in hexadecimal number");
1256         parse_err::<Uimm64>("-0", "Invalid character in decimal number");
1257         parse_err::<Uimm64>("-1", "Invalid character in decimal number");
1258         parse_err::<Uimm64>("abc", "Invalid character in decimal number");
1259         parse_err::<Uimm64>("-abc", "Invalid character in decimal number");
1260 
1261         // Hex count overflow.
1262         parse_err::<Uimm64>("0x0_0000_0000_0000_0000", "Too many hexadecimal digits");
1263     }
1264 
1265     #[test]
1266     fn format_offset32() {
1267         assert_eq!(Offset32(0).to_string(), "");
1268         assert_eq!(Offset32(1).to_string(), "+1");
1269         assert_eq!(Offset32(-1).to_string(), "-1");
1270         assert_eq!(Offset32(9999).to_string(), "+9999");
1271         assert_eq!(Offset32(10000).to_string(), "+0x2710");
1272         assert_eq!(Offset32(-9999).to_string(), "-9999");
1273         assert_eq!(Offset32(-10000).to_string(), "-0x2710");
1274         assert_eq!(Offset32(0xffff).to_string(), "+0xffff");
1275         assert_eq!(Offset32(0x10000).to_string(), "+0x0001_0000");
1276     }
1277 
1278     #[test]
1279     fn parse_offset32() {
1280         parse_ok::<Offset32>("+0", "");
1281         parse_ok::<Offset32>("+1", "+1");
1282         parse_ok::<Offset32>("-0", "");
1283         parse_ok::<Offset32>("-1", "-1");
1284         parse_ok::<Offset32>("+0x0", "");
1285         parse_ok::<Offset32>("+0xf", "+15");
1286         parse_ok::<Offset32>("-0x9", "-9");
1287         parse_ok::<Offset32>("-0x8000_0000", "-0x8000_0000");
1288 
1289         parse_err::<Offset32>("+0x8000_0000", "Offset out of range");
1290     }
1291 
1292     #[test]
1293     fn format_ieee16() {
1294         assert_eq!(Ieee16::with_bits(0).to_string(), "0.0"); // 0.0
1295         assert_eq!(Ieee16::with_bits(0x8000).to_string(), "-0.0"); // -0.0
1296         assert_eq!(Ieee16::with_bits(0x3c00).to_string(), "0x1.000p0"); // 1.0
1297         assert_eq!(Ieee16::with_bits(0x3e00).to_string(), "0x1.800p0"); // 1.5
1298         assert_eq!(Ieee16::with_bits(0x3800).to_string(), "0x1.000p-1"); // 0.5
1299         assert_eq!(
1300             Ieee16::with_bits(0x1400).to_string(), // `f16::EPSILON`
1301             "0x1.000p-10"
1302         );
1303         assert_eq!(
1304             Ieee16::with_bits(0xfbff).to_string(), // `f16::MIN`
1305             "-0x1.ffcp15"
1306         );
1307         assert_eq!(
1308             Ieee16::with_bits(0x7bff).to_string(), // `f16::MAX`
1309             "0x1.ffcp15"
1310         );
1311         // Smallest positive normal number.
1312         assert_eq!(
1313             Ieee16::with_bits(0x0400).to_string(), // `f16::MIN_POSITIVE`
1314             "0x1.000p-14"
1315         );
1316         // Subnormals.
1317         assert_eq!(
1318             Ieee16::with_bits(0x0200).to_string(), // `f16::MIN_POSITIVE / 2.0`
1319             "0x0.800p-14"
1320         );
1321         assert_eq!(
1322             Ieee16::with_bits(0x0001).to_string(), // `f16::MIN_POSITIVE * f16::EPSILON`
1323             "0x0.004p-14"
1324         );
1325         assert_eq!(
1326             Ieee16::with_bits(0x7c00).to_string(), // `f16::INFINITY`
1327             "+Inf"
1328         );
1329         assert_eq!(
1330             Ieee16::with_bits(0xfc00).to_string(), // `f16::NEG_INFINITY`
1331             "-Inf"
1332         );
1333         assert_eq!(
1334             Ieee16::with_bits(0x7e00).to_string(), // `f16::NAN`
1335             "+NaN"
1336         );
1337         assert_eq!(
1338             Ieee16::with_bits(0xfe00).to_string(), // `-f16::NAN`
1339             "-NaN"
1340         );
1341         // Construct some qNaNs with payloads.
1342         assert_eq!(Ieee16::with_bits(0x7e01).to_string(), "+NaN:0x1");
1343         assert_eq!(Ieee16::with_bits(0x7f01).to_string(), "+NaN:0x101");
1344         // Signaling NaNs.
1345         assert_eq!(Ieee16::with_bits(0x7c01).to_string(), "+sNaN:0x1");
1346         assert_eq!(Ieee16::with_bits(0x7d01).to_string(), "+sNaN:0x101");
1347     }
1348 
1349     #[test]
1350     fn parse_ieee16() {
1351         parse_ok::<Ieee16>("0.0", "0.0");
1352         parse_ok::<Ieee16>("+0.0", "0.0");
1353         parse_ok::<Ieee16>("-0.0", "-0.0");
1354         parse_ok::<Ieee16>("0x0", "0.0");
1355         parse_ok::<Ieee16>("0x0.0", "0.0");
1356         parse_ok::<Ieee16>("0x.0", "0.0");
1357         parse_ok::<Ieee16>("0x0.", "0.0");
1358         parse_ok::<Ieee16>("0x1", "0x1.000p0");
1359         parse_ok::<Ieee16>("+0x1", "0x1.000p0");
1360         parse_ok::<Ieee16>("-0x1", "-0x1.000p0");
1361         parse_ok::<Ieee16>("0x10", "0x1.000p4");
1362         parse_ok::<Ieee16>("0x10.0", "0x1.000p4");
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>("-0", "Float must be hexadecimal");
1367         parse_err::<Ieee16>(".", "Float must be hexadecimal");
1368         parse_err::<Ieee16>("", "Float must be hexadecimal");
1369         parse_err::<Ieee16>("-", "Float must be hexadecimal");
1370         parse_err::<Ieee16>("0x", "No digits");
1371         parse_err::<Ieee16>("0x..", "Multiple radix points");
1372 
1373         // Check significant bits.
1374         parse_ok::<Ieee16>("0x0.ffe", "0x1.ffcp-1");
1375         parse_ok::<Ieee16>("0x1.ffc", "0x1.ffcp0");
1376         parse_ok::<Ieee16>("0x3.ff8", "0x1.ffcp1");
1377         parse_ok::<Ieee16>("0x7.ff", "0x1.ffcp2");
1378         parse_ok::<Ieee16>("0xf.fe", "0x1.ffcp3");
1379         parse_err::<Ieee16>("0x1.ffe", "Too many significant bits");
1380         parse_err::<Ieee16>("0x1.ffc00000000000000000000000000000", "Too many digits");
1381 
1382         // Exponents.
1383         parse_ok::<Ieee16>("0x1p3", "0x1.000p3");
1384         parse_ok::<Ieee16>("0x1p-3", "0x1.000p-3");
1385         parse_ok::<Ieee16>("0x1.0p3", "0x1.000p3");
1386         parse_ok::<Ieee16>("0x2.0p3", "0x1.000p4");
1387         parse_ok::<Ieee16>("0x1.0p15", "0x1.000p15");
1388         parse_ok::<Ieee16>("0x1.0p-14", "0x1.000p-14");
1389         parse_ok::<Ieee16>("0x0.1p-10", "0x1.000p-14");
1390         parse_err::<Ieee16>("0x2.0p15", "Magnitude too large");
1391 
1392         // Subnormals.
1393         parse_ok::<Ieee16>("0x1.0p-15", "0x0.800p-14");
1394         parse_ok::<Ieee16>("0x1.0p-24", "0x0.004p-14");
1395         parse_ok::<Ieee16>("0x0.004p-14", "0x0.004p-14");
1396         parse_err::<Ieee16>("0x0.102p-14", "Subnormal underflow");
1397         parse_err::<Ieee16>("0x1.8p-24", "Subnormal underflow");
1398         parse_err::<Ieee16>("0x1.0p-25", "Magnitude too small");
1399 
1400         // NaNs and Infs.
1401         parse_ok::<Ieee16>("Inf", "+Inf");
1402         parse_ok::<Ieee16>("+Inf", "+Inf");
1403         parse_ok::<Ieee16>("-Inf", "-Inf");
1404         parse_ok::<Ieee16>("NaN", "+NaN");
1405         parse_ok::<Ieee16>("+NaN", "+NaN");
1406         parse_ok::<Ieee16>("-NaN", "-NaN");
1407         parse_ok::<Ieee16>("NaN:0x0", "+NaN");
1408         parse_err::<Ieee16>("NaN:", "Float must be hexadecimal");
1409         parse_err::<Ieee16>("NaN:0", "Float must be hexadecimal");
1410         parse_err::<Ieee16>("NaN:0x", "Invalid NaN payload");
1411         parse_ok::<Ieee16>("NaN:0x001", "+NaN:0x1");
1412         parse_ok::<Ieee16>("NaN:0x101", "+NaN:0x101");
1413         parse_err::<Ieee16>("NaN:0x301", "Invalid NaN payload");
1414         parse_ok::<Ieee16>("sNaN:0x1", "+sNaN:0x1");
1415         parse_err::<Ieee16>("sNaN:0x0", "Invalid sNaN payload");
1416         parse_ok::<Ieee16>("sNaN:0x101", "+sNaN:0x101");
1417         parse_err::<Ieee16>("sNaN:0x301", "Invalid sNaN payload");
1418     }
1419 
1420     #[test]
1421     fn pow2_ieee16() {
1422         assert_eq!(Ieee16::pow2(0).to_string(), "0x1.000p0");
1423         assert_eq!(Ieee16::pow2(1).to_string(), "0x1.000p1");
1424         assert_eq!(Ieee16::pow2(-1).to_string(), "0x1.000p-1");
1425         assert_eq!(Ieee16::pow2(15).to_string(), "0x1.000p15");
1426         assert_eq!(Ieee16::pow2(-14).to_string(), "0x1.000p-14");
1427 
1428         assert_eq!((-Ieee16::pow2(1)).to_string(), "-0x1.000p1");
1429     }
1430 
1431     #[test]
1432     fn fcvt_to_sint_negative_overflow_ieee16() {
1433         // FIXME(#8312): Replace with commented out version once Rust f16 support is stabilised.
1434         // let n = 8;
1435         // assert_eq!(
1436         //     -((1u16 << (n - 1)) as f16) - 1.0,
1437         //     Ieee16::fcvt_to_sint_negative_overflow(n).as_f16()
1438         // );
1439         let n = 8;
1440         assert_eq!(
1441             "-0x1.020p7",
1442             Ieee16::fcvt_to_sint_negative_overflow(n).to_string()
1443         );
1444     }
1445 
1446     #[test]
1447     fn format_ieee32() {
1448         assert_eq!(Ieee32::with_float(0.0).to_string(), "0.0");
1449         assert_eq!(Ieee32::with_float(-0.0).to_string(), "-0.0");
1450         assert_eq!(Ieee32::with_float(1.0).to_string(), "0x1.000000p0");
1451         assert_eq!(Ieee32::with_float(1.5).to_string(), "0x1.800000p0");
1452         assert_eq!(Ieee32::with_float(0.5).to_string(), "0x1.000000p-1");
1453         assert_eq!(
1454             Ieee32::with_float(f32::EPSILON).to_string(),
1455             "0x1.000000p-23"
1456         );
1457         assert_eq!(Ieee32::with_float(f32::MIN).to_string(), "-0x1.fffffep127");
1458         assert_eq!(Ieee32::with_float(f32::MAX).to_string(), "0x1.fffffep127");
1459         // Smallest positive normal number.
1460         assert_eq!(
1461             Ieee32::with_float(f32::MIN_POSITIVE).to_string(),
1462             "0x1.000000p-126"
1463         );
1464         // Subnormals.
1465         assert_eq!(
1466             Ieee32::with_float(f32::MIN_POSITIVE / 2.0).to_string(),
1467             "0x0.800000p-126"
1468         );
1469         assert_eq!(
1470             Ieee32::with_float(f32::MIN_POSITIVE * f32::EPSILON).to_string(),
1471             "0x0.000002p-126"
1472         );
1473         assert_eq!(Ieee32::with_float(f32::INFINITY).to_string(), "+Inf");
1474         assert_eq!(Ieee32::with_float(f32::NEG_INFINITY).to_string(), "-Inf");
1475         assert_eq!(Ieee32::with_float(f32::NAN).to_string(), "+NaN");
1476         assert_eq!(Ieee32::with_float(-f32::NAN).to_string(), "-NaN");
1477         // Construct some qNaNs with payloads.
1478         assert_eq!(Ieee32::with_bits(0x7fc00001).to_string(), "+NaN:0x1");
1479         assert_eq!(Ieee32::with_bits(0x7ff00001).to_string(), "+NaN:0x300001");
1480         // Signaling NaNs.
1481         assert_eq!(Ieee32::with_bits(0x7f800001).to_string(), "+sNaN:0x1");
1482         assert_eq!(Ieee32::with_bits(0x7fa00001).to_string(), "+sNaN:0x200001");
1483     }
1484 
1485     #[test]
1486     fn parse_ieee32() {
1487         parse_ok::<Ieee32>("0.0", "0.0");
1488         parse_ok::<Ieee32>("+0.0", "0.0");
1489         parse_ok::<Ieee32>("-0.0", "-0.0");
1490         parse_ok::<Ieee32>("0x0", "0.0");
1491         parse_ok::<Ieee32>("0x0.0", "0.0");
1492         parse_ok::<Ieee32>("0x.0", "0.0");
1493         parse_ok::<Ieee32>("0x0.", "0.0");
1494         parse_ok::<Ieee32>("0x1", "0x1.000000p0");
1495         parse_ok::<Ieee32>("+0x1", "0x1.000000p0");
1496         parse_ok::<Ieee32>("-0x1", "-0x1.000000p0");
1497         parse_ok::<Ieee32>("0x10", "0x1.000000p4");
1498         parse_ok::<Ieee32>("0x10.0", "0x1.000000p4");
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>("-0", "Float must be hexadecimal");
1503         parse_err::<Ieee32>(".", "Float must be hexadecimal");
1504         parse_err::<Ieee32>("", "Float must be hexadecimal");
1505         parse_err::<Ieee32>("-", "Float must be hexadecimal");
1506         parse_err::<Ieee32>("0x", "No digits");
1507         parse_err::<Ieee32>("0x..", "Multiple radix points");
1508 
1509         // Check significant bits.
1510         parse_ok::<Ieee32>("0x0.ffffff", "0x1.fffffep-1");
1511         parse_ok::<Ieee32>("0x1.fffffe", "0x1.fffffep0");
1512         parse_ok::<Ieee32>("0x3.fffffc", "0x1.fffffep1");
1513         parse_ok::<Ieee32>("0x7.fffff8", "0x1.fffffep2");
1514         parse_ok::<Ieee32>("0xf.fffff0", "0x1.fffffep3");
1515         parse_err::<Ieee32>("0x1.ffffff", "Too many significant bits");
1516         parse_err::<Ieee32>("0x1.fffffe00000000000000000000000000", "Too many digits");
1517 
1518         // Exponents.
1519         parse_ok::<Ieee32>("0x1p3", "0x1.000000p3");
1520         parse_ok::<Ieee32>("0x1p-3", "0x1.000000p-3");
1521         parse_ok::<Ieee32>("0x1.0p3", "0x1.000000p3");
1522         parse_ok::<Ieee32>("0x2.0p3", "0x1.000000p4");
1523         parse_ok::<Ieee32>("0x1.0p127", "0x1.000000p127");
1524         parse_ok::<Ieee32>("0x1.0p-126", "0x1.000000p-126");
1525         parse_ok::<Ieee32>("0x0.1p-122", "0x1.000000p-126");
1526         parse_err::<Ieee32>("0x2.0p127", "Magnitude too large");
1527 
1528         // Subnormals.
1529         parse_ok::<Ieee32>("0x1.0p-127", "0x0.800000p-126");
1530         parse_ok::<Ieee32>("0x1.0p-149", "0x0.000002p-126");
1531         parse_ok::<Ieee32>("0x0.000002p-126", "0x0.000002p-126");
1532         parse_err::<Ieee32>("0x0.100001p-126", "Subnormal underflow");
1533         parse_err::<Ieee32>("0x1.8p-149", "Subnormal underflow");
1534         parse_err::<Ieee32>("0x1.0p-150", "Magnitude too small");
1535 
1536         // NaNs and Infs.
1537         parse_ok::<Ieee32>("Inf", "+Inf");
1538         parse_ok::<Ieee32>("+Inf", "+Inf");
1539         parse_ok::<Ieee32>("-Inf", "-Inf");
1540         parse_ok::<Ieee32>("NaN", "+NaN");
1541         parse_ok::<Ieee32>("+NaN", "+NaN");
1542         parse_ok::<Ieee32>("-NaN", "-NaN");
1543         parse_ok::<Ieee32>("NaN:0x0", "+NaN");
1544         parse_err::<Ieee32>("NaN:", "Float must be hexadecimal");
1545         parse_err::<Ieee32>("NaN:0", "Float must be hexadecimal");
1546         parse_err::<Ieee32>("NaN:0x", "Invalid NaN payload");
1547         parse_ok::<Ieee32>("NaN:0x000001", "+NaN:0x1");
1548         parse_ok::<Ieee32>("NaN:0x300001", "+NaN:0x300001");
1549         parse_err::<Ieee32>("NaN:0x400001", "Invalid NaN payload");
1550         parse_ok::<Ieee32>("sNaN:0x1", "+sNaN:0x1");
1551         parse_err::<Ieee32>("sNaN:0x0", "Invalid sNaN payload");
1552         parse_ok::<Ieee32>("sNaN:0x200001", "+sNaN:0x200001");
1553         parse_err::<Ieee32>("sNaN:0x400001", "Invalid sNaN payload");
1554     }
1555 
1556     #[test]
1557     fn pow2_ieee32() {
1558         assert_eq!(Ieee32::pow2(0).to_string(), "0x1.000000p0");
1559         assert_eq!(Ieee32::pow2(1).to_string(), "0x1.000000p1");
1560         assert_eq!(Ieee32::pow2(-1).to_string(), "0x1.000000p-1");
1561         assert_eq!(Ieee32::pow2(127).to_string(), "0x1.000000p127");
1562         assert_eq!(Ieee32::pow2(-126).to_string(), "0x1.000000p-126");
1563 
1564         assert_eq!((-Ieee32::pow2(1)).to_string(), "-0x1.000000p1");
1565     }
1566 
1567     #[test]
1568     fn fcvt_to_sint_negative_overflow_ieee32() {
1569         for n in [8, 16] {
1570             assert_eq!(
1571                 -((1u32 << (n - 1)) as f32) - 1.0,
1572                 Ieee32::fcvt_to_sint_negative_overflow(n).as_f32(),
1573                 "n = {n}"
1574             );
1575         }
1576     }
1577 
1578     #[test]
1579     fn format_ieee64() {
1580         assert_eq!(Ieee64::with_float(0.0).to_string(), "0.0");
1581         assert_eq!(Ieee64::with_float(-0.0).to_string(), "-0.0");
1582         assert_eq!(Ieee64::with_float(1.0).to_string(), "0x1.0000000000000p0");
1583         assert_eq!(Ieee64::with_float(1.5).to_string(), "0x1.8000000000000p0");
1584         assert_eq!(Ieee64::with_float(0.5).to_string(), "0x1.0000000000000p-1");
1585         assert_eq!(
1586             Ieee64::with_float(f64::EPSILON).to_string(),
1587             "0x1.0000000000000p-52"
1588         );
1589         assert_eq!(
1590             Ieee64::with_float(f64::MIN).to_string(),
1591             "-0x1.fffffffffffffp1023"
1592         );
1593         assert_eq!(
1594             Ieee64::with_float(f64::MAX).to_string(),
1595             "0x1.fffffffffffffp1023"
1596         );
1597         // Smallest positive normal number.
1598         assert_eq!(
1599             Ieee64::with_float(f64::MIN_POSITIVE).to_string(),
1600             "0x1.0000000000000p-1022"
1601         );
1602         // Subnormals.
1603         assert_eq!(
1604             Ieee64::with_float(f64::MIN_POSITIVE / 2.0).to_string(),
1605             "0x0.8000000000000p-1022"
1606         );
1607         assert_eq!(
1608             Ieee64::with_float(f64::MIN_POSITIVE * f64::EPSILON).to_string(),
1609             "0x0.0000000000001p-1022"
1610         );
1611         assert_eq!(Ieee64::with_float(f64::INFINITY).to_string(), "+Inf");
1612         assert_eq!(Ieee64::with_float(f64::NEG_INFINITY).to_string(), "-Inf");
1613         assert_eq!(Ieee64::with_float(f64::NAN).to_string(), "+NaN");
1614         assert_eq!(Ieee64::with_float(-f64::NAN).to_string(), "-NaN");
1615         // Construct some qNaNs with payloads.
1616         assert_eq!(
1617             Ieee64::with_bits(0x7ff8000000000001).to_string(),
1618             "+NaN:0x1"
1619         );
1620         assert_eq!(
1621             Ieee64::with_bits(0x7ffc000000000001).to_string(),
1622             "+NaN:0x4000000000001"
1623         );
1624         // Signaling NaNs.
1625         assert_eq!(
1626             Ieee64::with_bits(0x7ff0000000000001).to_string(),
1627             "+sNaN:0x1"
1628         );
1629         assert_eq!(
1630             Ieee64::with_bits(0x7ff4000000000001).to_string(),
1631             "+sNaN:0x4000000000001"
1632         );
1633     }
1634 
1635     #[test]
1636     fn parse_ieee64() {
1637         parse_ok::<Ieee64>("0.0", "0.0");
1638         parse_ok::<Ieee64>("-0.0", "-0.0");
1639         parse_ok::<Ieee64>("0x0", "0.0");
1640         parse_ok::<Ieee64>("0x0.0", "0.0");
1641         parse_ok::<Ieee64>("0x.0", "0.0");
1642         parse_ok::<Ieee64>("0x0.", "0.0");
1643         parse_ok::<Ieee64>("0x1", "0x1.0000000000000p0");
1644         parse_ok::<Ieee64>("-0x1", "-0x1.0000000000000p0");
1645         parse_ok::<Ieee64>("0x10", "0x1.0000000000000p4");
1646         parse_ok::<Ieee64>("0x10.0", "0x1.0000000000000p4");
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>("-0", "Float must be hexadecimal");
1651         parse_err::<Ieee64>(".", "Float must be hexadecimal");
1652         parse_err::<Ieee64>("", "Float must be hexadecimal");
1653         parse_err::<Ieee64>("-", "Float must be hexadecimal");
1654         parse_err::<Ieee64>("0x", "No digits");
1655         parse_err::<Ieee64>("0x..", "Multiple radix points");
1656 
1657         // Check significant bits.
1658         parse_ok::<Ieee64>("0x0.fffffffffffff8", "0x1.fffffffffffffp-1");
1659         parse_ok::<Ieee64>("0x1.fffffffffffff", "0x1.fffffffffffffp0");
1660         parse_ok::<Ieee64>("0x3.ffffffffffffe", "0x1.fffffffffffffp1");
1661         parse_ok::<Ieee64>("0x7.ffffffffffffc", "0x1.fffffffffffffp2");
1662         parse_ok::<Ieee64>("0xf.ffffffffffff8", "0x1.fffffffffffffp3");
1663         parse_err::<Ieee64>("0x3.fffffffffffff", "Too many significant bits");
1664         parse_err::<Ieee64>("0x001.fffffe000000000000000000000000", "Too many digits");
1665 
1666         // Exponents.
1667         parse_ok::<Ieee64>("0x1p3", "0x1.0000000000000p3");
1668         parse_ok::<Ieee64>("0x1p-3", "0x1.0000000000000p-3");
1669         parse_ok::<Ieee64>("0x1.0p3", "0x1.0000000000000p3");
1670         parse_ok::<Ieee64>("0x2.0p3", "0x1.0000000000000p4");
1671         parse_ok::<Ieee64>("0x1.0p1023", "0x1.0000000000000p1023");
1672         parse_ok::<Ieee64>("0x1.0p-1022", "0x1.0000000000000p-1022");
1673         parse_ok::<Ieee64>("0x0.1p-1018", "0x1.0000000000000p-1022");
1674         parse_err::<Ieee64>("0x2.0p1023", "Magnitude too large");
1675 
1676         // Subnormals.
1677         parse_ok::<Ieee64>("0x1.0p-1023", "0x0.8000000000000p-1022");
1678         parse_ok::<Ieee64>("0x1.0p-1074", "0x0.0000000000001p-1022");
1679         parse_ok::<Ieee64>("0x0.0000000000001p-1022", "0x0.0000000000001p-1022");
1680         parse_err::<Ieee64>("0x0.10000000000008p-1022", "Subnormal underflow");
1681         parse_err::<Ieee64>("0x1.8p-1074", "Subnormal underflow");
1682         parse_err::<Ieee64>("0x1.0p-1075", "Magnitude too small");
1683 
1684         // NaNs and Infs.
1685         parse_ok::<Ieee64>("Inf", "+Inf");
1686         parse_ok::<Ieee64>("-Inf", "-Inf");
1687         parse_ok::<Ieee64>("NaN", "+NaN");
1688         parse_ok::<Ieee64>("-NaN", "-NaN");
1689         parse_ok::<Ieee64>("NaN:0x0", "+NaN");
1690         parse_err::<Ieee64>("NaN:", "Float must be hexadecimal");
1691         parse_err::<Ieee64>("NaN:0", "Float must be hexadecimal");
1692         parse_err::<Ieee64>("NaN:0x", "Invalid NaN payload");
1693         parse_ok::<Ieee64>("NaN:0x000001", "+NaN:0x1");
1694         parse_ok::<Ieee64>("NaN:0x4000000000001", "+NaN:0x4000000000001");
1695         parse_err::<Ieee64>("NaN:0x8000000000001", "Invalid NaN payload");
1696         parse_ok::<Ieee64>("sNaN:0x1", "+sNaN:0x1");
1697         parse_err::<Ieee64>("sNaN:0x0", "Invalid sNaN payload");
1698         parse_ok::<Ieee64>("sNaN:0x4000000000001", "+sNaN:0x4000000000001");
1699         parse_err::<Ieee64>("sNaN:0x8000000000001", "Invalid sNaN payload");
1700     }
1701 
1702     #[test]
1703     fn pow2_ieee64() {
1704         assert_eq!(Ieee64::pow2(0).to_string(), "0x1.0000000000000p0");
1705         assert_eq!(Ieee64::pow2(1).to_string(), "0x1.0000000000000p1");
1706         assert_eq!(Ieee64::pow2(-1).to_string(), "0x1.0000000000000p-1");
1707         assert_eq!(Ieee64::pow2(1023).to_string(), "0x1.0000000000000p1023");
1708         assert_eq!(Ieee64::pow2(-1022).to_string(), "0x1.0000000000000p-1022");
1709 
1710         assert_eq!((-Ieee64::pow2(1)).to_string(), "-0x1.0000000000000p1");
1711     }
1712 
1713     #[test]
1714     fn fcvt_to_sint_negative_overflow_ieee64() {
1715         for n in [8, 16, 32] {
1716             assert_eq!(
1717                 -((1u64 << (n - 1)) as f64) - 1.0,
1718                 Ieee64::fcvt_to_sint_negative_overflow(n).as_f64(),
1719                 "n = {n}"
1720             );
1721         }
1722     }
1723 
1724     #[test]
1725     fn format_ieee128() {
1726         assert_eq!(
1727             Ieee128::with_bits(0x00000000000000000000000000000000).to_string(), // 0.0
1728             "0.0"
1729         );
1730         assert_eq!(
1731             Ieee128::with_bits(0x80000000000000000000000000000000).to_string(), // -0.0
1732             "-0.0"
1733         );
1734         assert_eq!(
1735             Ieee128::with_bits(0x3fff0000000000000000000000000000).to_string(), // 1.0
1736             "0x1.0000000000000000000000000000p0"
1737         );
1738         assert_eq!(
1739             Ieee128::with_bits(0x3fff8000000000000000000000000000).to_string(), // 1.5
1740             "0x1.8000000000000000000000000000p0"
1741         );
1742         assert_eq!(
1743             Ieee128::with_bits(0x3ffe0000000000000000000000000000).to_string(), // 0.5
1744             "0x1.0000000000000000000000000000p-1"
1745         );
1746         assert_eq!(
1747             Ieee128::with_bits(0x3f8f0000000000000000000000000000).to_string(), // `f128::EPSILON`
1748             "0x1.0000000000000000000000000000p-112"
1749         );
1750         assert_eq!(
1751             Ieee128::with_bits(0xfffeffffffffffffffffffffffffffff).to_string(), // `f128::MIN`
1752             "-0x1.ffffffffffffffffffffffffffffp16383"
1753         );
1754         assert_eq!(
1755             Ieee128::with_bits(0x7ffeffffffffffffffffffffffffffff).to_string(), // `f128::MAX`
1756             "0x1.ffffffffffffffffffffffffffffp16383"
1757         );
1758         // Smallest positive normal number.
1759         assert_eq!(
1760             Ieee128::with_bits(0x00010000000000000000000000000000).to_string(), // `f128::MIN_POSITIVE`
1761             "0x1.0000000000000000000000000000p-16382"
1762         );
1763         // Subnormals.
1764         assert_eq!(
1765             Ieee128::with_bits(0x00008000000000000000000000000000).to_string(), // `f128::MIN_POSITIVE / 2.0`
1766             "0x0.8000000000000000000000000000p-16382"
1767         );
1768         assert_eq!(
1769             Ieee128::with_bits(0x00000000000000000000000000000001).to_string(), // `f128::MIN_POSITIVE * f128::EPSILON`
1770             "0x0.0000000000000000000000000001p-16382"
1771         );
1772         assert_eq!(
1773             Ieee128::with_bits(0x7fff0000000000000000000000000000).to_string(), // `f128::INFINITY`
1774             "+Inf"
1775         );
1776         assert_eq!(
1777             Ieee128::with_bits(0xffff0000000000000000000000000000).to_string(), // `f128::NEG_INFINITY`
1778             "-Inf"
1779         );
1780         assert_eq!(
1781             Ieee128::with_bits(0x7fff8000000000000000000000000000).to_string(), // `f128::NAN`
1782             "+NaN"
1783         );
1784         assert_eq!(
1785             Ieee128::with_bits(0xffff8000000000000000000000000000).to_string(), // `-f128::NAN`
1786             "-NaN"
1787         );
1788         // Construct some qNaNs with payloads.
1789         assert_eq!(
1790             Ieee128::with_bits(0x7fff8000000000000000000000000001).to_string(),
1791             "+NaN:0x1"
1792         );
1793         assert_eq!(
1794             Ieee128::with_bits(0x7fffc000000000000000000000000001).to_string(),
1795             "+NaN:0x4000000000000000000000000001"
1796         );
1797         // Signaling NaNs.
1798         assert_eq!(
1799             Ieee128::with_bits(0x7fff0000000000000000000000000001).to_string(),
1800             "+sNaN:0x1"
1801         );
1802         assert_eq!(
1803             Ieee128::with_bits(0x7fff4000000000000000000000000001).to_string(),
1804             "+sNaN:0x4000000000000000000000000001"
1805         );
1806     }
1807 
1808     #[test]
1809     fn parse_ieee128() {
1810         parse_ok::<Ieee128>("0.0", "0.0");
1811         parse_ok::<Ieee128>("-0.0", "-0.0");
1812         parse_ok::<Ieee128>("0x0", "0.0");
1813         parse_ok::<Ieee128>("0x0.0", "0.0");
1814         parse_ok::<Ieee128>("0x.0", "0.0");
1815         parse_ok::<Ieee128>("0x0.", "0.0");
1816         parse_ok::<Ieee128>("0x1", "0x1.0000000000000000000000000000p0");
1817         parse_ok::<Ieee128>("-0x1", "-0x1.0000000000000000000000000000p0");
1818         parse_ok::<Ieee128>("0x10", "0x1.0000000000000000000000000000p4");
1819         parse_ok::<Ieee128>("0x10.0", "0x1.0000000000000000000000000000p4");
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>("-0", "Float must be hexadecimal");
1824         parse_err::<Ieee128>(".", "Float must be hexadecimal");
1825         parse_err::<Ieee128>("", "Float must be hexadecimal");
1826         parse_err::<Ieee128>("-", "Float must be hexadecimal");
1827         parse_err::<Ieee128>("0x", "No digits");
1828         parse_err::<Ieee128>("0x..", "Multiple radix points");
1829 
1830         // Check significant bits.
1831         parse_ok::<Ieee128>(
1832             "0x0.ffffffffffffffffffffffffffff8",
1833             "0x1.ffffffffffffffffffffffffffffp-1",
1834         );
1835         parse_ok::<Ieee128>(
1836             "0x1.ffffffffffffffffffffffffffff",
1837             "0x1.ffffffffffffffffffffffffffffp0",
1838         );
1839         parse_ok::<Ieee128>(
1840             "0x3.fffffffffffffffffffffffffffe",
1841             "0x1.ffffffffffffffffffffffffffffp1",
1842         );
1843         parse_ok::<Ieee128>(
1844             "0x7.fffffffffffffffffffffffffffc",
1845             "0x1.ffffffffffffffffffffffffffffp2",
1846         );
1847         parse_ok::<Ieee128>(
1848             "0xf.fffffffffffffffffffffffffff8",
1849             "0x1.ffffffffffffffffffffffffffffp3",
1850         );
1851         parse_err::<Ieee128>(
1852             "0x3.ffffffffffffffffffffffffffff",
1853             "Too many significant bits",
1854         );
1855         parse_err::<Ieee128>("0x001.fffffe000000000000000000000000", "Too many digits");
1856 
1857         // Exponents.
1858         parse_ok::<Ieee128>("0x1p3", "0x1.0000000000000000000000000000p3");
1859         parse_ok::<Ieee128>("0x1p-3", "0x1.0000000000000000000000000000p-3");
1860         parse_ok::<Ieee128>("0x1.0p3", "0x1.0000000000000000000000000000p3");
1861         parse_ok::<Ieee128>("0x2.0p3", "0x1.0000000000000000000000000000p4");
1862         parse_ok::<Ieee128>("0x1.0p16383", "0x1.0000000000000000000000000000p16383");
1863         parse_ok::<Ieee128>("0x1.0p-16382", "0x1.0000000000000000000000000000p-16382");
1864         parse_ok::<Ieee128>("0x0.1p-16378", "0x1.0000000000000000000000000000p-16382");
1865         parse_err::<Ieee128>("0x2.0p16383", "Magnitude too large");
1866 
1867         // Subnormals.
1868         parse_ok::<Ieee128>("0x1.0p-16383", "0x0.8000000000000000000000000000p-16382");
1869         parse_ok::<Ieee128>("0x1.0p-16494", "0x0.0000000000000000000000000001p-16382");
1870         parse_ok::<Ieee128>(
1871             "0x0.0000000000000000000000000001p-16382",
1872             "0x0.0000000000000000000000000001p-16382",
1873         );
1874         parse_err::<Ieee128>(
1875             "0x0.10000000000000000000000000008p-16382",
1876             "Subnormal underflow",
1877         );
1878         parse_err::<Ieee128>("0x1.8p-16494", "Subnormal underflow");
1879         parse_err::<Ieee128>("0x1.0p-16495", "Magnitude too small");
1880 
1881         // NaNs and Infs.
1882         parse_ok::<Ieee128>("Inf", "+Inf");
1883         parse_ok::<Ieee128>("-Inf", "-Inf");
1884         parse_ok::<Ieee128>("NaN", "+NaN");
1885         parse_ok::<Ieee128>("-NaN", "-NaN");
1886         parse_ok::<Ieee128>("NaN:0x0", "+NaN");
1887         parse_err::<Ieee128>("NaN:", "Float must be hexadecimal");
1888         parse_err::<Ieee128>("NaN:0", "Float must be hexadecimal");
1889         parse_err::<Ieee128>("NaN:0x", "Invalid NaN payload");
1890         parse_ok::<Ieee128>("NaN:0x000001", "+NaN:0x1");
1891         parse_ok::<Ieee128>(
1892             "NaN:0x4000000000000000000000000001",
1893             "+NaN:0x4000000000000000000000000001",
1894         );
1895         parse_err::<Ieee128>("NaN:0x8000000000000000000000000001", "Invalid NaN payload");
1896         parse_ok::<Ieee128>("sNaN:0x1", "+sNaN:0x1");
1897         parse_err::<Ieee128>("sNaN:0x0", "Invalid sNaN payload");
1898         parse_ok::<Ieee128>(
1899             "sNaN:0x4000000000000000000000000001",
1900             "+sNaN:0x4000000000000000000000000001",
1901         );
1902         parse_err::<Ieee128>(
1903             "sNaN:0x8000000000000000000000000001",
1904             "Invalid sNaN payload",
1905         );
1906     }
1907 
1908     #[test]
1909     fn pow2_ieee128() {
1910         assert_eq!(
1911             Ieee128::pow2(0).to_string(),
1912             "0x1.0000000000000000000000000000p0"
1913         );
1914         assert_eq!(
1915             Ieee128::pow2(1).to_string(),
1916             "0x1.0000000000000000000000000000p1"
1917         );
1918         assert_eq!(
1919             Ieee128::pow2(-1).to_string(),
1920             "0x1.0000000000000000000000000000p-1"
1921         );
1922         assert_eq!(
1923             Ieee128::pow2(16383).to_string(),
1924             "0x1.0000000000000000000000000000p16383"
1925         );
1926         assert_eq!(
1927             Ieee128::pow2(-16382).to_string(),
1928             "0x1.0000000000000000000000000000p-16382"
1929         );
1930 
1931         assert_eq!(
1932             (-Ieee128::pow2(1)).to_string(),
1933             "-0x1.0000000000000000000000000000p1"
1934         );
1935     }
1936 
1937     #[test]
1938     fn fcvt_to_sint_negative_overflow_ieee128() {
1939         // FIXME(#8312): Replace with commented out version once Rust f128 support is stabilised.
1940         // for n in [8, 16, 32, 64] {
1941         //     assert_eq!(
1942         //         -((1u128 << (n - 1)) as f128) - 1.0,
1943         //         Ieee128::fcvt_to_sint_negative_overflow(n).as_f128(),
1944         //         "n = {n}"
1945         //     );
1946         // }
1947         for (n, expected) in [
1948             (8, "-0x1.0200000000000000000000000000p7"),
1949             (16, "-0x1.0002000000000000000000000000p15"),
1950             (32, "-0x1.0000000200000000000000000000p31"),
1951             (64, "-0x1.0000000000000002000000000000p63"),
1952         ] {
1953             assert_eq!(
1954                 expected,
1955                 Ieee128::fcvt_to_sint_negative_overflow(n).to_string(),
1956                 "n = {n}"
1957             );
1958         }
1959     }
1960 }
1961