authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-02-08 06:03:38+01:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-02-12 05:25:07+01:00
logc6b3db8910dc250a32aef49a2d5951bd0c24e5db
tree0ce12431eefad8a9727c4ce912c4e4010dd823af
parent7c9a96111c373599a55c9a04ea04f56b1dd76318

x86_64: implement `@abs` of big integers


1 files changed, 72 insertions(+), 20 deletions(-)

src/arch/x86_64/CodeGen.zig+72-20
...@@ -3919,7 +3919,7 @@ fn genSetFrameTruncatedOverflowCompare(...@@ -3919,7 +3919,7 @@ fn genSetFrameTruncatedOverflowCompare(
3919 const rest_ty = try mod.intType(.unsigned, int_info.bits - hi_bits);3919 const rest_ty = try mod.intType(.unsigned, int_info.bits - hi_bits);
39203920
3921 const temp_regs =3921 const temp_regs =
3922 try self.register_manager.allocRegs(3, .{ null, null, null }, abi.RegisterClass.gp);3922 try self.register_manager.allocRegs(3, .{null} ** 3, abi.RegisterClass.gp);
3923 const temp_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs);3923 const temp_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs);
3924 defer for (temp_locks) |lock| self.register_manager.unlockReg(lock);3924 defer for (temp_locks) |lock| self.register_manager.unlockReg(lock);
39253925
...@@ -4000,11 +4000,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -4000,11 +4000,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
4000 const lhs_mcv = try self.resolveInst(bin_op.lhs);4000 const lhs_mcv = try self.resolveInst(bin_op.lhs);
4001 const rhs_mcv = try self.resolveInst(bin_op.rhs);4001 const rhs_mcv = try self.resolveInst(bin_op.rhs);
40024002
4003 const temp_regs = try self.register_manager.allocRegs(4003 const temp_regs =
4004 4,4004 try self.register_manager.allocRegs(4, .{null} ** 4, abi.RegisterClass.gp);
4005 .{ null, null, null, null },
4006 abi.RegisterClass.gp,
4007 );
4008 const temp_locks = self.register_manager.lockRegsAssumeUnused(4, temp_regs);4005 const temp_locks = self.register_manager.lockRegsAssumeUnused(4, temp_regs);
4009 defer for (temp_locks) |lock| self.register_manager.unlockReg(lock);4006 defer for (temp_locks) |lock| self.register_manager.unlockReg(lock);
40104007
...@@ -6582,6 +6579,7 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void {...@@ -6582,6 +6579,7 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void {
6582 const mir_tag = @as(?Mir.Inst.FixedTag, switch (ty.zigTypeTag(mod)) {6579 const mir_tag = @as(?Mir.Inst.FixedTag, switch (ty.zigTypeTag(mod)) {
6583 else => null,6580 else => null,
6584 .Int => switch (ty.abiSize(mod)) {6581 .Int => switch (ty.abiSize(mod)) {
6582 0 => unreachable,
6585 1...8 => {6583 1...8 => {
6586 try self.spillEflagsIfOccupied();6584 try self.spillEflagsIfOccupied();
6587 const src_mcv = try self.resolveInst(ty_op.operand);6585 const src_mcv = try self.resolveInst(ty_op.operand);
...@@ -6647,7 +6645,64 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void {...@@ -6647,7 +6645,64 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void {
66476645
6648 break :result dst_mcv;6646 break :result dst_mcv;
6649 },6647 },
6650 else => return self.fail("TODO implement abs for {}", .{ty.fmt(mod)}),6648 else => {
6649 const abi_size: u31 = @intCast(ty.abiSize(mod));
6650 const limb_len = std.math.divCeil(u31, abi_size, 8) catch unreachable;
6651
6652 const tmp_regs =
6653 try self.register_manager.allocRegs(3, .{null} ** 3, abi.RegisterClass.gp);
6654 const tmp_locks = self.register_manager.lockRegsAssumeUnused(3, tmp_regs);
6655 defer for (tmp_locks) |lock| self.register_manager.unlockReg(lock);
6656
6657 try self.spillEflagsIfOccupied();
6658 const src_mcv = try self.resolveInst(ty_op.operand);
6659 const dst_mcv = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
6660 src_mcv
6661 else
6662 try self.allocRegOrMem(inst, false);
6663
6664 try self.asmMemoryImmediate(
6665 .{ ._, .cmp },
6666 try dst_mcv.address().offset((limb_len - 1) * 8).deref().mem(self, .qword),
6667 Immediate.u(0),
6668 );
6669 const positive = try self.asmJccReloc(.ns, undefined);
6670
6671 try self.asmRegisterRegister(.{ ._, .xor }, tmp_regs[0].to32(), tmp_regs[0].to32());
6672 try self.asmRegisterRegister(.{ ._, .xor }, tmp_regs[1].to8(), tmp_regs[1].to8());
6673
6674 const neg_loop: Mir.Inst.Index = @intCast(self.mir_instructions.len);
6675 try self.asmRegisterRegister(.{ ._, .xor }, tmp_regs[2].to32(), tmp_regs[2].to32());
6676 try self.asmRegisterImmediate(.{ ._r, .sh }, tmp_regs[1].to8(), Immediate.u(1));
6677 try self.asmRegisterMemory(.{ ._, .sbb }, tmp_regs[2].to64(), .{
6678 .base = .{ .frame = dst_mcv.load_frame.index },
6679 .mod = .{ .rm = .{
6680 .size = .qword,
6681 .index = tmp_regs[0].to64(),
6682 .scale = .@"8",
6683 } },
6684 });
6685 try self.asmSetccRegister(.c, tmp_regs[1].to8());
6686 try self.asmMemoryRegister(.{ ._, .mov }, .{
6687 .base = .{ .frame = dst_mcv.load_frame.index },
6688 .mod = .{ .rm = .{
6689 .size = .qword,
6690 .index = tmp_regs[0].to64(),
6691 .scale = .@"8",
6692 } },
6693 }, tmp_regs[2].to64());
6694
6695 if (self.hasFeature(.slow_incdec)) {
6696 try self.asmRegisterImmediate(.{ ._, .add }, tmp_regs[0].to32(), Immediate.u(1));
6697 } else {
6698 try self.asmRegister(.{ ._, .inc }, tmp_regs[0].to32());
6699 }
6700 try self.asmRegisterImmediate(.{ ._, .cmp }, tmp_regs[0].to32(), Immediate.u(limb_len));
6701 _ = try self.asmJccReloc(.b, neg_loop);
6702
6703 try self.performReloc(positive);
6704 break :result dst_mcv;
6705 },
6651 },6706 },
6652 .Float => return self.floatSign(inst, ty_op.operand, ty),6707 .Float => return self.floatSign(inst, ty_op.operand, ty),
6653 .Vector => switch (ty.childType(mod).zigTypeTag(mod)) {6708 .Vector => switch (ty.childType(mod).zigTypeTag(mod)) {
...@@ -7435,7 +7490,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -7435,7 +7490,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
7435 const dst_regs: [2]Register = if (field_rc.supersetOf(container_rc) and7490 const dst_regs: [2]Register = if (field_rc.supersetOf(container_rc) and
7436 self.reuseOperand(inst, operand, 0, src_mcv)) src_regs else dst: {7491 self.reuseOperand(inst, operand, 0, src_mcv)) src_regs else dst: {
7437 const dst_regs =7492 const dst_regs =
7438 try self.register_manager.allocRegs(2, .{ null, null }, field_rc);7493 try self.register_manager.allocRegs(2, .{null} ** 2, field_rc);
7439 const dst_locks = self.register_manager.lockRegsAssumeUnused(2, dst_regs);7494 const dst_locks = self.register_manager.lockRegsAssumeUnused(2, dst_regs);
7440 defer for (dst_locks) |lock| self.register_manager.unlockReg(lock);7495 defer for (dst_locks) |lock| self.register_manager.unlockReg(lock);
74417496
...@@ -8343,11 +8398,8 @@ fn genMulDivBinOp(...@@ -8343,11 +8398,8 @@ fn genMulDivBinOp(
8343 .{},8398 .{},
8344 );8399 );
83458400
8346 const temp_regs = try self.register_manager.allocRegs(8401 const temp_regs =
8347 4,8402 try self.register_manager.allocRegs(4, .{null} ** 4, abi.RegisterClass.gp);
8348 .{ null, null, null, null },
8349 abi.RegisterClass.gp,
8350 );
8351 const temp_locks = self.register_manager.lockRegs(4, temp_regs);8403 const temp_locks = self.register_manager.lockRegs(4, temp_regs);
8352 defer for (temp_locks) |temp_lock| if (temp_lock) |lock|8404 defer for (temp_locks) |temp_lock| if (temp_lock) |lock|
8353 self.register_manager.unlockReg(lock);8405 self.register_manager.unlockReg(lock);
...@@ -8909,14 +8961,14 @@ fn genBinOp(...@@ -8909,14 +8961,14 @@ fn genBinOp(
8909 const locks = self.register_manager.lockRegsAssumeUnused(2, lhs_regs);8961 const locks = self.register_manager.lockRegsAssumeUnused(2, lhs_regs);
8910 break :locks .{ locks[0], locks[1] };8962 break :locks .{ locks[0], locks[1] };
8911 },8963 },
8912 else => .{ null, null },8964 else => .{null} ** 2,
8913 };8965 };
8914 defer for (lhs_locks) |lhs_lock| if (lhs_lock) |lock| self.register_manager.unlockReg(lock);8966 defer for (lhs_locks) |lhs_lock| if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
89158967
8916 const rhs_locks: [2]?RegisterLock = switch (rhs_mcv) {8968 const rhs_locks: [2]?RegisterLock = switch (rhs_mcv) {
8917 .register => |rhs_reg| .{ self.register_manager.lockReg(rhs_reg), null },8969 .register => |rhs_reg| .{ self.register_manager.lockReg(rhs_reg), null },
8918 .register_pair => |rhs_regs| self.register_manager.lockRegs(2, rhs_regs),8970 .register_pair => |rhs_regs| self.register_manager.lockRegs(2, rhs_regs),
8919 else => .{ null, null },8971 else => .{null} ** 2,
8920 };8972 };
8921 defer for (rhs_locks) |rhs_lock| if (rhs_lock) |lock| self.register_manager.unlockReg(lock);8973 defer for (rhs_locks) |rhs_lock| if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
89228974
...@@ -8949,7 +9001,7 @@ fn genBinOp(...@@ -8949,7 +9001,7 @@ fn genBinOp(
8949 const dst_locks: [2]?RegisterLock = switch (dst_mcv) {9001 const dst_locks: [2]?RegisterLock = switch (dst_mcv) {
8950 .register => |dst_reg| .{ self.register_manager.lockReg(dst_reg), null },9002 .register => |dst_reg| .{ self.register_manager.lockReg(dst_reg), null },
8951 .register_pair => |dst_regs| self.register_manager.lockRegs(2, dst_regs),9003 .register_pair => |dst_regs| self.register_manager.lockRegs(2, dst_regs),
8952 else => .{ null, null },9004 else => .{null} ** 2,
8953 };9005 };
8954 defer for (dst_locks) |dst_lock| if (dst_lock) |lock| self.register_manager.unlockReg(lock);9006 defer for (dst_locks) |dst_lock| if (dst_lock) |lock| self.register_manager.unlockReg(lock);
89559007
...@@ -8965,7 +9017,7 @@ fn genBinOp(...@@ -8965,7 +9017,7 @@ fn genBinOp(
8965 const src_locks: [2]?RegisterLock = switch (src_mcv) {9017 const src_locks: [2]?RegisterLock = switch (src_mcv) {
8966 .register => |src_reg| .{ self.register_manager.lockReg(src_reg), null },9018 .register => |src_reg| .{ self.register_manager.lockReg(src_reg), null },
8967 .register_pair => |src_regs| self.register_manager.lockRegs(2, src_regs),9019 .register_pair => |src_regs| self.register_manager.lockRegs(2, src_regs),
8968 else => .{ null, null },9020 else => .{null} ** 2,
8969 };9021 };
8970 defer for (src_locks) |src_lock| if (src_lock) |lock| self.register_manager.unlockReg(lock);9022 defer for (src_locks) |src_lock| if (src_lock) |lock| self.register_manager.unlockReg(lock);
89719023
...@@ -9025,7 +9077,7 @@ fn genBinOp(...@@ -9025,7 +9077,7 @@ fn genBinOp(
9025 else => dst: {9077 else => dst: {
9026 const dst_regs = try self.register_manager.allocRegs(9078 const dst_regs = try self.register_manager.allocRegs(
9027 2,9079 2,
9028 .{ null, null },9080 .{null} ** 2,
9029 abi.RegisterClass.gp,9081 abi.RegisterClass.gp,
9030 );9082 );
9031 const dst_regs_locks = self.register_manager.lockRegs(2, dst_regs);9083 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 {...@@ -11631,7 +11683,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
1163111683
11632 const regs = try self.register_manager.allocRegs(11684 const regs = try self.register_manager.allocRegs(
11633 2,11685 2,
11634 .{ null, null },11686 .{null} ** 2,
11635 abi.RegisterClass.gp,11687 abi.RegisterClass.gp,
11636 );11688 );
11637 const acc_reg = regs[0].to64();11689 const acc_reg = regs[0].to64();
...@@ -16298,7 +16350,7 @@ fn airVaArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -16298,7 +16350,7 @@ fn airVaArg(self: *Self, inst: Air.Inst.Index) !void {
16298 try self.spillEflagsIfOccupied();16350 try self.spillEflagsIfOccupied();
1629916351
16300 const tmp_regs =16352 const tmp_regs =
16301 try self.register_manager.allocRegs(2, .{ null, null }, abi.RegisterClass.gp);16353 try self.register_manager.allocRegs(2, .{null} ** 2, abi.RegisterClass.gp);
16302 const offset_reg = tmp_regs[0].to32();16354 const offset_reg = tmp_regs[0].to32();
16303 const addr_reg = tmp_regs[1].to64();16355 const addr_reg = tmp_regs[1].to64();
16304 const tmp_locks = self.register_manager.lockRegsAssumeUnused(2, tmp_regs);16356 const tmp_locks = self.register_manager.lockRegsAssumeUnused(2, tmp_regs);