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:
@@ -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])
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
66
ext/bcmath/libbcmath/src/convert.c
Normal file
66
ext/bcmath/libbcmath/src/convert.c
Normal 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);
|
||||
}
|
||||
23
ext/bcmath/libbcmath/src/convert.h
Normal file
23
ext/bcmath/libbcmath/src/convert.h
Normal 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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user