peephole_opt.rs 3.71 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// Copyright 2017 The Australian National University
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

15 16
use compiler::CompilerPass;
use ast::ir::*;
qinsoon's avatar
qinsoon committed
17
use vm::VM;
qinsoon's avatar
qinsoon committed
18
use compiler::machine_code::CompiledFunction;
qinsoon's avatar
qinsoon committed
19
use compiler::backend;
20

qinsoon's avatar
qinsoon committed
21 22
use std::any::Any;

23 24 25 26 27 28 29 30 31 32 33 34
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
35 36
        if cf.mc().is_move(inst) && !cf.mc().is_using_mem_op(inst) {
            cf.mc().trace_inst(inst);
37 38
            
            let src : MuID = {
qinsoon's avatar
qinsoon committed
39
                let uses = cf.mc().get_inst_reg_uses(inst);
qinsoon's avatar
qinsoon committed
40
                if uses.len() == 0 {
41 42 43 44 45
                    // moving immediate to register, its not redundant
                    return;
                }                
                uses[0]
            };
qinsoon's avatar
qinsoon committed
46
            let dst : MuID = cf.mc().get_inst_reg_defines(inst)[0];
47 48 49 50 51 52 53 54 55 56 57 58 59 60
            
            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
                }
            };
            
61 62
            if backend::is_aliased(src_machine_reg, dst_machine_reg) {
                trace!("move between {} and {} is redundant! removed", src_machine_reg, dst_machine_reg);
63
                // redundant, remove this move
qinsoon's avatar
qinsoon committed
64
                cf.mc_mut().set_inst_nop(inst);
qinsoon's avatar
qinsoon committed
65 66
            } else {

67 68 69
            }
        }
    }
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98

    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
            }
        }
    }
99 100 101 102 103 104
}

impl CompilerPass for PeepholeOptimization {
    fn name(&self) -> &'static str {
        self.name
    }
qinsoon's avatar
qinsoon committed
105 106 107 108

    fn as_any(&self) -> &Any {
        self
    }
109
    
qinsoon's avatar
qinsoon committed
110 111
    fn visit_function(&mut self, vm: &VM, func: &mut MuFunctionVersion) {
        let compiled_funcs = vm.compiled_funcs().read().unwrap();
qinsoon's avatar
qinsoon committed
112
        let mut cf = compiled_funcs.get(&func.id()).unwrap().write().unwrap();
113
        
qinsoon's avatar
qinsoon committed
114
        for i in 0..cf.mc().number_of_insts() {
115
            self.remove_redundant_move(i, &mut cf);
116
            self.remove_unnecessary_jump(i, &mut cf);
117 118 119
        }
        
        trace!("after peephole optimization:");
qinsoon's avatar
qinsoon committed
120
        cf.mc().trace_mc();
121
    }
122
}