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. 21 fn into_bytes(self) -> Vec<u8>; 22 } 23 24 impl IntoBytes for u8 { 25 fn into_bytes(self) -> Vec<u8> { 26 vec![self] 27 } 28 } 29 30 impl IntoBytes for i8 { 31 fn into_bytes(self) -> Vec<u8> { 32 vec![self as u8] 33 } 34 } 35 36 impl IntoBytes for i16 { 37 fn into_bytes(self) -> Vec<u8> { 38 self.to_le_bytes().to_vec() 39 } 40 } 41 42 impl IntoBytes for i32 { 43 fn into_bytes(self) -> Vec<u8> { 44 self.to_le_bytes().to_vec() 45 } 46 } 47 48 impl IntoBytes for Vec<u8> { 49 fn into_bytes(self) -> Vec<u8> { 50 self 51 } 52 } 53 54 /// 64-bit immediate signed integer operand. 55 /// 56 /// An `Imm64` operand can also be used to represent immediate values of smaller integer types by 57 /// sign-extending to `i64`. 58 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] 59 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 60 pub struct Imm64(i64); 61 62 impl Imm64 { 63 /// Create a new `Imm64` representing the signed number `x`. 64 pub fn new(x: i64) -> Self { 65 Self(x) 66 } 67 68 /// Return self negated. 69 pub fn wrapping_neg(self) -> Self { 70 Self(self.0.wrapping_neg()) 71 } 72 73 /// Returns the value of this immediate. 74 pub fn bits(&self) -> i64 { 75 self.0 76 } 77 78 /// Mask this immediate to the given power-of-two bit width. 79 #[must_use] 80 pub(crate) fn mask_to_width(&self, bit_width: u32) -> Self { 81 debug_assert!(bit_width.is_power_of_two()); 82 83 if bit_width >= 64 { 84 return *self; 85 } 86 87 let bit_width = i64::from(bit_width); 88 let mask = (1 << bit_width) - 1; 89 let masked = self.0 & mask; 90 Imm64(masked) 91 } 92 93 /// Sign extend this immediate as if it were a signed integer of the given 94 /// power-of-two width. 95 #[must_use] 96 pub fn sign_extend_from_width(&self, bit_width: u32) -> Self { 97 debug_assert!( 98 bit_width.is_power_of_two(), 99 "{bit_width} is not a power of two" 100 ); 101 102 if bit_width >= 64 { 103 return *self; 104 } 105 106 let bit_width = i64::from(bit_width); 107 let delta = 64 - bit_width; 108 let sign_extended = (self.0 << delta) >> delta; 109 Imm64(sign_extended) 110 } 111 112 /// Zero extend this immediate as if it were an unsigned integer of the 113 /// given power-of-two width. 114 #[must_use] 115 pub fn zero_extend_from_width(&self, bit_width: u32) -> Self { 116 debug_assert!( 117 bit_width.is_power_of_two(), 118 "{bit_width} is not a power of two" 119 ); 120 121 if bit_width >= 64 { 122 return *self; 123 } 124 125 let bit_width = u64::from(bit_width); 126 let delta = 64 - bit_width; 127 let zero_extended = (self.0.cast_unsigned() << delta) >> delta; 128 Imm64(zero_extended.cast_signed()) 129 } 130 } 131 132 impl From<Imm64> for i64 { 133 fn from(val: Imm64) -> i64 { 134 val.0 135 } 136 } 137 138 impl IntoBytes for Imm64 { 139 fn into_bytes(self) -> Vec<u8> { 140 self.0.to_le_bytes().to_vec() 141 } 142 } 143 144 impl From<i64> for Imm64 { 145 fn from(x: i64) -> Self { 146 Self(x) 147 } 148 } 149 150 impl Display for Imm64 { 151 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 152 let x = self.0; 153 if x < 10_000 { 154 // Use decimal for small and negative numbers. 155 write!(f, "{x}") 156 } else { 157 write_hex(x as u64, f) 158 } 159 } 160 } 161 162 /// Parse a 64-bit signed number. 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. 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`. 203 pub fn new(x: u64) -> Self { 204 Self(x) 205 } 206 207 /// Return self negated. 208 pub fn wrapping_neg(self) -> Self { 209 Self(self.0.wrapping_neg()) 210 } 211 } 212 213 impl From<Uimm64> for u64 { 214 fn from(val: Uimm64) -> u64 { 215 val.0 216 } 217 } 218 219 impl From<u64> for Uimm64 { 220 fn from(x: u64) -> Self { 221 Self(x) 222 } 223 } 224 225 /// Hexadecimal with a multiple of 4 digits and group separators: 226 /// 227 /// 0xfff0 228 /// 0x0001_ffff 229 /// 0xffff_ffff_fff8_4400 230 /// 231 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 { 242 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 243 let x = self.0; 244 if x < 10_000 { 245 // Use decimal for small numbers. 246 write!(f, "{x}") 247 } else { 248 write_hex(x, f) 249 } 250 } 251 } 252 253 /// Parse a 64-bit unsigned number. 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. 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 { 334 fn from(val: Uimm32) -> u32 { 335 val.0 336 } 337 } 338 339 impl From<Uimm32> for u64 { 340 fn from(val: Uimm32) -> u64 { 341 val.0.into() 342 } 343 } 344 345 impl From<Uimm32> for i64 { 346 fn from(val: Uimm32) -> i64 { 347 i64::from(val.0) 348 } 349 } 350 351 impl From<u32> for Uimm32 { 352 fn from(x: u32) -> Self { 353 Self(x) 354 } 355 } 356 357 impl Display for Uimm32 { 358 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 359 if self.0 < 10_000 { 360 write!(f, "{}", self.0) 361 } else { 362 write_hex(u64::from(self.0), f) 363 } 364 } 365 } 366 367 impl FromStr for Uimm32 { 368 type Err = &'static str; 369 370 // Parse a decimal or hexadecimal `Uimm32`, formatted as above. 371 fn from_str(s: &str) -> Result<Self, &'static str> { 372 parse_i64(s).and_then(|x| { 373 if 0 <= x && x <= i64::from(u32::MAX) { 374 Ok(Self(x as u32)) 375 } else { 376 Err("Uimm32 out of range") 377 } 378 }) 379 } 380 } 381 382 /// A 128-bit immediate operand. 383 /// 384 /// This is used as an immediate value in SIMD instructions. 385 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] 386 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 387 pub struct V128Imm(pub [u8; 16]); 388 389 impl V128Imm { 390 /// Iterate over the bytes in the constant. 391 pub fn bytes(&self) -> impl Iterator<Item = &u8> { 392 self.0.iter() 393 } 394 395 /// Convert the immediate into a vector. 396 pub fn to_vec(self) -> Vec<u8> { 397 self.0.to_vec() 398 } 399 400 /// Convert the immediate into a slice. 401 pub fn as_slice(&self) -> &[u8] { 402 &self.0[..] 403 } 404 } 405 406 impl From<&[u8]> for V128Imm { 407 fn from(slice: &[u8]) -> Self { 408 assert_eq!(slice.len(), 16); 409 let mut buffer = [0; 16]; 410 buffer.copy_from_slice(slice); 411 Self(buffer) 412 } 413 } 414 415 impl From<u128> for V128Imm { 416 fn from(val: u128) -> Self { 417 V128Imm(val.to_le_bytes()) 418 } 419 } 420 421 /// 32-bit signed immediate offset. 422 /// 423 /// This is used to encode an immediate offset for load/store instructions. All supported ISAs have 424 /// a maximum load/store offset that fits in an `i32`. 425 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] 426 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 427 pub struct Offset32(i32); 428 429 impl Offset32 { 430 /// Create a new `Offset32` representing the signed number `x`. 431 pub fn new(x: i32) -> Self { 432 Self(x) 433 } 434 435 /// Create a new `Offset32` representing the signed number `x` if possible. 436 pub fn try_from_i64(x: i64) -> Option<Self> { 437 let x = i32::try_from(x).ok()?; 438 Some(Self::new(x)) 439 } 440 441 /// Add in the signed number `x` if possible. 442 pub fn try_add_i64(self, x: i64) -> Option<Self> { 443 let x = i32::try_from(x).ok()?; 444 let ret = self.0.checked_add(x)?; 445 Some(Self::new(ret)) 446 } 447 } 448 449 impl From<Offset32> for i32 { 450 fn from(val: Offset32) -> i32 { 451 val.0 452 } 453 } 454 455 impl From<Offset32> for i64 { 456 fn from(val: Offset32) -> i64 { 457 i64::from(val.0) 458 } 459 } 460 461 impl From<i32> for Offset32 { 462 fn from(x: i32) -> Self { 463 Self(x) 464 } 465 } 466 467 impl From<u8> for Offset32 { 468 fn from(val: u8) -> Offset32 { 469 Self(val.into()) 470 } 471 } 472 473 impl Display for Offset32 { 474 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 475 // 0 displays as an empty offset. 476 if self.0 == 0 { 477 return Ok(()); 478 } 479 480 // Always include a sign. 481 write!(f, "{}", if self.0 < 0 { '-' } else { '+' })?; 482 483 let val = i64::from(self.0).abs(); 484 if val < 10_000 { 485 write!(f, "{val}") 486 } else { 487 write_hex(val as u64, f) 488 } 489 } 490 } 491 492 impl FromStr for Offset32 { 493 type Err = &'static str; 494 495 // Parse a decimal or hexadecimal `Offset32`, formatted as above. 496 fn from_str(s: &str) -> Result<Self, &'static str> { 497 if !(s.starts_with('-') || s.starts_with('+')) { 498 return Err("Offset must begin with sign"); 499 } 500 parse_i64(s).and_then(|x| { 501 if i64::from(i32::MIN) <= x && x <= i64::from(i32::MAX) { 502 Ok(Self::new(x as i32)) 503 } else { 504 Err("Offset out of range") 505 } 506 }) 507 } 508 } 509 510 // FIXME(rust-lang/rust#83527): Replace with `${ignore()}` once it is stabilised. 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 /// 896 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 /// 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] 1130 fn format_imm64() { 1131 assert_eq!(Imm64(0).to_string(), "0"); 1132 assert_eq!(Imm64(9999).to_string(), "9999"); 1133 assert_eq!(Imm64(10000).to_string(), "0x2710"); 1134 assert_eq!(Imm64(-9999).to_string(), "-9999"); 1135 assert_eq!(Imm64(-10000).to_string(), "-10000"); 1136 assert_eq!(Imm64(0xffff).to_string(), "0xffff"); 1137 assert_eq!(Imm64(0x10000).to_string(), "0x0001_0000"); 1138 } 1139 1140 #[test] 1141 fn format_uimm64() { 1142 assert_eq!(Uimm64(0).to_string(), "0"); 1143 assert_eq!(Uimm64(9999).to_string(), "9999"); 1144 assert_eq!(Uimm64(10000).to_string(), "0x2710"); 1145 assert_eq!(Uimm64(-9999i64 as u64).to_string(), "0xffff_ffff_ffff_d8f1"); 1146 assert_eq!( 1147 Uimm64(-10000i64 as u64).to_string(), 1148 "0xffff_ffff_ffff_d8f0" 1149 ); 1150 assert_eq!(Uimm64(0xffff).to_string(), "0xffff"); 1151 assert_eq!(Uimm64(0x10000).to_string(), "0x0001_0000"); 1152 } 1153 1154 // Verify that `text` can be parsed as a `T` into a value that displays as `want`. 1155 #[track_caller] 1156 fn parse_ok<T: FromStr + Display>(text: &str, want: &str) 1157 where 1158 <T as FromStr>::Err: Display, 1159 { 1160 match text.parse::<T>() { 1161 Err(s) => panic!("\"{text}\".parse() error: {s}"), 1162 Ok(x) => assert_eq!(x.to_string(), want), 1163 } 1164 } 1165 1166 // Verify that `text` fails to parse as `T` with the error `msg`. 1167 fn parse_err<T: FromStr + Display>(text: &str, msg: &str) 1168 where 1169 <T as FromStr>::Err: Display, 1170 { 1171 match text.parse::<T>() { 1172 Err(s) => assert_eq!(s.to_string(), msg), 1173 Ok(x) => panic!("Wanted Err({msg}), but got {x}"), 1174 } 1175 } 1176 1177 #[test] 1178 fn parse_imm64() { 1179 parse_ok::<Imm64>("0", "0"); 1180 parse_ok::<Imm64>("1", "1"); 1181 parse_ok::<Imm64>("-0", "0"); 1182 parse_ok::<Imm64>("-1", "-1"); 1183 parse_ok::<Imm64>("0x0", "0"); 1184 parse_ok::<Imm64>("0xf", "15"); 1185 parse_ok::<Imm64>("-0x9", "-9"); 1186 1187 // Probe limits. 1188 parse_ok::<Imm64>("0xffffffff_ffffffff", "-1"); 1189 parse_ok::<Imm64>("0x80000000_00000000", "-9223372036854775808"); 1190 parse_ok::<Imm64>("-0x80000000_00000000", "-9223372036854775808"); 1191 parse_err::<Imm64>("-0x80000000_00000001", "Negative number too small"); 1192 parse_ok::<Imm64>("18446744073709551615", "-1"); 1193 parse_ok::<Imm64>("-9223372036854775808", "-9223372036854775808"); 1194 // Overflow both the `checked_add` and `checked_mul`. 1195 parse_err::<Imm64>("18446744073709551616", "Too large decimal number"); 1196 parse_err::<Imm64>("184467440737095516100", "Too large decimal number"); 1197 parse_err::<Imm64>("-9223372036854775809", "Negative number too small"); 1198 1199 // Underscores are allowed where digits go. 1200 parse_ok::<Imm64>("0_0", "0"); 1201 parse_ok::<Imm64>("-_10_0", "-100"); 1202 parse_ok::<Imm64>("_10_", "10"); 1203 parse_ok::<Imm64>("0x97_88_bb", "0x0097_88bb"); 1204 parse_ok::<Imm64>("0x_97_", "151"); 1205 1206 parse_err::<Imm64>("", "No digits in number"); 1207 parse_err::<Imm64>("-", "No digits in number"); 1208 parse_err::<Imm64>("_", "No digits in number"); 1209 parse_err::<Imm64>("0x", "No digits in number"); 1210 parse_err::<Imm64>("0x_", "No digits in number"); 1211 parse_err::<Imm64>("-0x", "No digits in number"); 1212 parse_err::<Imm64>(" ", "Invalid character in decimal number"); 1213 parse_err::<Imm64>("0 ", "Invalid character in decimal number"); 1214 parse_err::<Imm64>(" 0", "Invalid character in decimal number"); 1215 parse_err::<Imm64>("--", "Invalid character in decimal number"); 1216 parse_err::<Imm64>("-0x-", "Invalid character in hexadecimal number"); 1217 parse_err::<Imm64>("abc", "Invalid character in decimal number"); 1218 parse_err::<Imm64>("-abc", "Invalid character in decimal number"); 1219 1220 // Hex count overflow. 1221 parse_err::<Imm64>("0x0_0000_0000_0000_0000", "Too many hexadecimal digits"); 1222 } 1223 1224 #[test] 1225 fn parse_uimm64() { 1226 parse_ok::<Uimm64>("0", "0"); 1227 parse_ok::<Uimm64>("1", "1"); 1228 parse_ok::<Uimm64>("0x0", "0"); 1229 parse_ok::<Uimm64>("0xf", "15"); 1230 parse_ok::<Uimm64>("0xffffffff_fffffff7", "0xffff_ffff_ffff_fff7"); 1231 1232 // Probe limits. 1233 parse_ok::<Uimm64>("0xffffffff_ffffffff", "0xffff_ffff_ffff_ffff"); 1234 parse_ok::<Uimm64>("0x80000000_00000000", "0x8000_0000_0000_0000"); 1235 parse_ok::<Uimm64>("18446744073709551615", "0xffff_ffff_ffff_ffff"); 1236 // Overflow both the `checked_add` and `checked_mul`. 1237 parse_err::<Uimm64>("18446744073709551616", "Too large decimal number"); 1238 parse_err::<Uimm64>("184467440737095516100", "Too large decimal number"); 1239 1240 // Underscores are allowed where digits go. 1241 parse_ok::<Uimm64>("0_0", "0"); 1242 parse_ok::<Uimm64>("_10_", "10"); 1243 parse_ok::<Uimm64>("0x97_88_bb", "0x0097_88bb"); 1244 parse_ok::<Uimm64>("0x_97_", "151"); 1245 1246 parse_err::<Uimm64>("", "No digits in number"); 1247 parse_err::<Uimm64>("_", "No digits in number"); 1248 parse_err::<Uimm64>("0x", "No digits in number"); 1249 parse_err::<Uimm64>("0x_", "No digits in number"); 1250 parse_err::<Uimm64>("-", "Invalid character in decimal number"); 1251 parse_err::<Uimm64>("-0x", "Invalid character in hexadecimal number"); 1252 parse_err::<Uimm64>(" ", "Invalid character in decimal number"); 1253 parse_err::<Uimm64>("0 ", "Invalid character in decimal number"); 1254 parse_err::<Uimm64>(" 0", "Invalid character in decimal number"); 1255 parse_err::<Uimm64>("--", "Invalid character in decimal number"); 1256 parse_err::<Uimm64>("-0x-", "Invalid character in hexadecimal number"); 1257 parse_err::<Uimm64>("-0", "Invalid character in decimal number"); 1258 parse_err::<Uimm64>("-1", "Invalid character in decimal number"); 1259 parse_err::<Uimm64>("abc", "Invalid character in decimal number"); 1260 parse_err::<Uimm64>("-abc", "Invalid character in decimal number"); 1261 1262 // Hex count overflow. 1263 parse_err::<Uimm64>("0x0_0000_0000_0000_0000", "Too many hexadecimal digits"); 1264 } 1265 1266 #[test] 1267 fn format_offset32() { 1268 assert_eq!(Offset32(0).to_string(), ""); 1269 assert_eq!(Offset32(1).to_string(), "+1"); 1270 assert_eq!(Offset32(-1).to_string(), "-1"); 1271 assert_eq!(Offset32(9999).to_string(), "+9999"); 1272 assert_eq!(Offset32(10000).to_string(), "+0x2710"); 1273 assert_eq!(Offset32(-9999).to_string(), "-9999"); 1274 assert_eq!(Offset32(-10000).to_string(), "-0x2710"); 1275 assert_eq!(Offset32(0xffff).to_string(), "+0xffff"); 1276 assert_eq!(Offset32(0x10000).to_string(), "+0x0001_0000"); 1277 } 1278 1279 #[test] 1280 fn parse_offset32() { 1281 parse_ok::<Offset32>("+0", ""); 1282 parse_ok::<Offset32>("+1", "+1"); 1283 parse_ok::<Offset32>("-0", ""); 1284 parse_ok::<Offset32>("-1", "-1"); 1285 parse_ok::<Offset32>("+0x0", ""); 1286 parse_ok::<Offset32>("+0xf", "+15"); 1287 parse_ok::<Offset32>("-0x9", "-9"); 1288 parse_ok::<Offset32>("-0x8000_0000", "-0x8000_0000"); 1289 1290 parse_err::<Offset32>("+0x8000_0000", "Offset out of range"); 1291 } 1292 1293 #[test] 1294 fn format_ieee16() { 1295 assert_eq!(Ieee16::with_bits(0).to_string(), "0.0"); // 0.0 1296 assert_eq!(Ieee16::with_bits(0x8000).to_string(), "-0.0"); // -0.0 1297 assert_eq!(Ieee16::with_bits(0x3c00).to_string(), "0x1.000p0"); // 1.0 1298 assert_eq!(Ieee16::with_bits(0x3e00).to_string(), "0x1.800p0"); // 1.5 1299 assert_eq!(Ieee16::with_bits(0x3800).to_string(), "0x1.000p-1"); // 0.5 1300 assert_eq!( 1301 Ieee16::with_bits(0x1400).to_string(), // `f16::EPSILON` 1302 "0x1.000p-10" 1303 ); 1304 assert_eq!( 1305 Ieee16::with_bits(0xfbff).to_string(), // `f16::MIN` 1306 "-0x1.ffcp15" 1307 ); 1308 assert_eq!( 1309 Ieee16::with_bits(0x7bff).to_string(), // `f16::MAX` 1310 "0x1.ffcp15" 1311 ); 1312 // Smallest positive normal number. 1313 assert_eq!( 1314 Ieee16::with_bits(0x0400).to_string(), // `f16::MIN_POSITIVE` 1315 "0x1.000p-14" 1316 ); 1317 // Subnormals. 1318 assert_eq!( 1319 Ieee16::with_bits(0x0200).to_string(), // `f16::MIN_POSITIVE / 2.0` 1320 "0x0.800p-14" 1321 ); 1322 assert_eq!( 1323 Ieee16::with_bits(0x0001).to_string(), // `f16::MIN_POSITIVE * f16::EPSILON` 1324 "0x0.004p-14" 1325 ); 1326 assert_eq!( 1327 Ieee16::with_bits(0x7c00).to_string(), // `f16::INFINITY` 1328 "+Inf" 1329 ); 1330 assert_eq!( 1331 Ieee16::with_bits(0xfc00).to_string(), // `f16::NEG_INFINITY` 1332 "-Inf" 1333 ); 1334 assert_eq!( 1335 Ieee16::with_bits(0x7e00).to_string(), // `f16::NAN` 1336 "+NaN" 1337 ); 1338 assert_eq!( 1339 Ieee16::with_bits(0xfe00).to_string(), // `-f16::NAN` 1340 "-NaN" 1341 ); 1342 // Construct some qNaNs with payloads. 1343 assert_eq!(Ieee16::with_bits(0x7e01).to_string(), "+NaN:0x1"); 1344 assert_eq!(Ieee16::with_bits(0x7f01).to_string(), "+NaN:0x101"); 1345 // Signaling NaNs. 1346 assert_eq!(Ieee16::with_bits(0x7c01).to_string(), "+sNaN:0x1"); 1347 assert_eq!(Ieee16::with_bits(0x7d01).to_string(), "+sNaN:0x101"); 1348 } 1349 1350 #[test] 1351 fn parse_ieee16() { 1352 parse_ok::<Ieee16>("0.0", "0.0"); 1353 parse_ok::<Ieee16>("+0.0", "0.0"); 1354 parse_ok::<Ieee16>("-0.0", "-0.0"); 1355 parse_ok::<Ieee16>("0x0", "0.0"); 1356 parse_ok::<Ieee16>("0x0.0", "0.0"); 1357 parse_ok::<Ieee16>("0x.0", "0.0"); 1358 parse_ok::<Ieee16>("0x0.", "0.0"); 1359 parse_ok::<Ieee16>("0x1", "0x1.000p0"); 1360 parse_ok::<Ieee16>("+0x1", "0x1.000p0"); 1361 parse_ok::<Ieee16>("-0x1", "-0x1.000p0"); 1362 parse_ok::<Ieee16>("0x10", "0x1.000p4"); 1363 parse_ok::<Ieee16>("0x10.0", "0x1.000p4"); 1364 parse_err::<Ieee16>("0.", "Float must be hexadecimal"); 1365 parse_err::<Ieee16>(".0", "Float must be hexadecimal"); 1366 parse_err::<Ieee16>("0", "Float must be hexadecimal"); 1367 parse_err::<Ieee16>("-0", "Float must be hexadecimal"); 1368 parse_err::<Ieee16>(".", "Float must be hexadecimal"); 1369 parse_err::<Ieee16>("", "Float must be hexadecimal"); 1370 parse_err::<Ieee16>("-", "Float must be hexadecimal"); 1371 parse_err::<Ieee16>("0x", "No digits"); 1372 parse_err::<Ieee16>("0x..", "Multiple radix points"); 1373 1374 // Check significant bits. 1375 parse_ok::<Ieee16>("0x0.ffe", "0x1.ffcp-1"); 1376 parse_ok::<Ieee16>("0x1.ffc", "0x1.ffcp0"); 1377 parse_ok::<Ieee16>("0x3.ff8", "0x1.ffcp1"); 1378 parse_ok::<Ieee16>("0x7.ff", "0x1.ffcp2"); 1379 parse_ok::<Ieee16>("0xf.fe", "0x1.ffcp3"); 1380 parse_err::<Ieee16>("0x1.ffe", "Too many significant bits"); 1381 parse_err::<Ieee16>("0x1.ffc00000000000000000000000000000", "Too many digits"); 1382 1383 // Exponents. 1384 parse_ok::<Ieee16>("0x1p3", "0x1.000p3"); 1385 parse_ok::<Ieee16>("0x1p-3", "0x1.000p-3"); 1386 parse_ok::<Ieee16>("0x1.0p3", "0x1.000p3"); 1387 parse_ok::<Ieee16>("0x2.0p3", "0x1.000p4"); 1388 parse_ok::<Ieee16>("0x1.0p15", "0x1.000p15"); 1389 parse_ok::<Ieee16>("0x1.0p-14", "0x1.000p-14"); 1390 parse_ok::<Ieee16>("0x0.1p-10", "0x1.000p-14"); 1391 parse_err::<Ieee16>("0x2.0p15", "Magnitude too large"); 1392 1393 // Subnormals. 1394 parse_ok::<Ieee16>("0x1.0p-15", "0x0.800p-14"); 1395 parse_ok::<Ieee16>("0x1.0p-24", "0x0.004p-14"); 1396 parse_ok::<Ieee16>("0x0.004p-14", "0x0.004p-14"); 1397 parse_err::<Ieee16>("0x0.102p-14", "Subnormal underflow"); 1398 parse_err::<Ieee16>("0x1.8p-24", "Subnormal underflow"); 1399 parse_err::<Ieee16>("0x1.0p-25", "Magnitude too small"); 1400 1401 // NaNs and Infs. 1402 parse_ok::<Ieee16>("Inf", "+Inf"); 1403 parse_ok::<Ieee16>("+Inf", "+Inf"); 1404 parse_ok::<Ieee16>("-Inf", "-Inf"); 1405 parse_ok::<Ieee16>("NaN", "+NaN"); 1406 parse_ok::<Ieee16>("+NaN", "+NaN"); 1407 parse_ok::<Ieee16>("-NaN", "-NaN"); 1408 parse_ok::<Ieee16>("NaN:0x0", "+NaN"); 1409 parse_err::<Ieee16>("NaN:", "Float must be hexadecimal"); 1410 parse_err::<Ieee16>("NaN:0", "Float must be hexadecimal"); 1411 parse_err::<Ieee16>("NaN:0x", "Invalid NaN payload"); 1412 parse_ok::<Ieee16>("NaN:0x001", "+NaN:0x1"); 1413 parse_ok::<Ieee16>("NaN:0x101", "+NaN:0x101"); 1414 parse_err::<Ieee16>("NaN:0x301", "Invalid NaN payload"); 1415 parse_ok::<Ieee16>("sNaN:0x1", "+sNaN:0x1"); 1416 parse_err::<Ieee16>("sNaN:0x0", "Invalid sNaN payload"); 1417 parse_ok::<Ieee16>("sNaN:0x101", "+sNaN:0x101"); 1418 parse_err::<Ieee16>("sNaN:0x301", "Invalid sNaN payload"); 1419 } 1420 1421 #[test] 1422 fn pow2_ieee16() { 1423 assert_eq!(Ieee16::pow2(0).to_string(), "0x1.000p0"); 1424 assert_eq!(Ieee16::pow2(1).to_string(), "0x1.000p1"); 1425 assert_eq!(Ieee16::pow2(-1).to_string(), "0x1.000p-1"); 1426 assert_eq!(Ieee16::pow2(15).to_string(), "0x1.000p15"); 1427 assert_eq!(Ieee16::pow2(-14).to_string(), "0x1.000p-14"); 1428 1429 assert_eq!((-Ieee16::pow2(1)).to_string(), "-0x1.000p1"); 1430 } 1431 1432 #[test] 1433 fn fcvt_to_sint_negative_overflow_ieee16() { 1434 // FIXME(#8312): Replace with commented out version once Rust f16 support is stabilised. 1435 // let n = 8; 1436 // assert_eq!( 1437 // -((1u16 << (n - 1)) as f16) - 1.0, 1438 // Ieee16::fcvt_to_sint_negative_overflow(n).as_f16() 1439 // ); 1440 let n = 8; 1441 assert_eq!( 1442 "-0x1.020p7", 1443 Ieee16::fcvt_to_sint_negative_overflow(n).to_string() 1444 ); 1445 } 1446 1447 #[test] 1448 fn format_ieee32() { 1449 assert_eq!(Ieee32::with_float(0.0).to_string(), "0.0"); 1450 assert_eq!(Ieee32::with_float(-0.0).to_string(), "-0.0"); 1451 assert_eq!(Ieee32::with_float(1.0).to_string(), "0x1.000000p0"); 1452 assert_eq!(Ieee32::with_float(1.5).to_string(), "0x1.800000p0"); 1453 assert_eq!(Ieee32::with_float(0.5).to_string(), "0x1.000000p-1"); 1454 assert_eq!( 1455 Ieee32::with_float(f32::EPSILON).to_string(), 1456 "0x1.000000p-23" 1457 ); 1458 assert_eq!(Ieee32::with_float(f32::MIN).to_string(), "-0x1.fffffep127"); 1459 assert_eq!(Ieee32::with_float(f32::MAX).to_string(), "0x1.fffffep127"); 1460 // Smallest positive normal number. 1461 assert_eq!( 1462 Ieee32::with_float(f32::MIN_POSITIVE).to_string(), 1463 "0x1.000000p-126" 1464 ); 1465 // Subnormals. 1466 assert_eq!( 1467 Ieee32::with_float(f32::MIN_POSITIVE / 2.0).to_string(), 1468 "0x0.800000p-126" 1469 ); 1470 assert_eq!( 1471 Ieee32::with_float(f32::MIN_POSITIVE * f32::EPSILON).to_string(), 1472 "0x0.000002p-126" 1473 ); 1474 assert_eq!(Ieee32::with_float(f32::INFINITY).to_string(), "+Inf"); 1475 assert_eq!(Ieee32::with_float(f32::NEG_INFINITY).to_string(), "-Inf"); 1476 assert_eq!(Ieee32::with_float(f32::NAN).to_string(), "+NaN"); 1477 assert_eq!(Ieee32::with_float(-f32::NAN).to_string(), "-NaN"); 1478 // Construct some qNaNs with payloads. 1479 assert_eq!(Ieee32::with_bits(0x7fc00001).to_string(), "+NaN:0x1"); 1480 assert_eq!(Ieee32::with_bits(0x7ff00001).to_string(), "+NaN:0x300001"); 1481 // Signaling NaNs. 1482 assert_eq!(Ieee32::with_bits(0x7f800001).to_string(), "+sNaN:0x1"); 1483 assert_eq!(Ieee32::with_bits(0x7fa00001).to_string(), "+sNaN:0x200001"); 1484 } 1485 1486 #[test] 1487 fn parse_ieee32() { 1488 parse_ok::<Ieee32>("0.0", "0.0"); 1489 parse_ok::<Ieee32>("+0.0", "0.0"); 1490 parse_ok::<Ieee32>("-0.0", "-0.0"); 1491 parse_ok::<Ieee32>("0x0", "0.0"); 1492 parse_ok::<Ieee32>("0x0.0", "0.0"); 1493 parse_ok::<Ieee32>("0x.0", "0.0"); 1494 parse_ok::<Ieee32>("0x0.", "0.0"); 1495 parse_ok::<Ieee32>("0x1", "0x1.000000p0"); 1496 parse_ok::<Ieee32>("+0x1", "0x1.000000p0"); 1497 parse_ok::<Ieee32>("-0x1", "-0x1.000000p0"); 1498 parse_ok::<Ieee32>("0x10", "0x1.000000p4"); 1499 parse_ok::<Ieee32>("0x10.0", "0x1.000000p4"); 1500 parse_err::<Ieee32>("0.", "Float must be hexadecimal"); 1501 parse_err::<Ieee32>(".0", "Float must be hexadecimal"); 1502 parse_err::<Ieee32>("0", "Float must be hexadecimal"); 1503 parse_err::<Ieee32>("-0", "Float must be hexadecimal"); 1504 parse_err::<Ieee32>(".", "Float must be hexadecimal"); 1505 parse_err::<Ieee32>("", "Float must be hexadecimal"); 1506 parse_err::<Ieee32>("-", "Float must be hexadecimal"); 1507 parse_err::<Ieee32>("0x", "No digits"); 1508 parse_err::<Ieee32>("0x..", "Multiple radix points"); 1509 1510 // Check significant bits. 1511 parse_ok::<Ieee32>("0x0.ffffff", "0x1.fffffep-1"); 1512 parse_ok::<Ieee32>("0x1.fffffe", "0x1.fffffep0"); 1513 parse_ok::<Ieee32>("0x3.fffffc", "0x1.fffffep1"); 1514 parse_ok::<Ieee32>("0x7.fffff8", "0x1.fffffep2"); 1515 parse_ok::<Ieee32>("0xf.fffff0", "0x1.fffffep3"); 1516 parse_err::<Ieee32>("0x1.ffffff", "Too many significant bits"); 1517 parse_err::<Ieee32>("0x1.fffffe00000000000000000000000000", "Too many digits"); 1518 1519 // Exponents. 1520 parse_ok::<Ieee32>("0x1p3", "0x1.000000p3"); 1521 parse_ok::<Ieee32>("0x1p-3", "0x1.000000p-3"); 1522 parse_ok::<Ieee32>("0x1.0p3", "0x1.000000p3"); 1523 parse_ok::<Ieee32>("0x2.0p3", "0x1.000000p4"); 1524 parse_ok::<Ieee32>("0x1.0p127", "0x1.000000p127"); 1525 parse_ok::<Ieee32>("0x1.0p-126", "0x1.000000p-126"); 1526 parse_ok::<Ieee32>("0x0.1p-122", "0x1.000000p-126"); 1527 parse_err::<Ieee32>("0x2.0p127", "Magnitude too large"); 1528 1529 // Subnormals. 1530 parse_ok::<Ieee32>("0x1.0p-127", "0x0.800000p-126"); 1531 parse_ok::<Ieee32>("0x1.0p-149", "0x0.000002p-126"); 1532 parse_ok::<Ieee32>("0x0.000002p-126", "0x0.000002p-126"); 1533 parse_err::<Ieee32>("0x0.100001p-126", "Subnormal underflow"); 1534 parse_err::<Ieee32>("0x1.8p-149", "Subnormal underflow"); 1535 parse_err::<Ieee32>("0x1.0p-150", "Magnitude too small"); 1536 1537 // NaNs and Infs. 1538 parse_ok::<Ieee32>("Inf", "+Inf"); 1539 parse_ok::<Ieee32>("+Inf", "+Inf"); 1540 parse_ok::<Ieee32>("-Inf", "-Inf"); 1541 parse_ok::<Ieee32>("NaN", "+NaN"); 1542 parse_ok::<Ieee32>("+NaN", "+NaN"); 1543 parse_ok::<Ieee32>("-NaN", "-NaN"); 1544 parse_ok::<Ieee32>("NaN:0x0", "+NaN"); 1545 parse_err::<Ieee32>("NaN:", "Float must be hexadecimal"); 1546 parse_err::<Ieee32>("NaN:0", "Float must be hexadecimal"); 1547 parse_err::<Ieee32>("NaN:0x", "Invalid NaN payload"); 1548 parse_ok::<Ieee32>("NaN:0x000001", "+NaN:0x1"); 1549 parse_ok::<Ieee32>("NaN:0x300001", "+NaN:0x300001"); 1550 parse_err::<Ieee32>("NaN:0x400001", "Invalid NaN payload"); 1551 parse_ok::<Ieee32>("sNaN:0x1", "+sNaN:0x1"); 1552 parse_err::<Ieee32>("sNaN:0x0", "Invalid sNaN payload"); 1553 parse_ok::<Ieee32>("sNaN:0x200001", "+sNaN:0x200001"); 1554 parse_err::<Ieee32>("sNaN:0x400001", "Invalid sNaN payload"); 1555 } 1556 1557 #[test] 1558 fn pow2_ieee32() { 1559 assert_eq!(Ieee32::pow2(0).to_string(), "0x1.000000p0"); 1560 assert_eq!(Ieee32::pow2(1).to_string(), "0x1.000000p1"); 1561 assert_eq!(Ieee32::pow2(-1).to_string(), "0x1.000000p-1"); 1562 assert_eq!(Ieee32::pow2(127).to_string(), "0x1.000000p127"); 1563 assert_eq!(Ieee32::pow2(-126).to_string(), "0x1.000000p-126"); 1564 1565 assert_eq!((-Ieee32::pow2(1)).to_string(), "-0x1.000000p1"); 1566 } 1567 1568 #[test] 1569 fn fcvt_to_sint_negative_overflow_ieee32() { 1570 for n in [8, 16] { 1571 assert_eq!( 1572 -((1u32 << (n - 1)) as f32) - 1.0, 1573 Ieee32::fcvt_to_sint_negative_overflow(n).as_f32(), 1574 "n = {n}" 1575 ); 1576 } 1577 } 1578 1579 #[test] 1580 fn format_ieee64() { 1581 assert_eq!(Ieee64::with_float(0.0).to_string(), "0.0"); 1582 assert_eq!(Ieee64::with_float(-0.0).to_string(), "-0.0"); 1583 assert_eq!(Ieee64::with_float(1.0).to_string(), "0x1.0000000000000p0"); 1584 assert_eq!(Ieee64::with_float(1.5).to_string(), "0x1.8000000000000p0"); 1585 assert_eq!(Ieee64::with_float(0.5).to_string(), "0x1.0000000000000p-1"); 1586 assert_eq!( 1587 Ieee64::with_float(f64::EPSILON).to_string(), 1588 "0x1.0000000000000p-52" 1589 ); 1590 assert_eq!( 1591 Ieee64::with_float(f64::MIN).to_string(), 1592 "-0x1.fffffffffffffp1023" 1593 ); 1594 assert_eq!( 1595 Ieee64::with_float(f64::MAX).to_string(), 1596 "0x1.fffffffffffffp1023" 1597 ); 1598 // Smallest positive normal number. 1599 assert_eq!( 1600 Ieee64::with_float(f64::MIN_POSITIVE).to_string(), 1601 "0x1.0000000000000p-1022" 1602 ); 1603 // Subnormals. 1604 assert_eq!( 1605 Ieee64::with_float(f64::MIN_POSITIVE / 2.0).to_string(), 1606 "0x0.8000000000000p-1022" 1607 ); 1608 assert_eq!( 1609 Ieee64::with_float(f64::MIN_POSITIVE * f64::EPSILON).to_string(), 1610 "0x0.0000000000001p-1022" 1611 ); 1612 assert_eq!(Ieee64::with_float(f64::INFINITY).to_string(), "+Inf"); 1613 assert_eq!(Ieee64::with_float(f64::NEG_INFINITY).to_string(), "-Inf"); 1614 assert_eq!(Ieee64::with_float(f64::NAN).to_string(), "+NaN"); 1615 assert_eq!(Ieee64::with_float(-f64::NAN).to_string(), "-NaN"); 1616 // Construct some qNaNs with payloads. 1617 assert_eq!( 1618 Ieee64::with_bits(0x7ff8000000000001).to_string(), 1619 "+NaN:0x1" 1620 ); 1621 assert_eq!( 1622 Ieee64::with_bits(0x7ffc000000000001).to_string(), 1623 "+NaN:0x4000000000001" 1624 ); 1625 // Signaling NaNs. 1626 assert_eq!( 1627 Ieee64::with_bits(0x7ff0000000000001).to_string(), 1628 "+sNaN:0x1" 1629 ); 1630 assert_eq!( 1631 Ieee64::with_bits(0x7ff4000000000001).to_string(), 1632 "+sNaN:0x4000000000001" 1633 ); 1634 } 1635 1636 #[test] 1637 fn parse_ieee64() { 1638 parse_ok::<Ieee64>("0.0", "0.0"); 1639 parse_ok::<Ieee64>("-0.0", "-0.0"); 1640 parse_ok::<Ieee64>("0x0", "0.0"); 1641 parse_ok::<Ieee64>("0x0.0", "0.0"); 1642 parse_ok::<Ieee64>("0x.0", "0.0"); 1643 parse_ok::<Ieee64>("0x0.", "0.0"); 1644 parse_ok::<Ieee64>("0x1", "0x1.0000000000000p0"); 1645 parse_ok::<Ieee64>("-0x1", "-0x1.0000000000000p0"); 1646 parse_ok::<Ieee64>("0x10", "0x1.0000000000000p4"); 1647 parse_ok::<Ieee64>("0x10.0", "0x1.0000000000000p4"); 1648 parse_err::<Ieee64>("0.", "Float must be hexadecimal"); 1649 parse_err::<Ieee64>(".0", "Float must be hexadecimal"); 1650 parse_err::<Ieee64>("0", "Float must be hexadecimal"); 1651 parse_err::<Ieee64>("-0", "Float must be hexadecimal"); 1652 parse_err::<Ieee64>(".", "Float must be hexadecimal"); 1653 parse_err::<Ieee64>("", "Float must be hexadecimal"); 1654 parse_err::<Ieee64>("-", "Float must be hexadecimal"); 1655 parse_err::<Ieee64>("0x", "No digits"); 1656 parse_err::<Ieee64>("0x..", "Multiple radix points"); 1657 1658 // Check significant bits. 1659 parse_ok::<Ieee64>("0x0.fffffffffffff8", "0x1.fffffffffffffp-1"); 1660 parse_ok::<Ieee64>("0x1.fffffffffffff", "0x1.fffffffffffffp0"); 1661 parse_ok::<Ieee64>("0x3.ffffffffffffe", "0x1.fffffffffffffp1"); 1662 parse_ok::<Ieee64>("0x7.ffffffffffffc", "0x1.fffffffffffffp2"); 1663 parse_ok::<Ieee64>("0xf.ffffffffffff8", "0x1.fffffffffffffp3"); 1664 parse_err::<Ieee64>("0x3.fffffffffffff", "Too many significant bits"); 1665 parse_err::<Ieee64>("0x001.fffffe000000000000000000000000", "Too many digits"); 1666 1667 // Exponents. 1668 parse_ok::<Ieee64>("0x1p3", "0x1.0000000000000p3"); 1669 parse_ok::<Ieee64>("0x1p-3", "0x1.0000000000000p-3"); 1670 parse_ok::<Ieee64>("0x1.0p3", "0x1.0000000000000p3"); 1671 parse_ok::<Ieee64>("0x2.0p3", "0x1.0000000000000p4"); 1672 parse_ok::<Ieee64>("0x1.0p1023", "0x1.0000000000000p1023"); 1673 parse_ok::<Ieee64>("0x1.0p-1022", "0x1.0000000000000p-1022"); 1674 parse_ok::<Ieee64>("0x0.1p-1018", "0x1.0000000000000p-1022"); 1675 parse_err::<Ieee64>("0x2.0p1023", "Magnitude too large"); 1676 1677 // Subnormals. 1678 parse_ok::<Ieee64>("0x1.0p-1023", "0x0.8000000000000p-1022"); 1679 parse_ok::<Ieee64>("0x1.0p-1074", "0x0.0000000000001p-1022"); 1680 parse_ok::<Ieee64>("0x0.0000000000001p-1022", "0x0.0000000000001p-1022"); 1681 parse_err::<Ieee64>("0x0.10000000000008p-1022", "Subnormal underflow"); 1682 parse_err::<Ieee64>("0x1.8p-1074", "Subnormal underflow"); 1683 parse_err::<Ieee64>("0x1.0p-1075", "Magnitude too small"); 1684 1685 // NaNs and Infs. 1686 parse_ok::<Ieee64>("Inf", "+Inf"); 1687 parse_ok::<Ieee64>("-Inf", "-Inf"); 1688 parse_ok::<Ieee64>("NaN", "+NaN"); 1689 parse_ok::<Ieee64>("-NaN", "-NaN"); 1690 parse_ok::<Ieee64>("NaN:0x0", "+NaN"); 1691 parse_err::<Ieee64>("NaN:", "Float must be hexadecimal"); 1692 parse_err::<Ieee64>("NaN:0", "Float must be hexadecimal"); 1693 parse_err::<Ieee64>("NaN:0x", "Invalid NaN payload"); 1694 parse_ok::<Ieee64>("NaN:0x000001", "+NaN:0x1"); 1695 parse_ok::<Ieee64>("NaN:0x4000000000001", "+NaN:0x4000000000001"); 1696 parse_err::<Ieee64>("NaN:0x8000000000001", "Invalid NaN payload"); 1697 parse_ok::<Ieee64>("sNaN:0x1", "+sNaN:0x1"); 1698 parse_err::<Ieee64>("sNaN:0x0", "Invalid sNaN payload"); 1699 parse_ok::<Ieee64>("sNaN:0x4000000000001", "+sNaN:0x4000000000001"); 1700 parse_err::<Ieee64>("sNaN:0x8000000000001", "Invalid sNaN payload"); 1701 } 1702 1703 #[test] 1704 fn pow2_ieee64() { 1705 assert_eq!(Ieee64::pow2(0).to_string(), "0x1.0000000000000p0"); 1706 assert_eq!(Ieee64::pow2(1).to_string(), "0x1.0000000000000p1"); 1707 assert_eq!(Ieee64::pow2(-1).to_string(), "0x1.0000000000000p-1"); 1708 assert_eq!(Ieee64::pow2(1023).to_string(), "0x1.0000000000000p1023"); 1709 assert_eq!(Ieee64::pow2(-1022).to_string(), "0x1.0000000000000p-1022"); 1710 1711 assert_eq!((-Ieee64::pow2(1)).to_string(), "-0x1.0000000000000p1"); 1712 } 1713 1714 #[test] 1715 fn fcvt_to_sint_negative_overflow_ieee64() { 1716 for n in [8, 16, 32] { 1717 assert_eq!( 1718 -((1u64 << (n - 1)) as f64) - 1.0, 1719 Ieee64::fcvt_to_sint_negative_overflow(n).as_f64(), 1720 "n = {n}" 1721 ); 1722 } 1723 } 1724 1725 #[test] 1726 fn format_ieee128() { 1727 assert_eq!( 1728 Ieee128::with_bits(0x00000000000000000000000000000000).to_string(), // 0.0 1729 "0.0" 1730 ); 1731 assert_eq!( 1732 Ieee128::with_bits(0x80000000000000000000000000000000).to_string(), // -0.0 1733 "-0.0" 1734 ); 1735 assert_eq!( 1736 Ieee128::with_bits(0x3fff0000000000000000000000000000).to_string(), // 1.0 1737 "0x1.0000000000000000000000000000p0" 1738 ); 1739 assert_eq!( 1740 Ieee128::with_bits(0x3fff8000000000000000000000000000).to_string(), // 1.5 1741 "0x1.8000000000000000000000000000p0" 1742 ); 1743 assert_eq!( 1744 Ieee128::with_bits(0x3ffe0000000000000000000000000000).to_string(), // 0.5 1745 "0x1.0000000000000000000000000000p-1" 1746 ); 1747 assert_eq!( 1748 Ieee128::with_bits(0x3f8f0000000000000000000000000000).to_string(), // `f128::EPSILON` 1749 "0x1.0000000000000000000000000000p-112" 1750 ); 1751 assert_eq!( 1752 Ieee128::with_bits(0xfffeffffffffffffffffffffffffffff).to_string(), // `f128::MIN` 1753 "-0x1.ffffffffffffffffffffffffffffp16383" 1754 ); 1755 assert_eq!( 1756 Ieee128::with_bits(0x7ffeffffffffffffffffffffffffffff).to_string(), // `f128::MAX` 1757 "0x1.ffffffffffffffffffffffffffffp16383" 1758 ); 1759 // Smallest positive normal number. 1760 assert_eq!( 1761 Ieee128::with_bits(0x00010000000000000000000000000000).to_string(), // `f128::MIN_POSITIVE` 1762 "0x1.0000000000000000000000000000p-16382" 1763 ); 1764 // Subnormals. 1765 assert_eq!( 1766 Ieee128::with_bits(0x00008000000000000000000000000000).to_string(), // `f128::MIN_POSITIVE / 2.0` 1767 "0x0.8000000000000000000000000000p-16382" 1768 ); 1769 assert_eq!( 1770 Ieee128::with_bits(0x00000000000000000000000000000001).to_string(), // `f128::MIN_POSITIVE * f128::EPSILON` 1771 "0x0.0000000000000000000000000001p-16382" 1772 ); 1773 assert_eq!( 1774 Ieee128::with_bits(0x7fff0000000000000000000000000000).to_string(), // `f128::INFINITY` 1775 "+Inf" 1776 ); 1777 assert_eq!( 1778 Ieee128::with_bits(0xffff0000000000000000000000000000).to_string(), // `f128::NEG_INFINITY` 1779 "-Inf" 1780 ); 1781 assert_eq!( 1782 Ieee128::with_bits(0x7fff8000000000000000000000000000).to_string(), // `f128::NAN` 1783 "+NaN" 1784 ); 1785 assert_eq!( 1786 Ieee128::with_bits(0xffff8000000000000000000000000000).to_string(), // `-f128::NAN` 1787 "-NaN" 1788 ); 1789 // Construct some qNaNs with payloads. 1790 assert_eq!( 1791 Ieee128::with_bits(0x7fff8000000000000000000000000001).to_string(), 1792 "+NaN:0x1" 1793 ); 1794 assert_eq!( 1795 Ieee128::with_bits(0x7fffc000000000000000000000000001).to_string(), 1796 "+NaN:0x4000000000000000000000000001" 1797 ); 1798 // Signaling NaNs. 1799 assert_eq!( 1800 Ieee128::with_bits(0x7fff0000000000000000000000000001).to_string(), 1801 "+sNaN:0x1" 1802 ); 1803 assert_eq!( 1804 Ieee128::with_bits(0x7fff4000000000000000000000000001).to_string(), 1805 "+sNaN:0x4000000000000000000000000001" 1806 ); 1807 } 1808 1809 #[test] 1810 fn parse_ieee128() { 1811 parse_ok::<Ieee128>("0.0", "0.0"); 1812 parse_ok::<Ieee128>("-0.0", "-0.0"); 1813 parse_ok::<Ieee128>("0x0", "0.0"); 1814 parse_ok::<Ieee128>("0x0.0", "0.0"); 1815 parse_ok::<Ieee128>("0x.0", "0.0"); 1816 parse_ok::<Ieee128>("0x0.", "0.0"); 1817 parse_ok::<Ieee128>("0x1", "0x1.0000000000000000000000000000p0"); 1818 parse_ok::<Ieee128>("-0x1", "-0x1.0000000000000000000000000000p0"); 1819 parse_ok::<Ieee128>("0x10", "0x1.0000000000000000000000000000p4"); 1820 parse_ok::<Ieee128>("0x10.0", "0x1.0000000000000000000000000000p4"); 1821 parse_err::<Ieee128>("0.", "Float must be hexadecimal"); 1822 parse_err::<Ieee128>(".0", "Float must be hexadecimal"); 1823 parse_err::<Ieee128>("0", "Float must be hexadecimal"); 1824 parse_err::<Ieee128>("-0", "Float must be hexadecimal"); 1825 parse_err::<Ieee128>(".", "Float must be hexadecimal"); 1826 parse_err::<Ieee128>("", "Float must be hexadecimal"); 1827 parse_err::<Ieee128>("-", "Float must be hexadecimal"); 1828 parse_err::<Ieee128>("0x", "No digits"); 1829 parse_err::<Ieee128>("0x..", "Multiple radix points"); 1830 1831 // Check significant bits. 1832 parse_ok::<Ieee128>( 1833 "0x0.ffffffffffffffffffffffffffff8", 1834 "0x1.ffffffffffffffffffffffffffffp-1", 1835 ); 1836 parse_ok::<Ieee128>( 1837 "0x1.ffffffffffffffffffffffffffff", 1838 "0x1.ffffffffffffffffffffffffffffp0", 1839 ); 1840 parse_ok::<Ieee128>( 1841 "0x3.fffffffffffffffffffffffffffe", 1842 "0x1.ffffffffffffffffffffffffffffp1", 1843 ); 1844 parse_ok::<Ieee128>( 1845 "0x7.fffffffffffffffffffffffffffc", 1846 "0x1.ffffffffffffffffffffffffffffp2", 1847 ); 1848 parse_ok::<Ieee128>( 1849 "0xf.fffffffffffffffffffffffffff8", 1850 "0x1.ffffffffffffffffffffffffffffp3", 1851 ); 1852 parse_err::<Ieee128>( 1853 "0x3.ffffffffffffffffffffffffffff", 1854 "Too many significant bits", 1855 ); 1856 parse_err::<Ieee128>("0x001.fffffe000000000000000000000000", "Too many digits"); 1857 1858 // Exponents. 1859 parse_ok::<Ieee128>("0x1p3", "0x1.0000000000000000000000000000p3"); 1860 parse_ok::<Ieee128>("0x1p-3", "0x1.0000000000000000000000000000p-3"); 1861 parse_ok::<Ieee128>("0x1.0p3", "0x1.0000000000000000000000000000p3"); 1862 parse_ok::<Ieee128>("0x2.0p3", "0x1.0000000000000000000000000000p4"); 1863 parse_ok::<Ieee128>("0x1.0p16383", "0x1.0000000000000000000000000000p16383"); 1864 parse_ok::<Ieee128>("0x1.0p-16382", "0x1.0000000000000000000000000000p-16382"); 1865 parse_ok::<Ieee128>("0x0.1p-16378", "0x1.0000000000000000000000000000p-16382"); 1866 parse_err::<Ieee128>("0x2.0p16383", "Magnitude too large"); 1867 1868 // Subnormals. 1869 parse_ok::<Ieee128>("0x1.0p-16383", "0x0.8000000000000000000000000000p-16382"); 1870 parse_ok::<Ieee128>("0x1.0p-16494", "0x0.0000000000000000000000000001p-16382"); 1871 parse_ok::<Ieee128>( 1872 "0x0.0000000000000000000000000001p-16382", 1873 "0x0.0000000000000000000000000001p-16382", 1874 ); 1875 parse_err::<Ieee128>( 1876 "0x0.10000000000000000000000000008p-16382", 1877 "Subnormal underflow", 1878 ); 1879 parse_err::<Ieee128>("0x1.8p-16494", "Subnormal underflow"); 1880 parse_err::<Ieee128>("0x1.0p-16495", "Magnitude too small"); 1881 1882 // NaNs and Infs. 1883 parse_ok::<Ieee128>("Inf", "+Inf"); 1884 parse_ok::<Ieee128>("-Inf", "-Inf"); 1885 parse_ok::<Ieee128>("NaN", "+NaN"); 1886 parse_ok::<Ieee128>("-NaN", "-NaN"); 1887 parse_ok::<Ieee128>("NaN:0x0", "+NaN"); 1888 parse_err::<Ieee128>("NaN:", "Float must be hexadecimal"); 1889 parse_err::<Ieee128>("NaN:0", "Float must be hexadecimal"); 1890 parse_err::<Ieee128>("NaN:0x", "Invalid NaN payload"); 1891 parse_ok::<Ieee128>("NaN:0x000001", "+NaN:0x1"); 1892 parse_ok::<Ieee128>( 1893 "NaN:0x4000000000000000000000000001", 1894 "+NaN:0x4000000000000000000000000001", 1895 ); 1896 parse_err::<Ieee128>("NaN:0x8000000000000000000000000001", "Invalid NaN payload"); 1897 parse_ok::<Ieee128>("sNaN:0x1", "+sNaN:0x1"); 1898 parse_err::<Ieee128>("sNaN:0x0", "Invalid sNaN payload"); 1899 parse_ok::<Ieee128>( 1900 "sNaN:0x4000000000000000000000000001", 1901 "+sNaN:0x4000000000000000000000000001", 1902 ); 1903 parse_err::<Ieee128>( 1904 "sNaN:0x8000000000000000000000000001", 1905 "Invalid sNaN payload", 1906 ); 1907 } 1908 1909 #[test] 1910 fn pow2_ieee128() { 1911 assert_eq!( 1912 Ieee128::pow2(0).to_string(), 1913 "0x1.0000000000000000000000000000p0" 1914 ); 1915 assert_eq!( 1916 Ieee128::pow2(1).to_string(), 1917 "0x1.0000000000000000000000000000p1" 1918 ); 1919 assert_eq!( 1920 Ieee128::pow2(-1).to_string(), 1921 "0x1.0000000000000000000000000000p-1" 1922 ); 1923 assert_eq!( 1924 Ieee128::pow2(16383).to_string(), 1925 "0x1.0000000000000000000000000000p16383" 1926 ); 1927 assert_eq!( 1928 Ieee128::pow2(-16382).to_string(), 1929 "0x1.0000000000000000000000000000p-16382" 1930 ); 1931 1932 assert_eq!( 1933 (-Ieee128::pow2(1)).to_string(), 1934 "-0x1.0000000000000000000000000000p1" 1935 ); 1936 } 1937 1938 #[test] 1939 fn fcvt_to_sint_negative_overflow_ieee128() { 1940 // FIXME(#8312): Replace with commented out version once Rust f128 support is stabilised. 1941 // for n in [8, 16, 32, 64] { 1942 // assert_eq!( 1943 // -((1u128 << (n - 1)) as f128) - 1.0, 1944 // Ieee128::fcvt_to_sint_negative_overflow(n).as_f128(), 1945 // "n = {n}" 1946 // ); 1947 // } 1948 for (n, expected) in [ 1949 (8, "-0x1.0200000000000000000000000000p7"), 1950 (16, "-0x1.0002000000000000000000000000p15"), 1951 (32, "-0x1.0000000200000000000000000000p31"), 1952 (64, "-0x1.0000000000000002000000000000p63"), 1953 ] { 1954 assert_eq!( 1955 expected, 1956 Ieee128::fcvt_to_sint_negative_overflow(n).to_string(), 1957 "n = {n}" 1958 ); 1959 } 1960 } 1961 } 1962