summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2020-12-15 14:30:58 +0300
committerDmitry Stogov <dmitry@zend.com>2020-12-15 14:30:58 +0300
commitde78786566e6094cd6517d99a57ad5b97f95a18b (patch)
treedaf9be03a3bfd9d55605614cffe05061c49855df
parentc2fbab392c5b25aeb2daf243f4107557416942fb (diff)
downloadphp-git-de78786566e6094cd6517d99a57ad5b97f95a18b.tar.gz
Optimize out result value of ASSIGN, ASSIGN_OP and INC/DEC opcodes, if possible.
-rw-r--r--ext/opcache/Optimizer/dfa_pass.c110
1 files changed, 109 insertions, 1 deletions
diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c
index 92a7470b9e..0ac6c563d0 100644
--- a/ext/opcache/Optimizer/dfa_pass.c
+++ b/ext/opcache/Optimizer/dfa_pass.c
@@ -985,6 +985,77 @@ optimize_nop:
return removed_ops;
}
+static int zend_dfa_try_to_replace_result(zend_op_array *op_array, zend_ssa *ssa, int def, int cv_var)
+{
+ int result_var = ssa->ops[def].result_def;
+ int cv = EX_NUM_TO_VAR(ssa->vars[cv_var].var);
+
+ if (result_var >= 0
+ && !(ssa->var_info[cv_var].type & MAY_BE_REF)
+ && ssa->vars[cv_var].alias == NO_ALIAS
+ && ssa->vars[result_var].phi_use_chain == NULL
+ && ssa->vars[result_var].sym_use_chain == NULL) {
+ int use = ssa->vars[result_var].use_chain;
+
+ if (use >= 0
+ && zend_ssa_next_use(ssa->ops, result_var, use) < 0
+ && op_array->opcodes[use].opcode != ZEND_FREE
+ && op_array->opcodes[use].opcode != ZEND_SEND_VAL
+ && op_array->opcodes[use].opcode != ZEND_SEND_VAL_EX
+ && op_array->opcodes[use].opcode != ZEND_VERIFY_RETURN_TYPE) {
+ if (use > def) {
+ int i = use;
+ const zend_op *opline = &op_array->opcodes[use];
+
+ while (i > def) {
+ if ((opline->op1_type == IS_CV && opline->op1.var == cv)
+ || (opline->op2_type == IS_CV && opline->op2.var == cv)
+ || (opline->result_type == IS_CV && opline->result.var == cv)) {
+ return 0;
+ }
+ opline--;
+ i--;
+ }
+
+ /* Update opcodes and reconstruct SSA */
+ ssa->vars[result_var].definition = -1;
+ ssa->vars[result_var].use_chain = -1;
+ ssa->ops[def].result_def = -1;
+
+ op_array->opcodes[def].result_type = IS_UNUSED;
+ op_array->opcodes[def].result.var = 0;
+
+ if (ssa->ops[use].op1_use == result_var) {
+ ssa->ops[use].op1_use = cv_var;
+ ssa->ops[use].op1_use_chain = ssa->vars[cv_var].use_chain;
+ ssa->vars[cv_var].use_chain = use;
+
+ op_array->opcodes[use].op1_type = IS_CV;
+ op_array->opcodes[use].op1.var = cv;
+ } else if (ssa->ops[use].op2_use == result_var) {
+ ssa->ops[use].op2_use = cv_var;
+ ssa->ops[use].op2_use_chain = ssa->vars[cv_var].use_chain;
+ ssa->vars[cv_var].use_chain = use;
+
+ op_array->opcodes[use].op2_type = IS_CV;
+ op_array->opcodes[use].op2.var = cv;
+ } else if (ssa->ops[use].result_use == result_var) {
+ ssa->ops[use].result_use = cv_var;
+ ssa->ops[use].res_use_chain = ssa->vars[cv_var].use_chain;
+ ssa->vars[cv_var].use_chain = use;
+
+ op_array->opcodes[use].result_type = IS_CV;
+ op_array->opcodes[use].result.var = cv;
+ }
+
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, zend_ssa *ssa, zend_call_info **call_map)
{
if (ctx->debug_level & ZEND_DUMP_BEFORE_DFA_PASS) {
@@ -1303,6 +1374,44 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
continue;
}
+ if (ssa->ops[op_1].op1_def == v
+ && RETURN_VALUE_USED(opline)) {
+ if (opline->opcode == ZEND_ASSIGN
+ || opline->opcode == ZEND_ASSIGN_OP
+ || opline->opcode == ZEND_PRE_INC
+ || opline->opcode == ZEND_PRE_DEC) {
+ zend_dfa_try_to_replace_result(op_array, ssa, op_1, v);
+ } else if (opline->opcode == ZEND_POST_INC) {
+ int result_var = ssa->ops[op_1].result_def;
+
+ if (result_var >= 0
+ && (ssa->var_info[result_var].type & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_DOUBLE))) == 0) {
+ int use = ssa->vars[result_var].use_chain;
+
+ if (op_array->opcodes[use].opcode == ZEND_IS_SMALLER
+ && ssa->ops[use].op1_use == result_var
+ && zend_dfa_try_to_replace_result(op_array, ssa, op_1, v)) {
+ opline->opcode = ZEND_PRE_INC;
+ op_array->opcodes[use].opcode = ZEND_IS_SMALLER_OR_EQUAL;
+ }
+ }
+ } else if (opline->opcode == ZEND_POST_DEC) {
+ int result_var = ssa->ops[op_1].result_def;
+
+ if (result_var >= 0
+ && (ssa->var_info[result_var].type & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_DOUBLE))) == 0) {
+ int use = ssa->vars[result_var].use_chain;
+
+ if (op_array->opcodes[use].opcode == ZEND_IS_SMALLER
+ && ssa->ops[use].op2_use == result_var
+ && zend_dfa_try_to_replace_result(op_array, ssa, op_1, v)) {
+ opline->opcode = ZEND_PRE_DEC;
+ op_array->opcodes[use].opcode = ZEND_IS_SMALLER_OR_EQUAL;
+ }
+ }
+ }
+ }
+
if (opline->opcode == ZEND_ASSIGN
&& ssa->ops[op_1].op1_def == v
&& !RETURN_VALUE_USED(opline)
@@ -1312,7 +1421,6 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
if (orig_var >= 0
&& !(ssa->var_info[orig_var].type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))
) {
-
int src_var = ssa->ops[op_1].op2_use;
if ((opline->op2_type & (IS_TMP_VAR|IS_VAR))