Skip to content

Commit 23bbff2

Browse files
committed
Eliminate redundand comparison insructions
1 parent ab4c597 commit 23bbff2

File tree

3 files changed

+117
-14
lines changed

3 files changed

+117
-14
lines changed

ext/opcache/jit/zend_jit.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2842,7 +2842,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
28422842
res_addr,
28432843
zend_may_throw(opline, ssa_op, op_array, ssa),
28442844
smart_branch_opcode, target_label, target_label2,
2845-
NULL)) {
2845+
NULL, 0)) {
28462846
goto jit_failure;
28472847
}
28482848
goto done;
@@ -2871,7 +2871,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
28712871
RES_REG_ADDR(),
28722872
zend_may_throw(opline, ssa_op, op_array, ssa),
28732873
smart_branch_opcode, target_label, target_label2,
2874-
NULL)) {
2874+
NULL, 0)) {
28752875
goto jit_failure;
28762876
}
28772877
goto done;

ext/opcache/jit/zend_jit_trace.c

Lines changed: 100 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3431,6 +3431,89 @@ static void zend_jit_trace_update_condition_ranges(const zend_op *opline, const
34313431
}
34323432
}
34333433

3434+
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)
3435+
{
3436+
zend_uchar prev_opcode;
3437+
3438+
if (opline->op1_type == IS_CONST
3439+
&& Z_TYPE_P(RT_CONSTANT(opline, opline->op1)) == IS_LONG
3440+
&& Z_LVAL_P(RT_CONSTANT(opline, opline->op1)) == 0) {
3441+
if (ssa_op->op2_use >= 0) {
3442+
if ((ssa_op-1)->op1_def == ssa_op->op2_use) {
3443+
prev_opcode = ssa_opcodes[(ssa_op - ssa->ops) - 1]->opcode;
3444+
if (prev_opcode == ZEND_PRE_INC
3445+
|| prev_opcode == ZEND_PRE_DEC
3446+
|| prev_opcode == ZEND_POST_INC
3447+
|| prev_opcode == ZEND_POST_DEC) {
3448+
return 1;
3449+
}
3450+
} else if ((ssa_op-1)->result_def == ssa_op->op2_use) {
3451+
prev_opcode = ssa_opcodes[(ssa_op - ssa->ops) - 1]->opcode;
3452+
if (prev_opcode == ZEND_ADD
3453+
|| prev_opcode == ZEND_SUB) {
3454+
return 1;
3455+
}
3456+
}
3457+
}
3458+
} else if (opline->op2_type == IS_CONST
3459+
&& Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG
3460+
&& Z_LVAL_P(RT_CONSTANT(opline, opline->op2)) == 0) {
3461+
if (ssa_op->op1_use >= 0) {
3462+
if ((ssa_op-1)->op1_def == ssa_op->op1_use) {
3463+
prev_opcode = ssa_opcodes[(ssa_op - ssa->ops) - 1]->opcode;
3464+
if (prev_opcode == ZEND_PRE_INC
3465+
|| prev_opcode == ZEND_PRE_DEC
3466+
|| prev_opcode == ZEND_POST_INC
3467+
|| prev_opcode == ZEND_POST_DEC) {
3468+
return 1;
3469+
}
3470+
} else if ((ssa_op-1)->result_def == ssa_op->op1_use) {
3471+
prev_opcode = ssa_opcodes[(ssa_op - ssa->ops) - 1]->opcode;
3472+
if (prev_opcode == ZEND_ADD
3473+
|| prev_opcode == ZEND_SUB) {
3474+
return 1;
3475+
}
3476+
}
3477+
}
3478+
} else {
3479+
const zend_ssa_op *prev_ssa_op = ssa_op - 1;
3480+
prev_opcode = ssa_opcodes[prev_ssa_op - ssa->ops]->opcode;
3481+
3482+
if ((prev_opcode == ZEND_JMPZ || prev_opcode == ZEND_JMPNZ)
3483+
&& prev_ssa_op != ssa->ops
3484+
&& prev_ssa_op->op1_use >= 0
3485+
&& prev_ssa_op->op1_use == (prev_ssa_op-1)->result_def) {
3486+
prev_ssa_op--;
3487+
prev_opcode = ssa_opcodes[prev_ssa_op - ssa->ops]->opcode;
3488+
}
3489+
3490+
if (ssa_op->op1_use == prev_ssa_op->op1_use
3491+
&& ssa_op->op2_use == prev_ssa_op->op2_use) {
3492+
if (prev_opcode == ZEND_IS_EQUAL
3493+
|| prev_opcode == ZEND_IS_NOT_EQUAL
3494+
|| prev_opcode == ZEND_IS_SMALLER
3495+
|| prev_opcode == ZEND_IS_SMALLER_OR_EQUAL
3496+
|| prev_opcode == ZEND_CASE
3497+
|| prev_opcode == ZEND_IS_IDENTICAL
3498+
|| prev_opcode == ZEND_IS_NOT_IDENTICAL
3499+
|| prev_opcode == ZEND_CASE_STRICT) {
3500+
if (ssa_op->op1_use < 0) {
3501+
if (opline->op1.constant != ssa_opcodes[prev_ssa_op - ssa->ops]->op1.constant) {
3502+
return 0;
3503+
}
3504+
}
3505+
if (ssa_op->op2_use < 0) {
3506+
if (opline->op2.constant != ssa_opcodes[prev_ssa_op - ssa->ops]->op2.constant) {
3507+
return 0;
3508+
}
3509+
}
3510+
return 1;
3511+
}
3512+
}
3513+
}
3514+
return 0;
3515+
}
3516+
34343517
static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t parent_trace, uint32_t exit_num)
34353518
{
34363519
const void *handler = NULL;
@@ -3451,6 +3534,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
34513534
const void *exit_addr;
34523535
uint32_t op1_info, op1_def_info, op2_info, res_info, res_use_info, op1_data_info;
34533536
zend_bool send_result = 0;
3537+
zend_bool skip_comparison;
34543538
zend_jit_addr op1_addr, op1_def_addr, op2_addr, op2_def_addr, res_addr;
34553539
zend_class_entry *ce;
34563540
zend_bool ce_is_instanceof;
@@ -4675,8 +4759,13 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
46754759
case ZEND_IS_SMALLER_OR_EQUAL:
46764760
case ZEND_CASE:
46774761
op1_info = OP1_INFO();
4678-
CHECK_OP1_TRACE_TYPE();
46794762
op2_info = OP2_INFO();
4763+
skip_comparison =
4764+
ssa_op != ssa->ops &&
4765+
(op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
4766+
(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
4767+
zend_jit_may_skip_comparison(opline, ssa_op, ssa, ssa_opcodes);
4768+
CHECK_OP1_TRACE_TYPE();
46804769
CHECK_OP2_TRACE_TYPE();
46814770
if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
46824771
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
46974786
op2_info, OP2_RANGE(), OP2_REG_ADDR(),
46984787
RES_REG_ADDR(),
46994788
zend_may_throw(opline, ssa_op, op_array, ssa),
4700-
smart_branch_opcode, -1, -1, exit_addr)) {
4789+
smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
47014790
goto jit_failure;
47024791
}
47034792
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
47094798
op2_info, OP2_RANGE(), OP2_REG_ADDR(),
47104799
RES_REG_ADDR(),
47114800
zend_may_throw(opline, ssa_op, op_array, ssa),
4712-
smart_branch_opcode, -1, -1, exit_addr)) {
4801+
smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
47134802
goto jit_failure;
47144803
}
47154804
}
@@ -4718,8 +4807,13 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
47184807
case ZEND_IS_NOT_IDENTICAL:
47194808
case ZEND_CASE_STRICT:
47204809
op1_info = OP1_INFO();
4721-
CHECK_OP1_TRACE_TYPE();
47224810
op2_info = OP2_INFO();
4811+
skip_comparison =
4812+
ssa_op != ssa->ops &&
4813+
(op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
4814+
(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
4815+
zend_jit_may_skip_comparison(opline, ssa_op, ssa, ssa_opcodes);
4816+
CHECK_OP1_TRACE_TYPE();
47234817
CHECK_OP2_TRACE_TYPE();
47244818
if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
47254819
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
47434837
op2_info, OP2_RANGE(), OP2_REG_ADDR(),
47444838
RES_REG_ADDR(),
47454839
zend_may_throw(opline, ssa_op, op_array, ssa),
4746-
smart_branch_opcode, -1, -1, exit_addr)) {
4840+
smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
47474841
goto jit_failure;
47484842
}
47494843
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
47554849
op2_info, OP2_RANGE(), OP2_REG_ADDR(),
47564850
RES_REG_ADDR(),
47574851
zend_may_throw(opline, ssa_op, op_array, ssa),
4758-
smart_branch_opcode, -1, -1, exit_addr)) {
4852+
smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
47594853
goto jit_failure;
47604854
}
47614855
}

ext/opcache/jit/zend_jit_x86.dasc

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6745,7 +6745,8 @@ static int zend_jit_cmp_long_long(dasm_State **Dst,
67456745
zend_uchar smart_branch_opcode,
67466746
uint32_t target_label,
67476747
uint32_t target_label2,
6748-
const void *exit_addr)
6748+
const void *exit_addr,
6749+
zend_bool skip_comparison)
67496750
{
67506751
zend_bool swap = 0;
67516752
zend_bool result;
@@ -6780,7 +6781,13 @@ static int zend_jit_cmp_long_long(dasm_State **Dst,
67806781
return 1;
67816782
}
67826783

6783-
if (Z_MODE(op1_addr) == IS_REG) {
6784+
if (skip_comparison) {
6785+
if (Z_MODE(op1_addr) != IS_REG &&
6786+
(Z_MODE(op2_addr) == IS_REG ||
6787+
(Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) != IS_CONST_ZVAL))) {
6788+
swap = 1;
6789+
}
6790+
} else if (Z_MODE(op1_addr) == IS_REG) {
67846791
if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 0) {
67856792
| test Ra(Z_REG(op1_addr)), Ra(Z_REG(op1_addr))
67866793
} else {
@@ -7567,7 +7574,8 @@ static int zend_jit_cmp(dasm_State **Dst,
75677574
zend_uchar smart_branch_opcode,
75687575
uint32_t target_label,
75697576
uint32_t target_label2,
7570-
const void *exit_addr)
7577+
const void *exit_addr,
7578+
zend_bool skip_comparison)
75717579
{
75727580
zend_bool same_ops = (opline->op1_type == opline->op2_type) && (opline->op1.var == opline->op2.var);
75737581
zend_bool has_slow;
@@ -7603,7 +7611,7 @@ static int zend_jit_cmp(dasm_State **Dst,
76037611
| IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >9
76047612
}
76057613
}
7606-
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)) {
7614+
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)) {
76077615
return 0;
76087616
}
76097617
if (op1_info & MAY_BE_DOUBLE) {
@@ -7805,7 +7813,8 @@ static int zend_jit_identical(dasm_State **Dst,
78057813
zend_uchar smart_branch_opcode,
78067814
uint32_t target_label,
78077815
uint32_t target_label2,
7808-
const void *exit_addr)
7816+
const void *exit_addr,
7817+
zend_bool skip_comparison)
78097818
{
78107819
uint32_t identical_label = (uint32_t)-1;
78117820
uint32_t not_identical_label = (uint32_t)-1;
@@ -7838,7 +7847,7 @@ static int zend_jit_identical(dasm_State **Dst,
78387847

78397848
if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
78407849
(op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) {
7841-
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)) {
7850+
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)) {
78427851
return 0;
78437852
}
78447853
return 1;

0 commit comments

Comments
 (0)