authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2019-03-22 17:11:57+13:00
committergravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2019-03-22 17:11:57+13:00
loge3b70fe4ba5c9b5139055e2ffdde526414c86538
tree40ae97b310f44c8507421db8e95ab51b2c026134
parentd04a1456df996aa51dd5eb5857528ed4a237ca13

Simplify hex-float parsing code


2 files changed, 49 insertions(+), 50 deletions(-)

src/tokenizer.cpp+34-47
......@@ -327,61 +327,48 @@ static void end_float_token(Tokenize *t) {
327327 }
328328
329329 // A SoftFloat-3e float128 is represented internally as a standard
330 // quad-precision float with 15bit exponent and 113bit fractional.
330 // quad-precision float with 15bit exponent and 112bit fractional.
331331 union { uint64_t repr[2]; float128_t actual; } f_bits;
332332
333333 if (bigint_cmp_zero(&t->significand) == CmpEQ) {
334334 f_bits.repr[0] = 0;
335335 f_bits.repr[1] = 0;
336336 } else {
337 // normalize the significand
338 if (t->radix == 10) {
339 zig_panic("TODO: decimal floats");
340 } else {
341 int significand_magnitude_in_bin = 127 - bigint_clz(&t->significand, 128);
342 t->exponent_in_bin_or_dec += significand_magnitude_in_bin;
343 if (!(-16382 <= t->exponent_in_bin_or_dec && t->exponent_in_bin_or_dec <= 16383)) {
344 t->cur_tok->data.float_lit.overflow = true;
345 return;
346 }
347
348 const int shift = 112 - significand_magnitude_in_bin;
349
350 // must be special-cased to avoid undefined behavior on shift == 64
351 if (shift == 128) {
352 uint64_t sig_bits[2] = {0, 0};
353 bigint_write_twos_complement(&t->significand, (uint8_t*) sig_bits, 128, false);
354 f_bits.repr[0] = 0;
355 f_bits.repr[1] = sig_bits[0];
356 } else if (shift == 0) {
357 bigint_write_twos_complement(&t->significand, (uint8_t*) f_bits.repr, 128, false);
358 } else if (shift >= 64) {
359 uint64_t sig_bits[2] = {0, 0};
360 bigint_write_twos_complement(&t->significand, (uint8_t*) sig_bits, 128, false);
361 f_bits.repr[0] = 0;
362 f_bits.repr[1] = sig_bits[0] << (shift - 64);
363 } else if (shift < 0) {
364 BigInt shift_bigint;
365 bigint_init_unsigned(&shift_bigint, -shift);
366 BigInt shifted_significand;
367 bigint_shr(&shifted_significand, &t->significand, &shift_bigint);
368 if (t->exponent_in_bin_or_dec == -1) {
369 bigint_incr(&shifted_significand);
370 }
371 bigint_write_twos_complement(&shifted_significand, (uint8_t*) f_bits.repr, 128, false);
372 } else {
373 uint64_t sig_bits[2] = {0, 0};
374 bigint_write_twos_complement(&t->significand, (uint8_t*) sig_bits, 128, false);
375 f_bits.repr[0] = sig_bits[0] << shift;
376 f_bits.repr[1] = (sig_bits[1] << shift) | (sig_bits[0] >> (64 - shift));
377 }
337 int significand_magnitude_in_bin = 127 - bigint_clz(&t->significand, 128);
338 t->exponent_in_bin_or_dec += significand_magnitude_in_bin;
339 if (!(-16382 <= t->exponent_in_bin_or_dec && t->exponent_in_bin_or_dec <= 16383)) {
340 t->cur_tok->data.float_lit.overflow = true;
341 return;
342 }
378343
379 const uint64_t exp_shift = 48;
380 // Mask the sign bit to 0 since always non-negative lex
381 const uint64_t exp_mask = 0xffffull << exp_shift;
382 f_bits.repr[1] &= ~exp_mask;
383 f_bits.repr[1] |= (uint64_t)(t->exponent_in_bin_or_dec + 16383) << exp_shift;
344 // Shift bits of significand so they are left-justified at the 112-bit
345 // mark. We truncate excess bits and lose precision. No rounding.
346 //
347 // -16 <= shift <= 112
348 //
349 // NOTE: The loss of precision could be considered a limitation of using
350 // 128-bit floats. In stage2 we should use an arbitrary precision
351 // float/rational type to represent these and avoid this.
352 const int shift = 112 - significand_magnitude_in_bin;
353 bigint_write_twos_complement(&t->significand, (uint8_t*) f_bits.repr, 128, false);
354
355 if (shift >= 64) {
356 f_bits.repr[1] = f_bits.repr[0] << (shift - 64);
357 f_bits.repr[0] = 0;
358 } else if (shift > 0) {
359 f_bits.repr[1] = (f_bits.repr[1] << shift) | (f_bits.repr[0] >> (64 - shift));
360 f_bits.repr[0] = f_bits.repr[0] << shift;
361 } else if (shift < 0) {
362 int positive_shift = -shift;
363 assert(positive_shift <= 16);
364 f_bits.repr[0] = (f_bits.repr[0] >> positive_shift) | (f_bits.repr[1] << (64 - positive_shift));
365 f_bits.repr[1] = f_bits.repr[1] >> positive_shift;
384366 }
367
368 // Lexer separates negative sign from value so this is always non-negative.
369 const uint64_t exp_mask = 0xffffull << 48;
370 f_bits.repr[1] &= ~exp_mask;
371 f_bits.repr[1] |= (uint64_t)(t->exponent_in_bin_or_dec + 16383) << 48;
385372 }
386373
387374 bigfloat_init_128(&t->cur_tok->data.float_lit.bigfloat, f_bits.actual);
test/stage1/behavior/math.zig+15-3
......@@ -308,15 +308,27 @@ test "quad hex float literal parsing accurate" {
308308 const expected: u128 = 0x3fff1111222233334444555566667777;
309309 expect(@bitCast(u128, a) == expected);
310310
311 // non-normalized
312 const b: f128 = 0x11.111222233334444555566667777p-4;
313 expect(@bitCast(u128, b) == expected);
314
311315 const S = struct {
312316 fn doTheTest() void {
313317 {
314 var f1: f128 = 0x1.2eab345678439abcdefea56782346p+5;
315 expect(@bitCast(u128, f1) == 0x40042eab345678439abcdefea5678234);
318 var f: f128 = 0x1.2eab345678439abcdefea56782346p+5;
319 expect(@bitCast(u128, f) == 0x40042eab345678439abcdefea5678234);
316320 }
317321 {
318322 var f: f128 = 0x1.edcb34a235253948765432134674fp-1;
319 expect(@bitCast(u128, f) == 0x3ffeedcb34a235253948765432134675);
323 expect(@bitCast(u128, f) == 0x3ffeedcb34a235253948765432134674);
324 }
325 {
326 var f: f128 = 0x1.353e45674d89abacc3a2ebf3ff4ffp-50;
327 expect(@bitCast(u128, f) == 0x3fcd353e45674d89abacc3a2ebf3ff4f);
328 }
329 {
330 var f: f128 = 0x1.ed8764648369535adf4be3214567fp-9;
331 expect(@bitCast(u128, f) == 0x3ff6ed8764648369535adf4be3214567);
320332 }
321333 const exp2ft = []f64{
322334 0x1.6a09e667f3bcdp-1,