@@ -1186,10 +1186,13 @@ static zval *value_from_type_and_range(sccp_ctx *ctx, int var_num, zval *tmp) {
1186
1186
* if they have a certain type. */
1187
1187
static void replace_constant_operands (sccp_ctx * ctx ) {
1188
1188
zend_ssa * ssa = ctx -> ssa ;
1189
+ zend_op_array * op_array = ctx -> op_array ;
1189
1190
int i ;
1190
1191
zval tmp ;
1191
1192
1192
- for (i = 0 ; i < ssa -> vars_count ; i ++ ) {
1193
+ /* We iterate the variables backwards, so we can eliminate sequences like INIT_ROPE
1194
+ * and INIT_ARRAY. */
1195
+ for (i = ssa -> vars_count - 1 ; i >= 0 ; i -- ) {
1193
1196
zend_ssa_var * var = & ssa -> vars [i ];
1194
1197
zval * value ;
1195
1198
int use ;
@@ -1204,7 +1207,7 @@ static void replace_constant_operands(sccp_ctx *ctx) {
1204
1207
}
1205
1208
1206
1209
FOREACH_USE (var , use ) {
1207
- zend_op * opline = & ctx -> op_array -> opcodes [use ];
1210
+ zend_op * opline = & op_array -> opcodes [use ];
1208
1211
zend_ssa_op * ssa_op = & ssa -> ops [use ];
1209
1212
if (try_replace_op1 (ctx , opline , ssa_op , i , value )) {
1210
1213
ZEND_ASSERT (ssa_op -> op1_def == -1 );
@@ -1223,42 +1226,32 @@ static void replace_constant_operands(sccp_ctx *ctx) {
1223
1226
ssa_op -> op2_use_chain = -1 ;
1224
1227
}
1225
1228
} FOREACH_USE_END ();
1226
- }
1227
- }
1228
-
1229
- /* This is a basic DCE pass we run after SCCP. It only works on those instructions those result
1230
- * value(s) were determined by SCCP. It removes dead computational instructions and converts
1231
- * CV-affecting instructions into CONST ASSIGNs. This basic DCE is performed for multiple reasons:
1232
- * a) During operand replacement we eliminate FREEs. The corresponding computational instructions
1233
- * must be removed to avoid leaks. This way SCCP can run independently of the full DCE pass.
1234
- * b) The main DCE pass relies on type analysis to determine whether instructions have side-effects
1235
- * and can't be DCEd. This means that it will not be able collect all instructions rendered dead
1236
- * by SCCP, because they may have potentially side-effecting types, but the actual values are
1237
- * not. As such doing DCE here will allow us to eliminate more dead code in combination.
1238
- * c) The ordinary DCE pass cannot collect dead calls. However SCCP can result in dead calls, which
1239
- * we need to collect. */
1240
- static void eliminate_dead_instructions (sccp_ctx * ctx ) {
1241
- zend_ssa * ssa = ctx -> ssa ;
1242
- zend_op_array * op_array = ctx -> op_array ;
1243
- int i ;
1244
1229
1245
- /* We iterate the variables backwards, so we can eliminate sequences like INIT_ROPE
1246
- * and INIT_ARRAY. */
1247
- for (i = ssa -> vars_count - 1 ; i >= 0 ; i -- ) {
1248
- zend_ssa_var * var = & ssa -> vars [i ];
1249
- if (value_known (& ctx -> values [i ]) && var -> definition >= 0 ) {
1230
+ /* This is a basic DCE pass we run after SCCP. It only works on those instructions those result
1231
+ * value(s) were determined by SCCP. It removes dead computational instructions and converts
1232
+ * CV-affecting instructions into CONST ASSIGNs. This basic DCE is performed for multiple reasons:
1233
+ * a) During operand replacement we eliminate FREEs. The corresponding computational instructions
1234
+ * must be removed to avoid leaks. This way SCCP can run independently of the full DCE pass.
1235
+ * b) The main DCE pass relies on type analysis to determine whether instructions have side-effects
1236
+ * and can't be DCEd. This means that it will not be able collect all instructions rendered dead
1237
+ * by SCCP, because they may have potentially side-effecting types, but the actual values are
1238
+ * not. As such doing DCE here will allow us to eliminate more dead code in combination.
1239
+ * c) The ordinary DCE pass cannot collect dead calls. However SCCP can result in dead calls, which
1240
+ * we need to collect. */
1241
+
1242
+ if (var -> definition >= 0 && value_known (& ctx -> values [i ])) {
1250
1243
zend_op * opline = & op_array -> opcodes [var -> definition ];
1251
1244
zend_ssa_op * ssa_op = & ssa -> ops [var -> definition ];
1252
1245
if (opline -> opcode == ZEND_ASSIGN ) {
1253
1246
/* Leave assigns to DCE (due to dtor effects) */
1254
1247
continue ;
1255
1248
}
1256
1249
1257
- if (ssa_op -> result_def >= 0
1250
+ if (ssa_op -> result_def == i
1258
1251
&& ssa_op -> op1_def < 0
1259
1252
&& ssa_op -> op2_def < 0
1260
- && ssa -> vars [ ssa_op -> result_def ]. use_chain < 0
1261
- && ssa -> vars [ ssa_op -> result_def ]. phi_use_chain == NULL ) {
1253
+ && var -> use_chain < 0
1254
+ && var -> phi_use_chain == NULL ) {
1262
1255
if (opline -> opcode == ZEND_DO_ICALL ) {
1263
1256
/* Call instruction -> remove opcodes that are part of the call */
1264
1257
zend_call_info * call = ctx -> call_map [var -> definition ];
@@ -1278,10 +1271,8 @@ static void eliminate_dead_instructions(sccp_ctx *ctx) {
1278
1271
zend_ssa_remove_result_def (ssa , ssa_op );
1279
1272
zend_ssa_remove_instr (ssa , opline , ssa_op );
1280
1273
}
1281
- } else if (ssa_op -> op1_def >= 0 ) {
1274
+ } else if (ssa_op -> op1_def == i ) {
1282
1275
/* Compound assign or incdec -> convert to direct ASSIGN */
1283
- zval * val = & ctx -> values [ssa_op -> op1_def ];
1284
- ZEND_ASSERT (value_known (val ));
1285
1276
1286
1277
/* Destroy previous op2 */
1287
1278
if (opline -> op2_type == IS_CONST ) {
@@ -1308,8 +1299,8 @@ static void eliminate_dead_instructions(sccp_ctx *ctx) {
1308
1299
/* Convert to ASSIGN */
1309
1300
opline -> opcode = ZEND_ASSIGN ;
1310
1301
opline -> op2_type = IS_CONST ;
1311
- opline -> op2 .constant = zend_optimizer_add_literal (op_array , val );
1312
- Z_TRY_ADDREF_P (val );
1302
+ opline -> op2 .constant = zend_optimizer_add_literal (op_array , value );
1303
+ Z_TRY_ADDREF_P (value );
1313
1304
}
1314
1305
}
1315
1306
/*if (var->definition_phi
@@ -1354,17 +1345,6 @@ static void sccp_context_free(sccp_ctx *ctx) {
1354
1345
efree (ctx -> values );
1355
1346
}
1356
1347
1357
- static void sccp_apply_results (sccp_ctx * ctx ) {
1358
- replace_constant_operands (ctx );
1359
- #if 0
1360
- zend_dump_op_array (ctx -> op_array , ZEND_DUMP_SSA , "SCCP-1" , ctx -> ssa );
1361
- #endif
1362
- eliminate_dead_instructions (ctx );
1363
- #if 0
1364
- zend_dump_op_array (ctx -> op_array , ZEND_DUMP_SSA , "SCCP-2" , ctx -> ssa );
1365
- #endif
1366
- }
1367
-
1368
1348
void sccp_optimize_op_array (zend_op_array * op_array , zend_ssa * ssa , zend_call_info * * call_map )
1369
1349
{
1370
1350
scdf_ctx scdf ;
@@ -1380,7 +1360,7 @@ void sccp_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, zend_call_in
1380
1360
scdf_solve (& scdf , "SCCP" );
1381
1361
1382
1362
scdf_remove_unreachable_blocks (& scdf );
1383
- sccp_apply_results (& ctx );
1363
+ replace_constant_operands (& ctx );
1384
1364
1385
1365
scdf_free (& scdf );
1386
1366
sccp_context_free (& ctx );
0 commit comments