source: src/router/php7/ext/opcache/Optimizer/zend_ssa.c @ 31874

Last change on this file since 31874 was 31874, checked in by brainslayer, 4 months ago

update php

File size: 37.0 KB
Line 
1/*
2   +----------------------------------------------------------------------+
3   | Zend Engine, SSA - Static Single Assignment Form                     |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1998-2017 The PHP Group                                |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.php.net/license/3_01.txt                                  |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Authors: Dmitry Stogov <dmitry@zend.com>                             |
16   +----------------------------------------------------------------------+
17*/
18
19#include "php.h"
20#include "zend_compile.h"
21#include "zend_dfg.h"
22#include "zend_ssa.h"
23#include "zend_dump.h"
24#include "zend_inference.h"
25
26static zend_bool dominates(const zend_basic_block *blocks, int a, int b) {
27        while (blocks[b].level > blocks[a].level) {
28                b = blocks[b].idom;
29        }
30        return a == b;
31}
32
33static zend_bool dominates_other_predecessors(
34                const zend_cfg *cfg, const zend_basic_block *block, int check, int exclude) {
35        int i;
36        for (i = 0; i < block->predecessors_count; i++) {
37                int predecessor = cfg->predecessors[block->predecessor_offset + i];
38                if (predecessor != exclude && !dominates(cfg->blocks, check, predecessor)) {
39                        return 0;
40                }
41        }
42        return 1;
43}
44
45static zend_bool needs_pi(const zend_op_array *op_array, zend_dfg *dfg, zend_ssa *ssa, int from, int to, int var) /* {{{ */
46{
47        zend_basic_block *from_block, *to_block;
48        int other_successor;
49
50        if (!DFG_ISSET(dfg->in, dfg->size, to, var)) {
51                /* Variable is not live, certainly won't benefit from pi */
52                return 0;
53        }
54
55        to_block = &ssa->cfg.blocks[to];
56        if (to_block->predecessors_count == 1) {
57                /* Always place pi if one predecessor (an if branch) */
58                return 1;
59        }
60
61        /* Check that the other successor of the from block does not dominate all other predecessors.
62         * If it does, we'd probably end up annihilating a positive+negative pi assertion. */
63        from_block = &ssa->cfg.blocks[from];
64        other_successor = from_block->successors[0] == to
65                ? from_block->successors[1] : from_block->successors[0];
66        return !dominates_other_predecessors(&ssa->cfg, to_block, other_successor, from);
67}
68/* }}} */
69
70static zend_ssa_phi *add_pi(
71                zend_arena **arena, const zend_op_array *op_array, zend_dfg *dfg, zend_ssa *ssa,
72                int from, int to, int var) /* {{{ */
73{
74        zend_ssa_phi *phi;
75        if (!needs_pi(op_array, dfg, ssa, from, to, var)) {
76                return NULL;
77        }
78
79        phi = zend_arena_calloc(arena, 1,
80                ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)) +
81                ZEND_MM_ALIGNED_SIZE(sizeof(int) * ssa->cfg.blocks[to].predecessors_count) +
82                sizeof(void*) * ssa->cfg.blocks[to].predecessors_count);
83        phi->sources = (int*)(((char*)phi) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)));
84        memset(phi->sources, 0xff, sizeof(int) * ssa->cfg.blocks[to].predecessors_count);
85        phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + ZEND_MM_ALIGNED_SIZE(sizeof(int) * ssa->cfg.blocks[to].predecessors_count));
86
87        phi->pi = from;
88        phi->var = var;
89        phi->ssa_var = -1;
90        phi->next = ssa->blocks[to].phis;
91        ssa->blocks[to].phis = phi;
92
93        /* Block "to" now defines "var" via the pi statement, so add it to the "def" set. Note that
94         * this is not entirely accurate, because the pi is actually placed along the edge from->to.
95         * If there is a back-edge to "to" this may result in non-minimal SSA form. */
96        DFG_SET(dfg->def, dfg->size, to, var);
97
98        /* If there are multiple predecessors in the target block, we need to place a phi there.
99         * However this can (generally) not be expressed in terms of dominance frontiers, so place it
100         * explicitly. dfg->use here really is dfg->phi, we're reusing the set. */
101        if (ssa->cfg.blocks[to].predecessors_count > 1) {
102                DFG_SET(dfg->use, dfg->size, to, var);
103        }
104
105        return phi;
106}
107/* }}} */
108
109static void pi_range(
110                zend_ssa_phi *phi, int min_var, int max_var, zend_long min, zend_long max,
111                char underflow, char overflow, char negative) /* {{{ */
112{
113        zend_ssa_range_constraint *constraint = &phi->constraint.range;
114        constraint->min_var = min_var;
115        constraint->max_var = max_var;
116        constraint->min_ssa_var = -1;
117        constraint->max_ssa_var = -1;
118        constraint->range.min = min;
119        constraint->range.max = max;
120        constraint->range.underflow = underflow;
121        constraint->range.overflow = overflow;
122        constraint->negative = negative ? NEG_INIT : NEG_NONE;
123        phi->has_range_constraint = 1;
124}
125/* }}} */
126
127static inline void pi_range_equals(zend_ssa_phi *phi, int var, zend_long val) {
128        pi_range(phi, var, var, val, val, 0, 0, 0);
129}
130static inline void pi_range_not_equals(zend_ssa_phi *phi, int var, zend_long val) {
131        pi_range(phi, var, var, val, val, 0, 0, 1);
132}
133static inline void pi_range_min(zend_ssa_phi *phi, int var, zend_long val) {
134        pi_range(phi, var, -1, val, ZEND_LONG_MAX, 0, 1, 0);
135}
136static inline void pi_range_max(zend_ssa_phi *phi, int var, zend_long val) {
137        pi_range(phi, -1, var, ZEND_LONG_MIN, val, 1, 0, 0);
138}
139
140static void pi_type_mask(zend_ssa_phi *phi, uint32_t type_mask) {
141        phi->has_range_constraint = 0;
142        phi->constraint.type.ce = NULL;
143        phi->constraint.type.type_mask = MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
144        phi->constraint.type.type_mask |= type_mask;
145        if (type_mask & MAY_BE_NULL) {
146                phi->constraint.type.type_mask |= MAY_BE_UNDEF;
147        }
148}
149static inline void pi_not_type_mask(zend_ssa_phi *phi, uint32_t type_mask) {
150        uint32_t relevant = MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
151        pi_type_mask(phi, ~type_mask & relevant);
152}
153static inline uint32_t mask_for_type_check(uint32_t type) {
154        if (type == _IS_BOOL) {
155                return MAY_BE_TRUE|MAY_BE_FALSE;
156        } else if (type == IS_ARRAY) {
157                return MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
158        } else {
159                return 1 << type;
160        }
161}
162
163/* We can interpret $a + 5 == 0 as $a = 0 - 5, i.e. shift the adjustment to the other operand.
164 * This negated adjustment is what is written into the "adjustment" parameter. */
165static int find_adjusted_tmp_var(const zend_op_array *op_array, uint32_t build_flags, zend_op *opline, uint32_t var_num, zend_long *adjustment) /* {{{ */
166{
167        zend_op *op = opline;
168        zval *zv;
169
170        while (op != op_array->opcodes) {
171                op--;
172                if (op->result_type != IS_TMP_VAR || op->result.var != var_num) {
173                        continue;
174                }
175
176                if (op->opcode == ZEND_POST_DEC) {
177                        if (op->op1_type == IS_CV) {
178                                *adjustment = -1;
179                                return EX_VAR_TO_NUM(op->op1.var);
180                        }
181                } else if (op->opcode == ZEND_POST_INC) {
182                        if (op->op1_type == IS_CV) {
183                                *adjustment = 1;
184                                return EX_VAR_TO_NUM(op->op1.var);
185                        }
186                } else if (op->opcode == ZEND_ADD) {
187                        if (op->op1_type == IS_CV && op->op2_type == IS_CONST) {
188                                zv = CRT_CONSTANT(op->op2);
189                                if (Z_TYPE_P(zv) == IS_LONG
190                                 && Z_LVAL_P(zv) != ZEND_LONG_MIN) {
191                                        *adjustment = -Z_LVAL_P(zv);
192                                        return EX_VAR_TO_NUM(op->op1.var);
193                                }
194                        } else if (op->op2_type == IS_CV && op->op1_type == IS_CONST) {
195                                zv = CRT_CONSTANT(op->op1);
196                                if (Z_TYPE_P(zv) == IS_LONG
197                                 && Z_LVAL_P(zv) != ZEND_LONG_MIN) {
198                                        *adjustment = -Z_LVAL_P(zv);
199                                        return EX_VAR_TO_NUM(op->op2.var);
200                                }
201                        }
202                } else if (op->opcode == ZEND_SUB) {
203                        if (op->op1_type == IS_CV && op->op2_type == IS_CONST) {
204                                zv = CRT_CONSTANT(op->op2);
205                                if (Z_TYPE_P(zv) == IS_LONG) {
206                                        *adjustment = Z_LVAL_P(zv);
207                                        return EX_VAR_TO_NUM(op->op1.var);
208                                }
209                        }
210                }
211                break;
212        }
213        return -1;
214}
215/* }}} */
216
217static inline zend_bool add_will_overflow(zend_long a, zend_long b) {
218        return (b > 0 && a > ZEND_LONG_MAX - b)
219                || (b < 0 && a < ZEND_LONG_MIN - b);
220}
221static inline zend_bool sub_will_overflow(zend_long a, zend_long b) {
222        return (b > 0 && a < ZEND_LONG_MIN + b)
223                || (b < 0 && a > ZEND_LONG_MAX + b);
224}
225
226/* e-SSA construction: Pi placement (Pi is actually a Phi with single
227 * source and constraint).
228 * Order of Phis is importent, Pis must be placed before Phis
229 */
230static void place_essa_pis(
231                zend_arena **arena, const zend_script *script, const zend_op_array *op_array,
232                uint32_t build_flags, zend_ssa *ssa, zend_dfg *dfg) /* {{{ */ {
233        zend_basic_block *blocks = ssa->cfg.blocks;
234        int j, blocks_count = ssa->cfg.blocks_count;
235        for (j = 0; j < blocks_count; j++) {
236                zend_ssa_phi *pi;
237                zend_op *opline = op_array->opcodes + blocks[j].start + blocks[j].len - 1;
238                int bt; /* successor block number if a condition is true */
239                int bf; /* successor block number if a condition is false */
240
241                if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0 || blocks[j].len == 0) {
242                        continue;
243                }
244                /* the last instruction of basic block is conditional branch,
245                 * based on comparison of CV(s)
246                 */
247                switch (opline->opcode) {
248                        case ZEND_JMPZ:
249                        case ZEND_JMPZNZ:
250                                bf = blocks[j].successors[0];
251                                bt = blocks[j].successors[1];
252                                break;
253                        case ZEND_JMPNZ:
254                                bt = blocks[j].successors[0];
255                                bf = blocks[j].successors[1];
256                                break;
257                        default:
258                                continue;
259                }
260                if (opline->op1_type == IS_TMP_VAR &&
261                    ((opline-1)->opcode == ZEND_IS_EQUAL ||
262                     (opline-1)->opcode == ZEND_IS_NOT_EQUAL ||
263                     (opline-1)->opcode == ZEND_IS_SMALLER ||
264                     (opline-1)->opcode == ZEND_IS_SMALLER_OR_EQUAL) &&
265                    opline->op1.var == (opline-1)->result.var) {
266                        int  var1 = -1;
267                        int  var2 = -1;
268                        zend_long val1 = 0;
269                        zend_long val2 = 0;
270//                      long val = 0;
271
272                        if ((opline-1)->op1_type == IS_CV) {
273                                var1 = EX_VAR_TO_NUM((opline-1)->op1.var);
274                        } else if ((opline-1)->op1_type == IS_TMP_VAR) {
275                                var1 = find_adjusted_tmp_var(
276                                        op_array, build_flags, opline, (opline-1)->op1.var, &val2);
277                        }
278
279                        if ((opline-1)->op2_type == IS_CV) {
280                                var2 = EX_VAR_TO_NUM((opline-1)->op2.var);
281                        } else if ((opline-1)->op2_type == IS_TMP_VAR) {
282                                var2 = find_adjusted_tmp_var(
283                                        op_array, build_flags, opline, (opline-1)->op2.var, &val1);
284                        }
285
286                        if (var1 >= 0 && var2 >= 0) {
287                                if (!sub_will_overflow(val1, val2) && !sub_will_overflow(val2, val1)) {
288                                        zend_long tmp = val1;
289                                        val1 -= val2;
290                                        val2 -= tmp;
291                                } else {
292                                        var1 = -1;
293                                        var2 = -1;
294                                }
295                        } else if (var1 >= 0 && var2 < 0) {
296                                zend_long add_val2 = 0;
297                                if ((opline-1)->op2_type == IS_CONST) {
298                                        zval *zv = CRT_CONSTANT((opline-1)->op2);
299
300                                        if (Z_TYPE_P(zv) == IS_LONG) {
301                                                add_val2 = Z_LVAL_P(zv);
302                                        } else if (Z_TYPE_P(zv) == IS_FALSE) {
303                                                add_val2 = 0;
304                                        } else if (Z_TYPE_P(zv) == IS_TRUE) {
305                                                add_val2 = 1;
306                                        } else {
307                                                var1 = -1;
308                                        }
309                                } else {
310                                        var1 = -1;
311                                }
312                                if (!add_will_overflow(val2, add_val2)) {
313                                        val2 += add_val2;
314                                } else {
315                                        var1 = -1;
316                                }
317                        } else if (var1 < 0 && var2 >= 0) {
318                                zend_long add_val1 = 0;
319                                if ((opline-1)->op1_type == IS_CONST) {
320                                        zval *zv = CRT_CONSTANT((opline-1)->op1);
321                                        if (Z_TYPE_P(zv) == IS_LONG) {
322                                                add_val1 = Z_LVAL_P(CRT_CONSTANT((opline-1)->op1));
323                                        } else if (Z_TYPE_P(zv) == IS_FALSE) {
324                                                add_val1 = 0;
325                                        } else if (Z_TYPE_P(zv) == IS_TRUE) {
326                                                add_val1 = 1;
327                                        } else {
328                                                var2 = -1;
329                                        }
330                                } else {
331                                        var2 = -1;
332                                }
333                                if (!add_will_overflow(val1, add_val1)) {
334                                        val1 += add_val1;
335                                } else {
336                                        var2 = -1;
337                                }
338                        }
339
340                        if (var1 >= 0) {
341                                if ((opline-1)->opcode == ZEND_IS_EQUAL) {
342                                        if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var1))) {
343                                                pi_range_equals(pi, var2, val2);
344                                        }
345                                        if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var1))) {
346                                                pi_range_not_equals(pi, var2, val2);
347                                        }
348                                } else if ((opline-1)->opcode == ZEND_IS_NOT_EQUAL) {
349                                        if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var1))) {
350                                                pi_range_equals(pi, var2, val2);
351                                        }
352                                        if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var1))) {
353                                                pi_range_not_equals(pi, var2, val2);
354                                        }
355                                } else if ((opline-1)->opcode == ZEND_IS_SMALLER) {
356                                        if (val2 > ZEND_LONG_MIN) {
357                                                if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var1))) {
358                                                        pi_range_max(pi, var2, val2-1);
359                                                }
360                                        }
361                                        if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var1))) {
362                                                pi_range_min(pi, var2, val2);
363                                        }
364                                } else if ((opline-1)->opcode == ZEND_IS_SMALLER_OR_EQUAL) {
365                                        if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var1))) {
366                                                pi_range_max(pi, var2, val2);
367                                        }
368                                        if (val2 < ZEND_LONG_MAX) {
369                                                if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var1))) {
370                                                        pi_range_min(pi, var2, val2+1);
371                                                }
372                                        }
373                                }
374                        }
375                        if (var2 >= 0) {
376                                if((opline-1)->opcode == ZEND_IS_EQUAL) {
377                                        if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var2))) {
378                                                pi_range_equals(pi, var1, val1);
379                                        }
380                                        if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var2))) {
381                                                pi_range_not_equals(pi, var1, val1);
382                                        }
383                                } else if ((opline-1)->opcode == ZEND_IS_NOT_EQUAL) {
384                                        if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var2))) {
385                                                pi_range_equals(pi, var1, val1);
386                                        }
387                                        if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var2))) {
388                                                pi_range_not_equals(pi, var1, val1);
389                                        }
390                                } else if ((opline-1)->opcode == ZEND_IS_SMALLER) {
391                                        if (val1 < ZEND_LONG_MAX) {
392                                                if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var2))) {
393                                                        pi_range_min(pi, var1, val1+1);
394                                                }
395                                        }
396                                        if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var2))) {
397                                                pi_range_max(pi, var1, val1);
398                                        }
399                                } else if ((opline-1)->opcode == ZEND_IS_SMALLER_OR_EQUAL) {
400                                        if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var2))) {
401                                                pi_range_min(pi, var1, val1);
402                                        }
403                                        if (val1 > ZEND_LONG_MIN) {
404                                                if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var2))) {
405                                                        pi_range_max(pi, var1, val1-1);
406                                                }
407                                        }
408                                }
409                        }
410                } else if (opline->op1_type == IS_TMP_VAR &&
411                           ((opline-1)->opcode == ZEND_POST_INC ||
412                            (opline-1)->opcode == ZEND_POST_DEC) &&
413                           opline->op1.var == (opline-1)->result.var &&
414                           (opline-1)->op1_type == IS_CV) {
415                        int var = EX_VAR_TO_NUM((opline-1)->op1.var);
416
417                        if ((opline-1)->opcode == ZEND_POST_DEC) {
418                                if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) {
419                                        pi_range_equals(pi, -1, -1);
420                                }
421                                if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) {
422                                        pi_range_not_equals(pi, -1, -1);
423                                }
424                        } else if ((opline-1)->opcode == ZEND_POST_INC) {
425                                if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) {
426                                        pi_range_equals(pi, -1, 1);
427                                }
428                                if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) {
429                                        pi_range_not_equals(pi, -1, 1);
430                                }
431                        }
432                } else if (opline->op1_type == IS_VAR &&
433                           ((opline-1)->opcode == ZEND_PRE_INC ||
434                            (opline-1)->opcode == ZEND_PRE_DEC) &&
435                           opline->op1.var == (opline-1)->result.var &&
436                           (opline-1)->op1_type == IS_CV) {
437                        int var = EX_VAR_TO_NUM((opline-1)->op1.var);
438
439                        if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) {
440                                pi_range_equals(pi, -1, 0);
441                        }
442                        /* speculative */
443                        if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) {
444                                pi_range_not_equals(pi, -1, 0);
445                        }
446                } else if (opline->op1_type == IS_TMP_VAR && (opline-1)->opcode == ZEND_TYPE_CHECK &&
447                                   opline->op1.var == (opline-1)->result.var && (opline-1)->op1_type == IS_CV) {
448                        int var = EX_VAR_TO_NUM((opline-1)->op1.var);
449                        uint32_t type = (opline-1)->extended_value;
450                        if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) {
451                                pi_type_mask(pi, mask_for_type_check(type));
452                        }
453                        if (type != IS_OBJECT && type != IS_RESOURCE) {
454                                /* is_object() and is_resource() may return false, even though the value is
455                                 * an object/resource. */
456                                if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) {
457                                        pi_not_type_mask(pi, mask_for_type_check(type));
458                                }
459                        }
460                } else if (opline->op1_type == IS_TMP_VAR &&
461                                   ((opline-1)->opcode == ZEND_IS_IDENTICAL
462                                        || (opline-1)->opcode == ZEND_IS_NOT_IDENTICAL) &&
463                                   opline->op1.var == (opline-1)->result.var) {
464                        int var;
465                        zval *val;
466                        uint32_t type_mask;
467                        if ((opline-1)->op1_type == IS_CV && (opline-1)->op2_type == IS_CONST) {
468                                var = EX_VAR_TO_NUM((opline-1)->op1.var);
469                                val = CRT_CONSTANT((opline-1)->op2);
470                        } else if ((opline-1)->op1_type == IS_CONST && (opline-1)->op2_type == IS_CV) {
471                                var = EX_VAR_TO_NUM((opline-1)->op2.var);
472                                val = CRT_CONSTANT((opline-1)->op1);
473                        } else {
474                                continue;
475                        }
476
477                        /* We're interested in === null/true/false comparisons here, because they eliminate
478                         * a type in the false-branch. Other === VAL comparisons are unlikely to be useful. */
479                        if (Z_TYPE_P(val) != IS_NULL && Z_TYPE_P(val) != IS_TRUE && Z_TYPE_P(val) != IS_FALSE) {
480                                continue;
481                        }
482
483                        type_mask = _const_op_type(val);
484                        if ((opline-1)->opcode == ZEND_IS_IDENTICAL) {
485                                if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) {
486                                        pi_type_mask(pi, type_mask);
487                                }
488                                if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) {
489                                        pi_not_type_mask(pi, type_mask);
490                                }
491                        } else {
492                                if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) {
493                                        pi_type_mask(pi, type_mask);
494                                }
495                                if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) {
496                                        pi_not_type_mask(pi, type_mask);
497                                }
498                        }
499                } else if (opline->op1_type == IS_TMP_VAR && (opline-1)->opcode == ZEND_INSTANCEOF &&
500                                   opline->op1.var == (opline-1)->result.var && (opline-1)->op1_type == IS_CV &&
501                                   (opline-1)->op2_type == IS_CONST) {
502                        int var = EX_VAR_TO_NUM((opline-1)->op1.var);
503                        zend_string *lcname = Z_STR_P(CRT_CONSTANT((opline-1)->op2) + 1);
504                        zend_class_entry *ce = script ? zend_hash_find_ptr(&script->class_table, lcname) : NULL;
505                        if (!ce) {
506                                ce = zend_hash_find_ptr(CG(class_table), lcname);
507                                if (!ce || ce->type != ZEND_INTERNAL_CLASS) {
508                                        continue;
509                                }
510                        }
511
512                        if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) {
513                                pi_type_mask(pi, MAY_BE_OBJECT);
514                                pi->constraint.type.ce = ce;
515                        }
516                }
517        }
518}
519/* }}} */
520
521static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa, int *var, int n) /* {{{ */
522{
523        zend_basic_block *blocks = ssa->cfg.blocks;
524        zend_ssa_block *ssa_blocks = ssa->blocks;
525        zend_ssa_op *ssa_ops = ssa->ops;
526        int ssa_vars_count = ssa->vars_count;
527        int i, j;
528        zend_op *opline, *end;
529        int *tmp = NULL;
530        ALLOCA_FLAG(use_heap);
531
532        // FIXME: Can we optimize this copying out in some cases?
533        if (blocks[n].next_child >= 0) {
534                tmp = do_alloca(sizeof(int) * (op_array->last_var + op_array->T), use_heap);
535                memcpy(tmp, var, sizeof(int) * (op_array->last_var + op_array->T));
536                var = tmp;
537        }
538
539        if (ssa_blocks[n].phis) {
540                zend_ssa_phi *phi = ssa_blocks[n].phis;
541                do {
542                        if (phi->ssa_var < 0) {
543                                phi->ssa_var = ssa_vars_count;
544                                var[phi->var] = ssa_vars_count;
545                                ssa_vars_count++;
546                        } else {
547                                var[phi->var] = phi->ssa_var;
548                        }
549                        phi = phi->next;
550                } while (phi);
551        }
552
553        opline = op_array->opcodes + blocks[n].start;
554        end = opline + blocks[n].len;
555        for (; opline < end; opline++) {
556                uint32_t k = opline - op_array->opcodes;
557                if (opline->opcode != ZEND_OP_DATA) {
558                        zend_op *next = opline + 1;
559                        if (next < end && next->opcode == ZEND_OP_DATA) {
560                                if (next->op1_type == IS_CV) {
561                                        ssa_ops[k + 1].op1_use = var[EX_VAR_TO_NUM(next->op1.var)];
562                                        //USE_SSA_VAR(next->op1.var);
563                                } else if (next->op1_type & (IS_VAR|IS_TMP_VAR)) {
564                                        ssa_ops[k + 1].op1_use = var[EX_VAR_TO_NUM(next->op1.var)];
565                                        //USE_SSA_VAR(op_array->last_var + next->op1.var);
566                                }
567                                if (next->op2_type == IS_CV) {
568                                        ssa_ops[k + 1].op2_use = var[EX_VAR_TO_NUM(next->op2.var)];
569                                        //USE_SSA_VAR(next->op2.var);
570                                } else if (next->op2_type & (IS_VAR|IS_TMP_VAR)) {
571                                        ssa_ops[k + 1].op2_use = var[EX_VAR_TO_NUM(next->op2.var)];
572                                        //USE_SSA_VAR(op_array->last_var + next->op2.var);
573                                }
574                        }
575                        if (opline->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
576                                ssa_ops[k].op1_use = var[EX_VAR_TO_NUM(opline->op1.var)];
577                                //USE_SSA_VAR(op_array->last_var + opline->op1.var)
578                        }
579                        if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) {
580                                if (opline->op2_type == IS_CV) {
581                                        ssa_ops[k].op2_use = var[EX_VAR_TO_NUM(opline->op2.var)];
582                                }
583                                ssa_ops[k].op2_def = ssa_vars_count;
584                                var[EX_VAR_TO_NUM(opline->op2.var)] = ssa_vars_count;
585                                ssa_vars_count++;
586                                //NEW_SSA_VAR(opline->op2.var)
587                        } else if (opline->op2_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
588                                ssa_ops[k].op2_use = var[EX_VAR_TO_NUM(opline->op2.var)];
589                                //USE_SSA_VAR(op_array->last_var + opline->op2.var)
590                        }
591                        switch (opline->opcode) {
592                                case ZEND_ASSIGN:
593                                        if ((build_flags & ZEND_SSA_RC_INFERENCE) && opline->op2_type == IS_CV) {
594                                                ssa_ops[k].op2_def = ssa_vars_count;
595                                                var[EX_VAR_TO_NUM(opline->op2.var)] = ssa_vars_count;
596                                                ssa_vars_count++;
597                                                //NEW_SSA_VAR(opline->op2.var)
598                                        }
599                                        if (opline->op1_type == IS_CV) {
600                                                ssa_ops[k].op1_def = ssa_vars_count;
601                                                var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
602                                                ssa_vars_count++;
603                                                //NEW_SSA_VAR(opline->op1.var)
604                                        }
605                                        break;
606                                case ZEND_ASSIGN_REF:
607//TODO: ???
608                                        if (opline->op2_type == IS_CV) {
609                                                ssa_ops[k].op2_def = ssa_vars_count;
610                                                var[EX_VAR_TO_NUM(opline->op2.var)] = ssa_vars_count;
611                                                ssa_vars_count++;
612                                                //NEW_SSA_VAR(opline->op2.var)
613                                        }
614                                        if (opline->op1_type == IS_CV) {
615                                                ssa_ops[k].op1_def = ssa_vars_count;
616                                                var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
617                                                ssa_vars_count++;
618                                                //NEW_SSA_VAR(opline->op1.var)
619                                        }
620                                        break;
621                                case ZEND_BIND_GLOBAL:
622                                case ZEND_BIND_STATIC:
623                                        if (opline->op1_type == IS_CV) {
624                                                ssa_ops[k].op1_def = ssa_vars_count;
625                                                var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
626                                                ssa_vars_count++;
627                                                //NEW_SSA_VAR(opline->op1.var)
628                                        }
629                                        break;
630                                case ZEND_ASSIGN_DIM:
631                                case ZEND_ASSIGN_OBJ:
632                                        if (opline->op1_type == IS_CV) {
633                                                ssa_ops[k].op1_def = ssa_vars_count;
634                                                var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
635                                                ssa_vars_count++;
636                                                //NEW_SSA_VAR(opline->op1.var)
637                                        }
638                                        if ((build_flags & ZEND_SSA_RC_INFERENCE) && next->op1_type == IS_CV) {
639                                                ssa_ops[k + 1].op1_def = ssa_vars_count;
640                                                var[EX_VAR_TO_NUM(next->op1.var)] = ssa_vars_count;
641                                                ssa_vars_count++;
642                                                //NEW_SSA_VAR(next->op1.var)
643                                        }
644                                        break;
645                                case ZEND_ADD_ARRAY_ELEMENT:
646                                        ssa_ops[k].result_use = var[EX_VAR_TO_NUM(opline->result.var)];
647                                case ZEND_INIT_ARRAY:
648                                        if (((build_flags & ZEND_SSA_RC_INFERENCE)
649                                                                || (opline->extended_value & ZEND_ARRAY_ELEMENT_REF))
650                                                        && opline->op1_type == IS_CV) {
651                                                ssa_ops[k].op1_def = ssa_vars_count;
652                                                var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
653                                                ssa_vars_count++;
654                                                //NEW_SSA_VAR(opline+->op1.var)
655                                        }
656                                        break;
657                                case ZEND_SEND_VAR:
658                                case ZEND_CAST:
659                                case ZEND_QM_ASSIGN:
660                                case ZEND_JMP_SET:
661                                case ZEND_COALESCE:
662                                        if ((build_flags & ZEND_SSA_RC_INFERENCE) && opline->op1_type == IS_CV) {
663                                                ssa_ops[k].op1_def = ssa_vars_count;
664                                                var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
665                                                ssa_vars_count++;
666                                                //NEW_SSA_VAR(opline->op1.var)
667                                        }
668                                        break;
669                                case ZEND_SEND_VAR_NO_REF:
670                                case ZEND_SEND_VAR_NO_REF_EX:
671                                case ZEND_SEND_VAR_EX:
672                                case ZEND_SEND_REF:
673                                case ZEND_SEND_UNPACK:
674                                case ZEND_FE_RESET_RW:
675//TODO: ???
676                                        if (opline->op1_type == IS_CV) {
677                                                ssa_ops[k].op1_def = ssa_vars_count;
678                                                var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
679                                                ssa_vars_count++;
680                                                //NEW_SSA_VAR(opline->op1.var)
681                                        }
682                                        break;
683                                case ZEND_FE_RESET_R:
684                                        if ((build_flags & ZEND_SSA_RC_INFERENCE) && opline->op1_type == IS_CV) {
685                                                ssa_ops[k].op1_def = ssa_vars_count;
686                                                var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
687                                                ssa_vars_count++;
688                                                //NEW_SSA_VAR(opline->op1.var)
689                                        }
690                                        break;
691                                case ZEND_ASSIGN_ADD:
692                                case ZEND_ASSIGN_SUB:
693                                case ZEND_ASSIGN_MUL:
694                                case ZEND_ASSIGN_DIV:
695                                case ZEND_ASSIGN_MOD:
696                                case ZEND_ASSIGN_SL:
697                                case ZEND_ASSIGN_SR:
698                                case ZEND_ASSIGN_CONCAT:
699                                case ZEND_ASSIGN_BW_OR:
700                                case ZEND_ASSIGN_BW_AND:
701                                case ZEND_ASSIGN_BW_XOR:
702                                case ZEND_ASSIGN_POW:
703                                case ZEND_PRE_INC:
704                                case ZEND_PRE_DEC:
705                                case ZEND_POST_INC:
706                                case ZEND_POST_DEC:
707                                        if (opline->op1_type == IS_CV) {
708                                                ssa_ops[k].op1_def = ssa_vars_count;
709                                                var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
710                                                ssa_vars_count++;
711                                                //NEW_SSA_VAR(opline->op1.var)
712                                        }
713                                        break;
714                                case ZEND_UNSET_VAR:
715                                        if (opline->extended_value & ZEND_QUICK_SET) {
716                                                ssa_ops[k].op1_def = ssa_vars_count;
717                                                var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
718                                                ssa_vars_count++;
719                                        }
720                                        break;
721                                case ZEND_UNSET_DIM:
722                                case ZEND_UNSET_OBJ:
723                                case ZEND_FETCH_DIM_W:
724                                case ZEND_FETCH_DIM_RW:
725                                case ZEND_FETCH_DIM_FUNC_ARG:
726                                case ZEND_FETCH_DIM_UNSET:
727                                case ZEND_FETCH_OBJ_W:
728                                case ZEND_FETCH_OBJ_RW:
729                                case ZEND_FETCH_OBJ_FUNC_ARG:
730                                case ZEND_FETCH_OBJ_UNSET:
731                                        if (opline->op1_type == IS_CV) {
732                                                ssa_ops[k].op1_def = ssa_vars_count;
733                                                var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
734                                                ssa_vars_count++;
735                                                //NEW_SSA_VAR(opline->op1.var)
736                                        }
737                                        break;
738                                case ZEND_BIND_LEXICAL:
739                                        if (opline->extended_value || (build_flags & ZEND_SSA_RC_INFERENCE)) {
740                                                ssa_ops[k].op2_def = ssa_vars_count;
741                                                var[EX_VAR_TO_NUM(opline->op2.var)] = ssa_vars_count;
742                                                ssa_vars_count++;
743                                        }
744                                        break;
745                                case ZEND_YIELD:
746                                        if (opline->op1_type == IS_CV
747                                                        && ((op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)
748                                                                || (build_flags & ZEND_SSA_RC_INFERENCE))) {
749                                                ssa_ops[k].op1_def = ssa_vars_count;
750                                                var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
751                                                ssa_vars_count++;
752                                        }
753                                        break;
754                                case ZEND_VERIFY_RETURN_TYPE:
755                                        if (opline->op1_type & (IS_TMP_VAR|IS_VAR|IS_CV)) {
756                                                ssa_ops[k].op1_def = ssa_vars_count;
757                                                var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
758                                                ssa_vars_count++;
759                                                //NEW_SSA_VAR(opline->op1.var)
760                                        }
761                                        break;
762                                default:
763                                        break;
764                        }
765                        if (opline->result_type == IS_CV) {
766                                ssa_ops[k].result_def = ssa_vars_count;
767                                var[EX_VAR_TO_NUM(opline->result.var)] = ssa_vars_count;
768                                ssa_vars_count++;
769                                //NEW_SSA_VAR(opline->result.var)
770                        } else if (opline->result_type & (IS_VAR|IS_TMP_VAR)) {
771                                ssa_ops[k].result_def = ssa_vars_count;
772                                var[EX_VAR_TO_NUM(opline->result.var)] = ssa_vars_count;
773                                ssa_vars_count++;
774                                //NEW_SSA_VAR(op_array->last_var + opline->result.var)
775                        }
776                }
777        }
778
779        for (i = 0; i < 2; i++) {
780                int succ = blocks[n].successors[i];
781                if (succ >= 0) {
782                        zend_ssa_phi *p;
783                        for (p = ssa_blocks[succ].phis; p; p = p->next) {
784                                if (p->pi == n) {
785                                        /* e-SSA Pi */
786                                        if (p->has_range_constraint) {
787                                                if (p->constraint.range.min_var >= 0) {
788                                                        p->constraint.range.min_ssa_var = var[p->constraint.range.min_var];
789                                                }
790                                                if (p->constraint.range.max_var >= 0) {
791                                                        p->constraint.range.max_ssa_var = var[p->constraint.range.max_var];
792                                                }
793                                        }
794                                        for (j = 0; j < blocks[succ].predecessors_count; j++) {
795                                                p->sources[j] = var[p->var];
796                                        }
797                                        if (p->ssa_var < 0) {
798                                                p->ssa_var = ssa_vars_count;
799                                                ssa_vars_count++;
800                                        }
801                                } else if (p->pi < 0) {
802                                        /* Normal Phi */
803                                        for (j = 0; j < blocks[succ].predecessors_count; j++)
804                                                if (ssa->cfg.predecessors[blocks[succ].predecessor_offset + j] == n) {
805                                                        break;
806                                                }
807                                        ZEND_ASSERT(j < blocks[succ].predecessors_count);
808                                        p->sources[j] = var[p->var];
809                                }
810                        }
811                        for (p = ssa_blocks[succ].phis; p && (p->pi >= 0); p = p->next) {
812                                if (p->pi == n) {
813                                        zend_ssa_phi *q = p->next;
814                                        while (q) {
815                                                if (q->pi < 0 && q->var == p->var) {
816                                                        for (j = 0; j < blocks[succ].predecessors_count; j++) {
817                                                                if (ssa->cfg.predecessors[blocks[succ].predecessor_offset + j] == n) {
818                                                                        break;
819                                                                }
820                                                        }
821                                                        ZEND_ASSERT(j < blocks[succ].predecessors_count);
822                                                        q->sources[j] = p->ssa_var;
823                                                }
824                                                q = q->next;
825                                        }
826                                }
827                        }
828                }
829        }
830
831        ssa->vars_count = ssa_vars_count;
832
833        j = blocks[n].children;
834        while (j >= 0) {
835                // FIXME: Tail call optimization?
836                if (zend_ssa_rename(op_array, build_flags, ssa, var, j) != SUCCESS)
837                        return FAILURE;
838                j = blocks[j].next_child;
839        }
840
841        if (tmp) {
842                free_alloca(tmp, use_heap);
843        }
844
845        return SUCCESS;
846}
847/* }}} */
848
849int zend_build_ssa(zend_arena **arena, const zend_script *script, const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa, uint32_t *func_flags) /* {{{ */
850{
851        zend_basic_block *blocks = ssa->cfg.blocks;
852        zend_ssa_block *ssa_blocks;
853        int blocks_count = ssa->cfg.blocks_count;
854        uint32_t set_size;
855        zend_bitset def, in, phi;
856        int *var = NULL;
857        int i, j, k, changed;
858        zend_dfg dfg;
859        ALLOCA_FLAG(dfg_use_heap)
860        ALLOCA_FLAG(var_use_heap)
861
862        if ((blocks_count * (op_array->last_var + op_array->T)) > 4 * 1024 * 1024) {
863            /* Don't buld SSA for very big functions */
864                return FAILURE;
865        }
866
867        ssa->rt_constants = (build_flags & ZEND_RT_CONSTANTS);
868        ssa_blocks = zend_arena_calloc(arena, blocks_count, sizeof(zend_ssa_block));
869        if (!ssa_blocks) {
870                return FAILURE;
871        }
872        ssa->blocks = ssa_blocks;
873
874        /* Compute Variable Liveness */
875        dfg.vars = op_array->last_var + op_array->T;
876        dfg.size = set_size = zend_bitset_len(dfg.vars);
877        dfg.tmp = do_alloca((set_size * sizeof(zend_ulong)) * (blocks_count * 4 + 1), dfg_use_heap);
878        memset(dfg.tmp, 0, (set_size * sizeof(zend_ulong)) * (blocks_count * 4 + 1));
879        dfg.def = dfg.tmp + set_size;
880        dfg.use = dfg.def + set_size * blocks_count;
881        dfg.in  = dfg.use + set_size * blocks_count;
882        dfg.out = dfg.in  + set_size * blocks_count;
883
884        if (zend_build_dfg(op_array, &ssa->cfg, &dfg, build_flags) != SUCCESS) {
885                free_alloca(dfg.tmp, dfg_use_heap);
886                return FAILURE;
887        }
888
889        if (build_flags & ZEND_SSA_DEBUG_LIVENESS) {
890                zend_dump_dfg(op_array, &ssa->cfg, &dfg);
891        }
892
893        def = dfg.def;
894        in  = dfg.in;
895
896        /* Reuse the "use" set, as we no longer need it */
897        phi = dfg.use;
898        zend_bitset_clear(phi, set_size * blocks_count);
899
900        /* Place e-SSA pis. This will add additional "def" points, so it must
901         * happen before def propagation. */
902        place_essa_pis(arena, script, op_array, build_flags, ssa, &dfg);
903
904        /* SSA construction, Step 1: Propagate "def" sets in merge points */
905        do {
906                changed = 0;
907                for (j = 0; j < blocks_count; j++) {
908                        zend_bitset def_j = def + j * set_size, phi_j = phi + j * set_size;
909                        if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) {
910                                continue;
911                        }
912                        if (blocks[j].predecessors_count > 1) {
913                                if (blocks[j].flags & ZEND_BB_IRREDUCIBLE_LOOP) {
914                                        /* Prevent any values from flowing into irreducible loops by
915                                           replacing all incoming values with explicit phis.  The
916                                           register allocator depends on this property.  */
917                                        zend_bitset_union(phi_j, in + (j * set_size), set_size);
918                                } else {
919                                        for (k = 0; k < blocks[j].predecessors_count; k++) {
920                                                i = ssa->cfg.predecessors[blocks[j].predecessor_offset + k];
921                                                while (i != -1 && i != blocks[j].idom) {
922                                                        zend_bitset_union_with_intersection(
923                                                                phi_j, phi_j, def + (i * set_size), in + (j * set_size), set_size);
924                                                        i = blocks[i].idom;
925                                                }
926                                        }
927                                }
928                                if (!zend_bitset_subset(phi_j, def_j, set_size)) {
929                                        zend_bitset_union(def_j, phi_j, set_size);
930                                        changed = 1;
931                                }
932                        }
933                }
934        } while (changed);
935
936        /* SSA construction, Step 2: Phi placement based on Dominance Frontiers */
937        var = do_alloca(sizeof(int) * (op_array->last_var + op_array->T), var_use_heap);
938        if (!var) {
939                free_alloca(dfg.tmp, dfg_use_heap);
940                return FAILURE;
941        }
942
943        for (j = 0; j < blocks_count; j++) {
944                if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) {
945                        continue;
946                }
947                if (!zend_bitset_empty(phi + j * set_size, set_size)) {
948                        ZEND_BITSET_REVERSE_FOREACH(phi + j * set_size, set_size, i) {
949                                zend_ssa_phi *phi = zend_arena_calloc(arena, 1,
950                                        ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)) +
951                                        ZEND_MM_ALIGNED_SIZE(sizeof(int) * blocks[j].predecessors_count) +
952                                        sizeof(void*) * blocks[j].predecessors_count);
953
954                                phi->sources = (int*)(((char*)phi) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)));
955                                memset(phi->sources, 0xff, sizeof(int) * blocks[j].predecessors_count);
956                                phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + ZEND_MM_ALIGNED_SIZE(sizeof(int) * ssa->cfg.blocks[j].predecessors_count));
957
958                                phi->pi = -1;
959                                phi->var = i;
960                                phi->ssa_var = -1;
961
962                                /* Place phis after pis */
963                                {
964                                        zend_ssa_phi **pp = &ssa_blocks[j].phis;
965                                        while (*pp) {
966                                                if ((*pp)->pi < 0) {
967                                                        break;
968                                                }
969                                                pp = &(*pp)->next;
970                                        }
971                                        phi->next = *pp;
972                                        *pp = phi;
973                                }
974                        } ZEND_BITSET_FOREACH_END();
975                }
976        }
977
978        if (build_flags & ZEND_SSA_DEBUG_PHI_PLACEMENT) {
979                zend_dump_phi_placement(op_array, ssa);
980        }
981
982        /* SSA construction, Step 3: Renaming */
983        ssa->ops = zend_arena_calloc(arena, op_array->last, sizeof(zend_ssa_op));
984        memset(ssa->ops, 0xff, op_array->last * sizeof(zend_ssa_op));
985        memset(var + op_array->last_var, 0xff, op_array->T * sizeof(int));
986        /* Create uninitialized SSA variables for each CV */
987        for (j = 0; j < op_array->last_var; j++) {
988                var[j] = j;
989        }
990        ssa->vars_count = op_array->last_var;
991        if (zend_ssa_rename(op_array, build_flags, ssa, var, 0) != SUCCESS) {
992                free_alloca(var, var_use_heap);
993                free_alloca(dfg.tmp, dfg_use_heap);
994                return FAILURE;
995        }
996
997        free_alloca(var, var_use_heap);
998        free_alloca(dfg.tmp, dfg_use_heap);
999
1000        return SUCCESS;
1001}
1002/* }}} */
1003
1004int zend_ssa_compute_use_def_chains(zend_arena **arena, const zend_op_array *op_array, zend_ssa *ssa) /* {{{ */
1005{
1006        zend_ssa_var *ssa_vars;
1007        int i;
1008
1009        if (!ssa->vars) {
1010                ssa->vars = zend_arena_calloc(arena, ssa->vars_count, sizeof(zend_ssa_var));
1011        }
1012        ssa_vars = ssa->vars;
1013
1014        for (i = 0; i < op_array->last_var; i++) {
1015                ssa_vars[i].var = i;
1016                ssa_vars[i].scc = -1;
1017                ssa_vars[i].definition = -1;
1018                ssa_vars[i].use_chain = -1;
1019        }
1020        for (i = op_array->last_var; i < ssa->vars_count; i++) {
1021                ssa_vars[i].var = -1;
1022                ssa_vars[i].scc = -1;
1023                ssa_vars[i].definition = -1;
1024                ssa_vars[i].use_chain = -1;
1025        }
1026
1027        for (i = op_array->last - 1; i >= 0; i--) {
1028                zend_ssa_op *op = ssa->ops + i;
1029
1030                if (op->op1_use >= 0) {
1031                        op->op1_use_chain = ssa_vars[op->op1_use].use_chain;
1032                        ssa_vars[op->op1_use].use_chain = i;
1033                }
1034                if (op->op2_use >= 0 && op->op2_use != op->op1_use) {
1035                        op->op2_use_chain = ssa_vars[op->op2_use].use_chain;
1036                        ssa_vars[op->op2_use].use_chain = i;
1037                }
1038                if (op->result_use >= 0) {
1039                        op->res_use_chain = ssa_vars[op->result_use].use_chain;
1040                        ssa_vars[op->result_use].use_chain = i;
1041                }
1042                if (op->op1_def >= 0) {
1043                        ssa_vars[op->op1_def].var = EX_VAR_TO_NUM(op_array->opcodes[i].op1.var);
1044                        ssa_vars[op->op1_def].definition = i;
1045                }
1046                if (op->op2_def >= 0) {
1047                        ssa_vars[op->op2_def].var = EX_VAR_TO_NUM(op_array->opcodes[i].op2.var);
1048                        ssa_vars[op->op2_def].definition = i;
1049                }
1050                if (op->result_def >= 0) {
1051                        ssa_vars[op->result_def].var = EX_VAR_TO_NUM(op_array->opcodes[i].result.var);
1052                        ssa_vars[op->result_def].definition = i;
1053                }
1054        }
1055
1056        for (i = 0; i < ssa->cfg.blocks_count; i++) {
1057                zend_ssa_phi *phi = ssa->blocks[i].phis;
1058                while (phi) {
1059                        phi->block = i;
1060                        ssa_vars[phi->ssa_var].var = phi->var;
1061                        ssa_vars[phi->ssa_var].definition_phi = phi;
1062                        if (phi->pi >= 0) {
1063                                if (phi->sources[0] >= 0) {
1064                                        zend_ssa_phi *p = ssa_vars[phi->sources[0]].phi_use_chain;
1065                                        while (p && p != phi) {
1066                                                p = zend_ssa_next_use_phi(ssa, phi->sources[0], p);
1067                                        }
1068                                        if (!p) {
1069                                                phi->use_chains[0] = ssa_vars[phi->sources[0]].phi_use_chain;
1070                                                ssa_vars[phi->sources[0]].phi_use_chain = phi;
1071                                        }
1072                                }
1073                                if (phi->has_range_constraint) {
1074                                        /* min and max variables can't be used together */
1075                                        zend_ssa_range_constraint *constraint = &phi->constraint.range;
1076                                        if (constraint->min_ssa_var >= 0) {
1077                                                phi->sym_use_chain = ssa_vars[constraint->min_ssa_var].sym_use_chain;
1078                                                ssa_vars[constraint->min_ssa_var].sym_use_chain = phi;
1079                                        } else if (constraint->max_ssa_var >= 0) {
1080                                                phi->sym_use_chain = ssa_vars[constraint->max_ssa_var].sym_use_chain;
1081                                                ssa_vars[constraint->max_ssa_var].sym_use_chain = phi;
1082                                        }
1083                                }
1084                        } else {
1085                                int j;
1086
1087                                for (j = 0; j < ssa->cfg.blocks[i].predecessors_count; j++) {
1088                                        if (phi->sources[j] >= 0) {
1089                                                zend_ssa_phi *p = ssa_vars[phi->sources[j]].phi_use_chain;
1090                                                while (p && p != phi) {
1091                                                        p = zend_ssa_next_use_phi(ssa, phi->sources[j], p);
1092                                                }
1093                                                if (!p) {
1094                                                        phi->use_chains[j] = ssa_vars[phi->sources[j]].phi_use_chain;
1095                                                        ssa_vars[phi->sources[j]].phi_use_chain = phi;
1096                                                }
1097                                        }
1098                                }
1099                        }
1100                        phi = phi->next;
1101                }
1102        }
1103
1104        return SUCCESS;
1105}
1106/* }}} */
1107
1108int zend_ssa_unlink_use_chain(zend_ssa *ssa, int op, int var) /* {{{ */
1109{
1110        if (ssa->vars[var].use_chain == op) {
1111                ssa->vars[var].use_chain = zend_ssa_next_use(ssa->ops, var, op);
1112                return 1;
1113        } else {
1114                int use = ssa->vars[var].use_chain;
1115
1116                while (use >= 0) {
1117                        if (ssa->ops[use].result_use == var) {
1118                                if (ssa->ops[use].res_use_chain == op) {
1119                                        ssa->ops[use].res_use_chain = zend_ssa_next_use(ssa->ops, var, op);
1120                                        return 1;
1121                                } else {
1122                                        use = ssa->ops[use].res_use_chain;
1123                                }
1124                        } else if (ssa->ops[use].op1_use == var) {
1125                                if (ssa->ops[use].op1_use_chain == op) {
1126                                        ssa->ops[use].op1_use_chain = zend_ssa_next_use(ssa->ops, var, op);
1127                                        return 1;
1128                                } else {
1129                                        use = ssa->ops[use].op1_use_chain;
1130                                }
1131                        } else if (ssa->ops[use].op2_use == var) {
1132                                if (ssa->ops[use].op2_use_chain == op) {
1133                                        ssa->ops[use].op2_use_chain = zend_ssa_next_use(ssa->ops, var, op);
1134                                        return 1;
1135                                } else {
1136                                        use = ssa->ops[use].op2_use_chain;
1137                                }
1138                        } else {
1139                                break;
1140                        }
1141                }
1142                /* something wrong */
1143                ZEND_ASSERT(0);
1144                return 0;
1145        }
1146}
1147/* }}} */
1148
1149/*
1150 * Local variables:
1151 * tab-width: 4
1152 * c-basic-offset: 4
1153 * indent-tabs-mode: t
1154 * End:
1155 */
Note: See TracBrowser for help on using the repository browser.