Skip to main content

rucc_ir/
func.rs

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