Commit 0e289cc826

Jacob Young <jacobly0@users.noreply.github.com>
2023-04-02 11:15:26
x86_64: implement large add/sub with overflow
1 parent c713c86
Changed files (4)
src
arch
test
src/arch/x86_64/CodeGen.zig
@@ -1857,18 +1857,15 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
     const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
         const tag = self.air.instructions.items(.tag)[inst];
         const ty = self.air.typeOf(bin_op.lhs);
-        const abi_size = ty.abiSize(self.target.*);
         switch (ty.zigTypeTag()) {
             .Vector => return self.fail("TODO implement add/sub/shl with overflow for Vector type", .{}),
             .Int => {
-                if (abi_size > 8) {
-                    return self.fail("TODO implement add/sub/shl with overflow for Ints larger than 64bits", .{});
-                }
-
                 try self.spillEflagsIfOccupied();
 
                 if (tag == .shl_with_overflow) {
                     try self.spillRegisters(&.{.rcx});
+                    // cf/of don't work for shifts other than 1
+                    return self.fail("TODO implement shl_with_overflow for x86_64", .{});
                 }
 
                 const partial: MCValue = switch (tag) {
@@ -1885,16 +1882,29 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
                 };
 
                 const int_info = ty.intInfo(self.target.*);
-
                 if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) {
-                    self.eflags_inst = inst;
-                    break :result .{ .register_overflow = .{
-                        .reg = partial.register,
-                        .eflags = switch (int_info.signedness) {
-                            .unsigned => .c,
-                            .signed => .o,
+                    const cc: Condition = switch (int_info.signedness) {
+                        .unsigned => .c,
+                        .signed => .o,
+                    };
+                    switch (partial) {
+                        .register => |reg| {
+                            self.eflags_inst = inst;
+                            break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } };
                         },
-                    } };
+                        else => {},
+                    }
+
+                    const abi_size = @intCast(i32, ty.abiSize(self.target.*));
+                    const dst_mcv = try self.allocRegOrMem(inst, false);
+                    try self.genSetStack(
+                        Type.u1,
+                        dst_mcv.stack_offset - abi_size,
+                        .{ .eflags = cc },
+                        .{},
+                    );
+                    try self.genSetStack(ty, dst_mcv.stack_offset, partial, .{});
+                    break :result dst_mcv;
                 }
 
                 const tuple_ty = self.air.typeOfIndex(inst);
test/behavior/eval.zig
@@ -488,6 +488,7 @@ test "comptime bitwise operators" {
 test "comptime shlWithOverflow" {
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
 
     const ct_shifted = @shlWithOverflow(~@as(u64, 0), 16)[0];
     var a = ~@as(u64, 0);
test/behavior/int128.zig
@@ -40,7 +40,6 @@ test "undefined 128 bit int" {
 }
 
 test "int128" {
-    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/math.zig
@@ -1237,6 +1237,8 @@ fn testShlTrunc(x: u16) !void {
 }
 
 test "exact shift left" {
+    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+
     try testShlExact(0b00110101);
     comptime try testShlExact(0b00110101);
 }