1use crate::{codegen::CodeGenError, isa::reg::Reg, masm::StackSlot};
2use anyhow::{anyhow, Result};
3use smallvec::SmallVec;
4use wasmparser::{Ieee32, Ieee64};
5use wasmtime_environ::WasmValType;
6
7#[derive(Debug, Eq, PartialEq, Copy, Clone)]
10pub struct TypedReg {
11 pub reg: Reg,
13 pub ty: WasmValType,
15}
16
17impl TypedReg {
18 pub fn new(ty: WasmValType, reg: Reg) -> Self {
20 Self { ty, reg }
21 }
22
23 pub fn i64(reg: Reg) -> Self {
25 Self {
26 ty: WasmValType::I64,
27 reg,
28 }
29 }
30
31 pub fn i32(reg: Reg) -> Self {
33 Self {
34 ty: WasmValType::I32,
35 reg,
36 }
37 }
38
39 pub fn f64(reg: Reg) -> Self {
41 Self {
42 ty: WasmValType::F64,
43 reg,
44 }
45 }
46
47 pub fn f32(reg: Reg) -> Self {
49 Self {
50 ty: WasmValType::F32,
51 reg,
52 }
53 }
54
55 pub fn v128(reg: Reg) -> Self {
57 Self {
58 ty: WasmValType::V128,
59 reg,
60 }
61 }
62}
63
64impl From<TypedReg> for Reg {
65 fn from(tr: TypedReg) -> Self {
66 tr.reg
67 }
68}
69
70#[derive(Debug, Eq, PartialEq, Copy, Clone)]
72pub struct Local {
73 pub index: u32,
75 pub ty: WasmValType,
77}
78
79#[derive(Debug, Eq, PartialEq, Copy, Clone)]
81pub struct Memory {
82 pub ty: WasmValType,
84 pub slot: StackSlot,
86}
87
88#[derive(Debug, Eq, PartialEq, Copy, Clone)]
90pub(crate) enum Val {
91 I32(i32),
93 I64(i64),
95 F32(Ieee32),
97 F64(Ieee64),
99 V128(i128),
101 Reg(TypedReg),
103 Local(Local),
105 Memory(Memory),
107}
108
109impl From<TypedReg> for Val {
110 fn from(tr: TypedReg) -> Self {
111 Val::Reg(tr)
112 }
113}
114
115impl From<Local> for Val {
116 fn from(local: Local) -> Self {
117 Val::Local(local)
118 }
119}
120
121impl From<Memory> for Val {
122 fn from(mem: Memory) -> Self {
123 Val::Memory(mem)
124 }
125}
126
127impl TryFrom<u32> for Val {
128 type Error = anyhow::Error;
129 fn try_from(value: u32) -> Result<Self, Self::Error> {
130 i32::try_from(value).map(Val::i32).map_err(Into::into)
131 }
132}
133
134impl Val {
135 pub fn i32(v: i32) -> Self {
137 Self::I32(v)
138 }
139
140 pub fn i64(v: i64) -> Self {
142 Self::I64(v)
143 }
144
145 pub fn f32(v: Ieee32) -> Self {
147 Self::F32(v)
148 }
149
150 pub fn f64(v: Ieee64) -> Self {
151 Self::F64(v)
152 }
153
154 pub fn v128(v: i128) -> Self {
156 Self::V128(v)
157 }
158
159 pub fn reg(reg: Reg, ty: WasmValType) -> Self {
161 Self::Reg(TypedReg { reg, ty })
162 }
163
164 pub fn local(index: u32, ty: WasmValType) -> Self {
166 Self::Local(Local { index, ty })
167 }
168
169 pub fn mem(ty: WasmValType, slot: StackSlot) -> Self {
171 Self::Memory(Memory { ty, slot })
172 }
173
174 pub fn is_reg(&self) -> bool {
176 match *self {
177 Self::Reg(_) => true,
178 _ => false,
179 }
180 }
181
182 pub fn is_mem(&self) -> bool {
184 match *self {
185 Self::Memory(_) => true,
186 _ => false,
187 }
188 }
189
190 pub fn is_const(&self) -> bool {
192 match *self {
193 Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => true,
194 _ => false,
195 }
196 }
197
198 pub fn is_local_at_index(&self, index: u32) -> bool {
200 match *self {
201 Self::Local(Local { index: i, .. }) if i == index => true,
202 _ => false,
203 }
204 }
205
206 pub fn unwrap_reg(&self) -> TypedReg {
211 match self {
212 Self::Reg(tr) => *tr,
213 v => panic!("expected value {v:?} to be a register"),
214 }
215 }
216
217 pub fn unwrap_i32(&self) -> i32 {
222 match self {
223 Self::I32(v) => *v,
224 v => panic!("expected value {v:?} to be i32"),
225 }
226 }
227
228 pub fn unwrap_i64(&self) -> i64 {
233 match self {
234 Self::I64(v) => *v,
235 v => panic!("expected value {v:?} to be i64"),
236 }
237 }
238
239 pub fn unwrap_f32(&self) -> Ieee32 {
244 match self {
245 Self::F32(v) => *v,
246 v => panic!("expected value {v:?} to be f32"),
247 }
248 }
249
250 pub fn unwrap_f64(&self) -> Ieee64 {
255 match self {
256 Self::F64(v) => *v,
257 v => panic!("expected value {v:?} to be f64"),
258 }
259 }
260
261 pub fn unwrap_mem(&self) -> Memory {
263 match self {
264 Self::Memory(m) => *m,
265 v => panic!("expected value {v:?} to be a Memory"),
266 }
267 }
268
269 pub fn is_i32_const(&self) -> bool {
271 match *self {
272 Self::I32(_) => true,
273 _ => false,
274 }
275 }
276
277 pub fn is_i64_const(&self) -> bool {
279 match *self {
280 Self::I64(_) => true,
281 _ => false,
282 }
283 }
284
285 pub fn is_f32_const(&self) -> bool {
287 match *self {
288 Self::F32(_) => true,
289 _ => false,
290 }
291 }
292
293 pub fn is_f64_const(&self) -> bool {
295 match *self {
296 Self::F64(_) => true,
297 _ => false,
298 }
299 }
300
301 pub fn ty(&self) -> WasmValType {
303 match self {
304 Val::I32(_) => WasmValType::I32,
305 Val::I64(_) => WasmValType::I64,
306 Val::F32(_) => WasmValType::F32,
307 Val::F64(_) => WasmValType::F64,
308 Val::V128(_) => WasmValType::V128,
309 Val::Reg(r) => r.ty,
310 Val::Memory(m) => m.ty,
311 Val::Local(l) => l.ty,
312 }
313 }
314}
315
316#[derive(Default, Debug)]
318pub(crate) struct Stack {
319 inner: SmallVec<[Val; 64]>,
321}
322
323impl Stack {
324 pub fn new() -> Self {
326 Self {
327 inner: Default::default(),
328 }
329 }
330
331 pub fn ensure_index_at(&self, n: usize) -> Result<usize> {
334 if self.len() >= n {
335 Ok(self.len() - n)
336 } else {
337 Err(anyhow!(CodeGenError::missing_values_in_stack()))
338 }
339 }
340
341 pub fn contains_latent_local(&self, index: u32) -> bool {
344 self.inner
345 .iter()
346 .rev()
349 .skip(1)
352 .take_while(|v| !v.is_mem())
355 .any(|v| v.is_local_at_index(index))
356 }
357
358 pub fn extend(&mut self, values: impl IntoIterator<Item = Val>) {
360 self.inner.extend(values);
361 }
362
363 pub fn insert_many(&mut self, at: usize, values: &[Val]) {
365 debug_assert!(at <= self.len());
366
367 if at == self.len() {
368 self.inner.extend_from_slice(values);
369 } else {
370 self.inner.insert_from_slice(at, values);
371 }
372 }
373
374 pub fn len(&self) -> usize {
376 self.inner.len()
377 }
378
379 pub fn push(&mut self, val: Val) {
381 self.inner.push(val);
382 }
383
384 pub fn peek(&self) -> Option<&Val> {
386 self.inner.last()
387 }
388
389 pub fn peekn(&self, n: usize) -> impl Iterator<Item = &Val> + '_ {
392 let len = self.len();
393 assert!(n <= len);
394
395 let partition = len - n;
396 self.inner[partition..].into_iter()
397 }
398
399 pub fn pop(&mut self) -> Option<Val> {
401 self.inner.pop()
402 }
403
404 pub fn pop_i32_const(&mut self) -> Option<i32> {
407 match self.peek() {
408 Some(v) => v.is_i32_const().then(|| self.pop().unwrap().unwrap_i32()),
409 _ => None,
410 }
411 }
412
413 pub fn pop_i64_const(&mut self) -> Option<i64> {
416 match self.peek() {
417 Some(v) => v.is_i64_const().then(|| self.pop().unwrap().unwrap_i64()),
418 _ => None,
419 }
420 }
421
422 pub fn pop_f32_const(&mut self) -> Option<Ieee32> {
425 match self.peek() {
426 Some(v) => v.is_f32_const().then(|| self.pop().unwrap().unwrap_f32()),
427 _ => None,
428 }
429 }
430
431 pub fn pop_f64_const(&mut self) -> Option<Ieee64> {
434 match self.peek() {
435 Some(v) => v.is_f64_const().then(|| self.pop().unwrap().unwrap_f64()),
436 _ => None,
437 }
438 }
439
440 pub fn pop_reg(&mut self) -> Option<TypedReg> {
443 match self.peek() {
444 Some(v) => v.is_reg().then(|| self.pop().unwrap().unwrap_reg()),
445 _ => None,
446 }
447 }
448
449 pub fn pop_named_reg(&mut self, reg: Reg) -> Option<TypedReg> {
452 match self.peek() {
453 Some(v) => {
454 (v.is_reg() && v.unwrap_reg().reg == reg).then(|| self.pop().unwrap().unwrap_reg())
455 }
456 _ => None,
457 }
458 }
459
460 pub fn inner_mut(&mut self) -> &mut SmallVec<[Val; 64]> {
462 &mut self.inner
463 }
464
465 pub fn inner(&self) -> &SmallVec<[Val; 64]> {
467 &self.inner
468 }
469
470 pub fn sizeof(&self, top: usize) -> u32 {
473 self.peekn(top).fold(0, |acc, v| {
474 if v.is_mem() {
475 acc + v.unwrap_mem().slot.size
476 } else {
477 acc
478 }
479 })
480 }
481}
482
483#[cfg(test)]
484mod tests {
485 use super::{Stack, Val};
486 use crate::isa::reg::Reg;
487 use wasmtime_environ::WasmValType;
488
489 #[test]
490 fn test_pop_i32_const() {
491 let mut stack = Stack::new();
492 stack.push(Val::i32(33i32));
493 assert_eq!(33, stack.pop_i32_const().unwrap());
494
495 stack.push(Val::local(10, WasmValType::I32));
496 assert!(stack.pop_i32_const().is_none());
497 }
498
499 #[test]
500 fn test_pop_reg() {
501 let mut stack = Stack::new();
502 let reg = Reg::int(2usize);
503 stack.push(Val::reg(reg, WasmValType::I32));
504 stack.push(Val::i32(4));
505
506 assert_eq!(None, stack.pop_reg());
507 let _ = stack.pop().unwrap();
508 assert_eq!(reg, stack.pop_reg().unwrap().reg);
509 }
510
511 #[test]
512 fn test_pop_named_reg() {
513 let mut stack = Stack::new();
514 let reg = Reg::int(2usize);
515 stack.push(Val::reg(reg, WasmValType::I32));
516 stack.push(Val::reg(Reg::int(4), WasmValType::I32));
517
518 assert_eq!(None, stack.pop_named_reg(reg));
519 let _ = stack.pop().unwrap();
520 assert_eq!(reg, stack.pop_named_reg(reg).unwrap().reg);
521 }
522}