@@ -103,6 +103,14 @@ lld_errors: std.ArrayListUnmanaged(LldError) = .{},
103
103
104
104
work_queue : std .fifo .LinearFifo (Job , .Dynamic ),
105
105
106
+ codegen_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
114
/// These jobs are to invoke the Clang compiler to create an object file, which
107
115
/// gets linked with the Compilation.
108
116
c_object_work_queue : std .fifo .LinearFifo (* CObject , .Dynamic ),
@@ -362,6 +370,16 @@ const Job = union(enum) {
362
370
windows_import_lib : usize ,
363
371
};
364
372
373
+ const 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
+
365
383
pub const CObject = struct {
366
384
/// Relative to cwd. Owned by arena.
367
385
src : CSourceFile ,
@@ -1429,6 +1447,13 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1429
1447
.emit_llvm_ir = options .emit_llvm_ir ,
1430
1448
.emit_llvm_bc = options .emit_llvm_bc ,
1431
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
1457
.c_object_work_queue = std .fifo .LinearFifo (* CObject , .Dynamic ).init (gpa ),
1433
1458
.win32_resource_work_queue = if (build_options .only_core_functionality ) {} else std .fifo .LinearFifo (* Win32Resource , .Dynamic ).init (gpa ),
1434
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
3335
pub fn performAllTheWork (
3311
3336
comp : * Compilation ,
3312
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
+
3349
+ fn performAllTheWorkInner (
3350
+ comp : * Compilation ,
3351
+ main_progress_node : std.Progress.Node ,
3352
+ ) JobError ! void {
3314
3353
// Here we queue up all the AstGen tasks first, followed by C object compilation.
3315
3354
// We wait until the AstGen tasks are all completed before proceeding to the
3316
3355
// (at least for now) single-threaded main work queue. However, C object compilation
@@ -3410,16 +3449,20 @@ pub fn performAllTheWork(
3410
3449
mod .sema_prog_node = main_progress_node .start ("Semantic Analysis" , 0 );
3411
3450
mod .codegen_prog_node = main_progress_node .start ("Code Generation" , 0 );
3412
3451
}
3413
- defer if (comp .module ) | mod | {
3414
- mod .sema_prog_node .end ();
3415
- mod .sema_prog_node = undefined ;
3416
- mod .codegen_prog_node .end ();
3417
- mod .codegen_prog_node = undefined ;
3452
+
3453
+ if (! InternPool .single_threaded ) comp .thread_pool .spawnWgId (& comp .work_queue_wait_group , codegenThread , .{comp });
3454
+ defer if (! InternPool .single_threaded ) {
3455
+ {
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
};
3419
3462
3420
3463
while (true ) {
3421
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
3466
continue ;
3424
3467
}
3425
3468
if (comp .module ) | zcu | {
@@ -3447,11 +3490,12 @@ pub fn performAllTheWork(
3447
3490
}
3448
3491
}
3449
3492
3450
- fn processOneJob (tid : usize , comp : * Compilation , job : Job , prog_node : std.Progress.Node ) ! void {
3493
+ const JobError = Allocator .Error ;
3494
+
3495
+ fn processOneJob (tid : usize , comp : * Compilation , job : Job , prog_node : std.Progress.Node ) JobError ! void {
3451
3496
switch (job ) {
3452
3497
.codegen_decl = > | decl_index | {
3453
- const pt : Zcu.PerThread = .{ .zcu = comp .module .? , .tid = @enumFromInt (tid ) };
3454
- const decl = pt .zcu .declPtr (decl_index );
3498
+ const decl = comp .module .? .declPtr (decl_index );
3455
3499
3456
3500
switch (decl .analysis ) {
3457
3501
.unreferenced = > unreachable ,
@@ -3461,26 +3505,20 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
3461
3505
.sema_failure ,
3462
3506
.codegen_failure ,
3463
3507
.dependency_failure ,
3464
- = > return ,
3508
+ = > {} ,
3465
3509
3466
3510
.complete = > {
3467
- const named_frame = tracy .namedFrame ("codegen_decl" );
3468
- defer named_frame .end ();
3469
-
3470
3511
assert (decl .has_tv );
3471
-
3472
- try pt .linkerUpdateDecl (decl_index );
3473
- return ;
3512
+ try comp .queueCodegenJob (tid , .{ .decl = decl_index });
3474
3513
},
3475
3514
}
3476
3515
},
3477
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
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
3523
.analyze_func = > | func | {
3486
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
3810
}
3773
3811
}
3774
3812
3813
+ fn 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
+
3826
+ fn 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
+
3848
+ fn 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
+
3775
3868
fn workerDocsCopy (comp : * Compilation ) void {
3776
3869
docsCopyFallible (comp ) catch | err | {
3777
3870
return comp .lockAndSetMiscFailure (
0 commit comments