1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
use std::{collections::HashMap, fmt};

use debris_common::{CompileContext, Ident};
use debris_error::Result;
use debris_mir::Mir;
use itertools::Itertools;
use rustc_hash::FxHashMap;

use crate::{llir_builder::LlirBuilder, CodeStats, ObjectRef};

use super::{block_id::BlockId, llir_nodes::Function, type_context::TypeContext, Runtime};

/// The low-level intermediate representation struct
///
/// Contains all generated functions and a compilation configuration
#[derive(Debug)]
pub struct Llir {
    /// The functions which were created, excluding the main function
    pub functions: FxHashMap<BlockId, Function>,
    /// The entry point
    pub entry_function: BlockId,
    /// The runtime, which stores resources
    pub runtime: Runtime,
    /// Some statistics interesting for the backend
    pub stats: CodeStats,
}

impl Llir {
    /// Compiles the mir into a llir
    pub fn new(
        ctx: &CompileContext,
        extern_items_factory: impl Fn(&TypeContext) -> HashMap<Ident, ObjectRef>,
        mir: &Mir,
    ) -> Result<Llir> {
        let builder = LlirBuilder::new(
            ctx,
            extern_items_factory,
            &mir.extern_items,
            &mir.namespace,
            &mir.return_values_arena,
        )?;
        builder.build(mir.entry_context, &mir.contexts)
    }
}

impl fmt::Display for Llir {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let call_stats = &self.stats.function_calls;
        let fmt_function = &|func: &Function, f: &mut fmt::Formatter<'_>| {
            let num_calls = call_stats.get(&func.id).unwrap_or(&0);
            write!(f, "({num_calls} call(s)) - {func}")
        };

        for function in self.functions.values().sorted_by_key(|func| func.id) {
            fmt_function(function, f)?;
            f.write_str("\n")?;
        }

        Ok(())
    }
}