diff --git a/ext/bcmath/bcmath.c b/ext/bcmath/bcmath.c index 7f5a473472d7f..7eae0729d85e5 100644 --- a/ext/bcmath/bcmath.c +++ b/ext/bcmath/bcmath.c @@ -148,7 +148,7 @@ PHP_FUNCTION(bcadd) zend_string *left, *right; zend_long scale_param; bool scale_param_is_null = 1; - bc_num first = NULL, second = NULL, result; + bc_num first = NULL, second = NULL, result = NULL; int scale; ZEND_PARSE_PARAMETERS_START(2, 3) @@ -167,8 +167,6 @@ PHP_FUNCTION(bcadd) scale = (int) scale_param; } - bc_init_num(&result); - if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) { zend_argument_value_error(1, "is not well-formed"); goto cleanup; @@ -179,9 +177,9 @@ PHP_FUNCTION(bcadd) goto cleanup; } - bc_add (first, second, &result, scale); + result = bc_add (first, second, scale); - RETVAL_STR(bc_num2str_ex(result, scale)); + RETVAL_NEW_STR(bc_num2str_ex(result, scale)); cleanup: { bc_free_num(&first); @@ -197,7 +195,7 @@ PHP_FUNCTION(bcsub) zend_string *left, *right; zend_long scale_param; bool scale_param_is_null = 1; - bc_num first = NULL, second = NULL, result; + bc_num first = NULL, second = NULL, result = NULL; int scale; ZEND_PARSE_PARAMETERS_START(2, 3) @@ -216,8 +214,6 @@ PHP_FUNCTION(bcsub) scale = (int) scale_param; } - bc_init_num(&result); - if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) { zend_argument_value_error(1, "is not well-formed"); goto cleanup; @@ -228,9 +224,9 @@ PHP_FUNCTION(bcsub) goto cleanup; } - bc_sub (first, second, &result, scale); + result = bc_sub (first, second, scale); - RETVAL_STR(bc_num2str_ex(result, scale)); + RETVAL_NEW_STR(bc_num2str_ex(result, scale)); cleanup: { bc_free_num(&first); @@ -246,7 +242,7 @@ PHP_FUNCTION(bcmul) zend_string *left, *right; zend_long scale_param; bool scale_param_is_null = 1; - bc_num first = NULL, second = NULL, result; + bc_num first = NULL, second = NULL, result = NULL; int scale; ZEND_PARSE_PARAMETERS_START(2, 3) @@ -265,8 +261,6 @@ PHP_FUNCTION(bcmul) scale = (int) scale_param; } - bc_init_num(&result); - if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) { zend_argument_value_error(1, "is not well-formed"); goto cleanup; @@ -277,9 +271,9 @@ PHP_FUNCTION(bcmul) goto cleanup; } - bc_multiply (first, second, &result, scale); + result = bc_multiply (first, second, scale); - RETVAL_STR(bc_num2str_ex(result, scale)); + RETVAL_NEW_STR(bc_num2str_ex(result, scale)); cleanup: { bc_free_num(&first); @@ -331,7 +325,7 @@ PHP_FUNCTION(bcdiv) goto cleanup; } - RETVAL_STR(bc_num2str_ex(result, scale)); + RETVAL_NEW_STR(bc_num2str_ex(result, scale)); cleanup: { bc_free_num(&first); @@ -383,7 +377,7 @@ PHP_FUNCTION(bcmod) goto cleanup; } - RETVAL_STR(bc_num2str_ex(result, scale)); + RETVAL_NEW_STR(bc_num2str_ex(result, scale)); cleanup: { bc_free_num(&first); @@ -454,7 +448,7 @@ PHP_FUNCTION(bcpowmod) zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero"); goto cleanup; case OK: - RETVAL_STR(bc_num2str_ex(result, scale)); + RETVAL_NEW_STR(bc_num2str_ex(result, scale)); break; EMPTY_SWITCH_DEFAULT_CASE(); } @@ -518,7 +512,7 @@ PHP_FUNCTION(bcpow) bc_raise(first, exponent, &result, scale); - RETVAL_STR(bc_num2str_ex(result, scale)); + RETVAL_NEW_STR(bc_num2str_ex(result, scale)); cleanup: { bc_free_num(&first); @@ -558,7 +552,7 @@ PHP_FUNCTION(bcsqrt) } if (bc_sqrt (&result, scale) != 0) { - RETVAL_STR(bc_num2str_ex(result, scale)); + RETVAL_NEW_STR(bc_num2str_ex(result, scale)); } else { zend_argument_value_error(1, "must be greater than or equal to 0"); } @@ -617,21 +611,19 @@ PHP_FUNCTION(bccomp) static void bcfloor_or_bcceil(INTERNAL_FUNCTION_PARAMETERS, bool is_floor) { zend_string *numstr; - bc_num num = NULL, result; + bc_num num = NULL, result = NULL; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STR(numstr) ZEND_PARSE_PARAMETERS_END(); - bc_init_num(&result); - if (php_str2num(&num, ZSTR_VAL(numstr)) == FAILURE) { zend_argument_value_error(1, "is not well-formed"); goto cleanup; } - bc_floor_or_ceil(num, is_floor, &result); - RETVAL_STR(bc_num2str_ex(result, 0)); + result = bc_floor_or_ceil(num, is_floor); + RETVAL_NEW_STR(bc_num2str_ex(result, 0)); cleanup: { bc_free_num(&num); @@ -692,7 +684,7 @@ PHP_FUNCTION(bcround) } bc_round(num, precision, mode, &result); - RETVAL_STR(bc_num2str_ex(result, result->n_scale)); + RETVAL_NEW_STR(bc_num2str_ex(result, result->n_scale)); cleanup: { bc_free_num(&num); diff --git a/ext/bcmath/libbcmath/src/add.c b/ext/bcmath/libbcmath/src/add.c index 1e6285a0df19a..23f922b7eb6d1 100644 --- a/ext/bcmath/libbcmath/src/add.c +++ b/ext/bcmath/libbcmath/src/add.c @@ -39,7 +39,7 @@ N1 is added to N2 and the result placed into RESULT. SCALE_MIN is the minimum scale for the result. */ -void bc_add(bc_num n1, bc_num n2, bc_num *result, size_t scale_min) +bc_num bc_add(bc_num n1, bc_num n2, size_t scale_min) { bc_num sum = NULL; @@ -67,7 +67,5 @@ void bc_add(bc_num n1, bc_num n2, bc_num *result, size_t scale_min) } } - /* Clean up and return. */ - bc_free_num (result); - *result = sum; + return sum; } diff --git a/ext/bcmath/libbcmath/src/bcmath.h b/ext/bcmath/libbcmath/src/bcmath.h index 9cd611a6fd5b3..6b3b14bd15952 100644 --- a/ext/bcmath/libbcmath/src/bcmath.h +++ b/ext/bcmath/libbcmath/src/bcmath.h @@ -88,7 +88,12 @@ bc_num _bc_new_num_ex(size_t length, size_t scale, bool persistent); void _bc_free_num_ex(bc_num *num, bool persistent); -bc_num bc_copy_num(bc_num num); +/* Make a copy of a number! Just increments the reference count! */ +static inline bc_num bc_copy_num(bc_num num) +{ + num->n_refs++; + return num; +} void bc_init_num(bc_num *num); @@ -110,11 +115,29 @@ bool bc_is_near_zero(bc_num num, size_t scale); bool bc_is_neg(bc_num num); -void bc_add(bc_num n1, bc_num n2, bc_num *result, size_t scale_min); +bc_num bc_add(bc_num n1, bc_num n2, size_t scale_min); -void bc_sub(bc_num n1, bc_num n2, bc_num *result, size_t scale_min); +#define bc_add_ex(n1, n2, result, scale_min) do { \ + bc_num add_ex = bc_add(n1, n2, scale_min); \ + bc_free_num (result); \ + *(result) = add_ex; \ +} while (0) -void bc_multiply(bc_num n1, bc_num n2, bc_num *prod, size_t scale); +bc_num bc_sub(bc_num n1, bc_num n2, size_t scale_min); + +#define bc_sub_ex(n1, n2, result, scale_min) do { \ + bc_num sub_ex = bc_sub(n1, n2, scale_min); \ + bc_free_num (result); \ + *(result) = sub_ex; \ +} while (0) + +bc_num bc_multiply(bc_num n1, bc_num n2, size_t scale); + +#define bc_multiply_ex(n1, n2, result, scale_min) do { \ + bc_num mul_ex = bc_multiply(n1, n2, scale_min); \ + bc_free_num (result); \ + *(result) = mul_ex; \ +} while (0) bool bc_divide(bc_num n1, bc_num n2, bc_num *quot, int scale); @@ -122,7 +145,7 @@ bool bc_modulo(bc_num num1, bc_num num2, bc_num *resul, size_t scale); bool bc_divmod(bc_num num1, bc_num num2, bc_num *quo, bc_num *rem, size_t scale); -void bc_floor_or_ceil(bc_num num, bool is_floor, bc_num *result); +bc_num bc_floor_or_ceil(bc_num num, bool is_floor); void bc_round(bc_num num, zend_long places, zend_long mode, bc_num *result); diff --git a/ext/bcmath/libbcmath/src/convert.c b/ext/bcmath/libbcmath/src/convert.c index 6217583a0ad4d..953dde27bb13a 100644 --- a/ext/bcmath/libbcmath/src/convert.c +++ b/ext/bcmath/libbcmath/src/convert.c @@ -16,6 +16,9 @@ #include "bcmath.h" #include "convert.h" +#ifdef __SSE2__ +# include +#endif /* This will be 0x01010101 for 32-bit and 0x0101010101010101 */ #define SWAR_ONES (~((size_t) 0) / 0xFF) @@ -31,6 +34,19 @@ static char *bc_copy_and_shift_numbers(char *restrict dest, const char *source, shift = -shift; } +#ifdef __SSE2__ + /* SIMD SSE2 bulk shift + copy */ + __m128i shift_vector = _mm_set1_epi8(shift); + while (source + sizeof(__m128i) <= source_end) { + __m128i bytes = _mm_loadu_si128((const __m128i *) source); + bytes = _mm_add_epi8(bytes, shift_vector); + _mm_storeu_si128((__m128i *) dest, bytes); + + source += sizeof(__m128i); + dest += sizeof(__m128i); + } +#endif + /* 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 diff --git a/ext/bcmath/libbcmath/src/divmod.c b/ext/bcmath/libbcmath/src/divmod.c index d4f9d4d38cfa9..662e5600cb263 100644 --- a/ext/bcmath/libbcmath/src/divmod.c +++ b/ext/bcmath/libbcmath/src/divmod.c @@ -61,8 +61,8 @@ bool bc_divmod(bc_num num1, bc_num num2, bc_num *quot, bc_num *rem, size_t scale if (quot) { quotient = bc_copy_num(temp); } - bc_multiply(temp, num2, &temp, rscale); - bc_sub(num1, temp, rem, rscale); + bc_multiply_ex(temp, num2, &temp, rscale); + bc_sub_ex(num1, temp, rem, rscale); bc_free_num (&temp); if (quot) { diff --git a/ext/bcmath/libbcmath/src/floor_or_ceil.c b/ext/bcmath/libbcmath/src/floor_or_ceil.c index 5c3b17c01b610..95c1d60e1b3fb 100644 --- a/ext/bcmath/libbcmath/src/floor_or_ceil.c +++ b/ext/bcmath/libbcmath/src/floor_or_ceil.c @@ -18,22 +18,19 @@ #include "private.h" #include -void bc_floor_or_ceil(bc_num num, bool is_floor, bc_num *result) +bc_num bc_floor_or_ceil(bc_num num, bool is_floor) { - /* clear result */ - bc_free_num(result); - /* Initialize result */ - *result = bc_new_num(num->n_len, 0); - (*result)->n_sign = num->n_sign; + bc_num result = bc_new_num(num->n_len, 0); + result->n_sign = num->n_sign; /* copy integer part */ - memcpy((*result)->n_value, num->n_value, num->n_len); + memcpy(result->n_value, num->n_value, num->n_len); /* If the number is positive and we are flooring, then nothing else needs to be done. * Similarly, if the number is negative and we are ceiling, then nothing else needs to be done. */ - if (num->n_scale == 0 || (*result)->n_sign == (is_floor ? PLUS : MINUS)) { - return; + if (num->n_scale == 0 || result->n_sign == (is_floor ? PLUS : MINUS)) { + return result; } /* check fractional part. */ @@ -46,12 +43,12 @@ void bc_floor_or_ceil(bc_num num, bool is_floor, bc_num *result) /* If all digits past the decimal point are 0 */ if (count == 0) { - return; + return result; } /* Increment the absolute value of the result by 1 and add sign information */ - bc_num tmp = _bc_do_add(*result, BCG(_one_), 0); - tmp->n_sign = (*result)->n_sign; - bc_free_num(result); - *result = tmp; + bc_num tmp = _bc_do_add(result, BCG(_one_), 0); + tmp->n_sign = result->n_sign; + bc_free_num(&result); + return tmp; } diff --git a/ext/bcmath/libbcmath/src/init.c b/ext/bcmath/libbcmath/src/init.c index 959f47c21aa06..1db324aeee226 100644 --- a/ext/bcmath/libbcmath/src/init.c +++ b/ext/bcmath/libbcmath/src/init.c @@ -77,14 +77,6 @@ void bc_init_numbers(void) } -/* Make a copy of a number! Just increments the reference count! */ -bc_num bc_copy_num(bc_num num) -{ - num->n_refs++; - return num; -} - - /* Initialize a number NUM by making it a copy of zero. */ void bc_init_num(bc_num *num) { diff --git a/ext/bcmath/libbcmath/src/output.c b/ext/bcmath/libbcmath/src/output.c index 47a82d20655e3..ee3e726c87c53 100644 --- a/ext/bcmath/libbcmath/src/output.c +++ b/ext/bcmath/libbcmath/src/output.c @@ -79,7 +79,7 @@ void bc_out_num(bc_num num, int o_base, void (*out_char)(char), bool leading_zer int index, fdigit; bool pre_space; stk_rec *digits, *temp; - bc_num int_part, frac_part, base, cur_dig, t_num, max_o_digit; + bc_num int_part, base, cur_dig, t_num, max_o_digit; /* The negative sign if needed. */ if (num->n_sign == MINUS) (*out_char)('-'); @@ -120,10 +120,9 @@ void bc_out_num(bc_num num, int o_base, void (*out_char)(char), bool leading_zer digits = NULL; bc_init_num(&int_part); bc_divide(num, BCG(_one_), &int_part, 0); - bc_init_num(&frac_part); bc_init_num(&cur_dig); bc_init_num(&base); - bc_sub(num, int_part, &frac_part, 0); + bc_num frac_part = bc_sub(num, int_part, 0); /* Make the INT_PART and FRAC_PART positive. */ int_part->n_sign = PLUS; frac_part->n_sign = PLUS; @@ -163,17 +162,17 @@ void bc_out_num(bc_num num, int o_base, void (*out_char)(char), bool leading_zer pre_space = false; t_num = bc_copy_num(BCG(_one_)); while (t_num->n_len <= num->n_scale) { - bc_multiply(frac_part, base, &frac_part, num->n_scale); + bc_multiply_ex(frac_part, base, &frac_part, num->n_scale); fdigit = bc_num2long(frac_part); bc_int2num(&int_part, fdigit); - bc_sub(frac_part, int_part, &frac_part, 0); + bc_sub_ex(frac_part, int_part, &frac_part, 0); if (o_base <= 16) { (*out_char)(ref_str[fdigit]); } else { bc_out_long(fdigit, max_o_digit->n_len, pre_space, out_char); pre_space = true; } - bc_multiply(t_num, base, &t_num, 0); + bc_multiply_ex(t_num, base, &t_num, 0); } bc_free_num (&t_num); } diff --git a/ext/bcmath/libbcmath/src/raise.c b/ext/bcmath/libbcmath/src/raise.c index 61d64ace94744..390f4d6935c6d 100644 --- a/ext/bcmath/libbcmath/src/raise.c +++ b/ext/bcmath/libbcmath/src/raise.c @@ -69,7 +69,7 @@ void bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale) pwrscale = num1->n_scale; while ((exponent & 1) == 0) { pwrscale = 2 * pwrscale; - bc_multiply(power, power, &power, pwrscale); + bc_multiply_ex(power, power, &power, pwrscale); exponent = exponent >> 1; } temp = bc_copy_num(power); @@ -79,10 +79,10 @@ void bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale) /* Do the calculation. */ while (exponent > 0) { pwrscale = 2 * pwrscale; - bc_multiply(power, power, &power, pwrscale); + bc_multiply_ex(power, power, &power, pwrscale); if ((exponent & 1) == 1) { calcscale = pwrscale + calcscale; - bc_multiply(temp, power, &temp, calcscale); + bc_multiply_ex(temp, power, &temp, calcscale); } exponent = exponent >> 1; } diff --git a/ext/bcmath/libbcmath/src/raisemod.c b/ext/bcmath/libbcmath/src/raisemod.c index d4a2d01f3edb9..caf1a090f9807 100644 --- a/ext/bcmath/libbcmath/src/raisemod.c +++ b/ext/bcmath/libbcmath/src/raisemod.c @@ -72,10 +72,10 @@ raise_mod_status bc_raisemod(bc_num base, bc_num expo, bc_num mod, bc_num *resul while (!bc_is_zero(exponent)) { (void) bc_divmod(exponent, BCG(_two_), &exponent, &parity, 0); if (!bc_is_zero(parity)) { - bc_multiply(temp, power, &temp, scale); + bc_multiply_ex(temp, power, &temp, scale); (void) bc_modulo(temp, modulus, &temp, scale); } - bc_multiply(power, power, &power, scale); + bc_multiply_ex(power, power, &power, scale); (void) bc_modulo(power, modulus, &power, scale); } } diff --git a/ext/bcmath/libbcmath/src/recmul.c b/ext/bcmath/libbcmath/src/recmul.c index fe6a34817d99b..127330ba3ae54 100644 --- a/ext/bcmath/libbcmath/src/recmul.c +++ b/ext/bcmath/libbcmath/src/recmul.c @@ -163,7 +163,7 @@ static void _bc_shift_addsub(bc_num accum, bc_num val, int shift, bool sub) static void _bc_rec_mul(bc_num u, size_t ulen, bc_num v, size_t vlen, bc_num *prod) { bc_num u0, u1, v0, v1; - bc_num m1, m2, m3, d1, d2; + bc_num m1, m2, m3; size_t n; bool m1zero; @@ -203,10 +203,8 @@ static void _bc_rec_mul(bc_num u, size_t ulen, bc_num v, size_t vlen, bc_num *pr /* Calculate sub results ... */ - bc_init_num(&d1); - bc_init_num(&d2); - bc_sub(u1, u0, &d1, 0); - bc_sub(v0, v1, &d2, 0); + bc_num d1 = bc_sub(u1, u0, 0); + bc_num d2 = bc_sub(v0, v1, 0); /* Do recursive multiplies and shifted adds. */ @@ -255,7 +253,7 @@ static void _bc_rec_mul(bc_num u, size_t ulen, bc_num v, size_t vlen, bc_num *pr the result being MIN(N2 scale+N1 scale, MAX (SCALE, N2 scale, N1 scale)). */ -void bc_multiply(bc_num n1, bc_num n2, bc_num *prod, size_t scale) +bc_num bc_multiply(bc_num n1, bc_num n2, size_t scale) { bc_num pval; size_t len1, len2; @@ -278,6 +276,5 @@ void bc_multiply(bc_num n1, bc_num n2, bc_num *prod, size_t scale) if (bc_is_zero(pval)) { pval->n_sign = PLUS; } - bc_free_num(prod); - *prod = pval; + return pval; } diff --git a/ext/bcmath/libbcmath/src/sqrt.c b/ext/bcmath/libbcmath/src/sqrt.c index f29f9ce484bad..995bf076b54e7 100644 --- a/ext/bcmath/libbcmath/src/sqrt.c +++ b/ext/bcmath/libbcmath/src/sqrt.c @@ -79,7 +79,7 @@ bool bc_sqrt(bc_num *num, size_t scale) bc_int2num(&guess, 10); bc_int2num(&guess1, (*num)->n_len); - bc_multiply(guess1, point5, &guess1, 0); + bc_multiply_ex(guess1, point5, &guess1, 0); guess1->n_scale = 0; bc_raise_bc_exponent(guess, guess1, &guess, 0); bc_free_num (&guess1); @@ -92,9 +92,9 @@ bool bc_sqrt(bc_num *num, size_t scale) bc_free_num (&guess1); guess1 = bc_copy_num(guess); bc_divide(*num, guess, &guess, cscale); - bc_add(guess, guess1, &guess, 0); - bc_multiply(guess, point5, &guess, cscale); - bc_sub(guess, guess1, &diff, cscale + 1); + bc_add_ex(guess, guess1, &guess, 0); + bc_multiply_ex(guess, point5, &guess, cscale); + bc_sub_ex(guess, guess1, &diff, cscale + 1); if (bc_is_near_zero(diff, cscale)) { if (cscale < rscale + 1) { cscale = MIN (cscale * 3, rscale + 1); diff --git a/ext/bcmath/libbcmath/src/sub.c b/ext/bcmath/libbcmath/src/sub.c index d90f1a8858f29..185f9651dea63 100644 --- a/ext/bcmath/libbcmath/src/sub.c +++ b/ext/bcmath/libbcmath/src/sub.c @@ -39,7 +39,7 @@ N2 is subtracted from N1 and the result placed in RESULT. SCALE_MIN is the minimum scale for the result. */ -void bc_sub(bc_num n1, bc_num n2, bc_num *result, size_t scale_min) +bc_num bc_sub(bc_num n1, bc_num n2, size_t scale_min) { bc_num diff = NULL; @@ -70,7 +70,5 @@ void bc_sub(bc_num n1, bc_num n2, bc_num *result, size_t scale_min) } } - /* Clean up and return. */ - bc_free_num (result); - *result = diff; + return diff; }