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    /// Get the next position that a forwards traversal will move to, but do not
303    /// move this cursor.
304    fn next_position(&self) -> CursorPosition {
305        self.next_inst_position()
306            .unwrap_or_else(|| self.next_block_position())
307    }
308
309    /// Get the next position that a backwards traversal will move to, but do
310    /// not move this cursor.
311    fn prev_position(&self) -> CursorPosition {
312        self.prev_inst_position()
313            .unwrap_or_else(|| self.prev_block_position())
314    }
315
316    /// Get the position that a `cursor.next_block()` call would move this
317    /// cursor to, but do not update this cursor's position.
318    fn next_block_position(&self) -> CursorPosition {
319        let next = if let Some(block) = self.current_block() {
320            self.layout().next_block(block)
321        } else {
322            self.layout().entry_block()
323        };
324        match next {
325            Some(block) => CursorPosition::Before(block),
326            None => CursorPosition::Nowhere,
327        }
328    }
329
330    /// Go to the top of the next block in layout order and return it.
331    ///
332    /// - If the cursor wasn't pointing at anything, go to the top of the first block in the
333    ///   function.
334    /// - If there are no more blocks, leave the cursor pointing at nothing and return `None`.
335    ///
336    /// # Examples
337    ///
338    /// The `next_block()` method is intended for iterating over the blocks in layout order:
339    ///
340    /// ```
341    /// # use cranelift_codegen::ir::{Function, Block};
342    /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
343    /// fn edit_func(func: &mut Function) {
344    ///     let mut cursor = FuncCursor::new(func);
345    ///     while let Some(block) = cursor.next_block() {
346    ///         // Edit block.
347    ///     }
348    /// }
349    /// ```
350    fn next_block(&mut self) -> Option<ir::Block> {
351        let pos = self.next_block_position();
352        self.set_position(pos);
353        self.current_block()
354    }
355
356    /// Get the position that a `cursor.prev_block()` call would move this
357    /// cursor to, but do not update this cursor's position.
358    fn prev_block_position(&self) -> CursorPosition {
359        let prev = if let Some(block) = self.current_block() {
360            self.layout().prev_block(block)
361        } else {
362            self.layout().last_block()
363        };
364        match prev {
365            Some(block) => CursorPosition::After(block),
366            None => CursorPosition::Nowhere,
367        }
368    }
369
370    /// Go to the bottom of the previous block in layout order and return it.
371    ///
372    /// - If the cursor wasn't pointing at anything, go to the bottom of the last block in the
373    ///   function.
374    /// - If there are no more blocks, leave the cursor pointing at nothing and return `None`.
375    ///
376    /// # Examples
377    ///
378    /// The `prev_block()` method is intended for iterating over the blocks in backwards layout order:
379    ///
380    /// ```
381    /// # use cranelift_codegen::ir::{Function, Block};
382    /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
383    /// fn edit_func(func: &mut Function) {
384    ///     let mut cursor = FuncCursor::new(func);
385    ///     while let Some(block) = cursor.prev_block() {
386    ///         // Edit block.
387    ///     }
388    /// }
389    /// ```
390    fn prev_block(&mut self) -> Option<ir::Block> {
391        let pos = self.prev_block_position();
392        self.set_position(pos);
393        self.current_block()
394    }
395
396    /// Get the position that a `cursor.next_inst()` call would move this cursor
397    /// to, but do not update this cursor's position.
398    fn next_inst_position(&self) -> Option<CursorPosition> {
399        use self::CursorPosition::*;
400        match self.position() {
401            Nowhere | After(..) => None,
402            At(inst) => {
403                if let Some(next) = self.layout().next_inst(inst) {
404                    Some(At(next))
405                } else {
406                    Some(After(
407                        self.layout()
408                            .inst_block(inst)
409                            .expect("current instruction removed?"),
410                    ))
411                }
412            }
413            Before(block) => {
414                if let Some(next) = self.layout().first_inst(block) {
415                    Some(At(next))
416                } else {
417                    Some(After(block))
418                }
419            }
420        }
421    }
422
423    /// Move to the next instruction in the same block and return it.
424    ///
425    /// - If the cursor was positioned before a block, go to the first instruction in that block.
426    /// - If there are no more instructions in the block, go to the `After(block)` position and return
427    ///   `None`.
428    /// - If the cursor wasn't pointing anywhere, keep doing that.
429    ///
430    /// This method will never move the cursor to a different block.
431    ///
432    /// # Examples
433    ///
434    /// The `next_inst()` method is intended for iterating over the instructions in a block like
435    /// this:
436    ///
437    /// ```
438    /// # use cranelift_codegen::ir::{Function, Block};
439    /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
440    /// fn edit_block(func: &mut Function, block: Block) {
441    ///     let mut cursor = FuncCursor::new(func).at_top(block);
442    ///     while let Some(inst) = cursor.next_inst() {
443    ///         // Edit instructions...
444    ///     }
445    /// }
446    /// ```
447    /// The loop body can insert and remove instructions via the cursor.
448    ///
449    /// Iterating over all the instructions in a function looks like this:
450    ///
451    /// ```
452    /// # use cranelift_codegen::ir::{Function, Block};
453    /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
454    /// fn edit_func(func: &mut Function) {
455    ///     let mut cursor = FuncCursor::new(func);
456    ///     while let Some(block) = cursor.next_block() {
457    ///         while let Some(inst) = cursor.next_inst() {
458    ///             // Edit instructions...
459    ///         }
460    ///     }
461    /// }
462    /// ```
463    fn next_inst(&mut self) -> Option<ir::Inst> {
464        let pos = self.next_inst_position()?;
465        self.set_position(pos);
466        self.current_inst()
467    }
468
469    /// Get the position that a `cursor.prev_inst()` call would move this cursor
470    /// to, but do not update this cursor's position.
471    fn prev_inst_position(&self) -> Option<CursorPosition> {
472        use self::CursorPosition::*;
473        match self.position() {
474            Nowhere | Before(..) => None,
475            At(inst) => {
476                if let Some(prev) = self.layout().prev_inst(inst) {
477                    Some(At(prev))
478                } else {
479                    Some(Before(
480                        self.layout()
481                            .inst_block(inst)
482                            .expect("current instruction removed?"),
483                    ))
484                }
485            }
486            After(block) => {
487                if let Some(prev) = self.layout().last_inst(block) {
488                    Some(At(prev))
489                } else {
490                    Some(Before(block))
491                }
492            }
493        }
494    }
495
496    /// Move to the previous instruction in the same block and return it.
497    ///
498    /// - If the cursor was positioned after a block, go to the last instruction in that block.
499    /// - If there are no more instructions in the block, go to the `Before(block)` position and return
500    ///   `None`.
501    /// - If the cursor wasn't pointing anywhere, keep doing that.
502    ///
503    /// This method will never move the cursor to a different block.
504    ///
505    /// # Examples
506    ///
507    /// The `prev_inst()` method is intended for iterating backwards over the instructions in an
508    /// block like this:
509    ///
510    /// ```
511    /// # use cranelift_codegen::ir::{Function, Block};
512    /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
513    /// fn edit_block(func: &mut Function, block: Block) {
514    ///     let mut cursor = FuncCursor::new(func).at_bottom(block);
515    ///     while let Some(inst) = cursor.prev_inst() {
516    ///         // Edit instructions...
517    ///     }
518    /// }
519    /// ```
520    fn prev_inst(&mut self) -> Option<ir::Inst> {
521        let pos = self.prev_inst_position()?;
522        self.set_position(pos);
523        self.current_inst()
524    }
525
526    /// Insert an instruction at the current position.
527    ///
528    /// - If pointing at an instruction, the new instruction is inserted before the current
529    ///   instruction.
530    /// - If pointing at the bottom of a block, the new instruction is appended to the block.
531    /// - Otherwise panic.
532    ///
533    /// In either case, the cursor is not moved, such that repeated calls to `insert_inst()` causes
534    /// instructions to appear in insertion order in the block.
535    fn insert_inst(&mut self, inst: ir::Inst) {
536        use self::CursorPosition::*;
537        match self.position() {
538            Nowhere | Before(..) => panic!("Invalid insert_inst position"),
539            At(cur) => self.layout_mut().insert_inst(inst, cur),
540            After(block) => self.layout_mut().append_inst(inst, block),
541        }
542    }
543
544    /// Remove the instruction under the cursor.
545    ///
546    /// The cursor is left pointing at the position following the current instruction.
547    ///
548    /// Return the instruction that was removed.
549    fn remove_inst(&mut self) -> ir::Inst {
550        let inst = self.current_inst().expect("No instruction to remove");
551        self.next_inst();
552        self.layout_mut().remove_inst(inst);
553        inst
554    }
555
556    /// Remove the instruction under the cursor.
557    ///
558    /// The cursor is left pointing at the position preceding the current instruction.
559    ///
560    /// Return the instruction that was removed.
561    fn remove_inst_and_step_back(&mut self) -> ir::Inst {
562        let inst = self.current_inst().expect("No instruction to remove");
563        self.prev_inst();
564        self.layout_mut().remove_inst(inst);
565        inst
566    }
567
568    /// Replace the instruction under the cursor with `new_inst`.
569    ///
570    /// The cursor is left pointing at the new instruction.
571    ///
572    /// The old instruction that was replaced is returned.
573    fn replace_inst(&mut self, new_inst: ir::Inst) -> ir::Inst {
574        let prev_inst = self.remove_inst();
575        self.insert_inst(new_inst);
576        prev_inst
577    }
578
579    /// Insert a block at the current position and switch to it.
580    ///
581    /// As far as possible, this method behaves as if the block header were an instruction inserted
582    /// at the current position.
583    ///
584    /// - If the cursor is pointing at an existing instruction, *the current block is split in two*
585    ///   and the current instruction becomes the first instruction in the inserted block.
586    /// - If the cursor points at the bottom of a block, the new block is inserted after the current
587    ///   one, and moved to the bottom of the new block where instructions can be appended.
588    /// - If the cursor points to the top of a block, the new block is inserted above the current one.
589    /// - If the cursor is not pointing at anything, the new block is placed last in the layout.
590    ///
591    /// This means that it is always valid to call this method, and it always leaves the cursor in
592    /// a state that will insert instructions into the new block.
593    fn insert_block(&mut self, new_block: ir::Block) {
594        use self::CursorPosition::*;
595        match self.position() {
596            At(inst) => {
597                self.layout_mut().split_block(new_block, inst);
598                // All other cases move to `After(block)`, but in this case we'll stay `At(inst)`.
599                return;
600            }
601            Nowhere => self.layout_mut().append_block(new_block),
602            Before(block) => self.layout_mut().insert_block(new_block, block),
603            After(block) => self.layout_mut().insert_block_after(new_block, block),
604        }
605        // For everything but `At(inst)` we end up appending to the new block.
606        self.set_position(After(new_block));
607    }
608}
609
610/// Function cursor.
611///
612/// A `FuncCursor` holds a mutable reference to a whole `ir::Function` while keeping a position
613/// too. The function can be re-borrowed by accessing the public `cur.func` member.
614///
615/// This cursor is for use before legalization. The inserted instructions are not given an
616/// encoding.
617pub struct FuncCursor<'f> {
618    pos: CursorPosition,
619    srcloc: ir::SourceLoc,
620
621    /// The referenced function.
622    pub func: &'f mut ir::Function,
623}
624
625impl<'f> FuncCursor<'f> {
626    /// Create a new `FuncCursor` pointing nowhere.
627    pub fn new(func: &'f mut ir::Function) -> Self {
628        Self {
629            pos: CursorPosition::Nowhere,
630            srcloc: Default::default(),
631            func,
632        }
633    }
634
635    /// Use the source location of `inst` for future instructions.
636    pub fn use_srcloc(&mut self, inst: ir::Inst) {
637        self.srcloc = self.func.srcloc(inst);
638    }
639
640    /// Create an instruction builder that inserts an instruction at the current position.
641    pub fn ins(&mut self) -> ir::InsertBuilder<'_, &mut FuncCursor<'f>> {
642        ir::InsertBuilder::new(self)
643    }
644}
645
646impl<'f> Cursor for FuncCursor<'f> {
647    fn position(&self) -> CursorPosition {
648        self.pos
649    }
650
651    fn set_position(&mut self, pos: CursorPosition) {
652        self.pos = pos
653    }
654
655    fn srcloc(&self) -> ir::SourceLoc {
656        self.srcloc
657    }
658
659    fn set_srcloc(&mut self, srcloc: ir::SourceLoc) {
660        self.func.params.ensure_base_srcloc(srcloc);
661        self.srcloc = srcloc;
662    }
663
664    fn layout(&self) -> &ir::Layout {
665        &self.func.layout
666    }
667
668    fn layout_mut(&mut self) -> &mut ir::Layout {
669        &mut self.func.layout
670    }
671}
672
673impl<'c, 'f> ir::InstInserterBase<'c> for &'c mut FuncCursor<'f> {
674    fn data_flow_graph(&self) -> &ir::DataFlowGraph {
675        &self.func.dfg
676    }
677
678    fn data_flow_graph_mut(&mut self) -> &mut ir::DataFlowGraph {
679        &mut self.func.dfg
680    }
681
682    fn insert_built_inst(self, inst: ir::Inst) -> &'c mut ir::DataFlowGraph {
683        self.insert_inst(inst);
684        if !self.srcloc.is_default() {
685            self.func.set_srcloc(inst, self.srcloc);
686        }
687        &mut self.func.dfg
688    }
689}