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.)
This commit is contained in:
Nikita Popov 2016-05-22 00:05:06 +02:00
parent fa9566627b
commit 0d62dfdf81
4 changed files with 18 additions and 5 deletions

View file

@ -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); shiftlist = (uint32_t *)do_alloca(sizeof(uint32_t) * op_array->last, use_heap);
memset(shiftlist, 0, sizeof(uint32_t) * op_array->last); memset(shiftlist, 0, sizeof(uint32_t) * op_array->last);
for (b = blocks; b < end; b++) { 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; i = b->start;
b->start = target; b->start = target;
while (i <= b->end) { while (i <= b->end) {

View file

@ -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 = blocks + block_map[op_array->live_range[j].end];
b->flags |= ZEND_BB_KILL_VAR; b->flags |= ZEND_BB_KILL_VAR;
if (!(b->flags & ZEND_BB_REACHABLE)) { if (!(b->flags & ZEND_BB_REACHABLE)) {
if (cfg->split_at_live_ranges) {
changed = 1; changed = 1;
zend_mark_reachable(op_array->opcodes, blocks, b); 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 { } else {
ZEND_ASSERT(!(blocks[block_map[op_array->live_range[j].end]].flags & ZEND_BB_REACHABLE)); ZEND_ASSERT(!(blocks[block_map[op_array->live_range[j].end]].flags & ZEND_BB_REACHABLE));

View file

@ -32,6 +32,7 @@
#define ZEND_BB_GEN_VAR (1<<9) /* start of live range */ #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_KILL_VAR (1<<10) /* end of live range */
#define ZEND_BB_EMPTY (1<<11) #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_LOOP_HEADER (1<<16)
#define ZEND_BB_IRREDUCIBLE_LOOP (1<<17) #define ZEND_BB_IRREDUCIBLE_LOOP (1<<17)

View file

@ -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 (!ssa || !ssa->ops || ssa->ops[opline - op_array->opcodes].result_use < 0) {
if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) { 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; 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); zend_dump_ssa_var(op_array, ssa, ssa_var_num, opline->result_type, EX_VAR_TO_NUM(opline->result.var), dump_flags);
} else { } else {
zend_dump_var(op_array, opline->result_type, EX_VAR_TO_NUM(opline->result.var)); zend_dump_var(op_array, opline->result_type, EX_VAR_TO_NUM(opline->result.var));