Commit 81ccdf53 authored by qinsoon's avatar qinsoon

[wip] added slowpath for inst sel and reg alloc

now we have 4 passes: fast_inst_sel, fast_reg_alloc, followed
by slow_inst_sel and slow_reg_alloc. This might make the
compilation pipeline more linear
parent ef62712d
......@@ -13,6 +13,7 @@ use runtime::entrypoints;
use runtime::entrypoints::RuntimeEntrypoint;
use compiler::CompilerPass;
use compiler::PassExecutionResult;
use compiler::backend;
use compiler::backend::x86_64;
use compiler::backend::x86_64::CodeGenerator;
......@@ -1282,6 +1283,22 @@ impl CompilerPass for InstructionSelection {
self.name
}
fn execute(&mut self, vm: &VM, func: &mut MuFunctionVersion) -> PassExecutionResult {
debug!("---CompilerPass {} for {}---", self.name(), func);
if !self.is_fastpath {
unimplemented!()
}
self.start_function(vm, func);
self.visit_function(vm, func);
self.finish_function(vm, func);
debug!("---finish---");
PassExecutionResult::ProceedToNext
}
#[allow(unused_variables)]
fn start_function(&mut self, vm: &VM, func_ver: &mut MuFunctionVersion) {
debug!("{}", self.name());
......
use ast::ir::MuID;
use compiler::backend::reg_alloc::graph_coloring::liveness::InterferenceGraph;
use compiler::backend::reg_alloc::graph_coloring::liveness::{Node, Move};
use compiler::backend;
use compiler::backend::reg_alloc::RegAllocFailure;
use utils::vec_utils;
use utils::LinkedHashSet;
......@@ -41,7 +42,7 @@ pub struct GraphColoring {
}
impl GraphColoring {
pub fn start (ig: InterferenceGraph) -> GraphColoring {
pub fn start (ig: InterferenceGraph) -> Result<GraphColoring, RegAllocFailure> {
let mut coloring = GraphColoring {
ig: ig,
......@@ -76,12 +77,13 @@ impl GraphColoring {
select_stack: Vec::new()
};
coloring.init();
coloring
match coloring.init() {
Ok(_) => Ok(coloring),
Err(fail) => Err(fail)
}
}
fn init (&mut self) {
fn init (&mut self) -> Result<(), RegAllocFailure> {
trace!("Initializing coloring allocator...");
// precolor for all machine registers
......@@ -127,7 +129,7 @@ impl GraphColoring {
&& self.worklist_spill.is_empty())
} {}
self.assign_colors();
self.assign_colors()
}
fn build(&mut self) {
......@@ -537,7 +539,7 @@ impl GraphColoring {
self.freeze_moves(m);
}
fn assign_colors(&mut self) {
fn assign_colors(&mut self) -> Result<(), RegAllocFailure> {
trace!("---coloring done---");
while !self.select_stack.is_empty() {
let n = self.select_stack.pop().unwrap();
......@@ -561,7 +563,7 @@ impl GraphColoring {
trace!("Color {} as {}", self.node_info(n), first_available_color);
if !backend::is_callee_saved(first_available_color) {
panic!("using a non-callee-saved register. need to go to compiler slowpath. Unimplemented");
return Err(RegAllocFailure::FailedForUsingCallerSaved);
}
self.colored_nodes.push(n);
......@@ -578,6 +580,8 @@ impl GraphColoring {
trace!("Color {} as {}", self.node_info(n), alias_color);
self.ig.color_node(n, alias_color);
}
Ok(())
}
pub fn spills(&self) -> Vec<MuID> {
......
#![allow(dead_code)]
use compiler;
use compiler::CompilerPass;
use compiler::PassExecutionResult;
use ast::ir::*;
......@@ -9,8 +10,7 @@ use compiler::backend::init_machine_regs_for_func;
mod graph_coloring;
enum RegAllocResult {
Success,
pub enum RegAllocFailure {
FailedForSpilling,
FailedForUsingCallerSaved
}
......@@ -30,7 +30,7 @@ impl RegisterAllocation {
#[allow(unused_variables)]
// returns true if we spill registers (which requires another instruction selection)
fn coloring(&mut self, vm: &VM, func: &mut MuFunctionVersion) -> bool {
fn coloring(&mut self, vm: &VM, func: &mut MuFunctionVersion) -> Result<(), RegAllocFailure> {
let compiled_funcs = vm.compiled_funcs().read().unwrap();
let mut cf = compiled_funcs.get(&func.id()).unwrap().write().unwrap();
......@@ -41,12 +41,18 @@ impl RegisterAllocation {
let liveness = graph_coloring::build_inteference_graph(&mut cf, func);
liveness.print();
let coloring = graph_coloring::GraphColoring::start(liveness);
let coloring = match graph_coloring::GraphColoring::start(liveness) {
Ok(coloring) => coloring,
Err(err) => {
return Err(err);
}
};
let spills = coloring.spills();
if !spills.is_empty() {
return false;
return Err(RegAllocFailure::FailedForSpilling);
}
// replace regs
......@@ -70,7 +76,7 @@ impl RegisterAllocation {
cf.mc().trace_mc();
true
Ok(())
}
}
......@@ -81,15 +87,20 @@ impl CompilerPass for RegisterAllocation {
fn execute(&mut self, vm: &VM, func: &mut MuFunctionVersion) -> PassExecutionResult {
debug!("---CompilerPass {} for {}---", self.name(), func);
if self.coloring(vm, func) {
debug!("---finish---");
PassExecutionResult::ProceedToNext
} else {
// PassExecutionResult::GoBackTo(compiler::PASS_INST_SEL)
if !self.is_fastpath {
unimplemented!()
}
match self.coloring(vm, func) {
// skip slow path
Ok(_) => PassExecutionResult::ProceedTo(compiler::PASS_PEEPHOLE),
// go back to instruction selection for spilled operands
Err(RegAllocFailure::FailedForSpilling) => PassExecutionResult::GoBackTo(compiler::PASS_FAST_INST_SEL),
// proceed to slow path
Err(RegAllocFailure::FailedForUsingCallerSaved) => PassExecutionResult::ProceedToNext
}
}
}
......@@ -18,8 +18,10 @@ pub use compiler::passes::PASS_DEF_USE;
pub use compiler::passes::PASS_TREE_GEN;
pub use compiler::passes::PASS_CFA;
pub use compiler::passes::PASS_TRACE_GEN;
pub use compiler::passes::PASS_INST_SEL;
pub use compiler::passes::PASS_REG_ALLOC;
pub use compiler::passes::PASS_FAST_INST_SEL;
pub use compiler::passes::PASS_FAST_REG_ALLOC;
pub use compiler::passes::PASS_SLOW_INST_SEL;
pub use compiler::passes::PASS_SLOW_REG_ALLOC;
pub use compiler::passes::PASS_PEEPHOLE;
pub use compiler::passes::PASS_CODE_EMIT;
......@@ -53,7 +55,8 @@ impl Compiler {
match result {
PassExecutionResult::ProceedToNext => cur_pass += 1,
PassExecutionResult::GoBackTo(next) => cur_pass = next
PassExecutionResult::ProceedTo(next)
| PassExecutionResult::GoBackTo(next) => cur_pass = next.get()
}
drop(_p);
......@@ -77,12 +80,20 @@ impl CompilerPolicy {
impl Default for CompilerPolicy {
fn default() -> Self {
let mut passes : Vec<Box<CompilerPass>> = vec![];
// ir level passes
passes.push(Box::new(passes::DefUse::new()));
passes.push(Box::new(passes::TreeGen::new()));
passes.push(Box::new(passes::ControlFlowAnalysis::new()));
passes.push(Box::new(passes::TraceGen::new()));
// fast path compilation - use callee saved registers only
passes.push(Box::new(backend::inst_sel::InstructionSelection::new(true)));
passes.push(Box::new(backend::reg_alloc::RegisterAllocation::new(true)));
// slow path compilation - use all registers
passes.push(Box::new(backend::inst_sel::InstructionSelection::new(false)));
passes.push(Box::new(backend::reg_alloc::RegisterAllocation::new(false)));
// machine code level passes
passes.push(Box::new(backend::peephole_opt::PeepholeOptimization::new()));
passes.push(Box::new(backend::code_emission::CodeEmission::new()));
......
......@@ -6,24 +6,31 @@ mod tree_gen;
mod control_flow;
mod trace_gen;
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct PassID(usize);
impl PassID {pub fn get(&self) -> usize{self.0}}
pub use compiler::passes::def_use::DefUse;
pub use compiler::passes::tree_gen::TreeGen;
pub use compiler::passes::control_flow::ControlFlowAnalysis;
pub use compiler::passes::trace_gen::TraceGen;
pub const PASS_IR_CHECK : usize = 0;
pub const PASS_DEF_USE : usize = 1;
pub const PASS_TREE_GEN : usize = 2;
pub const PASS_CFA : usize = 3;
pub const PASS_TRACE_GEN : usize = 4;
pub const PASS_INST_SEL : usize = 5;
pub const PASS_REG_ALLOC : usize = 6;
pub const PASS_PEEPHOLE : usize = 7;
pub const PASS_CODE_EMIT : usize = 8;
pub const PASS_IR_CHECK : PassID = PassID(0);
pub const PASS_DEF_USE : PassID = PassID(1);
pub const PASS_TREE_GEN : PassID = PassID(2);
pub const PASS_CFA : PassID = PassID(3);
pub const PASS_TRACE_GEN : PassID = PassID(4);
pub const PASS_FAST_INST_SEL : PassID = PassID(5);
pub const PASS_FAST_REG_ALLOC : PassID = PassID(6);
pub const PASS_SLOW_INST_SEL : PassID = PassID(7);
pub const PASS_SLOW_REG_ALLOC : PassID = PassID(8);
pub const PASS_PEEPHOLE : PassID = PassID(9);
pub const PASS_CODE_EMIT : PassID = PassID(10);
pub enum PassExecutionResult {
ProceedToNext,
GoBackTo(usize)
ProceedTo(PassID),
GoBackTo(PassID)
}
#[allow(unused_variables)]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment