Skip to content

Commit 508b90f

Browse files
stage2 AArch64: implement basic integer rem/mod
1 parent 8b24c78 commit 508b90f

File tree

3 files changed

+107
-19
lines changed

3 files changed

+107
-19
lines changed

src/arch/aarch64/CodeGen.zig

Lines changed: 72 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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

11411142
fn 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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

0 commit comments

Comments
 (0)