Commit 8a27db05fda for php
commit 8a27db05fdaa3df4a7310ba02d6f55e84fe5dff6
Author: ndossche <7771979+ndossche@users.noreply.github.com>
Date: Sat Oct 3 15:26:32 2026 +0200
Add range inference for SPACESHIP
The result of <=> is always -1, 0 or 1.
Object comparison can technically violate this, so add an assertion.
diff --git a/Zend/Optimizer/zend_inference.c b/Zend/Optimizer/zend_inference.c
index 9ffc3157130..9b46134a7ba 100644
--- a/Zend/Optimizer/zend_inference.c
+++ b/Zend/Optimizer/zend_inference.c
@@ -1536,6 +1536,10 @@ ZEND_API bool zend_inference_propagate_range(const zend_op_array *op_array, cons
tmp->min = 0;
tmp->max = ZEND_LONG_MAX;
return 1;
+ case ZEND_SPACESHIP:
+ tmp->min = -1;
+ tmp->max = 1;
+ return 1;
case ZEND_COUNT:
/* count() on Countable objects may return negative numbers */
tmp->min = ZEND_LONG_MIN;
diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c
index 94c05fcee8c..9f1e18b5ca4 100644
--- a/Zend/zend_operators.c
+++ b/Zend/zend_operators.c
@@ -2318,7 +2318,9 @@ ZEND_API int ZEND_FASTCALL numeric_compare_function(const zval *op1, const zval
ZEND_API zend_result ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
{
- ZVAL_LONG(result, zend_compare(op1, op2));
+ int rv = zend_compare(op1, op2);
+ ZEND_ASSERT(-1 <= rv && rv <= 1);
+ ZVAL_LONG(result, rv);
return SUCCESS;
}
/* }}} */
diff --git a/ext/opcache/tests/opt/spaceship_range.phpt b/ext/opcache/tests/opt/spaceship_range.phpt
new file mode 100644
index 00000000000..9d79429a287
--- /dev/null
+++ b/ext/opcache/tests/opt/spaceship_range.phpt
@@ -0,0 +1,42 @@
+--TEST--
+Range inference for SPACESHIP
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+opcache.opt_debug_level=0x400000
+opcache.preload=
+--EXTENSIONS--
+opcache
+--FILE--
+<?php
+function test($a, $b) {
+ return ($a <=> $b) + 1;
+}
+?>
+--EXPECTF--
+$_main:
+ ; (lines=1, args=0, vars=0, tmps=%d, ssa_vars=0, no_loops)
+ ; (after dfa pass)
+ ; %s
+ ; return [long] RANGE[1..1]
+BB0:
+ ; start exit lines=[0-0]
+ ; level=0
+0000 RETURN int(1)
+
+test:
+ ; (lines=5, args=2, vars=2, tmps=%d, ssa_vars=6, no_loops)
+ ; (after dfa pass)
+ ; %s
+ ; return [long] RANGE[0..2]
+ ; #0.CV0($a) NOVAL [undef]
+ ; #1.CV1($b) NOVAL [undef]
+BB0:
+ ; start exit lines=[0-4]
+ ; level=0
+0000 #2.CV0($a) [any] = RECV 1
+0001 #3.CV1($b) [any] = RECV 2
+0002 #4.T2 [long] RANGE[-1..1] = SPACESHIP #2.CV0($a) [any] #3.CV1($b) [any]
+0003 #5.T3 [long] RANGE[0..2] = ADD #4.T2 [long] RANGE[-1..1] int(1)
+0004 RETURN #5.T3 [long] RANGE[0..2]