@@ -31,13 +31,68 @@ 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
+ #if 0
51
+ template<>
52
+ struct uint_type<float16> {
53
+ using type = uint16_t;
54
+ static_assert( sizeof( type ) == sizeof( float16 ) );
55
+ };
56
+ #endif
57
+
58
+ template <typename T>
59
+ using uint_type_t = typename uint_type<T>::type;
60
+
61
+ // / BoxNaN: Store a boxed floating point value inside a possibly larger one
62
+ template <typename T, typename U, typename = std::enable_if_t <sizeof ( T ) >= sizeof ( U )>>
63
+ inline void BoxNaN ( T* dest, const U* value ) {
64
+ if constexpr ( sizeof ( T ) == sizeof ( U ) ) {
65
+ *dest = *value;
66
+ } else {
67
+ uint_type_t <U> i;
68
+ memcpy ( &i, value, sizeof ( i ) ); // The value
69
+ uint_type_t <T> box = uint_type_t <T>{ i } | ~uint_type_t <T>{ 0 } << sizeof ( U ) * 8 ; // Boxed NaN value
70
+ memcpy ( dest, &box, sizeof ( box ) ); // Store in larger register
71
+ static_assert ( sizeof ( i ) == sizeof ( U ) && sizeof ( box ) == sizeof ( T ) );
72
+ }
73
+ }
74
+
75
+ // / UnBoxNaN: Unbox a floating point value into a possibly smaller one
76
+ // The second argument indicates whether it is a FMV/FS move/store
77
+ // instruction which just transfers bits and not care about NaN-Boxing.
78
+ template <typename T, bool FMV_FS = false , typename U, typename = std::enable_if_t <sizeof ( T ) <= sizeof ( U )>>
79
+ inline T UnBoxNaN ( const U* val ) {
80
+ if constexpr ( sizeof ( T ) == sizeof ( U ) ) {
81
+ return *val;
82
+ } else {
83
+ uint_type_t <U> i;
84
+ memcpy ( &i, val, sizeof ( i ) );
85
+ static_assert ( sizeof ( i ) == sizeof ( val ) );
86
+ T fp;
87
+ if ( !FMV_FS && ~i >> sizeof ( T ) * 8 ) {
88
+ fp = std::numeric_limits<T>::quiet_NaN ();
89
+ } else {
90
+ auto ifp = static_cast <uint_type_t <T>>( i );
91
+ memcpy ( &fp, &ifp, sizeof ( fp ) );
92
+ static_assert ( sizeof ( ifp ) == sizeof ( fp ) );
93
+ }
94
+ return fp;
95
+ }
41
96
}
42
97
43
98
// / RISC-V Register Mneumonics
@@ -303,34 +358,23 @@ class RevRegFile {
303
358
template <typename T, bool FMV_FS = false , typename U>
304
359
T GetFP ( U rs ) const {
305
360
if constexpr ( std::is_same_v<T, double > ) {
306
- return DPF[size_t ( rs )]; // The FP64 register's value
361
+ return DPF[size_t ( rs )];
362
+ } else if ( HasD ) {
363
+ return UnBoxNaN<T, FMV_FS>( &DPF[size_t ( rs )] );
307
364
} 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
365
+ return UnBoxNaN<T, FMV_FS>( &SPF[size_t ( rs )] );
322
366
}
323
367
}
324
368
325
369
// / SetFP: Set a specific FP register to a floating-point value
326
370
template <typename T, typename U>
327
371
void SetFP ( U rd, T value ) {
328
372
if constexpr ( std::is_same_v<T, double > ) {
329
- DPF[size_t ( rd )] = value; // Store in FP64 register
373
+ DPF[size_t ( rd )] = value;
330
374
} else if ( HasD ) {
331
- BoxNaN ( &DPF[size_t ( rd )], &value ); // Store NaN-boxed float in FP64 register
375
+ BoxNaN ( &DPF[size_t ( rd )], &value );
332
376
} else {
333
- SPF[size_t ( rd )] = value; // Store in FP32 register
377
+ BoxNaN ( & SPF[size_t ( rd )], & value );
334
378
}
335
379
}
336
380
@@ -425,8 +469,8 @@ class RevRegFile {
425
469
FCSR& GetFCSR () { return fcsr; }
426
470
427
471
// 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 );
472
+ template <typename INT , typename FP >
473
+ friend bool fcvtif ( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst );
430
474
431
475
template <typename T>
432
476
friend bool load ( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst );
0 commit comments