@@ -1564,7 +1564,11 @@ static int zend_jit_negative_shift_stub(dasm_State **Dst)
1564
1564
static int zend_jit_mod_by_zero_stub(dasm_State **Dst)
1565
1565
{
1566
1566
|->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
1568
1572
return 1;
1569
1573
}
1570
1574
@@ -3291,7 +3295,7 @@ static int zend_jit_long_math_helper(dasm_State **Dst,
3291
3295
}
3292
3296
3293
3297
if (opcode == ZEND_MOD) {
3294
- | brk #0 // TODO
3298
+ result_reg = ZREG_REG0;
3295
3299
} else if (Z_MODE(res_addr) == IS_REG) {
3296
3300
if ((opline->opcode == ZEND_SL || opline->opcode == ZEND_SR)
3297
3301
&& opline->op2_type != IS_CONST) {
@@ -3387,7 +3391,70 @@ static int zend_jit_long_math_helper(dasm_State **Dst,
3387
3391
| asr Rx(result_reg), Rx(result_reg), REG1
3388
3392
}
3389
3393
} 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
+ }
3391
3458
} else if (same_ops) {
3392
3459
| brk #0 // TODO
3393
3460
} else {
0 commit comments