Commit 17bb27b6ee0 for php

commit 17bb27b6ee08bef42aaf905a9039fa299e1b7eb8
Merge: 2581b6e7c2c c39a7f5e560
Author: ndossche <7771979+ndossche@users.noreply.github.com>
Date:   Sun Nov 8 11:31:22 2026 +0100

    Merge branch 'PHP-8.5' into PHP-8.6

    * PHP-8.5:
      Fix GH-25037: Function JIT ENTRY live var assertion
      IR: Backport fix for SIGFPE when folding MUL_OV of -1 by INT64_MIN
      IR: Backport fix for incorrect operand copy in AND/OR/MIN/MAX folding

diff --cc NEWS
index 547794bcf22,fde52abd24d..3f37b9b6b77
--- a/NEWS
+++ b/NEWS
@@@ -29,13 -26,11 +29,17 @@@ PH
    . Fixed memory leak in JIT ASSIGN_DIM when the assignment fails. (Jorg Sowa)
    . Fixed bug GH-16396 (Failed to invoke user error handler during index
      conversion in JIT). (Jorg Sowa)
+   . Fixed bug GH-24801 (JIT: SIGFPE in ir_fold MUL_OV constant folding).
+     (waroad)
+   . Fixed bug GH-25037 (Function JIT ENTRY live var assertion).
+     (Ilia Alshanetsky)

 +- OpenSSL:
 +  . Fixed bug GH-25172 (TLS session reuse shares request-lifetime callback
 +    structures with persistent streams). (cxxz16, David Carlier)
 +  . Fixed an exception thrown by the session_get_cb stream context callback
 +    being replaced with a TypeError. (Ilia Alshanetsky)
 +
  - SOAP:
    . Fixed bug GH-25267 (NULL dereference in to_xml_any() with integer key).
      (lazerg)
diff --cc ext/opcache/jit/ir/ir_cfg.c
index 4e4db166d37,0d6eeb8b84d..49b378bc7e8
--- a/ext/opcache/jit/ir/ir_cfg.c
+++ b/ext/opcache/jit/ir/ir_cfg.c
@@@ -1102,10 -1083,35 +1102,37 @@@ static IR_NEVER_INLINE uint32_t ir_coll
  			}
  		}
  	}
 +
 +	return loops;
  }

+ static IR_NEVER_INLINE void ir_check_loop_entry_in_preds(ir_ctx *ctx, uint32_t hdr, ir_worklist *work)
+ {
+ 	ir_block *blocks = ctx->cfg_blocks;
+ 	uint32_t *edges = ctx->cfg_edges;
+
+ 	ir_worklist_clear(work);
+ 	ir_bitset_incl(work->visited, blocks[hdr].idom);
+ 	ir_worklist_push(work, hdr);
+ 	while (ir_worklist_len(work)) {
+ 		ir_block *bb = &blocks[ir_worklist_pop(work)];
+
+ 		if (bb->flags & IR_BB_ENTRY) {
+ 			blocks[hdr].flags |= IR_BB_LOOP_WITH_ENTRY_IN_PREDS;
+ 			break;
+ 		}
+
+ 		uint32_t *p = &edges[bb->predecessors];
+ 		uint32_t count = bb->predecessors_count;
+
+ 		for (; count > 0; p++, count--) {
+ 			if (!ir_dominates(blocks, hdr, *p)) {
+ 				ir_worklist_push(work, *p);
+ 			}
+ 		}
+ 	}
+ }
+
  int ir_find_loops(ir_ctx *ctx)
  {
  	uint32_t b, j, n;
@@@ -1288,44 -1280,43 +1315,50 @@@ next
  		ir_list_free(&irreducible_list);
  	}

 -	if (ctx->flags2 & IR_CFG_HAS_LOOPS) {
 +	if (loops) {
 +		ir_block *bb;
 +
 +		/* Set loop_depth for loop headers */
 +		b = loops;
 +		do {
 +			bb = &blocks[b];
 +			b = bb->next_loop;
 +			IR_ASSERT(bb->flags & IR_BB_LOOP_HEADER);
 +			bb->loop_depth = (bb->loop_header) ? blocks[bb->loop_header].loop_depth + 1 : 1;
 +		} while (b);
 +
 +		/* Set loop_depth for loop members */
  		n = ctx->cfg_blocks_count + 1;
 -		for (j = 1; j < n; j++) {
 -			b = sorted_blocks[j];
 -			ir_block *bb = &blocks[b];
 -			if (bb->loop_header > 0) {
 -				ir_block *loop = &blocks[bb->loop_header];
 -				uint32_t loop_depth = loop->loop_depth;
 -
 -				if (bb->flags & IR_BB_LOOP_HEADER) {
 -					loop_depth++;
 +		for (j = 1, bb = blocks + 1; j < n; bb++, j++) {
 +			if (bb->loop_header) {
 +				if (!(bb->flags & IR_BB_LOOP_HEADER)) {
 +					bb->loop_depth = blocks[bb->loop_header].loop_depth;
  				}
 -				bb->loop_depth = loop_depth;
 -				if (bb->flags & (IR_BB_ENTRY|IR_BB_LOOP_WITH_ENTRY)) {
 -					loop->flags |= IR_BB_LOOP_WITH_ENTRY;
 -					if (loop_depth > 1) {
 -						/* Set IR_BB_LOOP_WITH_ENTRY flag for all the enclosing loops */
 -						bb = &blocks[loop->loop_header];
 -						while (1) {
 -							if (bb->flags & IR_BB_LOOP_WITH_ENTRY) {
 -								break;
 -							}
 -							bb->flags |= IR_BB_LOOP_WITH_ENTRY;
 -							if (bb->loop_depth == 1) {
 -								break;
 -							}
 -							bb = &blocks[loop->loop_header];
 -						}
 +				if (bb->flags & IR_BB_ENTRY) {
 +					if (bb->flags & IR_BB_LOOP_HEADER) {
 +						bb->flags |= IR_BB_LOOP_WITH_ENTRY;
  					}
 +					/* Set IR_BB_LOOP_WITH_ENTRY flag for all the enclosing loops */
 +					b = bb->loop_header;
 +					do {
 +						ir_block *loop = &blocks[b];
 +						if (loop->flags & IR_BB_LOOP_WITH_ENTRY) {
 +							break;
 +						}
 +						loop->flags |= IR_BB_LOOP_WITH_ENTRY;
 +						b = loop->loop_header;
 +					} while (b);
  				}
 +			} else if ((bb->flags & (IR_BB_LOOP_HEADER|IR_BB_ENTRY|IR_BB_LOOP_WITH_ENTRY)) ==
 +					(IR_BB_LOOP_HEADER|IR_BB_ENTRY)) {
 +				bb->flags |= IR_BB_LOOP_WITH_ENTRY;
  			}
+ 			bb = &blocks[b];
+ 			if (ctx->entries_count
+ 			 && (bb->flags & (IR_BB_LOOP_HEADER|IR_BB_LOOP_WITH_ENTRY)) == IR_BB_LOOP_HEADER
+ 			 && (bb->predecessors_count > 2 || (bb->flags & IR_BB_IRREDUCIBLE_LOOP))) {
+ 				ir_check_loop_entry_in_preds(ctx, b, &work);
+ 			}
  		}
  	}

diff --cc ext/opcache/jit/ir/ir_private.h
index b4409f97df7,25edb4bc41a..16cbacbbd52
--- a/ext/opcache/jit/ir/ir_private.h
+++ b/ext/opcache/jit/ir/ir_private.h
@@@ -1157,29 -1115,26 +1157,30 @@@ void ir_iter_cleanup(ir_ctx *ctx)
  #define IR_IS_BB_END(op) \
  	((ir_op_flags[op] & IR_OP_FLAG_BB_END) != 0)

 -#define IR_BB_UNREACHABLE      (1<<0)
 -#define IR_BB_START            (1<<1)
 -#define IR_BB_ENTRY            (1<<2)
 -#define IR_BB_LOOP_HEADER      (1<<3)
 -#define IR_BB_IRREDUCIBLE_LOOP (1<<4)
 -#define IR_BB_DESSA_MOVES      (1<<5) /* translation out of SSA requires MOVEs */
 -#define IR_BB_EMPTY            (1<<6)
 -#define IR_BB_PREV_EMPTY_ENTRY (1<<7)
 -#define IR_BB_OSR_ENTRY_LOADS  (1<<8) /* OSR Entry-point with register LOADs   */
 -#define IR_BB_LOOP_WITH_ENTRY  (1<<9) /* set together with LOOP_HEADER if there is an ENTRY in the loop */
 +#define IR_BB_UNREACHABLE       (1<<0)
 +#define IR_BB_START             (1<<1)
 +#define IR_BB_ENTRY             (1<<2)
 +#define IR_BB_LOOP_HEADER       (1<<3)
 +#define IR_BB_IRREDUCIBLE_LOOP  (1<<4)
 +#define IR_BB_IRREDUCIBLE_ENTRY (1<<5)
 +#define IR_BB_DESSA_MOVES       (1<<6) /* translation out of SSA requires MOVEs */
 +#define IR_BB_EMPTY             (1<<7)
 +#define IR_BB_PREV_EMPTY_ENTRY  (1<<8)
 +#define IR_BB_OSR_ENTRY_LOADS   (1<<9) /* OSR Entry-point with register LOADs   */
 +#define IR_BB_LOOP_WITH_ENTRY   (1<<10) /* set together with LOOP_HEADER if there is an ENTRY in the loop */
+ #define IR_BB_LOOP_WITH_ENTRY_IN_PREDS (1<<18) /* set together with LOOP_HEADER if an ENTRY reaches the loop bypassing its immediate dominator */

  /* The following flags are set by GCM */
 -#define IR_BB_HAS_PHI          (1<<10)
 -#define IR_BB_HAS_PI           (1<<11)
 -#define IR_BB_HAS_PARAM        (1<<12)
 -#define IR_BB_HAS_VAR          (1<<13)
 +#define IR_BB_HAS_PHI           (1<<11)
 +#define IR_BB_HAS_PI            (1<<12)
 +#define IR_BB_HAS_PARAM         (1<<13)
 +#define IR_BB_HAS_VAR           (1<<14)

  /* The following flags are set by BB scheduler */
 -#define IR_BB_ALIGN_LOOP       (1<<14)
 +#define IR_BB_ALIGN_LOOP        (1<<15)
 +
 +#define IR_BB_DESSA_TMP_INT     (1<<16) /* translation out of SSA may need temporary genral purpose register */
 +#define IR_BB_DESSA_TMP_FP      (1<<17) /* translation out of SSA may need temporary floating point register */

  struct _ir_block {
  	uint32_t flags;