Skip to content

Remove JMPZNZ opcode #7857

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 1 addition & 162 deletions Zend/Optimizer/block_pass.c
Original file line number Diff line number Diff line change
Expand Up @@ -613,53 +613,6 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
}
break;

case ZEND_JMPZNZ:
while (1) {
if (opline->op1_type == IS_CONST) {
++(*opt_count);
if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
zend_op *target_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
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);
}
block->successors_count = 1;
opline->op1_type = IS_UNUSED;
opline->extended_value = 0;
opline->opcode = ZEND_JMP;
break;
} else if (opline->op1_type == IS_TMP_VAR &&
!zend_bitset_in(used_ext, VAR_NUM(opline->op1.var))) {
src = VAR_SOURCE(opline->op1);
if (src) {
if (src->opcode == ZEND_BOOL_NOT) {
/* T = BOOL_NOT(X) + JMPZNZ(T,L1,L2) -> NOP, JMPZNZ(X,L2,L1) */
uint32_t tmp;

VAR_SOURCE(opline->op1) = NULL;
COPY_NODE(opline->op1, src->op1);
tmp = block->successors[0];
block->successors[0] = block->successors[1];
block->successors[1] = tmp;
MAKE_NOP(src);
++(*opt_count);
continue;
} else if (src->opcode == ZEND_BOOL ||
src->opcode == ZEND_QM_ASSIGN) {
VAR_SOURCE(opline->op1) = NULL;
COPY_NODE(opline->op1, src->op1);
MAKE_NOP(src);
++(*opt_count);
continue;
}
}
}
break;
}
break;

case ZEND_JMPZ_EX:
case ZEND_JMPNZ_EX:
while (1) {
Expand Down Expand Up @@ -1025,9 +978,6 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array, zend_op
case ZEND_JMP:
ZEND_SET_OP_JMP_ADDR(opline, opline->op1, new_opcodes + blocks[b->successors[0]].start);
break;
case ZEND_JMPZNZ:
opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, new_opcodes + blocks[b->successors[1]].start);
ZEND_FALLTHROUGH;
case ZEND_JMPZ:
case ZEND_JMPNZ:
case ZEND_JMPZ_EX:
Expand Down Expand Up @@ -1239,20 +1189,7 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
block->len--;
} else if (target_block->len == 1) {
target = op_array->opcodes + target_block->start;
if (target->opcode == ZEND_JMPZNZ) {
/* JMP L, L: JMPZNZ L1,L2 -> JMPZNZ L1,L2 */
*last_op = *target;
if (last_op->op1_type == IS_CONST) {
zval zv;
ZVAL_COPY(&zv, &ZEND_OP1_LITERAL(last_op));
last_op->op1.constant = zend_optimizer_add_literal(op_array, &zv);
}
block->successors_count = 2;
block->successors[0] = target_block->successors[0];
block->successors[1] = target_block->successors[1];
++(*opt_count);
goto optimize_jmpznz;
} else if ((target->opcode == ZEND_RETURN ||
if ((target->opcode == ZEND_RETURN ||
target->opcode == ZEND_RETURN_BY_REF ||
target->opcode == ZEND_GENERATOR_RETURN ||
target->opcode == ZEND_EXIT) &&
Expand Down Expand Up @@ -1311,10 +1248,6 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
SAME_VAR(target->op1, last_op->op1)) {
/* JMPZ(X, L), L: JMPNZ(X, L2) -> JMPZ(X, L+1) */
next = target_block->successors[1];
} else if (target->opcode == ZEND_JMPZNZ &&
SAME_VAR(target->op1, last_op->op1)) {
/* JMPZ(X, L), L: JMPZNZ(X, L2, L3) -> JMPZ(X, L2) */
next = target_block->successors[last_op->opcode == ZEND_JMPNZ];
} else {
break;
}
Expand Down Expand Up @@ -1366,16 +1299,6 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
break;
}
}

/* JMPZ(X,L1), JMP(L2) -> JMPZNZ(X,L1,L2) */
if (last_op->opcode == ZEND_JMPZ) {
block->successors[1] = follow_block->successors[0];
} else {
block->successors[1] = block->successors[0];
block->successors[0] = follow_block->successors[0];
}
last_op->opcode = ZEND_JMPZNZ;
++(*opt_count);
}
}
break;
Expand All @@ -1402,11 +1325,6 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
SAME_VAR(target->op1, last_op->op1))) {
/* T = JMPZ_EX(X, L1), L1: T = JMPZ_EX({X|T}, L2) -> T = JMPZ_EX(X, L2) */
next = target_block->successors[0];
} else if (target->opcode == ZEND_JMPZNZ &&
(SAME_VAR(target->op1, last_op->result) ||
SAME_VAR(target->op1, last_op->op1))) {
/* T = JMPZ_EX(X, L), L: JMPZNZ({X|T}, L2, L3) -> T = JMPZ_EX(X, L2) */
next = target_block->successors[last_op->opcode == ZEND_JMPNZ_EX];
} else if (target->opcode == INV_EX_COND(last_op->opcode) &&
(SAME_VAR(target->op1, last_op->result) ||
SAME_VAR(target->op1, last_op->op1))) {
Expand Down Expand Up @@ -1453,85 +1371,6 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
break;
}
break;

case ZEND_JMPZNZ: {
optimize_jmpznz:
jmp_hitlist_count = 0;
target_block = get_target_block(cfg, block, 0, opt_count);
while (target_block->len == 1) {
target = op_array->opcodes + target_block->start;

if (target->opcode == ZEND_JMP) {
/* JMPZNZ(X, L1, L2), L1: JMP(L3) -> JMPZNZ(X, L3, L2) */
next = target_block->successors[0];
} else if ((target->opcode == ZEND_JMPZ || target->opcode == ZEND_JMPZNZ) &&
SAME_VAR(target->op1, last_op->op1)) {
/* JMPZNZ(X, L1, L2), L1: JMPZ(X, L3) -> JMPZNZ(X, L3, L2) */
next = target_block->successors[0];
} else if (target->opcode == ZEND_JMPNZ &&
SAME_VAR(target->op1, last_op->op1)) {
/* JMPZNZ(X, L1, L2), L1: X = JMPNZ(X, L3) -> JMPZNZ(X, L1+1, L2) */
next = target_block->successors[1];
} else {
break;
}
CHECK_LOOP(next);
block->successors[0] = next;
++(*opt_count);
target_block = get_target_block(cfg, block, 0, opt_count);
}

jmp_hitlist_count = 0;
follow_block = get_target_block(cfg, block, 1, opt_count);
while (follow_block->len == 1) {
target = op_array->opcodes + follow_block->start;

if (target->opcode == ZEND_JMP) {
/* JMPZNZ(X, L1, L2), L2: JMP(L3) -> JMPZNZ(X, L1, L3) */
next = follow_block->successors[0];
} else if (target->opcode == ZEND_JMPNZ &&
SAME_VAR(target->op1, last_op->op1)) {
/* JMPZNZ(X, L1, L2), L2: X = JMPNZ(X, L3) -> JMPZNZ(X, L1, L3) */
next = follow_block->successors[0];
} else if ((target->opcode == ZEND_JMPZ || target->opcode == ZEND_JMPZNZ) &&
SAME_VAR(target->op1, last_op->op1)) {
/* JMPZNZ(X, L1, L2), L2: JMPZ(X, L3) -> JMPZNZ(X, L1, L2+1) */
next = follow_block->successors[1];
} else {
break;
}
CHECK_LOOP(next);
block->successors[1] = next;
++(*opt_count);
follow_block = get_target_block(cfg, block, 1, opt_count);
}

next_block = get_next_block(cfg, block);
if (target_block == follow_block &&
!(last_op->op1_type & (IS_VAR|IS_TMP_VAR))) {
/* JMPZNZ(?,L,L) -> JMP(L) */
last_op->opcode = ZEND_JMP;
SET_UNUSED(last_op->op1);
SET_UNUSED(last_op->op2);
last_op->extended_value = 0;
block->successors_count = 1;
++(*opt_count);
} else if (target_block == next_block) {
/* jumping to next on Z - can follow to it and jump only on NZ */
/* JMPZNZ(X,L1,L2) L1: -> JMPNZ(X,L2) */
int tmp = block->successors[0];
last_op->opcode = ZEND_JMPNZ;
block->successors[0] = block->successors[1];
block->successors[1] = tmp;
++(*opt_count);
} else if (follow_block == next_block) {
/* jumping to next on NZ - can follow to it and jump only on Z */
/* JMPZNZ(X,L1,L2) L2: -> JMPZ(X,L1) */
last_op->opcode = ZEND_JMPZ;
++(*opt_count);
}
break;
}
}
}

Expand Down
1 change: 0 additions & 1 deletion Zend/Optimizer/dce.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,6 @@ static inline bool may_have_side_effects(
case ZEND_JMP:
case ZEND_JMPZ:
case ZEND_JMPNZ:
case ZEND_JMPZNZ:
case ZEND_JMPZ_EX:
case ZEND_JMPNZ_EX:
case ZEND_JMP_SET:
Expand Down
48 changes: 0 additions & 48 deletions Zend/Optimizer/dfa_pass.c
Original file line number Diff line number Diff line change
Expand Up @@ -627,11 +627,6 @@ static void zend_ssa_replace_control_link(zend_op_array *op_array, zend_ssa *ssa
ZEND_ASSERT(ZEND_OP1_JMP_ADDR(opline) == op_array->opcodes + old->start);
ZEND_SET_OP_JMP_ADDR(opline, opline->op1, op_array->opcodes + dst->start);
break;
case ZEND_JMPZNZ:
if (ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value) == old->start) {
opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, dst->start);
}
ZEND_FALLTHROUGH;
case ZEND_JMPZ:
case ZEND_JMPNZ:
case ZEND_JMPZ_EX:
Expand Down Expand Up @@ -809,49 +804,6 @@ static int zend_dfa_optimize_jmps(zend_op_array *op_array, zend_ssa *ssa)
}
}
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 if (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 && can_follow) {
if (opline->op1_type == IS_CV && (OP1_INFO() & MAY_BE_UNDEF)) {
opline->opcode = ZEND_CHECK_VAR;
opline->op2.num = 0;
} else 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++;
goto optimize_nop;
} else {
opline->opcode = ZEND_FREE;
opline->op2.num = 0;
}
} else if ((opline->op1_type == IS_CV && !(OP1_INFO() & MAY_BE_UNDEF)) || !(OP1_INFO() & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
ZEND_ASSERT(ssa_op->op1_use >= 0);
zend_ssa_unlink_use_chain(ssa, op_num, ssa_op->op1_use);
ssa_op->op1_use = -1;
ssa_op->op1_use_chain = -1;
opline->opcode = ZEND_JMP;
opline->op1_type = IS_UNUSED;
opline->op1.num = opline->op2.num;
goto optimize_jmp;
}
}
}
break;
case ZEND_JMPZ_EX:
if (ssa->vars[ssa_op->result_def].use_chain < 0
&& ssa->vars[ssa_op->result_def].phi_use_chain == NULL) {
Expand Down
17 changes: 0 additions & 17 deletions Zend/Optimizer/pass1.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,23 +335,6 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
collect_constants = 0;
break;

case ZEND_JMPZNZ:
if (opline->op1_type == IS_CONST) {
zend_op *target_opline;

if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
target_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value); /* JMPNZ */
} else {
target_opline = ZEND_OP2_JMP_ADDR(opline); /* JMPZ */
}
literal_dtor(&ZEND_OP1_LITERAL(opline));
ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
opline->op1_type = IS_UNUSED;
opline->opcode = ZEND_JMP;
}
collect_constants = 0;
break;

case ZEND_RETURN:
case ZEND_RETURN_BY_REF:
case ZEND_GENERATOR_RETURN:
Expand Down
Loading