Commit 8f385e77ca

Jacob Young <jacobly0@users.noreply.github.com>
2023-03-25 08:44:02
x86_64: implement struct_field_val for packed containers
1 parent 0cfc0d0
Changed files (6)
src/arch/x86_64/CodeGen.zig
@@ -3745,18 +3745,22 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
     }
 
     const mcv = try self.resolveInst(operand);
-    const struct_ty = self.air.typeOf(operand);
-    if (struct_ty.zigTypeTag() == .Struct and struct_ty.containerLayout() == .Packed) {
-        return self.fail("TODO airStructFieldVal implement packed structs", .{});
-    }
-    const struct_field_offset = struct_ty.structFieldOffset(index, self.target.*);
-    const struct_field_ty = struct_ty.structFieldType(index);
+    const container_ty = self.air.typeOf(operand);
+    const field_ty = container_ty.structFieldType(index);
+    const field_bit_offset = switch (container_ty.containerLayout()) {
+        .Auto, .Extern => @intCast(u32, container_ty.structFieldOffset(index, self.target.*) * 8),
+        .Packed => if (container_ty.castTag(.@"struct")) |struct_obj|
+            struct_obj.data.packedFieldBitOffset(self.target.*, index)
+        else
+            0,
+    };
 
     const result: MCValue = result: {
         switch (mcv) {
             .stack_offset => |off| {
-                const stack_offset = off - @intCast(i32, struct_field_offset);
-                break :result MCValue{ .stack_offset = stack_offset };
+                const byte_offset = std.math.divExact(u32, field_bit_offset, 8) catch
+                    return self.fail("TODO implement struct_field_val for a packed struct", .{});
+                break :result MCValue{ .stack_offset = off - @intCast(i32, byte_offset) };
             },
             .register => |reg| {
                 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
@@ -3779,27 +3783,28 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
                 defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
 
                 // Shift by struct_field_offset.
-                const shift = @intCast(u8, struct_field_offset * 8);
-                try self.genShiftBinOpMir(.shr, Type.usize, dst_mcv.register, .{ .immediate = shift });
+                try self.genShiftBinOpMir(
+                    .shr,
+                    Type.usize,
+                    dst_mcv.register,
+                    .{ .immediate = field_bit_offset },
+                );
 
-                // Mask with reg.bitSize() - struct_field_size
-                const max_reg_bit_width = Register.rax.bitSize();
-                const mask_shift = @intCast(u6, (max_reg_bit_width - struct_field_ty.bitSize(self.target.*)));
-                const mask = (~@as(u64, 0)) >> mask_shift;
+                // Mask to field_bit_size bits
+                const field_bit_size = field_ty.bitSize(self.target.*);
+                const mask = ~@as(u64, 0) >> @intCast(u6, 64 - field_bit_size);
 
                 const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask });
                 try self.genBinOpMir(.@"and", Type.usize, dst_mcv, .{ .register = tmp_reg });
 
-                const signedness: std.builtin.Signedness = blk: {
-                    if (struct_field_ty.zigTypeTag() != .Int) break :blk .unsigned;
-                    break :blk struct_field_ty.intInfo(self.target.*).signedness;
-                };
-                const field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*));
-                if (signedness == .signed and field_size < 8) {
+                const signedness =
+                    if (field_ty.isAbiInt()) field_ty.intInfo(self.target.*).signedness else .unsigned;
+                const field_byte_size = @intCast(u32, field_ty.abiSize(self.target.*));
+                if (signedness == .signed and field_byte_size < 8) {
                     try self.asmRegisterRegister(
                         .movsx,
                         dst_mcv.register,
-                        registerAlias(dst_mcv.register, field_size),
+                        registerAlias(dst_mcv.register, field_byte_size),
                     );
                 }
 
test/behavior/bugs/9584.zig
@@ -44,7 +44,6 @@ pub fn b(x: *X) !void {
 }
 
 test {
-    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_sparc64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/bitcast.zig
@@ -157,7 +157,6 @@ test "bitcast generates a temporary value" {
 }
 
 test "@bitCast packed structs at runtime and comptime" {
-    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -215,7 +214,6 @@ test "@bitCast extern structs at runtime and comptime" {
 }
 
 test "bitcast packed struct to integer and back" {
-    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/packed-struct.zig
@@ -254,7 +254,6 @@ test "regular in irregular packed struct" {
 }
 
 test "byte-aligned field pointer offsets" {
-    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -397,7 +396,6 @@ test "@ptrToInt on a packed struct field" {
 }
 
 test "optional pointer in packed struct" {
-    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -530,7 +528,6 @@ test "nested packed struct field access test" {
 test "runtime init of unnamed packed struct type" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 
     var z: u8 = 123;
@@ -545,7 +542,6 @@ test "runtime init of unnamed packed struct type" {
 test "packed struct passed to callconv(.C) function" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 
     const S = struct {
test/behavior/struct.zig
@@ -387,7 +387,6 @@ const APackedStruct = packed struct {
 test "packed struct" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 
     var foo = APackedStruct{
@@ -496,7 +495,6 @@ const Bitfields = packed struct {
 test "packed struct fields are ordered from LSB to MSB" {
     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_x86_64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 
     var all: u64 = 0x7765443322221111;
@@ -632,7 +630,6 @@ test "default struct initialization fields" {
 }
 
 test "packed array 24bits" {
-    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;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/union.zig
@@ -1408,7 +1408,6 @@ test "union field ptr - zero sized field" {
 }
 
 test "packed union in packed struct" {
-    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_wasm) return error.SkipZigTest; // TODO
@@ -1494,7 +1493,6 @@ test "union reassignment can use previous value" {
 }
 
 test "packed union with zero-bit field" {
-    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_wasm) return error.SkipZigTest; // TODO