softfloat_wrapper_riscv/
f128.rs

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