authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-20 19:40:21-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-21 14:48:40-07:00
logdca17d3603e5b68a8f683bfc1bdabc9959654d26
tree285502dd184921918e0ad3b2d34c1d3fdef1830b
parentd06bf707ed374ca42a580ee7acf1cecaab078d0d

Sema: fix struct alignment regressions


2 files changed, 50 insertions(+), 23 deletions(-)

src/InternPool.zig+17-1
...@@ -536,6 +536,19 @@ pub const Key = union(enum) {...@@ -536,6 +536,19 @@ pub const Key = union(enum) {
536 s.flagsPtr(ip).layout_wip = false;536 s.flagsPtr(ip).layout_wip = false;
537 }537 }
538538
539 pub fn setAlignmentWip(s: @This(), ip: *InternPool) bool {
540 if (s.layout == .Packed) return false;
541 const flags_ptr = s.flagsPtr(ip);
542 if (flags_ptr.alignment_wip) return true;
543 flags_ptr.alignment_wip = true;
544 return false;
545 }
546
547 pub fn clearAlignmentWip(s: @This(), ip: *InternPool) void {
548 if (s.layout == .Packed) return;
549 s.flagsPtr(ip).alignment_wip = false;
550 }
551
539 pub fn setFullyResolved(s: @This(), ip: *InternPool) bool {552 pub fn setFullyResolved(s: @This(), ip: *InternPool) bool {
540 if (s.layout == .Packed) return true;553 if (s.layout == .Packed) return true;
541 const flags_ptr = s.flagsPtr(ip);554 const flags_ptr = s.flagsPtr(ip);
...@@ -2971,6 +2984,8 @@ pub const Tag = enum(u8) {...@@ -2971,6 +2984,8 @@ pub const Tag = enum(u8) {
2971 any_aligned_fields: bool,2984 any_aligned_fields: bool,
2972 /// `undefined` until the layout_resolved2985 /// `undefined` until the layout_resolved
2973 alignment: Alignment,2986 alignment: Alignment,
2987 /// Dependency loop detection when resolving struct alignment.
2988 alignment_wip: bool,
2974 /// Dependency loop detection when resolving field types.2989 /// Dependency loop detection when resolving field types.
2975 field_types_wip: bool,2990 field_types_wip: bool,
2976 /// Dependency loop detection when resolving struct layout.2991 /// Dependency loop detection when resolving struct layout.
...@@ -2982,7 +2997,7 @@ pub const Tag = enum(u8) {...@@ -2982,7 +2997,7 @@ pub const Tag = enum(u8) {
2982 // which `layout_resolved` does not ensure.2997 // which `layout_resolved` does not ensure.
2983 fully_resolved: bool,2998 fully_resolved: bool,
29842999
2985 _: u12 = 0,3000 _: u11 = 0,
2986 };3001 };
2987 };3002 };
2988};3003};
...@@ -5300,6 +5315,7 @@ pub fn getStructType(...@@ -5300,6 +5315,7 @@ pub fn getStructType(
5300 .any_default_inits = ini.any_default_inits,5315 .any_default_inits = ini.any_default_inits,
5301 .any_aligned_fields = ini.any_aligned_fields,5316 .any_aligned_fields = ini.any_aligned_fields,
5302 .alignment = .none,5317 .alignment = .none,
5318 .alignment_wip = false,
5303 .field_types_wip = false,5319 .field_types_wip = false,
5304 .layout_wip = false,5320 .layout_wip = false,
5305 .layout_resolved = false,5321 .layout_resolved = false,
src/Sema.zig+33-22
...@@ -26698,21 +26698,25 @@ fn structFieldPtrByIndex(...@@ -26698,21 +26698,25 @@ fn structFieldPtrByIndex(
26698 }26698 }
26699 }26699 }
26700 } else if (struct_type.layout == .Extern) {26700 } else if (struct_type.layout == .Extern) {
26701 // For extern structs, field aligment might be bigger than type's natural alignment. Eg, in26701 // For extern structs, field alignment might be bigger than type's
26702 // `extern struct { x: u32, y: u16 }` the second field is aligned as u32.26702 // natural alignment. Eg, in `extern struct { x: u32, y: u16 }` the
26703 // second field is aligned as u32.
26703 const field_offset = struct_ty.structFieldOffset(field_index, mod);26704 const field_offset = struct_ty.structFieldOffset(field_index, mod);
26704 ptr_ty_data.flags.alignment = if (parent_align == .none)26705 ptr_ty_data.flags.alignment = if (parent_align == .none)
26705 .none26706 .none
26706 else26707 else
26707 @enumFromInt(@min(@intFromEnum(parent_align), @ctz(field_offset)));26708 @enumFromInt(@min(@intFromEnum(parent_align), @ctz(field_offset)));
26708 } else {26709 } else {
26709 // Our alignment is capped at the field alignment26710 // Our alignment is capped at the field alignment.
26710 const field_align = try sema.structFieldAlignment(26711 const field_align = try sema.structFieldAlignment(
26711 struct_type.fieldAlign(ip, field_index),26712 struct_type.fieldAlign(ip, field_index),
26712 field_ty.toType(),26713 field_ty.toType(),
26713 struct_type.layout,26714 struct_type.layout,
26714 );26715 );
26715 ptr_ty_data.flags.alignment = field_align.min(parent_align);26716 ptr_ty_data.flags.alignment = if (struct_ptr_ty_info.flags.alignment == .none)
26717 field_align
26718 else
26719 field_align.min(parent_align);
26716 }26720 }
2671726721
26718 const ptr_field_ty = try sema.ptrType(ptr_ty_data);26722 const ptr_field_ty = try sema.ptrType(ptr_ty_data);
...@@ -28635,8 +28639,8 @@ const InMemoryCoercionResult = union(enum) {...@@ -28635,8 +28639,8 @@ const InMemoryCoercionResult = union(enum) {
28635 break;28639 break;
28636 },28640 },
28637 .ptr_alignment => |pair| {28641 .ptr_alignment => |pair| {
28638 try sema.errNote(block, src, msg, "pointer alignment '{}' cannot cast into pointer alignment '{}'", .{28642 try sema.errNote(block, src, msg, "pointer alignment '{d}' cannot cast into pointer alignment '{d}'", .{
28639 pair.actual, pair.wanted,28643 pair.actual.toByteUnits(0), pair.wanted.toByteUnits(0),
28640 });28644 });
28641 break;28645 break;
28642 },28646 },
...@@ -34307,20 +34311,29 @@ pub fn resolveStructAlignment(...@@ -34307,20 +34311,29 @@ pub fn resolveStructAlignment(
3430734311
34308 try sema.resolveTypeFieldsStruct(ty, struct_type);34312 try sema.resolveTypeFieldsStruct(ty, struct_type);
3430934313
34314 if (struct_type.setAlignmentWip(ip)) {
34315 // We'll guess "pointer-aligned", if the struct has an
34316 // underaligned pointer field then some allocations
34317 // might require explicit alignment.
34318 //TODO write this bit and emit an error later if incorrect
34319 //struct_type.flagsPtr(ip).assumed_pointer_aligned = true;
34320 const result = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
34321 struct_type.flagsPtr(ip).alignment = result;
34322 return result;
34323 }
34324
34310 var result: Alignment = .@"1";34325 var result: Alignment = .@"1";
3431134326
34312 for (0..struct_type.field_types.len) |i| {34327 for (0..struct_type.field_types.len) |i| {
34313 if (struct_type.fieldIsComptime(ip, i)) continue;
34314 const field_ty = struct_type.field_types.get(ip)[i].toType();34328 const field_ty = struct_type.field_types.get(ip)[i].toType();
34315 if (try sema.typeRequiresComptime(field_ty)) continue;34329 if (struct_type.fieldIsComptime(ip, i) or try sema.typeRequiresComptime(field_ty))
34316 if (try sema.typeHasRuntimeBits(field_ty)) {34330 continue;
34317 const field_align = try sema.structFieldAlignment(34331 const field_align = try sema.structFieldAlignment(
34318 struct_type.fieldAlign(ip, i),34332 struct_type.fieldAlign(ip, i),
34319 field_ty,34333 field_ty,
34320 struct_type.layout,34334 struct_type.layout,
34321 );34335 );
34322 result = result.max(field_align);34336 result = result.max(field_align);
34323 }
34324 }34337 }
3432534338
34326 struct_type.flagsPtr(ip).alignment = result;34339 struct_type.flagsPtr(ip).alignment = result;
...@@ -34358,7 +34371,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {...@@ -34358,7 +34371,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
3435834371
34359 for (aligns, sizes, 0..) |*field_align, *field_size, i| {34372 for (aligns, sizes, 0..) |*field_align, *field_size, i| {
34360 const field_ty = struct_type.field_types.get(ip)[i].toType();34373 const field_ty = struct_type.field_types.get(ip)[i].toType();
34361 if (struct_type.fieldIsComptime(ip, i) or !(try sema.typeHasRuntimeBits(field_ty))) {34374 if (struct_type.fieldIsComptime(ip, i) or try sema.typeRequiresComptime(field_ty)) {
34362 struct_type.offsets.get(ip)[i] = 0;34375 struct_type.offsets.get(ip)[i] = 0;
34363 field_size.* = 0;34376 field_size.* = 0;
34364 field_align.* = .none;34377 field_align.* = .none;
...@@ -34439,10 +34452,8 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {...@@ -34439,10 +34452,8 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
34439 var offset: u64 = 0;34452 var offset: u64 = 0;
34440 var big_align: Alignment = .@"1";34453 var big_align: Alignment = .@"1";
34441 while (it.next()) |i| {34454 while (it.next()) |i| {
34442 const field_ty = struct_type.field_types.get(ip)[i].toType();34455 if (aligns[i] == .none) continue;
34443 // Type query definitely valid as we performed it earlier34456 big_align = big_align.maxStrict(aligns[i]);
34444 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
34445 big_align = big_align.max(aligns[i]);
34446 offsets[i] = @intCast(aligns[i].forward(offset));34457 offsets[i] = @intCast(aligns[i].forward(offset));
34447 offset = offsets[i] + sizes[i];34458 offset = offsets[i] + sizes[i];
34448 }34459 }
...@@ -36870,7 +36881,7 @@ fn structFieldAlignment(...@@ -36870,7 +36881,7 @@ fn structFieldAlignment(
36870 // extern36881 // extern
36871 const ty_abi_align = try sema.typeAbiAlignment(field_ty);36882 const ty_abi_align = try sema.typeAbiAlignment(field_ty);
36872 if (field_ty.isAbiInt(mod) and field_ty.intInfo(mod).bits >= 128) {36883 if (field_ty.isAbiInt(mod) and field_ty.intInfo(mod).bits >= 128) {
36873 return ty_abi_align.max(.@"16");36884 return ty_abi_align.maxStrict(.@"16");
36874 }36885 }
36875 return ty_abi_align;36886 return ty_abi_align;
36876}36887}