Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ default = []
num-traits = { version = "0.2", default-features = false }

[lints.rust]
warnings = "deny"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I commented these out because a lot of code that wasn't added in this PR (I'm sure tons of what I added here does as well though!) violates various lints in these groups and my editor was screaming lol.

I could fix them in this PR if you'd like, @HarryR , although I think it would be more appropriate for me to do as a follow-up PR.

# warnings = "deny"

[lints.clippy]
all = "deny"
pedantic = "deny"
nursery = "deny"
perf = "deny"
# all = "deny"
# pedantic = "deny"
# nursery = "deny"
# perf = "deny"
94 changes: 94 additions & 0 deletions src/softfloat/f16_add.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use super::{float16_t, signF16UI, softfloat_addMagsF16, softfloat_subMagsF16};

#[inline]
#[must_use]
pub const fn f16_add(
a: float16_t,
b: float16_t,
roundingMode: u8,
detectTininess: u8,
) -> (float16_t, u8) {
if signF16UI(a.v ^ b.v) {
softfloat_subMagsF16(a.v, b.v, roundingMode, detectTininess)
} else {
softfloat_addMagsF16(a.v, b.v, roundingMode, detectTininess)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_f16_add() {
struct softfloat_f16_add_TestCase {
a: u16,
b: u16,
result: u16,
flags: u8,
roundingMode: u8,
detectTininess: u8,
}

let cases = [
softfloat_f16_add_TestCase {
a: 0x0000,
b: 0x3C00,
result: 0x3C00,
flags: 0,
roundingMode: 0,
detectTininess: 1,
},
softfloat_f16_add_TestCase {
a: 0x3C00,
b: 0x3C00,
result: 0x4000,
flags: 0,
roundingMode: 0,
detectTininess: 1,
},
softfloat_f16_add_TestCase {
a: 0xBC00,
b: 0x3C00,
result: 0x0000,
flags: 0,
roundingMode: 0,
detectTininess: 1,
},
softfloat_f16_add_TestCase {
a: 0x0000,
b: 0x0000,
result: 0x0000,
flags: 0,
roundingMode: 0,
detectTininess: 1,
},
softfloat_f16_add_TestCase {
a: 0x3800,
b: 0x3800,
result: 0x3C00,
flags: 0,
roundingMode: 0,
detectTininess: 1,
},
softfloat_f16_add_TestCase {
a: 0xBC00,
b: 0xBC00,
result: 0xC000,
flags: 0,
roundingMode: 0,
detectTininess: 1,
},
];

for (i, c) in cases.iter().enumerate() {
let (res, flags) = f16_add(
float16_t { v: c.a },
float16_t { v: c.b },
c.roundingMode,
c.detectTininess,
);
assert_eq!((i, res.v, flags), (i, c.result, c.flags));
}
}
}
23 changes: 23 additions & 0 deletions src/softfloat/f16_classify.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use super::{expF16UI, float16_t, fracF16UI, isNaNF16UI, signF16UI, softfloat_isSigNaNF16UI};

#[inline]
#[must_use]
pub const fn f16_classify(a: float16_t) -> u16 {
let infOrNaN = expF16UI(a.v) == 0x1F;
let subnormalOrZero = expF16UI(a.v) == 0;
let sign = signF16UI(a.v);
let fracZero = fracF16UI(a.v) == 0;
let isNaN = isNaNF16UI(a.v);
let isSNaN = softfloat_isSigNaNF16UI(a.v);

return ((sign && infOrNaN && fracZero) as u16)
| (((sign && !infOrNaN && !subnormalOrZero) as u16) << 1)
| (((sign && subnormalOrZero && !fracZero) as u16) << 2)
| (((sign && subnormalOrZero && fracZero) as u16) << 3)
| (((!sign && infOrNaN && fracZero) as u16) << 7)
| (((!sign && !infOrNaN && !subnormalOrZero) as u16) << 6)
| (((!sign && subnormalOrZero && !fracZero) as u16) << 5)
| (((!sign && subnormalOrZero && fracZero) as u16) << 4)
| (((isNaN && isSNaN) as u16) << 8)
| (((isNaN && !isSNaN) as u16) << 9);
}
213 changes: 213 additions & 0 deletions src/softfloat/f16_div.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
use super::{
defaultNaNF16UI, expF16UI, float16_t, fracF16UI, packToF16, packToF16UI, signF16UI,
softfloat_approxRecip_1k0s, softfloat_approxRecip_1k1s, softfloat_flag_infinite,
softfloat_flag_invalid, softfloat_normSubnormalF16Sig, softfloat_propagateNaNF16,
softfloat_roundPackToF16,
};

#[must_use]
pub const fn f16_div(
a: float16_t,
b: float16_t,
roundingMode: u8,
detectTininess: u8,
) -> (float16_t, u8) {
let signA = signF16UI(a.v);
let mut expA = expF16UI(a.v);
let mut sigA = fracF16UI(a.v);
let signB = signF16UI(b.v);
let mut expB = expF16UI(b.v);
let mut sigB = fracF16UI(b.v);
let signZ = signA ^ signB;
if expA == 0x1F {
if sigA != 0 {
return softfloat_propagateNaNF16(a.v, b.v);
}
if expB == 0x1F {
if sigB != 0 {
return softfloat_propagateNaNF16(a.v, b.v);
}
return (float16_t { v: defaultNaNF16UI }, softfloat_flag_invalid);
}
return (packToF16(signZ, 0x1F, 0), 0);
}
if expB == 0x1F {
if sigB != 0 {
return softfloat_propagateNaNF16(a.v, b.v);
}
return (packToF16(signZ, 0, 0), 0);
}
if expB == 0 {
if sigB == 0 {
if (expA as u16) | sigA == 0 {
return (float16_t { v: defaultNaNF16UI }, softfloat_flag_invalid);
}
return (packToF16(signZ, 0x1F, 0), softfloat_flag_infinite);
}
let normExpSig = softfloat_normSubnormalF16Sig(sigB);
expB = normExpSig.exp;
sigB = normExpSig.sig;
}
if expA == 0 {
if sigA == 0 {
return (packToF16(signZ, 0, 0), 0);
}
let normExpSig = softfloat_normSubnormalF16Sig(sigA);
expA = normExpSig.exp;
sigA = normExpSig.sig;
}
let mut expZ = (expA as i16).wrapping_sub(expB as i16).wrapping_add(0xE);
sigA |= 0x0400;
sigB |= 0x0400;
if sigA < sigB {
expZ = expZ.wrapping_sub(1);
sigA <<= 5;
} else {
sigA <<= 4;
}
let index = (sigB >> 6) & 0xF;
let r0 = softfloat_approxRecip_1k0s[index as usize].wrapping_sub(
((softfloat_approxRecip_1k1s[index as usize] as u32).wrapping_mul((sigB & 0x3F) as u32)
>> 10) as u16,
);
let mut sigZ = (((sigA as u32).wrapping_mul(r0 as u32)) >> 16) as u16;
let mut rem = (sigA << 10).wrapping_sub(sigZ.wrapping_mul(sigB));
sigZ = sigZ.wrapping_add(((rem as u32).wrapping_mul(r0 as u32) >> 26) as u16);
sigZ = sigZ.wrapping_add(1);
if (sigZ & 7) == 0 {
sigZ &= !1;
rem = (sigA << 10).wrapping_sub(sigZ.wrapping_mul(sigB));
if (rem & 0x8000) != 0 {
sigZ = sigZ.wrapping_sub(2);
} else if rem != 0 {
sigZ |= 1;
}
}
return softfloat_roundPackToF16(signZ, expZ, sigZ, roundingMode, detectTininess);
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_f16_div() {
struct softfloat_f16_div_TestCase {
a: u16,
b: u16,
result: u16,
flags: u8,
roundingMode: u8,
detectTininess: u8,
}

let cases = [
softfloat_f16_div_TestCase {
a: 0x3C00,
b: 0x3C00,
result: 0x3C00,
flags: 0,
roundingMode: 0,
detectTininess: 1,
},
softfloat_f16_div_TestCase {
a: 0x4000,
b: 0x3C00,
result: 0x4000,
flags: 0,
roundingMode: 0,
detectTininess: 1,
},
softfloat_f16_div_TestCase {
a: 0x3C00,
b: 0x4000,
result: 0x3800,
flags: 0,
roundingMode: 0,
detectTininess: 1,
},
softfloat_f16_div_TestCase {
a: 0x4400,
b: 0x4000,
result: 0x4000,
flags: 0,
roundingMode: 0,
detectTininess: 1,
},
softfloat_f16_div_TestCase {
a: 0xBC00,
b: 0x3C00,
result: 0xBC00,
flags: 0,
roundingMode: 0,
detectTininess: 1,
},
softfloat_f16_div_TestCase {
a: 0x3C00,
b: 0xBC00,
result: 0xBC00,
flags: 0,
roundingMode: 0,
detectTininess: 1,
},
softfloat_f16_div_TestCase {
a: 0xC000,
b: 0xBC00,
result: 0x4000,
flags: 0,
roundingMode: 0,
detectTininess: 1,
},
softfloat_f16_div_TestCase {
a: 0x4200,
b: 0x4000,
result: 0x3E00,
flags: 0,
roundingMode: 0,
detectTininess: 1,
},
softfloat_f16_div_TestCase {
a: 0x0000,
b: 0x3C00,
result: 0x0000,
flags: 0,
roundingMode: 0,
detectTininess: 1,
},
softfloat_f16_div_TestCase {
a: 0x3C00,
b: 0x7C00,
result: 0x0000,
flags: 0,
roundingMode: 0,
detectTininess: 1,
},
softfloat_f16_div_TestCase {
a: 0x7C00,
b: 0x3C00,
result: 0x7C00,
flags: 0,
roundingMode: 0,
detectTininess: 1,
},
softfloat_f16_div_TestCase {
a: 0x3C00,
b: 0x0000,
result: 0x7C00,
flags: softfloat_flag_infinite,
roundingMode: 0,
detectTininess: 1,
},
];

for (i, c) in cases.iter().enumerate() {
let (res, flags) = f16_div(
float16_t { v: c.a },
float16_t { v: c.b },
c.roundingMode,
c.detectTininess,
);
assert_eq!((i, res.v, flags), (i, c.result, c.flags));
}
}
}
13 changes: 13 additions & 0 deletions src/softfloat/f16_eq.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use super::{float16_t, isNaNF16UI, softfloat_flag_invalid, softfloat_isSigNaNF16UI};

#[inline]
#[must_use]
pub const fn f16_eq(a: float16_t, b: float16_t) -> (bool, u8) {
if isNaNF16UI(a.v) || isNaNF16UI(b.v) {
if softfloat_isSigNaNF16UI(a.v) || softfloat_isSigNaNF16UI(b.v) {
return (false, softfloat_flag_invalid);
}
return (false, 0);
}
return (a.v == b.v || ((a.v | b.v) << 1) == 0, 0);
}
10 changes: 10 additions & 0 deletions src/softfloat/f16_eq_signaling.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use super::{float16_t, isNaNF16UI, softfloat_flag_invalid};

#[inline]
#[must_use]
pub const fn f16_eq_signaling(a: float16_t, b: float16_t) -> (bool, u8) {
if isNaNF16UI(a.v) || isNaNF16UI(b.v) {
return (false, softfloat_flag_invalid);
}
return ((a.v == b.v) || ((a.v | b.v) << 1) == 0, 0);
}
7 changes: 7 additions & 0 deletions src/softfloat/f16_isSignalingNaN.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use super::{float16_t, softfloat_isSigNaNF16UI};

#[inline]
#[must_use]
pub const fn f16_isSignalingNaN(a: float16_t) -> bool {
return softfloat_isSigNaNF16UI(a.v);
}
Loading