Skip to content

Commit de78786

Browse files
committed
Optimize out result value of ASSIGN, ASSIGN_OP and INC/DEC opcodes, if possible.
1 parent c2fbab3 commit de78786

File tree

1 file changed

+109
-1
lines changed

1 file changed

+109
-1
lines changed

ext/opcache/Optimizer/dfa_pass.c

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -985,6 +985,77 @@ static int zend_dfa_optimize_jmps(zend_op_array *op_array, zend_ssa *ssa)
985985
return removed_ops;
986986
}
987987

988+
static int zend_dfa_try_to_replace_result(zend_op_array *op_array, zend_ssa *ssa, int def, int cv_var)
989+
{
990+
int result_var = ssa->ops[def].result_def;
991+
int cv = EX_NUM_TO_VAR(ssa->vars[cv_var].var);
992+
993+
if (result_var >= 0
994+
&& !(ssa->var_info[cv_var].type & MAY_BE_REF)
995+
&& ssa->vars[cv_var].alias == NO_ALIAS
996+
&& ssa->vars[result_var].phi_use_chain == NULL
997+
&& ssa->vars[result_var].sym_use_chain == NULL) {
998+
int use = ssa->vars[result_var].use_chain;
999+
1000+
if (use >= 0
1001+
&& zend_ssa_next_use(ssa->ops, result_var, use) < 0
1002+
&& op_array->opcodes[use].opcode != ZEND_FREE
1003+
&& op_array->opcodes[use].opcode != ZEND_SEND_VAL
1004+
&& op_array->opcodes[use].opcode != ZEND_SEND_VAL_EX
1005+
&& op_array->opcodes[use].opcode != ZEND_VERIFY_RETURN_TYPE) {
1006+
if (use > def) {
1007+
int i = use;
1008+
const zend_op *opline = &op_array->opcodes[use];
1009+
1010+
while (i > def) {
1011+
if ((opline->op1_type == IS_CV && opline->op1.var == cv)
1012+
|| (opline->op2_type == IS_CV && opline->op2.var == cv)
1013+
|| (opline->result_type == IS_CV && opline->result.var == cv)) {
1014+
return 0;
1015+
}
1016+
opline--;
1017+
i--;
1018+
}
1019+
1020+
/* Update opcodes and reconstruct SSA */
1021+
ssa->vars[result_var].definition = -1;
1022+
ssa->vars[result_var].use_chain = -1;
1023+
ssa->ops[def].result_def = -1;
1024+
1025+
op_array->opcodes[def].result_type = IS_UNUSED;
1026+
op_array->opcodes[def].result.var = 0;
1027+
1028+
if (ssa->ops[use].op1_use == result_var) {
1029+
ssa->ops[use].op1_use = cv_var;
1030+
ssa->ops[use].op1_use_chain = ssa->vars[cv_var].use_chain;
1031+
ssa->vars[cv_var].use_chain = use;
1032+
1033+
op_array->opcodes[use].op1_type = IS_CV;
1034+
op_array->opcodes[use].op1.var = cv;
1035+
} else if (ssa->ops[use].op2_use == result_var) {
1036+
ssa->ops[use].op2_use = cv_var;
1037+
ssa->ops[use].op2_use_chain = ssa->vars[cv_var].use_chain;
1038+
ssa->vars[cv_var].use_chain = use;
1039+
1040+
op_array->opcodes[use].op2_type = IS_CV;
1041+
op_array->opcodes[use].op2.var = cv;
1042+
} else if (ssa->ops[use].result_use == result_var) {
1043+
ssa->ops[use].result_use = cv_var;
1044+
ssa->ops[use].res_use_chain = ssa->vars[cv_var].use_chain;
1045+
ssa->vars[cv_var].use_chain = use;
1046+
1047+
op_array->opcodes[use].result_type = IS_CV;
1048+
op_array->opcodes[use].result.var = cv;
1049+
}
1050+
1051+
return 1;
1052+
}
1053+
}
1054+
}
1055+
1056+
return 0;
1057+
}
1058+
9881059
void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, zend_ssa *ssa, zend_call_info **call_map)
9891060
{
9901061
if (ctx->debug_level & ZEND_DUMP_BEFORE_DFA_PASS) {
@@ -1303,6 +1374,44 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
13031374
continue;
13041375
}
13051376

1377+
if (ssa->ops[op_1].op1_def == v
1378+
&& RETURN_VALUE_USED(opline)) {
1379+
if (opline->opcode == ZEND_ASSIGN
1380+
|| opline->opcode == ZEND_ASSIGN_OP
1381+
|| opline->opcode == ZEND_PRE_INC
1382+
|| opline->opcode == ZEND_PRE_DEC) {
1383+
zend_dfa_try_to_replace_result(op_array, ssa, op_1, v);
1384+
} else if (opline->opcode == ZEND_POST_INC) {
1385+
int result_var = ssa->ops[op_1].result_def;
1386+
1387+
if (result_var >= 0
1388+
&& (ssa->var_info[result_var].type & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_DOUBLE))) == 0) {
1389+
int use = ssa->vars[result_var].use_chain;
1390+
1391+
if (op_array->opcodes[use].opcode == ZEND_IS_SMALLER
1392+
&& ssa->ops[use].op1_use == result_var
1393+
&& zend_dfa_try_to_replace_result(op_array, ssa, op_1, v)) {
1394+
opline->opcode = ZEND_PRE_INC;
1395+
op_array->opcodes[use].opcode = ZEND_IS_SMALLER_OR_EQUAL;
1396+
}
1397+
}
1398+
} else if (opline->opcode == ZEND_POST_DEC) {
1399+
int result_var = ssa->ops[op_1].result_def;
1400+
1401+
if (result_var >= 0
1402+
&& (ssa->var_info[result_var].type & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_DOUBLE))) == 0) {
1403+
int use = ssa->vars[result_var].use_chain;
1404+
1405+
if (op_array->opcodes[use].opcode == ZEND_IS_SMALLER
1406+
&& ssa->ops[use].op2_use == result_var
1407+
&& zend_dfa_try_to_replace_result(op_array, ssa, op_1, v)) {
1408+
opline->opcode = ZEND_PRE_DEC;
1409+
op_array->opcodes[use].opcode = ZEND_IS_SMALLER_OR_EQUAL;
1410+
}
1411+
}
1412+
}
1413+
}
1414+
13061415
if (opline->opcode == ZEND_ASSIGN
13071416
&& ssa->ops[op_1].op1_def == v
13081417
&& !RETURN_VALUE_USED(opline)
@@ -1312,7 +1421,6 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
13121421
if (orig_var >= 0
13131422
&& !(ssa->var_info[orig_var].type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))
13141423
) {
1315-
13161424
int src_var = ssa->ops[op_1].op2_use;
13171425

13181426
if ((opline->op2_type & (IS_TMP_VAR|IS_VAR))

0 commit comments

Comments
 (0)