x86_64: implement @abs of big integers

This commit is contained in:
Jacob Young 2024-02-08 06:03:38 +01:00
parent 7c9a96111c
commit c6b3db8910

View File

@ -3919,7 +3919,7 @@ fn genSetFrameTruncatedOverflowCompare(
const rest_ty = try mod.intType(.unsigned, int_info.bits - hi_bits);
const temp_regs =
try self.register_manager.allocRegs(3, .{ null, null, null }, abi.RegisterClass.gp);
try self.register_manager.allocRegs(3, .{null} ** 3, abi.RegisterClass.gp);
const temp_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs);
defer for (temp_locks) |lock| self.register_manager.unlockReg(lock);
@ -4000,11 +4000,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
const lhs_mcv = try self.resolveInst(bin_op.lhs);
const rhs_mcv = try self.resolveInst(bin_op.rhs);
const temp_regs = try self.register_manager.allocRegs(
4,
.{ null, null, null, null },
abi.RegisterClass.gp,
);
const temp_regs =
try self.register_manager.allocRegs(4, .{null} ** 4, abi.RegisterClass.gp);
const temp_locks = self.register_manager.lockRegsAssumeUnused(4, temp_regs);
defer for (temp_locks) |lock| self.register_manager.unlockReg(lock);
@ -6582,6 +6579,7 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void {
const mir_tag = @as(?Mir.Inst.FixedTag, switch (ty.zigTypeTag(mod)) {
else => null,
.Int => switch (ty.abiSize(mod)) {
0 => unreachable,
1...8 => {
try self.spillEflagsIfOccupied();
const src_mcv = try self.resolveInst(ty_op.operand);
@ -6647,7 +6645,64 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void {
break :result dst_mcv;
},
else => return self.fail("TODO implement abs for {}", .{ty.fmt(mod)}),
else => {
const abi_size: u31 = @intCast(ty.abiSize(mod));
const limb_len = std.math.divCeil(u31, abi_size, 8) catch unreachable;
const tmp_regs =
try self.register_manager.allocRegs(3, .{null} ** 3, abi.RegisterClass.gp);
const tmp_locks = self.register_manager.lockRegsAssumeUnused(3, tmp_regs);
defer for (tmp_locks) |lock| self.register_manager.unlockReg(lock);
try self.spillEflagsIfOccupied();
const src_mcv = try self.resolveInst(ty_op.operand);
const dst_mcv = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
src_mcv
else
try self.allocRegOrMem(inst, false);
try self.asmMemoryImmediate(
.{ ._, .cmp },
try dst_mcv.address().offset((limb_len - 1) * 8).deref().mem(self, .qword),
Immediate.u(0),
);
const positive = try self.asmJccReloc(.ns, undefined);
try self.asmRegisterRegister(.{ ._, .xor }, tmp_regs[0].to32(), tmp_regs[0].to32());
try self.asmRegisterRegister(.{ ._, .xor }, tmp_regs[1].to8(), tmp_regs[1].to8());
const neg_loop: Mir.Inst.Index = @intCast(self.mir_instructions.len);
try self.asmRegisterRegister(.{ ._, .xor }, tmp_regs[2].to32(), tmp_regs[2].to32());
try self.asmRegisterImmediate(.{ ._r, .sh }, tmp_regs[1].to8(), Immediate.u(1));
try self.asmRegisterMemory(.{ ._, .sbb }, tmp_regs[2].to64(), .{
.base = .{ .frame = dst_mcv.load_frame.index },
.mod = .{ .rm = .{
.size = .qword,
.index = tmp_regs[0].to64(),
.scale = .@"8",
} },
});
try self.asmSetccRegister(.c, tmp_regs[1].to8());
try self.asmMemoryRegister(.{ ._, .mov }, .{
.base = .{ .frame = dst_mcv.load_frame.index },
.mod = .{ .rm = .{
.size = .qword,
.index = tmp_regs[0].to64(),
.scale = .@"8",
} },
}, tmp_regs[2].to64());
if (self.hasFeature(.slow_incdec)) {
try self.asmRegisterImmediate(.{ ._, .add }, tmp_regs[0].to32(), Immediate.u(1));
} else {
try self.asmRegister(.{ ._, .inc }, tmp_regs[0].to32());
}
try self.asmRegisterImmediate(.{ ._, .cmp }, tmp_regs[0].to32(), Immediate.u(limb_len));
_ = try self.asmJccReloc(.b, neg_loop);
try self.performReloc(positive);
break :result dst_mcv;
},
},
.Float => return self.floatSign(inst, ty_op.operand, ty),
.Vector => switch (ty.childType(mod).zigTypeTag(mod)) {
@ -7435,7 +7490,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
const dst_regs: [2]Register = if (field_rc.supersetOf(container_rc) and
self.reuseOperand(inst, operand, 0, src_mcv)) src_regs else dst: {
const dst_regs =
try self.register_manager.allocRegs(2, .{ null, null }, field_rc);
try self.register_manager.allocRegs(2, .{null} ** 2, field_rc);
const dst_locks = self.register_manager.lockRegsAssumeUnused(2, dst_regs);
defer for (dst_locks) |lock| self.register_manager.unlockReg(lock);
@ -8343,11 +8398,8 @@ fn genMulDivBinOp(
.{},
);
const temp_regs = try self.register_manager.allocRegs(
4,
.{ null, null, null, null },
abi.RegisterClass.gp,
);
const temp_regs =
try self.register_manager.allocRegs(4, .{null} ** 4, abi.RegisterClass.gp);
const temp_locks = self.register_manager.lockRegs(4, temp_regs);
defer for (temp_locks) |temp_lock| if (temp_lock) |lock|
self.register_manager.unlockReg(lock);
@ -8909,14 +8961,14 @@ fn genBinOp(
const locks = self.register_manager.lockRegsAssumeUnused(2, lhs_regs);
break :locks .{ locks[0], locks[1] };
},
else => .{ null, null },
else => .{null} ** 2,
};
defer for (lhs_locks) |lhs_lock| if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
const rhs_locks: [2]?RegisterLock = switch (rhs_mcv) {
.register => |rhs_reg| .{ self.register_manager.lockReg(rhs_reg), null },
.register_pair => |rhs_regs| self.register_manager.lockRegs(2, rhs_regs),
else => .{ null, null },
else => .{null} ** 2,
};
defer for (rhs_locks) |rhs_lock| if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
@ -8949,7 +9001,7 @@ fn genBinOp(
const dst_locks: [2]?RegisterLock = switch (dst_mcv) {
.register => |dst_reg| .{ self.register_manager.lockReg(dst_reg), null },
.register_pair => |dst_regs| self.register_manager.lockRegs(2, dst_regs),
else => .{ null, null },
else => .{null} ** 2,
};
defer for (dst_locks) |dst_lock| if (dst_lock) |lock| self.register_manager.unlockReg(lock);
@ -8965,7 +9017,7 @@ fn genBinOp(
const src_locks: [2]?RegisterLock = switch (src_mcv) {
.register => |src_reg| .{ self.register_manager.lockReg(src_reg), null },
.register_pair => |src_regs| self.register_manager.lockRegs(2, src_regs),
else => .{ null, null },
else => .{null} ** 2,
};
defer for (src_locks) |src_lock| if (src_lock) |lock| self.register_manager.unlockReg(lock);
@ -9025,7 +9077,7 @@ fn genBinOp(
else => dst: {
const dst_regs = try self.register_manager.allocRegs(
2,
.{ null, null },
.{null} ** 2,
abi.RegisterClass.gp,
);
const dst_regs_locks = self.register_manager.lockRegs(2, dst_regs);
@ -11631,7 +11683,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
const regs = try self.register_manager.allocRegs(
2,
.{ null, null },
.{null} ** 2,
abi.RegisterClass.gp,
);
const acc_reg = regs[0].to64();
@ -16298,7 +16350,7 @@ fn airVaArg(self: *Self, inst: Air.Inst.Index) !void {
try self.spillEflagsIfOccupied();
const tmp_regs =
try self.register_manager.allocRegs(2, .{ null, null }, abi.RegisterClass.gp);
try self.register_manager.allocRegs(2, .{null} ** 2, abi.RegisterClass.gp);
const offset_reg = tmp_regs[0].to32();
const addr_reg = tmp_regs[1].to64();
const tmp_locks = self.register_manager.lockRegsAssumeUnused(2, tmp_regs);