]> granicus.if.org Git - php/commitdiff
Support more than two successors in opcache CFG
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 17 Mar 2017 20:37:57 +0000 (21:37 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Mon, 10 Apr 2017 20:18:24 +0000 (22:18 +0200)
ext/opcache/Optimizer/block_pass.c
ext/opcache/Optimizer/zend_cfg.c
ext/opcache/Optimizer/zend_cfg.h
ext/opcache/Optimizer/zend_dfg.c
ext/opcache/Optimizer/zend_ssa.c

index 767fb672a1973bb67e553672363314bc5fd0f604..7436c559c1cfbf3459c60b53be355e3f315d4fde 100644 (file)
@@ -1079,7 +1079,7 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
                                                last_op->op1.constant = zend_optimizer_add_literal(op_array, &zv);
                                        }
                                        DEL_SOURCE(block, block->successors[0]);
-                                       block->successors[0] = -1;
+                                       block->successors_count = 0;
 #if 0
                                /* Temporarily disabled - see bug #0025274 */
                                } else if (0&& block->op1_to != block &&
@@ -1152,13 +1152,13 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
                                        /* JMPNZ(true) -> JMP */
                                        last_op->opcode = ZEND_JMP;
                                        DEL_SOURCE(block, block->successors[1]);
-                                       block->successors[1] = -1;
+                                       block->successors_count = 1;
                                } else {
                                        /* JMPNZ(false) -> NOP */
                                        MAKE_NOP(last_op);
                                        DEL_SOURCE(block, block->successors[0]);
+                                       block->successors_count = 1;
                                        block->successors[0] = block->successors[1];
-                                       block->successors[1] = -1;
                                }
                                break;
                        }
@@ -1175,7 +1175,7 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
                                } else {
                                        MAKE_NOP(last_op);
                                }
-                               block->successors[1] = -1;
+                               block->successors_count = 1;
                                break;
                        }
 
@@ -1304,8 +1304,8 @@ next_target:
                                        last_op->opcode = ZEND_QM_ASSIGN;
                                        SET_UNUSED(last_op->op2);
                                        DEL_SOURCE(block, block->successors[0]);
+                                       block->successors_count = 1;
                                        block->successors[0] = block->successors[1];
-                                       block->successors[1] = -1;
                                }
                                break;
                        }
@@ -1404,7 +1404,7 @@ next_target_ex:
                                        SET_UNUSED(last_op->op1);
                                        SET_UNUSED(last_op->op2);
                                        DEL_SOURCE(block, block->successors[1]);
-                                       block->successors[1] = -1;
+                                       block->successors_count = 1;
                                } else {
                                        /* JMPZNZ(true,L1,L2) -> JMP(L2) */
                                        literal_dtor(&ZEND_OP1_LITERAL(last_op));
@@ -1412,8 +1412,8 @@ next_target_ex:
                                        SET_UNUSED(last_op->op1);
                                        SET_UNUSED(last_op->op2);
                                        DEL_SOURCE(block, block->successors[0]);
+                                       block->successors_count = 1;
                                        block->successors[0] = block->successors[1];
-                                       block->successors[1] = -1;
                                }
                        } else if (block->successors[0] == block->successors[1]) {
                                /* both goto the same one - it's JMP */
@@ -1422,7 +1422,7 @@ next_target_ex:
                                        last_op->opcode = ZEND_JMP;
                                        SET_UNUSED(last_op->op1);
                                        SET_UNUSED(last_op->op2);
-                                       block->successors[1] = -1;
+                                       block->successors_count = 1;
                                }
                        } else if (block->successors[0] == next) {
                                /* jumping to next on Z - can follow to it and jump only on NZ */
@@ -1606,7 +1606,7 @@ static void zend_t_usage(zend_cfg *cfg, zend_op_array *op_array, zend_bitset use
                    (next_block->flags & ZEND_BB_TARGET)) {
                        /* Skip continuation of "extended" BB */
                        zend_bitset_copy(usage, used_ext, bitset_len);
-               } else if (block->successors[1] != -1) {
+               } else if (block->successors_count > 1) {
                        zend_bitset_union(usage, used_ext, bitset_len);
                }
                next_block = block;
@@ -1724,8 +1724,7 @@ static void zend_merge_blocks(zend_op_array *op_array, zend_cfg *cfg)
                if (b->flags & ZEND_BB_REACHABLE) {
                        if ((b->flags & ZEND_BB_FOLLOW) &&
                            !(b->flags & (ZEND_BB_TARGET | ZEND_BB_PROTECTED)) &&
-                           prev &&
-                           prev->successors[0] == i && prev->successors[1] == -1)
+                           prev && prev->successors_count == 1 && prev->successors[0] == i)
                        {
                                zend_op *last_op = op_array->opcodes + prev->start + prev->len - 1;
                                if (prev->len != 0 && last_op->opcode == ZEND_JMP) {
@@ -1752,14 +1751,13 @@ static void zend_merge_blocks(zend_op_array *op_array, zend_cfg *cfg)
                                /* re-link */
                                prev->flags |= (b->flags & ZEND_BB_EXIT);
                                prev->len = b->start + b->len - prev->start;
-                               prev->successors[0] = b->successors[0];
-                               prev->successors[1] = b->successors[1];
+                               prev->successors_count = b->successors_count;
+                               memcpy(prev->successors, b->successors, b->successors_count * sizeof(int));
 
                                /* unlink & make block empty and unreachable */
                                b->flags = 0;
                                b->len = 0;
-                               b->successors[0] = -1;
-                               b->successors[1] = -1;
+                               b->successors_count = 0;
                        } else {
                                prev = b;
                        }
index 0f0cabb2587cd853645d80eed7164f20100ca13e..c4394757b86f766be45ae49769f9ca52f0f28797 100644 (file)
 
 static void zend_mark_reachable(zend_op *opcodes, zend_cfg *cfg, zend_basic_block *b) /* {{{ */
 {
-       zend_uchar opcode;
-       zend_basic_block *b0;
-       int successor_0, successor_1;
        zend_basic_block *blocks = cfg->blocks;
 
        while (1) {
+               int i;
+
                b->flags |= ZEND_BB_REACHABLE;
-               successor_0 = b->successors[0];
-               if (successor_0 >= 0) {
-                       successor_1 = b->successors[1];
-                       if (successor_1 >= 0) {
-                               b0 = blocks + successor_0;
-                               b0->flags |= ZEND_BB_TARGET;
-                               if (!(b0->flags & ZEND_BB_REACHABLE)) {
-                                       zend_mark_reachable(opcodes, cfg, b0);
-                               }
+               if (b->successors_count == 0) {
+                       b->flags |= ZEND_BB_EXIT;
+                       return;
+               }
 
-                               ZEND_ASSERT(b->len != 0);
-                               opcode = opcodes[b->start + b->len - 1].opcode;
-                               b = blocks + successor_1;
-                               if (opcode == ZEND_JMPZNZ) {
-                                       b->flags |= ZEND_BB_TARGET;
-                               } else {
-                                       b->flags |= ZEND_BB_FOLLOW;
-                               }
-                       } else if (b->len != 0) {
-                               opcode = opcodes[b->start + b->len - 1].opcode;
-                               b = blocks + successor_0;
-                               if (opcode == ZEND_JMP) {
-                                       b->flags |= ZEND_BB_TARGET;
-                               } else {
-                                       b->flags |= ZEND_BB_FOLLOW;
-
-                                       if (cfg->split_at_calls) {
-                                               if (opcode == ZEND_INCLUDE_OR_EVAL ||
-                                                   opcode == ZEND_GENERATOR_CREATE ||
-                                                   opcode == ZEND_YIELD ||
-                                                   opcode == ZEND_YIELD_FROM ||
-                                                   opcode == ZEND_DO_FCALL ||
-                                                   opcode == ZEND_DO_UCALL ||
-                                                   opcode == ZEND_DO_FCALL_BY_NAME) {
-                                                       b->flags |= ZEND_BB_ENTRY;
+               for (i = 0; i < b->successors_count; i++) {
+                       zend_basic_block *succ = blocks + b->successors[i];
+
+                       if (b->len != 0) {
+                               zend_uchar opcode = opcodes[b->start + b->len - 1].opcode;
+                               if (b->successors_count == 1) {
+                                       if (opcode == ZEND_JMP) {
+                                               succ->flags |= ZEND_BB_TARGET;
+
+                                               if (cfg->split_at_calls) {
+                                                       if (opcode == ZEND_INCLUDE_OR_EVAL ||
+                                                               opcode == ZEND_GENERATOR_CREATE ||
+                                                               opcode == ZEND_YIELD ||
+                                                               opcode == ZEND_YIELD_FROM ||
+                                                               opcode == ZEND_DO_FCALL ||
+                                                               opcode == ZEND_DO_UCALL ||
+                                                               opcode == ZEND_DO_FCALL_BY_NAME) {
+                                                               b->flags |= ZEND_BB_ENTRY;
+                                                       }
                                                }
-                                       }
-                                       if (cfg->split_at_recv) {
-                                               if (opcode == ZEND_RECV ||
-                                                   opcode == ZEND_RECV_INIT) {
-                                                       b->flags |= ZEND_BB_RECV_ENTRY;
+                                               if (cfg->split_at_recv) {
+                                                       if (opcode == ZEND_RECV ||
+                                                               opcode == ZEND_RECV_INIT) {
+                                                               b->flags |= ZEND_BB_RECV_ENTRY;
+                                                       }
                                                }
+                                       } else {
+                                               succ->flags |= ZEND_BB_FOLLOW;
+                                       }
+                               } else if (b->successors_count == 2) {
+                                       if (i == 0 || opcode == ZEND_JMPZNZ) {
+                                               succ->flags |= ZEND_BB_TARGET;
+                                       } else {
+                                               succ->flags |= ZEND_BB_FOLLOW;
                                        }
+                               } else {
+                                       ZEND_ASSERT(0);
                                }
                        } else {
-                               b = blocks + successor_0;
-                               b->flags |= ZEND_BB_FOLLOW;
+                               succ->flags |= ZEND_BB_FOLLOW;
+                       }
+
+                       if (i == b->successors_count - 1) {
+                               /* Tail call optimization */
+                               if (succ->flags & ZEND_BB_REACHABLE) {
+                                       return;
+                               }
+
+                               b = succ;
+                               break;
+                       } else {
+                               /* Recusively check reachability */
+                               if (!(succ->flags & ZEND_BB_REACHABLE)) {
+                                       zend_mark_reachable(opcodes, cfg, succ);
+                               }
                        }
-                       if (b->flags & ZEND_BB_REACHABLE) return;
-               } else {
-                       b->flags |= ZEND_BB_EXIT;
-                       return;
                }
        }
 }
@@ -251,15 +259,10 @@ void zend_cfg_remark_reachable_blocks(const zend_op_array *op_array, zend_cfg *c
 }
 /* }}} */
 
-static void record_successor(zend_basic_block *blocks, int pred, int n, int succ)
-{
-       blocks[pred].successors[n] = succ;
-}
-
 static void initialize_block(zend_basic_block *block) {
        block->flags = 0;
-       block->successors[0] = -1;
-       block->successors[1] = -1;
+       block->successors = block->successors_storage;
+       block->successors_count = 0;
        block->predecessors_count = 0;
        block->predecessor_offset = -1;
        block->idom = -1;
@@ -484,13 +487,15 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b
 
        /* Build CFG, Step 3: Calculate successors */
        for (j = 0; j < blocks_count; j++) {
+               zend_basic_block *block = &blocks[j];
                zend_op *opline;
-               if (blocks[j].len == 0) {
-                       record_successor(blocks, j, 0, j + 1);
+               if (block->len == 0) {
+                       block->successors_count = 1;
+                       block->successors[0] = j + 1;
                        continue;
                }
 
-               opline = op_array->opcodes + blocks[j].start + blocks[j].len - 1;
+               opline = op_array->opcodes + block->start + block->len - 1;
                switch (opline->opcode) {
                        case ZEND_FAST_RET:
                        case ZEND_RETURN:
@@ -500,11 +505,13 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b
                        case ZEND_THROW:
                                break;
                        case ZEND_JMP:
-                               record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes]);
+                               block->successors_count = 1;
+                               block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes];
                                break;
                        case ZEND_JMPZNZ:
-                               record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes]);
-                               record_successor(blocks, j, 1, block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)]);
+                               block->successors_count = 2;
+                               block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
+                               block->successors[1] = block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
                                break;
                        case ZEND_JMPZ:
                        case ZEND_JMPNZ:
@@ -513,35 +520,42 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b
                        case ZEND_JMP_SET:
                        case ZEND_COALESCE:
                        case ZEND_ASSERT_CHECK:
-                               record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes]);
-                               record_successor(blocks, j, 1, j + 1);
+                               block->successors_count = 2;
+                               block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
+                               block->successors[1] = j + 1;
                                break;
                        case ZEND_CATCH:
                                if (!opline->result.num) {
-                                       record_successor(blocks, j, 0, block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)]);
-                                       record_successor(blocks, j, 1, j + 1);
+                                       block->successors_count = 2;
+                                       block->successors[0] = block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
+                                       block->successors[1] = j + 1;
                                } else {
-                                       record_successor(blocks, j, 0, j + 1);
+                                       block->successors_count = 1;
+                                       block->successors[0] = j + 1;
                                }
                                break;
                        case ZEND_DECLARE_ANON_CLASS:
                        case ZEND_DECLARE_ANON_INHERITED_CLASS:
                        case ZEND_FE_FETCH_R:
                        case ZEND_FE_FETCH_RW:
-                               record_successor(blocks, j, 0, block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)]);
-                               record_successor(blocks, j, 1, j + 1);
+                               block->successors_count = 2;
+                               block->successors[0] = block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
+                               block->successors[1] = j + 1;
                                break;
                        case ZEND_FE_RESET_R:
                        case ZEND_FE_RESET_RW:
-                               record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes]);
-                               record_successor(blocks, j, 1, j + 1);
+                               block->successors_count = 2;
+                               block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
+                               block->successors[1] = j + 1;
                                break;
                        case ZEND_FAST_CALL:
-                               record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes]);
-                               record_successor(blocks, j, 1, j + 1);
+                               block->successors_count = 2;
+                               block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes];
+                               block->successors[1] = j + 1;
                                break;
                        default:
-                               record_successor(blocks, j, 0, j + 1);
+                               block->successors_count = 1;
+                               block->successors[0] = j + 1;
                                break;
                }
        }
@@ -559,7 +573,7 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b
 
 int zend_cfg_build_predecessors(zend_arena **arena, zend_cfg *cfg) /* {{{ */
 {
-       int j, edges;
+       int j, s, edges;
        zend_basic_block *b;
        zend_basic_block *blocks = cfg->blocks;
        zend_basic_block *end = blocks + cfg->blocks_count;
@@ -571,17 +585,12 @@ int zend_cfg_build_predecessors(zend_arena **arena, zend_cfg *cfg) /* {{{ */
        }
        for (b = blocks; b < end; b++) {
                if (!(b->flags & ZEND_BB_REACHABLE)) {
-                       b->successors[0] = -1;
-                       b->successors[1] = -1;
+                       b->successors_count = 0;
                        b->predecessors_count = 0;
                } else {
-                       if (b->successors[0] >= 0) {
+                       for (s = 0; s < b->successors_count; s++) {
                                edges++;
-                               blocks[b->successors[0]].predecessors_count++;
-                               if (b->successors[1] >= 0 && b->successors[1] != b->successors[0]) {
-                                       edges++;
-                                       blocks[b->successors[1]].predecessors_count++;
-                               }
+                               blocks[b->successors[s]].predecessors_count++;
                        }
                }
        }
@@ -599,16 +608,10 @@ int zend_cfg_build_predecessors(zend_arena **arena, zend_cfg *cfg) /* {{{ */
 
        for (j = 0; j < cfg->blocks_count; j++) {
                if (blocks[j].flags & ZEND_BB_REACHABLE) {
-                       if (blocks[j].successors[0] >= 0) {
-                               zend_basic_block *b = blocks + blocks[j].successors[0];
+                       for (s = 0; s < blocks[j].successors_count; s++) {
+                               zend_basic_block *b = blocks + blocks[j].successors[s];
                                predecessors[b->predecessor_offset + b->predecessors_count] = j;
                                b->predecessors_count++;
-                               if (blocks[j].successors[1] >= 0
-                                               && blocks[j].successors[1] != blocks[j].successors[0]) {
-                                       zend_basic_block *b = blocks + blocks[j].successors[1];
-                                       predecessors[b->predecessor_offset + b->predecessors_count] = j;
-                                       b->predecessors_count++;
-                               }
                        }
                }
        }
@@ -621,17 +624,15 @@ int zend_cfg_build_predecessors(zend_arena **arena, zend_cfg *cfg) /* {{{ */
 static void compute_postnum_recursive(
                int *postnum, int *cur, const zend_cfg *cfg, int block_num) /* {{{ */
 {
+       int s;
        zend_basic_block *block = &cfg->blocks[block_num];
        if (postnum[block_num] != -1) {
                return;
        }
 
        postnum[block_num] = -2; /* Marker for "currently visiting" */
-       if (block->successors[0] >= 0) {
-               compute_postnum_recursive(postnum, cur, cfg, block->successors[0]);
-               if (block->successors[1] >= 0) {
-                       compute_postnum_recursive(postnum, cur, cfg, block->successors[1]);
-               }
+       for (s = 0; s < block->successors_count; s++) {
+               compute_postnum_recursive(postnum, cur, cfg, block->successors[s]);
        }
        postnum[block_num] = (*cur)++;
 }
@@ -788,11 +789,9 @@ int zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *cfg, uint32
                        }
                }
                /* Visit join edges.  */
-               for (j = 0; j < 2; j++) {
+               for (j = 0; j < blocks[i].successors_count; j++) {
                        int succ = blocks[i].successors[j];
-                       if (succ < 0) {
-                               continue;
-                       } else if (blocks[succ].idom == i) {
+                       if (blocks[succ].idom == i) {
                                continue;
                        } else if (zend_worklist_push(&work, succ)) {
                                goto next;
index d24bbd910d7367f3e0717fcfeb819041754201b9..315b93ef3a4d1479875182dec40e381921975996 100644 (file)
 #define ZEND_BB_PROTECTED        (ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY|ZEND_BB_TRY|ZEND_BB_CATCH|ZEND_BB_FINALLY|ZEND_BB_FINALLY_END|ZEND_BB_GEN_VAR|ZEND_BB_KILL_VAR)
 
 typedef struct _zend_basic_block {
+       int              *successors;         /* successor block indices     */
        uint32_t          flags;
        uint32_t          start;              /* first opcode number         */
        uint32_t          len;                /* number of opcodes           */
-       int               successors[2];      /* up to 2 successor blocks    */
+       int               successors_count;   /* number of successors        */
        int               predecessors_count; /* number of predecessors      */
        int               predecessor_offset; /* offset of 1-st predecessor  */
        int               idom;               /* immediate dominator block   */
@@ -53,6 +54,7 @@ typedef struct _zend_basic_block {
        int               level;              /* steps away from the entry in the dom. tree */
        int               children;           /* list of dominated blocks    */
        int               next_child;         /* next dominated block        */
+       int               successors_storage[2]; /* up to 2 successor blocks */
 } zend_basic_block;
 
 /*
index 6e6997b2a5a58d915bc64685f4a5937be8da0a75..e51c3a583af5d79593040759babadc0a5402a78d 100644 (file)
@@ -220,10 +220,10 @@ op2_use:
                        if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) {
                                continue;
                        }
-                       if (blocks[j].successors[0] >= 0) {
+                       if (blocks[j].successors_count != 0) {
                                zend_bitset_copy(DFG_BITSET(out, set_size, j), DFG_BITSET(in, set_size, blocks[j].successors[0]), set_size);
-                               if (blocks[j].successors[1] >= 0) {
-                                       zend_bitset_union(DFG_BITSET(out, set_size, j), DFG_BITSET(in, set_size, blocks[j].successors[1]), set_size);
+                               for (k = 1; k < blocks[j].successors_count; k++) {
+                                       zend_bitset_union(DFG_BITSET(out, set_size, j), DFG_BITSET(in, set_size, blocks[j].successors[k]), set_size);
                                }
                        } else {
                                zend_bitset_clear(DFG_BITSET(out, set_size, j), set_size);
index 4c3361b5c641298dd03cb14df1fd78e3930f60d1..54bf985d40ca1d5e606af1e25b691e4816542a46 100644 (file)
@@ -61,6 +61,7 @@ static zend_bool needs_pi(const zend_op_array *op_array, zend_dfg *dfg, zend_ssa
        /* Check that the other successor of the from block does not dominate all other predecessors.
         * If it does, we'd probably end up annihilating a positive+negative pi assertion. */
        from_block = &ssa->cfg.blocks[from];
+       ZEND_ASSERT(from_block->successors_count == 2);
        other_successor = from_block->successors[0] == to
                ? from_block->successors[1] : from_block->successors[0];
        return !dominates_other_predecessors(&ssa->cfg, to_block, other_successor, from);
@@ -779,53 +780,51 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags,
                }
        }
 
-       for (i = 0; i < 2; i++) {
+       for (i = 0; i < blocks[n].successors_count; i++) {
                int succ = blocks[n].successors[i];
-               if (succ >= 0) {
-                       zend_ssa_phi *p;
-                       for (p = ssa_blocks[succ].phis; p; p = p->next) {
-                               if (p->pi == n) {
-                                       /* e-SSA Pi */
-                                       if (p->has_range_constraint) {
-                                               if (p->constraint.range.min_var >= 0) {
-                                                       p->constraint.range.min_ssa_var = var[p->constraint.range.min_var];
-                                               }
-                                               if (p->constraint.range.max_var >= 0) {
-                                                       p->constraint.range.max_ssa_var = var[p->constraint.range.max_var];
-                                               }
+               zend_ssa_phi *p;
+               for (p = ssa_blocks[succ].phis; p; p = p->next) {
+                       if (p->pi == n) {
+                               /* e-SSA Pi */
+                               if (p->has_range_constraint) {
+                                       if (p->constraint.range.min_var >= 0) {
+                                               p->constraint.range.min_ssa_var = var[p->constraint.range.min_var];
                                        }
-                                       for (j = 0; j < blocks[succ].predecessors_count; j++) {
-                                               p->sources[j] = var[p->var];
+                                       if (p->constraint.range.max_var >= 0) {
+                                               p->constraint.range.max_ssa_var = var[p->constraint.range.max_var];
                                        }
-                                       if (p->ssa_var < 0) {
-                                               p->ssa_var = ssa_vars_count;
-                                               ssa_vars_count++;
-                                       }
-                               } else if (p->pi < 0) {
-                                       /* Normal Phi */
-                                       for (j = 0; j < blocks[succ].predecessors_count; j++)
-                                               if (ssa->cfg.predecessors[blocks[succ].predecessor_offset + j] == n) {
-                                                       break;
-                                               }
-                                       ZEND_ASSERT(j < blocks[succ].predecessors_count);
+                               }
+                               for (j = 0; j < blocks[succ].predecessors_count; j++) {
                                        p->sources[j] = var[p->var];
                                }
+                               if (p->ssa_var < 0) {
+                                       p->ssa_var = ssa_vars_count;
+                                       ssa_vars_count++;
+                               }
+                       } else if (p->pi < 0) {
+                               /* Normal Phi */
+                               for (j = 0; j < blocks[succ].predecessors_count; j++)
+                                       if (ssa->cfg.predecessors[blocks[succ].predecessor_offset + j] == n) {
+                                               break;
+                                       }
+                               ZEND_ASSERT(j < blocks[succ].predecessors_count);
+                               p->sources[j] = var[p->var];
                        }
-                       for (p = ssa_blocks[succ].phis; p && (p->pi >= 0); p = p->next) {
-                               if (p->pi == n) {
-                                       zend_ssa_phi *q = p->next;
-                                       while (q) {
-                                               if (q->pi < 0 && q->var == p->var) {
-                                                       for (j = 0; j < blocks[succ].predecessors_count; j++) {
-                                                               if (ssa->cfg.predecessors[blocks[succ].predecessor_offset + j] == n) {
-                                                                       break;
-                                                               }
+               }
+               for (p = ssa_blocks[succ].phis; p && (p->pi >= 0); p = p->next) {
+                       if (p->pi == n) {
+                               zend_ssa_phi *q = p->next;
+                               while (q) {
+                                       if (q->pi < 0 && q->var == p->var) {
+                                               for (j = 0; j < blocks[succ].predecessors_count; j++) {
+                                                       if (ssa->cfg.predecessors[blocks[succ].predecessor_offset + j] == n) {
+                                                               break;
                                                        }
-                                                       ZEND_ASSERT(j < blocks[succ].predecessors_count);
-                                                       q->sources[j] = p->ssa_var;
                                                }
-                                               q = q->next;
+                                               ZEND_ASSERT(j < blocks[succ].predecessors_count);
+                                               q->sources[j] = p->ssa_var;
                                        }
+                                       q = q->next;
                                }
                        }
                }