mirror of
https://github.com/ziglang/zig.git
synced 2026-01-10 09:25:11 +00:00
stage2 AArch64: implement basic integer rem/mod
This commit is contained in:
parent
8b24c783c5
commit
508b90fcfa
@ -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", .{});
|
||||
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user