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