From 0d62dfdf81fb7710c20a46a75ad6166e25e50a12 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sun, 22 May 2016 00:05:06 +0200 Subject: [PATCH] Improve previous fix Do not mark loop var free blocks as reachable after all -- as we can't construct SSA for unreachable blocks, this would cause issues down the line. Instead add an extra UNREACHABLE_FREE flag and retain only the FREE instruction during NOP removal. (If we retain all instructions in the BB we might leave a jump instruction that goes into the nowhere.) --- ext/opcache/Optimizer/dfa_pass.c | 9 ++++++++- ext/opcache/Optimizer/zend_cfg.c | 10 ++++++++-- ext/opcache/Optimizer/zend_cfg.h | 1 + ext/opcache/Optimizer/zend_dump.c | 3 +-- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c index 3f4112a7db..40a3dc996b 100644 --- a/ext/opcache/Optimizer/dfa_pass.c +++ b/ext/opcache/Optimizer/dfa_pass.c @@ -128,7 +128,14 @@ static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa) shiftlist = (uint32_t *)do_alloca(sizeof(uint32_t) * op_array->last, use_heap); memset(shiftlist, 0, sizeof(uint32_t) * op_array->last); for (b = blocks; b < end; b++) { - if (b->flags & ZEND_BB_REACHABLE) { + if (b->flags & (ZEND_BB_REACHABLE|ZEND_BB_UNREACHABLE_FREE)) { + if (b->flags & ZEND_BB_UNREACHABLE_FREE) { + /* Only keep the FREE for the loop var */ + ZEND_ASSERT(op_array->opcodes[b->start].opcode == ZEND_FREE + || op_array->opcodes[b->start].opcode == ZEND_FE_FREE); + b->end = b->start; + } + i = b->start; b->start = target; while (i <= b->end) { diff --git a/ext/opcache/Optimizer/zend_cfg.c b/ext/opcache/Optimizer/zend_cfg.c index c675da1116..33c34b85c4 100644 --- a/ext/opcache/Optimizer/zend_cfg.c +++ b/ext/opcache/Optimizer/zend_cfg.c @@ -114,8 +114,14 @@ static void zend_mark_reachable_blocks(const zend_op_array *op_array, zend_cfg * b = blocks + block_map[op_array->live_range[j].end]; b->flags |= ZEND_BB_KILL_VAR; if (!(b->flags & ZEND_BB_REACHABLE)) { - changed = 1; - zend_mark_reachable(op_array->opcodes, blocks, b); + if (cfg->split_at_live_ranges) { + changed = 1; + zend_mark_reachable(op_array->opcodes, blocks, b); + } else { + ZEND_ASSERT(!(b->flags & ZEND_BB_UNREACHABLE_FREE)); + ZEND_ASSERT(b->start == op_array->live_range[j].end); + b->flags |= ZEND_BB_UNREACHABLE_FREE; + } } } else { ZEND_ASSERT(!(blocks[block_map[op_array->live_range[j].end]].flags & ZEND_BB_REACHABLE)); diff --git a/ext/opcache/Optimizer/zend_cfg.h b/ext/opcache/Optimizer/zend_cfg.h index de94997dd5..cbf4225a31 100644 --- a/ext/opcache/Optimizer/zend_cfg.h +++ b/ext/opcache/Optimizer/zend_cfg.h @@ -32,6 +32,7 @@ #define ZEND_BB_GEN_VAR (1<<9) /* start of live range */ #define ZEND_BB_KILL_VAR (1<<10) /* end of live range */ #define ZEND_BB_EMPTY (1<<11) +#define ZEND_BB_UNREACHABLE_FREE (1<<12) /* unreachable loop free */ #define ZEND_BB_LOOP_HEADER (1<<16) #define ZEND_BB_IRREDUCIBLE_LOOP (1<<17) diff --git a/ext/opcache/Optimizer/zend_dump.c b/ext/opcache/Optimizer/zend_dump.c index 986e470345..70abe4d317 100644 --- a/ext/opcache/Optimizer/zend_dump.c +++ b/ext/opcache/Optimizer/zend_dump.c @@ -399,9 +399,8 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block * if (!ssa || !ssa->ops || ssa->ops[opline - op_array->opcodes].result_use < 0) { if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) { - if (ssa && ssa->ops) { + if (ssa && ssa->ops && ssa->ops[opline - op_array->opcodes].result_def >= 0) { int ssa_var_num = ssa->ops[opline - op_array->opcodes].result_def; - ZEND_ASSERT(ssa_var_num >= 0); zend_dump_ssa_var(op_array, ssa, ssa_var_num, opline->result_type, EX_VAR_TO_NUM(opline->result.var), dump_flags); } else { zend_dump_var(op_array, opline->result_type, EX_VAR_TO_NUM(opline->result.var)); -- 2.40.0