xref: /wasmtime-44.0.1/winch/codegen/src/stack.rs (revision a50c4972)
1835abbcdSSaúl Cabrera use crate::isa::reg::Reg;
2835abbcdSSaúl Cabrera use std::collections::VecDeque;
3835abbcdSSaúl Cabrera 
4835abbcdSSaúl Cabrera /// Value definition to be used within the shadow stack.
5*a50c4972SSaúl Cabrera #[derive(Debug, Eq, PartialEq, Copy, Clone)]
6835abbcdSSaúl Cabrera pub(crate) enum Val {
7835abbcdSSaúl Cabrera     /// I32 Constant.
8835abbcdSSaúl Cabrera     I32(i32),
97c5c7e4bSSaúl Cabrera     /// I64 Constant.
107c5c7e4bSSaúl Cabrera     I64(i64),
11835abbcdSSaúl Cabrera     /// A register.
12835abbcdSSaúl Cabrera     Reg(Reg),
13835abbcdSSaúl Cabrera     /// A local slot.
14835abbcdSSaúl Cabrera     Local(u32),
15835abbcdSSaúl Cabrera     /// Offset to a memory location.
16835abbcdSSaúl Cabrera     Memory(u32),
17835abbcdSSaúl Cabrera }
18835abbcdSSaúl Cabrera 
19835abbcdSSaúl Cabrera impl Val {
20835abbcdSSaúl Cabrera     /// Create a new I32 constant value.
21835abbcdSSaúl Cabrera     pub fn i32(v: i32) -> Self {
22835abbcdSSaúl Cabrera         Self::I32(v)
23835abbcdSSaúl Cabrera     }
24835abbcdSSaúl Cabrera 
257c5c7e4bSSaúl Cabrera     /// Create a new I64 constant value.
267c5c7e4bSSaúl Cabrera     pub fn i64(v: i64) -> Self {
277c5c7e4bSSaúl Cabrera         Self::I64(v)
287c5c7e4bSSaúl Cabrera     }
297c5c7e4bSSaúl Cabrera 
30835abbcdSSaúl Cabrera     /// Create a new Reg value.
31835abbcdSSaúl Cabrera     pub fn reg(r: Reg) -> Self {
32835abbcdSSaúl Cabrera         Self::Reg(r)
33835abbcdSSaúl Cabrera     }
34835abbcdSSaúl Cabrera 
35835abbcdSSaúl Cabrera     /// Create a new Local value.
36835abbcdSSaúl Cabrera     pub fn local(index: u32) -> Self {
37835abbcdSSaúl Cabrera         Self::Local(index)
38835abbcdSSaúl Cabrera     }
39835abbcdSSaúl Cabrera 
40835abbcdSSaúl Cabrera     /// Check whether the value is a register.
41835abbcdSSaúl Cabrera     pub fn is_reg(&self) -> bool {
42835abbcdSSaúl Cabrera         match *self {
43835abbcdSSaúl Cabrera             Self::Reg(_) => true,
44835abbcdSSaúl Cabrera             _ => false,
45835abbcdSSaúl Cabrera         }
46835abbcdSSaúl Cabrera     }
47835abbcdSSaúl Cabrera 
48af4d94c8SSaúl Cabrera     /// Check wheter the value is a memory offset.
49af4d94c8SSaúl Cabrera     pub fn is_mem(&self) -> bool {
50af4d94c8SSaúl Cabrera         match *self {
51af4d94c8SSaúl Cabrera             Self::Memory(_) => true,
52af4d94c8SSaúl Cabrera             _ => false,
53af4d94c8SSaúl Cabrera         }
54af4d94c8SSaúl Cabrera     }
55af4d94c8SSaúl Cabrera 
56835abbcdSSaúl Cabrera     /// Get the register representation of the value.
57835abbcdSSaúl Cabrera     ///
58835abbcdSSaúl Cabrera     /// # Panics
59835abbcdSSaúl Cabrera     /// This method will panic if the value is not a register.
60835abbcdSSaúl Cabrera     pub fn get_reg(&self) -> Reg {
61835abbcdSSaúl Cabrera         match self {
62835abbcdSSaúl Cabrera             Self::Reg(r) => *r,
63835abbcdSSaúl Cabrera             v => panic!("expected value {:?} to be a register", v),
64835abbcdSSaúl Cabrera         }
65835abbcdSSaúl Cabrera     }
66835abbcdSSaúl Cabrera 
67835abbcdSSaúl Cabrera     /// Get the integer representation of the value.
68835abbcdSSaúl Cabrera     ///
69835abbcdSSaúl Cabrera     /// # Panics
70835abbcdSSaúl Cabrera     /// This method will panic if the value is not an i32.
71835abbcdSSaúl Cabrera     pub fn get_i32(&self) -> i32 {
72835abbcdSSaúl Cabrera         match self {
73835abbcdSSaúl Cabrera             Self::I32(v) => *v,
74835abbcdSSaúl Cabrera             v => panic!("expected value {:?} to be i32", v),
75835abbcdSSaúl Cabrera         }
76835abbcdSSaúl Cabrera     }
77835abbcdSSaúl Cabrera 
787c5c7e4bSSaúl Cabrera     /// Get the integer representation of the value.
797c5c7e4bSSaúl Cabrera     ///
807c5c7e4bSSaúl Cabrera     /// # Panics
817c5c7e4bSSaúl Cabrera     /// This method will panic if the value is not an i64.
827c5c7e4bSSaúl Cabrera     pub fn get_i64(&self) -> i64 {
837c5c7e4bSSaúl Cabrera         match self {
847c5c7e4bSSaúl Cabrera             Self::I64(v) => *v,
857c5c7e4bSSaúl Cabrera             v => panic!("expected value {:?} to be i64", v),
867c5c7e4bSSaúl Cabrera         }
877c5c7e4bSSaúl Cabrera     }
887c5c7e4bSSaúl Cabrera 
89835abbcdSSaúl Cabrera     /// Check whether the value is an i32 constant.
90835abbcdSSaúl Cabrera     pub fn is_i32_const(&self) -> bool {
91835abbcdSSaúl Cabrera         match *self {
92835abbcdSSaúl Cabrera             Self::I32(_) => true,
93835abbcdSSaúl Cabrera             _ => false,
94835abbcdSSaúl Cabrera         }
95835abbcdSSaúl Cabrera     }
967c5c7e4bSSaúl Cabrera 
977c5c7e4bSSaúl Cabrera     /// Check whether the value is an i64 constant.
987c5c7e4bSSaúl Cabrera     pub fn is_i64_const(&self) -> bool {
997c5c7e4bSSaúl Cabrera         match *self {
1007c5c7e4bSSaúl Cabrera             Self::I64(_) => true,
1017c5c7e4bSSaúl Cabrera             _ => false,
1027c5c7e4bSSaúl Cabrera         }
1037c5c7e4bSSaúl Cabrera     }
104835abbcdSSaúl Cabrera }
105835abbcdSSaúl Cabrera 
106835abbcdSSaúl Cabrera /// The shadow stack used for compilation.
107835abbcdSSaúl Cabrera #[derive(Default, Debug)]
108835abbcdSSaúl Cabrera pub(crate) struct Stack {
109835abbcdSSaúl Cabrera     inner: VecDeque<Val>,
110835abbcdSSaúl Cabrera }
111835abbcdSSaúl Cabrera 
112835abbcdSSaúl Cabrera impl Stack {
113835abbcdSSaúl Cabrera     /// Allocate a new stack.
114835abbcdSSaúl Cabrera     pub fn new() -> Self {
115835abbcdSSaúl Cabrera         Self {
116835abbcdSSaúl Cabrera             inner: Default::default(),
117835abbcdSSaúl Cabrera         }
118835abbcdSSaúl Cabrera     }
119835abbcdSSaúl Cabrera 
12020c58362SSaúl Cabrera     /// Insert a new value at the specified index.
12120c58362SSaúl Cabrera     pub fn insert(&mut self, at: usize, val: Val) {
12220c58362SSaúl Cabrera         self.inner.insert(at, val);
12320c58362SSaúl Cabrera     }
12420c58362SSaúl Cabrera 
125af4d94c8SSaúl Cabrera     /// Get the length of the stack.
126af4d94c8SSaúl Cabrera     pub fn len(&self) -> usize {
127af4d94c8SSaúl Cabrera         self.inner.len()
128af4d94c8SSaúl Cabrera     }
129af4d94c8SSaúl Cabrera 
130835abbcdSSaúl Cabrera     /// Push a value to the stack.
131835abbcdSSaúl Cabrera     pub fn push(&mut self, val: Val) {
132835abbcdSSaúl Cabrera         self.inner.push_back(val);
133835abbcdSSaúl Cabrera     }
134835abbcdSSaúl Cabrera 
135835abbcdSSaúl Cabrera     /// Peek into the top in the stack.
1367c5c7e4bSSaúl Cabrera     pub fn peek(&self) -> Option<&Val> {
137835abbcdSSaúl Cabrera         self.inner.back()
138835abbcdSSaúl Cabrera     }
139835abbcdSSaúl Cabrera 
140af4d94c8SSaúl Cabrera     /// Returns an iterator referencing the last n items of the stack,
141af4d94c8SSaúl Cabrera     /// in bottom-most to top-most order.
142af4d94c8SSaúl Cabrera     pub fn peekn(&self, n: usize) -> impl Iterator<Item = &Val> + '_ {
143af4d94c8SSaúl Cabrera         let len = self.len();
144af4d94c8SSaúl Cabrera         assert!(n <= len);
145af4d94c8SSaúl Cabrera 
146af4d94c8SSaúl Cabrera         let partition = len - n;
147af4d94c8SSaúl Cabrera         self.inner.range(partition..)
148af4d94c8SSaúl Cabrera     }
149af4d94c8SSaúl Cabrera 
150835abbcdSSaúl Cabrera     /// Pops the top element of the stack, if any.
151835abbcdSSaúl Cabrera     pub fn pop(&mut self) -> Option<Val> {
152835abbcdSSaúl Cabrera         self.inner.pop_back()
153835abbcdSSaúl Cabrera     }
154835abbcdSSaúl Cabrera 
1557c5c7e4bSSaúl Cabrera     /// Pops the element at the top of the stack if it is an i32 const;
156835abbcdSSaúl Cabrera     /// returns `None` otherwise.
157835abbcdSSaúl Cabrera     pub fn pop_i32_const(&mut self) -> Option<i32> {
158835abbcdSSaúl Cabrera         match self.peek() {
159835abbcdSSaúl Cabrera             Some(v) => v.is_i32_const().then(|| self.pop().unwrap().get_i32()),
160835abbcdSSaúl Cabrera             _ => None,
161835abbcdSSaúl Cabrera         }
162835abbcdSSaúl Cabrera     }
163835abbcdSSaúl Cabrera 
1647c5c7e4bSSaúl Cabrera     /// Pops the element at the top of the stack if it is an i64 const;
1657c5c7e4bSSaúl Cabrera     /// returns `None` otherwise.
1667c5c7e4bSSaúl Cabrera     pub fn pop_i64_const(&mut self) -> Option<i64> {
1677c5c7e4bSSaúl Cabrera         match self.peek() {
1687c5c7e4bSSaúl Cabrera             Some(v) => v.is_i64_const().then(|| self.pop().unwrap().get_i64()),
1697c5c7e4bSSaúl Cabrera             _ => None,
1707c5c7e4bSSaúl Cabrera         }
1717c5c7e4bSSaúl Cabrera     }
1727c5c7e4bSSaúl Cabrera 
173835abbcdSSaúl Cabrera     /// Pops the element at the top of the stack if it is a register;
174835abbcdSSaúl Cabrera     /// returns `None` otherwise.
175835abbcdSSaúl Cabrera     pub fn pop_reg(&mut self) -> Option<Reg> {
176835abbcdSSaúl Cabrera         match self.peek() {
177835abbcdSSaúl Cabrera             Some(v) => v.is_reg().then(|| self.pop().unwrap().get_reg()),
178835abbcdSSaúl Cabrera             _ => None,
179835abbcdSSaúl Cabrera         }
180835abbcdSSaúl Cabrera     }
181835abbcdSSaúl Cabrera 
182835abbcdSSaúl Cabrera     /// Pops the given register if it is at the top of the stack;
183835abbcdSSaúl Cabrera     /// returns `None` otherwise.
184835abbcdSSaúl Cabrera     pub fn pop_named_reg(&mut self, reg: Reg) -> Option<Reg> {
185835abbcdSSaúl Cabrera         match self.peek() {
186835abbcdSSaúl Cabrera             Some(v) => (v.is_reg() && v.get_reg() == reg).then(|| self.pop().unwrap().get_reg()),
187835abbcdSSaúl Cabrera             _ => None,
188835abbcdSSaúl Cabrera         }
189835abbcdSSaúl Cabrera     }
190835abbcdSSaúl Cabrera 
191835abbcdSSaúl Cabrera     /// Get a mutable reference to the inner stack representation.
192835abbcdSSaúl Cabrera     pub fn inner_mut(&mut self) -> &mut VecDeque<Val> {
193835abbcdSSaúl Cabrera         &mut self.inner
194835abbcdSSaúl Cabrera     }
195835abbcdSSaúl Cabrera }
196835abbcdSSaúl Cabrera 
197835abbcdSSaúl Cabrera #[cfg(test)]
198835abbcdSSaúl Cabrera mod tests {
199835abbcdSSaúl Cabrera     use super::{Stack, Val};
200835abbcdSSaúl Cabrera     use crate::isa::reg::Reg;
201835abbcdSSaúl Cabrera 
202835abbcdSSaúl Cabrera     #[test]
203835abbcdSSaúl Cabrera     fn test_pop_i32_const() {
204835abbcdSSaúl Cabrera         let mut stack = Stack::new();
205835abbcdSSaúl Cabrera         stack.push(Val::i32(33i32));
206835abbcdSSaúl Cabrera         assert_eq!(33, stack.pop_i32_const().unwrap());
207835abbcdSSaúl Cabrera 
208835abbcdSSaúl Cabrera         stack.push(Val::local(10));
209835abbcdSSaúl Cabrera         assert!(stack.pop_i32_const().is_none());
210835abbcdSSaúl Cabrera     }
211835abbcdSSaúl Cabrera 
212835abbcdSSaúl Cabrera     #[test]
213835abbcdSSaúl Cabrera     fn test_pop_reg() {
214835abbcdSSaúl Cabrera         let mut stack = Stack::new();
215835abbcdSSaúl Cabrera         let reg = Reg::int(2usize);
216835abbcdSSaúl Cabrera         stack.push(Val::reg(reg));
217835abbcdSSaúl Cabrera         stack.push(Val::i32(4));
218835abbcdSSaúl Cabrera 
219835abbcdSSaúl Cabrera         assert_eq!(None, stack.pop_reg());
220835abbcdSSaúl Cabrera         let _ = stack.pop().unwrap();
221835abbcdSSaúl Cabrera         assert_eq!(reg, stack.pop_reg().unwrap());
222835abbcdSSaúl Cabrera     }
223835abbcdSSaúl Cabrera 
224835abbcdSSaúl Cabrera     #[test]
225835abbcdSSaúl Cabrera     fn test_pop_named_reg() {
226835abbcdSSaúl Cabrera         let mut stack = Stack::new();
227835abbcdSSaúl Cabrera         let reg = Reg::int(2usize);
228835abbcdSSaúl Cabrera         stack.push(Val::reg(reg));
229835abbcdSSaúl Cabrera         stack.push(Val::reg(Reg::int(4)));
230835abbcdSSaúl Cabrera 
231835abbcdSSaúl Cabrera         assert_eq!(None, stack.pop_named_reg(reg));
232835abbcdSSaúl Cabrera         let _ = stack.pop().unwrap();
233835abbcdSSaúl Cabrera         assert_eq!(reg, stack.pop_named_reg(reg).unwrap());
234835abbcdSSaúl Cabrera     }
235835abbcdSSaúl Cabrera }
236