GitLab will continue to be upgraded from 11.4.5-ce.0 on November 25th 2019 at 4.00pm (AEDT) to 5.00pm (AEDT) due to Critical Security Patch Availability. During the update, GitLab and Mattermost services will not be available.

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 @@ ...@@ -11,7 +11,7 @@
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <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="Cargo &lt;mu&gt;" level="project" />
<orderEntry type="library" name="Rust &lt;mu&gt;" level="project" />
</component> </component>
</module> </module>
\ No newline at end of file
...@@ -13,7 +13,6 @@ use runtime::ValueLocation; ...@@ -13,7 +13,6 @@ use runtime::ValueLocation;
use utils::vec_utils; use utils::vec_utils;
use utils::string_utils; use utils::string_utils;
use ast::ptr::P; use ast::ptr::P;
use ast::ir::*; use ast::ir::*;
...@@ -84,7 +83,10 @@ impl MachineCode for ASMCode { ...@@ -84,7 +83,10 @@ impl MachineCode for ASMCode {
} }
fn replace_reg(&mut self, from: MuID, to: MuID) { 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; let to_reg_string = "%".to_string() + &to_reg_tag;
match self.reg_defines.get(&from) { match self.reg_defines.get(&from) {
...@@ -98,19 +100,109 @@ impl MachineCode for ASMCode { ...@@ -98,19 +100,109 @@ impl MachineCode for ASMCode {
}, },
None => {} None => {}
} }
match self.reg_uses.get(&from) { match self.reg_uses.get(&from) {
Some(uses) => { Some(uses) => {
for loc in uses { for loc in uses {
let ref mut inst_to_patch = self.code[loc.line]; let ref mut inst_to_patch = self.code[loc.line];
for i in 0..loc.len { for i in 0..loc.len {
string_utils::replace(&mut inst_to_patch.code, loc.index, &to_reg_string, to_reg_string.len()); string_utils::replace(&mut inst_to_patch.code, loc.index, &to_reg_string, to_reg_string.len());
} }
} }
}, },
None => {} 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) { fn set_inst_nop(&mut self, index: usize) {
// FIXME: changing these info is inefficient - plus we probably do not need to // FIXME: changing these info is inefficient - plus we probably do not need to
...@@ -723,7 +815,37 @@ impl CodeGenerator for ASMCodeGen { ...@@ -723,7 +815,37 @@ impl CodeGenerator for ASMCodeGen {
ValueLocation::Relocatable(RegGroup::GPR, func_end) 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) { fn print_cur_code(&self) {
println!(""); println!("");
......
...@@ -3,10 +3,15 @@ use ast::ir::*; ...@@ -3,10 +3,15 @@ use ast::ir::*;
use runtime::ValueLocation; use runtime::ValueLocation;
use compiler::machine_code::MachineCode; use compiler::machine_code::MachineCode;
use compiler::backend::x86_64::ASMCodeGen;
pub trait CodeGenerator { pub trait CodeGenerator {
fn start_code(&mut self, func_name: MuName) -> ValueLocation; fn start_code(&mut self, func_name: MuName) -> ValueLocation;
fn finish_code(&mut self, func_name: MuName) -> (Box<MachineCode + Sync + Send>, 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); fn print_cur_code(&self);
...@@ -66,3 +71,87 @@ pub trait CodeGenerator { ...@@ -66,3 +71,87 @@ pub trait CodeGenerator {
fn emit_push_imm32(&mut self, src: i32); fn emit_push_imm32(&mut self, src: i32);
fn emit_pop_r64(&mut self, dest: &P<Value>); 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; ...@@ -5,6 +5,7 @@ pub mod inst_sel;
mod codegen; mod codegen;
pub use compiler::backend::x86_64::codegen::CodeGenerator; pub use compiler::backend::x86_64::codegen::CodeGenerator;
pub use compiler::backend::x86_64::codegen::spill_rewrite;
mod asm_backend; mod asm_backend;
pub use compiler::backend::x86_64::asm_backend::ASMCodeGen; pub use compiler::backend::x86_64::asm_backend::ASMCodeGen;
......
...@@ -36,6 +36,8 @@ pub use compiler::backend::x86_64::is_callee_saved; ...@@ -36,6 +36,8 @@ pub use compiler::backend::x86_64::is_callee_saved;
pub use compiler::backend::x86_64::emit_code; pub use compiler::backend::x86_64::emit_code;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
pub use compiler::backend::x86_64::emit_context; pub use compiler::backend::x86_64::emit_context;
#[cfg(target_arch = "x86_64")]
pub use compiler::backend::x86_64::spill_rewrite;
// ARM // ARM
......
...@@ -8,6 +8,7 @@ use compiler::CompilerPass; ...@@ -8,6 +8,7 @@ use compiler::CompilerPass;
use compiler::machine_code::CompiledFunction; use compiler::machine_code::CompiledFunction;
use compiler::PassExecutionResult; use compiler::PassExecutionResult;
use compiler::backend::init_machine_regs_for_func; use compiler::backend::init_machine_regs_for_func;
use compiler::backend;
use std::collections::HashMap; use std::collections::HashMap;
...@@ -65,7 +66,7 @@ impl RegisterAllocation { ...@@ -65,7 +66,7 @@ impl RegisterAllocation {
spilled_mem.insert(*reg_id, mem); 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); return Err(RegAllocFailure::FailedForSpilling);
} }
...@@ -93,17 +94,6 @@ impl RegisterAllocation { ...@@ -93,17 +94,6 @@ impl RegisterAllocation {
Ok(()) 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 { impl CompilerPass for RegisterAllocation {
......
...@@ -118,5 +118,10 @@ pub trait MachineCode { ...@@ -118,5 +118,10 @@ pub trait MachineCode {
// functions for rewrite // functions for rewrite
fn replace_reg(&mut self, from: MuID, to: MuID); 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); fn set_inst_nop(&mut self, index: usize);
} }
pub trait MachineInst {
}
\ No newline at end of file
use std::fmt; 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 { 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(); let mut vec_copy = vec.to_vec();
vec_copy.sort(); vec_copy.sort();
expect.sort(); expect.sort();
let a = as_str(&vec_copy); let a = as_str(&vec_copy);
let b = as_str(&expect); let b = as_str(&expect);
a == b 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 { let mut vec = vec.to_vec();
if vec.len() != vec2.len() { let mut vec2 = vec2.to_vec();
vec.sort();
vec2.sort();
for i in 0..vec.len() {
if vec[i] != vec2[i] {
return false; 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 { return true;
let mut ret = String::new(); }
for i in 0..vec.len() {
ret.push_str(format!("{}", vec[i]).as_str()); pub fn as_str<T: fmt::Display>(vec: &Vec<T>) -> String {
if i != vec.len() - 1 { let mut ret = String::new();
ret.push_str(", "); 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 { pub fn add_all<T: Copy + PartialEq> (vec: &mut Vec<T>, vec2: &Vec<T>) -> bool {
let mut is_changed = false; let mut is_changed = false;
for i in vec2.iter() { for i in vec2.iter() {
if !vec.contains(i) { if !vec.contains(i) {
vec.push(*i); vec.push(*i);
is_changed = true; 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) { pub fn append_unique<T: PartialEq> (vec: &mut Vec<T>, vec2: &mut Vec<T>) {
vec.push(val); 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() { pub fn append_clone_unique<T: PartialEq + Clone> (vec: &mut Vec<T>, vec2: &Vec<T>) {
let val = vec2.pop().unwrap(); for ele in vec2 {
add_unique(vec, val); add_unique(vec, ele.clone());
}
} }
}
pub fn append_clone_unique<T: PartialEq + Clone> (vec: &mut Vec<T>, vec2: &Vec<T>) {
for ele in vec2 { pub fn find_value<T: PartialEq> (vec: &Vec<T>, val: T) -> Option<usize> {
add_unique(vec, ele.clone()); 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> { None
for i in 0..vec.len() { }
if vec[i] == val {
return Some(i);
}
}
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) { while !vec.is_empty() {
match find_value(vec, val) { let val = vec.pop().unwrap();
Some(index) => {vec.remove(index);}, if cond(&val) {
None => {} // do nothing // true - remove
removed.push(val);
} else {
new_vec.push(val);
} }
} }
pub fn map<T, Q, F> (vec: &Vec<T>, map_func: F) -> Vec<Q> vec.append(&mut new_vec);
where F : Fn(&T) -> Q {
let mut ret = vec![]; removed
}
for t in vec {
ret.push(map_func(t)); 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
} vec.append(&mut new_vec);
\ No newline at end of file
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