Skip to main content

ir_lang/
module.rs

1//! The [`Module`]: functions, globals, signatures, and aggregates.
2
3use alloc::collections::BTreeMap;
4use alloc::string::{String, ToString};
5use alloc::vec::Vec;
6
7use crate::builder::Builder;
8use crate::entity::{AggId, FuncId, GlobalId, SigId};
9use crate::error::{ModuleError, ValidationError};
10use crate::function::Function;
11use crate::inst::Attrs;
12use crate::types::{Aggregate, Layout, MAX_AGGREGATE_SIZE, MemType, PointerWidth, Signature};
13
14/// How a symbol is visible outside its module.
15///
16/// # Examples
17///
18/// ```
19/// use ir_lang::Linkage;
20///
21/// assert_eq!(Linkage::Export.name(), "export");
22/// assert_eq!(Linkage::from_name("import"), Some(Linkage::Import));
23/// ```
24#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
25#[non_exhaustive]
26pub enum Linkage {
27    /// Defined here and visible only inside the module.
28    Local,
29    /// Defined here and visible to other modules.
30    Export,
31    /// Declared here and defined elsewhere (another module, the runtime, the host,
32    /// or the platform).
33    Import,
34}
35
36impl Linkage {
37    /// The textual name.
38    ///
39    /// # Examples
40    ///
41    /// ```
42    /// use ir_lang::Linkage;
43    ///
44    /// assert_eq!(Linkage::Local.name(), "local");
45    /// ```
46    #[must_use]
47    pub const fn name(self) -> &'static str {
48        match self {
49            Linkage::Local => "local",
50            Linkage::Export => "export",
51            Linkage::Import => "import",
52        }
53    }
54
55    /// Looks a linkage up by its textual name.
56    ///
57    /// # Examples
58    ///
59    /// ```
60    /// use ir_lang::Linkage;
61    ///
62    /// assert_eq!(Linkage::from_name("export"), Some(Linkage::Export));
63    /// ```
64    #[must_use]
65    pub fn from_name(name: &str) -> Option<Linkage> {
66        match name {
67            "local" => Some(Linkage::Local),
68            "export" => Some(Linkage::Export),
69            "import" => Some(Linkage::Import),
70            _ => None,
71        }
72    }
73}
74
75/// A function declaration: name, signature, linkage, and attributes.
76///
77/// # Examples
78///
79/// ```
80/// use ir_lang::{Attrs, Linkage, Module, Signature, Type};
81///
82/// let mut m = Module::new("m");
83/// let f = m.declare_function("puts", &Signature::new(&[Type::Ptr], &[Type::I32]), Linkage::Import)?;
84/// m.set_attrs(f, Attrs::NOGC)?;
85/// let d = m.func_decl(f).unwrap();
86/// assert_eq!((d.name(), d.linkage(), d.attrs()), ("puts", Linkage::Import, Attrs::NOGC));
87/// assert_eq!(m.signature(d.sig()).unwrap().returns, [Type::I32]);
88/// # Ok::<(), ir_lang::ModuleError>(())
89/// ```
90#[derive(Clone, PartialEq, Eq, Debug)]
91pub struct FuncDecl {
92    pub(crate) name: String,
93    pub(crate) sig: SigId,
94    pub(crate) linkage: Linkage,
95    pub(crate) attrs: Attrs,
96}
97
98impl FuncDecl {
99    /// The symbol name.
100    ///
101    /// # Examples
102    ///
103    /// ```
104    /// use ir_lang::{Linkage, Module, Signature};
105    ///
106    /// let mut m = Module::new("m");
107    /// let f = m.declare_function("main", &Signature::new(&[], &[]), Linkage::Export)?;
108    /// assert_eq!(m.func_decl(f).unwrap().name(), "main");
109    /// # Ok::<(), ir_lang::ModuleError>(())
110    /// ```
111    #[must_use]
112    pub fn name(&self) -> &str {
113        &self.name
114    }
115
116    /// The signature.
117    ///
118    /// # Examples
119    ///
120    /// ```
121    /// use ir_lang::{Linkage, Module, Signature};
122    ///
123    /// let mut m = Module::new("m");
124    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Export)?;
125    /// let s = m.func_decl(f).unwrap().sig();
126    /// assert_eq!(m.signature(s), Some(&Signature::new(&[], &[])));
127    /// # Ok::<(), ir_lang::ModuleError>(())
128    /// ```
129    #[must_use]
130    pub fn sig(&self) -> SigId {
131        self.sig
132    }
133
134    /// The linkage.
135    ///
136    /// # Examples
137    ///
138    /// ```
139    /// use ir_lang::{Linkage, Module, Signature};
140    ///
141    /// let mut m = Module::new("m");
142    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Import)?;
143    /// assert_eq!(m.func_decl(f).unwrap().linkage(), Linkage::Import);
144    /// # Ok::<(), ir_lang::ModuleError>(())
145    /// ```
146    #[must_use]
147    pub fn linkage(&self) -> Linkage {
148        self.linkage
149    }
150
151    /// The attributes.
152    ///
153    /// # Examples
154    ///
155    /// ```
156    /// use ir_lang::{Attrs, Linkage, Module, Signature};
157    ///
158    /// let mut m = Module::new("m");
159    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Import)?;
160    /// assert_eq!(m.func_decl(f).unwrap().attrs(), Attrs::NONE);
161    /// # Ok::<(), ir_lang::ModuleError>(())
162    /// ```
163    #[must_use]
164    pub fn attrs(&self) -> Attrs {
165        self.attrs
166    }
167}
168
169/// What a relocation points at.
170///
171/// # Examples
172///
173/// ```
174/// use ir_lang::{FuncId, SymbolRef};
175///
176/// assert!(matches!(SymbolRef::Func(FuncId::from_u32(0)), SymbolRef::Func(_)));
177/// ```
178#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
179#[non_exhaustive]
180pub enum SymbolRef {
181    /// A function's address.
182    Func(FuncId),
183    /// A global's address.
184    Global(GlobalId),
185}
186
187/// An address stored inside a global's initial data: at `offset`, the address of
188/// `target` plus `addend`, as a pointer-width little-endian word.
189///
190/// # Examples
191///
192/// ```
193/// use ir_lang::{GlobalId, Reloc, SymbolRef};
194///
195/// let r = Reloc { offset: 8, target: SymbolRef::Global(GlobalId::from_u32(0)), addend: 4 };
196/// assert_eq!(r.offset, 8);
197/// ```
198#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
199pub struct Reloc {
200    /// Byte offset inside the global.
201    pub offset: u64,
202    /// The symbol whose address is stored.
203    pub target: SymbolRef,
204    /// Added to the address.
205    pub addend: i64,
206}
207
208/// The initial contents of a global.
209///
210/// # Examples
211///
212/// ```
213/// use ir_lang::Init;
214///
215/// assert_eq!(Init::Bytes(vec![1, 2]), Init::Bytes(vec![1, 2]));
216/// ```
217#[derive(Clone, PartialEq, Eq, Hash, Debug)]
218#[non_exhaustive]
219pub enum Init {
220    /// All zero bytes.
221    Zeroed,
222    /// Exactly `size` bytes.
223    Bytes(Vec<u8>),
224}
225
226/// A global (data) definition or import.
227///
228/// Little-endian byte order is assumed for initializers and relocations (every
229/// target the family supports is little-endian).
230///
231/// # Examples
232///
233/// ```
234/// use ir_lang::{Global, Linkage, Module};
235///
236/// let mut m = Module::new("m");
237/// let g = m.declare_global("counter", Global::zeroed(8, 8).mutable())?;
238/// let msg = m.declare_global("msg", Global::bytes(b"hi\0", 1).with_linkage(Linkage::Local))?;
239/// assert!(m.global(g).unwrap().mutable);
240/// assert_eq!(m.global(msg).unwrap().size, 3);
241/// # Ok::<(), ir_lang::ModuleError>(())
242/// ```
243#[derive(Clone, PartialEq, Eq, Debug)]
244pub struct Global {
245    /// Linkage. An `Import` has `Init::Zeroed` and no relocations.
246    pub linkage: Linkage,
247    /// Size in bytes.
248    pub size: u64,
249    /// Alignment in bytes (a power of two, at most 2^16).
250    pub align: u32,
251    /// Whether the program may write it.
252    pub mutable: bool,
253    /// Initial contents.
254    pub init: Init,
255    /// Addresses stored in the initial contents.
256    pub relocs: Vec<Reloc>,
257}
258
259impl Global {
260    /// The largest alignment a global may request.
261    pub const MAX_ALIGN: u32 = 1 << 16;
262
263    /// An exported, immutable, zero-initialized global.
264    ///
265    /// # Examples
266    ///
267    /// ```
268    /// use ir_lang::{Global, Init};
269    ///
270    /// assert_eq!(Global::zeroed(4, 4).init, Init::Zeroed);
271    /// ```
272    #[must_use]
273    pub fn zeroed(size: u64, align: u32) -> Global {
274        Global {
275            linkage: Linkage::Export,
276            size,
277            align,
278            mutable: false,
279            init: Init::Zeroed,
280            relocs: Vec::new(),
281        }
282    }
283
284    /// An exported, immutable global holding `bytes`.
285    ///
286    /// # Examples
287    ///
288    /// ```
289    /// use ir_lang::Global;
290    ///
291    /// assert_eq!(Global::bytes(&[1, 2, 3], 1).size, 3);
292    /// ```
293    #[must_use]
294    pub fn bytes(bytes: &[u8], align: u32) -> Global {
295        Global {
296            linkage: Linkage::Export,
297            size: bytes.len() as u64,
298            align,
299            mutable: false,
300            init: Init::Bytes(bytes.to_vec()),
301            relocs: Vec::new(),
302        }
303    }
304
305    /// An imported global of the given size.
306    ///
307    /// # Examples
308    ///
309    /// ```
310    /// use ir_lang::{Global, Linkage};
311    ///
312    /// assert_eq!(Global::import(8, 8).linkage, Linkage::Import);
313    /// ```
314    #[must_use]
315    pub fn import(size: u64, align: u32) -> Global {
316        Global {
317            linkage: Linkage::Import,
318            ..Global::zeroed(size, align)
319        }
320    }
321
322    /// The same global, writable.
323    ///
324    /// # Examples
325    ///
326    /// ```
327    /// use ir_lang::Global;
328    ///
329    /// assert!(Global::zeroed(1, 1).mutable().mutable);
330    /// ```
331    #[must_use]
332    pub fn mutable(mut self) -> Global {
333        self.mutable = true;
334        self
335    }
336
337    /// The same global with another linkage.
338    ///
339    /// # Examples
340    ///
341    /// ```
342    /// use ir_lang::{Global, Linkage};
343    ///
344    /// assert_eq!(Global::zeroed(1, 1).with_linkage(Linkage::Local).linkage, Linkage::Local);
345    /// ```
346    #[must_use]
347    pub fn with_linkage(mut self, linkage: Linkage) -> Global {
348        self.linkage = linkage;
349        self
350    }
351
352    /// The same global with a relocation added.
353    ///
354    /// # Examples
355    ///
356    /// ```
357    /// use ir_lang::{FuncId, Global, Reloc, SymbolRef};
358    ///
359    /// let g = Global::zeroed(8, 8).with_reloc(Reloc { offset: 0, target: SymbolRef::Func(FuncId::from_u32(0)), addend: 0 });
360    /// assert_eq!(g.relocs.len(), 1);
361    /// ```
362    #[must_use]
363    pub fn with_reloc(mut self, reloc: Reloc) -> Global {
364        self.relocs.push(reloc);
365        self
366    }
367}
368
369#[derive(Clone, PartialEq, Eq, Debug)]
370pub(crate) struct AggData {
371    pub(crate) agg: Aggregate,
372    pub(crate) layout: Layout,
373    pub(crate) offsets: Vec<u64>,
374}
375
376#[derive(Clone, PartialEq, Eq, Debug)]
377pub(crate) struct GlobalDecl {
378    pub(crate) name: String,
379    pub(crate) global: Global,
380}
381
382/// The declarations of a module, borrowed by a builder while it edits one body.
383#[derive(Clone, Debug, Default)]
384pub(crate) struct Decls {
385    pub(crate) ptr: PointerWidth,
386    pub(crate) sigs: Vec<Signature>,
387    pub(crate) sig_index: BTreeMap<Signature, SigId>,
388    pub(crate) aggs: Vec<AggData>,
389    pub(crate) funcs: Vec<FuncDecl>,
390    pub(crate) globals: Vec<GlobalDecl>,
391}
392
393impl Decls {
394    pub(crate) fn layout(&self, ty: MemType) -> Option<Layout> {
395        match ty {
396            MemType::Scalar(t) => {
397                let size = t.size(self.ptr);
398                Some(Layout {
399                    size: u64::from(size),
400                    align: size.max(1),
401                })
402            }
403            MemType::Agg(a) => self.aggs.get(a.index()).map(|d| d.layout),
404        }
405    }
406
407    pub(crate) fn func_sig(&self, func: FuncId) -> Option<&Signature> {
408        self.funcs
409            .get(func.index())
410            .and_then(|d| self.sigs.get(d.sig.index()))
411    }
412
413    /// Computes the layout and field offsets of an aggregate whose components must
414    /// all be declared before `limit`.
415    pub(crate) fn compute_layout(
416        &self,
417        agg: &Aggregate,
418        limit: usize,
419    ) -> Result<(Layout, Vec<u64>), ModuleError> {
420        let component = |m: MemType| -> Result<Layout, ModuleError> {
421            if let MemType::Agg(a) = m {
422                if a.index() >= limit {
423                    return Err(ModuleError::UnknownAggregate { agg: a });
424                }
425            }
426            self.layout(m).ok_or(ModuleError::AggregateTooLarge)
427        };
428        match agg {
429            Aggregate::Struct { fields, packed } => {
430                let mut offset = 0u64;
431                let mut align = 1u32;
432                let mut offsets = Vec::with_capacity(fields.len());
433                for &field in fields {
434                    let l = component(field)?;
435                    if !packed {
436                        offset = round_up(offset, l.align).ok_or(ModuleError::AggregateTooLarge)?;
437                        align = align.max(l.align);
438                    }
439                    offsets.push(offset);
440                    offset = offset
441                        .checked_add(l.size)
442                        .filter(|&s| s <= MAX_AGGREGATE_SIZE)
443                        .ok_or(ModuleError::AggregateTooLarge)?;
444                }
445                let size = if *packed {
446                    offset
447                } else {
448                    round_up(offset, align).ok_or(ModuleError::AggregateTooLarge)?
449                };
450                if size > MAX_AGGREGATE_SIZE {
451                    return Err(ModuleError::AggregateTooLarge);
452                }
453                Ok((Layout { size, align }, offsets))
454            }
455            Aggregate::Array { elem, len } => {
456                let l = component(*elem)?;
457                let size = l
458                    .size
459                    .checked_mul(*len)
460                    .filter(|&s| s <= MAX_AGGREGATE_SIZE)
461                    .ok_or(ModuleError::AggregateTooLarge)?;
462                Ok((
463                    Layout {
464                        size,
465                        align: l.align,
466                    },
467                    Vec::new(),
468                ))
469            }
470        }
471    }
472}
473
474pub(crate) fn round_up(value: u64, align: u32) -> Option<u64> {
475    let a = u64::from(align.max(1));
476    let rem = value % a;
477    if rem == 0 {
478        Some(value)
479    } else {
480        value.checked_add(a - rem)
481    }
482}
483
484pub(crate) fn valid_align(align: u64, max: u64) -> bool {
485    align != 0 && align.is_power_of_two() && align <= max
486}
487
488/// A compilation unit of IR: function declarations and bodies, globals, interned
489/// signatures, and aggregate types.
490///
491/// Declarations come first (so calls and addresses can name any function or global);
492/// bodies are then built with [`build`](Module::build) and changed with
493/// [`edit`](Module::edit). [`validate`](Module::validate) checks the whole module, the
494/// [`Display`](core::fmt::Display) implementation prints it in the textual form, and
495/// [`parse`](crate::parse) reads that form back.
496///
497/// # Examples
498///
499/// ```
500/// use ir_lang::{CmpOp, Linkage, Module, Signature, Type};
501///
502/// // fn max(a: i64, b: i64) -> i64 { if a < b { b } else { a } }
503/// let mut m = Module::new("demo");
504/// let f = m.declare_function("max", &Signature::new(&[Type::I64, Type::I64], &[Type::I64]), Linkage::Export)?;
505/// let mut b = m.build(f)?;
506/// let (a, c) = (b.param(0)?, b.param(1)?);
507/// let lt = b.compare(CmpOp::Lt, a, c)?;
508/// let exit = b.create_block(&[Type::I64])?;
509/// b.branch(lt, exit, &[c], exit, &[a])?;
510/// b.switch_to(exit)?;
511/// let r = b.block_param(exit, 0)?;
512/// b.ret(&[r])?;
513///
514/// m.validate()?;
515/// let text = m.to_string();
516/// assert!(text.contains("br v2, b1(v1), b1(v0)"));
517/// assert_eq!(ir_lang::parse(&text)?.to_string(), text);
518/// # Ok::<(), Box<dyn std::error::Error>>(())
519/// ```
520#[derive(Clone, Debug)]
521pub struct Module {
522    pub(crate) name: String,
523    pub(crate) decls: Decls,
524    pub(crate) bodies: Vec<Option<Function>>,
525    pub(crate) names: BTreeMap<String, SymbolRef>,
526}
527
528impl Module {
529    /// An empty module with 64-bit addresses.
530    ///
531    /// # Examples
532    ///
533    /// ```
534    /// use ir_lang::{Module, PointerWidth};
535    ///
536    /// let m = Module::new("app");
537    /// assert_eq!((m.name(), m.pointer_width()), ("app", PointerWidth::P64));
538    /// ```
539    #[must_use]
540    pub fn new(name: &str) -> Module {
541        Module::with_pointer_width(name, PointerWidth::P64)
542    }
543
544    /// An empty module with the given address width.
545    ///
546    /// # Examples
547    ///
548    /// ```
549    /// use ir_lang::{Module, PointerWidth, Type};
550    ///
551    /// let m = Module::with_pointer_width("wasm", PointerWidth::P32);
552    /// assert_eq!(m.layout(Type::Ptr.into()).unwrap().size(), 4);
553    /// ```
554    #[must_use]
555    pub fn with_pointer_width(name: &str, ptr: PointerWidth) -> Module {
556        Module {
557            name: name.to_string(),
558            decls: Decls {
559                ptr,
560                ..Decls::default()
561            },
562            bodies: Vec::new(),
563            names: BTreeMap::new(),
564        }
565    }
566
567    /// The module's name.
568    ///
569    /// # Examples
570    ///
571    /// ```
572    /// use ir_lang::Module;
573    ///
574    /// assert_eq!(Module::new("app").name(), "app");
575    /// ```
576    #[must_use]
577    pub fn name(&self) -> &str {
578        &self.name
579    }
580
581    /// The address width.
582    ///
583    /// # Examples
584    ///
585    /// ```
586    /// use ir_lang::{Module, PointerWidth};
587    ///
588    /// assert_eq!(Module::with_pointer_width("w", PointerWidth::P32).pointer_width(), PointerWidth::P32);
589    /// ```
590    #[must_use]
591    pub fn pointer_width(&self) -> PointerWidth {
592        self.decls.ptr
593    }
594
595    /// Interns a signature, returning the existing handle for an equal one.
596    ///
597    /// # Errors
598    ///
599    /// [`ModuleError::CapacityExceeded`] if the table is full.
600    ///
601    /// # Examples
602    ///
603    /// ```
604    /// use ir_lang::{Module, Signature, Type};
605    ///
606    /// let mut m = Module::new("m");
607    /// let a = m.intern_signature(&Signature::new(&[Type::I32], &[]))?;
608    /// let b = m.intern_signature(&Signature::new(&[Type::I32], &[]))?;
609    /// assert_eq!(a, b);
610    /// # Ok::<(), ir_lang::ModuleError>(())
611    /// ```
612    pub fn intern_signature(&mut self, sig: &Signature) -> Result<SigId, ModuleError> {
613        if let Some(&id) = self.decls.sig_index.get(sig) {
614            return Ok(id);
615        }
616        let id = SigId::from_u32(next_index(self.decls.sigs.len())?);
617        self.decls.sigs.push(sig.clone());
618        let _ = self.decls.sig_index.insert(sig.clone(), id);
619        Ok(id)
620    }
621
622    /// The signature behind a handle.
623    ///
624    /// # Examples
625    ///
626    /// ```
627    /// use ir_lang::{Module, Signature, Type};
628    ///
629    /// let mut m = Module::new("m");
630    /// let s = m.intern_signature(&Signature::new(&[], &[Type::Bool]))?;
631    /// assert_eq!(m.signature(s).unwrap().returns, [Type::Bool]);
632    /// # Ok::<(), ir_lang::ModuleError>(())
633    /// ```
634    #[must_use]
635    pub fn signature(&self, sig: SigId) -> Option<&Signature> {
636        self.decls.sigs.get(sig.index())
637    }
638
639    /// The number of interned signatures.
640    ///
641    /// # Examples
642    ///
643    /// ```
644    /// use ir_lang::{Module, Signature};
645    ///
646    /// let mut m = Module::new("m");
647    /// m.intern_signature(&Signature::new(&[], &[]))?;
648    /// m.intern_signature(&Signature::new(&[], &[]))?;
649    /// assert_eq!(m.signature_count(), 1);
650    /// # Ok::<(), ir_lang::ModuleError>(())
651    /// ```
652    #[must_use]
653    pub fn signature_count(&self) -> usize {
654        self.decls.sigs.len()
655    }
656
657    /// Declares an aggregate type and computes its layout.
658    ///
659    /// # Errors
660    ///
661    /// [`ModuleError::UnknownAggregate`] if it names an aggregate not declared
662    /// before it; [`ModuleError::AggregateTooLarge`] if its size exceeds
663    /// [`MAX_AGGREGATE_SIZE`]; [`ModuleError::CapacityExceeded`].
664    ///
665    /// # Examples
666    ///
667    /// ```
668    /// use ir_lang::{Aggregate, Module, Type};
669    ///
670    /// let mut m = Module::new("m");
671    /// let v3 = m.declare_aggregate(Aggregate::array(Type::F32.into(), 3))?;
672    /// assert_eq!(m.layout(v3.into()).unwrap().size(), 12);
673    /// # Ok::<(), ir_lang::ModuleError>(())
674    /// ```
675    pub fn declare_aggregate(&mut self, agg: Aggregate) -> Result<AggId, ModuleError> {
676        let index = next_index(self.decls.aggs.len())?;
677        let (layout, offsets) = self.decls.compute_layout(&agg, index as usize)?;
678        self.decls.aggs.push(AggData {
679            agg,
680            layout,
681            offsets,
682        });
683        Ok(AggId::from_u32(index))
684    }
685
686    /// The aggregate behind a handle.
687    ///
688    /// # Examples
689    ///
690    /// ```
691    /// use ir_lang::{Aggregate, Module, Type};
692    ///
693    /// let mut m = Module::new("m");
694    /// let a = m.declare_aggregate(Aggregate::array(Type::U8.into(), 3))?;
695    /// assert_eq!(m.aggregate(a), Some(&Aggregate::array(Type::U8.into(), 3)));
696    /// # Ok::<(), ir_lang::ModuleError>(())
697    /// ```
698    #[must_use]
699    pub fn aggregate(&self, agg: AggId) -> Option<&Aggregate> {
700        self.decls.aggs.get(agg.index()).map(|d| &d.agg)
701    }
702
703    /// The number of declared aggregates.
704    ///
705    /// # Examples
706    ///
707    /// ```
708    /// use ir_lang::{Aggregate, Module, Type};
709    ///
710    /// let mut m = Module::new("m");
711    /// m.declare_aggregate(Aggregate::structure(&[Type::U8.into()]))?;
712    /// assert_eq!(m.aggregate_count(), 1);
713    /// # Ok::<(), ir_lang::ModuleError>(())
714    /// ```
715    #[must_use]
716    pub fn aggregate_count(&self) -> usize {
717        self.decls.aggs.len()
718    }
719
720    /// The size and alignment of a memory type, or `None` for an unknown
721    /// aggregate.
722    ///
723    /// # Examples
724    ///
725    /// ```
726    /// use ir_lang::{Module, Type};
727    ///
728    /// let m = Module::new("m");
729    /// assert_eq!(m.layout(Type::Bool.into()).unwrap().size(), 1);
730    /// ```
731    #[must_use]
732    pub fn layout(&self, ty: MemType) -> Option<Layout> {
733        self.decls.layout(ty)
734    }
735
736    /// The byte offset of a struct field, or `None` if `agg` is not a struct or has
737    /// no such field.
738    ///
739    /// # Examples
740    ///
741    /// ```
742    /// use ir_lang::{Aggregate, Module, Type};
743    ///
744    /// let mut m = Module::new("m");
745    /// let s = m.declare_aggregate(Aggregate::packed(&[Type::U8.into(), Type::U32.into()]))?;
746    /// assert_eq!(m.field_offset(s, 1), Some(1));
747    /// assert_eq!(m.field_offset(s, 2), None);
748    /// # Ok::<(), ir_lang::ModuleError>(())
749    /// ```
750    #[must_use]
751    pub fn field_offset(&self, agg: AggId, field: u32) -> Option<u64> {
752        let data = self.decls.aggs.get(agg.index())?;
753        match data.agg {
754            Aggregate::Struct { .. } => data.offsets.get(field as usize).copied(),
755            Aggregate::Array { .. } => None,
756        }
757    }
758
759    fn claim_name(&self, name: &str) -> Result<(), ModuleError> {
760        if name.is_empty() {
761            return Err(ModuleError::EmptyName);
762        }
763        if self.names.contains_key(name) {
764            return Err(ModuleError::DuplicateName {
765                name: name.to_string(),
766            });
767        }
768        Ok(())
769    }
770
771    /// Declares a function. Its signature is interned. A `Local` or `Export`
772    /// function needs a body ([`build`](Module::build)) before the module validates;
773    /// an `Import` must not have one.
774    ///
775    /// # Errors
776    ///
777    /// [`ModuleError::EmptyName`], [`ModuleError::DuplicateName`],
778    /// [`ModuleError::CapacityExceeded`].
779    ///
780    /// # Examples
781    ///
782    /// ```
783    /// use ir_lang::{Linkage, Module, Signature, Type};
784    ///
785    /// let mut m = Module::new("m");
786    /// let f = m.declare_function("main", &Signature::new(&[], &[Type::I32]), Linkage::Export)?;
787    /// assert_eq!(m.func_decl(f).unwrap().name(), "main");
788    /// # Ok::<(), ir_lang::ModuleError>(())
789    /// ```
790    pub fn declare_function(
791        &mut self,
792        name: &str,
793        sig: &Signature,
794        linkage: Linkage,
795    ) -> Result<FuncId, ModuleError> {
796        self.claim_name(name)?;
797        let index = next_index(self.decls.funcs.len())?;
798        let sig = self.intern_signature(sig)?;
799        let id = FuncId::from_u32(index);
800        self.decls.funcs.push(FuncDecl {
801            name: name.to_string(),
802            sig,
803            linkage,
804            attrs: Attrs::NONE,
805        });
806        self.bodies.push(None);
807        let _ = self.names.insert(name.to_string(), SymbolRef::Func(id));
808        Ok(id)
809    }
810
811    /// Sets a function's attributes.
812    ///
813    /// # Errors
814    ///
815    /// [`ModuleError::UnknownFunction`].
816    ///
817    /// # Examples
818    ///
819    /// ```
820    /// use ir_lang::{Attrs, Linkage, Module, Signature};
821    ///
822    /// let mut m = Module::new("m");
823    /// let f = m.declare_function("abort", &Signature::new(&[], &[]), Linkage::Import)?;
824    /// m.set_attrs(f, Attrs::NORETURN | Attrs::NOUNWIND)?;
825    /// assert!(m.func_decl(f).unwrap().attrs().contains(Attrs::NORETURN));
826    /// # Ok::<(), ir_lang::ModuleError>(())
827    /// ```
828    pub fn set_attrs(&mut self, func: FuncId, attrs: Attrs) -> Result<(), ModuleError> {
829        let decl = self
830            .decls
831            .funcs
832            .get_mut(func.index())
833            .ok_or(ModuleError::UnknownFunction { func })?;
834        decl.attrs = attrs;
835        Ok(())
836    }
837
838    /// A function's declaration.
839    ///
840    /// # Examples
841    ///
842    /// ```
843    /// use ir_lang::{Linkage, Module, Signature};
844    ///
845    /// let mut m = Module::new("m");
846    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
847    /// assert_eq!(m.func_decl(f).map(|d| d.linkage()), Some(Linkage::Local));
848    /// # Ok::<(), ir_lang::ModuleError>(())
849    /// ```
850    #[must_use]
851    pub fn func_decl(&self, func: FuncId) -> Option<&FuncDecl> {
852        self.decls.funcs.get(func.index())
853    }
854
855    /// A function's signature.
856    ///
857    /// # Examples
858    ///
859    /// ```
860    /// use ir_lang::{Linkage, Module, Signature, Type};
861    ///
862    /// let mut m = Module::new("m");
863    /// let f = m.declare_function("f", &Signature::new(&[Type::U8], &[]), Linkage::Import)?;
864    /// assert_eq!(m.func_signature(f).unwrap().params, [Type::U8]);
865    /// # Ok::<(), ir_lang::ModuleError>(())
866    /// ```
867    #[must_use]
868    pub fn func_signature(&self, func: FuncId) -> Option<&Signature> {
869        self.decls.func_sig(func)
870    }
871
872    /// The number of declared functions.
873    ///
874    /// # Examples
875    ///
876    /// ```
877    /// use ir_lang::{Linkage, Module, Signature};
878    ///
879    /// let mut m = Module::new("m");
880    /// m.declare_function("f", &Signature::new(&[], &[]), Linkage::Import)?;
881    /// assert_eq!(m.function_count(), 1);
882    /// # Ok::<(), ir_lang::ModuleError>(())
883    /// ```
884    #[must_use]
885    pub fn function_count(&self) -> usize {
886        self.decls.funcs.len()
887    }
888
889    /// Iterates over every declared function, in handle order.
890    ///
891    /// # Examples
892    ///
893    /// ```
894    /// use ir_lang::{Linkage, Module, Signature};
895    ///
896    /// let mut m = Module::new("m");
897    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Import)?;
898    /// assert_eq!(m.functions().collect::<Vec<_>>(), [f]);
899    /// # Ok::<(), ir_lang::ModuleError>(())
900    /// ```
901    pub fn functions(&self) -> impl ExactSizeIterator<Item = FuncId> {
902        (0..self.decls.funcs.len() as u32).map(FuncId::from_u32)
903    }
904
905    /// A function's body, if it has one.
906    ///
907    /// # Examples
908    ///
909    /// ```
910    /// use ir_lang::{Linkage, Module, Signature};
911    ///
912    /// let mut m = Module::new("m");
913    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Export)?;
914    /// assert!(m.function(f).is_none());
915    /// let mut b = m.build(f)?;
916    /// b.ret(&[])?;
917    /// assert!(m.function(f).is_some());
918    /// # Ok::<(), Box<dyn std::error::Error>>(())
919    /// ```
920    #[must_use]
921    pub fn function(&self, func: FuncId) -> Option<&Function> {
922        self.bodies.get(func.index()).and_then(Option::as_ref)
923    }
924
925    /// Declares a global.
926    ///
927    /// # Errors
928    ///
929    /// [`ModuleError::EmptyName`], [`ModuleError::DuplicateName`],
930    /// [`ModuleError::BadAlignment`], [`ModuleError::InitSizeMismatch`],
931    /// [`ModuleError::RelocOutOfRange`], [`ModuleError::ImportWithData`],
932    /// [`ModuleError::CapacityExceeded`]. Relocation targets are checked by
933    /// [`validate`](Module::validate), so a global may point at symbols declared
934    /// after it (or at itself).
935    ///
936    /// # Examples
937    ///
938    /// ```
939    /// use ir_lang::{Global, Module, ModuleError};
940    ///
941    /// let mut m = Module::new("m");
942    /// let err = m.declare_global("bad", Global::zeroed(8, 3)).unwrap_err();
943    /// assert_eq!(err, ModuleError::BadAlignment { align: 3 });
944    /// ```
945    pub fn declare_global(&mut self, name: &str, global: Global) -> Result<GlobalId, ModuleError> {
946        self.claim_name(name)?;
947        check_global(&global, self.decls.ptr)?;
948        let index = next_index(self.decls.globals.len())?;
949        let id = GlobalId::from_u32(index);
950        self.decls.globals.push(GlobalDecl {
951            name: name.to_string(),
952            global,
953        });
954        let _ = self.names.insert(name.to_string(), SymbolRef::Global(id));
955        Ok(id)
956    }
957
958    /// A global's definition.
959    ///
960    /// # Examples
961    ///
962    /// ```
963    /// use ir_lang::{Global, Module};
964    ///
965    /// let mut m = Module::new("m");
966    /// let g = m.declare_global("g", Global::zeroed(16, 8))?;
967    /// assert_eq!(m.global(g).map(|g| g.size), Some(16));
968    /// # Ok::<(), ir_lang::ModuleError>(())
969    /// ```
970    #[must_use]
971    pub fn global(&self, global: GlobalId) -> Option<&Global> {
972        self.decls.globals.get(global.index()).map(|g| &g.global)
973    }
974
975    /// A global's name.
976    ///
977    /// # Examples
978    ///
979    /// ```
980    /// use ir_lang::{Global, Module};
981    ///
982    /// let mut m = Module::new("m");
983    /// let g = m.declare_global("table", Global::zeroed(8, 8))?;
984    /// assert_eq!(m.global_name(g), Some("table"));
985    /// # Ok::<(), ir_lang::ModuleError>(())
986    /// ```
987    #[must_use]
988    pub fn global_name(&self, global: GlobalId) -> Option<&str> {
989        self.decls
990            .globals
991            .get(global.index())
992            .map(|g| g.name.as_str())
993    }
994
995    /// The number of declared globals.
996    ///
997    /// # Examples
998    ///
999    /// ```
1000    /// use ir_lang::{Global, Module};
1001    ///
1002    /// let mut m = Module::new("m");
1003    /// m.declare_global("g", Global::zeroed(1, 1))?;
1004    /// assert_eq!(m.global_count(), 1);
1005    /// # Ok::<(), ir_lang::ModuleError>(())
1006    /// ```
1007    #[must_use]
1008    pub fn global_count(&self) -> usize {
1009        self.decls.globals.len()
1010    }
1011
1012    /// Iterates over every declared global, in handle order.
1013    ///
1014    /// # Examples
1015    ///
1016    /// ```
1017    /// use ir_lang::{Global, Module};
1018    ///
1019    /// let mut m = Module::new("m");
1020    /// let g = m.declare_global("g", Global::zeroed(1, 1))?;
1021    /// assert_eq!(m.globals().collect::<Vec<_>>(), [g]);
1022    /// # Ok::<(), ir_lang::ModuleError>(())
1023    /// ```
1024    pub fn globals(&self) -> impl ExactSizeIterator<Item = GlobalId> {
1025        (0..self.decls.globals.len() as u32).map(GlobalId::from_u32)
1026    }
1027
1028    /// Looks a function or global up by name.
1029    ///
1030    /// # Examples
1031    ///
1032    /// ```
1033    /// use ir_lang::{Global, Module, SymbolRef};
1034    ///
1035    /// let mut m = Module::new("m");
1036    /// let g = m.declare_global("g", Global::zeroed(1, 1))?;
1037    /// assert_eq!(m.lookup("g"), Some(SymbolRef::Global(g)));
1038    /// assert_eq!(m.lookup("h"), None);
1039    /// # Ok::<(), ir_lang::ModuleError>(())
1040    /// ```
1041    #[must_use]
1042    pub fn lookup(&self, name: &str) -> Option<SymbolRef> {
1043        self.names.get(name).copied()
1044    }
1045
1046    /// Creates the body of a declared function and returns a [`Builder`]
1047    /// positioned at the end of its entry block. The entry block's parameters are
1048    /// the signature's parameters.
1049    ///
1050    /// # Errors
1051    ///
1052    /// [`ModuleError::UnknownFunction`], [`ModuleError::CannotDefineImport`],
1053    /// [`ModuleError::AlreadyDefined`].
1054    ///
1055    /// # Examples
1056    ///
1057    /// ```
1058    /// use ir_lang::{Linkage, Module, Signature};
1059    ///
1060    /// let mut m = Module::new("m");
1061    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Export)?;
1062    /// let mut b = m.build(f)?;
1063    /// b.ret(&[])?;
1064    /// assert!(m.build(f).is_err());
1065    /// m.validate()?;
1066    /// # Ok::<(), Box<dyn std::error::Error>>(())
1067    /// ```
1068    pub fn build(&mut self, func: FuncId) -> Result<Builder<'_>, ModuleError> {
1069        let decl = self
1070            .decls
1071            .funcs
1072            .get(func.index())
1073            .ok_or(ModuleError::UnknownFunction { func })?;
1074        if decl.linkage == Linkage::Import {
1075            return Err(ModuleError::CannotDefineImport { func });
1076        }
1077        let params = self
1078            .decls
1079            .sigs
1080            .get(decl.sig.index())
1081            .map(|s| s.params.clone())
1082            .unwrap_or_default();
1083        let slot = self
1084            .bodies
1085            .get_mut(func.index())
1086            .ok_or(ModuleError::UnknownFunction { func })?;
1087        if slot.is_some() {
1088            return Err(ModuleError::AlreadyDefined { func });
1089        }
1090        let body = slot.insert(Function::new(&params));
1091        Ok(Builder::new(&self.decls, body, func))
1092    }
1093
1094    /// Returns a [`Builder`] over an existing body, positioned at the end of the
1095    /// entry block, for rewriting.
1096    ///
1097    /// # Errors
1098    ///
1099    /// [`ModuleError::UnknownFunction`], [`ModuleError::NotDefined`].
1100    ///
1101    /// # Examples
1102    ///
1103    /// ```
1104    /// use ir_lang::{Linkage, Module, Signature};
1105    ///
1106    /// let mut m = Module::new("m");
1107    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Export)?;
1108    /// let _ = m.build(f)?;
1109    /// let mut b = m.edit(f)?;
1110    /// b.ret(&[])?;
1111    /// m.validate()?;
1112    /// # Ok::<(), Box<dyn std::error::Error>>(())
1113    /// ```
1114    pub fn edit(&mut self, func: FuncId) -> Result<Builder<'_>, ModuleError> {
1115        let body = self
1116            .bodies
1117            .get_mut(func.index())
1118            .ok_or(ModuleError::UnknownFunction { func })?
1119            .as_mut()
1120            .ok_or(ModuleError::NotDefined { func })?;
1121        Ok(Builder::new(&self.decls, body, func))
1122    }
1123
1124    /// Checks the whole module: declarations, then every function body.
1125    ///
1126    /// Validation is total: it either accepts the module, guaranteeing every rule
1127    /// of `specs/IR.md` holds, or returns the first violation. It never panics and
1128    /// runs in time linear in the size of the module (plus the size of the live
1129    /// ranges of GC references, for the safepoint rule).
1130    ///
1131    /// # Errors
1132    ///
1133    /// The first [`ValidationError`] found.
1134    ///
1135    /// # Examples
1136    ///
1137    /// ```
1138    /// use ir_lang::{Linkage, Module, Signature};
1139    ///
1140    /// let mut m = Module::new("m");
1141    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Export)?;
1142    /// assert!(m.validate().is_err()); // no body yet
1143    /// let mut b = m.build(f)?;
1144    /// b.ret(&[])?;
1145    /// assert!(m.validate().is_ok());
1146    /// # Ok::<(), Box<dyn std::error::Error>>(())
1147    /// ```
1148    pub fn validate(&self) -> Result<(), ValidationError> {
1149        crate::validate::validate_module(self)
1150    }
1151
1152    /// Checks one function body (and the declarations it uses).
1153    ///
1154    /// # Errors
1155    ///
1156    /// The first [`ValidationError`] found in that function;
1157    /// [`ValidationErrorKind::UnknownFunction`](crate::ValidationErrorKind::UnknownFunction)
1158    /// or [`MissingBody`](crate::ValidationErrorKind::MissingBody) if there is no
1159    /// such body.
1160    ///
1161    /// # Examples
1162    ///
1163    /// ```
1164    /// use ir_lang::{Linkage, Module, Signature};
1165    ///
1166    /// let mut m = Module::new("m");
1167    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Export)?;
1168    /// let mut b = m.build(f)?;
1169    /// b.ret(&[])?;
1170    /// m.validate_function(f)?;
1171    /// # Ok::<(), Box<dyn std::error::Error>>(())
1172    /// ```
1173    pub fn validate_function(&self, func: FuncId) -> Result<(), ValidationError> {
1174        crate::validate::validate_one(self, func)
1175    }
1176
1177    /// Prints one function in the textual form.
1178    ///
1179    /// # Examples
1180    ///
1181    /// ```
1182    /// use ir_lang::{Linkage, Module, Signature};
1183    ///
1184    /// let mut m = Module::new("m");
1185    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Export)?;
1186    /// let mut b = m.build(f)?;
1187    /// b.ret(&[])?;
1188    /// assert_eq!(m.display_function(f).to_string(), "func @f s0 export {\nb0:\n    ret\n}\n");
1189    /// # Ok::<(), Box<dyn std::error::Error>>(())
1190    /// ```
1191    #[must_use]
1192    pub fn display_function(&self, func: FuncId) -> impl core::fmt::Display + '_ {
1193        crate::print::FunctionDisplay { module: self, func }
1194    }
1195
1196    /// Installs a body without checks (the parser's door; validation catches any
1197    /// inconsistency).
1198    pub(crate) fn set_body(&mut self, func: FuncId, body: Function) {
1199        if let Some(slot) = self.bodies.get_mut(func.index()) {
1200            *slot = Some(body);
1201        }
1202    }
1203}
1204
1205fn next_index(len: usize) -> Result<u32, ModuleError> {
1206    u32::try_from(len)
1207        .ok()
1208        .filter(|&i| i < crate::function::MAX_ENTITIES)
1209        .ok_or(ModuleError::CapacityExceeded)
1210}
1211
1212pub(crate) fn check_global(global: &Global, ptr: PointerWidth) -> Result<(), ModuleError> {
1213    if !valid_align(u64::from(global.align), u64::from(Global::MAX_ALIGN)) {
1214        return Err(ModuleError::BadAlignment {
1215            align: u64::from(global.align),
1216        });
1217    }
1218    if global.linkage == Linkage::Import
1219        && (global.init != Init::Zeroed || !global.relocs.is_empty())
1220    {
1221        return Err(ModuleError::ImportWithData);
1222    }
1223    if let Init::Bytes(bytes) = &global.init {
1224        if bytes.len() as u64 != global.size {
1225            return Err(ModuleError::InitSizeMismatch {
1226                size: global.size,
1227                found: bytes.len() as u64,
1228            });
1229        }
1230    }
1231    for r in &global.relocs {
1232        let fits = r
1233            .offset
1234            .checked_add(u64::from(ptr.bytes()))
1235            .is_some_and(|end| end <= global.size);
1236        if !fits {
1237            return Err(ModuleError::RelocOutOfRange { offset: r.offset });
1238        }
1239    }
1240    Ok(())
1241}
1242
1243#[cfg(test)]
1244mod tests {
1245    use super::*;
1246    use crate::types::Type;
1247
1248    #[test]
1249    fn test_struct_layout_follows_c_rules() {
1250        let mut m = Module::new("m");
1251        let s = m
1252            .declare_aggregate(Aggregate::structure(&[
1253                Type::U8.into(),
1254                Type::U32.into(),
1255                Type::U16.into(),
1256            ]))
1257            .unwrap_or(AggId::from_u32(0));
1258        let l = m.layout(s.into()).unwrap_or(Layout { size: 0, align: 0 });
1259        assert_eq!((l.size, l.align), (12, 4));
1260        assert_eq!(m.field_offset(s, 0), Some(0));
1261        assert_eq!(m.field_offset(s, 1), Some(4));
1262        assert_eq!(m.field_offset(s, 2), Some(8));
1263    }
1264
1265    #[test]
1266    fn test_aggregate_cannot_name_a_later_aggregate() {
1267        let mut m = Module::new("m");
1268        let err = m.declare_aggregate(Aggregate::array(AggId::from_u32(0).into(), 2));
1269        assert_eq!(
1270            err,
1271            Err(ModuleError::UnknownAggregate {
1272                agg: AggId::from_u32(0)
1273            })
1274        );
1275    }
1276
1277    #[test]
1278    fn test_huge_aggregate_is_refused() {
1279        let mut m = Module::new("m");
1280        let err = m.declare_aggregate(Aggregate::array(Type::U64.into(), u64::MAX / 4));
1281        assert_eq!(err, Err(ModuleError::AggregateTooLarge));
1282    }
1283
1284    #[test]
1285    fn test_global_checks() {
1286        let mut m = Module::new("m");
1287        assert_eq!(
1288            m.declare_global(
1289                "x",
1290                Global {
1291                    init: Init::Bytes(alloc::vec![1]),
1292                    ..Global::zeroed(2, 1)
1293                }
1294            ),
1295            Err(ModuleError::InitSizeMismatch { size: 2, found: 1 })
1296        );
1297        let reloc = Reloc {
1298            offset: 4,
1299            target: SymbolRef::Global(GlobalId::from_u32(0)),
1300            addend: 0,
1301        };
1302        assert_eq!(
1303            m.declare_global("y", Global::zeroed(8, 8).with_reloc(reloc)),
1304            Err(ModuleError::RelocOutOfRange { offset: 4 })
1305        );
1306        assert_eq!(
1307            m.declare_global("", Global::zeroed(8, 8)),
1308            Err(ModuleError::EmptyName)
1309        );
1310    }
1311}