Commit c910df03 authored by qinsoon's avatar qinsoon

[wip] add machine registers

parent e7b85485
......@@ -82,7 +82,7 @@ impl MuFunction {
op: pick_op_code_for_inst(&v),
v: TreeNode_::Instruction(v),
})
}
}
}
#[derive(Debug)]
......@@ -225,6 +225,15 @@ pub struct TreeNode {
}
impl TreeNode {
// this is a hack to allow creating TreeNode without using a &mut MuFunction
pub fn new_inst(id: MuID, v: Instruction) -> P<TreeNode> {
P(TreeNode{
id: id,
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) => {
......@@ -237,10 +246,10 @@ impl TreeNode {
}
}
pub fn clone_value(&self) -> Option<P<Value>> {
pub fn clone_value(&self) -> P<Value> {
match self.v {
TreeNode_::Value(ref val) => Some(val.clone()),
_ => None
TreeNode_::Value(ref val) => val.clone(),
_ => panic!("expecting a value")
}
}
......
pub mod inst_sel;
mod temp;
pub use compiler::backend::temp::Temporary;
#[cfg(target_arch = "x86_64")]
mod x86_64;
......
use ast::types::*;
use ast::ir::*;
pub struct Temporary {
pub hll_id: MuID
}
\ No newline at end of file
......@@ -104,26 +104,24 @@ impl <'a> InstructionSelection {
trace!("deal with pre-call convention");
let ops = inst.ops.borrow();
let mut gpr_arg_count = 0;
let mut fpr_arg_count = 0;
for arg_index in data.args.iter() {
let ref arg = ops[*arg_index];
trace!("arg {}", arg);
match arg.op {
OpCode::RegI64 | OpCode::IntImmI64 => {
trace!("emit move-gpr-arg");
// move to register
},
OpCode::RegFP | OpCode::FPImm => {
trace!("emit move-fpr-arg");
// move to fp register
},
_ => {
trace!("nested: compute arg");
// instself for arg first
self.instruction_select(arg);
// mov based on type
trace!("emit move-arg after computing arg");
}
if self.match_ireg(arg) {
let arg = self.emit_ireg(arg);
self.backend.emit_mov_r64_r64(&x86_64::ARGUMENT_GPRs[gpr_arg_count], &arg);
gpr_arg_count += 1;
} else if self.match_iimm(arg) {
let arg = self.emit_get_iimm(arg);
self.backend.emit_mov_r64_imm32(&x86_64::ARGUMENT_GPRs[gpr_arg_count], arg);
gpr_arg_count += 1;
} else {
unimplemented!();
}
}
......
#![allow(dead_code)]
#![allow(non_upper_case_globals)]
pub mod inst_sel;
mod codegen;
......@@ -8,9 +11,109 @@ pub use compiler::backend::x86_64::asm_backend::ASMCodeGen;
use ast::ptr::P;
use ast::ir::*;
use ast::types::*;
macro_rules! GPR {
($name: expr, $id: expr) => {
P(Value {
tag: $name,
ty: GPR_TY.clone(),
v: Value_::SSAVar($id)
})
};
}
macro_rules! FPR {
($name: expr, $id: expr) => {
P(Value {
tag: $name,
ty: FPR_TY.clone(),
v: Value_::SSAVar($id)
})
};
}
lazy_static! {
pub static ref GPR_TY : P<MuType> = P(MuType::int(64));
pub static ref FPR_TY : P<MuType> = P(MuType::double());
}
// put into several segments to avoid 'recursion limit reached' error
lazy_static! {
pub static ref RAX : P<Value> = GPR!("rax", 0);
pub static ref RCX : P<Value> = GPR!("rcx", 1);
pub static ref RDX : P<Value> = GPR!("rdx", 2);
pub static ref RBX : P<Value> = GPR!("rbx", 3);
pub static ref RSP : P<Value> = GPR!("rsp", 4);
pub static ref RBP : P<Value> = GPR!("rbp", 5);
pub static ref RSI : P<Value> = GPR!("rsi", 6);
pub static ref RDI : P<Value> = GPR!("rdi", 7);
pub static ref R8 : P<Value> = GPR!("r8", 8);
pub static ref R9 : P<Value> = GPR!("r9", 9);
pub static ref R10 : P<Value> = GPR!("r10", 10);
pub static ref R11 : P<Value> = GPR!("r11", 11);
pub static ref R12 : P<Value> = GPR!("r12", 12);
pub static ref R13 : P<Value> = GPR!("r13", 13);
pub static ref R14 : P<Value> = GPR!("r14", 14);
pub static ref R15 : P<Value> = GPR!("r15", 15);
pub static ref RETURN_GPRs : [P<Value>; 2] = [
RAX.clone(),
RDX.clone(),
];
pub static ref ARGUMENT_GPRs : [P<Value>; 6] = [
RDI.clone(),
RSI.clone(),
RDX.clone(),
RCX.clone(),
R8.clone(),
R9.clone()
];
pub static ref CALLEE_SAVED_GPRs : [P<Value>; 6] = [
RBX.clone(),
RBP.clone(),
R12.clone(),
R13.clone(),
R14.clone(),
R15.clone()
];
}
lazy_static!{
pub static ref XMM0 : P<Value> = FPR!("xmm0", 20);
pub static ref XMM1 : P<Value> = FPR!("xmm1", 21);
pub static ref XMM2 : P<Value> = FPR!("xmm2", 22);
pub static ref XMM3 : P<Value> = FPR!("xmm3", 23);
pub static ref XMM4 : P<Value> = FPR!("xmm4", 24);
pub static ref XMM5 : P<Value> = FPR!("xmm5", 25);
pub static ref XMM6 : P<Value> = FPR!("xmm6", 26);
pub static ref XMM7 : P<Value> = FPR!("xmm7", 27);
pub static ref XMM8 : P<Value> = FPR!("xmm8", 28);
pub static ref XMM9 : P<Value> = FPR!("xmm9", 29);
pub static ref XMM10 : P<Value> = FPR!("xmm10",30);
pub static ref XMM11 : P<Value> = FPR!("xmm11",31);
pub static ref XMM12 : P<Value> = FPR!("xmm12",32);
pub static ref XMM13 : P<Value> = FPR!("xmm13",33);
pub static ref XMM14 : P<Value> = FPR!("xmm14",34);
pub static ref XMM15 : P<Value> = FPR!("xmm15",35);
pub static ref RETURN_FPRs : [P<Value>; 2] = [
XMM0.clone(),
XMM1.clone()
];
pub static ref ARGUMENT_FPRs : [P<Value>; 6] = [
XMM2.clone(),
XMM3.clone(),
XMM4.clone(),
XMM5.clone(),
XMM6.clone(),
XMM7.clone()
];
pub static ref CALLEE_SAVED_FPRs : [P<Value>; 0] = [];
}
pub fn is_valid_x86_imm(op: &P<Value>) -> bool {
......
......@@ -27,86 +27,93 @@ impl CompilerPass for TreeGen {
fn execute(&mut self, vm_context: &VMContext, func: &mut MuFunction) {
debug!("---CompilerPass {} for {}---", self.name(), func.fn_name);
for (label, ref mut block) in func.content.as_mut().unwrap().blocks.iter_mut() {
// take its content, we will need to put it back
let mut content = block.content.take().unwrap();
let body = content.body;
let mut new_body = vec![];
trace!("check block {}", label);
trace!("");
for node in body.into_iter() {
trace!("check inst: {}", node);
match &node.v {
&TreeNode_::Instruction(ref inst) => {
// check if any operands can be replaced by expression
{
trace!("check if we can replace any operand with inst");
let mut ops = inst.ops.borrow_mut();
for index in 0..ops.len() {
let possible_ssa_id = ops[index].extract_ssa_id();
if possible_ssa_id.is_some() {
let entry_value = func.context.get_value_mut(possible_ssa_id.unwrap()).unwrap();
if entry_value.expr.is_some() {
// replace the node with its expr
let expr = entry_value.expr.take().unwrap();
{
let ref mut func_content = func.content;
let ref mut context = func.context;
for (label, ref mut block) in func_content.as_mut().unwrap().blocks.iter_mut() {
// take its content, we will need to put it back
let mut content = block.content.take().unwrap();
let body = content.body;
let mut new_body = vec![];
trace!("check block {}", label);
trace!("");
for node in body.into_iter() {
trace!("check inst: {}", node);
match &node.v {
&TreeNode_::Instruction(ref inst) => {
// check if any operands can be replaced by expression
{
trace!("check if we can replace any operand with inst");
let mut ops = inst.ops.borrow_mut();
for index in 0..ops.len() {
let possible_ssa_id = ops[index].extract_ssa_id();
if possible_ssa_id.is_some() {
let entry_value = context.get_value_mut(possible_ssa_id.unwrap()).unwrap();
trace!("{} replaced by {}", ops[index], expr);
ops[index] = func.new_inst(expr);
}
} else {
trace!("{} cant be replaced", ops[index]);
if entry_value.expr.is_some() {
// replace the node with its expr
let expr = entry_value.expr.take().unwrap();
trace!("{} replaced by {}", ops[index], expr);
ops[index] = TreeNode::new_inst({
let ret = func.next_id;
func.next_id += 1;
ret}, expr);
}
} else {
trace!("{} cant be replaced", ops[index]);
}
}
}
}
// check if left hand side of an assignment has a single use
trace!("check if we should fold the inst");
if inst.value.is_some() {
let left = inst.value.as_ref().unwrap();
// if left is _one_ variable that is used once
// we can put the expression as a child node to its use
if left.len() == 1 {
let lhs = func.context.get_value_mut(left[0].extract_ssa_id().unwrap()).unwrap();
if lhs.use_count.get() == 1{
if is_movable(&inst.v) {
lhs.expr = Some(inst.clone()); // FIXME: should be able to move the inst here
trace!("yes");
trace!("");
continue;
// check if left hand side of an assignment has a single use
trace!("check if we should fold the inst");
if inst.value.is_some() {
let left = inst.value.as_ref().unwrap();
// if left is _one_ variable that is used once
// we can put the expression as a child node to its use
if left.len() == 1 {
let lhs = context.get_value_mut(left[0].extract_ssa_id().unwrap()).unwrap();
if lhs.use_count.get() == 1{
if is_movable(&inst.v) {
lhs.expr = Some(inst.clone()); // FIXME: should be able to move the inst here
trace!("yes");
trace!("");
continue;
} else {
trace!("no, not movable");
}
} else {
trace!("no, not movable");
trace!("no, use count more than 1");
}
} else {
trace!("no, use count more than 1");
trace!("no, yields more than 1 SSA var");
}
} else {
trace!("no, yields more than 1 SSA var");
trace!("no, no value yielded");
}
} else {
trace!("no, no value yielded");
}
},
_ => panic!("expected an instruction node here")
},
_ => panic!("expected an instruction node here")
}
trace!("add {} back to block {}", node, label);
trace!("");
new_body.push(node);
}
trace!("add {} back to block {}", node, label);
content.body = new_body;
trace!("block {} has {} insts", label, content.body.len());
trace!("");
new_body.push(node);
// put the content back
block.content = Some(content);
}
content.body = new_body;
trace!("block {} has {} insts", label, content.body.len());
trace!("");
// put the content back
block.content = Some(content);
}
self.finish_function(vm_context, func);
......
use ast::ir::*;
use compiler::backend::Temporary;
use std::collections::HashMap;
pub struct CompiledFunction {
pub fn_name: MuTag,
pub temps: HashMap<MuID, Temporary>
}
\ No newline at end of file
......@@ -47,7 +47,7 @@ pub fn sum() -> VMContext {
let const_def_int64_1_local = func.new_constant(const_def_int64_1.clone());
// BRANCH %head
let blk_entry_term = TreeNode::new_inst(Instruction {
let blk_entry_term = func.new_inst(Instruction {
value: None,
ops: RefCell::new(vec![blk_entry_n.clone(), const_def_int64_0_local.clone(), const_def_int64_0_local.clone()]),
v: Instruction_::Branch1(Destination{
......@@ -71,30 +71,30 @@ pub fn sum() -> VMContext {
// %s2 = ADD %s %i
let blk_head_s2 = func.new_ssa("blk_head_s2", type_def_int64.clone());
let blk_head_inst0 = TreeNode::new_inst(Instruction {
value: Some(vec![blk_head_s2.clone_value().unwrap()]),
let blk_head_inst0 = func.new_inst(Instruction {
value: Some(vec![blk_head_s2.clone_value()]),
ops: RefCell::new(vec![blk_head_s.clone(), blk_head_i.clone()]),
v: Instruction_::BinOp(BinOp::Add, 0, 1)
});
// %i2 = ADD %i 1
let blk_head_i2 = func.new_ssa("blk_head_i2", type_def_int64.clone());
let blk_head_inst1 = TreeNode::new_inst(Instruction {
value: Some(vec![blk_head_i2.clone_value().unwrap()]),
let blk_head_inst1 = func.new_inst(Instruction {
value: Some(vec![blk_head_i2.clone_value()]),
ops: RefCell::new(vec![blk_head_i.clone(), const_def_int64_1_local.clone()]),
v: Instruction_::BinOp(BinOp::Add, 0, 1)
});
// %cond = UGT %i %n
let blk_head_cond = func.new_ssa("blk_head_cond", type_def_int1.clone());
let blk_head_inst2 = TreeNode::new_inst(Instruction {
value: Some(vec![blk_head_cond.clone_value().unwrap()]),
let blk_head_inst2 = func.new_inst(Instruction {
value: Some(vec![blk_head_cond.clone_value()]),
ops: RefCell::new(vec![blk_head_i.clone(), blk_head_n.clone()]),
v: Instruction_::CmpOp(CmpOp::UGT, 0, 1)
});
// BRANCH2 %cond %ret(%s2) %head(%n %s2 %i2)
let blk_head_term = TreeNode::new_inst(Instruction{
let blk_head_term = func.new_inst(Instruction{
value: None,
ops: RefCell::new(vec![blk_head_cond.clone(), blk_head_n.clone(), blk_head_s2.clone(), blk_head_i2.clone()]),
v: Instruction_::Branch2 {
......@@ -123,7 +123,7 @@ pub fn sum() -> VMContext {
let blk_ret_s = func.new_ssa("blk_ret_s", type_def_int64.clone());
// RET %s
let blk_ret_term = TreeNode::new_inst(Instruction{
let blk_ret_term = func.new_inst(Instruction{
value: None,
ops: RefCell::new(vec![blk_ret_s.clone()]),
v: Instruction_::Return(vec![0])
......@@ -188,14 +188,14 @@ pub fn factorial() -> VMContext {
// %v48 = EQ <@int_64> %n_3 @int_64_1
let blk_0_v48 = func.new_ssa("blk_0_v48", type_def_int64.clone());
let blk_0_inst0 = TreeNode::new_inst(Instruction {
value: Some(vec![blk_0_v48.clone_value().unwrap()]),
let blk_0_inst0 = func.new_inst(Instruction {
value: Some(vec![blk_0_v48.clone_value()]),
ops: RefCell::new(vec![blk_0_n_3.clone(), const_def_int64_1_local.clone()]),
v: Instruction_::CmpOp(CmpOp::EQ, 0, 1)
});
// BRANCH2 %v48 %blk_2(@int_64_1) %blk_1(%n_3)
let blk_0_term = TreeNode::new_inst(Instruction{
let blk_0_term = func.new_inst(Instruction{
value: None,
ops: RefCell::new(vec![blk_0_v48.clone(), const_def_int64_1_local.clone(), blk_0_n_3.clone()]),
v: Instruction_::Branch2 {
......@@ -224,7 +224,7 @@ pub fn factorial() -> VMContext {
let blk_2_v53 = func.new_ssa("blk_2_v53", type_def_int64.clone());
// RET %v53
let blk_2_term = TreeNode::new_inst(Instruction{
let blk_2_term = func.new_inst(Instruction{
value: None,
ops: RefCell::new(vec![blk_2_v53.clone()]),
v: Instruction_::Return(vec![0])
......@@ -243,17 +243,18 @@ pub fn factorial() -> VMContext {
// %v50 = SUB <@int_64> %n_3 @int_64_1
let blk_1_v50 = func.new_ssa("blk_1_v50", type_def_int64.clone());
let blk_1_inst0 = TreeNode::new_inst(Instruction{
value: Some(vec![blk_1_v50.clone_value().unwrap()]),
let blk_1_inst0 = func.new_inst(Instruction{
value: Some(vec![blk_1_v50.clone_value()]),
ops: RefCell::new(vec![blk_1_n_3.clone(), const_def_int64_1_local.clone()]),
v: Instruction_::BinOp(BinOp::Sub, 0, 1)
});
// %v51 = CALL <@fac_sig> @fac (%v50)
let blk_1_v51 = func.new_ssa("blk_1_v51", type_def_int64.clone());
let blk_1_inst1 = TreeNode::new_inst(Instruction{
value: Some(vec![blk_1_v51.clone_value().unwrap()]),
ops: RefCell::new(vec![func.new_ssa("blk_1_fac", P(MuType::funcref(fac_sig.clone()))), blk_1_v50.clone()]),
let blk_1_fac = func.new_ssa("blk_1_fac", P(MuType::funcref(fac_sig.clone())));
let blk_1_inst1 = func.new_inst(Instruction{
value: Some(vec![blk_1_v51.clone_value()]),
ops: RefCell::new(vec![blk_1_fac, blk_1_v50.clone()]),
v: Instruction_::ExprCall {
data: CallData {
func: 0,
......@@ -266,13 +267,13 @@ pub fn factorial() -> VMContext {
// %v52 = MUL <@int_64> %n_3 %v51
let blk_1_v52 = func.new_ssa("blk_1_v52", type_def_int64.clone());
let blk_1_inst2 = TreeNode::new_inst(Instruction{
value: Some(vec![blk_1_v52.clone_value().unwrap()]),
let blk_1_inst2 = func.new_inst(Instruction{
value: Some(vec![blk_1_v52.clone_value()]),
ops: RefCell::new(vec![blk_1_n_3.clone(), blk_1_v51.clone()]),
v: Instruction_::BinOp(BinOp::Mul, 0, 1)
});
let blk_1_term = TreeNode::new_inst(Instruction{
let blk_1_term = func.new_inst(Instruction{
value: None,
ops: RefCell::new(vec![blk_1_v52.clone()]),
v: Instruction_::Branch1(Destination {
......
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