Skip to content

Commit 6e313eb

Browse files
committed
stage2: agree with LLVM that @alignOf(u128) is 8
on x86_64 and similar targets.
1 parent c5ba941 commit 6e313eb

File tree

6 files changed

+70
-28
lines changed

6 files changed

+70
-28
lines changed

lib/std/target.zig

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1806,9 +1806,9 @@ pub const Target = struct {
18061806
else => 4,
18071807
},
18081808

1809-
// For x86_64, LLVMABIAlignmentOfType(i128) reports 8. However I think 16
1810-
// is a better number for two reasons:
1811-
// 1. Better machine code when loading into SIMD register.
1809+
// For these, LLVMABIAlignmentOfType(i128) reports 8. Note that 16
1810+
// is a relevant number in three cases:
1811+
// 1. Different machine code instruction when loading into SIMD register.
18121812
// 2. The C ABI wants 16 for extern structs.
18131813
// 3. 16-byte cmpxchg needs 16-byte alignment.
18141814
// Same logic for riscv64, powerpc64, mips64, sparc64.
@@ -1819,6 +1819,7 @@ pub const Target = struct {
18191819
.mips64,
18201820
.mips64el,
18211821
.sparc64,
1822+
=> 8,
18221823

18231824
// Even LLVMABIAlignmentOfType(i128) agrees on these targets.
18241825
.aarch64,

src/Module.zig

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -935,13 +935,33 @@ pub const Struct = struct {
935935
/// If true then `default_val` is the comptime field value.
936936
is_comptime: bool,
937937

938-
/// Returns the field alignment, assuming the struct is not packed.
939-
pub fn normalAlignment(field: Field, target: Target) u32 {
940-
if (field.abi_align == 0) {
941-
return field.ty.abiAlignment(target);
942-
} else {
938+
/// Returns the field alignment. If the struct is packed, returns 0.
939+
pub fn alignment(
940+
field: Field,
941+
target: Target,
942+
layout: std.builtin.Type.ContainerLayout,
943+
) u32 {
944+
if (field.abi_align != 0) {
945+
assert(layout != .Packed);
943946
return field.abi_align;
944947
}
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+
}
945965
}
946966
};
947967

src/Sema.zig

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14380,10 +14380,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1438014380
else
1438114381
field.default_val;
1438214382
const default_val_ptr = try sema.optRefValue(block, src, field.ty, opt_default_val);
14383-
const alignment = switch (layout) {
14384-
.Auto, .Extern => field.normalAlignment(target),
14385-
.Packed => 0,
14386-
};
14383+
const alignment = field.alignment(target, layout);
1438714384

1438814385
struct_field_fields.* = .{
1438914386
// name: []const u8,

src/codegen/llvm.zig

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1841,6 +1841,7 @@ pub const Object = struct {
18411841
}
18421842

18431843
const fields = ty.structFields();
1844+
const layout = ty.containerLayout();
18441845

18451846
var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
18461847
defer di_fields.deinit(gpa);
@@ -1854,7 +1855,7 @@ pub const Object = struct {
18541855
if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;
18551856

18561857
const field_size = field.ty.abiSize(target);
1857-
const field_align = field.normalAlignment(target);
1858+
const field_align = field.alignment(target, layout);
18581859
const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align);
18591860
offset = field_offset + field_size;
18601861

@@ -2499,7 +2500,7 @@ pub const DeclGen = struct {
24992500

25002501
fn lowerType(dg: *DeclGen, t: Type) Allocator.Error!*const llvm.Type {
25012502
const llvm_ty = try lowerTypeInner(dg, t);
2502-
if (std.debug.runtime_safety and false) check: {
2503+
if (std.debug.runtime_safety) check: {
25032504
if (t.zigTypeTag() == .Opaque) break :check;
25042505
if (!t.hasRuntimeBits()) break :check;
25052506
if (!llvm_ty.isSized().toBool()) break :check;
@@ -2757,7 +2758,7 @@ pub const DeclGen = struct {
27572758
for (struct_obj.fields.values()) |field| {
27582759
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);
27612762
const field_ty_align = field.ty.abiAlignment(target);
27622763
any_underaligned_fields = any_underaligned_fields or
27632764
field_align < field_ty_align;
@@ -3433,7 +3434,7 @@ pub const DeclGen = struct {
34333434
for (struct_obj.fields.values()) |field, i| {
34343435
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);
34373438
big_align = @maximum(big_align, field_align);
34383439
const prev_offset = offset;
34393440
offset = std.mem.alignForwardGeneric(u64, offset, field_align);
@@ -9376,13 +9377,14 @@ fn llvmFieldIndex(
93769377
}
93779378
return null;
93789379
}
9379-
assert(ty.containerLayout() != .Packed);
9380+
const layout = ty.containerLayout();
9381+
assert(layout != .Packed);
93809382

93819383
var llvm_field_index: c_uint = 0;
93829384
for (ty.structFields().values()) |field, i| {
93839385
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);
93869388
big_align = @maximum(big_align, field_align);
93879389
const prev_offset = offset;
93889390
offset = std.mem.alignForwardGeneric(u64, offset, field_align);

src/type.zig

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3017,6 +3017,15 @@ pub const Type = extern union {
30173017
},
30183018
};
30193019
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+
}
30203029
}
30213030
return AbiAlignmentAdvanced{ .scalar = big_align };
30223031
},
@@ -5490,7 +5499,7 @@ pub const Type = extern union {
54905499
.@"struct" => {
54915500
const struct_obj = ty.castTag(.@"struct").?.data;
54925501
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);
54945503
},
54955504
.@"union", .union_safety_tagged, .union_tagged => {
54965505
const union_obj = ty.cast(Payload.Union).?.data;
@@ -5597,7 +5606,7 @@ pub const Type = extern union {
55975606
if (!field.ty.hasRuntimeBits() or field.is_comptime)
55985607
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);
56015610
it.big_align = @maximum(it.big_align, field_align);
56025611
it.offset = std.mem.alignForwardGeneric(u64, it.offset, field_align);
56035612
defer it.offset += field.ty.abiSize(it.target);

test/behavior/align.zig

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,19 @@ test "alignment and size of structs with 128-bit fields" {
143143
.riscv64,
144144
.sparc64,
145145
.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+
146159
.aarch64,
147160
.aarch64_be,
148161
.aarch64_32,
@@ -166,17 +179,17 @@ test "alignment and size of structs with 128-bit fields" {
166179
else => return error.SkipZigTest,
167180
};
168181
comptime {
169-
std.debug.assert(@alignOf(A) == expected.a_align);
170-
std.debug.assert(@sizeOf(A) == expected.a_size);
182+
assert(@alignOf(A) == expected.a_align);
183+
assert(@sizeOf(A) == expected.a_size);
171184

172-
std.debug.assert(@alignOf(B) == expected.b_align);
173-
std.debug.assert(@sizeOf(B) == expected.b_size);
185+
assert(@alignOf(B) == expected.b_align);
186+
assert(@sizeOf(B) == expected.b_size);
174187

175-
std.debug.assert(@alignOf(u128) == expected.u128_align);
176-
std.debug.assert(@sizeOf(u128) == expected.u128_size);
188+
assert(@alignOf(u128) == expected.u128_align);
189+
assert(@sizeOf(u128) == expected.u128_size);
177190

178-
std.debug.assert(@alignOf(u129) == expected.u129_align);
179-
std.debug.assert(@sizeOf(u129) == expected.u129_size);
191+
assert(@alignOf(u129) == expected.u129_align);
192+
assert(@sizeOf(u129) == expected.u129_size);
180193
}
181194
}
182195

0 commit comments

Comments
 (0)