use crate::fixed_point::core_types::errors::OverflowDetected;
#[cfg(any(table_format = "q16_16", table_format = "q32_32"))]
use crate::fixed_point::universal::fasc::stack_evaluator::BinaryStorage;
#[cfg(any(table_format = "q16_16", table_format = "q32_32"))]
use crate::fixed_point::imperative::FixedPoint;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum HalfKind {
Binary16,
BFloat16,
}
#[inline]
pub fn decompose(bits: u16, kind: HalfKind) -> Result<(bool, u64, i32), OverflowDetected> {
let sign = bits & 0x8000 != 0;
match kind {
HalfKind::Binary16 => {
let exp = ((bits >> 10) & 0x1F) as i32;
let mant = (bits & 0x3FF) as u64;
if exp == 0x1F {
return Err(OverflowDetected::InvalidInput);
}
Ok(if exp == 0 { (sign, mant, -24) } else { (sign, mant | 0x400, exp - 25) })
}
HalfKind::BFloat16 => {
let exp = ((bits >> 7) & 0xFF) as i32;
let mant = (bits & 0x7F) as u64;
if exp == 0xFF {
return Err(OverflowDetected::InvalidInput);
}
Ok(if exp == 0 { (sign, mant, -133) } else { (sign, mant | 0x80, exp - 134) })
}
}
}
pub fn to_raw(bits: u16, kind: HalfKind, frac_bits: u32) -> Result<i128, OverflowDetected> {
let (sign, m, e) = decompose(bits, kind)?;
if m == 0 {
return Ok(0);
}
let shift = e as i64 + frac_bits as i64;
let mag: i128 = if shift >= 0 {
let top = 64 - m.leading_zeros() as i64;
if top + shift > 127 {
return Err(OverflowDetected::TierOverflow);
}
(m as i128) << shift
} else if -shift >= 64 {
0
} else {
(m >> (-shift) as u32) as i128
};
Ok(if sign { -mag } else { mag })
}
#[inline]
pub fn to_q64_raw(bits: u16, kind: HalfKind) -> Result<i128, OverflowDetected> {
to_raw(bits, kind, 64)
}
#[cfg(any(table_format = "q16_16", table_format = "q32_32"))]
pub fn to_storage_raw(bits: u16, kind: HalfKind) -> Result<BinaryStorage, OverflowDetected> {
#[cfg(table_format = "q16_16")]
let frac_bits = crate::fixed_point::frac_config::FRAC_BITS;
#[cfg(table_format = "q32_32")]
let frac_bits = 32;
let raw = to_raw(bits, kind, frac_bits)?;
if raw > BinaryStorage::MAX as i128 || raw < -(BinaryStorage::MAX as i128) {
return Err(OverflowDetected::TierOverflow);
}
Ok(raw as BinaryStorage)
}
#[cfg(any(table_format = "q16_16", table_format = "q32_32"))]
#[inline]
pub fn to_fixed(bits: u16, kind: HalfKind) -> Result<FixedPoint, OverflowDetected> {
Ok(FixedPoint::from_raw(to_storage_raw(bits, kind)?))
}
pub fn to_tq19_raw(bits: u16, kind: HalfKind) -> Result<i64, OverflowDetected> {
let (sign, m, e) = decompose(bits, kind)?;
if m == 0 {
return Ok(0);
}
let n = (m as i64) * super::SCALE as i64;
let mag: i64 = if e >= 0 {
if e > 20 { i64::MAX / 4 } else { n << e }
} else {
let k = (-e) as u32;
if k >= 63 { 0 } else { (n + (1i64 << (k - 1))) >> k }
};
Ok(if sign { -mag } else { mag })
}
#[derive(Clone)]
pub struct WeightBits {
pub rows: usize,
pub cols: usize,
pub kind: HalfKind,
pub bits: Vec<u16>,
}
impl WeightBits {
pub fn from_le_bytes(rows: usize, cols: usize, kind: HalfKind, bytes: &[u8]) -> Result<Self, OverflowDetected> {
let n = rows * cols;
if bytes.len() < n * 2 {
return Err(OverflowDetected::InvalidInput);
}
let bits = bytes[..n * 2].chunks_exact(2).map(|c| u16::from_le_bytes([c[0], c[1]])).collect();
Ok(Self { rows, cols, kind, bits })
}
#[cfg(any(table_format = "q16_16", table_format = "q32_32"))]
#[inline]
pub fn storage_raw(&self, i: usize) -> Result<BinaryStorage, OverflowDetected> {
to_storage_raw(self.bits[i], self.kind)
}
#[inline]
pub fn tq19_raw(&self, i: usize) -> Result<i64, OverflowDetected> {
to_tq19_raw(self.bits[i], self.kind)
}
#[inline]
pub fn decompose(&self, i: usize) -> Result<(bool, u64, i32), OverflowDetected> {
decompose(self.bits[i], self.kind)
}
}