Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/ir/immediates.rs
1693 views
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
1962