cranelift_codegen/ir/
jumptable.rs1use crate::ir::instructions::ValueListPool;
7use crate::ir::BlockCall;
8use alloc::vec::Vec;
9use core::fmt::{self, Display, Formatter};
10use core::slice::{Iter, IterMut};
11
12#[cfg(feature = "enable-serde")]
13use serde_derive::{Deserialize, Serialize};
14
15#[derive(Debug, Clone, PartialEq, Hash)]
24#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
25pub struct JumpTableData {
26 table: Vec<BlockCall>,
28}
29
30impl JumpTableData {
31 pub fn new(def: BlockCall, table: &[BlockCall]) -> Self {
33 Self {
34 table: std::iter::once(def).chain(table.iter().copied()).collect(),
35 }
36 }
37
38 pub fn default_block(&self) -> BlockCall {
40 *self.table.first().unwrap()
41 }
42
43 pub fn default_block_mut(&mut self) -> &mut BlockCall {
45 self.table.first_mut().unwrap()
46 }
47
48 pub fn all_branches(&self) -> &[BlockCall] {
50 self.table.as_slice()
51 }
52
53 pub fn all_branches_mut(&mut self) -> &mut [BlockCall] {
56 self.table.as_mut_slice()
57 }
58
59 pub fn as_slice(&self) -> &[BlockCall] {
61 &self.table.as_slice()[1..]
62 }
63
64 pub fn as_mut_slice(&mut self) -> &mut [BlockCall] {
66 &mut self.table.as_mut_slice()[1..]
67 }
68
69 #[deprecated(since = "7.0.0", note = "please use `.as_slice()` instead")]
71 pub fn iter(&self) -> Iter<BlockCall> {
72 self.as_slice().iter()
73 }
74
75 #[deprecated(since = "7.0.0", note = "please use `.as_mut_slice()` instead")]
77 pub fn iter_mut(&mut self) -> IterMut<BlockCall> {
78 self.as_mut_slice().iter_mut()
79 }
80
81 pub fn clear(&mut self) {
83 self.table.drain(1..);
84 }
85
86 pub fn display<'a>(&'a self, pool: &'a ValueListPool) -> DisplayJumpTable<'a> {
88 DisplayJumpTable { jt: self, pool }
89 }
90}
91
92pub struct DisplayJumpTable<'a> {
94 jt: &'a JumpTableData,
95 pool: &'a ValueListPool,
96}
97
98impl<'a> Display for DisplayJumpTable<'a> {
99 fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
100 write!(fmt, "{}, [", self.jt.default_block().display(self.pool))?;
101 if let Some((first, rest)) = self.jt.as_slice().split_first() {
102 write!(fmt, "{}", first.display(self.pool))?;
103 for block in rest {
104 write!(fmt, ", {}", block.display(self.pool))?;
105 }
106 }
107 write!(fmt, "]")
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::JumpTableData;
114 use crate::entity::EntityRef;
115 use crate::ir::instructions::ValueListPool;
116 use crate::ir::{Block, BlockCall, Value};
117 use std::string::ToString;
118
119 #[test]
120 fn empty() {
121 let mut pool = ValueListPool::default();
122 let def = BlockCall::new(Block::new(0), &[], &mut pool);
123
124 let jt = JumpTableData::new(def, &[]);
125
126 assert_eq!(jt.all_branches().get(0), Some(&def));
127
128 assert_eq!(jt.as_slice().get(0), None);
129 assert_eq!(jt.as_slice().get(10), None);
130
131 assert_eq!(jt.display(&pool).to_string(), "block0, []");
132
133 assert_eq!(jt.all_branches(), [def]);
134 assert_eq!(jt.as_slice(), []);
135 }
136
137 #[test]
138 fn insert() {
139 let mut pool = ValueListPool::default();
140
141 let v0 = Value::new(0);
142 let v1 = Value::new(1);
143
144 let e0 = Block::new(0);
145 let e1 = Block::new(1);
146 let e2 = Block::new(2);
147
148 let def = BlockCall::new(e0, &[], &mut pool);
149 let b1 = BlockCall::new(e1, &[v0], &mut pool);
150 let b2 = BlockCall::new(e2, &[], &mut pool);
151 let b3 = BlockCall::new(e1, &[v1], &mut pool);
152
153 let jt = JumpTableData::new(def, &[b1, b2, b3]);
154
155 assert_eq!(jt.default_block(), def);
156 assert_eq!(
157 jt.display(&pool).to_string(),
158 "block0, [block1(v0), block2, block1(v1)]"
159 );
160
161 assert_eq!(jt.all_branches(), [def, b1, b2, b3]);
162 assert_eq!(jt.as_slice(), [b1, b2, b3]);
163
164 assert_eq!(jt.as_slice()[0].args_slice(&pool), [v0]);
165 assert_eq!(jt.as_slice()[1].args_slice(&pool), []);
166 assert_eq!(jt.as_slice()[2].args_slice(&pool), [v1]);
167 }
168}