Path: blob/main/cranelift/codegen/src/ir/jumptable.rs
1693 views
//! Jump table representation.1//!2//! Jump tables are declared in the preamble and assigned an `ir::entities::JumpTable` reference.3//! The actual table of destinations is stored in a `JumpTableData` struct defined in this module.45use crate::ir::BlockCall;6use crate::ir::instructions::ValueListPool;7use alloc::vec::Vec;8use core::fmt::{self, Display, Formatter};9use core::slice::{Iter, IterMut};1011#[cfg(feature = "enable-serde")]12use serde_derive::{Deserialize, Serialize};1314/// Contents of a jump table.15///16/// All jump tables use 0-based indexing and are densely populated.17///18/// The default block for the jump table is stored as the first element of the underlying vector.19/// It can be accessed through the `default_block` and `default_block_mut` functions. All blocks20/// may be iterated using the `all_branches` and `all_branches_mut` functions, which will both21/// iterate over the default block first.22#[derive(Debug, Clone, PartialEq, Hash)]23#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]24pub struct JumpTableData {25// Table entries.26table: Vec<BlockCall>,27}2829impl JumpTableData {30/// Create a new jump table with the provided blocks.31pub fn new(def: BlockCall, table: &[BlockCall]) -> Self {32Self {33table: std::iter::once(def).chain(table.iter().copied()).collect(),34}35}3637/// Fetch the default block for this jump table.38pub fn default_block(&self) -> BlockCall {39*self.table.first().unwrap()40}4142/// Mutable access to the default block of this jump table.43pub fn default_block_mut(&mut self) -> &mut BlockCall {44self.table.first_mut().unwrap()45}4647/// The jump table and default block as a single slice. The default block will always be first.48pub fn all_branches(&self) -> &[BlockCall] {49self.table.as_slice()50}5152/// The jump table and default block as a single mutable slice. The default block will always53/// be first.54pub fn all_branches_mut(&mut self) -> &mut [BlockCall] {55self.table.as_mut_slice()56}5758/// Access the jump table as a slice. This excludes the default block.59pub fn as_slice(&self) -> &[BlockCall] {60&self.table.as_slice()[1..]61}6263/// Access the jump table as a mutable slice. This excludes the default block.64pub fn as_mut_slice(&mut self) -> &mut [BlockCall] {65&mut self.table.as_mut_slice()[1..]66}6768/// Returns an iterator to the jump table, excluding the default block.69#[deprecated(since = "7.0.0", note = "please use `.as_slice()` instead")]70pub fn iter(&self) -> Iter<'_, BlockCall> {71self.as_slice().iter()72}7374/// Returns an iterator that allows modifying each value, excluding the default block.75#[deprecated(since = "7.0.0", note = "please use `.as_mut_slice()` instead")]76pub fn iter_mut(&mut self) -> IterMut<'_, BlockCall> {77self.as_mut_slice().iter_mut()78}7980/// Clears all entries in this jump table, except for the default block.81pub fn clear(&mut self) {82self.table.drain(1..);83}8485/// Return a value that can display the contents of this jump table.86pub fn display<'a>(&'a self, pool: &'a ValueListPool) -> DisplayJumpTable<'a> {87DisplayJumpTable { jt: self, pool }88}89}9091/// A wrapper for the context required to display a [JumpTableData].92pub struct DisplayJumpTable<'a> {93jt: &'a JumpTableData,94pool: &'a ValueListPool,95}9697impl<'a> Display for DisplayJumpTable<'a> {98fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {99write!(fmt, "{}, [", self.jt.default_block().display(self.pool))?;100if let Some((first, rest)) = self.jt.as_slice().split_first() {101write!(fmt, "{}", first.display(self.pool))?;102for block in rest {103write!(fmt, ", {}", block.display(self.pool))?;104}105}106write!(fmt, "]")107}108}109110#[cfg(test)]111mod tests {112use super::JumpTableData;113use crate::entity::EntityRef;114use crate::ir::instructions::ValueListPool;115use crate::ir::{Block, BlockArg, BlockCall, Value};116use alloc::vec::Vec;117use std::string::ToString;118119#[test]120fn empty() {121let mut pool = ValueListPool::default();122let def = BlockCall::new(Block::new(0), core::iter::empty(), &mut pool);123124let jt = JumpTableData::new(def, &[]);125126assert_eq!(jt.all_branches().get(0), Some(&def));127128assert_eq!(jt.as_slice().get(0), None);129assert_eq!(jt.as_slice().get(10), None);130131assert_eq!(jt.display(&pool).to_string(), "block0, []");132133assert_eq!(jt.all_branches(), [def]);134assert_eq!(jt.as_slice(), []);135}136137#[test]138fn insert() {139let mut pool = ValueListPool::default();140141let v0 = Value::new(0);142let v1 = Value::new(1);143144let e0 = Block::new(0);145let e1 = Block::new(1);146let e2 = Block::new(2);147148let def = BlockCall::new(e0, core::iter::empty(), &mut pool);149let b1 = BlockCall::new(e1, core::iter::once(v0.into()), &mut pool);150let b2 = BlockCall::new(e2, core::iter::empty(), &mut pool);151let b3 = BlockCall::new(e1, core::iter::once(v1.into()), &mut pool);152153let jt = JumpTableData::new(def, &[b1, b2, b3]);154155assert_eq!(jt.default_block(), def);156assert_eq!(157jt.display(&pool).to_string(),158"block0, [block1(v0), block2, block1(v1)]"159);160161assert_eq!(jt.all_branches(), [def, b1, b2, b3]);162assert_eq!(jt.as_slice(), [b1, b2, b3]);163164assert_eq!(165jt.as_slice()[0].args(&pool).collect::<Vec<_>>(),166[BlockArg::Value(v0)]167);168assert_eq!(jt.as_slice()[1].args(&pool).collect::<Vec<_>>(), []);169assert_eq!(170jt.as_slice()[2].args(&pool).collect::<Vec<_>>(),171[BlockArg::Value(v1)]172);173}174}175176177