1 use crate::isa::reg::Reg; 2 use std::collections::VecDeque; 3 4 /// Value definition to be used within the shadow stack. 5 #[derive(Debug, Eq, PartialEq)] 6 pub(crate) enum Val { 7 /// I32 Constant. 8 I32(i32), 9 /// I64 Constant. 10 I64(i64), 11 /// A register. 12 Reg(Reg), 13 /// A local slot. 14 Local(u32), 15 /// Offset to a memory location. 16 Memory(u32), 17 } 18 19 impl Val { 20 /// Create a new I32 constant value. 21 pub fn i32(v: i32) -> Self { 22 Self::I32(v) 23 } 24 25 /// Create a new I64 constant value. 26 pub fn i64(v: i64) -> Self { 27 Self::I64(v) 28 } 29 30 /// Create a new Reg value. 31 pub fn reg(r: Reg) -> Self { 32 Self::Reg(r) 33 } 34 35 /// Create a new Local value. 36 pub fn local(index: u32) -> Self { 37 Self::Local(index) 38 } 39 40 /// Check whether the value is a register. 41 pub fn is_reg(&self) -> bool { 42 match *self { 43 Self::Reg(_) => true, 44 _ => false, 45 } 46 } 47 48 /// Get the register representation of the value. 49 /// 50 /// # Panics 51 /// This method will panic if the value is not a register. 52 pub fn get_reg(&self) -> Reg { 53 match self { 54 Self::Reg(r) => *r, 55 v => panic!("expected value {:?} to be a register", v), 56 } 57 } 58 59 /// Get the integer representation of the value. 60 /// 61 /// # Panics 62 /// This method will panic if the value is not an i32. 63 pub fn get_i32(&self) -> i32 { 64 match self { 65 Self::I32(v) => *v, 66 v => panic!("expected value {:?} to be i32", v), 67 } 68 } 69 70 /// Get the integer representation of the value. 71 /// 72 /// # Panics 73 /// This method will panic if the value is not an i64. 74 pub fn get_i64(&self) -> i64 { 75 match self { 76 Self::I64(v) => *v, 77 v => panic!("expected value {:?} to be i64", v), 78 } 79 } 80 81 /// Check whether the value is an i32 constant. 82 pub fn is_i32_const(&self) -> bool { 83 match *self { 84 Self::I32(_) => true, 85 _ => false, 86 } 87 } 88 89 /// Check whether the value is an i64 constant. 90 pub fn is_i64_const(&self) -> bool { 91 match *self { 92 Self::I64(_) => true, 93 _ => false, 94 } 95 } 96 } 97 98 /// The shadow stack used for compilation. 99 #[derive(Default, Debug)] 100 pub(crate) struct Stack { 101 inner: VecDeque<Val>, 102 } 103 104 impl Stack { 105 /// Allocate a new stack. 106 pub fn new() -> Self { 107 Self { 108 inner: Default::default(), 109 } 110 } 111 112 /// Push a value to the stack. 113 pub fn push(&mut self, val: Val) { 114 self.inner.push_back(val); 115 } 116 117 /// Peek into the top in the stack. 118 pub fn peek(&self) -> Option<&Val> { 119 self.inner.back() 120 } 121 122 /// Pops the top element of the stack, if any. 123 pub fn pop(&mut self) -> Option<Val> { 124 self.inner.pop_back() 125 } 126 127 /// Pops the element at the top of the stack if it is an i32 const; 128 /// returns `None` otherwise. 129 pub fn pop_i32_const(&mut self) -> Option<i32> { 130 match self.peek() { 131 Some(v) => v.is_i32_const().then(|| self.pop().unwrap().get_i32()), 132 _ => None, 133 } 134 } 135 136 /// Pops the element at the top of the stack if it is an i64 const; 137 /// returns `None` otherwise. 138 pub fn pop_i64_const(&mut self) -> Option<i64> { 139 match self.peek() { 140 Some(v) => v.is_i64_const().then(|| self.pop().unwrap().get_i64()), 141 _ => None, 142 } 143 } 144 145 /// Pops the element at the top of the stack if it is a register; 146 /// returns `None` otherwise. 147 pub fn pop_reg(&mut self) -> Option<Reg> { 148 match self.peek() { 149 Some(v) => v.is_reg().then(|| self.pop().unwrap().get_reg()), 150 _ => None, 151 } 152 } 153 154 /// Pops the given register if it is at the top of the stack; 155 /// returns `None` otherwise. 156 pub fn pop_named_reg(&mut self, reg: Reg) -> Option<Reg> { 157 match self.peek() { 158 Some(v) => (v.is_reg() && v.get_reg() == reg).then(|| self.pop().unwrap().get_reg()), 159 _ => None, 160 } 161 } 162 163 /// Get a mutable reference to the inner stack representation. 164 pub fn inner_mut(&mut self) -> &mut VecDeque<Val> { 165 &mut self.inner 166 } 167 } 168 169 #[cfg(test)] 170 mod tests { 171 use super::{Stack, Val}; 172 use crate::isa::reg::Reg; 173 174 #[test] 175 fn test_pop_i32_const() { 176 let mut stack = Stack::new(); 177 stack.push(Val::i32(33i32)); 178 assert_eq!(33, stack.pop_i32_const().unwrap()); 179 180 stack.push(Val::local(10)); 181 assert!(stack.pop_i32_const().is_none()); 182 } 183 184 #[test] 185 fn test_pop_reg() { 186 let mut stack = Stack::new(); 187 let reg = Reg::int(2usize); 188 stack.push(Val::reg(reg)); 189 stack.push(Val::i32(4)); 190 191 assert_eq!(None, stack.pop_reg()); 192 let _ = stack.pop().unwrap(); 193 assert_eq!(reg, stack.pop_reg().unwrap()); 194 } 195 196 #[test] 197 fn test_pop_named_reg() { 198 let mut stack = Stack::new(); 199 let reg = Reg::int(2usize); 200 stack.push(Val::reg(reg)); 201 stack.push(Val::reg(Reg::int(4))); 202 203 assert_eq!(None, stack.pop_named_reg(reg)); 204 let _ = stack.pop().unwrap(); 205 assert_eq!(reg, stack.pop_named_reg(reg).unwrap()); 206 } 207 } 208