Commit 54ec8c4873c for php

commit 54ec8c4873cabd43696b71c2b80622ee473ccccd
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date:   Mon Nov 9 10:01:14 2026 -0500

    Update IR

    IR commit: 281a66a87aedc4444ca09f696b9b8e9dab89ad32

diff --git a/ext/opcache/jit/ir/dynasm/dasm_arm64.h b/ext/opcache/jit/ir/dynasm/dasm_arm64.h
index df8d5434d3a..2e22434eb5f 100644
--- a/ext/opcache/jit/ir/dynasm/dasm_arm64.h
+++ b/ext/opcache/jit/ir/dynasm/dasm_arm64.h
@@ -487,7 +487,7 @@ int dasm_encode(Dst_DECL, void *buffer)
 	  }
 	  break;
 	case DASM_REL_A: {
-	  ptrdiff_t na = (((ptrdiff_t)(*b++) << 32) | (unsigned int)n);
+	  ptrdiff_t na = (ptrdiff_t)(((unsigned long long)(unsigned int)(*b++) << 32) | (unsigned int)n);
 	  if ((ins & 0x3000) == 0x3000) {  /* ADRP */
 	    ins &= ~0x1000;
 	    na = (na >> 12) - (((ptrdiff_t)cp - 4) >> 12);
diff --git a/ext/opcache/jit/ir/ir.h b/ext/opcache/jit/ir/ir.h
index 74481865e0f..8c2029c03be 100644
--- a/ext/opcache/jit/ir/ir.h
+++ b/ext/opcache/jit/ir/ir.h
@@ -904,11 +904,11 @@ IR_ALWAYS_INLINE void ir_insn_set_op(ir_insn *insn, int32_t n, ir_ref val)
 	*p = val;
 }

-IR_ALWAYS_INLINE uint32_t ir_insn_find_op(const ir_insn *insn, ir_ref val)
+IR_ALWAYS_INLINE uint32_t ir_insn_find_op_ex(const ir_insn *insn, ir_ref val, int start)
 {
 	int i, n = insn->inputs_count;

-	for (i = 1; i <= n; i++) {
+	for (i = start; i <= n; i++) {
 		if (ir_insn_op(insn, i) == val) {
 			return i;
 		}
@@ -916,6 +916,11 @@ IR_ALWAYS_INLINE uint32_t ir_insn_find_op(const ir_insn *insn, ir_ref val)
 	return 0;
 }

+IR_ALWAYS_INLINE uint32_t ir_insn_find_op(const ir_insn *insn, ir_ref val)
+{
+	return ir_insn_find_op_ex(insn, val, 1);
+}
+
 ir_ref ir_fold(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3);

 ir_ref ir_fold0(ir_ctx *ctx, uint32_t opt);
diff --git a/ext/opcache/jit/ir/ir_aarch64.dasc b/ext/opcache/jit/ir/ir_aarch64.dasc
index 965b3e9f745..5f7c3a42e8b 100644
--- a/ext/opcache/jit/ir/ir_aarch64.dasc
+++ b/ext/opcache/jit/ir/ir_aarch64.dasc
@@ -3599,33 +3599,33 @@ static void ir_emit_shift(ir_ctx *ctx, ir_ref def, ir_insn *insn)
 			IR_ASSERT(0);
 		case IR_SHL:
 			if (ir_type_size[type] == 1) {
-				|	and Rw(def_reg), Rw(op1_reg), #0xff
-				|	lsl Rw(def_reg), Rw(def_reg), Rw(op2_reg)
+				|	and Rw(IR_REG_INT_TMP), Rw(op1_reg), #0xff
+				|	lsl Rw(def_reg), Rw(IR_REG_INT_TMP), Rw(op2_reg)
 			} else if (ir_type_size[type] == 2) {
-				|	and Rw(def_reg), Rw(op1_reg), #0xffff
-				|	lsl Rw(def_reg), Rw(def_reg), Rw(op2_reg)
+				|	and Rw(IR_REG_INT_TMP), Rw(op1_reg), #0xffff
+				|	lsl Rw(def_reg), Rw(IR_REG_INT_TMP), Rw(op2_reg)
 			} else {
 				|	ASM_REG_REG_REG_OP lsl, type, def_reg, op1_reg, op2_reg
 			}
 			break;
 		case IR_SHR:
 			if (ir_type_size[type] == 1) {
-				|	and Rw(def_reg), Rw(op1_reg), #0xff
-				|	lsr Rw(def_reg), Rw(def_reg), Rw(op2_reg)
+				|	and Rw(IR_REG_INT_TMP), Rw(op1_reg), #0xff
+				|	lsr Rw(def_reg), Rw(IR_REG_INT_TMP), Rw(op2_reg)
 			} else if (ir_type_size[type] == 2) {
-				|	and Rw(def_reg), Rw(op1_reg), #0xffff
-				|	lsr Rw(def_reg), Rw(def_reg), Rw(op2_reg)
+				|	and Rw(IR_REG_INT_TMP), Rw(op1_reg), #0xffff
+				|	lsr Rw(def_reg), Rw(IR_REG_INT_TMP), Rw(op2_reg)
 			} else {
 				|	ASM_REG_REG_REG_OP lsr, type, def_reg, op1_reg, op2_reg
 			}
 			break;
 		case IR_SAR:
 			if (ir_type_size[type] == 1) {
-				|	sxtb Rw(def_reg), Rw(op1_reg)
-				|	asr Rw(def_reg), Rw(def_reg), Rw(op2_reg)
+				|	sxtb Rw(IR_REG_INT_TMP), Rw(op1_reg)
+				|	asr Rw(def_reg), Rw(IR_REG_INT_TMP), Rw(op2_reg)
 			} else if (ir_type_size[type] == 2) {
-				|	sxth Rw(def_reg), Rw(op1_reg)
-				|	asr Rw(def_reg), Rw(def_reg), Rw(op2_reg)
+				|	sxth Rw(IR_REG_INT_TMP), Rw(op1_reg)
+				|	asr Rw(def_reg), Rw(IR_REG_INT_TMP), Rw(op2_reg)
 			} else {
 				|	ASM_REG_REG_REG_OP asr, type, def_reg, op1_reg, op2_reg
 			}
@@ -6432,8 +6432,10 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, const i
 		}
 		if (dst_reg != IR_REG_NONE) {
 			if (IR_IS_CONST_REF(arg) ||
-			    src_reg == IR_REG_NONE ||
-			    (IR_REG_SPILLED(src_reg) && !IR_REGSET_IN(cc->preserved_regs, IR_REG_NUM(src_reg)))) {
+				src_reg == IR_REG_NONE ||
+				(IR_REG_SPILLED(src_reg) &&
+					!IR_REGSET_IN(cc->preserved_regs, IR_REG_NUM(src_reg)) &&
+					ir_insn_find_op_ex(insn, arg, j + 1) == 0)) {
 				/* delay CONST->REG and MEM->REG moves to third pass */
 				do_pass3 = 1;
 			} else {
@@ -6519,8 +6521,10 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, const i
 			}
 			if (dst_reg != IR_REG_NONE) {
 				if (IR_IS_CONST_REF(arg) ||
-				    src_reg == IR_REG_NONE ||
-				    (IR_REG_SPILLED(src_reg) && !IR_REGSET_IN(cc->preserved_regs, IR_REG_NUM(src_reg)))) {
+					src_reg == IR_REG_NONE ||
+					(IR_REG_SPILLED(src_reg) &&
+						!IR_REGSET_IN(cc->preserved_regs, IR_REG_NUM(src_reg)) &&
+						ir_insn_find_op_ex(insn, arg, j + 1) == 0)) {
 					if (IR_IS_CONST_REF(arg) && IR_IS_TYPE_INT(type)) {
 						if (ir_type_size[type] == 1) {
 							type = IR_ADDR;
@@ -10001,7 +10005,7 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr)
 	if (ctx->code_buffer) {
 		entry = ctx->code_buffer->pos;
 		entry = (void*)IR_ALIGNED_SIZE(((size_t)(entry)), 16);
-		if (size > (size_t)((char*)ctx->code_buffer->end - (char*)entry)) {
+		if ((char*)entry > (char*)ctx->code_buffer->end || size > (size_t)((char*)ctx->code_buffer->end - (char*)entry)) {
 			dasm_free(&data.dasm_state);
 			ctx->data = NULL;
 			ctx->status = IR_ERROR_CODE_MEM_OVERFLOW;
@@ -10144,7 +10148,7 @@ const void *ir_emit_exitgroup(uint32_t first_exit_point, uint32_t exit_points_pe

 	entry = code_buffer->pos;
 	entry = (void*)IR_ALIGNED_SIZE(((size_t)(entry)), 16);
-	if (size > (size_t)((char*)code_buffer->end - (char*)entry)) {
+	if ((char*)entry > (char*)code_buffer->end || size > (size_t)((char*)code_buffer->end - (char*)entry)) {
 		dasm_free(&dasm_state);
 		return NULL;
 	}
@@ -10314,7 +10318,7 @@ void *ir_emit_thunk(ir_code_buffer *code_buffer, void *addr, size_t *size_ptr)

 	entry = code_buffer->pos;
 	entry = (void*)IR_ALIGNED_SIZE(((size_t)(entry)), 4);
-	if (size > (size_t)((char*)code_buffer->end - (char*)entry)) {
+	if ((char*)entry > (char*)code_buffer->end || size > (size_t)((char*)code_buffer->end - (char*)entry)) {
 		*size_ptr = size;
 		dasm_free(&dasm_state);
 		return NULL;
diff --git a/ext/opcache/jit/ir/ir_emit.c b/ext/opcache/jit/ir/ir_emit.c
index de6b53141a6..c53372d0ba3 100644
--- a/ext/opcache/jit/ir/ir_emit.c
+++ b/ext/opcache/jit/ir/ir_emit.c
@@ -968,30 +968,95 @@ static int ir_dessa_parallel_copy(ir_ctx *ctx, ir_dessa_copy *copies, int count,
 	}

 	/* finally we resolve remaining "windmill blades" - trees that set temporary registers */
-	ir_bitset_copy(ready, todo, len);
-	ir_bitset_difference(ready, srcs, len);
-	while ((to = ir_bitset_pop_first(ready, len)) >= 0) {
-		ir_bitset_excl(todo, to);
-		type = types[to];
-		from = pred[to];
-#ifdef IR_DEBUG
-		/* If destionation is set, it can't be used as temporary anymore */
-		if (to == tmp_reg) {
-			tmp_reg = IR_REG_NONE;
-		}
-		if (to == tmp_fp_reg) {
-			tmp_fp_reg = IR_REG_NONE;
+	if (tmp_reg != IR_REG_NONE && ir_bitset_in(todo, tmp_reg)) {
+		ir_mem tmp_spill_slot;
+		ir_type tmp_type;
+
+		ir_bitset_clear(ready, len);
+		to = tmp_reg;
+		tmp_type = types[to];
+		IR_MEM_VAL(tmp_spill_slot) = 0;
+		do {
+			ir_bitset_excl(todo, to);
+			type = types[to];
+			from = pred[to];
+			if (IR_IS_CONST_REF(from)) {
+				if (to >= IR_REG_NUM) {
+					/* Immediate to memory move inside a "blocked" blade requres an additional temporary register */
+					if (!IR_MEM_VAL(tmp_spill_slot)) {
+						/* Free a register, saving it in a temporary spill slot */
+						tmp_spill_slot = IR_MEM_BO(IR_REG_STACK_POINTER, -16);
+						ir_emit_store_mem(ctx, tmp_type, tmp_spill_slot, tmp_reg);
+					}
+				}
+				ir_emit_dessa_move(ctx, mem_slots, type, to, from, tmp_reg, tmp_fp_reg);
+			} else {
+				int32_t r = loc[from];
+
+				/* Memory to memory move inside a "blocked" blade requres an additional temporary register */
+				if (to >= IR_REG_NUM && r >= IR_REG_NUM) {
+					if (!IR_MEM_VAL(tmp_spill_slot)) {
+						/* Free a register, saving it in a temporary spill slot */
+						tmp_spill_slot = IR_MEM_BO(IR_REG_STACK_POINTER, -16);
+						ir_emit_store_mem(ctx, tmp_type, tmp_spill_slot, tmp_reg);
+					}
+				}
+				ir_emit_dessa_move(ctx, mem_slots, type, to, r, tmp_reg, tmp_fp_reg);
+				loc[from] = to;
+				if (from == r && ir_bitset_in(todo, from)) {
+					ir_bitset_incl(ready, from);
+				}
+			}
+		} while ((to = ir_bitset_pop_first(ready, len)) >= 0);
+
+		if (IR_MEM_VAL(tmp_spill_slot)) {
+			ir_emit_load_mem(ctx, tmp_type, tmp_reg, tmp_spill_slot);
 		}
-#endif
-		if (IR_IS_CONST_REF(from)) {
-			ir_emit_dessa_move(ctx, mem_slots, type, to, from, tmp_reg, tmp_fp_reg);
-		} else {
-			int32_t r = loc[from];
-			ir_emit_dessa_move(ctx, mem_slots, type, to, r, tmp_reg, tmp_fp_reg);
-			loc[from] = to;
-			if (from == r && ir_bitset_in(todo, from)) {
-				ir_bitset_incl(ready, from);
+	}
+
+	if (tmp_fp_reg != IR_REG_NONE && ir_bitset_in(todo, tmp_fp_reg)) {
+		ir_mem tmp_spill_slot;
+		ir_type tmp_type;
+
+		ir_bitset_clear(ready, len);
+		to = tmp_fp_reg;
+		tmp_type = types[to];
+		IR_MEM_VAL(tmp_spill_slot) = 0;
+		do {
+			ir_bitset_excl(todo, to);
+			type = types[to];
+			from = pred[to];
+			if (IR_IS_CONST_REF(from)) {
+				/* Immediate to memory move inside a "blocked" blade requres an additional temporary register */
+				if (to >= IR_REG_NUM) {
+					if (!IR_MEM_VAL(tmp_spill_slot)) {
+						/* Free a register, saving it in a temporary spill slot */
+						tmp_spill_slot = IR_MEM_BO(IR_REG_STACK_POINTER, -16);
+						ir_emit_store_mem(ctx, tmp_type, tmp_spill_slot, tmp_fp_reg);
+					}
+				}
+				ir_emit_dessa_move(ctx, mem_slots, type, to, from, tmp_reg, tmp_fp_reg);
+			} else {
+				int32_t r = loc[from];
+
+				/* Memory to memory move inside a "blocked" blade requres an additional temporary register */
+				if (to >= IR_REG_NUM && r >= IR_REG_NUM) {
+					if (!IR_MEM_VAL(tmp_spill_slot)) {
+						/* Free a register, saving it in a temporary spill slot */
+						tmp_spill_slot = IR_MEM_BO(IR_REG_STACK_POINTER, -16);
+						ir_emit_store_mem(ctx, tmp_type, tmp_spill_slot, tmp_fp_reg);
+					}
+				}
+				ir_emit_dessa_move(ctx, mem_slots, type, to, r, tmp_reg, tmp_fp_reg);
+				loc[from] = to;
+				if (from == r && ir_bitset_in(todo, from)) {
+					ir_bitset_incl(ready, from);
+				}
 			}
+		} while ((to = ir_bitset_pop_first(ready, len)) >= 0);
+
+		if (IR_MEM_VAL(tmp_spill_slot)) {
+			ir_emit_load_mem(ctx, tmp_type, tmp_fp_reg, tmp_spill_slot);
 		}
 	}

diff --git a/ext/opcache/jit/ir/ir_fold.h b/ext/opcache/jit/ir/ir_fold.h
index c8292191b5e..962668b9bc6 100644
--- a/ext/opcache/jit/ir/ir_fold.h
+++ b/ext/opcache/jit/ir/ir_fold.h
@@ -4275,7 +4275,7 @@ IR_FOLD(ULE(_, _))
 IR_FOLD(UGT(_, _))
 {
 	if (op1 == op2) {
-		if (IR_IS_TYPE_SCALAR(IR_OPT_TYPE(opt))) {
+		if (IR_IS_TYPE_INT(op1_insn->type)) {
 			/* a >= a => true (two low bits are differ) */
 			IR_FOLD_BOOL((opt ^ (opt >> 1)) & 1);
 		}
diff --git a/ext/opcache/jit/ir/ir_private.h b/ext/opcache/jit/ir/ir_private.h
index 9f91fbfba9f..5bca99a50c9 100644
--- a/ext/opcache/jit/ir/ir_private.h
+++ b/ext/opcache/jit/ir/ir_private.h
@@ -901,7 +901,7 @@ extern const uint8_t ir_type_size[IR_LAST_TYPE];

 IR_ALWAYS_INLINE ir_type ir_make_vector_type(ir_type base, uint8_t length)
 {
-	IR_ASSERT(IR_IS_TYPE_SCALAR(base) && length > 0 && length <= 64 && (length & (length - 1)) == 0);
+	IR_ASSERT(IR_IS_TYPE_SCALAR(base) && base != IR_ADDR && length > 0 && length <= 64 && (length & (length - 1)) == 0);

 	if (base == IR_CHAR) {
 		base = IR_I8;
diff --git a/ext/opcache/jit/ir/ir_ra.c b/ext/opcache/jit/ir/ir_ra.c
index f8d418d0614..886413ecf84 100644
--- a/ext/opcache/jit/ir/ir_ra.c
+++ b/ext/opcache/jit/ir/ir_ra.c
@@ -837,7 +837,7 @@ int ir_compute_live_ranges(ir_ctx *ctx)
 					ival = ctx->live_intervals[v];
 					if (UNEXPECTED(!ival)) {
 						/* Dead PHI */
-						ival = ir_add_live_range(ctx, v, IR_DEF_LIVE_POS_FROM_REF(ref), IR_USE_LIVE_POS_FROM_REF(ref));
+						ival = ir_add_live_range(ctx, v, IR_START_LIVE_POS_FROM_REF(bb->start), IR_SAVE_LIVE_POS_FROM_REF(ref));
 					}
 					ival->type = insn->type;
 					ir_add_use(ctx, ival, 0, IR_DEF_LIVE_POS_FROM_REF(ref), IR_REG_NONE, IR_USE_SHOULD_BE_IN_REG, 0);
@@ -1554,7 +1554,7 @@ int ir_compute_live_ranges(ir_ctx *ctx)
 					ival = ctx->live_intervals[v];
 					if (UNEXPECTED(!ival)) {
 						/* Dead PHI */
-						ival = ir_add_live_range(ctx, v, IR_DEF_LIVE_POS_FROM_REF(ref), IR_USE_LIVE_POS_FROM_REF(ref));
+						ival = ir_add_live_range(ctx, v, IR_START_LIVE_POS_FROM_REF(bb->start), IR_SAVE_LIVE_POS_FROM_REF(ref));
 					}
 					ival->type = insn->type;
 					ir_add_use(ctx, ival, 0, IR_DEF_LIVE_POS_FROM_REF(ref), IR_REG_NONE, IR_USE_SHOULD_BE_IN_REG, 0);
diff --git a/ext/opcache/jit/ir/ir_sccp.c b/ext/opcache/jit/ir/ir_sccp.c
index 2ca202add5e..8818a667f6f 100644
--- a/ext/opcache/jit/ir/ir_sccp.c
+++ b/ext/opcache/jit/ir/ir_sccp.c
@@ -2228,6 +2228,10 @@ static bool ir_try_promote_induction_var_ext(ir_ctx *ctx, ir_ref ext_ref, ir_ref
 				const ir_insn *use_insn = &ctx->ir_base[use];

 				if (use_insn->op >= IR_EQ && use_insn->op <= IR_UGT) {
+					if (op == IR_ZEXT && use_insn->op >= IR_LT && use_insn->op <= IR_GT) {
+						/* Zero extension may reset the sign bit and change the result of signed comparison */
+						return 0;
+					}
 					if (use_insn->op1 == phi_ref) {
 						if (IR_IS_TYPE_SIGNED(type) != IR_IS_TYPE_SIGNED(ctx->ir_base[use_insn->op2].type)) {
 							return 0;
@@ -2267,6 +2271,10 @@ static bool ir_try_promote_induction_var_ext(ir_ctx *ctx, ir_ref ext_ref, ir_ref
 				const ir_insn *use_insn = &ctx->ir_base[use];

 				if (use_insn->op >= IR_EQ && use_insn->op <= IR_UGT) {
+					if (op == IR_ZEXT && use_insn->op >= IR_LT && use_insn->op <= IR_GT) {
+						/* Zero extension may reset the sign bit and change the result of signed comparison */
+						return 0;
+					}
 					if (use_insn->op1 == op_ref) {
 						if (IR_IS_TYPE_SIGNED(type) != IR_IS_TYPE_SIGNED(ctx->ir_base[use_insn->op2].type)) {
 							return 0;
diff --git a/ext/opcache/jit/ir/ir_x86.dasc b/ext/opcache/jit/ir/ir_x86.dasc
index 463be9e750d..aa4e6e3da52 100644
--- a/ext/opcache/jit/ir/ir_x86.dasc
+++ b/ext/opcache/jit/ir/ir_x86.dasc
@@ -7731,6 +7731,15 @@ static void ir_emit_shift(ir_ctx *ctx, ir_ref def, ir_insn *insn)
 	IR_ASSERT(def_reg != IR_REG_NONE && def_reg != IR_REG_RCX);
 	if (op1_reg != IR_REG_NONE && IR_REG_SPILLED(op1_reg)) {
 		op1_reg = IR_REG_NUM(op1_reg);
+		/* in case op1_reg and op2_reg are the same - op2 should be moved to %rcx, then op1 loaded from spill slot */
+		if (op2_reg != IR_REG_NONE && op1_reg == IR_REG_NUM(op2_reg) && insn->op1 != insn->op2) {
+			if (IR_REG_SPILLED(op2_reg)) {
+				ir_emit_load(ctx, type, IR_REG_RCX, insn->op2);
+			} else if (op2_reg != IR_REG_RCX) {
+				ir_emit_mov(ctx, type, IR_REG_RCX, op2_reg);
+			}
+			op2_reg = IR_REG_RCX;
+		}
 		ir_emit_load(ctx, type, op1_reg, insn->op1);
 	}
 	if (op2_reg != IR_REG_NONE && IR_REG_SPILLED(op2_reg)) {
@@ -13467,8 +13476,10 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, const i
 		}
 		if (dst_reg != IR_REG_NONE) {
 			if (IR_IS_CONST_REF(arg) ||
-			    src_reg == IR_REG_NONE ||
-			    (IR_REG_SPILLED(src_reg) && !IR_REGSET_IN(cc->preserved_regs, IR_REG_NUM(src_reg)))) {
+				src_reg == IR_REG_NONE ||
+				(IR_REG_SPILLED(src_reg) &&
+					!IR_REGSET_IN(cc->preserved_regs, IR_REG_NUM(src_reg)) &&
+					ir_insn_find_op_ex(insn, arg, j + 1) == 0)) {
 				/* delay CONST->REG and MEM->REG moves to third pass */
 				do_pass3 = 1;
 			} else {
@@ -13600,8 +13611,10 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, const i
 			}
 			if (dst_reg != IR_REG_NONE) {
 				if (IR_IS_CONST_REF(arg) ||
-				    src_reg == IR_REG_NONE ||
-				    (IR_REG_SPILLED(src_reg) && !IR_REGSET_IN(cc->preserved_regs, IR_REG_NUM(src_reg)))) {
+					src_reg == IR_REG_NONE ||
+					(IR_REG_SPILLED(src_reg) &&
+					    !IR_REGSET_IN(cc->preserved_regs, IR_REG_NUM(src_reg)) &&
+						ir_insn_find_op_ex(insn, arg, j + 1) == 0)) {
 					if (IR_IS_TYPE_INT(type)) {
 						if (IR_IS_CONST_REF(arg)) {
 							if (type == IR_I8 || type == IR_I16) {
@@ -27566,7 +27579,7 @@ next_block:;
 	if (ctx->code_buffer) {
 		entry = ctx->code_buffer->pos;
 		entry = (void*)IR_ALIGNED_SIZE(((size_t)(entry)), required_alignment);
-		if (size > (size_t)((char*)ctx->code_buffer->end - (char*)entry)) {
+		if ((char*)entry > (char*)ctx->code_buffer->end || size > (size_t)((char*)ctx->code_buffer->end - (char*)entry)) {
 			dasm_free(&data.dasm_state);
 			ctx->data = NULL;
 			ctx->status = IR_ERROR_CODE_MEM_OVERFLOW;
@@ -27650,7 +27663,7 @@ next_block:;

 	ir_mem_flush(entry, size);

-#if defined(__GNUC__)
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
 	if ((ctx->flags & IR_GEN_CACHE_DEMOTE) && (ctx->mflags & IR_X86_CLDEMOTE)) {
 		uintptr_t start = (uintptr_t)entry;
 		uintptr_t p = (uintptr_t)start & ~0x3F;
@@ -27706,7 +27719,7 @@ const void *ir_emit_exitgroup(uint32_t first_exit_point, uint32_t exit_points_pe

 	entry = code_buffer->pos;
 	entry = (void*)IR_ALIGNED_SIZE(((size_t)(entry)), 16);
-	if (size > (size_t)((char*)code_buffer->end - (char*)entry)) {
+	if ((char*)entry > (char*)code_buffer->end || size > (size_t)((char*)code_buffer->end - (char*)entry)) {
 		dasm_free(&dasm_state);
 		return NULL;
 	}