diff --git a/compiler/gen_dev/src/generic64/aarch64.rs b/compiler/gen_dev/src/generic64/aarch64.rs index 334c3d6188..e069698a08 100644 --- a/compiler/gen_dev/src/generic64/aarch64.rs +++ b/compiler/gen_dev/src/generic64/aarch64.rs @@ -252,6 +252,16 @@ impl Assembler for AArch64Assembler { add_reg64_reg64_reg64(buf, dst, src1, src2); } + #[inline(always)] + fn add_freg64_freg64_freg64( + _buf: &mut Vec<'_, u8>, + _dst: AArch64FPReg, + _src1: AArch64FPReg, + _src2: AArch64FPReg, + ) { + unimplemented!("adding floats not yet implemented for AArch64"); + } + #[inline(always)] fn mov_freg64_imm64( _buf: &mut Vec<'_, u8>, @@ -302,6 +312,10 @@ impl Assembler for AArch64Assembler { } } + fn mov_freg64_stack32(_buf: &mut Vec<'_, u8>, _dst: AArch64FPReg, _offset: i32) { + unimplemented!("loading floating point reg from stack not yet implemented for AArch64"); + } + #[inline(always)] fn mov_stack32_freg64(_buf: &mut Vec<'_, u8>, _offset: i32, _src: AArch64FPReg) { unimplemented!("saving floating point reg to stack not yet implemented for AArch64"); diff --git a/compiler/gen_dev/src/generic64/mod.rs b/compiler/gen_dev/src/generic64/mod.rs index 43cf600a15..89d727e557 100644 --- a/compiler/gen_dev/src/generic64/mod.rs +++ b/compiler/gen_dev/src/generic64/mod.rs @@ -54,6 +54,7 @@ pub trait CallConv { pub trait Assembler { fn abs_reg64_reg64(buf: &mut Vec<'_, u8>, dst: GPReg, src: GPReg); fn add_reg64_reg64_imm32(buf: &mut Vec<'_, u8>, dst: GPReg, src1: GPReg, imm32: i32); + fn add_freg64_freg64_freg64(buf: &mut Vec<'_, u8>, dst: FPReg, src1: FPReg, src2: FPReg); fn add_reg64_reg64_reg64(buf: &mut Vec<'_, u8>, dst: GPReg, src1: GPReg, src2: GPReg); fn mov_freg64_imm64( buf: &mut Vec<'_, u8>, @@ -64,7 +65,7 @@ pub trait Assembler { fn mov_reg64_imm64(buf: &mut Vec<'_, u8>, dst: GPReg, imm: i64); fn mov_freg64_freg64(buf: &mut Vec<'_, u8>, dst: FPReg, src: FPReg); fn mov_reg64_reg64(buf: &mut Vec<'_, u8>, dst: GPReg, src: GPReg); - // fn mov_freg64_stack32(buf: &mut Vec<'_, u8>, dst: FPReg, offset: i32); + fn mov_freg64_stack32(buf: &mut Vec<'_, u8>, dst: FPReg, offset: i32); fn mov_reg64_stack32(buf: &mut Vec<'_, u8>, dst: GPReg, offset: i32); fn mov_stack32_freg64(buf: &mut Vec<'_, u8>, offset: i32, src: FPReg); fn mov_stack32_reg64(buf: &mut Vec<'_, u8>, offset: i32, src: GPReg); @@ -242,6 +243,19 @@ impl< Ok(()) } + fn build_num_add_f64( + &mut self, + dst: &Symbol, + src1: &Symbol, + src2: &Symbol, + ) -> Result<(), String> { + let dst_reg = self.claim_fpreg(dst)?; + let src1_reg = self.load_to_fpreg(src1)?; + let src2_reg = self.load_to_fpreg(src2)?; + ASM::add_freg64_freg64_freg64(&mut self.buf, dst_reg, src1_reg, src2_reg); + Ok(()) + } + fn build_num_sub_i64( &mut self, dst: &Symbol, @@ -388,6 +402,35 @@ impl< } } + fn load_to_fpreg(&mut self, sym: &Symbol) -> Result { + let val = self.symbols_map.remove(sym); + match val { + Some(SymbolStorage::GPReg(_reg)) => { + Err("Cannot load integer point symbol into FPReg".to_string()) + } + Some(SymbolStorage::FPReg(reg)) => { + self.symbols_map.insert(*sym, SymbolStorage::FPReg(reg)); + Ok(reg) + } + Some(SymbolStorage::StackAndGPReg(_reg, _offset)) => { + Err("Cannot load integer point symbol into FPReg".to_string()) + } + Some(SymbolStorage::StackAndFPReg(reg, offset)) => { + self.symbols_map + .insert(*sym, SymbolStorage::StackAndFPReg(reg, offset)); + Ok(reg) + } + Some(SymbolStorage::Stack(offset)) => { + let reg = self.claim_fpreg(sym)?; + self.symbols_map + .insert(*sym, SymbolStorage::StackAndFPReg(reg, offset)); + ASM::mov_freg64_stack32(&mut self.buf, reg, offset as i32); + Ok(reg) + } + None => Err(format!("Unknown symbol: {}", sym)), + } + } + fn free_to_stack(&mut self, sym: &Symbol) -> Result<(), String> { let val = self.symbols_map.remove(sym); match val { diff --git a/compiler/gen_dev/src/generic64/x86_64.rs b/compiler/gen_dev/src/generic64/x86_64.rs index e8a427e37e..d35e15adb3 100644 --- a/compiler/gen_dev/src/generic64/x86_64.rs +++ b/compiler/gen_dev/src/generic64/x86_64.rs @@ -381,6 +381,22 @@ impl Assembler for X86_64Assembler { } } #[inline(always)] + fn add_freg64_freg64_freg64( + buf: &mut Vec<'_, u8>, + dst: X86_64FPReg, + src1: X86_64FPReg, + src2: X86_64FPReg, + ) { + if dst == src1 { + addsd_freg64_freg64(buf, dst, src2); + } else if dst == src2 { + addsd_freg64_freg64(buf, dst, src1); + } else { + movsd_freg64_freg64(buf, dst, src1); + addsd_freg64_freg64(buf, dst, src2); + } + } + #[inline(always)] fn mov_freg64_imm64( buf: &mut Vec<'_, u8>, relocs: &mut Vec<'_, Relocation>, @@ -406,6 +422,10 @@ impl Assembler for X86_64Assembler { mov_reg64_reg64(buf, dst, src); } #[inline(always)] + fn mov_freg64_stack32(_buf: &mut Vec<'_, u8>, _dst: X86_64FPReg, _offset: i32) { + unimplemented!("loading floating point reg from stack not yet implemented for X86_64"); + } + #[inline(always)] fn mov_reg64_stack32(buf: &mut Vec<'_, u8>, dst: X86_64GPReg, offset: i32) { mov_reg64_stack32(buf, dst, offset); } @@ -515,6 +535,26 @@ fn add_reg64_reg64(buf: &mut Vec<'_, u8>, dst: X86_64GPReg, src: X86_64GPReg) { buf.extend(&[rex, 0x01, 0xC0 + dst_mod + src_mod]); } +/// `ADDSD xmm1,xmm2/m64` -> Add the low double-precision floating-point value from xmm2/mem to xmm1 and store the result in xmm1. +#[inline(always)] +fn addsd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FPReg, src: X86_64FPReg) { + let dst_high = dst as u8 > 7; + let dst_mod = dst as u8 % 8; + let src_high = src as u8 > 7; + let src_mod = src as u8 % 8; + if dst_high || src_high { + buf.extend(&[ + 0xF2, + 0x40 + ((dst_high as u8) << 2) + (src_high as u8), + 0x0F, + 0x58, + 0xC0 + (dst_mod << 3) + (src_mod), + ]) + } else { + buf.extend(&[0xF2, 0x0F, 0x58, 0xC0 + (dst_mod << 3) + (src_mod)]) + } +} + /// `SUB r/m64,r64` -> Sub r64 to r/m64. #[inline(always)] fn sub_reg64_reg64(buf: &mut Vec<'_, u8>, dst: X86_64GPReg, src: X86_64GPReg) { @@ -717,6 +757,34 @@ mod tests { } } + #[test] + fn test_addsd_freg64_freg64() { + let arena = bumpalo::Bump::new(); + let mut buf = bumpalo::vec![in &arena]; + for ((dst, src), expected) in &[ + ( + (X86_64FPReg::XMM0, X86_64FPReg::XMM0), + vec![0xF2, 0x0F, 0x58, 0xC0], + ), + ( + (X86_64FPReg::XMM0, X86_64FPReg::XMM15), + vec![0xF2, 0x41, 0x0F, 0x58, 0xC7], + ), + ( + (X86_64FPReg::XMM15, X86_64FPReg::XMM0), + vec![0xF2, 0x44, 0x0F, 0x58, 0xF8], + ), + ( + (X86_64FPReg::XMM15, X86_64FPReg::XMM15), + vec![0xF2, 0x45, 0x0F, 0x58, 0xFF], + ), + ] { + buf.clear(); + addsd_freg64_freg64(&mut buf, *dst, *src); + assert_eq!(&expected[..], &buf[..]); + } + } + #[test] fn test_cmovl_reg64_reg64() { let arena = bumpalo::Bump::new(); diff --git a/compiler/gen_dev/src/lib.rs b/compiler/gen_dev/src/lib.rs index a6a45d5e5b..c59bf3b69b 100644 --- a/compiler/gen_dev/src/lib.rs +++ b/compiler/gen_dev/src/lib.rs @@ -184,6 +184,9 @@ where Layout::Builtin(Builtin::Int64) => { self.build_num_add_i64(sym, &args[0], &args[1]) } + Layout::Builtin(Builtin::Float64) => { + self.build_num_add_f64(sym, &args[0], &args[1]) + } x => Err(format!("layout, {:?}, not implemented yet", x)), } } @@ -213,6 +216,15 @@ where src2: &Symbol, ) -> Result<(), String>; + /// build_num_add_f64 stores the sum of src1 and src2 into dst. + /// It only deals with inputs and outputs of f64 type. + fn build_num_add_f64( + &mut self, + dst: &Symbol, + src1: &Symbol, + src2: &Symbol, + ) -> Result<(), String>; + /// build_num_sub_i64 stores the `src1 - src2` difference into dst. /// It only deals with inputs and outputs of i64 type. fn build_num_sub_i64( diff --git a/compiler/gen_dev/tests/gen_num.rs b/compiler/gen_dev/tests/gen_num.rs index 251a500fb3..9ca98fcddc 100644 --- a/compiler/gen_dev/tests/gen_num.rs +++ b/compiler/gen_dev/tests/gen_num.rs @@ -55,7 +55,6 @@ mod gen_num { ); } - /* #[test] fn gen_add_f64() { assert_evals_to!( @@ -68,7 +67,6 @@ mod gen_num { f64 ); } - */ #[test] fn gen_sub_i64() {