Skip to content

Commit 6e7c225

Browse files
committed
Optimize zend_compare
1 parent 976d7ed commit 6e7c225

File tree

1 file changed

+104
-99
lines changed

1 file changed

+104
-99
lines changed

Zend/zend_operators.c

Lines changed: 104 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ static _locale_t current_locale = NULL;
5555
#define zend_tolower(c) tolower(c)
5656
#endif
5757

58-
#define TYPE_PAIR(t1,t2) (((t1) << 4) | (t2))
58+
#define TYPE_PAIR(t1,t2) ((unsigned char) (((t1) << 4) | (t2)))
5959

6060
#ifdef ZEND_INTRIN_AVX2_NATIVE
6161
#define HAVE_BLOCKCONV
@@ -2164,127 +2164,133 @@ static int compare_double_to_string(double dval, zend_string *str) /* {{{ */
21642164
}
21652165
/* }}} */
21662166

2167-
ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval *op2) /* {{{ */
2167+
static int ZEND_FASTCALL zend_compare_fast(zval *op1, zval *op2, bool converted);
2168+
2169+
static int ZEND_FASTCALL zend_compare_slow(zval *op1, zval *op2, bool converted)
21682170
{
2169-
int converted = 0;
2170-
zval op1_copy, op2_copy;
2171+
if (Z_ISREF_P(op1) || Z_ISREF_P(op2)) {
2172+
ZVAL_DEREF(op1);
2173+
ZVAL_DEREF(op2);
2174+
return zend_compare_fast(op1, op2, converted);
2175+
}
21712176

2172-
while (1) {
2173-
switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
2174-
case TYPE_PAIR(IS_LONG, IS_LONG):
2175-
return Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0);
2177+
if (Z_TYPE_P(op1) == IS_OBJECT
2178+
&& Z_TYPE_P(op2) == IS_OBJECT
2179+
&& Z_OBJ_P(op1) == Z_OBJ_P(op2)) {
2180+
return 0;
2181+
} else if (Z_TYPE_P(op1) == IS_OBJECT) {
2182+
return Z_OBJ_HANDLER_P(op1, compare)(op1, op2);
2183+
} else if (Z_TYPE_P(op2) == IS_OBJECT) {
2184+
return Z_OBJ_HANDLER_P(op2, compare)(op1, op2);
2185+
}
2186+
2187+
if (!converted) {
2188+
if (Z_TYPE_P(op1) < IS_TRUE) {
2189+
return zval_is_true(op2) ? -1 : 0;
2190+
} else if (Z_TYPE_P(op1) == IS_TRUE) {
2191+
return zval_is_true(op2) ? 0 : 1;
2192+
} else if (Z_TYPE_P(op2) < IS_TRUE) {
2193+
return zval_is_true(op1) ? 1 : 0;
2194+
} else if (Z_TYPE_P(op2) == IS_TRUE) {
2195+
return zval_is_true(op1) ? 0 : -1;
2196+
} else {
2197+
zval op1_copy, op2_copy;
2198+
op1 = _zendi_convert_scalar_to_number_silent(op1, &op1_copy);
2199+
op2 = _zendi_convert_scalar_to_number_silent(op2, &op2_copy);
2200+
if (EG(exception)) {
2201+
return 1; /* to stop comparison of arrays */
2202+
}
2203+
return zend_compare_fast(op1, op2, true);
2204+
}
2205+
} else if (Z_TYPE_P(op1)==IS_ARRAY) {
2206+
return 1;
2207+
} else if (Z_TYPE_P(op2)==IS_ARRAY) {
2208+
return -1;
2209+
} else {
2210+
ZEND_UNREACHABLE();
2211+
zend_throw_error(NULL, "Unsupported operand types");
2212+
return 1;
2213+
}
2214+
}
21762215

2177-
case TYPE_PAIR(IS_DOUBLE, IS_LONG):
2178-
return ZEND_THREEWAY_COMPARE(Z_DVAL_P(op1), (double)Z_LVAL_P(op2));
2216+
static inline int ZEND_FASTCALL zend_compare_fast(zval *op1, zval *op2, bool converted)
2217+
{
2218+
switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
2219+
case TYPE_PAIR(IS_LONG, IS_LONG):
2220+
return Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0);
21792221

2180-
case TYPE_PAIR(IS_LONG, IS_DOUBLE):
2181-
return ZEND_THREEWAY_COMPARE((double)Z_LVAL_P(op1), Z_DVAL_P(op2));
2222+
case TYPE_PAIR(IS_DOUBLE, IS_LONG):
2223+
return ZEND_THREEWAY_COMPARE(Z_DVAL_P(op1), (double)Z_LVAL_P(op2));
21822224

2183-
case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
2184-
return ZEND_THREEWAY_COMPARE(Z_DVAL_P(op1), Z_DVAL_P(op2));
2225+
case TYPE_PAIR(IS_LONG, IS_DOUBLE):
2226+
return ZEND_THREEWAY_COMPARE((double)Z_LVAL_P(op1), Z_DVAL_P(op2));
21852227

2186-
case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
2187-
return zend_compare_arrays(op1, op2);
2228+
case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
2229+
return ZEND_THREEWAY_COMPARE(Z_DVAL_P(op1), Z_DVAL_P(op2));
21882230

2189-
case TYPE_PAIR(IS_NULL, IS_NULL):
2190-
case TYPE_PAIR(IS_NULL, IS_FALSE):
2191-
case TYPE_PAIR(IS_FALSE, IS_NULL):
2192-
case TYPE_PAIR(IS_FALSE, IS_FALSE):
2193-
case TYPE_PAIR(IS_TRUE, IS_TRUE):
2194-
return 0;
2231+
case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
2232+
return zend_compare_arrays(op1, op2);
21952233

2196-
case TYPE_PAIR(IS_NULL, IS_TRUE):
2197-
return -1;
2234+
case TYPE_PAIR(IS_NULL, IS_NULL):
2235+
case TYPE_PAIR(IS_NULL, IS_FALSE):
2236+
case TYPE_PAIR(IS_FALSE, IS_NULL):
2237+
case TYPE_PAIR(IS_FALSE, IS_FALSE):
2238+
case TYPE_PAIR(IS_TRUE, IS_TRUE):
2239+
return 0;
21982240

2199-
case TYPE_PAIR(IS_TRUE, IS_NULL):
2200-
return 1;
2241+
case TYPE_PAIR(IS_NULL, IS_TRUE):
2242+
return -1;
22012243

2202-
case TYPE_PAIR(IS_STRING, IS_STRING):
2203-
if (Z_STR_P(op1) == Z_STR_P(op2)) {
2204-
return 0;
2205-
}
2206-
return zendi_smart_strcmp(Z_STR_P(op1), Z_STR_P(op2));
2244+
case TYPE_PAIR(IS_TRUE, IS_NULL):
2245+
return 1;
22072246

2208-
case TYPE_PAIR(IS_NULL, IS_STRING):
2209-
return Z_STRLEN_P(op2) == 0 ? 0 : -1;
2247+
case TYPE_PAIR(IS_STRING, IS_STRING):
2248+
if (Z_STR_P(op1) == Z_STR_P(op2)) {
2249+
return 0;
2250+
}
2251+
return zendi_smart_strcmp(Z_STR_P(op1), Z_STR_P(op2));
22102252

2211-
case TYPE_PAIR(IS_STRING, IS_NULL):
2212-
return Z_STRLEN_P(op1) == 0 ? 0 : 1;
2253+
case TYPE_PAIR(IS_NULL, IS_STRING):
2254+
return Z_STRLEN_P(op2) == 0 ? 0 : -1;
22132255

2214-
case TYPE_PAIR(IS_LONG, IS_STRING):
2215-
return compare_long_to_string(Z_LVAL_P(op1), Z_STR_P(op2));
2256+
case TYPE_PAIR(IS_STRING, IS_NULL):
2257+
return Z_STRLEN_P(op1) == 0 ? 0 : 1;
22162258

2217-
case TYPE_PAIR(IS_STRING, IS_LONG):
2218-
return -compare_long_to_string(Z_LVAL_P(op2), Z_STR_P(op1));
2259+
case TYPE_PAIR(IS_LONG, IS_STRING):
2260+
return compare_long_to_string(Z_LVAL_P(op1), Z_STR_P(op2));
22192261

2220-
case TYPE_PAIR(IS_DOUBLE, IS_STRING):
2221-
if (zend_isnan(Z_DVAL_P(op1))) {
2222-
return 1;
2223-
}
2262+
case TYPE_PAIR(IS_STRING, IS_LONG):
2263+
return -compare_long_to_string(Z_LVAL_P(op2), Z_STR_P(op1));
22242264

2225-
return compare_double_to_string(Z_DVAL_P(op1), Z_STR_P(op2));
2226-
2227-
case TYPE_PAIR(IS_STRING, IS_DOUBLE):
2228-
if (zend_isnan(Z_DVAL_P(op2))) {
2229-
return 1;
2230-
}
2265+
case TYPE_PAIR(IS_DOUBLE, IS_STRING):
2266+
if (zend_isnan(Z_DVAL_P(op1))) {
2267+
return 1;
2268+
}
22312269

2232-
return -compare_double_to_string(Z_DVAL_P(op2), Z_STR_P(op1));
2270+
return compare_double_to_string(Z_DVAL_P(op1), Z_STR_P(op2));
22332271

2234-
case TYPE_PAIR(IS_OBJECT, IS_NULL):
2272+
case TYPE_PAIR(IS_STRING, IS_DOUBLE):
2273+
if (zend_isnan(Z_DVAL_P(op2))) {
22352274
return 1;
2275+
}
22362276

2237-
case TYPE_PAIR(IS_NULL, IS_OBJECT):
2238-
return -1;
2277+
return -compare_double_to_string(Z_DVAL_P(op2), Z_STR_P(op1));
22392278

2240-
default:
2241-
if (Z_ISREF_P(op1)) {
2242-
op1 = Z_REFVAL_P(op1);
2243-
continue;
2244-
} else if (Z_ISREF_P(op2)) {
2245-
op2 = Z_REFVAL_P(op2);
2246-
continue;
2247-
}
2279+
case TYPE_PAIR(IS_OBJECT, IS_NULL):
2280+
return 1;
22482281

2249-
if (Z_TYPE_P(op1) == IS_OBJECT
2250-
&& Z_TYPE_P(op2) == IS_OBJECT
2251-
&& Z_OBJ_P(op1) == Z_OBJ_P(op2)) {
2252-
return 0;
2253-
} else if (Z_TYPE_P(op1) == IS_OBJECT) {
2254-
return Z_OBJ_HANDLER_P(op1, compare)(op1, op2);
2255-
} else if (Z_TYPE_P(op2) == IS_OBJECT) {
2256-
return Z_OBJ_HANDLER_P(op2, compare)(op1, op2);
2257-
}
2282+
case TYPE_PAIR(IS_NULL, IS_OBJECT):
2283+
return -1;
22582284

2259-
if (!converted) {
2260-
if (Z_TYPE_P(op1) < IS_TRUE) {
2261-
return zval_is_true(op2) ? -1 : 0;
2262-
} else if (Z_TYPE_P(op1) == IS_TRUE) {
2263-
return zval_is_true(op2) ? 0 : 1;
2264-
} else if (Z_TYPE_P(op2) < IS_TRUE) {
2265-
return zval_is_true(op1) ? 1 : 0;
2266-
} else if (Z_TYPE_P(op2) == IS_TRUE) {
2267-
return zval_is_true(op1) ? 0 : -1;
2268-
} else {
2269-
op1 = _zendi_convert_scalar_to_number_silent(op1, &op1_copy);
2270-
op2 = _zendi_convert_scalar_to_number_silent(op2, &op2_copy);
2271-
if (EG(exception)) {
2272-
return 1; /* to stop comparison of arrays */
2273-
}
2274-
converted = 1;
2275-
}
2276-
} else if (Z_TYPE_P(op1)==IS_ARRAY) {
2277-
return 1;
2278-
} else if (Z_TYPE_P(op2)==IS_ARRAY) {
2279-
return -1;
2280-
} else {
2281-
ZEND_UNREACHABLE();
2282-
zend_throw_error(NULL, "Unsupported operand types");
2283-
return 1;
2284-
}
2285-
}
2285+
default:
2286+
return zend_compare_slow(op1, op2, converted);
22862287
}
22872288
}
2289+
2290+
ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval *op2) /* {{{ */
2291+
{
2292+
return zend_compare_fast(op1, op2, false);
2293+
}
22882294
/* }}} */
22892295

22902296
/* return int to be compatible with compare_func_t */
@@ -3190,8 +3196,7 @@ ZEND_API int ZEND_FASTCALL zendi_smart_strcmp(zend_string *s1, zend_string *s2)
31903196
* so a numeric comparison would be inaccurate */
31913197
goto string_cmp;
31923198
}
3193-
dval1 = dval1 - dval2;
3194-
return ZEND_NORMALIZE_BOOL(dval1);
3199+
return ZEND_THREEWAY_COMPARE(dval1, dval2);
31953200
} else { /* they both have to be long's */
31963201
return lval1 > lval2 ? 1 : (lval1 < lval2 ? -1 : 0);
31973202
}

0 commit comments

Comments
 (0)