Skip to content

Commit

Permalink
Remove NOPs after DFA pass.
Browse files Browse the repository at this point in the history
  • Loading branch information
dstogov committed Mar 10, 2016
1 parent 624fe22 commit 8026da6
Showing 1 changed file with 200 additions and 1 deletion.
201 changes: 200 additions & 1 deletion ext/opcache/Optimizer/dfa_pass.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "zend_cfg.h"
#include "zend_ssa.h"
#include "zend_func_info.h"
#include "zend_call_graph.h"
#include "zend_inference.h"
#include "zend_dump.h"

Expand Down Expand Up @@ -112,6 +113,204 @@ int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx,
return SUCCESS;
}

static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa)
{
zend_basic_block *blocks = ssa->cfg.blocks;
zend_basic_block *end = blocks + ssa->cfg.blocks_count;
zend_basic_block *b;
zend_func_info *func_info;
int j;
uint32_t i;
uint32_t target = 0;
uint32_t *shiftlist;
ALLOCA_FLAG(use_heap);

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) {
i = b->start;
b->start = target;
while (i <= b->end) {
if (EXPECTED(op_array->opcodes[i].opcode != ZEND_NOP) ||
/*keep NOP to support ZEND_VM_SMART_BRANCH */
(i > 0 &&
i + 1 < op_array->last &&
(op_array->opcodes[i+1].opcode == ZEND_JMPZ ||
op_array->opcodes[i+1].opcode == ZEND_JMPNZ) &&
(op_array->opcodes[i-1].opcode == ZEND_IS_IDENTICAL ||
op_array->opcodes[i-1].opcode == ZEND_IS_NOT_IDENTICAL ||
op_array->opcodes[i-1].opcode == ZEND_IS_EQUAL ||
op_array->opcodes[i-1].opcode == ZEND_IS_NOT_EQUAL ||
op_array->opcodes[i-1].opcode == ZEND_IS_SMALLER ||
op_array->opcodes[i-1].opcode == ZEND_IS_SMALLER_OR_EQUAL ||
op_array->opcodes[i-1].opcode == ZEND_CASE ||
op_array->opcodes[i-1].opcode == ZEND_ISSET_ISEMPTY_VAR ||
op_array->opcodes[i-1].opcode == ZEND_ISSET_ISEMPTY_STATIC_PROP ||
op_array->opcodes[i-1].opcode == ZEND_ISSET_ISEMPTY_DIM_OBJ ||
op_array->opcodes[i-1].opcode == ZEND_ISSET_ISEMPTY_PROP_OBJ ||
op_array->opcodes[i-1].opcode == ZEND_INSTANCEOF ||
op_array->opcodes[i-1].opcode == ZEND_TYPE_CHECK ||
op_array->opcodes[i-1].opcode == ZEND_DEFINED))) {
if (i != target) {
op_array->opcodes[target] = op_array->opcodes[i];
ssa->ops[target] = ssa->ops[i];
shiftlist[i] = i - target;
}
target++;
}
i++;
}
if (b->end != target - 1) {
zend_op *opline;
zend_op *new_opline;

opline = op_array->opcodes + b->end;
b->end = target - 1;
new_opline = op_array->opcodes + b->end;
switch (new_opline->opcode) {
case ZEND_JMP:
case ZEND_FAST_CALL:
ZEND_SET_OP_JMP_ADDR(new_opline, new_opline->op1, ZEND_OP1_JMP_ADDR(opline));
break;
case ZEND_JMPZNZ:
new_opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, new_opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
/* break missing intentionally */
case ZEND_JMPZ:
case ZEND_JMPNZ:
case ZEND_JMPZ_EX:
case ZEND_JMPNZ_EX:
case ZEND_FE_RESET_R:
case ZEND_FE_RESET_RW:
case ZEND_NEW:
case ZEND_JMP_SET:
case ZEND_COALESCE:
case ZEND_ASSERT_CHECK:
ZEND_SET_OP_JMP_ADDR(new_opline, new_opline->op2, ZEND_OP2_JMP_ADDR(opline));
break;
case ZEND_CATCH:
if (!opline->result.num) {
new_opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, new_opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
}
break;
case ZEND_DECLARE_ANON_CLASS:
case ZEND_DECLARE_ANON_INHERITED_CLASS:
case ZEND_FE_FETCH_R:
case ZEND_FE_FETCH_RW:
new_opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, new_opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
break;
}
}
}
}

if (target != op_array->last) {
/* reset rest opcodes */
for (i = target; i < op_array->last; i++) {
MAKE_NOP(op_array->opcodes + i);
}

/* update SSA variables */
for (j = 0; j < ssa->vars_count; j++) {
if (ssa->vars[j].definition >= 0) {
ssa->vars[j].definition -= shiftlist[ssa->vars[j].definition];
}
if (ssa->vars[j].use_chain >= 0) {
ssa->vars[j].use_chain -= shiftlist[ssa->vars[j].use_chain];
}
}
for (i = 0; i < op_array->last; i++) {
if (ssa->ops[i].op1_use_chain >= 0) {
ssa->ops[i].op1_use_chain -= shiftlist[ssa->ops[i].op1_use_chain];
}
if (ssa->ops[i].op2_use_chain >= 0) {
ssa->ops[i].op2_use_chain -= shiftlist[ssa->ops[i].op2_use_chain];
}
if (ssa->ops[i].res_use_chain >= 0) {
ssa->ops[i].res_use_chain -= shiftlist[ssa->ops[i].res_use_chain];
}
}

/* update branch targets */
for (b = blocks; b < end; b++) {
if (b->flags & ZEND_BB_REACHABLE) {
zend_op *opline = op_array->opcodes + b->end;

switch (opline->opcode) {
case ZEND_JMP:
case ZEND_FAST_CALL:
ZEND_SET_OP_JMP_ADDR(opline, opline->op1, ZEND_OP1_JMP_ADDR(opline) - shiftlist[ZEND_OP1_JMP_ADDR(opline) - op_array->opcodes]);
break;
case ZEND_JMPZNZ:
opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value) - shiftlist[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)]);
/* break missing intentionally */
case ZEND_JMPZ:
case ZEND_JMPNZ:
case ZEND_JMPZ_EX:
case ZEND_JMPNZ_EX:
case ZEND_FE_RESET_R:
case ZEND_FE_RESET_RW:
case ZEND_NEW:
case ZEND_JMP_SET:
case ZEND_COALESCE:
case ZEND_ASSERT_CHECK:
ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(opline) - shiftlist[ZEND_OP2_JMP_ADDR(opline) - op_array->opcodes]);
break;
case ZEND_DECLARE_ANON_CLASS:
case ZEND_DECLARE_ANON_INHERITED_CLASS:
case ZEND_FE_FETCH_R:
case ZEND_FE_FETCH_RW:
case ZEND_CATCH:
opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value) - shiftlist[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)]);
break;
}
}
}

/* update brk/cont array */
for (j = 0; j < op_array->last_live_range; j++) {
op_array->live_range[j].start -= shiftlist[op_array->live_range[j].start];
op_array->live_range[j].end -= shiftlist[op_array->live_range[j].end];
}

/* update try/catch array */
for (j = 0; j < op_array->last_try_catch; j++) {
op_array->try_catch_array[j].try_op -= shiftlist[op_array->try_catch_array[j].try_op];
op_array->try_catch_array[j].catch_op -= shiftlist[op_array->try_catch_array[j].catch_op];
if (op_array->try_catch_array[j].finally_op) {
op_array->try_catch_array[j].finally_op -= shiftlist[op_array->try_catch_array[j].finally_op];
op_array->try_catch_array[j].finally_end -= shiftlist[op_array->try_catch_array[j].finally_end];
}
}

/* update early binding list */
if (op_array->early_binding != (uint32_t)-1) {
uint32_t *opline_num = &op_array->early_binding;

do {
*opline_num -= shiftlist[*opline_num];
opline_num = &ZEND_RESULT(&op_array->opcodes[*opline_num]).opline_num;
} while (*opline_num != (uint32_t)-1);
}

/* update call graph */
func_info = ZEND_FUNC_INFO(op_array);
if (func_info) {
zend_call_info *call_info = func_info->callee_info;
while (call_info) {
call_info->caller_init_opline -=
shiftlist[call_info->caller_init_opline - op_array->opcodes];
call_info->caller_call_opline -=
shiftlist[call_info->caller_call_opline - op_array->opcodes];
call_info = call_info->next_callee;
}
}

op_array->last = target;
}
free_alloca(shiftlist, use_heap);
}

void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, zend_ssa *ssa)
{
if (ctx->debug_level & ZEND_DUMP_BEFORE_DFA_PASS) {
Expand Down Expand Up @@ -207,7 +406,7 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
}
}
if (remove_nops) {
// TODO: remove nop???
zend_ssa_remove_nops(op_array, ssa);
}
}

Expand Down

0 comments on commit 8026da6

Please sign in to comment.