mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 00:24:34 +00:00
Add floating point addition
This commit is contained in:
parent
71b7ee7fab
commit
244113ede2
5 changed files with 138 additions and 3 deletions
|
@ -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");
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue