From a7c05c06bef1570546cae4c45a76027819c7fa09 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 17 Apr 2022 04:06:51 -0700 Subject: [PATCH] stage2: expose progress bar API to linker backends This gives us insight as to what is happening when we are waiting for things such as LLVM emit object and LLD linking. --- src/Compilation.zig | 30 ++++++++++++++++-------------- src/codegen/llvm.zig | 7 ++++++- src/link.zig | 44 ++++++++++++++++++++++---------------------- src/link/C.zig | 10 +++++++--- src/link/Coff.zig | 25 +++++++++++++++++-------- src/link/Elf.zig | 25 +++++++++++++++++-------- src/link/MachO.zig | 23 ++++++++++++++--------- src/link/NvPtx.zig | 8 ++++---- src/link/Plan9.zig | 10 +++++++--- src/link/SpirV.zig | 10 +++++++--- src/link/Wasm.zig | 25 +++++++++++++++++-------- 11 files changed, 134 insertions(+), 83 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 6c486de36a..f0e490c67d 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2084,7 +2084,13 @@ pub fn update(comp: *Compilation) !void { } } - try comp.performAllTheWork(); + // If the terminal is dumb, we dont want to show the user all the output. + var progress: std.Progress = .{ .dont_print_on_dumb = true }; + const main_progress_node = progress.start("", 0); + defer main_progress_node.end(); + if (comp.color == .off) progress.terminal = null; + + try comp.performAllTheWork(main_progress_node); if (!use_stage1) { if (comp.bin_file.options.module) |module| { @@ -2158,9 +2164,9 @@ pub fn update(comp: *Compilation) !void { .path = dir_path, }; - try comp.flush(); + try comp.flush(main_progress_node); } else { - try comp.flush(); + try comp.flush(main_progress_node); } // Failure here only means an unnecessary cache miss. @@ -2171,7 +2177,7 @@ pub fn update(comp: *Compilation) !void { assert(comp.bin_file.lock == null); comp.bin_file.lock = man.toOwnedLock(); } else { - try comp.flush(); + try comp.flush(main_progress_node); } // Unload all source files to save memory. @@ -2188,8 +2194,8 @@ pub fn update(comp: *Compilation) !void { } } -fn flush(comp: *Compilation) !void { - try comp.bin_file.flush(comp); // This is needed before reading the error flags. +fn flush(comp: *Compilation, prog_node: *std.Progress.Node) !void { + try comp.bin_file.flush(comp, prog_node); // This is needed before reading the error flags. comp.link_error_flags = comp.bin_file.errorFlags(); const use_stage1 = build_options.omit_stage2 or @@ -2590,14 +2596,10 @@ pub fn getCompileLogOutput(self: *Compilation) []const u8 { return module.compile_log_text.items; } -pub fn performAllTheWork(comp: *Compilation) error{ TimerUnsupported, OutOfMemory }!void { - // If the terminal is dumb, we dont want to show the user all the - // output. - var progress: std.Progress = .{ .dont_print_on_dumb = true }; - var main_progress_node = progress.start("", 0); - defer main_progress_node.end(); - if (comp.color == .off) progress.terminal = null; - +pub fn performAllTheWork( + comp: *Compilation, + main_progress_node: *std.Progress.Node, +) error{ TimerUnsupported, OutOfMemory }!void { // Here we queue up all the AstGen tasks first, followed by C object compilation. // We wait until the AstGen tasks are all completed before proceeding to the // (at least for now) single-threaded main work queue. However, C object compilation diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 364cccf335..cdb9addcff 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -469,7 +469,12 @@ pub const Object = struct { _ = builder.buildRet(is_lt); } - pub fn flushModule(self: *Object, comp: *Compilation) !void { + pub fn flushModule(self: *Object, comp: *Compilation, prog_node: *std.Progress.Node) !void { + var sub_prog_node = prog_node.start("LLVM Emit Object", 0); + sub_prog_node.activate(); + sub_prog_node.context.refresh(); + defer sub_prog_node.end(); + try self.genErrorNameTable(comp); try self.genCmpLtErrorsLenFunction(comp); diff --git a/src/link.zig b/src/link.zig index 2d7e577b70..c449a37ee6 100644 --- a/src/link.zig +++ b/src/link.zig @@ -573,7 +573,7 @@ pub const File = struct { /// Commit pending changes and write headers. Takes into account final output mode /// and `use_lld`, not only `effectiveOutputMode`. - pub fn flush(base: *File, comp: *Compilation) !void { + pub fn flush(base: *File, comp: *Compilation, prog_node: *std.Progress.Node) !void { if (comp.clang_preprocessor_mode == .yes) { const emit = base.options.emit orelse return; // -fno-emit-bin // TODO: avoid extra link step when it's just 1 object file (the `zig cc -c` case) @@ -591,32 +591,32 @@ pub const File = struct { const use_lld = build_options.have_llvm and base.options.use_lld; if (use_lld and base.options.output_mode == .Lib and base.options.link_mode == .Static) { - return base.linkAsArchive(comp); + return base.linkAsArchive(comp, prog_node); } switch (base.tag) { - .coff => return @fieldParentPtr(Coff, "base", base).flush(comp), - .elf => return @fieldParentPtr(Elf, "base", base).flush(comp), - .macho => return @fieldParentPtr(MachO, "base", base).flush(comp), - .c => return @fieldParentPtr(C, "base", base).flush(comp), - .wasm => return @fieldParentPtr(Wasm, "base", base).flush(comp), - .spirv => return @fieldParentPtr(SpirV, "base", base).flush(comp), - .plan9 => return @fieldParentPtr(Plan9, "base", base).flush(comp), - .nvptx => return @fieldParentPtr(NvPtx, "base", base).flush(comp), + .coff => return @fieldParentPtr(Coff, "base", base).flush(comp, prog_node), + .elf => return @fieldParentPtr(Elf, "base", base).flush(comp, prog_node), + .macho => return @fieldParentPtr(MachO, "base", base).flush(comp, prog_node), + .c => return @fieldParentPtr(C, "base", base).flush(comp, prog_node), + .wasm => return @fieldParentPtr(Wasm, "base", base).flush(comp, prog_node), + .spirv => return @fieldParentPtr(SpirV, "base", base).flush(comp, prog_node), + .plan9 => return @fieldParentPtr(Plan9, "base", base).flush(comp, prog_node), + .nvptx => return @fieldParentPtr(NvPtx, "base", base).flush(comp, prog_node), } } /// Commit pending changes and write headers. Works based on `effectiveOutputMode` /// rather than final output mode. - pub fn flushModule(base: *File, comp: *Compilation) !void { + pub fn flushModule(base: *File, comp: *Compilation, prog_node: *std.Progress.Node) !void { switch (base.tag) { - .coff => return @fieldParentPtr(Coff, "base", base).flushModule(comp), - .elf => return @fieldParentPtr(Elf, "base", base).flushModule(comp), - .macho => return @fieldParentPtr(MachO, "base", base).flushModule(comp), - .c => return @fieldParentPtr(C, "base", base).flushModule(comp), - .wasm => return @fieldParentPtr(Wasm, "base", base).flushModule(comp), - .spirv => return @fieldParentPtr(SpirV, "base", base).flushModule(comp), - .plan9 => return @fieldParentPtr(Plan9, "base", base).flushModule(comp), - .nvptx => return @fieldParentPtr(NvPtx, "base", base).flushModule(comp), + .coff => return @fieldParentPtr(Coff, "base", base).flushModule(comp, prog_node), + .elf => return @fieldParentPtr(Elf, "base", base).flushModule(comp, prog_node), + .macho => return @fieldParentPtr(MachO, "base", base).flushModule(comp, prog_node), + .c => return @fieldParentPtr(C, "base", base).flushModule(comp, prog_node), + .wasm => return @fieldParentPtr(Wasm, "base", base).flushModule(comp, prog_node), + .spirv => return @fieldParentPtr(SpirV, "base", base).flushModule(comp, prog_node), + .plan9 => return @fieldParentPtr(Plan9, "base", base).flushModule(comp, prog_node), + .nvptx => return @fieldParentPtr(NvPtx, "base", base).flushModule(comp, prog_node), } } @@ -754,7 +754,7 @@ pub const File = struct { } } - pub fn linkAsArchive(base: *File, comp: *Compilation) !void { + pub fn linkAsArchive(base: *File, comp: *Compilation, prog_node: *std.Progress.Node) !void { const tracy = trace(@src()); defer tracy.end(); @@ -787,9 +787,9 @@ pub const File = struct { } } if (base.options.object_format == .macho) { - try base.cast(MachO).?.flushObject(comp); + try base.cast(MachO).?.flushObject(comp, prog_node); } else { - try base.flushModule(comp); + try base.flushModule(comp, prog_node); } break :blk try fs.path.join(arena, &.{ fs.path.dirname(full_out_path_z).?, base.intermediary_basename.?, diff --git a/src/link/C.zig b/src/link/C.zig index 229990fc8e..63aa2b6030 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -235,14 +235,18 @@ pub fn updateDeclLineNumber(self: *C, module: *Module, decl: *Module.Decl) !void _ = decl; } -pub fn flush(self: *C, comp: *Compilation) !void { - return self.flushModule(comp); +pub fn flush(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) !void { + return self.flushModule(comp, prog_node); } -pub fn flushModule(self: *C, comp: *Compilation) !void { +pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) !void { const tracy = trace(@src()); defer tracy.end(); + var sub_prog_node = prog_node.start("Flush Module", 0); + sub_prog_node.activate(); + defer sub_prog_node.end(); + const gpa = comp.gpa; const module = self.base.options.module.?; diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 3293cf2dfc..a91f48dfbd 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -829,36 +829,40 @@ pub fn updateDeclExports( } } -pub fn flush(self: *Coff, comp: *Compilation) !void { +pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !void { if (self.base.options.emit == null) { if (build_options.have_llvm) { if (self.llvm_object) |llvm_object| { - return try llvm_object.flushModule(comp); + return try llvm_object.flushModule(comp, prog_node); } } return; } if (build_options.have_llvm and self.base.options.use_lld) { - return self.linkWithLLD(comp); + return self.linkWithLLD(comp, prog_node); } else { switch (self.base.options.effectiveOutputMode()) { .Exe, .Obj => {}, .Lib => return error.TODOImplementWritingLibFiles, } - return self.flushModule(comp); + return self.flushModule(comp, prog_node); } } -pub fn flushModule(self: *Coff, comp: *Compilation) !void { +pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !void { const tracy = trace(@src()); defer tracy.end(); if (build_options.have_llvm) { if (self.llvm_object) |llvm_object| { - return try llvm_object.flushModule(comp); + return try llvm_object.flushModule(comp, prog_node); } } + var sub_prog_node = prog_node.start("COFF Flush", 0); + sub_prog_node.activate(); + defer sub_prog_node.end(); + if (self.text_section_size_dirty) { // Write the new raw size in the .text header var buf: [4]u8 = undefined; @@ -892,7 +896,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation) !void { } } -fn linkWithLLD(self: *Coff, comp: *Compilation) !void { +fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !void { const tracy = trace(@src()); defer tracy.end(); @@ -924,7 +928,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { } } - try self.flushModule(comp); + try self.flushModule(comp, prog_node); if (fs.path.dirname(full_out_path)) |dirname| { break :blk try fs.path.join(arena, &.{ dirname, self.base.intermediary_basename.? }); @@ -933,6 +937,11 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { } } else null; + var sub_prog_node = prog_node.start("LLD Link", 0); + sub_prog_node.activate(); + sub_prog_node.context.refresh(); + defer sub_prog_node.end(); + const is_lib = self.base.options.output_mode == .Lib; const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib; const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe; diff --git a/src/link/Elf.zig b/src/link/Elf.zig index e5e65011cd..a58321c0ec 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -929,35 +929,39 @@ pub fn populateMissingMetadata(self: *Elf) !void { } } -pub fn flush(self: *Elf, comp: *Compilation) !void { +pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void { if (self.base.options.emit == null) { if (build_options.have_llvm) { if (self.llvm_object) |llvm_object| { - return try llvm_object.flushModule(comp); + return try llvm_object.flushModule(comp, prog_node); } } return; } const use_lld = build_options.have_llvm and self.base.options.use_lld; if (use_lld) { - return self.linkWithLLD(comp); + return self.linkWithLLD(comp, prog_node); } switch (self.base.options.output_mode) { - .Exe, .Obj => return self.flushModule(comp), + .Exe, .Obj => return self.flushModule(comp, prog_node), .Lib => return error.TODOImplementWritingLibFiles, } } -pub fn flushModule(self: *Elf, comp: *Compilation) !void { +pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void { const tracy = trace(@src()); defer tracy.end(); if (build_options.have_llvm) { if (self.llvm_object) |llvm_object| { - return try llvm_object.flushModule(comp); + return try llvm_object.flushModule(comp, prog_node); } } + var sub_prog_node = prog_node.start("ELF Flush", 0); + sub_prog_node.activate(); + defer sub_prog_node.end(); + // TODO This linker code currently assumes there is only 1 compilation unit and it // corresponds to the Zig source code. const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; @@ -1204,7 +1208,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void { assert(!self.debug_strtab_dirty); } -fn linkWithLLD(self: *Elf, comp: *Compilation) !void { +fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void { const tracy = trace(@src()); defer tracy.end(); @@ -1236,7 +1240,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { } } - try self.flushModule(comp); + try self.flushModule(comp, prog_node); if (fs.path.dirname(full_out_path)) |dirname| { break :blk try fs.path.join(arena, &.{ dirname, self.base.intermediary_basename.? }); @@ -1245,6 +1249,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { } } else null; + var sub_prog_node = prog_node.start("LLD Link", 0); + sub_prog_node.activate(); + sub_prog_node.context.refresh(); + defer sub_prog_node.end(); + const is_obj = self.base.options.output_mode == .Obj; const is_lib = self.base.options.output_mode == .Lib; const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib; diff --git a/src/link/MachO.zig b/src/link/MachO.zig index a7437ed576..e604029382 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -419,33 +419,34 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO { return self; } -pub fn flush(self: *MachO, comp: *Compilation) !void { +pub fn flush(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) !void { if (self.base.options.emit == null) { if (build_options.have_llvm) { if (self.llvm_object) |llvm_object| { - try llvm_object.flushModule(comp); + try llvm_object.flushModule(comp, prog_node); } } return; } + if (self.base.options.output_mode == .Lib and self.base.options.link_mode == .Static) { if (build_options.have_llvm) { - return self.base.linkAsArchive(comp); + return self.base.linkAsArchive(comp, prog_node); } else { log.err("TODO: non-LLVM archiver for MachO object files", .{}); return error.TODOImplementWritingStaticLibFiles; } } - try self.flushModule(comp); + try self.flushModule(comp, prog_node); } -pub fn flushModule(self: *MachO, comp: *Compilation) !void { +pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) !void { const tracy = trace(@src()); defer tracy.end(); const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1; if (!use_stage1 and self.base.options.output_mode == .Obj) - return self.flushObject(comp); + return self.flushObject(comp, prog_node); var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator); defer arena_allocator.deinit(); @@ -482,7 +483,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { const obj_basename = self.base.intermediary_basename orelse break :blk null; - try self.flushObject(comp); + try self.flushObject(comp, prog_node); if (fs.path.dirname(full_out_path)) |dirname| { break :blk try fs.path.join(arena, &.{ dirname, obj_basename }); @@ -491,6 +492,10 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { } } else null; + var sub_prog_node = prog_node.start("MachO Flush", 0); + sub_prog_node.activate(); + defer sub_prog_node.end(); + const is_lib = self.base.options.output_mode == .Lib; const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib; const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe; @@ -1111,13 +1116,13 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { self.cold_start = false; } -pub fn flushObject(self: *MachO, comp: *Compilation) !void { +pub fn flushObject(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) !void { const tracy = trace(@src()); defer tracy.end(); if (build_options.have_llvm) if (self.llvm_object) |llvm_object| - return llvm_object.flushModule(comp); + return llvm_object.flushModule(comp, prog_node); return error.TODOImplementWritingObjFiles; } diff --git a/src/link/NvPtx.zig b/src/link/NvPtx.zig index 5d0f578d1d..b518dc3f68 100644 --- a/src/link/NvPtx.zig +++ b/src/link/NvPtx.zig @@ -97,11 +97,11 @@ pub fn freeDecl(self: *NvPtx, decl: *Module.Decl) void { return self.llvm_object.freeDecl(decl); } -pub fn flush(self: *NvPtx, comp: *Compilation) !void { - return self.flushModule(comp); +pub fn flush(self: *NvPtx, comp: *Compilation, prog_node: *std.Progress.Node) !void { + return self.flushModule(comp, prog_node); } -pub fn flushModule(self: *NvPtx, comp: *Compilation) !void { +pub fn flushModule(self: *NvPtx, comp: *Compilation, prog_node: *std.Progress.Node) !void { if (!build_options.have_llvm) return; if (build_options.skip_non_native) { @panic("Attempted to compile for architecture that was disabled by build configuration"); @@ -117,5 +117,5 @@ pub fn flushModule(self: *NvPtx, comp: *Compilation) !void { }; hack_comp.bin_file.options.emit = null; } - return try self.llvm_object.flushModule(hack_comp); + return try self.llvm_object.flushModule(hack_comp, prog_node); } diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index 3269cb67d4..5d740dd2b9 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -351,7 +351,7 @@ fn updateFinish(self: *Plan9, decl: *Module.Decl) !void { } } -pub fn flush(self: *Plan9, comp: *Compilation) !void { +pub fn flush(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) !void { assert(!self.base.options.use_lld); switch (self.base.options.effectiveOutputMode()) { @@ -360,7 +360,7 @@ pub fn flush(self: *Plan9, comp: *Compilation) !void { .Obj => return error.TODOImplementPlan9Objs, .Lib => return error.TODOImplementWritingLibFiles, } - return self.flushModule(comp); + return self.flushModule(comp, prog_node); } pub fn changeLine(l: *std.ArrayList(u8), delta_line: i32) !void { @@ -387,7 +387,7 @@ fn declCount(self: *Plan9) usize { return self.data_decl_table.count() + fn_decl_count; } -pub fn flushModule(self: *Plan9, comp: *Compilation) !void { +pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) !void { if (build_options.skip_non_native and builtin.object_format != .plan9) { @panic("Attempted to compile for object format that was disabled by build configuration"); } @@ -396,6 +396,10 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void { const tracy = trace(@src()); defer tracy.end(); + var sub_prog_node = prog_node.start("Flush Module", 0); + sub_prog_node.activate(); + defer sub_prog_node.end(); + log.debug("flushModule", .{}); defer assert(self.hdr.entry != 0x0); diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index 19cb1373ef..e4d032539f 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -174,15 +174,15 @@ pub fn freeDecl(self: *SpirV, decl: *Module.Decl) void { self.decl_table.swapRemoveAt(index); } -pub fn flush(self: *SpirV, comp: *Compilation) !void { +pub fn flush(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.Node) !void { if (build_options.have_llvm and self.base.options.use_lld) { return error.LLD_LinkingIsTODO_ForSpirV; // TODO: LLD Doesn't support SpirV at all. } else { - return self.flushModule(comp); + return self.flushModule(comp, prog_node); } } -pub fn flushModule(self: *SpirV, comp: *Compilation) !void { +pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.Node) !void { if (build_options.skip_non_native) { @panic("Attempted to compile for architecture that was disabled by build configuration"); } @@ -190,6 +190,10 @@ pub fn flushModule(self: *SpirV, comp: *Compilation) !void { const tracy = trace(@src()); defer tracy.end(); + var sub_prog_node = prog_node.start("Flush Module", 0); + sub_prog_node.activate(); + defer sub_prog_node.end(); + const module = self.base.options.module.?; const target = comp.getTarget(); diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 961e382112..1ed733774f 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -1477,32 +1477,36 @@ fn resetState(self: *Wasm) void { self.code_section_index = null; } -pub fn flush(self: *Wasm, comp: *Compilation) !void { +pub fn flush(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !void { if (self.base.options.emit == null) { if (build_options.have_llvm) { if (self.llvm_object) |llvm_object| { - return try llvm_object.flushModule(comp); + return try llvm_object.flushModule(comp, prog_node); } } return; } if (build_options.have_llvm and self.base.options.use_lld) { - return self.linkWithLLD(comp); + return self.linkWithLLD(comp, prog_node); } else { - return self.flushModule(comp); + return self.flushModule(comp, prog_node); } } -pub fn flushModule(self: *Wasm, comp: *Compilation) !void { +pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !void { const tracy = trace(@src()); defer tracy.end(); if (build_options.have_llvm) { if (self.llvm_object) |llvm_object| { - return try llvm_object.flushModule(comp); + return try llvm_object.flushModule(comp, prog_node); } } + var sub_prog_node = prog_node.start("WASM Flush", 0); + sub_prog_node.activate(); + defer sub_prog_node.end(); + // ensure the error names table is populated when an error name is referenced try self.populateErrorNameTable(); @@ -2028,7 +2032,7 @@ fn emitImport(self: *Wasm, writer: anytype, import: types.Import) !void { } } -fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { +fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !void { const tracy = trace(@src()); defer tracy.end(); @@ -2060,7 +2064,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { } } - try self.flushModule(comp); + try self.flushModule(comp, prog_node); if (fs.path.dirname(full_out_path)) |dirname| { break :blk try fs.path.join(arena, &.{ dirname, self.base.intermediary_basename.? }); @@ -2069,6 +2073,11 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { } } else null; + var sub_prog_node = prog_node.start("LLD Link", 0); + sub_prog_node.activate(); + sub_prog_node.context.refresh(); + defer sub_prog_node.end(); + const is_obj = self.base.options.output_mode == .Obj; const compiler_rt_path: ?[]const u8 = if (self.base.options.include_compiler_rt and !is_obj)