Add Layout::split_ebb().
This method splits an EBB in two and moves trailing instructions to a new EBB.
This commit is contained in:
@@ -221,6 +221,71 @@ impl Layout {
|
||||
next: self.ebbs[ebb].first_inst.wrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Split the EBB containing `before` in two.
|
||||
///
|
||||
/// Insert `new_ebb` after the old EBB and move `before` and the following instructions to
|
||||
/// `new_ebb`:
|
||||
///
|
||||
/// ```text
|
||||
/// old_ebb:
|
||||
/// i1
|
||||
/// i2
|
||||
/// i3 << before
|
||||
/// i4
|
||||
/// ```
|
||||
/// becomes:
|
||||
///
|
||||
/// ```text
|
||||
/// old_ebb:
|
||||
/// i1
|
||||
/// i2
|
||||
/// new_ebb:
|
||||
/// i3 << before
|
||||
/// i4
|
||||
/// ```
|
||||
pub fn split_ebb(&mut self, new_ebb: Ebb, before: Inst) {
|
||||
let old_ebb = self.inst_ebb(before)
|
||||
.expect("The `before` instruction must be in the layout");
|
||||
assert!(!self.is_ebb_inserted(new_ebb));
|
||||
|
||||
// Insert new_ebb after old_ebb.
|
||||
let next_ebb = self.ebbs[old_ebb].next;
|
||||
let last_inst = self.ebbs[old_ebb].last_inst;
|
||||
{
|
||||
let node = self.ebbs.ensure(new_ebb);
|
||||
node.prev = old_ebb;
|
||||
node.next = next_ebb;
|
||||
node.first_inst = before;
|
||||
node.last_inst = last_inst;
|
||||
}
|
||||
self.ebbs[old_ebb].next = new_ebb;
|
||||
|
||||
// Fix backwards link.
|
||||
if Some(old_ebb) == self.last_ebb {
|
||||
self.last_ebb = Some(new_ebb);
|
||||
} else {
|
||||
self.ebbs[next_ebb].prev = new_ebb;
|
||||
}
|
||||
|
||||
// Disconnect the instruction links.
|
||||
let prev_inst = self.insts[before].prev;
|
||||
self.insts[before].prev = NO_INST;
|
||||
self.ebbs[old_ebb].last_inst = prev_inst;
|
||||
if prev_inst == NO_INST {
|
||||
self.ebbs[old_ebb].first_inst = NO_INST;
|
||||
} else {
|
||||
self.insts[prev_inst].next = NO_INST;
|
||||
}
|
||||
|
||||
// Fix the instruction -> ebb pointers.
|
||||
let mut i = before;
|
||||
while i != NO_INST {
|
||||
debug_assert_eq!(self.insts[i].ebb, old_ebb);
|
||||
self.insts[i].ebb = new_ebb;
|
||||
i = self.insts[i].next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
@@ -782,4 +847,79 @@ mod tests {
|
||||
assert_eq!(v0, [i0, i1]);
|
||||
assert_eq!(v1, [i2, i3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn split_ebb() {
|
||||
let mut layout = Layout::new();
|
||||
|
||||
let e0 = Ebb::new(0);
|
||||
let e1 = Ebb::new(1);
|
||||
let e2 = Ebb::new(2);
|
||||
|
||||
let i0 = Inst::new(0);
|
||||
let i1 = Inst::new(1);
|
||||
let i2 = Inst::new(2);
|
||||
let i3 = Inst::new(3);
|
||||
|
||||
layout.append_ebb(e0);
|
||||
layout.append_inst(i0, e0);
|
||||
assert_eq!(layout.inst_ebb(i0), Some(e0));
|
||||
layout.split_ebb(e1, i0);
|
||||
assert_eq!(layout.inst_ebb(i0), Some(e1));
|
||||
|
||||
{
|
||||
let mut cur = Cursor::new(&mut layout);
|
||||
assert_eq!(cur.next_ebb(), Some(e0));
|
||||
assert_eq!(cur.next_inst(), None);
|
||||
assert_eq!(cur.next_ebb(), Some(e1));
|
||||
assert_eq!(cur.next_inst(), Some(i0));
|
||||
assert_eq!(cur.next_inst(), None);
|
||||
assert_eq!(cur.next_ebb(), None);
|
||||
|
||||
// Check backwards links.
|
||||
assert_eq!(cur.prev_ebb(), Some(e1));
|
||||
assert_eq!(cur.prev_inst(), Some(i0));
|
||||
assert_eq!(cur.prev_inst(), None);
|
||||
assert_eq!(cur.prev_ebb(), Some(e0));
|
||||
assert_eq!(cur.prev_inst(), None);
|
||||
assert_eq!(cur.prev_ebb(), None);
|
||||
}
|
||||
|
||||
layout.append_inst(i1, e0);
|
||||
layout.append_inst(i2, e0);
|
||||
layout.append_inst(i3, e0);
|
||||
layout.split_ebb(e2, i2);
|
||||
|
||||
assert_eq!(layout.inst_ebb(i0), Some(e1));
|
||||
assert_eq!(layout.inst_ebb(i1), Some(e0));
|
||||
assert_eq!(layout.inst_ebb(i2), Some(e2));
|
||||
assert_eq!(layout.inst_ebb(i3), Some(e2));
|
||||
|
||||
{
|
||||
let mut cur = Cursor::new(&mut layout);
|
||||
assert_eq!(cur.next_ebb(), Some(e0));
|
||||
assert_eq!(cur.next_inst(), Some(i1));
|
||||
assert_eq!(cur.next_inst(), None);
|
||||
assert_eq!(cur.next_ebb(), Some(e2));
|
||||
assert_eq!(cur.next_inst(), Some(i2));
|
||||
assert_eq!(cur.next_inst(), Some(i3));
|
||||
assert_eq!(cur.next_inst(), None);
|
||||
assert_eq!(cur.next_ebb(), Some(e1));
|
||||
assert_eq!(cur.next_inst(), Some(i0));
|
||||
assert_eq!(cur.next_inst(), None);
|
||||
assert_eq!(cur.next_ebb(), None);
|
||||
|
||||
assert_eq!(cur.prev_ebb(), Some(e1));
|
||||
assert_eq!(cur.prev_inst(), Some(i0));
|
||||
assert_eq!(cur.prev_inst(), None);
|
||||
assert_eq!(cur.prev_ebb(), Some(e2));
|
||||
assert_eq!(cur.prev_inst(), Some(i3));
|
||||
assert_eq!(cur.prev_inst(), Some(i2));
|
||||
assert_eq!(cur.prev_inst(), None);
|
||||
assert_eq!(cur.prev_ebb(), Some(e0));
|
||||
assert_eq!(cur.prev_inst(), Some(i1));
|
||||
assert_eq!(cur.prev_inst(), None);
|
||||
assert_eq!(cur.prev_ebb(), None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user