| ... | @@ -101,7 +101,15 @@ link_error_flags: link.File.ErrorFlags = .{}, | ... | @@ -101,7 +101,15 @@ link_error_flags: link.File.ErrorFlags = .{}, |
| 101 | link_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{}, | 101 | link_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{}, |
| 102 | lld_errors: std.ArrayListUnmanaged(LldError) = .{}, | 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 | codegen_work: if (InternPool.single_threaded) void else struct { | 114 | codegen_work: if (InternPool.single_threaded) void else struct { |
| 107 | mutex: std.Thread.Mutex, | 115 | mutex: std.Thread.Mutex, |
| ... | @@ -370,6 +378,20 @@ const Job = union(enum) { | ... | @@ -370,6 +378,20 @@ const Job = union(enum) { |
| 370 | | 378 | |
| 371 | /// The value is the index into `system_libs`. | 379 | /// The value is the index into `system_libs`. |
| 372 | windows_import_lib: usize, | 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 | const CodegenJob = union(enum) { | 397 | const CodegenJob = union(enum) { |
| ... | @@ -1452,7 +1474,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil | ... | @@ -1452,7 +1474,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1452 | .emit_asm = options.emit_asm, | 1474 | .emit_asm = options.emit_asm, |
| 1453 | .emit_llvm_ir = options.emit_llvm_ir, | 1475 | .emit_llvm_ir = options.emit_llvm_ir, |
| 1454 | .emit_llvm_bc = options.emit_llvm_bc, | 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 | .codegen_work = if (InternPool.single_threaded) {} else .{ | 1478 | .codegen_work = if (InternPool.single_threaded) {} else .{ |
| 1457 | .mutex = .{}, | 1479 | .mutex = .{}, |
| 1458 | .cond = .{}, | 1480 | .cond = .{}, |
| ... | @@ -1760,12 +1782,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil | ... | @@ -1760,12 +1782,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1760 | if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable; | 1782 | if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable; |
| 1761 | | 1783 | |
| 1762 | if (glibc.needsCrtiCrtn(target)) { | 1784 | if (glibc.needsCrtiCrtn(target)) { |
| 1763 | try comp.work_queue.write(&[_]Job{ | 1785 | try comp.queueJobs(&[_]Job{ |
| 1764 | .{ .glibc_crt_file = .crti_o }, | 1786 | .{ .glibc_crt_file = .crti_o }, |
| 1765 | .{ .glibc_crt_file = .crtn_o }, | 1787 | .{ .glibc_crt_file = .crtn_o }, |
| 1766 | }); | 1788 | }); |
| 1767 | } | 1789 | } |
| 1768 | try comp.work_queue.write(&[_]Job{ | 1790 | try comp.queueJobs(&[_]Job{ |
| 1769 | .{ .glibc_crt_file = .scrt1_o }, | 1791 | .{ .glibc_crt_file = .scrt1_o }, |
| 1770 | .{ .glibc_crt_file = .libc_nonshared_a }, | 1792 | .{ .glibc_crt_file = .libc_nonshared_a }, |
| 1771 | .{ .glibc_shared_objects = {} }, | 1793 | .{ .glibc_shared_objects = {} }, |
| ... | @@ -1774,14 +1796,13 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil | ... | @@ -1774,14 +1796,13 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1774 | if (comp.wantBuildMuslFromSource()) { | 1796 | if (comp.wantBuildMuslFromSource()) { |
| 1775 | if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable; | 1797 | if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable; |
| 1776 | | 1798 | |
| 1777 | try comp.work_queue.ensureUnusedCapacity(6); | | |
| 1778 | if (musl.needsCrtiCrtn(target)) { | 1799 | if (musl.needsCrtiCrtn(target)) { |
| 1779 | comp.work_queue.writeAssumeCapacity(&[_]Job{ | 1800 | try comp.queueJobs(&[_]Job{ |
| 1780 | .{ .musl_crt_file = .crti_o }, | 1801 | .{ .musl_crt_file = .crti_o }, |
| 1781 | .{ .musl_crt_file = .crtn_o }, | 1802 | .{ .musl_crt_file = .crtn_o }, |
| 1782 | }); | 1803 | }); |
| 1783 | } | 1804 | } |
| 1784 | comp.work_queue.writeAssumeCapacity(&[_]Job{ | 1805 | try comp.queueJobs(&[_]Job{ |
| 1785 | .{ .musl_crt_file = .crt1_o }, | 1806 | .{ .musl_crt_file = .crt1_o }, |
| 1786 | .{ .musl_crt_file = .scrt1_o }, | 1807 | .{ .musl_crt_file = .scrt1_o }, |
| 1787 | .{ .musl_crt_file = .rcrt1_o }, | 1808 | .{ .musl_crt_file = .rcrt1_o }, |
| ... | @@ -1795,15 +1816,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil | ... | @@ -1795,15 +1816,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1795 | if (comp.wantBuildWasiLibcFromSource()) { | 1816 | if (comp.wantBuildWasiLibcFromSource()) { |
| 1796 | if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable; | 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 | for (comp.wasi_emulated_libs) |crt_file| { | 1819 | for (comp.wasi_emulated_libs) |crt_file| { |
| 1802 | comp.work_queue.writeItemAssumeCapacity(.{ | 1820 | try comp.queueJob(.{ |
| 1803 | .wasi_libc_crt_file = crt_file, | 1821 | .wasi_libc_crt_file = crt_file, |
| 1804 | }); | 1822 | }); |
| 1805 | } | 1823 | } |
| 1806 | comp.work_queue.writeAssumeCapacity(&[_]Job{ | 1824 | try comp.queueJobs(&[_]Job{ |
| 1807 | .{ .wasi_libc_crt_file = wasi_libc.execModelCrtFile(comp.config.wasi_exec_model) }, | 1825 | .{ .wasi_libc_crt_file = wasi_libc.execModelCrtFile(comp.config.wasi_exec_model) }, |
| 1808 | .{ .wasi_libc_crt_file = .libc_a }, | 1826 | .{ .wasi_libc_crt_file = .libc_a }, |
| 1809 | }); | 1827 | }); |
| ... | @@ -1813,9 +1831,10 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil | ... | @@ -1813,9 +1831,10 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1813 | if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable; | 1831 | if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable; |
| 1814 | | 1832 | |
| 1815 | const crt_job: Job = .{ .mingw_crt_file = if (is_dyn_lib) .dllcrt2_o else .crt2_o }; | 1833 | const crt_job: Job = .{ .mingw_crt_file = if (is_dyn_lib) .dllcrt2_o else .crt2_o }; |
| 1816 | try comp.work_queue.ensureUnusedCapacity(2); | 1834 | try comp.queueJobs(&.{ |
| 1817 | comp.work_queue.writeItemAssumeCapacity(.{ .mingw_crt_file = .mingw32_lib }); | 1835 | .{ .mingw_crt_file = .mingw32_lib }, |
| 1818 | comp.work_queue.writeItemAssumeCapacity(crt_job); | 1836 | crt_job, |
| | 1837 | }); |
| 1819 | | 1838 | |
| 1820 | // When linking mingw-w64 there are some import libs we always need. | 1839 | // When linking mingw-w64 there are some import libs we always need. |
| 1821 | for (mingw.always_link_libs) |name| { | 1840 | for (mingw.always_link_libs) |name| { |
| ... | @@ -1829,20 +1848,19 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil | ... | @@ -1829,20 +1848,19 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1829 | // Generate Windows import libs. | 1848 | // Generate Windows import libs. |
| 1830 | if (target.os.tag == .windows) { | 1849 | if (target.os.tag == .windows) { |
| 1831 | const count = comp.system_libs.count(); | 1850 | const count = comp.system_libs.count(); |
| 1832 | try comp.work_queue.ensureUnusedCapacity(count); | | |
| 1833 | for (0..count) |i| { | 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 | if (comp.wantBuildLibUnwindFromSource()) { | 1855 | if (comp.wantBuildLibUnwindFromSource()) { |
| 1838 | try comp.work_queue.writeItem(.{ .libunwind = {} }); | 1856 | try comp.queueJob(.{ .libunwind = {} }); |
| 1839 | } | 1857 | } |
| 1840 | if (build_options.have_llvm and is_exe_or_dyn_lib and comp.config.link_libcpp) { | 1858 | if (build_options.have_llvm and is_exe_or_dyn_lib and comp.config.link_libcpp) { |
| 1841 | try comp.work_queue.writeItem(.libcxx); | 1859 | try comp.queueJob(.libcxx); |
| 1842 | try comp.work_queue.writeItem(.libcxxabi); | 1860 | try comp.queueJob(.libcxxabi); |
| 1843 | } | 1861 | } |
| 1844 | if (build_options.have_llvm and comp.config.any_sanitize_thread) { | 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 | if (target.isMinGW() and comp.config.any_non_single_threaded) { | 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,7 +1890,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1872 | if (!comp.skip_linker_dependencies and is_exe_or_dyn_lib and | 1890 | if (!comp.skip_linker_dependencies and is_exe_or_dyn_lib and |
| 1873 | !comp.config.link_libc and capable_of_building_zig_libc) | 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,7 +1901,7 @@ pub fn destroy(comp: *Compilation) void { |
| 1883 | if (comp.bin_file) |lf| lf.destroy(); | 1901 | if (comp.bin_file) |lf| lf.destroy(); |
| 1884 | if (comp.module) |zcu| zcu.deinit(); | 1902 | if (comp.module) |zcu| zcu.deinit(); |
| 1885 | comp.cache_use.deinit(); | 1903 | comp.cache_use.deinit(); |
| 1886 | comp.work_queue.deinit(); | 1904 | for (comp.work_queues) |work_queue| work_queue.deinit(); |
| 1887 | if (!InternPool.single_threaded) comp.codegen_work.queue.deinit(); | 1905 | if (!InternPool.single_threaded) comp.codegen_work.queue.deinit(); |
| 1888 | comp.c_object_work_queue.deinit(); | 1906 | comp.c_object_work_queue.deinit(); |
| 1889 | if (!build_options.only_core_functionality) { | 1907 | if (!build_options.only_core_functionality) { |
| ... | @@ -2199,13 +2217,13 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { | ... | @@ -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 | if (comp.config.is_test) { | 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 | if (zcu.root_mod.deps.get("compiler_rt")) |compiler_rt_mod| { | 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,6 +3113,39 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 3095 | for (zcu.failed_embed_files.values()) |error_msg| { | 3113 | for (zcu.failed_embed_files.values()) |error_msg| { |
| 3096 | try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references); | 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 | for (zcu.failed_analysis.keys(), zcu.failed_analysis.values()) |anal_unit, error_msg| { | 3149 | for (zcu.failed_analysis.keys(), zcu.failed_analysis.values()) |anal_unit, error_msg| { |
| 3099 | const decl_index = switch (anal_unit.unwrap()) { | 3150 | const decl_index = switch (anal_unit.unwrap()) { |
| 3100 | .decl => |d| d, | 3151 | .decl => |d| d, |
| ... | @@ -3543,18 +3594,18 @@ fn performAllTheWorkInner( | ... | @@ -3543,18 +3594,18 @@ fn performAllTheWorkInner( |
| 3543 | comp.codegen_work.cond.signal(); | 3594 | comp.codegen_work.cond.signal(); |
| 3544 | }; | 3595 | }; |
| 3545 | | 3596 | |
| 3546 | while (true) { | 3597 | work: while (true) { |
| 3547 | if (comp.work_queue.readItem()) |work_item| { | 3598 | for (&comp.work_queues) |*work_queue| if (work_queue.readItem()) |job| { |
| 3548 | try processOneJob(@intFromEnum(Zcu.PerThread.Id.main), comp, work_item, main_progress_node); | 3599 | try processOneJob(@intFromEnum(Zcu.PerThread.Id.main), comp, job, main_progress_node); |
| 3549 | continue; | 3600 | continue :work; |
| 3550 | } | 3601 | }; |
| 3551 | if (comp.module) |zcu| { | 3602 | if (comp.module) |zcu| { |
| 3552 | // If there's no work queued, check if there's anything outdated | 3603 | // If there's no work queued, check if there's anything outdated |
| 3553 | // which we need to work on, and queue it if so. | 3604 | // which we need to work on, and queue it if so. |
| 3554 | if (try zcu.findOutdatedToAnalyze()) |outdated| { | 3605 | if (try zcu.findOutdatedToAnalyze()) |outdated| { |
| 3555 | switch (outdated.unwrap()) { | 3606 | switch (outdated.unwrap()) { |
| 3556 | .decl => |decl| try comp.work_queue.writeItem(.{ .analyze_decl = decl }), | 3607 | .decl => |decl| try comp.queueJob(.{ .analyze_decl = decl }), |
| 3557 | .func => |func| try comp.work_queue.writeItem(.{ .analyze_func = func }), | 3608 | .func => |func| try comp.queueJob(.{ .analyze_func = func }), |
| 3558 | } | 3609 | } |
| 3559 | continue; | 3610 | continue; |
| 3560 | } | 3611 | } |
| ... | @@ -3575,6 +3626,14 @@ fn performAllTheWorkInner( | ... | @@ -3575,6 +3626,14 @@ fn performAllTheWorkInner( |
| 3575 | | 3626 | |
| 3576 | const JobError = Allocator.Error; | 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 | fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progress.Node) JobError!void { | 3637 | fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progress.Node) JobError!void { |
| 3579 | switch (job) { | 3638 | switch (job) { |
| 3580 | .codegen_decl => |decl_index| { | 3639 | .codegen_decl => |decl_index| { |
| ... | @@ -6478,7 +6537,7 @@ pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void { | ... | @@ -6478,7 +6537,7 @@ pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void { |
| 6478 | }; | 6537 | }; |
| 6479 | const target = comp.root_mod.resolved_target.result; | 6538 | const target = comp.root_mod.resolved_target.result; |
| 6480 | if (target.os.tag == .windows and target.ofmt != .c) { | 6539 | if (target.os.tag == .windows and target.ofmt != .c) { |
| 6481 | try comp.work_queue.writeItem(.{ | 6540 | try comp.queueJob(.{ |
| 6482 | .windows_import_lib = comp.system_libs.count() - 1, | 6541 | .windows_import_lib = comp.system_libs.count() - 1, |
| 6483 | }); | 6542 | }); |
| 6484 | } | 6543 | } |