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