From ed331a3a96def9119049a391ec15fe7a14ca680a Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Wed, 20 May 2026 23:37:23 -0700 Subject: [PATCH] WIP fixing deadlock when running rename_execute_retire_save_restore_gprs --- crates/cpu/src/rename_execute_retire.rs | 169 ++++++++++++++++-------- 1 file changed, 113 insertions(+), 56 deletions(-) diff --git a/crates/cpu/src/rename_execute_retire.rs b/crates/cpu/src/rename_execute_retire.rs index 35b9312..104684e 100644 --- a/crates/cpu/src/rename_execute_retire.rs +++ b/crates/cpu/src/rename_execute_retire.rs @@ -256,16 +256,21 @@ impl SimValueDefault for RenameExecuteRetireDebugState } #[hdl(no_static)] -enum RenameTableEntry> { - L1(PRegNum), - L2(L2RegNum), +struct RenameTableEntry> { + l1: HdlOption>, + l2: HdlOption, } impl RenameTableEntry { #[hdl] fn const_zero(self) -> SimValue { #[hdl(sim)] - self.L1(self.L1.const_zero()) + Self { + l1: #[hdl(sim)] + (self.l1).HdlSome(self.l1.HdlSome.const_zero()), + l2: #[hdl(sim)] + HdlNone(), + } } } @@ -313,6 +318,7 @@ enum RenameTableUpdate { dest: SimValue, src: SimValue>, }, + DropAllL2RegFileOutputs, } impl RenameTable { @@ -352,39 +358,69 @@ impl RenameTable { } RenameTableUpdate::UpdateForReadL2Reg { dest, src } => { let new = #[hdl(sim)] - (RenameTableEntry[self.config]).L1(dest); + RenameTableEntry::<_> { + l1: #[hdl(sim)] + (HdlOption[dest.ty()]).HdlSome(dest), + l2: #[hdl(sim)] + HdlSome(src), + }; for (unrenamed_reg_num, entry) in self.entries.iter_mut().enumerate() { #[hdl(sim)] - match entry.inner() { - RenameTableEntry::<_>::L1(_) => {} - RenameTableEntry::<_>::L2(l2) => { - if L2RegNum::value_sim(l2) == L2RegNum::value_sim(src) { - println!( - "{rename_table_name}: UpdateForReadL2Reg: {unrenamed_reg_num:#x} \ - updating from {entry:?} to {new:?}", - ); - *entry = new.to_trace_as_string(); + if let HdlSome(l2) = &entry.inner().l2 { + if L2RegNum::value_sim(l2) == L2RegNum::value_sim(src) { + println!( + "{rename_table_name}: UpdateForReadL2Reg: {unrenamed_reg_num:#x} \ + updating from {entry:?} to {new:?}", + ); + #[hdl(sim)] + if let HdlSome(_) = &entry.inner().l1 { + unreachable!("l1 should be HdlNone: {entry:?}"); } + *entry = new.to_trace_as_string(); } } } } RenameTableUpdate::UpdateForWriteL2Reg { dest, src } => { let new = #[hdl(sim)] - (RenameTableEntry[self.config]).L2(dest); + RenameTableEntry::<_> { + l1: #[hdl(sim)] + (HdlOption[src.ty()]).HdlNone(), + l2: #[hdl(sim)] + HdlSome(dest), + }; for (unrenamed_reg_num, entry) in self.entries.iter_mut().enumerate() { #[hdl(sim)] - match entry.inner() { - RenameTableEntry::<_>::L1(l1) => { - if l1 == src { - println!( - "{rename_table_name}: UpdateForWriteL2Reg: {unrenamed_reg_num:#x} \ - updating from {entry:?} to {new:?}", - ); - *entry = new.to_trace_as_string(); + if let HdlSome(l1) = &entry.inner().l1 { + if l1 == src { + println!( + "{rename_table_name}: UpdateForWriteL2Reg: {unrenamed_reg_num:#x} \ + updating from {entry:?} to {new:?}", + ); + #[hdl(sim)] + if let HdlSome(_) = &entry.inner().l2 { + unreachable!("l2 should be HdlNone: {entry:?}"); } + *entry = new.to_trace_as_string(); + } + } + } + } + RenameTableUpdate::DropAllL2RegFileOutputs => { + for (unrenamed_reg_num, entry) in self.entries.iter_mut().enumerate() { + #[hdl(sim)] + if let HdlSome(_) = &entry.inner().l1 { + #[hdl(sim)] + if let HdlSome(_) = &entry.inner().l2 { + let mut new = entry.inner().clone(); + new.l1 = #[hdl(sim)] + (new.l1.ty()).HdlNone(); + println!( + "{rename_table_name}: DropAllL2RegFileOutputs: {unrenamed_reg_num:#x} \ + updating from {entry:?} to {new:?}", + ); + *entry = new.to_trace_as_string(); } - RenameTableEntry::<_>::L2(_) => {} } } } @@ -395,13 +431,10 @@ impl RenameTable { let mut seen = BTreeSet::new(); for entry in self.entries.iter() { #[hdl(sim)] - match entry.inner() { - RenameTableEntry::<_>::L1(v) => { - if UnitNum::index_sim(&v.unit_num) == Some(unit_index) { - seen.insert(UnitOutRegNum::value_sim(&v.unit_out_reg)); - } + if let HdlSome(v) = &entry.inner().l1 { + if UnitNum::index_sim(&v.unit_num) == Some(unit_index) { + seen.insert(UnitOutRegNum::value_sim(&v.unit_out_reg)); } - RenameTableEntry::<_>::L2(_) => {} } } seen.len() @@ -581,7 +614,7 @@ impl MOpInUnitState { Self::FinishedAndOrCausedCancel => None, } } - fn is_completed(self) -> bool { + fn is_finished_and_or_caused_cancel(self) -> bool { match self { Self::NotYetEnqueued => false, Self::InputsNotReadySpeculative { .. } => false, @@ -1019,6 +1052,12 @@ impl ReorderBuffer { .rename_table_updates .push(update); } + fn all_mops_are_finished_and_or_caused_cancel(&self) -> bool { + self.renamed().next().is_none_or(|entry| { + entry.all_prior_mops_are_finished + && entry.mop_in_unit_state.is_finished_and_or_caused_cancel() + }) + } } type SimOnlyString = SimOnly; @@ -1222,7 +1261,9 @@ impl RenameExecuteRetireState { fn space_available_for_unit(&self, unit_index: usize) -> usize { let mut retval = self.config.get().unit_max_in_flight(unit_index); for renamed in self.rob.renamed() { - if renamed.unit_index == unit_index && !renamed.mop_in_unit_state.is_completed() { + if renamed.unit_index == unit_index + && !renamed.mop_in_unit_state.is_finished_and_or_caused_cancel() + { let Some(v) = NonZero::new(retval.get() - 1) else { return 0; }; @@ -1259,13 +1300,10 @@ impl RenameExecuteRetireState { .chain(self.retire_rename_table.entries.iter()) { #[hdl(sim)] - match entry.inner() { - RenameTableEntry::<_>::L1(entry) => { - if Some(unit_index) == UnitNum::index_sim(&entry.unit_num) { - allocated_regs[UnitOutRegNum::value_sim(&entry.unit_out_reg)] = true; - } + if let HdlSome(l1) = &entry.inner().l1 { + if Some(unit_index) == UnitNum::index_sim(&l1.unit_num) { + allocated_regs[UnitOutRegNum::value_sim(&l1.unit_out_reg)] = true; } - RenameTableEntry::<_>::L2(_) => {} } } allocated_regs.iter().position(|v| !v) @@ -1292,11 +1330,8 @@ impl RenameExecuteRetireState { .chain(self.retire_rename_table.entries.iter()) { #[hdl(sim)] - match entry.inner() { - RenameTableEntry::<_>::L1(_) => {} - RenameTableEntry::<_>::L2(entry) => { - allocated_regs[L2RegNum::value_sim(entry)] = true; - } + if let HdlSome(l2) = &entry.inner().l2 { + allocated_regs[L2RegNum::value_sim(l2)] = true; } } allocated_regs.iter().position(|v| !v) @@ -1499,13 +1534,10 @@ impl RenameExecuteRetireState { "try_rename: checking that mop src reg ({renamed:?}) doesn't conflict with picked reg" ); #[hdl(sim)] - match renamed.inner() { - RenameTableEntry::<_>::L1(v) => { - if reg_to_free == *v { - any_collisions = true; - } + if let HdlSome(l1) = &renamed.inner().l1 { + if reg_to_free == *l1 { + any_collisions = true; } - RenameTableEntry::<_>::L2(_) => {} } }); if any_collisions { @@ -1600,10 +1632,16 @@ impl RenameExecuteRetireState { let renamed = &self.rename_table.entries[MOpRegNum::reg_num_sim(&src_reg) as usize]; println!("renaming src[{index}] from {src_reg:?} to {renamed:?}"); #[hdl(sim)] - match renamed.inner() { - RenameTableEntry::<_>::L1(v) => v.clone(), - RenameTableEntry::<_>::L2(v) => { - needed_load.get_or_insert_with(|| v.clone()); + match &renamed.inner().l1 { + HdlSome(l1) => l1.clone(), + HdlNone => { + let l2 = #[hdl(sim)] + if let HdlSome(l2) = &renamed.inner().l2 { + l2 + } else { + unreachable!("rename table entry has neither l1 nor l2: {src_reg:?}"); + }; + needed_load.get_or_insert_with(|| l2.clone()); PRegNum[self.config].const_zero_sim() } } @@ -1647,7 +1685,19 @@ impl RenameExecuteRetireState { self.l2_reg_file_unit_index, ), ); - println!("try_rename: l2 reg file has no space and/or has no free output regs"); + println!("try_rename: read l2 reg"); + Err( + #[hdl(sim)] + RenameDelayedEntry::<_> { + mop: insn, + delayed_for_l2_store, + }, + ) + } else if self.rob.all_mops_are_finished_and_or_caused_cancel() { + todo!("dropping the L2 register file's outputs still doesn't fix deadlocks"); + // TODO: add proper WaW and WaR tracking for renamed registers + println!("try_rename: dropping all l2 reg file outputs"); + self.update_rename_table(&insn, RenameTableUpdate::DropAllL2RegFileOutputs); Err( #[hdl(sim)] RenameDelayedEntry::<_> { @@ -1656,7 +1706,9 @@ impl RenameExecuteRetireState { }, ) } else { - println!("try_rename: l2 reg file has no space and/or has no free output regs"); + println!( + "try_rename: waiting for all mops to finish before dropping all l2 reg file outputs" + ); Err( #[hdl(sim)] RenameDelayedEntry::<_> { @@ -1673,7 +1725,12 @@ impl RenameExecuteRetireState { ) .into_trace_as_string(); let renamed_dest_reg = #[hdl(sim)] - (RenameTableEntry[self.config]).L1(renamed_dest_reg); + RenameTableEntry::<_> { + l1: #[hdl(sim)] + (HdlOption[renamed_dest_reg.ty()]).HdlSome(renamed_dest_reg), + l2: #[hdl(sim)] + HdlNone(), + }; for unrenamed_reg_num in unrenamed_dest_regs { self.update_rename_table( &insn,