Path: blob/main/cranelift/codegen/src/ir/layout.rs
1693 views
//! Function layout.1//!2//! The order of basic blocks in a function and the order of instructions in a block is3//! determined by the `Layout` data structure defined in this module.45use crate::entity::SecondaryMap;6use crate::ir::progpoint::ProgramPoint;7use crate::ir::{Block, Inst};8use crate::packed_option::PackedOption;9use crate::{timing, trace};10use core::cmp;1112/// The `Layout` struct determines the layout of blocks and instructions in a function. It does not13/// contain definitions of instructions or blocks, but depends on `Inst` and `Block` entity references14/// being defined elsewhere.15///16/// This data structure determines:17///18/// - The order of blocks in the function.19/// - Which block contains a given instruction.20/// - The order of instructions with a block.21///22/// While data dependencies are not recorded, instruction ordering does affect control23/// dependencies, so part of the semantics of the program are determined by the layout.24///25#[derive(Debug, Clone, PartialEq, Hash)]26pub struct Layout {27/// Linked list nodes for the layout order of blocks Forms a doubly linked list, terminated in28/// both ends by `None`.29blocks: SecondaryMap<Block, BlockNode>,3031/// Linked list nodes for the layout order of instructions. Forms a double linked list per block,32/// terminated in both ends by `None`.33insts: SecondaryMap<Inst, InstNode>,3435/// First block in the layout order, or `None` when no blocks have been laid out.36first_block: Option<Block>,3738/// Last block in the layout order, or `None` when no blocks have been laid out.39last_block: Option<Block>,40}4142impl Layout {43/// Create a new empty `Layout`.44pub fn new() -> Self {45Self {46blocks: SecondaryMap::new(),47insts: SecondaryMap::new(),48first_block: None,49last_block: None,50}51}5253/// Clear the layout.54pub fn clear(&mut self) {55self.blocks.clear();56self.insts.clear();57self.first_block = None;58self.last_block = None;59}6061/// Returns the capacity of the `BlockData` map.62pub fn block_capacity(&self) -> usize {63self.blocks.capacity()64}65}6667/// Sequence numbers.68///69/// All instructions are given a sequence number that can be used to quickly determine70/// their relative position in a block. The sequence numbers are not contiguous, but are assigned71/// like line numbers in BASIC: 10, 20, 30, ...72///73/// Sequence numbers are strictly increasing within a block, but are reset between blocks.74///75/// The result is that sequence numbers work like BASIC line numbers for the textual form of the IR.76type SequenceNumber = u32;7778/// Initial stride assigned to new sequence numbers.79const MAJOR_STRIDE: SequenceNumber = 10;8081/// Secondary stride used when renumbering locally.82const MINOR_STRIDE: SequenceNumber = 2;8384/// Limit on the sequence number range we'll renumber locally. If this limit is exceeded, we'll85/// switch to a full block renumbering.86const LOCAL_LIMIT: SequenceNumber = 100 * MINOR_STRIDE;8788/// Compute the midpoint between `a` and `b`.89/// Return `None` if the midpoint would be equal to either.90fn midpoint(a: SequenceNumber, b: SequenceNumber) -> Option<SequenceNumber> {91debug_assert!(a < b);92// Avoid integer overflow.93let m = a + (b - a) / 2;94if m > a { Some(m) } else { None }95}9697impl Layout {98/// Compare the program points `a` and `b` in the same block relative to this program order.99///100/// Return `Less` if `a` appears in the program before `b`.101///102/// This is declared as a generic such that it can be called with `Inst` and `Block` arguments103/// directly. Depending on the implementation, there is a good chance performance will be104/// improved for those cases where the type of either argument is known statically.105pub fn pp_cmp<A, B>(&self, a: A, b: B) -> cmp::Ordering106where107A: Into<ProgramPoint>,108B: Into<ProgramPoint>,109{110let a = a.into();111let b = b.into();112debug_assert_eq!(self.pp_block(a), self.pp_block(b));113let a_seq = match a {114ProgramPoint::Block(_block) => 0,115ProgramPoint::Inst(inst) => self.insts[inst].seq,116};117let b_seq = match b {118ProgramPoint::Block(_block) => 0,119ProgramPoint::Inst(inst) => self.insts[inst].seq,120};121a_seq.cmp(&b_seq)122}123}124125// Private methods for dealing with sequence numbers.126impl Layout {127/// Assign a valid sequence number to `inst` such that the numbers are still monotonic. This may128/// require renumbering.129fn assign_inst_seq(&mut self, inst: Inst) {130// Get the sequence number immediately before `inst`.131let prev_seq = match self.insts[inst].prev.expand() {132Some(prev_inst) => self.insts[prev_inst].seq,133None => 0,134};135136// Get the sequence number immediately following `inst`.137let next_seq = if let Some(next_inst) = self.insts[inst].next.expand() {138self.insts[next_inst].seq139} else {140// There is nothing after `inst`. We can just use a major stride.141self.insts[inst].seq = prev_seq + MAJOR_STRIDE;142return;143};144145// Check if there is room between these sequence numbers.146if let Some(seq) = midpoint(prev_seq, next_seq) {147self.insts[inst].seq = seq;148} else {149// No available integers between `prev_seq` and `next_seq`. We have to renumber.150self.renumber_insts(inst, prev_seq + MINOR_STRIDE, prev_seq + LOCAL_LIMIT);151}152}153154/// Renumber instructions starting from `inst` until the end of the block or until numbers catch155/// up.156///157/// If sequence numbers exceed `limit`, switch to a full block renumbering.158fn renumber_insts(&mut self, inst: Inst, seq: SequenceNumber, limit: SequenceNumber) {159let mut inst = inst;160let mut seq = seq;161162loop {163self.insts[inst].seq = seq;164165// Next instruction.166inst = match self.insts[inst].next.expand() {167None => return,168Some(next) => next,169};170171if seq < self.insts[inst].seq {172// Sequence caught up.173return;174}175176if seq > limit {177// We're pushing too many instructions in front of us.178// Switch to a full block renumbering to make some space.179self.full_block_renumber(180self.inst_block(inst)181.expect("inst must be inserted before assigning an seq"),182);183return;184}185186seq += MINOR_STRIDE;187}188}189190/// Renumber all instructions in a block.191///192/// This doesn't affect the position of anything, but it gives more room in the internal193/// sequence numbers for inserting instructions later.194fn full_block_renumber(&mut self, block: Block) {195let _tt = timing::layout_renumber();196// Avoid 0 as this is reserved for the program point indicating the block itself197let mut seq = MAJOR_STRIDE;198let mut next_inst = self.blocks[block].first_inst.expand();199while let Some(inst) = next_inst {200self.insts[inst].seq = seq;201seq += MAJOR_STRIDE;202next_inst = self.insts[inst].next.expand();203}204205trace!("Renumbered {} program points", seq / MAJOR_STRIDE);206}207}208209/// Methods for laying out blocks.210///211/// An unknown block starts out as *not inserted* in the block layout. The layout is a linear order of212/// inserted blocks. Once a block has been inserted in the layout, instructions can be added. A block213/// can only be removed from the layout when it is empty.214///215/// Since every block must end with a terminator instruction which cannot fall through, the layout of216/// blocks do not affect the semantics of the program.217///218impl Layout {219/// Is `block` currently part of the layout?220pub fn is_block_inserted(&self, block: Block) -> bool {221Some(block) == self.first_block || self.blocks[block].prev.is_some()222}223224/// Insert `block` as the last block in the layout.225pub fn append_block(&mut self, block: Block) {226debug_assert!(227!self.is_block_inserted(block),228"Cannot append block that is already in the layout"229);230{231let node = &mut self.blocks[block];232debug_assert!(node.first_inst.is_none() && node.last_inst.is_none());233node.prev = self.last_block.into();234node.next = None.into();235}236if let Some(last) = self.last_block {237self.blocks[last].next = block.into();238} else {239self.first_block = Some(block);240}241self.last_block = Some(block);242}243244/// Insert `block` in the layout before the existing block `before`.245pub fn insert_block(&mut self, block: Block, before: Block) {246debug_assert!(247!self.is_block_inserted(block),248"Cannot insert block that is already in the layout"249);250debug_assert!(251self.is_block_inserted(before),252"block Insertion point not in the layout"253);254let after = self.blocks[before].prev;255{256let node = &mut self.blocks[block];257node.next = before.into();258node.prev = after;259}260self.blocks[before].prev = block.into();261match after.expand() {262None => self.first_block = Some(block),263Some(a) => self.blocks[a].next = block.into(),264}265}266267/// Insert `block` in the layout *after* the existing block `after`.268pub fn insert_block_after(&mut self, block: Block, after: Block) {269debug_assert!(270!self.is_block_inserted(block),271"Cannot insert block that is already in the layout"272);273debug_assert!(274self.is_block_inserted(after),275"block Insertion point not in the layout"276);277let before = self.blocks[after].next;278{279let node = &mut self.blocks[block];280node.next = before;281node.prev = after.into();282}283self.blocks[after].next = block.into();284match before.expand() {285None => self.last_block = Some(block),286Some(b) => self.blocks[b].prev = block.into(),287}288}289290/// Remove `block` from the layout.291pub fn remove_block(&mut self, block: Block) {292debug_assert!(self.is_block_inserted(block), "block not in the layout");293debug_assert!(self.first_inst(block).is_none(), "block must be empty.");294295// Clear the `block` node and extract links.296let prev;297let next;298{299let n = &mut self.blocks[block];300prev = n.prev;301next = n.next;302n.prev = None.into();303n.next = None.into();304}305// Fix up links to `block`.306match prev.expand() {307None => self.first_block = next.expand(),308Some(p) => self.blocks[p].next = next,309}310match next.expand() {311None => self.last_block = prev.expand(),312Some(n) => self.blocks[n].prev = prev,313}314}315316/// Return an iterator over all blocks in layout order.317pub fn blocks(&self) -> Blocks<'_> {318Blocks {319layout: self,320next: self.first_block,321}322}323324/// Get the function's entry block.325/// This is simply the first block in the layout order.326pub fn entry_block(&self) -> Option<Block> {327self.first_block328}329330/// Get the last block in the layout.331pub fn last_block(&self) -> Option<Block> {332self.last_block333}334335/// Get the block preceding `block` in the layout order.336pub fn prev_block(&self, block: Block) -> Option<Block> {337self.blocks[block].prev.expand()338}339340/// Get the block following `block` in the layout order.341pub fn next_block(&self, block: Block) -> Option<Block> {342self.blocks[block].next.expand()343}344345/// Mark a block as "cold".346///347/// This will try to move it out of the ordinary path of execution348/// when lowered to machine code.349pub fn set_cold(&mut self, block: Block) {350self.blocks[block].cold = true;351}352353/// Is the given block cold?354pub fn is_cold(&self, block: Block) -> bool {355self.blocks[block].cold356}357}358359/// A single node in the linked-list of blocks.360// **Note:** Whenever you add new fields here, don't forget to update the custom serializer for `Layout` too.361#[derive(Clone, Debug, Default, PartialEq, Hash)]362struct BlockNode {363prev: PackedOption<Block>,364next: PackedOption<Block>,365first_inst: PackedOption<Inst>,366last_inst: PackedOption<Inst>,367cold: bool,368}369370/// Iterate over blocks in layout order. See [crate::ir::layout::Layout::blocks].371pub struct Blocks<'f> {372layout: &'f Layout,373next: Option<Block>,374}375376impl<'f> Iterator for Blocks<'f> {377type Item = Block;378379fn next(&mut self) -> Option<Block> {380match self.next {381Some(block) => {382self.next = self.layout.next_block(block);383Some(block)384}385None => None,386}387}388}389390/// Use a layout reference in a for loop.391impl<'f> IntoIterator for &'f Layout {392type Item = Block;393type IntoIter = Blocks<'f>;394395fn into_iter(self) -> Blocks<'f> {396self.blocks()397}398}399400/// Methods for arranging instructions.401///402/// An instruction starts out as *not inserted* in the layout. An instruction can be inserted into403/// a block at a given position.404impl Layout {405/// Get the block containing `inst`, or `None` if `inst` is not inserted in the layout.406pub fn inst_block(&self, inst: Inst) -> Option<Block> {407self.insts[inst].block.into()408}409410/// Get the block containing the program point `pp`. Panic if `pp` is not in the layout.411pub fn pp_block(&self, pp: ProgramPoint) -> Block {412match pp {413ProgramPoint::Block(block) => block,414ProgramPoint::Inst(inst) => self.inst_block(inst).expect("Program point not in layout"),415}416}417418/// Append `inst` to the end of `block`.419pub fn append_inst(&mut self, inst: Inst, block: Block) {420debug_assert_eq!(self.inst_block(inst), None);421debug_assert!(422self.is_block_inserted(block),423"Cannot append instructions to block not in layout"424);425{426let block_node = &mut self.blocks[block];427{428let inst_node = &mut self.insts[inst];429inst_node.block = block.into();430inst_node.prev = block_node.last_inst;431debug_assert!(inst_node.next.is_none());432}433if block_node.first_inst.is_none() {434block_node.first_inst = inst.into();435} else {436self.insts[block_node.last_inst.unwrap()].next = inst.into();437}438block_node.last_inst = inst.into();439}440self.assign_inst_seq(inst);441}442443/// Fetch a block's first instruction.444pub fn first_inst(&self, block: Block) -> Option<Inst> {445self.blocks[block].first_inst.into()446}447448/// Fetch a block's last instruction.449pub fn last_inst(&self, block: Block) -> Option<Inst> {450self.blocks[block].last_inst.into()451}452453/// Fetch the instruction following `inst`.454pub fn next_inst(&self, inst: Inst) -> Option<Inst> {455self.insts[inst].next.expand()456}457458/// Fetch the instruction preceding `inst`.459pub fn prev_inst(&self, inst: Inst) -> Option<Inst> {460self.insts[inst].prev.expand()461}462463/// Insert `inst` before the instruction `before` in the same block.464pub fn insert_inst(&mut self, inst: Inst, before: Inst) {465debug_assert_eq!(self.inst_block(inst), None);466let block = self467.inst_block(before)468.expect("Instruction before insertion point not in the layout");469let after = self.insts[before].prev;470{471let inst_node = &mut self.insts[inst];472inst_node.block = block.into();473inst_node.next = before.into();474inst_node.prev = after;475}476self.insts[before].prev = inst.into();477match after.expand() {478None => self.blocks[block].first_inst = inst.into(),479Some(a) => self.insts[a].next = inst.into(),480}481self.assign_inst_seq(inst);482}483484/// Remove `inst` from the layout.485pub fn remove_inst(&mut self, inst: Inst) {486let block = self.inst_block(inst).expect("Instruction already removed.");487// Clear the `inst` node and extract links.488let prev;489let next;490{491let n = &mut self.insts[inst];492prev = n.prev;493next = n.next;494n.block = None.into();495n.prev = None.into();496n.next = None.into();497}498// Fix up links to `inst`.499match prev.expand() {500None => self.blocks[block].first_inst = next,501Some(p) => self.insts[p].next = next,502}503match next.expand() {504None => self.blocks[block].last_inst = prev,505Some(n) => self.insts[n].prev = prev,506}507}508509/// Iterate over the instructions in `block` in layout order.510pub fn block_insts(&self, block: Block) -> Insts<'_> {511Insts {512layout: self,513head: self.blocks[block].first_inst.into(),514tail: self.blocks[block].last_inst.into(),515}516}517518/// Does the given block contain exactly one instruction?519pub fn block_contains_exactly_one_inst(&self, block: Block) -> bool {520let block = &self.blocks[block];521block.first_inst.is_some() && block.first_inst == block.last_inst522}523524/// Split the block containing `before` in two.525///526/// Insert `new_block` after the old block and move `before` and the following instructions to527/// `new_block`:528///529/// ```text530/// old_block:531/// i1532/// i2533/// i3 << before534/// i4535/// ```536/// becomes:537///538/// ```text539/// old_block:540/// i1541/// i2542/// new_block:543/// i3 << before544/// i4545/// ```546pub fn split_block(&mut self, new_block: Block, before: Inst) {547let old_block = self548.inst_block(before)549.expect("The `before` instruction must be in the layout");550debug_assert!(!self.is_block_inserted(new_block));551552// Insert new_block after old_block.553let next_block = self.blocks[old_block].next;554let last_inst = self.blocks[old_block].last_inst;555{556let node = &mut self.blocks[new_block];557node.prev = old_block.into();558node.next = next_block;559node.first_inst = before.into();560node.last_inst = last_inst;561}562self.blocks[old_block].next = new_block.into();563564// Fix backwards link.565if Some(old_block) == self.last_block {566self.last_block = Some(new_block);567} else {568self.blocks[next_block.unwrap()].prev = new_block.into();569}570571// Disconnect the instruction links.572let prev_inst = self.insts[before].prev;573self.insts[before].prev = None.into();574self.blocks[old_block].last_inst = prev_inst;575match prev_inst.expand() {576None => self.blocks[old_block].first_inst = None.into(),577Some(pi) => self.insts[pi].next = None.into(),578}579580// Fix the instruction -> block pointers.581let mut opt_i = Some(before);582while let Some(i) = opt_i {583debug_assert_eq!(self.insts[i].block.expand(), Some(old_block));584self.insts[i].block = new_block.into();585opt_i = self.insts[i].next.into();586}587}588}589590#[derive(Clone, Debug, Default)]591struct InstNode {592/// The Block containing this instruction, or `None` if the instruction is not yet inserted.593block: PackedOption<Block>,594prev: PackedOption<Inst>,595next: PackedOption<Inst>,596seq: SequenceNumber,597}598599impl PartialEq for InstNode {600fn eq(&self, other: &Self) -> bool {601// Ignore the sequence number as it is an optimization used by pp_cmp and may be different602// even for equivalent layouts.603self.block == other.block && self.prev == other.prev && self.next == other.next604}605}606607impl core::hash::Hash for InstNode {608fn hash<H: core::hash::Hasher>(&self, state: &mut H) {609// Ignore the sequence number as it is an optimization used by pp_cmp and may be different610// even for equivalent layouts.611self.block.hash(state);612self.prev.hash(state);613self.next.hash(state);614}615}616617/// Iterate over instructions in a block in layout order. See `Layout::block_insts()`.618pub struct Insts<'f> {619layout: &'f Layout,620head: Option<Inst>,621tail: Option<Inst>,622}623624impl<'f> Iterator for Insts<'f> {625type Item = Inst;626627fn next(&mut self) -> Option<Inst> {628let rval = self.head;629if let Some(inst) = rval {630if self.head == self.tail {631self.head = None;632self.tail = None;633} else {634self.head = self.layout.insts[inst].next.into();635}636}637rval638}639}640641impl<'f> DoubleEndedIterator for Insts<'f> {642fn next_back(&mut self) -> Option<Inst> {643let rval = self.tail;644if let Some(inst) = rval {645if self.head == self.tail {646self.head = None;647self.tail = None;648} else {649self.tail = self.layout.insts[inst].prev.into();650}651}652rval653}654}655656/// A custom serialize and deserialize implementation for [`Layout`].657///658/// This doesn't use a derived implementation as [`Layout`] is a manual implementation of a linked659/// list. Storing it directly as a regular list saves a lot of space.660///661/// The following format is used. (notated in EBNF form)662///663/// ```plain664/// data = block_data * ;665/// block_data = "block_id" , "cold" , "inst_count" , ( "inst_id" * ) ;666/// ```667#[cfg(feature = "enable-serde")]668mod serde {669use ::serde::de::{Deserializer, Error, SeqAccess, Visitor};670use ::serde::ser::{SerializeSeq, Serializer};671use ::serde::{Deserialize, Serialize};672use core::fmt;673use core::marker::PhantomData;674675use super::*;676677impl Serialize for Layout {678fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>679where680S: Serializer,681{682let size = self.blocks().count() * 3683+ self684.blocks()685.map(|block| self.block_insts(block).count())686.sum::<usize>();687let mut seq = serializer.serialize_seq(Some(size))?;688for block in self.blocks() {689seq.serialize_element(&block)?;690seq.serialize_element(&self.blocks[block].cold)?;691seq.serialize_element(&u32::try_from(self.block_insts(block).count()).unwrap())?;692for inst in self.block_insts(block) {693seq.serialize_element(&inst)?;694}695}696seq.end()697}698}699700impl<'de> Deserialize<'de> for Layout {701fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>702where703D: Deserializer<'de>,704{705deserializer.deserialize_seq(LayoutVisitor {706marker: PhantomData,707})708}709}710711struct LayoutVisitor {712marker: PhantomData<fn() -> Layout>,713}714715impl<'de> Visitor<'de> for LayoutVisitor {716type Value = Layout;717718fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {719write!(formatter, "a `cranelift_codegen::ir::Layout`")720}721722fn visit_seq<M>(self, mut access: M) -> Result<Self::Value, M::Error>723where724M: SeqAccess<'de>,725{726let mut layout = Layout::new();727728while let Some(block) = access.next_element::<Block>()? {729layout.append_block(block);730731let cold = access732.next_element::<bool>()?733.ok_or_else(|| Error::missing_field("cold"))?;734layout.blocks[block].cold = cold;735736let count = access737.next_element::<u32>()?738.ok_or_else(|| Error::missing_field("count"))?;739740for _ in 0..count {741let inst = access742.next_element::<Inst>()?743.ok_or_else(|| Error::missing_field("inst"))?;744layout.append_inst(inst, block);745}746}747748Ok(layout)749}750}751}752753#[cfg(test)]754mod tests {755use super::*;756use crate::cursor::{Cursor, CursorPosition};757use crate::entity::EntityRef;758use crate::ir::{Block, Inst, SourceLoc};759use alloc::vec::Vec;760use core::cmp::Ordering;761762#[test]763fn test_midpoint() {764assert_eq!(midpoint(0, 1), None);765assert_eq!(midpoint(0, 2), Some(1));766assert_eq!(midpoint(0, 3), Some(1));767assert_eq!(midpoint(0, 4), Some(2));768assert_eq!(midpoint(1, 4), Some(2));769assert_eq!(midpoint(2, 4), Some(3));770assert_eq!(midpoint(3, 4), None);771assert_eq!(midpoint(3, 4), None);772}773774struct LayoutCursor<'f> {775/// Borrowed function layout. Public so it can be re-borrowed from this cursor.776pub layout: &'f mut Layout,777pos: CursorPosition,778}779780impl<'f> Cursor for LayoutCursor<'f> {781fn position(&self) -> CursorPosition {782self.pos783}784785fn set_position(&mut self, pos: CursorPosition) {786self.pos = pos;787}788789fn srcloc(&self) -> SourceLoc {790unimplemented!()791}792793fn set_srcloc(&mut self, _srcloc: SourceLoc) {794unimplemented!()795}796797fn layout(&self) -> &Layout {798self.layout799}800801fn layout_mut(&mut self) -> &mut Layout {802self.layout803}804}805806impl<'f> LayoutCursor<'f> {807/// Create a new `LayoutCursor` for `layout`.808/// The cursor holds a mutable reference to `layout` for its entire lifetime.809pub fn new(layout: &'f mut Layout) -> Self {810Self {811layout,812pos: CursorPosition::Nowhere,813}814}815}816817fn verify(layout: &mut Layout, blocks: &[(Block, &[Inst])]) {818// Check that blocks are inserted and instructions belong the right places.819// Check forward linkage with iterators.820// Check that layout sequence numbers are strictly monotonic.821{822let mut block_iter = layout.blocks();823for &(block, insts) in blocks {824assert!(layout.is_block_inserted(block));825assert_eq!(block_iter.next(), Some(block));826827let mut seq = 0;828let mut inst_iter = layout.block_insts(block);829for &inst in insts {830assert_eq!(layout.inst_block(inst), Some(block));831assert_eq!(inst_iter.next(), Some(inst));832assert!(layout.insts[inst].seq > seq);833seq = layout.insts[inst].seq;834}835assert_eq!(inst_iter.next(), None);836}837assert_eq!(block_iter.next(), None);838}839840// Check backwards linkage with a cursor.841let mut cur = LayoutCursor::new(layout);842for &(block, insts) in blocks.into_iter().rev() {843assert_eq!(cur.prev_block(), Some(block));844for &inst in insts.into_iter().rev() {845assert_eq!(cur.prev_inst(), Some(inst));846}847assert_eq!(cur.prev_inst(), None);848}849assert_eq!(cur.prev_block(), None);850}851852#[test]853fn append_block() {854let mut layout = Layout::new();855let e0 = Block::new(0);856let e1 = Block::new(1);857let e2 = Block::new(2);858859{860let imm = &layout;861assert!(!imm.is_block_inserted(e0));862assert!(!imm.is_block_inserted(e1));863}864verify(&mut layout, &[]);865866layout.append_block(e1);867assert!(!layout.is_block_inserted(e0));868assert!(layout.is_block_inserted(e1));869assert!(!layout.is_block_inserted(e2));870let v: Vec<Block> = layout.blocks().collect();871assert_eq!(v, [e1]);872873layout.append_block(e2);874assert!(!layout.is_block_inserted(e0));875assert!(layout.is_block_inserted(e1));876assert!(layout.is_block_inserted(e2));877let v: Vec<Block> = layout.blocks().collect();878assert_eq!(v, [e1, e2]);879880layout.append_block(e0);881assert!(layout.is_block_inserted(e0));882assert!(layout.is_block_inserted(e1));883assert!(layout.is_block_inserted(e2));884let v: Vec<Block> = layout.blocks().collect();885assert_eq!(v, [e1, e2, e0]);886887{888let imm = &layout;889let mut v = Vec::new();890for e in imm {891v.push(e);892}893assert_eq!(v, [e1, e2, e0]);894}895896// Test cursor positioning.897let mut cur = LayoutCursor::new(&mut layout);898assert_eq!(cur.position(), CursorPosition::Nowhere);899assert_eq!(cur.next_inst(), None);900assert_eq!(cur.position(), CursorPosition::Nowhere);901assert_eq!(cur.prev_inst(), None);902assert_eq!(cur.position(), CursorPosition::Nowhere);903904assert_eq!(cur.next_block(), Some(e1));905assert_eq!(cur.position(), CursorPosition::Before(e1));906assert_eq!(cur.next_inst(), None);907assert_eq!(cur.position(), CursorPosition::After(e1));908assert_eq!(cur.next_inst(), None);909assert_eq!(cur.position(), CursorPosition::After(e1));910assert_eq!(cur.next_block(), Some(e2));911assert_eq!(cur.prev_inst(), None);912assert_eq!(cur.position(), CursorPosition::Before(e2));913assert_eq!(cur.next_block(), Some(e0));914assert_eq!(cur.next_block(), None);915assert_eq!(cur.position(), CursorPosition::Nowhere);916917// Backwards through the blocks.918assert_eq!(cur.prev_block(), Some(e0));919assert_eq!(cur.position(), CursorPosition::After(e0));920assert_eq!(cur.prev_block(), Some(e2));921assert_eq!(cur.prev_block(), Some(e1));922assert_eq!(cur.prev_block(), None);923assert_eq!(cur.position(), CursorPosition::Nowhere);924}925926#[test]927fn insert_block() {928let mut layout = Layout::new();929let e0 = Block::new(0);930let e1 = Block::new(1);931let e2 = Block::new(2);932933{934let imm = &layout;935assert!(!imm.is_block_inserted(e0));936assert!(!imm.is_block_inserted(e1));937938let v: Vec<Block> = layout.blocks().collect();939assert_eq!(v, []);940}941942layout.append_block(e1);943assert!(!layout.is_block_inserted(e0));944assert!(layout.is_block_inserted(e1));945assert!(!layout.is_block_inserted(e2));946verify(&mut layout, &[(e1, &[])]);947948layout.insert_block(e2, e1);949assert!(!layout.is_block_inserted(e0));950assert!(layout.is_block_inserted(e1));951assert!(layout.is_block_inserted(e2));952verify(&mut layout, &[(e2, &[]), (e1, &[])]);953954layout.insert_block(e0, e1);955assert!(layout.is_block_inserted(e0));956assert!(layout.is_block_inserted(e1));957assert!(layout.is_block_inserted(e2));958verify(&mut layout, &[(e2, &[]), (e0, &[]), (e1, &[])]);959}960961#[test]962fn insert_block_after() {963let mut layout = Layout::new();964let e0 = Block::new(0);965let e1 = Block::new(1);966let e2 = Block::new(2);967968layout.append_block(e1);969layout.insert_block_after(e2, e1);970verify(&mut layout, &[(e1, &[]), (e2, &[])]);971972layout.insert_block_after(e0, e1);973verify(&mut layout, &[(e1, &[]), (e0, &[]), (e2, &[])]);974}975976#[test]977fn append_inst() {978let mut layout = Layout::new();979let e1 = Block::new(1);980981layout.append_block(e1);982let v: Vec<Inst> = layout.block_insts(e1).collect();983assert_eq!(v, []);984985let i0 = Inst::new(0);986let i1 = Inst::new(1);987let i2 = Inst::new(2);988989assert_eq!(layout.inst_block(i0), None);990assert_eq!(layout.inst_block(i1), None);991assert_eq!(layout.inst_block(i2), None);992993layout.append_inst(i1, e1);994assert_eq!(layout.inst_block(i0), None);995assert_eq!(layout.inst_block(i1), Some(e1));996assert_eq!(layout.inst_block(i2), None);997let v: Vec<Inst> = layout.block_insts(e1).collect();998assert_eq!(v, [i1]);9991000layout.append_inst(i2, e1);1001assert_eq!(layout.inst_block(i0), None);1002assert_eq!(layout.inst_block(i1), Some(e1));1003assert_eq!(layout.inst_block(i2), Some(e1));1004let v: Vec<Inst> = layout.block_insts(e1).collect();1005assert_eq!(v, [i1, i2]);10061007// Test double-ended instruction iterator.1008let v: Vec<Inst> = layout.block_insts(e1).rev().collect();1009assert_eq!(v, [i2, i1]);10101011layout.append_inst(i0, e1);1012verify(&mut layout, &[(e1, &[i1, i2, i0])]);10131014// Test cursor positioning.1015let mut cur = LayoutCursor::new(&mut layout).at_top(e1);1016assert_eq!(cur.position(), CursorPosition::Before(e1));1017assert_eq!(cur.prev_inst(), None);1018assert_eq!(cur.position(), CursorPosition::Before(e1));1019assert_eq!(cur.next_inst(), Some(i1));1020assert_eq!(cur.position(), CursorPosition::At(i1));1021assert_eq!(cur.next_inst(), Some(i2));1022assert_eq!(cur.next_inst(), Some(i0));1023assert_eq!(cur.prev_inst(), Some(i2));1024assert_eq!(cur.position(), CursorPosition::At(i2));1025assert_eq!(cur.next_inst(), Some(i0));1026assert_eq!(cur.position(), CursorPosition::At(i0));1027assert_eq!(cur.next_inst(), None);1028assert_eq!(cur.position(), CursorPosition::After(e1));1029assert_eq!(cur.next_inst(), None);1030assert_eq!(cur.position(), CursorPosition::After(e1));1031assert_eq!(cur.prev_inst(), Some(i0));1032assert_eq!(cur.prev_inst(), Some(i2));1033assert_eq!(cur.prev_inst(), Some(i1));1034assert_eq!(cur.prev_inst(), None);1035assert_eq!(cur.position(), CursorPosition::Before(e1));10361037// Test remove_inst.1038cur.goto_inst(i2);1039assert_eq!(cur.remove_inst(), i2);1040verify(cur.layout, &[(e1, &[i1, i0])]);1041assert_eq!(cur.layout.inst_block(i2), None);1042assert_eq!(cur.remove_inst(), i0);1043verify(cur.layout, &[(e1, &[i1])]);1044assert_eq!(cur.layout.inst_block(i0), None);1045assert_eq!(cur.position(), CursorPosition::After(e1));1046cur.layout.remove_inst(i1);1047verify(cur.layout, &[(e1, &[])]);1048assert_eq!(cur.layout.inst_block(i1), None);1049}10501051#[test]1052fn insert_inst() {1053let mut layout = Layout::new();1054let e1 = Block::new(1);10551056layout.append_block(e1);1057let v: Vec<Inst> = layout.block_insts(e1).collect();1058assert_eq!(v, []);10591060let i0 = Inst::new(0);1061let i1 = Inst::new(1);1062let i2 = Inst::new(2);10631064assert_eq!(layout.inst_block(i0), None);1065assert_eq!(layout.inst_block(i1), None);1066assert_eq!(layout.inst_block(i2), None);10671068layout.append_inst(i1, e1);1069assert_eq!(layout.inst_block(i0), None);1070assert_eq!(layout.inst_block(i1), Some(e1));1071assert_eq!(layout.inst_block(i2), None);1072let v: Vec<Inst> = layout.block_insts(e1).collect();1073assert_eq!(v, [i1]);10741075layout.insert_inst(i2, i1);1076assert_eq!(layout.inst_block(i0), None);1077assert_eq!(layout.inst_block(i1), Some(e1));1078assert_eq!(layout.inst_block(i2), Some(e1));1079let v: Vec<Inst> = layout.block_insts(e1).collect();1080assert_eq!(v, [i2, i1]);10811082layout.insert_inst(i0, i1);1083verify(&mut layout, &[(e1, &[i2, i0, i1])]);1084}10851086#[test]1087fn multiple_blocks() {1088let mut layout = Layout::new();10891090let e0 = Block::new(0);1091let e1 = Block::new(1);10921093assert_eq!(layout.entry_block(), None);1094layout.append_block(e0);1095assert_eq!(layout.entry_block(), Some(e0));1096layout.append_block(e1);1097assert_eq!(layout.entry_block(), Some(e0));10981099let i0 = Inst::new(0);1100let i1 = Inst::new(1);1101let i2 = Inst::new(2);1102let i3 = Inst::new(3);11031104layout.append_inst(i0, e0);1105layout.append_inst(i1, e0);1106layout.append_inst(i2, e1);1107layout.append_inst(i3, e1);11081109let v0: Vec<Inst> = layout.block_insts(e0).collect();1110let v1: Vec<Inst> = layout.block_insts(e1).collect();1111assert_eq!(v0, [i0, i1]);1112assert_eq!(v1, [i2, i3]);1113}11141115#[test]1116fn split_block() {1117let mut layout = Layout::new();11181119let e0 = Block::new(0);1120let e1 = Block::new(1);1121let e2 = Block::new(2);11221123let i0 = Inst::new(0);1124let i1 = Inst::new(1);1125let i2 = Inst::new(2);1126let i3 = Inst::new(3);11271128layout.append_block(e0);1129layout.append_inst(i0, e0);1130assert_eq!(layout.inst_block(i0), Some(e0));1131layout.split_block(e1, i0);1132assert_eq!(layout.inst_block(i0), Some(e1));11331134{1135let mut cur = LayoutCursor::new(&mut layout);1136assert_eq!(cur.next_block(), Some(e0));1137assert_eq!(cur.next_inst(), None);1138assert_eq!(cur.next_block(), Some(e1));1139assert_eq!(cur.next_inst(), Some(i0));1140assert_eq!(cur.next_inst(), None);1141assert_eq!(cur.next_block(), None);11421143// Check backwards links.1144assert_eq!(cur.prev_block(), Some(e1));1145assert_eq!(cur.prev_inst(), Some(i0));1146assert_eq!(cur.prev_inst(), None);1147assert_eq!(cur.prev_block(), Some(e0));1148assert_eq!(cur.prev_inst(), None);1149assert_eq!(cur.prev_block(), None);1150}11511152layout.append_inst(i1, e0);1153layout.append_inst(i2, e0);1154layout.append_inst(i3, e0);1155layout.split_block(e2, i2);11561157assert_eq!(layout.inst_block(i0), Some(e1));1158assert_eq!(layout.inst_block(i1), Some(e0));1159assert_eq!(layout.inst_block(i2), Some(e2));1160assert_eq!(layout.inst_block(i3), Some(e2));11611162{1163let mut cur = LayoutCursor::new(&mut layout);1164assert_eq!(cur.next_block(), Some(e0));1165assert_eq!(cur.next_inst(), Some(i1));1166assert_eq!(cur.next_inst(), None);1167assert_eq!(cur.next_block(), Some(e2));1168assert_eq!(cur.next_inst(), Some(i2));1169assert_eq!(cur.next_inst(), Some(i3));1170assert_eq!(cur.next_inst(), None);1171assert_eq!(cur.next_block(), Some(e1));1172assert_eq!(cur.next_inst(), Some(i0));1173assert_eq!(cur.next_inst(), None);1174assert_eq!(cur.next_block(), None);11751176assert_eq!(cur.prev_block(), Some(e1));1177assert_eq!(cur.prev_inst(), Some(i0));1178assert_eq!(cur.prev_inst(), None);1179assert_eq!(cur.prev_block(), Some(e2));1180assert_eq!(cur.prev_inst(), Some(i3));1181assert_eq!(cur.prev_inst(), Some(i2));1182assert_eq!(cur.prev_inst(), None);1183assert_eq!(cur.prev_block(), Some(e0));1184assert_eq!(cur.prev_inst(), Some(i1));1185assert_eq!(cur.prev_inst(), None);1186assert_eq!(cur.prev_block(), None);1187}11881189// Check `ProgramOrder`.1190assert_eq!(layout.pp_cmp(e2, e2), Ordering::Equal);1191assert_eq!(layout.pp_cmp(e2, i2), Ordering::Less);1192assert_eq!(layout.pp_cmp(i3, i2), Ordering::Greater)1193}1194}119511961197