Skip to content

Commit 31f5458

Browse files
committed
Use range inference to eliminate useless comparisons
1 parent 90b80c8 commit 31f5458

File tree

3 files changed

+188
-25
lines changed

3 files changed

+188
-25
lines changed

ext/opcache/jit/zend_jit.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ static zend_bool zend_long_is_power_of_two(zend_long x)
192192

193193
#define OP_RANGE(ssa_op, opN) \
194194
(((opline->opN##_type & (IS_TMP_VAR|IS_VAR|IS_CV)) && \
195+
ssa->var_info && \
195196
(ssa_op)->opN##_use >= 0 && \
196197
ssa->var_info[(ssa_op)->opN##_use].has_range) ? \
197198
&ssa->var_info[(ssa_op)->opN##_use].range : NULL)
@@ -2796,8 +2797,8 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
27962797
target_label = target_label2 = (uint32_t)-1;
27972798
}
27982799
if (!zend_jit_cmp(&dasm_state, opline,
2799-
OP1_INFO(), OP1_REG_ADDR(),
2800-
OP2_INFO(), OP2_REG_ADDR(),
2800+
OP1_INFO(), OP1_RANGE(), OP1_REG_ADDR(),
2801+
OP2_INFO(), OP2_RANGE(), OP2_REG_ADDR(),
28012802
res_addr,
28022803
zend_may_throw(opline, ssa_op, op_array, ssa),
28032804
smart_branch_opcode, target_label, target_label2,
@@ -2825,8 +2826,8 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
28252826
target_label = target_label2 = (uint32_t)-1;
28262827
}
28272828
if (!zend_jit_identical(&dasm_state, opline,
2828-
OP1_INFO(), OP1_REG_ADDR(),
2829-
OP2_INFO(), OP2_REG_ADDR(),
2829+
OP1_INFO(), OP1_RANGE(), OP1_REG_ADDR(),
2830+
OP2_INFO(), OP2_RANGE(), OP2_REG_ADDR(),
28302831
RES_REG_ADDR(),
28312832
zend_may_throw(opline, ssa_op, op_array, ssa),
28322833
smart_branch_opcode, target_label, target_label2,

ext/opcache/jit/zend_jit_trace.c

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4299,18 +4299,26 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
42994299
goto jit_failure;
43004300
}
43014301
smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
4302+
if (!zend_jit_cmp(&dasm_state, opline,
4303+
op1_info, OP1_RANGE(), OP1_REG_ADDR(),
4304+
op2_info, OP2_RANGE(), OP2_REG_ADDR(),
4305+
RES_REG_ADDR(),
4306+
zend_may_throw(opline, ssa_op, op_array, ssa),
4307+
smart_branch_opcode, -1, -1, exit_addr)) {
4308+
goto jit_failure;
4309+
}
43024310
zend_jit_trace_update_condition_ranges(opline, ssa_op, op_array, ssa, exit_if_true);
43034311
} else {
43044312
smart_branch_opcode = 0;
43054313
exit_addr = NULL;
4306-
}
4307-
if (!zend_jit_cmp(&dasm_state, opline,
4308-
op1_info, OP1_REG_ADDR(),
4309-
op2_info, OP2_REG_ADDR(),
4310-
RES_REG_ADDR(),
4311-
zend_may_throw(opline, ssa_op, op_array, ssa),
4312-
smart_branch_opcode, -1, -1, exit_addr)) {
4313-
goto jit_failure;
4314+
if (!zend_jit_cmp(&dasm_state, opline,
4315+
op1_info, OP1_RANGE(), OP1_REG_ADDR(),
4316+
op2_info, OP2_RANGE(), OP2_REG_ADDR(),
4317+
RES_REG_ADDR(),
4318+
zend_may_throw(opline, ssa_op, op_array, ssa),
4319+
smart_branch_opcode, -1, -1, exit_addr)) {
4320+
goto jit_failure;
4321+
}
43144322
}
43154323
goto done;
43164324
case ZEND_IS_IDENTICAL:
@@ -4337,18 +4345,26 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
43374345
exit_if_true = !exit_if_true;
43384346
}
43394347
smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
4348+
if (!zend_jit_identical(&dasm_state, opline,
4349+
op1_info, OP1_RANGE(), OP1_REG_ADDR(),
4350+
op2_info, OP2_RANGE(), OP2_REG_ADDR(),
4351+
RES_REG_ADDR(),
4352+
zend_may_throw(opline, ssa_op, op_array, ssa),
4353+
smart_branch_opcode, -1, -1, exit_addr)) {
4354+
goto jit_failure;
4355+
}
43404356
zend_jit_trace_update_condition_ranges(opline, ssa_op, op_array, ssa, exit_if_true);
43414357
} else {
43424358
smart_branch_opcode = 0;
43434359
exit_addr = NULL;
4344-
}
4345-
if (!zend_jit_identical(&dasm_state, opline,
4346-
op1_info, OP1_REG_ADDR(),
4347-
op2_info, OP2_REG_ADDR(),
4348-
RES_REG_ADDR(),
4349-
zend_may_throw(opline, ssa_op, op_array, ssa),
4350-
smart_branch_opcode, -1, -1, exit_addr)) {
4351-
goto jit_failure;
4360+
if (!zend_jit_identical(&dasm_state, opline,
4361+
op1_info, OP1_RANGE(), OP1_REG_ADDR(),
4362+
op2_info, OP2_RANGE(), OP2_REG_ADDR(),
4363+
RES_REG_ADDR(),
4364+
zend_may_throw(opline, ssa_op, op_array, ssa),
4365+
smart_branch_opcode, -1, -1, exit_addr)) {
4366+
goto jit_failure;
4367+
}
43524368
}
43534369
goto done;
43544370
case ZEND_DEFINED:

ext/opcache/jit/zend_jit_x86.dasc

Lines changed: 151 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6572,9 +6572,129 @@ static int zend_jit_assign_op(dasm_State **Dst, const zend_op *opline, uint32_t
65726572
return result;
65736573
}
65746574

6575-
static int zend_jit_cmp_long_long(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
6575+
static int zend_jit_is_constant_cmp_long_long(const zend_op *opline,
6576+
zend_ssa_range *op1_range,
6577+
zend_jit_addr op1_addr,
6578+
zend_ssa_range *op2_range,
6579+
zend_jit_addr op2_addr,
6580+
zend_bool *result)
6581+
{
6582+
zend_long op1_min;
6583+
zend_long op1_max;
6584+
zend_long op2_min;
6585+
zend_long op2_max;
6586+
6587+
if (op1_range) {
6588+
op1_min = op1_range->min;
6589+
op1_max = op1_range->max;
6590+
} else if (Z_MODE(op1_addr) == IS_CONST_ZVAL) {
6591+
ZEND_ASSERT(Z_TYPE_P(Z_ZV(op1_addr)) == IS_LONG);
6592+
op1_min = op1_max = Z_LVAL_P(Z_ZV(op1_addr));
6593+
} else {
6594+
return 0;
6595+
}
6596+
6597+
if (op2_range) {
6598+
op2_min = op2_range->min;
6599+
op2_max = op2_range->max;
6600+
} else if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
6601+
ZEND_ASSERT(Z_TYPE_P(Z_ZV(op2_addr)) == IS_LONG);
6602+
op2_min = op2_max = Z_LVAL_P(Z_ZV(op2_addr));
6603+
} else {
6604+
return 0;
6605+
}
6606+
6607+
switch (opline->opcode) {
6608+
case ZEND_IS_EQUAL:
6609+
case ZEND_IS_IDENTICAL:
6610+
case ZEND_CASE:
6611+
case ZEND_CASE_STRICT:
6612+
if (op1_min == op1_max && op2_min == op2_max && op1_min == op2_min) {
6613+
*result = 1;
6614+
return 1;
6615+
} else if (op1_max < op2_min || op1_min > op2_max) {
6616+
*result = 0;
6617+
return 1;
6618+
}
6619+
return 0;
6620+
case ZEND_IS_NOT_EQUAL:
6621+
case ZEND_IS_NOT_IDENTICAL:
6622+
if (op1_min == op1_max && op2_min == op2_max && op1_min == op2_min) {
6623+
*result = 0;
6624+
return 1;
6625+
} else if (op1_max < op2_min || op1_min > op2_max) {
6626+
*result = 1;
6627+
return 1;
6628+
}
6629+
return 0;
6630+
case ZEND_IS_SMALLER:
6631+
if (op1_max < op2_min) {
6632+
*result = 1;
6633+
return 1;
6634+
} else if (op1_min >= op2_max) {
6635+
*result = 0;
6636+
return 1;
6637+
}
6638+
return 0;
6639+
case ZEND_IS_SMALLER_OR_EQUAL:
6640+
if (op1_max <= op2_min) {
6641+
*result = 1;
6642+
return 1;
6643+
} else if (op1_min > op2_max) {
6644+
*result = 0;
6645+
return 1;
6646+
}
6647+
return 0;
6648+
default:
6649+
ZEND_UNREACHABLE();
6650+
}
6651+
return 0;
6652+
}
6653+
6654+
static int zend_jit_cmp_long_long(dasm_State **Dst,
6655+
const zend_op *opline,
6656+
zend_ssa_range *op1_range,
6657+
zend_jit_addr op1_addr,
6658+
zend_ssa_range *op2_range,
6659+
zend_jit_addr op2_addr,
6660+
zend_jit_addr res_addr,
6661+
zend_uchar smart_branch_opcode,
6662+
uint32_t target_label,
6663+
uint32_t target_label2,
6664+
const void *exit_addr)
65766665
{
65776666
zend_bool swap = 0;
6667+
zend_bool result;
6668+
6669+
if (zend_jit_is_constant_cmp_long_long(opline, op1_range, op1_addr, op2_range, op2_addr, &result)) {
6670+
if (!smart_branch_opcode ||
6671+
smart_branch_opcode == ZEND_JMPZ_EX ||
6672+
smart_branch_opcode == ZEND_JMPNZ_EX) {
6673+
| SET_ZVAL_TYPE_INFO res_addr, (result ? IS_TRUE : IS_FALSE)
6674+
}
6675+
if (smart_branch_opcode && !exit_addr) {
6676+
if (smart_branch_opcode == ZEND_JMPZ ||
6677+
smart_branch_opcode == ZEND_JMPZ_EX) {
6678+
if (!result) {
6679+
| jmp => target_label
6680+
}
6681+
} else if (smart_branch_opcode == ZEND_JMPNZ ||
6682+
smart_branch_opcode == ZEND_JMPNZ_EX) {
6683+
if (result) {
6684+
| jmp => target_label
6685+
}
6686+
} else if (smart_branch_opcode == ZEND_JMPZNZ) {
6687+
if (!result) {
6688+
| jmp => target_label
6689+
} else {
6690+
| jmp => target_label2
6691+
}
6692+
} else {
6693+
ZEND_UNREACHABLE();
6694+
}
6695+
}
6696+
return 1;
6697+
}
65786698

65796699
if (Z_MODE(op1_addr) == IS_REG) {
65806700
if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 0) {
@@ -7350,7 +7470,20 @@ static int zend_jit_cmp_slow(dasm_State **Dst, const zend_op *opline, zend_jit_a
73507470
return 1;
73517471
}
73527472

7353-
static int zend_jit_cmp(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, zend_jit_addr op2_addr, zend_jit_addr res_addr, int may_throw, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
7473+
static int zend_jit_cmp(dasm_State **Dst,
7474+
const zend_op *opline,
7475+
uint32_t op1_info,
7476+
zend_ssa_range *op1_range,
7477+
zend_jit_addr op1_addr,
7478+
uint32_t op2_info,
7479+
zend_ssa_range *op2_range,
7480+
zend_jit_addr op2_addr,
7481+
zend_jit_addr res_addr,
7482+
int may_throw,
7483+
zend_uchar smart_branch_opcode,
7484+
uint32_t target_label,
7485+
uint32_t target_label2,
7486+
const void *exit_addr)
73547487
{
73557488
zend_bool same_ops = (opline->op1_type == opline->op2_type) && (opline->op1.var == opline->op2.var);
73567489
zend_bool has_slow;
@@ -7386,7 +7519,7 @@ static int zend_jit_cmp(dasm_State **Dst, const zend_op *opline, uint32_t op1_in
73867519
| IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >9
73877520
}
73887521
}
7389-
if (!zend_jit_cmp_long_long(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
7522+
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)) {
73907523
return 0;
73917524
}
73927525
if (op1_info & MAY_BE_DOUBLE) {
@@ -7575,7 +7708,20 @@ static int zend_jit_cmp(dasm_State **Dst, const zend_op *opline, uint32_t op1_in
75757708
return 1;
75767709
}
75777710

7578-
static int zend_jit_identical(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, zend_jit_addr op2_addr, zend_jit_addr res_addr, int may_throw, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
7711+
static int zend_jit_identical(dasm_State **Dst,
7712+
const zend_op *opline,
7713+
uint32_t op1_info,
7714+
zend_ssa_range *op1_range,
7715+
zend_jit_addr op1_addr,
7716+
uint32_t op2_info,
7717+
zend_ssa_range *op2_range,
7718+
zend_jit_addr op2_addr,
7719+
zend_jit_addr res_addr,
7720+
int may_throw,
7721+
zend_uchar smart_branch_opcode,
7722+
uint32_t target_label,
7723+
uint32_t target_label2,
7724+
const void *exit_addr)
75797725
{
75807726
uint32_t identical_label = (uint32_t)-1;
75817727
uint32_t not_identical_label = (uint32_t)-1;
@@ -7608,7 +7754,7 @@ static int zend_jit_identical(dasm_State **Dst, const zend_op *opline, uint32_t
76087754

76097755
if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
76107756
(op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) {
7611-
if (!zend_jit_cmp_long_long(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
7757+
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)) {
76127758
return 0;
76137759
}
76147760
return 1;

0 commit comments

Comments
 (0)