Commit 508b90fcfa
Changed files (3)
src
arch
aarch64
src/arch/aarch64/CodeGen.zig
@@ -1038,6 +1038,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
const operand_info = operand_ty.intInfo(self.target.*);
const dest_ty = self.air.typeOfIndex(inst);
+ const dest_abi_size = dest_ty.abiSize(self.target.*);
const dest_info = dest_ty.intInfo(self.target.*);
const result: MCValue = result: {
@@ -1047,16 +1048,21 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
};
defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
+ const truncated: MCValue = switch (operand_mcv) {
+ .register => |r| MCValue{ .register = registerAlias(r, dest_abi_size) },
+ else => operand_mcv,
+ };
+
if (dest_info.bits > operand_info.bits) {
const dest_mcv = try self.allocRegOrMem(inst, true);
- try self.setRegOrMem(self.air.typeOfIndex(inst), dest_mcv, operand_mcv);
+ try self.setRegOrMem(self.air.typeOfIndex(inst), dest_mcv, truncated);
break :result dest_mcv;
} else {
- if (self.reuseOperand(inst, operand, 0, operand_mcv)) {
- break :result operand_mcv;
+ if (self.reuseOperand(inst, operand, 0, truncated)) {
+ break :result truncated;
} else {
const dest_mcv = try self.allocRegOrMem(inst, true);
- try self.setRegOrMem(self.air.typeOfIndex(inst), dest_mcv, operand_mcv);
+ try self.setRegOrMem(self.air.typeOfIndex(inst), dest_mcv, truncated);
break :result dest_mcv;
}
}
@@ -1145,7 +1151,7 @@ fn trunc(
return MCValue{ .register = dest_reg };
} else {
- return self.fail("TODO: truncate to ints > 32 bits", .{});
+ return self.fail("TODO: truncate to ints > 64 bits", .{});
}
}
@@ -1679,14 +1685,67 @@ fn binOp(
.Int => {
assert(lhs_ty.eql(rhs_ty, mod));
const int_info = lhs_ty.intInfo(self.target.*);
- if (int_info.bits <= 32) {
- switch (int_info.signedness) {
- .signed => {
- return self.fail("TODO rem/mod on signed integers", .{});
- },
- .unsigned => {
- return self.fail("TODO rem/mod on unsigned integers", .{});
- },
+ if (int_info.bits <= 64) {
+ if (int_info.signedness == .signed and tag == .mod) {
+ return self.fail("TODO mod on signed integers", .{});
+ } else {
+ const lhs_is_register = lhs == .register;
+ const rhs_is_register = rhs == .register;
+
+ const lhs_lock: ?RegisterLock = if (lhs_is_register)
+ self.register_manager.lockReg(lhs.register)
+ else
+ null;
+ defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
+
+ const lhs_reg = if (lhs_is_register)
+ lhs.register
+ else
+ try self.register_manager.allocReg(null, gp);
+ const new_lhs_lock = self.register_manager.lockReg(lhs_reg);
+ defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
+
+ const rhs_reg = if (rhs_is_register)
+ rhs.register
+ else
+ try self.register_manager.allocReg(null, gp);
+ const new_rhs_lock = self.register_manager.lockReg(rhs_reg);
+ defer if (new_rhs_lock) |reg| self.register_manager.unlockReg(reg);
+
+ const dest_regs = try self.register_manager.allocRegs(2, .{ null, null }, gp);
+ const dest_regs_locks = self.register_manager.lockRegsAssumeUnused(2, dest_regs);
+ defer for (dest_regs_locks) |reg| {
+ self.register_manager.unlockReg(reg);
+ };
+ const quotient_reg = dest_regs[0];
+ const remainder_reg = dest_regs[1];
+
+ if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
+ if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
+
+ _ = try self.addInst(.{
+ .tag = switch (int_info.signedness) {
+ .signed => .sdiv,
+ .unsigned => .udiv,
+ },
+ .data = .{ .rrr = .{
+ .rd = quotient_reg,
+ .rn = lhs_reg,
+ .rm = rhs_reg,
+ } },
+ });
+
+ _ = try self.addInst(.{
+ .tag = .msub,
+ .data = .{ .rrrr = .{
+ .rd = remainder_reg,
+ .rn = quotient_reg,
+ .rm = rhs_reg,
+ .ra = lhs_reg,
+ } },
+ });
+
+ return MCValue{ .register = remainder_reg };
}
} else {
return self.fail("TODO rem/mod for integers with bits > 64", .{});
src/arch/aarch64/Emit.zig
@@ -190,6 +190,7 @@ pub fn emitMir(
.movk => try emit.mirMoveWideImmediate(inst),
.movz => try emit.mirMoveWideImmediate(inst),
+ .msub => try emit.mirDataProcessing3Source(inst),
.mul => try emit.mirDataProcessing3Source(inst),
.smulh => try emit.mirDataProcessing3Source(inst),
.smull => try emit.mirDataProcessing3Source(inst),
@@ -1140,14 +1141,31 @@ fn mirMoveWideImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
fn mirDataProcessing3Source(emit: *Emit, inst: Mir.Inst.Index) !void {
const tag = emit.mir.instructions.items(.tag)[inst];
- const rrr = emit.mir.instructions.items(.data)[inst].rrr;
switch (tag) {
- .mul => try emit.writeInstruction(Instruction.mul(rrr.rd, rrr.rn, rrr.rm)),
- .smulh => try emit.writeInstruction(Instruction.smulh(rrr.rd, rrr.rn, rrr.rm)),
- .smull => try emit.writeInstruction(Instruction.smull(rrr.rd, rrr.rn, rrr.rm)),
- .umulh => try emit.writeInstruction(Instruction.umulh(rrr.rd, rrr.rn, rrr.rm)),
- .umull => try emit.writeInstruction(Instruction.umull(rrr.rd, rrr.rn, rrr.rm)),
+ .mul,
+ .smulh,
+ .smull,
+ .umulh,
+ .umull,
+ => {
+ const rrr = emit.mir.instructions.items(.data)[inst].rrr;
+ switch (tag) {
+ .mul => try emit.writeInstruction(Instruction.mul(rrr.rd, rrr.rn, rrr.rm)),
+ .smulh => try emit.writeInstruction(Instruction.smulh(rrr.rd, rrr.rn, rrr.rm)),
+ .smull => try emit.writeInstruction(Instruction.smull(rrr.rd, rrr.rn, rrr.rm)),
+ .umulh => try emit.writeInstruction(Instruction.umulh(rrr.rd, rrr.rn, rrr.rm)),
+ .umull => try emit.writeInstruction(Instruction.umull(rrr.rd, rrr.rn, rrr.rm)),
+ else => unreachable,
+ }
+ },
+ .msub => {
+ const rrrr = emit.mir.instructions.items(.data)[inst].rrrr;
+ switch (tag) {
+ .msub => try emit.writeInstruction(Instruction.msub(rrrr.rd, rrrr.rn, rrrr.rm, rrrr.ra)),
+ else => unreachable,
+ }
+ },
else => unreachable,
}
}
src/arch/aarch64/Mir.zig
@@ -148,6 +148,8 @@ pub const Inst = struct {
movk,
/// Move wide with zero
movz,
+ /// Multiply-subtract
+ msub,
/// Multiply
mul,
/// Bitwise NOT
@@ -446,6 +448,15 @@ pub const Inst = struct {
rn: Register,
offset: bits.Instruction.LoadStorePairOffset,
},
+ /// Four registers
+ ///
+ /// Used by e.g. msub
+ rrrr: struct {
+ rd: Register,
+ rn: Register,
+ rm: Register,
+ ra: Register,
+ },
/// Debug info: line and column
///
/// Used by e.g. dbg_line