Skip to content

Commit 8724096

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

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
@@ -1805,9 +1805,9 @@ pub const Target = struct {
18051805
else => 4,
18061806
},
18071807

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

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

src/Module.zig

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

937-
/// Returns the field alignment, assuming the struct is not packed.
938-
pub fn normalAlignment(field: Field, target: Target) u32 {
939-
if (field.abi_align == 0) {
940-
return field.ty.abiAlignment(target);
941-
} else {
937+
/// Returns the field alignment. If the struct is packed, returns 0.
938+
pub fn alignment(
939+
field: Field,
940+
target: Target,
941+
layout: std.builtin.Type.ContainerLayout,
942+
) u32 {
943+
if (field.abi_align != 0) {
944+
assert(layout != .Packed);
942945
return field.abi_align;
943946
}
947+
948+
switch (layout) {
949+
.Packed => return 0,
950+
.Auto => return field.ty.abiAlignment(target),
951+
.Extern => {
952+
// This logic is duplicated in Type.abiAlignmentAdvanced.
953+
const ty_abi_align = field.ty.abiAlignment(target);
954+
955+
if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) {
956+
// The C ABI requires 128 bit integer fields of structs
957+
// to be 16-bytes aligned.
958+
return @maximum(ty_abi_align, 16);
959+
}
960+
961+
return ty_abi_align;
962+
},
963+
}
944964
}
945965
};
946966

src/Sema.zig

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13003,10 +13003,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1300313003
else
1300413004
field.default_val;
1300513005
const default_val_ptr = try sema.optRefValue(block, src, field.ty, opt_default_val);
13006-
const alignment = switch (layout) {
13007-
.Auto, .Extern => field.normalAlignment(target),
13008-
.Packed => 0,
13009-
};
13006+
const alignment = field.alignment(target, layout);
1301013007

1301113008
struct_field_fields.* = .{
1301213009
// name: []const u8,

src/codegen/llvm.zig

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

17791779
const fields = ty.structFields();
1780+
const layout = ty.containerLayout();
17801781

17811782
var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
17821783
defer di_fields.deinit(gpa);
@@ -1790,7 +1791,7 @@ pub const Object = struct {
17901791
if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;
17911792

17921793
const field_size = field.ty.abiSize(target);
1793-
const field_align = field.normalAlignment(target);
1794+
const field_align = field.alignment(target, layout);
17941795
const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align);
17951796
offset = field_offset + field_size;
17961797

@@ -2425,7 +2426,7 @@ pub const DeclGen = struct {
24252426

24262427
fn lowerType(dg: *DeclGen, t: Type) Allocator.Error!*const llvm.Type {
24272428
const llvm_ty = try lowerTypeInner(dg, t);
2428-
if (std.debug.runtime_safety and false) check: {
2429+
if (std.debug.runtime_safety) check: {
24292430
if (t.zigTypeTag() == .Opaque) break :check;
24302431
if (!t.hasRuntimeBits()) break :check;
24312432
if (!llvm_ty.isSized().toBool()) break :check;
@@ -2684,7 +2685,7 @@ pub const DeclGen = struct {
26842685
for (struct_obj.fields.values()) |field| {
26852686
if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;
26862687

2687-
const field_align = field.normalAlignment(target);
2688+
const field_align = field.alignment(target, struct_obj.layout);
26882689
big_align = @maximum(big_align, field_align);
26892690
const prev_offset = offset;
26902691
offset = std.mem.alignForwardGeneric(u64, offset, field_align);
@@ -3344,7 +3345,7 @@ pub const DeclGen = struct {
33443345
for (struct_obj.fields.values()) |field, i| {
33453346
if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;
33463347

3347-
const field_align = field.normalAlignment(target);
3348+
const field_align = field.alignment(target, struct_obj.layout);
33483349
big_align = @maximum(big_align, field_align);
33493350
const prev_offset = offset;
33503351
offset = std.mem.alignForwardGeneric(u64, offset, field_align);
@@ -8884,13 +8885,14 @@ fn llvmFieldIndex(
88848885
}
88858886
return null;
88868887
}
8887-
assert(ty.containerLayout() != .Packed);
8888+
const layout = ty.containerLayout();
8889+
assert(layout != .Packed);
88888890

88898891
var llvm_field_index: c_uint = 0;
88908892
for (ty.structFields().values()) |field, i| {
88918893
if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;
88928894

8893-
const field_align = field.normalAlignment(target);
8895+
const field_align = field.alignment(target, layout);
88948896
big_align = @maximum(big_align, field_align);
88958897
const prev_offset = offset;
88968898
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
@@ -3008,6 +3008,15 @@ pub const Type = extern union {
30083008
},
30093009
};
30103010
big_align = @maximum(big_align, field_align);
3011+
3012+
// This logic is duplicated in Module.Struct.Field.alignment.
3013+
if (struct_obj.layout == .Extern) {
3014+
if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) {
3015+
// The C ABI requires 128 bit integer fields of structs
3016+
// to be 16-bytes aligned.
3017+
big_align = @maximum(big_align, 16);
3018+
}
3019+
}
30113020
}
30123021
return AbiAlignmentAdvanced{ .scalar = big_align };
30133022
},
@@ -5428,7 +5437,7 @@ pub const Type = extern union {
54285437
.@"struct" => {
54295438
const struct_obj = ty.castTag(.@"struct").?.data;
54305439
assert(struct_obj.layout != .Packed);
5431-
return struct_obj.fields.values()[index].normalAlignment(target);
5440+
return struct_obj.fields.values()[index].alignment(target, struct_obj.layout);
54325441
},
54335442
.@"union", .union_tagged => {
54345443
const union_obj = ty.cast(Payload.Union).?.data;
@@ -5535,7 +5544,7 @@ pub const Type = extern union {
55355544
if (!field.ty.hasRuntimeBits() or field.is_comptime)
55365545
return FieldOffset{ .field = it.field, .offset = it.offset };
55375546

5538-
const field_align = field.normalAlignment(it.target);
5547+
const field_align = field.alignment(it.target, it.struct_obj.layout);
55395548
it.big_align = @maximum(it.big_align, field_align);
55405549
it.offset = std.mem.alignForwardGeneric(u64, it.offset, field_align);
55415550
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)