diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index 1988aa632cf35b..cc7b0939e45d2b 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -7451,6 +7451,18 @@ void CodeGen::genIntToFloatCast(GenTree* treeNode) noway_assert(srcType != TYP_UINT); noway_assert((srcType != TYP_ULONG) || (dstType != TYP_FLOAT)); + if (compiler->compOpportunisticallyDependsOn(InstructionSet_AVX512F)) + { + if (srcType == TYP_ULONG && (dstType == TYP_DOUBLE || dstType == TYP_FLOAT)) + { + genConsumeOperands(treeNode->AsOp()); + instruction ins = ins_FloatConv(dstType, srcType, emitTypeSize(srcType)); + GetEmitter()->emitInsBinary(ins, emitTypeSize(srcType), treeNode, op1); + genProduceReg(treeNode); + return; + } + } + // To convert int to a float/double, cvtsi2ss/sd SSE2 instruction is used // which does a partial write to lower 4/8 bytes of xmm register keeping the other // upper bytes unmodified. If "cvtsi2ss/sd xmmReg, r32/r64" occurs inside a loop, @@ -7562,8 +7574,10 @@ void CodeGen::genFloatToIntCast(GenTree* treeNode) noway_assert((dstSize == EA_ATTR(genTypeSize(TYP_INT))) || (dstSize == EA_ATTR(genTypeSize(TYP_LONG)))); // We shouldn't be seeing uint64 here as it should have been converted - // into a helper call by either front-end or lowering phase. - noway_assert(!varTypeIsUnsigned(dstType) || (dstSize != EA_ATTR(genTypeSize(TYP_LONG)))); + // into a helper call by either front-end or lowering phase, unless we have AVX512F + // accelerated conversions. + noway_assert(!varTypeIsUnsigned(dstType) || (dstSize != EA_ATTR(genTypeSize(TYP_LONG))) || + compiler->compOpportunisticallyDependsOn(InstructionSet_AVX512F)); // If the dstType is TYP_UINT, we have 32-bits to encode the // float number. Any of 33rd or above bits can be the sign bit. @@ -7576,7 +7590,7 @@ void CodeGen::genFloatToIntCast(GenTree* treeNode) // Note that we need to specify dstType here so that it will determine // the size of destination integer register and also the rex.w prefix. genConsumeOperands(treeNode->AsOp()); - instruction ins = ins_FloatConv(TYP_INT, srcType, emitTypeSize(srcType)); + instruction ins = ins_FloatConv(dstType, srcType, emitTypeSize(srcType)); GetEmitter()->emitInsBinary(ins, emitTypeSize(dstType), treeNode, op1); genProduceReg(treeNode); } diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h index 1d49eb69070061..ef401b7d115a2b 100644 --- a/src/coreclr/jit/emit.h +++ b/src/coreclr/jit/emit.h @@ -3857,6 +3857,15 @@ emitAttr emitter::emitGetMemOpSize(instrDesc* id) const return EA_32BYTE; } + case INS_vcvttss2usi64: + { + if (defaultSize == 8) + { + return EA_4BYTE; + } + return defaultSize; + } + case INS_movddup: { if (defaultSize == 64) diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 83cdb1c6fe72b7..c79e2993f25a8e 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -1294,7 +1294,6 @@ bool emitter::TakesRexWPrefix(const instrDesc* id) const case INS_vcvtsd2usi: case INS_vcvtss2usi: case INS_vcvttsd2usi: - case INS_vcvttss2usi: { if (attr == EA_8BYTE) { @@ -2518,7 +2517,8 @@ bool emitter::emitInsCanOnlyWriteSSE2OrAVXReg(instrDesc* id) case INS_vcvtsd2usi: case INS_vcvtss2usi: case INS_vcvttsd2usi: - case INS_vcvttss2usi: + case INS_vcvttss2usi32: + case INS_vcvttss2usi64: { // These SSE instructions write to a general purpose integer register. return false; @@ -11234,12 +11234,18 @@ void emitter::emitDispIns( case INS_vcvtsd2usi: case INS_vcvtss2usi: case INS_vcvttsd2usi: - case INS_vcvttss2usi: { printf(" %s, %s", emitRegName(id->idReg1(), attr), emitRegName(id->idReg2(), EA_16BYTE)); break; } + case INS_vcvttss2usi32: + case INS_vcvttss2usi64: + { + printf(" %s, %s", emitRegName(id->idReg1(), attr), emitRegName(id->idReg2(), EA_4BYTE)); + break; + } + #ifdef TARGET_AMD64 case INS_movsxd: { @@ -18157,23 +18163,40 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins case INS_cvtsi2sd64: case INS_cvtsi2ss64: case INS_vcvtsd2usi: - case INS_vcvttsd2usi: case INS_vcvtusi2sd32: - case INS_vcvtusi2sd64: case INS_vcvtusi2ss32: case INS_vcvtusi2ss64: result.insThroughput = PERFSCORE_THROUGHPUT_1C; result.insLatency += PERFSCORE_LATENCY_7C; break; + case INS_vcvttsd2usi: + result.insLatency += PERFSCORE_LATENCY_6C; + result.insThroughput = PERFSCORE_THROUGHPUT_1C; + break; + + case INS_vcvtusi2sd64: + result.insThroughput = PERFSCORE_THROUGHPUT_1C; + result.insLatency += PERFSCORE_LATENCY_5C; + break; + case INS_cvttss2si: case INS_cvtss2si: case INS_vcvtss2usi: - case INS_vcvttss2usi: result.insThroughput = PERFSCORE_THROUGHPUT_1C; result.insLatency += opSize == EA_8BYTE ? PERFSCORE_LATENCY_8C : PERFSCORE_LATENCY_7C; break; + case INS_vcvttss2usi32: + result.insThroughput = PERFSCORE_THROUGHPUT_1C; + result.insLatency += PERFSCORE_LATENCY_7C; + break; + + case INS_vcvttss2usi64: + result.insThroughput = PERFSCORE_THROUGHPUT_1C; + result.insLatency += PERFSCORE_LATENCY_8C; + break; + case INS_cvtss2sd: result.insThroughput = PERFSCORE_THROUGHPUT_1C; result.insLatency += PERFSCORE_LATENCY_5C; diff --git a/src/coreclr/jit/hwintrinsiclistxarch.h b/src/coreclr/jit/hwintrinsiclistxarch.h index 0c677837b8cf26..afbd92cfa534ac 100644 --- a/src/coreclr/jit/hwintrinsiclistxarch.h +++ b/src/coreclr/jit/hwintrinsiclistxarch.h @@ -836,7 +836,7 @@ HARDWARE_INTRINSIC(AVX512F, Ceiling, HARDWARE_INTRINSIC(AVX512F, ConvertScalarToVector128Double, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvtusi2sd32, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromSecondArg|HW_Flag_CopyUpperBits) HARDWARE_INTRINSIC(AVX512F, ConvertScalarToVector128Single, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvtusi2ss32, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromSecondArg|HW_Flag_CopyUpperBits) HARDWARE_INTRINSIC(AVX512F, ConvertToUInt32, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvtss2usi, INS_vcvtsd2usi}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(AVX512F, ConvertToUInt32WithTruncation, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvttss2usi, INS_vcvttsd2usi}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AVX512F, ConvertToUInt32WithTruncation, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvttss2usi32, INS_vcvttsd2usi}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(AVX512F, ConvertToVector128Byte, 64, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpmovdb, INS_vpmovdb, INS_vpmovqb, INS_vpmovqb, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(AVX512F, ConvertToVector128ByteWithSaturation, 64, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpmovusdb, INS_invalid, INS_vpmovusqb, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(AVX512F, ConvertToVector128Int16, 64, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpmovqw, INS_vpmovqw, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen) @@ -948,7 +948,7 @@ HARDWARE_INTRINSIC(AVX512F_VL, ShiftRightArithmeticVariable, HARDWARE_INTRINSIC(AVX512F_X64, ConvertScalarToVector128Double, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvtusi2sd64, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromSecondArg|HW_Flag_CopyUpperBits|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(AVX512F_X64, ConvertScalarToVector128Single, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvtusi2ss64, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromSecondArg|HW_Flag_CopyUpperBits|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(AVX512F_X64, ConvertToUInt64, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvtss2usi, INS_vcvtsd2usi}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(AVX512F_X64, ConvertToUInt64WithTruncation, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvttss2usi, INS_vcvttsd2usi}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AVX512F_X64, ConvertToUInt64WithTruncation, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vcvttss2usi64, INS_vcvttsd2usi}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // ISA Function name SIMD size NumArg Instructions Category Flags diff --git a/src/coreclr/jit/instr.cpp b/src/coreclr/jit/instr.cpp index b942ddd6d878d9..19fa2049dc9752 100644 --- a/src/coreclr/jit/instr.cpp +++ b/src/coreclr/jit/instr.cpp @@ -2165,6 +2165,9 @@ instruction CodeGen::ins_MathOp(genTreeOps oper, var_types type) instruction CodeGen::ins_FloatConv(var_types to, var_types from, emitAttr attr) { // AVX: For now we support only conversion from Int/Long -> float + // AVX512: Supports following conversions + // srcType = float/double castToType = ulong + // srcType = ulong castToType = double switch (from) { @@ -2213,6 +2216,8 @@ instruction CodeGen::ins_FloatConv(var_types to, var_types from, emitAttr attr) return ins_Move_Extend(TYP_FLOAT, false); case TYP_DOUBLE: return INS_cvtss2sd; + case TYP_ULONG: + return INS_vcvttss2usi64; default: unreached(); } @@ -2225,6 +2230,8 @@ instruction CodeGen::ins_FloatConv(var_types to, var_types from, emitAttr attr) return INS_cvttsd2si; case TYP_LONG: return INS_cvttsd2si; + case TYP_ULONG: + return INS_vcvttsd2usi; case TYP_FLOAT: return INS_cvtsd2ss; case TYP_DOUBLE: @@ -2234,6 +2241,15 @@ instruction CodeGen::ins_FloatConv(var_types to, var_types from, emitAttr attr) } break; + case TYP_ULONG: + switch (to) + { + case TYP_DOUBLE: + return INS_vcvtusi2sd64; + default: + unreached(); + } + default: unreached(); } diff --git a/src/coreclr/jit/instrsxarch.h b/src/coreclr/jit/instrsxarch.h index 589df2cd7bdeb6..17b8ac164d4056 100644 --- a/src/coreclr/jit/instrsxarch.h +++ b/src/coreclr/jit/instrsxarch.h @@ -626,7 +626,8 @@ INST3(vcvtss2usi, "cvtss2usi", IUM_WR, BAD_CODE, BAD_ INST3(vcvttpd2udq, "cvttpd2udq", IUM_WR, BAD_CODE, BAD_CODE, PCKFLT(0x78), INS_TT_FULL, Input_64Bit | REX_W1 | Encoding_EVEX) // cvt w/ truncation packed doubles to unsigned DWORDs INST3(vcvttps2udq, "cvttps2udq", IUM_WR, BAD_CODE, BAD_CODE, PCKFLT(0x78), INS_TT_FULL, Input_32Bit | REX_W0 | Encoding_EVEX) // cvt w/ truncation packed singles to unsigned DWORDs INST3(vcvttsd2usi, "cvttsd2usi", IUM_WR, BAD_CODE, BAD_CODE, SSEDBL(0x78), INS_TT_TUPLE1_FIXED, Input_64Bit | REX_WX | Encoding_EVEX) // cvt w/ truncation scalar double to unsigned DWORD/QWORD -INST3(vcvttss2usi, "cvttss2usi", IUM_WR, BAD_CODE, BAD_CODE, SSEFLT(0x78), INS_TT_TUPLE1_FIXED, Input_32Bit | REX_WX | Encoding_EVEX) // cvt w/ truncation scalar single to unsigned DWORD/QWORD +INST3(vcvttss2usi32, "cvttss2usi", IUM_WR, BAD_CODE, BAD_CODE, SSEFLT(0x78), INS_TT_TUPLE1_FIXED, Input_32Bit | REX_W0 | Encoding_EVEX) // cvt w/ truncation scalar single to unsigned DWORD/QWORD +INST3(vcvttss2usi64, "cvttss2usi", IUM_WR, BAD_CODE, BAD_CODE, SSEFLT(0x78), INS_TT_TUPLE1_FIXED, Input_32Bit | REX_W1 | Encoding_EVEX) // cvt w/ truncation scalar single to unsigned DWORD/QWORD INST3(vcvtudq2pd, "cvtudq2pd", IUM_WR, BAD_CODE, BAD_CODE, SSEFLT(0x7A), INS_TT_HALF, Input_32Bit | REX_W0 | Encoding_EVEX) // cvt packed unsigned DWORDs to doubles INST3(vcvtudq2ps, "cvtudq2ps", IUM_WR, BAD_CODE, BAD_CODE, SSEDBL(0x7A), INS_TT_FULL, Input_32Bit | REX_W0 | Encoding_EVEX) // cvt packed unsigned DWORDs to singles INST3(vcvtusi2sd32, "cvtusi2sd", IUM_WR, BAD_CODE, BAD_CODE, SSEDBL(0x7B), INS_TT_TUPLE1_SCALAR, Input_32Bit | REX_W0 | Encoding_EVEX | INS_Flags_IsDstDstSrcAVXInstruction) // cvt scalar unsigned DWORD to double diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index d780773abba69a..fa522dad83bb9d 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -795,15 +795,15 @@ void Lowering::LowerCast(GenTree* tree) // srcType = float/double castToType = * and overflow detecting cast // Reason: must be converted to a helper call // srcType = float/double, castToType = ulong - // Reason: must be converted to a helper call + // Reason: must be converted to a helper call unless we have AVX512F // srcType = uint castToType = float/double // Reason: uint -> float/double = uint -> long -> float/double // srcType = ulong castToType = float // Reason: ulong -> float = ulong -> double -> float - if (varTypeIsFloating(srcType)) + if (srcType == TYP_FLOAT) { - noway_assert(!tree->gtOverflow()); - noway_assert(castToType != TYP_ULONG); + noway_assert(!tree->gtOverflow() || comp->compOpportunisticallyDependsOn(InstructionSet_AVX512F)); + noway_assert(castToType != TYP_ULONG || comp->compOpportunisticallyDependsOn(InstructionSet_AVX512F)); } else if (srcType == TYP_UINT) { diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index a583c739816904..3d9653f72e71f1 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -358,6 +358,10 @@ GenTree* Compiler::fgMorphExpandCast(GenTreeCast* tree) #endif // !TARGET_AMD64 case TYP_ULONG: +#ifdef TARGET_AMD64 + if (compOpportunisticallyDependsOn(InstructionSet_AVX512F)) + return nullptr; +#endif return fgMorphCastIntoHelper(tree, CORINFO_HELP_DBL2ULNG, oper); default: unreached(); diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 084281763c0107..1a4f247d8ce698 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -572,6 +572,30 @@ FORCEINLINE INT64 FastDbl2Lng(double val) #endif } +/*********************************************************************/ +// helper function to truncate double numbers to nearest integer (round towards zero) +double TrucateDouble(double val) +{ + FCALL_CONTRACT; + int64_t *dintVal = (int64_t *)&val; + + uint64_t uintVal = (uint64_t)*dintVal; + int exponent = (int)((uintVal >> 52) & 0x7FF); + if (exponent < 1023) + { + uintVal = uintVal & 0x8000000000000000ull; + } + else if (exponent < 1075) + { + uintVal = uintVal & (unsigned long long)(~(0xFFFFFFFFFFFFF >> (exponent - 1023))); + } + int64_t intVal = (int64_t)uintVal; + double *doubleVal = (double *)&intVal; + double retVal = *doubleVal; + + return retVal; +} + /*********************************************************************/ HCIMPL1_V(UINT32, JIT_Dbl2UIntOvf, double val) { @@ -589,7 +613,14 @@ HCIMPLEND HCIMPL1_V(UINT64, JIT_Dbl2ULng, double val) { FCALL_CONTRACT; +#if defined(TARGET_X86) || defined(TARGET_AMD64) + const double uint64_max_plus_1 = -2.0 * (double)INT64_MIN; + val = TrucateDouble(val); + //return ((val != val) || ((val < 0) && (val + 1 < 0)) || (val >= uint64_max_plus_1)) ? UINT64_MAX : ((val < 0) && (val + 1 > 0)) ? 0 : (UINT64)val; + return ((val != val) || (val < 0) || (val >= uint64_max_plus_1)) ? UINT64_MAX : (UINT64)val; + +#else const double two63 = 2147483648.0 * 4294967296.0; UINT64 ret; if (val < two63) { @@ -600,6 +631,7 @@ HCIMPL1_V(UINT64, JIT_Dbl2ULng, double val) ret = FastDbl2Lng(val - two63) + I64(0x8000000000000000); } return ret; +#endif } HCIMPLEND diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs index 523ad54c060472..b0143ad159711f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Double.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs @@ -1400,7 +1400,7 @@ private static bool TryConvertTo(double value, [MaybeNullWhen(false)] ou { #if TARGET_64BIT nuint actualResult = (value >= ulong.MaxValue) ? unchecked((nuint)ulong.MaxValue) : - (value <= ulong.MinValue) ? unchecked((nuint)ulong.MinValue) : (nuint)value; + (value <= ulong.MinValue || IsNaN(value)) ? unchecked((nuint)ulong.MinValue) : (nuint)value; result = (TOther)(object)actualResult; return true; #else diff --git a/src/libraries/System.Private.CoreLib/src/System/Half.cs b/src/libraries/System.Private.CoreLib/src/System/Half.cs index b462c88b6e3908..54d2437f39722c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Half.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Half.cs @@ -1883,7 +1883,7 @@ private static bool TryConvertTo(Half value, [MaybeNullWhen(false)] out else if (typeof(TOther) == typeof(nuint)) { nuint actualResult = (value == PositiveInfinity) ? nuint.MaxValue : - (value <= Zero) ? nuint.MinValue : (nuint)value; + (value <= Zero || IsNaN(value)) ? nuint.MinValue : (nuint)value; result = (TOther)(object)actualResult; return true; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs index 7987c7eb89f159..12a0809373b144 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs @@ -1754,7 +1754,7 @@ private static bool TryConvertTo(NFloat value, [MaybeNullWhen(false)] ou return true; #else nuint actualResult = (value >= ulong.MaxValue) ? unchecked((nuint)ulong.MaxValue) : - (value <= ulong.MinValue) ? unchecked((nuint)ulong.MinValue) : (nuint)value; + (value <= ulong.MinValue || IsNaN(value)) ? unchecked((nuint)ulong.MinValue) : (nuint)value; result = (TOther)(object)actualResult; return true; #endif diff --git a/src/libraries/System.Private.CoreLib/src/System/Single.cs b/src/libraries/System.Private.CoreLib/src/System/Single.cs index 188534808e3a73..8f89dc39dadcb4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Single.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Single.cs @@ -1380,7 +1380,7 @@ private static bool TryConvertTo(float value, [MaybeNullWhen(false)] out { #if TARGET_64BIT nuint actualResult = (value >= ulong.MaxValue) ? unchecked((nuint)ulong.MaxValue) : - (value <= ulong.MinValue) ? unchecked((nuint)ulong.MinValue) : (nuint)value; + (value <= ulong.MinValue || IsNaN(value)) ? unchecked((nuint)ulong.MinValue) : (nuint)value; result = (TOther)(object)actualResult; return true; #else diff --git a/src/libraries/System.Runtime/tests/System/UIntPtrTests.GenericMath.cs b/src/libraries/System.Runtime/tests/System/UIntPtrTests.GenericMath.cs index 2e752a91af21f4..414788a4c47420 100644 --- a/src/libraries/System.Runtime/tests/System/UIntPtrTests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System/UIntPtrTests.GenericMath.cs @@ -12,6 +12,7 @@ public class UIntPtrTests_GenericMath // // IAdditionOperators // + public static Architecture arch = RuntimeInformation.ProcessArchitecture; [Fact] public static void op_AdditionTest() diff --git a/src/tests/JIT/Directed/Convert/out_of_range_fp_to_int_conversions.cpp b/src/tests/JIT/Directed/Convert/out_of_range_fp_to_int_conversions.cpp index eaf7f2fa1a9daa..3890fcac11a3dd 100644 --- a/src/tests/JIT/Directed/Convert/out_of_range_fp_to_int_conversions.cpp +++ b/src/tests/JIT/Directed/Convert/out_of_range_fp_to_int_conversions.cpp @@ -137,6 +137,7 @@ extern "C" DLLEXPORT uint64_t ConvertDoubleToUInt64(double x, FPtoIntegerConver return ((x != x) || (x < INT64_MIN) || (x >= uint64_max_plus_1)) ? (uint64_t)INT64_MIN : (x < 0) ? (uint64_t)(int64_t)x : (uint64_t)x; case CONVERT_SENTINEL: + case CONVERT_MANAGED_BACKWARD_COMPATIBLE_X86_X64: return ((x != x) || (x < 0) || (x >= uint64_max_plus_1)) ? UINT64_MAX : (uint64_t)x; case CONVERT_SATURATING: @@ -153,18 +154,8 @@ extern "C" DLLEXPORT uint64_t ConvertDoubleToUInt64(double x, FPtoIntegerConver return (uint64_t)ConvertDoubleToInt64(x - int64_max_plus_1, CONVERT_MANAGED_BACKWARD_COMPATIBLE_ARM32) + (0x8000000000000000); } } - - case CONVERT_MANAGED_BACKWARD_COMPATIBLE_X86_X64: - if (x < int64_max_plus_1) - { - return (x < INT64_MIN) ? (uint64_t)INT64_MIN : (uint64_t)(int64_t)x; - } - else - { - x -= int64_max_plus_1; - x = trunc(x); - return (uint64_t)(((x != x) || (x >= int64_max_plus_1)) ? INT64_MIN : (int64_t)x) + (0x8000000000000000); - } + + case CONVERT_NATIVECOMPILERBEHAVIOR: // handled above, but add case to silence warning return 0; } diff --git a/src/tests/JIT/Directed/Convert/out_of_range_fp_to_int_conversions.cs b/src/tests/JIT/Directed/Convert/out_of_range_fp_to_int_conversions.cs index 5b78783c09e4ca..e2be91c974fec3 100644 --- a/src/tests/JIT/Directed/Convert/out_of_range_fp_to_int_conversions.cs +++ b/src/tests/JIT/Directed/Convert/out_of_range_fp_to_int_conversions.cs @@ -183,6 +183,7 @@ public static ulong ConvertDoubleToUInt64(double x, FPtoIntegerConversionType t) return (Double.IsNaN(x) || (x < long.MinValue) || (x >= ullong_max_plus_1)) ? unchecked((ulong)long.MinValue): (x < 0) ? (ulong)(long)x: (ulong)x; case FPtoIntegerConversionType.CONVERT_SENTINEL: + case FPtoIntegerConversionType.CONVERT_MANAGED_BACKWARD_COMPATIBLE_X86_X64: return (Double.IsNaN(x) || (x < 0) || (x >= ullong_max_plus_1)) ? ulong.MaxValue : (ulong)x; case FPtoIntegerConversionType.CONVERT_SATURATING: @@ -199,21 +200,7 @@ public static ulong ConvertDoubleToUInt64(double x, FPtoIntegerConversionType t) return (ulong)ConvertDoubleToInt64(x - two63, FPtoIntegerConversionType.CONVERT_MANAGED_BACKWARD_COMPATIBLE_ARM32) + (0x8000000000000000); } } - - case FPtoIntegerConversionType.CONVERT_MANAGED_BACKWARD_COMPATIBLE_X86_X64: - - if (x < two63) - { - return (x < long.MinValue) ? unchecked((ulong)long.MinValue) : (ulong)(long)x; - } - else - { - // (double)LLONG_MAX cannot be represented exactly as double - const double llong_max_plus_1 = (double)((ulong)long.MaxValue + 1); - x -= two63; - x = Math.Truncate(x); - return (ulong)((Double.IsNaN(x) || (x >= llong_max_plus_1)) ? long.MinValue : (long)x) + (0x8000000000000000); - } + } return 0;