]> granicus.if.org Git - php/commitdiff
Optimize constant SWITCH_LONG and SWITCH_STRING
authorDmitry Stogov <dmitry@zend.com>
Tue, 23 Apr 2019 21:08:17 +0000 (00:08 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 23 Apr 2019 21:08:17 +0000 (00:08 +0300)
ext/opcache/Optimizer/dfa_pass.c
ext/opcache/Optimizer/sccp.c

index 58f5f500856e29dbe6ead6b1aa75f3142802260b..7cffa45ddbcfa4bcbf7adf7b4f5e39d03b65f5a8 100644 (file)
@@ -490,6 +490,19 @@ static zend_always_inline void take_successor_1(zend_ssa *ssa, int block_num, ze
        }
 }
 
+static zend_always_inline void take_successor_ex(zend_ssa *ssa, int block_num, zend_basic_block *block, int target_block)
+{
+       int i;
+
+       for (i = 0; i < block->successors_count; i++) {
+               if (block->successors[i] != target_block) {
+                       zend_ssa_remove_predecessor(ssa, block_num, block->successors[i]);
+               }
+       }
+       block->successors[0] = target_block;
+       block->successors_count = 1;
+}
+
 static void compress_block(zend_op_array *op_array, zend_basic_block *block)
 {
        while (block->len > 0) {
@@ -857,6 +870,64 @@ optimize_jmpnz:
                                        }
                                        break;
                                }
+                               case ZEND_SWITCH_LONG:
+                                       if (opline->op1_type == IS_CONST) {
+                                               zval *zv = CT_CONSTANT_EX(op_array, opline->op1.constant);
+                                               if (Z_TYPE_P(zv) != IS_LONG) {
+                                                       removed_ops++;
+                                                       MAKE_NOP(opline);
+                                                       opline->extended_value = 0;
+                                                       take_successor_ex(ssa, block_num, block, block->successors[0]);
+                                                       goto optimize_nop;
+                                               } else {
+                                                       HashTable *jmptable = Z_ARRVAL_P(CT_CONSTANT_EX(op_array, opline->op2.constant));
+                                                       zval *jmp_zv = zend_hash_index_find(jmptable, Z_LVAL_P(zv));
+                                                       uint32_t target;
+
+                                                       if (jmp_zv) {
+                                                               target = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(jmp_zv));
+                                                       } else {
+                                                               target = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value);
+                                                       }
+                                                       opline->opcode = ZEND_JMP;
+                                                       opline->extended_value = 0;
+                                                       SET_UNUSED(opline->op1);
+                                                       ZEND_SET_OP_JMP_ADDR(opline, opline->op1, op_array->opcodes + target);
+                                                       SET_UNUSED(opline->op2);
+                                                       take_successor_ex(ssa, block_num, block, ssa->cfg.map[target]);
+                                                       goto optimize_jmp;
+                                               }
+                                       }
+                                       break;
+                               case ZEND_SWITCH_STRING:
+                                       if (opline->op1_type == IS_CONST) {
+                                               zval *zv = CT_CONSTANT_EX(op_array, opline->op1.constant);
+                                               if (Z_TYPE_P(zv) != IS_STRING) {
+                                                       removed_ops++;
+                                                       MAKE_NOP(opline);
+                                                       opline->extended_value = 0;
+                                                       take_successor_ex(ssa, block_num, block, block->successors[0]);
+                                                       goto optimize_nop;
+                                               } else {
+                                                       HashTable *jmptable = Z_ARRVAL_P(CT_CONSTANT_EX(op_array, opline->op2.constant));
+                                                       zval *jmp_zv = zend_hash_find(jmptable, Z_STR_P(zv));
+                                                       uint32_t target;
+
+                                                       if (jmp_zv) {
+                                                               target = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(jmp_zv));
+                                                       } else {
+                                                               target = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value);
+                                                       }
+                                                       opline->opcode = ZEND_JMP;
+                                                       opline->extended_value = 0;
+                                                       SET_UNUSED(opline->op1);
+                                                       ZEND_SET_OP_JMP_ADDR(opline, opline->op1, op_array->opcodes + target);
+                                                       SET_UNUSED(opline->op2);
+                                                       take_successor_ex(ssa, block_num, block, ssa->cfg.map[target]);
+                                                       goto optimize_jmp;
+                                               }
+                                       }
+                                       break;
                                case ZEND_NOP:
 optimize_nop:
                                        compress_block(op_array, block);
index 9358afdf0c3729d28428fefb161bb194b11276c6..5f9f79b0186581ce9954e77a351be67dd4b0f438 100644 (file)
@@ -1884,6 +1884,42 @@ static void sccp_mark_feasible_successors(
                        }
                        s = zend_hash_num_elements(Z_ARR_P(op1)) != 0;
                        break;
+               case ZEND_SWITCH_LONG:
+                       if (Z_TYPE_P(op1) == IS_LONG) {
+                               zend_op_array *op_array = scdf->op_array;
+                               zend_ssa *ssa = scdf->ssa;
+                               HashTable *jmptable = Z_ARRVAL_P(CT_CONSTANT_EX(op_array, opline->op2.constant));
+                               zval *jmp_zv = zend_hash_index_find(jmptable, Z_LVAL_P(op1));
+                               int target;
+
+                               if (jmp_zv) {
+                                       target = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(jmp_zv))];
+                               } else {
+                                       target = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
+                               }
+                               scdf_mark_edge_feasible(scdf, block_num, target);
+                               return;
+                       }
+                       s = 0;
+                       break;
+               case ZEND_SWITCH_STRING:
+                       if (Z_TYPE_P(op1) == IS_STRING) {
+                               zend_op_array *op_array = scdf->op_array;
+                               zend_ssa *ssa = scdf->ssa;
+                               HashTable *jmptable = Z_ARRVAL_P(CT_CONSTANT_EX(op_array, opline->op2.constant));
+                               zval *jmp_zv = zend_hash_find(jmptable, Z_STR_P(op1));
+                               int target;
+
+                               if (jmp_zv) {
+                                       target = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(jmp_zv))];
+                               } else {
+                                       target = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
+                               }
+                               scdf_mark_edge_feasible(scdf, block_num, target);
+                               return;
+                       }
+                       s = 0;
+                       break;
                default:
                        for (s = 0; s < block->successors_count; s++) {
                                scdf_mark_edge_feasible(scdf, block_num, block->successors[s]);