1use crate::{Result, codegen::CodeGenError, format_err, isa::reg::Reg, masm::StackSlot};
2use smallvec::SmallVec;
3use wasmparser::{Ieee32, Ieee64};
4use wasmtime_environ::WasmValType;
5
6#[derive(Debug, Eq, PartialEq, Copy, Clone)]
9pub struct TypedReg {
10 pub reg: Reg,
12 pub ty: WasmValType,
14}
15
16impl TypedReg {
17 pub fn new(ty: WasmValType, reg: Reg) -> Self {
19 Self { ty, reg }
20 }
21
22 pub fn i64(reg: Reg) -> Self {
24 Self {
25 ty: WasmValType::I64,
26 reg,
27 }
28 }
29
30 pub fn i32(reg: Reg) -> Self {
32 Self {
33 ty: WasmValType::I32,
34 reg,
35 }
36 }
37
38 pub fn f64(reg: Reg) -> Self {
40 Self {
41 ty: WasmValType::F64,
42 reg,
43 }
44 }
45
46 pub fn f32(reg: Reg) -> Self {
48 Self {
49 ty: WasmValType::F32,
50 reg,
51 }
52 }
53
54 pub fn v128(reg: Reg) -> Self {
56 Self {
57 ty: WasmValType::V128,
58 reg,
59 }
60 }
61}
62
63impl From<TypedReg> for Reg {
64 fn from(tr: TypedReg) -> Self {
65 tr.reg
66 }
67}
68
69#[derive(Debug, Eq, PartialEq, Copy, Clone)]
71pub struct Local {
72 pub index: u32,
74 pub ty: WasmValType,
76}
77
78#[derive(Debug, Eq, PartialEq, Copy, Clone)]
80pub struct Memory {
81 pub ty: WasmValType,
83 pub slot: StackSlot,
85}
86
87#[derive(Debug, Eq, PartialEq, Copy, Clone)]
89pub(crate) enum Val {
90 I32(i32),
92 I64(i64),
94 F32(Ieee32),
96 F64(Ieee64),
98 V128(i128),
100 Reg(TypedReg),
102 Local(Local),
104 Memory(Memory),
106}
107
108impl From<TypedReg> for Val {
109 fn from(tr: TypedReg) -> Self {
110 Val::Reg(tr)
111 }
112}
113
114impl From<Local> for Val {
115 fn from(local: Local) -> Self {
116 Val::Local(local)
117 }
118}
119
120impl From<Memory> for Val {
121 fn from(mem: Memory) -> Self {
122 Val::Memory(mem)
123 }
124}
125
126impl TryFrom<u32> for Val {
127 type Error = crate::Error;
128 fn try_from(value: u32) -> Result<Self, Self::Error> {
129 i32::try_from(value).map(Val::i32).map_err(Into::into)
130 }
131}
132
133impl Val {
134 pub fn i32(v: i32) -> Self {
136 Self::I32(v)
137 }
138
139 pub fn i64(v: i64) -> Self {
141 Self::I64(v)
142 }
143
144 pub fn f32(v: Ieee32) -> Self {
146 Self::F32(v)
147 }
148
149 pub fn f64(v: Ieee64) -> Self {
150 Self::F64(v)
151 }
152
153 pub fn v128(v: i128) -> Self {
155 Self::V128(v)
156 }
157
158 pub fn reg(reg: Reg, ty: WasmValType) -> Self {
160 Self::Reg(TypedReg { reg, ty })
161 }
162
163 pub fn local(index: u32, ty: WasmValType) -> Self {
165 Self::Local(Local { index, ty })
166 }
167
168 pub fn mem(ty: WasmValType, slot: StackSlot) -> Self {
170 Self::Memory(Memory { ty, slot })
171 }
172
173 pub fn is_reg(&self) -> bool {
175 match *self {
176 Self::Reg(_) => true,
177 _ => false,
178 }
179 }
180
181 pub fn is_mem(&self) -> bool {
183 match *self {
184 Self::Memory(_) => true,
185 _ => false,
186 }
187 }
188
189 pub fn is_const(&self) -> bool {
191 match *self {
192 Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => true,
193 _ => false,
194 }
195 }
196
197 pub fn is_local_at_index(&self, index: u32) -> bool {
199 match *self {
200 Self::Local(Local { index: i, .. }) if i == index => true,
201 _ => false,
202 }
203 }
204
205 pub fn unwrap_reg(&self) -> TypedReg {
210 match self {
211 Self::Reg(tr) => *tr,
212 v => panic!("expected value {v:?} to be a register"),
213 }
214 }
215
216 pub fn unwrap_i32(&self) -> i32 {
221 match self {
222 Self::I32(v) => *v,
223 v => panic!("expected value {v:?} to be i32"),
224 }
225 }
226
227 pub fn unwrap_i64(&self) -> i64 {
232 match self {
233 Self::I64(v) => *v,
234 v => panic!("expected value {v:?} to be i64"),
235 }
236 }
237
238 pub fn unwrap_f32(&self) -> Ieee32 {
243 match self {
244 Self::F32(v) => *v,
245 v => panic!("expected value {v:?} to be f32"),
246 }
247 }
248
249 pub fn unwrap_f64(&self) -> Ieee64 {
254 match self {
255 Self::F64(v) => *v,
256 v => panic!("expected value {v:?} to be f64"),
257 }
258 }
259
260 pub fn unwrap_mem(&self) -> Memory {
262 match self {
263 Self::Memory(m) => *m,
264 v => panic!("expected value {v:?} to be a Memory"),
265 }
266 }
267
268 pub fn is_i32_const(&self) -> bool {
270 match *self {
271 Self::I32(_) => true,
272 _ => false,
273 }
274 }
275
276 pub fn is_i64_const(&self) -> bool {
278 match *self {
279 Self::I64(_) => true,
280 _ => false,
281 }
282 }
283
284 pub fn is_f32_const(&self) -> bool {
286 match *self {
287 Self::F32(_) => true,
288 _ => false,
289 }
290 }
291
292 pub fn is_f64_const(&self) -> bool {
294 match *self {
295 Self::F64(_) => true,
296 _ => false,
297 }
298 }
299
300 pub fn ty(&self) -> WasmValType {
302 match self {
303 Val::I32(_) => WasmValType::I32,
304 Val::I64(_) => WasmValType::I64,
305 Val::F32(_) => WasmValType::F32,
306 Val::F64(_) => WasmValType::F64,
307 Val::V128(_) => WasmValType::V128,
308 Val::Reg(r) => r.ty,
309 Val::Memory(m) => m.ty,
310 Val::Local(l) => l.ty,
311 }
312 }
313}
314
315#[derive(Default, Debug)]
317pub(crate) struct Stack {
318 inner: SmallVec<[Val; 64]>,
320}
321
322impl Stack {
323 pub fn new() -> Self {
325 Self {
326 inner: Default::default(),
327 }
328 }
329
330 pub fn ensure_index_at(&self, n: usize) -> Result<usize> {
333 if self.len() >= n {
334 Ok(self.len() - n)
335 } else {
336 Err(format_err!(CodeGenError::missing_values_in_stack()))
337 }
338 }
339
340 pub fn contains_latent_local(&self, index: u32) -> bool {
343 self.inner
344 .iter()
345 .rev()
348 .skip(1)
351 .take_while(|v| !v.is_mem())
354 .any(|v| v.is_local_at_index(index))
355 }
356
357 pub fn extend(&mut self, values: impl IntoIterator<Item = Val>) {
359 self.inner.extend(values);
360 }
361
362 pub fn insert_many(&mut self, at: usize, values: &[Val]) {
364 debug_assert!(at <= self.len());
365
366 if at == self.len() {
367 self.inner.extend_from_slice(values);
368 } else {
369 self.inner.insert_from_slice(at, values);
370 }
371 }
372
373 pub fn len(&self) -> usize {
375 self.inner.len()
376 }
377
378 pub fn push(&mut self, val: Val) {
380 self.inner.push(val);
381 }
382
383 pub fn peek(&self) -> Option<&Val> {
385 self.inner.last()
386 }
387
388 pub fn peekn(&self, n: usize) -> impl Iterator<Item = &Val> + '_ {
391 let len = self.len();
392 assert!(n <= len);
393
394 let partition = len - n;
395 self.inner[partition..].into_iter()
396 }
397
398 pub fn pop(&mut self) -> Option<Val> {
400 self.inner.pop()
401 }
402
403 pub fn pop_i32_const(&mut self) -> Option<i32> {
406 match self.peek() {
407 Some(v) => v.is_i32_const().then(|| self.pop().unwrap().unwrap_i32()),
408 _ => None,
409 }
410 }
411
412 pub fn pop_i64_const(&mut self) -> Option<i64> {
415 match self.peek() {
416 Some(v) => v.is_i64_const().then(|| self.pop().unwrap().unwrap_i64()),
417 _ => None,
418 }
419 }
420
421 pub fn pop_f32_const(&mut self) -> Option<Ieee32> {
424 match self.peek() {
425 Some(v) => v.is_f32_const().then(|| self.pop().unwrap().unwrap_f32()),
426 _ => None,
427 }
428 }
429
430 pub fn pop_f64_const(&mut self) -> Option<Ieee64> {
433 match self.peek() {
434 Some(v) => v.is_f64_const().then(|| self.pop().unwrap().unwrap_f64()),
435 _ => None,
436 }
437 }
438
439 pub fn pop_reg(&mut self) -> Option<TypedReg> {
442 match self.peek() {
443 Some(v) => v.is_reg().then(|| self.pop().unwrap().unwrap_reg()),
444 _ => None,
445 }
446 }
447
448 pub fn pop_named_reg(&mut self, reg: Reg) -> Option<TypedReg> {
451 match self.peek() {
452 Some(v) => {
453 (v.is_reg() && v.unwrap_reg().reg == reg).then(|| self.pop().unwrap().unwrap_reg())
454 }
455 _ => None,
456 }
457 }
458
459 pub fn inner_mut(&mut self) -> &mut SmallVec<[Val; 64]> {
461 &mut self.inner
462 }
463
464 pub fn inner(&self) -> &SmallVec<[Val; 64]> {
466 &self.inner
467 }
468
469 pub fn sizeof(&self, top: usize) -> u32 {
472 self.peekn(top).fold(0, |acc, v| {
473 if v.is_mem() {
474 acc + v.unwrap_mem().slot.size
475 } else {
476 acc
477 }
478 })
479 }
480}
481
482#[cfg(test)]
483mod tests {
484 use super::{Stack, Val};
485 use crate::isa::reg::Reg;
486 use wasmtime_environ::WasmValType;
487
488 #[test]
489 fn test_pop_i32_const() {
490 let mut stack = Stack::new();
491 stack.push(Val::i32(33i32));
492 assert_eq!(33, stack.pop_i32_const().unwrap());
493
494 stack.push(Val::local(10, WasmValType::I32));
495 assert!(stack.pop_i32_const().is_none());
496 }
497
498 #[test]
499 fn test_pop_reg() {
500 let mut stack = Stack::new();
501 let reg = Reg::int(2usize);
502 stack.push(Val::reg(reg, WasmValType::I32));
503 stack.push(Val::i32(4));
504
505 assert_eq!(None, stack.pop_reg());
506 let _ = stack.pop().unwrap();
507 assert_eq!(reg, stack.pop_reg().unwrap().reg);
508 }
509
510 #[test]
511 fn test_pop_named_reg() {
512 let mut stack = Stack::new();
513 let reg = Reg::int(2usize);
514 stack.push(Val::reg(reg, WasmValType::I32));
515 stack.push(Val::reg(Reg::int(4), WasmValType::I32));
516
517 assert_eq!(None, stack.pop_named_reg(reg));
518 let _ = stack.pop().unwrap();
519 assert_eq!(reg, stack.pop_named_reg(reg).unwrap().reg);
520 }
521}