From 4a35d7eeebec3f345e2482bc189f07c19dcf6f8b Mon Sep 17 00:00:00 2001 From: Marc Tiehuis Date: Thu, 28 Jun 2018 20:12:03 +1200 Subject: [PATCH] Correct hex-float parsing Unblocks #495. --- src/tokenizer.cpp | 11 +++++++++-- test/cases/math.zig | 8 ++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 2950b4eb49..f7f41af8a6 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -357,12 +357,19 @@ static void end_float_token(Tokenize *t) { // Mask the sign bit to 0 since always non-negative lex const uint64_t exp_mask = 0xffffull << exp_shift; - if (shift >= 64) { + // must be special-cased to avoid undefined behavior on shift == 64 + if (shift == 128) { + 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]; + } else if (shift >= 64) { f_bits.repr[0] = 0; f_bits.repr[1] = sig_bits[0] << (shift - 64); } else { f_bits.repr[0] = sig_bits[0] << shift; - f_bits.repr[1] = ((sig_bits[1] << shift) | (sig_bits[0] >> (64 - shift))); + f_bits.repr[1] = (sig_bits[1] << shift) | (sig_bits[0] >> (64 - shift)); } f_bits.repr[1] &= ~exp_mask; diff --git a/test/cases/math.zig b/test/cases/math.zig index 5931c5de31..195ada15dd 100644 --- a/test/cases/math.zig +++ b/test/cases/math.zig @@ -296,6 +296,14 @@ test "quad hex float literal parsing in range" { const d = 0x1.edcbff8ad76ab5bf46463233214fp-435; } +test "quad hex float literal parsing accurate" { + const a: f128 = 0x1.1111222233334444555566667777p+0; + + // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing. + const expected: u128 = 0x3fff1111222233334444555566667777; + assert(@bitCast(u128, a) == expected); +} + test "hex float literal within range" { const a = 0x1.0p16383; const b = 0x0.1p16387;