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
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use std::collections::{BTreeMap, BTreeSet, HashMap};
use std::rc::Rc;

use arret_runtime::intern;

use super::AnalysedFun;
use crate::mir::ops;

fn add_op_global_interned_names(names: &mut BTreeSet<Rc<str>>, op: &ops::Op) {
    use ops::OpKind;

    match op.kind() {
        OpKind::ConstInternedSym(_, name) | OpKind::ConstBoxedSym(_, name) => {
            if intern::InternedSym::try_from_inline_name(name).is_none() {
                names.insert(name.clone());
            }
        }
        OpKind::Cond(ops::CondOp {
            true_ops,
            false_ops,
            ..
        }) => {
            for op in true_ops.iter().rev().chain(false_ops.iter().rev()) {
                add_op_global_interned_names(names, op);
            }
        }
        _ => {}
    }
}

fn add_fun_global_interned_names(fun: &ops::Fun, names: &mut BTreeSet<Rc<str>>) {
    for op in fun.ops.iter() {
        add_op_global_interned_names(names, op);
    }
}

/// Finds all global interned names in the program and returns them in sorted order
pub fn calc_program_global_interned_names(
    private_funs: &HashMap<ops::PrivateFunId, AnalysedFun<'_>>,
    entry_fun: &ops::Fun,
) -> BTreeMap<Rc<str>, intern::InternedSym> {
    let mut names: BTreeSet<Rc<str>> = BTreeSet::new();

    for fun in private_funs
        .values()
        .map(|af| af.ops_fun)
        .chain(std::iter::once(entry_fun))
    {
        add_fun_global_interned_names(fun, &mut names);
    }

    names
        .into_iter()
        .enumerate()
        .map(|(idx, name)| (name, intern::InternedSym::from_global_index(idx as u32)))
        .collect()
}

#[cfg(test)]
mod test {
    use super::*;

    use arret_runtime::abitype::RetAbiType;
    use arret_runtime::boxed;

    use crate::source::EMPTY_SPAN;

    #[test]
    fn simple_global_interned_names() {
        let param_reg = ops::RegId::alloc();

        let inline_reg = ops::RegId::alloc();
        let alpha_reg = ops::RegId::alloc();
        let beta_reg = ops::RegId::alloc();
        let gamma_reg = ops::RegId::alloc();

        let test_fun = ops::Fun {
            span: EMPTY_SPAN,
            source_name: None,

            abi: ops::OpsAbi {
                call_conv: ops::CallConv::FastCc,
                params: Box::new([boxed::TypeTag::Int.into()]),
                ret: RetAbiType::Void,
            },
            param_regs: Box::new([]),
            ops: Box::new([
                ops::OpKind::ConstBoxedSym(inline_reg, "inline".into()).into(),
                ops::OpKind::Cond(ops::CondOp {
                    reg_phi: None,
                    test_reg: param_reg,
                    true_ops: Box::new([ops::OpKind::ConstBoxedSym(
                        beta_reg,
                        "beta NOT INLINE".into(),
                    )
                    .into()]),
                    false_ops: Box::new([ops::OpKind::ConstInternedSym(
                        gamma_reg,
                        "gamma NOT INLINE".into(),
                    )
                    .into()]),
                })
                .into(),
                ops::OpKind::ConstBoxedSym(alpha_reg, "alpha NOT INLINE".into()).into(),
            ]),
        };

        let global_interned_names = calc_program_global_interned_names(&HashMap::new(), &test_fun);

        assert_eq!(
            [
                ("alpha NOT INLINE", 0u32),
                ("beta NOT INLINE", 1u32),
                ("gamma NOT INLINE", 2u32)
            ]
            .iter()
            .map(|(name, idx)| ((*name).into(), intern::InternedSym::from_global_index(*idx)))
            .collect::<BTreeMap<Rc<str>, _>>(),
            global_interned_names
        );
    }
}