From 364a698766ca5f5f68c5b29aaa3a4212e9ff2cd5 Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Tue, 7 May 2024 21:57:21 +0900 Subject: [PATCH 1/6] use SIMD --- ext/bcmath/libbcmath/src/str2num.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/ext/bcmath/libbcmath/src/str2num.c b/ext/bcmath/libbcmath/src/str2num.c index 4787e16b53a2b..d212e75bbf561 100644 --- a/ext/bcmath/libbcmath/src/str2num.c +++ b/ext/bcmath/libbcmath/src/str2num.c @@ -76,6 +76,32 @@ static const char *bc_count_digits(const char *str, const char *end) return str; } +static inline const char *bc_skip_zero_reverse(const char *str, const char *end) +{ + +#ifdef __SSE2__ + const __m128i c_zero_repeat = _mm_set1_epi8((signed char) '0'); + while (str - sizeof(__m128i) >= end) { + str -= sizeof(__m128i); + __m128i bytes = _mm_loadu_si128((const __m128i *) str); + bytes = _mm_cmpeq_epi8(bytes, c_zero_repeat); + + int mask = _mm_movemask_epi8(bytes); + if (EXPECTED(mask != 0xffff)) { + str += sizeof(__m128i); + break; + } + } +#endif + + /* Exclude trailing zeros. */ + while (str - 1 >= end && str[-1] == '0') { + str--; + } + + return str; +} + /* Assumes `num` points to NULL, i.e. does yet not hold a number. */ bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, bool auto_scale) { @@ -124,9 +150,7 @@ bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, boo } /* Exclude trailing zeros. */ - while (fractional_end - 1 > decimal_point && fractional_end[-1] == '0') { - fractional_end--; - } + fractional_end = bc_skip_zero_reverse(fractional_end, fractional_ptr); /* Move the pointer to the beginning of the fraction. */ fractional_ptr = decimal_point + 1; From 570268d95ad629b75adcda665bade376a2e03361 Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Tue, 7 May 2024 21:57:41 +0900 Subject: [PATCH 2/6] use UNEXPECTED --- ext/bcmath/libbcmath/src/str2num.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/bcmath/libbcmath/src/str2num.c b/ext/bcmath/libbcmath/src/str2num.c index d212e75bbf561..30ddf16b77a1c 100644 --- a/ext/bcmath/libbcmath/src/str2num.c +++ b/ext/bcmath/libbcmath/src/str2num.c @@ -130,7 +130,7 @@ bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, boo const char *decimal_point = (*ptr == '.') ? ptr : NULL; /* If a non-digit and non-decimal-point indicator is in the string, i.e. an invalid character */ - if (!decimal_point && *ptr != '\0') { + if (UNEXPECTED(!decimal_point && *ptr != '\0')) { goto fail; } @@ -138,13 +138,13 @@ bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, boo if (decimal_point) { /* search */ fractional_ptr = fractional_end = decimal_point + 1; - if (*fractional_ptr == '\0') { + if (UNEXPECTED(*fractional_ptr == '\0')) { goto after_fractional; } /* validate */ fractional_end = bc_count_digits(fractional_ptr, end); - if (*fractional_end != '\0') { + if (UNEXPECTED(*fractional_end != '\0')) { /* invalid num */ goto fail; } From 1189f4fad58780ee4dcb056204ed4ec7c3c10dec Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Tue, 7 May 2024 22:03:16 +0900 Subject: [PATCH 3/6] Remove ineffective code --- ext/bcmath/libbcmath/src/str2num.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/ext/bcmath/libbcmath/src/str2num.c b/ext/bcmath/libbcmath/src/str2num.c index 30ddf16b77a1c..7836cd36bd6da 100644 --- a/ext/bcmath/libbcmath/src/str2num.c +++ b/ext/bcmath/libbcmath/src/str2num.c @@ -152,9 +152,6 @@ bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, boo /* Exclude trailing zeros. */ fractional_end = bc_skip_zero_reverse(fractional_end, fractional_ptr); - /* Move the pointer to the beginning of the fraction. */ - fractional_ptr = decimal_point + 1; - /* Calculate the length of the fraction excluding trailing zero. */ str_scale = fractional_end - fractional_ptr; From fc7f7cbe1a1a41931af33b26a92376a705aa8aab Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Tue, 7 May 2024 22:43:57 +0900 Subject: [PATCH 4/6] Added comments --- ext/bcmath/libbcmath/src/str2num.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ext/bcmath/libbcmath/src/str2num.c b/ext/bcmath/libbcmath/src/str2num.c index 7836cd36bd6da..8213d41a06ee4 100644 --- a/ext/bcmath/libbcmath/src/str2num.c +++ b/ext/bcmath/libbcmath/src/str2num.c @@ -78,16 +78,19 @@ static const char *bc_count_digits(const char *str, const char *end) static inline const char *bc_skip_zero_reverse(const char *str, const char *end) { - + /* Check in bulk */ #ifdef __SSE2__ const __m128i c_zero_repeat = _mm_set1_epi8((signed char) '0'); while (str - sizeof(__m128i) >= end) { str -= sizeof(__m128i); __m128i bytes = _mm_loadu_si128((const __m128i *) str); + /* Checks if all numeric strings are equal to '0'. */ bytes = _mm_cmpeq_epi8(bytes, c_zero_repeat); int mask = _mm_movemask_epi8(bytes); + /* The probability of having 16 trailing 0s in a row is very low, so we use EXPECTED. */ if (EXPECTED(mask != 0xffff)) { + /* Move the pointer back and check each character in loop. */ str += sizeof(__m128i); break; } @@ -138,6 +141,7 @@ bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, boo if (decimal_point) { /* search */ fractional_ptr = fractional_end = decimal_point + 1; + /* For strings that end with a decimal point, such as "012." */ if (UNEXPECTED(*fractional_ptr == '\0')) { goto after_fractional; } From 323e144bc17e8dcee59dc05d88e6fee34bcdaf8d Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Thu, 9 May 2024 09:23:12 +0900 Subject: [PATCH 5/6] address comments --- ext/bcmath/libbcmath/src/str2num.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ext/bcmath/libbcmath/src/str2num.c b/ext/bcmath/libbcmath/src/str2num.c index 3a8fb10ae4562..8e3e8cd1e35b8 100644 --- a/ext/bcmath/libbcmath/src/str2num.c +++ b/ext/bcmath/libbcmath/src/str2num.c @@ -76,14 +76,14 @@ static const char *bc_count_digits(const char *str, const char *end) return str; } -static inline const char *bc_skip_zero_reverse(const char *str, const char *end) +static inline const char *bc_skip_zero_reverse(const char *scaner, const char *stop) { /* Check in bulk */ #ifdef __SSE2__ - const __m128i c_zero_repeat = _mm_set1_epi8((signed char) '0'); - while (str - sizeof(__m128i) >= end) { - str -= sizeof(__m128i); - __m128i bytes = _mm_loadu_si128((const __m128i *) str); + const __m128i c_zero_repeat = _mm_set1_epi8('0'); + while (scaner - sizeof(__m128i) >= stop) { + scaner -= sizeof(__m128i); + __m128i bytes = _mm_loadu_si128((const __m128i *) scaner); /* Checks if all numeric strings are equal to '0'. */ bytes = _mm_cmpeq_epi8(bytes, c_zero_repeat); @@ -91,18 +91,18 @@ static inline const char *bc_skip_zero_reverse(const char *str, const char *end) /* The probability of having 16 trailing 0s in a row is very low, so we use EXPECTED. */ if (EXPECTED(mask != 0xffff)) { /* Move the pointer back and check each character in loop. */ - str += sizeof(__m128i); + scaner += sizeof(__m128i); break; } } #endif /* Exclude trailing zeros. */ - while (str - 1 >= end && str[-1] == '0') { - str--; + while (scaner - 1 >= stop && scaner[-1] == '0') { + scaner--; } - return str; + return scaner; } /* Assumes `num` points to NULL, i.e. does yet not hold a number. */ From 275abd0a4078138c9f55a13085d2e7923e2fb9e2 Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Thu, 9 May 2024 17:55:28 +0900 Subject: [PATCH 6/6] typo --- ext/bcmath/libbcmath/src/str2num.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ext/bcmath/libbcmath/src/str2num.c b/ext/bcmath/libbcmath/src/str2num.c index 8e3e8cd1e35b8..a46ae6a2c9d73 100644 --- a/ext/bcmath/libbcmath/src/str2num.c +++ b/ext/bcmath/libbcmath/src/str2num.c @@ -76,14 +76,14 @@ static const char *bc_count_digits(const char *str, const char *end) return str; } -static inline const char *bc_skip_zero_reverse(const char *scaner, const char *stop) +static inline const char *bc_skip_zero_reverse(const char *scanner, const char *stop) { /* Check in bulk */ #ifdef __SSE2__ const __m128i c_zero_repeat = _mm_set1_epi8('0'); - while (scaner - sizeof(__m128i) >= stop) { - scaner -= sizeof(__m128i); - __m128i bytes = _mm_loadu_si128((const __m128i *) scaner); + while (scanner - sizeof(__m128i) >= stop) { + scanner -= sizeof(__m128i); + __m128i bytes = _mm_loadu_si128((const __m128i *) scanner); /* Checks if all numeric strings are equal to '0'. */ bytes = _mm_cmpeq_epi8(bytes, c_zero_repeat); @@ -91,18 +91,18 @@ static inline const char *bc_skip_zero_reverse(const char *scaner, const char *s /* The probability of having 16 trailing 0s in a row is very low, so we use EXPECTED. */ if (EXPECTED(mask != 0xffff)) { /* Move the pointer back and check each character in loop. */ - scaner += sizeof(__m128i); + scanner += sizeof(__m128i); break; } } #endif /* Exclude trailing zeros. */ - while (scaner - 1 >= stop && scaner[-1] == '0') { - scaner--; + while (scanner - 1 >= stop && scanner[-1] == '0') { + scanner--; } - return scaner; + return scanner; } /* Assumes `num` points to NULL, i.e. does yet not hold a number. */