mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Combined constants substitutaion and dead instruction removing in single pass. This eleminates substitution in dead instructions.
This commit is contained in:
parent
f890375c16
commit
cffee2f7e5
1 changed files with 24 additions and 44 deletions
|
@ -1186,10 +1186,13 @@ static zval *value_from_type_and_range(sccp_ctx *ctx, int var_num, zval *tmp) {
|
||||||
* if they have a certain type. */
|
* if they have a certain type. */
|
||||||
static void replace_constant_operands(sccp_ctx *ctx) {
|
static void replace_constant_operands(sccp_ctx *ctx) {
|
||||||
zend_ssa *ssa = ctx->ssa;
|
zend_ssa *ssa = ctx->ssa;
|
||||||
|
zend_op_array *op_array = ctx->op_array;
|
||||||
int i;
|
int i;
|
||||||
zval tmp;
|
zval tmp;
|
||||||
|
|
||||||
for (i = 0; i < ssa->vars_count; i++) {
|
/* We iterate the variables backwards, so we can eliminate sequences like INIT_ROPE
|
||||||
|
* and INIT_ARRAY. */
|
||||||
|
for (i = ssa->vars_count - 1; i >= 0; i--) {
|
||||||
zend_ssa_var *var = &ssa->vars[i];
|
zend_ssa_var *var = &ssa->vars[i];
|
||||||
zval *value;
|
zval *value;
|
||||||
int use;
|
int use;
|
||||||
|
@ -1204,7 +1207,7 @@ static void replace_constant_operands(sccp_ctx *ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
FOREACH_USE(var, use) {
|
FOREACH_USE(var, use) {
|
||||||
zend_op *opline = &ctx->op_array->opcodes[use];
|
zend_op *opline = &op_array->opcodes[use];
|
||||||
zend_ssa_op *ssa_op = &ssa->ops[use];
|
zend_ssa_op *ssa_op = &ssa->ops[use];
|
||||||
if (try_replace_op1(ctx, opline, ssa_op, i, value)) {
|
if (try_replace_op1(ctx, opline, ssa_op, i, value)) {
|
||||||
ZEND_ASSERT(ssa_op->op1_def == -1);
|
ZEND_ASSERT(ssa_op->op1_def == -1);
|
||||||
|
@ -1223,8 +1226,6 @@ static void replace_constant_operands(sccp_ctx *ctx) {
|
||||||
ssa_op->op2_use_chain = -1;
|
ssa_op->op2_use_chain = -1;
|
||||||
}
|
}
|
||||||
} FOREACH_USE_END();
|
} FOREACH_USE_END();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is a basic DCE pass we run after SCCP. It only works on those instructions those result
|
/* This is a basic DCE pass we run after SCCP. It only works on those instructions those result
|
||||||
* value(s) were determined by SCCP. It removes dead computational instructions and converts
|
* value(s) were determined by SCCP. It removes dead computational instructions and converts
|
||||||
|
@ -1237,16 +1238,8 @@ static void replace_constant_operands(sccp_ctx *ctx) {
|
||||||
* not. As such doing DCE here will allow us to eliminate more dead code in combination.
|
* not. As such doing DCE here will allow us to eliminate more dead code in combination.
|
||||||
* c) The ordinary DCE pass cannot collect dead calls. However SCCP can result in dead calls, which
|
* c) The ordinary DCE pass cannot collect dead calls. However SCCP can result in dead calls, which
|
||||||
* we need to collect. */
|
* we need to collect. */
|
||||||
static void eliminate_dead_instructions(sccp_ctx *ctx) {
|
|
||||||
zend_ssa *ssa = ctx->ssa;
|
|
||||||
zend_op_array *op_array = ctx->op_array;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* We iterate the variables backwards, so we can eliminate sequences like INIT_ROPE
|
if (var->definition >= 0 && value_known(&ctx->values[i])) {
|
||||||
* and INIT_ARRAY. */
|
|
||||||
for (i = ssa->vars_count - 1; i >= 0; i--) {
|
|
||||||
zend_ssa_var *var = &ssa->vars[i];
|
|
||||||
if (value_known(&ctx->values[i]) && var->definition >= 0) {
|
|
||||||
zend_op *opline = &op_array->opcodes[var->definition];
|
zend_op *opline = &op_array->opcodes[var->definition];
|
||||||
zend_ssa_op *ssa_op = &ssa->ops[var->definition];
|
zend_ssa_op *ssa_op = &ssa->ops[var->definition];
|
||||||
if (opline->opcode == ZEND_ASSIGN) {
|
if (opline->opcode == ZEND_ASSIGN) {
|
||||||
|
@ -1254,11 +1247,11 @@ static void eliminate_dead_instructions(sccp_ctx *ctx) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ssa_op->result_def >= 0
|
if (ssa_op->result_def == i
|
||||||
&& ssa_op->op1_def < 0
|
&& ssa_op->op1_def < 0
|
||||||
&& ssa_op->op2_def < 0
|
&& ssa_op->op2_def < 0
|
||||||
&& ssa->vars[ssa_op->result_def].use_chain < 0
|
&& var->use_chain < 0
|
||||||
&& ssa->vars[ssa_op->result_def].phi_use_chain == NULL) {
|
&& var->phi_use_chain == NULL) {
|
||||||
if (opline->opcode == ZEND_DO_ICALL) {
|
if (opline->opcode == ZEND_DO_ICALL) {
|
||||||
/* Call instruction -> remove opcodes that are part of the call */
|
/* Call instruction -> remove opcodes that are part of the call */
|
||||||
zend_call_info *call = ctx->call_map[var->definition];
|
zend_call_info *call = ctx->call_map[var->definition];
|
||||||
|
@ -1278,10 +1271,8 @@ static void eliminate_dead_instructions(sccp_ctx *ctx) {
|
||||||
zend_ssa_remove_result_def(ssa, ssa_op);
|
zend_ssa_remove_result_def(ssa, ssa_op);
|
||||||
zend_ssa_remove_instr(ssa, opline, ssa_op);
|
zend_ssa_remove_instr(ssa, opline, ssa_op);
|
||||||
}
|
}
|
||||||
} else if (ssa_op->op1_def >= 0) {
|
} else if (ssa_op->op1_def == i) {
|
||||||
/* Compound assign or incdec -> convert to direct ASSIGN */
|
/* Compound assign or incdec -> convert to direct ASSIGN */
|
||||||
zval *val = &ctx->values[ssa_op->op1_def];
|
|
||||||
ZEND_ASSERT(value_known(val));
|
|
||||||
|
|
||||||
/* Destroy previous op2 */
|
/* Destroy previous op2 */
|
||||||
if (opline->op2_type == IS_CONST) {
|
if (opline->op2_type == IS_CONST) {
|
||||||
|
@ -1308,8 +1299,8 @@ static void eliminate_dead_instructions(sccp_ctx *ctx) {
|
||||||
/* Convert to ASSIGN */
|
/* Convert to ASSIGN */
|
||||||
opline->opcode = ZEND_ASSIGN;
|
opline->opcode = ZEND_ASSIGN;
|
||||||
opline->op2_type = IS_CONST;
|
opline->op2_type = IS_CONST;
|
||||||
opline->op2.constant = zend_optimizer_add_literal(op_array, val);
|
opline->op2.constant = zend_optimizer_add_literal(op_array, value);
|
||||||
Z_TRY_ADDREF_P(val);
|
Z_TRY_ADDREF_P(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*if (var->definition_phi
|
/*if (var->definition_phi
|
||||||
|
@ -1354,17 +1345,6 @@ static void sccp_context_free(sccp_ctx *ctx) {
|
||||||
efree(ctx->values);
|
efree(ctx->values);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sccp_apply_results(sccp_ctx *ctx) {
|
|
||||||
replace_constant_operands(ctx);
|
|
||||||
#if 0
|
|
||||||
zend_dump_op_array(ctx->op_array, ZEND_DUMP_SSA, "SCCP-1", ctx->ssa);
|
|
||||||
#endif
|
|
||||||
eliminate_dead_instructions(ctx);
|
|
||||||
#if 0
|
|
||||||
zend_dump_op_array(ctx->op_array, ZEND_DUMP_SSA, "SCCP-2", ctx->ssa);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void sccp_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, zend_call_info **call_map)
|
void sccp_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, zend_call_info **call_map)
|
||||||
{
|
{
|
||||||
scdf_ctx scdf;
|
scdf_ctx scdf;
|
||||||
|
@ -1380,7 +1360,7 @@ void sccp_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, zend_call_in
|
||||||
scdf_solve(&scdf, "SCCP");
|
scdf_solve(&scdf, "SCCP");
|
||||||
|
|
||||||
scdf_remove_unreachable_blocks(&scdf);
|
scdf_remove_unreachable_blocks(&scdf);
|
||||||
sccp_apply_results(&ctx);
|
replace_constant_operands(&ctx);
|
||||||
|
|
||||||
scdf_free(&scdf);
|
scdf_free(&scdf);
|
||||||
sccp_context_free(&ctx);
|
sccp_context_free(&ctx);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue