diff --git a/lib/cretonne/src/context.rs b/lib/cretonne/src/context.rs index 31a1569d5f..ce1e8b50ff 100644 --- a/lib/cretonne/src/context.rs +++ b/lib/cretonne/src/context.rs @@ -3,10 +3,18 @@ //! When compiling many small functions, it is important to avoid repeatedly allocating and //! deallocating the data structures needed for compilation. The `Context` struct is used to hold //! on to memory allocations between function compilations. +//! +//! The context does not hold a `TargetIsa` instance which has to be provided as an argument +//! instead. This is because an ISA instance is immutable and can be used by multiple compilation +//! contexts concurrently. Typically, you would have one context per compilation thread and only a +//! single ISA instance. use cfg::ControlFlowGraph; use dominator_tree::DominatorTree; use ir::Function; +use isa::TargetIsa; +use legalize_function; +use regalloc; /// Persistent data structures and compilation pipeline. pub struct Context { @@ -18,6 +26,9 @@ pub struct Context { /// Dominator tree for `func`. pub domtree: DominatorTree, + + /// Register allocation context. + pub regalloc: regalloc::Context, } impl Context { @@ -30,12 +41,23 @@ impl Context { func: Function::new(), cfg: ControlFlowGraph::new(), domtree: DominatorTree::new(), + regalloc: regalloc::Context::new(), } } + /// Run the legalizer for `isa` on the function. + pub fn legalize(&mut self, isa: &TargetIsa) { + legalize_function(&mut self.func, isa); + } + /// Recompute the control flow graph and dominator tree. pub fn flowgraph(&mut self) { self.cfg.compute(&self.func); self.domtree.compute(&self.func, &self.cfg); } + + /// Run the register allocator. + pub fn regalloc(&mut self, isa: &TargetIsa) { + self.regalloc.run(isa, &mut self.func, &self.cfg, &self.domtree); + } } diff --git a/lib/cretonne/src/regalloc/context.rs b/lib/cretonne/src/regalloc/context.rs new file mode 100644 index 0000000000..75863fbc63 --- /dev/null +++ b/lib/cretonne/src/regalloc/context.rs @@ -0,0 +1,57 @@ +//! Register allocator context. +//! +//! The `Context` struct contains data structures that should be preserved across invocations of +//! the register allocator algorithm. This doesn't preserve any data between functions, but it +//! avoids allocating data structures independently for each function begin compiled. + +use dominator_tree::DominatorTree; +use ir::Function; +use regalloc::coloring::Coloring; +use regalloc::live_value_tracker::LiveValueTracker; +use regalloc::liveness::Liveness; +use isa::TargetIsa; +use cfg::ControlFlowGraph; + +/// Persistent memory allocations for register allocation. +pub struct Context { + liveness: Liveness, + tracker: LiveValueTracker, + coloring: Coloring, +} + +impl Context { + /// Create a new context for register allocation. + /// + /// This context should be reused for multiple functions in order to avoid repeated memory + /// allocations. + pub fn new() -> Context { + Context { + liveness: Liveness::new(), + tracker: LiveValueTracker::new(), + coloring: Coloring::new(), + } + } + + /// Allocate registers in `func`. + /// + /// After register allocation, all values in `func` have been assigned to a register or stack + /// location that is consistent with instruction encoding constraints. + pub fn run(&mut self, + isa: &TargetIsa, + func: &mut Function, + cfg: &ControlFlowGraph, + domtree: &DominatorTree) { + // `Liveness` and `Coloring` are self-clearing. + // Tracker state (dominator live sets) is actually reused between the spilling and coloring + // phases. + self.tracker.clear(); + + // First pass: Liveness analysis. + self.liveness.compute(isa, func, cfg); + + // TODO: Second pass: Spilling. + + // Third pass: Reload and coloring. + self.coloring.run(isa, func, domtree, &mut self.liveness, &mut self.tracker); + } +} diff --git a/lib/cretonne/src/regalloc/liveness.rs b/lib/cretonne/src/regalloc/liveness.rs index a8591e8597..524b50e8ea 100644 --- a/lib/cretonne/src/regalloc/liveness.rs +++ b/lib/cretonne/src/regalloc/liveness.rs @@ -291,7 +291,7 @@ impl Liveness { /// Compute the live ranges of all SSA values used in `func`. /// This clears out any existing analysis stored in this data structure. - pub fn compute(&mut self, func: &Function, cfg: &ControlFlowGraph, isa: &TargetIsa) { + pub fn compute(&mut self, isa: &TargetIsa, func: &Function, cfg: &ControlFlowGraph) { self.ranges.clear(); // Get ISA data structures used for computing live range affinities. diff --git a/lib/cretonne/src/regalloc/mod.rs b/lib/cretonne/src/regalloc/mod.rs index 19bb350499..fb19286670 100644 --- a/lib/cretonne/src/regalloc/mod.rs +++ b/lib/cretonne/src/regalloc/mod.rs @@ -9,3 +9,6 @@ pub mod live_value_tracker; pub mod coloring; mod affinity; +mod context; + +pub use self::context::Context;