Add a FuncCursor type to the cursor library.

A FuncCursor works a like a layout cursor, but it holds a reference to
the entire function and lets you re-borrow the function reference.

Rewrite the dominator tree unit tests with a FuncCursor instead of a
layout cursor to demonstrate the difference. It avoids the constrained
lifetimes of the layout cursor in the tests.
This commit is contained in:
Jakob Stoklund Olesen
2017-08-04 15:31:08 -07:00
parent e904bff420
commit 92c3d8f87b
2 changed files with 161 additions and 128 deletions

View File

@@ -10,6 +10,67 @@ pub use ir::layout::CursorBase as Cursor;
pub use ir::layout::CursorPosition; pub use ir::layout::CursorPosition;
pub use ir::layout::Cursor as LayoutCursor; pub use ir::layout::Cursor as LayoutCursor;
/// Function cursor.
///
/// A `FuncCursor` holds a mutable reference to a whole `ir::Function` while keeping a position
/// too. The function can be re-borrowed by accessing the public `cur.func` member.
///
/// This cursor is for use before legalization. The inserted instructions are not given an
/// encoding.
pub struct FuncCursor<'f> {
pos: CursorPosition,
pub func: &'f mut ir::Function,
}
impl<'f> FuncCursor<'f> {
/// Create a new `FuncCursor` pointing nowhere.
pub fn new(func: &'f mut ir::Function) -> FuncCursor<'f> {
FuncCursor {
pos: CursorPosition::Nowhere,
func,
}
}
/// Create an instruction builder that inserts an instruction at the current position.
pub fn ins(&mut self) -> ir::InsertBuilder<&mut FuncCursor<'f>> {
ir::InsertBuilder::new(self)
}
}
impl<'f> Cursor for FuncCursor<'f> {
fn position(&self) -> CursorPosition {
self.pos
}
fn set_position(&mut self, pos: CursorPosition) {
self.pos = pos
}
fn layout(&self) -> &ir::Layout {
&self.func.layout
}
fn layout_mut(&mut self) -> &mut ir::Layout {
&mut self.func.layout
}
}
impl<'c, 'f> ir::InstInserterBase<'c> for &'c mut FuncCursor<'f> {
fn data_flow_graph(&self) -> &ir::DataFlowGraph {
&self.func.dfg
}
fn data_flow_graph_mut(&mut self) -> &mut ir::DataFlowGraph {
&mut self.func.dfg
}
fn insert_built_inst(self, inst: ir::Inst, _: ir::Type) -> &'c mut ir::DataFlowGraph {
self.insert_inst(inst);
&mut self.func.dfg
}
}
/// Encoding cursor. /// Encoding cursor.
/// ///
/// An `EncCursor` can be used to insert instructions that are immediately assigned an encoding. /// An `EncCursor` can be used to insert instructions that are immediately assigned an encoding.

View File

@@ -387,8 +387,9 @@ impl DominatorTree {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use cursor::{Cursor, FuncCursor};
use flowgraph::ControlFlowGraph; use flowgraph::ControlFlowGraph;
use ir::{Function, InstBuilder, Cursor, CursorBase, types}; use ir::{Function, InstBuilder, types};
use super::*; use super::*;
use ir::types::*; use ir::types::*;
use verifier::verify_context; use verifier::verify_context;
@@ -411,45 +412,38 @@ mod test {
let ebb2 = func.dfg.make_ebb(); let ebb2 = func.dfg.make_ebb();
let ebb0 = func.dfg.make_ebb(); let ebb0 = func.dfg.make_ebb();
let jmp_ebb3_ebb1; let mut cur = FuncCursor::new(&mut func);
let br_ebb1_ebb0;
let jmp_ebb1_ebb2;
{
let dfg = &mut func.dfg;
let cur = &mut Cursor::new(&mut func.layout);
cur.insert_ebb(ebb3); cur.insert_ebb(ebb3);
jmp_ebb3_ebb1 = dfg.ins(cur).jump(ebb1, &[]); let jmp_ebb3_ebb1 = cur.ins().jump(ebb1, &[]);
cur.insert_ebb(ebb1); cur.insert_ebb(ebb1);
br_ebb1_ebb0 = dfg.ins(cur).brnz(cond, ebb0, &[]); let br_ebb1_ebb0 = cur.ins().brnz(cond, ebb0, &[]);
jmp_ebb1_ebb2 = dfg.ins(cur).jump(ebb2, &[]); let jmp_ebb1_ebb2 = cur.ins().jump(ebb2, &[]);
cur.insert_ebb(ebb2); cur.insert_ebb(ebb2);
dfg.ins(cur).jump(ebb0, &[]); cur.ins().jump(ebb0, &[]);
cur.insert_ebb(ebb0); cur.insert_ebb(ebb0);
}
let cfg = ControlFlowGraph::with_function(&func); let cfg = ControlFlowGraph::with_function(cur.func);
let dt = DominatorTree::with_function(&func, &cfg); let dt = DominatorTree::with_function(cur.func, &cfg);
assert_eq!(func.layout.entry_block().unwrap(), ebb3); assert_eq!(cur.func.layout.entry_block().unwrap(), ebb3);
assert_eq!(dt.idom(ebb3), None); assert_eq!(dt.idom(ebb3), None);
assert_eq!(dt.idom(ebb1).unwrap(), jmp_ebb3_ebb1); assert_eq!(dt.idom(ebb1).unwrap(), jmp_ebb3_ebb1);
assert_eq!(dt.idom(ebb2).unwrap(), jmp_ebb1_ebb2); assert_eq!(dt.idom(ebb2).unwrap(), jmp_ebb1_ebb2);
assert_eq!(dt.idom(ebb0).unwrap(), br_ebb1_ebb0); assert_eq!(dt.idom(ebb0).unwrap(), br_ebb1_ebb0);
assert!(dt.dominates(br_ebb1_ebb0, br_ebb1_ebb0, &func.layout)); assert!(dt.dominates(br_ebb1_ebb0, br_ebb1_ebb0, &cur.func.layout));
assert!(!dt.dominates(br_ebb1_ebb0, jmp_ebb3_ebb1, &func.layout)); assert!(!dt.dominates(br_ebb1_ebb0, jmp_ebb3_ebb1, &cur.func.layout));
assert!(dt.dominates(jmp_ebb3_ebb1, br_ebb1_ebb0, &func.layout)); assert!(dt.dominates(jmp_ebb3_ebb1, br_ebb1_ebb0, &cur.func.layout));
assert_eq!(dt.rpo_cmp(ebb3, ebb3, &func.layout), Ordering::Equal); assert_eq!(dt.rpo_cmp(ebb3, ebb3, &cur.func.layout), Ordering::Equal);
assert_eq!(dt.rpo_cmp(ebb3, ebb1, &func.layout), Ordering::Less); assert_eq!(dt.rpo_cmp(ebb3, ebb1, &cur.func.layout), Ordering::Less);
assert_eq!(dt.rpo_cmp(ebb3, jmp_ebb3_ebb1, &func.layout), assert_eq!(dt.rpo_cmp(ebb3, jmp_ebb3_ebb1, &cur.func.layout),
Ordering::Less); Ordering::Less);
assert_eq!(dt.rpo_cmp(jmp_ebb3_ebb1, jmp_ebb1_ebb2, &func.layout), assert_eq!(dt.rpo_cmp(jmp_ebb3_ebb1, jmp_ebb1_ebb2, &cur.func.layout),
Ordering::Less); Ordering::Less);
assert_eq!(dt.cfg_postorder(), &[ebb2, ebb0, ebb1, ebb3]); assert_eq!(dt.cfg_postorder(), &[ebb2, ebb0, ebb1, ebb3]);
@@ -462,72 +456,66 @@ mod test {
let ebb1 = func.dfg.make_ebb(); let ebb1 = func.dfg.make_ebb();
let ebb2 = func.dfg.make_ebb(); let ebb2 = func.dfg.make_ebb();
let jmp02; let mut cur = FuncCursor::new(&mut func);
let jmp21;
let trap;
{
let dfg = &mut func.dfg;
let cur = &mut Cursor::new(&mut func.layout);
cur.insert_ebb(ebb0); cur.insert_ebb(ebb0);
jmp02 = dfg.ins(cur).jump(ebb2, &[]); let jmp02 = cur.ins().jump(ebb2, &[]);
cur.insert_ebb(ebb1); cur.insert_ebb(ebb1);
trap = dfg.ins(cur).trap(); let trap = cur.ins().trap();
cur.insert_ebb(ebb2); cur.insert_ebb(ebb2);
jmp21 = dfg.ins(cur).jump(ebb1, &[]); let jmp21 = cur.ins().jump(ebb1, &[]);
}
let cfg = ControlFlowGraph::with_function(&func); let cfg = ControlFlowGraph::with_function(cur.func);
let dt = DominatorTree::with_function(&func, &cfg); let dt = DominatorTree::with_function(cur.func, &cfg);
assert_eq!(func.layout.entry_block(), Some(ebb0)); assert_eq!(cur.func.layout.entry_block(), Some(ebb0));
assert_eq!(dt.idom(ebb0), None); assert_eq!(dt.idom(ebb0), None);
assert_eq!(dt.idom(ebb1), Some(jmp21)); assert_eq!(dt.idom(ebb1), Some(jmp21));
assert_eq!(dt.idom(ebb2), Some(jmp02)); assert_eq!(dt.idom(ebb2), Some(jmp02));
assert!(dt.dominates(ebb0, ebb0, &func.layout)); assert!(dt.dominates(ebb0, ebb0, &cur.func.layout));
assert!(dt.dominates(ebb0, jmp02, &func.layout)); assert!(dt.dominates(ebb0, jmp02, &cur.func.layout));
assert!(dt.dominates(ebb0, ebb1, &func.layout)); assert!(dt.dominates(ebb0, ebb1, &cur.func.layout));
assert!(dt.dominates(ebb0, trap, &func.layout)); assert!(dt.dominates(ebb0, trap, &cur.func.layout));
assert!(dt.dominates(ebb0, ebb2, &func.layout)); assert!(dt.dominates(ebb0, ebb2, &cur.func.layout));
assert!(dt.dominates(ebb0, jmp21, &func.layout)); assert!(dt.dominates(ebb0, jmp21, &cur.func.layout));
assert!(!dt.dominates(jmp02, ebb0, &func.layout)); assert!(!dt.dominates(jmp02, ebb0, &cur.func.layout));
assert!(dt.dominates(jmp02, jmp02, &func.layout)); assert!(dt.dominates(jmp02, jmp02, &cur.func.layout));
assert!(dt.dominates(jmp02, ebb1, &func.layout)); assert!(dt.dominates(jmp02, ebb1, &cur.func.layout));
assert!(dt.dominates(jmp02, trap, &func.layout)); assert!(dt.dominates(jmp02, trap, &cur.func.layout));
assert!(dt.dominates(jmp02, ebb2, &func.layout)); assert!(dt.dominates(jmp02, ebb2, &cur.func.layout));
assert!(dt.dominates(jmp02, jmp21, &func.layout)); assert!(dt.dominates(jmp02, jmp21, &cur.func.layout));
assert!(!dt.dominates(ebb1, ebb0, &func.layout)); assert!(!dt.dominates(ebb1, ebb0, &cur.func.layout));
assert!(!dt.dominates(ebb1, jmp02, &func.layout)); assert!(!dt.dominates(ebb1, jmp02, &cur.func.layout));
assert!(dt.dominates(ebb1, ebb1, &func.layout)); assert!(dt.dominates(ebb1, ebb1, &cur.func.layout));
assert!(dt.dominates(ebb1, trap, &func.layout)); assert!(dt.dominates(ebb1, trap, &cur.func.layout));
assert!(!dt.dominates(ebb1, ebb2, &func.layout)); assert!(!dt.dominates(ebb1, ebb2, &cur.func.layout));
assert!(!dt.dominates(ebb1, jmp21, &func.layout)); assert!(!dt.dominates(ebb1, jmp21, &cur.func.layout));
assert!(!dt.dominates(trap, ebb0, &func.layout)); assert!(!dt.dominates(trap, ebb0, &cur.func.layout));
assert!(!dt.dominates(trap, jmp02, &func.layout)); assert!(!dt.dominates(trap, jmp02, &cur.func.layout));
assert!(!dt.dominates(trap, ebb1, &func.layout)); assert!(!dt.dominates(trap, ebb1, &cur.func.layout));
assert!(dt.dominates(trap, trap, &func.layout)); assert!(dt.dominates(trap, trap, &cur.func.layout));
assert!(!dt.dominates(trap, ebb2, &func.layout)); assert!(!dt.dominates(trap, ebb2, &cur.func.layout));
assert!(!dt.dominates(trap, jmp21, &func.layout)); assert!(!dt.dominates(trap, jmp21, &cur.func.layout));
assert!(!dt.dominates(ebb2, ebb0, &func.layout)); assert!(!dt.dominates(ebb2, ebb0, &cur.func.layout));
assert!(!dt.dominates(ebb2, jmp02, &func.layout)); assert!(!dt.dominates(ebb2, jmp02, &cur.func.layout));
assert!(dt.dominates(ebb2, ebb1, &func.layout)); assert!(dt.dominates(ebb2, ebb1, &cur.func.layout));
assert!(dt.dominates(ebb2, trap, &func.layout)); assert!(dt.dominates(ebb2, trap, &cur.func.layout));
assert!(dt.dominates(ebb2, ebb2, &func.layout)); assert!(dt.dominates(ebb2, ebb2, &cur.func.layout));
assert!(dt.dominates(ebb2, jmp21, &func.layout)); assert!(dt.dominates(ebb2, jmp21, &cur.func.layout));
assert!(!dt.dominates(jmp21, ebb0, &func.layout)); assert!(!dt.dominates(jmp21, ebb0, &cur.func.layout));
assert!(!dt.dominates(jmp21, jmp02, &func.layout)); assert!(!dt.dominates(jmp21, jmp02, &cur.func.layout));
assert!(dt.dominates(jmp21, ebb1, &func.layout)); assert!(dt.dominates(jmp21, ebb1, &cur.func.layout));
assert!(dt.dominates(jmp21, trap, &func.layout)); assert!(dt.dominates(jmp21, trap, &cur.func.layout));
assert!(!dt.dominates(jmp21, ebb2, &func.layout)); assert!(!dt.dominates(jmp21, ebb2, &cur.func.layout));
assert!(dt.dominates(jmp21, jmp21, &func.layout)); assert!(dt.dominates(jmp21, jmp21, &cur.func.layout));
} }
#[test] #[test]
@@ -536,63 +524,47 @@ mod test {
let ebb0 = func.dfg.make_ebb(); let ebb0 = func.dfg.make_ebb();
let ebb100 = func.dfg.make_ebb(); let ebb100 = func.dfg.make_ebb();
let inst2; let mut cur = FuncCursor::new(&mut func);
let inst3;
let inst4;
let inst5;
{
let dfg = &mut func.dfg;
let cur = &mut Cursor::new(&mut func.layout);
cur.insert_ebb(ebb0); cur.insert_ebb(ebb0);
let cond = dfg.ins(cur).iconst(I32, 0); let cond = cur.ins().iconst(I32, 0);
inst2 = dfg.ins(cur).brz(cond, ebb0, &[]); let inst2 = cur.ins().brz(cond, ebb0, &[]);
inst3 = dfg.ins(cur).brz(cond, ebb0, &[]); let inst3 = cur.ins().brz(cond, ebb0, &[]);
inst4 = dfg.ins(cur).brz(cond, ebb0, &[]); let inst4 = cur.ins().brz(cond, ebb0, &[]);
inst5 = dfg.ins(cur).brz(cond, ebb0, &[]); let inst5 = cur.ins().brz(cond, ebb0, &[]);
dfg.ins(cur).jump(ebb100, &[]); cur.ins().jump(ebb100, &[]);
cur.insert_ebb(ebb100); cur.insert_ebb(ebb100);
dfg.ins(cur).return_(&[]); cur.ins().return_(&[]);
}
let mut cfg = ControlFlowGraph::with_function(&func);
let mut dt = DominatorTree::with_function(&func, &cfg);
let ebb1 = func.dfg.make_ebb(); let mut cfg = ControlFlowGraph::with_function(cur.func);
func.layout.split_ebb(ebb1, inst2); let mut dt = DominatorTree::with_function(cur.func, &cfg);
let middle_jump_inst = {
let cur = &mut Cursor::new(&mut func.layout); let ebb1 = cur.func.dfg.make_ebb();
cur.func.layout.split_ebb(ebb1, inst2);
cur.goto_bottom(ebb0); cur.goto_bottom(ebb0);
func.dfg.ins(cur).jump(ebb1, &[]) let middle_jump_inst = cur.ins().jump(ebb1, &[]);
};
dt.recompute_split_ebb(ebb0, ebb1, middle_jump_inst); dt.recompute_split_ebb(ebb0, ebb1, middle_jump_inst);
let ebb2 = func.dfg.make_ebb(); let ebb2 = cur.func.dfg.make_ebb();
func.layout.split_ebb(ebb2, inst3); cur.func.layout.split_ebb(ebb2, inst3);
let middle_jump_inst = {
let cur = &mut Cursor::new(&mut func.layout);
cur.goto_bottom(ebb1); cur.goto_bottom(ebb1);
func.dfg.ins(cur).jump(ebb2, &[]) let middle_jump_inst = cur.ins().jump(ebb2, &[]);
};
dt.recompute_split_ebb(ebb1, ebb2, middle_jump_inst); dt.recompute_split_ebb(ebb1, ebb2, middle_jump_inst);
let ebb3 = func.dfg.make_ebb(); let ebb3 = cur.func.dfg.make_ebb();
func.layout.split_ebb(ebb3, inst4); cur.func.layout.split_ebb(ebb3, inst4);
let middle_jump_inst = {
let cur = &mut Cursor::new(&mut func.layout);
cur.goto_bottom(ebb2); cur.goto_bottom(ebb2);
func.dfg.ins(cur).jump(ebb3, &[]) let middle_jump_inst = cur.ins().jump(ebb3, &[]);
};
dt.recompute_split_ebb(ebb2, ebb3, middle_jump_inst); dt.recompute_split_ebb(ebb2, ebb3, middle_jump_inst);
let ebb4 = func.dfg.make_ebb(); let ebb4 = cur.func.dfg.make_ebb();
func.layout.split_ebb(ebb4, inst5); cur.func.layout.split_ebb(ebb4, inst5);
let middle_jump_inst = {
let cur = &mut Cursor::new(&mut func.layout);
cur.goto_bottom(ebb3); cur.goto_bottom(ebb3);
func.dfg.ins(cur).jump(ebb4, &[]) let middle_jump_inst = cur.ins().jump(ebb4, &[]);
};
dt.recompute_split_ebb(ebb3, ebb4, middle_jump_inst); dt.recompute_split_ebb(ebb3, ebb4, middle_jump_inst);
cfg.compute(&func);
verify_context(&func, &cfg, &dt, None).unwrap(); cfg.compute(cur.func);
verify_context(cur.func, &cfg, &dt, None).unwrap();
} }
} }