From e6caf513ae103fc3c3d76094fb12676d1e414b7b Mon Sep 17 00:00:00 2001 From: TheCPP Date: Tue, 27 Aug 2024 11:19:18 +0200 Subject: [PATCH] [FIX] trying fix for #8 --- src/Target/target_descr.rs | 4 ++ src/Target/x64/asm/instr.rs | 24 ++++---- src/Target/x64/asm/optimizer.rs | 17 +++++- src/Target/x64/asm/parser.rs | 2 +- src/Target/x64/compilation/call.rs | 90 ++++++++++++++++------------ src/Target/x64/compilation/mod.rs | 12 ++-- src/Target/x64/compilation/prolog.rs | 5 ++ src/Target/x64/mod.rs | 8 ++- 8 files changed, 104 insertions(+), 58 deletions(-) diff --git a/src/Target/target_descr.rs b/src/Target/target_descr.rs index 5b88b318..ebcb8744 100644 --- a/src/Target/target_descr.rs +++ b/src/Target/target_descr.rs @@ -14,8 +14,11 @@ pub(crate) struct BackendInfos { pub(crate) openUsableRegisters16: VecDeque>, pub(crate) openUsableRegisters8: VecDeque>, pub(crate) tmpReg: Box, + pub(crate) saveRegister: Vec>, pub(crate) savedRegisters: Vec>, + pub(crate) mutable: Vec>, + pub(crate) stackSafe: bool, pub(crate) shadow: i64, @@ -30,6 +33,7 @@ impl BackendInfos { openUsableRegisters32: VecDeque::new(), openUsableRegisters16: VecDeque::new(), openUsableRegisters8: VecDeque::new(), + mutable: vec![], tmpReg: x64Reg::Rax.boxed(), diff --git a/src/Target/x64/asm/instr.rs b/src/Target/x64/asm/instr.rs index af205820..7f601c2b 100644 --- a/src/Target/x64/asm/instr.rs +++ b/src/Target/x64/asm/instr.rs @@ -133,10 +133,8 @@ impl Instr { } else {rex = Some(mem.rex())} } - op.extend_from_slice(&ModRm::regM( - *op0, - mem.clone() - )); + op.push(mem.encode(None).0 | op0.enc() << 3 | 0b100); + op.extend_from_slice(&mem.encode(None).1); } else { todo!() } @@ -322,7 +320,7 @@ impl Instr { (vec![], None) } } - Mnemonic::Debug => (vec![], None), + Mnemonic::Debug | Mnemonic::StartOptimization | Mnemonic::EndOptimization => (vec![], None), }) } @@ -402,7 +400,7 @@ impl Instr { } } } - Mnemonic::Link | Mnemonic::Debug => {}, + Mnemonic::Link | Mnemonic::Debug | Mnemonic::StartOptimization | Mnemonic::EndOptimization => {}, Mnemonic::Endbr64 => { if self.op1.is_some() || self.op2.is_some() { Err(InstrEncodingError::InvalidVariant(self.clone(), "endbr64 can't have operands".to_string()))? @@ -562,6 +560,10 @@ pub enum Mnemonic { Link, /// for debugging pourpusis Debug, + /// start optimization again + StartOptimization, + /// stop optimization + EndOptimization, } impl FromStr for Mnemonic { @@ -608,6 +610,8 @@ impl Display for Mnemonic { Mnemonic::Jmp => "jmp", Mnemonic::Endbr64 => "endbr64", Mnemonic::Link => "", + Mnemonic::StartOptimization => "", + Mnemonic::EndOptimization => "", Mnemonic::Debug => "#", }) } @@ -687,11 +691,11 @@ impl MemOp { modrm |= 0b00 << 6; } else if self.displ >= -128 && self.displ <= 127 { modrm |= 0b01 << 6; - scale = 1; + scale = 0b01 << 6; displ.push(self.displ as u8); } else { modrm |= 0b10 << 6; - scale = 4; + scale = 0b10; displ.extend_from_slice(&(self.displ as i32).to_le_bytes()); } @@ -823,7 +827,7 @@ impl Add for x64Reg { MemOp { base: Some(self.boxed()), index: None, - scale: 2, + scale: 1, displ: rhs as isize, rip: false, } @@ -851,7 +855,7 @@ impl Sub for x64Reg { MemOp { base: Some(self.boxed()), index: None, - scale: 2, + scale: 1, displ: -(rhs as isize), rip: false, } diff --git a/src/Target/x64/asm/optimizer.rs b/src/Target/x64/asm/optimizer.rs index e2a548fc..57608b40 100644 --- a/src/Target/x64/asm/optimizer.rs +++ b/src/Target/x64/asm/optimizer.rs @@ -12,10 +12,23 @@ impl Optimize for Vec { fn optimize(&mut self) -> Vec { let mut out: Vec = vec![]; + let mut optimize = false; + for instr in self.iter() { let mut optimized = false; - + if instr.mnemonic == Mnemonic::StartOptimization { + optimize = true; + } + + if instr.mnemonic == Mnemonic::EndOptimization { + optimize = false; + } + + if !optimize { + out.push(instr.to_owned()); + continue; + } let last = out.last().cloned(); if let Some(last) = &last { @@ -55,7 +68,7 @@ impl Optimize for Vec { } if instr.mnemonic == Mnemonic::Ret && last.mnemonic == Mnemonic::Call { out.pop(); - out.push(Instr::with1(Mnemonic::Jmp, instr.op1.clone().expect("call needs to have only one op"))); + out.push(Instr::with1(Mnemonic::Jmp, instr.op1.clone().expect("call needs to have one op"))); optimized = true; } if instr.mnemonic == Mnemonic::Ret { diff --git a/src/Target/x64/asm/parser.rs b/src/Target/x64/asm/parser.rs index bbb6c172..c3c971ce 100644 --- a/src/Target/x64/asm/parser.rs +++ b/src/Target/x64/asm/parser.rs @@ -128,7 +128,7 @@ impl x64Parser { Err(ParsingError::UnexpectedToken(token.clone()))? } else { todo!() } - if let Some(Token::L_Bracket) = self.tokens.front() {} else { + if let Some(Token::R_Bracket) = self.tokens.front() {} else { let mut sub = false; if let Some(Token::Sub) = self.tokens.front() { sub = true; self.tokens.pop_front(); } if let Some(Token::Add) = self.tokens.front() { sub = false; self.tokens.pop_front(); } diff --git a/src/Target/x64/compilation/call.rs b/src/Target/x64/compilation/call.rs index 51ea3eaf..716ff7b1 100644 --- a/src/Target/x64/compilation/call.rs +++ b/src/Target/x64/compilation/call.rs @@ -1,44 +1,62 @@ +use std::collections::HashMap; + use super::*; pub(crate) fn CompileCall(call: &Call, Var>, registry: &mut TargetBackendDescr) -> Vec { let boxed: Box = Box::new(call.clone()); let block = registry.block.unwrap(); - let mut asm = vec![]; - - let mut to_pop = vec![]; - - for reg in vec![x64Reg::Rcx, x64Reg::Rdx, x64Reg::Rsi, x64Reg::Rdi, x64Reg::Rsi] { // save mutable registers - if !registry.backend.openUsableRegisters64.contains(®.boxed()) { - let var = registry.backend.getVarByReg(reg.boxed()).cloned(); - - if let Some(var) = var { - if block.isVarUsedAfterNode(&boxed, &var) { - asm.push(Instr::with1(Mnemonic::Push, Operand::Reg(reg.boxed()))); - to_pop.push(reg); - } + let mut asm = vec![ + Instr::with0(Mnemonic::EndOptimization), + ]; + + registry.backend.stackSafe = true; + + let mut saved_var_memory_locations = HashMap::new(); + + let mut offset = registry.backend.currStackOffsetForLocalVars + 8; + + for reg in ®istry.backend.mutable { + if !registry.backend.openUsableRegisters64.contains(reg) { // is a variable in the reg + let var = registry.backend.getVarByReg(reg.clone()); + + if let Some(var) = var { // get the var + asm.push( Instr::with2(Mnemonic::Mov, Operand::Mem(x64Reg::Rbp - (offset as u32)), Operand::Reg(reg.clone())) ); + saved_var_memory_locations.insert(var.clone(), offset); + offset += 8; } } } - let func = &call.inner1; - let mut reg_args = 0; for arg in &call.inner2 { - let loc = registry.backend.varsStorage.get_key_value(arg).expect("expected valid variable as arg input"); + let loc = if let Some((x, y)) = registry.backend.varsStorage.get_key_value(arg) { + (x, y) + } else { + panic!("unknown variable {}", arg); + }; match loc.1 { VarStorage::Register(reg) => { if reg_args < registry.call.regArgs() { - match arg.ty { + + let args = match arg.ty { TypeMetadata::i64 | TypeMetadata::u64 | TypeMetadata::ptr => - asm.push( Instr::with2(Mnemonic::Mov, Operand::Reg(registry.call.args64()[reg_args].boxed()), Operand::Reg(reg.clone()))), + registry.call.args64(), TypeMetadata::i32 | TypeMetadata::u32 => - asm.push( Instr::with2(Mnemonic::Mov, Operand::Reg(registry.call.args32()[reg_args].boxed()), Operand::Reg(reg.clone()))), + registry.call.args32(), TypeMetadata::i16 | TypeMetadata::u16 => - asm.push( Instr::with2(Mnemonic::Mov, Operand::Reg(registry.call.args16()[reg_args].boxed()), Operand::Reg(reg.clone()))), - TypeMetadata::Void => {}, + registry.call.args16(), + TypeMetadata::Void => vec![], + }; + + if args.contains(reg.as_any().downcast_ref::().unwrap()) { + if let Some(offset) = saved_var_memory_locations.get(arg) { + asm.push( Instr::with2(Mnemonic::Mov, Operand::Reg(args[reg_args].boxed()), Operand::Mem(x64Reg::Rbp - (*offset as u32)))); + } + } else { + asm.push(Instr::with2(Mnemonic::Mov, Operand::Reg(args[reg_args].boxed()), Operand::Reg(reg.clone()))); } reg_args += 1; @@ -61,22 +79,14 @@ pub(crate) fn CompileCall(call: &Call, Var>, registry: &mut T } }, } - if !block.isVarUsedAfterNode(&boxed, arg) { - registry.backend.drop(arg); - } - } - - if registry.call.reset_eax() { - asm.push(Instr::with2(Mnemonic::Xor, Operand::Reg(x64Reg::Eax.boxed()), Operand::Reg(x64Reg::Eax.boxed()))); } - asm.push( Instr::with1(Mnemonic::Call, Operand::Imm(0))); + asm.push( Instr::with1(Mnemonic::Call, Operand::Imm(0)) ); + asm.push( Instr::with1(Mnemonic::Link, Operand::LinkDestination(call.inner1.name.to_string(), -4)) ); - asm.push( Instr::with1(Mnemonic::Link, Operand::LinkDestination(call.inner1.name.to_string(), -4))); - - if func.ty.ret != TypeMetadata::Void && block.isVarUsedAfterNode(&boxed, &call.inner3){ + if call.inner1.ty.ret != TypeMetadata::Void && block.isVarUsedAfterNode(&boxed, &call.inner3){ let store = if let Some(reg) = registry.backend.getOpenRegBasedOnTy(call.inner3.ty) { - match func.ty.ret { + match call.inner1.ty.ret { TypeMetadata::u16 | TypeMetadata::i16 => asm.push( Instr::with2(Mnemonic::Mov, Operand::Reg(reg.clone()), Operand::Reg(registry.call.ret16().boxed())) ), TypeMetadata::u32 | TypeMetadata::i32 => asm.push( Instr::with2(Mnemonic::Mov, Operand::Reg(reg.clone()), Operand::Reg(registry.call.ret32().boxed())) ), TypeMetadata::u64 | TypeMetadata::i64 => asm.push( Instr::with2(Mnemonic::Mov, Operand::Reg(reg.clone()), Operand::Reg(registry.call.ret64().boxed())) ), @@ -94,7 +104,7 @@ pub(crate) fn CompileCall(call: &Call, Var>, registry: &mut T registry.backend.currStackOffsetForLocalVars += addend; let mem = x64Reg::Rbp - (registry.backend.currStackOffsetForLocalVars - addend) as u32; - match func.ty.ret { + match call.inner1.ty.ret { TypeMetadata::u16 | TypeMetadata::i16 => asm.push( Instr::with2(Mnemonic::Mov, Operand::Mem(mem.clone()), Operand::Reg(registry.call.ret16().boxed())) ), TypeMetadata::u32 | TypeMetadata::i32 => asm.push( Instr::with2(Mnemonic::Mov, Operand::Mem(mem.clone()), Operand::Reg(registry.call.ret32().boxed())) ), TypeMetadata::u64 | TypeMetadata::i64 => asm.push( Instr::with2(Mnemonic::Mov, Operand::Mem(mem.clone()), Operand::Reg(registry.call.ret64().boxed())) ), @@ -106,10 +116,16 @@ pub(crate) fn CompileCall(call: &Call, Var>, registry: &mut T registry.backend.insertVar(call.inner3.clone(), store); } - - for reg in to_pop { - asm.push(Instr::with1(Mnemonic::Pop, Operand::Reg(reg.boxed()))); + + for (var, off) in saved_var_memory_locations { + let reg = if let Some(VarStorage::Register(reg)) = registry.backend.varsStorage.get(&var) { + reg.to_owned() + } else { todo!() }; // shouldn't happen + + asm.push( Instr::with2(Mnemonic::Mov, Operand::Reg(reg), Operand::Mem(x64Reg::Rbp - (off as u32))) ); } + asm.push(Instr::with0(Mnemonic::StartOptimization)); + asm } diff --git a/src/Target/x64/compilation/mod.rs b/src/Target/x64/compilation/mod.rs index c1105a45..6a0556f7 100644 --- a/src/Target/x64/compilation/mod.rs +++ b/src/Target/x64/compilation/mod.rs @@ -77,18 +77,16 @@ pub(crate) fn buildAsmX86<'a>(block: &'a Block, func: &Function, call: &CallConv registry.block = None; - let mut out = Vec::from(out); - - auto_max_optimize(&mut out); - - let mut out = VecDeque::from(out); - out.extend(x64BuildEpilog(&block, registry)); for epAsm in x64BuildProlog(&block, registry) { out.push_front(epAsm); } - Vec::from(out) + let mut out = Vec::from(out); + + auto_max_optimize(&mut out); + + out } \ No newline at end of file diff --git a/src/Target/x64/compilation/prolog.rs b/src/Target/x64/compilation/prolog.rs index 052cbdd1..fe470793 100644 --- a/src/Target/x64/compilation/prolog.rs +++ b/src/Target/x64/compilation/prolog.rs @@ -14,6 +14,8 @@ pub(crate) fn x64BuildProlog(_: &Block, registry: &mut TargetBackendDescr) -> Ve res.push( Instr::with1(Mnemonic::Push, Operand::Reg(backuped.boxed())) ) } + res.push( Instr::with0(Mnemonic::StartOptimization) ); + res.reverse(); res @@ -22,6 +24,9 @@ pub(crate) fn x64BuildProlog(_: &Block, registry: &mut TargetBackendDescr) -> Ve pub(crate) fn x64BuildEpilog(_: &Block, registry: &mut TargetBackendDescr) -> Vec { let mut res = vec![]; + + res.push( Instr::with0(Mnemonic::EndOptimization) ); + for backuped in ®istry.backend.saveRegister { res.push( Instr::with1(Mnemonic::Pop, Operand::Reg(backuped.boxed())) ) } diff --git a/src/Target/x64/mod.rs b/src/Target/x64/mod.rs index 775ec4fb..b1cccfb5 100644 --- a/src/Target/x64/mod.rs +++ b/src/Target/x64/mod.rs @@ -30,7 +30,13 @@ pub fn initializeX64Target<'a>(call_conv: CallConv) -> TargetBackendDescr<'a> { target.call = call_conv; target.backend.savedRegisters = vec![ - x64Reg::R10.boxed(), x64Reg::R11.boxed(), x64Reg::R12.boxed(), x64Reg::R13.boxed(), x64Reg::R14.boxed(), x64Reg::R15.boxed(), + x64Reg::R12.boxed(), x64Reg::R13.boxed(), x64Reg::R14.boxed(), x64Reg::R15.boxed(), + ]; + + target.backend.mutable = vec![ + x64Reg::Rax.boxed(), x64Reg::Rbx.boxed(), x64Reg::Rcx.boxed(), x64Reg::Rdx.boxed(), + x64Reg::Rdi.boxed(), x64Reg::Rsi.boxed(), x64Reg::R8.boxed(), x64Reg::R9.boxed(), + x64Reg::R10.boxed(), x64Reg::R11.boxed(), ]; match call_conv {