Skip to content

Commit 0a3ccc0

Browse files
authored
Use bulk conversion in BCMath of BCD/CHAR where possible (#14103)
On my i7-4790 with benchmark from #14076, on top of #14101 I obtain the following results: before (with #14101): ``` 1.672737121582 2.3618471622467 2.3474779129028 ``` after (with #14101 + this): ``` 1.5878579616547 2.0568618774414 2.0204811096191 ```
1 parent cf92a19 commit 0a3ccc0

File tree

6 files changed

+101
-25
lines changed

6 files changed

+101
-25
lines changed

ext/bcmath/config.m4

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ if test "$PHP_BCMATH" != "no"; then
88
libbcmath/src/add.c libbcmath/src/div.c libbcmath/src/init.c libbcmath/src/neg.c libbcmath/src/raisemod.c libbcmath/src/sub.c \
99
libbcmath/src/compare.c libbcmath/src/divmod.c libbcmath/src/int2num.c libbcmath/src/num2long.c libbcmath/src/output.c libbcmath/src/recmul.c \
1010
libbcmath/src/sqrt.c libbcmath/src/zero.c libbcmath/src/doaddsub.c libbcmath/src/floor_or_ceil.c libbcmath/src/nearzero.c libbcmath/src/num2str.c \
11-
libbcmath/src/raise.c libbcmath/src/rmzero.c libbcmath/src/round.c libbcmath/src/str2num.c,
11+
libbcmath/src/raise.c libbcmath/src/rmzero.c libbcmath/src/round.c libbcmath/src/str2num.c libbcmath/src/convert.c,
1212
$ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
1313
PHP_ADD_BUILD_DIR($ext_builddir/libbcmath/src)
1414
AC_DEFINE(HAVE_BCMATH, 1, [Whether you have bcmath])

ext/bcmath/config.w32

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ if (PHP_BCMATH == "yes") {
88
raisemod.c sub.c compare.c divmod.c int2num.c \
99
num2long.c output.c recmul.c sqrt.c zero.c doaddsub.c \
1010
floor_or_ceil.c nearzero.c num2str.c raise.c rmzero.c str2num.c \
11-
round.c", "bcmath");
11+
round.c convert.c", "bcmath");
1212

1313
AC_DEFINE('HAVE_BCMATH', 1, 'Have BCMATH library');
1414
}

ext/bcmath/libbcmath/src/convert.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| Copyright (c) The PHP Group |
4+
+----------------------------------------------------------------------+
5+
| This source file is subject to version 3.01 of the PHP license, |
6+
| that is bundled with this package in the file LICENSE, and is |
7+
| available through the world-wide-web at the following url: |
8+
| https://www.php.net/license/3_01.txt |
9+
| If you did not receive a copy of the PHP license and are unable to |
10+
| obtain it through the world-wide-web, please send a note to |
11+
| [email protected] so we can mail you a copy immediately. |
12+
+----------------------------------------------------------------------+
13+
| Authors: Niels Dossche <[email protected]> |
14+
+----------------------------------------------------------------------+
15+
*/
16+
17+
#include "bcmath.h"
18+
#include "convert.h"
19+
20+
/* This will be 0x01010101 for 32-bit and 0x0101010101010101 */
21+
#define SWAR_ONES (~((size_t) 0) / 0xFF)
22+
/* This repeats a byte `x` into an entire 32/64-bit word.
23+
* Example: SWAR_REPEAT(0xAB) will be 0xABABABAB for 32-bit and 0xABABABABABABABAB for 64-bit. */
24+
#define SWAR_REPEAT(x) (SWAR_ONES * (x))
25+
26+
static char *bc_copy_and_shift_numbers(char *restrict dest, const char *source, const char *source_end, unsigned char shift, bool add)
27+
{
28+
size_t bulk_shift = SWAR_REPEAT(shift);
29+
if (!add) {
30+
bulk_shift = -bulk_shift;
31+
shift = -shift;
32+
}
33+
34+
/* Handle sizeof(size_t) (i.e. 4/8) bytes at once.
35+
* We know that adding/subtracting an individual byte cannot overflow,
36+
* so it is possible to add/subtract an entire word of bytes at once
37+
* by using SWAR_REPEAT. */
38+
while (source + sizeof(size_t) <= source_end) {
39+
size_t bytes;
40+
memcpy(&bytes, source, sizeof(bytes));
41+
42+
bytes += bulk_shift;
43+
memcpy(dest, &bytes, sizeof(bytes));
44+
45+
source += sizeof(size_t);
46+
dest += sizeof(size_t);
47+
}
48+
49+
while (source < source_end) {
50+
*dest = *source + shift;
51+
dest++;
52+
source++;
53+
}
54+
55+
return dest;
56+
}
57+
58+
char *bc_copy_ch_val(char *restrict dest, const char *source, const char *source_end)
59+
{
60+
return bc_copy_and_shift_numbers(dest, source, source_end, '0', false);
61+
}
62+
63+
char *bc_copy_bcd_val(char *restrict dest, const char *source, const char *source_end)
64+
{
65+
return bc_copy_and_shift_numbers(dest, source, source_end, '0', true);
66+
}

ext/bcmath/libbcmath/src/convert.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| Copyright (c) The PHP Group |
4+
+----------------------------------------------------------------------+
5+
| This source file is subject to version 3.01 of the PHP license, |
6+
| that is bundled with this package in the file LICENSE, and is |
7+
| available through the world-wide-web at the following url: |
8+
| https://www.php.net/license/3_01.txt |
9+
| If you did not receive a copy of the PHP license and are unable to |
10+
| obtain it through the world-wide-web, please send a note to |
11+
| [email protected] so we can mail you a copy immediately. |
12+
+----------------------------------------------------------------------+
13+
| Authors: Niels Dossche <[email protected]> |
14+
+----------------------------------------------------------------------+
15+
*/
16+
17+
#ifndef BCMATH_CONVERT_H
18+
#define BCMATH_CONVERT_H
19+
20+
char *bc_copy_ch_val(char *restrict dest, const char *source, const char *source_end);
21+
char *bc_copy_bcd_val(char *restrict dest, const char *source, const char *source_end);
22+
23+
#endif

ext/bcmath/libbcmath/src/num2str.c

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
*************************************************************************/
3131

3232
#include "bcmath.h"
33-
#include <stddef.h>
33+
#include "convert.h"
3434
#include "zend_string.h"
3535

3636
/* Convert a numbers to a string. Base 10 only.*/
@@ -40,9 +40,10 @@ zend_string *bc_num2str_ex(bc_num num, size_t scale)
4040
char *sptr;
4141
size_t index;
4242
bool signch;
43+
size_t min_scale = MIN(num->n_scale, scale);
4344

4445
/* Number of sign chars. */
45-
signch = num->n_sign != PLUS && !bc_is_zero_for_scale(num, MIN(num->n_scale, scale));
46+
signch = num->n_sign != PLUS && !bc_is_zero_for_scale(num, min_scale);
4647
/* Allocate the string memory. */
4748
if (scale > 0) {
4849
str = zend_string_alloc(num->n_len + scale + signch + 1, 0);
@@ -56,16 +57,13 @@ zend_string *bc_num2str_ex(bc_num num, size_t scale)
5657

5758
/* Load the whole number. */
5859
const char *nptr = num->n_value;
59-
for (index = num->n_len; index > 0; index--) {
60-
*sptr++ = BCD_CHAR(*nptr++);
61-
}
60+
sptr = bc_copy_bcd_val(sptr, nptr, nptr + num->n_len);
61+
nptr += num->n_len;
6262

6363
/* Now the fraction. */
6464
if (scale > 0) {
6565
*sptr++ = '.';
66-
for (index = 0; index < scale && index < num->n_scale; index++) {
67-
*sptr++ = BCD_CHAR(*nptr++);
68-
}
66+
sptr = bc_copy_bcd_val(sptr, nptr, nptr + min_scale);
6967
for (index = num->n_scale; index < scale; index++) {
7068
*sptr++ = BCD_CHAR(0);
7169
}

ext/bcmath/libbcmath/src/str2num.c

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
*************************************************************************/
3131

3232
#include "bcmath.h"
33+
#include "convert.h"
3334
#include <stdbool.h>
3435
#include <stddef.h>
3536

@@ -124,24 +125,12 @@ bool bc_str2num(bc_num *num, char *str, size_t scale, bool auto_scale)
124125
* If zero_int is true and the str_scale is 0, there is an early return,
125126
* so here str_scale is always greater than 0.
126127
*/
127-
while (fractional_ptr < fractional_end) {
128-
*nptr = CH_VAL(*fractional_ptr);
129-
nptr++;
130-
fractional_ptr++;
131-
}
128+
nptr = bc_copy_ch_val(nptr, fractional_ptr, fractional_end);
132129
} else {
133130
const char *integer_end = integer_ptr + digits;
134-
while (integer_ptr < integer_end) {
135-
*nptr = CH_VAL(*integer_ptr);
136-
nptr++;
137-
integer_ptr++;
138-
}
131+
nptr = bc_copy_ch_val(nptr, integer_ptr, integer_end);
139132
if (str_scale > 0) {
140-
while (fractional_ptr < fractional_end) {
141-
*nptr = CH_VAL(*fractional_ptr);
142-
nptr++;
143-
fractional_ptr++;
144-
}
133+
nptr = bc_copy_ch_val(nptr, fractional_ptr, fractional_end);
145134
}
146135
}
147136

0 commit comments

Comments
 (0)