Skip to content

Commit

Permalink
JIT/ARM64: Improve JIT for MOD instruction.
Browse files Browse the repository at this point in the history
Eliminate x86 specific register constrints (idiv imlicitly used
%eax and %rdx). On ARM64 we use reserved TMP registers.
  • Loading branch information
dstogov committed Jun 9, 2021
1 parent 62e0b83 commit af319b0
Showing 1 changed file with 21 additions and 62 deletions.
83 changes: 21 additions & 62 deletions ext/opcache/jit/zend_jit_arm64.dasc
Expand Up @@ -4506,9 +4506,7 @@ static int zend_jit_long_math_helper(dasm_State **Dst,
}
}

if (opcode == ZEND_MOD) {
result_reg = ZREG_REG0;
} else if (Z_MODE(res_addr) == IS_REG) {
if (Z_MODE(res_addr) == IS_REG) {
if ((opline->opcode == ZEND_SL || opline->opcode == ZEND_SR)
&& opline->op2_type != IS_CONST) {
result_reg = ZREG_REG0;
Expand Down Expand Up @@ -4611,29 +4609,32 @@ static int zend_jit_long_math_helper(dasm_State **Dst,
| asr Rx(result_reg), Rx(result_reg), Rx(op2_reg)
}
} else if (opcode == ZEND_MOD) {
// REG0 -> result_reg
if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));

if (op2_lval == 0) {
| SET_EX_OPLINE opline, REG0
| b ->mod_by_zero
} else if (op2_lval == -1) {
| mov REG0, xzr
| mov Rx(result_reg), xzr
} else {
| GET_ZVAL_LVAL ZREG_REG1, op1_addr, TMP1
| GET_ZVAL_LVAL ZREG_REG2, op2_addr, TMP1
| sdiv REG0, REG1, REG2
| msub REG0, REG0, REG2, REG1
| GET_ZVAL_LVAL ZREG_TMP1, op1_addr, TMP1
| GET_ZVAL_LVAL ZREG_TMP2, op2_addr, TMP2
| sdiv Rx(result_reg), TMP1, TMP2
| msub Rx(result_reg), Rx(result_reg), TMP2, TMP1
}
} else {
zend_reg op2_reg;

if (Z_MODE(op2_addr) == IS_MEM_ZVAL) {
| MEM_ACCESS_64_WITH_UOFFSET ldr, TMP2, Rx(Z_REG(op2_addr)), Z_OFFSET(op2_addr), TMP2
op2_reg = ZREG_TMP2;
} else if (Z_MODE(op2_addr) == IS_REG) {
op2_reg = Z_REG(op2_addr);
}

if (!op2_range || (op2_range->min <= 0 && op2_range->max >= 0)) {
if (Z_MODE(op2_addr) == IS_MEM_ZVAL) {
| MEM_ACCESS_64_WITH_UOFFSET ldr, TMP1, Rx(Z_REG(op2_addr)), Z_OFFSET(op2_addr), TMP2
| cbz TMP1, >1
} else if (Z_MODE(op2_addr) == IS_REG) {
| cbz Rx(Z_REG(op2_addr)), >1
}
| cbz Rx(op2_reg), >1
|.cold_code
|1:
| SET_EX_OPLINE opline, REG0
Expand All @@ -4643,12 +4644,7 @@ static int zend_jit_long_math_helper(dasm_State **Dst,

/* Prevent overflow error/crash if op1 == LONG_MIN and op2 == -1 */
if (!op2_range || (op2_range->min <= -1 && op2_range->max >= -1)) {
if (Z_MODE(op2_addr) == IS_MEM_ZVAL) {
| MEM_ACCESS_64_WITH_UOFFSET ldr, TMP1, Rx(Z_REG(op2_addr)), Z_OFFSET(op2_addr), TMP2
| cmn TMP1, #1
} else if (Z_MODE(op2_addr) == IS_REG) {
| cmn Rx(Z_REG(op2_addr)), #1
}
| cmn Rx(op2_reg), #1
| beq >1
|.cold_code
|1:
Expand All @@ -4664,15 +4660,9 @@ static int zend_jit_long_math_helper(dasm_State **Dst,
|.code
}

| GET_ZVAL_LVAL ZREG_REG1, op1_addr, TMP1
if (Z_MODE(op2_addr) == IS_MEM_ZVAL) {
| ldr TMP1, [Rx(Z_REG(op2_addr)), #Z_OFFSET(op2_addr)]
| sdiv REG0, REG1, TMP1
| msub REG0, REG0, TMP1, REG1
} else if (Z_MODE(op2_addr) == IS_REG) {
| sdiv REG0, REG1, Rx(Z_REG(op2_addr))
| msub REG0, REG0, Rx(Z_REG(op2_addr)), REG1
}
| GET_ZVAL_LVAL ZREG_TMP1, op1_addr, TMP1
| sdiv Rx(result_reg), TMP1, Rx(op2_reg)
| msub Rx(result_reg), Rx(result_reg), Rx(op2_reg), TMP1
}
} else if (same_ops) {
| GET_ZVAL_LVAL result_reg, op1_addr, TMP1
Expand Down Expand Up @@ -14404,6 +14394,7 @@ static zend_regset zend_jit_get_scratch_regset(const zend_op *opline, const zend
case ZEND_BW_XOR:
case ZEND_SL:
case ZEND_SR:
case ZEND_MOD:
op1_info = OP1_INFO();
op2_info = OP2_INFO();
if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG)) &&
Expand All @@ -14415,38 +14406,6 @@ static zend_regset zend_jit_get_scratch_regset(const zend_op *opline, const zend
}
}
break;
case ZEND_MOD:
op1_info = OP1_INFO();
op2_info = OP2_INFO();
if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG)) &&
!(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG))) {
regset = ZEND_REGSET_EMPTY;
if (opline->op2_type == IS_CONST &&
Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG &&
zend_long_is_power_of_two(Z_LVAL_P(RT_CONSTANT(opline, opline->op2))) &&
OP1_HAS_RANGE() &&
OP1_MIN_RANGE() >= 0) {
if (ssa_op->result_def != current_var &&
(ssa_op->op1_use != current_var || !last_use)) {
ZEND_REGSET_INCL(regset, ZREG_REG0);
}
if (sizeof(void*) == 8
&& !IS_SIGNED_32BIT(Z_LVAL_P(RT_CONSTANT(opline, opline->op2)) - 1)) {
if (!ZEND_REGSET_IN(regset, ZREG_REG0)) {
ZEND_REGSET_INCL(regset, ZREG_REG0);
} else {
ZEND_REGSET_INCL(regset, ZREG_REG1);
}
}
} else {
ZEND_REGSET_INCL(regset, ZREG_REG0);
ZEND_REGSET_INCL(regset, ZREG_REG2);
if (opline->op2_type == IS_CONST) {
ZEND_REGSET_INCL(regset, ZREG_REG1);
}
}
}
break;
case ZEND_IS_SMALLER:
case ZEND_IS_SMALLER_OR_EQUAL:
case ZEND_IS_EQUAL:
Expand Down

0 comments on commit af319b0

Please sign in to comment.