Merge branch 'PHP-8.0'

* PHP-8.0:
  Eliminate redundand comparison insructions
This commit is contained in:
Dmitry Stogov 2020-12-24 16:59:27 +03:00
commit 14b5fff632
3 changed files with 117 additions and 14 deletions

View File

@ -2842,7 +2842,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
res_addr,
zend_may_throw(opline, ssa_op, op_array, ssa),
smart_branch_opcode, target_label, target_label2,
NULL)) {
NULL, 0)) {
goto jit_failure;
}
goto done;
@ -2871,7 +2871,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
RES_REG_ADDR(),
zend_may_throw(opline, ssa_op, op_array, ssa),
smart_branch_opcode, target_label, target_label2,
NULL)) {
NULL, 0)) {
goto jit_failure;
}
goto done;

View File

@ -3431,6 +3431,89 @@ static void zend_jit_trace_update_condition_ranges(const zend_op *opline, const
}
}
static zend_bool zend_jit_may_skip_comparison(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_ssa *ssa, const zend_op **ssa_opcodes)
{
zend_uchar prev_opcode;
if (opline->op1_type == IS_CONST
&& Z_TYPE_P(RT_CONSTANT(opline, opline->op1)) == IS_LONG
&& Z_LVAL_P(RT_CONSTANT(opline, opline->op1)) == 0) {
if (ssa_op->op2_use >= 0) {
if ((ssa_op-1)->op1_def == ssa_op->op2_use) {
prev_opcode = ssa_opcodes[(ssa_op - ssa->ops) - 1]->opcode;
if (prev_opcode == ZEND_PRE_INC
|| prev_opcode == ZEND_PRE_DEC
|| prev_opcode == ZEND_POST_INC
|| prev_opcode == ZEND_POST_DEC) {
return 1;
}
} else if ((ssa_op-1)->result_def == ssa_op->op2_use) {
prev_opcode = ssa_opcodes[(ssa_op - ssa->ops) - 1]->opcode;
if (prev_opcode == ZEND_ADD
|| prev_opcode == ZEND_SUB) {
return 1;
}
}
}
} else if (opline->op2_type == IS_CONST
&& Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG
&& Z_LVAL_P(RT_CONSTANT(opline, opline->op2)) == 0) {
if (ssa_op->op1_use >= 0) {
if ((ssa_op-1)->op1_def == ssa_op->op1_use) {
prev_opcode = ssa_opcodes[(ssa_op - ssa->ops) - 1]->opcode;
if (prev_opcode == ZEND_PRE_INC
|| prev_opcode == ZEND_PRE_DEC
|| prev_opcode == ZEND_POST_INC
|| prev_opcode == ZEND_POST_DEC) {
return 1;
}
} else if ((ssa_op-1)->result_def == ssa_op->op1_use) {
prev_opcode = ssa_opcodes[(ssa_op - ssa->ops) - 1]->opcode;
if (prev_opcode == ZEND_ADD
|| prev_opcode == ZEND_SUB) {
return 1;
}
}
}
} else {
const zend_ssa_op *prev_ssa_op = ssa_op - 1;
prev_opcode = ssa_opcodes[prev_ssa_op - ssa->ops]->opcode;
if ((prev_opcode == ZEND_JMPZ || prev_opcode == ZEND_JMPNZ)
&& prev_ssa_op != ssa->ops
&& prev_ssa_op->op1_use >= 0
&& prev_ssa_op->op1_use == (prev_ssa_op-1)->result_def) {
prev_ssa_op--;
prev_opcode = ssa_opcodes[prev_ssa_op - ssa->ops]->opcode;
}
if (ssa_op->op1_use == prev_ssa_op->op1_use
&& ssa_op->op2_use == prev_ssa_op->op2_use) {
if (prev_opcode == ZEND_IS_EQUAL
|| prev_opcode == ZEND_IS_NOT_EQUAL
|| prev_opcode == ZEND_IS_SMALLER
|| prev_opcode == ZEND_IS_SMALLER_OR_EQUAL
|| prev_opcode == ZEND_CASE
|| prev_opcode == ZEND_IS_IDENTICAL
|| prev_opcode == ZEND_IS_NOT_IDENTICAL
|| prev_opcode == ZEND_CASE_STRICT) {
if (ssa_op->op1_use < 0) {
if (opline->op1.constant != ssa_opcodes[prev_ssa_op - ssa->ops]->op1.constant) {
return 0;
}
}
if (ssa_op->op2_use < 0) {
if (opline->op2.constant != ssa_opcodes[prev_ssa_op - ssa->ops]->op2.constant) {
return 0;
}
}
return 1;
}
}
}
return 0;
}
static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t parent_trace, uint32_t exit_num)
{
const void *handler = NULL;
@ -3451,6 +3534,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
const void *exit_addr;
uint32_t op1_info, op1_def_info, op2_info, res_info, res_use_info, op1_data_info;
zend_bool send_result = 0;
zend_bool skip_comparison;
zend_jit_addr op1_addr, op1_def_addr, op2_addr, op2_def_addr, res_addr;
zend_class_entry *ce;
zend_bool ce_is_instanceof;
@ -4675,8 +4759,13 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
case ZEND_IS_SMALLER_OR_EQUAL:
case ZEND_CASE:
op1_info = OP1_INFO();
CHECK_OP1_TRACE_TYPE();
op2_info = OP2_INFO();
skip_comparison =
ssa_op != ssa->ops &&
(op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
zend_jit_may_skip_comparison(opline, ssa_op, ssa, ssa_opcodes);
CHECK_OP1_TRACE_TYPE();
CHECK_OP2_TRACE_TYPE();
if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
zend_bool exit_if_true = 0;
@ -4697,7 +4786,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
op2_info, OP2_RANGE(), OP2_REG_ADDR(),
RES_REG_ADDR(),
zend_may_throw(opline, ssa_op, op_array, ssa),
smart_branch_opcode, -1, -1, exit_addr)) {
smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
goto jit_failure;
}
zend_jit_trace_update_condition_ranges(opline, ssa_op, op_array, ssa, exit_if_true);
@ -4709,7 +4798,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
op2_info, OP2_RANGE(), OP2_REG_ADDR(),
RES_REG_ADDR(),
zend_may_throw(opline, ssa_op, op_array, ssa),
smart_branch_opcode, -1, -1, exit_addr)) {
smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
goto jit_failure;
}
}
@ -4718,8 +4807,13 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
case ZEND_IS_NOT_IDENTICAL:
case ZEND_CASE_STRICT:
op1_info = OP1_INFO();
CHECK_OP1_TRACE_TYPE();
op2_info = OP2_INFO();
skip_comparison =
ssa_op != ssa->ops &&
(op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
zend_jit_may_skip_comparison(opline, ssa_op, ssa, ssa_opcodes);
CHECK_OP1_TRACE_TYPE();
CHECK_OP2_TRACE_TYPE();
if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
zend_bool exit_if_true = 0;
@ -4743,7 +4837,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
op2_info, OP2_RANGE(), OP2_REG_ADDR(),
RES_REG_ADDR(),
zend_may_throw(opline, ssa_op, op_array, ssa),
smart_branch_opcode, -1, -1, exit_addr)) {
smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
goto jit_failure;
}
zend_jit_trace_update_condition_ranges(opline, ssa_op, op_array, ssa, exit_if_true);
@ -4755,7 +4849,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
op2_info, OP2_RANGE(), OP2_REG_ADDR(),
RES_REG_ADDR(),
zend_may_throw(opline, ssa_op, op_array, ssa),
smart_branch_opcode, -1, -1, exit_addr)) {
smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
goto jit_failure;
}
}

View File

@ -6745,7 +6745,8 @@ static int zend_jit_cmp_long_long(dasm_State **Dst,
zend_uchar smart_branch_opcode,
uint32_t target_label,
uint32_t target_label2,
const void *exit_addr)
const void *exit_addr,
zend_bool skip_comparison)
{
zend_bool swap = 0;
zend_bool result;
@ -6780,7 +6781,13 @@ static int zend_jit_cmp_long_long(dasm_State **Dst,
return 1;
}
if (Z_MODE(op1_addr) == IS_REG) {
if (skip_comparison) {
if (Z_MODE(op1_addr) != IS_REG &&
(Z_MODE(op2_addr) == IS_REG ||
(Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) != IS_CONST_ZVAL))) {
swap = 1;
}
} else if (Z_MODE(op1_addr) == IS_REG) {
if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 0) {
| test Ra(Z_REG(op1_addr)), Ra(Z_REG(op1_addr))
} else {
@ -7567,7 +7574,8 @@ static int zend_jit_cmp(dasm_State **Dst,
zend_uchar smart_branch_opcode,
uint32_t target_label,
uint32_t target_label2,
const void *exit_addr)
const void *exit_addr,
zend_bool skip_comparison)
{
zend_bool same_ops = (opline->op1_type == opline->op2_type) && (opline->op1.var == opline->op2.var);
zend_bool has_slow;
@ -7603,7 +7611,7 @@ static int zend_jit_cmp(dasm_State **Dst,
| IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >9
}
}
if (!zend_jit_cmp_long_long(Dst, opline, op1_range, op1_addr, op2_range, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
if (!zend_jit_cmp_long_long(Dst, opline, op1_range, op1_addr, op2_range, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr, skip_comparison)) {
return 0;
}
if (op1_info & MAY_BE_DOUBLE) {
@ -7805,7 +7813,8 @@ static int zend_jit_identical(dasm_State **Dst,
zend_uchar smart_branch_opcode,
uint32_t target_label,
uint32_t target_label2,
const void *exit_addr)
const void *exit_addr,
zend_bool skip_comparison)
{
uint32_t identical_label = (uint32_t)-1;
uint32_t not_identical_label = (uint32_t)-1;
@ -7838,7 +7847,7 @@ static int zend_jit_identical(dasm_State **Dst,
if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
(op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) {
if (!zend_jit_cmp_long_long(Dst, opline, op1_range, op1_addr, op2_range, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
if (!zend_jit_cmp_long_long(Dst, opline, op1_range, op1_addr, op2_range, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr, skip_comparison)) {
return 0;
}
return 1;