cranelift_codegen/
cursor.rs

1//! Cursor library.
2//!
3//! This module defines cursor data types that can be used for inserting instructions.
4
5use crate::ir;
6
7/// The possible positions of a cursor.
8#[derive(Clone, Copy, PartialEq, Eq, Debug)]
9pub enum CursorPosition {
10    /// Cursor is not pointing anywhere. No instructions can be inserted.
11    Nowhere,
12    /// Cursor is pointing at an existing instruction.
13    /// New instructions will be inserted *before* the current instruction.
14    At(ir::Inst),
15    /// Cursor is before the beginning of a block. No instructions can be inserted. Calling
16    /// `next_inst()` will move to the first instruction in the block.
17    Before(ir::Block),
18    /// Cursor is pointing after the end of a block.
19    /// New instructions will be appended to the block.
20    After(ir::Block),
21}
22
23/// All cursor types implement the `Cursor` which provides common navigation operations.
24pub trait Cursor {
25    /// Get the current cursor position.
26    fn position(&self) -> CursorPosition;
27
28    /// Set the current position.
29    fn set_position(&mut self, pos: CursorPosition);
30
31    /// Get the source location that should be assigned to new instructions.
32    fn srcloc(&self) -> ir::SourceLoc;
33
34    /// Set the source location that should be assigned to new instructions.
35    fn set_srcloc(&mut self, srcloc: ir::SourceLoc);
36
37    /// Borrow a reference to the function layout that this cursor is navigating.
38    fn layout(&self) -> &ir::Layout;
39
40    /// Borrow a mutable reference to the function layout that this cursor is navigating.
41    fn layout_mut(&mut self) -> &mut ir::Layout;
42
43    /// Exchange this cursor for one with a set source location.
44    ///
45    /// This is intended to be used as a builder method:
46    ///
47    /// ```
48    /// # use cranelift_codegen::ir::{Function, Block, SourceLoc};
49    /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
50    /// fn edit_func(func: &mut Function, srcloc: SourceLoc) {
51    ///     let mut pos = FuncCursor::new(func).with_srcloc(srcloc);
52    ///
53    ///     // Use `pos`...
54    /// }
55    /// ```
56    fn with_srcloc(mut self, srcloc: ir::SourceLoc) -> Self
57    where
58        Self: Sized,
59    {
60        self.set_srcloc(srcloc);
61        self
62    }
63
64    /// Rebuild this cursor positioned at `pos`.
65    fn at_position(mut self, pos: CursorPosition) -> Self
66    where
67        Self: Sized,
68    {
69        self.set_position(pos);
70        self
71    }
72
73    /// Rebuild this cursor positioned at `inst`.
74    ///
75    /// This is intended to be used as a builder method:
76    ///
77    /// ```
78    /// # use cranelift_codegen::ir::{Function, Block, Inst};
79    /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
80    /// fn edit_func(func: &mut Function, inst: Inst) {
81    ///     let mut pos = FuncCursor::new(func).at_inst(inst);
82    ///
83    ///     // Use `pos`...
84    /// }
85    /// ```
86    fn at_inst(mut self, inst: ir::Inst) -> Self
87    where
88        Self: Sized,
89    {
90        self.goto_inst(inst);
91        self
92    }
93
94    /// Rebuild this cursor positioned at the first insertion point for `block`.
95    /// This differs from `at_first_inst` in that it doesn't assume that any
96    /// instructions have been inserted into `block` yet.
97    ///
98    /// This is intended to be used as a builder method:
99    ///
100    /// ```
101    /// # use cranelift_codegen::ir::{Function, Block, Inst};
102    /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
103    /// fn edit_func(func: &mut Function, block: Block) {
104    ///     let mut pos = FuncCursor::new(func).at_first_insertion_point(block);
105    ///
106    ///     // Use `pos`...
107    /// }
108    /// ```
109    fn at_first_insertion_point(mut self, block: ir::Block) -> Self
110    where
111        Self: Sized,
112    {
113        self.goto_first_insertion_point(block);
114        self
115    }
116
117    /// Rebuild this cursor positioned at the first instruction in `block`.
118    ///
119    /// This is intended to be used as a builder method:
120    ///
121    /// ```
122    /// # use cranelift_codegen::ir::{Function, Block, Inst};
123    /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
124    /// fn edit_func(func: &mut Function, block: Block) {
125    ///     let mut pos = FuncCursor::new(func).at_first_inst(block);
126    ///
127    ///     // Use `pos`...
128    /// }
129    /// ```
130    fn at_first_inst(mut self, block: ir::Block) -> Self
131    where
132        Self: Sized,
133    {
134        self.goto_first_inst(block);
135        self
136    }
137
138    /// Rebuild this cursor positioned at the last instruction in `block`.
139    ///
140    /// This is intended to be used as a builder method:
141    ///
142    /// ```
143    /// # use cranelift_codegen::ir::{Function, Block, Inst};
144    /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
145    /// fn edit_func(func: &mut Function, block: Block) {
146    ///     let mut pos = FuncCursor::new(func).at_last_inst(block);
147    ///
148    ///     // Use `pos`...
149    /// }
150    /// ```
151    fn at_last_inst(mut self, block: ir::Block) -> Self
152    where
153        Self: Sized,
154    {
155        self.goto_last_inst(block);
156        self
157    }
158
159    /// Rebuild this cursor positioned after `inst`.
160    ///
161    /// This is intended to be used as a builder method:
162    ///
163    /// ```
164    /// # use cranelift_codegen::ir::{Function, Block, Inst};
165    /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
166    /// fn edit_func(func: &mut Function, inst: Inst) {
167    ///     let mut pos = FuncCursor::new(func).after_inst(inst);
168    ///
169    ///     // Use `pos`...
170    /// }
171    /// ```
172    fn after_inst(mut self, inst: ir::Inst) -> Self
173    where
174        Self: Sized,
175    {
176        self.goto_after_inst(inst);
177        self
178    }
179
180    /// Rebuild this cursor positioned at the top of `block`.
181    ///
182    /// This is intended to be used as a builder method:
183    ///
184    /// ```
185    /// # use cranelift_codegen::ir::{Function, Block, Inst};
186    /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
187    /// fn edit_func(func: &mut Function, block: Block) {
188    ///     let mut pos = FuncCursor::new(func).at_top(block);
189    ///
190    ///     // Use `pos`...
191    /// }
192    /// ```
193    fn at_top(mut self, block: ir::Block) -> Self
194    where
195        Self: Sized,
196    {
197        self.goto_top(block);
198        self
199    }
200
201    /// Rebuild this cursor positioned at the bottom of `block`.
202    ///
203    /// This is intended to be used as a builder method:
204    ///
205    /// ```
206    /// # use cranelift_codegen::ir::{Function, Block, Inst};
207    /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
208    /// fn edit_func(func: &mut Function, block: Block) {
209    ///     let mut pos = FuncCursor::new(func).at_bottom(block);
210    ///
211    ///     // Use `pos`...
212    /// }
213    /// ```
214    fn at_bottom(mut self, block: ir::Block) -> Self
215    where
216        Self: Sized,
217    {
218        self.goto_bottom(block);
219        self
220    }
221
222    /// Get the block corresponding to the current position.
223    fn current_block(&self) -> Option<ir::Block> {
224        use self::CursorPosition::*;
225        match self.position() {
226            Nowhere => None,
227            At(inst) => self.layout().inst_block(inst),
228            Before(block) | After(block) => Some(block),
229        }
230    }
231
232    /// Get the instruction corresponding to the current position, if any.
233    fn current_inst(&self) -> Option<ir::Inst> {
234        use self::CursorPosition::*;
235        match self.position() {
236            At(inst) => Some(inst),
237            _ => None,
238        }
239    }
240
241    /// Go to the position after a specific instruction, which must be inserted
242    /// in the layout. New instructions will be inserted after `inst`.
243    fn goto_after_inst(&mut self, inst: ir::Inst) {
244        debug_assert!(self.layout().inst_block(inst).is_some());
245        let new_pos = if let Some(next) = self.layout().next_inst(inst) {
246            CursorPosition::At(next)
247        } else {
248            CursorPosition::After(
249                self.layout()
250                    .inst_block(inst)
251                    .expect("current instruction removed?"),
252            )
253        };
254        self.set_position(new_pos);
255    }
256
257    /// Go to a specific instruction which must be inserted in the layout.
258    /// New instructions will be inserted before `inst`.
259    fn goto_inst(&mut self, inst: ir::Inst) {
260        debug_assert!(self.layout().inst_block(inst).is_some());
261        self.set_position(CursorPosition::At(inst));
262    }
263
264    /// Go to the position for inserting instructions at the beginning of `block`,
265    /// which unlike `goto_first_inst` doesn't assume that any instructions have
266    /// been inserted into `block` yet.
267    fn goto_first_insertion_point(&mut self, block: ir::Block) {
268        if let Some(inst) = self.layout().first_inst(block) {
269            self.goto_inst(inst);
270        } else {
271            self.goto_bottom(block);
272        }
273    }
274
275    /// Go to the first instruction in `block`.
276    fn goto_first_inst(&mut self, block: ir::Block) {
277        let inst = self.layout().first_inst(block).expect("Empty block");
278        self.goto_inst(inst);
279    }
280
281    /// Go to the last instruction in `block`.
282    fn goto_last_inst(&mut self, block: ir::Block) {
283        let inst = self.layout().last_inst(block).expect("Empty block");
284        self.goto_inst(inst);
285    }
286
287    /// Go to the top of `block` which must be inserted into the layout.
288    /// At this position, instructions cannot be inserted, but `next_inst()` will move to the first
289    /// instruction in `block`.
290    fn goto_top(&mut self, block: ir::Block) {
291        debug_assert!(self.layout().is_block_inserted(block));
292        self.set_position(CursorPosition::Before(block));
293    }
294
295    /// Go to the bottom of `block` which must be inserted into the layout.
296    /// At this position, inserted instructions will be appended to `block`.
297    fn goto_bottom(&mut self, block: ir::Block) {
298        debug_assert!(self.layout().is_block_inserted(block));
299        self.set_position(CursorPosition::After(block));
300    }
301
302    /// Go to the top of the next block in layout order and return it.
303    ///
304    /// - If the cursor wasn't pointing at anything, go to the top of the first block in the
305    ///   function.
306    /// - If there are no more blocks, leave the cursor pointing at nothing and return `None`.
307    ///
308    /// # Examples
309    ///
310    /// The `next_block()` method is intended for iterating over the blocks in layout order:
311    ///
312    /// ```
313    /// # use cranelift_codegen::ir::{Function, Block};
314    /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
315    /// fn edit_func(func: &mut Function) {
316    ///     let mut cursor = FuncCursor::new(func);
317    ///     while let Some(block) = cursor.next_block() {
318    ///         // Edit block.
319    ///     }
320    /// }
321    /// ```
322    fn next_block(&mut self) -> Option<ir::Block> {
323        let next = if let Some(block) = self.current_block() {
324            self.layout().next_block(block)
325        } else {
326            self.layout().entry_block()
327        };
328        self.set_position(match next {
329            Some(block) => CursorPosition::Before(block),
330            None => CursorPosition::Nowhere,
331        });
332        next
333    }
334
335    /// Go to the bottom of the previous block in layout order and return it.
336    ///
337    /// - If the cursor wasn't pointing at anything, go to the bottom of the last block in the
338    ///   function.
339    /// - If there are no more blocks, leave the cursor pointing at nothing and return `None`.
340    ///
341    /// # Examples
342    ///
343    /// The `prev_block()` method is intended for iterating over the blocks in backwards layout order:
344    ///
345    /// ```
346    /// # use cranelift_codegen::ir::{Function, Block};
347    /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
348    /// fn edit_func(func: &mut Function) {
349    ///     let mut cursor = FuncCursor::new(func);
350    ///     while let Some(block) = cursor.prev_block() {
351    ///         // Edit block.
352    ///     }
353    /// }
354    /// ```
355    fn prev_block(&mut self) -> Option<ir::Block> {
356        let prev = if let Some(block) = self.current_block() {
357            self.layout().prev_block(block)
358        } else {
359            self.layout().last_block()
360        };
361        self.set_position(match prev {
362            Some(block) => CursorPosition::After(block),
363            None => CursorPosition::Nowhere,
364        });
365        prev
366    }
367
368    /// Move to the next instruction in the same block and return it.
369    ///
370    /// - If the cursor was positioned before a block, go to the first instruction in that block.
371    /// - If there are no more instructions in the block, go to the `After(block)` position and return
372    ///   `None`.
373    /// - If the cursor wasn't pointing anywhere, keep doing that.
374    ///
375    /// This method will never move the cursor to a different block.
376    ///
377    /// # Examples
378    ///
379    /// The `next_inst()` method is intended for iterating over the instructions in a block like
380    /// this:
381    ///
382    /// ```
383    /// # use cranelift_codegen::ir::{Function, Block};
384    /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
385    /// fn edit_block(func: &mut Function, block: Block) {
386    ///     let mut cursor = FuncCursor::new(func).at_top(block);
387    ///     while let Some(inst) = cursor.next_inst() {
388    ///         // Edit instructions...
389    ///     }
390    /// }
391    /// ```
392    /// The loop body can insert and remove instructions via the cursor.
393    ///
394    /// Iterating over all the instructions in a function looks like this:
395    ///
396    /// ```
397    /// # use cranelift_codegen::ir::{Function, Block};
398    /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
399    /// fn edit_func(func: &mut Function) {
400    ///     let mut cursor = FuncCursor::new(func);
401    ///     while let Some(block) = cursor.next_block() {
402    ///         while let Some(inst) = cursor.next_inst() {
403    ///             // Edit instructions...
404    ///         }
405    ///     }
406    /// }
407    /// ```
408    fn next_inst(&mut self) -> Option<ir::Inst> {
409        use self::CursorPosition::*;
410        match self.position() {
411            Nowhere | After(..) => None,
412            At(inst) => {
413                if let Some(next) = self.layout().next_inst(inst) {
414                    self.set_position(At(next));
415                    Some(next)
416                } else {
417                    let pos = After(
418                        self.layout()
419                            .inst_block(inst)
420                            .expect("current instruction removed?"),
421                    );
422                    self.set_position(pos);
423                    None
424                }
425            }
426            Before(block) => {
427                if let Some(next) = self.layout().first_inst(block) {
428                    self.set_position(At(next));
429                    Some(next)
430                } else {
431                    self.set_position(After(block));
432                    None
433                }
434            }
435        }
436    }
437
438    /// Move to the previous instruction in the same block and return it.
439    ///
440    /// - If the cursor was positioned after a block, go to the last instruction in that block.
441    /// - If there are no more instructions in the block, go to the `Before(block)` position and return
442    ///   `None`.
443    /// - If the cursor wasn't pointing anywhere, keep doing that.
444    ///
445    /// This method will never move the cursor to a different block.
446    ///
447    /// # Examples
448    ///
449    /// The `prev_inst()` method is intended for iterating backwards over the instructions in an
450    /// block like this:
451    ///
452    /// ```
453    /// # use cranelift_codegen::ir::{Function, Block};
454    /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
455    /// fn edit_block(func: &mut Function, block: Block) {
456    ///     let mut cursor = FuncCursor::new(func).at_bottom(block);
457    ///     while let Some(inst) = cursor.prev_inst() {
458    ///         // Edit instructions...
459    ///     }
460    /// }
461    /// ```
462    fn prev_inst(&mut self) -> Option<ir::Inst> {
463        use self::CursorPosition::*;
464        match self.position() {
465            Nowhere | Before(..) => None,
466            At(inst) => {
467                if let Some(prev) = self.layout().prev_inst(inst) {
468                    self.set_position(At(prev));
469                    Some(prev)
470                } else {
471                    let pos = Before(
472                        self.layout()
473                            .inst_block(inst)
474                            .expect("current instruction removed?"),
475                    );
476                    self.set_position(pos);
477                    None
478                }
479            }
480            After(block) => {
481                if let Some(prev) = self.layout().last_inst(block) {
482                    self.set_position(At(prev));
483                    Some(prev)
484                } else {
485                    self.set_position(Before(block));
486                    None
487                }
488            }
489        }
490    }
491
492    /// Insert an instruction at the current position.
493    ///
494    /// - If pointing at an instruction, the new instruction is inserted before the current
495    ///   instruction.
496    /// - If pointing at the bottom of a block, the new instruction is appended to the block.
497    /// - Otherwise panic.
498    ///
499    /// In either case, the cursor is not moved, such that repeated calls to `insert_inst()` causes
500    /// instructions to appear in insertion order in the block.
501    fn insert_inst(&mut self, inst: ir::Inst) {
502        use self::CursorPosition::*;
503        match self.position() {
504            Nowhere | Before(..) => panic!("Invalid insert_inst position"),
505            At(cur) => self.layout_mut().insert_inst(inst, cur),
506            After(block) => self.layout_mut().append_inst(inst, block),
507        }
508    }
509
510    /// Remove the instruction under the cursor.
511    ///
512    /// The cursor is left pointing at the position following the current instruction.
513    ///
514    /// Return the instruction that was removed.
515    fn remove_inst(&mut self) -> ir::Inst {
516        let inst = self.current_inst().expect("No instruction to remove");
517        self.next_inst();
518        self.layout_mut().remove_inst(inst);
519        inst
520    }
521
522    /// Remove the instruction under the cursor.
523    ///
524    /// The cursor is left pointing at the position preceding the current instruction.
525    ///
526    /// Return the instruction that was removed.
527    fn remove_inst_and_step_back(&mut self) -> ir::Inst {
528        let inst = self.current_inst().expect("No instruction to remove");
529        self.prev_inst();
530        self.layout_mut().remove_inst(inst);
531        inst
532    }
533
534    /// Insert a block at the current position and switch to it.
535    ///
536    /// As far as possible, this method behaves as if the block header were an instruction inserted
537    /// at the current position.
538    ///
539    /// - If the cursor is pointing at an existing instruction, *the current block is split in two*
540    ///   and the current instruction becomes the first instruction in the inserted block.
541    /// - If the cursor points at the bottom of a block, the new block is inserted after the current
542    ///   one, and moved to the bottom of the new block where instructions can be appended.
543    /// - If the cursor points to the top of a block, the new block is inserted above the current one.
544    /// - If the cursor is not pointing at anything, the new block is placed last in the layout.
545    ///
546    /// This means that it is always valid to call this method, and it always leaves the cursor in
547    /// a state that will insert instructions into the new block.
548    fn insert_block(&mut self, new_block: ir::Block) {
549        use self::CursorPosition::*;
550        match self.position() {
551            At(inst) => {
552                self.layout_mut().split_block(new_block, inst);
553                // All other cases move to `After(block)`, but in this case we'll stay `At(inst)`.
554                return;
555            }
556            Nowhere => self.layout_mut().append_block(new_block),
557            Before(block) => self.layout_mut().insert_block(new_block, block),
558            After(block) => self.layout_mut().insert_block_after(new_block, block),
559        }
560        // For everything but `At(inst)` we end up appending to the new block.
561        self.set_position(After(new_block));
562    }
563}
564
565/// Function cursor.
566///
567/// A `FuncCursor` holds a mutable reference to a whole `ir::Function` while keeping a position
568/// too. The function can be re-borrowed by accessing the public `cur.func` member.
569///
570/// This cursor is for use before legalization. The inserted instructions are not given an
571/// encoding.
572pub struct FuncCursor<'f> {
573    pos: CursorPosition,
574    srcloc: ir::SourceLoc,
575
576    /// The referenced function.
577    pub func: &'f mut ir::Function,
578}
579
580impl<'f> FuncCursor<'f> {
581    /// Create a new `FuncCursor` pointing nowhere.
582    pub fn new(func: &'f mut ir::Function) -> Self {
583        Self {
584            pos: CursorPosition::Nowhere,
585            srcloc: Default::default(),
586            func,
587        }
588    }
589
590    /// Use the source location of `inst` for future instructions.
591    pub fn use_srcloc(&mut self, inst: ir::Inst) {
592        self.srcloc = self.func.srcloc(inst);
593    }
594
595    /// Create an instruction builder that inserts an instruction at the current position.
596    pub fn ins(&mut self) -> ir::InsertBuilder<'_, &mut FuncCursor<'f>> {
597        ir::InsertBuilder::new(self)
598    }
599}
600
601impl<'f> Cursor for FuncCursor<'f> {
602    fn position(&self) -> CursorPosition {
603        self.pos
604    }
605
606    fn set_position(&mut self, pos: CursorPosition) {
607        self.pos = pos
608    }
609
610    fn srcloc(&self) -> ir::SourceLoc {
611        self.srcloc
612    }
613
614    fn set_srcloc(&mut self, srcloc: ir::SourceLoc) {
615        self.func.params.ensure_base_srcloc(srcloc);
616        self.srcloc = srcloc;
617    }
618
619    fn layout(&self) -> &ir::Layout {
620        &self.func.layout
621    }
622
623    fn layout_mut(&mut self) -> &mut ir::Layout {
624        &mut self.func.layout
625    }
626}
627
628impl<'c, 'f> ir::InstInserterBase<'c> for &'c mut FuncCursor<'f> {
629    fn data_flow_graph(&self) -> &ir::DataFlowGraph {
630        &self.func.dfg
631    }
632
633    fn data_flow_graph_mut(&mut self) -> &mut ir::DataFlowGraph {
634        &mut self.func.dfg
635    }
636
637    fn insert_built_inst(self, inst: ir::Inst) -> &'c mut ir::DataFlowGraph {
638        self.insert_inst(inst);
639        if !self.srcloc.is_default() {
640            self.func.set_srcloc(inst, self.srcloc);
641        }
642        &mut self.func.dfg
643    }
644}