diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index a3b6c3c8bc7e87..2eed68d04f6d10 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -2587,7 +2587,7 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* tree) { // Implicit conversion to float or double assert(varTypeIsFloating(tree->TypeGet())); - conValTree = gtNewDconNode(value, tree->TypeGet()); + conValTree = gtNewDconNode(FloatingPointUtils::convertToDouble(value), tree->TypeGet()); } break; } @@ -2697,7 +2697,9 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* tree) case TYP_FLOAT: // Same sized reinterpretation of bits to float - conValTree = gtNewDconNode(*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/emit.cpp b/src/coreclr/jit/emit.cpp index 7e3c6501399c68..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 = forceCastToFloat(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 7a304b11469eda..33c6a447a44ab7 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -3793,8 +3793,8 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, if (op1->IsIntegralConst()) { - int32_t i32Cns = (int32_t)op1->AsIntConCommon()->IconValue(); - retNode = gtNewDconNode(*reinterpret_cast(&i32Cns), TYP_FLOAT); + float f32Cns = BitOperations::UInt32BitsToSingle((uint32_t)op1->AsIntConCommon()->IconValue()); + retNode = gtNewDconNode(FloatingPointUtils::convertToDouble(f32Cns), TYP_FLOAT); } else { @@ -3834,8 +3834,8 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, if (op1->IsCnsFltOrDbl()) { - float f32Cns = (float)op1->AsDblCon()->DconValue(); - retNode = gtNewIconNode(*reinterpret_cast(&f32Cns)); + float f32Cns = FloatingPointUtils::convertToSingle(op1->AsDblCon()->DconValue()); + retNode = gtNewIconNode((int32_t)BitOperations::SingleToUInt32Bits(f32Cns)); } else { @@ -4141,7 +4141,7 @@ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic, else { assert(fromType == TYP_FLOAT); - float f32Cns = static_cast(op1->AsDblCon()->DconValue()); + float f32Cns = FloatingPointUtils::convertToSingle(op1->AsDblCon()->DconValue()); return gtNewIconNode(static_cast(BitOperations::SingleToUInt32Bits(f32Cns))); } } @@ -4181,7 +4181,8 @@ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic, assert(toType == TYP_FLOAT); uint32_t u32Cns = static_cast(op1->AsIntConCommon()->IconValue()); - return gtNewDconNode(BitOperations::UInt32BitsToSingle(u32Cns), TYP_FLOAT); + float f32Cns = BitOperations::UInt32BitsToSingle(u32Cns); + return gtNewDconNode(FloatingPointUtils::convertToDouble(f32Cns), TYP_FLOAT); } } else diff --git a/src/coreclr/jit/utils.cpp b/src/coreclr/jit/utils.cpp index 93a8292e07ab94..df5b9710aea6b5 100644 --- a/src/coreclr/jit/utils.cpp +++ b/src/coreclr/jit/utils.cpp @@ -2051,6 +2051,70 @@ unsigned __int64 FloatingPointUtils::convertDoubleToUInt64(double d) return u64; } +//------------------------------------------------------------------------ +// 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 HOST_RISCV64 + if (f == f) + { + return f; + } + + 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 +} + +//------------------------------------------------------------------------ +// 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 HOST_RISCV64 + if (d == d) + { + return (float)d; + } + + 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, // 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..77f74ba95cb31d 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 convertToDouble(float f); + + static float convertToSingle(double d); + 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 0cb86cbd04e756..d49476802f9822 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -10345,7 +10345,8 @@ void Compiler::fgValueNumberTreeConst(GenTree* tree) case TYP_FLOAT: { - tree->gtVNPair.SetBoth(vnStore->VNForFloatCon((float)tree->AsDblCon()->DconValue())); + float f32Cns = FloatingPointUtils::convertToSingle(tree->AsDblCon()->DconValue()); + tree->gtVNPair.SetBoth(vnStore->VNForFloatCon(f32Cns)); break; }