use crate::entity::SecondaryMap;
use crate::ir::dfg::DataFlowGraph;
use crate::ir::progpoint::{ExpandedProgramPoint, ProgramOrder};
use crate::ir::{Block, Inst};
use crate::packed_option::PackedOption;
use crate::{timing, trace};
use core::cmp;
use core::iter::{IntoIterator, Iterator};
#[derive(Debug, Clone, PartialEq, Hash)]
pub struct Layout {
blocks: SecondaryMap<Block, BlockNode>,
insts: SecondaryMap<Inst, InstNode>,
first_block: Option<Block>,
last_block: Option<Block>,
}
impl Layout {
pub fn new() -> Self {
Self {
blocks: SecondaryMap::new(),
insts: SecondaryMap::new(),
first_block: None,
last_block: None,
}
}
pub fn clear(&mut self) {
self.blocks.clear();
self.insts.clear();
self.first_block = None;
self.last_block = None;
}
pub fn block_capacity(&self) -> usize {
self.blocks.capacity()
}
}
type SequenceNumber = u32;
const MAJOR_STRIDE: SequenceNumber = 10;
const MINOR_STRIDE: SequenceNumber = 2;
const LOCAL_LIMIT: SequenceNumber = 100 * MINOR_STRIDE;
fn midpoint(a: SequenceNumber, b: SequenceNumber) -> Option<SequenceNumber> {
debug_assert!(a < b);
let m = a + (b - a) / 2;
if m > a {
Some(m)
} else {
None
}
}
#[test]
fn test_midpoint() {
assert_eq!(midpoint(0, 1), None);
assert_eq!(midpoint(0, 2), Some(1));
assert_eq!(midpoint(0, 3), Some(1));
assert_eq!(midpoint(0, 4), Some(2));
assert_eq!(midpoint(1, 4), Some(2));
assert_eq!(midpoint(2, 4), Some(3));
assert_eq!(midpoint(3, 4), None);
assert_eq!(midpoint(3, 4), None);
}
impl ProgramOrder for Layout {
fn cmp<A, B>(&self, a: A, b: B) -> cmp::Ordering
where
A: Into<ExpandedProgramPoint>,
B: Into<ExpandedProgramPoint>,
{
let a_seq = self.seq(a);
let b_seq = self.seq(b);
a_seq.cmp(&b_seq)
}
fn is_block_gap(&self, inst: Inst, block: Block) -> bool {
let i = &self.insts[inst];
let e = &self.blocks[block];
i.next.is_none() && i.block == e.prev
}
}
impl Layout {
fn seq<PP: Into<ExpandedProgramPoint>>(&self, pp: PP) -> SequenceNumber {
match pp.into() {
ExpandedProgramPoint::Block(block) => self.blocks[block].seq,
ExpandedProgramPoint::Inst(inst) => self.insts[inst].seq,
}
}
fn last_block_seq(&self, block: Block) -> SequenceNumber {
self.blocks[block]
.last_inst
.map(|inst| self.insts[inst].seq)
.unwrap_or(self.blocks[block].seq)
}
fn assign_block_seq(&mut self, block: Block) {
debug_assert!(self.is_block_inserted(block));
let prev_seq = self.blocks[block]
.prev
.map(|prev_block| self.last_block_seq(prev_block))
.unwrap_or(0);
let next_seq = if let Some(inst) = self.blocks[block].first_inst.expand() {
self.insts[inst].seq
} else if let Some(next_block) = self.blocks[block].next.expand() {
self.blocks[next_block].seq
} else {
self.blocks[block].seq = prev_seq + MAJOR_STRIDE;
return;
};
if let Some(seq) = midpoint(prev_seq, next_seq) {
self.blocks[block].seq = seq;
} else {
self.renumber_from_block(block, prev_seq + MINOR_STRIDE, prev_seq + LOCAL_LIMIT);
}
}
fn assign_inst_seq(&mut self, inst: Inst) {
let block = self
.inst_block(inst)
.expect("inst must be inserted before assigning an seq");
let prev_seq = match self.insts[inst].prev.expand() {
Some(prev_inst) => self.insts[prev_inst].seq,
None => self.blocks[block].seq,
};
let next_seq = if let Some(next_inst) = self.insts[inst].next.expand() {
self.insts[next_inst].seq
} else if let Some(next_block) = self.blocks[block].next.expand() {
self.blocks[next_block].seq
} else {
self.insts[inst].seq = prev_seq + MAJOR_STRIDE;
return;
};
if let Some(seq) = midpoint(prev_seq, next_seq) {
self.insts[inst].seq = seq;
} else {
self.renumber_from_inst(inst, prev_seq + MINOR_STRIDE, prev_seq + LOCAL_LIMIT);
}
}
fn renumber_insts(
&mut self,
inst: Inst,
seq: SequenceNumber,
limit: SequenceNumber,
) -> Option<SequenceNumber> {
let mut inst = inst;
let mut seq = seq;
loop {
self.insts[inst].seq = seq;
inst = match self.insts[inst].next.expand() {
None => return Some(seq),
Some(next) => next,
};
if seq < self.insts[inst].seq {
return None;
}
if seq > limit {
self.full_renumber();
return None;
}
seq += MINOR_STRIDE;
}
}
fn renumber_from_block(
&mut self,
block: Block,
first_seq: SequenceNumber,
limit: SequenceNumber,
) {
let mut block = block;
let mut seq = first_seq;
loop {
self.blocks[block].seq = seq;
if let Some(inst) = self.blocks[block].first_inst.expand() {
seq = match self.renumber_insts(inst, seq + MINOR_STRIDE, limit) {
Some(s) => s,
None => return,
}
}
block = match self.blocks[block].next.expand() {
Some(next) => next,
None => return,
};
if seq < self.blocks[block].seq {
return;
}
seq += MINOR_STRIDE;
}
}
fn renumber_from_inst(&mut self, inst: Inst, first_seq: SequenceNumber, limit: SequenceNumber) {
if let Some(seq) = self.renumber_insts(inst, first_seq, limit) {
if let Some(next_block) = self.blocks[self.inst_block(inst).unwrap()].next.expand() {
self.renumber_from_block(next_block, seq + MINOR_STRIDE, limit);
}
}
}
pub(crate) fn full_renumber(&mut self) {
let _tt = timing::layout_renumber();
let mut seq = 0;
let mut next_block = self.first_block;
while let Some(block) = next_block {
self.blocks[block].seq = seq;
seq += MAJOR_STRIDE;
next_block = self.blocks[block].next.expand();
let mut next_inst = self.blocks[block].first_inst.expand();
while let Some(inst) = next_inst {
self.insts[inst].seq = seq;
seq += MAJOR_STRIDE;
next_inst = self.insts[inst].next.expand();
}
}
trace!("Renumbered {} program points", seq / MAJOR_STRIDE);
}
}
impl Layout {
pub fn is_block_inserted(&self, block: Block) -> bool {
Some(block) == self.first_block || self.blocks[block].prev.is_some()
}
pub fn append_block(&mut self, block: Block) {
debug_assert!(
!self.is_block_inserted(block),
"Cannot append block that is already in the layout"
);
{
let node = &mut self.blocks[block];
debug_assert!(node.first_inst.is_none() && node.last_inst.is_none());
node.prev = self.last_block.into();
node.next = None.into();
}
if let Some(last) = self.last_block {
self.blocks[last].next = block.into();
} else {
self.first_block = Some(block);
}
self.last_block = Some(block);
self.assign_block_seq(block);
}
pub fn insert_block(&mut self, block: Block, before: Block) {
debug_assert!(
!self.is_block_inserted(block),
"Cannot insert block that is already in the layout"
);
debug_assert!(
self.is_block_inserted(before),
"block Insertion point not in the layout"
);
let after = self.blocks[before].prev;
{
let node = &mut self.blocks[block];
node.next = before.into();
node.prev = after;
}
self.blocks[before].prev = block.into();
match after.expand() {
None => self.first_block = Some(block),
Some(a) => self.blocks[a].next = block.into(),
}
self.assign_block_seq(block);
}
pub fn insert_block_after(&mut self, block: Block, after: Block) {
debug_assert!(
!self.is_block_inserted(block),
"Cannot insert block that is already in the layout"
);
debug_assert!(
self.is_block_inserted(after),
"block Insertion point not in the layout"
);
let before = self.blocks[after].next;
{
let node = &mut self.blocks[block];
node.next = before;
node.prev = after.into();
}
self.blocks[after].next = block.into();
match before.expand() {
None => self.last_block = Some(block),
Some(b) => self.blocks[b].prev = block.into(),
}
self.assign_block_seq(block);
}
pub fn remove_block(&mut self, block: Block) {
debug_assert!(self.is_block_inserted(block), "block not in the layout");
debug_assert!(self.first_inst(block).is_none(), "block must be empty.");
let prev;
let next;
{
let n = &mut self.blocks[block];
prev = n.prev;
next = n.next;
n.prev = None.into();
n.next = None.into();
}
match prev.expand() {
None => self.first_block = next.expand(),
Some(p) => self.blocks[p].next = next,
}
match next.expand() {
None => self.last_block = prev.expand(),
Some(n) => self.blocks[n].prev = prev,
}
}
pub fn blocks(&self) -> Blocks {
Blocks {
layout: self,
next: self.first_block,
}
}
pub fn entry_block(&self) -> Option<Block> {
self.first_block
}
pub fn last_block(&self) -> Option<Block> {
self.last_block
}
pub fn prev_block(&self, block: Block) -> Option<Block> {
self.blocks[block].prev.expand()
}
pub fn next_block(&self, block: Block) -> Option<Block> {
self.blocks[block].next.expand()
}
pub fn set_cold(&mut self, block: Block) {
self.blocks[block].cold = true;
}
pub fn is_cold(&self, block: Block) -> bool {
self.blocks[block].cold
}
}
#[derive(Clone, Debug, Default, PartialEq, Hash)]
struct BlockNode {
prev: PackedOption<Block>,
next: PackedOption<Block>,
first_inst: PackedOption<Inst>,
last_inst: PackedOption<Inst>,
seq: SequenceNumber,
cold: bool,
}
pub struct Blocks<'f> {
layout: &'f Layout,
next: Option<Block>,
}
impl<'f> Iterator for Blocks<'f> {
type Item = Block;
fn next(&mut self) -> Option<Block> {
match self.next {
Some(block) => {
self.next = self.layout.next_block(block);
Some(block)
}
None => None,
}
}
}
impl<'f> IntoIterator for &'f Layout {
type Item = Block;
type IntoIter = Blocks<'f>;
fn into_iter(self) -> Blocks<'f> {
self.blocks()
}
}
impl Layout {
pub fn inst_block(&self, inst: Inst) -> Option<Block> {
self.insts[inst].block.into()
}
pub fn pp_block<PP>(&self, pp: PP) -> Block
where
PP: Into<ExpandedProgramPoint>,
{
match pp.into() {
ExpandedProgramPoint::Block(block) => block,
ExpandedProgramPoint::Inst(inst) => {
self.inst_block(inst).expect("Program point not in layout")
}
}
}
pub fn append_inst(&mut self, inst: Inst, block: Block) {
debug_assert_eq!(self.inst_block(inst), None);
debug_assert!(
self.is_block_inserted(block),
"Cannot append instructions to block not in layout"
);
{
let block_node = &mut self.blocks[block];
{
let inst_node = &mut self.insts[inst];
inst_node.block = block.into();
inst_node.prev = block_node.last_inst;
debug_assert!(inst_node.next.is_none());
}
if block_node.first_inst.is_none() {
block_node.first_inst = inst.into();
} else {
self.insts[block_node.last_inst.unwrap()].next = inst.into();
}
block_node.last_inst = inst.into();
}
self.assign_inst_seq(inst);
}
pub fn first_inst(&self, block: Block) -> Option<Inst> {
self.blocks[block].first_inst.into()
}
pub fn last_inst(&self, block: Block) -> Option<Inst> {
self.blocks[block].last_inst.into()
}
pub fn next_inst(&self, inst: Inst) -> Option<Inst> {
self.insts[inst].next.expand()
}
pub fn prev_inst(&self, inst: Inst) -> Option<Inst> {
self.insts[inst].prev.expand()
}
pub fn canonical_branch_inst(&self, dfg: &DataFlowGraph, block: Block) -> Option<Inst> {
let last = self.last_inst(block)?;
if let Some(prev) = self.prev_inst(last) {
if dfg[prev].opcode().is_branch() {
return Some(prev);
}
}
Some(last)
}
pub fn insert_inst(&mut self, inst: Inst, before: Inst) {
debug_assert_eq!(self.inst_block(inst), None);
let block = self
.inst_block(before)
.expect("Instruction before insertion point not in the layout");
let after = self.insts[before].prev;
{
let inst_node = &mut self.insts[inst];
inst_node.block = block.into();
inst_node.next = before.into();
inst_node.prev = after;
}
self.insts[before].prev = inst.into();
match after.expand() {
None => self.blocks[block].first_inst = inst.into(),
Some(a) => self.insts[a].next = inst.into(),
}
self.assign_inst_seq(inst);
}
pub fn remove_inst(&mut self, inst: Inst) {
let block = self.inst_block(inst).expect("Instruction already removed.");
let prev;
let next;
{
let n = &mut self.insts[inst];
prev = n.prev;
next = n.next;
n.block = None.into();
n.prev = None.into();
n.next = None.into();
}
match prev.expand() {
None => self.blocks[block].first_inst = next,
Some(p) => self.insts[p].next = next,
}
match next.expand() {
None => self.blocks[block].last_inst = prev,
Some(n) => self.insts[n].prev = prev,
}
}
pub fn block_insts(&self, block: Block) -> Insts {
Insts {
layout: self,
head: self.blocks[block].first_inst.into(),
tail: self.blocks[block].last_inst.into(),
}
}
pub fn block_likely_branches(&self, block: Block) -> Insts {
let mut iter = self.block_insts(block);
let head = iter.head;
let tail = iter.tail;
iter.next_back();
let head = iter.next_back().or(head);
Insts {
layout: self,
head,
tail,
}
}
pub fn split_block(&mut self, new_block: Block, before: Inst) {
let old_block = self
.inst_block(before)
.expect("The `before` instruction must be in the layout");
debug_assert!(!self.is_block_inserted(new_block));
let next_block = self.blocks[old_block].next;
let last_inst = self.blocks[old_block].last_inst;
{
let node = &mut self.blocks[new_block];
node.prev = old_block.into();
node.next = next_block;
node.first_inst = before.into();
node.last_inst = last_inst;
}
self.blocks[old_block].next = new_block.into();
if Some(old_block) == self.last_block {
self.last_block = Some(new_block);
} else {
self.blocks[next_block.unwrap()].prev = new_block.into();
}
let prev_inst = self.insts[before].prev;
self.insts[before].prev = None.into();
self.blocks[old_block].last_inst = prev_inst;
match prev_inst.expand() {
None => self.blocks[old_block].first_inst = None.into(),
Some(pi) => self.insts[pi].next = None.into(),
}
let mut opt_i = Some(before);
while let Some(i) = opt_i {
debug_assert_eq!(self.insts[i].block.expand(), Some(old_block));
self.insts[i].block = new_block.into();
opt_i = self.insts[i].next.into();
}
self.assign_block_seq(new_block);
}
}
#[derive(Clone, Debug, Default, PartialEq, Hash)]
struct InstNode {
block: PackedOption<Block>,
prev: PackedOption<Inst>,
next: PackedOption<Inst>,
seq: SequenceNumber,
}
pub struct Insts<'f> {
layout: &'f Layout,
head: Option<Inst>,
tail: Option<Inst>,
}
impl<'f> Iterator for Insts<'f> {
type Item = Inst;
fn next(&mut self) -> Option<Inst> {
let rval = self.head;
if let Some(inst) = rval {
if self.head == self.tail {
self.head = None;
self.tail = None;
} else {
self.head = self.layout.insts[inst].next.into();
}
}
rval
}
}
impl<'f> DoubleEndedIterator for Insts<'f> {
fn next_back(&mut self) -> Option<Inst> {
let rval = self.tail;
if let Some(inst) = rval {
if self.head == self.tail {
self.head = None;
self.tail = None;
} else {
self.tail = self.layout.insts[inst].prev.into();
}
}
rval
}
}
#[cfg(feature = "enable-serde")]
mod serde {
use ::serde::de::{Deserializer, Error, SeqAccess, Visitor};
use ::serde::ser::{SerializeSeq, Serializer};
use ::serde::{Deserialize, Serialize};
use core::convert::TryFrom;
use core::fmt;
use core::marker::PhantomData;
use super::*;
impl Serialize for Layout {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let size = self.blocks().count() * 3
+ self
.blocks()
.map(|block| self.block_insts(block).count())
.sum::<usize>();
let mut seq = serializer.serialize_seq(Some(size))?;
for block in self.blocks() {
seq.serialize_element(&block)?;
seq.serialize_element(&self.blocks[block].cold)?;
seq.serialize_element(&u32::try_from(self.block_insts(block).count()).unwrap())?;
for inst in self.block_insts(block) {
seq.serialize_element(&inst)?;
}
}
seq.end()
}
}
impl<'de> Deserialize<'de> for Layout {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_seq(LayoutVisitor {
marker: PhantomData,
})
}
}
struct LayoutVisitor {
marker: PhantomData<fn() -> Layout>,
}
impl<'de> Visitor<'de> for LayoutVisitor {
type Value = Layout;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a `cranelift_codegen::ir::Layout`")
}
fn visit_seq<M>(self, mut access: M) -> Result<Self::Value, M::Error>
where
M: SeqAccess<'de>,
{
let mut layout = Layout::new();
while let Some(block) = access.next_element::<Block>()? {
layout.append_block(block);
let cold = access
.next_element::<bool>()?
.ok_or_else(|| Error::missing_field("cold"))?;
layout.blocks[block].cold = cold;
let count = access
.next_element::<u32>()?
.ok_or_else(|| Error::missing_field("count"))?;
for _ in 0..count {
let inst = access
.next_element::<Inst>()?
.ok_or_else(|| Error::missing_field("inst"))?;
layout.append_inst(inst, block);
}
}
Ok(layout)
}
}
}
#[cfg(test)]
mod tests {
use super::Layout;
use crate::cursor::{Cursor, CursorPosition};
use crate::entity::EntityRef;
use crate::ir::{Block, Inst, ProgramOrder, SourceLoc};
use alloc::vec::Vec;
use core::cmp::Ordering;
struct LayoutCursor<'f> {
pub layout: &'f mut Layout,
pos: CursorPosition,
}
impl<'f> Cursor for LayoutCursor<'f> {
fn position(&self) -> CursorPosition {
self.pos
}
fn set_position(&mut self, pos: CursorPosition) {
self.pos = pos;
}
fn srcloc(&self) -> SourceLoc {
unimplemented!()
}
fn set_srcloc(&mut self, _srcloc: SourceLoc) {
unimplemented!()
}
fn layout(&self) -> &Layout {
self.layout
}
fn layout_mut(&mut self) -> &mut Layout {
self.layout
}
}
impl<'f> LayoutCursor<'f> {
pub fn new(layout: &'f mut Layout) -> Self {
Self {
layout,
pos: CursorPosition::Nowhere,
}
}
}
fn verify(layout: &mut Layout, blocks: &[(Block, &[Inst])]) {
{
let mut seq = 0;
let mut block_iter = layout.blocks();
for &(block, insts) in blocks {
assert!(layout.is_block_inserted(block));
assert_eq!(block_iter.next(), Some(block));
assert!(layout.blocks[block].seq > seq);
seq = layout.blocks[block].seq;
let mut inst_iter = layout.block_insts(block);
for &inst in insts {
assert_eq!(layout.inst_block(inst), Some(block));
assert_eq!(inst_iter.next(), Some(inst));
assert!(layout.insts[inst].seq > seq);
seq = layout.insts[inst].seq;
}
assert_eq!(inst_iter.next(), None);
}
assert_eq!(block_iter.next(), None);
}
let mut cur = LayoutCursor::new(layout);
for &(block, insts) in blocks.into_iter().rev() {
assert_eq!(cur.prev_block(), Some(block));
for &inst in insts.into_iter().rev() {
assert_eq!(cur.prev_inst(), Some(inst));
}
assert_eq!(cur.prev_inst(), None);
}
assert_eq!(cur.prev_block(), None);
}
#[test]
fn append_block() {
let mut layout = Layout::new();
let e0 = Block::new(0);
let e1 = Block::new(1);
let e2 = Block::new(2);
{
let imm = &layout;
assert!(!imm.is_block_inserted(e0));
assert!(!imm.is_block_inserted(e1));
}
verify(&mut layout, &[]);
layout.append_block(e1);
assert!(!layout.is_block_inserted(e0));
assert!(layout.is_block_inserted(e1));
assert!(!layout.is_block_inserted(e2));
let v: Vec<Block> = layout.blocks().collect();
assert_eq!(v, [e1]);
layout.append_block(e2);
assert!(!layout.is_block_inserted(e0));
assert!(layout.is_block_inserted(e1));
assert!(layout.is_block_inserted(e2));
let v: Vec<Block> = layout.blocks().collect();
assert_eq!(v, [e1, e2]);
layout.append_block(e0);
assert!(layout.is_block_inserted(e0));
assert!(layout.is_block_inserted(e1));
assert!(layout.is_block_inserted(e2));
let v: Vec<Block> = layout.blocks().collect();
assert_eq!(v, [e1, e2, e0]);
{
let imm = &layout;
let mut v = Vec::new();
for e in imm {
v.push(e);
}
assert_eq!(v, [e1, e2, e0]);
}
let mut cur = LayoutCursor::new(&mut layout);
assert_eq!(cur.position(), CursorPosition::Nowhere);
assert_eq!(cur.next_inst(), None);
assert_eq!(cur.position(), CursorPosition::Nowhere);
assert_eq!(cur.prev_inst(), None);
assert_eq!(cur.position(), CursorPosition::Nowhere);
assert_eq!(cur.next_block(), Some(e1));
assert_eq!(cur.position(), CursorPosition::Before(e1));
assert_eq!(cur.next_inst(), None);
assert_eq!(cur.position(), CursorPosition::After(e1));
assert_eq!(cur.next_inst(), None);
assert_eq!(cur.position(), CursorPosition::After(e1));
assert_eq!(cur.next_block(), Some(e2));
assert_eq!(cur.prev_inst(), None);
assert_eq!(cur.position(), CursorPosition::Before(e2));
assert_eq!(cur.next_block(), Some(e0));
assert_eq!(cur.next_block(), None);
assert_eq!(cur.position(), CursorPosition::Nowhere);
assert_eq!(cur.prev_block(), Some(e0));
assert_eq!(cur.position(), CursorPosition::After(e0));
assert_eq!(cur.prev_block(), Some(e2));
assert_eq!(cur.prev_block(), Some(e1));
assert_eq!(cur.prev_block(), None);
assert_eq!(cur.position(), CursorPosition::Nowhere);
}
#[test]
fn insert_block() {
let mut layout = Layout::new();
let e0 = Block::new(0);
let e1 = Block::new(1);
let e2 = Block::new(2);
{
let imm = &layout;
assert!(!imm.is_block_inserted(e0));
assert!(!imm.is_block_inserted(e1));
let v: Vec<Block> = layout.blocks().collect();
assert_eq!(v, []);
}
layout.append_block(e1);
assert!(!layout.is_block_inserted(e0));
assert!(layout.is_block_inserted(e1));
assert!(!layout.is_block_inserted(e2));
verify(&mut layout, &[(e1, &[])]);
layout.insert_block(e2, e1);
assert!(!layout.is_block_inserted(e0));
assert!(layout.is_block_inserted(e1));
assert!(layout.is_block_inserted(e2));
verify(&mut layout, &[(e2, &[]), (e1, &[])]);
layout.insert_block(e0, e1);
assert!(layout.is_block_inserted(e0));
assert!(layout.is_block_inserted(e1));
assert!(layout.is_block_inserted(e2));
verify(&mut layout, &[(e2, &[]), (e0, &[]), (e1, &[])]);
}
#[test]
fn insert_block_after() {
let mut layout = Layout::new();
let e0 = Block::new(0);
let e1 = Block::new(1);
let e2 = Block::new(2);
layout.append_block(e1);
layout.insert_block_after(e2, e1);
verify(&mut layout, &[(e1, &[]), (e2, &[])]);
layout.insert_block_after(e0, e1);
verify(&mut layout, &[(e1, &[]), (e0, &[]), (e2, &[])]);
}
#[test]
fn append_inst() {
let mut layout = Layout::new();
let e1 = Block::new(1);
layout.append_block(e1);
let v: Vec<Inst> = layout.block_insts(e1).collect();
assert_eq!(v, []);
let i0 = Inst::new(0);
let i1 = Inst::new(1);
let i2 = Inst::new(2);
assert_eq!(layout.inst_block(i0), None);
assert_eq!(layout.inst_block(i1), None);
assert_eq!(layout.inst_block(i2), None);
layout.append_inst(i1, e1);
assert_eq!(layout.inst_block(i0), None);
assert_eq!(layout.inst_block(i1), Some(e1));
assert_eq!(layout.inst_block(i2), None);
let v: Vec<Inst> = layout.block_insts(e1).collect();
assert_eq!(v, [i1]);
layout.append_inst(i2, e1);
assert_eq!(layout.inst_block(i0), None);
assert_eq!(layout.inst_block(i1), Some(e1));
assert_eq!(layout.inst_block(i2), Some(e1));
let v: Vec<Inst> = layout.block_insts(e1).collect();
assert_eq!(v, [i1, i2]);
let v: Vec<Inst> = layout.block_insts(e1).rev().collect();
assert_eq!(v, [i2, i1]);
layout.append_inst(i0, e1);
verify(&mut layout, &[(e1, &[i1, i2, i0])]);
let mut cur = LayoutCursor::new(&mut layout).at_top(e1);
assert_eq!(cur.position(), CursorPosition::Before(e1));
assert_eq!(cur.prev_inst(), None);
assert_eq!(cur.position(), CursorPosition::Before(e1));
assert_eq!(cur.next_inst(), Some(i1));
assert_eq!(cur.position(), CursorPosition::At(i1));
assert_eq!(cur.next_inst(), Some(i2));
assert_eq!(cur.next_inst(), Some(i0));
assert_eq!(cur.prev_inst(), Some(i2));
assert_eq!(cur.position(), CursorPosition::At(i2));
assert_eq!(cur.next_inst(), Some(i0));
assert_eq!(cur.position(), CursorPosition::At(i0));
assert_eq!(cur.next_inst(), None);
assert_eq!(cur.position(), CursorPosition::After(e1));
assert_eq!(cur.next_inst(), None);
assert_eq!(cur.position(), CursorPosition::After(e1));
assert_eq!(cur.prev_inst(), Some(i0));
assert_eq!(cur.prev_inst(), Some(i2));
assert_eq!(cur.prev_inst(), Some(i1));
assert_eq!(cur.prev_inst(), None);
assert_eq!(cur.position(), CursorPosition::Before(e1));
cur.goto_inst(i2);
assert_eq!(cur.remove_inst(), i2);
verify(cur.layout, &[(e1, &[i1, i0])]);
assert_eq!(cur.layout.inst_block(i2), None);
assert_eq!(cur.remove_inst(), i0);
verify(cur.layout, &[(e1, &[i1])]);
assert_eq!(cur.layout.inst_block(i0), None);
assert_eq!(cur.position(), CursorPosition::After(e1));
cur.layout.remove_inst(i1);
verify(cur.layout, &[(e1, &[])]);
assert_eq!(cur.layout.inst_block(i1), None);
}
#[test]
fn insert_inst() {
let mut layout = Layout::new();
let e1 = Block::new(1);
layout.append_block(e1);
let v: Vec<Inst> = layout.block_insts(e1).collect();
assert_eq!(v, []);
let i0 = Inst::new(0);
let i1 = Inst::new(1);
let i2 = Inst::new(2);
assert_eq!(layout.inst_block(i0), None);
assert_eq!(layout.inst_block(i1), None);
assert_eq!(layout.inst_block(i2), None);
layout.append_inst(i1, e1);
assert_eq!(layout.inst_block(i0), None);
assert_eq!(layout.inst_block(i1), Some(e1));
assert_eq!(layout.inst_block(i2), None);
let v: Vec<Inst> = layout.block_insts(e1).collect();
assert_eq!(v, [i1]);
layout.insert_inst(i2, i1);
assert_eq!(layout.inst_block(i0), None);
assert_eq!(layout.inst_block(i1), Some(e1));
assert_eq!(layout.inst_block(i2), Some(e1));
let v: Vec<Inst> = layout.block_insts(e1).collect();
assert_eq!(v, [i2, i1]);
layout.insert_inst(i0, i1);
verify(&mut layout, &[(e1, &[i2, i0, i1])]);
}
#[test]
fn multiple_blocks() {
let mut layout = Layout::new();
let e0 = Block::new(0);
let e1 = Block::new(1);
assert_eq!(layout.entry_block(), None);
layout.append_block(e0);
assert_eq!(layout.entry_block(), Some(e0));
layout.append_block(e1);
assert_eq!(layout.entry_block(), Some(e0));
let i0 = Inst::new(0);
let i1 = Inst::new(1);
let i2 = Inst::new(2);
let i3 = Inst::new(3);
layout.append_inst(i0, e0);
layout.append_inst(i1, e0);
layout.append_inst(i2, e1);
layout.append_inst(i3, e1);
let v0: Vec<Inst> = layout.block_insts(e0).collect();
let v1: Vec<Inst> = layout.block_insts(e1).collect();
assert_eq!(v0, [i0, i1]);
assert_eq!(v1, [i2, i3]);
}
#[test]
fn split_block() {
let mut layout = Layout::new();
let e0 = Block::new(0);
let e1 = Block::new(1);
let e2 = Block::new(2);
let i0 = Inst::new(0);
let i1 = Inst::new(1);
let i2 = Inst::new(2);
let i3 = Inst::new(3);
layout.append_block(e0);
layout.append_inst(i0, e0);
assert_eq!(layout.inst_block(i0), Some(e0));
layout.split_block(e1, i0);
assert_eq!(layout.inst_block(i0), Some(e1));
{
let mut cur = LayoutCursor::new(&mut layout);
assert_eq!(cur.next_block(), Some(e0));
assert_eq!(cur.next_inst(), None);
assert_eq!(cur.next_block(), Some(e1));
assert_eq!(cur.next_inst(), Some(i0));
assert_eq!(cur.next_inst(), None);
assert_eq!(cur.next_block(), None);
assert_eq!(cur.prev_block(), Some(e1));
assert_eq!(cur.prev_inst(), Some(i0));
assert_eq!(cur.prev_inst(), None);
assert_eq!(cur.prev_block(), Some(e0));
assert_eq!(cur.prev_inst(), None);
assert_eq!(cur.prev_block(), None);
}
layout.append_inst(i1, e0);
layout.append_inst(i2, e0);
layout.append_inst(i3, e0);
layout.split_block(e2, i2);
assert_eq!(layout.inst_block(i0), Some(e1));
assert_eq!(layout.inst_block(i1), Some(e0));
assert_eq!(layout.inst_block(i2), Some(e2));
assert_eq!(layout.inst_block(i3), Some(e2));
{
let mut cur = LayoutCursor::new(&mut layout);
assert_eq!(cur.next_block(), Some(e0));
assert_eq!(cur.next_inst(), Some(i1));
assert_eq!(cur.next_inst(), None);
assert_eq!(cur.next_block(), 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_block(), Some(e1));
assert_eq!(cur.next_inst(), Some(i0));
assert_eq!(cur.next_inst(), None);
assert_eq!(cur.next_block(), None);
assert_eq!(cur.prev_block(), Some(e1));
assert_eq!(cur.prev_inst(), Some(i0));
assert_eq!(cur.prev_inst(), None);
assert_eq!(cur.prev_block(), 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_block(), Some(e0));
assert_eq!(cur.prev_inst(), Some(i1));
assert_eq!(cur.prev_inst(), None);
assert_eq!(cur.prev_block(), None);
}
assert_eq!(layout.cmp(e2, e2), Ordering::Equal);
assert_eq!(layout.cmp(e2, i2), Ordering::Less);
assert_eq!(layout.cmp(i3, i2), Ordering::Greater);
assert_eq!(layout.is_block_gap(i1, e2), true);
assert_eq!(layout.is_block_gap(i3, e1), true);
assert_eq!(layout.is_block_gap(i1, e1), false);
assert_eq!(layout.is_block_gap(i2, e1), false);
}
}