lamina_codegen/wasm/
regalloc.rs1use std::collections::HashMap;
2
3use crate::regalloc::{
4 LocalRegisterAllocator as MirRegisterAllocator, PhysRegConvertible, PhysRegHandle,
5};
6use lamina_mir::{Register, RegisterClass, VirtualReg};
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
10pub struct WasmStackSlot(pub u32);
11
12impl PhysRegConvertible for WasmStackSlot {
13 fn into_handle(self) -> PhysRegHandle {
14 PhysRegHandle::Named(format!("wasm_slot_{}", self.0).leak())
15 }
16
17 fn from_handle(handle: PhysRegHandle) -> Option<Self> {
18 match handle {
19 PhysRegHandle::Named(name) => name
20 .strip_prefix("wasm_slot_")
21 .and_then(|n| n.parse().ok())
22 .map(WasmStackSlot),
23 }
24 }
25}
26
27pub struct WasmRegAlloc {
29 vreg_to_stack: HashMap<VirtualReg, u32>,
30 next_stack_slot: u32,
31}
32
33impl Default for WasmRegAlloc {
34 fn default() -> Self {
35 Self::new()
36 }
37}
38
39impl WasmRegAlloc {
40 pub fn new() -> Self {
41 Self {
42 vreg_to_stack: HashMap::new(),
43 next_stack_slot: 0,
44 }
45 }
46
47 pub fn get_stack_position(&self, vreg: &VirtualReg) -> Option<u32> {
48 self.vreg_to_stack.get(vreg).copied()
49 }
50
51 pub fn allocate_stack(&mut self, vreg: VirtualReg) -> u32 {
52 if let Some(pos) = self.vreg_to_stack.get(&vreg) {
53 *pos
54 } else {
55 let pos = self.next_stack_slot;
56 self.vreg_to_stack.insert(vreg, pos);
57 self.next_stack_slot += 1;
58 pos
59 }
60 }
61}
62
63impl MirRegisterAllocator for WasmRegAlloc {
64 type PhysReg = WasmStackSlot;
65
66 fn alloc_scratch(&mut self) -> Option<Self::PhysReg> {
67 let pos = self.next_stack_slot;
68 self.next_stack_slot += 1;
69 Some(WasmStackSlot(pos))
70 }
71
72 fn free_scratch(&mut self, _phys: Self::PhysReg) {}
73
74 fn get_mapping(&self, vreg: &VirtualReg) -> Option<Self::PhysReg> {
75 self.vreg_to_stack.get(vreg).copied().map(WasmStackSlot)
76 }
77
78 fn ensure_mapping(&mut self, vreg: VirtualReg) -> Option<Self::PhysReg> {
79 if vreg.class != RegisterClass::Gpr {
80 return None;
81 }
82 Some(WasmStackSlot(self.allocate_stack(vreg)))
83 }
84
85 fn mapped_for_register(&self, reg: &Register) -> Option<Self::PhysReg> {
86 match reg {
87 Register::Virtual(v) => self.vreg_to_stack.get(v).copied().map(WasmStackSlot),
88 Register::Physical(_) => None,
89 }
90 }
91
92 fn occupy(&mut self, _phys: Self::PhysReg) {}
93
94 fn release(&mut self, _phys: Self::PhysReg) {}
95
96 fn is_occupied(&self, _phys: Self::PhysReg) -> bool {
97 false
98 }
99}