diff options
author | Dmitry Stogov <dmitry@zend.com> | 2015-12-24 19:05:27 +0300 |
---|---|---|
committer | Dmitry Stogov <dmitry@zend.com> | 2015-12-24 19:05:27 +0300 |
commit | b3d0178915163c8d52091a6a822007a56ce02801 (patch) | |
tree | ff5936c497d49a468422e81dc30d43aa54c84c9b | |
parent | 7a2f60d3c7a0b80525f5435b3582540e7ae337ee (diff) | |
download | php-git-b3d0178915163c8d52091a6a822007a56ce02801.tar.gz |
Rearrange code to enable inner precedure inference
-rw-r--r-- | ext/opcache/Optimizer/dfa_pass.c | 158 | ||||
-rw-r--r-- | ext/opcache/Optimizer/zend_inference.c | 16 | ||||
-rw-r--r-- | ext/opcache/Optimizer/zend_optimizer.c | 44 | ||||
-rw-r--r-- | ext/opcache/Optimizer/zend_optimizer_internal.h | 4 |
4 files changed, 133 insertions, 89 deletions
diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c index a2a94af073..18f9e5c9a5 100644 --- a/ext/opcache/Optimizer/dfa_pass.c +++ b/ext/opcache/Optimizer/dfa_pass.c @@ -30,50 +30,41 @@ #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); } diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index 3793ea4884..730f60343a 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -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 { diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index 01d56b3c33..7ae7213ed9 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -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) { diff --git a/ext/opcache/Optimizer/zend_optimizer_internal.h b/ext/opcache/Optimizer/zend_optimizer_internal.h index 3bf96165e7..85e50cab0a 100644 --- a/ext/opcache/Optimizer/zend_optimizer_internal.h +++ b/ext/opcache/Optimizer/zend_optimizer_internal.h @@ -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); |