1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

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
This commit is contained in:
Tyson Andre
2020-06-07 13:17:40 -04:00
parent 3d4f79d678
commit 543684e796
2 changed files with 66 additions and 0 deletions

View File

@@ -1678,6 +1678,16 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o
}
SET_RESULT_BOT(result);
break;
case ZEND_YIELD_FROM:
// tmp = yield from [] -> tmp = null
SKIP_IF_TOP(op1);
if (Z_TYPE_P(op1) == IS_ARRAY && zend_hash_num_elements(Z_ARR_P(op1)) == 0) {
ZVAL_NULL(&zv);
SET_RESULT(result, &zv);
break;
}
SET_RESULT_BOT(result);
break;
case ZEND_COUNT:
SKIP_IF_TOP(op1);
if (Z_TYPE_P(op1) == IS_ARRAY) {

View File

@@ -0,0 +1,56 @@
--TEST--
SCCP 032: Yield from optimizations
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.optimization_level=-1
opcache.opt_debug_level=0x20000
opcache.preload=
--SKIPIF--
<?php require_once('skipif.inc'); ?>
--FILE--
<?php
function test(): Generator {
$result = yield from [];
$a = [];
yield from $a;
yield $result;
$a[] = 3;
yield from $a;
}
foreach (test() as $x) {
var_export($x);
echo "\n";
}
?>
--EXPECTF--
$_main:
; (lines=11, args=0, vars=1, tmps=2)
; (after optimizer)
; %ssccp_032.php:1-15
0000 INIT_FCALL 0 %d string("test")
0001 V2 = DO_UCALL
0002 V1 = FE_RESET_R V2 0009
0003 FE_FETCH_R V1 CV0($x) 0009
0004 INIT_FCALL 1 %d string("var_export")
0005 SEND_VAR CV0($x) 1
0006 DO_ICALL
0007 ECHO string("
")
0008 JMP 0003
0009 FE_FREE V1
0010 RETURN int(1)
LIVE RANGES:
1: 0003 - 0009 (loop)
test:
; (lines=5, args=0, vars=0, tmps=1)
; (after optimizer)
; %ssccp_032.php:2-9
0000 GENERATOR_CREATE
0001 YIELD null
0002 T0 = YIELD_FROM array(...)
0003 FREE T0
0004 GENERATOR_RETURN null
NULL
3