From 0d5d5a9e7bfb93526aae9570d4da782b97991ab8 Mon Sep 17 00:00:00 2001 From: Dong-Heon Jung Date: Thu, 6 Jul 2023 17:22:31 +0900 Subject: [PATCH 1/4] [RISC-V][JIT] Fix canonical NaN issue --- src/coreclr/jit/assertionprop.cpp | 36 +++++++++++++++++++--- src/coreclr/jit/emit.cpp | 10 ++++++- src/coreclr/jit/importercalls.cpp | 50 +++++++++++++++++++++++++++---- src/coreclr/jit/valuenum.cpp | 12 +++++++- 4 files changed, 96 insertions(+), 12 deletions(-) diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index a3b6c3c8bc7e87..de6178e1366f5b 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -1200,8 +1200,18 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1, } else { - noway_assert(op2->gtOper == GT_CNS_DBL); /* If we have an NaN value then don't record it */ + noway_assert(op2->gtOper == GT_CNS_DBL); +#ifdef TARGET_RISCV64 + if (op2->TypeGet() == TYP_FLOAT) + { + double f64Cns = op2->AsDblCon()->DconValue(); + if (_isnan(*reinterpret_cast(&f64Cns))) + { + goto DONE_ASSERTION; + } + } +#endif // TARGET_RISCV64 if (_isnan(op2->AsDblCon()->DconValue())) { goto DONE_ASSERTION; // Don't make an assertion @@ -2587,7 +2597,16 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* tree) { // Implicit conversion to float or double assert(varTypeIsFloating(tree->TypeGet())); - conValTree = gtNewDconNode(value, tree->TypeGet()); +#ifdef TARGET_RISCV64 + if (tree->TypeGet() == TYP_FLOAT && _isnan(*reinterpret_cast(&value))) + { + conValTree = gtNewDconNode(*reinterpret_cast(&value), tree->TypeGet()); + } + else +#endif // TARGET_RISCV64 + { + conValTree = gtNewDconNode(value, tree->TypeGet()); + } } break; } @@ -2696,8 +2715,17 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* tree) break; case TYP_FLOAT: - // Same sized reinterpretation of bits to float - conValTree = gtNewDconNode(*reinterpret_cast(&value), TYP_FLOAT); +#ifdef TARGET_RISCV64 + if (_isnan(*reinterpret_cast(&value))) + { + conValTree = gtNewDconNode(*reinterpret_cast(&value), TYP_FLOAT); + } + else +#endif // TARGET_RISCV64 + { + // Same sized reinterpretation of bits to float + conValTree = gtNewDconNode(*reinterpret_cast(&value), TYP_FLOAT); + } break; case TYP_DOUBLE: diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index 7e3c6501399c68..2941516d048ab3 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -8050,7 +8050,15 @@ CORINFO_FIELD_HANDLE emitter::emitFltOrDblConst(double constValue, emitAttr attr if (attr == EA_4BYTE) { - f = forceCastToFloat(constValue); +#ifdef TARGET_RISCV64 + f = *reinterpret_cast(&constValue); + if (!FloatingPointUtils::isNaN(f)) + { + f = forceCastToFloat(constValue); + } +#else + f = forceCastToFloat(constValue); +#endif // TARGET_RISCV64 cnsAddr = &f; dataType = TYP_FLOAT; } diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 7a304b11469eda..9df243d1a9994d 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -1556,7 +1556,7 @@ GenTree* Compiler::impFixupCallStructReturn(GenTreeCall* call, CORINFO_CLASS_HAN const ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); const unsigned retRegCount = retTypeDesc->GetReturnRegCount(); #else // !FEATURE_MULTIREG_RET - const unsigned retRegCount = 1; + const unsigned retRegCount = 1; #endif // !FEATURE_MULTIREG_RET structPassingKind howToReturnStruct; @@ -3794,7 +3794,17 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, if (op1->IsIntegralConst()) { int32_t i32Cns = (int32_t)op1->AsIntConCommon()->IconValue(); - retNode = gtNewDconNode(*reinterpret_cast(&i32Cns), TYP_FLOAT); +#ifdef TARGET_RISCV64 + float f32Cns = *reinterpret_cast(&i32Cns); + if (FloatingPointUtils::isNaN(f32Cns)) + { + retNode = gtNewDconNode(*reinterpret_cast(&i32Cns), TYP_FLOAT); + } + else +#endif // TARGET_RISCV64 + { + retNode = gtNewDconNode(*reinterpret_cast(&i32Cns), TYP_FLOAT); + } } else { @@ -3834,8 +3844,17 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, if (op1->IsCnsFltOrDbl()) { - float f32Cns = (float)op1->AsDblCon()->DconValue(); - retNode = gtNewIconNode(*reinterpret_cast(&f32Cns)); +#ifdef TARGET_RISCV64 + double f64Cns = op1->AsDblCon()->DconValue(); + float f32Cns = *reinterpret_cast(&f64Cns); + if (!FloatingPointUtils::isNaN(f32Cns)) + { + f32Cns = (float)op1->AsDblCon()->DconValue(); + } +#else + float f32Cns = (float)op1->AsDblCon()->DconValue(); +#endif // TARGET_RISCV64 + retNode = gtNewIconNode(*reinterpret_cast(&f32Cns)); } else { @@ -4141,7 +4160,16 @@ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic, else { assert(fromType == TYP_FLOAT); - float f32Cns = static_cast(op1->AsDblCon()->DconValue()); +#ifdef TARGET_RISCV64 + double f64Cns = op1->AsDblCon()->DconValue(); + float f32Cns = *reinterpret_cast(&f64Cns); + if (!FloatingPointUtils::isNaN(f32Cns)) + { + f32Cns = static_cast(op1->AsDblCon()->DconValue()); + } +#else + float f32Cns = static_cast(op1->AsDblCon()->DconValue()); +#endif // TARGET_RISCV64 return gtNewIconNode(static_cast(BitOperations::SingleToUInt32Bits(f32Cns))); } } @@ -4181,7 +4209,17 @@ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic, assert(toType == TYP_FLOAT); uint32_t u32Cns = static_cast(op1->AsIntConCommon()->IconValue()); - return gtNewDconNode(BitOperations::UInt32BitsToSingle(u32Cns), TYP_FLOAT); +#ifdef TARGET_RISCV64 + float f32Cns = BitOperations::UInt32BitsToSingle(u32Cns); + if (FloatingPointUtils::isNaN(f32Cns)) + { + return gtNewDconNode(*reinterpret_cast(&f32Cns), TYP_FLOAT); + } + else +#endif // TARGET_RISCV64 + { + return gtNewDconNode(BitOperations::UInt32BitsToSingle(u32Cns), TYP_FLOAT); + } } } else diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 0cb86cbd04e756..0f6a4642953109 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -10345,7 +10345,17 @@ void Compiler::fgValueNumberTreeConst(GenTree* tree) case TYP_FLOAT: { - tree->gtVNPair.SetBoth(vnStore->VNForFloatCon((float)tree->AsDblCon()->DconValue())); +#ifdef TARGET_RISCV64 + double f64Cns = tree->AsDblCon()->DconValue(); + float f32Cns = *reinterpret_cast(&f64Cns); + if (!_isnan(f32Cns)) + { + f32Cns = (float)f64Cns; + } +#else + float f32Cns = (float)tree->AsDblCon()->DconValue(); +#endif // TARGET_RISCV64 + tree->gtVNPair.SetBoth(vnStore->VNForFloatCon(f32Cns)); break; } From 3904786d29693437969fe87e37cd6adbefdae908 Mon Sep 17 00:00:00 2001 From: Dong-Heon Jung Date: Fri, 7 Jul 2023 18:21:40 +0900 Subject: [PATCH 2/4] [RISC-V][JIT] Update to use helpers --- src/coreclr/jit/assertionprop.cpp | 23 +++++--------- src/coreclr/jit/emit.cpp | 10 +----- src/coreclr/jit/importercalls.cpp | 52 +++++-------------------------- src/coreclr/jit/utils.cpp | 23 ++++++++++++++ src/coreclr/jit/utils.h | 4 +++ src/coreclr/jit/valuenum.cpp | 11 +------ 6 files changed, 45 insertions(+), 78 deletions(-) diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index de6178e1366f5b..6e1e672cbad740 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -1205,8 +1205,7 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1, #ifdef TARGET_RISCV64 if (op2->TypeGet() == TYP_FLOAT) { - double f64Cns = op2->AsDblCon()->DconValue(); - if (_isnan(*reinterpret_cast(&f64Cns))) + if (_isnan(FloatingPointUtils::convertDoubleToFloat(op2->AsDblCon()->DconValue()))) { goto DONE_ASSERTION; } @@ -2597,10 +2596,11 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* tree) { // Implicit conversion to float or double assert(varTypeIsFloating(tree->TypeGet())); + #ifdef TARGET_RISCV64 - if (tree->TypeGet() == TYP_FLOAT && _isnan(*reinterpret_cast(&value))) + if (tree->TypeGet() == TYP_FLOAT) { - conValTree = gtNewDconNode(*reinterpret_cast(&value), tree->TypeGet()); + conValTree = gtNewDconNode(FloatingPointUtils::convertFloatToDouble(value), tree->TypeGet()); } else #endif // TARGET_RISCV64 @@ -2715,17 +2715,10 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* tree) break; case TYP_FLOAT: -#ifdef TARGET_RISCV64 - if (_isnan(*reinterpret_cast(&value))) - { - conValTree = gtNewDconNode(*reinterpret_cast(&value), TYP_FLOAT); - } - else -#endif // TARGET_RISCV64 - { - // Same sized reinterpretation of bits to float - conValTree = gtNewDconNode(*reinterpret_cast(&value), TYP_FLOAT); - } + // Same sized reinterpretation of bits to float + conValTree = + gtNewDconNode(FloatingPointUtils::convertFloatToDouble(*reinterpret_cast(&value)), + TYP_FLOAT); break; case TYP_DOUBLE: diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index 2941516d048ab3..459f819e47b86a 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -8050,15 +8050,7 @@ CORINFO_FIELD_HANDLE emitter::emitFltOrDblConst(double constValue, emitAttr attr if (attr == EA_4BYTE) { -#ifdef TARGET_RISCV64 - f = *reinterpret_cast(&constValue); - if (!FloatingPointUtils::isNaN(f)) - { - f = forceCastToFloat(constValue); - } -#else - f = forceCastToFloat(constValue); -#endif // TARGET_RISCV64 + f = FloatingPointUtils::convertDoubleToFloat(constValue); cnsAddr = &f; dataType = TYP_FLOAT; } diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 9df243d1a9994d..798858b9d735ed 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -1556,7 +1556,7 @@ GenTree* Compiler::impFixupCallStructReturn(GenTreeCall* call, CORINFO_CLASS_HAN const ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); const unsigned retRegCount = retTypeDesc->GetReturnRegCount(); #else // !FEATURE_MULTIREG_RET - const unsigned retRegCount = 1; + const unsigned retRegCount = 1; #endif // !FEATURE_MULTIREG_RET structPassingKind howToReturnStruct; @@ -3794,17 +3794,8 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, if (op1->IsIntegralConst()) { int32_t i32Cns = (int32_t)op1->AsIntConCommon()->IconValue(); -#ifdef TARGET_RISCV64 - float f32Cns = *reinterpret_cast(&i32Cns); - if (FloatingPointUtils::isNaN(f32Cns)) - { - retNode = gtNewDconNode(*reinterpret_cast(&i32Cns), TYP_FLOAT); - } - else -#endif // TARGET_RISCV64 - { - retNode = gtNewDconNode(*reinterpret_cast(&i32Cns), TYP_FLOAT); - } + float f32Cns = *reinterpret_cast(&i32Cns); + retNode = gtNewDconNode(FloatingPointUtils::convertFloatToDouble(f32Cns), TYP_FLOAT); } else { @@ -3844,17 +3835,8 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, if (op1->IsCnsFltOrDbl()) { -#ifdef TARGET_RISCV64 - double f64Cns = op1->AsDblCon()->DconValue(); - float f32Cns = *reinterpret_cast(&f64Cns); - if (!FloatingPointUtils::isNaN(f32Cns)) - { - f32Cns = (float)op1->AsDblCon()->DconValue(); - } -#else - float f32Cns = (float)op1->AsDblCon()->DconValue(); -#endif // TARGET_RISCV64 - retNode = gtNewIconNode(*reinterpret_cast(&f32Cns)); + float f32Cns = FloatingPointUtils::convertDoubleToFloat(op1->AsDblCon()->DconValue()); + retNode = gtNewIconNode(*reinterpret_cast(&f32Cns)); } else { @@ -4160,16 +4142,7 @@ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic, else { assert(fromType == TYP_FLOAT); -#ifdef TARGET_RISCV64 - double f64Cns = op1->AsDblCon()->DconValue(); - float f32Cns = *reinterpret_cast(&f64Cns); - if (!FloatingPointUtils::isNaN(f32Cns)) - { - f32Cns = static_cast(op1->AsDblCon()->DconValue()); - } -#else - float f32Cns = static_cast(op1->AsDblCon()->DconValue()); -#endif // TARGET_RISCV64 + float f32Cns = FloatingPointUtils::convertDoubleToFloat(op1->AsDblCon()->DconValue()); return gtNewIconNode(static_cast(BitOperations::SingleToUInt32Bits(f32Cns))); } } @@ -4209,17 +4182,8 @@ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic, assert(toType == TYP_FLOAT); uint32_t u32Cns = static_cast(op1->AsIntConCommon()->IconValue()); -#ifdef TARGET_RISCV64 - float f32Cns = BitOperations::UInt32BitsToSingle(u32Cns); - if (FloatingPointUtils::isNaN(f32Cns)) - { - return gtNewDconNode(*reinterpret_cast(&f32Cns), TYP_FLOAT); - } - else -#endif // TARGET_RISCV64 - { - return gtNewDconNode(BitOperations::UInt32BitsToSingle(u32Cns), TYP_FLOAT); - } + float f32Cns = BitOperations::UInt32BitsToSingle(u32Cns); + return gtNewDconNode(FloatingPointUtils::convertFloatToDouble(f32Cns), TYP_FLOAT); } } else diff --git a/src/coreclr/jit/utils.cpp b/src/coreclr/jit/utils.cpp index 93a8292e07ab94..5a43874214c1f1 100644 --- a/src/coreclr/jit/utils.cpp +++ b/src/coreclr/jit/utils.cpp @@ -2051,6 +2051,29 @@ unsigned __int64 FloatingPointUtils::convertDoubleToUInt64(double d) return u64; } +double FloatingPointUtils::convertFloatToDouble(float f32) +{ +#ifdef TARGET_RISCV64 + if (FloatingPointUtils::isNaN(f32)) + { + return *reinterpret_cast(&f32); + } +#endif // TARGET_RISCV64 + return (double)f32; +} + +float FloatingPointUtils::convertDoubleToFloat(double f64) +{ +#ifdef TARGET_RISCV64 + float f32 = *reinterpret_cast(&f64); + if (FloatingPointUtils::isNaN(f32)) + { + return f32; + } +#endif // TARGET_RISCV64 + return forceCastToFloat(f64); +} + // Rounds a double-precision floating-point value to the nearest integer, // and rounds midpoint values to the nearest even number. double FloatingPointUtils::round(double x) diff --git a/src/coreclr/jit/utils.h b/src/coreclr/jit/utils.h index 5cf3501143273b..3df97c1d971a84 100644 --- a/src/coreclr/jit/utils.h +++ b/src/coreclr/jit/utils.h @@ -729,6 +729,10 @@ class FloatingPointUtils static unsigned __int64 convertDoubleToUInt64(double d); + static double convertFloatToDouble(float f32); + + static float convertDoubleToFloat(double f64); + static double round(double x); static float round(float x); diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 0f6a4642953109..2023a213d0d678 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -10345,16 +10345,7 @@ void Compiler::fgValueNumberTreeConst(GenTree* tree) case TYP_FLOAT: { -#ifdef TARGET_RISCV64 - double f64Cns = tree->AsDblCon()->DconValue(); - float f32Cns = *reinterpret_cast(&f64Cns); - if (!_isnan(f32Cns)) - { - f32Cns = (float)f64Cns; - } -#else - float f32Cns = (float)tree->AsDblCon()->DconValue(); -#endif // TARGET_RISCV64 + float f32Cns = FloatingPointUtils::convertDoubleToFloat(tree->AsDblCon()->DconValue()); tree->gtVNPair.SetBoth(vnStore->VNForFloatCon(f32Cns)); break; } From d267584d031e0b7c8d4dfc06b14267163761a487 Mon Sep 17 00:00:00 2001 From: Dong-Heon Jung Date: Thu, 20 Jul 2023 13:37:02 +0900 Subject: [PATCH 3/4] [RISC-V][JIT] Update conversion functions --- src/coreclr/jit/assertionprop.cpp | 25 ++---------- src/coreclr/jit/emit.cpp | 2 +- src/coreclr/jit/importercalls.cpp | 8 ++-- src/coreclr/jit/utils.cpp | 67 +++++++++++++++++++++++++------ src/coreclr/jit/utils.h | 4 +- src/coreclr/jit/valuenum.cpp | 2 +- 6 files changed, 65 insertions(+), 43 deletions(-) diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index 6e1e672cbad740..736f323506ac0e 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -1200,17 +1200,8 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1, } else { - /* If we have an NaN value then don't record it */ noway_assert(op2->gtOper == GT_CNS_DBL); -#ifdef TARGET_RISCV64 - if (op2->TypeGet() == TYP_FLOAT) - { - if (_isnan(FloatingPointUtils::convertDoubleToFloat(op2->AsDblCon()->DconValue()))) - { - goto DONE_ASSERTION; - } - } -#endif // TARGET_RISCV64 + /* If we have an NaN value then don't record it */ if (_isnan(op2->AsDblCon()->DconValue())) { goto DONE_ASSERTION; // Don't make an assertion @@ -2596,17 +2587,7 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* tree) { // Implicit conversion to float or double assert(varTypeIsFloating(tree->TypeGet())); - -#ifdef TARGET_RISCV64 - if (tree->TypeGet() == TYP_FLOAT) - { - conValTree = gtNewDconNode(FloatingPointUtils::convertFloatToDouble(value), tree->TypeGet()); - } - else -#endif // TARGET_RISCV64 - { - conValTree = gtNewDconNode(value, tree->TypeGet()); - } + conValTree = gtNewDconNode(FloatingPointUtils::convertToDouble(value), tree->TypeGet()); } break; } @@ -2717,7 +2698,7 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* tree) case TYP_FLOAT: // Same sized reinterpretation of bits to float conValTree = - gtNewDconNode(FloatingPointUtils::convertFloatToDouble(*reinterpret_cast(&value)), + gtNewDconNode(FloatingPointUtils::convertToDouble(*reinterpret_cast(&value)), TYP_FLOAT); break; diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index 459f819e47b86a..f93a8248e1f67c 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -8050,7 +8050,7 @@ CORINFO_FIELD_HANDLE emitter::emitFltOrDblConst(double constValue, emitAttr attr if (attr == EA_4BYTE) { - f = FloatingPointUtils::convertDoubleToFloat(constValue); + f = FloatingPointUtils::convertToSingle(constValue); cnsAddr = &f; dataType = TYP_FLOAT; } diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 798858b9d735ed..fe4370b206b3d1 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -3795,7 +3795,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, { int32_t i32Cns = (int32_t)op1->AsIntConCommon()->IconValue(); float f32Cns = *reinterpret_cast(&i32Cns); - retNode = gtNewDconNode(FloatingPointUtils::convertFloatToDouble(f32Cns), TYP_FLOAT); + retNode = gtNewDconNode(FloatingPointUtils::convertToDouble(f32Cns), TYP_FLOAT); } else { @@ -3835,7 +3835,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, if (op1->IsCnsFltOrDbl()) { - float f32Cns = FloatingPointUtils::convertDoubleToFloat(op1->AsDblCon()->DconValue()); + float f32Cns = FloatingPointUtils::convertToSingle(op1->AsDblCon()->DconValue()); retNode = gtNewIconNode(*reinterpret_cast(&f32Cns)); } else @@ -4142,7 +4142,7 @@ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic, else { assert(fromType == TYP_FLOAT); - float f32Cns = FloatingPointUtils::convertDoubleToFloat(op1->AsDblCon()->DconValue()); + float f32Cns = FloatingPointUtils::convertToSingle(op1->AsDblCon()->DconValue()); return gtNewIconNode(static_cast(BitOperations::SingleToUInt32Bits(f32Cns))); } } @@ -4183,7 +4183,7 @@ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic, uint32_t u32Cns = static_cast(op1->AsIntConCommon()->IconValue()); float f32Cns = BitOperations::UInt32BitsToSingle(u32Cns); - return gtNewDconNode(FloatingPointUtils::convertFloatToDouble(f32Cns), TYP_FLOAT); + return gtNewDconNode(FloatingPointUtils::convertToDouble(f32Cns), TYP_FLOAT); } } else diff --git a/src/coreclr/jit/utils.cpp b/src/coreclr/jit/utils.cpp index 5a43874214c1f1..df5b9710aea6b5 100644 --- a/src/coreclr/jit/utils.cpp +++ b/src/coreclr/jit/utils.cpp @@ -2051,27 +2051,68 @@ unsigned __int64 FloatingPointUtils::convertDoubleToUInt64(double d) return u64; } -double FloatingPointUtils::convertFloatToDouble(float f32) +//------------------------------------------------------------------------ +// convertToDouble: Convert a single to a double with platform independent +// preservation of payload bits. +// +// Arguments: +// f - the single +// +// Return Value: +// A double. +// +// Remarks: +// All our host platforms except for RISCV-64 will preserve payload bits of +// NaNs. This function implements the conversion in software for RISCV-64 to +// mimic other platforms. +// +double FloatingPointUtils::convertToDouble(float f) { -#ifdef TARGET_RISCV64 - if (FloatingPointUtils::isNaN(f32)) +#ifdef HOST_RISCV64 + if (f == f) { - return *reinterpret_cast(&f32); + return f; } -#endif // TARGET_RISCV64 - return (double)f32; + + uint32_t bits = BitOperations::SingleToUInt32Bits(f); + uint32_t payload = bits & ((1u << 23) - 1); + uint64_t newBits = ((uint64_t)(bits >> 31) << 63) | 0x7FF8000000000000ul | ((uint64_t)payload << 29); + return BitOperations::UInt64BitsToDouble(newBits); +#else + return f; +#endif } -float FloatingPointUtils::convertDoubleToFloat(double f64) +//------------------------------------------------------------------------ +// convertToSingle: Convert a double to a single with platform independent +// preservation of payload bits. +// +// Arguments: +// d - the double +// +// Return Value: +// A float. +// +// Remarks: +// All our host platforms except for RISCV-64 will preserve payload bits of +// NaNs. This function implements the conversion in software for RISCV-64 to +// mimic other platforms. +// +float FloatingPointUtils::convertToSingle(double d) { -#ifdef TARGET_RISCV64 - float f32 = *reinterpret_cast(&f64); - if (FloatingPointUtils::isNaN(f32)) +#ifdef HOST_RISCV64 + if (d == d) { - return f32; + return (float)d; } -#endif // TARGET_RISCV64 - return forceCastToFloat(f64); + + uint64_t bits = BitOperations::DoubleToUInt64Bits(d); + uint32_t newPayload = (uint32_t)((bits >> 29) & ((1u << 23) - 1)); + uint32_t newBits = ((uint32_t)(bits >> 63) << 31) | 0x7F800000u | newPayload; + return BitOperations::UInt32BitsToSingle(newBits); +#else + return (float)d; +#endif } // Rounds a double-precision floating-point value to the nearest integer, diff --git a/src/coreclr/jit/utils.h b/src/coreclr/jit/utils.h index 3df97c1d971a84..77f74ba95cb31d 100644 --- a/src/coreclr/jit/utils.h +++ b/src/coreclr/jit/utils.h @@ -729,9 +729,9 @@ class FloatingPointUtils static unsigned __int64 convertDoubleToUInt64(double d); - static double convertFloatToDouble(float f32); + static double convertToDouble(float f); - static float convertDoubleToFloat(double f64); + static float convertToSingle(double d); static double round(double x); diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 2023a213d0d678..d49476802f9822 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -10345,7 +10345,7 @@ void Compiler::fgValueNumberTreeConst(GenTree* tree) case TYP_FLOAT: { - float f32Cns = FloatingPointUtils::convertDoubleToFloat(tree->AsDblCon()->DconValue()); + float f32Cns = FloatingPointUtils::convertToSingle(tree->AsDblCon()->DconValue()); tree->gtVNPair.SetBoth(vnStore->VNForFloatCon(f32Cns)); break; } From e46699a9787c8507eb99ee39985cbb75ccaa2f5d Mon Sep 17 00:00:00 2001 From: Dong-Heon Jung Date: Thu, 20 Jul 2023 18:37:49 +0900 Subject: [PATCH 4/4] [RISC-V][JIT] Update --- src/coreclr/jit/assertionprop.cpp | 6 +++--- src/coreclr/jit/importercalls.cpp | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index 736f323506ac0e..2eed68d04f6d10 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -2697,9 +2697,9 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* tree) case TYP_FLOAT: // Same sized reinterpretation of bits to float - conValTree = - gtNewDconNode(FloatingPointUtils::convertToDouble(*reinterpret_cast(&value)), - TYP_FLOAT); + conValTree = gtNewDconNode(FloatingPointUtils::convertToDouble( + BitOperations::UInt32BitsToSingle((uint32_t)value)), + TYP_FLOAT); break; case TYP_DOUBLE: diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index fe4370b206b3d1..33c6a447a44ab7 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -3793,9 +3793,8 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, if (op1->IsIntegralConst()) { - int32_t i32Cns = (int32_t)op1->AsIntConCommon()->IconValue(); - float f32Cns = *reinterpret_cast(&i32Cns); - retNode = gtNewDconNode(FloatingPointUtils::convertToDouble(f32Cns), TYP_FLOAT); + float f32Cns = BitOperations::UInt32BitsToSingle((uint32_t)op1->AsIntConCommon()->IconValue()); + retNode = gtNewDconNode(FloatingPointUtils::convertToDouble(f32Cns), TYP_FLOAT); } else { @@ -3836,7 +3835,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, if (op1->IsCnsFltOrDbl()) { float f32Cns = FloatingPointUtils::convertToSingle(op1->AsDblCon()->DconValue()); - retNode = gtNewIconNode(*reinterpret_cast(&f32Cns)); + retNode = gtNewIconNode((int32_t)BitOperations::SingleToUInt32Bits(f32Cns)); } else {