Phase 29aa P3: Jump→Return single-pred rc propagation

This commit is contained in:
2025-12-28 01:16:52 +09:00
parent ed68e48ed1
commit 94ad562aa5
5 changed files with 200 additions and 11 deletions

View File

@ -21,7 +21,7 @@ use crate::mir::MirModule;
#[cfg(feature = "rc-insertion-minimal")]
use crate::ast::Span;
#[cfg(feature = "rc-insertion-minimal")]
use crate::mir::{MirInstruction, ValueId};
use crate::mir::{BasicBlockId, MirInstruction, ValueId};
#[cfg(feature = "rc-insertion-minimal")]
use crate::mir::types::ConstValue;
#[cfg(feature = "rc-insertion-minimal")]
@ -109,7 +109,54 @@ pub fn insert_rc_instructions(module: &mut MirModule) -> RcInsertionStats {
for (_name, func) in &mut module.functions {
stats.functions_processed += 1;
for (_bid, block) in &mut func.blocks {
let mut predecessors: HashMap<BasicBlockId, Vec<BasicBlockId>> = HashMap::new();
for (bid, b) in &func.blocks {
let Some(term) = b.terminator.as_ref() else {
continue;
};
match term {
MirInstruction::Jump { target, .. } => {
predecessors.entry(*target).or_default().push(*bid);
}
MirInstruction::Branch { then_bb, else_bb, .. } => {
predecessors.entry(*then_bb).or_default().push(*bid);
predecessors.entry(*else_bb).or_default().push(*bid);
}
_ => {}
}
}
let mut propagated_initial: HashMap<BasicBlockId, HashMap<ValueId, ValueId>> =
HashMap::new();
for (bid, b) in &func.blocks {
if !matches!(b.terminator.as_ref(), Some(MirInstruction::Return { .. })) {
continue;
}
let preds = predecessors.get(bid).map(|p| p.as_slice()).unwrap_or(&[]);
if preds.len() != 1 {
continue;
}
let pred_id = preds[0];
let Some(pred_block) = func.blocks.get(&pred_id) else {
continue;
};
match pred_block.terminator.as_ref() {
Some(MirInstruction::Jump { target, .. }) if *target == *bid => {
let empty_state: HashMap<ValueId, ValueId> = HashMap::new();
let (_plan, out_state) = plan_rc_insertion_for_block(
&pred_block.instructions,
pred_block.terminator.as_ref(),
&empty_state,
);
if !out_state.is_empty() {
propagated_initial.insert(*bid, out_state);
}
}
_ => {}
}
}
for (bid, block) in &mut func.blocks {
stats.blocks_visited += 1;
// Take ownership of instructions to rebuild with inserted releases
@ -124,7 +171,29 @@ pub fn insert_rc_instructions(module: &mut MirModule) -> RcInsertionStats {
spans.push(Span::unknown());
}
let plan = plan_rc_insertion_for_block(&insts, terminator.as_ref());
let empty_state: HashMap<ValueId, ValueId> = HashMap::new();
let initial_state = propagated_initial.get(bid);
if let Some(state) = initial_state {
let pred_count = predecessors.get(bid).map(|p| p.len()).unwrap_or(0);
debug_assert!(
pred_count == 1,
"rc_insertion: initial state requires single predecessor"
);
debug_assert!(
matches!(terminator.as_ref(), Some(MirInstruction::Return { .. })),
"rc_insertion: initial state must target Return block"
);
debug_assert!(
!state.is_empty(),
"rc_insertion: initial state for Return block must be non-empty"
);
}
let (plan, _end_state) = plan_rc_insertion_for_block(
&insts,
terminator.as_ref(),
initial_state.unwrap_or(&empty_state),
);
let (new_insts, new_spans, new_terminator, new_terminator_span) =
apply_rc_plan(insts, spans, terminator, terminator_span, plan, &mut stats);
@ -143,10 +212,11 @@ pub fn insert_rc_instructions(module: &mut MirModule) -> RcInsertionStats {
fn plan_rc_insertion_for_block(
insts: &[MirInstruction],
terminator: Option<&MirInstruction>,
) -> RcPlan {
initial_ptr_to_value: &HashMap<ValueId, ValueId>,
) -> (RcPlan, HashMap<ValueId, ValueId>) {
let mut plan = RcPlan { drops: Vec::new() };
let mut ptr_to_value: HashMap<ValueId, ValueId> = HashMap::new();
let mut ptr_to_value: HashMap<ValueId, ValueId> = initial_ptr_to_value.clone();
let mut null_values: HashSet<ValueId> = HashSet::new();
for (idx, inst) in insts.iter().enumerate() {
@ -211,7 +281,7 @@ fn plan_rc_insertion_for_block(
}
}
plan
(plan, ptr_to_value)
}
#[cfg(feature = "rc-insertion-minimal")]