Skip to content

Commit 9a22f6a

Browse files
committed
Optimize double comparison
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.
1 parent 9a90a7a commit 9a22f6a

File tree

1 file changed

+8
-18
lines changed

1 file changed

+8
-18
lines changed

Zend/zend_operators.c

+8-18
Original file line numberDiff line numberDiff line change
@@ -2109,7 +2109,7 @@ ZEND_API int ZEND_FASTCALL numeric_compare_function(zval *op1, zval *op2) /* {{{
21092109
d1 = zval_get_double(op1);
21102110
d2 = zval_get_double(op2);
21112111

2112-
return ZEND_NORMALIZE_BOOL(d1 - d2);
2112+
return ZEND_THREEWAY_COMPARE(d1, d2);
21132113
}
21142114
/* }}} */
21152115

@@ -2131,8 +2131,7 @@ static int compare_long_to_string(zend_long lval, zend_string *str) /* {{{ */
21312131
}
21322132

21332133
if (type == IS_DOUBLE) {
2134-
double diff = (double) lval - str_dval;
2135-
return ZEND_NORMALIZE_BOOL(diff);
2134+
return ZEND_THREEWAY_COMPARE((double) lval, str_dval);
21362135
}
21372136

21382137
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) /* {{{ */
21502149
uint8_t type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0);
21512150

21522151
if (type == IS_LONG) {
2153-
double diff = dval - (double) str_lval;
2154-
return ZEND_NORMALIZE_BOOL(diff);
2152+
return ZEND_THREEWAY_COMPARE(dval, (double) str_lval);
21552153
}
21562154

21572155
if (type == IS_DOUBLE) {
2158-
if (dval == str_dval) {
2159-
return 0;
2160-
}
2161-
return ZEND_NORMALIZE_BOOL(dval - str_dval);
2156+
return ZEND_THREEWAY_COMPARE(dval, str_dval);
21622157
}
21632158

21642159
zend_string *dval_as_str = zend_double_to_str(dval);
@@ -2225,17 +2220,13 @@ static inline int ZEND_FASTCALL zend_compare_fast(zval *op1, zval *op2, bool con
22252220
return Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0);
22262221

22272222
case TYPE_PAIR(IS_DOUBLE, IS_LONG):
2228-
return ZEND_NORMALIZE_BOOL(Z_DVAL_P(op1) - (double)Z_LVAL_P(op2));
2223+
return ZEND_THREEWAY_COMPARE(Z_DVAL_P(op1), (double)Z_LVAL_P(op2));
22292224

22302225
case TYPE_PAIR(IS_LONG, IS_DOUBLE):
2231-
return ZEND_NORMALIZE_BOOL((double)Z_LVAL_P(op1) - Z_DVAL_P(op2));
2226+
return ZEND_THREEWAY_COMPARE((double)Z_LVAL_P(op1), Z_DVAL_P(op2));
22322227

22332228
case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
2234-
if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) {
2235-
return 0;
2236-
} else {
2237-
return ZEND_NORMALIZE_BOOL(Z_DVAL_P(op1) - Z_DVAL_P(op2));
2238-
}
2229+
return ZEND_THREEWAY_COMPARE(Z_DVAL_P(op1), Z_DVAL_P(op2));
22392230

22402231
case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
22412232
return zend_compare_arrays(op1, op2);
@@ -3205,8 +3196,7 @@ ZEND_API int ZEND_FASTCALL zendi_smart_strcmp(zend_string *s1, zend_string *s2)
32053196
* so a numeric comparison would be inaccurate */
32063197
goto string_cmp;
32073198
}
3208-
dval1 = dval1 - dval2;
3209-
return ZEND_NORMALIZE_BOOL(dval1);
3199+
return ZEND_THREEWAY_COMPARE(dval1, dval2);
32103200
} else { /* they both have to be long's */
32113201
return lval1 > lval2 ? 1 : (lval1 < lval2 ? -1 : 0);
32123202
}

0 commit comments

Comments
 (0)