authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-16 16:27:37-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-08-18 17:11:32-07:00
log6e313eb1107d4f5d7b0ada0a67c810ce90e79bf5
tree11a0dd0f9dd004e8509321cd8ee757100832d89e
parentc5ba941b77fbdb06841f28142420c6786f2a4d0c

stage2: agree with LLVM that `@alignOf(u128)` is 8

on x86_64 and similar targets.

6 files changed, 70 insertions(+), 28 deletions(-)

lib/std/target.zig+4-3
...@@ -1806,9 +1806,9 @@ pub const Target = struct {...@@ -1806,9 +1806,9 @@ pub const Target = struct {
1806 else => 4,1806 else => 4,
1807 },1807 },
18081808
1809 // For x86_64, LLVMABIAlignmentOfType(i128) reports 8. However I think 161809 // For these, LLVMABIAlignmentOfType(i128) reports 8. Note that 16
1810 // is a better number for two reasons:1810 // is a relevant number in three cases:
1811 // 1. Better machine code when loading into SIMD register.1811 // 1. Different machine code instruction when loading into SIMD register.
1812 // 2. The C ABI wants 16 for extern structs.1812 // 2. The C ABI wants 16 for extern structs.
1813 // 3. 16-byte cmpxchg needs 16-byte alignment.1813 // 3. 16-byte cmpxchg needs 16-byte alignment.
1814 // Same logic for riscv64, powerpc64, mips64, sparc64.1814 // Same logic for riscv64, powerpc64, mips64, sparc64.
...@@ -1819,6 +1819,7 @@ pub const Target = struct {...@@ -1819,6 +1819,7 @@ pub const Target = struct {
1819 .mips64,1819 .mips64,
1820 .mips64el,1820 .mips64el,
1821 .sparc64,1821 .sparc64,
1822 => 8,
18221823
1823 // Even LLVMABIAlignmentOfType(i128) agrees on these targets.1824 // Even LLVMABIAlignmentOfType(i128) agrees on these targets.
1824 .aarch64,1825 .aarch64,
src/Module.zig+25-5
...@@ -935,13 +935,33 @@ pub const Struct = struct {...@@ -935,13 +935,33 @@ pub const Struct = struct {
935 /// If true then `default_val` is the comptime field value.935 /// If true then `default_val` is the comptime field value.
936 is_comptime: bool,936 is_comptime: bool,
937937
938 /// Returns the field alignment, assuming the struct is not packed.938 /// Returns the field alignment. If the struct is packed, returns 0.
939 pub fn normalAlignment(field: Field, target: Target) u32 {939 pub fn alignment(
940 if (field.abi_align == 0) {940 field: Field,
941 return field.ty.abiAlignment(target);941 target: Target,
942 } else {942 layout: std.builtin.Type.ContainerLayout,
943 ) u32 {
944 if (field.abi_align != 0) {
945 assert(layout != .Packed);
943 return field.abi_align;946 return field.abi_align;
944 }947 }
948
949 switch (layout) {
950 .Packed => return 0,
951 .Auto => return field.ty.abiAlignment(target),
952 .Extern => {
953 // This logic is duplicated in Type.abiAlignmentAdvanced.
954 const ty_abi_align = field.ty.abiAlignment(target);
955
956 if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) {
957 // The C ABI requires 128 bit integer fields of structs
958 // to be 16-bytes aligned.
959 return @maximum(ty_abi_align, 16);
960 }
961
962 return ty_abi_align;
963 },
964 }
945 }965 }
946 };966 };
947967
src/Sema.zig+1-4
...@@ -14380,10 +14380,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -14380,10 +14380,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
14380 else14380 else
14381 field.default_val;14381 field.default_val;
14382 const default_val_ptr = try sema.optRefValue(block, src, field.ty, opt_default_val);14382 const default_val_ptr = try sema.optRefValue(block, src, field.ty, opt_default_val);
14383 const alignment = switch (layout) {14383 const alignment = field.alignment(target, layout);
14384 .Auto, .Extern => field.normalAlignment(target),
14385 .Packed => 0,
14386 };
1438714384
14388 struct_field_fields.* = .{14385 struct_field_fields.* = .{
14389 // name: []const u8,14386 // name: []const u8,
src/codegen/llvm.zig+8-6
...@@ -1841,6 +1841,7 @@ pub const Object = struct {...@@ -1841,6 +1841,7 @@ pub const Object = struct {
1841 }1841 }
18421842
1843 const fields = ty.structFields();1843 const fields = ty.structFields();
1844 const layout = ty.containerLayout();
18441845
1845 var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};1846 var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
1846 defer di_fields.deinit(gpa);1847 defer di_fields.deinit(gpa);
...@@ -1854,7 +1855,7 @@ pub const Object = struct {...@@ -1854,7 +1855,7 @@ pub const Object = struct {
1854 if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;1855 if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;
18551856
1856 const field_size = field.ty.abiSize(target);1857 const field_size = field.ty.abiSize(target);
1857 const field_align = field.normalAlignment(target);1858 const field_align = field.alignment(target, layout);
1858 const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align);1859 const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align);
1859 offset = field_offset + field_size;1860 offset = field_offset + field_size;
18601861
...@@ -2499,7 +2500,7 @@ pub const DeclGen = struct {...@@ -2499,7 +2500,7 @@ pub const DeclGen = struct {
24992500
2500 fn lowerType(dg: *DeclGen, t: Type) Allocator.Error!*const llvm.Type {2501 fn lowerType(dg: *DeclGen, t: Type) Allocator.Error!*const llvm.Type {
2501 const llvm_ty = try lowerTypeInner(dg, t);2502 const llvm_ty = try lowerTypeInner(dg, t);
2502 if (std.debug.runtime_safety and false) check: {2503 if (std.debug.runtime_safety) check: {
2503 if (t.zigTypeTag() == .Opaque) break :check;2504 if (t.zigTypeTag() == .Opaque) break :check;
2504 if (!t.hasRuntimeBits()) break :check;2505 if (!t.hasRuntimeBits()) break :check;
2505 if (!llvm_ty.isSized().toBool()) break :check;2506 if (!llvm_ty.isSized().toBool()) break :check;
...@@ -2757,7 +2758,7 @@ pub const DeclGen = struct {...@@ -2757,7 +2758,7 @@ pub const DeclGen = struct {
2757 for (struct_obj.fields.values()) |field| {2758 for (struct_obj.fields.values()) |field| {
2758 if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;2759 if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;
27592760
2760 const field_align = field.normalAlignment(target);2761 const field_align = field.alignment(target, struct_obj.layout);
2761 const field_ty_align = field.ty.abiAlignment(target);2762 const field_ty_align = field.ty.abiAlignment(target);
2762 any_underaligned_fields = any_underaligned_fields or2763 any_underaligned_fields = any_underaligned_fields or
2763 field_align < field_ty_align;2764 field_align < field_ty_align;
...@@ -3433,7 +3434,7 @@ pub const DeclGen = struct {...@@ -3433,7 +3434,7 @@ pub const DeclGen = struct {
3433 for (struct_obj.fields.values()) |field, i| {3434 for (struct_obj.fields.values()) |field, i| {
3434 if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;3435 if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;
34353436
3436 const field_align = field.normalAlignment(target);3437 const field_align = field.alignment(target, struct_obj.layout);
3437 big_align = @maximum(big_align, field_align);3438 big_align = @maximum(big_align, field_align);
3438 const prev_offset = offset;3439 const prev_offset = offset;
3439 offset = std.mem.alignForwardGeneric(u64, offset, field_align);3440 offset = std.mem.alignForwardGeneric(u64, offset, field_align);
...@@ -9376,13 +9377,14 @@ fn llvmFieldIndex(...@@ -9376,13 +9377,14 @@ fn llvmFieldIndex(
9376 }9377 }
9377 return null;9378 return null;
9378 }9379 }
9379 assert(ty.containerLayout() != .Packed);9380 const layout = ty.containerLayout();
9381 assert(layout != .Packed);
93809382
9381 var llvm_field_index: c_uint = 0;9383 var llvm_field_index: c_uint = 0;
9382 for (ty.structFields().values()) |field, i| {9384 for (ty.structFields().values()) |field, i| {
9383 if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;9385 if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;
93849386
9385 const field_align = field.normalAlignment(target);9387 const field_align = field.alignment(target, layout);
9386 big_align = @maximum(big_align, field_align);9388 big_align = @maximum(big_align, field_align);
9387 const prev_offset = offset;9389 const prev_offset = offset;
9388 offset = std.mem.alignForwardGeneric(u64, offset, field_align);9390 offset = std.mem.alignForwardGeneric(u64, offset, field_align);
src/type.zig+11-2
...@@ -3017,6 +3017,15 @@ pub const Type = extern union {...@@ -3017,6 +3017,15 @@ pub const Type = extern union {
3017 },3017 },
3018 };3018 };
3019 big_align = @maximum(big_align, field_align);3019 big_align = @maximum(big_align, field_align);
3020
3021 // This logic is duplicated in Module.Struct.Field.alignment.
3022 if (struct_obj.layout == .Extern) {
3023 if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) {
3024 // The C ABI requires 128 bit integer fields of structs
3025 // to be 16-bytes aligned.
3026 big_align = @maximum(big_align, 16);
3027 }
3028 }
3020 }3029 }
3021 return AbiAlignmentAdvanced{ .scalar = big_align };3030 return AbiAlignmentAdvanced{ .scalar = big_align };
3022 },3031 },
...@@ -5490,7 +5499,7 @@ pub const Type = extern union {...@@ -5490,7 +5499,7 @@ pub const Type = extern union {
5490 .@"struct" => {5499 .@"struct" => {
5491 const struct_obj = ty.castTag(.@"struct").?.data;5500 const struct_obj = ty.castTag(.@"struct").?.data;
5492 assert(struct_obj.layout != .Packed);5501 assert(struct_obj.layout != .Packed);
5493 return struct_obj.fields.values()[index].normalAlignment(target);5502 return struct_obj.fields.values()[index].alignment(target, struct_obj.layout);
5494 },5503 },
5495 .@"union", .union_safety_tagged, .union_tagged => {5504 .@"union", .union_safety_tagged, .union_tagged => {
5496 const union_obj = ty.cast(Payload.Union).?.data;5505 const union_obj = ty.cast(Payload.Union).?.data;
...@@ -5597,7 +5606,7 @@ pub const Type = extern union {...@@ -5597,7 +5606,7 @@ pub const Type = extern union {
5597 if (!field.ty.hasRuntimeBits() or field.is_comptime)5606 if (!field.ty.hasRuntimeBits() or field.is_comptime)
5598 return FieldOffset{ .field = it.field, .offset = it.offset };5607 return FieldOffset{ .field = it.field, .offset = it.offset };
55995608
5600 const field_align = field.normalAlignment(it.target);5609 const field_align = field.alignment(it.target, it.struct_obj.layout);
5601 it.big_align = @maximum(it.big_align, field_align);5610 it.big_align = @maximum(it.big_align, field_align);
5602 it.offset = std.mem.alignForwardGeneric(u64, it.offset, field_align);5611 it.offset = std.mem.alignForwardGeneric(u64, it.offset, field_align);
5603 defer it.offset += field.ty.abiSize(it.target);5612 defer it.offset += field.ty.abiSize(it.target);
test/behavior/align.zig+21-8
...@@ -143,6 +143,19 @@ test "alignment and size of structs with 128-bit fields" {...@@ -143,6 +143,19 @@ test "alignment and size of structs with 128-bit fields" {
143 .riscv64,143 .riscv64,
144 .sparc64,144 .sparc64,
145 .x86_64,145 .x86_64,
146 => .{
147 .a_align = 8,
148 .a_size = 16,
149
150 .b_align = 16,
151 .b_size = 32,
152
153 .u128_align = 8,
154 .u128_size = 16,
155 .u129_align = 8,
156 .u129_size = 24,
157 },
158
146 .aarch64,159 .aarch64,
147 .aarch64_be,160 .aarch64_be,
148 .aarch64_32,161 .aarch64_32,
...@@ -166,17 +179,17 @@ test "alignment and size of structs with 128-bit fields" {...@@ -166,17 +179,17 @@ test "alignment and size of structs with 128-bit fields" {
166 else => return error.SkipZigTest,179 else => return error.SkipZigTest,
167 };180 };
168 comptime {181 comptime {
169 std.debug.assert(@alignOf(A) == expected.a_align);182 assert(@alignOf(A) == expected.a_align);
170 std.debug.assert(@sizeOf(A) == expected.a_size);183 assert(@sizeOf(A) == expected.a_size);
171184
172 std.debug.assert(@alignOf(B) == expected.b_align);185 assert(@alignOf(B) == expected.b_align);
173 std.debug.assert(@sizeOf(B) == expected.b_size);186 assert(@sizeOf(B) == expected.b_size);
174187
175 std.debug.assert(@alignOf(u128) == expected.u128_align);188 assert(@alignOf(u128) == expected.u128_align);
176 std.debug.assert(@sizeOf(u128) == expected.u128_size);189 assert(@sizeOf(u128) == expected.u128_size);
177190
178 std.debug.assert(@alignOf(u129) == expected.u129_align);191 assert(@alignOf(u129) == expected.u129_align);
179 std.debug.assert(@sizeOf(u129) == expected.u129_size);192 assert(@sizeOf(u129) == expected.u129_size);
180 }193 }
181}194}
182195