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(),
|
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)]
|
#[derive(Clone, Debug, Default)]
|
||||||
@@ -782,4 +847,79 @@ mod tests {
|
|||||||
assert_eq!(v0, [i0, i1]);
|
assert_eq!(v0, [i0, i1]);
|
||||||
assert_eq!(v1, [i2, i3]);
|
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