Add floating point addition

This commit is contained in:
Brendan Hansknecht 2021-01-19 15:25:21 -08:00
parent 71b7ee7fab
commit 244113ede2
5 changed files with 138 additions and 3 deletions

View file

@ -252,6 +252,16 @@ impl Assembler<AArch64GPReg, AArch64FPReg> for AArch64Assembler {
add_reg64_reg64_reg64(buf, dst, src1, src2); 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)] #[inline(always)]
fn mov_freg64_imm64( fn mov_freg64_imm64(
_buf: &mut Vec<'_, u8>, _buf: &mut Vec<'_, u8>,
@ -302,6 +312,10 @@ impl Assembler<AArch64GPReg, AArch64FPReg> 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)] #[inline(always)]
fn mov_stack32_freg64(_buf: &mut Vec<'_, u8>, _offset: i32, _src: AArch64FPReg) { fn mov_stack32_freg64(_buf: &mut Vec<'_, u8>, _offset: i32, _src: AArch64FPReg) {
unimplemented!("saving floating point reg to stack not yet implemented for AArch64"); unimplemented!("saving floating point reg to stack not yet implemented for AArch64");

View file

@ -54,6 +54,7 @@ pub trait CallConv<GPReg: RegTrait, FPReg: RegTrait> {
pub trait Assembler<GPReg: RegTrait, FPReg: RegTrait> { pub trait Assembler<GPReg: RegTrait, FPReg: RegTrait> {
fn abs_reg64_reg64(buf: &mut Vec<'_, u8>, dst: GPReg, src: GPReg); 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_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 add_reg64_reg64_reg64(buf: &mut Vec<'_, u8>, dst: GPReg, src1: GPReg, src2: GPReg);
fn mov_freg64_imm64( fn mov_freg64_imm64(
buf: &mut Vec<'_, u8>, buf: &mut Vec<'_, u8>,
@ -64,7 +65,7 @@ pub trait Assembler<GPReg: RegTrait, FPReg: RegTrait> {
fn mov_reg64_imm64(buf: &mut Vec<'_, u8>, dst: GPReg, imm: i64); 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_freg64_freg64(buf: &mut Vec<'_, u8>, dst: FPReg, src: FPReg);
fn mov_reg64_reg64(buf: &mut Vec<'_, u8>, dst: GPReg, src: GPReg); 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_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_freg64(buf: &mut Vec<'_, u8>, offset: i32, src: FPReg);
fn mov_stack32_reg64(buf: &mut Vec<'_, u8>, offset: i32, src: GPReg); fn mov_stack32_reg64(buf: &mut Vec<'_, u8>, offset: i32, src: GPReg);
@ -242,6 +243,19 @@ impl<
Ok(()) 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( fn build_num_sub_i64(
&mut self, &mut self,
dst: &Symbol, dst: &Symbol,
@ -388,6 +402,35 @@ impl<
} }
} }
fn load_to_fpreg(&mut self, sym: &Symbol) -> Result<FPReg, String> {
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> { fn free_to_stack(&mut self, sym: &Symbol) -> Result<(), String> {
let val = self.symbols_map.remove(sym); let val = self.symbols_map.remove(sym);
match val { match val {

View file

@ -381,6 +381,22 @@ impl Assembler<X86_64GPReg, X86_64FPReg> for X86_64Assembler {
} }
} }
#[inline(always)] #[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( fn mov_freg64_imm64(
buf: &mut Vec<'_, u8>, buf: &mut Vec<'_, u8>,
relocs: &mut Vec<'_, Relocation>, relocs: &mut Vec<'_, Relocation>,
@ -406,6 +422,10 @@ impl Assembler<X86_64GPReg, X86_64FPReg> for X86_64Assembler {
mov_reg64_reg64(buf, dst, src); mov_reg64_reg64(buf, dst, src);
} }
#[inline(always)] #[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) { fn mov_reg64_stack32(buf: &mut Vec<'_, u8>, dst: X86_64GPReg, offset: i32) {
mov_reg64_stack32(buf, dst, offset); 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]); 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. /// `SUB r/m64,r64` -> Sub r64 to r/m64.
#[inline(always)] #[inline(always)]
fn sub_reg64_reg64(buf: &mut Vec<'_, u8>, dst: X86_64GPReg, src: X86_64GPReg) { 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] #[test]
fn test_cmovl_reg64_reg64() { fn test_cmovl_reg64_reg64() {
let arena = bumpalo::Bump::new(); let arena = bumpalo::Bump::new();

View file

@ -184,6 +184,9 @@ where
Layout::Builtin(Builtin::Int64) => { Layout::Builtin(Builtin::Int64) => {
self.build_num_add_i64(sym, &args[0], &args[1]) 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)), x => Err(format!("layout, {:?}, not implemented yet", x)),
} }
} }
@ -213,6 +216,15 @@ where
src2: &Symbol, src2: &Symbol,
) -> Result<(), String>; ) -> 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. /// build_num_sub_i64 stores the `src1 - src2` difference into dst.
/// It only deals with inputs and outputs of i64 type. /// It only deals with inputs and outputs of i64 type.
fn build_num_sub_i64( fn build_num_sub_i64(

View file

@ -55,7 +55,6 @@ mod gen_num {
); );
} }
/*
#[test] #[test]
fn gen_add_f64() { fn gen_add_f64() {
assert_evals_to!( assert_evals_to!(
@ -68,7 +67,6 @@ mod gen_num {
f64 f64
); );
} }
*/
#[test] #[test]
fn gen_sub_i64() { fn gen_sub_i64() {