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;
33use rucc_target::Slot;
34
35use crate::inst::{
36    Abi, AbiList, AsmInfo, Block, BlockCall, BlockCallList, BlockData, CallInfo, Def, Extra, Imm,
37    ImmList, Inst, InstData, InstLayout, MemInfo, Sig, Signature, SlotList, SwitchInfo, VaInfo,
38    Value, ValueData, ValueList,
39};
40use crate::module::{Linkage, Visibility};
41use crate::{Attrs, Facts, Flags, FloatPred, IntPred, MemOrder, Opcode, PrefetchHint, RmwOp, Type};
42
43/// One function.
44#[derive(Debug)]
45pub struct Func {
46    /// The name it is called by, which is what a direct call to it names.
47    pub name: Symbol,
48    /// How the linker sees it. `Internal` for a `static` function.
49    pub linkage: Linkage,
50    /// How the dynamic linker sees it.
51    pub visibility: Visibility,
52    /// The section to put it in, from `__attribute__((section(...)))`, or `None` to let the
53    /// object writer choose.
54    pub section: Option<Symbol>,
55    /// What its first instruction has to be aligned to, from `__attribute__((aligned(...)))`, or
56    /// `None` for the alignment the target gives every function anyway.
57    ///
58    /// A raise and never a lower, the way the attribute is everywhere: a function asked to be at
59    /// a multiple of two hundred and fifty six is at one, and one asked for less than the target's
60    /// own alignment keeps the target's.
61    pub align: Option<u32>,
62    /// What is true of the whole function, which is what a caller reads when it wants to know
63    /// what a call to it does without looking inside.
64    pub attrs: Attrs,
65
66    values: Vec<ValueData>,
67    insts: Vec<InstData>,
68    inst_layout: Vec<InstLayout>,
69    inst_spans: Vec<Span>,
70    blocks: Vec<BlockData>,
71
72    value_pool: Vec<Value>,
73    block_calls: Vec<BlockCall>,
74    imms: Vec<Imm>,
75    mem: Vec<MemInfo>,
76    calls: Vec<CallInfo>,
77    abis: Vec<Abi>,
78    switches: Vec<SwitchInfo>,
79    asms: Vec<AsmInfo>,
80    slots: Vec<Slot>,
81    va_objects: Vec<VaInfo>,
82    signatures: Vec<Signature>,
83    facts: Vec<(Value, Facts)>,
84    labels: Vec<(Block, Symbol)>,
85
86    first_block: Option<Block>,
87    last_block: Option<Block>,
88}
89
90impl Func {
91    /// A function with that name and that signature, and nothing in it.
92    ///
93    /// The signature becomes signature zero, which is what [`Func::signature`] gives back. The
94    /// entry block is not created here, because the caller is about to create it and give it
95    /// the parameters, and a half-built entry block is worse than no entry block. So a
96    /// function fresh from here is a declaration, and stops being one when it gets a block.
97    #[must_use]
98    pub fn new(name: Symbol, signature: Signature) -> Self {
99        Self {
100            name,
101            linkage: Linkage::External,
102            visibility: Visibility::Default,
103            section: None,
104            align: None,
105            attrs: Attrs::NONE,
106            values: Vec::new(),
107            insts: Vec::new(),
108            inst_layout: Vec::new(),
109            inst_spans: Vec::new(),
110            blocks: Vec::new(),
111            value_pool: Vec::new(),
112            block_calls: Vec::new(),
113            imms: Vec::new(),
114            mem: Vec::new(),
115            calls: Vec::new(),
116            abis: Vec::new(),
117            switches: Vec::new(),
118            asms: Vec::new(),
119            slots: Vec::new(),
120            va_objects: Vec::new(),
121            signatures: vec![signature],
122            facts: Vec::new(),
123            labels: Vec::new(),
124            first_block: None,
125            last_block: None,
126        }
127    }
128
129    /// Its own signature.
130    #[must_use]
131    pub fn signature(&self) -> &Signature {
132        &self.signatures[0]
133    }
134
135    /// Gives the function a different signature of its own.
136    ///
137    /// There is one caller and it is the back end pass that puts an integer the machine has no
138    /// register for into the pair of registers it travels in. A parameter that becomes two is a
139    /// parameter list that is not the one the function was created with, and the entry block's
140    /// parameters have to say the same thing, which is why this is next to
141    /// [`Func::retain_params`] in what a pass has to keep straight rather than something the
142    /// middle end reaches for. Nothing else changes a function's own signature, because a
143    /// signature is what its callers were compiled against.
144    pub fn set_signature(&mut self, signature: Signature) {
145        self.signatures[0] = signature;
146    }
147
148    /// Every signature the function holds, its own first and then the ones its calls name.
149    pub fn signatures(&self) -> impl Iterator<Item = &Signature> {
150        self.signatures.iter()
151    }
152
153    /// Records a signature a `call_indirect` is made with, and gives back its index.
154    pub fn add_signature(&mut self, signature: Signature) -> Sig {
155        self.signatures.push(signature);
156        Idx::from_usize(self.signatures.len() - 1)
157    }
158
159    /// The entry block, which is the first one in layout order.
160    ///
161    /// `None` only before one has been created. The verifier is what insists a finished
162    /// function has one.
163    #[must_use]
164    pub fn entry(&self) -> Option<Block> {
165        self.first_block
166    }
167
168    /// Whether this only says the function exists somewhere, which is a function with no
169    /// blocks in it.
170    ///
171    /// `extern int puts(const char *);` and every other declaration of something defined in
172    /// another object is one of these, and it is here rather than left out of the module
173    /// because a call needs its signature and its linkage.
174    #[must_use]
175    pub fn is_declaration(&self) -> bool {
176        self.first_block.is_none()
177    }
178
179    // Blocks.
180
181    /// Creates a block with no parameters and no instructions, at the end of the layout.
182    pub fn create_block(&mut self) -> Block {
183        let block = Idx::from_usize(self.blocks.len());
184        self.blocks.push(BlockData { prev: self.last_block, ..BlockData::default() });
185        match self.last_block {
186            Some(last) => self.blocks[last.index()].next = Some(block),
187            None => self.first_block = Some(block),
188        }
189        self.last_block = Some(block);
190        block
191    }
192
193    /// Takes a block out of the layout, along with everything in it.
194    ///
195    /// The block keeps its number, the way a removed instruction keeps its own, because
196    /// renumbering would move every block after it and invalidate every index anybody was
197    /// holding. What it stops being is a block of this function: nothing walks it, nothing
198    /// prints it, and the values defined in it are as gone as the instructions that defined
199    /// them. Deleting one whose branches something still reaches is how a function ends up
200    /// branching to nowhere, so the caller is the one that has to know nothing reaches it.
201    ///
202    /// # Panics
203    ///
204    /// Panics if the block is the entry block, which is the one block a function has to have.
205    pub fn remove_block(&mut self, block: Block) {
206        assert!(self.first_block != Some(block), "the entry block is not removable");
207        let (prev, next) = (self.blocks[block.index()].prev, self.blocks[block.index()].next);
208        match prev {
209            Some(prev) => self.blocks[prev.index()].next = next,
210            None => self.first_block = next,
211        }
212        match next {
213            Some(next) => self.blocks[next.index()].prev = prev,
214            None => self.last_block = prev,
215        }
216        // The instructions say they are in no block now, which is what a removed instruction
217        // says, so that asking one where it is gives an answer rather than a block nothing
218        // walks.
219        let insts: Vec<Inst> = self.insts(block).collect();
220        for inst in insts {
221            self.inst_layout[inst.index()] = InstLayout::default();
222        }
223        self.blocks[block.index()] = BlockData::default();
224    }
225
226    /// Adds a parameter of that type to a block, and gives back the value it arrives as.
227    ///
228    /// Every predecessor's branch has to grow an argument to match, which is
229    /// [`Func::append_arg`], and the verifier is what notices if one of them did not.
230    ///
231    /// # Panics
232    ///
233    /// Panics if the block already has four billion parameters, which no block does.
234    pub fn append_param(&mut self, block: Block, ty: Type) -> Value {
235        let index = u32::try_from(self.blocks[block.index()].params.len())
236            .expect("a block with four billion parameters");
237        let value = self.add_value(ValueData { ty, def: Def::Param { block, index } });
238        self.blocks[block.index()].params.push(value);
239        value
240    }
241
242    /// Drops the parameters of a block that a predicate turns down, and renumbers the rest.
243    ///
244    /// The predicate is asked about each parameter in the order the block takes them. A
245    /// parameter that goes has to take the argument in the same position out of every branch
246    /// to the block, which is the caller's work rather than this method's, because only the
247    /// caller knows which branches there are. This is what removing a redundant block
248    /// parameter is, and SSA construction is the thing that makes them.
249    ///
250    /// # Panics
251    ///
252    /// Panics if the block has four billion parameters, which no block does.
253    pub fn retain_params(&mut self, block: Block, mut keep: impl FnMut(Value) -> bool) {
254        let mut params = std::mem::take(&mut self.blocks[block.index()].params);
255        params.retain(|&value| keep(value));
256        for (index, &value) in params.iter().enumerate() {
257            let index = u32::try_from(index).expect("a block with four billion parameters");
258            self.values[value.index()].def = Def::Param { block, index };
259        }
260        self.blocks[block.index()].params = params;
261    }
262
263    /// Gives a value a different type, leaving where it comes from alone.
264    ///
265    /// There is one caller and it is the back end pass that puts an integer of a width the
266    /// machine has no register for into the width it does have one for. Nothing in the middle
267    /// end changes a value's type, because a value's type is what the instruction that made it
268    /// produces and changing one without changing the other is how an IR stops meaning
269    /// anything. That pass changes both, which is why this is a method and not a field.
270    ///
271    /// # Panics
272    ///
273    /// Panics if the value is not one of this function's.
274    pub fn retype(&mut self, value: Value, ty: Type) {
275        self.values[value.index()].ty = ty;
276    }
277
278    /// Every value the function has, including ones whose defining instruction has gone.
279    ///
280    /// In the order they were created, which is the order a pass that walks all of them wants:
281    /// a value is defined before it is used, so a walk in this order sees a definition first.
282    pub fn values(&self) -> impl Iterator<Item = Value> + use<'_> {
283        (0..self.values.len()).map(Idx::from_usize)
284    }
285
286    /// Every block, in layout order.
287    pub fn blocks(&self) -> impl Iterator<Item = Block> + use<'_> {
288        std::iter::successors(self.first_block, move |&block| self.blocks[block.index()].next)
289    }
290
291    /// Every instruction in a block, in order.
292    pub fn insts(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_> {
293        std::iter::successors(self.blocks[block.index()].first, move |&inst| {
294            self.inst_layout[inst.index()].next
295        })
296    }
297
298    /// Every instruction in a block, last first.
299    ///
300    /// Which is the order a liveness walk needs, and it is here rather than at the caller because
301    /// the layout links are private and collecting the block into a vector to reverse it is an
302    /// allocation per block per round of a fixpoint.
303    pub fn insts_backwards(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_> {
304        std::iter::successors(self.blocks[block.index()].last, move |&inst| {
305            self.inst_layout[inst.index()].prev
306        })
307    }
308
309    /// The last instruction of a block, which is its terminator once it is finished.
310    #[must_use]
311    pub fn terminator(&self, block: Block) -> Option<Inst> {
312        self.blocks[block.index()].last.filter(|&inst| self.is_terminator(inst))
313    }
314
315    /// Whether control leaves the block at this instruction.
316    ///
317    /// A question for the function rather than for the instruction, because inline assembly is
318    /// the one case where the opcode is not enough: `asm goto` has labels and everything else
319    /// does not, and the labels are in the function's table rather than on the instruction.
320    #[must_use]
321    pub fn is_terminator(&self, inst: Inst) -> bool {
322        let data = &self[inst];
323        match data.extra {
324            Extra::Asm(info) => {
325                data.opcode.is_terminator() || !self.asms[info.index()].targets.is_empty()
326            }
327            _ => data.opcode.is_terminator(),
328        }
329    }
330
331    // Instructions.
332
333    /// Creates an instruction and its result values, without putting it in a block.
334    ///
335    /// The results are allocated here and are contiguous, which is what lets an instruction
336    /// hold the first of them and a count rather than a list.
337    ///
338    /// # Panics
339    ///
340    /// Panics if `results` has more than 255 types, which no instruction in the set does.
341    pub fn create_inst(&mut self, mut data: InstData, results: &[Type], span: Span) -> Inst {
342        let inst = Idx::from_usize(self.insts.len());
343        data.results = u8::try_from(results.len()).expect("an instruction with too many results");
344        data.first_result = results.first().map(|_| Idx::from_usize(self.values.len()));
345        for (index, &ty) in results.iter().enumerate() {
346            let index = u8::try_from(index).expect("checked just above");
347            self.add_value(ValueData { ty, def: Def::Result { inst, index } });
348        }
349        self.insts.push(data);
350        self.inst_layout.push(InstLayout::default());
351        self.inst_spans.push(span);
352        inst
353    }
354
355    /// Puts an instruction at the end of a block.
356    ///
357    /// # Panics
358    ///
359    /// Panics if the instruction is already in a block. Moving one is removing it and
360    /// appending it, and doing it by accident is how a linked list ends up in two pieces.
361    pub fn append_inst(&mut self, block: Block, inst: Inst) {
362        assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
363        let last = self.blocks[block.index()].last;
364        self.inst_layout[inst.index()] = InstLayout { block: Some(block), prev: last, next: None };
365        match last {
366            Some(last) => self.inst_layout[last.index()].next = Some(inst),
367            None => self.blocks[block.index()].first = Some(inst),
368        }
369        self.blocks[block.index()].last = Some(inst);
370    }
371
372    /// Puts an instruction immediately before another one, in the block that one is in.
373    ///
374    /// # Panics
375    ///
376    /// Panics if `inst` is already in a block, or if `before` is not in one.
377    pub fn insert_before(&mut self, inst: Inst, before: Inst) {
378        assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
379        let at = self.inst_layout[before.index()];
380        let block = at.block.expect("the instruction to insert before is not in a block");
381        self.inst_layout[inst.index()] =
382            InstLayout { block: Some(block), prev: at.prev, next: Some(before) };
383        self.inst_layout[before.index()].prev = Some(inst);
384        match at.prev {
385            Some(prev) => self.inst_layout[prev.index()].next = Some(inst),
386            None => self.blocks[block.index()].first = Some(inst),
387        }
388    }
389
390    /// Puts an instruction immediately after another one, in the block that one is in.
391    ///
392    /// The mirror of [`Func::insert_before`], and it exists because a pass that has to talk about
393    /// a value an instruction produced has nowhere else to put what it is adding. Check insertion
394    /// is the caller: `check_deriv` is handed the pointer the derivation produced, so it goes
395    /// after the derivation and no amount of rearranging moves it earlier.
396    ///
397    /// # Panics
398    ///
399    /// Panics if `inst` is already in a block, if `after` is not in one, or if `after` is the
400    /// block's terminator, since nothing may come between a terminator and the branch it is.
401    pub fn insert_after(&mut self, inst: Inst, after: Inst) {
402        assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
403        let at = self.inst_layout[after.index()];
404        let block = at.block.expect("the instruction to insert after is not in a block");
405        assert!(at.next.is_some(), "nothing goes after a terminator");
406        self.inst_layout[inst.index()] =
407            InstLayout { block: Some(block), prev: Some(after), next: at.next };
408        self.inst_layout[after.index()].next = Some(inst);
409        if let Some(next) = at.next {
410            self.inst_layout[next.index()].prev = Some(inst);
411        }
412    }
413
414    /// Takes an instruction out of its block, leaving it and its results in the tables.
415    ///
416    /// The instruction is not deleted, because deleting it would move every instruction after
417    /// it. A removed instruction is unreachable from any block and is dropped when the whole
418    /// function is.
419    ///
420    /// # Panics
421    ///
422    /// Panics if the instruction is not in a block.
423    pub fn remove_inst(&mut self, inst: Inst) {
424        let at = self.inst_layout[inst.index()];
425        let block = at.block.expect("the instruction is not in a block");
426        match at.prev {
427            Some(prev) => self.inst_layout[prev.index()].next = at.next,
428            None => self.blocks[block.index()].first = at.next,
429        }
430        match at.next {
431            Some(next) => self.inst_layout[next.index()].prev = at.prev,
432            None => self.blocks[block.index()].last = at.prev,
433        }
434        self.inst_layout[inst.index()] = InstLayout::default();
435    }
436
437    /// The block an instruction is in, or `None` if it has been removed from one.
438    #[must_use]
439    pub fn block_of(&self, inst: Inst) -> Option<Block> {
440        self.inst_layout[inst.index()].block
441    }
442
443    /// The version of memory an instruction reads, when the function carries memory SSA.
444    ///
445    /// Document 09 of `spec/optimizer`. Memory is a value of type `mem`, it is the last operand
446    /// of every instruction that touches memory, and it is absent in a function that does not
447    /// carry it, which is what `-O0` and `-O1` produce. Absent means unordered with respect to
448    /// everything, so a reader that gets `None` asks the alias analysis directly.
449    ///
450    /// The operand is last rather than first on purpose. Every other operand keeps the position
451    /// it had, so a pass that reads the address of a load as `args[0]` goes on working whether
452    /// or not memory has been threaded, and the only code that has to know about the extra
453    /// operand is this accessor and the verifier.
454    #[must_use]
455    pub fn mem_in(&self, inst: Inst) -> Option<Value> {
456        let args = &self[self[inst].args];
457        args.last().copied().filter(|&arg| self[arg].ty.is_mem())
458    }
459
460    /// The version of memory an instruction produces, when it writes memory and the function
461    /// carries memory SSA.
462    ///
463    /// Last among the results, for the reason [`Func::mem_in`] is last among the operands. A
464    /// `load` never has one, because it reads memory without changing it.
465    ///
466    /// Nothing reads the last version in a function, and that means nothing. A store whose
467    /// memory result has no reader is not dead, and what decides whether it is dead is dead
468    /// store elimination, which is document 17's.
469    #[must_use]
470    pub fn mem_out(&self, inst: Inst) -> Option<Value> {
471        self[inst].results().last().filter(|&result| self[result].ty.is_mem())
472    }
473
474    /// Whether an instruction has been threaded onto the memory chain.
475    #[must_use]
476    pub fn carries_mem(&self, inst: Inst) -> bool {
477        self.mem_in(inst).is_some() || self.mem_out(inst).is_some()
478    }
479
480    /// The same instruction with a version of memory threaded through it.
481    ///
482    /// A result cannot be added to an instruction that already exists, because the results of one
483    /// are values next to each other and there is no room after them. So threading memory makes a
484    /// new instruction and the caller puts it where the old one was, forwards the old results to
485    /// the new ones, which are at the same positions, and deletes the old one. That is what memory
486    /// SSA construction does in one pass over the function.
487    ///
488    /// The new instruction is not in any block. Its results are what the old one produced, in the
489    /// same order, and then the new version of memory where the opcode writes memory.
490    ///
491    /// # Panics
492    ///
493    /// Panics if `incoming` is not memory, if the instruction does not touch memory, or if it is
494    /// already on the chain. All three are a construction bug rather than bad input.
495    pub fn with_mem(&mut self, inst: Inst, incoming: Value) -> Inst {
496        assert!(self[incoming].ty.is_mem(), "the incoming version of memory is not memory");
497        assert!(self[inst].opcode.touches_memory(), "this does not touch memory");
498        assert!(self.mem_in(inst).is_none(), "this is already on the memory chain");
499        let data = self[inst];
500        let mut args = self[data.args].to_vec();
501        args.push(incoming);
502        let mut results: Vec<Type> = data.results().map(|result| self[result].ty).collect();
503        if data.opcode.writes_memory() {
504            results.push(Type::MEM);
505        }
506        let span = self.span(inst);
507        let args = self.push_values(&args);
508        self.create_inst(InstData { args, ..data }, &results, span)
509    }
510
511    /// The same instruction with the version of memory taken back off.
512    ///
513    /// The inverse of [`Func::with_mem`] and the same shape for the same reason: a result cannot be
514    /// taken off an instruction that already exists, so this makes a new one and the caller puts it
515    /// where the old one was, forwards the results it kept, which are at the same positions, and
516    /// deletes the old one. The memory result has no forwarding to do, because taking the chain off
517    /// is only ever done when nothing reads it any more.
518    ///
519    /// The new instruction is not in any block. Its results are what the old one produced without
520    /// the version of memory at the end of them.
521    ///
522    /// # Panics
523    ///
524    /// Panics if the instruction is not on the chain, which is a caller that did not look first.
525    pub fn without_mem(&mut self, inst: Inst) -> Inst {
526        assert!(self.carries_mem(inst), "this is not on the memory chain");
527        let data = self[inst];
528        let mut args = self[data.args].to_vec();
529        if self.mem_in(inst).is_some() {
530            args.pop();
531        }
532        let results: Vec<Type> =
533            data.results().map(|result| self[result].ty).filter(|ty| !ty.is_mem()).collect();
534        let span = self.span(inst);
535        let args = self.push_values(&args);
536        self.create_inst(InstData { args, ..data }, &results, span)
537    }
538
539    /// Where an instruction came from in the source.
540    #[must_use]
541    pub fn span(&self, inst: Inst) -> Span {
542        self.inst_spans[inst.index()]
543    }
544
545    /// Where an instruction branches to, which is empty when it does not branch.
546    ///
547    /// This is the one place that knows a `switch` keeps its targets in a side table and
548    /// `asm goto` in another one, so nothing walking the CFG has to.
549    pub fn successors(&self, inst: Inst) -> impl Iterator<Item = BlockCall> + use<'_> {
550        self.block_calls[self.target_list(inst).as_usize_range()].iter().copied()
551    }
552
553    /// Where a terminator keeps its targets, for something that edits them rather than reads
554    /// them.
555    ///
556    /// [`Func::successors`] is what walking the CFG wants. This is what recording an edge
557    /// wants, because an edge that will grow an argument later has to be named by its place in
558    /// the table rather than by the block it went to.
559    #[must_use]
560    pub fn target_list(&self, inst: Inst) -> BlockCallList {
561        match self[inst].extra {
562            Extra::Targets(targets) => targets,
563            Extra::Switch(info) => self.switches[info.index()].targets,
564            Extra::Asm(info) => self.asms[info.index()].targets,
565            _ => BlockCallList::EMPTY,
566        }
567    }
568
569    // The pools.
570
571    /// Records a run of value operands.
572    pub fn push_values(&mut self, values: &[Value]) -> ValueList {
573        let start = Idx::from_usize(self.value_pool.len());
574        self.value_pool.extend_from_slice(values);
575        ValueList::new(start, Idx::from_usize(self.value_pool.len()))
576    }
577
578    /// Adds one value to the end of a run, giving back the run it became.
579    ///
580    /// The run grows in place when nothing has been put after it, which is the case while a
581    /// list is being built. Otherwise it is copied to the end and the old space is left
582    /// behind, which is what makes adding a parameter to a loop header possible at all. That
583    /// happens once per value carried around a loop, so the copying is not what costs.
584    pub fn append_arg(&mut self, list: ValueList, value: Value) -> ValueList {
585        let range = list.as_usize_range();
586        if range.end == self.value_pool.len() {
587            self.value_pool.push(value);
588            return ValueList::new(Idx::from_usize(range.start), Idx::from_usize(range.end + 1));
589        }
590        let start = self.value_pool.len();
591        self.value_pool.extend_from_within(range);
592        self.value_pool.push(value);
593        ValueList::new(Idx::from_usize(start), Idx::from_usize(self.value_pool.len()))
594    }
595
596    /// Replaces the values in a run, which is what substituting one definition for another is.
597    ///
598    /// A run is a run whether it is an instruction's operands or a branch's arguments, so this
599    /// is the whole of the rewriting a substitution has to do.
600    pub fn rewrite(&mut self, list: ValueList, mut with: impl FnMut(Value) -> Value) {
601        for value in &mut self.value_pool[list.as_usize_range()] {
602            *value = with(*value);
603        }
604    }
605
606    /// Records a run of branch targets.
607    pub fn push_block_calls(&mut self, calls: &[BlockCall]) -> BlockCallList {
608        let start = Idx::from_usize(self.block_calls.len());
609        self.block_calls.extend_from_slice(calls);
610        BlockCallList::new(start, Idx::from_usize(self.block_calls.len()))
611    }
612
613    /// Replaces one branch target, which is what redirecting an edge is.
614    pub fn set_block_call(&mut self, at: Idx<BlockCall>, call: BlockCall) {
615        self.block_calls[at.index()] = call;
616    }
617
618    /// Records a run of case values.
619    pub fn push_imms(&mut self, imms: &[Imm]) -> ImmList {
620        let start = Idx::from_usize(self.imms.len());
621        self.imms.extend_from_slice(imms);
622        ImmList::new(start, Idx::from_usize(self.imms.len()))
623    }
624
625    /// Records a constant.
626    pub fn add_imm(&mut self, imm: Imm) -> Idx<Imm> {
627        self.imms.push(imm);
628        Idx::from_usize(self.imms.len() - 1)
629    }
630
631    /// Records where each eightbyte of an object travelled.
632    pub fn push_slots(&mut self, slots: &[Slot]) -> SlotList {
633        let start = Idx::from_usize(self.slots.len());
634        self.slots.extend_from_slice(slots);
635        SlotList::new(start, Idx::from_usize(self.slots.len()))
636    }
637
638    /// Records an object read off a variable argument list.
639    pub fn add_va_object(&mut self, info: VaInfo) -> Idx<VaInfo> {
640        self.va_objects.push(info);
641        Idx::from_usize(self.va_objects.len() - 1)
642    }
643
644    /// Records what an access does.
645    pub fn add_mem(&mut self, info: MemInfo) -> Idx<MemInfo> {
646        self.mem.push(info);
647        Idx::from_usize(self.mem.len() - 1)
648    }
649
650    /// Records what the ABI asks of the arguments a call's signature does not name.
651    pub fn push_abis(&mut self, abis: &[Abi]) -> AbiList {
652        let start = Idx::from_usize(self.abis.len());
653        self.abis.extend_from_slice(abis);
654        AbiList::new(start, Idx::from_usize(self.abis.len()))
655    }
656
657    /// Records a call's callee and signature.
658    pub fn add_call(&mut self, info: CallInfo) -> Idx<CallInfo> {
659        self.calls.push(info);
660        Idx::from_usize(self.calls.len() - 1)
661    }
662
663    /// Records a `switch`'s targets and case values.
664    pub fn add_switch(&mut self, info: SwitchInfo) -> Idx<SwitchInfo> {
665        self.switches.push(info);
666        Idx::from_usize(self.switches.len() - 1)
667    }
668
669    /// Records an inline assembly instruction's template and constraints.
670    pub fn add_asm(&mut self, info: AsmInfo) -> Idx<AsmInfo> {
671        self.asms.push(info);
672        Idx::from_usize(self.asms.len() - 1)
673    }
674
675    /// How many values, instructions and blocks there are, for a reader that wants to size
676    /// something by them.
677    #[must_use]
678    pub fn counts(&self) -> Counts {
679        Counts { values: self.values.len(), insts: self.insts.len(), blocks: self.blocks.len() }
680    }
681
682    /// What is known about a value, which is nothing at all unless somebody said otherwise.
683    ///
684    /// Section 6.2.3 of `spec/safe-memory/06-instrumentation.md`. Facts are in a side table and
685    /// not in the value, so a function nobody has said anything about carries no facts and is
686    /// the same size it was before facts existed.
687    #[must_use]
688    pub fn facts(&self, value: Value) -> Facts {
689        match self.facts.binary_search_by_key(&value.raw(), |&(at, _)| at.raw()) {
690            Ok(at) => self.facts[at].1,
691            Err(_) => Facts::NONE,
692        }
693    }
694
695    /// Says what is known about a value, replacing whatever was known before.
696    ///
697    /// Setting [`Facts::NONE`] takes the value back out of the table, which is what keeps the
698    /// table empty in a function that has had facts put on and then taken off again.
699    pub fn set_facts(&mut self, value: Value, facts: Facts) {
700        let found = self.facts.binary_search_by_key(&value.raw(), |&(at, _)| at.raw());
701        match (found, facts.is_empty()) {
702            (Ok(at), true) => drop(self.facts.remove(at)),
703            (Ok(at), false) => self.facts[at].1 = facts,
704            (Err(_), true) => {}
705            (Err(at), false) => self.facts.insert(at, (value, facts)),
706        }
707    }
708
709    /// Every value something is known about, in value order.
710    pub fn known(&self) -> impl Iterator<Item = (Value, Facts)> + '_ {
711        self.facts.iter().copied()
712    }
713
714    /// Gives a block a name of its own, which is how an image written before the program runs
715    /// says it holds the address of a place inside this function.
716    ///
717    /// What asks for this is GNU's address of a label in the initializer of an object with static
718    /// storage duration, which is how every threaded interpreter builds its dispatch table. The
719    /// address a `lea` produces needs none of this, because both ends of that distance are in the
720    /// same section and the object writer works it out for itself. An image is the other case: it
721    /// is in another section, so what it holds is a relocation, and a relocation names a symbol.
722    ///
723    /// One name per block. Two labels on the same statement are two labels and one block, and the
724    /// image asks for a name rather than for a particular one, so the second ask keeps the first
725    /// answer. Nothing outside this table ever sees the name, which is why it may be anything the
726    /// object format lets a local symbol be called.
727    pub fn name_block(&mut self, block: Block, name: Symbol) {
728        let found = self.labels.binary_search_by_key(&block.raw(), |&(at, _)| at.raw());
729        if let Err(at) = found {
730            self.labels.insert(at, (block, name));
731        }
732    }
733
734    /// The name a block was given, or `None` for a block nothing took the address of.
735    #[must_use]
736    pub fn block_name(&self, block: Block) -> Option<Symbol> {
737        match self.labels.binary_search_by_key(&block.raw(), |&(at, _)| at.raw()) {
738            Ok(at) => Some(self.labels[at].1),
739            Err(_) => None,
740        }
741    }
742
743    /// Every block that has a name, in block order.
744    pub fn named_blocks(&self) -> impl Iterator<Item = (Block, Symbol)> + '_ {
745        self.labels.iter().copied()
746    }
747
748    fn add_value(&mut self, data: ValueData) -> Value {
749        self.values.push(data);
750        Idx::from_usize(self.values.len() - 1)
751    }
752}
753
754/// How many of each thing a function holds.
755#[derive(Clone, Copy, Debug, PartialEq, Eq)]
756pub struct Counts {
757    /// Values, including the ones whose defining instruction has been removed.
758    pub values: usize,
759    /// Instructions, including the ones that have been removed from their block.
760    pub insts: usize,
761    /// Blocks.
762    pub blocks: usize,
763}
764
765// Reading is indexing. There is one of these for each handle, so `func[inst]` and `func[value]`
766// and `&func[args]` all work and none of them needs a method whose name says which table.
767impl Index<Value> for Func {
768    type Output = ValueData;
769
770    fn index(&self, value: Value) -> &ValueData {
771        &self.values[value.index()]
772    }
773}
774
775impl Index<Inst> for Func {
776    type Output = InstData;
777
778    fn index(&self, inst: Inst) -> &InstData {
779        &self.insts[inst.index()]
780    }
781}
782
783impl IndexMut<Inst> for Func {
784    fn index_mut(&mut self, inst: Inst) -> &mut InstData {
785        &mut self.insts[inst.index()]
786    }
787}
788
789impl Index<Block> for Func {
790    type Output = BlockData;
791
792    fn index(&self, block: Block) -> &BlockData {
793        &self.blocks[block.index()]
794    }
795}
796
797impl Index<Sig> for Func {
798    type Output = Signature;
799
800    fn index(&self, sig: Sig) -> &Signature {
801        &self.signatures[sig.index()]
802    }
803}
804
805impl Index<ValueList> for Func {
806    type Output = [Value];
807
808    fn index(&self, list: ValueList) -> &[Value] {
809        &self.value_pool[list.as_usize_range()]
810    }
811}
812
813impl Index<BlockCallList> for Func {
814    type Output = [BlockCall];
815
816    fn index(&self, list: BlockCallList) -> &[BlockCall] {
817        &self.block_calls[list.as_usize_range()]
818    }
819}
820
821impl Index<Idx<BlockCall>> for Func {
822    type Output = BlockCall;
823
824    fn index(&self, at: Idx<BlockCall>) -> &BlockCall {
825        &self.block_calls[at.index()]
826    }
827}
828
829impl Index<ImmList> for Func {
830    type Output = [Imm];
831
832    fn index(&self, list: ImmList) -> &[Imm] {
833        &self.imms[list.as_usize_range()]
834    }
835}
836
837impl Index<Idx<Imm>> for Func {
838    type Output = Imm;
839
840    fn index(&self, at: Idx<Imm>) -> &Imm {
841        &self.imms[at.index()]
842    }
843}
844
845impl Index<Idx<MemInfo>> for Func {
846    type Output = MemInfo;
847
848    fn index(&self, at: Idx<MemInfo>) -> &MemInfo {
849        &self.mem[at.index()]
850    }
851}
852
853impl Index<AbiList> for Func {
854    type Output = [Abi];
855
856    fn index(&self, list: AbiList) -> &[Abi] {
857        &self.abis[list.as_usize_range()]
858    }
859}
860
861impl Index<SlotList> for Func {
862    type Output = [Slot];
863
864    fn index(&self, list: SlotList) -> &[Slot] {
865        &self.slots[list.as_usize_range()]
866    }
867}
868
869impl Index<Idx<VaInfo>> for Func {
870    type Output = VaInfo;
871
872    fn index(&self, at: Idx<VaInfo>) -> &VaInfo {
873        &self.va_objects[at.index()]
874    }
875}
876
877impl Index<Idx<CallInfo>> for Func {
878    type Output = CallInfo;
879
880    fn index(&self, at: Idx<CallInfo>) -> &CallInfo {
881        &self.calls[at.index()]
882    }
883}
884
885impl Index<Idx<SwitchInfo>> for Func {
886    type Output = SwitchInfo;
887
888    fn index(&self, at: Idx<SwitchInfo>) -> &SwitchInfo {
889        &self.switches[at.index()]
890    }
891}
892
893impl Index<Idx<AsmInfo>> for Func {
894    type Output = AsmInfo;
895
896    fn index(&self, at: Idx<AsmInfo>) -> &AsmInfo {
897        &self.asms[at.index()]
898    }
899}
900
901/// A cursor that appends to the end of one block.
902///
903/// This is the shape lowering wants: it works on one block at a time, it appends, and it wants
904/// the value back so it can use it in the next instruction. Everything here is a thin wrapper
905/// over [`Func::create_inst`] and [`Func::append_inst`], and anything the wrappers do not
906/// cover is done with those two directly.
907#[derive(Debug)]
908pub struct Builder<'a> {
909    func: &'a mut Func,
910    block: Block,
911    span: Span,
912}
913
914impl<'a> Builder<'a> {
915    /// A cursor appending to that block, with every instruction taking that source location.
916    pub fn new(func: &'a mut Func, block: Block) -> Self {
917        Self { func, block, span: Span::DUMMY }
918    }
919
920    /// The same cursor, with a source location for the instructions after this.
921    #[must_use]
922    pub fn at(mut self, span: Span) -> Self {
923        self.span = span;
924        self
925    }
926
927    /// Sets the source location for the instructions after this.
928    pub fn set_span(&mut self, span: Span) {
929        self.span = span;
930    }
931
932    /// The function being built.
933    pub fn func(&mut self) -> &mut Func {
934        self.func
935    }
936
937    /// The block being appended to.
938    #[must_use]
939    pub fn block(&self) -> Block {
940        self.block
941    }
942
943    /// Appends an instruction as it is, and gives back its results.
944    pub fn inst(&mut self, data: InstData, results: &[Type]) -> Inst {
945        let inst = self.func.create_inst(data, results, self.span);
946        self.func.append_inst(self.block, inst);
947        inst
948    }
949
950    /// The one value an instruction produces.
951    ///
952    /// # Panics
953    ///
954    /// Panics if it did not produce exactly one.
955    pub fn value(&mut self, data: InstData, ty: Type) -> Value {
956        let inst = self.inst(data, &[ty]);
957        self.func[inst].first_result.expect("one result was asked for")
958    }
959
960    /// An integer constant.
961    ///
962    /// # Panics
963    ///
964    /// Panics if `ty` is not an integer type.
965    pub fn iconst(&mut self, ty: Type, value: i128) -> Value {
966        let imm = self.func.add_imm(Imm::int(value, ty.lane()));
967        self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::IConst) }, ty)
968    }
969
970    /// A floating point constant, given as the bits of its format.
971    pub fn fconst(&mut self, ty: Type, bits: u128) -> Value {
972        let imm = self.func.add_imm(Imm::from_bits(bits));
973        self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::FConst) }, ty)
974    }
975
976    /// A two-operand instruction whose result has the type of its operands.
977    pub fn binary(&mut self, opcode: Opcode, lhs: Value, rhs: Value, flags: Flags) -> Value {
978        let ty = self.func[lhs].ty;
979        let args = self.func.push_values(&[lhs, rhs]);
980        self.value(InstData { args, flags, ..InstData::new(opcode) }, ty)
981    }
982
983    /// Arithmetic that answers with both the wrapped result and whether it wrapped.
984    ///
985    /// The one shape in the IR whose result is two things, which is why it has a builder of its
986    /// own rather than going through [`Builder::value`]. The first result is the answer in the
987    /// type of the operands, the same as the ordinary form of the same arithmetic would give, and
988    /// the second is one `i1` per lane saying whether the exact answer needed more bits than that
989    /// type has.
990    ///
991    /// # Panics
992    ///
993    /// Panics if the instruction did not produce exactly the two results it was created with,
994    /// which is the same promise [`Builder::value`] makes about its one.
995    pub fn checked(&mut self, opcode: Opcode, lhs: Value, rhs: Value) -> (Value, Value) {
996        let ty = self.func[lhs].ty;
997        let args = self.func.push_values(&[lhs, rhs]);
998        let results = [ty, ty.with_lane(Type::I1)];
999        let inst = self.inst(InstData { args, ..InstData::new(opcode) }, &results);
1000        let mut answers = self.func[inst].results();
1001        let value = answers.next().expect("two results were asked for");
1002        let wrapped = answers.next().expect("two results were asked for");
1003        (value, wrapped)
1004    }
1005
1006    /// A one-operand instruction whose result has the type given.
1007    pub fn unary(&mut self, opcode: Opcode, arg: Value, ty: Type) -> Value {
1008        let args = self.func.push_values(&[arg]);
1009        self.value(InstData { args, ..InstData::new(opcode) }, ty)
1010    }
1011
1012    /// An integer comparison, which produces one `i1` per lane.
1013    pub fn icmp(&mut self, pred: IntPred, lhs: Value, rhs: Value) -> Value {
1014        let ty = self.func[lhs].ty.with_lane(Type::I1);
1015        let args = self.func.push_values(&[lhs, rhs]);
1016        self.value(
1017            InstData { args, extra: Extra::IntPred(pred), ..InstData::new(Opcode::ICmp) },
1018            ty,
1019        )
1020    }
1021
1022    /// One of two values, chosen by a bit, which is what a diamond becomes when it stops being one.
1023    ///
1024    /// The type comes from the arms rather than from the bit, and the two arms have to agree, which
1025    /// the verifier checks. Both are evaluated, so the caller owes the argument that evaluating the
1026    /// one that is not chosen is harmless.
1027    pub fn select(&mut self, cond: Value, then: Value, other: Value) -> Value {
1028        let ty = self.func[then].ty;
1029        let args = self.func.push_values(&[cond, then, other]);
1030        self.value(InstData { args, ..InstData::new(Opcode::Select) }, ty)
1031    }
1032
1033    /// A floating point comparison, which produces one `i1` per lane.
1034    pub fn fcmp(&mut self, pred: FloatPred, lhs: Value, rhs: Value, flags: Flags) -> Value {
1035        let ty = self.func[lhs].ty.with_lane(Type::I1);
1036        let args = self.func.push_values(&[lhs, rhs]);
1037        self.value(
1038            InstData { args, flags, extra: Extra::FloatPred(pred), ..InstData::new(Opcode::FCmp) },
1039            ty,
1040        )
1041    }
1042
1043    /// Memory as the function found it, which is where a memory SSA chain starts.
1044    ///
1045    /// It belongs at the top of the entry block and there is one of them in a function.
1046    pub fn mem_entry(&mut self) -> Value {
1047        self.value(InstData::new(Opcode::MemEntry), Type::MEM)
1048    }
1049
1050    /// A read of that type from that address.
1051    pub fn load(&mut self, ty: Type, addr: Value, info: MemInfo, flags: Flags) -> Value {
1052        let mem = self.func.add_mem(info);
1053        let args = self.func.push_values(&[addr]);
1054        self.value(
1055            InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Load) },
1056            ty,
1057        )
1058    }
1059
1060    /// A write of a value to an address.
1061    pub fn store(&mut self, value: Value, addr: Value, info: MemInfo, flags: Flags) -> Inst {
1062        let mem = self.func.add_mem(info);
1063        let args = self.func.push_values(&[value, addr]);
1064        self.inst(
1065            InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Store) },
1066            &[],
1067        )
1068    }
1069
1070    /// The same read, ordered.
1071    ///
1072    /// A separate opcode rather than an ordering on [`Builder::load`], because the two are not the
1073    /// same thing to anything that moves code: a plain load may be moved, duplicated and dropped,
1074    /// and this one may not. The IR verifier is what keeps the pair honest, since it refuses an
1075    /// ordering on a plain access and refuses an unordered one here, so no pass has to remember to
1076    /// check the payload before deciding a load is free.
1077    pub fn atomic_load(&mut self, ty: Type, addr: Value, info: MemInfo, flags: Flags) -> Value {
1078        let mem = self.func.add_mem(info);
1079        let args = self.func.push_values(&[addr]);
1080        self.value(
1081            InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::AtomicLoad) },
1082            ty,
1083        )
1084    }
1085
1086    /// The same write, ordered.
1087    pub fn atomic_store(&mut self, value: Value, addr: Value, info: MemInfo, flags: Flags) -> Inst {
1088        let mem = self.func.add_mem(info);
1089        let args = self.func.push_values(&[value, addr]);
1090        self.inst(
1091            InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::AtomicStore) },
1092            &[],
1093        )
1094    }
1095
1096    /// A compare and exchange, which answers what it found and whether that was what was expected.
1097    ///
1098    /// Two values out of one instruction, in that order, because a caller that had to ask twice
1099    /// would be asking about two different moments. The type of the first is the type of the value
1100    /// expected, which is what says how wide the access is, and the type of the second is
1101    /// [`Type::I1`] whatever the width was.
1102    pub fn cmpxchg(
1103        &mut self,
1104        addr: Value,
1105        expected: Value,
1106        desired: Value,
1107        info: MemInfo,
1108        flags: Flags,
1109    ) -> (Value, Value) {
1110        let ty = self.func[expected].ty;
1111        let mem = self.func.add_mem(info);
1112        let args = self.func.push_values(&[addr, expected, desired]);
1113        let inst = self.inst(
1114            InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Cmpxchg) },
1115            &[ty, Type::I1],
1116        );
1117        let results: Vec<Value> = self.func[inst].results().collect();
1118        let [old, exchanged] = results[..] else { unreachable!("two results were asked for") };
1119        (old, exchanged)
1120    }
1121
1122    /// A read, an operation on what was read, and a write back, with nothing able to get between
1123    /// them.
1124    ///
1125    /// The value it answers is the one that was there before, which is the convention every machine
1126    /// and every language in this area uses, and a caller that wanted the value afterwards works it
1127    /// out from the two it already has rather than asking for a second flavour of the instruction.
1128    /// The type of that value is the type of the operand, which is what says how wide the access is.
1129    pub fn atomic_rmw(
1130        &mut self,
1131        op: RmwOp,
1132        addr: Value,
1133        operand: Value,
1134        info: MemInfo,
1135        flags: Flags,
1136    ) -> Value {
1137        let ty = self.func[operand].ty;
1138        let mem = self.func.add_mem(info);
1139        let args = self.func.push_values(&[addr, operand]);
1140        self.value(
1141            InstData {
1142                args,
1143                flags,
1144                extra: Extra::Rmw(op, mem),
1145                ..InstData::new(Opcode::AtomicRmw)
1146            },
1147            ty,
1148        )
1149    }
1150
1151    /// A barrier, which touches no address and is its ordering and nothing else.
1152    pub fn fence(&mut self, order: MemOrder) -> Inst {
1153        self.inst(InstData { extra: Extra::Order(order), ..InstData::new(Opcode::Fence) }, &[])
1154    }
1155
1156    /// A hint that an address is about to be read or written, which produces nothing.
1157    ///
1158    /// It reads the address rather than the memory at it, in the sense that nothing after this
1159    /// sees anything it did not see before. What it is allowed to do is take time, so it is on the
1160    /// memory chain anyway: a prefetch of an address a store is about to write to has to stay on
1161    /// the side of that store it was written on, or it is a hint about the wrong thing.
1162    pub fn prefetch(&mut self, address: Value, hint: PrefetchHint) -> Inst {
1163        let args = self.func.push_values(&[address]);
1164        self.inst(
1165            InstData { args, extra: Extra::Prefetch(hint), ..InstData::new(Opcode::Prefetch) },
1166            &[],
1167        )
1168    }
1169
1170    /// An unconditional branch.
1171    pub fn jump(&mut self, target: Block, args: &[Value]) -> Inst {
1172        let call = self.block_call(target, args);
1173        let targets = self.func.push_block_calls(&[call]);
1174        self.inst(InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::Jump) }, &[])
1175    }
1176
1177    /// The address of a block, which is a value a later `indirect_br` can branch to.
1178    ///
1179    /// The block is a target here in the same sense a branch's is, so everything that asks an
1180    /// instruction which blocks it names finds this one, and a block whose address is taken is
1181    /// not mistaken for a block nothing mentions.
1182    pub fn block_addr(&mut self, target: Block) -> Value {
1183        let call = self.block_call(target, &[]);
1184        let targets = self.func.push_block_calls(&[call]);
1185        self.value(
1186            InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::BlockAddr) },
1187            Type::PTR,
1188        )
1189    }
1190
1191    /// A branch to an address, which arrives at one of the blocks listed.
1192    ///
1193    /// Every block the address can hold has to be there. The list is what the rest of the
1194    /// compiler reads, so a block left out of it is a block the branch is saying it never
1195    /// reaches, and none of it is checked against the addresses anybody took.
1196    pub fn indirect_br(&mut self, addr: Value, targets: &[Block]) -> Inst {
1197        let calls: Vec<BlockCall> =
1198            targets.iter().map(|&target| self.block_call(target, &[])).collect();
1199        let targets = self.func.push_block_calls(&calls);
1200        let args = self.func.push_values(&[addr]);
1201        self.inst(
1202            InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::IndirectBr) },
1203            &[],
1204        )
1205    }
1206
1207    /// A two-way branch, taking the first target when the condition is one.
1208    pub fn br_if(
1209        &mut self,
1210        cond: Value,
1211        then_block: Block,
1212        then_args: &[Value],
1213        else_block: Block,
1214        else_args: &[Value],
1215    ) -> Inst {
1216        let then_call = self.block_call(then_block, then_args);
1217        let else_call = self.block_call(else_block, else_args);
1218        let targets = self.func.push_block_calls(&[then_call, else_call]);
1219        let args = self.func.push_values(&[cond]);
1220        self.inst(
1221            InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::BrIf) },
1222            &[],
1223        )
1224    }
1225
1226    /// A branch on an integer, taking the target its value selects and the default when it
1227    /// selects none.
1228    ///
1229    /// The cases are values and blocks rather than a table with the default in it, because the
1230    /// order the side table wants, which is the default first, is not an order anybody building
1231    /// a `switch` has their cases in.
1232    pub fn switch(&mut self, value: Value, default: Block, cases: &[(i128, Block)]) -> Inst {
1233        let ty = self.func[value].ty.lane();
1234        let mut calls = vec![self.block_call(default, &[])];
1235        let mut values = Vec::with_capacity(cases.len());
1236        for &(value, block) in cases {
1237            calls.push(self.block_call(block, &[]));
1238            values.push(Imm::int(value, ty));
1239        }
1240        let targets = self.func.push_block_calls(&calls);
1241        let cases = self.func.push_imms(&values);
1242        let info = self.func.add_switch(SwitchInfo { targets, cases });
1243        let args = self.func.push_values(&[value]);
1244        self.inst(
1245            InstData { args, extra: Extra::Switch(info), ..InstData::new(Opcode::Switch) },
1246            &[],
1247        )
1248    }
1249
1250    /// A return of the values the signature says.
1251    pub fn ret(&mut self, values: &[Value]) -> Inst {
1252        let args = self.func.push_values(values);
1253        self.inst(InstData { args, ..InstData::new(Opcode::Return) }, &[])
1254    }
1255
1256    /// A place control does not reach.
1257    pub fn unreachable(&mut self) -> Inst {
1258        self.inst(InstData::new(Opcode::Unreachable), &[])
1259    }
1260
1261    /// A direct call, with the results its signature says it produces.
1262    pub fn call(&mut self, callee: Symbol, signature: Sig, args: &[Value]) -> Inst {
1263        self.call_varargs(callee, signature, args, &[])
1264    }
1265
1266    /// The same, saying how the arguments the signature does not name travel.
1267    ///
1268    /// Empty says they all travel as the values in hand, which is what [`Builder::call`] passes
1269    /// and is the usual case. Anything else has one entry for each argument past the ones the
1270    /// signature names.
1271    pub fn call_varargs(
1272        &mut self,
1273        callee: Symbol,
1274        signature: Sig,
1275        args: &[Value],
1276        varargs: &[Abi],
1277    ) -> Inst {
1278        let varargs = self.func.push_abis(varargs);
1279        let info = self.func.add_call(CallInfo { callee: Some(callee), signature, varargs });
1280        let returns: Vec<Type> = self.func[signature].return_types().collect();
1281        let args = self.func.push_values(args);
1282        self.inst(
1283            InstData { args, extra: Extra::Call(info), ..InstData::new(Opcode::Call) },
1284            &returns,
1285        )
1286    }
1287
1288    /// Inline assembly, which is a terminator when the info carries targets.
1289    ///
1290    /// The targets are built by the caller, because the frontend is the only thing that knows
1291    /// which block is the one control reaches when the assembly does not jump, and that block
1292    /// has to come first.
1293    pub fn inline_asm(
1294        &mut self,
1295        info: AsmInfo,
1296        args: &[Value],
1297        results: &[Type],
1298        flags: Flags,
1299    ) -> Inst {
1300        let info = self.func.add_asm(info);
1301        let args = self.func.push_values(args);
1302        self.inst(
1303            InstData { args, flags, extra: Extra::Asm(info), ..InstData::new(Opcode::InlineAsm) },
1304            results,
1305        )
1306    }
1307
1308    fn block_call(&mut self, block: Block, args: &[Value]) -> BlockCall {
1309        BlockCall::new(block, self.func.push_values(args))
1310    }
1311}
1312
1313#[cfg(test)]
1314mod tests {
1315    use rucc_base::Interner;
1316
1317    use super::*;
1318    use crate::inst::BlockCallList;
1319    use crate::{MemOrder, Restrict};
1320
1321    /// The example from the spec, near enough: a loop that sums one to n and stores it.
1322    fn sum() -> (Func, Block, Block, Block) {
1323        let mut names = Interner::new();
1324        let i32_ = Type::int(32);
1325        let mut func = Func::new(
1326            names.intern("sum"),
1327            Signature::new().with_params(&[i32_]).with_returns(&[i32_]),
1328        );
1329
1330        let entry = func.create_block();
1331        let n = func.append_param(entry, i32_);
1332        let header = func.create_block();
1333        let acc = func.append_param(header, i32_);
1334        let i = func.append_param(header, i32_);
1335        let exit = func.create_block();
1336        let result = func.append_param(exit, i32_);
1337
1338        let mut b = Builder::new(&mut func, entry);
1339        let zero = b.iconst(i32_, 0);
1340        let cmp = b.icmp(IntPred::Sle, n, zero);
1341        b.br_if(cmp, exit, &[zero], header, &[zero, zero]);
1342
1343        let mut b = Builder::new(&mut func, header);
1344        let one = b.iconst(i32_, 1);
1345        let next = b.binary(Opcode::Add, i, one, Flags::NSW);
1346        let total = b.binary(Opcode::Add, acc, next, Flags::NSW);
1347        let done = b.icmp(IntPred::Sge, next, n);
1348        b.br_if(done, exit, &[total], header, &[total, next]);
1349
1350        let mut b = Builder::new(&mut func, exit);
1351        b.ret(&[result]);
1352
1353        (func, entry, header, exit)
1354    }
1355
1356    #[test]
1357    fn the_blocks_come_back_in_the_order_they_were_made() {
1358        let (func, entry, header, exit) = sum();
1359        assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, header, exit]);
1360        assert_eq!(func.entry(), Some(entry));
1361    }
1362
1363    #[test]
1364    fn a_removed_block_is_gone_from_the_layout_and_so_is_what_was_in_it() {
1365        let (mut func, entry, header, exit) = sum();
1366        let inside: Vec<Inst> = func.insts(header).collect();
1367        func.remove_block(header);
1368        assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, exit]);
1369        assert_eq!(func.entry(), Some(entry));
1370        assert_eq!(func[entry].next, Some(exit));
1371        assert_eq!(func[exit].prev, Some(entry));
1372        // The instructions say they are in no block, the way a removed one does.
1373        assert!(inside.iter().all(|&inst| func.block_of(inst).is_none()));
1374        assert!(func.insts(header).next().is_none());
1375    }
1376
1377    #[test]
1378    fn each_block_holds_what_was_appended_to_it() {
1379        let (func, entry, header, exit) = sum();
1380        let opcodes =
1381            |block| func.insts(block).map(|inst| func[inst].opcode.name()).collect::<Vec<_>>();
1382        assert_eq!(opcodes(entry), ["iconst", "icmp", "br_if"]);
1383        assert_eq!(opcodes(header), ["iconst", "add", "add", "icmp", "br_if"]);
1384        assert_eq!(opcodes(exit), ["return"]);
1385    }
1386
1387    #[test]
1388    fn asm_ends_a_block_when_it_has_labels_and_not_otherwise() {
1389        // The labels are in the function's table, so the instruction on its own cannot answer
1390        // and anything asking it rather than the function would walk off the end of the block.
1391        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1392        let block = func.create_block();
1393        let plain = func.add_asm(AsmInfo {
1394            template: Symbol::from_raw(0),
1395            constraints: Symbol::from_raw(0),
1396            clobbers: Symbol::from_raw(0),
1397            targets: BlockCallList::EMPTY,
1398        });
1399        let call = BlockCall::to(block);
1400        let targets = func.push_block_calls(&[call]);
1401        let labelled = func.add_asm(AsmInfo {
1402            template: Symbol::from_raw(0),
1403            constraints: Symbol::from_raw(0),
1404            clobbers: Symbol::from_raw(0),
1405            targets,
1406        });
1407
1408        let mut make = |extra| {
1409            let data = InstData { extra, ..InstData::new(Opcode::InlineAsm) };
1410            func.create_inst(data, &[], Span::DUMMY)
1411        };
1412        let plain = make(Extra::Asm(plain));
1413        let labelled = make(Extra::Asm(labelled));
1414        assert!(!func.is_terminator(plain));
1415        assert!(func.is_terminator(labelled));
1416    }
1417
1418    #[test]
1419    fn every_block_ends_in_its_terminator() {
1420        let (func, entry, header, exit) = sum();
1421        for block in [entry, header, exit] {
1422            let last = func.terminator(block).expect("a terminator");
1423            assert_eq!(Some(last), func.insts(block).last());
1424        }
1425    }
1426
1427    #[test]
1428    fn a_branch_carries_the_arguments_the_block_takes() {
1429        let (func, entry, header, _) = sum();
1430        let br = func.terminator(entry).expect("a terminator");
1431        let calls: Vec<BlockCall> = func.successors(br).collect();
1432        assert_eq!(calls.len(), 2);
1433        // The loop header takes two parameters, so the branch to it passes two.
1434        assert_eq!(calls[1].block, header);
1435        assert_eq!(func[calls[1].args].len(), 2);
1436        assert_eq!(func[header].params.len(), 2);
1437        assert_eq!(func[calls[0].args].len(), 1);
1438    }
1439
1440    #[test]
1441    fn a_value_knows_what_defined_it() {
1442        let (func, entry, _, _) = sum();
1443        let first = func.insts(entry).next().expect("an instruction");
1444        let value = func[first].first_result.expect("a result");
1445        assert_eq!(func[value].def, Def::Result { inst: first, index: 0 });
1446        assert_eq!(func[value].ty, Type::int(32));
1447
1448        let param = func[entry].params[0];
1449        assert_eq!(func[param].def, Def::Param { block: entry, index: 0 });
1450    }
1451
1452    #[test]
1453    fn a_comparison_produces_one_bit() {
1454        let (func, entry, _, _) = sum();
1455        let cmp = func.insts(entry).nth(1).expect("the comparison");
1456        let value = func[cmp].first_result.expect("a result");
1457        assert_eq!(func[value].ty, Type::I1);
1458        assert_eq!(func[cmp].extra, Extra::IntPred(IntPred::Sle));
1459    }
1460
1461    #[test]
1462    fn flags_ride_along_on_the_instruction_that_was_given_them() {
1463        let (func, _, header, _) = sum();
1464        let add = func.insts(header).nth(1).expect("the addition");
1465        assert_eq!(func[add].flags, Flags::NSW);
1466        let cmp = func.insts(header).nth(3).expect("the comparison");
1467        assert_eq!(func[cmp].flags, Flags::NONE);
1468    }
1469
1470    #[test]
1471    fn removing_an_instruction_takes_it_out_of_the_middle() {
1472        let (mut func, _, header, _) = sum();
1473        let add = func.insts(header).nth(1).expect("the addition");
1474        func.remove_inst(add);
1475        let opcodes: Vec<&str> = func.insts(header).map(|inst| func[inst].opcode.name()).collect();
1476        assert_eq!(opcodes, ["iconst", "add", "icmp", "br_if"]);
1477        assert_eq!(func.block_of(add), None);
1478    }
1479
1480    #[test]
1481    fn removing_the_first_and_the_last_keeps_the_ends_right() {
1482        let (mut func, entry, _, _) = sum();
1483        let first = func.insts(entry).next().expect("an instruction");
1484        let last = func.terminator(entry).expect("a terminator");
1485        func.remove_inst(first);
1486        func.remove_inst(last);
1487        let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1488        assert_eq!(opcodes, ["icmp"]);
1489        assert_eq!(func[entry].first, func[entry].last);
1490    }
1491
1492    #[test]
1493    fn removing_the_only_instruction_empties_the_block() {
1494        let (mut func, _, _, exit) = sum();
1495        let only = func.insts(exit).next().expect("an instruction");
1496        func.remove_inst(only);
1497        assert_eq!(func.insts(exit).count(), 0);
1498        assert_eq!(func[exit].first, None);
1499        assert_eq!(func[exit].last, None);
1500    }
1501
1502    #[test]
1503    fn inserting_before_puts_it_in_the_right_place() {
1504        let (mut func, entry, _, _) = sum();
1505        let cmp = func.insts(entry).nth(1).expect("the comparison");
1506        let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1507        func.insert_before(made, cmp);
1508        let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1509        assert_eq!(opcodes, ["iconst", "unreachable", "icmp", "br_if"]);
1510    }
1511
1512    #[test]
1513    fn inserting_before_the_first_makes_it_the_first() {
1514        let (mut func, entry, _, _) = sum();
1515        let first = func.insts(entry).next().expect("an instruction");
1516        let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1517        func.insert_before(made, first);
1518        assert_eq!(func.insts(entry).next(), Some(made));
1519        assert_eq!(func[entry].first, Some(made));
1520    }
1521
1522    #[test]
1523    fn inserting_after_puts_it_in_the_right_place() {
1524        let (mut func, entry, _, _) = sum();
1525        let first = func.insts(entry).next().expect("an instruction");
1526        let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1527        func.insert_after(made, first);
1528        let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1529        assert_eq!(opcodes, ["iconst", "unreachable", "icmp", "br_if"]);
1530        assert_eq!(func[entry].first, Some(first));
1531    }
1532
1533    #[test]
1534    #[should_panic(expected = "nothing goes after a terminator")]
1535    fn inserting_after_the_terminator_is_refused() {
1536        // A block ends where its branch is, so an instruction after one would be in no block that
1537        // control ever reaches, and the layout would be claiming otherwise.
1538        let (mut func, entry, _, _) = sum();
1539        let last = func.insts(entry).last().expect("a terminator");
1540        let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1541        func.insert_after(made, last);
1542    }
1543
1544    #[test]
1545    fn a_list_grows_in_place_while_it_is_the_last_thing_in_the_pool() {
1546        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1547        let block = func.create_block();
1548        let a = func.append_param(block, Type::int(32));
1549        let b = func.append_param(block, Type::int(32));
1550        let list = func.push_values(&[a]);
1551        let grown = func.append_arg(list, b);
1552        assert_eq!(func[grown], [a, b]);
1553        assert_eq!(grown.as_usize_range().start, list.as_usize_range().start);
1554    }
1555
1556    #[test]
1557    fn a_list_is_copied_when_something_is_behind_it() {
1558        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1559        let block = func.create_block();
1560        let a = func.append_param(block, Type::int(32));
1561        let b = func.append_param(block, Type::int(32));
1562        let list = func.push_values(&[a, a]);
1563        let behind = func.push_values(&[b]);
1564        let grown = func.append_arg(list, b);
1565        assert_eq!(func[grown], [a, a, b]);
1566        assert_eq!(func[list], [a, a], "the old run is still readable");
1567        assert_eq!(func[behind], [b], "and so is what was behind it");
1568        assert_ne!(grown.as_usize_range().start, list.as_usize_range().start);
1569    }
1570
1571    #[test]
1572    fn a_parameter_added_late_is_the_next_one_along() {
1573        // This is the shape SSA construction leaves: the loop header gains a parameter after
1574        // the blocks that branch to it already exist, and each of their branches grows an
1575        // argument to match.
1576        let (mut func, entry, header, _) = sum();
1577        let extra = func.append_param(header, Type::int(32));
1578        assert_eq!(func[header].params.len(), 3);
1579        assert_eq!(func[extra].def, Def::Param { block: header, index: 2 });
1580
1581        let br = func.terminator(entry).expect("a terminator");
1582        let call = func.successors(br).nth(1).expect("the branch to the header");
1583        let grown = func.append_arg(call.args, extra);
1584        assert_eq!(func[grown].len(), 3);
1585    }
1586
1587    #[test]
1588    fn a_span_rides_along_with_the_instruction() {
1589        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1590        let block = func.create_block();
1591        let span = Span::new(10, 20);
1592        let mut b = Builder::new(&mut func, block).at(span);
1593        let value = b.iconst(Type::int(32), 7);
1594        let inst = match func[value].def {
1595            Def::Result { inst, .. } => inst,
1596            Def::Param { .. } => unreachable!("a constant is not a parameter"),
1597        };
1598        assert_eq!(func.span(inst), span);
1599    }
1600
1601    #[test]
1602    fn a_store_produces_nothing_and_a_load_produces_one_value() {
1603        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1604        let block = func.create_block();
1605        let addr = func.append_param(block, Type::PTR);
1606        let info = MemInfo {
1607            size: 4,
1608            align: 4,
1609            order: MemOrder::NotAtomic,
1610            tbaa: None,
1611            owns: 0,
1612            restrict: Restrict::NONE,
1613        };
1614        let mut b = Builder::new(&mut func, block);
1615        let value = b.load(Type::int(32), addr, info, Flags::NONE);
1616        let store = b.store(value, addr, info, Flags::VOLATILE);
1617        assert_eq!(func[store].results, 0);
1618        assert_eq!(func[store].flags, Flags::VOLATILE);
1619        assert_eq!(func[value].ty, Type::int(32));
1620    }
1621
1622    #[test]
1623    fn a_call_produces_what_its_signature_returns() {
1624        let mut names = Interner::new();
1625        let mut func = Func::new(names.intern("caller"), Signature::new());
1626        let sig = func.add_signature(
1627            Signature::new().with_params(&[Type::int(32)]).with_returns(&[Type::int(64)]),
1628        );
1629        let block = func.create_block();
1630        let arg = func.append_param(block, Type::int(32));
1631        let callee = names.intern("callee");
1632        let mut b = Builder::new(&mut func, block);
1633        let call = b.call(callee, sig, &[arg]);
1634        assert_eq!(func[call].results, 1);
1635        let value = func[call].first_result.expect("a result");
1636        assert_eq!(func[value].ty, Type::int(64));
1637        assert_eq!(func[call].extra, Extra::Call(Idx::new(0)));
1638    }
1639
1640    #[test]
1641    fn the_counts_are_what_was_made() {
1642        let (func, _, _, _) = sum();
1643        let counts = func.counts();
1644        assert_eq!(counts.blocks, 3);
1645        assert_eq!(counts.insts, 9);
1646        // Four block parameters and five instruction results, which is the two constants, the
1647        // two additions and the two comparisons less the branches, which produce nothing.
1648        assert_eq!(counts.values, 4 + 6);
1649    }
1650
1651    #[test]
1652    #[should_panic(expected = "the instruction is in a block")]
1653    fn appending_an_instruction_twice_is_refused() {
1654        let (mut func, entry, _, _) = sum();
1655        let first = func.insts(entry).next().expect("an instruction");
1656        func.append_inst(entry, first);
1657    }
1658
1659    #[test]
1660    #[should_panic(expected = "the instruction is not in a block")]
1661    fn removing_an_instruction_twice_is_refused() {
1662        let (mut func, entry, _, _) = sum();
1663        let first = func.insts(entry).next().expect("an instruction");
1664        func.remove_inst(first);
1665        func.remove_inst(first);
1666    }
1667
1668    /// A store and a load with memory threaded through them, as memory SSA construction does it.
1669    fn threaded() -> (Func, Inst, Inst) {
1670        let mut names = Interner::new();
1671        let i32_ = Type::int(32);
1672        let mut func = Func::new(
1673            names.intern("thread"),
1674            Signature::new().with_params(&[Type::PTR]).with_returns(&[i32_]),
1675        );
1676        let entry = func.create_block();
1677        let addr = func.append_param(entry, Type::PTR);
1678        let info = MemInfo {
1679            size: 4,
1680            align: 4,
1681            order: MemOrder::NotAtomic,
1682            tbaa: None,
1683            owns: 0,
1684            restrict: Restrict::NONE,
1685        };
1686
1687        let mut b = Builder::new(&mut func, entry);
1688        let start = b.mem_entry();
1689        let seven = b.iconst(i32_, 7);
1690        let store = b.store(seven, addr, info, Flags::NONE);
1691        let value = b.load(i32_, addr, info, Flags::NONE);
1692        let Def::Result { inst: load, .. } = func[value].def else {
1693            panic!("the load produced it");
1694        };
1695
1696        let store = func.with_mem(store, start);
1697        let after = func.mem_out(store).expect("a store makes a new version");
1698        let load = func.with_mem(load, after);
1699        (func, store, load)
1700    }
1701
1702    #[test]
1703    fn threading_memory_puts_it_last_and_leaves_everything_else_where_it_was() {
1704        let (func, store, load) = threaded();
1705        assert_eq!(func.mem_in(store), func.mem_out(store).map(|_| func[func[store].args][2]));
1706        assert_eq!(func[func[store].args].len(), 3);
1707        assert!(func.carries_mem(store));
1708        assert!(func.carries_mem(load));
1709
1710        // The address of the load is still its first operand, which is the point of putting
1711        // memory last: nothing that read the operands before has to learn about it.
1712        assert_eq!(func[func[load].args][0], func[func.entry().expect("an entry")].params[0]);
1713        assert_eq!(func.mem_in(load), func.mem_out(store));
1714        assert_eq!(func.mem_out(load), None);
1715    }
1716
1717    #[test]
1718    #[should_panic(expected = "this is already on the memory chain")]
1719    fn threading_memory_through_the_same_instruction_twice_is_refused() {
1720        let (mut func, store, _) = threaded();
1721        let start = func.mem_in(store).expect("it was threaded");
1722        func.with_mem(store, start);
1723    }
1724}