| ... | ... | @@ -1416,8 +1416,9 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1416 | 1416 | |
| 1417 | 1417 | .div_float => try self.divFloat(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 1418 | 1418 | |
| 1419 | | .div_trunc => try self.div(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 1420 | | .div_floor => try self.div(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 1419 | .div_trunc => try self.divTrunc(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 1420 | |
| 1421 | .div_floor => try self.divFloor(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 1421 | 1422 | |
| 1422 | 1423 | .div_exact => try self.divExact(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 1423 | 1424 | |
| ... | ... | @@ -1567,12 +1568,12 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1567 | 1568 | |
| 1568 | 1569 | const dest = blk: { |
| 1569 | 1570 | if (rhs_immediate_ok) { |
| 1570 | | break :blk try self.binOpImmediateNew(mir_tag, lhs_bind, rhs_immediate.?, lhs_ty, false, null); |
| 1571 | break :blk try self.binOpImmediate(mir_tag, lhs_bind, rhs_immediate.?, lhs_ty, false, null); |
| 1571 | 1572 | } else if (lhs_immediate_ok) { |
| 1572 | 1573 | // swap lhs and rhs |
| 1573 | | break :blk try self.binOpImmediateNew(mir_tag, rhs_bind, lhs_immediate.?, rhs_ty, true, null); |
| 1574 | break :blk try self.binOpImmediate(mir_tag, rhs_bind, lhs_immediate.?, rhs_ty, true, null); |
| 1574 | 1575 | } else { |
| 1575 | | break :blk try self.binOpRegisterNew(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, null); |
| 1576 | break :blk try self.binOpRegister(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, null); |
| 1576 | 1577 | } |
| 1577 | 1578 | }; |
| 1578 | 1579 | |
| ... | ... | @@ -1625,7 +1626,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1625 | 1626 | .unsigned => .mul, |
| 1626 | 1627 | }; |
| 1627 | 1628 | |
| 1628 | | const dest = try self.binOpRegisterNew(base_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, null); |
| 1629 | const dest = try self.binOpRegister(base_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, null); |
| 1629 | 1630 | const dest_reg = dest.register; |
| 1630 | 1631 | const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg); |
| 1631 | 1632 | defer self.register_manager.unlockReg(dest_reg_lock); |
| ... | ... | @@ -3123,7 +3124,7 @@ fn allocRegs( |
| 3123 | 3124 | /// instructions which are binary operations acting on two registers |
| 3124 | 3125 | /// |
| 3125 | 3126 | /// Returns the destination register |
| 3126 | | fn binOpRegisterNew( |
| 3127 | fn binOpRegister( |
| 3127 | 3128 | self: *Self, |
| 3128 | 3129 | mir_tag: Mir.Inst.Tag, |
| 3129 | 3130 | lhs_bind: ReadArg.Bind, |
| ... | ... | @@ -3196,7 +3197,7 @@ fn binOpRegisterNew( |
| 3196 | 3197 | /// an immediate |
| 3197 | 3198 | /// |
| 3198 | 3199 | /// Returns the destination register |
| 3199 | | fn binOpImmediateNew( |
| 3200 | fn binOpImmediate( |
| 3200 | 3201 | self: *Self, |
| 3201 | 3202 | mir_tag: Mir.Inst.Tag, |
| 3202 | 3203 | lhs_bind: ReadArg.Bind, |
| ... | ... | @@ -3265,11 +3266,11 @@ fn addSub( |
| 3265 | 3266 | rhs_ty: Type, |
| 3266 | 3267 | maybe_inst: ?Air.Inst.Index, |
| 3267 | 3268 | ) InnerError!MCValue { |
| 3269 | const mod = self.bin_file.options.module.?; |
| 3268 | 3270 | switch (lhs_ty.zigTypeTag()) { |
| 3269 | 3271 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3270 | 3272 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3271 | 3273 | .Int => { |
| 3272 | | const mod = self.bin_file.options.module.?; |
| 3273 | 3274 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 3274 | 3275 | const int_info = lhs_ty.intInfo(self.target.*); |
| 3275 | 3276 | if (int_info.bits <= 32) { |
| ... | ... | @@ -3298,12 +3299,12 @@ fn addSub( |
| 3298 | 3299 | }; |
| 3299 | 3300 | |
| 3300 | 3301 | if (rhs_immediate_ok) { |
| 3301 | | return try self.binOpImmediateNew(mir_tag, lhs_bind, rhs_immediate.?, lhs_ty, false, maybe_inst); |
| 3302 | return try self.binOpImmediate(mir_tag, lhs_bind, rhs_immediate.?, lhs_ty, false, maybe_inst); |
| 3302 | 3303 | } else if (lhs_immediate_ok) { |
| 3303 | 3304 | // swap lhs and rhs |
| 3304 | | return try self.binOpImmediateNew(mir_tag, rhs_bind, lhs_immediate.?, rhs_ty, true, maybe_inst); |
| 3305 | return try self.binOpImmediate(mir_tag, rhs_bind, lhs_immediate.?, rhs_ty, true, maybe_inst); |
| 3305 | 3306 | } else { |
| 3306 | | return try self.binOpRegisterNew(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 3307 | return try self.binOpRegister(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 3307 | 3308 | } |
| 3308 | 3309 | } else { |
| 3309 | 3310 | return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); |
| ... | ... | @@ -3321,18 +3322,18 @@ fn mul( |
| 3321 | 3322 | rhs_ty: Type, |
| 3322 | 3323 | maybe_inst: ?Air.Inst.Index, |
| 3323 | 3324 | ) InnerError!MCValue { |
| 3325 | const mod = self.bin_file.options.module.?; |
| 3324 | 3326 | switch (lhs_ty.zigTypeTag()) { |
| 3325 | 3327 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3326 | 3328 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3327 | 3329 | .Int => { |
| 3328 | | const mod = self.bin_file.options.module.?; |
| 3329 | 3330 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 3330 | 3331 | const int_info = lhs_ty.intInfo(self.target.*); |
| 3331 | 3332 | if (int_info.bits <= 32) { |
| 3332 | 3333 | // TODO add optimisations for multiplication |
| 3333 | 3334 | // with immediates, for example a * 2 can be |
| 3334 | 3335 | // lowered to a << 1 |
| 3335 | | return try self.binOpRegisterNew(.mul, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 3336 | return try self.binOpRegister(.mul, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 3336 | 3337 | } else { |
| 3337 | 3338 | return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); |
| 3338 | 3339 | } |
| ... | ... | @@ -3361,22 +3362,62 @@ fn divFloat( |
| 3361 | 3362 | } |
| 3362 | 3363 | } |
| 3363 | 3364 | |
| 3364 | | fn div( |
| 3365 | fn divTrunc( |
| 3365 | 3366 | self: *Self, |
| 3366 | | tag: Air.Inst.Tag, |
| 3367 | 3367 | lhs_bind: ReadArg.Bind, |
| 3368 | 3368 | rhs_bind: ReadArg.Bind, |
| 3369 | 3369 | lhs_ty: Type, |
| 3370 | 3370 | rhs_ty: Type, |
| 3371 | 3371 | maybe_inst: ?Air.Inst.Index, |
| 3372 | 3372 | ) InnerError!MCValue { |
| 3373 | | _ = tag; |
| 3373 | const mod = self.bin_file.options.module.?; |
| 3374 | switch (lhs_ty.zigTypeTag()) { |
| 3375 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3376 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3377 | .Int => { |
| 3378 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 3379 | const int_info = lhs_ty.intInfo(self.target.*); |
| 3380 | if (int_info.bits <= 32) { |
| 3381 | switch (int_info.signedness) { |
| 3382 | .signed => { |
| 3383 | return self.fail("TODO ARM signed integer division", .{}); |
| 3384 | }, |
| 3385 | .unsigned => { |
| 3386 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); |
| 3387 | |
| 3388 | if (rhs_immediate) |imm| { |
| 3389 | if (std.math.isPowerOfTwo(imm)) { |
| 3390 | const shift = std.math.log2_int(u32, imm); |
| 3391 | return try self.binOpImmediate(.lsr, lhs_bind, shift, lhs_ty, false, maybe_inst); |
| 3392 | } else { |
| 3393 | return self.fail("TODO ARM integer division by constants", .{}); |
| 3394 | } |
| 3395 | } else { |
| 3396 | return self.fail("TODO ARM integer division", .{}); |
| 3397 | } |
| 3398 | }, |
| 3399 | } |
| 3400 | } else { |
| 3401 | return self.fail("TODO ARM integer division for integers > u32/i32", .{}); |
| 3402 | } |
| 3403 | }, |
| 3404 | else => unreachable, |
| 3405 | } |
| 3406 | } |
| 3374 | 3407 | |
| 3408 | fn divFloor( |
| 3409 | self: *Self, |
| 3410 | lhs_bind: ReadArg.Bind, |
| 3411 | rhs_bind: ReadArg.Bind, |
| 3412 | lhs_ty: Type, |
| 3413 | rhs_ty: Type, |
| 3414 | maybe_inst: ?Air.Inst.Index, |
| 3415 | ) InnerError!MCValue { |
| 3416 | const mod = self.bin_file.options.module.?; |
| 3375 | 3417 | switch (lhs_ty.zigTypeTag()) { |
| 3376 | 3418 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3377 | 3419 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3378 | 3420 | .Int => { |
| 3379 | | const mod = self.bin_file.options.module.?; |
| 3380 | 3421 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 3381 | 3422 | const int_info = lhs_ty.intInfo(self.target.*); |
| 3382 | 3423 | if (int_info.bits <= 32) { |
| ... | ... | @@ -3390,7 +3431,7 @@ fn div( |
| 3390 | 3431 | if (rhs_immediate) |imm| { |
| 3391 | 3432 | if (std.math.isPowerOfTwo(imm)) { |
| 3392 | 3433 | const shift = std.math.log2_int(u32, imm); |
| 3393 | | return try self.binOpImmediateNew(.lsr, lhs_bind, shift, lhs_ty, false, maybe_inst); |
| 3434 | return try self.binOpImmediate(.lsr, lhs_bind, shift, lhs_ty, false, maybe_inst); |
| 3394 | 3435 | } else { |
| 3395 | 3436 | return self.fail("TODO ARM integer division by constants", .{}); |
| 3396 | 3437 | } |
| ... | ... | @@ -3436,11 +3477,11 @@ fn rem( |
| 3436 | 3477 | rhs_ty: Type, |
| 3437 | 3478 | maybe_inst: ?Air.Inst.Index, |
| 3438 | 3479 | ) InnerError!MCValue { |
| 3480 | const mod = self.bin_file.options.module.?; |
| 3439 | 3481 | switch (lhs_ty.zigTypeTag()) { |
| 3440 | 3482 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3441 | 3483 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3442 | 3484 | .Int => { |
| 3443 | | const mod = self.bin_file.options.module.?; |
| 3444 | 3485 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 3445 | 3486 | const int_info = lhs_ty.intInfo(self.target.*); |
| 3446 | 3487 | if (int_info.bits <= 32) { |
| ... | ... | @@ -3522,28 +3563,26 @@ fn wrappingArithmetic( |
| 3522 | 3563 | rhs_ty: Type, |
| 3523 | 3564 | maybe_inst: ?Air.Inst.Index, |
| 3524 | 3565 | ) InnerError!MCValue { |
| 3525 | | const base_tag: Air.Inst.Tag = switch (tag) { |
| 3526 | | .addwrap => .add, |
| 3527 | | .subwrap => .sub, |
| 3528 | | .mulwrap => .mul, |
| 3529 | | else => unreachable, |
| 3530 | | }; |
| 3531 | | |
| 3532 | | // Generate an add/sub/mul |
| 3533 | | const result = try self.addSub(base_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 3534 | | |
| 3535 | | // Truncate if necessary |
| 3536 | 3566 | switch (lhs_ty.zigTypeTag()) { |
| 3537 | 3567 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3538 | 3568 | .Int => { |
| 3539 | 3569 | const int_info = lhs_ty.intInfo(self.target.*); |
| 3540 | 3570 | if (int_info.bits <= 32) { |
| 3541 | | const result_reg = result.register; |
| 3571 | // Generate an add/sub/mul |
| 3572 | const result: MCValue = switch (tag) { |
| 3573 | .addwrap => try self.addSub(.add, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst), |
| 3574 | .subwrap => try self.addSub(.sub, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst), |
| 3575 | .mulwrap => try self.mul(lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst), |
| 3576 | else => unreachable, |
| 3577 | }; |
| 3542 | 3578 | |
| 3579 | // Truncate if necessary |
| 3580 | const result_reg = result.register; |
| 3543 | 3581 | if (int_info.bits < 32) { |
| 3544 | 3582 | try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits); |
| 3545 | | return result; |
| 3546 | | } else return result; |
| 3583 | } |
| 3584 | |
| 3585 | return result; |
| 3547 | 3586 | } else { |
| 3548 | 3587 | return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); |
| 3549 | 3588 | } |
| ... | ... | @@ -3582,12 +3621,12 @@ fn bitwise( |
| 3582 | 3621 | }; |
| 3583 | 3622 | |
| 3584 | 3623 | if (rhs_immediate_ok) { |
| 3585 | | return try self.binOpImmediateNew(mir_tag, lhs_bind, rhs_immediate.?, lhs_ty, false, maybe_inst); |
| 3624 | return try self.binOpImmediate(mir_tag, lhs_bind, rhs_immediate.?, lhs_ty, false, maybe_inst); |
| 3586 | 3625 | } else if (lhs_immediate_ok) { |
| 3587 | 3626 | // swap lhs and rhs |
| 3588 | | return try self.binOpImmediateNew(mir_tag, rhs_bind, lhs_immediate.?, rhs_ty, true, maybe_inst); |
| 3627 | return try self.binOpImmediate(mir_tag, rhs_bind, lhs_immediate.?, rhs_ty, true, maybe_inst); |
| 3589 | 3628 | } else { |
| 3590 | | return try self.binOpRegisterNew(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 3629 | return try self.binOpRegister(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 3591 | 3630 | } |
| 3592 | 3631 | } else { |
| 3593 | 3632 | return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); |
| ... | ... | @@ -3623,9 +3662,9 @@ fn shiftExact( |
| 3623 | 3662 | }; |
| 3624 | 3663 | |
| 3625 | 3664 | if (rhs_immediate) |imm| { |
| 3626 | | return try self.binOpImmediateNew(mir_tag, lhs_bind, imm, lhs_ty, false, maybe_inst); |
| 3665 | return try self.binOpImmediate(mir_tag, lhs_bind, imm, lhs_ty, false, maybe_inst); |
| 3627 | 3666 | } else { |
| 3628 | | return try self.binOpRegisterNew(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 3667 | return try self.binOpRegister(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 3629 | 3668 | } |
| 3630 | 3669 | } else { |
| 3631 | 3670 | return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); |
| ... | ... | @@ -3644,34 +3683,34 @@ fn shiftNormal( |
| 3644 | 3683 | rhs_ty: Type, |
| 3645 | 3684 | maybe_inst: ?Air.Inst.Index, |
| 3646 | 3685 | ) InnerError!MCValue { |
| 3647 | | const base_tag: Air.Inst.Tag = switch (tag) { |
| 3648 | | .shl => .shl_exact, |
| 3649 | | .shr => .shr_exact, |
| 3650 | | else => unreachable, |
| 3651 | | }; |
| 3652 | | |
| 3653 | | // Generate a shl_exact/shr_exact |
| 3654 | | const result = try self.shiftExact(base_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 3686 | switch (lhs_ty.zigTypeTag()) { |
| 3687 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3688 | .Int => { |
| 3689 | const int_info = lhs_ty.intInfo(self.target.*); |
| 3690 | if (int_info.bits <= 32) { |
| 3691 | // Generate a shl_exact/shr_exact |
| 3692 | const result: MCValue = switch (tag) { |
| 3693 | .shl => try self.shiftExact(.shl_exact, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst), |
| 3694 | .shr => try self.shiftExact(.shr_exact, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst), |
| 3695 | else => unreachable, |
| 3696 | }; |
| 3655 | 3697 | |
| 3656 | | // Truncate if necessary |
| 3657 | | switch (tag) { |
| 3658 | | .shr => return result, |
| 3659 | | .shl => switch (lhs_ty.zigTypeTag()) { |
| 3660 | | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3661 | | .Int => { |
| 3662 | | const int_info = lhs_ty.intInfo(self.target.*); |
| 3663 | | if (int_info.bits <= 32) { |
| 3664 | | const result_reg = result.register; |
| 3698 | // Truncate if necessary |
| 3699 | switch (tag) { |
| 3700 | .shr => return result, |
| 3701 | .shl => { |
| 3702 | const result_reg = result.register; |
| 3703 | if (int_info.bits < 32) { |
| 3704 | try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits); |
| 3705 | } |
| 3665 | 3706 | |
| 3666 | | if (int_info.bits < 32) { |
| 3667 | | try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits); |
| 3668 | 3707 | return result; |
| 3669 | | } else return result; |
| 3670 | | } else { |
| 3671 | | return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); |
| 3708 | }, |
| 3709 | else => unreachable, |
| 3672 | 3710 | } |
| 3673 | | }, |
| 3674 | | else => unreachable, |
| 3711 | } else { |
| 3712 | return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); |
| 3713 | } |
| 3675 | 3714 | }, |
| 3676 | 3715 | else => unreachable, |
| 3677 | 3716 | } |
| ... | ... | @@ -3698,12 +3737,12 @@ fn booleanOp( |
| 3698 | 3737 | }; |
| 3699 | 3738 | |
| 3700 | 3739 | if (rhs_immediate) |imm| { |
| 3701 | | return try self.binOpImmediateNew(mir_tag, lhs_bind, imm, lhs_ty, false, maybe_inst); |
| 3740 | return try self.binOpImmediate(mir_tag, lhs_bind, imm, lhs_ty, false, maybe_inst); |
| 3702 | 3741 | } else if (lhs_immediate) |imm| { |
| 3703 | 3742 | // swap lhs and rhs |
| 3704 | | return try self.binOpImmediateNew(mir_tag, rhs_bind, imm, rhs_ty, true, maybe_inst); |
| 3743 | return try self.binOpImmediate(mir_tag, rhs_bind, imm, rhs_ty, true, maybe_inst); |
| 3705 | 3744 | } else { |
| 3706 | | return try self.binOpRegisterNew(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 3745 | return try self.binOpRegister(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 3707 | 3746 | } |
| 3708 | 3747 | }, |
| 3709 | 3748 | else => unreachable, |