Skip to content

Commit 543684e

Browse files
committed
Optimize out no-op yield from statements
If the array is empty, then I'd expect that the generator is never left, and that can be converted to a no-op and the return value would always be `null`. Make `yield from [];` as efficient as `if (false) { yield null; }` when opcache's sccp pass is enabled. Closes GH-5679
1 parent 3d4f79d commit 543684e

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

ext/opcache/Optimizer/sccp.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1678,6 +1678,16 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o
16781678
}
16791679
SET_RESULT_BOT(result);
16801680
break;
1681+
case ZEND_YIELD_FROM:
1682+
// tmp = yield from [] -> tmp = null
1683+
SKIP_IF_TOP(op1);
1684+
if (Z_TYPE_P(op1) == IS_ARRAY && zend_hash_num_elements(Z_ARR_P(op1)) == 0) {
1685+
ZVAL_NULL(&zv);
1686+
SET_RESULT(result, &zv);
1687+
break;
1688+
}
1689+
SET_RESULT_BOT(result);
1690+
break;
16811691
case ZEND_COUNT:
16821692
SKIP_IF_TOP(op1);
16831693
if (Z_TYPE_P(op1) == IS_ARRAY) {

ext/opcache/tests/opt/sccp_032.phpt

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
--TEST--
2+
SCCP 032: Yield from optimizations
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.optimization_level=-1
7+
opcache.opt_debug_level=0x20000
8+
opcache.preload=
9+
--SKIPIF--
10+
<?php require_once('skipif.inc'); ?>
11+
--FILE--
12+
<?php
13+
function test(): Generator {
14+
$result = yield from [];
15+
$a = [];
16+
yield from $a;
17+
yield $result;
18+
$a[] = 3;
19+
yield from $a;
20+
}
21+
foreach (test() as $x) {
22+
var_export($x);
23+
echo "\n";
24+
}
25+
?>
26+
--EXPECTF--
27+
$_main:
28+
; (lines=11, args=0, vars=1, tmps=2)
29+
; (after optimizer)
30+
; %ssccp_032.php:1-15
31+
0000 INIT_FCALL 0 %d string("test")
32+
0001 V2 = DO_UCALL
33+
0002 V1 = FE_RESET_R V2 0009
34+
0003 FE_FETCH_R V1 CV0($x) 0009
35+
0004 INIT_FCALL 1 %d string("var_export")
36+
0005 SEND_VAR CV0($x) 1
37+
0006 DO_ICALL
38+
0007 ECHO string("
39+
")
40+
0008 JMP 0003
41+
0009 FE_FREE V1
42+
0010 RETURN int(1)
43+
LIVE RANGES:
44+
1: 0003 - 0009 (loop)
45+
46+
test:
47+
; (lines=5, args=0, vars=0, tmps=1)
48+
; (after optimizer)
49+
; %ssccp_032.php:2-9
50+
0000 GENERATOR_CREATE
51+
0001 YIELD null
52+
0002 T0 = YIELD_FROM array(...)
53+
0003 FREE T0
54+
0004 GENERATOR_RETURN null
55+
NULL
56+
3

0 commit comments

Comments
 (0)