Commit 8f260a2a authored by qinsoon's avatar qinsoon

backend code emission for factorial

parent 1ac03aae
......@@ -56,7 +56,7 @@ impl MuFunction {
let id = self.get_id();
self.context.value_tags.insert(tag, id);
self.context.values.insert(id, ValueEntry{id: id, tag: tag, ty: ty.clone(), use_count: Cell::new(0), expr: None});
self.context.values.insert(id, SSAVarEntry{id: id, tag: tag, ty: ty.clone(), use_count: Cell::new(0), expr: None});
P(TreeNode {
id: id,
......@@ -121,7 +121,7 @@ impl FunctionContent {
#[derive(Debug)]
pub struct FunctionContext {
pub value_tags: HashMap<MuTag, MuID>,
pub values: HashMap<MuID, ValueEntry>
pub values: HashMap<MuID, SSAVarEntry>
}
impl FunctionContext {
......@@ -132,14 +132,14 @@ impl FunctionContext {
}
}
pub fn get_value_by_tag(&self, tag: MuTag) -> Option<&ValueEntry> {
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 ValueEntry> {
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
......@@ -148,11 +148,11 @@ impl FunctionContext {
self.get_value_mut(id)
}
pub fn get_value(&self, id: MuID) -> Option<&ValueEntry> {
pub fn get_value(&self, id: MuID) -> Option<&SSAVarEntry> {
self.values.get(&id)
}
pub fn get_value_mut(&mut self, id: MuID) -> Option<&mut ValueEntry> {
pub fn get_value_mut(&mut self, id: MuID) -> Option<&mut SSAVarEntry> {
self.values.get_mut(&id)
}
}
......@@ -383,7 +383,7 @@ pub enum Value_ {
}
#[derive(Debug, Clone)]
pub struct ValueEntry {
pub struct SSAVarEntry {
pub id: MuID,
pub tag: MuTag,
pub ty: P<MuType>,
......@@ -396,13 +396,13 @@ pub struct ValueEntry {
pub expr: Option<Instruction>
}
impl ValueEntry {
impl SSAVarEntry {
pub fn assign_expr(&mut self, expr: Instruction) {
self.expr = Some(expr)
}
}
impl fmt::Display for ValueEntry {
impl fmt::Display for SSAVarEntry {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {}#{}", self.ty, self.tag, self.id)
}
......
......@@ -7,138 +7,425 @@ use ast::ir::*;
use ast::types::*;
use ast::inst::*;
use std::collections::HashMap;
use std::fmt;
use std::str;
struct ASMCode {
name: MuTag,
code: Vec<String>,
regs: HashMap<MuID, RegUses>,
}
pub struct ASMCodeGen {
foo: usize
cur: Option<ASMCode>,
all_code: HashMap<MuTag, ASMCode>
}
struct RegUses {
locs: Vec<ASMLocation>
}
struct ASMLocation {
line: usize,
index: usize,
len: usize
}
impl ASMLocation {
fn new(line: usize, index: usize, len: usize) -> ASMLocation {
ASMLocation{
line: line,
index: index,
len: len
}
}
}
const REG_PLACEHOLDER_LEN : usize = 3;
lazy_static! {
pub static ref REG_PLACEHOLDER : String = {
let blank_spaces = [' ' as u8; REG_PLACEHOLDER_LEN];
format!("%{}", str::from_utf8(&blank_spaces).unwrap())
};
}
impl ASMCodeGen {
pub fn new() -> ASMCodeGen {
ASMCodeGen {foo: 0}
ASMCodeGen {
cur: None,
all_code: HashMap::new()
}
}
fn cur(&self) -> &ASMCode {
self.cur.as_ref().unwrap()
}
fn cur_mut(&mut self) -> &mut ASMCode {
self.cur.as_mut().unwrap()
}
fn replace(s: &mut String, index: usize, replace: &str, replace_len: usize) {
let vec = unsafe {s.as_mut_vec()};
for i in 0..replace_len {
if i < replace.len() {
vec[index + i] = replace.as_bytes()[i] as u8;
} else {
vec[index + i] = ' ' as u8;
}
}
}
/// return line number for this code
fn add_assembly(&mut self, code: String) -> usize {
let len = self.cur_mut().code.len();
self.cur_mut().code.push(code);
len
}
fn use_reg(&mut self, reg: &P<Value>, loc: ASMLocation) {
let id = reg.extract_ssa_id().unwrap();
let code = self.cur_mut();
if code.regs.contains_key(&id) {
let reg_uses = code.regs.get_mut(&id).unwrap();
reg_uses.locs.push(loc);
} else {
code.regs.insert(id, RegUses {
locs: vec![loc]
});
}
}
fn asm_reg_op(&self, op: &P<Value>) -> String {
let id = op.extract_ssa_id().unwrap();
if id < RESERVED_NODE_IDS_FOR_MACHINE {
// machine reg
format!("%{}", op.tag)
} else {
// virtual register, use place holder
REG_PLACEHOLDER.clone()
}
}
fn asm_block_label(&self, label: MuTag) -> String {
format!("{}_{}", self.cur().name, label)
}
}
impl CodeGenerator for ASMCodeGen {
fn start_code(&mut self, func_name: MuTag) {
self.cur = Some(ASMCode {
name: func_name,
code: vec![],
regs: HashMap::new()
});
self.add_assembly(format!(".globl {}", func_name));
}
fn finish_code(&mut self) {
let finish = self.cur.take().unwrap();
self.all_code.insert(finish.name, finish);
}
fn print_cur_code(&self) {
println!("");
if self.cur.is_some() {
let code = self.cur.as_ref().unwrap();
println!("code for {}: ", code.name);
for line in code.code.iter() {
println!("{}", line);
}
} else {
println!("no current code");
}
println!("");
}
fn start_block(&mut self, block_name: MuTag) {
let label = format!("{}:", self.asm_block_label(block_name));
self.add_assembly(label);
}
fn emit_cmp_r64_r64(&mut self, op1: &P<Value>, op2: &P<Value>) {
trace!("emit: cmp {} {}", op1, op2);
let reg1 = self.asm_reg_op(op1);
let reg2 = self.asm_reg_op(op2);
let asm = format!("cmpq {} {}", reg1, reg2);
let line = self.add_assembly(asm);
let loc_reg1 = ASMLocation::new(line, 4 + 1, reg1.len());
self.use_reg(op1, loc_reg1);
let loc_reg2 = ASMLocation::new(line, 4 + 1 + reg1.len() + 1, reg2.len());
self.use_reg(op2, loc_reg2);
}
fn emit_cmp_r64_imm32(&mut self, op1: &P<Value>, op2: u32) {
trace!("emit: cmp {} {}", op1, op2);
let reg1 = self.asm_reg_op(op1);
let asm = format!("cmpq {} ${}", reg1, op2);
let line = self.add_assembly(asm);
let loc_reg1 = ASMLocation::new(line, 4 + 1, reg1.len());
self.use_reg(op1, loc_reg1);
}
fn emit_cmp_r64_mem64(&mut self, op1: &P<Value>, op2: &P<Value>) {
trace!("emit: cmp {} {}", op1, op2);
unimplemented!()
}
fn emit_mov_r64_imm32(&mut self, dest: &P<Value>, src: u32) {
trace!("emit: mov {} -> {}", src, dest);
let reg1 = self.asm_reg_op(dest);
let asm = format!("movq {} ${}", src, reg1);
let line = self.add_assembly(asm);
let loc_reg1 = ASMLocation::new(line, 4 + 1, reg1.len());
self.use_reg(dest, loc_reg1);
}
fn emit_mov_r64_mem64(&mut self, dest: &P<Value>, src: &P<Value>) {
trace!("emit: mov {} -> {}", src, dest);
unimplemented!()
}
fn emit_mov_r64_r64(&mut self, dest: &P<Value>, src: &P<Value>) {
trace!("emit: mov {} -> {}", src, dest);
let reg1 = self.asm_reg_op(dest);
let reg2 = self.asm_reg_op(src);
let asm = format!("movq {} {}", reg2, reg1);
let line = self.add_assembly(asm);
let loc_reg1 = ASMLocation::new(line, 4 + 1, reg1.len());
self.use_reg(dest, loc_reg1);
let loc_reg2 = ASMLocation::new(line, 4 + 1 + reg1.len() + 1, reg2.len());
self.use_reg(src, loc_reg2);
}
fn emit_add_r64_r64(&mut self, dest: &P<Value>, src: &P<Value>) {
trace!("emit: add {}, {} -> {}", dest, src, dest);
let reg1 = self.asm_reg_op(dest);
let reg2 = self.asm_reg_op(src);
let asm = format!("addq {} {}", reg2, reg1);
let line = self.add_assembly(asm);
let loc_reg1 = ASMLocation::new(line, 4 + 1, reg1.len());
self.use_reg(dest, loc_reg1);
let loc_reg2 = ASMLocation::new(line, 4 + 1 + reg1.len() + 1, reg2.len());
self.use_reg(src, loc_reg2);
}
fn emit_add_r64_mem64(&mut self, dest: &P<Value>, src: &P<Value>) {
trace!("emit: add {}, {} -> {}", dest, src, dest);
unimplemented!()
}
fn emit_add_r64_imm32(&mut self, dest: &P<Value>, src: u32) {
trace!("emit: add {}, {} -> {}", dest, src, dest);
let reg1 = self.asm_reg_op(dest);
let asm = format!("addq {} ${}", src, reg1);
let line = self.add_assembly(asm);
let loc_reg1 = ASMLocation::new(line, 4 + 1, reg1.len());
self.use_reg(dest, loc_reg1);
}
fn emit_sub_r64_r64(&mut self, dest: &P<Value>, src: &P<Value>) {
trace!("emit: sub {}, {} -> {}", dest, src, dest);
let reg1 = self.asm_reg_op(dest);
let reg2 = self.asm_reg_op(src);
let asm = format!("subq {} {}", reg2, reg1);
let line = self.add_assembly(asm);
let loc_reg1 = ASMLocation::new(line, 4 + 1, reg1.len());
self.use_reg(dest, loc_reg1);
let loc_reg2 = ASMLocation::new(line, 4 + 1 + reg1.len() + 1, reg2.len());
self.use_reg(src, loc_reg2);
}
fn emit_sub_r64_mem64(&mut self, dest: &P<Value>, src: &P<Value>) {
trace!("emit: sub {}, {} -> {}", dest, src, dest);
unimplemented!()
}
fn emit_sub_r64_imm32(&mut self, dest: &P<Value>, src: u32) {
trace!("emit: sub {}, {} -> {}", dest, src, dest);
let reg1 = self.asm_reg_op(dest);
let asm = format!("subq {} ${}", src, reg1);
let line = self.add_assembly(asm);
let loc_reg1 = ASMLocation::new(line, 4 + 1, reg1.len());
self.use_reg(dest, loc_reg1);
}
fn emit_mul_r64(&mut self, src: &P<Value>) {
trace!("emit: mul rax, {} -> rax", src);
let reg = self.asm_reg_op(src);
let asm = format!("mul {}", reg);
let line = self.add_assembly(asm);
let loc_reg = ASMLocation::new(line, 3 + 1, reg.len());
self.use_reg(src, loc_reg);
}
fn emit_mul_mem64(&mut self, src: &P<Value>) {
trace!("emit: mul rax, {} -> rax", src);
unimplemented!()
}
fn emit_jmp(&mut self, dest: &Destination) {
trace!("emit: jmp {}", dest.target);
// symbolic label, we dont need to patch it
let asm = format!("jmp {}", self.asm_block_label(dest.target));
self.add_assembly(asm);
}
fn emit_je(&mut self, dest: &Destination) {
trace!("emit: je {}", dest.target);
let asm = format!("je {}", self.asm_block_label(dest.target));
self.add_assembly(asm);
}
fn emit_jne(&mut self, dest: &Destination) {
trace!("emit: jne {}", dest.target);
let asm = format!("jne {}", self.asm_block_label(dest.target));
self.add_assembly(asm);
}
fn emit_ja(&mut self, dest: &Destination) {
trace!("emit: ja {}", dest.target);
let asm = format!("ja {}", self.asm_block_label(dest.target));
self.add_assembly(asm);
}
fn emit_jae(&mut self, dest: &Destination) {
trace!("emit: jae {}", dest.target);
let asm = format!("jae {}", self.asm_block_label(dest.target));
self.add_assembly(asm);
}
fn emit_jb(&mut self, dest: &Destination) {
trace!("emit: jb {}", dest.target);
let asm = format!("jb {}", self.asm_block_label(dest.target));
self.add_assembly(asm);
}
fn emit_jbe(&mut self, dest: &Destination) {
trace!("emit: jbe {}", dest.target);
let asm = format!("jbe {}", self.asm_block_label(dest.target));
self.add_assembly(asm);
}
fn emit_jg(&mut self, dest: &Destination) {
trace!("emit: jg {}", dest.target);
let asm = format!("jg {}", self.asm_block_label(dest.target));
self.add_assembly(asm);
}
fn emit_jge(&mut self, dest: &Destination) {
trace!("emit: jge {}", dest.target);
let asm = format!("jge {}", self.asm_block_label(dest.target));
self.add_assembly(asm);
}
fn emit_jl(&mut self, dest: &Destination) {
trace!("emit: jl {}", dest.target);
let asm = format!("jl {}", self.asm_block_label(dest.target));
self.add_assembly(asm);
}
fn emit_jle(&mut self, dest: &Destination) {
trace!("emit: jle {}", dest.target);
let asm = format!("jle {}", self.asm_block_label(dest.target));
self.add_assembly(asm);
}
fn emit_call_near_rel32(&mut self, func: MuTag) {
trace!("emit: call {}", func);
let asm = format!("call {}", func);
self.add_assembly(asm);
}
fn emit_call_near_r64(&mut self, func: &P<Value>) {
trace!("emit: call {}", func);
unimplemented!()
}
fn emit_call_near_mem64(&mut self, func: &P<Value>) {
trace!("emit: call {}", func);
unimplemented!()
}
fn emit_ret(&mut self) {
trace!("emit: ret");
let asm = format!("ret");
self.add_assembly(asm);
}
fn emit_push(&mut self, src: &P<Value>) {
fn emit_push_r64(&mut self, src: &P<Value>) {
trace!("emit: push {}", src);
let reg = self.asm_reg_op(src);
let asm = format!("pushq {}", reg);
let line = self.add_assembly(asm);
let loc_reg = ASMLocation::new(line, 5 + 1, reg.len());
self.use_reg(src, loc_reg);
}
fn emit_pop(&mut self, dest: &P<Value>) {
fn emit_pop_r64(&mut self, dest: &P<Value>) {
trace!("emit: pop {}", dest);
let reg = self.asm_reg_op(dest);
let asm = format!("popq {}", reg);
let line = self.add_assembly(asm);
let loc_reg = ASMLocation::new(line, 4 + 1, reg.len());
self.use_reg(dest, loc_reg);
}
}
\ No newline at end of file
......@@ -3,6 +3,13 @@ use ast::ir::*;
use ast::inst::*;
pub trait CodeGenerator {
fn start_code(&mut self, func_name: MuTag);
fn finish_code(&mut self);
fn print_cur_code(&self);
fn start_block(&mut self, block_name: MuTag);
fn emit_cmp_r64_r64(&mut self, op1: &P<Value>, op2: &P<Value>);
fn emit_cmp_r64_imm32(&mut self, op1: &P<Value>, op2: u32);
fn emit_cmp_r64_mem64(&mut self, op1: &P<Value>, op2: &P<Value>);
......@@ -40,6 +47,6 @@ pub trait CodeGenerator {
fn emit_ret(&mut self);
fn emit_push(&mut self, src: &P<Value>);
fn emit_pop(&mut self, dest: &P<Value>);
fn emit_push_r64(&mut self, src: &P<Value>);
fn emit_pop_r64(&mut self, dest: &P<Value>);
}
\ No newline at end of file
......@@ -375,9 +375,11 @@ impl <'a> InstructionSelection {
}
fn emit_common_prologue(&mut self, args: &Vec<P<Value>>) {
self.backend.start_block("prologue");
// push all callee-saved registers
for reg in x86_64::CALLEE_SAVED_GPRs.iter() {
self.backend.emit_push(&reg);
self.backend.emit_push_r64(&reg);
}
// unload arguments
......@@ -401,9 +403,11 @@ 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(&reg);
self.backend.emit_pop_r64(&reg);
}
let ref ops = ret_inst.ops.borrow();
......@@ -617,7 +621,9 @@ impl CompilerPass for InstructionSelection {
fn start_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) {
debug!("{}", self.name());
// prologue (get arguments from entry block first)
self.backend.start_code(func.fn_name);
// prologue (get arguments from entry block first)
let entry_block = func.content.as_ref().unwrap().get_entry_block();
let ref args = entry_block.content.as_ref().unwrap().args;
self.emit_common_prologue(args);
......@@ -627,6 +633,8 @@ impl CompilerPass for InstructionSelection {
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);
self.backend.start_block(block.label);
let block_content = block.content.as_mut().unwrap();
......@@ -635,4 +643,11 @@ impl CompilerPass for InstructionSelection {
}
}
}
#[allow(unused_variables)]
fn finish_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) {
self.backend.print_cur_code();
self.backend.finish_code();
}
}
\ 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