Skip to main content

backend_lang/mir/
function.rs

1//! A machine function: blocks of target instructions over virtual and
2//! physical registers, with block parameters, stack slots, and symbols.
3
4use alloc::string::String;
5use alloc::vec::Vec;
6
7use super::entity::{Block, Inst, StackSlot, Symbol};
8use super::operand::{BlockCall, Implicit, ImplicitKind, Operand};
9use super::verify::MirError;
10use crate::regs::{PReg, Reg, RegClass, RegSet, VReg};
11use crate::target::abi::Abi;
12use crate::target::frame::{FrameError, FrameInput, FrameLayout};
13use crate::target::{InstKind, Opcode, OperandRule, Target};
14
15/// What a stack slot is.
16///
17/// # Examples
18///
19/// ```
20/// use backend_lang::mir::{Function, SlotKind};
21/// use backend_lang::x86_64::SYSV;
22///
23/// let mut f = Function::new("f", &SYSV);
24/// let local = f.stack_slot(SlotKind::Local { size: 24, align: 8 })?;
25/// let arg = f.stack_slot(SlotKind::Incoming { offset: 0, size: 8 })?;
26/// assert_eq!(f.slot(local), Some(SlotKind::Local { size: 24, align: 8 }));
27/// assert!(matches!(f.slot(arg), Some(SlotKind::Incoming { .. })));
28/// # Ok::<(), backend_lang::mir::MirError>(())
29/// ```
30#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
31#[non_exhaustive]
32pub enum SlotKind {
33    /// Space in this function's frame.
34    Local {
35        /// Bytes.
36        size: u32,
37        /// Alignment in bytes: a power of two up to the stack alignment.
38        align: u32,
39    },
40    /// An argument the caller passed on the stack, at `offset` bytes above
41    /// the canonical frame address (see
42    /// [`ArgLoc::Stack`](crate::target::abi::ArgLoc::Stack)).
43    Incoming {
44        /// Offset from the canonical frame address.
45        offset: u32,
46        /// Bytes.
47        size: u32,
48    },
49}
50
51impl SlotKind {
52    /// The slot's size in bytes.
53    ///
54    /// # Examples
55    ///
56    /// ```
57    /// use backend_lang::mir::SlotKind;
58    ///
59    /// assert_eq!(SlotKind::Incoming { offset: 8, size: 8 }.size(), 8);
60    /// ```
61    #[inline]
62    #[must_use]
63    pub const fn size(self) -> u32 {
64        match self {
65            SlotKind::Local { size, .. } | SlotKind::Incoming { size, .. } => size,
66        }
67    }
68}
69
70/// Extra implicit operands for one instruction: registers it reads and
71/// writes without naming them, and registers it clobbers, beyond what its
72/// opcode always has. Used for calls (argument registers, return registers,
73/// the convention's clobbers), returns (result registers), and system calls.
74///
75/// # Examples
76///
77/// ```
78/// use backend_lang::mir::Effects;
79/// use backend_lang::x86_64::{SYSV, RAX, RDI};
80///
81/// let e = Effects::new().uses(&[RDI]).defs(&[RAX]).clobbers(SYSV.call_clobbers());
82/// assert_eq!(e.uses_regs(), [RDI]);
83/// assert!(e.clobber_set().contains(RAX));
84/// ```
85#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
86pub struct Effects<'a> {
87    uses: &'a [PReg],
88    defs: &'a [PReg],
89    clobbers: RegSet,
90}
91
92impl<'a> Effects<'a> {
93    /// No extra operands.
94    ///
95    /// # Examples
96    ///
97    /// ```
98    /// use backend_lang::mir::Effects;
99    ///
100    /// assert!(Effects::new().uses_regs().is_empty());
101    /// ```
102    #[must_use]
103    pub const fn new() -> Effects<'a> {
104        Effects {
105            uses: &[],
106            defs: &[],
107            clobbers: RegSet::EMPTY,
108        }
109    }
110
111    /// Registers read.
112    ///
113    /// # Examples
114    ///
115    /// ```
116    /// use backend_lang::mir::Effects;
117    /// use backend_lang::x86_64::RSI;
118    ///
119    /// assert_eq!(Effects::new().uses(&[RSI]).uses_regs(), [RSI]);
120    /// ```
121    #[must_use]
122    pub const fn uses(self, regs: &'a [PReg]) -> Effects<'a> {
123        Effects { uses: regs, ..self }
124    }
125
126    /// Registers written with defined values.
127    ///
128    /// # Examples
129    ///
130    /// ```
131    /// use backend_lang::mir::Effects;
132    /// use backend_lang::x86_64::RAX;
133    ///
134    /// assert_eq!(Effects::new().defs(&[RAX]).defs_regs(), [RAX]);
135    /// ```
136    #[must_use]
137    pub const fn defs(self, regs: &'a [PReg]) -> Effects<'a> {
138        Effects { defs: regs, ..self }
139    }
140
141    /// Registers left with unspecified contents.
142    ///
143    /// # Examples
144    ///
145    /// ```
146    /// use backend_lang::RegSet;
147    /// use backend_lang::mir::Effects;
148    /// use backend_lang::x86_64::R11;
149    ///
150    /// assert!(Effects::new().clobbers(RegSet::of(&[R11])).clobber_set().contains(R11));
151    /// ```
152    #[must_use]
153    pub const fn clobbers(self, regs: RegSet) -> Effects<'a> {
154        Effects {
155            clobbers: regs,
156            ..self
157        }
158    }
159
160    /// The registers read.
161    ///
162    /// # Examples
163    ///
164    /// ```
165    /// use backend_lang::mir::Effects;
166    ///
167    /// assert!(Effects::new().uses_regs().is_empty());
168    /// ```
169    #[must_use]
170    pub const fn uses_regs(&self) -> &'a [PReg] {
171        self.uses
172    }
173
174    /// The registers written.
175    ///
176    /// # Examples
177    ///
178    /// ```
179    /// use backend_lang::mir::Effects;
180    ///
181    /// assert!(Effects::new().defs_regs().is_empty());
182    /// ```
183    #[must_use]
184    pub const fn defs_regs(&self) -> &'a [PReg] {
185        self.defs
186    }
187
188    /// The registers clobbered.
189    ///
190    /// # Examples
191    ///
192    /// ```
193    /// use backend_lang::mir::Effects;
194    ///
195    /// assert!(Effects::new().clobber_set().is_empty());
196    /// ```
197    #[must_use]
198    pub const fn clobber_set(&self) -> RegSet {
199        self.clobbers
200    }
201}
202
203/// One instruction's record. Operands, implicit operands, and clobber sets
204/// live in the function's shared pools; the record holds ranges into them.
205#[derive(Clone, Copy, Debug)]
206pub(crate) struct InstData {
207    pub(crate) opcode: Opcode,
208    pub(crate) block: Block,
209    pub(crate) ops: u32,
210    pub(crate) nops: u32,
211    pub(crate) imp: u32,
212    pub(crate) nimp: u32,
213    /// Index into `clobbers`, or `NO_CLOBBERS`.
214    pub(crate) clobber: u32,
215}
216
217pub(crate) const NO_CLOBBERS: u32 = u32::MAX;
218
219/// One call-site record: the GC roots of a safepoint call (its stack map) and
220/// the block unwinding lands in, if any.
221#[derive(Clone, Copy, Debug)]
222pub(crate) struct SiteData {
223    pub(crate) inst: Inst,
224    pub(crate) gc: u32,
225    pub(crate) ngc: u32,
226    pub(crate) landing: Option<Block>,
227}
228
229/// What a call instruction records besides its operands: the stack slots that
230/// hold its GC roots while it runs (its **stack map**), and the **landing
231/// pad** control reaches if the callee unwinds.
232///
233/// # Examples
234///
235/// ```
236/// use backend_lang::mir::{Function, SlotKind};
237/// use backend_lang::x86_64::{op, SYSV};
238///
239/// let mut f = Function::new("f", &SYSV);
240/// let b = f.block()?;
241/// let root = f.stack_slot(SlotKind::Local { size: 8, align: 8 })?;
242/// let g = f.symbol("g")?;
243/// let call = f.push(b, op::CALL, &[g.into()])?;
244/// f.push(b, op::RET, &[])?;
245/// f.set_call_site(call, &[root], None)?;
246/// let site = f.call_site(call).unwrap();
247/// assert_eq!(site.gc_slots(), [root]);
248/// assert_eq!(site.landing_pad(), None);
249/// # Ok::<(), backend_lang::mir::MirError>(())
250/// ```
251#[derive(Clone, Copy, Debug, PartialEq, Eq)]
252pub struct CallSite<'a> {
253    inst: Inst,
254    gc_slots: &'a [StackSlot],
255    landing_pad: Option<Block>,
256}
257
258impl<'a> CallSite<'a> {
259    /// The call instruction.
260    ///
261    /// # Examples
262    ///
263    /// ```
264    /// use backend_lang::mir::Function;
265    /// use backend_lang::x86_64::{op, SYSV};
266    ///
267    /// let mut f = Function::new("f", &SYSV);
268    /// let b = f.block()?;
269    /// let g = f.symbol("g")?;
270    /// let call = f.push(b, op::CALL, &[g.into()])?;
271    /// f.set_call_site(call, &[], None)?;
272    /// assert_eq!(f.call_site(call).unwrap().inst(), call);
273    /// # Ok::<(), backend_lang::mir::MirError>(())
274    /// ```
275    #[inline]
276    #[must_use]
277    pub const fn inst(&self) -> Inst {
278        self.inst
279    }
280
281    /// The slots holding the GC references live across the call, which a
282    /// collector reads and may rewrite while the callee runs.
283    ///
284    /// # Examples
285    ///
286    /// ```
287    /// use backend_lang::mir::{Function, SlotKind};
288    /// use backend_lang::x86_64::{op, SYSV};
289    ///
290    /// let mut f = Function::new("f", &SYSV);
291    /// let b = f.block()?;
292    /// let s = f.stack_slot(SlotKind::Local { size: 8, align: 8 })?;
293    /// let g = f.symbol("g")?;
294    /// let call = f.push(b, op::CALL, &[g.into()])?;
295    /// f.set_call_site(call, &[s], None)?;
296    /// assert_eq!(f.call_site(call).unwrap().gc_slots().len(), 1);
297    /// # Ok::<(), backend_lang::mir::MirError>(())
298    /// ```
299    #[inline]
300    #[must_use]
301    pub const fn gc_slots(&self) -> &'a [StackSlot] {
302        self.gc_slots
303    }
304
305    /// The block control reaches when the callee unwinds, if any.
306    ///
307    /// # Examples
308    ///
309    /// ```
310    /// use backend_lang::mir::Function;
311    /// use backend_lang::x86_64::{op, SYSV};
312    ///
313    /// let mut f = Function::new("f", &SYSV);
314    /// let b = f.block()?;
315    /// let pad = f.block()?;
316    /// let g = f.symbol("g")?;
317    /// let call = f.push(b, op::CALL, &[g.into()])?;
318    /// f.set_call_site(call, &[], Some(pad))?;
319    /// assert_eq!(f.call_site(call).unwrap().landing_pad(), Some(pad));
320    /// # Ok::<(), backend_lang::mir::MirError>(())
321    /// ```
322    #[inline]
323    #[must_use]
324    pub const fn landing_pad(&self) -> Option<Block> {
325        self.landing_pad
326    }
327}
328
329#[derive(Clone, Debug, Default)]
330pub(crate) struct BlockData {
331    pub(crate) params: Vec<Operand>,
332    pub(crate) insts: Vec<Inst>,
333}
334
335/// The most entries any one table of a function may hold (instructions,
336/// operands, blocks, slots, symbols): ids are 32-bit.
337pub(crate) const MAX_ENTRIES: usize = u32::MAX as usize - 1;
338
339/// A machine function.
340///
341/// Blocks hold target instructions in order; the first block is the entry.
342/// Instructions name virtual registers (each typed by a register class) or
343/// physical registers, stack slots, and other functions by symbol. Control
344/// flow passes values between blocks through **block parameters**: a branch
345/// names its target with arguments, and on the edge every parameter receives
346/// its argument at once (a parallel copy). Block parameters are SSA's phi
347/// nodes written at the edge, which is the form an SSA register allocator
348/// works on and the form ir-lang already uses; see the crate docs for the
349/// rationale.
350///
351/// Every table is a dense vector indexed by its id type; nothing is
352/// recursive.
353///
354/// # Examples
355///
356/// Sum `1..=n` with virtual registers:
357///
358/// ```
359/// use backend_lang::mir::{Function, Operand};
360/// use backend_lang::x86_64::{self, op, GPR, SYSV};
361/// use isa_lang::x86_64::Cond;
362///
363/// let mut f = Function::new("sum", &SYSV);
364/// let entry = f.block()?;
365/// let head = f.block()?;
366/// let exit = f.block()?;
367/// let n = f.vreg(GPR)?;
368/// f.add_param(entry, n.into())?;
369/// // Parameters come first: branches are checked against them.
370/// let (acc, i) = (f.vreg(GPR)?, f.vreg(GPR)?);
371/// f.add_param(head, acc.into())?;
372/// f.add_param(head, i.into())?;
373/// let result = f.vreg(GPR)?;
374/// f.add_param(exit, result.into())?;
375///
376/// let zero = f.vreg(GPR)?;
377/// f.push(entry, op::MOV64RI, &[zero.into(), Operand::Imm(0)])?;
378/// let to_head = f.block_call(head, &[zero.into(), n.into()])?;
379/// f.push(entry, op::JMP, &[to_head.into()])?;
380///
381/// let (acc2, i2) = (f.vreg(GPR)?, f.vreg(GPR)?);
382/// f.push(head, op::ADD64, &[acc2.into(), acc.into(), i.into()])?;
383/// f.push(head, op::SUB64, &[i2.into(), i.into(), Operand::Imm(1)])?;
384/// let again = f.block_call(head, &[acc2.into(), i2.into()])?;
385/// let done = f.block_call(exit, &[acc2.into()])?;
386/// f.push(head, op::JCC, &[x86_64::cond(Cond::Ne).into(), again.into(), done.into()])?;
387///
388/// f.push(exit, op::RET, &[])?;
389///
390/// f.verify()?;
391/// assert!(f.to_string().contains("%5:gpr = add64 %1, %2"));
392/// # Ok::<(), backend_lang::mir::MirError>(())
393/// ```
394#[derive(Clone, Debug)]
395pub struct Function {
396    name: String,
397    abi: &'static Abi,
398    pub(crate) vregs: Vec<RegClass>,
399    pub(crate) blocks: Vec<BlockData>,
400    pub(crate) insts: Vec<InstData>,
401    pub(crate) operands: Vec<Operand>,
402    pub(crate) args: Vec<Operand>,
403    pub(crate) implicits: Vec<Implicit>,
404    pub(crate) clobbers: Vec<RegSet>,
405    pub(crate) slots: Vec<SlotKind>,
406    pub(crate) symbols: Vec<String>,
407    /// Call-site records, sorted by instruction.
408    pub(crate) sites: Vec<SiteData>,
409    pub(crate) site_slots: Vec<StackSlot>,
410    outgoing: u32,
411    frame_pointer: bool,
412}
413
414/// Fails unless a table of `len` entries has room for one more id.
415fn room(len: usize) -> Result<(), MirError> {
416    next_id(len).map(|_| ())
417}
418
419fn next_id(len: usize) -> Result<u32, MirError> {
420    if len < MAX_ENTRIES {
421        Ok(len as u32)
422    } else {
423        Err(MirError::Limit)
424    }
425}
426
427impl Function {
428    /// An empty function named `name`, under calling convention `abi` (which
429    /// also fixes the target).
430    ///
431    /// # Examples
432    ///
433    /// ```
434    /// use backend_lang::mir::Function;
435    /// use backend_lang::x86_64::WIN64;
436    ///
437    /// let f = Function::new("main", &WIN64);
438    /// assert_eq!(f.name(), "main");
439    /// assert_eq!(f.abi().name(), "win64");
440    /// ```
441    #[must_use]
442    pub fn new(name: &str, abi: &'static Abi) -> Function {
443        Function {
444            name: String::from(name),
445            abi,
446            vregs: Vec::new(),
447            blocks: Vec::new(),
448            insts: Vec::new(),
449            operands: Vec::new(),
450            args: Vec::new(),
451            implicits: Vec::new(),
452            clobbers: Vec::new(),
453            slots: Vec::new(),
454            symbols: Vec::new(),
455            sites: Vec::new(),
456            site_slots: Vec::new(),
457            outgoing: 0,
458            frame_pointer: true,
459        }
460    }
461
462    /// An empty function with room for `insts` instructions and `operands`
463    /// operands, so building a large function does not reallocate.
464    ///
465    /// # Examples
466    ///
467    /// ```
468    /// use backend_lang::mir::Function;
469    /// use backend_lang::x86_64::SYSV;
470    ///
471    /// let f = Function::with_capacity("big", &SYSV, 100_000, 300_000);
472    /// assert_eq!(f.inst_count(), 0);
473    /// ```
474    #[must_use]
475    pub fn with_capacity(name: &str, abi: &'static Abi, insts: usize, operands: usize) -> Function {
476        let mut f = Function::new(name, abi);
477        f.insts.reserve(insts);
478        f.operands.reserve(operands);
479        f
480    }
481
482    /// The function's name, which is also the symbol other functions call it
483    /// by.
484    ///
485    /// # Examples
486    ///
487    /// ```
488    /// use backend_lang::mir::Function;
489    /// use backend_lang::x86_64::SYSV;
490    ///
491    /// assert_eq!(Function::new("f", &SYSV).name(), "f");
492    /// ```
493    #[inline]
494    #[must_use]
495    pub fn name(&self) -> &str {
496        &self.name
497    }
498
499    /// The calling convention.
500    ///
501    /// # Examples
502    ///
503    /// ```
504    /// use backend_lang::mir::Function;
505    /// use backend_lang::x86_64::SYSV;
506    ///
507    /// assert_eq!(Function::new("f", &SYSV).abi().name(), "sysv64");
508    /// ```
509    #[inline]
510    #[must_use]
511    pub fn abi(&self) -> &'static Abi {
512        self.abi
513    }
514
515    /// The target (the calling convention's).
516    ///
517    /// # Examples
518    ///
519    /// ```
520    /// use backend_lang::mir::Function;
521    /// use backend_lang::x86_64::SYSV;
522    ///
523    /// assert_eq!(Function::new("f", &SYSV).target().name(), "x86-64");
524    /// ```
525    #[inline]
526    #[must_use]
527    pub fn target(&self) -> &'static Target {
528        self.abi.target()
529    }
530
531    /// A new virtual register of `class`.
532    ///
533    /// # Errors
534    ///
535    /// [`MirError::UnknownClass`] if the target has no such class,
536    /// [`MirError::Limit`] past [`VReg::MAX`] registers.
537    ///
538    /// # Examples
539    ///
540    /// ```
541    /// use backend_lang::RegClass;
542    /// use backend_lang::mir::{Function, MirError};
543    /// use backend_lang::x86_64::{SYSV, VEC};
544    ///
545    /// let mut f = Function::new("f", &SYSV);
546    /// assert!(f.vreg(VEC)?.is_virtual());
547    /// assert_eq!(f.vreg(RegClass::new(7)), Err(MirError::UnknownClass(RegClass::new(7))));
548    /// # Ok::<(), MirError>(())
549    /// ```
550    pub fn vreg(&mut self, class: RegClass) -> Result<Reg, MirError> {
551        if !self.target().has_class(class) {
552            return Err(MirError::UnknownClass(class));
553        }
554        if self.vregs.len() >= VReg::MAX {
555            return Err(MirError::Limit);
556        }
557        let v = VReg::from_index(self.vregs.len() as u32);
558        self.vregs.push(class);
559        Ok(v.into())
560    }
561
562    /// The class of a virtual register, or `None` if the function does not
563    /// have it.
564    ///
565    /// # Examples
566    ///
567    /// ```
568    /// use backend_lang::mir::Function;
569    /// use backend_lang::x86_64::{GPR, SYSV};
570    ///
571    /// let mut f = Function::new("f", &SYSV);
572    /// let v = f.vreg(GPR)?.as_virt().unwrap();
573    /// assert_eq!(f.vreg_class(v), Some(GPR));
574    /// # Ok::<(), backend_lang::mir::MirError>(())
575    /// ```
576    #[inline]
577    #[must_use]
578    pub fn vreg_class(&self, vreg: VReg) -> Option<RegClass> {
579        self.vregs.get(vreg.index()).copied()
580    }
581
582    /// The number of virtual registers.
583    ///
584    /// # Examples
585    ///
586    /// ```
587    /// use backend_lang::mir::Function;
588    /// use backend_lang::x86_64::{GPR, SYSV};
589    ///
590    /// let mut f = Function::new("f", &SYSV);
591    /// let _ = f.vreg(GPR)?;
592    /// assert_eq!(f.vreg_count(), 1);
593    /// # Ok::<(), backend_lang::mir::MirError>(())
594    /// ```
595    #[inline]
596    #[must_use]
597    pub fn vreg_count(&self) -> usize {
598        self.vregs.len()
599    }
600
601    /// The class of any register: a virtual register's declared class, or
602    /// a physical register's class in the target.
603    ///
604    /// # Examples
605    ///
606    /// ```
607    /// use backend_lang::mir::Function;
608    /// use backend_lang::x86_64::{GPR, SYSV, VEC, XMM2};
609    ///
610    /// let mut f = Function::new("f", &SYSV);
611    /// let v = f.vreg(GPR)?;
612    /// assert_eq!(f.reg_class(v), Some(GPR));
613    /// assert_eq!(f.reg_class(XMM2.into()), Some(VEC));
614    /// # Ok::<(), backend_lang::mir::MirError>(())
615    /// ```
616    #[must_use]
617    pub fn reg_class(&self, reg: Reg) -> Option<RegClass> {
618        match (reg.as_phys(), reg.as_virt()) {
619            (Some(p), _) => self.target().class_of(p),
620            (_, Some(v)) => self.vreg_class(v),
621            _ => None,
622        }
623    }
624
625    /// A new, empty block. The first block is the entry.
626    ///
627    /// # Errors
628    ///
629    /// [`MirError::Limit`] past `u32::MAX - 1` blocks.
630    ///
631    /// # Examples
632    ///
633    /// ```
634    /// use backend_lang::mir::Function;
635    /// use backend_lang::x86_64::SYSV;
636    ///
637    /// let mut f = Function::new("f", &SYSV);
638    /// let entry = f.block()?;
639    /// assert_eq!(f.entry(), Some(entry));
640    /// # Ok::<(), backend_lang::mir::MirError>(())
641    /// ```
642    pub fn block(&mut self) -> Result<Block, MirError> {
643        let id = next_id(self.blocks.len())?;
644        self.blocks.push(BlockData::default());
645        Ok(Block::new(id))
646    }
647
648    /// The entry block, if any block exists.
649    ///
650    /// # Examples
651    ///
652    /// ```
653    /// use backend_lang::mir::Function;
654    /// use backend_lang::x86_64::SYSV;
655    ///
656    /// assert_eq!(Function::new("f", &SYSV).entry(), None);
657    /// ```
658    #[inline]
659    #[must_use]
660    pub fn entry(&self) -> Option<Block> {
661        if self.blocks.is_empty() {
662            None
663        } else {
664            Some(Block::new(0))
665        }
666    }
667
668    /// The blocks, in layout order (the order emission lays them out).
669    ///
670    /// # Examples
671    ///
672    /// ```
673    /// use backend_lang::mir::Function;
674    /// use backend_lang::x86_64::SYSV;
675    ///
676    /// let mut f = Function::new("f", &SYSV);
677    /// let a = f.block()?;
678    /// let b = f.block()?;
679    /// assert_eq!(f.blocks().collect::<Vec<_>>(), [a, b]);
680    /// # Ok::<(), backend_lang::mir::MirError>(())
681    /// ```
682    pub fn blocks(&self) -> impl ExactSizeIterator<Item = Block> + '_ {
683        (0..self.blocks.len()).map(Block::from_index)
684    }
685
686    /// The number of blocks.
687    ///
688    /// # Examples
689    ///
690    /// ```
691    /// use backend_lang::mir::Function;
692    /// use backend_lang::x86_64::SYSV;
693    ///
694    /// assert_eq!(Function::new("f", &SYSV).block_count(), 0);
695    /// ```
696    #[inline]
697    #[must_use]
698    pub fn block_count(&self) -> usize {
699        self.blocks.len()
700    }
701
702    /// Appends a parameter to `block`: a register (virtual before
703    /// allocation, physical after) or a whole stack slot
704    /// ([`Operand::slot`]). The entry block's parameters are the function's
705    /// incoming arguments.
706    ///
707    /// # Errors
708    ///
709    /// [`MirError::UnknownBlock`] for a block the function does not have,
710    /// [`MirError::BadParam`] for any other operand shape (including a slot
711    /// operand with an offset), [`MirError::UnknownVReg`],
712    /// [`MirError::UnknownPReg`], or [`MirError::UnknownSlot`] for a register
713    /// or slot the function or target does not have.
714    ///
715    /// # Examples
716    ///
717    /// ```
718    /// use backend_lang::mir::{Function, Operand};
719    /// use backend_lang::x86_64::{RDI, SYSV};
720    ///
721    /// let mut f = Function::new("f", &SYSV);
722    /// let entry = f.block()?;
723    /// f.add_param(entry, RDI.into())?;
724    /// assert_eq!(f.params(entry), [Operand::from(RDI)]);
725    /// assert!(f.add_param(entry, Operand::Imm(1)).is_err());
726    /// # Ok::<(), backend_lang::mir::MirError>(())
727    /// ```
728    pub fn add_param(&mut self, block: Block, param: Operand) -> Result<(), MirError> {
729        match param {
730            Operand::Reg(r) => self.check_reg(r)?,
731            Operand::Slot { slot, offset: 0 } => self.check_slot(slot)?,
732            _ => return Err(MirError::BadParam { block }),
733        }
734        let data = self
735            .blocks
736            .get_mut(block.index())
737            .ok_or(MirError::UnknownBlock(block))?;
738        room(data.params.len())?;
739        data.params.push(param);
740        Ok(())
741    }
742
743    /// A block's parameters (empty for a block the function does not have).
744    ///
745    /// # Examples
746    ///
747    /// ```
748    /// use backend_lang::mir::Function;
749    /// use backend_lang::x86_64::SYSV;
750    ///
751    /// let mut f = Function::new("f", &SYSV);
752    /// let b = f.block()?;
753    /// assert!(f.params(b).is_empty());
754    /// # Ok::<(), backend_lang::mir::MirError>(())
755    /// ```
756    #[inline]
757    #[must_use]
758    pub fn params(&self, block: Block) -> &[Operand] {
759        self.blocks
760            .get(block.index())
761            .map_or(&[], |b| b.params.as_slice())
762    }
763
764    /// A new stack slot.
765    ///
766    /// # Errors
767    ///
768    /// [`MirError::Limit`] past `u32::MAX - 1` slots. Sizes and alignments
769    /// are checked when the frame is laid out.
770    ///
771    /// # Examples
772    ///
773    /// ```
774    /// use backend_lang::mir::{Function, SlotKind};
775    /// use backend_lang::x86_64::SYSV;
776    ///
777    /// let mut f = Function::new("f", &SYSV);
778    /// let s = f.stack_slot(SlotKind::Local { size: 16, align: 16 })?;
779    /// assert_eq!(f.slot(s).map(SlotKind::size), Some(16));
780    /// # Ok::<(), backend_lang::mir::MirError>(())
781    /// ```
782    pub fn stack_slot(&mut self, kind: SlotKind) -> Result<StackSlot, MirError> {
783        let id = next_id(self.slots.len())?;
784        self.slots.push(kind);
785        Ok(StackSlot::new(id))
786    }
787
788    /// A new stack slot sized and aligned to hold one value of `class`.
789    ///
790    /// # Errors
791    ///
792    /// [`MirError::UnknownClass`] for a class the target does not have,
793    /// [`MirError::Limit`] past `u32::MAX - 1` slots.
794    ///
795    /// # Examples
796    ///
797    /// ```
798    /// use backend_lang::mir::{Function, SlotKind};
799    /// use backend_lang::x86_64::{SYSV, VEC};
800    ///
801    /// let mut f = Function::new("f", &SYSV);
802    /// let s = f.spill_slot(VEC)?;
803    /// assert_eq!(f.slot(s), Some(SlotKind::Local { size: 16, align: 16 }));
804    /// # Ok::<(), backend_lang::mir::MirError>(())
805    /// ```
806    pub fn spill_slot(&mut self, class: RegClass) -> Result<StackSlot, MirError> {
807        if !self.target().has_class(class) {
808            return Err(MirError::UnknownClass(class));
809        }
810        let info = self.target().class(class);
811        self.stack_slot(SlotKind::Local {
812            size: info.spill_size(),
813            align: info.spill_align(),
814        })
815    }
816
817    /// A slot's kind, or `None` if the function does not have it.
818    ///
819    /// # Examples
820    ///
821    /// ```
822    /// use backend_lang::mir::{Function, StackSlot};
823    /// use backend_lang::x86_64::SYSV;
824    ///
825    /// assert_eq!(Function::new("f", &SYSV).slot(StackSlot::new(0)), None);
826    /// ```
827    #[inline]
828    #[must_use]
829    pub fn slot(&self, slot: StackSlot) -> Option<SlotKind> {
830        self.slots.get(slot.index()).copied()
831    }
832
833    /// Every slot's kind, indexed by [`StackSlot::index`].
834    ///
835    /// # Examples
836    ///
837    /// ```
838    /// use backend_lang::mir::Function;
839    /// use backend_lang::x86_64::SYSV;
840    ///
841    /// assert!(Function::new("f", &SYSV).slots().is_empty());
842    /// ```
843    #[inline]
844    #[must_use]
845    pub fn slots(&self) -> &[SlotKind] {
846        &self.slots
847    }
848
849    /// A new reference to the function named `name`.
850    ///
851    /// # Errors
852    ///
853    /// [`MirError::Limit`] past `u32::MAX - 1` symbols.
854    ///
855    /// # Examples
856    ///
857    /// ```
858    /// use backend_lang::mir::Function;
859    /// use backend_lang::x86_64::SYSV;
860    ///
861    /// let mut f = Function::new("f", &SYSV);
862    /// let callee = f.symbol("g")?;
863    /// assert_eq!(f.symbol_name(callee), Some("g"));
864    /// # Ok::<(), backend_lang::mir::MirError>(())
865    /// ```
866    pub fn symbol(&mut self, name: &str) -> Result<Symbol, MirError> {
867        let id = next_id(self.symbols.len())?;
868        self.symbols.push(String::from(name));
869        Ok(Symbol::new(id))
870    }
871
872    /// A symbol's name, or `None` if the function does not have it.
873    ///
874    /// # Examples
875    ///
876    /// ```
877    /// use backend_lang::mir::{Function, Symbol};
878    /// use backend_lang::x86_64::SYSV;
879    ///
880    /// assert_eq!(Function::new("f", &SYSV).symbol_name(Symbol::new(0)), None);
881    /// ```
882    #[inline]
883    #[must_use]
884    pub fn symbol_name(&self, symbol: Symbol) -> Option<&str> {
885        self.symbols.get(symbol.index()).map(String::as_str)
886    }
887
888    /// A branch target: `block` with `args` for its parameters, as an
889    /// operand for a jump or branch. The arguments are registers, whole
890    /// stack slots, or immediates.
891    ///
892    /// # Errors
893    ///
894    /// [`MirError::UnknownBlock`], [`MirError::BadArg`] for another operand
895    /// shape, the `Unknown*` errors for registers or slots the function does
896    /// not have, and [`MirError::Limit`] when the argument pool is full.
897    /// Argument counts and classes are checked when the branch is pushed.
898    ///
899    /// # Examples
900    ///
901    /// ```
902    /// use backend_lang::mir::{Function, Operand};
903    /// use backend_lang::x86_64::{op, SYSV};
904    ///
905    /// let mut f = Function::new("f", &SYSV);
906    /// let entry = f.block()?;
907    /// let target = f.block()?;
908    /// let call = f.block_call(target, &[])?;
909    /// f.push(entry, op::JMP, &[call.into()])?;
910    /// # Ok::<(), backend_lang::mir::MirError>(())
911    /// ```
912    pub fn block_call(&mut self, block: Block, args: &[Operand]) -> Result<BlockCall, MirError> {
913        if block.index() >= self.blocks.len() {
914            return Err(MirError::UnknownBlock(block));
915        }
916        for &a in args {
917            match a {
918                Operand::Reg(r) => self.check_reg(r)?,
919                Operand::Slot { slot, offset: 0 } => self.check_slot(slot)?,
920                Operand::Imm(_) => {}
921                _ => return Err(MirError::BadArg { block }),
922            }
923        }
924        let start = next_id(self.args.len())?;
925        let len = u32::try_from(args.len()).map_err(|_| MirError::Limit)?;
926        room(self.args.len().saturating_add(args.len()))?;
927        self.args.extend_from_slice(args);
928        Ok(BlockCall::new(block, start, len))
929    }
930
931    /// The arguments of a branch target (empty for one this function did not
932    /// make).
933    ///
934    /// # Examples
935    ///
936    /// ```
937    /// use backend_lang::mir::{Function, Operand};
938    /// use backend_lang::x86_64::SYSV;
939    ///
940    /// let mut f = Function::new("f", &SYSV);
941    /// let b = f.block()?;
942    /// let call = f.block_call(b, &[Operand::Imm(7)])?;
943    /// assert_eq!(f.args(call), [Operand::Imm(7)]);
944    /// # Ok::<(), backend_lang::mir::MirError>(())
945    /// ```
946    #[inline]
947    #[must_use]
948    pub fn args(&self, call: BlockCall) -> &[Operand] {
949        self.args.get(call.range()).unwrap_or(&[])
950    }
951
952    /// Appends an instruction to `block`.
953    ///
954    /// The operands are checked against the opcode's description at once:
955    /// their count, each one's shape and class, immediate ranges, branch
956    /// argument counts against the target block's parameters (so a block's
957    /// parameters must be added before branches to it), and the target's
958    /// memory-operand limit.
959    ///
960    /// # Errors
961    ///
962    /// A [`MirError`] naming the problem; nothing is appended then.
963    ///
964    /// # Examples
965    ///
966    /// ```
967    /// use backend_lang::mir::{Function, MirError, Operand};
968    /// use backend_lang::x86_64::{op, GPR, SYSV};
969    ///
970    /// let mut f = Function::new("f", &SYSV);
971    /// let b = f.block()?;
972    /// let (a, c) = (f.vreg(GPR)?, f.vreg(GPR)?);
973    /// f.push(b, op::MOV64RI, &[a.into(), Operand::Imm(40)])?;
974    /// f.push(b, op::ADD64, &[c.into(), a.into(), Operand::Imm(2)])?;
975    /// // add64 takes a 32-bit immediate at most.
976    /// let err = f.push(b, op::ADD64, &[c.into(), a.into(), Operand::Imm(1 << 40)]).unwrap_err();
977    /// assert!(matches!(err, MirError::ImmediateRange { .. }));
978    /// # Ok::<(), MirError>(())
979    /// ```
980    pub fn push(
981        &mut self,
982        block: Block,
983        opcode: Opcode,
984        operands: &[Operand],
985    ) -> Result<Inst, MirError> {
986        self.push_with(block, opcode, operands, Effects::new())
987    }
988
989    /// Appends an instruction with extra implicit operands (see
990    /// [`Effects`]).
991    ///
992    /// # Errors
993    ///
994    /// As for [`Function::push`], plus [`MirError::UnknownPReg`] for an
995    /// implicit register the target does not have.
996    ///
997    /// # Examples
998    ///
999    /// ```
1000    /// use backend_lang::mir::{Effects, Function, Operand};
1001    /// use backend_lang::x86_64::{op, SYSV, RAX, RDI};
1002    ///
1003    /// let mut f = Function::new("f", &SYSV);
1004    /// let b = f.block()?;
1005    /// f.push(b, op::MOV64RI, &[RAX.into(), Operand::Imm(60)])?;
1006    /// f.push_with(b, op::SYSCALL, &[], Effects::new().uses(&[RDI]))?;
1007    /// f.push(b, op::UD2, &[])?;
1008    /// assert!(f.to_string().contains("syscall implicit(rdi)"));
1009    /// # Ok::<(), backend_lang::mir::MirError>(())
1010    /// ```
1011    pub fn push_with(
1012        &mut self,
1013        block: Block,
1014        opcode: Opcode,
1015        operands: &[Operand],
1016        effects: Effects<'_>,
1017    ) -> Result<Inst, MirError> {
1018        let inst = self.create_inst(block, opcode, operands, effects)?;
1019        if let Some(b) = self.blocks.get_mut(block.index()) {
1020            b.insts.push(inst);
1021        }
1022        Ok(inst)
1023    }
1024
1025    /// Creates a checked instruction of `block` without placing it in the
1026    /// block's list (passes that insert code rebuild the list in one go).
1027    pub(crate) fn create_inst(
1028        &mut self,
1029        block: Block,
1030        opcode: Opcode,
1031        operands: &[Operand],
1032        effects: Effects<'_>,
1033    ) -> Result<Inst, MirError> {
1034        if block.index() >= self.blocks.len() {
1035            return Err(MirError::UnknownBlock(block));
1036        }
1037        let inst = Inst::new(next_id(self.insts.len())?);
1038        self.check_inst(inst, opcode, operands)?;
1039        for &r in effects.uses.iter().chain(effects.defs) {
1040            if !self.target().has_reg(r) {
1041                return Err(MirError::UnknownPReg(r));
1042            }
1043        }
1044        let ops = next_id(self.operands.len())?;
1045        room(self.operands.len().saturating_add(operands.len()))?;
1046        let imp = next_id(self.implicits.len())?;
1047        let nimp = effects.uses.len() + effects.defs.len();
1048        room(self.implicits.len().saturating_add(nimp))?;
1049        let clobber = if effects.clobbers.is_empty() {
1050            NO_CLOBBERS
1051        } else {
1052            let id = next_id(self.clobbers.len())?;
1053            self.clobbers.push(effects.clobbers);
1054            id
1055        };
1056        self.operands.extend_from_slice(operands);
1057        self.implicits
1058            .extend(effects.uses.iter().map(|&reg| Implicit {
1059                reg,
1060                kind: ImplicitKind::Use,
1061            }));
1062        self.implicits
1063            .extend(effects.defs.iter().map(|&reg| Implicit {
1064                reg,
1065                kind: ImplicitKind::Def,
1066            }));
1067        self.insts.push(InstData {
1068            opcode,
1069            block,
1070            ops,
1071            nops: operands.len() as u32,
1072            imp,
1073            nimp: nimp as u32,
1074            clobber,
1075        });
1076        Ok(inst)
1077    }
1078
1079    /// Replaces `block`'s instruction list.
1080    pub(crate) fn set_block_insts(&mut self, block: Block, insts: Vec<Inst>) {
1081        if let Some(b) = self.blocks.get_mut(block.index()) {
1082            b.insts = insts;
1083        }
1084    }
1085
1086    /// Takes `block`'s instruction list, leaving it empty.
1087    pub(crate) fn take_block_insts(&mut self, block: Block) -> Vec<Inst> {
1088        self.blocks
1089            .get_mut(block.index())
1090            .map(|b| core::mem::take(&mut b.insts))
1091            .unwrap_or_default()
1092    }
1093
1094    /// Replaces `block`'s parameter list.
1095    pub(crate) fn set_params(&mut self, block: Block, params: Vec<Operand>) {
1096        if let Some(b) = self.blocks.get_mut(block.index()) {
1097            b.params = params;
1098        }
1099    }
1100
1101    /// The index of `inst`'s first operand in the operand pool.
1102    pub(crate) fn operand_base(&self, inst: Inst) -> usize {
1103        self.insts.get(inst.index()).map_or(0, |d| d.ops as usize)
1104    }
1105
1106    /// The instructions of `block`, in order (empty for a block the function
1107    /// does not have).
1108    ///
1109    /// # Examples
1110    ///
1111    /// ```
1112    /// use backend_lang::mir::Function;
1113    /// use backend_lang::x86_64::{op, SYSV};
1114    ///
1115    /// let mut f = Function::new("f", &SYSV);
1116    /// let b = f.block()?;
1117    /// let r = f.push(b, op::RET, &[])?;
1118    /// assert_eq!(f.insts(b), [r]);
1119    /// # Ok::<(), backend_lang::mir::MirError>(())
1120    /// ```
1121    #[inline]
1122    #[must_use]
1123    pub fn insts(&self, block: Block) -> &[Inst] {
1124        self.blocks
1125            .get(block.index())
1126            .map_or(&[], |b| b.insts.as_slice())
1127    }
1128
1129    /// The number of instructions in the function.
1130    ///
1131    /// # Examples
1132    ///
1133    /// ```
1134    /// use backend_lang::mir::Function;
1135    /// use backend_lang::x86_64::SYSV;
1136    ///
1137    /// assert_eq!(Function::new("f", &SYSV).inst_count(), 0);
1138    /// ```
1139    #[inline]
1140    #[must_use]
1141    pub fn inst_count(&self) -> usize {
1142        self.insts.len()
1143    }
1144
1145    /// An instruction's opcode, or `None` for one the function does not have.
1146    ///
1147    /// # Examples
1148    ///
1149    /// ```
1150    /// use backend_lang::mir::Function;
1151    /// use backend_lang::x86_64::{op, SYSV};
1152    ///
1153    /// let mut f = Function::new("f", &SYSV);
1154    /// let b = f.block()?;
1155    /// let r = f.push(b, op::RET, &[])?;
1156    /// assert_eq!(f.opcode(r), Some(op::RET));
1157    /// # Ok::<(), backend_lang::mir::MirError>(())
1158    /// ```
1159    #[inline]
1160    #[must_use]
1161    pub fn opcode(&self, inst: Inst) -> Option<Opcode> {
1162        self.insts.get(inst.index()).map(|d| d.opcode)
1163    }
1164
1165    /// The block an instruction is in.
1166    ///
1167    /// # Examples
1168    ///
1169    /// ```
1170    /// use backend_lang::mir::Function;
1171    /// use backend_lang::x86_64::{op, SYSV};
1172    ///
1173    /// let mut f = Function::new("f", &SYSV);
1174    /// let b = f.block()?;
1175    /// let r = f.push(b, op::RET, &[])?;
1176    /// assert_eq!(f.inst_block(r), Some(b));
1177    /// # Ok::<(), backend_lang::mir::MirError>(())
1178    /// ```
1179    #[inline]
1180    #[must_use]
1181    pub fn inst_block(&self, inst: Inst) -> Option<Block> {
1182        self.insts.get(inst.index()).map(|d| d.block)
1183    }
1184
1185    /// An instruction's explicit operands (empty for one the function does
1186    /// not have).
1187    ///
1188    /// # Examples
1189    ///
1190    /// ```
1191    /// use backend_lang::mir::{Function, Operand};
1192    /// use backend_lang::x86_64::{op, SYSV, RAX};
1193    ///
1194    /// let mut f = Function::new("f", &SYSV);
1195    /// let b = f.block()?;
1196    /// let i = f.push(b, op::MOV64RI, &[RAX.into(), Operand::Imm(5)])?;
1197    /// assert_eq!(f.operands(i), [Operand::from(RAX), Operand::Imm(5)]);
1198    /// # Ok::<(), backend_lang::mir::MirError>(())
1199    /// ```
1200    #[inline]
1201    #[must_use]
1202    pub fn operands(&self, inst: Inst) -> &[Operand] {
1203        self.insts
1204            .get(inst.index())
1205            .and_then(|d| {
1206                self.operands
1207                    .get(d.ops as usize..d.ops as usize + d.nops as usize)
1208            })
1209            .unwrap_or(&[])
1210    }
1211
1212    /// An instruction's extra implicit operands, uses first (empty for one
1213    /// the function does not have). The opcode's own implicit operands are in
1214    /// its [`InstDesc`](crate::target::InstDesc).
1215    ///
1216    /// # Examples
1217    ///
1218    /// ```
1219    /// use backend_lang::mir::{Effects, Function};
1220    /// use backend_lang::x86_64::{op, SYSV, RAX};
1221    ///
1222    /// let mut f = Function::new("f", &SYSV);
1223    /// let b = f.block()?;
1224    /// let r = f.push_with(b, op::RET, &[], Effects::new().uses(&[RAX]))?;
1225    /// assert_eq!(f.implicit(r).len(), 1);
1226    /// # Ok::<(), backend_lang::mir::MirError>(())
1227    /// ```
1228    #[inline]
1229    #[must_use]
1230    pub fn implicit(&self, inst: Inst) -> &[Implicit] {
1231        self.insts
1232            .get(inst.index())
1233            .and_then(|d| {
1234                self.implicits
1235                    .get(d.imp as usize..d.imp as usize + d.nimp as usize)
1236            })
1237            .unwrap_or(&[])
1238    }
1239
1240    /// An instruction's extra clobbers (empty for one the function does not
1241    /// have).
1242    ///
1243    /// # Examples
1244    ///
1245    /// ```
1246    /// use backend_lang::mir::{Effects, Function};
1247    /// use backend_lang::x86_64::{op, SYSV};
1248    ///
1249    /// let mut f = Function::new("f", &SYSV);
1250    /// let b = f.block()?;
1251    /// let callee = f.symbol("g")?;
1252    /// let c = f.push_with(b, op::CALL, &[callee.into()], Effects::new().clobbers(SYSV.call_clobbers()))?;
1253    /// assert_eq!(f.clobbers(c), SYSV.call_clobbers());
1254    /// # Ok::<(), backend_lang::mir::MirError>(())
1255    /// ```
1256    #[inline]
1257    #[must_use]
1258    pub fn clobbers(&self, inst: Inst) -> RegSet {
1259        self.insts
1260            .get(inst.index())
1261            .and_then(|d| self.clobbers.get(d.clobber as usize))
1262            .copied()
1263            .unwrap_or(RegSet::EMPTY)
1264    }
1265
1266    /// Records what a call instruction carries besides its operands: the
1267    /// stack slots holding its GC roots (its stack map: a collector running
1268    /// during the call finds the references there and may update them), and
1269    /// the block control reaches if the callee unwinds. Setting it again
1270    /// replaces the record.
1271    ///
1272    /// A landing pad is a successor of the call's block for liveness: the
1273    /// values it uses are live across the call.
1274    ///
1275    /// # Errors
1276    ///
1277    /// [`MirError::NotACall`] if `inst` is not a call,
1278    /// [`MirError::UnknownSlot`] or [`MirError::UnknownBlock`] for a slot or
1279    /// block the function does not have, [`MirError::Limit`] past 32-bit
1280    /// tables.
1281    ///
1282    /// # Examples
1283    ///
1284    /// ```
1285    /// use backend_lang::mir::{Function, MirError, SlotKind};
1286    /// use backend_lang::x86_64::{op, SYSV};
1287    ///
1288    /// let mut f = Function::new("f", &SYSV);
1289    /// let b = f.block()?;
1290    /// let root = f.stack_slot(SlotKind::Local { size: 8, align: 8 })?;
1291    /// let g = f.symbol("g")?;
1292    /// let call = f.push(b, op::CALL, &[g.into()])?;
1293    /// let ret = f.push(b, op::RET, &[])?;
1294    /// f.set_call_site(call, &[root], None)?;
1295    /// assert_eq!(f.set_call_site(ret, &[], None), Err(MirError::NotACall { inst: ret }));
1296    /// # Ok::<(), MirError>(())
1297    /// ```
1298    pub fn set_call_site(
1299        &mut self,
1300        inst: Inst,
1301        gc_slots: &[StackSlot],
1302        landing_pad: Option<Block>,
1303    ) -> Result<(), MirError> {
1304        let is_call = self
1305            .opcode(inst)
1306            .and_then(|o| self.target().inst(o))
1307            .is_some_and(|d| d.kind() == InstKind::Call);
1308        if !is_call {
1309            return Err(MirError::NotACall { inst });
1310        }
1311        for &s in gc_slots {
1312            self.check_slot(s)?;
1313        }
1314        if let Some(b) = landing_pad {
1315            if b.index() >= self.blocks.len() {
1316                return Err(MirError::UnknownBlock(b));
1317            }
1318        }
1319        let gc = next_id(self.site_slots.len())?;
1320        room(self.site_slots.len().saturating_add(gc_slots.len()))?;
1321        let ngc = u32::try_from(gc_slots.len()).map_err(|_| MirError::Limit)?;
1322        self.site_slots.extend_from_slice(gc_slots);
1323        let data = SiteData {
1324            inst,
1325            gc,
1326            ngc,
1327            landing: landing_pad,
1328        };
1329        // Records arrive in instruction order from instruction selection, so
1330        // this is an append; out-of-order records still land sorted.
1331        match self.sites.binary_search_by_key(&inst, |s| s.inst) {
1332            Ok(i) => self.sites[i] = data,
1333            Err(i) => {
1334                room(self.sites.len())?;
1335                self.sites.insert(i, data);
1336            }
1337        }
1338        Ok(())
1339    }
1340
1341    /// The call-site record of `inst`, if it has one.
1342    ///
1343    /// # Examples
1344    ///
1345    /// ```
1346    /// use backend_lang::mir::{Function, Inst};
1347    /// use backend_lang::x86_64::SYSV;
1348    ///
1349    /// assert!(Function::new("f", &SYSV).call_site(Inst::new(0)).is_none());
1350    /// ```
1351    #[must_use]
1352    pub fn call_site(&self, inst: Inst) -> Option<CallSite<'_>> {
1353        let i = self.sites.binary_search_by_key(&inst, |s| s.inst).ok()?;
1354        self.sites.get(i).map(|d| self.site_ref(d))
1355    }
1356
1357    /// Every call-site record, by instruction.
1358    ///
1359    /// # Examples
1360    ///
1361    /// ```
1362    /// use backend_lang::mir::Function;
1363    /// use backend_lang::x86_64::SYSV;
1364    ///
1365    /// assert_eq!(Function::new("f", &SYSV).call_sites().count(), 0);
1366    /// ```
1367    pub fn call_sites(&self) -> impl ExactSizeIterator<Item = CallSite<'_>> + '_ {
1368        self.sites.iter().map(|d| self.site_ref(d))
1369    }
1370
1371    fn site_ref(&self, d: &SiteData) -> CallSite<'_> {
1372        let start = d.gc as usize;
1373        CallSite {
1374            inst: d.inst,
1375            gc_slots: self
1376                .site_slots
1377                .get(start..start + d.ngc as usize)
1378                .unwrap_or(&[]),
1379            landing_pad: d.landing,
1380        }
1381    }
1382
1383    /// Reserves `bytes` of outgoing argument area at the bottom of the frame
1384    /// (the largest over all calls; see
1385    /// [`Abi::assign_args`](crate::target::abi::Abi::assign_args)). Stack
1386    /// arguments are stored to `[sp + offset]` before a call. Calling it
1387    /// again keeps the larger value.
1388    ///
1389    /// # Examples
1390    ///
1391    /// ```
1392    /// use backend_lang::mir::Function;
1393    /// use backend_lang::x86_64::SYSV;
1394    ///
1395    /// let mut f = Function::new("f", &SYSV);
1396    /// f.reserve_outgoing(24);
1397    /// f.reserve_outgoing(8);
1398    /// assert_eq!(f.outgoing(), 24);
1399    /// ```
1400    pub fn reserve_outgoing(&mut self, bytes: u32) {
1401        self.outgoing = self.outgoing.max(bytes);
1402    }
1403
1404    /// The outgoing argument area reserved.
1405    ///
1406    /// # Examples
1407    ///
1408    /// ```
1409    /// use backend_lang::mir::Function;
1410    /// use backend_lang::x86_64::SYSV;
1411    ///
1412    /// assert_eq!(Function::new("f", &SYSV).outgoing(), 0);
1413    /// ```
1414    #[inline]
1415    #[must_use]
1416    pub fn outgoing(&self) -> u32 {
1417        self.outgoing
1418    }
1419
1420    /// Lays the frame out without a frame pointer, which frees the frame
1421    /// pointer register for the body (it is then saved like any other
1422    /// callee-saved register it writes). The frame pointer is kept by
1423    /// default.
1424    ///
1425    /// # Examples
1426    ///
1427    /// ```
1428    /// use backend_lang::mir::Function;
1429    /// use backend_lang::x86_64::SYSV;
1430    ///
1431    /// let mut f = Function::new("f", &SYSV);
1432    /// f.omit_frame_pointer();
1433    /// assert!(!f.frame_pointer());
1434    /// assert!(f.frame_layout().unwrap().prologue().is_empty());
1435    /// ```
1436    pub fn omit_frame_pointer(&mut self) {
1437        self.frame_pointer = false;
1438    }
1439
1440    /// Whether the frame keeps a frame pointer.
1441    ///
1442    /// # Examples
1443    ///
1444    /// ```
1445    /// use backend_lang::mir::Function;
1446    /// use backend_lang::x86_64::SYSV;
1447    ///
1448    /// assert!(Function::new("f", &SYSV).frame_pointer());
1449    /// ```
1450    #[inline]
1451    #[must_use]
1452    pub fn frame_pointer(&self) -> bool {
1453        self.frame_pointer
1454    }
1455
1456    /// The registers reserved for the frame, which the body may read but not
1457    /// write: the stack pointer, and the frame pointer when it is kept.
1458    ///
1459    /// # Examples
1460    ///
1461    /// ```
1462    /// use backend_lang::mir::Function;
1463    /// use backend_lang::x86_64::{SYSV, RBP, RSP};
1464    ///
1465    /// let f = Function::new("f", &SYSV);
1466    /// assert!(f.reserved().contains(RSP) && f.reserved().contains(RBP));
1467    /// ```
1468    #[must_use]
1469    pub fn reserved(&self) -> RegSet {
1470        let t = self.target();
1471        let set = RegSet::of(&[t.stack_pointer()]);
1472        if self.frame_pointer {
1473            set.with(t.frame_pointer())
1474        } else {
1475            set
1476        }
1477    }
1478
1479    /// Whether any instruction is a call.
1480    ///
1481    /// # Examples
1482    ///
1483    /// ```
1484    /// use backend_lang::mir::Function;
1485    /// use backend_lang::x86_64::SYSV;
1486    ///
1487    /// assert!(!Function::new("f", &SYSV).has_calls());
1488    /// ```
1489    #[must_use]
1490    pub fn has_calls(&self) -> bool {
1491        let t = self.target();
1492        self.insts.iter().any(|d| {
1493            t.inst(d.opcode)
1494                .is_some_and(|desc| desc.kind() == InstKind::Call)
1495        })
1496    }
1497
1498    /// Every physical register the function's instructions may write:
1499    /// explicit and implicit definitions, clobbers, and physical block
1500    /// parameters (written by the moves on the edges into them). The
1501    /// callee-saved registers among them are what the prologue saves.
1502    ///
1503    /// # Examples
1504    ///
1505    /// ```
1506    /// use backend_lang::mir::{Function, Operand};
1507    /// use backend_lang::x86_64::{op, SYSV, RBX, RDX, RAX, FLAGS};
1508    ///
1509    /// let mut f = Function::new("f", &SYSV);
1510    /// let b = f.block()?;
1511    /// f.push(b, op::MOV64RI, &[RBX.into(), Operand::Imm(1)])?;
1512    /// f.push(b, op::CQO, &[])?;
1513    /// let w = f.written_regs();
1514    /// assert!(w.contains(RBX) && w.contains(RDX));
1515    /// assert!(!w.contains(RAX));
1516    /// # Ok::<(), backend_lang::mir::MirError>(())
1517    /// ```
1518    #[must_use]
1519    pub fn written_regs(&self) -> RegSet {
1520        let t = self.target();
1521        let mut set = RegSet::EMPTY;
1522        for (i, d) in self.insts.iter().enumerate() {
1523            let inst = Inst::from_index(i);
1524            let Some(desc) = t.inst(d.opcode) else {
1525                continue;
1526            };
1527            for p in desc.implicit_defs() {
1528                set = set.with(*p);
1529            }
1530            set = set.union(desc.clobbers()).union(self.clobbers(inst));
1531            for imp in self.implicit(inst) {
1532                if imp.kind == ImplicitKind::Def {
1533                    set = set.with(imp.reg);
1534                }
1535            }
1536            let ops = self.operands(inst);
1537            let defs = match desc.kind() {
1538                InstKind::Copy => ops.len().min(1),
1539                InstKind::ParallelCopy => ops.len() / 2,
1540                _ => desc
1541                    .operands()
1542                    .iter()
1543                    .take_while(|r| matches!(r, OperandRule::Def(_)))
1544                    .count(),
1545            };
1546            for op in ops.iter().take(defs) {
1547                if let Some(p) = op.reg().and_then(Reg::as_phys) {
1548                    set = set.with(p);
1549                }
1550            }
1551        }
1552        for b in &self.blocks {
1553            for p in &b.params {
1554                if let Some(r) = p.reg().and_then(Reg::as_phys) {
1555                    set = set.with(r);
1556                }
1557            }
1558        }
1559        set
1560    }
1561
1562    /// Lays out the function's frame under its calling convention.
1563    ///
1564    /// # Errors
1565    ///
1566    /// [`FrameError`] for a slot alignment the frame cannot provide,
1567    /// overlapping incoming slots, or a frame beyond 32-bit offsets.
1568    ///
1569    /// # Examples
1570    ///
1571    /// ```
1572    /// use backend_lang::mir::{Function, SlotKind};
1573    /// use backend_lang::x86_64::WIN64;
1574    ///
1575    /// let mut f = Function::new("f", &WIN64);
1576    /// let s = f.stack_slot(SlotKind::Local { size: 8, align: 8 })?;
1577    /// let frame = f.frame_layout().unwrap();
1578    /// // Win64 has no red zone; after the rbp push the stack pointer is
1579    /// // 16-aligned, so 8 bytes of locals round up to 16.
1580    /// assert_eq!(frame.alloc(), 16);
1581    /// assert_eq!(frame.slot_offset(s), Some(0));
1582    /// # Ok::<(), backend_lang::mir::MirError>(())
1583    /// ```
1584    pub fn frame_layout(&self) -> Result<FrameLayout, FrameError> {
1585        self.abi.layout_frame(&FrameInput {
1586            slots: &self.slots,
1587            written: self.written_regs(),
1588            has_calls: self.has_calls(),
1589            outgoing: self.outgoing,
1590            frame_pointer: self.frame_pointer,
1591        })
1592    }
1593
1594    pub(crate) fn check_reg(&self, reg: Reg) -> Result<(), MirError> {
1595        match (reg.as_phys(), reg.as_virt()) {
1596            (Some(p), _) if !self.target().has_reg(p) => Err(MirError::UnknownPReg(p)),
1597            (_, Some(v)) if v.index() >= self.vregs.len() => Err(MirError::UnknownVReg(v)),
1598            _ => Ok(()),
1599        }
1600    }
1601
1602    pub(crate) fn check_slot(&self, slot: StackSlot) -> Result<(), MirError> {
1603        if slot.index() < self.slots.len() {
1604            Ok(())
1605        } else {
1606            Err(MirError::UnknownSlot(slot))
1607        }
1608    }
1609}