To protect your data, the CISO officer has suggested users to enable GitLab 2FA as soon as possible.

mod.rs 5.64 KB
Newer Older
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1
// Copyright 2017 The Australian National University
2
//
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
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
6
//
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
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.

qinsoon's avatar
qinsoon committed
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

qinsoon's avatar
qinsoon committed
30
31
pub use compiler::passes::CompilerPass;

32
/// Zebu compiler
qinsoon's avatar
qinsoon committed
33
pub struct Compiler<'vm> {
34
    /// policy decides what passes to be executed
35
    policy: RefCell<CompilerPolicy>,
36
    /// a reference to vm, for compiler to query VM-wide info
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
37
    vm: &'vm VM,
38
39
}

40
impl<'vm> Compiler<'vm> {
41
    /// creates a new compiler
qinsoon's avatar
qinsoon committed
42
    pub fn new(policy: CompilerPolicy, vm: &VM) -> Compiler {
43
        Compiler {
44
            policy: RefCell::new(policy),
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
45
            vm: vm,
46
        }
47
    }
qinsoon's avatar
qinsoon committed
48

49
    /// compiles a certain function version
50
    pub fn compile(&self, func: &mut MuFunctionVersion) {
qinsoon's avatar
qinsoon committed
51
52
53
54
        info!("");
        info!("Start compiling {}", func);
        info!("");
        debug!("{:?}", func);
55

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

59
        let ref mut passes = self.policy.borrow_mut().passes;
60
61
        for pass in passes.iter_mut() {
            let _p = hprof::enter(pass.name());
qinsoon's avatar
qinsoon committed
62

qinsoon's avatar
qinsoon committed
63
            pass.execute(self.vm, func);
qinsoon's avatar
qinsoon committed
64
65

            drop(_p);
66
        }
qinsoon's avatar
qinsoon committed
67

68
        drop(_p);
69
        hprof_print_timing(hprof::profiler().root());
qinsoon's avatar
qinsoon committed
70
71

        func.set_compiled();
72
        if self.vm.is_doing_jit() {
73
74
75
            // build exception table for this function
            unimplemented!()
        }
76
77
78
    }
}

79
80
/// CompilerPolicy specifies a list of ordered CompilerPasses
/// the compiler will follow the list to compile each function
81
pub struct CompilerPolicy {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
82
    pub passes: Vec<Box<CompilerPass>>,
83
84
85
}

impl CompilerPolicy {
86
    pub fn new(passes: Vec<Box<CompilerPass>>) -> CompilerPolicy {
87
        CompilerPolicy { passes: passes }
88
89
90
91
92
    }
}

impl Default for CompilerPolicy {
    fn default() -> Self {
93
        let mut passes: Vec<Box<CompilerPass>> = vec![];
94
        passes.push(Box::new(passes::DotGen::new(".orig")));
qinsoon's avatar
qinsoon committed
95
        passes.push(Box::new(passes::Inlining::new()));
96
        // ir level passes
qinsoon's avatar
qinsoon committed
97
98
        passes.push(Box::new(passes::DefUse::new()));
        passes.push(Box::new(passes::TreeGen::new()));
99
        passes.push(Box::new(passes::GenMovPhi::new()));
100
        passes.push(Box::new(passes::ControlFlowAnalysis::new()));
101
        passes.push(Box::new(passes::TraceGen::new()));
102
        passes.push(Box::new(passes::DotGen::new(".transformed")));
103

104
105
106
        // compilation
        passes.push(Box::new(backend::inst_sel::InstructionSelection::new()));
        passes.push(Box::new(backend::reg_alloc::RegisterAllocation::new()));
107
108

        // machine code level passes
109
110
        passes.push(Box::new(backend::peephole_opt::PeepholeOptimization::new()));
        passes.push(Box::new(backend::code_emission::CodeEmission::new()));
qinsoon's avatar
qinsoon committed
111

112
        CompilerPolicy { passes: passes }
113
    }
114
}
115

116
// rewrite parts of the hprof crates to print via log (instead of print!())
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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() {
139
140
141
142
143
144
145
146
        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
147
148
        );
    } else {
149
150
151
152
153
154
155
156
        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
157
158
159
        );
    }
    for c in &*this.children.borrow() {
160
        hprof_print_child(c, indent + 2);
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
    }
}

// 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.)
        }
    }
}