softfloat_wrapper_riscv/
f16.rs

1use crate::{Float, RoundingMode, F128, F32, F64};
2use softfloat_sys_riscv::float16_t;
3use std::borrow::Borrow;
4use std::cmp::Ordering;
5
6/// standard 16-bit float
7#[derive(Copy, Clone, Debug)]
8pub struct F16(float16_t);
9
10impl Float for F16 {
11    type Payload = u16;
12
13    const EXPONENT_BIT: Self::Payload = 0x1f;
14    const FRACTION_BIT: Self::Payload = 0x3ff;
15    const SIGN_POS: usize = 15;
16    const EXPONENT_POS: usize = 10;
17
18    #[inline]
19    fn set_payload(&mut self, x: Self::Payload) {
20        self.0.v = x;
21    }
22
23    #[inline]
24    fn from_bits(v: Self::Payload) -> Self {
25        Self(float16_t { v })
26    }
27
28    #[inline]
29    fn bits(&self) -> Self::Payload {
30        self.0.v
31    }
32
33    fn add<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self {
34        rnd.set();
35        let ret = unsafe { softfloat_sys_riscv::f16_add(self.0, x.borrow().0) };
36        Self(ret)
37    }
38
39    fn sub<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self {
40        rnd.set();
41        let ret = unsafe { softfloat_sys_riscv::f16_sub(self.0, x.borrow().0) };
42        Self(ret)
43    }
44
45    fn mul<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self {
46        rnd.set();
47        let ret = unsafe { softfloat_sys_riscv::f16_mul(self.0, x.borrow().0) };
48        Self(ret)
49    }
50
51    fn fused_mul_add<T: Borrow<Self>>(&self, x: T, y: T, rnd: RoundingMode) -> Self {
52        rnd.set();
53        let ret = unsafe { softfloat_sys_riscv::f16_mulAdd(self.0, x.borrow().0, y.borrow().0) };
54        Self(ret)
55    }
56
57    fn div<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self {
58        rnd.set();
59        let ret = unsafe { softfloat_sys_riscv::f16_div(self.0, x.borrow().0) };
60        Self(ret)
61    }
62
63    fn rem<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self {
64        rnd.set();
65        let ret = unsafe { softfloat_sys_riscv::f16_rem(self.0, x.borrow().0) };
66        Self(ret)
67    }
68
69    fn sqrt(&self, rnd: RoundingMode) -> Self {
70        rnd.set();
71        let ret = unsafe { softfloat_sys_riscv::f16_sqrt(self.0) };
72        Self(ret)
73    }
74
75    fn compare<T: Borrow<Self>>(&self, x: T) -> Option<Ordering> {
76        let eq = unsafe { softfloat_sys_riscv::f16_eq(self.0, x.borrow().0) };
77        let lt = unsafe { softfloat_sys_riscv::f16_lt(self.0, x.borrow().0) };
78        if self.is_nan() || x.borrow().is_nan() {
79            None
80        } else if eq {
81            Some(Ordering::Equal)
82        } else if lt {
83            Some(Ordering::Less)
84        } else {
85            Some(Ordering::Greater)
86        }
87    }
88
89    fn from_u32(x: u32, rnd: RoundingMode) -> Self {
90        rnd.set();
91        let ret = unsafe { softfloat_sys_riscv::ui32_to_f16(x) };
92        Self(ret)
93    }
94
95    fn from_u64(x: u64, rnd: RoundingMode) -> Self {
96        rnd.set();
97        let ret = unsafe { softfloat_sys_riscv::ui64_to_f16(x) };
98        Self(ret)
99    }
100
101    fn from_i32(x: i32, rnd: RoundingMode) -> Self {
102        rnd.set();
103        let ret = unsafe { softfloat_sys_riscv::i32_to_f16(x) };
104        Self(ret)
105    }
106
107    fn from_i64(x: i64, rnd: RoundingMode) -> Self {
108        rnd.set();
109        let ret = unsafe { softfloat_sys_riscv::i64_to_f16(x) };
110        Self(ret)
111    }
112
113    fn to_u32(&self, rnd: RoundingMode) -> u32 {
114        let ret = unsafe { softfloat_sys_riscv::f16_to_ui32(self.0, rnd.to_softfloat(), false) };
115        ret as u32
116    }
117
118    fn to_u64(&self, rnd: RoundingMode) -> u64 {
119        let ret = unsafe { softfloat_sys_riscv::f16_to_ui64(self.0, rnd.to_softfloat(), false) };
120        ret
121    }
122
123    fn to_i32(&self, rnd: RoundingMode) -> i32 {
124        let ret = unsafe { softfloat_sys_riscv::f16_to_i32(self.0, rnd.to_softfloat(), false) };
125        ret as i32
126    }
127
128    fn to_i64(&self, rnd: RoundingMode) -> i64 {
129        let ret = unsafe { softfloat_sys_riscv::f16_to_i64(self.0, rnd.to_softfloat(), false) };
130        ret
131    }
132
133    fn to_f16(&self, _rnd: RoundingMode) -> F16 {
134        Self::from_bits(self.bits())
135    }
136
137    fn to_f32(&self, rnd: RoundingMode) -> F32 {
138        rnd.set();
139        let ret = unsafe { softfloat_sys_riscv::f16_to_f32(self.0) };
140        F32::from_bits(ret.v)
141    }
142
143    fn to_f64(&self, rnd: RoundingMode) -> F64 {
144        rnd.set();
145        let ret = unsafe { softfloat_sys_riscv::f16_to_f64(self.0) };
146        F64::from_bits(ret.v)
147    }
148
149    fn to_f128(&self, rnd: RoundingMode) -> F128 {
150        rnd.set();
151        let ret = unsafe { softfloat_sys_riscv::f16_to_f128(self.0) };
152        let mut v = 0u128;
153        v |= ret.v[0] as u128;
154        v |= (ret.v[1] as u128) << 64;
155        F128::from_bits(v)
156    }
157
158    fn round_to_integral(&self, rnd: RoundingMode) -> Self {
159        let ret = unsafe { softfloat_sys_riscv::f16_roundToInt(self.0, rnd.to_softfloat(), false) };
160        Self(ret)
161    }
162}
163
164#[cfg(test)]
165mod tests {
166    use super::*;
167
168    #[test]
169    fn f16_add() {
170        let a = 0x1234;
171        let b = 0x7654;
172        let a0 = F16::from_bits(a);
173        let b0 = F16::from_bits(b);
174        let d0 = a0.add(b0, RoundingMode::TiesToEven);
175        let a1 = simple_soft_float::F16::from_bits(a);
176        let b1 = simple_soft_float::F16::from_bits(b);
177        let d1 = a1.add(&b1, Some(simple_soft_float::RoundingMode::TiesToEven), None);
178        assert_eq!(d0.bits(), *d1.bits());
179    }
180
181    #[test]
182    fn f16_sub() {
183        let a = 0x1234;
184        let b = 0x7654;
185        let a0 = F16::from_bits(a);
186        let b0 = F16::from_bits(b);
187        let d0 = a0.sub(b0, RoundingMode::TiesToEven);
188        let a1 = simple_soft_float::F16::from_bits(a);
189        let b1 = simple_soft_float::F16::from_bits(b);
190        let d1 = a1.sub(&b1, Some(simple_soft_float::RoundingMode::TiesToEven), None);
191        assert_eq!(d0.bits(), *d1.bits());
192    }
193
194    #[test]
195    fn f16_mul() {
196        let a = 0x1234;
197        let b = 0x7654;
198        let a0 = F16::from_bits(a);
199        let b0 = F16::from_bits(b);
200        let d0 = a0.mul(b0, RoundingMode::TiesToEven);
201        let a1 = simple_soft_float::F16::from_bits(a);
202        let b1 = simple_soft_float::F16::from_bits(b);
203        let d1 = a1.mul(&b1, Some(simple_soft_float::RoundingMode::TiesToEven), None);
204        assert_eq!(d0.bits(), *d1.bits());
205    }
206
207    #[test]
208    fn f16_fused_mul_add() {
209        let a = 0x1234;
210        let b = 0x1234;
211        let c = 0x1234;
212        let a0 = F16::from_bits(a);
213        let b0 = F16::from_bits(b);
214        let c0 = F16::from_bits(c);
215        let d0 = a0.fused_mul_add(b0, c0, RoundingMode::TiesToEven);
216        let a1 = simple_soft_float::F16::from_bits(a);
217        let b1 = simple_soft_float::F16::from_bits(b);
218        let c1 = simple_soft_float::F16::from_bits(c);
219        let d1 = a1.fused_mul_add(
220            &b1,
221            &c1,
222            Some(simple_soft_float::RoundingMode::TiesToEven),
223            None,
224        );
225        assert_eq!(d0.bits(), *d1.bits());
226    }
227
228    #[test]
229    fn f16_div() {
230        let a = 0x7654;
231        let b = 0x1234;
232        let a0 = F16::from_bits(a);
233        let b0 = F16::from_bits(b);
234        let d0 = a0.div(b0, RoundingMode::TiesToEven);
235        let a1 = simple_soft_float::F16::from_bits(a);
236        let b1 = simple_soft_float::F16::from_bits(b);
237        let d1 = a1.div(&b1, Some(simple_soft_float::RoundingMode::TiesToEven), None);
238        assert_eq!(d0.bits(), *d1.bits());
239    }
240
241    #[test]
242    fn f16_rem() {
243        let a = 0x7654;
244        let b = 0x1234;
245        let a0 = F16::from_bits(a);
246        let b0 = F16::from_bits(b);
247        let d0 = a0.rem(b0, RoundingMode::TiesToEven);
248        let a1 = simple_soft_float::F16::from_bits(a);
249        let b1 = simple_soft_float::F16::from_bits(b);
250        let d1 = a1.ieee754_remainder(&b1, Some(simple_soft_float::RoundingMode::TiesToEven), None);
251        assert_eq!(d0.bits(), *d1.bits());
252    }
253
254    #[test]
255    fn f16_sqrt() {
256        let a = 0x7654;
257        let a0 = F16::from_bits(a);
258        let d0 = a0.sqrt(RoundingMode::TiesToEven);
259        let a1 = simple_soft_float::F16::from_bits(a);
260        let d1 = a1.sqrt(Some(simple_soft_float::RoundingMode::TiesToEven), None);
261        assert_eq!(d0.bits(), *d1.bits());
262    }
263
264    #[test]
265    fn f16_compare() {
266        let a = F16::from_bits(0x7654);
267        let b = F16::from_bits(0x1234);
268        let d = a.compare(b);
269        assert_eq!(d, Some(Ordering::Greater));
270
271        let a = F16::from_bits(0x1234);
272        let b = F16::from_bits(0x7654);
273        let d = a.compare(b);
274        assert_eq!(d, Some(Ordering::Less));
275
276        let a = F16::from_bits(0x1234);
277        let b = F16::from_bits(0x1234);
278        let d = a.compare(b);
279        assert_eq!(d, Some(Ordering::Equal));
280    }
281}