From: Dmitry Stogov Date: Tue, 23 Apr 2019 21:08:17 +0000 (+0300) Subject: Optimize constant SWITCH_LONG and SWITCH_STRING X-Git-Tag: php-7.4.0alpha1~424 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=db2ffcf1579fee9cb048cc806adf782e659cc456;p=php Optimize constant SWITCH_LONG and SWITCH_STRING --- diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c index 58f5f50085..7cffa45ddb 100644 --- a/ext/opcache/Optimizer/dfa_pass.c +++ b/ext/opcache/Optimizer/dfa_pass.c @@ -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); diff --git a/ext/opcache/Optimizer/sccp.c b/ext/opcache/Optimizer/sccp.c index 9358afdf0c..5f9f79b018 100644 --- a/ext/opcache/Optimizer/sccp.c +++ b/ext/opcache/Optimizer/sccp.c @@ -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]);