| ... | ... | @@ -101,7 +101,15 @@ link_error_flags: link.File.ErrorFlags = .{}, |
| 101 | 101 | link_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{}, |
| 102 | 102 | lld_errors: std.ArrayListUnmanaged(LldError) = .{}, |
| 103 | 103 | |
| 104 | | work_queue: std.fifo.LinearFifo(Job, .Dynamic), |
| 104 | work_queues: [ |
| 105 | len: { |
| 106 | var len: usize = 0; |
| 107 | for (std.enums.values(Job.Tag)) |tag| { |
| 108 | len = @max(Job.stage(tag) + 1, len); |
| 109 | } |
| 110 | break :len len; |
| 111 | } |
| 112 | ]std.fifo.LinearFifo(Job, .Dynamic), |
| 105 | 113 | |
| 106 | 114 | codegen_work: if (InternPool.single_threaded) void else struct { |
| 107 | 115 | mutex: std.Thread.Mutex, |
| ... | ... | @@ -370,6 +378,20 @@ const Job = union(enum) { |
| 370 | 378 | |
| 371 | 379 | /// The value is the index into `system_libs`. |
| 372 | 380 | windows_import_lib: usize, |
| 381 | |
| 382 | const Tag = @typeInfo(Job).Union.tag_type.?; |
| 383 | fn stage(tag: Tag) usize { |
| 384 | return switch (tag) { |
| 385 | // Prioritize functions so that codegen can get to work on them on a |
| 386 | // separate thread, while Sema goes back to its own work. |
| 387 | .resolve_type_fully, .analyze_func, .codegen_func => 0, |
| 388 | else => 1, |
| 389 | }; |
| 390 | } |
| 391 | comptime { |
| 392 | // Job dependencies |
| 393 | assert(stage(.resolve_type_fully) <= stage(.codegen_func)); |
| 394 | } |
| 373 | 395 | }; |
| 374 | 396 | |
| 375 | 397 | const CodegenJob = union(enum) { |
| ... | ... | @@ -1452,7 +1474,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1452 | 1474 | .emit_asm = options.emit_asm, |
| 1453 | 1475 | .emit_llvm_ir = options.emit_llvm_ir, |
| 1454 | 1476 | .emit_llvm_bc = options.emit_llvm_bc, |
| 1455 | | .work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa), |
| 1477 | .work_queues = .{std.fifo.LinearFifo(Job, .Dynamic).init(gpa)} ** @typeInfo(std.meta.FieldType(Compilation, .work_queues)).Array.len, |
| 1456 | 1478 | .codegen_work = if (InternPool.single_threaded) {} else .{ |
| 1457 | 1479 | .mutex = .{}, |
| 1458 | 1480 | .cond = .{}, |
| ... | ... | @@ -1760,12 +1782,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1760 | 1782 | if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable; |
| 1761 | 1783 | |
| 1762 | 1784 | if (glibc.needsCrtiCrtn(target)) { |
| 1763 | | try comp.work_queue.write(&[_]Job{ |
| 1785 | try comp.queueJobs(&[_]Job{ |
| 1764 | 1786 | .{ .glibc_crt_file = .crti_o }, |
| 1765 | 1787 | .{ .glibc_crt_file = .crtn_o }, |
| 1766 | 1788 | }); |
| 1767 | 1789 | } |
| 1768 | | try comp.work_queue.write(&[_]Job{ |
| 1790 | try comp.queueJobs(&[_]Job{ |
| 1769 | 1791 | .{ .glibc_crt_file = .scrt1_o }, |
| 1770 | 1792 | .{ .glibc_crt_file = .libc_nonshared_a }, |
| 1771 | 1793 | .{ .glibc_shared_objects = {} }, |
| ... | ... | @@ -1774,14 +1796,13 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1774 | 1796 | if (comp.wantBuildMuslFromSource()) { |
| 1775 | 1797 | if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable; |
| 1776 | 1798 | |
| 1777 | | try comp.work_queue.ensureUnusedCapacity(6); |
| 1778 | 1799 | if (musl.needsCrtiCrtn(target)) { |
| 1779 | | comp.work_queue.writeAssumeCapacity(&[_]Job{ |
| 1800 | try comp.queueJobs(&[_]Job{ |
| 1780 | 1801 | .{ .musl_crt_file = .crti_o }, |
| 1781 | 1802 | .{ .musl_crt_file = .crtn_o }, |
| 1782 | 1803 | }); |
| 1783 | 1804 | } |
| 1784 | | comp.work_queue.writeAssumeCapacity(&[_]Job{ |
| 1805 | try comp.queueJobs(&[_]Job{ |
| 1785 | 1806 | .{ .musl_crt_file = .crt1_o }, |
| 1786 | 1807 | .{ .musl_crt_file = .scrt1_o }, |
| 1787 | 1808 | .{ .musl_crt_file = .rcrt1_o }, |
| ... | ... | @@ -1795,15 +1816,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1795 | 1816 | if (comp.wantBuildWasiLibcFromSource()) { |
| 1796 | 1817 | if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable; |
| 1797 | 1818 | |
| 1798 | | // worst-case we need all components |
| 1799 | | try comp.work_queue.ensureUnusedCapacity(comp.wasi_emulated_libs.len + 2); |
| 1800 | | |
| 1801 | 1819 | for (comp.wasi_emulated_libs) |crt_file| { |
| 1802 | | comp.work_queue.writeItemAssumeCapacity(.{ |
| 1820 | try comp.queueJob(.{ |
| 1803 | 1821 | .wasi_libc_crt_file = crt_file, |
| 1804 | 1822 | }); |
| 1805 | 1823 | } |
| 1806 | | comp.work_queue.writeAssumeCapacity(&[_]Job{ |
| 1824 | try comp.queueJobs(&[_]Job{ |
| 1807 | 1825 | .{ .wasi_libc_crt_file = wasi_libc.execModelCrtFile(comp.config.wasi_exec_model) }, |
| 1808 | 1826 | .{ .wasi_libc_crt_file = .libc_a }, |
| 1809 | 1827 | }); |
| ... | ... | @@ -1813,9 +1831,10 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1813 | 1831 | if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable; |
| 1814 | 1832 | |
| 1815 | 1833 | const crt_job: Job = .{ .mingw_crt_file = if (is_dyn_lib) .dllcrt2_o else .crt2_o }; |
| 1816 | | try comp.work_queue.ensureUnusedCapacity(2); |
| 1817 | | comp.work_queue.writeItemAssumeCapacity(.{ .mingw_crt_file = .mingw32_lib }); |
| 1818 | | comp.work_queue.writeItemAssumeCapacity(crt_job); |
| 1834 | try comp.queueJobs(&.{ |
| 1835 | .{ .mingw_crt_file = .mingw32_lib }, |
| 1836 | crt_job, |
| 1837 | }); |
| 1819 | 1838 | |
| 1820 | 1839 | // When linking mingw-w64 there are some import libs we always need. |
| 1821 | 1840 | for (mingw.always_link_libs) |name| { |
| ... | ... | @@ -1829,20 +1848,19 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1829 | 1848 | // Generate Windows import libs. |
| 1830 | 1849 | if (target.os.tag == .windows) { |
| 1831 | 1850 | const count = comp.system_libs.count(); |
| 1832 | | try comp.work_queue.ensureUnusedCapacity(count); |
| 1833 | 1851 | for (0..count) |i| { |
| 1834 | | comp.work_queue.writeItemAssumeCapacity(.{ .windows_import_lib = i }); |
| 1852 | try comp.queueJob(.{ .windows_import_lib = i }); |
| 1835 | 1853 | } |
| 1836 | 1854 | } |
| 1837 | 1855 | if (comp.wantBuildLibUnwindFromSource()) { |
| 1838 | | try comp.work_queue.writeItem(.{ .libunwind = {} }); |
| 1856 | try comp.queueJob(.{ .libunwind = {} }); |
| 1839 | 1857 | } |
| 1840 | 1858 | if (build_options.have_llvm and is_exe_or_dyn_lib and comp.config.link_libcpp) { |
| 1841 | | try comp.work_queue.writeItem(.libcxx); |
| 1842 | | try comp.work_queue.writeItem(.libcxxabi); |
| 1859 | try comp.queueJob(.libcxx); |
| 1860 | try comp.queueJob(.libcxxabi); |
| 1843 | 1861 | } |
| 1844 | 1862 | if (build_options.have_llvm and comp.config.any_sanitize_thread) { |
| 1845 | | try comp.work_queue.writeItem(.libtsan); |
| 1863 | try comp.queueJob(.libtsan); |
| 1846 | 1864 | } |
| 1847 | 1865 | |
| 1848 | 1866 | if (target.isMinGW() and comp.config.any_non_single_threaded) { |
| ... | ... | @@ -1872,7 +1890,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1872 | 1890 | if (!comp.skip_linker_dependencies and is_exe_or_dyn_lib and |
| 1873 | 1891 | !comp.config.link_libc and capable_of_building_zig_libc) |
| 1874 | 1892 | { |
| 1875 | | try comp.work_queue.writeItem(.{ .zig_libc = {} }); |
| 1893 | try comp.queueJob(.{ .zig_libc = {} }); |
| 1876 | 1894 | } |
| 1877 | 1895 | } |
| 1878 | 1896 | |
| ... | ... | @@ -1883,7 +1901,7 @@ pub fn destroy(comp: *Compilation) void { |
| 1883 | 1901 | if (comp.bin_file) |lf| lf.destroy(); |
| 1884 | 1902 | if (comp.module) |zcu| zcu.deinit(); |
| 1885 | 1903 | comp.cache_use.deinit(); |
| 1886 | | comp.work_queue.deinit(); |
| 1904 | for (comp.work_queues) |work_queue| work_queue.deinit(); |
| 1887 | 1905 | if (!InternPool.single_threaded) comp.codegen_work.queue.deinit(); |
| 1888 | 1906 | comp.c_object_work_queue.deinit(); |
| 1889 | 1907 | if (!build_options.only_core_functionality) { |
| ... | ... | @@ -2199,13 +2217,13 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { |
| 2199 | 2217 | } |
| 2200 | 2218 | } |
| 2201 | 2219 | |
| 2202 | | try comp.work_queue.writeItem(.{ .analyze_mod = std_mod }); |
| 2220 | try comp.queueJob(.{ .analyze_mod = std_mod }); |
| 2203 | 2221 | if (comp.config.is_test) { |
| 2204 | | try comp.work_queue.writeItem(.{ .analyze_mod = zcu.main_mod }); |
| 2222 | try comp.queueJob(.{ .analyze_mod = zcu.main_mod }); |
| 2205 | 2223 | } |
| 2206 | 2224 | |
| 2207 | 2225 | if (zcu.root_mod.deps.get("compiler_rt")) |compiler_rt_mod| { |
| 2208 | | try comp.work_queue.writeItem(.{ .analyze_mod = compiler_rt_mod }); |
| 2226 | try comp.queueJob(.{ .analyze_mod = compiler_rt_mod }); |
| 2209 | 2227 | } |
| 2210 | 2228 | } |
| 2211 | 2229 | |
| ... | ... | @@ -3095,6 +3113,39 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 3095 | 3113 | for (zcu.failed_embed_files.values()) |error_msg| { |
| 3096 | 3114 | try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references); |
| 3097 | 3115 | } |
| 3116 | { |
| 3117 | const SortOrder = struct { |
| 3118 | zcu: *Zcu, |
| 3119 | err: *?Error, |
| 3120 | |
| 3121 | const Error = @typeInfo( |
| 3122 | @typeInfo(@TypeOf(Zcu.SrcLoc.span)).Fn.return_type.?, |
| 3123 | ).ErrorUnion.error_set; |
| 3124 | |
| 3125 | pub fn lessThan(ctx: @This(), lhs_index: usize, rhs_index: usize) bool { |
| 3126 | if (ctx.err.*) |_| return lhs_index < rhs_index; |
| 3127 | const errors = ctx.zcu.failed_analysis.values(); |
| 3128 | const lhs_src_loc = errors[lhs_index].src_loc.upgrade(ctx.zcu); |
| 3129 | const rhs_src_loc = errors[rhs_index].src_loc.upgrade(ctx.zcu); |
| 3130 | return if (lhs_src_loc.file_scope != rhs_src_loc.file_scope) std.mem.order( |
| 3131 | u8, |
| 3132 | lhs_src_loc.file_scope.sub_file_path, |
| 3133 | rhs_src_loc.file_scope.sub_file_path, |
| 3134 | ).compare(.lt) else (lhs_src_loc.span(ctx.zcu.gpa) catch |e| { |
| 3135 | ctx.err.* = e; |
| 3136 | return lhs_index < rhs_index; |
| 3137 | }).main < (rhs_src_loc.span(ctx.zcu.gpa) catch |e| { |
| 3138 | ctx.err.* = e; |
| 3139 | return lhs_index < rhs_index; |
| 3140 | }).main; |
| 3141 | } |
| 3142 | }; |
| 3143 | var err: ?SortOrder.Error = null; |
| 3144 | // This leaves `zcu.failed_analysis` an invalid state, but we do not |
| 3145 | // need lookups anymore anyway. |
| 3146 | zcu.failed_analysis.entries.sort(SortOrder{ .zcu = zcu, .err = &err }); |
| 3147 | if (err) |e| return e; |
| 3148 | } |
| 3098 | 3149 | for (zcu.failed_analysis.keys(), zcu.failed_analysis.values()) |anal_unit, error_msg| { |
| 3099 | 3150 | const decl_index = switch (anal_unit.unwrap()) { |
| 3100 | 3151 | .decl => |d| d, |
| ... | ... | @@ -3543,18 +3594,18 @@ fn performAllTheWorkInner( |
| 3543 | 3594 | comp.codegen_work.cond.signal(); |
| 3544 | 3595 | }; |
| 3545 | 3596 | |
| 3546 | | while (true) { |
| 3547 | | if (comp.work_queue.readItem()) |work_item| { |
| 3548 | | try processOneJob(@intFromEnum(Zcu.PerThread.Id.main), comp, work_item, main_progress_node); |
| 3549 | | continue; |
| 3550 | | } |
| 3597 | work: while (true) { |
| 3598 | for (&comp.work_queues) |*work_queue| if (work_queue.readItem()) |job| { |
| 3599 | try processOneJob(@intFromEnum(Zcu.PerThread.Id.main), comp, job, main_progress_node); |
| 3600 | continue :work; |
| 3601 | }; |
| 3551 | 3602 | if (comp.module) |zcu| { |
| 3552 | 3603 | // If there's no work queued, check if there's anything outdated |
| 3553 | 3604 | // which we need to work on, and queue it if so. |
| 3554 | 3605 | if (try zcu.findOutdatedToAnalyze()) |outdated| { |
| 3555 | 3606 | switch (outdated.unwrap()) { |
| 3556 | | .decl => |decl| try comp.work_queue.writeItem(.{ .analyze_decl = decl }), |
| 3557 | | .func => |func| try comp.work_queue.writeItem(.{ .analyze_func = func }), |
| 3607 | .decl => |decl| try comp.queueJob(.{ .analyze_decl = decl }), |
| 3608 | .func => |func| try comp.queueJob(.{ .analyze_func = func }), |
| 3558 | 3609 | } |
| 3559 | 3610 | continue; |
| 3560 | 3611 | } |
| ... | ... | @@ -3575,6 +3626,14 @@ fn performAllTheWorkInner( |
| 3575 | 3626 | |
| 3576 | 3627 | const JobError = Allocator.Error; |
| 3577 | 3628 | |
| 3629 | pub fn queueJob(comp: *Compilation, job: Job) !void { |
| 3630 | try comp.work_queues[Job.stage(job)].writeItem(job); |
| 3631 | } |
| 3632 | |
| 3633 | pub fn queueJobs(comp: *Compilation, jobs: []const Job) !void { |
| 3634 | for (jobs) |job| try comp.queueJob(job); |
| 3635 | } |
| 3636 | |
| 3578 | 3637 | fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progress.Node) JobError!void { |
| 3579 | 3638 | switch (job) { |
| 3580 | 3639 | .codegen_decl => |decl_index| { |
| ... | ... | @@ -6478,7 +6537,7 @@ pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void { |
| 6478 | 6537 | }; |
| 6479 | 6538 | const target = comp.root_mod.resolved_target.result; |
| 6480 | 6539 | if (target.os.tag == .windows and target.ofmt != .c) { |
| 6481 | | try comp.work_queue.writeItem(.{ |
| 6540 | try comp.queueJob(.{ |
| 6482 | 6541 | .windows_import_lib = comp.system_libs.count() - 1, |
| 6483 | 6542 | }); |
| 6484 | 6543 | } |