mod.rs 6.2 KB
Newer Older
1
// Copyright 2017 The Australian National University
qinsoon's avatar
qinsoon committed
2
//
3 4 5
// 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
qinsoon's avatar
qinsoon committed
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
qinsoon's avatar
qinsoon committed
8
//
9 10 11 12 13 14
// 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
extern crate hprof;

17
use ast::ir::*;
qinsoon's avatar
qinsoon committed
18
use vm::VM;
19 20
use std::cell::RefCell;

21
/// compiler passes
22
pub mod passes;
23
/// compiler backends, include target description, and target dependent passes
24
pub mod backend;
25
/// a frame layout for a compiled function
qinsoon's avatar
qinsoon committed
26
pub mod frame;
27
/// machine code representation
qinsoon's avatar
qinsoon committed
28
pub mod machine_code;
29

30 31
pub use compiler::passes::CompilerPass;

32 33 34 35 36
/// name for prologue (this is not full name, but prologue name is generated from this)
pub const PROLOGUE_BLOCK_NAME: &'static str = "prologue";
/// name for epilogue (this is not full name, but epilogue name is generated from this)
pub const EPILOGUE_BLOCK_NAME: &'static str = "epilogue";

37
/// Zebu compiler
38
pub struct Compiler<'vm> {
39
    /// policy decides what passes to be executed
40
    policy: RefCell<CompilerPolicy>,
41
    /// a reference to vm, for compiler to query VM-wide info
42
    vm: &'vm VM
43 44
}

qinsoon's avatar
qinsoon committed
45
impl<'vm> Compiler<'vm> {
46
    /// creates a new compiler
47
    pub fn new(policy: CompilerPolicy, vm: &VM) -> Compiler {
qinsoon's avatar
qinsoon committed
48
        Compiler {
49
            policy: RefCell::new(policy),
50
            vm: vm
51
        }
52
    }
53

54
    /// compiles a certain function version
55
    pub fn compile(&self, func: &mut MuFunctionVersion) {
qinsoon's avatar
qinsoon committed
56
        info!("");
57
        info!("compilation_start {}", func.id());
qinsoon's avatar
qinsoon committed
58 59 60
        info!("Start compiling {}", func);
        info!("");
        debug!("{:?}", func);
qinsoon's avatar
qinsoon committed
61

qinsoon's avatar
qinsoon committed
62 63
        // FIXME: should use function name here (however hprof::enter only accept &'static str)
        let _p = hprof::enter("Function Compilation");
64

65
        let ref mut passes = self.policy.borrow_mut().passes;
66 67
        for pass in passes.iter_mut() {
            let _p = hprof::enter(pass.name());
68

69
            pass.execute(self.vm, func);
70 71

            drop(_p);
72
        }
73

74
        drop(_p);
75
        hprof_print_timing(hprof::profiler().root());
76 77

        func.set_compiled();
78
        if self.vm.is_doing_jit() {
79 80 81
            // build exception table for this function
            unimplemented!()
        }
82
        info!("compilation_end {}", func.id());
83 84 85
    }
}

86 87
/// CompilerPolicy specifies a list of ordered CompilerPasses
/// the compiler will follow the list to compile each function
88
pub struct CompilerPolicy {
89
    pub passes: Vec<Box<CompilerPass>>
90 91 92
}

impl CompilerPolicy {
93
    pub fn new(passes: Vec<Box<CompilerPass>>) -> CompilerPolicy {
qinsoon's avatar
qinsoon committed
94
        CompilerPolicy { passes: passes }
95 96 97 98 99
    }
}

impl Default for CompilerPolicy {
    fn default() -> Self {
qinsoon's avatar
qinsoon committed
100
        let mut passes: Vec<Box<CompilerPass>> = vec![];
101
        passes.push(Box::new(passes::UIRGen::new("")));
102
        passes.push(Box::new(passes::DotGen::new(".orig")));
qinsoon's avatar
qinsoon committed
103

104
        // ir level passes
qinsoon's avatar
qinsoon committed
105 106
        passes.push(Box::new(passes::RetSink::new()));
        passes.push(Box::new(passes::Inlining::new()));
qinsoon's avatar
qinsoon committed
107 108
        passes.push(Box::new(passes::DefUse::new()));
        passes.push(Box::new(passes::TreeGen::new()));
109
        passes.push(Box::new(passes::GenMovPhi::new()));
110
        passes.push(Box::new(passes::ControlFlowAnalysis::new()));
111
        passes.push(Box::new(passes::TraceGen::new()));
112
        passes.push(Box::new(passes::DotGen::new(".transformed")));
113

114 115
        // compilation
        passes.push(Box::new(backend::inst_sel::InstructionSelection::new()));
qinsoon's avatar
qinsoon committed
116
        passes.push(Box::new(backend::mc_loopanalysis::MCLoopAnalysis::new()));
117
        passes.push(Box::new(backend::reg_alloc::RegisterAllocation::new()));
118 119

        // machine code level passes
120 121
        passes.push(Box::new(backend::peephole_opt::PeepholeOptimization::new()));
        passes.push(Box::new(backend::code_emission::CodeEmission::new()));
122

qinsoon's avatar
qinsoon committed
123
        CompilerPolicy { passes: passes }
124
    }
125
}
126

127
// rewrite parts of the hprof crates to print via log (instead of print!())
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
use self::hprof::ProfileNode;
use std::rc::Rc;

fn hprof_print_timing(root: Rc<ProfileNode>) {
    info!("Timing information for {}:", root.name);
    for child in &*root.children.borrow() {
        hprof_print_child(child, 2);
    }
}

fn hprof_print_child(this: &ProfileNode, indent: usize) {
    let mut indent_str = "".to_string();
    for _ in 0..indent {
        indent_str += " ";
    }

    let parent_time = this.parent
        .as_ref()
        .map(|p| p.total_time.get())
        .unwrap_or(this.total_time.get()) as f64;
    let percent = 100.0 * (this.total_time.get() as f64 / parent_time);
    if percent.is_infinite() {
qinsoon's avatar
qinsoon committed
150 151 152 153 154 155 156 157
        info!(
            "{}{name} - {calls} * {each} = {total} @ {hz:.1}hz",
            indent_str,
            name = this.name,
            calls = this.calls.get(),
            each = Nanoseconds((this.total_time.get() as f64 / this.calls.get() as f64) as u64),
            total = Nanoseconds(this.total_time.get()),
            hz = this.calls.get() as f64 / this.total_time.get() as f64 * 1e9f64
158 159
        );
    } else {
qinsoon's avatar
qinsoon committed
160 161 162 163 164 165 166 167
        info!(
            "{}{name} - {calls} * {each} = {total} ({percent:.1}%)",
            indent_str,
            name = this.name,
            calls = this.calls.get(),
            each = Nanoseconds((this.total_time.get() as f64 / this.calls.get() as f64) as u64),
            total = Nanoseconds(this.total_time.get()),
            percent = percent
168 169 170
        );
    }
    for c in &*this.children.borrow() {
qinsoon's avatar
qinsoon committed
171
        hprof_print_child(c, indent + 2);
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
    }
}

// used to do a pretty printing of time
struct Nanoseconds(u64);

use std::fmt;
impl fmt::Display for Nanoseconds {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.0 < 1_000 {
            write!(f, "{}ns", self.0)
        } else if self.0 < 1_000_000 {
            write!(f, "{:.1}us", self.0 as f64 / 1_000.)
        } else if self.0 < 1_000_000_000 {
            write!(f, "{:.1}ms", self.0 as f64 / 1_000_000.)
        } else {
            write!(f, "{:.1}s", self.0 as f64 / 1_000_000_000.)
        }
    }
}