]> granicus.if.org Git - php/commitdiff
Optimize out no-op `yield from` statements
authorTyson Andre <tysonandre775@hotmail.com>
Sun, 7 Jun 2020 17:17:40 +0000 (13:17 -0400)
committerTyson Andre <tysonandre775@hotmail.com>
Mon, 8 Jun 2020 13:17:13 +0000 (09:17 -0400)
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

ext/opcache/Optimizer/sccp.c
ext/opcache/tests/opt/sccp_032.phpt [new file with mode: 0644]

index b2d6dcf9e74d0a1ffcb7bd8275218b24d1accb19..1bec01c5e20c7b10aeadfc612a45f4905a2a8566 100644 (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) {
diff --git a/ext/opcache/tests/opt/sccp_032.phpt b/ext/opcache/tests/opt/sccp_032.phpt
new file mode 100644 (file)
index 0000000..e7d9e48
--- /dev/null
@@ -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