Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
948ad3e
fix(codegen): prune spills by reachability, not dominance
greenhat Jul 5, 2026
8440f20
test(codegen): rewrite spill pruning tests on parsed IR and lit
greenhat Jul 5, 2026
ce155f5
fix(codegen): treat repetitive-region re-entry as reachable in spill …
greenhat Jul 5, 2026
46769e3
docs(codegen): describe reload coverage in path terms, not dominance
greenhat Jul 5, 2026
b0f5209
refactor(codegen): rename spill_reaches_reload to op_reaches
greenhat Jul 5, 2026
9d49292
test(codegen): pin the then-arm store count in the spill pruning lit …
greenhat Jul 5, 2026
9419c55
fix(codegen): answer op_reaches conservatively outside a single isola…
greenhat Jul 6, 2026
f2d0736
chore(codegen): mark the uncovered-reload diagnostic as an internal e…
greenhat Jul 6, 2026
6217bb2
test(codegen): anchor the reload to the join block in the spill lit test
greenhat Jul 6, 2026
f7cd840
fix(codegen): treat CFG-cycle re-entry of an enclosing block as reach…
greenhat Jul 6, 2026
e543da9
test(codegen): name the op_reaches unit tests after their subject
greenhat Jul 6, 2026
55ff70d
refactor(codegen): pair reloads with spills via the analysis value in…
greenhat Jul 6, 2026
f6f37b3
docs(codegen): document the reachability helpers' subtle contracts
greenhat Jul 6, 2026
ca7b4dc
fix(codegen): key spill locals by the analysis value, not the spill o…
greenhat Jul 6, 2026
7928657
refactor(hir): replace op_reaches with Operation::reachability
greenhat Jul 10, 2026
76c18ec
fix(hir): tighten sibling, guarantee, and enclosure Reachability clas…
greenhat Aug 3, 2026
f8571df
perf(codegen): cache block reachability and index live reloads by value
greenhat Aug 3, 2026
95b5d57
hir: make same-block reachability conservative
bitwalker Aug 8, 2026
7027671
hir: make enclosure reachability directional
bitwalker Aug 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 22 additions & 6 deletions dialects/hir/src/transforms/spill.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use alloc::rc::Rc;
use alloc::{format, rc::Rc};

use midenc_hir::{
BlockRef, BuilderExt, EntityMut, Op, OpBuilder, OperationName, OperationRef, Report, Rewriter,
Expand All @@ -8,11 +8,16 @@ use midenc_hir::{
pass::{Pass, PassExecutionState, PostPassStatus},
};
use midenc_hir_analysis::analyses::SpillAnalysis;
use midenc_hir_transform::{self as transforms, ReloadLike, SpillLike, TransformSpillsInterface};
use midenc_hir_transform::{self as transforms, SpillLike, TransformSpillsInterface};

#[derive(Default)]
pub struct TransformSpills;

midenc_hir::inventory::submit!(::midenc_hir::pass::registry::PassInfo::new::<TransformSpills>(
"transform-spills",
"materialize operand stack spills as stores/loads of procedure locals"
));

impl Pass for TransformSpills {
type Target = Function;

Expand Down Expand Up @@ -129,14 +134,18 @@ impl TransformSpillsInterface for TransformSpillsImpl {
&mut self,
rewriter: &mut dyn Rewriter,
spill: OperationRef,
value: ValueRef,
) -> Result<(), Report> {
use crate::HirOpBuilder;

// The local is keyed by the analysis's identity of the spilled value; the stored operand
// is the op's current one, which SSA reconstruction may have rewritten (e.g. to a
// preceding reload's result), but always carries the same runtime value.
let spilled = spill.borrow().as_trait::<dyn SpillLike>().unwrap().spilled_value();
let mut function = self.function;
let local = *self.locals.entry(spilled).or_insert_with(|| {
let local = *self.locals.entry(value).or_insert_with(|| {
let mut function = function.borrow_mut();
function.alloc_local(spilled.borrow().ty().clone())
function.alloc_local(value.borrow().ty().clone())
});

let store = rewriter.store_local(local, spilled, spill.span())?;
Expand All @@ -150,11 +159,18 @@ impl TransformSpillsInterface for TransformSpillsImpl {
&mut self,
rewriter: &mut dyn Rewriter,
reload: OperationRef,
value: ValueRef,
) -> Result<(), Report> {
use crate::HirOpBuilder;

let spilled = reload.borrow().as_trait::<dyn ReloadLike>().unwrap().spilled_value();
let local = self.locals[&spilled];
let Some(local) = self.locals.get(&value).copied() else {
let function = self.function.borrow();
let function = function.get_name();
return Err(Report::msg(format!(
"internal error: live reload of {value} in {function} has no corresponding spill: \
every kept reload must be covered by at least one spill of the same value"
)));
};
let reloaded = rewriter.load_local(local, reload.span())?;

rewriter.replace_op_with_values(reload, &[Some(reloaded)]);
Expand Down
Loading
Loading