Commit 55466779 authored by qinsoon's avatar qinsoon

refactoring and added time profiling

parent 250d61a8
......@@ -9,4 +9,5 @@ lazy_static = "0.1.15"
log = "0.3.5"
simple_logger = "0.4.0"
nalgebra = "0.8.2"
linked-hash-map = "0.0.10"
\ No newline at end of file
linked-hash-map = "0.0.10"
hprof = "0.1.3"
......@@ -2,7 +2,7 @@ use ast::ir::*;
use ast::ptr::*;
use ast::types::*;
use ast::op::*;
use common::vector_as_str;
use utils::vec_utils::as_str as vector_as_str;
use std::fmt;
use std::cell::RefCell;
......@@ -34,33 +34,33 @@ impl fmt::Display for Instruction {
#[derive(Debug, Clone)]
pub enum Instruction_ {
// non-terminal instruction
// expressions
BinOp(BinOp, OpIndex, OpIndex),
BinOp(BinOp, OpIndex, OpIndex),
CmpOp(CmpOp, OpIndex, OpIndex),
// yields a tuple of results from the call
ExprCall{
data: CallData,
is_abort: bool, // T to abort, F to rethrow
},
// yields the memory value
Load{
is_ptr: bool,
order: MemoryOrder,
mem_loc: OpIndex
},
// yields nothing
Store{
is_ptr: bool,
order: MemoryOrder,
order: MemoryOrder,
mem_loc: OpIndex,
value: OpIndex
},
// yields pair (oldvalue, boolean (T = success, F = failure))
CmpXchg{
is_ptr: bool,
......@@ -71,7 +71,7 @@ pub enum Instruction_ {
expected_value: OpIndex,
desired_value: OpIndex
},
// yields old memory value
AtomicRMW{
is_ptr: bool, // T for iref, F for ptr
......@@ -80,62 +80,62 @@ pub enum Instruction_ {
mem_loc: OpIndex,
value: OpIndex // operand for op
},
// yields a reference of the type
New(P<MuType>),
// yields an iref of the type
AllocA(P<MuType>),
// yields ref
NewHybrid(P<MuType>, OpIndex),
// yields iref
AllocAHybrid(P<MuType>, OpIndex),
// yields stack ref
NewStack(OpIndex), // func
// TODO: common inst
// yields thread reference
NewThread(OpIndex, Vec<OpIndex>), // stack, args
// yields thread reference (thread resumes with exceptional value)
NewThreadExn(OpIndex, OpIndex), // stack, exception
// yields frame cursor
NewFrameCursor(OpIndex), // stack
// ref<T> -> iref<T>
GetIRef(OpIndex),
// iref|uptr<struct|hybrid<T>> int<M> -> iref|uptr<U>
GetFieldIRef{
is_ptr: bool,
base: OpIndex, // iref or uptr
index: OpIndex // constant
},
// iref|uptr<array<T N>> int<M> -> iref|uptr<T>
GetElementIRef{
is_ptr: bool,
base: OpIndex,
index: OpIndex // can be constant or ssa var
},
// iref|uptr<T> int<M> -> iref|uptr<T>
ShiftIRef{
is_ptr: bool,
base: OpIndex,
offset: OpIndex
},
// iref|uptr<hybrid<T U>> -> iref|uptr<U>
GetVarPartIRef{
is_ptr: bool,
base: OpIndex
},
// PushFrame{
// stack: P<Value>,
// func: P<Value>
......@@ -145,7 +145,7 @@ pub enum Instruction_ {
// }
Fence(MemoryOrder),
// terminal instruction
Return(Vec<OpIndex>),
ThreadExit, // TODO: common inst
......@@ -166,9 +166,9 @@ pub enum Instruction_ {
id: Option<WPID>,
disable_dest: Option<Destination>,
resume: ResumptionData
},
},
WPBranch{
wp: WPID,
wp: WPID,
disable_dest: Destination,
enable_dest: Destination
},
......@@ -204,18 +204,18 @@ impl Instruction_ {
},
&Instruction_::Load{is_ptr, mem_loc, order} => {
let ptr = select_value!(is_ptr, "PTR", "");
format!("LOAD {} {:?} {}", ptr, order, ops[mem_loc])
format!("LOAD {} {:?} {}", ptr, order, ops[mem_loc])
},
&Instruction_::Store{value, is_ptr, mem_loc, order} => {
let ptr = select_value!(is_ptr, "PTR", "");
format!("STORE {} {:?} {} {}", ptr, order, ops[mem_loc], ops[value])
},
&Instruction_::CmpXchg{is_ptr, is_weak, success_order, fail_order,
&Instruction_::CmpXchg{is_ptr, is_weak, success_order, fail_order,
mem_loc, expected_value, desired_value} => {
let ptr = select_value!(is_ptr, "PTR", "");
let weak = select_value!(is_weak, "WEAK", "");
format!("CMPXCHG {} {} {:?} {:?} {} {} {}",
ptr, weak, success_order, fail_order, ops[mem_loc], ops[expected_value], ops[desired_value])
format!("CMPXCHG {} {} {:?} {:?} {} {} {}",
ptr, weak, success_order, fail_order, ops[mem_loc], ops[expected_value], ops[desired_value])
},
&Instruction_::AtomicRMW{is_ptr, order, op, mem_loc, value} => {
let ptr = select_value!(is_ptr, "PTR", "");
......@@ -246,11 +246,11 @@ impl Instruction_ {
let ptr = select_value!(is_ptr, "PTR", "");
format!("GETVARPARTIREF {} {}", ptr, ops[base])
},
&Instruction_::Fence(order) => {
format!("FENCE {:?}", order)
},
&Instruction_::Return(ref vals) => format!("RET {}", op_vector_str(vals, ops)),
&Instruction_::ThreadExit => "THREADEXIT".to_string(),
&Instruction_::Throw(ref vals) => format!("THROW {}", op_vector_str(vals, ops)),
......@@ -286,14 +286,14 @@ impl Instruction_ {
}
}
ret.push_str("}}");
ret
},
&Instruction_::ExnInstruction{ref inner, ref resume} => {
format!("{} {}", inner.debug_str(ops), resume.debug_str(ops))
}
}
}
}
}
#[derive(Copy, Clone, Debug)]
......@@ -361,7 +361,7 @@ impl Destination {
}
}
ret.push(']');
ret
}
}
......@@ -376,7 +376,7 @@ impl DestArg {
fn debug_str(&self, ops: &Vec<P<TreeNode>>) -> String {
match self {
&DestArg::Normal(index) => format!("{}", ops[index]),
&DestArg::Freshbound(n) => format!("${}", n)
&DestArg::Freshbound(n) => format!("${}", n)
}
}
}
\ No newline at end of file
}
......@@ -2,7 +2,7 @@ use ast::ptr::P;
use ast::types::*;
use ast::inst::*;
use ast::op::*;
use common::vector_as_str;
use utils::vec_utils::as_str as vector_as_str;
use std::collections::HashMap;
use std::fmt;
......@@ -19,9 +19,9 @@ pub type OpIndex = usize;
#[derive(Debug)]
pub struct MuFunction {
pub fn_name: MuTag,
pub next_id: MuID,
pub sig: P<MuFuncSig>,
pub content: Option<FunctionContent>,
pub context: FunctionContext,
......@@ -35,13 +35,13 @@ impl MuFunction {
pub fn new(fn_name: MuTag, sig: P<MuFuncSig>) -> MuFunction {
MuFunction{
fn_name: fn_name,
next_id: RESERVED_NODE_IDS_FOR_MACHINE,
sig: sig,
content: None,
context: FunctionContext::new(),
next_id: RESERVED_NODE_IDS_FOR_MACHINE,
sig: sig,
content: None,
context: FunctionContext::new(),
block_trace: None}
}
fn get_id(&mut self) -> MuID {
let ret = self.next_id;
self.next_id += 1;
......@@ -54,7 +54,7 @@ impl MuFunction {
pub fn new_ssa(&mut self, tag: MuTag, ty: P<MuType>) -> P<TreeNode> {
let id = self.get_id();
self.context.value_tags.insert(tag, id);
self.context.values.insert(id, SSAVarEntry{id: id, tag: tag, ty: ty.clone(), use_count: Cell::new(0), expr: None});
......@@ -76,14 +76,14 @@ impl MuFunction {
v: TreeNode_::Value(v)
})
}
pub fn new_inst(&mut self, v: Instruction) -> P<TreeNode> {
P(TreeNode{
id: self.get_id(),
op: pick_op_code_for_inst(&v),
op: pick_op_code_for_inst(&v),
v: TreeNode_::Instruction(v),
})
}
}
}
#[derive(Debug)]
......@@ -132,20 +132,20 @@ impl FunctionContext {
values: HashMap::new()
}
}
pub fn get_value_by_tag(&self, tag: MuTag) -> Option<&SSAVarEntry> {
match self.value_tags.get(tag) {
Some(id) => self.get_value(*id),
None => None
}
}
pub fn get_value_mut_by_tag(&mut self, tag: MuTag) -> Option<&mut SSAVarEntry> {
let id : MuID = match self.value_tags.get(tag) {
Some(id) => *id,
None => return None
};
self.get_value_mut(id)
}
......@@ -249,11 +249,11 @@ impl TreeNode {
pub fn new_inst(id: MuID, v: Instruction) -> P<TreeNode> {
P(TreeNode{
id: id,
op: pick_op_code_for_inst(&v),
op: pick_op_code_for_inst(&v),
v: TreeNode_::Instruction(v),
})
}
}
pub fn extract_ssa_id(&self) -> Option<MuID> {
match self.v {
TreeNode_::Value(ref pv) => {
......@@ -265,18 +265,18 @@ impl TreeNode {
_ => None
}
}
pub fn clone_value(&self) -> P<Value> {
match self.v {
TreeNode_::Value(ref val) => val.clone(),
_ => panic!("expecting a value")
_ => panic!("expecting a value")
}
}
}
pub fn into_value(self) -> Option<P<Value>> {
match self.v {
TreeNode_::Value(val) => Some(val),
_ => None
_ => None
}
}
}
......@@ -329,7 +329,7 @@ impl Value {
_ => false
}
}
pub fn is_fp_reg(&self) -> bool {
match self.v {
Value_::SSAVar(_) => {
......@@ -342,7 +342,7 @@ impl Value {
_ => false
}
}
pub fn is_int_const(&self) -> bool {
match self.v {
Value_::Constant(_) => {
......@@ -355,7 +355,7 @@ impl Value {
_ => false
}
}
pub fn extract_ssa_id(&self) -> Option<MuID> {
match self.v {
Value_::SSAVar(id) => Some(id),
......
use ast::ptr::P;
use ast::ir::*;
use common::vector_as_str;
use utils::vec_utils::as_str as vector_as_str;
use std::fmt;
use std::collections::HashMap;
......@@ -16,43 +16,43 @@ pub enum MuType_ {
Float,
/// double
Double,
/// ref<T>
Ref (P<MuType>), // Box is needed for non-recursive enum
/// iref<T>: internal reference
IRef (P<MuType>),
/// weakref<T>
WeakRef (P<MuType>),
/// uptr<T>: unsafe pointer
UPtr (P<MuType>),
/// struct<T1 T2 ...>
Struct (MuTag),
/// array<T length>
Array (P<MuType>, usize),
/// hybrid<F1 F2 ... V>: a hybrid of fixed length parts and a variable length part
Hybrid (Vec<P<MuType>>, P<MuType>),
/// void
Void,
/// threadref
ThreadRef,
/// stackref
StackRef,
/// tagref64: hold a double or an int or an ref<void>
Tagref64,
/// vector<T length>
Vector (P<MuType>, usize),
/// funcref<@sig>
FuncRef (P<MuFuncSig>),
/// ufuncptr<@sig>
UFuncPtr (P<MuFuncSig>),
}
......@@ -68,7 +68,7 @@ impl fmt::Display for MuType_ {
&MuType_::WeakRef(ref ty) => write!(f, "weakref<{}>", ty),
&MuType_::UPtr(ref ty) => write!(f, "uptr<{}>", ty),
&MuType_::Array(ref ty, size) => write!(f, "array<{} {}>", ty, size),
&MuType_::Hybrid(ref fix_tys, ref var_ty) => write!(f, "hybrid<[{}] {}>", vector_as_str(fix_tys), var_ty),
&MuType_::Hybrid(ref fix_tys, ref var_ty) => write!(f, "hybrid<[{}] {}>", vector_as_str(fix_tys), var_ty),
&MuType_::Void => write!(f, "void"),
&MuType_::ThreadRef => write!(f, "threadref"),
&MuType_::StackRef => write!(f, "stackref"),
......@@ -102,7 +102,7 @@ impl fmt::Display for StructType_ {
}
}
write!(f, ">")
}
}
}
impl StructType_ {
......@@ -228,7 +228,7 @@ pub fn is_scalar(ty: &MuType) -> bool {
}
/// is a type traced by the garbage collector?
/// Note: An aggregated type is traced if any of its part is traced.
/// Note: An aggregated type is traced if any of its part is traced.
pub fn is_traced(ty: &MuType) -> bool {
match *ty {
MuType_::Ref(_) => true,
......@@ -242,13 +242,13 @@ pub fn is_traced(ty: &MuType) -> bool {
MuType_::Hybrid(ref fix_tys, ref var_ty) => {
is_traced(var_ty) ||
fix_tys.into_iter().map(|ty| is_traced(ty))
.fold(false, |ret, this| ret || this)
.fold(false, |ret, this| ret || this)
},
MuType_::Struct(tag) => {
let map = STRUCT_TAG_MAP.read().unwrap();
let struct_ty = map.get(tag).unwrap();
let ref field_tys = struct_ty.tys;
field_tys.into_iter().map(|ty| is_traced(&ty))
.fold(false, |ret, this| ret || this)
},
......@@ -269,7 +269,7 @@ pub fn is_native_safe(ty: &MuType) -> bool {
MuType_::UPtr(_) => true,
MuType_::UFuncPtr(_) => true,
MuType_::Hybrid(ref fix_tys, ref var_ty) => {
is_native_safe(var_ty) &&
is_native_safe(var_ty) &&
fix_tys.into_iter().map(|ty| is_native_safe(&ty))
.fold(true, |ret, this| ret && this)
},
......@@ -277,7 +277,7 @@ pub fn is_native_safe(ty: &MuType) -> bool {
let map = STRUCT_TAG_MAP.read().unwrap();
let struct_ty = map.get(tag).unwrap();
let ref field_tys = struct_ty.tys;
field_tys.into_iter().map(|ty| is_native_safe(&ty))
.fold(true, |ret, this| ret && this)
},
......@@ -303,5 +303,5 @@ pub struct MuFuncSig {
impl fmt::Display for MuFuncSig {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{}] -> [{}]", vector_as_str(&self.ret_tys), vector_as_str(&self.arg_tys))
}
}
\ No newline at end of file
}
}
use std::fmt;
macro_rules! select_value {
($cond: expr, $res1 : expr, $res2 : expr) => {
if $cond {
$res1
} else {
$res2
}
}
}
pub fn vector_as_str<T: fmt::Display>(vec: &Vec<T>) -> String {
let mut ret = String::new();
for i in 0..vec.len() {
ret.push_str(format!("{}", vec[i]).as_str());
if i != vec.len() - 1 {
ret.push_str(", ");
}
}
ret
}
\ No newline at end of file
#![allow(dead_code)]
use compiler::CompilerPass;
use compiler::PassExecutionResult;
use compiler;
use ast::ir::*;
use vm::context::VMContext;
......@@ -22,17 +20,17 @@ impl CompilerPass for CodeEmission {
fn name(&self) -> &'static str {
self.name
}
fn visit_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) {
use std::io::prelude::*;
use std::fs::File;
use std::fs;
use std::fs;
let compiled_funcs = vm_context.compiled_funcs().read().unwrap();
let mut cf = compiled_funcs.get(func.fn_name).unwrap().borrow();
let cf = compiled_funcs.get(func.fn_name).unwrap().borrow();
let code = cf.mc.emit();
// FIXME: this is only for asm backend
const EMIT_DIR : &'static str = "emit";
// match fs::remove_dir_all(EMIT_DIR) {
......@@ -40,19 +38,19 @@ impl CompilerPass for CodeEmission {
// Err(_) => {}
// }
match fs::create_dir(EMIT_DIR) {
Ok(dir) => {},
Ok(_) => {},
Err(_) => {}
}
let file_name = EMIT_DIR.to_string() + "/" + func.fn_name + ".s";
let mut file = match File::create(file_name.clone()) {
Err(why) => panic!("couldn't create emission file {}: {}", file_name, why),
Ok(file) => file
};
match file.write_all(code.as_slice()) {
Err(why) => panic!("couldn'd write to file {}: {}", file_name, why),
Ok(_) => println!("emit code to {}", file_name)
}
}
}
\ No newline at end of file
}
extern crate hprof;
use ast::ir::*;
use vm::context::VMContext;
......@@ -7,6 +9,16 @@ use std::sync::Arc;
pub mod passes;
pub mod backend;
pub use compiler::passes::CompilerPass;
pub use compiler::passes::PassExecutionResult;
pub use compiler::passes::PASS0_DEF_USE;
pub use compiler::passes::PASS1_TREE_GEN;
pub use compiler::passes::PASS2_CFA;
pub use compiler::passes::PASS3_TRACE_GEN;
pub use compiler::passes::PASS4_INST_SEL;
pub use compiler::passes::PASS5_REG_ALLOC;
pub use compiler::passes::PASS6_CODE_EMIT;
pub struct Compiler {
policy: RefCell<CompilerPolicy>,
vm: Arc<VMContext>
......@@ -19,21 +31,29 @@ impl Compiler {
vm: vm
}
}
pub fn compile(&self, func: &mut MuFunction) {
let _p = hprof::enter(func.fn_name);
let mut cur_pass = 0;
let n_passes = self.policy.borrow().passes.len();
let ref mut passes = self.policy.borrow_mut().passes;
while cur_pass < n_passes {
let _p = hprof::enter(passes[cur_pass].name());
let result = passes[cur_pass].execute(&self.vm, func);
match result {
PassExecutionResult::ProceedToNext => cur_pass += 1,
PassExecutionResult::GoBackTo(next) => cur_pass = next
}
drop(_p);
}
drop(_p);
hprof::profiler().print_timing();
}
}
......@@ -41,13 +61,6 @@ pub struct CompilerPolicy {
passes: Vec<Box<CompilerPass>>
}
pub const PASS0_DEF_USE : usize = 0;
pub const PASS1_TREE_GEN : usize = 1;
pub const PASS2_CFA : usize = 2;
pub const PASS3_TRACE_GEN : usize = 3;
pub const PASS4_INST_SEL : usize = 4;
pub const PASS5_REG_ALLOC : usize = 5;
impl CompilerPolicy {
pub fn default() -> CompilerPolicy {
let mut passes : Vec<Box<CompilerPass>> = vec![];
......@@ -57,59 +70,11 @@ impl CompilerPolicy {
passes.push(Box::new(passes::TraceGen::new()));
passes.push(Box::new(backend::inst_sel::InstructionSelection::new()));
passes.push(Box::new(backend::reg_alloc::RegisterAllocation::new()));
CompilerPolicy{passes: passes}
}
pub fn new(passes: Vec<Box<CompilerPass>>) -> CompilerPolicy {
CompilerPolicy{passes: passes}
}
}
pub enum PassExecutionResult {
ProceedToNext,
GoBackTo(usize)
}
#[allow(unused_variables)]
pub trait CompilerPass {
fn name(&self) -> &'static str;
fn execute(&mut self, vm_context: &VMContext, func: &mut MuFunction) -> PassExecutionResult {
debug!("---CompilerPass {} for {}---", self.name(), func.fn_name);
self.start_function(vm_context, func);
self.visit_function(vm_context, func);
self.finish_function(vm_context, func);
debug!("---finish---");
PassExecutionResult::ProceedToNext
}
fn visit_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) {
for (label, ref mut block) in func.content.as_mut().unwrap().blocks.iter_mut() {
debug!("block: {}", label);
self.start_block(vm_context, &mut func.context, block);
self.visit_block(vm_context, &mut func.context, block);
self.finish_block(vm_context, &mut func.context, block);
}
}
fn visit_block(&mut self, vm_context: &VMContext, func_context: &mut FunctionContext, block: &mut Block) {
for inst in block.content.as_mut().unwrap().body.iter_mut() {
debug!("{}", inst);
self.visit_inst(vm_context, func_context, inst);
}
}
fn start_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) {}
fn finish_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) {}
fn start_block(&mut self, vm_context: &VMContext, func_context: &mut FunctionContext, block: &mut Block) {}
fn finish_block(&mut self, vm_context: &VMContext, func_context: &mut FunctionContext, block: &mut Block) {}
fn visit_inst(&mut self, vm_context: &VMContext, func_context: &mut FunctionContext, node: &mut TreeNode) {}
}
use ast::ir::*;
use ast::inst::Instruction_::*;
use common::vector_as_str;
use utils::vec_utils::as_str as vector_as_str;
use vm::context::VMContext;
use compiler::CompilerPass;
......@@ -29,7 +29,7 @@ fn new_edge(cur: MuTag, edge: BlockEdge, stack: &mut Vec<MuTag>, visited: &mut V
let target = func.content.as_mut().unwrap().get_block_mut(edge.target);
target.control_flow.preds.push(cur);
}
// add target as current block's successors and start dfs