diff --git a/src/Target/registry.rs b/src/Target/registry.rs index 9d228c28..f69f1786 100644 --- a/src/Target/registry.rs +++ b/src/Target/registry.rs @@ -16,6 +16,12 @@ pub(crate) trait Reg: Display + ToString + Debug { fn from(&self, string: String) -> Box; } +impl PartialEq for dyn Reg { + fn eq(&self, other: &Self) -> bool { + other.sub64() == self.sub64() + } +} + #[derive(Debug)] pub(crate) struct BackendInfos { pub(crate) varsStorage: HashMap, @@ -24,6 +30,8 @@ pub(crate) struct BackendInfos { pub(crate) openUsableRegisters32: VecDeque>, pub(crate) openUsableRegisters16: VecDeque>, pub(crate) openUsableRegisters8: VecDeque>, + pub(crate) saveRegister: Vec>, + pub(crate) savedRegisters: Vec>, } impl BackendInfos { @@ -35,6 +43,9 @@ impl BackendInfos { openUsableRegisters32: VecDeque::new(), openUsableRegisters16: VecDeque::new(), openUsableRegisters8: VecDeque::new(), + + saveRegister: vec![], + savedRegisters: vec![], } } @@ -67,6 +78,14 @@ impl BackendInfos { } } + /// Adds the register back to the usable registers in the front + pub(crate) fn dropReg(&mut self, reg: Box) { + self.openUsableRegisters64.push_front(reg.from(reg.sub64())); + self.openUsableRegisters32.push_front(reg.from(reg.sub32())); + self.openUsableRegisters16.push_front(reg.from(reg.sub16())); + self.openUsableRegisters8.push_front(reg.from(reg.sub8())); + } + pub(crate) fn insertVar(&mut self, var: Var, store: VarStorage) { self.varsStorage.insert(var, store); } @@ -75,21 +94,42 @@ impl BackendInfos { self.openUsableRegisters32.pop_front(); // update all other members self.openUsableRegisters16.pop_front(); self.openUsableRegisters8.pop_front(); - self.openUsableRegisters64.pop_front() + let reg = self.openUsableRegisters64.pop_front()?; + + if self.savedRegisters.contains(®) && !self.saveRegister.contains(®) { + self.savedRegisters.push(reg.boxed()); + } + + + Some(reg) } pub(crate) fn getOpenReg32(&mut self) -> Option> { self.openUsableRegisters64.pop_front(); // update all other members self.openUsableRegisters16.pop_front(); self.openUsableRegisters8.pop_front(); - self.openUsableRegisters32.pop_front() + let reg = self.openUsableRegisters32.pop_front()?; + + if self.savedRegisters.contains(®) && !self.saveRegister.contains(®) { + self.savedRegisters.push(reg.boxed()); + } + + + Some(reg) } pub(crate) fn getOpenReg16(&mut self) -> Option> { self.openUsableRegisters64.pop_front(); // update all other members self.openUsableRegisters32.pop_front(); self.openUsableRegisters8.pop_front(); - self.openUsableRegisters16.pop_front() + let reg = self.openUsableRegisters16.pop_front()?; + + if self.savedRegisters.contains(®) && !self.saveRegister.contains(®) { + self.savedRegisters.push(reg.boxed()); + } + + + Some(reg) } #[allow(dead_code)] @@ -97,7 +137,14 @@ impl BackendInfos { self.openUsableRegisters64.pop_front(); // update all other members self.openUsableRegisters32.pop_front(); self.openUsableRegisters16.pop_front(); - self.openUsableRegisters8.pop_front() + let reg = self.openUsableRegisters8.pop_front()?; + + if self.savedRegisters.contains(®) && !self.saveRegister.contains(®) { + self.savedRegisters.push(reg.boxed()); + } + + + Some(reg) } pub(crate) fn getOpenRegBasedOnTy(&mut self, ty: TypeMetadata) -> Option> { diff --git a/src/Target/x64/ir.rs b/src/Target/x64/ir.rs index f72ecdba..623f5c25 100644 --- a/src/Target/x64/ir.rs +++ b/src/Target/x64/ir.rs @@ -1,3 +1,5 @@ +use std::collections::VecDeque; + use crate::{prelude::{Block, Function, Type, TypeMetadata, Var}, Target::{registry::{Reg, VarStorage}, TargetBackendDescr}, IR::ir::*}; use crate::Target::CallConv; @@ -155,12 +157,16 @@ pub(crate) fn CompileAddTyTy(add: &Add, registry: &mut TargetBa } pub(crate) fn CompileRetType(ret: &Return, registry: &mut TargetBackendDescr) -> Vec { - vec![format!("mov {}, {}", match ret.inner1 { - Type::u16(_) | Type::i16(_) => registry.call.ret16(), - Type::u32(_) | Type::i32(_) => registry.call.ret32(), - Type::u64(_) | Type::i64(_) => registry.call.ret64(), - Type::Void => todo!(), - }, ret.inner1.val())] + if ret.inner1 != Type::Void { + vec![format!("mov {}, {}", match ret.inner1 { + Type::u16(_) | Type::i16(_) => registry.call.ret16(), + Type::u32(_) | Type::i32(_) => registry.call.ret32(), + Type::u64(_) | Type::i64(_) => registry.call.ret64(), + Type::Void => todo!(), + }, ret.inner1.val())] + } else { + vec![] + } } @@ -186,6 +192,40 @@ pub(crate) fn CompileRetVar(ret: &Return, registry: &mut TargetBackendDescr else { unreachable!() } })] } + +pub(crate) fn x64BuildProlog(_: &Block, registry: &mut TargetBackendDescr) -> Vec { + let mut res = vec![]; + + if registry.backend.currStackOffsetForLocalVars != 0 { + res.push(format!("push rbp")); + res.push(format!("mov rbp, rsp")); + res.push(format!("sub rsp, 16")); + } + + for backuped in ®istry.backend.saveRegister { + res.push( format!("push {}", backuped) ) + } + + res +} + +pub(crate) fn x64BuildEpilog(_: &Block, registry: &mut TargetBackendDescr) -> Vec { + let mut res = vec![]; + + for backuped in ®istry.backend.saveRegister { + res.push( format!("pop {}", backuped) ) + } + + if registry.backend.currStackOffsetForLocalVars != 0 { + res.push(format!("add rsp, 16")); + res.push(format!("pop rbp")); + } + + res.push(format!("ret")); + + res +} + impl Block { /// Builds the block to x86 assembly intel syntax pub fn buildAsmX86<'a>(&'a self, func: &Function, call: &CallConv, registry: &mut TargetBackendDescr<'a>) -> Vec { @@ -195,10 +235,11 @@ impl Block { let mut reg_vars = 0; let mut stack_off = 0; + let mut var_index = 0; - for (index, meta) in &func.ty.args { + for (_, meta) in &func.ty.args { let mut var = Var(&mut self.clone(), meta.to_owned()); - var.name = format!("%{}", index); + var.name = format!("%{}", var_index); info.insertVar(var, { if reg_vars >= call.regArgs() { @@ -221,19 +262,36 @@ impl Block { }) } }); + + var_index += 1; + } + + if reg_vars < call.regArgs() { + info.dropReg(call.args64()[reg_vars - 1].boxed()); } - let mut out = vec![]; + let mut out = VecDeque::new(); for node in &self.nodes { let compiled = node.compile(registry); - out.extend_from_slice(&compiled); + out.extend(compiled); } + + registry.block = None; - out + let mut prolog = x64BuildProlog(&self, registry); + prolog.reverse(); // cuz: push_front + + for epAsm in prolog { + out.push_front(epAsm); + } + + out.extend(x64BuildEpilog(&self, registry)); + + Vec::from(out) } pub(crate) fn isVarUsedAfterNode(&self, startingNode: &Box, var: &Var) -> bool { diff --git a/src/Target/x64/mod.rs b/src/Target/x64/mod.rs index 9ad150b2..411339d3 100644 --- a/src/Target/x64/mod.rs +++ b/src/Target/x64/mod.rs @@ -19,6 +19,10 @@ pub(crate) mod call; pub fn initializeX64Target<'a>(call_conv: CallConv) -> TargetBackendDescr<'a> { let mut target = TargetBackendDescr::new(); + target.backend.savedRegisters = vec![ + x64Reg::R10.boxed(), x64Reg::R11.boxed(), x64Reg::R12.boxed(), x64Reg::R13.boxed(), x64Reg::R14.boxed(), x64Reg::R15.boxed(), + ]; + match call_conv { CallConv::WindowsFastCall => { target.backend.openUsableRegisters64 = VecDeque::from(