Commit db578c90 authored by John Zhang's avatar John Zhang

Merge branch 'master' into jit-test

parents 4ca9d100 54361cad
......@@ -5,7 +5,7 @@ authors = [ "Your name <you@example.com>" ]
build = "build.rs"
[lib]
crate-type = ["staticlib", "rlib"]
crate-type = ["staticlib", "rlib", "dylib"]
[features]
default = ["aot"]
......
......@@ -256,7 +256,14 @@ impl FunctionContext {
op: pick_op_code_for_ssa(&val.ty),
v: TreeNode_::Value(val)
})
}
}
pub fn get_temp_display(&self, id: MuID) -> String {
match self.get_value(id) {
Some(entry) => format!("{}", entry.value()),
None => "CANT_FOUND_ID".to_string()
}
}
pub fn get_value(&self, id: MuID) -> Option<&SSAVarEntry> {
self.values.get(&id)
......
......@@ -21,6 +21,7 @@ use compiler::machine_code::CompiledFunction;
use compiler::frame::Frame;
use std::collections::HashMap;
use std::any::Any;
pub struct InstructionSelection {
name: &'static str,
......@@ -1286,6 +1287,10 @@ impl CompilerPass for InstructionSelection {
self.name
}
fn as_any(&self) -> &Any {
self
}
#[allow(unused_variables)]
fn start_function(&mut self, vm: &VM, func_ver: &mut MuFunctionVersion) {
debug!("{}", self.name());
......
......@@ -5,6 +5,8 @@ use ast::ir::*;
use vm::VM;
use compiler::backend::emit_code;
use std::any::Any;
pub struct CodeEmission {
name: &'static str
}
......@@ -22,6 +24,10 @@ impl CompilerPass for CodeEmission {
self.name
}
fn as_any(&self) -> &Any {
self
}
fn visit_function(&mut self, vm: &VM, func: &mut MuFunctionVersion) {
emit_code(func, vm);
}
......
......@@ -3,6 +3,8 @@ use ast::ir::*;
use vm::VM;
use compiler::machine_code::CompiledFunction;
use std::any::Any;
pub struct PeepholeOptimization {
name: &'static str
}
......@@ -54,6 +56,10 @@ impl CompilerPass for PeepholeOptimization {
fn name(&self) -> &'static str {
self.name
}
fn as_any(&self) -> &Any {
self
}
fn visit_function(&mut self, vm: &VM, func: &mut MuFunctionVersion) {
let compiled_funcs = vm.compiled_funcs().read().unwrap();
......
......@@ -15,7 +15,11 @@ use std::collections::HashMap;
const COALESCING : bool = true;
pub struct GraphColoring {
pub struct GraphColoring<'a> {
pub func: &'a mut MuFunctionVersion,
pub cf: &'a mut CompiledFunction,
pub vm: &'a VM,
pub ig: InterferenceGraph,
precolored: LinkedHashSet<Node>,
......@@ -44,12 +48,18 @@ pub struct GraphColoring {
select_stack: Vec<Node>
}
impl GraphColoring {
pub fn start (func: &mut MuFunctionVersion, cf: &mut CompiledFunction, vm: &VM) -> Result<GraphColoring, RegAllocFailure> {
impl <'a> GraphColoring<'a> {
pub fn start (func: &'a mut MuFunctionVersion, cf: &'a mut CompiledFunction, vm: &'a VM) -> Result<GraphColoring<'a>, RegAllocFailure> {
cf.mc().trace_mc();
let ig = graph_coloring::build_inteference_graph(cf, func);
let mut coloring = GraphColoring {
ig: graph_coloring::build_inteference_graph(cf, func),
func: func,
cf: cf,
vm: vm,
ig: ig,
precolored: LinkedHashSet::new(),
colors: {
......@@ -82,21 +92,14 @@ impl GraphColoring {
select_stack: Vec::new()
};
match coloring.regalloc(func, cf, vm) {
Ok(_) => Ok(coloring),
Err(fail) => Err(fail)
}
coloring.regalloc()
}
fn regalloc(&mut self, func: &mut MuFunctionVersion, cf: &mut CompiledFunction, vm: &VM) -> Result<(), RegAllocFailure> {
fn regalloc(mut self) -> Result<GraphColoring<'a>, RegAllocFailure> {
trace!("Initializing coloring allocator...");
trace!("---InterenceGraph---");
self.ig.print();
trace!("---All temps---");
for entry in func.context.values.values() {
trace!("{}", entry);
}
self.ig.print(&self.func.context);
// precolor for all machine registers
for reg in backend::all_regs().values() {
......@@ -117,7 +120,11 @@ impl GraphColoring {
self.initial.push(node);
let outdegree = self.ig.outdegree_of(node);
self.degree.insert(node, outdegree);
trace!("{} has a degree of {}", self.node_info(node), outdegree);
trace!("{} has a degree of {}", {
let id = self.ig.get_temp_of(node);
self.func.context.get_temp_display(id)
}, outdegree);
}
}
......@@ -152,12 +159,12 @@ impl GraphColoring {
}
}
self.rewrite_program(func, cf, vm);
self.rewrite_program();
GraphColoring::start(func, cf, vm);
return GraphColoring::start(self.func, self.cf, self.vm);
}
Ok(())
Ok(self)
}
fn build(&mut self) {
......@@ -612,23 +619,23 @@ impl GraphColoring {
Ok(())
}
fn rewrite_program(&mut self, func: &mut MuFunctionVersion, cf: &mut CompiledFunction, vm: &VM) {
fn rewrite_program(&mut self) {
let spills = self.spills();
let mut spilled_mem = HashMap::new();
// allocating frame slots for every spilled temp
for reg_id in spills.iter() {
let ssa_entry = match func.context.get_value(*reg_id) {
let ssa_entry = match self.func.context.get_value(*reg_id) {
Some(entry) => entry,
None => panic!("The spilled register {} is not in func context", reg_id)
};
let mem = cf.frame.alloc_slot_for_spilling(ssa_entry.value().clone(), vm);
let mem = self.cf.frame.alloc_slot_for_spilling(ssa_entry.value().clone(), self.vm);
spilled_mem.insert(*reg_id, mem);
}
let new_temps = backend::spill_rewrite(&spilled_mem, func, cf, vm);
let new_temps = backend::spill_rewrite(&spilled_mem, self.func, self.cf, self.vm);
//
// self.spilled_nodes.clear();
//
......
......@@ -124,14 +124,19 @@ impl InterferenceGraph {
fn add_move(&mut self, src: Node, dst: Node) {
self.moves.insert(Move{from: src, to: dst});
}
pub fn is_same_group(&self, node1: Node, node2: Node) -> bool {
self.nodes_property.get(&node1).unwrap().group
== self.nodes_property.get(&node2).unwrap().group
}
pub fn add_interference_edge(&mut self, from: Node, to: Node) {
// only if two nodes are from the same RegGroup,
// they may interefere
if self.nodes_property.get(&from).unwrap().group
== self.nodes_property.get(&to).unwrap().group {
self.matrix.as_mut().unwrap()[(from.0, to.0)] = true;
}
self.matrix.as_mut().unwrap()[(from.0, to.0)] = true;
}
pub fn is_interferenced_with(&self, node1: Node, node2: Node) -> bool {
self.matrix.as_ref().unwrap()[(node1.0, node2.0)]
|| self.matrix.as_ref().unwrap()[(node2.0, node1.0)]
}
pub fn color_node(&mut self, node: Node, color: MuID) {
......@@ -207,18 +212,21 @@ impl InterferenceGraph {
self.outdegree_of(node) + self.indegree_of(node)
}
pub fn print(&self) {
pub fn print(&self, context: &FunctionContext) {
println!("");
println!("Interference Graph");
println!("nodes:");
for id in self.nodes.keys() {
println!("Reg {} -> {:?}", id, self.nodes.get(&id).unwrap());
let val = context.get_value(*id).unwrap().value();
println!("Reg {} -> {:?}", val, self.nodes.get(&id).unwrap());
}
println!("color:");
for (n, c) in self.nodes_property.iter() {
println!("{:?} -> Color/Reg {:?}", n, c);
for (node, color) in self.nodes_property.iter() {
let node_val = context.get_value(self.get_temp_of(*node)).unwrap().value();
let color_val = context.get_value(color.temp).unwrap().value();
println!("Reg {} of {:?} -> Color/Reg {}", node_val, node, color_val);
}
println!("moves:");
for mov in self.moves.iter() {
......@@ -242,8 +250,11 @@ impl InterferenceGraph {
if matrix[(i, j)] {
let from_node = node_to_reg_id.get(&Node(i)).unwrap();
let to_node = node_to_reg_id.get(&Node(j)).unwrap();
println!("Reg {} -> Reg {}", from_node, to_node);
let from_val = context.get_value(*from_node).unwrap().value();
let to_val = context.get_value(*to_node).unwrap().value();
println!("Reg {} -> Reg {}", from_val, to_val);
}
}
}
......@@ -355,14 +366,29 @@ pub fn build_chaitin_briggs (cf: &mut CompiledFunction, func: &MuFunctionVersion
Some(liveout) => liveout.to_vec(),
None => panic!("cannot find liveout for block {}", block)
});
if cfg!(debug_assertions) {
trace!("Block{}: live out", block);
for ele in current_live.iter() {
trace!("{}", func.context.get_temp_display(*ele));
}
}
let range = cf.mc().get_block_range(&block);
if range.is_none() {
warn!("Block{}: has no range (no instructions?)", block);
continue;
}
trace!("Block{}: range = {:?}", block, range.as_ref().unwrap());
// for every inst I in reverse order
for i in range.unwrap().rev() {
if cfg!(debug_assertions) {
trace!("Block{}: Inst{}: start. current_live:", block, i);
for ele in current_live.iter() {
trace!("{}", func.context.get_temp_display(*ele));
}
}
let src : Option<MuID> = {
if cf.mc().is_move(i) {
let src = cf.mc().get_inst_reg_uses(i);
......@@ -377,6 +403,9 @@ pub fn build_chaitin_briggs (cf: &mut CompiledFunction, func: &MuFunctionVersion
if src.len() == 1 {
let node1 = ig.get_node(src[0]);
let node2 = ig.get_node(dst[0]);
trace!("add move between {} and {}",
func.context.get_temp_display(src[0]),
func.context.get_temp_display(dst[0]));
ig.add_move(node1, node2);
Some(src[0])
......@@ -388,21 +417,34 @@ pub fn build_chaitin_briggs (cf: &mut CompiledFunction, func: &MuFunctionVersion
None
}
};
trace!("Block{}: Inst{}: src={:?}", block, i, src);
// for every definition D in I
for d in cf.mc().get_inst_reg_defines(i) {
trace!("Block{}: Inst{}: for definition {}", block, i, func.context.get_temp_display(d));
// add an interference from D to every element E in Current_Live - {D}
// creating nodes if necessary
for e in current_live.iter() {
trace!("Block{}: Inst{}: for each live {}",
block, i,
func.context.get_temp_display(*e));
if src.is_none() || (src.is_some() && *e != src.unwrap()) {
let from = ig.get_node(d);
let to = ig.get_node(*e);
if !ig.is_same_node(from, to) && !ig.is_adj(from, to) {
if !ig.is_same_node(from, to) &&ig.is_same_group(from, to) && !ig.is_adj(from, to) {
if !ig.is_colored(from) {
trace!("Block{}: Inst{}: add interference between {} and {}",
block, i,
func.context.get_temp_display(d),
func.context.get_temp_display(*e));
ig.add_interference_edge(from, to);
}
if !ig.is_colored(to) {
trace!("Block{}: Inst{}: add interference between {} and {}",
block, i,
func.context.get_temp_display(*e),
func.context.get_temp_display(d));
ig.add_interference_edge(to, from);
}
}
......@@ -412,15 +454,28 @@ pub fn build_chaitin_briggs (cf: &mut CompiledFunction, func: &MuFunctionVersion
// for every definition D in I
for d in cf.mc().get_inst_reg_defines(i) {
trace!("Block{}: Inst{}: remove define {} from current_live",
block, i,
func.context.get_temp_display(d));
// remove D from Current_Live
current_live.remove(&d);
}
// for every use U in I
for u in cf.mc().get_inst_reg_uses(i) {
trace!("Block{}: Inst{}: add use {} to current_live",
block, i,
func.context.get_temp_display(u));
// add U to Current_live
current_live.insert(u);
}
if cfg!(debug_assertions) {
trace!("Block{}: Inst{}: done. current_live:", block, i);
for ele in current_live.iter() {
trace!("{}", func.context.get_temp_display(*ele));
}
}
}
}
......
......@@ -5,3 +5,92 @@ pub use compiler::backend::reg_alloc::graph_coloring::liveness::InterferenceGrap
//pub use compiler::backend::reg_alloc::graph_coloring::liveness::build as build_inteference_graph;
pub use compiler::backend::reg_alloc::graph_coloring::liveness::build_chaitin_briggs as build_inteference_graph;
pub use compiler::backend::reg_alloc::graph_coloring::coloring::GraphColoring;
use ast::ir::*;
use vm::VM;
use compiler;
use compiler::CompilerPass;
use compiler::PassExecutionResult;
use compiler::backend::init_machine_regs_for_func;
use compiler::backend;
use compiler::backend::reg_alloc::RegAllocFailure;
use std::collections::HashMap;
use std::any::Any;
pub struct RegisterAllocation {
name: &'static str,
}
impl RegisterAllocation {
pub fn new() -> RegisterAllocation {
RegisterAllocation {
name: "Register Allocation",
}
}
#[allow(unused_variables)]
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();
// initialize machine registers for the function context
init_machine_regs_for_func(&mut func.context);
let coloring = match GraphColoring::start(func, &mut cf, vm) {
Ok(coloring) => coloring,
Err(_) => panic!("error during coloring - unexpected")
};
// replace regs
trace!("Replacing Registers...");
for node in coloring.ig.nodes() {
let temp = coloring.ig.get_temp_of(node);
// skip machine registers
if temp < MACHINE_ID_END {
continue;
} else {
let alias = coloring.get_alias(node);
let machine_reg = match coloring.ig.get_color_of(alias) {
Some(reg) => reg,
None => panic!(
"Reg{}/{:?} (aliased as Reg{}/{:?}) is not assigned with a color",
coloring.ig.get_temp_of(node), node,
coloring.ig.get_temp_of(alias), alias)
};
trace!("replacing {} with {}", temp, machine_reg);
coloring.cf.mc_mut().replace_reg(temp, machine_reg);
coloring.cf.temps.insert(temp, machine_reg);
}
}
coloring.cf.mc().trace_mc();
Ok(())
}
}
impl CompilerPass for RegisterAllocation {
fn name(&self) -> &'static str {
self.name
}
fn as_any(&self) -> &Any {
self
}
fn execute(&mut self, vm: &VM, func: &mut MuFunctionVersion) -> PassExecutionResult {
debug!("---CompilerPass {} for {}---", self.name(), func);
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_INST_SEL),
}
}
}
#![allow(dead_code)]
use ast::ir::*;
use vm::VM;
use compiler;
use compiler::CompilerPass;
use compiler::PassExecutionResult;
use compiler::backend::init_machine_regs_for_func;
use compiler::backend;
use std::collections::HashMap;
mod graph_coloring;
pub mod graph_coloring;
pub enum RegAllocFailure {
FailedForSpilling,
}
pub struct RegisterAllocation {
name: &'static str,
}
impl RegisterAllocation {
pub fn new() -> RegisterAllocation {
RegisterAllocation {
name: "Register Allcoation",
}
}
#[allow(unused_variables)]
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();
// initialize machine registers for the function context
init_machine_regs_for_func(&mut func.context);
let coloring = match graph_coloring::GraphColoring::start(func, &mut cf, vm) {
Ok(coloring) => coloring,
Err(_) => panic!("error during coloring - unexpected")
};
// replace regs
trace!("Replacing Registers...");
for node in coloring.ig.nodes() {
let temp = coloring.ig.get_temp_of(node);
// skip machine registers
if temp < MACHINE_ID_END {
continue;
} else {
let alias = coloring.get_alias(node);
let machine_reg = match coloring.ig.get_color_of(alias) {
Some(reg) => reg,
None => panic!(
"Reg{}/{:?} (aliased as Reg{}/{:?}) is not assigned with a color",
coloring.ig.get_temp_of(node), node,
coloring.ig.get_temp_of(alias), alias)
};
trace!("replacing {} with {}", temp, machine_reg);
cf.mc_mut().replace_reg(temp, machine_reg);
cf.temps.insert(temp, machine_reg);
}
}
cf.mc().trace_mc();
Ok(())
}
}
impl CompilerPass for RegisterAllocation {
fn name(&self) -> &'static str {
self.name
}
fn execute(&mut self, vm: &VM, func: &mut MuFunctionVersion) -> PassExecutionResult {
debug!("---CompilerPass {} for {}---", self.name(), func);
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_INST_SEL),
}
}
}
pub use compiler::backend::reg_alloc::graph_coloring::RegisterAllocation;
\ No newline at end of file
......@@ -63,6 +63,10 @@ impl Compiler {
drop(_p);
hprof::profiler().print_timing();
}
pub fn get_policy(&self) -> &RefCell<CompilerPolicy> {
&self.policy
}
}
pub struct CompilerPolicy {
......
......@@ -2,9 +2,10 @@ use ast::ir::*;
use ast::inst::Instruction_::*;
use utils::vec_utils::as_str as vector_as_str;
use vm::VM;
use compiler::CompilerPass;
use std::any::Any;
pub struct ControlFlowAnalysis {
name: &'static str
}
......@@ -195,6 +196,10 @@ impl CompilerPass for ControlFlowAnalysis {
self.name
}
fn as_any(&self) -> &Any {
self
}
#[allow(unused_variables)]
fn visit_function(&mut self, vm: &VM, func: &mut MuFunctionVersion) {
let mut stack : Vec<MuID> = vec![];
......
......@@ -3,6 +3,7 @@ use ast::ptr::*;
use vm::VM;
use compiler::CompilerPass;
use std::any::Any;
pub struct DefUse {
name: &'static str,
......@@ -37,6 +38,10 @@ impl CompilerPass for DefUse {
fn name(&self) -> &'static str {
self.name
}
fn as_any(&self) -> &Any {
self
}
#[allow(unused_variables)]
fn start_block(&mut self, vm: &VM, func_context: &mut FunctionContext, block: &mut Block) {
......
......@@ -32,9 +32,12 @@ pub enum PassExecutionResult {
GoBackTo(PassID)
}
use std::any::Any;
#[allow(unused_variables)]
pub trait CompilerPass {
fn name(&self) -> &'static str;
fn as_any(&self) -> &Any;
fn execute(&mut self, vm: &VM, func: &mut MuFunctionVersion) -> PassExecutionResult {
debug!("---CompilerPass {} for {}---", self.name(), func);
......
......@@ -2,6 +2,8 @@ use ast::ir::*;
use vm::VM;
use compiler::CompilerPass;
use std::any::Any;
pub struct TraceGen {
name: &'static str
}
......@@ -16,6 +18,10 @@ impl CompilerPass for TraceGen {
fn name(&self) -> &'static str {
self.name
}
fn as_any(&self) -> &Any {
self
}
#[allow(unused_variables)]
fn visit_function(&mut self, vm: &VM, func: &mut MuFunctionVersion) {
......
......@@ -6,6 +6,8 @@ use vm::VM;
use compiler::CompilerPass;
use compiler::PassExecutionResult;
use std::any::Any;
pub struct TreeGen {
name: &'static str
}
......@@ -24,6 +26,10 @@ impl CompilerPass for TreeGen {
fn name(&self) -> &'static str {
self.name
}
fn as_any(&self) -> &Any {
self
}
fn execute(&mut self, vm: &VM, func: &mut MuFunctionVersion) -> PassExecutionResult {
debug!("---CompilerPass {} for {}---", self.name(), func);
......
......@@ -46,18 +46,18 @@ fn from_MuVM_ptr(ptr: *mut CMuVM) -> *mut MuVM {
}
#[inline(always)]
fn from_MuCtx_ptr<'v>(ptr: *mut CMuCtx) -> *mut MuCtx<'v> {
fn from_MuCtx_ptr<'v>(ptr: *mut CMuCtx) -> *mut MuCtx {
debug_assert!(!ptr.is_null());
unsafe {
(*ptr).header as *mut MuCtx<'v>
(*ptr).header as *mut MuCtx
}
}
#[inline(always)]
fn from_MuIRBuilder_ptr<'c>(ptr: *mut CMuIRBuilder) -> *mut MuIRBuilder<'c> {
fn from_MuIRBuilder_ptr<'c>(ptr: *mut CMuIRBuilder) -> *mut MuIRBuilder {
debug_assert!(!ptr.is_null());
unsafe {
(*ptr).header as *mut MuIRBuilder<'c>
(*ptr).header as *mut MuIRBuilder
}
}
......