From 74daa98974509aacd18b8504af6d4ef5846d2b5e Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 16 Dec 2015 13:14:31 +0300 Subject: [PATCH] Added simple DFA optimisation pattern (just to prove the concept) --- ext/opcache/Optimizer/dfa_pass.c | 57 +++++++++++++++++++++++++++++++- ext/opcache/Optimizer/zend_ssa.c | 40 ++++++++++++++++++++++ ext/opcache/Optimizer/zend_ssa.h | 1 + 3 files changed, 97 insertions(+), 1 deletion(-) diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c index f4ec641c40..0e7a9329c7 100644 --- a/ext/opcache/Optimizer/dfa_pass.c +++ b/ext/opcache/Optimizer/dfa_pass.c @@ -128,7 +128,62 @@ void optimize_dfa(zend_op_array *op_array, zend_optimizer_ctx *ctx) zend_dump_op_array(op_array, ZEND_DUMP_SSA | ZEND_DUMP_HIDE_UNUSED_VARS, "before dfa pass", &ssa); } - //TODO: Add optimization??? + //TODO: Add optimization patterns ??? + if (ssa.var_info) { + int i; + // 1: #1.T = OP_Y | #3.CV = OP_Y + // 2: ASSIGN #2.CV [undef,null,bool] -> #3.cv, #1.T | NOP + for (i = 0; i < ssa.vars_count; i++) { + int op2 = ssa.vars[i].definition; + + if (op2 >= 0 + && op_array->opcodes[op2].opcode == ZEND_ASSIGN + && op_array->opcodes[op2].op1_type == IS_CV + && (op_array->opcodes[op2].op2_type & (IS_TMP_VAR|IS_VAR)) + && !RETURN_VALUE_USED(&op_array->opcodes[op2]) + ) { + + int var1 = ssa.ops[op2].op2_use; + int var2 = ssa.ops[op2].op1_use; + + if (var1 >= 0 + && var2 >= 0 + && !(ssa.var_info[var2].type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) + && !(ssa.var_info[var1].type & MAY_BE_REF) + && ssa.vars[var1].definition >= 0 + && ssa.ops[ssa.vars[var1].definition].result_def == var1 + && ssa.ops[ssa.vars[var1].definition].result_use < 0 + && ssa.vars[var1].use_chain == op2 + && ssa.ops[op2].op2_use_chain < 0 + && !ssa.vars[var1].phi_use_chain + && !ssa.vars[var1].sym_use_chain + ) { + int op1 = ssa.vars[var1].definition; + int var3 = i; + + if (zend_ssa_unlink_use_chain(&ssa, op2, var2)) { + /* Reconstruct SSA */ + ssa.vars[var3].definition = op1; + ssa.ops[op1].result_def = var3; + + ssa.vars[var1].definition = -1; + ssa.vars[var1].use_chain = -1; + + ssa.ops[op2].op1_use = -1; + ssa.ops[op2].op2_use = -1; + ssa.ops[op2].op1_def = -1; + ssa.ops[op2].op1_use_chain = -1; + + /* Update opcodes */ + op_array->opcodes[op1].result_type = op_array->opcodes[op2].op1_type; + op_array->opcodes[op1].result.var = op_array->opcodes[op2].op1.var; + MAKE_NOP(&op_array->opcodes[op2]); + } + } + } + } + } + if (ctx->debug_level & ZEND_DUMP_AFTER_DFA_PASS) { zend_dump_op_array(op_array, ZEND_DUMP_SSA | ZEND_DUMP_HIDE_UNUSED_VARS, "after dfa pass", &ssa); diff --git a/ext/opcache/Optimizer/zend_ssa.c b/ext/opcache/Optimizer/zend_ssa.c index 24b2eb1ed5..86e7e2d6ff 100644 --- a/ext/opcache/Optimizer/zend_ssa.c +++ b/ext/opcache/Optimizer/zend_ssa.c @@ -994,6 +994,46 @@ int zend_ssa_compute_use_def_chains(zend_arena **arena, const zend_op_array *op_ } /* }}} */ +int zend_ssa_unlink_use_chain(zend_ssa *ssa, int op, int var) +{ + if (ssa->vars[var].use_chain == op) { + ssa->vars[var].use_chain = zend_ssa_next_use(ssa->ops, var, op); + return 1; + } else { + int use = ssa->vars[var].use_chain; + + while (use >= 0) { + if (ssa->ops[use].result_use == var) { + if (ssa->ops[use].res_use_chain == op) { + ssa->ops[use].res_use_chain = zend_ssa_next_use(ssa->ops, var, op); + return 1; + } else { + use = ssa->ops[use].res_use_chain; + } + } else if (ssa->ops[use].op1_use == var) { + if (ssa->ops[use].op1_use_chain == op) { + ssa->ops[use].op1_use_chain = zend_ssa_next_use(ssa->ops, var, op); + return 1; + } else { + use = ssa->ops[use].op1_use_chain; + } + } else if (ssa->ops[use].op2_use == var) { + if (ssa->ops[use].op2_use_chain == op) { + ssa->ops[use].op2_use_chain = zend_ssa_next_use(ssa->ops, var, op); + return 1; + } else { + use = ssa->ops[use].op2_use_chain; + } + } else { + break; + } + } + /* something wrong */ + ZEND_ASSERT(0); + return 0; + } +} + /* * Local variables: * tab-width: 4 diff --git a/ext/opcache/Optimizer/zend_ssa.h b/ext/opcache/Optimizer/zend_ssa.h index dc0c1b3aba..bc6c22e315 100644 --- a/ext/opcache/Optimizer/zend_ssa.h +++ b/ext/opcache/Optimizer/zend_ssa.h @@ -117,6 +117,7 @@ BEGIN_EXTERN_C() int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa, uint32_t *func_flags); int zend_ssa_compute_use_def_chains(zend_arena **arena, const zend_op_array *op_array, zend_ssa *ssa); +int zend_ssa_unlink_use_chain(zend_ssa *ssa, int op, int var); END_EXTERN_C() -- 2.50.1