mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Set RETURN_VALUE_UNUSED instead of additional FREE opcode, if possible.
Keep alive dead instructions that have to free two temporary variables.
This commit is contained in:
parent
94c9b26695
commit
624f76df48
1 changed files with 77 additions and 7 deletions
|
@ -276,6 +276,68 @@ static inline zend_bool is_var_dead(context *ctx, int var_num) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sometimes we can mark the var as EXT_UNUSED
|
||||||
|
static zend_bool try_remove_var_def(context *ctx, int free_var, int use_chain, zend_op *opline) {
|
||||||
|
if (use_chain >= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
zend_ssa_var *var = &ctx->ssa->vars[free_var];
|
||||||
|
int def = var->definition;
|
||||||
|
|
||||||
|
if (def >= 0) {
|
||||||
|
zend_ssa_op *def_op = &ctx->ssa->ops[def];
|
||||||
|
|
||||||
|
if (def_op->result_def == free_var
|
||||||
|
&& var->phi_use_chain == NULL
|
||||||
|
&& var->use_chain == (opline - ctx->op_array->opcodes)) {
|
||||||
|
zend_op *def_opline = &ctx->op_array->opcodes[def];
|
||||||
|
|
||||||
|
switch (def_opline->opcode) {
|
||||||
|
case ZEND_ASSIGN:
|
||||||
|
case ZEND_ASSIGN_REF:
|
||||||
|
case ZEND_ASSIGN_DIM:
|
||||||
|
case ZEND_ASSIGN_OBJ:
|
||||||
|
case ZEND_ASSIGN_ADD:
|
||||||
|
case ZEND_ASSIGN_SUB:
|
||||||
|
case ZEND_ASSIGN_MUL:
|
||||||
|
case ZEND_ASSIGN_DIV:
|
||||||
|
case ZEND_ASSIGN_MOD:
|
||||||
|
case ZEND_ASSIGN_SL:
|
||||||
|
case ZEND_ASSIGN_SR:
|
||||||
|
case ZEND_ASSIGN_CONCAT:
|
||||||
|
case ZEND_ASSIGN_BW_OR:
|
||||||
|
case ZEND_ASSIGN_BW_AND:
|
||||||
|
case ZEND_ASSIGN_BW_XOR:
|
||||||
|
case ZEND_ASSIGN_POW:
|
||||||
|
case ZEND_PRE_INC:
|
||||||
|
case ZEND_POST_INC:
|
||||||
|
case ZEND_PRE_DEC:
|
||||||
|
case ZEND_POST_DEC:
|
||||||
|
case ZEND_PRE_INC_OBJ:
|
||||||
|
case ZEND_POST_INC_OBJ:
|
||||||
|
case ZEND_PRE_DEC_OBJ:
|
||||||
|
case ZEND_POST_DEC_OBJ:
|
||||||
|
case ZEND_DO_ICALL:
|
||||||
|
case ZEND_DO_UCALL:
|
||||||
|
case ZEND_DO_FCALL_BY_NAME:
|
||||||
|
case ZEND_DO_FCALL:
|
||||||
|
case ZEND_INCLUDE_OR_EVAL:
|
||||||
|
case ZEND_YIELD:
|
||||||
|
case ZEND_YIELD_FROM:
|
||||||
|
case ZEND_ASSERT_CHECK:
|
||||||
|
def_opline->result_type = IS_UNUSED;
|
||||||
|
def_opline->result.var = 0;
|
||||||
|
def_op->result_def = -1;
|
||||||
|
var->definition = -1;
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Returns whether the instruction has been DCEd */
|
/* Returns whether the instruction has been DCEd */
|
||||||
static zend_bool dce_instr(context *ctx, zend_op *opline, zend_ssa_op *ssa_op) {
|
static zend_bool dce_instr(context *ctx, zend_op *opline, zend_ssa_op *ssa_op) {
|
||||||
zend_ssa *ssa = ctx->ssa;
|
zend_ssa *ssa = ctx->ssa;
|
||||||
|
@ -291,20 +353,28 @@ static zend_bool dce_instr(context *ctx, zend_op *opline, zend_ssa_op *ssa_op) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Two free vars?
|
|
||||||
if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !is_var_dead(ctx, ssa_op->op1_use)) {
|
if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !is_var_dead(ctx, ssa_op->op1_use)) {
|
||||||
free_var = ssa_op->op1_use;
|
if (!try_remove_var_def(ctx, ssa_op->op1_use, ssa_op->op1_use_chain, opline)) {
|
||||||
free_var_type = opline->op1_type;
|
free_var = ssa_op->op1_use;
|
||||||
} else if ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) && !is_var_dead(ctx, ssa_op->op2_use)) {
|
free_var_type = opline->op1_type;
|
||||||
free_var = ssa_op->op2_use;
|
}
|
||||||
free_var_type = opline->op2_type;
|
}
|
||||||
|
if ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) && !is_var_dead(ctx, ssa_op->op2_use)) {
|
||||||
|
if (!try_remove_var_def(ctx, ssa_op->op2_use, ssa_op->op2_use_chain, opline)) {
|
||||||
|
if (free_var >= 0) {
|
||||||
|
// TODO: We can't free two vars. Keep instruction alive.
|
||||||
|
zend_bitset_excl(ctx->instr_dead, opline - ctx->op_array->opcodes);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
free_var = ssa_op->op2_use;
|
||||||
|
free_var_type = opline->op2_type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
zend_ssa_rename_defs_of_instr(ctx->ssa, ssa_op);
|
zend_ssa_rename_defs_of_instr(ctx->ssa, ssa_op);
|
||||||
zend_ssa_remove_instr(ctx->ssa, opline, ssa_op);
|
zend_ssa_remove_instr(ctx->ssa, opline, ssa_op);
|
||||||
|
|
||||||
if (free_var >= 0) {
|
if (free_var >= 0) {
|
||||||
// TODO Sometimes we can mark the var as EXT_UNUSED
|
|
||||||
opline->opcode = ZEND_FREE;
|
opline->opcode = ZEND_FREE;
|
||||||
opline->op1.var = (uintptr_t) ZEND_CALL_VAR_NUM(NULL, ssa->vars[free_var].var);
|
opline->op1.var = (uintptr_t) ZEND_CALL_VAR_NUM(NULL, ssa->vars[free_var].var);
|
||||||
opline->op1_type = free_var_type;
|
opline->op1_type = free_var_type;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue