From 1ee9110b35eab79f74d08278c104c92796740fa7 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 6 Jul 2017 19:34:43 +0300 Subject: [PATCH] Remove NOP instructions, introduced bvy SCCP. This commit discloses unrelated issue caused ext/soap/tests/bug70211.phpt failure. --- ext/opcache/Optimizer/dfa_pass.c | 4 +++- ext/opcache/Optimizer/sccp.c | 17 +++++++++++++---- ext/opcache/Optimizer/scdf.c | 6 +++++- ext/opcache/Optimizer/scdf.h | 2 +- ext/opcache/Optimizer/zend_optimizer_internal.h | 2 +- 5 files changed, 23 insertions(+), 8 deletions(-) diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c index a6900be36b6..88f30a7d8ec 100644 --- a/ext/opcache/Optimizer/dfa_pass.c +++ b/ext/opcache/Optimizer/dfa_pass.c @@ -332,7 +332,9 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx zend_op *opline; zval tmp; - sccp_optimize_op_array(op_array, ssa, call_map); + if (sccp_optimize_op_array(op_array, ssa, call_map)) { + remove_nops = 1; + } for (v = op_array->last_var; v < ssa->vars_count; v++) { diff --git a/ext/opcache/Optimizer/sccp.c b/ext/opcache/Optimizer/sccp.c index f06e90fe2c8..99c7f0f5ce8 100644 --- a/ext/opcache/Optimizer/sccp.c +++ b/ext/opcache/Optimizer/sccp.c @@ -1209,11 +1209,12 @@ static zval *value_from_type_and_range(sccp_ctx *ctx, int var_num, zval *tmp) { /* This will try to replace uses of SSA variables we have determined to be constant. Not all uses * can be replaced, because some instructions don't accept constant operands or only accept them * if they have a certain type. */ -static void replace_constant_operands(sccp_ctx *ctx) { +static int replace_constant_operands(sccp_ctx *ctx) { zend_ssa *ssa = ctx->ssa; zend_op_array *op_array = ctx->op_array; int i; zval tmp; + int removed_ops; /* We iterate the variables backwards, so we can eliminate sequences like INIT_ROPE * and INIT_ARRAY. */ @@ -1291,10 +1292,12 @@ static void replace_constant_operands(sccp_ctx *ctx) { zend_ssa_remove_instr(ssa, call->arg_info[i].opline, &ssa->ops[call->arg_info[i].opline - op_array->opcodes]); } + removed_ops = call->num_args + 2; } else { /* Ordinary computational instruction -> remove it */ zend_ssa_remove_result_def(ssa, ssa_op); zend_ssa_remove_instr(ssa, opline, ssa_op); + removed_ops++; } } else if (ssa_op->op1_def == i) { /* Compound assign or incdec -> convert to direct ASSIGN */ @@ -1318,6 +1321,7 @@ static void replace_constant_operands(sccp_ctx *ctx) { /* Remove OP_DATA opcode */ if (opline->opcode == ZEND_ASSIGN_DIM) { + removed_ops++; zend_ssa_remove_instr(ssa, opline + 1, ssa_op + 1); } @@ -1334,6 +1338,8 @@ static void replace_constant_operands(sccp_ctx *ctx) { zend_ssa_remove_phi(ssa, var->definition_phi); }*/ } + + return removed_ops; } static void sccp_context_init(sccp_ctx *ctx, @@ -1370,10 +1376,11 @@ static void sccp_context_free(sccp_ctx *ctx) { efree(ctx->values); } -void sccp_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, zend_call_info **call_map) +int sccp_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, zend_call_info **call_map) { scdf_ctx scdf; sccp_ctx ctx; + int removed_ops = 0; sccp_context_init(&ctx, ssa, op_array, call_map); @@ -1384,9 +1391,11 @@ void sccp_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, zend_call_in scdf_init(&scdf, op_array, ssa, &ctx); scdf_solve(&scdf, "SCCP"); - scdf_remove_unreachable_blocks(&scdf); - replace_constant_operands(&ctx); + removed_ops += scdf_remove_unreachable_blocks(&scdf); + removed_ops += replace_constant_operands(&ctx); scdf_free(&scdf); sccp_context_free(&ctx); + + return removed_ops; } diff --git a/ext/opcache/Optimizer/scdf.c b/ext/opcache/Optimizer/scdf.c index 1eab7a9dfe9..a35559a513b 100644 --- a/ext/opcache/Optimizer/scdf.c +++ b/ext/opcache/Optimizer/scdf.c @@ -216,14 +216,18 @@ static zend_bool kept_alive_by_live_range(scdf_ctx *scdf, uint32_t block) { /* Removes unreachable blocks. This will remove both the instructions (and phis) in the * blocks, as well as remove them from the successor / predecessor lists and mark them * unreachable. Blocks already marked unreachable are not removed. */ -void scdf_remove_unreachable_blocks(scdf_ctx *scdf) { +int scdf_remove_unreachable_blocks(scdf_ctx *scdf) { zend_ssa *ssa = scdf->ssa; int i; + int removed_ops = 0; + for (i = 0; i < ssa->cfg.blocks_count; i++) { if (!zend_bitset_in(scdf->executable_blocks, i) && (ssa->cfg.blocks[i].flags & ZEND_BB_REACHABLE) && !kept_alive_by_live_range(scdf, i)) { + removed_ops += ssa->cfg.blocks[i].len; zend_ssa_remove_block(scdf->op_array, ssa, i); } } + return removed_ops; } diff --git a/ext/opcache/Optimizer/scdf.h b/ext/opcache/Optimizer/scdf.h index a777ccc4fb6..dfdcb11b1e7 100644 --- a/ext/opcache/Optimizer/scdf.h +++ b/ext/opcache/Optimizer/scdf.h @@ -51,7 +51,7 @@ void scdf_init(scdf_ctx *scdf, zend_op_array *op_array, zend_ssa *ssa, void *ctx void scdf_solve(scdf_ctx *scdf, const char *name); void scdf_free(scdf_ctx *scdf); -void scdf_remove_unreachable_blocks(scdf_ctx *scdf); +int scdf_remove_unreachable_blocks(scdf_ctx *scdf); /* Add uses to worklist */ static inline void scdf_add_to_worklist(scdf_ctx *scdf, int var_num) { diff --git a/ext/opcache/Optimizer/zend_optimizer_internal.h b/ext/opcache/Optimizer/zend_optimizer_internal.h index aeccdb302a3..d2b8b08a87d 100644 --- a/ext/opcache/Optimizer/zend_optimizer_internal.h +++ b/ext/opcache/Optimizer/zend_optimizer_internal.h @@ -110,6 +110,6 @@ uint32_t zend_optimizer_classify_function(zend_string *name, uint32_t num_args); void zend_optimizer_migrate_jump(zend_op_array *op_array, zend_op *new_opline, zend_op *opline); void zend_optimizer_shift_jump(zend_op_array *op_array, zend_op *opline, uint32_t *shiftlist); zend_uchar zend_compound_assign_to_binary_op(zend_uchar opcode); -void sccp_optimize_op_array(zend_op_array *op_arrya, zend_ssa *ssa, zend_call_info **call_map); +int sccp_optimize_op_array(zend_op_array *op_arrya, zend_ssa *ssa, zend_call_info **call_map); #endif