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]