Skip to content

Commit 3024d9c

Browse files
committed
Optimize out MAY_BE_LONG +/- 0 and MAY_BE_DOUBLE +/- 0.0
1 parent 92d0a10 commit 3024d9c

File tree

1 file changed

+163
-16
lines changed

1 file changed

+163
-16
lines changed

ext/opcache/Optimizer/dfa_pass.c

Lines changed: 163 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,29 +1091,68 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
10911091
|| opline->opcode == ZEND_IS_SMALLER_OR_EQUAL
10921092
) {
10931093

1094-
if (opline->op1_type == IS_CONST
1095-
&& opline->op2_type != IS_CONST
1096-
&& (OP2_INFO() & MAY_BE_ANY) == MAY_BE_DOUBLE
1097-
&& Z_TYPE_INFO_P(CT_CONSTANT_EX(op_array, opline->op1.constant)) == IS_LONG
1098-
) {
1094+
if (opline->op1_type == IS_CONST && opline->op2_type != IS_CONST) {
1095+
zval *zv = CT_CONSTANT_EX(op_array, opline->op1.constant);
1096+
1097+
if ((OP2_INFO() & MAY_BE_ANY) == MAY_BE_DOUBLE
1098+
&& Z_TYPE_INFO_P(zv) == IS_LONG) {
10991099

11001100
// op_1: #v.? = ADD long(?), #?.? [double] => #v.? = ADD double(?), #?.? [double]
11011101

1102-
zval *zv = CT_CONSTANT_EX(op_array, opline->op1.constant);
1103-
ZVAL_DOUBLE(&tmp, zval_get_double(zv));
1104-
opline->op1.constant = zend_optimizer_add_literal(op_array, &tmp);
1102+
ZVAL_DOUBLE(&tmp, zval_get_double(zv));
1103+
opline->op1.constant = zend_optimizer_add_literal(op_array, &tmp);
1104+
zv = CT_CONSTANT_EX(op_array, opline->op1.constant);
1105+
}
1106+
if (opline->opcode == ZEND_ADD) {
1107+
zv = CT_CONSTANT_EX(op_array, opline->op1.constant);
1108+
1109+
if (((OP2_INFO() & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG
1110+
&& Z_TYPE_INFO_P(zv) == IS_LONG
1111+
&& Z_LVAL_P(zv) == 0)
1112+
|| ((OP2_INFO() & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE
1113+
&& Z_TYPE_INFO_P(zv) == IS_DOUBLE
1114+
&& Z_DVAL_P(zv) == 0.0)) {
1115+
1116+
// op_1: #v.? = ADD 0, #?.? [double,long] => #v.? = QM_ASSIGN #?.?
1117+
1118+
opline->opcode = ZEND_QM_ASSIGN;
1119+
opline->op1_type = opline->op2_type;
1120+
opline->op1.var = opline->op2.var;
1121+
opline->op2_type = IS_UNUSED;
1122+
opline->op2.num = 0;
1123+
ssa->ops[op_1].op1_use = ssa->ops[op_1].op2_use;
1124+
ssa->ops[op_1].op1_use_chain = ssa->ops[op_1].op2_use_chain;
1125+
ssa->ops[op_1].op2_use = -1;
1126+
ssa->ops[op_1].op2_use_chain = -1;
1127+
}
1128+
}
1129+
} else if (opline->op1_type != IS_CONST && opline->op2_type == IS_CONST) {
1130+
zval *zv = CT_CONSTANT_EX(op_array, opline->op2.constant);
11051131

1106-
} else if (opline->op1_type != IS_CONST
1107-
&& opline->op2_type == IS_CONST
1108-
&& (OP1_INFO() & MAY_BE_ANY) == MAY_BE_DOUBLE
1109-
&& Z_TYPE_INFO_P(CT_CONSTANT_EX(op_array, opline->op2.constant)) == IS_LONG
1110-
) {
1132+
if ((OP1_INFO() & MAY_BE_ANY) == MAY_BE_DOUBLE
1133+
&& Z_TYPE_INFO_P(CT_CONSTANT_EX(op_array, opline->op2.constant)) == IS_LONG) {
11111134

11121135
// op_1: #v.? = ADD #?.? [double], long(?) => #v.? = ADD #?.? [double], double(?)
11131136

1114-
zval *zv = CT_CONSTANT_EX(op_array, opline->op2.constant);
1115-
ZVAL_DOUBLE(&tmp, zval_get_double(zv));
1116-
opline->op2.constant = zend_optimizer_add_literal(op_array, &tmp);
1137+
ZVAL_DOUBLE(&tmp, zval_get_double(zv));
1138+
opline->op2.constant = zend_optimizer_add_literal(op_array, &tmp);
1139+
zv = CT_CONSTANT_EX(op_array, opline->op2.constant);
1140+
}
1141+
if (opline->opcode == ZEND_ADD || opline->opcode == ZEND_SUB) {
1142+
if (((OP1_INFO() & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG
1143+
&& Z_TYPE_INFO_P(zv) == IS_LONG
1144+
&& Z_LVAL_P(zv) == 0)
1145+
|| ((OP1_INFO() & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE
1146+
&& Z_TYPE_INFO_P(zv) == IS_DOUBLE
1147+
&& Z_DVAL_P(zv) == 0.0)) {
1148+
1149+
// op_1: #v.? = ADD #?.? [double,long], 0 => #v.? = QM_ASSIGN #?.?
1150+
1151+
opline->opcode = ZEND_QM_ASSIGN;
1152+
opline->op2_type = IS_UNUSED;
1153+
opline->op2.num = 0;
1154+
}
1155+
}
11171156
}
11181157
} else if (opline->opcode == ZEND_CONCAT) {
11191158
if (!(OP1_INFO() & MAY_BE_OBJECT)
@@ -1151,6 +1190,114 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
11511190
}
11521191
}
11531192

1193+
if (opline->opcode == ZEND_QM_ASSIGN
1194+
&& ssa->ops[op_1].result_def == v
1195+
&& opline->op1_type & (IS_TMP_VAR|IS_VAR)
1196+
&& !(ssa->var_info[v].type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))
1197+
) {
1198+
1199+
int src_var = ssa->ops[op_1].op1_use;
1200+
1201+
if (src_var >= 0
1202+
&& !(ssa->var_info[src_var].type & MAY_BE_REF)
1203+
&& ssa->vars[src_var].definition >= 0
1204+
&& ssa->ops[ssa->vars[src_var].definition].result_def == src_var
1205+
&& ssa->ops[ssa->vars[src_var].definition].result_use < 0
1206+
&& ssa->vars[src_var].use_chain == op_1
1207+
&& ssa->ops[op_1].op1_use_chain < 0
1208+
&& !ssa->vars[src_var].phi_use_chain
1209+
&& !ssa->vars[src_var].sym_use_chain
1210+
&& opline_supports_assign_contraction(
1211+
ssa, &op_array->opcodes[ssa->vars[src_var].definition],
1212+
src_var, opline->result.var)
1213+
) {
1214+
1215+
int orig_var = ssa->ops[op_1].result_use;
1216+
int op_2 = ssa->vars[src_var].definition;
1217+
1218+
// op_2: #src_var.T = OP ... => #v.CV = OP ...
1219+
// op_1: QM_ASSIGN #src_var.T #orig_var.CV [undef,scalar] -> #v.CV, NOP
1220+
1221+
if (orig_var < 0 || zend_ssa_unlink_use_chain(ssa, op_1, orig_var)) {
1222+
/* Reconstruct SSA */
1223+
ssa->vars[v].definition = op_2;
1224+
ssa->ops[op_2].result_def = v;
1225+
1226+
ssa->vars[src_var].definition = -1;
1227+
ssa->vars[src_var].use_chain = -1;
1228+
1229+
ssa->ops[op_1].op1_use = -1;
1230+
ssa->ops[op_1].op1_def = -1;
1231+
ssa->ops[op_1].op1_use_chain = -1;
1232+
ssa->ops[op_1].result_use = -1;
1233+
ssa->ops[op_1].result_def = -1;
1234+
ssa->ops[op_1].res_use_chain = -1;
1235+
1236+
/* Update opcodes */
1237+
op_array->opcodes[op_2].result_type = opline->result_type;
1238+
op_array->opcodes[op_2].result.var = opline->result.var;
1239+
1240+
MAKE_NOP(opline);
1241+
remove_nops = 1;
1242+
1243+
if (op_array->opcodes[op_2].opcode == ZEND_SUB
1244+
&& op_array->opcodes[op_2].op1_type == op_array->opcodes[op_2].result_type
1245+
&& op_array->opcodes[op_2].op1.var == op_array->opcodes[op_2].result.var
1246+
&& op_array->opcodes[op_2].op2_type == IS_CONST
1247+
&& Z_TYPE_P(CT_CONSTANT_EX(op_array, op_array->opcodes[op_2].op2.constant)) == IS_LONG
1248+
&& Z_LVAL_P(CT_CONSTANT_EX(op_array, op_array->opcodes[op_2].op2.constant)) == 1
1249+
&& ssa->ops[op_2].op1_use >= 0
1250+
&& !(ssa->var_info[ssa->ops[op_2].op1_use].type & (MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
1251+
1252+
op_array->opcodes[op_2].opcode = ZEND_PRE_DEC;
1253+
SET_UNUSED(op_array->opcodes[op_2].op2);
1254+
SET_UNUSED(op_array->opcodes[op_2].result);
1255+
1256+
ssa->ops[op_2].result_def = -1;
1257+
ssa->ops[op_2].op1_def = v;
1258+
1259+
} else if (op_array->opcodes[op_2].opcode == ZEND_ADD
1260+
&& op_array->opcodes[op_2].op1_type == op_array->opcodes[op_2].result_type
1261+
&& op_array->opcodes[op_2].op1.var == op_array->opcodes[op_2].result.var
1262+
&& op_array->opcodes[op_2].op2_type == IS_CONST
1263+
&& Z_TYPE_P(CT_CONSTANT_EX(op_array, op_array->opcodes[op_2].op2.constant)) == IS_LONG
1264+
&& Z_LVAL_P(CT_CONSTANT_EX(op_array, op_array->opcodes[op_2].op2.constant)) == 1
1265+
&& ssa->ops[op_2].op1_use >= 0
1266+
&& !(ssa->var_info[ssa->ops[op_2].op1_use].type & (MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
1267+
1268+
op_array->opcodes[op_2].opcode = ZEND_PRE_INC;
1269+
SET_UNUSED(op_array->opcodes[op_2].op2);
1270+
SET_UNUSED(op_array->opcodes[op_2].result);
1271+
1272+
ssa->ops[op_2].result_def = -1;
1273+
ssa->ops[op_2].op1_def = v;
1274+
1275+
} else if (op_array->opcodes[op_2].opcode == ZEND_ADD
1276+
&& op_array->opcodes[op_2].op2_type == op_array->opcodes[op_2].result_type
1277+
&& op_array->opcodes[op_2].op2.var == op_array->opcodes[op_2].result.var
1278+
&& op_array->opcodes[op_2].op1_type == IS_CONST
1279+
&& Z_TYPE_P(CT_CONSTANT_EX(op_array, op_array->opcodes[op_2].op1.constant)) == IS_LONG
1280+
&& Z_LVAL_P(CT_CONSTANT_EX(op_array, op_array->opcodes[op_2].op1.constant)) == 1
1281+
&& ssa->ops[op_2].op2_use >= 0
1282+
&& !(ssa->var_info[ssa->ops[op_2].op2_use].type & (MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
1283+
1284+
op_array->opcodes[op_2].opcode = ZEND_PRE_INC;
1285+
op_array->opcodes[op_2].op1_type = op_array->opcodes[op_2].op2_type;
1286+
op_array->opcodes[op_2].op1.var = op_array->opcodes[op_2].op2.var;
1287+
SET_UNUSED(op_array->opcodes[op_2].op2);
1288+
SET_UNUSED(op_array->opcodes[op_2].result);
1289+
1290+
ssa->ops[op_2].result_def = -1;
1291+
ssa->ops[op_2].op1_def = v;
1292+
ssa->ops[op_2].op1_use = ssa->ops[op_2].op2_use;
1293+
ssa->ops[op_2].op1_use_chain = ssa->ops[op_2].op2_use_chain;
1294+
ssa->ops[op_2].op2_use = -1;
1295+
ssa->ops[op_2].op2_use_chain = -1;
1296+
}
1297+
}
1298+
}
1299+
}
1300+
11541301
if (ssa->vars[v].var >= op_array->last_var) {
11551302
/* skip TMP and VAR */
11561303
continue;

0 commit comments

Comments
 (0)