Skip to content

Commit af319b0

Browse files
committed
JIT/ARM64: Improve JIT for MOD instruction.
Eliminate x86 specific register constrints (idiv imlicitly used %eax and %rdx). On ARM64 we use reserved TMP registers.
1 parent 62e0b83 commit af319b0

File tree

1 file changed

+21
-62
lines changed

1 file changed

+21
-62
lines changed

ext/opcache/jit/zend_jit_arm64.dasc

Lines changed: 21 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -4506,9 +4506,7 @@ static int zend_jit_long_math_helper(dasm_State **Dst,
45064506
}
45074507
}
45084508

4509-
if (opcode == ZEND_MOD) {
4510-
result_reg = ZREG_REG0;
4511-
} else if (Z_MODE(res_addr) == IS_REG) {
4509+
if (Z_MODE(res_addr) == IS_REG) {
45124510
if ((opline->opcode == ZEND_SL || opline->opcode == ZEND_SR)
45134511
&& opline->op2_type != IS_CONST) {
45144512
result_reg = ZREG_REG0;
@@ -4611,29 +4609,32 @@ static int zend_jit_long_math_helper(dasm_State **Dst,
46114609
| asr Rx(result_reg), Rx(result_reg), Rx(op2_reg)
46124610
}
46134611
} else if (opcode == ZEND_MOD) {
4614-
// REG0 -> result_reg
46154612
if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
46164613
zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
46174614

46184615
if (op2_lval == 0) {
46194616
| SET_EX_OPLINE opline, REG0
46204617
| b ->mod_by_zero
46214618
} else if (op2_lval == -1) {
4622-
| mov REG0, xzr
4619+
| mov Rx(result_reg), xzr
46234620
} else {
4624-
| GET_ZVAL_LVAL ZREG_REG1, op1_addr, TMP1
4625-
| GET_ZVAL_LVAL ZREG_REG2, op2_addr, TMP1
4626-
| sdiv REG0, REG1, REG2
4627-
| msub REG0, REG0, REG2, REG1
4621+
| GET_ZVAL_LVAL ZREG_TMP1, op1_addr, TMP1
4622+
| GET_ZVAL_LVAL ZREG_TMP2, op2_addr, TMP2
4623+
| sdiv Rx(result_reg), TMP1, TMP2
4624+
| msub Rx(result_reg), Rx(result_reg), TMP2, TMP1
46284625
}
46294626
} else {
4627+
zend_reg op2_reg;
4628+
4629+
if (Z_MODE(op2_addr) == IS_MEM_ZVAL) {
4630+
| MEM_ACCESS_64_WITH_UOFFSET ldr, TMP2, Rx(Z_REG(op2_addr)), Z_OFFSET(op2_addr), TMP2
4631+
op2_reg = ZREG_TMP2;
4632+
} else if (Z_MODE(op2_addr) == IS_REG) {
4633+
op2_reg = Z_REG(op2_addr);
4634+
}
4635+
46304636
if (!op2_range || (op2_range->min <= 0 && op2_range->max >= 0)) {
4631-
if (Z_MODE(op2_addr) == IS_MEM_ZVAL) {
4632-
| MEM_ACCESS_64_WITH_UOFFSET ldr, TMP1, Rx(Z_REG(op2_addr)), Z_OFFSET(op2_addr), TMP2
4633-
| cbz TMP1, >1
4634-
} else if (Z_MODE(op2_addr) == IS_REG) {
4635-
| cbz Rx(Z_REG(op2_addr)), >1
4636-
}
4637+
| cbz Rx(op2_reg), >1
46374638
|.cold_code
46384639
|1:
46394640
| SET_EX_OPLINE opline, REG0
@@ -4643,12 +4644,7 @@ static int zend_jit_long_math_helper(dasm_State **Dst,
46434644

46444645
/* Prevent overflow error/crash if op1 == LONG_MIN and op2 == -1 */
46454646
if (!op2_range || (op2_range->min <= -1 && op2_range->max >= -1)) {
4646-
if (Z_MODE(op2_addr) == IS_MEM_ZVAL) {
4647-
| MEM_ACCESS_64_WITH_UOFFSET ldr, TMP1, Rx(Z_REG(op2_addr)), Z_OFFSET(op2_addr), TMP2
4648-
| cmn TMP1, #1
4649-
} else if (Z_MODE(op2_addr) == IS_REG) {
4650-
| cmn Rx(Z_REG(op2_addr)), #1
4651-
}
4647+
| cmn Rx(op2_reg), #1
46524648
| beq >1
46534649
|.cold_code
46544650
|1:
@@ -4664,15 +4660,9 @@ static int zend_jit_long_math_helper(dasm_State **Dst,
46644660
|.code
46654661
}
46664662

4667-
| GET_ZVAL_LVAL ZREG_REG1, op1_addr, TMP1
4668-
if (Z_MODE(op2_addr) == IS_MEM_ZVAL) {
4669-
| ldr TMP1, [Rx(Z_REG(op2_addr)), #Z_OFFSET(op2_addr)]
4670-
| sdiv REG0, REG1, TMP1
4671-
| msub REG0, REG0, TMP1, REG1
4672-
} else if (Z_MODE(op2_addr) == IS_REG) {
4673-
| sdiv REG0, REG1, Rx(Z_REG(op2_addr))
4674-
| msub REG0, REG0, Rx(Z_REG(op2_addr)), REG1
4675-
}
4663+
| GET_ZVAL_LVAL ZREG_TMP1, op1_addr, TMP1
4664+
| sdiv Rx(result_reg), TMP1, Rx(op2_reg)
4665+
| msub Rx(result_reg), Rx(result_reg), Rx(op2_reg), TMP1
46764666
}
46774667
} else if (same_ops) {
46784668
| GET_ZVAL_LVAL result_reg, op1_addr, TMP1
@@ -14404,6 +14394,7 @@ static zend_regset zend_jit_get_scratch_regset(const zend_op *opline, const zend
1440414394
case ZEND_BW_XOR:
1440514395
case ZEND_SL:
1440614396
case ZEND_SR:
14397+
case ZEND_MOD:
1440714398
op1_info = OP1_INFO();
1440814399
op2_info = OP2_INFO();
1440914400
if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG)) &&
@@ -14415,38 +14406,6 @@ static zend_regset zend_jit_get_scratch_regset(const zend_op *opline, const zend
1441514406
}
1441614407
}
1441714408
break;
14418-
case ZEND_MOD:
14419-
op1_info = OP1_INFO();
14420-
op2_info = OP2_INFO();
14421-
if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG)) &&
14422-
!(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG))) {
14423-
regset = ZEND_REGSET_EMPTY;
14424-
if (opline->op2_type == IS_CONST &&
14425-
Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG &&
14426-
zend_long_is_power_of_two(Z_LVAL_P(RT_CONSTANT(opline, opline->op2))) &&
14427-
OP1_HAS_RANGE() &&
14428-
OP1_MIN_RANGE() >= 0) {
14429-
if (ssa_op->result_def != current_var &&
14430-
(ssa_op->op1_use != current_var || !last_use)) {
14431-
ZEND_REGSET_INCL(regset, ZREG_REG0);
14432-
}
14433-
if (sizeof(void*) == 8
14434-
&& !IS_SIGNED_32BIT(Z_LVAL_P(RT_CONSTANT(opline, opline->op2)) - 1)) {
14435-
if (!ZEND_REGSET_IN(regset, ZREG_REG0)) {
14436-
ZEND_REGSET_INCL(regset, ZREG_REG0);
14437-
} else {
14438-
ZEND_REGSET_INCL(regset, ZREG_REG1);
14439-
}
14440-
}
14441-
} else {
14442-
ZEND_REGSET_INCL(regset, ZREG_REG0);
14443-
ZEND_REGSET_INCL(regset, ZREG_REG2);
14444-
if (opline->op2_type == IS_CONST) {
14445-
ZEND_REGSET_INCL(regset, ZREG_REG1);
14446-
}
14447-
}
14448-
}
14449-
break;
1445014409
case ZEND_IS_SMALLER:
1445114410
case ZEND_IS_SMALLER_OR_EQUAL:
1445214411
case ZEND_IS_EQUAL:

0 commit comments

Comments
 (0)