Skip to content

Commit

Permalink
Fix DCE of FREE of COALESCE
Browse files Browse the repository at this point in the history
When encountering the following SSA graph:

    BB1:
    #2.T1 [string] = COALESCE #1.CV0($str) [null, string] BB2

    BB2:
    #5.T1 [string] = QM_ASSIGN string("")

    BB3:
    #7.X1 [string] = Phi(#2.X1 [string], #5.X1 [string])
    FREE #7.T1 [string]

We would currently determine that #7, #5 are dead, and eliminate
the FREE and QM_ASSIGN. However, we cannot eliminate #2, as
COALESCE is also responsible for control flow.

Fix this my marking all non-CV phis as live to start with. This
can be relaxed to check the kind of the source instruction, but
I couldn't immediately come up with a case where it would be
useful.
  • Loading branch information
nikic committed Apr 8, 2021
1 parent 25f5a1b commit 0826a54
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 0 deletions.
10 changes: 10 additions & 0 deletions ext/opcache/Optimizer/dce.c
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,16 @@ int dce_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, zend_bool reor
ctx.phi_dead = alloca(sizeof(zend_ulong) * ctx.phi_worklist_len);
memset(ctx.phi_dead, 0xff, sizeof(zend_ulong) * ctx.phi_worklist_len);

/* Mark non-CV phis as live. Even if the result is unused, we generally cannot remove one
* of the producing instructions, as it combines producing the result with control flow.
* This can be made more precise if there are any cases where this is not the case. */
FOREACH_PHI(phi) {
if (phi->var >= op_array->last_var) {
zend_bitset_excl(ctx.phi_dead, phi->ssa_var);
add_phi_sources_to_worklists(&ctx, phi, 0);
}
} FOREACH_PHI_END();

/* Mark reacable instruction without side effects as dead */
int b = ssa->cfg.blocks_count;
while (b > 0) {
Expand Down
17 changes: 17 additions & 0 deletions ext/opcache/tests/opt/dce_009.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
Incorrect DCE of FREE of COALESCE
--FILE--
<?php

function test(?string $str) {
$str ?? $str = '';
return strlen($str);
}

$foo = 'foo';
$foo .= 'bar';
var_dump(test($foo));

?>
--EXPECT--
int(6)

0 comments on commit 0826a54

Please sign in to comment.