@@ -1091,29 +1091,68 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
1091
1091
|| opline -> opcode == ZEND_IS_SMALLER_OR_EQUAL
1092
1092
) {
1093
1093
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 ) {
1099
1099
1100
1100
// op_1: #v.? = ADD long(?), #?.? [double] => #v.? = ADD double(?), #?.? [double]
1101
1101
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 );
1105
1131
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 ) {
1111
1134
1112
1135
// op_1: #v.? = ADD #?.? [double], long(?) => #v.? = ADD #?.? [double], double(?)
1113
1136
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
+ }
1117
1156
}
1118
1157
} else if (opline -> opcode == ZEND_CONCAT ) {
1119
1158
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
1151
1190
}
1152
1191
}
1153
1192
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
+
1154
1301
if (ssa -> vars [v ].var >= op_array -> last_var ) {
1155
1302
/* skip TMP and VAR */
1156
1303
continue ;
0 commit comments