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(¶ms));
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}