Skip to main content

ir_lang/
function.rs

1//! The body of a function: blocks, instructions, values, and stack slots.
2
3use alloc::vec::Vec;
4
5use crate::entity::{Block, Inst, NONE, StackSlot, Value, ValueRange};
6use crate::inst::{InstData, Terminator};
7use crate::types::Type;
8
9/// Where a value comes from.
10///
11/// # Examples
12///
13/// ```
14/// use ir_lang::{Linkage, Module, Signature, Type, ValueDef};
15///
16/// let mut m = Module::new("demo");
17/// let f = m.declare_function("f", &Signature::new(&[Type::I32], &[]), Linkage::Export)?;
18/// let b = m.build(f)?;
19/// let x = b.param(0)?;
20/// assert_eq!(b.func().value_def(x), Some(ValueDef::Param { block: b.func().entry(), index: 0 }));
21/// # Ok::<(), Box<dyn std::error::Error>>(())
22/// ```
23#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
24#[non_exhaustive]
25pub enum ValueDef {
26    /// The `index`-th parameter of `block`.
27    Param {
28        /// The block.
29        block: Block,
30        /// The parameter position.
31        index: u32,
32    },
33    /// The `index`-th result of `inst`.
34    Result {
35        /// The instruction.
36        inst: Inst,
37        /// The result position.
38        index: u32,
39    },
40    /// No longer defined: its instruction or block was removed, or its block
41    /// parameter was removed. Using a detached value is a validation error.
42    Detached,
43}
44
45/// The size and alignment of a stack slot, in bytes.
46///
47/// # Examples
48///
49/// ```
50/// use ir_lang::SlotData;
51///
52/// let s = SlotData { size: 16, align: 8 };
53/// assert_eq!(s.size, 16);
54/// ```
55#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
56pub struct SlotData {
57    /// Size in bytes.
58    pub size: u32,
59    /// Alignment in bytes (a power of two, at most 2^16).
60    pub align: u32,
61}
62
63impl SlotData {
64    /// The largest alignment a stack slot may request.
65    pub const MAX_ALIGN: u32 = 1 << 16;
66}
67
68#[derive(Clone, Debug)]
69pub(crate) struct BlockNode {
70    pub(crate) params: Vec<Value>,
71    pub(crate) first: u32,
72    pub(crate) last: u32,
73    pub(crate) term: Option<Terminator>,
74    pub(crate) live: bool,
75}
76
77impl BlockNode {
78    pub(crate) fn new(params: Vec<Value>) -> BlockNode {
79        BlockNode {
80            params,
81            first: NONE,
82            last: NONE,
83            term: None,
84            live: true,
85        }
86    }
87}
88
89#[derive(Clone, Debug)]
90pub(crate) struct InstNode {
91    pub(crate) data: InstData,
92    pub(crate) results: ValueRange,
93    pub(crate) prev: u32,
94    pub(crate) next: u32,
95    /// The containing block, or `NONE` once removed.
96    pub(crate) block: u32,
97}
98
99#[derive(Clone, Debug)]
100pub(crate) struct ValueNode {
101    pub(crate) ty: Type,
102    pub(crate) def: ValueDef,
103    /// The value this one forwards to after `replace_all_uses`, or `NONE`.
104    pub(crate) alias: u32,
105}
106
107/// The largest number of entities of one kind (values, blocks, instructions, slots)
108/// a function may hold.
109pub const MAX_ENTITIES: u32 = u32::MAX - 1;
110
111/// A function body in SSA form: a control-flow graph of basic blocks.
112///
113/// Each block has parameters (the SSA values that flow in along its incoming edges,
114/// in place of phi nodes), a sequence of instructions, and one [`Terminator`]. Every
115/// value is defined once, by a block parameter or an instruction result, and has
116/// one [`Type`]. The entry block's parameters are the function's parameters.
117///
118/// A `Function` lives in a [`Module`](crate::Module), which holds its declaration
119/// (name, [`Signature`](crate::Signature), linkage, attributes). It is created and
120/// changed through a [`Builder`](crate::Builder) (`Module::build`, `Module::edit`)
121/// and read through the accessors here.
122///
123/// Instructions of a block form a linked list over a dense arena, so inserting or
124/// removing an instruction is O(1) and handles never move. Removed instructions and
125/// blocks leave tombstones; [`Builder::compact`](crate::Builder::compact) renumbers densely and
126/// reports the mapping.
127///
128/// # Examples
129///
130/// ```
131/// use ir_lang::{Linkage, Module, Overflow, Signature, Type};
132///
133/// let mut m = Module::new("demo");
134/// let f = m.declare_function("double", &Signature::new(&[Type::I64], &[Type::I64]), Linkage::Export)?;
135/// let mut b = m.build(f)?;
136/// let x = b.param(0)?;
137/// let y = b.add(x, x, Overflow::Wrap)?;
138/// b.ret(&[y])?;
139///
140/// let func = m.function(f).unwrap();
141/// let entry = func.entry();
142/// assert_eq!(func.block_params(entry), &[x]);
143/// assert_eq!(func.insts(entry).count(), 1);
144/// assert_eq!(func.value_type(y), Some(Type::I64));
145/// m.validate()?;
146/// # Ok::<(), Box<dyn std::error::Error>>(())
147/// ```
148#[derive(Clone, Debug)]
149pub struct Function {
150    pub(crate) blocks: Vec<BlockNode>,
151    pub(crate) insts: Vec<InstNode>,
152    pub(crate) values: Vec<ValueNode>,
153    pub(crate) slots: Vec<SlotData>,
154    pub(crate) entry: Block,
155}
156
157/// An iterator over the instructions of a block, in order.
158#[derive(Clone, Debug)]
159pub struct Insts<'f> {
160    func: &'f Function,
161    next: u32,
162    budget: usize,
163}
164
165impl Iterator for Insts<'_> {
166    type Item = Inst;
167
168    fn next(&mut self) -> Option<Inst> {
169        // The budget bounds the walk even if the list were corrupt (it never is
170        // through the public API), so iteration always terminates.
171        if self.next == NONE || self.budget == 0 {
172            return None;
173        }
174        self.budget -= 1;
175        let inst = Inst::from_u32(self.next);
176        self.next = self
177            .func
178            .insts
179            .get(self.next as usize)
180            .map_or(NONE, |n| n.next);
181        Some(inst)
182    }
183}
184
185impl Function {
186    /// A function whose entry block has parameters of the given types.
187    pub(crate) fn new(params: &[Type]) -> Function {
188        let mut f = Function {
189            blocks: Vec::new(),
190            insts: Vec::new(),
191            values: Vec::new(),
192            slots: Vec::new(),
193            entry: Block::from_u32(0),
194        };
195        let mut values = Vec::with_capacity(params.len());
196        for (i, &ty) in params.iter().enumerate() {
197            let v = Value::from_u32(f.values.len() as u32);
198            f.values.push(ValueNode {
199                ty,
200                def: ValueDef::Param {
201                    block: Block::from_u32(0),
202                    index: i as u32,
203                },
204                alias: NONE,
205            });
206            values.push(v);
207        }
208        f.blocks.push(BlockNode::new(values));
209        f
210    }
211
212    /// An empty function with no blocks (the parser fills it in).
213    pub(crate) fn empty() -> Function {
214        Function {
215            blocks: Vec::new(),
216            insts: Vec::new(),
217            values: Vec::new(),
218            slots: Vec::new(),
219            entry: Block::from_u32(0),
220        }
221    }
222
223    /// The entry block, where execution begins. Its parameters are the function's
224    /// parameters, and no edge may target it.
225    ///
226    /// # Examples
227    ///
228    /// ```
229    /// use ir_lang::{Linkage, Module, Signature};
230    ///
231    /// let mut m = Module::new("m");
232    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
233    /// let b = m.build(f)?;
234    /// assert_eq!(b.func().entry().index(), 0);
235    /// # Ok::<(), Box<dyn std::error::Error>>(())
236    /// ```
237    #[inline]
238    #[must_use]
239    pub const fn entry(&self) -> Block {
240        self.entry
241    }
242
243    /// The number of block handles ever created (live and removed): block handles
244    /// run over `0..block_count()`.
245    ///
246    /// # Examples
247    ///
248    /// ```
249    /// use ir_lang::{Linkage, Module, Signature};
250    ///
251    /// let mut m = Module::new("m");
252    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
253    /// let mut b = m.build(f)?;
254    /// let _ = b.create_block(&[])?;
255    /// assert_eq!(b.func().block_count(), 2);
256    /// # Ok::<(), Box<dyn std::error::Error>>(())
257    /// ```
258    #[inline]
259    #[must_use]
260    pub fn block_count(&self) -> usize {
261        self.blocks.len()
262    }
263
264    /// Iterates over the live blocks in handle order (the entry is block 0 for a
265    /// function from the builder).
266    ///
267    /// # Examples
268    ///
269    /// ```
270    /// use ir_lang::{Linkage, Module, Signature};
271    ///
272    /// let mut m = Module::new("m");
273    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
274    /// let mut b = m.build(f)?;
275    /// let extra = b.create_block(&[])?;
276    /// b.remove_block(extra)?;
277    /// assert_eq!(b.func().blocks().count(), 1);
278    /// # Ok::<(), Box<dyn std::error::Error>>(())
279    /// ```
280    pub fn blocks(&self) -> impl Iterator<Item = Block> + '_ {
281        self.blocks
282            .iter()
283            .enumerate()
284            .filter(|(_, b)| b.live)
285            .map(|(i, _)| Block::from_u32(i as u32))
286    }
287
288    /// Whether `block` exists and has not been removed.
289    ///
290    /// # Examples
291    ///
292    /// ```
293    /// use ir_lang::{Block, Linkage, Module, Signature};
294    ///
295    /// let mut m = Module::new("m");
296    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
297    /// let b = m.build(f)?;
298    /// assert!(b.func().is_live_block(Block::from_u32(0)));
299    /// assert!(!b.func().is_live_block(Block::from_u32(9)));
300    /// # Ok::<(), Box<dyn std::error::Error>>(())
301    /// ```
302    #[must_use]
303    pub fn is_live_block(&self, block: Block) -> bool {
304        self.blocks.get(block.index()).is_some_and(|b| b.live)
305    }
306
307    /// The parameters of `block`, or an empty slice for an unknown block.
308    ///
309    /// # Examples
310    ///
311    /// ```
312    /// use ir_lang::{Linkage, Module, Signature, Type};
313    ///
314    /// let mut m = Module::new("m");
315    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
316    /// let mut b = m.build(f)?;
317    /// let blk = b.create_block(&[Type::Bool, Type::F64])?;
318    /// assert_eq!(b.func().block_params(blk).len(), 2);
319    /// # Ok::<(), Box<dyn std::error::Error>>(())
320    /// ```
321    #[must_use]
322    pub fn block_params(&self, block: Block) -> &[Value] {
323        self.blocks
324            .get(block.index())
325            .map_or(&[], |b| b.params.as_slice())
326    }
327
328    /// Iterates over the instructions of `block` in order (empty for an unknown
329    /// block). The terminator is not an instruction; see
330    /// [`terminator`](Function::terminator).
331    ///
332    /// # Examples
333    ///
334    /// ```
335    /// use ir_lang::{Linkage, Module, Signature, Type};
336    ///
337    /// let mut m = Module::new("m");
338    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
339    /// let mut b = m.build(f)?;
340    /// let _ = b.iconst(Type::I32, 1)?;
341    /// let _ = b.iconst(Type::I32, 2)?;
342    /// let entry = b.func().entry();
343    /// assert_eq!(b.func().insts(entry).count(), 2);
344    /// # Ok::<(), Box<dyn std::error::Error>>(())
345    /// ```
346    #[must_use]
347    pub fn insts(&self, block: Block) -> Insts<'_> {
348        let first = self.blocks.get(block.index()).map_or(NONE, |b| b.first);
349        Insts {
350            func: self,
351            next: first,
352            budget: self.insts.len(),
353        }
354    }
355
356    /// The first instruction of `block`, if any.
357    ///
358    /// # Examples
359    ///
360    /// ```
361    /// use ir_lang::{Linkage, Module, Signature};
362    ///
363    /// let mut m = Module::new("m");
364    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
365    /// let b = m.build(f)?;
366    /// assert_eq!(b.func().first_inst(b.func().entry()), None);
367    /// # Ok::<(), Box<dyn std::error::Error>>(())
368    /// ```
369    #[must_use]
370    pub fn first_inst(&self, block: Block) -> Option<Inst> {
371        self.blocks
372            .get(block.index())
373            .and_then(|b| (b.first != NONE).then(|| Inst::from_u32(b.first)))
374    }
375
376    /// The last instruction of `block` (before its terminator), if any.
377    ///
378    /// # Examples
379    ///
380    /// ```
381    /// use ir_lang::{Linkage, Module, Signature, Type};
382    ///
383    /// let mut m = Module::new("m");
384    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
385    /// let mut b = m.build(f)?;
386    /// let _ = b.iconst(Type::U8, 1)?;
387    /// let entry = b.func().entry();
388    /// assert!(b.func().last_inst(entry).is_some());
389    /// # Ok::<(), Box<dyn std::error::Error>>(())
390    /// ```
391    #[must_use]
392    pub fn last_inst(&self, block: Block) -> Option<Inst> {
393        self.blocks
394            .get(block.index())
395            .and_then(|b| (b.last != NONE).then(|| Inst::from_u32(b.last)))
396    }
397
398    /// The instruction after `inst` in its block, if any.
399    ///
400    /// # Examples
401    ///
402    /// ```
403    /// use ir_lang::{Linkage, Module, Signature, Type};
404    ///
405    /// let mut m = Module::new("m");
406    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
407    /// let mut b = m.build(f)?;
408    /// let a = b.iconst(Type::U8, 1)?;
409    /// let c = b.iconst(Type::U8, 2)?;
410    /// let (ia, ic) = (b.func().defining_inst(a).unwrap(), b.func().defining_inst(c).unwrap());
411    /// assert_eq!(b.func().next_inst(ia), Some(ic));
412    /// assert_eq!(b.func().prev_inst(ic), Some(ia));
413    /// # Ok::<(), Box<dyn std::error::Error>>(())
414    /// ```
415    #[must_use]
416    pub fn next_inst(&self, inst: Inst) -> Option<Inst> {
417        self.insts
418            .get(inst.index())
419            .filter(|n| n.block != NONE && n.next != NONE)
420            .map(|n| Inst::from_u32(n.next))
421    }
422
423    /// The instruction before `inst` in its block, if any.
424    ///
425    /// See [`next_inst`](Function::next_inst) for an example.
426    #[must_use]
427    pub fn prev_inst(&self, inst: Inst) -> Option<Inst> {
428        self.insts
429            .get(inst.index())
430            .filter(|n| n.block != NONE && n.prev != NONE)
431            .map(|n| Inst::from_u32(n.prev))
432    }
433
434    /// The number of instruction handles ever created (live and removed).
435    ///
436    /// # Examples
437    ///
438    /// ```
439    /// use ir_lang::{Linkage, Module, Signature, Type};
440    ///
441    /// let mut m = Module::new("m");
442    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
443    /// let mut b = m.build(f)?;
444    /// let _ = b.iconst(Type::U8, 1)?;
445    /// assert_eq!(b.func().inst_count(), 1);
446    /// # Ok::<(), Box<dyn std::error::Error>>(())
447    /// ```
448    #[inline]
449    #[must_use]
450    pub fn inst_count(&self) -> usize {
451        self.insts.len()
452    }
453
454    /// The data of `inst` (also for a removed instruction), or `None` for an
455    /// unknown handle.
456    ///
457    /// # Examples
458    ///
459    /// ```
460    /// use ir_lang::{InstData, Linkage, Module, Signature, Type};
461    ///
462    /// let mut m = Module::new("m");
463    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
464    /// let mut b = m.build(f)?;
465    /// let v = b.iconst(Type::I8, -1)?;
466    /// let inst = b.func().defining_inst(v).unwrap();
467    /// assert_eq!(b.func().inst(inst), Some(&InstData::Const { ty: Type::I8, bits: 0xff }));
468    /// # Ok::<(), Box<dyn std::error::Error>>(())
469    /// ```
470    #[must_use]
471    pub fn inst(&self, inst: Inst) -> Option<&InstData> {
472        self.insts.get(inst.index()).map(|n| &n.data)
473    }
474
475    /// The block containing `inst`, or `None` if it was removed or is unknown.
476    ///
477    /// # Examples
478    ///
479    /// ```
480    /// use ir_lang::{Linkage, Module, Signature, Type};
481    ///
482    /// let mut m = Module::new("m");
483    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
484    /// let mut b = m.build(f)?;
485    /// let v = b.iconst(Type::I8, 0)?;
486    /// let inst = b.func().defining_inst(v).unwrap();
487    /// assert_eq!(b.func().inst_block(inst), Some(b.func().entry()));
488    /// # Ok::<(), Box<dyn std::error::Error>>(())
489    /// ```
490    #[must_use]
491    pub fn inst_block(&self, inst: Inst) -> Option<Block> {
492        self.insts
493            .get(inst.index())
494            .filter(|n| n.block != NONE)
495            .map(|n| Block::from_u32(n.block))
496    }
497
498    /// The values `inst` defines (empty for an unknown handle).
499    ///
500    /// # Examples
501    ///
502    /// ```
503    /// use ir_lang::{Linkage, Module, Signature, Type};
504    ///
505    /// let mut m = Module::new("m");
506    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
507    /// let mut b = m.build(f)?;
508    /// let v = b.iconst(Type::I8, 0)?;
509    /// let inst = b.func().defining_inst(v).unwrap();
510    /// assert_eq!(b.func().results(inst).first(), Some(v));
511    /// # Ok::<(), Box<dyn std::error::Error>>(())
512    /// ```
513    #[must_use]
514    pub fn results(&self, inst: Inst) -> ValueRange {
515        self.insts
516            .get(inst.index())
517            .map_or(ValueRange::default(), |n| n.results)
518    }
519
520    /// The terminator of `block`, or `None` if it has none yet (or is unknown).
521    ///
522    /// # Examples
523    ///
524    /// ```
525    /// use ir_lang::{Linkage, Module, Signature, Terminator};
526    ///
527    /// let mut m = Module::new("m");
528    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
529    /// let mut b = m.build(f)?;
530    /// b.unreachable()?;
531    /// let entry = b.func().entry();
532    /// assert_eq!(b.func().terminator(entry), Some(&Terminator::Unreachable));
533    /// # Ok::<(), Box<dyn std::error::Error>>(())
534    /// ```
535    #[must_use]
536    pub fn terminator(&self, block: Block) -> Option<&Terminator> {
537        self.blocks.get(block.index()).and_then(|b| b.term.as_ref())
538    }
539
540    /// The number of value handles ever created: value handles run over
541    /// `0..value_count()`.
542    ///
543    /// # Examples
544    ///
545    /// ```
546    /// use ir_lang::{Linkage, Module, Signature, Type};
547    ///
548    /// let mut m = Module::new("m");
549    /// let f = m.declare_function("f", &Signature::new(&[Type::I32], &[]), Linkage::Local)?;
550    /// let b = m.build(f)?;
551    /// assert_eq!(b.func().value_count(), 1);
552    /// # Ok::<(), Box<dyn std::error::Error>>(())
553    /// ```
554    #[inline]
555    #[must_use]
556    pub fn value_count(&self) -> usize {
557        self.values.len()
558    }
559
560    /// The type of `value`, or `None` for an unknown handle.
561    ///
562    /// # Examples
563    ///
564    /// ```
565    /// use ir_lang::{Linkage, Module, Signature, Type};
566    ///
567    /// let mut m = Module::new("m");
568    /// let f = m.declare_function("f", &Signature::new(&[Type::F32], &[]), Linkage::Local)?;
569    /// let b = m.build(f)?;
570    /// assert_eq!(b.func().value_type(b.param(0)?), Some(Type::F32));
571    /// # Ok::<(), Box<dyn std::error::Error>>(())
572    /// ```
573    #[must_use]
574    pub fn value_type(&self, value: Value) -> Option<Type> {
575        self.values.get(value.index()).map(|v| v.ty)
576    }
577
578    /// Where `value` is defined, or `None` for an unknown handle.
579    ///
580    /// See [`ValueDef`] for an example.
581    #[must_use]
582    pub fn value_def(&self, value: Value) -> Option<ValueDef> {
583        self.values.get(value.index()).map(|v| v.def)
584    }
585
586    /// The instruction defining `value`, if it is an instruction result.
587    ///
588    /// # Examples
589    ///
590    /// ```
591    /// use ir_lang::{Linkage, Module, Signature, Type};
592    ///
593    /// let mut m = Module::new("m");
594    /// let f = m.declare_function("f", &Signature::new(&[Type::F32], &[]), Linkage::Local)?;
595    /// let mut b = m.build(f)?;
596    /// let p = b.param(0)?;
597    /// let c = b.iconst(Type::U8, 3)?;
598    /// assert!(b.func().defining_inst(c).is_some());
599    /// assert!(b.func().defining_inst(p).is_none());
600    /// # Ok::<(), Box<dyn std::error::Error>>(())
601    /// ```
602    #[must_use]
603    pub fn defining_inst(&self, value: Value) -> Option<Inst> {
604        match self.value_def(value) {
605            Some(ValueDef::Result { inst, .. }) => Some(inst),
606            _ => None,
607        }
608    }
609
610    /// Follows `replace_all_uses` forwarding: the value every use of `value` now
611    /// reads. A value that was never replaced resolves to itself.
612    ///
613    /// Operands stored in instructions are not rewritten eagerly by
614    /// [`Builder::replace_all_uses`](crate::Builder::replace_all_uses) (that keeps it
615    /// O(1)), so a pass reading operands should resolve them, or call
616    /// [`Builder::resolve_aliases`](crate::Builder::resolve_aliases) once first.
617    ///
618    /// # Examples
619    ///
620    /// ```
621    /// use ir_lang::{Linkage, Module, Signature, Type};
622    ///
623    /// let mut m = Module::new("m");
624    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
625    /// let mut b = m.build(f)?;
626    /// let one = b.iconst(Type::I32, 1)?;
627    /// let two = b.iconst(Type::I32, 2)?;
628    /// b.replace_all_uses(one, two)?;
629    /// assert_eq!(b.func().resolve(one), two);
630    /// assert_eq!(b.func().resolve(two), two);
631    /// # Ok::<(), Box<dyn std::error::Error>>(())
632    /// ```
633    #[must_use]
634    pub fn resolve(&self, value: Value) -> Value {
635        let mut v = value.as_u32();
636        // Alias chains are acyclic by construction (replace_all_uses refuses a
637        // cycle); the step bound keeps resolution total on any input regardless.
638        for _ in 0..=self.values.len() {
639            match self.values.get(v as usize) {
640                Some(node) if node.alias != NONE => v = node.alias,
641                _ => return Value::from_u32(v),
642            }
643        }
644        Value::from_u32(v)
645    }
646
647    /// The number of stack slots.
648    ///
649    /// # Examples
650    ///
651    /// ```
652    /// use ir_lang::{Linkage, Module, Signature};
653    ///
654    /// let mut m = Module::new("m");
655    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
656    /// let mut b = m.build(f)?;
657    /// let _ = b.stack_slot(8, 8)?;
658    /// assert_eq!(b.func().slot_count(), 1);
659    /// # Ok::<(), Box<dyn std::error::Error>>(())
660    /// ```
661    #[inline]
662    #[must_use]
663    pub fn slot_count(&self) -> usize {
664        self.slots.len()
665    }
666
667    /// The size and alignment of a stack slot.
668    ///
669    /// # Examples
670    ///
671    /// ```
672    /// use ir_lang::{Linkage, Module, Signature, SlotData};
673    ///
674    /// let mut m = Module::new("m");
675    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
676    /// let mut b = m.build(f)?;
677    /// let ss = b.stack_slot(24, 8)?;
678    /// assert_eq!(b.func().slot(ss), Some(SlotData { size: 24, align: 8 }));
679    /// # Ok::<(), Box<dyn std::error::Error>>(())
680    /// ```
681    #[must_use]
682    pub fn slot(&self, slot: StackSlot) -> Option<SlotData> {
683        self.slots.get(slot.index()).copied()
684    }
685
686    /// The predecessor blocks of every block, indexed by block handle, listing a
687    /// predecessor once per edge (a branch with both edges to one block lists it
688    /// twice). Only live blocks contribute edges.
689    ///
690    /// # Examples
691    ///
692    /// ```
693    /// use ir_lang::{Linkage, Module, Signature};
694    ///
695    /// let mut m = Module::new("m");
696    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Local)?;
697    /// let mut b = m.build(f)?;
698    /// let exit = b.create_block(&[])?;
699    /// b.jump(exit, &[])?;
700    /// b.switch_to(exit)?;
701    /// b.ret(&[])?;
702    /// let preds = b.func().predecessors();
703    /// assert_eq!(preds[exit.index()], [b.func().entry()]);
704    /// # Ok::<(), Box<dyn std::error::Error>>(())
705    /// ```
706    #[must_use]
707    pub fn predecessors(&self) -> Vec<Vec<Block>> {
708        let mut preds = alloc::vec![Vec::new(); self.blocks.len()];
709        for (i, node) in self.blocks.iter().enumerate() {
710            if !node.live {
711                continue;
712            }
713            if let Some(term) = &node.term {
714                for dest in term.successors() {
715                    if let Some(p) = preds.get_mut(dest.block.index()) {
716                        p.push(Block::from_u32(i as u32));
717                    }
718                }
719            }
720        }
721        preds
722    }
723
724    // ----- internal construction helpers (used by the builder and the parser) -----
725
726    pub(crate) fn push_value(&mut self, ty: Type, def: ValueDef) -> Option<Value> {
727        let index = u32::try_from(self.values.len())
728            .ok()
729            .filter(|&i| i < MAX_ENTITIES)?;
730        self.values.push(ValueNode {
731            ty,
732            def,
733            alias: NONE,
734        });
735        Some(Value::from_u32(index))
736    }
737
738    pub(crate) fn push_block(&mut self) -> Option<Block> {
739        let index = u32::try_from(self.blocks.len())
740            .ok()
741            .filter(|&i| i < MAX_ENTITIES)?;
742        self.blocks.push(BlockNode::new(Vec::new()));
743        Some(Block::from_u32(index))
744    }
745
746    /// Allocates an unlinked instruction node.
747    pub(crate) fn push_inst(&mut self, data: InstData) -> Option<Inst> {
748        let index = u32::try_from(self.insts.len())
749            .ok()
750            .filter(|&i| i < MAX_ENTITIES)?;
751        self.insts.push(InstNode {
752            data,
753            results: ValueRange::default(),
754            prev: NONE,
755            next: NONE,
756            block: NONE,
757        });
758        Some(Inst::from_u32(index))
759    }
760
761    /// Links an unlinked instruction at the end of `block`.
762    pub(crate) fn link_at_end(&mut self, inst: Inst, block: Block) {
763        let last = match self.blocks.get(block.index()) {
764            Some(b) => b.last,
765            None => return,
766        };
767        self.link_between(inst, block, last, NONE);
768    }
769
770    /// Links an unlinked instruction immediately before `before`.
771    pub(crate) fn link_before(&mut self, inst: Inst, before: Inst) {
772        let Some(node) = self.insts.get(before.index()) else {
773            return;
774        };
775        let (block, prev) = (node.block, node.prev);
776        if block == NONE {
777            return;
778        }
779        self.link_between(inst, Block::from_u32(block), prev, before.as_u32());
780    }
781
782    /// Links an unlinked instruction immediately after `after`.
783    pub(crate) fn link_after(&mut self, inst: Inst, after: Inst) {
784        let Some(node) = self.insts.get(after.index()) else {
785            return;
786        };
787        let (block, next) = (node.block, node.next);
788        if block == NONE {
789            return;
790        }
791        self.link_between(inst, Block::from_u32(block), after.as_u32(), next);
792    }
793
794    fn link_between(&mut self, inst: Inst, block: Block, prev: u32, next: u32) {
795        let i = inst.as_u32();
796        if let Some(n) = self.insts.get_mut(inst.index()) {
797            n.prev = prev;
798            n.next = next;
799            n.block = block.as_u32();
800        }
801        if prev == NONE {
802            if let Some(b) = self.blocks.get_mut(block.index()) {
803                b.first = i;
804            }
805        } else if let Some(p) = self.insts.get_mut(prev as usize) {
806            p.next = i;
807        }
808        if next == NONE {
809            if let Some(b) = self.blocks.get_mut(block.index()) {
810                b.last = i;
811            }
812        } else if let Some(n) = self.insts.get_mut(next as usize) {
813            n.prev = i;
814        }
815    }
816
817    /// Unlinks a linked instruction from its block (its node stays in the arena).
818    pub(crate) fn unlink(&mut self, inst: Inst) {
819        let Some(node) = self.insts.get(inst.index()) else {
820            return;
821        };
822        let (block, prev, next) = (node.block, node.prev, node.next);
823        if block == NONE {
824            return;
825        }
826        if prev == NONE {
827            if let Some(b) = self.blocks.get_mut(block as usize) {
828                b.first = next;
829            }
830        } else if let Some(p) = self.insts.get_mut(prev as usize) {
831            p.next = next;
832        }
833        if next == NONE {
834            if let Some(b) = self.blocks.get_mut(block as usize) {
835                b.last = prev;
836            }
837        } else if let Some(n) = self.insts.get_mut(next as usize) {
838            n.prev = prev;
839        }
840        if let Some(n) = self.insts.get_mut(inst.index()) {
841            n.prev = NONE;
842            n.next = NONE;
843            n.block = NONE;
844        }
845    }
846}
847
848#[cfg(test)]
849mod tests {
850    use super::*;
851
852    #[test]
853    fn test_link_and_unlink_keep_list_consistent() {
854        let mut f = Function::new(&[]);
855        let entry = f.entry();
856        let mut made = Vec::new();
857        for _ in 0..3 {
858            let i = f
859                .push_inst(InstData::Fence {
860                    order: crate::inst::MemOrder::SeqCst,
861                })
862                .unwrap_or(Inst::from_u32(NONE));
863            f.link_at_end(i, entry);
864            made.push(i);
865        }
866        assert_eq!(f.insts(entry).collect::<Vec<_>>(), made);
867        f.unlink(made[1]);
868        assert_eq!(f.insts(entry).collect::<Vec<_>>(), [made[0], made[2]]);
869        f.link_before(made[1], made[0]);
870        assert_eq!(
871            f.insts(entry).collect::<Vec<_>>(),
872            [made[1], made[0], made[2]]
873        );
874        f.unlink(made[2]);
875        f.link_after(made[2], made[1]);
876        assert_eq!(
877            f.insts(entry).collect::<Vec<_>>(),
878            [made[1], made[2], made[0]]
879        );
880        assert_eq!(f.first_inst(entry), Some(made[1]));
881        assert_eq!(f.last_inst(entry), Some(made[0]));
882    }
883
884    #[test]
885    fn test_resolve_terminates_on_a_corrupt_cycle() {
886        let mut f = Function::new(&[Type::I32, Type::I32]);
887        f.values[0].alias = 1;
888        f.values[1].alias = 0;
889        // A cycle cannot be built through the API; resolution still terminates.
890        let _ = f.resolve(Value::from_u32(0));
891    }
892
893    #[test]
894    fn test_unknown_handles_read_as_empty() {
895        let f = Function::new(&[]);
896        assert!(f.block_params(Block::from_u32(5)).is_empty());
897        assert_eq!(f.insts(Block::from_u32(5)).count(), 0);
898        assert_eq!(f.value_type(Value::from_u32(3)), None);
899        assert_eq!(f.inst(Inst::from_u32(0)), None);
900        assert!(f.results(Inst::from_u32(0)).is_empty());
901    }
902}