]> granicus.if.org Git - php/commitdiff
Rearrange code to enable inner precedure inference
authorDmitry Stogov <dmitry@zend.com>
Thu, 24 Dec 2015 16:05:27 +0000 (19:05 +0300)
committerDmitry Stogov <dmitry@zend.com>
Thu, 24 Dec 2015 16:05:27 +0000 (19:05 +0300)
ext/opcache/Optimizer/dfa_pass.c
ext/opcache/Optimizer/zend_inference.c
ext/opcache/Optimizer/zend_optimizer.c
ext/opcache/Optimizer/zend_optimizer_internal.h

index a2a94af073a84fefec27b98a2fc55603af4e54ff..18f9e5c9a5878d898a4ed9254636148928a6417e 100644 (file)
 #include "zend_inference.h"
 #include "zend_dump.h"
 
-void optimize_dfa(zend_op_array *op_array, zend_optimizer_ctx *ctx)
+int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, zend_ssa *ssa, uint32_t *flags)
 {
-       void *checkpoint;
        uint32_t build_flags;
-       uint32_t flags = 0;
-       zend_ssa ssa;
 
     /* Build SSA */
-       memset(&ssa, 0, sizeof(ssa));
-       checkpoint = zend_arena_checkpoint(ctx->arena);
+       memset(ssa, 0, sizeof(zend_ssa));
 
-       if (zend_build_cfg(&ctx->arena, op_array, 0, &ssa.cfg, &flags) != SUCCESS) {
-               zend_arena_release(&ctx->arena, checkpoint);
-               return;
+       if (zend_build_cfg(&ctx->arena, op_array, 0, &ssa->cfg, flags) != SUCCESS) {
+               return FAILURE;
        }
 
-       if (flags & ZEND_FUNC_TOO_DYNAMIC) {
-               zend_arena_release(&ctx->arena, checkpoint);
-               return;
+       if (*flags & ZEND_FUNC_TOO_DYNAMIC) {
+               return FAILURE;
        }
 
-       if (zend_cfg_build_predecessors(&ctx->arena, &ssa.cfg) != SUCCESS) {
-               zend_arena_release(&ctx->arena, checkpoint);
-               return;
+       if (zend_cfg_build_predecessors(&ctx->arena, &ssa->cfg) != SUCCESS) {
+               return FAILURE;
        }
 
        if (ctx->debug_level & ZEND_DUMP_DFA_CFG) {
-               zend_dump_op_array(op_array, ZEND_DUMP_CFG | ZEND_DUMP_HIDE_UNUSED_VARS, "dfa cfg", &ssa.cfg);
+               zend_dump_op_array(op_array, ZEND_DUMP_CFG | ZEND_DUMP_HIDE_UNUSED_VARS, "dfa cfg", &ssa->cfg);
        }
 
        /* Compute Dominators Tree */
-       if (zend_cfg_compute_dominators_tree(op_array, &ssa.cfg) != SUCCESS) {
-               zend_arena_release(&ctx->arena, checkpoint);
-               return;
+       if (zend_cfg_compute_dominators_tree(op_array, &ssa->cfg) != SUCCESS) {
+               return FAILURE;
        }
 
        /* Identify reducible and irreducible loops */
-       if (zend_cfg_identify_loops(op_array, &ssa.cfg, &flags) != SUCCESS) {
-               zend_arena_release(&ctx->arena, checkpoint);
-               return;
+       if (zend_cfg_identify_loops(op_array, &ssa->cfg, flags) != SUCCESS) {
+               return FAILURE;
        }
 
        if (ctx->debug_level & ZEND_DUMP_DFA_DOMINATORS) {
-               zend_dump_dominators(op_array, &ssa.cfg);
+               zend_dump_dominators(op_array, &ssa->cfg);
        }
 
        build_flags = 0;
@@ -83,45 +74,45 @@ void optimize_dfa(zend_op_array *op_array, zend_optimizer_ctx *ctx)
        if (ctx->debug_level & ZEND_DUMP_DFA_PHI) {
                build_flags |= ZEND_SSA_DEBUG_PHI_PLACEMENT;
        }
-       if (zend_build_ssa(&ctx->arena, op_array, build_flags, &ssa, &flags) != SUCCESS) {
-               zend_arena_release(&ctx->arena, checkpoint);
-               return;
+       if (zend_build_ssa(&ctx->arena, op_array, build_flags, ssa, flags) != SUCCESS) {
+               return FAILURE;
        }
 
        if (ctx->debug_level & ZEND_DUMP_DFA_SSA) {
-               zend_dump_op_array(op_array, ZEND_DUMP_SSA | ZEND_DUMP_HIDE_UNUSED_VARS, "before dfa pass", &ssa);
+               zend_dump_op_array(op_array, ZEND_DUMP_SSA | ZEND_DUMP_HIDE_UNUSED_VARS, "before dfa pass", ssa);
        }
 
 
-       if (zend_ssa_compute_use_def_chains(&ctx->arena, op_array, &ssa) != SUCCESS){
-               zend_arena_release(&ctx->arena, checkpoint);
-               return;
+       if (zend_ssa_compute_use_def_chains(&ctx->arena, op_array, ssa) != SUCCESS){
+               return FAILURE;
        }
 
-       if (zend_ssa_find_false_dependencies(op_array, &ssa) != SUCCESS) {
-               zend_arena_release(&ctx->arena, checkpoint);
-               return;
+       if (zend_ssa_find_false_dependencies(op_array, ssa) != SUCCESS) {
+               return FAILURE;
        }
 
-       if (zend_ssa_find_sccs(op_array, &ssa) != SUCCESS){
-               zend_arena_release(&ctx->arena, checkpoint);
-               return;
+       if (zend_ssa_find_sccs(op_array, ssa) != SUCCESS){
+               return FAILURE;
        }
 
-       if (zend_ssa_inference(&ctx->arena, op_array, ctx->script, &ssa) != SUCCESS) {
-               return;
+       if (zend_ssa_inference(&ctx->arena, op_array, ctx->script, ssa) != SUCCESS) {
+               return FAILURE;
        }
 
        if (ctx->debug_level & ZEND_DUMP_DFA_SSA_VARS) {
-               zend_dump_ssa_variables(op_array, &ssa);
+               zend_dump_ssa_variables(op_array, ssa);
        }
 
+       return SUCCESS;
+}
+
+void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, zend_ssa *ssa)
+{
        if (ctx->debug_level & ZEND_DUMP_BEFORE_DFA_PASS) {
-               zend_dump_op_array(op_array, ZEND_DUMP_SSA | ZEND_DUMP_HIDE_UNUSED_VARS, "before dfa pass", &ssa);
+               zend_dump_op_array(op_array, ZEND_DUMP_SSA | ZEND_DUMP_HIDE_UNUSED_VARS, "before dfa pass", ssa);
        }
 
-       //TODO: Add optimization patterns ???
-       if (ssa.var_info) {
+       if (ssa->var_info) {
                int i;
                int remove_nops = 0;
 
@@ -132,48 +123,48 @@ void optimize_dfa(zend_op_array *op_array, zend_optimizer_ctx *ctx)
                // --
                // 2: ASSIGN #2.CV [undef,scalar] -> #3.CV, #1.CV |  3.CV = QM_ASSIGN #1.CV
 
-               for (i = 0; i < ssa.vars_count; i++) {
-                       int op2 = ssa.vars[i].definition;
+               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
                         && !RETURN_VALUE_USED(&op_array->opcodes[op2])
                        ) {
-                               int var2 = ssa.ops[op2].op1_use;
+                               int var2 = ssa->ops[op2].op1_use;
 
                                if (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[var2].type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))
                                ) {
 
                                        if (op_array->opcodes[op2].op2_type & (IS_TMP_VAR|IS_VAR)) {
-                                               int var1 = ssa.ops[op2].op2_use;
+                                               int var1 = ssa->ops[op2].op2_use;
 
                                                if (var1 >= 0
-                                                && !(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
+                                                && !(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 op1 = ssa->vars[var1].definition;
                                                        int var3 = i;
 
-                                                       if (zend_ssa_unlink_use_chain(&ssa, op2, var2)) {
+                                                       if (zend_ssa_unlink_use_chain(ssa, op2, var2)) {
                                                                /* Reconstruct SSA */
-                                                               ssa.vars[var3].definition = op1;
-                                                               ssa.ops[op1].result_def = var3;
+                                                               ssa->vars[var3].definition = op1;
+                                                               ssa->ops[op1].result_def = var3;
 
-                                                               ssa.vars[var1].definition = -1;
-                                                               ssa.vars[var1].use_chain = -1;
+                                                               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;
+                                                               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;
@@ -184,20 +175,20 @@ void optimize_dfa(zend_op_array *op_array, zend_optimizer_ctx *ctx)
                                                }
                                        } else if (op_array->opcodes[op2].op2_type == IS_CONST
                                         || (op_array->opcodes[op2].op2_type == IS_CV
-                                            && ssa.ops[op2].op2_use >= 0
-                                            && ssa.ops[op2].op2_def < 0
-                                            && !(ssa.var_info[ssa.ops[op2].op2_use].type & MAY_BE_REF))
+                                            && ssa->ops[op2].op2_use >= 0
+                                            && ssa->ops[op2].op2_def < 0
+                                            && !(ssa->var_info[ssa->ops[op2].op2_use].type & MAY_BE_REF))
                                        ) {
                                                int var3 = i;
 
-                                               if (zend_ssa_unlink_use_chain(&ssa, op2, var2)) {
+                                               if (zend_ssa_unlink_use_chain(ssa, op2, var2)) {
                                                        /* Reconstruct SSA */
-                                                       ssa.ops[op2].result_def = var3;
-                                                       ssa.ops[op2].op1_def = -1;
-                                                       ssa.ops[op2].op1_use = ssa.ops[op2].op2_use;
-                                                       ssa.ops[op2].op1_use_chain = ssa.ops[op2].op2_use_chain;
-                                                       ssa.ops[op2].op2_use = -1;
-                                                       ssa.ops[op2].op2_use_chain = -1;
+                                                       ssa->ops[op2].result_def = var3;
+                                                       ssa->ops[op2].op1_def = -1;
+                                                       ssa->ops[op2].op1_use = ssa->ops[op2].op2_use;
+                                                       ssa->ops[op2].op1_use_chain = ssa->ops[op2].op2_use_chain;
+                                                       ssa->ops[op2].op2_use = -1;
+                                                       ssa->ops[op2].op2_use_chain = -1;
 
                                                        /* Update opcode */
                                                        op_array->opcodes[op2].result_type = op_array->opcodes[op2].op1_type;
@@ -217,11 +208,24 @@ void optimize_dfa(zend_op_array *op_array, zend_optimizer_ctx *ctx)
                }
        }
 
-
        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);
+               zend_dump_op_array(op_array, ZEND_DUMP_SSA | ZEND_DUMP_HIDE_UNUSED_VARS, "after dfa pass", ssa);
+       }
+}
+
+void optimize_dfa(zend_op_array *op_array, zend_optimizer_ctx *ctx)
+{
+       void *checkpoint = zend_arena_checkpoint(ctx->arena);
+       uint32_t flags = 0;
+       zend_ssa ssa;
+
+       if (zend_dfa_analyze_op_array(op_array, ctx, &ssa, &flags) != SUCCESS) {
+               zend_arena_release(&ctx->arena, checkpoint);
+               return;
        }
 
+       zend_dfa_optimize_op_array(op_array, ctx, &ssa);
+
        /* Destroy SSA */
        zend_arena_release(&ctx->arena, checkpoint);
 }
index 3793ea488429a7b6f59edce2828b886d70d58b24..730f60343ab5c0ea4a20a963648c599f95dfeab3 100644 (file)
@@ -3897,7 +3897,7 @@ void zend_func_return_info(const zend_op_array   *op_array,
                                }
 
                                if (opline->op1_type == IS_CONST) {
-                                       if (Z_TYPE_P(RT_CONSTANT(op_array, opline->op1)) == IS_NULL) {
+                                       if (Z_TYPE_P(CRT_CONSTANT_EX(op_array, opline->op1, info->ssa.rt_constants)) == IS_NULL) {
                                                if (tmp_has_range < 0) {
                                                        tmp_has_range = 1;
                                                        tmp_range.underflow = 0;
@@ -3912,7 +3912,7 @@ void zend_func_return_info(const zend_op_array   *op_array,
                                                                tmp_range.max = MAX(tmp_range.max, 0);
                                                        }
                                                }
-                                       } else if (Z_TYPE_P(RT_CONSTANT(op_array, opline->op1)) == IS_FALSE) {
+                                       } else if (Z_TYPE_P(CRT_CONSTANT_EX(op_array, opline->op1, info->ssa.rt_constants)) == IS_FALSE) {
                                                if (tmp_has_range < 0) {
                                                        tmp_has_range = 1;
                                                        tmp_range.underflow = 0;
@@ -3927,7 +3927,7 @@ void zend_func_return_info(const zend_op_array   *op_array,
                                                                tmp_range.max = MAX(tmp_range.max, 0);
                                                        }
                                                }
-                                       } else if (Z_TYPE_P(RT_CONSTANT(op_array, opline->op1)) == IS_TRUE) {
+                                       } else if (Z_TYPE_P(CRT_CONSTANT_EX(op_array, opline->op1, info->ssa.rt_constants)) == IS_TRUE) {
                                                if (tmp_has_range < 0) {
                                                        tmp_has_range = 1;
                                                        tmp_range.underflow = 0;
@@ -3942,19 +3942,19 @@ void zend_func_return_info(const zend_op_array   *op_array,
                                                                tmp_range.max = MAX(tmp_range.max, 1);
                                                        }
                                                }
-                                       } else if (Z_TYPE_P(RT_CONSTANT(op_array, opline->op1)) == IS_LONG) {
+                                       } else if (Z_TYPE_P(CRT_CONSTANT_EX(op_array, opline->op1, info->ssa.rt_constants)) == IS_LONG) {
                                                if (tmp_has_range < 0) {
                                                        tmp_has_range = 1;
                                                        tmp_range.underflow = 0;
-                                                       tmp_range.min = Z_LVAL_P(RT_CONSTANT(op_array, opline->op1));
-                                                       tmp_range.max = Z_LVAL_P(RT_CONSTANT(op_array, opline->op1));
+                                                       tmp_range.min = Z_LVAL_P(CRT_CONSTANT_EX(op_array, opline->op1, info->ssa.rt_constants));
+                                                       tmp_range.max = Z_LVAL_P(CRT_CONSTANT_EX(op_array, opline->op1, info->ssa.rt_constants));
                                                        tmp_range.overflow = 0;
                                                } else if (tmp_has_range) {
                                                        if (!tmp_range.underflow) {
-                                                               tmp_range.min = MIN(tmp_range.min, Z_LVAL_P(RT_CONSTANT(op_array, opline->op1)));
+                                                               tmp_range.min = MIN(tmp_range.min, Z_LVAL_P(CRT_CONSTANT_EX(op_array, opline->op1, info->ssa.rt_constants)));
                                                        }
                                                        if (!tmp_range.overflow) {
-                                                               tmp_range.max = MAX(tmp_range.max, Z_LVAL_P(RT_CONSTANT(op_array, opline->op1)));
+                                                               tmp_range.max = MAX(tmp_range.max, Z_LVAL_P(CRT_CONSTANT_EX(op_array, opline->op1, info->ssa.rt_constants)));
                                                        }
                                                }
                                        } else {
index 01d56b3c3394b8ba4d4697948709817801b5af4c..7ae7213ed99d8589c8f9db0ad76d424094561c0a 100644 (file)
@@ -727,6 +727,25 @@ static void zend_adjust_fcall_stack_size(zend_op_array *op_array, zend_optimizer
        }
 }
 
+static void zend_adjust_fcall_stack_size_graph(zend_op_array *op_array)
+{
+       zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
+
+       if (func_info) {
+               zend_call_info *call_info =func_info->callee_info;
+
+               while (call_info) {
+                       zend_op *opline = call_info->caller_init_opline;
+
+                       if (opline && call_info->callee_func) {
+                               ZEND_ASSERT(opline->opcode == ZEND_INIT_FCALL);
+                               opline->op1.num = zend_vm_calc_used_stack(opline->extended_value, call_info->callee_func);
+                       }
+                       call_info = call_info->next_callee;
+               }
+       }
+}
+
 int zend_optimize_script(zend_script *script, zend_long optimization_level, zend_long debug_level)
 {
        uint idx, j;
@@ -777,19 +796,28 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
            (ZEND_OPTIMIZER_PASS_7 & optimization_level) &&
            zend_build_call_graph(&ctx.arena, script, ZEND_RT_CONSTANTS, &call_graph) == SUCCESS) {
                /* Optimize using call-graph */
-               uint32_t i;
+               void *checkpoint = zend_arena_checkpoint(ctx.arena);
+               int i;
                zend_func_info *func_info;
 
                for (i = 0; i < call_graph.op_arrays_count; i++) {
                        zend_revert_pass_two(call_graph.op_arrays[i]);
+               }
+
+               for (i = 0; i < call_graph.op_arrays_count; i++) {
                        func_info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
                        if (func_info) {
-                               func_info->ssa.rt_constants = 0;
+                               zend_dfa_analyze_op_array(call_graph.op_arrays[i], &ctx, &func_info->ssa, &func_info->flags);
                        }
                }
 
+               //TODO: perform inner-script inference???
+
                for (i = 0; i < call_graph.op_arrays_count; i++) {
-                       optimize_dfa(call_graph.op_arrays[i], &ctx);
+                       func_info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
+                       if (func_info) {
+                               zend_dfa_optimize_op_array(call_graph.op_arrays[i], &ctx, &func_info->ssa);
+                       }
                }
 
                if (debug_level & ZEND_DUMP_AFTER_PASS_7) {
@@ -798,11 +826,19 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
                        }
                }
 
+               if (ZEND_OPTIMIZER_PASS_12 & optimization_level) {
+                       for (i = 0; i < call_graph.op_arrays_count; i++) {
+                               zend_adjust_fcall_stack_size_graph(call_graph.op_arrays[i]);
+                       }
+               }
+
                for (i = 0; i < call_graph.op_arrays_count; i++) {
                        zend_redo_pass_two(call_graph.op_arrays[i]);
                        ZEND_SET_FUNC_INFO(call_graph.op_arrays[i], NULL);
                }
-       }
+
+               zend_arena_release(&ctx.arena, checkpoint);
+       } else
 #endif
 
        if (ZEND_OPTIMIZER_PASS_12 & optimization_level) {
index 3bf96165e745e7716638ddabf7e65a99408540b1..85e50cab0aeffcd0b9a1638ddaa10def3ea8e113 100644 (file)
@@ -22,6 +22,8 @@
 #ifndef ZEND_OPTIMIZER_INTERNAL_H
 #define ZEND_OPTIMIZER_INTERNAL_H
 
+#include "zend_ssa.h"
+
 #define ZEND_RESULT_TYPE(opline)               (opline)->result_type
 #define ZEND_RESULT(opline)                            (opline)->result
 #define ZEND_OP1_TYPE(opline)                  (opline)->op1_type
@@ -98,6 +100,8 @@ void zend_optimizer_pass3(zend_op_array *op_array);
 void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx);
 void optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx);
 void optimize_dfa(zend_op_array *op_array, zend_optimizer_ctx *ctx);
+int  zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, zend_ssa *ssa, uint32_t *flags);
+void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, zend_ssa *ssa);
 void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *ctx);
 void zend_optimizer_nop_removal(zend_op_array *op_array);
 void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx *ctx);