authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-02-28 10:10:15+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-03-10 10:26:13+00:00
log0a246f5e67118328a11df51cd6dfa419793ebeb1
tree420631e4a735bd3274ad61658c740e653170ac96
parentd462794e20127f396753c7d6064a9d2b4e0304d9
signaturelock-open Commit is signed but in an unrecognized format.

compiler: stop LLVM bossing the frontend around

I previously wrote some weird code in the compiler frontend solely because the LLVM backend has some weird requirements, but the better solution is to avoid those requirements. This commit does that by introducing "alignment forward references" to `std.zig.llvm.Builder`. Much like debug forward references, they allow you to reference an alignment value which will be populated at a later time (and which can be updated many times, which is important for incremental compilation). Then, when we want to reference a type's ABI alignment while the type is not necessarily resolved (required for `@"align"` attributes on function parameters and function call arguments), we create a forward reference and use `link.ConstPool` to populate it when ready. This allows us to remove from the compiler frontend some extremely arbitrary calls to `Sema.ensureLayoutResolved`, so that the language specification is not being built around the particular needs of our compiler implementation's LLVM code generation backend.

4 files changed, 228 insertions(+), 154 deletions(-)

lib/std/zig/llvm/Builder.zig+126-73
...@@ -7,6 +7,7 @@ const Allocator = std.mem.Allocator;...@@ -7,6 +7,7 @@ const Allocator = std.mem.Allocator;
7const assert = std.debug.assert;7const assert = std.debug.assert;
8const DW = std.dwarf;8const DW = std.dwarf;
9const log = std.log.scoped(.llvm);9const log = std.log.scoped(.llvm);
10const maxInt = std.math.maxInt;
10const Writer = std.Io.Writer;11const Writer = std.Io.Writer;
1112
12const bitcode_writer = @import("bitcode_writer.zig");13const bitcode_writer = @import("bitcode_writer.zig");
...@@ -55,6 +56,8 @@ constant_items: std.MultiArrayList(Constant.Item),...@@ -55,6 +56,8 @@ constant_items: std.MultiArrayList(Constant.Item),
55constant_extra: std.ArrayList(u32),56constant_extra: std.ArrayList(u32),
56constant_limbs: std.ArrayList(std.math.big.Limb),57constant_limbs: std.ArrayList(std.math.big.Limb),
5758
59alignment_forward_references: std.ArrayList(Alignment),
60
58metadata_map: std.AutoArrayHashMapUnmanaged(void, void),61metadata_map: std.AutoArrayHashMapUnmanaged(void, void),
59metadata_items: std.MultiArrayList(Metadata.Item),62metadata_items: std.MultiArrayList(Metadata.Item),
60metadata_extra: std.ArrayList(u32),63metadata_extra: std.ArrayList(u32),
...@@ -85,7 +88,7 @@ pub const Options = struct {...@@ -85,7 +88,7 @@ pub const Options = struct {
85};88};
8689
87pub const String = enum(u32) {90pub const String = enum(u32) {
88 none = std.math.maxInt(u31),91 none = maxInt(u31),
89 empty,92 empty,
90 _,93 _,
9194
...@@ -245,7 +248,7 @@ pub const Type = enum(u32) {...@@ -245,7 +248,7 @@ pub const Type = enum(u32) {
245 ptr,248 ptr,
246 @"ptr addrspace(4)",249 @"ptr addrspace(4)",
247250
248 none = std.math.maxInt(u32),251 none = maxInt(u32),
249 _,252 _,
250253
251 pub const ptr_amdgpu_constant =254 pub const ptr_amdgpu_constant =
...@@ -941,7 +944,7 @@ pub const Attribute = union(Kind) {...@@ -941,7 +944,7 @@ pub const Attribute = union(Kind) {
941 inalloca: Type,944 inalloca: Type,
942 sret: Type,945 sret: Type,
943 elementtype: Type,946 elementtype: Type,
944 @"align": Alignment,947 @"align": Alignment.Lazy,
945 @"noalias",948 @"noalias",
946 nocapture,949 nocapture,
947 nofree,950 nofree,
...@@ -956,7 +959,7 @@ pub const Attribute = union(Kind) {...@@ -956,7 +959,7 @@ pub const Attribute = union(Kind) {
956 immarg,959 immarg,
957 noundef,960 noundef,
958 nofpclass: FpClass,961 nofpclass: FpClass,
959 alignstack: Alignment,962 alignstack: Alignment.Lazy,
960 allocalign,963 allocalign,
961 allocptr,964 allocptr,
962 readnone,965 readnone,
...@@ -964,7 +967,7 @@ pub const Attribute = union(Kind) {...@@ -964,7 +967,7 @@ pub const Attribute = union(Kind) {
964 writeonly,967 writeonly,
965968
966 // Function Attributes969 // Function Attributes
967 //alignstack: Alignment,970 //alignstack: Alignment.Lazy,
968 allockind: AllocKind,971 allockind: AllocKind,
969 allocsize: AllocSize,972 allocsize: AllocSize,
970 alwaysinline,973 alwaysinline,
...@@ -1145,7 +1148,7 @@ pub const Attribute = union(Kind) {...@@ -1145,7 +1148,7 @@ pub const Attribute = union(Kind) {
1145 return @unionInit(Attribute, field.name, switch (field.type) {1148 return @unionInit(Attribute, field.name, switch (field.type) {
1146 void => {},1149 void => {},
1147 u32 => storage.value,1150 u32 => storage.value,
1148 Alignment, String, Type, UwTable => @enumFromInt(storage.value),1151 Alignment.Lazy, String, Type, UwTable => @enumFromInt(storage.value),
1149 AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(storage.value),1152 AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(storage.value),
1150 else => @compileError("bad payload type: " ++ field.name ++ ": " ++1153 else => @compileError("bad payload type: " ++ field.name ++ ": " ++
1151 @typeName(field.type)),1154 @typeName(field.type)),
...@@ -1246,7 +1249,7 @@ pub const Attribute = union(Kind) {...@@ -1246,7 +1249,7 @@ pub const Attribute = union(Kind) {
1246 .sret,1249 .sret,
1247 .elementtype,1250 .elementtype,
1248 => |ty| try w.print(" {s}({f})", .{ @tagName(attribute), ty.fmt(data.builder, .percent) }),1251 => |ty| try w.print(" {s}({f})", .{ @tagName(attribute), ty.fmt(data.builder, .percent) }),
1249 .@"align" => |alignment| try w.print("{f}", .{alignment.fmt(" ")}),1252 .@"align" => |alignment| try w.print("{f}", .{alignment.resolve(data.builder).fmt(" ")}),
1250 .dereferenceable,1253 .dereferenceable,
1251 .dereferenceable_or_null,1254 .dereferenceable_or_null,
1252 => |size| try w.print(" {s}({d})", .{ @tagName(attribute), size }),1255 => |size| try w.print(" {s}({d})", .{ @tagName(attribute), size }),
...@@ -1270,7 +1273,7 @@ pub const Attribute = union(Kind) {...@@ -1270,7 +1273,7 @@ pub const Attribute = union(Kind) {
1270 },1273 },
1271 .alignstack => |alignment| {1274 .alignstack => |alignment| {
1272 try w.print(" {t}", .{attribute});1275 try w.print(" {t}", .{attribute});
1273 const alignment_bytes = alignment.toByteUnits() orelse return;1276 const alignment_bytes = alignment.resolve(data.builder).toByteUnits() orelse return;
1274 if (data.flags.pound) {1277 if (data.flags.pound) {
1275 try w.print("={d}", .{alignment_bytes});1278 try w.print("={d}", .{alignment_bytes});
1276 } else {1279 } else {
...@@ -1435,8 +1438,8 @@ pub const Attribute = union(Kind) {...@@ -1435,8 +1438,8 @@ pub const Attribute = union(Kind) {
1435 //sanitize_memtag,1438 //sanitize_memtag,
1436 sanitize_address_dyninit = 102,1439 sanitize_address_dyninit = 102,
14371440
1438 string = std.math.maxInt(u31),1441 string = maxInt(u31),
1439 none = std.math.maxInt(u32),1442 none = maxInt(u32),
1440 _,1443 _,
14411444
1442 pub const len = @typeInfo(Kind).@"enum".fields.len - 2;1445 pub const len = @typeInfo(Kind).@"enum".fields.len - 2;
...@@ -1516,12 +1519,12 @@ pub const Attribute = union(Kind) {...@@ -1516,12 +1519,12 @@ pub const Attribute = union(Kind) {
1516 elem_size: u16,1519 elem_size: u16,
1517 num_elems: u16,1520 num_elems: u16,
15181521
1519 pub const none = std.math.maxInt(u16);1522 pub const none = maxInt(u16);
15201523
1521 fn toLlvm(self: AllocSize) packed struct(u64) { num_elems: u32, elem_size: u32 } {1524 fn toLlvm(self: AllocSize) packed struct(u64) { num_elems: u32, elem_size: u32 } {
1522 return .{ .num_elems = switch (self.num_elems) {1525 return .{ .num_elems = switch (self.num_elems) {
1523 else => self.num_elems,1526 else => self.num_elems,
1524 none => std.math.maxInt(u32),1527 none => maxInt(u32),
1525 }, .elem_size = self.elem_size };1528 }, .elem_size = self.elem_size };
1526 }1529 }
1527 };1530 };
...@@ -1577,7 +1580,7 @@ pub const Attribute = union(Kind) {...@@ -1577,7 +1580,7 @@ pub const Attribute = union(Kind) {
1577 inline else => |value, tag| .{ .kind = @as(Kind, self), .value = switch (@TypeOf(value)) {1580 inline else => |value, tag| .{ .kind = @as(Kind, self), .value = switch (@TypeOf(value)) {
1578 void => 0,1581 void => 0,
1579 u32 => value,1582 u32 => value,
1580 Alignment, String, Type, UwTable => @intFromEnum(value),1583 Alignment.Lazy, String, Type, UwTable => @intFromEnum(value),
1581 AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(value),1584 AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(value),
1582 else => @compileError("bad payload type: " ++ @tagName(tag) ++ @typeName(@TypeOf(value))),1585 else => @compileError("bad payload type: " ++ @tagName(tag) ++ @typeName(@TypeOf(value))),
1583 } },1586 } },
...@@ -2017,9 +2020,32 @@ pub const ExternallyInitialized = enum {...@@ -2017,9 +2020,32 @@ pub const ExternallyInitialized = enum {
2017};2020};
20182021
2019pub const Alignment = enum(u6) {2022pub const Alignment = enum(u6) {
2020 default = std.math.maxInt(u6),2023 default = maxInt(u6),
2021 _,2024 _,
20222025
2026 pub const Lazy = enum(u32) {
2027 /// Values which fit in a `u6` are already-resolved `Alignment` values. Other values are
2028 /// indices into `Builder.alignment_forward_references`, offset by `maxInt(u6)`.
2029 _,
2030
2031 pub fn wrap(a: Alignment) Lazy {
2032 return @enumFromInt(@intFromEnum(a));
2033 }
2034 pub fn resolve(l: Lazy, b: *const Builder) Alignment {
2035 return switch (@intFromEnum(l)) {
2036 0...maxInt(u6) => |raw| @enumFromInt(raw),
2037 else => |offset_index| b.alignment_forward_references.items[offset_index - maxInt(u6)],
2038 };
2039 }
2040
2041 fn fromFwdRefIndex(index: usize) Lazy {
2042 return @enumFromInt(index + maxInt(u6));
2043 }
2044 fn toFwdRefIndex(l: Lazy) usize {
2045 return @intFromEnum(l) - maxInt(u6);
2046 }
2047 };
2048
2023 pub fn fromByteUnits(bytes: u64) Alignment {2049 pub fn fromByteUnits(bytes: u64) Alignment {
2024 if (bytes == 0) return .default;2050 if (bytes == 0) return .default;
2025 assert(std.math.isPowerOfTwo(bytes));2051 assert(std.math.isPowerOfTwo(bytes));
...@@ -2028,11 +2054,17 @@ pub const Alignment = enum(u6) {...@@ -2028,11 +2054,17 @@ pub const Alignment = enum(u6) {
2028 }2054 }
20292055
2030 pub fn toByteUnits(self: Alignment) ?u64 {2056 pub fn toByteUnits(self: Alignment) ?u64 {
2031 return if (self == .default) null else @as(u64, 1) << @intFromEnum(self);2057 return switch (self) {
2058 .default => null,
2059 else => @as(u64, 1) << @intFromEnum(self),
2060 };
2032 }2061 }
20332062
2034 pub fn toLlvm(self: Alignment) u6 {2063 pub fn toLlvm(self: Alignment) u6 {
2035 return if (self == .default) 0 else (@intFromEnum(self) + 1);2064 return switch (self) {
2065 .default => 0,
2066 else => @intFromEnum(self) + 1,
2067 };
2036 }2068 }
20372069
2038 pub const Prefixed = struct {2070 pub const Prefixed = struct {
...@@ -2180,7 +2212,7 @@ pub const CallConv = enum(u10) {...@@ -2180,7 +2212,7 @@ pub const CallConv = enum(u10) {
2180};2212};
21812213
2182pub const StrtabString = enum(u32) {2214pub const StrtabString = enum(u32) {
2183 none = std.math.maxInt(u31),2215 none = maxInt(u31),
2184 empty,2216 empty,
2185 _,2217 _,
21862218
...@@ -2308,7 +2340,7 @@ pub const Global = struct {...@@ -2308,7 +2340,7 @@ pub const Global = struct {
2308 },2340 },
23092341
2310 pub const Index = enum(u32) {2342 pub const Index = enum(u32) {
2311 none = std.math.maxInt(u32),2343 none = maxInt(u32),
2312 _,2344 _,
23132345
2314 pub fn unwrap(self: Index, builder: *const Builder) Index {2346 pub fn unwrap(self: Index, builder: *const Builder) Index {
...@@ -2478,7 +2510,7 @@ pub const Alias = struct {...@@ -2478,7 +2510,7 @@ pub const Alias = struct {
2478 aliasee: Constant = .no_init,2510 aliasee: Constant = .no_init,
24792511
2480 pub const Index = enum(u32) {2512 pub const Index = enum(u32) {
2481 none = std.math.maxInt(u32),2513 none = maxInt(u32),
2482 _,2514 _,
24832515
2484 pub fn ptr(self: Index, builder: *Builder) *Alias {2516 pub fn ptr(self: Index, builder: *Builder) *Alias {
...@@ -2530,7 +2562,7 @@ pub const Variable = struct {...@@ -2530,7 +2562,7 @@ pub const Variable = struct {
2530 alignment: Alignment = .default,2562 alignment: Alignment = .default,
25312563
2532 pub const Index = enum(u32) {2564 pub const Index = enum(u32) {
2533 none = std.math.maxInt(u32),2565 none = maxInt(u32),
2534 _,2566 _,
25352567
2536 pub fn ptr(self: Index, builder: *Builder) *Variable {2568 pub fn ptr(self: Index, builder: *Builder) *Variable {
...@@ -3949,7 +3981,7 @@ pub const Intrinsic = enum {...@@ -3949,7 +3981,7 @@ pub const Intrinsic = enum {
3949 .params = &.{3981 .params = &.{
3950 .{3982 .{
3951 .kind = .{ .type = Type.ptr_amdgpu_constant },3983 .kind = .{ .type = Type.ptr_amdgpu_constant },
3952 .attrs = &.{.{ .@"align" = Builder.Alignment.fromByteUnits(4) }},3984 .attrs = &.{.{ .@"align" = .wrap(.fromByteUnits(4)) }},
3953 },3985 },
3954 },3986 },
3955 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },3987 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
...@@ -4057,7 +4089,7 @@ pub const Function = struct {...@@ -4057,7 +4089,7 @@ pub const Function = struct {
4057 extra: []const u32 = &.{},4089 extra: []const u32 = &.{},
40584090
4059 pub const Index = enum(u32) {4091 pub const Index = enum(u32) {
4060 none = std.math.maxInt(u32),4092 none = maxInt(u32),
4061 _,4093 _,
40624094
4063 pub fn ptr(self: Index, builder: *Builder) *Function {4095 pub fn ptr(self: Index, builder: *Builder) *Function {
...@@ -4411,7 +4443,7 @@ pub const Function = struct {...@@ -4411,7 +4443,7 @@ pub const Function = struct {
4411 };4443 };
44124444
4413 pub const Index = enum(u32) {4445 pub const Index = enum(u32) {
4414 none = std.math.maxInt(u31),4446 none = maxInt(u31),
4415 _,4447 _,
44164448
4417 pub fn name(self: Instruction.Index, function: *const Function) String {4449 pub fn name(self: Instruction.Index, function: *const Function) String {
...@@ -5007,7 +5039,7 @@ pub const Function = struct {...@@ -5007,7 +5039,7 @@ pub const Function = struct {
5007 fsub = 12,5039 fsub = 12,
5008 fmax = 13,5040 fmax = 13,
5009 fmin = 14,5041 fmin = 14,
5010 none = std.math.maxInt(u5),5042 none = maxInt(u5),
5011 };5043 };
5012 };5044 };
50135045
...@@ -6132,8 +6164,8 @@ pub const WipFunction = struct {...@@ -6132,8 +6164,8 @@ pub const WipFunction = struct {
6132 kind: MemoryAccessKind,6164 kind: MemoryAccessKind,
6133 @"inline": bool,6165 @"inline": bool,
6134 ) Allocator.Error!Instruction.Index {6166 ) Allocator.Error!Instruction.Index {
6135 var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })};6167 var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = .wrap(dst_align) })};
6136 var src_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = src_align })};6168 var src_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = .wrap(src_align) })};
6137 const value = try self.callIntrinsic(6169 const value = try self.callIntrinsic(
6138 .normal,6170 .normal,
6139 try self.builder.fnAttrs(&.{6171 try self.builder.fnAttrs(&.{
...@@ -6162,8 +6194,8 @@ pub const WipFunction = struct {...@@ -6162,8 +6194,8 @@ pub const WipFunction = struct {
6162 len: Value,6194 len: Value,
6163 kind: MemoryAccessKind,6195 kind: MemoryAccessKind,
6164 ) Allocator.Error!Instruction.Index {6196 ) Allocator.Error!Instruction.Index {
6165 var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })};6197 var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = .wrap(dst_align) })};
6166 var src_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = src_align })};6198 var src_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = .wrap(src_align) })};
6167 const value = try self.callIntrinsic(6199 const value = try self.callIntrinsic(
6168 .normal,6200 .normal,
6169 try self.builder.fnAttrs(&.{6201 try self.builder.fnAttrs(&.{
...@@ -6192,7 +6224,7 @@ pub const WipFunction = struct {...@@ -6192,7 +6224,7 @@ pub const WipFunction = struct {
6192 kind: MemoryAccessKind,6224 kind: MemoryAccessKind,
6193 @"inline": bool,6225 @"inline": bool,
6194 ) Allocator.Error!Instruction.Index {6226 ) Allocator.Error!Instruction.Index {
6195 var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })};6227 var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = .wrap(dst_align) })};
6196 const value = try self.callIntrinsic(6228 const value = try self.callIntrinsic(
6197 .normal,6229 .normal,
6198 try self.builder.fnAttrs(&.{ .none, .none, try self.builder.attrs(&dst_attrs) }),6230 try self.builder.fnAttrs(&.{ .none, .none, try self.builder.attrs(&dst_attrs) }),
...@@ -7329,7 +7361,7 @@ pub const Constant = enum(u32) {...@@ -7329,7 +7361,7 @@ pub const Constant = enum(u32) {
7329 //indices: [info.indices_len]Constant,7361 //indices: [info.indices_len]Constant,
73307362
7331 pub const Kind = enum { normal, inbounds };7363 pub const Kind = enum { normal, inbounds };
7332 pub const InRangeIndex = enum(u16) { none = std.math.maxInt(u16), _ };7364 pub const InRangeIndex = enum(u16) { none = maxInt(u16), _ };
7333 pub const Info = packed struct(u32) { indices_len: u16, inrange: InRangeIndex };7365 pub const Info = packed struct(u32) { indices_len: u16, inrange: InRangeIndex };
7334 };7366 };
73357367
...@@ -7579,7 +7611,7 @@ pub const Constant = enum(u32) {...@@ -7579,7 +7611,7 @@ pub const Constant = enum(u32) {
7579 string: [7611 string: [
7580 (std.math.big.int.Const{7612 (std.math.big.int.Const{
7581 .limbs = &([1]std.math.big.Limb{7613 .limbs = &([1]std.math.big.Limb{
7582 std.math.maxInt(std.math.big.Limb),7614 maxInt(std.math.big.Limb),
7583 } ** expected_limbs),7615 } ** expected_limbs),
7584 .positive = false,7616 .positive = false,
7585 }).sizeInBaseUpperBound(10)7617 }).sizeInBaseUpperBound(10)
...@@ -7643,7 +7675,7 @@ pub const Constant = enum(u32) {...@@ -7643,7 +7675,7 @@ pub const Constant = enum(u32) {
7643 std.math.minInt(Exponent64),7675 std.math.minInt(Exponent64),
7644 else => @as(Exponent64, repr.exponent) +7676 else => @as(Exponent64, repr.exponent) +
7645 (std.math.floatExponentMax(f64) - std.math.floatExponentMax(f32)),7677 (std.math.floatExponentMax(f64) - std.math.floatExponentMax(f32)),
7646 std.math.maxInt(Exponent32) => std.math.maxInt(Exponent64),7678 maxInt(Exponent32) => maxInt(Exponent64),
7647 },7679 },
7648 .sign = repr.sign,7680 .sign = repr.sign,
7649 }))});7681 }))});
...@@ -7820,7 +7852,7 @@ pub const Constant = enum(u32) {...@@ -7820,7 +7852,7 @@ pub const Constant = enum(u32) {
7820};7852};
78217853
7822pub const Value = enum(u32) {7854pub const Value = enum(u32) {
7823 none = std.math.maxInt(u31),7855 none = maxInt(u31),
7824 false = first_constant + @intFromEnum(Constant.false),7856 false = first_constant + @intFromEnum(Constant.false),
7825 true = first_constant + @intFromEnum(Constant.true),7857 true = first_constant + @intFromEnum(Constant.true),
7826 @"0" = first_constant + @intFromEnum(Constant.@"0"),7858 @"0" = first_constant + @intFromEnum(Constant.@"0"),
...@@ -8688,6 +8720,8 @@ pub fn init(options: Options) Allocator.Error!Builder {...@@ -8688,6 +8720,8 @@ pub fn init(options: Options) Allocator.Error!Builder {
8688 .constant_extra = .empty,8720 .constant_extra = .empty,
8689 .constant_limbs = .empty,8721 .constant_limbs = .empty,
86908722
8723 .alignment_forward_references = .empty,
8724
8691 .metadata_map = .empty,8725 .metadata_map = .empty,
8692 .metadata_items = .empty,8726 .metadata_items = .empty,
8693 .metadata_extra = .empty,8727 .metadata_extra = .empty,
...@@ -8800,51 +8834,55 @@ pub fn clearAndFree(self: *Builder) void {...@@ -8800,51 +8834,55 @@ pub fn clearAndFree(self: *Builder) void {
8800}8834}
88018835
8802pub fn deinit(self: *Builder) void {8836pub fn deinit(self: *Builder) void {
8803 self.module_asm.deinit(self.gpa);8837 const gpa = self.gpa;
88048838
8805 self.string_map.deinit(self.gpa);8839 self.module_asm.deinit(gpa);
8806 self.string_indices.deinit(self.gpa);
8807 self.string_bytes.deinit(self.gpa);
88088840
8809 self.types.deinit(self.gpa);8841 self.string_map.deinit(gpa);
8810 self.next_unique_type_id.deinit(self.gpa);8842 self.string_indices.deinit(gpa);
8811 self.type_map.deinit(self.gpa);8843 self.string_bytes.deinit(gpa);
8812 self.type_items.deinit(self.gpa);
8813 self.type_extra.deinit(self.gpa);
88148844
8815 self.attributes.deinit(self.gpa);8845 self.types.deinit(gpa);
8816 self.attributes_map.deinit(self.gpa);8846 self.next_unique_type_id.deinit(gpa);
8817 self.attributes_indices.deinit(self.gpa);8847 self.type_map.deinit(gpa);
8818 self.attributes_extra.deinit(self.gpa);8848 self.type_items.deinit(gpa);
8849 self.type_extra.deinit(gpa);
88198850
8820 self.function_attributes_set.deinit(self.gpa);8851 self.attributes.deinit(gpa);
8852 self.attributes_map.deinit(gpa);
8853 self.attributes_indices.deinit(gpa);
8854 self.attributes_extra.deinit(gpa);
88218855
8822 self.globals.deinit(self.gpa);8856 self.function_attributes_set.deinit(gpa);
8823 self.next_unique_global_id.deinit(self.gpa);8857
8824 self.aliases.deinit(self.gpa);8858 self.globals.deinit(gpa);
8825 self.variables.deinit(self.gpa);8859 self.next_unique_global_id.deinit(gpa);
8826 for (self.functions.items) |*function| function.deinit(self.gpa);8860 self.aliases.deinit(gpa);
8827 self.functions.deinit(self.gpa);8861 self.variables.deinit(gpa);
8862 for (self.functions.items) |*function| function.deinit(gpa);
8863 self.functions.deinit(gpa);
88288864
8829 self.strtab_string_map.deinit(self.gpa);8865 self.strtab_string_map.deinit(gpa);
8830 self.strtab_string_indices.deinit(self.gpa);8866 self.strtab_string_indices.deinit(gpa);
8831 self.strtab_string_bytes.deinit(self.gpa);8867 self.strtab_string_bytes.deinit(gpa);
88328868
8833 self.constant_map.deinit(self.gpa);8869 self.constant_map.deinit(gpa);
8834 self.constant_items.deinit(self.gpa);8870 self.constant_items.deinit(gpa);
8835 self.constant_extra.deinit(self.gpa);8871 self.constant_extra.deinit(gpa);
8836 self.constant_limbs.deinit(self.gpa);8872 self.constant_limbs.deinit(gpa);
88378873
8838 self.metadata_map.deinit(self.gpa);8874 self.alignment_forward_references.deinit(gpa);
8839 self.metadata_items.deinit(self.gpa);
8840 self.metadata_extra.deinit(self.gpa);
8841 self.metadata_limbs.deinit(self.gpa);
8842 self.metadata_forward_references.deinit(self.gpa);
8843 self.metadata_named.deinit(self.gpa);
88448875
8845 self.metadata_string_map.deinit(self.gpa);8876 self.metadata_map.deinit(gpa);
8846 self.metadata_string_indices.deinit(self.gpa);8877 self.metadata_items.deinit(gpa);
8847 self.metadata_string_bytes.deinit(self.gpa);8878 self.metadata_extra.deinit(gpa);
8879 self.metadata_limbs.deinit(gpa);
8880 self.metadata_forward_references.deinit(gpa);
8881 self.metadata_named.deinit(gpa);
8882
8883 self.metadata_string_map.deinit(gpa);
8884 self.metadata_string_indices.deinit(gpa);
8885 self.metadata_string_bytes.deinit(gpa);
88488886
8849 self.* = undefined;8887 self.* = undefined;
8850}8888}
...@@ -8962,7 +9000,7 @@ pub fn structType(...@@ -8962,7 +9000,7 @@ pub fn structType(
8962pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type {9000pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type {
8963 try self.string_map.ensureUnusedCapacity(self.gpa, 1);9001 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
8964 if (name.slice(self)) |id| {9002 if (name.slice(self)) |id| {
8965 const count: usize = comptime std.fmt.count("{d}", .{std.math.maxInt(u32)});9003 const count: usize = comptime std.fmt.count("{d}", .{maxInt(u32)});
8966 try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);9004 try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);
8967 }9005 }
8968 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);9006 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
...@@ -9578,6 +9616,21 @@ pub fn asmValue(...@@ -9578,6 +9616,21 @@ pub fn asmValue(
9578 return (try self.asmConst(ty, info, assembly, constraints)).toValue();9616 return (try self.asmConst(ty, info, assembly, constraints)).toValue();
9579}9617}
95809618
9619/// The initial "resolved" value of the forward reference is `Alignment.default`.
9620pub fn alignmentForwardReference(b: *Builder) Allocator.Error!Alignment.Lazy {
9621 const index = b.alignment_forward_references.items.len;
9622 try b.alignment_forward_references.append(b.gpa, .default);
9623 return .fromFwdRefIndex(index);
9624}
9625
9626/// Updates the "resolved" value of the alignment forward reference `fwd_ref` to `value`.
9627///
9628/// Asserts that `fwd_ref` is a forward reference, as opposed to a resolved alignment value.
9629pub fn resolveAlignmentForwardReference(b: *Builder, fwd_ref: Alignment.Lazy, value: Alignment) void {
9630 const index = fwd_ref.toFwdRefIndex();
9631 b.alignment_forward_references.items[index] = value;
9632}
9633
9581pub fn dump(b: *Builder, io: Io) void {9634pub fn dump(b: *Builder, io: Io) void {
9582 var buffer: [4000]u8 = undefined;9635 var buffer: [4000]u8 = undefined;
9583 const stderr: Io.File = .stderr();9636 const stderr: Io.File = .stderr();
...@@ -10515,7 +10568,7 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void...@@ -10515,7 +10568,7 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
10515 string: [10568 string: [
10516 (std.math.big.int.Const{10569 (std.math.big.int.Const{
10517 .limbs = &([1]std.math.big.Limb{10570 .limbs = &([1]std.math.big.Limb{
10518 std.math.maxInt(std.math.big.Limb),10571 maxInt(std.math.big.Limb),
10519 } ** expected_limbs),10572 } ** expected_limbs),
10520 .positive = false,10573 .positive = false,
10521 }).sizeInBaseUpperBound(10)10574 }).sizeInBaseUpperBound(10)
...@@ -10665,7 +10718,7 @@ fn printEscapedString(slice: []const u8, quotes: QuoteBehavior, w: *Writer) Writ...@@ -10665,7 +10718,7 @@ fn printEscapedString(slice: []const u8, quotes: QuoteBehavior, w: *Writer) Writ
10665fn ensureUnusedGlobalCapacity(self: *Builder, name: StrtabString) Allocator.Error!void {10718fn ensureUnusedGlobalCapacity(self: *Builder, name: StrtabString) Allocator.Error!void {
10666 try self.strtab_string_map.ensureUnusedCapacity(self.gpa, 1);10719 try self.strtab_string_map.ensureUnusedCapacity(self.gpa, 1);
10667 if (name.slice(self)) |id| {10720 if (name.slice(self)) |id| {
10668 const count: usize = comptime std.fmt.count("{d}", .{std.math.maxInt(u32)});10721 const count: usize = comptime std.fmt.count("{d}", .{maxInt(u32)});
10669 try self.strtab_string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);10722 try self.strtab_string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);
10670 }10723 }
10671 try self.strtab_string_indices.ensureUnusedCapacity(self.gpa, 1);10724 try self.strtab_string_indices.ensureUnusedCapacity(self.gpa, 1);
...@@ -13518,7 +13571,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco...@@ -13518,7 +13571,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
13518 try record.ensureUnusedCapacity(self.gpa, 3);13571 try record.ensureUnusedCapacity(self.gpa, 3);
13519 record.appendAssumeCapacity(1);13572 record.appendAssumeCapacity(1);
13520 record.appendAssumeCapacity(@intFromEnum(kind));13573 record.appendAssumeCapacity(@intFromEnum(kind));
13521 record.appendAssumeCapacity(alignment.toByteUnits() orelse 0);13574 record.appendAssumeCapacity(alignment.resolve(self).toByteUnits() orelse 0);
13522 },13575 },
13523 .dereferenceable,13576 .dereferenceable,
13524 .dereferenceable_or_null,13577 .dereferenceable_or_null,
src/Sema.zig-15
...@@ -7110,12 +7110,7 @@ fn analyzeCall(...@@ -7110,12 +7110,7 @@ fn analyzeCall(
7110 }7110 }
7111 for (args, 0..) |arg, arg_idx| {7111 for (args, 0..) |arg, arg_idx| {
7112 const arg_src = args_info.argSrc(block, arg_idx);7112 const arg_src = args_info.argSrc(block, arg_idx);
7113 const arg_ty = sema.typeOf(arg);
7114 try sema.validateRuntimeValue(block, arg_src, arg);7113 try sema.validateRuntimeValue(block, arg_src, arg);
7115 if (arg_ty.isPtrAtRuntime(zcu) or arg_ty.isSliceAtRuntime(zcu)) {
7116 // LLVM wants this information for an "align" attribute on the argument.
7117 try sema.ensureLayoutResolved(arg_ty.nullablePtrElem(zcu), arg_src, .init);
7118 }
7119 }7114 }
7120 const runtime_func: Air.Inst.Ref, const runtime_args: []const Air.Inst.Ref = func: {7115 const runtime_func: Air.Inst.Ref, const runtime_args: []const Air.Inst.Ref = func: {
7121 if (!any_generic_types and !any_comptime_params) break :func .{ callee, args };7116 if (!any_generic_types and !any_comptime_params) break :func .{ callee, args };
...@@ -24779,16 +24774,6 @@ fn zirBuiltinExtern(...@@ -24779,16 +24774,6 @@ fn zirBuiltinExtern(
24779 }24774 }
24780 const ptr_info = ty.ptrInfo(zcu);24775 const ptr_info = ty.ptrInfo(zcu);
2478124776
24782 if (Type.fromInterned(ptr_info.child).zigTypeTag(zcu) == .@"fn") {
24783 const func_type = ip.indexToKey(ptr_info.child).func_type;
24784 for (func_type.param_types.get(ip)) |param_ty_ip| {
24785 const param_ty: Type = .fromInterned(param_ty_ip);
24786 if (param_ty.isPtrAtRuntime(zcu) or param_ty.isSliceAtRuntime(zcu)) {
24787 // LLVM wants this information for an "align" attribute on the parameter.
24788 try sema.ensureLayoutResolved(param_ty.nullablePtrElem(zcu), ty_src, .parameter);
24789 }
24790 }
24791 }
24792 const extern_val = try pt.getExtern(.{24777 const extern_val = try pt.getExtern(.{
24793 .name = options.name,24778 .name = options.name,
24794 .ty = ptr_info.child,24779 .ty = ptr_info.child,
src/Zcu/PerThread.zig-14
...@@ -1832,16 +1832,6 @@ fn analyzeNavVal(...@@ -1832,16 +1832,6 @@ fn analyzeNavVal(
1832 const lib_name_src = block.src(.{ .node_offset_lib_name = .zero });1832 const lib_name_src = block.src(.{ .node_offset_lib_name = .zero });
1833 try sema.handleExternLibName(&block, lib_name_src, l);1833 try sema.handleExternLibName(&block, lib_name_src, l);
1834 }1834 }
1835 if (nav_ty.zigTypeTag(zcu) == .@"fn") {
1836 const func_type = ip.indexToKey(nav_ty.toIntern()).func_type;
1837 for (func_type.param_types.get(ip)) |param_ty_ip| {
1838 const param_ty: Type = .fromInterned(param_ty_ip);
1839 if (param_ty.isPtrAtRuntime(zcu) or param_ty.isSliceAtRuntime(zcu)) {
1840 // LLVM wants this information for an "align" attribute on the parameter.
1841 try sema.ensureLayoutResolved(param_ty.nullablePtrElem(zcu), ty_src, .parameter);
1842 }
1843 }
1844 }
1845 break :val .fromInterned(try pt.getExtern(.{1835 break :val .fromInterned(try pt.getExtern(.{
1846 .name = old_nav.name,1836 .name = old_nav.name,
1847 .ty = nav_ty.toIntern(),1837 .ty = nav_ty.toIntern(),
...@@ -3398,10 +3388,6 @@ fn analyzeFuncBodyInner(...@@ -3398,10 +3388,6 @@ fn analyzeFuncBodyInner(
3398 const param_ty_src = inner_block.src(.{ .func_decl_param_ty = @intCast(zir_param_index) });3388 const param_ty_src = inner_block.src(.{ .func_decl_param_ty = @intCast(zir_param_index) });
33993389
3400 try sema.ensureLayoutResolved(param_ty, param_ty_src, .parameter);3390 try sema.ensureLayoutResolved(param_ty, param_ty_src, .parameter);
3401 if (param_ty.isPtrAtRuntime(zcu) or param_ty.isSliceAtRuntime(zcu)) {
3402 // LLVM wants this information for an "align" attribute on the parameter.
3403 try sema.ensureLayoutResolved(param_ty.nullablePtrElem(zcu), param_ty_src, .parameter);
3404 }
3405 if (try param_ty.onePossibleValue(pt)) |opv| {3391 if (try param_ty.onePossibleValue(pt)) |opv| {
3406 gop.value_ptr.* = .fromValue(opv);3392 gop.value_ptr.* = .fromValue(opv);
3407 continue;3393 continue;
src/codegen/llvm.zig+102-52
...@@ -520,6 +520,21 @@ pub const Object = struct {...@@ -520,6 +520,21 @@ pub const Object = struct {
520 gpa: Allocator,520 gpa: Allocator,
521 builder: Builder,521 builder: Builder,
522522
523 /// This pool contains only types (and not `@as(type, undefined)`). It has two purposes:
524 ///
525 /// * Lazily tracking ABI alignment of types, so that `@"align"` attributes can be set to a
526 /// type's ABI alignment before that type is fully resolved. Each type in the pool has a
527 /// corresponding entry in `lazy_abi_aligns`.
528 ///
529 /// * If `!Object.builder.strip`, lazily tracking debug information types, so that debug
530 /// information can handle indirect self-reference (and so that debug information works
531 /// correctly across incremental updates). Each type has a corresponding entry in
532 /// `debug_types`, provided that `Object.builder.strip` is `false`.
533 type_pool: link.ConstPool,
534
535 /// Keyed on `link.ConstPool.Index`.
536 lazy_abi_aligns: std.ArrayList(Builder.Alignment.Lazy),
537
523 debug_compile_unit: Builder.Metadata.Optional,538 debug_compile_unit: Builder.Metadata.Optional,
524539
525 debug_enums_fwd_ref: Builder.Metadata.Optional,540 debug_enums_fwd_ref: Builder.Metadata.Optional,
...@@ -530,8 +545,6 @@ pub const Object = struct {...@@ -530,8 +545,6 @@ pub const Object = struct {
530545
531 debug_file_map: std.AutoHashMapUnmanaged(Zcu.File.Index, Builder.Metadata),546 debug_file_map: std.AutoHashMapUnmanaged(Zcu.File.Index, Builder.Metadata),
532547
533 /// This pool *only* contains types (and does not contain `@as(type, undefined)`).
534 debug_type_pool: link.ConstPool,
535 /// Keyed on `link.ConstPool.Index`.548 /// Keyed on `link.ConstPool.Index`.
536 debug_types: std.ArrayList(Builder.Metadata),549 debug_types: std.ArrayList(Builder.Metadata),
537 /// Initially `.none`, set if the type `anyerror` is lowered to a debug type. The type will not550 /// Initially `.none`, set if the type `anyerror` is lowered to a debug type. The type will not
...@@ -660,13 +673,14 @@ pub const Object = struct {...@@ -660,13 +673,14 @@ pub const Object = struct {
660 obj.* = .{673 obj.* = .{
661 .gpa = gpa,674 .gpa = gpa,
662 .builder = builder,675 .builder = builder,
676 .type_pool = .empty,
677 .lazy_abi_aligns = .empty,
663 .debug_compile_unit = debug_compile_unit,678 .debug_compile_unit = debug_compile_unit,
664 .debug_enums_fwd_ref = debug_enums_fwd_ref,679 .debug_enums_fwd_ref = debug_enums_fwd_ref,
665 .debug_globals_fwd_ref = debug_globals_fwd_ref,680 .debug_globals_fwd_ref = debug_globals_fwd_ref,
666 .debug_enums = .empty,681 .debug_enums = .empty,
667 .debug_globals = .empty,682 .debug_globals = .empty,
668 .debug_file_map = .empty,683 .debug_file_map = .empty,
669 .debug_type_pool = .empty,
670 .debug_types = .empty,684 .debug_types = .empty,
671 .debug_anyerror_fwd_ref = .none,685 .debug_anyerror_fwd_ref = .none,
672 .target = target,686 .target = target,
...@@ -685,10 +699,11 @@ pub const Object = struct {...@@ -685,10 +699,11 @@ pub const Object = struct {
685699
686 pub fn deinit(self: *Object) void {700 pub fn deinit(self: *Object) void {
687 const gpa = self.gpa;701 const gpa = self.gpa;
702 self.type_pool.deinit(gpa);
703 self.lazy_abi_aligns.deinit(gpa);
688 self.debug_enums.deinit(gpa);704 self.debug_enums.deinit(gpa);
689 self.debug_globals.deinit(gpa);705 self.debug_globals.deinit(gpa);
690 self.debug_file_map.deinit(gpa);706 self.debug_file_map.deinit(gpa);
691 self.debug_type_pool.deinit(gpa);
692 self.debug_types.deinit(gpa);707 self.debug_types.deinit(gpa);
693 self.nav_map.deinit(gpa);708 self.nav_map.deinit(gpa);
694 self.uav_map.deinit(gpa);709 self.uav_map.deinit(gpa);
...@@ -836,7 +851,7 @@ pub const Object = struct {...@@ -836,7 +851,7 @@ pub const Object = struct {
836 o.builder.resolveDebugForwardReference(fwd_ref, debug_anyerror_type);851 o.builder.resolveDebugForwardReference(fwd_ref, debug_anyerror_type);
837 }852 }
838853
839 try o.flushPendingDebugTypes(pt);854 try o.flushTypePool(pt);
840855
841 o.builder.resolveDebugForwardReference(856 o.builder.resolveDebugForwardReference(
842 o.debug_enums_fwd_ref.unwrap().?,857 o.debug_enums_fwd_ref.unwrap().?,
...@@ -1396,10 +1411,10 @@ pub const Object = struct {...@@ -1396,10 +1411,10 @@ pub const Object = struct {
1396 if (ptr_info.flags.is_const) {1411 if (ptr_info.flags.is_const) {
1397 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);1412 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
1398 }1413 }
1399 const elem_align = (if (ptr_info.flags.alignment != .none)1414 const elem_align: Builder.Alignment.Lazy = switch (ptr_info.flags.alignment) {
1400 @as(InternPool.Alignment, ptr_info.flags.alignment)1415 else => |a| .wrap(a.toLlvm()),
1401 else1416 .none => try o.lazyAbiAlignment(pt, .fromInterned(ptr_info.child)),
1402 Type.fromInterned(ptr_info.child).abiAlignment(zcu).max(.@"1")).toLlvm();1417 };
1403 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);1418 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
1404 const ptr_param = wip.arg(llvm_arg_i);1419 const ptr_param = wip.arg(llvm_arg_i);
1405 llvm_arg_i += 1;1420 llvm_arg_i += 1;
...@@ -1600,7 +1615,7 @@ pub const Object = struct {...@@ -1600,7 +1615,7 @@ pub const Object = struct {
1600 }1615 }
16011616
1602 try fg.wip.finish();1617 try fg.wip.finish();
1603 try o.flushPendingDebugTypes(pt);1618 try o.flushTypePool(pt);
1604 }1619 }
16051620
1606 pub fn updateNav(self: *Object, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {1621 pub fn updateNav(self: *Object, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
...@@ -1617,11 +1632,11 @@ pub const Object = struct {...@@ -1617,11 +1632,11 @@ pub const Object = struct {
1617 },1632 },
1618 else => |e| return e,1633 else => |e| return e,
1619 };1634 };
1620 try self.flushPendingDebugTypes(pt);1635 try self.flushTypePool(pt);
1621 }1636 }
16221637
1623 fn flushPendingDebugTypes(o: *Object, pt: Zcu.PerThread) Allocator.Error!void {1638 fn flushTypePool(o: *Object, pt: Zcu.PerThread) Allocator.Error!void {
1624 try o.debug_type_pool.flushPending(pt, .{ .llvm = o });1639 try o.type_pool.flushPending(pt, .{ .llvm = o });
1625 }1640 }
16261641
1627 pub fn updateExports(1642 pub fn updateExports(
...@@ -1818,51 +1833,81 @@ pub const Object = struct {...@@ -1818,51 +1833,81 @@ pub const Object = struct {
1818 }1833 }
18191834
1820 pub fn updateContainerType(o: *Object, pt: Zcu.PerThread, ty: InternPool.Index, success: bool) Allocator.Error!void {1835 pub fn updateContainerType(o: *Object, pt: Zcu.PerThread, ty: InternPool.Index, success: bool) Allocator.Error!void {
1821 if (!o.builder.strip) {1836 try o.type_pool.updateContainerType(pt, .{ .llvm = o }, ty, success);
1822 try o.debug_type_pool.updateContainerType(pt, .{ .llvm = o }, ty, success);
1823 }
1824 }1837 }
18251838
1826 /// Should only be called by the `link.ConstPool` implementation.1839 /// Should only be called by the `link.ConstPool` implementation.
1827 ///1840 ///
1828 /// `val` is always a type because `o.debug_type_pool` only contains types.1841 /// `val` is always a type because `o.type_pool` only contains types.
1829 pub fn addConst(o: *Object, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) Allocator.Error!void {1842 pub fn addConst(o: *Object, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) Allocator.Error!void {
1830 const zcu = pt.zcu;1843 const zcu = pt.zcu;
1831 const gpa = zcu.comp.gpa;1844 const gpa = zcu.comp.gpa;
1832 assert(zcu.intern_pool.typeOf(val) == .type_type);1845 assert(zcu.intern_pool.typeOf(val) == .type_type);
1833 assert(@intFromEnum(index) == o.debug_types.items.len);1846
1834 try o.debug_types.ensureUnusedCapacity(gpa, 1);1847 {
1835 const fwd_ref = try o.builder.debugForwardReference();1848 assert(@intFromEnum(index) == o.lazy_abi_aligns.items.len);
1836 o.debug_types.appendAssumeCapacity(fwd_ref);1849 try o.lazy_abi_aligns.ensureUnusedCapacity(gpa, 1);
1837 if (val == .anyerror_type) {1850 const fwd_ref = try o.builder.alignmentForwardReference();
1838 assert(o.debug_anyerror_fwd_ref.is_none);1851 o.lazy_abi_aligns.appendAssumeCapacity(fwd_ref);
1839 o.debug_anyerror_fwd_ref = fwd_ref.toOptional();1852 }
1853
1854 if (!o.builder.strip) {
1855 assert(@intFromEnum(index) == o.debug_types.items.len);
1856 try o.debug_types.ensureUnusedCapacity(gpa, 1);
1857 const fwd_ref = try o.builder.debugForwardReference();
1858 o.debug_types.appendAssumeCapacity(fwd_ref);
1859 if (val == .anyerror_type) {
1860 assert(o.debug_anyerror_fwd_ref.is_none);
1861 o.debug_anyerror_fwd_ref = fwd_ref.toOptional();
1862 }
1840 }1863 }
1841 }1864 }
1842 /// Should only be called by the `link.ConstPool` implementation.1865 /// Should only be called by the `link.ConstPool` implementation.
1843 ///1866 ///
1844 /// `val` is always a type because `o.debug_type_pool` only contains types.1867 /// `val` is always a type because `o.type_pool` only contains types.
1845 pub fn updateConstIncomplete(o: *Object, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) Allocator.Error!void {1868 pub fn updateConstIncomplete(o: *Object, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) Allocator.Error!void {
1846 assert(pt.zcu.intern_pool.typeOf(val) == .type_type);1869 const zcu = pt.zcu;
1847 const fwd_ref = o.debug_types.items[@intFromEnum(index)];1870 assert(zcu.intern_pool.typeOf(val) == .type_type);
1848 assert(val != .anyerror_type);1871
1849 const name_str = try o.builder.metadataStringFmt("{f}", .{Type.fromInterned(val).fmt(pt)});1872 const ty: Type = .fromInterned(val);
1850 const debug_incomplete_type = try o.builder.debugSignedType(name_str, 0);1873
1851 o.builder.resolveDebugForwardReference(fwd_ref, debug_incomplete_type);1874 {
1875 const fwd_ref = o.lazy_abi_aligns.items[@intFromEnum(index)];
1876 o.builder.resolveAlignmentForwardReference(fwd_ref, .fromByteUnits(1));
1877 }
1878
1879 if (!o.builder.strip) {
1880 assert(val != .anyerror_type);
1881 const fwd_ref = o.debug_types.items[@intFromEnum(index)];
1882 const name_str = try o.builder.metadataStringFmt("{f}", .{ty.fmt(pt)});
1883 const debug_incomplete_type = try o.builder.debugSignedType(name_str, 0);
1884 o.builder.resolveDebugForwardReference(fwd_ref, debug_incomplete_type);
1885 }
1852 }1886 }
1853 /// Should only be called by the `link.ConstPool` implementation.1887 /// Should only be called by the `link.ConstPool` implementation.
1854 ///1888 ///
1855 /// `val` is always a type because `o.debug_type_pool` only contains types.1889 /// `val` is always a type because `o.type_pool` only contains types.
1856 pub fn updateConst(o: *Object, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) Allocator.Error!void {1890 pub fn updateConst(o: *Object, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) Allocator.Error!void {
1857 assert(pt.zcu.intern_pool.typeOf(val) == .type_type);1891 const zcu = pt.zcu;
1858 const fwd_ref = o.debug_types.items[@intFromEnum(index)];1892 assert(zcu.intern_pool.typeOf(val) == .type_type);
1859 if (val == .anyerror_type) {1893
1860 // Don't lower this now; it will be populated in `emit` instead.1894 const ty: Type = .fromInterned(val);
1861 assert(o.debug_anyerror_fwd_ref == fwd_ref.toOptional());1895
1862 return;1896 {
1897 const fwd_ref = o.lazy_abi_aligns.items[@intFromEnum(index)];
1898 o.builder.resolveAlignmentForwardReference(fwd_ref, ty.abiAlignment(zcu).toLlvm());
1899 }
1900
1901 if (!o.builder.strip) {
1902 const fwd_ref = o.debug_types.items[@intFromEnum(index)];
1903 if (val == .anyerror_type) {
1904 // Don't lower this now; it will be populated in `emit` instead.
1905 assert(o.debug_anyerror_fwd_ref == fwd_ref.toOptional());
1906 } else {
1907 const debug_type = try o.lowerDebugType(pt, ty, fwd_ref);
1908 o.builder.resolveDebugForwardReference(fwd_ref, debug_type);
1909 }
1863 }1910 }
1864 const debug_type = try o.lowerDebugType(pt, .fromInterned(val), fwd_ref);
1865 o.builder.resolveDebugForwardReference(fwd_ref, debug_type);
1866 }1911 }
18671912
1868 fn getDebugFile(o: *Object, pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.Error!Builder.Metadata {1913 fn getDebugFile(o: *Object, pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.Error!Builder.Metadata {
...@@ -1883,7 +1928,7 @@ pub const Object = struct {...@@ -1883,7 +1928,7 @@ pub const Object = struct {
18831928
1884 fn getDebugType(o: *Object, pt: Zcu.PerThread, ty: Type) Allocator.Error!Builder.Metadata {1929 fn getDebugType(o: *Object, pt: Zcu.PerThread, ty: Type) Allocator.Error!Builder.Metadata {
1885 assert(!o.builder.strip);1930 assert(!o.builder.strip);
1886 const index = try o.debug_type_pool.get(pt, .{ .llvm = o }, ty.toIntern());1931 const index = try o.type_pool.get(pt, .{ .llvm = o }, ty.toIntern());
1887 return o.debug_types.items[@intFromEnum(index)];1932 return o.debug_types.items[@intFromEnum(index)];
1888 }1933 }
18891934
...@@ -2680,7 +2725,7 @@ pub const Object = struct {...@@ -2680,7 +2725,7 @@ pub const Object = struct {
2680 function_index.setCallConv(cc_info.llvm_cc, &o.builder);2725 function_index.setCallConv(cc_info.llvm_cc, &o.builder);
26812726
2682 if (cc_info.align_stack) {2727 if (cc_info.align_stack) {
2683 try attributes.addFnAttr(.{ .alignstack = .fromByteUnits(target.stackAlignment()) }, &o.builder);2728 try attributes.addFnAttr(.{ .alignstack = .wrap(.fromByteUnits(target.stackAlignment())) }, &o.builder);
2684 } else {2729 } else {
2685 _ = try attributes.removeFnAttr(.alignstack);2730 _ = try attributes.removeFnAttr(.alignstack);
2686 }2731 }
...@@ -4166,11 +4211,11 @@ pub const Object = struct {...@@ -4166,11 +4211,11 @@ pub const Object = struct {
4166 if (ptr_info.flags.is_const) {4211 if (ptr_info.flags.is_const) {
4167 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);4212 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
4168 }4213 }
4169 const elem_align = if (ptr_info.flags.alignment != .none)4214 const elem_align: Builder.Alignment.Lazy = switch (ptr_info.flags.alignment) {
4170 ptr_info.flags.alignment4215 else => |a| .wrap(a.toLlvm()),
4171 else4216 .none => try o.lazyAbiAlignment(pt, .fromInterned(ptr_info.child)),
4172 Type.fromInterned(ptr_info.child).abiAlignment(zcu).max(.@"1");4217 };
4173 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align.toLlvm() }, &o.builder);4218 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
4174 } else if (ccAbiPromoteInt(fn_info.cc, zcu, param_ty)) |s| switch (s) {4219 } else if (ccAbiPromoteInt(fn_info.cc, zcu, param_ty)) |s| switch (s) {
4175 .signed => try attributes.addParamAttr(llvm_arg_i, .signext, &o.builder),4220 .signed => try attributes.addParamAttr(llvm_arg_i, .signext, &o.builder),
4176 .unsigned => try attributes.addParamAttr(llvm_arg_i, .zeroext, &o.builder),4221 .unsigned => try attributes.addParamAttr(llvm_arg_i, .zeroext, &o.builder),
...@@ -4187,7 +4232,7 @@ pub const Object = struct {...@@ -4187,7 +4232,7 @@ pub const Object = struct {
4187 ) Allocator.Error!void {4232 ) Allocator.Error!void {
4188 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);4233 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
4189 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);4234 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
4190 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = alignment }, &o.builder);4235 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = .wrap(alignment) }, &o.builder);
4191 if (byval) try attributes.addParamAttr(llvm_arg_i, .{ .byval = param_llvm_ty }, &o.builder);4236 if (byval) try attributes.addParamAttr(llvm_arg_i, .{ .byval = param_llvm_ty }, &o.builder);
4192 }4237 }
41934238
...@@ -4297,6 +4342,11 @@ pub const Object = struct {...@@ -4297,6 +4342,11 @@ pub const Object = struct {
4297 try wip.finish();4342 try wip.finish();
4298 return function_index;4343 return function_index;
4299 }4344 }
4345
4346 fn lazyAbiAlignment(o: *Object, pt: Zcu.PerThread, ty: Type) Allocator.Error!Builder.Alignment.Lazy {
4347 const index = try o.type_pool.get(pt, .{ .llvm = o }, ty.toIntern());
4348 return o.lazy_abi_aligns.items[@intFromEnum(index)];
4349 }
4300};4350};
43014351
4302pub const NavGen = struct {4352pub const NavGen = struct {
...@@ -5259,10 +5309,10 @@ pub const FuncGen = struct {...@@ -5259,10 +5309,10 @@ pub const FuncGen = struct {
5259 if (ptr_info.flags.is_const) {5309 if (ptr_info.flags.is_const) {
5260 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);5310 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
5261 }5311 }
5262 const elem_align = (if (ptr_info.flags.alignment != .none)5312 const elem_align: Builder.Alignment.Lazy = switch (ptr_info.flags.alignment) {
5263 @as(InternPool.Alignment, ptr_info.flags.alignment)5313 else => |a| .wrap(a.toLlvm()),
5264 else5314 .none => try o.lazyAbiAlignment(pt, .fromInterned(ptr_info.child)),
5265 Type.fromInterned(ptr_info.child).abiAlignment(zcu).max(.@"1")).toLlvm();5315 };
5266 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);5316 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
5267 },5317 },
5268 };5318 };