From 74ba5762ece3029bcac4934b430dd5180f54fe1c Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sun, 15 Dec 2024 22:46:02 -0500 Subject: [PATCH 1/4] Dwarf: preserve deduped struct navs Previously, if multiple navs owned the same type due to being the same zir node and having the same captures, they would overwrite each other. Now, the navs codegenned later emit a decl alias to the first one. --- src/link/Dwarf.zig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 14a1190cf3..6bf311fe7f 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -2632,7 +2632,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern()); if (type_gop.found_existing) { - dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).clear(); + if (dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).len > 0) break :tag .decl_alias; nav_gop.value_ptr.* = type_gop.value_ptr.*; } else { if (nav_gop.found_existing) @@ -2733,7 +2733,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern()); if (type_gop.found_existing) { - dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).clear(); + if (dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).len > 0) break :tag .decl_alias; nav_gop.value_ptr.* = type_gop.value_ptr.*; } else { if (nav_gop.found_existing) @@ -2788,7 +2788,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern()); if (type_gop.found_existing) { - dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).clear(); + if (dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).len > 0) break :tag .decl_alias; nav_gop.value_ptr.* = type_gop.value_ptr.*; } else { if (nav_gop.found_existing) @@ -2879,7 +2879,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern()); if (type_gop.found_existing) { - dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).clear(); + if (dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).len > 0) break :tag .decl_alias; nav_gop.value_ptr.* = type_gop.value_ptr.*; } else { if (nav_gop.found_existing) From 1983adb8ae710a374b4cb1bb4cb5514abac7ddd0 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 16 Dec 2024 02:15:36 -0500 Subject: [PATCH 2/4] InternPool: we have pointer subtraction now! --- src/InternPool.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/InternPool.zig b/src/InternPool.zig index 749be6348a..1dbfbb24e1 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -1163,7 +1163,7 @@ const Local = struct { capacity: u32, }; fn header(list: ListSelf) *Header { - return @ptrFromInt(@intFromPtr(list.bytes) - bytes_offset); + return @alignCast(@ptrCast(list.bytes - bytes_offset)); } pub fn view(list: ListSelf) View { const capacity = list.header().capacity; @@ -1372,7 +1372,7 @@ const Shard = struct { } }; fn header(map: @This()) *Header { - return @ptrFromInt(@intFromPtr(map.entries) - entries_offset); + return @alignCast(@ptrCast(@as([*]u8, @ptrCast(map.entries)) - entries_offset)); } const Entry = extern struct { From 5af740465597c3bcee3d26adbc7b1994d40df0f1 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 16 Dec 2024 05:11:10 -0500 Subject: [PATCH 3/4] lldb: add pretty printer for `InternPool.Local.List` --- tools/lldb_pretty_printers.py | 37 +++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tools/lldb_pretty_printers.py b/tools/lldb_pretty_printers.py index dd4fe77add..6e1c6201be 100644 --- a/tools/lldb_pretty_printers.py +++ b/tools/lldb_pretty_printers.py @@ -7,10 +7,28 @@ import lldb import re +# Helpers + page_size = 1 << 12 def log2_int(i): return i.bit_length() - 1 +def create_struct(name, struct_type, **inits): + struct_bytes = bytearray(struct_type.size) + struct_data = lldb.SBData() + for field in struct_type.fields: + field_size = field.type.size + field_bytes = inits[field.name].data.uint8[:field_size] + match struct_data.byte_order: + case lldb.eByteOrderLittle: + field_start = field.byte_offset + struct_bytes[field_start:field_start + len(field_bytes)] = field_bytes + case lldb.eByteOrderBig: + field_end = field.byte_offset + field_size + struct_bytes[field_end - len(field_bytes):field_end] = field_bytes + struct_data.SetData(lldb.SBError(), struct_bytes, struct_data.byte_order, struct_data.GetAddressByteSize()) + return next(iter(inits.values())).CreateValueFromData(name, struct_data, struct_type) + # Define Zig Language zig_keywords = { @@ -678,6 +696,22 @@ value_tag_handlers = { 'lazy_size': lambda payload: '@sizeOf(%s)' % type_Type_SummaryProvider(payload), } +# Define Zig Stage2 Compiler (compiled with the self-hosted backend) + +class root_InternPool_Local_List_SynthProvider: + def __init__(self, value, _=None): self.value = value + def update(self): + capacity = self.value.EvaluateExpression('@as(*@This().Header, @alignCast(@ptrCast(@this().bytes - @This().bytes_offset))).capacity') + self.view = create_struct('view', self.value.EvaluateExpression('@This().View').GetValueAsType(), bytes=self.value.GetChildMemberWithName('bytes'), len=capacity, capacity=capacity).GetNonSyntheticValue() + def has_children(self): return True + def num_children(self): return 1 + def get_child_index(self, name): + try: return ('view',).index(name) + except: pass + def get_child_at_index(self, index): + try: return (self.view,)[index] + except: pass + # Initialize def add(debugger, *, category, regex=False, type, identifier=None, synth=False, inline_children=False, expand=False, summary=False): @@ -729,3 +763,6 @@ def __lldb_init_module(debugger, _=None): add(debugger, category='zig.stage2', type='InternPool.Key.Ptr.Addr', identifier='zig_TaggedUnion', synth=True) add(debugger, category='zig.stage2', type='InternPool.Key.Aggregate.Storage', identifier='zig_TaggedUnion', synth=True) add(debugger, category='zig.stage2', type='arch.x86_64.CodeGen.MCValue', identifier='zig_TaggedUnion', synth=True, inline_children=True, summary=True) + + # Initialize Zig Stage2 Compiler (compiled with the self-hosted backend) + add(debugger, category='zig', regex=True, type='^root\\.InternPool\\.Local\\.List\\(.*\\)$', identifier='root_InternPool_Local_List', synth=True, expand=True, summary='capacity=${var%#}') From 8c0628d0e290c7c1168c52c3adb408b48b48f8d0 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 16 Dec 2024 15:11:15 -0500 Subject: [PATCH 4/4] Dwarf: include comptime-only values in debug info --- lib/std/dwarf/AT.zig | 2 + lib/std/dwarf/TAG.zig | 1 + src/InternPool.zig | 75 ++- src/Type.zig | 1 + src/link/Dwarf.zig | 1127 +++++++++++++++++++++++++++++++++-------- 5 files changed, 1002 insertions(+), 204 deletions(-) diff --git a/lib/std/dwarf/AT.zig b/lib/std/dwarf/AT.zig index 3477fd4079..a2a2011a8b 100644 --- a/lib/std/dwarf/AT.zig +++ b/lib/std/dwarf/AT.zig @@ -224,6 +224,8 @@ pub const ZIG_parent = 0x2ccd; pub const ZIG_padding = 0x2cce; pub const ZIG_relative_decl = 0x2cd0; pub const ZIG_decl_line_relative = 0x2cd1; +pub const ZIG_comptime_value = 0x2cd2; +pub const ZIG_comptime_default_value = 0x2cd3; pub const ZIG_sentinel = 0x2ce2; // UPC extension. diff --git a/lib/std/dwarf/TAG.zig b/lib/std/dwarf/TAG.zig index 3e16925ee0..6838c1dd02 100644 --- a/lib/std/dwarf/TAG.zig +++ b/lib/std/dwarf/TAG.zig @@ -119,3 +119,4 @@ pub const PGI_interface_block = 0xA020; // ZIG extensions. pub const ZIG_padding = 0xfdb1; +pub const ZIG_comptime_value = 0xfdb2; diff --git a/src/InternPool.zig b/src/InternPool.zig index 1dbfbb24e1..9dbcc3cef5 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -4704,9 +4704,45 @@ pub const Index = enum(u32) { } comptime { - if (builtin.zig_backend == .stage2_llvm and !builtin.strip_debug_info) { - _ = &dbHelper; - } + if (!builtin.strip_debug_info) switch (builtin.zig_backend) { + .stage2_llvm => _ = &dbHelper, + .stage2_x86_64 => { + for (@typeInfo(Tag).@"enum".fields) |tag| { + if (!@hasField(@TypeOf(Tag.encodings), tag.name)) { + if (false) @compileLog("missing: " ++ @typeName(Tag) ++ ".encodings." ++ tag.name); + continue; + } + const encoding = @field(Tag.encodings, tag.name); + for (@typeInfo(encoding.trailing).@"struct".fields) |field| { + struct { + fn checkConfig(name: []const u8) void { + if (!@hasField(@TypeOf(encoding.config), name)) @compileError("missing field: " ++ @typeName(Tag) ++ ".encodings." ++ tag.name ++ ".config.@\"" ++ name ++ "\""); + const FieldType = @TypeOf(@field(encoding.config, name)); + if (@typeInfo(FieldType) != .enum_literal) @compileError("expected enum literal: " ++ @typeName(Tag) ++ ".encodings." ++ tag.name ++ ".config.@\"" ++ name ++ "\": " ++ @typeName(FieldType)); + } + fn checkField(name: []const u8, Type: type) void { + switch (@typeInfo(Type)) { + .int => {}, + .@"enum" => {}, + .@"struct" => |info| assert(info.layout == .@"packed"), + .optional => |info| { + checkConfig(name ++ ".?"); + checkField(name ++ ".?", info.child); + }, + .pointer => |info| { + assert(info.size == .Slice); + checkConfig(name ++ ".len"); + checkField(name ++ "[0]", info.child); + }, + else => @compileError("unsupported type: " ++ @typeName(Tag) ++ ".encodings." ++ tag.name ++ "." ++ name ++ ": " ++ @typeName(Type)), + } + } + }.checkField("trailing." ++ field.name, field.type); + } + } + }, + else => {}, + }; } }; @@ -5302,6 +5338,39 @@ pub const Tag = enum(u8) { }; } + const encodings = .{ + .type_struct = .{ + .payload = TypeStruct, + .trailing = struct { + captures_len: ?u32, + captures: ?[]CaptureValue, + type_hash: ?u64, + field_types: []Index, + field_inits: ?[]Index, + field_aligns: ?[]Alignment, + field_is_comptime_bits: ?[]u32, + field_index: ?[]LoadedStructType.RuntimeOrder, + field_offset: []u32, + }, + .config = .{ + .@"trailing.captures_len.?" = .@"payload.flags.any_captures", + .@"trailing.captures.?" = .@"payload.flags.any_captures", + .@"trailing.captures.?.len" = .@"trailing.captures_len", + .@"trailing.type_hash.?" = .@"payload.flags.is_reified", + .@"trailing.field_types.len" = .@"payload.fields_len", + .@"trailing.field_inits.?" = .@"payload.flags.any_default_inits", + .@"trailing.field_inits.?.len" = .@"payload.fields_len", + .@"trailing.field_aligns.?" = .@"payload.flags.any_aligned_fields", + .@"trailing.field_aligns.?.len" = .@"payload.fields_len", + .@"trailing.field_is_comptime_bits.?" = .@"payload.flags.any_comptime_fields", + .@"trailing.field_is_comptime_bits.?.len" = .@"(payload.fields_len + 31) / 32", + .@"trailing.field_index.?" = .@"!payload.flags.is_extern", + .@"trailing.field_index.?.len" = .@"!payload.flags.is_extern", + .@"trailing.field_offset.len" = .@"payload.fields_len", + }, + }, + }; + pub const Variable = struct { ty: Index, /// May be `none`. diff --git a/src/Type.zig b/src/Type.zig index dc229fef61..e3056fdd21 100644 --- a/src/Type.zig +++ b/src/Type.zig @@ -4126,6 +4126,7 @@ pub const @"anyframe": Type = .{ .ip_index = .anyframe_type }; pub const @"null": Type = .{ .ip_index = .null_type }; pub const @"undefined": Type = .{ .ip_index = .undefined_type }; pub const @"noreturn": Type = .{ .ip_index = .noreturn_type }; +pub const enum_literal: Type = .{ .ip_index = .enum_literal_type }; pub const @"c_char": Type = .{ .ip_index = .c_char_type }; pub const @"c_short": Type = .{ .ip_index = .c_short_type }; diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 6bf311fe7f..4f336083ec 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -6,6 +6,7 @@ address_size: AddressSize, mods: std.AutoArrayHashMapUnmanaged(*Module, ModInfo), types: std.AutoArrayHashMapUnmanaged(InternPool.Index, Entry.Index), +values: std.AutoArrayHashMapUnmanaged(InternPool.Index, Entry.Index), navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Entry.Index), debug_abbrev: DebugAbbrev, @@ -1055,6 +1056,11 @@ pub const Loc = union(enum) { form_tls_address: *const Loc, implicit_value: []const u8, stack_value: *const Loc, + implicit_pointer: struct { + unit: Unit.Index, + entry: Entry.Index, + offset: i65, + }, wasm_ext: union(enum) { local: u32, global: u32, @@ -1193,6 +1199,11 @@ pub const Loc = union(enum) { try value.write(adapter); try writer.writeByte(DW.OP.stack_value); }, + .implicit_pointer => |implicit_pointer| { + try writer.writeByte(DW.OP.implicit_pointer); + try adapter.infoEntry(implicit_pointer.unit, implicit_pointer.entry); + try sleb128(writer, implicit_pointer.offset); + }, .wasm_ext => |wasm_ext| { try writer.writeByte(DW.OP.WASM_location); switch (wasm_ext) { @@ -1386,7 +1397,7 @@ pub const WipNav = struct { debug_info: std.ArrayListUnmanaged(u8), debug_line: std.ArrayListUnmanaged(u8), debug_loclists: std.ArrayListUnmanaged(u8), - pending_types: std.ArrayListUnmanaged(InternPool.Index), + pending_lazy: std.ArrayListUnmanaged(InternPool.Index), pub fn deinit(wip_nav: *WipNav) void { const gpa = wip_nav.dwarf.gpa; @@ -1395,7 +1406,7 @@ pub const WipNav = struct { wip_nav.debug_info.deinit(gpa); wip_nav.debug_line.deinit(gpa); wip_nav.debug_loclists.deinit(gpa); - wip_nav.pending_types.deinit(gpa); + wip_nav.pending_lazy.deinit(gpa); } pub fn genDebugFrame(wip_nav: *WipNav, loc: u32, cfa: Cfa) UpdateError!void { @@ -1420,7 +1431,7 @@ pub const WipNav = struct { }); try wip_nav.strp(name); try wip_nav.refType(ty); - try wip_nav.exprloc(loc); + try wip_nav.infoExprloc(loc); wip_nav.any_children = true; } @@ -1627,33 +1638,39 @@ pub const WipNav = struct { try uleb128(wip_nav.debug_info.writer(wip_nav.dwarf.gpa), try wip_nav.dwarf.refAbbrevCode(abbrev_code)); } - fn infoSectionOffset(wip_nav: *WipNav, sec: Section.Index, unit: Unit.Index, entry: Entry.Index, off: u32) UpdateError!void { + fn sectionOffset(wip_nav: *WipNav, comptime sec: Section.Index, target_sec: Section.Index, target_unit: Unit.Index, target_entry: Entry.Index, target_off: u32) UpdateError!void { const dwarf = wip_nav.dwarf; const gpa = dwarf.gpa; - const entry_ptr = dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry); - if (sec != .debug_info) { + const entry_ptr = @field(dwarf, @tagName(sec)).section.getUnit(wip_nav.unit).getEntry(wip_nav.entry); + const bytes = &@field(wip_nav, @tagName(sec)); + const source_off: u32 = @intCast(bytes.items.len); + if (target_sec != sec) { try entry_ptr.cross_section_relocs.append(gpa, .{ - .source_off = @intCast(wip_nav.debug_info.items.len), - .target_sec = sec, - .target_unit = unit, - .target_entry = entry.toOptional(), - .target_off = off, + .source_off = source_off, + .target_sec = target_sec, + .target_unit = target_unit, + .target_entry = target_entry.toOptional(), + .target_off = target_off, }); - } else if (unit != wip_nav.unit) { + } else if (target_unit != wip_nav.unit) { try entry_ptr.cross_unit_relocs.append(gpa, .{ - .source_off = @intCast(wip_nav.debug_info.items.len), - .target_unit = unit, - .target_entry = entry.toOptional(), - .target_off = off, + .source_off = source_off, + .target_unit = target_unit, + .target_entry = target_entry.toOptional(), + .target_off = target_off, }); } else { try entry_ptr.cross_entry_relocs.append(gpa, .{ - .source_off = @intCast(wip_nav.debug_info.items.len), - .target_entry = entry.toOptional(), - .target_off = off, + .source_off = source_off, + .target_entry = target_entry.toOptional(), + .target_off = target_off, }); } - try wip_nav.debug_info.appendNTimes(gpa, 0, dwarf.sectionOffsetBytes()); + try bytes.appendNTimes(gpa, 0, dwarf.sectionOffsetBytes()); + } + + fn infoSectionOffset(wip_nav: *WipNav, target_sec: Section.Index, target_unit: Unit.Index, target_entry: Entry.Index, target_off: u32) UpdateError!void { + try wip_nav.sectionOffset(.debug_info, target_sec, target_unit, target_entry, target_off); } fn strp(wip_nav: *WipNav, str: []const u8) UpdateError!void { @@ -1663,7 +1680,15 @@ pub const WipNav = struct { const ExprLocCounter = struct { const Stream = std.io.CountingWriter(std.io.NullWriter); stream: Stream, + section_offset_bytes: u32, address_size: AddressSize, + fn init(dwarf: *Dwarf) ExprLocCounter { + return .{ + .stream = std.io.countingWriter(std.io.null_writer), + .section_offset_bytes = dwarf.sectionOffsetBytes(), + .address_size = dwarf.address_size, + }; + } fn writer(counter: *ExprLocCounter) Stream.Writer { return counter.stream.writer(); } @@ -1673,13 +1698,13 @@ pub const WipNav = struct { fn addrSym(counter: *ExprLocCounter, _: u32) error{}!void { counter.stream.bytes_written += @intFromEnum(counter.address_size); } + fn infoEntry(counter: *ExprLocCounter, _: Unit.Index, _: Entry.Index) error{}!void { + counter.stream.bytes_written += counter.section_offset_bytes; + } }; - fn exprloc(wip_nav: *WipNav, loc: Loc) UpdateError!void { - var counter: ExprLocCounter = .{ - .stream = std.io.countingWriter(std.io.null_writer), - .address_size = wip_nav.dwarf.address_size, - }; + fn infoExprloc(wip_nav: *WipNav, loc: Loc) UpdateError!void { + var counter: ExprLocCounter = .init(wip_nav.dwarf); try loc.write(&counter); const adapter: struct { @@ -1693,6 +1718,9 @@ pub const WipNav = struct { fn addrSym(ctx: @This(), sym_index: u32) UpdateError!void { try ctx.wip_nav.infoAddrSym(sym_index, 0); } + fn infoEntry(ctx: @This(), unit: Unit.Index, entry: Entry.Index) UpdateError!void { + try ctx.wip_nav.infoSectionOffset(.debug_info, unit, entry, 0); + } } = .{ .wip_nav = wip_nav }; try uleb128(adapter.writer(), counter.stream.bytes_written); try loc.write(adapter); @@ -1708,10 +1736,7 @@ pub const WipNav = struct { } fn frameExprloc(wip_nav: *WipNav, loc: Loc) UpdateError!void { - var counter: ExprLocCounter = .{ - .stream = std.io.countingWriter(std.io.null_writer), - .address_size = wip_nav.dwarf.address_size, - }; + var counter: ExprLocCounter = .init(wip_nav.dwarf); try loc.write(&counter); const adapter: struct { @@ -1725,6 +1750,9 @@ pub const WipNav = struct { fn addrSym(ctx: @This(), sym_index: u32) UpdateError!void { try ctx.wip_nav.frameAddrSym(sym_index, 0); } + fn infoEntry(ctx: @This(), unit: Unit.Index, entry: Entry.Index) UpdateError!void { + try ctx.wip_nav.sectionOffset(.debug_frame, .debug_info, unit, entry, 0); + } } = .{ .wip_nav = wip_nav }; try uleb128(adapter.writer(), counter.stream.bytes_written); try loc.write(adapter); @@ -1739,6 +1767,22 @@ pub const WipNav = struct { try wip_nav.debug_frame.appendNTimes(wip_nav.dwarf.gpa, 0, @intFromEnum(wip_nav.dwarf.address_size)); } + fn getNavEntry(wip_nav: *WipNav, nav_index: InternPool.Nav.Index) UpdateError!struct { Unit.Index, Entry.Index } { + const zcu = wip_nav.pt.zcu; + const ip = &zcu.intern_pool; + const unit = try wip_nav.dwarf.getUnit(zcu.fileByIndex(ip.getNav(nav_index).srcInst(ip).resolveFile(ip)).mod); + const gop = try wip_nav.dwarf.navs.getOrPut(wip_nav.dwarf.gpa, nav_index); + if (gop.found_existing) return .{ unit, gop.value_ptr.* }; + const entry = try wip_nav.dwarf.addCommonEntry(unit); + gop.value_ptr.* = entry; + return .{ unit, entry }; + } + + fn refNav(wip_nav: *WipNav, nav_index: InternPool.Nav.Index) UpdateError!void { + const unit, const entry = try wip_nav.getNavEntry(nav_index); + try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0); + } + fn getTypeEntry(wip_nav: *WipNav, ty: Type) UpdateError!struct { Unit.Index, Entry.Index } { const zcu = wip_nav.pt.zcu; const ip = &zcu.intern_pool; @@ -1751,7 +1795,7 @@ pub const WipNav = struct { if (gop.found_existing) return .{ unit, gop.value_ptr.* }; const entry = try wip_nav.dwarf.addCommonEntry(unit); gop.value_ptr.* = entry; - if (maybe_inst_index == null) try wip_nav.pending_types.append(wip_nav.dwarf.gpa, ty.toIntern()); + if (maybe_inst_index == null) try wip_nav.pending_lazy.append(wip_nav.dwarf.gpa, ty.toIntern()); return .{ unit, entry }; } @@ -1760,13 +1804,25 @@ pub const WipNav = struct { try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0); } - fn refNav(wip_nav: *WipNav, nav_index: InternPool.Nav.Index) UpdateError!void { + fn getValueEntry(wip_nav: *WipNav, value: Value) UpdateError!struct { Unit.Index, Entry.Index } { const zcu = wip_nav.pt.zcu; const ip = &zcu.intern_pool; - const unit = try wip_nav.dwarf.getUnit(zcu.fileByIndex(ip.getNav(nav_index).srcInst(ip).resolveFile(ip)).mod); - const nav_gop = try wip_nav.dwarf.navs.getOrPut(wip_nav.dwarf.gpa, nav_index); - if (!nav_gop.found_existing) nav_gop.value_ptr.* = try wip_nav.dwarf.addCommonEntry(unit); - try wip_nav.infoSectionOffset(.debug_info, unit, nav_gop.value_ptr.*, 0); + const ty = value.typeOf(zcu); + if (std.debug.runtime_safety) assert(ty.comptimeOnly(zcu) and try ty.onePossibleValue(wip_nav.pt) == null); + if (ty.toIntern() == .type_type) return wip_nav.getTypeEntry(value.toType()); + if (ip.isFunctionType(ty.toIntern())) return wip_nav.getNavEntry(zcu.funcInfo(value.toIntern()).owner_nav); + const gop = try wip_nav.dwarf.values.getOrPut(wip_nav.dwarf.gpa, value.toIntern()); + const unit: Unit.Index = .main; + if (gop.found_existing) return .{ unit, gop.value_ptr.* }; + const entry = try wip_nav.dwarf.addCommonEntry(unit); + gop.value_ptr.* = entry; + try wip_nav.pending_lazy.append(wip_nav.dwarf.gpa, value.toIntern()); + return .{ unit, entry }; + } + + fn refValue(wip_nav: *WipNav, value: Value) UpdateError!void { + const unit, const entry = try wip_nav.getValueEntry(value); + try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0); } fn refForward(wip_nav: *WipNav) std.mem.Allocator.Error!u32 { @@ -1809,73 +1865,81 @@ pub const WipNav = struct { } } + const AbbrevCodeForForm = struct { + sdata: AbbrevCode, + udata: AbbrevCode, + block: AbbrevCode, + }; + + fn bigIntConstValue( + wip_nav: *WipNav, + abbrev_code: AbbrevCodeForForm, + ty: Type, + big_int: std.math.big.int.Const, + ) UpdateError!void { + const zcu = wip_nav.pt.zcu; + const diw = wip_nav.debug_info.writer(wip_nav.dwarf.gpa); + const signedness = switch (ty.toIntern()) { + .comptime_int_type, .comptime_float_type => .signed, + else => ty.intInfo(zcu).signedness, + }; + const bits = @max(1, big_int.bitCountTwosCompForSignedness(signedness)); + if (bits <= 64) { + try wip_nav.abbrevCode(switch (signedness) { + .signed => abbrev_code.sdata, + .unsigned => abbrev_code.udata, + }); + try wip_nav.debug_info.ensureUnusedCapacity(wip_nav.dwarf.gpa, std.math.divCeil(usize, bits, 7) catch unreachable); + var bit: usize = 0; + var carry: u1 = 1; + while (bit < bits) { + const limb_bits = @typeInfo(std.math.big.Limb).int.bits; + const limb_index = bit / limb_bits; + const limb_shift: std.math.Log2Int(std.math.big.Limb) = @intCast(bit % limb_bits); + const low_abs_part: u7 = @truncate(big_int.limbs[limb_index] >> limb_shift); + const abs_part = if (limb_shift > limb_bits - 7 and limb_index + 1 < big_int.limbs.len) abs_part: { + const high_abs_part: u7 = @truncate(big_int.limbs[limb_index + 1] << -%limb_shift); + break :abs_part high_abs_part | low_abs_part; + } else low_abs_part; + const twos_comp_part = if (big_int.positive) abs_part else twos_comp_part: { + const twos_comp_part, carry = @addWithOverflow(~abs_part, carry); + break :twos_comp_part twos_comp_part; + }; + bit += 7; + wip_nav.debug_info.appendAssumeCapacity(@as(u8, if (bit < bits) 0x80 else 0x00) | twos_comp_part); + } + } else { + try wip_nav.abbrevCode(abbrev_code.block); + const bytes = @max(ty.abiSize(zcu), std.math.divCeil(usize, bits, 8) catch unreachable); + try uleb128(diw, bytes); + big_int.writeTwosComplement( + try wip_nav.debug_info.addManyAsSlice(wip_nav.dwarf.gpa, @intCast(bytes)), + wip_nav.dwarf.endian, + ); + } + } + fn enumConstValue( wip_nav: *WipNav, loaded_enum: InternPool.LoadedEnumType, - abbrev_code: struct { - sdata: AbbrevCode, - udata: AbbrevCode, - block: AbbrevCode, - }, + abbrev_code: AbbrevCodeForForm, field_index: usize, ) UpdateError!void { const zcu = wip_nav.pt.zcu; const ip = &zcu.intern_pool; - const diw = wip_nav.debug_info.writer(wip_nav.dwarf.gpa); - const signedness = switch (loaded_enum.tag_ty) { - .comptime_int_type => .signed, - else => Type.fromInterned(loaded_enum.tag_ty).intInfo(zcu).signedness, - }; - if (loaded_enum.values.len > 0) { - var big_int_space: Value.BigIntSpace = undefined; - const big_int = ip.indexToKey(loaded_enum.values.get(ip)[field_index]).int.storage.toBigInt(&big_int_space); - const bits = @max(1, big_int.bitCountTwosCompForSignedness(signedness)); - if (bits <= 64) { - try wip_nav.abbrevCode(switch (signedness) { - .signed => abbrev_code.sdata, - .unsigned => abbrev_code.udata, - }); - try wip_nav.debug_info.ensureUnusedCapacity(wip_nav.dwarf.gpa, std.math.divCeil(usize, bits, 7) catch unreachable); - var bit: usize = 0; - var carry: u1 = 1; - while (bit < bits) : (bit += 7) { - const limb_bits = @typeInfo(std.math.big.Limb).int.bits; - const limb_index = bit / limb_bits; - const limb_shift: std.math.Log2Int(std.math.big.Limb) = @intCast(bit % limb_bits); - const low_abs_part: u7 = @truncate(big_int.limbs[limb_index] >> limb_shift); - const abs_part = if (limb_shift > limb_bits - 7 and limb_index + 1 < big_int.limbs.len) abs_part: { - const high_abs_part: u7 = @truncate(big_int.limbs[limb_index + 1] << -%limb_shift); - break :abs_part high_abs_part | low_abs_part; - } else low_abs_part; - const twos_comp_part = if (big_int.positive) abs_part else twos_comp_part: { - const twos_comp_part, carry = @addWithOverflow(~abs_part, carry); - break :twos_comp_part twos_comp_part; - }; - wip_nav.debug_info.appendAssumeCapacity(@as(u8, if (bit + 7 < bits) 0x80 else 0x00) | twos_comp_part); - } - } else { - try wip_nav.abbrevCode(abbrev_code.block); - const bytes = Type.fromInterned(loaded_enum.tag_ty).abiSize(zcu); - try uleb128(diw, bytes); - big_int.writeTwosComplement( - try wip_nav.debug_info.addManyAsSlice(wip_nav.dwarf.gpa, @intCast(bytes)), - wip_nav.dwarf.endian, - ); - } - } else switch (signedness) { - .signed => { - try wip_nav.abbrevCode(abbrev_code.sdata); - try sleb128(diw, field_index); - }, - .unsigned => { - try wip_nav.abbrevCode(abbrev_code.udata); - try uleb128(diw, field_index); - }, - } + var big_int_space: Value.BigIntSpace = undefined; + try wip_nav.bigIntConstValue(abbrev_code, .fromInterned(loaded_enum.tag_ty), if (loaded_enum.values.len > 0) + Value.fromInterned(loaded_enum.values.get(ip)[field_index]).toBigInt(&big_int_space, zcu) + else + std.math.big.int.Mutable.init(&big_int_space.limbs, field_index).toConst()); } - fn flush(wip_nav: *WipNav, src_loc: Zcu.LazySrcLoc) UpdateError!void { - while (wip_nav.pending_types.popOrNull()) |ty| try wip_nav.dwarf.updateType(wip_nav.pt, src_loc, ty, &wip_nav.pending_types); + fn updateLazy(wip_nav: *WipNav, src_loc: Zcu.LazySrcLoc) UpdateError!void { + const ip = &wip_nav.pt.zcu.intern_pool; + while (wip_nav.pending_lazy.popOrNull()) |val| switch (ip.typeOf(val)) { + .type_type => try wip_nav.dwarf.updateLazyType(wip_nav.pt, src_loc, val, &wip_nav.pending_lazy), + else => try wip_nav.dwarf.updateLazyValue(wip_nav.pt, src_loc, val, &wip_nav.pending_lazy), + }; } }; @@ -1904,6 +1968,7 @@ pub fn init(lf: *link.File, format: DW.Format) Dwarf { .mods = .{}, .types = .{}, + .values = .{}, .navs = .{}, .debug_abbrev = .{ .section = Section.init }, @@ -2075,6 +2140,7 @@ pub fn deinit(dwarf: *Dwarf) void { for (dwarf.mods.values()) |*mod_info| mod_info.deinit(gpa); dwarf.mods.deinit(gpa); dwarf.types.deinit(gpa); + dwarf.values.deinit(gpa); dwarf.navs.deinit(gpa); dwarf.debug_abbrev.section.deinit(gpa); dwarf.debug_aranges.section.deinit(gpa); @@ -2186,7 +2252,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In .debug_info = .{}, .debug_line = .{}, .debug_loclists = .{}, - .pending_types = .{}, + .pending_lazy = .{}, }; errdefer wip_nav.deinit(); @@ -2223,7 +2289,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In const diw = wip_nav.debug_info.writer(dwarf.gpa); try wip_nav.abbrevCode(.decl_var); - try wip_nav.refType(Type.fromInterned(parent_type)); + try wip_nav.refType(.fromInterned(parent_type)); assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); try uleb128(diw, loc.column + 1); @@ -2232,7 +2298,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In try wip_nav.strp(nav.fqn.toSlice(ip)); const nav_ty = nav_val.typeOf(zcu); const nav_ty_reloc_index = try wip_nav.refForward(); - try wip_nav.exprloc(.{ .addr = .{ .sym = sym_index } }); + try wip_nav.infoExprloc(.{ .addr = .{ .sym = sym_index } }); try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse nav_ty.abiAlignment(zcu).toByteUnits().?); try diw.writeByte(@intFromBool(false)); @@ -2272,17 +2338,17 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In const diw = wip_nav.debug_info.writer(dwarf.gpa); try wip_nav.abbrevCode(.decl_var); - try wip_nav.refType(Type.fromInterned(parent_type)); + try wip_nav.refType(.fromInterned(parent_type)); assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); try uleb128(diw, loc.column + 1); try diw.writeByte(accessibility); try wip_nav.strp(nav.name.toSlice(ip)); try wip_nav.strp(nav.fqn.toSlice(ip)); - const ty = Type.fromInterned(variable.ty); + const ty: Type = .fromInterned(variable.ty); try wip_nav.refType(ty); const addr: Loc = .{ .addr = .{ .sym = sym_index } }; - try wip_nav.exprloc(if (variable.is_threadlocal) .{ .form_tls_address = &addr } else addr); + try wip_nav.infoExprloc(if (variable.is_threadlocal) .{ .form_tls_address = &addr } else addr); try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse ty.abiAlignment(zcu).toByteUnits().?); try diw.writeByte(@intFromBool(false)); @@ -2364,14 +2430,14 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In const diw = wip_nav.debug_info.writer(dwarf.gpa); try wip_nav.abbrevCode(.decl_func); - try wip_nav.refType(Type.fromInterned(parent_type)); + try wip_nav.refType(.fromInterned(parent_type)); assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); try uleb128(diw, loc.column + 1); try diw.writeByte(accessibility); try wip_nav.strp(nav.name.toSlice(ip)); try wip_nav.strp(nav.fqn.toSlice(ip)); - try wip_nav.refType(Type.fromInterned(func_type.return_type)); + try wip_nav.refType(.fromInterned(func_type.return_type)); try wip_nav.infoAddrSym(sym_index, 0); wip_nav.func_high_pc = @intCast(wip_nav.debug_info.items.len); try diw.writeInt(u32, 0, dwarf.endian); @@ -2525,7 +2591,7 @@ pub fn finishWipNav( } try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.items); - try wip_nav.flush(zcu.navSrcLoc(nav_index)); + try wip_nav.updateLazy(zcu.navSrcLoc(nav_index)); } pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateError!void { @@ -2586,7 +2652,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool .debug_info = .{}, .debug_line = .{}, .debug_loclists = .{}, - .pending_types = .{}, + .pending_lazy = .{}, }; defer wip_nav.deinit(); @@ -2648,7 +2714,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool switch (loaded_struct.layout) { .auto, .@"extern" => { try wip_nav.abbrevCode(if (loaded_struct.field_types.len == 0) .decl_namespace_struct else .decl_struct); - try wip_nav.refType(Type.fromInterned(parent_type)); + try wip_nav.refType(.fromInterned(parent_type)); assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); try uleb128(diw, loc.column + 1); @@ -2661,43 +2727,65 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool const is_comptime = loaded_struct.fieldIsComptime(ip, field_index); const field_init = loaded_struct.fieldInit(ip, field_index); assert(!(is_comptime and field_init == .none)); + const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); + const has_runtime_bits, const has_comptime_state = switch (field_init) { + .none => .{ false, false }, + else => .{ + field_type.hasRuntimeBits(zcu), + field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null, + }, + }; try wip_nav.abbrevCode(if (is_comptime) - .struct_field_comptime + if (has_runtime_bits and has_comptime_state) + .struct_field_comptime_runtime_bits_comptime_state + else if (has_comptime_state) + .struct_field_comptime_comptime_state + else if (has_runtime_bits) + .struct_field_comptime_runtime_bits + else + .struct_field_comptime else if (field_init != .none) - .struct_field_default + if (has_runtime_bits and has_comptime_state) + .struct_field_default_runtime_bits_comptime_state + else if (has_comptime_state) + .struct_field_default_comptime_state + else if (has_runtime_bits) + .struct_field_default_runtime_bits + else + .struct_field_default else .struct_field); if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else { - const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index}); - defer dwarf.gpa.free(field_name); + var field_name_buf: [std.fmt.count("{d}", .{std.math.maxInt(u32)})]u8 = undefined; + const field_name = std.fmt.bufPrint(&field_name_buf, "{d}", .{field_index}) catch unreachable; try wip_nav.strp(field_name); } - const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]); try wip_nav.refType(field_type); if (!is_comptime) { try uleb128(diw, loaded_struct.offsets.get(ip)[field_index]); try uleb128(diw, loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse field_type.abiAlignment(zcu).toByteUnits().?); } - if (field_init != .none) try wip_nav.blockValue(nav_src_loc, Value.fromInterned(field_init)); + if (has_runtime_bits) try wip_nav.blockValue(nav_src_loc, .fromInterned(field_init)); + if (has_comptime_state) try wip_nav.refValue(.fromInterned(field_init)); } try uleb128(diw, @intFromEnum(AbbrevCode.null)); } }, .@"packed" => { try wip_nav.abbrevCode(.decl_packed_struct); - try wip_nav.refType(Type.fromInterned(parent_type)); + try wip_nav.refType(.fromInterned(parent_type)); assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); try uleb128(diw, loc.column + 1); try diw.writeByte(accessibility); try wip_nav.strp(nav.name.toSlice(ip)); - try wip_nav.refType(Type.fromInterned(loaded_struct.backingIntTypeUnordered(ip))); + try wip_nav.refType(.fromInterned(loaded_struct.backingIntTypeUnordered(ip))); var field_bit_offset: u16 = 0; for (0..loaded_struct.field_types.len) |field_index| { try wip_nav.abbrevCode(.packed_struct_field); try wip_nav.strp(loaded_struct.fieldName(ip, field_index).unwrap().?.toSlice(ip)); - const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]); + const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); try wip_nav.refType(field_type); try uleb128(diw, field_bit_offset); field_bit_offset += @intCast(field_type.bitSize(zcu)); @@ -2745,13 +2833,13 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool wip_nav.entry = nav_gop.value_ptr.*; const diw = wip_nav.debug_info.writer(dwarf.gpa); try wip_nav.abbrevCode(if (loaded_enum.names.len > 0) .decl_enum else .decl_empty_enum); - try wip_nav.refType(Type.fromInterned(parent_type)); + try wip_nav.refType(.fromInterned(parent_type)); assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); try uleb128(diw, loc.column + 1); try diw.writeByte(accessibility); try wip_nav.strp(nav.name.toSlice(ip)); - try wip_nav.refType(Type.fromInterned(loaded_enum.tag_ty)); + try wip_nav.refType(.fromInterned(loaded_enum.tag_ty)); for (0..loaded_enum.names.len) |field_index| { try wip_nav.enumConstValue(loaded_enum, .{ .sdata = .signed_enum_field, @@ -2800,7 +2888,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool wip_nav.entry = nav_gop.value_ptr.*; const diw = wip_nav.debug_info.writer(dwarf.gpa); try wip_nav.abbrevCode(.decl_union); - try wip_nav.refType(Type.fromInterned(parent_type)); + try wip_nav.refType(.fromInterned(parent_type)); assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); try uleb128(diw, loc.column + 1); @@ -2821,7 +2909,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool { try wip_nav.abbrevCode(.generated_field); try wip_nav.strp("tag"); - try wip_nav.refType(Type.fromInterned(loaded_union.enum_tag_ty)); + try wip_nav.refType(.fromInterned(loaded_union.enum_tag_ty)); try uleb128(diw, union_layout.tagOffset()); for (0..loaded_union.field_types.len) |field_index| { @@ -2833,7 +2921,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool { try wip_nav.abbrevCode(.struct_field); try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip)); - const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]); + const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]); try wip_nav.refType(field_type); try uleb128(diw, union_layout.payloadOffset()); try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse @@ -2846,7 +2934,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool } else for (0..loaded_union.field_types.len) |field_index| { try wip_nav.abbrevCode(.untagged_union_field); try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip)); - const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]); + const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]); try wip_nav.refType(field_type); try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse field_type.abiAlignment(zcu).toByteUnits().?); @@ -2891,7 +2979,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool wip_nav.entry = nav_gop.value_ptr.*; const diw = wip_nav.debug_info.writer(dwarf.gpa); try wip_nav.abbrevCode(.decl_namespace_struct); - try wip_nav.refType(Type.fromInterned(parent_type)); + try wip_nav.refType(.fromInterned(parent_type)); assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); try uleb128(diw, loc.column + 1); @@ -2947,17 +3035,17 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool .decl_func_generic else .decl_empty_func_generic); - try wip_nav.refType(Type.fromInterned(parent_type)); + try wip_nav.refType(.fromInterned(parent_type)); assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); try uleb128(diw, loc.column + 1); try diw.writeByte(accessibility); try wip_nav.strp(nav.name.toSlice(ip)); - try wip_nav.refType(Type.fromInterned(func_type.return_type)); + try wip_nav.refType(.fromInterned(func_type.return_type)); if (func_type.param_types.len > 0 or func_type.is_var_args) { for (0..func_type.param_types.len) |param_index| { try wip_nav.abbrevCode(.func_type_param); - try wip_nav.refType(Type.fromInterned(func_type.param_types.get(ip)[param_index])); + try wip_nav.refType(.fromInterned(func_type.param_types.get(ip)[param_index])); } if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args); try uleb128(diw, @intFromEnum(AbbrevCode.null)); @@ -2979,7 +3067,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool .decl_alias => { const diw = wip_nav.debug_info.writer(dwarf.gpa); try wip_nav.abbrevCode(.decl_alias); - try wip_nav.refType(Type.fromInterned(parent_type)); + try wip_nav.refType(.fromInterned(parent_type)); assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); try uleb128(diw, loc.column + 1); @@ -2990,7 +3078,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool .decl_var => { const diw = wip_nav.debug_info.writer(dwarf.gpa); try wip_nav.abbrevCode(.decl_var); - try wip_nav.refType(Type.fromInterned(parent_type)); + try wip_nav.refType(.fromInterned(parent_type)); assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); try uleb128(diw, loc.column + 1); @@ -3006,42 +3094,52 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool }, .decl_const => { const diw = wip_nav.debug_info.writer(dwarf.gpa); - try wip_nav.abbrevCode(.decl_const); - try wip_nav.refType(Type.fromInterned(parent_type)); + const nav_ty = nav_val.typeOf(zcu); + const has_runtime_bits = nav_ty.hasRuntimeBits(zcu); + const has_comptime_state = nav_ty.comptimeOnly(zcu) and try nav_ty.onePossibleValue(pt) == null; + try wip_nav.abbrevCode(if (has_runtime_bits and has_comptime_state) + .decl_const_runtime_bits_comptime_state + else if (has_comptime_state) + .decl_const_comptime_state + else if (has_runtime_bits) + .decl_const_runtime_bits + else + .decl_const); + try wip_nav.refType(.fromInterned(parent_type)); assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); try uleb128(diw, loc.column + 1); try diw.writeByte(accessibility); try wip_nav.strp(nav.name.toSlice(ip)); try wip_nav.strp(nav.fqn.toSlice(ip)); - const nav_ty = nav_val.typeOf(zcu); const nav_ty_reloc_index = try wip_nav.refForward(); - try wip_nav.blockValue(nav_src_loc, nav_val); try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse nav_ty.abiAlignment(zcu).toByteUnits().?); try diw.writeByte(@intFromBool(false)); + if (has_runtime_bits) try wip_nav.blockValue(nav_src_loc, nav_val); + if (has_comptime_state) try wip_nav.refValue(nav_val); wip_nav.finishForward(nav_ty_reloc_index); try wip_nav.abbrevCode(.is_const); try wip_nav.refType(nav_ty); }, } try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items); - try wip_nav.flush(nav_src_loc); + try wip_nav.updateLazy(nav_src_loc); } -fn updateType( +fn updateLazyType( dwarf: *Dwarf, pt: Zcu.PerThread, src_loc: Zcu.LazySrcLoc, type_index: InternPool.Index, - pending_types: *std.ArrayListUnmanaged(InternPool.Index), + pending_lazy: *std.ArrayListUnmanaged(InternPool.Index), ) UpdateError!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; - const ty = Type.fromInterned(type_index); + const ty: Type = .fromInterned(type_index); switch (type_index) { - .generic_poison_type => log.debug("updateType({s})", .{"anytype"}), - else => log.debug("updateType({})", .{ty.fmt(pt)}), + .generic_poison_type => log.debug("updateLazyType({s})", .{"anytype"}), + else => log.debug("updateLazyType({})", .{ty.fmt(pt)}), } var wip_nav: WipNav = .{ @@ -3059,11 +3157,11 @@ fn updateType( .debug_info = .{}, .debug_line = .{}, .debug_loclists = .{}, - .pending_types = pending_types.*, + .pending_lazy = pending_lazy.*, }; defer { - pending_types.* = wip_nav.pending_types; - wip_nav.pending_types = .{}; + pending_lazy.* = wip_nav.pending_lazy; + wip_nav.pending_lazy = .{}; wip_nav.deinit(); } const diw = wip_nav.debug_info.writer(dwarf.gpa); @@ -3086,13 +3184,10 @@ fn updateType( }, .ptr_type => |ptr_type| switch (ptr_type.flags.size) { .One, .Many, .C => { - const ptr_child_type = Type.fromInterned(ptr_type.child); + const ptr_child_type: Type = .fromInterned(ptr_type.child); try wip_nav.abbrevCode(if (ptr_type.sentinel == .none) .ptr_type else .ptr_sentinel_type); try wip_nav.strp(name); - if (ptr_type.sentinel != .none) try wip_nav.blockValue( - src_loc, - Value.fromInterned(ptr_type.sentinel), - ); + if (ptr_type.sentinel != .none) try wip_nav.blockValue(src_loc, .fromInterned(ptr_type.sentinel)); try uleb128(diw, ptr_type.flags.alignment.toByteUnits() orelse ptr_child_type.abiAlignment(zcu).toByteUnits().?); try diw.writeByte(@intFromEnum(ptr_type.flags.address_space)); @@ -3128,37 +3223,34 @@ fn updateType( try uleb128(diw, 0); try wip_nav.abbrevCode(.generated_field); try wip_nav.strp("len"); - const len_field_type = Type.usize; + const len_field_type: Type = .usize; try wip_nav.refType(len_field_type); try uleb128(diw, len_field_type.abiAlignment(zcu).forward(ptr_field_type.abiSize(zcu))); try uleb128(diw, @intFromEnum(AbbrevCode.null)); }, }, .array_type => |array_type| { - const array_child_type = Type.fromInterned(array_type.child); + const array_child_type: Type = .fromInterned(array_type.child); try wip_nav.abbrevCode(if (array_type.sentinel == .none) .array_type else .array_sentinel_type); try wip_nav.strp(name); - if (array_type.sentinel != .none) try wip_nav.blockValue( - src_loc, - Value.fromInterned(array_type.sentinel), - ); + if (array_type.sentinel != .none) try wip_nav.blockValue(src_loc, .fromInterned(array_type.sentinel)); try wip_nav.refType(array_child_type); try wip_nav.abbrevCode(.array_index); - try wip_nav.refType(Type.usize); + try wip_nav.refType(.usize); try uleb128(diw, array_type.len); try uleb128(diw, @intFromEnum(AbbrevCode.null)); }, .vector_type => |vector_type| { try wip_nav.abbrevCode(.vector_type); try wip_nav.strp(name); - try wip_nav.refType(Type.fromInterned(vector_type.child)); + try wip_nav.refType(.fromInterned(vector_type.child)); try wip_nav.abbrevCode(.array_index); - try wip_nav.refType(Type.usize); + try wip_nav.refType(.usize); try uleb128(diw, vector_type.len); try uleb128(diw, @intFromEnum(AbbrevCode.null)); }, .opt_type => |opt_child_type_index| { - const opt_child_type = Type.fromInterned(opt_child_type_index); + const opt_child_type: Type = .fromInterned(opt_child_type_index); try wip_nav.abbrevCode(.union_type); try wip_nav.strp(name); try uleb128(diw, ty.abiSize(zcu)); @@ -3166,7 +3258,7 @@ fn updateType( if (opt_child_type.isNoReturn(zcu)) { try wip_nav.abbrevCode(.generated_field); try wip_nav.strp("null"); - try wip_nav.refType(Type.null); + try wip_nav.refType(.null); try uleb128(diw, 0); } else { try wip_nav.abbrevCode(.tagged_union); @@ -3189,21 +3281,21 @@ fn updateType( }; switch (repr) { .unpacked => { - try wip_nav.refType(Type.bool); + try wip_nav.refType(.bool); try uleb128(diw, if (opt_child_type.hasRuntimeBits(zcu)) opt_child_type.abiSize(zcu) else 0); }, .error_set => { - try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{ + try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{ .signedness = .unsigned, .bits = zcu.errorSetBits(), } }))); try uleb128(diw, 0); }, .pointer => { - try wip_nav.refType(Type.usize); + try wip_nav.refType(.usize); try uleb128(diw, 0); }, } @@ -3213,7 +3305,7 @@ fn updateType( { try wip_nav.abbrevCode(.generated_field); try wip_nav.strp("null"); - try wip_nav.refType(Type.null); + try wip_nav.refType(.null); try uleb128(diw, 0); } try uleb128(diw, @intFromEnum(AbbrevCode.null)); @@ -3233,8 +3325,8 @@ fn updateType( }, .anyframe_type => unreachable, .error_union_type => |error_union_type| { - const error_union_error_set_type = Type.fromInterned(error_union_type.error_set_type); - const error_union_payload_type = Type.fromInterned(error_union_type.payload_type); + const error_union_error_set_type: Type = .fromInterned(error_union_type.error_set_type); + const error_union_payload_type: Type = .fromInterned(error_union_type.payload_type); const error_union_error_set_offset, const error_union_payload_offset = switch (error_union_type.payload_type) { .generic_poison_type => .{ 0, 0 }, else => .{ @@ -3265,7 +3357,7 @@ fn updateType( { try wip_nav.abbrevCode(.generated_field); try wip_nav.strp("is_error"); - try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{ + try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{ .signedness = .unsigned, .bits = zcu.errorSetBits(), } }))); @@ -3363,24 +3455,39 @@ fn updateType( var field_byte_offset: u64 = 0; for (0..tuple_type.types.len) |field_index| { const comptime_value = tuple_type.values.get(ip)[field_index]; - try wip_nav.abbrevCode(if (comptime_value != .none) .struct_field_comptime else .struct_field); + const field_type: Type = .fromInterned(tuple_type.types.get(ip)[field_index]); + const has_runtime_bits, const has_comptime_state = switch (comptime_value) { + .none => .{ false, false }, + else => .{ + field_type.hasRuntimeBits(zcu), + field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null, + }, + }; + try wip_nav.abbrevCode(if (has_runtime_bits and has_comptime_state) + .struct_field_comptime_runtime_bits_comptime_state + else if (has_comptime_state) + .struct_field_comptime_comptime_state + else if (has_runtime_bits) + .struct_field_comptime_runtime_bits + else if (comptime_value != .none) + .struct_field_comptime + else + .struct_field); { - var name_buf: [32]u8 = undefined; - const field_name = std.fmt.bufPrint(&name_buf, "{d}", .{field_index}) catch unreachable; + var field_name_buf: [std.fmt.count("{d}", .{std.math.maxInt(u32)})]u8 = undefined; + const field_name = std.fmt.bufPrint(&field_name_buf, "{d}", .{field_index}) catch unreachable; try wip_nav.strp(field_name); } - const field_type = Type.fromInterned(tuple_type.types.get(ip)[field_index]); try wip_nav.refType(field_type); - if (comptime_value != .none) try wip_nav.blockValue( - src_loc, - Value.fromInterned(comptime_value), - ) else { + if (comptime_value == .none) { const field_align = field_type.abiAlignment(zcu); field_byte_offset = field_align.forward(field_byte_offset); try uleb128(diw, field_byte_offset); try uleb128(diw, field_type.abiAlignment(zcu).toByteUnits().?); field_byte_offset += field_type.abiSize(zcu); } + if (has_runtime_bits) try wip_nav.blockValue(src_loc, .fromInterned(comptime_value)); + if (has_comptime_state) try wip_nav.refValue(.fromInterned(comptime_value)); } try uleb128(diw, @intFromEnum(AbbrevCode.null)); }, @@ -3388,7 +3495,7 @@ fn updateType( const loaded_enum = ip.loadEnumType(type_index); try wip_nav.abbrevCode(if (loaded_enum.names.len > 0) .enum_type else .empty_enum_type); try wip_nav.strp(name); - try wip_nav.refType(Type.fromInterned(loaded_enum.tag_ty)); + try wip_nav.refType(.fromInterned(loaded_enum.tag_ty)); for (0..loaded_enum.names.len) |field_index| { try wip_nav.enumConstValue(loaded_enum, .{ .sdata = .signed_enum_field, @@ -3469,10 +3576,10 @@ fn updateType( }; }; try diw.writeByte(@intFromEnum(cc)); - try wip_nav.refType(Type.fromInterned(func_type.return_type)); + try wip_nav.refType(.fromInterned(func_type.return_type)); for (0..func_type.param_types.len) |param_index| { try wip_nav.abbrevCode(.func_type_param); - try wip_nav.refType(Type.fromInterned(func_type.param_types.get(ip)[param_index])); + try wip_nav.refType(.fromInterned(func_type.param_types.get(ip)[param_index])); } if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args); if (!is_nullary) try uleb128(diw, @intFromEnum(AbbrevCode.null)); @@ -3480,7 +3587,7 @@ fn updateType( .error_set_type => |error_set_type| { try wip_nav.abbrevCode(if (error_set_type.names.len > 0) .enum_type else .empty_enum_type); try wip_nav.strp(name); - try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{ + try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{ .signedness = .unsigned, .bits = zcu.errorSetBits(), } }))); @@ -3495,7 +3602,7 @@ fn updateType( .inferred_error_set_type => |func| { try wip_nav.abbrevCode(.inferred_error_set_type); try wip_nav.strp(name); - try wip_nav.refType(Type.fromInterned(switch (ip.funcIesResolvedUnordered(func)) { + try wip_nav.refType(.fromInterned(switch (ip.funcIesResolvedUnordered(func)) { .none => .anyerror_type, else => |ies| ies, })); @@ -3526,10 +3633,378 @@ fn updateType( try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items); } +fn updateLazyValue( + dwarf: *Dwarf, + pt: Zcu.PerThread, + src_loc: Zcu.LazySrcLoc, + value_index: InternPool.Index, + pending_lazy: *std.ArrayListUnmanaged(InternPool.Index), +) UpdateError!void { + const zcu = pt.zcu; + const ip = &zcu.intern_pool; + log.debug("updateLazyValue({})", .{Value.fromInterned(value_index).fmtValue(pt)}); + var wip_nav: WipNav = .{ + .dwarf = dwarf, + .pt = pt, + .unit = .main, + .entry = dwarf.values.get(value_index).?, + .any_children = false, + .func = .none, + .func_sym_index = undefined, + .func_high_pc = undefined, + .blocks = undefined, + .cfi = undefined, + .debug_frame = .{}, + .debug_info = .{}, + .debug_line = .{}, + .debug_loclists = .{}, + .pending_lazy = pending_lazy.*, + }; + defer { + pending_lazy.* = wip_nav.pending_lazy; + wip_nav.pending_lazy = .{}; + wip_nav.deinit(); + } + const diw = wip_nav.debug_info.writer(dwarf.gpa); + var big_int_space: Value.BigIntSpace = undefined; + switch (ip.indexToKey(value_index)) { + .int_type, + .ptr_type, + .array_type, + .vector_type, + .opt_type, + .anyframe_type, + .error_union_type, + .simple_type, + .struct_type, + .tuple_type, + .union_type, + .opaque_type, + .enum_type, + .func_type, + .error_set_type, + .inferred_error_set_type, + => unreachable, // already handled + .undef => |ty| { + try wip_nav.abbrevCode(.aggregate_comptime_value); + try wip_nav.refType(.fromInterned(ty)); + try uleb128(diw, @intFromEnum(AbbrevCode.null)); + }, + .simple_value => unreachable, // opv state + .variable, .@"extern" => unreachable, // not a value + .func => unreachable, // already handled + .int => |int| { + try wip_nav.bigIntConstValue(.{ + .sdata = .sdata_comptime_value, + .udata = .udata_comptime_value, + .block = .block_comptime_value, + }, .fromInterned(int.ty), Value.fromInterned(value_index).toBigInt(&big_int_space, zcu)); + try wip_nav.refType(.fromInterned(int.ty)); + }, + .err => |err| { + try wip_nav.abbrevCode(.udata_comptime_value); + try wip_nav.refType(.fromInterned(err.ty)); + try uleb128(diw, try pt.getErrorValue(err.name)); + }, + .error_union => |error_union| { + try wip_nav.abbrevCode(.aggregate_comptime_value); + const err_abi_size = std.math.divCeil(u17, zcu.errorSetBits(), 8) catch unreachable; + const err_value = switch (error_union.val) { + .err_name => |err_name| try pt.getErrorValue(err_name), + .payload => 0, + }; + { + try wip_nav.abbrevCode(.comptime_value_field_runtime_bits); + try wip_nav.strp("is_error"); + try uleb128(diw, err_abi_size); + dwarf.writeInt(try wip_nav.debug_info.addManyAsSlice(dwarf.gpa, err_abi_size), err_value); + } + payload_field: switch (error_union.val) { + .err_name => {}, + .payload => |payload_val| { + const payload_type: Type = .fromInterned(ip.typeOf(payload_val)); + const has_runtime_bits = payload_type.hasRuntimeBits(zcu); + const has_comptime_state = payload_type.comptimeOnly(zcu) and try payload_type.onePossibleValue(pt) == null; + try wip_nav.abbrevCode(if (has_comptime_state) + .comptime_value_field_comptime_state + else if (has_runtime_bits) + .comptime_value_field_runtime_bits + else + break :payload_field); + try wip_nav.strp("value"); + if (has_comptime_state) + try wip_nav.refValue(.fromInterned(payload_val)) + else + try wip_nav.blockValue(src_loc, .fromInterned(payload_val)); + }, + } + { + try wip_nav.abbrevCode(.comptime_value_field_runtime_bits); + try wip_nav.strp("error"); + try uleb128(diw, err_abi_size); + dwarf.writeInt(try wip_nav.debug_info.addManyAsSlice(dwarf.gpa, err_abi_size), err_value); + } + switch (error_union.val) { + .err_name => {}, + .payload => |payload| { + _ = payload; + try wip_nav.abbrevCode(.aggregate_comptime_value); + }, + } + try wip_nav.refType(.fromInterned(error_union.ty)); + try uleb128(diw, @intFromEnum(AbbrevCode.null)); + }, + .enum_literal => |enum_literal| { + try wip_nav.abbrevCode(.string_comptime_value); + try wip_nav.strp(enum_literal.toSlice(ip)); + try wip_nav.refType(.enum_literal); + }, + .enum_tag => |enum_tag| { + const int = ip.indexToKey(enum_tag.int).int; + try wip_nav.bigIntConstValue(.{ + .sdata = .sdata_comptime_value, + .udata = .udata_comptime_value, + .block = .block_comptime_value, + }, .fromInterned(int.ty), Value.fromInterned(value_index).toBigInt(&big_int_space, zcu)); + try wip_nav.refType(.fromInterned(enum_tag.ty)); + }, + .empty_enum_value => unreachable, + .float => |float| { + switch (float.storage) { + .f16 => |f16_val| { + try wip_nav.abbrevCode(.data2_comptime_value); + try diw.writeInt(u16, @bitCast(f16_val), dwarf.endian); + }, + .f32 => |f32_val| { + try wip_nav.abbrevCode(.data4_comptime_value); + try diw.writeInt(u32, @bitCast(f32_val), dwarf.endian); + }, + .f64 => |f64_val| { + try wip_nav.abbrevCode(.data8_comptime_value); + try diw.writeInt(u64, @bitCast(f64_val), dwarf.endian); + }, + .f80 => |f80_val| { + try wip_nav.abbrevCode(.block_comptime_value); + try uleb128(diw, @divExact(80, 8)); + try diw.writeInt(u80, @bitCast(f80_val), dwarf.endian); + }, + .f128 => |f128_val| { + try wip_nav.abbrevCode(.data16_comptime_value); + try diw.writeInt(u128, @bitCast(f128_val), dwarf.endian); + }, + } + try wip_nav.refType(.fromInterned(float.ty)); + }, + .ptr => |ptr| { + location: { + var base_addr = ptr.base_addr; + var byte_offset = ptr.byte_offset; + const base_unit, const base_entry = while (true) { + const base_ptr = base_ptr: switch (base_addr) { + .nav => |nav_index| break try wip_nav.getNavEntry(nav_index), + .comptime_alloc, .comptime_field => unreachable, + .uav => |uav| { + const uav_ty: Type = .fromInterned(ip.typeOf(uav.val)); + if (try uav_ty.onePossibleValue(pt)) |_| { + try wip_nav.abbrevCode(.udata_comptime_value); + try uleb128(diw, ip.indexToKey(uav.orig_ty).ptr_type.flags.alignment.toByteUnits() orelse + uav_ty.abiAlignment(zcu).toByteUnits().?); + break :location; + } else break try wip_nav.getValueEntry(.fromInterned(uav.val)); + }, + .int => { + try wip_nav.abbrevCode(.udata_comptime_value); + try uleb128(diw, byte_offset); + break :location; + }, + .eu_payload => |eu_ptr| { + const base_ptr = ip.indexToKey(eu_ptr).ptr; + byte_offset += codegen.errUnionPayloadOffset(.fromInterned(ip.indexToKey( + ip.indexToKey(base_ptr.ty).ptr_type.child, + ).error_union_type.payload_type), zcu); + break :base_ptr base_ptr; + }, + .opt_payload => |opt_ptr| ip.indexToKey(opt_ptr).ptr, + .field => unreachable, + .arr_elem => unreachable, + }; + base_addr = base_ptr.base_addr; + byte_offset += base_ptr.byte_offset; + }; + try wip_nav.abbrevCode(.location_comptime_value); + try wip_nav.infoExprloc(.{ .implicit_pointer = .{ + .unit = base_unit, + .entry = base_entry, + .offset = byte_offset, + } }); + } + try wip_nav.refType(.fromInterned(ptr.ty)); + }, + .slice => |slice| { + try wip_nav.abbrevCode(.aggregate_comptime_value); + try wip_nav.refType(.fromInterned(slice.ty)); + { + try wip_nav.abbrevCode(.comptime_value_field_comptime_state); + try wip_nav.strp("ptr"); + try wip_nav.refValue(.fromInterned(slice.ptr)); + } + { + try wip_nav.abbrevCode(.comptime_value_field_runtime_bits); + try wip_nav.strp("len"); + try wip_nav.blockValue(src_loc, .fromInterned(slice.len)); + } + try uleb128(diw, @intFromEnum(AbbrevCode.null)); + }, + .opt => |opt| { + const child_type: Type = .fromInterned(ip.indexToKey(opt.ty).opt_type); + try wip_nav.abbrevCode(.aggregate_comptime_value); + try wip_nav.refType(.fromInterned(opt.ty)); + { + try wip_nav.abbrevCode(.comptime_value_field_runtime_bits); + try wip_nav.strp("has_value"); + if (Type.fromInterned(opt.ty).optionalReprIsPayload(zcu)) { + try wip_nav.blockValue(src_loc, .fromInterned(opt.val)); + } else { + try uleb128(diw, 1); + try diw.writeByte(@intFromBool(opt.val != .none)); + } + } + if (opt.val != .none) child_field: { + const has_runtime_bits = child_type.hasRuntimeBits(zcu); + const has_comptime_state = child_type.comptimeOnly(zcu) and try child_type.onePossibleValue(pt) == null; + try wip_nav.abbrevCode(if (has_comptime_state) + .comptime_value_field_comptime_state + else if (has_runtime_bits) + .comptime_value_field_runtime_bits + else + break :child_field); + try wip_nav.strp("?"); + if (has_comptime_state) + try wip_nav.refValue(.fromInterned(opt.val)) + else + try wip_nav.blockValue(src_loc, .fromInterned(opt.val)); + } + try uleb128(diw, @intFromEnum(AbbrevCode.null)); + }, + .aggregate => |aggregate| { + try wip_nav.abbrevCode(.aggregate_comptime_value); + try wip_nav.refType(.fromInterned(aggregate.ty)); + switch (ip.indexToKey(aggregate.ty)) { + .struct_type => { + const loaded_struct_type = ip.loadStructType(aggregate.ty); + assert(loaded_struct_type.layout == .auto); + for (0..loaded_struct_type.field_types.len) |field_index| { + if (loaded_struct_type.fieldIsComptime(ip, field_index)) continue; + const field_type: Type = .fromInterned(loaded_struct_type.field_types.get(ip)[field_index]); + const has_runtime_bits = field_type.hasRuntimeBits(zcu); + const has_comptime_state = field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null; + try wip_nav.abbrevCode(if (has_comptime_state) + .comptime_value_field_comptime_state + else if (has_runtime_bits) + .comptime_value_field_runtime_bits + else + continue); + if (loaded_struct_type.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else { + var field_name_buf: [std.fmt.count("{d}", .{std.math.maxInt(u32)})]u8 = undefined; + const field_name = std.fmt.bufPrint(&field_name_buf, "{d}", .{field_index}) catch unreachable; + try wip_nav.strp(field_name); + } + const field_value: Value = .fromInterned(switch (aggregate.storage) { + .bytes => unreachable, + .elems => |elems| elems[field_index], + .repeated_elem => |repeated_elem| repeated_elem, + }); + if (has_comptime_state) + try wip_nav.refValue(field_value) + else + try wip_nav.blockValue(src_loc, field_value); + } + }, + .tuple_type => |tuple_type| for (0..tuple_type.types.len) |field_index| { + if (tuple_type.values.get(ip)[field_index] != .none) continue; + const field_type: Type = .fromInterned(tuple_type.types.get(ip)[field_index]); + const has_runtime_bits = field_type.hasRuntimeBits(zcu); + const has_comptime_state = field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null; + try wip_nav.abbrevCode(if (has_comptime_state) + .comptime_value_field_comptime_state + else if (has_runtime_bits) + .comptime_value_field_runtime_bits + else + continue); + { + var field_name_buf: [std.fmt.count("{d}", .{std.math.maxInt(u32)})]u8 = undefined; + const field_name = std.fmt.bufPrint(&field_name_buf, "{d}", .{field_index}) catch unreachable; + try wip_nav.strp(field_name); + } + const field_value: Value = .fromInterned(switch (aggregate.storage) { + .bytes => unreachable, + .elems => |elems| elems[field_index], + .repeated_elem => |repeated_elem| repeated_elem, + }); + if (has_comptime_state) + try wip_nav.refValue(field_value) + else + try wip_nav.blockValue(src_loc, field_value); + }, + inline .array_type, .vector_type => |sequence_type| { + const child_type: Type = .fromInterned(sequence_type.child); + const has_runtime_bits = child_type.hasRuntimeBits(zcu); + const has_comptime_state = child_type.comptimeOnly(zcu) and try child_type.onePossibleValue(pt) == null; + for (switch (aggregate.storage) { + .bytes => unreachable, + .elems => |elems| elems, + .repeated_elem => |*repeated_elem| repeated_elem[0..1], + }) |elem| { + try wip_nav.abbrevCode(if (has_comptime_state) + .comptime_value_elem_comptime_state + else if (has_runtime_bits) + .comptime_value_elem_runtime_bits + else + break); + if (has_comptime_state) + try wip_nav.refValue(.fromInterned(elem)) + else + try wip_nav.blockValue(src_loc, .fromInterned(elem)); + } + }, + else => unreachable, + } + try uleb128(diw, @intFromEnum(AbbrevCode.null)); + }, + .un => |un| { + try wip_nav.abbrevCode(.aggregate_comptime_value); + try wip_nav.refType(.fromInterned(un.ty)); + field: { + const loaded_union_type = ip.loadUnionType(un.ty); + assert(loaded_union_type.flagsUnordered(ip).layout == .auto); + const field_index = zcu.unionTagFieldIndex(loaded_union_type, Value.fromInterned(un.tag)).?; + const field_ty: Type = .fromInterned(loaded_union_type.field_types.get(ip)[field_index]); + const field_name = loaded_union_type.loadTagType(ip).names.get(ip)[field_index]; + const has_runtime_bits = field_ty.hasRuntimeBits(zcu); + const has_comptime_state = field_ty.comptimeOnly(zcu) and try field_ty.onePossibleValue(pt) == null; + try wip_nav.abbrevCode(if (has_comptime_state) + .comptime_value_field_comptime_state + else if (has_runtime_bits) + .comptime_value_field_runtime_bits + else + break :field); + try wip_nav.strp(field_name.toSlice(ip)); + if (has_comptime_state) + try wip_nav.refValue(.fromInterned(un.val)) + else + try wip_nav.blockValue(src_loc, .fromInterned(un.val)); + } + try uleb128(diw, @intFromEnum(AbbrevCode.null)); + }, + .memoized_call => unreachable, // not a value + } + try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items); +} + pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternPool.Index) UpdateError!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; - const ty = Type.fromInterned(type_index); + const ty: Type = .fromInterned(type_index); const ty_src_loc = ty.srcLoc(zcu); log.debug("updateContainerType({}({d}))", .{ ty.fmt(pt), @intFromEnum(type_index) }); @@ -3554,7 +4029,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP .debug_info = .{}, .debug_line = .{}, .debug_loclists = .{}, - .pending_types = .{}, + .pending_lazy = .{}, }; defer wip_nav.deinit(); @@ -3572,31 +4047,53 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP const is_comptime = loaded_struct.fieldIsComptime(ip, field_index); const field_init = loaded_struct.fieldInit(ip, field_index); assert(!(is_comptime and field_init == .none)); + const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); + const has_runtime_bits, const has_comptime_state = switch (field_init) { + .none => .{ false, false }, + else => .{ + field_type.hasRuntimeBits(zcu), + field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null, + }, + }; try wip_nav.abbrevCode(if (is_comptime) - .struct_field_comptime + if (has_runtime_bits and has_comptime_state) + .struct_field_comptime_runtime_bits_comptime_state + else if (has_comptime_state) + .struct_field_comptime_comptime_state + else if (has_runtime_bits) + .struct_field_comptime_runtime_bits + else + .struct_field_comptime else if (field_init != .none) - .struct_field_default + if (has_runtime_bits and has_comptime_state) + .struct_field_default_runtime_bits_comptime_state + else if (has_comptime_state) + .struct_field_default_comptime_state + else if (has_runtime_bits) + .struct_field_default_runtime_bits + else + .struct_field_default else .struct_field); if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else { - const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index}); - defer dwarf.gpa.free(field_name); + var field_name_buf: [std.fmt.count("{d}", .{std.math.maxInt(u32)})]u8 = undefined; + const field_name = std.fmt.bufPrint(&field_name_buf, "{d}", .{field_index}) catch unreachable; try wip_nav.strp(field_name); } - const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]); try wip_nav.refType(field_type); if (!is_comptime) { try uleb128(diw, loaded_struct.offsets.get(ip)[field_index]); try uleb128(diw, loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse field_type.abiAlignment(zcu).toByteUnits().?); } - if (field_init != .none) try wip_nav.blockValue(ty_src_loc, Value.fromInterned(field_init)); + if (has_runtime_bits) try wip_nav.blockValue(ty_src_loc, .fromInterned(field_init)); + if (has_comptime_state) try wip_nav.refValue(.fromInterned(field_init)); } try uleb128(diw, @intFromEnum(AbbrevCode.null)); } try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items); - try wip_nav.flush(ty_src_loc); + try wip_nav.updateLazy(ty_src_loc); } else { { // Note that changes to ZIR instruction tracking only need to update this code @@ -3637,7 +4134,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP .debug_info = .{}, .debug_line = .{}, .debug_loclists = .{}, - .pending_types = .{}, + .pending_lazy = .{}, }; defer wip_nav.deinit(); const diw = wip_nav.debug_info.writer(dwarf.gpa); @@ -3658,25 +4155,47 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP const is_comptime = loaded_struct.fieldIsComptime(ip, field_index); const field_init = loaded_struct.fieldInit(ip, field_index); assert(!(is_comptime and field_init == .none)); + const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); + const has_runtime_bits, const has_comptime_state = switch (field_init) { + .none => .{ false, false }, + else => .{ + field_type.hasRuntimeBits(zcu), + field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null, + }, + }; try wip_nav.abbrevCode(if (is_comptime) - .struct_field_comptime + if (has_runtime_bits and has_comptime_state) + .struct_field_comptime_runtime_bits_comptime_state + else if (has_comptime_state) + .struct_field_comptime_comptime_state + else if (has_runtime_bits) + .struct_field_comptime_runtime_bits + else + .struct_field_comptime else if (field_init != .none) - .struct_field_default + if (has_runtime_bits and has_comptime_state) + .struct_field_default_runtime_bits_comptime_state + else if (has_comptime_state) + .struct_field_default_comptime_state + else if (has_runtime_bits) + .struct_field_default_runtime_bits + else + .struct_field_default else .struct_field); if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else { - const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index}); - defer dwarf.gpa.free(field_name); + var field_name_buf: [std.fmt.count("{d}", .{std.math.maxInt(u32)})]u8 = undefined; + const field_name = std.fmt.bufPrint(&field_name_buf, "{d}", .{field_index}) catch unreachable; try wip_nav.strp(field_name); } - const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]); try wip_nav.refType(field_type); if (!is_comptime) { try uleb128(diw, loaded_struct.offsets.get(ip)[field_index]); try uleb128(diw, loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse field_type.abiAlignment(zcu).toByteUnits().?); } - if (field_init != .none) try wip_nav.blockValue(ty_src_loc, Value.fromInterned(field_init)); + if (has_runtime_bits) try wip_nav.blockValue(ty_src_loc, .fromInterned(field_init)); + if (has_comptime_state) try wip_nav.refValue(.fromInterned(field_init)); } try uleb128(diw, @intFromEnum(AbbrevCode.null)); } @@ -3684,12 +4203,12 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP .@"packed" => { try wip_nav.abbrevCode(if (loaded_struct.field_types.len > 0) .packed_struct_type else .empty_packed_struct_type); try wip_nav.strp(name); - try wip_nav.refType(Type.fromInterned(loaded_struct.backingIntTypeUnordered(ip))); + try wip_nav.refType(.fromInterned(loaded_struct.backingIntTypeUnordered(ip))); var field_bit_offset: u16 = 0; for (0..loaded_struct.field_types.len) |field_index| { try wip_nav.abbrevCode(.packed_struct_field); try wip_nav.strp(loaded_struct.fieldName(ip, field_index).unwrap().?.toSlice(ip)); - const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]); + const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); try wip_nav.refType(field_type); try uleb128(diw, field_bit_offset); field_bit_offset += @intCast(field_type.bitSize(zcu)); @@ -3702,7 +4221,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP const loaded_enum = ip.loadEnumType(type_index); try wip_nav.abbrevCode(if (loaded_enum.names.len > 0) .enum_type else .empty_enum_type); try wip_nav.strp(name); - try wip_nav.refType(Type.fromInterned(loaded_enum.tag_ty)); + try wip_nav.refType(.fromInterned(loaded_enum.tag_ty)); for (0..loaded_enum.names.len) |field_index| { try wip_nav.enumConstValue(loaded_enum, .{ .sdata = .signed_enum_field, @@ -3732,7 +4251,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP { try wip_nav.abbrevCode(.generated_field); try wip_nav.strp("tag"); - try wip_nav.refType(Type.fromInterned(loaded_union.enum_tag_ty)); + try wip_nav.refType(.fromInterned(loaded_union.enum_tag_ty)); try uleb128(diw, union_layout.tagOffset()); for (0..loaded_union.field_types.len) |field_index| { @@ -3744,7 +4263,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP { try wip_nav.abbrevCode(.struct_field); try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip)); - const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]); + const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]); try wip_nav.refType(field_type); try uleb128(diw, union_layout.payloadOffset()); try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse @@ -3757,7 +4276,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP } else for (0..loaded_union.field_types.len) |field_index| { try wip_nav.abbrevCode(.untagged_union_field); try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip)); - const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]); + const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]); try wip_nav.refType(field_type); try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse field_type.abiAlignment(zcu).toByteUnits().?); @@ -3773,7 +4292,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP } try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items); try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.items); - try wip_nav.flush(ty_src_loc); + try wip_nav.updateLazy(ty_src_loc); } } @@ -3840,14 +4359,14 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { .debug_info = .{}, .debug_line = .{}, .debug_loclists = .{}, - .pending_types = .{}, + .pending_lazy = .{}, }; defer wip_nav.deinit(); const diw = wip_nav.debug_info.writer(dwarf.gpa); const global_error_set_names = ip.global_error_set.getNamesFromMainThread(); try wip_nav.abbrevCode(if (global_error_set_names.len > 0) .enum_type else .empty_enum_type); try wip_nav.strp("anyerror"); - try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{ + try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{ .signedness = .unsigned, .bits = zcu.errorSetBits(), } }))); @@ -3858,7 +4377,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { } if (global_error_set_names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null)); try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items); - try wip_nav.flush(.unneeded); + try wip_nav.updateLazy(.unneeded); } { @@ -4244,6 +4763,9 @@ const AbbrevCode = enum { decl_union, decl_var, decl_const, + decl_const_runtime_bits, + decl_const_comptime_state, + decl_const_runtime_bits_comptime_state, decl_func, decl_empty_func, decl_func_generic, @@ -4259,7 +4781,13 @@ const AbbrevCode = enum { generated_field, struct_field, struct_field_default, + struct_field_default_runtime_bits, + struct_field_default_comptime_state, + struct_field_default_runtime_bits_comptime_state, struct_field_comptime, + struct_field_comptime_runtime_bits, + struct_field_comptime_comptime_state, + struct_field_comptime_runtime_bits_comptime_state, packed_struct_field, untagged_union_field, tagged_union, @@ -4296,6 +4824,20 @@ const AbbrevCode = enum { inlined_func, local_arg, local_var, + data2_comptime_value, + data4_comptime_value, + data8_comptime_value, + data16_comptime_value, + sdata_comptime_value, + udata_comptime_value, + block_comptime_value, + string_comptime_value, + location_comptime_value, + aggregate_comptime_value, + comptime_value_field_runtime_bits, + comptime_value_field_comptime_state, + comptime_value_elem_runtime_bits, + comptime_value_elem_comptime_state, const decl_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.decl_empty_func_generic)); @@ -4387,11 +4929,41 @@ const AbbrevCode = enum { .attrs = decl_abbrev_common_attrs ++ .{ .{ .linkage_name, .strp }, .{ .type, .ref_addr }, - .{ .const_value, .block }, .{ .alignment, .udata }, .{ .external, .flag }, }, }, + .decl_const_runtime_bits = .{ + .tag = .constant, + .attrs = decl_abbrev_common_attrs ++ .{ + .{ .linkage_name, .strp }, + .{ .type, .ref_addr }, + .{ .alignment, .udata }, + .{ .external, .flag }, + .{ .const_value, .block }, + }, + }, + .decl_const_comptime_state = .{ + .tag = .constant, + .attrs = decl_abbrev_common_attrs ++ .{ + .{ .linkage_name, .strp }, + .{ .type, .ref_addr }, + .{ .alignment, .udata }, + .{ .external, .flag }, + .{ .ZIG_comptime_value, .ref_addr }, + }, + }, + .decl_const_runtime_bits_comptime_state = .{ + .tag = .constant, + .attrs = decl_abbrev_common_attrs ++ .{ + .{ .linkage_name, .strp }, + .{ .type, .ref_addr }, + .{ .alignment, .udata }, + .{ .external, .flag }, + .{ .const_value, .block }, + .{ .ZIG_comptime_value, .ref_addr }, + }, + }, .decl_func = .{ .tag = .subprogram, .children = true, @@ -4509,6 +5081,15 @@ const AbbrevCode = enum { }, }, .struct_field_default = .{ + .tag = .member, + .attrs = &.{ + .{ .name, .strp }, + .{ .type, .ref_addr }, + .{ .data_member_location, .udata }, + .{ .alignment, .udata }, + }, + }, + .struct_field_default_runtime_bits = .{ .tag = .member, .attrs = &.{ .{ .name, .strp }, @@ -4518,7 +5099,36 @@ const AbbrevCode = enum { .{ .default_value, .block }, }, }, + .struct_field_default_comptime_state = .{ + .tag = .member, + .attrs = &.{ + .{ .name, .strp }, + .{ .type, .ref_addr }, + .{ .data_member_location, .udata }, + .{ .alignment, .udata }, + .{ .ZIG_comptime_default_value, .ref_addr }, + }, + }, + .struct_field_default_runtime_bits_comptime_state = .{ + .tag = .member, + .attrs = &.{ + .{ .name, .strp }, + .{ .type, .ref_addr }, + .{ .data_member_location, .udata }, + .{ .alignment, .udata }, + .{ .default_value, .block }, + .{ .ZIG_comptime_default_value, .ref_addr }, + }, + }, .struct_field_comptime = .{ + .tag = .member, + .attrs = &.{ + .{ .const_expr, .flag_present }, + .{ .name, .strp }, + .{ .type, .ref_addr }, + }, + }, + .struct_field_comptime_runtime_bits = .{ .tag = .member, .attrs = &.{ .{ .const_expr, .flag_present }, @@ -4527,6 +5137,25 @@ const AbbrevCode = enum { .{ .const_value, .block }, }, }, + .struct_field_comptime_comptime_state = .{ + .tag = .member, + .attrs = &.{ + .{ .const_expr, .flag_present }, + .{ .name, .strp }, + .{ .type, .ref_addr }, + .{ .ZIG_comptime_value, .ref_addr }, + }, + }, + .struct_field_comptime_runtime_bits_comptime_state = .{ + .tag = .member, + .attrs = &.{ + .{ .const_expr, .flag_present }, + .{ .name, .strp }, + .{ .type, .ref_addr }, + .{ .const_value, .block }, + .{ .ZIG_comptime_value, .ref_addr }, + }, + }, .packed_struct_field = .{ .tag = .member, .attrs = &.{ @@ -4804,6 +5433,102 @@ const AbbrevCode = enum { .{ .location, .exprloc }, }, }, + .data2_comptime_value = .{ + .tag = .ZIG_comptime_value, + .attrs = &.{ + .{ .const_value, .data2 }, + .{ .type, .ref_addr }, + }, + }, + .data4_comptime_value = .{ + .tag = .ZIG_comptime_value, + .attrs = &.{ + .{ .const_value, .data4 }, + .{ .type, .ref_addr }, + }, + }, + .data8_comptime_value = .{ + .tag = .ZIG_comptime_value, + .attrs = &.{ + .{ .const_value, .data8 }, + .{ .type, .ref_addr }, + }, + }, + .data16_comptime_value = .{ + .tag = .ZIG_comptime_value, + .attrs = &.{ + .{ .const_value, .data16 }, + .{ .type, .ref_addr }, + }, + }, + .sdata_comptime_value = .{ + .tag = .ZIG_comptime_value, + .attrs = &.{ + .{ .const_value, .sdata }, + .{ .type, .ref_addr }, + }, + }, + .udata_comptime_value = .{ + .tag = .ZIG_comptime_value, + .attrs = &.{ + .{ .const_value, .udata }, + .{ .type, .ref_addr }, + }, + }, + .block_comptime_value = .{ + .tag = .ZIG_comptime_value, + .attrs = &.{ + .{ .const_value, .block }, + .{ .type, .ref_addr }, + }, + }, + .string_comptime_value = .{ + .tag = .ZIG_comptime_value, + .attrs = &.{ + .{ .const_value, .strp }, + .{ .type, .ref_addr }, + }, + }, + .location_comptime_value = .{ + .tag = .ZIG_comptime_value, + .attrs = &.{ + .{ .location, .exprloc }, + .{ .type, .ref_addr }, + }, + }, + .aggregate_comptime_value = .{ + .tag = .ZIG_comptime_value, + .children = true, + .attrs = &.{ + .{ .type, .ref_addr }, + }, + }, + .comptime_value_field_runtime_bits = .{ + .tag = .member, + .attrs = &.{ + .{ .name, .strp }, + .{ .const_value, .block }, + }, + }, + .comptime_value_field_comptime_state = .{ + .tag = .member, + .attrs = &.{ + .{ .name, .strp }, + .{ .ZIG_comptime_value, .ref_addr }, + }, + }, + .comptime_value_elem_runtime_bits = .{ + .tag = .member, + .attrs = &.{ + .{ .const_value, .block }, + }, + }, + .comptime_value_elem_comptime_state = .{ + .tag = .member, + .attrs = &.{ + .{ .ZIG_comptime_value, .ref_addr }, + }, + }, .null = undefined, }); };