Add +r? jets.

This commit is contained in:
Sigilante 2023-09-25 17:31:37 -05:00
parent 4dd009c04c
commit c8b0762a4f
7 changed files with 2558 additions and 26 deletions

View File

@ -23,6 +23,7 @@ criterion = "0.4"
static_assertions = "1.1.0"
ibig = { path = "../ibig-rs" }
assert_no_alloc = "1.1.2"
softfloat_sys = "0.1.3"
[build-dependencies]
cc = "1.0.79"

View File

@ -0,0 +1,558 @@
/** Floating-point jets
*/
use crate::jets;
use crate::jets::JetErr::*;
use crate::jets::util::*;
use crate::jets::util::test::{assert_jet, assert_jet_err, assert_jet_ubig, assert_nary_jet_ubig, init_stack, A};
use crate::mem::NockStack;
use crate::newt::Newt;
use crate::noun::{Atom, IndirectAtom, Noun, D, T, Cell, NO, YES};
use ibig::{UBig, ubig};
use softfloat_sys::*;
use std::io::Write;
crate::gdb!();
const DOUBNAN: u64 = 0x7ff8000000000000;
const DOUBINF: u64 = 0x7ff0000000000000;
const DOUBZERO: u64 = 0x0000000000000000;
#[inline(always)]
fn _nan_test(
a: float64_t
) -> bool {
unsafe {
!f64_eq(a, a)
}
}
#[inline(always)]
fn _nan_unify(
a: float64_t
) -> float64_t {
unsafe {
if _nan_test(a) {
return softfloat_sys::float64_t { v: DOUBNAN };
}
a
}
}
#[inline(always)]
fn _set_rounding(
r: char
) -> u8 {
match r {
'n' => softfloat_round_near_even,
'z' => softfloat_round_minMag,
'u' => softfloat_round_max,
'd' => softfloat_round_min,
// formal fallthrough, should never happen
_ => softfloat_round_near_even,
}
}
pub fn jet_rd_add(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe {
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?;
let b = slot(sam, 3)?.as_atom()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
// @rd MAY be indirect but they are 64 bits
let dat_a = softfloat_sys::float64_t { v: a.as_u64()? };
let dat_b = softfloat_sys::float64_t { v: b.as_u64()? };
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f64_add(dat_a, dat_b));
let x_msb = ((x.v >> 63) & 1) != 0;
let x_2sb = ((x.v >> 62) & 1) != 0;
if x_msb || x_2sb {
Ok(A(stack, &UBig::from(x.v as u64)))
} else {
Ok(D(x.v as u64))
}
}
}
pub fn jet_rd_sub(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe {
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?;
let b = slot(sam, 3)?.as_atom()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
// @rd MAY be indirect but they are 64 bits
let dat_a = softfloat_sys::float64_t { v: a.as_u64()? };
let dat_b = softfloat_sys::float64_t { v: b.as_u64()? };
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f64_sub(dat_a, dat_b));
let x_msb = ((x.v >> 63) & 1) != 0;
let x_2sb = ((x.v >> 62) & 1) != 0;
if x_msb || x_2sb {
Ok(A(stack, &UBig::from(x.v as u64)))
} else {
Ok(D(x.v as u64))
}
}
}
pub fn jet_rd_mul(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe {
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?;
let b = slot(sam, 3)?.as_atom()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
// @rd MAY be indirect but they are 64 bits
let dat_a = softfloat_sys::float64_t { v: a.as_u64()? };
let dat_b = softfloat_sys::float64_t { v: b.as_u64()? };
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f64_mul(dat_a, dat_b));
let x_msb = ((x.v >> 63) & 1) != 0;
let x_2sb = ((x.v >> 62) & 1) != 0;
if x_msb || x_2sb {
Ok(A(stack, &UBig::from(x.v as u64)))
} else {
Ok(D(x.v as u64))
}
}
}
pub fn jet_rd_div(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe {
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?;
let b = slot(sam, 3)?.as_atom()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
// @rd MAY be indirect but they are 64 bits
let dat_a = softfloat_sys::float64_t { v: a.as_u64()? };
let dat_b = softfloat_sys::float64_t { v: b.as_u64()? };
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f64_div(dat_a, dat_b));
let x_msb = ((x.v >> 63) & 1) != 0;
let x_2sb = ((x.v >> 62) & 1) != 0;
if x_msb || x_2sb {
Ok(A(stack, &UBig::from(x.v as u64)))
} else {
Ok(D(x.v as u64))
}
}
}
pub fn jet_rd_sqt(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = sam.as_atom()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float64_t { v: a.as_u64()? };
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f64_sqrt(dat_a));
let x_msb = ((x.v >> 63) & 1) != 0;
let x_2sb = ((x.v >> 62) & 1) != 0;
if x_msb || x_2sb {
Ok(A(stack, &UBig::from(x.v as u64)))
} else {
Ok(D(x.v as u64))
}
}
}
pub fn jet_rd_fma(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?;
let b = slot(sam, 6)?.as_atom()?;
let c = slot(sam, 7)?.as_atom()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float64_t { v: a.as_u64()? };
let dat_b = softfloat_sys::float64_t { v: b.as_u64()? };
let dat_c = softfloat_sys::float64_t { v: c.as_u64()? };
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f64_mulAdd(dat_a, dat_b, dat_c));
let x_msb = ((x.v >> 63) & 1) != 0;
let x_2sb = ((x.v >> 62) & 1) != 0;
if x_msb || x_2sb {
Ok(A(stack, &UBig::from(x.v as u64)))
} else {
Ok(D(x.v as u64))
}
}
}
pub fn jet_rd_lth(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?;
let b = slot(sam, 3)?.as_atom()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float64_t { v: a.as_u64()? };
let dat_b = softfloat_sys::float64_t { v: b.as_u64()? };
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let t = f64_lt(dat_a, dat_b);
if t { Ok(YES) } else { Ok(NO) }
}
}
pub fn jet_rd_lte(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?;
let b = slot(sam, 3)?.as_atom()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float64_t { v: a.as_u64()? };
let dat_b = softfloat_sys::float64_t { v: b.as_u64()? };
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let t = f64_le(dat_a, dat_b);
if t { Ok(YES) } else { Ok(NO) }
}
}
pub fn jet_rd_equ(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?;
let b = slot(sam, 3)?.as_atom()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float64_t { v: a.as_u64()? };
let dat_b = softfloat_sys::float64_t { v: b.as_u64()? };
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let t = f64_eq(dat_a, dat_b);
if t { Ok(YES) } else { Ok(NO) }
}
}
pub fn jet_rd_gte(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?;
let b = slot(sam, 3)?.as_atom()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float64_t { v: a.as_u64()? };
let dat_b = softfloat_sys::float64_t { v: b.as_u64()? };
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let t = f64_le(dat_b, dat_a);
if t { Ok(YES) } else { Ok(NO) }
}
}
pub fn jet_rd_gth(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?;
let b = slot(sam, 3)?.as_atom()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float64_t { v: a.as_u64()? };
let dat_b = softfloat_sys::float64_t { v: b.as_u64()? };
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let t = f64_lt(dat_b, dat_a);
if t { Ok(YES) } else { Ok(NO) }
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::jets::{Jet, JetErr};
use crate::jets::util::test::{assert_jet, assert_jet_err, init_stack};
use crate::noun::D;
use crate::jets::util::test::{assert_noun_eq};
use assert_no_alloc::assert_no_alloc;
use libc::SS;
pub fn assert_jet_in_door(
stack: &mut NockStack,
jet: Jet,
sam: &[fn(&mut NockStack) -> Noun], // regular sample
ctx: &[fn(&mut NockStack) -> Noun], // door sample as context
res: Noun) {
unsafe {
let mut sam: Vec<Noun> = sam.iter().map(|f| f(stack)).collect();
let mut ctx: Vec<Noun> = ctx.iter().map(|f| f(stack)).collect();
let sam = if(sam.len() > 1) { T(stack, &sam) } else { sam[0] };
eprintln!("sam: {:?}", sam);
let ctx = if(ctx.len() > 1) { T(stack, &ctx) } else { ctx[0] };
eprintln!("ctx: {:?}", ctx);
let pay = Cell::new(stack, sam, ctx).as_noun();
eprintln!("pay: {:?}", pay);
let sbj = Cell::new(stack, D(0), pay).as_noun();
eprintln!("sbj: {:?}", sbj);
std::io::stderr().flush().unwrap();
let jet_res = jet(stack, &mut None, sbj).unwrap();
//eprintln!("jet: {:x}\n", jet_res.as_atom().expect("").as_direct().expect("").data());
std::io::stderr().flush().unwrap();
assert_noun_eq(stack, jet_res, res);
}
}
fn atom_0(stack: &mut NockStack) -> Noun {
A(stack, &ubig!(0x0000000000000000))
}
fn atom_1(stack: &mut NockStack) -> Noun {
A(stack, &ubig!(0x3ff0000000000000))
}
fn atom_2(stack: &mut NockStack) -> Noun {
A(stack, &ubig!(0x4000000000000000))
}
fn atom_3(stack: &mut NockStack) -> Noun {
A(stack, &ubig!(0x4008000000000000))
}
fn atom_1_5(stack: &mut NockStack) -> Noun {
A(stack, &ubig!(0x3ff8000000000000))
}
fn atom_1_1(stack: &mut NockStack) -> Noun {
A(stack, &ubig!(0x3ff199999999999a))
}
fn atom_0_8(stack: &mut NockStack) -> Noun {
A(stack, &ubig!(0x3fe999999999999a))
}
fn atom_0_3(stack: &mut NockStack) -> Noun {
A(stack, &ubig!(0x3fd3333333333333))
}
fn r_sample_n(_stack: &mut NockStack) -> Noun {
D('n' as u8 as u64)
}
fn r_sample_z(_stack: &mut NockStack) -> Noun {
D('z' as u8 as u64)
}
fn r_sample_u(_stack: &mut NockStack) -> Noun {
D('u' as u8 as u64)
}
fn r_sample_d(_stack: &mut NockStack) -> Noun {
D('d' as u8 as u64)
}
#[test]
fn test_rd_add() {
let s = &mut init_stack();
let q = &mut init_stack();
assert_jet_in_door(s, jet_rd_add, &[atom_0, atom_0], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x0000000000000000)));
assert_jet_in_door(s, jet_rd_add, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3ff0000000000000)));
assert_jet_in_door(s, jet_rd_add, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x4000000000000000)));
assert_jet_in_door(s, jet_rd_add, &[atom_1, atom_2], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x4008000000000000)));
assert_jet_in_door(s, jet_rd_add, &[atom_2, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x4008000000000000)));
assert_jet_in_door(s, jet_rd_add, &[atom_0_8, atom_0_3], &[atom_0, r_sample_z, atom_0], A(q, &ubig!(0x3ff1999999999999)));
assert_jet_in_door(s, jet_rd_add, &[atom_0_8, atom_0_3], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3ff199999999999a)));
}
#[test]
fn test_rd_sub() {
let s = &mut init_stack();
let q = &mut init_stack();
assert_jet_in_door(s, jet_rd_sub, &[atom_0, atom_0], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x0000000000000000)));
assert_jet_in_door(s, jet_rd_sub, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0xbff0000000000000)));
assert_jet_in_door(s, jet_rd_sub, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x0000000000000000)));
assert_jet_in_door(s, jet_rd_sub, &[atom_1, atom_2], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0xbff0000000000000)));
assert_jet_in_door(s, jet_rd_sub, &[atom_2, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3ff0000000000000)));
assert_jet_in_door(s, jet_rd_sub, &[atom_1_1, atom_0_8], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3fd3333333333334)));
assert_jet_in_door(s, jet_rd_sub, &[atom_1_1, atom_0_3], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3fe999999999999a)));
}
#[test]
fn test_rd_mul() {
let s = &mut init_stack();
let q = &mut init_stack();
assert_jet_in_door(s, jet_rd_mul, &[atom_0, atom_0], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x0000000000000000)));
assert_jet_in_door(s, jet_rd_mul, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x0000000000000000)));
assert_jet_in_door(s, jet_rd_mul, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3ff0000000000000)));
assert_jet_in_door(s, jet_rd_mul, &[atom_1, atom_2], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x4000000000000000)));
assert_jet_in_door(s, jet_rd_mul, &[atom_2, atom_2], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x4010000000000000)));
assert_jet_in_door(s, jet_rd_mul, &[atom_1_5, atom_2], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x4008000000000000)));
assert_jet_in_door(s, jet_rd_mul, &[atom_1_1, atom_0_8], &[atom_0, r_sample_z, atom_0], A(q, &ubig!(0x3fec28f5c28f5c2a)));
assert_jet_in_door(s, jet_rd_mul, &[atom_1_1, atom_0_8], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3fec28f5c28f5c2a)));
assert_jet_in_door(s, jet_rd_mul, &[atom_1_1, atom_0_3], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3fd51eb851eb851f)));
}
#[test]
fn test_rd_div() {
let s = &mut init_stack();
let q = &mut init_stack();
assert_jet_in_door(s, jet_rd_div, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], A(q, &UBig::from(DOUBINF as u64)));
// XX test 0/0
assert_jet_in_door(s, jet_rd_div, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x0000000000000000)));
assert_jet_in_door(s, jet_rd_div, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3ff0000000000000)));
assert_jet_in_door(s, jet_rd_div, &[atom_1, atom_2], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3fe0000000000000)));
assert_jet_in_door(s, jet_rd_div, &[atom_2, atom_2], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3ff0000000000000)));
assert_jet_in_door(s, jet_rd_div, &[atom_1_1, atom_0_8], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3ff6000000000000)));
assert_jet_in_door(s, jet_rd_div, &[atom_1_1, atom_0_3], &[atom_0, r_sample_z, atom_0], A(q, &ubig!(0x400d555555555556)));
assert_jet_in_door(s, jet_rd_div, &[atom_1_1, atom_0_3], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x400d555555555556)));
}
#[test]
fn test_rd_sqt() {
let s = &mut init_stack();
let q = &mut init_stack();
assert_jet_in_door(s, jet_rd_sqt, &[atom_0], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x0000000000000000)));
assert_jet_in_door(s, jet_rd_sqt, &[atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3ff0000000000000)));
assert_jet_in_door(s, jet_rd_sqt, &[atom_2], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3ff6a09e667f3bcd)));
assert_jet_in_door(s, jet_rd_sqt, &[atom_2], &[atom_0, r_sample_z, atom_0], A(q, &ubig!(0x3ff6a09e667f3bcc)));
assert_jet_in_door(s, jet_rd_sqt, &[atom_3], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3ffbb67ae8584caa)));
assert_jet_in_door(s, jet_rd_sqt, &[atom_1_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3ff0c7ebc96a56f6)));
assert_jet_in_door(s, jet_rd_sqt, &[atom_1_1], &[atom_0, r_sample_z, atom_0], A(q, &ubig!(0x3ff0c7ebc96a56f5)));
}
#[test]
fn test_rd_fma() {
let s = &mut init_stack();
let q = &mut init_stack();
assert_jet_in_door(s, jet_rd_fma, &[atom_1, atom_0, atom_0], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x0000000000000000)));
assert_jet_in_door(s, jet_rd_fma, &[atom_0, atom_1, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3ff0000000000000)));
assert_jet_in_door(s, jet_rd_fma, &[atom_1, atom_1, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x4000000000000000)));
assert_jet_in_door(s, jet_rd_fma, &[atom_1, atom_2, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x4008000000000000)));
assert_jet_in_door(s, jet_rd_fma, &[atom_2, atom_2, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x4014000000000000)));
assert_jet_in_door(s, jet_rd_fma, &[atom_1_1, atom_0_8, atom_0_3], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3ff2e147ae147ae2)));
assert_jet_in_door(s, jet_rd_fma, &[atom_1_1, atom_0_8, atom_0_3], &[atom_0, r_sample_z, atom_0], A(q, &ubig!(0x3ff2e147ae147ae1)));
}
#[test]
fn test_rd_lth() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rd_lth, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rd_lth, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], YES);
assert_jet_in_door(s, jet_rd_lth, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], NO);
}
#[test]
fn test_rd_lte() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rd_lte, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rd_lte, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], YES);
assert_jet_in_door(s, jet_rd_lte, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], YES);
}
#[test]
fn test_rd_equ() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rd_equ, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rd_equ, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rd_equ, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], YES);
}
#[test]
fn test_rd_gte() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rd_gte, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], YES);
assert_jet_in_door(s, jet_rd_gte, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rd_gte, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], YES);
}
#[test]
fn test_rd_gth() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rd_gth, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], YES);
assert_jet_in_door(s, jet_rd_gth, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rd_gth, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], NO);
}
}

View File

@ -0,0 +1,510 @@
/** Floating-point jets
*/
use crate::jets;
use crate::jets::JetErr::*;
use crate::jets::util::*;
use crate::jets::util::test::{assert_jet, assert_jet_err, assert_jet_ubig, assert_nary_jet_ubig, init_stack, A};
use crate::mem::NockStack;
use crate::newt::Newt;
use crate::noun::{Atom, IndirectAtom, Noun, D, T, Cell, NO, YES};
use ibig::{UBig, ubig};
use softfloat_sys::*;
use std::io::Write;
crate::gdb!();
const HALFNAN: u16 = 0x7e00;
const HALFINF: u16 = 0x7c00;
const HALFZERO: u16 = 0x0000;
#[inline(always)]
fn _nan_test(
a: float16_t
) -> bool {
unsafe {
!f16_eq(a, a)
}
}
#[inline(always)]
fn _nan_unify(
a: float16_t
) -> float16_t {
unsafe {
if _nan_test(a) {
return softfloat_sys::float16_t { v: HALFNAN};
}
a
}
}
#[inline(always)]
fn _set_rounding(
r: char
) -> u8 {
match r {
'n' => softfloat_round_near_even,
'z' => softfloat_round_minMag,
'u' => softfloat_round_max,
'd' => softfloat_round_min,
// formal fallthrough, should never happen
_ => softfloat_round_near_even,
}
}
pub fn jet_rh_add(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?.as_direct()?;
let b = slot(sam, 3)?.as_atom()?.as_direct()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float16_t { v: a.data() as u16};
let dat_b = softfloat_sys::float16_t { v: b.data() as u16};
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f16_add(dat_a, dat_b));
Ok(D(x.v as u64))
}
}
pub fn jet_rh_sub(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?.as_direct()?;
let b = slot(sam, 3)?.as_atom()?.as_direct()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float16_t { v: a.data() as u16};
let dat_b = softfloat_sys::float16_t { v: b.data() as u16};
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f16_sub(dat_a, dat_b));
Ok(D(x.v as u64))
}
}
pub fn jet_rh_mul(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?.as_direct()?;
let b = slot(sam, 3)?.as_atom()?.as_direct()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float16_t { v: a.data() as u16};
let dat_b = softfloat_sys::float16_t { v: b.data() as u16};
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f16_mul(dat_a, dat_b));
Ok(D(x.v as u64))
}
}
pub fn jet_rh_div(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?.as_direct()?;
let b = slot(sam, 3)?.as_atom()?.as_direct()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float16_t { v: a.data() as u16};
let dat_b = softfloat_sys::float16_t { v: b.data() as u16};
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f16_div(dat_a, dat_b));
Ok(D(x.v as u64))
}
}
pub fn jet_rh_sqt(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
eprintln!("»sam: {:?}", sam);
let a = sam.as_atom()?.as_direct()?;
eprintln!("»a: {:?}", a.as_noun());
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float16_t { v: a.data() as u16};
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f16_sqrt(dat_a));
Ok(D(x.v as u64))
}
}
pub fn jet_rh_fma(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?.as_direct()?;
let b = slot(sam, 6)?.as_atom()?.as_direct()?;
let c = slot(sam, 7)?.as_atom()?.as_direct()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float16_t { v: a.data() as u16};
let dat_b = softfloat_sys::float16_t { v: b.data() as u16};
let dat_c = softfloat_sys::float16_t { v: c.data() as u16};
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f16_mulAdd(dat_a, dat_b, dat_c));
Ok(D(x.v as u64))
}
}
pub fn jet_rh_lth(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?.as_direct()?;
let b = slot(sam, 3)?.as_atom()?.as_direct()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float16_t { v: a.data() as u16};
let dat_b = softfloat_sys::float16_t { v: b.data() as u16};
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let t = f16_lt(dat_a, dat_b);
if t { Ok(YES) } else { Ok(NO) }
}
}
pub fn jet_rh_lte(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?.as_direct()?;
let b = slot(sam, 3)?.as_atom()?.as_direct()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float16_t { v: a.data() as u16};
let dat_b = softfloat_sys::float16_t { v: b.data() as u16};
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let t = f16_le(dat_a, dat_b);
if t { Ok(YES) } else { Ok(NO) }
}
}
pub fn jet_rh_equ(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?.as_direct()?;
let b = slot(sam, 3)?.as_atom()?.as_direct()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float16_t { v: a.data() as u16};
let dat_b = softfloat_sys::float16_t { v: b.data() as u16};
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let t = f16_eq(dat_a, dat_b);
if t { Ok(YES) } else { Ok(NO) }
}
}
pub fn jet_rh_gte(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?.as_direct()?;
let b = slot(sam, 3)?.as_atom()?.as_direct()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float16_t { v: a.data() as u16};
let dat_b = softfloat_sys::float16_t { v: b.data() as u16};
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let t = f16_le(dat_b, dat_a);
if t { Ok(YES) } else { Ok(NO) }
}
}
pub fn jet_rh_gth(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?.as_direct()?;
let b = slot(sam, 3)?.as_atom()?.as_direct()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float16_t { v: a.data() as u16};
let dat_b = softfloat_sys::float16_t { v: b.data() as u16};
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let t = f16_lt(dat_b, dat_a);
if t { Ok(YES) } else { Ok(NO) }
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::jets::{Jet, JetErr};
use crate::jets::util::test::{assert_jet, assert_jet_err, init_stack};
use crate::noun::D;
use crate::jets::util::test::{assert_noun_eq};
use assert_no_alloc::assert_no_alloc;
pub fn assert_jet_in_door(
stack: &mut NockStack,
jet: Jet,
sam: &[fn(&mut NockStack) -> Noun], // regular sample
ctx: &[fn(&mut NockStack) -> Noun], // door sample as context
res: Noun) {
unsafe {
let mut sam: Vec<Noun> = sam.iter().map(|f| f(stack)).collect();
let mut ctx: Vec<Noun> = ctx.iter().map(|f| f(stack)).collect();
let sam = if(sam.len() > 1) { T(stack, &sam) } else { sam[0] };
eprintln!("sam: {:?}", sam);
let ctx = if(ctx.len() > 1) { T(stack, &ctx) } else { ctx[0] };
eprintln!("ctx: {:?}", ctx);
let pay = Cell::new(stack, sam, ctx).as_noun();
eprintln!("pay: {:?}", pay);
let sbj = Cell::new(stack, D(0), pay).as_noun();
eprintln!("sbj: {:?}", sbj);
std::io::stderr().flush().unwrap();
let jet_res = jet(stack, &mut None, sbj).unwrap();
eprintln!("jet: {:x}\n", jet_res.as_atom().expect("").as_direct().expect("").data());
std::io::stderr().flush().unwrap();
assert_noun_eq(stack, jet_res, res);
}
}
fn atom_0(_stack: &mut NockStack) -> Noun {
D(0x0000)
}
fn atom_1(_stack: &mut NockStack) -> Noun {
D(0x3c00)
}
fn atom_2(_stack: &mut NockStack) -> Noun {
D(0x4000)
}
fn atom_3(_stack: &mut NockStack) -> Noun {
D(0x4200)
}
fn atom_1_5(_stack: &mut NockStack) -> Noun {
D(0x3e00)
}
fn atom_1_1(_stack: &mut NockStack) -> Noun {
D(0x3c66)
}
fn atom_0_8(_stack: &mut NockStack) -> Noun {
D(0x3a66)
}
fn atom_0_3(_stack: &mut NockStack) -> Noun {
D(0x34cd)
}
fn r_sample_n(_stack: &mut NockStack) -> Noun {
D('n' as u8 as u64)
}
fn r_sample_z(_stack: &mut NockStack) -> Noun {
D('z' as u8 as u64)
}
fn r_sample_u(_stack: &mut NockStack) -> Noun {
D('u' as u8 as u64)
}
fn r_sample_d(_stack: &mut NockStack) -> Noun {
D('d' as u8 as u64)
}
#[test]
fn test_rh_add() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rh_add, &[atom_0, atom_0], &[atom_0, r_sample_n, atom_0], D(0x0000));
assert_jet_in_door(s, jet_rh_add, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], D(0x3c00));
assert_jet_in_door(s, jet_rh_add, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], D(0x4000));
assert_jet_in_door(s, jet_rh_add, &[atom_1, atom_2], &[atom_0, r_sample_n, atom_0], D(0x4200));
assert_jet_in_door(s, jet_rh_add, &[atom_2, atom_1], &[atom_0, r_sample_n, atom_0], D(0x4200));
assert_jet_in_door(s, jet_rh_add, &[atom_0_8, atom_0_3], &[atom_0, r_sample_n, atom_0], D(0x3c66));
}
#[test]
fn test_rh_sub() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rh_sub, &[atom_0, atom_0], &[atom_0, r_sample_n, atom_0], D(0x0000));
assert_jet_in_door(s, jet_rh_sub, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], D(0xbc00));
assert_jet_in_door(s, jet_rh_sub, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], D(0x0000));
assert_jet_in_door(s, jet_rh_sub, &[atom_1, atom_2], &[atom_0, r_sample_n, atom_0], D(0xbc00));
assert_jet_in_door(s, jet_rh_sub, &[atom_2, atom_1], &[atom_0, r_sample_n, atom_0], D(0x3c00));
assert_jet_in_door(s, jet_rh_sub, &[atom_1_1, atom_0_8], &[atom_0, r_sample_n, atom_0], D(0x34cc));
assert_jet_in_door(s, jet_rh_sub, &[atom_1_1, atom_0_3], &[atom_0, r_sample_n, atom_0], D(0x3a66));
}
#[test]
fn test_rh_mul() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rh_mul, &[atom_0, atom_0], &[atom_0, r_sample_n, atom_0], D(0x0000));
assert_jet_in_door(s, jet_rh_mul, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], D(0x0000));
assert_jet_in_door(s, jet_rh_mul, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], D(0x3c00));
assert_jet_in_door(s, jet_rh_mul, &[atom_1, atom_2], &[atom_0, r_sample_n, atom_0], D(0x4000));
assert_jet_in_door(s, jet_rh_mul, &[atom_2, atom_2], &[atom_0, r_sample_n, atom_0], D(0x4400));
assert_jet_in_door(s, jet_rh_mul, &[atom_1_5, atom_2], &[atom_0, r_sample_n, atom_0], D(0x4200));
assert_jet_in_door(s, jet_rh_mul, &[atom_1_1, atom_0_8], &[atom_0, r_sample_z, atom_0], D(0x3b09));
assert_jet_in_door(s, jet_rh_mul, &[atom_1_1, atom_0_8], &[atom_0, r_sample_u, atom_0], D(0x3b0a));
assert_jet_in_door(s, jet_rh_mul, &[atom_1_1, atom_0_3], &[atom_0, r_sample_n, atom_0], D(0x3547));
}
#[test]
fn test_rh_div() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rh_div, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], D(HALFINF as u64));
// XX test 0/0
assert_jet_in_door(s, jet_rh_div, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], D(0x0000));
assert_jet_in_door(s, jet_rh_div, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], D(0x3c00));
assert_jet_in_door(s, jet_rh_div, &[atom_1, atom_2], &[atom_0, r_sample_n, atom_0], D(0x3800));
assert_jet_in_door(s, jet_rh_div, &[atom_2, atom_2], &[atom_0, r_sample_n, atom_0], D(0x3c00));
assert_jet_in_door(s, jet_rh_div, &[atom_1_1, atom_0_8], &[atom_0, r_sample_z, atom_0], D(0x3d7f));
assert_jet_in_door(s, jet_rh_div, &[atom_1_1, atom_0_8], &[atom_0, r_sample_n, atom_0], D(0x3d80));
assert_jet_in_door(s, jet_rh_div, &[atom_1_1, atom_0_3], &[atom_0, r_sample_n, atom_0], D(0x4354));
assert_jet_in_door(s, jet_rh_div, &[atom_1_1, atom_0_3], &[atom_0, r_sample_u, atom_0], D(0x4355));
}
#[test]
fn test_rh_sqt() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rh_sqt, &[atom_0], &[atom_0, r_sample_n, atom_0], D(0x0000));
assert_jet_in_door(s, jet_rh_sqt, &[atom_1], &[atom_0, r_sample_n, atom_0], D(0x3c00));
assert_jet_in_door(s, jet_rh_sqt, &[atom_2], &[atom_0, r_sample_n, atom_0], D(0x3da8));
assert_jet_in_door(s, jet_rh_sqt, &[atom_3], &[atom_0, r_sample_n, atom_0], D(0x3eee));
assert_jet_in_door(s, jet_rh_sqt, &[atom_3], &[atom_0, r_sample_z, atom_0], D(0x3eed));
assert_jet_in_door(s, jet_rh_sqt, &[atom_1_1], &[atom_0, r_sample_n, atom_0], D(0x3c32));
assert_jet_in_door(s, jet_rh_sqt, &[atom_1_1], &[atom_0, r_sample_z, atom_0], D(0x3c31));
}
#[test]
fn test_rh_fma() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rh_fma, &[atom_1, atom_0, atom_0], &[atom_0, r_sample_n, atom_0], D(0x0000));
assert_jet_in_door(s, jet_rh_fma, &[atom_0, atom_1, atom_1], &[atom_0, r_sample_n, atom_0], D(0x3c00));
assert_jet_in_door(s, jet_rh_fma, &[atom_1, atom_1, atom_1], &[atom_0, r_sample_n, atom_0], D(0x4000));
assert_jet_in_door(s, jet_rh_fma, &[atom_1, atom_2, atom_1], &[atom_0, r_sample_n, atom_0], D(0x4200));
assert_jet_in_door(s, jet_rh_fma, &[atom_2, atom_2, atom_1], &[atom_0, r_sample_n, atom_0], D(0x4500));
assert_jet_in_door(s, jet_rh_fma, &[atom_1_1, atom_0_8, atom_0_3], &[atom_0, r_sample_n, atom_0], D(0x3cb8));
assert_jet_in_door(s, jet_rh_fma, &[atom_1_1, atom_0_8, atom_0_3], &[atom_0, r_sample_z, atom_0], D(0x3cb7));
}
#[test]
fn test_rh_lth() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rh_lth, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rh_lth, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], YES);
assert_jet_in_door(s, jet_rh_lth, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], NO);
}
#[test]
fn test_rh_lte() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rh_lte, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rh_lte, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], YES);
assert_jet_in_door(s, jet_rh_lte, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], YES);
}
#[test]
fn test_rh_equ() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rh_equ, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rh_equ, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rh_equ, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], YES);
}
#[test]
fn test_rh_gte() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rh_gte, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], YES);
assert_jet_in_door(s, jet_rh_gte, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rh_gte, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], YES);
}
#[test]
fn test_rh_gth() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rh_gth, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], YES);
assert_jet_in_door(s, jet_rh_gth, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rh_gth, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], NO);
}
}

View File

@ -0,0 +1,577 @@
/** Floating-point jets
*/
use crate::jets;
use crate::jets::JetErr::*;
use crate::jets::util::*;
use crate::jets::util::test::{assert_jet, assert_jet_err, assert_jet_ubig, assert_nary_jet_ubig, init_stack, A};
use crate::mem::NockStack;
use crate::newt::Newt;
use crate::noun::{Atom, IndirectAtom, Noun, D, T, Cell, NO, YES};
use ibig::{UBig, ubig};
use softfloat_sys::*;
use std::io::Write;
crate::gdb!();
const QUADNAN: [u64; 2] = [0x0000000000000000, 0x7fff800000000000];
const QUADINF: [u64; 2] = [0x0000000000000000, 0x7fff000000000000];
const QUADZERO: [u64; 2] = [0x0000000000000000, 0x0000000000000000];
#[inline(always)]
fn _nan_test(
a: float128_t
) -> bool {
unsafe {
!f128_eq(a, a)
}
}
#[inline(always)]
fn _nan_unify(
a: float128_t
) -> float128_t {
unsafe {
if _nan_test(a) {
return softfloat_sys::float128_t { v: QUADNAN };
}
a
}
}
#[inline(always)]
fn _set_rounding(
r: char
) -> u8 {
match r {
'n' => softfloat_round_near_even,
'z' => softfloat_round_minMag,
'u' => softfloat_round_max,
'd' => softfloat_round_min,
// formal fallthrough, should never happen
_ => softfloat_round_near_even,
}
}
pub fn jet_rq_add(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe {
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?;
let b = slot(sam, 3)?.as_atom()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
// @rq MAY be indirect but they are 128 bits
let dat_a = softfloat_sys::float128_t { v: a.as_u128_pair()? };
let dat_b = softfloat_sys::float128_t { v: b.as_u128_pair()? };
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f128_add(dat_a, dat_b));
let x1_msb = (x.v[1] | 0) != 0;
let x2_msb = ((x.v[0] >> 63) & 1) != 0;
let x2_2sb = ((x.v[0] >> 62) & 1) != 0;
if x1_msb || x2_msb || x2_2sb {
let hi = (x.v[1] as u128) << 64;
let lo = x.v[0] as u128;
Ok(A(stack, &UBig::from(hi | lo)))
} else {
Ok(D(x.v[0]))
}
}
}
pub fn jet_rq_sub(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe {
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?;
let b = slot(sam, 3)?.as_atom()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
// @rq MAY be indirect but they are 128 bits
let dat_a = softfloat_sys::float128_t { v: a.as_u128_pair()? };
let dat_b = softfloat_sys::float128_t { v: b.as_u128_pair()? };
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f128_sub(dat_a, dat_b));
let x1_msb = (x.v[1] | 0) != 0;
let x2_msb = ((x.v[0] >> 63) & 1) != 0;
let x2_2sb = ((x.v[0] >> 62) & 1) != 0;
if x1_msb || x2_msb || x2_2sb {
let hi = (x.v[1] as u128) << 64;
let lo = x.v[0] as u128;
Ok(A(stack, &UBig::from(hi | lo)))
} else {
Ok(D(x.v[0]))
}
}
}
pub fn jet_rq_mul(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe {
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?;
let b = slot(sam, 3)?.as_atom()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
// @rq MAY be indirect but they are 128 bits
let dat_a = softfloat_sys::float128_t { v: a.as_u128_pair()? };
let dat_b = softfloat_sys::float128_t { v: b.as_u128_pair()? };
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f128_mul(dat_a, dat_b));
let x1_msb = (x.v[1] | 0) != 0;
let x2_msb = ((x.v[0] >> 63) & 1) != 0;
let x2_2sb = ((x.v[0] >> 62) & 1) != 0;
if x1_msb || x2_msb || x2_2sb {
let hi = (x.v[1] as u128) << 64;
let lo = x.v[0] as u128;
Ok(A(stack, &UBig::from(hi | lo)))
} else {
Ok(D(x.v[0]))
}
}
}
pub fn jet_rq_div(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe {
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?;
let b = slot(sam, 3)?.as_atom()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
// @rq MAY be indirect but they are 128 bits
let dat_a = softfloat_sys::float128_t { v: a.as_u128_pair()? };
let dat_b = softfloat_sys::float128_t { v: b.as_u128_pair()? };
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f128_div(dat_a, dat_b));
let x1_msb = (x.v[1] | 0) != 0;
let x2_msb = ((x.v[0] >> 63) & 1) != 0;
let x2_2sb = ((x.v[0] >> 62) & 1) != 0;
if x1_msb || x2_msb || x2_2sb {
let hi = (x.v[1] as u128) << 64;
let lo = x.v[0] as u128;
Ok(A(stack, &UBig::from(hi | lo)))
} else {
Ok(D(x.v[0]))
}
}
}
pub fn jet_rq_sqt(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = sam.as_atom()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float128_t { v: a.as_u128_pair()? };
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f128_sqrt(dat_a));
let x1_msb = (x.v[1] | 0) != 0;
let x2_msb = ((x.v[0] >> 63) & 1) != 0;
let x2_2sb = ((x.v[0] >> 62) & 1) != 0;
if x1_msb || x2_msb || x2_2sb {
let hi = (x.v[1] as u128) << 64;
let lo = x.v[0] as u128;
Ok(A(stack, &UBig::from(hi | lo)))
} else {
Ok(D(x.v[0]))
}
}
}
pub fn jet_rq_fma(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?;
let b = slot(sam, 6)?.as_atom()?;
let c = slot(sam, 7)?.as_atom()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float128_t { v: a.as_u128_pair()? };
let dat_b = softfloat_sys::float128_t { v: b.as_u128_pair()? };
let dat_c = softfloat_sys::float128_t { v: c.as_u128_pair()? };
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f128_mulAdd(dat_a, dat_b, dat_c));
let x1_msb = (x.v[1] | 0) != 0;
let x2_msb = ((x.v[0] >> 63) & 1) != 0;
let x2_2sb = ((x.v[0] >> 62) & 1) != 0;
if x1_msb || x2_msb || x2_2sb {
let hi = (x.v[1] as u128) << 64;
let lo = x.v[0] as u128;
Ok(A(stack, &UBig::from(hi | lo)))
} else {
Ok(D(x.v[0]))
}
}
}
pub fn jet_rq_lth(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?;
let b = slot(sam, 3)?.as_atom()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float128_t { v: a.as_u128_pair()? };
let dat_b = softfloat_sys::float128_t { v: b.as_u128_pair()? };
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let t = f128_lt(dat_a, dat_b);
if t { Ok(YES) } else { Ok(NO) }
}
}
pub fn jet_rq_lte(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?;
let b = slot(sam, 3)?.as_atom()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float128_t { v: a.as_u128_pair()? };
let dat_b = softfloat_sys::float128_t { v: b.as_u128_pair()? };
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let t = f128_le(dat_a, dat_b);
if t { Ok(YES) } else { Ok(NO) }
}
}
pub fn jet_rq_equ(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?;
let b = slot(sam, 3)?.as_atom()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float128_t { v: a.as_u128_pair()? };
let dat_b = softfloat_sys::float128_t { v: b.as_u128_pair()? };
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let t = f128_eq(dat_a, dat_b);
if t { Ok(YES) } else { Ok(NO) }
}
}
pub fn jet_rq_gte(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?;
let b = slot(sam, 3)?.as_atom()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float128_t { v: a.as_u128_pair()? };
let dat_b = softfloat_sys::float128_t { v: b.as_u128_pair()? };
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let t = f128_le(dat_b, dat_a);
if t { Ok(YES) } else { Ok(NO) }
}
}
pub fn jet_rq_gth(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?;
let b = slot(sam, 3)?.as_atom()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float128_t { v: a.as_u128_pair()? };
let dat_b = softfloat_sys::float128_t { v: b.as_u128_pair()? };
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let t = f128_lt(dat_b, dat_a);
if t { Ok(YES) } else { Ok(NO) }
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::jets::{Jet, JetErr};
use crate::jets::util::test::{assert_jet, assert_jet_err, init_stack};
use crate::noun::D;
use crate::jets::util::test::{assert_noun_eq};
use assert_no_alloc::assert_no_alloc;
use libc::SS;
pub fn assert_jet_in_door(
stack: &mut NockStack,
jet: Jet,
sam: &[fn(&mut NockStack) -> Noun], // regular sample
ctx: &[fn(&mut NockStack) -> Noun], // door sample as context
res: Noun) {
unsafe {
let mut sam: Vec<Noun> = sam.iter().map(|f| f(stack)).collect();
let mut ctx: Vec<Noun> = ctx.iter().map(|f| f(stack)).collect();
let sam = if(sam.len() > 1) { T(stack, &sam) } else { sam[0] };
eprintln!("sam: {:?}", sam);
let ctx = if(ctx.len() > 1) { T(stack, &ctx) } else { ctx[0] };
eprintln!("ctx: {:?}", ctx);
let pay = Cell::new(stack, sam, ctx).as_noun();
eprintln!("pay: {:?}", pay);
let sbj = Cell::new(stack, D(0), pay).as_noun();
eprintln!("sbj: {:?}", sbj);
std::io::stderr().flush().unwrap();
let jet_res = jet(stack, &mut None, sbj).unwrap();
//eprintln!("jet: {:x}\n", jet_res.as_atom().expect("").as_direct().expect("").data());
std::io::stderr().flush().unwrap();
assert_noun_eq(stack, jet_res, res);
}
}
fn atom_0(stack: &mut NockStack) -> Noun {
A(stack, &ubig!(0x00000000000000000000000000000000))
}
fn atom_1(stack: &mut NockStack) -> Noun {
A(stack, &ubig!(0x3fff0000000000000000000000000000))
}
fn atom_2(stack: &mut NockStack) -> Noun {
A(stack, &ubig!(0x40000000000000000000000000000000))
}
fn atom_3(stack: &mut NockStack) -> Noun {
A(stack, &ubig!(0x40008000000000000000000000000000))
}
fn atom_1_5(stack: &mut NockStack) -> Noun {
A(stack, &ubig!(0x3fff8000000000000000000000000000))
}
fn atom_1_1(stack: &mut NockStack) -> Noun {
A(stack, &ubig!(0x3fff199999999999999999999999999a))
}
fn atom_0_8(stack: &mut NockStack) -> Noun {
A(stack, &ubig!(0x3ffe999999999999999999999999999a))
}
fn atom_0_3(stack: &mut NockStack) -> Noun {
A(stack, &ubig!(0x3ffd3333333333333333333333333333))
}
fn r_sample_n(_stack: &mut NockStack) -> Noun {
D('n' as u8 as u64)
}
fn r_sample_z(_stack: &mut NockStack) -> Noun {
D('z' as u8 as u64)
}
fn r_sample_u(_stack: &mut NockStack) -> Noun {
D('u' as u8 as u64)
}
fn r_sample_d(_stack: &mut NockStack) -> Noun {
D('d' as u8 as u64)
}
#[test]
fn test_rq_add() {
let s = &mut init_stack();
let q = &mut init_stack();
assert_jet_in_door(s, jet_rq_add, &[atom_0, atom_0], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x00000000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_add, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3fff0000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_add, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x40000000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_add, &[atom_1, atom_2], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x40008000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_add, &[atom_2, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x40008000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_add, &[atom_0_8, atom_0_3], &[atom_0, r_sample_z, atom_0], A(q, &ubig!(0x3fff1999999999999999999999999999)));
assert_jet_in_door(s, jet_rq_add, &[atom_0_8, atom_0_3], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3fff199999999999999999999999999a)));
}
#[test]
fn test_rq_sub() {
let s = &mut init_stack();
let q = &mut init_stack();
assert_jet_in_door(s, jet_rq_sub, &[atom_0, atom_0], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x00000000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_sub, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0xbfff0000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_sub, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x00000000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_sub, &[atom_1, atom_2], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0xbfff0000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_sub, &[atom_2, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3fff0000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_sub, &[atom_1_1, atom_0_8], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3ffd3333333333333333333333333334)));
assert_jet_in_door(s, jet_rq_sub, &[atom_1_1, atom_0_3], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3ffe999999999999999999999999999a)));
}
#[test]
fn test_rq_mul() {
let s = &mut init_stack();
let q = &mut init_stack();
assert_jet_in_door(s, jet_rq_mul, &[atom_0, atom_0], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x00000000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_mul, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x00000000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_mul, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3fff0000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_mul, &[atom_1, atom_2], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x40000000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_mul, &[atom_2, atom_2], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x40010000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_mul, &[atom_1_5, atom_2], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x40008000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_mul, &[atom_1_1, atom_0_8], &[atom_0, r_sample_z, atom_0], A(q, &ubig!(0x3ffec28f5c28f5c28f5c28f5c28f5c2a)));
assert_jet_in_door(s, jet_rq_mul, &[atom_1_1, atom_0_8], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3ffec28f5c28f5c28f5c28f5c28f5c2a)));
assert_jet_in_door(s, jet_rq_mul, &[atom_1_1, atom_0_3], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3ffd51eb851eb851eb851eb851eb851f)));
assert_jet_in_door(s, jet_rq_mul, &[atom_1_1, atom_0_3], &[atom_0, r_sample_z, atom_0], A(q, &ubig!(0x3ffd51eb851eb851eb851eb851eb851e)));
}
#[test]
fn test_rq_div() {
let s = &mut init_stack();
let q = &mut init_stack();
assert_jet_in_door(s, jet_rq_div, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], A(q, &UBig::from((QUADINF[1] as u128) << 64)));
// XX test 0/0
assert_jet_in_door(s, jet_rq_div, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x00000000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_div, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3fff0000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_div, &[atom_1, atom_2], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3ffe0000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_div, &[atom_2, atom_2], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3fff0000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_div, &[atom_1_1, atom_0_8], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3fff6000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_div, &[atom_1_1, atom_0_3], &[atom_0, r_sample_z, atom_0], A(q, &ubig!(0x4000d555555555555555555555555556)));
assert_jet_in_door(s, jet_rq_div, &[atom_1_1, atom_0_3], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x4000d555555555555555555555555556)));
}
#[test]
fn test_rq_sqt() {
let s = &mut init_stack();
let q = &mut init_stack();
assert_jet_in_door(s, jet_rq_sqt, &[atom_0], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x00000000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_sqt, &[atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3fff0000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_sqt, &[atom_2], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3fff6a09e667f3bcc908b2fb1366ea95)));
assert_jet_in_door(s, jet_rq_sqt, &[atom_2], &[atom_0, r_sample_z, atom_0], A(q, &ubig!(0x3fff6a09e667f3bcc908b2fb1366ea95)));
assert_jet_in_door(s, jet_rq_sqt, &[atom_3], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3fffbb67ae8584caa73b25742d7078b8)));
assert_jet_in_door(s, jet_rq_sqt, &[atom_1_1], &[atom_0, r_sample_z, atom_0], A(q, &ubig!(0x3fff0c7ebc96a56f59f61213380ea638)));
assert_jet_in_door(s, jet_rq_sqt, &[atom_1_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3fff0c7ebc96a56f59f61213380ea638)));
}
#[test]
fn test_rq_fma() {
let s = &mut init_stack();
let q = &mut init_stack();
assert_jet_in_door(s, jet_rq_fma, &[atom_1, atom_0, atom_0], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x00000000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_fma, &[atom_0, atom_1, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3fff0000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_fma, &[atom_1, atom_1, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x40000000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_fma, &[atom_1, atom_2, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x40008000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_fma, &[atom_2, atom_2, atom_1], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x40014000000000000000000000000000)));
assert_jet_in_door(s, jet_rq_fma, &[atom_1_1, atom_0_8, atom_0_3], &[atom_0, r_sample_n, atom_0], A(q, &ubig!(0x3fff2e147ae147ae147ae147ae147ae2)));
assert_jet_in_door(s, jet_rq_fma, &[atom_1_1, atom_0_8, atom_0_3], &[atom_0, r_sample_z, atom_0], A(q, &ubig!(0x3fff2e147ae147ae147ae147ae147ae1)));
}
#[test]
fn test_rq_lth() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rq_lth, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rq_lth, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], YES);
assert_jet_in_door(s, jet_rq_lth, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], NO);
}
#[test]
fn test_rq_lte() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rq_lte, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rq_lte, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], YES);
assert_jet_in_door(s, jet_rq_lte, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], YES);
}
#[test]
fn test_rq_equ() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rq_equ, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rq_equ, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rq_equ, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], YES);
}
#[test]
fn test_rq_gte() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rq_gte, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], YES);
assert_jet_in_door(s, jet_rq_gte, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rq_gte, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], YES);
}
#[test]
fn test_rq_gth() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rq_gth, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], YES);
assert_jet_in_door(s, jet_rq_gth, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rq_gth, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], NO);
}
}

View File

@ -0,0 +1,504 @@
/** Floating-point jets
*/
use crate::jets;
use crate::jets::JetErr::*;
use crate::jets::util::*;
use crate::jets::util::test::{assert_jet, assert_jet_err, assert_jet_ubig, assert_nary_jet_ubig, init_stack, A};
use crate::mem::NockStack;
use crate::newt::Newt;
use crate::noun::{Atom, IndirectAtom, Noun, D, T, Cell, NO, YES};
use ibig::{UBig, ubig};
use softfloat_sys::*;
use std::io::Write;
crate::gdb!();
const SINGNAN: u32 = 0x7fc00000;
const SINGINF: u32 = 0x7f800000;
const SINGZERO: u32 = 0x00000000;
#[inline(always)]
fn _nan_test(
a: float32_t
) -> bool {
unsafe {
!f32_eq(a, a)
}
}
#[inline(always)]
fn _nan_unify(
a: float32_t
) -> float32_t {
unsafe {
if _nan_test(a) {
return softfloat_sys::float32_t { v: SINGNAN };
}
a
}
}
#[inline(always)]
fn _set_rounding(
r: char
) -> u8 {
match r {
'n' => softfloat_round_near_even,
'z' => softfloat_round_minMag,
'u' => softfloat_round_max,
'd' => softfloat_round_min,
// formal fallthrough, should never happen
_ => softfloat_round_near_even,
}
}
pub fn jet_rs_add(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?.as_direct()?;
let b = slot(sam, 3)?.as_atom()?.as_direct()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float32_t { v: a.data() as u32};
let dat_b = softfloat_sys::float32_t { v: b.data() as u32};
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f32_add(dat_a, dat_b));
Ok(D(x.v as u64))
}
}
pub fn jet_rs_sub(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?.as_direct()?;
let b = slot(sam, 3)?.as_atom()?.as_direct()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float32_t { v: a.data() as u32};
let dat_b = softfloat_sys::float32_t { v: b.data() as u32};
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f32_sub(dat_a, dat_b));
Ok(D(x.v as u64))
}
}
pub fn jet_rs_mul(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?.as_direct()?;
let b = slot(sam, 3)?.as_atom()?.as_direct()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float32_t { v: a.data() as u32};
let dat_b = softfloat_sys::float32_t { v: b.data() as u32};
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f32_mul(dat_a, dat_b));
Ok(D(x.v as u64))
}
}
pub fn jet_rs_div(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?.as_direct()?;
let b = slot(sam, 3)?.as_atom()?.as_direct()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float32_t { v: a.data() as u32};
let dat_b = softfloat_sys::float32_t { v: b.data() as u32};
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f32_div(dat_a, dat_b));
Ok(D(x.v as u64))
}
}
pub fn jet_rs_sqt(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
eprintln!("»sam: {:?}", sam);
let a = sam.as_atom()?.as_direct()?;
eprintln!("»a: {:?}", a.as_noun());
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float32_t { v: a.data() as u32};
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f32_sqrt(dat_a));
Ok(D(x.v as u64))
}
}
pub fn jet_rs_fma(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?.as_direct()?;
let b = slot(sam, 6)?.as_atom()?.as_direct()?;
let c = slot(sam, 7)?.as_atom()?.as_direct()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float32_t { v: a.data() as u32};
let dat_b = softfloat_sys::float32_t { v: b.data() as u32};
let dat_c = softfloat_sys::float32_t { v: c.data() as u32};
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let x = _nan_unify(f32_mulAdd(dat_a, dat_b, dat_c));
Ok(D(x.v as u64))
}
}
pub fn jet_rs_lth(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?.as_direct()?;
let b = slot(sam, 3)?.as_atom()?.as_direct()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float32_t { v: a.data() as u32};
let dat_b = softfloat_sys::float32_t { v: b.data() as u32};
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let t = f32_lt(dat_a, dat_b);
if t { Ok(YES) } else { Ok(NO) }
}
}
pub fn jet_rs_lte(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?.as_direct()?;
let b = slot(sam, 3)?.as_atom()?.as_direct()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float32_t { v: a.data() as u32};
let dat_b = softfloat_sys::float32_t { v: b.data() as u32};
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let t = f32_le(dat_a, dat_b);
if t { Ok(YES) } else { Ok(NO) }
}
}
pub fn jet_rs_equ(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?.as_direct()?;
let b = slot(sam, 3)?.as_atom()?.as_direct()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float32_t { v: a.data() as u32};
let dat_b = softfloat_sys::float32_t { v: b.data() as u32};
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let t = f32_eq(dat_a, dat_b);
if t { Ok(YES) } else { Ok(NO) }
}
}
pub fn jet_rs_gte(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?.as_direct()?;
let b = slot(sam, 3)?.as_atom()?.as_direct()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float32_t { v: a.data() as u32};
let dat_b = softfloat_sys::float32_t { v: b.data() as u32};
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let t = f32_le(dat_b, dat_a);
if t { Ok(YES) } else { Ok(NO) }
}
}
pub fn jet_rs_gth(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?.as_atom()?.as_direct()?;
let b = slot(sam, 3)?.as_atom()?.as_direct()?;
let r = slot(subject, 30)?.as_atom()?.as_direct()?.data() as u8 as char;
let dat_a = softfloat_sys::float32_t { v: a.data() as u32};
let dat_b = softfloat_sys::float32_t { v: b.data() as u32};
let mod_r = _set_rounding(r);
softfloat_roundingMode_write_helper(mod_r);
let t = f32_lt(dat_b, dat_a);
if t { Ok(YES) } else { Ok(NO) }
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::jets::{Jet, JetErr};
use crate::jets::util::test::{assert_jet, assert_jet_err, init_stack};
use crate::noun::D;
use crate::jets::util::test::{assert_noun_eq};
use assert_no_alloc::assert_no_alloc;
pub fn assert_jet_in_door(
stack: &mut NockStack,
jet: Jet,
sam: &[fn(&mut NockStack) -> Noun], // regular sample
ctx: &[fn(&mut NockStack) -> Noun], // door sample as context
res: Noun) {
unsafe {
let mut sam: Vec<Noun> = sam.iter().map(|f| f(stack)).collect();
let mut ctx: Vec<Noun> = ctx.iter().map(|f| f(stack)).collect();
let sam = if(sam.len() > 1) { T(stack, &sam) } else { sam[0] };
eprintln!("sam: {:?}", sam);
let ctx = if(ctx.len() > 1) { T(stack, &ctx) } else { ctx[0] };
eprintln!("ctx: {:?}", ctx);
let pay = Cell::new(stack, sam, ctx).as_noun();
eprintln!("pay: {:?}", pay);
let sbj = Cell::new(stack, D(0), pay).as_noun();
eprintln!("sbj: {:?}", sbj);
std::io::stderr().flush().unwrap();
let jet_res = jet(stack, &mut None, sbj).unwrap();
eprintln!("jet: {:x}\n", jet_res.as_atom().expect("").as_direct().expect("").data());
std::io::stderr().flush().unwrap();
assert_noun_eq(stack, jet_res, res);
}
}
fn atom_0(_stack: &mut NockStack) -> Noun {
D(0x00000000)
}
fn atom_1(_stack: &mut NockStack) -> Noun {
D(0x3f800000)
}
fn atom_2(_stack: &mut NockStack) -> Noun {
D(0x40000000)
}
fn atom_3(_stack: &mut NockStack) -> Noun {
D(0x40400000)
}
fn atom_1_5(_stack: &mut NockStack) -> Noun {
D(0x3fc00000)
}
fn atom_1_1(_stack: &mut NockStack) -> Noun {
D(0x3f8ccccd)
}
fn atom_0_8(_stack: &mut NockStack) -> Noun {
D(0x3f4ccccd)
}
fn atom_0_3(_stack: &mut NockStack) -> Noun {
D(0x3e99999a)
}
fn r_sample_n(_stack: &mut NockStack) -> Noun {
D('n' as u8 as u64)
}
fn r_sample_z(_stack: &mut NockStack) -> Noun {
D('z' as u8 as u64)
}
fn r_sample_u(_stack: &mut NockStack) -> Noun {
D('u' as u8 as u64)
}
fn r_sample_d(_stack: &mut NockStack) -> Noun {
D('d' as u8 as u64)
}
#[test]
fn test_rs_add() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rs_add, &[atom_0, atom_0], &[atom_0, r_sample_n, atom_0], D(0x00000000));
assert_jet_in_door(s, jet_rs_add, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], D(0x3f800000));
assert_jet_in_door(s, jet_rs_add, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], D(0x40000000));
assert_jet_in_door(s, jet_rs_add, &[atom_1, atom_2], &[atom_0, r_sample_n, atom_0], D(0x40400000));
assert_jet_in_door(s, jet_rs_add, &[atom_2, atom_1], &[atom_0, r_sample_n, atom_0], D(0x40400000));
assert_jet_in_door(s, jet_rs_add, &[atom_0_8, atom_0_3], &[atom_0, r_sample_n, atom_0], D(0x3f8ccccd));
}
#[test]
fn test_rs_sub() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rs_sub, &[atom_0, atom_0], &[atom_0, r_sample_n, atom_0], D(0x00000000));
assert_jet_in_door(s, jet_rs_sub, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], D(0xbf800000));
assert_jet_in_door(s, jet_rs_sub, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], D(0x00000000));
assert_jet_in_door(s, jet_rs_sub, &[atom_1, atom_2], &[atom_0, r_sample_n, atom_0], D(0xbf800000));
assert_jet_in_door(s, jet_rs_sub, &[atom_2, atom_1], &[atom_0, r_sample_n, atom_0], D(0x3f800000));
assert_jet_in_door(s, jet_rs_sub, &[atom_1_1, atom_0_8], &[atom_0, r_sample_n, atom_0], D(0x3e99999a));
assert_jet_in_door(s, jet_rs_sub, &[atom_1_1, atom_0_3], &[atom_0, r_sample_n, atom_0], D(0x3f4ccccd));
}
#[test]
fn test_rs_mul() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rs_mul, &[atom_0, atom_0], &[atom_0, r_sample_n, atom_0], D(0x00000000));
assert_jet_in_door(s, jet_rs_mul, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], D(0x00000000));
assert_jet_in_door(s, jet_rs_mul, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], D(0x3f800000));
assert_jet_in_door(s, jet_rs_mul, &[atom_1, atom_2], &[atom_0, r_sample_n, atom_0], D(0x40000000));
assert_jet_in_door(s, jet_rs_mul, &[atom_2, atom_2], &[atom_0, r_sample_n, atom_0], D(0x40800000));
assert_jet_in_door(s, jet_rs_mul, &[atom_1_5, atom_2], &[atom_0, r_sample_n, atom_0], D(0x40400000));
assert_jet_in_door(s, jet_rs_mul, &[atom_1_1, atom_0_8], &[atom_0, r_sample_z, atom_0], D(0x3f6147ae));
assert_jet_in_door(s, jet_rs_mul, &[atom_1_1, atom_0_8], &[atom_0, r_sample_n, atom_0], D(0x3f6147af));
assert_jet_in_door(s, jet_rs_mul, &[atom_1_1, atom_0_3], &[atom_0, r_sample_n, atom_0], D(0x3ea8f5c3));
}
#[test]
fn test_rs_div() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rs_div, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], D(SINGINF as u64));
// XX test 0/0
assert_jet_in_door(s, jet_rs_div, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], D(0x00000000));
assert_jet_in_door(s, jet_rs_div, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], D(0x3f800000));
assert_jet_in_door(s, jet_rs_div, &[atom_1, atom_2], &[atom_0, r_sample_n, atom_0], D(0x3f000000));
assert_jet_in_door(s, jet_rs_div, &[atom_2, atom_2], &[atom_0, r_sample_n, atom_0], D(0x3f800000));
assert_jet_in_door(s, jet_rs_div, &[atom_1_1, atom_0_8], &[atom_0, r_sample_n, atom_0], D(0x3fb00000));
assert_jet_in_door(s, jet_rs_div, &[atom_1_1, atom_0_3], &[atom_0, r_sample_n, atom_0], D(0x406aaaaa));
assert_jet_in_door(s, jet_rs_div, &[atom_1_1, atom_0_3], &[atom_0, r_sample_u, atom_0], D(0x406aaaab));
}
#[test]
fn test_rs_sqt() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rs_sqt, &[atom_0], &[atom_0, r_sample_n, atom_0], D(0x00000000));
assert_jet_in_door(s, jet_rs_sqt, &[atom_1], &[atom_0, r_sample_n, atom_0], D(0x3f800000));
assert_jet_in_door(s, jet_rs_sqt, &[atom_2], &[atom_0, r_sample_n, atom_0], D(0x3fb504f3));
assert_jet_in_door(s, jet_rs_sqt, &[atom_3], &[atom_0, r_sample_n, atom_0], D(0x3fddb3d7));
assert_jet_in_door(s, jet_rs_sqt, &[atom_1_1], &[atom_0, r_sample_n, atom_0], D(0x3f863f5e));
}
#[test]
fn test_rs_fma() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rs_fma, &[atom_1, atom_0, atom_0], &[atom_0, r_sample_n, atom_0], D(0x00000000));
assert_jet_in_door(s, jet_rs_fma, &[atom_0, atom_1, atom_1], &[atom_0, r_sample_n, atom_0], D(0x3f800000));
assert_jet_in_door(s, jet_rs_fma, &[atom_1, atom_1, atom_1], &[atom_0, r_sample_n, atom_0], D(0x40000000));
assert_jet_in_door(s, jet_rs_fma, &[atom_1, atom_2, atom_1], &[atom_0, r_sample_n, atom_0], D(0x40400000));
assert_jet_in_door(s, jet_rs_fma, &[atom_2, atom_2, atom_1], &[atom_0, r_sample_n, atom_0], D(0x40a00000));
assert_jet_in_door(s, jet_rs_fma, &[atom_1_1, atom_0_8, atom_0_3], &[atom_0, r_sample_n, atom_0], D(0x3f970a3e));
assert_jet_in_door(s, jet_rs_fma, &[atom_1_1, atom_0_8, atom_0_3], &[atom_0, r_sample_z, atom_0], D(0x3f970a3d));
}
#[test]
fn test_rs_lth() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rs_lth, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rs_lth, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], YES);
assert_jet_in_door(s, jet_rs_lth, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], NO);
}
#[test]
fn test_rs_lte() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rs_lte, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rs_lte, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], YES);
assert_jet_in_door(s, jet_rs_lte, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], YES);
}
#[test]
fn test_rs_equ() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rs_equ, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rs_equ, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rs_equ, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], YES);
}
#[test]
fn test_rs_gte() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rs_gte, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], YES);
assert_jet_in_door(s, jet_rs_gte, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rs_gte, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], YES);
}
#[test]
fn test_rs_gth() {
let s = &mut init_stack();
assert_jet_in_door(s, jet_rs_gth, &[atom_1, atom_0], &[atom_0, r_sample_n, atom_0], YES);
assert_jet_in_door(s, jet_rs_gth, &[atom_0, atom_1], &[atom_0, r_sample_n, atom_0], NO);
assert_jet_in_door(s, jet_rs_gth, &[atom_1, atom_1], &[atom_0, r_sample_n, atom_0], NO);
}
}

218
rust/ares/src/jets/tree.rs Normal file
View File

@ -0,0 +1,218 @@
/** Tree jets
*/
use crate::jets;
use crate::jets::JetErr::*;
use crate::jets::util::*;
use crate::jets::util::test::{assert_jet, assert_jet_err, assert_jet_ubig, assert_nary_jet_ubig, init_stack, A};
use crate::mem::NockStack;
use crate::newt::Newt;
use crate::noun::{Atom, IndirectAtom, Noun, D, T};
//use crate::noun::{Atom, DirectAtom, IndirectAtom, Noun, D, DIRECT_MAX, NO, T, YES};
use ibig::{UBig, ubig};
crate::gdb!();
pub fn jet_cap(
_stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
let arg = slot(subject, 6)?;
let tom = arg.as_atom()?;
let met = met(0, tom);
unsafe {
if met < 2 {
Err(Deterministic)
} else if *(tom.as_bitslice().get_unchecked(met - 2)) {
Ok(D(3))
} else {
Ok(D(2))
}
}
}
pub fn jet_mas(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
let arg = slot(subject, 6)?;
let tom = arg.as_atom()?;
let met = met(0, tom);
if met < 2 {
Err(Deterministic)
} else {
let c = bex(stack, met - 1);
let d = bex(stack, met - 2);
let e = sub(stack, tom, c)?;
Ok(con(stack, e, d).as_noun())
}
}
pub fn jet_peg(
stack: &mut NockStack,
_newt: &mut Option<&mut Newt>,
subject: Noun
) -> jets::Result {
unsafe{
let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?;
if let Ok(a) = a.as_direct() {
if a.data() == 0 {
return Err(Deterministic);
}
};
if let Ok(b) = b.as_direct() {
if b.data() == 0 {
return Err(Deterministic);
}
};
let met_a = met(6, a);
let met_b = met(6, b);
let (mut result, destination) = IndirectAtom::new_raw_mut_bitslice(stack, met_a+met_b);
let len_a = met(0, a);
let len_b = met(0, b);
destination[0..len_b-1].copy_from_bitslice(&b.as_bitslice()[0..len_b-1]);
destination[len_b-1..len_b-1+len_a].copy_from_bitslice(&a.as_bitslice()[0..len_a]);
Ok(result.normalize_as_atom().as_noun())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::jets::JetErr;
use crate::jets::util::test::{assert_jet, assert_jet_err, init_stack};
use crate::noun::D;
#[test]
fn test_cap() {
let s = &mut init_stack();
assert_jet_err(s, jet_cap, D(0), JetErr::Deterministic);
assert_jet_err(s, jet_cap, D(1), JetErr::Deterministic);
assert_jet(s, jet_cap, D(2), D(2));
assert_jet(s, jet_cap, D(3), D(3));
assert_jet(s, jet_cap, D(4), D(2));
assert_jet(s, jet_cap, D(5), D(2));
assert_jet(s, jet_cap, D(6), D(3));
assert_jet(s, jet_cap, D(7), D(3));
assert_jet(s, jet_cap, D(8), D(2));
}
#[test]
fn test_mas() {
let s = &mut init_stack();
assert_jet_err(s, jet_mas, D(0), JetErr::Deterministic);
assert_jet_err(s, jet_mas, D(1), JetErr::Deterministic);
assert_jet(s, jet_mas, D(2), D(1));
assert_jet(s, jet_mas, D(3), D(1));
assert_jet(s, jet_mas, D(4), D(2));
assert_jet(s, jet_mas, D(5), D(3));
assert_jet(s, jet_mas, D(6), D(2));
assert_jet(s, jet_mas, D(7), D(3));
assert_jet(s, jet_mas, D(8), D(4));
}
fn assert_math_jet(
stack: &mut NockStack,
jet: jets::Jet,
sam: &[fn(&mut NockStack) -> Noun],
res: UBig,
) {
let sam: Vec<Noun> = sam.iter().map(|f| f(stack)).collect();
assert_nary_jet_ubig(stack, jet, &sam, res);
}
fn assert_math_jet_err(
stack: &mut NockStack,
jet: jets::Jet,
sam: &[fn(&mut NockStack) -> Noun],
err: JetErr,
) {
let sam: Vec<Noun> = sam.iter().map(|f| f(stack)).collect();
let sam = T(stack, &sam);
assert_jet_err(stack, jet, sam, err);
}
fn atom_0(_stack: &mut NockStack) -> Noun {
print!("{:x}", 0);
D(0x0)
}
fn atom_1(_stack: &mut NockStack) -> Noun {
print!("{:x}", 1);
D(0x1)
}
fn atom_2(_stack: &mut NockStack) -> Noun {
print!("{:x}", 2);
D(0x2)
}
fn atom_3(_stack: &mut NockStack) -> Noun {
print!("{:x}", 3);
D(0x3)
}
fn atom_4(_stack: &mut NockStack) -> Noun {
D(0x4)
}
fn atom_5(_stack: &mut NockStack) -> Noun {
D(0x5)
}
fn atom_0a(_stack: &mut NockStack) -> Noun {
D(0xa)
}
fn atom_7f(_stack: &mut NockStack) -> Noun {
D(0x7fffffffffffffff)
}
fn atom_100(stack: &mut NockStack) -> Noun {
let shl1_6 = UBig::from_str_radix("10000000000000000", 16);
A(stack, &ubig!(shl1_6))
}
fn atom_1000(stack: &mut NockStack) -> Noun {
let shl1_7 = UBig::from_str_radix("100000000000000000000000000000000", 16);
A(stack, &ubig!(shl1_7))
}
fn atom_2000(stack: &mut NockStack) -> Noun {
let shl2_7 = UBig::from_str_radix("200000000000000000000000000000000", 16);
A(stack, &ubig!(shl2_7))
}
#[test]
fn test_peg() {
let s = &mut init_stack();
assert_math_jet_err(s, jet_peg, &[atom_0, atom_1], JetErr::Deterministic);
// Test direct
assert_math_jet(s, jet_peg, &[atom_2, atom_3], ubig!(5));
assert_math_jet(s, jet_peg, &[atom_0a,atom_0a], ubig!(82));
assert_math_jet(s, jet_peg, &[atom_7f, atom_2], ubig!(0xfffffffffffffffe));
assert_math_jet(s, jet_peg, &[atom_7f, atom_3], ubig!(0xffffffffffffffff));
// Test direct with overflow.
assert_math_jet(s, jet_peg, &[atom_7f, atom_4], ubig!(0x1fffffffffffffffc));
assert_math_jet(s, jet_peg, &[atom_7f, atom_5], ubig!(0x1fffffffffffffffd));
}
}

View File

@ -1,6 +1,6 @@
use crate::mem::{word_size_of, NockStack};
use bitvec::prelude::{BitSlice, Lsb0};
use either::Either;
use either::{Either, Left, Right};
use ibig::{Stack, UBig};
use intmap::IntMap;
use std::fmt;
@ -18,6 +18,9 @@ const DIRECT_MASK: u64 = !(u64::MAX >> 1);
/** Maximum value of a direct atom. Values higher than this must be represented by indirect atoms. */
pub const DIRECT_MAX: u64 = u64::MAX >> 1;
/** Highest direct bit (since leading 0 marks directness) */
const DIRECT_BITS: u64 = 62;
/** Tag for an indirect atom. */
const INDIRECT_TAG: u64 = u64::MAX & DIRECT_MASK;
@ -61,8 +64,8 @@ pub fn acyclic_noun(noun: Noun) -> bool {
fn acyclic_noun_go(noun: Noun, seen: &mut IntMap<()>) -> bool {
match noun.as_either_atom_cell() {
Either::Left(_atom) => true,
Either::Right(cell) => {
Left(_atom) => true,
Right(cell) => {
if seen.get(cell.0).is_some() {
false
} else {
@ -373,11 +376,11 @@ impl IndirectAtom {
/** Pointer to data for indirect atom */
pub fn data_pointer(&self) -> *const u64 {
unsafe { self.to_raw_pointer().add(2) }
unsafe { self.to_raw_pointer().add(2) as *const u64 }
}
pub fn data_pointer_mut(&mut self) -> *mut u64 {
unsafe { self.to_raw_pointer_mut().add(2) }
unsafe { self.to_raw_pointer_mut().add(2) as *mut u64 }
}
pub fn as_slice(&self) -> &[u64] {
@ -431,6 +434,24 @@ impl IndirectAtom {
}
}
pub unsafe fn as_u64(self) -> Result<u64> {
if self.size() == 1 {
Ok(*(self.data_pointer()))
} else {
Err(Error::NotRepresentable)
}
}
pub unsafe fn as_u128_pair(self) -> Result<[u64; 2]> {
if self.size() <= 2 {
let mut u128_array = &mut [0u64; 2];
u128_array.copy_from_slice(&(self.as_slice()[0..2]));
Ok(unsafe { *u128_array } )
} else {
Err(Error::NotRepresentable)
}
}
pub fn as_atom(self) -> Atom {
Atom { indirect: self }
}
@ -575,6 +596,27 @@ impl fmt::Display for Cell {
}
}
impl Slots for Cell {}
impl private::RawSlots for Cell {
fn raw_slot(&self, axis: &BitSlice<u64, Lsb0>) -> Result<Noun> {
let mut noun: Noun = self.as_noun();
let mut cursor = axis.last_one().expect("raw_slow somehow by-passed 0 check");
while cursor != 0 {
cursor -= 1;
// Returns Err if axis tried to descend through atom
if axis[cursor] {
noun = noun.as_cell()?.tail();
} else {
noun = noun.as_cell()?.head();
}
}
Ok(noun)
}
}
/**
* Memory representation of the contents of a cell
*/
@ -630,6 +672,29 @@ impl Atom {
unsafe { is_indirect_atom(self.raw) }
}
pub fn as_u64(self) -> Result<u64> {
if self.is_direct() {
Ok(unsafe { self.direct.data() })
} else {
unsafe {
self.indirect.as_u64()
}
}
}
pub unsafe fn as_u128_pair(self) -> Result<[u64; 2]> {
if self.is_direct() {
let mut u128_array = &mut [0u64; 2];
u128_array[0] = 0x0 as u64;
u128_array[1] = self.as_direct()?.data() as u64;
Ok(unsafe { *u128_array } )
} else {
unsafe {
self.indirect.as_u128_pair()
}
}
}
pub fn as_direct(&self) -> Result<DirectAtom> {
if self.is_direct() {
unsafe { Ok(self.direct) }
@ -648,9 +713,9 @@ impl Atom {
pub fn as_either(&self) -> Either<DirectAtom, IndirectAtom> {
if self.is_indirect() {
unsafe { Either::Right(self.indirect) }
unsafe { Right(self.indirect) }
} else {
unsafe { Either::Left(self.direct) }
unsafe { Left(self.direct) }
}
}
@ -678,24 +743,40 @@ impl Atom {
}
}
pub fn direct(&self) -> Option<DirectAtom> {
if self.is_direct() {
unsafe { Some(self.direct) }
} else {
None
}
}
pub fn indirect(&self) -> Option<IndirectAtom> {
if self.is_indirect() {
unsafe { Some(self.indirect) }
} else {
None
}
}
pub fn size(&self) -> usize {
match self.as_either() {
Either::Left(_direct) => 1,
Either::Right(indirect) => indirect.size(),
Left(_direct) => 1,
Right(indirect) => indirect.size(),
}
}
pub fn bit_size(&self) -> usize {
match self.as_either() {
Either::Left(direct) => direct.bit_size(),
Either::Right(indirect) => indirect.bit_size(),
Left(direct) => direct.bit_size(),
Right(indirect) => indirect.bit_size(),
}
}
pub fn data_pointer(&self) -> *const u64 {
match self.as_either() {
Either::Left(_direct) => (self as *const Atom) as *const u64,
Either::Right(indirect) => indirect.data_pointer(),
Left(_direct) => (self as *const Atom) as *const u64,
Right(indirect) => indirect.data_pointer(),
}
}
@ -750,24 +831,24 @@ impl Allocated {
pub unsafe fn forwarding_pointer(&self) -> Option<Allocated> {
match self.as_either() {
Either::Left(indirect) => indirect.forwarding_pointer().map(|i| i.as_allocated()),
Either::Right(cell) => cell.forwarding_pointer().map(|c| c.as_allocated()),
Left(indirect) => indirect.forwarding_pointer().map(|i| i.as_allocated()),
Right(cell) => cell.forwarding_pointer().map(|c| c.as_allocated()),
}
}
pub unsafe fn get_metadata(&self) -> u64 {
*(self.to_raw_pointer())
*(self.to_raw_pointer() as *const u64)
}
pub unsafe fn set_metadata(self, metadata: u64) {
*(self.const_to_raw_pointer_mut()) = metadata;
*(self.const_to_raw_pointer_mut() as *mut u64) = metadata;
}
pub fn as_either(&self) -> Either<IndirectAtom, Cell> {
if self.is_indirect() {
unsafe { Either::Left(self.indirect) }
unsafe { Left(self.indirect) }
} else {
unsafe { Either::Right(self.cell) }
unsafe { Right(self.cell) }
}
}
@ -868,17 +949,57 @@ impl Noun {
pub fn as_either_atom_cell(&self) -> Either<Atom, Cell> {
if self.is_cell() {
unsafe { Either::Right(self.cell) }
unsafe { Right(self.cell) }
} else {
unsafe { Either::Left(self.atom) }
unsafe { Left(self.atom) }
}
}
pub fn as_either_direct_allocated(&self) -> Either<DirectAtom, Allocated> {
if self.is_direct() {
unsafe { Either::Left(self.direct) }
unsafe { Left(self.direct) }
} else {
unsafe { Either::Right(self.allocated) }
unsafe { Right(self.allocated) }
}
}
pub fn atom(&self) -> Option<Atom> {
if self.is_atom() {
unsafe { Some(self.atom) }
} else {
None
}
}
pub fn cell(&self) -> Option<Cell> {
if self.is_cell() {
unsafe { Some(self.cell) }
} else {
None
}
}
pub fn direct(&self) -> Option<DirectAtom> {
if self.is_direct() {
unsafe { Some(self.direct) }
} else {
None
}
}
pub fn indirect(&self) -> Option<IndirectAtom> {
if self.is_indirect() {
unsafe { Some(self.indirect) }
} else {
None
}
}
pub fn allocated(&self) -> Option<Allocated> {
if self.is_allocated() {
unsafe { Some(self.allocated) }
} else {
None
}
}
@ -936,8 +1057,8 @@ impl Noun {
if allocated.get_metadata() & (1 << 32) == 0 {
allocated.set_metadata(allocated.get_metadata() | (1 << 32));
match allocated.as_either() {
Either::Left(indirect) => indirect.size() + 2,
Either::Right(cell) => {
Left(indirect) => indirect.size() + 2,
Right(cell) => {
word_size_of::<CellMemory>()
+ cell.head().mass_wind(inside)
+ cell.tail().mass_wind(inside)
@ -959,7 +1080,7 @@ impl Noun {
if let Ok(allocated) = self.as_allocated() {
if inside(allocated.to_raw_pointer()) {
allocated.set_metadata(allocated.get_metadata() & !(1 << 32));
if let Either::Right(cell) = allocated.as_either() {
if let Right(cell) = allocated.as_either() {
cell.head().mass_unwind(inside);
cell.tail().mass_unwind(inside);
}
@ -996,6 +1117,16 @@ impl fmt::Display for Noun {
}
}
impl Slots for Noun {}
impl private::RawSlots for Noun {
fn raw_slot(&self, axis: &BitSlice<u64, Lsb0>) -> Result<Noun> {
match self.as_either_atom_cell() {
Right(cell) => cell.raw_slot(axis),
Left(_atom) => Err(Error::NotCell), // Axis tried to descend through atom
}
}
}
/**
* An allocation object (probably a mem::NockStack) which can allocate a memory buffer sized to
* a certain number of nouns
@ -1010,3 +1141,36 @@ pub trait NounAllocator: Sized {
/** Allocate memory for a cell */
unsafe fn alloc_cell(&mut self) -> *mut CellMemory;
}
/**
* Implementing types allow component Nouns to be retreived by numeric axis
*/
pub trait Slots: private::RawSlots {
/**
* Retrieve component Noun at given axis, or fail with descriptive error
*/
fn slot(&self, axis: u64) -> Result<Noun> {
if axis == 0 {
Err(Error::NotRepresentable) // 0 is not allowed as an axis
} else {
self.raw_slot(DirectAtom::new(axis).unwrap().as_bitslice())
}
}
}
/**
* Implementation methods that should not be made available to derived crates
*/
mod private {
use crate::noun::{BitSlice, Lsb0, Noun, Result};
/**
* Implementation of the Slots trait
*/
pub trait RawSlots {
/**
* Actual logic of retreiving Noun object at some axis
*/
fn raw_slot(&self, axis: &BitSlice<u64, Lsb0>) -> Result<Noun>;
}
}