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(|®| Implicit {
1059 reg,
1060 kind: ImplicitKind::Use,
1061 }));
1062 self.implicits
1063 .extend(effects.defs.iter().map(|®| 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}