authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-08-05 15:22:53+02:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-08-05 20:30:52+02:00
log508b90fcfa4749b50618f947e2c3573edcf29713
treedb000a2abda242e0e8b7d0584e922fd1ea233479
parent8b24c783c5bd417f84beeb2f3736a78c3f595d22
signaturelock-open Commit is signed but in an unrecognized format.

stage2 AArch64: implement basic integer rem/mod


3 files changed, 107 insertions(+), 19 deletions(-)

src/arch/aarch64/CodeGen.zig+72-13
......@@ -1038,6 +1038,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
10381038 const operand_info = operand_ty.intInfo(self.target.*);
10391039
10401040 const dest_ty = self.air.typeOfIndex(inst);
1041 const dest_abi_size = dest_ty.abiSize(self.target.*);
10411042 const dest_info = dest_ty.intInfo(self.target.*);
10421043
10431044 const result: MCValue = result: {
......@@ -1047,16 +1048,21 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
10471048 };
10481049 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
10491050
1051 const truncated: MCValue = switch (operand_mcv) {
1052 .register => |r| MCValue{ .register = registerAlias(r, dest_abi_size) },
1053 else => operand_mcv,
1054 };
1055
10501056 if (dest_info.bits > operand_info.bits) {
10511057 const dest_mcv = try self.allocRegOrMem(inst, true);
1052 try self.setRegOrMem(self.air.typeOfIndex(inst), dest_mcv, operand_mcv);
1058 try self.setRegOrMem(self.air.typeOfIndex(inst), dest_mcv, truncated);
10531059 break :result dest_mcv;
10541060 } else {
1055 if (self.reuseOperand(inst, operand, 0, operand_mcv)) {
1056 break :result operand_mcv;
1061 if (self.reuseOperand(inst, operand, 0, truncated)) {
1062 break :result truncated;
10571063 } else {
10581064 const dest_mcv = try self.allocRegOrMem(inst, true);
1059 try self.setRegOrMem(self.air.typeOfIndex(inst), dest_mcv, operand_mcv);
1065 try self.setRegOrMem(self.air.typeOfIndex(inst), dest_mcv, truncated);
10601066 break :result dest_mcv;
10611067 }
10621068 }
......@@ -1145,7 +1151,7 @@ fn trunc(
11451151
11461152 return MCValue{ .register = dest_reg };
11471153 } else {
1148 return self.fail("TODO: truncate to ints > 32 bits", .{});
1154 return self.fail("TODO: truncate to ints > 64 bits", .{});
11491155 }
11501156}
11511157
......@@ -1679,14 +1685,67 @@ fn binOp(
16791685 .Int => {
16801686 assert(lhs_ty.eql(rhs_ty, mod));
16811687 const int_info = lhs_ty.intInfo(self.target.*);
1682 if (int_info.bits <= 32) {
1683 switch (int_info.signedness) {
1684 .signed => {
1685 return self.fail("TODO rem/mod on signed integers", .{});
1686 },
1687 .unsigned => {
1688 return self.fail("TODO rem/mod on unsigned integers", .{});
1689 },
1688 if (int_info.bits <= 64) {
1689 if (int_info.signedness == .signed and tag == .mod) {
1690 return self.fail("TODO mod on signed integers", .{});
1691 } else {
1692 const lhs_is_register = lhs == .register;
1693 const rhs_is_register = rhs == .register;
1694
1695 const lhs_lock: ?RegisterLock = if (lhs_is_register)
1696 self.register_manager.lockReg(lhs.register)
1697 else
1698 null;
1699 defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
1700
1701 const lhs_reg = if (lhs_is_register)
1702 lhs.register
1703 else
1704 try self.register_manager.allocReg(null, gp);
1705 const new_lhs_lock = self.register_manager.lockReg(lhs_reg);
1706 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
1707
1708 const rhs_reg = if (rhs_is_register)
1709 rhs.register
1710 else
1711 try self.register_manager.allocReg(null, gp);
1712 const new_rhs_lock = self.register_manager.lockReg(rhs_reg);
1713 defer if (new_rhs_lock) |reg| self.register_manager.unlockReg(reg);
1714
1715 const dest_regs = try self.register_manager.allocRegs(2, .{ null, null }, gp);
1716 const dest_regs_locks = self.register_manager.lockRegsAssumeUnused(2, dest_regs);
1717 defer for (dest_regs_locks) |reg| {
1718 self.register_manager.unlockReg(reg);
1719 };
1720 const quotient_reg = dest_regs[0];
1721 const remainder_reg = dest_regs[1];
1722
1723 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
1724 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
1725
1726 _ = try self.addInst(.{
1727 .tag = switch (int_info.signedness) {
1728 .signed => .sdiv,
1729 .unsigned => .udiv,
1730 },
1731 .data = .{ .rrr = .{
1732 .rd = quotient_reg,
1733 .rn = lhs_reg,
1734 .rm = rhs_reg,
1735 } },
1736 });
1737
1738 _ = try self.addInst(.{
1739 .tag = .msub,
1740 .data = .{ .rrrr = .{
1741 .rd = remainder_reg,
1742 .rn = quotient_reg,
1743 .rm = rhs_reg,
1744 .ra = lhs_reg,
1745 } },
1746 });
1747
1748 return MCValue{ .register = remainder_reg };
16901749 }
16911750 } else {
16921751 return self.fail("TODO rem/mod for integers with bits > 64", .{});
src/arch/aarch64/Emit.zig+24-6
......@@ -190,6 +190,7 @@ pub fn emitMir(
190190 .movk => try emit.mirMoveWideImmediate(inst),
191191 .movz => try emit.mirMoveWideImmediate(inst),
192192
193 .msub => try emit.mirDataProcessing3Source(inst),
193194 .mul => try emit.mirDataProcessing3Source(inst),
194195 .smulh => try emit.mirDataProcessing3Source(inst),
195196 .smull => try emit.mirDataProcessing3Source(inst),
......@@ -1140,14 +1141,31 @@ fn mirMoveWideImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
11401141
11411142fn mirDataProcessing3Source(emit: *Emit, inst: Mir.Inst.Index) !void {
11421143 const tag = emit.mir.instructions.items(.tag)[inst];
1143 const rrr = emit.mir.instructions.items(.data)[inst].rrr;
11441144
11451145 switch (tag) {
1146 .mul => try emit.writeInstruction(Instruction.mul(rrr.rd, rrr.rn, rrr.rm)),
1147 .smulh => try emit.writeInstruction(Instruction.smulh(rrr.rd, rrr.rn, rrr.rm)),
1148 .smull => try emit.writeInstruction(Instruction.smull(rrr.rd, rrr.rn, rrr.rm)),
1149 .umulh => try emit.writeInstruction(Instruction.umulh(rrr.rd, rrr.rn, rrr.rm)),
1150 .umull => try emit.writeInstruction(Instruction.umull(rrr.rd, rrr.rn, rrr.rm)),
1146 .mul,
1147 .smulh,
1148 .smull,
1149 .umulh,
1150 .umull,
1151 => {
1152 const rrr = emit.mir.instructions.items(.data)[inst].rrr;
1153 switch (tag) {
1154 .mul => try emit.writeInstruction(Instruction.mul(rrr.rd, rrr.rn, rrr.rm)),
1155 .smulh => try emit.writeInstruction(Instruction.smulh(rrr.rd, rrr.rn, rrr.rm)),
1156 .smull => try emit.writeInstruction(Instruction.smull(rrr.rd, rrr.rn, rrr.rm)),
1157 .umulh => try emit.writeInstruction(Instruction.umulh(rrr.rd, rrr.rn, rrr.rm)),
1158 .umull => try emit.writeInstruction(Instruction.umull(rrr.rd, rrr.rn, rrr.rm)),
1159 else => unreachable,
1160 }
1161 },
1162 .msub => {
1163 const rrrr = emit.mir.instructions.items(.data)[inst].rrrr;
1164 switch (tag) {
1165 .msub => try emit.writeInstruction(Instruction.msub(rrrr.rd, rrrr.rn, rrrr.rm, rrrr.ra)),
1166 else => unreachable,
1167 }
1168 },
11511169 else => unreachable,
11521170 }
11531171}
src/arch/aarch64/Mir.zig+11
......@@ -148,6 +148,8 @@ pub const Inst = struct {
148148 movk,
149149 /// Move wide with zero
150150 movz,
151 /// Multiply-subtract
152 msub,
151153 /// Multiply
152154 mul,
153155 /// Bitwise NOT
......@@ -446,6 +448,15 @@ pub const Inst = struct {
446448 rn: Register,
447449 offset: bits.Instruction.LoadStorePairOffset,
448450 },
451 /// Four registers
452 ///
453 /// Used by e.g. msub
454 rrrr: struct {
455 rd: Register,
456 rn: Register,
457 rm: Register,
458 ra: Register,
459 },
449460 /// Debug info: line and column
450461 ///
451462 /// Used by e.g. dbg_line