llhd/ir/
module.rs

1// Copyright (c) 2017-2021 Fabian Schuiki
2
3//! Representation of linked LLHD units.
4//!
5//! This module implements the `Module`, a collection of LLHD `Function`,
6//! `Process`, and `Entity` objects linked together. A module acts as the root
7//! node of an LLHD intermediate representation, and is the unit of information
8//! ingested by the reader and emitted by the writer.
9
10use crate::{
11    impl_table_key,
12    ir::{ExtUnit, Signature, Unit, UnitBuilder, UnitData, UnitName},
13    table::{PrimaryTable, TableKey},
14    verifier::Verifier,
15};
16use rayon::prelude::*;
17use std::collections::{BTreeSet, HashMap};
18
19/// A module.
20///
21/// This is the root node of an LLHD intermediate representation. Contains
22/// `Function`, `Process`, and `Entity` declarations and definitions.
23#[derive(Serialize, Deserialize)]
24pub struct Module {
25    /// The units in this module.
26    pub(crate) units: PrimaryTable<UnitId, UnitData>,
27    /// The order of units in the module.
28    unit_order: BTreeSet<UnitId>,
29    /// The declarations in this module.
30    pub(crate) decls: PrimaryTable<DeclId, DeclData>,
31    /// The order of declarations in the module.
32    decl_order: BTreeSet<DeclId>,
33    /// The local link table. Maps an external unit declared within a unit to a
34    /// unit in the module.
35    link_table: Option<HashMap<(UnitId, ExtUnit), LinkedUnit>>,
36    /// The location of units in the input file. If the module was read from a
37    /// file, this table *may* contain additional hints on the byte offsets
38    /// where the units were located.
39    location_hints: HashMap<UnitId, usize>,
40}
41
42impl Module {
43    /// Create a new empty module.
44    pub fn new() -> Self {
45        Self {
46            units: PrimaryTable::new(),
47            unit_order: BTreeSet::new(),
48            decls: PrimaryTable::new(),
49            decl_order: BTreeSet::new(),
50            link_table: None,
51            location_hints: Default::default(),
52        }
53    }
54
55    /// Dump the module in human-readable form.
56    pub fn dump(&self) -> ModuleDumper {
57        ModuleDumper(self)
58    }
59
60    /// Add a unit to the module.
61    pub fn add_unit(&mut self, data: UnitData) -> UnitId {
62        let unit = self.units.add(data);
63        self.unit_order.insert(unit);
64        self.link_table = None;
65        unit
66    }
67
68    /// Remove a unit from the module.
69    pub fn remove_unit(&mut self, unit: UnitId) {
70        self.units.remove(unit);
71        self.unit_order.remove(&unit);
72    }
73
74    /// Declare an external unit.
75    pub fn declare(&mut self, name: UnitName, sig: Signature) -> DeclId {
76        self.add_decl(DeclData {
77            name,
78            sig,
79            loc: None,
80        })
81    }
82
83    /// Declare an external unit.
84    pub fn add_decl(&mut self, data: DeclData) -> DeclId {
85        let decl = self.decls.add(data);
86        self.decl_order.insert(decl);
87        self.link_table = None;
88        decl
89    }
90
91    /// Remove a declaration from the module.
92    pub fn remove_decl(&mut self, decl: DeclId) {
93        self.decls.remove(decl);
94        self.decl_order.remove(&decl);
95    }
96
97    /// Return an iterator over the units in this module.
98    pub fn units<'a>(&'a self) -> impl Iterator<Item = Unit<'a>> + 'a {
99        self.unit_order.iter().map(move |&id| self.unit(id))
100    }
101
102    /// Return a mutable iterator over the units in this module.
103    pub fn units_mut<'a>(&'a mut self) -> impl Iterator<Item = UnitBuilder<'a>> + 'a {
104        self.units
105            .storage
106            .iter_mut()
107            .map(|(&id, data)| UnitBuilder::new(UnitId::new(id), data))
108    }
109
110    /// Return a parallel iterator over the units in this module.
111    pub fn par_units<'a>(&'a self) -> impl ParallelIterator<Item = Unit<'a>> + 'a {
112        self.unit_order.par_iter().map(move |&id| self.unit(id))
113    }
114
115    /// Return a parallel mutable iterator over the units in this module.
116    pub fn par_units_mut<'a>(&'a mut self) -> impl ParallelIterator<Item = UnitBuilder<'a>> + 'a {
117        self.units
118            .storage
119            .par_iter_mut()
120            .map(|(&id, data)| UnitBuilder::new(UnitId::new(id), data))
121    }
122
123    /// Return an iterator over the functions in this module.
124    pub fn functions<'a>(&'a self) -> impl Iterator<Item = Unit<'a>> + 'a {
125        self.units().filter(|unit| unit.is_function())
126    }
127
128    /// Return an iterator over the processes in this module.
129    pub fn processes<'a>(&'a self) -> impl Iterator<Item = Unit<'a>> + 'a {
130        self.units().filter(|unit| unit.is_process())
131    }
132
133    /// Return an iterator over the entities in this module.
134    pub fn entities<'a>(&'a self) -> impl Iterator<Item = Unit<'a>> + 'a {
135        self.units().filter(|unit| unit.is_entity())
136    }
137
138    /// Return an iterator over the external unit declarations in this module.
139    pub fn decls<'a>(&'a self) -> impl Iterator<Item = DeclId> + 'a {
140        self.decl_order.iter().cloned()
141    }
142
143    /// Return an unit in the module.
144    pub fn unit(&self, unit: UnitId) -> Unit {
145        Unit::new(unit, &self[unit])
146    }
147
148    /// Return a mutable unit in the module.
149    pub fn unit_mut(&mut self, unit: UnitId) -> UnitBuilder {
150        self.link_table = None;
151        UnitBuilder::new(unit, &mut self[unit])
152    }
153
154    /// Return an iterator over the symbols in the module.
155    pub fn symbols<'a>(&'a self) -> impl Iterator<Item = (&UnitName, LinkedUnit, &Signature)> + 'a {
156        self.units()
157            .map(|unit| (unit.name(), LinkedUnit::Def(unit.id()), unit.sig()))
158            .chain(
159                self.decls()
160                    .map(move |decl| (&self[decl].name, LinkedUnit::Decl(decl), &self[decl].sig)),
161            )
162    }
163
164    /// Return an iterator over the local symbols in the module.
165    pub fn local_symbols<'a>(
166        &'a self,
167    ) -> impl Iterator<Item = (&UnitName, LinkedUnit, &Signature)> + 'a {
168        self.symbols().filter(|&(name, ..)| name.is_local())
169    }
170
171    /// Return an iterator over the global symbols in the module.
172    pub fn global_symbols<'a>(
173        &'a self,
174    ) -> impl Iterator<Item = (&UnitName, LinkedUnit, &Signature)> + 'a {
175        self.symbols().filter(|&(name, ..)| name.is_global())
176    }
177
178    /// Check whether the module is internally linked.
179    ///
180    /// Adding or modifying a unit invalidates the linkage within the module.
181    pub fn is_linked(&self) -> bool {
182        self.link_table.is_some()
183    }
184
185    /// Locally link the module.
186    pub fn link(&mut self) {
187        let mut failed = false;
188
189        // Collect a table of symbols that we can resolve against.
190        let mut symbols = HashMap::new();
191        for (name, unit, sig) in self.symbols() {
192            if let Some((existing, _)) = symbols.insert(name, (unit, sig)) {
193                if !existing.is_decl() {
194                    eprintln!("unit {} declared multiple times", name);
195                    failed = true;
196                }
197            }
198        }
199        if failed {
200            panic!("linking failed; multiple uses of the same name");
201        }
202
203        // Resolve the external units in each unit.
204        let mut linked = HashMap::new();
205        for unit in self.units() {
206            for (ext_unit, data) in unit.extern_units() {
207                let (to, to_sig) = match symbols.get(&data.name).cloned() {
208                    Some(to) => to,
209                    None => {
210                        eprintln!(
211                            "unit {} not found; referenced in {}",
212                            data.name,
213                            unit.name()
214                        );
215                        failed = true;
216                        continue;
217                    }
218                };
219                if to_sig != &data.sig {
220                    eprintln!(
221                        "signature mismatch: {} has {}, but reference in {} expects {}",
222                        data.name,
223                        to_sig,
224                        unit.name(),
225                        data.sig
226                    );
227                    failed = true;
228                    continue;
229                }
230                linked.insert((unit.id(), ext_unit), to);
231            }
232        }
233        if failed {
234            panic!("linking failed; unresolved references");
235        }
236        self.link_table = Some(linked);
237    }
238
239    /// Panic if the module is not well-formed.
240    pub fn verify(&self) {
241        let mut verifier = Verifier::new();
242        verifier.verify_module(self);
243        match verifier.finish() {
244            Ok(()) => (),
245            Err(errs) => {
246                eprintln!("");
247                eprintln!("Verified module:");
248                eprintln!("{}", self.dump());
249                eprintln!("");
250                eprintln!("Verification errors:");
251                eprintln!("{}", errs);
252                panic!("verification failed");
253            }
254        }
255    }
256
257    /// Lookup what an external unit links to.
258    ///
259    /// The module must be linked for this to work.
260    pub fn lookup_ext_unit(&self, ext_unit: ExtUnit, within: UnitId) -> Option<LinkedUnit> {
261        self.link_table
262            .as_ref()
263            .and_then(|lt| lt.get(&(within, ext_unit)))
264            .cloned()
265    }
266
267    /// Add a location hint to a unit.
268    ///
269    /// Annotates the byte offset of a unit in the input file.
270    pub fn set_location_hint(&mut self, mod_unit: UnitId, loc: usize) {
271        self.location_hints.insert(mod_unit, loc);
272    }
273
274    /// Get the location hint associated with a unit.
275    ///
276    /// Returns the byte offset of the unit in the input file, or None if there
277    /// is no hint for the value.
278    pub fn location_hint(&self, mod_unit: UnitId) -> Option<usize> {
279        self.location_hints.get(&mod_unit).cloned()
280    }
281}
282
283impl std::ops::Index<UnitId> for Module {
284    type Output = UnitData;
285    fn index(&self, idx: UnitId) -> &UnitData {
286        &self.units[idx]
287    }
288}
289
290impl std::ops::IndexMut<UnitId> for Module {
291    fn index_mut(&mut self, idx: UnitId) -> &mut UnitData {
292        self.link_table = None;
293        &mut self.units[idx]
294    }
295}
296
297impl std::ops::Index<DeclId> for Module {
298    type Output = DeclData;
299    fn index(&self, idx: DeclId) -> &DeclData {
300        &self.decls[idx]
301    }
302}
303
304impl std::ops::IndexMut<DeclId> for Module {
305    fn index_mut(&mut self, idx: DeclId) -> &mut DeclData {
306        self.link_table = None;
307        &mut self.decls[idx]
308    }
309}
310
311/// Temporary object to dump a `Module` in human-readable form for debugging.
312pub struct ModuleDumper<'a>(&'a Module);
313
314impl std::fmt::Display for ModuleDumper<'_> {
315    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
316        let mut newline = false;
317        for unit in self.0.units() {
318            if newline {
319                writeln!(f, "")?;
320                writeln!(f, "")?;
321            }
322            newline = true;
323            write!(f, "{}: ", unit.id())?;
324            write!(f, "{}", unit)?;
325        }
326        if newline && !self.0.decls().count() > 0 {
327            writeln!(f, "")?;
328        }
329        for decl in self.0.decls() {
330            if newline {
331                writeln!(f, "")?;
332            }
333            newline = true;
334            let data = &self.0[decl];
335            write!(f, "declare {} {}", data.name, data.sig)?;
336        }
337        Ok(())
338    }
339}
340
341impl_table_key! {
342    /// A unit definition in a module.
343    struct UnitId(u32) as "u";
344    /// A unit declaration in a module.
345    struct DeclId(u32) as "decl";
346}
347
348/// A unit declaration.
349#[derive(Serialize, Deserialize)]
350pub struct DeclData {
351    /// The unit signature.
352    pub sig: Signature,
353    /// The unit name.
354    pub name: UnitName,
355    /// The location in the source file.
356    pub loc: Option<usize>,
357}
358
359/// A linked unit.
360#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
361pub enum LinkedUnit {
362    /// A unit definition.
363    Def(UnitId),
364    /// A unit declaration.
365    Decl(DeclId),
366}
367
368impl LinkedUnit {
369    /// Check whether the linked unit is a definition.
370    pub fn is_def(&self) -> bool {
371        match self {
372            LinkedUnit::Def(..) => true,
373            _ => false,
374        }
375    }
376
377    /// Check whether the linked unit is a declaration.
378    pub fn is_decl(&self) -> bool {
379        match self {
380            LinkedUnit::Decl(..) => true,
381            _ => false,
382        }
383    }
384}