@@ -1564,7 +1564,11 @@ static int zend_jit_negative_shift_stub(dasm_State **Dst)
15641564static 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