diff --git a/lib/dynasm-backend/src/machine.rs b/lib/dynasm-backend/src/machine.rs index 2c3181ccc..0de50dee9 100644 --- a/lib/dynasm-backend/src/machine.rs +++ b/lib/dynasm-backend/src/machine.rs @@ -2,44 +2,38 @@ use crate::emitter_x64::*; use std::collections::HashSet; use wasmparser::Type as WpType; -pub struct Machine { +struct MachineStackOffset(usize); + +pub struct Machine { used_gprs: HashSet, used_xmms: HashSet, - control: Vec>, - stack_offset: usize, + stack_offset: MachineStackOffset } -#[derive(Debug)] -pub struct ControlFrame { - pub label: E::Label, - pub loop_like: bool, - pub returns: Vec, - pub stack_offset_snapshot: usize, -} +impl Machine { + pub fn new() -> Self { + Machine { + used_gprs: HashSet::new(), + used_xmms: HashSet::new(), + stack_offset: MachineStackOffset(0), + } + } -impl Machine { - /// Picks an unused general purpose register. + /// Picks an unused general purpose register for local/stack/argument use. /// /// This method does not mark the register as used. pub fn pick_gpr(&self) -> Option { use GPR::*; static REGS: &'static [GPR] = &[ - //RAX, RCX, RDX, RBX, - RSP, - RBP, RSI, RDI, R8, R9, R10, R11, - //R12, - //R13, - //R14, - //R15 ]; for r in REGS { if !self.used_gprs.contains(r) { @@ -49,15 +43,46 @@ impl Machine { None } + /// Picks an unused general purpose register for internal temporary use. + /// + /// This method does not mark the register as used. + pub fn pick_temp_gpr(&self) -> Option { + use GPR::*; + static REGS: &'static [GPR] = &[ + RAX, + R12, + R13, + R14, + R15 + ]; + for r in REGS { + if !self.used_gprs.contains(r) { + return Some(*r) + } + } + None + } + + /// Acquires a temporary GPR. + pub fn acquire_temp_gpr(&mut self) -> Option { + let gpr = self.pick_temp_gpr(); + if let Some(x) = gpr { + self.used_gprs.insert(x); + } + gpr + } + + /// Releases a temporary GPR. + pub fn release_temp_gpr(&mut self, gpr: GPR) { + assert_eq!(self.used_gprs.remove(&gpr), true); + } + /// Picks an unused XMM register. /// /// This method does not mark the register as used. pub fn pick_xmm(&self) -> Option { use XMM::*; static REGS: &'static [XMM] = &[ - //XMM0, - //XMM1, - //XMM2, XMM3, XMM4, XMM5, @@ -72,14 +97,47 @@ impl Machine { None } + /// Picks an unused XMM register for internal temporary use. + /// + /// This method does not mark the register as used. + pub fn pick_temp_xmm(&self) -> Option { + use XMM::*; + static REGS: &'static [XMM] = &[ + XMM0, + XMM1, + XMM2, + ]; + for r in REGS { + if !self.used_xmms.contains(r) { + return Some(*r) + } + } + None + } + + /// Acquires a temporary XMM register. + pub fn acquire_temp_xmm(&mut self) -> Option { + let xmm = self.pick_temp_xmm(); + if let Some(x) = xmm { + self.used_xmms.insert(x); + } + xmm + } + + /// Releases a temporary XMM register. + pub fn release_temp_xmm(&mut self, xmm: XMM) { + assert_eq!(self.used_xmms.remove(&xmm), true); + } + /// Acquires locations from the machine state. /// /// If the returned locations are used for stack value, `release_location` needs to be called on them; /// Otherwise, if the returned locations are used for locals, `release_location` does not need to be called on them. - pub fn acquire_locations( + pub fn acquire_locations( &mut self, assembler: &mut E, tys: &[WpType], + zeroed: bool, ) -> Vec { let mut ret = vec![]; let mut delta_stack_offset: usize = 0; @@ -100,9 +158,9 @@ impl Machine { let loc = if let Some(x) = loc { x } else { - self.stack_offset += 8; + self.stack_offset.0 += 8; delta_stack_offset += 8; - Location::Memory(GPR::RBP, -(self.stack_offset as i32)) + Location::Memory(GPR::RBP, -(self.stack_offset.0 as i32)) }; if let Location::GPR(x) = loc { self.used_gprs.insert(x); @@ -113,11 +171,16 @@ impl Machine { } assembler.emit_sub(Size::S64, Location::Imm32(delta_stack_offset as u32), Location::GPR(GPR::RSP)); + if zeroed { + for i in 0..tys.len() { + assembler.emit_mov(Size::S64, Location::Imm32(0), Location::Memory(GPR::RSP, (i * 8) as i32)); + } + } ret } /// Releases locations used for stack value. - pub fn release_locations( + pub fn release_locations( &mut self, assembler: &mut E, locs: &[Location] @@ -137,10 +200,10 @@ impl Machine { unreachable!(); } let offset = (-x) as usize; - if offset != self.stack_offset { + if offset != self.stack_offset.0 { unreachable!(); } - self.stack_offset -= 8; + self.stack_offset.0 -= 8; delta_stack_offset += 8; }, _ => {}