Skip to content

Commit 4543cd3

Browse files
committed
Remove JMPZNZ opcode
While JMPZNZ can avoid execution of a separate JMP opcode in some cases, it also prevents smart branch optimization, so creating JMPZNZ may actually have a negative effect. It also adds additional complexity for optimizations. Drop JMPZNZ in favor of JMPZ+JMP or JMPNZ+JMP. Closes GH-7857.
1 parent 387c78a commit 4543cd3

23 files changed

+1376
-2199
lines changed

Zend/Optimizer/block_pass.c

Lines changed: 1 addition & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -613,53 +613,6 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
613613
}
614614
break;
615615

616-
case ZEND_JMPZNZ:
617-
while (1) {
618-
if (opline->op1_type == IS_CONST) {
619-
++(*opt_count);
620-
if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
621-
zend_op *target_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
622-
ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
623-
block->successors[0] = block->successors[1];
624-
} else {
625-
zend_op *target_opline = ZEND_OP2_JMP_ADDR(opline);
626-
ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
627-
}
628-
block->successors_count = 1;
629-
opline->op1_type = IS_UNUSED;
630-
opline->extended_value = 0;
631-
opline->opcode = ZEND_JMP;
632-
break;
633-
} else if (opline->op1_type == IS_TMP_VAR &&
634-
!zend_bitset_in(used_ext, VAR_NUM(opline->op1.var))) {
635-
src = VAR_SOURCE(opline->op1);
636-
if (src) {
637-
if (src->opcode == ZEND_BOOL_NOT) {
638-
/* T = BOOL_NOT(X) + JMPZNZ(T,L1,L2) -> NOP, JMPZNZ(X,L2,L1) */
639-
uint32_t tmp;
640-
641-
VAR_SOURCE(opline->op1) = NULL;
642-
COPY_NODE(opline->op1, src->op1);
643-
tmp = block->successors[0];
644-
block->successors[0] = block->successors[1];
645-
block->successors[1] = tmp;
646-
MAKE_NOP(src);
647-
++(*opt_count);
648-
continue;
649-
} else if (src->opcode == ZEND_BOOL ||
650-
src->opcode == ZEND_QM_ASSIGN) {
651-
VAR_SOURCE(opline->op1) = NULL;
652-
COPY_NODE(opline->op1, src->op1);
653-
MAKE_NOP(src);
654-
++(*opt_count);
655-
continue;
656-
}
657-
}
658-
}
659-
break;
660-
}
661-
break;
662-
663616
case ZEND_JMPZ_EX:
664617
case ZEND_JMPNZ_EX:
665618
while (1) {
@@ -1025,9 +978,6 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array, zend_op
1025978
case ZEND_JMP:
1026979
ZEND_SET_OP_JMP_ADDR(opline, opline->op1, new_opcodes + blocks[b->successors[0]].start);
1027980
break;
1028-
case ZEND_JMPZNZ:
1029-
opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, new_opcodes + blocks[b->successors[1]].start);
1030-
ZEND_FALLTHROUGH;
1031981
case ZEND_JMPZ:
1032982
case ZEND_JMPNZ:
1033983
case ZEND_JMPZ_EX:
@@ -1239,20 +1189,7 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
12391189
block->len--;
12401190
} else if (target_block->len == 1) {
12411191
target = op_array->opcodes + target_block->start;
1242-
if (target->opcode == ZEND_JMPZNZ) {
1243-
/* JMP L, L: JMPZNZ L1,L2 -> JMPZNZ L1,L2 */
1244-
*last_op = *target;
1245-
if (last_op->op1_type == IS_CONST) {
1246-
zval zv;
1247-
ZVAL_COPY(&zv, &ZEND_OP1_LITERAL(last_op));
1248-
last_op->op1.constant = zend_optimizer_add_literal(op_array, &zv);
1249-
}
1250-
block->successors_count = 2;
1251-
block->successors[0] = target_block->successors[0];
1252-
block->successors[1] = target_block->successors[1];
1253-
++(*opt_count);
1254-
goto optimize_jmpznz;
1255-
} else if ((target->opcode == ZEND_RETURN ||
1192+
if ((target->opcode == ZEND_RETURN ||
12561193
target->opcode == ZEND_RETURN_BY_REF ||
12571194
target->opcode == ZEND_GENERATOR_RETURN ||
12581195
target->opcode == ZEND_EXIT) &&
@@ -1311,10 +1248,6 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
13111248
SAME_VAR(target->op1, last_op->op1)) {
13121249
/* JMPZ(X, L), L: JMPNZ(X, L2) -> JMPZ(X, L+1) */
13131250
next = target_block->successors[1];
1314-
} else if (target->opcode == ZEND_JMPZNZ &&
1315-
SAME_VAR(target->op1, last_op->op1)) {
1316-
/* JMPZ(X, L), L: JMPZNZ(X, L2, L3) -> JMPZ(X, L2) */
1317-
next = target_block->successors[last_op->opcode == ZEND_JMPNZ];
13181251
} else {
13191252
break;
13201253
}
@@ -1366,16 +1299,6 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
13661299
break;
13671300
}
13681301
}
1369-
1370-
/* JMPZ(X,L1), JMP(L2) -> JMPZNZ(X,L1,L2) */
1371-
if (last_op->opcode == ZEND_JMPZ) {
1372-
block->successors[1] = follow_block->successors[0];
1373-
} else {
1374-
block->successors[1] = block->successors[0];
1375-
block->successors[0] = follow_block->successors[0];
1376-
}
1377-
last_op->opcode = ZEND_JMPZNZ;
1378-
++(*opt_count);
13791302
}
13801303
}
13811304
break;
@@ -1402,11 +1325,6 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
14021325
SAME_VAR(target->op1, last_op->op1))) {
14031326
/* T = JMPZ_EX(X, L1), L1: T = JMPZ_EX({X|T}, L2) -> T = JMPZ_EX(X, L2) */
14041327
next = target_block->successors[0];
1405-
} else if (target->opcode == ZEND_JMPZNZ &&
1406-
(SAME_VAR(target->op1, last_op->result) ||
1407-
SAME_VAR(target->op1, last_op->op1))) {
1408-
/* T = JMPZ_EX(X, L), L: JMPZNZ({X|T}, L2, L3) -> T = JMPZ_EX(X, L2) */
1409-
next = target_block->successors[last_op->opcode == ZEND_JMPNZ_EX];
14101328
} else if (target->opcode == INV_EX_COND(last_op->opcode) &&
14111329
(SAME_VAR(target->op1, last_op->result) ||
14121330
SAME_VAR(target->op1, last_op->op1))) {
@@ -1453,85 +1371,6 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
14531371
break;
14541372
}
14551373
break;
1456-
1457-
case ZEND_JMPZNZ: {
1458-
optimize_jmpznz:
1459-
jmp_hitlist_count = 0;
1460-
target_block = get_target_block(cfg, block, 0, opt_count);
1461-
while (target_block->len == 1) {
1462-
target = op_array->opcodes + target_block->start;
1463-
1464-
if (target->opcode == ZEND_JMP) {
1465-
/* JMPZNZ(X, L1, L2), L1: JMP(L3) -> JMPZNZ(X, L3, L2) */
1466-
next = target_block->successors[0];
1467-
} else if ((target->opcode == ZEND_JMPZ || target->opcode == ZEND_JMPZNZ) &&
1468-
SAME_VAR(target->op1, last_op->op1)) {
1469-
/* JMPZNZ(X, L1, L2), L1: JMPZ(X, L3) -> JMPZNZ(X, L3, L2) */
1470-
next = target_block->successors[0];
1471-
} else if (target->opcode == ZEND_JMPNZ &&
1472-
SAME_VAR(target->op1, last_op->op1)) {
1473-
/* JMPZNZ(X, L1, L2), L1: X = JMPNZ(X, L3) -> JMPZNZ(X, L1+1, L2) */
1474-
next = target_block->successors[1];
1475-
} else {
1476-
break;
1477-
}
1478-
CHECK_LOOP(next);
1479-
block->successors[0] = next;
1480-
++(*opt_count);
1481-
target_block = get_target_block(cfg, block, 0, opt_count);
1482-
}
1483-
1484-
jmp_hitlist_count = 0;
1485-
follow_block = get_target_block(cfg, block, 1, opt_count);
1486-
while (follow_block->len == 1) {
1487-
target = op_array->opcodes + follow_block->start;
1488-
1489-
if (target->opcode == ZEND_JMP) {
1490-
/* JMPZNZ(X, L1, L2), L2: JMP(L3) -> JMPZNZ(X, L1, L3) */
1491-
next = follow_block->successors[0];
1492-
} else if (target->opcode == ZEND_JMPNZ &&
1493-
SAME_VAR(target->op1, last_op->op1)) {
1494-
/* JMPZNZ(X, L1, L2), L2: X = JMPNZ(X, L3) -> JMPZNZ(X, L1, L3) */
1495-
next = follow_block->successors[0];
1496-
} else if ((target->opcode == ZEND_JMPZ || target->opcode == ZEND_JMPZNZ) &&
1497-
SAME_VAR(target->op1, last_op->op1)) {
1498-
/* JMPZNZ(X, L1, L2), L2: JMPZ(X, L3) -> JMPZNZ(X, L1, L2+1) */
1499-
next = follow_block->successors[1];
1500-
} else {
1501-
break;
1502-
}
1503-
CHECK_LOOP(next);
1504-
block->successors[1] = next;
1505-
++(*opt_count);
1506-
follow_block = get_target_block(cfg, block, 1, opt_count);
1507-
}
1508-
1509-
next_block = get_next_block(cfg, block);
1510-
if (target_block == follow_block &&
1511-
!(last_op->op1_type & (IS_VAR|IS_TMP_VAR))) {
1512-
/* JMPZNZ(?,L,L) -> JMP(L) */
1513-
last_op->opcode = ZEND_JMP;
1514-
SET_UNUSED(last_op->op1);
1515-
SET_UNUSED(last_op->op2);
1516-
last_op->extended_value = 0;
1517-
block->successors_count = 1;
1518-
++(*opt_count);
1519-
} else if (target_block == next_block) {
1520-
/* jumping to next on Z - can follow to it and jump only on NZ */
1521-
/* JMPZNZ(X,L1,L2) L1: -> JMPNZ(X,L2) */
1522-
int tmp = block->successors[0];
1523-
last_op->opcode = ZEND_JMPNZ;
1524-
block->successors[0] = block->successors[1];
1525-
block->successors[1] = tmp;
1526-
++(*opt_count);
1527-
} else if (follow_block == next_block) {
1528-
/* jumping to next on NZ - can follow to it and jump only on Z */
1529-
/* JMPZNZ(X,L1,L2) L2: -> JMPZ(X,L1) */
1530-
last_op->opcode = ZEND_JMPZ;
1531-
++(*opt_count);
1532-
}
1533-
break;
1534-
}
15351374
}
15361375
}
15371376

Zend/Optimizer/dce.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,6 @@ static inline bool may_have_side_effects(
139139
case ZEND_JMP:
140140
case ZEND_JMPZ:
141141
case ZEND_JMPNZ:
142-
case ZEND_JMPZNZ:
143142
case ZEND_JMPZ_EX:
144143
case ZEND_JMPNZ_EX:
145144
case ZEND_JMP_SET:

Zend/Optimizer/dfa_pass.c

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -627,11 +627,6 @@ static void zend_ssa_replace_control_link(zend_op_array *op_array, zend_ssa *ssa
627627
ZEND_ASSERT(ZEND_OP1_JMP_ADDR(opline) == op_array->opcodes + old->start);
628628
ZEND_SET_OP_JMP_ADDR(opline, opline->op1, op_array->opcodes + dst->start);
629629
break;
630-
case ZEND_JMPZNZ:
631-
if (ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value) == old->start) {
632-
opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, dst->start);
633-
}
634-
ZEND_FALLTHROUGH;
635630
case ZEND_JMPZ:
636631
case ZEND_JMPNZ:
637632
case ZEND_JMPZ_EX:
@@ -809,49 +804,6 @@ static int zend_dfa_optimize_jmps(zend_op_array *op_array, zend_ssa *ssa)
809804
}
810805
}
811806
break;
812-
case ZEND_JMPZNZ:
813-
if (opline->op1_type == IS_CONST) {
814-
if (zend_is_true(CT_CONSTANT_EX(op_array, opline->op1.constant))) {
815-
zend_op *target_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
816-
ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
817-
take_successor_1(ssa, block_num, block);
818-
} else {
819-
zend_op *target_opline = ZEND_OP2_JMP_ADDR(opline);
820-
ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
821-
take_successor_0(ssa, block_num, block);
822-
}
823-
opline->op1_type = IS_UNUSED;
824-
opline->extended_value = 0;
825-
opline->opcode = ZEND_JMP;
826-
goto optimize_jmp;
827-
} else if (block->successors_count == 2) {
828-
if (block->successors[0] == block->successors[1]) {
829-
take_successor_0(ssa, block_num, block);
830-
if (block->successors[0] == next_block_num && can_follow) {
831-
if (opline->op1_type == IS_CV && (OP1_INFO() & MAY_BE_UNDEF)) {
832-
opline->opcode = ZEND_CHECK_VAR;
833-
opline->op2.num = 0;
834-
} else if (opline->op1_type == IS_CV || !(OP1_INFO() & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
835-
zend_ssa_remove_instr(ssa, opline, ssa_op);
836-
removed_ops++;
837-
goto optimize_nop;
838-
} else {
839-
opline->opcode = ZEND_FREE;
840-
opline->op2.num = 0;
841-
}
842-
} 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))) {
843-
ZEND_ASSERT(ssa_op->op1_use >= 0);
844-
zend_ssa_unlink_use_chain(ssa, op_num, ssa_op->op1_use);
845-
ssa_op->op1_use = -1;
846-
ssa_op->op1_use_chain = -1;
847-
opline->opcode = ZEND_JMP;
848-
opline->op1_type = IS_UNUSED;
849-
opline->op1.num = opline->op2.num;
850-
goto optimize_jmp;
851-
}
852-
}
853-
}
854-
break;
855807
case ZEND_JMPZ_EX:
856808
if (ssa->vars[ssa_op->result_def].use_chain < 0
857809
&& ssa->vars[ssa_op->result_def].phi_use_chain == NULL) {

Zend/Optimizer/pass1.c

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -335,23 +335,6 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
335335
collect_constants = 0;
336336
break;
337337

338-
case ZEND_JMPZNZ:
339-
if (opline->op1_type == IS_CONST) {
340-
zend_op *target_opline;
341-
342-
if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
343-
target_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value); /* JMPNZ */
344-
} else {
345-
target_opline = ZEND_OP2_JMP_ADDR(opline); /* JMPZ */
346-
}
347-
literal_dtor(&ZEND_OP1_LITERAL(opline));
348-
ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
349-
opline->op1_type = IS_UNUSED;
350-
opline->opcode = ZEND_JMP;
351-
}
352-
collect_constants = 0;
353-
break;
354-
355338
case ZEND_RETURN:
356339
case ZEND_RETURN_BY_REF:
357340
case ZEND_GENERATOR_RETURN:

0 commit comments

Comments
 (0)