]> granicus.if.org Git - php/commitdiff
Improve SSA representation of FE_FETCH
authorNikita Popov <nikita.ppv@gmail.com>
Mon, 30 Dec 2019 13:42:19 +0000 (14:42 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 17 Jan 2020 08:41:27 +0000 (09:41 +0100)
The op2 of FE_FETCH is only written if the loop edge is taken.
Fix up the SSA form to use the pre-assignment value if the exit
edge is taken.

This allows us to properly infer the type of the loop variable,
without letting the pre-loop type leak in.

Closes GH-5040.

ext/opcache/Optimizer/zend_inference.c
ext/opcache/Optimizer/zend_ssa.c
ext/opcache/Optimizer/zend_ssa.h

index 1838fe387baedb0733508c0c7518ffba67a698eb..93e91a3872b46844c3a17f4be34ceacdbc3f394f 100644 (file)
@@ -3285,7 +3285,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
                        break;
                case ZEND_FE_FETCH_R:
                case ZEND_FE_FETCH_RW:
-                       tmp = t2;
+                       tmp = t2 & MAY_BE_REF;
                        if (t1 & MAY_BE_OBJECT) {
                                if (opline->opcode == ZEND_FE_FETCH_RW) {
                                        tmp |= MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
index 64680be7454241bee49f547d2c6442e53d619f83..b4d581f2471b035ba6923fd4ad486d870653fdc0 100644 (file)
@@ -772,6 +772,10 @@ add_op1_def:
                }
        }
 
+       zend_ssa_op *fe_fetch_ssa_op = blocks[n].len != 0
+                       && ((end-1)->opcode == ZEND_FE_FETCH_R || (end-1)->opcode == ZEND_FE_FETCH_RW)
+                       && (end-1)->op2_type == IS_CV
+               ? &ssa_ops[blocks[n].start + blocks[n].len - 1] : NULL;
        for (i = 0; i < blocks[n].successors_count; i++) {
                int succ = blocks[n].successors[i];
                zend_ssa_phi *p;
@@ -801,6 +805,10 @@ add_op1_def:
                                        }
                                ZEND_ASSERT(j < blocks[succ].predecessors_count);
                                p->sources[j] = var[p->var];
+                               if (fe_fetch_ssa_op && i == 0 && p->sources[j] == fe_fetch_ssa_op->op2_def) {
+                                       /* On the exit edge of an FE_FETCH, use the pre-modification value instead. */
+                                       p->sources[j] = fe_fetch_ssa_op->op2_use;
+                               }
                        }
                }
                for (p = ssa_blocks[succ].phis; p && (p->pi >= 0); p = p->next) {
index 799af21532b1b50b35a9382c9dd0d65503d979cc..5abe44c93d6eb1ca8e9310c68523e19e17bc6c3d 100644 (file)
@@ -215,10 +215,9 @@ static zend_always_inline zend_bool zend_ssa_is_no_val_use(const zend_op *opline
        if (opline->opcode == ZEND_ASSIGN || opline->opcode == ZEND_UNSET_CV) {
                return ssa_op->op1_use == var && ssa_op->op2_use != var;
        }
-       // TODO: Re-enable this after changing the SSA structure.
-       /*if (opline->opcode == ZEND_FE_FETCH_R) {
+       if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) {
                return ssa_op->op2_use == var && ssa_op->op1_use != var;
-       }*/
+       }
        if (ssa_op->result_use == var
                        && opline->opcode != ZEND_ADD_ARRAY_ELEMENT
                        && opline->opcode != ZEND_ADD_ARRAY_UNPACK) {