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::collections::{HashMap, HashSet};
30use std::ops::{Index, IndexMut};
31
32use rucc_base::{Idx, Symbol};
33use rucc_diag::Span;
34use rucc_target::Slot;
35
36use crate::inst::{
37    Abi, AbiList, AsmInfo, Block, BlockCall, BlockCallList, BlockData, Bulk, CallInfo, Def, Extra,
38    Imm, ImmList, Inst, InstData, InstLayout, MemInfo, Sig, Signature, SlotList, SwitchInfo,
39    VaInfo, Value, ValueData, ValueList,
40};
41use crate::module::{Linkage, Visibility};
42use crate::{Attrs, Facts, Flags, FloatPred, IntPred, MemOrder, Opcode, PrefetchHint, RmwOp, Type};
43
44/// One function.
45#[derive(Debug)]
46pub struct Func {
47    /// The name it is called by, which is what a direct call to it names.
48    pub name: Symbol,
49    /// The name the source spelled, where an assembler name means the symbol is not that name.
50    ///
51    /// `extern char *strstr (const char *, const char *) __asm ("my_strstr");` declares the
52    /// standard `strstr` and says the symbol is `my_strstr`, and both of those are facts a later
53    /// pass needs: the symbol is what a call names and what the linker resolves, and the spelling
54    /// is what says this is the function the standard describes. Keeping only the symbol is how a
55    /// rename hides a library call from every fold that knows what that library call does, which
56    /// is what `gcc.c-torture/execute/builtins/strstr-asm.c` is written to catch.
57    ///
58    /// `None` where the two are the same, which is every function that renamed nothing, so this
59    /// costs a word on a function and appears in the printed form only where a program asked for
60    /// it.
61    pub spelled: Option<Symbol>,
62    /// How the linker sees it. `Internal` for a `static` function.
63    pub linkage: Linkage,
64    /// How the dynamic linker sees it.
65    pub visibility: Visibility,
66    /// The section to put it in, from `__attribute__((section(...)))`, or `None` to let the
67    /// object writer choose.
68    pub section: Option<Symbol>,
69    /// What its first instruction has to be aligned to, from `__attribute__((aligned(...)))`, or
70    /// `None` for the alignment the target gives every function anyway.
71    ///
72    /// A raise and never a lower, the way the attribute is everywhere: a function asked to be at
73    /// a multiple of two hundred and fifty six is at one, and one asked for less than the target's
74    /// own alignment keeps the target's.
75    pub align: Option<u32>,
76    /// What is true of the whole function, which is what a caller reads when it wants to know
77    /// what a call to it does without looking inside.
78    pub attrs: Attrs,
79    /// Where it was declared, which is what a debugger says the prologue is.
80    ///
81    /// Not any instruction's span, and that is the point of it. The pushes, the frame and the
82    /// moves that put the arguments where the body expects them come from no expression in the
83    /// source, so every one of them carries [`Span::DUMMY`], and the front of every function would
84    /// otherwise be the one part of it the line table says nothing about. A program counter in
85    /// there would get no answer rather than a slightly early one, which is the worse of the two
86    /// for whoever is reading a backtrace.
87    ///
88    /// [`Span::DUMMY`] in a function built by something that is not a C source, which is what the
89    /// tests and the IR parser build.
90    ///
91    /// Spelled `declared` rather than `span` because [`Func::span`] is already the span of an
92    /// instruction, and a field and a method of the same name on the same type is a reading
93    /// hazard for no gain.
94    pub declared: Span,
95
96    values: Vec<ValueData>,
97    insts: Vec<InstData>,
98    inst_layout: Vec<InstLayout>,
99    inst_spans: Vec<Span>,
100    blocks: Vec<BlockData>,
101
102    value_pool: Vec<Value>,
103    block_calls: Vec<BlockCall>,
104    imms: Vec<Imm>,
105    mem: Vec<MemInfo>,
106    calls: Vec<CallInfo>,
107    abis: Vec<Abi>,
108    switches: Vec<SwitchInfo>,
109    asms: Vec<AsmInfo>,
110    slots: Vec<Slot>,
111    va_objects: Vec<VaInfo>,
112    signatures: Vec<Signature>,
113    facts: Vec<(Value, Facts)>,
114    labels: Vec<(Block, Symbol)>,
115    mem_decls: Vec<(Idx<MemInfo>, u32)>,
116    value_decls: Vec<(Value, u32)>,
117    value_starts: Vec<(Value, Start)>,
118    /// The instructions some start in [`Func::value_starts`] is after, so that taking one out only
119    /// has to remember where it was when it is one of them.
120    anchors: HashSet<Inst>,
121    /// The starts [`Func::remove_inst`] made out of the names on an instruction's results, by the
122    /// instruction, so that putting the instruction back somewhere turns them back into names.
123    unplaced: HashMap<Inst, Vec<(Value, Start)>>,
124    /// How many of a call's arguments each C argument became, for the calls the lowering says.
125    ///
126    /// Not part of the IR's text and not something the verifier reads. It is there for one
127    /// reader, `rucc_opt::inline`, which forwards the anonymous arguments of a call to an
128    /// `always_inline` function into a call inside it and has to know which values were one
129    /// structure, since the ABI puts all of a structure in registers or none of it. A module read
130    /// back from text has none of these, and the inliner forwards less for it.
131    arg_groups: HashMap<Inst, Vec<u32>>,
132    /// Where each instruction some start is after was when a pass took it out, as the block and
133    /// the instruction in front of it. See [`Func::start_place`].
134    gone: HashMap<Inst, (Block, Option<Inst>)>,
135
136    first_block: Option<Block>,
137    last_block: Option<Block>,
138}
139
140impl Func {
141    /// A function with that name and that signature, and nothing in it.
142    ///
143    /// The signature becomes signature zero, which is what [`Func::signature`] gives back. The
144    /// entry block is not created here, because the caller is about to create it and give it
145    /// the parameters, and a half-built entry block is worse than no entry block. So a
146    /// function fresh from here is a declaration, and stops being one when it gets a block.
147    #[must_use]
148    pub fn new(name: Symbol, signature: Signature) -> Self {
149        Self {
150            name,
151            spelled: None,
152            linkage: Linkage::External,
153            visibility: Visibility::Default,
154            section: None,
155            align: None,
156            attrs: Attrs::NONE,
157            declared: Span::DUMMY,
158            values: Vec::new(),
159            insts: Vec::new(),
160            inst_layout: Vec::new(),
161            inst_spans: Vec::new(),
162            blocks: Vec::new(),
163            value_pool: Vec::new(),
164            block_calls: Vec::new(),
165            imms: Vec::new(),
166            mem: Vec::new(),
167            calls: Vec::new(),
168            abis: Vec::new(),
169            switches: Vec::new(),
170            asms: Vec::new(),
171            slots: Vec::new(),
172            va_objects: Vec::new(),
173            signatures: vec![signature],
174            facts: Vec::new(),
175            labels: Vec::new(),
176            mem_decls: Vec::new(),
177            value_decls: Vec::new(),
178            value_starts: Vec::new(),
179            anchors: HashSet::new(),
180            unplaced: HashMap::new(),
181            arg_groups: HashMap::new(),
182            gone: HashMap::new(),
183            first_block: None,
184            last_block: None,
185        }
186    }
187
188    /// Its own signature.
189    #[must_use]
190    pub fn signature(&self) -> &Signature {
191        &self.signatures[0]
192    }
193
194    /// Gives the function a different signature of its own.
195    ///
196    /// Two callers. One is the back end pass that puts an integer the machine has no register for
197    /// into the pair of registers it travels in, where one parameter becomes two. The other is the
198    /// interprocedural pass that takes out a parameter nothing reads, where one parameter becomes
199    /// none, and that one rewrites every call in the unit in the same breath. A parameter list
200    /// that is not the one the function was created with is a list the entry block's parameters
201    /// have to say the same thing about, which is why this is next to [`Func::retain_params`] in
202    /// what a pass has to keep straight rather than something the middle end reaches for. Nothing
203    /// else changes a function's own signature, because a signature is what its callers were
204    /// compiled against.
205    pub fn set_signature(&mut self, signature: Signature) {
206        self.signatures[0] = signature;
207    }
208
209    /// Every signature the function holds, its own first and then the ones its calls name.
210    pub fn signatures(&self) -> impl Iterator<Item = &Signature> {
211        self.signatures.iter()
212    }
213
214    /// Records a signature a `call_indirect` is made with, and gives back its index.
215    pub fn add_signature(&mut self, signature: Signature) -> Sig {
216        self.signatures.push(signature);
217        Idx::from_usize(self.signatures.len() - 1)
218    }
219
220    /// The entry block, which is the first one in layout order.
221    ///
222    /// `None` only before one has been created. The verifier is what insists a finished
223    /// function has one.
224    #[must_use]
225    pub fn entry(&self) -> Option<Block> {
226        self.first_block
227    }
228
229    /// Whether this only says the function exists somewhere, which is a function with no
230    /// blocks in it.
231    ///
232    /// `extern int puts(const char *);` and every other declaration of something defined in
233    /// another object is one of these, and it is here rather than left out of the module
234    /// because a call needs its signature and its linkage.
235    #[must_use]
236    pub fn is_declaration(&self) -> bool {
237        self.first_block.is_none()
238    }
239
240    // Blocks.
241
242    /// Creates a block with no parameters and no instructions, at the end of the layout.
243    pub fn create_block(&mut self) -> Block {
244        let block = Idx::from_usize(self.blocks.len());
245        self.blocks.push(BlockData { prev: self.last_block, ..BlockData::default() });
246        match self.last_block {
247            Some(last) => self.blocks[last.index()].next = Some(block),
248            None => self.first_block = Some(block),
249        }
250        self.last_block = Some(block);
251        block
252    }
253
254    /// Takes a block out of the layout, along with everything in it.
255    ///
256    /// The block keeps its number, the way a removed instruction keeps its own, because
257    /// renumbering would move every block after it and invalidate every index anybody was
258    /// holding. What it stops being is a block of this function: nothing walks it, nothing
259    /// prints it, and the values defined in it are as gone as the instructions that defined
260    /// them. Deleting one whose branches something still reaches is how a function ends up
261    /// branching to nowhere, so the caller is the one that has to know nothing reaches it.
262    ///
263    /// # Panics
264    ///
265    /// Panics if the block is the entry block, which is the one block a function has to have.
266    pub fn remove_block(&mut self, block: Block) {
267        assert!(self.first_block != Some(block), "the entry block is not removable");
268        let (prev, next) = (self.blocks[block.index()].prev, self.blocks[block.index()].next);
269        match prev {
270            Some(prev) => self.blocks[prev.index()].next = next,
271            None => self.first_block = next,
272        }
273        match next {
274            Some(next) => self.blocks[next.index()].prev = prev,
275            None => self.last_block = prev,
276        }
277        // The instructions say they are in no block now, which is what a removed instruction
278        // says, so that asking one where it is gives an answer rather than a block nothing
279        // walks.
280        let insts: Vec<Inst> = self.insts(block).collect();
281        for inst in insts {
282            self.inst_layout[inst.index()] = InstLayout::default();
283        }
284        self.blocks[block.index()] = BlockData::default();
285    }
286
287    /// Adds a parameter of that type to a block, and gives back the value it arrives as.
288    ///
289    /// Every predecessor's branch has to grow an argument to match, which is
290    /// [`Func::append_arg`], and the verifier is what notices if one of them did not.
291    ///
292    /// # Panics
293    ///
294    /// Panics if the block already has four billion parameters, which no block does.
295    pub fn append_param(&mut self, block: Block, ty: Type) -> Value {
296        let index = u32::try_from(self.blocks[block.index()].params.len())
297            .expect("a block with four billion parameters");
298        let value = self.add_value(ValueData { ty, def: Def::Param { block, index } });
299        self.blocks[block.index()].params.push(value);
300        value
301    }
302
303    /// Drops the parameters of a block that a predicate turns down, and renumbers the rest.
304    ///
305    /// The predicate is asked about each parameter in the order the block takes them. A
306    /// parameter that goes has to take the argument in the same position out of every branch
307    /// to the block, which is the caller's work rather than this method's, because only the
308    /// caller knows which branches there are. This is what removing a redundant block
309    /// parameter is, and SSA construction is the thing that makes them.
310    ///
311    /// # Panics
312    ///
313    /// Panics if the block has four billion parameters, which no block does.
314    pub fn retain_params(&mut self, block: Block, mut keep: impl FnMut(Value) -> bool) {
315        let mut params = std::mem::take(&mut self.blocks[block.index()].params);
316        let mut dropped = Vec::new();
317        params.retain(|&value| {
318            let kept = keep(value);
319            if !kept {
320                dropped.push(value);
321            }
322            kept
323        });
324        // The same as an instruction taken out: a declaration a dropped parameter was the value of
325        // was given it at the top of the block.
326        for value in dropped {
327            self.held_from(value, block, None);
328        }
329        for (index, &value) in params.iter().enumerate() {
330            let index = u32::try_from(index).expect("a block with four billion parameters");
331            self.values[value.index()].def = Def::Param { block, index };
332        }
333        self.blocks[block.index()].params = params;
334    }
335
336    /// Gives a value a different type, leaving where it comes from alone.
337    ///
338    /// There is one caller and it is the back end pass that puts an integer of a width the
339    /// machine has no register for into the width it does have one for. Nothing in the middle
340    /// end changes a value's type, because a value's type is what the instruction that made it
341    /// produces and changing one without changing the other is how an IR stops meaning
342    /// anything. That pass changes both, which is why this is a method and not a field.
343    ///
344    /// # Panics
345    ///
346    /// Panics if the value is not one of this function's.
347    pub fn retype(&mut self, value: Value, ty: Type) {
348        self.values[value.index()].ty = ty;
349    }
350
351    /// Every value the function has, including ones whose defining instruction has gone.
352    ///
353    /// In the order they were created, which is the order a pass that walks all of them wants:
354    /// a value is defined before it is used, so a walk in this order sees a definition first.
355    pub fn values(&self) -> impl Iterator<Item = Value> + use<'_> {
356        (0..self.values.len()).map(Idx::from_usize)
357    }
358
359    /// Every block, in layout order.
360    pub fn blocks(&self) -> impl Iterator<Item = Block> + use<'_> {
361        std::iter::successors(self.first_block, move |&block| self.blocks[block.index()].next)
362    }
363
364    /// Every instruction in a block, in order.
365    pub fn insts(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_> {
366        std::iter::successors(self.blocks[block.index()].first, move |&inst| {
367            self.inst_layout[inst.index()].next
368        })
369    }
370
371    /// Every instruction in a block, last first.
372    ///
373    /// Which is the order a liveness walk needs, and it is here rather than at the caller because
374    /// the layout links are private and collecting the block into a vector to reverse it is an
375    /// allocation per block per round of a fixpoint.
376    pub fn insts_backwards(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_> {
377        std::iter::successors(self.blocks[block.index()].last, move |&inst| {
378            self.inst_layout[inst.index()].prev
379        })
380    }
381
382    /// The last instruction of a block, which is its terminator once it is finished.
383    #[must_use]
384    pub fn terminator(&self, block: Block) -> Option<Inst> {
385        self.blocks[block.index()].last.filter(|&inst| self.is_terminator(inst))
386    }
387
388    /// Whether control leaves the block at this instruction.
389    ///
390    /// A question for the function rather than for the instruction, because inline assembly is
391    /// the one case where the opcode is not enough: `asm goto` has labels and everything else
392    /// does not, and the labels are in the function's table rather than on the instruction.
393    #[must_use]
394    pub fn is_terminator(&self, inst: Inst) -> bool {
395        let data = &self[inst];
396        match data.extra {
397            Extra::Asm(info) => {
398                data.opcode.is_terminator() || !self.asms[info.index()].targets.is_empty()
399            }
400            _ => data.opcode.is_terminator(),
401        }
402    }
403
404    // Instructions.
405
406    /// Creates an instruction and its result values, without putting it in a block.
407    ///
408    /// The results are allocated here and are contiguous, which is what lets an instruction
409    /// hold the first of them and a count rather than a list.
410    ///
411    /// # Panics
412    ///
413    /// Panics if `results` has more than 255 types, which no instruction in the set does.
414    pub fn create_inst(&mut self, mut data: InstData, results: &[Type], span: Span) -> Inst {
415        let inst = Idx::from_usize(self.insts.len());
416        data.results = u8::try_from(results.len()).expect("an instruction with too many results");
417        data.first_result = results.first().map(|_| Idx::from_usize(self.values.len()));
418        for (index, &ty) in results.iter().enumerate() {
419            let index = u8::try_from(index).expect("checked just above");
420            self.add_value(ValueData { ty, def: Def::Result { inst, index } });
421        }
422        self.insts.push(data);
423        self.inst_layout.push(InstLayout::default());
424        self.inst_spans.push(span);
425        inst
426    }
427
428    /// Takes the results in front of an instruction away, leaving the ones behind them.
429    ///
430    /// One caller, the interprocedural pass that stops a function handing a value back. The
431    /// results of an instruction are consecutive values with memory last, so dropping the ones in
432    /// front is moving the first one along and shortening the count, and the values that went stay
433    /// in the table with nothing referring to them, because nothing here ever takes a value out.
434    ///
435    /// The ones that stay are renumbered, so that a value still says which of its instruction's
436    /// results it is. A pass that asks that question of a call result is asking whether it is the
437    /// pointer an allocator handed back, and an answer left over from before the drop is an answer
438    /// about a result that is no longer there.
439    ///
440    /// # Panics
441    ///
442    /// Panics if the instruction does not produce that many results.
443    pub fn drop_results(&mut self, inst: Inst, drop: u8) {
444        let data = &self.insts[inst.index()];
445        assert!(drop <= data.results, "the instruction does not produce that many results");
446        let left = data.results - drop;
447        let first = data.first_result.map_or(0, Idx::raw) + u32::from(drop);
448        let data = &mut self.insts[inst.index()];
449        data.results = left;
450        data.first_result = (left > 0).then(|| Value::new(first));
451        for offset in 0..u32::from(left) {
452            let index = u8::try_from(offset).expect("no more than the count it came from");
453            let value = Value::new(first + offset);
454            self.values[value.index()].def = Def::Result { inst, index };
455        }
456    }
457
458    /// Puts an instruction at the end of a block.
459    ///
460    /// # Panics
461    ///
462    /// Panics if the instruction is already in a block. Moving one is removing it and
463    /// appending it, and doing it by accident is how a linked list ends up in two pieces.
464    pub fn append_inst(&mut self, block: Block, inst: Inst) {
465        assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
466        let last = self.blocks[block.index()].last;
467        self.inst_layout[inst.index()] = InstLayout { block: Some(block), prev: last, next: None };
468        match last {
469            Some(last) => self.inst_layout[last.index()].next = Some(inst),
470            None => self.blocks[block.index()].first = Some(inst),
471        }
472        self.blocks[block.index()].last = Some(inst);
473        self.placed(inst);
474    }
475
476    /// Puts an instruction immediately before another one, in the block that one is in.
477    ///
478    /// # Panics
479    ///
480    /// Panics if `inst` is already in a block, or if `before` is not in one.
481    pub fn insert_before(&mut self, inst: Inst, before: Inst) {
482        assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
483        let at = self.inst_layout[before.index()];
484        let block = at.block.expect("the instruction to insert before is not in a block");
485        self.inst_layout[inst.index()] =
486            InstLayout { block: Some(block), prev: at.prev, next: Some(before) };
487        self.inst_layout[before.index()].prev = Some(inst);
488        match at.prev {
489            Some(prev) => self.inst_layout[prev.index()].next = Some(inst),
490            None => self.blocks[block.index()].first = Some(inst),
491        }
492        self.placed(inst);
493    }
494
495    /// Puts an instruction immediately after another one, in the block that one is in.
496    ///
497    /// The mirror of [`Func::insert_before`], and it exists because a pass that has to talk about
498    /// a value an instruction produced has nowhere else to put what it is adding. Check insertion
499    /// is the caller: `check_deriv` is handed the pointer the derivation produced, so it goes
500    /// after the derivation and no amount of rearranging moves it earlier.
501    ///
502    /// # Panics
503    ///
504    /// Panics if `inst` is already in a block, if `after` is not in one, or if `after` is the
505    /// block's terminator, since nothing may come between a terminator and the branch it is.
506    pub fn insert_after(&mut self, inst: Inst, after: Inst) {
507        assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
508        let at = self.inst_layout[after.index()];
509        let block = at.block.expect("the instruction to insert after is not in a block");
510        assert!(at.next.is_some(), "nothing goes after a terminator");
511        self.inst_layout[inst.index()] =
512            InstLayout { block: Some(block), prev: Some(after), next: at.next };
513        self.inst_layout[after.index()].next = Some(inst);
514        if let Some(next) = at.next {
515            self.inst_layout[next.index()].prev = Some(inst);
516        }
517        self.placed(inst);
518    }
519
520    /// Takes an instruction out of its block, leaving it and its results in the tables.
521    ///
522    /// The instruction is not deleted, because deleting it would move every instruction after
523    /// it. A removed instruction is unreachable from any block and is dropped when the whole
524    /// function is.
525    ///
526    /// # Panics
527    ///
528    /// Panics if the instruction is not in a block.
529    pub fn remove_inst(&mut self, inst: Inst) {
530        let at = self.inst_layout[inst.index()];
531        let block = at.block.expect("the instruction is not in a block");
532        match at.prev {
533            Some(prev) => self.inst_layout[prev.index()].next = at.next,
534            None => self.blocks[block.index()].first = at.next,
535        }
536        match at.next {
537            Some(next) => self.inst_layout[next.index()].prev = at.prev,
538            None => self.blocks[block.index()].last = at.prev,
539        }
540        self.inst_layout[inst.index()] = InstLayout::default();
541        // A start after this instruction is after wherever a pass that is moving it puts it, and
542        // after the instruction that was in front of it for a pass that is deleting it, which is the
543        // same place: nothing was between the two but this. Which of the two it is is not known
544        // yet, so the second answer is kept and [`Func::start_place`] asks in that order.
545        if self.anchors.contains(&inst) {
546            self.gone.insert(inst, (block, at.prev));
547            self.anchors.extend(at.prev);
548        }
549        // A declaration that held a result of this instruction was given it here, and once the
550        // instruction is gone nothing else says where that was. So it becomes a start at the same
551        // place, which is where the value it is renamed to, if it is, is the declaration's from.
552        // A pass that is moving the instruction puts it back, and then the names go back as they
553        // were, since a value computed somewhere else is still the declaration's from where it is
554        // computed.
555        let mut made = Vec::new();
556        for value in self.insts[inst.index()].results() {
557            for decl in self.held_from(value, block, at.prev) {
558                made.push((value, Start { decl, block, after: at.prev }));
559            }
560        }
561        if !made.is_empty() {
562            self.unplaced.insert(inst, made);
563        }
564    }
565
566    /// Whether a block is still one of this function's, which a block [`Func::remove_block`] took
567    /// out is not.
568    #[must_use]
569    pub fn is_placed(&self, block: Block) -> bool {
570        let data = &self.blocks[block.index()];
571        self.first_block == Some(block) || data.prev.is_some()
572    }
573
574    /// The block an instruction is in, or `None` if it has been removed from one.
575    #[must_use]
576    pub fn block_of(&self, inst: Inst) -> Option<Block> {
577        self.inst_layout[inst.index()].block
578    }
579
580    /// The version of memory an instruction reads, when the function carries memory SSA.
581    ///
582    /// Document 09 of `spec/optimizer`. Memory is a value of type `mem`, it is the last operand
583    /// of every instruction that touches memory, and it is absent in a function that does not
584    /// carry it, which is what `-O0` and `-O1` produce. Absent means unordered with respect to
585    /// everything, so a reader that gets `None` asks the alias analysis directly.
586    ///
587    /// The operand is last rather than first on purpose. Every other operand keeps the position
588    /// it had, so a pass that reads the address of a load as `args[0]` goes on working whether
589    /// or not memory has been threaded, and the only code that has to know about the extra
590    /// operand is this accessor and the verifier.
591    #[must_use]
592    pub fn mem_in(&self, inst: Inst) -> Option<Value> {
593        let args = &self[self[inst].args];
594        args.last().copied().filter(|&arg| self[arg].ty.is_mem())
595    }
596
597    /// The version of memory an instruction produces, when it writes memory and the function
598    /// carries memory SSA.
599    ///
600    /// Last among the results, for the reason [`Func::mem_in`] is last among the operands. A
601    /// `load` never has one, because it reads memory without changing it.
602    ///
603    /// Nothing reads the last version in a function, and that means nothing. A store whose
604    /// memory result has no reader is not dead, and what decides whether it is dead is dead
605    /// store elimination, which is document 17's.
606    #[must_use]
607    pub fn mem_out(&self, inst: Inst) -> Option<Value> {
608        self[inst].results().last().filter(|&result| self[result].ty.is_mem())
609    }
610
611    /// A bulk copy or fill taken apart, or nothing where the instruction is not one.
612    ///
613    /// The length is an operand on a bulk operation over an object whose length the program works
614    /// out and is [`MemInfo::size`] on every other one. Both shapes are here so that a pass which
615    /// asks this cannot read the payload's number on the one where it is not the count: what it
616    /// gets is the operand or nothing, and nothing is the only answer that means the payload.
617    ///
618    /// Memory is the last operand where the function carries it, which is why the length is found
619    /// by position from the front rather than from the back.
620    #[must_use]
621    pub fn bulk(&self, inst: Inst) -> Option<Bulk> {
622        if !matches!(self[inst].opcode, Opcode::Memcpy | Opcode::Memmove | Opcode::Memset) {
623            return None;
624        }
625        let all = &self[self[inst].args];
626        let args = &all[..all.len() - usize::from(self.mem_in(inst).is_some())];
627        let [to, with, rest @ ..] = args else { return None };
628        Some(Bulk { to: *to, with: *with, length: rest.first().copied() })
629    }
630
631    /// Whether an instruction has been threaded onto the memory chain.
632    #[must_use]
633    pub fn carries_mem(&self, inst: Inst) -> bool {
634        self.mem_in(inst).is_some() || self.mem_out(inst).is_some()
635    }
636
637    /// The same instruction with a version of memory threaded through it.
638    ///
639    /// A result cannot be added to an instruction that already exists, because the results of one
640    /// are values next to each other and there is no room after them. So threading memory makes a
641    /// new instruction and the caller puts it where the old one was, forwards the old results to
642    /// the new ones, which are at the same positions, and deletes the old one. That is what memory
643    /// SSA construction does in one pass over the function.
644    ///
645    /// The new instruction is not in any block. Its results are what the old one produced, in the
646    /// same order, and then the new version of memory where the opcode writes memory.
647    ///
648    /// # Panics
649    ///
650    /// Panics if `incoming` is not memory, if the instruction does not touch memory, or if it is
651    /// already on the chain. All three are a construction bug rather than bad input.
652    pub fn with_mem(&mut self, inst: Inst, incoming: Value) -> Inst {
653        assert!(self[incoming].ty.is_mem(), "the incoming version of memory is not memory");
654        assert!(self[inst].opcode.touches_memory(), "this does not touch memory");
655        assert!(self.mem_in(inst).is_none(), "this is already on the memory chain");
656        let data = self[inst];
657        let mut args = self[data.args].to_vec();
658        args.push(incoming);
659        let mut results: Vec<Type> = data.results().map(|result| self[result].ty).collect();
660        if data.opcode.writes_memory() {
661            results.push(Type::MEM);
662        }
663        let span = self.span(inst);
664        let args = self.push_values(&args);
665        self.create_inst(InstData { args, ..data }, &results, span)
666    }
667
668    /// The same instruction with the version of memory taken back off.
669    ///
670    /// The inverse of [`Func::with_mem`] and the same shape for the same reason: a result cannot be
671    /// taken off an instruction that already exists, so this makes a new one and the caller puts it
672    /// where the old one was, forwards the results it kept, which are at the same positions, and
673    /// deletes the old one. The memory result has no forwarding to do, because taking the chain off
674    /// is only ever done when nothing reads it any more.
675    ///
676    /// The new instruction is not in any block. Its results are what the old one produced without
677    /// the version of memory at the end of them.
678    ///
679    /// # Panics
680    ///
681    /// Panics if the instruction is not on the chain, which is a caller that did not look first.
682    pub fn without_mem(&mut self, inst: Inst) -> Inst {
683        assert!(self.carries_mem(inst), "this is not on the memory chain");
684        let data = self[inst];
685        let mut args = self[data.args].to_vec();
686        if self.mem_in(inst).is_some() {
687            args.pop();
688        }
689        let results: Vec<Type> =
690            data.results().map(|result| self[result].ty).filter(|ty| !ty.is_mem()).collect();
691        let span = self.span(inst);
692        let args = self.push_values(&args);
693        self.create_inst(InstData { args, ..data }, &results, span)
694    }
695
696    /// Where an instruction came from in the source.
697    #[must_use]
698    pub fn span(&self, inst: Inst) -> Span {
699        self.inst_spans[inst.index()]
700    }
701
702    /// Where an instruction branches to, which is empty when it does not branch.
703    ///
704    /// This is the one place that knows a `switch` keeps its targets in a side table and
705    /// `asm goto` in another one, so nothing walking the CFG has to.
706    pub fn successors(&self, inst: Inst) -> impl Iterator<Item = BlockCall> + use<'_> {
707        self.block_calls[self.target_list(inst).as_usize_range()].iter().copied()
708    }
709
710    /// Where a terminator keeps its targets, for something that edits them rather than reads
711    /// them.
712    ///
713    /// [`Func::successors`] is what walking the CFG wants. This is what recording an edge
714    /// wants, because an edge that will grow an argument later has to be named by its place in
715    /// the table rather than by the block it went to.
716    #[must_use]
717    pub fn target_list(&self, inst: Inst) -> BlockCallList {
718        match self[inst].extra {
719            Extra::Targets(targets) => targets,
720            Extra::Switch(info) => self.switches[info.index()].targets,
721            Extra::Asm(info) => self.asms[info.index()].targets,
722            _ => BlockCallList::EMPTY,
723        }
724    }
725
726    // The pools.
727
728    /// Records a run of value operands.
729    pub fn push_values(&mut self, values: &[Value]) -> ValueList {
730        let start = Idx::from_usize(self.value_pool.len());
731        self.value_pool.extend_from_slice(values);
732        ValueList::new(start, Idx::from_usize(self.value_pool.len()))
733    }
734
735    /// Adds one value to the end of a run, giving back the run it became.
736    ///
737    /// The run grows in place when nothing has been put after it, which is the case while a
738    /// list is being built. Otherwise it is copied to the end and the old space is left
739    /// behind, which is what makes adding a parameter to a loop header possible at all. That
740    /// happens once per value carried around a loop, so the copying is not what costs.
741    pub fn append_arg(&mut self, list: ValueList, value: Value) -> ValueList {
742        let range = list.as_usize_range();
743        if range.end == self.value_pool.len() {
744            self.value_pool.push(value);
745            return ValueList::new(Idx::from_usize(range.start), Idx::from_usize(range.end + 1));
746        }
747        let start = self.value_pool.len();
748        self.value_pool.extend_from_within(range);
749        self.value_pool.push(value);
750        ValueList::new(Idx::from_usize(start), Idx::from_usize(self.value_pool.len()))
751    }
752
753    /// Replaces the values in a run, which is what substituting one definition for another is.
754    ///
755    /// A run is a run whether it is an instruction's operands or a branch's arguments, so this
756    /// is the whole of the rewriting a substitution has to do.
757    pub fn rewrite(&mut self, list: ValueList, mut with: impl FnMut(Value) -> Value) {
758        for value in &mut self.value_pool[list.as_usize_range()] {
759            *value = with(*value);
760        }
761    }
762
763    /// Records a run of branch targets.
764    pub fn push_block_calls(&mut self, calls: &[BlockCall]) -> BlockCallList {
765        let start = Idx::from_usize(self.block_calls.len());
766        self.block_calls.extend_from_slice(calls);
767        BlockCallList::new(start, Idx::from_usize(self.block_calls.len()))
768    }
769
770    /// Replaces one branch target, which is what redirecting an edge is.
771    pub fn set_block_call(&mut self, at: Idx<BlockCall>, call: BlockCall) {
772        self.block_calls[at.index()] = call;
773    }
774
775    /// Records a run of case values.
776    pub fn push_imms(&mut self, imms: &[Imm]) -> ImmList {
777        let start = Idx::from_usize(self.imms.len());
778        self.imms.extend_from_slice(imms);
779        ImmList::new(start, Idx::from_usize(self.imms.len()))
780    }
781
782    /// Records a constant.
783    pub fn add_imm(&mut self, imm: Imm) -> Idx<Imm> {
784        self.imms.push(imm);
785        Idx::from_usize(self.imms.len() - 1)
786    }
787
788    /// Records where each eightbyte of an object travelled.
789    pub fn push_slots(&mut self, slots: &[Slot]) -> SlotList {
790        let start = Idx::from_usize(self.slots.len());
791        self.slots.extend_from_slice(slots);
792        SlotList::new(start, Idx::from_usize(self.slots.len()))
793    }
794
795    /// Records an object read off a variable argument list.
796    pub fn add_va_object(&mut self, info: VaInfo) -> Idx<VaInfo> {
797        self.va_objects.push(info);
798        Idx::from_usize(self.va_objects.len() - 1)
799    }
800
801    /// Records what an access does.
802    pub fn add_mem(&mut self, info: MemInfo) -> Idx<MemInfo> {
803        self.mem.push(info);
804        Idx::from_usize(self.mem.len() - 1)
805    }
806
807    /// Records what the ABI asks of the arguments a call's signature does not name.
808    pub fn push_abis(&mut self, abis: &[Abi]) -> AbiList {
809        let start = Idx::from_usize(self.abis.len());
810        self.abis.extend_from_slice(abis);
811        AbiList::new(start, Idx::from_usize(self.abis.len()))
812    }
813
814    /// Records a call's callee and signature.
815    pub fn add_call(&mut self, info: CallInfo) -> Idx<CallInfo> {
816        self.calls.push(info);
817        Idx::from_usize(self.calls.len() - 1)
818    }
819
820    /// Says how many of a call's arguments each C argument became, in order.
821    pub fn set_arg_groups(&mut self, call: Inst, groups: Vec<u32>) {
822        self.arg_groups.insert(call, groups);
823    }
824
825    /// How many of a call's arguments each C argument became, where the lowering said.
826    ///
827    /// `None` for almost every call, since the lowering only says it for a call that the inliner
828    /// might forward the arguments of. See [`Func::set_arg_groups`].
829    #[must_use]
830    pub fn arg_groups(&self, call: Inst) -> Option<&[u32]> {
831        self.arg_groups.get(&call).map(Vec::as_slice)
832    }
833
834    /// Records a `switch`'s targets and case values.
835    pub fn add_switch(&mut self, info: SwitchInfo) -> Idx<SwitchInfo> {
836        self.switches.push(info);
837        Idx::from_usize(self.switches.len() - 1)
838    }
839
840    /// Records an inline assembly instruction's template and constraints.
841    pub fn add_asm(&mut self, info: AsmInfo) -> Idx<AsmInfo> {
842        self.asms.push(info);
843        Idx::from_usize(self.asms.len() - 1)
844    }
845
846    /// How many values, instructions and blocks there are, for a reader that wants to size
847    /// something by them.
848    #[must_use]
849    pub fn counts(&self) -> Counts {
850        Counts { values: self.values.len(), insts: self.insts.len(), blocks: self.blocks.len() }
851    }
852
853    /// What is known about a value, which is nothing at all unless somebody said otherwise.
854    ///
855    /// Section 6.2.3 of `spec/safe-memory/06-instrumentation.md`. Facts are in a side table and
856    /// not in the value, so a function nobody has said anything about carries no facts and is
857    /// the same size it was before facts existed.
858    #[must_use]
859    pub fn facts(&self, value: Value) -> Facts {
860        match self.facts.binary_search_by_key(&value.raw(), |&(at, _)| at.raw()) {
861            Ok(at) => self.facts[at].1,
862            Err(_) => Facts::NONE,
863        }
864    }
865
866    /// Says what is known about a value, replacing whatever was known before.
867    ///
868    /// Setting [`Facts::NONE`] takes the value back out of the table, which is what keeps the
869    /// table empty in a function that has had facts put on and then taken off again.
870    pub fn set_facts(&mut self, value: Value, facts: Facts) {
871        let found = self.facts.binary_search_by_key(&value.raw(), |&(at, _)| at.raw());
872        match (found, facts.is_empty()) {
873            (Ok(at), true) => drop(self.facts.remove(at)),
874            (Ok(at), false) => self.facts[at].1 = facts,
875            (Err(_), true) => {}
876            (Err(at), false) => self.facts.insert(at, (value, facts)),
877        }
878    }
879
880    /// Every value something is known about, in value order.
881    pub fn known(&self) -> impl Iterator<Item = (Value, Facts)> + '_ {
882        self.facts.iter().copied()
883    }
884
885    /// Gives a block a name of its own, which is how an image written before the program runs
886    /// says it holds the address of a place inside this function.
887    ///
888    /// What asks for this is GNU's address of a label in the initializer of an object with static
889    /// storage duration, which is how every threaded interpreter builds its dispatch table. The
890    /// address a `lea` produces needs none of this, because both ends of that distance are in the
891    /// same section and the object writer works it out for itself. An image is the other case: it
892    /// is in another section, so what it holds is a relocation, and a relocation names a symbol.
893    ///
894    /// One name per block. Two labels on the same statement are two labels and one block, and the
895    /// image asks for a name rather than for a particular one, so the second ask keeps the first
896    /// answer. Nothing outside this table ever sees the name, which is why it may be anything the
897    /// object format lets a local symbol be called.
898    pub fn name_block(&mut self, block: Block, name: Symbol) {
899        let found = self.labels.binary_search_by_key(&block.raw(), |&(at, _)| at.raw());
900        if let Err(at) = found {
901            self.labels.insert(at, (block, name));
902        }
903    }
904
905    /// The name a block was given, or `None` for a block nothing took the address of.
906    #[must_use]
907    pub fn block_name(&self, block: Block) -> Option<Symbol> {
908        match self.labels.binary_search_by_key(&block.raw(), |&(at, _)| at.raw()) {
909            Ok(at) => Some(self.labels[at].1),
910            Err(_) => None,
911        }
912    }
913
914    /// Every block that has a name, in block order.
915    pub fn named_blocks(&self) -> impl Iterator<Item = (Block, Symbol)> + '_ {
916        self.labels.iter().copied()
917    }
918
919    /// Says which declaration in the source a piece of memory was made for, which is how a build
920    /// that was asked for debugging information ends up able to print a local by its name.
921    ///
922    /// The number is whatever the front end counts declarations by and means nothing here. This
923    /// crate sits below the one that has a type for it, and inventing a second name for the same
924    /// thing so that it could be spelled out here would buy nothing: nothing between the front end
925    /// that writes the number and the back end that hands it back reads it.
926    ///
927    /// On the memory rather than on the `alloca` that asks for it because the memory is what
928    /// survives. An instruction is rewritten, moved and renumbered by every pass it goes through,
929    /// and [`MemInfo`] is appended to and never reordered, so the number an access carries today is
930    /// the number it carries at the end.
931    ///
932    /// One declaration per piece of memory, and the first ask wins. Nothing asks twice.
933    pub fn declare_mem(&mut self, mem: Idx<MemInfo>, decl: u32) {
934        let found = self.mem_decls.binary_search_by_key(&mem.raw(), |&(at, _)| at.raw());
935        if let Err(at) = found {
936            self.mem_decls.insert(at, (mem, decl));
937        }
938    }
939
940    /// The declaration a piece of memory was made for, or `None` for memory no declaration in the
941    /// source asked for, which is every temporary and every spill.
942    #[must_use]
943    pub fn mem_decl(&self, mem: Idx<MemInfo>) -> Option<u32> {
944        match self.mem_decls.binary_search_by_key(&mem.raw(), |&(at, _)| at.raw()) {
945            Ok(at) => Some(self.mem_decls[at].1),
946            Err(_) => None,
947        }
948    }
949
950    /// Says which declaration in the source a value is a value of, which is the other half of
951    /// [`Func::declare_mem`].
952    ///
953    /// A local whose address is never taken has no memory to put the number on, because nothing
954    /// asked for any, and what holds it is a value the SSA construction worked out.
955    ///
956    /// One declaration is many values. Every assignment to it makes one, and so does every block
957    /// parameter that collects two of them where control joins. One value can be more than one
958    /// declaration as well, because a pass that finds two values equal points the readers of one at
959    /// the other, and both names then mean the one that is left. Neither of those is a mistake to
960    /// be ruled out here, so this is a list of pairs rather than a map in either direction.
961    ///
962    /// What the pairs do not say is which of a declaration's values it holds at a given address,
963    /// and nothing in this crate can say it. That is a question about where the definitions ended
964    /// up in the code that came out and how long each of them survived there, which the back end
965    /// knows and the IR does not.
966    pub fn declare_value(&mut self, value: Value, decl: u32) {
967        let key = (value.raw(), decl);
968        let found = self.value_decls.binary_search_by_key(&key, |&(at, decl)| (at.raw(), decl));
969        if let Err(at) = found {
970            self.value_decls.insert(at, (value, decl));
971        }
972    }
973
974    /// Every declaration a value is a value of, in the order the front end numbered them.
975    ///
976    /// Empty for a value no declaration in the source is behind, which is most of them: every
977    /// temporary an expression needed, every address computed on the way to a member, and every
978    /// result of a rule the peephole applied.
979    pub fn value_decls(&self, value: Value) -> impl Iterator<Item = u32> + '_ {
980        let at = self.value_decls.partition_point(|&(held, _)| held.raw() < value.raw());
981        self.value_decls[at..]
982            .iter()
983            .take_while(move |&&(held, _)| held == value)
984            .map(|&(_, decl)| decl)
985    }
986
987    /// Moves every declaration one value is a value of onto another value.
988    ///
989    /// What a pass that found two values equal does about the names. It points the readers of one
990    /// at the other and the one it pointed away from is about to be nobody's, so the names go with
991    /// the readers: the declaration still holds the value it held, and the value is now spelled the
992    /// other way. Where the value going away is still defined, the declarations that held it are
993    /// turned into starts at that definition first, since the value left may have been computed
994    /// earlier and the declaration was not given it any sooner for that. A pass that deletes a
995    /// value without giving its readers somewhere else to look is
996    /// a pass that deleted something nothing reads, and a declaration whose value went that way is
997    /// one the back end will have nothing to say about over those addresses, which is the right
998    /// answer rather than a lost one.
999    pub fn rename_value(&mut self, from: Value, to: Value) {
1000        if from == to {
1001            return;
1002        }
1003        // The value left is usually one computed earlier, and a declaration that held the one going
1004        // away was given it where that one was computed and not before. See [`Func::held_from`].
1005        match self.values[from.index()].def {
1006            Def::Result { inst, .. } => {
1007                let at = self.inst_layout[inst.index()];
1008                if let Some(block) = at.block {
1009                    self.held_from(from, block, at.prev);
1010                }
1011            }
1012            Def::Param { block, index } => {
1013                let param = usize::try_from(index)
1014                    .ok()
1015                    .and_then(|index| self.blocks[block.index()].params.get(index).copied());
1016                if param == Some(from) {
1017                    self.held_from(from, block, None);
1018                }
1019            }
1020        }
1021        let at = self.value_decls.partition_point(|&(held, _)| held.raw() < from.raw());
1022        let end = at + self.value_decls[at..].iter().take_while(|&&(held, _)| held == from).count();
1023        let moving: Vec<u32> = self.value_decls.drain(at..end).map(|(_, decl)| decl).collect();
1024        for decl in moving {
1025            self.declare_value(to, decl);
1026        }
1027        let at = self.value_starts.partition_point(|&(held, _)| held.raw() < from.raw());
1028        let end =
1029            at + self.value_starts[at..].iter().take_while(|&&(held, _)| held == from).count();
1030        let moving: Vec<Start> = self.value_starts.drain(at..end).map(|(_, start)| start).collect();
1031        for start in moving {
1032            self.declare_value_from(to, start);
1033        }
1034    }
1035
1036    /// Says that a declaration holds a value from a point in a block onward, rather than from
1037    /// where the value was computed.
1038    ///
1039    /// What `int m = a;` is. The assignment computes nothing, so the value `m` is given is one
1040    /// `a` already holds, and naming it with [`Func::declare_value`] would say `m` held it from
1041    /// wherever `a` was written. This says where the assignment was instead, as the instruction in
1042    /// front of it, or `None` for one at the top of the block.
1043    ///
1044    /// A pass that moves that instruction moves the start with it, and one that deletes it leaves
1045    /// the start after the one that was in front of it, which is the same place. A block that is
1046    /// taken out takes its starts with it, and the back end reads those as saying nothing rather
1047    /// than guess. See [`Func::start_place`].
1048    pub fn declare_value_from(&mut self, value: Value, start: Start) {
1049        let at = self.value_starts.partition_point(|&(held, _)| held.raw() <= value.raw());
1050        if !self.value_starts[..at]
1051            .iter()
1052            .rev()
1053            .take_while(|&&(held, _)| held == value)
1054            .any(|&(_, have)| have == start)
1055        {
1056            self.value_starts.insert(at, (value, start));
1057            self.anchors.extend(start.after);
1058        }
1059    }
1060
1061    /// Every place a declaration starts holding a value part of the way through, in the order they
1062    /// were said. See [`Func::declare_value_from`].
1063    pub fn value_starts(&self, value: Value) -> impl Iterator<Item = Start> + '_ {
1064        let at = self.value_starts.partition_point(|&(held, _)| held.raw() < value.raw());
1065        self.value_starts[at..]
1066            .iter()
1067            .take_while(move |&&(held, _)| held == value)
1068            .map(|&(_, start)| start)
1069    }
1070
1071    /// Hands some of the starts on one value over to another, for a pass that gives part of the
1072    /// function a value of its own in place of one it read before.
1073    ///
1074    /// The starts are the ones in `which` that `from` has, and the rest stay where they are. A
1075    /// start is a place in the function, so one in the part that now reads `into` is a place the
1076    /// declaration was given `into`, and one left on `from` there would say the declaration holds
1077    /// whatever `from` turns into later.
1078    pub fn move_starts(&mut self, from: Value, into: Value, which: &[Start]) {
1079        if from == into {
1080            return;
1081        }
1082        let at = self.value_starts.partition_point(|&(held, _)| held.raw() < from.raw());
1083        let end =
1084            at + self.value_starts[at..].iter().take_while(|&&(held, _)| held == from).count();
1085        let (moving, staying): (Vec<Start>, Vec<Start>) = self
1086            .value_starts
1087            .drain(at..end)
1088            .map(|(_, start)| start)
1089            .partition(|start| which.contains(start));
1090        let at = self.value_starts.partition_point(|&(held, _)| held.raw() < from.raw());
1091        self.value_starts.splice(at..at, staying.into_iter().map(|start| (from, start)));
1092        for start in moving {
1093            self.declare_value_from(into, start);
1094        }
1095    }
1096
1097    /// Turns every declaration that holds a value from where it was computed into one that holds it
1098    /// from a place, for a value whose definition is about to stop saying where that was.
1099    ///
1100    /// A pass that takes out the instruction that computed a value, drops the block parameter it
1101    /// arrived as, or points its readers at another value, leaves the declarations behind it with
1102    /// nothing that says where they were given it. The place is the same place, the instruction in
1103    /// front of the definition or the top of the block, so what the declaration holds and from
1104    /// where is unchanged, and it now survives the value being renamed to one computed earlier.
1105    fn held_from(&mut self, value: Value, block: Block, after: Option<Inst>) -> Vec<u32> {
1106        let at = self.value_decls.partition_point(|&(held, _)| held.raw() < value.raw());
1107        let end =
1108            at + self.value_decls[at..].iter().take_while(|&&(held, _)| held == value).count();
1109        let moving: Vec<u32> = self.value_decls.drain(at..end).map(|(_, decl)| decl).collect();
1110        for &decl in &moving {
1111            self.declare_value_from(value, Start { decl, block, after });
1112        }
1113        moving
1114    }
1115
1116    /// Turns the starts [`Func::remove_inst`] made for an instruction back into names, now that it
1117    /// is in a block again.
1118    fn placed(&mut self, inst: Inst) {
1119        if self.unplaced.is_empty() {
1120            return;
1121        }
1122        let Some(made) = self.unplaced.remove(&inst) else { return };
1123        for (value, start) in made {
1124            let at = self.value_starts.partition_point(|&(held, _)| held.raw() < value.raw());
1125            let found = self.value_starts[at..]
1126                .iter()
1127                .take_while(|&&(held, _)| held == value)
1128                .position(|&(_, have)| have == start);
1129            // Gone when a pass renamed the value away before putting the instruction back, and
1130            // then the name went with the readers and is not this value's to have back.
1131            if let Some(found) = found {
1132                self.value_starts.remove(at + found);
1133                self.declare_value(value, start.decl);
1134            }
1135        }
1136    }
1137
1138    /// Where a start is now, as the block and the instruction it is after, or `None` for one in a
1139    /// block a pass took out.
1140    ///
1141    /// The instruction it is after says, where it is still in a block, since a pass that moves
1142    /// that instruction moves the assignment with it. One a pass deleted is where it was, which
1143    /// is after the instruction that was in front of it then, and so on back to one that is still
1144    /// there or to the top of the block. A start at the top of a block is there for as long as
1145    /// the block is in the function.
1146    #[must_use]
1147    pub fn start_place(&self, start: Start) -> Option<(Block, Option<Inst>)> {
1148        let (mut block, mut after) = (start.block, start.after);
1149        loop {
1150            let Some(inst) = after else {
1151                return self.is_placed(block).then_some((block, None));
1152            };
1153            if let Some(now) = self.block_of(inst) {
1154                return Some((now, Some(inst)));
1155            }
1156            (block, after) = *self.gone.get(&inst)?;
1157        }
1158    }
1159
1160    /// Moves the starts at the top of one block to after an instruction in another, for a pass
1161    /// that is emptying the first into the second and taking it out.
1162    ///
1163    /// The top of the block it empties is the place right after `after` once the instructions
1164    /// have gone in behind it, or the top of `into` for `None`, and nothing else can say that,
1165    /// because the block the start was in is about to stop being one.
1166    pub fn carry_starts(&mut self, from: Block, into: Block, after: Option<Inst>) {
1167        let unplaced = self.unplaced.values_mut().flatten().map(|(_, start)| start);
1168        for start in self.value_starts.iter_mut().map(|(_, start)| start).chain(unplaced) {
1169            if start.block == from && start.after.is_none() {
1170                *start = Start { block: into, after, ..*start };
1171            }
1172        }
1173        for place in self.gone.values_mut() {
1174            if *place == (from, None) {
1175                *place = (into, after);
1176            }
1177        }
1178        self.anchors.extend(after);
1179    }
1180
1181    fn add_value(&mut self, data: ValueData) -> Value {
1182        self.values.push(data);
1183        Idx::from_usize(self.values.len() - 1)
1184    }
1185}
1186
1187/// Where a declaration starts holding a value, when that is not where the value was computed.
1188///
1189/// The block and the instruction in front of the assignment, because an assignment that computes
1190/// nothing is not an instruction and the one in front of it is the nearest thing that is. The block
1191/// is carried for a start at the top of one, and for the rest it is where the start was made, since
1192/// a pass can move the instruction to another block. [`Func::start_place`] says where it is now.
1193#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1194pub struct Start {
1195    /// The declaration, in whatever numbering the front end gave it.
1196    pub decl: u32,
1197    /// The block the assignment is in.
1198    pub block: Block,
1199    /// The instruction in front of the assignment, or `None` for one at the top of the block.
1200    pub after: Option<Inst>,
1201}
1202
1203/// How many of each thing a function holds.
1204#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1205pub struct Counts {
1206    /// Values, including the ones whose defining instruction has been removed.
1207    pub values: usize,
1208    /// Instructions, including the ones that have been removed from their block.
1209    pub insts: usize,
1210    /// Blocks.
1211    pub blocks: usize,
1212}
1213
1214// Reading is indexing. There is one of these for each handle, so `func[inst]` and `func[value]`
1215// and `&func[args]` all work and none of them needs a method whose name says which table.
1216impl Index<Value> for Func {
1217    type Output = ValueData;
1218
1219    fn index(&self, value: Value) -> &ValueData {
1220        &self.values[value.index()]
1221    }
1222}
1223
1224impl Index<Inst> for Func {
1225    type Output = InstData;
1226
1227    fn index(&self, inst: Inst) -> &InstData {
1228        &self.insts[inst.index()]
1229    }
1230}
1231
1232impl IndexMut<Inst> for Func {
1233    fn index_mut(&mut self, inst: Inst) -> &mut InstData {
1234        &mut self.insts[inst.index()]
1235    }
1236}
1237
1238impl Index<Block> for Func {
1239    type Output = BlockData;
1240
1241    fn index(&self, block: Block) -> &BlockData {
1242        &self.blocks[block.index()]
1243    }
1244}
1245
1246impl Index<Sig> for Func {
1247    type Output = Signature;
1248
1249    fn index(&self, sig: Sig) -> &Signature {
1250        &self.signatures[sig.index()]
1251    }
1252}
1253
1254impl Index<ValueList> for Func {
1255    type Output = [Value];
1256
1257    fn index(&self, list: ValueList) -> &[Value] {
1258        &self.value_pool[list.as_usize_range()]
1259    }
1260}
1261
1262impl Index<BlockCallList> for Func {
1263    type Output = [BlockCall];
1264
1265    fn index(&self, list: BlockCallList) -> &[BlockCall] {
1266        &self.block_calls[list.as_usize_range()]
1267    }
1268}
1269
1270impl Index<Idx<BlockCall>> for Func {
1271    type Output = BlockCall;
1272
1273    fn index(&self, at: Idx<BlockCall>) -> &BlockCall {
1274        &self.block_calls[at.index()]
1275    }
1276}
1277
1278impl Index<ImmList> for Func {
1279    type Output = [Imm];
1280
1281    fn index(&self, list: ImmList) -> &[Imm] {
1282        &self.imms[list.as_usize_range()]
1283    }
1284}
1285
1286impl Index<Idx<Imm>> for Func {
1287    type Output = Imm;
1288
1289    fn index(&self, at: Idx<Imm>) -> &Imm {
1290        &self.imms[at.index()]
1291    }
1292}
1293
1294impl Index<Idx<MemInfo>> for Func {
1295    type Output = MemInfo;
1296
1297    fn index(&self, at: Idx<MemInfo>) -> &MemInfo {
1298        &self.mem[at.index()]
1299    }
1300}
1301
1302impl Index<AbiList> for Func {
1303    type Output = [Abi];
1304
1305    fn index(&self, list: AbiList) -> &[Abi] {
1306        &self.abis[list.as_usize_range()]
1307    }
1308}
1309
1310impl Index<SlotList> for Func {
1311    type Output = [Slot];
1312
1313    fn index(&self, list: SlotList) -> &[Slot] {
1314        &self.slots[list.as_usize_range()]
1315    }
1316}
1317
1318impl Index<Idx<VaInfo>> for Func {
1319    type Output = VaInfo;
1320
1321    fn index(&self, at: Idx<VaInfo>) -> &VaInfo {
1322        &self.va_objects[at.index()]
1323    }
1324}
1325
1326impl Index<Idx<CallInfo>> for Func {
1327    type Output = CallInfo;
1328
1329    fn index(&self, at: Idx<CallInfo>) -> &CallInfo {
1330        &self.calls[at.index()]
1331    }
1332}
1333
1334impl Index<Idx<SwitchInfo>> for Func {
1335    type Output = SwitchInfo;
1336
1337    fn index(&self, at: Idx<SwitchInfo>) -> &SwitchInfo {
1338        &self.switches[at.index()]
1339    }
1340}
1341
1342impl Index<Idx<AsmInfo>> for Func {
1343    type Output = AsmInfo;
1344
1345    fn index(&self, at: Idx<AsmInfo>) -> &AsmInfo {
1346        &self.asms[at.index()]
1347    }
1348}
1349
1350/// A cursor that appends to the end of one block.
1351///
1352/// This is the shape lowering wants: it works on one block at a time, it appends, and it wants
1353/// the value back so it can use it in the next instruction. Everything here is a thin wrapper
1354/// over [`Func::create_inst`] and [`Func::append_inst`], and anything the wrappers do not
1355/// cover is done with those two directly.
1356#[derive(Debug)]
1357pub struct Builder<'a> {
1358    func: &'a mut Func,
1359    block: Block,
1360    span: Span,
1361}
1362
1363impl<'a> Builder<'a> {
1364    /// A cursor appending to that block, with every instruction taking that source location.
1365    pub fn new(func: &'a mut Func, block: Block) -> Self {
1366        Self { func, block, span: Span::DUMMY }
1367    }
1368
1369    /// The same cursor, with a source location for the instructions after this.
1370    #[must_use]
1371    pub fn at(mut self, span: Span) -> Self {
1372        self.span = span;
1373        self
1374    }
1375
1376    /// Sets the source location for the instructions after this.
1377    pub fn set_span(&mut self, span: Span) {
1378        self.span = span;
1379    }
1380
1381    /// The function being built.
1382    pub fn func(&mut self) -> &mut Func {
1383        self.func
1384    }
1385
1386    /// The block being appended to.
1387    #[must_use]
1388    pub fn block(&self) -> Block {
1389        self.block
1390    }
1391
1392    /// Appends an instruction as it is, and gives back its results.
1393    pub fn inst(&mut self, data: InstData, results: &[Type]) -> Inst {
1394        let inst = self.func.create_inst(data, results, self.span);
1395        self.func.append_inst(self.block, inst);
1396        inst
1397    }
1398
1399    /// The one value an instruction produces.
1400    ///
1401    /// # Panics
1402    ///
1403    /// Panics if it did not produce exactly one.
1404    pub fn value(&mut self, data: InstData, ty: Type) -> Value {
1405        let inst = self.inst(data, &[ty]);
1406        self.func[inst].first_result.expect("one result was asked for")
1407    }
1408
1409    /// An integer constant.
1410    ///
1411    /// # Panics
1412    ///
1413    /// Panics if `ty` is not an integer type.
1414    pub fn iconst(&mut self, ty: Type, value: i128) -> Value {
1415        let imm = self.func.add_imm(Imm::int(value, ty.lane()));
1416        self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::IConst) }, ty)
1417    }
1418
1419    /// A floating point constant, given as the bits of its format.
1420    pub fn fconst(&mut self, ty: Type, bits: u128) -> Value {
1421        let imm = self.func.add_imm(Imm::from_bits(bits));
1422        self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::FConst) }, ty)
1423    }
1424
1425    /// A two-operand instruction whose result has the type of its operands.
1426    pub fn binary(&mut self, opcode: Opcode, lhs: Value, rhs: Value, flags: Flags) -> Value {
1427        let ty = self.func[lhs].ty;
1428        let args = self.func.push_values(&[lhs, rhs]);
1429        self.value(InstData { args, flags, ..InstData::new(opcode) }, ty)
1430    }
1431
1432    /// Arithmetic that answers with both the wrapped result and whether it wrapped.
1433    ///
1434    /// The one shape in the IR whose result is two things, which is why it has a builder of its
1435    /// own rather than going through [`Builder::value`]. The first result is the answer in the
1436    /// type of the operands, the same as the ordinary form of the same arithmetic would give, and
1437    /// the second is one `i1` per lane saying whether the exact answer needed more bits than that
1438    /// type has.
1439    ///
1440    /// # Panics
1441    ///
1442    /// Panics if the instruction did not produce exactly the two results it was created with,
1443    /// which is the same promise [`Builder::value`] makes about its one.
1444    pub fn checked(&mut self, opcode: Opcode, lhs: Value, rhs: Value) -> (Value, Value) {
1445        let ty = self.func[lhs].ty;
1446        let args = self.func.push_values(&[lhs, rhs]);
1447        let results = [ty, ty.with_lane(Type::I1)];
1448        let inst = self.inst(InstData { args, ..InstData::new(opcode) }, &results);
1449        let mut answers = self.func[inst].results();
1450        let value = answers.next().expect("two results were asked for");
1451        let wrapped = answers.next().expect("two results were asked for");
1452        (value, wrapped)
1453    }
1454
1455    /// A one-operand instruction whose result has the type given.
1456    pub fn unary(&mut self, opcode: Opcode, arg: Value, ty: Type) -> Value {
1457        let args = self.func.push_values(&[arg]);
1458        self.value(InstData { args, ..InstData::new(opcode) }, ty)
1459    }
1460
1461    /// An integer comparison, which produces one `i1` per lane.
1462    pub fn icmp(&mut self, pred: IntPred, lhs: Value, rhs: Value) -> Value {
1463        let ty = self.func[lhs].ty.with_lane(Type::I1);
1464        let args = self.func.push_values(&[lhs, rhs]);
1465        self.value(
1466            InstData { args, extra: Extra::IntPred(pred), ..InstData::new(Opcode::ICmp) },
1467            ty,
1468        )
1469    }
1470
1471    /// One of two values, chosen by a bit, which is what a diamond becomes when it stops being one.
1472    ///
1473    /// The type comes from the arms rather than from the bit, and the two arms have to agree, which
1474    /// the verifier checks. Both are evaluated, so the caller owes the argument that evaluating the
1475    /// one that is not chosen is harmless.
1476    pub fn select(&mut self, cond: Value, then: Value, other: Value) -> Value {
1477        let ty = self.func[then].ty;
1478        let args = self.func.push_values(&[cond, then, other]);
1479        self.value(InstData { args, ..InstData::new(Opcode::Select) }, ty)
1480    }
1481
1482    /// A floating point comparison, which produces one `i1` per lane.
1483    pub fn fcmp(&mut self, pred: FloatPred, lhs: Value, rhs: Value, flags: Flags) -> Value {
1484        let ty = self.func[lhs].ty.with_lane(Type::I1);
1485        let args = self.func.push_values(&[lhs, rhs]);
1486        self.value(
1487            InstData { args, flags, extra: Extra::FloatPred(pred), ..InstData::new(Opcode::FCmp) },
1488            ty,
1489        )
1490    }
1491
1492    /// Memory as the function found it, which is where a memory SSA chain starts.
1493    ///
1494    /// It belongs at the top of the entry block and there is one of them in a function.
1495    pub fn mem_entry(&mut self) -> Value {
1496        self.value(InstData::new(Opcode::MemEntry), Type::MEM)
1497    }
1498
1499    /// A read of that type from that address.
1500    pub fn load(&mut self, ty: Type, addr: Value, info: MemInfo, flags: Flags) -> Value {
1501        let mem = self.func.add_mem(info);
1502        let args = self.func.push_values(&[addr]);
1503        self.value(
1504            InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Load) },
1505            ty,
1506        )
1507    }
1508
1509    /// A write of a value to an address.
1510    pub fn store(&mut self, value: Value, addr: Value, info: MemInfo, flags: Flags) -> Inst {
1511        let mem = self.func.add_mem(info);
1512        let args = self.func.push_values(&[value, addr]);
1513        self.inst(
1514            InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Store) },
1515            &[],
1516        )
1517    }
1518
1519    /// The same read, ordered.
1520    ///
1521    /// A separate opcode rather than an ordering on [`Builder::load`], because the two are not the
1522    /// same thing to anything that moves code: a plain load may be moved, duplicated and dropped,
1523    /// and this one may not. The IR verifier is what keeps the pair honest, since it refuses an
1524    /// ordering on a plain access and refuses an unordered one here, so no pass has to remember to
1525    /// check the payload before deciding a load is free.
1526    pub fn atomic_load(&mut self, ty: Type, addr: Value, info: MemInfo, flags: Flags) -> Value {
1527        let mem = self.func.add_mem(info);
1528        let args = self.func.push_values(&[addr]);
1529        self.value(
1530            InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::AtomicLoad) },
1531            ty,
1532        )
1533    }
1534
1535    /// The same write, ordered.
1536    pub fn atomic_store(&mut self, value: Value, addr: Value, info: MemInfo, flags: Flags) -> Inst {
1537        let mem = self.func.add_mem(info);
1538        let args = self.func.push_values(&[value, addr]);
1539        self.inst(
1540            InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::AtomicStore) },
1541            &[],
1542        )
1543    }
1544
1545    /// A compare and exchange, which answers what it found and whether that was what was expected.
1546    ///
1547    /// Two values out of one instruction, in that order, because a caller that had to ask twice
1548    /// would be asking about two different moments. The type of the first is the type of the value
1549    /// expected, which is what says how wide the access is, and the type of the second is
1550    /// [`Type::I1`] whatever the width was.
1551    pub fn cmpxchg(
1552        &mut self,
1553        addr: Value,
1554        expected: Value,
1555        desired: Value,
1556        info: MemInfo,
1557        flags: Flags,
1558    ) -> (Value, Value) {
1559        let ty = self.func[expected].ty;
1560        let mem = self.func.add_mem(info);
1561        let args = self.func.push_values(&[addr, expected, desired]);
1562        let inst = self.inst(
1563            InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Cmpxchg) },
1564            &[ty, Type::I1],
1565        );
1566        let results: Vec<Value> = self.func[inst].results().collect();
1567        let [old, exchanged] = results[..] else { unreachable!("two results were asked for") };
1568        (old, exchanged)
1569    }
1570
1571    /// A read, an operation on what was read, and a write back, with nothing able to get between
1572    /// them.
1573    ///
1574    /// The value it answers is the one that was there before, which is the convention every machine
1575    /// and every language in this area uses, and a caller that wanted the value afterwards works it
1576    /// out from the two it already has rather than asking for a second flavour of the instruction.
1577    /// The type of that value is the type of the operand, which is what says how wide the access is.
1578    pub fn atomic_rmw(
1579        &mut self,
1580        op: RmwOp,
1581        addr: Value,
1582        operand: Value,
1583        info: MemInfo,
1584        flags: Flags,
1585    ) -> Value {
1586        let ty = self.func[operand].ty;
1587        let mem = self.func.add_mem(info);
1588        let args = self.func.push_values(&[addr, operand]);
1589        self.value(
1590            InstData {
1591                args,
1592                flags,
1593                extra: Extra::Rmw(op, mem),
1594                ..InstData::new(Opcode::AtomicRmw)
1595            },
1596            ty,
1597        )
1598    }
1599
1600    /// A barrier, which touches no address and is its ordering and nothing else.
1601    pub fn fence(&mut self, order: MemOrder) -> Inst {
1602        self.inst(InstData { extra: Extra::Order(order), ..InstData::new(Opcode::Fence) }, &[])
1603    }
1604
1605    /// A hint that an address is about to be read or written, which produces nothing.
1606    ///
1607    /// It reads the address rather than the memory at it, in the sense that nothing after this
1608    /// sees anything it did not see before. What it is allowed to do is take time, so it is on the
1609    /// memory chain anyway: a prefetch of an address a store is about to write to has to stay on
1610    /// the side of that store it was written on, or it is a hint about the wrong thing.
1611    pub fn prefetch(&mut self, address: Value, hint: PrefetchHint) -> Inst {
1612        let args = self.func.push_values(&[address]);
1613        self.inst(
1614            InstData { args, extra: Extra::Prefetch(hint), ..InstData::new(Opcode::Prefetch) },
1615            &[],
1616        )
1617    }
1618
1619    /// An unconditional branch.
1620    pub fn jump(&mut self, target: Block, args: &[Value]) -> Inst {
1621        let call = self.block_call(target, args);
1622        let targets = self.func.push_block_calls(&[call]);
1623        self.inst(InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::Jump) }, &[])
1624    }
1625
1626    /// The address of a block, which is a value a later `indirect_br` can branch to.
1627    ///
1628    /// The block is a target here in the same sense a branch's is, so everything that asks an
1629    /// instruction which blocks it names finds this one, and a block whose address is taken is
1630    /// not mistaken for a block nothing mentions.
1631    pub fn block_addr(&mut self, target: Block) -> Value {
1632        let call = self.block_call(target, &[]);
1633        let targets = self.func.push_block_calls(&[call]);
1634        self.value(
1635            InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::BlockAddr) },
1636            Type::PTR,
1637        )
1638    }
1639
1640    /// A branch to an address, which arrives at one of the blocks listed.
1641    ///
1642    /// Every block the address can hold has to be there. The list is what the rest of the
1643    /// compiler reads, so a block left out of it is a block the branch is saying it never
1644    /// reaches, and none of it is checked against the addresses anybody took.
1645    pub fn indirect_br(&mut self, addr: Value, targets: &[Block]) -> Inst {
1646        let calls: Vec<BlockCall> =
1647            targets.iter().map(|&target| self.block_call(target, &[])).collect();
1648        let targets = self.func.push_block_calls(&calls);
1649        let args = self.func.push_values(&[addr]);
1650        self.inst(
1651            InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::IndirectBr) },
1652            &[],
1653        )
1654    }
1655
1656    /// A two-way branch, taking the first target when the condition is one.
1657    pub fn br_if(
1658        &mut self,
1659        cond: Value,
1660        then_block: Block,
1661        then_args: &[Value],
1662        else_block: Block,
1663        else_args: &[Value],
1664    ) -> Inst {
1665        let then_call = self.block_call(then_block, then_args);
1666        let else_call = self.block_call(else_block, else_args);
1667        let targets = self.func.push_block_calls(&[then_call, else_call]);
1668        let args = self.func.push_values(&[cond]);
1669        self.inst(
1670            InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::BrIf) },
1671            &[],
1672        )
1673    }
1674
1675    /// A branch on an integer, taking the target its value selects and the default when it
1676    /// selects none.
1677    ///
1678    /// The cases are values and blocks rather than a table with the default in it, because the
1679    /// order the side table wants, which is the default first, is not an order anybody building
1680    /// a `switch` has their cases in.
1681    pub fn switch(&mut self, value: Value, default: Block, cases: &[(i128, Block)]) -> Inst {
1682        let ty = self.func[value].ty.lane();
1683        let mut calls = vec![self.block_call(default, &[])];
1684        let mut values = Vec::with_capacity(cases.len());
1685        for &(value, block) in cases {
1686            calls.push(self.block_call(block, &[]));
1687            values.push(Imm::int(value, ty));
1688        }
1689        let targets = self.func.push_block_calls(&calls);
1690        let cases = self.func.push_imms(&values);
1691        let info = self.func.add_switch(SwitchInfo { targets, cases });
1692        let args = self.func.push_values(&[value]);
1693        self.inst(
1694            InstData { args, extra: Extra::Switch(info), ..InstData::new(Opcode::Switch) },
1695            &[],
1696        )
1697    }
1698
1699    /// A return of the values the signature says.
1700    pub fn ret(&mut self, values: &[Value]) -> Inst {
1701        let args = self.func.push_values(values);
1702        self.inst(InstData { args, ..InstData::new(Opcode::Return) }, &[])
1703    }
1704
1705    /// A place control does not reach.
1706    pub fn unreachable(&mut self) -> Inst {
1707        self.inst(InstData::new(Opcode::Unreachable), &[])
1708    }
1709
1710    /// A direct call, with the results its signature says it produces.
1711    pub fn call(&mut self, callee: Symbol, signature: Sig, args: &[Value]) -> Inst {
1712        self.call_varargs(callee, signature, args, &[])
1713    }
1714
1715    /// The same, saying how the arguments the signature does not name travel.
1716    ///
1717    /// Empty says they all travel as the values in hand, which is what [`Builder::call`] passes
1718    /// and is the usual case. Anything else has one entry for each argument past the ones the
1719    /// signature names.
1720    pub fn call_varargs(
1721        &mut self,
1722        callee: Symbol,
1723        signature: Sig,
1724        args: &[Value],
1725        varargs: &[Abi],
1726    ) -> Inst {
1727        let varargs = self.func.push_abis(varargs);
1728        let info = self.func.add_call(CallInfo { callee: Some(callee), signature, varargs });
1729        let returns: Vec<Type> = self.func[signature].return_types().collect();
1730        let args = self.func.push_values(args);
1731        self.inst(
1732            InstData { args, extra: Extra::Call(info), ..InstData::new(Opcode::Call) },
1733            &returns,
1734        )
1735    }
1736
1737    /// Inline assembly, which is a terminator when the info carries targets.
1738    ///
1739    /// The targets are built by the caller, because the frontend is the only thing that knows
1740    /// which block is the one control reaches when the assembly does not jump, and that block
1741    /// has to come first.
1742    pub fn inline_asm(
1743        &mut self,
1744        info: AsmInfo,
1745        args: &[Value],
1746        results: &[Type],
1747        flags: Flags,
1748    ) -> Inst {
1749        let info = self.func.add_asm(info);
1750        let args = self.func.push_values(args);
1751        self.inst(
1752            InstData { args, flags, extra: Extra::Asm(info), ..InstData::new(Opcode::InlineAsm) },
1753            results,
1754        )
1755    }
1756
1757    fn block_call(&mut self, block: Block, args: &[Value]) -> BlockCall {
1758        BlockCall::new(block, self.func.push_values(args))
1759    }
1760}
1761
1762#[cfg(test)]
1763mod tests {
1764    use rucc_base::Interner;
1765
1766    use super::*;
1767    use crate::inst::BlockCallList;
1768    use crate::{MemOrder, Restrict};
1769
1770    /// The example from the spec, near enough: a loop that sums one to n and stores it.
1771    fn sum() -> (Func, Block, Block, Block) {
1772        let mut names = Interner::new();
1773        let i32_ = Type::int(32);
1774        let mut func = Func::new(
1775            names.intern("sum"),
1776            Signature::new().with_params(&[i32_]).with_returns(&[i32_]),
1777        );
1778
1779        let entry = func.create_block();
1780        let n = func.append_param(entry, i32_);
1781        let header = func.create_block();
1782        let acc = func.append_param(header, i32_);
1783        let i = func.append_param(header, i32_);
1784        let exit = func.create_block();
1785        let result = func.append_param(exit, i32_);
1786
1787        let mut b = Builder::new(&mut func, entry);
1788        let zero = b.iconst(i32_, 0);
1789        let cmp = b.icmp(IntPred::Sle, n, zero);
1790        b.br_if(cmp, exit, &[zero], header, &[zero, zero]);
1791
1792        let mut b = Builder::new(&mut func, header);
1793        let one = b.iconst(i32_, 1);
1794        let next = b.binary(Opcode::Add, i, one, Flags::NSW);
1795        let total = b.binary(Opcode::Add, acc, next, Flags::NSW);
1796        let done = b.icmp(IntPred::Sge, next, n);
1797        b.br_if(done, exit, &[total], header, &[total, next]);
1798
1799        let mut b = Builder::new(&mut func, exit);
1800        b.ret(&[result]);
1801
1802        (func, entry, header, exit)
1803    }
1804
1805    #[test]
1806    fn the_blocks_come_back_in_the_order_they_were_made() {
1807        let (func, entry, header, exit) = sum();
1808        assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, header, exit]);
1809        assert_eq!(func.entry(), Some(entry));
1810    }
1811
1812    #[test]
1813    fn a_removed_block_is_gone_from_the_layout_and_so_is_what_was_in_it() {
1814        let (mut func, entry, header, exit) = sum();
1815        let inside: Vec<Inst> = func.insts(header).collect();
1816        func.remove_block(header);
1817        assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, exit]);
1818        assert_eq!(func.entry(), Some(entry));
1819        assert_eq!(func[entry].next, Some(exit));
1820        assert_eq!(func[exit].prev, Some(entry));
1821        // The instructions say they are in no block, the way a removed one does.
1822        assert!(inside.iter().all(|&inst| func.block_of(inst).is_none()));
1823        assert!(func.insts(header).next().is_none());
1824    }
1825
1826    #[test]
1827    fn each_block_holds_what_was_appended_to_it() {
1828        let (func, entry, header, exit) = sum();
1829        let opcodes =
1830            |block| func.insts(block).map(|inst| func[inst].opcode.name()).collect::<Vec<_>>();
1831        assert_eq!(opcodes(entry), ["iconst", "icmp", "br_if"]);
1832        assert_eq!(opcodes(header), ["iconst", "add", "add", "icmp", "br_if"]);
1833        assert_eq!(opcodes(exit), ["return"]);
1834    }
1835
1836    #[test]
1837    fn dropping_the_results_in_front_moves_the_first_one_along_and_renumbers_the_rest() {
1838        // The last result of a call is the memory it produces, and the caller of this is the pass
1839        // that stops a function handing a value back. What has to survive is that the memory is
1840        // still the last result and still says which of the results it is, because a pass reading
1841        // that index is asking whether it is looking at the value a call handed over.
1842        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1843        let types = [Type::int(32), Type::int(64), Type::MEM];
1844        let inst = func.create_inst(InstData::new(Opcode::Call), &types, Span::DUMMY);
1845        let before: Vec<Value> = func[inst].results().collect();
1846        func.drop_results(inst, 1);
1847        assert_eq!(func[inst].results().collect::<Vec<_>>(), before[1..]);
1848        assert_eq!(func[before[1]].def, Def::Result { inst, index: 0 });
1849        assert_eq!(func[before[2]].def, Def::Result { inst, index: 1 });
1850        assert_eq!(func.mem_out(inst), Some(before[2]));
1851    }
1852
1853    #[test]
1854    fn dropping_every_result_leaves_an_instruction_that_produces_nothing() {
1855        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1856        let inst = func.create_inst(InstData::new(Opcode::Call), &[Type::int(32)], Span::DUMMY);
1857        func.drop_results(inst, 1);
1858        assert_eq!(func[inst].results().count(), 0);
1859        assert_eq!(func[inst].first_result, None);
1860    }
1861
1862    #[test]
1863    fn asm_ends_a_block_when_it_has_labels_and_not_otherwise() {
1864        // The labels are in the function's table, so the instruction on its own cannot answer
1865        // and anything asking it rather than the function would walk off the end of the block.
1866        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1867        let block = func.create_block();
1868        let plain = func.add_asm(AsmInfo {
1869            template: Symbol::from_raw(0),
1870            constraints: Symbol::from_raw(0),
1871            clobbers: Symbol::from_raw(0),
1872            targets: BlockCallList::EMPTY,
1873        });
1874        let call = BlockCall::to(block);
1875        let targets = func.push_block_calls(&[call]);
1876        let labelled = func.add_asm(AsmInfo {
1877            template: Symbol::from_raw(0),
1878            constraints: Symbol::from_raw(0),
1879            clobbers: Symbol::from_raw(0),
1880            targets,
1881        });
1882
1883        let mut make = |extra| {
1884            let data = InstData { extra, ..InstData::new(Opcode::InlineAsm) };
1885            func.create_inst(data, &[], Span::DUMMY)
1886        };
1887        let plain = make(Extra::Asm(plain));
1888        let labelled = make(Extra::Asm(labelled));
1889        assert!(!func.is_terminator(plain));
1890        assert!(func.is_terminator(labelled));
1891    }
1892
1893    #[test]
1894    fn every_block_ends_in_its_terminator() {
1895        let (func, entry, header, exit) = sum();
1896        for block in [entry, header, exit] {
1897            let last = func.terminator(block).expect("a terminator");
1898            assert_eq!(Some(last), func.insts(block).last());
1899        }
1900    }
1901
1902    #[test]
1903    fn a_branch_carries_the_arguments_the_block_takes() {
1904        let (func, entry, header, _) = sum();
1905        let br = func.terminator(entry).expect("a terminator");
1906        let calls: Vec<BlockCall> = func.successors(br).collect();
1907        assert_eq!(calls.len(), 2);
1908        // The loop header takes two parameters, so the branch to it passes two.
1909        assert_eq!(calls[1].block, header);
1910        assert_eq!(func[calls[1].args].len(), 2);
1911        assert_eq!(func[header].params.len(), 2);
1912        assert_eq!(func[calls[0].args].len(), 1);
1913    }
1914
1915    #[test]
1916    fn a_value_knows_what_defined_it() {
1917        let (func, entry, _, _) = sum();
1918        let first = func.insts(entry).next().expect("an instruction");
1919        let value = func[first].first_result.expect("a result");
1920        assert_eq!(func[value].def, Def::Result { inst: first, index: 0 });
1921        assert_eq!(func[value].ty, Type::int(32));
1922
1923        let param = func[entry].params[0];
1924        assert_eq!(func[param].def, Def::Param { block: entry, index: 0 });
1925    }
1926
1927    #[test]
1928    fn a_comparison_produces_one_bit() {
1929        let (func, entry, _, _) = sum();
1930        let cmp = func.insts(entry).nth(1).expect("the comparison");
1931        let value = func[cmp].first_result.expect("a result");
1932        assert_eq!(func[value].ty, Type::I1);
1933        assert_eq!(func[cmp].extra, Extra::IntPred(IntPred::Sle));
1934    }
1935
1936    #[test]
1937    fn flags_ride_along_on_the_instruction_that_was_given_them() {
1938        let (func, _, header, _) = sum();
1939        let add = func.insts(header).nth(1).expect("the addition");
1940        assert_eq!(func[add].flags, Flags::NSW);
1941        let cmp = func.insts(header).nth(3).expect("the comparison");
1942        assert_eq!(func[cmp].flags, Flags::NONE);
1943    }
1944
1945    #[test]
1946    fn removing_an_instruction_takes_it_out_of_the_middle() {
1947        let (mut func, _, header, _) = sum();
1948        let add = func.insts(header).nth(1).expect("the addition");
1949        func.remove_inst(add);
1950        let opcodes: Vec<&str> = func.insts(header).map(|inst| func[inst].opcode.name()).collect();
1951        assert_eq!(opcodes, ["iconst", "add", "icmp", "br_if"]);
1952        assert_eq!(func.block_of(add), None);
1953    }
1954
1955    #[test]
1956    fn removing_the_first_and_the_last_keeps_the_ends_right() {
1957        let (mut func, entry, _, _) = sum();
1958        let first = func.insts(entry).next().expect("an instruction");
1959        let last = func.terminator(entry).expect("a terminator");
1960        func.remove_inst(first);
1961        func.remove_inst(last);
1962        let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1963        assert_eq!(opcodes, ["icmp"]);
1964        assert_eq!(func[entry].first, func[entry].last);
1965    }
1966
1967    #[test]
1968    fn removing_the_only_instruction_empties_the_block() {
1969        let (mut func, _, _, exit) = sum();
1970        let only = func.insts(exit).next().expect("an instruction");
1971        func.remove_inst(only);
1972        assert_eq!(func.insts(exit).count(), 0);
1973        assert_eq!(func[exit].first, None);
1974        assert_eq!(func[exit].last, None);
1975    }
1976
1977    #[test]
1978    fn inserting_before_puts_it_in_the_right_place() {
1979        let (mut func, entry, _, _) = sum();
1980        let cmp = func.insts(entry).nth(1).expect("the comparison");
1981        let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1982        func.insert_before(made, cmp);
1983        let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1984        assert_eq!(opcodes, ["iconst", "unreachable", "icmp", "br_if"]);
1985    }
1986
1987    #[test]
1988    fn inserting_before_the_first_makes_it_the_first() {
1989        let (mut func, entry, _, _) = sum();
1990        let first = func.insts(entry).next().expect("an instruction");
1991        let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1992        func.insert_before(made, first);
1993        assert_eq!(func.insts(entry).next(), Some(made));
1994        assert_eq!(func[entry].first, Some(made));
1995    }
1996
1997    #[test]
1998    fn inserting_after_puts_it_in_the_right_place() {
1999        let (mut func, entry, _, _) = sum();
2000        let first = func.insts(entry).next().expect("an instruction");
2001        let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
2002        func.insert_after(made, first);
2003        let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
2004        assert_eq!(opcodes, ["iconst", "unreachable", "icmp", "br_if"]);
2005        assert_eq!(func[entry].first, Some(first));
2006    }
2007
2008    #[test]
2009    #[should_panic(expected = "nothing goes after a terminator")]
2010    fn inserting_after_the_terminator_is_refused() {
2011        // A block ends where its branch is, so an instruction after one would be in no block that
2012        // control ever reaches, and the layout would be claiming otherwise.
2013        let (mut func, entry, _, _) = sum();
2014        let last = func.insts(entry).last().expect("a terminator");
2015        let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
2016        func.insert_after(made, last);
2017    }
2018
2019    #[test]
2020    fn a_list_grows_in_place_while_it_is_the_last_thing_in_the_pool() {
2021        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2022        let block = func.create_block();
2023        let a = func.append_param(block, Type::int(32));
2024        let b = func.append_param(block, Type::int(32));
2025        let list = func.push_values(&[a]);
2026        let grown = func.append_arg(list, b);
2027        assert_eq!(func[grown], [a, b]);
2028        assert_eq!(grown.as_usize_range().start, list.as_usize_range().start);
2029    }
2030
2031    #[test]
2032    fn a_list_is_copied_when_something_is_behind_it() {
2033        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2034        let block = func.create_block();
2035        let a = func.append_param(block, Type::int(32));
2036        let b = func.append_param(block, Type::int(32));
2037        let list = func.push_values(&[a, a]);
2038        let behind = func.push_values(&[b]);
2039        let grown = func.append_arg(list, b);
2040        assert_eq!(func[grown], [a, a, b]);
2041        assert_eq!(func[list], [a, a], "the old run is still readable");
2042        assert_eq!(func[behind], [b], "and so is what was behind it");
2043        assert_ne!(grown.as_usize_range().start, list.as_usize_range().start);
2044    }
2045
2046    #[test]
2047    fn a_parameter_added_late_is_the_next_one_along() {
2048        // This is the shape SSA construction leaves: the loop header gains a parameter after
2049        // the blocks that branch to it already exist, and each of their branches grows an
2050        // argument to match.
2051        let (mut func, entry, header, _) = sum();
2052        let extra = func.append_param(header, Type::int(32));
2053        assert_eq!(func[header].params.len(), 3);
2054        assert_eq!(func[extra].def, Def::Param { block: header, index: 2 });
2055
2056        let br = func.terminator(entry).expect("a terminator");
2057        let call = func.successors(br).nth(1).expect("the branch to the header");
2058        let grown = func.append_arg(call.args, extra);
2059        assert_eq!(func[grown].len(), 3);
2060    }
2061
2062    #[test]
2063    fn a_span_rides_along_with_the_instruction() {
2064        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2065        let block = func.create_block();
2066        let span = Span::new(10, 20);
2067        let mut b = Builder::new(&mut func, block).at(span);
2068        let value = b.iconst(Type::int(32), 7);
2069        let inst = match func[value].def {
2070            Def::Result { inst, .. } => inst,
2071            Def::Param { .. } => unreachable!("a constant is not a parameter"),
2072        };
2073        assert_eq!(func.span(inst), span);
2074    }
2075
2076    #[test]
2077    fn a_store_produces_nothing_and_a_load_produces_one_value() {
2078        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2079        let block = func.create_block();
2080        let addr = func.append_param(block, Type::PTR);
2081        let info = MemInfo {
2082            size: 4,
2083            align: 4,
2084            order: MemOrder::NotAtomic,
2085            tbaa: None,
2086            owns: 0,
2087            restrict: Restrict::NONE,
2088        };
2089        let mut b = Builder::new(&mut func, block);
2090        let value = b.load(Type::int(32), addr, info, Flags::NONE);
2091        let store = b.store(value, addr, info, Flags::VOLATILE);
2092        assert_eq!(func[store].results, 0);
2093        assert_eq!(func[store].flags, Flags::VOLATILE);
2094        assert_eq!(func[value].ty, Type::int(32));
2095    }
2096
2097    #[test]
2098    fn memory_remembers_which_declaration_asked_for_it_and_which_did_not() {
2099        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2100        let info = MemInfo {
2101            size: 4,
2102            align: 4,
2103            order: MemOrder::NotAtomic,
2104            tbaa: None,
2105            owns: 0,
2106            restrict: Restrict::NONE,
2107        };
2108        let first = func.add_mem(info);
2109        let second = func.add_mem(info);
2110        let third = func.add_mem(info);
2111
2112        // Out of order, because a declaration is recorded where the walk reaches it and the table
2113        // is kept sorted so that reading it back is a search rather than a scan.
2114        func.declare_mem(third, 7);
2115        func.declare_mem(first, 2);
2116        // The second ask about the same memory keeps the first answer.
2117        func.declare_mem(first, 9);
2118
2119        assert_eq!(func.mem_decl(first), Some(2));
2120        assert_eq!(func.mem_decl(third), Some(7));
2121        // Memory no declaration asked for, which is what every temporary is.
2122        assert_eq!(func.mem_decl(second), None);
2123    }
2124
2125    /// A value says which declarations it is the value of, and a rename carries them over.
2126    ///
2127    /// Both directions are many, which is why this is a list rather than a map: a declaration
2128    /// assigned twice has a value for each assignment, and two values a pass found equal end up
2129    /// as one value that two declarations are both spelled by.
2130    #[test]
2131    fn a_value_says_which_declarations_it_is_and_a_rename_carries_them_over() {
2132        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2133        let block = func.create_block();
2134        let first = func.append_param(block, Type::int(32));
2135        let second = func.append_param(block, Type::int(32));
2136        let third = func.append_param(block, Type::int(32));
2137
2138        // Out of order, because a value is named where the walk reaches the assignment that made
2139        // it and the table is kept sorted so that reading it back is a search rather than a scan.
2140        func.declare_value(third, 7);
2141        func.declare_value(first, 2);
2142        // The same ask twice, which a read that memoises what it found makes, and it is one pair.
2143        func.declare_value(first, 2);
2144
2145        assert_eq!(func.value_decls(first).collect::<Vec<u32>>(), vec![2]);
2146        assert_eq!(func.value_decls(third).collect::<Vec<u32>>(), vec![7]);
2147        // A value no declaration is behind, which is what every temporary is.
2148        assert_eq!(func.value_decls(second).count(), 0);
2149
2150        // A pass finds two values equal and points the readers of one at the other. The names go
2151        // with the readers, and the value that is left is both of them, the one that went away's
2152        // from where it was defined, which for a parameter is the top of its block.
2153        func.rename_value(third, first);
2154        assert_eq!(func.value_decls(first).collect::<Vec<u32>>(), vec![2]);
2155        assert_eq!(
2156            func.value_starts(first).collect::<Vec<Start>>(),
2157            vec![Start { decl: 7, block, after: None }]
2158        );
2159        assert_eq!(func.value_decls(third).count(), 0);
2160
2161        // And renaming a value nothing named moves nothing rather than inventing a pair.
2162        func.rename_value(second, third);
2163        assert_eq!(func.value_decls(third).count(), 0);
2164    }
2165
2166    /// A declaration that starts holding a value part of the way through says where, and a rename
2167    /// carries that over as it does a name.
2168    #[test]
2169    fn a_start_part_of_the_way_through_is_kept_and_a_rename_carries_it_over() {
2170        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2171        let block = func.create_block();
2172        let first = func.append_param(block, Type::int(32));
2173        let second = func.append_param(block, Type::int(32));
2174        let one = Builder::new(&mut func, block).iconst(Type::int(32), 1);
2175        let inst = func.insts(block).next().expect("the constant");
2176
2177        let top = Start { decl: 4, block, after: None };
2178        let later = Start { decl: 4, block, after: Some(inst) };
2179        func.declare_value_from(first, later);
2180        func.declare_value_from(first, top);
2181        // The same ask twice is one start.
2182        func.declare_value_from(first, later);
2183        assert_eq!(func.value_starts(first).collect::<Vec<_>>(), vec![later, top]);
2184        assert_eq!(func.value_starts(one).count(), 0);
2185
2186        func.rename_value(first, second);
2187        assert_eq!(func.value_starts(second).collect::<Vec<_>>(), vec![later, top]);
2188        assert_eq!(func.value_starts(first).count(), 0);
2189    }
2190
2191    /// Where a start is, by where it resolves to rather than what it was made with.
2192    fn places(func: &Func, value: Value) -> Vec<Option<(Block, Option<Inst>)>> {
2193        func.value_starts(value).map(|start| func.start_place(start)).collect()
2194    }
2195
2196    /// Taking out the instruction a start is after leaves it after the one in front, which is the
2197    /// same place, and a replacement put in front of the old one is what it ends up after.
2198    #[test]
2199    fn a_start_after_an_instruction_that_is_taken_out_stays_where_it_was() {
2200        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2201        let block = func.create_block();
2202        let value = func.append_param(block, Type::int(32));
2203        let mut build = Builder::new(&mut func, block);
2204        build.iconst(Type::int(32), 1);
2205        build.iconst(Type::int(32), 2);
2206        let [one, two]: [Inst; 2] = func.insts(block).collect::<Vec<_>>().try_into().expect("two");
2207        func.declare_value_from(value, Start { decl: 4, block, after: Some(two) });
2208
2209        func.remove_inst(two);
2210        assert_eq!(places(&func, value), [Some((block, Some(one)))]);
2211        let data = func[one];
2212        let fresh = func.create_inst(data, &[Type::int(32)], Span::DUMMY);
2213        func.insert_before(fresh, one);
2214        func.remove_inst(one);
2215        assert_eq!(places(&func, value), [Some((block, Some(fresh)))]);
2216        func.remove_inst(fresh);
2217        assert_eq!(places(&func, value), [Some((block, None))]);
2218    }
2219
2220    /// A pass that moves the instruction a start is after to another block moves the assignment
2221    /// with it, rather than leaving it after whatever was in front of the instruction before.
2222    #[test]
2223    fn a_start_after_an_instruction_a_pass_moves_goes_with_it() {
2224        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2225        let top = func.create_block();
2226        let below = func.create_block();
2227        let value = func.append_param(top, Type::int(32));
2228        let mut build = Builder::new(&mut func, below);
2229        build.iconst(Type::int(32), 1);
2230        build.iconst(Type::int(32), 2);
2231        let [one, two]: [Inst; 2] = func.insts(below).collect::<Vec<_>>().try_into().expect("two");
2232        func.declare_value_from(value, Start { decl: 4, block: below, after: Some(two) });
2233
2234        // Emptied into the block above one at a time, which is what a merge does.
2235        for inst in [one, two] {
2236            func.remove_inst(inst);
2237            func.append_inst(top, inst);
2238        }
2239        func.remove_block(below);
2240        assert_eq!(places(&func, value), [Some((top, Some(two)))]);
2241    }
2242
2243    /// A start at the top of a block a pass empties into the one above goes after what that block
2244    /// ended with before, which is where the top of the block that went is now.
2245    #[test]
2246    fn a_start_at_the_top_of_a_block_that_is_merged_away_is_carried_over() {
2247        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2248        let top = func.create_block();
2249        let below = func.create_block();
2250        let value = func.append_param(top, Type::int(32));
2251        Builder::new(&mut func, top).iconst(Type::int(32), 1);
2252        Builder::new(&mut func, below).iconst(Type::int(32), 2);
2253        let last = func.insts(top).next();
2254        func.declare_value_from(value, Start { decl: 4, block: below, after: None });
2255
2256        for inst in func.insts(below).collect::<Vec<_>>() {
2257            func.remove_inst(inst);
2258            func.append_inst(top, inst);
2259        }
2260        func.carry_starts(below, top, last);
2261        func.remove_block(below);
2262        assert_eq!(places(&func, value), [Some((top, last))]);
2263    }
2264
2265    /// A value whose instruction is taken out and not put back leaves its declaration starting
2266    /// where it was, and one put back somewhere else leaves it the name it had.
2267    #[test]
2268    fn a_name_on_a_value_whose_instruction_goes_becomes_a_start_and_comes_back_if_it_returns() {
2269        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2270        let block = func.create_block();
2271        let mut build = Builder::new(&mut func, block);
2272        let kept = build.iconst(Type::int(32), 1);
2273        let moved = build.iconst(Type::int(32), 2);
2274        let first = func.insts(block).next().expect("one");
2275        let second = func.insts(block).nth(1).expect("two");
2276        func.declare_value(kept, 4);
2277        func.declare_value(moved, 5);
2278
2279        func.remove_inst(first);
2280        assert_eq!(func.value_decls(kept).count(), 0);
2281        assert_eq!(places(&func, kept), [Some((block, None))]);
2282
2283        func.remove_inst(second);
2284        func.append_inst(block, second);
2285        assert_eq!(func.value_decls(moved).collect::<Vec<_>>(), [5]);
2286        assert_eq!(func.value_starts(moved).count(), 0);
2287    }
2288
2289    /// Renaming a value into one computed earlier leaves the declaration starting where the one
2290    /// that went away was computed, rather than holding the earlier one from where it was.
2291    #[test]
2292    fn a_rename_into_an_earlier_value_starts_the_declaration_where_the_later_one_was() {
2293        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2294        let block = func.create_block();
2295        let mut build = Builder::new(&mut func, block);
2296        let early = build.iconst(Type::int(32), 1);
2297        build.iconst(Type::int(32), 3);
2298        let late = build.iconst(Type::int(32), 1);
2299        let middle = func.insts(block).nth(1).expect("three");
2300        func.declare_value(late, 4);
2301
2302        func.rename_value(late, early);
2303        assert_eq!(func.value_decls(early).count(), 0);
2304        assert_eq!(places(&func, early), [Some((block, Some(middle)))]);
2305    }
2306
2307    /// Moving some of a value's starts to another leaves the rest where they were, in order.
2308    #[test]
2309    fn moving_starts_moves_the_ones_asked_for_and_no_others() {
2310        let mut func = Func::new(Symbol::from_raw(0), Signature::new());
2311        let block = func.create_block();
2312        let mut build = Builder::new(&mut func, block);
2313        let from = build.iconst(Type::int(32), 1);
2314        let into = build.iconst(Type::int(32), 2);
2315        let first = func.insts(block).next();
2316        let starts: Vec<Start> = (5..8).map(|decl| Start { decl, block, after: first }).collect();
2317        for &start in &starts {
2318            func.declare_value_from(from, start);
2319        }
2320
2321        func.move_starts(from, into, &starts[1..2]);
2322        assert_eq!(func.value_starts(from).collect::<Vec<Start>>(), [starts[0], starts[2]]);
2323        assert_eq!(func.value_starts(into).collect::<Vec<Start>>(), [starts[1]]);
2324    }
2325
2326    #[test]
2327    fn a_call_produces_what_its_signature_returns() {
2328        let mut names = Interner::new();
2329        let mut func = Func::new(names.intern("caller"), Signature::new());
2330        let sig = func.add_signature(
2331            Signature::new().with_params(&[Type::int(32)]).with_returns(&[Type::int(64)]),
2332        );
2333        let block = func.create_block();
2334        let arg = func.append_param(block, Type::int(32));
2335        let callee = names.intern("callee");
2336        let mut b = Builder::new(&mut func, block);
2337        let call = b.call(callee, sig, &[arg]);
2338        assert_eq!(func[call].results, 1);
2339        let value = func[call].first_result.expect("a result");
2340        assert_eq!(func[value].ty, Type::int(64));
2341        assert_eq!(func[call].extra, Extra::Call(Idx::new(0)));
2342    }
2343
2344    #[test]
2345    fn the_counts_are_what_was_made() {
2346        let (func, _, _, _) = sum();
2347        let counts = func.counts();
2348        assert_eq!(counts.blocks, 3);
2349        assert_eq!(counts.insts, 9);
2350        // Four block parameters and five instruction results, which is the two constants, the
2351        // two additions and the two comparisons less the branches, which produce nothing.
2352        assert_eq!(counts.values, 4 + 6);
2353    }
2354
2355    #[test]
2356    #[should_panic(expected = "the instruction is in a block")]
2357    fn appending_an_instruction_twice_is_refused() {
2358        let (mut func, entry, _, _) = sum();
2359        let first = func.insts(entry).next().expect("an instruction");
2360        func.append_inst(entry, first);
2361    }
2362
2363    #[test]
2364    #[should_panic(expected = "the instruction is not in a block")]
2365    fn removing_an_instruction_twice_is_refused() {
2366        let (mut func, entry, _, _) = sum();
2367        let first = func.insts(entry).next().expect("an instruction");
2368        func.remove_inst(first);
2369        func.remove_inst(first);
2370    }
2371
2372    /// A store and a load with memory threaded through them, as memory SSA construction does it.
2373    fn threaded() -> (Func, Inst, Inst) {
2374        let mut names = Interner::new();
2375        let i32_ = Type::int(32);
2376        let mut func = Func::new(
2377            names.intern("thread"),
2378            Signature::new().with_params(&[Type::PTR]).with_returns(&[i32_]),
2379        );
2380        let entry = func.create_block();
2381        let addr = func.append_param(entry, Type::PTR);
2382        let info = MemInfo {
2383            size: 4,
2384            align: 4,
2385            order: MemOrder::NotAtomic,
2386            tbaa: None,
2387            owns: 0,
2388            restrict: Restrict::NONE,
2389        };
2390
2391        let mut b = Builder::new(&mut func, entry);
2392        let start = b.mem_entry();
2393        let seven = b.iconst(i32_, 7);
2394        let store = b.store(seven, addr, info, Flags::NONE);
2395        let value = b.load(i32_, addr, info, Flags::NONE);
2396        let Def::Result { inst: load, .. } = func[value].def else {
2397            panic!("the load produced it");
2398        };
2399
2400        let store = func.with_mem(store, start);
2401        let after = func.mem_out(store).expect("a store makes a new version");
2402        let load = func.with_mem(load, after);
2403        (func, store, load)
2404    }
2405
2406    #[test]
2407    fn threading_memory_puts_it_last_and_leaves_everything_else_where_it_was() {
2408        let (func, store, load) = threaded();
2409        assert_eq!(func.mem_in(store), func.mem_out(store).map(|_| func[func[store].args][2]));
2410        assert_eq!(func[func[store].args].len(), 3);
2411        assert!(func.carries_mem(store));
2412        assert!(func.carries_mem(load));
2413
2414        // The address of the load is still its first operand, which is the point of putting
2415        // memory last: nothing that read the operands before has to learn about it.
2416        assert_eq!(func[func[load].args][0], func[func.entry().expect("an entry")].params[0]);
2417        assert_eq!(func.mem_in(load), func.mem_out(store));
2418        assert_eq!(func.mem_out(load), None);
2419    }
2420
2421    #[test]
2422    #[should_panic(expected = "this is already on the memory chain")]
2423    fn threading_memory_through_the_same_instruction_twice_is_refused() {
2424        let (mut func, store, _) = threaded();
2425        let start = func.mem_in(store).expect("it was threaded");
2426        func.with_mem(store, start);
2427    }
2428
2429    /// Two copies of the same pair of addresses, the first of a fixed length and the second of one
2430    /// the caller passed in, both on the memory chain so that the length is not the last operand.
2431    fn copies() -> (Func, Inst, Inst) {
2432        let mut names = Interner::new();
2433        let i64_ = Type::int(64);
2434        let mut func = Func::new(
2435            names.intern("copies"),
2436            Signature::new().with_params(&[Type::PTR, Type::PTR, i64_]),
2437        );
2438        let entry = func.create_block();
2439        let to = func.append_param(entry, Type::PTR);
2440        let from = func.append_param(entry, Type::PTR);
2441        let length = func.append_param(entry, i64_);
2442        let info = MemInfo {
2443            size: 16,
2444            align: 4,
2445            order: MemOrder::NotAtomic,
2446            tbaa: None,
2447            owns: 0,
2448            restrict: Restrict::NONE,
2449        };
2450
2451        let mut b = Builder::new(&mut func, entry);
2452        let start = b.mem_entry();
2453        let mem = b.func().add_mem(info);
2454        let args = b.func().push_values(&[to, from]);
2455        let fixed =
2456            b.inst(InstData { args, extra: Extra::Mem(mem), ..InstData::new(Opcode::Memcpy) }, &[]);
2457        let mem = b.func().add_mem(MemInfo { size: 0, ..info });
2458        let args = b.func().push_values(&[to, from, length]);
2459        let computed =
2460            b.inst(InstData { args, extra: Extra::Mem(mem), ..InstData::new(Opcode::Memcpy) }, &[]);
2461        b.ret(&[]);
2462
2463        let fixed = func.with_mem(fixed, start);
2464        let after = func.mem_out(fixed).expect("a copy makes a new version");
2465        let computed = func.with_mem(computed, after);
2466        (func, fixed, computed)
2467    }
2468
2469    #[test]
2470    fn a_bulk_copy_hands_back_its_length_where_it_has_one_and_nothing_where_the_payload_has_it() {
2471        let (func, fixed, computed) = copies();
2472        let params = &func[func.entry().expect("an entry")].params;
2473        let [to, from, length] = params[..] else { panic!("three of them were appended") };
2474
2475        let bulk = func.bulk(fixed).expect("a memcpy is one");
2476        assert_eq!((bulk.to, bulk.with, bulk.length), (to, from, None));
2477
2478        let bulk = func.bulk(computed).expect("a memcpy is one");
2479        assert_eq!((bulk.to, bulk.with, bulk.length), (to, from, Some(length)));
2480    }
2481
2482    #[test]
2483    fn an_instruction_that_is_not_a_bulk_operation_is_not_taken_apart_as_one() {
2484        let (func, store, load) = threaded();
2485        assert_eq!(func.bulk(store), None);
2486        assert_eq!(func.bulk(load), None);
2487    }
2488}