xref: /wasmtime-44.0.1/winch/codegen/src/stack.rs (revision b93e1bc0)
1*b93e1bc0SSaúl Cabrera use crate::{codegen::CodeGenError, isa::reg::Reg, masm::StackSlot};
2*b93e1bc0SSaúl Cabrera use anyhow::{anyhow, Result};
31b5c4ae8SSaúl Cabrera use smallvec::SmallVec;
414b39bc2SSaúl Cabrera use wasmparser::{Ieee32, Ieee64};
5496237c2SNick Fitzgerald use wasmtime_environ::WasmValType;
614b39bc2SSaúl Cabrera 
714b39bc2SSaúl Cabrera /// A typed register value used to track register values in the value
814b39bc2SSaúl Cabrera /// stack.
914b39bc2SSaúl Cabrera #[derive(Debug, Eq, PartialEq, Copy, Clone)]
1014b39bc2SSaúl Cabrera pub struct TypedReg {
1114b39bc2SSaúl Cabrera     /// The physical register.
1214b39bc2SSaúl Cabrera     pub reg: Reg,
1314b39bc2SSaúl Cabrera     /// The type associated to the physical register.
14496237c2SNick Fitzgerald     pub ty: WasmValType,
1514b39bc2SSaúl Cabrera }
1614b39bc2SSaúl Cabrera 
1714b39bc2SSaúl Cabrera impl TypedReg {
184b288ba8SSaúl Cabrera     /// Create a new [`TypedReg`].
19496237c2SNick Fitzgerald     pub fn new(ty: WasmValType, reg: Reg) -> Self {
2014b39bc2SSaúl Cabrera         Self { ty, reg }
2114b39bc2SSaúl Cabrera     }
2214b39bc2SSaúl Cabrera 
234b288ba8SSaúl Cabrera     /// Create an i64 [`TypedReg`].
2414b39bc2SSaúl Cabrera     pub fn i64(reg: Reg) -> Self {
2514b39bc2SSaúl Cabrera         Self {
26496237c2SNick Fitzgerald             ty: WasmValType::I64,
2714b39bc2SSaúl Cabrera             reg,
2814b39bc2SSaúl Cabrera         }
2914b39bc2SSaúl Cabrera     }
30a109d2abSSaúl Cabrera 
31f0162a40SSaúl Cabrera     /// Create an i32 [`TypedReg`].
32a109d2abSSaúl Cabrera     pub fn i32(reg: Reg) -> Self {
33a109d2abSSaúl Cabrera         Self {
34496237c2SNick Fitzgerald             ty: WasmValType::I32,
35a109d2abSSaúl Cabrera             reg,
36a109d2abSSaúl Cabrera         }
37a109d2abSSaúl Cabrera     }
3817091e6fSJeffrey Charles 
3917091e6fSJeffrey Charles     /// Create an f64 [`TypedReg`].
4017091e6fSJeffrey Charles     pub fn f64(reg: Reg) -> Self {
4117091e6fSJeffrey Charles         Self {
42496237c2SNick Fitzgerald             ty: WasmValType::F64,
4317091e6fSJeffrey Charles             reg,
4417091e6fSJeffrey Charles         }
4517091e6fSJeffrey Charles     }
4617091e6fSJeffrey Charles 
4717091e6fSJeffrey Charles     /// Create an f32 [`TypedReg`].
4817091e6fSJeffrey Charles     pub fn f32(reg: Reg) -> Self {
4917091e6fSJeffrey Charles         Self {
50496237c2SNick Fitzgerald             ty: WasmValType::F32,
5117091e6fSJeffrey Charles             reg,
5217091e6fSJeffrey Charles         }
5317091e6fSJeffrey Charles     }
5414b39bc2SSaúl Cabrera }
5514b39bc2SSaúl Cabrera 
5614b39bc2SSaúl Cabrera impl From<TypedReg> for Reg {
5714b39bc2SSaúl Cabrera     fn from(tr: TypedReg) -> Self {
5814b39bc2SSaúl Cabrera         tr.reg
5914b39bc2SSaúl Cabrera     }
6014b39bc2SSaúl Cabrera }
6114b39bc2SSaúl Cabrera 
6214b39bc2SSaúl Cabrera /// A local value.
6314b39bc2SSaúl Cabrera #[derive(Debug, Eq, PartialEq, Copy, Clone)]
6414b39bc2SSaúl Cabrera pub struct Local {
6514b39bc2SSaúl Cabrera     /// The index of the local.
6614b39bc2SSaúl Cabrera     pub index: u32,
6714b39bc2SSaúl Cabrera     /// The type of the local.
68496237c2SNick Fitzgerald     pub ty: WasmValType,
6914b39bc2SSaúl Cabrera }
7014b39bc2SSaúl Cabrera 
7114b39bc2SSaúl Cabrera /// A memory value.
7214b39bc2SSaúl Cabrera #[derive(Debug, Eq, PartialEq, Copy, Clone)]
7314b39bc2SSaúl Cabrera pub struct Memory {
7414b39bc2SSaúl Cabrera     /// The type associated with the memory offset.
75496237c2SNick Fitzgerald     pub ty: WasmValType,
7614b39bc2SSaúl Cabrera     /// The stack slot corresponding to the memory value.
7714b39bc2SSaúl Cabrera     pub slot: StackSlot,
7814b39bc2SSaúl Cabrera }
79835abbcdSSaúl Cabrera 
80835abbcdSSaúl Cabrera /// Value definition to be used within the shadow stack.
81a50c4972SSaúl Cabrera #[derive(Debug, Eq, PartialEq, Copy, Clone)]
82835abbcdSSaúl Cabrera pub(crate) enum Val {
83835abbcdSSaúl Cabrera     /// I32 Constant.
84835abbcdSSaúl Cabrera     I32(i32),
857c5c7e4bSSaúl Cabrera     /// I64 Constant.
867c5c7e4bSSaúl Cabrera     I64(i64),
8714b39bc2SSaúl Cabrera     /// F32 Constant.
8814b39bc2SSaúl Cabrera     F32(Ieee32),
8914b39bc2SSaúl Cabrera     /// F64 Constant.
9014b39bc2SSaúl Cabrera     F64(Ieee64),
91fa9a948dSJeffrey Charles     /// V128 Constant.
92fa9a948dSJeffrey Charles     V128(i128),
9314b39bc2SSaúl Cabrera     /// A register value.
9414b39bc2SSaúl Cabrera     Reg(TypedReg),
95835abbcdSSaúl Cabrera     /// A local slot.
9614b39bc2SSaúl Cabrera     Local(Local),
97835abbcdSSaúl Cabrera     /// Offset to a memory location.
9814b39bc2SSaúl Cabrera     Memory(Memory),
9914b39bc2SSaúl Cabrera }
10014b39bc2SSaúl Cabrera 
10114b39bc2SSaúl Cabrera impl From<TypedReg> for Val {
10214b39bc2SSaúl Cabrera     fn from(tr: TypedReg) -> Self {
10314b39bc2SSaúl Cabrera         Val::Reg(tr)
10414b39bc2SSaúl Cabrera     }
10514b39bc2SSaúl Cabrera }
10614b39bc2SSaúl Cabrera 
10714b39bc2SSaúl Cabrera impl From<Local> for Val {
10814b39bc2SSaúl Cabrera     fn from(local: Local) -> Self {
10914b39bc2SSaúl Cabrera         Val::Local(local)
11014b39bc2SSaúl Cabrera     }
11114b39bc2SSaúl Cabrera }
11214b39bc2SSaúl Cabrera 
11314b39bc2SSaúl Cabrera impl From<Memory> for Val {
11414b39bc2SSaúl Cabrera     fn from(mem: Memory) -> Self {
11514b39bc2SSaúl Cabrera         Val::Memory(mem)
11614b39bc2SSaúl Cabrera     }
117835abbcdSSaúl Cabrera }
118835abbcdSSaúl Cabrera 
1194b288ba8SSaúl Cabrera impl TryFrom<u32> for Val {
1204b288ba8SSaúl Cabrera     type Error = anyhow::Error;
1214b288ba8SSaúl Cabrera     fn try_from(value: u32) -> Result<Self, Self::Error> {
1224b288ba8SSaúl Cabrera         i32::try_from(value).map(Val::i32).map_err(Into::into)
1234b288ba8SSaúl Cabrera     }
1244b288ba8SSaúl Cabrera }
1254b288ba8SSaúl Cabrera 
126835abbcdSSaúl Cabrera impl Val {
127835abbcdSSaúl Cabrera     /// Create a new I32 constant value.
128835abbcdSSaúl Cabrera     pub fn i32(v: i32) -> Self {
129835abbcdSSaúl Cabrera         Self::I32(v)
130835abbcdSSaúl Cabrera     }
131835abbcdSSaúl Cabrera 
1327c5c7e4bSSaúl Cabrera     /// Create a new I64 constant value.
1337c5c7e4bSSaúl Cabrera     pub fn i64(v: i64) -> Self {
1347c5c7e4bSSaúl Cabrera         Self::I64(v)
1357c5c7e4bSSaúl Cabrera     }
1367c5c7e4bSSaúl Cabrera 
13714b39bc2SSaúl Cabrera     /// Create a new F32 constant value.
13814b39bc2SSaúl Cabrera     pub fn f32(v: Ieee32) -> Self {
13914b39bc2SSaúl Cabrera         Self::F32(v)
14014b39bc2SSaúl Cabrera     }
14114b39bc2SSaúl Cabrera 
14214b39bc2SSaúl Cabrera     pub fn f64(v: Ieee64) -> Self {
14314b39bc2SSaúl Cabrera         Self::F64(v)
14414b39bc2SSaúl Cabrera     }
14514b39bc2SSaúl Cabrera 
146fa9a948dSJeffrey Charles     /// Create a new V128 constant value.
147fa9a948dSJeffrey Charles     pub fn v128(v: i128) -> Self {
148fa9a948dSJeffrey Charles         Self::V128(v)
149fa9a948dSJeffrey Charles     }
150fa9a948dSJeffrey Charles 
151835abbcdSSaúl Cabrera     /// Create a new Reg value.
152496237c2SNick Fitzgerald     pub fn reg(reg: Reg, ty: WasmValType) -> Self {
15314b39bc2SSaúl Cabrera         Self::Reg(TypedReg { reg, ty })
154835abbcdSSaúl Cabrera     }
155835abbcdSSaúl Cabrera 
156835abbcdSSaúl Cabrera     /// Create a new Local value.
157496237c2SNick Fitzgerald     pub fn local(index: u32, ty: WasmValType) -> Self {
15814b39bc2SSaúl Cabrera         Self::Local(Local { index, ty })
15914b39bc2SSaúl Cabrera     }
16014b39bc2SSaúl Cabrera 
16114b39bc2SSaúl Cabrera     /// Create a Memory value.
162496237c2SNick Fitzgerald     pub fn mem(ty: WasmValType, slot: StackSlot) -> Self {
16314b39bc2SSaúl Cabrera         Self::Memory(Memory { ty, slot })
164835abbcdSSaúl Cabrera     }
165835abbcdSSaúl Cabrera 
166835abbcdSSaúl Cabrera     /// Check whether the value is a register.
167835abbcdSSaúl Cabrera     pub fn is_reg(&self) -> bool {
168835abbcdSSaúl Cabrera         match *self {
169835abbcdSSaúl Cabrera             Self::Reg(_) => true,
170835abbcdSSaúl Cabrera             _ => false,
171835abbcdSSaúl Cabrera         }
172835abbcdSSaúl Cabrera     }
173835abbcdSSaúl Cabrera 
1740e9121daSFrankReh     /// Check whether the value is a memory offset.
175af4d94c8SSaúl Cabrera     pub fn is_mem(&self) -> bool {
176af4d94c8SSaúl Cabrera         match *self {
177af4d94c8SSaúl Cabrera             Self::Memory(_) => true,
178af4d94c8SSaúl Cabrera             _ => false,
179af4d94c8SSaúl Cabrera         }
180af4d94c8SSaúl Cabrera     }
181af4d94c8SSaúl Cabrera 
18255f9a4bdSJeffrey Charles     /// Check whether the value is a constant.
18355f9a4bdSJeffrey Charles     pub fn is_const(&self) -> bool {
18455f9a4bdSJeffrey Charles         match *self {
185fa9a948dSJeffrey Charles             Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => true,
18655f9a4bdSJeffrey Charles             _ => false,
18755f9a4bdSJeffrey Charles         }
18855f9a4bdSJeffrey Charles     }
18955f9a4bdSJeffrey Charles 
190321294a5SJeffrey Charles     /// Check whether the value is local with a particular index.
191321294a5SJeffrey Charles     pub fn is_local_at_index(&self, index: u32) -> bool {
192321294a5SJeffrey Charles         match *self {
193321294a5SJeffrey Charles             Self::Local(Local { index: i, .. }) if i == index => true,
194321294a5SJeffrey Charles             _ => false,
195321294a5SJeffrey Charles         }
196321294a5SJeffrey Charles     }
197321294a5SJeffrey Charles 
198835abbcdSSaúl Cabrera     /// Get the register representation of the value.
199835abbcdSSaúl Cabrera     ///
200835abbcdSSaúl Cabrera     /// # Panics
201835abbcdSSaúl Cabrera     /// This method will panic if the value is not a register.
202f0162a40SSaúl Cabrera     pub fn unwrap_reg(&self) -> TypedReg {
203835abbcdSSaúl Cabrera         match self {
20414b39bc2SSaúl Cabrera             Self::Reg(tr) => *tr,
205a0442ea0SHamir Mahal             v => panic!("expected value {v:?} to be a register"),
206835abbcdSSaúl Cabrera         }
207835abbcdSSaúl Cabrera     }
208835abbcdSSaúl Cabrera 
209835abbcdSSaúl Cabrera     /// Get the integer representation of the value.
210835abbcdSSaúl Cabrera     ///
211835abbcdSSaúl Cabrera     /// # Panics
212835abbcdSSaúl Cabrera     /// This method will panic if the value is not an i32.
213f0162a40SSaúl Cabrera     pub fn unwrap_i32(&self) -> i32 {
214835abbcdSSaúl Cabrera         match self {
215835abbcdSSaúl Cabrera             Self::I32(v) => *v,
216a0442ea0SHamir Mahal             v => panic!("expected value {v:?} to be i32"),
217835abbcdSSaúl Cabrera         }
218835abbcdSSaúl Cabrera     }
219835abbcdSSaúl Cabrera 
2207c5c7e4bSSaúl Cabrera     /// Get the integer representation of the value.
2217c5c7e4bSSaúl Cabrera     ///
2227c5c7e4bSSaúl Cabrera     /// # Panics
2237c5c7e4bSSaúl Cabrera     /// This method will panic if the value is not an i64.
224f0162a40SSaúl Cabrera     pub fn unwrap_i64(&self) -> i64 {
2257c5c7e4bSSaúl Cabrera         match self {
2267c5c7e4bSSaúl Cabrera             Self::I64(v) => *v,
227a0442ea0SHamir Mahal             v => panic!("expected value {v:?} to be i64"),
2287c5c7e4bSSaúl Cabrera         }
2297c5c7e4bSSaúl Cabrera     }
2307c5c7e4bSSaúl Cabrera 
231f0162a40SSaúl Cabrera     /// Returns the underlying memory value if it is one, panics otherwise.
232f0162a40SSaúl Cabrera     pub fn unwrap_mem(&self) -> Memory {
233f0162a40SSaúl Cabrera         match self {
234f0162a40SSaúl Cabrera             Self::Memory(m) => *m,
235a0442ea0SHamir Mahal             v => panic!("expected value {v:?} to be a Memory"),
236f0162a40SSaúl Cabrera         }
237f0162a40SSaúl Cabrera     }
238f0162a40SSaúl Cabrera 
239835abbcdSSaúl Cabrera     /// Check whether the value is an i32 constant.
240835abbcdSSaúl Cabrera     pub fn is_i32_const(&self) -> bool {
241835abbcdSSaúl Cabrera         match *self {
242835abbcdSSaúl Cabrera             Self::I32(_) => true,
243835abbcdSSaúl Cabrera             _ => false,
244835abbcdSSaúl Cabrera         }
245835abbcdSSaúl Cabrera     }
2467c5c7e4bSSaúl Cabrera 
2477c5c7e4bSSaúl Cabrera     /// Check whether the value is an i64 constant.
2487c5c7e4bSSaúl Cabrera     pub fn is_i64_const(&self) -> bool {
2497c5c7e4bSSaúl Cabrera         match *self {
2507c5c7e4bSSaúl Cabrera             Self::I64(_) => true,
2517c5c7e4bSSaúl Cabrera             _ => false,
2527c5c7e4bSSaúl Cabrera         }
2537c5c7e4bSSaúl Cabrera     }
25414b39bc2SSaúl Cabrera 
25514b39bc2SSaúl Cabrera     /// Get the type of the value.
256496237c2SNick Fitzgerald     pub fn ty(&self) -> WasmValType {
25714b39bc2SSaúl Cabrera         match self {
258496237c2SNick Fitzgerald             Val::I32(_) => WasmValType::I32,
259496237c2SNick Fitzgerald             Val::I64(_) => WasmValType::I64,
260496237c2SNick Fitzgerald             Val::F32(_) => WasmValType::F32,
261496237c2SNick Fitzgerald             Val::F64(_) => WasmValType::F64,
262fa9a948dSJeffrey Charles             Val::V128(_) => WasmValType::V128,
26314b39bc2SSaúl Cabrera             Val::Reg(r) => r.ty,
26414b39bc2SSaúl Cabrera             Val::Memory(m) => m.ty,
26514b39bc2SSaúl Cabrera             Val::Local(l) => l.ty,
26614b39bc2SSaúl Cabrera         }
26714b39bc2SSaúl Cabrera     }
268835abbcdSSaúl Cabrera }
269835abbcdSSaúl Cabrera 
270835abbcdSSaúl Cabrera /// The shadow stack used for compilation.
271835abbcdSSaúl Cabrera #[derive(Default, Debug)]
272835abbcdSSaúl Cabrera pub(crate) struct Stack {
2731b5c4ae8SSaúl Cabrera     // NB: The 64 is chosen arbitrarily. We can adjust as we see fit.
2741b5c4ae8SSaúl Cabrera     inner: SmallVec<[Val; 64]>,
275835abbcdSSaúl Cabrera }
276835abbcdSSaúl Cabrera 
277835abbcdSSaúl Cabrera impl Stack {
278835abbcdSSaúl Cabrera     /// Allocate a new stack.
279835abbcdSSaúl Cabrera     pub fn new() -> Self {
280835abbcdSSaúl Cabrera         Self {
281835abbcdSSaúl Cabrera             inner: Default::default(),
282835abbcdSSaúl Cabrera         }
283835abbcdSSaúl Cabrera     }
284835abbcdSSaúl Cabrera 
285*b93e1bc0SSaúl Cabrera     /// Ensures that there are at least `n` elements in the value stack,
286*b93e1bc0SSaúl Cabrera     /// and returns the index calculated by: stack length minus `n`.
287*b93e1bc0SSaúl Cabrera     pub fn ensure_index_at(&self, n: usize) -> Result<usize> {
288*b93e1bc0SSaúl Cabrera         if self.len() >= n {
289*b93e1bc0SSaúl Cabrera             Ok(self.len() - n)
290*b93e1bc0SSaúl Cabrera         } else {
291*b93e1bc0SSaúl Cabrera             Err(anyhow!(CodeGenError::missing_values_in_stack()))
292*b93e1bc0SSaúl Cabrera         }
293*b93e1bc0SSaúl Cabrera     }
294*b93e1bc0SSaúl Cabrera 
295321294a5SJeffrey Charles     /// Returns true if the stack contains a local with the provided index
296321294a5SJeffrey Charles     /// except if the only time the local appears is the top element.
297321294a5SJeffrey Charles     pub fn contains_latent_local(&self, index: u32) -> bool {
298321294a5SJeffrey Charles         self.inner
299321294a5SJeffrey Charles             .iter()
300321294a5SJeffrey Charles             // Iterate top-to-bottom so we can skip the top element and stop
301321294a5SJeffrey Charles             // when we see a memory element.
302321294a5SJeffrey Charles             .rev()
303321294a5SJeffrey Charles             // The local is not latent if it's the top element because the top
304321294a5SJeffrey Charles             // element will be popped next which materializes the local.
305321294a5SJeffrey Charles             .skip(1)
306321294a5SJeffrey Charles             // Stop when we see a memory element because that marks where we
307321294a5SJeffrey Charles             // spilled up to so there will not be any locals past this point.
308321294a5SJeffrey Charles             .take_while(|v| !v.is_mem())
309321294a5SJeffrey Charles             .any(|v| v.is_local_at_index(index))
310321294a5SJeffrey Charles     }
311321294a5SJeffrey Charles 
312a109d2abSSaúl Cabrera     /// Extend the stack with the given elements.
313a109d2abSSaúl Cabrera     pub fn extend(&mut self, values: impl IntoIterator<Item = Val>) {
314a109d2abSSaúl Cabrera         self.inner.extend(values);
315a109d2abSSaúl Cabrera     }
316a109d2abSSaúl Cabrera 
317a109d2abSSaúl Cabrera     /// Inserts many values at the given index.
3181b5c4ae8SSaúl Cabrera     pub fn insert_many(&mut self, at: usize, values: &[Val]) {
319a109d2abSSaúl Cabrera         debug_assert!(at <= self.len());
3201b5c4ae8SSaúl Cabrera 
3211b5c4ae8SSaúl Cabrera         if at == self.len() {
3221b5c4ae8SSaúl Cabrera             self.inner.extend_from_slice(values);
323a109d2abSSaúl Cabrera         } else {
3241b5c4ae8SSaúl Cabrera             self.inner.insert_from_slice(at, values);
325a109d2abSSaúl Cabrera         }
32620c58362SSaúl Cabrera     }
32720c58362SSaúl Cabrera 
328af4d94c8SSaúl Cabrera     /// Get the length of the stack.
329af4d94c8SSaúl Cabrera     pub fn len(&self) -> usize {
330af4d94c8SSaúl Cabrera         self.inner.len()
331af4d94c8SSaúl Cabrera     }
332af4d94c8SSaúl Cabrera 
333835abbcdSSaúl Cabrera     /// Push a value to the stack.
334835abbcdSSaúl Cabrera     pub fn push(&mut self, val: Val) {
3357690c500STrevor Elliott         self.inner.push(val);
336835abbcdSSaúl Cabrera     }
337835abbcdSSaúl Cabrera 
338835abbcdSSaúl Cabrera     /// Peek into the top in the stack.
3397c5c7e4bSSaúl Cabrera     pub fn peek(&self) -> Option<&Val> {
3407690c500STrevor Elliott         self.inner.last()
341835abbcdSSaúl Cabrera     }
342835abbcdSSaúl Cabrera 
343af4d94c8SSaúl Cabrera     /// Returns an iterator referencing the last n items of the stack,
344af4d94c8SSaúl Cabrera     /// in bottom-most to top-most order.
345af4d94c8SSaúl Cabrera     pub fn peekn(&self, n: usize) -> impl Iterator<Item = &Val> + '_ {
346af4d94c8SSaúl Cabrera         let len = self.len();
347af4d94c8SSaúl Cabrera         assert!(n <= len);
348af4d94c8SSaúl Cabrera 
349af4d94c8SSaúl Cabrera         let partition = len - n;
3507690c500STrevor Elliott         self.inner[partition..].into_iter()
351af4d94c8SSaúl Cabrera     }
352af4d94c8SSaúl Cabrera 
353835abbcdSSaúl Cabrera     /// Pops the top element of the stack, if any.
354835abbcdSSaúl Cabrera     pub fn pop(&mut self) -> Option<Val> {
3557690c500STrevor Elliott         self.inner.pop()
356835abbcdSSaúl Cabrera     }
357835abbcdSSaúl Cabrera 
3587c5c7e4bSSaúl Cabrera     /// Pops the element at the top of the stack if it is an i32 const;
359835abbcdSSaúl Cabrera     /// returns `None` otherwise.
360835abbcdSSaúl Cabrera     pub fn pop_i32_const(&mut self) -> Option<i32> {
361835abbcdSSaúl Cabrera         match self.peek() {
362f0162a40SSaúl Cabrera             Some(v) => v.is_i32_const().then(|| self.pop().unwrap().unwrap_i32()),
363835abbcdSSaúl Cabrera             _ => None,
364835abbcdSSaúl Cabrera         }
365835abbcdSSaúl Cabrera     }
366835abbcdSSaúl Cabrera 
3677c5c7e4bSSaúl Cabrera     /// Pops the element at the top of the stack if it is an i64 const;
3687c5c7e4bSSaúl Cabrera     /// returns `None` otherwise.
3697c5c7e4bSSaúl Cabrera     pub fn pop_i64_const(&mut self) -> Option<i64> {
3707c5c7e4bSSaúl Cabrera         match self.peek() {
371f0162a40SSaúl Cabrera             Some(v) => v.is_i64_const().then(|| self.pop().unwrap().unwrap_i64()),
3727c5c7e4bSSaúl Cabrera             _ => None,
3737c5c7e4bSSaúl Cabrera         }
3747c5c7e4bSSaúl Cabrera     }
3757c5c7e4bSSaúl Cabrera 
376835abbcdSSaúl Cabrera     /// Pops the element at the top of the stack if it is a register;
377835abbcdSSaúl Cabrera     /// returns `None` otherwise.
37814b39bc2SSaúl Cabrera     pub fn pop_reg(&mut self) -> Option<TypedReg> {
379835abbcdSSaúl Cabrera         match self.peek() {
380f0162a40SSaúl Cabrera             Some(v) => v.is_reg().then(|| self.pop().unwrap().unwrap_reg()),
381835abbcdSSaúl Cabrera             _ => None,
382835abbcdSSaúl Cabrera         }
383835abbcdSSaúl Cabrera     }
384835abbcdSSaúl Cabrera 
385835abbcdSSaúl Cabrera     /// Pops the given register if it is at the top of the stack;
386835abbcdSSaúl Cabrera     /// returns `None` otherwise.
38714b39bc2SSaúl Cabrera     pub fn pop_named_reg(&mut self, reg: Reg) -> Option<TypedReg> {
388835abbcdSSaúl Cabrera         match self.peek() {
38914b39bc2SSaúl Cabrera             Some(v) => {
390f0162a40SSaúl Cabrera                 (v.is_reg() && v.unwrap_reg().reg == reg).then(|| self.pop().unwrap().unwrap_reg())
39114b39bc2SSaúl Cabrera             }
392835abbcdSSaúl Cabrera             _ => None,
393835abbcdSSaúl Cabrera         }
394835abbcdSSaúl Cabrera     }
395835abbcdSSaúl Cabrera 
396835abbcdSSaúl Cabrera     /// Get a mutable reference to the inner stack representation.
3971b5c4ae8SSaúl Cabrera     pub fn inner_mut(&mut self) -> &mut SmallVec<[Val; 64]> {
398835abbcdSSaúl Cabrera         &mut self.inner
399835abbcdSSaúl Cabrera     }
40050733725SSaúl Cabrera 
401446a7f5eSSaúl Cabrera     /// Get a reference to the inner stack representation.
4021b5c4ae8SSaúl Cabrera     pub fn inner(&self) -> &SmallVec<[Val; 64]> {
403446a7f5eSSaúl Cabrera         &self.inner
404446a7f5eSSaúl Cabrera     }
405446a7f5eSSaúl Cabrera 
40650733725SSaúl Cabrera     /// Calculates the size of, in bytes, of the top n [Memory] entries
40750733725SSaúl Cabrera     /// in the value stack.
40850733725SSaúl Cabrera     pub fn sizeof(&self, top: usize) -> u32 {
40950733725SSaúl Cabrera         self.peekn(top).fold(0, |acc, v| {
41050733725SSaúl Cabrera             if v.is_mem() {
41150733725SSaúl Cabrera                 acc + v.unwrap_mem().slot.size
41250733725SSaúl Cabrera             } else {
41350733725SSaúl Cabrera                 acc
41450733725SSaúl Cabrera             }
41550733725SSaúl Cabrera         })
41650733725SSaúl Cabrera     }
417835abbcdSSaúl Cabrera }
418835abbcdSSaúl Cabrera 
419835abbcdSSaúl Cabrera #[cfg(test)]
420835abbcdSSaúl Cabrera mod tests {
421835abbcdSSaúl Cabrera     use super::{Stack, Val};
422835abbcdSSaúl Cabrera     use crate::isa::reg::Reg;
423496237c2SNick Fitzgerald     use wasmtime_environ::WasmValType;
424835abbcdSSaúl Cabrera 
425835abbcdSSaúl Cabrera     #[test]
426835abbcdSSaúl Cabrera     fn test_pop_i32_const() {
427835abbcdSSaúl Cabrera         let mut stack = Stack::new();
428835abbcdSSaúl Cabrera         stack.push(Val::i32(33i32));
429835abbcdSSaúl Cabrera         assert_eq!(33, stack.pop_i32_const().unwrap());
430835abbcdSSaúl Cabrera 
431496237c2SNick Fitzgerald         stack.push(Val::local(10, WasmValType::I32));
432835abbcdSSaúl Cabrera         assert!(stack.pop_i32_const().is_none());
433835abbcdSSaúl Cabrera     }
434835abbcdSSaúl Cabrera 
435835abbcdSSaúl Cabrera     #[test]
436835abbcdSSaúl Cabrera     fn test_pop_reg() {
437835abbcdSSaúl Cabrera         let mut stack = Stack::new();
438835abbcdSSaúl Cabrera         let reg = Reg::int(2usize);
439496237c2SNick Fitzgerald         stack.push(Val::reg(reg, WasmValType::I32));
440835abbcdSSaúl Cabrera         stack.push(Val::i32(4));
441835abbcdSSaúl Cabrera 
442835abbcdSSaúl Cabrera         assert_eq!(None, stack.pop_reg());
443835abbcdSSaúl Cabrera         let _ = stack.pop().unwrap();
44414b39bc2SSaúl Cabrera         assert_eq!(reg, stack.pop_reg().unwrap().reg);
445835abbcdSSaúl Cabrera     }
446835abbcdSSaúl Cabrera 
447835abbcdSSaúl Cabrera     #[test]
448835abbcdSSaúl Cabrera     fn test_pop_named_reg() {
449835abbcdSSaúl Cabrera         let mut stack = Stack::new();
450835abbcdSSaúl Cabrera         let reg = Reg::int(2usize);
451496237c2SNick Fitzgerald         stack.push(Val::reg(reg, WasmValType::I32));
452496237c2SNick Fitzgerald         stack.push(Val::reg(Reg::int(4), WasmValType::I32));
453835abbcdSSaúl Cabrera 
454835abbcdSSaúl Cabrera         assert_eq!(None, stack.pop_named_reg(reg));
455835abbcdSSaúl Cabrera         let _ = stack.pop().unwrap();
45614b39bc2SSaúl Cabrera         assert_eq!(reg, stack.pop_named_reg(reg).unwrap().reg);
457835abbcdSSaúl Cabrera     }
458835abbcdSSaúl Cabrera }
459