mirror of
https://github.com/php/php-src.git
synced 2024-12-16 13:26:19 +08:00
Micro-optimize double comparison (#11061)
When using ZEND_NORMALIZE_BOOL(a - b) where a and b are doubles, this generates the following instruction sequence on x64: subsd xmm0, xmm1 pxor xmm1, xmm1 comisd xmm0, xmm1 ... whereas if we use ZEND_THREEWAY_COMPARE we get two instructions less: ucomisd xmm0, xmm1 The only difference is that the threeway compare uses *u*comisd instead of comisd. The difference is that it will cause a FP signal if a signaling NAN is used, but as far as I'm aware this doesn't matter for our use case. Similarly, the amount of instructions on AArch64 is also quite a bit lower for this code compared to the old code. ** Results ** Using the benchmark https://gist.github.com/nielsdos/b36517d81a1af74d96baa3576c2b70df I used hyperfine: hyperfine --runs 25 --warmup 3 './sapi/cli/php sort_double.php' No extensions such as opcache used during benchmarking. BEFORE THIS PATCH ----------------- Time (mean ± σ): 255.5 ms ± 2.2 ms [User: 251.0 ms, System: 2.5 ms] Range (min … max): 251.5 ms … 260.7 ms 25 runs AFTER THIS PATCH ---------------- Time (mean ± σ): 236.2 ms ± 2.8 ms [User: 228.9 ms, System: 5.0 ms] Range (min … max): 231.5 ms … 242.7 ms 25 runs
This commit is contained in:
parent
8d5e06dc94
commit
a0476fd32f
@ -2109,7 +2109,7 @@ ZEND_API int ZEND_FASTCALL numeric_compare_function(zval *op1, zval *op2) /* {{{
|
||||
d1 = zval_get_double(op1);
|
||||
d2 = zval_get_double(op2);
|
||||
|
||||
return ZEND_NORMALIZE_BOOL(d1 - d2);
|
||||
return ZEND_THREEWAY_COMPARE(d1, d2);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@ -2131,8 +2131,7 @@ static int compare_long_to_string(zend_long lval, zend_string *str) /* {{{ */
|
||||
}
|
||||
|
||||
if (type == IS_DOUBLE) {
|
||||
double diff = (double) lval - str_dval;
|
||||
return ZEND_NORMALIZE_BOOL(diff);
|
||||
return ZEND_THREEWAY_COMPARE((double) lval, str_dval);
|
||||
}
|
||||
|
||||
zend_string *lval_as_str = zend_long_to_str(lval);
|
||||
@ -2150,15 +2149,11 @@ static int compare_double_to_string(double dval, zend_string *str) /* {{{ */
|
||||
uint8_t type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0);
|
||||
|
||||
if (type == IS_LONG) {
|
||||
double diff = dval - (double) str_lval;
|
||||
return ZEND_NORMALIZE_BOOL(diff);
|
||||
return ZEND_THREEWAY_COMPARE(dval, (double) str_lval);
|
||||
}
|
||||
|
||||
if (type == IS_DOUBLE) {
|
||||
if (dval == str_dval) {
|
||||
return 0;
|
||||
}
|
||||
return ZEND_NORMALIZE_BOOL(dval - str_dval);
|
||||
return ZEND_THREEWAY_COMPARE(dval, str_dval);
|
||||
}
|
||||
|
||||
zend_string *dval_as_str = zend_double_to_str(dval);
|
||||
@ -2180,17 +2175,13 @@ ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval *op2) /* {{{ */
|
||||
return Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0);
|
||||
|
||||
case TYPE_PAIR(IS_DOUBLE, IS_LONG):
|
||||
return ZEND_NORMALIZE_BOOL(Z_DVAL_P(op1) - (double)Z_LVAL_P(op2));
|
||||
return ZEND_THREEWAY_COMPARE(Z_DVAL_P(op1), (double)Z_LVAL_P(op2));
|
||||
|
||||
case TYPE_PAIR(IS_LONG, IS_DOUBLE):
|
||||
return ZEND_NORMALIZE_BOOL((double)Z_LVAL_P(op1) - Z_DVAL_P(op2));
|
||||
return ZEND_THREEWAY_COMPARE((double)Z_LVAL_P(op1), Z_DVAL_P(op2));
|
||||
|
||||
case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
|
||||
if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) {
|
||||
return 0;
|
||||
} else {
|
||||
return ZEND_NORMALIZE_BOOL(Z_DVAL_P(op1) - Z_DVAL_P(op2));
|
||||
}
|
||||
return ZEND_THREEWAY_COMPARE(Z_DVAL_P(op1), Z_DVAL_P(op2));
|
||||
|
||||
case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
|
||||
return zend_compare_arrays(op1, op2);
|
||||
|
@ -247,7 +247,7 @@ static int spl_ptr_pqueue_elem_cmp_long(void *x, void *y, zval *object) {
|
||||
static int spl_ptr_pqueue_elem_cmp_double(void *x, void *y, zval *object) {
|
||||
double a = Z_DVAL(((spl_pqueue_elem*) x)->priority);
|
||||
double b = Z_DVAL(((spl_pqueue_elem*) y)->priority);
|
||||
return ZEND_NORMALIZE_BOOL(a - b);
|
||||
return ZEND_THREEWAY_COMPARE(a, b);
|
||||
}
|
||||
|
||||
static spl_ptr_heap *spl_ptr_heap_init(spl_ptr_heap_cmp_func cmp, spl_ptr_heap_ctor_func ctor, spl_ptr_heap_dtor_func dtor, size_t elem_size) /* {{{ */
|
||||
|
@ -164,7 +164,7 @@ static zend_always_inline int php_array_key_compare_numeric_unstable_i(Bucket *f
|
||||
} else {
|
||||
d2 = (double)(zend_long)s->h;
|
||||
}
|
||||
return ZEND_NORMALIZE_BOOL(d1 - d2);
|
||||
return ZEND_THREEWAY_COMPARE(d1, d2);
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
Loading…
Reference in New Issue
Block a user