@@ -985,6 +985,77 @@ static int zend_dfa_optimize_jmps(zend_op_array *op_array, zend_ssa *ssa)
985
985
return removed_ops ;
986
986
}
987
987
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
+
988
1059
void zend_dfa_optimize_op_array (zend_op_array * op_array , zend_optimizer_ctx * ctx , zend_ssa * ssa , zend_call_info * * call_map )
989
1060
{
990
1061
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
1303
1374
continue ;
1304
1375
}
1305
1376
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
+
1306
1415
if (opline -> opcode == ZEND_ASSIGN
1307
1416
&& ssa -> ops [op_1 ].op1_def == v
1308
1417
&& !RETURN_VALUE_USED (opline )
@@ -1312,7 +1421,6 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
1312
1421
if (orig_var >= 0
1313
1422
&& !(ssa -> var_info [orig_var ].type & (MAY_BE_STRING |MAY_BE_ARRAY |MAY_BE_OBJECT |MAY_BE_RESOURCE |MAY_BE_REF ))
1314
1423
) {
1315
-
1316
1424
int src_var = ssa -> ops [op_1 ].op2_use ;
1317
1425
1318
1426
if ((opline -> op2_type & (IS_TMP_VAR |IS_VAR ))
0 commit comments