Skip to main content

rucc_ir/
func.rs

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