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

code_emission.rs 6.02 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.

15
16
17
18
#![allow(dead_code)]

use compiler::CompilerPass;
use ast::ir::*;
qinsoon's avatar
qinsoon committed
19
use vm::VM;
20
use compiler::backend::emit_code;
qinsoon's avatar
qinsoon committed
21
22
use std::any::Any;

qinsoon's avatar
qinsoon committed
23
24
25
use std::path;
use std::io::prelude::*;
use std::fs::File;
26
use std::collections::HashMap;
qinsoon's avatar
qinsoon committed
27

qinsoon's avatar
qinsoon committed
28
/// should emit Mu IR dot graph?
29
pub const EMIT_MUIR: bool = true;
qinsoon's avatar
qinsoon committed
30
/// should emit machien code dot graph?
31
pub const EMIT_MC_DOT: bool = true;
qinsoon's avatar
qinsoon committed
32

qinsoon's avatar
qinsoon committed
33
pub struct CodeEmission {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
34
    name: &'static str,
qinsoon's avatar
qinsoon committed
35
36
37
38
39
}

impl CodeEmission {
    pub fn new() -> CodeEmission {
        CodeEmission {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
40
            name: "Code Emission",
qinsoon's avatar
qinsoon committed
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
        }
    }
}

impl CompilerPass for CodeEmission {
    fn name(&self) -> &'static str {
        self.name
    }

    fn as_any(&self) -> &Any {
        self
    }

    fn visit_function(&mut self, vm: &VM, func: &mut MuFunctionVersion) {
        // emit the actual code
        emit_code(func, vm);

        // emit debug graphs
        if EMIT_MC_DOT {
            emit_mc_dot(func, vm);
        }
    }
}

/// creates the emit directory (if it doesnt exist)
qinsoon's avatar
qinsoon committed
66
67
68
pub fn create_emit_directory(vm: &VM) {
    use std::fs;
    match fs::create_dir(&vm.vm_options.flag_aot_emit_dir) {
69
        Ok(_) => {}
qinsoon's avatar
qinsoon committed
70
71
72
73
        Err(_) => {}
    }
}

qinsoon's avatar
qinsoon committed
74
/// creates an file to write, panics if the creation fails
75
76
77
78
79
80
fn create_emit_file(name: String, vm: &VM) -> File {
    let mut file_path = path::PathBuf::new();
    file_path.push(&vm.vm_options.flag_aot_emit_dir);
    file_path.push(name);

    match File::create(file_path.as_path()) {
81
82
83
84
85
86
87
        Err(why) => {
            panic!(
                "couldn't create emit file {}: {}",
                file_path.to_str().unwrap(),
                why
            )
        }
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
88
        Ok(file) => file,
89
90
91
    }
}

92
#[allow(dead_code)]
93
pub fn emit_mu_types(suffix: &str, vm: &VM) {
94
95
96
97
98
    if EMIT_MUIR {
        create_emit_directory(vm);

        let mut file_path = path::PathBuf::new();
        file_path.push(&vm.vm_options.flag_aot_emit_dir);
99
        file_path.push("___types".to_string() + suffix + ".muty");
100
        let mut file = match File::create(file_path.as_path()) {
101
102
103
104
105
106
107
            Err(why) => {
                panic!(
                    "couldn't create mu types file {}: {}",
                    file_path.to_str().unwrap(),
                    why
                )
            }
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
108
            Ok(file) => file,
109
110
111
112
113
114
115
116
117
118
119
        };

        {
            use ast::types::*;

            let ty_guard = vm.types().read().unwrap();
            let struct_map = STRUCT_TAG_MAP.read().unwrap();
            let hybrid_map = HYBRID_TAG_MAP.read().unwrap();

            for ty in ty_guard.values() {
                if ty.is_struct() {
120
                    write!(file, "{}", ty).unwrap();
121

122
123
124
                    let struct_ty = struct_map
                        .get(&ty.get_struct_hybrid_tag().unwrap())
                        .unwrap();
125
126
                    writeln!(file, " -> {}", struct_ty).unwrap();
                    writeln!(file, "  {}", vm.get_backend_type_info(ty.id())).unwrap();
127
                } else if ty.is_hybrid() {
128
                    write!(file, "{}", ty).unwrap();
129
130
131
                    let hybrid_ty = hybrid_map
                        .get(&ty.get_struct_hybrid_tag().unwrap())
                        .unwrap();
132
133
                    writeln!(file, " -> {}", hybrid_ty).unwrap();
                    writeln!(file, "  {}", vm.get_backend_type_info(ty.id())).unwrap();
134
                } else {
qinsoon's avatar
qinsoon committed
135
                    // we only care about struct
136
137
138
139
140
141
142
143
                }
            }
        }


    }
}

144
fn emit_mc_dot(func: &MuFunctionVersion, vm: &VM) {
145
    let func_name = func.name();
146
147
148

    // create emit directory/file
    create_emit_directory(vm);
149
    let mut file = create_emit_file(func_name.clone() + ".mc.dot", &vm);
150
151

    // diagraph func {
152
    writeln!(file, "digraph {} {{", mangle_name(func_name)).unwrap();
153
    // node shape: rect
154
    writeln!(file, "node [shape=rect];").unwrap();
155
156
157
158
159
160
161
162

    let compiled_funcs = vm.compiled_funcs().read().unwrap();
    let cf = compiled_funcs.get(&func.id()).unwrap().read().unwrap();
    let mc = cf.mc();

    let blocks = mc.get_all_blocks();

    type DotID = usize;
163
    let name_id_map: HashMap<MuName, DotID> = {
164
165
166
167
168
169
170
171
172
173
174
175
176
177
        let mut ret = HashMap::new();
        let mut index = 0;

        for block_name in blocks.iter() {
            ret.insert(block_name.clone(), index);
            index += 1;
        }

        ret
    };
    let id = |x: MuName| name_id_map.get(&x).unwrap();

    for block_name in blocks.iter() {
        // BB [label = "
178
179
180
181
182
183
        write!(
            file,
            "{} [label = \"{}:\\l\\l",
            id(block_name.clone()),
            block_name
        ).unwrap();
184
185

        for inst in mc.get_block_range(&block_name).unwrap() {
186
187
            file.write_all(&mc.emit_inst(inst)).unwrap();
            write!(file, "\\l").unwrap();
188
189
190
        }

        // "];
191
        writeln!(file, "\"];").unwrap();
192
193
194
195
196
    }

    for block_name in blocks.iter() {
        let end_inst = mc.get_block_range(block_name).unwrap().end;

197
198
199
200
        for succ in mc.get_succs(mc.get_last_inst(end_inst).unwrap())
            .into_iter()
        {
            match mc.get_block_for_inst(*succ) {
201
202
203
                Some(target) => {
                    let source_id = id(block_name.clone());
                    let target_id = id(target.clone());
204
                    writeln!(file, "{} -> {};", source_id, target_id).unwrap();
205
206
                }
                None => {
207
                    panic!("cannot find succesor {} for block {}", succ, block_name);
208
209
210
211
212
                }
            }
        }
    }

213
    writeln!(file, "}}").unwrap();
214
}