1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

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
```
This commit is contained in:
Niels Dossche
2024-05-01 16:48:42 +02:00
committed by GitHub
parent cf92a191e8
commit 0a3ccc0b99
6 changed files with 101 additions and 25 deletions

View File

@@ -8,7 +8,7 @@ if test "$PHP_BCMATH" != "no"; then
libbcmath/src/add.c libbcmath/src/div.c libbcmath/src/init.c libbcmath/src/neg.c libbcmath/src/raisemod.c libbcmath/src/sub.c \
libbcmath/src/compare.c libbcmath/src/divmod.c libbcmath/src/int2num.c libbcmath/src/num2long.c libbcmath/src/output.c libbcmath/src/recmul.c \
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 \
libbcmath/src/raise.c libbcmath/src/rmzero.c libbcmath/src/round.c libbcmath/src/str2num.c,
libbcmath/src/raise.c libbcmath/src/rmzero.c libbcmath/src/round.c libbcmath/src/str2num.c libbcmath/src/convert.c,
$ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
PHP_ADD_BUILD_DIR($ext_builddir/libbcmath/src)
AC_DEFINE(HAVE_BCMATH, 1, [Whether you have bcmath])

View File

@@ -8,7 +8,7 @@ if (PHP_BCMATH == "yes") {
raisemod.c sub.c compare.c divmod.c int2num.c \
num2long.c output.c recmul.c sqrt.c zero.c doaddsub.c \
floor_or_ceil.c nearzero.c num2str.c raise.c rmzero.c str2num.c \
round.c", "bcmath");
round.c convert.c", "bcmath");
AC_DEFINE('HAVE_BCMATH', 1, 'Have BCMATH library');
}

View File

@@ -0,0 +1,66 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Niels Dossche <nielsdos@php.net> |
+----------------------------------------------------------------------+
*/
#include "bcmath.h"
#include "convert.h"
/* This will be 0x01010101 for 32-bit and 0x0101010101010101 */
#define SWAR_ONES (~((size_t) 0) / 0xFF)
/* This repeats a byte `x` into an entire 32/64-bit word.
* Example: SWAR_REPEAT(0xAB) will be 0xABABABAB for 32-bit and 0xABABABABABABABAB for 64-bit. */
#define SWAR_REPEAT(x) (SWAR_ONES * (x))
static char *bc_copy_and_shift_numbers(char *restrict dest, const char *source, const char *source_end, unsigned char shift, bool add)
{
size_t bulk_shift = SWAR_REPEAT(shift);
if (!add) {
bulk_shift = -bulk_shift;
shift = -shift;
}
/* Handle sizeof(size_t) (i.e. 4/8) bytes at once.
* We know that adding/subtracting an individual byte cannot overflow,
* so it is possible to add/subtract an entire word of bytes at once
* by using SWAR_REPEAT. */
while (source + sizeof(size_t) <= source_end) {
size_t bytes;
memcpy(&bytes, source, sizeof(bytes));
bytes += bulk_shift;
memcpy(dest, &bytes, sizeof(bytes));
source += sizeof(size_t);
dest += sizeof(size_t);
}
while (source < source_end) {
*dest = *source + shift;
dest++;
source++;
}
return dest;
}
char *bc_copy_ch_val(char *restrict dest, const char *source, const char *source_end)
{
return bc_copy_and_shift_numbers(dest, source, source_end, '0', false);
}
char *bc_copy_bcd_val(char *restrict dest, const char *source, const char *source_end)
{
return bc_copy_and_shift_numbers(dest, source, source_end, '0', true);
}

View File

@@ -0,0 +1,23 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Niels Dossche <nielsdos@php.net> |
+----------------------------------------------------------------------+
*/
#ifndef BCMATH_CONVERT_H
#define BCMATH_CONVERT_H
char *bc_copy_ch_val(char *restrict dest, const char *source, const char *source_end);
char *bc_copy_bcd_val(char *restrict dest, const char *source, const char *source_end);
#endif

View File

@@ -30,7 +30,7 @@
*************************************************************************/
#include "bcmath.h"
#include <stddef.h>
#include "convert.h"
#include "zend_string.h"
/* Convert a numbers to a string. Base 10 only.*/
@@ -40,9 +40,10 @@ zend_string *bc_num2str_ex(bc_num num, size_t scale)
char *sptr;
size_t index;
bool signch;
size_t min_scale = MIN(num->n_scale, scale);
/* Number of sign chars. */
signch = num->n_sign != PLUS && !bc_is_zero_for_scale(num, MIN(num->n_scale, scale));
signch = num->n_sign != PLUS && !bc_is_zero_for_scale(num, min_scale);
/* Allocate the string memory. */
if (scale > 0) {
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)
/* Load the whole number. */
const char *nptr = num->n_value;
for (index = num->n_len; index > 0; index--) {
*sptr++ = BCD_CHAR(*nptr++);
}
sptr = bc_copy_bcd_val(sptr, nptr, nptr + num->n_len);
nptr += num->n_len;
/* Now the fraction. */
if (scale > 0) {
*sptr++ = '.';
for (index = 0; index < scale && index < num->n_scale; index++) {
*sptr++ = BCD_CHAR(*nptr++);
}
sptr = bc_copy_bcd_val(sptr, nptr, nptr + min_scale);
for (index = num->n_scale; index < scale; index++) {
*sptr++ = BCD_CHAR(0);
}

View File

@@ -30,6 +30,7 @@
*************************************************************************/
#include "bcmath.h"
#include "convert.h"
#include <stdbool.h>
#include <stddef.h>
@@ -124,24 +125,12 @@ after_fractional:
* If zero_int is true and the str_scale is 0, there is an early return,
* so here str_scale is always greater than 0.
*/
while (fractional_ptr < fractional_end) {
*nptr = CH_VAL(*fractional_ptr);
nptr++;
fractional_ptr++;
}
nptr = bc_copy_ch_val(nptr, fractional_ptr, fractional_end);
} else {
const char *integer_end = integer_ptr + digits;
while (integer_ptr < integer_end) {
*nptr = CH_VAL(*integer_ptr);
nptr++;
integer_ptr++;
}
nptr = bc_copy_ch_val(nptr, integer_ptr, integer_end);
if (str_scale > 0) {
while (fractional_ptr < fractional_end) {
*nptr = CH_VAL(*fractional_ptr);
nptr++;
fractional_ptr++;
}
nptr = bc_copy_ch_val(nptr, fractional_ptr, fractional_end);
}
}