summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2015-12-24 19:05:27 +0300
committerDmitry Stogov <dmitry@zend.com>2015-12-24 19:05:27 +0300
commitb3d0178915163c8d52091a6a822007a56ce02801 (patch)
treeff5936c497d49a468422e81dc30d43aa54c84c9b
parent7a2f60d3c7a0b80525f5435b3582540e7ae337ee (diff)
downloadphp-git-b3d0178915163c8d52091a6a822007a56ce02801.tar.gz
Rearrange code to enable inner precedure inference
-rw-r--r--ext/opcache/Optimizer/dfa_pass.c158
-rw-r--r--ext/opcache/Optimizer/zend_inference.c16
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.c44
-rw-r--r--ext/opcache/Optimizer/zend_optimizer_internal.h4
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);