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

23 24 25
use std::path;
use std::io::prelude::*;
use std::fs::File;
26
use std::collections::HashMap;
27

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

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

impl CodeEmission {
    pub fn new() -> CodeEmission {
        CodeEmission {
qinsoon's avatar
qinsoon committed
40
            name: "Code Emission",
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) {
qinsoon's avatar
qinsoon committed
69
        Ok(_) => {}
qinsoon's avatar
qinsoon committed
70 71 72 73
        Err(_) => {}
    }
}

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()) {
qinsoon's avatar
qinsoon committed
81 82 83 84 85 86 87 88
        Err(why) => {
            panic!(
                "couldn't create emit file {}: {}",
                file_path.to_str().unwrap(),
                why
            )
        }
        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()) {
qinsoon's avatar
qinsoon committed
101 102 103 104 105 106 107 108
            Err(why) => {
                panic!(
                    "couldn't create mu types file {}: {}",
                    file_path.to_str().unwrap(),
                    why
                )
            }
            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

qinsoon's avatar
qinsoon committed
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();
qinsoon's avatar
qinsoon committed
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;
qinsoon's avatar
qinsoon committed
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 = "
qinsoon's avatar
qinsoon committed
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;

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