1747ad3c4Slazypassion //! Cursor library.
2747ad3c4Slazypassion //!
3747ad3c4Slazypassion //! This module defines cursor data types that can be used for inserting instructions.
4747ad3c4Slazypassion 
5747ad3c4Slazypassion use crate::ir;
6747ad3c4Slazypassion 
7747ad3c4Slazypassion /// The possible positions of a cursor.
8747ad3c4Slazypassion #[derive(Clone, Copy, PartialEq, Eq, Debug)]
9747ad3c4Slazypassion pub enum CursorPosition {
10747ad3c4Slazypassion     /// Cursor is not pointing anywhere. No instructions can be inserted.
11747ad3c4Slazypassion     Nowhere,
12747ad3c4Slazypassion     /// Cursor is pointing at an existing instruction.
13747ad3c4Slazypassion     /// New instructions will be inserted *before* the current instruction.
14747ad3c4Slazypassion     At(ir::Inst),
1507f335dcSRyan Hunt     /// Cursor is before the beginning of a block. No instructions can be inserted. Calling
16832666c4SRyan Hunt     /// `next_inst()` will move to the first instruction in the block.
17832666c4SRyan Hunt     Before(ir::Block),
1807f335dcSRyan Hunt     /// Cursor is pointing after the end of a block.
19832666c4SRyan Hunt     /// New instructions will be appended to the block.
20832666c4SRyan Hunt     After(ir::Block),
21747ad3c4Slazypassion }
22747ad3c4Slazypassion 
23747ad3c4Slazypassion /// All cursor types implement the `Cursor` which provides common navigation operations.
24747ad3c4Slazypassion pub trait Cursor {
25747ad3c4Slazypassion     /// Get the current cursor position.
position(&self) -> CursorPosition26747ad3c4Slazypassion     fn position(&self) -> CursorPosition;
27747ad3c4Slazypassion 
28747ad3c4Slazypassion     /// Set the current position.
set_position(&mut self, pos: CursorPosition)29747ad3c4Slazypassion     fn set_position(&mut self, pos: CursorPosition);
30747ad3c4Slazypassion 
31747ad3c4Slazypassion     /// Get the source location that should be assigned to new instructions.
srcloc(&self) -> ir::SourceLoc32747ad3c4Slazypassion     fn srcloc(&self) -> ir::SourceLoc;
33747ad3c4Slazypassion 
34747ad3c4Slazypassion     /// Set the source location that should be assigned to new instructions.
set_srcloc(&mut self, srcloc: ir::SourceLoc)35747ad3c4Slazypassion     fn set_srcloc(&mut self, srcloc: ir::SourceLoc);
36747ad3c4Slazypassion 
37747ad3c4Slazypassion     /// Borrow a reference to the function layout that this cursor is navigating.
layout(&self) -> &ir::Layout38747ad3c4Slazypassion     fn layout(&self) -> &ir::Layout;
39747ad3c4Slazypassion 
40747ad3c4Slazypassion     /// Borrow a mutable reference to the function layout that this cursor is navigating.
layout_mut(&mut self) -> &mut ir::Layout41747ad3c4Slazypassion     fn layout_mut(&mut self) -> &mut ir::Layout;
42747ad3c4Slazypassion 
43747ad3c4Slazypassion     /// Exchange this cursor for one with a set source location.
44747ad3c4Slazypassion     ///
45747ad3c4Slazypassion     /// This is intended to be used as a builder method:
46747ad3c4Slazypassion     ///
47747ad3c4Slazypassion     /// ```
48832666c4SRyan Hunt     /// # use cranelift_codegen::ir::{Function, Block, SourceLoc};
49747ad3c4Slazypassion     /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
50747ad3c4Slazypassion     /// fn edit_func(func: &mut Function, srcloc: SourceLoc) {
51747ad3c4Slazypassion     ///     let mut pos = FuncCursor::new(func).with_srcloc(srcloc);
52747ad3c4Slazypassion     ///
53747ad3c4Slazypassion     ///     // Use `pos`...
54747ad3c4Slazypassion     /// }
55747ad3c4Slazypassion     /// ```
with_srcloc(mut self, srcloc: ir::SourceLoc) -> Self where Self: Sized,56747ad3c4Slazypassion     fn with_srcloc(mut self, srcloc: ir::SourceLoc) -> Self
57747ad3c4Slazypassion     where
58747ad3c4Slazypassion         Self: Sized,
59747ad3c4Slazypassion     {
60747ad3c4Slazypassion         self.set_srcloc(srcloc);
61747ad3c4Slazypassion         self
62747ad3c4Slazypassion     }
63747ad3c4Slazypassion 
64747ad3c4Slazypassion     /// Rebuild this cursor positioned at `pos`.
at_position(mut self, pos: CursorPosition) -> Self where Self: Sized,65747ad3c4Slazypassion     fn at_position(mut self, pos: CursorPosition) -> Self
66747ad3c4Slazypassion     where
67747ad3c4Slazypassion         Self: Sized,
68747ad3c4Slazypassion     {
69747ad3c4Slazypassion         self.set_position(pos);
70747ad3c4Slazypassion         self
71747ad3c4Slazypassion     }
72747ad3c4Slazypassion 
73747ad3c4Slazypassion     /// Rebuild this cursor positioned at `inst`.
74747ad3c4Slazypassion     ///
75747ad3c4Slazypassion     /// This is intended to be used as a builder method:
76747ad3c4Slazypassion     ///
77747ad3c4Slazypassion     /// ```
78832666c4SRyan Hunt     /// # use cranelift_codegen::ir::{Function, Block, Inst};
79747ad3c4Slazypassion     /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
80747ad3c4Slazypassion     /// fn edit_func(func: &mut Function, inst: Inst) {
81747ad3c4Slazypassion     ///     let mut pos = FuncCursor::new(func).at_inst(inst);
82747ad3c4Slazypassion     ///
83747ad3c4Slazypassion     ///     // Use `pos`...
84747ad3c4Slazypassion     /// }
85747ad3c4Slazypassion     /// ```
at_inst(mut self, inst: ir::Inst) -> Self where Self: Sized,86747ad3c4Slazypassion     fn at_inst(mut self, inst: ir::Inst) -> Self
87747ad3c4Slazypassion     where
88747ad3c4Slazypassion         Self: Sized,
89747ad3c4Slazypassion     {
90747ad3c4Slazypassion         self.goto_inst(inst);
91747ad3c4Slazypassion         self
92747ad3c4Slazypassion     }
93747ad3c4Slazypassion 
94832666c4SRyan Hunt     /// Rebuild this cursor positioned at the first insertion point for `block`.
95747ad3c4Slazypassion     /// This differs from `at_first_inst` in that it doesn't assume that any
96832666c4SRyan Hunt     /// instructions have been inserted into `block` yet.
97747ad3c4Slazypassion     ///
98747ad3c4Slazypassion     /// This is intended to be used as a builder method:
99747ad3c4Slazypassion     ///
100747ad3c4Slazypassion     /// ```
101832666c4SRyan Hunt     /// # use cranelift_codegen::ir::{Function, Block, Inst};
102747ad3c4Slazypassion     /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
103832666c4SRyan Hunt     /// fn edit_func(func: &mut Function, block: Block) {
104832666c4SRyan Hunt     ///     let mut pos = FuncCursor::new(func).at_first_insertion_point(block);
105747ad3c4Slazypassion     ///
106747ad3c4Slazypassion     ///     // Use `pos`...
107747ad3c4Slazypassion     /// }
108747ad3c4Slazypassion     /// ```
at_first_insertion_point(mut self, block: ir::Block) -> Self where Self: Sized,109832666c4SRyan Hunt     fn at_first_insertion_point(mut self, block: ir::Block) -> Self
110747ad3c4Slazypassion     where
111747ad3c4Slazypassion         Self: Sized,
112747ad3c4Slazypassion     {
113832666c4SRyan Hunt         self.goto_first_insertion_point(block);
114747ad3c4Slazypassion         self
115747ad3c4Slazypassion     }
116747ad3c4Slazypassion 
117832666c4SRyan Hunt     /// Rebuild this cursor positioned at the first instruction in `block`.
118747ad3c4Slazypassion     ///
119747ad3c4Slazypassion     /// This is intended to be used as a builder method:
120747ad3c4Slazypassion     ///
121747ad3c4Slazypassion     /// ```
122832666c4SRyan Hunt     /// # use cranelift_codegen::ir::{Function, Block, Inst};
123747ad3c4Slazypassion     /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
124832666c4SRyan Hunt     /// fn edit_func(func: &mut Function, block: Block) {
125832666c4SRyan Hunt     ///     let mut pos = FuncCursor::new(func).at_first_inst(block);
126747ad3c4Slazypassion     ///
127747ad3c4Slazypassion     ///     // Use `pos`...
128747ad3c4Slazypassion     /// }
129747ad3c4Slazypassion     /// ```
at_first_inst(mut self, block: ir::Block) -> Self where Self: Sized,130832666c4SRyan Hunt     fn at_first_inst(mut self, block: ir::Block) -> Self
131747ad3c4Slazypassion     where
132747ad3c4Slazypassion         Self: Sized,
133747ad3c4Slazypassion     {
134832666c4SRyan Hunt         self.goto_first_inst(block);
135747ad3c4Slazypassion         self
136747ad3c4Slazypassion     }
137747ad3c4Slazypassion 
138832666c4SRyan Hunt     /// Rebuild this cursor positioned at the last instruction in `block`.
139747ad3c4Slazypassion     ///
140747ad3c4Slazypassion     /// This is intended to be used as a builder method:
141747ad3c4Slazypassion     ///
142747ad3c4Slazypassion     /// ```
143832666c4SRyan Hunt     /// # use cranelift_codegen::ir::{Function, Block, Inst};
144747ad3c4Slazypassion     /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
145832666c4SRyan Hunt     /// fn edit_func(func: &mut Function, block: Block) {
146832666c4SRyan Hunt     ///     let mut pos = FuncCursor::new(func).at_last_inst(block);
147747ad3c4Slazypassion     ///
148747ad3c4Slazypassion     ///     // Use `pos`...
149747ad3c4Slazypassion     /// }
150747ad3c4Slazypassion     /// ```
at_last_inst(mut self, block: ir::Block) -> Self where Self: Sized,151832666c4SRyan Hunt     fn at_last_inst(mut self, block: ir::Block) -> Self
152747ad3c4Slazypassion     where
153747ad3c4Slazypassion         Self: Sized,
154747ad3c4Slazypassion     {
155832666c4SRyan Hunt         self.goto_last_inst(block);
156747ad3c4Slazypassion         self
157747ad3c4Slazypassion     }
158747ad3c4Slazypassion 
159747ad3c4Slazypassion     /// Rebuild this cursor positioned after `inst`.
160747ad3c4Slazypassion     ///
161747ad3c4Slazypassion     /// This is intended to be used as a builder method:
162747ad3c4Slazypassion     ///
163747ad3c4Slazypassion     /// ```
164832666c4SRyan Hunt     /// # use cranelift_codegen::ir::{Function, Block, Inst};
165747ad3c4Slazypassion     /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
166747ad3c4Slazypassion     /// fn edit_func(func: &mut Function, inst: Inst) {
167747ad3c4Slazypassion     ///     let mut pos = FuncCursor::new(func).after_inst(inst);
168747ad3c4Slazypassion     ///
169747ad3c4Slazypassion     ///     // Use `pos`...
170747ad3c4Slazypassion     /// }
171747ad3c4Slazypassion     /// ```
after_inst(mut self, inst: ir::Inst) -> Self where Self: Sized,172747ad3c4Slazypassion     fn after_inst(mut self, inst: ir::Inst) -> Self
173747ad3c4Slazypassion     where
174747ad3c4Slazypassion         Self: Sized,
175747ad3c4Slazypassion     {
176747ad3c4Slazypassion         self.goto_after_inst(inst);
177747ad3c4Slazypassion         self
178747ad3c4Slazypassion     }
179747ad3c4Slazypassion 
180832666c4SRyan Hunt     /// Rebuild this cursor positioned at the top of `block`.
181747ad3c4Slazypassion     ///
182747ad3c4Slazypassion     /// This is intended to be used as a builder method:
183747ad3c4Slazypassion     ///
184747ad3c4Slazypassion     /// ```
185832666c4SRyan Hunt     /// # use cranelift_codegen::ir::{Function, Block, Inst};
186747ad3c4Slazypassion     /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
187832666c4SRyan Hunt     /// fn edit_func(func: &mut Function, block: Block) {
188832666c4SRyan Hunt     ///     let mut pos = FuncCursor::new(func).at_top(block);
189747ad3c4Slazypassion     ///
190747ad3c4Slazypassion     ///     // Use `pos`...
191747ad3c4Slazypassion     /// }
192747ad3c4Slazypassion     /// ```
at_top(mut self, block: ir::Block) -> Self where Self: Sized,193832666c4SRyan Hunt     fn at_top(mut self, block: ir::Block) -> Self
194747ad3c4Slazypassion     where
195747ad3c4Slazypassion         Self: Sized,
196747ad3c4Slazypassion     {
197832666c4SRyan Hunt         self.goto_top(block);
198747ad3c4Slazypassion         self
199747ad3c4Slazypassion     }
200747ad3c4Slazypassion 
201832666c4SRyan Hunt     /// Rebuild this cursor positioned at the bottom of `block`.
202747ad3c4Slazypassion     ///
203747ad3c4Slazypassion     /// This is intended to be used as a builder method:
204747ad3c4Slazypassion     ///
205747ad3c4Slazypassion     /// ```
206832666c4SRyan Hunt     /// # use cranelift_codegen::ir::{Function, Block, Inst};
207747ad3c4Slazypassion     /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
208832666c4SRyan Hunt     /// fn edit_func(func: &mut Function, block: Block) {
209832666c4SRyan Hunt     ///     let mut pos = FuncCursor::new(func).at_bottom(block);
210747ad3c4Slazypassion     ///
211747ad3c4Slazypassion     ///     // Use `pos`...
212747ad3c4Slazypassion     /// }
213747ad3c4Slazypassion     /// ```
at_bottom(mut self, block: ir::Block) -> Self where Self: Sized,214832666c4SRyan Hunt     fn at_bottom(mut self, block: ir::Block) -> Self
215747ad3c4Slazypassion     where
216747ad3c4Slazypassion         Self: Sized,
217747ad3c4Slazypassion     {
218832666c4SRyan Hunt         self.goto_bottom(block);
219747ad3c4Slazypassion         self
220747ad3c4Slazypassion     }
221747ad3c4Slazypassion 
222832666c4SRyan Hunt     /// Get the block corresponding to the current position.
current_block(&self) -> Option<ir::Block>223832666c4SRyan Hunt     fn current_block(&self) -> Option<ir::Block> {
224747ad3c4Slazypassion         use self::CursorPosition::*;
225747ad3c4Slazypassion         match self.position() {
226747ad3c4Slazypassion             Nowhere => None,
227832666c4SRyan Hunt             At(inst) => self.layout().inst_block(inst),
228832666c4SRyan Hunt             Before(block) | After(block) => Some(block),
229747ad3c4Slazypassion         }
230747ad3c4Slazypassion     }
231747ad3c4Slazypassion 
232747ad3c4Slazypassion     /// Get the instruction corresponding to the current position, if any.
current_inst(&self) -> Option<ir::Inst>233747ad3c4Slazypassion     fn current_inst(&self) -> Option<ir::Inst> {
234747ad3c4Slazypassion         use self::CursorPosition::*;
235747ad3c4Slazypassion         match self.position() {
236747ad3c4Slazypassion             At(inst) => Some(inst),
237747ad3c4Slazypassion             _ => None,
238747ad3c4Slazypassion         }
239747ad3c4Slazypassion     }
240747ad3c4Slazypassion 
241747ad3c4Slazypassion     /// Go to the position after a specific instruction, which must be inserted
242747ad3c4Slazypassion     /// in the layout. New instructions will be inserted after `inst`.
goto_after_inst(&mut self, inst: ir::Inst)243747ad3c4Slazypassion     fn goto_after_inst(&mut self, inst: ir::Inst) {
244832666c4SRyan Hunt         debug_assert!(self.layout().inst_block(inst).is_some());
245747ad3c4Slazypassion         let new_pos = if let Some(next) = self.layout().next_inst(inst) {
246747ad3c4Slazypassion             CursorPosition::At(next)
247747ad3c4Slazypassion         } else {
248747ad3c4Slazypassion             CursorPosition::After(
249747ad3c4Slazypassion                 self.layout()
250832666c4SRyan Hunt                     .inst_block(inst)
251747ad3c4Slazypassion                     .expect("current instruction removed?"),
252747ad3c4Slazypassion             )
253747ad3c4Slazypassion         };
254747ad3c4Slazypassion         self.set_position(new_pos);
255747ad3c4Slazypassion     }
256747ad3c4Slazypassion 
257747ad3c4Slazypassion     /// Go to a specific instruction which must be inserted in the layout.
258747ad3c4Slazypassion     /// New instructions will be inserted before `inst`.
goto_inst(&mut self, inst: ir::Inst)259747ad3c4Slazypassion     fn goto_inst(&mut self, inst: ir::Inst) {
260832666c4SRyan Hunt         debug_assert!(self.layout().inst_block(inst).is_some());
261747ad3c4Slazypassion         self.set_position(CursorPosition::At(inst));
262747ad3c4Slazypassion     }
263747ad3c4Slazypassion 
264832666c4SRyan Hunt     /// Go to the position for inserting instructions at the beginning of `block`,
265747ad3c4Slazypassion     /// which unlike `goto_first_inst` doesn't assume that any instructions have
266832666c4SRyan Hunt     /// been inserted into `block` yet.
goto_first_insertion_point(&mut self, block: ir::Block)267832666c4SRyan Hunt     fn goto_first_insertion_point(&mut self, block: ir::Block) {
268832666c4SRyan Hunt         if let Some(inst) = self.layout().first_inst(block) {
269747ad3c4Slazypassion             self.goto_inst(inst);
270747ad3c4Slazypassion         } else {
271832666c4SRyan Hunt             self.goto_bottom(block);
272747ad3c4Slazypassion         }
273747ad3c4Slazypassion     }
274747ad3c4Slazypassion 
275832666c4SRyan Hunt     /// Go to the first instruction in `block`.
goto_first_inst(&mut self, block: ir::Block)276832666c4SRyan Hunt     fn goto_first_inst(&mut self, block: ir::Block) {
277832666c4SRyan Hunt         let inst = self.layout().first_inst(block).expect("Empty block");
278747ad3c4Slazypassion         self.goto_inst(inst);
279747ad3c4Slazypassion     }
280747ad3c4Slazypassion 
281832666c4SRyan Hunt     /// Go to the last instruction in `block`.
goto_last_inst(&mut self, block: ir::Block)282832666c4SRyan Hunt     fn goto_last_inst(&mut self, block: ir::Block) {
283832666c4SRyan Hunt         let inst = self.layout().last_inst(block).expect("Empty block");
284747ad3c4Slazypassion         self.goto_inst(inst);
285747ad3c4Slazypassion     }
286747ad3c4Slazypassion 
287832666c4SRyan Hunt     /// Go to the top of `block` which must be inserted into the layout.
288747ad3c4Slazypassion     /// At this position, instructions cannot be inserted, but `next_inst()` will move to the first
289832666c4SRyan Hunt     /// instruction in `block`.
goto_top(&mut self, block: ir::Block)290832666c4SRyan Hunt     fn goto_top(&mut self, block: ir::Block) {
291832666c4SRyan Hunt         debug_assert!(self.layout().is_block_inserted(block));
292832666c4SRyan Hunt         self.set_position(CursorPosition::Before(block));
293747ad3c4Slazypassion     }
294747ad3c4Slazypassion 
295832666c4SRyan Hunt     /// Go to the bottom of `block` which must be inserted into the layout.
296832666c4SRyan Hunt     /// At this position, inserted instructions will be appended to `block`.
goto_bottom(&mut self, block: ir::Block)297832666c4SRyan Hunt     fn goto_bottom(&mut self, block: ir::Block) {
298832666c4SRyan Hunt         debug_assert!(self.layout().is_block_inserted(block));
299832666c4SRyan Hunt         self.set_position(CursorPosition::After(block));
300747ad3c4Slazypassion     }
301747ad3c4Slazypassion 
302*3d4bd054SNick Fitzgerald     /// Get the next position that a forwards traversal will move to, but do not
303*3d4bd054SNick Fitzgerald     /// move this cursor.
next_position(&self) -> CursorPosition304*3d4bd054SNick Fitzgerald     fn next_position(&self) -> CursorPosition {
305*3d4bd054SNick Fitzgerald         self.next_inst_position()
306*3d4bd054SNick Fitzgerald             .unwrap_or_else(|| self.next_block_position())
307*3d4bd054SNick Fitzgerald     }
308*3d4bd054SNick Fitzgerald 
309*3d4bd054SNick Fitzgerald     /// Get the next position that a backwards traversal will move to, but do
310*3d4bd054SNick Fitzgerald     /// not move this cursor.
prev_position(&self) -> CursorPosition311*3d4bd054SNick Fitzgerald     fn prev_position(&self) -> CursorPosition {
312*3d4bd054SNick Fitzgerald         self.prev_inst_position()
313*3d4bd054SNick Fitzgerald             .unwrap_or_else(|| self.prev_block_position())
314*3d4bd054SNick Fitzgerald     }
315*3d4bd054SNick Fitzgerald 
316*3d4bd054SNick Fitzgerald     /// Get the position that a `cursor.next_block()` call would move this
317*3d4bd054SNick Fitzgerald     /// cursor to, but do not update this cursor's position.
next_block_position(&self) -> CursorPosition318*3d4bd054SNick Fitzgerald     fn next_block_position(&self) -> CursorPosition {
319*3d4bd054SNick Fitzgerald         let next = if let Some(block) = self.current_block() {
320*3d4bd054SNick Fitzgerald             self.layout().next_block(block)
321*3d4bd054SNick Fitzgerald         } else {
322*3d4bd054SNick Fitzgerald             self.layout().entry_block()
323*3d4bd054SNick Fitzgerald         };
324*3d4bd054SNick Fitzgerald         match next {
325*3d4bd054SNick Fitzgerald             Some(block) => CursorPosition::Before(block),
326*3d4bd054SNick Fitzgerald             None => CursorPosition::Nowhere,
327*3d4bd054SNick Fitzgerald         }
328*3d4bd054SNick Fitzgerald     }
329*3d4bd054SNick Fitzgerald 
330832666c4SRyan Hunt     /// Go to the top of the next block in layout order and return it.
331747ad3c4Slazypassion     ///
332832666c4SRyan Hunt     /// - If the cursor wasn't pointing at anything, go to the top of the first block in the
333747ad3c4Slazypassion     ///   function.
334832666c4SRyan Hunt     /// - If there are no more blocks, leave the cursor pointing at nothing and return `None`.
335747ad3c4Slazypassion     ///
336747ad3c4Slazypassion     /// # Examples
337747ad3c4Slazypassion     ///
338832666c4SRyan Hunt     /// The `next_block()` method is intended for iterating over the blocks in layout order:
339747ad3c4Slazypassion     ///
340747ad3c4Slazypassion     /// ```
341832666c4SRyan Hunt     /// # use cranelift_codegen::ir::{Function, Block};
342747ad3c4Slazypassion     /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
343747ad3c4Slazypassion     /// fn edit_func(func: &mut Function) {
344747ad3c4Slazypassion     ///     let mut cursor = FuncCursor::new(func);
345832666c4SRyan Hunt     ///     while let Some(block) = cursor.next_block() {
346832666c4SRyan Hunt     ///         // Edit block.
347747ad3c4Slazypassion     ///     }
348747ad3c4Slazypassion     /// }
349747ad3c4Slazypassion     /// ```
next_block(&mut self) -> Option<ir::Block>350832666c4SRyan Hunt     fn next_block(&mut self) -> Option<ir::Block> {
351*3d4bd054SNick Fitzgerald         let pos = self.next_block_position();
352*3d4bd054SNick Fitzgerald         self.set_position(pos);
353*3d4bd054SNick Fitzgerald         self.current_block()
354*3d4bd054SNick Fitzgerald     }
355*3d4bd054SNick Fitzgerald 
356*3d4bd054SNick Fitzgerald     /// Get the position that a `cursor.prev_block()` call would move this
357*3d4bd054SNick Fitzgerald     /// cursor to, but do not update this cursor's position.
prev_block_position(&self) -> CursorPosition358*3d4bd054SNick Fitzgerald     fn prev_block_position(&self) -> CursorPosition {
359*3d4bd054SNick Fitzgerald         let prev = if let Some(block) = self.current_block() {
360*3d4bd054SNick Fitzgerald             self.layout().prev_block(block)
361747ad3c4Slazypassion         } else {
362*3d4bd054SNick Fitzgerald             self.layout().last_block()
363747ad3c4Slazypassion         };
364*3d4bd054SNick Fitzgerald         match prev {
365*3d4bd054SNick Fitzgerald             Some(block) => CursorPosition::After(block),
366747ad3c4Slazypassion             None => CursorPosition::Nowhere,
367*3d4bd054SNick Fitzgerald         }
368747ad3c4Slazypassion     }
369747ad3c4Slazypassion 
370832666c4SRyan Hunt     /// Go to the bottom of the previous block in layout order and return it.
371747ad3c4Slazypassion     ///
372832666c4SRyan Hunt     /// - If the cursor wasn't pointing at anything, go to the bottom of the last block in the
373747ad3c4Slazypassion     ///   function.
374832666c4SRyan Hunt     /// - If there are no more blocks, leave the cursor pointing at nothing and return `None`.
375747ad3c4Slazypassion     ///
376747ad3c4Slazypassion     /// # Examples
377747ad3c4Slazypassion     ///
378832666c4SRyan Hunt     /// The `prev_block()` method is intended for iterating over the blocks in backwards layout order:
379747ad3c4Slazypassion     ///
380747ad3c4Slazypassion     /// ```
381832666c4SRyan Hunt     /// # use cranelift_codegen::ir::{Function, Block};
382747ad3c4Slazypassion     /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
383747ad3c4Slazypassion     /// fn edit_func(func: &mut Function) {
384747ad3c4Slazypassion     ///     let mut cursor = FuncCursor::new(func);
385832666c4SRyan Hunt     ///     while let Some(block) = cursor.prev_block() {
386832666c4SRyan Hunt     ///         // Edit block.
387747ad3c4Slazypassion     ///     }
388747ad3c4Slazypassion     /// }
389747ad3c4Slazypassion     /// ```
prev_block(&mut self) -> Option<ir::Block>390832666c4SRyan Hunt     fn prev_block(&mut self) -> Option<ir::Block> {
391*3d4bd054SNick Fitzgerald         let pos = self.prev_block_position();
392*3d4bd054SNick Fitzgerald         self.set_position(pos);
393*3d4bd054SNick Fitzgerald         self.current_block()
394*3d4bd054SNick Fitzgerald     }
395*3d4bd054SNick Fitzgerald 
396*3d4bd054SNick Fitzgerald     /// Get the position that a `cursor.next_inst()` call would move this cursor
397*3d4bd054SNick Fitzgerald     /// to, but do not update this cursor's position.
next_inst_position(&self) -> Option<CursorPosition>398*3d4bd054SNick Fitzgerald     fn next_inst_position(&self) -> Option<CursorPosition> {
399*3d4bd054SNick Fitzgerald         use self::CursorPosition::*;
400*3d4bd054SNick Fitzgerald         match self.position() {
401*3d4bd054SNick Fitzgerald             Nowhere | After(..) => None,
402*3d4bd054SNick Fitzgerald             At(inst) => {
403*3d4bd054SNick Fitzgerald                 if let Some(next) = self.layout().next_inst(inst) {
404*3d4bd054SNick Fitzgerald                     Some(At(next))
405747ad3c4Slazypassion                 } else {
406*3d4bd054SNick Fitzgerald                     Some(After(
407*3d4bd054SNick Fitzgerald                         self.layout()
408*3d4bd054SNick Fitzgerald                             .inst_block(inst)
409*3d4bd054SNick Fitzgerald                             .expect("current instruction removed?"),
410*3d4bd054SNick Fitzgerald                     ))
411*3d4bd054SNick Fitzgerald                 }
412*3d4bd054SNick Fitzgerald             }
413*3d4bd054SNick Fitzgerald             Before(block) => {
414*3d4bd054SNick Fitzgerald                 if let Some(next) = self.layout().first_inst(block) {
415*3d4bd054SNick Fitzgerald                     Some(At(next))
416*3d4bd054SNick Fitzgerald                 } else {
417*3d4bd054SNick Fitzgerald                     Some(After(block))
418*3d4bd054SNick Fitzgerald                 }
419*3d4bd054SNick Fitzgerald             }
420*3d4bd054SNick Fitzgerald         }
421747ad3c4Slazypassion     }
422747ad3c4Slazypassion 
423832666c4SRyan Hunt     /// Move to the next instruction in the same block and return it.
424747ad3c4Slazypassion     ///
42507f335dcSRyan Hunt     /// - If the cursor was positioned before a block, go to the first instruction in that block.
426832666c4SRyan Hunt     /// - If there are no more instructions in the block, go to the `After(block)` position and return
427747ad3c4Slazypassion     ///   `None`.
428747ad3c4Slazypassion     /// - If the cursor wasn't pointing anywhere, keep doing that.
429747ad3c4Slazypassion     ///
430832666c4SRyan Hunt     /// This method will never move the cursor to a different block.
431747ad3c4Slazypassion     ///
432747ad3c4Slazypassion     /// # Examples
433747ad3c4Slazypassion     ///
43407f335dcSRyan Hunt     /// The `next_inst()` method is intended for iterating over the instructions in a block like
435747ad3c4Slazypassion     /// this:
436747ad3c4Slazypassion     ///
437747ad3c4Slazypassion     /// ```
438832666c4SRyan Hunt     /// # use cranelift_codegen::ir::{Function, Block};
439747ad3c4Slazypassion     /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
440832666c4SRyan Hunt     /// fn edit_block(func: &mut Function, block: Block) {
441832666c4SRyan Hunt     ///     let mut cursor = FuncCursor::new(func).at_top(block);
442747ad3c4Slazypassion     ///     while let Some(inst) = cursor.next_inst() {
443747ad3c4Slazypassion     ///         // Edit instructions...
444747ad3c4Slazypassion     ///     }
445747ad3c4Slazypassion     /// }
446747ad3c4Slazypassion     /// ```
447747ad3c4Slazypassion     /// The loop body can insert and remove instructions via the cursor.
448747ad3c4Slazypassion     ///
449747ad3c4Slazypassion     /// Iterating over all the instructions in a function looks like this:
450747ad3c4Slazypassion     ///
451747ad3c4Slazypassion     /// ```
452832666c4SRyan Hunt     /// # use cranelift_codegen::ir::{Function, Block};
453747ad3c4Slazypassion     /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
454747ad3c4Slazypassion     /// fn edit_func(func: &mut Function) {
455747ad3c4Slazypassion     ///     let mut cursor = FuncCursor::new(func);
456832666c4SRyan Hunt     ///     while let Some(block) = cursor.next_block() {
457747ad3c4Slazypassion     ///         while let Some(inst) = cursor.next_inst() {
458747ad3c4Slazypassion     ///             // Edit instructions...
459747ad3c4Slazypassion     ///         }
460747ad3c4Slazypassion     ///     }
461747ad3c4Slazypassion     /// }
462747ad3c4Slazypassion     /// ```
next_inst(&mut self) -> Option<ir::Inst>463747ad3c4Slazypassion     fn next_inst(&mut self) -> Option<ir::Inst> {
464*3d4bd054SNick Fitzgerald         let pos = self.next_inst_position()?;
465*3d4bd054SNick Fitzgerald         self.set_position(pos);
466*3d4bd054SNick Fitzgerald         self.current_inst()
467*3d4bd054SNick Fitzgerald     }
468*3d4bd054SNick Fitzgerald 
469*3d4bd054SNick Fitzgerald     /// Get the position that a `cursor.prev_inst()` call would move this cursor
470*3d4bd054SNick Fitzgerald     /// to, but do not update this cursor's position.
prev_inst_position(&self) -> Option<CursorPosition>471*3d4bd054SNick Fitzgerald     fn prev_inst_position(&self) -> Option<CursorPosition> {
472747ad3c4Slazypassion         use self::CursorPosition::*;
473747ad3c4Slazypassion         match self.position() {
474*3d4bd054SNick Fitzgerald             Nowhere | Before(..) => None,
475747ad3c4Slazypassion             At(inst) => {
476*3d4bd054SNick Fitzgerald                 if let Some(prev) = self.layout().prev_inst(inst) {
477*3d4bd054SNick Fitzgerald                     Some(At(prev))
478747ad3c4Slazypassion                 } else {
479*3d4bd054SNick Fitzgerald                     Some(Before(
480747ad3c4Slazypassion                         self.layout()
481832666c4SRyan Hunt                             .inst_block(inst)
482747ad3c4Slazypassion                             .expect("current instruction removed?"),
483*3d4bd054SNick Fitzgerald                     ))
484747ad3c4Slazypassion                 }
485747ad3c4Slazypassion             }
486*3d4bd054SNick Fitzgerald             After(block) => {
487*3d4bd054SNick Fitzgerald                 if let Some(prev) = self.layout().last_inst(block) {
488*3d4bd054SNick Fitzgerald                     Some(At(prev))
489747ad3c4Slazypassion                 } else {
490*3d4bd054SNick Fitzgerald                     Some(Before(block))
491747ad3c4Slazypassion                 }
492747ad3c4Slazypassion             }
493747ad3c4Slazypassion         }
494747ad3c4Slazypassion     }
495747ad3c4Slazypassion 
496832666c4SRyan Hunt     /// Move to the previous instruction in the same block and return it.
497747ad3c4Slazypassion     ///
49807f335dcSRyan Hunt     /// - If the cursor was positioned after a block, go to the last instruction in that block.
499832666c4SRyan Hunt     /// - If there are no more instructions in the block, go to the `Before(block)` position and return
500747ad3c4Slazypassion     ///   `None`.
501747ad3c4Slazypassion     /// - If the cursor wasn't pointing anywhere, keep doing that.
502747ad3c4Slazypassion     ///
503832666c4SRyan Hunt     /// This method will never move the cursor to a different block.
504747ad3c4Slazypassion     ///
505747ad3c4Slazypassion     /// # Examples
506747ad3c4Slazypassion     ///
507747ad3c4Slazypassion     /// The `prev_inst()` method is intended for iterating backwards over the instructions in an
508832666c4SRyan Hunt     /// block like this:
509747ad3c4Slazypassion     ///
510747ad3c4Slazypassion     /// ```
511832666c4SRyan Hunt     /// # use cranelift_codegen::ir::{Function, Block};
512747ad3c4Slazypassion     /// # use cranelift_codegen::cursor::{Cursor, FuncCursor};
513832666c4SRyan Hunt     /// fn edit_block(func: &mut Function, block: Block) {
514832666c4SRyan Hunt     ///     let mut cursor = FuncCursor::new(func).at_bottom(block);
515747ad3c4Slazypassion     ///     while let Some(inst) = cursor.prev_inst() {
516747ad3c4Slazypassion     ///         // Edit instructions...
517747ad3c4Slazypassion     ///     }
518747ad3c4Slazypassion     /// }
519747ad3c4Slazypassion     /// ```
prev_inst(&mut self) -> Option<ir::Inst>520747ad3c4Slazypassion     fn prev_inst(&mut self) -> Option<ir::Inst> {
521*3d4bd054SNick Fitzgerald         let pos = self.prev_inst_position()?;
522747ad3c4Slazypassion         self.set_position(pos);
523*3d4bd054SNick Fitzgerald         self.current_inst()
524747ad3c4Slazypassion     }
525747ad3c4Slazypassion 
526747ad3c4Slazypassion     /// Insert an instruction at the current position.
527747ad3c4Slazypassion     ///
528747ad3c4Slazypassion     /// - If pointing at an instruction, the new instruction is inserted before the current
529747ad3c4Slazypassion     ///   instruction.
53007f335dcSRyan Hunt     /// - If pointing at the bottom of a block, the new instruction is appended to the block.
531747ad3c4Slazypassion     /// - Otherwise panic.
532747ad3c4Slazypassion     ///
533747ad3c4Slazypassion     /// In either case, the cursor is not moved, such that repeated calls to `insert_inst()` causes
534832666c4SRyan Hunt     /// instructions to appear in insertion order in the block.
insert_inst(&mut self, inst: ir::Inst)535747ad3c4Slazypassion     fn insert_inst(&mut self, inst: ir::Inst) {
536747ad3c4Slazypassion         use self::CursorPosition::*;
537747ad3c4Slazypassion         match self.position() {
538747ad3c4Slazypassion             Nowhere | Before(..) => panic!("Invalid insert_inst position"),
539747ad3c4Slazypassion             At(cur) => self.layout_mut().insert_inst(inst, cur),
540832666c4SRyan Hunt             After(block) => self.layout_mut().append_inst(inst, block),
541747ad3c4Slazypassion         }
542747ad3c4Slazypassion     }
543747ad3c4Slazypassion 
544747ad3c4Slazypassion     /// Remove the instruction under the cursor.
545747ad3c4Slazypassion     ///
546747ad3c4Slazypassion     /// The cursor is left pointing at the position following the current instruction.
547747ad3c4Slazypassion     ///
548747ad3c4Slazypassion     /// Return the instruction that was removed.
remove_inst(&mut self) -> ir::Inst549747ad3c4Slazypassion     fn remove_inst(&mut self) -> ir::Inst {
550747ad3c4Slazypassion         let inst = self.current_inst().expect("No instruction to remove");
551747ad3c4Slazypassion         self.next_inst();
552747ad3c4Slazypassion         self.layout_mut().remove_inst(inst);
553747ad3c4Slazypassion         inst
554747ad3c4Slazypassion     }
555747ad3c4Slazypassion 
556747ad3c4Slazypassion     /// Remove the instruction under the cursor.
557747ad3c4Slazypassion     ///
558747ad3c4Slazypassion     /// The cursor is left pointing at the position preceding the current instruction.
559747ad3c4Slazypassion     ///
560747ad3c4Slazypassion     /// Return the instruction that was removed.
remove_inst_and_step_back(&mut self) -> ir::Inst561747ad3c4Slazypassion     fn remove_inst_and_step_back(&mut self) -> ir::Inst {
562747ad3c4Slazypassion         let inst = self.current_inst().expect("No instruction to remove");
563747ad3c4Slazypassion         self.prev_inst();
564747ad3c4Slazypassion         self.layout_mut().remove_inst(inst);
565747ad3c4Slazypassion         inst
566747ad3c4Slazypassion     }
567747ad3c4Slazypassion 
5687bf31723SNick Fitzgerald     /// Replace the instruction under the cursor with `new_inst`.
5697bf31723SNick Fitzgerald     ///
5707bf31723SNick Fitzgerald     /// The cursor is left pointing at the new instruction.
5717bf31723SNick Fitzgerald     ///
5727bf31723SNick Fitzgerald     /// The old instruction that was replaced is returned.
replace_inst(&mut self, new_inst: ir::Inst) -> ir::Inst5737bf31723SNick Fitzgerald     fn replace_inst(&mut self, new_inst: ir::Inst) -> ir::Inst {
5747bf31723SNick Fitzgerald         let prev_inst = self.remove_inst();
5757bf31723SNick Fitzgerald         self.insert_inst(new_inst);
5767bf31723SNick Fitzgerald         prev_inst
5777bf31723SNick Fitzgerald     }
5787bf31723SNick Fitzgerald 
57907f335dcSRyan Hunt     /// Insert a block at the current position and switch to it.
580747ad3c4Slazypassion     ///
581832666c4SRyan Hunt     /// As far as possible, this method behaves as if the block header were an instruction inserted
582747ad3c4Slazypassion     /// at the current position.
583747ad3c4Slazypassion     ///
584832666c4SRyan Hunt     /// - If the cursor is pointing at an existing instruction, *the current block is split in two*
585832666c4SRyan Hunt     ///   and the current instruction becomes the first instruction in the inserted block.
58607f335dcSRyan Hunt     /// - If the cursor points at the bottom of a block, the new block is inserted after the current
587832666c4SRyan Hunt     ///   one, and moved to the bottom of the new block where instructions can be appended.
58807f335dcSRyan Hunt     /// - If the cursor points to the top of a block, the new block is inserted above the current one.
589832666c4SRyan Hunt     /// - If the cursor is not pointing at anything, the new block is placed last in the layout.
590747ad3c4Slazypassion     ///
591747ad3c4Slazypassion     /// This means that it is always valid to call this method, and it always leaves the cursor in
592832666c4SRyan Hunt     /// a state that will insert instructions into the new block.
insert_block(&mut self, new_block: ir::Block)593832666c4SRyan Hunt     fn insert_block(&mut self, new_block: ir::Block) {
594747ad3c4Slazypassion         use self::CursorPosition::*;
595747ad3c4Slazypassion         match self.position() {
596747ad3c4Slazypassion             At(inst) => {
597832666c4SRyan Hunt                 self.layout_mut().split_block(new_block, inst);
598832666c4SRyan Hunt                 // All other cases move to `After(block)`, but in this case we'll stay `At(inst)`.
599747ad3c4Slazypassion                 return;
600747ad3c4Slazypassion             }
601832666c4SRyan Hunt             Nowhere => self.layout_mut().append_block(new_block),
602832666c4SRyan Hunt             Before(block) => self.layout_mut().insert_block(new_block, block),
603832666c4SRyan Hunt             After(block) => self.layout_mut().insert_block_after(new_block, block),
604747ad3c4Slazypassion         }
605832666c4SRyan Hunt         // For everything but `At(inst)` we end up appending to the new block.
606832666c4SRyan Hunt         self.set_position(After(new_block));
607747ad3c4Slazypassion     }
608747ad3c4Slazypassion }
609747ad3c4Slazypassion 
610747ad3c4Slazypassion /// Function cursor.
611747ad3c4Slazypassion ///
612747ad3c4Slazypassion /// A `FuncCursor` holds a mutable reference to a whole `ir::Function` while keeping a position
613747ad3c4Slazypassion /// too. The function can be re-borrowed by accessing the public `cur.func` member.
614747ad3c4Slazypassion ///
615747ad3c4Slazypassion /// This cursor is for use before legalization. The inserted instructions are not given an
616747ad3c4Slazypassion /// encoding.
617747ad3c4Slazypassion pub struct FuncCursor<'f> {
618747ad3c4Slazypassion     pos: CursorPosition,
619747ad3c4Slazypassion     srcloc: ir::SourceLoc,
620747ad3c4Slazypassion 
621747ad3c4Slazypassion     /// The referenced function.
622747ad3c4Slazypassion     pub func: &'f mut ir::Function,
623747ad3c4Slazypassion }
624747ad3c4Slazypassion 
625747ad3c4Slazypassion impl<'f> FuncCursor<'f> {
626747ad3c4Slazypassion     /// Create a new `FuncCursor` pointing nowhere.
new(func: &'f mut ir::Function) -> Self627747ad3c4Slazypassion     pub fn new(func: &'f mut ir::Function) -> Self {
628747ad3c4Slazypassion         Self {
629747ad3c4Slazypassion             pos: CursorPosition::Nowhere,
630747ad3c4Slazypassion             srcloc: Default::default(),
631747ad3c4Slazypassion             func,
632747ad3c4Slazypassion         }
633747ad3c4Slazypassion     }
634747ad3c4Slazypassion 
635747ad3c4Slazypassion     /// Use the source location of `inst` for future instructions.
use_srcloc(&mut self, inst: ir::Inst)636747ad3c4Slazypassion     pub fn use_srcloc(&mut self, inst: ir::Inst) {
6378a9b1a90SBenjamin Bouvier         self.srcloc = self.func.srcloc(inst);
638747ad3c4Slazypassion     }
639747ad3c4Slazypassion 
640747ad3c4Slazypassion     /// Create an instruction builder that inserts an instruction at the current position.
ins(&mut self) -> ir::InsertBuilder<'_, &mut FuncCursor<'f>>641868f0c38SNick Fitzgerald     pub fn ins(&mut self) -> ir::InsertBuilder<'_, &mut FuncCursor<'f>> {
642747ad3c4Slazypassion         ir::InsertBuilder::new(self)
643747ad3c4Slazypassion     }
644747ad3c4Slazypassion }
645747ad3c4Slazypassion 
646747ad3c4Slazypassion impl<'f> Cursor for FuncCursor<'f> {
position(&self) -> CursorPosition647747ad3c4Slazypassion     fn position(&self) -> CursorPosition {
648747ad3c4Slazypassion         self.pos
649747ad3c4Slazypassion     }
650747ad3c4Slazypassion 
set_position(&mut self, pos: CursorPosition)651747ad3c4Slazypassion     fn set_position(&mut self, pos: CursorPosition) {
652747ad3c4Slazypassion         self.pos = pos
653747ad3c4Slazypassion     }
654747ad3c4Slazypassion 
srcloc(&self) -> ir::SourceLoc655747ad3c4Slazypassion     fn srcloc(&self) -> ir::SourceLoc {
656747ad3c4Slazypassion         self.srcloc
657747ad3c4Slazypassion     }
658747ad3c4Slazypassion 
set_srcloc(&mut self, srcloc: ir::SourceLoc)659747ad3c4Slazypassion     fn set_srcloc(&mut self, srcloc: ir::SourceLoc) {
6608a9b1a90SBenjamin Bouvier         self.func.params.ensure_base_srcloc(srcloc);
661747ad3c4Slazypassion         self.srcloc = srcloc;
662747ad3c4Slazypassion     }
663747ad3c4Slazypassion 
layout(&self) -> &ir::Layout664747ad3c4Slazypassion     fn layout(&self) -> &ir::Layout {
665747ad3c4Slazypassion         &self.func.layout
666747ad3c4Slazypassion     }
667747ad3c4Slazypassion 
layout_mut(&mut self) -> &mut ir::Layout668747ad3c4Slazypassion     fn layout_mut(&mut self) -> &mut ir::Layout {
669747ad3c4Slazypassion         &mut self.func.layout
670747ad3c4Slazypassion     }
671747ad3c4Slazypassion }
672747ad3c4Slazypassion 
673747ad3c4Slazypassion impl<'c, 'f> ir::InstInserterBase<'c> for &'c mut FuncCursor<'f> {
data_flow_graph(&self) -> &ir::DataFlowGraph674747ad3c4Slazypassion     fn data_flow_graph(&self) -> &ir::DataFlowGraph {
675747ad3c4Slazypassion         &self.func.dfg
676747ad3c4Slazypassion     }
677747ad3c4Slazypassion 
data_flow_graph_mut(&mut self) -> &mut ir::DataFlowGraph678747ad3c4Slazypassion     fn data_flow_graph_mut(&mut self) -> &mut ir::DataFlowGraph {
679747ad3c4Slazypassion         &mut self.func.dfg
680747ad3c4Slazypassion     }
681747ad3c4Slazypassion 
insert_built_inst(self, inst: ir::Inst) -> &'c mut ir::DataFlowGraph682bae4ec64SBenjamin Bouvier     fn insert_built_inst(self, inst: ir::Inst) -> &'c mut ir::DataFlowGraph {
683747ad3c4Slazypassion         self.insert_inst(inst);
684747ad3c4Slazypassion         if !self.srcloc.is_default() {
6858a9b1a90SBenjamin Bouvier             self.func.set_srcloc(inst, self.srcloc);
686747ad3c4Slazypassion         }
687747ad3c4Slazypassion         &mut self.func.dfg
688747ad3c4Slazypassion     }
689747ad3c4Slazypassion }
690