diff --git a/ext/opcache/Optimizer/sccp.c b/ext/opcache/Optimizer/sccp.c index c4e0f0dfc83..62da6ff4aa6 100644 --- a/ext/opcache/Optimizer/sccp.c +++ b/ext/opcache/Optimizer/sccp.c @@ -1331,6 +1331,9 @@ static int replace_constant_operands(sccp_ctx *ctx) { call = ctx->call_map[var->definition]; ZEND_ASSERT(call); ZEND_ASSERT(call->caller_call_opline == opline); + if (opline->result_type & (IS_TMP_VAR|IS_VAR)) { + zend_optimizer_remove_live_range_ex(op_array, opline->result.var, var->definition + 1); + } zend_ssa_remove_result_def(ssa, ssa_op); zend_ssa_remove_instr(ssa, opline, ssa_op); zend_ssa_remove_instr(ssa, call->caller_init_opline, @@ -1346,6 +1349,9 @@ static int replace_constant_operands(sccp_ctx *ctx) { call->callee_func = NULL; } else { /* Ordinary computational instruction -> remove it */ + if (opline->result_type & (IS_TMP_VAR|IS_VAR)) { + zend_optimizer_remove_live_range_ex(op_array, opline->result.var, var->definition + 1); + } zend_ssa_remove_result_def(ssa, ssa_op); zend_ssa_remove_instr(ssa, opline, ssa_op); removed_ops++; @@ -1366,6 +1372,9 @@ static int replace_constant_operands(sccp_ctx *ctx) { if (ssa_op->result_def >= 0 && ssa->vars[ssa_op->result_def].use_chain < 0 && ssa->vars[ssa_op->result_def].phi_use_chain == NULL) { + if (opline->result_type & (IS_TMP_VAR|IS_VAR)) { + zend_optimizer_remove_live_range_ex(op_array, opline->result.var, var->definition + 1); + } zend_ssa_remove_result_def(ssa, ssa_op); opline->result_type = IS_UNUSED; } diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index 4a70de5eabc..03558d8e9c5 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -551,6 +551,23 @@ void zend_optimizer_remove_live_range(zend_op_array *op_array, uint32_t var) } } +void zend_optimizer_remove_live_range_ex(zend_op_array *op_array, uint32_t var, uint32_t start) +{ + uint32_t i = 0; + + while (i < op_array->last_live_range) { + if (op_array->live_range[i].var == var + && op_array->live_range[i].start == start) { + op_array->last_live_range--; + if (i < op_array->last_live_range) { + memmove(&op_array->live_range[i], &op_array->live_range[i+1], (op_array->last_live_range - i) * sizeof(zend_live_range)); + } + break; + } + i++; + } +} + int zend_optimizer_replace_by_const(zend_op_array *op_array, zend_op *opline, zend_uchar type, diff --git a/ext/opcache/Optimizer/zend_optimizer_internal.h b/ext/opcache/Optimizer/zend_optimizer_internal.h index 71dcf0a274a..407154f55c3 100644 --- a/ext/opcache/Optimizer/zend_optimizer_internal.h +++ b/ext/opcache/Optimizer/zend_optimizer_internal.h @@ -92,6 +92,7 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array, zval *val); void zend_optimizer_remove_live_range(zend_op_array *op_array, uint32_t var); +void zend_optimizer_remove_live_range_ex(zend_op_array *op_array, uint32_t var, uint32_t start); void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx); void zend_optimizer_pass2(zend_op_array *op_array); void zend_optimizer_pass3(zend_op_array *op_array); diff --git a/ext/opcache/Optimizer/zend_ssa.c b/ext/opcache/Optimizer/zend_ssa.c index 32f3e9101fc..afc5b5c6821 100644 --- a/ext/opcache/Optimizer/zend_ssa.c +++ b/ext/opcache/Optimizer/zend_ssa.c @@ -23,6 +23,7 @@ #include "zend_ssa.h" #include "zend_dump.h" #include "zend_inference.h" +#include "Optimizer/zend_optimizer_internal.h" static zend_bool dominates(const zend_basic_block *blocks, int a, int b) { while (blocks[b].level > blocks[a].level) { @@ -1361,6 +1362,9 @@ void zend_ssa_remove_block(zend_op_array *op_array, zend_ssa *ssa, int i) /* {{{ continue; } + if (op_array->opcodes[j].result_type & (IS_TMP_VAR|IS_VAR)) { + zend_optimizer_remove_live_range_ex(op_array, op_array->opcodes[j].result.var, j + 1); + } zend_ssa_remove_defs_of_instr(ssa, &ssa->ops[j]); zend_ssa_remove_instr(ssa, &op_array->opcodes[j], &ssa->ops[j]); }