]> granicus.if.org Git - php/commitdiff
Fix optimization of $i = $i++
authorNikita Popov <nikic@php.net>
Sun, 17 Jul 2016 20:47:49 +0000 (22:47 +0200)
committerNikita Popov <nikic@php.net>
Sun, 17 Jul 2016 20:47:49 +0000 (22:47 +0200)
ext/opcache/Optimizer/dfa_pass.c
ext/opcache/tests/ssa_bug_006.phpt [new file with mode: 0644]

index a64619bfe8b6540ee07baa4ca29d2b2262ed886b..a99d50fc4177b20c516d96a3dddce5eafc0337a4 100644 (file)
@@ -343,7 +343,8 @@ static inline zend_bool can_elide_return_type_check(
        return 1;
 }
 
-static zend_bool opline_supports_assign_contraction(zend_ssa *ssa, zend_op *opline, int src_var) {
+static zend_bool opline_supports_assign_contraction(
+               zend_ssa *ssa, zend_op *opline, int src_var, uint32_t cv_var) {
        if (opline->opcode == ZEND_NEW) {
                /* see Zend/tests/generators/aborted_yield_during_new.phpt */
                return 0;
@@ -358,6 +359,12 @@ static zend_bool opline_supports_assign_contraction(zend_ssa *ssa, zend_op *opli
                return !((type & MAY_BE_ANY) & ~simple);
        }
 
+       if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
+               /* POST_INC/DEC write the result variable before performing the inc/dec. For $i = $i++
+                * eliding the temporary variable would thus yield an incorrect result. */
+               return opline->op1_type != IS_CV || opline->op1.var != cv_var;
+       }
+
        return 1;
 }
 
@@ -476,7 +483,8 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
                                         && !ssa->vars[src_var].phi_use_chain
                                         && !ssa->vars[src_var].sym_use_chain
                                         && opline_supports_assign_contraction(
-                                                ssa, &op_array->opcodes[ssa->vars[src_var].definition], src_var)
+                                                ssa, &op_array->opcodes[ssa->vars[src_var].definition],
+                                                src_var, opline->op1.var)
                                        ) {
 
                                                int op_2 = ssa->vars[src_var].definition;
diff --git a/ext/opcache/tests/ssa_bug_006.phpt b/ext/opcache/tests/ssa_bug_006.phpt
new file mode 100644 (file)
index 0000000..624c1e0
--- /dev/null
@@ -0,0 +1,20 @@
+--TEST--
+Incorrect optimization of $i = $i++
+--FILE--
+<?php
+
+function test() {
+    $i = 1;
+    $i = $i++;
+    var_dump($i);
+
+    $i = 1;
+    $i = $i--;
+    var_dump($i);
+}
+test();
+
+?>
+--EXPECT--
+int(1)
+int(1)