Fix parsing issues on 32-bit hosts

These were mostly bugs with code of the following form:
```
  if uint64Value < (... literal expression ...)
```
Swift's comparison operators allow their left- and right-hand sides to be of
different widths.  This in turn means that the literal expression above
typically gets typechecked by default as a plain `Int` or `UInt` expression.
In a number of cases, this led to truncation on platforms where `Int` is
not 64 bits.

In particular, this seems to fix tests on wasm32.
This commit is contained in:
Tim Kientzle
2025-12-12 07:16:59 -08:00
parent f82cf1ebfb
commit e75a8c03e7
3 changed files with 13 additions and 17 deletions

View File

@@ -450,7 +450,7 @@ fileprivate func hexFloat(
) -> ParseResult {
var i = start + 2 // Skip leading '0x'
let firstDigitOffset = i
let limit = UInt64(1) << 60
var significand: UInt64 = 0
//
@@ -458,10 +458,10 @@ fileprivate func hexFloat(
//
// Accumulate the most significant 64 bits...
while i < input.count && hexdigit(input[i]) < 16 && significand < (1 << 60) {
significand &<<= 4
significand += UInt64(hexdigit(input[i]))
i += 1
while i < input.count && hexdigit(input[i]) < 16 && significand < limit {
significand &<<= 4
significand += UInt64(hexdigit(input[i]))
i += 1
}
// Initialize binary exponent to the number of bits we collected above
@@ -521,7 +521,7 @@ fileprivate func hexFloat(
}
}
// Pack more bits into the accumulator (up to 60)
while i < input.count && hexdigit(input[i]) < 16 && significand < (1 << 60) {
while i < input.count && hexdigit(input[i]) < 16 && significand < limit {
significand &<<= 4
significand += UInt64(hexdigit(input[i]))
i += 1
@@ -631,12 +631,12 @@ fileprivate func hexFloat(
&& (targetSignificand & 1) == 1)) {
// Round up, test for overflow
targetSignificand += 1
if targetSignificand >= (1 << targetFormat.significandBits) {
if targetSignificand >= (UInt64(1) << targetFormat.significandBits) {
// Normal overflowed, need to renormalize
targetSignificand >>= 1
binaryExponent += 1
} else if (binaryExponent < targetFormat.minBinaryExponent
&& targetSignificand >= (1 << (targetFormat.significandBits - 1))) {
&& targetSignificand >= (UInt64(1) << (targetFormat.significandBits - 1))) {
// Subnormal overflowed to normal
binaryExponent += 1
}
@@ -1769,7 +1769,7 @@ fileprivate func slowDecimalToBinary(
count: targetFormat.significandBits,
remainderNonZero: false)
if significand >= (1 &<< targetFormat.significandBits) {
if significand >= (UInt64(1) &<< targetFormat.significandBits) {
significand >>= 1
binaryExponent &+= 1
}
@@ -1865,7 +1865,7 @@ fileprivate func slowDecimalToBinary(
range: quotientRange,
count: targetFormat.significandBits,
remainderNonZero: remainderNonZero)
if significand >= (1 &<< targetFormat.significandBits) {
if significand >= (UInt64(1) &<< targetFormat.significandBits) {
significand >>= 1
binaryExponent &+= 1
}
@@ -1889,7 +1889,7 @@ fileprivate func slowDecimalToBinary(
// exponent. Then we've transitioned from a subnormal to
// a normal, so the extra overflow bit will naturally get
// dropped, we just have to bump the exponent.
if significand >= (1 &<< (targetFormat.significandBits &- 1)) {
if significand >= (UInt64(1) &<< (targetFormat.significandBits &- 1)) {
binaryExponent &+= 1
}
targetSignificand = significand

View File

@@ -7,9 +7,6 @@
// Float16 is only available in watchOS 7.0 or newer
// UNSUPPORTED: OS=watchos
// TODO: Figure out why this test breaks on wasm32
// UNSUPPORTED: CPU=wasm32
// Cannot test with old OS stdlib, because that used libc strtof
// for parsing, which results in incorrect results.
// UNSUPPORTED: use_os_stdlib
@@ -105,7 +102,9 @@ tests.test("NaNs") {
expectRoundTrip(Float16.nan)
expectRoundTrip(-Float16.nan)
expectRoundTrip(Float16(nan:73, signaling:false))
#if !arch(wasm32)
expectRoundTrip(Float16(nan:73, signaling:true))
#endif
expectParse("nan", Float16.nan)
expectParse("NAN", Float16.nan)
expectParse("NaN", Float16.nan)

View File

@@ -5,9 +5,6 @@
// REQUIRES: executable_test
// TODO: Figure out why this test breaks on wasm32
// UNSUPPORTED: CPU=wasm32
// Needed to declare the ABI entry point
// REQUIRES: swift_feature_Extern