diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 8186f206dfe37..6525964428f8f 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -4408,6 +4408,7 @@ static int zend_jit_math_long_long(dasm_State **Dst, uint32_t res_use_info, int may_overflow) { + bool must_set_cflags = 0; bool same_ops = zend_jit_same_addr(op1_addr, op2_addr); zend_reg result_reg; zend_reg tmp_reg = ZREG_R0; @@ -4430,10 +4431,39 @@ static int zend_jit_math_long_long(dasm_State **Dst, tmp_reg = ZREG_FCARG1; } + if (may_overflow) { + must_set_cflags = 1; + } else { + const zend_op *next_opline = opline + 1; + + if (next_opline->opcode == ZEND_IS_EQUAL || + next_opline->opcode == ZEND_IS_NOT_EQUAL || + next_opline->opcode == ZEND_IS_SMALLER || + next_opline->opcode == ZEND_IS_SMALLER_OR_EQUAL || + next_opline->opcode == ZEND_CASE || + next_opline->opcode == ZEND_IS_IDENTICAL || + next_opline->opcode == ZEND_IS_NOT_IDENTICAL || + next_opline->opcode == ZEND_CASE_STRICT) { + if (next_opline->op1_type == IS_CONST + && Z_TYPE_P(RT_CONSTANT(next_opline, next_opline->op1)) == IS_LONG + && Z_LVAL_P(RT_CONSTANT(next_opline, next_opline->op1)) == 0 + && next_opline->op2_type == opline->result_type + && next_opline->op2.var == opline->result.var) { + must_set_cflags = 1; + } else if (next_opline->op2_type == IS_CONST + && Z_TYPE_P(RT_CONSTANT(next_opline, next_opline->op2)) == IS_LONG + && Z_LVAL_P(RT_CONSTANT(next_opline, next_opline->op2)) == 0 + && next_opline->op2_type == opline->result_type + && next_opline->op2.var == opline->result.var) { + must_set_cflags = 1; + } + } + } + if (opcode == ZEND_MUL && Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 2) { - if (Z_MODE(op1_addr) == IS_REG && !may_overflow) { + if (Z_MODE(op1_addr) == IS_REG && !must_set_cflags) { | lea Ra(result_reg), [Ra(Z_REG(op1_addr))+Ra(Z_REG(op1_addr))] } else { | GET_ZVAL_LVAL result_reg, op1_addr @@ -4441,7 +4471,7 @@ static int zend_jit_math_long_long(dasm_State **Dst, } } else if (opcode == ZEND_MUL && Z_MODE(op2_addr) == IS_CONST_ZVAL && - !may_overflow && + !must_set_cflags && Z_LVAL_P(Z_ZV(op2_addr)) > 0 && zend_long_is_power_of_two(Z_LVAL_P(Z_ZV(op2_addr)))) { | GET_ZVAL_LVAL result_reg, op1_addr @@ -4449,7 +4479,7 @@ static int zend_jit_math_long_long(dasm_State **Dst, } else if (opcode == ZEND_MUL && Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op1_addr)) == 2) { - if (Z_MODE(op2_addr) == IS_REG && !may_overflow) { + if (Z_MODE(op2_addr) == IS_REG && !must_set_cflags) { | lea Ra(result_reg), [Ra(Z_REG(op2_addr))+Ra(Z_REG(op2_addr))] } else { | GET_ZVAL_LVAL result_reg, op2_addr @@ -4457,7 +4487,7 @@ static int zend_jit_math_long_long(dasm_State **Dst, } } else if (opcode == ZEND_MUL && Z_MODE(op1_addr) == IS_CONST_ZVAL && - !may_overflow && + !must_set_cflags && Z_LVAL_P(Z_ZV(op1_addr)) > 0 && zend_long_is_power_of_two(Z_LVAL_P(Z_ZV(op1_addr)))) { | GET_ZVAL_LVAL result_reg, op2_addr @@ -4468,19 +4498,19 @@ static int zend_jit_math_long_long(dasm_State **Dst, | GET_ZVAL_LVAL result_reg, op1_addr | shr Ra(result_reg), zend_long_floor_log2(Z_LVAL_P(Z_ZV(op2_addr))) } else if (opcode == ZEND_ADD && - !may_overflow && + !must_set_cflags && Z_MODE(op1_addr) == IS_REG && Z_MODE(op2_addr) == IS_CONST_ZVAL && IS_SIGNED_32BIT(Z_LVAL_P(Z_ZV(op2_addr)))) { | lea Ra(result_reg), [Ra(Z_REG(op1_addr))+Z_LVAL_P(Z_ZV(op2_addr))] } else if (opcode == ZEND_ADD && - !may_overflow && + !must_set_cflags && Z_MODE(op2_addr) == IS_REG && Z_MODE(op1_addr) == IS_CONST_ZVAL && IS_SIGNED_32BIT(Z_LVAL_P(Z_ZV(op1_addr)))) { | lea Ra(result_reg), [Ra(Z_REG(op2_addr))+Z_LVAL_P(Z_ZV(op1_addr))] } else if (opcode == ZEND_SUB && - !may_overflow && + !must_set_cflags && Z_MODE(op1_addr) == IS_REG && Z_MODE(op2_addr) == IS_CONST_ZVAL && IS_SIGNED_32BIT(-Z_LVAL_P(Z_ZV(op2_addr)))) { diff --git a/ext/opcache/tests/jit/gh12382.phpt b/ext/opcache/tests/jit/gh12382.phpt new file mode 100644 index 0000000000000..52b564b5e845c --- /dev/null +++ b/ext/opcache/tests/jit/gh12382.phpt @@ -0,0 +1,39 @@ +--TEST-- +GH-12382: JIT Index invalid or out of range error +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +--FILE-- += 0 + && 0 === $array[$y][$x - 1] + ) + ) { + } + } + } +} + +$matrix = SplFixedArray::fromArray( + array_map( + fn (array $arr): SplFixedArray => SplFixedArray::fromArray($arr), + [[1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, ], [1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, ], [1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, ], [1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, ], [1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, ], [1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, ], [1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, ], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], [0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, ], [0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, ], [0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, ], [1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, ], [1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, ], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, ], [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, ], [1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, ], [1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, ], [1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, ], [1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, ], [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, ], [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, ], ] + ) +); + +applyMaskPenaltyRule3($matrix); +applyMaskPenaltyRule3($matrix); +?> +DONE +--EXPECT-- +DONE