GitLab will continue to be upgraded from 11.4.5-ce.0 on November 25th 2019 at 4.00pm (AEDT) to 5.00pm (AEDT) due to Critical Security Patch Availability. During the update, GitLab and Mattermost services will not be available.

Commit f83e4dde authored by qinsoon's avatar qinsoon

[wip] debugging

parent b77b1887
......@@ -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);
......
......@@ -73,6 +73,110 @@ fn test_ir_liveness_fac() {
assert!(vec_utils::is_identical_to_str_ignore_order(block_2_liveout, expect));
}
use mu::compiler::backend::reg_alloc::graph_coloring::GraphColoring;
use mu::compiler::backend::reg_alloc::graph_coloring::InterferenceGraph;
use mu::compiler::backend::init_machine_regs_for_func;
use std::any::Any;
struct InspectInterferenceGraph {
name: &'static str,
ig: Option<InterferenceGraph>,
}
impl InspectInterferenceGraph {
pub fn new() -> InspectInterferenceGraph {
InspectInterferenceGraph {
name: "Inspect Interference Graph",
ig: None
}
}
}
impl CompilerPass for InspectInterferenceGraph {
fn name(&self) -> &'static str {
self.name