authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-07-08 09:05:30-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-07-08 11:00:38-04:00
log65ced4a33436fa762de75e22a986ae08a8c0d9cc
treed19b6b0cdb71a7e0f6bc65379441992753979a4a
parentc36e2bb9802ab4317980a98ea518483010fe2c80

Compilation: put supported codegen backends on a separate thread

(There are no supported backends.)

7 files changed, 173 insertions(+), 65 deletions(-)

lib/std/Progress.zig+1-1
...@@ -282,7 +282,7 @@ pub const Node = struct {...@@ -282,7 +282,7 @@ pub const Node = struct {
282 }282 }
283283
284 fn init(free_index: Index, parent: Parent, name: []const u8, estimated_total_items: usize) Node {284 fn init(free_index: Index, parent: Parent, name: []const u8, estimated_total_items: usize) Node {
285 assert(parent != .unused);285 assert(parent == .none or @intFromEnum(parent) < node_storage_buffer_len);
286286
287 const storage = storageByIndex(free_index);287 const storage = storageByIndex(free_index);
288 storage.* = .{288 storage.* = .{
lib/std/Thread/Pool.zig+10-13
...@@ -21,11 +21,11 @@ const Runnable = struct {...@@ -21,11 +21,11 @@ const Runnable = struct {
21 runFn: RunProto,21 runFn: RunProto,
22};22};
2323
24const RunProto = *const fn (*Runnable, id: ?u32) void;24const RunProto = *const fn (*Runnable, id: ?usize) void;
2525
26pub const Options = struct {26pub const Options = struct {
27 allocator: std.mem.Allocator,27 allocator: std.mem.Allocator,
28 n_jobs: ?u32 = null,28 n_jobs: ?usize = null,
29 track_ids: bool = false,29 track_ids: bool = false,
30};30};
3131
...@@ -109,7 +109,7 @@ pub fn spawnWg(pool: *Pool, wait_group: *WaitGroup, comptime func: anytype, args...@@ -109,7 +109,7 @@ pub fn spawnWg(pool: *Pool, wait_group: *WaitGroup, comptime func: anytype, args
109 run_node: RunQueue.Node = .{ .data = .{ .runFn = runFn } },109 run_node: RunQueue.Node = .{ .data = .{ .runFn = runFn } },
110 wait_group: *WaitGroup,110 wait_group: *WaitGroup,
111111
112 fn runFn(runnable: *Runnable, _: ?u32) void {112 fn runFn(runnable: *Runnable, _: ?usize) void {
113 const run_node: *RunQueue.Node = @fieldParentPtr("data", runnable);113 const run_node: *RunQueue.Node = @fieldParentPtr("data", runnable);
114 const closure: *@This() = @alignCast(@fieldParentPtr("run_node", run_node));114 const closure: *@This() = @alignCast(@fieldParentPtr("run_node", run_node));
115 @call(.auto, func, closure.arguments);115 @call(.auto, func, closure.arguments);
...@@ -150,7 +150,7 @@ pub fn spawnWg(pool: *Pool, wait_group: *WaitGroup, comptime func: anytype, args...@@ -150,7 +150,7 @@ pub fn spawnWg(pool: *Pool, wait_group: *WaitGroup, comptime func: anytype, args
150/// Runs `func` in the thread pool, calling `WaitGroup.start` beforehand, and150/// Runs `func` in the thread pool, calling `WaitGroup.start` beforehand, and
151/// `WaitGroup.finish` after it returns.151/// `WaitGroup.finish` after it returns.
152///152///
153/// The first argument passed to `func` is a dense `u32` thread id, the rest153/// The first argument passed to `func` is a dense `usize` thread id, the rest
154/// of the arguments are passed from `args`. Requires the pool to have been154/// of the arguments are passed from `args`. Requires the pool to have been
155/// initialized with `.track_ids = true`.155/// initialized with `.track_ids = true`.
156///156///
...@@ -172,7 +172,7 @@ pub fn spawnWgId(pool: *Pool, wait_group: *WaitGroup, comptime func: anytype, ar...@@ -172,7 +172,7 @@ pub fn spawnWgId(pool: *Pool, wait_group: *WaitGroup, comptime func: anytype, ar
172 run_node: RunQueue.Node = .{ .data = .{ .runFn = runFn } },172 run_node: RunQueue.Node = .{ .data = .{ .runFn = runFn } },
173 wait_group: *WaitGroup,173 wait_group: *WaitGroup,
174174
175 fn runFn(runnable: *Runnable, id: ?u32) void {175 fn runFn(runnable: *Runnable, id: ?usize) void {
176 const run_node: *RunQueue.Node = @fieldParentPtr("data", runnable);176 const run_node: *RunQueue.Node = @fieldParentPtr("data", runnable);
177 const closure: *@This() = @alignCast(@fieldParentPtr("run_node", run_node));177 const closure: *@This() = @alignCast(@fieldParentPtr("run_node", run_node));
178 @call(.auto, func, .{id.?} ++ closure.arguments);178 @call(.auto, func, .{id.?} ++ closure.arguments);
...@@ -191,7 +191,7 @@ pub fn spawnWgId(pool: *Pool, wait_group: *WaitGroup, comptime func: anytype, ar...@@ -191,7 +191,7 @@ pub fn spawnWgId(pool: *Pool, wait_group: *WaitGroup, comptime func: anytype, ar
191 pool.mutex.lock();191 pool.mutex.lock();
192192
193 const closure = pool.allocator.create(Closure) catch {193 const closure = pool.allocator.create(Closure) catch {
194 const id = pool.ids.getIndex(std.Thread.getCurrentId());194 const id: ?usize = pool.ids.getIndex(std.Thread.getCurrentId());
195 pool.mutex.unlock();195 pool.mutex.unlock();
196 @call(.auto, func, .{id.?} ++ args);196 @call(.auto, func, .{id.?} ++ args);
197 wait_group.finish();197 wait_group.finish();
...@@ -258,7 +258,7 @@ fn worker(pool: *Pool) void {...@@ -258,7 +258,7 @@ fn worker(pool: *Pool) void {
258 pool.mutex.lock();258 pool.mutex.lock();
259 defer pool.mutex.unlock();259 defer pool.mutex.unlock();
260260
261 const id: ?u32 = if (pool.ids.count() > 0) @intCast(pool.ids.count()) else null;261 const id: ?usize = if (pool.ids.count() > 0) @intCast(pool.ids.count()) else null;
262 if (id) |_| pool.ids.putAssumeCapacityNoClobber(std.Thread.getCurrentId(), {});262 if (id) |_| pool.ids.putAssumeCapacityNoClobber(std.Thread.getCurrentId(), {});
263263
264 while (true) {264 while (true) {
...@@ -280,15 +280,12 @@ fn worker(pool: *Pool) void {...@@ -280,15 +280,12 @@ fn worker(pool: *Pool) void {
280}280}
281281
282pub fn waitAndWork(pool: *Pool, wait_group: *WaitGroup) void {282pub fn waitAndWork(pool: *Pool, wait_group: *WaitGroup) void {
283 var id: ?u32 = null;283 var id: ?usize = null;
284284
285 while (!wait_group.isDone()) {285 while (!wait_group.isDone()) {
286 pool.mutex.lock();286 pool.mutex.lock();
287 if (pool.run_queue.popFirst()) |run_node| {287 if (pool.run_queue.popFirst()) |run_node| {
288 id = id orelse if (pool.ids.getIndex(std.Thread.getCurrentId())) |index|288 id = id orelse pool.ids.getIndex(std.Thread.getCurrentId());
289 @intCast(index)
290 else
291 null;
292 pool.mutex.unlock();289 pool.mutex.unlock();
293 run_node.data.runFn(&run_node.data, id);290 run_node.data.runFn(&run_node.data, id);
294 continue;291 continue;
...@@ -300,6 +297,6 @@ pub fn waitAndWork(pool: *Pool, wait_group: *WaitGroup) void {...@@ -300,6 +297,6 @@ pub fn waitAndWork(pool: *Pool, wait_group: *WaitGroup) void {
300 }297 }
301}298}
302299
303pub fn getIdCount(pool: *Pool) u32 {300pub fn getIdCount(pool: *Pool) usize {
304 return @intCast(1 + pool.threads.len);301 return @intCast(1 + pool.threads.len);
305}302}
src/Compilation.zig+115-22
...@@ -103,6 +103,14 @@ lld_errors: std.ArrayListUnmanaged(LldError) = .{},...@@ -103,6 +103,14 @@ lld_errors: std.ArrayListUnmanaged(LldError) = .{},
103103
104work_queue: std.fifo.LinearFifo(Job, .Dynamic),104work_queue: std.fifo.LinearFifo(Job, .Dynamic),
105105
106codegen_work: if (InternPool.single_threaded) void else struct {
107 mutex: std.Thread.Mutex,
108 cond: std.Thread.Condition,
109 queue: std.fifo.LinearFifo(CodegenJob, .Dynamic),
110 job_error: ?JobError,
111 done: bool,
112},
113
106/// These jobs are to invoke the Clang compiler to create an object file, which114/// These jobs are to invoke the Clang compiler to create an object file, which
107/// gets linked with the Compilation.115/// gets linked with the Compilation.
108c_object_work_queue: std.fifo.LinearFifo(*CObject, .Dynamic),116c_object_work_queue: std.fifo.LinearFifo(*CObject, .Dynamic),
...@@ -362,6 +370,16 @@ const Job = union(enum) {...@@ -362,6 +370,16 @@ const Job = union(enum) {
362 windows_import_lib: usize,370 windows_import_lib: usize,
363};371};
364372
373const CodegenJob = union(enum) {
374 decl: InternPool.DeclIndex,
375 func: struct {
376 func: InternPool.Index,
377 /// This `Air` is owned by the `Job` and allocated with `gpa`.
378 /// It must be deinited when the job is processed.
379 air: Air,
380 },
381};
382
365pub const CObject = struct {383pub const CObject = struct {
366 /// Relative to cwd. Owned by arena.384 /// Relative to cwd. Owned by arena.
367 src: CSourceFile,385 src: CSourceFile,
...@@ -1429,6 +1447,13 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1429,6 +1447,13 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1429 .emit_llvm_ir = options.emit_llvm_ir,1447 .emit_llvm_ir = options.emit_llvm_ir,
1430 .emit_llvm_bc = options.emit_llvm_bc,1448 .emit_llvm_bc = options.emit_llvm_bc,
1431 .work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),1449 .work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),
1450 .codegen_work = if (InternPool.single_threaded) {} else .{
1451 .mutex = .{},
1452 .cond = .{},
1453 .queue = std.fifo.LinearFifo(CodegenJob, .Dynamic).init(gpa),
1454 .job_error = null,
1455 .done = false,
1456 },
1432 .c_object_work_queue = std.fifo.LinearFifo(*CObject, .Dynamic).init(gpa),1457 .c_object_work_queue = std.fifo.LinearFifo(*CObject, .Dynamic).init(gpa),
1433 .win32_resource_work_queue = if (build_options.only_core_functionality) {} else std.fifo.LinearFifo(*Win32Resource, .Dynamic).init(gpa),1458 .win32_resource_work_queue = if (build_options.only_core_functionality) {} else std.fifo.LinearFifo(*Win32Resource, .Dynamic).init(gpa),
1434 .astgen_work_queue = std.fifo.LinearFifo(Zcu.File.Index, .Dynamic).init(gpa),1459 .astgen_work_queue = std.fifo.LinearFifo(Zcu.File.Index, .Dynamic).init(gpa),
...@@ -3310,7 +3335,21 @@ pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Zcu.File) !void {...@@ -3310,7 +3335,21 @@ pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Zcu.File) !void {
3310pub fn performAllTheWork(3335pub fn performAllTheWork(
3311 comp: *Compilation,3336 comp: *Compilation,
3312 main_progress_node: std.Progress.Node,3337 main_progress_node: std.Progress.Node,
3313) error{ TimerUnsupported, OutOfMemory }!void {3338) JobError!void {
3339 defer if (comp.module) |mod| {
3340 mod.sema_prog_node.end();
3341 mod.sema_prog_node = std.Progress.Node.none;
3342 mod.codegen_prog_node.end();
3343 mod.codegen_prog_node = std.Progress.Node.none;
3344 };
3345 try comp.performAllTheWorkInner(main_progress_node);
3346 if (!InternPool.single_threaded) if (comp.codegen_work.job_error) |job_error| return job_error;
3347}
3348
3349fn performAllTheWorkInner(
3350 comp: *Compilation,
3351 main_progress_node: std.Progress.Node,
3352) JobError!void {
3314 // Here we queue up all the AstGen tasks first, followed by C object compilation.3353 // Here we queue up all the AstGen tasks first, followed by C object compilation.
3315 // We wait until the AstGen tasks are all completed before proceeding to the3354 // We wait until the AstGen tasks are all completed before proceeding to the
3316 // (at least for now) single-threaded main work queue. However, C object compilation3355 // (at least for now) single-threaded main work queue. However, C object compilation
...@@ -3410,16 +3449,20 @@ pub fn performAllTheWork(...@@ -3410,16 +3449,20 @@ pub fn performAllTheWork(
3410 mod.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);3449 mod.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
3411 mod.codegen_prog_node = main_progress_node.start("Code Generation", 0);3450 mod.codegen_prog_node = main_progress_node.start("Code Generation", 0);
3412 }3451 }
3413 defer if (comp.module) |mod| {3452
3414 mod.sema_prog_node.end();3453 if (!InternPool.single_threaded) comp.thread_pool.spawnWgId(&comp.work_queue_wait_group, codegenThread, .{comp});
3415 mod.sema_prog_node = undefined;3454 defer if (!InternPool.single_threaded) {
3416 mod.codegen_prog_node.end();3455 {
3417 mod.codegen_prog_node = undefined;3456 comp.codegen_work.mutex.lock();
3457 defer comp.codegen_work.mutex.unlock();
3458 comp.codegen_work.done = true;
3459 }
3460 comp.codegen_work.cond.signal();
3418 };3461 };
34193462
3420 while (true) {3463 while (true) {
3421 if (comp.work_queue.readItem()) |work_item| {3464 if (comp.work_queue.readItem()) |work_item| {
3422 try processOneJob(0, comp, work_item, main_progress_node);3465 try processOneJob(@intFromEnum(Zcu.PerThread.Id.main), comp, work_item, main_progress_node);
3423 continue;3466 continue;
3424 }3467 }
3425 if (comp.module) |zcu| {3468 if (comp.module) |zcu| {
...@@ -3447,11 +3490,12 @@ pub fn performAllTheWork(...@@ -3447,11 +3490,12 @@ pub fn performAllTheWork(
3447 }3490 }
3448}3491}
34493492
3450fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progress.Node) !void {3493const JobError = Allocator.Error;
3494
3495fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progress.Node) JobError!void {
3451 switch (job) {3496 switch (job) {
3452 .codegen_decl => |decl_index| {3497 .codegen_decl => |decl_index| {
3453 const pt: Zcu.PerThread = .{ .zcu = comp.module.?, .tid = @enumFromInt(tid) };3498 const decl = comp.module.?.declPtr(decl_index);
3454 const decl = pt.zcu.declPtr(decl_index);
34553499
3456 switch (decl.analysis) {3500 switch (decl.analysis) {
3457 .unreferenced => unreachable,3501 .unreferenced => unreachable,
...@@ -3461,26 +3505,20 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre...@@ -3461,26 +3505,20 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
3461 .sema_failure,3505 .sema_failure,
3462 .codegen_failure,3506 .codegen_failure,
3463 .dependency_failure,3507 .dependency_failure,
3464 => return,3508 => {},
34653509
3466 .complete => {3510 .complete => {
3467 const named_frame = tracy.namedFrame("codegen_decl");
3468 defer named_frame.end();
3469
3470 assert(decl.has_tv);3511 assert(decl.has_tv);
34713512 try comp.queueCodegenJob(tid, .{ .decl = decl_index });
3472 try pt.linkerUpdateDecl(decl_index);
3473 return;
3474 },3513 },
3475 }3514 }
3476 },3515 },
3477 .codegen_func => |func| {3516 .codegen_func => |func| {
3478 const named_frame = tracy.namedFrame("codegen_func");
3479 defer named_frame.end();
3480
3481 const pt: Zcu.PerThread = .{ .zcu = comp.module.?, .tid = @enumFromInt(tid) };
3482 // This call takes ownership of `func.air`.3517 // This call takes ownership of `func.air`.
3483 try pt.linkerUpdateFunc(func.func, func.air);3518 try comp.queueCodegenJob(tid, .{ .func = .{
3519 .func = func.func,
3520 .air = func.air,
3521 } });
3484 },3522 },
3485 .analyze_func => |func| {3523 .analyze_func => |func| {
3486 const named_frame = tracy.namedFrame("analyze_func");3524 const named_frame = tracy.namedFrame("analyze_func");
...@@ -3772,6 +3810,61 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre...@@ -3772,6 +3810,61 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
3772 }3810 }
3773}3811}
37743812
3813fn queueCodegenJob(comp: *Compilation, tid: usize, codegen_job: CodegenJob) !void {
3814 if (InternPool.single_threaded or
3815 !comp.module.?.backendSupportsFeature(.separate_thread))
3816 return processOneCodegenJob(tid, comp, codegen_job);
3817
3818 {
3819 comp.codegen_work.mutex.lock();
3820 defer comp.codegen_work.mutex.unlock();
3821 try comp.codegen_work.queue.writeItem(codegen_job);
3822 }
3823 comp.codegen_work.cond.signal();
3824}
3825
3826fn codegenThread(tid: usize, comp: *Compilation) void {
3827 comp.codegen_work.mutex.lock();
3828 defer comp.codegen_work.mutex.unlock();
3829
3830 while (true) {
3831 if (comp.codegen_work.queue.readItem()) |codegen_job| {
3832 comp.codegen_work.mutex.unlock();
3833 defer comp.codegen_work.mutex.lock();
3834
3835 processOneCodegenJob(tid, comp, codegen_job) catch |job_error| {
3836 comp.codegen_work.job_error = job_error;
3837 break;
3838 };
3839 continue;
3840 }
3841
3842 if (comp.codegen_work.done) break;
3843
3844 comp.codegen_work.cond.wait(&comp.codegen_work.mutex);
3845 }
3846}
3847
3848fn processOneCodegenJob(tid: usize, comp: *Compilation, codegen_job: CodegenJob) JobError!void {
3849 switch (codegen_job) {
3850 .decl => |decl_index| {
3851 const named_frame = tracy.namedFrame("codegen_decl");
3852 defer named_frame.end();
3853
3854 const pt: Zcu.PerThread = .{ .zcu = comp.module.?, .tid = @enumFromInt(tid) };
3855 try pt.linkerUpdateDecl(decl_index);
3856 },
3857 .func => |func| {
3858 const named_frame = tracy.namedFrame("codegen_func");
3859 defer named_frame.end();
3860
3861 const pt: Zcu.PerThread = .{ .zcu = comp.module.?, .tid = @enumFromInt(tid) };
3862 // This call takes ownership of `func.air`.
3863 try pt.linkerUpdateFunc(func.func, func.air);
3864 },
3865 }
3866}
3867
3775fn workerDocsCopy(comp: *Compilation) void {3868fn workerDocsCopy(comp: *Compilation) void {
3776 docsCopyFallible(comp) catch |err| {3869 docsCopyFallible(comp) catch |err| {
3777 return comp.lockAndSetMiscFailure(3870 return comp.lockAndSetMiscFailure(
src/Compilation/Config.zig+2-6
...@@ -440,12 +440,8 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -440,12 +440,8 @@ pub fn resolve(options: Options) ResolveError!Config {
440 };440 };
441 };441 };
442442
443 const backend_supports_error_tracing = target_util.backendSupportsFeature(443 const backend = target_util.zigBackend(target, use_llvm);
444 target.cpu.arch,444 const backend_supports_error_tracing = target_util.backendSupportsFeature(backend, .error_return_trace);
445 target.ofmt,
446 use_llvm,
447 .error_return_trace,
448 );
449445
450 const root_error_tracing = b: {446 const root_error_tracing = b: {
451 if (options.root_error_tracing) |x| break :b x;447 if (options.root_error_tracing) |x| break :b x;
src/Zcu.zig+7-7
...@@ -64,8 +64,8 @@ root_mod: *Package.Module,...@@ -64,8 +64,8 @@ root_mod: *Package.Module,
64/// `root_mod` is the test runner, and `main_mod` is the user's source file which has the tests.64/// `root_mod` is the test runner, and `main_mod` is the user's source file which has the tests.
65main_mod: *Package.Module,65main_mod: *Package.Module,
66std_mod: *Package.Module,66std_mod: *Package.Module,
67sema_prog_node: std.Progress.Node = undefined,67sema_prog_node: std.Progress.Node = std.Progress.Node.none,
68codegen_prog_node: std.Progress.Node = undefined,68codegen_prog_node: std.Progress.Node = std.Progress.Node.none,
6969
70/// Used by AstGen worker to load and store ZIR cache.70/// Used by AstGen worker to load and store ZIR cache.
71global_zir_cache: Compilation.Directory,71global_zir_cache: Compilation.Directory,
...@@ -3557,13 +3557,13 @@ pub const Feature = enum {...@@ -3557,13 +3557,13 @@ pub const Feature = enum {
3557 /// to generate better machine code in the backends. All backends should migrate to3557 /// to generate better machine code in the backends. All backends should migrate to
3558 /// enabling this feature.3558 /// enabling this feature.
3559 safety_checked_instructions,3559 safety_checked_instructions,
3560 /// If the backend supports running from another thread.
3561 separate_thread,
3560};3562};
35613563
3562pub fn backendSupportsFeature(zcu: Module, feature: Feature) bool {3564pub fn backendSupportsFeature(zcu: Module, comptime feature: Feature) bool {
3563 const cpu_arch = zcu.root_mod.resolved_target.result.cpu.arch;3565 const backend = target_util.zigBackend(zcu.root_mod.resolved_target.result, zcu.comp.config.use_llvm);
3564 const ofmt = zcu.root_mod.resolved_target.result.ofmt;3566 return target_util.backendSupportsFeature(backend, feature);
3565 const use_llvm = zcu.comp.config.use_llvm;
3566 return target_util.backendSupportsFeature(cpu_arch, ofmt, use_llvm, feature);
3567}3567}
35683568
3569pub const AtomicPtrAlignmentError = error{3569pub const AtomicPtrAlignmentError = error{
src/Zcu/PerThread.zig+2-2
...@@ -2129,7 +2129,7 @@ pub fn populateTestFunctions(...@@ -2129,7 +2129,7 @@ pub fn populateTestFunctions(
2129 zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);2129 zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
2130 defer {2130 defer {
2131 zcu.sema_prog_node.end();2131 zcu.sema_prog_node.end();
2132 zcu.sema_prog_node = undefined;2132 zcu.sema_prog_node = std.Progress.Node.none;
2133 }2133 }
2134 try pt.ensureDeclAnalyzed(decl_index);2134 try pt.ensureDeclAnalyzed(decl_index);
2135 }2135 }
...@@ -2238,7 +2238,7 @@ pub fn populateTestFunctions(...@@ -2238,7 +2238,7 @@ pub fn populateTestFunctions(
2238 zcu.codegen_prog_node = main_progress_node.start("Code Generation", 0);2238 zcu.codegen_prog_node = main_progress_node.start("Code Generation", 0);
2239 defer {2239 defer {
2240 zcu.codegen_prog_node.end();2240 zcu.codegen_prog_node.end();
2241 zcu.codegen_prog_node = undefined;2241 zcu.codegen_prog_node = std.Progress.Node.none;
2242 }2242 }
22432243
2244 try pt.linkerUpdateDecl(decl_index);2244 try pt.linkerUpdateDecl(decl_index);
src/target.zig+36-14
...@@ -537,20 +537,42 @@ pub fn zigBackend(target: std.Target, use_llvm: bool) std.builtin.CompilerBacken...@@ -537,20 +537,42 @@ pub fn zigBackend(target: std.Target, use_llvm: bool) std.builtin.CompilerBacken
537 };537 };
538}538}
539539
540pub fn backendSupportsFeature(540pub inline fn backendSupportsFeature(backend: std.builtin.CompilerBackend, comptime feature: Feature) bool {
541 cpu_arch: std.Target.Cpu.Arch,
542 ofmt: std.Target.ObjectFormat,
543 use_llvm: bool,
544 feature: Feature,
545) bool {
546 return switch (feature) {541 return switch (feature) {
547 .panic_fn => ofmt == .c or use_llvm or cpu_arch == .x86_64 or cpu_arch == .riscv64,542 .panic_fn => switch (backend) {
548 .panic_unwrap_error => ofmt == .c or use_llvm,543 .stage2_c, .stage2_llvm, .stage2_x86_64, .stage2_riscv64 => true,
549 .safety_check_formatted => ofmt == .c or use_llvm,544 else => false,
550 .error_return_trace => use_llvm,545 },
551 .is_named_enum_value => use_llvm,546 .panic_unwrap_error => switch (backend) {
552 .error_set_has_value => use_llvm or cpu_arch.isWasm(),547 .stage2_c, .stage2_llvm => true,
553 .field_reordering => ofmt == .c or use_llvm,548 else => false,
554 .safety_checked_instructions => use_llvm,549 },
550 .safety_check_formatted => switch (backend) {
551 .stage2_c, .stage2_llvm => true,
552 else => false,
553 },
554 .error_return_trace => switch (backend) {
555 .stage2_llvm => true,
556 else => false,
557 },
558 .is_named_enum_value => switch (backend) {
559 .stage2_llvm => true,
560 else => false,
561 },
562 .error_set_has_value => switch (backend) {
563 .stage2_llvm, .stage2_wasm => true,
564 else => false,
565 },
566 .field_reordering => switch (backend) {
567 .stage2_c, .stage2_llvm => true,
568 else => false,
569 },
570 .safety_checked_instructions => switch (backend) {
571 .stage2_llvm => true,
572 else => false,
573 },
574 .separate_thread => switch (backend) {
575 else => false,
576 },
555 };577 };
556}578}