stage2 AArch64: implement basic integer rem/mod

This commit is contained in:
joachimschmidt557 2022-08-05 15:22:53 +02:00
parent 8b24c783c5
commit 508b90fcfa
No known key found for this signature in database
GPG Key ID: E0B575BE2884ACC5
3 changed files with 107 additions and 19 deletions

View File

@ -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", .{});

View File

@ -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,
}
}

View File

@ -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