@@ -31,13 +31,66 @@ namespace SST::RevCPU {
31
31
32
32
struct RevInst ;
33
33
34
- // / BoxNaN: Store a boxed float inside a double
35
- inline void BoxNaN ( double * dest, const float * value ) {
36
- uint32_t i32;
37
- memcpy ( &i32, value, sizeof ( i32 ) ); // The FP32 value
38
- uint64_t i64 = uint64_t { i32 } | ~uint64_t { 0 } << 32 ; // Boxed NaN value
39
- memcpy ( dest, &i64, sizeof ( i64 ) ); // Store in FP64 register
40
- static_assert ( sizeof ( i32 ) == sizeof ( float ) && sizeof ( i64 ) == sizeof ( double ) );
34
+ // Mappings from floating point to same-sized integer types
35
+ template <typename T>
36
+ struct uint_type {};
37
+
38
+ template <>
39
+ struct uint_type <double > {
40
+ using type = uint64_t ;
41
+ static_assert ( sizeof ( type ) == sizeof ( double ) );
42
+ };
43
+
44
+ template <>
45
+ struct uint_type <float > {
46
+ using type = uint32_t ;
47
+ static_assert ( sizeof ( type ) == sizeof ( float ) );
48
+ };
49
+
50
+ template <>
51
+ struct uint_type <float16> {
52
+ using type = uint16_t ;
53
+ static_assert ( sizeof ( type ) == sizeof ( float16 ) );
54
+ };
55
+
56
+ template <typename T>
57
+ using uint_type_t = typename uint_type<T>::type;
58
+
59
+ // / BoxNaN: Store a boxed floating point value inside a possibly larger one
60
+ template <typename T, typename U, typename = std::enable_if_t <sizeof ( T ) >= sizeof ( U )>>
61
+ inline void BoxNaN ( T* dest, const U* value ) {
62
+ if constexpr ( sizeof ( T ) == sizeof ( U ) ) {
63
+ *dest = *value;
64
+ } else {
65
+ uint_type_t <U> i;
66
+ memcpy ( &i, value, sizeof ( i ) ); // The value
67
+ uint_type_t <T> box = uint_type_t <T>{ i } | ~uint_type_t <T>{ 0 } << sizeof ( U ) * 8 ; // Boxed NaN value
68
+ memcpy ( dest, &box, sizeof ( box ) ); // Store in larger register
69
+ static_assert ( sizeof ( i ) == sizeof ( U ) && sizeof ( box ) == sizeof ( T ) );
70
+ }
71
+ }
72
+
73
+ // / UnBoxNaN: Unbox a floating point value into a possibly smaller one
74
+ // The second argument indicates whether it is a FMV/FS move/store
75
+ // instruction which just transfers bits and not care about NaN-Boxing.
76
+ template <typename T, bool FMV_FS = false , typename U, typename = std::enable_if_t <sizeof ( T ) <= sizeof ( U )>>
77
+ inline T UnBoxNaN ( const U* val ) {
78
+ if constexpr ( sizeof ( T ) == sizeof ( U ) ) {
79
+ return *val;
80
+ } else {
81
+ uint_type_t <U> i;
82
+ memcpy ( &i, val, sizeof ( i ) );
83
+ static_assert ( sizeof ( i ) == sizeof ( val ) );
84
+ T fp;
85
+ if ( !FMV_FS && ~i >> sizeof ( T ) * 8 ) {
86
+ fp = std::numeric_limits<T>::quiet_NaN ();
87
+ } else {
88
+ auto ifp = static_cast <uint_type_t <T>>( i );
89
+ memcpy ( &fp, &ifp, sizeof ( fp ) );
90
+ static_assert ( sizeof ( ifp ) == sizeof ( fp ) );
91
+ }
92
+ return fp;
93
+ }
41
94
}
42
95
43
96
// / RISC-V Register Mneumonics
@@ -303,34 +356,23 @@ class RevRegFile {
303
356
template <typename T, bool FMV_FS = false , typename U>
304
357
T GetFP ( U rs ) const {
305
358
if constexpr ( std::is_same_v<T, double > ) {
306
- return DPF[size_t ( rs )]; // The FP64 register's value
359
+ return DPF[size_t ( rs )];
360
+ } else if ( HasD ) {
361
+ return UnBoxNaN<T, FMV_FS>( &DPF[size_t ( rs )] );
307
362
} else {
308
- float fp32;
309
- if ( !HasD ) {
310
- fp32 = SPF[size_t ( rs )]; // The FP32 register's value
311
- } else {
312
- uint64_t i64;
313
- memcpy ( &i64, &DPF[size_t ( rs )], sizeof ( i64 ) ); // The FP64 register's value
314
- if ( !FMV_FS && ~i64 >> 32 ) { // Check for boxed NaN unless FMV/FS
315
- fp32 = NAN; // Return NaN if it's not boxed
316
- } else {
317
- auto i32 = static_cast <uint32_t >( i64 ); // For endian independence on host
318
- memcpy ( &fp32, &i32, sizeof ( fp32 ) ); // The bottom half of FP64
319
- }
320
- }
321
- return fp32; // Reinterpreted as FP32
363
+ return UnBoxNaN<T, FMV_FS>( &SPF[size_t ( rs )] );
322
364
}
323
365
}
324
366
325
367
// / SetFP: Set a specific FP register to a floating-point value
326
368
template <typename T, typename U>
327
369
void SetFP ( U rd, T value ) {
328
370
if constexpr ( std::is_same_v<T, double > ) {
329
- DPF[size_t ( rd )] = value; // Store in FP64 register
371
+ DPF[size_t ( rd )] = value;
330
372
} else if ( HasD ) {
331
- BoxNaN ( &DPF[size_t ( rd )], &value ); // Store NaN-boxed float in FP64 register
373
+ BoxNaN ( &DPF[size_t ( rd )], &value );
332
374
} else {
333
- SPF[size_t ( rd )] = value; // Store in FP32 register
375
+ BoxNaN ( & SPF[size_t ( rd )], & value );
334
376
}
335
377
}
336
378
@@ -425,8 +467,8 @@ class RevRegFile {
425
467
FCSR& GetFCSR () { return fcsr; }
426
468
427
469
// Friend functions and classes to access internal register state
428
- template <typename FP , typename INT >
429
- friend bool CvtFpToInt ( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst );
470
+ template <typename INT , typename FP >
471
+ friend bool fcvtif ( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst );
430
472
431
473
template <typename T>
432
474
friend bool load ( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst );
0 commit comments