Commit cee82c7ce4

Andrew Kelley <andrew@ziglang.org>
2022-08-19 05:34:36
improved ABI alignment/size for >= 128-bit integers
* riscv64: adjust alignment and size of 128-bit integers. * take ofmt=c into account for ABI alignment of 128-bit integers and structs. * Type: make packed struct support intInfo * fix f80 alignment for i386-windows-msvc
1 parent b975f7a
Changed files (4)
lib
src
test
behavior
lib/std/target.zig
@@ -1808,20 +1808,23 @@ pub const Target = struct {
             // 1. Different machine code instruction when loading into SIMD register.
             // 2. The C ABI wants 16 for extern structs.
             // 3. 16-byte cmpxchg needs 16-byte alignment.
-            // Same logic for riscv64, powerpc64, mips64, sparc64.
+            // Same logic for powerpc64, mips64, sparc64.
             .x86_64,
-            .riscv64,
             .powerpc64,
             .powerpc64le,
             .mips64,
             .mips64el,
             .sparc64,
-            => 8,
+            => return switch (target.ofmt) {
+                .c => 16,
+                else => 8,
+            },
 
             // Even LLVMABIAlignmentOfType(i128) agrees on these targets.
             .aarch64,
             .aarch64_be,
             .aarch64_32,
+            .riscv64,
             .bpfel,
             .bpfeb,
             .nvptx,
src/Module.zig
@@ -948,20 +948,28 @@ pub const Struct = struct {
 
             switch (layout) {
                 .Packed => return 0,
-                .Auto => return field.ty.abiAlignment(target),
-                .Extern => {
-                    // This logic is duplicated in Type.abiAlignmentAdvanced.
-                    const ty_abi_align = field.ty.abiAlignment(target);
-
-                    if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) {
-                        // The C ABI requires 128 bit integer fields of structs
-                        // to be 16-bytes aligned.
-                        return @maximum(ty_abi_align, 16);
+                .Auto => {
+                    if (target.ofmt == .c) {
+                        return alignmentExtern(field, target);
+                    } else {
+                        return field.ty.abiAlignment(target);
                     }
-
-                    return ty_abi_align;
                 },
+                .Extern => return alignmentExtern(field, target),
+            }
+        }
+
+        pub fn alignmentExtern(field: Field, target: Target) u32 {
+            // This logic is duplicated in Type.abiAlignmentAdvanced.
+            const ty_abi_align = field.ty.abiAlignment(target);
+
+            if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) {
+                // The C ABI requires 128 bit integer fields of structs
+                // to be 16-bytes aligned.
+                return @maximum(ty_abi_align, 16);
             }
+
+            return ty_abi_align;
         }
     };
 
src/type.zig
@@ -3019,7 +3019,7 @@ pub const Type = extern union {
                     big_align = @maximum(big_align, field_align);
 
                     // This logic is duplicated in Module.Struct.Field.alignment.
-                    if (struct_obj.layout == .Extern) {
+                    if (struct_obj.layout == .Extern or target.ofmt == .c) {
                         if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) {
                             // The C ABI requires 128 bit integer fields of structs
                             // to be 16-bytes aligned.
@@ -3348,7 +3348,13 @@ pub const Type = extern union {
             .f128 => return AbiSizeAdvanced{ .scalar = 16 },
 
             .f80 => switch (target.cpu.arch) {
-                .i386 => return AbiSizeAdvanced{ .scalar = 12 },
+                .i386 => switch (target.os.tag) {
+                    .windows => switch (target.abi) {
+                        .msvc => return AbiSizeAdvanced{ .scalar = 16 },
+                        else => return AbiSizeAdvanced{ .scalar = 12 },
+                    },
+                    else => return AbiSizeAdvanced{ .scalar = 12 },
+                },
                 .x86_64 => return AbiSizeAdvanced{ .scalar = 16 },
                 else => {
                     var payload: Payload.Bits = .{
@@ -4559,6 +4565,12 @@ pub const Type = extern union {
 
             .vector => ty = ty.castTag(.vector).?.data.elem_type,
 
+            .@"struct" => {
+                const struct_obj = ty.castTag(.@"struct").?.data;
+                assert(struct_obj.layout == .Packed);
+                ty = struct_obj.backing_int_ty;
+            },
+
             else => unreachable,
         };
     }
test/behavior/align.zig
@@ -100,8 +100,8 @@ test "alignment and size of structs with 128-bit fields" {
             .a_align = 8,
             .a_size = 16,
 
-            .b_align = 8,
-            .b_size = 24,
+            .b_align = 16,
+            .b_size = 32,
 
             .u128_align = 8,
             .u128_size = 16,
@@ -114,8 +114,8 @@ test "alignment and size of structs with 128-bit fields" {
                 .a_align = 8,
                 .a_size = 16,
 
-                .b_align = 8,
-                .b_size = 24,
+                .b_align = 16,
+                .b_size = 32,
 
                 .u128_align = 8,
                 .u128_size = 16,
@@ -126,8 +126,8 @@ test "alignment and size of structs with 128-bit fields" {
                 .a_align = 4,
                 .a_size = 16,
 
-                .b_align = 4,
-                .b_size = 20,
+                .b_align = 16,
+                .b_size = 32,
 
                 .u128_align = 4,
                 .u128_size = 16,
@@ -140,25 +140,39 @@ test "alignment and size of structs with 128-bit fields" {
         .mips64el,
         .powerpc64,
         .powerpc64le,
-        .riscv64,
         .sparc64,
         .x86_64,
-        => .{
-            .a_align = 8,
-            .a_size = 16,
+        => switch (builtin.object_format) {
+            .c => .{
+                .a_align = 16,
+                .a_size = 16,
 
-            .b_align = 16,
-            .b_size = 32,
+                .b_align = 16,
+                .b_size = 32,
 
-            .u128_align = 8,
-            .u128_size = 16,
-            .u129_align = 8,
-            .u129_size = 24,
+                .u128_align = 16,
+                .u128_size = 16,
+                .u129_align = 16,
+                .u129_size = 32,
+            },
+            else => .{
+                .a_align = 8,
+                .a_size = 16,
+
+                .b_align = 16,
+                .b_size = 32,
+
+                .u128_align = 8,
+                .u128_size = 16,
+                .u129_align = 8,
+                .u129_size = 24,
+            },
         },
 
         .aarch64,
         .aarch64_be,
         .aarch64_32,
+        .riscv64,
         .bpfel,
         .bpfeb,
         .nvptx,