fix parsing of large hex float literals

closes #2083
This commit is contained in:
Andrew Kelley
2019-03-21 16:17:29 -04:00
parent b5cc92f163
commit af509c68b0
2 changed files with 82 additions and 10 deletions

View File

@@ -326,7 +326,7 @@ static void end_float_token(Tokenize *t) {
return;
}
// A SoftFloat-3d float128 is represented internally as a standard
// A SoftFloat-3e float128 is represented internally as a standard
// quad-precision float with 15bit exponent and 113bit fractional.
union { uint64_t repr[2]; float128_t actual; } f_bits;
@@ -345,29 +345,37 @@ static void end_float_token(Tokenize *t) {
return;
}
uint64_t sig_bits[2] = {0, 0};
bigint_write_twos_complement(&t->significand, (uint8_t*) sig_bits, 128, false);
const uint64_t shift = 112 - significand_magnitude_in_bin;
const uint64_t exp_shift = 48;
// Mask the sign bit to 0 since always non-negative lex
const uint64_t exp_mask = 0xffffull << exp_shift;
const int shift = 112 - significand_magnitude_in_bin;
// must be special-cased to avoid undefined behavior on shift == 64
if (shift == 128) {
uint64_t sig_bits[2] = {0, 0};
bigint_write_twos_complement(&t->significand, (uint8_t*) sig_bits, 128, false);
f_bits.repr[0] = 0;
f_bits.repr[1] = sig_bits[0];
} else if (shift == 0) {
f_bits.repr[0] = sig_bits[0];
f_bits.repr[1] = sig_bits[1];
bigint_write_twos_complement(&t->significand, (uint8_t*) f_bits.repr, 128, false);
} else if (shift >= 64) {
uint64_t sig_bits[2] = {0, 0};
bigint_write_twos_complement(&t->significand, (uint8_t*) sig_bits, 128, false);
f_bits.repr[0] = 0;
f_bits.repr[1] = sig_bits[0] << (shift - 64);
} else if (shift < 0) {
BigInt shift_bigint;
bigint_init_unsigned(&shift_bigint, -shift);
BigInt shifted_significand;
bigint_shr(&shifted_significand, &t->significand, &shift_bigint);
bigint_write_twos_complement(&shifted_significand, (uint8_t*) f_bits.repr, 128, false);
} else {
uint64_t sig_bits[2] = {0, 0};
bigint_write_twos_complement(&t->significand, (uint8_t*) sig_bits, 128, false);
f_bits.repr[0] = sig_bits[0] << shift;
f_bits.repr[1] = (sig_bits[1] << shift) | (sig_bits[0] >> (64 - shift));
}
const uint64_t exp_shift = 48;
// Mask the sign bit to 0 since always non-negative lex
const uint64_t exp_mask = 0xffffull << exp_shift;
f_bits.repr[1] &= ~exp_mask;
f_bits.repr[1] |= (uint64_t)(t->exponent_in_bin_or_dec + 16383) << exp_shift;
}