Skip to content

Commit 36d484a

Browse files
shqkingdstogov
authored andcommitted
Support failed JIT test case: mod_001.phpt
Instructions 'cqo' + 'idiv' are used in x86 to conduct MOD operation. Specific registers RDX:RAX are used. We use instructions 'sdiv' + 'msub' to accomplish the equivalent functionality[1], and there is no such contrain on registers. Similary to left/right shift operations in the previous patches, boundary values, i.e. the second operand is 0 or -1, are handled. [1] https://stackoverflow.com/questions/35351470/obtaining-remainder-using-single-aarch64-instruction
1 parent a9f854a commit 36d484a

File tree

1 file changed

+70
-3
lines changed

1 file changed

+70
-3
lines changed

ext/opcache/jit/zend_jit_arm64.dasc

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,7 +1564,11 @@ static int zend_jit_negative_shift_stub(dasm_State **Dst)
15641564
static int zend_jit_mod_by_zero_stub(dasm_State **Dst)
15651565
{
15661566
|->mod_by_zero:
1567-
| brk #0 // TODO
1567+
| UNDEF_OPLINE_RESULT TMP1w
1568+
| LOAD_ADDR CARG1, zend_ce_division_by_zero_error
1569+
| LOAD_ADDR CARG2, "Modulo by zero"
1570+
| EXT_CALL zend_throw_error, REG0
1571+
| b ->exception_handler
15681572
return 1;
15691573
}
15701574

@@ -3291,7 +3295,7 @@ static int zend_jit_long_math_helper(dasm_State **Dst,
32913295
}
32923296

32933297
if (opcode == ZEND_MOD) {
3294-
| brk #0 // TODO
3298+
result_reg = ZREG_REG0;
32953299
} else if (Z_MODE(res_addr) == IS_REG) {
32963300
if ((opline->opcode == ZEND_SL || opline->opcode == ZEND_SR)
32973301
&& opline->op2_type != IS_CONST) {
@@ -3387,7 +3391,70 @@ static int zend_jit_long_math_helper(dasm_State **Dst,
33873391
| asr Rx(result_reg), Rx(result_reg), REG1
33883392
}
33893393
} else if (opcode == ZEND_MOD) {
3390-
| brk #0 // TODO
3394+
// REG0 -> result_reg
3395+
if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
3396+
zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
3397+
3398+
if (op2_lval == 0) {
3399+
| SET_EX_OPLINE opline, REG0
3400+
| b ->mod_by_zero
3401+
} else if (op2_lval == -1) {
3402+
| mov REG0, xzr
3403+
} else {
3404+
| GET_ZVAL_LVAL ZREG_REG1, op1_addr, TMP1
3405+
| GET_ZVAL_LVAL ZREG_REG2, op2_addr, TMP1
3406+
| sdiv REG0, REG1, REG2
3407+
| msub REG0, REG0, REG2, REG1
3408+
}
3409+
} else {
3410+
if (!op2_range || (op2_range->min <= 0 && op2_range->max >= 0)) {
3411+
if (Z_MODE(op2_addr) == IS_MEM_ZVAL) {
3412+
| SAFE_MEM_ACC_WITH_UOFFSET ldr, TMP1, Rx(Z_REG(op2_addr)), Z_OFFSET(op2_addr), TMP2
3413+
| cmp TMP1, #0
3414+
} else if (Z_MODE(op2_addr) == IS_REG) {
3415+
| tst Rx(Z_REG(op2_addr)), Rx(Z_REG(op2_addr))
3416+
}
3417+
| beq >1
3418+
|.cold_code
3419+
|1:
3420+
| SET_EX_OPLINE opline, REG0
3421+
| b ->mod_by_zero
3422+
|.code
3423+
}
3424+
3425+
/* Prevent overflow error/crash if op1 == LONG_MIN and op2 == -1 */
3426+
if (!op2_range || (op2_range->min <= -1 && op2_range->max >= -1)) {
3427+
if (Z_MODE(op2_addr) == IS_MEM_ZVAL) {
3428+
| SAFE_MEM_ACC_WITH_UOFFSET ldr, TMP1, Rx(Z_REG(op2_addr)), Z_OFFSET(op2_addr), TMP2
3429+
| cmn TMP1, #1
3430+
} else if (Z_MODE(op2_addr) == IS_REG) {
3431+
| cmn Rx(Z_REG(op2_addr)), #1
3432+
}
3433+
| beq >1
3434+
|.cold_code
3435+
|1:
3436+
| SET_ZVAL_LVAL_FROM_REG res_addr, xzr, TMP1
3437+
if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
3438+
if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != Z_REG(res_addr) || Z_OFFSET(op1_addr) != Z_OFFSET(res_addr)) {
3439+
if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) {
3440+
| SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2
3441+
}
3442+
}
3443+
}
3444+
| b >5
3445+
|.code
3446+
}
3447+
3448+
| GET_ZVAL_LVAL ZREG_REG1, op1_addr, TMP1
3449+
if (Z_MODE(op2_addr) == IS_MEM_ZVAL) {
3450+
| ldr TMP1, [Rx(Z_REG(op2_addr)), #Z_OFFSET(op2_addr)]
3451+
| sdiv REG0, REG1, TMP1
3452+
| msub REG0, REG0, TMP1, REG1
3453+
} else if (Z_MODE(op2_addr) == IS_REG) {
3454+
| sdiv REG0, REG1, Rx(Z_REG(op2_addr))
3455+
| msub REG0, REG0, Rx(Z_REG(op2_addr)), REG1
3456+
}
3457+
}
33913458
} else if (same_ops) {
33923459
| brk #0 // TODO
33933460
} else {

0 commit comments

Comments
 (0)