softfloat_wrapper_riscv/
lib.rs1mod f128;
25mod f16;
26mod f32;
27mod f64;
28pub use crate::f128::F128;
29pub use crate::f16::F16;
30pub use crate::f32::F32;
31pub use crate::f64::F64;
32
33use num_traits::{
34 identities::{One, Zero},
35 PrimInt,
36};
37use std::borrow::Borrow;
38use std::cmp::Ordering;
39use std::fmt::{LowerHex, UpperHex};
40
41#[derive(Copy, Clone, Debug)]
43pub enum RoundingMode {
44 TiesToEven,
46 TowardZero,
48 TowardNegative,
50 TowardPositive,
52 TiesToAway,
54}
55
56impl RoundingMode {
57 fn set(&self) {
58 unsafe {
59 softfloat_sys_riscv::softfloat_roundingMode_write_helper(self.to_softfloat());
60 }
61 }
62
63 fn to_softfloat(&self) -> u8 {
64 match self {
65 RoundingMode::TiesToEven => softfloat_sys_riscv::softfloat_round_near_even,
66 RoundingMode::TowardZero => softfloat_sys_riscv::softfloat_round_minMag,
67 RoundingMode::TowardNegative => softfloat_sys_riscv::softfloat_round_min,
68 RoundingMode::TowardPositive => softfloat_sys_riscv::softfloat_round_max,
69 RoundingMode::TiesToAway => softfloat_sys_riscv::softfloat_round_near_maxMag,
70 }
71 }
72}
73
74#[derive(Copy, Clone, Debug, Default)]
92pub struct ExceptionFlags(u8);
93
94impl ExceptionFlags {
95 const FLAG_INEXACT: u8 = softfloat_sys_riscv::softfloat_flag_inexact;
96 const FLAG_INFINITE: u8 = softfloat_sys_riscv::softfloat_flag_infinite;
97 const FLAG_INVALID: u8 = softfloat_sys_riscv::softfloat_flag_invalid;
98 const FLAG_OVERFLOW: u8 = softfloat_sys_riscv::softfloat_flag_overflow;
99 const FLAG_UNDERFLOW: u8 = softfloat_sys_riscv::softfloat_flag_underflow;
100
101 pub fn from_bits(x: u8) -> Self {
102 Self(x)
103 }
104
105 pub fn bits(&self) -> u8 {
106 self.0
107 }
108
109 pub fn is_inexact(&self) -> bool {
110 self.0 & Self::FLAG_INEXACT != 0
111 }
112
113 pub fn is_infinite(&self) -> bool {
114 self.0 & Self::FLAG_INFINITE != 0
115 }
116
117 pub fn is_invalid(&self) -> bool {
118 self.0 & Self::FLAG_INVALID != 0
119 }
120
121 pub fn is_overflow(&self) -> bool {
122 self.0 & Self::FLAG_OVERFLOW != 0
123 }
124
125 pub fn is_underflow(&self) -> bool {
126 self.0 & Self::FLAG_UNDERFLOW != 0
127 }
128
129 pub fn set(&self) {
130 unsafe {
131 softfloat_sys_riscv::softfloat_exceptionFlags_write_helper(self.bits());
132 }
133 }
134
135 pub fn get(&mut self) {
136 let x = unsafe { softfloat_sys_riscv::softfloat_exceptionFlags_read_helper() };
137 self.0 = x;
138 }
139}
140
141pub trait Float {
162 type Payload: PrimInt + UpperHex + LowerHex;
163
164 const EXPONENT_BIT: Self::Payload;
165 const FRACTION_BIT: Self::Payload;
166 const SIGN_POS: usize;
167 const EXPONENT_POS: usize;
168
169 fn set_payload(&mut self, x: Self::Payload);
170
171 fn from_bits(v: Self::Payload) -> Self;
172
173 fn bits(&self) -> Self::Payload;
174
175 fn add<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self;
176
177 fn sub<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self;
178
179 fn mul<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self;
180
181 fn fused_mul_add<T: Borrow<Self>>(&self, x: T, y: T, rnd: RoundingMode) -> Self;
182
183 fn div<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self;
184
185 fn rem<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self;
186
187 fn sqrt(&self, rnd: RoundingMode) -> Self;
188
189 fn compare<T: Borrow<Self>>(&self, x: T) -> Option<Ordering>;
190
191 fn from_u32(x: u32, rnd: RoundingMode) -> Self;
192
193 fn from_u64(x: u64, rnd: RoundingMode) -> Self;
194
195 fn from_i32(x: i32, rnd: RoundingMode) -> Self;
196
197 fn from_i64(x: i64, rnd: RoundingMode) -> Self;
198
199 fn to_u32(&self, rnd: RoundingMode) -> u32;
200
201 fn to_u64(&self, rnd: RoundingMode) -> u64;
202
203 fn to_i32(&self, rnd: RoundingMode) -> i32;
204
205 fn to_i64(&self, rnd: RoundingMode) -> i64;
206
207 fn to_f16(&self, rnd: RoundingMode) -> F16;
208
209 fn to_f32(&self, rnd: RoundingMode) -> F32;
210
211 fn to_f64(&self, rnd: RoundingMode) -> F64;
212
213 fn to_f128(&self, rnd: RoundingMode) -> F128;
214
215 fn round_to_integral(&self, rnd: RoundingMode) -> Self;
216
217 #[inline]
218 fn from_u8(x: u8, rnd: RoundingMode) -> Self
219 where
220 Self: Sized,
221 {
222 Self::from_u32(x as u32, rnd)
223 }
224
225 #[inline]
226 fn from_u16(x: u16, rnd: RoundingMode) -> Self
227 where
228 Self: Sized,
229 {
230 Self::from_u32(x as u32, rnd)
231 }
232
233 #[inline]
234 fn from_i8(x: i8, rnd: RoundingMode) -> Self
235 where
236 Self: Sized,
237 {
238 Self::from_i32(x as i32, rnd)
239 }
240
241 #[inline]
242 fn from_i16(x: i16, rnd: RoundingMode) -> Self
243 where
244 Self: Sized,
245 {
246 Self::from_i32(x as i32, rnd)
247 }
248
249 #[inline]
250 fn neg(&self) -> Self
251 where
252 Self: Sized,
253 {
254 let mut ret = Self::from_bits(self.bits());
255 ret.set_sign(!self.sign());
256 ret
257 }
258
259 #[inline]
260 fn abs(&self) -> Self
261 where
262 Self: Sized,
263 {
264 let mut ret = Self::from_bits(self.bits());
265 ret.set_sign(Self::Payload::zero());
266 ret
267 }
268
269 #[inline]
270 fn sign(&self) -> Self::Payload {
271 (self.bits() >> Self::SIGN_POS) & Self::Payload::one()
272 }
273
274 #[inline]
275 fn exponent(&self) -> Self::Payload {
276 (self.bits() >> Self::EXPONENT_POS) & Self::EXPONENT_BIT
277 }
278
279 #[inline]
280 fn fraction(&self) -> Self::Payload {
281 self.bits() & Self::FRACTION_BIT
282 }
283
284 #[inline]
285 fn is_positive(&self) -> bool {
286 self.sign() == Self::Payload::zero()
287 }
288
289 #[inline]
290 fn is_positive_zero(&self) -> bool {
291 self.is_positive()
292 && self.exponent() == Self::Payload::zero()
293 && self.fraction() == Self::Payload::zero()
294 }
295
296 #[inline]
297 fn is_positive_subnormal(&self) -> bool {
298 self.is_positive()
299 && self.exponent() == Self::Payload::zero()
300 && self.fraction() != Self::Payload::zero()
301 }
302
303 #[inline]
304 fn is_positive_normal(&self) -> bool {
305 self.is_positive()
306 && self.exponent() != Self::Payload::zero()
307 && self.exponent() != Self::EXPONENT_BIT
308 }
309
310 #[inline]
311 fn is_positive_infinity(&self) -> bool {
312 self.is_positive()
313 && self.exponent() == Self::EXPONENT_BIT
314 && self.fraction() == Self::Payload::zero()
315 }
316
317 #[inline]
318 fn is_negative(&self) -> bool {
319 self.sign() == Self::Payload::one()
320 }
321
322 #[inline]
323 fn is_negative_zero(&self) -> bool {
324 self.is_negative()
325 && self.exponent() == Self::Payload::zero()
326 && self.fraction() == Self::Payload::zero()
327 }
328
329 #[inline]
330 fn is_negative_subnormal(&self) -> bool {
331 self.is_negative()
332 && self.exponent() == Self::Payload::zero()
333 && self.fraction() != Self::Payload::zero()
334 }
335
336 #[inline]
337 fn is_negative_normal(&self) -> bool {
338 self.is_negative()
339 && self.exponent() != Self::Payload::zero()
340 && self.exponent() != Self::EXPONENT_BIT
341 }
342
343 #[inline]
344 fn is_negative_infinity(&self) -> bool {
345 self.is_negative()
346 && self.exponent() == Self::EXPONENT_BIT
347 && self.fraction() == Self::Payload::zero()
348 }
349
350 #[inline]
351 fn is_nan(&self) -> bool {
352 self.exponent() == Self::EXPONENT_BIT && self.fraction() != Self::Payload::zero()
353 }
354
355 #[inline]
356 fn is_zero(&self) -> bool {
357 self.is_positive_zero() || self.is_negative_zero()
358 }
359
360 #[inline]
361 fn is_subnormal(&self) -> bool {
362 self.exponent() == Self::Payload::zero()
363 }
364
365 #[inline]
366 fn set_sign(&mut self, x: Self::Payload) {
367 self.set_payload(
368 (self.bits() & !(Self::Payload::one() << Self::SIGN_POS))
369 | ((x & Self::Payload::one()) << Self::SIGN_POS),
370 );
371 }
372
373 #[inline]
374 fn set_exponent(&mut self, x: Self::Payload) {
375 self.set_payload(
376 (self.bits() & !(Self::EXPONENT_BIT << Self::EXPONENT_POS))
377 | ((x & Self::EXPONENT_BIT) << Self::EXPONENT_POS),
378 );
379 }
380
381 #[inline]
382 fn set_fraction(&mut self, x: Self::Payload) {
383 self.set_payload((self.bits() & !Self::FRACTION_BIT) | (x & Self::FRACTION_BIT));
384 }
385
386 #[inline]
387 fn positive_infinity() -> Self
388 where
389 Self: Sized,
390 {
391 let mut x = Self::from_bits(Self::Payload::zero());
392 x.set_exponent(Self::EXPONENT_BIT);
393 x
394 }
395
396 #[inline]
397 fn positive_zero() -> Self
398 where
399 Self: Sized,
400 {
401 let x = Self::from_bits(Self::Payload::zero());
402 x
403 }
404
405 #[inline]
406 fn negative_infinity() -> Self
407 where
408 Self: Sized,
409 {
410 let mut x = Self::from_bits(Self::Payload::zero());
411 x.set_sign(Self::Payload::one());
412 x.set_exponent(Self::EXPONENT_BIT);
413 x
414 }
415
416 #[inline]
417 fn negative_zero() -> Self
418 where
419 Self: Sized,
420 {
421 let mut x = Self::from_bits(Self::Payload::zero());
422 x.set_sign(Self::Payload::one());
423 x
424 }
425
426 #[inline]
427 fn quiet_nan() -> Self
428 where
429 Self: Sized,
430 {
431 let mut x = Self::from_bits(Self::Payload::zero());
432 x.set_exponent(Self::EXPONENT_BIT);
433 x.set_fraction(Self::Payload::one() << (Self::EXPONENT_POS - 1));
434 x
435 }
436}
437
438#[cfg(test)]
439mod tests {
440 use super::*;
441
442 #[test]
443 fn flag_inexact() {
444 let a = 0x1234;
445 let b = 0x7654;
446 let a = F16::from_bits(a);
447 let b = F16::from_bits(b);
448 let mut flag = ExceptionFlags::default();
449 flag.set();
450 let _d = a.add(b, RoundingMode::TiesToEven);
451 flag.get();
452 assert!(flag.is_inexact());
453 assert!(!flag.is_infinite());
454 assert!(!flag.is_invalid());
455 assert!(!flag.is_overflow());
456 assert!(!flag.is_underflow());
457 }
458
459 #[test]
460 fn flag_infinite() {
461 let a = 0x1234;
462 let b = 0x0;
463 let a = F16::from_bits(a);
464 let b = F16::from_bits(b);
465 let mut flag = ExceptionFlags::default();
466 flag.set();
467 let _d = a.div(b, RoundingMode::TiesToEven);
468 flag.get();
469 assert!(!flag.is_inexact());
470 assert!(flag.is_infinite());
471 assert!(!flag.is_invalid());
472 assert!(!flag.is_overflow());
473 assert!(!flag.is_underflow());
474 }
475
476 #[test]
477 fn flag_invalid() {
478 let a = 0x0;
479 let b = 0x0;
480 let a = F16::from_bits(a);
481 let b = F16::from_bits(b);
482 let mut flag = ExceptionFlags::default();
483 flag.set();
484 let _d = a.div(b, RoundingMode::TiesToEven);
485 flag.get();
486 assert!(!flag.is_inexact());
487 assert!(!flag.is_infinite());
488 assert!(flag.is_invalid());
489 assert!(!flag.is_overflow());
490 assert!(!flag.is_underflow());
491 }
492
493 #[test]
494 fn flag_overflow() {
495 let a = 0x7bff;
496 let b = 0x7bff;
497 let a = F16::from_bits(a);
498 let b = F16::from_bits(b);
499 let mut flag = ExceptionFlags::default();
500 flag.set();
501 let _d = a.add(b, RoundingMode::TiesToEven);
502 flag.get();
503 assert!(flag.is_inexact());
504 assert!(!flag.is_infinite());
505 assert!(!flag.is_invalid());
506 assert!(flag.is_overflow());
507 assert!(!flag.is_underflow());
508 }
509
510 #[test]
511 fn flag_underflow() {
512 let a = 0x0001;
513 let b = 0x0001;
514 let a = F16::from_bits(a);
515 let b = F16::from_bits(b);
516 let mut flag = ExceptionFlags::default();
517 flag.set();
518 let _d = a.mul(b, RoundingMode::TiesToEven);
519 flag.get();
520 assert!(flag.is_inexact());
521 assert!(!flag.is_infinite());
522 assert!(!flag.is_invalid());
523 assert!(!flag.is_overflow());
524 assert!(flag.is_underflow());
525 }
526}