peephole_opt.rs 3.11 KB
Newer Older
1 2
use compiler::CompilerPass;
use ast::ir::*;
qinsoon's avatar
qinsoon committed
3
use vm::VM;
qinsoon's avatar
qinsoon committed
4
use compiler::machine_code::CompiledFunction;
qinsoon's avatar
qinsoon committed
5
use compiler::backend;
6

qinsoon's avatar
qinsoon committed
7 8
use std::any::Any;

9 10 11 12 13 14 15 16 17 18 19 20
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) {
qinsoon's avatar
qinsoon committed
21 22
        if cf.mc().is_move(inst) && !cf.mc().is_using_mem_op(inst) {
            cf.mc().trace_inst(inst);
23 24
            
            let src : MuID = {
qinsoon's avatar
qinsoon committed
25
                let uses = cf.mc().get_inst_reg_uses(inst);
qinsoon's avatar
qinsoon committed
26
                if uses.len() == 0 {
27 28 29 30 31
                    // moving immediate to register, its not redundant
                    return;
                }                
                uses[0]
            };
qinsoon's avatar
qinsoon committed
32
            let dst : MuID = cf.mc().get_inst_reg_defines(inst)[0];
33 34 35 36 37 38 39 40 41 42 43 44 45 46
            
            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
                }
            };
            
47 48
            if backend::is_aliased(src_machine_reg, dst_machine_reg) {
                trace!("move between {} and {} is redundant! removed", src_machine_reg, dst_machine_reg);
49
                // redundant, remove this move
qinsoon's avatar
qinsoon committed
50
                cf.mc_mut().set_inst_nop(inst);
qinsoon's avatar
qinsoon committed
51 52
            } else {

53 54 55
            }
        }
    }
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84

    pub fn remove_unnecessary_jump(&mut self, inst: usize, cf: &mut CompiledFunction) {
        let mut mc = cf.mc_mut();

        // if this is last instruction, return
        if inst == mc.number_of_insts() - 1 {
            return;
        }

        // if this inst jumps to a label that directly follows it, we can set it to nop
        let opt_dest = mc.is_jmp(inst);

        match opt_dest {
            Some(ref dest) => {
                let opt_label = mc.is_label(inst + 1);
                match opt_label {
                    Some(ref label) if dest == label => {
                            mc.set_inst_nop(inst);
                    }
                    _ => {
                        // do nothing
                    }
                }
            }
            None => {
                // do nothing
            }
        }
    }
85 86 87 88 89 90
}

impl CompilerPass for PeepholeOptimization {
    fn name(&self) -> &'static str {
        self.name
    }
qinsoon's avatar
qinsoon committed
91 92 93 94

    fn as_any(&self) -> &Any {
        self
    }
95
    
qinsoon's avatar
qinsoon committed
96 97
    fn visit_function(&mut self, vm: &VM, func: &mut MuFunctionVersion) {
        let compiled_funcs = vm.compiled_funcs().read().unwrap();
qinsoon's avatar
qinsoon committed
98
        let mut cf = compiled_funcs.get(&func.id()).unwrap().write().unwrap();
99
        
qinsoon's avatar
qinsoon committed
100
        for i in 0..cf.mc().number_of_insts() {
101
            self.remove_redundant_move(i, &mut cf);
102
            self.remove_unnecessary_jump(i, &mut cf);
103 104 105
        }
        
        trace!("after peephole optimization:");
qinsoon's avatar
qinsoon committed
106
        cf.mc().trace_mc();
107
    }
108
}