Skip to content

Commit 4371902

Browse files
committed
Improve SSA representation of FE_FETCH
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.
1 parent bd19772 commit 4371902

File tree

3 files changed

+11
-4
lines changed

3 files changed

+11
-4
lines changed

ext/opcache/Optimizer/zend_inference.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3285,7 +3285,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
32853285
break;
32863286
case ZEND_FE_FETCH_R:
32873287
case ZEND_FE_FETCH_RW:
3288-
tmp = t2;
3288+
tmp = t2 & MAY_BE_REF;
32893289
if (t1 & MAY_BE_OBJECT) {
32903290
if (opline->opcode == ZEND_FE_FETCH_RW) {
32913291
tmp |= MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;

ext/opcache/Optimizer/zend_ssa.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,10 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags,
772772
}
773773
}
774774

775+
zend_ssa_op *fe_fetch_ssa_op = blocks[n].len != 0
776+
&& ((end-1)->opcode == ZEND_FE_FETCH_R || (end-1)->opcode == ZEND_FE_FETCH_RW)
777+
&& (end-1)->op2_type == IS_CV
778+
? &ssa_ops[blocks[n].start + blocks[n].len - 1] : NULL;
775779
for (i = 0; i < blocks[n].successors_count; i++) {
776780
int succ = blocks[n].successors[i];
777781
zend_ssa_phi *p;
@@ -801,6 +805,10 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags,
801805
}
802806
ZEND_ASSERT(j < blocks[succ].predecessors_count);
803807
p->sources[j] = var[p->var];
808+
if (fe_fetch_ssa_op && i == 0 && p->sources[j] == fe_fetch_ssa_op->op2_def) {
809+
/* On the exit edge of an FE_FETCH, use the pre-modification value instead. */
810+
p->sources[j] = fe_fetch_ssa_op->op2_use;
811+
}
804812
}
805813
}
806814
for (p = ssa_blocks[succ].phis; p && (p->pi >= 0); p = p->next) {

ext/opcache/Optimizer/zend_ssa.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,10 +215,9 @@ static zend_always_inline zend_bool zend_ssa_is_no_val_use(const zend_op *opline
215215
if (opline->opcode == ZEND_ASSIGN || opline->opcode == ZEND_UNSET_CV) {
216216
return ssa_op->op1_use == var && ssa_op->op2_use != var;
217217
}
218-
// TODO: Re-enable this after changing the SSA structure.
219-
/*if (opline->opcode == ZEND_FE_FETCH_R) {
218+
if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) {
220219
return ssa_op->op2_use == var && ssa_op->op1_use != var;
221-
}*/
220+
}
222221
if (ssa_op->result_use == var
223222
&& opline->opcode != ZEND_ADD_ARRAY_ELEMENT
224223
&& opline->opcode != ZEND_ADD_ARRAY_UNPACK) {

0 commit comments

Comments
 (0)