Commit a9e2bc9b authored by qinsoon's avatar qinsoon

[wip] generate spill code. going to copy and insert the code

parent c15fcff7
......@@ -11,7 +11,7 @@
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Rust &lt;mu&gt;" level="project" />
<orderEntry type="library" name="Cargo &lt;mu&gt;" level="project" />
<orderEntry type="library" name="Rust &lt;mu&gt;" level="project" />
</component>
</module>
\ No newline at end of file
......@@ -13,7 +13,6 @@ use runtime::ValueLocation;
use utils::vec_utils;
use utils::string_utils;
use ast::ptr::P;
use ast::ir::*;
......@@ -84,7 +83,10 @@ impl MachineCode for ASMCode {
}
fn replace_reg(&mut self, from: MuID, to: MuID) {
let to_reg_tag : MuName = backend::all_regs().get(&to).unwrap().name().unwrap();
let to_reg_tag : MuName = match backend::all_regs().get(&to) {
Some(reg) => reg.name().unwrap(),
None => panic!("expecting a machine register, but we are required to replace to {}", to)
};
let to_reg_string = "%".to_string() + &to_reg_tag;
match self.reg_defines.get(&from) {
......@@ -98,19 +100,109 @@ impl MachineCode for ASMCode {
},
None => {}
}
match self.reg_uses.get(&from) {
Some(uses) => {
for loc in uses {
let ref mut inst_to_patch = self.code[loc.line];
for i in 0..loc.len {
string_utils::replace(&mut inst_to_patch.code, loc.index, &to_reg_string, to_reg_string.len());
}
}
}
},
None => {}
}
}
fn replace_reg_for_inst(&mut self, from: MuID, to: MuID, inst: usize) {
let to_reg_string : MuName = match backend::all_regs().get(&to) {
Some(ref machine_reg) => {
let name = machine_reg.name().unwrap();
"%".to_string() + &name
},
None => REG_PLACEHOLDER.clone()
};
{
let asm = &mut self.code[inst];
// if this reg is defined, replace the define
if asm.defines.contains(&from) {
vec_utils::remove_value(&mut asm.defines, from);
asm.defines.push(to);
}
// if this reg is used, replace the use
if asm.uses.contains(&from) {
vec_utils::remove_value(&mut asm.uses, from);
asm.uses.push(to);
}
}
// replace the define
// replace code
match self.reg_defines.get(&from) {
Some(defines) => {
for loc in defines {
if loc.line == inst {
let ref mut inst_to_patch = self.code[loc.line];
for i in 0..loc.len {
string_utils::replace(&mut inst_to_patch.code, loc.index, &to_reg_string, to_reg_string.len());
}
}
}
},
None => {}
}
// replace info
let replaced_define = match self.reg_defines.get_mut(&from) {
Some(defines) => {
Some(vec_utils::remove_value_if_true(defines, |x| {x.line == inst}))
},
None => None
};
match replaced_define {
Some(mut defines) => {
if self.reg_defines.contains_key(&to) {
self.reg_defines.get_mut(&to).unwrap().append(&mut defines);
} else {
self.reg_defines.insert(to, defines);
}
}
None => {}
};
// replace the use
// replace code
match self.reg_uses.get(&from) {
Some(uses) => {
for loc in uses {
if loc.line == inst {
let ref mut inst_to_patch = self.code[loc.line];
for i in 0..loc.len {
string_utils::replace(&mut inst_to_patch.code, loc.index, &to_reg_string, to_reg_string.len());
}
}
}
},
None => {}
}
// replace info
let replaced_use = match self.reg_uses.get_mut(&from) {
Some(uses) => {
Some(vec_utils::remove_value_if_true(uses, |x| {x.line == inst}))
},
None => None
};
match replaced_use {
Some(mut uses) => {
if self.reg_uses.contains_key(&to) {
self.reg_uses.get_mut(&to).unwrap().append(&mut uses);
} else {
self.reg_uses.insert(to, uses);
}
}
None => {}
};
}
fn set_inst_nop(&mut self, index: usize) {
// FIXME: changing these info is inefficient - plus we probably do not need to
......@@ -723,7 +815,37 @@ impl CodeGenerator for ASMCodeGen {
ValueLocation::Relocatable(RegGroup::GPR, func_end)
)
}
fn start_code_sequence(&mut self) {
self.cur = Some(Box::new(ASMCode {
name: "snippet".to_string(),
code: vec![],
reg_defines: HashMap::new(),
reg_uses: HashMap::new(),
mem_op_used: HashMap::new(),
preds: vec![],
succs: vec![],
idx_to_blk: HashMap::new(),
blk_to_idx: HashMap::new(),
cond_branches: HashMap::new(),
branches: HashMap::new(),
blocks: vec![],
block_start: HashMap::new(),
block_range: HashMap::new(),
block_livein: HashMap::new(),
block_liveout: HashMap::new()
}));
}
fn finish_code_sequence(&mut self) -> Box<MachineCode + Sync + Send> {
self.cur.take().unwrap()
}
fn print_cur_code(&self) {
println!("");
......
......@@ -3,10 +3,15 @@ use ast::ir::*;
use runtime::ValueLocation;
use compiler::machine_code::MachineCode;
use compiler::backend::x86_64::ASMCodeGen;
pub trait CodeGenerator {
fn start_code(&mut self, func_name: MuName) -> ValueLocation;
fn finish_code(&mut self, func_name: MuName) -> (Box<MachineCode + Sync + Send>, ValueLocation);
// generate unnamed sequence of linear code (no branch)
fn start_code_sequence(&mut self);
fn finish_code_sequence(&mut self) -> Box<MachineCode + Sync + Send>;
fn print_cur_code(&self);
......@@ -66,3 +71,87 @@ pub trait CodeGenerator {
fn emit_push_imm32(&mut self, src: i32);
fn emit_pop_r64(&mut self, dest: &P<Value>);
}
use std::collections::HashMap;
use compiler::machine_code::CompiledFunction;
use vm::VM;
#[cfg(feature = "aot")]
pub fn spill_rewrite(
spills: &HashMap<MuID, P<Value>>,
func: &mut MuFunctionVersion,
cf: &mut CompiledFunction,
vm: &VM)
{
// record code and their insertion point, so we can do the copy/insertion all at once
let mut spill_code_before: HashMap<usize, Vec<Box<MachineCode>>> = HashMap::new();
let mut spill_code_after: HashMap<usize, Vec<Box<MachineCode>>> = HashMap::new();
// iterate through all instructions
for i in 0..cf.mc().number_of_insts() {
// find use of any register that gets spilled
{
let reg_uses = cf.mc().get_inst_reg_uses(i).to_vec();
for reg in reg_uses {
if spills.contains_key(&reg) {
// a register used here is spilled
let spill_mem = spills.get(&reg).unwrap();
// generate a random new temporary
let temp_ty = func.context.get_value(reg).unwrap().ty().clone();
let temp = func.new_ssa(vm.next_id(), temp_ty).clone_value();
// generate a load
let code = {
let mut codegen = ASMCodeGen::new();
codegen.start_code_sequence();
codegen.emit_mov_r64_mem64(&temp, spill_mem);
codegen.finish_code_sequence()
};
// record that this load will be inserted at i
if spill_code_before.contains_key(&i) {
spill_code_before.get_mut(&i).unwrap().push(code);
} else {
spill_code_before.insert(i, vec![code]);
}
// replace register reg with temp
cf.mc_mut().replace_reg_for_inst(reg, temp.id(), i);
}
}
}
// fine define of any register that gets spilled
{
let reg_defines = cf.mc().get_inst_reg_defines(i).to_vec();
for reg in reg_defines {
if spills.contains_key(&reg) {
let spill_mem = spills.get(&reg).unwrap();
let temp_ty = func.context.get_value(reg).unwrap().ty().clone();
let temp = func.new_ssa(vm.next_id(), temp_ty).clone_value();
let code = {
let mut codegen = ASMCodeGen::new();
codegen.start_code_sequence();
codegen.emit_mov_mem64_r64(spill_mem, &temp);
codegen.finish_code_sequence()
};
if spill_code_after.contains_key(&i) {
spill_code_after.get_mut(&i).unwrap().push(code);
} else {
spill_code_after.insert(i, vec![code]);
}
cf.mc_mut().replace_reg_for_inst(reg, temp.id(), i);
}
}
}
}
// copy and insert the code
unimplemented!()
}
\ No newline at end of file
......@@ -5,6 +5,7 @@ pub mod inst_sel;
mod codegen;
pub use compiler::backend::x86_64::codegen::CodeGenerator;
pub use compiler::backend::x86_64::codegen::spill_rewrite;
mod asm_backend;
pub use compiler::backend::x86_64::asm_backend::ASMCodeGen;
......
......@@ -36,6 +36,8 @@ pub use compiler::backend::x86_64::is_callee_saved;
pub use compiler::backend::x86_64::emit_code;
#[cfg(target_arch = "x86_64")]
pub use compiler::backend::x86_64::emit_context;
#[cfg(target_arch = "x86_64")]
pub use compiler::backend::x86_64::spill_rewrite;
// ARM
......
......@@ -8,6 +8,7 @@ use compiler::CompilerPass;
use compiler::machine_code::CompiledFunction;
use compiler::PassExecutionResult;
use compiler::backend::init_machine_regs_for_func;
use compiler::backend;
use std::collections::HashMap;
......@@ -65,7 +66,7 @@ impl RegisterAllocation {
spilled_mem.insert(*reg_id, mem);
}
self.spill_rewrite(&spilled_mem, func, &mut cf, vm);
backend::spill_rewrite(&spilled_mem, func, &mut cf, vm);
return Err(RegAllocFailure::FailedForSpilling);
}
......@@ -93,17 +94,6 @@ impl RegisterAllocation {
Ok(())
}
#[cfg(feature = "aot")]
fn spill_rewrite(
&mut self,
spills: &HashMap<MuID, P<Value>>,
func: &mut MuFunctionVersion,
compiled_func: &mut CompiledFunction,
vm: &VM)
{
unimplemented!()
}
}
impl CompilerPass for RegisterAllocation {
......
......@@ -118,5 +118,10 @@ pub trait MachineCode {
// functions for rewrite
fn replace_reg(&mut self, from: MuID, to: MuID);
fn replace_reg_for_inst(&mut self, from: MuID, to: MuID, inst: usize);
fn set_inst_nop(&mut self, index: usize);
}
pub trait MachineInst {
}
\ No newline at end of file
use std::fmt;
pub fn is_identical_to_str_ignore_order<T: Ord + fmt::Display + Clone, Q: Ord + fmt::Display + Clone> (vec: &Vec<T>, mut expect: Vec<Q>) -> bool {
let mut vec_copy = vec.to_vec();
vec_copy.sort();
expect.sort();
let a = as_str(&vec_copy);
let b = as_str(&expect);
a == b
use std::fmt;
pub fn is_identical_to_str_ignore_order<T: Ord + fmt::Display + Clone, Q: Ord + fmt::Display + Clone> (vec: &Vec<T>, mut expect: Vec<Q>) -> bool {
let mut vec_copy = vec.to_vec();
vec_copy.sort();
expect.sort();
let a = as_str(&vec_copy);
let b = as_str(&expect);
a == b
}
pub fn is_identical_ignore_order<T: Ord + Clone> (vec: &Vec<T>, vec2: &Vec<T>) -> bool {
if vec.len() != vec2.len() {
return false;
}
pub fn is_identical_ignore_order<T: Ord + Clone> (vec: &Vec<T>, vec2: &Vec<T>) -> bool {
if vec.len() != vec2.len() {
let mut vec = vec.to_vec();
let mut vec2 = vec2.to_vec();
vec.sort();
vec2.sort();
for i in 0..vec.len() {
if vec[i] != vec2[i] {
return false;
}
let mut vec = vec.to_vec();
let mut vec2 = vec2.to_vec();
vec.sort();
vec2.sort();
for i in 0..vec.len() {
if vec[i] != vec2[i] {
return false;
}
}
return true;
}
pub fn 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(", ");
}
return true;
}
pub fn 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
}
ret
}
pub fn add_all<T: Copy + PartialEq> (vec: &mut Vec<T>, vec2: &Vec<T>) -> bool {
let mut is_changed = false;
pub fn add_all<T: Copy + PartialEq> (vec: &mut Vec<T>, vec2: &Vec<T>) -> bool {
let mut is_changed = false;
for i in vec2.iter() {
if !vec.contains(i) {
vec.push(*i);
is_changed = true;
}
for i in vec2.iter() {
if !vec.contains(i) {
vec.push(*i);
is_changed = true;
}
}
is_changed
}
is_changed
pub fn add_unique<T: PartialEq> (vec: &mut Vec<T>, val: T) {
if !vec.contains(&val) {
vec.push(val);
}
pub fn add_unique<T: PartialEq> (vec: &mut Vec<T>, val: T) {
if !vec.contains(&val) {
vec.push(val);
}
}
pub fn append_unique<T: PartialEq> (vec: &mut Vec<T>, vec2: &mut Vec<T>) {
while !vec2.is_empty() {
let val = vec2.pop().unwrap();
add_unique(vec, val);
}
pub fn append_unique<T: PartialEq> (vec: &mut Vec<T>, vec2: &mut Vec<T>) {
while !vec2.is_empty() {
let val = vec2.pop().unwrap();
add_unique(vec, val);
}
}
pub fn append_clone_unique<T: PartialEq + Clone> (vec: &mut Vec<T>, vec2: &Vec<T>) {
for ele in vec2 {
add_unique(vec, ele.clone());
}
pub fn append_clone_unique<T: PartialEq + Clone> (vec: &mut Vec<T>, vec2: &Vec<T>) {
for ele in vec2 {
add_unique(vec, ele.clone());
}
pub fn find_value<T: PartialEq> (vec: &Vec<T>, val: T) -> Option<usize> {
for i in 0..vec.len() {
if vec[i] == val {
return Some(i);
}
}
pub fn find_value<T: PartialEq> (vec: &Vec<T>, val: T) -> Option<usize> {
for i in 0..vec.len() {
if vec[i] == val {
return Some(i);
}
}
None
}
None
pub fn remove_value<T: PartialEq> (vec: &mut Vec<T>, val: T) {
match find_value(vec, val) {
Some(index) => {vec.remove(index);},
None => {} // do nothing
}
}
pub fn remove_value_if_true<T, F> (vec: &mut Vec<T>, cond: F) -> Vec<T>
where F : Fn(&T) -> bool
{
let mut new_vec = vec![];
let mut removed = vec![];
pub fn remove_value<T: PartialEq> (vec: &mut Vec<T>, val: T) {
match find_value(vec, val) {
Some(index) => {vec.remove(index);},
None => {} // do nothing
while !vec.is_empty() {
let val = vec.pop().unwrap();
if cond(&val) {
// true - remove
removed.push(val);
} else {
new_vec.push(val);
}
}
pub fn map<T, Q, F> (vec: &Vec<T>, map_func: F) -> Vec<Q>
where F : Fn(&T) -> Q {
let mut ret = vec![];
for t in vec {
ret.push(map_func(t));
vec.append(&mut new_vec);
removed
}
pub fn remove_value_if_false<T, F> (vec: &mut Vec<T>, cond: F) -> Vec<T>
where F : Fn(&T) -> bool
{
let mut new_vec = vec![];
let mut removed = vec![];
while !vec.is_empty() {
let val = vec.pop().unwrap();
if cond(&val) {
new_vec.push(val)
} else {
// false - remove
removed.push(val)
}
ret
}
\ No newline at end of file
}
vec.append(&mut new_vec);
removed
}
pub fn map<T, Q, F> (vec: &Vec<T>, map_func: F) -> Vec<Q>
where F : Fn(&T) -> Q {
let mut ret = vec![];
for t in vec {
ret.push(map_func(t));
}
ret
}
\ 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