Commit c6b3db8910

Jacob Young <jacobly0@users.noreply.github.com>
2024-02-08 06:03:38
x86_64: implement `@abs` of big integers
1 parent 7c9a961
Changed files (1)
src
arch
src/arch/x86_64/CodeGen.zig
@@ -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);