| ... | @@ -1550,28 +1550,161 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1550,28 +1550,161 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 1550 | | 1550 | |
| 1551 | fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { | 1551 | fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1552 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1552 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1553 | const result: MCValue = if (self.liveness.isUnused(inst)) | 1553 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1554 | .dead | 1554 | const ty = self.air.typeOf(bin_op.lhs); |
| 1555 | else | 1555 | |
| 1556 | return self.fail("TODO implement add_sat for {}", .{self.target.cpu.arch}); | 1556 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| | 1557 | const dst_mcv = if (lhs_mcv.isRegister() and self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv)) |
| | 1558 | lhs_mcv |
| | 1559 | else |
| | 1560 | try self.copyToRegisterWithInstTracking(inst, ty, lhs_mcv); |
| | 1561 | const dst_reg = dst_mcv.register; |
| | 1562 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| | 1563 | defer self.register_manager.unlockReg(dst_lock); |
| | 1564 | |
| | 1565 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| | 1566 | const rhs_lock = switch (rhs_mcv) { |
| | 1567 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| | 1568 | else => null, |
| | 1569 | }; |
| | 1570 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| | 1571 | |
| | 1572 | const limit_reg = try self.register_manager.allocReg(null, gp); |
| | 1573 | const limit_mcv = MCValue{ .register = limit_reg }; |
| | 1574 | const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg); |
| | 1575 | defer self.register_manager.unlockReg(limit_lock); |
| | 1576 | |
| | 1577 | const reg_bits = self.regBitSize(ty); |
| | 1578 | const cc: Condition = if (ty.isSignedInt()) cc: { |
| | 1579 | try self.genSetReg(ty, limit_reg, dst_mcv); |
| | 1580 | try self.genBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); |
| | 1581 | try self.genBinOpMir(.xor, ty, limit_mcv, .{ |
| | 1582 | .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1, |
| | 1583 | }); |
| | 1584 | break :cc .o; |
| | 1585 | } else cc: { |
| | 1586 | try self.genSetReg(ty, limit_reg, .{ |
| | 1587 | .immediate = @as(u64, std.math.maxInt(u64)) >> @intCast(u6, 64 - reg_bits), |
| | 1588 | }); |
| | 1589 | break :cc .c; |
| | 1590 | }; |
| | 1591 | try self.genBinOpMir(.add, ty, dst_mcv, rhs_mcv); |
| | 1592 | |
| | 1593 | const abi_size = @intCast(u32, @max(ty.abiSize(self.target.*), 2)); |
| | 1594 | try self.asmCmovccRegisterRegister( |
| | 1595 | registerAlias(dst_reg, abi_size), |
| | 1596 | registerAlias(limit_reg, abi_size), |
| | 1597 | cc, |
| | 1598 | ); |
| | 1599 | break :result dst_mcv; |
| | 1600 | }; |
| 1557 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1601 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1558 | } | 1602 | } |
| 1559 | | 1603 | |
| 1560 | fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { | 1604 | fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1561 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1605 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1562 | const result: MCValue = if (self.liveness.isUnused(inst)) | 1606 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1563 | .dead | 1607 | const ty = self.air.typeOf(bin_op.lhs); |
| 1564 | else | 1608 | |
| 1565 | return self.fail("TODO implement sub_sat for {}", .{self.target.cpu.arch}); | 1609 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| | 1610 | const dst_mcv = if (lhs_mcv.isRegister() and self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv)) |
| | 1611 | lhs_mcv |
| | 1612 | else |
| | 1613 | try self.copyToRegisterWithInstTracking(inst, ty, lhs_mcv); |
| | 1614 | const dst_reg = dst_mcv.register; |
| | 1615 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| | 1616 | defer self.register_manager.unlockReg(dst_lock); |
| | 1617 | |
| | 1618 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| | 1619 | const rhs_lock = switch (rhs_mcv) { |
| | 1620 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| | 1621 | else => null, |
| | 1622 | }; |
| | 1623 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| | 1624 | |
| | 1625 | const limit_reg = try self.register_manager.allocReg(null, gp); |
| | 1626 | const limit_mcv = MCValue{ .register = limit_reg }; |
| | 1627 | const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg); |
| | 1628 | defer self.register_manager.unlockReg(limit_lock); |
| | 1629 | |
| | 1630 | const reg_bits = self.regBitSize(ty); |
| | 1631 | const cc: Condition = if (ty.isSignedInt()) cc: { |
| | 1632 | try self.genSetReg(ty, limit_reg, dst_mcv); |
| | 1633 | try self.genBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); |
| | 1634 | try self.genBinOpMir(.xor, ty, limit_mcv, .{ |
| | 1635 | .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1, |
| | 1636 | }); |
| | 1637 | break :cc .o; |
| | 1638 | } else cc: { |
| | 1639 | try self.genSetReg(ty, limit_reg, .{ .immediate = 0 }); |
| | 1640 | break :cc .c; |
| | 1641 | }; |
| | 1642 | try self.genBinOpMir(.sub, ty, dst_mcv, rhs_mcv); |
| | 1643 | |
| | 1644 | const abi_size = @intCast(u32, @max(ty.abiSize(self.target.*), 2)); |
| | 1645 | try self.asmCmovccRegisterRegister( |
| | 1646 | registerAlias(dst_reg, abi_size), |
| | 1647 | registerAlias(limit_reg, abi_size), |
| | 1648 | cc, |
| | 1649 | ); |
| | 1650 | break :result dst_mcv; |
| | 1651 | }; |
| 1566 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1652 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1567 | } | 1653 | } |
| 1568 | | 1654 | |
| 1569 | fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { | 1655 | fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1570 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1656 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1571 | const result: MCValue = if (self.liveness.isUnused(inst)) | 1657 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1572 | .dead | 1658 | const ty = self.air.typeOf(bin_op.lhs); |
| 1573 | else | 1659 | |
| 1574 | return self.fail("TODO implement mul_sat for {}", .{self.target.cpu.arch}); | 1660 | try self.spillRegisters(&.{ .rax, .rdx }); |
| | 1661 | const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx }); |
| | 1662 | defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| | 1663 | |
| | 1664 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| | 1665 | const lhs_lock = switch (lhs_mcv) { |
| | 1666 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| | 1667 | else => null, |
| | 1668 | }; |
| | 1669 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| | 1670 | |
| | 1671 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| | 1672 | const rhs_lock = switch (rhs_mcv) { |
| | 1673 | .register => |reg| self.register_manager.lockReg(reg), |
| | 1674 | else => null, |
| | 1675 | }; |
| | 1676 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| | 1677 | |
| | 1678 | const limit_reg = try self.register_manager.allocReg(null, gp); |
| | 1679 | const limit_mcv = MCValue{ .register = limit_reg }; |
| | 1680 | const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg); |
| | 1681 | defer self.register_manager.unlockReg(limit_lock); |
| | 1682 | |
| | 1683 | const reg_bits = self.regBitSize(ty); |
| | 1684 | const cc: Condition = if (ty.isSignedInt()) cc: { |
| | 1685 | try self.genSetReg(ty, limit_reg, lhs_mcv); |
| | 1686 | try self.genBinOpMir(.xor, ty, limit_mcv, rhs_mcv); |
| | 1687 | try self.genBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); |
| | 1688 | try self.genBinOpMir(.xor, ty, limit_mcv, .{ |
| | 1689 | .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1, |
| | 1690 | }); |
| | 1691 | break :cc .o; |
| | 1692 | } else cc: { |
| | 1693 | try self.genSetReg(ty, limit_reg, .{ |
| | 1694 | .immediate = @as(u64, std.math.maxInt(u64)) >> @intCast(u6, 64 - reg_bits), |
| | 1695 | }); |
| | 1696 | break :cc .c; |
| | 1697 | }; |
| | 1698 | |
| | 1699 | const dst_mcv = try self.genMulDivBinOp(.mul, inst, ty, lhs_mcv, rhs_mcv); |
| | 1700 | const abi_size = @intCast(u32, @max(ty.abiSize(self.target.*), 2)); |
| | 1701 | try self.asmCmovccRegisterRegister( |
| | 1702 | registerAlias(dst_mcv.register, abi_size), |
| | 1703 | registerAlias(limit_reg, abi_size), |
| | 1704 | cc, |
| | 1705 | ); |
| | 1706 | break :result dst_mcv; |
| | 1707 | }; |
| 1575 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1708 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1576 | } | 1709 | } |
| 1577 | | 1710 | |
| ... | @@ -3915,7 +4048,8 @@ fn genMulDivBinOp( | ... | @@ -3915,7 +4048,8 @@ fn genMulDivBinOp( |
| 3915 | if (ty.zigTypeTag() == .Vector or ty.zigTypeTag() == .Float) { | 4048 | if (ty.zigTypeTag() == .Vector or ty.zigTypeTag() == .Float) { |
| 3916 | return self.fail("TODO implement genMulDivBinOp for {}", .{ty.fmtDebug()}); | 4049 | return self.fail("TODO implement genMulDivBinOp for {}", .{ty.fmtDebug()}); |
| 3917 | } | 4050 | } |
| 3918 | if (ty.abiSize(self.target.*) > 8) { | 4051 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); |
| | 4052 | if (abi_size > 8) { |
| 3919 | return self.fail("TODO implement genMulDivBinOp for {}", .{ty.fmtDebug()}); | 4053 | return self.fail("TODO implement genMulDivBinOp for {}", .{ty.fmtDebug()}); |
| 3920 | } | 4054 | } |
| 3921 | if (tag == .div_float) { | 4055 | if (tag == .div_float) { |
| ... | @@ -3925,10 +4059,8 @@ fn genMulDivBinOp( | ... | @@ -3925,10 +4059,8 @@ fn genMulDivBinOp( |
| 3925 | assert(self.register_manager.isRegFree(.rax)); | 4059 | assert(self.register_manager.isRegFree(.rax)); |
| 3926 | assert(self.register_manager.isRegFree(.rdx)); | 4060 | assert(self.register_manager.isRegFree(.rdx)); |
| 3927 | | 4061 | |
| 3928 | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); | 4062 | const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx }); |
| 3929 | defer for (reg_locks) |reg| { | 4063 | defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 3930 | self.register_manager.unlockReg(reg); | | |
| 3931 | }; | | |
| 3932 | | 4064 | |
| 3933 | const int_info = ty.intInfo(self.target.*); | 4065 | const int_info = ty.intInfo(self.target.*); |
| 3934 | const signedness = int_info.signedness; | 4066 | const signedness = int_info.signedness; |
| ... | @@ -3953,35 +4085,24 @@ fn genMulDivBinOp( | ... | @@ -3953,35 +4085,24 @@ fn genMulDivBinOp( |
| 3953 | | 4085 | |
| 3954 | const mir_tag: Mir.Inst.Tag = switch (signedness) { | 4086 | const mir_tag: Mir.Inst.Tag = switch (signedness) { |
| 3955 | .signed => switch (tag) { | 4087 | .signed => switch (tag) { |
| 3956 | .mul, .mulwrap => Mir.Inst.Tag.imul, | 4088 | .mul, .mulwrap => .imul, |
| 3957 | .div_trunc, .div_exact, .rem => Mir.Inst.Tag.idiv, | 4089 | .div_trunc, .div_exact, .rem => .idiv, |
| 3958 | else => unreachable, | 4090 | else => unreachable, |
| 3959 | }, | 4091 | }, |
| 3960 | .unsigned => switch (tag) { | 4092 | .unsigned => switch (tag) { |
| 3961 | .mul, .mulwrap => Mir.Inst.Tag.mul, | 4093 | .mul, .mulwrap => .mul, |
| 3962 | .div_trunc, .div_exact, .rem => Mir.Inst.Tag.div, | 4094 | .div_trunc, .div_exact, .rem => .div, |
| 3963 | else => unreachable, | 4095 | else => unreachable, |
| 3964 | }, | 4096 | }, |
| 3965 | }; | 4097 | }; |
| 3966 | | 4098 | |
| 3967 | try self.genIntMulDivOpMir(mir_tag, ty, .signed, lhs, rhs); | 4099 | try self.genIntMulDivOpMir(mir_tag, ty, .signed, lhs, rhs); |
| 3968 | | 4100 | |
| 3969 | switch (signedness) { | 4101 | return .{ .register = registerAlias(switch (tag) { |
| 3970 | .signed => switch (tag) { | 4102 | .mul, .mulwrap, .div_trunc, .div_exact => .rax, |
| 3971 | .mul, .mulwrap, .div_trunc, .div_exact => return MCValue{ .register = .rax }, | 4103 | .rem => .rdx, |
| 3972 | .rem => return MCValue{ .register = .rdx }, | 4104 | else => unreachable, |
| 3973 | else => unreachable, | 4105 | }, abi_size) }; |
| 3974 | }, | | |
| 3975 | .unsigned => switch (tag) { | | |
| 3976 | .mul, .mulwrap, .div_trunc, .div_exact => return MCValue{ | | |
| 3977 | .register = registerAlias(.rax, @intCast(u32, ty.abiSize(self.target.*))), | | |
| 3978 | }, | | |
| 3979 | .rem => return MCValue{ | | |
| 3980 | .register = registerAlias(.rdx, @intCast(u32, ty.abiSize(self.target.*))), | | |
| 3981 | }, | | |
| 3982 | else => unreachable, | | |
| 3983 | }, | | |
| 3984 | } | | |
| 3985 | }, | 4106 | }, |
| 3986 | | 4107 | |
| 3987 | .mod => { | 4108 | .mod => { |
| ... | @@ -3998,14 +4119,14 @@ fn genMulDivBinOp( | ... | @@ -3998,14 +4119,14 @@ fn genMulDivBinOp( |
| 3998 | const result: MCValue = if (maybe_inst) |inst| | 4119 | const result: MCValue = if (maybe_inst) |inst| |
| 3999 | try self.copyToRegisterWithInstTracking(inst, ty, lhs) | 4120 | try self.copyToRegisterWithInstTracking(inst, ty, lhs) |
| 4000 | else | 4121 | else |
| 4001 | MCValue{ .register = try self.copyToTmpRegister(ty, lhs) }; | 4122 | .{ .register = try self.copyToTmpRegister(ty, lhs) }; |
| 4002 | try self.genBinOpMir(.sub, ty, result, div_floor); | 4123 | try self.genBinOpMir(.sub, ty, result, div_floor); |
| 4003 | | 4124 | |
| 4004 | return result; | 4125 | return result; |
| 4005 | }, | 4126 | }, |
| 4006 | .unsigned => { | 4127 | .unsigned => { |
| 4007 | try self.genIntMulDivOpMir(.div, ty, .unsigned, lhs, rhs); | 4128 | try self.genIntMulDivOpMir(.div, ty, .unsigned, lhs, rhs); |
| 4008 | return MCValue{ .register = registerAlias(.rdx, @intCast(u32, ty.abiSize(self.target.*))) }; | 4129 | return .{ .register = registerAlias(.rdx, abi_size) }; |
| 4009 | }, | 4130 | }, |
| 4010 | } | 4131 | } |
| 4011 | }, | 4132 | }, |