diff --git a/Zend/Optimizer/scdf.c b/Zend/Optimizer/scdf.c index 0e0a66c1086..72cb2da0483 100644 --- a/Zend/Optimizer/scdf.c +++ b/Zend/Optimizer/scdf.c @@ -224,10 +224,11 @@ static uint32_t cleanup_loop_var_free_block(scdf_ctx *scdf, zend_basic_block *bl zend_ssa *ssa = scdf->ssa; const zend_op_array *op_array = scdf->op_array; const zend_cfg *cfg = &ssa->cfg; + int block_num = block - cfg->blocks; uint32_t removed_ops = 0; /* Removes phi nodes */ - for (zend_ssa_phi *phi = ssa->blocks[block - cfg->blocks].phis; phi; phi = phi->next) { + for (zend_ssa_phi *phi = ssa->blocks[block_num].phis; phi; phi = phi->next) { zend_ssa_remove_uses_of_var(ssa, phi->ssa_var); zend_ssa_remove_phi(ssa, phi); } @@ -235,7 +236,8 @@ static uint32_t cleanup_loop_var_free_block(scdf_ctx *scdf, zend_basic_block *bl for (uint32_t i = block->start; i < block->start + block->len; i++) { zend_op *opline = &op_array->opcodes[i]; zend_ssa_op *ssa_op = &scdf->ssa->ops[i]; - if (is_live_loop_var_free(scdf, opline, ssa_op)) { + if (opline->opcode == ZEND_NOP + || is_live_loop_var_free(scdf, opline, ssa_op)) { continue; } @@ -243,10 +245,11 @@ static uint32_t cleanup_loop_var_free_block(scdf_ctx *scdf, zend_basic_block *bl * in the block. */ zend_ssa_remove_defs_of_instr(ssa, ssa_op); zend_ssa_remove_instr(ssa, opline, ssa_op); + removed_ops++; } - /* This block has no predecessors anymore. */ - block->predecessors_count = 0; + zend_ssa_remove_block_from_cfg(ssa, block_num); + return removed_ops; } diff --git a/Zend/Optimizer/zend_ssa.c b/Zend/Optimizer/zend_ssa.c index d173f20d330..cd0e179cd89 100644 --- a/Zend/Optimizer/zend_ssa.c +++ b/Zend/Optimizer/zend_ssa.c @@ -1448,9 +1448,8 @@ void zend_ssa_remove_block(zend_op_array *op_array, zend_ssa *ssa, int i) /* {{{ { zend_basic_block *block = &ssa->cfg.blocks[i]; zend_ssa_block *ssa_block = &ssa->blocks[i]; - int *predecessors; zend_ssa_phi *phi; - int j, s; + int j; block->flags &= ~ZEND_BB_REACHABLE; @@ -1470,6 +1469,16 @@ void zend_ssa_remove_block(zend_op_array *op_array, zend_ssa *ssa, int i) /* {{{ zend_ssa_remove_instr(ssa, &op_array->opcodes[j], &ssa->ops[j]); } + zend_ssa_remove_block_from_cfg(ssa, i); +} +/* }}} */ + +void zend_ssa_remove_block_from_cfg(zend_ssa *ssa, int i) /* {{{ */ +{ + zend_basic_block *block = &ssa->cfg.blocks[i]; + int *predecessors; + int j, s; + for (s = 0; s < block->successors_count; s++) { zend_ssa_remove_predecessor(ssa, i, block->successors[s]); } diff --git a/Zend/Optimizer/zend_ssa.h b/Zend/Optimizer/zend_ssa.h index 1fef8ddee96..8ff2343dc40 100644 --- a/Zend/Optimizer/zend_ssa.h +++ b/Zend/Optimizer/zend_ssa.h @@ -157,6 +157,7 @@ void zend_ssa_remove_phi(zend_ssa *ssa, zend_ssa_phi *phi); void zend_ssa_remove_uses_of_var(zend_ssa *ssa, int var_num); void zend_ssa_remove_block(zend_op_array *op_array, zend_ssa *ssa, int b); void zend_ssa_rename_var_uses(zend_ssa *ssa, int old_var, int new_var, bool update_types); +void zend_ssa_remove_block_from_cfg(zend_ssa *ssa, int b); static zend_always_inline void _zend_ssa_remove_def(zend_ssa_var *var) { diff --git a/Zend/tests/match/match_scdf_cleanup.phpt b/Zend/tests/match/match_scdf_cleanup.phpt new file mode 100644 index 00000000000..784802ac31e --- /dev/null +++ b/Zend/tests/match/match_scdf_cleanup.phpt @@ -0,0 +1,11 @@ +--TEST-- +Cleanup of basic block kept only because of FREE loop var +--FILE-- +X}); +?> +--EXPECTF-- +Fatal error: Uncaught Error: Undefined constant "X" in %smatch_scdf_cleanup.php:2 +Stack trace: +#0 {main} + thrown in %smatch_scdf_cleanup.php on line 2