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