Introduce CodegenState.

The codegen main loop has two bools, `codegen_done` and
`codegen_aborted`. There are only three valid combinations: `(false,
false)`, `(true, false)`, `(true, true)`.

This commit replaces them with a single tri-state enum, which makes
things clearer.
This commit is contained in:
Nicholas Nethercote 2023-06-20 14:05:55 +10:00
parent a521ba400d
commit 3bbf9f0128

View File

@ -1239,10 +1239,19 @@ fn start_executing_work<B: ExtraBackendMethods>(
let mut needs_thin_lto = Vec::new(); let mut needs_thin_lto = Vec::new();
let mut lto_import_only_modules = Vec::new(); let mut lto_import_only_modules = Vec::new();
let mut started_lto = false; let mut started_lto = false;
let mut codegen_aborted = false;
// This flag tracks whether all items have gone through codegens /// Possible state transitions:
let mut codegen_done = false; /// - Ongoing -> Completed
/// - Ongoing -> Aborted
/// - Completed -> Aborted
#[derive(Debug, PartialEq)]
enum CodegenState {
Ongoing,
Completed,
Aborted,
}
use CodegenState::*;
let mut codegen_state = Ongoing;
// This is the queue of LLVM work items that still need processing. // This is the queue of LLVM work items that still need processing.
let mut work_items = Vec::<(WorkItem<B>, u64)>::new(); let mut work_items = Vec::<(WorkItem<B>, u64)>::new();
@ -1262,10 +1271,10 @@ fn start_executing_work<B: ExtraBackendMethods>(
// wait for all existing work to finish, so many of the conditions here // wait for all existing work to finish, so many of the conditions here
// only apply if codegen hasn't been aborted as they represent pending // only apply if codegen hasn't been aborted as they represent pending
// work to be done. // work to be done.
while !codegen_done while codegen_state == Ongoing
|| running > 0 || running > 0
|| main_thread_worker_state == MainThreadWorkerState::LLVMing || main_thread_worker_state == MainThreadWorkerState::LLVMing
|| (!codegen_aborted || (codegen_state == Completed
&& !(work_items.is_empty() && !(work_items.is_empty()
&& needs_fat_lto.is_empty() && needs_fat_lto.is_empty()
&& needs_thin_lto.is_empty() && needs_thin_lto.is_empty()
@ -1275,7 +1284,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
// While there are still CGUs to be codegened, the coordinator has // While there are still CGUs to be codegened, the coordinator has
// to decide how to utilize the compiler processes implicit Token: // to decide how to utilize the compiler processes implicit Token:
// For codegenning more CGU or for running them through LLVM. // For codegenning more CGU or for running them through LLVM.
if !codegen_done { if codegen_state == Ongoing {
if main_thread_worker_state == MainThreadWorkerState::Idle { if main_thread_worker_state == MainThreadWorkerState::Idle {
// Compute the number of workers that will be running once we've taken as many // Compute the number of workers that will be running once we've taken as many
// items from the work queue as we can, plus one for the main thread. It's not // items from the work queue as we can, plus one for the main thread. It's not
@ -1312,10 +1321,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
spawn_work(cgcx, item); spawn_work(cgcx, item);
} }
} }
} else if codegen_aborted { } else if codegen_state == Completed {
// don't queue up any more work if codegen was aborted, we're
// just waiting for our existing children to finish
} else {
// If we've finished everything related to normal codegen // If we've finished everything related to normal codegen
// then it must be the case that we've got some LTO work to do. // then it must be the case that we've got some LTO work to do.
// Perform the serial work here of figuring out what we're // Perform the serial work here of figuring out what we're
@ -1382,11 +1388,15 @@ fn start_executing_work<B: ExtraBackendMethods>(
// Already making good use of that token // Already making good use of that token
} }
} }
} else {
// Don't queue up any more work if codegen was aborted, we're
// just waiting for our existing children to finish.
assert!(codegen_state == Aborted);
} }
// Spin up what work we can, only doing this while we've got available // Spin up what work we can, only doing this while we've got available
// parallelism slots and work left to spawn. // parallelism slots and work left to spawn.
while !codegen_aborted && !work_items.is_empty() && running < tokens.len() { while codegen_state != Aborted && !work_items.is_empty() && running < tokens.len() {
let (item, _) = work_items.pop().unwrap(); let (item, _) = work_items.pop().unwrap();
maybe_start_llvm_timer(prof, cgcx.config(item.module_kind()), &mut llvm_start_time); maybe_start_llvm_timer(prof, cgcx.config(item.module_kind()), &mut llvm_start_time);
@ -1438,8 +1448,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
Err(e) => { Err(e) => {
let msg = &format!("failed to acquire jobserver token: {}", e); let msg = &format!("failed to acquire jobserver token: {}", e);
shared_emitter.fatal(msg); shared_emitter.fatal(msg);
codegen_done = true; codegen_state = Aborted;
codegen_aborted = true;
} }
} }
} }
@ -1467,7 +1476,9 @@ fn start_executing_work<B: ExtraBackendMethods>(
} }
Message::CodegenComplete => { Message::CodegenComplete => {
codegen_done = true; if codegen_state != Aborted {
codegen_state = Completed;
}
assert_eq!(main_thread_worker_state, MainThreadWorkerState::Codegenning); assert_eq!(main_thread_worker_state, MainThreadWorkerState::Codegenning);
main_thread_worker_state = MainThreadWorkerState::Idle; main_thread_worker_state = MainThreadWorkerState::Idle;
} }
@ -1479,8 +1490,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
// then conditions above will ensure no more work is spawned but // then conditions above will ensure no more work is spawned but
// we'll keep executing this loop until `running` hits 0. // we'll keep executing this loop until `running` hits 0.
Message::CodegenAborted => { Message::CodegenAborted => {
codegen_done = true; codegen_state = Aborted;
codegen_aborted = true;
} }
Message::WorkItem { result, worker_id } => { Message::WorkItem { result, worker_id } => {
@ -1512,8 +1522,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
} }
Err(Some(WorkerFatalError)) => { Err(Some(WorkerFatalError)) => {
// Like `CodegenAborted`, wait for remaining work to finish. // Like `CodegenAborted`, wait for remaining work to finish.
codegen_done = true; codegen_state = Aborted;
codegen_aborted = true;
} }
Err(None) => { Err(None) => {
// If the thread failed that means it panicked, so // If the thread failed that means it panicked, so
@ -1525,7 +1534,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
Message::AddImportOnlyModule { module_data, work_product } => { Message::AddImportOnlyModule { module_data, work_product } => {
assert!(!started_lto); assert!(!started_lto);
assert!(!codegen_done); assert_eq!(codegen_state, Ongoing);
assert_eq!(main_thread_worker_state, MainThreadWorkerState::Codegenning); assert_eq!(main_thread_worker_state, MainThreadWorkerState::Codegenning);
lto_import_only_modules.push((module_data, work_product)); lto_import_only_modules.push((module_data, work_product));
main_thread_worker_state = MainThreadWorkerState::Idle; main_thread_worker_state = MainThreadWorkerState::Idle;
@ -1533,7 +1542,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
} }
} }
if codegen_aborted { if codegen_state == Aborted {
return Err(()); return Err(());
} }