mirror of
https://github.com/php/php-src.git
synced 2025-08-19 08:49:28 +02:00
Use range inference to eliminate useless comparisons
This commit is contained in:
parent
90b80c8278
commit
31f54586b5
3 changed files with 188 additions and 25 deletions
|
@ -192,6 +192,7 @@ static zend_bool zend_long_is_power_of_two(zend_long x)
|
|||
|
||||
#define OP_RANGE(ssa_op, opN) \
|
||||
(((opline->opN##_type & (IS_TMP_VAR|IS_VAR|IS_CV)) && \
|
||||
ssa->var_info && \
|
||||
(ssa_op)->opN##_use >= 0 && \
|
||||
ssa->var_info[(ssa_op)->opN##_use].has_range) ? \
|
||||
&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
|
|||
target_label = target_label2 = (uint32_t)-1;
|
||||
}
|
||||
if (!zend_jit_cmp(&dasm_state, opline,
|
||||
OP1_INFO(), OP1_REG_ADDR(),
|
||||
OP2_INFO(), OP2_REG_ADDR(),
|
||||
OP1_INFO(), OP1_RANGE(), OP1_REG_ADDR(),
|
||||
OP2_INFO(), OP2_RANGE(), OP2_REG_ADDR(),
|
||||
res_addr,
|
||||
zend_may_throw(opline, ssa_op, op_array, ssa),
|
||||
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
|
|||
target_label = target_label2 = (uint32_t)-1;
|
||||
}
|
||||
if (!zend_jit_identical(&dasm_state, opline,
|
||||
OP1_INFO(), OP1_REG_ADDR(),
|
||||
OP2_INFO(), OP2_REG_ADDR(),
|
||||
OP1_INFO(), OP1_RANGE(), OP1_REG_ADDR(),
|
||||
OP2_INFO(), OP2_RANGE(), OP2_REG_ADDR(),
|
||||
RES_REG_ADDR(),
|
||||
zend_may_throw(opline, ssa_op, op_array, ssa),
|
||||
smart_branch_opcode, target_label, target_label2,
|
||||
|
|
|
@ -4299,18 +4299,26 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
|
|||
goto jit_failure;
|
||||
}
|
||||
smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
|
||||
if (!zend_jit_cmp(&dasm_state, opline,
|
||||
op1_info, OP1_RANGE(), OP1_REG_ADDR(),
|
||||
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)) {
|
||||
goto jit_failure;
|
||||
}
|
||||
zend_jit_trace_update_condition_ranges(opline, ssa_op, op_array, ssa, exit_if_true);
|
||||
} else {
|
||||
smart_branch_opcode = 0;
|
||||
exit_addr = NULL;
|
||||
}
|
||||
if (!zend_jit_cmp(&dasm_state, opline,
|
||||
op1_info, OP1_REG_ADDR(),
|
||||
op2_info, OP2_REG_ADDR(),
|
||||
RES_REG_ADDR(),
|
||||
zend_may_throw(opline, ssa_op, op_array, ssa),
|
||||
smart_branch_opcode, -1, -1, exit_addr)) {
|
||||
goto jit_failure;
|
||||
if (!zend_jit_cmp(&dasm_state, opline,
|
||||
op1_info, OP1_RANGE(), OP1_REG_ADDR(),
|
||||
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)) {
|
||||
goto jit_failure;
|
||||
}
|
||||
}
|
||||
goto done;
|
||||
case ZEND_IS_IDENTICAL:
|
||||
|
@ -4337,18 +4345,26 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
|
|||
exit_if_true = !exit_if_true;
|
||||
}
|
||||
smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
|
||||
if (!zend_jit_identical(&dasm_state, opline,
|
||||
op1_info, OP1_RANGE(), OP1_REG_ADDR(),
|
||||
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)) {
|
||||
goto jit_failure;
|
||||
}
|
||||
zend_jit_trace_update_condition_ranges(opline, ssa_op, op_array, ssa, exit_if_true);
|
||||
} else {
|
||||
smart_branch_opcode = 0;
|
||||
exit_addr = NULL;
|
||||
}
|
||||
if (!zend_jit_identical(&dasm_state, opline,
|
||||
op1_info, OP1_REG_ADDR(),
|
||||
op2_info, OP2_REG_ADDR(),
|
||||
RES_REG_ADDR(),
|
||||
zend_may_throw(opline, ssa_op, op_array, ssa),
|
||||
smart_branch_opcode, -1, -1, exit_addr)) {
|
||||
goto jit_failure;
|
||||
if (!zend_jit_identical(&dasm_state, opline,
|
||||
op1_info, OP1_RANGE(), OP1_REG_ADDR(),
|
||||
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)) {
|
||||
goto jit_failure;
|
||||
}
|
||||
}
|
||||
goto done;
|
||||
case ZEND_DEFINED:
|
||||
|
|
|
@ -6572,9 +6572,129 @@ static int zend_jit_assign_op(dasm_State **Dst, const zend_op *opline, uint32_t
|
|||
return result;
|
||||
}
|
||||
|
||||
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)
|
||||
static int zend_jit_is_constant_cmp_long_long(const zend_op *opline,
|
||||
zend_ssa_range *op1_range,
|
||||
zend_jit_addr op1_addr,
|
||||
zend_ssa_range *op2_range,
|
||||
zend_jit_addr op2_addr,
|
||||
zend_bool *result)
|
||||
{
|
||||
zend_long op1_min;
|
||||
zend_long op1_max;
|
||||
zend_long op2_min;
|
||||
zend_long op2_max;
|
||||
|
||||
if (op1_range) {
|
||||
op1_min = op1_range->min;
|
||||
op1_max = op1_range->max;
|
||||
} else if (Z_MODE(op1_addr) == IS_CONST_ZVAL) {
|
||||
ZEND_ASSERT(Z_TYPE_P(Z_ZV(op1_addr)) == IS_LONG);
|
||||
op1_min = op1_max = Z_LVAL_P(Z_ZV(op1_addr));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (op2_range) {
|
||||
op2_min = op2_range->min;
|
||||
op2_max = op2_range->max;
|
||||
} else if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
|
||||
ZEND_ASSERT(Z_TYPE_P(Z_ZV(op2_addr)) == IS_LONG);
|
||||
op2_min = op2_max = Z_LVAL_P(Z_ZV(op2_addr));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (opline->opcode) {
|
||||
case ZEND_IS_EQUAL:
|
||||
case ZEND_IS_IDENTICAL:
|
||||
case ZEND_CASE:
|
||||
case ZEND_CASE_STRICT:
|
||||
if (op1_min == op1_max && op2_min == op2_max && op1_min == op2_min) {
|
||||
*result = 1;
|
||||
return 1;
|
||||
} else if (op1_max < op2_min || op1_min > op2_max) {
|
||||
*result = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
case ZEND_IS_NOT_EQUAL:
|
||||
case ZEND_IS_NOT_IDENTICAL:
|
||||
if (op1_min == op1_max && op2_min == op2_max && op1_min == op2_min) {
|
||||
*result = 0;
|
||||
return 1;
|
||||
} else if (op1_max < op2_min || op1_min > op2_max) {
|
||||
*result = 1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
case ZEND_IS_SMALLER:
|
||||
if (op1_max < op2_min) {
|
||||
*result = 1;
|
||||
return 1;
|
||||
} else if (op1_min >= op2_max) {
|
||||
*result = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
case ZEND_IS_SMALLER_OR_EQUAL:
|
||||
if (op1_max <= op2_min) {
|
||||
*result = 1;
|
||||
return 1;
|
||||
} else if (op1_min > op2_max) {
|
||||
*result = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
ZEND_UNREACHABLE();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zend_jit_cmp_long_long(dasm_State **Dst,
|
||||
const zend_op *opline,
|
||||
zend_ssa_range *op1_range,
|
||||
zend_jit_addr op1_addr,
|
||||
zend_ssa_range *op2_range,
|
||||
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)
|
||||
{
|
||||
zend_bool swap = 0;
|
||||
zend_bool result;
|
||||
|
||||
if (zend_jit_is_constant_cmp_long_long(opline, op1_range, op1_addr, op2_range, op2_addr, &result)) {
|
||||
if (!smart_branch_opcode ||
|
||||
smart_branch_opcode == ZEND_JMPZ_EX ||
|
||||
smart_branch_opcode == ZEND_JMPNZ_EX) {
|
||||
| SET_ZVAL_TYPE_INFO res_addr, (result ? IS_TRUE : IS_FALSE)
|
||||
}
|
||||
if (smart_branch_opcode && !exit_addr) {
|
||||
if (smart_branch_opcode == ZEND_JMPZ ||
|
||||
smart_branch_opcode == ZEND_JMPZ_EX) {
|
||||
if (!result) {
|
||||
| jmp => target_label
|
||||
}
|
||||
} else if (smart_branch_opcode == ZEND_JMPNZ ||
|
||||
smart_branch_opcode == ZEND_JMPNZ_EX) {
|
||||
if (result) {
|
||||
| jmp => target_label
|
||||
}
|
||||
} else if (smart_branch_opcode == ZEND_JMPZNZ) {
|
||||
if (!result) {
|
||||
| jmp => target_label
|
||||
} else {
|
||||
| jmp => target_label2
|
||||
}
|
||||
} else {
|
||||
ZEND_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (Z_MODE(op1_addr) == IS_REG) {
|
||||
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
|
|||
return 1;
|
||||
}
|
||||
|
||||
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)
|
||||
static int zend_jit_cmp(dasm_State **Dst,
|
||||
const zend_op *opline,
|
||||
uint32_t op1_info,
|
||||
zend_ssa_range *op1_range,
|
||||
zend_jit_addr op1_addr,
|
||||
uint32_t op2_info,
|
||||
zend_ssa_range *op2_range,
|
||||
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)
|
||||
{
|
||||
zend_bool same_ops = (opline->op1_type == opline->op2_type) && (opline->op1.var == opline->op2.var);
|
||||
zend_bool has_slow;
|
||||
|
@ -7386,7 +7519,7 @@ static int zend_jit_cmp(dasm_State **Dst, const zend_op *opline, uint32_t op1_in
|
|||
| IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >9
|
||||
}
|
||||
}
|
||||
if (!zend_jit_cmp_long_long(Dst, opline, op1_addr, 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)) {
|
||||
return 0;
|
||||
}
|
||||
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
|
|||
return 1;
|
||||
}
|
||||
|
||||
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)
|
||||
static int zend_jit_identical(dasm_State **Dst,
|
||||
const zend_op *opline,
|
||||
uint32_t op1_info,
|
||||
zend_ssa_range *op1_range,
|
||||
zend_jit_addr op1_addr,
|
||||
uint32_t op2_info,
|
||||
zend_ssa_range *op2_range,
|
||||
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)
|
||||
{
|
||||
uint32_t identical_label = (uint32_t)-1;
|
||||
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
|
|||
|
||||
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_addr, 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)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue