Commit 933b1e25 authored by qinsoon's avatar qinsoon

a peephole optimization to find redundant moves

parent 3d1b37f7
......@@ -97,6 +97,11 @@ impl MachineCode for ASMCode {
}
}
fn set_inst_nop(&mut self, index: usize) {
self.code.remove(index);
self.code.insert(index, ASM::nop());
}
fn emit(&self) -> Vec<u8> {
let mut ret = vec![];
......@@ -108,19 +113,23 @@ impl MachineCode for ASMCode {
ret
}
fn print(&self) {
println!("");
fn trace_mc(&self) {
trace!("");
println!("code for {}: ", self.name);
trace!("code for {}: \n", self.name);
let n_insts = self.code.len();
for i in 0..n_insts {
let ref line = self.code[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]);
self.trace_inst(i);
}
println!("");
trace!("")
}
fn trace_inst(&self, i: usize) {
trace!("#{}\t{:30}\t\tdefine: {:?}\tuses: {:?}\tpred: {:?}\tsucc: {:?}",
i, self.code[i].code, self.get_inst_reg_defines(i), self.get_inst_reg_uses(i),
self.preds[i], self.succs[i]);
}
fn get_ir_block_livein(&self, block: MuTag) -> Option<&Vec<MuID>> {
......@@ -173,6 +182,14 @@ impl ASM {
uses: vec![]
}
}
fn nop() -> ASM {
ASM {
code: "".to_string(),
defines: vec![],
uses: vec![]
}
}
}
#[derive(Clone, Debug)]
......
......@@ -15,6 +15,8 @@ use compiler::backend::x86_64;
use compiler::backend::x86_64::CodeGenerator;
use compiler::backend::x86_64::ASMCodeGen;
use std::collections::HashMap;
pub struct InstructionSelection {
name: &'static str,
......@@ -713,6 +715,7 @@ impl CompilerPass for InstructionSelection {
let mc = self.backend.finish_code();
let compiled_func = CompiledFunction {
fn_name: func.fn_name,
temps: HashMap::new(),
mc: mc
};
......
pub mod inst_sel;
pub mod reg_alloc;
pub mod peephole_opt;
pub mod code_emission;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
......
use compiler::CompilerPass;
use ast::ir::*;
use vm::context::VMContext;
use vm::machine_code::CompiledFunction;
pub struct PeepholeOptimization {
name: &'static str
}
impl PeepholeOptimization {
pub fn new() -> PeepholeOptimization {
PeepholeOptimization {
name: "Peephole Optimization"
}
}
pub fn remove_redundant_move(&mut self, inst: usize, cf: &mut CompiledFunction) {
if cf.mc.is_move(inst) {
cf.mc.trace_inst(inst);
let src : MuID = {
let uses = cf.mc.get_inst_reg_uses(inst);
if uses.len() != 1 {
// moving immediate to register, its not redundant
return;
}
uses[0]
};
let dst : MuID = cf.mc.get_inst_reg_defines(inst)[0];
let src_machine_reg : MuID = {
match cf.temps.get(&src) {
Some(reg) => *reg,
None => src
}
};
let dst_machine_reg : MuID = {
match cf.temps.get(&dst) {
Some(reg) => *reg,
None => dst
}
};
if src_machine_reg == dst_machine_reg {
trace!("Redundant! removed");
// redundant, remove this move
cf.mc.set_inst_nop(inst);
}
}
}
}
impl CompilerPass for PeepholeOptimization {
fn name(&self) -> &'static str {
self.name
}
fn visit_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) {
let compiled_funcs = vm_context.compiled_funcs().read().unwrap();
let mut cf = compiled_funcs.get(func.fn_name).unwrap().borrow_mut();
for i in 0..cf.mc.number_of_insts() {
self.remove_redundant_move(i, &mut cf);
}
trace!("after peephole optimization:");
cf.mc.trace_mc();
}
}
\ No newline at end of file
......@@ -27,7 +27,7 @@ impl RegisterAllocation {
let compiled_funcs = vm_context.compiled_funcs().read().unwrap();
let mut cf = compiled_funcs.get(func.fn_name).unwrap().borrow_mut();
cf.mc.print();
cf.mc.trace_mc();
// initialize machine registers for the function context
init_machine_regs_for_func(&mut func.context);
......@@ -56,10 +56,12 @@ impl RegisterAllocation {
trace!("replacing {} with {}", temp, machine_reg);
cf.mc.replace_reg(temp, machine_reg);
cf.temps.insert(temp, machine_reg);
}
}
cf.mc.print();
cf.mc.trace_mc();
true
}
......
......@@ -17,7 +17,8 @@ pub use compiler::passes::PASS2_CFA;
pub use compiler::passes::PASS3_TRACE_GEN;
pub use compiler::passes::PASS4_INST_SEL;
pub use compiler::passes::PASS5_REG_ALLOC;
pub use compiler::passes::PASS6_CODE_EMIT;
pub use compiler::passes::PASS6_PEEPHOLE;
pub use compiler::passes::PASS7_CODE_EMIT;
pub struct Compiler {
policy: RefCell<CompilerPolicy>,
......@@ -52,8 +53,8 @@ impl Compiler {
drop(_p);
}
drop(_p);
hprof::profiler().print_timing();
drop(_p);
hprof::profiler().print_timing();
}
}
......@@ -70,6 +71,8 @@ impl CompilerPolicy {
passes.push(Box::new(passes::TraceGen::new()));
passes.push(Box::new(backend::inst_sel::InstructionSelection::new()));
passes.push(Box::new(backend::reg_alloc::RegisterAllocation::new()));
passes.push(Box::new(backend::peephole_opt::PeepholeOptimization::new()));
passes.push(Box::new(backend::code_emission::CodeEmission::new()));
CompilerPolicy{passes: passes}
}
......
......@@ -17,7 +17,8 @@ pub const PASS2_CFA : usize = 2;
pub const PASS3_TRACE_GEN : usize = 3;
pub const PASS4_INST_SEL : usize = 4;
pub const PASS5_REG_ALLOC : usize = 5;
pub const PASS6_CODE_EMIT : usize = 6;
pub const PASS6_PEEPHOLE : usize = 6;
pub const PASS7_CODE_EMIT : usize = 7;
pub enum PassExecutionResult {
ProceedToNext,
......
use ast::ir::*;
use std::ops;
use std::collections::HashMap;
pub struct CompiledFunction {
pub fn_name: MuTag,
pub temps: HashMap<MuID, MuID>, // assumes one temperary maps to one register
pub mc: Box<MachineCode>
}
pub trait MachineCode {
fn print(&self);
fn trace_mc(&self);
fn trace_inst(&self, index: usize);
fn emit(&self) -> Vec<u8>;
fn number_of_insts(&self) -> usize;
......@@ -19,11 +23,12 @@ pub trait MachineCode {
fn get_inst_reg_uses(&self, index: usize) -> &Vec<MuID>;
fn get_inst_reg_defines(&self, index: usize) -> &Vec<MuID>;
fn replace_reg(&mut self, from: MuID, to: MuID);
fn get_ir_block_livein(&self, block: MuTag) -> Option<&Vec<MuID>>;
fn get_ir_block_liveout(&self, block: MuTag) -> Option<&Vec<MuID>>;
fn get_all_blocks(&self) -> &Vec<MuTag>;
fn get_block_range(&self, block: MuTag) -> Option<ops::Range<usize>>;
fn replace_reg(&mut self, from: MuID, to: MuID);
fn set_inst_nop(&mut self, index: usize);
}
\ No newline at end of file
......@@ -74,6 +74,7 @@ fn test_regalloc_fac() {
Box::new(passes::TraceGen::new()),
Box::new(backend::inst_sel::InstructionSelection::new()),
Box::new(backend::reg_alloc::RegisterAllocation::new()),
Box::new(backend::peephole_opt::PeepholeOptimization::new()),
Box::new(backend::code_emission::CodeEmission::new())
]), vm_context.clone());
......
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