Skip to content

Commit c178e1e

Browse files
authored
Merge pull request #307 from tactcomplabs/revert-306-templatize_helpers
Revert "Fully templatize floating-point helper functions"
2 parents 1c0ddb0 + deee736 commit c178e1e

File tree

7 files changed

+193
-211
lines changed

7 files changed

+193
-211
lines changed

common/include/RevCommon.h

-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@
3434

3535
namespace SST::RevCPU {
3636

37-
using float16 = _Float16;
38-
3937
/// Zero-extend value of bits size
4038
template<typename T>
4139
constexpr auto ZeroExt( T val, size_t bits ) {

include/RevInstHelpers.h

+2-87
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ inline constexpr double fpmin<double, uint64_t> = 0x0p+0;
6565
/// General template for converting between Floating Point and Integer.
6666
/// FP values outside the range of the target integer type are clipped
6767
/// at the integer type's numerical limits, whether signed or unsigned.
68-
template<typename INT, typename FP>
69-
bool fcvtif( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
68+
template<typename FP, typename INT>
69+
bool CvtFpToInt( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
7070
// Read the FP register. Round to integer according to current rounding mode.
7171
FP fp = std::rint( R->GetFP<FP>( Inst.rs1 ) );
7272

@@ -115,10 +115,6 @@ uint32_t fclass( T val ) {
115115
uint32_t i32;
116116
memcpy( &i32, &val, sizeof( i32 ) );
117117
return ( i32 & uint32_t{ 1 } << 22 ) != 0 ? QuietNaN : SignalingNaN;
118-
} else if constexpr( std::is_same_v<T, float16> ) {
119-
uint16_t i16;
120-
memcpy( &i16, &val, sizeof( i16 ) );
121-
return ( i16 & uint16_t{ 1 } << 9 ) != 0 ? QuietNaN : SignalingNaN;
122118
} else {
123119
uint64_t i64;
124120
memcpy( &i64, &val, sizeof( i64 ) );
@@ -447,87 +443,6 @@ bool fnmadd( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
447443
return true;
448444
}
449445

450-
// Square root
451-
template<typename T>
452-
static bool fsqrt( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
453-
R->SetFP( Inst.rd, std::sqrt( R->GetFP<T>( Inst.rs1 ) ) );
454-
R->AdvancePC( Inst );
455-
return true;
456-
}
457-
458-
// Transfer sign bit
459-
template<typename T>
460-
static bool fsgnj( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
461-
R->SetFP( Inst.rd, std::copysign( R->GetFP<T>( Inst.rs1 ), R->GetFP<T>( Inst.rs2 ) ) );
462-
R->AdvancePC( Inst );
463-
return true;
464-
}
465-
466-
// Negated transfer sign bit
467-
template<typename T>
468-
static bool fsgnjn( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
469-
R->SetFP( Inst.rd, std::copysign( R->GetFP<T>( Inst.rs1 ), negate( R->GetFP<T>( Inst.rs2 ) ) ) );
470-
R->AdvancePC( Inst );
471-
return true;
472-
}
473-
474-
// Xor transfer sign bit
475-
template<typename T>
476-
static bool fsgnjx( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
477-
T rs1 = R->GetFP<T>( Inst.rs1 ), rs2 = R->GetFP<T>( Inst.rs2 );
478-
R->SetFP( Inst.rd, std::copysign( rs1, std::signbit( rs1 ) ? negate( rs2 ) : rs2 ) );
479-
R->AdvancePC( Inst );
480-
return true;
481-
}
482-
483-
// Move floating-point register to integer register
484-
template<typename T>
485-
static bool fmvif( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
486-
std::make_signed_t<uint_type_t<T>> i;
487-
T fp = R->GetFP<T, true>( Inst.rs1 ); // The FP value
488-
static_assert( sizeof( i ) == sizeof( fp ) );
489-
memcpy( &i, &fp, sizeof( i ) ); // Reinterpreted as int
490-
R->SetX( Inst.rd, i ); // Copied to the destination register
491-
R->AdvancePC( Inst );
492-
return true;
493-
}
494-
495-
// Move integer register to floating-point register
496-
template<typename T>
497-
static bool fmvfi( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
498-
T fp;
499-
auto i = R->GetX<uint_type_t<T>>( Inst.rs1 ); // The X register
500-
static_assert( sizeof( i ) == sizeof( fp ) );
501-
memcpy( &fp, &i, sizeof( fp ) ); // Reinterpreted as FP
502-
R->SetFP( Inst.rd, fp ); // Copied to the destination register
503-
R->AdvancePC( Inst );
504-
return true;
505-
}
506-
507-
// Floating-point classify
508-
template<typename T>
509-
static bool fclassify( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
510-
R->SetX( Inst.rd, fclass( R->GetFP<T>( Inst.rs1 ) ) );
511-
R->AdvancePC( Inst );
512-
return true;
513-
}
514-
515-
// Convert integer to floating point
516-
template<typename FP, typename INT>
517-
static bool fcvtfi( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
518-
R->SetFP( Inst.rd, static_cast<FP>( R->GetX<INT>( Inst.rs1 ) ) );
519-
R->AdvancePC( Inst );
520-
return true;
521-
}
522-
523-
// Convert floating point to floating point
524-
template<typename FP2, typename FP1>
525-
static bool fcvtff( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
526-
R->SetFP( Inst.rd, static_cast<FP2>( R->GetFP<FP1>( Inst.rs1 ) ) );
527-
R->AdvancePC( Inst );
528-
return true;
529-
}
530-
531446
} // namespace SST::RevCPU
532447

533448
#endif

include/RevRegFile.h

+27-69
Original file line numberDiff line numberDiff line change
@@ -31,66 +31,13 @@ namespace SST::RevCPU {
3131

3232
struct RevInst;
3333

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-
}
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 ) );
9441
}
9542

9643
/// RISC-V Register Mneumonics
@@ -356,23 +303,34 @@ class RevRegFile {
356303
template<typename T, bool FMV_FS = false, typename U>
357304
T GetFP( U rs ) const {
358305
if constexpr( std::is_same_v<T, double> ) {
359-
return DPF[size_t( rs )];
360-
} else if( HasD ) {
361-
return UnBoxNaN<T, FMV_FS>( &DPF[size_t( rs )] );
306+
return DPF[size_t( rs )]; // The FP64 register's value
362307
} else {
363-
return UnBoxNaN<T, FMV_FS>( &SPF[size_t( rs )] );
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
364322
}
365323
}
366324

367325
/// SetFP: Set a specific FP register to a floating-point value
368326
template<typename T, typename U>
369327
void SetFP( U rd, T value ) {
370328
if constexpr( std::is_same_v<T, double> ) {
371-
DPF[size_t( rd )] = value;
329+
DPF[size_t( rd )] = value; // Store in FP64 register
372330
} else if( HasD ) {
373-
BoxNaN( &DPF[size_t( rd )], &value );
331+
BoxNaN( &DPF[size_t( rd )], &value ); // Store NaN-boxed float in FP64 register
374332
} else {
375-
BoxNaN( &SPF[size_t( rd )], &value );
333+
SPF[size_t( rd )] = value; // Store in FP32 register
376334
}
377335
}
378336

@@ -467,8 +425,8 @@ class RevRegFile {
467425
FCSR& GetFCSR() { return fcsr; }
468426

469427
// Friend functions and classes to access internal register state
470-
template<typename INT, typename FP>
471-
friend bool fcvtif( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst );
428+
template<typename FP, typename INT>
429+
friend bool CvtFpToInt( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst );
472430

473431
template<typename T>
474432
friend bool load( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst );

include/insns/RV32D.h

+56-20
Original file line numberDiff line numberDiff line change
@@ -44,33 +44,69 @@ class RV32D : public RevExt {
4444
static constexpr auto& fled = fcondop<double, std::less_equal>;
4545

4646
// FP to Integer Conversion instructions
47-
static constexpr auto& fcvtwd = fcvtif<int32_t, double>;
48-
static constexpr auto& fcvtwud = fcvtif<uint32_t, double>;
47+
static constexpr auto& fcvtwd = CvtFpToInt<double, int32_t>;
48+
static constexpr auto& fcvtwud = CvtFpToInt<double, uint32_t>;
4949

50-
// Square root
51-
static constexpr auto& fsqrtd = fsqrt<double>;
50+
static bool fsqrtd( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
51+
R->SetFP( Inst.rd, std::sqrt( R->GetFP<double>( Inst.rs1 ) ) );
52+
R->AdvancePC( Inst );
53+
return true;
54+
}
5255

53-
// Sign transfer
54-
static constexpr auto& fsgnjd = fsgnj<double>;
55-
static constexpr auto& fsgnjnd = fsgnjn<double>;
56-
static constexpr auto& fsgnjxd = fsgnjx<double>;
56+
static bool fsgnjd( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
57+
R->SetFP( Inst.rd, std::copysign( R->GetFP<double>( Inst.rs1 ), R->GetFP<double>( Inst.rs2 ) ) );
58+
R->AdvancePC( Inst );
59+
return true;
60+
}
5761

58-
// Conversions between single and double precision FP
59-
static constexpr auto& fcvtsd = fcvtff<float, double>;
60-
static constexpr auto& fcvtds = fcvtff<double, float>;
62+
static bool fsgnjnd( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
63+
R->SetFP( Inst.rd, std::copysign( R->GetFP<double>( Inst.rs1 ), -R->GetFP<double>( Inst.rs2 ) ) );
64+
R->AdvancePC( Inst );
65+
return true;
66+
}
6167

62-
// FP Classify
63-
static constexpr auto& fclassd = fclassify<double>;
68+
static bool fsgnjxd( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
69+
double rs1 = R->GetFP<double>( Inst.rs1 ), rs2 = R->GetFP<double>( Inst.rs2 );
70+
R->SetFP( Inst.rd, std::copysign( rs1, std::signbit( rs1 ) ? -rs2 : rs2 ) );
71+
R->AdvancePC( Inst );
72+
return true;
73+
}
6474

65-
// Conversion from integer to double
66-
static constexpr auto& fcvtdw = fcvtfi<double, int32_t>;
67-
static constexpr auto& fcvtdwu = fcvtfi<double, uint32_t>;
75+
static bool fcvtsd( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
76+
R->SetFP( Inst.rd, static_cast<float>( R->GetFP<double>( Inst.rs1 ) ) );
77+
R->AdvancePC( Inst );
78+
return true;
79+
}
80+
81+
static bool fcvtds( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
82+
R->SetFP( Inst.rd, static_cast<double>( R->GetFP<float>( Inst.rs1 ) ) );
83+
R->AdvancePC( Inst );
84+
return true;
85+
}
86+
87+
static bool fclassd( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
88+
R->SetX( Inst.rd, fclass( R->GetFP<double>( Inst.rs1 ) ) );
89+
R->AdvancePC( Inst );
90+
return true;
91+
}
92+
93+
static bool fcvtdw( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
94+
R->SetFP( Inst.rd, static_cast<double>( R->GetX<int32_t>( Inst.rs1 ) ) );
95+
R->AdvancePC( Inst );
96+
return true;
97+
}
98+
99+
static bool fcvtdwu( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
100+
R->SetFP( Inst.rd, static_cast<double>( R->GetX<uint32_t>( Inst.rs1 ) ) );
101+
R->AdvancePC( Inst );
102+
return true;
103+
}
68104

69105
// Compressed instructions
70-
static constexpr auto& cfldsp = fld;
71-
static constexpr auto& cfsdsp = fsd;
72-
static constexpr auto& cfld = fld;
73-
static constexpr auto& cfsd = fsd;
106+
static constexpr auto& cfldsp = fld;
107+
static constexpr auto& cfsdsp = fsd;
108+
static constexpr auto& cfld = fld;
109+
static constexpr auto& cfsd = fsd;
74110

75111
// ----------------------------------------------------------------------
76112
//

0 commit comments

Comments
 (0)