From 98165680582b4d592adb0a057ae2e00d74922e61 Mon Sep 17 00:00:00 2001 From: Matthew Lugg Date: Wed, 27 May 2026 09:44:20 +0100 Subject: [PATCH 1/6] compiler: make Tracy integration more useful --- build.zig | 51 +++--- src/Air/Liveness.zig | 4 +- src/Compilation.zig | 4 +- src/Sema.zig | 287 ------------------------------- src/Sema/type_resolution.zig | 21 +++ src/Zcu.zig | 55 +++++- src/Zcu/PerThread.zig | 88 ++++++---- src/codegen.zig | 7 + src/link.zig | 2 +- src/link/Elf2.zig | 5 + src/main.zig | 6 +- src/tracy.zig | 315 +++++++++++++++-------------------- 12 files changed, 305 insertions(+), 540 deletions(-) diff --git a/build.zig b/build.zig index 4f5ea5a0cc0d48c8aef83812ebf2758ab74092d4..b4172e5893c1502422705f1687b7f2e03b934458 100644 --- a/build.zig +++ b/build.zig @@ -181,10 +181,10 @@ pub fn build(b: *std.Build) !void { return; const entitlements = b.option([]const u8, "entitlements", "Path to entitlements file for hot-code swapping without sudo on macOS"); - const tracy = b.option([]const u8, "tracy", "Enable Tracy integration. Supply path to Tracy source"); - const tracy_callstack = b.option(bool, "tracy-callstack", "Include callstack information with Tracy data. Does nothing if -Dtracy is not provided") orelse (tracy != null); - const tracy_allocation = b.option(bool, "tracy-allocation", "Include allocation information with Tracy data. Does nothing if -Dtracy is not provided") orelse (tracy != null); - const tracy_callstack_depth: u32 = b.option(u32, "tracy-callstack-depth", "Declare callstack depth for Tracy data. Does nothing if -Dtracy_callstack is not provided") orelse 10; + const tracy = b.option(std.Build.LazyPath, "tracy", "Enable Tracy integration. Supply path to Tracy source"); + const tracy_callstack = b.option(bool, "tracy-callstack", "Include callstack information with Tracy data. Does nothing if -Dtracy is not provided. Has a significant performance impact in some cases. Default: false") orelse false; + const tracy_allocation = b.option(bool, "tracy-allocation", "Include allocation information with Tracy data. Does nothing if -Dtracy is not provided. Default: true") orelse (tracy != null); + const tracy_callstack_depth: u32 = b.option(u32, "tracy-callstack-depth", "Declare callstack depth for Tracy data. Does nothing if -Dtracy-callstack is not provided") orelse 6; const debug_gpa = b.option(bool, "debug-allocator", "Force the compiler to use SafeAllocator") orelse false; const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse (enable_llvm or only_c); const sanitize_thread = b.option(bool, "sanitize-thread", "Enable thread-sanitization") orelse false; @@ -373,32 +373,31 @@ pub fn build(b: *std.Build) !void { exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation); exe_options.addOption(u32, "tracy_callstack_depth", tracy_callstack_depth); exe_options.addOption(bool, "value_tracing", value_tracing); - if (tracy) |tracy_path| { - const client_cpp = b.pathJoin( - &[_][]const u8{ tracy_path, "public", "TracyClient.cpp" }, - ); - - const tracy_c_flags: []const []const u8 = &.{ - "-DTRACY_ENABLE=1", - "-fno-sanitize=undefined", - "-DTRACY_FIBERS", - }; - - exe.root_module.addIncludePath(.{ .cwd_relative = tracy_path }); - exe.root_module.addCSourceFile(.{ - .file = .{ .cwd_relative = client_cpp }, - .flags = tracy_c_flags[0..switch (io_mode) { - .threaded => 2, - .evented => 3, - }], + if (tracy) |tracy_dir| { + const tracy_mod = b.createModule(.{ + .target = target, + // Always build Tracy in ReleaseFast so that it doesn't make Debug compiler builds unusable. + .optimize = .ReleaseFast, + .root_source_file = null, + .link_libc = true, + .link_libcpp = true, }); - exe.root_module.link_libc = true; - exe.root_module.link_libcpp = true; + + tracy_mod.addCMacro("TRACY_ENABLE", "1"); + + if (!tracy_callstack) { + tracy_mod.addCMacro("TRACY_NO_CALLSTACK", "1"); + } + + tracy_mod.addIncludePath(tracy_dir); + tracy_mod.addCSourceFile(.{ .file = tracy_dir.path(b, "public/TracyClient.cpp") }); if (target.result.os.tag == .windows) { - exe.root_module.linkSystemLibrary("dbghelp", .{}); - exe.root_module.linkSystemLibrary("ws2_32", .{}); + tracy_mod.linkSystemLibrary("dbghelp", .{}); + tracy_mod.linkSystemLibrary("ws2_32", .{}); } + + exe.root_module.addImport("tracy", tracy_mod); } const test_filters = b.option([]const []const u8, "test-filter", "Skip tests that do not match any filter") orelse &[0][]const u8{}; diff --git a/src/Air/Liveness.zig b/src/Air/Liveness.zig index cc0b4803b6b1a49c6b9fb678aa1e1a0b16f85a48..773074a1ce9de7cf019a167d36483db6e3316ec8 100644 --- a/src/Air/Liveness.zig +++ b/src/Air/Liveness.zig @@ -13,7 +13,7 @@ const Log2Int = std.math.Log2Int; const Writer = std.Io.Writer; const Liveness = @This(); -const trace = @import("../tracy.zig").trace; +const traceNamed = @import("../tracy.zig").traceNamed; const Air = @import("../Air.zig"); const InternPool = @import("../InternPool.zig"); const Zcu = @import("../Zcu.zig"); @@ -140,7 +140,7 @@ fn LivenessPassData(comptime pass: LivenessPass) type { } pub fn analyze(zcu: *Zcu, air: Air, intern_pool: *InternPool) Allocator.Error!Liveness { - const tracy = trace(@src()); + const tracy = traceNamed(@src(), "analyze_liveness"); defer tracy.end(); const gpa = zcu.gpa; diff --git a/src/Compilation.zig b/src/Compilation.zig index 8f5cd5ce8972640a47ae6b39fee3b9008ace462b..180d41f08ce99369294308dc2739d90e8a46b22d 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2870,8 +2870,8 @@ pub const UpdateError = error{ /// Detect changes to source files, perform semantic analysis, and update the output files. pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateError!void { - const tracy_trace = trace(@src()); - defer tracy_trace.end(); + const tracy_frame = tracy.namedFrame(comp.root_name); + defer tracy_frame.end(); const gpa = comp.gpa; const io = comp.io; diff --git a/src/Sema.zig b/src/Sema.zig index b2ba7c8643df8b61a5065a4a38e6f6ab168ec76d..8d3e2ddbd75775415acf4d1602f0a193f7a51ac6 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -19,7 +19,6 @@ const Type = @import("Type.zig"); const Air = @import("Air.zig"); const Zir = std.zig.Zir; const Zcu = @import("Zcu.zig"); -const trace = @import("tracy.zig").trace; const Namespace = Zcu.Namespace; const CompileError = Zcu.CompileError; const SemaError = Zcu.SemaError; @@ -1127,8 +1126,6 @@ fn analyzeBodyInner( block: *Block, body: []const Zir.Inst.Index, ) CompileError!void { - // No tracy calls here, to avoid interfering with the tail call mechanism. - try sema.inst_map.ensureSpaceForInstructions(sema.gpa, body); const pt = sema.pt; @@ -3002,9 +2999,6 @@ fn zirErrorSetDecl( sema: *Sema, inst: Zir.Inst.Index, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const comp = zcu.comp; @@ -3032,9 +3026,6 @@ fn zirErrorSetDecl( } fn zirRetPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; @@ -3061,18 +3052,12 @@ fn zirRetPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. } fn zirRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_tok; const operand = sema.resolveInst(inst_data.operand); return sema.analyzeRef(block, block.tokenOffset(inst_data.src_tok), operand, .none); } fn zirEnsureResultUsed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const operand = sema.resolveInst(inst_data.operand); const src = block.nodeOffset(inst_data.src_node); @@ -3114,9 +3099,6 @@ fn ensureResultUsed( } fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; @@ -3139,9 +3121,6 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com } fn zirEnsureErrUnionPayloadVoid(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; @@ -3166,9 +3145,6 @@ fn zirEnsureErrUnionPayloadVoid(sema: *Sema, block: *Block, inst: Zir.Inst.Index } fn zirIndexablePtrLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const src = block.nodeOffset(inst_data.src_node); const object = sema.resolveInst(inst_data.operand); @@ -3302,9 +3278,6 @@ fn zirAllocExtended( } fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node }); const var_src = block.nodeOffset(inst_data.src_node); @@ -3732,9 +3705,6 @@ fn zirAllocInferredComptime( } fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; @@ -3764,9 +3734,6 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I } fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; @@ -3797,9 +3764,6 @@ fn zirAllocInferred( block: *Block, is_const: bool, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const gpa = sema.gpa; if (block.isComptime()) { @@ -3830,9 +3794,6 @@ fn zirAllocInferred( } fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const gpa = sema.gpa; @@ -4391,9 +4352,6 @@ fn zirValidatePtrStructInit( block: *Block, inst: Zir.Inst.Index, ) CompileError!void { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const validate_inst = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; @@ -4776,9 +4734,6 @@ pub fn addDeclaredHereNote(sema: *Sema, parent: *Zcu.ErrorMsg, decl_ty: Type) !v } fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { - const tracy = trace(@src()); - defer tracy.end(); - const pl_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const src = block.nodeOffset(pl_node.src_node); const bin = sema.code.extraData(Zir.Inst.Bin, pl_node.payload_index).data; @@ -4870,9 +4825,6 @@ fn zirSetEvalBranchQuota(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi } fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { - const tracy = trace(@src()); - defer tracy.end(); - const zir_tags = sema.code.instructions.items(.tag); const zir_datas = sema.code.instructions.items(.data); const inst_data = zir_datas[@intFromEnum(inst)].pl_node; @@ -4935,8 +4887,6 @@ fn uavRef(sema: *Sema, val: Value) CompileError!Air.Inst.Ref { fn zirInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { _ = block; - const tracy = trace(@src()); - defer tracy.end(); const int = sema.code.instructions.items(.data)[@intFromEnum(inst)].int; return sema.pt.intRef(.comptime_int, int); @@ -4944,8 +4894,6 @@ fn zirInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins fn zirIntBig(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { _ = block; - const tracy = trace(@src()); - defer tracy.end(); const int = sema.code.instructions.items(.data)[@intFromEnum(inst)].str; const byte_count = int.len * @sizeOf(std.math.big.Limb); @@ -4981,9 +4929,6 @@ fn zirFloat128(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } fn zirCompileError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const src = block.nodeOffset(inst_data.src_node); const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0); @@ -5111,9 +5056,6 @@ fn zirTrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { } fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; @@ -5202,9 +5144,6 @@ fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) Comp } fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pl_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const src = parent_block.nodeOffset(pl_node.src_node); const extra = sema.code.extraData(Zir.Inst.Block, pl_node.payload_index); @@ -5326,9 +5265,6 @@ fn resolveAnalyzedBlock( merges: *Block.Merges, need_debug_scope: bool, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const gpa = sema.gpa; const pt = sema.pt; const zcu = pt.zcu; @@ -5540,9 +5476,6 @@ fn resolveAnalyzedBlock( } fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; @@ -5713,9 +5646,6 @@ fn zirSetRuntimeSafety(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compile } fn zirBreak(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError!void { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].@"break"; const extra = sema.code.extraData(Zir.Inst.Break, inst_data.payload_index).data; const operand = sema.resolveInst(inst_data.operand); @@ -5746,9 +5676,6 @@ fn zirBreak(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError } fn zirSwitchContinue(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError!void { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].@"break"; const extra = sema.code.extraData(Zir.Inst.Break, inst_data.payload_index).data; const operand_src = start_block.nodeOffset(extra.operand_src_node.unwrap().?); @@ -6139,9 +6066,6 @@ fn zirCall( inst: Zir.Inst.Index, comptime kind: enum { direct, field }, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const comp = zcu.comp; @@ -7376,9 +7300,6 @@ fn zirIntType(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { } fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; @@ -7469,9 +7390,6 @@ fn zirVectorType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! } fn zirArrayType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; const len_src = block.src(.{ .node_offset_array_type_len = inst_data.src_node }); @@ -7488,9 +7406,6 @@ fn zirArrayType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A } fn zirArrayTypeSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const comp = zcu.comp; @@ -7534,9 +7449,6 @@ fn validateArrayElemType(sema: *Sema, block: *Block, elem_type: Type, elem_src: } fn zirAnyframeType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; if (true) { return sema.failWithUseOfAsync(block, block.nodeOffset(inst_data.src_node)); @@ -7550,9 +7462,6 @@ fn zirAnyframeType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro } fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; @@ -7613,9 +7522,6 @@ fn zirErrorValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! } fn zirIntFromError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; @@ -7655,9 +7561,6 @@ fn zirIntFromError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD } fn zirErrorFromInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const io = zcu.comp.io; @@ -7702,9 +7605,6 @@ fn zirErrorFromInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD } fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; @@ -7759,8 +7659,6 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr fn zirEnumLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { _ = block; - const tracy = trace(@src()); - defer tracy.end(); const pt = sema.pt; const zcu = pt.zcu; @@ -7776,9 +7674,6 @@ fn zirEnumLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError } fn zirDeclLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index, do_coerce: bool) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const comp = zcu.comp; @@ -7960,9 +7855,6 @@ fn zirOptionalPayloadPtr( inst: Zir.Inst.Index, safety_check: bool, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const optional_ptr = sema.resolveInst(inst_data.operand); const src = block.nodeOffset(inst_data.src_node); @@ -8051,9 +7943,6 @@ fn zirOptionalPayload( inst: Zir.Inst.Index, safety_check: bool, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; @@ -8105,9 +7994,6 @@ fn zirErrUnionPayload( block: *Block, inst: Zir.Inst.Index, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; @@ -8164,9 +8050,6 @@ fn zirErrUnionPayloadPtr( block: *Block, inst: Zir.Inst.Index, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const operand = sema.resolveInst(inst_data.operand); const src = block.nodeOffset(inst_data.src_node); @@ -8256,9 +8139,6 @@ fn analyzeErrUnionPayloadPtr( /// Value in, value out fn zirErrUnionCode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const src = block.nodeOffset(inst_data.src_node); const operand = sema.resolveInst(inst_data.operand); @@ -8292,9 +8172,6 @@ fn analyzeErrUnionCode(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air /// Pointer in, value out fn zirErrUnionCodePtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const src = block.nodeOffset(inst_data.src_node); const operand = sema.resolveInst(inst_data.operand); @@ -9088,9 +8965,6 @@ fn zirParamAnytype( } fn zirAsNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const src = block.nodeOffset(inst_data.src_node); const extra = sema.code.extraData(Zir.Inst.As, inst_data.payload_index).data; @@ -9098,9 +8972,6 @@ fn zirAsNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. } fn zirAsShiftOperand(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const src = block.nodeOffset(inst_data.src_node); const extra = sema.code.extraData(Zir.Inst.As, inst_data.payload_index).data; @@ -9136,9 +9007,6 @@ fn analyzeAs( } fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; @@ -9193,9 +9061,6 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! } fn zirFieldPtrLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const comp = zcu.comp; @@ -9218,9 +9083,6 @@ fn zirFieldPtrLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro } fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const comp = zcu.comp; @@ -9243,9 +9105,6 @@ fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } fn zirStructInitFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const comp = zcu.comp; @@ -9276,9 +9135,6 @@ fn zirStructInitFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi } fn zirFieldPtrNamedLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const src = block.nodeOffset(inst_data.src_node); const field_name_src = block.builtinCallArgSrc(inst_data.src_node, 1); @@ -9289,9 +9145,6 @@ fn zirFieldPtrNamedLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil } fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const src = block.nodeOffset(inst_data.src_node); const field_name_src = block.builtinCallArgSrc(inst_data.src_node, 1); @@ -9302,9 +9155,6 @@ fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr } fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const src = block.nodeOffset(inst_data.src_node); const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0); @@ -9375,9 +9225,6 @@ fn intCast( } fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; @@ -9541,9 +9388,6 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air } fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; @@ -9609,9 +9453,6 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A } fn zirElemVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const src = block.nodeOffset(inst_data.src_node); const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; @@ -9621,9 +9462,6 @@ fn zirElemVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air } fn zirElemPtrLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const src = block.nodeOffset(inst_data.src_node); const elem_index_src = block.src(.{ .node_offset_array_access_index = inst_data.src_node }); @@ -9643,9 +9481,6 @@ fn zirElemPtrLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError } fn zirElemValImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].elem_val_imm; const array = sema.resolveInst(inst_data.operand); const elem_index = try sema.pt.intRef(.usize, inst_data.idx); @@ -9653,9 +9488,6 @@ fn zirElemValImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! } fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; @@ -9684,9 +9516,6 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air } fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const src = block.nodeOffset(inst_data.src_node); const elem_index_src = block.src(.{ .node_offset_array_access_index = inst_data.src_node }); @@ -9698,9 +9527,6 @@ fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError } fn zirArrayInitElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; @@ -9719,9 +9545,6 @@ fn zirArrayInitElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compile } fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const src = block.nodeOffset(inst_data.src_node); const extra = sema.code.extraData(Zir.Inst.SliceStart, inst_data.payload_index).data; @@ -9735,9 +9558,6 @@ fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! } fn zirSliceEnd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const src = block.nodeOffset(inst_data.src_node); const extra = sema.code.extraData(Zir.Inst.SliceEnd, inst_data.payload_index).data; @@ -9752,9 +9572,6 @@ fn zirSliceEnd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } fn zirSliceSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const src = block.nodeOffset(inst_data.src_node); const sentinel_src = block.src(.{ .node_offset_slice_sentinel = inst_data.src_node }); @@ -9771,9 +9588,6 @@ fn zirSliceSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr } fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const src = block.nodeOffset(inst_data.src_node); const extra = sema.code.extraData(Zir.Inst.SliceLength, inst_data.payload_index).data; @@ -9793,9 +9607,6 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError } fn zirSliceSentinelTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; @@ -9833,9 +9644,6 @@ fn zirSliceSentinelTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE } fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const gpa = sema.gpa; @@ -9999,8 +9807,6 @@ fn zirSwitchBlock( inst: Zir.Inst.Index, operand_is_ref: bool, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); const zir_switch = sema.code.getSwitchBlock(inst); const block_inst: Air.Inst.Index = @enumFromInt(sema.air_instructions.len); @@ -12847,9 +12653,6 @@ fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air } fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_tok; @@ -12898,9 +12701,6 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. } fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; @@ -12935,9 +12735,6 @@ fn zirShl( inst: Zir.Inst.Index, air_tag: Air.Inst.Tag, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; @@ -13125,9 +12922,6 @@ fn zirShr( inst: Zir.Inst.Index, air_tag: Air.Inst.Tag, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; @@ -13255,9 +13049,6 @@ fn zirBitwise( inst: Zir.Inst.Index, air_tag: Air.Inst.Tag, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; @@ -13438,9 +13229,6 @@ fn analyzeTupleCat( } fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; @@ -13933,9 +13721,6 @@ fn zirArithmetic( zir_tag: Zir.Inst.Tag, safety: bool, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const src = block.src(.{ .node_offset_bin_op = inst_data.src_node }); const lhs_src = block.src(.{ .node_offset_bin_lhs = inst_data.src_node }); @@ -14663,9 +14448,6 @@ fn zirOverflowArithmetic( extended: Zir.Inst.Extended.InstData, zir_tag: Zir.Inst.Extended, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; const src = block.nodeOffset(extra.node); @@ -15183,9 +14965,6 @@ fn analyzePtrArithmetic( } fn zirLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const src = block.nodeOffset(inst_data.src_node); const ptr_src = src; // TODO better source location @@ -15199,9 +14978,6 @@ fn zirAsm( extended: Zir.Inst.Extended.InstData, tmpl_is_expr: bool, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const comp = zcu.comp; @@ -15393,9 +15169,6 @@ fn zirCmpEq( op: std.math.CompareOperator, air_tag: Air.Inst.Tag, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; @@ -15509,9 +15282,6 @@ fn zirCmp( inst: Zir.Inst.Index, op: std.math.CompareOperator, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; const src: LazySrcLoc = block.nodeOffset(inst_data.src_node); @@ -15852,9 +15622,6 @@ fn zirBuiltinSrc( block: *Block, extended: Zir.Inst.Extended.InstData, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const comp = zcu.comp; @@ -17181,9 +16948,6 @@ fn zirTypeofPeer( extended: Zir.Inst.Extended.InstData, inst: Zir.Inst.Index, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const extra = sema.code.extraData(Zir.Inst.TypeOfPeer, extended.operand); const src = block.nodeOffset(extra.data.src_node); const body = sema.code.bodySlice(extra.data.body_index, extra.data.body_len); @@ -17249,9 +17013,6 @@ fn zirBoolBr( inst: Zir.Inst.Index, is_bool_or: bool, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const gpa = sema.gpa; @@ -17418,9 +17179,6 @@ fn zirIsNonNull( block: *Block, inst: Zir.Inst.Index, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const src = block.nodeOffset(inst_data.src_node); const operand = sema.resolveInst(inst_data.operand); @@ -17433,9 +17191,6 @@ fn zirIsNonNullPtr( block: *Block, inst: Zir.Inst.Index, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; @@ -17472,9 +17227,6 @@ fn checkErrorType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { } fn zirIsNonErr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const src = block.nodeOffset(inst_data.src_node); const operand = sema.resolveInst(inst_data.operand); @@ -17483,9 +17235,6 @@ fn zirIsNonErr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; @@ -17500,9 +17249,6 @@ fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError } fn zirRetIsNonErr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const src = block.nodeOffset(inst_data.src_node); const operand = sema.resolveInst(inst_data.operand); @@ -17514,9 +17260,6 @@ fn zirCondbr( parent_block: *Block, inst: Zir.Inst.Index, ) CompileError!void { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; @@ -17866,9 +17609,6 @@ fn zirRetImplicit( block: *Block, inst: Zir.Inst.Index, ) CompileError!void { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_tok; @@ -17913,9 +17653,6 @@ fn zirRetImplicit( } fn zirRetNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const operand = sema.resolveInst(inst_data.operand); const src = block.nodeOffset(inst_data.src_node); @@ -17924,9 +17661,6 @@ fn zirRetNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi } fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const src = block.nodeOffset(inst_data.src_node); const ret_ptr = sema.resolveInst(inst_data.operand); @@ -18071,9 +17805,6 @@ fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, extended: Zir.Inst.Ex /// its state at the point `block` was reached (or, if `block` is `none`, the /// point this function began execution). fn restoreErrRetIndex(sema: *Sema, start_block: *Block, src: LazySrcLoc, target_block: Zir.Inst.Ref, operand_zir: Zir.Inst.Ref) CompileError!void { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; @@ -18229,9 +17960,6 @@ fn floatOpAllowed(tag: Zir.Inst.Tag) bool { } fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const comp = zcu.comp; @@ -18361,9 +18089,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air } fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const src = block.nodeOffset(inst_data.src_node); const ty_src = block.src(.{ .node_offset_init_ty = inst_data.src_node }); @@ -18382,9 +18107,6 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE } fn zirStructInitEmptyResult(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_byref: bool) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; @@ -19622,9 +19344,6 @@ fn zirUnaryMath( air_tag: Air.Inst.Tag, comptime eval: fn (Value, Type, Allocator, Zcu.PerThread) Allocator.Error!Value, ) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const operand = sema.resolveInst(inst_data.operand); const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0); @@ -23441,9 +23160,6 @@ fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. } fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; @@ -24489,9 +24205,6 @@ fn zirResume(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. } fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const pt = sema.pt; const zcu = pt.zcu; const comp = zcu.comp; diff --git a/src/Sema/type_resolution.zig b/src/Sema/type_resolution.zig index c3ef0e41f0b3b2e8febc0c6ddd451fbe35c04045..9f260a05795fd5993cb60f5f4bfffb8a1ffe644f 100644 --- a/src/Sema/type_resolution.zig +++ b/src/Sema/type_resolution.zig @@ -13,6 +13,7 @@ const LazySrcLoc = Zcu.LazySrcLoc; const InternPool = @import("../InternPool.zig"); const Alignment = InternPool.Alignment; const arith = @import("arith.zig"); +const trace = @import("../tracy.zig").trace; pub const LayoutResolveReason = enum { variable, @@ -174,6 +175,11 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { const gpa = comp.gpa; const ip = &zcu.intern_pool; + const tracy = trace(@src()); + defer tracy.end(); + tracy.addText(struct_ty.containerTypeName(ip).toSlice(ip)); + tracy.addTextFmt("ip_index={d}", .{struct_ty.toIntern()}); + assert(sema.owner.unwrap().type_layout == struct_ty.toIntern()); const struct_obj = ip.loadStructType(struct_ty.toIntern()); @@ -548,6 +554,11 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void { const gpa = comp.gpa; const ip = &zcu.intern_pool; + const tracy = trace(@src()); + defer tracy.end(); + tracy.addText(struct_ty.containerTypeName(ip).toSlice(ip)); + tracy.addTextFmt("ip_index={d}", .{struct_ty.toIntern()}); + assert(sema.owner.unwrap().struct_defaults == struct_ty.toIntern()); // We always depend on the layout of `struct_ty`. However, we don't actually need to resolve it @@ -655,6 +666,11 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { const gpa = comp.gpa; const ip = &zcu.intern_pool; + const tracy = trace(@src()); + defer tracy.end(); + tracy.addText(union_ty.containerTypeName(ip).toSlice(ip)); + tracy.addTextFmt("ip_index={d}", .{union_ty.toIntern()}); + assert(sema.owner.unwrap().type_layout == union_ty.toIntern()); const union_obj = ip.loadUnionType(union_ty.toIntern()); @@ -1134,6 +1150,11 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void { const gpa = comp.gpa; const ip = &zcu.intern_pool; + const tracy = trace(@src()); + defer tracy.end(); + tracy.addText(enum_ty.containerTypeName(ip).toSlice(ip)); + tracy.addTextFmt("ip_index={d}", .{enum_ty.toIntern()}); + assert(sema.owner.unwrap().type_layout == enum_ty.toIntern()); const enum_obj = ip.loadEnumType(enum_ty.toIntern()); diff --git a/src/Zcu.zig b/src/Zcu.zig index 80c3366381f33a660af5f6f5dd334243640fc532..d4bc62b365e8e92fd6da49f84c74c72d2e92099d 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -29,7 +29,7 @@ const Package = @import("Package.zig"); const link = @import("link.zig"); const Air = @import("Air.zig"); const Zir = std.zig.Zir; -const trace = @import("tracy.zig").trace; +const tracy = @import("tracy.zig"); const AstGen = std.zig.AstGen; const Sema = @import("Sema.zig"); const target_util = @import("target.zig"); @@ -2811,6 +2811,7 @@ pub const CompileError = error{ pub fn init(zcu: *Zcu, gpa: Allocator, io: Io, thread_count: usize) !void { try zcu.intern_pool.init(gpa, io, thread_count); + zcu.initTracyPlots(); } pub fn deinit(zcu: *Zcu) void { @@ -3161,12 +3162,15 @@ pub fn markDependeeOutdated( try zcu.markTransitiveDependersPotentiallyOutdated(depender); } } + + zcu.updateTracyOutdatedPlots(); } pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(zcu.comp.io); defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(zcu.comp.io); - return markPoDependeeUpToDateInner(zcu, dependee); + try markPoDependeeUpToDateInner(zcu, dependee); + zcu.updateTracyOutdatedPlots(); } /// Assumes that `zcu.outdated_lock` is already held exclusively. fn markPoDependeeUpToDateInner(zcu: *Zcu, dependee: InternPool.Dependee) !void { @@ -3304,6 +3308,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { // Everything is up-to-date. There could be lingering entries in `zcu.potentially_outdated` // from a dependency loop on a previous update. zcu.potentially_outdated.clearRetainingCapacity(); + zcu.updateTracyOutdatedPlots(); log.debug("findOutdatedToAnalyze: all up-to-date", .{}); return null; } @@ -3337,6 +3342,7 @@ pub fn flushRetryableFailures(zcu: *Zcu) !void { try zcu.markTransitiveDependersPotentiallyOutdated(depender); } zcu.retryable_failures.clearRetainingCapacity(); + zcu.updateTracyOutdatedPlots(); } pub fn mapOldZirToNew( @@ -3580,6 +3586,7 @@ pub fn ensureFuncBodyAnalysisQueued(zcu: *Zcu, func: InternPool.Index) !void { try zcu.outdated_ready.funcs.ensureUnusedCapacity(gpa, 1); zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .func = func }), 0); zcu.outdated_ready.funcs.putAssumeCapacityNoClobber(func, {}); + zcu.updateTracyOutdatedPlots(); } } @@ -3598,6 +3605,7 @@ pub fn ensureNavValAnalysisQueued(zcu: *Zcu, nav: InternPool.Nav.Index) !void { zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .nav_ty = nav }), 0); zcu.outdated_ready.other.putAssumeCapacityNoClobber(.wrap(.{ .nav_val = nav }), {}); zcu.outdated_ready.other.putAssumeCapacityNoClobber(.wrap(.{ .nav_ty = nav }), {}); + zcu.updateTracyOutdatedPlots(); } } @@ -3614,6 +3622,7 @@ pub fn queueComptimeUnitAnalysis(zcu: *Zcu, cu: InternPool.ComptimeUnit.Id) Allo try zcu.outdated_ready.other.ensureUnusedCapacity(gpa, 1); zcu.outdated.putAssumeCapacityNoClobber(unit, 0); zcu.outdated_ready.other.putAssumeCapacityNoClobber(unit, {}); + zcu.updateTracyOutdatedPlots(); } /// If `unit` was marked as outdated or porentially outdated, clears that status and returns `true`. @@ -3632,8 +3641,10 @@ pub fn clearOutdatedState(zcu: *Zcu, unit: AnalUnit) bool { } else { assert(!was_ready); } + zcu.updateTracyOutdatedPlots(); return true; } else if (zcu.potentially_outdated.swapRemove(unit)) { + zcu.updateTracyOutdatedPlots(); return true; } else { return false; @@ -4164,6 +4175,9 @@ pub fn resolveReferences(zcu: *Zcu) Allocator.Error!*const std.AutoArrayHashMapU return &zcu.resolved_references.?; } fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.AutoArrayHashMapUnmanaged(AnalUnit, ?ResolvedReference) { + const trace = tracy.trace(@src()); + defer trace.end(); + const gpa = zcu.gpa; const comp = zcu.comp; const ip = &zcu.intern_pool; @@ -5265,6 +5279,7 @@ pub const CodegenTaskPool = struct { mir.deinit(zcu); } assert(pool.available_air_bytes == max_air_bytes_in_flight); + zcu.updateTracyPlot("air_bytes_in_flight", 0); } pub fn start( @@ -5298,6 +5313,12 @@ pub const CodegenTaskPool = struct { } pool.available_air_bytes -= effective_air_bytes; + + zcu.updateTracyPlot("air_bytes_in_flight", @max( + max_air_bytes_in_flight - pool.available_air_bytes, + actual_air_bytes, + )); + break :index pool.free.pop().?; }; @@ -5326,8 +5347,9 @@ pub const CodegenTaskPool = struct { pub fn wait( index: Index, pool: *CodegenTaskPool, - io: Io, + zcu: *const Zcu, ) PerThread.RunCodegenError!struct { InternPool.Index, codegen.AnyMir } { + const io = zcu.comp.io; const func = pool.task_funcs[@intFromEnum(index)]; assert(func != .none); const effective_air_bytes = pool.task_air_bytes[@intFromEnum(index)]; @@ -5343,6 +5365,7 @@ pub const CodegenTaskPool = struct { pool.available_air_bytes += effective_air_bytes; pool.free.appendAssumeCapacity(index); pool.free_cond.signal(io); + zcu.updateTracyPlot("air_bytes_in_flight", max_air_bytes_in_flight - pool.available_air_bytes); } return .{ func, try result }; @@ -5376,3 +5399,29 @@ pub const CodegenTaskPool = struct { return pt.runCodegen(func_index, air); } }; + +fn initTracyPlots(zcu: *const Zcu) void { + if (zcu.comp.skip_linker_dependencies) return; + + tracy.plotConfig("air_bytes_in_flight", .{ .format = .memory, .mode = .step }); + + tracy.plotConfig("outdated + potentially_outdated", .{ .format = .number, .mode = .step, .color = 0xFFFF00 }); + tracy.plotConfig("outdated", .{ .format = .number, .mode = .step, .color = 0xFF0000 }); + tracy.plotConfig("potentially_outdated", .{ .format = .number, .mode = .step, .color = 0xFF7700 }); + tracy.plotConfig("outdated_ready", .{ .format = .number, .mode = .step, .color = 0x00FF00 }); +} + +/// Marked `inline` to prevent binary bloat from trivial generic instances, and to ensure there is +/// minimal overhead to this call when Tracy is disabled, even in Debug builds. +inline fn updateTracyPlot(zcu: *const Zcu, comptime name: [*:0]const u8, val: u64) void { + if (zcu.comp.skip_linker_dependencies) return; + tracy.plotInt(name, @intCast(val)); +} + +/// Assumes that `zcu.outdated_lock` is already held. +fn updateTracyOutdatedPlots(zcu: *const Zcu) void { + zcu.updateTracyPlot("outdated + potentially_outdated", zcu.outdated.count() + zcu.potentially_outdated.count()); + zcu.updateTracyPlot("outdated", zcu.outdated.count()); + zcu.updateTracyPlot("potentially_outdated", zcu.potentially_outdated.count()); + zcu.updateTracyPlot("outdated_ready", zcu.outdated_ready.funcs.count() + zcu.outdated_ready.other.count()); +} diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index e4a3b9ca8226915482e8058d236ee2f585ee9da0..e537db9c87516d1a069ac0446207cff82e2ce248 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -313,18 +313,22 @@ pub fn update( // `comptime` declarations, any declarations marked `export`, and `test` declarations in the // main module if this is a test compilation---become referenced, and so will be picked up // up by the main semantic analysis loop below. - for (zcu.analysisRoots()) |analysis_root_mod| { - const analysis_root_file = zcu.module_roots.get(analysis_root_mod).?.unwrap().?; - try pt.ensureFilePopulated(analysis_root_file); + { + const tracy_trace = traceNamed(@src(), "populate_sema_roots"); + defer tracy_trace.end(); + for (zcu.analysisRoots()) |analysis_root_mod| { + const analysis_root_file = zcu.module_roots.get(analysis_root_mod).?.unwrap().?; + try pt.ensureFilePopulated(analysis_root_file); + } } + const tracy_trace = traceNamed(@src(), "sema_loop"); + defer tracy_trace.end(); + // This is the main semantic analysis loop, which is essentially the main loop of the whole // Zig compilation pipeline. It selects some `AnalUnit` which we know needs to be analyzed, // and analyzes it, which may in turn discover more `AnalUnit`s which we need to analyze. while (try zcu.findOutdatedToAnalyze()) |unit| { - const tracy_trace = traceNamed(@src(), "analyze_outdated"); - defer tracy_trace.end(); - const maybe_err: Zcu.SemaError!void = switch (unit.unwrap()) { .@"comptime" => |cu| pt.ensureComptimeUnitUpToDate(cu), .nav_ty => |nav| pt.ensureNavTypeUpToDate(nav, null), @@ -823,6 +827,9 @@ fn updateZirRefs(pt: Zcu.PerThread) (Io.Cancelable || Allocator.Error)!void { const gpa = comp.gpa; const io = comp.io; + const tracy_trace = trace(@src()); + defer tracy_trace.end(); + // We need to visit every updated File for every TrackedInst in InternPool. // This only includes Zig files; ZON files are omitted. var updated_files: std.AutoArrayHashMapUnmanaged(Zcu.File.Index, UpdatedFile) = .empty; @@ -1008,9 +1015,6 @@ fn updateZirRefs(pt: Zcu.PerThread) (Io.Cancelable || Allocator.Error)!void { pub fn ensureFilePopulated(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Allocator.Error || Io.Cancelable)!void { dev.check(.sema); - const tracy_trace = trace(@src()); - defer tracy_trace.end(); - const zcu = pt.zcu; const comp = zcu.comp; const io = comp.io; @@ -1019,6 +1023,9 @@ pub fn ensureFilePopulated(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Alloc if (zcu.fileRootType(file_index) != .none) return; // already good + const tracy_trace = traceNamed(@src(), "create_file_struct"); + defer tracy_trace.end(); + if (zcu.comp.time_report) |*tr| tr.stats.n_imported_files += 1; const file = zcu.fileByIndex(file_index); @@ -1065,9 +1072,6 @@ pub fn ensureMemoizedStateUpToDate( /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. reason: ?*const Zcu.DependencyReason, ) Zcu.SemaError!void { - const tracy_trace = trace(@src()); - defer tracy_trace.end(); - const zcu = pt.zcu; const gpa = zcu.gpa; @@ -1142,6 +1146,10 @@ fn analyzeMemoizedState( log.debug("analyzeMemoizedState({t})", .{stage}); + const tracy_trace = trace(@src()); + defer tracy_trace.end(); + tracy_trace.addText(@tagName(stage)); + const unit: AnalUnit = .wrap(.{ .memoized_state = stage }); try zcu.analysis_in_progress.putNoClobber(gpa, unit, reason); @@ -1174,9 +1182,6 @@ fn analyzeMemoizedState( /// if necessary. Returns `error.AnalysisFail` if an analysis error is encountered; the caller is /// free to ignore this, since the error is already registered. pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu.SemaError!void { - const tracy_trace = trace(@src()); - defer tracy_trace.end(); - const zcu = pt.zcu; const gpa = zcu.gpa; @@ -1257,6 +1262,10 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu log.debug("analyzeComptimeUnit {f}", .{zcu.fmtAnalUnit(anal_unit)}); + const tracy_trace = trace(@src()); + defer tracy_trace.end(); + tracy_trace.addTextFmt("cu_id={d}", .{cu_id}); + const inst_resolved = comptime_unit.zir_index.resolveFull(ip) orelse return error.AnalysisFail; const file = zcu.fileByIndex(inst_resolved.file); const zir = file.zir.?; @@ -1333,9 +1342,6 @@ pub fn ensureTypeLayoutUpToDate( /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. reason: ?*const Zcu.DependencyReason, ) Zcu.SemaError!void { - const tracy_trace = trace(@src()); - defer tracy_trace.end(); - const zcu = pt.zcu; const ip = &zcu.intern_pool; const comp = zcu.comp; @@ -1464,9 +1470,6 @@ pub fn ensureStructDefaultsUpToDate( /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. reason: ?*const Zcu.DependencyReason, ) Zcu.SemaError!void { - const tracy_trace = trace(@src()); - defer tracy_trace.end(); - const zcu = pt.zcu; const ip = &zcu.intern_pool; const comp = zcu.comp; @@ -1572,9 +1575,6 @@ pub fn ensureNavValUpToDate( /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. reason: ?*const Zcu.DependencyReason, ) Zcu.SemaError!void { - const tracy_trace = trace(@src()); - defer tracy_trace.end(); - const zcu = pt.zcu; const gpa = zcu.gpa; const ip = &zcu.intern_pool; @@ -1677,6 +1677,11 @@ fn analyzeNavVal( log.debug("analyzeNavVal {f}", .{zcu.fmtAnalUnit(anal_unit)}); + const tracy_trace = trace(@src()); + defer tracy_trace.end(); + tracy_trace.addText(old_nav.fqn.toSlice(ip)); + tracy_trace.addTextFmt("nav_id={d}", .{nav_id}); + const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail; const file = zcu.fileByIndex(inst_resolved.file); const zir = file.zir.?; @@ -1939,9 +1944,6 @@ pub fn ensureNavTypeUpToDate( /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. reason: ?*const Zcu.DependencyReason, ) Zcu.SemaError!void { - const tracy_trace = trace(@src()); - defer tracy_trace.end(); - const zcu = pt.zcu; const gpa = zcu.gpa; const ip = &zcu.intern_pool; @@ -2044,6 +2046,11 @@ fn analyzeNavType( log.debug("analyzeNavType {f}", .{zcu.fmtAnalUnit(anal_unit)}); + const tracy_trace = trace(@src()); + defer tracy_trace.end(); + tracy_trace.addText(old_nav.fqn.toSlice(ip)); + tracy_trace.addTextFmt("nav_id={d}", .{nav_id}); + const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail; const file = zcu.fileByIndex(inst_resolved.file); const zir = file.zir.?; @@ -2183,9 +2190,6 @@ pub fn ensureFuncBodyUpToDate( ) Zcu.SemaError!void { dev.check(.sema); - const tracy_trace = trace(@src()); - defer tracy_trace.end(); - const zcu = pt.zcu; const gpa = zcu.gpa; const ip = &zcu.intern_pool; @@ -2283,6 +2287,11 @@ fn analyzeFuncBody( log.debug("analyzeFuncBody {f}", .{zcu.fmtAnalUnit(anal_unit)}); + const tracy_trace = trace(@src()); + defer tracy_trace.end(); + tracy_trace.addText(ip.getNav(func.owner_nav).fqn.toSlice(ip)); + tracy_trace.addTextFmt("func_ip_index={d}", .{func_index}); + var air = try pt.analyzeFuncBodyInner(func_index, reason); var air_owned = true; defer if (air_owned) air.deinit(gpa); @@ -2592,6 +2601,9 @@ fn computeAliveFiles(pt: Zcu.PerThread) Allocator.Error!bool { const comp = zcu.comp; const gpa = zcu.gpa; + const tracy_trace = trace(@src()); + defer tracy_trace.end(); + var any_fatal_files = false; zcu.multi_module_err = null; zcu.failed_imports.clearRetainingCapacity(); @@ -3028,14 +3040,16 @@ pub fn scanNamespace( namespace_index: Zcu.Namespace.Index, decls: []const Zir.Inst.Index, ) Allocator.Error!void { - const tracy_trace = trace(@src()); - defer tracy_trace.end(); - const zcu = pt.zcu; const ip = &zcu.intern_pool; const gpa = zcu.gpa; const namespace = zcu.namespacePtr(namespace_index); + const tracy_trace = trace(@src()); + defer tracy_trace.end(); + tracy_trace.addText(Type.fromInterned(namespace.owner_type).containerTypeName(ip).toSlice(ip)); + tracy_trace.addTextFmt("type_ip_index={d}", .{namespace.owner_type}); + const tracked_unit = zcu.trackUnitSema( Type.fromInterned(namespace.owner_type).containerTypeName(ip).toSlice(ip), null, @@ -3247,9 +3261,6 @@ fn analyzeFuncBodyInner( func_index: InternPool.Index, reason: ?*const Zcu.DependencyReason, ) Zcu.SemaError!Air { - const tracy_trace = trace(@src()); - defer tracy_trace.end(); - const zcu = pt.zcu; const comp = zcu.comp; const gpa = comp.gpa; @@ -4556,6 +4567,11 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e const codegen_prog_node = zcu.codegen_prog_node.start(fqn.toSlice(ip), 0); defer codegen_prog_node.end(); + const tracy_trace = trace(@src()); + defer tracy_trace.end(); + tracy_trace.addText(fqn.toSlice(ip)); + tracy_trace.addTextFmt("func_ip_index={d}", .{func_index}); + if (codegen.legalizeFeatures(pt, nav)) |features| { try air.legalize(pt, features); } diff --git a/src/codegen.zig b/src/codegen.zig index 7e03dcf491cc2698e1e88cc7149dc2a15c17861d..402728d6337651b26abbcd5490bca4917153b8ce 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -186,6 +186,12 @@ pub fn emitFunction( const zcu = pt.zcu; const func = zcu.funcInfo(func_index); const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result; + + const tracy_trace = trace(@src()); + defer tracy_trace.end(); + tracy_trace.addText(zcu.intern_pool.getNav(func.owner_nav).fqn.toSlice(&zcu.intern_pool)); + tracy_trace.addTextFmt("func_ip_index={d}", .{func_index}); + switch (target_util.zigBackend(target, zcu.comp.config.use_llvm)) { else => unreachable, inline .stage2_aarch64, @@ -236,6 +242,7 @@ pub fn generateLazySymbol( ) (CodeGenError || std.Io.Writer.Error)!void { const tracy = trace(@src()); defer tracy.end(); + tracy.addTextFmt("{t}, {f}", .{ lazy_sym.kind, Type.fromInterned(lazy_sym.ty).fmt(pt) }); const comp = bin_file.comp; const zcu = pt.zcu; diff --git a/src/link.zig b/src/link.zig index dca69bfc756c6b6e66d3a7789c1f57b3df5df909..2c8a4f7aa5ea02dd6fe9047593fc016a0a5a700a 100644 --- a/src/link.zig +++ b/src/link.zig @@ -1573,7 +1573,7 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void }, .link_func => |codegen_task| nav: { timer.pause(io); - const func, var mir = codegen_task.wait(&zcu.codegen_task_pool, io) catch |err| switch (err) { + const func, var mir = codegen_task.wait(&zcu.codegen_task_pool, zcu) catch |err| switch (err) { error.Canceled, error.AlreadyReported => { comp.link_prog_node.completeOne(); return; diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig index 0ba105205e8c0887e97d53a17e3424958eb9eb02..f833663e78c94c2e41e064c9c0a240929efec32d 100644 --- a/src/link/Elf2.zig +++ b/src/link/Elf2.zig @@ -14,6 +14,7 @@ const InternPool = @import("../InternPool.zig"); const link = @import("../link.zig"); const MappedFile = @import("MappedFile.zig"); const target_util = @import("../target.zig"); +const tracy = @import("../tracy.zig"); const Type = @import("../Type.zig"); const Value = @import("../Value.zig"); const Zcu = @import("../Zcu.zig"); @@ -5865,6 +5866,8 @@ fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void { } fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { + const trace = tracy.trace(@src()); + defer trace.end(); switch (elf.getNode(ni)) { .file => unreachable, .ehdr, .shdr => try elf.flushFileOffset(ni), @@ -6019,6 +6022,8 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { } fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { + const trace = tracy.trace(@src()); + defer trace.end(); _, const size = ni.location(&elf.mf).resolve(&elf.mf); switch (elf.getNode(ni)) { .file => {}, diff --git a/src/main.zig b/src/main.zig index 0c3c458dd40985f37e8d30f9d7727656b35726f9..49630f637209c97817b6b6151bf8f6507de5365e 100644 --- a/src/main.zig +++ b/src/main.zig @@ -218,8 +218,8 @@ pub fn main(init: std.process.Init.Minimal) anyerror!void { var environ_map = init.environ.createMap(arena) catch |err| fatal("failed to parse environment: {t}", .{err}); if (tracy.enable_allocation) { - var gpa_tracy = tracy.tracyAllocator(gpa); - return mainArgs(gpa_tracy.allocator(), arena, io, args, &environ_map); + var tracy_allocator: tracy.Allocator = .{ .parent_allocator = gpa }; + return mainArgs(tracy_allocator.interface(), arena, io, args, &environ_map); } if (native_os == .wasi) { @@ -4239,7 +4239,6 @@ fn serve( switch (hdr.tag) { .exit => return cleanExit(io), .update => { - tracy.frameMark(); file_system_inputs.clearRetainingCapacity(); if (arg_mode == .translate_c) { @@ -4296,7 +4295,6 @@ fn serve( //); }, .hot_update => { - tracy.frameMark(); file_system_inputs.clearRetainingCapacity(); if (child_pid) |pid| { try comp.hotCodeSwap(main_progress_node, pid); diff --git a/src/tracy.zig b/src/tracy.zig index 7dd8123b98f7b186ff577c5c6fcf13016ecd49ac..ae3ca4ef9d505b6bf419d86644c86b2bff2717b4 100644 --- a/src/tracy.zig +++ b/src/tracy.zig @@ -1,11 +1,13 @@ const std = @import("std"); +const assert = std.debug.assert; + const builtin = @import("builtin"); const build_options = @import("build_options"); pub const enable = if (builtin.is_test) false else build_options.enable_tracy; pub const enable_allocation = enable and build_options.enable_tracy_allocation; pub const enable_callstack = enable and build_options.enable_tracy_callstack; -pub const callstack_depth = if (enable_callstack and build_options.tracy_callstack_depth > 0) build_options.tracy_callstack_depth else 10; +pub const callstack_depth = if (enable_callstack) build_options.tracy_callstack_depth else 0; const ___tracy_c_zone_context = extern struct { id: u32, @@ -19,6 +21,12 @@ const ___tracy_c_zone_context = extern struct { ___tracy_emit_zone_text(self, text.ptr, text.len); } + pub inline fn addTextFmt(self: @This(), comptime fmt: []const u8, args: anytype) void { + var buf: [512]u8 = undefined; + const slice = std.fmt.bufPrint(&buf, fmt, args) catch &buf; + self.addText(slice); + } + pub inline fn setName(self: @This(), name: []const u8) void { ___tracy_emit_zone_name(self, name.ptr, name.len); } @@ -42,6 +50,12 @@ pub const Ctx = if (enable) ___tracy_c_zone_context else struct { _ = text; } + pub inline fn addTextFmt(self: @This(), comptime fmt: []const u8, args: anytype) void { + _ = self; + _ = fmt; + _ = args; + } + pub inline fn setName(self: @This(), name: []const u8) void { _ = self; _ = name; @@ -71,11 +85,7 @@ pub inline fn trace(comptime src: std.lang.SourceLocation) Ctx { }; }; - if (enable_callstack) { - return ___tracy_emit_zone_begin_callstack(&global.loc, callstack_depth, 1); - } else { - return ___tracy_emit_zone_begin(&global.loc, 1); - } + return ___tracy_emit_zone_begin_callstack(&global.loc, callstack_depth, 1); } pub inline fn traceNamed(comptime src: std.lang.SourceLocation, comptime name: [:0]const u8) Ctx { @@ -91,11 +101,7 @@ pub inline fn traceNamed(comptime src: std.lang.SourceLocation, comptime name: [ }; }; - if (enable_callstack) { - return ___tracy_emit_zone_begin_callstack(&global.loc, callstack_depth, 1); - } else { - return ___tracy_emit_zone_begin(&global.loc, 1); - } + return ___tracy_emit_zone_begin_callstack(&global.loc, callstack_depth, 1); } pub inline fn fiberEnter(fiber: [*:0]const u8) void { @@ -108,102 +114,93 @@ pub inline fn fiberLeave() void { ___tracy_fiber_leave(); } -pub fn tracyAllocator(allocator: std.mem.Allocator) TracyAllocator(null) { - return TracyAllocator(null).init(allocator); +pub inline fn plotConfig(comptime name: [*:0]const u8, config: PlotConfig) void { + if (!enable) return; + ___tracy_emit_plot_config( + name, + config.format, + config.mode, + @intFromBool(config.fill), + // https://github.com/wolfpld/tracy/issues/1232 + @byteSwap(config.color), + ); } -pub fn TracyAllocator(comptime name: ?[:0]const u8) type { - return struct { - parent_allocator: std.mem.Allocator, - - const Self = @This(); - - pub fn init(parent_allocator: std.mem.Allocator) Self { - return .{ - .parent_allocator = parent_allocator, - }; - } - - pub fn allocator(self: *Self) std.mem.Allocator { - return .{ - .ptr = self, - .vtable = &.{ - .alloc = allocFn, - .resize = resizeFn, - .remap = remapFn, - .free = freeFn, - }, - }; - } +pub inline fn plotInt(comptime name: [*:0]const u8, val: i64) void { + if (!enable) return; + ___tracy_emit_plot_int(name, val); +} - fn allocFn(ptr: *anyopaque, len: usize, alignment: std.mem.Alignment, ret_addr: usize) ?[*]u8 { - const self: *Self = @ptrCast(@alignCast(ptr)); - const result = self.parent_allocator.rawAlloc(len, alignment, ret_addr); - if (result) |memory| { - if (len != 0) { - if (name) |n| { - allocNamed(memory, len, n); - } else { - alloc(memory, len); - } - } - } else { - messageColor("allocation failed", 0xFF0000); - } - return result; +pub const Allocator = struct { + parent_allocator: std.mem.Allocator, + + comptime { + assert(enable); // used `tracy.Allocator` with Tracy disabled + } + + pub fn interface(self: *Allocator) std.mem.Allocator { + return .{ + .ptr = self, + .vtable = &.{ + .alloc = allocFn, + .resize = resizeFn, + .remap = remapFn, + .free = freeFn, + }, + }; + } + + fn allocFn(ptr: *anyopaque, len: usize, alignment: std.mem.Alignment, ret_addr: usize) ?[*]u8 { + const self: *Allocator = @ptrCast(@alignCast(ptr)); + assert(len > 0); + if (self.parent_allocator.rawAlloc(len, alignment, ret_addr)) |memory| { + ___tracy_emit_memory_alloc_callstack(memory, len, callstack_depth, 0); + return memory; + } else { + messageColor("allocation failed", 0xFF0000); + return null; } - - fn resizeFn(ptr: *anyopaque, memory: []u8, alignment: std.mem.Alignment, new_len: usize, ret_addr: usize) bool { - const self: *Self = @ptrCast(@alignCast(ptr)); - if (self.parent_allocator.rawResize(memory, alignment, new_len, ret_addr)) { - if (name) |n| { - freeNamed(memory.ptr, n); - allocNamed(memory.ptr, new_len, n); - } else { - free(memory.ptr); - alloc(memory.ptr, new_len); - } - - return true; - } - - // during normal operation the compiler hits this case thousands of times due to this - // emitting messages for it is both slow and causes clutter + } + + fn resizeFn(ptr: *anyopaque, memory: []u8, alignment: std.mem.Alignment, new_len: usize, ret_addr: usize) bool { + const self: *Allocator = @ptrCast(@alignCast(ptr)); + assert(memory.len > 0); + assert(new_len > 0); + // We need to mark the free before calling the implementation to avoid a race. + ___tracy_emit_memory_free_callstack(memory.ptr, callstack_depth, 0); + if (self.parent_allocator.rawResize(memory, alignment, new_len, ret_addr)) { + ___tracy_emit_memory_alloc_callstack(memory.ptr, new_len, callstack_depth, 0); + return true; + } else { + // No `messageColor` call here because this case is hit frequently in normal operation. + ___tracy_emit_memory_alloc_callstack(memory.ptr, memory.len, callstack_depth, 0); return false; } + } - fn remapFn(ptr: *anyopaque, memory: []u8, alignment: std.mem.Alignment, new_len: usize, ret_addr: usize) ?[*]u8 { - const self: *Self = @ptrCast(@alignCast(ptr)); - if (self.parent_allocator.rawRemap(memory, alignment, new_len, ret_addr)) |new_memory| { - if (name) |n| { - freeNamed(memory.ptr, n); - allocNamed(new_memory, new_len, n); - } else { - free(memory.ptr); - alloc(new_memory, new_len); - } - return new_memory; - } else { - messageColor("reallocation failed", 0xFF0000); - return null; - } + fn remapFn(ptr: *anyopaque, memory: []u8, alignment: std.mem.Alignment, new_len: usize, ret_addr: usize) ?[*]u8 { + const self: *Allocator = @ptrCast(@alignCast(ptr)); + assert(memory.len > 0); + assert(new_len > 0); + // We need to mark the free before calling the implementation to avoid a race. + ___tracy_emit_memory_free_callstack(memory.ptr, callstack_depth, 0); + if (self.parent_allocator.rawRemap(memory, alignment, new_len, ret_addr)) |new_memory| { + ___tracy_emit_memory_alloc_callstack(new_memory, new_len, callstack_depth, 0); + return new_memory; + } else { + // No `messageColor` call here because this case is hit frequently in normal operation. + ___tracy_emit_memory_alloc_callstack(memory.ptr, memory.len, callstack_depth, 0); + return null; } + } - fn freeFn(ptr: *anyopaque, memory: []u8, alignment: std.mem.Alignment, ret_addr: usize) void { - const self: *Self = @ptrCast(@alignCast(ptr)); - self.parent_allocator.rawFree(memory, alignment, ret_addr); - // this condition is to handle free being called on an empty slice that was never even allocated - // example case: `std.process.getSelfExeSharedLibPaths` can return `&[_][:0]u8{}` - if (memory.len != 0) { - if (name) |n| { - freeNamed(memory.ptr, n); - } else { - free(memory.ptr); - } - } - } - }; -} + fn freeFn(ptr: *anyopaque, memory: []u8, alignment: std.mem.Alignment, ret_addr: usize) void { + const self: *Allocator = @ptrCast(@alignCast(ptr)); + assert(memory.len > 0); + ___tracy_emit_memory_free_callstack(memory.ptr, callstack_depth, 0); + self.parent_allocator.rawFree(memory, alignment, ret_addr); + } +}; // This function only accepts comptime-known strings, see `messageCopy` for runtime strings pub inline fn message(comptime msg: [:0]const u8) void { @@ -213,7 +210,7 @@ pub inline fn message(comptime msg: [:0]const u8) void { // This function only accepts comptime-known strings, see `messageColorCopy` for runtime strings pub inline fn messageColor(comptime msg: [:0]const u8, color: u24) void { if (!enable) return; - ___tracy_emit_logStringL(.Info, color, if (enable_callstack) callstack_depth else 0, msg.ptr); + ___tracy_emit_logStringL(.Info, color, callstack_depth, msg.ptr); } pub inline fn messageCopy(msg: []const u8) void { @@ -222,84 +219,29 @@ pub inline fn messageCopy(msg: []const u8) void { pub inline fn messageColorCopy(msg: []const u8, color: u24) void { if (!enable) return; - ___tracy_emit_logString(.Info, color, if (enable_callstack) callstack_depth else 0, msg.len, msg.ptr); + ___tracy_emit_logString(.Info, color, callstack_depth, msg.len, msg.ptr); } -pub inline fn frameMark() void { - if (!enable) return; - ___tracy_emit_frame_mark(null); -} - -pub inline fn frameMarkNamed(comptime name: [:0]const u8) void { - if (!enable) return; - ___tracy_emit_frame_mark(name.ptr); -} - -pub inline fn namedFrame(comptime name: [:0]const u8) Frame(name) { - frameMarkStart(name); - return .{}; -} - -pub fn Frame(comptime name: [:0]const u8) type { - return struct { - pub fn end(_: @This()) void { - frameMarkEnd(name); - } - }; -} - -inline fn frameMarkStart(comptime name: [:0]const u8) void { - if (!enable) return; - ___tracy_emit_frame_mark_start(name.ptr); -} - -inline fn frameMarkEnd(comptime name: [:0]const u8) void { - if (!enable) return; - ___tracy_emit_frame_mark_end(name.ptr); -} - -extern fn ___tracy_emit_frame_mark_start(name: [*:0]const u8) void; -extern fn ___tracy_emit_frame_mark_end(name: [*:0]const u8) void; +/// Used to store strings which Tracy requires to have stable pointers for the program's entire +/// lifetime. All such strings will be leaked. +/// +/// The `enable` check ensures that this is not referenced if Tracy is disabled. +var tracy_arena: std.heap.ArenaAllocator = if (enable) .init(std.heap.page_allocator); -inline fn alloc(ptr: [*]u8, len: usize) void { - if (!enable) return; - - if (enable_callstack) { - ___tracy_emit_memory_alloc_callstack(ptr, len, callstack_depth, 0); - } else { - ___tracy_emit_memory_alloc(ptr, len, 0); - } -} - -inline fn allocNamed(ptr: [*]u8, len: usize, comptime name: [:0]const u8) void { - if (!enable) return; - - if (enable_callstack) { - ___tracy_emit_memory_alloc_callstack_named(ptr, len, callstack_depth, 0, name.ptr); - } else { - ___tracy_emit_memory_alloc_named(ptr, len, 0, name.ptr); - } +pub inline fn namedFrame(name: []const u8) Frame { + if (!enable) return .{ .name = {} }; + const stable_name = tracy_arena.allocator().dupeSentinel(u8, name, 0) catch @panic("tracy arena OOM"); + ___tracy_emit_frame_mark_start(stable_name.ptr); + return .{ .name = stable_name.ptr }; } -inline fn free(ptr: [*]u8) void { - if (!enable) return; - - if (enable_callstack) { - ___tracy_emit_memory_free_callstack(ptr, callstack_depth, 0); - } else { - ___tracy_emit_memory_free(ptr, 0); - } -} - -inline fn freeNamed(ptr: [*]u8, comptime name: [:0]const u8) void { - if (!enable) return; - - if (enable_callstack) { - ___tracy_emit_memory_free_callstack_named(ptr, callstack_depth, 0, name.ptr); - } else { - ___tracy_emit_memory_free_named(ptr, 0, name.ptr); +pub const Frame = struct { + name: if (enable) [*:0]const u8 else void, + pub inline fn end(frame: Frame) void { + if (!enable) return; + ___tracy_emit_frame_mark_end(frame.name); } -} +}; pub const MessageSeverity = enum(i8) { Trace, // Broadly track variable states and events in the software program. @@ -310,24 +252,39 @@ pub const MessageSeverity = enum(i8) { Fatal, // Describes a critical event that will lead to a software failure/crash. }; -extern fn ___tracy_emit_zone_begin(srcloc: *const ___tracy_source_location_data, active: i32) ___tracy_c_zone_context; +pub const PlotConfig = struct { + format: Format, + mode: Mode, + fill: bool = true, + color: u24 = 0, + + pub const Format = enum(i32) { + number = 0, + memory = 1, + percentage = 2, + watt = 3, + }; + + pub const Mode = enum(i32) { + line = 0, + step = 1, + }; +}; + +extern fn ___tracy_emit_frame_mark_start(name: [*:0]const u8) void; +extern fn ___tracy_emit_frame_mark_end(name: [*:0]const u8) void; extern fn ___tracy_emit_zone_begin_callstack(srcloc: *const ___tracy_source_location_data, depth: i32, active: i32) ___tracy_c_zone_context; extern fn ___tracy_emit_zone_text(ctx: ___tracy_c_zone_context, txt: [*]const u8, size: usize) void; extern fn ___tracy_emit_zone_name(ctx: ___tracy_c_zone_context, txt: [*]const u8, size: usize) void; extern fn ___tracy_emit_zone_color(ctx: ___tracy_c_zone_context, color: u32) void; extern fn ___tracy_emit_zone_value(ctx: ___tracy_c_zone_context, value: u64) void; extern fn ___tracy_emit_zone_end(ctx: ___tracy_c_zone_context) void; -extern fn ___tracy_emit_memory_alloc(ptr: *const anyopaque, size: usize, secure: i32) void; extern fn ___tracy_emit_memory_alloc_callstack(ptr: *const anyopaque, size: usize, depth: i32, secure: i32) void; -extern fn ___tracy_emit_memory_free(ptr: *const anyopaque, secure: i32) void; extern fn ___tracy_emit_memory_free_callstack(ptr: *const anyopaque, depth: i32, secure: i32) void; -extern fn ___tracy_emit_memory_alloc_named(ptr: *const anyopaque, size: usize, secure: i32, name: [*:0]const u8) void; -extern fn ___tracy_emit_memory_alloc_callstack_named(ptr: *const anyopaque, size: usize, depth: i32, secure: i32, name: [*:0]const u8) void; -extern fn ___tracy_emit_memory_free_named(ptr: *const anyopaque, secure: i32, name: [*:0]const u8) void; -extern fn ___tracy_emit_memory_free_callstack_named(ptr: *const anyopaque, depth: i32, secure: i32, name: [*:0]const u8) void; extern fn ___tracy_emit_logString(severity: MessageSeverity, color: i32, callstack_depth: i32, size: usize, txt: [*]const u8) void; extern fn ___tracy_emit_logStringL(severity: MessageSeverity, color: i32, callstack_depth: i32, txt: [*:0]const u8) void; -extern fn ___tracy_emit_frame_mark(name: ?[*:0]const u8) void; +extern fn ___tracy_emit_plot_int(name: [*:0]const u8, val: i64) void; +extern fn ___tracy_emit_plot_config(name: [*:0]const u8, format: PlotConfig.Format, mode: PlotConfig.Mode, fill: i32, color: u32) void; extern fn ___tracy_fiber_enter(fiber: [*:0]const u8) void; extern fn ___tracy_fiber_leave() void; -- 2.54.0 From b12c0de096b22b1ce17c73c466b645ed0631e818 Mon Sep 17 00:00:00 2001 From: Matthew Lugg Date: Wed, 27 May 2026 14:43:10 +0100 Subject: [PATCH 2/6] Elf2: move applyTargetRelocs to Symbol.Id This is just a little more efficient since it may avoid some hashmap lookups when applying relocations. --- src/link/Elf2.zig | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig index f833663e78c94c2e41e064c9c0a240929efec32d..3a6f9771d698386d963081992fef46f354b6d2ef 100644 --- a/src/link/Elf2.zig +++ b/src/link/Elf2.zig @@ -1967,17 +1967,6 @@ const Symbol = struct { fn ptr(si: Symbol.Index, elf: *Elf) *Symbol { return &elf.symtab.items[@intFromEnum(si)]; } - - fn applyTargetRelocs(si: Symbol.Index, elf: *Elf) void { - assert(elf.ehdrField(.type) != .REL); - var ri = si.ptr(elf).first_target_reloc; - while (ri != .none) { - const reloc = ri.get(elf); - assert(reloc.target.index(elf) == si); - reloc.apply(elf); - ri = reloc.next; - } - } }; /// A `LocalIndex` is a raw index into the symtab like `Index`, but it guarantees that the @@ -2064,7 +2053,7 @@ const Symbol = struct { // Re-apply relocations targeting this symbol if (elf.ehdrField(.type) != .REL) { - sym_index.applyTargetRelocs(elf); + sym_id.applyTargetRelocs(elf); } // Update GOT entries targeting this symbol @@ -2080,6 +2069,17 @@ const Symbol = struct { } } + fn applyTargetRelocs(sym_id: Symbol.Id, elf: *Elf) void { + assert(elf.ehdrField(.type) != .REL); + var ri = sym_id.index(elf).ptr(elf).first_target_reloc; + while (ri != .none) { + const reloc = ri.get(elf); + assert(reloc.target == sym_id); + reloc.apply(elf); + ri = reloc.next; + } + } + /// Returns `true` if the target of `s` has moved, meaning the symbol's value will change at /// some point due to a call to `flushMoved`. fn hasMoved(s: Symbol.Id, elf: *Elf) bool { @@ -4442,7 +4442,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void { elf.addPltEntry(name, global_ptr.dynsym_index); // ...and therefore, we need to re-apply that symbol's relocations, as // some might be targeting its PLT entry. - global_ptr.symtab_index.applyTargetRelocs(elf); + Symbol.Id.global(name).applyTargetRelocs(elf); } } } @@ -6157,7 +6157,7 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad // specific tracking for PLT relocations---instead just re-apply all relocations // targeting symbols with PLT entries. for (elf.plt.keys()) |sym| { - sym.index(elf).applyTargetRelocs(elf); + sym.applyTargetRelocs(elf); } // We also need to update all of the references from `.plt.sec` to `.got.plt`. // However, if there's also a flush pending for `.got.plt`, don't bother doing -- 2.54.0 From f60fe4dcb667cc638f4f8ea8fb20d11de3440671 Mon Sep 17 00:00:00 2001 From: Matthew Lugg Date: Wed, 27 May 2026 14:45:32 +0100 Subject: [PATCH 3/6] Elf2: immediately clear unnecessary changed_symbol_index entries --- src/link/Elf2.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig index 3a6f9771d698386d963081992fef46f354b6d2ef..b781fe4bc1c070be7d775bf6da3737457cd8d0f1 100644 --- a/src/link/Elf2.zig +++ b/src/link/Elf2.zig @@ -5669,7 +5669,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { }; break :task; } - if (elf.changed_symtab_index.pop()) |kv| { + while (elf.changed_symtab_index.pop()) |kv| { // We only need to do work in relocatables, because in ELF modules (non-relocatables) // our `ElfN.Rela` entries use `.dynsym` indices rather than `.symtab` indices, and // `.dynsym` indices are (at the time of writing) always immutable. -- 2.54.0 From c698e55754748fa9e97fed4fe279c604d3b381cd Mon Sep 17 00:00:00 2001 From: Matthew Lugg Date: Wed, 27 May 2026 16:28:52 +0100 Subject: [PATCH 4/6] Compilation: don't update C inputs on incremental updates ...at least, for now, so that the use case of performing incremental updates to the *Zig* source code works without crashing the linker. This works around https://codeberg.org/ziglang/zig/issues/32081. --- src/Compilation.zig | 20 ++++++++++++++++---- src/link.zig | 3 +++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 180d41f08ce99369294308dc2739d90e8a46b22d..9b187614a76bfc115f244004fb055f9d38eb321a 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -3008,10 +3008,19 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE // For compiling C objects, we rely on the cache hash system to avoid duplicating work. // Add a Job for each C object. - try comp.c_object_work_queue.ensureUnusedCapacity(gpa, comp.c_object_table.count()); - for (comp.c_object_table.keys()) |c_object| { - comp.c_object_work_queue.pushBackAssumeCapacity(c_object); - try comp.appendFileSystemInput(try .fromUnresolved(arena, comp.dirs, &.{c_object.src.src_path})); + if (comp.bin_file != null and comp.bin_file.?.post_prelink) { + assert(comp.config.incremental); + // TODO: this indicates that we are using incremental compilation and this is not the first + // incremental update. The incremental linkers do not (currently?) support updating C inputs + // incrementally. The frontend needs to learn to trigger a full rebuild if a C link input + // changes. For now, to avoid crashing the linker in this case, don't kick off C object + // updates if we've done prelink already. https://codeberg.org/ziglang/zig/issues/32081 + } else { + try comp.c_object_work_queue.ensureUnusedCapacity(gpa, comp.c_object_table.count()); + for (comp.c_object_table.keys()) |c_object| { + comp.c_object_work_queue.pushBackAssumeCapacity(c_object); + try comp.appendFileSystemInput(try .fromUnresolved(arena, comp.dirs, &.{c_object.src.src_path})); + } } for (comp.link_inputs) |input| if (input.path()) |path| { @@ -7595,6 +7604,9 @@ pub fn queuePrelinkTaskMode(comp: *Compilation, path: Cache.Path, must_link: boo /// Only valid to call during `update`. pub fn queuePrelinkTasks(comp: *Compilation, tasks: []const link.PrelinkTask) Io.Cancelable!void { + if (tasks.len > 0) { + if (comp.bin_file) |lf| assert(!lf.post_prelink); + } comp.link_prog_node.increaseEstimatedTotalItems(tasks.len); try comp.link_queue.enqueuePrelink(comp, tasks); } diff --git a/src/link.zig b/src/link.zig index 2c8a4f7aa5ea02dd6fe9047593fc016a0a5a700a..728d2d4f245d83902ef319881b7db128fbf1e85f 100644 --- a/src/link.zig +++ b/src/link.zig @@ -1205,6 +1205,7 @@ pub const File = struct { pub fn loadInput(base: *File, input: Input) anyerror!void { if (base.tag == .lld) return; + assert(!base.post_prelink); switch (base.tag) { inline .elf, .elf2, .wasm => |tag| { dev.check(tag.devFeature()); @@ -1424,6 +1425,8 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void { return; }; + assert(!base.post_prelink); + var timer = comp.startTimer(); defer if (timer.finish(io)) |ns| { comp.mutex.lockUncancelable(io); -- 2.54.0 From a7531ba928938029f2381b8ec5845c2797528b12 Mon Sep 17 00:00:00 2001 From: Matthew Lugg Date: Thu, 28 May 2026 12:10:05 +0100 Subject: [PATCH 5/6] link: deduplicate static archive inputs This has the benefit of preventing redundant work in linker implementations, but it also helps to prevent incomplete linker implementations (currently Elf2) from emitting "multiple definitions of symbol" errors when the same static library is passed on the command line multiple times. --- src/link.zig | 81 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 14 deletions(-) diff --git a/src/link.zig b/src/link.zig index 728d2d4f245d83902ef319881b7db128fbf1e85f..8759d2810e55da1e53094fa429efdbdcc2825912 100644 --- a/src/link.zig +++ b/src/link.zig @@ -1853,6 +1853,9 @@ pub fn resolveInputs( var ld_script_bytes: std.ArrayList(u8) = .empty; defer ld_script_bytes.deinit(gpa); + var archive_dedup: ArchiveDedupMap = .empty; + defer archive_dedup.deinit(gpa); + var failed_libs: std.ArrayList(struct { name: []const u8, strategy: UnresolvedInput.SearchStrategy, @@ -1892,6 +1895,7 @@ pub fn resolveInputs( resolved_inputs, &checked_paths, &ld_script_bytes, + &archive_dedup, lib_directory, name_query, target, @@ -1919,6 +1923,7 @@ pub fn resolveInputs( resolved_inputs, &checked_paths, &ld_script_bytes, + &archive_dedup, lib_directory, name_query, target, @@ -1947,6 +1952,7 @@ pub fn resolveInputs( resolved_inputs, &checked_paths, &ld_script_bytes, + &archive_dedup, lib_directory, name_query, target, @@ -1966,6 +1972,7 @@ pub fn resolveInputs( resolved_inputs, &checked_paths, &ld_script_bytes, + &archive_dedup, lib_directory, name_query, target, @@ -1997,6 +2004,7 @@ pub fn resolveInputs( unresolved_inputs, resolved_inputs, &ld_script_bytes, + &archive_dedup, target, .{ .path = Path.initCwd(an.name), @@ -2015,6 +2023,7 @@ pub fn resolveInputs( unresolved_inputs, resolved_inputs, &ld_script_bytes, + &archive_dedup, target, .{ .path = .{ @@ -2043,6 +2052,7 @@ pub fn resolveInputs( unresolved_inputs, resolved_inputs, &ld_script_bytes, + &archive_dedup, target, pq, color, @@ -2088,6 +2098,8 @@ fn resolveLibInput( checked_paths: *std.ArrayList(u8), /// Allocated via `gpa`. ld_script_bytes: *std.ArrayList(u8), + /// Allocated via `gpa`. + archive_dedup: *ArchiveDedupMap, lib_directory: Directory, name_query: UnresolvedInput.NameQuery, target: *const std.Target, @@ -2095,6 +2107,7 @@ fn resolveLibInput( color: std.zig.Color, ) Allocator.Error!ResolveLibInputResult { try resolved_inputs.ensureUnusedCapacity(gpa, 1); + try archive_dedup.ensureUnusedCapacity(gpa, 1); const lib_name = name_query.name; @@ -2110,7 +2123,7 @@ fn resolveLibInput( else => |e| fatal("unable to search for tbd library '{f}': {s}", .{ test_path, @errorName(e) }), }; errdefer file.close(io); - return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query); + return finishResolveLibInput(io, resolved_inputs, archive_dedup, test_path, file, link_mode, name_query.query); } { @@ -2125,7 +2138,7 @@ fn resolveLibInput( }), }; try checked_paths.print(gpa, "\n {f}", .{test_path}); - switch (try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, target, .{ + switch (try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, archive_dedup, target, .{ .path = test_path, .query = name_query.query, }, link_mode, color)) { @@ -2149,7 +2162,7 @@ fn resolveLibInput( }), }; errdefer file.close(io); - return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query); + return finishResolveLibInput(io, resolved_inputs, archive_dedup, test_path, file, link_mode, name_query.query); } // In the case of MinGW, the main check will be .lib but we also need to @@ -2165,26 +2178,61 @@ fn resolveLibInput( else => |e| fatal("unable to search for static library '{f}': {s}", .{ test_path, @errorName(e) }), }; errdefer file.close(io); - return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query); + return finishResolveLibInput(io, resolved_inputs, archive_dedup, test_path, file, link_mode, name_query.query); } return .no_match; } +/// Deduplicates static archive link inputs based on their path. This is done for efficiency, so +/// that linker implementations do not need to open and scan the archive just to determine that they +/// need not extract any objects. At the time of writing, it also helps avoid "multiple definitions +/// of symbol" errors in incomplete linker implementations. +/// +/// Key is index into `resolved_inputs` of an `Input.archive`. +/// +/// Accessed through `ArchiveDedupAdapter`. +/// +const ArchiveDedupMap = std.array_hash_map.Custom(u32, void, void, true); +/// Adapter for accessing `ArchiveDedupMap` with an effective key type of `Path`. +const ArchiveDedupAdapter = struct { + resolved_inputs: []const Input, + pub fn hash(ctx: ArchiveDedupAdapter, path: Path) u32 { + _ = ctx; + return Path.TableAdapter.hash(.{}, path); + } + pub fn eql(ctx: ArchiveDedupAdapter, a_path: Path, b_input_index: u32, _: usize) bool { + const b_path = ctx.resolved_inputs[b_input_index].archive.path; + return a_path.eql(b_path); + } +}; + fn finishResolveLibInput( + io: Io, resolved_inputs: *std.ArrayList(Input), + archive_dedup: *ArchiveDedupMap, path: Path, file: Io.File, link_mode: std.lang.LinkMode, query: UnresolvedInput.Query, ) ResolveLibInputResult { switch (link_mode) { - .static => resolved_inputs.appendAssumeCapacity(.{ .archive = .{ - .path = path, - .file = file, - .must_link = query.must_link, - .hidden = query.hidden, - } }), + .static => { + const ctx: ArchiveDedupAdapter = .{ .resolved_inputs = resolved_inputs.items }; + const gop = archive_dedup.getOrPutAssumeCapacityAdapted(path, ctx); + if (gop.found_existing) { + // Ignore duplicate archive input + file.close(io); + return .ok; + } + gop.key_ptr.* = @intCast(resolved_inputs.items.len); + resolved_inputs.appendAssumeCapacity(.{ .archive = .{ + .path = path, + .file = file, + .must_link = query.must_link, + .hidden = query.hidden, + } }); + }, .dynamic => resolved_inputs.appendAssumeCapacity(.{ .dso = .{ .path = path, .file = file, @@ -2206,13 +2254,15 @@ fn resolvePathInput( resolved_inputs: *std.ArrayList(Input), /// Allocated via `gpa`. ld_script_bytes: *std.ArrayList(u8), + /// Allocated via `gpa`. + archive_dedup: *ArchiveDedupMap, target: *const std.Target, pq: UnresolvedInput.PathQuery, color: std.zig.Color, ) Allocator.Error!?ResolveLibInputResult { switch (Compilation.classifyFileExt(pq.path.sub_path)) { - .static_library => return try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, target, pq, .static, color), - .shared_library => return try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, target, pq, .dynamic, color), + .static_library => return try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, archive_dedup, target, pq, .static, color), + .shared_library => return try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, archive_dedup, target, pq, .dynamic, color), .object => { var file = pq.path.root_dir.handle.openFile(io, pq.path.sub_path, .{}) catch |err| fatal("failed to open object {f}: {s}", .{ pq.path, @errorName(err) }); @@ -2249,12 +2299,15 @@ fn resolvePathInputLib( resolved_inputs: *std.ArrayList(Input), /// Allocated via `gpa`. ld_script_bytes: *std.ArrayList(u8), + /// Allocated via `gpa`. + archive_dedup: *ArchiveDedupMap, target: *const std.Target, pq: UnresolvedInput.PathQuery, link_mode: std.lang.LinkMode, color: std.zig.Color, ) Allocator.Error!ResolveLibInputResult { try resolved_inputs.ensureUnusedCapacity(gpa, 1); + try archive_dedup.ensureUnusedCapacity(gpa, 1); const test_path: Path = pq.path; // In the case of shared libraries, they might actually be "linker scripts" @@ -2279,7 +2332,7 @@ fn resolvePathInputLib( mem.startsWith(u8, buf, std.elf.ARMAG_THIN)) { // Appears to be an ELF or archive file. - return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query); + return finishResolveLibInput(io, resolved_inputs, archive_dedup, test_path, file, link_mode, pq.query); } const stat = file.stat(io) catch |err| fatal("failed to stat {f}: {t}", .{ test_path, err }); @@ -2349,7 +2402,7 @@ fn resolvePathInputLib( }), }; errdefer file.close(io); - return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query); + return finishResolveLibInput(io, resolved_inputs, archive_dedup, test_path, file, link_mode, pq.query); } pub fn openObject(io: Io, path: Path, must_link: bool, hidden: bool) !Input.Object { -- 2.54.0 From ee13aaeb8ddb8d00d4186c300b616b21da121963 Mon Sep 17 00:00:00 2001 From: Matthew Lugg Date: Thu, 28 May 2026 12:14:19 +0100 Subject: [PATCH 6/6] Elf2: prevent bogus relocations into debug sections If a `.debug_*` section---or any non-alloc section for that matter!---references a symbol which is not resolved, we must not emit a dynamic relocation for it. Since a non-alloc section's base virtual address is 0, this could potentially cause crashes in rtld. I'm not sure what the correct behavior is here, but for now, this prevents a possible crash. --- src/link/Elf2.zig | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig index b781fe4bc1c070be7d775bf6da3737457cd8d0f1..e05e9796c4e6b2c059427fa17003cd185cbb04f5 100644 --- a/src/link/Elf2.zig +++ b/src/link/Elf2.zig @@ -128,7 +128,7 @@ section_by_name: std.array_hash_map.Auto(String(.shstrtab), void), changed_symtab_index: std.array_hash_map.Auto(String(.strtab), void), /// Counts how many relocations are currently in `.rela.dyn` which would require a `DT_TEXTREL` /// entry in the `.dynamic` section. This allows adding `DT_TEXTREL` to the output `.dynamic` -/// section in `flush` only when it is actually necessary. See also `nodeRequiresTextrel`. +/// section in `flush` only when it is actually necessary. See also `nodeWantsDsoRelocation`. textrel_count: u32, const_prog_node: std.Progress.Node, @@ -1128,8 +1128,10 @@ const SymbolReloc = struct { } if (reloc.rela_index.unwrap()) |rela_index| { reloc.relaSection(elf).relaDeleteOne(elf, rela_index); - if (elf.nodeRequiresTextrel(reloc.node)) { - elf.textrel_count -= 1; + switch (elf.nodeWantsDsoRelocation(reloc.node)) { + .no => unreachable, // there *was* a dynamic relocation! + .yes => {}, + .yes_textrel => elf.textrel_count -= 1, } } if (reloc.type.dependsOnTlsSize()) { @@ -1672,8 +1674,10 @@ fn setGlobalSymbolValue( assert(reloc.target == Symbol.Id.global(global_name)); if (reloc.rela_index.unwrap()) |rela_index| { reloc.relaSection(elf).relaDeleteOne(elf, rela_index); - if (elf.nodeRequiresTextrel(reloc.node)) { - elf.textrel_count -= 1; + switch (elf.nodeWantsDsoRelocation(reloc.node)) { + .no => unreachable, // there *was* a dynamic relocation! + .yes => {}, + .yes_textrel => elf.textrel_count -= 1, } reloc.rela_index = .none; } @@ -5108,8 +5112,10 @@ fn addSymbolRelocAssumeCapacity( } else elf.globalByName(name).?.dynsym_index, }; - if (elf.nodeRequiresTextrel(node)) { - elf.textrel_count += 1; + switch (elf.nodeWantsDsoRelocation(node)) { + .no => break :r .none, + .yes => {}, + .yes_textrel => elf.textrel_count += 1, } // It currently looks like we need a runtime relocation for this. @@ -5383,13 +5389,18 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void { }; } -/// Returns whether a `DT_TEXTREL` dynamic entry is needed to have a runtime relocation in `node`. -fn nodeRequiresTextrel(elf: *Elf, node: MappedFile.Node.Index) bool { +/// If `node` cannot contain runtime relocations, returns `.no`. +/// +/// If `node` can contain runtime relocations, `returns `.yes_textrel` if such a relocation requires +/// the presence of a `DT_TEXTREL` dynamic entry, or `.yes` otherwise. +fn nodeWantsDsoRelocation(elf: *Elf, node: MappedFile.Node.Index) enum { yes, yes_textrel, no } { const shndx = elf.getNodeShndx(node); const shf: std.elf.SHF = switch (elf.shdrPtr(shndx)) { inline else => |shdr| elf.targetLoad(&shdr.flags).shf, }; - return shf.ALLOC and !shf.WRITE; + if (!shf.ALLOC) return .no; + if (!shf.WRITE) return .yes_textrel; + return .yes; } pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { -- 2.54.0