Commit ef135dc0 authored by qinsoon's avatar qinsoon
Browse files

[wip] continue working on liveness. need more tests

parent 8669dba8
......@@ -2,7 +2,7 @@ use ast::ptr::P;
use ast::types::*;
use ast::inst::*;
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum OpCode {
// SSA
RegI64,
......@@ -112,7 +112,7 @@ pub fn pick_op_code_for_const(ty: &P<MuType>) -> OpCode {
}
}
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum BinOp {
// Int(n) BinOp Int(n) -> Int(n)
Add,
......@@ -138,7 +138,7 @@ pub enum BinOp {
FRem
}
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum CmpOp {
// for Int comparison
EQ,
......@@ -171,7 +171,7 @@ pub enum CmpOp {
FUNO
}
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AtomicRMWOp {
XCHG,
ADD,
......
......@@ -63,7 +63,9 @@ impl MachineCode for ASMCode {
let n_insts = self.code.len();
for i in 0..n_insts {
let ref line = self.code[i];
println!("#{}\t{}\t\tpred: {:?}, succ: {:?}", i, line.code, self.preds[i], self.succs[i]);
println!("#{}\t{:30}\t\tdefine: {:?}\tuses: {:?}\tpred: {:?}\tsucc: {:?}",
i, line.code, self.get_inst_reg_defines(i), self.get_inst_reg_uses(i),
self.preds[i], self.succs[i]);
}
println!("");
......@@ -252,9 +254,9 @@ impl ASMCodeGen {
loc.line = line;
if mc.reg_uses.contains_key(&id) {
mc.reg_defines.get_mut(&id).unwrap().push(loc.clone());
mc.reg_uses.get_mut(&id).unwrap().push(loc.clone());
} else {
mc.reg_defines.insert(id, vec![loc.clone()]);
mc.reg_uses.insert(id, vec![loc.clone()]);
}
}
......@@ -466,16 +468,16 @@ impl CodeGenerator for ASMCodeGen {
fn emit_mov_r64_imm32(&mut self, dest: &P<Value>, src: u32) {
trace!("emit: mov {} -> {}", src, dest);
let (reg1, id1, loc1) = self.prepare_op(dest, 4 + 1);
let (reg1, id1, loc1) = self.prepare_op(dest, 4 + 1 + 1 + src.to_string().len() + 1);
let asm = format!("movq {} ${}", src, reg1);
let asm = format!("movq ${} {}", src, reg1);
self.add_asm_inst(
asm,
vec![],
vec![],
vec![id1],
vec![loc1]
vec![loc1],
vec![],
vec![]
)
}
......@@ -708,15 +710,16 @@ impl CodeGenerator for ASMCodeGen {
trace!("emit: push {}", src);
let (reg, id, loc) = self.prepare_op(src, 5 + 1);
let rsp = self.prepare_machine_reg(&x86_64::RSP);
let asm = format!("pushq {}", reg);
self.add_asm_inst(
asm,
vec![rsp],
vec![],
vec![],
vec![id],
vec![loc]
vec![rsp],
vec![]
)
}
......@@ -724,14 +727,15 @@ impl CodeGenerator for ASMCodeGen {
trace!("emit: pop {}", dest);
let (reg, id, loc) = self.prepare_op(dest, 4 + 1);
let rsp = self.prepare_machine_reg(&x86_64::RSP);
let asm = format!("popq {}", reg);
self.add_asm_inst(
asm,
vec![id],
vec![id, rsp],
vec![loc.clone()],
vec![id],
vec![id, rsp],
vec![loc]
)
}
......
......@@ -36,12 +36,9 @@ impl <'a> InstructionSelection {
// 3. we need to backup/restore all the callee-saved registers
// if any of these assumption breaks, we will need to re-emit the code
#[allow(unused_variables)]
fn instruction_select(&mut self, node: &'a P<TreeNode>) {
fn instruction_select(&mut self, node: &'a P<TreeNode>, cur_func: &MuFunction) {
trace!("instsel on node {}", node);
// let mut state = inst.state.borrow_mut();
// *state = Some(BURSState::new(MATCH_RES_LEN));
match node.v {
TreeNode_::Instruction(ref inst) => {
match inst.v {
......@@ -58,14 +55,14 @@ impl <'a> InstructionSelection {
let ops = inst.ops.borrow();
self.process_dest(&ops, fallthrough_dest);
self.process_dest(&ops, branch_dest);
self.process_dest(&ops, fallthrough_dest, cur_func);
self.process_dest(&ops, branch_dest, cur_func);
let ref cond = ops[cond];
if self.match_cmp_res(cond) {
trace!("emit cmp_eq-branch2");
match self.emit_cmp_res(cond) {
match self.emit_cmp_res(cond, cur_func) {
op::CmpOp::EQ => self.backend.emit_je(branch_dest),
op::CmpOp::NE => self.backend.emit_jne(branch_dest),
op::CmpOp::UGE => self.backend.emit_jae(branch_dest),
......@@ -81,7 +78,7 @@ impl <'a> InstructionSelection {
} else if self.match_ireg(cond) {
trace!("emit ireg-branch2");
let cond_reg = self.emit_ireg(cond);
let cond_reg = self.emit_ireg(cond, cur_func);
// emit: cmp cond_reg 1
self.backend.emit_cmp_r64_imm32(&cond_reg, 1);
......@@ -95,7 +92,7 @@ impl <'a> InstructionSelection {
Instruction_::Branch1(ref dest) => {
let ops = inst.ops.borrow();
self.process_dest(&ops, dest);
self.process_dest(&ops, dest, cur_func);
trace!("emit branch1");
// jmp
......@@ -130,7 +127,7 @@ impl <'a> InstructionSelection {
trace!("arg {}", arg);
if self.match_ireg(arg) {
let arg = self.emit_ireg(arg);
let arg = self.emit_ireg(arg, cur_func);
if gpr_arg_count < x86_64::ARGUMENT_GPRs.len() {
self.backend.emit_mov_r64_r64(&x86_64::ARGUMENT_GPRs[gpr_arg_count], &arg);
......@@ -160,7 +157,7 @@ impl <'a> InstructionSelection {
self.backend.emit_call_near_rel32(target);
} else if self.match_ireg(func) {
let target = self.emit_ireg(func);
let target = self.emit_ireg(func, cur_func);
self.backend.emit_call_near_r64(&target);
} else if self.match_mem(func) {
......@@ -191,7 +188,7 @@ impl <'a> InstructionSelection {
},
Instruction_::Return(_) => {
self.emit_common_epilogue(inst);
self.emit_common_epilogue(inst, cur_func);
self.backend.emit_ret();
},
......@@ -204,8 +201,8 @@ impl <'a> InstructionSelection {
if self.match_ireg(&ops[op1]) && self.match_ireg(&ops[op2]) {
trace!("emit add-ireg-ireg");
let reg_op1 = self.emit_ireg(&ops[op1]);
let reg_op2 = self.emit_ireg(&ops[op2]);
let reg_op1 = self.emit_ireg(&ops[op1], cur_func);
let reg_op2 = self.emit_ireg(&ops[op2], cur_func);
let res_tmp = self.emit_get_result(node);
// mov op1, res
......@@ -215,7 +212,7 @@ impl <'a> InstructionSelection {
} else if self.match_ireg(&ops[op1]) && self.match_iimm(&ops[op2]) {
trace!("emit add-ireg-imm");
let reg_op1 = self.emit_ireg(&ops[op1]);
let reg_op1 = self.emit_ireg(&ops[op1], cur_func);
let reg_op2 = self.emit_get_iimm(&ops[op2]);
let res_tmp = self.emit_get_result(node);
......@@ -229,7 +226,7 @@ impl <'a> InstructionSelection {
} else if self.match_ireg(&ops[op1]) && self.match_mem(&ops[op2]) {
trace!("emit add-ireg-mem");
let reg_op1 = self.emit_ireg(&ops[op1]);
let reg_op1 = self.emit_ireg(&ops[op1], cur_func);
let reg_op2 = self.emit_mem(&ops[op2]);
let res_tmp = self.emit_get_result(node);
......@@ -248,8 +245,8 @@ impl <'a> InstructionSelection {
if self.match_ireg(&ops[op1]) && self.match_ireg(&ops[op2]) {
trace!("emit sub-ireg-ireg");
let reg_op1 = self.emit_ireg(&ops[op1]);
let reg_op2 = self.emit_ireg(&ops[op2]);
let reg_op1 = self.emit_ireg(&ops[op1], cur_func);
let reg_op2 = self.emit_ireg(&ops[op2], cur_func);
let res_tmp = self.emit_get_result(node);
// mov op1, res
......@@ -259,7 +256,7 @@ impl <'a> InstructionSelection {
} else if self.match_ireg(&ops[op1]) && self.match_iimm(&ops[op2]) {
trace!("emit sub-ireg-imm");
let reg_op1 = self.emit_ireg(&ops[op1]);
let reg_op1 = self.emit_ireg(&ops[op1], cur_func);
let imm_op2 = self.emit_get_iimm(&ops[op2]);
let res_tmp = self.emit_get_result(node);
......@@ -273,7 +270,7 @@ impl <'a> InstructionSelection {
} else if self.match_ireg(&ops[op1]) && self.match_mem(&ops[op2]) {
trace!("emit sub-ireg-mem");
let reg_op1 = self.emit_ireg(&ops[op1]);
let reg_op1 = self.emit_ireg(&ops[op1], cur_func);
let mem_op2 = self.emit_mem(&ops[op2]);
let res_tmp = self.emit_get_result(node);
......@@ -293,7 +290,7 @@ impl <'a> InstructionSelection {
let rax = x86_64::RAX.clone();
let op1 = &ops[op1];
if self.match_ireg(op1) {
let reg_op1 = self.emit_ireg(op1);
let reg_op1 = self.emit_ireg(op1, cur_func);
self.backend.emit_mov_r64_r64(&rax, &reg_op1);
} else if self.match_iimm(op1) {
......@@ -311,7 +308,7 @@ impl <'a> InstructionSelection {
// mul op2 -> rax
let op2 = &ops[op2];
if self.match_ireg(op2) {
let reg_op2 = self.emit_ireg(op2);
let reg_op2 = self.emit_ireg(op2, cur_func);
self.backend.emit_mul_r64(&reg_op2);
} else if self.match_iimm(op2) {
......@@ -351,24 +348,32 @@ impl <'a> InstructionSelection {
}
#[allow(unused_variables)]
fn process_dest(&mut self, ops: &Vec<P<TreeNode>>, dest: &Destination) {
for dest_arg in dest.args.iter() {
fn process_dest(&mut self, ops: &Vec<P<TreeNode>>, dest: &Destination, cur_func: &MuFunction) {
for i in 0..dest.args.len() {
let ref dest_arg = dest.args[i];
match dest_arg {
&DestArg::Normal(op_index) => {
let ref arg = ops[op_index];
match arg.op {
OpCode::RegI64
| OpCode::RegFP
| OpCode::IntImmI64
| OpCode::FPImm => {
// do nothing
},
_ => {
trace!("nested: compute arg for branch");
// nested: compute arg
self.instruction_select(arg);
}
}
// match arg.op {
// OpCode::RegI64
// | OpCode::RegFP
// | OpCode::IntImmI64
// | OpCode::FPImm => {
// // do nothing
// },
// _ => {
// trace!("nested: compute arg for branch");
// // nested: compute arg
// self.instruction_select(arg, cur_func);
//
// self.emit_get_result(arg);
// }
// }
//
let ref target_args = cur_func.content.as_ref().unwrap().get_block(dest.target).content.as_ref().unwrap().args;
let ref target_arg = target_args[i];
self.emit_general_move(&arg, target_arg, cur_func);
},
&DestArg::Freshbound(_) => unimplemented!()
}
......@@ -378,11 +383,18 @@ impl <'a> InstructionSelection {
fn emit_common_prologue(&mut self, args: &Vec<P<Value>>) {
self.backend.start_block("prologue");
// TODO: push rbp, store rsp, etc.
// push rbp
self.backend.emit_push_r64(&x86_64::RBP);
// mov rsp -> rbp
self.backend.emit_mov_r64_r64(&x86_64::RSP, &x86_64::RBP);
// push all callee-saved registers
for reg in x86_64::CALLEE_SAVED_GPRs.iter() {
self.backend.emit_push_r64(&reg);
for i in 0..x86_64::CALLEE_SAVED_GPRs.len() {
let ref reg = x86_64::CALLEE_SAVED_GPRs[i];
// not pushing rbp (as we have done taht)
if reg.extract_ssa_id().unwrap() != x86_64::RBP.extract_ssa_id().unwrap() {
self.backend.emit_push_r64(&reg);
}
}
// unload arguments
......@@ -405,14 +417,10 @@ impl <'a> InstructionSelection {
}
}
fn emit_common_epilogue(&mut self, ret_inst: &Instruction) {
self.backend.start_block("epilogue");
// pop all callee-saved registers
for reg in x86_64::CALLEE_SAVED_GPRs.iter() {
self.backend.emit_pop_r64(&reg);
}
fn emit_common_epilogue(&mut self, ret_inst: &Instruction, cur_func: &MuFunction) {
self.backend.start_block("epilogue");
// prepare return regs
let ref ops = ret_inst.ops.borrow();
let ret_val_indices = match ret_inst.v {
Instruction_::Return(ref vals) => vals,
......@@ -424,7 +432,7 @@ impl <'a> InstructionSelection {
for i in ret_val_indices {
let ref ret_val = ops[*i];
if self.match_ireg(ret_val) {
let reg_ret_val = self.emit_ireg(ret_val);
let reg_ret_val = self.emit_ireg(ret_val, cur_func);
self.backend.emit_mov_r64_r64(&x86_64::RETURN_GPRs[gpr_ret_count], &reg_ret_val);
gpr_ret_count += 1;
......@@ -436,7 +444,18 @@ impl <'a> InstructionSelection {
} else {
unimplemented!();
}
}
// pop all callee-saved registers - reverse order
for i in (0..x86_64::CALLEE_SAVED_GPRs.len()).rev() {
let ref reg = x86_64::CALLEE_SAVED_GPRs[i];
if reg.extract_ssa_id().unwrap() != x86_64::RBP.extract_ssa_id().unwrap() {
self.backend.emit_pop_r64(&reg);
}
}
// pop rbp
self.backend.emit_pop_r64(&x86_64::RBP);
}
fn match_cmp_res(&mut self, op: &P<TreeNode>) -> bool {
......@@ -451,7 +470,7 @@ impl <'a> InstructionSelection {
}
}
fn emit_cmp_res(&mut self, cond: &P<TreeNode>) -> op::CmpOp {
fn emit_cmp_res(&mut self, cond: &P<TreeNode>, cur_func: &MuFunction) -> op::CmpOp {
match cond.v {
TreeNode_::Instruction(ref inst) => {
let ops = inst.ops.borrow();
......@@ -463,12 +482,12 @@ impl <'a> InstructionSelection {
if op::is_int_cmp(op) {
if self.match_ireg(op1) && self.match_ireg(op2) {
let reg_op1 = self.emit_ireg(op1);
let reg_op2 = self.emit_ireg(op2);
let reg_op1 = self.emit_ireg(op1, cur_func);
let reg_op2 = self.emit_ireg(op2, cur_func);
self.backend.emit_cmp_r64_r64(&reg_op1, &reg_op2);
} else if self.match_ireg(op1) && self.match_iimm(op2) {
let reg_op1 = self.emit_ireg(op1);
let reg_op1 = self.emit_ireg(op1, cur_func);
let iimm_op2 = self.emit_get_iimm(op2);
self.backend.emit_cmp_r64_imm32(&reg_op1, iimm_op2);
......@@ -515,10 +534,10 @@ impl <'a> InstructionSelection {
}
}
fn emit_ireg(&mut self, op: &P<TreeNode>) -> P<Value> {
fn emit_ireg(&mut self, op: &P<TreeNode>, cur_func: &MuFunction) -> P<Value> {
match op.v {
TreeNode_::Instruction(_) => {
self.instruction_select(op);
self.instruction_select(op, cur_func);
self.emit_get_result(op)
},
......@@ -615,7 +634,27 @@ impl <'a> InstructionSelection {
pv.clone()
}
}
}
}
fn emit_general_move(&mut self, src: &P<TreeNode>, dest: &P<Value>, cur_func: &MuFunction) {
let ref dst_ty = dest.ty;
if !types::is_fp(dst_ty) && types::is_scalar(dst_ty) {
if self.match_ireg(src) {
let src_reg = self.emit_ireg(src, cur_func);
self.backend.emit_mov_r64_r64(dest, &src_reg);
} else if self.match_iimm(src) {
let src_imm = self.emit_get_iimm(src);
self.backend.emit_mov_r64_imm32(dest, src_imm);
} else {
panic!("expected an int type op");
}
} else if !types::is_fp(dst_ty) && types::is_scalar(dst_ty) {
unimplemented!()
} else {
panic!("unexpected type for move");
}
}
}
impl CompilerPass for InstructionSelection {
......@@ -638,14 +677,14 @@ impl CompilerPass for InstructionSelection {
#[allow(unused_variables)]
fn visit_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) {
for block_label in func.block_trace.as_ref().unwrap() {
let block = func.content.as_mut().unwrap().get_block_mut(block_label);
let block = func.content.as_ref().unwrap().get_block(block_label);
self.backend.start_block(block.label);
let block_content = block.content.as_mut().unwrap();
let block_content = block.content.as_ref().unwrap();
for inst in block_content.body.iter_mut() {
self.instruction_select(inst);
for inst in block_content.body.iter() {
self.instruction_select(inst, func);
}
}
}
......
......@@ -87,16 +87,52 @@ impl InterferenceGraph {
self.matrix.as_ref().unwrap()[(from_ix, to_ix)]
}
pub fn print_with(&self, func: &MuFunction) {
pub fn print(&self) {
println!("");
println!("Interference Graph");
println!("color:");
for (n, c) in self.color.iter() {
println!("Node {} -> Color {}", n, c);
}
println!("moves:");
for mov in self.moves.iter() {
println!("Move {} -> {}", mov.0, mov.1);
}
println!("graph:");
{
let idx_to_node_id = {
let mut ret : HashMap<MatrixIndex, MuID> = HashMap::new();
for node_id in self.nodes.keys() {
ret.insert(*self.nodes.get(node_id).unwrap(), *node_id);
}
ret
};
let matrix = self.matrix.as_ref().unwrap();
for i in 0..matrix.ncols() {
for j in 0..matrix.nrows() {
if matrix[(i, j)] {
let from_node = idx_to_node_id.get(&i).unwrap();
let to_node = idx_to_node_id.get(&j).unwrap();
println!("Node {} -> Node {}", from_node, to_node);
}
}
}
}
println!("");
}
#[allow(dead_code)]
pub fn print_symbols(&self, func: &MuFunction) {
let ref context = func.context;
println!("");
println!("Interference Graph");
println!("nodes:");
for (n, ix) in self.nodes.iter() {
println!("Node {} -> Index {}", get_tag(*n, context), ix);
}
println!("color:");
for (n, c) in self.color.iter() {
println!("Node {} -> Color {}", get_tag(*n, context), get_tag(*c, context));
......@@ -124,7 +160,7 @@ impl InterferenceGraph {
let from_node = idx_to_node_id.get(&i).unwrap();
let to_node = idx_to_node_id.get(&j).unwrap();
println!("{} -> {}", get_tag(*from_node, context), get_tag(*to_node, context));
println!("Node {} -> Node {}", get_tag(*from_node, context), get_tag(*to_node, context));
}
}
}
......@@ -142,7 +178,7 @@ fn is_machine_reg(node: MuID) -> bool {
}
// from tony's code src/RegAlloc/Liveness.java
pub fn build (cf: &CompiledFunction, f: &MuFunction) -> InterferenceGraph {
pub fn build (cf: &CompiledFunction) -> InterferenceGraph {
let mut ig = InterferenceGraph::new();
// move precolor nodes to later iteration of registers
......@@ -223,12 +259,17 @@ pub fn build (cf: &CompiledFunction, f: &MuFunction) -> InterferenceGraph {
let src = cf.mc.get_inst_reg_uses(n);
let dst = cf.mc.get_inst_reg_defines(n);
debug_assert!(src.len() == 1);
// src may be immediate number
// dest is definitly register
debug_assert!(dst.len() == 1);
ig.add_move(src[0], dst[0]);
Some(src[0])
if src.len() == 1 {
ig.add_move(src[0], dst[0]);
Some(src[0])
} else {
None
}
} else {
None
}
......
......@@ -28,7 +28,7 @@ impl CompilerPass for RegisterAllocation {
cf.mc.print();
let liveness = liveness::build(&mut cf, func);
liveness.print_with(func);
let liveness = liveness::build(&mut cf);
liveness.print();
}
}
\ 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