From 562a83461a250f66d1edc92fffc271e2b7e6cf3c Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 10:47:13 -0400 Subject: [PATCH 01/23] F16 addition Holy shit is porting C to Rust a chore --- Cargo.toml | 10 +- src/softfloat/f16_add.rs | 94 ++++++++++++ src/softfloat/internals.rs | 54 +++++++ src/softfloat/mod.rs | 12 ++ src/softfloat/riscv/mod.rs | 6 + src/softfloat/riscv/s_commonNaNToF16UI.rs | 12 ++ src/softfloat/riscv/s_f16UIToCommonNaN.rs | 18 +++ src/softfloat/riscv/s_propagateNaNF16UI.rs | 27 ++++ src/softfloat/riscv/specialize.rs | 16 ++ src/softfloat/s_addMagsF16.rs | 170 +++++++++++++++++++++ src/softfloat/s_countLeadingZeros16.rs | 5 + src/softfloat/s_normRoundPackToF16.rs | 27 ++++ src/softfloat/s_roundPackToF16.rs | 69 +++++++++ src/softfloat/s_subMagsF16.rs | 166 ++++++++++++++++++++ src/softfloat/types.rs | 21 +++ 15 files changed, 702 insertions(+), 5 deletions(-) create mode 100644 src/softfloat/f16_add.rs create mode 100644 src/softfloat/riscv/s_commonNaNToF16UI.rs create mode 100644 src/softfloat/riscv/s_f16UIToCommonNaN.rs create mode 100644 src/softfloat/riscv/s_propagateNaNF16UI.rs create mode 100644 src/softfloat/s_addMagsF16.rs create mode 100644 src/softfloat/s_countLeadingZeros16.rs create mode 100644 src/softfloat/s_normRoundPackToF16.rs create mode 100644 src/softfloat/s_roundPackToF16.rs create mode 100644 src/softfloat/s_subMagsF16.rs diff --git a/Cargo.toml b/Cargo.toml index ca94a5f..bfc61c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,10 +18,10 @@ default = [] num-traits = { version = "0.2", default-features = false } [lints.rust] -warnings = "deny" +# warnings = "deny" [lints.clippy] -all = "deny" -pedantic = "deny" -nursery = "deny" -perf = "deny" +# all = "deny" +# pedantic = "deny" +# nursery = "deny" +# perf = "deny" diff --git a/src/softfloat/f16_add.rs b/src/softfloat/f16_add.rs new file mode 100644 index 0000000..cdc2397 --- /dev/null +++ b/src/softfloat/f16_add.rs @@ -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)); + } + } +} diff --git a/src/softfloat/internals.rs b/src/softfloat/internals.rs index dc91a6a..70a9525 100644 --- a/src/softfloat/internals.rs +++ b/src/softfloat/internals.rs @@ -33,8 +33,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ +use crate::softfloat::float16_t; + use super::types::{float32_t, float64_t}; +#[derive(Copy, Clone)] +#[repr(C)] +pub union ui16_f16 { + pub ui: u16, + pub f: float16_t, +} + #[derive(Copy, Clone)] #[repr(C)] pub union ui32_f32 { @@ -49,6 +58,51 @@ pub union ui64_f64 { pub f: float64_t, } +//#define signF16UI( a ) ((bool) ((uint16_t) (a)>>15)) +#[inline] +#[must_use] +pub const fn signF16UI(a: u16) -> bool { + (a >> 15) != 0 +} + +//#define expF16UI( a ) ((int_fast8_t) ((a)>>10) & 0x1F) +#[inline] +#[must_use] +pub const fn expF16UI(a: u16) -> i8 { + ((a >> 10) & 0x1F) as i8 +} + +//#define fracF16UI( a ) ((a) & 0x03FF) +#[inline] +#[must_use] +pub const fn fracF16UI(a: u16) -> u16 { + a & 0x03FF +} + +//#define packToF16UI( sign, exp, sig ) (((uint16_t) (sign)<<15) + ((uint16_t) (exp)<<10) + (sig)) +#[inline] +#[must_use] +pub const fn packToF16UI(sign: bool, exp: i8, sig: u16) -> u16 { + ((sign as u16) << 15) + .wrapping_add(((exp as u16) << 10)) + .wrapping_add(sig) +} + +#[inline] +#[must_use] +pub const fn packToF16(sign: bool, exp: i8, sig: u16) -> float16_t { + float16_t { + v: packToF16UI(sign, exp, sig), + } +} + +//#define isNaNF16UI( a ) (((~(a) & 0x7C00) == 0) && ((a) & 0x03FF)) +#[inline] +#[must_use] +pub const fn isNaNF16UI(a: u16) -> bool { + ((!(a & 0x7C00) == 0) && (a & 0x03FF) != 0) +} + //#define signF32UI( a ) ((bool) ((uint32_t) (a)>>31)) #[inline] #[must_use] diff --git a/src/softfloat/mod.rs b/src/softfloat/mod.rs index 0370a9a..288f16f 100644 --- a/src/softfloat/mod.rs +++ b/src/softfloat/mod.rs @@ -19,6 +19,7 @@ clippy::if_not_else )] +mod f16_add; mod f32_add; mod f32_classify; mod f32_div; @@ -103,6 +104,11 @@ mod ui64_to_f32; mod ui64_to_f64; mod internals; +mod s_addMagsF16; +mod s_countLeadingZeros16; +mod s_normRoundPackToF16; +mod s_roundPackToF16; +mod s_subMagsF16; pub use internals::*; mod riscv; @@ -127,6 +133,7 @@ pub const softfloat_round_max: u8 = 3; pub const softfloat_round_near_maxMag: u8 = 4; pub const softfloat_round_odd: u8 = 6; +pub use f16_add::f16_add; pub use f32_add::f32_add; pub use f32_classify::f32_classify; pub use f32_div::f32_div; @@ -173,12 +180,14 @@ pub use i32_to_f32::i32_to_f32; pub use i32_to_f64::i32_to_f64; pub use i64_to_f32::i64_to_f32; pub use i64_to_f64::i64_to_f64; +pub use s_addMagsF16::softfloat_addMagsF16; pub use s_addMagsF32::softfloat_addMagsF32; pub use s_addMagsF64::softfloat_addMagsF64; pub use s_approxRecip32_1::softfloat_approxRecip32_1; pub use s_approxRecipSqrt32_1::softfloat_approxRecipSqrt32_1; pub use s_approxRecipSqrt_1Ks::softfloat_approxRecipSqrt_1k0s; pub use s_approxRecipSqrt_1Ks::softfloat_approxRecipSqrt_1k1s; +pub use s_countLeadingZeros16::softfloat_countLeadingZeros16; pub use s_countLeadingZeros32::softfloat_countLeadingZeros32; pub use s_countLeadingZeros64::softfloat_countLeadingZeros64; @@ -188,10 +197,12 @@ pub use s_approxRecip_1Ks::softfloat_approxRecip_1k1s; pub use s_mul64To128::softfloat_mul64To128; pub use s_mulAddF32::softfloat_mulAddF32; pub use s_mulAddF64::softfloat_mulAddF64; +pub use s_normRoundPackToF16::softfloat_normRoundPackToF16; pub use s_normRoundPackToF32::softfloat_normRoundPackToF32; pub use s_normRoundPackToF64::softfloat_normRoundPackToF64; pub use s_normSubnormalF32Sig::softfloat_normSubnormalF32Sig; pub use s_normSubnormalF64Sig::softfloat_normSubnormalF64Sig; +pub use s_roundPackToF16::softfloat_roundPackToF16; pub use s_roundPackToF32::*; pub use s_roundPackToF64::softfloat_roundPackToF64; pub use s_roundToI32::softfloat_roundToI32; @@ -206,6 +217,7 @@ pub use s_shortShiftLeft128::softfloat_shortShiftLeft128; pub use s_shortShiftRightJam128::softfloat_shortShiftRightJam128; pub use s_shortShiftRightJam64::softfloat_shortShiftRightJam64; pub use s_sub128::softfloat_sub128; +pub use s_subMagsF16::softfloat_subMagsF16; pub use s_subMagsF32::softfloat_subMagsF32; pub use s_subMagsF64::softfloat_subMagsF64; pub use ui32_to_f32::ui32_to_f32; diff --git a/src/softfloat/riscv/mod.rs b/src/softfloat/riscv/mod.rs index a8a2763..0fbb973 100644 --- a/src/softfloat/riscv/mod.rs +++ b/src/softfloat/riscv/mod.rs @@ -1,15 +1,21 @@ +mod s_commonNaNToF16UI; mod s_commonNaNToF32UI; mod s_commonNaNToF64UI; +mod s_f16UIToCommonNaN; mod s_f32UIToCommonNaN; mod s_f64UIToCommonNaN; +mod s_propagateNaNF16UI; mod s_propagateNaNF32UI; mod s_propagateNaNF64UI; mod specialize; +pub use s_commonNaNToF16UI::softfloat_commonNaNToF16UI; pub use s_commonNaNToF32UI::softfloat_commonNaNToF32UI; pub use s_commonNaNToF64UI::softfloat_commonNaNToF64UI; +pub use s_f16UIToCommonNaN::softfloat_f16UIToCommonNaN; pub use s_f32UIToCommonNaN::softfloat_f32UIToCommonNaN; pub use s_f64UIToCommonNaN::softfloat_f64UIToCommonNaN; +pub use s_propagateNaNF16UI::{softfloat_propagateNaNF16, softfloat_propagateNaNF16UI}; pub use s_propagateNaNF32UI::{softfloat_propagateNaNF32, softfloat_propagateNaNF32UI}; pub use s_propagateNaNF64UI::{softfloat_propagateNaNF64, softfloat_propagateNaNF64UI}; pub use specialize::*; diff --git a/src/softfloat/riscv/s_commonNaNToF16UI.rs b/src/softfloat/riscv/s_commonNaNToF16UI.rs new file mode 100644 index 0000000..9ac4701 --- /dev/null +++ b/src/softfloat/riscv/s_commonNaNToF16UI.rs @@ -0,0 +1,12 @@ +use crate::softfloat::{commonNaN, defaultNaNF16UI}; + +/*---------------------------------------------------------------------------- +| Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point +| NaN, and returns the bit pattern of this value as an unsigned integer. +*----------------------------------------------------------------------------*/ +//#define softfloat_commonNaNToF16UI( aPtr ) ((uint_fast16_t) defaultNaNF16UI) +#[inline] +#[must_use] +pub const fn softfloat_commonNaNToF16UI(_aPtr: commonNaN) -> u16 { + defaultNaNF16UI +} diff --git a/src/softfloat/riscv/s_f16UIToCommonNaN.rs b/src/softfloat/riscv/s_f16UIToCommonNaN.rs new file mode 100644 index 0000000..ef8e0c3 --- /dev/null +++ b/src/softfloat/riscv/s_f16UIToCommonNaN.rs @@ -0,0 +1,18 @@ +use crate::softfloat::{commonNaN, softfloat_flag_invalid}; + +/*---------------------------------------------------------------------------- +| Assuming 'uiA' has the bit pattern of a 16-bit floating-point NaN, converts +| this NaN to the common NaN form, and stores the resulting common NaN at the +| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid +| exception is raised. +*----------------------------------------------------------------------------*/ +//#define softfloat_f16UIToCommonNaN( uiA, zPtr ) if ( ! ((uiA) & 0x0200) ) softfloat_raiseFlags( softfloat_flag_invalid ) + +#[inline] +#[must_use] +pub const fn softfloat_f16UIToCommonNaN(uiA: u16) -> (commonNaN, u8) { + if (uiA & 0x0200) == 0 { + return (commonNaN::default(), softfloat_flag_invalid); + } + (commonNaN::default(), 0) +} diff --git a/src/softfloat/riscv/s_propagateNaNF16UI.rs b/src/softfloat/riscv/s_propagateNaNF16UI.rs new file mode 100644 index 0000000..3bf9c30 --- /dev/null +++ b/src/softfloat/riscv/s_propagateNaNF16UI.rs @@ -0,0 +1,27 @@ +use crate::softfloat::{ + defaultNaNF16UI, defaultNaNF32UI, float16_t, softfloat_flag_invalid, softfloat_isSigNaNF16UI, +}; + +/*---------------------------------------------------------------------------- +| Interpreting `uiA' and `uiB' as the bit patterns of two 16-bit floating- +| point values, at least one of which is a NaN, returns the bit pattern of +| the combined NaN result. If either `uiA' or `uiB' has the pattern of a +| signaling NaN, the invalid exception is raised. +*----------------------------------------------------------------------------*/ +#[inline] +#[must_use] +pub const fn softfloat_propagateNaNF16UI(uiA: u16, uiB: u16) -> (u16, u8) { + let mut flags = 0; + if softfloat_isSigNaNF16UI(uiA) || softfloat_isSigNaNF16UI(uiB) { + flags |= softfloat_flag_invalid; + } + return (defaultNaNF16UI, flags); +} + +#[inline] +#[must_use] +pub const fn softfloat_propagateNaNF16(uiA: u16, uiB: u16) -> (float16_t, u8) { + let (ret, flags) = softfloat_propagateNaNF16UI(uiA, uiB); + + (float16_t { v: ret }, flags) +} diff --git a/src/softfloat/riscv/specialize.rs b/src/softfloat/riscv/specialize.rs index eacfc1b..fa029c1 100644 --- a/src/softfloat/riscv/specialize.rs +++ b/src/softfloat/riscv/specialize.rs @@ -75,6 +75,22 @@ impl commonNaN { } } +/*---------------------------------------------------------------------------- +| The bit pattern for a default generated 16-bit floating-point NaN. +*----------------------------------------------------------------------------*/ +pub const defaultNaNF16UI: u16 = 0x7E00; + +/*---------------------------------------------------------------------------- +| Returns true when 16-bit unsigned integer 'uiA' has the bit pattern of a +| 16-bit floating-point signaling NaN. +| Note: This macro evaluates its argument more than once. +*----------------------------------------------------------------------------*/ +#[inline] +#[must_use] +pub const fn softfloat_isSigNaNF16UI(uiA: u16) -> bool { + (((uiA) & 0x7E00) == 0x7C00) && ((uiA) & 0x01FF) != 0 +} + /*---------------------------------------------------------------------------- | The bit pattern for a default generated 32-bit floating-point NaN. *----------------------------------------------------------------------------*/ diff --git a/src/softfloat/s_addMagsF16.rs b/src/softfloat/s_addMagsF16.rs new file mode 100644 index 0000000..97612dd --- /dev/null +++ b/src/softfloat/s_addMagsF16.rs @@ -0,0 +1,170 @@ +use crate::softfloat::softfloat_propagateNaNF16; + +use super::{ + expF16UI, float16_t, fracF16UI, packToF16, packToF16UI, signF16UI, softfloat_flag_inexact, + softfloat_flag_overflow, softfloat_propagateNaNF16UI, softfloat_roundPackToF16, + softfloat_round_max, softfloat_round_min, softfloat_round_near_even, softfloat_round_odd, +}; + +#[must_use] +pub const fn softfloat_addMagsF16( + uiA: u16, + uiB: u16, + roundingMode: u8, + detectTininess: u8, +) -> (float16_t, u8) { + let expA = expF16UI(uiA); + let sigA = fracF16UI(uiA); + let expB = expF16UI(uiB); + let sigB = fracF16UI(uiB); + let expDiff = expA.wrapping_sub(expB); + if expDiff == 0 { + if expA == 0 { + let uiZ = uiA.wrapping_add(sigB); + return (float16_t { v: uiZ }, 0); + } + if expA == 0x1F { + if (sigA | sigB) != 0 { + return softfloat_propagateNaNF16(uiA, uiB); + } + return (float16_t { v: uiA }, 0); + } + let signZ = signF16UI(uiA); + let expZ = expA; + let mut sigZ = 0x0800_u16.wrapping_add(sigA).wrapping_add(sigB); + if (sigZ & 1) == 0 && (expZ < 0x1E) { + sigZ >>= 1; + return (packToF16(signZ, expZ, sigZ), 0); + } + sigZ <<= 3; + return softfloat_roundPackToF16(signZ, expZ as i16, sigZ, roundingMode, detectTininess); + } + let signZ = signF16UI(uiA); + let expZ: i8; + let sigX: u16; + let sigY: u16; + let shiftDist: i8; + if expDiff < 0 { + if expB == 0x1F { + if sigB != 0 { + return softfloat_propagateNaNF16(uiA, uiB); + } + let uiZ = packToF16UI(signZ, 0x1F, 0); + return (float16_t { v: uiZ }, 0); + } + if expDiff <= -13 { + let uiZ = packToF16UI(signZ, expB, sigB); + if (expA | (sigA as i8)) != 0 { + let mut flags = softfloat_flag_inexact; + let mut result_uiZ = uiZ; + if roundingMode != softfloat_round_near_even { + if roundingMode + == if signF16UI(result_uiZ) { + softfloat_round_min + } else { + softfloat_round_max + } + { + result_uiZ = result_uiZ.wrapping_add(1); + if ((result_uiZ << 1) as u16) == 0xF800 { + flags |= softfloat_flag_overflow; + } + } else if roundingMode == softfloat_round_odd { + result_uiZ |= 1; + } + } + return (float16_t { v: result_uiZ }, flags); + } + return (float16_t { v: uiZ }, 0); + } + expZ = expB; + sigX = sigB | 0x0400; + sigY = sigA.wrapping_add(if expA != 0 { 0x0400 } else { sigA }); + shiftDist = 19 + expDiff; + } else { + let uiZ = uiA; + if expA == 0x1F { + if sigA != 0 { + return softfloat_propagateNaNF16(uiA, uiB); + } + return (float16_t { v: uiZ }, 0); + } + if 13 <= expDiff { + if (expB | (sigB as i8)) != 0 { + let mut flags = softfloat_flag_inexact; + let mut result_uiZ = uiZ; + if roundingMode != softfloat_round_near_even { + if roundingMode + == if signF16UI(result_uiZ) { + softfloat_round_min + } else { + softfloat_round_max + } + { + result_uiZ = result_uiZ.wrapping_add(1); + if ((result_uiZ << 1) as u16) == 0xF800 { + flags |= softfloat_flag_overflow; + } + } else if roundingMode == softfloat_round_odd { + result_uiZ |= 1; + } + } + return (float16_t { v: result_uiZ }, flags); + } + return (float16_t { v: uiZ }, 0); + } + expZ = expA; + sigX = sigA | 0x0400; + sigY = sigB.wrapping_add(if expB != 0 { 0x0400 } else { sigB }); + shiftDist = 19 - expDiff; + } + let mut sig32Z = ((sigX as u32) << 19).wrapping_add((sigY as u32) << shiftDist); + if sig32Z < 0x4000_0000 { + let expZ = expZ.wrapping_sub(1); + sig32Z <<= 1; + let sigZ = (sig32Z >> 16) as u16; + if (sig32Z & 0xFFFF) != 0 { + let sigZ = sigZ | 1; + return softfloat_roundPackToF16( + signZ, + expZ as i16, + sigZ, + roundingMode, + detectTininess, + ); + } + if (sigZ & 0xF) == 0 && (expZ < 0x1E) { + let sigZ = sigZ >> 4; + return (packToF16(signZ, expZ, sigZ), 0); + } + return softfloat_roundPackToF16( + signZ, + expZ as i16, + sigZ, + roundingMode, + detectTininess, + ); + } + let sigZ = (sig32Z >> 16) as u16; + if (sig32Z & 0xFFFF) != 0 { + let sigZ = sigZ | 1; + return softfloat_roundPackToF16( + signZ, + expZ as i16, + sigZ, + roundingMode, + detectTininess, + ); + } + if (sigZ & 0xF) == 0 && (expZ < 0x1E) { + let sigZ = sigZ >> 4; + return (packToF16(signZ, expZ, sigZ), 0); + } + return softfloat_roundPackToF16( + signZ, + expZ as i16, + sigZ, + roundingMode, + detectTininess, + ); +} diff --git a/src/softfloat/s_countLeadingZeros16.rs b/src/softfloat/s_countLeadingZeros16.rs new file mode 100644 index 0000000..92c6b88 --- /dev/null +++ b/src/softfloat/s_countLeadingZeros16.rs @@ -0,0 +1,5 @@ +#[inline] +#[must_use] +pub const fn softfloat_countLeadingZeros16(a: u16) -> u8 { + (if a != 0 { a.leading_zeros() } else { 16 }) as u8 +} diff --git a/src/softfloat/s_normRoundPackToF16.rs b/src/softfloat/s_normRoundPackToF16.rs new file mode 100644 index 0000000..470c81e --- /dev/null +++ b/src/softfloat/s_normRoundPackToF16.rs @@ -0,0 +1,27 @@ +use crate::softfloat::{ + float16_t, packToF16, softfloat_countLeadingZeros32, + softfloat_roundPackToF16, +}; + +#[must_use] +pub const fn softfloat_normRoundPackToF16( + sign: bool, + exp: i16, + sig: u32, + roundingMode: u8, + detectTininess: u8, +) -> (float16_t, u8) { + let shiftDist = softfloat_countLeadingZeros32(sig).wrapping_sub(1) as i8; + let exp = exp.wrapping_sub(shiftDist as i16); + if 4 <= shiftDist && exp < 0x1D { + return ( + packToF16( + sign, + if sig != 0 { exp as i8 } else { 0 }, + (sig << shiftDist.wrapping_sub(4)) as u16, + ), + 0, + ); + } + return softfloat_roundPackToF16(sign, exp, (sig << shiftDist) as u16, roundingMode, detectTininess); +} diff --git a/src/softfloat/s_roundPackToF16.rs b/src/softfloat/s_roundPackToF16.rs new file mode 100644 index 0000000..e252949 --- /dev/null +++ b/src/softfloat/s_roundPackToF16.rs @@ -0,0 +1,69 @@ +use crate::softfloat::{ + float16_t, packToF16, packToF16UI, softfloat_flag_inexact, softfloat_flag_overflow, + softfloat_flag_underflow, softfloat_round_max, softfloat_round_min, softfloat_round_near_even, + softfloat_round_near_maxMag, softfloat_round_odd, softfloat_shiftRightJam32, + softfloat_tininess_beforeRounding, +}; + +#[must_use] +pub const fn softfloat_roundPackToF16( + sign: bool, + mut exp: i16, + mut sig: u16, + roundingMode: u8, + detectTininess: u8, +) -> (float16_t, u8) { + let mut flags = 0; + let roundNearEven = roundingMode == softfloat_round_near_even; + let mut roundIncrement: u8 = 0x8; + + if !roundNearEven && roundingMode != softfloat_round_near_maxMag { + let x = if sign { + softfloat_round_min + } else { + softfloat_round_max + }; + + roundIncrement = if roundingMode == x { 0xF } else { 0 }; + } + let roundBits = (sig & 0xF) as u8; + + if 0x1D <= (exp as u32) { + if exp < 0 { + let isTiny = (detectTininess == softfloat_tininess_beforeRounding) + || (exp < -1) + || (sig.wrapping_add(roundIncrement as u16) < 0x8000); + + sig = softfloat_shiftRightJam32(sig as u32, exp.wrapping_neg() as u16) as u16; + exp = 0; + let roundBits = (sig & 0xF) as u8; + + if isTiny && roundBits != 0 { + flags |= softfloat_flag_underflow; + } + } else if (0x1D < exp) || (0x8000 <= sig.wrapping_add(roundIncrement as u16)) { + flags |= softfloat_flag_overflow | softfloat_flag_inexact; + return ( + float16_t { + v: packToF16UI(sign, 0x1F, 0).wrapping_sub((roundIncrement == 0) as u16), + }, + flags, + ); + } + } + + sig = sig.wrapping_add(roundIncrement as u16) >> 4; + if roundBits != 0 { + flags |= softfloat_flag_inexact; + if roundingMode == softfloat_round_odd { + sig |= 1; + return (packToF16(sign, exp as i8, sig as u16), flags); + } + } + sig &= !(((roundBits ^ 0x8) == 0) as u16 & (roundNearEven as u16)); + if sig == 0 { + exp = 0; + } + + return (packToF16(sign, exp as i8, sig as u16), flags); +} diff --git a/src/softfloat/s_subMagsF16.rs b/src/softfloat/s_subMagsF16.rs new file mode 100644 index 0000000..fe107bc --- /dev/null +++ b/src/softfloat/s_subMagsF16.rs @@ -0,0 +1,166 @@ +use crate::softfloat::softfloat_propagateNaNF16; + +use super::{ + defaultNaNF16UI, expF16UI, float16_t, fracF16UI, packToF16, packToF16UI, signF16UI, + softfloat_countLeadingZeros16, softfloat_countLeadingZeros32, softfloat_flag_inexact, + softfloat_flag_invalid, softfloat_propagateNaNF16UI, softfloat_round_max, + softfloat_round_min, softfloat_round_minMag, softfloat_round_near_even, softfloat_round_odd, + softfloat_roundPackToF16, +}; + +#[must_use] +pub const fn softfloat_subMagsF16( + uiA: u16, + uiB: u16, + roundingMode: u8, + detectTininess: u8, +) -> (float16_t, u8) { + let mut expA = expF16UI(uiA); + let mut sigA = fracF16UI(uiA); + let mut expB = expF16UI(uiB); + let mut sigB = fracF16UI(uiB); + // ------------------------------------------------------------------------ + let mut expDiff = expA.wrapping_sub(expB); + if expDiff == 0 { + // -------------------------------------------------------------------- + if expA == 0x1F { + if (sigA | sigB) != 0 { + return softfloat_propagateNaNF16(uiA, uiB); + } + return ( + float16_t { + v: defaultNaNF16UI, + }, + softfloat_flag_invalid, + ); + } + let mut sigDiff = (sigA as i16).wrapping_sub(sigB as i16); + if sigDiff == 0 { + return ( + packToF16(roundingMode == softfloat_round_min, 0, 0), + 0, + ); + } + if expA != 0 { + expA = expA.wrapping_sub(1); + } + let mut signZ = signF16UI(uiA); + if sigDiff < 0 { + signZ = !signZ; + sigDiff = sigDiff.wrapping_neg(); + } + let mut shiftDist = (softfloat_countLeadingZeros16(sigDiff as u16) as i8).wrapping_sub(5); + let mut expZ = (expA as i8).wrapping_sub(shiftDist); + if expZ < 0 { + shiftDist = expA as i8; + expZ = 0; + } + return ( + packToF16(signZ, expZ, (sigDiff << shiftDist) as u16), + 0, + ); + } + // -------------------------------------------------------------------- + let mut signZ = signF16UI(uiA); + let mut expZ: i8; + let mut sigX: u16; + let mut sigY: u16; + if expDiff < 0 { + // ---------------------------------------------------------------- + signZ = !signZ; + if expB == 0x1F { + if sigB != 0 { + return softfloat_propagateNaNF16(uiA, uiB); + } + return (packToF16(signZ, 0x1F, 0), 0); + } + if expDiff <= -13 { + let uiZ = packToF16UI(signZ, expB, sigB); + if (expA | (sigA as i8)) != 0 { + // -------------------------------------------------------- + let mut flags = softfloat_flag_inexact; + let mut result_uiZ = uiZ; + if roundingMode != softfloat_round_near_even { + if roundingMode == softfloat_round_minMag + || (roundingMode + == if signF16UI(result_uiZ) { + softfloat_round_max + } else { + softfloat_round_min + }) + { + result_uiZ = result_uiZ.wrapping_sub(1); + } else if roundingMode == softfloat_round_odd { + result_uiZ = (result_uiZ.wrapping_sub(1)) | 1; + } + } + return (float16_t { v: result_uiZ }, flags); + } + return (float16_t { v: uiZ }, 0); + } + expZ = (expA as i8) + 19; + sigX = sigB | 0x0400; + sigY = sigA.wrapping_add(if expA != 0 { 0x0400 } else { sigA }); + expDiff = expDiff.wrapping_neg(); + } + // -------------------------------------------------------------------- + let uiZ = uiA; + if expA == 0x1F { + if sigA != 0 { + return softfloat_propagateNaNF16(uiA, uiB); + } + return (float16_t { v: uiZ }, 0); + } + if 13 <= expDiff { + if (expB | (sigB as i8)) != 0 { + // ------------------------------------------------------------ + let mut flags = softfloat_flag_inexact; + let mut result_uiZ = uiZ; + if roundingMode != softfloat_round_near_even { + if roundingMode == softfloat_round_minMag + || (roundingMode + == if signF16UI(result_uiZ) { + softfloat_round_max + } else { + softfloat_round_min + }) + { + result_uiZ = result_uiZ.wrapping_sub(1); + } else if roundingMode == softfloat_round_odd { + result_uiZ = (result_uiZ.wrapping_sub(1)) | 1; + } + } + return (float16_t { v: result_uiZ }, flags); + } + return (float16_t { v: uiZ }, 0); + } + expZ = (expB as i8) + 19; + sigX = sigA | 0x0400; + sigY = sigB.wrapping_add(if expB != 0 { 0x0400 } else { sigB }); + let mut sig32Z = ((sigX as u32) << expDiff).wrapping_sub(sigY as u32); + let shiftDist = (softfloat_countLeadingZeros32(sig32Z) as i8).wrapping_sub(1); + sig32Z <<= shiftDist; + let expZ = expZ.wrapping_sub(shiftDist); + let mut sigZ = (sig32Z >> 16) as u16; + if (sig32Z & 0xFFFF) != 0 { + sigZ |= 1; + return softfloat_roundPackToF16( + signZ, + expZ as i16, + sigZ, + roundingMode, + detectTininess, + ); + } + if (sigZ & 0xF) == 0 && ((expZ as u32) < 0x1E) { + sigZ >>= 4; + return (packToF16(signZ, expZ, sigZ), 0); + } + return softfloat_roundPackToF16( + signZ, + expZ as i16, + sigZ, + roundingMode, + detectTininess, + ); +} diff --git a/src/softfloat/types.rs b/src/softfloat/types.rs index 3d6fb6e..07b1942 100644 --- a/src/softfloat/types.rs +++ b/src/softfloat/types.rs @@ -1,3 +1,10 @@ +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Copy, Clone, Debug, PartialEq)] +#[repr(C)] +pub struct float16_t { + pub v: u16, +} + #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Copy, Clone, Debug, PartialEq)] #[repr(C)] @@ -74,3 +81,17 @@ impl float64_t { self.v } } + +impl float16_t { + #[inline] + #[must_use] + pub const fn from_bits(v: u16) -> Self { + Self { v } + } + + #[inline] + #[must_use] + pub const fn to_bits(self) -> u16 { + self.v + } +} From 943a5f5cb8988887ec07539991515ffb54033eca Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 10:54:49 -0400 Subject: [PATCH 02/23] F16 sub --- src/softfloat/f16_sub.rs | 15 +++++++++++++++ src/softfloat/mod.rs | 2 ++ 2 files changed, 17 insertions(+) create mode 100644 src/softfloat/f16_sub.rs diff --git a/src/softfloat/f16_sub.rs b/src/softfloat/f16_sub.rs new file mode 100644 index 0000000..e8d23d2 --- /dev/null +++ b/src/softfloat/f16_sub.rs @@ -0,0 +1,15 @@ +use super::{float16_t, signF16UI, softfloat_addMagsF16, softfloat_subMagsF16}; + +#[must_use] +pub const fn f16_sub( + a: float16_t, + b: float16_t, + roundingMode: u8, + detectTininess: u8, +) -> (float16_t, u8) { + if signF16UI(a.v ^ b.v) { + softfloat_addMagsF16(a.v, b.v, roundingMode, detectTininess) + } else { + softfloat_subMagsF16(a.v, b.v, roundingMode, detectTininess) + } +} \ No newline at end of file diff --git a/src/softfloat/mod.rs b/src/softfloat/mod.rs index 288f16f..ab36951 100644 --- a/src/softfloat/mod.rs +++ b/src/softfloat/mod.rs @@ -109,6 +109,7 @@ mod s_countLeadingZeros16; mod s_normRoundPackToF16; mod s_roundPackToF16; mod s_subMagsF16; +mod f16_sub; pub use internals::*; mod riscv; @@ -134,6 +135,7 @@ pub const softfloat_round_near_maxMag: u8 = 4; pub const softfloat_round_odd: u8 = 6; pub use f16_add::f16_add; +pub use f16_sub::f16_sub; pub use f32_add::f32_add; pub use f32_classify::f32_classify; pub use f32_div::f32_div; From 57f75c8926db2bd5a8e1b64f68d27a4ceded221a Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 11:25:54 -0400 Subject: [PATCH 03/23] F16 div --- src/softfloat/f16_div.rs | 213 +++++++++++++++++++++++++ src/softfloat/mod.rs | 4 + src/softfloat/s_normSubnormalF16Sig.rs | 11 ++ src/softfloat/types.rs | 7 + 4 files changed, 235 insertions(+) create mode 100644 src/softfloat/f16_div.rs create mode 100644 src/softfloat/s_normSubnormalF16Sig.rs diff --git a/src/softfloat/f16_div.rs b/src/softfloat/f16_div.rs new file mode 100644 index 0000000..31e6e63 --- /dev/null +++ b/src/softfloat/f16_div.rs @@ -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)); + } + } +} diff --git a/src/softfloat/mod.rs b/src/softfloat/mod.rs index ab36951..6283b22 100644 --- a/src/softfloat/mod.rs +++ b/src/softfloat/mod.rs @@ -20,6 +20,7 @@ )] mod f16_add; +mod f16_div; mod f32_add; mod f32_classify; mod f32_div; @@ -76,6 +77,7 @@ mod s_approxRecip_1Ks; mod s_countLeadingZeros32; mod s_countLeadingZeros64; mod s_mul64To128; +mod s_normSubnormalF16Sig; mod s_mulAddF32; mod s_mulAddF64; mod s_normRoundPackToF32; @@ -135,6 +137,7 @@ pub const softfloat_round_near_maxMag: u8 = 4; pub const softfloat_round_odd: u8 = 6; pub use f16_add::f16_add; +pub use f16_div::f16_div; pub use f16_sub::f16_sub; pub use f32_add::f32_add; pub use f32_classify::f32_classify; @@ -202,6 +205,7 @@ pub use s_mulAddF64::softfloat_mulAddF64; pub use s_normRoundPackToF16::softfloat_normRoundPackToF16; pub use s_normRoundPackToF32::softfloat_normRoundPackToF32; pub use s_normRoundPackToF64::softfloat_normRoundPackToF64; +pub use s_normSubnormalF16Sig::softfloat_normSubnormalF16Sig; pub use s_normSubnormalF32Sig::softfloat_normSubnormalF32Sig; pub use s_normSubnormalF64Sig::softfloat_normSubnormalF64Sig; pub use s_roundPackToF16::softfloat_roundPackToF16; diff --git a/src/softfloat/s_normSubnormalF16Sig.rs b/src/softfloat/s_normSubnormalF16Sig.rs new file mode 100644 index 0000000..28421a8 --- /dev/null +++ b/src/softfloat/s_normSubnormalF16Sig.rs @@ -0,0 +1,11 @@ +use super::{exp8_sig16, softfloat_countLeadingZeros16}; + +#[inline] +#[must_use] +pub const fn softfloat_normSubnormalF16Sig(sig: u16) -> exp8_sig16 { + let shiftDist = softfloat_countLeadingZeros16(sig).wrapping_sub(5) as i8; + exp8_sig16 { + exp: (1 as i8).wrapping_sub(shiftDist), + sig: sig << shiftDist, + } +} diff --git a/src/softfloat/types.rs b/src/softfloat/types.rs index 07b1942..e7b3455 100644 --- a/src/softfloat/types.rs +++ b/src/softfloat/types.rs @@ -26,6 +26,13 @@ pub struct uint128 { pub v64: u64, } +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct exp8_sig16 { + pub exp: i8, + pub sig: u16, +} + #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct exp16_sig32 { From 1475d6c8b6f34d46c1a4aea4d8502fb52cd59677 Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 11:28:51 -0400 Subject: [PATCH 04/23] F16 classify --- src/softfloat/f16_classify.rs | 22 ++++++++++++++++++++++ src/softfloat/mod.rs | 2 ++ 2 files changed, 24 insertions(+) create mode 100644 src/softfloat/f16_classify.rs diff --git a/src/softfloat/f16_classify.rs b/src/softfloat/f16_classify.rs new file mode 100644 index 0000000..fe40499 --- /dev/null +++ b/src/softfloat/f16_classify.rs @@ -0,0 +1,22 @@ +use super::{expF16UI, float16_t, fracF16UI, isNaNF16UI, signF16UI, softfloat_isSigNaNF16UI}; + +#[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); +} diff --git a/src/softfloat/mod.rs b/src/softfloat/mod.rs index 6283b22..64294bd 100644 --- a/src/softfloat/mod.rs +++ b/src/softfloat/mod.rs @@ -20,6 +20,7 @@ )] mod f16_add; +mod f16_classify; mod f16_div; mod f32_add; mod f32_classify; @@ -137,6 +138,7 @@ pub const softfloat_round_near_maxMag: u8 = 4; pub const softfloat_round_odd: u8 = 6; pub use f16_add::f16_add; +pub use f16_classify::f16_classify; pub use f16_div::f16_div; pub use f16_sub::f16_sub; pub use f32_add::f32_add; From 59de77ae9f0ae30594a4c7c6b082efa3fca0e8a8 Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 11:30:50 -0400 Subject: [PATCH 05/23] F16 eq_signaling --- src/softfloat/f16_eq_signaling.rs | 9 +++++++++ src/softfloat/mod.rs | 2 ++ 2 files changed, 11 insertions(+) create mode 100644 src/softfloat/f16_eq_signaling.rs diff --git a/src/softfloat/f16_eq_signaling.rs b/src/softfloat/f16_eq_signaling.rs new file mode 100644 index 0000000..8cbdc49 --- /dev/null +++ b/src/softfloat/f16_eq_signaling.rs @@ -0,0 +1,9 @@ +use super::{float16_t, isNaNF16UI, softfloat_flag_invalid}; + +#[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); +} diff --git a/src/softfloat/mod.rs b/src/softfloat/mod.rs index 64294bd..9b01ece 100644 --- a/src/softfloat/mod.rs +++ b/src/softfloat/mod.rs @@ -113,6 +113,7 @@ mod s_normRoundPackToF16; mod s_roundPackToF16; mod s_subMagsF16; mod f16_sub; +mod f16_eq_signaling; pub use internals::*; mod riscv; @@ -140,6 +141,7 @@ pub const softfloat_round_odd: u8 = 6; pub use f16_add::f16_add; pub use f16_classify::f16_classify; pub use f16_div::f16_div; +pub use f16_eq_signaling::f16_eq_signaling; pub use f16_sub::f16_sub; pub use f32_add::f32_add; pub use f32_classify::f32_classify; From 98dc53f8840f0058780d0a2a958801db7ee9b50c Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 11:32:23 -0400 Subject: [PATCH 06/23] F16 eq --- src/softfloat/f16_eq.rs | 12 ++++++++++++ src/softfloat/mod.rs | 8 +++++--- 2 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 src/softfloat/f16_eq.rs diff --git a/src/softfloat/f16_eq.rs b/src/softfloat/f16_eq.rs new file mode 100644 index 0000000..d1b75d4 --- /dev/null +++ b/src/softfloat/f16_eq.rs @@ -0,0 +1,12 @@ +use super::{float16_t, isNaNF16UI, softfloat_flag_invalid, softfloat_isSigNaNF16UI}; + +#[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); +} diff --git a/src/softfloat/mod.rs b/src/softfloat/mod.rs index 9b01ece..a14c650 100644 --- a/src/softfloat/mod.rs +++ b/src/softfloat/mod.rs @@ -78,11 +78,11 @@ mod s_approxRecip_1Ks; mod s_countLeadingZeros32; mod s_countLeadingZeros64; mod s_mul64To128; -mod s_normSubnormalF16Sig; mod s_mulAddF32; mod s_mulAddF64; mod s_normRoundPackToF32; mod s_normRoundPackToF64; +mod s_normSubnormalF16Sig; mod s_normSubnormalF32Sig; mod s_normSubnormalF64Sig; mod s_roundPackToF32; @@ -106,14 +106,15 @@ mod ui32_to_f64; mod ui64_to_f32; mod ui64_to_f64; +mod f16_eq; +mod f16_eq_signaling; +mod f16_sub; mod internals; mod s_addMagsF16; mod s_countLeadingZeros16; mod s_normRoundPackToF16; mod s_roundPackToF16; mod s_subMagsF16; -mod f16_sub; -mod f16_eq_signaling; pub use internals::*; mod riscv; @@ -141,6 +142,7 @@ pub const softfloat_round_odd: u8 = 6; pub use f16_add::f16_add; pub use f16_classify::f16_classify; pub use f16_div::f16_div; +pub use f16_eq::f16_eq; pub use f16_eq_signaling::f16_eq_signaling; pub use f16_sub::f16_sub; pub use f32_add::f32_add; From 75f60d39c857232fda5e3f1feb96010bb0d390d0 Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 11:33:09 -0400 Subject: [PATCH 07/23] F16 isSignalingNaN --- src/softfloat/f16_isSignalingNaN.rs | 7 +++++++ src/softfloat/mod.rs | 2 ++ 2 files changed, 9 insertions(+) create mode 100644 src/softfloat/f16_isSignalingNaN.rs diff --git a/src/softfloat/f16_isSignalingNaN.rs b/src/softfloat/f16_isSignalingNaN.rs new file mode 100644 index 0000000..e91a098 --- /dev/null +++ b/src/softfloat/f16_isSignalingNaN.rs @@ -0,0 +1,7 @@ +use super::{float16_t, softfloat_isSigNaNF16UI}; + +#[must_use] +#[inline] +pub const fn f16_isSignalingNaN(a: float16_t) -> bool { + return softfloat_isSigNaNF16UI(a.v); +} diff --git a/src/softfloat/mod.rs b/src/softfloat/mod.rs index a14c650..6b3bb01 100644 --- a/src/softfloat/mod.rs +++ b/src/softfloat/mod.rs @@ -108,6 +108,7 @@ mod ui64_to_f64; mod f16_eq; mod f16_eq_signaling; +mod f16_isSignalingNaN; mod f16_sub; mod internals; mod s_addMagsF16; @@ -144,6 +145,7 @@ pub use f16_classify::f16_classify; pub use f16_div::f16_div; pub use f16_eq::f16_eq; pub use f16_eq_signaling::f16_eq_signaling; +pub use f16_isSignalingNaN::f16_isSignalingNaN; pub use f16_sub::f16_sub; pub use f32_add::f32_add; pub use f32_classify::f32_classify; From bfd4af0e1f83c7d8ee847f56845e04a6770a991e Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 11:35:09 -0400 Subject: [PATCH 08/23] F16 le_quiet --- src/softfloat/f16_le_quiet.rs | 21 +++++++++++++++++++++ src/softfloat/mod.rs | 2 ++ 2 files changed, 23 insertions(+) create mode 100644 src/softfloat/f16_le_quiet.rs diff --git a/src/softfloat/f16_le_quiet.rs b/src/softfloat/f16_le_quiet.rs new file mode 100644 index 0000000..a9652ad --- /dev/null +++ b/src/softfloat/f16_le_quiet.rs @@ -0,0 +1,21 @@ +use super::{float16_t, isNaNF16UI, signF16UI, softfloat_flag_invalid, softfloat_isSigNaNF16UI}; + +#[must_use] +pub const fn f16_le_quiet(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); + } + let signA = signF16UI(a.v); + let signB = signF16UI(b.v); + ( + if signA != signB { + signA || ((a.v | b.v) << 1) == 0 + } else { + a.v == b.v || signA ^ (a.v < b.v) + }, + 0, + ) +} diff --git a/src/softfloat/mod.rs b/src/softfloat/mod.rs index 6b3bb01..6332a50 100644 --- a/src/softfloat/mod.rs +++ b/src/softfloat/mod.rs @@ -116,6 +116,7 @@ mod s_countLeadingZeros16; mod s_normRoundPackToF16; mod s_roundPackToF16; mod s_subMagsF16; +mod f16_le_quiet; pub use internals::*; mod riscv; @@ -146,6 +147,7 @@ pub use f16_div::f16_div; pub use f16_eq::f16_eq; pub use f16_eq_signaling::f16_eq_signaling; pub use f16_isSignalingNaN::f16_isSignalingNaN; +pub use f16_le_quiet::f16_le_quiet; pub use f16_sub::f16_sub; pub use f32_add::f32_add; pub use f32_classify::f32_classify; From 573b36dff1ac0421c388aafb000aeefd43838b66 Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 11:35:59 -0400 Subject: [PATCH 09/23] F16 le --- src/softfloat/f16_le.rs | 18 ++++++++++++++++++ src/softfloat/mod.rs | 2 ++ 2 files changed, 20 insertions(+) create mode 100644 src/softfloat/f16_le.rs diff --git a/src/softfloat/f16_le.rs b/src/softfloat/f16_le.rs new file mode 100644 index 0000000..aaf49a0 --- /dev/null +++ b/src/softfloat/f16_le.rs @@ -0,0 +1,18 @@ +use super::{float16_t, isNaNF16UI, signF16UI, softfloat_flag_invalid}; + +#[must_use] +pub const fn f16_le(a: float16_t, b: float16_t) -> (bool, u8) { + if isNaNF16UI(a.v) || isNaNF16UI(b.v) { + return (false, softfloat_flag_invalid); + } + let signA = signF16UI(a.v); + let signB = signF16UI(b.v); + ( + if signA != signB { + signA || ((a.v | b.v) << 1) == 0 + } else { + a.v == b.v || signA ^ (a.v < b.v) + }, + 0, + ) +} diff --git a/src/softfloat/mod.rs b/src/softfloat/mod.rs index 6332a50..e3b23ef 100644 --- a/src/softfloat/mod.rs +++ b/src/softfloat/mod.rs @@ -117,6 +117,7 @@ mod s_normRoundPackToF16; mod s_roundPackToF16; mod s_subMagsF16; mod f16_le_quiet; +mod f16_le; pub use internals::*; mod riscv; @@ -148,6 +149,7 @@ pub use f16_eq::f16_eq; pub use f16_eq_signaling::f16_eq_signaling; pub use f16_isSignalingNaN::f16_isSignalingNaN; pub use f16_le_quiet::f16_le_quiet; +pub use f16_le::f16_le; pub use f16_sub::f16_sub; pub use f32_add::f32_add; pub use f32_classify::f32_classify; From 107fa3cb7760aaa82d454da019b8c6dafd1edf2c Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 11:37:31 -0400 Subject: [PATCH 10/23] F16 lt/lt_quiet --- src/softfloat/f16_lt.rs | 18 ++++++++++++++++++ src/softfloat/f16_lt_quiet.rs | 21 +++++++++++++++++++++ src/softfloat/mod.rs | 4 ++++ 3 files changed, 43 insertions(+) create mode 100644 src/softfloat/f16_lt.rs create mode 100644 src/softfloat/f16_lt_quiet.rs diff --git a/src/softfloat/f16_lt.rs b/src/softfloat/f16_lt.rs new file mode 100644 index 0000000..764d873 --- /dev/null +++ b/src/softfloat/f16_lt.rs @@ -0,0 +1,18 @@ +use super::{float16_t, isNaNF16UI, signF16UI, softfloat_flag_invalid}; + +#[must_use] +pub const fn f16_lt(a: float16_t, b: float16_t) -> (bool, u8) { + if isNaNF16UI(a.v) || isNaNF16UI(b.v) { + return (false, softfloat_flag_invalid); + } + let signA = signF16UI(a.v); + let signB = signF16UI(b.v); + return ( + if signA != signB { + signA && ((a.v | b.v) << 1) != 0 + } else { + a.v != b.v && signA ^ (a.v < b.v) + }, + 0, + ); +} diff --git a/src/softfloat/f16_lt_quiet.rs b/src/softfloat/f16_lt_quiet.rs new file mode 100644 index 0000000..a1562d6 --- /dev/null +++ b/src/softfloat/f16_lt_quiet.rs @@ -0,0 +1,21 @@ +use super::{float16_t, isNaNF16UI, signF16UI, softfloat_flag_invalid, softfloat_isSigNaNF16UI}; + +#[must_use] +pub const fn f16_lt_quiet(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); + } + let signA = signF16UI(a.v); + let signB = signF16UI(b.v); + return ( + if signA != signB { + signA && ((a.v | b.v) << 1) != 0 + } else { + a.v != b.v && signA ^ (a.v < b.v) + }, + 0, + ); +} diff --git a/src/softfloat/mod.rs b/src/softfloat/mod.rs index e3b23ef..4cb1d7f 100644 --- a/src/softfloat/mod.rs +++ b/src/softfloat/mod.rs @@ -118,6 +118,8 @@ mod s_roundPackToF16; mod s_subMagsF16; mod f16_le_quiet; mod f16_le; +mod f16_lt_quiet; +mod f16_lt; pub use internals::*; mod riscv; @@ -149,6 +151,8 @@ pub use f16_eq::f16_eq; pub use f16_eq_signaling::f16_eq_signaling; pub use f16_isSignalingNaN::f16_isSignalingNaN; pub use f16_le_quiet::f16_le_quiet; +pub use f16_lt_quiet::f16_lt_quiet; +pub use f16_lt::f16_lt; pub use f16_le::f16_le; pub use f16_sub::f16_sub; pub use f32_add::f32_add; From db6402dc9c61e4e61075ab50534e372d0ffc8cbb Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 12:05:13 -0400 Subject: [PATCH 11/23] F16 mul --- src/softfloat/f16_mul.rs | 158 +++++++++++++++++++++++++++++++++++++++ src/softfloat/mod.rs | 14 ++-- 2 files changed, 166 insertions(+), 6 deletions(-) create mode 100644 src/softfloat/f16_mul.rs diff --git a/src/softfloat/f16_mul.rs b/src/softfloat/f16_mul.rs new file mode 100644 index 0000000..63aaf80 --- /dev/null +++ b/src/softfloat/f16_mul.rs @@ -0,0 +1,158 @@ +use super::{ + defaultNaNF16UI, exp8_sig16, expF16UI, float16_t, fracF16UI, packToF16, signF16UI, + softfloat_flag_invalid, softfloat_normSubnormalF16Sig, softfloat_propagateNaNF16, + softfloat_roundPackToF16, +}; + +#[must_use] +pub const fn f16_mul( + 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 || ((expB == 0x1F) && sigB != 0) { + return softfloat_propagateNaNF16(a.v, b.v); + } + let magBits = (expB as u16) | sigB; + if magBits == 0 { + return (float16_t { v: defaultNaNF16UI }, softfloat_flag_invalid); + } + return (packToF16(signZ, 0x1F, 0), 0); + } + + let mut normExpSig = exp8_sig16 { exp: 0, sig: 0 }; + + if expB == 0x1F { + if sigB != 0 { + return softfloat_propagateNaNF16(a.v, b.v); + } + let magBits = (expA as u16) | sigA; + if magBits == 0 { + return (float16_t { v: defaultNaNF16UI }, softfloat_flag_invalid); + } + return (packToF16(signZ, 0x1F, 0), 0); + } + + if expA == 0 { + if sigA == 0 { + return (packToF16(signZ, 0, 0), 0); + } + normExpSig = softfloat_normSubnormalF16Sig(sigA); + expA = normExpSig.exp; + sigA = normExpSig.sig; + } + + if expB == 0 { + if sigB == 0 { + return (packToF16(signZ, 0, 0), 0); + } + normExpSig = softfloat_normSubnormalF16Sig(sigB); + expB = normExpSig.exp; + sigB = normExpSig.sig; + } + + let mut expZ = (expA as i16).wrapping_add(expB as i16).wrapping_sub(0xF); + sigA = (sigA | 0x0400) << 4; + sigB = (sigB | 0x0400) << 5; + let sig32Z: u32 = (sigA as u32).wrapping_mul(sigB as u32); + let mut sigZ: u16 = (sig32Z >> 16) as u16; + if (sig32Z & 0xFFFF) != 0 { + sigZ |= 1; + } + if sigZ < 0x4000 { + expZ -= 1; + sigZ <<= 1; + } + + return softfloat_roundPackToF16(signZ, expZ, sigZ, roundingMode, detectTininess); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_f16_mul() { + struct softfloat_f16_mul_TestCase { + a: u16, + b: u16, + result: u16, + flags: u8, + roundingMode: u8, + detectTininess: u8, + } + + let cases = [ + softfloat_f16_mul_TestCase { + a: 0x3C00, + b: 0x3C00, + result: 0x3C00, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f16_mul_TestCase { + a: 0x4000, + b: 0x4200, + result: 0x4600, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f16_mul_TestCase { + a: 0x3800, + b: 0x3800, + result: 0x3400, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f16_mul_TestCase { + a: 0xBC00, + b: 0x3C00, + result: 0xBC00, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f16_mul_TestCase { + a: 0x0000, + b: 0x3C00, + result: 0x0000, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f16_mul_TestCase { + a: 0xBC00, + b: 0xBC00, + result: 0x3C00, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + ]; + + for (i, c) in cases.iter().enumerate() { + let (res, flags) = f16_mul( + 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)); + } + } +} diff --git a/src/softfloat/mod.rs b/src/softfloat/mod.rs index 4cb1d7f..638639c 100644 --- a/src/softfloat/mod.rs +++ b/src/softfloat/mod.rs @@ -109,6 +109,11 @@ mod ui64_to_f64; mod f16_eq; mod f16_eq_signaling; mod f16_isSignalingNaN; +mod f16_le; +mod f16_le_quiet; +mod f16_lt; +mod f16_lt_quiet; +mod f16_mul; mod f16_sub; mod internals; mod s_addMagsF16; @@ -116,10 +121,6 @@ mod s_countLeadingZeros16; mod s_normRoundPackToF16; mod s_roundPackToF16; mod s_subMagsF16; -mod f16_le_quiet; -mod f16_le; -mod f16_lt_quiet; -mod f16_lt; pub use internals::*; mod riscv; @@ -150,10 +151,11 @@ pub use f16_div::f16_div; pub use f16_eq::f16_eq; pub use f16_eq_signaling::f16_eq_signaling; pub use f16_isSignalingNaN::f16_isSignalingNaN; +pub use f16_le::f16_le; pub use f16_le_quiet::f16_le_quiet; -pub use f16_lt_quiet::f16_lt_quiet; pub use f16_lt::f16_lt; -pub use f16_le::f16_le; +pub use f16_lt_quiet::f16_lt_quiet; +pub use f16_mul::f16_mul; pub use f16_sub::f16_sub; pub use f32_add::f32_add; pub use f32_classify::f32_classify; From a321ba322ddfc68d3c8ad272a39f9ae261ef173e Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 14:24:39 -0400 Subject: [PATCH 12/23] F16 mulAdd --- src/softfloat/f16_mulAdd.rs | 81 ++++++++++++++ src/softfloat/mod.rs | 4 + src/softfloat/s_mulAddF16.rs | 210 +++++++++++++++++++++++++++++++++++ 3 files changed, 295 insertions(+) create mode 100644 src/softfloat/f16_mulAdd.rs create mode 100644 src/softfloat/s_mulAddF16.rs diff --git a/src/softfloat/f16_mulAdd.rs b/src/softfloat/f16_mulAdd.rs new file mode 100644 index 0000000..4f89bf6 --- /dev/null +++ b/src/softfloat/f16_mulAdd.rs @@ -0,0 +1,81 @@ +use super::{float16_t, softfloat_mulAddF16}; + +#[inline] +#[must_use] +pub const fn f16_mulAdd( + a: float16_t, + b: float16_t, + c: float16_t, + roundingMode: u8, + detectTininess: u8, +) -> (float16_t, u8) { + return softfloat_mulAddF16(a.v, b.v, c.v, 0, roundingMode, detectTininess); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_f16_mulAdd() { + struct softfloat_f16_mulAdd_TestCase { + a: u16, + b: u16, + c: u16, + result: u16, + flags: u8, + roundingMode: u8, + detectTininess: u8, + } + + let cases = [ + softfloat_f16_mulAdd_TestCase { + a: 0x3C00, + b: 0x3C00, + c: 0x0000, + result: 0x3C00, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f16_mulAdd_TestCase { + a: 0x4000, + b: 0x4200, + c: 0x3C00, + result: 0x4700, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f16_mulAdd_TestCase { + a: 0x3800, + b: 0x3800, + c: 0x3800, + result: 0x3A00, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f16_mulAdd_TestCase { + a: 0x3C00, + b: 0x0000, + c: 0x3C00, + result: 0x3C00, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + ]; + + for (i, c) in cases.iter().enumerate() { + let (res, flags) = f16_mulAdd( + float16_t { v: c.a }, + float16_t { v: c.b }, + float16_t { v: c.c }, + c.roundingMode, + c.detectTininess, + ); + assert_eq!((i, res.v, flags), (i, c.result, c.flags)); + } + } +} diff --git a/src/softfloat/mod.rs b/src/softfloat/mod.rs index 638639c..15566da 100644 --- a/src/softfloat/mod.rs +++ b/src/softfloat/mod.rs @@ -22,6 +22,7 @@ mod f16_add; mod f16_classify; mod f16_div; +mod f16_mulAdd; mod f32_add; mod f32_classify; mod f32_div; @@ -118,6 +119,7 @@ mod f16_sub; mod internals; mod s_addMagsF16; mod s_countLeadingZeros16; +mod s_mulAddF16; mod s_normRoundPackToF16; mod s_roundPackToF16; mod s_subMagsF16; @@ -156,6 +158,7 @@ pub use f16_le_quiet::f16_le_quiet; pub use f16_lt::f16_lt; pub use f16_lt_quiet::f16_lt_quiet; pub use f16_mul::f16_mul; +pub use f16_mulAdd::f16_mulAdd; pub use f16_sub::f16_sub; pub use f32_add::f32_add; pub use f32_classify::f32_classify; @@ -218,6 +221,7 @@ pub use s_add128::softfloat_add128; pub use s_approxRecip_1Ks::softfloat_approxRecip_1k0s; pub use s_approxRecip_1Ks::softfloat_approxRecip_1k1s; pub use s_mul64To128::softfloat_mul64To128; +pub use s_mulAddF16::softfloat_mulAddF16; pub use s_mulAddF32::softfloat_mulAddF32; pub use s_mulAddF64::softfloat_mulAddF64; pub use s_normRoundPackToF16::softfloat_normRoundPackToF16; diff --git a/src/softfloat/s_mulAddF16.rs b/src/softfloat/s_mulAddF16.rs new file mode 100644 index 0000000..cdc01ba --- /dev/null +++ b/src/softfloat/s_mulAddF16.rs @@ -0,0 +1,210 @@ +use super::{ + defaultNaNF16UI, expF16UI, float16_t, fracF16UI, packToF16, packToF16UI, signF16UI, + softfloat_countLeadingZeros32, softfloat_flag_invalid, softfloat_normSubnormalF16Sig, + softfloat_propagateNaNF16, softfloat_propagateNaNF16UI, softfloat_roundPackToF16, + softfloat_round_min, softfloat_shiftRightJam32, +}; + +pub const softfloat_mulAdd_subProd: u8 = 2; +pub const softfloat_mulAdd_subC: u8 = 1; + +#[inline] +const fn propagateNaN_ZC(uiZ: u16, uiC: u16) -> (float16_t, u8) { + softfloat_propagateNaNF16(uiZ, uiC) +} + +#[inline] +const fn propagateNaN_ABC(uiA: u16, uiB: u16, uiC: u16) -> (float16_t, u8) { + let (uiZ, flags) = softfloat_propagateNaNF16UI(uiA, uiB); + let (res, new_flags) = propagateNaN_ZC(uiZ, uiC); + return (res, flags | new_flags); +} + +#[inline] +const fn infProdArg( + magBits: u16, + signProd: bool, + expC: i8, + sigC: u16, + signC: bool, + uiC: u16, +) -> (float16_t, u8) { + if magBits != 0 { + let uiZ = packToF16UI(signProd, 0x1F, 0); + if expC != 0x1F { + return (float16_t { v: uiZ }, 0); + } + if sigC != 0 { + return propagateNaN_ZC(uiZ, uiC); + } + if signProd == signC { + return (float16_t { v: uiZ }, 0); + } + } + let (res, flags) = propagateNaN_ZC(defaultNaNF16UI, uiC); + return (res, flags | softfloat_flag_invalid); +} + +#[inline] +const fn completeCancellation(roundingMode: u8) -> float16_t { + packToF16((roundingMode == softfloat_round_min), 0, 0) +} + +#[inline] +const fn zeroProd( + uiC: u16, + expC: i8, + sigC: u16, + signProd: bool, + signC: bool, + roundingMode: u8, +) -> float16_t { + if ((expC as u16) | sigC) == 0 && (signProd != signC) { + return completeCancellation(roundingMode); + } + return float16_t { v: uiC }; +} + +#[must_use] +pub const fn softfloat_mulAddF16( + uiA: u16, + uiB: u16, + uiC: u16, + op: u8, + roundingMode: u8, + detectTininess: u8, +) -> (float16_t, u8) { + let signA = signF16UI(uiA); + let mut expA = expF16UI(uiA); + let mut sigA = fracF16UI(uiA); + let signB = signF16UI(uiB); + let mut expB = expF16UI(uiB); + let mut sigB = fracF16UI(uiB); + let signC = signF16UI(uiC) ^ (op == softfloat_mulAdd_subC); + let mut expC = expF16UI(uiC); + let mut sigC = fracF16UI(uiC); + let signProd = signA ^ signB ^ (op == softfloat_mulAdd_subProd); + + if expA == 0x1F { + if sigA != 0 || ((expB == 0x1F) && (sigB != 0)) { + return propagateNaN_ABC(uiA, uiB, uiC); + } + return infProdArg((expB as u16) | sigB, signProd, expC, sigC, signC, uiC); + } + if expB == 0x1F { + if sigB != 0 { + return propagateNaN_ABC(uiA, uiB, uiC); + } + return infProdArg((expA as u16) | sigA, signProd, expC, sigC, signC, uiC); + } + if expC == 0x1F { + if sigC != 0 { + return propagateNaN_ZC(0, uiC); + } + return (float16_t { v: uiC }, 0); + } + + if expA == 0 { + if sigA == 0 { + return (zeroProd(uiC, expC, sigC, signProd, signC, roundingMode), 0); + } + let normExpSig = softfloat_normSubnormalF16Sig(sigA); + expA = normExpSig.exp; + sigA = normExpSig.sig; + } + if expB == 0 { + if sigB == 0 { + return (zeroProd(uiC, expC, sigC, signProd, signC, roundingMode), 0); + } + let normExpSig = softfloat_normSubnormalF16Sig(sigB); + expB = normExpSig.exp; + sigB = normExpSig.sig; + } + + let mut expProd = expA.wrapping_add(expB).wrapping_sub(0xE); + sigA = (sigA | 0x0400) << 4; + sigB = (sigB | 0x0400) << 4; + let mut sigProd = (sigA as u32).wrapping_mul(sigB as u32); + if sigProd < 0x2000_0000 { + expProd = expProd.wrapping_sub(1); + sigProd <<= 1; + } + + let mut signZ = signProd; + if expC == 0 { + if sigC == 0 { + let expZ = expProd.wrapping_sub(1); + let sigZ = (sigProd >> 15) as u16 | ((sigProd & 0x7FFF) != 0) as u16; + return softfloat_roundPackToF16( + signZ, + expZ as i16, + sigZ, + roundingMode, + detectTininess, + ); + } + let normExpSig = softfloat_normSubnormalF16Sig(sigC); + expC = normExpSig.exp; + sigC = normExpSig.sig; + } + sigC = (sigC | 0x0400) << 3; + + let expDiff = expProd - expC; + let mut sig32Z: u32; + let mut sigZ: u16; + let mut expZ: i8; + if signProd == signC { + if expDiff <= 0 { + expZ = expC; + sigZ = (sigC as u32).wrapping_add(softfloat_shiftRightJam32( + sigProd, + (16_i8).wrapping_sub(expDiff) as u16, + )) as u16; + } else { + expZ = expProd; + sig32Z = sigProd.wrapping_add(softfloat_shiftRightJam32( + (sigC as u32) << 16, + expDiff as u16, + )); + sigZ = (sig32Z >> 16) as u16 | ((sig32Z & 0xFFFF) != 0) as u16; + } + if sigZ < 0x4000 { + expZ = expZ.wrapping_sub(1); + sigZ <<= 1; + } + } else { + let sig32C = (sigC as u32) << 16; + if expDiff < 0 { + signZ = signC; + expZ = expC; + sig32Z = sig32C.wrapping_sub(softfloat_shiftRightJam32( + sigProd, + expDiff.wrapping_neg() as u16, + )); + } else if expDiff == 0 { + expZ = expProd; + sig32Z = sigProd.wrapping_sub(sig32C); + if sig32Z == 0 { + return (packToF16((roundingMode == softfloat_round_min), 0, 0), 0); + } + if (sig32Z & 0x8000_0000) != 0 { + signZ = !signZ; + sig32Z = sig32Z.wrapping_neg(); + } + } else { + expZ = expProd; + sig32Z = sigProd.wrapping_sub(softfloat_shiftRightJam32(sig32C, expDiff as u16)); + } + let mut shiftDist: i8 = softfloat_countLeadingZeros32(sig32Z).wrapping_sub(1) as i8; + expZ = expZ.wrapping_sub(shiftDist); + shiftDist = shiftDist.wrapping_sub(16); + if shiftDist < 0 { + sigZ = (sig32Z >> shiftDist.wrapping_neg()) as u16 + | ((sig32Z << (shiftDist & 31)) != 0) as u16; + } else { + sigZ = (sig32Z << shiftDist) as u16; + } + } + + return softfloat_roundPackToF16(signZ, expZ as i16, sigZ, roundingMode, detectTininess); +} From 860418f5fab06d816072f6c1a02eb23fbcf9d955 Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 15:21:45 -0400 Subject: [PATCH 13/23] F16 rem --- src/softfloat/f16_rem.rs | 178 ++++++++++++++++++++++++++ src/softfloat/mod.rs | 2 + src/softfloat/s_normRoundPackToF16.rs | 23 ++-- 3 files changed, 192 insertions(+), 11 deletions(-) create mode 100644 src/softfloat/f16_rem.rs diff --git a/src/softfloat/f16_rem.rs b/src/softfloat/f16_rem.rs new file mode 100644 index 0000000..4a48ffe --- /dev/null +++ b/src/softfloat/f16_rem.rs @@ -0,0 +1,178 @@ +use crate::softfloat::{ + defaultNaNF16UI, expF16UI, float16_t, fracF16UI, signF16UI, softfloat_approxRecip32_1, + softfloat_flag_invalid, softfloat_normRoundPackToF16, softfloat_normSubnormalF16Sig, + softfloat_propagateNaNF16, +}; + +#[must_use] +pub const fn f16_rem( + 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 mut expB = expF16UI(b.v); + let mut sigB = fracF16UI(b.v); + + if expA == 0x1F { + if (sigA != 0) || ((expB == 0x1F) && (sigB != 0)) { + return softfloat_propagateNaNF16(a.v, b.v); + } + return (float16_t { v: defaultNaNF16UI }, softfloat_flag_invalid); + } + if expB == 0x1F { + if sigB != 0 { + return softfloat_propagateNaNF16(a.v, b.v); + } + return (a, 0); + } + + if expB == 0 { + if sigB == 0 { + return (float16_t { v: defaultNaNF16UI }, softfloat_flag_invalid); + } + let normExpSig = softfloat_normSubnormalF16Sig(sigB); + expB = normExpSig.exp; + sigB = normExpSig.sig; + } + if expA == 0 { + if sigA == 0 { + return (a, 0); + } + let normExpSig = softfloat_normSubnormalF16Sig(sigA); + expA = normExpSig.exp; + sigA = normExpSig.sig; + } + + let mut rem = sigA | 0x0400; + let mut q: u16; + sigB |= 0x0400; + let mut expDiff = expA.wrapping_sub(expB); + if expDiff < 1 { + if expDiff < -1 { + return (a, 0); + } + + sigB <<= 3; + if expDiff != 0 { + rem <<= 2; + q = 0; + } else { + rem <<= 3; + q = (sigB <= rem) as u16; + if q != 0 { + rem = rem.wrapping_sub(sigB); + } + } + } else { + let recip32 = softfloat_approxRecip32_1((sigB as u32) << 21); + rem <<= 4; + expDiff = expDiff.wrapping_sub(31); + sigB <<= 3; + + let mut q32: u32; + loop { + q32 = ((rem as u64).wrapping_mul(recip32 as u64) >> 16) as u32; + if expDiff < 0 { + break; + } + rem = (q32 as u16).wrapping_mul(sigB).wrapping_neg(); + expDiff -= 29; + } + + q32 >>= !(expDiff as u16) & 31; + q = q32 as u16; + rem = (rem.wrapping_shl((expDiff as u32).wrapping_add(30))) + .wrapping_sub(q.wrapping_mul(sigB)); + } + + // ------------------------------------------------------------------------ + + let mut altRem: u16; + loop { + altRem = rem; + q = q.wrapping_add(1); + rem = rem.wrapping_sub(sigB); + + if (rem & 0x8000) != 0 { + break; + } + } + let meanRem = rem.wrapping_add(altRem); + if (meanRem & 0x8000) != 0 || (meanRem == 0 && ((q & 1) != 0)) { + rem = altRem; + } + let mut signRem = signA; + if 0x8000 <= rem { + signRem = !signRem; + rem = rem.wrapping_neg(); + } + + return softfloat_normRoundPackToF16(signRem, expB as i16, rem, roundingMode, detectTininess); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_f16_rem() { + struct softfloat_f16_rem_TestCase { + a: u16, + b: u16, + result: u16, + flags: u8, + roundingMode: u8, + detectTininess: u8, + } + + let cases = [ + softfloat_f16_rem_TestCase { + a: 0x4500, + b: 0x4000, + result: 0x3C00, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f16_rem_TestCase { + a: 0x3C00, + b: 0x3C00, + result: 0x0000, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f16_rem_TestCase { + a: 0x4300, + b: 0x4000, + result: 0xB800, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f16_rem_TestCase { + a: 0x4700, + b: 0x4200, + result: 0x3C00, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + ]; + + for (i, c) in cases.iter().enumerate() { + let (res, flags) = f16_rem( + 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)); + } + } +} diff --git a/src/softfloat/mod.rs b/src/softfloat/mod.rs index 15566da..a6f4094 100644 --- a/src/softfloat/mod.rs +++ b/src/softfloat/mod.rs @@ -115,6 +115,7 @@ mod f16_le_quiet; mod f16_lt; mod f16_lt_quiet; mod f16_mul; +mod f16_rem; mod f16_sub; mod internals; mod s_addMagsF16; @@ -159,6 +160,7 @@ pub use f16_lt::f16_lt; pub use f16_lt_quiet::f16_lt_quiet; pub use f16_mul::f16_mul; pub use f16_mulAdd::f16_mulAdd; +pub use f16_rem::f16_rem; pub use f16_sub::f16_sub; pub use f32_add::f32_add; pub use f32_classify::f32_classify; diff --git a/src/softfloat/s_normRoundPackToF16.rs b/src/softfloat/s_normRoundPackToF16.rs index 470c81e..6bae028 100644 --- a/src/softfloat/s_normRoundPackToF16.rs +++ b/src/softfloat/s_normRoundPackToF16.rs @@ -1,27 +1,28 @@ use crate::softfloat::{ - float16_t, packToF16, softfloat_countLeadingZeros32, - softfloat_roundPackToF16, + float16_t, packToF16UI, softfloat_countLeadingZeros16, softfloat_roundPackToF16, }; #[must_use] pub const fn softfloat_normRoundPackToF16( sign: bool, exp: i16, - sig: u32, + sig: u16, roundingMode: u8, detectTininess: u8, ) -> (float16_t, u8) { - let shiftDist = softfloat_countLeadingZeros32(sig).wrapping_sub(1) as i8; + let shiftDist = softfloat_countLeadingZeros16(sig).wrapping_sub(1) as i8; let exp = exp.wrapping_sub(shiftDist as i16); - if 4 <= shiftDist && exp < 0x1D { + if (4 <= shiftDist) && ((exp as u32) < 0x1D) { return ( - packToF16( - sign, - if sig != 0 { exp as i8 } else { 0 }, - (sig << shiftDist.wrapping_sub(4)) as u16, - ), + float16_t { + v: packToF16UI( + sign, + if sig != 0 { exp as i8 } else { 0 }, + sig << (shiftDist - 4), + ), + }, 0, ); } - return softfloat_roundPackToF16(sign, exp, (sig << shiftDist) as u16, roundingMode, detectTininess); + return softfloat_roundPackToF16(sign, exp, sig << shiftDist, roundingMode, detectTininess); } From 4b99a528ae974adaa4e600058c5dae3f4dccb8ff Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 15:27:15 -0400 Subject: [PATCH 14/23] F16 roundToInt --- src/softfloat/f16_roundToInt.rs | 156 ++++++++++++++++++++++++++++++++ src/softfloat/mod.rs | 2 + 2 files changed, 158 insertions(+) create mode 100644 src/softfloat/f16_roundToInt.rs diff --git a/src/softfloat/f16_roundToInt.rs b/src/softfloat/f16_roundToInt.rs new file mode 100644 index 0000000..d3fc560 --- /dev/null +++ b/src/softfloat/f16_roundToInt.rs @@ -0,0 +1,156 @@ +use super::{ + expF16UI, float16_t, fracF16UI, packToF16UI, signF16UI, softfloat_flag_inexact, + softfloat_propagateNaNF16UI, softfloat_round_max, softfloat_round_min, softfloat_round_minMag, + softfloat_round_near_even, softfloat_round_near_maxMag, softfloat_round_odd, +}; + +#[must_use] +pub const fn f16_roundToInt(a: float16_t, roundingMode: u8, exact: bool) -> (float16_t, u8) { + let uiA = a.v; + let exp = expF16UI(uiA); + let mut flags: u8 = 0; + if exp <= 0xE { + if (uiA << 1) == 0 { + return (a, flags); + } + if exact { + flags |= softfloat_flag_inexact; + } + let mut uiZ = uiA & packToF16UI(true, 0, 0); + match roundingMode { + softfloat_round_near_even => { + if fracF16UI(uiA) != 0 && exp == 0xE { + uiZ |= packToF16UI(false, 0xF, 0); + } + } + softfloat_round_near_maxMag => { + if exp == 0xE { + uiZ |= packToF16UI(false, 0xF, 0); + } + } + softfloat_round_min => { + if uiZ != 0 { + uiZ = packToF16UI(true, 0xF, 0); + } + } + softfloat_round_max => { + if uiZ == 0 { + uiZ = packToF16UI(false, 0xF, 0); + } + } + softfloat_round_odd => { + uiZ |= packToF16UI(false, 0xF, 0); + } + _ => {} + } + return (float16_t { v: uiZ }, flags); + } + + if 0x19 <= exp { + if (exp == 0x1F) && (fracF16UI(uiA) != 0) { + let (uiZ, new_flags) = softfloat_propagateNaNF16UI(uiA, 0); + return (float16_t { v: uiZ }, flags | new_flags); + } + return (a, flags); + } + + let mut uiZ = uiA; + let lastBitMask = (1 as u16) << (0x19_i8).wrapping_sub(exp); + let roundBitsMask = lastBitMask.wrapping_sub(1); + + if roundingMode == softfloat_round_near_maxMag { + uiZ = uiZ.wrapping_add(lastBitMask >> 1); + } else if roundingMode == softfloat_round_near_even { + uiZ = uiZ.wrapping_add(lastBitMask >> 1); + if (uiZ & roundBitsMask) == 0 { + uiZ &= !lastBitMask; + } + } else if roundingMode + == (if signF16UI(uiZ) { + softfloat_round_min + } else { + softfloat_round_max + }) + { + uiZ = uiZ.wrapping_add(roundBitsMask); + } + + uiZ &= !roundBitsMask; + + if uiZ != uiA { + if roundingMode == softfloat_round_odd { + uiZ |= lastBitMask; + } + if exact { + flags |= softfloat_flag_inexact; + } + } + + return (float16_t { v: uiZ }, flags); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_f16_roundToInt() { + struct softfloat_f16_roundToInt_TestCase { + a: u16, + roundingMode: u8, + exact: bool, + result: u16, + flags: u8, + } + + let cases = [ + softfloat_f16_roundToInt_TestCase { + a: 0x3E00, + roundingMode: softfloat_round_near_even, + exact: true, + result: 0x4000, + flags: softfloat_flag_inexact, + }, + softfloat_f16_roundToInt_TestCase { + a: 0x4100, + roundingMode: softfloat_round_near_even, + exact: true, + result: 0x4000, + flags: softfloat_flag_inexact, + }, + softfloat_f16_roundToInt_TestCase { + a: 0x4300, + roundingMode: softfloat_round_near_even, + exact: true, + result: 0x4400, + flags: softfloat_flag_inexact, + }, + softfloat_f16_roundToInt_TestCase { + a: 0x3C00, + roundingMode: softfloat_round_near_even, + exact: true, + result: 0x3C00, + flags: 0, + }, + softfloat_f16_roundToInt_TestCase { + a: 0x3800, + roundingMode: softfloat_round_near_even, + exact: true, + result: 0x0000, + flags: softfloat_flag_inexact, + }, + softfloat_f16_roundToInt_TestCase { + a: 0x3E00, + roundingMode: softfloat_round_minMag, + exact: true, + result: 0x3C00, + flags: softfloat_flag_inexact, + }, + ]; + + for (i, c) in cases.iter().enumerate() { + let (res, flags) = f16_roundToInt(float16_t { v: c.a }, c.roundingMode, c.exact); + assert_eq!((i, res.v, flags), (i, c.result, c.flags)); + } + } +} diff --git a/src/softfloat/mod.rs b/src/softfloat/mod.rs index a6f4094..13ef806 100644 --- a/src/softfloat/mod.rs +++ b/src/softfloat/mod.rs @@ -23,6 +23,7 @@ mod f16_add; mod f16_classify; mod f16_div; mod f16_mulAdd; +mod f16_roundToInt; mod f32_add; mod f32_classify; mod f32_div; @@ -161,6 +162,7 @@ pub use f16_lt_quiet::f16_lt_quiet; pub use f16_mul::f16_mul; pub use f16_mulAdd::f16_mulAdd; pub use f16_rem::f16_rem; +pub use f16_roundToInt::f16_roundToInt; pub use f16_sub::f16_sub; pub use f32_add::f32_add; pub use f32_classify::f32_classify; From acbc258019ad8f8a21c28728fe84688db1ab9e09 Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 15:41:07 -0400 Subject: [PATCH 15/23] F16 sqrt --- src/softfloat/f16_sqrt.rs | 135 ++++++++++++++++++++++++++++++++++++++ src/softfloat/mod.rs | 2 + 2 files changed, 137 insertions(+) create mode 100644 src/softfloat/f16_sqrt.rs diff --git a/src/softfloat/f16_sqrt.rs b/src/softfloat/f16_sqrt.rs new file mode 100644 index 0000000..a25fae8 --- /dev/null +++ b/src/softfloat/f16_sqrt.rs @@ -0,0 +1,135 @@ +use super::{ + defaultNaNF16UI, expF16UI, float16_t, fracF16UI, signF16UI, softfloat_approxRecipSqrt_1k0s, + softfloat_approxRecipSqrt_1k1s, softfloat_flag_invalid, softfloat_normSubnormalF16Sig, + softfloat_propagateNaNF16UI, softfloat_roundPackToF16, +}; + +#[must_use] +pub const fn f16_sqrt(a: float16_t, roundingMode: u8, detectTininess: u8) -> (float16_t, u8) { + let uiA = a.v; + let signA = signF16UI(uiA); + let mut expA = expF16UI(uiA); + let mut sigA = fracF16UI(uiA); + // ------------------------------------------------------------------------ + if expA == 0x1F { + if sigA != 0 { + let (uiZ, flags) = softfloat_propagateNaNF16UI(uiA, 0); + return (float16_t { v: uiZ }, flags); + } + if !signA { + return (a, 0); + } + return (float16_t { v: defaultNaNF16UI }, softfloat_flag_invalid); + } + // ------------------------------------------------------------------------ + if signA { + if 0 == ((expA as u16) | sigA) { + return (a, 0); + } + return (float16_t { v: defaultNaNF16UI }, softfloat_flag_invalid); + } + // ------------------------------------------------------------------------ + if expA == 0 { + if sigA == 0 { + return (a, 0); + } + let normExpSig = softfloat_normSubnormalF16Sig(sigA); + expA = normExpSig.exp; + sigA = normExpSig.sig; + } + // ------------------------------------------------------------------------ + let expZ = ((expA.wrapping_sub(0xF)) >> 1).wrapping_add(0xE); + expA &= 1; + sigA |= 0x0400; + let index = ((sigA >> 6) & 0xE) + (expA as u16); + let r0 = (softfloat_approxRecipSqrt_1k0s[index as usize] as u16).wrapping_sub( + (((softfloat_approxRecipSqrt_1k1s[index as usize] as u32) + .wrapping_mul((sigA & 0x7F) as u32)) + >> 11) as u16, + ); + let mut ESqrR0 = ((r0 as u32).wrapping_mul(r0 as u32)) >> 1; + if expA != 0 { + ESqrR0 >>= 1; + } + let sigma0 = (!(ESqrR0.wrapping_mul(sigA as u32) >> 16)) as u16; + let mut recipSqrt16 = r0.wrapping_add((((r0 as u32).wrapping_mul(sigma0 as u32)) >> 25) as u16); + if (recipSqrt16 & 0x8000) == 0 { + recipSqrt16 = 0x8000; + } + let mut sigZ = (((sigA as u32) << 5).wrapping_mul(recipSqrt16 as u32) >> 16) as u16; + if expA != 0 { + sigZ >>= 1; + } + // ------------------------------------------------------------------------ + sigZ = sigZ.wrapping_add(1); + if (sigZ & 7) == 0 { + let shiftedSigZ = sigZ >> 1; + let negRem = shiftedSigZ.wrapping_mul(shiftedSigZ); + sigZ &= !1; + if (negRem & 0x8000) != 0 { + sigZ |= 1; + } else if negRem != 0 { + sigZ = sigZ.wrapping_sub(1); + } + } + return softfloat_roundPackToF16(false, expZ as i16, sigZ, roundingMode, detectTininess); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_f16_sqrt() { + struct softfloat_f16_sqrt_TestCase { + a: u16, + result: u16, + flags: u8, + roundingMode: u8, + detectTininess: u8, + } + + let cases = [ + softfloat_f16_sqrt_TestCase { + a: 0x4400, + result: 0x4000, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f16_sqrt_TestCase { + a: 0x3C00, + result: 0x3C00, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f16_sqrt_TestCase { + a: 0x0000, + result: 0x0000, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f16_sqrt_TestCase { + a: 0x4880, + result: 0x4200, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f16_sqrt_TestCase { + a: 0x3400, + result: 0x3800, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + ]; + + for (i, c) in cases.iter().enumerate() { + let (res, flags) = f16_sqrt(float16_t { v: c.a }, c.roundingMode, c.detectTininess); + assert_eq!((i, res.v, flags), (i, c.result, c.flags)); + } + } +} diff --git a/src/softfloat/mod.rs b/src/softfloat/mod.rs index 13ef806..8fb1c97 100644 --- a/src/softfloat/mod.rs +++ b/src/softfloat/mod.rs @@ -24,6 +24,7 @@ mod f16_classify; mod f16_div; mod f16_mulAdd; mod f16_roundToInt; +mod f16_sqrt; mod f32_add; mod f32_classify; mod f32_div; @@ -163,6 +164,7 @@ pub use f16_mul::f16_mul; pub use f16_mulAdd::f16_mulAdd; pub use f16_rem::f16_rem; pub use f16_roundToInt::f16_roundToInt; +pub use f16_sqrt::f16_sqrt; pub use f16_sub::f16_sub; pub use f32_add::f32_add; pub use f32_classify::f32_classify; From 70c61e9544100b8a4695c07d9591e8c489e18892 Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 16:01:55 -0400 Subject: [PATCH 16/23] F16 f16_to_f32/f16_to_f64 --- src/softfloat/f16_to_f32.rs | 96 +++++++++++++++++++++++++++++++++++++ src/softfloat/f16_to_f64.rs | 96 +++++++++++++++++++++++++++++++++++++ src/softfloat/mod.rs | 4 ++ 3 files changed, 196 insertions(+) create mode 100644 src/softfloat/f16_to_f32.rs create mode 100644 src/softfloat/f16_to_f64.rs diff --git a/src/softfloat/f16_to_f32.rs b/src/softfloat/f16_to_f32.rs new file mode 100644 index 0000000..61620bf --- /dev/null +++ b/src/softfloat/f16_to_f32.rs @@ -0,0 +1,96 @@ +use super::{ + expF16UI, float16_t, float32_t, fracF16UI, packToF32, packToF32UI, signF16UI, + softfloat_commonNaNToF32UI, softfloat_f16UIToCommonNaN, softfloat_normSubnormalF16Sig, +}; + +#[must_use] +pub const fn f16_to_f32(a: float16_t) -> (float32_t, u8) { + let uiA = a.v; + let sign = signF16UI(uiA); + let mut exp = expF16UI(uiA); + let mut frac = fracF16UI(uiA); + + if exp == 0x1F { + if frac != 0 { + let (commonNaN, flags) = softfloat_f16UIToCommonNaN(uiA); + return ( + float32_t { + v: softfloat_commonNaNToF32UI(&commonNaN), + }, + flags, + ); + } + return ( + float32_t { + v: packToF32UI(sign, 0xFF, 0), + }, + 0, + ); + } + + if exp == 0 { + if frac == 0 { + return (packToF32(sign, 0, 0), 0); + } + let normExpSig = softfloat_normSubnormalF16Sig(frac); + exp = normExpSig.exp.wrapping_sub(1); + frac = normExpSig.sig; + } + + return ( + packToF32(sign, (exp as i16).wrapping_add(0x70), (frac as u32) << 13), + 0, + ); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_f16_to_f32() { + struct softfloat_f16_to_f32_TestCase { + a: u16, + result: u32, + flags: u8, + } + + let cases = [ + softfloat_f16_to_f32_TestCase { + a: 0x3C00, + result: 0x3F800000, + flags: 0, + }, + softfloat_f16_to_f32_TestCase { + a: 0x0000, + result: 0x00000000, + flags: 0, + }, + softfloat_f16_to_f32_TestCase { + a: 0x8000, + result: 0x80000000, + flags: 0, + }, + softfloat_f16_to_f32_TestCase { + a: 0x4000, + result: 0x40000000, + flags: 0, + }, + softfloat_f16_to_f32_TestCase { + a: 0x3800, + result: 0x3F000000, + flags: 0, + }, + softfloat_f16_to_f32_TestCase { + a: 0xBC00, + result: 0xBF800000, + flags: 0, + }, + ]; + + for (i, c) in cases.iter().enumerate() { + let (res, flags) = f16_to_f32(float16_t { v: c.a }); + assert_eq!((i, res.v, flags), (i, c.result, c.flags)); + } + } +} diff --git a/src/softfloat/f16_to_f64.rs b/src/softfloat/f16_to_f64.rs new file mode 100644 index 0000000..f090b38 --- /dev/null +++ b/src/softfloat/f16_to_f64.rs @@ -0,0 +1,96 @@ +use super::{ + expF16UI, float16_t, float64_t, fracF16UI, packToF64, packToF64UI, signF16UI, + softfloat_commonNaNToF64UI, softfloat_f16UIToCommonNaN, softfloat_normSubnormalF16Sig, +}; + +#[must_use] +pub const fn f16_to_f64(a: float16_t) -> (float64_t, u8) { + let uiA = a.v; + let sign = signF16UI(uiA); + let mut exp = expF16UI(uiA); + let mut frac = fracF16UI(uiA); + + if exp == 0x1F { + if frac != 0 { + let (commonNaN, flags) = softfloat_f16UIToCommonNaN(uiA); + return ( + float64_t { + v: softfloat_commonNaNToF64UI(&commonNaN), + }, + flags, + ); + } + return ( + float64_t { + v: packToF64UI(sign, 0x7FF, 0), + }, + 0, + ); + } + + if exp == 0 { + if frac == 0 { + return (packToF64(sign, 0, 0), 0); + } + let normExpSig = softfloat_normSubnormalF16Sig(frac); + exp = normExpSig.exp.wrapping_sub(1); + frac = normExpSig.sig; + } + + return ( + packToF64(sign, (exp as i16).wrapping_add(0x3F0), (frac as u64) << 42), + 0, + ); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_f16_to_f64() { + struct softfloat_f16_to_f64_TestCase { + a: u16, + result: u64, + flags: u8, + } + + let cases = [ + softfloat_f16_to_f64_TestCase { + a: 0x3C00, + result: 0x3FF0000000000000, + flags: 0, + }, + softfloat_f16_to_f64_TestCase { + a: 0x0000, + result: 0x0000000000000000, + flags: 0, + }, + softfloat_f16_to_f64_TestCase { + a: 0x8000, + result: 0x8000000000000000, + flags: 0, + }, + softfloat_f16_to_f64_TestCase { + a: 0x4000, + result: 0x4000000000000000, + flags: 0, + }, + softfloat_f16_to_f64_TestCase { + a: 0x3800, + result: 0x3FE0000000000000, + flags: 0, + }, + softfloat_f16_to_f64_TestCase { + a: 0xBC00, + result: 0xBFF0000000000000, + flags: 0, + }, + ]; + + for (i, c) in cases.iter().enumerate() { + let (res, flags) = f16_to_f64(float16_t { v: c.a }); + assert_eq!((i, res.v, flags), (i, c.result, c.flags)); + } + } +} diff --git a/src/softfloat/mod.rs b/src/softfloat/mod.rs index 8fb1c97..69732cb 100644 --- a/src/softfloat/mod.rs +++ b/src/softfloat/mod.rs @@ -25,6 +25,8 @@ mod f16_div; mod f16_mulAdd; mod f16_roundToInt; mod f16_sqrt; +mod f16_to_f32; +mod f16_to_f64; mod f32_add; mod f32_classify; mod f32_div; @@ -166,6 +168,8 @@ pub use f16_rem::f16_rem; pub use f16_roundToInt::f16_roundToInt; pub use f16_sqrt::f16_sqrt; pub use f16_sub::f16_sub; +pub use f16_to_f32::f16_to_f32; +pub use f16_to_f64::f16_to_f64; pub use f32_add::f32_add; pub use f32_classify::f32_classify; pub use f32_div::f32_div; From 1d60294e3f5588163a1d440f55f7d71d31ec7b20 Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 16:12:26 -0400 Subject: [PATCH 17/23] F16 f16_to_i32/f16_to_i64 --- src/softfloat/f16_to_i32.rs | 107 +++++++++++++++++++++++++++++++++++ src/softfloat/f16_to_i64.rs | 108 ++++++++++++++++++++++++++++++++++++ src/softfloat/mod.rs | 4 ++ 3 files changed, 219 insertions(+) create mode 100644 src/softfloat/f16_to_i32.rs create mode 100644 src/softfloat/f16_to_i64.rs diff --git a/src/softfloat/f16_to_i32.rs b/src/softfloat/f16_to_i32.rs new file mode 100644 index 0000000..04ce53b --- /dev/null +++ b/src/softfloat/f16_to_i32.rs @@ -0,0 +1,107 @@ +use super::{ + expF16UI, float16_t, fracF16UI, i32_fromNaN, i32_fromNegOverflow, i32_fromPosOverflow, + signF16UI, softfloat_flag_invalid, softfloat_roundToI32, +}; + +#[must_use] +pub const fn f16_to_i32(a: float16_t, roundingMode: u8, exact: bool) -> (i32, u8) { + let uiA = a.v; + let sign = signF16UI(uiA); + let exp = expF16UI(uiA); + let frac = fracF16UI(uiA); + + if exp == 0x1F { + return ( + if frac != 0 { + i32_fromNaN + } else if sign { + i32_fromNegOverflow + } else { + i32_fromPosOverflow + }, + softfloat_flag_invalid, + ); + } + + let mut sig32 = frac as i32; + if exp != 0 { + sig32 |= 0x0400; + let shiftDist = exp.wrapping_sub(0x19); + if 0 <= shiftDist { + sig32 <<= shiftDist; + return (if sign { -sig32 } else { sig32 }, 0); + } + let shiftDist = exp.wrapping_sub(0x0D); + if 0 < shiftDist { + sig32 <<= shiftDist; + } + } + + return softfloat_roundToI32(sign, sig32 as u64, roundingMode, exact); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_f16_to_i32() { + struct softfloat_f16_to_i32_TestCase { + a: u16, + roundingMode: u8, + exact: bool, + result: i32, + flags: u8, + } + + let cases = [ + softfloat_f16_to_i32_TestCase { + a: 0x3C00, + roundingMode: 0, + exact: false, + result: 1, + flags: 0, + }, + softfloat_f16_to_i32_TestCase { + a: 0x0000, + roundingMode: 0, + exact: false, + result: 0, + flags: 0, + }, + softfloat_f16_to_i32_TestCase { + a: 0xBC00, + roundingMode: 0, + exact: false, + result: -1, + flags: 0, + }, + softfloat_f16_to_i32_TestCase { + a: 0x4000, + roundingMode: 0, + exact: false, + result: 2, + flags: 0, + }, + softfloat_f16_to_i32_TestCase { + a: 0x5640, + roundingMode: 0, + exact: false, + result: 100, + flags: 0, + }, + softfloat_f16_to_i32_TestCase { + a: 0xD640, + roundingMode: 0, + exact: false, + result: -100, + flags: 0, + }, + ]; + + for (i, c) in cases.iter().enumerate() { + let (res, flags) = f16_to_i32(float16_t { v: c.a }, c.roundingMode, c.exact); + assert_eq!((i, res, flags), (i, c.result, c.flags)); + } + } +} diff --git a/src/softfloat/f16_to_i64.rs b/src/softfloat/f16_to_i64.rs new file mode 100644 index 0000000..bfb6bc0 --- /dev/null +++ b/src/softfloat/f16_to_i64.rs @@ -0,0 +1,108 @@ +use super::{ + expF16UI, float16_t, fracF16UI, i64_fromNaN, i64_fromNegOverflow, i64_fromPosOverflow, + signF16UI, softfloat_flag_invalid, softfloat_roundToI32, +}; + +#[must_use] +pub const fn f16_to_i64(a: float16_t, roundingMode: u8, exact: bool) -> (i64, u8) { + let uiA = a.v; + let sign = signF16UI(uiA); + let exp = expF16UI(uiA); + let frac = fracF16UI(uiA); + + if exp == 0x1F { + return ( + if frac != 0 { + i64_fromNaN + } else if sign { + i64_fromNegOverflow + } else { + i64_fromPosOverflow + }, + softfloat_flag_invalid, + ); + } + + let mut sig32 = frac as i32; + if exp != 0 { + sig32 |= 0x0400; + let shiftDist = exp.wrapping_sub(0x19); + if 0 <= shiftDist { + sig32 <<= shiftDist; + return (if sign { -(sig32 as i64) } else { sig32 as i64 }, 0); + } + let shiftDist = exp.wrapping_sub(0x0D); + if 0 < shiftDist { + sig32 <<= shiftDist; + } + } + + let (res, flags) = softfloat_roundToI32(sign, sig32 as u64, roundingMode, exact); + return (res as i64, flags); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_f16_to_i64() { + struct softfloat_f16_to_i64_TestCase { + a: u16, + roundingMode: u8, + exact: bool, + result: i64, + flags: u8, + } + + let cases = [ + softfloat_f16_to_i64_TestCase { + a: 0x3C00, + roundingMode: 0, + exact: false, + result: 1, + flags: 0, + }, + softfloat_f16_to_i64_TestCase { + a: 0x0000, + roundingMode: 0, + exact: false, + result: 0, + flags: 0, + }, + softfloat_f16_to_i64_TestCase { + a: 0xBC00, + roundingMode: 0, + exact: false, + result: -1, + flags: 0, + }, + softfloat_f16_to_i64_TestCase { + a: 0x4000, + roundingMode: 0, + exact: false, + result: 2, + flags: 0, + }, + softfloat_f16_to_i64_TestCase { + a: 0x5640, + roundingMode: 0, + exact: false, + result: 100, + flags: 0, + }, + softfloat_f16_to_i64_TestCase { + a: 0xD640, + roundingMode: 0, + exact: false, + result: -100, + flags: 0, + }, + ]; + + for (i, c) in cases.iter().enumerate() { + let (res, flags) = f16_to_i64(float16_t { v: c.a }, c.roundingMode, c.exact); + assert_eq!((i, res, flags), (i, c.result, c.flags)); + } + } +} diff --git a/src/softfloat/mod.rs b/src/softfloat/mod.rs index 69732cb..f60aa76 100644 --- a/src/softfloat/mod.rs +++ b/src/softfloat/mod.rs @@ -27,6 +27,8 @@ mod f16_roundToInt; mod f16_sqrt; mod f16_to_f32; mod f16_to_f64; +mod f16_to_i32; +mod f16_to_i64; mod f32_add; mod f32_classify; mod f32_div; @@ -170,6 +172,8 @@ pub use f16_sqrt::f16_sqrt; pub use f16_sub::f16_sub; pub use f16_to_f32::f16_to_f32; pub use f16_to_f64::f16_to_f64; +pub use f16_to_i32::f16_to_i32; +pub use f16_to_i64::f16_to_i64; pub use f32_add::f32_add; pub use f32_classify::f32_classify; pub use f32_div::f32_div; From 7d072f30b2e4192dae2eec3ecd772fd8098048fb Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 16:21:57 -0400 Subject: [PATCH 18/23] F16 f16_to_ui32/f16_to_ui64 --- src/softfloat/f16_to_ui32.rs | 99 ++++++++++++++++++++++++++++++++ src/softfloat/f16_to_ui64.rs | 107 +++++++++++++++++++++++++++++++++++ src/softfloat/mod.rs | 4 ++ 3 files changed, 210 insertions(+) create mode 100644 src/softfloat/f16_to_ui32.rs create mode 100644 src/softfloat/f16_to_ui64.rs diff --git a/src/softfloat/f16_to_ui32.rs b/src/softfloat/f16_to_ui32.rs new file mode 100644 index 0000000..46b5d95 --- /dev/null +++ b/src/softfloat/f16_to_ui32.rs @@ -0,0 +1,99 @@ +use super::{ + expF16UI, float16_t, fracF16UI, signF16UI, softfloat_flag_invalid, softfloat_roundToUI32, + ui32_fromNaN, ui32_fromNegOverflow, ui32_fromPosOverflow, +}; + +#[must_use] +pub const fn f16_to_ui32(a: float16_t, roundingMode: u8, exact: bool) -> (u32, u8) { + let uiA = a.v; + let sign = signF16UI(uiA); + let exp = expF16UI(uiA); + let frac = fracF16UI(uiA); + + if exp == 0x1F { + return ( + if frac != 0 { + ui32_fromNaN + } else if sign { + ui32_fromNegOverflow + } else { + ui32_fromPosOverflow + }, + softfloat_flag_invalid, + ); + } + + let mut sig32 = frac as u32; + if exp != 0 { + sig32 |= 0x0400; + let shiftDist = exp.wrapping_sub(0x19); + if (0 <= shiftDist) && !sign { + return (sig32.wrapping_shl(shiftDist as u32), 0); + } + let shiftDist = exp.wrapping_sub(0x0D); + if 0 < shiftDist { + sig32 = sig32.wrapping_shl(shiftDist as u32); + } + } + + return softfloat_roundToUI32(sign, sig32 as u64, roundingMode, exact); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_f16_to_ui32() { + struct softfloat_f16_to_ui32_TestCase { + a: u16, + roundingMode: u8, + exact: bool, + result: u32, + flags: u8, + } + + let cases = [ + softfloat_f16_to_ui32_TestCase { + a: 0x3C00, + roundingMode: 0, + exact: false, + result: 1, + flags: 0, + }, + softfloat_f16_to_ui32_TestCase { + a: 0x0000, + roundingMode: 0, + exact: false, + result: 0, + flags: 0, + }, + softfloat_f16_to_ui32_TestCase { + a: 0x4000, + roundingMode: 0, + exact: false, + result: 2, + flags: 0, + }, + softfloat_f16_to_ui32_TestCase { + a: 0x5640, + roundingMode: 0, + exact: false, + result: 100, + flags: 0, + }, + softfloat_f16_to_ui32_TestCase { + a: 0x7800, + roundingMode: 0, + exact: false, + result: 32768, + flags: 0, + }, + ]; + + for (i, c) in cases.iter().enumerate() { + let (res, flags) = f16_to_ui32(float16_t { v: c.a }, c.roundingMode, c.exact); + assert_eq!((i, res, flags), (i, c.result, c.flags)); + } + } +} diff --git a/src/softfloat/f16_to_ui64.rs b/src/softfloat/f16_to_ui64.rs new file mode 100644 index 0000000..8c109a6 --- /dev/null +++ b/src/softfloat/f16_to_ui64.rs @@ -0,0 +1,107 @@ +use crate::softfloat::softfloat_roundToUI64; + +use super::{ + expF16UI, float16_t, fracF16UI, signF16UI, softfloat_flag_invalid, softfloat_roundToUI32, + ui64_fromNaN, ui64_fromNegOverflow, ui64_fromPosOverflow, +}; + +#[must_use] +pub const fn f16_to_ui64(a: float16_t, roundingMode: u8, exact: bool) -> (u64, u8) { + let uiA = a.v; + let sign = signF16UI(uiA); + let exp = expF16UI(uiA); + let frac = fracF16UI(uiA); + + if exp == 0x1F { + return ( + if frac != 0 { + ui64_fromNaN + } else if sign { + ui64_fromNegOverflow + } else { + ui64_fromPosOverflow + }, + softfloat_flag_invalid, + ); + } + + let mut sig32 = frac as u32; + if exp != 0 { + sig32 |= 0x0400; + let shiftDist = exp.wrapping_sub(0x19); + if (0 <= shiftDist) && !sign { + return ((sig32.wrapping_shl(shiftDist as u32)) as u64, 0); + } + let shiftDist = exp.wrapping_sub(0x0D); + if 0 < shiftDist { + sig32 = sig32.wrapping_shl(shiftDist as u32); + } + } + + return softfloat_roundToUI64( + sign, + (sig32.wrapping_shr(12)) as u64, + (sig32.wrapping_shr(52)) as u64, + roundingMode, + exact, + ); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_f16_to_ui64() { + struct softfloat_f16_to_ui64_TestCase { + a: u16, + roundingMode: u8, + exact: bool, + result: u64, + flags: u8, + } + + let cases = [ + softfloat_f16_to_ui64_TestCase { + a: 0x3C00, + roundingMode: 0, + exact: false, + result: 1, + flags: 0, + }, + softfloat_f16_to_ui64_TestCase { + a: 0x0000, + roundingMode: 0, + exact: false, + result: 0, + flags: 0, + }, + softfloat_f16_to_ui64_TestCase { + a: 0x4000, + roundingMode: 0, + exact: false, + result: 2, + flags: 0, + }, + softfloat_f16_to_ui64_TestCase { + a: 0x5640, + roundingMode: 0, + exact: false, + result: 100, + flags: 0, + }, + softfloat_f16_to_ui64_TestCase { + a: 0x7800, + roundingMode: 0, + exact: false, + result: 32768, + flags: 0, + }, + ]; + + for (i, c) in cases.iter().enumerate() { + let (res, flags) = f16_to_ui64(float16_t { v: c.a }, c.roundingMode, c.exact); + assert_eq!((i, res, flags), (i, c.result, c.flags)); + } + } +} diff --git a/src/softfloat/mod.rs b/src/softfloat/mod.rs index f60aa76..b4ccd4f 100644 --- a/src/softfloat/mod.rs +++ b/src/softfloat/mod.rs @@ -29,6 +29,8 @@ mod f16_to_f32; mod f16_to_f64; mod f16_to_i32; mod f16_to_i64; +mod f16_to_ui32; +mod f16_to_ui64; mod f32_add; mod f32_classify; mod f32_div; @@ -174,6 +176,8 @@ pub use f16_to_f32::f16_to_f32; pub use f16_to_f64::f16_to_f64; pub use f16_to_i32::f16_to_i32; pub use f16_to_i64::f16_to_i64; +pub use f16_to_ui32::f16_to_ui32; +pub use f16_to_ui64::f16_to_ui64; pub use f32_add::f32_add; pub use f32_classify::f32_classify; pub use f32_div::f32_div; From 46252d17434a2e32c9397620a9e6a22c7f5607cf Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 16:37:56 -0400 Subject: [PATCH 19/23] F16 f32_to_f16/f64_to_f16 --- src/softfloat/f32_to_f16.rs | 109 +++++++++++++++++++++++++++++++++++ src/softfloat/f64_to_f16.rs | 110 ++++++++++++++++++++++++++++++++++++ src/softfloat/mod.rs | 4 ++ 3 files changed, 223 insertions(+) create mode 100644 src/softfloat/f32_to_f16.rs create mode 100644 src/softfloat/f64_to_f16.rs diff --git a/src/softfloat/f32_to_f16.rs b/src/softfloat/f32_to_f16.rs new file mode 100644 index 0000000..5964613 --- /dev/null +++ b/src/softfloat/f32_to_f16.rs @@ -0,0 +1,109 @@ +use super::{ + expF32UI, float16_t, float32_t, fracF32UI, packToF16, packToF16UI, signF32UI, + softfloat_commonNaNToF16UI, softfloat_f32UIToCommonNaN, softfloat_roundPackToF16, +}; + +#[must_use] +pub const fn f32_to_f16(a: float32_t, roundingMode: u8, detectTininess: u8) -> (float16_t, u8) { + let uiA = a.v; + let sign = signF32UI(uiA); + let exp = expF32UI(uiA); + let frac = fracF32UI(uiA); + + if exp == 0xFF { + if frac != 0 { + let (commonNaN, flags) = softfloat_f32UIToCommonNaN(uiA); + return ( + float16_t { + v: softfloat_commonNaNToF16UI(commonNaN), + }, + flags, + ); + } + return ( + float16_t { + v: packToF16UI(sign, 0x1F, 0), + }, + 0, + ); + } + + let frac16 = (frac >> 9) | ((frac & 0x1FF) != 0) as u32; + if ((exp as u32) | frac16) == 0 { + return (packToF16(sign, 0, 0), 0); + } + + return softfloat_roundPackToF16( + sign, + (exp as i16).wrapping_sub(0x71), + (frac16 | 0x4000) as u16, + roundingMode, + detectTininess, + ); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_f32_to_f16() { + struct softfloat_f32_to_f16_TestCase { + a: u32, + result: u16, + flags: u8, + roundingMode: u8, + detectTininess: u8, + } + + let cases = [ + softfloat_f32_to_f16_TestCase { + a: 0x3F800000, + result: 0x3C00, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f32_to_f16_TestCase { + a: 0x00000000, + result: 0x0000, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f32_to_f16_TestCase { + a: 0x80000000, + result: 0x8000, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f32_to_f16_TestCase { + a: 0x40000000, + result: 0x4000, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f32_to_f16_TestCase { + a: 0x3F000000, + result: 0x3800, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f32_to_f16_TestCase { + a: 0xBF800000, + result: 0xBC00, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + ]; + + for (i, c) in cases.iter().enumerate() { + let (res, flags) = f32_to_f16(float32_t { v: c.a }, c.roundingMode, c.detectTininess); + assert_eq!((i, res.v, flags), (i, c.result, c.flags)); + } + } +} diff --git a/src/softfloat/f64_to_f16.rs b/src/softfloat/f64_to_f16.rs new file mode 100644 index 0000000..852513b --- /dev/null +++ b/src/softfloat/f64_to_f16.rs @@ -0,0 +1,110 @@ +use super::{ + expF64UI, float16_t, float64_t, fracF64UI, packToF16, packToF16UI, signF64UI, + softfloat_commonNaNToF16UI, softfloat_f64UIToCommonNaN, softfloat_roundPackToF16, + softfloat_shortShiftRightJam64, +}; + +#[must_use] +pub const fn f64_to_f16(a: float64_t, roundingMode: u8, detectTininess: u8) -> (float16_t, u8) { + let uiA = a.v; + let sign = signF64UI(uiA); + let exp = expF64UI(uiA); + let frac = fracF64UI(uiA); + + if exp == 0x7FF { + if frac != 0 { + let (commonNaN, flags) = softfloat_f64UIToCommonNaN(uiA); + return ( + float16_t { + v: softfloat_commonNaNToF16UI(commonNaN), + }, + flags, + ); + } + return ( + float16_t { + v: packToF16UI(sign, 0x1F, 0), + }, + 0, + ); + } + + let frac16 = softfloat_shortShiftRightJam64(frac, 38) as u16; + if ((exp as u16) | frac16) == 0 { + return (packToF16(sign, 0, 0), 0); + } + + return softfloat_roundPackToF16( + sign, + exp.wrapping_sub(0x3F1), + frac16 | 0x4000, + roundingMode, + detectTininess, + ); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_f64_to_f16() { + struct softfloat_f64_to_f16_TestCase { + a: u64, + result: u16, + flags: u8, + roundingMode: u8, + detectTininess: u8, + } + + let cases = [ + softfloat_f64_to_f16_TestCase { + a: 0x3FF0000000000000, + result: 0x3C00, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f64_to_f16_TestCase { + a: 0x0000000000000000, + result: 0x0000, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f64_to_f16_TestCase { + a: 0x8000000000000000, + result: 0x8000, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f64_to_f16_TestCase { + a: 0x4000000000000000, + result: 0x4000, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f64_to_f16_TestCase { + a: 0x3FE0000000000000, + result: 0x3800, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_f64_to_f16_TestCase { + a: 0xBFF0000000000000, + result: 0xBC00, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + ]; + + for (i, c) in cases.iter().enumerate() { + let (res, flags) = f64_to_f16(float64_t { v: c.a }, c.roundingMode, c.detectTininess); + assert_eq!((i, res.v, flags), (i, c.result, c.flags)); + } + } +} diff --git a/src/softfloat/mod.rs b/src/softfloat/mod.rs index b4ccd4f..f36a334 100644 --- a/src/softfloat/mod.rs +++ b/src/softfloat/mod.rs @@ -47,6 +47,7 @@ mod f32_rem; mod f32_roundToInt; mod f32_sqrt; mod f32_sub; +mod f32_to_f16; mod f32_to_f64; mod f32_to_i32; mod f32_to_i64; @@ -68,6 +69,7 @@ mod f64_rem; mod f64_roundToInt; mod f64_sqrt; mod f64_sub; +mod f64_to_f16; mod f64_to_f32; mod f64_to_i32; mod f64_to_i64; @@ -194,6 +196,7 @@ pub use f32_rem::f32_rem; pub use f32_roundToInt::f32_roundToInt; pub use f32_sqrt::f32_sqrt; pub use f32_sub::f32_sub; +pub use f32_to_f16::f32_to_f16; pub use f32_to_f64::f32_to_f64; pub use f32_to_i32::f32_to_i32; pub use f32_to_i64::f32_to_i64; @@ -215,6 +218,7 @@ pub use f64_rem::f64_rem; pub use f64_roundToInt::f64_roundToInt; pub use f64_sqrt::f64_sqrt; pub use f64_sub::f64_sub; +pub use f64_to_f16::f64_to_f16; pub use f64_to_f32::f64_to_f32; pub use f64_to_i32::f64_to_i32; pub use f64_to_i64::f64_to_i64; From 078cbae97bf2d9f9181d83bf139bf943f9658f2d Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 16:50:55 -0400 Subject: [PATCH 20/23] F16 i32_to_f16/i64_to_f16 --- src/softfloat/i32_to_f16.rs | 118 +++++++++++++++++++++++++++++++ src/softfloat/i64_to_f16.rs | 135 ++++++++++++++++++++++++++++++++++++ src/softfloat/mod.rs | 4 ++ 3 files changed, 257 insertions(+) create mode 100644 src/softfloat/i32_to_f16.rs create mode 100644 src/softfloat/i64_to_f16.rs diff --git a/src/softfloat/i32_to_f16.rs b/src/softfloat/i32_to_f16.rs new file mode 100644 index 0000000..1e0325b --- /dev/null +++ b/src/softfloat/i32_to_f16.rs @@ -0,0 +1,118 @@ +use super::{float16_t, packToF16UI, softfloat_countLeadingZeros32, softfloat_roundPackToF16}; + +#[must_use] +pub const fn i32_to_f16(a: i32, roundingMode: u8, detectTininess: u8) -> (float16_t, u8) { + let sign = a < 0; + let absA = if sign { + (a as u32).wrapping_neg() + } else { + a as u32 + }; + + let mut shiftDist = (softfloat_countLeadingZeros32(absA) as i8).wrapping_sub(21); + if shiftDist >= 0 { + let uiZ = if a != 0 { + packToF16UI( + sign, + (0x18i8).wrapping_sub(shiftDist), + (absA << shiftDist) as u16, + ) + } else { + 0 + }; + return (float16_t { v: uiZ }, 0); + } + shiftDist = shiftDist.wrapping_add(4); + let sig = if shiftDist < 0 { + (absA >> -shiftDist) as u16 | ((absA << (shiftDist & 31)) != 0) as u16 + } else { + (absA << shiftDist) as u16 + }; + return softfloat_roundPackToF16( + sign, + (0x1Ci8).wrapping_sub(shiftDist) as i16, + sig, + roundingMode, + detectTininess, + ); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_i32_to_f16() { + struct softfloat_i32_to_f16_TestCase { + a: i32, + result: u16, + flags: u8, + roundingMode: u8, + detectTininess: u8, + } + + let cases = [ + softfloat_i32_to_f16_TestCase { + a: 0, + result: 0x0000, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_i32_to_f16_TestCase { + a: 1, + result: 0x3C00, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_i32_to_f16_TestCase { + a: -1, + result: 0xBC00, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_i32_to_f16_TestCase { + a: 2, + result: 0x4000, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_i32_to_f16_TestCase { + a: 100, + result: 0x5640, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_i32_to_f16_TestCase { + a: -100, + result: 0xD640, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_i32_to_f16_TestCase { + a: 32768, + result: 0x7800, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_i32_to_f16_TestCase { + a: -32768, + result: 0xF800, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + ]; + + for (i, c) in cases.iter().enumerate() { + let (res, flags) = i32_to_f16(c.a, c.roundingMode, c.detectTininess); + assert_eq!((i, res.v, flags), (i, c.result, c.flags)); + } + } +} diff --git a/src/softfloat/i64_to_f16.rs b/src/softfloat/i64_to_f16.rs new file mode 100644 index 0000000..3bcdb9d --- /dev/null +++ b/src/softfloat/i64_to_f16.rs @@ -0,0 +1,135 @@ +use super::{ + float16_t, packToF16UI, softfloat_countLeadingZeros64, softfloat_roundPackToF16, + softfloat_shortShiftRightJam64, +}; + +#[must_use] +pub const fn i64_to_f16(a: i64, roundingMode: u8, detectTininess: u8) -> (float16_t, u8) { + let sign = a < 0; + let absA = if sign { + (a as u64).wrapping_neg() + } else { + a as u64 + }; + + let mut shiftDist = (softfloat_countLeadingZeros64(absA) as i8).wrapping_sub(53); + if shiftDist >= 0 { + let uiZ = if a != 0 { + packToF16UI( + sign, + (0x18i8).wrapping_sub(shiftDist), + (absA << shiftDist) as u16, + ) + } else { + 0 + }; + return (float16_t { v: uiZ }, 0); + } + shiftDist = shiftDist.wrapping_add(4); + let sig = if shiftDist < 0 { + softfloat_shortShiftRightJam64(absA, (-shiftDist) as u8) as u16 + } else { + (absA << shiftDist) as u16 + }; + return softfloat_roundPackToF16( + sign, + (0x1Ci8).wrapping_sub(shiftDist) as i16, + sig, + roundingMode, + detectTininess, + ); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_i64_to_f16() { + struct softfloat_i64_to_f16_TestCase { + a: i64, + result: u16, + flags: u8, + roundingMode: u8, + detectTininess: u8, + } + + let cases = [ + softfloat_i64_to_f16_TestCase { + a: 0, + result: 0x0000, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_i64_to_f16_TestCase { + a: 1, + result: 0x3C00, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_i64_to_f16_TestCase { + a: -1, + result: 0xBC00, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_i64_to_f16_TestCase { + a: 2, + result: 0x4000, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_i64_to_f16_TestCase { + a: 100, + result: 0x5640, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_i64_to_f16_TestCase { + a: -100, + result: 0xD640, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_i64_to_f16_TestCase { + a: 32768, + result: 0x7800, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_i64_to_f16_TestCase { + a: -32768, + result: 0xF800, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_i64_to_f16_TestCase { + a: 0x7FFFFFFFFFFFFFFF, + result: 0x7C00, + flags: 5, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_i64_to_f16_TestCase { + a: -0x8000000000000000i64, + result: 0xFC00, + flags: 5, + roundingMode: 0, + detectTininess: 1, + }, + ]; + + for (i, c) in cases.iter().enumerate() { + let (res, flags) = i64_to_f16(c.a, c.roundingMode, c.detectTininess); + assert_eq!((i, res.v, flags), (i, c.result, c.flags)); + } + } +} diff --git a/src/softfloat/mod.rs b/src/softfloat/mod.rs index f36a334..7fcbd3a 100644 --- a/src/softfloat/mod.rs +++ b/src/softfloat/mod.rs @@ -75,8 +75,10 @@ mod f64_to_i32; mod f64_to_i64; mod f64_to_ui32; mod f64_to_ui64; +mod i32_to_f16; mod i32_to_f32; mod i32_to_f64; +mod i64_to_f16; mod i64_to_f32; mod i64_to_f64; mod s_add128; @@ -224,8 +226,10 @@ pub use f64_to_i32::f64_to_i32; pub use f64_to_i64::f64_to_i64; pub use f64_to_ui32::f64_to_ui32; pub use f64_to_ui64::f64_to_ui64; +pub use i32_to_f16::i32_to_f16; pub use i32_to_f32::i32_to_f32; pub use i32_to_f64::i32_to_f64; +pub use i64_to_f16::i64_to_f16; pub use i64_to_f32::i64_to_f32; pub use i64_to_f64::i64_to_f64; pub use s_addMagsF16::softfloat_addMagsF16; From 989789c520a5e2f51e2196cbdb9d3bd869830e68 Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 17:03:01 -0400 Subject: [PATCH 21/23] F16 ui32_to_f16/ui64_to_f16 --- src/softfloat/mod.rs | 4 ++ src/softfloat/ui32_to_f16.rs | 92 ++++++++++++++++++++++++++++++++++ src/softfloat/ui64_to_f16.rs | 95 ++++++++++++++++++++++++++++++++++++ 3 files changed, 191 insertions(+) create mode 100644 src/softfloat/ui32_to_f16.rs create mode 100644 src/softfloat/ui64_to_f16.rs diff --git a/src/softfloat/mod.rs b/src/softfloat/mod.rs index 7fcbd3a..b137b90 100644 --- a/src/softfloat/mod.rs +++ b/src/softfloat/mod.rs @@ -114,8 +114,10 @@ mod s_shortShiftRightJam64; mod s_sub128; mod s_subMagsF32; mod s_subMagsF64; +mod ui32_to_f16; mod ui32_to_f32; mod ui32_to_f64; +mod ui64_to_f16; mod ui64_to_f32; mod ui64_to_f64; @@ -274,7 +276,9 @@ pub use s_sub128::softfloat_sub128; pub use s_subMagsF16::softfloat_subMagsF16; pub use s_subMagsF32::softfloat_subMagsF32; pub use s_subMagsF64::softfloat_subMagsF64; +pub use ui32_to_f16::ui32_to_f16; pub use ui32_to_f32::ui32_to_f32; pub use ui32_to_f64::ui32_to_f64; +pub use ui64_to_f16::ui64_to_f16; pub use ui64_to_f32::ui64_to_f32; pub use ui64_to_f64::ui64_to_f64; diff --git a/src/softfloat/ui32_to_f16.rs b/src/softfloat/ui32_to_f16.rs new file mode 100644 index 0000000..92e813b --- /dev/null +++ b/src/softfloat/ui32_to_f16.rs @@ -0,0 +1,92 @@ +use super::{float16_t, packToF16UI, softfloat_countLeadingZeros32, softfloat_roundPackToF16}; + +#[must_use] +pub const fn ui32_to_f16(a: u32, roundingMode: u8, detectTininess: u8) -> (float16_t, u8) { + let mut shiftDist = (softfloat_countLeadingZeros32(a) as i8).wrapping_sub(21); + if shiftDist >= 0 { + let uiZ = if a != 0 { + packToF16UI( + false, + (0x18i8).wrapping_sub(shiftDist), + (a << shiftDist) as u16, + ) + } else { + 0 + }; + return (float16_t { v: uiZ }, 0); + } + + shiftDist = shiftDist.wrapping_add(4); + let sig = if shiftDist < 0 { + (a >> -shiftDist) as u16 | ((a << (shiftDist & 31)) != 0) as u16 + } else { + (a << shiftDist) as u16 + }; + + return softfloat_roundPackToF16( + false, + (0x1Ci8).wrapping_sub(shiftDist) as i16, + sig, + roundingMode, + detectTininess, + ); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_ui32_to_f16() { + struct softfloat_ui32_to_f16_TestCase { + a: u32, + result: u16, + flags: u8, + roundingMode: u8, + detectTininess: u8, + } + + let cases = [ + softfloat_ui32_to_f16_TestCase { + a: 0, + result: 0x0000, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_ui32_to_f16_TestCase { + a: 1, + result: 0x3C00, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_ui32_to_f16_TestCase { + a: 2, + result: 0x4000, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_ui32_to_f16_TestCase { + a: 100, + result: 0x5640, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_ui32_to_f16_TestCase { + a: 32768, + result: 0x7800, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + ]; + + for (i, c) in cases.iter().enumerate() { + let (res, flags) = ui32_to_f16(c.a, c.roundingMode, c.detectTininess); + assert_eq!((i, res.v, flags), (i, c.result, c.flags)); + } + } +} diff --git a/src/softfloat/ui64_to_f16.rs b/src/softfloat/ui64_to_f16.rs new file mode 100644 index 0000000..9fcf4e0 --- /dev/null +++ b/src/softfloat/ui64_to_f16.rs @@ -0,0 +1,95 @@ +use super::{ + float16_t, packToF16UI, softfloat_countLeadingZeros64, softfloat_roundPackToF16, + softfloat_shortShiftRightJam64, +}; + +#[must_use] +pub const fn ui64_to_f16(a: u64, roundingMode: u8, detectTininess: u8) -> (float16_t, u8) { + let mut shiftDist = (softfloat_countLeadingZeros64(a) as i8).wrapping_sub(53); + if shiftDist >= 0 { + let uiZ = if a != 0 { + packToF16UI( + false, + (0x18i8).wrapping_sub(shiftDist), + (a << shiftDist) as u16, + ) + } else { + 0 + }; + return (float16_t { v: uiZ }, 0); + } + + shiftDist = shiftDist.wrapping_add(4); + let sig = if shiftDist < 0 { + softfloat_shortShiftRightJam64(a, (-shiftDist) as u8) as u16 + } else { + (a << shiftDist) as u16 + }; + + return softfloat_roundPackToF16( + false, + (0x1Ci8).wrapping_sub(shiftDist) as i16, + sig, + roundingMode, + detectTininess, + ); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_ui64_to_f16() { + struct softfloat_ui64_to_f16_TestCase { + a: u64, + result: u16, + flags: u8, + roundingMode: u8, + detectTininess: u8, + } + + let cases = [ + softfloat_ui64_to_f16_TestCase { + a: 0, + result: 0x0000, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_ui64_to_f16_TestCase { + a: 1, + result: 0x3C00, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_ui64_to_f16_TestCase { + a: 2, + result: 0x4000, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_ui64_to_f16_TestCase { + a: 100, + result: 0x5640, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + softfloat_ui64_to_f16_TestCase { + a: 32768, + result: 0x7800, + flags: 0, + roundingMode: 0, + detectTininess: 1, + }, + ]; + + for (i, c) in cases.iter().enumerate() { + let (res, flags) = ui64_to_f16(c.a, c.roundingMode, c.detectTininess); + assert_eq!((i, res.v, flags), (i, c.result, c.flags)); + } + } +} From e8d3eafc616b7cd94381d0b45f01ae48880d5418 Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 17:04:03 -0400 Subject: [PATCH 22/23] format --- src/softfloat/f16_sub.rs | 2 +- src/softfloat/s_addMagsF16.rs | 24 +++------------------ src/softfloat/s_subMagsF16.rs | 39 +++++++---------------------------- 3 files changed, 12 insertions(+), 53 deletions(-) diff --git a/src/softfloat/f16_sub.rs b/src/softfloat/f16_sub.rs index e8d23d2..829f612 100644 --- a/src/softfloat/f16_sub.rs +++ b/src/softfloat/f16_sub.rs @@ -12,4 +12,4 @@ pub const fn f16_sub( } else { softfloat_subMagsF16(a.v, b.v, roundingMode, detectTininess) } -} \ No newline at end of file +} diff --git a/src/softfloat/s_addMagsF16.rs b/src/softfloat/s_addMagsF16.rs index 97612dd..65c1d46 100644 --- a/src/softfloat/s_addMagsF16.rs +++ b/src/softfloat/s_addMagsF16.rs @@ -137,34 +137,16 @@ pub const fn softfloat_addMagsF16( let sigZ = sigZ >> 4; return (packToF16(signZ, expZ, sigZ), 0); } - return softfloat_roundPackToF16( - signZ, - expZ as i16, - sigZ, - roundingMode, - detectTininess, - ); + return softfloat_roundPackToF16(signZ, expZ as i16, sigZ, roundingMode, detectTininess); } let sigZ = (sig32Z >> 16) as u16; if (sig32Z & 0xFFFF) != 0 { let sigZ = sigZ | 1; - return softfloat_roundPackToF16( - signZ, - expZ as i16, - sigZ, - roundingMode, - detectTininess, - ); + return softfloat_roundPackToF16(signZ, expZ as i16, sigZ, roundingMode, detectTininess); } if (sigZ & 0xF) == 0 && (expZ < 0x1E) { let sigZ = sigZ >> 4; return (packToF16(signZ, expZ, sigZ), 0); } - return softfloat_roundPackToF16( - signZ, - expZ as i16, - sigZ, - roundingMode, - detectTininess, - ); + return softfloat_roundPackToF16(signZ, expZ as i16, sigZ, roundingMode, detectTininess); } diff --git a/src/softfloat/s_subMagsF16.rs b/src/softfloat/s_subMagsF16.rs index fe107bc..8af01fa 100644 --- a/src/softfloat/s_subMagsF16.rs +++ b/src/softfloat/s_subMagsF16.rs @@ -3,9 +3,9 @@ use crate::softfloat::softfloat_propagateNaNF16; use super::{ defaultNaNF16UI, expF16UI, float16_t, fracF16UI, packToF16, packToF16UI, signF16UI, softfloat_countLeadingZeros16, softfloat_countLeadingZeros32, softfloat_flag_inexact, - softfloat_flag_invalid, softfloat_propagateNaNF16UI, softfloat_round_max, - softfloat_round_min, softfloat_round_minMag, softfloat_round_near_even, softfloat_round_odd, - softfloat_roundPackToF16, + softfloat_flag_invalid, softfloat_propagateNaNF16UI, softfloat_roundPackToF16, + softfloat_round_max, softfloat_round_min, softfloat_round_minMag, softfloat_round_near_even, + softfloat_round_odd, }; #[must_use] @@ -27,19 +27,11 @@ pub const fn softfloat_subMagsF16( if (sigA | sigB) != 0 { return softfloat_propagateNaNF16(uiA, uiB); } - return ( - float16_t { - v: defaultNaNF16UI, - }, - softfloat_flag_invalid, - ); + return (float16_t { v: defaultNaNF16UI }, softfloat_flag_invalid); } let mut sigDiff = (sigA as i16).wrapping_sub(sigB as i16); if sigDiff == 0 { - return ( - packToF16(roundingMode == softfloat_round_min, 0, 0), - 0, - ); + return (packToF16(roundingMode == softfloat_round_min, 0, 0), 0); } if expA != 0 { expA = expA.wrapping_sub(1); @@ -55,10 +47,7 @@ pub const fn softfloat_subMagsF16( shiftDist = expA as i8; expZ = 0; } - return ( - packToF16(signZ, expZ, (sigDiff << shiftDist) as u16), - 0, - ); + return (packToF16(signZ, expZ, (sigDiff << shiftDist) as u16), 0); } // -------------------------------------------------------------------- let mut signZ = signF16UI(uiA); @@ -144,23 +133,11 @@ pub const fn softfloat_subMagsF16( let mut sigZ = (sig32Z >> 16) as u16; if (sig32Z & 0xFFFF) != 0 { sigZ |= 1; - return softfloat_roundPackToF16( - signZ, - expZ as i16, - sigZ, - roundingMode, - detectTininess, - ); + return softfloat_roundPackToF16(signZ, expZ as i16, sigZ, roundingMode, detectTininess); } if (sigZ & 0xF) == 0 && ((expZ as u32) < 0x1E) { sigZ >>= 4; return (packToF16(signZ, expZ, sigZ), 0); } - return softfloat_roundPackToF16( - signZ, - expZ as i16, - sigZ, - roundingMode, - detectTininess, - ); + return softfloat_roundPackToF16(signZ, expZ as i16, sigZ, roundingMode, detectTininess); } From 8cce208094bba5d5604f526c5a47f98f2602da9a Mon Sep 17 00:00:00 2001 From: Lillian Rose Date: Sun, 5 Oct 2025 19:11:31 -0400 Subject: [PATCH 23/23] Inline specific F16 functions --- src/softfloat/f16_classify.rs | 1 + src/softfloat/f16_eq.rs | 1 + src/softfloat/f16_eq_signaling.rs | 1 + src/softfloat/f16_isSignalingNaN.rs | 2 +- src/softfloat/f16_le.rs | 1 + src/softfloat/f16_le_quiet.rs | 1 + src/softfloat/f16_lt.rs | 1 + src/softfloat/f16_lt_quiet.rs | 1 + src/softfloat/f16_sub.rs | 1 + src/softfloat/s_normRoundPackToF16.rs | 1 + 10 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/softfloat/f16_classify.rs b/src/softfloat/f16_classify.rs index fe40499..e65041c 100644 --- a/src/softfloat/f16_classify.rs +++ b/src/softfloat/f16_classify.rs @@ -1,5 +1,6 @@ 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; diff --git a/src/softfloat/f16_eq.rs b/src/softfloat/f16_eq.rs index d1b75d4..416dfb7 100644 --- a/src/softfloat/f16_eq.rs +++ b/src/softfloat/f16_eq.rs @@ -1,5 +1,6 @@ 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) { diff --git a/src/softfloat/f16_eq_signaling.rs b/src/softfloat/f16_eq_signaling.rs index 8cbdc49..d692e13 100644 --- a/src/softfloat/f16_eq_signaling.rs +++ b/src/softfloat/f16_eq_signaling.rs @@ -1,5 +1,6 @@ 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) { diff --git a/src/softfloat/f16_isSignalingNaN.rs b/src/softfloat/f16_isSignalingNaN.rs index e91a098..e5a3d01 100644 --- a/src/softfloat/f16_isSignalingNaN.rs +++ b/src/softfloat/f16_isSignalingNaN.rs @@ -1,7 +1,7 @@ use super::{float16_t, softfloat_isSigNaNF16UI}; -#[must_use] #[inline] +#[must_use] pub const fn f16_isSignalingNaN(a: float16_t) -> bool { return softfloat_isSigNaNF16UI(a.v); } diff --git a/src/softfloat/f16_le.rs b/src/softfloat/f16_le.rs index aaf49a0..fe83e8a 100644 --- a/src/softfloat/f16_le.rs +++ b/src/softfloat/f16_le.rs @@ -1,5 +1,6 @@ use super::{float16_t, isNaNF16UI, signF16UI, softfloat_flag_invalid}; +#[inline] #[must_use] pub const fn f16_le(a: float16_t, b: float16_t) -> (bool, u8) { if isNaNF16UI(a.v) || isNaNF16UI(b.v) { diff --git a/src/softfloat/f16_le_quiet.rs b/src/softfloat/f16_le_quiet.rs index a9652ad..790c517 100644 --- a/src/softfloat/f16_le_quiet.rs +++ b/src/softfloat/f16_le_quiet.rs @@ -1,5 +1,6 @@ use super::{float16_t, isNaNF16UI, signF16UI, softfloat_flag_invalid, softfloat_isSigNaNF16UI}; +#[inline] #[must_use] pub const fn f16_le_quiet(a: float16_t, b: float16_t) -> (bool, u8) { if isNaNF16UI(a.v) || isNaNF16UI(b.v) { diff --git a/src/softfloat/f16_lt.rs b/src/softfloat/f16_lt.rs index 764d873..4f080d6 100644 --- a/src/softfloat/f16_lt.rs +++ b/src/softfloat/f16_lt.rs @@ -1,5 +1,6 @@ use super::{float16_t, isNaNF16UI, signF16UI, softfloat_flag_invalid}; +#[inline] #[must_use] pub const fn f16_lt(a: float16_t, b: float16_t) -> (bool, u8) { if isNaNF16UI(a.v) || isNaNF16UI(b.v) { diff --git a/src/softfloat/f16_lt_quiet.rs b/src/softfloat/f16_lt_quiet.rs index a1562d6..cfcb27b 100644 --- a/src/softfloat/f16_lt_quiet.rs +++ b/src/softfloat/f16_lt_quiet.rs @@ -1,5 +1,6 @@ use super::{float16_t, isNaNF16UI, signF16UI, softfloat_flag_invalid, softfloat_isSigNaNF16UI}; +#[inline] #[must_use] pub const fn f16_lt_quiet(a: float16_t, b: float16_t) -> (bool, u8) { if isNaNF16UI(a.v) || isNaNF16UI(b.v) { diff --git a/src/softfloat/f16_sub.rs b/src/softfloat/f16_sub.rs index 829f612..6538350 100644 --- a/src/softfloat/f16_sub.rs +++ b/src/softfloat/f16_sub.rs @@ -1,5 +1,6 @@ use super::{float16_t, signF16UI, softfloat_addMagsF16, softfloat_subMagsF16}; +#[inline] #[must_use] pub const fn f16_sub( a: float16_t, diff --git a/src/softfloat/s_normRoundPackToF16.rs b/src/softfloat/s_normRoundPackToF16.rs index 6bae028..7bf081b 100644 --- a/src/softfloat/s_normRoundPackToF16.rs +++ b/src/softfloat/s_normRoundPackToF16.rs @@ -2,6 +2,7 @@ use crate::softfloat::{ float16_t, packToF16UI, softfloat_countLeadingZeros16, softfloat_roundPackToF16, }; +#[inline] #[must_use] pub const fn softfloat_normRoundPackToF16( sign: bool,