libstdc++: Apply modifications to our local copy of Ryu

This performs the following modifications to our local copy of Ryu in
order to make it more readily usable for our std::to_chars
implementation:

  * Remove all #includes
  * Remove copy_special_str routines
  * Adjust the exponent formatting to match printf
  * Remove some functions we're not going to use
  * Add an out-parameter to d2exp_buffered_n for the scientific exponent
  * Store the sign bit inside struct floating_decimal_[32|64]
  * Rename [df]2s_buffered_n and change their return type
  * Make generic_binary_to_decimal take the bit representation in parts

libstdc++-v3/ChangeLog:

	* src/c++17/ryu/common.h, src/c++17/ryu/d2fixed.c,
	src/c++17/ryu/d2fixed_full_table.h, src/c++17/ryu/d2s.c,
	src/c++17/ryu/d2s_intrinsics.h, src/c++17/ryu/f2s.c,
	src/c++17/ryu/f2s_intrinsics.h, src/c++17/ryu/generic_128.c:
	Apply local modifications.
This commit is contained in:
Patrick Palka 2020-12-17 23:11:15 -05:00
parent e3f0eaa282
commit 5033506993
8 changed files with 45 additions and 236 deletions

View file

@ -17,9 +17,6 @@
#ifndef RYU_COMMON_H
#define RYU_COMMON_H
#include <assert.h>
#include <stdint.h>
#include <string.h>
#if defined(_M_IX86) || defined(_M_ARM)
#define RYU_32_BIT_PLATFORM
@ -83,22 +80,6 @@ static inline uint32_t log10Pow5(const int32_t e) {
return (((uint32_t) e) * 732923) >> 20;
}
static inline int copy_special_str(char * const result, const bool sign, const bool exponent, const bool mantissa) {
if (mantissa) {
memcpy(result, "NaN", 3);
return 3;
}
if (sign) {
result[0] = '-';
}
if (exponent) {
memcpy(result + sign, "Infinity", 8);
return sign + 8;
}
memcpy(result + sign, "0E0", 3);
return sign + 3;
}
static inline uint32_t float_to_bits(const float f) {
uint32_t bits = 0;
memcpy(&bits, &f, sizeof(float));

View file

@ -23,23 +23,11 @@
//
// -DRYU_AVOID_UINT128 Avoid using uint128_t. Slower, depending on your compiler.
#include "ryu/ryu.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifdef RYU_DEBUG
#include <inttypes.h>
#include <stdio.h>
#endif
#include "ryu/common.h"
#include "ryu/digit_table.h"
#include "ryu/d2fixed_full_table.h"
#include "ryu/d2s_intrinsics.h"
#define DOUBLE_MANTISSA_BITS 52
#define DOUBLE_EXPONENT_BITS 11
@ -328,33 +316,6 @@ static inline uint32_t lengthForIndex(const uint32_t idx) {
return (log10Pow2(16 * (int32_t) idx) + 1 + 16 + 8) / 9;
}
static inline int copy_special_str_printf(char* const result, const bool sign, const uint64_t mantissa) {
#if defined(_MSC_VER)
// TODO: Check that -nan is expected output on Windows.
if (sign) {
result[0] = '-';
}
if (mantissa) {
if (mantissa < (1ull << (DOUBLE_MANTISSA_BITS - 1))) {
memcpy(result + sign, "nan(snan)", 9);
return sign + 9;
}
memcpy(result + sign, "nan", 3);
return sign + 3;
}
#else
if (mantissa) {
memcpy(result, "nan", 3);
return 3;
}
if (sign) {
result[0] = '-';
}
#endif
memcpy(result + sign, "Infinity", 8);
return sign + 8;
}
int d2fixed_buffered_n(double d, uint32_t precision, char* result) {
const uint64_t bits = double_to_bits(d);
#ifdef RYU_DEBUG
@ -372,20 +333,10 @@ int d2fixed_buffered_n(double d, uint32_t precision, char* result) {
// Case distinction; exit early for the easy cases.
if (ieeeExponent == ((1u << DOUBLE_EXPONENT_BITS) - 1u)) {
return copy_special_str_printf(result, ieeeSign, ieeeMantissa);
__builtin_abort();
}
if (ieeeExponent == 0 && ieeeMantissa == 0) {
int index = 0;
if (ieeeSign) {
result[index++] = '-';
}
result[index++] = '0';
if (precision > 0) {
result[index++] = '.';
memset(result + index, '0', precision);
index += precision;
}
return index;
__builtin_abort();
}
int32_t e2;
@ -549,21 +500,9 @@ int d2fixed_buffered_n(double d, uint32_t precision, char* result) {
return index;
}
void d2fixed_buffered(double d, uint32_t precision, char* result) {
const int len = d2fixed_buffered_n(d, precision, result);
result[len] = '\0';
}
char* d2fixed(double d, uint32_t precision) {
char* const buffer = (char*)malloc(2000);
const int index = d2fixed_buffered_n(d, precision, buffer);
buffer[index] = '\0';
return buffer;
}
int d2exp_buffered_n(double d, uint32_t precision, char* result) {
int d2exp_buffered_n(double d, uint32_t precision, char* result, int* exp_out) {
const uint64_t bits = double_to_bits(d);
#ifdef RYU_DEBUG
printf("IN=");
@ -580,22 +519,10 @@ int d2exp_buffered_n(double d, uint32_t precision, char* result) {
// Case distinction; exit early for the easy cases.
if (ieeeExponent == ((1u << DOUBLE_EXPONENT_BITS) - 1u)) {
return copy_special_str_printf(result, ieeeSign, ieeeMantissa);
__builtin_abort();
}
if (ieeeExponent == 0 && ieeeMantissa == 0) {
int index = 0;
if (ieeeSign) {
result[index++] = '-';
}
result[index++] = '0';
if (precision > 0) {
result[index++] = '.';
memset(result + index, '0', precision);
index += precision;
}
memcpy(result + index, "e+00", 4);
index += 4;
return index;
__builtin_abort();
}
int32_t e2;
@ -785,6 +712,9 @@ int d2exp_buffered_n(double d, uint32_t precision, char* result) {
}
}
}
if (exp_out) {
*exp_out = exp;
}
result[index++] = 'e';
if (exp < 0) {
result[index++] = '-';
@ -805,15 +735,3 @@ int d2exp_buffered_n(double d, uint32_t precision, char* result) {
return index;
}
void d2exp_buffered(double d, uint32_t precision, char* result) {
const int len = d2exp_buffered_n(d, precision, result);
result[len] = '\0';
}
char* d2exp(double d, uint32_t precision) {
char* const buffer = (char*)malloc(2000);
const int index = d2exp_buffered_n(d, precision, buffer);
buffer[index] = '\0';
return buffer;
}

View file

@ -17,7 +17,6 @@
#ifndef RYU_D2FIXED_FULL_TABLE_H
#define RYU_D2FIXED_FULL_TABLE_H
#include <stdint.h>
#define TABLE_SIZE 64

View file

@ -27,28 +27,15 @@
// size by about 10x (only one case, and only double) at the cost of some
// performance. Currently requires MSVC intrinsics.
#include "ryu/ryu.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifdef RYU_DEBUG
#include <inttypes.h>
#include <stdio.h>
#endif
#include "ryu/common.h"
#include "ryu/digit_table.h"
#include "ryu/d2s_intrinsics.h"
// Include either the small or the full lookup tables depending on the mode.
#if defined(RYU_OPTIMIZE_SIZE)
#include "ryu/d2s_small_table.h"
#else
#include "ryu/d2s_full_table.h"
#endif
#define DOUBLE_MANTISSA_BITS 52
@ -86,9 +73,10 @@ typedef struct floating_decimal_64 {
// Decimal exponent's range is -324 to 308
// inclusive, and can fit in a short if needed.
int32_t exponent;
bool sign;
} floating_decimal_64;
static inline floating_decimal_64 d2d(const uint64_t ieeeMantissa, const uint32_t ieeeExponent) {
static inline floating_decimal_64 d2d(const uint64_t ieeeMantissa, const uint32_t ieeeExponent, const bool ieeeSign) {
int32_t e2;
uint64_t m2;
if (ieeeExponent == 0) {
@ -308,13 +296,14 @@ static inline floating_decimal_64 d2d(const uint64_t ieeeMantissa, const uint32_
floating_decimal_64 fd;
fd.exponent = exp;
fd.mantissa = output;
fd.sign = ieeeSign;
return fd;
}
static inline int to_chars(const floating_decimal_64 v, const bool sign, char* const result) {
static inline int to_chars(const floating_decimal_64 v, char* const result) {
// Step 5: Print the decimal representation.
int index = 0;
if (sign) {
if (v.sign) {
result[index++] = '-';
}
@ -397,29 +386,28 @@ static inline int to_chars(const floating_decimal_64 v, const bool sign, char* c
}
// Print the exponent.
result[index++] = 'E';
result[index++] = 'e';
int32_t exp = v.exponent + (int32_t) olength - 1;
if (exp < 0) {
result[index++] = '-';
exp = -exp;
}
} else
result[index++] = '+';
if (exp >= 100) {
const int32_t c = exp % 10;
memcpy(result + index, DIGIT_TABLE + 2 * (exp / 10), 2);
result[index + 2] = (char) ('0' + c);
index += 3;
} else if (exp >= 10) {
} else {
memcpy(result + index, DIGIT_TABLE + 2 * exp, 2);
index += 2;
} else {
result[index++] = (char) ('0' + exp);
}
return index;
}
static inline bool d2d_small_int(const uint64_t ieeeMantissa, const uint32_t ieeeExponent,
static inline bool d2d_small_int(const uint64_t ieeeMantissa, const uint32_t ieeeExponent, const bool ieeeSign,
floating_decimal_64* const v) {
const uint64_t m2 = (1ull << DOUBLE_MANTISSA_BITS) | ieeeMantissa;
const int32_t e2 = (int32_t) ieeeExponent - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS;
@ -448,10 +436,11 @@ static inline bool d2d_small_int(const uint64_t ieeeMantissa, const uint32_t iee
// Note: since 2^53 < 10^16, there is no need to adjust decimalLength17().
v->mantissa = m2 >> -e2;
v->exponent = 0;
v->sign = ieeeSign;
return true;
}
int d2s_buffered_n(double f, char* result) {
floating_decimal_64 floating_to_fd64(double f) {
// Step 1: Decode the floating-point number, and unify normalized and subnormal cases.
const uint64_t bits = double_to_bits(f);
@ -469,11 +458,11 @@ int d2s_buffered_n(double f, char* result) {
const uint32_t ieeeExponent = (uint32_t) ((bits >> DOUBLE_MANTISSA_BITS) & ((1u << DOUBLE_EXPONENT_BITS) - 1));
// Case distinction; exit early for the easy cases.
if (ieeeExponent == ((1u << DOUBLE_EXPONENT_BITS) - 1u) || (ieeeExponent == 0 && ieeeMantissa == 0)) {
return copy_special_str(result, ieeeSign, ieeeExponent, ieeeMantissa);
__builtin_abort();
}
floating_decimal_64 v;
const bool isSmallInt = d2d_small_int(ieeeMantissa, ieeeExponent, &v);
const bool isSmallInt = d2d_small_int(ieeeMantissa, ieeeExponent, ieeeSign, &v);
if (isSmallInt) {
// For small integers in the range [1, 2^53), v.mantissa might contain trailing (decimal) zeros.
// For scientific notation we need to move these zeros into the exponent.
@ -489,21 +478,8 @@ int d2s_buffered_n(double f, char* result) {
++v.exponent;
}
} else {
v = d2d(ieeeMantissa, ieeeExponent);
v = d2d(ieeeMantissa, ieeeExponent, ieeeSign);
}
return to_chars(v, ieeeSign, result);
}
void d2s_buffered(double f, char* result) {
const int index = d2s_buffered_n(f, result);
// Terminate the string.
result[index] = '\0';
}
char* d2s(double f) {
char* const result = (char*) malloc(25);
d2s_buffered(f, result);
return result;
return v;
}

View file

@ -17,11 +17,8 @@
#ifndef RYU_D2S_INTRINSICS_H
#define RYU_D2S_INTRINSICS_H
#include <assert.h>
#include <stdint.h>
// Defines RYU_32_BIT_PLATFORM if applicable.
#include "ryu/common.h"
// ABSL avoids uint128_t on Win32 even if __SIZEOF_INT128__ is defined.
// Let's do the same for now.
@ -37,7 +34,6 @@ typedef __uint128_t uint128_t;
#if defined(HAS_64_BIT_INTRINSICS)
#include <intrin.h>
static inline uint64_t umul128(const uint64_t a, const uint64_t b, uint64_t* const productHi) {
return _umul128(a, b, productHi);

View file

@ -18,22 +18,11 @@
// Runtime compiler options:
// -DRYU_DEBUG Generate verbose debugging output to stdout.
#include "ryu/ryu.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#ifdef RYU_DEBUG
#include <stdio.h>
#endif
#include "ryu/common.h"
#include "ryu/f2s_intrinsics.h"
#include "ryu/digit_table.h"
#define FLOAT_MANTISSA_BITS 23
#define FLOAT_EXPONENT_BITS 8
@ -45,9 +34,10 @@ typedef struct floating_decimal_32 {
// Decimal exponent's range is -45 to 38
// inclusive, and can fit in a short if needed.
int32_t exponent;
bool sign;
} floating_decimal_32;
static inline floating_decimal_32 f2d(const uint32_t ieeeMantissa, const uint32_t ieeeExponent) {
static inline floating_decimal_32 f2d(const uint32_t ieeeMantissa, const uint32_t ieeeExponent, const bool ieeeSign) {
int32_t e2;
uint32_t m2;
if (ieeeExponent == 0) {
@ -224,13 +214,14 @@ static inline floating_decimal_32 f2d(const uint32_t ieeeMantissa, const uint32_
floating_decimal_32 fd;
fd.exponent = exp;
fd.mantissa = output;
fd.sign = ieeeSign;
return fd;
}
static inline int to_chars(const floating_decimal_32 v, const bool sign, char* const result) {
static inline int to_chars(const floating_decimal_32 v, char* const result) {
// Step 5: Print the decimal representation.
int index = 0;
if (sign) {
if (v.sign) {
result[index++] = '-';
}
@ -288,24 +279,22 @@ static inline int to_chars(const floating_decimal_32 v, const bool sign, char* c
}
// Print the exponent.
result[index++] = 'E';
result[index++] = 'e';
int32_t exp = v.exponent + (int32_t) olength - 1;
if (exp < 0) {
result[index++] = '-';
exp = -exp;
} else {
result[index++] = '+';
}
if (exp >= 10) {
memcpy(result + index, DIGIT_TABLE + 2 * exp, 2);
index += 2;
} else {
result[index++] = (char) ('0' + exp);
}
memcpy(result + index, DIGIT_TABLE + 2 * exp, 2);
index += 2;
return index;
}
int f2s_buffered_n(float f, char* result) {
floating_decimal_32 floating_to_fd32(float f) {
// Step 1: Decode the floating-point number, and unify normalized and subnormal cases.
const uint32_t bits = float_to_bits(f);
@ -324,22 +313,9 @@ int f2s_buffered_n(float f, char* result) {
// Case distinction; exit early for the easy cases.
if (ieeeExponent == ((1u << FLOAT_EXPONENT_BITS) - 1u) || (ieeeExponent == 0 && ieeeMantissa == 0)) {
return copy_special_str(result, ieeeSign, ieeeExponent, ieeeMantissa);
__builtin_abort();
}
const floating_decimal_32 v = f2d(ieeeMantissa, ieeeExponent);
return to_chars(v, ieeeSign, result);
}
void f2s_buffered(float f, char* result) {
const int index = f2s_buffered_n(f, result);
// Terminate the string.
result[index] = '\0';
}
char* f2s(float f) {
char* const result = (char*) malloc(16);
f2s_buffered(f, result);
return result;
const floating_decimal_32 v = f2d(ieeeMantissa, ieeeExponent, ieeeSign);
return v;
}

View file

@ -18,18 +18,14 @@
#define RYU_F2S_INTRINSICS_H
// Defines RYU_32_BIT_PLATFORM if applicable.
#include "ryu/common.h"
#if defined(RYU_FLOAT_FULL_TABLE)
#include "ryu/f2s_full_table.h"
#else
#if defined(RYU_OPTIMIZE_SIZE)
#include "ryu/d2s_small_table.h"
#else
#include "ryu/d2s_full_table.h"
#endif
#define FLOAT_POW5_INV_BITCOUNT (DOUBLE_POW5_INV_BITCOUNT - 64)
#define FLOAT_POW5_BITCOUNT (DOUBLE_POW5_BITCOUNT - 64)

View file

@ -37,42 +37,9 @@ static char* s(uint128_t v) {
#define ONE ((uint128_t) 1)
#define FLOAT_MANTISSA_BITS 23
#define FLOAT_EXPONENT_BITS 8
struct floating_decimal_128 float_to_fd128(float f) {
uint32_t bits = 0;
memcpy(&bits, &f, sizeof(float));
return generic_binary_to_decimal(bits, FLOAT_MANTISSA_BITS, FLOAT_EXPONENT_BITS, false);
}
#define DOUBLE_MANTISSA_BITS 52
#define DOUBLE_EXPONENT_BITS 11
struct floating_decimal_128 double_to_fd128(double d) {
uint64_t bits = 0;
memcpy(&bits, &d, sizeof(double));
return generic_binary_to_decimal(bits, DOUBLE_MANTISSA_BITS, DOUBLE_EXPONENT_BITS, false);
}
#define LONG_DOUBLE_MANTISSA_BITS 64
#define LONG_DOUBLE_EXPONENT_BITS 15
struct floating_decimal_128 long_double_to_fd128(long double d) {
uint128_t bits = 0;
memcpy(&bits, &d, sizeof(long double));
#ifdef RYU_DEBUG
// For some odd reason, this ends up with noise in the top 48 bits. We can
// clear out those bits with the following line; this is not required, the
// conversion routine should ignore those bits, but the debug output can be
// confusing if they aren't 0s.
bits &= (ONE << 80) - 1;
#endif
return generic_binary_to_decimal(bits, LONG_DOUBLE_MANTISSA_BITS, LONG_DOUBLE_EXPONENT_BITS, true);
}
struct floating_decimal_128 generic_binary_to_decimal(
const uint128_t bits, const uint32_t mantissaBits, const uint32_t exponentBits, const bool explicitLeadingBit) {
const uint128_t ieeeMantissa, const uint32_t ieeeExponent, const bool ieeeSign,
const uint32_t mantissaBits, const uint32_t exponentBits, const bool explicitLeadingBit) {
#ifdef RYU_DEBUG
printf("IN=");
for (int32_t bit = 127; bit >= 0; --bit) {
@ -82,9 +49,6 @@ struct floating_decimal_128 generic_binary_to_decimal(
#endif
const uint32_t bias = (1u << (exponentBits - 1)) - 1;
const bool ieeeSign = ((bits >> (mantissaBits + exponentBits)) & 1) != 0;
const uint128_t ieeeMantissa = bits & ((ONE << mantissaBits) - 1);
const uint32_t ieeeExponent = (uint32_t) ((bits >> mantissaBits) & ((ONE << exponentBits) - 1u));
if (ieeeExponent == 0 && ieeeMantissa == 0) {
struct floating_decimal_128 fd;
@ -320,14 +284,17 @@ int generic_to_chars(const struct floating_decimal_128 v, char* const result) {
}
// Print the exponent.
result[index++] = 'E';
result[index++] = 'e';
int32_t exp = v.exponent + olength - 1;
if (exp < 0) {
result[index++] = '-';
exp = -exp;
}
} else
result[index++] = '+';
uint32_t elength = decimalLength(exp);
if (elength == 1)
++elength;
for (uint32_t i = 0; i < elength; ++i) {
const uint32_t c = exp % 10;
exp /= 10;