summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2020-11-30 11:09:28 +0100
committerNikita Popov <nikita.ppv@gmail.com>2020-11-30 11:18:21 +0100
commitfdb05b92bfb62906771fd41f3fcdbc184d89e3fe (patch)
tree09acc32f460b4ec94db80fef06c1f20edbcc5a0e
parente77ac88a441ac2cea9099fd97a0c5fb914df720e (diff)
downloadphp-git-fdb05b92bfb62906771fd41f3fcdbc184d89e3fe.tar.gz
Only replace IN_ARRAY result type for JMPZ/JMPNZ
Replacing the result type in the general case is dangerous, because not all opcodes support both VAR and TMP. One common case is the in_array() result being passed to SEND_VAR, which would have to be changed to SEND_VAL. Rather than complicating this logic, reduce the scope to only doing the type replacement for JMPZ and JMPNZ. The only reason we're doing this in the first place is to enable the smart branch optimization, so we can limit it to the relevant opcodes. Replacing the result type may be marginally useful in other cases as well (as it may avoid reference checks), but not worth the bother.
-rw-r--r--ext/opcache/Optimizer/dfa_pass.c20
-rw-r--r--ext/opcache/tests/opt/sccp_in_array.phpt14
2 files changed, 24 insertions, 10 deletions
diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c
index 765b023f07..92a7470b9e 100644
--- a/ext/opcache/Optimizer/dfa_pass.c
+++ b/ext/opcache/Optimizer/dfa_pass.c
@@ -474,16 +474,16 @@ int zend_dfa_optimize_calls(zend_op_array *op_array, zend_ssa *ssa)
int var = ssa_op->result_def;
int use = ssa->vars[var].use_chain;
- if (ssa->vars[var].phi_use_chain == NULL) {
- if (ssa->ops[use].op1_use == var
- && ssa->ops[use].op1_use_chain == -1) {
- call_info->caller_call_opline->result_type = IS_TMP_VAR;
- op_array->opcodes[use].op1_type = IS_TMP_VAR;
- } else if (ssa->ops[use].op2_use == var
- && ssa->ops[use].op2_use_chain == -1) {
- call_info->caller_call_opline->result_type = IS_TMP_VAR;
- op_array->opcodes[use].op2_type = IS_TMP_VAR;
- }
+ /* If the result is used only in a JMPZ/JMPNZ, replace result type with
+ * IS_TMP_VAR, which will enable use of smart branches. Don't do this
+ * in other cases, as not all opcodes support both VAR and TMP. */
+ if (ssa->vars[var].phi_use_chain == NULL
+ && ssa->ops[use].op1_use == var
+ && ssa->ops[use].op1_use_chain == -1
+ && (op_array->opcodes[use].opcode == ZEND_JMPZ
+ || op_array->opcodes[use].opcode == ZEND_JMPNZ)) {
+ call_info->caller_call_opline->result_type = IS_TMP_VAR;
+ op_array->opcodes[use].op1_type = IS_TMP_VAR;
}
}
}
diff --git a/ext/opcache/tests/opt/sccp_in_array.phpt b/ext/opcache/tests/opt/sccp_in_array.phpt
new file mode 100644
index 0000000000..e7716b8ad8
--- /dev/null
+++ b/ext/opcache/tests/opt/sccp_in_array.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Don't replace IN_ARRAY result type if the using opcode doesn't support it
+--FILE--
+<?php
+
+function test($v) {
+ $ary = ['x', 'y'];
+ var_dump(in_array($v, $ary));
+}
+test('x');
+
+?>
+--EXPECT--
+bool(true)