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 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