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;
77const assert = std.debug.assert;
88const DW = std.dwarf;
99const log = std.log.scoped(.llvm);
10const maxInt = std.math.maxInt;
1011const Writer = std.Io.Writer;
1112
1213const bitcode_writer = @import("bitcode_writer.zig");
......@@ -55,6 +56,8 @@ constant_items: std.MultiArrayList(Constant.Item),
5556constant_extra: std.ArrayList(u32),
5657constant_limbs: std.ArrayList(std.math.big.Limb),
5758
59alignment_forward_references: std.ArrayList(Alignment),
60
5861metadata_map: std.AutoArrayHashMapUnmanaged(void, void),
5962metadata_items: std.MultiArrayList(Metadata.Item),
6063metadata_extra: std.ArrayList(u32),
......@@ -85,7 +88,7 @@ pub const Options = struct {
8588};
8689
8790pub const String = enum(u32) {
88 none = std.math.maxInt(u31),
91 none = maxInt(u31),
8992 empty,
9093 _,
9194
......@@ -245,7 +248,7 @@ pub const Type = enum(u32) {
245248 ptr,
246249 @"ptr addrspace(4)",
247250
248 none = std.math.maxInt(u32),
251 none = maxInt(u32),
249252 _,
250253
251254 pub const ptr_amdgpu_constant =
......@@ -941,7 +944,7 @@ pub const Attribute = union(Kind) {
941944 inalloca: Type,
942945 sret: Type,
943946 elementtype: Type,
944 @"align": Alignment,
947 @"align": Alignment.Lazy,
945948 @"noalias",
946949 nocapture,
947950 nofree,
......@@ -956,7 +959,7 @@ pub const Attribute = union(Kind) {
956959 immarg,
957960 noundef,
958961 nofpclass: FpClass,
959 alignstack: Alignment,
962 alignstack: Alignment.Lazy,
960963 allocalign,
961964 allocptr,
962965 readnone,
......@@ -964,7 +967,7 @@ pub const Attribute = union(Kind) {
964967 writeonly,
965968
966969 // Function Attributes
967 //alignstack: Alignment,
970 //alignstack: Alignment.Lazy,
968971 allockind: AllocKind,
969972 allocsize: AllocSize,
970973 alwaysinline,
......@@ -1145,7 +1148,7 @@ pub const Attribute = union(Kind) {
11451148 return @unionInit(Attribute, field.name, switch (field.type) {
11461149 void => {},
11471150 u32 => storage.value,
1148 Alignment, String, Type, UwTable => @enumFromInt(storage.value),
1151 Alignment.Lazy, String, Type, UwTable => @enumFromInt(storage.value),
11491152 AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(storage.value),
11501153 else => @compileError("bad payload type: " ++ field.name ++ ": " ++
11511154 @typeName(field.type)),
......@@ -1246,7 +1249,7 @@ pub const Attribute = union(Kind) {
12461249 .sret,
12471250 .elementtype,
12481251 => |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(" ")}),
12501253 .dereferenceable,
12511254 .dereferenceable_or_null,
12521255 => |size| try w.print(" {s}({d})", .{ @tagName(attribute), size }),
......@@ -1270,7 +1273,7 @@ pub const Attribute = union(Kind) {
12701273 },
12711274 .alignstack => |alignment| {
12721275 try w.print(" {t}", .{attribute});
1273 const alignment_bytes = alignment.toByteUnits() orelse return;
1276 const alignment_bytes = alignment.resolve(data.builder).toByteUnits() orelse return;
12741277 if (data.flags.pound) {
12751278 try w.print("={d}", .{alignment_bytes});
12761279 } else {
......@@ -1435,8 +1438,8 @@ pub const Attribute = union(Kind) {
14351438 //sanitize_memtag,
14361439 sanitize_address_dyninit = 102,
14371440
1438 string = std.math.maxInt(u31),
1439 none = std.math.maxInt(u32),
1441 string = maxInt(u31),
1442 none = maxInt(u32),
14401443 _,
14411444
14421445 pub const len = @typeInfo(Kind).@"enum".fields.len - 2;
......@@ -1516,12 +1519,12 @@ pub const Attribute = union(Kind) {
15161519 elem_size: u16,
15171520 num_elems: u16,
15181521
1519 pub const none = std.math.maxInt(u16);
1522 pub const none = maxInt(u16);
15201523
15211524 fn toLlvm(self: AllocSize) packed struct(u64) { num_elems: u32, elem_size: u32 } {
15221525 return .{ .num_elems = switch (self.num_elems) {
15231526 else => self.num_elems,
1524 none => std.math.maxInt(u32),
1527 none => maxInt(u32),
15251528 }, .elem_size = self.elem_size };
15261529 }
15271530 };
......@@ -1577,7 +1580,7 @@ pub const Attribute = union(Kind) {
15771580 inline else => |value, tag| .{ .kind = @as(Kind, self), .value = switch (@TypeOf(value)) {
15781581 void => 0,
15791582 u32 => value,
1580 Alignment, String, Type, UwTable => @intFromEnum(value),
1583 Alignment.Lazy, String, Type, UwTable => @intFromEnum(value),
15811584 AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(value),
15821585 else => @compileError("bad payload type: " ++ @tagName(tag) ++ @typeName(@TypeOf(value))),
15831586 } },
......@@ -2017,9 +2020,32 @@ pub const ExternallyInitialized = enum {
20172020};
20182021
20192022pub const Alignment = enum(u6) {
2020 default = std.math.maxInt(u6),
2023 default = maxInt(u6),
20212024 _,
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
20232049 pub fn fromByteUnits(bytes: u64) Alignment {
20242050 if (bytes == 0) return .default;
20252051 assert(std.math.isPowerOfTwo(bytes));
......@@ -2028,11 +2054,17 @@ pub const Alignment = enum(u6) {
20282054 }
20292055
20302056 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 };
20322061 }
20332062
20342063 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 };
20362068 }
20372069
20382070 pub const Prefixed = struct {
......@@ -2180,7 +2212,7 @@ pub const CallConv = enum(u10) {
21802212};
21812213
21822214pub const StrtabString = enum(u32) {
2183 none = std.math.maxInt(u31),
2215 none = maxInt(u31),
21842216 empty,
21852217 _,
21862218
......@@ -2308,7 +2340,7 @@ pub const Global = struct {
23082340 },
23092341
23102342 pub const Index = enum(u32) {
2311 none = std.math.maxInt(u32),
2343 none = maxInt(u32),
23122344 _,
23132345
23142346 pub fn unwrap(self: Index, builder: *const Builder) Index {
......@@ -2478,7 +2510,7 @@ pub const Alias = struct {
24782510 aliasee: Constant = .no_init,
24792511
24802512 pub const Index = enum(u32) {
2481 none = std.math.maxInt(u32),
2513 none = maxInt(u32),
24822514 _,
24832515
24842516 pub fn ptr(self: Index, builder: *Builder) *Alias {
......@@ -2530,7 +2562,7 @@ pub const Variable = struct {
25302562 alignment: Alignment = .default,
25312563
25322564 pub const Index = enum(u32) {
2533 none = std.math.maxInt(u32),
2565 none = maxInt(u32),
25342566 _,
25352567
25362568 pub fn ptr(self: Index, builder: *Builder) *Variable {
......@@ -3949,7 +3981,7 @@ pub const Intrinsic = enum {
39493981 .params = &.{
39503982 .{
39513983 .kind = .{ .type = Type.ptr_amdgpu_constant },
3952 .attrs = &.{.{ .@"align" = Builder.Alignment.fromByteUnits(4) }},
3984 .attrs = &.{.{ .@"align" = .wrap(.fromByteUnits(4)) }},
39533985 },
39543986 },
39553987 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
......@@ -4057,7 +4089,7 @@ pub const Function = struct {
40574089 extra: []const u32 = &.{},
40584090
40594091 pub const Index = enum(u32) {
4060 none = std.math.maxInt(u32),
4092 none = maxInt(u32),
40614093 _,
40624094
40634095 pub fn ptr(self: Index, builder: *Builder) *Function {
......@@ -4411,7 +4443,7 @@ pub const Function = struct {
44114443 };
44124444
44134445 pub const Index = enum(u32) {
4414 none = std.math.maxInt(u31),
4446 none = maxInt(u31),
44154447 _,
44164448
44174449 pub fn name(self: Instruction.Index, function: *const Function) String {
......@@ -5007,7 +5039,7 @@ pub const Function = struct {
50075039 fsub = 12,
50085040 fmax = 13,
50095041 fmin = 14,
5010 none = std.math.maxInt(u5),
5042 none = maxInt(u5),
50115043 };
50125044 };
50135045
......@@ -6132,8 +6164,8 @@ pub const WipFunction = struct {
61326164 kind: MemoryAccessKind,
61336165 @"inline": bool,
61346166 ) Allocator.Error!Instruction.Index {
6135 var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })};
6136 var src_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = src_align })};
6167 var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = .wrap(dst_align) })};
6168 var src_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = .wrap(src_align) })};
61376169 const value = try self.callIntrinsic(
61386170 .normal,
61396171 try self.builder.fnAttrs(&.{
......@@ -6162,8 +6194,8 @@ pub const WipFunction = struct {
61626194 len: Value,
61636195 kind: MemoryAccessKind,
61646196 ) Allocator.Error!Instruction.Index {
6165 var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })};
6166 var src_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = src_align })};
6197 var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = .wrap(dst_align) })};
6198 var src_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = .wrap(src_align) })};
61676199 const value = try self.callIntrinsic(
61686200 .normal,
61696201 try self.builder.fnAttrs(&.{
......@@ -6192,7 +6224,7 @@ pub const WipFunction = struct {
61926224 kind: MemoryAccessKind,
61936225 @"inline": bool,
61946226 ) 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) })};
61966228 const value = try self.callIntrinsic(
61976229 .normal,
61986230 try self.builder.fnAttrs(&.{ .none, .none, try self.builder.attrs(&dst_attrs) }),
......@@ -7329,7 +7361,7 @@ pub const Constant = enum(u32) {
73297361 //indices: [info.indices_len]Constant,
73307362
73317363 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), _ };
73337365 pub const Info = packed struct(u32) { indices_len: u16, inrange: InRangeIndex };
73347366 };
73357367
......@@ -7579,7 +7611,7 @@ pub const Constant = enum(u32) {
75797611 string: [
75807612 (std.math.big.int.Const{
75817613 .limbs = &([1]std.math.big.Limb{
7582 std.math.maxInt(std.math.big.Limb),
7614 maxInt(std.math.big.Limb),
75837615 } ** expected_limbs),
75847616 .positive = false,
75857617 }).sizeInBaseUpperBound(10)
......@@ -7643,7 +7675,7 @@ pub const Constant = enum(u32) {
76437675 std.math.minInt(Exponent64),
76447676 else => @as(Exponent64, repr.exponent) +
76457677 (std.math.floatExponentMax(f64) - std.math.floatExponentMax(f32)),
7646 std.math.maxInt(Exponent32) => std.math.maxInt(Exponent64),
7678 maxInt(Exponent32) => maxInt(Exponent64),
76477679 },
76487680 .sign = repr.sign,
76497681 }))});
......@@ -7820,7 +7852,7 @@ pub const Constant = enum(u32) {
78207852};
78217853
78227854pub const Value = enum(u32) {
7823 none = std.math.maxInt(u31),
7855 none = maxInt(u31),
78247856 false = first_constant + @intFromEnum(Constant.false),
78257857 true = first_constant + @intFromEnum(Constant.true),
78267858 @"0" = first_constant + @intFromEnum(Constant.@"0"),
......@@ -8688,6 +8720,8 @@ pub fn init(options: Options) Allocator.Error!Builder {
86888720 .constant_extra = .empty,
86898721 .constant_limbs = .empty,
86908722
8723 .alignment_forward_references = .empty,
8724
86918725 .metadata_map = .empty,
86928726 .metadata_items = .empty,
86938727 .metadata_extra = .empty,
......@@ -8800,51 +8834,55 @@ pub fn clearAndFree(self: *Builder) void {
88008834}
88018835
88028836pub 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);
8806 self.string_indices.deinit(self.gpa);
8807 self.string_bytes.deinit(self.gpa);
8839 self.module_asm.deinit(gpa);
88088840
8809 self.types.deinit(self.gpa);
8810 self.next_unique_type_id.deinit(self.gpa);
8811 self.type_map.deinit(self.gpa);
8812 self.type_items.deinit(self.gpa);
8813 self.type_extra.deinit(self.gpa);
8841 self.string_map.deinit(gpa);
8842 self.string_indices.deinit(gpa);
8843 self.string_bytes.deinit(gpa);
88148844
8815 self.attributes.deinit(self.gpa);
8816 self.attributes_map.deinit(self.gpa);
8817 self.attributes_indices.deinit(self.gpa);
8818 self.attributes_extra.deinit(self.gpa);
8845 self.types.deinit(gpa);
8846 self.next_unique_type_id.deinit(gpa);
8847 self.type_map.deinit(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);
8823 self.next_unique_global_id.deinit(self.gpa);
8824 self.aliases.deinit(self.gpa);
8825 self.variables.deinit(self.gpa);
8826 for (self.functions.items) |*function| function.deinit(self.gpa);
8827 self.functions.deinit(self.gpa);
8856 self.function_attributes_set.deinit(gpa);
8857
8858 self.globals.deinit(gpa);
8859 self.next_unique_global_id.deinit(gpa);
8860 self.aliases.deinit(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);
8830 self.strtab_string_indices.deinit(self.gpa);
8831 self.strtab_string_bytes.deinit(self.gpa);
8865 self.strtab_string_map.deinit(gpa);
8866 self.strtab_string_indices.deinit(gpa);
8867 self.strtab_string_bytes.deinit(gpa);
88328868
8833 self.constant_map.deinit(self.gpa);
8834 self.constant_items.deinit(self.gpa);
8835 self.constant_extra.deinit(self.gpa);
8836 self.constant_limbs.deinit(self.gpa);
8869 self.constant_map.deinit(gpa);
8870 self.constant_items.deinit(gpa);
8871 self.constant_extra.deinit(gpa);
8872 self.constant_limbs.deinit(gpa);
88378873
8838 self.metadata_map.deinit(self.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);
8874 self.alignment_forward_references.deinit(gpa);
88448875
8845 self.metadata_string_map.deinit(self.gpa);
8846 self.metadata_string_indices.deinit(self.gpa);
8847 self.metadata_string_bytes.deinit(self.gpa);
8876 self.metadata_map.deinit(gpa);
8877 self.metadata_items.deinit(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
88498887 self.* = undefined;
88508888}
......@@ -8962,7 +9000,7 @@ pub fn structType(
89629000pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type {
89639001 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
89649002 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)});
89669004 try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);
89679005 }
89689006 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
......@@ -9578,6 +9616,21 @@ pub fn asmValue(
95789616 return (try self.asmConst(ty, info, assembly, constraints)).toValue();
95799617}
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
95819634pub fn dump(b: *Builder, io: Io) void {
95829635 var buffer: [4000]u8 = undefined;
95839636 const stderr: Io.File = .stderr();
......@@ -10515,7 +10568,7 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
1051510568 string: [
1051610569 (std.math.big.int.Const{
1051710570 .limbs = &([1]std.math.big.Limb{
10518 std.math.maxInt(std.math.big.Limb),
10571 maxInt(std.math.big.Limb),
1051910572 } ** expected_limbs),
1052010573 .positive = false,
1052110574 }).sizeInBaseUpperBound(10)
......@@ -10665,7 +10718,7 @@ fn printEscapedString(slice: []const u8, quotes: QuoteBehavior, w: *Writer) Writ
1066510718fn ensureUnusedGlobalCapacity(self: *Builder, name: StrtabString) Allocator.Error!void {
1066610719 try self.strtab_string_map.ensureUnusedCapacity(self.gpa, 1);
1066710720 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)});
1066910722 try self.strtab_string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);
1067010723 }
1067110724 try self.strtab_string_indices.ensureUnusedCapacity(self.gpa, 1);
......@@ -13518,7 +13571,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
1351813571 try record.ensureUnusedCapacity(self.gpa, 3);
1351913572 record.appendAssumeCapacity(1);
1352013573 record.appendAssumeCapacity(@intFromEnum(kind));
13521 record.appendAssumeCapacity(alignment.toByteUnits() orelse 0);
13574 record.appendAssumeCapacity(alignment.resolve(self).toByteUnits() orelse 0);
1352213575 },
1352313576 .dereferenceable,
1352413577 .dereferenceable_or_null,
src/Sema.zig-15
......@@ -7110,12 +7110,7 @@ fn analyzeCall(
71107110 }
71117111 for (args, 0..) |arg, arg_idx| {
71127112 const arg_src = args_info.argSrc(block, arg_idx);
7113 const arg_ty = sema.typeOf(arg);
71147113 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 }
71197114 }
71207115 const runtime_func: Air.Inst.Ref, const runtime_args: []const Air.Inst.Ref = func: {
71217116 if (!any_generic_types and !any_comptime_params) break :func .{ callee, args };
......@@ -24779,16 +24774,6 @@ fn zirBuiltinExtern(
2477924774 }
2478024775 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 }
2479224777 const extern_val = try pt.getExtern(.{
2479324778 .name = options.name,
2479424779 .ty = ptr_info.child,
src/Zcu/PerThread.zig-14
......@@ -1832,16 +1832,6 @@ fn analyzeNavVal(
18321832 const lib_name_src = block.src(.{ .node_offset_lib_name = .zero });
18331833 try sema.handleExternLibName(&block, lib_name_src, l);
18341834 }
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 }
18451835 break :val .fromInterned(try pt.getExtern(.{
18461836 .name = old_nav.name,
18471837 .ty = nav_ty.toIntern(),
......@@ -3398,10 +3388,6 @@ fn analyzeFuncBodyInner(
33983388 const param_ty_src = inner_block.src(.{ .func_decl_param_ty = @intCast(zir_param_index) });
33993389
34003390 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 }
34053391 if (try param_ty.onePossibleValue(pt)) |opv| {
34063392 gop.value_ptr.* = .fromValue(opv);
34073393 continue;
src/codegen/llvm.zig+102-52
......@@ -520,6 +520,21 @@ pub const Object = struct {
520520 gpa: Allocator,
521521 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
523538 debug_compile_unit: Builder.Metadata.Optional,
524539
525540 debug_enums_fwd_ref: Builder.Metadata.Optional,
......@@ -530,8 +545,6 @@ pub const Object = struct {
530545
531546 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,
535548 /// Keyed on `link.ConstPool.Index`.
536549 debug_types: std.ArrayList(Builder.Metadata),
537550 /// 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 {
660673 obj.* = .{
661674 .gpa = gpa,
662675 .builder = builder,
676 .type_pool = .empty,
677 .lazy_abi_aligns = .empty,
663678 .debug_compile_unit = debug_compile_unit,
664679 .debug_enums_fwd_ref = debug_enums_fwd_ref,
665680 .debug_globals_fwd_ref = debug_globals_fwd_ref,
666681 .debug_enums = .empty,
667682 .debug_globals = .empty,
668683 .debug_file_map = .empty,
669 .debug_type_pool = .empty,
670684 .debug_types = .empty,
671685 .debug_anyerror_fwd_ref = .none,
672686 .target = target,
......@@ -685,10 +699,11 @@ pub const Object = struct {
685699
686700 pub fn deinit(self: *Object) void {
687701 const gpa = self.gpa;
702 self.type_pool.deinit(gpa);
703 self.lazy_abi_aligns.deinit(gpa);
688704 self.debug_enums.deinit(gpa);
689705 self.debug_globals.deinit(gpa);
690706 self.debug_file_map.deinit(gpa);
691 self.debug_type_pool.deinit(gpa);
692707 self.debug_types.deinit(gpa);
693708 self.nav_map.deinit(gpa);
694709 self.uav_map.deinit(gpa);
......@@ -836,7 +851,7 @@ pub const Object = struct {
836851 o.builder.resolveDebugForwardReference(fwd_ref, debug_anyerror_type);
837852 }
838853
839 try o.flushPendingDebugTypes(pt);
854 try o.flushTypePool(pt);
840855
841856 o.builder.resolveDebugForwardReference(
842857 o.debug_enums_fwd_ref.unwrap().?,
......@@ -1396,10 +1411,10 @@ pub const Object = struct {
13961411 if (ptr_info.flags.is_const) {
13971412 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
13981413 }
1399 const elem_align = (if (ptr_info.flags.alignment != .none)
1400 @as(InternPool.Alignment, ptr_info.flags.alignment)
1401 else
1402 Type.fromInterned(ptr_info.child).abiAlignment(zcu).max(.@"1")).toLlvm();
1414 const elem_align: Builder.Alignment.Lazy = switch (ptr_info.flags.alignment) {
1415 else => |a| .wrap(a.toLlvm()),
1416 .none => try o.lazyAbiAlignment(pt, .fromInterned(ptr_info.child)),
1417 };
14031418 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
14041419 const ptr_param = wip.arg(llvm_arg_i);
14051420 llvm_arg_i += 1;
......@@ -1600,7 +1615,7 @@ pub const Object = struct {
16001615 }
16011616
16021617 try fg.wip.finish();
1603 try o.flushPendingDebugTypes(pt);
1618 try o.flushTypePool(pt);
16041619 }
16051620
16061621 pub fn updateNav(self: *Object, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
......@@ -1617,11 +1632,11 @@ pub const Object = struct {
16171632 },
16181633 else => |e| return e,
16191634 };
1620 try self.flushPendingDebugTypes(pt);
1635 try self.flushTypePool(pt);
16211636 }
16221637
1623 fn flushPendingDebugTypes(o: *Object, pt: Zcu.PerThread) Allocator.Error!void {
1624 try o.debug_type_pool.flushPending(pt, .{ .llvm = o });
1638 fn flushTypePool(o: *Object, pt: Zcu.PerThread) Allocator.Error!void {
1639 try o.type_pool.flushPending(pt, .{ .llvm = o });
16251640 }
16261641
16271642 pub fn updateExports(
......@@ -1818,51 +1833,81 @@ pub const Object = struct {
18181833 }
18191834
18201835 pub fn updateContainerType(o: *Object, pt: Zcu.PerThread, ty: InternPool.Index, success: bool) Allocator.Error!void {
1821 if (!o.builder.strip) {
1822 try o.debug_type_pool.updateContainerType(pt, .{ .llvm = o }, ty, success);
1823 }
1836 try o.type_pool.updateContainerType(pt, .{ .llvm = o }, ty, success);
18241837 }
18251838
18261839 /// Should only be called by the `link.ConstPool` implementation.
18271840 ///
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.
18291842 pub fn addConst(o: *Object, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) Allocator.Error!void {
18301843 const zcu = pt.zcu;
18311844 const gpa = zcu.comp.gpa;
18321845 assert(zcu.intern_pool.typeOf(val) == .type_type);
1833 assert(@intFromEnum(index) == o.debug_types.items.len);
1834 try o.debug_types.ensureUnusedCapacity(gpa, 1);
1835 const fwd_ref = try o.builder.debugForwardReference();
1836 o.debug_types.appendAssumeCapacity(fwd_ref);
1837 if (val == .anyerror_type) {
1838 assert(o.debug_anyerror_fwd_ref.is_none);
1839 o.debug_anyerror_fwd_ref = fwd_ref.toOptional();
1846
1847 {
1848 assert(@intFromEnum(index) == o.lazy_abi_aligns.items.len);
1849 try o.lazy_abi_aligns.ensureUnusedCapacity(gpa, 1);
1850 const fwd_ref = try o.builder.alignmentForwardReference();
1851 o.lazy_abi_aligns.appendAssumeCapacity(fwd_ref);
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 }
18401863 }
18411864 }
18421865 /// Should only be called by the `link.ConstPool` implementation.
18431866 ///
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.
18451868 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);
1847 const fwd_ref = o.debug_types.items[@intFromEnum(index)];
1848 assert(val != .anyerror_type);
1849 const name_str = try o.builder.metadataStringFmt("{f}", .{Type.fromInterned(val).fmt(pt)});
1850 const debug_incomplete_type = try o.builder.debugSignedType(name_str, 0);
1851 o.builder.resolveDebugForwardReference(fwd_ref, debug_incomplete_type);
1869 const zcu = pt.zcu;
1870 assert(zcu.intern_pool.typeOf(val) == .type_type);
1871
1872 const ty: Type = .fromInterned(val);
1873
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 }
18521886 }
18531887 /// Should only be called by the `link.ConstPool` implementation.
18541888 ///
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.
18561890 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);
1858 const fwd_ref = o.debug_types.items[@intFromEnum(index)];
1859 if (val == .anyerror_type) {
1860 // Don't lower this now; it will be populated in `emit` instead.
1861 assert(o.debug_anyerror_fwd_ref == fwd_ref.toOptional());
1862 return;
1891 const zcu = pt.zcu;
1892 assert(zcu.intern_pool.typeOf(val) == .type_type);
1893
1894 const ty: Type = .fromInterned(val);
1895
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 }
18631910 }
1864 const debug_type = try o.lowerDebugType(pt, .fromInterned(val), fwd_ref);
1865 o.builder.resolveDebugForwardReference(fwd_ref, debug_type);
18661911 }
18671912
18681913 fn getDebugFile(o: *Object, pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.Error!Builder.Metadata {
......@@ -1883,7 +1928,7 @@ pub const Object = struct {
18831928
18841929 fn getDebugType(o: *Object, pt: Zcu.PerThread, ty: Type) Allocator.Error!Builder.Metadata {
18851930 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());
18871932 return o.debug_types.items[@intFromEnum(index)];
18881933 }
18891934
......@@ -2680,7 +2725,7 @@ pub const Object = struct {
26802725 function_index.setCallConv(cc_info.llvm_cc, &o.builder);
26812726
26822727 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);
26842729 } else {
26852730 _ = try attributes.removeFnAttr(.alignstack);
26862731 }
......@@ -4166,11 +4211,11 @@ pub const Object = struct {
41664211 if (ptr_info.flags.is_const) {
41674212 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
41684213 }
4169 const elem_align = if (ptr_info.flags.alignment != .none)
4170 ptr_info.flags.alignment
4171 else
4172 Type.fromInterned(ptr_info.child).abiAlignment(zcu).max(.@"1");
4173 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align.toLlvm() }, &o.builder);
4214 const elem_align: Builder.Alignment.Lazy = switch (ptr_info.flags.alignment) {
4215 else => |a| .wrap(a.toLlvm()),
4216 .none => try o.lazyAbiAlignment(pt, .fromInterned(ptr_info.child)),
4217 };
4218 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
41744219 } else if (ccAbiPromoteInt(fn_info.cc, zcu, param_ty)) |s| switch (s) {
41754220 .signed => try attributes.addParamAttr(llvm_arg_i, .signext, &o.builder),
41764221 .unsigned => try attributes.addParamAttr(llvm_arg_i, .zeroext, &o.builder),
......@@ -4187,7 +4232,7 @@ pub const Object = struct {
41874232 ) Allocator.Error!void {
41884233 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
41894234 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);
41914236 if (byval) try attributes.addParamAttr(llvm_arg_i, .{ .byval = param_llvm_ty }, &o.builder);
41924237 }
41934238
......@@ -4297,6 +4342,11 @@ pub const Object = struct {
42974342 try wip.finish();
42984343 return function_index;
42994344 }
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 }
43004350};
43014351
43024352pub const NavGen = struct {
......@@ -5259,10 +5309,10 @@ pub const FuncGen = struct {
52595309 if (ptr_info.flags.is_const) {
52605310 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
52615311 }
5262 const elem_align = (if (ptr_info.flags.alignment != .none)
5263 @as(InternPool.Alignment, ptr_info.flags.alignment)
5264 else
5265 Type.fromInterned(ptr_info.child).abiAlignment(zcu).max(.@"1")).toLlvm();
5312 const elem_align: Builder.Alignment.Lazy = switch (ptr_info.flags.alignment) {
5313 else => |a| .wrap(a.toLlvm()),
5314 .none => try o.lazyAbiAlignment(pt, .fromInterned(ptr_info.child)),
5315 };
52665316 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
52675317 },
52685318 };