Skip to main content

rucc_ir/
func.rs

1//! The function: its blocks, its instructions, its values, and the tables they live in.
2//!
3//! Design: `spec/08-ir.md` sections 8.1 and 8.6.
4//!
5//! One [`Func`] owns everything in it. Nothing is boxed and nothing is individually freed: the
6//! instructions are a flat vector, a reference to one is a four-byte index, and the whole
7//! function is dropped in one go. The same shape as the AST, for the same reasons.
8//!
9//! Two things are not flat, and both for the same reason, which is that SSA construction
10//! finishes a loop header long after it has built the blocks inside the loop.
11//!
12//! The instructions in a block are a doubly linked list rather than a run, because the
13//! optimizer inserts and removes instructions constantly and a run would move every
14//! instruction after the edit, invalidating every [`Inst`] anybody was holding.
15//!
16//! A block's parameters are a `Vec` rather than a run in a pool, because a run in a pool
17//! cannot grow once something else has been put after it, and adding a parameter to a loop
18//! header is exactly the operation that has to grow one.
19//!
20//! # CFG invariants
21//!
22//! The entry block has no predecessors and its parameters are the function's arguments in
23//! their C-level form, before the ABI has been applied. Every other block ends in exactly one
24//! terminator and contains no terminator anywhere else. These are checked by the verifier
25//! rather than by the builder, because a function under construction breaks all of them and
26//! the useful question is whether it still does when the pass that was building it says it has
27//! finished.
28
29use std::ops::{Index, IndexMut};
30
31use rucc_base::{Idx, Symbol};
32use rucc_diag::Span;
33
34use crate::inst::{
35    Abi, AbiList, AsmInfo, Block, BlockCall, BlockCallList, BlockData, CallInfo, Def, Extra, Imm,
36    ImmList, Inst, InstData, InstLayout, MemInfo, Sig, Signature, SwitchInfo, Value, ValueData,
37    ValueList,
38};
39use crate::module::{Linkage, Visibility};
40use crate::{Attrs, Flags, FloatPred, IntPred, Opcode, Type};
41
42/// One function.
43#[derive(Debug)]
44pub struct Func {
45    /// The name it is called by, which is what a direct call to it names.
46    pub name: Symbol,
47    /// How the linker sees it. `Internal` for a `static` function.
48    pub linkage: Linkage,
49    /// How the dynamic linker sees it.
50    pub visibility: Visibility,
51    /// The section to put it in, from `__attribute__((section(...)))`, or `None` to let the
52    /// object writer choose.
53    pub section: Option<Symbol>,
54    /// What is true of the whole function, which is what a caller reads when it wants to know
55    /// what a call to it does without looking inside.
56    pub attrs: Attrs,
57
58    values: Vec<ValueData>,
59    insts: Vec<InstData>,
60    inst_layout: Vec<InstLayout>,
61    inst_spans: Vec<Span>,
62    blocks: Vec<BlockData>,
63
64    value_pool: Vec<Value>,
65    block_calls: Vec<BlockCall>,
66    imms: Vec<Imm>,
67    mem: Vec<MemInfo>,
68    calls: Vec<CallInfo>,
69    abis: Vec<Abi>,
70    switches: Vec<SwitchInfo>,
71    asms: Vec<AsmInfo>,
72    signatures: Vec<Signature>,
73
74    first_block: Option<Block>,
75    last_block: Option<Block>,
76}
77
78impl Func {
79    /// A function with that name and that signature, and nothing in it.
80    ///
81    /// The signature becomes signature zero, which is what [`Func::signature`] gives back. The
82    /// entry block is not created here, because the caller is about to create it and give it
83    /// the parameters, and a half-built entry block is worse than no entry block. So a
84    /// function fresh from here is a declaration, and stops being one when it gets a block.
85    #[must_use]
86    pub fn new(name: Symbol, signature: Signature) -> Self {
87        Self {
88            name,
89            linkage: Linkage::External,
90            visibility: Visibility::Default,
91            section: None,
92            attrs: Attrs::NONE,
93            values: Vec::new(),
94            insts: Vec::new(),
95            inst_layout: Vec::new(),
96            inst_spans: Vec::new(),
97            blocks: Vec::new(),
98            value_pool: Vec::new(),
99            block_calls: Vec::new(),
100            imms: Vec::new(),
101            mem: Vec::new(),
102            calls: Vec::new(),
103            abis: Vec::new(),
104            switches: Vec::new(),
105            asms: Vec::new(),
106            signatures: vec![signature],
107            first_block: None,
108            last_block: None,
109        }
110    }
111
112    /// Its own signature.
113    #[must_use]
114    pub fn signature(&self) -> &Signature {
115        &self.signatures[0]
116    }
117
118    /// Every signature the function holds, its own first and then the ones its calls name.
119    pub fn signatures(&self) -> impl Iterator<Item = &Signature> {
120        self.signatures.iter()
121    }
122
123    /// Records a signature a `call_indirect` is made with, and gives back its index.
124    pub fn add_signature(&mut self, signature: Signature) -> Sig {
125        self.signatures.push(signature);
126        Idx::from_usize(self.signatures.len() - 1)
127    }
128
129    /// The entry block, which is the first one in layout order.
130    ///
131    /// `None` only before one has been created. The verifier is what insists a finished
132    /// function has one.
133    #[must_use]
134    pub fn entry(&self) -> Option<Block> {
135        self.first_block
136    }
137
138    /// Whether this only says the function exists somewhere, which is a function with no
139    /// blocks in it.
140    ///
141    /// `extern int puts(const char *);` and every other declaration of something defined in
142    /// another object is one of these, and it is here rather than left out of the module
143    /// because a call needs its signature and its linkage.
144    #[must_use]
145    pub fn is_declaration(&self) -> bool {
146        self.first_block.is_none()
147    }
148
149    // Blocks.
150
151    /// Creates a block with no parameters and no instructions, at the end of the layout.
152    pub fn create_block(&mut self) -> Block {
153        let block = Idx::from_usize(self.blocks.len());
154        self.blocks.push(BlockData { prev: self.last_block, ..BlockData::default() });
155        match self.last_block {
156            Some(last) => self.blocks[last.index()].next = Some(block),
157            None => self.first_block = Some(block),
158        }
159        self.last_block = Some(block);
160        block
161    }
162
163    /// Takes a block out of the layout, along with everything in it.
164    ///
165    /// The block keeps its number, the way a removed instruction keeps its own, because
166    /// renumbering would move every block after it and invalidate every index anybody was
167    /// holding. What it stops being is a block of this function: nothing walks it, nothing
168    /// prints it, and the values defined in it are as gone as the instructions that defined
169    /// them. Deleting one whose branches something still reaches is how a function ends up
170    /// branching to nowhere, so the caller is the one that has to know nothing reaches it.
171    ///
172    /// # Panics
173    ///
174    /// Panics if the block is the entry block, which is the one block a function has to have.
175    pub fn remove_block(&mut self, block: Block) {
176        assert!(self.first_block != Some(block), "the entry block is not removable");
177        let (prev, next) = (self.blocks[block.index()].prev, self.blocks[block.index()].next);
178        match prev {
179            Some(prev) => self.blocks[prev.index()].next = next,
180            None => self.first_block = next,
181        }
182        match next {
183            Some(next) => self.blocks[next.index()].prev = prev,
184            None => self.last_block = prev,
185        }
186        // The instructions say they are in no block now, which is what a removed instruction
187        // says, so that asking one where it is gives an answer rather than a block nothing
188        // walks.
189        let insts: Vec<Inst> = self.insts(block).collect();
190        for inst in insts {
191            self.inst_layout[inst.index()] = InstLayout::default();
192        }
193        self.blocks[block.index()] = BlockData::default();
194    }
195
196    /// Adds a parameter of that type to a block, and gives back the value it arrives as.
197    ///
198    /// Every predecessor's branch has to grow an argument to match, which is
199    /// [`Func::append_arg`], and the verifier is what notices if one of them did not.
200    ///
201    /// # Panics
202    ///
203    /// Panics if the block already has four billion parameters, which no block does.
204    pub fn append_param(&mut self, block: Block, ty: Type) -> Value {
205        let index = u32::try_from(self.blocks[block.index()].params.len())
206            .expect("a block with four billion parameters");
207        let value = self.add_value(ValueData { ty, def: Def::Param { block, index } });
208        self.blocks[block.index()].params.push(value);
209        value
210    }
211
212    /// Drops the parameters of a block that a predicate turns down, and renumbers the rest.
213    ///
214    /// The predicate is asked about each parameter in the order the block takes them. A
215    /// parameter that goes has to take the argument in the same position out of every branch
216    /// to the block, which is the caller's work rather than this method's, because only the
217    /// caller knows which branches there are. This is what removing a redundant block
218    /// parameter is, and SSA construction is the thing that makes them.
219    ///
220    /// # Panics
221    ///
222    /// Panics if the block has four billion parameters, which no block does.
223    pub fn retain_params(&mut self, block: Block, mut keep: impl FnMut(Value) -> bool) {
224        let mut params = std::mem::take(&mut self.blocks[block.index()].params);
225        params.retain(|&value| keep(value));
226        for (index, &value) in params.iter().enumerate() {
227            let index = u32::try_from(index).expect("a block with four billion parameters");
228            self.values[value.index()].def = Def::Param { block, index };
229        }
230        self.blocks[block.index()].params = params;
231    }
232
233    /// Every block, in layout order.
234    pub fn blocks(&self) -> impl Iterator<Item = Block> + use<'_> {
235        std::iter::successors(self.first_block, move |&block| self.blocks[block.index()].next)
236    }
237
238    /// Every instruction in a block, in order.
239    pub fn insts(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_> {
240        std::iter::successors(self.blocks[block.index()].first, move |&inst| {
241            self.inst_layout[inst.index()].next
242        })
243    }
244
245    /// The last instruction of a block, which is its terminator once it is finished.
246    #[must_use]
247    pub fn terminator(&self, block: Block) -> Option<Inst> {
248        self.blocks[block.index()].last.filter(|&inst| self.is_terminator(inst))
249    }
250
251    /// Whether control leaves the block at this instruction.
252    ///
253    /// A question for the function rather than for the instruction, because inline assembly is
254    /// the one case where the opcode is not enough: `asm goto` has labels and everything else
255    /// does not, and the labels are in the function's table rather than on the instruction.
256    #[must_use]
257    pub fn is_terminator(&self, inst: Inst) -> bool {
258        let data = &self[inst];
259        match data.extra {
260            Extra::Asm(info) => {
261                data.opcode.is_terminator() || !self.asms[info.index()].targets.is_empty()
262            }
263            _ => data.opcode.is_terminator(),
264        }
265    }
266
267    // Instructions.
268
269    /// Creates an instruction and its result values, without putting it in a block.
270    ///
271    /// The results are allocated here and are contiguous, which is what lets an instruction
272    /// hold the first of them and a count rather than a list.
273    ///
274    /// # Panics
275    ///
276    /// Panics if `results` has more than 255 types, which no instruction in the set does.
277    pub fn create_inst(&mut self, mut data: InstData, results: &[Type], span: Span) -> Inst {
278        let inst = Idx::from_usize(self.insts.len());
279        data.results = u8::try_from(results.len()).expect("an instruction with too many results");
280        data.first_result = results.first().map(|_| Idx::from_usize(self.values.len()));
281        for (index, &ty) in results.iter().enumerate() {
282            let index = u8::try_from(index).expect("checked just above");
283            self.add_value(ValueData { ty, def: Def::Result { inst, index } });
284        }
285        self.insts.push(data);
286        self.inst_layout.push(InstLayout::default());
287        self.inst_spans.push(span);
288        inst
289    }
290
291    /// Puts an instruction at the end of a block.
292    ///
293    /// # Panics
294    ///
295    /// Panics if the instruction is already in a block. Moving one is removing it and
296    /// appending it, and doing it by accident is how a linked list ends up in two pieces.
297    pub fn append_inst(&mut self, block: Block, inst: Inst) {
298        assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
299        let last = self.blocks[block.index()].last;
300        self.inst_layout[inst.index()] = InstLayout { block: Some(block), prev: last, next: None };
301        match last {
302            Some(last) => self.inst_layout[last.index()].next = Some(inst),
303            None => self.blocks[block.index()].first = Some(inst),
304        }
305        self.blocks[block.index()].last = Some(inst);
306    }
307
308    /// Puts an instruction immediately before another one, in the block that one is in.
309    ///
310    /// # Panics
311    ///
312    /// Panics if `inst` is already in a block, or if `before` is not in one.
313    pub fn insert_before(&mut self, inst: Inst, before: Inst) {
314        assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
315        let at = self.inst_layout[before.index()];
316        let block = at.block.expect("the instruction to insert before is not in a block");
317        self.inst_layout[inst.index()] =
318            InstLayout { block: Some(block), prev: at.prev, next: Some(before) };
319        self.inst_layout[before.index()].prev = Some(inst);
320        match at.prev {
321            Some(prev) => self.inst_layout[prev.index()].next = Some(inst),
322            None => self.blocks[block.index()].first = Some(inst),
323        }
324    }
325
326    /// Takes an instruction out of its block, leaving it and its results in the tables.
327    ///
328    /// The instruction is not deleted, because deleting it would move every instruction after
329    /// it. A removed instruction is unreachable from any block and is dropped when the whole
330    /// function is.
331    ///
332    /// # Panics
333    ///
334    /// Panics if the instruction is not in a block.
335    pub fn remove_inst(&mut self, inst: Inst) {
336        let at = self.inst_layout[inst.index()];
337        let block = at.block.expect("the instruction is not in a block");
338        match at.prev {
339            Some(prev) => self.inst_layout[prev.index()].next = at.next,
340            None => self.blocks[block.index()].first = at.next,
341        }
342        match at.next {
343            Some(next) => self.inst_layout[next.index()].prev = at.prev,
344            None => self.blocks[block.index()].last = at.prev,
345        }
346        self.inst_layout[inst.index()] = InstLayout::default();
347    }
348
349    /// The block an instruction is in, or `None` if it has been removed from one.
350    #[must_use]
351    pub fn block_of(&self, inst: Inst) -> Option<Block> {
352        self.inst_layout[inst.index()].block
353    }
354
355    /// Where an instruction came from in the source.
356    #[must_use]
357    pub fn span(&self, inst: Inst) -> Span {
358        self.inst_spans[inst.index()]
359    }
360
361    /// Where an instruction branches to, which is empty when it does not branch.
362    ///
363    /// This is the one place that knows a `switch` keeps its targets in a side table and
364    /// `asm goto` in another one, so nothing walking the CFG has to.
365    pub fn successors(&self, inst: Inst) -> impl Iterator<Item = BlockCall> + use<'_> {
366        self.block_calls[self.target_list(inst).as_usize_range()].iter().copied()
367    }
368
369    /// Where a terminator keeps its targets, for something that edits them rather than reads
370    /// them.
371    ///
372    /// [`Func::successors`] is what walking the CFG wants. This is what recording an edge
373    /// wants, because an edge that will grow an argument later has to be named by its place in
374    /// the table rather than by the block it went to.
375    #[must_use]
376    pub fn target_list(&self, inst: Inst) -> BlockCallList {
377        match self[inst].extra {
378            Extra::Targets(targets) => targets,
379            Extra::Switch(info) => self.switches[info.index()].targets,
380            Extra::Asm(info) => self.asms[info.index()].targets,
381            _ => BlockCallList::EMPTY,
382        }
383    }
384
385    // The pools.
386
387    /// Records a run of value operands.
388    pub fn push_values(&mut self, values: &[Value]) -> ValueList {
389        let start = Idx::from_usize(self.value_pool.len());
390        self.value_pool.extend_from_slice(values);
391        ValueList::new(start, Idx::from_usize(self.value_pool.len()))
392    }
393
394    /// Adds one value to the end of a run, giving back the run it became.
395    ///
396    /// The run grows in place when nothing has been put after it, which is the case while a
397    /// list is being built. Otherwise it is copied to the end and the old space is left
398    /// behind, which is what makes adding a parameter to a loop header possible at all. That
399    /// happens once per value carried around a loop, so the copying is not what costs.
400    pub fn append_arg(&mut self, list: ValueList, value: Value) -> ValueList {
401        let range = list.as_usize_range();
402        if range.end == self.value_pool.len() {
403            self.value_pool.push(value);
404            return ValueList::new(Idx::from_usize(range.start), Idx::from_usize(range.end + 1));
405        }
406        let start = self.value_pool.len();
407        self.value_pool.extend_from_within(range);
408        self.value_pool.push(value);
409        ValueList::new(Idx::from_usize(start), Idx::from_usize(self.value_pool.len()))
410    }
411
412    /// Replaces the values in a run, which is what substituting one definition for another is.
413    ///
414    /// A run is a run whether it is an instruction's operands or a branch's arguments, so this
415    /// is the whole of the rewriting a substitution has to do.
416    pub fn rewrite(&mut self, list: ValueList, mut with: impl FnMut(Value) -> Value) {
417        for value in &mut self.value_pool[list.as_usize_range()] {
418            *value = with(*value);
419        }
420    }
421
422    /// Records a run of branch targets.
423    pub fn push_block_calls(&mut self, calls: &[BlockCall]) -> BlockCallList {
424        let start = Idx::from_usize(self.block_calls.len());
425        self.block_calls.extend_from_slice(calls);
426        BlockCallList::new(start, Idx::from_usize(self.block_calls.len()))
427    }
428
429    /// Replaces one branch target, which is what redirecting an edge is.
430    pub fn set_block_call(&mut self, at: Idx<BlockCall>, call: BlockCall) {
431        self.block_calls[at.index()] = call;
432    }
433
434    /// Records a run of case values.
435    pub fn push_imms(&mut self, imms: &[Imm]) -> ImmList {
436        let start = Idx::from_usize(self.imms.len());
437        self.imms.extend_from_slice(imms);
438        ImmList::new(start, Idx::from_usize(self.imms.len()))
439    }
440
441    /// Records a constant.
442    pub fn add_imm(&mut self, imm: Imm) -> Idx<Imm> {
443        self.imms.push(imm);
444        Idx::from_usize(self.imms.len() - 1)
445    }
446
447    /// Records what an access does.
448    pub fn add_mem(&mut self, info: MemInfo) -> Idx<MemInfo> {
449        self.mem.push(info);
450        Idx::from_usize(self.mem.len() - 1)
451    }
452
453    /// Records what the ABI asks of the arguments a call's signature does not name.
454    pub fn push_abis(&mut self, abis: &[Abi]) -> AbiList {
455        let start = Idx::from_usize(self.abis.len());
456        self.abis.extend_from_slice(abis);
457        AbiList::new(start, Idx::from_usize(self.abis.len()))
458    }
459
460    /// Records a call's callee and signature.
461    pub fn add_call(&mut self, info: CallInfo) -> Idx<CallInfo> {
462        self.calls.push(info);
463        Idx::from_usize(self.calls.len() - 1)
464    }
465
466    /// Records a `switch`'s targets and case values.
467    pub fn add_switch(&mut self, info: SwitchInfo) -> Idx<SwitchInfo> {
468        self.switches.push(info);
469        Idx::from_usize(self.switches.len() - 1)
470    }
471
472    /// Records an inline assembly instruction's template and constraints.
473    pub fn add_asm(&mut self, info: AsmInfo) -> Idx<AsmInfo> {
474        self.asms.push(info);
475        Idx::from_usize(self.asms.len() - 1)
476    }
477
478    /// How many values, instructions and blocks there are, for a reader that wants to size
479    /// something by them.
480    #[must_use]
481    pub fn counts(&self) -> Counts {
482        Counts { values: self.values.len(), insts: self.insts.len(), blocks: self.blocks.len() }
483    }
484
485    fn add_value(&mut self, data: ValueData) -> Value {
486        self.values.push(data);
487        Idx::from_usize(self.values.len() - 1)
488    }
489}
490
491/// How many of each thing a function holds.
492#[derive(Clone, Copy, Debug, PartialEq, Eq)]
493pub struct Counts {
494    /// Values, including the ones whose defining instruction has been removed.
495    pub values: usize,
496    /// Instructions, including the ones that have been removed from their block.
497    pub insts: usize,
498    /// Blocks.
499    pub blocks: usize,
500}
501
502// Reading is indexing. There is one of these for each handle, so `func[inst]` and `func[value]`
503// and `&func[args]` all work and none of them needs a method whose name says which table.
504impl Index<Value> for Func {
505    type Output = ValueData;
506
507    fn index(&self, value: Value) -> &ValueData {
508        &self.values[value.index()]
509    }
510}
511
512impl Index<Inst> for Func {
513    type Output = InstData;
514
515    fn index(&self, inst: Inst) -> &InstData {
516        &self.insts[inst.index()]
517    }
518}
519
520impl IndexMut<Inst> for Func {
521    fn index_mut(&mut self, inst: Inst) -> &mut InstData {
522        &mut self.insts[inst.index()]
523    }
524}
525
526impl Index<Block> for Func {
527    type Output = BlockData;
528
529    fn index(&self, block: Block) -> &BlockData {
530        &self.blocks[block.index()]
531    }
532}
533
534impl Index<Sig> for Func {
535    type Output = Signature;
536
537    fn index(&self, sig: Sig) -> &Signature {
538        &self.signatures[sig.index()]
539    }
540}
541
542impl Index<ValueList> for Func {
543    type Output = [Value];
544
545    fn index(&self, list: ValueList) -> &[Value] {
546        &self.value_pool[list.as_usize_range()]
547    }
548}
549
550impl Index<BlockCallList> for Func {
551    type Output = [BlockCall];
552
553    fn index(&self, list: BlockCallList) -> &[BlockCall] {
554        &self.block_calls[list.as_usize_range()]
555    }
556}
557
558impl Index<Idx<BlockCall>> for Func {
559    type Output = BlockCall;
560
561    fn index(&self, at: Idx<BlockCall>) -> &BlockCall {
562        &self.block_calls[at.index()]
563    }
564}
565
566impl Index<ImmList> for Func {
567    type Output = [Imm];
568
569    fn index(&self, list: ImmList) -> &[Imm] {
570        &self.imms[list.as_usize_range()]
571    }
572}
573
574impl Index<Idx<Imm>> for Func {
575    type Output = Imm;
576
577    fn index(&self, at: Idx<Imm>) -> &Imm {
578        &self.imms[at.index()]
579    }
580}
581
582impl Index<Idx<MemInfo>> for Func {
583    type Output = MemInfo;
584
585    fn index(&self, at: Idx<MemInfo>) -> &MemInfo {
586        &self.mem[at.index()]
587    }
588}
589
590impl Index<AbiList> for Func {
591    type Output = [Abi];
592
593    fn index(&self, list: AbiList) -> &[Abi] {
594        &self.abis[list.as_usize_range()]
595    }
596}
597
598impl Index<Idx<CallInfo>> for Func {
599    type Output = CallInfo;
600
601    fn index(&self, at: Idx<CallInfo>) -> &CallInfo {
602        &self.calls[at.index()]
603    }
604}
605
606impl Index<Idx<SwitchInfo>> for Func {
607    type Output = SwitchInfo;
608
609    fn index(&self, at: Idx<SwitchInfo>) -> &SwitchInfo {
610        &self.switches[at.index()]
611    }
612}
613
614impl Index<Idx<AsmInfo>> for Func {
615    type Output = AsmInfo;
616
617    fn index(&self, at: Idx<AsmInfo>) -> &AsmInfo {
618        &self.asms[at.index()]
619    }
620}
621
622/// A cursor that appends to the end of one block.
623///
624/// This is the shape lowering wants: it works on one block at a time, it appends, and it wants
625/// the value back so it can use it in the next instruction. Everything here is a thin wrapper
626/// over [`Func::create_inst`] and [`Func::append_inst`], and anything the wrappers do not
627/// cover is done with those two directly.
628#[derive(Debug)]
629pub struct Builder<'a> {
630    func: &'a mut Func,
631    block: Block,
632    span: Span,
633}
634
635impl<'a> Builder<'a> {
636    /// A cursor appending to that block, with every instruction taking that source location.
637    pub fn new(func: &'a mut Func, block: Block) -> Self {
638        Self { func, block, span: Span::DUMMY }
639    }
640
641    /// The same cursor, with a source location for the instructions after this.
642    #[must_use]
643    pub fn at(mut self, span: Span) -> Self {
644        self.span = span;
645        self
646    }
647
648    /// Sets the source location for the instructions after this.
649    pub fn set_span(&mut self, span: Span) {
650        self.span = span;
651    }
652
653    /// The function being built.
654    pub fn func(&mut self) -> &mut Func {
655        self.func
656    }
657
658    /// The block being appended to.
659    #[must_use]
660    pub fn block(&self) -> Block {
661        self.block
662    }
663
664    /// Appends an instruction as it is, and gives back its results.
665    pub fn inst(&mut self, data: InstData, results: &[Type]) -> Inst {
666        let inst = self.func.create_inst(data, results, self.span);
667        self.func.append_inst(self.block, inst);
668        inst
669    }
670
671    /// The one value an instruction produces.
672    ///
673    /// # Panics
674    ///
675    /// Panics if it did not produce exactly one.
676    pub fn value(&mut self, data: InstData, ty: Type) -> Value {
677        let inst = self.inst(data, &[ty]);
678        self.func[inst].first_result.expect("one result was asked for")
679    }
680
681    /// An integer constant.
682    ///
683    /// # Panics
684    ///
685    /// Panics if `ty` is not an integer type.
686    pub fn iconst(&mut self, ty: Type, value: i128) -> Value {
687        let imm = self.func.add_imm(Imm::int(value, ty.lane()));
688        self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::IConst) }, ty)
689    }
690
691    /// A floating point constant, given as the bits of its format.
692    pub fn fconst(&mut self, ty: Type, bits: u128) -> Value {
693        let imm = self.func.add_imm(Imm::from_bits(bits));
694        self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::FConst) }, ty)
695    }
696
697    /// A two-operand instruction whose result has the type of its operands.
698    pub fn binary(&mut self, opcode: Opcode, lhs: Value, rhs: Value, flags: Flags) -> Value {
699        let ty = self.func[lhs].ty;
700        let args = self.func.push_values(&[lhs, rhs]);
701        self.value(InstData { args, flags, ..InstData::new(opcode) }, ty)
702    }
703
704    /// A one-operand instruction whose result has the type given.
705    pub fn unary(&mut self, opcode: Opcode, arg: Value, ty: Type) -> Value {
706        let args = self.func.push_values(&[arg]);
707        self.value(InstData { args, ..InstData::new(opcode) }, ty)
708    }
709
710    /// An integer comparison, which produces one `i1` per lane.
711    pub fn icmp(&mut self, pred: IntPred, lhs: Value, rhs: Value) -> Value {
712        let ty = self.func[lhs].ty.with_lane(Type::I1);
713        let args = self.func.push_values(&[lhs, rhs]);
714        self.value(
715            InstData { args, extra: Extra::IntPred(pred), ..InstData::new(Opcode::ICmp) },
716            ty,
717        )
718    }
719
720    /// A floating point comparison, which produces one `i1` per lane.
721    pub fn fcmp(&mut self, pred: FloatPred, lhs: Value, rhs: Value, flags: Flags) -> Value {
722        let ty = self.func[lhs].ty.with_lane(Type::I1);
723        let args = self.func.push_values(&[lhs, rhs]);
724        self.value(
725            InstData { args, flags, extra: Extra::FloatPred(pred), ..InstData::new(Opcode::FCmp) },
726            ty,
727        )
728    }
729
730    /// A read of that type from that address.
731    pub fn load(&mut self, ty: Type, addr: Value, info: MemInfo, flags: Flags) -> Value {
732        let mem = self.func.add_mem(info);
733        let args = self.func.push_values(&[addr]);
734        self.value(
735            InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Load) },
736            ty,
737        )
738    }
739
740    /// A write of a value to an address.
741    pub fn store(&mut self, value: Value, addr: Value, info: MemInfo, flags: Flags) -> Inst {
742        let mem = self.func.add_mem(info);
743        let args = self.func.push_values(&[value, addr]);
744        self.inst(
745            InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Store) },
746            &[],
747        )
748    }
749
750    /// An unconditional branch.
751    pub fn jump(&mut self, target: Block, args: &[Value]) -> Inst {
752        let call = self.block_call(target, args);
753        let targets = self.func.push_block_calls(&[call]);
754        self.inst(InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::Jump) }, &[])
755    }
756
757    /// The address of a block, which is a value a later `indirect_br` can branch to.
758    ///
759    /// The block is a target here in the same sense a branch's is, so everything that asks an
760    /// instruction which blocks it names finds this one, and a block whose address is taken is
761    /// not mistaken for a block nothing mentions.
762    pub fn block_addr(&mut self, target: Block) -> Value {
763        let call = self.block_call(target, &[]);
764        let targets = self.func.push_block_calls(&[call]);
765        self.value(
766            InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::BlockAddr) },
767            Type::PTR,
768        )
769    }
770
771    /// A branch to an address, which arrives at one of the blocks listed.
772    ///
773    /// Every block the address can hold has to be there. The list is what the rest of the
774    /// compiler reads, so a block left out of it is a block the branch is saying it never
775    /// reaches, and none of it is checked against the addresses anybody took.
776    pub fn indirect_br(&mut self, addr: Value, targets: &[Block]) -> Inst {
777        let calls: Vec<BlockCall> =
778            targets.iter().map(|&target| self.block_call(target, &[])).collect();
779        let targets = self.func.push_block_calls(&calls);
780        let args = self.func.push_values(&[addr]);
781        self.inst(
782            InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::IndirectBr) },
783            &[],
784        )
785    }
786
787    /// A two-way branch, taking the first target when the condition is one.
788    pub fn br_if(
789        &mut self,
790        cond: Value,
791        then_block: Block,
792        then_args: &[Value],
793        else_block: Block,
794        else_args: &[Value],
795    ) -> Inst {
796        let then_call = self.block_call(then_block, then_args);
797        let else_call = self.block_call(else_block, else_args);
798        let targets = self.func.push_block_calls(&[then_call, else_call]);
799        let args = self.func.push_values(&[cond]);
800        self.inst(
801            InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::BrIf) },
802            &[],
803        )
804    }
805
806    /// A branch on an integer, taking the target its value selects and the default when it
807    /// selects none.
808    ///
809    /// The cases are values and blocks rather than a table with the default in it, because the
810    /// order the side table wants, which is the default first, is not an order anybody building
811    /// a `switch` has their cases in.
812    pub fn switch(&mut self, value: Value, default: Block, cases: &[(i128, Block)]) -> Inst {
813        let ty = self.func[value].ty.lane();
814        let mut calls = vec![self.block_call(default, &[])];
815        let mut values = Vec::with_capacity(cases.len());
816        for &(value, block) in cases {
817            calls.push(self.block_call(block, &[]));
818            values.push(Imm::int(value, ty));
819        }
820        let targets = self.func.push_block_calls(&calls);
821        let cases = self.func.push_imms(&values);
822        let info = self.func.add_switch(SwitchInfo { targets, cases });
823        let args = self.func.push_values(&[value]);
824        self.inst(
825            InstData { args, extra: Extra::Switch(info), ..InstData::new(Opcode::Switch) },
826            &[],
827        )
828    }
829
830    /// A return of the values the signature says.
831    pub fn ret(&mut self, values: &[Value]) -> Inst {
832        let args = self.func.push_values(values);
833        self.inst(InstData { args, ..InstData::new(Opcode::Return) }, &[])
834    }
835
836    /// A place control does not reach.
837    pub fn unreachable(&mut self) -> Inst {
838        self.inst(InstData::new(Opcode::Unreachable), &[])
839    }
840
841    /// A direct call, with the results its signature says it produces.
842    pub fn call(&mut self, callee: Symbol, signature: Sig, args: &[Value]) -> Inst {
843        self.call_varargs(callee, signature, args, &[])
844    }
845
846    /// The same, saying how the arguments the signature does not name travel.
847    ///
848    /// Empty says they all travel as the values in hand, which is what [`Builder::call`] passes
849    /// and is the usual case. Anything else has one entry for each argument past the ones the
850    /// signature names.
851    pub fn call_varargs(
852        &mut self,
853        callee: Symbol,
854        signature: Sig,
855        args: &[Value],
856        varargs: &[Abi],
857    ) -> Inst {
858        let varargs = self.func.push_abis(varargs);
859        let info = self.func.add_call(CallInfo { callee: Some(callee), signature, varargs });
860        let returns: Vec<Type> = self.func[signature].return_types().collect();
861        let args = self.func.push_values(args);
862        self.inst(
863            InstData { args, extra: Extra::Call(info), ..InstData::new(Opcode::Call) },
864            &returns,
865        )
866    }
867
868    /// Inline assembly, which is a terminator when the info carries targets.
869    ///
870    /// The targets are built by the caller, because the frontend is the only thing that knows
871    /// which block is the one control reaches when the assembly does not jump, and that block
872    /// has to come first.
873    pub fn inline_asm(
874        &mut self,
875        info: AsmInfo,
876        args: &[Value],
877        results: &[Type],
878        flags: Flags,
879    ) -> Inst {
880        let info = self.func.add_asm(info);
881        let args = self.func.push_values(args);
882        self.inst(
883            InstData { args, flags, extra: Extra::Asm(info), ..InstData::new(Opcode::InlineAsm) },
884            results,
885        )
886    }
887
888    fn block_call(&mut self, block: Block, args: &[Value]) -> BlockCall {
889        BlockCall { block, args: self.func.push_values(args) }
890    }
891}
892
893#[cfg(test)]
894mod tests {
895    use rucc_base::Interner;
896
897    use super::*;
898    use crate::MemOrder;
899    use crate::inst::BlockCallList;
900
901    /// The example from the spec, near enough: a loop that sums one to n and stores it.
902    fn sum() -> (Func, Block, Block, Block) {
903        let mut names = Interner::new();
904        let i32_ = Type::int(32);
905        let mut func = Func::new(
906            names.intern("sum"),
907            Signature::new().with_params(&[i32_]).with_returns(&[i32_]),
908        );
909
910        let entry = func.create_block();
911        let n = func.append_param(entry, i32_);
912        let header = func.create_block();
913        let acc = func.append_param(header, i32_);
914        let i = func.append_param(header, i32_);
915        let exit = func.create_block();
916        let result = func.append_param(exit, i32_);
917
918        let mut b = Builder::new(&mut func, entry);
919        let zero = b.iconst(i32_, 0);
920        let cmp = b.icmp(IntPred::Sle, n, zero);
921        b.br_if(cmp, exit, &[zero], header, &[zero, zero]);
922
923        let mut b = Builder::new(&mut func, header);
924        let one = b.iconst(i32_, 1);
925        let next = b.binary(Opcode::Add, i, one, Flags::NSW);
926        let total = b.binary(Opcode::Add, acc, next, Flags::NSW);
927        let done = b.icmp(IntPred::Sge, next, n);
928        b.br_if(done, exit, &[total], header, &[total, next]);
929
930        let mut b = Builder::new(&mut func, exit);
931        b.ret(&[result]);
932
933        (func, entry, header, exit)
934    }
935
936    #[test]
937    fn the_blocks_come_back_in_the_order_they_were_made() {
938        let (func, entry, header, exit) = sum();
939        assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, header, exit]);
940        assert_eq!(func.entry(), Some(entry));
941    }
942
943    #[test]
944    fn a_removed_block_is_gone_from_the_layout_and_so_is_what_was_in_it() {
945        let (mut func, entry, header, exit) = sum();
946        let inside: Vec<Inst> = func.insts(header).collect();
947        func.remove_block(header);
948        assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, exit]);
949        assert_eq!(func.entry(), Some(entry));
950        assert_eq!(func[entry].next, Some(exit));
951        assert_eq!(func[exit].prev, Some(entry));
952        // The instructions say they are in no block, the way a removed one does.
953        assert!(inside.iter().all(|&inst| func.block_of(inst).is_none()));
954        assert!(func.insts(header).next().is_none());
955    }
956
957    #[test]
958    fn each_block_holds_what_was_appended_to_it() {
959        let (func, entry, header, exit) = sum();
960        let opcodes =
961            |block| func.insts(block).map(|inst| func[inst].opcode.name()).collect::<Vec<_>>();
962        assert_eq!(opcodes(entry), ["iconst", "icmp", "br_if"]);
963        assert_eq!(opcodes(header), ["iconst", "add", "add", "icmp", "br_if"]);
964        assert_eq!(opcodes(exit), ["return"]);
965    }
966
967    #[test]
968    fn asm_ends_a_block_when_it_has_labels_and_not_otherwise() {
969        // The labels are in the function's table, so the instruction on its own cannot answer
970        // and anything asking it rather than the function would walk off the end of the block.
971        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
972        let block = func.create_block();
973        let plain = func.add_asm(AsmInfo {
974            template: Symbol::from_raw(0),
975            constraints: Symbol::from_raw(0),
976            clobbers: Symbol::from_raw(0),
977            targets: BlockCallList::EMPTY,
978        });
979        let call = BlockCall { block, args: ValueList::EMPTY };
980        let targets = func.push_block_calls(&[call]);
981        let labelled = func.add_asm(AsmInfo {
982            template: Symbol::from_raw(0),
983            constraints: Symbol::from_raw(0),
984            clobbers: Symbol::from_raw(0),
985            targets,
986        });
987
988        let mut make = |extra| {
989            let data = InstData { extra, ..InstData::new(Opcode::InlineAsm) };
990            func.create_inst(data, &[], Span::DUMMY)
991        };
992        let plain = make(Extra::Asm(plain));
993        let labelled = make(Extra::Asm(labelled));
994        assert!(!func.is_terminator(plain));
995        assert!(func.is_terminator(labelled));
996    }
997
998    #[test]
999    fn every_block_ends_in_its_terminator() {
1000        let (func, entry, header, exit) = sum();
1001        for block in [entry, header, exit] {
1002            let last = func.terminator(block).expect("a terminator");
1003            assert_eq!(Some(last), func.insts(block).last());
1004        }
1005    }
1006
1007    #[test]
1008    fn a_branch_carries_the_arguments_the_block_takes() {
1009        let (func, entry, header, _) = sum();
1010        let br = func.terminator(entry).expect("a terminator");
1011        let calls: Vec<BlockCall> = func.successors(br).collect();
1012        assert_eq!(calls.len(), 2);
1013        // The loop header takes two parameters, so the branch to it passes two.
1014        assert_eq!(calls[1].block, header);
1015        assert_eq!(func[calls[1].args].len(), 2);
1016        assert_eq!(func[header].params.len(), 2);
1017        assert_eq!(func[calls[0].args].len(), 1);
1018    }
1019
1020    #[test]
1021    fn a_value_knows_what_defined_it() {
1022        let (func, entry, _, _) = sum();
1023        let first = func.insts(entry).next().expect("an instruction");
1024        let value = func[first].first_result.expect("a result");
1025        assert_eq!(func[value].def, Def::Result { inst: first, index: 0 });
1026        assert_eq!(func[value].ty, Type::int(32));
1027
1028        let param = func[entry].params[0];
1029        assert_eq!(func[param].def, Def::Param { block: entry, index: 0 });
1030    }
1031
1032    #[test]
1033    fn a_comparison_produces_one_bit() {
1034        let (func, entry, _, _) = sum();
1035        let cmp = func.insts(entry).nth(1).expect("the comparison");
1036        let value = func[cmp].first_result.expect("a result");
1037        assert_eq!(func[value].ty, Type::I1);
1038        assert_eq!(func[cmp].extra, Extra::IntPred(IntPred::Sle));
1039    }
1040
1041    #[test]
1042    fn flags_ride_along_on_the_instruction_that_was_given_them() {
1043        let (func, _, header, _) = sum();
1044        let add = func.insts(header).nth(1).expect("the addition");
1045        assert_eq!(func[add].flags, Flags::NSW);
1046        let cmp = func.insts(header).nth(3).expect("the comparison");
1047        assert_eq!(func[cmp].flags, Flags::NONE);
1048    }
1049
1050    #[test]
1051    fn removing_an_instruction_takes_it_out_of_the_middle() {
1052        let (mut func, _, header, _) = sum();
1053        let add = func.insts(header).nth(1).expect("the addition");
1054        func.remove_inst(add);
1055        let opcodes: Vec<&str> = func.insts(header).map(|inst| func[inst].opcode.name()).collect();
1056        assert_eq!(opcodes, ["iconst", "add", "icmp", "br_if"]);
1057        assert_eq!(func.block_of(add), None);
1058    }
1059
1060    #[test]
1061    fn removing_the_first_and_the_last_keeps_the_ends_right() {
1062        let (mut func, entry, _, _) = sum();
1063        let first = func.insts(entry).next().expect("an instruction");
1064        let last = func.terminator(entry).expect("a terminator");
1065        func.remove_inst(first);
1066        func.remove_inst(last);
1067        let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1068        assert_eq!(opcodes, ["icmp"]);
1069        assert_eq!(func[entry].first, func[entry].last);
1070    }
1071
1072    #[test]
1073    fn removing_the_only_instruction_empties_the_block() {
1074        let (mut func, _, _, exit) = sum();
1075        let only = func.insts(exit).next().expect("an instruction");
1076        func.remove_inst(only);
1077        assert_eq!(func.insts(exit).count(), 0);
1078        assert_eq!(func[exit].first, None);
1079        assert_eq!(func[exit].last, None);
1080    }
1081
1082    #[test]
1083    fn inserting_before_puts_it_in_the_right_place() {
1084        let (mut func, entry, _, _) = sum();
1085        let cmp = func.insts(entry).nth(1).expect("the comparison");
1086        let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1087        func.insert_before(made, cmp);
1088        let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1089        assert_eq!(opcodes, ["iconst", "unreachable", "icmp", "br_if"]);
1090    }
1091
1092    #[test]
1093    fn inserting_before_the_first_makes_it_the_first() {
1094        let (mut func, entry, _, _) = sum();
1095        let first = func.insts(entry).next().expect("an instruction");
1096        let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1097        func.insert_before(made, first);
1098        assert_eq!(func.insts(entry).next(), Some(made));
1099        assert_eq!(func[entry].first, Some(made));
1100    }
1101
1102    #[test]
1103    fn a_list_grows_in_place_while_it_is_the_last_thing_in_the_pool() {
1104        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1105        let block = func.create_block();
1106        let a = func.append_param(block, Type::int(32));
1107        let b = func.append_param(block, Type::int(32));
1108        let list = func.push_values(&[a]);
1109        let grown = func.append_arg(list, b);
1110        assert_eq!(func[grown], [a, b]);
1111        assert_eq!(grown.as_usize_range().start, list.as_usize_range().start);
1112    }
1113
1114    #[test]
1115    fn a_list_is_copied_when_something_is_behind_it() {
1116        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1117        let block = func.create_block();
1118        let a = func.append_param(block, Type::int(32));
1119        let b = func.append_param(block, Type::int(32));
1120        let list = func.push_values(&[a, a]);
1121        let behind = func.push_values(&[b]);
1122        let grown = func.append_arg(list, b);
1123        assert_eq!(func[grown], [a, a, b]);
1124        assert_eq!(func[list], [a, a], "the old run is still readable");
1125        assert_eq!(func[behind], [b], "and so is what was behind it");
1126        assert_ne!(grown.as_usize_range().start, list.as_usize_range().start);
1127    }
1128
1129    #[test]
1130    fn a_parameter_added_late_is_the_next_one_along() {
1131        // This is the shape SSA construction leaves: the loop header gains a parameter after
1132        // the blocks that branch to it already exist, and each of their branches grows an
1133        // argument to match.
1134        let (mut func, entry, header, _) = sum();
1135        let extra = func.append_param(header, Type::int(32));
1136        assert_eq!(func[header].params.len(), 3);
1137        assert_eq!(func[extra].def, Def::Param { block: header, index: 2 });
1138
1139        let br = func.terminator(entry).expect("a terminator");
1140        let call = func.successors(br).nth(1).expect("the branch to the header");
1141        let grown = func.append_arg(call.args, extra);
1142        assert_eq!(func[grown].len(), 3);
1143    }
1144
1145    #[test]
1146    fn a_span_rides_along_with_the_instruction() {
1147        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1148        let block = func.create_block();
1149        let span = Span::new(10, 20);
1150        let mut b = Builder::new(&mut func, block).at(span);
1151        let value = b.iconst(Type::int(32), 7);
1152        let inst = match func[value].def {
1153            Def::Result { inst, .. } => inst,
1154            Def::Param { .. } => unreachable!("a constant is not a parameter"),
1155        };
1156        assert_eq!(func.span(inst), span);
1157    }
1158
1159    #[test]
1160    fn a_store_produces_nothing_and_a_load_produces_one_value() {
1161        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1162        let block = func.create_block();
1163        let addr = func.append_param(block, Type::PTR);
1164        let info = MemInfo { size: 4, align: 4, order: MemOrder::NotAtomic, tbaa: None };
1165        let mut b = Builder::new(&mut func, block);
1166        let value = b.load(Type::int(32), addr, info, Flags::NONE);
1167        let store = b.store(value, addr, info, Flags::VOLATILE);
1168        assert_eq!(func[store].results, 0);
1169        assert_eq!(func[store].flags, Flags::VOLATILE);
1170        assert_eq!(func[value].ty, Type::int(32));
1171    }
1172
1173    #[test]
1174    fn a_call_produces_what_its_signature_returns() {
1175        let mut names = Interner::new();
1176        let mut func = Func::new(names.intern("caller"), Signature::new());
1177        let sig = func.add_signature(
1178            Signature::new().with_params(&[Type::int(32)]).with_returns(&[Type::int(64)]),
1179        );
1180        let block = func.create_block();
1181        let arg = func.append_param(block, Type::int(32));
1182        let callee = names.intern("callee");
1183        let mut b = Builder::new(&mut func, block);
1184        let call = b.call(callee, sig, &[arg]);
1185        assert_eq!(func[call].results, 1);
1186        let value = func[call].first_result.expect("a result");
1187        assert_eq!(func[value].ty, Type::int(64));
1188        assert_eq!(func[call].extra, Extra::Call(Idx::new(0)));
1189    }
1190
1191    #[test]
1192    fn the_counts_are_what_was_made() {
1193        let (func, _, _, _) = sum();
1194        let counts = func.counts();
1195        assert_eq!(counts.blocks, 3);
1196        assert_eq!(counts.insts, 9);
1197        // Four block parameters and five instruction results, which is the two constants, the
1198        // two additions and the two comparisons less the branches, which produce nothing.
1199        assert_eq!(counts.values, 4 + 6);
1200    }
1201
1202    #[test]
1203    #[should_panic(expected = "the instruction is in a block")]
1204    fn appending_an_instruction_twice_is_refused() {
1205        let (mut func, entry, _, _) = sum();
1206        let first = func.insts(entry).next().expect("an instruction");
1207        func.append_inst(entry, first);
1208    }
1209
1210    #[test]
1211    #[should_panic(expected = "the instruction is not in a block")]
1212    fn removing_an_instruction_twice_is_refused() {
1213        let (mut func, entry, _, _) = sum();
1214        let first = func.insts(entry).next().expect("an instruction");
1215        func.remove_inst(first);
1216        func.remove_inst(first);
1217    }
1218}