GitLab will be upgraded on June 2nd 2020 at 2.00 pm (AEDT) to 3.00 pm (AEDT) due to Critical Security Patch Availability. During the update, GitLab and Mattermost services will not be available. If you have any concerns with this, please talk to local Gitlab admin team.

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
}
}
......
/*!
* This module contains the high-level implementation of the Mu API.
*
* Structs are written in idiomatic Rust code. The internal structures of these structs are
* implementation-specific. Methods are defined using `impl`.
*/
#![allow(unused_imports)] // work in progress