Commit 05431d7c4a

Jakub Konka <kubkon@jakubkonka.com>
2022-02-28 17:48:38
x64: impl unwrap_errunion_payload and unwrap_errunion_err for register
1 parent a7ca40b
Changed files (2)
src
arch
test
behavior
src/arch/x86_64/CodeGen.zig
@@ -1738,14 +1738,22 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
         return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
     }
     const err_union_ty = self.air.typeOf(ty_op.operand);
+    const err_ty = err_union_ty.errorUnionSet();
     const payload_ty = err_union_ty.errorUnionPayload();
     const operand = try self.resolveInst(ty_op.operand);
+    operand.freezeIfRegister(&self.register_manager);
+    defer operand.unfreezeIfRegister(&self.register_manager);
+
     const result: MCValue = result: {
         if (!payload_ty.hasRuntimeBits()) break :result operand;
         switch (operand) {
             .stack_offset => |off| {
                 break :result MCValue{ .stack_offset = off };
             },
+            .register => {
+                // TODO reuse operand
+                break :result try self.copyToRegisterWithInstTracking(inst, err_ty, operand);
+            },
             else => return self.fail("TODO implement unwrap_err_err for {}", .{operand}),
         }
     };
@@ -1763,13 +1771,24 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
         if (!payload_ty.hasRuntimeBits()) break :result MCValue.none;
 
         const operand = try self.resolveInst(ty_op.operand);
+        operand.freezeIfRegister(&self.register_manager);
+        defer operand.unfreezeIfRegister(&self.register_manager);
+
         const err_ty = err_union_ty.errorUnionSet();
-        const err_abi_size = @intCast(u32, err_ty.abiSize(self.target.*));
         switch (operand) {
             .stack_offset => |off| {
+                const err_abi_size = @intCast(u32, err_ty.abiSize(self.target.*));
                 const offset = off - @intCast(i32, err_abi_size);
                 break :result MCValue{ .stack_offset = offset };
             },
+            .register => {
+                // TODO reuse operand
+                const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);
+                try self.shiftRegister(result.register.to64(), @intCast(u6, err_ty.bitSize(self.target.*)));
+                break :result MCValue{
+                    .register = registerAlias(result.register, @intCast(u32, payload_ty.abiSize(self.target.*))),
+                };
+            },
             else => return self.fail("TODO implement unwrap_err_payload for {}", .{operand}),
         }
     };
@@ -2686,27 +2705,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
                 };
 
                 // Shift by struct_field_offset.
-                const shift_amount = @intCast(u8, struct_field_offset * 8);
-                if (shift_amount > 0) {
-                    if (shift_amount == 1) {
-                        _ = try self.addInst(.{
-                            .tag = .shr,
-                            .ops = (Mir.Ops{
-                                .reg1 = dst_mcv.register,
-                            }).encode(),
-                            .data = undefined,
-                        });
-                    } else {
-                        _ = try self.addInst(.{
-                            .tag = .shr,
-                            .ops = (Mir.Ops{
-                                .reg1 = dst_mcv.register,
-                                .flags = 0b10,
-                            }).encode(),
-                            .data = .{ .imm = shift_amount },
-                        });
-                    }
-                }
+                const shift = @intCast(u8, struct_field_offset * 8);
+                try self.shiftRegister(dst_mcv.register, shift);
 
                 // Mask with reg.size() - struct_field_size
                 const mask_shift = @intCast(u6, (64 - struct_field_ty.bitSize(self.target.*)));
@@ -5768,3 +5768,25 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {
         unreachable; // TODO handle floating-point registers
     }
 }
+
+fn shiftRegister(self: *Self, reg: Register, shift: u8) !void {
+    if (shift == 0) return;
+    if (shift == 1) {
+        _ = try self.addInst(.{
+            .tag = .shr,
+            .ops = (Mir.Ops{
+                .reg1 = reg,
+            }).encode(),
+            .data = undefined,
+        });
+    } else {
+        _ = try self.addInst(.{
+            .tag = .shr,
+            .ops = (Mir.Ops{
+                .reg1 = reg,
+                .flags = 0b10,
+            }).encode(),
+            .data = .{ .imm = shift },
+        });
+    }
+}
test/behavior/error.zig
@@ -78,7 +78,6 @@ fn unwrapSimpleValueFromErrorDo() anyerror!isize {
 }
 
 test "error return in assignment" {
-    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
 
@@ -121,7 +120,6 @@ test "widen cast integer payload of error union function call" {
 }
 
 test "debug info for optional error set" {
-    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
 
@@ -173,7 +171,6 @@ fn bar2() (error{}!void) {}
 test "error union type " {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
 
     try testErrorUnionType();
@@ -191,7 +188,6 @@ fn testErrorUnionType() !void {
 test "error set type" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
 
     try testErrorSetType();