From 86eb9e7551213533389ddf761594b7cc8e759bb3 Mon Sep 17 00:00:00 2001 From: Cr0a3 Date: Mon, 4 Nov 2024 19:49:07 +0100 Subject: [PATCH] [X64] fixes #47 --- src/CodeGen/compilation/mod.rs | 2 + src/CodeGen/compilation/prolog.rs | 8 ++++ src/Target/wasm/mod.rs | 1 + src/Target/x64/compilation.rs | 6 ++- src/Target/x64/lower/cmov.rs | 20 ++++----- src/Target/x64/lower/cmp.rs | 8 ++-- src/Target/x64/lower/math.rs | 20 ++++----- src/Target/x64/lower/prolog.rs | 43 +++++++++++++++--- src/Target/x64/lower/switch.rs | 4 +- src/Target/x64/reg.rs | 73 ++++++++++--------------------- src/Target/x64/reg_alloc.rs | 7 +++ 11 files changed, 108 insertions(+), 84 deletions(-) diff --git a/src/CodeGen/compilation/mod.rs b/src/CodeGen/compilation/mod.rs index 2c3f181f..f938c875 100644 --- a/src/CodeGen/compilation/mod.rs +++ b/src/CodeGen/compilation/mod.rs @@ -61,6 +61,8 @@ pub struct Allocator { pub(crate) ffpregs: Vec, pub(crate) call: MachineCallingConvention, + + pub(crate) callee_save_registers: Vec, } /// helps with compilation #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/src/CodeGen/compilation/prolog.rs b/src/CodeGen/compilation/prolog.rs index db6544f1..f03ba450 100644 --- a/src/CodeGen/compilation/prolog.rs +++ b/src/CodeGen/compilation/prolog.rs @@ -8,6 +8,10 @@ impl CompilationHelper { let mut instr = MachineInstr::new( MachineMnemonic::Prolog ); instr.add_operand( MachineOperand::Imm(self.alloc.stack_off as f64) ); + for save in &self.alloc.callee_save_registers { + instr.add_operand( MachineOperand::Reg(*save) ); + } + sink.push( instr ); } @@ -16,6 +20,10 @@ impl CompilationHelper { let mut instr = MachineInstr::new( MachineMnemonic::Epilog ); instr.add_operand( MachineOperand::Imm(self.alloc.stack_off as f64) ); + for save in &self.alloc.callee_save_registers { + instr.add_operand( MachineOperand::Reg(*save) ); + } + sink.push( instr ); } } \ No newline at end of file diff --git a/src/Target/wasm/mod.rs b/src/Target/wasm/mod.rs index 97fcb89a..42f4d9f6 100644 --- a/src/Target/wasm/mod.rs +++ b/src/Target/wasm/mod.rs @@ -43,6 +43,7 @@ pub fn initializeWasmTarget(_: CallConv) -> TargetBackendDescr { fregs: Vec::new(), ffpregs: Vec::new(), call: MachineCallingConvention { call_conv: CallConv::WasmBasicCAbi }, + callee_save_registers: Vec::new(), }; let mut compiler = CompilationHelper::new( diff --git a/src/Target/x64/compilation.rs b/src/Target/x64/compilation.rs index ae75ee07..5761250a 100644 --- a/src/Target/x64/compilation.rs +++ b/src/Target/x64/compilation.rs @@ -41,6 +41,7 @@ pub(crate) fn construct_compilation_helper(call_conv: CallConv) -> CompilationHe Reg::x64(X64Reg::Xmm13)], fregs: vec![ + // Please do not move rbx forward, cuz then it will be select earlier and rbx is a callee saved register Reg::x64(X64Reg::Rcx), Reg::x64(X64Reg::Rdx), Reg::x64(X64Reg::Rsi), @@ -48,8 +49,7 @@ pub(crate) fn construct_compilation_helper(call_conv: CallConv) -> CompilationHe Reg::x64(X64Reg::R8), Reg::x64(X64Reg::R9), Reg::x64(X64Reg::R10), - Reg::x64(X64Reg::R11), - Reg::x64(X64Reg::R12), + Reg::x64(X64Reg::Rbx), Reg::x64(X64Reg::R12), Reg::x64(X64Reg::R13), Reg::x64(X64Reg::R14), @@ -57,6 +57,8 @@ pub(crate) fn construct_compilation_helper(call_conv: CallConv) -> CompilationHe ], call: calling_convention, + + callee_save_registers: Vec::new(), // will be set in the allocation }; alloc.fregs.reverse(); diff --git a/src/Target/x64/lower/cmov.rs b/src/Target/x64/lower/cmov.rs index d5bf0075..bcdcc56d 100644 --- a/src/Target/x64/lower/cmov.rs +++ b/src/Target/x64/lower/cmov.rs @@ -18,8 +18,8 @@ pub(crate) fn x64_lower_cmov_zero(sink: &mut Vec, instr: &MachineIns let out = out.into(); let cmp = if let Operand::Mem(_) = cond { - vec![X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rbx), Operand::Imm(0)), - X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Reg(X64Reg::Rbx))] + vec![X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::R11), Operand::Imm(0)), + X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Reg(X64Reg::R11))] } else { vec![X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Imm(0))] }; @@ -61,8 +61,8 @@ pub(crate) fn x64_lower_cmov_not_zero(sink: &mut Vec, instr: &Machin let out = out.into(); let cmp = if let Operand::Mem(_) = cond { - vec![X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rbx), Operand::Imm(0)), - X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Reg(X64Reg::Rbx))] + vec![X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::R11), Operand::Imm(0)), + X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Reg(X64Reg::R11))] } else { vec![X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Imm(0))] }; @@ -100,7 +100,7 @@ pub(crate) fn x64_lower_fcmov0(sink: &mut Vec, instr: &MachineInstr) let out: Operand = out.into(); let tmp = if instr.meta == TypeMetadata::f32 { X64Reg::Eax } else { X64Reg::Rax }; - let tmp2 = if instr.meta == TypeMetadata::f32 { X64Reg::Ebx } else { X64Reg::Rbx }; + let tmp2 = if instr.meta == TypeMetadata::f32 { X64Reg::Ebx } else { X64Reg::R11 }; let mnemonic =if instr.meta == TypeMetadata::f32 { Mnemonic::Movd @@ -109,8 +109,8 @@ pub(crate) fn x64_lower_fcmov0(sink: &mut Vec, instr: &MachineInstr) }; sink.extend_from_slice(&if let Operand::Mem(_) = cond { - vec![X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rbx), Operand::Imm(0)), - X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Reg(X64Reg::Rbx))] + vec![X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::R11), Operand::Imm(0)), + X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Reg(X64Reg::R11))] } else { vec![X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Imm(0))] }); @@ -143,7 +143,7 @@ pub(crate) fn x64_lower_fcmovne0(sink: &mut Vec, instr: &MachineInst let out: Operand = out.into(); let tmp = if instr.meta == TypeMetadata::f32 { X64Reg::Eax } else { X64Reg::Rax }; - let tmp2 = if instr.meta == TypeMetadata::f32 { X64Reg::Ebx } else { X64Reg::Rbx }; + let tmp2 = if instr.meta == TypeMetadata::f32 { X64Reg::Ebx } else { X64Reg::R11 }; let mnemonic =if instr.meta == TypeMetadata::f32 { Mnemonic::Movd @@ -152,8 +152,8 @@ pub(crate) fn x64_lower_fcmovne0(sink: &mut Vec, instr: &MachineInst }; sink.extend_from_slice(&if let Operand::Mem(_) = cond { - vec![X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rbx), Operand::Imm(0)), - X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Reg(X64Reg::Rbx))] + vec![X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::R11), Operand::Imm(0)), + X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Reg(X64Reg::R11))] } else { vec![X64MCInstr::with2(Mnemonic::Cmp, cond, Operand::Imm(0))] }); diff --git a/src/Target/x64/lower/cmp.rs b/src/Target/x64/lower/cmp.rs index e9d48bd5..c6b6c2ff 100644 --- a/src/Target/x64/lower/cmp.rs +++ b/src/Target/x64/lower/cmp.rs @@ -23,16 +23,16 @@ fn x64_lower_cmp(sink: &mut Vec, instr: &MachineInstr, mode: &CmpMod if let Operand::Mem(_) = ls { if ls == out { - sink.push(X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rbx.sub_ty(instr.meta)), ls.clone())); + sink.push(X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::R11.sub_ty(instr.meta)), ls.clone())); sink.push(X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)), Operand::Imm(0))); sink.push(X64MCInstr::with2(Mnemonic::Mov, ls, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)))); - sink.push(X64MCInstr::with2(Mnemonic::Cmp, Operand::Reg(X64Reg::Rbx.sub_ty(instr.meta)), rs)); + sink.push(X64MCInstr::with2(Mnemonic::Cmp, Operand::Reg(X64Reg::R11.sub_ty(instr.meta)), rs)); } else if rs == out { - sink.push(X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rbx.sub_ty(instr.meta)), rs.clone())); + sink.push(X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::R11.sub_ty(instr.meta)), rs.clone())); sink.push(X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)), Operand::Imm(0))); sink.push(X64MCInstr::with2(Mnemonic::Mov, rs, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)))); sink.push(X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)), ls)); - sink.push(X64MCInstr::with2(Mnemonic::Cmp, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)), Operand::Reg(X64Reg::Rbx.sub_ty(instr.meta)))); + sink.push(X64MCInstr::with2(Mnemonic::Cmp, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)), Operand::Reg(X64Reg::R11.sub_ty(instr.meta)))); } else { if let Operand::Reg(_) = out { sink.push(X64MCInstr::with2(Mnemonic::Mov, out.clone(), Operand::Imm(0))); diff --git a/src/Target/x64/lower/math.rs b/src/Target/x64/lower/math.rs index 18e2e880..5007a99b 100644 --- a/src/Target/x64/lower/math.rs +++ b/src/Target/x64/lower/math.rs @@ -49,8 +49,8 @@ pub(crate) fn x64_lower_mul(sink: &mut Vec, instr: &MachineInstr) { if op1.is_imm() && op2.is_imm() { // theoraticly we could precalculate it here but if the user wanted us to do this he would use `-O` flag sink.extend_from_slice(&[ X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)), op1), - X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rbx.sub_ty(instr.meta)), op2), - X64MCInstr::with2(Mnemonic::Imul, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)), Operand::Reg(X64Reg::Rbx.sub_ty(instr.meta))), + X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::R11.sub_ty(instr.meta)), op2), + X64MCInstr::with2(Mnemonic::Imul, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta)), Operand::Reg(X64Reg::R11.sub_ty(instr.meta))), X64MCInstr::with2(Mnemonic::Mov, out, Operand::Reg(X64Reg::Rax.sub_ty(instr.meta))), ]); @@ -162,11 +162,11 @@ pub(crate) fn x64_lower_div(sink: &mut Vec, instr: &MachineInstr) { // assembly code is here let div_instr = if op2.is_imm() { - sink.push(X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rbx.sub_ty(instr.meta)), op2)); - X64MCInstr::with1(div_mnemonic, Operand::Reg(X64Reg::Rbx.sub_ty(instr.meta))) + sink.push(X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::R11.sub_ty(instr.meta)), op2)); + X64MCInstr::with1(div_mnemonic, Operand::Reg(X64Reg::R11.sub_ty(instr.meta))) } else if matches!(op2, Operand::Reg(X64Reg::Rdx) | Operand::Reg(X64Reg::Edx)) { - sink.push(X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rbx.sub_ty(instr.meta)), op2)); - X64MCInstr::with1(div_mnemonic, Operand::Reg(X64Reg::Rbx.sub_ty(instr.meta))) + sink.push(X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::R11.sub_ty(instr.meta)), op2)); + X64MCInstr::with1(div_mnemonic, Operand::Reg(X64Reg::R11.sub_ty(instr.meta))) } else { X64MCInstr::with1(div_mnemonic, op2) }; @@ -232,11 +232,11 @@ pub(crate) fn x64_lower_rem(sink: &mut Vec, instr: &MachineInstr) { // mul/imul only accept r/m if let Operand::Imm(_) = op2 { - sink.push(X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rbx.sub_ty(instr.meta)), op2.clone())); - sink.push(X64MCInstr::with1(mnemonic, Operand::Reg(X64Reg::Rbx.sub_ty(instr.meta)))); + sink.push(X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::R11.sub_ty(instr.meta)), op2.clone())); + sink.push(X64MCInstr::with1(mnemonic, Operand::Reg(X64Reg::R11.sub_ty(instr.meta)))); } else if let Operand::Mem(_) = op2 { - sink.push(X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rbx.sub_ty(instr.meta)), op2.clone())); - sink.push(X64MCInstr::with1(mnemonic, Operand::Reg(X64Reg::Rbx.sub_ty(instr.meta)))); + sink.push(X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::R11.sub_ty(instr.meta)), op2.clone())); + sink.push(X64MCInstr::with1(mnemonic, Operand::Reg(X64Reg::R11.sub_ty(instr.meta)))); } else { sink.push(X64MCInstr::with1(mnemonic, op2.clone())); } diff --git a/src/Target/x64/lower/prolog.rs b/src/Target/x64/lower/prolog.rs index 65b9b4de..263954fa 100644 --- a/src/Target/x64/lower/prolog.rs +++ b/src/Target/x64/lower/prolog.rs @@ -1,18 +1,47 @@ -use crate::CodeGen::MachineInstr; +use crate::CodeGen::{MachineInstr, MachineOperand}; use crate::Target::x64::X64Reg; use crate::Target::x64::asm::instr::*; pub(crate) fn x64_lower_prolog(sink: &mut Vec, instr: &MachineInstr) { //sink.push( X64MCInstr::with0(Mnemonic::Endbr64) ); - sink.push( X64MCInstr::with1(Mnemonic::Push, Operand::Reg(X64Reg::Rbp) ) ); - sink.push( X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rbp), Operand::Reg(X64Reg::Rsp) ) ); - if let Some(op0) = instr.operands.get(0) { - let op0 = (*op0).into(); - sink.push( X64MCInstr::with2(Mnemonic::Sub, Operand::Reg(X64Reg::Rbp), op0) ); + for op in instr.operands.iter() { // we remove the stack_off + let MachineOperand::Reg(crate::CodeGen::Reg::x64(callee_save)) = op else { continue; }; + + if callee_save.is_xmm() { + sink.extend_from_slice(&[ + X64MCInstr::with2(Mnemonic::Movq, Operand::Mem(MemOp { base: Some(X64Reg::Rsp), index: None, scale: 1, displ: 0, rip: false }), Operand::Reg(*callee_save)), + X64MCInstr::with2(Mnemonic::Sub, Operand::Reg(X64Reg::Rsp), Operand::Imm(8)), + ]); + } else { + sink.push(X64MCInstr::with1(Mnemonic::Push, Operand::Reg(*callee_save))); + } } + + let Some(MachineOperand::Imm(stack_off)) = instr.operands.get(0) else { panic!("expected valid stack_off for prolog")}; + let stack_off = *stack_off as i64; + + if stack_off > 0 { + sink.push( X64MCInstr::with1(Mnemonic::Push, Operand::Reg(X64Reg::Rbp) ) ); + sink.push( X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rbp), Operand::Reg(X64Reg::Rsp) ) ); + sink.push( X64MCInstr::with2(Mnemonic::Sub, Operand::Reg(X64Reg::Rbp), Operand::Imm(stack_off)) ); + } + } -pub(crate) fn x64_lower_epilog(sink: &mut Vec, _: &MachineInstr) { +pub(crate) fn x64_lower_epilog(sink: &mut Vec, instr: &MachineInstr) { + for op in instr.operands.iter().rev() { // we remove the stack_off + let MachineOperand::Reg(crate::CodeGen::Reg::x64(callee_save)) = op else { continue; }; + + if callee_save.is_xmm() { + sink.extend_from_slice(&[ + X64MCInstr::with2(Mnemonic::Movq, Operand::Reg(*callee_save), Operand::Mem(MemOp { base: Some(X64Reg::Rsp), index: None, scale: 1, displ: 0, rip: false })), + X64MCInstr::with2(Mnemonic::Add, Operand::Reg(X64Reg::Rsp), Operand::Imm(8)), + ]); + } else { + sink.push(X64MCInstr::with1(Mnemonic::Pop, Operand::Reg(*callee_save))); + } + } + sink.push( X64MCInstr::with1(Mnemonic::Pop, Operand::Reg(X64Reg::Rbp) ) ); } diff --git a/src/Target/x64/lower/switch.rs b/src/Target/x64/lower/switch.rs index 639405d9..986d99b7 100644 --- a/src/Target/x64/lower/switch.rs +++ b/src/Target/x64/lower/switch.rs @@ -56,8 +56,8 @@ pub(crate) fn x64_lower_fswitch(sink: &mut Vec, instr: &MachineInstr let cmp_mne = if instr.meta == TypeMetadata::f32 { Mnemonic::Ucomiss } else { Mnemonic::Ucomisd }; sink.extend_from_slice(&[ - X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::Rbx.sub_ty(size)), Operand::Imm(imm)), - X64MCInstr::with2(move_mne, Operand::Reg(X64Reg::Xmm14), Operand::Reg(X64Reg::Rbx.sub_ty(size))), + X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(X64Reg::R11.sub_ty(size)), Operand::Imm(imm)), + X64MCInstr::with2(move_mne, Operand::Reg(X64Reg::Xmm14), Operand::Reg(X64Reg::R11.sub_ty(size))), X64MCInstr::with2(cmp_mne, Operand::Reg(X64Reg::Xmm15), Operand::Reg(X64Reg::Xmm14)), X64MCInstr::with1(Mnemonic::Je, Operand::BlockLinkDestination(block.name.to_owned(), -4)), ]); diff --git a/src/Target/x64/reg.rs b/src/Target/x64/reg.rs index 30a8283f..29d01a42 100644 --- a/src/Target/x64/reg.rs +++ b/src/Target/x64/reg.rs @@ -1,6 +1,6 @@ use std::fmt::Display; -use crate::IR::TypeMetadata; +use crate::{Target::CallConv, IR::TypeMetadata}; /// A x64 register #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -37,7 +37,7 @@ impl X64Reg { use X64Reg::*; match string.to_ascii_lowercase().as_str() { "rax" => Some(Rax), "eax" => Some(Eax), "ax" => Some(Ax), "al" => Some(Al), - "rbx" => Some(Rbx), "ebx" => Some(Ebx), "bx" => Some(Bx), "bl" => Some(Bl), + "rbx" => Some(R11), "ebx" => Some(Ebx), "bx" => Some(Bx), "bl" => Some(Bl), "rcx" => Some(Rcx), "ecx" => Some(Ecx), "cx" => Some(Cx), "cl" => Some(Cl), "rdx" => Some(Rdx), "edx" => Some(Edx), "dx" => Some(Dx), "dl" => Some(Dl), "rsi" => Some(Rsi), "esi" => Some(Esi), "si" => Some(Si), "sil" => Some(Sil), @@ -90,7 +90,7 @@ impl X64Reg { use X64Reg::*; match self { Rax | Eax | Ax | Al => Rax, - Rbx | Ebx | Bx | Bl => Rbx, + Rbx | Ebx | Bx | Bl => R11, Rcx | Ecx | Cx | Cl => Rcx, Rdx | Edx | Dx | Dl => Rdx, Rsi | Esi | Si | Sil => Rsi, @@ -290,57 +290,32 @@ impl X64Reg { _ => false, } } - - #[doc(hidden)] - pub fn enc(&self) -> u8 { - match self { - // GR - X64Reg::Rax | X64Reg::Eax | X64Reg::Ax | X64Reg::Al => 0, - X64Reg::Rcx | X64Reg::Ecx | X64Reg::Cx | X64Reg::Cl => 1, - X64Reg::Rdx | X64Reg::Edx | X64Reg::Dx | X64Reg::Dl => 2, - X64Reg::Rbx | X64Reg::Ebx | X64Reg::Bx | X64Reg::Bl => 3, - X64Reg::Rsi | X64Reg::Esi | X64Reg::Si | X64Reg::Sil => 6, - X64Reg::Rbp | X64Reg::Ebp | X64Reg::Bp | X64Reg::Bpl => 5, - X64Reg::Rsp | X64Reg::Esp | X64Reg::Sp | X64Reg::Spl => 4, - X64Reg::Rdi | X64Reg::Edi | X64Reg::Di | X64Reg::Dil => 7, - - // here use a rex prefix - X64Reg::R8 | X64Reg::R8d | X64Reg::R8w | X64Reg::R8b => 0, - X64Reg::R9 | X64Reg::R9d | X64Reg::R9w | X64Reg::R9b => 1, - X64Reg::R10 | X64Reg::R10d | X64Reg::R10w | X64Reg::R10b => 2, - X64Reg::R11 | X64Reg::R11d | X64Reg::R11w | X64Reg::R11b => 3, - X64Reg::R12 | X64Reg::R12d | X64Reg::R12w | X64Reg::R12b => 4, - X64Reg::R13 | X64Reg::R13d | X64Reg::R13w | X64Reg::R13b => 5, - X64Reg::R14 | X64Reg::R14d | X64Reg::R14w | X64Reg::R14b => 6, - X64Reg::R15 | X64Reg::R15d | X64Reg::R15w | X64Reg::R15b => 7, - - // Xmm - X64Reg::Xmm0 => 0, - X64Reg::Xmm1 => 1, - X64Reg::Xmm2 => 2, - X64Reg::Xmm3 => 3, - X64Reg::Xmm4 => 4, - X64Reg::Xmm5 => 5, - X64Reg::Xmm6 => 6, - X64Reg::Xmm7 => 7, - - // here use a rex prefix - X64Reg::Xmm8 => 0, - X64Reg::Xmm9 => 1, - X64Reg::Xmm10 => 2, - X64Reg::Xmm11 => 3, - X64Reg::Xmm12 => 4, - X64Reg::Xmm13 => 5, - X64Reg::Xmm14 => 6, - X64Reg::Xmm15 => 7, - - } - } #[doc(hidden)] pub fn as_any(&self) -> &dyn std::any::Any { self } + + /// Returns if the register is callee saved on the given calling convention + pub fn callee_saved(&self, call: CallConv) -> bool { + use X64Reg::*; + + if self.is_xmm() { + return if call == CallConv::WindowsFastCall { + match self { + Xmm6 | Xmm7 | Xmm8 | + Xmm9 | Xmm10 | Xmm11 | Xmm12 | + Xmm13 | Xmm14 | Xmm15 => true, + _ => false, + } + } else { false } + } + + match self.sub64() { + Rbx | Rbp | R12 | R13 | R14 | R15 | Rsp => true, + _ => false, + } + } } impl Display for X64Reg { diff --git a/src/Target/x64/reg_alloc.rs b/src/Target/x64/reg_alloc.rs index 355c2b9b..de66e69f 100644 --- a/src/Target/x64/reg_alloc.rs +++ b/src/Target/x64/reg_alloc.rs @@ -96,6 +96,13 @@ pub(crate) fn x64_alloc_rv(alloc: &mut Allocator, ty: TypeMetadata) -> VarLocati let vec = if ty.float() { &mut alloc.ffpregs } else { &mut alloc.fregs }; // select free registers vec if let Some(reg) = vec.pop() { + let Reg::x64(x64) = reg else { panic!("x64 reg alloc expects x64 regs") }; + + if x64.callee_saved(alloc.call.call_conv) { + alloc.callee_save_registers.push(Reg::x64(x64)); + alloc.epilog = true; + } + VarLocation::Reg(match reg { // this code here just changes the register to be the fitting type Reg::x64(x64) => Reg::x64(x64.sub_ty(ty)), _ => panic!("the x64 register allocator just got an non x64 register")