]> granicus.if.org Git - php/commitdiff
SAMRT BRANCH improvement.
authorDmitry Stogov <dmitry@zend.com>
Wed, 9 Oct 2019 10:48:39 +0000 (13:48 +0300)
committerDmitry Stogov <dmitry@zend.com>
Wed, 9 Oct 2019 10:48:39 +0000 (13:48 +0300)
Avoid need of insertion NOP opcoes between unrelated SMART BRANCH instruction and following JMPZ/JMPNZ.
Now instead of checking the opcode of following instruction, the same information is encoded into SMART BRANH result_type.

Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_execute.c
Zend/zend_vm_execute.h
Zend/zend_vm_gen.php
ext/opcache/Optimizer/block_pass.c
ext/opcache/Optimizer/dfa_pass.c
ext/opcache/Optimizer/ssa_integrity.c
ext/opcache/Optimizer/zend_dump.c
ext/opcache/Optimizer/zend_optimizer.c
ext/opcache/jit/zend_jit.c

index 57ec93231037076edc9aa157027b21c5edb53090..edc0888c2d72333254e392fcbd6fb5601ca1a8a7 100644 (file)
@@ -2000,14 +2000,20 @@ ZEND_API int zend_is_smart_branch(const zend_op *opline) /* {{{ */
 static inline uint32_t zend_emit_cond_jump(zend_uchar opcode, znode *cond, uint32_t opnum_target) /* {{{ */
 {
        uint32_t opnum = get_next_op_number();
-       zend_op *opline;
-
-       if ((cond->op_type & (IS_CV|IS_CONST))
-        && opnum > 0
-        && zend_is_smart_branch(CG(active_op_array)->opcodes + opnum - 1)) {
-               /* emit extra NOP to avoid incorrect SMART_BRANCH in very rare cases */
-               zend_emit_op(NULL, ZEND_NOP, NULL, NULL);
-               opnum = get_next_op_number();
+       zend_op *opline = CG(active_op_array)->opcodes + opnum - 1;
+
+       if (cond->op_type == IS_TMP_VAR && opnum > 0) {
+               opline = CG(active_op_array)->opcodes + opnum - 1;
+               if (opline->result_type == IS_TMP_VAR
+                && opline->result.var == cond->u.op.var
+                && zend_is_smart_branch(opline)) {
+                       if (opcode == ZEND_JMPZ) {
+                               opline->result_type = IS_TMP_VAR | IS_SMART_BRANCH_JMPZ;
+                       } else {
+                               ZEND_ASSERT(opcode == ZEND_JMPNZ);
+                               opline->result_type = IS_TMP_VAR | IS_SMART_BRANCH_JMPNZ;
+                       }
+               }
        }
        opline = zend_emit_op(NULL, opcode, cond, NULL);
        opline->op2.opline_num = opnum_target;
index 03e007fe3354d6155f48d9fb59baba9f4dd0c549..b0ed47ddff72043767e42fdc2969b851e9118d67 100644 (file)
@@ -702,6 +702,10 @@ struct _zend_execute_data {
 #define IS_VAR         (1<<2)
 #define IS_CV          (1<<3)  /* Compiled variable */
 
+/* Used for result.type of smart branch instructions */
+#define IS_SMART_BRANCH_JMPZ  (1<<4)
+#define IS_SMART_BRANCH_JMPNZ (1<<5)
+
 #define ZEND_EXTRA_VALUE 1
 
 #include "zend_globals.h"
index 53c88f007c64ed405a8898fabfde002c715e70d1..2c544741192bb5fc4886bc15d96597f42e53c969 100644 (file)
@@ -4261,13 +4261,13 @@ static zend_never_inline int ZEND_FASTCALL zend_quick_check_constant(
 #define ZEND_VM_SMART_BRANCH(_result, _check) do { \
                if ((_check) && UNEXPECTED(EG(exception))) { \
                        OPLINE = EX(opline); \
-               } else if (EXPECTED((opline+1)->opcode == ZEND_JMPZ)) { \
+               } else if (EXPECTED(opline->result_type == (IS_SMART_BRANCH_JMPZ|IS_TMP_VAR))) { \
                        if (_result) { \
                                ZEND_VM_SET_NEXT_OPCODE(opline + 2); \
                        } else { \
                                ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline + 1, (opline+1)->op2)); \
                        } \
-               } else if (EXPECTED((opline+1)->opcode == ZEND_JMPNZ)) { \
+               } else if (EXPECTED(opline->result_type == (IS_SMART_BRANCH_JMPNZ|IS_TMP_VAR))) { \
                        if (!(_result)) { \
                                ZEND_VM_SET_NEXT_OPCODE(opline + 2); \
                        } else { \
@@ -4305,9 +4305,9 @@ static zend_never_inline int ZEND_FASTCALL zend_quick_check_constant(
                ZEND_VM_CONTINUE(); \
        } while (0)
 #define ZEND_VM_SMART_BRANCH_TRUE() do { \
-               if (EXPECTED((opline+1)->opcode == ZEND_JMPNZ)) { \
+               if (EXPECTED(opline->result_type == (IS_SMART_BRANCH_JMPNZ|IS_TMP_VAR))) { \
                        ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline + 1, (opline+1)->op2)); \
-               } else if (EXPECTED((opline+1)->opcode == ZEND_JMPZ)) { \
+               } else if (EXPECTED(opline->result_type == (IS_SMART_BRANCH_JMPZ|IS_TMP_VAR))) { \
                        ZEND_VM_SET_NEXT_OPCODE(opline + 2); \
                } else { \
                        ZVAL_TRUE(EX_VAR(opline->result.var)); \
@@ -4328,9 +4328,9 @@ static zend_never_inline int ZEND_FASTCALL zend_quick_check_constant(
                ZEND_VM_NEXT_OPCODE(); \
        } while (0)
 #define ZEND_VM_SMART_BRANCH_FALSE() do { \
-               if (EXPECTED((opline+1)->opcode == ZEND_JMPNZ)) { \
+               if (EXPECTED(opline->result_type == (IS_SMART_BRANCH_JMPNZ|IS_TMP_VAR))) { \
                        ZEND_VM_SET_NEXT_OPCODE(opline + 2); \
-               } else if (EXPECTED((opline+1)->opcode == ZEND_JMPZ)) { \
+               } else if (EXPECTED(opline->result_type == (IS_SMART_BRANCH_JMPZ|IS_TMP_VAR))) { \
                        ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline + 1, (opline+1)->op2)); \
                } else { \
                        ZVAL_FALSE(EX_VAR(opline->result.var)); \
index ffd3ede5814a7e4414111e803594ab266272dfca..accf802b17a5e69b2ae5d7a5ff66dc5850314d80 100644 (file)
@@ -61000,9 +61000,9 @@ static const uint32_t ZEND_FASTCALL zend_vm_get_opcode_handler_idx(uint32_t spec
                        offset = offset * 2 + (op->extended_value & ZEND_ISEMPTY);
                } else if (spec & SPEC_RULE_SMART_BRANCH) {
                        offset = offset * 3;
-                       if ((op+1)->opcode == ZEND_JMPZ) {
+                       if (op->result_type == (IS_SMART_BRANCH_JMPZ|IS_TMP_VAR)) {
                                offset += 1;
-                       } else if ((op+1)->opcode == ZEND_JMPNZ) {
+                       } else if (op->result_type == (IS_SMART_BRANCH_JMPNZ|IS_TMP_VAR)) {
                                offset += 2;
                        }
                }
index a63d0d03cc3a8ab3562a3ee72cd44982a295bcac..d263f542c50b9bfda86125f40eeea6195379d10d 100755 (executable)
@@ -2746,9 +2746,9 @@ function gen_vm($def, $skel) {
                        if (isset($used_extra_spec["SMART_BRANCH"])) {
                                out($f, "\t\t{$else}if (spec & SPEC_RULE_SMART_BRANCH) {\n");
                                out($f, "\t\t\toffset = offset * 3;\n");
-                               out($f, "\t\t\tif ((op+1)->opcode == ZEND_JMPZ) {\n");
+                               out($f, "\t\t\tif (op->result_type == (IS_SMART_BRANCH_JMPZ|IS_TMP_VAR)) {\n");
                                out($f, "\t\t\t\toffset += 1;\n");
-                               out($f, "\t\t\t} else if ((op+1)->opcode == ZEND_JMPNZ) {\n");
+                               out($f, "\t\t\t} else if (op->result_type == (IS_SMART_BRANCH_JMPNZ|IS_TMP_VAR)) {\n");
                                out($f, "\t\t\t\toffset += 2;\n");
                                out($f, "\t\t\t}\n");
                                $else = "} else ";
index 4e4d270b62eecf92080ba3af1943e5dbb4f78efc..d1f79d1ab8f68b356b57a8aa64958eaa84719384 100644 (file)
@@ -73,15 +73,6 @@ static void strip_leading_nops(zend_op_array *op_array, zend_basic_block *b)
        zend_op *opcodes = op_array->opcodes;
 
        do {
-           /* check if NOP breaks incorrect smart branch */
-               if (b->len == 2
-                && (opcodes[b->start + 1].opcode == ZEND_JMPZ
-                 || opcodes[b->start + 1].opcode == ZEND_JMPNZ)
-                && (opcodes[b->start + 1].op1_type & (IS_CV|IS_CONST))
-                && b->start > 0
-                && zend_is_smart_branch(opcodes + b->start - 1)) {
-                       break;
-               }
                b->start++;
                b->len--;
        } while (b->len > 0 && opcodes[b->start].opcode == ZEND_NOP);
@@ -112,14 +103,6 @@ static void strip_nops(zend_op_array *op_array, zend_basic_block *b)
                        }
                        j++;
                }
-               if (i + 1 < b->start + b->len
-                && (op_array->opcodes[i+1].opcode == ZEND_JMPZ
-                 || op_array->opcodes[i+1].opcode == ZEND_JMPNZ)
-                && op_array->opcodes[i+1].op1_type & (IS_CV|IS_CONST)
-                && zend_is_smart_branch(op_array->opcodes + j - 1)) {
-                       /* don't remove NOP, that splits incorrect smart branch */
-                       j++;
-               }
                i++;
        }
        b->len = j - b->start;
index f3156e1fa59dfc6be29bf8c47242832126d9ac7e..d753c54a00ddc583cf4d16f0d4ff32344430ea0e 100644 (file)
@@ -125,33 +125,6 @@ int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx,
        return SUCCESS;
 }
 
-static zend_bool is_smart_branch_inhibiting_nop(
-               zend_op_array *op_array, uint32_t target, uint32_t current,
-               zend_basic_block *b, zend_basic_block *blocks_end)
-{
-       uint32_t next;
-       /* Target points one past the last non-nop instruction. Make sure there is one. */
-       if (target == 0) {
-               return 0;
-       }
-
-       /* Find the next instruction, skipping unreachable or empty blocks. */
-       next = current + 1;
-       if (next >= b->start + b->len) {
-               do {
-                       b++;
-                       if (b == blocks_end) {
-                               return 0;
-                       }
-               } while (!(b->flags & ZEND_BB_REACHABLE) || b->len == 0);
-               next = b->start;
-       }
-
-       return (op_array->opcodes[next].opcode == ZEND_JMPZ ||
-                op_array->opcodes[next].opcode == ZEND_JMPNZ) &&
-               zend_is_smart_branch(op_array->opcodes + target - 1);
-}
-
 static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa, zend_optimizer_ctx *ctx)
 {
        zend_basic_block *blocks = ssa->cfg.blocks;
@@ -199,8 +172,7 @@ static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa, zend_op
                                old_end = b->start + b->len;
                                while (i < old_end) {
                                        shiftlist[i] = i - target;
-                                       if (EXPECTED(op_array->opcodes[i].opcode != ZEND_NOP) ||
-                                               is_smart_branch_inhibiting_nop(op_array, target, i, b, blocks_end)) {
+                                       if (EXPECTED(op_array->opcodes[i].opcode != ZEND_NOP)) {
                                                if (i != target) {
                                                        op_array->opcodes[target] = op_array->opcodes[i];
                                                        ssa->ops[target] = ssa->ops[i];
@@ -484,6 +456,24 @@ int zend_dfa_optimize_calls(zend_op_array *op_array, zend_ssa *ssa)
                                                MAKE_NOP(send_array);
                                                removed_ops++;
 
+                                               op_num = call_info->caller_call_opline - op_array->opcodes;
+                                               ssa_op = ssa->ops + op_num;
+                                               if (ssa_op->result_def >= 0) {
+                                                       int var = ssa_op->result_def;
+                                                       int use = ssa->vars[var].use_chain;
+
+                                                       if (ssa->vars[var].phi_use_chain == NULL) {
+                                                               if (ssa->ops[use].op1_use == var
+                                                                && ssa->ops[use].op1_use_chain == -1) {
+                                                                       call_info->caller_call_opline->result_type = IS_TMP_VAR;
+                                                                       op_array->opcodes[use].op1_type = IS_TMP_VAR;
+                                                               } else if (ssa->ops[use].op2_use == var
+                                                                && ssa->ops[use].op2_use_chain == -1) {
+                                                                       call_info->caller_call_opline->result_type = IS_TMP_VAR;
+                                                                       op_array->opcodes[use].op2_type = IS_TMP_VAR;
+                                                               }
+                                                       }
+                                               }
                                        }
                                }
                        }
@@ -533,8 +523,7 @@ static void compress_block(zend_op_array *op_array, zend_basic_block *block)
        while (block->len > 0) {
                zend_op *opline = &op_array->opcodes[block->start + block->len - 1];
 
-               if (opline->opcode == ZEND_NOP
-                               && (block->len == 1 || !zend_is_smart_branch(opline - 1))) {
+               if (opline->opcode == ZEND_NOP) {
                        block->len--;
                } else {
                        break;
index ede40be59a75fffa3c33d5a7cb6f35ba55049ad2..4f042cae74255e2f9b9a5529e546233265caa459 100644 (file)
@@ -87,7 +87,7 @@ static inline zend_bool is_in_successors(zend_basic_block *block, int check) {
 }
 
 static inline zend_bool is_var_type(zend_uchar type) {
-       return type == IS_CV || type == IS_VAR || type == IS_TMP_VAR;
+       return (type & (IS_CV|IS_VAR|IS_TMP_VAR)) != 0;
 }
 
 #define FAIL(...) do { \
index d10e7f989e2dbe5a07346ae12ff4c658191d4f36..cc4602192a54a1cd8d028aa90bc3bf5486c41d3c 100644 (file)
@@ -139,7 +139,7 @@ void zend_dump_var(const zend_op_array *op_array, zend_uchar var_type, int var_n
                fprintf(stderr, "CV%d($%s)", var_num, op_array->vars[var_num]->val);
        } else if (var_type == IS_VAR) {
                fprintf(stderr, "V%d", var_num);
-       } else if (var_type == IS_TMP_VAR) {
+       } else if (var_type == IS_TMP_VAR || !(var_type & (IS_VAR|IS_CV))) {
                fprintf(stderr, "T%d", var_num);
        } else {
                fprintf(stderr, "X%d", var_num);
@@ -688,6 +688,12 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *
        }
        if (opline->result_type == IS_CONST) {
                zend_dump_const(CRT_CONSTANT_EX(op_array, opline, opline->result, (dump_flags & ZEND_DUMP_RT_CONSTANTS)));
+#if 0
+       } else if (opline->result_type & IS_SMART_BRANCH_JMPZ) {
+               fprintf(stderr, " jmpz");
+       } else if (opline->result_type & IS_SMART_BRANCH_JMPNZ) {
+               fprintf(stderr, " jmpnz");
+#endif
        } else 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 (ssa && ssa->ops) {
index 1307c5f9c847016e54ff6f53e81bea87e298186f..d7f24e47cea2f9f912db5bf83b08ed643ab8d6c2 100644 (file)
@@ -1055,6 +1055,8 @@ static void zend_revert_pass_two(zend_op_array *op_array)
                if (opline->op2_type == IS_CONST) {
                        ZEND_PASS_TWO_UNDO_CONSTANT(op_array, opline, opline->op2);
                }
+               /* reset smart branch flags IS_SMART_BRANCH_JMP[N]Z */
+               opline->result_type &= (IS_TMP_VAR|IS_VAR|IS_CV|IS_CONST);
                opline++;
        }
 #if !ZEND_USE_ABS_CONST_ADDR
@@ -1099,10 +1101,10 @@ static void zend_redo_pass_two(zend_op_array *op_array)
                if (opline->op2_type == IS_CONST) {
                        ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline, opline->op2);
                }
-#if ZEND_USE_ABS_JMP_ADDR && !ZEND_USE_ABS_CONST_ADDR
                if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
                        /* fix jumps to point to new array */
                        switch (opline->opcode) {
+#if ZEND_USE_ABS_JMP_ADDR && !ZEND_USE_ABS_CONST_ADDR
                                case ZEND_JMP:
                                case ZEND_FAST_CALL:
                                        opline->op1.jmp_addr = &op_array->opcodes[opline->op1.jmp_addr - old_opcodes];
@@ -1132,9 +1134,41 @@ static void zend_redo_pass_two(zend_op_array *op_array)
                                case ZEND_SWITCH_STRING:
                                        /* relative extended_value don't have to be changed */
                                        break;
+#endif
+                               case ZEND_IS_IDENTICAL:
+                               case ZEND_IS_NOT_IDENTICAL:
+                               case ZEND_IS_EQUAL:
+                               case ZEND_IS_NOT_EQUAL:
+                               case ZEND_IS_SMALLER:
+                               case ZEND_IS_SMALLER_OR_EQUAL:
+                               case ZEND_CASE:
+                               case ZEND_ISSET_ISEMPTY_CV:
+                               case ZEND_ISSET_ISEMPTY_VAR:
+                               case ZEND_ISSET_ISEMPTY_DIM_OBJ:
+                               case ZEND_ISSET_ISEMPTY_PROP_OBJ:
+                               case ZEND_ISSET_ISEMPTY_STATIC_PROP:
+                               case ZEND_INSTANCEOF:
+                               case ZEND_TYPE_CHECK:
+                               case ZEND_DEFINED:
+                               case ZEND_IN_ARRAY:
+                               case ZEND_ARRAY_KEY_EXISTS:
+                                       if (opline->result_type & IS_TMP_VAR) {
+                                               /* reinitialize result_type od smart branch instructions */
+                                               if (opline + 1 < end) {
+                                                       if ((opline+1)->opcode == ZEND_JMPZ
+                                                        && (opline+1)->op1_type == IS_TMP_VAR
+                                                        && (opline+1)->op1.var == opline->result.var) {
+                                                               opline->result_type = IS_SMART_BRANCH_JMPZ | IS_TMP_VAR;
+                                                       } else if ((opline+1)->opcode == ZEND_JMPNZ
+                                                        && (opline+1)->op1_type == IS_TMP_VAR
+                                                        && (opline+1)->op1.var == opline->result.var) {
+                                                               opline->result_type = IS_SMART_BRANCH_JMPNZ | IS_TMP_VAR;
+                                                       }
+                                               }
+                                       }
+                                       break;
                        }
                }
-#endif
                ZEND_VM_SET_OPCODE_HANDLER(opline);
                opline++;
        }
@@ -1185,11 +1219,10 @@ static void zend_redo_pass_two_ex(zend_op_array *op_array, zend_ssa *ssa)
                        ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline, opline->op2);
                }
 
-               zend_vm_set_opcode_handler_ex(opline, op1_info, op2_info, res_info);
-#if ZEND_USE_ABS_JMP_ADDR && !ZEND_USE_ABS_CONST_ADDR
                if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
                        /* fix jumps to point to new array */
                        switch (opline->opcode) {
+#if ZEND_USE_ABS_JMP_ADDR && !ZEND_USE_ABS_CONST_ADDR
                                case ZEND_JMP:
                                case ZEND_FAST_CALL:
                                        opline->op1.jmp_addr = &op_array->opcodes[opline->op1.jmp_addr - old_opcodes];
@@ -1219,9 +1252,42 @@ static void zend_redo_pass_two_ex(zend_op_array *op_array, zend_ssa *ssa)
                                case ZEND_SWITCH_STRING:
                                        /* relative extended_value don't have to be changed */
                                        break;
+#endif
+                               case ZEND_IS_IDENTICAL:
+                               case ZEND_IS_NOT_IDENTICAL:
+                               case ZEND_IS_EQUAL:
+                               case ZEND_IS_NOT_EQUAL:
+                               case ZEND_IS_SMALLER:
+                               case ZEND_IS_SMALLER_OR_EQUAL:
+                               case ZEND_CASE:
+                               case ZEND_ISSET_ISEMPTY_CV:
+                               case ZEND_ISSET_ISEMPTY_VAR:
+                               case ZEND_ISSET_ISEMPTY_DIM_OBJ:
+                               case ZEND_ISSET_ISEMPTY_PROP_OBJ:
+                               case ZEND_ISSET_ISEMPTY_STATIC_PROP:
+                               case ZEND_INSTANCEOF:
+                               case ZEND_TYPE_CHECK:
+                               case ZEND_DEFINED:
+                               case ZEND_IN_ARRAY:
+                               case ZEND_ARRAY_KEY_EXISTS:
+                                       if (opline->result_type & IS_TMP_VAR) {
+                                               /* reinitialize result_type od smart branch instructions */
+                                               if (opline + 1 < end) {
+                                                       if ((opline+1)->opcode == ZEND_JMPZ
+                                                        && (opline+1)->op1_type == IS_TMP_VAR
+                                                        && (opline+1)->op1.var == opline->result.var) {
+                                                               opline->result_type = IS_SMART_BRANCH_JMPZ | IS_TMP_VAR;
+                                                       } else if ((opline+1)->opcode == ZEND_JMPNZ
+                                                        && (opline+1)->op1_type == IS_TMP_VAR
+                                                        && (opline+1)->op1.var == opline->result.var) {
+                                                               opline->result_type = IS_SMART_BRANCH_JMPNZ | IS_TMP_VAR;
+                                                       }
+                                               }
+                                       }
+                                       break;
                        }
                }
-#endif
+               zend_vm_set_opcode_handler_ex(opline, op1_info, op2_info, res_info);
                opline++;
        }
 }
index dccff807aaebdaffb99ec7829dcf8f5c08b9df35..8c7f1abcc65eba6e785f439a29b7a364a0179ffc 100644 (file)
@@ -2321,28 +2321,20 @@ static int zend_jit(zend_op_array *op_array, zend_ssa *ssa, const zend_op *rt_op
                                                goto done;
                                        case ZEND_JMPZ:
                                        case ZEND_JMPNZ:
-                                       case ZEND_JMPZNZ:
-                                       case ZEND_JMPZ_EX:
-                                       case ZEND_JMPNZ_EX:
-                                               if (i != ssa->cfg.blocks[b].start &&
-                                                   ((opline-1)->opcode == ZEND_IS_EQUAL ||
-                                                    (opline-1)->opcode == ZEND_IS_NOT_EQUAL ||
-                                                    (opline-1)->opcode == ZEND_IS_SMALLER ||
-                                                    (opline-1)->opcode == ZEND_IS_SMALLER_OR_EQUAL ||
-                                                    (opline-1)->opcode == ZEND_CASE)) {
-                                                       /* skip */
-                                               } else if (i != ssa->cfg.blocks[b].start &&
-                                                          (opline->opcode == ZEND_JMPZ ||
-                                                          (opline->opcode == ZEND_JMPNZ)) &&
-                                                              zend_is_smart_branch(opline-1)) {
-                                                   /* smart branch */
+                                               if (opline > op_array->opcodes &&
+                                                   ((opline-1)->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
+                                                       /* smart branch */
                                                        if (!zend_jit_cond_jmp(&dasm_state, opline + 1, ssa->cfg.blocks[b].successors[0])) {
                                                                goto jit_failure;
                                                        }
-                                               } else {
-                                                       if (!zend_jit_bool_jmpznz(&dasm_state, opline, b, op_array, ssa, ra)) {
-                                                               goto jit_failure;
-                                                       }
+                                                       goto done;
+                                               }
+                                               /* break missing intentionally */
+                                       case ZEND_JMPZNZ:
+                                       case ZEND_JMPZ_EX:
+                                       case ZEND_JMPNZ_EX:
+                                               if (!zend_jit_bool_jmpznz(&dasm_state, opline, b, op_array, ssa, ra)) {
+                                                       goto jit_failure;
                                                }
                                                goto done;
                                        case ZEND_FETCH_DIM_R:
@@ -2468,14 +2460,13 @@ static int zend_jit(zend_op_array *op_array, zend_ssa *ssa, const zend_op *rt_op
                                        break;
                                case ZEND_JMPZ:
                                case ZEND_JMPNZ:
-                                       if (i != ssa->cfg.blocks[b].start) {
-                                               if (zend_is_smart_branch(opline-1)) {
-                                                   /* smart branch */
-                                                       if (!zend_jit_cond_jmp(&dasm_state, opline + 1, ssa->cfg.blocks[b].successors[0])) {
-                                                               goto jit_failure;
-                                                       }
-                                                       break;
+                                       if (opline > op_array->opcodes &&
+                                           ((opline-1)->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
+                                               /* smart branch */
+                                               if (!zend_jit_cond_jmp(&dasm_state, opline + 1, ssa->cfg.blocks[b].successors[0])) {
+                                                       goto jit_failure;
                                                }
+                                               goto done;
                                        }
                                        /* break missing intentionally */
                                case ZEND_JMPZ_EX: