mirror of
https://github.com/php/php-src.git
synced 2025-08-19 17:04:47 +02:00
Collect all jump optimisations in a single optimization pass.
Run this pass twice (after SCCP and after DCE).
This commit is contained in:
parent
4d1ddeb02a
commit
f5ef1a83a8
3 changed files with 203 additions and 246 deletions
|
@ -423,112 +423,6 @@ static zend_bool dce_instr(context *ctx, zend_op *opline, zend_ssa_op *ssa_op) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Move this somewhere else (CFG simplification?)
|
|
||||||
static int simplify_jumps(zend_ssa *ssa, zend_op_array *op_array) {
|
|
||||||
int removed_ops = 0;
|
|
||||||
zend_basic_block *block;
|
|
||||||
FOREACH_BLOCK(block) {
|
|
||||||
int block_num = block - ssa->cfg.blocks;
|
|
||||||
zend_op *opline = &op_array->opcodes[block->start + block->len - 1];
|
|
||||||
zend_ssa_op *ssa_op = &ssa->ops[block->start + block->len - 1];
|
|
||||||
zval *op1;
|
|
||||||
|
|
||||||
if (block->len == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert jump-and-set into jump if result is not used */
|
|
||||||
switch (opline->opcode) {
|
|
||||||
case ZEND_JMPZ_EX:
|
|
||||||
ZEND_ASSERT(ssa_op->result_def >= 0);
|
|
||||||
if (ssa->vars[ssa_op->result_def].use_chain < 0
|
|
||||||
&& ssa->vars[ssa_op->result_def].phi_use_chain == NULL) {
|
|
||||||
opline->opcode = ZEND_JMPZ;
|
|
||||||
opline->result_type = IS_UNUSED;
|
|
||||||
zend_ssa_remove_result_def(ssa, ssa_op);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ZEND_JMPNZ_EX:
|
|
||||||
case ZEND_JMP_SET:
|
|
||||||
ZEND_ASSERT(ssa_op->result_def >= 0);
|
|
||||||
if (ssa->vars[ssa_op->result_def].use_chain < 0
|
|
||||||
&& ssa->vars[ssa_op->result_def].phi_use_chain == NULL) {
|
|
||||||
opline->opcode = ZEND_JMPNZ;
|
|
||||||
opline->result_type = IS_UNUSED;
|
|
||||||
zend_ssa_remove_result_def(ssa, ssa_op);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert jump-and-set to QM_ASSIGN/BOOL if the "else" branch is not taken. */
|
|
||||||
switch (opline->opcode) {
|
|
||||||
case ZEND_JMPZ_EX:
|
|
||||||
case ZEND_JMPNZ_EX:
|
|
||||||
if (block->successors_count == 1 && block->successors[0] != block_num + 1) {
|
|
||||||
opline->opcode = ZEND_BOOL;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ZEND_JMP_SET:
|
|
||||||
case ZEND_COALESCE:
|
|
||||||
if (block->successors_count == 1 && block->successors[0] != block_num + 1) {
|
|
||||||
opline->opcode = ZEND_QM_ASSIGN;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opline->op1_type != IS_CONST) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert constant conditional jump to unconditional jump */
|
|
||||||
op1 = &ZEND_OP1_LITERAL(opline);
|
|
||||||
switch (opline->opcode) {
|
|
||||||
case ZEND_JMPZ:
|
|
||||||
if (!zend_is_true(op1)) {
|
|
||||||
literal_dtor(op1);
|
|
||||||
opline->op1_type = IS_UNUSED;
|
|
||||||
opline->op1.num = opline->op2.num;
|
|
||||||
opline->opcode = ZEND_JMP;
|
|
||||||
} else {
|
|
||||||
MAKE_NOP(opline);
|
|
||||||
removed_ops++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ZEND_JMPNZ:
|
|
||||||
if (zend_is_true(op1)) {
|
|
||||||
literal_dtor(op1);
|
|
||||||
opline->op1_type = IS_UNUSED;
|
|
||||||
opline->op1.num = opline->op2.num;
|
|
||||||
opline->opcode = ZEND_JMP;
|
|
||||||
} else {
|
|
||||||
MAKE_NOP(opline);
|
|
||||||
removed_ops++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ZEND_COALESCE:
|
|
||||||
ZEND_ASSERT(ssa_op->result_def >= 0);
|
|
||||||
if (ssa->vars[ssa_op->result_def].use_chain >= 0
|
|
||||||
|| ssa->vars[ssa_op->result_def].phi_use_chain != NULL) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
zend_ssa_remove_result_def(ssa, ssa_op);
|
|
||||||
if (Z_TYPE_P(op1) != IS_NULL) {
|
|
||||||
literal_dtor(op1);
|
|
||||||
opline->op1_type = IS_UNUSED;
|
|
||||||
opline->op1.num = opline->op2.num;
|
|
||||||
opline->opcode = ZEND_JMP;
|
|
||||||
opline->result_type = IS_UNUSED;
|
|
||||||
} else {
|
|
||||||
MAKE_NOP(opline);
|
|
||||||
removed_ops++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} FOREACH_BLOCK_END();
|
|
||||||
return removed_ops;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int get_common_phi_source(zend_ssa *ssa, zend_ssa_phi *phi) {
|
static inline int get_common_phi_source(zend_ssa *ssa, zend_ssa_phi *phi) {
|
||||||
int common_source = -1;
|
int common_source = -1;
|
||||||
int source;
|
int source;
|
||||||
|
@ -772,7 +666,5 @@ int dce_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, zend_bool reor
|
||||||
}
|
}
|
||||||
} FOREACH_PHI_END();
|
} FOREACH_PHI_END();
|
||||||
|
|
||||||
removed_ops += simplify_jumps(ssa, op_array);
|
|
||||||
|
|
||||||
return removed_ops;
|
return removed_ops;
|
||||||
}
|
}
|
||||||
|
|
|
@ -454,6 +454,27 @@ int zend_dfa_optimize_calls(zend_op_array *op_array, zend_ssa *ssa)
|
||||||
return removed_ops;
|
return removed_ops;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static zend_always_inline void take_successor_0(zend_ssa *ssa, int block_num, zend_basic_block *block)
|
||||||
|
{
|
||||||
|
if (block->successors_count == 2) {
|
||||||
|
if (block->successors[1] != block->successors[0]) {
|
||||||
|
zend_ssa_remove_predecessor(ssa, block_num, block->successors[1]);
|
||||||
|
}
|
||||||
|
block->successors_count = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static zend_always_inline void take_successor_1(zend_ssa *ssa, int block_num, zend_basic_block *block)
|
||||||
|
{
|
||||||
|
if (block->successors_count == 2) {
|
||||||
|
if (block->successors[1] != block->successors[0]) {
|
||||||
|
zend_ssa_remove_predecessor(ssa, block_num, block->successors[0]);
|
||||||
|
block->successors[0] = block->successors[1];
|
||||||
|
}
|
||||||
|
block->successors_count = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int zend_dfa_optimize_jmps(zend_op_array *op_array, zend_ssa *ssa)
|
static int zend_dfa_optimize_jmps(zend_op_array *op_array, zend_ssa *ssa)
|
||||||
{
|
{
|
||||||
int removed_ops = 0;
|
int removed_ops = 0;
|
||||||
|
@ -468,7 +489,7 @@ static int zend_dfa_optimize_jmps(zend_op_array *op_array, zend_ssa *ssa)
|
||||||
zend_basic_block *block = &ssa->cfg.blocks[block_num];
|
zend_basic_block *block = &ssa->cfg.blocks[block_num];
|
||||||
uint32_t op_num;
|
uint32_t op_num;
|
||||||
zend_op *opline;
|
zend_op *opline;
|
||||||
zend_ssa_op *op;
|
zend_ssa_op *ssa_op;
|
||||||
|
|
||||||
while (next_block_num < ssa->cfg.blocks_count
|
while (next_block_num < ssa->cfg.blocks_count
|
||||||
&& !(ssa->cfg.blocks[next_block_num].flags & ZEND_BB_REACHABLE)) {
|
&& !(ssa->cfg.blocks[next_block_num].flags & ZEND_BB_REACHABLE)) {
|
||||||
|
@ -476,54 +497,180 @@ static int zend_dfa_optimize_jmps(zend_op_array *op_array, zend_ssa *ssa)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block->len) {
|
if (block->len) {
|
||||||
if (block->successors_count == 2) {
|
op_num = block->start + block->len - 1;
|
||||||
if (block->successors[0] == block->successors[1]) {
|
opline = op_array->opcodes + op_num;
|
||||||
op_num = block->start + block->len - 1;
|
ssa_op = ssa->ops + op_num;
|
||||||
opline = op_array->opcodes + op_num;
|
|
||||||
switch (opline->opcode) {
|
switch (opline->opcode) {
|
||||||
case ZEND_JMPZ:
|
case ZEND_JMP:
|
||||||
case ZEND_JMPNZ:
|
optimize_jmp:
|
||||||
case ZEND_JMPZNZ:
|
if (block->successors[0] == next_block_num) {
|
||||||
op = ssa->ops + op_num;
|
MAKE_NOP(opline);
|
||||||
|
removed_ops++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ZEND_JMPZ:
|
||||||
|
optimize_jmpz:
|
||||||
|
if (opline->op1_type == IS_CONST) {
|
||||||
|
if (zend_is_true(CT_CONSTANT_EX(op_array, opline->op1.constant))) {
|
||||||
|
MAKE_NOP(opline);
|
||||||
|
removed_ops++;
|
||||||
|
take_successor_1(ssa, block_num, block);
|
||||||
|
} else {
|
||||||
|
opline->opcode = ZEND_JMP;
|
||||||
|
COPY_NODE(opline->op1, opline->op2);
|
||||||
|
take_successor_0(ssa, block_num, block);
|
||||||
|
goto optimize_jmp;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (block->successors[0] == next_block_num) {
|
||||||
|
take_successor_0(ssa, block_num, block);
|
||||||
|
if (opline->op1_type == IS_CV || !(OP1_INFO() & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
|
||||||
|
zend_ssa_remove_instr(ssa, opline, ssa_op);
|
||||||
|
removed_ops++;
|
||||||
|
} else {
|
||||||
|
opline->opcode = ZEND_FREE;
|
||||||
|
opline->op2.num = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ZEND_JMPNZ:
|
||||||
|
optimize_jmpnz:
|
||||||
|
if (opline->op1_type == IS_CONST) {
|
||||||
|
if (zend_is_true(CT_CONSTANT_EX(op_array, opline->op1.constant))) {
|
||||||
|
opline->opcode = ZEND_JMP;
|
||||||
|
COPY_NODE(opline->op1, opline->op2);
|
||||||
|
take_successor_0(ssa, block_num, block);
|
||||||
|
goto optimize_jmp;
|
||||||
|
} else {
|
||||||
|
MAKE_NOP(opline);
|
||||||
|
removed_ops++;
|
||||||
|
take_successor_1(ssa, block_num, block);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ZEND_ASSERT(block->successors_count == 2);
|
||||||
|
if (block->successors[0] == next_block_num) {
|
||||||
|
take_successor_0(ssa, block_num, block);
|
||||||
|
if (opline->op1_type == IS_CV || !(OP1_INFO() & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
|
||||||
|
zend_ssa_remove_instr(ssa, opline, ssa_op);
|
||||||
|
removed_ops++;
|
||||||
|
} else {
|
||||||
|
opline->opcode = ZEND_FREE;
|
||||||
|
opline->op2.num = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ZEND_JMPZNZ:
|
||||||
|
if (opline->op1_type == IS_CONST) {
|
||||||
|
if (zend_is_true(CT_CONSTANT_EX(op_array, opline->op1.constant))) {
|
||||||
|
zend_op *target_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
|
||||||
|
ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
|
||||||
|
take_successor_1(ssa, block_num, block);
|
||||||
|
} else {
|
||||||
|
zend_op *target_opline = ZEND_OP2_JMP_ADDR(opline);
|
||||||
|
ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
|
||||||
|
take_successor_0(ssa, block_num, block);
|
||||||
|
}
|
||||||
|
opline->op1_type = IS_UNUSED;
|
||||||
|
opline->extended_value = 0;
|
||||||
|
opline->opcode = ZEND_JMP;
|
||||||
|
goto optimize_jmp;
|
||||||
|
} else {
|
||||||
|
ZEND_ASSERT(block->successors_count == 2);
|
||||||
|
if (block->successors[0] == block->successors[1]) {
|
||||||
|
take_successor_0(ssa, block_num, block);
|
||||||
if (block->successors[0] == next_block_num) {
|
if (block->successors[0] == next_block_num) {
|
||||||
if (opline->op1_type & (IS_CV|IS_CONST)) {
|
if (opline->op1_type == IS_CV || !(OP1_INFO() & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
|
||||||
zend_ssa_remove_instr(ssa, opline, op);
|
zend_ssa_remove_instr(ssa, opline, ssa_op);
|
||||||
if (op->op1_use >= 0) {
|
|
||||||
zend_ssa_unlink_use_chain(ssa, op_num, op->op1_use);
|
|
||||||
op->op1_use = -1;
|
|
||||||
op->op1_use_chain = -1;
|
|
||||||
}
|
|
||||||
MAKE_NOP(opline);
|
|
||||||
removed_ops++;
|
removed_ops++;
|
||||||
} else {
|
} else {
|
||||||
opline->opcode = ZEND_FREE;
|
opline->opcode = ZEND_FREE;
|
||||||
opline->op2.num = 0;
|
opline->op2.num = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (opline->op1_type == IS_CV || !(OP1_INFO() & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
|
||||||
if (opline->op1_type & (IS_CV|IS_CONST)) {
|
ZEND_ASSERT(ssa_op->op1_use >= 0);
|
||||||
if (op->op1_use >= 0) {
|
zend_ssa_unlink_use_chain(ssa, op_num, ssa_op->op1_use);
|
||||||
zend_ssa_unlink_use_chain(ssa, op_num, op->op1_use);
|
ssa_op->op1_use = -1;
|
||||||
op->op1_use = -1;
|
ssa_op->op1_use_chain = -1;
|
||||||
op->op1_use_chain = -1;
|
opline->opcode = ZEND_JMP;
|
||||||
}
|
opline->op1_type = IS_UNUSED;
|
||||||
opline->opcode = ZEND_JMP;
|
opline->op1.num = opline->op2.num;
|
||||||
opline->op1_type = IS_UNUSED;
|
goto optimize_jmp;
|
||||||
opline->op1.num = opline->op2.num;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
} else if (block->successors_count == 1 && block->successors[0] == next_block_num) {
|
case ZEND_JMPZ_EX:
|
||||||
op_num = block->start + block->len - 1;
|
if (ssa->vars[ssa_op->result_def].use_chain < 0
|
||||||
opline = op_array->opcodes + op_num;
|
&& ssa->vars[ssa_op->result_def].phi_use_chain == NULL) {
|
||||||
if (opline->opcode == ZEND_JMP) {
|
opline->opcode = ZEND_JMPZ;
|
||||||
MAKE_NOP(opline);
|
opline->result_type = IS_UNUSED;
|
||||||
removed_ops++;
|
zend_ssa_remove_result_def(ssa, ssa_op);
|
||||||
}
|
goto optimize_jmpz;
|
||||||
}
|
} else if (opline->op1_type == IS_CONST) {
|
||||||
|
if (zend_is_true(CT_CONSTANT_EX(op_array, opline->op1.constant))) {
|
||||||
|
opline->opcode = ZEND_QM_ASSIGN;
|
||||||
|
take_successor_1(ssa, block_num, block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ZEND_JMPNZ_EX:
|
||||||
|
if (ssa->vars[ssa_op->result_def].use_chain < 0
|
||||||
|
&& ssa->vars[ssa_op->result_def].phi_use_chain == NULL) {
|
||||||
|
opline->opcode = ZEND_JMPNZ;
|
||||||
|
opline->result_type = IS_UNUSED;
|
||||||
|
zend_ssa_remove_result_def(ssa, ssa_op);
|
||||||
|
goto optimize_jmpnz;
|
||||||
|
} else if (opline->op1_type == IS_CONST) {
|
||||||
|
if (!zend_is_true(CT_CONSTANT_EX(op_array, opline->op1.constant))) {
|
||||||
|
opline->opcode = ZEND_QM_ASSIGN;
|
||||||
|
take_successor_1(ssa, block_num, block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ZEND_JMP_SET:
|
||||||
|
if (ssa->vars[ssa_op->result_def].use_chain < 0
|
||||||
|
&& ssa->vars[ssa_op->result_def].phi_use_chain == NULL) {
|
||||||
|
opline->opcode = ZEND_JMPNZ;
|
||||||
|
opline->result_type = IS_UNUSED;
|
||||||
|
zend_ssa_remove_result_def(ssa, ssa_op);
|
||||||
|
goto optimize_jmpnz;
|
||||||
|
} else if (opline->op1_type == IS_CONST) {
|
||||||
|
if (!zend_is_true(CT_CONSTANT_EX(op_array, opline->op1.constant))) {
|
||||||
|
MAKE_NOP(opline);
|
||||||
|
removed_ops++;
|
||||||
|
take_successor_1(ssa, block_num, block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ZEND_COALESCE:
|
||||||
|
if (opline->op1_type == IS_CONST) {
|
||||||
|
if (Z_TYPE_P(CT_CONSTANT_EX(op_array, opline->op1.constant)) == IS_NULL) {
|
||||||
|
MAKE_NOP(opline);
|
||||||
|
removed_ops++;
|
||||||
|
take_successor_1(ssa, block_num, block);
|
||||||
|
} else {
|
||||||
|
zend_ssa_var *var = &ssa->vars[ssa_op->result_def];
|
||||||
|
if (var->use_chain < 0 && var->phi_use_chain == NULL) {
|
||||||
|
ssa_op->result_def = -1;
|
||||||
|
if (opline->result_type & (IS_TMP_VAR|IS_VAR)) {
|
||||||
|
zend_optimizer_remove_live_range_ex(op_array, opline->result.var, var->definition);
|
||||||
|
}
|
||||||
|
zend_ssa_unlink_use_chain(ssa, opline - op_array->opcodes, ssa_op->op1_use);
|
||||||
|
ssa_op->op1_use = -1;
|
||||||
|
ssa_op->op1_use_chain = -1;
|
||||||
|
opline->opcode = ZEND_JMP;
|
||||||
|
COPY_NODE(opline->op1, opline->op2);
|
||||||
|
take_successor_0(ssa, block_num, block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
block_num = next_block_num;
|
block_num = next_block_num;
|
||||||
|
@ -574,6 +721,9 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
|
||||||
if (dce_optimize_op_array(op_array, ssa, 0)) {
|
if (dce_optimize_op_array(op_array, ssa, 0)) {
|
||||||
remove_nops = 1;
|
remove_nops = 1;
|
||||||
}
|
}
|
||||||
|
if (zend_dfa_optimize_jmps(op_array, ssa)) {
|
||||||
|
remove_nops = 1;
|
||||||
|
}
|
||||||
if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_14) {
|
if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_14) {
|
||||||
zend_dump_op_array(op_array, ZEND_DUMP_SSA, "after dce pass", ssa);
|
zend_dump_op_array(op_array, ZEND_DUMP_SSA, "after dce pass", ssa);
|
||||||
}
|
}
|
||||||
|
|
|
@ -283,93 +283,6 @@ static zend_bool try_replace_op1(
|
||||||
zval zv;
|
zval zv;
|
||||||
ZVAL_COPY(&zv, value);
|
ZVAL_COPY(&zv, value);
|
||||||
if (zend_optimizer_update_op1_const(ctx->scdf.op_array, opline, &zv)) {
|
if (zend_optimizer_update_op1_const(ctx->scdf.op_array, opline, &zv)) {
|
||||||
/* Reconstruct SSA */
|
|
||||||
int num;
|
|
||||||
zend_basic_block *block;
|
|
||||||
|
|
||||||
switch (opline->opcode) {
|
|
||||||
case ZEND_JMPZ:
|
|
||||||
if (zend_is_true(&zv)) {
|
|
||||||
MAKE_NOP(opline);
|
|
||||||
num = ctx->scdf.ssa->cfg.map[opline - ctx->scdf.op_array->opcodes];
|
|
||||||
block = &ctx->scdf.ssa->cfg.blocks[num];
|
|
||||||
if (block->successors_count == 2) {
|
|
||||||
if (block->successors[1] != block->successors[0]) {
|
|
||||||
zend_ssa_remove_predecessor(ctx->scdf.ssa, num, block->successors[0]);
|
|
||||||
}
|
|
||||||
block->successors_count = 1;
|
|
||||||
block->successors[0] = block->successors[1];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
opline->opcode = ZEND_JMP;
|
|
||||||
COPY_NODE(opline->op1, opline->op2);
|
|
||||||
num = ctx->scdf.ssa->cfg.map[opline - ctx->scdf.op_array->opcodes];
|
|
||||||
block = &ctx->scdf.ssa->cfg.blocks[num];
|
|
||||||
if (block->successors_count == 2) {
|
|
||||||
if (block->successors[1] != block->successors[0]) {
|
|
||||||
zend_ssa_remove_predecessor(ctx->scdf.ssa, num, block->successors[1]);
|
|
||||||
}
|
|
||||||
block->successors_count = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ZEND_JMPNZ:
|
|
||||||
if (zend_is_true(&zv)) {
|
|
||||||
opline->opcode = ZEND_JMP;
|
|
||||||
COPY_NODE(opline->op1, opline->op2);
|
|
||||||
num = ctx->scdf.ssa->cfg.map[opline - ctx->scdf.op_array->opcodes];
|
|
||||||
block = &ctx->scdf.ssa->cfg.blocks[num];
|
|
||||||
if (block->successors_count == 2) {
|
|
||||||
if (block->successors[1] != block->successors[0]) {
|
|
||||||
zend_ssa_remove_predecessor(ctx->scdf.ssa, num, block->successors[1]);
|
|
||||||
}
|
|
||||||
block->successors_count = 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
MAKE_NOP(opline);
|
|
||||||
num = ctx->scdf.ssa->cfg.map[opline - ctx->scdf.op_array->opcodes];
|
|
||||||
block = &ctx->scdf.ssa->cfg.blocks[num];
|
|
||||||
if (block->successors_count == 2) {
|
|
||||||
if (block->successors[1] != block->successors[0]) {
|
|
||||||
zend_ssa_remove_predecessor(ctx->scdf.ssa, num, block->successors[0]);
|
|
||||||
}
|
|
||||||
block->successors_count = 1;
|
|
||||||
block->successors[0] = block->successors[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ZEND_JMPZNZ:
|
|
||||||
if (zend_is_true(&zv)) {
|
|
||||||
zend_op *target_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
|
|
||||||
ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
|
|
||||||
num = ctx->scdf.ssa->cfg.map[opline - ctx->scdf.op_array->opcodes];
|
|
||||||
block = &ctx->scdf.ssa->cfg.blocks[num];
|
|
||||||
if (block->successors_count == 2) {
|
|
||||||
if (block->successors[1] != block->successors[0]) {
|
|
||||||
zend_ssa_remove_predecessor(ctx->scdf.ssa, num, block->successors[0]);
|
|
||||||
}
|
|
||||||
block->successors_count = 1;
|
|
||||||
block->successors[0] = block->successors[1];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
zend_op *target_opline = ZEND_OP2_JMP_ADDR(opline);
|
|
||||||
ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
|
|
||||||
num = ctx->scdf.ssa->cfg.map[opline - ctx->scdf.op_array->opcodes];
|
|
||||||
block = &ctx->scdf.ssa->cfg.blocks[num];
|
|
||||||
if (block->successors_count == 2) {
|
|
||||||
if (block->successors[1] != block->successors[0]) {
|
|
||||||
zend_ssa_remove_predecessor(ctx->scdf.ssa, num, block->successors[1]);
|
|
||||||
}
|
|
||||||
block->successors_count = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
opline->op1_type = IS_UNUSED;
|
|
||||||
opline->extended_value = 0;
|
|
||||||
opline->opcode = ZEND_JMP;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
// TODO: check the following special cases ???
|
// TODO: check the following special cases ???
|
||||||
|
@ -2082,6 +1995,17 @@ static int try_remove_definition(sccp_ctx *ctx, int var_num, zend_ssa_var *var,
|
||||||
|| ssa_op->op2_def >= 0) {
|
|| ssa_op->op2_def >= 0) {
|
||||||
/* we cannot remove instruction that defines other varibales */
|
/* we cannot remove instruction that defines other varibales */
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (opline->opcode == ZEND_JMPZ_EX
|
||||||
|
|| opline->opcode == ZEND_JMPNZ_EX
|
||||||
|
|| opline->opcode == ZEND_JMP_SET
|
||||||
|
|| opline->opcode == ZEND_COALESCE
|
||||||
|
|| opline->opcode == ZEND_FE_RESET_R
|
||||||
|
|| opline->opcode == ZEND_FE_RESET_RW
|
||||||
|
|| opline->opcode == ZEND_FE_FETCH_R
|
||||||
|
|| opline->opcode == ZEND_FE_FETCH_RW
|
||||||
|
|| opline->opcode == ZEND_NEW) {
|
||||||
|
/* we cannot simple remove jump instructions */
|
||||||
|
return 0;
|
||||||
} else if (var->use_chain >= 0
|
} else if (var->use_chain >= 0
|
||||||
|| var->phi_use_chain != NULL) {
|
|| var->phi_use_chain != NULL) {
|
||||||
if (value
|
if (value
|
||||||
|
@ -2090,16 +2014,7 @@ static int try_remove_definition(sccp_ctx *ctx, int var_num, zend_ssa_var *var,
|
||||||
&& opline->opcode != ZEND_ROPE_INIT
|
&& opline->opcode != ZEND_ROPE_INIT
|
||||||
&& opline->opcode != ZEND_ROPE_ADD
|
&& opline->opcode != ZEND_ROPE_ADD
|
||||||
&& opline->opcode != ZEND_INIT_ARRAY
|
&& opline->opcode != ZEND_INIT_ARRAY
|
||||||
&& opline->opcode != ZEND_ADD_ARRAY_ELEMENT
|
&& opline->opcode != ZEND_ADD_ARRAY_ELEMENT) {
|
||||||
&& opline->opcode != ZEND_JMPZ_EX
|
|
||||||
&& opline->opcode != ZEND_JMPNZ_EX
|
|
||||||
&& opline->opcode != ZEND_JMP_SET
|
|
||||||
&& opline->opcode != ZEND_COALESCE
|
|
||||||
&& opline->opcode != ZEND_FE_RESET_R
|
|
||||||
&& opline->opcode != ZEND_FE_RESET_RW
|
|
||||||
&& opline->opcode != ZEND_FE_FETCH_R
|
|
||||||
&& opline->opcode != ZEND_FE_FETCH_RW
|
|
||||||
&& opline->opcode != ZEND_NEW) {
|
|
||||||
/* Replace with QM_ASSIGN */
|
/* Replace with QM_ASSIGN */
|
||||||
zend_uchar old_type = opline->result_type;
|
zend_uchar old_type = opline->result_type;
|
||||||
zend_uchar old_var = opline->result.var;
|
zend_uchar old_var = opline->result.var;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue