cranelift_codegen/ir/
immediates.rs

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