Commit b7799ef322

Andrew Kelley <andrew@ziglang.org>
2024-04-30 02:40:49
std.Target.maxIntAlignment: move to compiler implementation
This should not be a public API, and the x86 backend does not support the value 16.
1 parent 6238101
Changed files (7)
lib
compiler
aro
std
src
test
behavior
lib/compiler/aro/aro/Type.zig
@@ -1116,7 +1116,7 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {
 
         .bit_int => @min(
             std.math.ceilPowerOfTwoPromote(u16, (ty.data.int.bits + 7) / 8),
-            comp.target.maxIntAlignment(),
+            16, // comp.target.maxIntAlignment(), please use your own logic for this value as it is implementation-defined
         ),
 
         .float => comp.target.c_type_alignment(.float),
lib/std/Target.zig
@@ -1862,97 +1862,6 @@ pub fn standardDynamicLinkerPath(target: Target) DynamicLinker {
     return DynamicLinker.standard(target.cpu, target.os.tag, target.abi);
 }
 
-pub fn maxIntAlignment(target: Target) u16 {
-    return switch (target.cpu.arch) {
-        .avr => 1,
-        .msp430 => 2,
-        .xcore => 4,
-
-        .arm,
-        .armeb,
-        .thumb,
-        .thumbeb,
-        .hexagon,
-        .mips,
-        .mipsel,
-        .powerpc,
-        .powerpcle,
-        .r600,
-        .amdgcn,
-        .riscv32,
-        .sparc,
-        .sparcel,
-        .s390x,
-        .lanai,
-        .wasm32,
-        .wasm64,
-        => 8,
-
-        .x86 => if (target.ofmt == .c) 16 else return switch (target.os.tag) {
-            .windows, .uefi => 8,
-            else => 4,
-        },
-
-        // For these, LLVMABIAlignmentOfType(i128) reports 8. Note that 16
-        // is a relevant number in three cases:
-        // 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 powerpc64, mips64, sparc64.
-        .powerpc64,
-        .powerpc64le,
-        .mips64,
-        .mips64el,
-        .sparc64,
-        => return switch (target.ofmt) {
-            .c => 16,
-            else => 8,
-        },
-
-        // Even LLVMABIAlignmentOfType(i128) agrees on these targets.
-        .x86_64,
-        .aarch64,
-        .aarch64_be,
-        .aarch64_32,
-        .riscv64,
-        .bpfel,
-        .bpfeb,
-        .nvptx,
-        .nvptx64,
-        => 16,
-
-        // Below this comment are unverified but based on the fact that C requires
-        // int128_t to be 16 bytes aligned, it's a safe default.
-        .spu_2,
-        .csky,
-        .arc,
-        .m68k,
-        .tce,
-        .tcele,
-        .le32,
-        .amdil,
-        .hsail,
-        .spir,
-        .kalimba,
-        .renderscript32,
-        .spirv,
-        .spirv32,
-        .shave,
-        .le64,
-        .amdil64,
-        .hsail64,
-        .spir64,
-        .renderscript64,
-        .ve,
-        .spirv64,
-        .dxil,
-        .loongarch32,
-        .loongarch64,
-        .xtensa,
-        => 16,
-    };
-}
-
 pub fn ptrBitWidth_cpu_abi(cpu: Cpu, abi: Abi) u16 {
     switch (abi) {
         .gnux32, .muslx32, .gnuabin32, .gnuilp32 => return 32,
src/codegen/c/Type.zig
@@ -1312,10 +1312,10 @@ pub const Pool = struct {
             },
             else => {
                 const target = &mod.resolved_target.result;
-                const abi_align = Type.intAbiAlignment(int_info.bits, target.*);
+                const abi_align = Type.intAbiAlignment(int_info.bits, target.*, false);
                 const abi_align_bytes = abi_align.toByteUnits().?;
                 const array_ctype = try pool.getArray(allocator, .{
-                    .len = @divExact(Type.intAbiSize(int_info.bits, target.*), abi_align_bytes),
+                    .len = @divExact(Type.intAbiSize(int_info.bits, target.*, false), abi_align_bytes),
                     .elem_ctype = try pool.fromIntInfo(allocator, .{
                         .signedness = .unsigned,
                         .bits = @intCast(abi_align_bytes * 8),
@@ -1443,7 +1443,7 @@ pub const Pool = struct {
                         .name = .{ .index = .len },
                         .ctype = CType.usize,
                         .alignas = AlignAs.fromAbiAlignment(
-                            Type.intAbiAlignment(target.ptrBitWidth(), target.*),
+                            Type.intAbiAlignment(target.ptrBitWidth(), target.*, false),
                         ),
                     },
                 };
@@ -1545,7 +1545,7 @@ pub const Pool = struct {
                                 .name = .{ .index = .len },
                                 .ctype = CType.usize,
                                 .alignas = AlignAs.fromAbiAlignment(
-                                    Type.intAbiAlignment(target.ptrBitWidth(), target.*),
+                                    Type.intAbiAlignment(target.ptrBitWidth(), target.*, false),
                                 ),
                             },
                         };
@@ -1665,7 +1665,7 @@ pub const Pool = struct {
                             .name = .{ .index = .@"error" },
                             .ctype = error_set_ctype,
                             .alignas = AlignAs.fromAbiAlignment(
-                                Type.intAbiAlignment(error_set_bits, target.*),
+                                Type.intAbiAlignment(error_set_bits, target.*, false),
                             ),
                         },
                         .{
src/codegen/llvm.zig
@@ -609,7 +609,7 @@ const DataLayoutBuilder = struct {
         switch (kind) {
             .integer => {
                 if (self.target.ptrBitWidth() <= 16 and size >= 128) return;
-                abi = @min(abi, self.target.maxIntAlignment() * 8);
+                abi = @min(abi, Type.maxIntAlignment(self.target, true) * 8);
                 switch (self.target.cpu.arch) {
                     .aarch64,
                     .aarch64_be,
src/link/C.zig
@@ -383,7 +383,9 @@ fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) {
         .msvc => try writer.writeAll("#define ZIG_TARGET_ABI_MSVC\n"),
         else => {},
     }
-    try writer.print("#define ZIG_TARGET_MAX_INT_ALIGNMENT {d}\n", .{target.maxIntAlignment()});
+    try writer.print("#define ZIG_TARGET_MAX_INT_ALIGNMENT {d}\n", .{
+        Type.maxIntAlignment(target, false),
+    });
     return defines;
 }
 
src/type.zig
@@ -883,6 +883,7 @@ pub const Type = struct {
         strat: AbiAlignmentAdvancedStrat,
     ) Module.CompileError!AbiAlignmentAdvanced {
         const target = mod.getTarget();
+        const use_llvm = mod.comp.config.use_llvm;
         const ip = &mod.intern_pool;
 
         const opt_sema = switch (strat) {
@@ -895,7 +896,7 @@ pub const Type = struct {
             else => switch (ip.indexToKey(ty.toIntern())) {
                 .int_type => |int_type| {
                     if (int_type.bits == 0) return AbiAlignmentAdvanced{ .scalar = .@"1" };
-                    return .{ .scalar = intAbiAlignment(int_type.bits, target) };
+                    return .{ .scalar = intAbiAlignment(int_type.bits, target, use_llvm) };
                 },
                 .ptr_type, .anyframe_type => {
                     return .{ .scalar = ptrAbiAlignment(target) };
@@ -941,7 +942,7 @@ pub const Type = struct {
                 .error_set_type, .inferred_error_set_type => {
                     const bits = mod.errorSetBits();
                     if (bits == 0) return AbiAlignmentAdvanced{ .scalar = .@"1" };
-                    return .{ .scalar = intAbiAlignment(bits, target) };
+                    return .{ .scalar = intAbiAlignment(bits, target, use_llvm) };
                 },
 
                 // represents machine code; not a pointer
@@ -962,7 +963,7 @@ pub const Type = struct {
 
                     .usize,
                     .isize,
-                    => return .{ .scalar = intAbiAlignment(target.ptrBitWidth(), target) },
+                    => return .{ .scalar = intAbiAlignment(target.ptrBitWidth(), target, use_llvm) },
 
                     .export_options,
                     .extern_options,
@@ -1001,7 +1002,7 @@ pub const Type = struct {
                     .anyerror, .adhoc_inferred_error_set => {
                         const bits = mod.errorSetBits();
                         if (bits == 0) return AbiAlignmentAdvanced{ .scalar = .@"1" };
-                        return .{ .scalar = intAbiAlignment(bits, target) };
+                        return .{ .scalar = intAbiAlignment(bits, target, use_llvm) };
                     },
 
                     .void,
@@ -1216,6 +1217,7 @@ pub const Type = struct {
         strat: AbiAlignmentAdvancedStrat,
     ) Module.CompileError!AbiSizeAdvanced {
         const target = mod.getTarget();
+        const use_llvm = mod.comp.config.use_llvm;
         const ip = &mod.intern_pool;
 
         switch (ty.toIntern()) {
@@ -1224,7 +1226,7 @@ pub const Type = struct {
             else => switch (ip.indexToKey(ty.toIntern())) {
                 .int_type => |int_type| {
                     if (int_type.bits == 0) return AbiSizeAdvanced{ .scalar = 0 };
-                    return AbiSizeAdvanced{ .scalar = intAbiSize(int_type.bits, target) };
+                    return AbiSizeAdvanced{ .scalar = intAbiSize(int_type.bits, target, use_llvm) };
                 },
                 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
                     .Slice => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) * 2 },
@@ -1286,7 +1288,7 @@ pub const Type = struct {
                 .error_set_type, .inferred_error_set_type => {
                     const bits = mod.errorSetBits();
                     if (bits == 0) return AbiSizeAdvanced{ .scalar = 0 };
-                    return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target) };
+                    return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target, use_llvm) };
                 },
 
                 .error_union_type => |error_union_type| {
@@ -1384,7 +1386,7 @@ pub const Type = struct {
                     .anyerror, .adhoc_inferred_error_set => {
                         const bits = mod.errorSetBits();
                         if (bits == 0) return AbiSizeAdvanced{ .scalar = 0 };
-                        return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target) };
+                        return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target, use_llvm) };
                     },
 
                     .prefetch_options => unreachable, // missing call to resolveTypeFields
@@ -1533,17 +1535,112 @@ pub const Type = struct {
         return Alignment.fromNonzeroByteUnits(@divExact(target.ptrBitWidth(), 8));
     }
 
-    pub fn intAbiSize(bits: u16, target: Target) u64 {
-        return intAbiAlignment(bits, target).forward(@as(u16, @intCast((@as(u17, bits) + 7) / 8)));
+    pub fn intAbiSize(bits: u16, target: Target, use_llvm: bool) u64 {
+        return intAbiAlignment(bits, target, use_llvm).forward(@as(u16, @intCast((@as(u17, bits) + 7) / 8)));
     }
 
-    pub fn intAbiAlignment(bits: u16, target: Target) Alignment {
+    pub fn intAbiAlignment(bits: u16, target: Target, use_llvm: bool) Alignment {
         return Alignment.fromByteUnits(@min(
             std.math.ceilPowerOfTwoPromote(u16, @as(u16, @intCast((@as(u17, bits) + 7) / 8))),
-            target.maxIntAlignment(),
+            maxIntAlignment(target, use_llvm),
         ));
     }
 
+    pub fn maxIntAlignment(target: std.Target, use_llvm: bool) u16 {
+        return switch (target.cpu.arch) {
+            .avr => 1,
+            .msp430 => 2,
+            .xcore => 4,
+
+            .arm,
+            .armeb,
+            .thumb,
+            .thumbeb,
+            .hexagon,
+            .mips,
+            .mipsel,
+            .powerpc,
+            .powerpcle,
+            .r600,
+            .amdgcn,
+            .riscv32,
+            .sparc,
+            .sparcel,
+            .s390x,
+            .lanai,
+            .wasm32,
+            .wasm64,
+            => 8,
+
+            .x86 => if (target.ofmt == .c) 16 else return switch (target.os.tag) {
+                .windows, .uefi => 8,
+                else => 4,
+            },
+
+            // For these, LLVMABIAlignmentOfType(i128) reports 8. Note that 16
+            // is a relevant number in three cases:
+            // 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 powerpc64, mips64, sparc64.
+            .powerpc64,
+            .powerpc64le,
+            .mips64,
+            .mips64el,
+            .sparc64,
+            => switch (target.ofmt) {
+                .c => 16,
+                else => 8,
+            },
+
+            .x86_64 => switch (target_util.zigBackend(target, use_llvm)) {
+                .stage2_x86_64 => 8,
+                else => 16,
+            },
+
+            // Even LLVMABIAlignmentOfType(i128) agrees on these targets.
+            .aarch64,
+            .aarch64_be,
+            .aarch64_32,
+            .riscv64,
+            .bpfel,
+            .bpfeb,
+            .nvptx,
+            .nvptx64,
+            => 16,
+
+            // Below this comment are unverified but based on the fact that C requires
+            // int128_t to be 16 bytes aligned, it's a safe default.
+            .spu_2,
+            .csky,
+            .arc,
+            .m68k,
+            .tce,
+            .tcele,
+            .le32,
+            .amdil,
+            .hsail,
+            .spir,
+            .kalimba,
+            .renderscript32,
+            .spirv,
+            .spirv32,
+            .shave,
+            .le64,
+            .amdil64,
+            .hsail64,
+            .spir64,
+            .renderscript64,
+            .ve,
+            .spirv64,
+            .dxil,
+            .loongarch32,
+            .loongarch64,
+            .xtensa,
+            => 16,
+        };
+    }
+
     pub fn bitSize(ty: Type, mod: *Module) u64 {
         return bitSizeAdvanced(ty, mod, null) catch unreachable;
     }
test/behavior/align.zig
@@ -184,6 +184,33 @@ test "alignment and size of structs with 128-bit fields" {
             },
         },
 
+        .x86_64 => switch (builtin.zig_backend) {
+            .stage2_x86_64 => .{
+                .a_align = 8,
+                .a_size = 16,
+
+                .b_align = 16,
+                .b_size = 32,
+
+                .u128_align = 8,
+                .u128_size = 16,
+                .u129_align = 8,
+                .u129_size = 24,
+            },
+            else => .{
+                .a_align = 16,
+                .a_size = 16,
+
+                .b_align = 16,
+                .b_size = 32,
+
+                .u128_align = 16,
+                .u128_size = 16,
+                .u129_align = 16,
+                .u129_size = 32,
+            },
+        },
+
         .aarch64,
         .aarch64_be,
         .aarch64_32,
@@ -192,7 +219,6 @@ test "alignment and size of structs with 128-bit fields" {
         .bpfeb,
         .nvptx,
         .nvptx64,
-        .x86_64,
         => .{
             .a_align = 16,
             .a_size = 16,