authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-08-12 19:45:59-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-08-15 18:29:06-04:00
log375bc2d7b53868fbffc7b1b639247bd814dc3efd
treefecef43ae0e687fc8f9bddf98991c3a20f79b2ed
parent8ef82e83551cfca60698eb82dc180118e64b8fde

Dwarf: implement comptime-known extern values

Closes #24259

4 files changed, 217 insertions(+), 62 deletions(-)

src/link/Dwarf.zig+212-57
......@@ -1720,7 +1720,7 @@ pub const WipNav = struct {
17201720 std.leb.writeUnsignedFixed(
17211721 block_bytes,
17221722 wip_nav.debug_info.written()[block.abbrev_code..][0..block_bytes],
1723 try wip_nav.dwarf.refAbbrevCode(.empty_block),
1723 @intCast(try wip_nav.dwarf.refAbbrevCode(.empty_block)),
17241724 );
17251725 std.mem.writeInt(u32, wip_nav.debug_info.written()[block.high_pc..][0..4], @intCast(code_off - block.low_pc_off), wip_nav.dwarf.endian);
17261726 wip_nav.any_children = true;
......@@ -1782,7 +1782,7 @@ pub const WipNav = struct {
17821782 std.leb.writeUnsignedFixed(
17831783 inlined_func_bytes,
17841784 wip_nav.debug_info.written()[block.abbrev_code..][0..inlined_func_bytes],
1785 try wip_nav.dwarf.refAbbrevCode(.empty_inlined_func),
1785 @intCast(try wip_nav.dwarf.refAbbrevCode(.empty_inlined_func)),
17861786 );
17871787 std.mem.writeInt(u32, wip_nav.debug_info.written()[block.high_pc..][0..4], @intCast(code_off - block.low_pc_off), wip_nav.dwarf.endian);
17881788 try wip_nav.setInlineFunc(func);
......@@ -2077,7 +2077,11 @@ pub const WipNav = struct {
20772077 const ty = value.typeOf(zcu);
20782078 if (std.debug.runtime_safety) assert(ty.comptimeOnly(zcu) and try ty.onePossibleValue(wip_nav.pt) == null);
20792079 if (ty.toIntern() == .type_type) return wip_nav.getTypeEntry(value.toType());
2080 if (ip.isFunctionType(ty.toIntern()) and !value.isUndef(zcu)) return wip_nav.getNavEntry(zcu.funcInfo(value.toIntern()).owner_nav);
2080 if (ip.isFunctionType(ty.toIntern()) and !value.isUndef(zcu)) return wip_nav.getNavEntry(switch (ip.indexToKey(value.toIntern())) {
2081 else => unreachable,
2082 .func => |func| func.owner_nav,
2083 .@"extern" => |@"extern"| @"extern".owner_nav,
2084 });
20812085 const gop = try wip_nav.dwarf.values.getOrPut(wip_nav.dwarf.gpa, value.toIntern());
20822086 const unit: Unit.Index = .main;
20832087 if (gop.found_existing) return .{ unit, gop.value_ptr.* };
......@@ -2250,6 +2254,8 @@ pub const WipNav = struct {
22502254 .decl_func,
22512255 .decl_nullary_func_generic,
22522256 .decl_func_generic,
2257 .decl_extern_nullary_func,
2258 .decl_extern_func,
22532259 => false,
22542260 .generic_decl_var,
22552261 .generic_decl_const,
......@@ -2585,7 +2591,7 @@ pub fn initWipNav(
25852591 pt: Zcu.PerThread,
25862592 nav_index: InternPool.Nav.Index,
25872593 sym_index: u32,
2588) error{ OutOfMemory, CodegenFail }!?WipNav {
2594) error{ OutOfMemory, CodegenFail }!WipNav {
25892595 return initWipNavInner(dwarf, pt, nav_index, sym_index) catch |err| switch (err) {
25902596 error.OutOfMemory => error.OutOfMemory,
25912597 else => |e| pt.zcu.codegenFail(nav_index, "failed to init dwarf: {s}", .{@errorName(e)}),
......@@ -2597,7 +2603,7 @@ fn initWipNavInner(
25972603 pt: Zcu.PerThread,
25982604 nav_index: InternPool.Nav.Index,
25992605 sym_index: u32,
2600) !?WipNav {
2606) !WipNav {
26012607 const zcu = pt.zcu;
26022608 const ip = &zcu.intern_pool;
26032609
......@@ -2613,15 +2619,6 @@ fn initWipNavInner(
26132619 nav.fqn.fmt(ip),
26142620 });
26152621
2616 const nav_val = zcu.navValue(nav_index);
2617 const nav_key = ip.indexToKey(nav_val.toIntern());
2618 switch (nav_key) {
2619 // Ignore @extern
2620 .@"extern" => |@"extern"| if (decl.linkage != .@"extern" or
2621 !@"extern".name.eqlSlice(file.zir.?.nullTerminatedString(decl.name), ip)) return null,
2622 else => {},
2623 }
2624
26252622 const mod = file.mod.?;
26262623 const unit = try dwarf.getUnit(mod);
26272624 const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
......@@ -2654,44 +2651,63 @@ fn initWipNavInner(
26542651 };
26552652 errdefer wip_nav.deinit();
26562653
2657 switch (nav_key) {
2658 else => {
2659 const diw = &wip_nav.debug_info.writer;
2660 try wip_nav.declCommon(.{
2661 .decl = .decl_var,
2662 .generic_decl = .generic_decl_var,
2663 .decl_instance = .decl_instance_var,
2664 }, &nav, inst_info.file, &decl);
2665 try wip_nav.strp(nav.fqn.toSlice(ip));
2666 const ty: Type = nav_val.typeOf(zcu);
2667 const addr: Loc = .{ .addr_reloc = sym_index };
2668 const loc: Loc = if (decl.is_threadlocal) loc: {
2669 const target = zcu.comp.root_mod.resolved_target.result;
2670 break :loc switch (target.cpu.arch) {
2671 .x86_64 => .{ .form_tls_address = &addr },
2672 else => .empty,
2654 const nav_val = zcu.navValue(nav_index);
2655 nav_val: switch (ip.indexToKey(nav_val.toIntern())) {
2656 .@"extern" => |@"extern"| switch (@"extern".source) {
2657 .builtin => {
2658 const maybe_func_type = switch (ip.indexToKey(@"extern".ty)) {
2659 .func_type => |func_type| func_type,
2660 else => null,
26732661 };
2674 } else addr;
2675 switch (decl.kind) {
2676 .unnamed_test, .@"test", .decltest, .@"comptime" => unreachable,
2677 .@"const" => {
2678 const const_ty_reloc_index = try wip_nav.refForward();
2679 try wip_nav.infoExprLoc(loc);
2680 try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse
2681 ty.abiAlignment(zcu).toByteUnits().?);
2682 try diw.writeByte(@intFromBool(decl.linkage != .normal));
2683 wip_nav.finishForward(const_ty_reloc_index);
2684 try wip_nav.abbrevCode(.is_const);
2685 try wip_nav.refType(ty);
2686 },
2687 .@"var" => {
2688 try wip_nav.refType(ty);
2689 try wip_nav.infoExprLoc(loc);
2690 try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse
2691 ty.abiAlignment(zcu).toByteUnits().?);
2692 try diw.writeByte(@intFromBool(decl.linkage != .normal));
2662 const diw = &wip_nav.debug_info.writer;
2663 try wip_nav.abbrevCode(if (maybe_func_type) |func_type|
2664 if (func_type.param_types.len > 0 or func_type.is_var_args) .builtin_extern_func else .builtin_extern_nullary_func
2665 else
2666 .builtin_extern_var);
2667 try wip_nav.refType(.fromInterned(zcu.fileRootType(inst_info.file)));
2668 try wip_nav.strp(@"extern".name.toSlice(ip));
2669 try wip_nav.refType(.fromInterned(if (maybe_func_type) |func_type| func_type.return_type else @"extern".ty));
2670 if (maybe_func_type) |func_type| {
2671 try wip_nav.infoAddrSym(sym_index, 0);
2672 try diw.writeByte(@intFromBool(ip.isNoReturn(func_type.return_type)));
2673 if (func_type.param_types.len > 0 or func_type.is_var_args) {
2674 for (func_type.param_types.get(ip)) |param_type| {
2675 try wip_nav.abbrevCode(.extern_param);
2676 try wip_nav.refType(.fromInterned(param_type));
2677 }
2678 if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
2679 try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
2680 }
2681 } else try wip_nav.infoExprLoc(.{ .addr_reloc = sym_index });
2682 },
2683 .syntax => switch (ip.isFunctionType(@"extern".ty)) {
2684 false => continue :nav_val .{ .variable = undefined },
2685 true => {
2686 const func_type = ip.indexToKey(@"extern".ty).func_type;
2687 const diw = &wip_nav.debug_info.writer;
2688 try wip_nav.declCommon(if (func_type.param_types.len > 0 or func_type.is_var_args) .{
2689 .decl = .decl_extern_func,
2690 .generic_decl = .generic_decl_func,
2691 .decl_instance = .decl_instance_extern_func,
2692 } else .{
2693 .decl = .decl_extern_nullary_func,
2694 .generic_decl = .generic_decl_func,
2695 .decl_instance = .decl_instance_extern_nullary_func,
2696 }, &nav, inst_info.file, &decl);
2697 try wip_nav.strp(@"extern".name.toSlice(ip));
2698 try wip_nav.refType(.fromInterned(func_type.return_type));
2699 try wip_nav.infoAddrSym(sym_index, 0);
2700 try diw.writeByte(@intFromBool(ip.isNoReturn(func_type.return_type)));
2701 if (func_type.param_types.len > 0 or func_type.is_var_args) {
2702 for (func_type.param_types.get(ip)) |param_type| {
2703 try wip_nav.abbrevCode(.extern_param);
2704 try wip_nav.refType(.fromInterned(param_type));
2705 }
2706 if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
2707 try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
2708 }
26932709 },
2694 }
2710 },
26952711 },
26962712 .func => |func| if (func.owner_nav != nav_index) {
26972713 try wip_nav.declCommon(.{
......@@ -2752,7 +2768,10 @@ fn initWipNavInner(
27522768 .generic_decl = .generic_decl_func,
27532769 .decl_instance = .decl_instance_func,
27542770 }, &nav, inst_info.file, &decl);
2755 try wip_nav.strp(nav.fqn.toSlice(ip));
2771 try wip_nav.strp(switch (decl.linkage) {
2772 .normal => nav.fqn,
2773 .@"extern", .@"export" => nav.name,
2774 }.toSlice(ip));
27562775 try wip_nav.refType(.fromInterned(func_type.return_type));
27572776 try wip_nav.infoAddrSym(sym_index, 0);
27582777 wip_nav.func_high_pc = @intCast(diw.end);
......@@ -2763,7 +2782,7 @@ fn initWipNavInner(
27632782 else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),
27642783 }.toByteUnits().?);
27652784 try diw.writeByte(@intFromBool(decl.linkage != .normal));
2766 try diw.writeByte(@intFromBool(func_type.return_type == .noreturn_type));
2785 try diw.writeByte(@intFromBool(ip.isNoReturn(func_type.return_type)));
27672786
27682787 const dlw = &wip_nav.debug_line.writer;
27692788 try dlw.writeByte(DW.LNS.extended_op);
......@@ -2801,6 +2820,47 @@ fn initWipNavInner(
28012820 try wip_nav.advancePCAndLine(@intCast(decl.src_line + func.lbrace_line), 0);
28022821 }
28032822 },
2823 else => {
2824 const diw = &wip_nav.debug_info.writer;
2825 try wip_nav.declCommon(.{
2826 .decl = .decl_var,
2827 .generic_decl = .generic_decl_var,
2828 .decl_instance = .decl_instance_var,
2829 }, &nav, inst_info.file, &decl);
2830 try wip_nav.strp(switch (decl.linkage) {
2831 .normal => nav.fqn,
2832 .@"extern", .@"export" => nav.name,
2833 }.toSlice(ip));
2834 const ty: Type = nav_val.typeOf(zcu);
2835 const addr: Loc = .{ .addr_reloc = sym_index };
2836 const loc: Loc = if (decl.is_threadlocal) loc: {
2837 const target = zcu.comp.root_mod.resolved_target.result;
2838 break :loc switch (target.cpu.arch) {
2839 .x86_64 => .{ .form_tls_address = &addr },
2840 else => .empty,
2841 };
2842 } else addr;
2843 switch (decl.kind) {
2844 .unnamed_test, .@"test", .decltest, .@"comptime" => unreachable,
2845 .@"const" => {
2846 const const_ty_reloc_index = try wip_nav.refForward();
2847 try wip_nav.infoExprLoc(loc);
2848 try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse
2849 ty.abiAlignment(zcu).toByteUnits().?);
2850 try diw.writeByte(@intFromBool(decl.linkage != .normal));
2851 wip_nav.finishForward(const_ty_reloc_index);
2852 try wip_nav.abbrevCode(.is_const);
2853 try wip_nav.refType(ty);
2854 },
2855 .@"var" => {
2856 try wip_nav.refType(ty);
2857 try wip_nav.infoExprLoc(loc);
2858 try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse
2859 ty.abiAlignment(zcu).toByteUnits().?);
2860 try diw.writeByte(@intFromBool(decl.linkage != .normal));
2861 },
2862 }
2863 },
28042864 }
28052865 return wip_nav;
28062866}
......@@ -2891,11 +2951,11 @@ fn finishWipNavFuncWriterError(
28912951 std.leb.writeUnsignedFixed(
28922952 AbbrevCode.decl_bytes,
28932953 abbrev_code_buf,
2894 try dwarf.refAbbrevCode(switch (abbrev_code) {
2954 @intCast(try dwarf.refAbbrevCode(switch (abbrev_code) {
28952955 else => unreachable,
28962956 .decl_func => .decl_nullary_func,
28972957 .decl_instance_func => .decl_instance_nullary_func,
2898 }),
2958 })),
28992959 );
29002960 }
29012961 }
......@@ -3357,7 +3417,10 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
33573417 .generic_decl = .generic_decl_var,
33583418 .decl_instance = .decl_instance_var,
33593419 }, &nav, inst_info.file, &decl);
3360 try wip_nav.strp(nav.fqn.toSlice(ip));
3420 try wip_nav.strp(switch (decl.linkage) {
3421 .normal => nav.fqn,
3422 .@"extern", .@"export" => nav.name,
3423 }.toSlice(ip));
33613424 const nav_ty = nav_val.typeOf(zcu);
33623425 try wip_nav.refType(nav_ty);
33633426 try wip_nav.blockValue(nav_src_loc, nav_val);
......@@ -3387,7 +3450,10 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
33873450 .generic_decl = .generic_decl_const,
33883451 .decl_instance = .decl_instance_const,
33893452 }, &nav, inst_info.file, &decl);
3390 try wip_nav.strp(nav.fqn.toSlice(ip));
3453 try wip_nav.strp(switch (decl.linkage) {
3454 .normal => nav.fqn,
3455 .@"extern", .@"export" => nav.name,
3456 }.toSlice(ip));
33913457 const nav_ty_reloc_index = try wip_nav.refForward();
33923458 try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse
33933459 nav_ty.abiAlignment(zcu).toByteUnits().?);
......@@ -5109,6 +5175,8 @@ const AbbrevCode = enum {
51095175 decl_func,
51105176 decl_nullary_func_generic,
51115177 decl_func_generic,
5178 decl_extern_nullary_func,
5179 decl_extern_func,
51125180 generic_decl_var,
51135181 generic_decl_const,
51145182 generic_decl_func,
......@@ -5128,6 +5196,8 @@ const AbbrevCode = enum {
51285196 decl_instance_func,
51295197 decl_instance_nullary_func_generic,
51305198 decl_instance_func_generic,
5199 decl_instance_extern_nullary_func,
5200 decl_instance_extern_func,
51315201 // the rest are unrestricted other than empty variants must not be longer
51325202 // than the non-empty variant, and so should appear first
51335203 compile_unit,
......@@ -5179,6 +5249,9 @@ const AbbrevCode = enum {
51795249 packed_struct_type,
51805250 empty_union_type,
51815251 union_type,
5252 builtin_extern_nullary_func,
5253 builtin_extern_func,
5254 builtin_extern_var,
51825255 empty_block,
51835256 block,
51845257 empty_inlined_func,
......@@ -5193,6 +5266,7 @@ const AbbrevCode = enum {
51935266 unnamed_comptime_arg_comptime_state,
51945267 comptime_arg_runtime_bits_comptime_state,
51955268 unnamed_comptime_arg_runtime_bits_comptime_state,
5269 extern_param,
51965270 local_var,
51975271 local_const,
51985272 local_const_runtime_bits,
......@@ -5214,7 +5288,7 @@ const AbbrevCode = enum {
52145288 comptime_value_elem_runtime_bits,
52155289 comptime_value_elem_comptime_state,
52165290
5217 const decl_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.decl_instance_func_generic));
5291 const decl_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.decl_instance_extern_func));
52185292 comptime {
52195293 assert(uleb128Bytes(@intFromEnum(AbbrevCode.pad_1)) == 1);
52205294 assert(uleb128Bytes(@intFromEnum(AbbrevCode.pad_n)) == 1);
......@@ -5389,6 +5463,27 @@ const AbbrevCode = enum {
53895463 .{ .type, .ref_addr },
53905464 },
53915465 },
5466 .decl_extern_nullary_func = .{
5467 .tag = .subprogram,
5468 .attrs = decl_abbrev_common_attrs ++ .{
5469 .{ .linkage_name, .strp },
5470 .{ .type, .ref_addr },
5471 .{ .low_pc, .addr },
5472 .{ .external, .flag_present },
5473 .{ .noreturn, .flag },
5474 },
5475 },
5476 .decl_extern_func = .{
5477 .tag = .subprogram,
5478 .children = true,
5479 .attrs = decl_abbrev_common_attrs ++ .{
5480 .{ .linkage_name, .strp },
5481 .{ .type, .ref_addr },
5482 .{ .low_pc, .addr },
5483 .{ .external, .flag_present },
5484 .{ .noreturn, .flag },
5485 },
5486 },
53925487 .generic_decl_var = .{
53935488 .tag = .variable,
53945489 .attrs = generic_decl_abbrev_common_attrs,
......@@ -5537,6 +5632,27 @@ const AbbrevCode = enum {
55375632 .{ .type, .ref_addr },
55385633 },
55395634 },
5635 .decl_instance_extern_nullary_func = .{
5636 .tag = .subprogram,
5637 .attrs = decl_instance_abbrev_common_attrs ++ .{
5638 .{ .linkage_name, .strp },
5639 .{ .type, .ref_addr },
5640 .{ .low_pc, .addr },
5641 .{ .external, .flag_present },
5642 .{ .noreturn, .flag },
5643 },
5644 },
5645 .decl_instance_extern_func = .{
5646 .tag = .subprogram,
5647 .children = true,
5648 .attrs = decl_instance_abbrev_common_attrs ++ .{
5649 .{ .linkage_name, .strp },
5650 .{ .type, .ref_addr },
5651 .{ .low_pc, .addr },
5652 .{ .external, .flag_present },
5653 .{ .noreturn, .flag },
5654 },
5655 },
55405656 .compile_unit = .{
55415657 .tag = .compile_unit,
55425658 .children = true,
......@@ -5934,6 +6050,39 @@ const AbbrevCode = enum {
59346050 .{ .alignment, .udata },
59356051 },
59366052 },
6053 .builtin_extern_nullary_func = .{
6054 .tag = .subprogram,
6055 .attrs = &.{
6056 .{ .ZIG_parent, .ref_addr },
6057 .{ .linkage_name, .strp },
6058 .{ .type, .ref_addr },
6059 .{ .low_pc, .addr },
6060 .{ .external, .flag_present },
6061 .{ .noreturn, .flag },
6062 },
6063 },
6064 .builtin_extern_func = .{
6065 .tag = .subprogram,
6066 .children = true,
6067 .attrs = &.{
6068 .{ .ZIG_parent, .ref_addr },
6069 .{ .linkage_name, .strp },
6070 .{ .type, .ref_addr },
6071 .{ .low_pc, .addr },
6072 .{ .external, .flag_present },
6073 .{ .noreturn, .flag },
6074 },
6075 },
6076 .builtin_extern_var = .{
6077 .tag = .variable,
6078 .attrs = &.{
6079 .{ .ZIG_parent, .ref_addr },
6080 .{ .linkage_name, .strp },
6081 .{ .type, .ref_addr },
6082 .{ .location, .exprloc },
6083 .{ .external, .flag_present },
6084 },
6085 },
59376086 .empty_block = .{
59386087 .tag = .lexical_block,
59396088 .attrs = &.{
......@@ -6053,6 +6202,12 @@ const AbbrevCode = enum {
60536202 .{ .ZIG_comptime_value, .ref_addr },
60546203 },
60556204 },
6205 .extern_param = .{
6206 .tag = .formal_parameter,
6207 .attrs = &.{
6208 .{ .type, .ref_addr },
6209 },
6210 },
60566211 .local_var = .{
60576212 .tag = .variable,
60586213 .attrs = &.{
src/link/Elf/ZigObject.zig+2-2
......@@ -1543,8 +1543,8 @@ pub fn updateNav(
15431543 @"extern".lib_name.toSlice(ip),
15441544 );
15451545 if (@"extern".is_threadlocal and elf_file.base.comp.config.any_non_single_threaded) self.symbol(sym_index).flags.is_tls = true;
1546 if (self.dwarf) |*dwarf| dwarf: {
1547 var debug_wip_nav = try dwarf.initWipNav(pt, nav_index, sym_index) orelse break :dwarf;
1546 if (self.dwarf) |*dwarf| {
1547 var debug_wip_nav = try dwarf.initWipNav(pt, nav_index, sym_index);
15481548 defer debug_wip_nav.deinit();
15491549 dwarf.finishWipNav(pt, nav_index, &debug_wip_nav) catch |err| switch (err) {
15501550 error.OutOfMemory => return error.OutOfMemory,
src/link/MachO/ZigObject.zig+2-2
......@@ -877,8 +877,8 @@ pub fn updateNav(
877877 const lib_name = @"extern".lib_name.toSlice(ip);
878878 const sym_index = try self.getGlobalSymbol(macho_file, name, lib_name);
879879 if (@"extern".is_threadlocal and macho_file.base.comp.config.any_non_single_threaded) self.symbols.items[sym_index].flags.tlv = true;
880 if (self.dwarf) |*dwarf| dwarf: {
881 var debug_wip_nav = try dwarf.initWipNav(pt, nav_index, sym_index) orelse break :dwarf;
880 if (self.dwarf) |*dwarf| {
881 var debug_wip_nav = try dwarf.initWipNav(pt, nav_index, sym_index);
882882 defer debug_wip_nav.deinit();
883883 dwarf.finishWipNav(pt, nav_index, &debug_wip_nav) catch |err| switch (err) {
884884 error.OutOfMemory => return error.OutOfMemory,
test/incremental/change_exports+1-1
......@@ -1,4 +1,4 @@
1#target=x86_64-linux-selfhosted
1//#target=x86_64-linux-selfhosted
22#target=x86_64-linux-cbe
33#target=x86_64-windows-cbe
44