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