Backed out changeset 45210f041ea7 (bug 1558538) for causing bustages. CLOSED TREE
authorMihai Alexandru Michis <malexandru@mozilla.com>
Wed, 19 Jun 2019 18:26:41 +0300
changeset 479209 265a8451194c0a558fde24db7bb44982ad4a8c8e
parent 479208 45210f041ea71be2f52d7e7c66cf9cb1fb8659c7
child 479210 33ef5e8d04f8a28ce8f6c6ba35ee6ec37babb97d
push id36174
push useropoprus@mozilla.com
push dateWed, 19 Jun 2019 21:38:13 +0000
treeherdermozilla-central@5b9a3de04646 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1558538
milestone69.0a1
backs out45210f041ea71be2f52d7e7c66cf9cb1fb8659c7
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset 45210f041ea7 (bug 1558538) for causing bustages. CLOSED TREE
js/src/tests/non262/BigInt/Number-conversion-rounding.js
js/src/vm/BigIntType.cpp
deleted file mode 100644
--- a/js/src/tests/non262/BigInt/Number-conversion-rounding.js
+++ /dev/null
@@ -1,187 +0,0 @@
-// |reftest| skip-if(!this.hasOwnProperty("BigInt"))
-// Any copyright is dedicated to the Public Domain.
-// https://creativecommons.org/licenses/publicdomain/
-
-/**
- * Simple single-Digit on x64, double-Digit on x86 tests.
- */
-
-assertEq(BigInt(Number(2n**53n - 2n)), 2n**53n - 2n);
-assertEq(BigInt(Number(2n**53n - 1n)), 2n**53n - 1n);
-assertEq(BigInt(Number(2n**53n)), 2n**53n);
-assertEq(BigInt(Number(2n**53n + 1n)), 2n**53n);
-assertEq(BigInt(Number(2n**53n + 2n)), 2n**53n + 2n);
-assertEq(BigInt(Number(2n**53n + 3n)), 2n**53n + 4n);
-assertEq(BigInt(Number(2n**53n + 4n)), 2n**53n + 4n);
-assertEq(BigInt(Number(2n**53n + 5n)), 2n**53n + 4n);
-assertEq(BigInt(Number(2n**53n + 6n)), 2n**53n + 6n);
-assertEq(BigInt(Number(2n**53n + 7n)), 2n**53n + 8n);
-assertEq(BigInt(Number(2n**53n + 8n)), 2n**53n + 8n);
-
-assertEq(BigInt(Number(2n**54n - 4n)), 2n**54n - 4n);
-assertEq(BigInt(Number(2n**54n - 3n)), 2n**54n - 4n);
-assertEq(BigInt(Number(2n**54n - 2n)), 2n**54n - 2n);
-assertEq(BigInt(Number(2n**54n - 1n)), 2n**54n);
-assertEq(BigInt(Number(2n**54n)), 2n**54n);
-assertEq(BigInt(Number(2n**54n + 1n)), 2n**54n);
-assertEq(BigInt(Number(2n**54n + 2n)), 2n**54n);
-assertEq(BigInt(Number(2n**54n + 3n)), 2n**54n + 4n);
-assertEq(BigInt(Number(2n**54n + 4n)), 2n**54n + 4n);
-assertEq(BigInt(Number(2n**54n + 5n)), 2n**54n + 4n);
-assertEq(BigInt(Number(2n**54n + 6n)), 2n**54n + 8n);
-assertEq(BigInt(Number(2n**54n + 7n)), 2n**54n + 8n);
-assertEq(BigInt(Number(2n**54n + 8n)), 2n**54n + 8n);
-
-assertEq(BigInt(Number(2n**55n - 8n)), 2n**55n - 8n);
-assertEq(BigInt(Number(2n**55n - 7n)), 2n**55n - 8n);
-assertEq(BigInt(Number(2n**55n - 6n)), 2n**55n - 8n);
-assertEq(BigInt(Number(2n**55n - 5n)), 2n**55n - 4n);
-assertEq(BigInt(Number(2n**55n - 4n)), 2n**55n - 4n);
-assertEq(BigInt(Number(2n**55n - 3n)), 2n**55n - 4n);
-assertEq(BigInt(Number(2n**55n - 2n)), 2n**55n);
-assertEq(BigInt(Number(2n**55n - 1n)), 2n**55n);
-assertEq(BigInt(Number(2n**55n)), 2n**55n);
-assertEq(BigInt(Number(2n**55n + 1n)), 2n**55n);
-assertEq(BigInt(Number(2n**55n + 2n)), 2n**55n);
-assertEq(BigInt(Number(2n**55n + 3n)), 2n**55n);
-assertEq(BigInt(Number(2n**55n + 4n)), 2n**55n);
-assertEq(BigInt(Number(2n**55n + 5n)), 2n**55n + 8n);
-assertEq(BigInt(Number(2n**55n + 6n)), 2n**55n + 8n);
-assertEq(BigInt(Number(2n**55n + 7n)), 2n**55n + 8n);
-assertEq(BigInt(Number(2n**55n + 8n)), 2n**55n + 8n);
-assertEq(BigInt(Number(2n**55n + 9n)), 2n**55n + 8n);
-assertEq(BigInt(Number(2n**55n + 10n)), 2n**55n + 8n);
-assertEq(BigInt(Number(2n**55n + 11n)), 2n**55n + 8n);
-assertEq(BigInt(Number(2n**55n + 12n)), 2n**55n + 16n);
-assertEq(BigInt(Number(2n**55n + 13n)), 2n**55n + 16n);
-assertEq(BigInt(Number(2n**55n + 14n)), 2n**55n + 16n);
-assertEq(BigInt(Number(2n**55n + 15n)), 2n**55n + 16n);
-assertEq(BigInt(Number(2n**55n + 16n)), 2n**55n + 16n);
-
-
-/**
- * Simple double-Digit on x64, triple-Digit on x86 tests.
- */
-
-// The tests below that aren't subtracting bits will have no bits in the
-// ultimate significand from the most-significant digit (because of the implicit
-// one being excluded).
-assertEq(BigInt(Number(2n**64n - 2n**11n)), 2n**64n - 2n**11n);
-assertEq(BigInt(Number(2n**64n - 2n**11n + 2n**10n - 1n)), 2n**64n - 2n**11n);
-assertEq(BigInt(Number(2n**64n - 2n**11n + 2n**10n)), 2n**64n);
-assertEq(BigInt(Number(2n**64n - 2n**10n)), 2n**64n);
-assertEq(BigInt(Number(2n**64n)), 2n**64n);
-assertEq(BigInt(Number(2n**64n + 1n)), 2n**64n);
-assertEq(BigInt(Number(2n**64n + 2n**5n)), 2n**64n);
-assertEq(BigInt(Number(2n**64n + 2n**10n)), 2n**64n);
-assertEq(BigInt(Number(2n**64n + 2n**11n)), 2n**64n);
-assertEq(BigInt(Number(2n**64n + 2n**11n + 1n)), 2n**64n + 2n**12n);
-assertEq(BigInt(Number(2n**64n + 2n**12n)), 2n**64n + 2n**12n);
-assertEq(BigInt(Number(2n**64n + 2n**12n + 1n)), 2n**64n + 2n**12n);
-assertEq(BigInt(Number(2n**64n + 2n**12n + 2n**5n)), 2n**64n + 2n**12n);
-assertEq(BigInt(Number(2n**64n + 2n**12n + 2n**10n)), 2n**64n + 2n**12n);
-assertEq(BigInt(Number(2n**64n + 2n**12n + 2n**11n - 1n)), 2n**64n + 2n**12n);
-assertEq(BigInt(Number(2n**64n + 2n**12n + 2n**11n)), 2n**64n + 2n**13n);
-assertEq(BigInt(Number(2n**64n + 2n**12n + 2n**11n + 1n)), 2n**64n + 2n**13n);
-
-// These tests *will* have a bit from the most-significant digit in the ultimate
-// significand.
-assertEq(BigInt(Number(2n**65n - 2n**12n)), 2n**65n - 2n**12n);
-assertEq(BigInt(Number(2n**65n - 2n**12n + 2n**11n - 1n)), 2n**65n - 2n**12n);
-assertEq(BigInt(Number(2n**65n - 2n**12n + 2n**11n)), 2n**65n);
-assertEq(BigInt(Number(2n**65n - 2n**11n)), 2n**65n);
-assertEq(BigInt(Number(2n**65n)), 2n**65n);
-assertEq(BigInt(Number(2n**65n + 1n)), 2n**65n);
-assertEq(BigInt(Number(2n**65n + 2n**5n)), 2n**65n);
-assertEq(BigInt(Number(2n**65n + 2n**11n)), 2n**65n);
-assertEq(BigInt(Number(2n**65n + 2n**12n)), 2n**65n);
-assertEq(BigInt(Number(2n**65n + 2n**12n + 1n)), 2n**65n + 2n**13n);
-assertEq(BigInt(Number(2n**65n + 2n**13n)), 2n**65n + 2n**13n);
-assertEq(BigInt(Number(2n**65n + 2n**13n + 1n)), 2n**65n + 2n**13n);
-assertEq(BigInt(Number(2n**65n + 2n**13n + 2n**5n)), 2n**65n + 2n**13n);
-assertEq(BigInt(Number(2n**65n + 2n**13n + 2n**11n)), 2n**65n + 2n**13n);
-assertEq(BigInt(Number(2n**65n + 2n**13n + 2n**12n - 1n)), 2n**65n + 2n**13n);
-assertEq(BigInt(Number(2n**65n + 2n**13n + 2n**12n)), 2n**65n + 2n**14n);
-assertEq(BigInt(Number(2n**65n + 2n**13n + 2n**12n + 1n)), 2n**65n + 2n**14n);
-
-// ...and in these tests, the contributed bit from the most-significant digit
-// is additionally nonzero.
-assertEq(BigInt(Number(2n**65n + 2n**64n)), 2n**65n + 2n**64n);
-assertEq(BigInt(Number(2n**65n + 2n**64n + 1n)), 2n**65n + 2n**64n);
-assertEq(BigInt(Number(2n**65n + 2n**64n + 2n**5n)), 2n**65n + 2n**64n);
-assertEq(BigInt(Number(2n**65n + 2n**64n + 2n**11n)), 2n**65n + 2n**64n);
-assertEq(BigInt(Number(2n**65n + 2n**64n + 2n**12n)), 2n**65n + 2n**64n);
-assertEq(BigInt(Number(2n**65n + 2n**64n + 2n**12n + 1n)), 2n**65n + 2n**64n + 2n**13n);
-assertEq(BigInt(Number(2n**65n + 2n**64n + 2n**13n)), 2n**65n + 2n**64n + 2n**13n);
-assertEq(BigInt(Number(2n**65n + 2n**64n + 2n**13n + 1n)), 2n**65n + 2n**64n + 2n**13n);
-assertEq(BigInt(Number(2n**65n + 2n**64n + 2n**13n + 2n**5n)), 2n**65n + 2n**64n + 2n**13n);
-assertEq(BigInt(Number(2n**65n + 2n**64n + 2n**13n + 2n**11n)), 2n**65n + 2n**64n + 2n**13n);
-assertEq(BigInt(Number(2n**65n + 2n**64n + 2n**13n + 2n**12n - 1n)), 2n**65n + 2n**64n + 2n**13n);
-assertEq(BigInt(Number(2n**65n + 2n**64n + 2n**13n + 2n**12n)), 2n**65n + 2n**64n + 2n**14n);
-assertEq(BigInt(Number(2n**65n + 2n**64n + 2n**13n + 2n**12n + 1n)), 2n**65n + 2n**64n + 2n**14n);
-
-/**
- * Versions of the testing above with all the high-order bits massively bumped
- * upward to test that super-low bits, not just bits in high digits, are
- * properly accounted for in rounding.
- */
-
-// The tests below that aren't subtracting bits will have no bits in the
-// ultimate significand from the most-significant digit (because of the implicit
-// one being excluded).
-assertEq(BigInt(Number(2n**940n - 2n**887n + 1n)), 2n**940n - 2n**887n);
-assertEq(BigInt(Number(2n**940n - 2n**887n + 2n**886n - 1n)), 2n**940n - 2n**887n);
-assertEq(BigInt(Number(2n**940n - 2n**887n + 2n**886n)), 2n**940n);
-assertEq(BigInt(Number(2n**940n - 2n**886n)), 2n**940n);
-assertEq(BigInt(Number(2n**940n)), 2n**940n);
-assertEq(BigInt(Number(2n**940n + 1n)), 2n**940n);
-assertEq(BigInt(Number(2n**940n + 2n**880n)), 2n**940n);
-assertEq(BigInt(Number(2n**940n + 2n**885n)), 2n**940n);
-assertEq(BigInt(Number(2n**940n + 2n**887n)), 2n**940n);
-assertEq(BigInt(Number(2n**940n + 2n**887n + 1n)), 2n**940n + 2n**888n);
-assertEq(BigInt(Number(2n**940n + 2n**888n)), 2n**940n + 2n**888n);
-assertEq(BigInt(Number(2n**940n + 2n**888n + 1n)), 2n**940n + 2n**888n);
-assertEq(BigInt(Number(2n**940n + 2n**888n + 2n**5n)), 2n**940n + 2n**888n);
-assertEq(BigInt(Number(2n**940n + 2n**888n + 2n**12n)), 2n**940n + 2n**888n);
-assertEq(BigInt(Number(2n**940n + 2n**888n + 2n**887n - 1n)), 2n**940n + 2n**888n);
-assertEq(BigInt(Number(2n**940n + 2n**888n + 2n**887n)), 2n**940n + 2n**889n);
-assertEq(BigInt(Number(2n**940n + 2n**888n + 2n**887n + 1n)), 2n**940n + 2n**889n);
-
-// These tests *will* have a bit from the most-significant digit in the ultimate
-// significand.
-assertEq(BigInt(Number(2n**941n - 2n**888n)), 2n**941n - 2n**888n);
-assertEq(BigInt(Number(2n**941n - 2n**888n + 2n**887n - 1n)), 2n**941n - 2n**888n);
-assertEq(BigInt(Number(2n**941n - 2n**888n + 2n**887n)), 2n**941n);
-assertEq(BigInt(Number(2n**941n - 2n**887n)), 2n**941n);
-assertEq(BigInt(Number(2n**941n)), 2n**941n);
-assertEq(BigInt(Number(2n**941n + 1n)), 2n**941n);
-assertEq(BigInt(Number(2n**941n + 2n**881n)), 2n**941n);
-assertEq(BigInt(Number(2n**941n + 2n**886n)), 2n**941n);
-assertEq(BigInt(Number(2n**941n + 2n**888n)), 2n**941n);
-assertEq(BigInt(Number(2n**941n + 2n**888n + 1n)), 2n**941n + 2n**889n);
-assertEq(BigInt(Number(2n**941n + 2n**889n)), 2n**941n + 2n**889n);
-assertEq(BigInt(Number(2n**941n + 2n**889n + 1n)), 2n**941n + 2n**889n);
-assertEq(BigInt(Number(2n**941n + 2n**889n + 2n**5n)), 2n**941n + 2n**889n);
-assertEq(BigInt(Number(2n**941n + 2n**889n + 2n**12n)), 2n**941n + 2n**889n);
-assertEq(BigInt(Number(2n**941n + 2n**889n + 2n**888n - 1n)), 2n**941n + 2n**889n);
-assertEq(BigInt(Number(2n**941n + 2n**889n + 2n**888n)), 2n**941n + 2n**890n);
-assertEq(BigInt(Number(2n**941n + 2n**889n + 2n**888n + 1n)), 2n**941n + 2n**890n);
-
-// ...and in these tests, the contributed bit from the most-significant digit
-// is additionally nonzero.
-assertEq(BigInt(Number(2n**941n + 2n**940n)), 2n**941n + 2n**940n);
-assertEq(BigInt(Number(2n**941n + 2n**940n + 1n)), 2n**941n + 2n**940n);
-assertEq(BigInt(Number(2n**941n + 2n**940n + 2n**881n)), 2n**941n + 2n**940n);
-assertEq(BigInt(Number(2n**941n + 2n**940n + 2n**886n)), 2n**941n + 2n**940n);
-assertEq(BigInt(Number(2n**941n + 2n**940n + 2n**888n)), 2n**941n + 2n**940n);
-assertEq(BigInt(Number(2n**941n + 2n**940n + 2n**888n + 1n)), 2n**941n + 2n**940n + 2n**889n);
-assertEq(BigInt(Number(2n**941n + 2n**940n + 2n**889n)), 2n**941n + 2n**940n + 2n**889n);
-assertEq(BigInt(Number(2n**941n + 2n**940n + 2n**889n + 1n)), 2n**941n + 2n**940n + 2n**889n);
-assertEq(BigInt(Number(2n**941n + 2n**940n + 2n**889n + 2n**5n)), 2n**941n + 2n**940n + 2n**889n);
-assertEq(BigInt(Number(2n**941n + 2n**940n + 2n**889n + 2n**12n)), 2n**941n + 2n**940n + 2n**889n);
-assertEq(BigInt(Number(2n**941n + 2n**940n + 2n**889n + 2n**888n - 1n)), 2n**941n + 2n**940n + 2n**889n);
-assertEq(BigInt(Number(2n**941n + 2n**940n + 2n**889n + 2n**888n)), 2n**941n + 2n**940n + 2n**890n);
-assertEq(BigInt(Number(2n**941n + 2n**940n + 2n**889n + 2n**888n + 1n)), 2n**941n + 2n**940n + 2n**890n);
-
-if (typeof reportCompare === "function")
-  reportCompare(true, true);
--- a/js/src/vm/BigIntType.cpp
+++ b/js/src/vm/BigIntType.cpp
@@ -2721,19 +2721,18 @@ double BigInt::numberValue(BigInt* x) {
   constexpr uint8_t ExponentShift = Double::kExponentShift;
   constexpr uint8_t SignificandWidth = Double::kSignificandWidth;
   constexpr unsigned ExponentBias = Double::kExponentBias;
   constexpr uint8_t SignShift = Double::kExponentWidth + SignificandWidth;
 
   size_t length = x->digitLength();
   MOZ_ASSERT(length != 0);
 
-  // Fast path for the likely-common case of up to a uint64_t of magnitude not
-  // exceeding integral precision in IEEE-754.  (Note that we *depend* on this
-  // optimization being performed further down.)
+  // Fast path for the likely-common case of up to a uint64_t of magnitude
+  // that doesn't exceed integral precision in IEEE-754.
   if (length <= 64 / DigitBits) {
     uint64_t magnitude = x->digit(0);
     if (DigitBits == 32 && length > 1) {
       magnitude |= uint64_t(x->digit(1)) << 32;
     }
     const uint64_t MaxIntegralPrecisionDouble = uint64_t(1)
                                                 << (SignificandWidth + 1);
     if (magnitude <= MaxIntegralPrecisionDouble) {
@@ -2756,175 +2755,72 @@ double BigInt::numberValue(BigInt* x) {
   // Otherwise munge the most significant bits of the number into proper
   // position in an IEEE-754 double and go to town.
 
   // Omit the most significant bit: the IEEE-754 format includes this bit
   // implicitly for all double-precision integers.
   const uint8_t msdIgnoredBits = msdLeadingZeroes + 1;
   const uint8_t msdIncludedBits = DigitBits - msdIgnoredBits;
 
-  // We compute the final mantissa of the result, shifted upward to the top of
-  // the `uint64_t` space -- plus an extra bit to detect potential rounding.
-  constexpr uint8_t BitsNeededForShiftedMantissa = SignificandWidth + 1;
-
-  // Shift `msd`'s contributed bits upward to remove high-order zeroes and the
-  // highest set bit (which is implicit in IEEE-754 integral values so must be
-  // removed) and to add low-order zeroes.  (Lower-order garbage bits are
-  // discarded when `shiftedMantissa` is converted to a real mantissa.)
+  uint8_t bitsFilled = msdIncludedBits;
+
+  // Shift `msd`'s contributed bits upward to remove high-order zeroes and
+  // the highest set bit (which is implicit in IEEE-754 integral values so
+  // must be removed) and to add low-order zeroes.
   uint64_t shiftedMantissa =
       msdIncludedBits == 0 ? 0 : uint64_t(msd) << (64 - msdIncludedBits);
 
-  // If the extra bit is set, correctly rounding the result may require
-  // examining all lower-order bits.  Also compute 1) the index of the Digit
-  // storing the extra bit, and 2) whether bits beneath the extra bit in that
-  // Digit are nonzero so we can round if needed.
-  size_t digitContainingExtraBit;
-  Digit bitsBeneathExtraBitInDigitContainingExtraBit;
-
-  // Add shifted bits to `shiftedMantissa` until we have a complete mantissa and
-  // an extra bit.
-  if (msdIncludedBits >= BitsNeededForShiftedMantissa) {
-    //       DigitBits=64 (necessarily for msdIncludedBits ≥ SignificandWidth+1;
-    //            |        C++ compiler range analysis ought eliminate this
-    //            |        check on 32-bit)
-    //   _________|__________
-    //  /                    \
-    //        msdIncludedBits
-    //      ________|________
-    //     /                 \
-    // [001···················|
-    //  \_/\_____________/\__/
-    //   |            |    |
-    // msdIgnoredBits |   bits below the extra bit (may be no bits)
-    //      BitsNeededForShiftedMantissa=SignificandWidth+1
-    digitContainingExtraBit = length - 1;
-
-    const uint8_t countOfBitsInDigitBelowExtraBit =
-        DigitBits - BitsNeededForShiftedMantissa - msdIgnoredBits;
-    bitsBeneathExtraBitInDigitContainingExtraBit =
-        msd & ((Digit(1) << CountOfBitsInDigitBelowExtraBit) - 1);
-  } else {
+  // Add in bits from the next one or two digits if `msd` didn't contain all
+  // bits necessary to define the result.  (The extra bit allows us to
+  // properly round an inexact overall result.)  Any lower bits that are
+  // uselessly set will be shifted away when `shiftedMantissa` is converted to
+  // a real mantissa.
+  if (bitsFilled < SignificandWidth + 1) {
     MOZ_ASSERT(length >= 2,
                "single-Digit numbers with this few bits should have been "
                "handled by the fast-path above");
 
     Digit second = x->digit(length - 2);
-    if (DigitBits == 64) {
-      shiftedMantissa |= second >> msdIncludedBits;
-
-      digitContainingExtraBit = length - 2;
-
-      //  msdIncludedBits + DigitBits
-      //      ________|_________
-      //     /                  \
-      //             DigitBits=64
-      // msdIncludedBits    |
-      //      __|___   _____|___
-      //     /      \ /         \
-      // [001········|···········|
-      //  \_/\_____________/\___/
-      //   |            |     |
-      // msdIgnoredBits | bits below the extra bit (always more than one)
-      //                |
-      //      BitsNeededForShiftedMantissa=SignificandWidth+1
-      const uint8_t countOfBitsInSecondDigitBelowExtraBit =
-          (msdIncludedBits + DigitBits) - BitsNeededForShiftedMantissa;
-
-      bitsBeneathExtraBitInDigitContainingExtraBit =
-          second << (DigitBits - CountOfBitsInSecondDigitBelowExtraBit);
-    } else {
+    if (DigitBits == 32) {
       shiftedMantissa |= uint64_t(second) << msdIgnoredBits;
-
-      if (msdIncludedBits + DigitBits >= BitsNeededForShiftedMantissa) {
-        digitContainingExtraBit = length - 2;
-
-        //  msdIncludedBits + DigitBits
-        //      ______|________
-        //     /               \
-        //             DigitBits=32
-        // msdIncludedBits |
-        //      _|_   _____|___
-        //     /   \ /         \
-        // [001·····|···········|
-        //     \___________/\__/
-        //          |        |
-        //          |      bits below the extra bit (may be no bits)
-        //      BitsNeededForShiftedMantissa=SignificandWidth+1
-        const uint8_t countOfBitsInSecondDigitBelowExtraBit =
-            (msdIncludedBits + DigitBits) - BitsNeededForShiftedMantissa;
-
-        bitsBeneathExtraBitInDigitContainingExtraBit =
-            second & ((Digit(1) << CountOfBitsInSecondDigitBelowExtraBit) - 1);
-      } else {
-        MOZ_ASSERT(length >= 3,
-                   "we must have at least three digits here, because "
-                   "`msdIncludedBits + 32 < BitsNeededForShiftedMantissa` "
-                   "guarantees `x < 2**53` -- and therefore the "
-                   "MaxIntegralPrecisionDouble optimization above will have "
-                   "handled two-digit cases");
-
+      bitsFilled += DigitBits;
+
+      // Add in bits from another digit, if any, if we still have unfilled
+      // significand bits.
+      if (bitsFilled < SignificandWidth + 1 && length >= 3) {
         Digit third = x->digit(length - 3);
         shiftedMantissa |= uint64_t(third) >> msdIncludedBits;
-
-        digitContainingExtraBit = length - 3;
-
-        //    msdIncludedBits + DigitBits + DigitBits
-        //      ____________|______________
-        //     /                           \
-        //             DigitBits=32
-        // msdIncludedBits |     DigitBits=32
-        //      _|_   _____|___   ____|____
-        //     /   \ /         \ /         \
-        // [001·····|···········|···········|
-        //     \____________________/\_____/
-        //               |               |
-        //               |      bits below the extra bit
-        //      BitsNeededForShiftedMantissa=SignificandWidth+1
-        static_assert(2 * DigitBits > BitsNeededForShiftedMantissa,
-                      "two 32-bit digits should more than fill a mantissa");
-        const uint8_t countOfBitsInThirdDigitBelowExtraBit =
-            msdIncludedBits + 2 * DigitBits - BitsNeededForShiftedMantissa;
-
-        // Shift out the mantissa bits and the extra bit.
-        bitsBeneathExtraBitInDigitContainingExtraBit =
-            third << (DigitBits - CountOfBitsInThirdDigitBelowExtraBit);
+        // The second and third 32-bit digits contributed 64 bits total, filling
+        // well beyond the mantissa.
+        bitsFilled = 64;
       }
+    } else {
+      shiftedMantissa |= second >> msdIncludedBits;
+      // A full 64-bit digit's worth of bits (some from the most significant
+      // digit, the rest from the next) fills well beyond the mantissa.
+      bitsFilled = 64;
     }
   }
 
-  constexpr uint64_t LeastSignificantBit = uint64_t(1)
-                                           << (64 - SignificandWidth);
-  constexpr uint64_t ExtraBit = LeastSignificantBit >> 1;
-
-  // The extra bit must be set for rounding to change the mantissa.
-  if ((shiftedMantissa & ExtraBit) != 0) {
-    bool shouldRoundUp;
-    if (shiftedMantissa & LeastSignificantBit) {
-      // If the lowest mantissa bit is set, it doesn't matter what lower bits
-      // are: nearest-even rounds up regardless.
-      shouldRoundUp = true;
-    } else {
-      // If the lowest mantissa bit is unset, *all* lower bits are relevant.
-      // All-zero bits below the extra bit situates `x` halfway between two
-      // values, and the nearest *even* value lies downward.  But if any bit
-      // below the extra bit is set, `x` is closer to the rounded-up value.
-      shouldRoundUp = bitsBeneathExtraBitInDigitContainingExtraBit != 0;
-      if (!shouldRoundUp) {
-        while (digitContainingExtraBit-- > 0) {
-          if (x->digit(digitContainingExtraBit) != 0) {
-            shouldRoundUp = true;
-            break;
-          }
-        }
-      }
-    }
-
-    if (shouldRoundUp) {
-      // Add one to the significand bits.  If they overflow, the exponent must
-      // also be increased.  If *that* overflows, return the correct infinity.
+  // Round the overall result, if necessary.  (It's possible we don't need to
+  // round -- the number might not have enough bits to round.)
+  if (bitsFilled >= SignificandWidth + 1) {
+    constexpr uint64_t LeastSignificantBit = uint64_t(1)
+                                             << (64 - SignificandWidth);
+    constexpr uint64_t ExtraBit = LeastSignificantBit >> 1;
+
+    // When the first bit outside the significand is set, the overall value
+    // is rounded: downward (i.e. no change to the bits) if the least
+    // significant bit in the significand is zero, upward if it instead is
+    // one.
+    if ((shiftedMantissa & ExtraBit) &&
+        (shiftedMantissa & LeastSignificantBit)) {
+      // We're rounding upward: add to the significand bits.  If they
+      // overflow, the exponent must also be increased.  If *that*
+      // overflows, return the appropriate infinity.
       uint64_t before = shiftedMantissa;
       shiftedMantissa += ExtraBit;
       if (shiftedMantissa < before) {
         exponent++;
         if (exponent > ExponentBias) {
           return x->isNegative() ? NegativeInfinity<double>()
                                  : PositiveInfinity<double>();
         }