about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_apfloat/Cargo.toml8
-rw-r--r--compiler/rustc_apfloat/src/ieee.rs2757
-rw-r--r--compiler/rustc_apfloat/src/lib.rs695
-rw-r--r--compiler/rustc_apfloat/src/ppc.rs434
-rw-r--r--compiler/rustc_apfloat/tests/ieee.rs3301
-rw-r--r--compiler/rustc_apfloat/tests/ppc.rs530
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs2
-rw-r--r--compiler/rustc_const_eval/Cargo.toml2
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs4
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs2
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs46
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/discriminant.rs44
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs18
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/mod.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs97
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs250
-rw-r--r--compiler/rustc_const_eval/src/interpret/projection.rs27
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/visitor.rs4
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs2
-rw-r--r--compiler/rustc_errors/src/diagnostic_builder.rs4
-rw-r--r--compiler/rustc_errors/src/json/tests.rs2
-rw-r--r--compiler/rustc_errors/src/lib.rs75
-rw-r--r--compiler/rustc_expand/src/parse/tests.rs12
-rw-r--r--compiler/rustc_expand/src/tests.rs69
-rw-r--r--compiler/rustc_lint/messages.ftl2
-rw-r--r--compiler/rustc_lint/src/types.rs83
-rw-r--r--compiler/rustc_middle/Cargo.toml2
-rw-r--r--compiler/rustc_mir_build/Cargo.toml2
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs4
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_session/src/parse.rs30
-rw-r--r--compiler/rustc_session/src/session.rs14
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs22
-rw-r--r--compiler/rustc_smir/src/stable_mir/ty.rs14
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs79
42 files changed, 502 insertions, 8167 deletions
diff --git a/compiler/rustc_apfloat/Cargo.toml b/compiler/rustc_apfloat/Cargo.toml
deleted file mode 100644
index 98305201bc9..00000000000
--- a/compiler/rustc_apfloat/Cargo.toml
+++ /dev/null
@@ -1,8 +0,0 @@
-[package]
-name = "rustc_apfloat"
-version = "0.0.0"
-edition = "2021"
-
-[dependencies]
-bitflags = "1.2.1"
-smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_apfloat/src/ieee.rs b/compiler/rustc_apfloat/src/ieee.rs
deleted file mode 100644
index 2286712f025..00000000000
--- a/compiler/rustc_apfloat/src/ieee.rs
+++ /dev/null
@@ -1,2757 +0,0 @@
-use crate::{Category, ExpInt, IEK_INF, IEK_NAN, IEK_ZERO};
-use crate::{Float, FloatConvert, ParseError, Round, Status, StatusAnd};
-
-use core::cmp::{self, Ordering};
-use core::fmt::{self, Write};
-use core::marker::PhantomData;
-use core::mem;
-use core::ops::Neg;
-use smallvec::{smallvec, SmallVec};
-
-#[must_use]
-pub struct IeeeFloat<S> {
-    /// Absolute significand value (including the integer bit).
-    sig: [Limb; 1],
-
-    /// The signed unbiased exponent of the value.
-    exp: ExpInt,
-
-    /// What kind of floating point number this is.
-    category: Category,
-
-    /// Sign bit of the number.
-    sign: bool,
-
-    marker: PhantomData<S>,
-}
-
-/// Fundamental unit of big integer arithmetic, but also
-/// large to store the largest significands by itself.
-type Limb = u128;
-const LIMB_BITS: usize = 128;
-fn limbs_for_bits(bits: usize) -> usize {
-    (bits + LIMB_BITS - 1) / LIMB_BITS
-}
-
-/// Enum that represents what fraction of the LSB truncated bits of an fp number
-/// represent.
-///
-/// This essentially combines the roles of guard and sticky bits.
-#[must_use]
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-enum Loss {
-    // Example of truncated bits:
-    ExactlyZero,  // 000000
-    LessThanHalf, // 0xxxxx  x's not all zero
-    ExactlyHalf,  // 100000
-    MoreThanHalf, // 1xxxxx  x's not all zero
-}
-
-/// Represents floating point arithmetic semantics.
-pub trait Semantics: Sized {
-    /// Total number of bits in the in-memory format.
-    const BITS: usize;
-
-    /// Number of bits in the significand. This includes the integer bit.
-    const PRECISION: usize;
-
-    /// The largest E such that 2<sup>E</sup> is representable; this matches the
-    /// definition of IEEE 754.
-    const MAX_EXP: ExpInt;
-
-    /// The smallest E such that 2<sup>E</sup> is a normalized number; this
-    /// matches the definition of IEEE 754.
-    const MIN_EXP: ExpInt = -Self::MAX_EXP + 1;
-
-    /// The significand bit that marks NaN as quiet.
-    const QNAN_BIT: usize = Self::PRECISION - 2;
-
-    /// The significand bitpattern to mark a NaN as quiet.
-    /// NOTE: for X87DoubleExtended we need to set two bits instead of 2.
-    const QNAN_SIGNIFICAND: Limb = 1 << Self::QNAN_BIT;
-
-    fn from_bits(bits: u128) -> IeeeFloat<Self> {
-        assert!(Self::BITS > Self::PRECISION);
-
-        let sign = bits & (1 << (Self::BITS - 1));
-        let exponent = (bits & !sign) >> (Self::PRECISION - 1);
-        let mut r = IeeeFloat {
-            sig: [bits & ((1 << (Self::PRECISION - 1)) - 1)],
-            // Convert the exponent from its bias representation to a signed integer.
-            exp: (exponent as ExpInt) - Self::MAX_EXP,
-            category: Category::Zero,
-            sign: sign != 0,
-            marker: PhantomData,
-        };
-
-        if r.exp == Self::MIN_EXP - 1 && r.sig == [0] {
-            // Exponent, significand meaningless.
-            r.category = Category::Zero;
-        } else if r.exp == Self::MAX_EXP + 1 && r.sig == [0] {
-            // Exponent, significand meaningless.
-            r.category = Category::Infinity;
-        } else if r.exp == Self::MAX_EXP + 1 && r.sig != [0] {
-            // Sign, exponent, significand meaningless.
-            r.category = Category::NaN;
-        } else {
-            r.category = Category::Normal;
-            if r.exp == Self::MIN_EXP - 1 {
-                // Denormal.
-                r.exp = Self::MIN_EXP;
-            } else {
-                // Set integer bit.
-                sig::set_bit(&mut r.sig, Self::PRECISION - 1);
-            }
-        }
-
-        r
-    }
-
-    fn to_bits(x: IeeeFloat<Self>) -> u128 {
-        assert!(Self::BITS > Self::PRECISION);
-
-        // Split integer bit from significand.
-        let integer_bit = sig::get_bit(&x.sig, Self::PRECISION - 1);
-        let mut significand = x.sig[0] & ((1 << (Self::PRECISION - 1)) - 1);
-        let exponent = match x.category {
-            Category::Normal => {
-                if x.exp == Self::MIN_EXP && !integer_bit {
-                    // Denormal.
-                    Self::MIN_EXP - 1
-                } else {
-                    x.exp
-                }
-            }
-            Category::Zero => {
-                // FIXME(eddyb) Maybe we should guarantee an invariant instead?
-                significand = 0;
-                Self::MIN_EXP - 1
-            }
-            Category::Infinity => {
-                // FIXME(eddyb) Maybe we should guarantee an invariant instead?
-                significand = 0;
-                Self::MAX_EXP + 1
-            }
-            Category::NaN => Self::MAX_EXP + 1,
-        };
-
-        // Convert the exponent from a signed integer to its bias representation.
-        let exponent = (exponent + Self::MAX_EXP) as u128;
-
-        ((x.sign as u128) << (Self::BITS - 1)) | (exponent << (Self::PRECISION - 1)) | significand
-    }
-}
-
-impl<S> Copy for IeeeFloat<S> {}
-impl<S> Clone for IeeeFloat<S> {
-    fn clone(&self) -> Self {
-        *self
-    }
-}
-
-macro_rules! ieee_semantics {
-    ($($name:ident = $sem:ident($bits:tt : $exp_bits:tt)),*) => {
-        $(pub struct $sem;)*
-        $(pub type $name = IeeeFloat<$sem>;)*
-        $(impl Semantics for $sem {
-            const BITS: usize = $bits;
-            const PRECISION: usize = ($bits - 1 - $exp_bits) + 1;
-            const MAX_EXP: ExpInt = (1 << ($exp_bits - 1)) - 1;
-        })*
-    }
-}
-
-ieee_semantics! {
-    Half = HalfS(16:5),
-    Single = SingleS(32:8),
-    Double = DoubleS(64:11),
-    Quad = QuadS(128:15)
-}
-
-pub struct X87DoubleExtendedS;
-pub type X87DoubleExtended = IeeeFloat<X87DoubleExtendedS>;
-impl Semantics for X87DoubleExtendedS {
-    const BITS: usize = 80;
-    const PRECISION: usize = 64;
-    const MAX_EXP: ExpInt = (1 << (15 - 1)) - 1;
-
-    /// For x87 extended precision, we want to make a NaN, not a
-    /// pseudo-NaN. Maybe we should expose the ability to make
-    /// pseudo-NaNs?
-    const QNAN_SIGNIFICAND: Limb = 0b11 << Self::QNAN_BIT;
-
-    /// Integer bit is explicit in this format. Intel hardware (387 and later)
-    /// does not support these bit patterns:
-    ///  exponent = all 1's, integer bit 0, significand 0 ("pseudoinfinity")
-    ///  exponent = all 1's, integer bit 0, significand nonzero ("pseudoNaN")
-    ///  exponent = 0, integer bit 1 ("pseudodenormal")
-    ///  exponent != 0 nor all 1's, integer bit 0 ("unnormal")
-    /// At the moment, the first two are treated as NaNs, the second two as Normal.
-    fn from_bits(bits: u128) -> IeeeFloat<Self> {
-        let sign = bits & (1 << (Self::BITS - 1));
-        let exponent = (bits & !sign) >> Self::PRECISION;
-        let mut r = IeeeFloat {
-            sig: [bits & ((1 << (Self::PRECISION - 1)) - 1)],
-            // Convert the exponent from its bias representation to a signed integer.
-            exp: (exponent as ExpInt) - Self::MAX_EXP,
-            category: Category::Zero,
-            sign: sign != 0,
-            marker: PhantomData,
-        };
-
-        if r.exp == Self::MIN_EXP - 1 && r.sig == [0] {
-            // Exponent, significand meaningless.
-            r.category = Category::Zero;
-        } else if r.exp == Self::MAX_EXP + 1 && r.sig == [1 << (Self::PRECISION - 1)] {
-            // Exponent, significand meaningless.
-            r.category = Category::Infinity;
-        } else if r.exp == Self::MAX_EXP + 1 && r.sig != [1 << (Self::PRECISION - 1)] {
-            // Sign, exponent, significand meaningless.
-            r.category = Category::NaN;
-        } else {
-            r.category = Category::Normal;
-            if r.exp == Self::MIN_EXP - 1 {
-                // Denormal.
-                r.exp = Self::MIN_EXP;
-            }
-        }
-
-        r
-    }
-
-    fn to_bits(x: IeeeFloat<Self>) -> u128 {
-        // Get integer bit from significand.
-        let integer_bit = sig::get_bit(&x.sig, Self::PRECISION - 1);
-        let mut significand = x.sig[0] & ((1 << Self::PRECISION) - 1);
-        let exponent = match x.category {
-            Category::Normal => {
-                if x.exp == Self::MIN_EXP && !integer_bit {
-                    // Denormal.
-                    Self::MIN_EXP - 1
-                } else {
-                    x.exp
-                }
-            }
-            Category::Zero => {
-                // FIXME(eddyb) Maybe we should guarantee an invariant instead?
-                significand = 0;
-                Self::MIN_EXP - 1
-            }
-            Category::Infinity => {
-                // FIXME(eddyb) Maybe we should guarantee an invariant instead?
-                significand = 1 << (Self::PRECISION - 1);
-                Self::MAX_EXP + 1
-            }
-            Category::NaN => Self::MAX_EXP + 1,
-        };
-
-        // Convert the exponent from a signed integer to its bias representation.
-        let exponent = (exponent + Self::MAX_EXP) as u128;
-
-        ((x.sign as u128) << (Self::BITS - 1)) | (exponent << Self::PRECISION) | significand
-    }
-}
-
-float_common_impls!(IeeeFloat<S>);
-
-impl<S: Semantics> PartialEq for IeeeFloat<S> {
-    fn eq(&self, rhs: &Self) -> bool {
-        self.partial_cmp(rhs) == Some(Ordering::Equal)
-    }
-}
-
-impl<S: Semantics> PartialOrd for IeeeFloat<S> {
-    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
-        match (self.category, rhs.category) {
-            (Category::NaN, _) | (_, Category::NaN) => None,
-
-            (Category::Infinity, Category::Infinity) => Some((!self.sign).cmp(&(!rhs.sign))),
-
-            (Category::Zero, Category::Zero) => Some(Ordering::Equal),
-
-            (Category::Infinity, _) | (Category::Normal, Category::Zero) => {
-                Some((!self.sign).cmp(&self.sign))
-            }
-
-            (_, Category::Infinity) | (Category::Zero, Category::Normal) => {
-                Some(rhs.sign.cmp(&(!rhs.sign)))
-            }
-
-            (Category::Normal, Category::Normal) => {
-                // Two normal numbers. Do they have the same sign?
-                Some((!self.sign).cmp(&(!rhs.sign)).then_with(|| {
-                    // Compare absolute values; invert result if negative.
-                    let result = self.cmp_abs_normal(*rhs);
-
-                    if self.sign { result.reverse() } else { result }
-                }))
-            }
-        }
-    }
-}
-
-impl<S> Neg for IeeeFloat<S> {
-    type Output = Self;
-    fn neg(mut self) -> Self {
-        self.sign = !self.sign;
-        self
-    }
-}
-
-/// Prints this value as a decimal string.
-///
-/// \param precision The maximum number of digits of
-///   precision to output. If there are fewer digits available,
-///   zero padding will not be used unless the value is
-///   integral and small enough to be expressed in
-///   precision digits. 0 means to use the natural
-///   precision of the number.
-/// \param width The maximum number of zeros to
-///   consider inserting before falling back to scientific
-///   notation. 0 means to always use scientific notation.
-///
-/// \param alternate Indicate whether to remove the trailing zero in
-///   fraction part or not. Also setting this parameter to true forces
-///   producing of output more similar to default printf behavior.
-///   Specifically the lower e is used as exponent delimiter and exponent
-///   always contains no less than two digits.
-///
-/// Number       precision    width      Result
-/// ------       ---------    -----      ------
-/// 1.01E+4              5        2       10100
-/// 1.01E+4              4        2       1.01E+4
-/// 1.01E+4              5        1       1.01E+4
-/// 1.01E-2              5        2       0.0101
-/// 1.01E-2              4        2       0.0101
-/// 1.01E-2              4        1       1.01E-2
-impl<S: Semantics> fmt::Display for IeeeFloat<S> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let width = f.width().unwrap_or(3);
-        let alternate = f.alternate();
-
-        match self.category {
-            Category::Infinity => {
-                if self.sign {
-                    return f.write_str("-Inf");
-                } else {
-                    return f.write_str("+Inf");
-                }
-            }
-
-            Category::NaN => return f.write_str("NaN"),
-
-            Category::Zero => {
-                if self.sign {
-                    f.write_char('-')?;
-                }
-
-                if width == 0 {
-                    if alternate {
-                        f.write_str("0.0")?;
-                        if let Some(n) = f.precision() {
-                            for _ in 1..n {
-                                f.write_char('0')?;
-                            }
-                        }
-                        f.write_str("e+00")?;
-                    } else {
-                        f.write_str("0.0E+0")?;
-                    }
-                } else {
-                    f.write_char('0')?;
-                }
-                return Ok(());
-            }
-
-            Category::Normal => {}
-        }
-
-        if self.sign {
-            f.write_char('-')?;
-        }
-
-        // We use enough digits so the number can be round-tripped back to an
-        // APFloat. The formula comes from "How to Print Floating-Point Numbers
-        // Accurately" by Steele and White.
-        // FIXME: Using a formula based purely on the precision is conservative;
-        // we can print fewer digits depending on the actual value being printed.
-
-        // precision = 2 + floor(S::PRECISION / lg_2(10))
-        let precision = f.precision().unwrap_or(2 + S::PRECISION * 59 / 196);
-
-        // Decompose the number into an APInt and an exponent.
-        let mut exp = self.exp - (S::PRECISION as ExpInt - 1);
-        let mut sig = vec![self.sig[0]];
-
-        // Ignore trailing binary zeros.
-        let trailing_zeros = sig[0].trailing_zeros();
-        let _: Loss = sig::shift_right(&mut sig, &mut exp, trailing_zeros as usize);
-
-        // Change the exponent from 2^e to 10^e.
-        if exp == 0 {
-            // Nothing to do.
-        } else if exp > 0 {
-            // Just shift left.
-            let shift = exp as usize;
-            sig.resize(limbs_for_bits(S::PRECISION + shift), 0);
-            sig::shift_left(&mut sig, &mut exp, shift);
-        } else {
-            // exp < 0
-            let mut texp = -exp as usize;
-
-            // We transform this using the identity:
-            //   (N)(2^-e) == (N)(5^e)(10^-e)
-
-            // Multiply significand by 5^e.
-            //   N * 5^0101 == N * 5^(1*1) * 5^(0*2) * 5^(1*4) * 5^(0*8)
-            let mut sig_scratch = vec![];
-            let mut p5 = vec![];
-            let mut p5_scratch = vec![];
-            while texp != 0 {
-                if p5.is_empty() {
-                    p5.push(5);
-                } else {
-                    p5_scratch.resize(p5.len() * 2, 0);
-                    let _: Loss =
-                        sig::mul(&mut p5_scratch, &mut 0, &p5, &p5, p5.len() * 2 * LIMB_BITS);
-                    while p5_scratch.last() == Some(&0) {
-                        p5_scratch.pop();
-                    }
-                    mem::swap(&mut p5, &mut p5_scratch);
-                }
-                if texp & 1 != 0 {
-                    sig_scratch.resize(sig.len() + p5.len(), 0);
-                    let _: Loss = sig::mul(
-                        &mut sig_scratch,
-                        &mut 0,
-                        &sig,
-                        &p5,
-                        (sig.len() + p5.len()) * LIMB_BITS,
-                    );
-                    while sig_scratch.last() == Some(&0) {
-                        sig_scratch.pop();
-                    }
-                    mem::swap(&mut sig, &mut sig_scratch);
-                }
-                texp >>= 1;
-            }
-        }
-
-        // Fill the buffer.
-        let mut buffer = vec![];
-
-        // Ignore digits from the significand until it is no more
-        // precise than is required for the desired precision.
-        // 196/59 is a very slight overestimate of lg_2(10).
-        let required = (precision * 196 + 58) / 59;
-        let mut discard_digits = sig::omsb(&sig).saturating_sub(required) * 59 / 196;
-        let mut in_trail = true;
-        while !sig.is_empty() {
-            // Perform short division by 10 to extract the rightmost digit.
-            // rem <- sig % 10
-            // sig <- sig / 10
-            let mut rem = 0;
-
-            // Use 64-bit division and remainder, with 32-bit chunks from sig.
-            sig::each_chunk(&mut sig, 32, |chunk| {
-                let chunk = chunk as u32;
-                let combined = ((rem as u64) << 32) | (chunk as u64);
-                rem = (combined % 10) as u8;
-                (combined / 10) as u32 as Limb
-            });
-
-            // Reduce the significand to avoid wasting time dividing 0's.
-            while sig.last() == Some(&0) {
-                sig.pop();
-            }
-
-            let digit = rem;
-
-            // Ignore digits we don't need.
-            if discard_digits > 0 {
-                discard_digits -= 1;
-                exp += 1;
-                continue;
-            }
-
-            // Drop trailing zeros.
-            if in_trail && digit == 0 {
-                exp += 1;
-            } else {
-                in_trail = false;
-                buffer.push(b'0' + digit);
-            }
-        }
-
-        assert!(!buffer.is_empty(), "no characters in buffer!");
-
-        // Drop down to precision.
-        // FIXME: don't do more precise calculations above than are required.
-        if buffer.len() > precision {
-            // The most significant figures are the last ones in the buffer.
-            let mut first_sig = buffer.len() - precision;
-
-            // Round.
-            // FIXME: this probably shouldn't use 'round half up'.
-
-            // Rounding down is just a truncation, except we also want to drop
-            // trailing zeros from the new result.
-            if buffer[first_sig - 1] < b'5' {
-                while first_sig < buffer.len() && buffer[first_sig] == b'0' {
-                    first_sig += 1;
-                }
-            } else {
-                // Rounding up requires a decimal add-with-carry. If we continue
-                // the carry, the newly-introduced zeros will just be truncated.
-                for x in &mut buffer[first_sig..] {
-                    if *x == b'9' {
-                        first_sig += 1;
-                    } else {
-                        *x += 1;
-                        break;
-                    }
-                }
-            }
-
-            exp += first_sig as ExpInt;
-            buffer.drain(..first_sig);
-
-            // If we carried through, we have exactly one digit of precision.
-            if buffer.is_empty() {
-                buffer.push(b'1');
-            }
-        }
-
-        let digits = buffer.len();
-
-        // Check whether we should use scientific notation.
-        let scientific = if width == 0 {
-            true
-        } else if exp >= 0 {
-            // 765e3 --> 765000
-            //              ^^^
-            // But we shouldn't make the number look more precise than it is.
-            exp as usize > width || digits + exp as usize > precision
-        } else {
-            // Power of the most significant digit.
-            let msd = exp + (digits - 1) as ExpInt;
-            if msd >= 0 {
-                // 765e-2 == 7.65
-                false
-            } else {
-                // 765e-5 == 0.00765
-                //           ^ ^^
-                -msd as usize > width
-            }
-        };
-
-        // Scientific formatting is pretty straightforward.
-        if scientific {
-            exp += digits as ExpInt - 1;
-
-            f.write_char(buffer[digits - 1] as char)?;
-            f.write_char('.')?;
-            let truncate_zero = !alternate;
-            if digits == 1 && truncate_zero {
-                f.write_char('0')?;
-            } else {
-                for &d in buffer[..digits - 1].iter().rev() {
-                    f.write_char(d as char)?;
-                }
-            }
-            // Fill with zeros up to precision.
-            if !truncate_zero && precision > digits - 1 {
-                for _ in 0..=precision - digits {
-                    f.write_char('0')?;
-                }
-            }
-            // For alternate we use lower 'e'.
-            f.write_char(if alternate { 'e' } else { 'E' })?;
-
-            // Exponent always at least two digits if we do not truncate zeros.
-            if truncate_zero {
-                write!(f, "{:+}", exp)?;
-            } else {
-                write!(f, "{:+03}", exp)?;
-            }
-
-            return Ok(());
-        }
-
-        // Non-scientific, positive exponents.
-        if exp >= 0 {
-            for &d in buffer.iter().rev() {
-                f.write_char(d as char)?;
-            }
-            for _ in 0..exp {
-                f.write_char('0')?;
-            }
-            return Ok(());
-        }
-
-        // Non-scientific, negative exponents.
-        let unit_place = -exp as usize;
-        if unit_place < digits {
-            for &d in buffer[unit_place..].iter().rev() {
-                f.write_char(d as char)?;
-            }
-            f.write_char('.')?;
-            for &d in buffer[..unit_place].iter().rev() {
-                f.write_char(d as char)?;
-            }
-        } else {
-            f.write_str("0.")?;
-            for _ in digits..unit_place {
-                f.write_char('0')?;
-            }
-            for &d in buffer.iter().rev() {
-                f.write_char(d as char)?;
-            }
-        }
-
-        Ok(())
-    }
-}
-
-impl<S: Semantics> fmt::Debug for IeeeFloat<S> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "{}({:?} | {}{:?} * 2^{})",
-            self,
-            self.category,
-            if self.sign { "-" } else { "+" },
-            self.sig,
-            self.exp
-        )
-    }
-}
-
-impl<S: Semantics> Float for IeeeFloat<S> {
-    const BITS: usize = S::BITS;
-    const PRECISION: usize = S::PRECISION;
-    const MAX_EXP: ExpInt = S::MAX_EXP;
-    const MIN_EXP: ExpInt = S::MIN_EXP;
-
-    const ZERO: Self = IeeeFloat {
-        sig: [0],
-        exp: S::MIN_EXP - 1,
-        category: Category::Zero,
-        sign: false,
-        marker: PhantomData,
-    };
-
-    const INFINITY: Self = IeeeFloat {
-        sig: [0],
-        exp: S::MAX_EXP + 1,
-        category: Category::Infinity,
-        sign: false,
-        marker: PhantomData,
-    };
-
-    // FIXME(eddyb) remove when qnan becomes const fn.
-    const NAN: Self = IeeeFloat {
-        sig: [S::QNAN_SIGNIFICAND],
-        exp: S::MAX_EXP + 1,
-        category: Category::NaN,
-        sign: false,
-        marker: PhantomData,
-    };
-
-    fn qnan(payload: Option<u128>) -> Self {
-        IeeeFloat {
-            sig: [S::QNAN_SIGNIFICAND
-                | payload.map_or(0, |payload| {
-                    // Zero out the excess bits of the significand.
-                    payload & ((1 << S::QNAN_BIT) - 1)
-                })],
-            exp: S::MAX_EXP + 1,
-            category: Category::NaN,
-            sign: false,
-            marker: PhantomData,
-        }
-    }
-
-    fn snan(payload: Option<u128>) -> Self {
-        let mut snan = Self::qnan(payload);
-
-        // We always have to clear the QNaN bit to make it an SNaN.
-        sig::clear_bit(&mut snan.sig, S::QNAN_BIT);
-
-        // If there are no bits set in the payload, we have to set
-        // *something* to make it a NaN instead of an infinity;
-        // conventionally, this is the next bit down from the QNaN bit.
-        if snan.sig[0] & !S::QNAN_SIGNIFICAND == 0 {
-            sig::set_bit(&mut snan.sig, S::QNAN_BIT - 1);
-        }
-
-        snan
-    }
-
-    fn largest() -> Self {
-        // We want (in interchange format):
-        //   exponent = 1..10
-        //   significand = 1..1
-        IeeeFloat {
-            sig: [(1 << S::PRECISION) - 1],
-            exp: S::MAX_EXP,
-            category: Category::Normal,
-            sign: false,
-            marker: PhantomData,
-        }
-    }
-
-    // We want (in interchange format):
-    //   exponent = 0..0
-    //   significand = 0..01
-    const SMALLEST: Self = IeeeFloat {
-        sig: [1],
-        exp: S::MIN_EXP,
-        category: Category::Normal,
-        sign: false,
-        marker: PhantomData,
-    };
-
-    fn smallest_normalized() -> Self {
-        // We want (in interchange format):
-        //   exponent = 0..0
-        //   significand = 10..0
-        IeeeFloat {
-            sig: [1 << (S::PRECISION - 1)],
-            exp: S::MIN_EXP,
-            category: Category::Normal,
-            sign: false,
-            marker: PhantomData,
-        }
-    }
-
-    fn add_r(mut self, rhs: Self, round: Round) -> StatusAnd<Self> {
-        let status = match (self.category, rhs.category) {
-            (Category::Infinity, Category::Infinity) => {
-                // Differently signed infinities can only be validly
-                // subtracted.
-                if self.sign != rhs.sign {
-                    self = Self::NAN;
-                    Status::INVALID_OP
-                } else {
-                    Status::OK
-                }
-            }
-
-            // Sign may depend on rounding mode; handled below.
-            (_, Category::Zero) | (Category::NaN, _) | (Category::Infinity, Category::Normal) => {
-                Status::OK
-            }
-
-            (Category::Zero, _) | (_, Category::NaN | Category::Infinity) => {
-                self = rhs;
-                Status::OK
-            }
-
-            // This return code means it was not a simple case.
-            (Category::Normal, Category::Normal) => {
-                let loss = sig::add_or_sub(
-                    &mut self.sig,
-                    &mut self.exp,
-                    &mut self.sign,
-                    &mut [rhs.sig[0]],
-                    rhs.exp,
-                    rhs.sign,
-                );
-                let status;
-                self = unpack!(status=, self.normalize(round, loss));
-
-                // Can only be zero if we lost no fraction.
-                assert!(self.category != Category::Zero || loss == Loss::ExactlyZero);
-
-                status
-            }
-        };
-
-        // If two numbers add (exactly) to zero, IEEE 754 decrees it is a
-        // positive zero unless rounding to minus infinity, except that
-        // adding two like-signed zeroes gives that zero.
-        if self.category == Category::Zero
-            && (rhs.category != Category::Zero || self.sign != rhs.sign)
-        {
-            self.sign = round == Round::TowardNegative;
-        }
-
-        status.and(self)
-    }
-
-    fn mul_r(mut self, rhs: Self, round: Round) -> StatusAnd<Self> {
-        self.sign ^= rhs.sign;
-
-        match (self.category, rhs.category) {
-            (Category::NaN, _) => {
-                self.sign = false;
-                Status::OK.and(self)
-            }
-
-            (_, Category::NaN) => {
-                self.sign = false;
-                self.category = Category::NaN;
-                self.sig = rhs.sig;
-                Status::OK.and(self)
-            }
-
-            (Category::Zero, Category::Infinity) | (Category::Infinity, Category::Zero) => {
-                Status::INVALID_OP.and(Self::NAN)
-            }
-
-            (_, Category::Infinity) | (Category::Infinity, _) => {
-                self.category = Category::Infinity;
-                Status::OK.and(self)
-            }
-
-            (Category::Zero, _) | (_, Category::Zero) => {
-                self.category = Category::Zero;
-                Status::OK.and(self)
-            }
-
-            (Category::Normal, Category::Normal) => {
-                self.exp += rhs.exp;
-                let mut wide_sig = [0; 2];
-                let loss =
-                    sig::mul(&mut wide_sig, &mut self.exp, &self.sig, &rhs.sig, S::PRECISION);
-                self.sig = [wide_sig[0]];
-                let mut status;
-                self = unpack!(status=, self.normalize(round, loss));
-                if loss != Loss::ExactlyZero {
-                    status |= Status::INEXACT;
-                }
-                status.and(self)
-            }
-        }
-    }
-
-    fn mul_add_r(mut self, multiplicand: Self, addend: Self, round: Round) -> StatusAnd<Self> {
-        // If and only if all arguments are normal do we need to do an
-        // extended-precision calculation.
-        if !self.is_finite_non_zero() || !multiplicand.is_finite_non_zero() || !addend.is_finite() {
-            let mut status;
-            self = unpack!(status=, self.mul_r(multiplicand, round));
-
-            // FS can only be Status::OK or Status::INVALID_OP. There is no more work
-            // to do in the latter case. The IEEE-754R standard says it is
-            // implementation-defined in this case whether, if ADDEND is a
-            // quiet NaN, we raise invalid op; this implementation does so.
-            //
-            // If we need to do the addition we can do so with normal
-            // precision.
-            if status == Status::OK {
-                self = unpack!(status=, self.add_r(addend, round));
-            }
-            return status.and(self);
-        }
-
-        // Post-multiplication sign, before addition.
-        self.sign ^= multiplicand.sign;
-
-        // Allocate space for twice as many bits as the original significand, plus one
-        // extra bit for the addition to overflow into.
-        assert!(limbs_for_bits(S::PRECISION * 2 + 1) <= 2);
-        let mut wide_sig = sig::widening_mul(self.sig[0], multiplicand.sig[0]);
-
-        let mut loss = Loss::ExactlyZero;
-        let mut omsb = sig::omsb(&wide_sig);
-        self.exp += multiplicand.exp;
-
-        // Assume the operands involved in the multiplication are single-precision
-        // FP, and the two multiplicants are:
-        //     lhs = a23 . a22 ... a0 * 2^e1
-        //     rhs = b23 . b22 ... b0 * 2^e2
-        // the result of multiplication is:
-        //     lhs = c48 c47 c46 . c45 ... c0 * 2^(e1+e2)
-        // Note that there are three significant bits at the left-hand side of the
-        // radix point: two for the multiplication, and an overflow bit for the
-        // addition (that will always be zero at this point). Move the radix point
-        // toward left by two bits, and adjust exponent accordingly.
-        self.exp += 2;
-
-        if addend.is_non_zero() {
-            // Normalize our MSB to one below the top bit to allow for overflow.
-            let ext_precision = 2 * S::PRECISION + 1;
-            if omsb != ext_precision - 1 {
-                assert!(ext_precision > omsb);
-                sig::shift_left(&mut wide_sig, &mut self.exp, (ext_precision - 1) - omsb);
-            }
-
-            // The intermediate result of the multiplication has "2 * S::PRECISION"
-            // significant bit; adjust the addend to be consistent with mul result.
-            let mut ext_addend_sig = [addend.sig[0], 0];
-
-            // Extend the addend significand to ext_precision - 1. This guarantees
-            // that the high bit of the significand is zero (same as wide_sig),
-            // so the addition will overflow (if it does overflow at all) into the top bit.
-            sig::shift_left(&mut ext_addend_sig, &mut 0, ext_precision - 1 - S::PRECISION);
-            loss = sig::add_or_sub(
-                &mut wide_sig,
-                &mut self.exp,
-                &mut self.sign,
-                &mut ext_addend_sig,
-                addend.exp + 1,
-                addend.sign,
-            );
-
-            omsb = sig::omsb(&wide_sig);
-        }
-
-        // Convert the result having "2 * S::PRECISION" significant-bits back to the one
-        // having "S::PRECISION" significant-bits. First, move the radix point from
-        // position "2*S::PRECISION - 1" to "S::PRECISION - 1". The exponent need to be
-        // adjusted by "2*S::PRECISION - 1" - "S::PRECISION - 1" = "S::PRECISION".
-        self.exp -= S::PRECISION as ExpInt + 1;
-
-        // In case MSB resides at the left-hand side of radix point, shift the
-        // mantissa right by some amount to make sure the MSB reside right before
-        // the radix point (i.e., "MSB . rest-significant-bits").
-        if omsb > S::PRECISION {
-            let bits = omsb - S::PRECISION;
-            loss = sig::shift_right(&mut wide_sig, &mut self.exp, bits).combine(loss);
-        }
-
-        self.sig[0] = wide_sig[0];
-
-        let mut status;
-        self = unpack!(status=, self.normalize(round, loss));
-        if loss != Loss::ExactlyZero {
-            status |= Status::INEXACT;
-        }
-
-        // If two numbers add (exactly) to zero, IEEE 754 decrees it is a
-        // positive zero unless rounding to minus infinity, except that
-        // adding two like-signed zeroes gives that zero.
-        if self.category == Category::Zero
-            && !status.intersects(Status::UNDERFLOW)
-            && self.sign != addend.sign
-        {
-            self.sign = round == Round::TowardNegative;
-        }
-
-        status.and(self)
-    }
-
-    fn div_r(mut self, rhs: Self, round: Round) -> StatusAnd<Self> {
-        self.sign ^= rhs.sign;
-
-        match (self.category, rhs.category) {
-            (Category::NaN, _) => {
-                self.sign = false;
-                Status::OK.and(self)
-            }
-
-            (_, Category::NaN) => {
-                self.category = Category::NaN;
-                self.sig = rhs.sig;
-                self.sign = false;
-                Status::OK.and(self)
-            }
-
-            (Category::Infinity, Category::Infinity) | (Category::Zero, Category::Zero) => {
-                Status::INVALID_OP.and(Self::NAN)
-            }
-
-            (Category::Infinity | Category::Zero, _) => Status::OK.and(self),
-
-            (Category::Normal, Category::Infinity) => {
-                self.category = Category::Zero;
-                Status::OK.and(self)
-            }
-
-            (Category::Normal, Category::Zero) => {
-                self.category = Category::Infinity;
-                Status::DIV_BY_ZERO.and(self)
-            }
-
-            (Category::Normal, Category::Normal) => {
-                self.exp -= rhs.exp;
-                let dividend = self.sig[0];
-                let loss = sig::div(
-                    &mut self.sig,
-                    &mut self.exp,
-                    &mut [dividend],
-                    &mut [rhs.sig[0]],
-                    S::PRECISION,
-                );
-                let mut status;
-                self = unpack!(status=, self.normalize(round, loss));
-                if loss != Loss::ExactlyZero {
-                    status |= Status::INEXACT;
-                }
-                status.and(self)
-            }
-        }
-    }
-
-    fn c_fmod(mut self, rhs: Self) -> StatusAnd<Self> {
-        match (self.category, rhs.category) {
-            (Category::NaN, _)
-            | (Category::Zero, Category::Infinity | Category::Normal)
-            | (Category::Normal, Category::Infinity) => Status::OK.and(self),
-
-            (_, Category::NaN) => {
-                self.sign = false;
-                self.category = Category::NaN;
-                self.sig = rhs.sig;
-                Status::OK.and(self)
-            }
-
-            (Category::Infinity, _) | (_, Category::Zero) => Status::INVALID_OP.and(Self::NAN),
-
-            (Category::Normal, Category::Normal) => {
-                while self.is_finite_non_zero()
-                    && rhs.is_finite_non_zero()
-                    && self.cmp_abs_normal(rhs) != Ordering::Less
-                {
-                    let mut v = rhs.scalbn(self.ilogb() - rhs.ilogb());
-                    if self.cmp_abs_normal(v) == Ordering::Less {
-                        v = v.scalbn(-1);
-                    }
-                    v.sign = self.sign;
-
-                    let status;
-                    self = unpack!(status=, self - v);
-                    assert_eq!(status, Status::OK);
-                }
-                Status::OK.and(self)
-            }
-        }
-    }
-
-    fn round_to_integral(self, round: Round) -> StatusAnd<Self> {
-        // If the exponent is large enough, we know that this value is already
-        // integral, and the arithmetic below would potentially cause it to saturate
-        // to +/-Inf. Bail out early instead.
-        if self.is_finite_non_zero() && self.exp + 1 >= S::PRECISION as ExpInt {
-            return Status::OK.and(self);
-        }
-
-        // The algorithm here is quite simple: we add 2^(p-1), where p is the
-        // precision of our format, and then subtract it back off again. The choice
-        // of rounding modes for the addition/subtraction determines the rounding mode
-        // for our integral rounding as well.
-        // NOTE: When the input value is negative, we do subtraction followed by
-        // addition instead.
-        assert!(S::PRECISION <= 128);
-        let mut status;
-        let magic_const = unpack!(status=, Self::from_u128(1 << (S::PRECISION - 1)));
-        let magic_const = magic_const.copy_sign(self);
-
-        if status != Status::OK {
-            return status.and(self);
-        }
-
-        let mut r = self;
-        r = unpack!(status=, r.add_r(magic_const, round));
-        if status != Status::OK && status != Status::INEXACT {
-            return status.and(self);
-        }
-
-        // Restore the input sign to handle 0.0/-0.0 cases correctly.
-        r.sub_r(magic_const, round).map(|r| r.copy_sign(self))
-    }
-
-    fn next_up(mut self) -> StatusAnd<Self> {
-        // Compute nextUp(x), handling each float category separately.
-        match self.category {
-            Category::Infinity => {
-                if self.sign {
-                    // nextUp(-inf) = -largest
-                    Status::OK.and(-Self::largest())
-                } else {
-                    // nextUp(+inf) = +inf
-                    Status::OK.and(self)
-                }
-            }
-            Category::NaN => {
-                // IEEE-754R 2008 6.2 Par 2: nextUp(sNaN) = qNaN. Set Invalid flag.
-                // IEEE-754R 2008 6.2: nextUp(qNaN) = qNaN. Must be identity so we do not
-                //                     change the payload.
-                if self.is_signaling() {
-                    // For consistency, propagate the sign of the sNaN to the qNaN.
-                    Status::INVALID_OP.and(Self::NAN.copy_sign(self))
-                } else {
-                    Status::OK.and(self)
-                }
-            }
-            Category::Zero => {
-                // nextUp(pm 0) = +smallest
-                Status::OK.and(Self::SMALLEST)
-            }
-            Category::Normal => {
-                // nextUp(-smallest) = -0
-                if self.is_smallest() && self.sign {
-                    return Status::OK.and(-Self::ZERO);
-                }
-
-                // nextUp(largest) == INFINITY
-                if self.is_largest() && !self.sign {
-                    return Status::OK.and(Self::INFINITY);
-                }
-
-                // Excluding the integral bit. This allows us to test for binade boundaries.
-                let sig_mask = (1 << (S::PRECISION - 1)) - 1;
-
-                // nextUp(normal) == normal + inc.
-                if self.sign {
-                    // If we are negative, we need to decrement the significand.
-
-                    // We only cross a binade boundary that requires adjusting the exponent
-                    // if:
-                    //   1. exponent != S::MIN_EXP. This implies we are not in the
-                    //   smallest binade or are dealing with denormals.
-                    //   2. Our significand excluding the integral bit is all zeros.
-                    let crossing_binade_boundary =
-                        self.exp != S::MIN_EXP && self.sig[0] & sig_mask == 0;
-
-                    // Decrement the significand.
-                    //
-                    // We always do this since:
-                    //   1. If we are dealing with a non-binade decrement, by definition we
-                    //   just decrement the significand.
-                    //   2. If we are dealing with a normal -> normal binade decrement, since
-                    //   we have an explicit integral bit the fact that all bits but the
-                    //   integral bit are zero implies that subtracting one will yield a
-                    //   significand with 0 integral bit and 1 in all other spots. Thus we
-                    //   must just adjust the exponent and set the integral bit to 1.
-                    //   3. If we are dealing with a normal -> denormal binade decrement,
-                    //   since we set the integral bit to 0 when we represent denormals, we
-                    //   just decrement the significand.
-                    sig::decrement(&mut self.sig);
-
-                    if crossing_binade_boundary {
-                        // Our result is a normal number. Do the following:
-                        // 1. Set the integral bit to 1.
-                        // 2. Decrement the exponent.
-                        sig::set_bit(&mut self.sig, S::PRECISION - 1);
-                        self.exp -= 1;
-                    }
-                } else {
-                    // If we are positive, we need to increment the significand.
-
-                    // We only cross a binade boundary that requires adjusting the exponent if
-                    // the input is not a denormal and all of said input's significand bits
-                    // are set. If all of said conditions are true: clear the significand, set
-                    // the integral bit to 1, and increment the exponent. If we have a
-                    // denormal always increment since moving denormals and the numbers in the
-                    // smallest normal binade have the same exponent in our representation.
-                    let crossing_binade_boundary =
-                        !self.is_denormal() && self.sig[0] & sig_mask == sig_mask;
-
-                    if crossing_binade_boundary {
-                        self.sig = [0];
-                        sig::set_bit(&mut self.sig, S::PRECISION - 1);
-                        assert_ne!(
-                            self.exp,
-                            S::MAX_EXP,
-                            "We can not increment an exponent beyond the MAX_EXP \
-                             allowed by the given floating point semantics."
-                        );
-                        self.exp += 1;
-                    } else {
-                        sig::increment(&mut self.sig);
-                    }
-                }
-                Status::OK.and(self)
-            }
-        }
-    }
-
-    fn from_bits(input: u128) -> Self {
-        // Dispatch to semantics.
-        S::from_bits(input)
-    }
-
-    fn from_u128_r(input: u128, round: Round) -> StatusAnd<Self> {
-        IeeeFloat {
-            sig: [input],
-            exp: S::PRECISION as ExpInt - 1,
-            category: Category::Normal,
-            sign: false,
-            marker: PhantomData,
-        }
-        .normalize(round, Loss::ExactlyZero)
-    }
-
-    fn from_str_r(mut s: &str, mut round: Round) -> Result<StatusAnd<Self>, ParseError> {
-        if s.is_empty() {
-            return Err(ParseError("Invalid string length"));
-        }
-
-        // Handle special cases.
-        match s {
-            "inf" | "INFINITY" => return Ok(Status::OK.and(Self::INFINITY)),
-            "-inf" | "-INFINITY" => return Ok(Status::OK.and(-Self::INFINITY)),
-            "nan" | "NaN" => return Ok(Status::OK.and(Self::NAN)),
-            "-nan" | "-NaN" => return Ok(Status::OK.and(-Self::NAN)),
-            _ => {}
-        }
-
-        // Handle a leading minus sign.
-        let minus = s.starts_with('-');
-        if minus || s.starts_with('+') {
-            s = &s[1..];
-            if s.is_empty() {
-                return Err(ParseError("String has no digits"));
-            }
-        }
-
-        // Adjust the rounding mode for the absolute value below.
-        if minus {
-            round = -round;
-        }
-
-        let r = if s.starts_with("0x") || s.starts_with("0X") {
-            s = &s[2..];
-            if s.is_empty() {
-                return Err(ParseError("Invalid string"));
-            }
-            Self::from_hexadecimal_string(s, round)?
-        } else {
-            Self::from_decimal_string(s, round)?
-        };
-
-        Ok(r.map(|r| if minus { -r } else { r }))
-    }
-
-    fn to_bits(self) -> u128 {
-        // Dispatch to semantics.
-        S::to_bits(self)
-    }
-
-    fn to_u128_r(self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<u128> {
-        // The result of trying to convert a number too large.
-        let overflow = if self.sign {
-            // Negative numbers cannot be represented as unsigned.
-            0
-        } else {
-            // Largest unsigned integer of the given width.
-            !0 >> (128 - width)
-        };
-
-        *is_exact = false;
-
-        match self.category {
-            Category::NaN => Status::INVALID_OP.and(0),
-
-            Category::Infinity => Status::INVALID_OP.and(overflow),
-
-            Category::Zero => {
-                // Negative zero can't be represented as an int.
-                *is_exact = !self.sign;
-                Status::OK.and(0)
-            }
-
-            Category::Normal => {
-                let mut r = 0;
-
-                // Step 1: place our absolute value, with any fraction truncated, in
-                // the destination.
-                let truncated_bits = if self.exp < 0 {
-                    // Our absolute value is less than one; truncate everything.
-                    // For exponent -1 the integer bit represents .5, look at that.
-                    // For smaller exponents leftmost truncated bit is 0.
-                    S::PRECISION - 1 + (-self.exp) as usize
-                } else {
-                    // We want the most significant (exponent + 1) bits; the rest are
-                    // truncated.
-                    let bits = self.exp as usize + 1;
-
-                    // Hopelessly large in magnitude?
-                    if bits > width {
-                        return Status::INVALID_OP.and(overflow);
-                    }
-
-                    if bits < S::PRECISION {
-                        // We truncate (S::PRECISION - bits) bits.
-                        r = self.sig[0] >> (S::PRECISION - bits);
-                        S::PRECISION - bits
-                    } else {
-                        // We want at least as many bits as are available.
-                        r = self.sig[0] << (bits - S::PRECISION);
-                        0
-                    }
-                };
-
-                // Step 2: work out any lost fraction, and increment the absolute
-                // value if we would round away from zero.
-                let mut loss = Loss::ExactlyZero;
-                if truncated_bits > 0 {
-                    loss = Loss::through_truncation(&self.sig, truncated_bits);
-                    if loss != Loss::ExactlyZero
-                        && self.round_away_from_zero(round, loss, truncated_bits)
-                    {
-                        r = r.wrapping_add(1);
-                        if r == 0 {
-                            return Status::INVALID_OP.and(overflow); // Overflow.
-                        }
-                    }
-                }
-
-                // Step 3: check if we fit in the destination.
-                if r > overflow {
-                    return Status::INVALID_OP.and(overflow);
-                }
-
-                if loss == Loss::ExactlyZero {
-                    *is_exact = true;
-                    Status::OK.and(r)
-                } else {
-                    Status::INEXACT.and(r)
-                }
-            }
-        }
-    }
-
-    fn cmp_abs_normal(self, rhs: Self) -> Ordering {
-        assert!(self.is_finite_non_zero());
-        assert!(rhs.is_finite_non_zero());
-
-        // If exponents are equal, do an unsigned comparison of the significands.
-        self.exp.cmp(&rhs.exp).then_with(|| sig::cmp(&self.sig, &rhs.sig))
-    }
-
-    fn bitwise_eq(self, rhs: Self) -> bool {
-        if self.category != rhs.category || self.sign != rhs.sign {
-            return false;
-        }
-
-        if self.category == Category::Zero || self.category == Category::Infinity {
-            return true;
-        }
-
-        if self.is_finite_non_zero() && self.exp != rhs.exp {
-            return false;
-        }
-
-        self.sig == rhs.sig
-    }
-
-    fn is_negative(self) -> bool {
-        self.sign
-    }
-
-    fn is_denormal(self) -> bool {
-        self.is_finite_non_zero()
-            && self.exp == S::MIN_EXP
-            && !sig::get_bit(&self.sig, S::PRECISION - 1)
-    }
-
-    fn is_signaling(self) -> bool {
-        // IEEE-754R 2008 6.2.1: A signaling NaN bit string should be encoded with the
-        // first bit of the trailing significand being 0.
-        self.is_nan() && !sig::get_bit(&self.sig, S::QNAN_BIT)
-    }
-
-    fn category(self) -> Category {
-        self.category
-    }
-
-    fn get_exact_inverse(self) -> Option<Self> {
-        // Special floats and denormals have no exact inverse.
-        if !self.is_finite_non_zero() {
-            return None;
-        }
-
-        // Check that the number is a power of two by making sure that only the
-        // integer bit is set in the significand.
-        if self.sig != [1 << (S::PRECISION - 1)] {
-            return None;
-        }
-
-        // Get the inverse.
-        let mut reciprocal = Self::from_u128(1).value;
-        let status;
-        reciprocal = unpack!(status=, reciprocal / self);
-        if status != Status::OK {
-            return None;
-        }
-
-        // Avoid multiplication with a denormal, it is not safe on all platforms and
-        // may be slower than a normal division.
-        if reciprocal.is_denormal() {
-            return None;
-        }
-
-        assert!(reciprocal.is_finite_non_zero());
-        assert_eq!(reciprocal.sig, [1 << (S::PRECISION - 1)]);
-
-        Some(reciprocal)
-    }
-
-    fn ilogb(mut self) -> ExpInt {
-        if self.is_nan() {
-            return IEK_NAN;
-        }
-        if self.is_zero() {
-            return IEK_ZERO;
-        }
-        if self.is_infinite() {
-            return IEK_INF;
-        }
-        if !self.is_denormal() {
-            return self.exp;
-        }
-
-        let sig_bits = (S::PRECISION - 1) as ExpInt;
-        self.exp += sig_bits;
-        self = self.normalize(Round::NearestTiesToEven, Loss::ExactlyZero).value;
-        self.exp - sig_bits
-    }
-
-    fn scalbn_r(mut self, exp: ExpInt, round: Round) -> Self {
-        // If exp is wildly out-of-scale, simply adding it to self.exp will
-        // overflow; clamp it to a safe range before adding, but ensure that the range
-        // is large enough that the clamp does not change the result. The range we
-        // need to support is the difference between the largest possible exponent and
-        // the normalized exponent of half the smallest denormal.
-
-        let sig_bits = (S::PRECISION - 1) as i32;
-        let max_change = S::MAX_EXP as i32 - (S::MIN_EXP as i32 - sig_bits) + 1;
-
-        // Clamp to one past the range ends to let normalize handle overflow.
-        let exp_change = cmp::min(cmp::max(exp as i32, -max_change - 1), max_change);
-        self.exp = self.exp.saturating_add(exp_change as ExpInt);
-        self = self.normalize(round, Loss::ExactlyZero).value;
-        if self.is_nan() {
-            sig::set_bit(&mut self.sig, S::QNAN_BIT);
-        }
-        self
-    }
-
-    fn frexp_r(mut self, exp: &mut ExpInt, round: Round) -> Self {
-        *exp = self.ilogb();
-
-        // Quiet signalling nans.
-        if *exp == IEK_NAN {
-            sig::set_bit(&mut self.sig, S::QNAN_BIT);
-            return self;
-        }
-
-        if *exp == IEK_INF {
-            return self;
-        }
-
-        // 1 is added because frexp is defined to return a normalized fraction in
-        // +/-[0.5, 1.0), rather than the usual +/-[1.0, 2.0).
-        if *exp == IEK_ZERO {
-            *exp = 0;
-        } else {
-            *exp += 1;
-        }
-        self.scalbn_r(-*exp, round)
-    }
-}
-
-impl<S: Semantics, T: Semantics> FloatConvert<IeeeFloat<T>> for IeeeFloat<S> {
-    fn convert_r(self, round: Round, loses_info: &mut bool) -> StatusAnd<IeeeFloat<T>> {
-        let mut r = IeeeFloat {
-            sig: self.sig,
-            exp: self.exp,
-            category: self.category,
-            sign: self.sign,
-            marker: PhantomData,
-        };
-
-        // x86 has some unusual NaNs which cannot be represented in any other
-        // format; note them here.
-        fn is_x87_double_extended<S: Semantics>() -> bool {
-            S::QNAN_SIGNIFICAND == X87DoubleExtendedS::QNAN_SIGNIFICAND
-        }
-        let x87_special_nan = is_x87_double_extended::<S>()
-            && !is_x87_double_extended::<T>()
-            && r.category == Category::NaN
-            && (r.sig[0] & S::QNAN_SIGNIFICAND) != S::QNAN_SIGNIFICAND;
-
-        // If this is a truncation of a denormal number, and the target semantics
-        // has larger exponent range than the source semantics (this can happen
-        // when truncating from PowerPC double-double to double format), the
-        // right shift could lose result mantissa bits. Adjust exponent instead
-        // of performing excessive shift.
-        let mut shift = T::PRECISION as ExpInt - S::PRECISION as ExpInt;
-        if shift < 0 && r.is_finite_non_zero() {
-            let mut exp_change = sig::omsb(&r.sig) as ExpInt - S::PRECISION as ExpInt;
-            if r.exp + exp_change < T::MIN_EXP {
-                exp_change = T::MIN_EXP - r.exp;
-            }
-            if exp_change < shift {
-                exp_change = shift;
-            }
-            if exp_change < 0 {
-                shift -= exp_change;
-                r.exp += exp_change;
-            }
-        }
-
-        // If this is a truncation, perform the shift.
-        let loss = if shift < 0 && (r.is_finite_non_zero() || r.category == Category::NaN) {
-            sig::shift_right(&mut r.sig, &mut 0, -shift as usize)
-        } else {
-            Loss::ExactlyZero
-        };
-
-        // If this is an extension, perform the shift.
-        if shift > 0 && (r.is_finite_non_zero() || r.category == Category::NaN) {
-            sig::shift_left(&mut r.sig, &mut 0, shift as usize);
-        }
-
-        let status;
-        if r.is_finite_non_zero() {
-            r = unpack!(status=, r.normalize(round, loss));
-            *loses_info = status != Status::OK;
-        } else if r.category == Category::NaN {
-            *loses_info = loss != Loss::ExactlyZero || x87_special_nan;
-
-            // For x87 extended precision, we want to make a NaN, not a special NaN if
-            // the input wasn't special either.
-            if !x87_special_nan && is_x87_double_extended::<T>() {
-                sig::set_bit(&mut r.sig, T::PRECISION - 1);
-            }
-
-            // Convert of sNaN creates qNaN and raises an exception (invalid op).
-            // This also guarantees that a sNaN does not become Inf on a truncation
-            // that loses all payload bits.
-            if self.is_signaling() {
-                // Quiet signaling NaN.
-                sig::set_bit(&mut r.sig, T::QNAN_BIT);
-                status = Status::INVALID_OP;
-            } else {
-                status = Status::OK;
-            }
-        } else {
-            *loses_info = false;
-            status = Status::OK;
-        }
-
-        status.and(r)
-    }
-}
-
-impl<S: Semantics> IeeeFloat<S> {
-    /// Handle positive overflow. We either return infinity or
-    /// the largest finite number. For negative overflow,
-    /// negate the `round` argument before calling.
-    fn overflow_result(round: Round) -> StatusAnd<Self> {
-        match round {
-            // Infinity?
-            Round::NearestTiesToEven | Round::NearestTiesToAway | Round::TowardPositive => {
-                (Status::OVERFLOW | Status::INEXACT).and(Self::INFINITY)
-            }
-            // Otherwise we become the largest finite number.
-            Round::TowardNegative | Round::TowardZero => Status::INEXACT.and(Self::largest()),
-        }
-    }
-
-    /// Returns `true` if, when truncating the current number, with `bit` the
-    /// new LSB, with the given lost fraction and rounding mode, the result
-    /// would need to be rounded away from zero (i.e., by increasing the
-    /// signficand). This routine must work for `Category::Zero` of both signs, and
-    /// `Category::Normal` numbers.
-    fn round_away_from_zero(&self, round: Round, loss: Loss, bit: usize) -> bool {
-        // NaNs and infinities should not have lost fractions.
-        assert!(self.is_finite_non_zero() || self.is_zero());
-
-        // Current callers never pass this so we don't handle it.
-        assert_ne!(loss, Loss::ExactlyZero);
-
-        match round {
-            Round::NearestTiesToAway => loss == Loss::ExactlyHalf || loss == Loss::MoreThanHalf,
-            Round::NearestTiesToEven => {
-                if loss == Loss::MoreThanHalf {
-                    return true;
-                }
-
-                // Our zeros don't have a significand to test.
-                if loss == Loss::ExactlyHalf && self.category != Category::Zero {
-                    return sig::get_bit(&self.sig, bit);
-                }
-
-                false
-            }
-            Round::TowardZero => false,
-            Round::TowardPositive => !self.sign,
-            Round::TowardNegative => self.sign,
-        }
-    }
-
-    fn normalize(mut self, round: Round, mut loss: Loss) -> StatusAnd<Self> {
-        if !self.is_finite_non_zero() {
-            return Status::OK.and(self);
-        }
-
-        // Before rounding normalize the exponent of Category::Normal numbers.
-        let mut omsb = sig::omsb(&self.sig);
-
-        if omsb > 0 {
-            // OMSB is numbered from 1. We want to place it in the integer
-            // bit numbered PRECISION if possible, with a compensating change in
-            // the exponent.
-            let mut final_exp = self.exp.saturating_add(omsb as ExpInt - S::PRECISION as ExpInt);
-
-            // If the resulting exponent is too high, overflow according to
-            // the rounding mode.
-            if final_exp > S::MAX_EXP {
-                let round = if self.sign { -round } else { round };
-                return Self::overflow_result(round).map(|r| r.copy_sign(self));
-            }
-
-            // Subnormal numbers have exponent MIN_EXP, and their MSB
-            // is forced based on that.
-            if final_exp < S::MIN_EXP {
-                final_exp = S::MIN_EXP;
-            }
-
-            // Shifting left is easy as we don't lose precision.
-            if final_exp < self.exp {
-                assert_eq!(loss, Loss::ExactlyZero);
-
-                let exp_change = (self.exp - final_exp) as usize;
-                sig::shift_left(&mut self.sig, &mut self.exp, exp_change);
-
-                return Status::OK.and(self);
-            }
-
-            // Shift right and capture any new lost fraction.
-            if final_exp > self.exp {
-                let exp_change = (final_exp - self.exp) as usize;
-                loss = sig::shift_right(&mut self.sig, &mut self.exp, exp_change).combine(loss);
-
-                // Keep OMSB up-to-date.
-                omsb = omsb.saturating_sub(exp_change);
-            }
-        }
-
-        // Now round the number according to round given the lost
-        // fraction.
-
-        // As specified in IEEE 754, since we do not trap we do not report
-        // underflow for exact results.
-        if loss == Loss::ExactlyZero {
-            // Canonicalize zeros.
-            if omsb == 0 {
-                self.category = Category::Zero;
-            }
-
-            return Status::OK.and(self);
-        }
-
-        // Increment the significand if we're rounding away from zero.
-        if self.round_away_from_zero(round, loss, 0) {
-            if omsb == 0 {
-                self.exp = S::MIN_EXP;
-            }
-
-            // We should never overflow.
-            assert_eq!(sig::increment(&mut self.sig), 0);
-            omsb = sig::omsb(&self.sig);
-
-            // Did the significand increment overflow?
-            if omsb == S::PRECISION + 1 {
-                // Renormalize by incrementing the exponent and shifting our
-                // significand right one. However if we already have the
-                // maximum exponent we overflow to infinity.
-                if self.exp == S::MAX_EXP {
-                    self.category = Category::Infinity;
-
-                    return (Status::OVERFLOW | Status::INEXACT).and(self);
-                }
-
-                let _: Loss = sig::shift_right(&mut self.sig, &mut self.exp, 1);
-
-                return Status::INEXACT.and(self);
-            }
-        }
-
-        // The normal case - we were and are not denormal, and any
-        // significand increment above didn't overflow.
-        if omsb == S::PRECISION {
-            return Status::INEXACT.and(self);
-        }
-
-        // We have a non-zero denormal.
-        assert!(omsb < S::PRECISION);
-
-        // Canonicalize zeros.
-        if omsb == 0 {
-            self.category = Category::Zero;
-        }
-
-        // The Category::Zero case is a denormal that underflowed to zero.
-        (Status::UNDERFLOW | Status::INEXACT).and(self)
-    }
-
-    fn from_hexadecimal_string(s: &str, round: Round) -> Result<StatusAnd<Self>, ParseError> {
-        let mut r = IeeeFloat {
-            sig: [0],
-            exp: 0,
-            category: Category::Normal,
-            sign: false,
-            marker: PhantomData,
-        };
-
-        let mut any_digits = false;
-        let mut has_exp = false;
-        let mut bit_pos = LIMB_BITS as isize;
-        let mut loss = None;
-
-        // Without leading or trailing zeros, irrespective of the dot.
-        let mut first_sig_digit = None;
-        let mut dot = s.len();
-
-        for (p, c) in s.char_indices() {
-            // Skip leading zeros and any (hexa)decimal point.
-            if c == '.' {
-                if dot != s.len() {
-                    return Err(ParseError("String contains multiple dots"));
-                }
-                dot = p;
-            } else if let Some(hex_value) = c.to_digit(16) {
-                any_digits = true;
-
-                if first_sig_digit.is_none() {
-                    if hex_value == 0 {
-                        continue;
-                    }
-                    first_sig_digit = Some(p);
-                }
-
-                // Store the number while we have space.
-                bit_pos -= 4;
-                if bit_pos >= 0 {
-                    r.sig[0] |= (hex_value as Limb) << bit_pos;
-                // If zero or one-half (the hexadecimal digit 8) are followed
-                // by non-zero, they're a little more than zero or one-half.
-                } else if let Some(ref mut loss) = loss {
-                    if hex_value != 0 {
-                        if *loss == Loss::ExactlyZero {
-                            *loss = Loss::LessThanHalf;
-                        }
-                        if *loss == Loss::ExactlyHalf {
-                            *loss = Loss::MoreThanHalf;
-                        }
-                    }
-                } else {
-                    loss = Some(match hex_value {
-                        0 => Loss::ExactlyZero,
-                        1..=7 => Loss::LessThanHalf,
-                        8 => Loss::ExactlyHalf,
-                        9..=15 => Loss::MoreThanHalf,
-                        _ => unreachable!(),
-                    });
-                }
-            } else if c == 'p' || c == 'P' {
-                if !any_digits {
-                    return Err(ParseError("Significand has no digits"));
-                }
-
-                if dot == s.len() {
-                    dot = p;
-                }
-
-                let mut chars = s[p + 1..].chars().peekable();
-
-                // Adjust for the given exponent.
-                let exp_minus = chars.peek() == Some(&'-');
-                if exp_minus || chars.peek() == Some(&'+') {
-                    chars.next();
-                }
-
-                for c in chars {
-                    if let Some(value) = c.to_digit(10) {
-                        has_exp = true;
-                        r.exp = r.exp.saturating_mul(10).saturating_add(value as ExpInt);
-                    } else {
-                        return Err(ParseError("Invalid character in exponent"));
-                    }
-                }
-                if !has_exp {
-                    return Err(ParseError("Exponent has no digits"));
-                }
-
-                if exp_minus {
-                    r.exp = -r.exp;
-                }
-
-                break;
-            } else {
-                return Err(ParseError("Invalid character in significand"));
-            }
-        }
-        if !any_digits {
-            return Err(ParseError("Significand has no digits"));
-        }
-
-        // Hex floats require an exponent but not a hexadecimal point.
-        if !has_exp {
-            return Err(ParseError("Hex strings require an exponent"));
-        }
-
-        // Ignore the exponent if we are zero.
-        let first_sig_digit = match first_sig_digit {
-            Some(p) => p,
-            None => return Ok(Status::OK.and(Self::ZERO)),
-        };
-
-        // Calculate the exponent adjustment implicit in the number of
-        // significant digits and adjust for writing the significand starting
-        // at the most significant nibble.
-        let exp_adjustment = if dot > first_sig_digit {
-            ExpInt::try_from(dot - first_sig_digit).unwrap()
-        } else {
-            -ExpInt::try_from(first_sig_digit - dot - 1).unwrap()
-        };
-        let exp_adjustment = exp_adjustment
-            .saturating_mul(4)
-            .saturating_sub(1)
-            .saturating_add(S::PRECISION as ExpInt)
-            .saturating_sub(LIMB_BITS as ExpInt);
-        r.exp = r.exp.saturating_add(exp_adjustment);
-
-        Ok(r.normalize(round, loss.unwrap_or(Loss::ExactlyZero)))
-    }
-
-    fn from_decimal_string(s: &str, round: Round) -> Result<StatusAnd<Self>, ParseError> {
-        // Given a normal decimal floating point number of the form
-        //
-        //   dddd.dddd[eE][+-]ddd
-        //
-        // where the decimal point and exponent are optional, fill out the
-        // variables below. Exponent is appropriate if the significand is
-        // treated as an integer, and normalized_exp if the significand
-        // is taken to have the decimal point after a single leading
-        // non-zero digit.
-        //
-        // If the value is zero, first_sig_digit is None.
-
-        let mut any_digits = false;
-        let mut dec_exp = 0i32;
-
-        // Without leading or trailing zeros, irrespective of the dot.
-        let mut first_sig_digit = None;
-        let mut last_sig_digit = 0;
-        let mut dot = s.len();
-
-        for (p, c) in s.char_indices() {
-            if c == '.' {
-                if dot != s.len() {
-                    return Err(ParseError("String contains multiple dots"));
-                }
-                dot = p;
-            } else if let Some(dec_value) = c.to_digit(10) {
-                any_digits = true;
-
-                if dec_value != 0 {
-                    if first_sig_digit.is_none() {
-                        first_sig_digit = Some(p);
-                    }
-                    last_sig_digit = p;
-                }
-            } else if c == 'e' || c == 'E' {
-                if !any_digits {
-                    return Err(ParseError("Significand has no digits"));
-                }
-
-                if dot == s.len() {
-                    dot = p;
-                }
-
-                let mut chars = s[p + 1..].chars().peekable();
-
-                // Adjust for the given exponent.
-                let exp_minus = chars.peek() == Some(&'-');
-                if exp_minus || chars.peek() == Some(&'+') {
-                    chars.next();
-                }
-
-                any_digits = false;
-                for c in chars {
-                    if let Some(value) = c.to_digit(10) {
-                        any_digits = true;
-                        dec_exp = dec_exp.saturating_mul(10).saturating_add(value as i32);
-                    } else {
-                        return Err(ParseError("Invalid character in exponent"));
-                    }
-                }
-                if !any_digits {
-                    return Err(ParseError("Exponent has no digits"));
-                }
-
-                if exp_minus {
-                    dec_exp = -dec_exp;
-                }
-
-                break;
-            } else {
-                return Err(ParseError("Invalid character in significand"));
-            }
-        }
-        if !any_digits {
-            return Err(ParseError("Significand has no digits"));
-        }
-
-        // Test if we have a zero number allowing for non-zero exponents.
-        let first_sig_digit = match first_sig_digit {
-            Some(p) => p,
-            None => return Ok(Status::OK.and(Self::ZERO)),
-        };
-
-        // Adjust the exponents for any decimal point.
-        if dot > last_sig_digit {
-            dec_exp = dec_exp.saturating_add((dot - last_sig_digit - 1) as i32);
-        } else {
-            dec_exp = dec_exp.saturating_sub((last_sig_digit - dot) as i32);
-        }
-        let significand_digits = last_sig_digit - first_sig_digit + 1
-            - (dot > first_sig_digit && dot < last_sig_digit) as usize;
-        let normalized_exp = dec_exp.saturating_add(significand_digits as i32 - 1);
-
-        // Handle the cases where exponents are obviously too large or too
-        // small. Writing L for log 10 / log 2, a number d.ddddd*10^dec_exp
-        // definitely overflows if
-        //
-        //       (dec_exp - 1) * L >= MAX_EXP
-        //
-        // and definitely underflows to zero where
-        //
-        //       (dec_exp + 1) * L <= MIN_EXP - PRECISION
-        //
-        // With integer arithmetic the tightest bounds for L are
-        //
-        //       93/28 < L < 196/59            [ numerator <= 256 ]
-        //       42039/12655 < L < 28738/8651  [ numerator <= 65536 ]
-
-        // Check for MAX_EXP.
-        if normalized_exp.saturating_sub(1).saturating_mul(42039) >= 12655 * S::MAX_EXP as i32 {
-            // Overflow and round.
-            return Ok(Self::overflow_result(round));
-        }
-
-        // Check for MIN_EXP.
-        if normalized_exp.saturating_add(1).saturating_mul(28738)
-            <= 8651 * (S::MIN_EXP as i32 - S::PRECISION as i32)
-        {
-            // Underflow to zero and round.
-            let r =
-                if round == Round::TowardPositive { IeeeFloat::SMALLEST } else { IeeeFloat::ZERO };
-            return Ok((Status::UNDERFLOW | Status::INEXACT).and(r));
-        }
-
-        // A tight upper bound on number of bits required to hold an
-        // N-digit decimal integer is N * 196 / 59. Allocate enough space
-        // to hold the full significand, and an extra limb required by
-        // tcMultiplyPart.
-        let max_limbs = limbs_for_bits(1 + 196 * significand_digits / 59);
-        let mut dec_sig: SmallVec<[Limb; 1]> = SmallVec::with_capacity(max_limbs);
-
-        // Convert to binary efficiently - we do almost all multiplication
-        // in a Limb. When this would overflow do we do a single
-        // bignum multiplication, and then revert again to multiplication
-        // in a Limb.
-        let mut chars = s[first_sig_digit..=last_sig_digit].chars();
-        loop {
-            let mut val = 0;
-            let mut multiplier = 1;
-
-            loop {
-                let dec_value = match chars.next() {
-                    Some('.') => continue,
-                    Some(c) => c.to_digit(10).unwrap(),
-                    None => break,
-                };
-
-                multiplier *= 10;
-                val = val * 10 + dec_value as Limb;
-
-                // The maximum number that can be multiplied by ten with any
-                // digit added without overflowing a Limb.
-                if multiplier > (!0 - 9) / 10 {
-                    break;
-                }
-            }
-
-            // If we've consumed no digits, we're done.
-            if multiplier == 1 {
-                break;
-            }
-
-            // Multiply out the current limb.
-            let mut carry = val;
-            for x in &mut dec_sig {
-                let [low, mut high] = sig::widening_mul(*x, multiplier);
-
-                // Now add carry.
-                let (low, overflow) = low.overflowing_add(carry);
-                high += overflow as Limb;
-
-                *x = low;
-                carry = high;
-            }
-
-            // If we had carry, we need another limb (likely but not guaranteed).
-            if carry > 0 {
-                dec_sig.push(carry);
-            }
-        }
-
-        // Calculate pow(5, abs(dec_exp)) into `pow5_full`.
-        // The *_calc Vec's are reused scratch space, as an optimization.
-        let (pow5_full, mut pow5_calc, mut sig_calc, mut sig_scratch_calc) = {
-            let mut power = dec_exp.abs() as usize;
-
-            const FIRST_EIGHT_POWERS: [Limb; 8] = [1, 5, 25, 125, 625, 3125, 15625, 78125];
-
-            let mut p5_scratch = smallvec![];
-            let mut p5: SmallVec<[Limb; 1]> = smallvec![FIRST_EIGHT_POWERS[4]];
-
-            let mut r_scratch = smallvec![];
-            let mut r: SmallVec<[Limb; 1]> = smallvec![FIRST_EIGHT_POWERS[power & 7]];
-            power >>= 3;
-
-            while power > 0 {
-                // Calculate pow(5,pow(2,n+3)).
-                p5_scratch.resize(p5.len() * 2, 0);
-                let _: Loss = sig::mul(&mut p5_scratch, &mut 0, &p5, &p5, p5.len() * 2 * LIMB_BITS);
-                while p5_scratch.last() == Some(&0) {
-                    p5_scratch.pop();
-                }
-                mem::swap(&mut p5, &mut p5_scratch);
-
-                if power & 1 != 0 {
-                    r_scratch.resize(r.len() + p5.len(), 0);
-                    let _: Loss =
-                        sig::mul(&mut r_scratch, &mut 0, &r, &p5, (r.len() + p5.len()) * LIMB_BITS);
-                    while r_scratch.last() == Some(&0) {
-                        r_scratch.pop();
-                    }
-                    mem::swap(&mut r, &mut r_scratch);
-                }
-
-                power >>= 1;
-            }
-
-            (r, r_scratch, p5, p5_scratch)
-        };
-
-        // Attempt dec_sig * 10^dec_exp with increasing precision.
-        let mut attempt = 0;
-        loop {
-            let calc_precision = (LIMB_BITS << attempt) - 1;
-            attempt += 1;
-
-            let calc_normal_from_limbs = |sig: &mut SmallVec<[Limb; 1]>,
-                                          limbs: &[Limb]|
-             -> StatusAnd<ExpInt> {
-                sig.resize(limbs_for_bits(calc_precision), 0);
-                let (mut loss, mut exp) = sig::from_limbs(sig, limbs, calc_precision);
-
-                // Before rounding normalize the exponent of Category::Normal numbers.
-                let mut omsb = sig::omsb(sig);
-
-                assert_ne!(omsb, 0);
-
-                // OMSB is numbered from 1. We want to place it in the integer
-                // bit numbered PRECISION if possible, with a compensating change in
-                // the exponent.
-                let final_exp = exp.saturating_add(omsb as ExpInt - calc_precision as ExpInt);
-
-                // Shifting left is easy as we don't lose precision.
-                if final_exp < exp {
-                    assert_eq!(loss, Loss::ExactlyZero);
-
-                    let exp_change = (exp - final_exp) as usize;
-                    sig::shift_left(sig, &mut exp, exp_change);
-
-                    return Status::OK.and(exp);
-                }
-
-                // Shift right and capture any new lost fraction.
-                if final_exp > exp {
-                    let exp_change = (final_exp - exp) as usize;
-                    loss = sig::shift_right(sig, &mut exp, exp_change).combine(loss);
-
-                    // Keep OMSB up-to-date.
-                    omsb = omsb.saturating_sub(exp_change);
-                }
-
-                assert_eq!(omsb, calc_precision);
-
-                // Now round the number according to round given the lost
-                // fraction.
-
-                // As specified in IEEE 754, since we do not trap we do not report
-                // underflow for exact results.
-                if loss == Loss::ExactlyZero {
-                    return Status::OK.and(exp);
-                }
-
-                // Increment the significand if we're rounding away from zero.
-                if loss == Loss::MoreThanHalf || loss == Loss::ExactlyHalf && sig::get_bit(sig, 0) {
-                    // We should never overflow.
-                    assert_eq!(sig::increment(sig), 0);
-                    omsb = sig::omsb(sig);
-
-                    // Did the significand increment overflow?
-                    if omsb == calc_precision + 1 {
-                        let _: Loss = sig::shift_right(sig, &mut exp, 1);
-
-                        return Status::INEXACT.and(exp);
-                    }
-                }
-
-                // The normal case - we were and are not denormal, and any
-                // significand increment above didn't overflow.
-                Status::INEXACT.and(exp)
-            };
-
-            let status;
-            let mut exp = unpack!(status=,
-                calc_normal_from_limbs(&mut sig_calc, &dec_sig));
-            let pow5_status;
-            let pow5_exp = unpack!(pow5_status=,
-                calc_normal_from_limbs(&mut pow5_calc, &pow5_full));
-
-            // Add dec_exp, as 10^n = 5^n * 2^n.
-            exp += dec_exp as ExpInt;
-
-            let mut used_bits = S::PRECISION;
-            let mut truncated_bits = calc_precision - used_bits;
-
-            let half_ulp_err1 = (status != Status::OK) as Limb;
-            let (calc_loss, half_ulp_err2);
-            if dec_exp >= 0 {
-                exp += pow5_exp;
-
-                sig_scratch_calc.resize(sig_calc.len() + pow5_calc.len(), 0);
-                calc_loss = sig::mul(
-                    &mut sig_scratch_calc,
-                    &mut exp,
-                    &sig_calc,
-                    &pow5_calc,
-                    calc_precision,
-                );
-                mem::swap(&mut sig_calc, &mut sig_scratch_calc);
-
-                half_ulp_err2 = (pow5_status != Status::OK) as Limb;
-            } else {
-                exp -= pow5_exp;
-
-                sig_scratch_calc.resize(sig_calc.len(), 0);
-                calc_loss = sig::div(
-                    &mut sig_scratch_calc,
-                    &mut exp,
-                    &mut sig_calc,
-                    &mut pow5_calc,
-                    calc_precision,
-                );
-                mem::swap(&mut sig_calc, &mut sig_scratch_calc);
-
-                // Denormal numbers have less precision.
-                if exp < S::MIN_EXP {
-                    truncated_bits += (S::MIN_EXP - exp) as usize;
-                    used_bits = calc_precision.saturating_sub(truncated_bits);
-                }
-                // Extra half-ulp lost in reciprocal of exponent.
-                half_ulp_err2 =
-                    2 * (pow5_status != Status::OK || calc_loss != Loss::ExactlyZero) as Limb;
-            }
-
-            // Both sig::mul and sig::div return the
-            // result with the integer bit set.
-            assert!(sig::get_bit(&sig_calc, calc_precision - 1));
-
-            // The error from the true value, in half-ulps, on multiplying two
-            // floating point numbers, which differ from the value they
-            // approximate by at most half_ulp_err1 and half_ulp_err2 half-ulps, is strictly less
-            // than the returned value.
-            //
-            // See "How to Read Floating Point Numbers Accurately" by William D Clinger.
-            assert!(half_ulp_err1 < 2 || half_ulp_err2 < 2 || (half_ulp_err1 + half_ulp_err2 < 8));
-
-            let inexact = (calc_loss != Loss::ExactlyZero) as Limb;
-            let half_ulp_err = if half_ulp_err1 + half_ulp_err2 == 0 {
-                inexact * 2 // <= inexact half-ulps.
-            } else {
-                inexact + 2 * (half_ulp_err1 + half_ulp_err2)
-            };
-
-            let ulps_from_boundary = {
-                let bits = calc_precision - used_bits - 1;
-
-                let i = bits / LIMB_BITS;
-                let limb = sig_calc[i] & (!0 >> (LIMB_BITS - 1 - bits % LIMB_BITS));
-                let boundary = match round {
-                    Round::NearestTiesToEven | Round::NearestTiesToAway => 1 << (bits % LIMB_BITS),
-                    _ => 0,
-                };
-                if i == 0 {
-                    let delta = limb.wrapping_sub(boundary);
-                    cmp::min(delta, delta.wrapping_neg())
-                } else if limb == boundary {
-                    if !sig::is_all_zeros(&sig_calc[1..i]) {
-                        !0 // A lot.
-                    } else {
-                        sig_calc[0]
-                    }
-                } else if limb == boundary.wrapping_sub(1) {
-                    if sig_calc[1..i].iter().any(|&x| x.wrapping_neg() != 1) {
-                        !0 // A lot.
-                    } else {
-                        sig_calc[0].wrapping_neg()
-                    }
-                } else {
-                    !0 // A lot.
-                }
-            };
-
-            // Are we guaranteed to round correctly if we truncate?
-            if ulps_from_boundary.saturating_mul(2) >= half_ulp_err {
-                let mut r = IeeeFloat {
-                    sig: [0],
-                    exp,
-                    category: Category::Normal,
-                    sign: false,
-                    marker: PhantomData,
-                };
-                sig::extract(&mut r.sig, &sig_calc, used_bits, calc_precision - used_bits);
-                // If we extracted less bits above we must adjust our exponent
-                // to compensate for the implicit right shift.
-                r.exp += (S::PRECISION - used_bits) as ExpInt;
-                let loss = Loss::through_truncation(&sig_calc, truncated_bits);
-                return Ok(r.normalize(round, loss));
-            }
-        }
-    }
-}
-
-impl Loss {
-    /// Combine the effect of two lost fractions.
-    fn combine(self, less_significant: Loss) -> Loss {
-        let mut more_significant = self;
-        if less_significant != Loss::ExactlyZero {
-            if more_significant == Loss::ExactlyZero {
-                more_significant = Loss::LessThanHalf;
-            } else if more_significant == Loss::ExactlyHalf {
-                more_significant = Loss::MoreThanHalf;
-            }
-        }
-
-        more_significant
-    }
-
-    /// Returns the fraction lost were a bignum truncated losing the least
-    /// significant `bits` bits.
-    fn through_truncation(limbs: &[Limb], bits: usize) -> Loss {
-        if bits == 0 {
-            return Loss::ExactlyZero;
-        }
-
-        let half_bit = bits - 1;
-        let half_limb = half_bit / LIMB_BITS;
-        let (half_limb, rest) = if half_limb < limbs.len() {
-            (limbs[half_limb], &limbs[..half_limb])
-        } else {
-            (0, limbs)
-        };
-        let half = 1 << (half_bit % LIMB_BITS);
-        let has_half = half_limb & half != 0;
-        let has_rest = half_limb & (half - 1) != 0 || !sig::is_all_zeros(rest);
-
-        match (has_half, has_rest) {
-            (false, false) => Loss::ExactlyZero,
-            (false, true) => Loss::LessThanHalf,
-            (true, false) => Loss::ExactlyHalf,
-            (true, true) => Loss::MoreThanHalf,
-        }
-    }
-}
-
-/// Implementation details of IeeeFloat significands, such as big integer arithmetic.
-/// As a rule of thumb, no functions in this module should dynamically allocate.
-mod sig {
-    use super::{limbs_for_bits, ExpInt, Limb, Loss, LIMB_BITS};
-    use core::cmp::Ordering;
-    use core::iter;
-    use core::mem;
-
-    pub(super) fn is_all_zeros(limbs: &[Limb]) -> bool {
-        limbs.iter().all(|&l| l == 0)
-    }
-
-    /// One, not zero, based LSB. That is, returns 0 for a zeroed significand.
-    pub(super) fn olsb(limbs: &[Limb]) -> usize {
-        limbs
-            .iter()
-            .enumerate()
-            .find(|(_, &limb)| limb != 0)
-            .map_or(0, |(i, limb)| i * LIMB_BITS + limb.trailing_zeros() as usize + 1)
-    }
-
-    /// One, not zero, based MSB. That is, returns 0 for a zeroed significand.
-    pub(super) fn omsb(limbs: &[Limb]) -> usize {
-        limbs
-            .iter()
-            .enumerate()
-            .rfind(|(_, &limb)| limb != 0)
-            .map_or(0, |(i, limb)| (i + 1) * LIMB_BITS - limb.leading_zeros() as usize)
-    }
-
-    /// Comparison (unsigned) of two significands.
-    pub(super) fn cmp(a: &[Limb], b: &[Limb]) -> Ordering {
-        assert_eq!(a.len(), b.len());
-        for (a, b) in a.iter().zip(b).rev() {
-            match a.cmp(b) {
-                Ordering::Equal => {}
-                o => return o,
-            }
-        }
-
-        Ordering::Equal
-    }
-
-    /// Extracts the given bit.
-    pub(super) fn get_bit(limbs: &[Limb], bit: usize) -> bool {
-        limbs[bit / LIMB_BITS] & (1 << (bit % LIMB_BITS)) != 0
-    }
-
-    /// Sets the given bit.
-    pub(super) fn set_bit(limbs: &mut [Limb], bit: usize) {
-        limbs[bit / LIMB_BITS] |= 1 << (bit % LIMB_BITS);
-    }
-
-    /// Clear the given bit.
-    pub(super) fn clear_bit(limbs: &mut [Limb], bit: usize) {
-        limbs[bit / LIMB_BITS] &= !(1 << (bit % LIMB_BITS));
-    }
-
-    /// Shifts `dst` left `bits` bits, subtract `bits` from its exponent.
-    pub(super) fn shift_left(dst: &mut [Limb], exp: &mut ExpInt, bits: usize) {
-        if bits > 0 {
-            // Our exponent should not underflow.
-            *exp = exp.checked_sub(bits as ExpInt).unwrap();
-
-            // Jump is the inter-limb jump; shift is the intra-limb shift.
-            let jump = bits / LIMB_BITS;
-            let shift = bits % LIMB_BITS;
-
-            for i in (0..dst.len()).rev() {
-                let mut limb;
-
-                if i < jump {
-                    limb = 0;
-                } else {
-                    // dst[i] comes from the two limbs src[i - jump] and, if we have
-                    // an intra-limb shift, src[i - jump - 1].
-                    limb = dst[i - jump];
-                    if shift > 0 {
-                        limb <<= shift;
-                        if i > jump {
-                            limb |= dst[i - jump - 1] >> (LIMB_BITS - shift);
-                        }
-                    }
-                }
-
-                dst[i] = limb;
-            }
-        }
-    }
-
-    /// Shifts `dst` right `bits` bits noting lost fraction.
-    pub(super) fn shift_right(dst: &mut [Limb], exp: &mut ExpInt, bits: usize) -> Loss {
-        let loss = Loss::through_truncation(dst, bits);
-
-        if bits > 0 {
-            // Our exponent should not overflow.
-            *exp = exp.checked_add(bits as ExpInt).unwrap();
-
-            // Jump is the inter-limb jump; shift is the intra-limb shift.
-            let jump = bits / LIMB_BITS;
-            let shift = bits % LIMB_BITS;
-
-            // Perform the shift. This leaves the most significant `bits` bits
-            // of the result at zero.
-            for i in 0..dst.len() {
-                let mut limb;
-
-                if i + jump >= dst.len() {
-                    limb = 0;
-                } else {
-                    limb = dst[i + jump];
-                    if shift > 0 {
-                        limb >>= shift;
-                        if i + jump + 1 < dst.len() {
-                            limb |= dst[i + jump + 1] << (LIMB_BITS - shift);
-                        }
-                    }
-                }
-
-                dst[i] = limb;
-            }
-        }
-
-        loss
-    }
-
-    /// Copies the bit vector of width `src_bits` from `src`, starting at bit SRC_LSB,
-    /// to `dst`, such that the bit SRC_LSB becomes the least significant bit of `dst`.
-    /// All high bits above `src_bits` in `dst` are zero-filled.
-    pub(super) fn extract(dst: &mut [Limb], src: &[Limb], src_bits: usize, src_lsb: usize) {
-        if src_bits == 0 {
-            return;
-        }
-
-        let dst_limbs = limbs_for_bits(src_bits);
-        assert!(dst_limbs <= dst.len());
-
-        let src = &src[src_lsb / LIMB_BITS..];
-        dst[..dst_limbs].copy_from_slice(&src[..dst_limbs]);
-
-        let shift = src_lsb % LIMB_BITS;
-        let _: Loss = shift_right(&mut dst[..dst_limbs], &mut 0, shift);
-
-        // We now have (dst_limbs * LIMB_BITS - shift) bits from `src`
-        // in `dst`.  If this is less that src_bits, append the rest, else
-        // clear the high bits.
-        let n = dst_limbs * LIMB_BITS - shift;
-        if n < src_bits {
-            let mask = (1 << (src_bits - n)) - 1;
-            dst[dst_limbs - 1] |= (src[dst_limbs] & mask) << (n % LIMB_BITS);
-        } else if n > src_bits && src_bits % LIMB_BITS > 0 {
-            dst[dst_limbs - 1] &= (1 << (src_bits % LIMB_BITS)) - 1;
-        }
-
-        // Clear high limbs.
-        for x in &mut dst[dst_limbs..] {
-            *x = 0;
-        }
-    }
-
-    /// We want the most significant PRECISION bits of `src`. There may not
-    /// be that many; extract what we can.
-    pub(super) fn from_limbs(dst: &mut [Limb], src: &[Limb], precision: usize) -> (Loss, ExpInt) {
-        let omsb = omsb(src);
-
-        if precision <= omsb {
-            extract(dst, src, precision, omsb - precision);
-            (Loss::through_truncation(src, omsb - precision), omsb as ExpInt - 1)
-        } else {
-            extract(dst, src, omsb, 0);
-            (Loss::ExactlyZero, precision as ExpInt - 1)
-        }
-    }
-
-    /// For every consecutive chunk of `bits` bits from `limbs`,
-    /// going from most significant to the least significant bits,
-    /// call `f` to transform those bits and store the result back.
-    pub(super) fn each_chunk<F: FnMut(Limb) -> Limb>(limbs: &mut [Limb], bits: usize, mut f: F) {
-        assert_eq!(LIMB_BITS % bits, 0);
-        for limb in limbs.iter_mut().rev() {
-            let mut r = 0;
-            for i in (0..LIMB_BITS / bits).rev() {
-                r |= f((*limb >> (i * bits)) & ((1 << bits) - 1)) << (i * bits);
-            }
-            *limb = r;
-        }
-    }
-
-    /// Increment in-place, return the carry flag.
-    pub(super) fn increment(dst: &mut [Limb]) -> Limb {
-        for x in dst {
-            *x = x.wrapping_add(1);
-            if *x != 0 {
-                return 0;
-            }
-        }
-
-        1
-    }
-
-    /// Decrement in-place, return the borrow flag.
-    pub(super) fn decrement(dst: &mut [Limb]) -> Limb {
-        for x in dst {
-            *x = x.wrapping_sub(1);
-            if *x != !0 {
-                return 0;
-            }
-        }
-
-        1
-    }
-
-    /// `a += b + c` where `c` is zero or one. Returns the carry flag.
-    pub(super) fn add(a: &mut [Limb], b: &[Limb], mut c: Limb) -> Limb {
-        assert!(c <= 1);
-
-        for (a, &b) in iter::zip(a, b) {
-            let (r, overflow) = a.overflowing_add(b);
-            let (r, overflow2) = r.overflowing_add(c);
-            *a = r;
-            c = (overflow | overflow2) as Limb;
-        }
-
-        c
-    }
-
-    /// `a -= b + c` where `c` is zero or one. Returns the borrow flag.
-    pub(super) fn sub(a: &mut [Limb], b: &[Limb], mut c: Limb) -> Limb {
-        assert!(c <= 1);
-
-        for (a, &b) in iter::zip(a, b) {
-            let (r, overflow) = a.overflowing_sub(b);
-            let (r, overflow2) = r.overflowing_sub(c);
-            *a = r;
-            c = (overflow | overflow2) as Limb;
-        }
-
-        c
-    }
-
-    /// `a += b` or `a -= b`. Does not preserve `b`.
-    pub(super) fn add_or_sub(
-        a_sig: &mut [Limb],
-        a_exp: &mut ExpInt,
-        a_sign: &mut bool,
-        b_sig: &mut [Limb],
-        b_exp: ExpInt,
-        b_sign: bool,
-    ) -> Loss {
-        // Are we bigger exponent-wise than the RHS?
-        let bits = *a_exp - b_exp;
-
-        // Determine if the operation on the absolute values is effectively
-        // an addition or subtraction.
-        // Subtraction is more subtle than one might naively expect.
-        if *a_sign ^ b_sign {
-            let (reverse, loss);
-
-            if bits == 0 {
-                reverse = cmp(a_sig, b_sig) == Ordering::Less;
-                loss = Loss::ExactlyZero;
-            } else if bits > 0 {
-                loss = shift_right(b_sig, &mut 0, (bits - 1) as usize);
-                shift_left(a_sig, a_exp, 1);
-                reverse = false;
-            } else {
-                loss = shift_right(a_sig, a_exp, (-bits - 1) as usize);
-                shift_left(b_sig, &mut 0, 1);
-                reverse = true;
-            }
-
-            let borrow = (loss != Loss::ExactlyZero) as Limb;
-            if reverse {
-                // The code above is intended to ensure that no borrow is necessary.
-                assert_eq!(sub(b_sig, a_sig, borrow), 0);
-                a_sig.copy_from_slice(b_sig);
-                *a_sign = !*a_sign;
-            } else {
-                // The code above is intended to ensure that no borrow is necessary.
-                assert_eq!(sub(a_sig, b_sig, borrow), 0);
-            }
-
-            // Invert the lost fraction - it was on the RHS and subtracted.
-            match loss {
-                Loss::LessThanHalf => Loss::MoreThanHalf,
-                Loss::MoreThanHalf => Loss::LessThanHalf,
-                _ => loss,
-            }
-        } else {
-            let loss = if bits > 0 {
-                shift_right(b_sig, &mut 0, bits as usize)
-            } else {
-                shift_right(a_sig, a_exp, -bits as usize)
-            };
-            // We have a guard bit; generating a carry cannot happen.
-            assert_eq!(add(a_sig, b_sig, 0), 0);
-            loss
-        }
-    }
-
-    /// `[low, high] = a * b`.
-    ///
-    /// This cannot overflow, because
-    ///
-    /// `(n - 1) * (n - 1) + 2 * (n - 1) == (n - 1) * (n + 1)`
-    ///
-    /// which is less than n<sup>2</sup>.
-    pub(super) fn widening_mul(a: Limb, b: Limb) -> [Limb; 2] {
-        let mut wide = [0, 0];
-
-        if a == 0 || b == 0 {
-            return wide;
-        }
-
-        const HALF_BITS: usize = LIMB_BITS / 2;
-
-        let select = |limb, i| (limb >> (i * HALF_BITS)) & ((1 << HALF_BITS) - 1);
-        for i in 0..2 {
-            for j in 0..2 {
-                let mut x = [select(a, i) * select(b, j), 0];
-                shift_left(&mut x, &mut 0, (i + j) * HALF_BITS);
-                assert_eq!(add(&mut wide, &x, 0), 0);
-            }
-        }
-
-        wide
-    }
-
-    /// `dst = a * b` (for normal `a` and `b`). Returns the lost fraction.
-    pub(super) fn mul<'a>(
-        dst: &mut [Limb],
-        exp: &mut ExpInt,
-        mut a: &'a [Limb],
-        mut b: &'a [Limb],
-        precision: usize,
-    ) -> Loss {
-        // Put the narrower number on the `a` for less loops below.
-        if a.len() > b.len() {
-            mem::swap(&mut a, &mut b);
-        }
-
-        for x in &mut dst[..b.len()] {
-            *x = 0;
-        }
-
-        for i in 0..a.len() {
-            let mut carry = 0;
-            for j in 0..b.len() {
-                let [low, mut high] = widening_mul(a[i], b[j]);
-
-                // Now add carry.
-                let (low, overflow) = low.overflowing_add(carry);
-                high += overflow as Limb;
-
-                // And now `dst[i + j]`, and store the new low part there.
-                let (low, overflow) = low.overflowing_add(dst[i + j]);
-                high += overflow as Limb;
-
-                dst[i + j] = low;
-                carry = high;
-            }
-            dst[i + b.len()] = carry;
-        }
-
-        // Assume the operands involved in the multiplication are single-precision
-        // FP, and the two multiplicants are:
-        //     a = a23 . a22 ... a0 * 2^e1
-        //     b = b23 . b22 ... b0 * 2^e2
-        // the result of multiplication is:
-        //     dst = c48 c47 c46 . c45 ... c0 * 2^(e1+e2)
-        // Note that there are three significant bits at the left-hand side of the
-        // radix point: two for the multiplication, and an overflow bit for the
-        // addition (that will always be zero at this point). Move the radix point
-        // toward left by two bits, and adjust exponent accordingly.
-        *exp += 2;
-
-        // Convert the result having "2 * precision" significant-bits back to the one
-        // having "precision" significant-bits. First, move the radix point from
-        // poision "2*precision - 1" to "precision - 1". The exponent need to be
-        // adjusted by "2*precision - 1" - "precision - 1" = "precision".
-        *exp -= precision as ExpInt + 1;
-
-        // In case MSB resides at the left-hand side of radix point, shift the
-        // mantissa right by some amount to make sure the MSB reside right before
-        // the radix point (i.e., "MSB . rest-significant-bits").
-        //
-        // Note that the result is not normalized when "omsb < precision". So, the
-        // caller needs to call IeeeFloat::normalize() if normalized value is
-        // expected.
-        let omsb = omsb(dst);
-        if omsb <= precision { Loss::ExactlyZero } else { shift_right(dst, exp, omsb - precision) }
-    }
-
-    /// `quotient = dividend / divisor`. Returns the lost fraction.
-    /// Does not preserve `dividend` or `divisor`.
-    pub(super) fn div(
-        quotient: &mut [Limb],
-        exp: &mut ExpInt,
-        dividend: &mut [Limb],
-        divisor: &mut [Limb],
-        precision: usize,
-    ) -> Loss {
-        // Normalize the divisor.
-        let bits = precision - omsb(divisor);
-        shift_left(divisor, &mut 0, bits);
-        *exp += bits as ExpInt;
-
-        // Normalize the dividend.
-        let bits = precision - omsb(dividend);
-        shift_left(dividend, exp, bits);
-
-        // Division by 1.
-        let olsb_divisor = olsb(divisor);
-        if olsb_divisor == precision {
-            quotient.copy_from_slice(dividend);
-            return Loss::ExactlyZero;
-        }
-
-        // Ensure the dividend >= divisor initially for the loop below.
-        // Incidentally, this means that the division loop below is
-        // guaranteed to set the integer bit to one.
-        if cmp(dividend, divisor) == Ordering::Less {
-            shift_left(dividend, exp, 1);
-            assert_ne!(cmp(dividend, divisor), Ordering::Less)
-        }
-
-        // Helper for figuring out the lost fraction.
-        let lost_fraction = |dividend: &[Limb], divisor: &[Limb]| match cmp(dividend, divisor) {
-            Ordering::Greater => Loss::MoreThanHalf,
-            Ordering::Equal => Loss::ExactlyHalf,
-            Ordering::Less => {
-                if is_all_zeros(dividend) {
-                    Loss::ExactlyZero
-                } else {
-                    Loss::LessThanHalf
-                }
-            }
-        };
-
-        // Try to perform a (much faster) short division for small divisors.
-        let divisor_bits = precision - (olsb_divisor - 1);
-        macro_rules! try_short_div {
-            ($W:ty, $H:ty, $half:expr) => {
-                if divisor_bits * 2 <= $half {
-                    // Extract the small divisor.
-                    let _: Loss = shift_right(divisor, &mut 0, olsb_divisor - 1);
-                    let divisor = divisor[0] as $H as $W;
-
-                    // Shift the dividend to produce a quotient with the unit bit set.
-                    let top_limb = *dividend.last().unwrap();
-                    let mut rem = (top_limb >> (LIMB_BITS - (divisor_bits - 1))) as $H;
-                    shift_left(dividend, &mut 0, divisor_bits - 1);
-
-                    // Apply short division in place on $H (of $half bits) chunks.
-                    each_chunk(dividend, $half, |chunk| {
-                        let chunk = chunk as $H;
-                        let combined = ((rem as $W) << $half) | (chunk as $W);
-                        rem = (combined % divisor) as $H;
-                        (combined / divisor) as $H as Limb
-                    });
-                    quotient.copy_from_slice(dividend);
-
-                    return lost_fraction(&[(rem as Limb) << 1], &[divisor as Limb]);
-                }
-            };
-        }
-
-        try_short_div!(u32, u16, 16);
-        try_short_div!(u64, u32, 32);
-        try_short_div!(u128, u64, 64);
-
-        // Zero the quotient before setting bits in it.
-        for x in &mut quotient[..limbs_for_bits(precision)] {
-            *x = 0;
-        }
-
-        // Long division.
-        for bit in (0..precision).rev() {
-            if cmp(dividend, divisor) != Ordering::Less {
-                sub(dividend, divisor, 0);
-                set_bit(quotient, bit);
-            }
-            shift_left(dividend, &mut 0, 1);
-        }
-
-        lost_fraction(dividend, divisor)
-    }
-}
diff --git a/compiler/rustc_apfloat/src/lib.rs b/compiler/rustc_apfloat/src/lib.rs
deleted file mode 100644
index dde368e7b92..00000000000
--- a/compiler/rustc_apfloat/src/lib.rs
+++ /dev/null
@@ -1,695 +0,0 @@
-//! Port of LLVM's APFloat software floating-point implementation from the
-//! following C++ sources (please update commit hash when backporting):
-//! <https://github.com/llvm-mirror/llvm/tree/23efab2bbd424ed13495a420ad8641cb2c6c28f9>
-//!
-//! * `include/llvm/ADT/APFloat.h` -> `Float` and `FloatConvert` traits
-//! * `lib/Support/APFloat.cpp` -> `ieee` and `ppc` modules
-//! * `unittests/ADT/APFloatTest.cpp` -> `tests` directory
-//!
-//! The port contains no unsafe code, global state, or side-effects in general,
-//! and the only allocations are in the conversion to/from decimal strings.
-//!
-//! Most of the API and the testcases are intact in some form or another,
-//! with some ergonomic changes, such as idiomatic short names, returning
-//! new values instead of mutating the receiver, and having separate method
-//! variants that take a non-default rounding mode (with the suffix `_r`).
-//! Comments have been preserved where possible, only slightly adapted.
-//!
-//! Instead of keeping a pointer to a configuration struct and inspecting it
-//! dynamically on every operation, types (e.g., `ieee::Double`), traits
-//! (e.g., `ieee::Semantics`) and associated constants are employed for
-//! increased type safety and performance.
-//!
-//! On-heap bigints are replaced everywhere (except in decimal conversion),
-//! with short arrays of `type Limb = u128` elements (instead of `u64`),
-//! This allows fitting the largest supported significands in one integer
-//! (`ieee::Quad` and `ppc::Fallback` use slightly less than 128 bits).
-//! All of the functions in the `ieee::sig` module operate on slices.
-//!
-//! # Note
-//!
-//! This API is completely unstable and subject to change.
-
-#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![no_std]
-#![forbid(unsafe_code)]
-#![deny(rustc::untranslatable_diagnostic)]
-#![deny(rustc::diagnostic_outside_of_impl)]
-
-#[macro_use]
-extern crate alloc;
-
-use core::cmp::Ordering;
-use core::fmt;
-use core::ops::{Add, Div, Mul, Neg, Rem, Sub};
-use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
-use core::str::FromStr;
-
-bitflags::bitflags! {
-    /// IEEE-754R 7: Default exception handling.
-    ///
-    /// UNDERFLOW or OVERFLOW are always returned or-ed with INEXACT.
-    #[must_use]
-    pub struct Status: u8 {
-        const OK = 0x00;
-        const INVALID_OP = 0x01;
-        const DIV_BY_ZERO = 0x02;
-        const OVERFLOW = 0x04;
-        const UNDERFLOW = 0x08;
-        const INEXACT = 0x10;
-    }
-}
-
-#[must_use]
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
-pub struct StatusAnd<T> {
-    pub status: Status,
-    pub value: T,
-}
-
-impl Status {
-    pub fn and<T>(self, value: T) -> StatusAnd<T> {
-        StatusAnd { status: self, value }
-    }
-}
-
-impl<T> StatusAnd<T> {
-    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> StatusAnd<U> {
-        StatusAnd { status: self.status, value: f(self.value) }
-    }
-}
-
-#[macro_export]
-macro_rules! unpack {
-    ($status:ident|=, $e:expr) => {
-        match $e {
-            $crate::StatusAnd { status, value } => {
-                $status |= status;
-                value
-            }
-        }
-    };
-    ($status:ident=, $e:expr) => {
-        match $e {
-            $crate::StatusAnd { status, value } => {
-                $status = status;
-                value
-            }
-        }
-    };
-}
-
-/// Category of internally-represented number.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum Category {
-    Infinity,
-    NaN,
-    Normal,
-    Zero,
-}
-
-/// IEEE-754R 4.3: Rounding-direction attributes.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum Round {
-    NearestTiesToEven,
-    TowardPositive,
-    TowardNegative,
-    TowardZero,
-    NearestTiesToAway,
-}
-
-impl Neg for Round {
-    type Output = Round;
-    fn neg(self) -> Round {
-        match self {
-            Round::TowardPositive => Round::TowardNegative,
-            Round::TowardNegative => Round::TowardPositive,
-            Round::NearestTiesToEven | Round::TowardZero | Round::NearestTiesToAway => self,
-        }
-    }
-}
-
-/// A signed type to represent a floating point number's unbiased exponent.
-pub type ExpInt = i16;
-
-// \c ilogb error results.
-pub const IEK_INF: ExpInt = ExpInt::MAX;
-pub const IEK_NAN: ExpInt = ExpInt::MIN;
-pub const IEK_ZERO: ExpInt = ExpInt::MIN + 1;
-
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub struct ParseError(pub &'static str);
-
-/// A self-contained host- and target-independent arbitrary-precision
-/// floating-point software implementation.
-///
-/// `apfloat` uses significand bignum integer arithmetic as provided by functions
-/// in the `ieee::sig`.
-///
-/// Written for clarity rather than speed, in particular with a view to use in
-/// the front-end of a cross compiler so that target arithmetic can be correctly
-/// performed on the host. Performance should nonetheless be reasonable,
-/// particularly for its intended use. It may be useful as a base
-/// implementation for a run-time library during development of a faster
-/// target-specific one.
-///
-/// All 5 rounding modes in the IEEE-754R draft are handled correctly for all
-/// implemented operations. Currently implemented operations are add, subtract,
-/// multiply, divide, fused-multiply-add, conversion-to-float,
-/// conversion-to-integer and conversion-from-integer. New rounding modes
-/// (e.g., away from zero) can be added with three or four lines of code.
-///
-/// Four formats are built-in: IEEE single precision, double precision,
-/// quadruple precision, and x87 80-bit extended double (when operating with
-/// full extended precision). Adding a new format that obeys IEEE semantics
-/// only requires adding two lines of code: a declaration and definition of the
-/// format.
-///
-/// All operations return the status of that operation as an exception bit-mask,
-/// so multiple operations can be done consecutively with their results or-ed
-/// together. The returned status can be useful for compiler diagnostics; e.g.,
-/// inexact, underflow and overflow can be easily diagnosed on constant folding,
-/// and compiler optimizers can determine what exceptions would be raised by
-/// folding operations and optimize, or perhaps not optimize, accordingly.
-///
-/// At present, underflow tininess is detected after rounding; it should be
-/// straight forward to add support for the before-rounding case too.
-///
-/// The library reads hexadecimal floating point numbers as per C99, and
-/// correctly rounds if necessary according to the specified rounding mode.
-/// Syntax is required to have been validated by the caller.
-///
-/// It also reads decimal floating point numbers and correctly rounds according
-/// to the specified rounding mode.
-///
-/// Non-zero finite numbers are represented internally as a sign bit, a 16-bit
-/// signed exponent, and the significand as an array of integer limbs. After
-/// normalization of a number of precision P the exponent is within the range of
-/// the format, and if the number is not denormal the P-th bit of the
-/// significand is set as an explicit integer bit. For denormals the most
-/// significant bit is shifted right so that the exponent is maintained at the
-/// format's minimum, so that the smallest denormal has just the least
-/// significant bit of the significand set. The sign of zeros and infinities
-/// is significant; the exponent and significand of such numbers is not stored,
-/// but has a known implicit (deterministic) value: 0 for the significands, 0
-/// for zero exponent, all 1 bits for infinity exponent. For NaNs the sign and
-/// significand are deterministic, although not really meaningful, and preserved
-/// in non-conversion operations. The exponent is implicitly all 1 bits.
-///
-/// `apfloat` does not provide any exception handling beyond default exception
-/// handling. We represent Signaling NaNs via IEEE-754R 2008 6.2.1 should clause
-/// by encoding Signaling NaNs with the first bit of its trailing significand
-/// as 0.
-///
-/// Future work
-/// ===========
-///
-/// Some features that may or may not be worth adding:
-///
-/// Optional ability to detect underflow tininess before rounding.
-///
-/// New formats: x87 in single and double precision mode (IEEE apart from
-/// extended exponent range) (hard).
-///
-/// New operations: sqrt, nexttoward.
-///
-pub trait Float:
-    Copy
-    + Default
-    + FromStr<Err = ParseError>
-    + PartialOrd
-    + fmt::Display
-    + Neg<Output = Self>
-    + AddAssign
-    + SubAssign
-    + MulAssign
-    + DivAssign
-    + RemAssign
-    + Add<Output = StatusAnd<Self>>
-    + Sub<Output = StatusAnd<Self>>
-    + Mul<Output = StatusAnd<Self>>
-    + Div<Output = StatusAnd<Self>>
-    + Rem<Output = StatusAnd<Self>>
-{
-    /// Total number of bits in the in-memory format.
-    const BITS: usize;
-
-    /// Number of bits in the significand. This includes the integer bit.
-    const PRECISION: usize;
-
-    /// The largest E such that 2<sup>E</sup> is representable; this matches the
-    /// definition of IEEE 754.
-    const MAX_EXP: ExpInt;
-
-    /// The smallest E such that 2<sup>E</sup> is a normalized number; this
-    /// matches the definition of IEEE 754.
-    const MIN_EXP: ExpInt;
-
-    /// Positive Zero.
-    const ZERO: Self;
-
-    /// Positive Infinity.
-    const INFINITY: Self;
-
-    /// NaN (Not a Number).
-    // FIXME(eddyb) provide a default when qnan becomes const fn.
-    const NAN: Self;
-
-    /// Factory for QNaN values.
-    // FIXME(eddyb) should be const fn.
-    fn qnan(payload: Option<u128>) -> Self;
-
-    /// Factory for SNaN values.
-    // FIXME(eddyb) should be const fn.
-    fn snan(payload: Option<u128>) -> Self;
-
-    /// Largest finite number.
-    // FIXME(eddyb) should be const (but FloatPair::largest is nontrivial).
-    fn largest() -> Self;
-
-    /// Smallest (by magnitude) finite number.
-    /// Might be denormalized, which implies a relative loss of precision.
-    const SMALLEST: Self;
-
-    /// Smallest (by magnitude) normalized finite number.
-    // FIXME(eddyb) should be const (but FloatPair::smallest_normalized is nontrivial).
-    fn smallest_normalized() -> Self;
-
-    // Arithmetic
-
-    fn add_r(self, rhs: Self, round: Round) -> StatusAnd<Self>;
-    fn sub_r(self, rhs: Self, round: Round) -> StatusAnd<Self> {
-        self.add_r(-rhs, round)
-    }
-    fn mul_r(self, rhs: Self, round: Round) -> StatusAnd<Self>;
-    fn mul_add_r(self, multiplicand: Self, addend: Self, round: Round) -> StatusAnd<Self>;
-    fn mul_add(self, multiplicand: Self, addend: Self) -> StatusAnd<Self> {
-        self.mul_add_r(multiplicand, addend, Round::NearestTiesToEven)
-    }
-    fn div_r(self, rhs: Self, round: Round) -> StatusAnd<Self>;
-    /// IEEE remainder.
-    // This is not currently correct in all cases.
-    fn ieee_rem(self, rhs: Self) -> StatusAnd<Self> {
-        let mut v = self;
-
-        let status;
-        v = unpack!(status=, v / rhs);
-        if status == Status::DIV_BY_ZERO {
-            return status.and(self);
-        }
-
-        assert!(Self::PRECISION < 128);
-
-        let status;
-        let x = unpack!(status=, v.to_i128_r(128, Round::NearestTiesToEven, &mut false));
-        if status == Status::INVALID_OP {
-            return status.and(self);
-        }
-
-        let status;
-        let mut v = unpack!(status=, Self::from_i128(x));
-        assert_eq!(status, Status::OK); // should always work
-
-        let status;
-        v = unpack!(status=, v * rhs);
-        assert_eq!(status - Status::INEXACT, Status::OK); // should not overflow or underflow
-
-        let status;
-        v = unpack!(status=, self - v);
-        assert_eq!(status - Status::INEXACT, Status::OK); // likewise
-
-        if v.is_zero() {
-            status.and(v.copy_sign(self)) // IEEE754 requires this
-        } else {
-            status.and(v)
-        }
-    }
-    /// C fmod, or llvm frem.
-    fn c_fmod(self, rhs: Self) -> StatusAnd<Self>;
-    fn round_to_integral(self, round: Round) -> StatusAnd<Self>;
-
-    /// IEEE-754R 2008 5.3.1: nextUp.
-    fn next_up(self) -> StatusAnd<Self>;
-
-    /// IEEE-754R 2008 5.3.1: nextDown.
-    ///
-    /// *NOTE* since nextDown(x) = -nextUp(-x), we only implement nextUp with
-    /// appropriate sign switching before/after the computation.
-    fn next_down(self) -> StatusAnd<Self> {
-        (-self).next_up().map(|r| -r)
-    }
-
-    fn abs(self) -> Self {
-        if self.is_negative() { -self } else { self }
-    }
-    fn copy_sign(self, rhs: Self) -> Self {
-        if self.is_negative() != rhs.is_negative() { -self } else { self }
-    }
-
-    // Conversions
-    fn from_bits(input: u128) -> Self;
-    fn from_i128_r(input: i128, round: Round) -> StatusAnd<Self> {
-        if input < 0 {
-            Self::from_u128_r(input.wrapping_neg() as u128, -round).map(|r| -r)
-        } else {
-            Self::from_u128_r(input as u128, round)
-        }
-    }
-    fn from_i128(input: i128) -> StatusAnd<Self> {
-        Self::from_i128_r(input, Round::NearestTiesToEven)
-    }
-    fn from_u128_r(input: u128, round: Round) -> StatusAnd<Self>;
-    fn from_u128(input: u128) -> StatusAnd<Self> {
-        Self::from_u128_r(input, Round::NearestTiesToEven)
-    }
-    fn from_str_r(s: &str, round: Round) -> Result<StatusAnd<Self>, ParseError>;
-    fn to_bits(self) -> u128;
-
-    /// Converts a floating point number to an integer according to the
-    /// rounding mode. In case of an invalid operation exception,
-    /// deterministic values are returned, namely zero for NaNs and the
-    /// minimal or maximal value respectively for underflow or overflow.
-    /// If the rounded value is in range but the floating point number is
-    /// not the exact integer, the C standard doesn't require an inexact
-    /// exception to be raised. IEEE-854 does require it so we do that.
-    ///
-    /// Note that for conversions to integer type the C standard requires
-    /// round-to-zero to always be used.
-    ///
-    /// The *is_exact output tells whether the result is exact, in the sense
-    /// that converting it back to the original floating point type produces
-    /// the original value. This is almost equivalent to `result == Status::OK`,
-    /// except for negative zeroes.
-    fn to_i128_r(self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<i128> {
-        let status;
-        if self.is_negative() {
-            if self.is_zero() {
-                // Negative zero can't be represented as an int.
-                *is_exact = false;
-            }
-            let r = unpack!(status=, (-self).to_u128_r(width, -round, is_exact));
-
-            // Check for values that don't fit in the signed integer.
-            if r > (1 << (width - 1)) {
-                // Return the most negative integer for the given width.
-                *is_exact = false;
-                Status::INVALID_OP.and(-1 << (width - 1))
-            } else {
-                status.and(r.wrapping_neg() as i128)
-            }
-        } else {
-            // Positive case is simpler, can pretend it's a smaller unsigned
-            // integer, and `to_u128` will take care of all the edge cases.
-            self.to_u128_r(width - 1, round, is_exact).map(|r| r as i128)
-        }
-    }
-    fn to_i128(self, width: usize) -> StatusAnd<i128> {
-        self.to_i128_r(width, Round::TowardZero, &mut true)
-    }
-    fn to_u128_r(self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<u128>;
-    fn to_u128(self, width: usize) -> StatusAnd<u128> {
-        self.to_u128_r(width, Round::TowardZero, &mut true)
-    }
-
-    fn cmp_abs_normal(self, rhs: Self) -> Ordering;
-
-    /// Bitwise comparison for equality (QNaNs compare equal, 0!=-0).
-    fn bitwise_eq(self, rhs: Self) -> bool;
-
-    // IEEE-754R 5.7.2 General operations.
-
-    /// Implements IEEE minNum semantics. Returns the smaller of the 2 arguments if
-    /// both are not NaN. If either argument is a NaN, returns the other argument.
-    fn min(self, other: Self) -> Self {
-        if self.is_nan() {
-            other
-        } else if other.is_nan() {
-            self
-        } else if other.partial_cmp(&self) == Some(Ordering::Less) {
-            other
-        } else {
-            self
-        }
-    }
-
-    /// Implements IEEE maxNum semantics. Returns the larger of the 2 arguments if
-    /// both are not NaN. If either argument is a NaN, returns the other argument.
-    fn max(self, other: Self) -> Self {
-        if self.is_nan() {
-            other
-        } else if other.is_nan() {
-            self
-        } else if self.partial_cmp(&other) == Some(Ordering::Less) {
-            other
-        } else {
-            self
-        }
-    }
-
-    /// IEEE-754R isSignMinus: Returns whether the current value is
-    /// negative.
-    ///
-    /// This applies to zeros and NaNs as well.
-    fn is_negative(self) -> bool;
-
-    /// IEEE-754R isNormal: Returns whether the current value is normal.
-    ///
-    /// This implies that the current value of the float is not zero, subnormal,
-    /// infinite, or NaN following the definition of normality from IEEE-754R.
-    fn is_normal(self) -> bool {
-        !self.is_denormal() && self.is_finite_non_zero()
-    }
-
-    /// Returns `true` if the current value is zero, subnormal, or
-    /// normal.
-    ///
-    /// This means that the value is not infinite or NaN.
-    fn is_finite(self) -> bool {
-        !self.is_nan() && !self.is_infinite()
-    }
-
-    /// Returns `true` if the float is plus or minus zero.
-    fn is_zero(self) -> bool {
-        self.category() == Category::Zero
-    }
-
-    /// IEEE-754R isSubnormal(): Returns whether the float is a
-    /// denormal.
-    fn is_denormal(self) -> bool;
-
-    /// IEEE-754R isInfinite(): Returns whether the float is infinity.
-    fn is_infinite(self) -> bool {
-        self.category() == Category::Infinity
-    }
-
-    /// Returns `true` if the float is a quiet or signaling NaN.
-    fn is_nan(self) -> bool {
-        self.category() == Category::NaN
-    }
-
-    /// Returns `true` if the float is a signaling NaN.
-    fn is_signaling(self) -> bool;
-
-    // Simple Queries
-
-    fn category(self) -> Category;
-    fn is_non_zero(self) -> bool {
-        !self.is_zero()
-    }
-    fn is_finite_non_zero(self) -> bool {
-        self.is_finite() && !self.is_zero()
-    }
-    fn is_pos_zero(self) -> bool {
-        self.is_zero() && !self.is_negative()
-    }
-    fn is_neg_zero(self) -> bool {
-        self.is_zero() && self.is_negative()
-    }
-
-    /// Returns `true` if the number has the smallest possible non-zero
-    /// magnitude in the current semantics.
-    fn is_smallest(self) -> bool {
-        Self::SMALLEST.copy_sign(self).bitwise_eq(self)
-    }
-
-    /// Returns `true` if the number has the largest possible finite
-    /// magnitude in the current semantics.
-    fn is_largest(self) -> bool {
-        Self::largest().copy_sign(self).bitwise_eq(self)
-    }
-
-    /// Returns `true` if the number is an exact integer.
-    fn is_integer(self) -> bool {
-        // This could be made more efficient; I'm going for obviously correct.
-        if !self.is_finite() {
-            return false;
-        }
-        self.round_to_integral(Round::TowardZero).value.bitwise_eq(self)
-    }
-
-    /// If this value has an exact multiplicative inverse, return it.
-    fn get_exact_inverse(self) -> Option<Self>;
-
-    /// Returns the exponent of the internal representation of the Float.
-    ///
-    /// Because the radix of Float is 2, this is equivalent to floor(log2(x)).
-    /// For special Float values, this returns special error codes:
-    ///
-    ///   NaN -> \c IEK_NAN
-    ///   0   -> \c IEK_ZERO
-    ///   Inf -> \c IEK_INF
-    ///
-    fn ilogb(self) -> ExpInt;
-
-    /// Returns: self * 2<sup>exp</sup> for integral exponents.
-    /// Equivalent to C standard library function `ldexp`.
-    fn scalbn_r(self, exp: ExpInt, round: Round) -> Self;
-    fn scalbn(self, exp: ExpInt) -> Self {
-        self.scalbn_r(exp, Round::NearestTiesToEven)
-    }
-
-    /// Equivalent to C standard library function with the same name.
-    ///
-    /// While the C standard says exp is an unspecified value for infinity and nan,
-    /// this returns INT_MAX for infinities, and INT_MIN for NaNs (see `ilogb`).
-    fn frexp_r(self, exp: &mut ExpInt, round: Round) -> Self;
-    fn frexp(self, exp: &mut ExpInt) -> Self {
-        self.frexp_r(exp, Round::NearestTiesToEven)
-    }
-}
-
-pub trait FloatConvert<T: Float>: Float {
-    /// Converts a value of one floating point type to another.
-    /// The return value corresponds to the IEEE754 exceptions. *loses_info
-    /// records whether the transformation lost information, i.e., whether
-    /// converting the result back to the original type will produce the
-    /// original value (this is almost the same as return `value == Status::OK`,
-    /// but there are edge cases where this is not so).
-    fn convert_r(self, round: Round, loses_info: &mut bool) -> StatusAnd<T>;
-    fn convert(self, loses_info: &mut bool) -> StatusAnd<T> {
-        self.convert_r(Round::NearestTiesToEven, loses_info)
-    }
-}
-
-macro_rules! float_common_impls {
-    ($ty:ident<$t:tt>) => {
-        impl<$t> Default for $ty<$t>
-        where
-            Self: Float,
-        {
-            fn default() -> Self {
-                Self::ZERO
-            }
-        }
-
-        impl<$t> ::core::str::FromStr for $ty<$t>
-        where
-            Self: Float,
-        {
-            type Err = ParseError;
-            fn from_str(s: &str) -> Result<Self, ParseError> {
-                Self::from_str_r(s, Round::NearestTiesToEven).map(|x| x.value)
-            }
-        }
-
-        // Rounding ties to the nearest even, by default.
-
-        impl<$t> ::core::ops::Add for $ty<$t>
-        where
-            Self: Float,
-        {
-            type Output = StatusAnd<Self>;
-            fn add(self, rhs: Self) -> StatusAnd<Self> {
-                self.add_r(rhs, Round::NearestTiesToEven)
-            }
-        }
-
-        impl<$t> ::core::ops::Sub for $ty<$t>
-        where
-            Self: Float,
-        {
-            type Output = StatusAnd<Self>;
-            fn sub(self, rhs: Self) -> StatusAnd<Self> {
-                self.sub_r(rhs, Round::NearestTiesToEven)
-            }
-        }
-
-        impl<$t> ::core::ops::Mul for $ty<$t>
-        where
-            Self: Float,
-        {
-            type Output = StatusAnd<Self>;
-            fn mul(self, rhs: Self) -> StatusAnd<Self> {
-                self.mul_r(rhs, Round::NearestTiesToEven)
-            }
-        }
-
-        impl<$t> ::core::ops::Div for $ty<$t>
-        where
-            Self: Float,
-        {
-            type Output = StatusAnd<Self>;
-            fn div(self, rhs: Self) -> StatusAnd<Self> {
-                self.div_r(rhs, Round::NearestTiesToEven)
-            }
-        }
-
-        impl<$t> ::core::ops::Rem for $ty<$t>
-        where
-            Self: Float,
-        {
-            type Output = StatusAnd<Self>;
-            fn rem(self, rhs: Self) -> StatusAnd<Self> {
-                self.c_fmod(rhs)
-            }
-        }
-
-        impl<$t> ::core::ops::AddAssign for $ty<$t>
-        where
-            Self: Float,
-        {
-            fn add_assign(&mut self, rhs: Self) {
-                *self = (*self + rhs).value;
-            }
-        }
-
-        impl<$t> ::core::ops::SubAssign for $ty<$t>
-        where
-            Self: Float,
-        {
-            fn sub_assign(&mut self, rhs: Self) {
-                *self = (*self - rhs).value;
-            }
-        }
-
-        impl<$t> ::core::ops::MulAssign for $ty<$t>
-        where
-            Self: Float,
-        {
-            fn mul_assign(&mut self, rhs: Self) {
-                *self = (*self * rhs).value;
-            }
-        }
-
-        impl<$t> ::core::ops::DivAssign for $ty<$t>
-        where
-            Self: Float,
-        {
-            fn div_assign(&mut self, rhs: Self) {
-                *self = (*self / rhs).value;
-            }
-        }
-
-        impl<$t> ::core::ops::RemAssign for $ty<$t>
-        where
-            Self: Float,
-        {
-            fn rem_assign(&mut self, rhs: Self) {
-                *self = (*self % rhs).value;
-            }
-        }
-    };
-}
-
-pub mod ieee;
-pub mod ppc;
diff --git a/compiler/rustc_apfloat/src/ppc.rs b/compiler/rustc_apfloat/src/ppc.rs
deleted file mode 100644
index 65a0f66645b..00000000000
--- a/compiler/rustc_apfloat/src/ppc.rs
+++ /dev/null
@@ -1,434 +0,0 @@
-use crate::ieee;
-use crate::{Category, ExpInt, Float, FloatConvert, ParseError, Round, Status, StatusAnd};
-
-use core::cmp::Ordering;
-use core::fmt;
-use core::ops::Neg;
-
-#[must_use]
-#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
-pub struct DoubleFloat<F>(F, F);
-pub type DoubleDouble = DoubleFloat<ieee::Double>;
-
-// These are legacy semantics for the Fallback, inaccurate implementation of
-// IBM double-double, if the accurate DoubleDouble doesn't handle the
-// operation. It's equivalent to having an IEEE number with consecutive 106
-// bits of mantissa and 11 bits of exponent.
-//
-// It's not equivalent to IBM double-double. For example, a legit IBM
-// double-double, 1 + epsilon:
-//
-//   1 + epsilon = 1 + (1 >> 1076)
-//
-// is not representable by a consecutive 106 bits of mantissa.
-//
-// Currently, these semantics are used in the following way:
-//
-//   DoubleDouble -> (Double, Double) ->
-//   DoubleDouble's Fallback -> IEEE operations
-//
-// FIXME: Implement all operations in DoubleDouble, and delete these
-// semantics.
-// FIXME(eddyb) This shouldn't need to be `pub`, it's only used in bounds.
-pub struct FallbackS<F>(#[allow(unused)] F);
-type Fallback<F> = ieee::IeeeFloat<FallbackS<F>>;
-impl<F: Float> ieee::Semantics for FallbackS<F> {
-    // Forbid any conversion to/from bits.
-    const BITS: usize = 0;
-    const PRECISION: usize = F::PRECISION * 2;
-    const MAX_EXP: ExpInt = F::MAX_EXP as ExpInt;
-    const MIN_EXP: ExpInt = F::MIN_EXP as ExpInt + F::PRECISION as ExpInt;
-}
-
-// Convert number to F. To avoid spurious underflows, we re-
-// normalize against the F exponent range first, and only *then*
-// truncate the mantissa. The result of that second conversion
-// may be inexact, but should never underflow.
-// FIXME(eddyb) This shouldn't need to be `pub`, it's only used in bounds.
-pub struct FallbackExtendedS<F>(#[allow(unused)] F);
-type FallbackExtended<F> = ieee::IeeeFloat<FallbackExtendedS<F>>;
-impl<F: Float> ieee::Semantics for FallbackExtendedS<F> {
-    // Forbid any conversion to/from bits.
-    const BITS: usize = 0;
-    const PRECISION: usize = Fallback::<F>::PRECISION;
-    const MAX_EXP: ExpInt = F::MAX_EXP as ExpInt;
-}
-
-impl<F: Float> From<Fallback<F>> for DoubleFloat<F>
-where
-    F: FloatConvert<FallbackExtended<F>>,
-    FallbackExtended<F>: FloatConvert<F>,
-{
-    fn from(x: Fallback<F>) -> Self {
-        let mut status;
-        let mut loses_info = false;
-
-        let extended: FallbackExtended<F> = unpack!(status=, x.convert(&mut loses_info));
-        assert_eq!((status, loses_info), (Status::OK, false));
-
-        let a = unpack!(status=, extended.convert(&mut loses_info));
-        assert_eq!(status - Status::INEXACT, Status::OK);
-
-        // If conversion was exact or resulted in a special case, we're done;
-        // just set the second double to zero. Otherwise, re-convert back to
-        // the extended format and compute the difference. This now should
-        // convert exactly to double.
-        let b = if a.is_finite_non_zero() && loses_info {
-            let u: FallbackExtended<F> = unpack!(status=, a.convert(&mut loses_info));
-            assert_eq!((status, loses_info), (Status::OK, false));
-            let v = unpack!(status=, extended - u);
-            assert_eq!(status, Status::OK);
-            let v = unpack!(status=, v.convert(&mut loses_info));
-            assert_eq!((status, loses_info), (Status::OK, false));
-            v
-        } else {
-            F::ZERO
-        };
-
-        DoubleFloat(a, b)
-    }
-}
-
-impl<F: FloatConvert<Self>> From<DoubleFloat<F>> for Fallback<F> {
-    fn from(DoubleFloat(a, b): DoubleFloat<F>) -> Self {
-        let mut status;
-        let mut loses_info = false;
-
-        // Get the first F and convert to our format.
-        let a = unpack!(status=, a.convert(&mut loses_info));
-        assert_eq!((status, loses_info), (Status::OK, false));
-
-        // Unless we have a special case, add in second F.
-        if a.is_finite_non_zero() {
-            let b = unpack!(status=, b.convert(&mut loses_info));
-            assert_eq!((status, loses_info), (Status::OK, false));
-
-            (a + b).value
-        } else {
-            a
-        }
-    }
-}
-
-float_common_impls!(DoubleFloat<F>);
-
-impl<F: Float> Neg for DoubleFloat<F> {
-    type Output = Self;
-    fn neg(self) -> Self {
-        if self.1.is_finite_non_zero() {
-            DoubleFloat(-self.0, -self.1)
-        } else {
-            DoubleFloat(-self.0, self.1)
-        }
-    }
-}
-
-impl<F: FloatConvert<Fallback<F>>> fmt::Display for DoubleFloat<F> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(&Fallback::from(*self), f)
-    }
-}
-
-impl<F: FloatConvert<Fallback<F>>> Float for DoubleFloat<F>
-where
-    Self: From<Fallback<F>>,
-{
-    const BITS: usize = F::BITS * 2;
-    const PRECISION: usize = Fallback::<F>::PRECISION;
-    const MAX_EXP: ExpInt = Fallback::<F>::MAX_EXP;
-    const MIN_EXP: ExpInt = Fallback::<F>::MIN_EXP;
-
-    const ZERO: Self = DoubleFloat(F::ZERO, F::ZERO);
-
-    const INFINITY: Self = DoubleFloat(F::INFINITY, F::ZERO);
-
-    // FIXME(eddyb) remove when qnan becomes const fn.
-    const NAN: Self = DoubleFloat(F::NAN, F::ZERO);
-
-    fn qnan(payload: Option<u128>) -> Self {
-        DoubleFloat(F::qnan(payload), F::ZERO)
-    }
-
-    fn snan(payload: Option<u128>) -> Self {
-        DoubleFloat(F::snan(payload), F::ZERO)
-    }
-
-    fn largest() -> Self {
-        let status;
-        let mut r = DoubleFloat(F::largest(), F::largest());
-        r.1 = r.1.scalbn(-(F::PRECISION as ExpInt + 1));
-        r.1 = unpack!(status=, r.1.next_down());
-        assert_eq!(status, Status::OK);
-        r
-    }
-
-    const SMALLEST: Self = DoubleFloat(F::SMALLEST, F::ZERO);
-
-    fn smallest_normalized() -> Self {
-        DoubleFloat(F::smallest_normalized().scalbn(F::PRECISION as ExpInt), F::ZERO)
-    }
-
-    // Implement addition, subtraction, multiplication and division based on:
-    // "Software for Doubled-Precision Floating-Point Computations",
-    // by Seppo Linnainmaa, ACM TOMS vol 7 no 3, September 1981, pages 272-283.
-
-    fn add_r(mut self, rhs: Self, round: Round) -> StatusAnd<Self> {
-        match (self.category(), rhs.category()) {
-            (Category::Infinity, Category::Infinity) => {
-                if self.is_negative() != rhs.is_negative() {
-                    Status::INVALID_OP.and(Self::NAN.copy_sign(self))
-                } else {
-                    Status::OK.and(self)
-                }
-            }
-
-            (_, Category::Zero) | (Category::NaN, _) | (Category::Infinity, Category::Normal) => {
-                Status::OK.and(self)
-            }
-
-            (Category::Zero, _) | (_, Category::NaN | Category::Infinity) => Status::OK.and(rhs),
-
-            (Category::Normal, Category::Normal) => {
-                let mut status = Status::OK;
-                let (a, aa, c, cc) = (self.0, self.1, rhs.0, rhs.1);
-                let mut z = a;
-                z = unpack!(status|=, z.add_r(c, round));
-                if !z.is_finite() {
-                    if !z.is_infinite() {
-                        return status.and(DoubleFloat(z, F::ZERO));
-                    }
-                    status = Status::OK;
-                    let a_cmp_c = a.cmp_abs_normal(c);
-                    z = cc;
-                    z = unpack!(status|=, z.add_r(aa, round));
-                    if a_cmp_c == Ordering::Greater {
-                        // z = cc + aa + c + a;
-                        z = unpack!(status|=, z.add_r(c, round));
-                        z = unpack!(status|=, z.add_r(a, round));
-                    } else {
-                        // z = cc + aa + a + c;
-                        z = unpack!(status|=, z.add_r(a, round));
-                        z = unpack!(status|=, z.add_r(c, round));
-                    }
-                    if !z.is_finite() {
-                        return status.and(DoubleFloat(z, F::ZERO));
-                    }
-                    self.0 = z;
-                    let mut zz = aa;
-                    zz = unpack!(status|=, zz.add_r(cc, round));
-                    if a_cmp_c == Ordering::Greater {
-                        // self.1 = a - z + c + zz;
-                        self.1 = a;
-                        self.1 = unpack!(status|=, self.1.sub_r(z, round));
-                        self.1 = unpack!(status|=, self.1.add_r(c, round));
-                        self.1 = unpack!(status|=, self.1.add_r(zz, round));
-                    } else {
-                        // self.1 = c - z + a + zz;
-                        self.1 = c;
-                        self.1 = unpack!(status|=, self.1.sub_r(z, round));
-                        self.1 = unpack!(status|=, self.1.add_r(a, round));
-                        self.1 = unpack!(status|=, self.1.add_r(zz, round));
-                    }
-                } else {
-                    // q = a - z;
-                    let mut q = a;
-                    q = unpack!(status|=, q.sub_r(z, round));
-
-                    // zz = q + c + (a - (q + z)) + aa + cc;
-                    // Compute a - (q + z) as -((q + z) - a) to avoid temporary copies.
-                    let mut zz = q;
-                    zz = unpack!(status|=, zz.add_r(c, round));
-                    q = unpack!(status|=, q.add_r(z, round));
-                    q = unpack!(status|=, q.sub_r(a, round));
-                    q = -q;
-                    zz = unpack!(status|=, zz.add_r(q, round));
-                    zz = unpack!(status|=, zz.add_r(aa, round));
-                    zz = unpack!(status|=, zz.add_r(cc, round));
-                    if zz.is_zero() && !zz.is_negative() {
-                        return Status::OK.and(DoubleFloat(z, F::ZERO));
-                    }
-                    self.0 = z;
-                    self.0 = unpack!(status|=, self.0.add_r(zz, round));
-                    if !self.0.is_finite() {
-                        self.1 = F::ZERO;
-                        return status.and(self);
-                    }
-                    self.1 = z;
-                    self.1 = unpack!(status|=, self.1.sub_r(self.0, round));
-                    self.1 = unpack!(status|=, self.1.add_r(zz, round));
-                }
-                status.and(self)
-            }
-        }
-    }
-
-    fn mul_r(mut self, rhs: Self, round: Round) -> StatusAnd<Self> {
-        // Interesting observation: For special categories, finding the lowest
-        // common ancestor of the following layered graph gives the correct
-        // return category:
-        //
-        //    NaN
-        //   /   \
-        // Zero  Inf
-        //   \   /
-        //   Normal
-        //
-        // e.g., NaN * NaN = NaN
-        //      Zero * Inf = NaN
-        //      Normal * Zero = Zero
-        //      Normal * Inf = Inf
-        match (self.category(), rhs.category()) {
-            (Category::NaN, _) => Status::OK.and(self),
-
-            (_, Category::NaN) => Status::OK.and(rhs),
-
-            (Category::Zero, Category::Infinity) | (Category::Infinity, Category::Zero) => {
-                Status::OK.and(Self::NAN)
-            }
-
-            (Category::Zero | Category::Infinity, _) => Status::OK.and(self),
-
-            (_, Category::Zero | Category::Infinity) => Status::OK.and(rhs),
-
-            (Category::Normal, Category::Normal) => {
-                let mut status = Status::OK;
-                let (a, b, c, d) = (self.0, self.1, rhs.0, rhs.1);
-                // t = a * c
-                let mut t = a;
-                t = unpack!(status|=, t.mul_r(c, round));
-                if !t.is_finite_non_zero() {
-                    return status.and(DoubleFloat(t, F::ZERO));
-                }
-
-                // tau = fmsub(a, c, t), that is -fmadd(-a, c, t).
-                let mut tau = a;
-                tau = unpack!(status|=, tau.mul_add_r(c, -t, round));
-                // v = a * d
-                let mut v = a;
-                v = unpack!(status|=, v.mul_r(d, round));
-                // w = b * c
-                let mut w = b;
-                w = unpack!(status|=, w.mul_r(c, round));
-                v = unpack!(status|=, v.add_r(w, round));
-                // tau += v + w
-                tau = unpack!(status|=, tau.add_r(v, round));
-                // u = t + tau
-                let mut u = t;
-                u = unpack!(status|=, u.add_r(tau, round));
-
-                self.0 = u;
-                if !u.is_finite() {
-                    self.1 = F::ZERO;
-                } else {
-                    // self.1 = (t - u) + tau
-                    t = unpack!(status|=, t.sub_r(u, round));
-                    t = unpack!(status|=, t.add_r(tau, round));
-                    self.1 = t;
-                }
-                status.and(self)
-            }
-        }
-    }
-
-    fn mul_add_r(self, multiplicand: Self, addend: Self, round: Round) -> StatusAnd<Self> {
-        Fallback::from(self)
-            .mul_add_r(Fallback::from(multiplicand), Fallback::from(addend), round)
-            .map(Self::from)
-    }
-
-    fn div_r(self, rhs: Self, round: Round) -> StatusAnd<Self> {
-        Fallback::from(self).div_r(Fallback::from(rhs), round).map(Self::from)
-    }
-
-    fn c_fmod(self, rhs: Self) -> StatusAnd<Self> {
-        Fallback::from(self).c_fmod(Fallback::from(rhs)).map(Self::from)
-    }
-
-    fn round_to_integral(self, round: Round) -> StatusAnd<Self> {
-        Fallback::from(self).round_to_integral(round).map(Self::from)
-    }
-
-    fn next_up(self) -> StatusAnd<Self> {
-        Fallback::from(self).next_up().map(Self::from)
-    }
-
-    fn from_bits(input: u128) -> Self {
-        let (a, b) = (input, input >> F::BITS);
-        DoubleFloat(F::from_bits(a & ((1 << F::BITS) - 1)), F::from_bits(b & ((1 << F::BITS) - 1)))
-    }
-
-    fn from_u128_r(input: u128, round: Round) -> StatusAnd<Self> {
-        Fallback::from_u128_r(input, round).map(Self::from)
-    }
-
-    fn from_str_r(s: &str, round: Round) -> Result<StatusAnd<Self>, ParseError> {
-        Fallback::from_str_r(s, round).map(|r| r.map(Self::from))
-    }
-
-    fn to_bits(self) -> u128 {
-        self.0.to_bits() | (self.1.to_bits() << F::BITS)
-    }
-
-    fn to_u128_r(self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<u128> {
-        Fallback::from(self).to_u128_r(width, round, is_exact)
-    }
-
-    fn cmp_abs_normal(self, rhs: Self) -> Ordering {
-        self.0.cmp_abs_normal(rhs.0).then_with(|| {
-            let result = self.1.cmp_abs_normal(rhs.1);
-            if result != Ordering::Equal {
-                let against = self.0.is_negative() ^ self.1.is_negative();
-                let rhs_against = rhs.0.is_negative() ^ rhs.1.is_negative();
-                (!against)
-                    .cmp(&!rhs_against)
-                    .then_with(|| if against { result.reverse() } else { result })
-            } else {
-                result
-            }
-        })
-    }
-
-    fn bitwise_eq(self, rhs: Self) -> bool {
-        self.0.bitwise_eq(rhs.0) && self.1.bitwise_eq(rhs.1)
-    }
-
-    fn is_negative(self) -> bool {
-        self.0.is_negative()
-    }
-
-    fn is_denormal(self) -> bool {
-        self.category() == Category::Normal
-            && (self.0.is_denormal() || self.0.is_denormal() ||
-          // (double)(Hi + Lo) == Hi defines a normal number.
-          !(self.0 + self.1).value.bitwise_eq(self.0))
-    }
-
-    fn is_signaling(self) -> bool {
-        self.0.is_signaling()
-    }
-
-    fn category(self) -> Category {
-        self.0.category()
-    }
-
-    fn get_exact_inverse(self) -> Option<Self> {
-        Fallback::from(self).get_exact_inverse().map(Self::from)
-    }
-
-    fn ilogb(self) -> ExpInt {
-        self.0.ilogb()
-    }
-
-    fn scalbn_r(self, exp: ExpInt, round: Round) -> Self {
-        DoubleFloat(self.0.scalbn_r(exp, round), self.1.scalbn_r(exp, round))
-    }
-
-    fn frexp_r(self, exp: &mut ExpInt, round: Round) -> Self {
-        let a = self.0.frexp_r(exp, round);
-        let mut b = self.1;
-        if self.category() == Category::Normal {
-            b = b.scalbn_r(-*exp, round);
-        }
-        DoubleFloat(a, b)
-    }
-}
diff --git a/compiler/rustc_apfloat/tests/ieee.rs b/compiler/rustc_apfloat/tests/ieee.rs
deleted file mode 100644
index f8fac0c2358..00000000000
--- a/compiler/rustc_apfloat/tests/ieee.rs
+++ /dev/null
@@ -1,3301 +0,0 @@
-// ignore-tidy-filelength
-
-use rustc_apfloat::ieee::{Double, Half, Quad, Single, X87DoubleExtended};
-use rustc_apfloat::unpack;
-use rustc_apfloat::{Category, ExpInt, IEK_INF, IEK_NAN, IEK_ZERO};
-use rustc_apfloat::{Float, FloatConvert, ParseError, Round, Status};
-
-trait SingleExt {
-    fn from_f32(input: f32) -> Self;
-    fn to_f32(self) -> f32;
-}
-
-impl SingleExt for Single {
-    fn from_f32(input: f32) -> Self {
-        Self::from_bits(input.to_bits() as u128)
-    }
-
-    fn to_f32(self) -> f32 {
-        f32::from_bits(self.to_bits() as u32)
-    }
-}
-
-trait DoubleExt {
-    fn from_f64(input: f64) -> Self;
-    fn to_f64(self) -> f64;
-}
-
-impl DoubleExt for Double {
-    fn from_f64(input: f64) -> Self {
-        Self::from_bits(input.to_bits() as u128)
-    }
-
-    fn to_f64(self) -> f64 {
-        f64::from_bits(self.to_bits() as u64)
-    }
-}
-
-#[test]
-fn is_signaling() {
-    // We test qNaN, -qNaN, +sNaN, -sNaN with and without payloads.
-    let payload = 4;
-    assert!(!Single::qnan(None).is_signaling());
-    assert!(!(-Single::qnan(None)).is_signaling());
-    assert!(!Single::qnan(Some(payload)).is_signaling());
-    assert!(!(-Single::qnan(Some(payload))).is_signaling());
-    assert!(Single::snan(None).is_signaling());
-    assert!((-Single::snan(None)).is_signaling());
-    assert!(Single::snan(Some(payload)).is_signaling());
-    assert!((-Single::snan(Some(payload))).is_signaling());
-}
-
-#[test]
-fn next() {
-    // 1. Test Special Cases Values.
-    //
-    // Test all special values for nextUp and nextDown perscribed by IEEE-754R
-    // 2008. These are:
-    //   1. +inf
-    //   2. -inf
-    //   3. largest
-    //   4. -largest
-    //   5. smallest
-    //   6. -smallest
-    //   7. qNaN
-    //   8. sNaN
-    //   9. +0
-    //   10. -0
-
-    let mut status;
-
-    // nextUp(+inf) = +inf.
-    let test = unpack!(status=, Quad::INFINITY.next_up());
-    let expected = Quad::INFINITY;
-    assert_eq!(status, Status::OK);
-    assert!(test.is_infinite());
-    assert!(!test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(+inf) = -nextUp(-inf) = -(-largest) = largest
-    let test = unpack!(status=, Quad::INFINITY.next_down());
-    let expected = Quad::largest();
-    assert_eq!(status, Status::OK);
-    assert!(!test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(-inf) = -largest
-    let test = unpack!(status=, (-Quad::INFINITY).next_up());
-    let expected = -Quad::largest();
-    assert_eq!(status, Status::OK);
-    assert!(test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(-inf) = -nextUp(+inf) = -(+inf) = -inf.
-    let test = unpack!(status=, (-Quad::INFINITY).next_down());
-    let expected = -Quad::INFINITY;
-    assert_eq!(status, Status::OK);
-    assert!(test.is_infinite() && test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(largest) = +inf
-    let test = unpack!(status=, Quad::largest().next_up());
-    let expected = Quad::INFINITY;
-    assert_eq!(status, Status::OK);
-    assert!(test.is_infinite() && !test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(largest) = -nextUp(-largest)
-    //                        = -(-largest + inc)
-    //                        = largest - inc.
-    let test = unpack!(status=, Quad::largest().next_down());
-    let expected = "0x1.fffffffffffffffffffffffffffep+16383".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(!test.is_infinite() && !test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(-largest) = -largest + inc.
-    let test = unpack!(status=, (-Quad::largest()).next_up());
-    let expected = "-0x1.fffffffffffffffffffffffffffep+16383".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(-largest) = -nextUp(largest) = -(inf) = -inf.
-    let test = unpack!(status=, (-Quad::largest()).next_down());
-    let expected = -Quad::INFINITY;
-    assert_eq!(status, Status::OK);
-    assert!(test.is_infinite() && test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(smallest) = smallest + inc.
-    let test = unpack!(status=, "0x0.0000000000000000000000000001p-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = "0x0.0000000000000000000000000002p-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(smallest) = -nextUp(-smallest) = -(-0) = +0.
-    let test = unpack!(status=, "0x0.0000000000000000000000000001p-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = Quad::ZERO;
-    assert_eq!(status, Status::OK);
-    assert!(test.is_pos_zero());
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(-smallest) = -0.
-    let test = unpack!(status=, "-0x0.0000000000000000000000000001p-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = -Quad::ZERO;
-    assert_eq!(status, Status::OK);
-    assert!(test.is_neg_zero());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(-smallest) = -nextUp(smallest) = -smallest - inc.
-    let test = unpack!(status=, "-0x0.0000000000000000000000000001p-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = "-0x0.0000000000000000000000000002p-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(qNaN) = qNaN
-    let test = unpack!(status=, Quad::qnan(None).next_up());
-    let expected = Quad::qnan(None);
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(qNaN) = qNaN
-    let test = unpack!(status=, Quad::qnan(None).next_down());
-    let expected = Quad::qnan(None);
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(sNaN) = qNaN
-    let test = unpack!(status=, Quad::snan(None).next_up());
-    let expected = Quad::qnan(None);
-    assert_eq!(status, Status::INVALID_OP);
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(sNaN) = qNaN
-    let test = unpack!(status=, Quad::snan(None).next_down());
-    let expected = Quad::qnan(None);
-    assert_eq!(status, Status::INVALID_OP);
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(+0) = +smallest
-    let test = unpack!(status=, Quad::ZERO.next_up());
-    let expected = Quad::SMALLEST;
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(+0) = -nextUp(-0) = -smallest
-    let test = unpack!(status=, Quad::ZERO.next_down());
-    let expected = -Quad::SMALLEST;
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(-0) = +smallest
-    let test = unpack!(status=, (-Quad::ZERO).next_up());
-    let expected = Quad::SMALLEST;
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(-0) = -nextUp(0) = -smallest
-    let test = unpack!(status=, (-Quad::ZERO).next_down());
-    let expected = -Quad::SMALLEST;
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // 2. Binade Boundary Tests.
-
-    // 2a. Test denormal <-> normal binade boundaries.
-    //     * nextUp(+Largest Denormal) -> +Smallest Normal.
-    //     * nextDown(-Largest Denormal) -> -Smallest Normal.
-    //     * nextUp(-Smallest Normal) -> -Largest Denormal.
-    //     * nextDown(+Smallest Normal) -> +Largest Denormal.
-
-    // nextUp(+Largest Denormal) -> +Smallest Normal.
-    let test = unpack!(status=, "0x0.ffffffffffffffffffffffffffffp-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = "0x1.0000000000000000000000000000p-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(!test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(-Largest Denormal) -> -Smallest Normal.
-    let test = unpack!(status=, "-0x0.ffffffffffffffffffffffffffffp-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = "-0x1.0000000000000000000000000000p-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(!test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(-Smallest Normal) -> -Largest Denormal.
-    let test = unpack!(status=, "-0x1.0000000000000000000000000000p-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = "-0x0.ffffffffffffffffffffffffffffp-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(+Smallest Normal) -> +Largest Denormal.
-    let test = unpack!(status=, "+0x1.0000000000000000000000000000p-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = "+0x0.ffffffffffffffffffffffffffffp-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-
-    // 2b. Test normal <-> normal binade boundaries.
-    //     * nextUp(-Normal Binade Boundary) -> -Normal Binade Boundary + 1.
-    //     * nextDown(+Normal Binade Boundary) -> +Normal Binade Boundary - 1.
-    //     * nextUp(+Normal Binade Boundary - 1) -> +Normal Binade Boundary.
-    //     * nextDown(-Normal Binade Boundary + 1) -> -Normal Binade Boundary.
-
-    // nextUp(-Normal Binade Boundary) -> -Normal Binade Boundary + 1.
-    let test = unpack!(status=, "-0x1p+1".parse::<Quad>().unwrap().next_up());
-    let expected = "-0x1.ffffffffffffffffffffffffffffp+0".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(+Normal Binade Boundary) -> +Normal Binade Boundary - 1.
-    let test = unpack!(status=, "0x1p+1".parse::<Quad>().unwrap().next_down());
-    let expected = "0x1.ffffffffffffffffffffffffffffp+0".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(+Normal Binade Boundary - 1) -> +Normal Binade Boundary.
-    let test = unpack!(status=, "0x1.ffffffffffffffffffffffffffffp+0"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = "0x1p+1".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(-Normal Binade Boundary + 1) -> -Normal Binade Boundary.
-    let test = unpack!(status=, "-0x1.ffffffffffffffffffffffffffffp+0"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = "-0x1p+1".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // 2c. Test using next at binade boundaries with a direction away from the
-    // binade boundary. Away from denormal <-> normal boundaries.
-    //
-    // This is to make sure that even though we are at a binade boundary, since
-    // we are rounding away, we do not trigger the binade boundary code. Thus we
-    // test:
-    //   * nextUp(-Largest Denormal) -> -Largest Denormal + inc.
-    //   * nextDown(+Largest Denormal) -> +Largest Denormal - inc.
-    //   * nextUp(+Smallest Normal) -> +Smallest Normal + inc.
-    //   * nextDown(-Smallest Normal) -> -Smallest Normal - inc.
-
-    // nextUp(-Largest Denormal) -> -Largest Denormal + inc.
-    let test = unpack!(status=, "-0x0.ffffffffffffffffffffffffffffp-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = "-0x0.fffffffffffffffffffffffffffep-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.is_denormal());
-    assert!(test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(+Largest Denormal) -> +Largest Denormal - inc.
-    let test = unpack!(status=, "0x0.ffffffffffffffffffffffffffffp-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = "0x0.fffffffffffffffffffffffffffep-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.is_denormal());
-    assert!(!test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(+Smallest Normal) -> +Smallest Normal + inc.
-    let test = unpack!(status=, "0x1.0000000000000000000000000000p-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = "0x1.0000000000000000000000000001p-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(!test.is_denormal());
-    assert!(!test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(-Smallest Normal) -> -Smallest Normal - inc.
-    let test = unpack!(status=, "-0x1.0000000000000000000000000000p-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = "-0x1.0000000000000000000000000001p-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(!test.is_denormal());
-    assert!(test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // 2d. Test values which cause our exponent to go to min exponent. This
-    // is to ensure that guards in the code to check for min exponent
-    // trigger properly.
-    //     * nextUp(-0x1p-16381) -> -0x1.ffffffffffffffffffffffffffffp-16382
-    //     * nextDown(-0x1.ffffffffffffffffffffffffffffp-16382) ->
-    //         -0x1p-16381
-    //     * nextUp(0x1.ffffffffffffffffffffffffffffp-16382) -> 0x1p-16382
-    //     * nextDown(0x1p-16382) -> 0x1.ffffffffffffffffffffffffffffp-16382
-
-    // nextUp(-0x1p-16381) -> -0x1.ffffffffffffffffffffffffffffp-16382
-    let test = unpack!(status=, "-0x1p-16381".parse::<Quad>().unwrap().next_up());
-    let expected = "-0x1.ffffffffffffffffffffffffffffp-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(-0x1.ffffffffffffffffffffffffffffp-16382) ->
-    //         -0x1p-16381
-    let test = unpack!(status=, "-0x1.ffffffffffffffffffffffffffffp-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = "-0x1p-16381".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(0x1.ffffffffffffffffffffffffffffp-16382) -> 0x1p-16381
-    let test = unpack!(status=, "0x1.ffffffffffffffffffffffffffffp-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = "0x1p-16381".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(0x1p-16381) -> 0x1.ffffffffffffffffffffffffffffp-16382
-    let test = unpack!(status=, "0x1p-16381".parse::<Quad>().unwrap().next_down());
-    let expected = "0x1.ffffffffffffffffffffffffffffp-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // 3. Now we test both denormal/normal computation which will not cause us
-    // to go across binade boundaries. Specifically we test:
-    //   * nextUp(+Denormal) -> +Denormal.
-    //   * nextDown(+Denormal) -> +Denormal.
-    //   * nextUp(-Denormal) -> -Denormal.
-    //   * nextDown(-Denormal) -> -Denormal.
-    //   * nextUp(+Normal) -> +Normal.
-    //   * nextDown(+Normal) -> +Normal.
-    //   * nextUp(-Normal) -> -Normal.
-    //   * nextDown(-Normal) -> -Normal.
-
-    // nextUp(+Denormal) -> +Denormal.
-    let test = unpack!(status=, "0x0.ffffffffffffffffffffffff000cp-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = "0x0.ffffffffffffffffffffffff000dp-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.is_denormal());
-    assert!(!test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(+Denormal) -> +Denormal.
-    let test = unpack!(status=, "0x0.ffffffffffffffffffffffff000cp-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = "0x0.ffffffffffffffffffffffff000bp-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.is_denormal());
-    assert!(!test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(-Denormal) -> -Denormal.
-    let test = unpack!(status=, "-0x0.ffffffffffffffffffffffff000cp-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = "-0x0.ffffffffffffffffffffffff000bp-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.is_denormal());
-    assert!(test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(-Denormal) -> -Denormal
-    let test = unpack!(status=, "-0x0.ffffffffffffffffffffffff000cp-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = "-0x0.ffffffffffffffffffffffff000dp-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.is_denormal());
-    assert!(test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(+Normal) -> +Normal.
-    let test = unpack!(status=, "0x1.ffffffffffffffffffffffff000cp-16000"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = "0x1.ffffffffffffffffffffffff000dp-16000".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(!test.is_denormal());
-    assert!(!test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(+Normal) -> +Normal.
-    let test = unpack!(status=, "0x1.ffffffffffffffffffffffff000cp-16000"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = "0x1.ffffffffffffffffffffffff000bp-16000".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(!test.is_denormal());
-    assert!(!test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(-Normal) -> -Normal.
-    let test = unpack!(status=, "-0x1.ffffffffffffffffffffffff000cp-16000"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = "-0x1.ffffffffffffffffffffffff000bp-16000".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(!test.is_denormal());
-    assert!(test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(-Normal) -> -Normal.
-    let test = unpack!(status=, "-0x1.ffffffffffffffffffffffff000cp-16000"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = "-0x1.ffffffffffffffffffffffff000dp-16000".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(!test.is_denormal());
-    assert!(test.is_negative());
-    assert!(test.bitwise_eq(expected));
-}
-
-#[test]
-fn fma() {
-    {
-        let mut f1 = Single::from_f32(14.5);
-        let f2 = Single::from_f32(-14.5);
-        let f3 = Single::from_f32(225.0);
-        f1 = f1.mul_add(f2, f3).value;
-        assert_eq!(14.75, f1.to_f32());
-    }
-
-    {
-        let val2 = Single::from_f32(2.0);
-        let mut f1 = Single::from_f32(1.17549435e-38);
-        let mut f2 = Single::from_f32(1.17549435e-38);
-        f1 /= val2;
-        f2 /= val2;
-        let f3 = Single::from_f32(12.0);
-        f1 = f1.mul_add(f2, f3).value;
-        assert_eq!(12.0, f1.to_f32());
-    }
-
-    // Test for correct zero sign when answer is exactly zero.
-    // fma(1.0, -1.0, 1.0) -> +ve 0.
-    {
-        let mut f1 = Double::from_f64(1.0);
-        let f2 = Double::from_f64(-1.0);
-        let f3 = Double::from_f64(1.0);
-        f1 = f1.mul_add(f2, f3).value;
-        assert!(!f1.is_negative() && f1.is_zero());
-    }
-
-    // Test for correct zero sign when answer is exactly zero and rounding towards
-    // negative.
-    // fma(1.0, -1.0, 1.0) -> +ve 0.
-    {
-        let mut f1 = Double::from_f64(1.0);
-        let f2 = Double::from_f64(-1.0);
-        let f3 = Double::from_f64(1.0);
-        f1 = f1.mul_add_r(f2, f3, Round::TowardNegative).value;
-        assert!(f1.is_negative() && f1.is_zero());
-    }
-
-    // Test for correct (in this case -ve) sign when adding like signed zeros.
-    // Test fma(0.0, -0.0, -0.0) -> -ve 0.
-    {
-        let mut f1 = Double::from_f64(0.0);
-        let f2 = Double::from_f64(-0.0);
-        let f3 = Double::from_f64(-0.0);
-        f1 = f1.mul_add(f2, f3).value;
-        assert!(f1.is_negative() && f1.is_zero());
-    }
-
-    // Test -ve sign preservation when small negative results underflow.
-    {
-        let mut f1 = "-0x1p-1074".parse::<Double>().unwrap();
-        let f2 = "+0x1p-1074".parse::<Double>().unwrap();
-        let f3 = Double::from_f64(0.0);
-        f1 = f1.mul_add(f2, f3).value;
-        assert!(f1.is_negative() && f1.is_zero());
-    }
-
-    // Test x87 extended precision case from https://llvm.org/PR20728.
-    {
-        let mut m1 = X87DoubleExtended::from_u128(1).value;
-        let m2 = X87DoubleExtended::from_u128(1).value;
-        let a = X87DoubleExtended::from_u128(3).value;
-
-        let mut loses_info = false;
-        m1 = m1.mul_add(m2, a).value;
-        let r: Single = m1.convert(&mut loses_info).value;
-        assert!(!loses_info);
-        assert_eq!(4.0, r.to_f32());
-    }
-}
-
-#[test]
-fn issue_69532() {
-    let f = Double::from_bits(0x7FF0_0000_0000_0001u64 as u128);
-    let mut loses_info = false;
-    let sta = f.convert(&mut loses_info);
-    let r: Single = sta.value;
-    assert!(loses_info);
-    assert!(r.is_nan());
-    assert_eq!(sta.status, Status::INVALID_OP);
-}
-
-#[test]
-fn min_num() {
-    let f1 = Double::from_f64(1.0);
-    let f2 = Double::from_f64(2.0);
-    let nan = Double::NAN;
-
-    assert_eq!(1.0, f1.min(f2).to_f64());
-    assert_eq!(1.0, f2.min(f1).to_f64());
-    assert_eq!(1.0, f1.min(nan).to_f64());
-    assert_eq!(1.0, nan.min(f1).to_f64());
-}
-
-#[test]
-fn max_num() {
-    let f1 = Double::from_f64(1.0);
-    let f2 = Double::from_f64(2.0);
-    let nan = Double::NAN;
-
-    assert_eq!(2.0, f1.max(f2).to_f64());
-    assert_eq!(2.0, f2.max(f1).to_f64());
-    assert_eq!(1.0, f1.max(nan).to_f64());
-    assert_eq!(1.0, nan.max(f1).to_f64());
-}
-
-#[test]
-fn denormal() {
-    // Test single precision
-    {
-        assert!(!Single::from_f32(0.0).is_denormal());
-
-        let mut t = "1.17549435082228750797e-38".parse::<Single>().unwrap();
-        assert!(!t.is_denormal());
-
-        let val2 = Single::from_f32(2.0e0);
-        t /= val2;
-        assert!(t.is_denormal());
-    }
-
-    // Test double precision
-    {
-        assert!(!Double::from_f64(0.0).is_denormal());
-
-        let mut t = "2.22507385850720138309e-308".parse::<Double>().unwrap();
-        assert!(!t.is_denormal());
-
-        let val2 = Double::from_f64(2.0e0);
-        t /= val2;
-        assert!(t.is_denormal());
-    }
-
-    // Test Intel double-ext
-    {
-        assert!(!X87DoubleExtended::from_u128(0).value.is_denormal());
-
-        let mut t = "3.36210314311209350626e-4932".parse::<X87DoubleExtended>().unwrap();
-        assert!(!t.is_denormal());
-
-        t /= X87DoubleExtended::from_u128(2).value;
-        assert!(t.is_denormal());
-    }
-
-    // Test quadruple precision
-    {
-        assert!(!Quad::from_u128(0).value.is_denormal());
-
-        let mut t = "3.36210314311209350626267781732175260e-4932".parse::<Quad>().unwrap();
-        assert!(!t.is_denormal());
-
-        t /= Quad::from_u128(2).value;
-        assert!(t.is_denormal());
-    }
-}
-
-#[test]
-fn decimal_strings_without_null_terminators() {
-    // Make sure that we can parse strings without null terminators.
-    // rdar://14323230.
-    let val = "0.00"[..3].parse::<Double>().unwrap();
-    assert_eq!(val.to_f64(), 0.0);
-    let val = "0.01"[..3].parse::<Double>().unwrap();
-    assert_eq!(val.to_f64(), 0.0);
-    let val = "0.09"[..3].parse::<Double>().unwrap();
-    assert_eq!(val.to_f64(), 0.0);
-    let val = "0.095"[..4].parse::<Double>().unwrap();
-    assert_eq!(val.to_f64(), 0.09);
-    let val = "0.00e+3"[..7].parse::<Double>().unwrap();
-    assert_eq!(val.to_f64(), 0.00);
-    let val = "0e+3"[..4].parse::<Double>().unwrap();
-    assert_eq!(val.to_f64(), 0.00);
-}
-
-#[test]
-fn from_zero_decimal_string() {
-    assert_eq!(0.0, "0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0.".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0.".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0.".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, ".0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+.0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-.0".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0.0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0.0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0.0".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "00000.".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+00000.".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-00000.".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, ".00000".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+.00000".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-.00000".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0000.00000".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0000.00000".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0000.00000".parse::<Double>().unwrap().to_f64());
-}
-
-#[test]
-fn from_zero_decimal_single_exponent_string() {
-    assert_eq!(0.0, "0e1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0e1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0e1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0e+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0e+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0e+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0e-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0e-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0e-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0.e1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0.e1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0.e1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0.e+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0.e+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0.e+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0.e-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0.e-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0.e-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, ".0e1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+.0e1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-.0e1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, ".0e+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+.0e+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-.0e+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, ".0e-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+.0e-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-.0e-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0.0e1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0.0e1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0.0e1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0.0e+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0.0e+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0.0e+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0.0e-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0.0e-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0.0e-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "000.0000e1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+000.0000e+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-000.0000e+1".parse::<Double>().unwrap().to_f64());
-}
-
-#[test]
-fn from_zero_decimal_large_exponent_string() {
-    assert_eq!(0.0, "0e1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0e1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0e1234".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0e+1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0e+1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0e+1234".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0e-1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0e-1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0e-1234".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "000.0000e1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "000.0000e-1234".parse::<Double>().unwrap().to_f64());
-}
-
-#[test]
-fn from_zero_hexadecimal_string() {
-    assert_eq!(0.0, "0x0p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x0p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x0p1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x0p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x0p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x0p+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x0p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x0p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x0p-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x0.p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x0.p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x0.p1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x0.p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x0.p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x0.p+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x0.p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x0.p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x0.p-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x.0p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x.0p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x.0p1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x.0p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x.0p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x.0p+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x.0p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x.0p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x.0p-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x0.0p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x0.0p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x0.0p1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x0.0p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x0.0p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x0.0p+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x0.0p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x0.0p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x0.0p-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x00000.p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "0x0000.00000p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "0x.00000p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "0x0.p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "0x0p1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x0p1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "0x00000.p1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "0x0000.00000p1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "0x.00000p1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "0x0.p1234".parse::<Double>().unwrap().to_f64());
-}
-
-#[test]
-fn from_decimal_string() {
-    assert_eq!(1.0, "1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.0, "2.".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.5, ".5".parse::<Double>().unwrap().to_f64());
-    assert_eq!(1.0, "1.0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-2.0, "-2".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-4.0, "-4.".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.5, "-.5".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-1.5, "-1.5".parse::<Double>().unwrap().to_f64());
-    assert_eq!(1.25e12, "1.25e12".parse::<Double>().unwrap().to_f64());
-    assert_eq!(1.25e+12, "1.25e+12".parse::<Double>().unwrap().to_f64());
-    assert_eq!(1.25e-12, "1.25e-12".parse::<Double>().unwrap().to_f64());
-    assert_eq!(1024.0, "1024.".parse::<Double>().unwrap().to_f64());
-    assert_eq!(1024.05, "1024.05000".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.05, ".05000".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.0, "2.".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.0e2, "2.e2".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.0e+2, "2.e+2".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.0e-2, "2.e-2".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.05e2, "002.05000e2".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.05e+2, "002.05000e+2".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.05e-2, "002.05000e-2".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.05e12, "002.05000e12".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.05e+12, "002.05000e+12".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.05e-12, "002.05000e-12".parse::<Double>().unwrap().to_f64());
-
-    // These are "carefully selected" to overflow the fast log-base
-    // calculations in the implementation.
-    assert!("99e99999".parse::<Double>().unwrap().is_infinite());
-    assert!("-99e99999".parse::<Double>().unwrap().is_infinite());
-    assert!("1e-99999".parse::<Double>().unwrap().is_pos_zero());
-    assert!("-1e-99999".parse::<Double>().unwrap().is_neg_zero());
-
-    assert_eq!(2.71828, "2.71828".parse::<Double>().unwrap().to_f64());
-}
-
-#[test]
-fn from_hexadecimal_string() {
-    assert_eq!(1.0, "0x1p0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(1.0, "+0x1p0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-1.0, "-0x1p0".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(1.0, "0x1p+0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(1.0, "+0x1p+0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-1.0, "-0x1p+0".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(1.0, "0x1p-0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(1.0, "+0x1p-0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-1.0, "-0x1p-0".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(2.0, "0x1p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.0, "+0x1p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-2.0, "-0x1p1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(2.0, "0x1p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.0, "+0x1p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-2.0, "-0x1p+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.5, "0x1p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.5, "+0x1p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.5, "-0x1p-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(3.0, "0x1.8p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(3.0, "+0x1.8p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-3.0, "-0x1.8p1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(3.0, "0x1.8p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(3.0, "+0x1.8p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-3.0, "-0x1.8p+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.75, "0x1.8p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.75, "+0x1.8p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.75, "-0x1.8p-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(8192.0, "0x1000.000p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(8192.0, "+0x1000.000p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-8192.0, "-0x1000.000p1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(8192.0, "0x1000.000p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(8192.0, "+0x1000.000p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-8192.0, "-0x1000.000p+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(2048.0, "0x1000.000p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2048.0, "+0x1000.000p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-2048.0, "-0x1000.000p-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(8192.0, "0x1000p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(8192.0, "+0x1000p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-8192.0, "-0x1000p1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(8192.0, "0x1000p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(8192.0, "+0x1000p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-8192.0, "-0x1000p+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(2048.0, "0x1000p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2048.0, "+0x1000p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-2048.0, "-0x1000p-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(16384.0, "0x10p10".parse::<Double>().unwrap().to_f64());
-    assert_eq!(16384.0, "+0x10p10".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-16384.0, "-0x10p10".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(16384.0, "0x10p+10".parse::<Double>().unwrap().to_f64());
-    assert_eq!(16384.0, "+0x10p+10".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-16384.0, "-0x10p+10".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.015625, "0x10p-10".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.015625, "+0x10p-10".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.015625, "-0x10p-10".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(1.0625, "0x1.1p0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(1.0, "0x1p0".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(
-        "0x1p-150".parse::<Double>().unwrap().to_f64(),
-        "+0x800000000000000001.p-221".parse::<Double>().unwrap().to_f64()
-    );
-    assert_eq!(
-        2251799813685248.5,
-        "0x80000000000004000000.010p-28".parse::<Double>().unwrap().to_f64()
-    );
-}
-
-#[test]
-fn to_string() {
-    let to_string = |d: f64, precision: usize, width: usize| {
-        let x = Double::from_f64(d);
-        if precision == 0 {
-            format!("{:1$}", x, width)
-        } else {
-            format!("{:2$.1$}", x, precision, width)
-        }
-    };
-    assert_eq!("10", to_string(10.0, 6, 3));
-    assert_eq!("1.0E+1", to_string(10.0, 6, 0));
-    assert_eq!("10100", to_string(1.01E+4, 5, 2));
-    assert_eq!("1.01E+4", to_string(1.01E+4, 4, 2));
-    assert_eq!("1.01E+4", to_string(1.01E+4, 5, 1));
-    assert_eq!("0.0101", to_string(1.01E-2, 5, 2));
-    assert_eq!("0.0101", to_string(1.01E-2, 4, 2));
-    assert_eq!("1.01E-2", to_string(1.01E-2, 5, 1));
-    assert_eq!("0.78539816339744828", to_string(0.78539816339744830961, 0, 3));
-    assert_eq!("4.9406564584124654E-324", to_string(4.9406564584124654e-324, 0, 3));
-    assert_eq!("873.18340000000001", to_string(873.1834, 0, 1));
-    assert_eq!("8.7318340000000001E+2", to_string(873.1834, 0, 0));
-    assert_eq!("1.7976931348623157E+308", to_string(1.7976931348623157E+308, 0, 0));
-
-    let to_string = |d: f64, precision: usize, width: usize| {
-        let x = Double::from_f64(d);
-        if precision == 0 {
-            format!("{:#1$}", x, width)
-        } else {
-            format!("{:#2$.1$}", x, precision, width)
-        }
-    };
-    assert_eq!("10", to_string(10.0, 6, 3));
-    assert_eq!("1.000000e+01", to_string(10.0, 6, 0));
-    assert_eq!("10100", to_string(1.01E+4, 5, 2));
-    assert_eq!("1.0100e+04", to_string(1.01E+4, 4, 2));
-    assert_eq!("1.01000e+04", to_string(1.01E+4, 5, 1));
-    assert_eq!("0.0101", to_string(1.01E-2, 5, 2));
-    assert_eq!("0.0101", to_string(1.01E-2, 4, 2));
-    assert_eq!("1.01000e-02", to_string(1.01E-2, 5, 1));
-    assert_eq!("0.78539816339744828", to_string(0.78539816339744830961, 0, 3));
-    assert_eq!("4.94065645841246540e-324", to_string(4.9406564584124654e-324, 0, 3));
-    assert_eq!("873.18340000000001", to_string(873.1834, 0, 1));
-    assert_eq!("8.73183400000000010e+02", to_string(873.1834, 0, 0));
-    assert_eq!("1.79769313486231570e+308", to_string(1.7976931348623157E+308, 0, 0));
-}
-
-#[test]
-fn to_integer() {
-    let mut is_exact = false;
-
-    assert_eq!(
-        Status::OK.and(10),
-        "10".parse::<Double>().unwrap().to_u128_r(5, Round::TowardZero, &mut is_exact,)
-    );
-    assert!(is_exact);
-
-    assert_eq!(
-        Status::INVALID_OP.and(0),
-        "-10".parse::<Double>().unwrap().to_u128_r(5, Round::TowardZero, &mut is_exact,)
-    );
-    assert!(!is_exact);
-
-    assert_eq!(
-        Status::INVALID_OP.and(31),
-        "32".parse::<Double>().unwrap().to_u128_r(5, Round::TowardZero, &mut is_exact,)
-    );
-    assert!(!is_exact);
-
-    assert_eq!(
-        Status::INEXACT.and(7),
-        "7.9".parse::<Double>().unwrap().to_u128_r(5, Round::TowardZero, &mut is_exact,)
-    );
-    assert!(!is_exact);
-
-    assert_eq!(
-        Status::OK.and(-10),
-        "-10".parse::<Double>().unwrap().to_i128_r(5, Round::TowardZero, &mut is_exact,)
-    );
-    assert!(is_exact);
-
-    assert_eq!(
-        Status::INVALID_OP.and(-16),
-        "-17".parse::<Double>().unwrap().to_i128_r(5, Round::TowardZero, &mut is_exact,)
-    );
-    assert!(!is_exact);
-
-    assert_eq!(
-        Status::INVALID_OP.and(15),
-        "16".parse::<Double>().unwrap().to_i128_r(5, Round::TowardZero, &mut is_exact,)
-    );
-    assert!(!is_exact);
-}
-
-#[test]
-fn nan() {
-    fn nanbits<T: Float>(signaling: bool, negative: bool, fill: u128) -> u128 {
-        let x = if signaling { T::snan(Some(fill)) } else { T::qnan(Some(fill)) };
-        if negative { (-x).to_bits() } else { x.to_bits() }
-    }
-
-    assert_eq!(0x7fc00000, nanbits::<Single>(false, false, 0));
-    assert_eq!(0xffc00000, nanbits::<Single>(false, true, 0));
-    assert_eq!(0x7fc0ae72, nanbits::<Single>(false, false, 0xae72));
-    assert_eq!(0x7fffae72, nanbits::<Single>(false, false, 0xffffae72));
-    assert_eq!(0x7fa00000, nanbits::<Single>(true, false, 0));
-    assert_eq!(0xffa00000, nanbits::<Single>(true, true, 0));
-    assert_eq!(0x7f80ae72, nanbits::<Single>(true, false, 0xae72));
-    assert_eq!(0x7fbfae72, nanbits::<Single>(true, false, 0xffffae72));
-
-    assert_eq!(0x7ff8000000000000, nanbits::<Double>(false, false, 0));
-    assert_eq!(0xfff8000000000000, nanbits::<Double>(false, true, 0));
-    assert_eq!(0x7ff800000000ae72, nanbits::<Double>(false, false, 0xae72));
-    assert_eq!(0x7fffffffffffae72, nanbits::<Double>(false, false, 0xffffffffffffae72));
-    assert_eq!(0x7ff4000000000000, nanbits::<Double>(true, false, 0));
-    assert_eq!(0xfff4000000000000, nanbits::<Double>(true, true, 0));
-    assert_eq!(0x7ff000000000ae72, nanbits::<Double>(true, false, 0xae72));
-    assert_eq!(0x7ff7ffffffffae72, nanbits::<Double>(true, false, 0xffffffffffffae72));
-}
-
-#[test]
-fn string_decimal_death() {
-    assert_eq!("".parse::<Double>(), Err(ParseError("Invalid string length")));
-    assert_eq!("+".parse::<Double>(), Err(ParseError("String has no digits")));
-    assert_eq!("-".parse::<Double>(), Err(ParseError("String has no digits")));
-
-    assert_eq!("\0".parse::<Double>(), Err(ParseError("Invalid character in significand")));
-    assert_eq!("1\0".parse::<Double>(), Err(ParseError("Invalid character in significand")));
-    assert_eq!("1\02".parse::<Double>(), Err(ParseError("Invalid character in significand")));
-    assert_eq!("1\02e1".parse::<Double>(), Err(ParseError("Invalid character in significand")));
-    assert_eq!("1e\0".parse::<Double>(), Err(ParseError("Invalid character in exponent")));
-    assert_eq!("1e1\0".parse::<Double>(), Err(ParseError("Invalid character in exponent")));
-    assert_eq!("1e1\02".parse::<Double>(), Err(ParseError("Invalid character in exponent")));
-
-    assert_eq!("1.0f".parse::<Double>(), Err(ParseError("Invalid character in significand")));
-
-    assert_eq!("..".parse::<Double>(), Err(ParseError("String contains multiple dots")));
-    assert_eq!("..0".parse::<Double>(), Err(ParseError("String contains multiple dots")));
-    assert_eq!("1.0.0".parse::<Double>(), Err(ParseError("String contains multiple dots")));
-}
-
-#[test]
-fn string_decimal_significand_death() {
-    assert_eq!(".".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+.".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-.".parse::<Double>(), Err(ParseError("Significand has no digits")));
-
-    assert_eq!("e".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+e".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-e".parse::<Double>(), Err(ParseError("Significand has no digits")));
-
-    assert_eq!("e1".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+e1".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-e1".parse::<Double>(), Err(ParseError("Significand has no digits")));
-
-    assert_eq!(".e1".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+.e1".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-.e1".parse::<Double>(), Err(ParseError("Significand has no digits")));
-
-    assert_eq!(".e".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+.e".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-.e".parse::<Double>(), Err(ParseError("Significand has no digits")));
-}
-
-#[test]
-fn string_decimal_exponent_death() {
-    assert_eq!("1e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+1e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-1e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("1.e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+1.e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-1.e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!(".1e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+.1e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-.1e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("1.1e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+1.1e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-1.1e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("1e+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("1e-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!(".1e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!(".1e+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!(".1e-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("1.0e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("1.0e+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("1.0e-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-}
-
-#[test]
-fn string_hexadecimal_death() {
-    assert_eq!("0x".parse::<Double>(), Err(ParseError("Invalid string")));
-    assert_eq!("+0x".parse::<Double>(), Err(ParseError("Invalid string")));
-    assert_eq!("-0x".parse::<Double>(), Err(ParseError("Invalid string")));
-
-    assert_eq!("0x0".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-    assert_eq!("+0x0".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-    assert_eq!("-0x0".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-
-    assert_eq!("0x0.".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-    assert_eq!("+0x0.".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-    assert_eq!("-0x0.".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-
-    assert_eq!("0x.0".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-    assert_eq!("+0x.0".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-    assert_eq!("-0x.0".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-
-    assert_eq!("0x0.0".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-    assert_eq!("+0x0.0".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-    assert_eq!("-0x0.0".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-
-    assert_eq!("0x\0".parse::<Double>(), Err(ParseError("Invalid character in significand")));
-    assert_eq!("0x1\0".parse::<Double>(), Err(ParseError("Invalid character in significand")));
-    assert_eq!("0x1\02".parse::<Double>(), Err(ParseError("Invalid character in significand")));
-    assert_eq!("0x1\02p1".parse::<Double>(), Err(ParseError("Invalid character in significand")));
-    assert_eq!("0x1p\0".parse::<Double>(), Err(ParseError("Invalid character in exponent")));
-    assert_eq!("0x1p1\0".parse::<Double>(), Err(ParseError("Invalid character in exponent")));
-    assert_eq!("0x1p1\02".parse::<Double>(), Err(ParseError("Invalid character in exponent")));
-
-    assert_eq!("0x1p0f".parse::<Double>(), Err(ParseError("Invalid character in exponent")));
-
-    assert_eq!("0x..p1".parse::<Double>(), Err(ParseError("String contains multiple dots")));
-    assert_eq!("0x..0p1".parse::<Double>(), Err(ParseError("String contains multiple dots")));
-    assert_eq!("0x1.0.0p1".parse::<Double>(), Err(ParseError("String contains multiple dots")));
-}
-
-#[test]
-fn string_hexadecimal_significand_death() {
-    assert_eq!("0x.".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+0x.".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-0x.".parse::<Double>(), Err(ParseError("Significand has no digits")));
-
-    assert_eq!("0xp".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+0xp".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-0xp".parse::<Double>(), Err(ParseError("Significand has no digits")));
-
-    assert_eq!("0xp+".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+0xp+".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-0xp+".parse::<Double>(), Err(ParseError("Significand has no digits")));
-
-    assert_eq!("0xp-".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+0xp-".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-0xp-".parse::<Double>(), Err(ParseError("Significand has no digits")));
-
-    assert_eq!("0x.p".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+0x.p".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-0x.p".parse::<Double>(), Err(ParseError("Significand has no digits")));
-
-    assert_eq!("0x.p+".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+0x.p+".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-0x.p+".parse::<Double>(), Err(ParseError("Significand has no digits")));
-
-    assert_eq!("0x.p-".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+0x.p-".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-0x.p-".parse::<Double>(), Err(ParseError("Significand has no digits")));
-}
-
-#[test]
-fn string_hexadecimal_exponent_death() {
-    assert_eq!("0x1p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x1p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x1p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("0x1p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x1p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x1p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("0x1p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x1p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x1p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("0x1.p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x1.p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x1.p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("0x1.p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x1.p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x1.p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("0x1.p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x1.p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x1.p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("0x.1p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x.1p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x.1p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("0x.1p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x.1p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x.1p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("0x.1p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x.1p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x.1p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("0x1.1p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x1.1p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x1.1p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("0x1.1p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x1.1p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x1.1p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("0x1.1p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x1.1p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x1.1p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-}
-
-#[test]
-fn exact_inverse() {
-    // Trivial operation.
-    assert!(Double::from_f64(2.0).get_exact_inverse().unwrap().bitwise_eq(Double::from_f64(0.5)));
-    assert!(Single::from_f32(2.0).get_exact_inverse().unwrap().bitwise_eq(Single::from_f32(0.5)));
-    assert!(
-        "2.0"
-            .parse::<Quad>()
-            .unwrap()
-            .get_exact_inverse()
-            .unwrap()
-            .bitwise_eq("0.5".parse::<Quad>().unwrap())
-    );
-    assert!(
-        "2.0"
-            .parse::<X87DoubleExtended>()
-            .unwrap()
-            .get_exact_inverse()
-            .unwrap()
-            .bitwise_eq("0.5".parse::<X87DoubleExtended>().unwrap())
-    );
-
-    // FLT_MIN
-    assert!(
-        Single::from_f32(1.17549435e-38)
-            .get_exact_inverse()
-            .unwrap()
-            .bitwise_eq(Single::from_f32(8.5070592e+37))
-    );
-
-    // Large float, inverse is a denormal.
-    assert!(Single::from_f32(1.7014118e38).get_exact_inverse().is_none());
-    // Zero
-    assert!(Double::from_f64(0.0).get_exact_inverse().is_none());
-    // Denormalized float
-    assert!(Single::from_f32(1.40129846e-45).get_exact_inverse().is_none());
-}
-
-#[test]
-fn round_to_integral() {
-    let t = Double::from_f64(-0.5);
-    assert_eq!(-0.0, t.round_to_integral(Round::TowardZero).value.to_f64());
-    assert_eq!(-1.0, t.round_to_integral(Round::TowardNegative).value.to_f64());
-    assert_eq!(-0.0, t.round_to_integral(Round::TowardPositive).value.to_f64());
-    assert_eq!(-0.0, t.round_to_integral(Round::NearestTiesToEven).value.to_f64());
-
-    let s = Double::from_f64(3.14);
-    assert_eq!(3.0, s.round_to_integral(Round::TowardZero).value.to_f64());
-    assert_eq!(3.0, s.round_to_integral(Round::TowardNegative).value.to_f64());
-    assert_eq!(4.0, s.round_to_integral(Round::TowardPositive).value.to_f64());
-    assert_eq!(3.0, s.round_to_integral(Round::NearestTiesToEven).value.to_f64());
-
-    let r = Double::largest();
-    assert_eq!(r.to_f64(), r.round_to_integral(Round::TowardZero).value.to_f64());
-    assert_eq!(r.to_f64(), r.round_to_integral(Round::TowardNegative).value.to_f64());
-    assert_eq!(r.to_f64(), r.round_to_integral(Round::TowardPositive).value.to_f64());
-    assert_eq!(r.to_f64(), r.round_to_integral(Round::NearestTiesToEven).value.to_f64());
-
-    let p = Double::ZERO.round_to_integral(Round::TowardZero).value;
-    assert_eq!(0.0, p.to_f64());
-    let p = (-Double::ZERO).round_to_integral(Round::TowardZero).value;
-    assert_eq!(-0.0, p.to_f64());
-    let p = Double::NAN.round_to_integral(Round::TowardZero).value;
-    assert!(p.to_f64().is_nan());
-    let p = Double::INFINITY.round_to_integral(Round::TowardZero).value;
-    assert!(p.to_f64().is_infinite() && p.to_f64() > 0.0);
-    let p = (-Double::INFINITY).round_to_integral(Round::TowardZero).value;
-    assert!(p.to_f64().is_infinite() && p.to_f64() < 0.0);
-}
-
-#[test]
-fn is_integer() {
-    let t = Double::from_f64(-0.0);
-    assert!(t.is_integer());
-    let t = Double::from_f64(3.14159);
-    assert!(!t.is_integer());
-    let t = Double::NAN;
-    assert!(!t.is_integer());
-    let t = Double::INFINITY;
-    assert!(!t.is_integer());
-    let t = -Double::INFINITY;
-    assert!(!t.is_integer());
-    let t = Double::largest();
-    assert!(t.is_integer());
-}
-
-#[test]
-fn largest() {
-    assert_eq!(3.402823466e+38, Single::largest().to_f32());
-    assert_eq!(1.7976931348623158e+308, Double::largest().to_f64());
-}
-
-#[test]
-fn smallest() {
-    let test = Single::SMALLEST;
-    let expected = "0x0.000002p-126".parse::<Single>().unwrap();
-    assert!(!test.is_negative());
-    assert!(test.is_finite_non_zero());
-    assert!(test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-
-    let test = -Single::SMALLEST;
-    let expected = "-0x0.000002p-126".parse::<Single>().unwrap();
-    assert!(test.is_negative());
-    assert!(test.is_finite_non_zero());
-    assert!(test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-
-    let test = Quad::SMALLEST;
-    let expected = "0x0.0000000000000000000000000001p-16382".parse::<Quad>().unwrap();
-    assert!(!test.is_negative());
-    assert!(test.is_finite_non_zero());
-    assert!(test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-
-    let test = -Quad::SMALLEST;
-    let expected = "-0x0.0000000000000000000000000001p-16382".parse::<Quad>().unwrap();
-    assert!(test.is_negative());
-    assert!(test.is_finite_non_zero());
-    assert!(test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-}
-
-#[test]
-fn smallest_normalized() {
-    let test = Single::smallest_normalized();
-    let expected = "0x1p-126".parse::<Single>().unwrap();
-    assert!(!test.is_negative());
-    assert!(test.is_finite_non_zero());
-    assert!(!test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-
-    let test = -Single::smallest_normalized();
-    let expected = "-0x1p-126".parse::<Single>().unwrap();
-    assert!(test.is_negative());
-    assert!(test.is_finite_non_zero());
-    assert!(!test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-
-    let test = Quad::smallest_normalized();
-    let expected = "0x1p-16382".parse::<Quad>().unwrap();
-    assert!(!test.is_negative());
-    assert!(test.is_finite_non_zero());
-    assert!(!test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-
-    let test = -Quad::smallest_normalized();
-    let expected = "-0x1p-16382".parse::<Quad>().unwrap();
-    assert!(test.is_negative());
-    assert!(test.is_finite_non_zero());
-    assert!(!test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-}
-
-#[test]
-fn zero() {
-    assert_eq!(0.0, Single::from_f32(0.0).to_f32());
-    assert_eq!(-0.0, Single::from_f32(-0.0).to_f32());
-    assert!(Single::from_f32(-0.0).is_negative());
-
-    assert_eq!(0.0, Double::from_f64(0.0).to_f64());
-    assert_eq!(-0.0, Double::from_f64(-0.0).to_f64());
-    assert!(Double::from_f64(-0.0).is_negative());
-
-    fn test<T: Float>(sign: bool, bits: u128) {
-        let test = if sign { -T::ZERO } else { T::ZERO };
-        let pattern = if sign { "-0x0p+0" } else { "0x0p+0" };
-        let expected = pattern.parse::<T>().unwrap();
-        assert!(test.is_zero());
-        assert_eq!(sign, test.is_negative());
-        assert!(test.bitwise_eq(expected));
-        assert_eq!(bits, test.to_bits());
-    }
-    test::<Half>(false, 0);
-    test::<Half>(true, 0x8000);
-    test::<Single>(false, 0);
-    test::<Single>(true, 0x80000000);
-    test::<Double>(false, 0);
-    test::<Double>(true, 0x8000000000000000);
-    test::<Quad>(false, 0);
-    test::<Quad>(true, 0x8000000000000000_0000000000000000);
-    test::<X87DoubleExtended>(false, 0);
-    test::<X87DoubleExtended>(true, 0x8000_0000000000000000);
-}
-
-#[test]
-fn copy_sign() {
-    assert!(
-        Double::from_f64(-42.0)
-            .bitwise_eq(Double::from_f64(42.0).copy_sign(Double::from_f64(-1.0),),)
-    );
-    assert!(
-        Double::from_f64(42.0)
-            .bitwise_eq(Double::from_f64(-42.0).copy_sign(Double::from_f64(1.0),),)
-    );
-    assert!(
-        Double::from_f64(-42.0)
-            .bitwise_eq(Double::from_f64(-42.0).copy_sign(Double::from_f64(-1.0),),)
-    );
-    assert!(
-        Double::from_f64(42.0)
-            .bitwise_eq(Double::from_f64(42.0).copy_sign(Double::from_f64(1.0),),)
-    );
-}
-
-#[test]
-fn convert() {
-    let mut loses_info = false;
-    let test = "1.0".parse::<Double>().unwrap();
-    let test: Single = test.convert(&mut loses_info).value;
-    assert_eq!(1.0, test.to_f32());
-    assert!(!loses_info);
-
-    let mut test = "0x1p-53".parse::<X87DoubleExtended>().unwrap();
-    let one = "1.0".parse::<X87DoubleExtended>().unwrap();
-    test += one;
-    let test: Double = test.convert(&mut loses_info).value;
-    assert_eq!(1.0, test.to_f64());
-    assert!(loses_info);
-
-    let mut test = "0x1p-53".parse::<Quad>().unwrap();
-    let one = "1.0".parse::<Quad>().unwrap();
-    test += one;
-    let test: Double = test.convert(&mut loses_info).value;
-    assert_eq!(1.0, test.to_f64());
-    assert!(loses_info);
-
-    let test = "0xf.fffffffp+28".parse::<X87DoubleExtended>().unwrap();
-    let test: Double = test.convert(&mut loses_info).value;
-    assert_eq!(4294967295.0, test.to_f64());
-    assert!(!loses_info);
-
-    let test = Single::qnan(None);
-    let x87_qnan = X87DoubleExtended::qnan(None);
-    let test: X87DoubleExtended = test.convert(&mut loses_info).value;
-    assert!(test.bitwise_eq(x87_qnan));
-    assert!(!loses_info);
-
-    let test = Single::snan(None);
-    let sta = test.convert(&mut loses_info);
-    let test: X87DoubleExtended = sta.value;
-    assert!(test.is_nan());
-    assert!(!test.is_signaling());
-    assert!(!loses_info);
-    assert_eq!(sta.status, Status::INVALID_OP);
-
-    let test = X87DoubleExtended::qnan(None);
-    let test: X87DoubleExtended = test.convert(&mut loses_info).value;
-    assert!(test.bitwise_eq(x87_qnan));
-    assert!(!loses_info);
-
-    let test = X87DoubleExtended::snan(None);
-    let sta = test.convert(&mut loses_info);
-    let test: X87DoubleExtended = sta.value;
-    assert!(test.is_nan());
-    assert!(!test.is_signaling());
-    assert!(!loses_info);
-    assert_eq!(sta.status, Status::INVALID_OP);
-}
-
-#[test]
-fn is_negative() {
-    let t = "0x1p+0".parse::<Single>().unwrap();
-    assert!(!t.is_negative());
-    let t = "-0x1p+0".parse::<Single>().unwrap();
-    assert!(t.is_negative());
-
-    assert!(!Single::INFINITY.is_negative());
-    assert!((-Single::INFINITY).is_negative());
-
-    assert!(!Single::ZERO.is_negative());
-    assert!((-Single::ZERO).is_negative());
-
-    assert!(!Single::NAN.is_negative());
-    assert!((-Single::NAN).is_negative());
-
-    assert!(!Single::snan(None).is_negative());
-    assert!((-Single::snan(None)).is_negative());
-}
-
-#[test]
-fn is_normal() {
-    let t = "0x1p+0".parse::<Single>().unwrap();
-    assert!(t.is_normal());
-
-    assert!(!Single::INFINITY.is_normal());
-    assert!(!Single::ZERO.is_normal());
-    assert!(!Single::NAN.is_normal());
-    assert!(!Single::snan(None).is_normal());
-    assert!(!"0x1p-149".parse::<Single>().unwrap().is_normal());
-}
-
-#[test]
-fn is_finite() {
-    let t = "0x1p+0".parse::<Single>().unwrap();
-    assert!(t.is_finite());
-    assert!(!Single::INFINITY.is_finite());
-    assert!(Single::ZERO.is_finite());
-    assert!(!Single::NAN.is_finite());
-    assert!(!Single::snan(None).is_finite());
-    assert!("0x1p-149".parse::<Single>().unwrap().is_finite());
-}
-
-#[test]
-fn is_infinite() {
-    let t = "0x1p+0".parse::<Single>().unwrap();
-    assert!(!t.is_infinite());
-    assert!(Single::INFINITY.is_infinite());
-    assert!(!Single::ZERO.is_infinite());
-    assert!(!Single::NAN.is_infinite());
-    assert!(!Single::snan(None).is_infinite());
-    assert!(!"0x1p-149".parse::<Single>().unwrap().is_infinite());
-}
-
-#[test]
-fn is_nan() {
-    let t = "0x1p+0".parse::<Single>().unwrap();
-    assert!(!t.is_nan());
-    assert!(!Single::INFINITY.is_nan());
-    assert!(!Single::ZERO.is_nan());
-    assert!(Single::NAN.is_nan());
-    assert!(Single::snan(None).is_nan());
-    assert!(!"0x1p-149".parse::<Single>().unwrap().is_nan());
-}
-
-#[test]
-fn is_finite_non_zero() {
-    // Test positive/negative normal value.
-    assert!("0x1p+0".parse::<Single>().unwrap().is_finite_non_zero());
-    assert!("-0x1p+0".parse::<Single>().unwrap().is_finite_non_zero());
-
-    // Test positive/negative denormal value.
-    assert!("0x1p-149".parse::<Single>().unwrap().is_finite_non_zero());
-    assert!("-0x1p-149".parse::<Single>().unwrap().is_finite_non_zero());
-
-    // Test +/- Infinity.
-    assert!(!Single::INFINITY.is_finite_non_zero());
-    assert!(!(-Single::INFINITY).is_finite_non_zero());
-
-    // Test +/- Zero.
-    assert!(!Single::ZERO.is_finite_non_zero());
-    assert!(!(-Single::ZERO).is_finite_non_zero());
-
-    // Test +/- qNaN. +/- don't mean anything with qNaN but paranoia can't hurt in
-    // this instance.
-    assert!(!Single::NAN.is_finite_non_zero());
-    assert!(!(-Single::NAN).is_finite_non_zero());
-
-    // Test +/- sNaN. +/- don't mean anything with sNaN but paranoia can't hurt in
-    // this instance.
-    assert!(!Single::snan(None).is_finite_non_zero());
-    assert!(!(-Single::snan(None)).is_finite_non_zero());
-}
-
-#[test]
-fn add() {
-    // Test Special Cases against each other and normal values.
-
-    // FIXMES/NOTES:
-    // 1. Since we perform only default exception handling all operations with
-    // signaling NaNs should have a result that is a quiet NaN. Currently they
-    // return sNaN.
-
-    let p_inf = Single::INFINITY;
-    let m_inf = -Single::INFINITY;
-    let p_zero = Single::ZERO;
-    let m_zero = -Single::ZERO;
-    let qnan = Single::NAN;
-    let p_normal_value = "0x1p+0".parse::<Single>().unwrap();
-    let m_normal_value = "-0x1p+0".parse::<Single>().unwrap();
-    let p_largest_value = Single::largest();
-    let m_largest_value = -Single::largest();
-    let p_smallest_value = Single::SMALLEST;
-    let m_smallest_value = -Single::SMALLEST;
-    let p_smallest_normalized = Single::smallest_normalized();
-    let m_smallest_normalized = -Single::smallest_normalized();
-
-    let overflow_status = Status::OVERFLOW | Status::INEXACT;
-
-    let special_cases = [
-        (p_inf, p_inf, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (p_inf, p_zero, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_zero, "inf", Status::OK, Category::Infinity),
-        (p_inf, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_inf, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_inf, p_normal_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_normal_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, p_largest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_largest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, p_smallest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_smallest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, p_smallest_normalized, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_smallest_normalized, "inf", Status::OK, Category::Infinity),
-        (m_inf, p_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (m_inf, m_inf, "-inf", Status::OK, Category::Infinity),
-        (m_inf, p_zero, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_zero, "-inf", Status::OK, Category::Infinity),
-        (m_inf, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_inf, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_inf, p_normal_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_normal_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, p_largest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_largest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, p_smallest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_smallest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, p_smallest_normalized, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_smallest_normalized, "-inf", Status::OK, Category::Infinity),
-        (p_zero, p_inf, "inf", Status::OK, Category::Infinity),
-        (p_zero, m_inf, "-inf", Status::OK, Category::Infinity),
-        (p_zero, p_zero, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_zero, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_zero, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_zero, p_normal_value, "0x1p+0", Status::OK, Category::Normal),
-        (p_zero, m_normal_value, "-0x1p+0", Status::OK, Category::Normal),
-        (p_zero, p_largest_value, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_zero, m_largest_value, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_zero, p_smallest_value, "0x1p-149", Status::OK, Category::Normal),
-        (p_zero, m_smallest_value, "-0x1p-149", Status::OK, Category::Normal),
-        (p_zero, p_smallest_normalized, "0x1p-126", Status::OK, Category::Normal),
-        (p_zero, m_smallest_normalized, "-0x1p-126", Status::OK, Category::Normal),
-        (m_zero, p_inf, "inf", Status::OK, Category::Infinity),
-        (m_zero, m_inf, "-inf", Status::OK, Category::Infinity),
-        (m_zero, p_zero, "0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_zero, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_zero, p_normal_value, "0x1p+0", Status::OK, Category::Normal),
-        (m_zero, m_normal_value, "-0x1p+0", Status::OK, Category::Normal),
-        (m_zero, p_largest_value, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_zero, m_largest_value, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_zero, p_smallest_value, "0x1p-149", Status::OK, Category::Normal),
-        (m_zero, m_smallest_value, "-0x1p-149", Status::OK, Category::Normal),
-        (m_zero, p_smallest_normalized, "0x1p-126", Status::OK, Category::Normal),
-        (m_zero, m_smallest_normalized, "-0x1p-126", Status::OK, Category::Normal),
-        (qnan, p_inf, "nan", Status::OK, Category::NaN),
-        (qnan, m_inf, "nan", Status::OK, Category::NaN),
-        (qnan, p_zero, "nan", Status::OK, Category::NaN),
-        (qnan, m_zero, "nan", Status::OK, Category::NaN),
-        (qnan, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (qnan, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (qnan, p_normal_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_normal_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_largest_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_largest_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_smallest_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_smallest_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_smallest_normalized, "nan", Status::OK, Category::NaN),
-        (qnan, m_smallest_normalized, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (snan, p_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, qnan, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, snan, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_normal_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_normal_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_largest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_largest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_smallest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_smallest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_smallest_normalized, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_smallest_normalized, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_normal_value, p_inf, "inf", Status::OK, Category::Infinity),
-        (p_normal_value, m_inf, "-inf", Status::OK, Category::Infinity),
-        (p_normal_value, p_zero, "0x1p+0", Status::OK, Category::Normal),
-        (p_normal_value, m_zero, "0x1p+0", Status::OK, Category::Normal),
-        (p_normal_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_normal_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_normal_value, p_normal_value, "0x1p+1", Status::OK, Category::Normal),
-        (p_normal_value, m_normal_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_normal_value, p_largest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_normal_value, m_largest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_normal_value, p_smallest_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (p_normal_value, m_smallest_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (p_normal_value, p_smallest_normalized, "0x1p+0", Status::INEXACT, Category::Normal),
-        (p_normal_value, m_smallest_normalized, "0x1p+0", Status::INEXACT, Category::Normal),
-        (m_normal_value, p_inf, "inf", Status::OK, Category::Infinity),
-        (m_normal_value, m_inf, "-inf", Status::OK, Category::Infinity),
-        (m_normal_value, p_zero, "-0x1p+0", Status::OK, Category::Normal),
-        (m_normal_value, m_zero, "-0x1p+0", Status::OK, Category::Normal),
-        (m_normal_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_normal_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_normal_value, p_normal_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_normal_value, m_normal_value, "-0x1p+1", Status::OK, Category::Normal),
-        (m_normal_value, p_largest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_normal_value, m_largest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_normal_value, p_smallest_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (m_normal_value, m_smallest_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (m_normal_value, p_smallest_normalized, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (m_normal_value, m_smallest_normalized, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (p_largest_value, p_inf, "inf", Status::OK, Category::Infinity),
-        (p_largest_value, m_inf, "-inf", Status::OK, Category::Infinity),
-        (p_largest_value, p_zero, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_largest_value, m_zero, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_largest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_largest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_largest_value, p_normal_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_largest_value, m_normal_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_largest_value, p_largest_value, "inf", overflow_status, Category::Infinity),
-        (p_largest_value, m_largest_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_largest_value, p_smallest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_largest_value, m_smallest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (
-            p_largest_value,
-            p_smallest_normalized,
-            "0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (
-            p_largest_value,
-            m_smallest_normalized,
-            "0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (m_largest_value, p_inf, "inf", Status::OK, Category::Infinity),
-        (m_largest_value, m_inf, "-inf", Status::OK, Category::Infinity),
-        (m_largest_value, p_zero, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_largest_value, m_zero, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_largest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_largest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_largest_value, p_normal_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_largest_value, m_normal_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_largest_value, p_largest_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_largest_value, m_largest_value, "-inf", overflow_status, Category::Infinity),
-        (m_largest_value, p_smallest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_largest_value, m_smallest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (
-            m_largest_value,
-            p_smallest_normalized,
-            "-0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (
-            m_largest_value,
-            m_smallest_normalized,
-            "-0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (p_smallest_value, p_inf, "inf", Status::OK, Category::Infinity),
-        (p_smallest_value, m_inf, "-inf", Status::OK, Category::Infinity),
-        (p_smallest_value, p_zero, "0x1p-149", Status::OK, Category::Normal),
-        (p_smallest_value, m_zero, "0x1p-149", Status::OK, Category::Normal),
-        (p_smallest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_smallest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_smallest_value, p_normal_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (p_smallest_value, m_normal_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (p_smallest_value, p_largest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_smallest_value, m_largest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_smallest_value, p_smallest_value, "0x1p-148", Status::OK, Category::Normal),
-        (p_smallest_value, m_smallest_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_smallest_value, p_smallest_normalized, "0x1.000002p-126", Status::OK, Category::Normal),
-        (p_smallest_value, m_smallest_normalized, "-0x1.fffffcp-127", Status::OK, Category::Normal),
-        (m_smallest_value, p_inf, "inf", Status::OK, Category::Infinity),
-        (m_smallest_value, m_inf, "-inf", Status::OK, Category::Infinity),
-        (m_smallest_value, p_zero, "-0x1p-149", Status::OK, Category::Normal),
-        (m_smallest_value, m_zero, "-0x1p-149", Status::OK, Category::Normal),
-        (m_smallest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_smallest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_smallest_value, p_normal_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (m_smallest_value, m_normal_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (m_smallest_value, p_largest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_smallest_value, m_largest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_smallest_value, p_smallest_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_value, m_smallest_value, "-0x1p-148", Status::OK, Category::Normal),
-        (m_smallest_value, p_smallest_normalized, "0x1.fffffcp-127", Status::OK, Category::Normal),
-        (m_smallest_value, m_smallest_normalized, "-0x1.000002p-126", Status::OK, Category::Normal),
-        (p_smallest_normalized, p_inf, "inf", Status::OK, Category::Infinity),
-        (p_smallest_normalized, m_inf, "-inf", Status::OK, Category::Infinity),
-        (p_smallest_normalized, p_zero, "0x1p-126", Status::OK, Category::Normal),
-        (p_smallest_normalized, m_zero, "0x1p-126", Status::OK, Category::Normal),
-        (p_smallest_normalized, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_smallest_normalized, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_smallest_normalized, p_normal_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (p_smallest_normalized, m_normal_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (
-            p_smallest_normalized,
-            p_largest_value,
-            "0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (
-            p_smallest_normalized,
-            m_largest_value,
-            "-0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (p_smallest_normalized, p_smallest_value, "0x1.000002p-126", Status::OK, Category::Normal),
-        (p_smallest_normalized, m_smallest_value, "0x1.fffffcp-127", Status::OK, Category::Normal),
-        (p_smallest_normalized, p_smallest_normalized, "0x1p-125", Status::OK, Category::Normal),
-        (p_smallest_normalized, m_smallest_normalized, "0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_normalized, p_inf, "inf", Status::OK, Category::Infinity),
-        (m_smallest_normalized, m_inf, "-inf", Status::OK, Category::Infinity),
-        (m_smallest_normalized, p_zero, "-0x1p-126", Status::OK, Category::Normal),
-        (m_smallest_normalized, m_zero, "-0x1p-126", Status::OK, Category::Normal),
-        (m_smallest_normalized, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_smallest_normalized, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_smallest_normalized, p_normal_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (m_smallest_normalized, m_normal_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (
-            m_smallest_normalized,
-            p_largest_value,
-            "0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (
-            m_smallest_normalized,
-            m_largest_value,
-            "-0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (m_smallest_normalized, p_smallest_value, "-0x1.fffffcp-127", Status::OK, Category::Normal),
-        (m_smallest_normalized, m_smallest_value, "-0x1.000002p-126", Status::OK, Category::Normal),
-        (m_smallest_normalized, p_smallest_normalized, "0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_normalized, m_smallest_normalized, "-0x1p-125", Status::OK, Category::Normal),
-    ];
-
-    for (x, y, e_result, e_status, e_category) in special_cases {
-        let status;
-        let result = unpack!(status=, x + y);
-        assert_eq!(status, e_status);
-        assert_eq!(result.category(), e_category);
-        assert!(result.bitwise_eq(e_result.parse::<Single>().unwrap()));
-    }
-}
-
-#[test]
-fn subtract() {
-    // Test Special Cases against each other and normal values.
-
-    // FIXMES/NOTES:
-    // 1. Since we perform only default exception handling all operations with
-    // signaling NaNs should have a result that is a quiet NaN. Currently they
-    // return sNaN.
-
-    let p_inf = Single::INFINITY;
-    let m_inf = -Single::INFINITY;
-    let p_zero = Single::ZERO;
-    let m_zero = -Single::ZERO;
-    let qnan = Single::NAN;
-    let p_normal_value = "0x1p+0".parse::<Single>().unwrap();
-    let m_normal_value = "-0x1p+0".parse::<Single>().unwrap();
-    let p_largest_value = Single::largest();
-    let m_largest_value = -Single::largest();
-    let p_smallest_value = Single::SMALLEST;
-    let m_smallest_value = -Single::SMALLEST;
-    let p_smallest_normalized = Single::smallest_normalized();
-    let m_smallest_normalized = -Single::smallest_normalized();
-
-    let overflow_status = Status::OVERFLOW | Status::INEXACT;
-
-    let special_cases = [
-        (p_inf, p_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (p_inf, m_inf, "inf", Status::OK, Category::Infinity),
-        (p_inf, p_zero, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_zero, "inf", Status::OK, Category::Infinity),
-        (p_inf, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_inf, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_inf, p_normal_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_normal_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, p_largest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_largest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, p_smallest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_smallest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, p_smallest_normalized, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_smallest_normalized, "inf", Status::OK, Category::Infinity),
-        (m_inf, p_inf, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (m_inf, p_zero, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_zero, "-inf", Status::OK, Category::Infinity),
-        (m_inf, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_inf, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_inf, p_normal_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_normal_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, p_largest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_largest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, p_smallest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_smallest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, p_smallest_normalized, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_smallest_normalized, "-inf", Status::OK, Category::Infinity),
-        (p_zero, p_inf, "-inf", Status::OK, Category::Infinity),
-        (p_zero, m_inf, "inf", Status::OK, Category::Infinity),
-        (p_zero, p_zero, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_zero, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_zero, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_zero, p_normal_value, "-0x1p+0", Status::OK, Category::Normal),
-        (p_zero, m_normal_value, "0x1p+0", Status::OK, Category::Normal),
-        (p_zero, p_largest_value, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_zero, m_largest_value, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_zero, p_smallest_value, "-0x1p-149", Status::OK, Category::Normal),
-        (p_zero, m_smallest_value, "0x1p-149", Status::OK, Category::Normal),
-        (p_zero, p_smallest_normalized, "-0x1p-126", Status::OK, Category::Normal),
-        (p_zero, m_smallest_normalized, "0x1p-126", Status::OK, Category::Normal),
-        (m_zero, p_inf, "-inf", Status::OK, Category::Infinity),
-        (m_zero, m_inf, "inf", Status::OK, Category::Infinity),
-        (m_zero, p_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_zero, "0x0p+0", Status::OK, Category::Zero),
-        (m_zero, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_zero, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_zero, p_normal_value, "-0x1p+0", Status::OK, Category::Normal),
-        (m_zero, m_normal_value, "0x1p+0", Status::OK, Category::Normal),
-        (m_zero, p_largest_value, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_zero, m_largest_value, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_zero, p_smallest_value, "-0x1p-149", Status::OK, Category::Normal),
-        (m_zero, m_smallest_value, "0x1p-149", Status::OK, Category::Normal),
-        (m_zero, p_smallest_normalized, "-0x1p-126", Status::OK, Category::Normal),
-        (m_zero, m_smallest_normalized, "0x1p-126", Status::OK, Category::Normal),
-        (qnan, p_inf, "nan", Status::OK, Category::NaN),
-        (qnan, m_inf, "nan", Status::OK, Category::NaN),
-        (qnan, p_zero, "nan", Status::OK, Category::NaN),
-        (qnan, m_zero, "nan", Status::OK, Category::NaN),
-        (qnan, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (qnan, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (qnan, p_normal_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_normal_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_largest_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_largest_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_smallest_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_smallest_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_smallest_normalized, "nan", Status::OK, Category::NaN),
-        (qnan, m_smallest_normalized, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (snan, p_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, qnan, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, snan, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_normal_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_normal_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_largest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_largest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_smallest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_smallest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_smallest_normalized, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_smallest_normalized, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_normal_value, p_inf, "-inf", Status::OK, Category::Infinity),
-        (p_normal_value, m_inf, "inf", Status::OK, Category::Infinity),
-        (p_normal_value, p_zero, "0x1p+0", Status::OK, Category::Normal),
-        (p_normal_value, m_zero, "0x1p+0", Status::OK, Category::Normal),
-        (p_normal_value, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_normal_value, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_normal_value, p_normal_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_normal_value, m_normal_value, "0x1p+1", Status::OK, Category::Normal),
-        (p_normal_value, p_largest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_normal_value, m_largest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_normal_value, p_smallest_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (p_normal_value, m_smallest_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (p_normal_value, p_smallest_normalized, "0x1p+0", Status::INEXACT, Category::Normal),
-        (p_normal_value, m_smallest_normalized, "0x1p+0", Status::INEXACT, Category::Normal),
-        (m_normal_value, p_inf, "-inf", Status::OK, Category::Infinity),
-        (m_normal_value, m_inf, "inf", Status::OK, Category::Infinity),
-        (m_normal_value, p_zero, "-0x1p+0", Status::OK, Category::Normal),
-        (m_normal_value, m_zero, "-0x1p+0", Status::OK, Category::Normal),
-        (m_normal_value, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_normal_value, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_normal_value, p_normal_value, "-0x1p+1", Status::OK, Category::Normal),
-        (m_normal_value, m_normal_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_normal_value, p_largest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_normal_value, m_largest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_normal_value, p_smallest_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (m_normal_value, m_smallest_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (m_normal_value, p_smallest_normalized, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (m_normal_value, m_smallest_normalized, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (p_largest_value, p_inf, "-inf", Status::OK, Category::Infinity),
-        (p_largest_value, m_inf, "inf", Status::OK, Category::Infinity),
-        (p_largest_value, p_zero, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_largest_value, m_zero, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_largest_value, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_largest_value, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_largest_value, p_normal_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_largest_value, m_normal_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_largest_value, p_largest_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_largest_value, m_largest_value, "inf", overflow_status, Category::Infinity),
-        (p_largest_value, p_smallest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_largest_value, m_smallest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (
-            p_largest_value,
-            p_smallest_normalized,
-            "0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (
-            p_largest_value,
-            m_smallest_normalized,
-            "0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (m_largest_value, p_inf, "-inf", Status::OK, Category::Infinity),
-        (m_largest_value, m_inf, "inf", Status::OK, Category::Infinity),
-        (m_largest_value, p_zero, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_largest_value, m_zero, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_largest_value, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_largest_value, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_largest_value, p_normal_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_largest_value, m_normal_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_largest_value, p_largest_value, "-inf", overflow_status, Category::Infinity),
-        (m_largest_value, m_largest_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_largest_value, p_smallest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_largest_value, m_smallest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (
-            m_largest_value,
-            p_smallest_normalized,
-            "-0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (
-            m_largest_value,
-            m_smallest_normalized,
-            "-0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (p_smallest_value, p_inf, "-inf", Status::OK, Category::Infinity),
-        (p_smallest_value, m_inf, "inf", Status::OK, Category::Infinity),
-        (p_smallest_value, p_zero, "0x1p-149", Status::OK, Category::Normal),
-        (p_smallest_value, m_zero, "0x1p-149", Status::OK, Category::Normal),
-        (p_smallest_value, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_smallest_value, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_smallest_value, p_normal_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (p_smallest_value, m_normal_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (p_smallest_value, p_largest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_smallest_value, m_largest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_smallest_value, p_smallest_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_smallest_value, m_smallest_value, "0x1p-148", Status::OK, Category::Normal),
-        (p_smallest_value, p_smallest_normalized, "-0x1.fffffcp-127", Status::OK, Category::Normal),
-        (p_smallest_value, m_smallest_normalized, "0x1.000002p-126", Status::OK, Category::Normal),
-        (m_smallest_value, p_inf, "-inf", Status::OK, Category::Infinity),
-        (m_smallest_value, m_inf, "inf", Status::OK, Category::Infinity),
-        (m_smallest_value, p_zero, "-0x1p-149", Status::OK, Category::Normal),
-        (m_smallest_value, m_zero, "-0x1p-149", Status::OK, Category::Normal),
-        (m_smallest_value, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_smallest_value, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_smallest_value, p_normal_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (m_smallest_value, m_normal_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (m_smallest_value, p_largest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_smallest_value, m_largest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_smallest_value, p_smallest_value, "-0x1p-148", Status::OK, Category::Normal),
-        (m_smallest_value, m_smallest_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_value, p_smallest_normalized, "-0x1.000002p-126", Status::OK, Category::Normal),
-        (m_smallest_value, m_smallest_normalized, "0x1.fffffcp-127", Status::OK, Category::Normal),
-        (p_smallest_normalized, p_inf, "-inf", Status::OK, Category::Infinity),
-        (p_smallest_normalized, m_inf, "inf", Status::OK, Category::Infinity),
-        (p_smallest_normalized, p_zero, "0x1p-126", Status::OK, Category::Normal),
-        (p_smallest_normalized, m_zero, "0x1p-126", Status::OK, Category::Normal),
-        (p_smallest_normalized, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_smallest_normalized, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_smallest_normalized, p_normal_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (p_smallest_normalized, m_normal_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (
-            p_smallest_normalized,
-            p_largest_value,
-            "-0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (
-            p_smallest_normalized,
-            m_largest_value,
-            "0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (p_smallest_normalized, p_smallest_value, "0x1.fffffcp-127", Status::OK, Category::Normal),
-        (p_smallest_normalized, m_smallest_value, "0x1.000002p-126", Status::OK, Category::Normal),
-        (p_smallest_normalized, p_smallest_normalized, "0x0p+0", Status::OK, Category::Zero),
-        (p_smallest_normalized, m_smallest_normalized, "0x1p-125", Status::OK, Category::Normal),
-        (m_smallest_normalized, p_inf, "-inf", Status::OK, Category::Infinity),
-        (m_smallest_normalized, m_inf, "inf", Status::OK, Category::Infinity),
-        (m_smallest_normalized, p_zero, "-0x1p-126", Status::OK, Category::Normal),
-        (m_smallest_normalized, m_zero, "-0x1p-126", Status::OK, Category::Normal),
-        (m_smallest_normalized, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_smallest_normalized, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_smallest_normalized, p_normal_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (m_smallest_normalized, m_normal_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (
-            m_smallest_normalized,
-            p_largest_value,
-            "-0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (
-            m_smallest_normalized,
-            m_largest_value,
-            "0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (m_smallest_normalized, p_smallest_value, "-0x1.000002p-126", Status::OK, Category::Normal),
-        (m_smallest_normalized, m_smallest_value, "-0x1.fffffcp-127", Status::OK, Category::Normal),
-        (m_smallest_normalized, p_smallest_normalized, "-0x1p-125", Status::OK, Category::Normal),
-        (m_smallest_normalized, m_smallest_normalized, "0x0p+0", Status::OK, Category::Zero),
-    ];
-
-    for (x, y, e_result, e_status, e_category) in special_cases {
-        let status;
-        let result = unpack!(status=, x - y);
-        assert_eq!(status, e_status);
-        assert_eq!(result.category(), e_category);
-        assert!(result.bitwise_eq(e_result.parse::<Single>().unwrap()));
-    }
-}
-
-#[test]
-fn multiply() {
-    // Test Special Cases against each other and normal values.
-
-    // FIXMES/NOTES:
-    // 1. Since we perform only default exception handling all operations with
-    // signaling NaNs should have a result that is a quiet NaN. Currently they
-    // return sNaN.
-
-    let p_inf = Single::INFINITY;
-    let m_inf = -Single::INFINITY;
-    let p_zero = Single::ZERO;
-    let m_zero = -Single::ZERO;
-    let qnan = Single::NAN;
-    let p_normal_value = "0x1p+0".parse::<Single>().unwrap();
-    let m_normal_value = "-0x1p+0".parse::<Single>().unwrap();
-    let p_largest_value = Single::largest();
-    let m_largest_value = -Single::largest();
-    let p_smallest_value = Single::SMALLEST;
-    let m_smallest_value = -Single::SMALLEST;
-    let p_smallest_normalized = Single::smallest_normalized();
-    let m_smallest_normalized = -Single::smallest_normalized();
-
-    let overflow_status = Status::OVERFLOW | Status::INEXACT;
-    let underflow_status = Status::UNDERFLOW | Status::INEXACT;
-
-    let special_cases = [
-        (p_inf, p_inf, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_inf, "-inf", Status::OK, Category::Infinity),
-        (p_inf, p_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (p_inf, m_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (p_inf, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_inf, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_inf, p_normal_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_normal_value, "-inf", Status::OK, Category::Infinity),
-        (p_inf, p_largest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_largest_value, "-inf", Status::OK, Category::Infinity),
-        (p_inf, p_smallest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_smallest_value, "-inf", Status::OK, Category::Infinity),
-        (p_inf, p_smallest_normalized, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_smallest_normalized, "-inf", Status::OK, Category::Infinity),
-        (m_inf, p_inf, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_inf, "inf", Status::OK, Category::Infinity),
-        (m_inf, p_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (m_inf, m_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (m_inf, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_inf, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_inf, p_normal_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_normal_value, "inf", Status::OK, Category::Infinity),
-        (m_inf, p_largest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_largest_value, "inf", Status::OK, Category::Infinity),
-        (m_inf, p_smallest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_smallest_value, "inf", Status::OK, Category::Infinity),
-        (m_inf, p_smallest_normalized, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_smallest_normalized, "inf", Status::OK, Category::Infinity),
-        (p_zero, p_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (p_zero, m_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (p_zero, p_zero, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (p_zero, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_zero, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_zero, p_normal_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_normal_value, "-0x0p+0", Status::OK, Category::Zero),
-        (p_zero, p_largest_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_largest_value, "-0x0p+0", Status::OK, Category::Zero),
-        (p_zero, p_smallest_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_smallest_value, "-0x0p+0", Status::OK, Category::Zero),
-        (p_zero, p_smallest_normalized, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_smallest_normalized, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, p_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (m_zero, m_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (m_zero, p_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_zero, "0x0p+0", Status::OK, Category::Zero),
-        (m_zero, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_zero, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_zero, p_normal_value, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_normal_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_zero, p_largest_value, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_largest_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_zero, p_smallest_value, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_smallest_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_zero, p_smallest_normalized, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_smallest_normalized, "0x0p+0", Status::OK, Category::Zero),
-        (qnan, p_inf, "nan", Status::OK, Category::NaN),
-        (qnan, m_inf, "nan", Status::OK, Category::NaN),
-        (qnan, p_zero, "nan", Status::OK, Category::NaN),
-        (qnan, m_zero, "nan", Status::OK, Category::NaN),
-        (qnan, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (qnan, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (qnan, p_normal_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_normal_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_largest_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_largest_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_smallest_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_smallest_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_smallest_normalized, "nan", Status::OK, Category::NaN),
-        (qnan, m_smallest_normalized, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (snan, p_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, qnan, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, snan, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_normal_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_normal_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_largest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_largest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_smallest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_smallest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_smallest_normalized, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_smallest_normalized, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_normal_value, p_inf, "inf", Status::OK, Category::Infinity),
-        (p_normal_value, m_inf, "-inf", Status::OK, Category::Infinity),
-        (p_normal_value, p_zero, "0x0p+0", Status::OK, Category::Zero),
-        (p_normal_value, m_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (p_normal_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_normal_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_normal_value, p_normal_value, "0x1p+0", Status::OK, Category::Normal),
-        (p_normal_value, m_normal_value, "-0x1p+0", Status::OK, Category::Normal),
-        (p_normal_value, p_largest_value, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_normal_value, m_largest_value, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_normal_value, p_smallest_value, "0x1p-149", Status::OK, Category::Normal),
-        (p_normal_value, m_smallest_value, "-0x1p-149", Status::OK, Category::Normal),
-        (p_normal_value, p_smallest_normalized, "0x1p-126", Status::OK, Category::Normal),
-        (p_normal_value, m_smallest_normalized, "-0x1p-126", Status::OK, Category::Normal),
-        (m_normal_value, p_inf, "-inf", Status::OK, Category::Infinity),
-        (m_normal_value, m_inf, "inf", Status::OK, Category::Infinity),
-        (m_normal_value, p_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (m_normal_value, m_zero, "0x0p+0", Status::OK, Category::Zero),
-        (m_normal_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_normal_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_normal_value, p_normal_value, "-0x1p+0", Status::OK, Category::Normal),
-        (m_normal_value, m_normal_value, "0x1p+0", Status::OK, Category::Normal),
-        (m_normal_value, p_largest_value, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_normal_value, m_largest_value, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_normal_value, p_smallest_value, "-0x1p-149", Status::OK, Category::Normal),
-        (m_normal_value, m_smallest_value, "0x1p-149", Status::OK, Category::Normal),
-        (m_normal_value, p_smallest_normalized, "-0x1p-126", Status::OK, Category::Normal),
-        (m_normal_value, m_smallest_normalized, "0x1p-126", Status::OK, Category::Normal),
-        (p_largest_value, p_inf, "inf", Status::OK, Category::Infinity),
-        (p_largest_value, m_inf, "-inf", Status::OK, Category::Infinity),
-        (p_largest_value, p_zero, "0x0p+0", Status::OK, Category::Zero),
-        (p_largest_value, m_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (p_largest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_largest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_largest_value, p_normal_value, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_largest_value, m_normal_value, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_largest_value, p_largest_value, "inf", overflow_status, Category::Infinity),
-        (p_largest_value, m_largest_value, "-inf", overflow_status, Category::Infinity),
-        (p_largest_value, p_smallest_value, "0x1.fffffep-22", Status::OK, Category::Normal),
-        (p_largest_value, m_smallest_value, "-0x1.fffffep-22", Status::OK, Category::Normal),
-        (p_largest_value, p_smallest_normalized, "0x1.fffffep+1", Status::OK, Category::Normal),
-        (p_largest_value, m_smallest_normalized, "-0x1.fffffep+1", Status::OK, Category::Normal),
-        (m_largest_value, p_inf, "-inf", Status::OK, Category::Infinity),
-        (m_largest_value, m_inf, "inf", Status::OK, Category::Infinity),
-        (m_largest_value, p_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (m_largest_value, m_zero, "0x0p+0", Status::OK, Category::Zero),
-        (m_largest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_largest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_largest_value, p_normal_value, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_largest_value, m_normal_value, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_largest_value, p_largest_value, "-inf", overflow_status, Category::Infinity),
-        (m_largest_value, m_largest_value, "inf", overflow_status, Category::Infinity),
-        (m_largest_value, p_smallest_value, "-0x1.fffffep-22", Status::OK, Category::Normal),
-        (m_largest_value, m_smallest_value, "0x1.fffffep-22", Status::OK, Category::Normal),
-        (m_largest_value, p_smallest_normalized, "-0x1.fffffep+1", Status::OK, Category::Normal),
-        (m_largest_value, m_smallest_normalized, "0x1.fffffep+1", Status::OK, Category::Normal),
-        (p_smallest_value, p_inf, "inf", Status::OK, Category::Infinity),
-        (p_smallest_value, m_inf, "-inf", Status::OK, Category::Infinity),
-        (p_smallest_value, p_zero, "0x0p+0", Status::OK, Category::Zero),
-        (p_smallest_value, m_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (p_smallest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_smallest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_smallest_value, p_normal_value, "0x1p-149", Status::OK, Category::Normal),
-        (p_smallest_value, m_normal_value, "-0x1p-149", Status::OK, Category::Normal),
-        (p_smallest_value, p_largest_value, "0x1.fffffep-22", Status::OK, Category::Normal),
-        (p_smallest_value, m_largest_value, "-0x1.fffffep-22", Status::OK, Category::Normal),
-        (p_smallest_value, p_smallest_value, "0x0p+0", underflow_status, Category::Zero),
-        (p_smallest_value, m_smallest_value, "-0x0p+0", underflow_status, Category::Zero),
-        (p_smallest_value, p_smallest_normalized, "0x0p+0", underflow_status, Category::Zero),
-        (p_smallest_value, m_smallest_normalized, "-0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_value, p_inf, "-inf", Status::OK, Category::Infinity),
-        (m_smallest_value, m_inf, "inf", Status::OK, Category::Infinity),
-        (m_smallest_value, p_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_value, m_zero, "0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_smallest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_smallest_value, p_normal_value, "-0x1p-149", Status::OK, Category::Normal),
-        (m_smallest_value, m_normal_value, "0x1p-149", Status::OK, Category::Normal),
-        (m_smallest_value, p_largest_value, "-0x1.fffffep-22", Status::OK, Category::Normal),
-        (m_smallest_value, m_largest_value, "0x1.fffffep-22", Status::OK, Category::Normal),
-        (m_smallest_value, p_smallest_value, "-0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_value, m_smallest_value, "0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_value, p_smallest_normalized, "-0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_value, m_smallest_normalized, "0x0p+0", underflow_status, Category::Zero),
-        (p_smallest_normalized, p_inf, "inf", Status::OK, Category::Infinity),
-        (p_smallest_normalized, m_inf, "-inf", Status::OK, Category::Infinity),
-        (p_smallest_normalized, p_zero, "0x0p+0", Status::OK, Category::Zero),
-        (p_smallest_normalized, m_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (p_smallest_normalized, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_smallest_normalized, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_smallest_normalized, p_normal_value, "0x1p-126", Status::OK, Category::Normal),
-        (p_smallest_normalized, m_normal_value, "-0x1p-126", Status::OK, Category::Normal),
-        (p_smallest_normalized, p_largest_value, "0x1.fffffep+1", Status::OK, Category::Normal),
-        (p_smallest_normalized, m_largest_value, "-0x1.fffffep+1", Status::OK, Category::Normal),
-        (p_smallest_normalized, p_smallest_value, "0x0p+0", underflow_status, Category::Zero),
-        (p_smallest_normalized, m_smallest_value, "-0x0p+0", underflow_status, Category::Zero),
-        (p_smallest_normalized, p_smallest_normalized, "0x0p+0", underflow_status, Category::Zero),
-        (p_smallest_normalized, m_smallest_normalized, "-0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_normalized, p_inf, "-inf", Status::OK, Category::Infinity),
-        (m_smallest_normalized, m_inf, "inf", Status::OK, Category::Infinity),
-        (m_smallest_normalized, p_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_normalized, m_zero, "0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_normalized, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_smallest_normalized, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_smallest_normalized, p_normal_value, "-0x1p-126", Status::OK, Category::Normal),
-        (m_smallest_normalized, m_normal_value, "0x1p-126", Status::OK, Category::Normal),
-        (m_smallest_normalized, p_largest_value, "-0x1.fffffep+1", Status::OK, Category::Normal),
-        (m_smallest_normalized, m_largest_value, "0x1.fffffep+1", Status::OK, Category::Normal),
-        (m_smallest_normalized, p_smallest_value, "-0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_normalized, m_smallest_value, "0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_normalized, p_smallest_normalized, "-0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_normalized, m_smallest_normalized, "0x0p+0", underflow_status, Category::Zero),
-    ];
-
-    for (x, y, e_result, e_status, e_category) in special_cases {
-        let status;
-        let result = unpack!(status=, x * y);
-        assert_eq!(status, e_status);
-        assert_eq!(result.category(), e_category);
-        assert!(result.bitwise_eq(e_result.parse::<Single>().unwrap()));
-    }
-}
-
-#[test]
-fn divide() {
-    // Test Special Cases against each other and normal values.
-
-    // FIXMES/NOTES:
-    // 1. Since we perform only default exception handling all operations with
-    // signaling NaNs should have a result that is a quiet NaN. Currently they
-    // return sNaN.
-
-    let p_inf = Single::INFINITY;
-    let m_inf = -Single::INFINITY;
-    let p_zero = Single::ZERO;
-    let m_zero = -Single::ZERO;
-    let qnan = Single::NAN;
-    let p_normal_value = "0x1p+0".parse::<Single>().unwrap();
-    let m_normal_value = "-0x1p+0".parse::<Single>().unwrap();
-    let p_largest_value = Single::largest();
-    let m_largest_value = -Single::largest();
-    let p_smallest_value = Single::SMALLEST;
-    let m_smallest_value = -Single::SMALLEST;
-    let p_smallest_normalized = Single::smallest_normalized();
-    let m_smallest_normalized = -Single::smallest_normalized();
-
-    let overflow_status = Status::OVERFLOW | Status::INEXACT;
-    let underflow_status = Status::UNDERFLOW | Status::INEXACT;
-
-    let special_cases = [
-        (p_inf, p_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (p_inf, m_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (p_inf, p_zero, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_zero, "-inf", Status::OK, Category::Infinity),
-        (p_inf, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_inf, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_inf, p_normal_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_normal_value, "-inf", Status::OK, Category::Infinity),
-        (p_inf, p_largest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_largest_value, "-inf", Status::OK, Category::Infinity),
-        (p_inf, p_smallest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_smallest_value, "-inf", Status::OK, Category::Infinity),
-        (p_inf, p_smallest_normalized, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_smallest_normalized, "-inf", Status::OK, Category::Infinity),
-        (m_inf, p_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (m_inf, m_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (m_inf, p_zero, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_zero, "inf", Status::OK, Category::Infinity),
-        (m_inf, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_inf, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_inf, p_normal_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_normal_value, "inf", Status::OK, Category::Infinity),
-        (m_inf, p_largest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_largest_value, "inf", Status::OK, Category::Infinity),
-        (m_inf, p_smallest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_smallest_value, "inf", Status::OK, Category::Infinity),
-        (m_inf, p_smallest_normalized, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_smallest_normalized, "inf", Status::OK, Category::Infinity),
-        (p_zero, p_inf, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_inf, "-0x0p+0", Status::OK, Category::Zero),
-        (p_zero, p_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (p_zero, m_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (p_zero, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_zero, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_zero, p_normal_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_normal_value, "-0x0p+0", Status::OK, Category::Zero),
-        (p_zero, p_largest_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_largest_value, "-0x0p+0", Status::OK, Category::Zero),
-        (p_zero, p_smallest_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_smallest_value, "-0x0p+0", Status::OK, Category::Zero),
-        (p_zero, p_smallest_normalized, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_smallest_normalized, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, p_inf, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_inf, "0x0p+0", Status::OK, Category::Zero),
-        (m_zero, p_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (m_zero, m_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (m_zero, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_zero, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_zero, p_normal_value, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_normal_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_zero, p_largest_value, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_largest_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_zero, p_smallest_value, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_smallest_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_zero, p_smallest_normalized, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_smallest_normalized, "0x0p+0", Status::OK, Category::Zero),
-        (qnan, p_inf, "nan", Status::OK, Category::NaN),
-        (qnan, m_inf, "nan", Status::OK, Category::NaN),
-        (qnan, p_zero, "nan", Status::OK, Category::NaN),
-        (qnan, m_zero, "nan", Status::OK, Category::NaN),
-        (qnan, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (qnan, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (qnan, p_normal_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_normal_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_largest_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_largest_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_smallest_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_smallest_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_smallest_normalized, "nan", Status::OK, Category::NaN),
-        (qnan, m_smallest_normalized, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (snan, p_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, qnan, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, snan, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_normal_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_normal_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_largest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_largest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_smallest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_smallest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_smallest_normalized, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_smallest_normalized, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_normal_value, p_inf, "0x0p+0", Status::OK, Category::Zero),
-        (p_normal_value, m_inf, "-0x0p+0", Status::OK, Category::Zero),
-        (p_normal_value, p_zero, "inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (p_normal_value, m_zero, "-inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (p_normal_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_normal_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_normal_value, p_normal_value, "0x1p+0", Status::OK, Category::Normal),
-        (p_normal_value, m_normal_value, "-0x1p+0", Status::OK, Category::Normal),
-        (p_normal_value, p_largest_value, "0x1p-128", underflow_status, Category::Normal),
-        (p_normal_value, m_largest_value, "-0x1p-128", underflow_status, Category::Normal),
-        (p_normal_value, p_smallest_value, "inf", overflow_status, Category::Infinity),
-        (p_normal_value, m_smallest_value, "-inf", overflow_status, Category::Infinity),
-        (p_normal_value, p_smallest_normalized, "0x1p+126", Status::OK, Category::Normal),
-        (p_normal_value, m_smallest_normalized, "-0x1p+126", Status::OK, Category::Normal),
-        (m_normal_value, p_inf, "-0x0p+0", Status::OK, Category::Zero),
-        (m_normal_value, m_inf, "0x0p+0", Status::OK, Category::Zero),
-        (m_normal_value, p_zero, "-inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (m_normal_value, m_zero, "inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (m_normal_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_normal_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_normal_value, p_normal_value, "-0x1p+0", Status::OK, Category::Normal),
-        (m_normal_value, m_normal_value, "0x1p+0", Status::OK, Category::Normal),
-        (m_normal_value, p_largest_value, "-0x1p-128", underflow_status, Category::Normal),
-        (m_normal_value, m_largest_value, "0x1p-128", underflow_status, Category::Normal),
-        (m_normal_value, p_smallest_value, "-inf", overflow_status, Category::Infinity),
-        (m_normal_value, m_smallest_value, "inf", overflow_status, Category::Infinity),
-        (m_normal_value, p_smallest_normalized, "-0x1p+126", Status::OK, Category::Normal),
-        (m_normal_value, m_smallest_normalized, "0x1p+126", Status::OK, Category::Normal),
-        (p_largest_value, p_inf, "0x0p+0", Status::OK, Category::Zero),
-        (p_largest_value, m_inf, "-0x0p+0", Status::OK, Category::Zero),
-        (p_largest_value, p_zero, "inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (p_largest_value, m_zero, "-inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (p_largest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_largest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_largest_value, p_normal_value, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_largest_value, m_normal_value, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_largest_value, p_largest_value, "0x1p+0", Status::OK, Category::Normal),
-        (p_largest_value, m_largest_value, "-0x1p+0", Status::OK, Category::Normal),
-        (p_largest_value, p_smallest_value, "inf", overflow_status, Category::Infinity),
-        (p_largest_value, m_smallest_value, "-inf", overflow_status, Category::Infinity),
-        (p_largest_value, p_smallest_normalized, "inf", overflow_status, Category::Infinity),
-        (p_largest_value, m_smallest_normalized, "-inf", overflow_status, Category::Infinity),
-        (m_largest_value, p_inf, "-0x0p+0", Status::OK, Category::Zero),
-        (m_largest_value, m_inf, "0x0p+0", Status::OK, Category::Zero),
-        (m_largest_value, p_zero, "-inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (m_largest_value, m_zero, "inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (m_largest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_largest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_largest_value, p_normal_value, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_largest_value, m_normal_value, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_largest_value, p_largest_value, "-0x1p+0", Status::OK, Category::Normal),
-        (m_largest_value, m_largest_value, "0x1p+0", Status::OK, Category::Normal),
-        (m_largest_value, p_smallest_value, "-inf", overflow_status, Category::Infinity),
-        (m_largest_value, m_smallest_value, "inf", overflow_status, Category::Infinity),
-        (m_largest_value, p_smallest_normalized, "-inf", overflow_status, Category::Infinity),
-        (m_largest_value, m_smallest_normalized, "inf", overflow_status, Category::Infinity),
-        (p_smallest_value, p_inf, "0x0p+0", Status::OK, Category::Zero),
-        (p_smallest_value, m_inf, "-0x0p+0", Status::OK, Category::Zero),
-        (p_smallest_value, p_zero, "inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (p_smallest_value, m_zero, "-inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (p_smallest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_smallest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_smallest_value, p_normal_value, "0x1p-149", Status::OK, Category::Normal),
-        (p_smallest_value, m_normal_value, "-0x1p-149", Status::OK, Category::Normal),
-        (p_smallest_value, p_largest_value, "0x0p+0", underflow_status, Category::Zero),
-        (p_smallest_value, m_largest_value, "-0x0p+0", underflow_status, Category::Zero),
-        (p_smallest_value, p_smallest_value, "0x1p+0", Status::OK, Category::Normal),
-        (p_smallest_value, m_smallest_value, "-0x1p+0", Status::OK, Category::Normal),
-        (p_smallest_value, p_smallest_normalized, "0x1p-23", Status::OK, Category::Normal),
-        (p_smallest_value, m_smallest_normalized, "-0x1p-23", Status::OK, Category::Normal),
-        (m_smallest_value, p_inf, "-0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_value, m_inf, "0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_value, p_zero, "-inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (m_smallest_value, m_zero, "inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (m_smallest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_smallest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_smallest_value, p_normal_value, "-0x1p-149", Status::OK, Category::Normal),
-        (m_smallest_value, m_normal_value, "0x1p-149", Status::OK, Category::Normal),
-        (m_smallest_value, p_largest_value, "-0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_value, m_largest_value, "0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_value, p_smallest_value, "-0x1p+0", Status::OK, Category::Normal),
-        (m_smallest_value, m_smallest_value, "0x1p+0", Status::OK, Category::Normal),
-        (m_smallest_value, p_smallest_normalized, "-0x1p-23", Status::OK, Category::Normal),
-        (m_smallest_value, m_smallest_normalized, "0x1p-23", Status::OK, Category::Normal),
-        (p_smallest_normalized, p_inf, "0x0p+0", Status::OK, Category::Zero),
-        (p_smallest_normalized, m_inf, "-0x0p+0", Status::OK, Category::Zero),
-        (p_smallest_normalized, p_zero, "inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (p_smallest_normalized, m_zero, "-inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (p_smallest_normalized, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_smallest_normalized, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_smallest_normalized, p_normal_value, "0x1p-126", Status::OK, Category::Normal),
-        (p_smallest_normalized, m_normal_value, "-0x1p-126", Status::OK, Category::Normal),
-        (p_smallest_normalized, p_largest_value, "0x0p+0", underflow_status, Category::Zero),
-        (p_smallest_normalized, m_largest_value, "-0x0p+0", underflow_status, Category::Zero),
-        (p_smallest_normalized, p_smallest_value, "0x1p+23", Status::OK, Category::Normal),
-        (p_smallest_normalized, m_smallest_value, "-0x1p+23", Status::OK, Category::Normal),
-        (p_smallest_normalized, p_smallest_normalized, "0x1p+0", Status::OK, Category::Normal),
-        (p_smallest_normalized, m_smallest_normalized, "-0x1p+0", Status::OK, Category::Normal),
-        (m_smallest_normalized, p_inf, "-0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_normalized, m_inf, "0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_normalized, p_zero, "-inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (m_smallest_normalized, m_zero, "inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (m_smallest_normalized, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_smallest_normalized, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_smallest_normalized, p_normal_value, "-0x1p-126", Status::OK, Category::Normal),
-        (m_smallest_normalized, m_normal_value, "0x1p-126", Status::OK, Category::Normal),
-        (m_smallest_normalized, p_largest_value, "-0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_normalized, m_largest_value, "0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_normalized, p_smallest_value, "-0x1p+23", Status::OK, Category::Normal),
-        (m_smallest_normalized, m_smallest_value, "0x1p+23", Status::OK, Category::Normal),
-        (m_smallest_normalized, p_smallest_normalized, "-0x1p+0", Status::OK, Category::Normal),
-        (m_smallest_normalized, m_smallest_normalized, "0x1p+0", Status::OK, Category::Normal),
-    ];
-
-    for (x, y, e_result, e_status, e_category) in special_cases {
-        let status;
-        let result = unpack!(status=, x / y);
-        assert_eq!(status, e_status);
-        assert_eq!(result.category(), e_category);
-        assert!(result.bitwise_eq(e_result.parse::<Single>().unwrap()));
-    }
-}
-
-#[test]
-fn operator_overloads() {
-    // This is mostly testing that these operator overloads compile.
-    let one = "0x1p+0".parse::<Single>().unwrap();
-    let two = "0x2p+0".parse::<Single>().unwrap();
-    assert!(two.bitwise_eq((one + one).value));
-    assert!(one.bitwise_eq((two - one).value));
-    assert!(two.bitwise_eq((one * two).value));
-    assert!(one.bitwise_eq((two / two).value));
-}
-
-#[test]
-fn abs() {
-    let p_inf = Single::INFINITY;
-    let m_inf = -Single::INFINITY;
-    let p_zero = Single::ZERO;
-    let m_zero = -Single::ZERO;
-    let p_qnan = Single::NAN;
-    let m_qnan = -Single::NAN;
-    let p_snan = Single::snan(None);
-    let m_snan = -Single::snan(None);
-    let p_normal_value = "0x1p+0".parse::<Single>().unwrap();
-    let m_normal_value = "-0x1p+0".parse::<Single>().unwrap();
-    let p_largest_value = Single::largest();
-    let m_largest_value = -Single::largest();
-    let p_smallest_value = Single::SMALLEST;
-    let m_smallest_value = -Single::SMALLEST;
-    let p_smallest_normalized = Single::smallest_normalized();
-    let m_smallest_normalized = -Single::smallest_normalized();
-
-    assert!(p_inf.bitwise_eq(p_inf.abs()));
-    assert!(p_inf.bitwise_eq(m_inf.abs()));
-    assert!(p_zero.bitwise_eq(p_zero.abs()));
-    assert!(p_zero.bitwise_eq(m_zero.abs()));
-    assert!(p_qnan.bitwise_eq(p_qnan.abs()));
-    assert!(p_qnan.bitwise_eq(m_qnan.abs()));
-    assert!(p_snan.bitwise_eq(p_snan.abs()));
-    assert!(p_snan.bitwise_eq(m_snan.abs()));
-    assert!(p_normal_value.bitwise_eq(p_normal_value.abs()));
-    assert!(p_normal_value.bitwise_eq(m_normal_value.abs()));
-    assert!(p_largest_value.bitwise_eq(p_largest_value.abs()));
-    assert!(p_largest_value.bitwise_eq(m_largest_value.abs()));
-    assert!(p_smallest_value.bitwise_eq(p_smallest_value.abs()));
-    assert!(p_smallest_value.bitwise_eq(m_smallest_value.abs()));
-    assert!(p_smallest_normalized.bitwise_eq(p_smallest_normalized.abs(),));
-    assert!(p_smallest_normalized.bitwise_eq(m_smallest_normalized.abs(),));
-}
-
-#[test]
-fn neg() {
-    let one = "1.0".parse::<Single>().unwrap();
-    let neg_one = "-1.0".parse::<Single>().unwrap();
-    let zero = Single::ZERO;
-    let neg_zero = -Single::ZERO;
-    let inf = Single::INFINITY;
-    let neg_inf = -Single::INFINITY;
-    let qnan = Single::NAN;
-    let neg_qnan = -Single::NAN;
-
-    assert!(neg_one.bitwise_eq(-one));
-    assert!(one.bitwise_eq(-neg_one));
-    assert!(neg_zero.bitwise_eq(-zero));
-    assert!(zero.bitwise_eq(-neg_zero));
-    assert!(neg_inf.bitwise_eq(-inf));
-    assert!(inf.bitwise_eq(-neg_inf));
-    assert!(neg_inf.bitwise_eq(-inf));
-    assert!(inf.bitwise_eq(-neg_inf));
-    assert!(neg_qnan.bitwise_eq(-qnan));
-    assert!(qnan.bitwise_eq(-neg_qnan));
-}
-
-#[test]
-fn ilogb() {
-    assert_eq!(-1074, Double::SMALLEST.ilogb());
-    assert_eq!(-1074, (-Double::SMALLEST).ilogb());
-    assert_eq!(-1023, "0x1.ffffffffffffep-1024".parse::<Double>().unwrap().ilogb());
-    assert_eq!(-1023, "0x1.ffffffffffffep-1023".parse::<Double>().unwrap().ilogb());
-    assert_eq!(-1023, "-0x1.ffffffffffffep-1023".parse::<Double>().unwrap().ilogb());
-    assert_eq!(-51, "0x1p-51".parse::<Double>().unwrap().ilogb());
-    assert_eq!(-1023, "0x1.c60f120d9f87cp-1023".parse::<Double>().unwrap().ilogb());
-    assert_eq!(-2, "0x0.ffffp-1".parse::<Double>().unwrap().ilogb());
-    assert_eq!(-1023, "0x1.fffep-1023".parse::<Double>().unwrap().ilogb());
-    assert_eq!(1023, Double::largest().ilogb());
-    assert_eq!(1023, (-Double::largest()).ilogb());
-
-    assert_eq!(0, "0x1p+0".parse::<Single>().unwrap().ilogb());
-    assert_eq!(0, "-0x1p+0".parse::<Single>().unwrap().ilogb());
-    assert_eq!(42, "0x1p+42".parse::<Single>().unwrap().ilogb());
-    assert_eq!(-42, "0x1p-42".parse::<Single>().unwrap().ilogb());
-
-    assert_eq!(IEK_INF, Single::INFINITY.ilogb());
-    assert_eq!(IEK_INF, (-Single::INFINITY).ilogb());
-    assert_eq!(IEK_ZERO, Single::ZERO.ilogb());
-    assert_eq!(IEK_ZERO, (-Single::ZERO).ilogb());
-    assert_eq!(IEK_NAN, Single::NAN.ilogb());
-    assert_eq!(IEK_NAN, Single::snan(None).ilogb());
-
-    assert_eq!(127, Single::largest().ilogb());
-    assert_eq!(127, (-Single::largest()).ilogb());
-
-    assert_eq!(-149, Single::SMALLEST.ilogb());
-    assert_eq!(-149, (-Single::SMALLEST).ilogb());
-    assert_eq!(-126, Single::smallest_normalized().ilogb());
-    assert_eq!(-126, (-Single::smallest_normalized()).ilogb());
-}
-
-#[test]
-fn scalbn() {
-    assert!(
-        "0x1p+0"
-            .parse::<Single>()
-            .unwrap()
-            .bitwise_eq("0x1p+0".parse::<Single>().unwrap().scalbn(0),)
-    );
-    assert!(
-        "0x1p+42"
-            .parse::<Single>()
-            .unwrap()
-            .bitwise_eq("0x1p+0".parse::<Single>().unwrap().scalbn(42),)
-    );
-    assert!(
-        "0x1p-42"
-            .parse::<Single>()
-            .unwrap()
-            .bitwise_eq("0x1p+0".parse::<Single>().unwrap().scalbn(-42),)
-    );
-
-    let p_inf = Single::INFINITY;
-    let m_inf = -Single::INFINITY;
-    let p_zero = Single::ZERO;
-    let m_zero = -Single::ZERO;
-    let p_qnan = Single::NAN;
-    let m_qnan = -Single::NAN;
-    let snan = Single::snan(None);
-
-    assert!(p_inf.bitwise_eq(p_inf.scalbn(0)));
-    assert!(m_inf.bitwise_eq(m_inf.scalbn(0)));
-    assert!(p_zero.bitwise_eq(p_zero.scalbn(0)));
-    assert!(m_zero.bitwise_eq(m_zero.scalbn(0)));
-    assert!(p_qnan.bitwise_eq(p_qnan.scalbn(0)));
-    assert!(m_qnan.bitwise_eq(m_qnan.scalbn(0)));
-    assert!(!snan.scalbn(0).is_signaling());
-
-    let scalbn_snan = snan.scalbn(1);
-    assert!(scalbn_snan.is_nan() && !scalbn_snan.is_signaling());
-
-    // Make sure highest bit of payload is preserved.
-    let payload = (1 << 50) | (1 << 49) | (1234 << 32) | 1;
-
-    let snan_with_payload = Double::snan(Some(payload));
-    let quiet_payload = snan_with_payload.scalbn(1);
-    assert!(quiet_payload.is_nan() && !quiet_payload.is_signaling());
-    assert_eq!(payload, quiet_payload.to_bits() & ((1 << 51) - 1));
-
-    assert!(p_inf.bitwise_eq("0x1p+0".parse::<Single>().unwrap().scalbn(128),));
-    assert!(m_inf.bitwise_eq("-0x1p+0".parse::<Single>().unwrap().scalbn(128),));
-    assert!(p_inf.bitwise_eq("0x1p+127".parse::<Single>().unwrap().scalbn(1),));
-    assert!(p_zero.bitwise_eq("0x1p-127".parse::<Single>().unwrap().scalbn(-127),));
-    assert!(m_zero.bitwise_eq("-0x1p-127".parse::<Single>().unwrap().scalbn(-127),));
-    assert!(
-        "-0x1p-149"
-            .parse::<Single>()
-            .unwrap()
-            .bitwise_eq("-0x1p-127".parse::<Single>().unwrap().scalbn(-22),)
-    );
-    assert!(p_zero.bitwise_eq("0x1p-126".parse::<Single>().unwrap().scalbn(-24),));
-
-    let smallest_f64 = Double::SMALLEST;
-    let neg_smallest_f64 = -Double::SMALLEST;
-
-    let largest_f64 = Double::largest();
-    let neg_largest_f64 = -Double::largest();
-
-    let largest_denormal_f64 = "0x1.ffffffffffffep-1023".parse::<Double>().unwrap();
-    let neg_largest_denormal_f64 = "-0x1.ffffffffffffep-1023".parse::<Double>().unwrap();
-
-    assert!(smallest_f64.bitwise_eq("0x1p-1074".parse::<Double>().unwrap().scalbn(0),));
-    assert!(neg_smallest_f64.bitwise_eq("-0x1p-1074".parse::<Double>().unwrap().scalbn(0),));
-
-    assert!("0x1p+1023".parse::<Double>().unwrap().bitwise_eq(smallest_f64.scalbn(2097,),));
-
-    assert!(smallest_f64.scalbn(-2097).is_pos_zero());
-    assert!(smallest_f64.scalbn(-2098).is_pos_zero());
-    assert!(smallest_f64.scalbn(-2099).is_pos_zero());
-    assert!("0x1p+1022".parse::<Double>().unwrap().bitwise_eq(smallest_f64.scalbn(2096,),));
-    assert!("0x1p+1023".parse::<Double>().unwrap().bitwise_eq(smallest_f64.scalbn(2097,),));
-    assert!(smallest_f64.scalbn(2098).is_infinite());
-    assert!(smallest_f64.scalbn(2099).is_infinite());
-
-    // Test for integer overflows when adding to exponent.
-    assert!(smallest_f64.scalbn(-ExpInt::MAX).is_pos_zero());
-    assert!(largest_f64.scalbn(ExpInt::MAX).is_infinite());
-
-    assert!(largest_denormal_f64.bitwise_eq(largest_denormal_f64.scalbn(0),));
-    assert!(neg_largest_denormal_f64.bitwise_eq(neg_largest_denormal_f64.scalbn(0),));
-
-    assert!(
-        "0x1.ffffffffffffep-1022"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq(largest_denormal_f64.scalbn(1))
-    );
-    assert!(
-        "-0x1.ffffffffffffep-1021"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq(neg_largest_denormal_f64.scalbn(2))
-    );
-
-    assert!(
-        "0x1.ffffffffffffep+1"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq(largest_denormal_f64.scalbn(1024))
-    );
-    assert!(largest_denormal_f64.scalbn(-1023).is_pos_zero());
-    assert!(largest_denormal_f64.scalbn(-1024).is_pos_zero());
-    assert!(largest_denormal_f64.scalbn(-2048).is_pos_zero());
-    assert!(largest_denormal_f64.scalbn(2047).is_infinite());
-    assert!(largest_denormal_f64.scalbn(2098).is_infinite());
-    assert!(largest_denormal_f64.scalbn(2099).is_infinite());
-
-    assert!(
-        "0x1.ffffffffffffep-2"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq(largest_denormal_f64.scalbn(1021))
-    );
-    assert!(
-        "0x1.ffffffffffffep-1"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq(largest_denormal_f64.scalbn(1022))
-    );
-    assert!(
-        "0x1.ffffffffffffep+0"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq(largest_denormal_f64.scalbn(1023))
-    );
-    assert!(
-        "0x1.ffffffffffffep+1023"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq(largest_denormal_f64.scalbn(2046))
-    );
-    assert!("0x1p+974".parse::<Double>().unwrap().bitwise_eq(smallest_f64.scalbn(2048,),));
-
-    let random_denormal_f64 = "0x1.c60f120d9f87cp+51".parse::<Double>().unwrap();
-    assert!(
-        "0x1.c60f120d9f87cp-972"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq(random_denormal_f64.scalbn(-1023))
-    );
-    assert!(
-        "0x1.c60f120d9f87cp-1"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq(random_denormal_f64.scalbn(-52))
-    );
-    assert!(
-        "0x1.c60f120d9f87cp-2"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq(random_denormal_f64.scalbn(-53))
-    );
-    assert!(
-        "0x1.c60f120d9f87cp+0"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq(random_denormal_f64.scalbn(-51))
-    );
-
-    assert!(random_denormal_f64.scalbn(-2097).is_pos_zero());
-    assert!(random_denormal_f64.scalbn(-2090).is_pos_zero());
-
-    assert!("-0x1p-1073".parse::<Double>().unwrap().bitwise_eq(neg_largest_f64.scalbn(-2097),));
-
-    assert!("-0x1p-1024".parse::<Double>().unwrap().bitwise_eq(neg_largest_f64.scalbn(-2048),));
-
-    assert!("0x1p-1073".parse::<Double>().unwrap().bitwise_eq(largest_f64.scalbn(-2097,),));
-
-    assert!("0x1p-1074".parse::<Double>().unwrap().bitwise_eq(largest_f64.scalbn(-2098,),));
-    assert!("-0x1p-1074".parse::<Double>().unwrap().bitwise_eq(neg_largest_f64.scalbn(-2098),));
-    assert!(neg_largest_f64.scalbn(-2099).is_neg_zero());
-    assert!(largest_f64.scalbn(1).is_infinite());
-
-    assert!(
-        "0x1p+0"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq("0x1p+52".parse::<Double>().unwrap().scalbn(-52),)
-    );
-
-    assert!(
-        "0x1p-103"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq("0x1p-51".parse::<Double>().unwrap().scalbn(-52),)
-    );
-}
-
-#[test]
-fn frexp() {
-    let p_zero = Double::ZERO;
-    let m_zero = -Double::ZERO;
-    let one = Double::from_f64(1.0);
-    let m_one = Double::from_f64(-1.0);
-
-    let largest_denormal = "0x1.ffffffffffffep-1023".parse::<Double>().unwrap();
-    let neg_largest_denormal = "-0x1.ffffffffffffep-1023".parse::<Double>().unwrap();
-
-    let smallest = Double::SMALLEST;
-    let neg_smallest = -Double::SMALLEST;
-
-    let largest = Double::largest();
-    let neg_largest = -Double::largest();
-
-    let p_inf = Double::INFINITY;
-    let m_inf = -Double::INFINITY;
-
-    let p_qnan = Double::NAN;
-    let m_qnan = -Double::NAN;
-    let snan = Double::snan(None);
-
-    // Make sure highest bit of payload is preserved.
-    let payload = (1 << 50) | (1 << 49) | (1234 << 32) | 1;
-
-    let snan_with_payload = Double::snan(Some(payload));
-
-    let mut exp = 0;
-
-    let frac = p_zero.frexp(&mut exp);
-    assert_eq!(0, exp);
-    assert!(frac.is_pos_zero());
-
-    let frac = m_zero.frexp(&mut exp);
-    assert_eq!(0, exp);
-    assert!(frac.is_neg_zero());
-
-    let frac = one.frexp(&mut exp);
-    assert_eq!(1, exp);
-    assert!("0x1p-1".parse::<Double>().unwrap().bitwise_eq(frac));
-
-    let frac = m_one.frexp(&mut exp);
-    assert_eq!(1, exp);
-    assert!("-0x1p-1".parse::<Double>().unwrap().bitwise_eq(frac));
-
-    let frac = largest_denormal.frexp(&mut exp);
-    assert_eq!(-1022, exp);
-    assert!("0x1.ffffffffffffep-1".parse::<Double>().unwrap().bitwise_eq(frac));
-
-    let frac = neg_largest_denormal.frexp(&mut exp);
-    assert_eq!(-1022, exp);
-    assert!("-0x1.ffffffffffffep-1".parse::<Double>().unwrap().bitwise_eq(frac));
-
-    let frac = smallest.frexp(&mut exp);
-    assert_eq!(-1073, exp);
-    assert!("0x1p-1".parse::<Double>().unwrap().bitwise_eq(frac));
-
-    let frac = neg_smallest.frexp(&mut exp);
-    assert_eq!(-1073, exp);
-    assert!("-0x1p-1".parse::<Double>().unwrap().bitwise_eq(frac));
-
-    let frac = largest.frexp(&mut exp);
-    assert_eq!(1024, exp);
-    assert!("0x1.fffffffffffffp-1".parse::<Double>().unwrap().bitwise_eq(frac));
-
-    let frac = neg_largest.frexp(&mut exp);
-    assert_eq!(1024, exp);
-    assert!("-0x1.fffffffffffffp-1".parse::<Double>().unwrap().bitwise_eq(frac));
-
-    let frac = p_inf.frexp(&mut exp);
-    assert_eq!(IEK_INF, exp);
-    assert!(frac.is_infinite() && !frac.is_negative());
-
-    let frac = m_inf.frexp(&mut exp);
-    assert_eq!(IEK_INF, exp);
-    assert!(frac.is_infinite() && frac.is_negative());
-
-    let frac = p_qnan.frexp(&mut exp);
-    assert_eq!(IEK_NAN, exp);
-    assert!(frac.is_nan());
-
-    let frac = m_qnan.frexp(&mut exp);
-    assert_eq!(IEK_NAN, exp);
-    assert!(frac.is_nan());
-
-    let frac = snan.frexp(&mut exp);
-    assert_eq!(IEK_NAN, exp);
-    assert!(frac.is_nan() && !frac.is_signaling());
-
-    let frac = snan_with_payload.frexp(&mut exp);
-    assert_eq!(IEK_NAN, exp);
-    assert!(frac.is_nan() && !frac.is_signaling());
-    assert_eq!(payload, frac.to_bits() & ((1 << 51) - 1));
-
-    let frac = "0x0.ffffp-1".parse::<Double>().unwrap().frexp(&mut exp);
-    assert_eq!(-1, exp);
-    assert!("0x1.fffep-1".parse::<Double>().unwrap().bitwise_eq(frac));
-
-    let frac = "0x1p-51".parse::<Double>().unwrap().frexp(&mut exp);
-    assert_eq!(-50, exp);
-    assert!("0x1p-1".parse::<Double>().unwrap().bitwise_eq(frac));
-
-    let frac = "0x1.c60f120d9f87cp+51".parse::<Double>().unwrap().frexp(&mut exp);
-    assert_eq!(52, exp);
-    assert!("0x1.c60f120d9f87cp-1".parse::<Double>().unwrap().bitwise_eq(frac));
-}
-
-#[test]
-fn modulo() {
-    let mut status;
-    {
-        let f1 = "1.5".parse::<Double>().unwrap();
-        let f2 = "1.0".parse::<Double>().unwrap();
-        let expected = "0.5".parse::<Double>().unwrap();
-        assert!(unpack!(status=, f1 % f2).bitwise_eq(expected));
-        assert_eq!(status, Status::OK);
-    }
-    {
-        let f1 = "0.5".parse::<Double>().unwrap();
-        let f2 = "1.0".parse::<Double>().unwrap();
-        let expected = "0.5".parse::<Double>().unwrap();
-        assert!(unpack!(status=, f1 % f2).bitwise_eq(expected));
-        assert_eq!(status, Status::OK);
-    }
-    {
-        let f1 = "0x1.3333333333333p-2".parse::<Double>().unwrap(); // 0.3
-        let f2 = "0x1.47ae147ae147bp-7".parse::<Double>().unwrap(); // 0.01
-        // 0.009999999999999983
-        let expected = "0x1.47ae147ae1471p-7".parse::<Double>().unwrap();
-        assert!(unpack!(status=, f1 % f2).bitwise_eq(expected));
-        assert_eq!(status, Status::OK);
-    }
-    {
-        let f1 = "0x1p64".parse::<Double>().unwrap(); // 1.8446744073709552e19
-        let f2 = "1.5".parse::<Double>().unwrap();
-        let expected = "1.0".parse::<Double>().unwrap();
-        assert!(unpack!(status=, f1 % f2).bitwise_eq(expected));
-        assert_eq!(status, Status::OK);
-    }
-    {
-        let f1 = "0x1p1000".parse::<Double>().unwrap();
-        let f2 = "0x1p-1000".parse::<Double>().unwrap();
-        let expected = "0.0".parse::<Double>().unwrap();
-        assert!(unpack!(status=, f1 % f2).bitwise_eq(expected));
-        assert_eq!(status, Status::OK);
-    }
-    {
-        let f1 = "0.0".parse::<Double>().unwrap();
-        let f2 = "1.0".parse::<Double>().unwrap();
-        let expected = "0.0".parse::<Double>().unwrap();
-        assert!(unpack!(status=, f1 % f2).bitwise_eq(expected));
-        assert_eq!(status, Status::OK);
-    }
-    {
-        let f1 = "1.0".parse::<Double>().unwrap();
-        let f2 = "0.0".parse::<Double>().unwrap();
-        assert!(unpack!(status=, f1 % f2).is_nan());
-        assert_eq!(status, Status::INVALID_OP);
-    }
-    {
-        let f1 = "0.0".parse::<Double>().unwrap();
-        let f2 = "0.0".parse::<Double>().unwrap();
-        assert!(unpack!(status=, f1 % f2).is_nan());
-        assert_eq!(status, Status::INVALID_OP);
-    }
-    {
-        let f1 = Double::INFINITY;
-        let f2 = "1.0".parse::<Double>().unwrap();
-        assert!(unpack!(status=, f1 % f2).is_nan());
-        assert_eq!(status, Status::INVALID_OP);
-    }
-}
diff --git a/compiler/rustc_apfloat/tests/ppc.rs b/compiler/rustc_apfloat/tests/ppc.rs
deleted file mode 100644
index c769d265437..00000000000
--- a/compiler/rustc_apfloat/tests/ppc.rs
+++ /dev/null
@@ -1,530 +0,0 @@
-use rustc_apfloat::ppc::DoubleDouble;
-use rustc_apfloat::{Category, Float, Round};
-
-use std::cmp::Ordering;
-
-#[test]
-fn ppc_double_double() {
-    let test = DoubleDouble::ZERO;
-    let expected = "0x0p+0".parse::<DoubleDouble>().unwrap();
-    assert!(test.is_zero());
-    assert!(!test.is_negative());
-    assert!(test.bitwise_eq(expected));
-    assert_eq!(0, test.to_bits());
-
-    let test = -DoubleDouble::ZERO;
-    let expected = "-0x0p+0".parse::<DoubleDouble>().unwrap();
-    assert!(test.is_zero());
-    assert!(test.is_negative());
-    assert!(test.bitwise_eq(expected));
-    assert_eq!(0x8000000000000000, test.to_bits());
-
-    let test = "1.0".parse::<DoubleDouble>().unwrap();
-    assert_eq!(0x3ff0000000000000, test.to_bits());
-
-    // LDBL_MAX
-    let test = "1.79769313486231580793728971405301e+308".parse::<DoubleDouble>().unwrap();
-    assert_eq!(0x7c8ffffffffffffe_7fefffffffffffff, test.to_bits());
-
-    // LDBL_MIN
-    let test = "2.00416836000897277799610805135016e-292".parse::<DoubleDouble>().unwrap();
-    assert_eq!(0x0000000000000000_0360000000000000, test.to_bits());
-}
-
-#[test]
-fn ppc_double_double_add_special() {
-    let data = [
-        // (1 + 0) + (-1 + 0) = Category::Zero
-        (0x3ff0000000000000, 0xbff0000000000000, Category::Zero, Round::NearestTiesToEven),
-        // LDBL_MAX + (1.1 >> (1023 - 106) + 0)) = Category::Infinity
-        (
-            0x7c8ffffffffffffe_7fefffffffffffff,
-            0x7948000000000000,
-            Category::Infinity,
-            Round::NearestTiesToEven,
-        ),
-        // FIXME: change the 4th 0x75effffffffffffe to 0x75efffffffffffff when
-        // DoubleDouble's fallback is gone.
-        // LDBL_MAX + (1.011111... >> (1023 - 106) + (1.1111111...0 >> (1023 -
-        // 160))) = Category::Normal
-        (
-            0x7c8ffffffffffffe_7fefffffffffffff,
-            0x75effffffffffffe_7947ffffffffffff,
-            Category::Normal,
-            Round::NearestTiesToEven,
-        ),
-        // LDBL_MAX + (1.1 >> (1023 - 106) + 0)) = Category::Infinity
-        (
-            0x7c8ffffffffffffe_7fefffffffffffff,
-            0x7c8ffffffffffffe_7fefffffffffffff,
-            Category::Infinity,
-            Round::NearestTiesToEven,
-        ),
-        // NaN + (1 + 0) = Category::NaN
-        (0x7ff8000000000000, 0x3ff0000000000000, Category::NaN, Round::NearestTiesToEven),
-    ];
-
-    for (op1, op2, expected, round) in data {
-        {
-            let mut a1 = DoubleDouble::from_bits(op1);
-            let a2 = DoubleDouble::from_bits(op2);
-            a1 = a1.add_r(a2, round).value;
-
-            assert_eq!(expected, a1.category(), "{:#x} + {:#x}", op1, op2);
-        }
-        {
-            let a1 = DoubleDouble::from_bits(op1);
-            let mut a2 = DoubleDouble::from_bits(op2);
-            a2 = a2.add_r(a1, round).value;
-
-            assert_eq!(expected, a2.category(), "{:#x} + {:#x}", op2, op1);
-        }
-    }
-}
-
-#[test]
-fn ppc_double_double_add() {
-    let data = [
-        // (1 + 0) + (1e-105 + 0) = (1 + 1e-105)
-        (
-            0x3ff0000000000000,
-            0x3960000000000000,
-            0x3960000000000000_3ff0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // (1 + 0) + (1e-106 + 0) = (1 + 1e-106)
-        (
-            0x3ff0000000000000,
-            0x3950000000000000,
-            0x3950000000000000_3ff0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // (1 + 1e-106) + (1e-106 + 0) = (1 + 1e-105)
-        (
-            0x3950000000000000_3ff0000000000000,
-            0x3950000000000000,
-            0x3960000000000000_3ff0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // (1 + 0) + (epsilon + 0) = (1 + epsilon)
-        (
-            0x3ff0000000000000,
-            0x0000000000000001,
-            0x0000000000000001_3ff0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // FIXME: change 0xf950000000000000 to 0xf940000000000000, when
-        // DoubleDouble's fallback is gone.
-        // (DBL_MAX - 1 << (1023 - 105)) + (1 << (1023 - 53) + 0) = DBL_MAX +
-        // 1.11111... << (1023 - 52)
-        (
-            0xf950000000000000_7fefffffffffffff,
-            0x7c90000000000000,
-            0x7c8ffffffffffffe_7fefffffffffffff,
-            Round::NearestTiesToEven,
-        ),
-        // FIXME: change 0xf950000000000000 to 0xf940000000000000, when
-        // DoubleDouble's fallback is gone.
-        // (1 << (1023 - 53) + 0) + (DBL_MAX - 1 << (1023 - 105)) = DBL_MAX +
-        // 1.11111... << (1023 - 52)
-        (
-            0x7c90000000000000,
-            0xf950000000000000_7fefffffffffffff,
-            0x7c8ffffffffffffe_7fefffffffffffff,
-            Round::NearestTiesToEven,
-        ),
-    ];
-
-    for (op1, op2, expected, round) in data {
-        {
-            let mut a1 = DoubleDouble::from_bits(op1);
-            let a2 = DoubleDouble::from_bits(op2);
-            a1 = a1.add_r(a2, round).value;
-
-            assert_eq!(expected, a1.to_bits(), "{:#x} + {:#x}", op1, op2);
-        }
-        {
-            let a1 = DoubleDouble::from_bits(op1);
-            let mut a2 = DoubleDouble::from_bits(op2);
-            a2 = a2.add_r(a1, round).value;
-
-            assert_eq!(expected, a2.to_bits(), "{:#x} + {:#x}", op2, op1);
-        }
-    }
-}
-
-#[test]
-fn ppc_double_double_subtract() {
-    let data = [
-        // (1 + 0) - (-1e-105 + 0) = (1 + 1e-105)
-        (
-            0x3ff0000000000000,
-            0xb960000000000000,
-            0x3960000000000000_3ff0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // (1 + 0) - (-1e-106 + 0) = (1 + 1e-106)
-        (
-            0x3ff0000000000000,
-            0xb950000000000000,
-            0x3950000000000000_3ff0000000000000,
-            Round::NearestTiesToEven,
-        ),
-    ];
-
-    for (op1, op2, expected, round) in data {
-        let mut a1 = DoubleDouble::from_bits(op1);
-        let a2 = DoubleDouble::from_bits(op2);
-        a1 = a1.sub_r(a2, round).value;
-
-        assert_eq!(expected, a1.to_bits(), "{:#x} - {:#x}", op1, op2);
-    }
-}
-
-#[test]
-fn ppc_double_double_multiply_special() {
-    let data = [
-        // Category::NaN * Category::NaN = Category::NaN
-        (0x7ff8000000000000, 0x7ff8000000000000, Category::NaN, Round::NearestTiesToEven),
-        // Category::NaN * Category::Zero = Category::NaN
-        (0x7ff8000000000000, 0, Category::NaN, Round::NearestTiesToEven),
-        // Category::NaN * Category::Infinity = Category::NaN
-        (0x7ff8000000000000, 0x7ff0000000000000, Category::NaN, Round::NearestTiesToEven),
-        // Category::NaN * Category::Normal = Category::NaN
-        (0x7ff8000000000000, 0x3ff0000000000000, Category::NaN, Round::NearestTiesToEven),
-        // Category::Infinity * Category::Infinity = Category::Infinity
-        (0x7ff0000000000000, 0x7ff0000000000000, Category::Infinity, Round::NearestTiesToEven),
-        // Category::Infinity * Category::Zero = Category::NaN
-        (0x7ff0000000000000, 0, Category::NaN, Round::NearestTiesToEven),
-        // Category::Infinity * Category::Normal = Category::Infinity
-        (0x7ff0000000000000, 0x3ff0000000000000, Category::Infinity, Round::NearestTiesToEven),
-        // Category::Zero * Category::Zero = Category::Zero
-        (0, 0, Category::Zero, Round::NearestTiesToEven),
-        // Category::Zero * Category::Normal = Category::Zero
-        (0, 0x3ff0000000000000, Category::Zero, Round::NearestTiesToEven),
-    ];
-
-    for (op1, op2, expected, round) in data {
-        {
-            let mut a1 = DoubleDouble::from_bits(op1);
-            let a2 = DoubleDouble::from_bits(op2);
-            a1 = a1.mul_r(a2, round).value;
-
-            assert_eq!(expected, a1.category(), "{:#x} * {:#x}", op1, op2);
-        }
-        {
-            let a1 = DoubleDouble::from_bits(op1);
-            let mut a2 = DoubleDouble::from_bits(op2);
-            a2 = a2.mul_r(a1, round).value;
-
-            assert_eq!(expected, a2.category(), "{:#x} * {:#x}", op2, op1);
-        }
-    }
-}
-
-#[test]
-fn ppc_double_double_multiply() {
-    let data = [
-        // 1/3 * 3 = 1.0
-        (
-            0x3c75555555555556_3fd5555555555555,
-            0x4008000000000000,
-            0x3ff0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // (1 + epsilon) * (1 + 0) = Category::Zero
-        (
-            0x0000000000000001_3ff0000000000000,
-            0x3ff0000000000000,
-            0x0000000000000001_3ff0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // (1 + epsilon) * (1 + epsilon) = 1 + 2 * epsilon
-        (
-            0x0000000000000001_3ff0000000000000,
-            0x0000000000000001_3ff0000000000000,
-            0x0000000000000002_3ff0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // -(1 + epsilon) * (1 + epsilon) = -1
-        (
-            0x0000000000000001_bff0000000000000,
-            0x0000000000000001_3ff0000000000000,
-            0xbff0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // (0.5 + 0) * (1 + 2 * epsilon) = 0.5 + epsilon
-        (
-            0x3fe0000000000000,
-            0x0000000000000002_3ff0000000000000,
-            0x0000000000000001_3fe0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // (0.5 + 0) * (1 + epsilon) = 0.5
-        (
-            0x3fe0000000000000,
-            0x0000000000000001_3ff0000000000000,
-            0x3fe0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // __LDBL_MAX__ * (1 + 1 << 106) = inf
-        (
-            0x7c8ffffffffffffe_7fefffffffffffff,
-            0x3950000000000000_3ff0000000000000,
-            0x7ff0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // __LDBL_MAX__ * (1 + 1 << 107) > __LDBL_MAX__, but not inf, yes =_=|||
-        (
-            0x7c8ffffffffffffe_7fefffffffffffff,
-            0x3940000000000000_3ff0000000000000,
-            0x7c8fffffffffffff_7fefffffffffffff,
-            Round::NearestTiesToEven,
-        ),
-        // __LDBL_MAX__ * (1 + 1 << 108) = __LDBL_MAX__
-        (
-            0x7c8ffffffffffffe_7fefffffffffffff,
-            0x3930000000000000_3ff0000000000000,
-            0x7c8ffffffffffffe_7fefffffffffffff,
-            Round::NearestTiesToEven,
-        ),
-    ];
-
-    for (op1, op2, expected, round) in data {
-        {
-            let mut a1 = DoubleDouble::from_bits(op1);
-            let a2 = DoubleDouble::from_bits(op2);
-            a1 = a1.mul_r(a2, round).value;
-
-            assert_eq!(expected, a1.to_bits(), "{:#x} * {:#x}", op1, op2);
-        }
-        {
-            let a1 = DoubleDouble::from_bits(op1);
-            let mut a2 = DoubleDouble::from_bits(op2);
-            a2 = a2.mul_r(a1, round).value;
-
-            assert_eq!(expected, a2.to_bits(), "{:#x} * {:#x}", op2, op1);
-        }
-    }
-}
-
-#[test]
-fn ppc_double_double_divide() {
-    // FIXME: Only a sanity check for now. Add more edge cases when the
-    // double-double algorithm is implemented.
-    let data = [
-        // 1 / 3 = 1/3
-        (
-            0x3ff0000000000000,
-            0x4008000000000000,
-            0x3c75555555555556_3fd5555555555555,
-            Round::NearestTiesToEven,
-        ),
-    ];
-
-    for (op1, op2, expected, round) in data {
-        let mut a1 = DoubleDouble::from_bits(op1);
-        let a2 = DoubleDouble::from_bits(op2);
-        a1 = a1.div_r(a2, round).value;
-
-        assert_eq!(expected, a1.to_bits(), "{:#x} / {:#x}", op1, op2);
-    }
-}
-
-#[test]
-fn ppc_double_double_remainder() {
-    let data = [
-        // ieee_rem(3.0 + 3.0 << 53, 1.25 + 1.25 << 53) = (0.5 + 0.5 << 53)
-        (
-            0x3cb8000000000000_4008000000000000,
-            0x3ca4000000000000_3ff4000000000000,
-            0x3c90000000000000_3fe0000000000000,
-        ),
-        // ieee_rem(3.0 + 3.0 << 53, 1.75 + 1.75 << 53) = (-0.5 - 0.5 << 53)
-        (
-            0x3cb8000000000000_4008000000000000,
-            0x3cac000000000000_3ffc000000000000,
-            0xbc90000000000000_bfe0000000000000,
-        ),
-    ];
-
-    for (op1, op2, expected) in data {
-        let a1 = DoubleDouble::from_bits(op1);
-        let a2 = DoubleDouble::from_bits(op2);
-        let result = a1.ieee_rem(a2).value;
-
-        assert_eq!(expected, result.to_bits(), "ieee_rem({:#x}, {:#x})", op1, op2);
-    }
-}
-
-#[test]
-fn ppc_double_double_mod() {
-    let data = [
-        // mod(3.0 + 3.0 << 53, 1.25 + 1.25 << 53) = (0.5 + 0.5 << 53)
-        (
-            0x3cb8000000000000_4008000000000000,
-            0x3ca4000000000000_3ff4000000000000,
-            0x3c90000000000000_3fe0000000000000,
-        ),
-        // mod(3.0 + 3.0 << 53, 1.75 + 1.75 << 53) = (1.25 + 1.25 << 53)
-        // 0xbc98000000000000 doesn't seem right, but it's what we currently have.
-        // FIXME: investigate
-        (
-            0x3cb8000000000000_4008000000000000,
-            0x3cac000000000000_3ffc000000000000,
-            0xbc98000000000000_3ff4000000000001,
-        ),
-    ];
-
-    for (op1, op2, expected) in data {
-        let a1 = DoubleDouble::from_bits(op1);
-        let a2 = DoubleDouble::from_bits(op2);
-        let r = (a1 % a2).value;
-
-        assert_eq!(expected, r.to_bits(), "fmod({:#x}, {:#x})", op1, op2);
-    }
-}
-
-#[test]
-fn ppc_double_double_fma() {
-    // Sanity check for now.
-    let mut a = "2".parse::<DoubleDouble>().unwrap();
-    a = a.mul_add("3".parse::<DoubleDouble>().unwrap(), "4".parse::<DoubleDouble>().unwrap()).value;
-    assert_eq!(Some(Ordering::Equal), "10".parse::<DoubleDouble>().unwrap().partial_cmp(&a));
-}
-
-#[test]
-fn ppc_double_double_round_to_integral() {
-    {
-        let a = "1.5".parse::<DoubleDouble>().unwrap();
-        let a = a.round_to_integral(Round::NearestTiesToEven).value;
-        assert_eq!(Some(Ordering::Equal), "2".parse::<DoubleDouble>().unwrap().partial_cmp(&a));
-    }
-    {
-        let a = "2.5".parse::<DoubleDouble>().unwrap();
-        let a = a.round_to_integral(Round::NearestTiesToEven).value;
-        assert_eq!(Some(Ordering::Equal), "2".parse::<DoubleDouble>().unwrap().partial_cmp(&a));
-    }
-}
-
-#[test]
-fn ppc_double_double_compare() {
-    let data = [
-        // (1 + 0) = (1 + 0)
-        (0x3ff0000000000000, 0x3ff0000000000000, Some(Ordering::Equal)),
-        // (1 + 0) < (1.00...1 + 0)
-        (0x3ff0000000000000, 0x3ff0000000000001, Some(Ordering::Less)),
-        // (1.00...1 + 0) > (1 + 0)
-        (0x3ff0000000000001, 0x3ff0000000000000, Some(Ordering::Greater)),
-        // (1 + 0) < (1 + epsilon)
-        (0x3ff0000000000000, 0x0000000000000001_3ff0000000000001, Some(Ordering::Less)),
-        // NaN != NaN
-        (0x7ff8000000000000, 0x7ff8000000000000, None),
-        // (1 + 0) != NaN
-        (0x3ff0000000000000, 0x7ff8000000000000, None),
-        // Inf = Inf
-        (0x7ff0000000000000, 0x7ff0000000000000, Some(Ordering::Equal)),
-    ];
-
-    for (op1, op2, expected) in data {
-        let a1 = DoubleDouble::from_bits(op1);
-        let a2 = DoubleDouble::from_bits(op2);
-        assert_eq!(expected, a1.partial_cmp(&a2), "compare({:#x}, {:#x})", op1, op2,);
-    }
-}
-
-#[test]
-fn ppc_double_double_bitwise_eq() {
-    let data = [
-        // (1 + 0) = (1 + 0)
-        (0x3ff0000000000000, 0x3ff0000000000000, true),
-        // (1 + 0) != (1.00...1 + 0)
-        (0x3ff0000000000000, 0x3ff0000000000001, false),
-        // NaN = NaN
-        (0x7ff8000000000000, 0x7ff8000000000000, true),
-        // NaN != NaN with a different bit pattern
-        (0x7ff8000000000000, 0x3ff0000000000000_7ff8000000000000, false),
-        // Inf = Inf
-        (0x7ff0000000000000, 0x7ff0000000000000, true),
-    ];
-
-    for (op1, op2, expected) in data {
-        let a1 = DoubleDouble::from_bits(op1);
-        let a2 = DoubleDouble::from_bits(op2);
-        assert_eq!(expected, a1.bitwise_eq(a2), "{:#x} = {:#x}", op1, op2);
-    }
-}
-
-#[test]
-fn ppc_double_double_change_sign() {
-    let float = DoubleDouble::from_bits(0xbcb0000000000000_400f000000000000);
-    {
-        let actual = float.copy_sign("1".parse::<DoubleDouble>().unwrap());
-        assert_eq!(0xbcb0000000000000_400f000000000000, actual.to_bits());
-    }
-    {
-        let actual = float.copy_sign("-1".parse::<DoubleDouble>().unwrap());
-        assert_eq!(0x3cb0000000000000_c00f000000000000, actual.to_bits());
-    }
-}
-
-#[test]
-fn ppc_double_double_factories() {
-    assert_eq!(0, DoubleDouble::ZERO.to_bits());
-    assert_eq!(0x7c8ffffffffffffe_7fefffffffffffff, DoubleDouble::largest().to_bits());
-    assert_eq!(0x0000000000000001, DoubleDouble::SMALLEST.to_bits());
-    assert_eq!(0x0360000000000000, DoubleDouble::smallest_normalized().to_bits());
-    assert_eq!(0x0000000000000000_8000000000000000, (-DoubleDouble::ZERO).to_bits());
-    assert_eq!(0xfc8ffffffffffffe_ffefffffffffffff, (-DoubleDouble::largest()).to_bits());
-    assert_eq!(0x0000000000000000_8000000000000001, (-DoubleDouble::SMALLEST).to_bits());
-    assert_eq!(
-        0x0000000000000000_8360000000000000,
-        (-DoubleDouble::smallest_normalized()).to_bits()
-    );
-    assert!(DoubleDouble::SMALLEST.is_smallest());
-    assert!(DoubleDouble::largest().is_largest());
-}
-
-#[test]
-fn ppc_double_double_is_denormal() {
-    assert!(DoubleDouble::SMALLEST.is_denormal());
-    assert!(!DoubleDouble::largest().is_denormal());
-    assert!(!DoubleDouble::smallest_normalized().is_denormal());
-    {
-        // (4 + 3) is not normalized
-        let data = 0x4008000000000000_4010000000000000;
-        assert!(DoubleDouble::from_bits(data).is_denormal());
-    }
-}
-
-#[test]
-fn ppc_double_double_exact_inverse() {
-    assert!(
-        "2.0"
-            .parse::<DoubleDouble>()
-            .unwrap()
-            .get_exact_inverse()
-            .unwrap()
-            .bitwise_eq("0.5".parse::<DoubleDouble>().unwrap())
-    );
-}
-
-#[test]
-fn ppc_double_double_scalbn() {
-    // 3.0 + 3.0 << 53
-    let input = 0x3cb8000000000000_4008000000000000;
-    let result = DoubleDouble::from_bits(input).scalbn(1);
-    // 6.0 + 6.0 << 53
-    assert_eq!(0x3cc8000000000000_4018000000000000, result.to_bits());
-}
-
-#[test]
-fn ppc_double_double_frexp() {
-    // 3.0 + 3.0 << 53
-    let input = 0x3cb8000000000000_4008000000000000;
-    let mut exp = 0;
-    // 0.75 + 0.75 << 53
-    let result = DoubleDouble::from_bits(input).frexp(&mut exp);
-    assert_eq!(2, exp);
-    assert_eq!(0x3c98000000000000_3fe8000000000000, result.to_bits());
-}
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 6c781c6f082..0bbb6c9c338 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -362,7 +362,7 @@ pub struct CodegenContext<B: WriteBackendMethods> {
 
 impl<B: WriteBackendMethods> CodegenContext<B> {
     pub fn create_diag_handler(&self) -> Handler {
-        Handler::with_emitter(true, None, Box::new(self.diag_emitter.clone()), None)
+        Handler::with_emitter(Box::new(self.diag_emitter.clone()))
     }
 
     pub fn config(&self, kind: ModuleKind) -> &ModuleConfig {
diff --git a/compiler/rustc_const_eval/Cargo.toml b/compiler/rustc_const_eval/Cargo.toml
index 74030a43c50..4e47fed8640 100644
--- a/compiler/rustc_const_eval/Cargo.toml
+++ b/compiler/rustc_const_eval/Cargo.toml
@@ -8,7 +8,7 @@ edition = "2021"
 [dependencies]
 tracing = "0.1"
 either = "1"
-rustc_apfloat = { path = "../rustc_apfloat" }
+rustc_apfloat = "0.2.0"
 rustc_ast = { path = "../rustc_ast" }
 rustc_attr = { path = "../rustc_attr" }
 rustc_data_structures = { path = "../rustc_data_structures" }
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index b21cb984de6..55d719d2703 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -58,7 +58,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
     ecx.push_stack_frame(
         cid.instance,
         body,
-        &ret.into(),
+        &ret.clone().into(),
         StackPopCleanup::Root { cleanup: false },
     )?;
 
@@ -356,7 +356,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
             // Since evaluation had no errors, validate the resulting constant.
             // This is a separate `try` block to provide more targeted error reporting.
             let validation: Result<_, InterpErrorInfo<'_>> = try {
-                let mut ref_tracking = RefTracking::new(mplace);
+                let mut ref_tracking = RefTracking::new(mplace.clone());
                 let mut inner = false;
                 while let Some((mplace, path)) = ref_tracking.todo.pop() {
                     let mode = match tcx.static_mutability(cid.instance.def_id()) {
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 267795a6cb4..6630eeca27e 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -216,7 +216,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
 
             let mut msg_place = self.deref_operand(&args[0])?;
             while msg_place.layout.ty.is_ref() {
-                msg_place = self.deref_operand(&msg_place.into())?;
+                msg_place = self.deref_operand(&msg_place)?;
             }
 
             let msg = Symbol::intern(self.read_str(&msg_place)?);
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index b519bcdf4a3..744dd114ca7 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -5,7 +5,7 @@ use crate::const_eval::CanAccessStatics;
 use crate::interpret::MPlaceTy;
 use crate::interpret::{
     intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta,
-    MemoryKind, PlaceTy, Projectable, Scalar,
+    MemoryKind, Place, Projectable, Scalar,
 };
 use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
 use rustc_span::source_map::DUMMY_SP;
@@ -21,7 +21,7 @@ fn branches<'tcx>(
 ) -> ValTreeCreationResult<'tcx> {
     let place = match variant {
         Some(variant) => ecx.project_downcast(place, variant).unwrap(),
-        None => *place,
+        None => place.clone(),
     };
     let variant = variant.map(|variant| Some(ty::ValTree::Leaf(ScalarInt::from(variant.as_u32()))));
     debug!(?place, ?variant);
@@ -86,7 +86,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
             Ok(ty::ValTree::zst())
         }
         ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
-            let Ok(val) = ecx.read_immediate(&place.into()) else {
+            let Ok(val) = ecx.read_immediate(place) else {
                 return Err(ValTreeCreationError::Other);
             };
             let val = val.to_scalar();
@@ -102,7 +102,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
         ty::FnPtr(_) | ty::RawPtr(_) => Err(ValTreeCreationError::NonSupportedType),
 
         ty::Ref(_, _, _)  => {
-            let Ok(derefd_place)= ecx.deref_operand(&place.into()) else {
+            let Ok(derefd_place)= ecx.deref_operand(place) else {
                 return Err(ValTreeCreationError::Other);
             };
             debug!(?derefd_place);
@@ -130,7 +130,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
                 bug!("uninhabited types should have errored and never gotten converted to valtree")
             }
 
-            let Ok(variant) = ecx.read_discriminant(&place.into()) else {
+            let Ok(variant) = ecx.read_discriminant(place) else {
                 return Err(ValTreeCreationError::Other);
             };
             branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes)
@@ -280,7 +280,7 @@ pub fn valtree_to_const_value<'tcx>(
             ),
         },
         ty::Ref(_, _, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Adt(..) => {
-            let mut place = match ty.kind() {
+            let place = match ty.kind() {
                 ty::Ref(_, inner_ty, _) => {
                     // Need to create a place for the pointee to fill for Refs
                     create_pointee_place(&mut ecx, *inner_ty, valtree)
@@ -289,8 +289,8 @@ pub fn valtree_to_const_value<'tcx>(
             };
             debug!(?place);
 
-            valtree_into_mplace(&mut ecx, &mut place, valtree);
-            dump_place(&ecx, place.into());
+            valtree_into_mplace(&mut ecx, &place, valtree);
+            dump_place(&ecx, &place);
             intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap();
 
             match ty.kind() {
@@ -329,7 +329,7 @@ pub fn valtree_to_const_value<'tcx>(
 #[instrument(skip(ecx), level = "debug")]
 fn valtree_into_mplace<'tcx>(
     ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>,
-    place: &mut MPlaceTy<'tcx>,
+    place: &MPlaceTy<'tcx>,
     valtree: ty::ValTree<'tcx>,
 ) {
     // This will match on valtree and write the value(s) corresponding to the ValTree
@@ -345,14 +345,14 @@ fn valtree_into_mplace<'tcx>(
         ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
             let scalar_int = valtree.unwrap_leaf();
             debug!("writing trivial valtree {:?} to place {:?}", scalar_int, place);
-            ecx.write_immediate(Immediate::Scalar(scalar_int.into()), &place.into()).unwrap();
+            ecx.write_immediate(Immediate::Scalar(scalar_int.into()), place).unwrap();
         }
         ty::Ref(_, inner_ty, _) => {
-            let mut pointee_place = create_pointee_place(ecx, *inner_ty, valtree);
+            let pointee_place = create_pointee_place(ecx, *inner_ty, valtree);
             debug!(?pointee_place);
 
-            valtree_into_mplace(ecx, &mut pointee_place, valtree);
-            dump_place(ecx, pointee_place.into());
+            valtree_into_mplace(ecx, &pointee_place, valtree);
+            dump_place(ecx, &pointee_place);
             intern_const_alloc_recursive(ecx, InternKind::Constant, &pointee_place).unwrap();
 
             let imm = match inner_ty.kind() {
@@ -369,7 +369,7 @@ fn valtree_into_mplace<'tcx>(
             };
             debug!(?imm);
 
-            ecx.write_immediate(imm, &place.into()).unwrap();
+            ecx.write_immediate(imm, place).unwrap();
         }
         ty::Adt(_, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Str | ty::Slice(_) => {
             let branches = valtree.unwrap_branch();
@@ -389,7 +389,7 @@ fn valtree_into_mplace<'tcx>(
                         Some(variant_idx),
                     )
                 }
-                _ => (*place, branches, None),
+                _ => (place.clone(), branches, None),
             };
             debug!(?place_adjusted, ?branches);
 
@@ -398,7 +398,7 @@ fn valtree_into_mplace<'tcx>(
             for (i, inner_valtree) in branches.iter().enumerate() {
                 debug!(?i, ?inner_valtree);
 
-                let mut place_inner = match ty.kind() {
+                let place_inner = match ty.kind() {
                     ty::Str | ty::Slice(_) => ecx.project_index(place, i as u64).unwrap(),
                     _ if !ty.is_sized(*ecx.tcx, ty::ParamEnv::empty())
                         && i == branches.len() - 1 =>
@@ -443,25 +443,25 @@ fn valtree_into_mplace<'tcx>(
                 };
 
                 debug!(?place_inner);
-                valtree_into_mplace(ecx, &mut place_inner, *inner_valtree);
-                dump_place(&ecx, place_inner.into());
+                valtree_into_mplace(ecx, &place_inner, *inner_valtree);
+                dump_place(&ecx, &place_inner);
             }
 
             debug!("dump of place_adjusted:");
-            dump_place(ecx, place_adjusted.into());
+            dump_place(ecx, &place_adjusted);
 
             if let Some(variant_idx) = variant_idx {
                 // don't forget filling the place with the discriminant of the enum
-                ecx.write_discriminant(variant_idx, &place.into()).unwrap();
+                ecx.write_discriminant(variant_idx, place).unwrap();
             }
 
             debug!("dump of place after writing discriminant:");
-            dump_place(ecx, place.into());
+            dump_place(ecx, place);
         }
         _ => bug!("shouldn't have created a ValTree for {:?}", ty),
     }
 }
 
-fn dump_place<'tcx>(ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: PlaceTy<'tcx>) {
-    trace!("{:?}", ecx.dump_place(*place));
+fn dump_place<'tcx>(ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: &MPlaceTy<'tcx>) {
+    trace!("{:?}", ecx.dump_place(Place::Ptr(**place)));
 }
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 977e49b6343..98e853dc4d9 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -56,7 +56,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
 
             CastKind::FnPtrToPtr | CastKind::PtrToPtr => {
-                let src = self.read_immediate(&src)?;
+                let src = self.read_immediate(src)?;
                 let res = self.ptr_to_ptr(&src, cast_ty)?;
                 self.write_immediate(res, dest)?;
             }
diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs
index aff86d5f486..6c35fb01a93 100644
--- a/compiler/rustc_const_eval/src/interpret/discriminant.rs
+++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs
@@ -5,7 +5,7 @@ use rustc_middle::{mir, ty};
 use rustc_target::abi::{self, TagEncoding};
 use rustc_target::abi::{VariantIdx, Variants};
 
-use super::{ImmTy, InterpCx, InterpResult, Machine, OpTy, PlaceTy, Scalar};
+use super::{ImmTy, InterpCx, InterpResult, Machine, Readable, Scalar, Writeable};
 
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Writes the discriminant of the given variant.
@@ -13,7 +13,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn write_discriminant(
         &mut self,
         variant_index: VariantIdx,
-        dest: &PlaceTy<'tcx, M::Provenance>,
+        dest: &impl Writeable<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         // Layout computation excludes uninhabited variants from consideration
         // therefore there's no way to represent those variants in the given layout.
@@ -21,11 +21,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // discriminant, so we cannot do anything here.
         // When evaluating we will always error before even getting here, but ConstProp 'executes'
         // dead code, so we cannot ICE here.
-        if dest.layout.for_variant(self, variant_index).abi.is_uninhabited() {
+        if dest.layout().for_variant(self, variant_index).abi.is_uninhabited() {
             throw_ub!(UninhabitedEnumVariantWritten(variant_index))
         }
 
-        match dest.layout.variants {
+        match dest.layout().variants {
             abi::Variants::Single { index } => {
                 assert_eq!(index, variant_index);
             }
@@ -38,8 +38,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // No need to validate that the discriminant here because the
                 // `TyAndLayout::for_variant()` call earlier already checks the variant is valid.
 
-                let discr_val =
-                    dest.layout.ty.discriminant_for_variant(*self.tcx, variant_index).unwrap().val;
+                let discr_val = dest
+                    .layout()
+                    .ty
+                    .discriminant_for_variant(*self.tcx, variant_index)
+                    .unwrap()
+                    .val;
 
                 // raw discriminants for enums are isize or bigger during
                 // their computation, but the in-memory tag is the smallest possible
@@ -92,11 +96,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     #[instrument(skip(self), level = "trace")]
     pub fn read_discriminant(
         &self,
-        op: &OpTy<'tcx, M::Provenance>,
+        op: &impl Readable<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, VariantIdx> {
-        trace!("read_discriminant_value {:#?}", op.layout);
+        let ty = op.layout().ty;
+        trace!("read_discriminant_value {:#?}", op.layout());
         // Get type and layout of the discriminant.
-        let discr_layout = self.layout_of(op.layout.ty.discriminant_ty(*self.tcx))?;
+        let discr_layout = self.layout_of(ty.discriminant_ty(*self.tcx))?;
         trace!("discriminant type: {:?}", discr_layout.ty);
 
         // We use "discriminant" to refer to the value associated with a particular enum variant.
@@ -104,20 +109,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // declared list of variants -- they can differ with explicitly assigned discriminants.
         // We use "tag" to refer to how the discriminant is encoded in memory, which can be either
         // straight-forward (`TagEncoding::Direct`) or with a niche (`TagEncoding::Niche`).
-        let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout.variants {
+        let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout().variants {
             Variants::Single { index } => {
                 // Do some extra checks on enums.
-                if op.layout.ty.is_enum() {
+                if ty.is_enum() {
                     // Hilariously, `Single` is used even for 0-variant enums.
                     // (See https://github.com/rust-lang/rust/issues/89765).
-                    if matches!(op.layout.ty.kind(), ty::Adt(def, ..) if def.variants().is_empty())
-                    {
+                    if matches!(ty.kind(), ty::Adt(def, ..) if def.variants().is_empty()) {
                         throw_ub!(UninhabitedEnumVariantRead(index))
                     }
                     // For consisteny with `write_discriminant`, and to make sure that
                     // `project_downcast` cannot fail due to strange layouts, we declare immediate UB
                     // for uninhabited variants.
-                    if op.layout.for_variant(self, index).abi.is_uninhabited() {
+                    if op.layout().for_variant(self, index).abi.is_uninhabited() {
                         throw_ub!(UninhabitedEnumVariantRead(index))
                     }
                 }
@@ -163,7 +167,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     self.cast_from_int_like(scalar, tag_val.layout, discr_layout.ty).unwrap();
                 let discr_bits = discr_val.assert_bits(discr_layout.size);
                 // Convert discriminant to variant index, and catch invalid discriminants.
-                let index = match *op.layout.ty.kind() {
+                let index = match *ty.kind() {
                     ty::Adt(adt, _) => {
                         adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits)
                     }
@@ -217,12 +221,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                                     .checked_add(variant_index_relative)
                                     .expect("overflow computing absolute variant idx"),
                             );
-                            let variants = op
-                                .layout
-                                .ty
-                                .ty_adt_def()
-                                .expect("tagged layout for non adt")
-                                .variants();
+                            let variants =
+                                ty.ty_adt_def().expect("tagged layout for non adt").variants();
                             assert!(variant_index < variants.next_index());
                             variant_index
                         } else {
@@ -237,7 +237,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
         };
         // For consisteny with `write_discriminant`, and to make sure that `project_downcast` cannot fail due to strange layouts, we declare immediate UB for uninhabited variants.
-        if op.layout.for_variant(self, index).abi.is_uninhabited() {
+        if op.layout().for_variant(self, index).abi.is_uninhabited() {
             throw_ub!(UninhabitedEnumVariantRead(index))
         }
         Ok(index)
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index 3a7fe8bd478..910c3ca5d0a 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -170,7 +170,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
         let tcx = self.ecx.tcx;
         let ty = mplace.layout.ty;
         if let ty::Ref(_, referenced_ty, ref_mutability) = *ty.kind() {
-            let value = self.ecx.read_immediate(&mplace.into())?;
+            let value = self.ecx.read_immediate(mplace)?;
             let mplace = self.ecx.ref_to_mplace(&value)?;
             assert_eq!(mplace.layout.ty, referenced_ty);
             // Handle trait object vtables.
@@ -358,7 +358,7 @@ pub fn intern_const_alloc_recursive<
         Some(ret.layout.ty),
     );
 
-    ref_tracking.track((*ret, base_intern_mode), || ());
+    ref_tracking.track((ret.clone(), base_intern_mode), || ());
 
     while let Some(((mplace, mode), _)) = ref_tracking.todo.pop() {
         let res = InternVisitor {
@@ -464,7 +464,7 @@ impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>>
         ) -> InterpResult<'tcx, ()>,
     ) -> InterpResult<'tcx, ConstAllocation<'tcx>> {
         let dest = self.allocate(layout, MemoryKind::Stack)?;
-        f(self, &dest.into())?;
+        f(self, &dest.clone().into())?;
         let mut alloc = self.memory.alloc_map.remove(&dest.ptr.provenance.unwrap()).unwrap().1;
         alloc.mutability = Mutability::Not;
         Ok(self.tcx.mk_const_alloc(alloc))
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 3f697168280..4020d96b80e 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -226,7 +226,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
             sym::discriminant_value => {
                 let place = self.deref_operand(&args[0])?;
-                let variant = self.read_discriminant(&place.into())?;
+                let variant = self.read_discriminant(&place)?;
                 let discr = self.discriminant_for_variant(place.layout, variant)?;
                 self.write_scalar(discr, dest)?;
             }
@@ -432,7 +432,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     } else {
                         self.project_index(&input, i)?.into()
                     };
-                    self.copy_op(&value, &place.into(), /*allow_transmute*/ false)?;
+                    self.copy_op(&value, &place, /*allow_transmute*/ false)?;
                 }
             }
             sym::simd_extract => {
@@ -445,7 +445,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     input_len
                 );
                 self.copy_op(
-                    &self.project_index(&input, index)?.into(),
+                    &self.project_index(&input, index)?,
                     dest,
                     /*allow_transmute*/ false,
                 )?;
@@ -610,7 +610,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
         nonoverlapping: bool,
     ) -> InterpResult<'tcx> {
-        let count = self.read_target_usize(&count)?;
+        let count = self.read_target_usize(count)?;
         let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?;
         let (size, align) = (layout.size, layout.align.abi);
         // `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max),
@@ -622,8 +622,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             )
         })?;
 
-        let src = self.read_pointer(&src)?;
-        let dst = self.read_pointer(&dst)?;
+        let src = self.read_pointer(src)?;
+        let dst = self.read_pointer(dst)?;
 
         self.mem_copy(src, align, dst, align, size, nonoverlapping)
     }
@@ -636,9 +636,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     ) -> InterpResult<'tcx> {
         let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap().ty)?;
 
-        let dst = self.read_pointer(&dst)?;
-        let byte = self.read_scalar(&byte)?.to_u8()?;
-        let count = self.read_target_usize(&count)?;
+        let dst = self.read_pointer(dst)?;
+        let byte = self.read_scalar(byte)?.to_u8()?;
+        let count = self.read_target_usize(count)?;
 
         // `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max),
         // but no actual allocation can be big enough for the difference to be noticeable.
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
index 44a12751743..948bec7464a 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
@@ -101,11 +101,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let location = self.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();
 
         // Initialize fields.
-        self.write_immediate(file.to_ref(self), &self.project_field(&location, 0).unwrap().into())
+        self.write_immediate(file.to_ref(self), &self.project_field(&location, 0).unwrap())
             .expect("writing to memory we just allocated cannot fail");
-        self.write_scalar(line, &self.project_field(&location, 1).unwrap().into())
+        self.write_scalar(line, &self.project_field(&location, 1).unwrap())
             .expect("writing to memory we just allocated cannot fail");
-        self.write_scalar(col, &self.project_field(&location, 2).unwrap().into())
+        self.write_scalar(col, &self.project_field(&location, 2).unwrap())
             .expect("writing to memory we just allocated cannot fail");
 
         location
diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs
index 7974920bc14..b0b553c45d4 100644
--- a/compiler/rustc_const_eval/src/interpret/mod.rs
+++ b/compiler/rustc_const_eval/src/interpret/mod.rs
@@ -24,8 +24,8 @@ pub use self::eval_context::{Frame, FrameInfo, InterpCx, LocalState, LocalValue,
 pub use self::intern::{intern_const_alloc_recursive, InternKind};
 pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump};
 pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
-pub use self::operand::{ImmTy, Immediate, OpTy, Operand};
-pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy};
+pub use self::operand::{ImmTy, Immediate, OpTy, Operand, Readable};
+pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy, Writeable};
 pub use self::projection::Projectable;
 pub use self::terminator::FnArg;
 pub use self::validity::{CtfeValidationMode, RefTracking};
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index be39e63ab4f..d1427b09632 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -180,20 +180,6 @@ impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
     }
 }
 
-impl<'tcx, Prov: Provenance> From<&'_ MPlaceTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
-    #[inline(always)]
-    fn from(mplace: &MPlaceTy<'tcx, Prov>) -> Self {
-        OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout, align: Some(mplace.align) }
-    }
-}
-
-impl<'tcx, Prov: Provenance> From<&'_ mut MPlaceTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
-    #[inline(always)]
-    fn from(mplace: &mut MPlaceTy<'tcx, Prov>) -> Self {
-        OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout, align: Some(mplace.align) }
-    }
-}
-
 impl<'tcx, Prov: Provenance> From<ImmTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
     #[inline(always)]
     fn from(val: ImmTy<'tcx, Prov>) -> Self {
@@ -201,20 +187,6 @@ impl<'tcx, Prov: Provenance> From<ImmTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
     }
 }
 
-impl<'tcx, Prov: Provenance> From<&'_ ImmTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
-    #[inline(always)]
-    fn from(val: &ImmTy<'tcx, Prov>) -> Self {
-        OpTy { op: Operand::Immediate(val.imm), layout: val.layout, align: None }
-    }
-}
-
-impl<'tcx, Prov: Provenance> From<&'_ mut ImmTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
-    #[inline(always)]
-    fn from(val: &mut ImmTy<'tcx, Prov>) -> Self {
-        OpTy { op: Operand::Immediate(val.imm), layout: val.layout, align: None }
-    }
-}
-
 impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
     #[inline]
     pub fn from_scalar(val: Scalar<Prov>, layout: TyAndLayout<'tcx>) -> Self {
@@ -312,13 +284,13 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
     }
 }
 
-impl<'mir, 'tcx: 'mir, Prov: Provenance> Projectable<'mir, 'tcx, Prov> for ImmTy<'tcx, Prov> {
+impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for ImmTy<'tcx, Prov> {
     #[inline(always)]
     fn layout(&self) -> TyAndLayout<'tcx> {
         self.layout
     }
 
-    fn meta<M: Machine<'mir, 'tcx, Provenance = Prov>>(
+    fn meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
         &self,
         _ecx: &InterpCx<'mir, 'tcx, M>,
     ) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>> {
@@ -337,11 +309,11 @@ impl<'mir, 'tcx: 'mir, Prov: Provenance> Projectable<'mir, 'tcx, Prov> for ImmTy
         Ok(self.offset_(offset, layout, cx))
     }
 
-    fn to_op<M: Machine<'mir, 'tcx, Provenance = Prov>>(
+    fn to_op<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
         &self,
         _ecx: &InterpCx<'mir, 'tcx, M>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
-        Ok(self.into())
+        Ok(self.clone().into())
     }
 }
 
@@ -362,15 +334,13 @@ impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> {
     }
 }
 
-impl<'mir, 'tcx: 'mir, Prov: Provenance + 'static> Projectable<'mir, 'tcx, Prov>
-    for OpTy<'tcx, Prov>
-{
+impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for OpTy<'tcx, Prov> {
     #[inline(always)]
     fn layout(&self) -> TyAndLayout<'tcx> {
         self.layout
     }
 
-    fn meta<M: Machine<'mir, 'tcx, Provenance = Prov>>(
+    fn meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
         &self,
         _ecx: &InterpCx<'mir, 'tcx, M>,
     ) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>> {
@@ -394,7 +364,7 @@ impl<'mir, 'tcx: 'mir, Prov: Provenance + 'static> Projectable<'mir, 'tcx, Prov>
         }
     }
 
-    fn to_op<M: Machine<'mir, 'tcx, Provenance = Prov>>(
+    fn to_op<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
         &self,
         _ecx: &InterpCx<'mir, 'tcx, M>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
@@ -402,6 +372,31 @@ impl<'mir, 'tcx: 'mir, Prov: Provenance + 'static> Projectable<'mir, 'tcx, Prov>
     }
 }
 
+pub trait Readable<'tcx, Prov: Provenance>: Projectable<'tcx, Prov> {
+    fn as_mplace_or_imm(&self) -> Either<MPlaceTy<'tcx, Prov>, ImmTy<'tcx, Prov>>;
+}
+
+impl<'tcx, Prov: Provenance + 'static> Readable<'tcx, Prov> for OpTy<'tcx, Prov> {
+    #[inline(always)]
+    fn as_mplace_or_imm(&self) -> Either<MPlaceTy<'tcx, Prov>, ImmTy<'tcx, Prov>> {
+        self.as_mplace_or_imm()
+    }
+}
+
+impl<'tcx, Prov: Provenance + 'static> Readable<'tcx, Prov> for MPlaceTy<'tcx, Prov> {
+    #[inline(always)]
+    fn as_mplace_or_imm(&self) -> Either<MPlaceTy<'tcx, Prov>, ImmTy<'tcx, Prov>> {
+        Left(self.clone())
+    }
+}
+
+impl<'tcx, Prov: Provenance> Readable<'tcx, Prov> for ImmTy<'tcx, Prov> {
+    #[inline(always)]
+    fn as_mplace_or_imm(&self) -> Either<MPlaceTy<'tcx, Prov>, ImmTy<'tcx, Prov>> {
+        Right(self.clone())
+    }
+}
+
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Try reading an immediate in memory; this is interesting particularly for `ScalarPair`.
     /// Returns `None` if the layout does not permit loading this as a value.
@@ -474,14 +469,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// ConstProp needs it, though.
     pub fn read_immediate_raw(
         &self,
-        src: &OpTy<'tcx, M::Provenance>,
+        src: &impl Readable<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, Either<MPlaceTy<'tcx, M::Provenance>, ImmTy<'tcx, M::Provenance>>> {
         Ok(match src.as_mplace_or_imm() {
             Left(ref mplace) => {
                 if let Some(val) = self.read_immediate_from_mplace_raw(mplace)? {
                     Right(val)
                 } else {
-                    Left(*mplace)
+                    Left(mplace.clone())
                 }
             }
             Right(val) => Right(val),
@@ -494,14 +489,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     #[inline(always)]
     pub fn read_immediate(
         &self,
-        op: &OpTy<'tcx, M::Provenance>,
+        op: &impl Readable<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
         if !matches!(
-            op.layout.abi,
+            op.layout().abi,
             Abi::Scalar(abi::Scalar::Initialized { .. })
                 | Abi::ScalarPair(abi::Scalar::Initialized { .. }, abi::Scalar::Initialized { .. })
         ) {
-            span_bug!(self.cur_span(), "primitive read not possible for type: {:?}", op.layout.ty);
+            span_bug!(
+                self.cur_span(),
+                "primitive read not possible for type: {:?}",
+                op.layout().ty
+            );
         }
         let imm = self.read_immediate_raw(op)?.right().unwrap();
         if matches!(*imm, Immediate::Uninit) {
@@ -513,7 +512,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Read a scalar from a place
     pub fn read_scalar(
         &self,
-        op: &OpTy<'tcx, M::Provenance>,
+        op: &impl Readable<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, Scalar<M::Provenance>> {
         Ok(self.read_immediate(op)?.to_scalar())
     }
@@ -524,16 +523,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Read a pointer from a place.
     pub fn read_pointer(
         &self,
-        op: &OpTy<'tcx, M::Provenance>,
+        op: &impl Readable<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
         self.read_scalar(op)?.to_pointer(self)
     }
     /// Read a pointer-sized unsigned integer from a place.
-    pub fn read_target_usize(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx, u64> {
+    pub fn read_target_usize(
+        &self,
+        op: &impl Readable<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, u64> {
         self.read_scalar(op)?.to_target_usize(self)
     }
     /// Read a pointer-sized signed integer from a place.
-    pub fn read_target_isize(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx, i64> {
+    pub fn read_target_isize(
+        &self,
+        op: &impl Readable<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, i64> {
         self.read_scalar(op)?.to_target_isize(self)
     }
 
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index db1239c7136..96a960118ce 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -18,7 +18,7 @@ use rustc_target::abi::{self, Abi, Align, FieldIdx, HasDataLayout, Size, FIRST_V
 use super::{
     alloc_range, mir_assign_valid_types, AllocId, AllocRef, AllocRefMut, CheckInAllocMsg,
     ConstAlloc, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemoryKind, OpTy, Operand,
-    Pointer, Projectable, Provenance, Scalar,
+    Pointer, Projectable, Provenance, Readable, Scalar,
 };
 
 #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
@@ -81,7 +81,7 @@ pub struct MemPlace<Prov: Provenance = AllocId> {
 }
 
 /// A MemPlace with its layout. Constructing it is only possible in this module.
-#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
+#[derive(Clone, Hash, Eq, PartialEq, Debug)]
 pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> {
     mplace: MemPlace<Prov>,
     pub layout: TyAndLayout<'tcx>,
@@ -92,6 +92,14 @@ pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> {
     pub align: Align,
 }
 
+impl<'tcx, Prov: Provenance> std::ops::Deref for MPlaceTy<'tcx, Prov> {
+    type Target = MemPlace<Prov>;
+    #[inline(always)]
+    fn deref(&self) -> &MemPlace<Prov> {
+        &self.mplace
+    }
+}
+
 #[derive(Copy, Clone, Debug)]
 pub enum Place<Prov: Provenance = AllocId> {
     /// A place referring to a value allocated in the `Memory` system.
@@ -125,14 +133,6 @@ impl<'tcx, Prov: Provenance> std::ops::Deref for PlaceTy<'tcx, Prov> {
     }
 }
 
-impl<'tcx, Prov: Provenance> std::ops::Deref for MPlaceTy<'tcx, Prov> {
-    type Target = MemPlace<Prov>;
-    #[inline(always)]
-    fn deref(&self) -> &MemPlace<Prov> {
-        &self.mplace
-    }
-}
-
 impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> {
     #[inline(always)]
     fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self {
@@ -140,20 +140,6 @@ impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov>
     }
 }
 
-impl<'tcx, Prov: Provenance> From<&'_ MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> {
-    #[inline(always)]
-    fn from(mplace: &MPlaceTy<'tcx, Prov>) -> Self {
-        PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout, align: mplace.align }
-    }
-}
-
-impl<'tcx, Prov: Provenance> From<&'_ mut MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> {
-    #[inline(always)]
-    fn from(mplace: &mut MPlaceTy<'tcx, Prov>) -> Self {
-        PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout, align: mplace.align }
-    }
-}
-
 impl<Prov: Provenance> MemPlace<Prov> {
     #[inline(always)]
     pub fn from_ptr(ptr: Pointer<Option<Prov>>) -> Self {
@@ -229,15 +215,13 @@ impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> {
     }
 }
 
-impl<'mir, 'tcx: 'mir, Prov: Provenance + 'static> Projectable<'mir, 'tcx, Prov>
-    for MPlaceTy<'tcx, Prov>
-{
+impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for MPlaceTy<'tcx, Prov> {
     #[inline(always)]
     fn layout(&self) -> TyAndLayout<'tcx> {
         self.layout
     }
 
-    fn meta<M: Machine<'mir, 'tcx, Provenance = Prov>>(
+    fn meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
         &self,
         _ecx: &InterpCx<'mir, 'tcx, M>,
     ) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>> {
@@ -258,11 +242,59 @@ impl<'mir, 'tcx: 'mir, Prov: Provenance + 'static> Projectable<'mir, 'tcx, Prov>
         })
     }
 
-    fn to_op<M: Machine<'mir, 'tcx, Provenance = Prov>>(
+    fn to_op<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
         &self,
         _ecx: &InterpCx<'mir, 'tcx, M>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
-        Ok(self.into())
+        Ok(self.clone().into())
+    }
+}
+
+impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for PlaceTy<'tcx, Prov> {
+    #[inline(always)]
+    fn layout(&self) -> TyAndLayout<'tcx> {
+        self.layout
+    }
+
+    fn meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
+        &self,
+        ecx: &InterpCx<'mir, 'tcx, M>,
+    ) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>> {
+        ecx.place_meta(self)
+    }
+
+    fn offset_with_meta(
+        &self,
+        offset: Size,
+        meta: MemPlaceMeta<Prov>,
+        layout: TyAndLayout<'tcx>,
+        cx: &impl HasDataLayout,
+    ) -> InterpResult<'tcx, Self> {
+        Ok(match self.as_mplace_or_local() {
+            Left(mplace) => mplace.offset_with_meta(offset, meta, layout, cx)?.into(),
+            Right((frame, local, old_offset)) => {
+                assert_matches!(meta, MemPlaceMeta::None); // we couldn't store it anyway...
+                let new_offset = cx
+                    .data_layout()
+                    .offset(old_offset.unwrap_or(Size::ZERO).bytes(), offset.bytes())?;
+                PlaceTy {
+                    place: Place::Local {
+                        frame,
+                        local,
+                        offset: Some(Size::from_bytes(new_offset)),
+                    },
+                    align: self.align.restrict_for_offset(offset),
+                    layout,
+                }
+            }
+        })
+    }
+
+    fn to_op<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
+        &self,
+        ecx: &InterpCx<'mir, 'tcx, M>,
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
+        ecx.place_to_op(self)
     }
 }
 
@@ -314,53 +346,51 @@ impl<'tcx, Prov: Provenance + 'static> PlaceTy<'tcx, Prov> {
     }
 }
 
-impl<'mir, 'tcx: 'mir, Prov: Provenance + 'static> Projectable<'mir, 'tcx, Prov>
-    for PlaceTy<'tcx, Prov>
-{
+pub trait Writeable<'tcx, Prov: Provenance>: Projectable<'tcx, Prov> {
+    fn as_mplace_or_local(
+        &self,
+    ) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local, Option<Size>, Align, TyAndLayout<'tcx>)>;
+
+    fn force_mplace<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
+        &self,
+        ecx: &mut InterpCx<'mir, 'tcx, M>,
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, Prov>>;
+}
+
+impl<'tcx, Prov: Provenance + 'static> Writeable<'tcx, Prov> for PlaceTy<'tcx, Prov> {
     #[inline(always)]
-    fn layout(&self) -> TyAndLayout<'tcx> {
-        self.layout
+    fn as_mplace_or_local(
+        &self,
+    ) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local, Option<Size>, Align, TyAndLayout<'tcx>)>
+    {
+        self.as_mplace_or_local()
+            .map_right(|(frame, local, offset)| (frame, local, offset, self.align, self.layout))
     }
 
-    fn meta<M: Machine<'mir, 'tcx, Provenance = Prov>>(
+    #[inline(always)]
+    fn force_mplace<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
         &self,
-        ecx: &InterpCx<'mir, 'tcx, M>,
-    ) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>> {
-        ecx.place_meta(self)
+        ecx: &mut InterpCx<'mir, 'tcx, M>,
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, Prov>> {
+        ecx.force_allocation(self)
     }
+}
 
-    fn offset_with_meta(
+impl<'tcx, Prov: Provenance + 'static> Writeable<'tcx, Prov> for MPlaceTy<'tcx, Prov> {
+    #[inline(always)]
+    fn as_mplace_or_local(
         &self,
-        offset: Size,
-        meta: MemPlaceMeta<Prov>,
-        layout: TyAndLayout<'tcx>,
-        cx: &impl HasDataLayout,
-    ) -> InterpResult<'tcx, Self> {
-        Ok(match self.as_mplace_or_local() {
-            Left(mplace) => mplace.offset_with_meta(offset, meta, layout, cx)?.into(),
-            Right((frame, local, old_offset)) => {
-                assert_matches!(meta, MemPlaceMeta::None); // we couldn't store it anyway...
-                let new_offset = cx
-                    .data_layout()
-                    .offset(old_offset.unwrap_or(Size::ZERO).bytes(), offset.bytes())?;
-                PlaceTy {
-                    place: Place::Local {
-                        frame,
-                        local,
-                        offset: Some(Size::from_bytes(new_offset)),
-                    },
-                    align: self.align.restrict_for_offset(offset),
-                    layout,
-                }
-            }
-        })
+    ) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local, Option<Size>, Align, TyAndLayout<'tcx>)>
+    {
+        Left(self.clone())
     }
 
-    fn to_op<M: Machine<'mir, 'tcx, Provenance = Prov>>(
+    #[inline(always)]
+    fn force_mplace<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
         &self,
-        ecx: &InterpCx<'mir, 'tcx, M>,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
-        ecx.place_to_op(self)
+        _ecx: &mut InterpCx<'mir, 'tcx, M>,
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, Prov>> {
+        Ok(self.clone())
     }
 }
 
@@ -412,7 +442,7 @@ where
     #[instrument(skip(self), level = "debug")]
     pub fn deref_operand(
         &self,
-        src: &OpTy<'tcx, M::Provenance>,
+        src: &impl Readable<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
         let val = self.read_immediate(src)?;
         trace!("deref to {} on {:?}", val.layout.ty, *val);
@@ -422,7 +452,7 @@ where
         }
 
         let mplace = self.ref_to_mplace(&val)?;
-        self.check_mplace(mplace)?;
+        self.check_mplace(&mplace)?;
         Ok(mplace)
     }
 
@@ -453,7 +483,7 @@ where
     }
 
     /// Check if this mplace is dereferenceable and sufficiently aligned.
-    pub fn check_mplace(&self, mplace: MPlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
+    pub fn check_mplace(&self, mplace: &MPlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
         let (size, _align) = self
             .size_and_align_of_mplace(&mplace)?
             .unwrap_or((mplace.layout.size, mplace.layout.align.abi));
@@ -537,13 +567,13 @@ where
     pub fn write_immediate(
         &mut self,
         src: Immediate<M::Provenance>,
-        dest: &PlaceTy<'tcx, M::Provenance>,
+        dest: &impl Writeable<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         self.write_immediate_no_validate(src, dest)?;
 
-        if M::enforce_validity(self, dest.layout) {
+        if M::enforce_validity(self, dest.layout()) {
             // Data got changed, better make sure it matches the type!
-            self.validate_operand(&self.place_to_op(dest)?)?;
+            self.validate_operand(&dest.to_op(self)?)?;
         }
 
         Ok(())
@@ -554,7 +584,7 @@ where
     pub fn write_scalar(
         &mut self,
         val: impl Into<Scalar<M::Provenance>>,
-        dest: &PlaceTy<'tcx, M::Provenance>,
+        dest: &impl Writeable<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         self.write_immediate(Immediate::Scalar(val.into()), dest)
     }
@@ -564,7 +594,7 @@ where
     pub fn write_pointer(
         &mut self,
         ptr: impl Into<Pointer<Option<M::Provenance>>>,
-        dest: &PlaceTy<'tcx, M::Provenance>,
+        dest: &impl Writeable<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         self.write_scalar(Scalar::from_maybe_pointer(ptr.into(), self), dest)
     }
@@ -575,20 +605,19 @@ where
     fn write_immediate_no_validate(
         &mut self,
         src: Immediate<M::Provenance>,
-        dest: &PlaceTy<'tcx, M::Provenance>,
+        dest: &impl Writeable<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
-        assert!(dest.layout.is_sized(), "Cannot write unsized immediate data");
-        trace!("write_immediate: {:?} <- {:?}: {}", *dest, src, dest.layout.ty);
+        assert!(dest.layout().is_sized(), "Cannot write unsized immediate data");
 
         // See if we can avoid an allocation. This is the counterpart to `read_immediate_raw`,
         // but not factored as a separate function.
-        let mplace = match dest.place {
-            Place::Local { frame, local, offset } => {
+        let mplace = match dest.as_mplace_or_local() {
+            Right((frame, local, offset, align, layout)) => {
                 if offset.is_some() {
                     // This has been projected to a part of this local. We could have complicated
                     // logic to still keep this local as an `Operand`... but it's much easier to
                     // just fall back to the indirect path.
-                    *self.force_allocation(dest)?
+                    dest.force_mplace(self)?
                 } else {
                     match M::access_local_mut(self, frame, local)? {
                         Operand::Immediate(local_val) => {
@@ -623,16 +652,16 @@ where
                         }
                         Operand::Indirect(mplace) => {
                             // The local is in memory, go on below.
-                            *mplace
+                            MPlaceTy { mplace: *mplace, align, layout }
                         }
                     }
                 }
             }
-            Place::Ptr(mplace) => mplace, // already referring to memory
+            Left(mplace) => mplace, // already referring to memory
         };
 
         // This is already in memory, write there.
-        self.write_immediate_to_mplace_no_validate(src, dest.layout, dest.align, mplace)
+        self.write_immediate_to_mplace_no_validate(src, mplace.layout, mplace.align, mplace.mplace)
     }
 
     /// Write an immediate to memory.
@@ -696,16 +725,19 @@ where
         }
     }
 
-    pub fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
+    pub fn write_uninit(
+        &mut self,
+        dest: &impl Writeable<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx> {
         let mplace = match dest.as_mplace_or_local() {
             Left(mplace) => mplace,
-            Right((frame, local, offset)) => {
+            Right((frame, local, offset, align, layout)) => {
                 if offset.is_some() {
                     // This has been projected to a part of this local. We could have complicated
                     // logic to still keep this local as an `Operand`... but it's much easier to
                     // just fall back to the indirect path.
                     // FIXME: share the logic with `write_immediate_no_validate`.
-                    self.force_allocation(dest)?
+                    dest.force_mplace(self)?
                 } else {
                     match M::access_local_mut(self, frame, local)? {
                         Operand::Immediate(local) => {
@@ -714,7 +746,7 @@ where
                         }
                         Operand::Indirect(mplace) => {
                             // The local is in memory, go on below.
-                            MPlaceTy { mplace: *mplace, layout: dest.layout, align: dest.align }
+                            MPlaceTy { mplace: *mplace, layout, align }
                         }
                     }
                 }
@@ -734,15 +766,15 @@ where
     #[instrument(skip(self), level = "debug")]
     pub fn copy_op(
         &mut self,
-        src: &OpTy<'tcx, M::Provenance>,
-        dest: &PlaceTy<'tcx, M::Provenance>,
+        src: &impl Readable<'tcx, M::Provenance>,
+        dest: &impl Writeable<'tcx, M::Provenance>,
         allow_transmute: bool,
     ) -> InterpResult<'tcx> {
         self.copy_op_no_validate(src, dest, allow_transmute)?;
 
-        if M::enforce_validity(self, dest.layout) {
+        if M::enforce_validity(self, dest.layout()) {
             // Data got changed, better make sure it matches the type!
-            self.validate_operand(&self.place_to_op(dest)?)?;
+            self.validate_operand(&dest.to_op(self)?)?;
         }
 
         Ok(())
@@ -755,20 +787,20 @@ where
     #[instrument(skip(self), level = "debug")]
     fn copy_op_no_validate(
         &mut self,
-        src: &OpTy<'tcx, M::Provenance>,
-        dest: &PlaceTy<'tcx, M::Provenance>,
+        src: &impl Readable<'tcx, M::Provenance>,
+        dest: &impl Writeable<'tcx, M::Provenance>,
         allow_transmute: bool,
     ) -> InterpResult<'tcx> {
         // We do NOT compare the types for equality, because well-typed code can
         // actually "transmute" `&mut T` to `&T` in an assignment without a cast.
         let layout_compat =
-            mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout);
+            mir_assign_valid_types(*self.tcx, self.param_env, src.layout(), dest.layout());
         if !allow_transmute && !layout_compat {
             span_bug!(
                 self.cur_span(),
                 "type mismatch when copying!\nsrc: {:?},\ndest: {:?}",
-                src.layout.ty,
-                dest.layout.ty,
+                src.layout().ty,
+                dest.layout().ty,
             );
         }
 
@@ -781,13 +813,13 @@ where
                 // actually sized, due to a trivially false where-clause
                 // predicate like `where Self: Sized` with `Self = dyn Trait`.
                 // See #102553 for an example of such a predicate.
-                if src.layout.is_unsized() {
-                    throw_inval!(SizeOfUnsizedType(src.layout.ty));
+                if src.layout().is_unsized() {
+                    throw_inval!(SizeOfUnsizedType(src.layout().ty));
                 }
-                if dest.layout.is_unsized() {
-                    throw_inval!(SizeOfUnsizedType(dest.layout.ty));
+                if dest.layout().is_unsized() {
+                    throw_inval!(SizeOfUnsizedType(dest.layout().ty));
                 }
-                assert_eq!(src.layout.size, dest.layout.size);
+                assert_eq!(src.layout().size, dest.layout().size);
                 // Yay, we got a value that we can write directly.
                 return if layout_compat {
                     self.write_immediate_no_validate(*src_val, dest)
@@ -796,10 +828,10 @@ where
                     // loaded using the offsets defined by `src.layout`. When we put this back into
                     // the destination, we have to use the same offsets! So (a) we make sure we
                     // write back to memory, and (b) we use `dest` *with the source layout*.
-                    let dest_mem = self.force_allocation(dest)?;
+                    let dest_mem = dest.force_mplace(self)?;
                     self.write_immediate_to_mplace_no_validate(
                         *src_val,
-                        src.layout,
+                        src.layout(),
                         dest_mem.align,
                         *dest_mem,
                     )
@@ -808,9 +840,9 @@ where
             Left(mplace) => mplace,
         };
         // Slow path, this does not fit into an immediate. Just memcpy.
-        trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout.ty);
+        trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout().ty);
 
-        let dest = self.force_allocation(&dest)?;
+        let dest = dest.force_mplace(self)?;
         let Some((dest_size, _)) = self.size_and_align_of_mplace(&dest)? else {
             span_bug!(self.cur_span(), "copy_op needs (dynamically) sized values")
         };
@@ -928,7 +960,7 @@ where
         operands: &IndexSlice<FieldIdx, mir::Operand<'tcx>>,
         dest: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
-        self.write_uninit(&dest)?;
+        self.write_uninit(dest)?;
         let (variant_index, variant_dest, active_field_index) = match *kind {
             mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => {
                 let variant_dest = self.project_downcast(dest, variant_index)?;
@@ -945,7 +977,7 @@ where
             let op = self.eval_operand(operand, Some(field_dest.layout))?;
             self.copy_op(&op, &field_dest, /*allow_transmute*/ false)?;
         }
-        self.write_discriminant(variant_index, &dest)
+        self.write_discriminant(variant_index, dest)
     }
 
     pub fn raw_const_to_mplace(
@@ -983,7 +1015,7 @@ where
 
     /// Turn a `dyn* Trait` type into an value with the actual dynamic type.
     /// Also returns the vtable.
-    pub(super) fn unpack_dyn_star<P: Projectable<'mir, 'tcx, M::Provenance>>(
+    pub(super) fn unpack_dyn_star<P: Projectable<'tcx, M::Provenance>>(
         &self,
         val: &P,
     ) -> InterpResult<'tcx, (P, Pointer<Option<M::Provenance>>)> {
diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index ddcbc8350aa..bce43aedb69 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -16,21 +16,20 @@ use rustc_target::abi::HasDataLayout;
 use rustc_target::abi::Size;
 use rustc_target::abi::{self, VariantIdx};
 
-use super::MPlaceTy;
-use super::{InterpCx, InterpResult, Machine, MemPlaceMeta, OpTy, Provenance, Scalar};
+use super::{InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Provenance, Scalar};
 
 /// A thing that we can project into, and that has a layout.
-pub trait Projectable<'mir, 'tcx: 'mir, Prov: Provenance>: Sized {
+pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug {
     /// Get the layout.
     fn layout(&self) -> TyAndLayout<'tcx>;
 
     /// Get the metadata of a wide value.
-    fn meta<M: Machine<'mir, 'tcx, Provenance = Prov>>(
+    fn meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
         &self,
         ecx: &InterpCx<'mir, 'tcx, M>,
     ) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>>;
 
-    fn len<M: Machine<'mir, 'tcx, Provenance = Prov>>(
+    fn len<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
         &self,
         ecx: &InterpCx<'mir, 'tcx, M>,
     ) -> InterpResult<'tcx, u64> {
@@ -67,7 +66,7 @@ pub trait Projectable<'mir, 'tcx: 'mir, Prov: Provenance>: Sized {
 
     /// Convert this to an `OpTy`. This might be an irreversible transformation, but is useful for
     /// reading from this thing.
-    fn to_op<M: Machine<'mir, 'tcx, Provenance = Prov>>(
+    fn to_op<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
         &self,
         ecx: &InterpCx<'mir, 'tcx, M>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>;
@@ -85,7 +84,7 @@ where
     ///
     /// This also works for arrays, but then the `usize` index type is restricting.
     /// For indexing into arrays, use `mplace_index`.
-    pub fn project_field<P: Projectable<'mir, 'tcx, M::Provenance>>(
+    pub fn project_field<P: Projectable<'tcx, M::Provenance>>(
         &self,
         base: &P,
         field: usize,
@@ -128,7 +127,7 @@ where
     }
 
     /// Downcasting to an enum variant.
-    pub fn project_downcast<P: Projectable<'mir, 'tcx, M::Provenance>>(
+    pub fn project_downcast<P: Projectable<'tcx, M::Provenance>>(
         &self,
         base: &P,
         variant: VariantIdx,
@@ -149,7 +148,7 @@ where
     }
 
     /// Compute the offset and field layout for accessing the given index.
-    pub fn project_index<P: Projectable<'mir, 'tcx, M::Provenance>>(
+    pub fn project_index<P: Projectable<'tcx, M::Provenance>>(
         &self,
         base: &P,
         index: u64,
@@ -178,7 +177,7 @@ where
         base.offset(offset, field_layout, self)
     }
 
-    fn project_constant_index<P: Projectable<'mir, 'tcx, M::Provenance>>(
+    fn project_constant_index<P: Projectable<'tcx, M::Provenance>>(
         &self,
         base: &P,
         offset: u64,
@@ -204,7 +203,7 @@ where
 
     /// Iterates over all fields of an array. Much more efficient than doing the
     /// same by repeatedly calling `operand_index`.
-    pub fn project_array_fields<'a, P: Projectable<'mir, 'tcx, M::Provenance>>(
+    pub fn project_array_fields<'a, P: Projectable<'tcx, M::Provenance>>(
         &self,
         base: &'a P,
     ) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, P>> + 'a>
@@ -224,7 +223,7 @@ where
     }
 
     /// Subslicing
-    fn project_subslice<P: Projectable<'mir, 'tcx, M::Provenance>>(
+    fn project_subslice<P: Projectable<'tcx, M::Provenance>>(
         &self,
         base: &P,
         from: u64,
@@ -284,9 +283,7 @@ where
     #[instrument(skip(self), level = "trace")]
     pub fn project<P>(&self, base: &P, proj_elem: mir::PlaceElem<'tcx>) -> InterpResult<'tcx, P>
     where
-        P: Projectable<'mir, 'tcx, M::Provenance>
-            + From<MPlaceTy<'tcx, M::Provenance>>
-            + std::fmt::Debug,
+        P: Projectable<'tcx, M::Provenance> + From<MPlaceTy<'tcx, M::Provenance>> + std::fmt::Debug,
     {
         use rustc_middle::mir::ProjectionElem::*;
         Ok(match proj_elem {
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 9182d23128f..1f2d04f4008 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -198,7 +198,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 } else {
                     // Write the src to the first element.
                     let first = self.project_index(&dest, 0)?;
-                    self.copy_op(&src, &first.into(), /*allow_transmute*/ false)?;
+                    self.copy_op(&src, &first, /*allow_transmute*/ false)?;
 
                     // This is performance-sensitive code for big static/const arrays! So we
                     // avoid writing each operand individually and instead just make many copies
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index f934cca2517..d0191ea978a 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -634,7 +634,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     // Ensure the return place is aligned and dereferenceable, and protect it for
                     // in-place return value passing.
                     if let Either::Left(mplace) = destination.as_mplace_or_local() {
-                        self.check_mplace(mplace)?;
+                        self.check_mplace(&mplace)?;
                     } else {
                         // Nothing to do for locals, they are always properly allocated and aligned.
                     }
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index a82c98e7205..4fd5fd13c3c 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -136,19 +136,19 @@ pub struct RefTracking<T, PATH = ()> {
     pub todo: Vec<(T, PATH)>,
 }
 
-impl<T: Copy + Eq + Hash + std::fmt::Debug, PATH: Default> RefTracking<T, PATH> {
+impl<T: Clone + Eq + Hash + std::fmt::Debug, PATH: Default> RefTracking<T, PATH> {
     pub fn empty() -> Self {
         RefTracking { seen: FxHashSet::default(), todo: vec![] }
     }
     pub fn new(op: T) -> Self {
         let mut ref_tracking_for_consts =
-            RefTracking { seen: FxHashSet::default(), todo: vec![(op, PATH::default())] };
+            RefTracking { seen: FxHashSet::default(), todo: vec![(op.clone(), PATH::default())] };
         ref_tracking_for_consts.seen.insert(op);
         ref_tracking_for_consts
     }
 
     pub fn track(&mut self, op: T, path: impl FnOnce() -> PATH) {
-        if self.seen.insert(op) {
+        if self.seen.insert(op.clone()) {
             trace!("Recursing below ptr {:#?}", op);
             let path = path();
             // Remember to come back to this later.
diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs
index 4ec19d9e655..531e2bd3ee0 100644
--- a/compiler/rustc_const_eval/src/interpret/visitor.rs
+++ b/compiler/rustc_const_eval/src/interpret/visitor.rs
@@ -13,9 +13,7 @@ use super::{InterpCx, MPlaceTy, Machine, Projectable};
 
 /// How to traverse a value and what to do when we are at the leaves.
 pub trait ValueVisitor<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized {
-    type V: Projectable<'mir, 'tcx, M::Provenance>
-        + From<MPlaceTy<'tcx, M::Provenance>>
-        + std::fmt::Debug;
+    type V: Projectable<'tcx, M::Provenance> + From<MPlaceTy<'tcx, M::Provenance>>;
 
     /// The visitor must have an `InterpCx` in it.
     fn ecx(&self) -> &InterpCx<'mir, 'tcx, M>;
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 8722979cb5e..8f8b9eaa274 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -1415,7 +1415,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info:
         false,
         TerminalUrl::No,
     ));
-    let handler = rustc_errors::Handler::with_emitter(true, None, emitter, None);
+    let handler = rustc_errors::Handler::with_emitter(emitter);
 
     // a .span_bug or .bug call has already printed what
     // it wants to print.
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index 08ff2cfba5c..5e23ae655fe 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -536,7 +536,9 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
             }
         };
 
-        if handler.flags.dont_buffer_diagnostics || handler.flags.treat_err_as_bug.is_some() {
+        if handler.inner.lock().flags.dont_buffer_diagnostics
+            || handler.inner.lock().flags.treat_err_as_bug.is_some()
+        {
             self.emit();
             return None;
         }
diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs
index db0dd4ffe8e..1f9a2981e02 100644
--- a/compiler/rustc_errors/src/json/tests.rs
+++ b/compiler/rustc_errors/src/json/tests.rs
@@ -64,7 +64,7 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) {
         );
 
         let span = Span::with_root_ctxt(BytePos(span.0), BytePos(span.1));
-        let handler = Handler::with_emitter(true, None, Box::new(je), None);
+        let handler = Handler::with_emitter(Box::new(je));
         handler.span_err(span, "foo");
 
         let bytes = output.lock().unwrap();
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index eae7a46e07a..d18e01d178e 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -391,7 +391,6 @@ use std::backtrace::{Backtrace, BacktraceStatus};
 /// Certain errors (fatal, bug, unimpl) may cause immediate exit,
 /// others log errors for later reporting.
 pub struct Handler {
-    flags: HandlerFlags,
     inner: Lock<HandlerInner>,
 }
 
@@ -549,69 +548,47 @@ impl Drop for HandlerInner {
 
 impl Handler {
     pub fn with_tty_emitter(
-        color_config: ColorConfig,
-        can_emit_warnings: bool,
-        treat_err_as_bug: Option<NonZeroUsize>,
         sm: Option<Lrc<SourceMap>>,
-        fluent_bundle: Option<Lrc<FluentBundle>>,
         fallback_bundle: LazyFallbackBundle,
-        ice_file: Option<PathBuf>,
-    ) -> Self {
-        Self::with_tty_emitter_and_flags(
-            color_config,
-            sm,
-            fluent_bundle,
-            fallback_bundle,
-            HandlerFlags { can_emit_warnings, treat_err_as_bug, ..Default::default() },
-            ice_file,
-        )
-    }
-
-    pub fn with_tty_emitter_and_flags(
-        color_config: ColorConfig,
-        sm: Option<Lrc<SourceMap>>,
-        fluent_bundle: Option<Lrc<FluentBundle>>,
-        fallback_bundle: LazyFallbackBundle,
-        flags: HandlerFlags,
-        ice_file: Option<PathBuf>,
     ) -> Self {
         let emitter = Box::new(EmitterWriter::stderr(
-            color_config,
+            ColorConfig::Auto,
             sm,
-            fluent_bundle,
+            None,
             fallback_bundle,
             false,
             false,
             None,
-            flags.macro_backtrace,
-            flags.track_diagnostics,
+            false,
+            false,
             TerminalUrl::No,
         ));
-        Self::with_emitter_and_flags(emitter, flags, ice_file)
+        Self::with_emitter(emitter)
+    }
+    pub fn disable_warnings(mut self) -> Self {
+        self.inner.get_mut().flags.can_emit_warnings = false;
+        self
     }
 
-    pub fn with_emitter(
-        can_emit_warnings: bool,
-        treat_err_as_bug: Option<NonZeroUsize>,
-        emitter: Box<dyn Emitter + sync::Send>,
-        ice_file: Option<PathBuf>,
-    ) -> Self {
-        Handler::with_emitter_and_flags(
-            emitter,
-            HandlerFlags { can_emit_warnings, treat_err_as_bug, ..Default::default() },
-            ice_file,
-        )
+    pub fn treat_err_as_bug(mut self, treat_err_as_bug: NonZeroUsize) -> Self {
+        self.inner.get_mut().flags.treat_err_as_bug = Some(treat_err_as_bug);
+        self
     }
 
-    pub fn with_emitter_and_flags(
-        emitter: Box<dyn Emitter + sync::Send>,
-        flags: HandlerFlags,
-        ice_file: Option<PathBuf>,
-    ) -> Self {
+    pub fn with_flags(mut self, flags: HandlerFlags) -> Self {
+        self.inner.get_mut().flags = flags;
+        self
+    }
+
+    pub fn with_ice_file(mut self, ice_file: PathBuf) -> Self {
+        self.inner.get_mut().ice_file = Some(ice_file);
+        self
+    }
+
+    pub fn with_emitter(emitter: Box<dyn Emitter + sync::Send>) -> Self {
         Self {
-            flags,
             inner: Lock::new(HandlerInner {
-                flags,
+                flags: HandlerFlags { can_emit_warnings: true, ..Default::default() },
                 lint_err_count: 0,
                 err_count: 0,
                 warn_count: 0,
@@ -629,7 +606,7 @@ impl Handler {
                 check_unstable_expect_diagnostics: false,
                 unstable_expect_diagnostics: Vec::new(),
                 fulfilled_expectations: Default::default(),
-                ice_file,
+                ice_file: None,
             }),
         }
     }
@@ -657,7 +634,7 @@ impl Handler {
     // This is here to not allow mutation of flags;
     // as of this writing it's only used in tests in librustc_middle.
     pub fn can_emit_warnings(&self) -> bool {
-        self.flags.can_emit_warnings
+        self.inner.lock().flags.can_emit_warnings
     }
 
     /// Resets the diagnostic error count as well as the cached emitted diagnostics.
diff --git a/compiler/rustc_expand/src/parse/tests.rs b/compiler/rustc_expand/src/parse/tests.rs
index 8b37728b60f..e133501c5d0 100644
--- a/compiler/rustc_expand/src/parse/tests.rs
+++ b/compiler/rustc_expand/src/parse/tests.rs
@@ -1,4 +1,6 @@
-use crate::tests::{matches_codepattern, string_to_stream, with_error_checking_parse};
+use crate::tests::{
+    matches_codepattern, string_to_stream, with_error_checking_parse, with_expected_parse_error,
+};
 
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, Token};
@@ -51,11 +53,15 @@ fn string_to_item(source_str: String) -> Option<P<ast::Item>> {
     with_error_checking_parse(source_str, &sess(), |p| p.parse_item(ForceCollect::No))
 }
 
-#[should_panic]
 #[test]
 fn bad_path_expr_1() {
+    // This should trigger error: expected identifier, found keyword `return`
     create_default_session_globals_then(|| {
-        string_to_expr("::abc::def::return".to_string());
+        with_expected_parse_error(
+            "::abc::def::return",
+            "expected identifier, found keyword `return`",
+            |p| p.parse_expr(),
+        );
     })
 }
 
diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs
index 6490e52955d..30fa5fea407 100644
--- a/compiler/rustc_expand/src/tests.rs
+++ b/compiler/rustc_expand/src/tests.rs
@@ -22,6 +22,33 @@ fn string_to_parser(ps: &ParseSess, source_str: String) -> Parser<'_> {
     new_parser_from_source_str(ps, PathBuf::from("bogofile").into(), source_str)
 }
 
+fn create_test_handler() -> (Handler, Lrc<SourceMap>, Arc<Mutex<Vec<u8>>>) {
+    let output = Arc::new(Mutex::new(Vec::new()));
+    let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
+    let fallback_bundle = rustc_errors::fallback_fluent_bundle(
+        vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
+        false,
+    );
+    let emitter = EmitterWriter::new(
+        Box::new(Shared { data: output.clone() }),
+        Some(source_map.clone()),
+        None,
+        fallback_bundle,
+        false,
+        false,
+        false,
+        Some(140),
+        false,
+        false,
+        TerminalUrl::No,
+    );
+    let handler = Handler::with_emitter(Box::new(emitter));
+    (handler, source_map, output)
+}
+
+/// Returns the result of parsing the given string via the given callback.
+///
+/// If there are any errors, this will panic.
 pub(crate) fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> T
 where
     F: FnOnce(&mut Parser<'a>) -> PResult<'a, T>,
@@ -32,6 +59,26 @@ where
     x
 }
 
+/// Verifies that parsing the given string using the given callback will
+/// generate an error that contains the given text.
+pub(crate) fn with_expected_parse_error<T, F>(source_str: &str, expected_output: &str, f: F)
+where
+    F: for<'a> FnOnce(&mut Parser<'a>) -> PResult<'a, T>,
+{
+    let (handler, source_map, output) = create_test_handler();
+    let ps = ParseSess::with_span_handler(handler, source_map);
+    let mut p = string_to_parser(&ps, source_str.to_string());
+    let result = f(&mut p);
+    assert!(result.is_ok());
+
+    let bytes = output.lock().unwrap();
+    let actual_output = str::from_utf8(&bytes).unwrap();
+    println!("expected output:\n------\n{}------", expected_output);
+    println!("actual output:\n------\n{}------", actual_output);
+
+    assert!(actual_output.contains(expected_output))
+}
+
 /// Maps a string to tts, using a made-up filename.
 pub(crate) fn string_to_stream(source_str: String) -> TokenStream {
     let ps = ParseSess::new(
@@ -130,13 +177,7 @@ impl<T: Write> Write for Shared<T> {
 
 fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) {
     create_default_session_if_not_set_then(|_| {
-        let output = Arc::new(Mutex::new(Vec::new()));
-
-        let fallback_bundle = rustc_errors::fallback_fluent_bundle(
-            vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
-            false,
-        );
-        let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
+        let (handler, source_map, output) = create_test_handler();
         source_map.new_source_file(Path::new("test.rs").to_owned().into(), file_text.to_owned());
 
         let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end);
@@ -148,20 +189,6 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &
             println!("text: {:?}", source_map.span_to_snippet(span));
         }
 
-        let emitter = EmitterWriter::new(
-            Box::new(Shared { data: output.clone() }),
-            Some(source_map.clone()),
-            None,
-            fallback_bundle,
-            false,
-            false,
-            false,
-            None,
-            false,
-            false,
-            TerminalUrl::No,
-        );
-        let handler = Handler::with_emitter(true, None, Box::new(emitter), None);
         #[allow(rustc::untranslatable_diagnostic)]
         handler.span_err(msp, "foo");
 
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 2c92277b50d..252177932e4 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -267,8 +267,6 @@ lint_improper_ctypes_char_help = consider using `u32` or `libc::wchar_t` instead
 lint_improper_ctypes_char_reason = the `char` type has no C equivalent
 lint_improper_ctypes_dyn = trait objects have no C equivalent
 
-lint_improper_ctypes_enum_phantomdata = this enum contains a PhantomData field
-
 lint_improper_ctypes_enum_repr_help =
     consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
 
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 3379479b174..226d01b79a8 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -985,39 +985,43 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
     ) -> FfiResult<'tcx> {
         use FfiResult::*;
 
-        let transparent_safety = def.repr().transparent().then(|| {
-            // Can assume that at most one field is not a ZST, so only check
-            // that field's type for FFI-safety.
+        let transparent_with_all_zst_fields = if def.repr().transparent() {
             if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
-                return self.check_field_type_for_ffi(cache, field, args);
+                // Transparent newtypes have at most one non-ZST field which needs to be checked..
+                match self.check_field_type_for_ffi(cache, field, args) {
+                    FfiUnsafe { ty, .. } if ty.is_unit() => (),
+                    r => return r,
+                }
+
+                false
             } else {
-                // All fields are ZSTs; this means that the type should behave
-                // like (), which is FFI-unsafe... except if all fields are PhantomData,
-                // which is tested for below
-                FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None }
+                // ..or have only ZST fields, which is FFI-unsafe (unless those fields are all
+                // `PhantomData`).
+                true
             }
-        });
-        // We can't completely trust repr(C) markings; make sure the fields are
-        // actually safe.
+        } else {
+            false
+        };
+
+        // We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
         let mut all_phantom = !variant.fields.is_empty();
         for field in &variant.fields {
-            match self.check_field_type_for_ffi(cache, &field, args) {
-                FfiSafe => {
-                    all_phantom = false;
-                }
-                FfiPhantom(..) if !def.repr().transparent() && def.is_enum() => {
-                    return FfiUnsafe {
-                        ty,
-                        reason: fluent::lint_improper_ctypes_enum_phantomdata,
-                        help: None,
-                    };
-                }
-                FfiPhantom(..) => {}
-                r => return transparent_safety.unwrap_or(r),
+            all_phantom &= match self.check_field_type_for_ffi(cache, &field, args) {
+                FfiSafe => false,
+                // `()` fields are FFI-safe!
+                FfiUnsafe { ty, .. } if ty.is_unit() => false,
+                FfiPhantom(..) => true,
+                r @ FfiUnsafe { .. } => return r,
             }
         }
 
-        if all_phantom { FfiPhantom(ty) } else { transparent_safety.unwrap_or(FfiSafe) }
+        if all_phantom {
+            FfiPhantom(ty)
+        } else if transparent_with_all_zst_fields {
+            FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None }
+        } else {
+            FfiSafe
+        }
     }
 
     /// Checks if the given type is "ffi-safe" (has a stable, well-defined
@@ -1220,25 +1224,19 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 }
 
                 let sig = tcx.erase_late_bound_regions(sig);
-                if !sig.output().is_unit() {
-                    let r = self.check_type_for_ffi(cache, sig.output());
-                    match r {
-                        FfiSafe => {}
-                        _ => {
-                            return r;
-                        }
-                    }
-                }
                 for arg in sig.inputs() {
-                    let r = self.check_type_for_ffi(cache, *arg);
-                    match r {
+                    match self.check_type_for_ffi(cache, *arg) {
                         FfiSafe => {}
-                        _ => {
-                            return r;
-                        }
+                        r => return r,
                     }
                 }
-                FfiSafe
+
+                let ret_ty = sig.output();
+                if ret_ty.is_unit() {
+                    return FfiSafe;
+                }
+
+                self.check_type_for_ffi(cache, ret_ty)
             }
 
             ty::Foreign(..) => FfiSafe,
@@ -1354,7 +1352,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         }
 
         // Don't report FFI errors for unit return types. This check exists here, and not in
-        // `check_foreign_fn` (where it would make more sense) so that normalization has definitely
+        // the caller (where it would make more sense) so that normalization has definitely
         // happened.
         if is_return_type && ty.is_unit() {
             return;
@@ -1370,9 +1368,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                     None,
                 );
             }
-            // If `ty` is a `repr(transparent)` newtype, and the non-zero-sized type is a generic
-            // argument, which after substitution, is `()`, then this branch can be hit.
-            FfiResult::FfiUnsafe { ty, .. } if is_return_type && ty.is_unit() => {}
             FfiResult::FfiUnsafe { ty, reason, help } => {
                 self.emit_ffi_unsafe_type_lint(ty, sp, reason, help);
             }
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index 4c238308fe8..bb8e774cea3 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -13,7 +13,7 @@ gsgdt = "0.1.2"
 field-offset = "0.3.5"
 measureme = "10.0.0"
 polonius-engine = "0.13.0"
-rustc_apfloat = { path = "../rustc_apfloat" }
+rustc_apfloat = "0.2.0"
 rustc_arena = { path = "../rustc_arena" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_attr = { path = "../rustc_attr" }
diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml
index 58449ee9eb4..c7e2c625ce5 100644
--- a/compiler/rustc_mir_build/Cargo.toml
+++ b/compiler/rustc_mir_build/Cargo.toml
@@ -10,7 +10,7 @@ rustc_arena = { path = "../rustc_arena" }
 tracing = "0.1"
 either = "1"
 rustc_middle = { path = "../rustc_middle" }
-rustc_apfloat = { path = "../rustc_apfloat" }
+rustc_apfloat = "0.2.0"
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_index = { path = "../rustc_index" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index 01b945afda6..ac07c25763b 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -494,7 +494,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         trace!("assertion on {:?} should be {:?}", value, expected);
 
         let expected = Scalar::from_bool(expected);
-        let value_const = self.use_ecx(location, |this| this.ecx.read_scalar(&value))?;
+        let value_const = self.use_ecx(location, |this| this.ecx.read_scalar(value))?;
 
         if expected != value_const {
             // Poison all places this operand references so that further code
@@ -664,7 +664,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
             }
             TerminatorKind::SwitchInt { ref discr, ref targets } => {
                 if let Some(ref value) = self.eval_operand(&discr, location)
-                  && let Some(value_const) = self.use_ecx(location, |this| this.ecx.read_scalar(&value))
+                  && let Some(value_const) = self.use_ecx(location, |this| this.ecx.read_scalar(value))
                   && let Ok(constant) = value_const.try_to_int()
                   && let Ok(constant) = constant.to_bits(constant.size())
                 {
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index c19c2d1dc9e..4a535f80b8a 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1433,8 +1433,6 @@ options! {
     dep_tasks: bool = (false, parse_bool, [UNTRACKED],
         "print tasks that execute and the color their dep node gets (requires debug build) \
         (default: no)"),
-    diagnostic_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
-        "set the current output width for diagnostic truncation"),
     dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
         "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) \
         (default: no)"),
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index b0a67c564ce..bca49981668 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -9,7 +9,7 @@ use crate::lint::{
 use rustc_ast::node_id::NodeId;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_data_structures::sync::{AppendOnlyVec, AtomicBool, Lock, Lrc};
-use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
+use rustc_errors::{emitter::SilentEmitter, Handler};
 use rustc_errors::{
     fallback_fluent_bundle, Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
     EmissionGuarantee, ErrorGuaranteed, IntoDiagnostic, MultiSpan, Noted, StashKey,
@@ -224,15 +224,7 @@ impl ParseSess {
     pub fn new(locale_resources: Vec<&'static str>, file_path_mapping: FilePathMapping) -> Self {
         let fallback_bundle = fallback_fluent_bundle(locale_resources, false);
         let sm = Lrc::new(SourceMap::new(file_path_mapping));
-        let handler = Handler::with_tty_emitter(
-            ColorConfig::Auto,
-            true,
-            None,
-            Some(sm.clone()),
-            None,
-            fallback_bundle,
-            None,
-        );
+        let handler = Handler::with_tty_emitter(Some(sm.clone()), fallback_bundle);
         ParseSess::with_span_handler(handler, sm)
     }
 
@@ -262,21 +254,9 @@ impl ParseSess {
     pub fn with_silent_emitter(fatal_note: Option<String>) -> Self {
         let fallback_bundle = fallback_fluent_bundle(Vec::new(), false);
         let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
-        let fatal_handler = Handler::with_tty_emitter(
-            ColorConfig::Auto,
-            false,
-            None,
-            None,
-            None,
-            fallback_bundle,
-            None,
-        );
-        let handler = Handler::with_emitter(
-            false,
-            None,
-            Box::new(SilentEmitter { fatal_handler, fatal_note }),
-            None,
-        );
+        let fatal_handler = Handler::with_tty_emitter(None, fallback_bundle).disable_warnings();
+        let handler = Handler::with_emitter(Box::new(SilentEmitter { fatal_handler, fatal_note }))
+            .disable_warnings();
         ParseSess::with_span_handler(handler, sm)
     }
 
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 3c8be439111..ad22e7c703d 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1442,11 +1442,11 @@ pub fn build_session(
     );
     let emitter = default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle);
 
-    let span_diagnostic = rustc_errors::Handler::with_emitter_and_flags(
-        emitter,
-        sopts.unstable_opts.diagnostic_handler_flags(can_emit_warnings),
-        ice_file,
-    );
+    let mut span_diagnostic = rustc_errors::Handler::with_emitter(emitter)
+        .with_flags(sopts.unstable_opts.diagnostic_handler_flags(can_emit_warnings));
+    if let Some(ice_file) = ice_file {
+        span_diagnostic = span_diagnostic.with_ice_file(ice_file);
+    }
 
     let self_profiler = if let SwitchWithOptPath::Enabled(ref d) = sopts.unstable_opts.self_profile
     {
@@ -1737,7 +1737,7 @@ pub struct EarlyErrorHandler {
 impl EarlyErrorHandler {
     pub fn new(output: ErrorOutputType) -> Self {
         let emitter = mk_emitter(output);
-        Self { handler: rustc_errors::Handler::with_emitter(true, None, emitter, None) }
+        Self { handler: rustc_errors::Handler::with_emitter(emitter) }
     }
 
     pub fn abort_if_errors(&self) {
@@ -1751,7 +1751,7 @@ impl EarlyErrorHandler {
         self.handler.abort_if_errors();
 
         let emitter = mk_emitter(output);
-        self.handler = Handler::with_emitter(true, None, emitter, None);
+        self.handler = Handler::with_emitter(emitter);
     }
 
     #[allow(rustc::untranslatable_diagnostic)]
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index 044e2f8f325..cefcab1e18f 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -825,8 +825,10 @@ impl<'tcx> Stable<'tcx> for Ty<'tcx> {
             ty::Alias(alias_kind, alias_ty) => {
                 TyKind::Alias(alias_kind.stable(tables), alias_ty.stable(tables))
             }
-            ty::Param(_) => todo!(),
-            ty::Bound(_, _) => todo!(),
+            ty::Param(param_ty) => TyKind::Param(param_ty.stable(tables)),
+            ty::Bound(debruijn_idx, bound_ty) => {
+                TyKind::Bound(debruijn_idx.as_usize(), bound_ty.stable(tables))
+            }
             ty::Placeholder(..)
             | ty::GeneratorWitness(_)
             | ty::GeneratorWitnessMIR(_, _)
@@ -837,3 +839,19 @@ impl<'tcx> Stable<'tcx> for Ty<'tcx> {
         }
     }
 }
+
+impl<'tcx> Stable<'tcx> for rustc_middle::ty::ParamTy {
+    type T = stable_mir::ty::ParamTy;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::ty::ParamTy;
+        ParamTy { index: self.index, name: self.name.to_string() }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_middle::ty::BoundTy {
+    type T = stable_mir::ty::BoundTy;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::ty::BoundTy;
+        BoundTy { var: self.var.as_usize(), kind: self.kind.stable(tables) }
+    }
+}
diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs
index 7b4747a7fe2..7a72afd666c 100644
--- a/compiler/rustc_smir/src/stable_mir/ty.rs
+++ b/compiler/rustc_smir/src/stable_mir/ty.rs
@@ -18,6 +18,8 @@ type Span = Opaque;
 pub enum TyKind {
     RigidTy(RigidTy),
     Alias(AliasKind, AliasTy),
+    Param(ParamTy),
+    Bound(usize, BoundTy),
 }
 
 #[derive(Clone, Debug)]
@@ -228,3 +230,15 @@ pub struct ExistentialProjection {
     pub generic_args: GenericArgs,
     pub term: TermKind,
 }
+
+#[derive(Clone, Debug)]
+pub struct ParamTy {
+    pub index: u32,
+    pub name: String,
+}
+
+#[derive(Clone, Debug)]
+pub struct BoundTy {
+    pub var: usize,
+    pub kind: BoundTyKind,
+}
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 08925761b39..54eb7bef5f2 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -372,6 +372,7 @@ symbols! {
         arm_target_feature,
         array,
         arrays,
+        as_mut_ptr,
         as_ptr,
         as_ref,
         as_str,
@@ -858,6 +859,7 @@ symbols! {
         item,
         item_like_imports,
         iter,
+        iter_mut,
         iter_repeat,
         iterator_collect_fn,
         kcfi,
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index f683832e3df..845b5791161 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -7,10 +7,10 @@
 ///
 /// For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
 /// see design document in the tracking issue #89653.
-use core::fmt::Display;
 use rustc_data_structures::base_n;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
+use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{
     self, Const, ExistentialPredicate, FloatTy, FnSig, Instance, IntTy, List, Region, RegionKind,
     TermKind, Ty, TyCtxt, UintTy,
@@ -19,6 +19,7 @@ use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgsRef};
 use rustc_span::def_id::DefId;
 use rustc_span::sym;
 use rustc_target::abi::call::{Conv, FnAbi};
+use rustc_target::abi::Integer;
 use rustc_target::spec::abi::Abi;
 use std::fmt::Write as _;
 
@@ -93,44 +94,54 @@ fn encode_const<'tcx>(
     dict: &mut FxHashMap<DictKey<'tcx>, usize>,
     options: EncodeTyOptions,
 ) -> String {
-    // L<element-type>[n]<element-value>E as literal argument
+    // L<element-type>[n][<element-value>]E as literal argument
     let mut s = String::from('L');
 
-    // Element type
-    s.push_str(&encode_ty(tcx, c.ty(), dict, options));
+    match c.kind() {
+        // Const parameters
+        ty::ConstKind::Param(..) => {
+            // L<element-type>E as literal argument
 
-    // The only allowed types of const parameters are bool, u8, u16, u32, u64, u128, usize i8, i16,
-    // i32, i64, i128, isize, and char. The bool value false is encoded as 0 and true as 1.
-    fn push_signed_value<T: Display + PartialOrd>(s: &mut String, value: T, zero: T) {
-        if value < zero {
-            s.push('n')
-        };
-        let _ = write!(s, "{value}");
-    }
-
-    fn push_unsigned_value<T: Display>(s: &mut String, value: T) {
-        let _ = write!(s, "{value}");
-    }
+            // Element type
+            s.push_str(&encode_ty(tcx, c.ty(), dict, options));
+        }
 
-    if let Some(scalar_int) = c.try_to_scalar_int() {
-        let signed = c.ty().is_signed();
-        match scalar_int.size().bits() {
-            8 if signed => push_signed_value(&mut s, scalar_int.try_to_i8().unwrap(), 0),
-            16 if signed => push_signed_value(&mut s, scalar_int.try_to_i16().unwrap(), 0),
-            32 if signed => push_signed_value(&mut s, scalar_int.try_to_i32().unwrap(), 0),
-            64 if signed => push_signed_value(&mut s, scalar_int.try_to_i64().unwrap(), 0),
-            128 if signed => push_signed_value(&mut s, scalar_int.try_to_i128().unwrap(), 0),
-            8 => push_unsigned_value(&mut s, scalar_int.try_to_u8().unwrap()),
-            16 => push_unsigned_value(&mut s, scalar_int.try_to_u16().unwrap()),
-            32 => push_unsigned_value(&mut s, scalar_int.try_to_u32().unwrap()),
-            64 => push_unsigned_value(&mut s, scalar_int.try_to_u64().unwrap()),
-            128 => push_unsigned_value(&mut s, scalar_int.try_to_u128().unwrap()),
-            _ => {
-                bug!("encode_const: unexpected size `{:?}`", scalar_int.size().bits());
+        // Literal arguments
+        ty::ConstKind::Value(..) => {
+            // L<element-type>[n]<element-value>E as literal argument
+
+            // Element type
+            s.push_str(&encode_ty(tcx, c.ty(), dict, options));
+
+            // The only allowed types of const values are bool, u8, u16, u32,
+            // u64, u128, usize i8, i16, i32, i64, i128, isize, and char. The
+            // bool value false is encoded as 0 and true as 1.
+            match c.ty().kind() {
+                ty::Int(ity) => {
+                    let bits = c.eval_bits(tcx, ty::ParamEnv::reveal_all(), c.ty());
+                    let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
+                    if val < 0 {
+                        s.push('n');
+                    }
+                    let _ = write!(s, "{val}");
+                }
+                ty::Uint(_) => {
+                    let val = c.eval_bits(tcx, ty::ParamEnv::reveal_all(), c.ty());
+                    let _ = write!(s, "{val}");
+                }
+                ty::Bool => {
+                    let val = c.try_eval_bool(tcx, ty::ParamEnv::reveal_all()).unwrap();
+                    let _ = write!(s, "{val}");
+                }
+                _ => {
+                    bug!("encode_const: unexpected type `{:?}`", c.ty());
+                }
             }
-        };
-    } else {
-        bug!("encode_const: unexpected type `{:?}`", c.ty());
+        }
+
+        _ => {
+            bug!("encode_const: unexpected kind `{:?}`", c.kind());
+        }
     }
 
     // Close the "L..E" pair