Commit 66cd7772 authored by qinsoon's avatar qinsoon

[wip] inlining

parent bd087834
......@@ -188,6 +188,78 @@ impl MuFunctionVersion {
v: TreeNode_::Instruction(v),
})
}
/// get Map(CallSiteID -> FuncID) that are called by this function
pub fn get_static_call_edges(&self) -> HashMap<MuID, MuID> {
let mut ret = HashMap::new();
let f_content = self.content.as_ref().unwrap();
for (blk_id, block) in f_content.blocks.iter() {
let block_content = block.content.as_ref().unwrap();
for inst in block_content.body.iter() {
match inst.v {
TreeNode_::Instruction(ref inst) => {
let ops = inst.ops.read().unwrap();
match inst.v {
Instruction_::ExprCall{ref data, ..}
| Instruction_::ExprCCall{ref data, ..}
| Instruction_::Call {ref data, ..}
| Instruction_::CCall {ref data, ..} => {
let ref callee = ops[data.func];
match callee.v {
TreeNode_::Instruction(_) => {},
TreeNode_::Value(ref pv) => match pv.v {
Value_::Constant(Constant::FuncRef(id)) => {ret.insert(inst.id(), id);},
_ => {}
}
}
},
_ => {
// do nothing
}
}
},
_ => {
unreachable!()
}
}
}
}
ret
}
pub fn has_throw(&self) -> bool {
let f_content = self.content.as_ref().unwrap();
for (blk_id, block) in f_content.blocks.iter() {
let block_content = block.content.as_ref().unwrap();
for inst in block_content.body.iter() {
match inst.v {
TreeNode_::Instruction(ref inst) => {
let ops = inst.ops.read().unwrap();
match inst.v {
Instruction_::Throw(_) => {return true;}
_ => {
// do nothing
}
}
},
_ => {
unreachable!()
}
}
}
}
false
}
}
#[derive(RustcEncodable, RustcDecodable, Clone)]
......@@ -310,6 +382,16 @@ impl Block {
pub fn is_exception_block(&self) -> bool {
return self.content.as_ref().unwrap().exn_arg.is_some()
}
pub fn number_of_irs(&self) -> usize {
if self.content.is_none() {
0
} else {
let content = self.content.as_ref().unwrap();
content.body.len()
}
}
}
#[derive(Debug, RustcEncodable, RustcDecodable, Clone)]
......@@ -482,6 +564,13 @@ impl TreeNode {
})
}
pub fn new_boxed_inst(v: Instruction) -> Box<TreeNode> {
Box::new(TreeNode{
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) => {
......@@ -514,6 +603,13 @@ impl TreeNode {
_ => None
}
}
pub fn into_inst(self) -> Option<Instruction> {
match self.v {
TreeNode_::Instruction(inst) => Some(inst),
_ => None
}
}
}
/// use +() to display a node
......
......@@ -64,6 +64,7 @@ impl CompilerPolicy {
impl Default for CompilerPolicy {
fn default() -> Self {
let mut passes : Vec<Box<CompilerPass>> = vec![];
passes.push(Box::new(passes::Inlining::new()));
// ir level passes
passes.push(Box::new(passes::DefUse::new()));
passes.push(Box::new(passes::TreeGen::new()));
......
This diff is collapsed.
......@@ -66,3 +66,25 @@ pub fn compile_fnc<'a>(fnc_name: &'static str, build_fnc: &'a Fn() -> VM) -> ll:
let dylib = aot::link_dylib(vec![Mu(fnc_name)], libname, &vm);
ll::Library::new(dylib.as_os_str()).unwrap()
}
pub fn compile_fncs<'a>(entry: &'static str, fnc_names: Vec<&'static str>, build_fnc: &'a Fn() -> VM) -> ll::Library {
VM::start_logging_trace;
let vm = Arc::new(build_fnc());
let compiler = Compiler::new(CompilerPolicy::default(), vm.clone());
for func in fnc_names.iter() {
let func_id = vm.id_of(func);
let funcs = vm.funcs().read().unwrap();
let func = funcs.get(&func_id).unwrap().read().unwrap();
let func_vers = vm.func_vers().read().unwrap();
let mut func_ver = func_vers.get(&func.cur_ver.unwrap()).unwrap().write().unwrap();
compiler.compile(&mut func_ver);
}
backend::emit_context(&vm);
let libname = &format!("lib{}.dylib", entry);
let dylib = aot::link_dylib(fnc_names.iter().map(|x| Mu(x)).collect(), libname, &vm);
ll::Library::new(dylib.as_os_str()).unwrap()
}
\ No newline at end of file
......@@ -736,6 +736,17 @@ impl <'a> VM {
pub fn func_vers(&self) -> &RwLock<HashMap<MuID, RwLock<MuFunctionVersion>>> {
&self.func_vers
}
pub fn get_cur_version_of(&self, fid: MuID) -> Option<MuID> {
let funcs_guard = self.funcs.read().unwrap();
match funcs_guard.get(&fid) {
Some(rwlock_func) => {
let func_guard = rwlock_func.read().unwrap();
func_guard.cur_ver
},
None => None
}
}
pub fn compiled_funcs(&self) -> &RwLock<HashMap<MuID, RwLock<CompiledFunction>>> {
&self.compiled_funcs
......
......@@ -38,6 +38,11 @@ macro_rules! typedef {
let $name = $vm.declare_type($vm.next_id(), MuType_::hybrid(Mu(stringify!($name)), vec![], $var_ty.clone()));
$vm.set_name($name.as_entity(), Mu(stringify!($name)));
};
(($vm: expr) $name: ident = mu_funcref($sig: ident)) => {
let $name = $vm.declare_type($vm.next_id(), MuType_::funcref($sig.clone()));
$vm.set_name($name.as_entity(), Mu(stringify!($name)));
}
}
macro_rules! constdef {
......@@ -309,6 +314,25 @@ macro_rules! inst {
});
};
// CALL
(($vm: expr, $fv: ident) $name: ident: $res: ident = EXPRCALL ($cc: expr, is_abort: $is_abort: expr) $func: ident ($($val: ident), +)) => {
let ops = vec![$func, $($val.clone()), *];
let ops_len = ops.len();
let $name = $fv.new_inst(Instruction{
hdr: MuEntityHeader::unnamed($vm.next_id()),
value: Some(vec![$res.clone_value()]),
ops: RwLock::new(ops),
v: Instruction_::ExprCall {
data: CallData {
func: 0,
args: (1..ops_len).collect(),
convention: $cc
},
is_abort: $is_abort
}
});
};
// RET
(($vm: expr, $fv: ident) $name: ident: RET ($($val: ident), +)) => {
let $name = $fv.new_inst(Instruction{
......
......@@ -11,4 +11,5 @@ mod test_int;
mod test_binop;
mod test_controlflow;
mod test_call;
mod test_mem_inst;
\ No newline at end of file
mod test_mem_inst;
mod test_inline;
\ No newline at end of file
extern crate libloading;
use mu::ast::types::*;
use mu::ast::ir::*;
use mu::ast::inst::*;
use mu::ast::op::*;
use mu::vm::*;
use mu::compiler::*;
use mu::testutil;
use std::sync::Arc;
use std::sync::RwLock;
use mu::testutil::aot;
#[test]
fn test_inline_add() {
let lib = testutil::compile_fncs("add_trampoline", vec!["add_trampoline", "add"], &inline_add);
unsafe {
let inline_add : libloading::Symbol<unsafe extern fn(u64, u64) -> u64> = lib.get(b"add_trampoline").unwrap();
let inline_add_1_1 = inline_add(1, 1);
println!("add(1, 1) = {}", inline_add_1_1);
assert!(inline_add_1_1 == 2);
}
}
fn inline_add() -> VM {
let vm = VM::new();
typedef! ((vm) int64 = mu_int(64));
funcsig! ((vm) sig = (int64, int64) -> (int64));
funcdecl! ((vm) <sig> add);
{
// add
funcdef! ((vm) <sig> add VERSION add_v1);
block! ((vm, add_v1) blk_entry);
ssa! ((vm, add_v1) <int64> x);
ssa! ((vm, add_v1) <int64> y);
ssa! ((vm, add_v1) <int64> res);
inst! ((vm, add_v1) blk_entry_add:
res = BINOP (BinOp::Add) x y
);
inst! ((vm, add_v1) blk_entry_ret:
RET (res)
);
define_block! ((vm, add_v1) blk_entry(x, y) {blk_entry_add, blk_entry_ret});
define_func_ver!((vm) add_v1 (entry: blk_entry) {blk_entry});
}
{
// add_trampoline
typedef! ((vm) funcref_to_sig = mu_funcref(sig));
constdef! ((vm) <funcref_to_sig> funcref_add = Constant::FuncRef(add));
funcdecl! ((vm) <sig> add_trampoline);
funcdef! ((vm) <sig> add_trampoline VERSION add_trampoline_v1);
block! ((vm, add_trampoline_v1) tramp_blk_entry);
ssa! ((vm, add_trampoline_v1) <int64> tramp_x);
ssa! ((vm, add_trampoline_v1) <int64> tramp_y);
consta! ((vm, add_trampoline_v1) funcref_add_local = funcref_add);
ssa! ((vm, add_trampoline_v1) <int64> tramp_res);
inst! ((vm, add_trampoline_v1) tramp_blk_call:
tramp_res = EXPRCALL (CallConvention::Mu, is_abort: false) funcref_add_local (tramp_x, tramp_y)
);
inst! ((vm, add_trampoline_v1) tramp_blk_ret:
RET (tramp_res)
);
define_block! ((vm, add_trampoline_v1) tramp_blk_entry(tramp_x, tramp_y) {tramp_blk_call, tramp_blk_ret});
define_func_ver!((vm) add_trampoline_v1 (entry: tramp_blk_entry) {tramp_blk_entry});
}
vm
}
\ No newline at end of file
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