mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 03:42:17 +00:00
Merge pull request #5068 from roc-lang/gen-dev-i128
gen-dev: num additions
This commit is contained in:
commit
a87aec77b4
8 changed files with 422 additions and 120 deletions
|
@ -748,6 +748,7 @@ sqrtChecked = \x ->
|
|||
else
|
||||
Ok (Num.sqrt x)
|
||||
|
||||
## Natural logarithm
|
||||
log : Frac a -> Frac a
|
||||
|
||||
logChecked : Frac a -> Result (Frac a) [LogNeedsPositive]
|
||||
|
|
|
@ -2,10 +2,13 @@ use crate::generic64::{storage::StorageManager, Assembler, CallConv, RegTrait};
|
|||
use crate::Relocation;
|
||||
use bumpalo::collections::Vec;
|
||||
use packed_struct::prelude::*;
|
||||
use roc_builtins::bitcode::FloatWidth;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{InLayout, STLayoutInterner};
|
||||
|
||||
use super::CompareOperation;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub enum AArch64GeneralReg {
|
||||
|
@ -888,6 +891,18 @@ impl Assembler<AArch64GeneralReg, AArch64FloatReg> for AArch64Assembler {
|
|||
todo!("registers unsigned less than for AArch64");
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn cmp_freg_freg_reg64(
|
||||
_buf: &mut Vec<'_, u8>,
|
||||
_dst: AArch64GeneralReg,
|
||||
_src1: AArch64FloatReg,
|
||||
_src2: AArch64FloatReg,
|
||||
_width: FloatWidth,
|
||||
_operation: CompareOperation,
|
||||
) {
|
||||
todo!("registers float comparison for AArch64");
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn igt_reg64_reg64_reg64(
|
||||
_buf: &mut Vec<'_, u8>,
|
||||
|
@ -1038,6 +1053,14 @@ impl Assembler<AArch64GeneralReg, AArch64FloatReg> for AArch64Assembler {
|
|||
{
|
||||
todo!("sar for AArch64")
|
||||
}
|
||||
|
||||
fn sqrt_freg64_freg64(_buf: &mut Vec<'_, u8>, _dst: AArch64FloatReg, _src: AArch64FloatReg) {
|
||||
todo!("sqrt")
|
||||
}
|
||||
|
||||
fn sqrt_freg32_freg32(_buf: &mut Vec<'_, u8>, _dst: AArch64FloatReg, _src: AArch64FloatReg) {
|
||||
todo!("sqrt")
|
||||
}
|
||||
}
|
||||
|
||||
impl AArch64Assembler {}
|
||||
|
|
|
@ -113,6 +113,13 @@ pub trait CallConv<GeneralReg: RegTrait, FloatReg: RegTrait, ASM: Assembler<Gene
|
|||
);
|
||||
}
|
||||
|
||||
pub enum CompareOperation {
|
||||
LessThan,
|
||||
LessThanOrEqual,
|
||||
GreaterThan,
|
||||
GreaterThanOrEqual,
|
||||
}
|
||||
|
||||
/// Assembler contains calls to the backend assembly generator.
|
||||
/// These calls do not necessarily map directly to a single assembly instruction.
|
||||
/// They are higher level in cases where an instruction would not be common and shared between multiple architectures.
|
||||
|
@ -310,6 +317,9 @@ pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait>: Sized + Copy {
|
|||
fn mov_stack32_freg64(buf: &mut Vec<'_, u8>, offset: i32, src: FloatReg);
|
||||
fn mov_stack32_reg64(buf: &mut Vec<'_, u8>, offset: i32, src: GeneralReg);
|
||||
|
||||
fn sqrt_freg64_freg64(buf: &mut Vec<'_, u8>, dst: FloatReg, src: FloatReg);
|
||||
fn sqrt_freg32_freg32(buf: &mut Vec<'_, u8>, dst: FloatReg, src: FloatReg);
|
||||
|
||||
fn neg_reg64_reg64(buf: &mut Vec<'_, u8>, dst: GeneralReg, src: GeneralReg);
|
||||
fn mul_freg32_freg32_freg32(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
|
@ -406,6 +416,15 @@ pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait>: Sized + Copy {
|
|||
src2: GeneralReg,
|
||||
);
|
||||
|
||||
fn cmp_freg_freg_reg64(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
dst: GeneralReg,
|
||||
src1: FloatReg,
|
||||
src2: FloatReg,
|
||||
width: FloatWidth,
|
||||
operation: CompareOperation,
|
||||
);
|
||||
|
||||
fn igt_reg64_reg64_reg64(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
dst: GeneralReg,
|
||||
|
@ -1273,6 +1292,20 @@ impl<
|
|||
.load_to_general_reg(&mut self.buf, src2);
|
||||
ASM::ult_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
|
||||
}
|
||||
Layout::Builtin(Builtin::Float(width)) => {
|
||||
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
|
||||
let src1_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src1);
|
||||
let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2);
|
||||
|
||||
ASM::cmp_freg_freg_reg64(
|
||||
&mut self.buf,
|
||||
dst_reg,
|
||||
src1_reg,
|
||||
src2_reg,
|
||||
width,
|
||||
CompareOperation::LessThan,
|
||||
);
|
||||
}
|
||||
x => todo!("NumLt: layout, {:?}", x),
|
||||
}
|
||||
}
|
||||
|
@ -1305,6 +1338,20 @@ impl<
|
|||
.load_to_general_reg(&mut self.buf, src2);
|
||||
ASM::ugt_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
|
||||
}
|
||||
Layout::Builtin(Builtin::Float(width)) => {
|
||||
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
|
||||
let src1_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src1);
|
||||
let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2);
|
||||
|
||||
ASM::cmp_freg_freg_reg64(
|
||||
&mut self.buf,
|
||||
dst_reg,
|
||||
src1_reg,
|
||||
src2_reg,
|
||||
width,
|
||||
CompareOperation::GreaterThan,
|
||||
);
|
||||
}
|
||||
x => todo!("NumGt: layout, {:?}", x),
|
||||
}
|
||||
}
|
||||
|
@ -1385,6 +1432,26 @@ impl<
|
|||
.load_to_general_reg(&mut self.buf, src2);
|
||||
ASM::lte_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
|
||||
}
|
||||
Layout::F64 | Layout::F32 => {
|
||||
let width = if *arg_layout == Layout::F64 {
|
||||
FloatWidth::F64
|
||||
} else {
|
||||
FloatWidth::F32
|
||||
};
|
||||
|
||||
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
|
||||
let src1_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src1);
|
||||
let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2);
|
||||
|
||||
ASM::cmp_freg_freg_reg64(
|
||||
&mut self.buf,
|
||||
dst_reg,
|
||||
src1_reg,
|
||||
src2_reg,
|
||||
width,
|
||||
CompareOperation::LessThanOrEqual,
|
||||
);
|
||||
}
|
||||
x => todo!("NumLte: layout, {:?}", x),
|
||||
}
|
||||
}
|
||||
|
@ -1407,6 +1474,26 @@ impl<
|
|||
.load_to_general_reg(&mut self.buf, src2);
|
||||
ASM::gte_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
|
||||
}
|
||||
Layout::F64 | Layout::F32 => {
|
||||
let width = if *arg_layout == Layout::F64 {
|
||||
FloatWidth::F64
|
||||
} else {
|
||||
FloatWidth::F32
|
||||
};
|
||||
|
||||
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
|
||||
let src1_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src1);
|
||||
let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2);
|
||||
|
||||
ASM::cmp_freg_freg_reg64(
|
||||
&mut self.buf,
|
||||
dst_reg,
|
||||
src1_reg,
|
||||
src2_reg,
|
||||
width,
|
||||
CompareOperation::GreaterThanOrEqual,
|
||||
);
|
||||
}
|
||||
x => todo!("NumGte: layout, {:?}", x),
|
||||
}
|
||||
}
|
||||
|
@ -2147,6 +2234,28 @@ impl<
|
|||
let val = *x;
|
||||
ASM::mov_reg64_imm64(&mut self.buf, reg, i128::from_ne_bytes(val) as i64);
|
||||
}
|
||||
(
|
||||
Literal::Int(bytes),
|
||||
Layout::Builtin(Builtin::Int(IntWidth::I128 | IntWidth::U128)),
|
||||
) => {
|
||||
self.storage_manager.with_tmp_general_reg(
|
||||
&mut self.buf,
|
||||
|storage_manager, buf, reg| {
|
||||
let base_offset = storage_manager.claim_stack_area(sym, 16);
|
||||
|
||||
let mut num_bytes = [0; 8];
|
||||
num_bytes.copy_from_slice(&bytes[..8]);
|
||||
let num = i64::from_ne_bytes(num_bytes);
|
||||
ASM::mov_reg64_imm64(buf, reg, num);
|
||||
ASM::mov_base32_reg64(buf, base_offset, reg);
|
||||
|
||||
num_bytes.copy_from_slice(&bytes[8..16]);
|
||||
let num = i64::from_ne_bytes(num_bytes);
|
||||
ASM::mov_reg64_imm64(buf, reg, num);
|
||||
ASM::mov_base32_reg64(buf, base_offset + 8, reg);
|
||||
},
|
||||
);
|
||||
}
|
||||
(Literal::Byte(x), Layout::Builtin(Builtin::Int(IntWidth::U8 | IntWidth::I8))) => {
|
||||
let reg = self.storage_manager.claim_general_reg(&mut self.buf, sym);
|
||||
let val = *x;
|
||||
|
@ -2167,6 +2276,25 @@ impl<
|
|||
let val = *x as f32;
|
||||
ASM::mov_freg32_imm32(&mut self.buf, &mut self.relocs, reg, val);
|
||||
}
|
||||
(Literal::Decimal(bytes), Layout::Builtin(Builtin::Decimal)) => {
|
||||
self.storage_manager.with_tmp_general_reg(
|
||||
&mut self.buf,
|
||||
|storage_manager, buf, reg| {
|
||||
let base_offset = storage_manager.claim_stack_area(sym, 16);
|
||||
|
||||
let mut num_bytes = [0; 8];
|
||||
num_bytes.copy_from_slice(&bytes[..8]);
|
||||
let num = i64::from_ne_bytes(num_bytes);
|
||||
ASM::mov_reg64_imm64(buf, reg, num);
|
||||
ASM::mov_base32_reg64(buf, base_offset, reg);
|
||||
|
||||
num_bytes.copy_from_slice(&bytes[8..16]);
|
||||
let num = i64::from_ne_bytes(num_bytes);
|
||||
ASM::mov_reg64_imm64(buf, reg, num);
|
||||
ASM::mov_base32_reg64(buf, base_offset + 8, reg);
|
||||
},
|
||||
);
|
||||
}
|
||||
(Literal::Str(x), Layout::Builtin(Builtin::Str)) => {
|
||||
if x.len() < 24 {
|
||||
// Load small string.
|
||||
|
@ -2446,6 +2574,18 @@ impl<
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_num_sqrt(&mut self, dst: Symbol, src: Symbol, float_width: FloatWidth) {
|
||||
let buf = &mut self.buf;
|
||||
|
||||
let dst_reg = self.storage_manager.claim_float_reg(buf, &dst);
|
||||
let src_reg = self.storage_manager.load_to_float_reg(buf, &src);
|
||||
|
||||
match float_width {
|
||||
FloatWidth::F32 => ASM::sqrt_freg32_freg32(buf, dst_reg, src_reg),
|
||||
FloatWidth::F64 => ASM::sqrt_freg64_freg64(buf, dst_reg, src_reg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This impl block is for ir related instructions that need backend specific information.
|
||||
|
|
|
@ -753,7 +753,7 @@ impl<
|
|||
debug_assert_eq!(from_offset % 8, 0);
|
||||
debug_assert_eq!(size % 8, 0);
|
||||
debug_assert_eq!(size, layout_interner.stack_size(*layout));
|
||||
self.copy_symbol_to_stack_offset_help(buf, size, from_offset, to_offset)
|
||||
self.copy_to_stack_offset(buf, size, from_offset, to_offset)
|
||||
}
|
||||
IntWidth::I64 | IntWidth::U64 => {
|
||||
debug_assert_eq!(to_offset % 8, 0);
|
||||
|
@ -795,7 +795,7 @@ impl<
|
|||
debug_assert_eq!(from_offset % 8, 0);
|
||||
debug_assert_eq!(size % 8, 0);
|
||||
debug_assert_eq!(size, layout_interner.stack_size(*layout));
|
||||
self.copy_symbol_to_stack_offset_help(buf, size, from_offset, to_offset)
|
||||
self.copy_to_stack_offset(buf, size, from_offset, to_offset)
|
||||
}
|
||||
},
|
||||
Layout::Boxed(_) => {
|
||||
|
@ -824,13 +824,13 @@ impl<
|
|||
debug_assert_eq!(from_offset % 8, 0);
|
||||
debug_assert_eq!(size % 8, 0);
|
||||
debug_assert_eq!(size, layout_interner.stack_size(*layout));
|
||||
self.copy_symbol_to_stack_offset_help(buf, size, from_offset, to_offset)
|
||||
self.copy_to_stack_offset(buf, size, from_offset, to_offset)
|
||||
}
|
||||
x => todo!("copying data to the stack with layout, {:?}", x),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn copy_symbol_to_stack_offset_help(
|
||||
pub fn copy_to_stack_offset(
|
||||
&mut self,
|
||||
buf: &mut Vec<'a, u8>,
|
||||
size: u32,
|
||||
|
|
|
@ -4,10 +4,13 @@ use crate::{
|
|||
single_register_layouts, Relocation,
|
||||
};
|
||||
use bumpalo::collections::Vec;
|
||||
use roc_builtins::bitcode::FloatWidth;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{InLayout, Layout, LayoutInterner, STLayoutInterner};
|
||||
|
||||
use super::CompareOperation;
|
||||
|
||||
// Not sure exactly how I want to represent registers.
|
||||
// If we want max speed, we would likely make them structs that impl the same trait to avoid ifs.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
|
||||
|
@ -1592,6 +1595,33 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
|
|||
setb_reg64(buf, dst);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn cmp_freg_freg_reg64(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
dst: X86_64GeneralReg,
|
||||
src1: X86_64FloatReg,
|
||||
src2: X86_64FloatReg,
|
||||
width: FloatWidth,
|
||||
operation: CompareOperation,
|
||||
) {
|
||||
use CompareOperation::*;
|
||||
|
||||
let (arg1, arg2) = match operation {
|
||||
LessThan | LessThanOrEqual => (src1, src2),
|
||||
GreaterThan | GreaterThanOrEqual => (src2, src1),
|
||||
};
|
||||
|
||||
match width {
|
||||
FloatWidth::F32 => cmp_freg32_freg32(buf, arg2, arg1),
|
||||
FloatWidth::F64 => cmp_freg64_freg64(buf, arg2, arg1),
|
||||
}
|
||||
|
||||
match operation {
|
||||
LessThan | GreaterThan => seta_reg64(buf, dst),
|
||||
LessThanOrEqual | GreaterThanOrEqual => setae_reg64(buf, dst),
|
||||
};
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn igt_reg64_reg64_reg64(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
|
@ -1715,6 +1745,14 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
|
|||
{
|
||||
shift_reg64_reg64_reg64(buf, storage_manager, sar_reg64_reg64, dst, src1, src2)
|
||||
}
|
||||
|
||||
fn sqrt_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64FloatReg) {
|
||||
sqrtsd_freg64_freg64(buf, dst, src)
|
||||
}
|
||||
|
||||
fn sqrt_freg32_freg32(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64FloatReg) {
|
||||
sqrtss_freg32_freg32(buf, dst, src)
|
||||
}
|
||||
}
|
||||
|
||||
fn shift_reg64_reg64_reg64<'a, 'r, ASM, CC>(
|
||||
|
@ -2085,6 +2123,90 @@ fn cmp_reg64_reg64(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, src: X86_64Gene
|
|||
binop_reg64_reg64(0x39, buf, dst, src);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn cmp_freg64_freg64(buf: &mut Vec<'_, u8>, src1: X86_64FloatReg, src2: X86_64FloatReg) {
|
||||
let src1_high = src1 as u8 > 7;
|
||||
let src1_mod = src1 as u8 % 8;
|
||||
|
||||
let src2_high = src2 as u8 > 7;
|
||||
let src2_mod = src2 as u8 % 8;
|
||||
|
||||
if src1_high || src2_high {
|
||||
buf.extend([
|
||||
0x66,
|
||||
0x40 | ((src1_high as u8) << 2) | (src2_high as u8),
|
||||
0x0F,
|
||||
0x2E,
|
||||
0xC0 | (src1_mod << 3) | (src2_mod),
|
||||
])
|
||||
} else {
|
||||
buf.extend([0x66, 0x0F, 0x2E, 0xC0 | (src1_mod << 3) | (src2_mod)])
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn cmp_freg32_freg32(buf: &mut Vec<'_, u8>, src1: X86_64FloatReg, src2: X86_64FloatReg) {
|
||||
let src1_high = src1 as u8 > 7;
|
||||
let src1_mod = src1 as u8 % 8;
|
||||
|
||||
let src2_high = src2 as u8 > 7;
|
||||
let src2_mod = src2 as u8 % 8;
|
||||
|
||||
if src1_high || src2_high {
|
||||
buf.extend([
|
||||
0x65,
|
||||
0x40 | ((src1_high as u8) << 2) | (src2_high as u8),
|
||||
0x0F,
|
||||
0x2E,
|
||||
0xC0 | (src1_mod << 3) | (src2_mod),
|
||||
])
|
||||
} else {
|
||||
buf.extend([0x65, 0x0F, 0x2E, 0xC0 | (src1_mod << 3) | (src2_mod)])
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn sqrtsd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64FloatReg) {
|
||||
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,
|
||||
0x51,
|
||||
0xC0 | (dst_mod << 3) | (src_mod),
|
||||
])
|
||||
} else {
|
||||
buf.extend([0xF2, 0x0F, 0x51, 0xC0 | (dst_mod << 3) | (src_mod)])
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn sqrtss_freg32_freg32(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64FloatReg) {
|
||||
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([
|
||||
0xF3,
|
||||
0x40 | ((dst_high as u8) << 2) | (src_high as u8),
|
||||
0x0F,
|
||||
0x51,
|
||||
0xC0 | (dst_mod << 3) | (src_mod),
|
||||
])
|
||||
} else {
|
||||
buf.extend([0xF3, 0x0F, 0x51, 0xC0 | (dst_mod << 3) | (src_mod)])
|
||||
}
|
||||
}
|
||||
|
||||
/// `TEST r/m64,r64` -> AND r64 with r/m64; set SF, ZF, PF according to result.
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
|
@ -2757,6 +2879,12 @@ fn seta_reg64(buf: &mut Vec<'_, u8>, reg: X86_64GeneralReg) {
|
|||
set_reg64_help(0x97, buf, reg);
|
||||
}
|
||||
|
||||
/// `SETAE r/m64` -> Set byte if above or equal (CF=0).
|
||||
#[inline(always)]
|
||||
fn setae_reg64(buf: &mut Vec<'_, u8>, reg: X86_64GeneralReg) {
|
||||
set_reg64_help(0x93, buf, reg);
|
||||
}
|
||||
|
||||
/// `SETLE r/m64` -> Set byte if less or equal (ZF=1 or SF≠ OF).
|
||||
#[inline(always)]
|
||||
fn setle_reg64(buf: &mut Vec<'_, u8>, reg: X86_64GeneralReg) {
|
||||
|
@ -3523,4 +3651,24 @@ mod tests {
|
|||
fn test_push_reg64() {
|
||||
disassembler_test!(push_reg64, |reg| format!("push {}", reg), ALL_GENERAL_REGS);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sqrt_freg64_freg64() {
|
||||
disassembler_test!(
|
||||
sqrtsd_freg64_freg64,
|
||||
|dst, src| format!("sqrtsd {dst}, {src}"),
|
||||
ALL_FLOAT_REGS,
|
||||
ALL_FLOAT_REGS
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sqrt_freg32_freg32() {
|
||||
disassembler_test!(
|
||||
sqrtss_freg32_freg32,
|
||||
|dst, src| format!("sqrtss {dst}, {src}"),
|
||||
ALL_FLOAT_REGS,
|
||||
ALL_FLOAT_REGS
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -751,6 +751,30 @@ trait Backend<'a> {
|
|||
);
|
||||
self.build_num_gte(sym, &args[0], &args[1], &arg_layouts[0])
|
||||
}
|
||||
LowLevel::NumLogUnchecked => {
|
||||
let float_width = match arg_layouts[0] {
|
||||
Layout::F64 => FloatWidth::F64,
|
||||
Layout::F32 => FloatWidth::F32,
|
||||
_ => unreachable!("invalid layout for sqrt"),
|
||||
};
|
||||
|
||||
self.build_fn_call(
|
||||
sym,
|
||||
bitcode::NUM_LOG[float_width].to_string(),
|
||||
args,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
)
|
||||
}
|
||||
LowLevel::NumSqrtUnchecked => {
|
||||
let float_width = match arg_layouts[0] {
|
||||
Layout::F64 => FloatWidth::F64,
|
||||
Layout::F32 => FloatWidth::F32,
|
||||
_ => unreachable!("invalid layout for sqrt"),
|
||||
};
|
||||
|
||||
self.build_num_sqrt(*sym, args[0], float_width);
|
||||
}
|
||||
LowLevel::NumRound => self.build_fn_call(
|
||||
sym,
|
||||
bitcode::NUM_ROUND_F64[IntWidth::I64].to_string(),
|
||||
|
@ -1261,6 +1285,9 @@ trait Backend<'a> {
|
|||
arg_layout: &InLayout<'a>,
|
||||
);
|
||||
|
||||
/// build_sqrt stores the result of `sqrt(src)` into dst.
|
||||
fn build_num_sqrt(&mut self, dst: Symbol, src: Symbol, float_width: FloatWidth);
|
||||
|
||||
/// build_list_len returns the length of a list.
|
||||
fn build_list_len(&mut self, dst: &Symbol, list: &Symbol);
|
||||
|
||||
|
|
|
@ -19,11 +19,11 @@ fn nat_alias() {
|
|||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
i : Num.Nat
|
||||
i = 1
|
||||
i : Num.Nat
|
||||
i = 1
|
||||
|
||||
i
|
||||
"#
|
||||
i
|
||||
"#
|
||||
),
|
||||
1,
|
||||
usize
|
||||
|
@ -31,16 +31,16 @@ fn nat_alias() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn i128_signed_int_alias() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
i : I128
|
||||
i = 128
|
||||
i : I128
|
||||
i = 128
|
||||
|
||||
i
|
||||
"#
|
||||
i
|
||||
"#
|
||||
),
|
||||
128,
|
||||
i128
|
||||
|
@ -71,11 +71,11 @@ fn i32_signed_int_alias() {
|
|||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
i : I32
|
||||
i = 32
|
||||
i : I32
|
||||
i = 32
|
||||
|
||||
i
|
||||
"#
|
||||
i
|
||||
"#
|
||||
),
|
||||
32,
|
||||
i32
|
||||
|
@ -115,7 +115,7 @@ fn i8_signed_int_alias() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
fn i128_hex_int_alias() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -196,7 +196,7 @@ fn i8_hex_int_alias() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
fn u128_signed_int_alias() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -277,7 +277,7 @@ fn u8_signed_int_alias() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
fn u128_hex_int_alias() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -418,7 +418,7 @@ fn character_literal_new_line() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
fn dec_float_alias() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -451,7 +451,7 @@ fn f64_float_alias() {
|
|||
);
|
||||
}
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
fn f32_float_alias() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -468,112 +468,51 @@ fn f32_float_alias() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn f64_sqrt() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Num.sqrtChecked 100 is
|
||||
Ok val -> val
|
||||
Err _ -> -1
|
||||
"#
|
||||
),
|
||||
10.0,
|
||||
f64
|
||||
);
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
fn f64_sqrt_100() {
|
||||
assert_evals_to!("Num.sqrt 100", 10.0, f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
fn f64_sqrt_checked_0() {
|
||||
assert_evals_to!("Num.sqrt 0", 0.0, f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn f64_log() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
Num.log 7.38905609893
|
||||
"#
|
||||
),
|
||||
1.999999999999912,
|
||||
f64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn f64_log_checked_one() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Num.logChecked 1 is
|
||||
Ok val -> val
|
||||
Err _ -> -1
|
||||
"#
|
||||
),
|
||||
0.0,
|
||||
f64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn f64_sqrt_zero() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Num.sqrtChecked 0 is
|
||||
Ok val -> val
|
||||
Err _ -> -1
|
||||
"#
|
||||
),
|
||||
0.0,
|
||||
f64
|
||||
);
|
||||
fn f64_sqrt_checked_positive() {
|
||||
assert_evals_to!("Num.sqrtChecked 100", RocResult::ok(10.0), RocResult<f64, ()>);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn f64_sqrt_checked_negative() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Num.sqrtChecked -1 is
|
||||
Err _ -> 42
|
||||
Ok val -> val
|
||||
"#
|
||||
),
|
||||
42.0,
|
||||
f64
|
||||
);
|
||||
assert_evals_to!("Num.sqrtChecked -1f64", RocResult::err(()), RocResult<f64, ()>);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
fn f64_log() {
|
||||
assert_evals_to!("Num.log 7.38905609893", 1.999999999999912, f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn f64_log_checked_one() {
|
||||
assert_evals_to!("Num.logChecked 1", RocResult::ok(0.0), RocResult<f64, ()>);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn f64_log_checked_zero() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Num.logChecked 0 is
|
||||
Err _ -> 42
|
||||
Ok val -> val
|
||||
"#
|
||||
),
|
||||
42.0,
|
||||
f64
|
||||
);
|
||||
assert_evals_to!("Num.logChecked 0", RocResult::err(()), RocResult<f64, ()>);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn f64_log_negative() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
Num.log -1
|
||||
"#
|
||||
),
|
||||
true,
|
||||
f64,
|
||||
|f: f64| f.is_nan()
|
||||
);
|
||||
assert_evals_to!("Num.log -1", true, f64, |f: f64| f.is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -890,16 +829,20 @@ fn gen_int_neq() {
|
|||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn gen_int_less_than() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
4 < 5
|
||||
"#
|
||||
),
|
||||
true,
|
||||
bool
|
||||
);
|
||||
fn int_less_than() {
|
||||
assert_evals_to!("4 < 5", true, bool);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn float_less_than() {
|
||||
assert_evals_to!("4.0 < 5.0", true, bool);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn float_greater_than() {
|
||||
assert_evals_to!("5.0 > 4.0", true, bool);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -227,7 +227,7 @@ fn is_err() {
|
|||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn roc_result_ok() {
|
||||
fn roc_result_ok_i64() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
|
@ -242,6 +242,26 @@ fn roc_result_ok() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn roc_result_ok_f64() {
|
||||
// NOTE: the dev backend does not currently use float registers when returning a more
|
||||
// complex type, but the rust side does expect it to. Hence this test fails with gen-dev
|
||||
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
result : Result F64 {}
|
||||
result = Ok 42.0
|
||||
|
||||
result
|
||||
"#
|
||||
),
|
||||
RocResult::ok(42.0),
|
||||
RocResult<f64, ()>
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn roc_result_err() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue