From 5968f8dc46adda2fd9228f81c53302a4dcbc592a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Fri, 23 Feb 2024 16:21:06 +0100 Subject: [PATCH 01/29] Rewrite math jit helpers to managed code --- src/coreclr/inc/corinfo.h | 10 +- src/coreclr/inc/jithelpers.h | 34 +- src/coreclr/jit/morph.cpp | 4 +- src/coreclr/jit/utils.cpp | 4 - src/coreclr/jit/valuenum.cpp | 12 - src/coreclr/nativeaot/Runtime/MathHelpers.cpp | 86 +--- .../Runtime/CompilerHelpers/MathHelpers.cs | 245 +--------- .../Common/TypeSystem/IL/HelperExtensions.cs | 8 + .../ILCompiler.Compiler/Compiler/JitHelper.cs | 62 ++- .../IL/ILImporter.Scanner.cs | 48 +- src/coreclr/vm/appdomain.cpp | 2 +- src/coreclr/vm/corelib.h | 23 +- src/coreclr/vm/ecall.cpp | 58 ++- src/coreclr/vm/ecall.h | 2 +- src/coreclr/vm/i386/jithelp.S | 81 ---- src/coreclr/vm/i386/jithelp.asm | 212 --------- src/coreclr/vm/i386/jitinterfacex86.cpp | 45 -- src/coreclr/vm/jithelpers.cpp | 429 ++---------------- src/coreclr/vm/jitinterface.cpp | 15 +- src/coreclr/vm/jitinterface.h | 11 - .../System.Private.CoreLib/src/System/Math.cs | 240 ++++++++++ .../src/System/MathF.cs | 23 + 22 files changed, 520 insertions(+), 1134 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 111c6488df073..aaade1919d1ed 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -387,18 +387,18 @@ enum CorInfoHelpFunc CORINFO_HELP_ULMOD, CORINFO_HELP_LNG2DBL, // Convert a signed int64 to a double CORINFO_HELP_ULNG2DBL, // Convert a unsigned int64 to a double - CORINFO_HELP_DBL2INT, + CORINFO_HELP_DBL2INT, // unused CORINFO_HELP_DBL2INT_OVF, CORINFO_HELP_DBL2LNG, CORINFO_HELP_DBL2LNG_OVF, - CORINFO_HELP_DBL2UINT, + CORINFO_HELP_DBL2UINT, // unused CORINFO_HELP_DBL2UINT_OVF, CORINFO_HELP_DBL2ULNG, CORINFO_HELP_DBL2ULNG_OVF, CORINFO_HELP_FLTREM, CORINFO_HELP_DBLREM, - CORINFO_HELP_FLTROUND, - CORINFO_HELP_DBLROUND, + CORINFO_HELP_FLTROUND, // unused + CORINFO_HELP_DBLROUND, // unused /* Allocating a new object. Always use ICorClassInfo::getNewHelper() to decide which is the right helper to use to allocate an object of a given type. */ @@ -2058,7 +2058,7 @@ class ICorStaticInfo // Example of a scenario addressed by notifyMethodInfoUsage: // 1) Crossgen (with --opt-cross-module=MyLib) attempts to inline a call from MyLib.dll into MyApp.dll // and realizes that the call always throws. - // 2) JIT aborts the inlining attempt and marks the call as no-return instead. The code that follows the call is + // 2) JIT aborts the inlining attempt and marks the call as no-return instead. The code that follows the call is // replaced with a breakpoint instruction that is expected to be unreachable. // 3) MyLib is updated to a new version so it's no longer within the same version bubble with MyApp.dll // and the new version of the call no longer throws and does some work. diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index 65167abd6a4dd..13df743419c0b 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -35,8 +35,6 @@ JITHELPER(CORINFO_HELP_UDIV, JIT_UDiv, CORINFO_HELP_SIG_8_STACK) JITHELPER(CORINFO_HELP_UMOD, JIT_UMod, CORINFO_HELP_SIG_8_STACK) - // CORINFO_HELP_DBL2INT, CORINFO_HELP_DBL2UINT, and CORINFO_HELP_DBL2LONG get - // patched for CPUs that support SSE2 (P4 and above). #ifndef TARGET_64BIT JITHELPER(CORINFO_HELP_LLSH, JIT_LLsh, CORINFO_HELP_SIG_REG_ONLY) JITHELPER(CORINFO_HELP_LRSH, JIT_LRsh, CORINFO_HELP_SIG_REG_ONLY) @@ -47,26 +45,26 @@ JITHELPER(CORINFO_HELP_LRSZ, NULL, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB) #endif // TARGET_64BIT JITHELPER(CORINFO_HELP_LMUL, JIT_LMul, CORINFO_HELP_SIG_16_STACK) - JITHELPER(CORINFO_HELP_LMUL_OVF, JIT_LMulOvf, CORINFO_HELP_SIG_16_STACK) - JITHELPER(CORINFO_HELP_ULMUL_OVF, JIT_ULMulOvf, CORINFO_HELP_SIG_16_STACK) + DYNAMICJITHELPER(CORINFO_HELP_LMUL_OVF, NULL, CORINFO_HELP_SIG_16_STACK) + DYNAMICJITHELPER(CORINFO_HELP_ULMUL_OVF, NULL, CORINFO_HELP_SIG_16_STACK) JITHELPER(CORINFO_HELP_LDIV, JIT_LDiv, CORINFO_HELP_SIG_16_STACK) JITHELPER(CORINFO_HELP_LMOD, JIT_LMod, CORINFO_HELP_SIG_16_STACK) JITHELPER(CORINFO_HELP_ULDIV, JIT_ULDiv, CORINFO_HELP_SIG_16_STACK) JITHELPER(CORINFO_HELP_ULMOD, JIT_ULMod, CORINFO_HELP_SIG_16_STACK) JITHELPER(CORINFO_HELP_LNG2DBL, JIT_Lng2Dbl, CORINFO_HELP_SIG_8_STACK) - JITHELPER(CORINFO_HELP_ULNG2DBL, JIT_ULng2Dbl, CORINFO_HELP_SIG_8_STACK) - DYNAMICJITHELPER(CORINFO_HELP_DBL2INT, JIT_Dbl2Lng, CORINFO_HELP_SIG_8_STACK) - JITHELPER(CORINFO_HELP_DBL2INT_OVF, JIT_Dbl2IntOvf, CORINFO_HELP_SIG_8_STACK) - DYNAMICJITHELPER(CORINFO_HELP_DBL2LNG, JIT_Dbl2Lng, CORINFO_HELP_SIG_8_STACK) - JITHELPER(CORINFO_HELP_DBL2LNG_OVF, JIT_Dbl2LngOvf, CORINFO_HELP_SIG_8_STACK) - DYNAMICJITHELPER(CORINFO_HELP_DBL2UINT, JIT_Dbl2Lng, CORINFO_HELP_SIG_8_STACK) - JITHELPER(CORINFO_HELP_DBL2UINT_OVF, JIT_Dbl2UIntOvf, CORINFO_HELP_SIG_8_STACK) - JITHELPER(CORINFO_HELP_DBL2ULNG, JIT_Dbl2ULng, CORINFO_HELP_SIG_8_STACK) - JITHELPER(CORINFO_HELP_DBL2ULNG_OVF, JIT_Dbl2ULngOvf, CORINFO_HELP_SIG_8_STACK) - JITHELPER(CORINFO_HELP_FLTREM, JIT_FltRem, CORINFO_HELP_SIG_8_STACK) - JITHELPER(CORINFO_HELP_DBLREM, JIT_DblRem, CORINFO_HELP_SIG_16_STACK) - JITHELPER(CORINFO_HELP_FLTROUND, JIT_FloatRound, CORINFO_HELP_SIG_8_STACK) - JITHELPER(CORINFO_HELP_DBLROUND, JIT_DoubleRound, CORINFO_HELP_SIG_16_STACK) + DYNAMICJITHELPER(CORINFO_HELP_ULNG2DBL, NULL, CORINFO_HELP_SIG_8_STACK) + DYNAMICJITHELPER(CORINFO_HELP_DBL2INT, NULL, CORINFO_HELP_SIG_8_STACK) + DYNAMICJITHELPER(CORINFO_HELP_DBL2INT_OVF, NULL, CORINFO_HELP_SIG_8_STACK) + JITHELPER(CORINFO_HELP_DBL2LNG, JIT_Dbl2Lng, CORINFO_HELP_SIG_8_STACK) + DYNAMICJITHELPER(CORINFO_HELP_DBL2LNG_OVF, NULL, CORINFO_HELP_SIG_8_STACK) + DYNAMICJITHELPER(CORINFO_HELP_DBL2UINT, NULL, CORINFO_HELP_SIG_8_STACK) + DYNAMICJITHELPER(CORINFO_HELP_DBL2UINT_OVF, NULL, CORINFO_HELP_SIG_8_STACK) + DYNAMICJITHELPER(CORINFO_HELP_DBL2ULNG, NULL, CORINFO_HELP_SIG_8_STACK) + DYNAMICJITHELPER(CORINFO_HELP_DBL2ULNG_OVF, NULL, CORINFO_HELP_SIG_8_STACK) + DYNAMICJITHELPER(CORINFO_HELP_FLTREM, NULL, CORINFO_HELP_SIG_8_STACK) + DYNAMICJITHELPER(CORINFO_HELP_DBLREM, NULL, CORINFO_HELP_SIG_16_STACK) + DYNAMICJITHELPER(CORINFO_HELP_FLTROUND, NULL, CORINFO_HELP_SIG_8_STACK) + DYNAMICJITHELPER(CORINFO_HELP_DBLROUND, NULL, CORINFO_HELP_SIG_16_STACK) // Allocating a new object JITHELPER(CORINFO_HELP_NEWFAST, JIT_New, CORINFO_HELP_SIG_REG_ONLY) @@ -203,7 +201,7 @@ JITHELPER(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE, JIT_GetSharedNonGCThreadStaticBase, CORINFO_HELP_SIG_REG_ONLY) JITHELPER(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR, JIT_GetSharedGCThreadStaticBase, CORINFO_HELP_SIG_REG_ONLY) JITHELPER(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR, JIT_GetSharedNonGCThreadStaticBase, CORINFO_HELP_SIG_REG_ONLY) - JITHELPER(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS, JIT_GetSharedGCThreadStaticBaseDynamicClass, CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS, JIT_GetSharedGCThreadStaticBaseDynamicClass, CORINFO_HELP_SIG_REG_ONLY) JITHELPER(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS, JIT_GetSharedNonGCThreadStaticBaseDynamicClass, CORINFO_HELP_SIG_REG_ONLY) JITHELPER(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, JIT_GetSharedGCThreadStaticBaseOptimized, CORINFO_HELP_SIG_REG_ONLY) JITHELPER(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, JIT_GetSharedNonGCThreadStaticBaseOptimized, CORINFO_HELP_SIG_REG_ONLY) diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 9758a43b5f17f..25024f9330d99 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -377,7 +377,9 @@ GenTree* Compiler::fgMorphExpandCast(GenTreeCast* tree) #if defined(TARGET_ARM) || defined(TARGET_AMD64) return nullptr; #else // TARGET_X86 - return fgMorphCastIntoHelper(tree, CORINFO_HELP_DBL2UINT, oper); + oper = gtNewCastNode(TYP_LONG, oper, false, TYP_LONG); + tree = gtNewCastNode(TYP_INT, oper, false, TYP_UINT); + return fgMorphTree(tree); #endif // TARGET_X86 case TYP_LONG: diff --git a/src/coreclr/jit/utils.cpp b/src/coreclr/jit/utils.cpp index aed8cda7c24df..5b9e74e91b242 100644 --- a/src/coreclr/jit/utils.cpp +++ b/src/coreclr/jit/utils.cpp @@ -1536,14 +1536,10 @@ void HelperCallProperties::init() case CORINFO_HELP_LMUL: case CORINFO_HELP_LNG2DBL: case CORINFO_HELP_ULNG2DBL: - case CORINFO_HELP_DBL2INT: case CORINFO_HELP_DBL2LNG: - case CORINFO_HELP_DBL2UINT: case CORINFO_HELP_DBL2ULNG: case CORINFO_HELP_FLTREM: case CORINFO_HELP_DBLREM: - case CORINFO_HELP_FLTROUND: - case CORINFO_HELP_DBLROUND: isPure = true; noThrow = true; diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index cf4954762cebd..40ecc8fbf616f 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -12786,11 +12786,6 @@ void Compiler::fgValueNumberCastHelper(GenTreeCall* call) srcIsUnsigned = true; break; - case CORINFO_HELP_DBL2INT: - castToType = TYP_INT; - castFromType = TYP_DOUBLE; - break; - case CORINFO_HELP_DBL2INT_OVF: castToType = TYP_INT; castFromType = TYP_DOUBLE; @@ -12808,11 +12803,6 @@ void Compiler::fgValueNumberCastHelper(GenTreeCall* call) hasOverflowCheck = true; break; - case CORINFO_HELP_DBL2UINT: - castToType = TYP_UINT; - castFromType = TYP_DOUBLE; - break; - case CORINFO_HELP_DBL2UINT_OVF: castToType = TYP_UINT; castFromType = TYP_DOUBLE; @@ -13118,11 +13108,9 @@ bool Compiler::fgValueNumberHelperCall(GenTreeCall* call) { case CORINFO_HELP_LNG2DBL: case CORINFO_HELP_ULNG2DBL: - case CORINFO_HELP_DBL2INT: case CORINFO_HELP_DBL2INT_OVF: case CORINFO_HELP_DBL2LNG: case CORINFO_HELP_DBL2LNG_OVF: - case CORINFO_HELP_DBL2UINT: case CORINFO_HELP_DBL2UINT_OVF: case CORINFO_HELP_DBL2ULNG: case CORINFO_HELP_DBL2ULNG_OVF: diff --git a/src/coreclr/nativeaot/Runtime/MathHelpers.cpp b/src/coreclr/nativeaot/Runtime/MathHelpers.cpp index 1d73305679168..39acda9d5f4f0 100644 --- a/src/coreclr/nativeaot/Runtime/MathHelpers.cpp +++ b/src/coreclr/nativeaot/Runtime/MathHelpers.cpp @@ -5,78 +5,13 @@ #include "CommonMacros.h" #include "rhassert.h" -// -// Floating point and 64-bit integer math helpers. -// - -EXTERN_C NATIVEAOT_API uint64_t REDHAWK_CALLCONV RhpDbl2ULng(double val) -{ - const double two63 = 2147483648.0 * 4294967296.0; - uint64_t ret; - if (val < two63) - { - ret = (int64_t)(val); - } - else - { - // subtract 0x8000000000000000, do the convert then add it back again - ret = (int64_t)(val - two63) + I64(0x8000000000000000); - } - return ret; -} - #undef min #undef max #include -EXTERN_C NATIVEAOT_API float REDHAWK_CALLCONV RhpFltRem(float dividend, float divisor) -{ - // - // From the ECMA standard: - // - // If [divisor] is zero or [dividend] is infinity - // the result is NaN. - // If [divisor] is infinity, - // the result is [dividend] (negated for -infinity***). - // - // ***"negated for -infinity" has been removed from the spec - // - - if (divisor==0 || !std::isfinite(dividend)) - { - return -nanf(""); - } - else if (!std::isfinite(divisor) && !std::isnan(divisor)) - { - return dividend; - } - // else... - return fmodf(dividend,divisor); -} - -EXTERN_C NATIVEAOT_API double REDHAWK_CALLCONV RhpDblRem(double dividend, double divisor) -{ - // - // From the ECMA standard: - // - // If [divisor] is zero or [dividend] is infinity - // the result is NaN. - // If [divisor] is infinity, - // the result is [dividend] (negated for -infinity***). - // - // ***"negated for -infinity" has been removed from the spec - // - if (divisor==0 || !std::isfinite(dividend)) - { - return -nan(""); - } - else if (!std::isfinite(divisor) && !std::isnan(divisor)) - { - return dividend; - } - // else... - return(fmod(dividend,divisor)); -} +// +// Floating point and 64-bit integer math helpers. +// #ifdef HOST_ARM EXTERN_C NATIVEAOT_API int32_t REDHAWK_CALLCONV RhpIDiv(int32_t i, int32_t j) @@ -157,24 +92,9 @@ EXTERN_C NATIVEAOT_API int64_t REDHAWK_CALLCONV RhpDbl2Lng(double val) return (int64_t)val; } -EXTERN_C NATIVEAOT_API int32_t REDHAWK_CALLCONV RhpDbl2Int(double val) -{ - return (int32_t)val; -} - -EXTERN_C NATIVEAOT_API uint32_t REDHAWK_CALLCONV RhpDbl2UInt(double val) -{ - return (uint32_t)val; -} - EXTERN_C NATIVEAOT_API double REDHAWK_CALLCONV RhpLng2Dbl(int64_t val) { return (double)val; } -EXTERN_C NATIVEAOT_API double REDHAWK_CALLCONV RhpULng2Dbl(uint64_t val) -{ - return (double)val; -} - #endif // HOST_ARM diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/MathHelpers.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/MathHelpers.cs index 7175ea9c00cbe..b6930717ab0b7 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/MathHelpers.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/MathHelpers.cs @@ -5,8 +5,6 @@ using System.Runtime; using System.Runtime.CompilerServices; -using Internal.Runtime; - namespace Internal.Runtime.CompilerHelpers { /// @@ -16,136 +14,10 @@ namespace Internal.Runtime.CompilerHelpers internal static class MathHelpers { #if !TARGET_64BIT - // - // 64-bit checked multiplication for 32-bit platforms - // - private const string RuntimeLibrary = "*"; - // Helper to multiply two 32-bit uints - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ulong Mul32x32To64(uint a, uint b) - { - return a * (ulong)b; - } - - // Helper to get high 32-bit of 64-bit int - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Hi32Bits(long a) - { - return (uint)(a >> 32); - } - - // Helper to get high 32-bit of 64-bit int - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Hi32Bits(ulong a) - { - return (uint)(a >> 32); - } - - [RuntimeExport("LMulOvf")] - public static long LMulOvf(long i, long j) - { - long ret; - - // Remember the sign of the result - int sign = (int)(Hi32Bits(i) ^ Hi32Bits(j)); - - // Convert to unsigned multiplication - if (i < 0) i = -i; - if (j < 0) j = -j; - - // Get the upper 32 bits of the numbers - uint val1High = Hi32Bits(i); - uint val2High = Hi32Bits(j); - - ulong valMid; - - if (val1High == 0) - { - // Compute the 'middle' bits of the long multiplication - valMid = Mul32x32To64(val2High, (uint)i); - } - else - { - if (val2High != 0) - goto ThrowExcep; - // Compute the 'middle' bits of the long multiplication - valMid = Mul32x32To64(val1High, (uint)j); - } - - // See if any bits after bit 32 are set - if (Hi32Bits(valMid) != 0) - goto ThrowExcep; - - ret = (long)(Mul32x32To64((uint)i, (uint)j) + (valMid << 32)); - - // check for overflow - if (Hi32Bits(ret) < (uint)valMid) - goto ThrowExcep; - - if (sign >= 0) - { - // have we spilled into the sign bit? - if (ret < 0) - goto ThrowExcep; - } - else - { - ret = -ret; - // have we spilled into the sign bit? - if (ret > 0) - goto ThrowExcep; - } - return ret; - - ThrowExcep: - return ThrowLngOvf(); - } - - [RuntimeExport("ULMulOvf")] - public static ulong ULMulOvf(ulong i, ulong j) - { - ulong ret; - - // Get the upper 32 bits of the numbers - uint val1High = Hi32Bits(i); - uint val2High = Hi32Bits(j); - - ulong valMid; - - if (val1High == 0) - { - if (val2High == 0) - return Mul32x32To64((uint)i, (uint)j); - // Compute the 'middle' bits of the long multiplication - valMid = Mul32x32To64(val2High, (uint)i); - } - else - { - if (val2High != 0) - goto ThrowExcep; - // Compute the 'middle' bits of the long multiplication - valMid = Mul32x32To64(val1High, (uint)j); - } - - // See if any bits after bit 32 are set - if (Hi32Bits(valMid) != 0) - goto ThrowExcep; - - ret = Mul32x32To64((uint)i, (uint)j) + (valMid << 32); - - // check for overflow - if (Hi32Bits(ret) < (uint)valMid) - goto ThrowExcep; - return ret; - - ThrowExcep: - return ThrowULngOvf(); - } - [RuntimeImport(RuntimeLibrary, "RhpULMod")] - [MethodImplAttribute(MethodImplOptions.InternalCall)] + [MethodImpl(MethodImplOptions.InternalCall)] private static extern ulong RhpULMod(ulong i, ulong j); public static ulong ULMod(ulong i, ulong j) @@ -157,7 +29,7 @@ public static ulong ULMod(ulong i, ulong j) } [RuntimeImport(RuntimeLibrary, "RhpLMod")] - [MethodImplAttribute(MethodImplOptions.InternalCall)] + [MethodImpl(MethodImplOptions.InternalCall)] private static extern long RhpLMod(long i, long j); public static long LMod(long i, long j) @@ -171,7 +43,7 @@ public static long LMod(long i, long j) } [RuntimeImport(RuntimeLibrary, "RhpULDiv")] - [MethodImplAttribute(MethodImplOptions.InternalCall)] + [MethodImpl(MethodImplOptions.InternalCall)] private static extern ulong RhpULDiv(ulong i, ulong j); public static ulong ULDiv(ulong i, ulong j) @@ -183,7 +55,7 @@ public static ulong ULDiv(ulong i, ulong j) } [RuntimeImport(RuntimeLibrary, "RhpLDiv")] - [MethodImplAttribute(MethodImplOptions.InternalCall)] + [MethodImpl(MethodImplOptions.InternalCall)] private static extern long RhpLDiv(long i, long j); public static long LDiv(long i, long j) @@ -196,94 +68,9 @@ public static long LDiv(long i, long j) return RhpLDiv(i, j); } - [MethodImpl(MethodImplOptions.NoInlining)] - private static long ThrowLngDivByZero() - { - throw new DivideByZeroException(); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static ulong ThrowULngDivByZero() - { - throw new DivideByZeroException(); - } -#endif // TARGET_64BIT - - [RuntimeExport("Dbl2IntOvf")] - public static int Dbl2IntOvf(double val) - { - const double two31 = 2147483648.0; - - // Note that this expression also works properly for val = NaN case - if (val > -two31 - 1 && val < two31) - return unchecked((int)val); - - return ThrowIntOvf(); - } - - [RuntimeExport("Dbl2UIntOvf")] - public static uint Dbl2UIntOvf(double val) - { - // Note that this expression also works properly for val = NaN case - if (val > -1.0 && val < 4294967296.0) - return unchecked((uint)val); - - return ThrowUIntOvf(); - } - - [RuntimeExport("Dbl2LngOvf")] - public static long Dbl2LngOvf(double val) - { - const double two63 = 2147483648.0 * 4294967296.0; - - // Note that this expression also works properly for val = NaN case - // We need to compare with the very next double to two63. 0x402 is epsilon to get us there. - if (val > -two63 - 0x402 && val < two63) - return unchecked((long)val); - - return ThrowLngOvf(); - } - - [RuntimeExport("Dbl2ULngOvf")] - public static ulong Dbl2ULngOvf(double val) - { - const double two64 = 2.0 * 2147483648.0 * 4294967296.0; - - // Note that this expression also works properly for val = NaN case - if (val > -1.0 && val < two64) - return unchecked((ulong)val); - - return ThrowULngOvf(); - } - - [RuntimeExport("Flt2IntOvf")] - public static int Flt2IntOvf(float val) - { - const double two31 = 2147483648.0; - - // Note that this expression also works properly for val = NaN case - if (val > -two31 - 1 && val < two31) - return ((int)val); - - return ThrowIntOvf(); - } - - [RuntimeExport("Flt2LngOvf")] - public static long Flt2LngOvf(float val) - { - const double two63 = 2147483648.0 * 4294967296.0; - - // Note that this expression also works properly for val = NaN case - // We need to compare with the very next double to two63. 0x402 is epsilon to get us there. - if (val > -two63 - 0x402 && val < two63) - return ((long)val); - - return ThrowIntOvf(); - } - #if TARGET_ARM [RuntimeImport(RuntimeLibrary, "RhpIDiv")] - [MethodImplAttribute(MethodImplOptions.InternalCall)] + [MethodImpl(MethodImplOptions.InternalCall)] private static extern int RhpIDiv(int i, int j); public static int IDiv(int i, int j) @@ -297,7 +84,7 @@ public static int IDiv(int i, int j) } [RuntimeImport(RuntimeLibrary, "RhpUDiv")] - [MethodImplAttribute(MethodImplOptions.InternalCall)] + [MethodImpl(MethodImplOptions.InternalCall)] private static extern uint RhpUDiv(uint i, uint j); public static long UDiv(uint i, uint j) @@ -309,7 +96,7 @@ public static long UDiv(uint i, uint j) } [RuntimeImport(RuntimeLibrary, "RhpIMod")] - [MethodImplAttribute(MethodImplOptions.InternalCall)] + [MethodImpl(MethodImplOptions.InternalCall)] private static extern int RhpIMod(int i, int j); public static int IMod(int i, int j) @@ -323,7 +110,7 @@ public static int IMod(int i, int j) } [RuntimeImport(RuntimeLibrary, "RhpUMod")] - [MethodImplAttribute(MethodImplOptions.InternalCall)] + [MethodImpl(MethodImplOptions.InternalCall)] private static extern uint RhpUMod(uint i, uint j); public static long UMod(uint i, uint j) @@ -339,32 +126,31 @@ public static long UMod(uint i, uint j) // Matching return types of throw helpers enables tailcalling them. It improves performance // of the hot path because of it does not need to raise full stackframe. // - [MethodImpl(MethodImplOptions.NoInlining)] - private static int ThrowIntOvf() + private static long ThrowLngOvf() { throw new OverflowException(); } [MethodImpl(MethodImplOptions.NoInlining)] - private static uint ThrowUIntOvf() + private static long ThrowLngDivByZero() { - throw new OverflowException(); + throw new DivideByZeroException(); } [MethodImpl(MethodImplOptions.NoInlining)] - private static long ThrowLngOvf() + private static ulong ThrowULngDivByZero() { - throw new OverflowException(); + throw new DivideByZeroException(); } +#if TARGET_ARM [MethodImpl(MethodImplOptions.NoInlining)] - private static ulong ThrowULngOvf() + private static int ThrowIntOvf() { throw new OverflowException(); } -#if TARGET_ARM [MethodImpl(MethodImplOptions.NoInlining)] private static int ThrowIntDivByZero() { @@ -377,5 +163,6 @@ private static uint ThrowUIntDivByZero() throw new DivideByZeroException(); } #endif // TARGET_ARM +#endif // TARGET_64BIT } } diff --git a/src/coreclr/tools/Common/TypeSystem/IL/HelperExtensions.cs b/src/coreclr/tools/Common/TypeSystem/IL/HelperExtensions.cs index 4ccaff2d6dd9f..fa24787613574 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/HelperExtensions.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/HelperExtensions.cs @@ -7,6 +7,7 @@ using Internal.IL.Stubs; using Debug = System.Diagnostics.Debug; +using System.Xml.Linq; namespace Internal.IL { @@ -40,6 +41,13 @@ public static MethodDesc GetOptionalHelperEntryPoint(this TypeSystemContext cont return helperMethod; } + public static MethodDesc GetHelperEntryPoint(this TypeSystemContext context, string typeNamespace, string typeName, string methodName) + { + MetadataType helperType = context.SystemModule.GetKnownType(typeNamespace, typeName); + MethodDesc helperMethod = helperType.GetKnownMethod(methodName, null); + return helperMethod; + } + /// /// Emits a call to a throw helper. Use this to emit calls to static parameterless methods that don't return. /// The advantage of using this extension method is that you don't have to deal with what code to emit after diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs index 8bcf658230b08..8b25f36d29caf 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs @@ -158,54 +158,66 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, methodDesc = context.GetHelperEntryPoint("LdTokenHelpers", "GetRuntimeFieldHandle"); break; - case ReadyToRunHelper.Lng2Dbl: - mangledName = "RhpLng2Dbl"; + case ReadyToRunHelper.LMulOfv: + methodDesc = context.GetHelperEntryPoint("System", "Math", "LongMultiplyOverflow"); break; - case ReadyToRunHelper.ULng2Dbl: - mangledName = "RhpULng2Dbl"; + case ReadyToRunHelper.ULMulOvf: + methodDesc = context.GetHelperEntryPoint("System", "Math", "ULongMultiplyOverflow"); break; - case ReadyToRunHelper.Dbl2Lng: - mangledName = "RhpDbl2Lng"; + case ReadyToRunHelper.ULng2Dbl: + methodDesc = context.GetHelperEntryPoint("System", "Math", "ULongToDouble"); break; case ReadyToRunHelper.Dbl2ULng: - mangledName = "RhpDbl2ULng"; - break; - case ReadyToRunHelper.Dbl2Int: - mangledName = "RhpDbl2Int"; - break; - case ReadyToRunHelper.Dbl2UInt: - mangledName = "RhpDbl2UInt"; + methodDesc = context.GetHelperEntryPoint("System", "Math", "DoubleToULong"); break; case ReadyToRunHelper.Dbl2IntOvf: - methodDesc = context.GetHelperEntryPoint("MathHelpers", "Dbl2IntOvf"); + methodDesc = context.GetHelperEntryPoint("System", "Math", "DoubleToIntOverflow"); break; case ReadyToRunHelper.Dbl2UIntOvf: - methodDesc = context.GetHelperEntryPoint("MathHelpers", "Dbl2UIntOvf"); + methodDesc = context.GetHelperEntryPoint("System", "Math", "DoubleToUIntOverflow"); break; case ReadyToRunHelper.Dbl2LngOvf: - methodDesc = context.GetHelperEntryPoint("MathHelpers", "Dbl2LngOvf"); + methodDesc = context.GetHelperEntryPoint("System", "Math", "DoubleToLongOverflow"); break; case ReadyToRunHelper.Dbl2ULngOvf: - methodDesc = context.GetHelperEntryPoint("MathHelpers", "Dbl2ULngOvf"); + methodDesc = context.GetHelperEntryPoint("System", "Math", "DoubleToULongOverflow"); break; case ReadyToRunHelper.DblRem: - mangledName = "RhpDblRem"; + methodDesc = context.GetHelperEntryPoint("System", "Math", "DoubleReminder"); break; case ReadyToRunHelper.FltRem: - mangledName = "RhpFltRem"; + methodDesc = context.GetHelperEntryPoint("System", "MathF", "FloatReminder"); break; - case ReadyToRunHelper.LMul: - mangledName = "RhpLMul"; + case ReadyToRunHelper.Dbl2Int: + methodDesc = context.GetHelperEntryPoint("System", "Math", "DoubleToInt"); break; - case ReadyToRunHelper.LMulOfv: - methodDesc = context.GetHelperEntryPoint("MathHelpers", "LMulOvf"); + case ReadyToRunHelper.Dbl2UInt: + methodDesc = context.GetHelperEntryPoint("System", "MathF", "DoubleToUInt"); break; - case ReadyToRunHelper.ULMulOvf: - methodDesc = context.GetHelperEntryPoint("MathHelpers", "ULMulOvf"); + case ReadyToRunHelper.DblRound: + DefType doubleType = context.GetWellKnownType(WellKnownType.Double); + methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("Round", + new MethodSignature(MethodSignatureFlags.Static, 0, doubleType, [doubleType])); + break; + case ReadyToRunHelper.FltRound: + DefType floatType = context.GetWellKnownType(WellKnownType.Single); + methodDesc = context.SystemModule.GetKnownType("System", "MathF").GetKnownMethod("Round", + new MethodSignature(MethodSignatureFlags.Static, 0, floatType, [floatType])); + break; + + case ReadyToRunHelper.Lng2Dbl: + mangledName = "RhpLng2Dbl"; + break; + case ReadyToRunHelper.Dbl2Lng: + mangledName = "RhpDbl2Lng"; + break; + + case ReadyToRunHelper.LMul: + mangledName = "RhpLMul"; break; case ReadyToRunHelper.Mod: diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs index 7ae867370bdf4..e152de9cb404a 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using Internal.TypeSystem; using Internal.ReadyToRunConstants; @@ -9,6 +10,7 @@ using Debug = System.Diagnostics.Debug; using DependencyList = ILCompiler.DependencyAnalysisFramework.DependencyNodeCore.DependencyList; +using System.Reflection.Emit; #pragma warning disable IDE0060 @@ -1259,6 +1261,51 @@ private void ImportBinaryOperation(ILOpcode opcode) { _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ThrowDivZero), "_divbyzero"); } + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.DblRem), "rem"); + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.FltRem), "rem"); + break; + } + } + + private void ImportConvert(WellKnownType wellKnownType, bool checkOverflow, bool unsigned) + { + switch (wellKnownType) + { + case WellKnownType.SByte: + case WellKnownType.Int16: + case WellKnownType.Int32: + if (checkOverflow) + { + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Dbl2IntOvf), "conv_i4_ovf"); + } + break; + case WellKnownType.Int64: + if (checkOverflow) + { + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Dbl2LngOvf), "conv_i8_ovf"); + } + break; + case WellKnownType.Byte: + case WellKnownType.UInt16: + case WellKnownType.UInt32: + if (checkOverflow) + { + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Dbl2UIntOvf), "conv_u8_ovf"); + } + break; + case WellKnownType.UInt64: + if (checkOverflow) + { + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Dbl2ULngOvf), "conv_u8_ovf"); + } + else + { + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Dbl2ULng), "conv_u8"); + } + break; + case WellKnownType.Single: + case WellKnownType.Double: + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ULng2Dbl), "conv_r"); break; } } @@ -1388,7 +1435,6 @@ private static void ImportStoreIndirect(int token) { } private static void ImportStoreIndirect(TypeDesc type) { } private static void ImportShiftOperation(ILOpcode opcode) { } private static void ImportCompareOperation(ILOpcode opcode) { } - private static void ImportConvert(WellKnownType wellKnownType, bool checkOverflow, bool unsigned) { } private static void ImportUnaryOperation(ILOpcode opCode) { } private static void ImportCpOpj(int token) { } private static void ImportCkFinite() { } diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index feafd1f8abad6..bb5d3d17e0053 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -1352,7 +1352,7 @@ void SystemDomain::LoadBaseSystemClasses() // further loading of nonprimitive types may need casting support. // initialize cast cache here. CastCache::Initialize(); - ECall::PopulateManagedCastHelpers(); + ECall::PopulateManagedHelpers(); // used by IsImplicitInterfaceOfSZArray CoreLibBinder::GetClass(CLASS__IENUMERABLEGENERIC); diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 8e68900686a7e..4960e5b7e6960 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -259,11 +259,28 @@ DEFINE_FIELD(DELEGATE, METHOD_PTR_AUX, _methodPtrAux) DEFINE_METHOD(DELEGATE, CONSTRUCT_DELEGATE, DelegateConstruct, IM_Obj_IntPtr_RetVoid) DEFINE_METHOD(DELEGATE, GET_INVOKE_METHOD, GetInvokeMethod, IM_RetIntPtr) -DEFINE_CLASS(INT128, System, Int128) -DEFINE_CLASS(UINT128, System, UInt128) +DEFINE_CLASS(INT128, System, Int128) +DEFINE_CLASS(UINT128, System, UInt128) + +DEFINE_CLASS(MATH, System, Math) +DEFINE_METHOD(MATH, LONG_MULTIPLY_OVERFLOW, LongMultiplyOverflow, NoSig) +DEFINE_METHOD(MATH, ULONG_MULTIPLY_OVERFLOW,ULongMultiplyOverflow, NoSig) +DEFINE_METHOD(MATH, ULONG_TO_DOUBLE, ULongToDouble, NoSig) +DEFINE_METHOD(MATH, DOUBLE_TO_ULONG, DoubleToULong, NoSig) +DEFINE_METHOD(MATH, DOUBLE_TO_INT_OVERFLOW, DoubleToIntOverflow, NoSig) +DEFINE_METHOD(MATH, DOUBLE_TO_UINT_OVERFLOW,DoubleToUIntOverflow, NoSig) +DEFINE_METHOD(MATH, DOUBLE_TO_LONG_OVERFLOW,DoubleToLongOverflow, NoSig) +DEFINE_METHOD(MATH, DOUBLE_TO_ULONG_OVERFLOW,DoubleToULongOverflow, NoSig) +DEFINE_METHOD(MATH, DOUBLE_REMINDER, DoubleReminder, NoSig) +DEFINE_METHOD(MATH, DOUBLE_TO_INT, DoubleToInt, NoSig) +DEFINE_METHOD(MATH, DOUBLE_TO_UINT, DoubleToUInt, NoSig) +DEFINE_METHOD(MATH, ROUND, Round, SM_Dbl_RetDbl) + +DEFINE_CLASS(MATHF, System, MathF) +DEFINE_METHOD(MATHF, FLOAT_REMINDER, FloatReminder, NoSig) +DEFINE_METHOD(MATHF, ROUND, Round, SM_Flt_RetFlt) DEFINE_CLASS(DYNAMICMETHOD, ReflectionEmit, DynamicMethod) - DEFINE_CLASS(DYNAMICRESOLVER, ReflectionEmit, DynamicResolver) DEFINE_FIELD(DYNAMICRESOLVER, DYNAMIC_METHOD, m_method) diff --git a/src/coreclr/vm/ecall.cpp b/src/coreclr/vm/ecall.cpp index 37ac50d124f6f..47c537e7f7919 100644 --- a/src/coreclr/vm/ecall.cpp +++ b/src/coreclr/vm/ecall.cpp @@ -96,7 +96,7 @@ void ECall::PopulateManagedStringConstructors() INDEBUG(fInitialized = true); } -void ECall::PopulateManagedCastHelpers() +void ECall::PopulateManagedHelpers() { STANDARD_VM_CONTRACT; @@ -144,6 +144,62 @@ void ECall::PopulateManagedCastHelpers() pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__CASTHELPERS__LDELEMAREF)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_LDELEMA_REF, pDest); + + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__LONG_MULTIPLY_OVERFLOW)); + pDest = pMD->GetMultiCallableAddrOfCode(); + SetJitHelperFunction(CORINFO_HELP_LMUL_OVF, pDest); + + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__ULONG_MULTIPLY_OVERFLOW)); + pDest = pMD->GetMultiCallableAddrOfCode(); + SetJitHelperFunction(CORINFO_HELP_ULMUL_OVF, pDest); + + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__ULONG_TO_DOUBLE)); + pDest = pMD->GetMultiCallableAddrOfCode(); + SetJitHelperFunction(CORINFO_HELP_ULNG2DBL, pDest); + + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__DOUBLE_TO_ULONG)); + pDest = pMD->GetMultiCallableAddrOfCode(); + SetJitHelperFunction(CORINFO_HELP_DBL2ULNG, pDest); + + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__DOUBLE_TO_INT_OVERFLOW)); + pDest = pMD->GetMultiCallableAddrOfCode(); + SetJitHelperFunction(CORINFO_HELP_DBL2INT_OVF, pDest); + + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__DOUBLE_TO_UINT_OVERFLOW)); + pDest = pMD->GetMultiCallableAddrOfCode(); + SetJitHelperFunction(CORINFO_HELP_DBL2UINT_OVF, pDest); + + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__DOUBLE_TO_LONG_OVERFLOW)); + pDest = pMD->GetMultiCallableAddrOfCode(); + SetJitHelperFunction(CORINFO_HELP_DBL2LNG_OVF, pDest); + + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__DOUBLE_TO_ULONG_OVERFLOW)); + pDest = pMD->GetMultiCallableAddrOfCode(); + SetJitHelperFunction(CORINFO_HELP_DBL2ULNG_OVF, pDest); + + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__DOUBLE_REMINDER)); + pDest = pMD->GetMultiCallableAddrOfCode(); + SetJitHelperFunction(CORINFO_HELP_DBLREM, pDest); + + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATHF__FLOAT_REMINDER)); + pDest = pMD->GetMultiCallableAddrOfCode(); + SetJitHelperFunction(CORINFO_HELP_FLTREM, pDest); + + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__DOUBLE_TO_INT)); + pDest = pMD->GetMultiCallableAddrOfCode(); + SetJitHelperFunction(CORINFO_HELP_DBL2INT, pDest); + + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__DOUBLE_TO_UINT)); + pDest = pMD->GetMultiCallableAddrOfCode(); + SetJitHelperFunction(CORINFO_HELP_DBL2UINT, pDest); + + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__ROUND)); + pDest = pMD->GetMultiCallableAddrOfCode(); + SetJitHelperFunction(CORINFO_HELP_DBLROUND, pDest); + + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATHF__ROUND)); + pDest = pMD->GetMultiCallableAddrOfCode(); + SetJitHelperFunction(CORINFO_HELP_FLTROUND, pDest); } static CrstStatic gFCallLock; diff --git a/src/coreclr/vm/ecall.h b/src/coreclr/vm/ecall.h index bc9d63ae46713..792eea633e8f7 100644 --- a/src/coreclr/vm/ecall.h +++ b/src/coreclr/vm/ecall.h @@ -94,7 +94,7 @@ class ECall static void PopulateManagedStringConstructors(); - static void PopulateManagedCastHelpers(); + static void PopulateManagedHelpers(); #ifdef DACCESS_COMPILE // Enumerates all gFCallMethods for minidumps. diff --git a/src/coreclr/vm/i386/jithelp.S b/src/coreclr/vm/i386/jithelp.S index c1da6f4dcb801..d027525202781 100644 --- a/src/coreclr/vm/i386/jithelp.S +++ b/src/coreclr/vm/i386/jithelp.S @@ -551,87 +551,6 @@ LOCAL_LABEL(LRszMORE32): ret LEAF_END JIT_LRsz, _TEXT -// *********************************************************************/ -// JIT_Dbl2LngP4x87 -// -// Purpose: -// converts a double to a long truncating toward zero (C semantics) -// -// uses stdcall calling conventions -// -// This code is faster on a P4 than the Dbl2Lng code above, but is -// slower on a PIII. Hence we choose this code when on a P4 or above. -// -LEAF_ENTRY JIT_Dbl2LngP4x87, _TEXT - // get some local space - sub esp, 8 - - #define arg1 [esp + 0x0C] - fld QWORD PTR arg1 // fetch arg - fnstcw WORD PTR arg1 // store FPCW - movzx eax, WORD PTR arg1 // zero extend - wide - or ah, 0x0C // turn on OE and DE flags - mov DWORD PTR [esp], eax // store new FPCW bits - fldcw WORD PTR [esp] // reload FPCW with new bits - fistp QWORD PTR [esp] // convert - - // reload FP result - mov eax, DWORD PTR [esp] - mov edx, DWORD PTR [esp + 4] - - // reload original FPCW value - fldcw WORD PTR arg1 - #undef arg1 - - // restore stack - add esp, 8 - - ret -LEAF_END JIT_Dbl2LngP4x87, _TEXT - -// *********************************************************************/ -// JIT_Dbl2LngSSE3 -// -// Purpose: -// converts a double to a long truncating toward zero (C semantics) -// -// uses stdcall calling conventions -// -// This code is faster than the above P4 x87 code for Intel processors -// equal or later than Core2 and Atom that have SSE3 support -// -LEAF_ENTRY JIT_Dbl2LngSSE3, _TEXT - // get some local space - sub esp, 8 - - fld QWORD PTR [esp + 0x0C] // fetch arg - fisttp QWORD PTR [esp] // convert - mov eax, DWORD PTR [esp] // reload FP result - mov edx, DWORD PTR [esp + 4] - - // restore stack - add esp, 8 - - ret -LEAF_END JIT_Dbl2LngSSE3, _TEXT - -// *********************************************************************/ -// JIT_Dbl2IntSSE2 -// -// Purpose: -// converts a double to a long truncating toward zero (C semantics) -// -// uses stdcall calling conventions -// -// This code is even faster than the P4 x87 code for Dbl2LongP4x87, -// but only returns a 32 bit value (only good for int). -// -LEAF_ENTRY JIT_Dbl2IntSSE2, _TEXT - movsd xmm0, [esp + 4] - cvttsd2si eax, xmm0 - ret -LEAF_END JIT_Dbl2IntSSE2, _TEXT - // *********************************************************************/ // JIT_StackProbe // diff --git a/src/coreclr/vm/i386/jithelp.asm b/src/coreclr/vm/i386/jithelp.asm index 5f6890b8312e0..b7446327d47f9 100644 --- a/src/coreclr/vm/i386/jithelp.asm +++ b/src/coreclr/vm/i386/jithelp.asm @@ -36,11 +36,7 @@ JIT_LLsh TEXTEQU <_JIT_LLsh@0> JIT_LRsh TEXTEQU <_JIT_LRsh@0> JIT_LRsz TEXTEQU <_JIT_LRsz@0> JIT_LMul TEXTEQU <@JIT_LMul@16> -JIT_Dbl2LngOvf TEXTEQU <@JIT_Dbl2LngOvf@8> JIT_Dbl2Lng TEXTEQU <@JIT_Dbl2Lng@8> -JIT_Dbl2IntSSE2 TEXTEQU <@JIT_Dbl2IntSSE2@8> -JIT_Dbl2LngP4x87 TEXTEQU <@JIT_Dbl2LngP4x87@8> -JIT_Dbl2LngSSE3 TEXTEQU <@JIT_Dbl2LngSSE3@8> JIT_InternalThrowFromHelper TEXTEQU <@JIT_InternalThrowFromHelper@4> JIT_WriteBarrierReg_PreGrow TEXTEQU <_JIT_WriteBarrierReg_PreGrow@0> JIT_WriteBarrierReg_PostGrow TEXTEQU <_JIT_WriteBarrierReg_PostGrow@0> @@ -635,181 +631,6 @@ LMul_hard: JIT_LMul ENDP -;*********************************************************************/ -; JIT_Dbl2LngOvf - -;Purpose: -; converts a double to a long truncating toward zero (C semantics) -; with check for overflow -; -; uses stdcall calling conventions -; -PUBLIC JIT_Dbl2LngOvf -JIT_Dbl2LngOvf PROC - fnclex - fld qword ptr [esp+4] - push ecx - push ecx - fstp qword ptr [esp] - call JIT_Dbl2Lng - mov ecx,eax - fnstsw ax - test ax,01h - jnz Dbl2LngOvf_throw - mov eax,ecx - ret 8 - -Dbl2LngOvf_throw: - mov ECX, CORINFO_OverflowException_ASM - call JIT_InternalThrowFromHelper - ret 8 -JIT_Dbl2LngOvf ENDP - -;*********************************************************************/ -; JIT_Dbl2Lng - -;Purpose: -; converts a double to a long truncating toward zero (C semantics) -; -; uses stdcall calling conventions -; -; note that changing the rounding mode is very expensive. This -; routine basiclly does the truncation semantics without changing -; the rounding mode, resulting in a win. -; -PUBLIC JIT_Dbl2Lng -JIT_Dbl2Lng PROC - fld qword ptr[ESP+4] ; fetch arg - lea ecx,[esp-8] - sub esp,16 ; allocate frame - and ecx,-8 ; align pointer on boundary of 8 - fld st(0) ; duplciate top of stack - fistp qword ptr[ecx] ; leave arg on stack, also save in temp - fild qword ptr[ecx] ; arg, round(arg) now on stack - mov edx,[ecx+4] ; high dword of integer - mov eax,[ecx] ; low dword of integer - test eax,eax - je integer_QNaN_or_zero - -arg_is_not_integer_QNaN: - fsubp st(1),st ; TOS=d-round(d), - ; { st(1)=st(1)-st & pop ST } - test edx,edx ; what's sign of integer - jns positive - ; number is negative - ; dead cycle - ; dead cycle - fstp dword ptr[ecx] ; result of subtraction - mov ecx,[ecx] ; dword of difference(single precision) - add esp,16 - xor ecx,80000000h - add ecx,7fffffffh ; if difference>0 then increment integer - adc eax,0 ; inc eax (add CARRY flag) - adc edx,0 ; propagate carry flag to upper bits - ret 8 - -positive: - fstp dword ptr[ecx] ;17-18 ; result of subtraction - mov ecx,[ecx] ; dword of difference (single precision) - add esp,16 - add ecx,7fffffffh ; if difference<0 then decrement integer - sbb eax,0 ; dec eax (subtract CARRY flag) - sbb edx,0 ; propagate carry flag to upper bits - ret 8 - -integer_QNaN_or_zero: - test edx,7fffffffh - jnz arg_is_not_integer_QNaN - fstp st(0) ;; pop round(arg) - fstp st(0) ;; arg - add esp,16 - ret 8 -JIT_Dbl2Lng ENDP - -;*********************************************************************/ -; JIT_Dbl2LngP4x87 - -;Purpose: -; converts a double to a long truncating toward zero (C semantics) -; -; uses stdcall calling conventions -; -; This code is faster on a P4 than the Dbl2Lng code above, but is -; slower on a PIII. Hence we choose this code when on a P4 or above. -; -PUBLIC JIT_Dbl2LngP4x87 -JIT_Dbl2LngP4x87 PROC -arg1 equ <[esp+0Ch]> - - sub esp, 8 ; get some local space - - fld qword ptr arg1 ; fetch arg - fnstcw word ptr arg1 ; store FPCW - movzx eax, word ptr arg1 ; zero extend - wide - or ah, 0Ch ; turn on OE and DE flags - mov dword ptr [esp], eax ; store new FPCW bits - fldcw word ptr [esp] ; reload FPCW with new bits - fistp qword ptr [esp] ; convert - mov eax, dword ptr [esp] ; reload FP result - mov edx, dword ptr [esp+4] ; - fldcw word ptr arg1 ; reload original FPCW value - - add esp, 8 ; restore stack - - ret 8 -JIT_Dbl2LngP4x87 ENDP - -;*********************************************************************/ -; JIT_Dbl2LngSSE3 - -;Purpose: -; converts a double to a long truncating toward zero (C semantics) -; -; uses stdcall calling conventions -; -; This code is faster than the above P4 x87 code for Intel processors -; equal or later than Core2 and Atom that have SSE3 support -; -.686P -.XMM -PUBLIC JIT_Dbl2LngSSE3 -JIT_Dbl2LngSSE3 PROC -arg1 equ <[esp+0Ch]> - - sub esp, 8 ; get some local space - - fld qword ptr arg1 ; fetch arg - fisttp qword ptr [esp] ; convert - mov eax, dword ptr [esp] ; reload FP result - mov edx, dword ptr [esp+4] - - add esp, 8 ; restore stack - - ret 8 -JIT_Dbl2LngSSE3 ENDP -.586 - -;*********************************************************************/ -; JIT_Dbl2IntSSE2 - -;Purpose: -; converts a double to a long truncating toward zero (C semantics) -; -; uses stdcall calling conventions -; -; This code is even faster than the P4 x87 code for Dbl2LongP4x87, -; but only returns a 32 bit value (only good for int). -; -.686P -.XMM -PUBLIC JIT_Dbl2IntSSE2 -JIT_Dbl2IntSSE2 PROC - $movsd xmm0, [esp+4] - cvttsd2si eax, xmm0 - ret 8 -JIT_Dbl2IntSSE2 ENDP -.586 - ;*********************************************************************/ ; This is the small write barrier thunk we use when we know the @@ -1212,39 +1033,6 @@ JIT_TailCallVSDLeave: JIT_TailCall ENDP - -;------------------------------------------------------------------------------ - -; HCIMPL2_VV(float, JIT_FltRem, float dividend, float divisor) -@JIT_FltRem@8 proc public - fld dword ptr [esp+4] ; divisor - fld dword ptr [esp+8] ; dividend -fremloop: - fprem - fstsw ax - fwait - sahf - jp fremloop ; Continue while the FPU status bit C2 is set - fxch ; swap, so divisor is on top and result is in st(1) - fstp ST(0) ; Pop the divisor from the FP stack - retn 8 ; Return value is in st(0) -@JIT_FltRem@8 endp - -; HCIMPL2_VV(float, JIT_DblRem, float dividend, float divisor) -@JIT_DblRem@16 proc public - fld qword ptr [esp+4] ; divisor - fld qword ptr [esp+12] ; dividend -fremloopd: - fprem - fstsw ax - fwait - sahf - jp fremloopd ; Continue while the FPU status bit C2 is set - fxch ; swap, so divisor is on top and result is in st(1) - fstp ST(0) ; Pop the divisor from the FP stack - retn 16 ; Return value is in st(0) -@JIT_DblRem@16 endp - ;------------------------------------------------------------------------------ ; PatchedCodeStart and PatchedCodeEnd are used to determine bounds of patched code. diff --git a/src/coreclr/vm/i386/jitinterfacex86.cpp b/src/coreclr/vm/i386/jitinterfacex86.cpp index 08360e9ff0c06..9ad2fdf112d95 100644 --- a/src/coreclr/vm/i386/jitinterfacex86.cpp +++ b/src/coreclr/vm/i386/jitinterfacex86.cpp @@ -96,25 +96,6 @@ extern "C" void STDCALL WriteBarrierAssert(BYTE* ptr, Object* obj) #endif // _DEBUG -#ifndef TARGET_UNIX - -HCIMPL1_V(INT32, JIT_Dbl2IntOvf, double val) -{ - FCALL_CONTRACT; - - INT64 ret = HCCALL1_V(JIT_Dbl2Lng, val); - - if (ret != (INT32) ret) - goto THROW; - - return (INT32) ret; - -THROW: - FCThrow(kOverflowException); -} -HCIMPLEND -#endif // TARGET_UNIX - FCDECL1(Object*, JIT_New, CORINFO_CLASS_HANDLE typeHnd_); @@ -961,32 +942,6 @@ void InitJITHelpers1() JIT_TrialAlloc::Flags flags = GCHeapUtilities::UseThreadAllocationContexts() ? JIT_TrialAlloc::MP_ALLOCATOR : JIT_TrialAlloc::NORMAL; - // Get CPU features and check for SSE2 support. - // This code should eventually probably be moved into codeman.cpp, - // where we set the cpu feature flags for the JIT based on CPU type and features. - int cpuFeatures[4]; - __cpuid(cpuFeatures, 1); - - DWORD dwCPUFeaturesECX = cpuFeatures[2]; - DWORD dwCPUFeaturesEDX = cpuFeatures[3]; - - // If bit 26 (SSE2) is set, then we can use the SSE2 flavors - // and faster x87 implementation for the P4 of Dbl2Lng. - if (dwCPUFeaturesEDX & (1<<26)) - { - SetJitHelperFunction(CORINFO_HELP_DBL2INT, JIT_Dbl2IntSSE2); - if (dwCPUFeaturesECX & 1) // check SSE3 - { - SetJitHelperFunction(CORINFO_HELP_DBL2UINT, JIT_Dbl2LngSSE3); - SetJitHelperFunction(CORINFO_HELP_DBL2LNG, JIT_Dbl2LngSSE3); - } - else - { - SetJitHelperFunction(CORINFO_HELP_DBL2UINT, JIT_Dbl2LngP4x87); // SSE2 only for signed - SetJitHelperFunction(CORINFO_HELP_DBL2LNG, JIT_Dbl2LngP4x87); - } - } - if (!(TrackAllocationsEnabled() || LoggingOn(LF_GCALLOC, LL_INFO10) #ifdef _DEBUG diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 450752ae36778..442a00ba96d82 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -91,6 +91,32 @@ #include +#if !defined(HOST_64BIT) && !defined(TARGET_X86) +/*********************************************************************/ +HCIMPL2_VV(UINT64, JIT_LLsh, UINT64 num, int shift) +{ + FCALL_CONTRACT; + return num << (shift & 0x3F); +} +HCIMPLEND + +/*********************************************************************/ +HCIMPL2_VV(INT64, JIT_LRsh, INT64 num, int shift) +{ + FCALL_CONTRACT; + return num >> (shift & 0x3F); +} +HCIMPLEND + +/*********************************************************************/ +HCIMPL2_VV(UINT64, JIT_LRsz, UINT64 num, int shift) +{ + FCALL_CONTRACT; + return num >> (shift & 0x3F); +} +HCIMPLEND +#endif // !HOST_64BIT && !TARGET_X86 + // // helper macro to multiply two 32-bit uints // @@ -137,117 +163,6 @@ HCIMPL2_VV(INT64, JIT_LMul, INT64 val1, INT64 val2) HCIMPLEND #endif // !TARGET_X86 || TARGET_UNIX -/*********************************************************************/ -HCIMPL2_VV(INT64, JIT_LMulOvf, INT64 val1, INT64 val2) -{ - FCALL_CONTRACT; - - // This short-cut does not actually help since the multiplication - // of two 32-bit signed ints compiles into the call to a slow helper - // if (Is32BitSigned(val1) && Is32BitSigned(val2)) - // return (INT64)(INT32)val1 * (INT64)(INT32)val2; - - INDEBUG(INT64 expected = val1 * val2;) - INT64 ret; - - // Remember the sign of the result - INT32 sign = Hi32Bits(val1) ^ Hi32Bits(val2); - - // Convert to unsigned multiplication - if (val1 < 0) val1 = -val1; - if (val2 < 0) val2 = -val2; - - // Get the upper 32 bits of the numbers - UINT32 val1High = Hi32Bits(val1); - UINT32 val2High = Hi32Bits(val2); - - UINT64 valMid; - - if (val1High == 0) { - // Compute the 'middle' bits of the long multiplication - valMid = Mul32x32To64(val2High, val1); - } - else { - if (val2High != 0) - goto ThrowExcep; - // Compute the 'middle' bits of the long multiplication - valMid = Mul32x32To64(val1High, val2); - } - - // See if any bits after bit 32 are set - if (Hi32Bits(valMid) != 0) - goto ThrowExcep; - - ret = Mul32x32To64(val1, val2) + ShiftToHi32Bits((UINT32)(valMid)); - - // check for overflow - if (Hi32Bits(ret) < (UINT32)valMid) - goto ThrowExcep; - - if (sign >= 0) { - // have we spilled into the sign bit? - if (ret < 0) - goto ThrowExcep; - } - else { - ret = -ret; - // have we spilled into the sign bit? - if (ret > 0) - goto ThrowExcep; - } - _ASSERTE(ret == expected); - return ret; - -ThrowExcep: - FCThrow(kOverflowException); -} -HCIMPLEND - -/*********************************************************************/ -HCIMPL2_VV(UINT64, JIT_ULMulOvf, UINT64 val1, UINT64 val2) -{ - FCALL_CONTRACT; - - INDEBUG(UINT64 expected = val1 * val2;) - UINT64 ret; - - // Get the upper 32 bits of the numbers - UINT32 val1High = Hi32Bits(val1); - UINT32 val2High = Hi32Bits(val2); - - UINT64 valMid; - - if (val1High == 0) { - if (val2High == 0) - return Mul32x32To64(val1, val2); - // Compute the 'middle' bits of the long multiplication - valMid = Mul32x32To64(val2High, val1); - } - else { - if (val2High != 0) - goto ThrowExcep; - // Compute the 'middle' bits of the long multiplication - valMid = Mul32x32To64(val1High, val2); - } - - // See if any bits after bit 32 are set - if (Hi32Bits(valMid) != 0) - goto ThrowExcep; - - ret = Mul32x32To64(val1, val2) + ShiftToHi32Bits((UINT32)(valMid)); - - // check for overflow - if (Hi32Bits(ret) < (UINT32)valMid) - goto ThrowExcep; - - _ASSERTE(ret == expected); - return ret; - -ThrowExcep: - FCThrow(kOverflowException); - } -HCIMPLEND - /*********************************************************************/ HCIMPL2(INT32, JIT_Div, INT32 dividend, INT32 divisor) { @@ -450,32 +365,6 @@ HCIMPL2_VV(UINT64, JIT_ULMod, UINT64 dividend, UINT64 divisor) } HCIMPLEND -#if !defined(HOST_64BIT) && !defined(TARGET_X86) -/*********************************************************************/ -HCIMPL2_VV(UINT64, JIT_LLsh, UINT64 num, int shift) -{ - FCALL_CONTRACT; - return num << (shift & 0x3F); -} -HCIMPLEND - -/*********************************************************************/ -HCIMPL2_VV(INT64, JIT_LRsh, INT64 num, int shift) -{ - FCALL_CONTRACT; - return num >> (shift & 0x3F); -} -HCIMPLEND - -/*********************************************************************/ -HCIMPL2_VV(UINT64, JIT_LRsz, UINT64 num, int shift) -{ - FCALL_CONTRACT; - return num >> (shift & 0x3F); -} -HCIMPLEND -#endif // !HOST_64BIT && !TARGET_X86 - #include @@ -488,282 +377,22 @@ HCIMPLEND #include /*********************************************************************/ -// -HCIMPL1_V(double, JIT_ULng2Dbl, UINT64 val) -{ - FCALL_CONTRACT; - - double conv = (double) ((INT64) val); - if (conv < 0) - conv += (4294967296.0 * 4294967296.0); // add 2^64 - _ASSERTE(conv >= 0); - return(conv); -} -HCIMPLEND - -/*********************************************************************/ -// needed for ARM and RyuJIT-x86 +// needed for ARM and x86 HCIMPL1_V(double, JIT_Lng2Dbl, INT64 val) { FCALL_CONTRACT; - return double(val); + return (double)val; } HCIMPLEND -//-------------------------------------------------------------------------- -template -ftype modftype(ftype value, ftype *iptr); -template <> float modftype(float value, float *iptr) { return modff(value, iptr); } -template <> double modftype(double value, double *iptr) { return modf(value, iptr); } - -// round to nearest, round to even if tied -template -ftype BankersRound(ftype value) -{ - if (value < 0.0) return -BankersRound (-value); - - ftype integerPart; - modftype( value, &integerPart ); - - // if decimal part is exactly .5 - if ((value -(integerPart +0.5)) == 0.0) - { - // round to even - if (fmod(ftype(integerPart), ftype(2.0)) == 0.0) - return integerPart; - - // Else return the nearest even integer - return (ftype)copysign(ceil(fabs(value+0.5)), - value); - } - - // Otherwise round to closest - return (ftype)copysign(floor(fabs(value)+0.5), - value); -} - - -/*********************************************************************/ -// round double to nearest int (as double) -HCIMPL1_V(double, JIT_DoubleRound, double val) -{ - FCALL_CONTRACT; - return BankersRound(val); -} -HCIMPLEND - -/*********************************************************************/ -// round float to nearest int (as float) -HCIMPL1_V(float, JIT_FloatRound, float val) -{ - FCALL_CONTRACT; - return BankersRound(val); -} -HCIMPLEND - -/*********************************************************************/ -// Call fast Dbl2Lng conversion - used by functions below -FORCEINLINE INT64 FastDbl2Lng(double val) -{ -#ifdef TARGET_X86 - FCALL_CONTRACT; - return HCCALL1_V(JIT_Dbl2Lng, val); -#else - FCALL_CONTRACT; - return((__int64) val); -#endif -} - -/*********************************************************************/ -HCIMPL1_V(UINT32, JIT_Dbl2UIntOvf, double val) -{ - FCALL_CONTRACT; - - // Note that this expression also works properly for val = NaN case - if (val > -1.0 && val < 4294967296.0) - return((UINT32)FastDbl2Lng(val)); - - FCThrow(kOverflowException); -} -HCIMPLEND - -/*********************************************************************/ -HCIMPL1_V(UINT64, JIT_Dbl2ULng, double val) -{ - FCALL_CONTRACT; - - const double two63 = 2147483648.0 * 4294967296.0; - UINT64 ret; - if (val < two63) { - ret = FastDbl2Lng(val); - } - else { - // subtract 0x8000000000000000, do the convert then add it back again - ret = FastDbl2Lng(val - two63) + I64(0x8000000000000000); - } - return ret; -} -HCIMPLEND - -/*********************************************************************/ -HCIMPL1_V(UINT64, JIT_Dbl2ULngOvf, double val) -{ - FCALL_CONTRACT; - - const double two64 = 4294967296.0 * 4294967296.0; - // Note that this expression also works properly for val = NaN case - if (val > -1.0 && val < two64) { - const double two63 = 2147483648.0 * 4294967296.0; - UINT64 ret; - if (val < two63) { - ret = FastDbl2Lng(val); - } - else { - // subtract 0x8000000000000000, do the convert then add it back again - ret = FastDbl2Lng(val - two63) + I64(0x8000000000000000); - } -#ifdef _DEBUG - // since no overflow can occur, the value always has to be within 1 - double roundTripVal = HCCALL1_V(JIT_ULng2Dbl, ret); - _ASSERTE(val - 1.0 <= roundTripVal && roundTripVal <= val + 1.0); -#endif // _DEBUG - return ret; - } - - FCThrow(kOverflowException); -} -HCIMPLEND - - -#if !defined(TARGET_X86) || defined(TARGET_UNIX) - HCIMPL1_V(INT64, JIT_Dbl2Lng, double val) { FCALL_CONTRACT; - return((INT64)val); + return (INT64)val; } HCIMPLEND -HCIMPL1_V(int, JIT_Dbl2IntOvf, double val) -{ - FCALL_CONTRACT; - - const double two31 = 2147483648.0; - - // Note that this expression also works properly for val = NaN case - if (val > -two31 - 1 && val < two31) - return((INT32)val); - - FCThrow(kOverflowException); -} -HCIMPLEND - -HCIMPL1_V(INT64, JIT_Dbl2LngOvf, double val) -{ - FCALL_CONTRACT; - - const double two63 = 2147483648.0 * 4294967296.0; - - // Note that this expression also works properly for val = NaN case - // We need to compare with the very next double to two63. 0x402 is epsilon to get us there. - if (val > -two63 - 0x402 && val < two63) - return((INT64)val); - - FCThrow(kOverflowException); -} -HCIMPLEND - -#ifndef TARGET_WINDOWS -namespace -{ - bool isnan(float val) - { - UINT32 bits = *reinterpret_cast(&val); - return (bits & 0x7FFFFFFFU) > 0x7F800000U; - } - bool isnan(double val) - { - UINT64 bits = *reinterpret_cast(&val); - return (bits & 0x7FFFFFFFFFFFFFFFULL) > 0x7FF0000000000000ULL; - } - bool isfinite(float val) - { - UINT32 bits = *reinterpret_cast(&val); - return (~bits & 0x7F800000U) != 0; - } - bool isfinite(double val) - { - UINT64 bits = *reinterpret_cast(&val); - return (~bits & 0x7FF0000000000000ULL) != 0; - } -} -#endif - -HCIMPL2_VV(float, JIT_FltRem, float dividend, float divisor) -{ - FCALL_CONTRACT; - - // - // From the ECMA standard: - // - // If [divisor] is zero or [dividend] is infinity - // the result is NaN. - // If [divisor] is infinity, - // the result is [dividend] (negated for -infinity***). - // - // ***"negated for -infinity" has been removed from the spec - // - - if (divisor==0 || !isfinite(dividend)) - { - UINT32 NaN = CLR_NAN_32; - return *(float *)(&NaN); - } - else if (!isfinite(divisor) && !isnan(divisor)) - { - return dividend; - } - // else... -#if 0 - // COMPILER BUG WITH FMODF() + /Oi, USE FMOD() INSTEAD - return fmodf(dividend,divisor); -#else - return (float)fmod((double)dividend,(double)divisor); -#endif -} -HCIMPLEND - -HCIMPL2_VV(double, JIT_DblRem, double dividend, double divisor) -{ - FCALL_CONTRACT; - - // - // From the ECMA standard: - // - // If [divisor] is zero or [dividend] is infinity - // the result is NaN. - // If [divisor] is infinity, - // the result is [dividend] (negated for -infinity***). - // - // ***"negated for -infinity" has been removed from the spec - // - if (divisor==0 || !isfinite(dividend)) - { - UINT64 NaN = CLR_NAN_64; - return *(double *)(&NaN); - } - else if (!isfinite(divisor) && !isnan(divisor)) - { - return dividend; - } - // else... - return(fmod(dividend,divisor)); -} -HCIMPLEND - -#endif // !TARGET_X86 || TARGET_UNIX - #include diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index a2146482a2fc0..a97dc3964f8f3 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -10682,7 +10682,17 @@ void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */ dynamicFtnNum == DYNAMIC_CORINFO_HELP_CHKCASTCLASS_SPECIAL || dynamicFtnNum == DYNAMIC_CORINFO_HELP_UNBOX || dynamicFtnNum == DYNAMIC_CORINFO_HELP_ARRADDR_ST || - dynamicFtnNum == DYNAMIC_CORINFO_HELP_LDELEMA_REF) + dynamicFtnNum == DYNAMIC_CORINFO_HELP_LDELEMA_REF || + dynamicFtnNum == DYNAMIC_CORINFO_HELP_LMUL_OVF || + dynamicFtnNum == DYNAMIC_CORINFO_HELP_ULMUL_OVF || + dynamicFtnNum == DYNAMIC_CORINFO_HELP_ULNG2DBL || + dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2ULNG || + dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2INT_OVF || + dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2UINT_OVF || + dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2LNG_OVF || + dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2ULNG_OVF || + dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBLREM || + dynamicFtnNum == DYNAMIC_CORINFO_HELP_FLTREM) { Precode* pPrecode = Precode::GetPrecodeFromEntryPoint((PCODE)hlpDynamicFuncTable[dynamicFtnNum].pfnHelper); _ASSERTE(pPrecode->GetType() == PRECODE_FIXUP); @@ -10712,12 +10722,15 @@ void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */ { // Cache it for future uses to avoid taking the lock again. hlpFinalTierAddrTable[dynamicFtnNum] = finalTierAddr; + EE_TO_JIT_TRANSITION_LEAF(); return finalTierAddr; } } } *ppIndirection = ((FixupPrecode*)pPrecode)->GetTargetSlot(); + + EE_TO_JIT_TRANSITION_LEAF(); return NULL; } diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 63666b46552cf..ed276b536e09e 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -325,17 +325,6 @@ EXTERN_C FCDECL2(Object*, JIT_NewArr1OBJ_MP_InlineGetThread, CORINFO_CLASS_HANDL EXTERN_C FCDECL2_VV(INT64, JIT_LMul, INT64 val1, INT64 val2); -EXTERN_C FCDECL1_V(INT64, JIT_Dbl2Lng, double val); -EXTERN_C FCDECL1_V(INT64, JIT_Dbl2IntSSE2, double val); -EXTERN_C FCDECL1_V(INT64, JIT_Dbl2LngP4x87, double val); -EXTERN_C FCDECL1_V(INT64, JIT_Dbl2LngSSE3, double val); -EXTERN_C FCDECL1_V(INT64, JIT_Dbl2LngOvf, double val); - -EXTERN_C FCDECL1_V(INT32, JIT_Dbl2IntOvf, double val); - -EXTERN_C FCDECL2_VV(float, JIT_FltRem, float dividend, float divisor); -EXTERN_C FCDECL2_VV(double, JIT_DblRem, double dividend, double divisor); - #ifndef HOST_64BIT #ifdef TARGET_X86 // JIThelp.asm diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index 1d1c50a4e2b55..8d1bbea9b6b26 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -1481,5 +1481,245 @@ public static double ScaleB(double x, int n) double u = BitConverter.Int64BitsToDouble(((long)(0x3ff + n) << 52)); return y * u; } + + [StackTraceHidden] + private static long LongMultiplyOverflow(long i, long j) + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static uint Hi32Bits(ulong a) + { + return (uint)(a >> 32); + } + + // Remember the sign of the result + int sign = (int)(Hi32Bits((ulong)i) ^ Hi32Bits((ulong)j)); + + // Convert to unsigned multiplication + if (i < 0) i = -i; + if (j < 0) j = -j; + + // Get the upper 32 bits of the numbers + uint val1High = Hi32Bits((ulong)i); + uint val2High = Hi32Bits((ulong)j); + + ulong valMid; + + if (val1High == 0) + { + // Compute the 'middle' bits of the long multiplication + valMid = BigMul(val2High, (uint)i); + } + else + { + if (val2High != 0) + goto Overflow; + // Compute the 'middle' bits of the long multiplication + valMid = BigMul(val1High, (uint)j); + } + + // See if any bits after bit 32 are set + if (Hi32Bits(valMid) != 0) + goto Overflow; + + long ret = (long)(BigMul((uint)i, (uint)j) + (valMid << 32)); + + // check for overflow + if (Hi32Bits((ulong)ret) < (uint)valMid) + goto Overflow; + + if (sign >= 0) + { + // have we spilled into the sign bit? + if (ret < 0) + goto Overflow; + } + else + { + ret = -ret; + // have we spilled into the sign bit? + if (ret > 0) + goto Overflow; + } + + Debug.Assert(ret == i * j); + return ret; + + Overflow: + ThrowHelper.ThrowOverflowException(); + return 0; + } + + [StackTraceHidden] + private static ulong ULongMultiplyOverflow(ulong i, ulong j) + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static uint Hi32Bits(ulong a) + { + return (uint)(a >> 32); + } + + // Get the upper 32 bits of the numbers + uint val1High = Hi32Bits(i); + uint val2High = Hi32Bits(j); + + ulong valMid; + + if (val1High == 0) + { + if (val2High == 0) + return BigMul((uint)i, (uint)j); + // Compute the 'middle' bits of the long multiplication + valMid = BigMul(val2High, (uint)i); + } + else + { + if (val2High != 0) + goto Overflow; + // Compute the 'middle' bits of the long multiplication + valMid = BigMul(val1High, (uint)j); + } + + // See if any bits after bit 32 are set + if (Hi32Bits(valMid) != 0) + goto Overflow; + + ulong ret = BigMul((uint)i, (uint)j) + (valMid << 32); + + // check for overflow + if (Hi32Bits(ret) < (uint)valMid) + goto Overflow; + + Debug.Assert(ret == i * j); + return ret; + + Overflow: + ThrowHelper.ThrowOverflowException(); + return 0; + } + + private static double ULongToDouble(ulong val) + { + double conv = (long)val; + if (conv < 0) + conv += 4294967296.0 * 4294967296.0; // add 2^64 + Debug.Assert(conv >= 0); + return conv; + } + + private static ulong DoubleToULong(double val) + { + const double two63 = 2147483648.0 * 4294967296.0; + ulong ret; + if (val < two63) + { + ret = (ulong)(long)val; + } + else + { + // subtract 0x8000000000000000, do the convert then add it back again + ret = (ulong)(long)(val - two63) + 0x8000000000000000UL; + } + return ret; + } + + [StackTraceHidden] + private static int DoubleToIntOverflow(double val) + { + const double two31 = 2147483648.0; + + // Note that this expression also works properly for val = NaN case + if (val is > -two31 - 1 and < two31) + { + int ret = (int)val; + // since no overflow can occur, the value always has to be within 1 + Debug.Assert(val - 1.0 <= ret); + Debug.Assert(ret <= val + 1.0); + return ret; + } + + ThrowHelper.ThrowOverflowException(); + return 0; + } + + [StackTraceHidden] + private static uint DoubleToUIntOverflow(double val) + { + // Note that this expression also works properly for val = NaN case + if (val is > -1.0 and < 4294967296.0) + { + uint ret = (uint)(long)val; + // since no overflow can occur, the value always has to be within 1 + Debug.Assert(val - 1.0 <= ret); + Debug.Assert(ret <= val + 1.0); + return ret; + } + + ThrowHelper.ThrowOverflowException(); + return 0; + } + + [StackTraceHidden] + private static long DoubleToLongOverflow(double val) + { + const double two63 = 2147483648.0 * 4294967296.0; + + // Note that this expression also works properly for val = NaN case + // We need to compare with the very next double to two63. 0x402 is epsilon to get us there. + if (val is > -two63 - 0x402 and < two63) + { + long ret = (long)val; + // since no overflow can occur, the value always has to be within 1 + Debug.Assert(val - 1.0 <= ret); + Debug.Assert(ret <= val + 1.0); + return ret; + } + + ThrowHelper.ThrowOverflowException(); + return 0; + } + + [StackTraceHidden] + private static ulong DoubleToULongOverflow(double val) + { + const double two64 = 4294967296.0 * 4294967296.0; + // Note that this expression also works properly for val = NaN case + if (val is > -1.0 and < two64) + { + ulong ret = (ulong)val; + // since no overflow can occur, the value always has to be within 1 + Debug.Assert(val - 1.0 <= ret); + Debug.Assert(ret <= val + 1.0); + return ret; + } + + ThrowHelper.ThrowOverflowException(); + return 0; + } + + private static double DoubleReminder(double dividend, double divisor) + { + // From the ECMA standard: + // + // If [divisor] is zero or [dividend] is infinity + // the result is NaN. + // If [divisor] is infinity, + // the result is [dividend] (negated for -infinity***). + // + // ***"negated for -infinity" has been removed from the spec + if (divisor == 0 || !double.IsFinite(dividend)) + { + return double.NaN; + } + + if (!double.IsFinite(divisor) && !double.IsNaN(divisor)) + { + return dividend; + } + + return FMod(dividend, divisor); + } + + private static int DoubleToInt(double val) => (int)(long)val; + private static uint DoubleToUInt(double val) => (uint)(long)val; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/MathF.cs b/src/libraries/System.Private.CoreLib/src/System/MathF.cs index cc0795255d0c8..d58e059d26c26 100644 --- a/src/libraries/System.Private.CoreLib/src/System/MathF.cs +++ b/src/libraries/System.Private.CoreLib/src/System/MathF.cs @@ -511,5 +511,28 @@ public static float ScaleB(float x, int n) float u = BitConverter.Int32BitsToSingle(((int)(0x7f + n) << 23)); return y * u; } + + private static float FloatReminder(float dividend, float divisor) + { + // From the ECMA standard: + // + // If [divisor] is zero or [dividend] is infinity + // the result is NaN. + // If [divisor] is infinity, + // the result is [dividend] (negated for -infinity***). + // + // ***"negated for -infinity" has been removed from the spec + if (divisor == 0 || !float.IsFinite(dividend)) + { + return float.NaN; + } + + if (!float.IsFinite(divisor) && !float.IsNaN(divisor)) + { + return dividend; + } + + return FMod(dividend, divisor); + } } } From dfbcf221a547983c2e0df7c40c8600150cd7975f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Fri, 23 Feb 2024 19:27:51 +0100 Subject: [PATCH 02/29] Fix asserts --- src/coreclr/jit/gentree.cpp | 1 + .../System.Private.CoreLib/src/System/Math.cs | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 298fd1074a4f1..7194fbeab6325 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -5980,6 +5980,7 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree) switch (tree->AsIntrinsic()->gtIntrinsicName) { case NI_System_Math_Atan2: + case NI_System_Math_FMod: case NI_System_Math_Pow: // These math intrinsics are actually implemented by user calls. Increase the // Sethi 'complexity' by two to reflect the argument register requirement. diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index 8d1bbea9b6b26..f8615abf86a8f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -1491,6 +1491,10 @@ static uint Hi32Bits(ulong a) return (uint)(a >> 32); } +#if DEBUG + long result = i * j; +#endif + // Remember the sign of the result int sign = (int)(Hi32Bits((ulong)i) ^ Hi32Bits((ulong)j)); @@ -1541,7 +1545,9 @@ static uint Hi32Bits(ulong a) goto Overflow; } - Debug.Assert(ret == i * j); +#if DEBUG + Debug.Assert(ret == result, $"Multiply overflow got: {ret}, expected: {result}"); +#endif return ret; Overflow: @@ -1589,7 +1595,7 @@ static uint Hi32Bits(ulong a) if (Hi32Bits(ret) < (uint)valMid) goto Overflow; - Debug.Assert(ret == i * j); + Debug.Assert(ret == i * j, $"Multiply overflow got: {ret}, expected: {i * j}"); return ret; Overflow: From 878b5731c8533182ff3c555d289690dfd50ccf71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Thu, 7 Mar 2024 00:50:40 +0100 Subject: [PATCH 03/29] Cleanup changes, add comments --- src/coreclr/jit/utils.cpp | 4 ++++ src/coreclr/jit/valuenum.cpp | 12 ++++++++++++ .../tools/Common/TypeSystem/IL/HelperExtensions.cs | 1 - .../aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs | 2 -- .../System.Private.CoreLib/src/System/Math.cs | 7 +++++-- 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/coreclr/jit/utils.cpp b/src/coreclr/jit/utils.cpp index 5b9e74e91b242..aed8cda7c24df 100644 --- a/src/coreclr/jit/utils.cpp +++ b/src/coreclr/jit/utils.cpp @@ -1536,10 +1536,14 @@ void HelperCallProperties::init() case CORINFO_HELP_LMUL: case CORINFO_HELP_LNG2DBL: case CORINFO_HELP_ULNG2DBL: + case CORINFO_HELP_DBL2INT: case CORINFO_HELP_DBL2LNG: + case CORINFO_HELP_DBL2UINT: case CORINFO_HELP_DBL2ULNG: case CORINFO_HELP_FLTREM: case CORINFO_HELP_DBLREM: + case CORINFO_HELP_FLTROUND: + case CORINFO_HELP_DBLROUND: isPure = true; noThrow = true; diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 4a8ca85aa3e58..79cc554835540 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -12759,6 +12759,11 @@ void Compiler::fgValueNumberCastHelper(GenTreeCall* call) srcIsUnsigned = true; break; + case CORINFO_HELP_DBL2INT: + castToType = TYP_INT; + castFromType = TYP_DOUBLE; + break; + case CORINFO_HELP_DBL2INT_OVF: castToType = TYP_INT; castFromType = TYP_DOUBLE; @@ -12776,6 +12781,11 @@ void Compiler::fgValueNumberCastHelper(GenTreeCall* call) hasOverflowCheck = true; break; + case CORINFO_HELP_DBL2UINT: + castToType = TYP_UINT; + castFromType = TYP_DOUBLE; + break; + case CORINFO_HELP_DBL2UINT_OVF: castToType = TYP_UINT; castFromType = TYP_DOUBLE; @@ -13081,9 +13091,11 @@ bool Compiler::fgValueNumberHelperCall(GenTreeCall* call) { case CORINFO_HELP_LNG2DBL: case CORINFO_HELP_ULNG2DBL: + case CORINFO_HELP_DBL2INT: case CORINFO_HELP_DBL2INT_OVF: case CORINFO_HELP_DBL2LNG: case CORINFO_HELP_DBL2LNG_OVF: + case CORINFO_HELP_DBL2UINT: case CORINFO_HELP_DBL2UINT_OVF: case CORINFO_HELP_DBL2ULNG: case CORINFO_HELP_DBL2ULNG_OVF: diff --git a/src/coreclr/tools/Common/TypeSystem/IL/HelperExtensions.cs b/src/coreclr/tools/Common/TypeSystem/IL/HelperExtensions.cs index fa24787613574..ca5dc2eca5dbe 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/HelperExtensions.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/HelperExtensions.cs @@ -7,7 +7,6 @@ using Internal.IL.Stubs; using Debug = System.Diagnostics.Debug; -using System.Xml.Linq; namespace Internal.IL { diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs index e152de9cb404a..4a701b8e0af8c 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; using Internal.TypeSystem; using Internal.ReadyToRunConstants; @@ -10,7 +9,6 @@ using Debug = System.Diagnostics.Debug; using DependencyList = ILCompiler.DependencyAnalysisFramework.DependencyNodeCore.DependencyList; -using System.Reflection.Emit; #pragma warning disable IDE0060 diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index 34211170f9c3d..c63f6fd2dffba 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -1617,7 +1617,7 @@ private static double ULongToDouble(ulong val) { double conv = (long)val; if (conv < 0) - conv += 4294967296.0 * 4294967296.0; // add 2^64 + conv += 4294967296.0 * 4294967296.0; // add 2^64 Debug.Assert(conv >= 0); return conv; } @@ -1626,6 +1626,7 @@ private static ulong DoubleToULong(double val) { const double two63 = 2147483648.0 * 4294967296.0; ulong ret; + // don't remove the double casts, the runtime would call this method recursively without them if (val < two63) { ret = (ulong)(long)val; @@ -1663,7 +1664,7 @@ private static uint DoubleToUIntOverflow(double val) // Note that this expression also works properly for val = NaN case if (val is > -1.0 and < 4294967296.0) { - uint ret = (uint)(long)val; + uint ret = (uint)val; // since no overflow can occur, the value always has to be within 1 Debug.Assert(val - 1.0 <= ret); Debug.Assert(ret <= val + 1.0); @@ -1735,6 +1736,8 @@ private static double DoubleReminder(double dividend, double divisor) return FMod(dividend, divisor); } + // those helpers are currently unused, they're only kept for R2R compatibility for now + // don't remove the double casts, the runtime would call the methods recursively without them private static int DoubleToInt(double val) => (int)(long)val; private static uint DoubleToUInt(double val) => (uint)(long)val; } From ef4868b00903d3661ab1085eab62f84981ddbb6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Thu, 7 Mar 2024 00:56:31 +0100 Subject: [PATCH 04/29] Fix typo --- .../tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs index 4a701b8e0af8c..4e9a1537fb5d9 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs @@ -1288,7 +1288,7 @@ private void ImportConvert(WellKnownType wellKnownType, bool checkOverflow, bool case WellKnownType.UInt32: if (checkOverflow) { - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Dbl2UIntOvf), "conv_u8_ovf"); + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Dbl2UIntOvf), "conv_u4_ovf"); } break; case WellKnownType.UInt64: From 08eaa088d43fa85a5c6333617343ad73764f8f00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Thu, 7 Mar 2024 01:26:41 +0100 Subject: [PATCH 05/29] Fix small type overflow in the scanner --- .../tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs index 4e9a1537fb5d9..ff6c1ab38363f 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs @@ -1269,6 +1269,8 @@ private void ImportConvert(WellKnownType wellKnownType, bool checkOverflow, bool { switch (wellKnownType) { + case WellKnownType.Byte: + case WellKnownType.UInt16: case WellKnownType.SByte: case WellKnownType.Int16: case WellKnownType.Int32: @@ -1283,8 +1285,6 @@ private void ImportConvert(WellKnownType wellKnownType, bool checkOverflow, bool _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Dbl2LngOvf), "conv_i8_ovf"); } break; - case WellKnownType.Byte: - case WellKnownType.UInt16: case WellKnownType.UInt32: if (checkOverflow) { From a96f68a8685492d7a652ce23da3bc193a4d43bb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Thu, 7 Mar 2024 01:33:10 +0100 Subject: [PATCH 06/29] Update JIT-EE GUID --- src/coreclr/inc/jiteeversionguid.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 11675936acfa3..712a82cfa60f8 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID; #define GUID_DEFINED #endif // !GUID_DEFINED -constexpr GUID JITEEVersionIdentifier = { /* 86eab154-5d93-4fad-bc07-e94fd9268b70 */ - 0x86eab154, - 0x5d93, - 0x4fad, - {0xbc, 0x07, 0xe9, 0x4f, 0xd9, 0x26, 0x8b, 0x70} +constexpr GUID JITEEVersionIdentifier = { /* 3220f4c7-a292-4896-976a-4e7c9503baa3 */ + 0x3220f4c7, + 0xa292, + 0x4896, + {0x97, 0x6a, 0x4e, 0x7c, 0x95, 0x03, 0xba, 0xa3} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// From 2b4b7953bce5a647d3df62634391da712de4a64f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Thu, 7 Mar 2024 23:19:16 +0100 Subject: [PATCH 07/29] Remove helper --- .../Common/TypeSystem/IL/HelperExtensions.cs | 7 ------ .../ILCompiler.Compiler/Compiler/JitHelper.cs | 24 +++++++++---------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/HelperExtensions.cs b/src/coreclr/tools/Common/TypeSystem/IL/HelperExtensions.cs index ca5dc2eca5dbe..4ccaff2d6dd9f 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/HelperExtensions.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/HelperExtensions.cs @@ -40,13 +40,6 @@ public static MethodDesc GetOptionalHelperEntryPoint(this TypeSystemContext cont return helperMethod; } - public static MethodDesc GetHelperEntryPoint(this TypeSystemContext context, string typeNamespace, string typeName, string methodName) - { - MetadataType helperType = context.SystemModule.GetKnownType(typeNamespace, typeName); - MethodDesc helperMethod = helperType.GetKnownMethod(methodName, null); - return helperMethod; - } - /// /// Emits a call to a throw helper. Use this to emit calls to static parameterless methods that don't return. /// The advantage of using this extension method is that you don't have to deal with what code to emit after diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs index 8d5b1357d9e3e..46de7de7e3326 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs @@ -165,44 +165,44 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, break; case ReadyToRunHelper.LMulOfv: - methodDesc = context.GetHelperEntryPoint("System", "Math", "LongMultiplyOverflow"); + methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("LongMultiplyOverflow", null); break; case ReadyToRunHelper.ULMulOvf: - methodDesc = context.GetHelperEntryPoint("System", "Math", "ULongMultiplyOverflow"); + methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("ULongMultiplyOverflow", null); break; case ReadyToRunHelper.ULng2Dbl: - methodDesc = context.GetHelperEntryPoint("System", "Math", "ULongToDouble"); + methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("ULongToDouble", null); break; case ReadyToRunHelper.Dbl2ULng: - methodDesc = context.GetHelperEntryPoint("System", "Math", "DoubleToULong"); + methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("DoubleToULong", null); break; case ReadyToRunHelper.Dbl2IntOvf: - methodDesc = context.GetHelperEntryPoint("System", "Math", "DoubleToIntOverflow"); + methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("DoubleToIntOverflow", null); break; case ReadyToRunHelper.Dbl2UIntOvf: - methodDesc = context.GetHelperEntryPoint("System", "Math", "DoubleToUIntOverflow"); + methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("DoubleToUIntOverflow", null); break; case ReadyToRunHelper.Dbl2LngOvf: - methodDesc = context.GetHelperEntryPoint("System", "Math", "DoubleToLongOverflow"); + methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("DoubleToLongOverflow", null); break; case ReadyToRunHelper.Dbl2ULngOvf: - methodDesc = context.GetHelperEntryPoint("System", "Math", "DoubleToULongOverflow"); + methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("DoubleToULongOverflow", null); break; case ReadyToRunHelper.DblRem: - methodDesc = context.GetHelperEntryPoint("System", "Math", "DoubleReminder"); + methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("DoubleReminder", null); break; case ReadyToRunHelper.FltRem: - methodDesc = context.GetHelperEntryPoint("System", "MathF", "FloatReminder"); + methodDesc = context.SystemModule.GetKnownType("System", "MathF").GetKnownMethod("FloatReminder", null); break; case ReadyToRunHelper.Dbl2Int: - methodDesc = context.GetHelperEntryPoint("System", "Math", "DoubleToInt"); + methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("DoubleToInt", null); break; case ReadyToRunHelper.Dbl2UInt: - methodDesc = context.GetHelperEntryPoint("System", "MathF", "DoubleToUInt"); + methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("DoubleToUInt", null); break; case ReadyToRunHelper.DblRound: DefType doubleType = context.GetWellKnownType(WellKnownType.Double); From 64b9bbcfa8391dfa930f13856e532c6cc69f8af1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Sun, 10 Mar 2024 17:35:03 +0100 Subject: [PATCH 08/29] Fully managed conversions to double --- src/coreclr/inc/jithelpers.h | 2 +- src/coreclr/nativeaot/Runtime/MathHelpers.cpp | 5 ---- .../ILCompiler.Compiler/Compiler/JitHelper.cs | 6 ++--- .../IL/ILImporter.Scanner.cs | 1 + src/coreclr/vm/corelib.h | 1 + src/coreclr/vm/ecall.cpp | 4 +++ src/coreclr/vm/jithelpers.cpp | 6 ----- src/coreclr/vm/jitinterface.cpp | 1 + .../System.Private.CoreLib/src/System/Math.cs | 27 +++++++++++++++---- 9 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index e0f65ff5de908..2f225da1b578c 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -51,7 +51,7 @@ JITHELPER(CORINFO_HELP_LMOD, JIT_LMod, CORINFO_HELP_SIG_16_STACK) JITHELPER(CORINFO_HELP_ULDIV, JIT_ULDiv, CORINFO_HELP_SIG_16_STACK) JITHELPER(CORINFO_HELP_ULMOD, JIT_ULMod, CORINFO_HELP_SIG_16_STACK) - JITHELPER(CORINFO_HELP_LNG2DBL, JIT_Lng2Dbl, CORINFO_HELP_SIG_8_STACK) + DYNAMICJITHELPER(CORINFO_HELP_LNG2DBL, NULL, CORINFO_HELP_SIG_8_STACK) DYNAMICJITHELPER(CORINFO_HELP_ULNG2DBL, NULL, CORINFO_HELP_SIG_8_STACK) DYNAMICJITHELPER(CORINFO_HELP_DBL2INT, NULL, CORINFO_HELP_SIG_8_STACK) DYNAMICJITHELPER(CORINFO_HELP_DBL2INT_OVF, NULL, CORINFO_HELP_SIG_8_STACK) diff --git a/src/coreclr/nativeaot/Runtime/MathHelpers.cpp b/src/coreclr/nativeaot/Runtime/MathHelpers.cpp index 2464a2568d8f9..0aa0d7b74a364 100644 --- a/src/coreclr/nativeaot/Runtime/MathHelpers.cpp +++ b/src/coreclr/nativeaot/Runtime/MathHelpers.cpp @@ -86,9 +86,4 @@ EXTERN_C int64_t REDHAWK_CALLCONV RhpDbl2Lng(double val) { return (int64_t)val; } - -EXTERN_C double REDHAWK_CALLCONV RhpLng2Dbl(int64_t val) -{ - return (double)val; -} #endif // HOST_ARM diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs index 46de7de7e3326..47e6cbc6faf27 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs @@ -171,6 +171,9 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("ULongMultiplyOverflow", null); break; + case ReadyToRunHelper.Lng2Dbl: + methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("LongToDouble", null); + break; case ReadyToRunHelper.ULng2Dbl: methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("ULongToDouble", null); break; @@ -215,9 +218,6 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, new MethodSignature(MethodSignatureFlags.Static, 0, floatType, [floatType])); break; - case ReadyToRunHelper.Lng2Dbl: - mangledName = "RhpLng2Dbl"; - break; case ReadyToRunHelper.Dbl2Lng: mangledName = "RhpDbl2Lng"; break; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs index ff6c1ab38363f..d6d6f5259ad95 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs @@ -1303,6 +1303,7 @@ private void ImportConvert(WellKnownType wellKnownType, bool checkOverflow, bool break; case WellKnownType.Single: case WellKnownType.Double: + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Lng2Dbl), "conv_r"); _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ULng2Dbl), "conv_r"); break; } diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index eef4d60b64b87..ec3c1084ab864 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -265,6 +265,7 @@ DEFINE_CLASS(UINT128, System, UInt128) DEFINE_CLASS(MATH, System, Math) DEFINE_METHOD(MATH, LONG_MULTIPLY_OVERFLOW, LongMultiplyOverflow, NoSig) DEFINE_METHOD(MATH, ULONG_MULTIPLY_OVERFLOW,ULongMultiplyOverflow, NoSig) +DEFINE_METHOD(MATH, LONG_TO_DOUBLE, LongToDouble, NoSig) DEFINE_METHOD(MATH, ULONG_TO_DOUBLE, ULongToDouble, NoSig) DEFINE_METHOD(MATH, DOUBLE_TO_ULONG, DoubleToULong, NoSig) DEFINE_METHOD(MATH, DOUBLE_TO_INT_OVERFLOW, DoubleToIntOverflow, NoSig) diff --git a/src/coreclr/vm/ecall.cpp b/src/coreclr/vm/ecall.cpp index fa8cf590c28d6..dfba7ff6bb69c 100644 --- a/src/coreclr/vm/ecall.cpp +++ b/src/coreclr/vm/ecall.cpp @@ -165,6 +165,10 @@ void ECall::PopulateManagedHelpers() pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_ULMUL_OVF, pDest); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__LONG_TO_DOUBLE)); + pDest = pMD->GetMultiCallableAddrOfCode(); + SetJitHelperFunction(CORINFO_HELP_LNG2DBL, pDest); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__ULONG_TO_DOUBLE)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_ULNG2DBL, pDest); diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 092dc342547bb..529cf7e6fd9cb 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -378,12 +378,6 @@ HCIMPLEND /*********************************************************************/ // needed for ARM and x86 -HCIMPL1_V(double, JIT_Lng2Dbl, INT64 val) -{ - FCALL_CONTRACT; - return (double)val; -} -HCIMPLEND HCIMPL1_V(INT64, JIT_Dbl2Lng, double val) { diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index dbf4aa43de507..945541f52d16e 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -10695,6 +10695,7 @@ void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */ dynamicFtnNum == DYNAMIC_CORINFO_HELP_MEMCPY || dynamicFtnNum == DYNAMIC_CORINFO_HELP_LMUL_OVF || dynamicFtnNum == DYNAMIC_CORINFO_HELP_ULMUL_OVF || + dynamicFtnNum == DYNAMIC_CORINFO_HELP_LNG2DBL || dynamicFtnNum == DYNAMIC_CORINFO_HELP_ULNG2DBL || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2ULNG || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2INT_OVF || diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index c63f6fd2dffba..f2786ce9c1af0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -9,6 +9,7 @@ using System.Diagnostics.CodeAnalysis; using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; @@ -1613,13 +1614,29 @@ static uint Hi32Bits(ulong a) return 0; } + private static ref double DoubleConversionTable => ref MemoryMarshal.GetReference([0.0, 4294967296.0]); + + private static double LongToDouble(long val) + { + uint upper = (uint)(val >>> 32); + uint lower = (uint)val; + double a = (int)upper; + double b = (int)lower; + b += Unsafe.Add(ref DoubleConversionTable, lower >> 31); + // todo: check if https://github.com/dotnet/runtime/issues/98053 will be useful here + return a * Unsafe.Add(ref DoubleConversionTable, 1U) + b; + } + private static double ULongToDouble(ulong val) { - double conv = (long)val; - if (conv < 0) - conv += 4294967296.0 * 4294967296.0; // add 2^64 - Debug.Assert(conv >= 0); - return conv; + uint upper = (uint)(val >> 32); + uint lower = (uint)val; + double a = (int)upper; + double b = (int)lower; + a += Unsafe.Add(ref DoubleConversionTable, upper >> 31); + b += Unsafe.Add(ref DoubleConversionTable, lower >> 31); + // todo: check if https://github.com/dotnet/runtime/issues/98053 will be useful here + return a * Unsafe.Add(ref DoubleConversionTable, 1U) + b; } private static ulong DoubleToULong(double val) From b4d0521aba752c66f47047cb7574e5c1f153634f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Mon, 11 Mar 2024 20:43:38 +0100 Subject: [PATCH 09/29] Restore one ASM helper --- src/coreclr/inc/jithelpers.h | 2 +- src/coreclr/vm/i386/jithelp.S | 25 +++++++++++++++++++++ src/coreclr/vm/i386/jithelp.asm | 30 ++++++++++++++++++++++++- src/coreclr/vm/i386/jitinterfacex86.cpp | 13 +++++++++++ src/coreclr/vm/jitinterface.cpp | 17 +++++++------- src/coreclr/vm/jitinterface.h | 1 + 6 files changed, 78 insertions(+), 10 deletions(-) diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index 2f225da1b578c..25151dc65c2bb 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -55,7 +55,7 @@ DYNAMICJITHELPER(CORINFO_HELP_ULNG2DBL, NULL, CORINFO_HELP_SIG_8_STACK) DYNAMICJITHELPER(CORINFO_HELP_DBL2INT, NULL, CORINFO_HELP_SIG_8_STACK) DYNAMICJITHELPER(CORINFO_HELP_DBL2INT_OVF, NULL, CORINFO_HELP_SIG_8_STACK) - JITHELPER(CORINFO_HELP_DBL2LNG, JIT_Dbl2Lng, CORINFO_HELP_SIG_8_STACK) + DYNAMICJITHELPER(CORINFO_HELP_DBL2LNG, JIT_Dbl2Lng, CORINFO_HELP_SIG_8_STACK) DYNAMICJITHELPER(CORINFO_HELP_DBL2LNG_OVF, NULL, CORINFO_HELP_SIG_8_STACK) DYNAMICJITHELPER(CORINFO_HELP_DBL2UINT, NULL, CORINFO_HELP_SIG_8_STACK) DYNAMICJITHELPER(CORINFO_HELP_DBL2UINT_OVF, NULL, CORINFO_HELP_SIG_8_STACK) diff --git a/src/coreclr/vm/i386/jithelp.S b/src/coreclr/vm/i386/jithelp.S index d027525202781..873669bfedde1 100644 --- a/src/coreclr/vm/i386/jithelp.S +++ b/src/coreclr/vm/i386/jithelp.S @@ -551,6 +551,31 @@ LOCAL_LABEL(LRszMORE32): ret LEAF_END JIT_LRsz, _TEXT +// *********************************************************************/ +// JIT_Dbl2LngFpu +// +// Purpose: +// converts a double to a long truncating toward zero (C semantics) +// +// uses stdcall calling conventions +// +// This code is faster than C++ even on modern CPUs but it requires SSE3 +// +LEAF_ENTRY JIT_Dbl2LngFpu, _TEXT + // get some local space + sub esp, 8 + + fld QWORD PTR [esp + 0x0C] // fetch arg + fisttp QWORD PTR [esp] // convert + mov eax, DWORD PTR [esp] // reload FP result + mov edx, DWORD PTR [esp + 4] + + // restore stack + add esp, 8 + + ret +LEAF_END JIT_Dbl2LngFpu, _TEXT + // *********************************************************************/ // JIT_StackProbe // diff --git a/src/coreclr/vm/i386/jithelp.asm b/src/coreclr/vm/i386/jithelp.asm index b7446327d47f9..9e6ee6fea2d03 100644 --- a/src/coreclr/vm/i386/jithelp.asm +++ b/src/coreclr/vm/i386/jithelp.asm @@ -36,7 +36,7 @@ JIT_LLsh TEXTEQU <_JIT_LLsh@0> JIT_LRsh TEXTEQU <_JIT_LRsh@0> JIT_LRsz TEXTEQU <_JIT_LRsz@0> JIT_LMul TEXTEQU <@JIT_LMul@16> -JIT_Dbl2Lng TEXTEQU <@JIT_Dbl2Lng@8> +JIT_Dbl2LngFpu TEXTEQU <@JIT_Dbl2LngFpu@8> JIT_InternalThrowFromHelper TEXTEQU <@JIT_InternalThrowFromHelper@4> JIT_WriteBarrierReg_PreGrow TEXTEQU <_JIT_WriteBarrierReg_PreGrow@0> JIT_WriteBarrierReg_PostGrow TEXTEQU <_JIT_WriteBarrierReg_PostGrow@0> @@ -631,6 +631,34 @@ LMul_hard: JIT_LMul ENDP +;*********************************************************************/ +; JIT_Dbl2LngFpu +; +;Purpose: +; converts a double to a long truncating toward zero (C semantics) +; +; uses stdcall calling conventions +; +; This code is faster than C++ even on modern CPUs but it requires SSE3 +; +.686P +.XMM +PUBLIC JIT_Dbl2LngFpu +JIT_Dbl2LngFpu PROC +arg1 equ <[esp+0Ch]> + + sub esp, 8 ; get some local space + + fld qword ptr arg1 ; fetch arg + fisttp qword ptr [esp] ; convert + mov eax, dword ptr [esp] ; reload FP result + mov edx, dword ptr [esp+4] + + add esp, 8 ; restore stack + + ret 8 +JIT_Dbl2LngFpu ENDP +.586 ;*********************************************************************/ ; This is the small write barrier thunk we use when we know the diff --git a/src/coreclr/vm/i386/jitinterfacex86.cpp b/src/coreclr/vm/i386/jitinterfacex86.cpp index 9ad2fdf112d95..b815fa6c0631d 100644 --- a/src/coreclr/vm/i386/jitinterfacex86.cpp +++ b/src/coreclr/vm/i386/jitinterfacex86.cpp @@ -942,6 +942,19 @@ void InitJITHelpers1() JIT_TrialAlloc::Flags flags = GCHeapUtilities::UseThreadAllocationContexts() ? JIT_TrialAlloc::MP_ALLOCATOR : JIT_TrialAlloc::NORMAL; + // Get CPU features and check for SSE3 support. + // This code should eventually probably be moved into codeman.cpp, + // where we set the cpu feature flags for the JIT based on CPU type and features. + int cpuFeatures[4]; + __cpuid(cpuFeatures, 1); + + DWORD dwCPUFeaturesECX = cpuFeatures[2]; + + if (dwCPUFeaturesECX & 1) // check SSE3 + { + SetJitHelperFunction(CORINFO_HELP_DBL2LNG, JIT_Dbl2LngFpu); + } + if (!(TrackAllocationsEnabled() || LoggingOn(LF_GCALLOC, LL_INFO10) #ifdef _DEBUG diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 945541f52d16e..fb017f516b61b 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -10666,7 +10666,8 @@ void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */ { _ASSERTE(ppIndirection != NULL); *ppIndirection = &hlpDynamicFuncTable[dynamicFtnNum].pfnHelper; - return NULL; + result = NULL; + goto Exit; } #endif @@ -10675,7 +10676,8 @@ void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */ LPVOID finalTierAddr = hlpFinalTierAddrTable[dynamicFtnNum]; if (finalTierAddr != NULL) { - return finalTierAddr; + result = finalTierAddr; + goto Exit; } if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_ISINSTANCEOFINTERFACE || @@ -10733,16 +10735,15 @@ void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */ { // Cache it for future uses to avoid taking the lock again. hlpFinalTierAddrTable[dynamicFtnNum] = finalTierAddr; - EE_TO_JIT_TRANSITION_LEAF(); - return finalTierAddr; + result = finalTierAddr; + goto Exit; } } } *ppIndirection = ((FixupPrecode*)pPrecode)->GetTargetSlot(); - - EE_TO_JIT_TRANSITION_LEAF(); - return NULL; + result = NULL; + goto Exit; } pfnHelper = hlpDynamicFuncTable[dynamicFtnNum].pfnHelper; @@ -10756,8 +10757,8 @@ void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */ result = (LPVOID)GetEEFuncEntryPoint(pfnHelper); +Exit: EE_TO_JIT_TRANSITION_LEAF(); - return result; } diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index fe11b7c93e9ba..00281984b2839 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -324,6 +324,7 @@ EXTERN_C FCDECL2(Object*, JIT_NewArr1OBJ_MP_InlineGetThread, CORINFO_CLASS_HANDL #endif // HOST_64BIT EXTERN_C FCDECL2_VV(INT64, JIT_LMul, INT64 val1, INT64 val2); +EXTERN_C FCDECL1_V(INT64, JIT_Dbl2LngFpu, double val); #ifndef HOST_64BIT #ifdef TARGET_X86 From 6a525ee0cc419ce0f66b4933003a16e1de081d8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Wed, 13 Mar 2024 19:51:08 +0100 Subject: [PATCH 10/29] Cleanup code, move uint cast to managed --- src/coreclr/inc/corinfo.h | 4 +- src/coreclr/inc/jiteeversionguid.h | 10 +-- src/coreclr/jit/morph.cpp | 4 +- src/coreclr/vm/jitinterface.cpp | 2 + .../System.Private.CoreLib/src/System/Math.cs | 81 ++++++++++--------- 5 files changed, 55 insertions(+), 46 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index bd39f8b28c2d1..f3e7b0a944683 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -387,11 +387,11 @@ enum CorInfoHelpFunc CORINFO_HELP_ULMOD, CORINFO_HELP_LNG2DBL, // Convert a signed int64 to a double CORINFO_HELP_ULNG2DBL, // Convert a unsigned int64 to a double - CORINFO_HELP_DBL2INT, // unused + CORINFO_HELP_DBL2INT, CORINFO_HELP_DBL2INT_OVF, CORINFO_HELP_DBL2LNG, CORINFO_HELP_DBL2LNG_OVF, - CORINFO_HELP_DBL2UINT, // unused + CORINFO_HELP_DBL2UINT, CORINFO_HELP_DBL2UINT_OVF, CORINFO_HELP_DBL2ULNG, CORINFO_HELP_DBL2ULNG_OVF, diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index b6cc5d7a0b475..8d54d8f3d3e71 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID; #define GUID_DEFINED #endif // !GUID_DEFINED -constexpr GUID JITEEVersionIdentifier = { /* e5f629d4-edc8-48f1-a75d-0fa1f0b5af6f */ - 0xe5f629d4, - 0xedc8, - 0x48f1, - {0xa7, 0x5d, 0x0f, 0xa1, 0xf0, 0xb5, 0xaf, 0x6f} +constexpr GUID JITEEVersionIdentifier = { /* f4da6024-dd94-4b02-af3d-83e74297b17b */ + 0xf4da6024, + 0xdd94, + 0x4b02, + {0xaf, 0x3d, 0x83, 0xe7, 0x42, 0x97, 0xb1, 0x7b} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index c04ed48665786..30b83dcc6f900 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -377,9 +377,7 @@ GenTree* Compiler::fgMorphExpandCast(GenTreeCast* tree) #if defined(TARGET_ARM) || defined(TARGET_AMD64) return nullptr; #else // TARGET_X86 - oper = gtNewCastNode(TYP_LONG, oper, false, TYP_LONG); - tree = gtNewCastNode(TYP_INT, oper, false, TYP_UINT); - return fgMorphTree(tree); + return fgMorphCastIntoHelper(tree, CORINFO_HELP_DBL2UINT, oper); #endif // TARGET_X86 case TYP_LONG: diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index ffc0a14718129..9ed9fa8dd8c27 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -10731,6 +10731,8 @@ void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */ dynamicFtnNum == DYNAMIC_CORINFO_HELP_LNG2DBL || dynamicFtnNum == DYNAMIC_CORINFO_HELP_ULNG2DBL || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2ULNG || + dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2INT || + dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2UINT || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2INT_OVF || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2UINT_OVF || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2LNG_OVF || diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index f2786ce9c1af0..9f43301030f71 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -1493,29 +1493,29 @@ public static double ScaleB(double x, int n) return y * u; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint High32Bits(ulong a) + { + return (uint)(a >> 32); + } + [StackTraceHidden] private static long LongMultiplyOverflow(long i, long j) { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - static uint Hi32Bits(ulong a) - { - return (uint)(a >> 32); - } - #if DEBUG long result = i * j; #endif // Remember the sign of the result - int sign = (int)(Hi32Bits((ulong)i) ^ Hi32Bits((ulong)j)); + int sign = (int)(High32Bits((ulong)i) ^ High32Bits((ulong)j)); // Convert to unsigned multiplication if (i < 0) i = -i; if (j < 0) j = -j; // Get the upper 32 bits of the numbers - uint val1High = Hi32Bits((ulong)i); - uint val2High = Hi32Bits((ulong)j); + uint val1High = High32Bits((ulong)i); + uint val2High = High32Bits((ulong)j); ulong valMid; @@ -1533,13 +1533,13 @@ static uint Hi32Bits(ulong a) } // See if any bits after bit 32 are set - if (Hi32Bits(valMid) != 0) + if (High32Bits(valMid) != 0) goto Overflow; long ret = (long)(BigMul((uint)i, (uint)j) + (valMid << 32)); // check for overflow - if (Hi32Bits((ulong)ret) < (uint)valMid) + if (High32Bits((ulong)ret) < (uint)valMid) goto Overflow; if (sign >= 0) @@ -1569,15 +1569,9 @@ static uint Hi32Bits(ulong a) [StackTraceHidden] private static ulong ULongMultiplyOverflow(ulong i, ulong j) { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - static uint Hi32Bits(ulong a) - { - return (uint)(a >> 32); - } - // Get the upper 32 bits of the numbers - uint val1High = Hi32Bits(i); - uint val2High = Hi32Bits(j); + uint val1High = High32Bits(i); + uint val2High = High32Bits(j); ulong valMid; @@ -1597,13 +1591,13 @@ static uint Hi32Bits(ulong a) } // See if any bits after bit 32 are set - if (Hi32Bits(valMid) != 0) + if (High32Bits(valMid) != 0) goto Overflow; ulong ret = BigMul((uint)i, (uint)j) + (valMid << 32); // check for overflow - if (Hi32Bits(ret) < (uint)valMid) + if (High32Bits(ret) < (uint)valMid) goto Overflow; Debug.Assert(ret == i * j, $"Multiply overflow got: {ret}, expected: {i * j}"); @@ -1614,34 +1608,45 @@ static uint Hi32Bits(ulong a) return 0; } - private static ref double DoubleConversionTable => ref MemoryMarshal.GetReference([0.0, 4294967296.0]); + private const double IntMaxValueOffset = 2147483648.0; // 2^31, int.MaxValue + 1 + private const double UIntMaxValueOffset = 4294967296.0; // 2^32, uint.MaxValue + 1 + private static ref double DoubleConversionTable => ref MemoryMarshal.GetReference([0.0, UIntMaxValueOffset]); private static double LongToDouble(long val) { uint upper = (uint)(val >>> 32); uint lower = (uint)val; double a = (int)upper; + // X86 has no uint -> double casts, we need to do this to avoid recursion here +#if TARGET_X86 double b = (int)lower; b += Unsafe.Add(ref DoubleConversionTable, lower >> 31); - // todo: check if https://github.com/dotnet/runtime/issues/98053 will be useful here - return a * Unsafe.Add(ref DoubleConversionTable, 1U) + b; +#else + double b = lower; +#endif + return a * UIntMaxValueOffset + b; } private static double ULongToDouble(ulong val) { uint upper = (uint)(val >> 32); uint lower = (uint)val; + // X86 has no uint -> double casts, we need to do this to avoid recursion here +#if TARGET_X86 double a = (int)upper; double b = (int)lower; a += Unsafe.Add(ref DoubleConversionTable, upper >> 31); b += Unsafe.Add(ref DoubleConversionTable, lower >> 31); - // todo: check if https://github.com/dotnet/runtime/issues/98053 will be useful here - return a * Unsafe.Add(ref DoubleConversionTable, 1U) + b; +#else + double a = upper; + double b = lower; +#endif + return a * UIntMaxValueOffset + b; } private static ulong DoubleToULong(double val) { - const double two63 = 2147483648.0 * 4294967296.0; + const double two63 = IntMaxValueOffset * UIntMaxValueOffset; ulong ret; // don't remove the double casts, the runtime would call this method recursively without them if (val < two63) @@ -1656,13 +1661,18 @@ private static ulong DoubleToULong(double val) return ret; } + private static uint DoubleToUInt(double val) + { + int a = (int)val; + int b = (int)(val - IntMaxValueOffset); + return (uint)(a | (b & (a >> 31))); + } + [StackTraceHidden] private static int DoubleToIntOverflow(double val) { - const double two31 = 2147483648.0; - // Note that this expression also works properly for val = NaN case - if (val is > -two31 - 1 and < two31) + if (val is > -IntMaxValueOffset - 1 and < IntMaxValueOffset) { int ret = (int)val; // since no overflow can occur, the value always has to be within 1 @@ -1679,7 +1689,7 @@ private static int DoubleToIntOverflow(double val) private static uint DoubleToUIntOverflow(double val) { // Note that this expression also works properly for val = NaN case - if (val is > -1.0 and < 4294967296.0) + if (val is > -1.0 and < UIntMaxValueOffset) { uint ret = (uint)val; // since no overflow can occur, the value always has to be within 1 @@ -1695,7 +1705,7 @@ private static uint DoubleToUIntOverflow(double val) [StackTraceHidden] private static long DoubleToLongOverflow(double val) { - const double two63 = 2147483648.0 * 4294967296.0; + const double two63 = IntMaxValueOffset * UIntMaxValueOffset; // Note that this expression also works properly for val = NaN case // We need to compare with the very next double to two63. 0x402 is epsilon to get us there. @@ -1715,7 +1725,7 @@ private static long DoubleToLongOverflow(double val) [StackTraceHidden] private static ulong DoubleToULongOverflow(double val) { - const double two64 = 4294967296.0 * 4294967296.0; + const double two64 = UIntMaxValueOffset * UIntMaxValueOffset; // Note that this expression also works properly for val = NaN case if (val is > -1.0 and < two64) { @@ -1753,9 +1763,8 @@ private static double DoubleReminder(double dividend, double divisor) return FMod(dividend, divisor); } - // those helpers are currently unused, they're only kept for R2R compatibility for now - // don't remove the double casts, the runtime would call the methods recursively without them + // this helper is currently unused, it's only kept for R2R compatibility for now + // don't remove the double cast, the runtime would call the method recursively without it private static int DoubleToInt(double val) => (int)(long)val; - private static uint DoubleToUInt(double val) => (uint)(long)val; } } From da0b4345fdaccf82b6c5d175fb60f708f384e26e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Wed, 13 Mar 2024 20:09:30 +0100 Subject: [PATCH 11/29] Update jithelpers.h --- src/coreclr/inc/jithelpers.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index 25151dc65c2bb..62dd6aa36728d 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -55,6 +55,7 @@ DYNAMICJITHELPER(CORINFO_HELP_ULNG2DBL, NULL, CORINFO_HELP_SIG_8_STACK) DYNAMICJITHELPER(CORINFO_HELP_DBL2INT, NULL, CORINFO_HELP_SIG_8_STACK) DYNAMICJITHELPER(CORINFO_HELP_DBL2INT_OVF, NULL, CORINFO_HELP_SIG_8_STACK) + // CORINFO_HELP_DBL2LNG gets patched for CPUs with SSE3 in jitinterfacex86.cpp DYNAMICJITHELPER(CORINFO_HELP_DBL2LNG, JIT_Dbl2Lng, CORINFO_HELP_SIG_8_STACK) DYNAMICJITHELPER(CORINFO_HELP_DBL2LNG_OVF, NULL, CORINFO_HELP_SIG_8_STACK) DYNAMICJITHELPER(CORINFO_HELP_DBL2UINT, NULL, CORINFO_HELP_SIG_8_STACK) From 18565e4deac1c7162777192ec7e45bbff0c3bc3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Wed, 13 Mar 2024 20:29:38 +0100 Subject: [PATCH 12/29] Remove DoubleToUInt --- src/coreclr/inc/jithelpers.h | 6 ++++-- .../tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs | 6 +++--- src/coreclr/vm/corelib.h | 1 - src/coreclr/vm/ecall.cpp | 4 ---- src/coreclr/vm/i386/jitinterfacex86.cpp | 1 + src/coreclr/vm/jitinterface.cpp | 1 - src/libraries/System.Private.CoreLib/src/System/Math.cs | 7 ------- 7 files changed, 8 insertions(+), 18 deletions(-) diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index 62dd6aa36728d..c7fd8eb31e88f 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -55,10 +55,12 @@ DYNAMICJITHELPER(CORINFO_HELP_ULNG2DBL, NULL, CORINFO_HELP_SIG_8_STACK) DYNAMICJITHELPER(CORINFO_HELP_DBL2INT, NULL, CORINFO_HELP_SIG_8_STACK) DYNAMICJITHELPER(CORINFO_HELP_DBL2INT_OVF, NULL, CORINFO_HELP_SIG_8_STACK) - // CORINFO_HELP_DBL2LNG gets patched for CPUs with SSE3 in jitinterfacex86.cpp + // CORINFO_HELP_DBL2LNG and CORINFO_HELP_DBL2UINT get patched for CPUs with SSE3 in jitinterfacex86.cpp DYNAMICJITHELPER(CORINFO_HELP_DBL2LNG, JIT_Dbl2Lng, CORINFO_HELP_SIG_8_STACK) DYNAMICJITHELPER(CORINFO_HELP_DBL2LNG_OVF, NULL, CORINFO_HELP_SIG_8_STACK) - DYNAMICJITHELPER(CORINFO_HELP_DBL2UINT, NULL, CORINFO_HELP_SIG_8_STACK) + // this relies on ABI returning the lower half of long the same as an uint + // and the upper half in a caller saver register + DYNAMICJITHELPER(CORINFO_HELP_DBL2UINT, JIT_Dbl2Lng, CORINFO_HELP_SIG_8_STACK) DYNAMICJITHELPER(CORINFO_HELP_DBL2UINT_OVF, NULL, CORINFO_HELP_SIG_8_STACK) DYNAMICJITHELPER(CORINFO_HELP_DBL2ULNG, NULL, CORINFO_HELP_SIG_8_STACK) DYNAMICJITHELPER(CORINFO_HELP_DBL2ULNG_OVF, NULL, CORINFO_HELP_SIG_8_STACK) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs index 47e6cbc6faf27..7d65453a53fba 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs @@ -204,9 +204,6 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, case ReadyToRunHelper.Dbl2Int: methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("DoubleToInt", null); break; - case ReadyToRunHelper.Dbl2UInt: - methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("DoubleToUInt", null); - break; case ReadyToRunHelper.DblRound: DefType doubleType = context.GetWellKnownType(WellKnownType.Double); methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("Round", @@ -221,6 +218,9 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, case ReadyToRunHelper.Dbl2Lng: mangledName = "RhpDbl2Lng"; break; + case ReadyToRunHelper.Dbl2UInt: + mangledName = "RhpDbl2Lng"; + break; case ReadyToRunHelper.LMul: mangledName = "RhpLMul"; diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index ec3c1084ab864..7259fd6fb8a09 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -274,7 +274,6 @@ DEFINE_METHOD(MATH, DOUBLE_TO_LONG_OVERFLOW,DoubleToLongOverflow DEFINE_METHOD(MATH, DOUBLE_TO_ULONG_OVERFLOW,DoubleToULongOverflow, NoSig) DEFINE_METHOD(MATH, DOUBLE_REMINDER, DoubleReminder, NoSig) DEFINE_METHOD(MATH, DOUBLE_TO_INT, DoubleToInt, NoSig) -DEFINE_METHOD(MATH, DOUBLE_TO_UINT, DoubleToUInt, NoSig) DEFINE_METHOD(MATH, ROUND, Round, SM_Dbl_RetDbl) DEFINE_CLASS(MATHF, System, MathF) diff --git a/src/coreclr/vm/ecall.cpp b/src/coreclr/vm/ecall.cpp index dfba7ff6bb69c..a22069877c383 100644 --- a/src/coreclr/vm/ecall.cpp +++ b/src/coreclr/vm/ecall.cpp @@ -205,10 +205,6 @@ void ECall::PopulateManagedHelpers() pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBL2INT, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__DOUBLE_TO_UINT)); - pDest = pMD->GetMultiCallableAddrOfCode(); - SetJitHelperFunction(CORINFO_HELP_DBL2UINT, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__ROUND)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBLROUND, pDest); diff --git a/src/coreclr/vm/i386/jitinterfacex86.cpp b/src/coreclr/vm/i386/jitinterfacex86.cpp index b815fa6c0631d..cd7ee25bdbcec 100644 --- a/src/coreclr/vm/i386/jitinterfacex86.cpp +++ b/src/coreclr/vm/i386/jitinterfacex86.cpp @@ -952,6 +952,7 @@ void InitJITHelpers1() if (dwCPUFeaturesECX & 1) // check SSE3 { + SetJitHelperFunction(CORINFO_HELP_DBL2UINT, JIT_Dbl2LngFpu); SetJitHelperFunction(CORINFO_HELP_DBL2LNG, JIT_Dbl2LngFpu); } diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 9ed9fa8dd8c27..0cf49e9f1c9b3 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -10732,7 +10732,6 @@ void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */ dynamicFtnNum == DYNAMIC_CORINFO_HELP_ULNG2DBL || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2ULNG || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2INT || - dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2UINT || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2INT_OVF || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2UINT_OVF || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2LNG_OVF || diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index 9f43301030f71..f7f4ea03d93a1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -1661,13 +1661,6 @@ private static ulong DoubleToULong(double val) return ret; } - private static uint DoubleToUInt(double val) - { - int a = (int)val; - int b = (int)(val - IntMaxValueOffset); - return (uint)(a | (b & (a >> 31))); - } - [StackTraceHidden] private static int DoubleToIntOverflow(double val) { From a7e114b547c869c150c77502ed8db09d17e82325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Wed, 13 Mar 2024 21:41:04 +0100 Subject: [PATCH 13/29] Move the helpers --- .../src/System/Math.CoreCLR.cs | 2 +- .../src/System/MathF.CoreCLR.cs | 2 +- .../src/System/Math.NativeAot.cs | 2 +- .../src/System/MathF.NativeAot.cs | 2 +- .../ILCompiler.Compiler/Compiler/JitHelper.cs | 43 +-- src/coreclr/vm/corelib.h | 32 ++- src/coreclr/vm/ecall.cpp | 46 +-- .../src/System/Double.cs | 156 ++++++++++ .../src/System/Int64.cs | 77 +++++ .../System.Private.CoreLib/src/System/Math.cs | 267 ------------------ .../src/System/MathF.cs | 23 -- .../src/System/Single.cs | 27 ++ .../src/System/UInt64.cs | 53 ++++ .../src/System/Math.Mono.cs | 2 +- .../src/System/MathF.Mono.cs | 2 +- 15 files changed, 384 insertions(+), 352 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Math.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Math.CoreCLR.cs index a619dc4b1ca79..ec5b0121590f1 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Math.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Math.CoreCLR.cs @@ -117,7 +117,7 @@ public static unsafe (double Sin, double Cos) SinCos(double x) [Intrinsic] [MethodImpl(MethodImplOptions.InternalCall)] - private static extern double FMod(double x, double y); + internal static extern double FMod(double x, double y); [MethodImpl(MethodImplOptions.InternalCall)] private static extern unsafe double ModF(double x, double* intptr); diff --git a/src/coreclr/System.Private.CoreLib/src/System/MathF.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/MathF.CoreCLR.cs index 855a1b1e7ef15..a2d8055c661bb 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/MathF.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/MathF.CoreCLR.cs @@ -114,7 +114,7 @@ public static unsafe (float Sin, float Cos) SinCos(float x) [Intrinsic] [MethodImpl(MethodImplOptions.InternalCall)] - private static extern float FMod(float x, float y); + internal static extern float FMod(float x, float y); [MethodImpl(MethodImplOptions.InternalCall)] private static extern unsafe float ModF(float x, float* intptr); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Math.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Math.NativeAot.cs index 15b629dbee219..842013a1b4312 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Math.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Math.NativeAot.cs @@ -155,7 +155,7 @@ public static double Tanh(double value) } [Intrinsic] - private static double FMod(double x, double y) + internal static double FMod(double x, double y) { return RuntimeImports.fmod(x, y); } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/MathF.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/MathF.NativeAot.cs index 2f42ad90e94c3..5fb0054cb3f5a 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/MathF.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/MathF.NativeAot.cs @@ -155,7 +155,7 @@ public static float Tanh(float x) } [Intrinsic] - private static float FMod(float x, float y) + internal static float FMod(float x, float y) { return RuntimeImports.fmodf(x, y); } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs index 7d65453a53fba..cb771c947895e 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs @@ -164,46 +164,47 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, methodDesc = context.GetHelperEntryPoint("LdTokenHelpers", "GetRuntimeFieldHandle"); break; - case ReadyToRunHelper.LMulOfv: - methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("LongMultiplyOverflow", null); - break; - case ReadyToRunHelper.ULMulOvf: - methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("ULongMultiplyOverflow", null); - break; - - case ReadyToRunHelper.Lng2Dbl: - methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("LongToDouble", null); - break; - case ReadyToRunHelper.ULng2Dbl: - methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("ULongToDouble", null); + case ReadyToRunHelper.Dbl2Int: + methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToInt32", null); break; case ReadyToRunHelper.Dbl2ULng: - methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("DoubleToULong", null); + methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToUInt64", null); break; case ReadyToRunHelper.Dbl2IntOvf: - methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("DoubleToIntOverflow", null); + methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToInt32Overflow", null); break; case ReadyToRunHelper.Dbl2UIntOvf: - methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("DoubleToUIntOverflow", null); + methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToUInt32Overflow", null); break; case ReadyToRunHelper.Dbl2LngOvf: - methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("DoubleToLongOverflow", null); + methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToInt64gOverflow", null); break; case ReadyToRunHelper.Dbl2ULngOvf: - methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("DoubleToULongOverflow", null); + methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToUInt64Overflow", null); + break; + + case ReadyToRunHelper.Lng2Dbl: + methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertFromInt64", null); + break; + case ReadyToRunHelper.ULng2Dbl: + methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertFromUInt64", null); break; case ReadyToRunHelper.DblRem: - methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("DoubleReminder", null); + methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("Reminder", null); break; case ReadyToRunHelper.FltRem: - methodDesc = context.SystemModule.GetKnownType("System", "MathF").GetKnownMethod("FloatReminder", null); + methodDesc = context.SystemModule.GetKnownType("System", "Single").GetKnownMethod("Reminder", null); break; - case ReadyToRunHelper.Dbl2Int: - methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("DoubleToInt", null); + case ReadyToRunHelper.LMulOfv: + methodDesc = context.SystemModule.GetKnownType("System", "Int64").GetKnownMethod("MultiplyOverflow", null); + break; + case ReadyToRunHelper.ULMulOvf: + methodDesc = context.SystemModule.GetKnownType("System", "UInt64").GetKnownMethod("MultiplyOverflow", null); break; + case ReadyToRunHelper.DblRound: DefType doubleType = context.GetWellKnownType(WellKnownType.Double); methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("Round", diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 7259fd6fb8a09..9b142e43c7caa 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -259,25 +259,33 @@ DEFINE_FIELD(DELEGATE, METHOD_PTR_AUX, _methodPtrAux) DEFINE_METHOD(DELEGATE, CONSTRUCT_DELEGATE, DelegateConstruct, IM_Obj_IntPtr_RetVoid) DEFINE_METHOD(DELEGATE, GET_INVOKE_METHOD, GetInvokeMethod, IM_RetIntPtr) +DEFINE_CLASS(DOUBLE_SPC, System, Double) +DEFINE_METHOD(DOUBLE_SPC, CONVERT_TO_INT32, ConvertToInt32, NoSig) +DEFINE_METHOD(DOUBLE_SPC, CONVERT_TO_UINT64, ConvertToUInt64, NoSig) +DEFINE_METHOD(DOUBLE_SPC, CONVERT_TO_INT32_OVERFLOW,ConvertToInt32Overflow, NoSig) +DEFINE_METHOD(DOUBLE_SPC, CONVERT_TO_UINT32_OVERFLOW,ConvertToUInt32Overflow, NoSig) +DEFINE_METHOD(DOUBLE_SPC, CONVERT_TO_INT64_OVERFLOW,ConvertToInt64Overflow, NoSig) +DEFINE_METHOD(DOUBLE_SPC, CONVERT_TO_UINT64_OVERFLOW,ConvertToUInt64Overflow, NoSig) +DEFINE_METHOD(DOUBLE_SPC, CONVERT_FROM_INT64, ConvertFromInt64, NoSig) +DEFINE_METHOD(DOUBLE_SPC, CONVERT_FROM_UINT64, ConvertFromUInt64, NoSig) +DEFINE_METHOD(DOUBLE_SPC, REMINDER, Reminder, NoSig) + +DEFINE_CLASS(SINGLE_SPC, System, Single) +DEFINE_METHOD(SINGLE_SPC, REMINDER, Reminder, NoSig) + +DEFINE_CLASS(INT64_SPC, System, Int64) +DEFINE_METHOD(INT64_SPC, MULTIPLY_OVERFLOW, MultiplyOverflow, NoSig) + +DEFINE_CLASS(UINT64_SPC, System, UInt64) +DEFINE_METHOD(UINT64_SPC, MULTIPLY_OVERFLOW, MultiplyOverflow, NoSig) + DEFINE_CLASS(INT128, System, Int128) DEFINE_CLASS(UINT128, System, UInt128) DEFINE_CLASS(MATH, System, Math) -DEFINE_METHOD(MATH, LONG_MULTIPLY_OVERFLOW, LongMultiplyOverflow, NoSig) -DEFINE_METHOD(MATH, ULONG_MULTIPLY_OVERFLOW,ULongMultiplyOverflow, NoSig) -DEFINE_METHOD(MATH, LONG_TO_DOUBLE, LongToDouble, NoSig) -DEFINE_METHOD(MATH, ULONG_TO_DOUBLE, ULongToDouble, NoSig) -DEFINE_METHOD(MATH, DOUBLE_TO_ULONG, DoubleToULong, NoSig) -DEFINE_METHOD(MATH, DOUBLE_TO_INT_OVERFLOW, DoubleToIntOverflow, NoSig) -DEFINE_METHOD(MATH, DOUBLE_TO_UINT_OVERFLOW,DoubleToUIntOverflow, NoSig) -DEFINE_METHOD(MATH, DOUBLE_TO_LONG_OVERFLOW,DoubleToLongOverflow, NoSig) -DEFINE_METHOD(MATH, DOUBLE_TO_ULONG_OVERFLOW,DoubleToULongOverflow, NoSig) -DEFINE_METHOD(MATH, DOUBLE_REMINDER, DoubleReminder, NoSig) -DEFINE_METHOD(MATH, DOUBLE_TO_INT, DoubleToInt, NoSig) DEFINE_METHOD(MATH, ROUND, Round, SM_Dbl_RetDbl) DEFINE_CLASS(MATHF, System, MathF) -DEFINE_METHOD(MATHF, FLOAT_REMINDER, FloatReminder, NoSig) DEFINE_METHOD(MATHF, ROUND, Round, SM_Flt_RetFlt) DEFINE_CLASS(DYNAMICMETHOD, ReflectionEmit, DynamicMethod) diff --git a/src/coreclr/vm/ecall.cpp b/src/coreclr/vm/ecall.cpp index a22069877c383..ad6dd047bbc1a 100644 --- a/src/coreclr/vm/ecall.cpp +++ b/src/coreclr/vm/ecall.cpp @@ -157,53 +157,53 @@ void ECall::PopulateManagedHelpers() pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_MEMCPY, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__LONG_MULTIPLY_OVERFLOW)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE_SPC__CONVERT_TO_INT32)); pDest = pMD->GetMultiCallableAddrOfCode(); - SetJitHelperFunction(CORINFO_HELP_LMUL_OVF, pDest); - - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__ULONG_MULTIPLY_OVERFLOW)); - pDest = pMD->GetMultiCallableAddrOfCode(); - SetJitHelperFunction(CORINFO_HELP_ULMUL_OVF, pDest); - - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__LONG_TO_DOUBLE)); - pDest = pMD->GetMultiCallableAddrOfCode(); - SetJitHelperFunction(CORINFO_HELP_LNG2DBL, pDest); - - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__ULONG_TO_DOUBLE)); - pDest = pMD->GetMultiCallableAddrOfCode(); - SetJitHelperFunction(CORINFO_HELP_ULNG2DBL, pDest); + SetJitHelperFunction(CORINFO_HELP_DBL2INT, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__DOUBLE_TO_ULONG)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE_SPC__CONVERT_TO_UINT64)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBL2ULNG, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__DOUBLE_TO_INT_OVERFLOW)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE_SPC__CONVERT_TO_INT32_OVERFLOW)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBL2INT_OVF, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__DOUBLE_TO_UINT_OVERFLOW)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE_SPC__CONVERT_TO_UINT32_OVERFLOW)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBL2UINT_OVF, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__DOUBLE_TO_LONG_OVERFLOW)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE_SPC__CONVERT_TO_INT64_OVERFLOW)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBL2LNG_OVF, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__DOUBLE_TO_ULONG_OVERFLOW)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE_SPC__CONVERT_TO_UINT64_OVERFLOW)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBL2ULNG_OVF, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__DOUBLE_REMINDER)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE_SPC__CONVERT_FROM_INT64)); + pDest = pMD->GetMultiCallableAddrOfCode(); + SetJitHelperFunction(CORINFO_HELP_LNG2DBL, pDest); + + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE_SPC__CONVERT_FROM_UINT64)); + pDest = pMD->GetMultiCallableAddrOfCode(); + SetJitHelperFunction(CORINFO_HELP_ULNG2DBL, pDest); + + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE_SPC__REMINDER)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBLREM, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATHF__FLOAT_REMINDER)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__SINGLE_SPC__REMINDER)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_FLTREM, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__DOUBLE_TO_INT)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__INT64_SPC__MULTIPLY_OVERFLOW)); pDest = pMD->GetMultiCallableAddrOfCode(); - SetJitHelperFunction(CORINFO_HELP_DBL2INT, pDest); + SetJitHelperFunction(CORINFO_HELP_LMUL_OVF, pDest); + + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__UINT64_SPC__MULTIPLY_OVERFLOW)); + pDest = pMD->GetMultiCallableAddrOfCode(); + SetJitHelperFunction(CORINFO_HELP_ULMUL_OVF, pDest); pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__ROUND)); pDest = pMD->GetMultiCallableAddrOfCode(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs index 71d73546bc136..71766a8b355f5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Double.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs @@ -440,6 +440,162 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro return Number.TryParseFloat(s, style, NumberFormatInfo.GetInstance(provider), out result); } + // + // Helpers, those methods are referenced from the JIT + // + + private const double IntMaxValueOffset = 2147483648.0; // 2^31, int.MaxValue + 1 + private const double UIntMaxValueOffset = 4294967296.0; // 2^32, uint.MaxValue + 1 + + // TODO: make the helpers saturating when implementing https://github.com/dotnet/runtime/issues/61885 + private static int ConvertToInt32(double val) => (int)(long)val; + + private static ulong ConvertToUInt64(double val) + { + const double two63 = IntMaxValueOffset * UIntMaxValueOffset; + ulong ret; + // don't remove the double casts, the runtime would call this method recursively without them + if (val < two63) + { + ret = (ulong)(long)val; + } + else + { + // subtract 0x8000000000000000, do the convert then add it back again + ret = (ulong)(long)(val - two63) + 0x8000000000000000UL; + } + return ret; + } + + [StackTraceHidden] + private static int ConvertToInt32Overflow(double val) + { + // Note that this expression also works properly for val = NaN case + if (val is > -IntMaxValueOffset - 1 and < IntMaxValueOffset) + { + int ret = (int)val; + // since no overflow can occur, the value always has to be within 1 + Debug.Assert(val - 1.0 <= ret); + Debug.Assert(ret <= val + 1.0); + return ret; + } + + ThrowHelper.ThrowOverflowException(); + return 0; + } + + [StackTraceHidden] + private static uint ConvertToUInt32Overflow(double val) + { + // Note that this expression also works properly for val = NaN case + if (val is > -1.0 and < UIntMaxValueOffset) + { + uint ret = (uint)val; + // since no overflow can occur, the value always has to be within 1 + Debug.Assert(val - 1.0 <= ret); + Debug.Assert(ret <= val + 1.0); + return ret; + } + + ThrowHelper.ThrowOverflowException(); + return 0; + } + + [StackTraceHidden] + private static long ConvertToInt64Overflow(double val) + { + const double two63 = IntMaxValueOffset * UIntMaxValueOffset; + + // Note that this expression also works properly for val = NaN case + // We need to compare with the very next double to two63. 0x402 is epsilon to get us there. + if (val is > -two63 - 0x402 and < two63) + { + long ret = (long)val; + // since no overflow can occur, the value always has to be within 1 + Debug.Assert(val - 1.0 <= ret); + Debug.Assert(ret <= val + 1.0); + return ret; + } + + ThrowHelper.ThrowOverflowException(); + return 0; + } + + [StackTraceHidden] + private static ulong ConvertToUInt64Overflow(double val) + { + const double two64 = UIntMaxValueOffset * UIntMaxValueOffset; + // Note that this expression also works properly for val = NaN case + if (val is > -1.0 and < two64) + { + ulong ret = (ulong)val; + // since no overflow can occur, the value always has to be within 1 + Debug.Assert(val - 1.0 <= ret); + Debug.Assert(ret <= val + 1.0); + return ret; + } + + ThrowHelper.ThrowOverflowException(); + return 0; + } + + private static ref double DoubleConversionTable => ref MemoryMarshal.GetReference([0.0, UIntMaxValueOffset]); + + private static double ConvertFromInt64(long val) + { + uint upper = (uint)(val >>> 32); + uint lower = (uint)val; + double a = (int)upper; + // X86 has no uint -> double casts, we need to do this to avoid recursion here +#if TARGET_X86 + double b = (int)lower; + b += Unsafe.Add(ref DoubleConversionTable, lower >> 31); +#else + double b = lower; +#endif + return a * UIntMaxValueOffset + b; + } + + private static double ConvertFromUInt64(ulong val) + { + uint upper = (uint)(val >> 32); + uint lower = (uint)val; + // X86 has no uint -> double casts, we need to do this to avoid recursion here +#if TARGET_X86 + double a = (int)upper; + double b = (int)lower; + a += Unsafe.Add(ref DoubleConversionTable, upper >> 31); + b += Unsafe.Add(ref DoubleConversionTable, lower >> 31); +#else + double a = upper; + double b = lower; +#endif + return a * UIntMaxValueOffset + b; + } + + private static double Reminder(double dividend, double divisor) + { + // From the ECMA standard: + // + // If [divisor] is zero or [dividend] is infinity + // the result is NaN. + // If [divisor] is infinity, + // the result is [dividend] (negated for -infinity***). + // + // ***"negated for -infinity" has been removed from the spec + if (divisor == 0 || !IsFinite(dividend)) + { + return NaN; + } + + if (!IsFinite(divisor) && !IsNaN(divisor)) + { + return dividend; + } + + return Math.FMod(dividend, divisor); + } + // // IConvertible implementation // diff --git a/src/libraries/System.Private.CoreLib/src/System/Int64.cs b/src/libraries/System.Private.CoreLib/src/System/Int64.cs index ca170d8c903ed..d21ab0ac1a94f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int64.cs @@ -179,6 +179,83 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } + // + // Helpers, those methods are referenced from the JIT + // + + [StackTraceHidden] + private static long MultiplyOverflow(long i, long j) + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static uint High32Bits(ulong a) + { + return (uint)(a >> 32); + } + +#if DEBUG + long result = i * j; +#endif + + // Remember the sign of the result + int sign = (int)(High32Bits((ulong)i) ^ High32Bits((ulong)j)); + + // Convert to unsigned multiplication + if (i < 0) i = -i; + if (j < 0) j = -j; + + // Get the upper 32 bits of the numbers + uint val1High = High32Bits((ulong)i); + uint val2High = High32Bits((ulong)j); + + ulong valMid; + + if (val1High == 0) + { + // Compute the 'middle' bits of the long multiplication + valMid = Math.BigMul(val2High, (uint)i); + } + else + { + if (val2High != 0) + goto Overflow; + // Compute the 'middle' bits of the long multiplication + valMid = Math.BigMul(val1High, (uint)j); + } + + // See if any bits after bit 32 are set + if (High32Bits(valMid) != 0) + goto Overflow; + + long ret = (long)(Math.BigMul((uint)i, (uint)j) + (valMid << 32)); + + // check for overflow + if (High32Bits((ulong)ret) < (uint)valMid) + goto Overflow; + + if (sign >= 0) + { + // have we spilled into the sign bit? + if (ret < 0) + goto Overflow; + } + else + { + ret = -ret; + // have we spilled into the sign bit? + if (ret > 0) + goto Overflow; + } + +#if DEBUG + Debug.Assert(ret == result, $"Multiply overflow got: {ret}, expected: {result}"); +#endif + return ret; + + Overflow: + ThrowHelper.ThrowOverflowException(); + return 0; + } + // // IConvertible implementation // diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index f7f4ea03d93a1..73944ed3341de 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -1492,272 +1492,5 @@ public static double ScaleB(double x, int n) double u = BitConverter.Int64BitsToDouble(((long)(0x3ff + n) << 52)); return y * u; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint High32Bits(ulong a) - { - return (uint)(a >> 32); - } - - [StackTraceHidden] - private static long LongMultiplyOverflow(long i, long j) - { -#if DEBUG - long result = i * j; -#endif - - // Remember the sign of the result - int sign = (int)(High32Bits((ulong)i) ^ High32Bits((ulong)j)); - - // Convert to unsigned multiplication - if (i < 0) i = -i; - if (j < 0) j = -j; - - // Get the upper 32 bits of the numbers - uint val1High = High32Bits((ulong)i); - uint val2High = High32Bits((ulong)j); - - ulong valMid; - - if (val1High == 0) - { - // Compute the 'middle' bits of the long multiplication - valMid = BigMul(val2High, (uint)i); - } - else - { - if (val2High != 0) - goto Overflow; - // Compute the 'middle' bits of the long multiplication - valMid = BigMul(val1High, (uint)j); - } - - // See if any bits after bit 32 are set - if (High32Bits(valMid) != 0) - goto Overflow; - - long ret = (long)(BigMul((uint)i, (uint)j) + (valMid << 32)); - - // check for overflow - if (High32Bits((ulong)ret) < (uint)valMid) - goto Overflow; - - if (sign >= 0) - { - // have we spilled into the sign bit? - if (ret < 0) - goto Overflow; - } - else - { - ret = -ret; - // have we spilled into the sign bit? - if (ret > 0) - goto Overflow; - } - -#if DEBUG - Debug.Assert(ret == result, $"Multiply overflow got: {ret}, expected: {result}"); -#endif - return ret; - - Overflow: - ThrowHelper.ThrowOverflowException(); - return 0; - } - - [StackTraceHidden] - private static ulong ULongMultiplyOverflow(ulong i, ulong j) - { - // Get the upper 32 bits of the numbers - uint val1High = High32Bits(i); - uint val2High = High32Bits(j); - - ulong valMid; - - if (val1High == 0) - { - if (val2High == 0) - return BigMul((uint)i, (uint)j); - // Compute the 'middle' bits of the long multiplication - valMid = BigMul(val2High, (uint)i); - } - else - { - if (val2High != 0) - goto Overflow; - // Compute the 'middle' bits of the long multiplication - valMid = BigMul(val1High, (uint)j); - } - - // See if any bits after bit 32 are set - if (High32Bits(valMid) != 0) - goto Overflow; - - ulong ret = BigMul((uint)i, (uint)j) + (valMid << 32); - - // check for overflow - if (High32Bits(ret) < (uint)valMid) - goto Overflow; - - Debug.Assert(ret == i * j, $"Multiply overflow got: {ret}, expected: {i * j}"); - return ret; - - Overflow: - ThrowHelper.ThrowOverflowException(); - return 0; - } - - private const double IntMaxValueOffset = 2147483648.0; // 2^31, int.MaxValue + 1 - private const double UIntMaxValueOffset = 4294967296.0; // 2^32, uint.MaxValue + 1 - private static ref double DoubleConversionTable => ref MemoryMarshal.GetReference([0.0, UIntMaxValueOffset]); - - private static double LongToDouble(long val) - { - uint upper = (uint)(val >>> 32); - uint lower = (uint)val; - double a = (int)upper; - // X86 has no uint -> double casts, we need to do this to avoid recursion here -#if TARGET_X86 - double b = (int)lower; - b += Unsafe.Add(ref DoubleConversionTable, lower >> 31); -#else - double b = lower; -#endif - return a * UIntMaxValueOffset + b; - } - - private static double ULongToDouble(ulong val) - { - uint upper = (uint)(val >> 32); - uint lower = (uint)val; - // X86 has no uint -> double casts, we need to do this to avoid recursion here -#if TARGET_X86 - double a = (int)upper; - double b = (int)lower; - a += Unsafe.Add(ref DoubleConversionTable, upper >> 31); - b += Unsafe.Add(ref DoubleConversionTable, lower >> 31); -#else - double a = upper; - double b = lower; -#endif - return a * UIntMaxValueOffset + b; - } - - private static ulong DoubleToULong(double val) - { - const double two63 = IntMaxValueOffset * UIntMaxValueOffset; - ulong ret; - // don't remove the double casts, the runtime would call this method recursively without them - if (val < two63) - { - ret = (ulong)(long)val; - } - else - { - // subtract 0x8000000000000000, do the convert then add it back again - ret = (ulong)(long)(val - two63) + 0x8000000000000000UL; - } - return ret; - } - - [StackTraceHidden] - private static int DoubleToIntOverflow(double val) - { - // Note that this expression also works properly for val = NaN case - if (val is > -IntMaxValueOffset - 1 and < IntMaxValueOffset) - { - int ret = (int)val; - // since no overflow can occur, the value always has to be within 1 - Debug.Assert(val - 1.0 <= ret); - Debug.Assert(ret <= val + 1.0); - return ret; - } - - ThrowHelper.ThrowOverflowException(); - return 0; - } - - [StackTraceHidden] - private static uint DoubleToUIntOverflow(double val) - { - // Note that this expression also works properly for val = NaN case - if (val is > -1.0 and < UIntMaxValueOffset) - { - uint ret = (uint)val; - // since no overflow can occur, the value always has to be within 1 - Debug.Assert(val - 1.0 <= ret); - Debug.Assert(ret <= val + 1.0); - return ret; - } - - ThrowHelper.ThrowOverflowException(); - return 0; - } - - [StackTraceHidden] - private static long DoubleToLongOverflow(double val) - { - const double two63 = IntMaxValueOffset * UIntMaxValueOffset; - - // Note that this expression also works properly for val = NaN case - // We need to compare with the very next double to two63. 0x402 is epsilon to get us there. - if (val is > -two63 - 0x402 and < two63) - { - long ret = (long)val; - // since no overflow can occur, the value always has to be within 1 - Debug.Assert(val - 1.0 <= ret); - Debug.Assert(ret <= val + 1.0); - return ret; - } - - ThrowHelper.ThrowOverflowException(); - return 0; - } - - [StackTraceHidden] - private static ulong DoubleToULongOverflow(double val) - { - const double two64 = UIntMaxValueOffset * UIntMaxValueOffset; - // Note that this expression also works properly for val = NaN case - if (val is > -1.0 and < two64) - { - ulong ret = (ulong)val; - // since no overflow can occur, the value always has to be within 1 - Debug.Assert(val - 1.0 <= ret); - Debug.Assert(ret <= val + 1.0); - return ret; - } - - ThrowHelper.ThrowOverflowException(); - return 0; - } - - private static double DoubleReminder(double dividend, double divisor) - { - // From the ECMA standard: - // - // If [divisor] is zero or [dividend] is infinity - // the result is NaN. - // If [divisor] is infinity, - // the result is [dividend] (negated for -infinity***). - // - // ***"negated for -infinity" has been removed from the spec - if (divisor == 0 || !double.IsFinite(dividend)) - { - return double.NaN; - } - - if (!double.IsFinite(divisor) && !double.IsNaN(divisor)) - { - return dividend; - } - - return FMod(dividend, divisor); - } - - // this helper is currently unused, it's only kept for R2R compatibility for now - // don't remove the double cast, the runtime would call the method recursively without it - private static int DoubleToInt(double val) => (int)(long)val; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/MathF.cs b/src/libraries/System.Private.CoreLib/src/System/MathF.cs index d58e059d26c26..cc0795255d0c8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/MathF.cs +++ b/src/libraries/System.Private.CoreLib/src/System/MathF.cs @@ -511,28 +511,5 @@ public static float ScaleB(float x, int n) float u = BitConverter.Int32BitsToSingle(((int)(0x7f + n) << 23)); return y * u; } - - private static float FloatReminder(float dividend, float divisor) - { - // From the ECMA standard: - // - // If [divisor] is zero or [dividend] is infinity - // the result is NaN. - // If [divisor] is infinity, - // the result is [dividend] (negated for -infinity***). - // - // ***"negated for -infinity" has been removed from the spec - if (divisor == 0 || !float.IsFinite(dividend)) - { - return float.NaN; - } - - if (!float.IsFinite(divisor) && !float.IsNaN(divisor)) - { - return dividend; - } - - return FMod(dividend, divisor); - } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Single.cs b/src/libraries/System.Private.CoreLib/src/System/Single.cs index 9cc7c6b56c0ad..309dfe3d1879e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Single.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Single.cs @@ -435,6 +435,33 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro return Number.TryParseFloat(s, style, NumberFormatInfo.GetInstance(provider), out result); } + // + // Helpers, those methods are referenced from the JIT + // + + private static float Reminder(float dividend, float divisor) + { + // From the ECMA standard: + // + // If [divisor] is zero or [dividend] is infinity + // the result is NaN. + // If [divisor] is infinity, + // the result is [dividend] (negated for -infinity***). + // + // ***"negated for -infinity" has been removed from the spec + if (divisor == 0 || !IsFinite(dividend)) + { + return float.NaN; + } + + if (!IsFinite(divisor) && !IsNaN(divisor)) + { + return dividend; + } + + return MathF.FMod(dividend, divisor); + } + // // IConvertible implementation // diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt64.cs b/src/libraries/System.Private.CoreLib/src/System/UInt64.cs index dc12c5c006a82..e03c340f270f2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt64.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Buffers.Binary; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Numerics; @@ -176,6 +177,58 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } + // + // Helpers, those methods are referenced from the JIT + // + + [StackTraceHidden] + private static ulong MultiplyOverflow(ulong i, ulong j) + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static uint High32Bits(ulong a) + { + return (uint)(a >> 32); + } + + // Get the upper 32 bits of the numbers + uint val1High = High32Bits(i); + uint val2High = High32Bits(j); + + ulong valMid; + + if (val1High == 0) + { + if (val2High == 0) + return Math.BigMul((uint)i, (uint)j); + // Compute the 'middle' bits of the long multiplication + valMid = Math.BigMul(val2High, (uint)i); + } + else + { + if (val2High != 0) + goto Overflow; + // Compute the 'middle' bits of the long multiplication + valMid = Math.BigMul(val1High, (uint)j); + } + + // See if any bits after bit 32 are set + if (High32Bits(valMid) != 0) + goto Overflow; + + ulong ret = Math.BigMul((uint)i, (uint)j) + (valMid << 32); + + // check for overflow + if (High32Bits(ret) < (uint)valMid) + goto Overflow; + + Debug.Assert(ret == i * j, $"Multiply overflow got: {ret}, expected: {i * j}"); + return ret; + + Overflow: + ThrowHelper.ThrowOverflowException(); + return 0; + } + // // IConvertible implementation // diff --git a/src/mono/System.Private.CoreLib/src/System/Math.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Math.Mono.cs index eb0024f983e64..a4b691e8b7946 100644 --- a/src/mono/System.Private.CoreLib/src/System/Math.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Math.Mono.cs @@ -80,7 +80,7 @@ public partial class Math public static extern double Log2(double x); [MethodImpl(MethodImplOptions.InternalCall)] - private static extern double FMod(double x, double y); + internal static extern double FMod(double x, double y); [MethodImpl(MethodImplOptions.InternalCall)] private static extern unsafe double ModF(double x, double* intptr); diff --git a/src/mono/System.Private.CoreLib/src/System/MathF.Mono.cs b/src/mono/System.Private.CoreLib/src/System/MathF.Mono.cs index 4fd4dc614458b..1e6ab8155d148 100644 --- a/src/mono/System.Private.CoreLib/src/System/MathF.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/MathF.Mono.cs @@ -80,7 +80,7 @@ public partial class MathF public static extern float Log2(float x); [MethodImpl(MethodImplOptions.InternalCall)] - private static extern float FMod(float x, float y); + internal static extern float FMod(float x, float y); [MethodImpl(MethodImplOptions.InternalCall)] private static extern unsafe float ModF(float x, float* intptr); From 070beaddbf7b10587fa63bd27c05592509889359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Wed, 13 Mar 2024 21:46:45 +0100 Subject: [PATCH 14/29] Remove the using --- src/libraries/System.Private.CoreLib/src/System/Math.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index 73944ed3341de..60a638198f8f6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -9,7 +9,6 @@ using System.Diagnostics.CodeAnalysis; using System.Numerics; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; From d4fd66da3efde2d1c99cfcc21f0e2ccfc020421b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Wed, 13 Mar 2024 23:08:54 +0100 Subject: [PATCH 15/29] Fix typos --- .../tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs | 6 +++--- src/coreclr/vm/corelib.h | 4 ++-- src/coreclr/vm/ecall.cpp | 4 ++-- src/libraries/System.Private.CoreLib/src/System/Double.cs | 2 +- src/libraries/System.Private.CoreLib/src/System/Single.cs | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs index cb771c947895e..b0236385037fd 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs @@ -178,7 +178,7 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToUInt32Overflow", null); break; case ReadyToRunHelper.Dbl2LngOvf: - methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToInt64gOverflow", null); + methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToInt64Overflow", null); break; case ReadyToRunHelper.Dbl2ULngOvf: methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToUInt64Overflow", null); @@ -192,10 +192,10 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, break; case ReadyToRunHelper.DblRem: - methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("Reminder", null); + methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("Remainder", null); break; case ReadyToRunHelper.FltRem: - methodDesc = context.SystemModule.GetKnownType("System", "Single").GetKnownMethod("Reminder", null); + methodDesc = context.SystemModule.GetKnownType("System", "Single").GetKnownMethod("Remainder", null); break; case ReadyToRunHelper.LMulOfv: diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 9b142e43c7caa..63518357d2f6f 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -268,10 +268,10 @@ DEFINE_METHOD(DOUBLE_SPC, CONVERT_TO_INT64_OVERFLOW,ConvertToInt64Over DEFINE_METHOD(DOUBLE_SPC, CONVERT_TO_UINT64_OVERFLOW,ConvertToUInt64Overflow, NoSig) DEFINE_METHOD(DOUBLE_SPC, CONVERT_FROM_INT64, ConvertFromInt64, NoSig) DEFINE_METHOD(DOUBLE_SPC, CONVERT_FROM_UINT64, ConvertFromUInt64, NoSig) -DEFINE_METHOD(DOUBLE_SPC, REMINDER, Reminder, NoSig) +DEFINE_METHOD(DOUBLE_SPC, REMAINDER, Remainder, NoSig) DEFINE_CLASS(SINGLE_SPC, System, Single) -DEFINE_METHOD(SINGLE_SPC, REMINDER, Reminder, NoSig) +DEFINE_METHOD(SINGLE_SPC, REMAINDER, Remainder, NoSig) DEFINE_CLASS(INT64_SPC, System, Int64) DEFINE_METHOD(INT64_SPC, MULTIPLY_OVERFLOW, MultiplyOverflow, NoSig) diff --git a/src/coreclr/vm/ecall.cpp b/src/coreclr/vm/ecall.cpp index ad6dd047bbc1a..28533ba901777 100644 --- a/src/coreclr/vm/ecall.cpp +++ b/src/coreclr/vm/ecall.cpp @@ -189,11 +189,11 @@ void ECall::PopulateManagedHelpers() pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_ULNG2DBL, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE_SPC__REMINDER)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE_SPC__REMAINDER)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBLREM, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__SINGLE_SPC__REMINDER)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__SINGLE_SPC__REMAINDER)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_FLTREM, pDest); diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs index 71766a8b355f5..5226761a85ff7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Double.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs @@ -573,7 +573,7 @@ private static double ConvertFromUInt64(ulong val) return a * UIntMaxValueOffset + b; } - private static double Reminder(double dividend, double divisor) + private static double Remainder(double dividend, double divisor) { // From the ECMA standard: // diff --git a/src/libraries/System.Private.CoreLib/src/System/Single.cs b/src/libraries/System.Private.CoreLib/src/System/Single.cs index 309dfe3d1879e..c02d9d39d111d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Single.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Single.cs @@ -439,7 +439,7 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro // Helpers, those methods are referenced from the JIT // - private static float Reminder(float dividend, float divisor) + private static float Remainder(float dividend, float divisor) { // From the ECMA standard: // From 8efe9ebdb5180899db34c35ef99685dbc1c921af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Thu, 14 Mar 2024 18:58:26 +0100 Subject: [PATCH 16/29] Rename defined and helper --- src/coreclr/vm/corelib.h | 46 +++++++++++++++---------- src/coreclr/vm/ecall.cpp | 24 ++++++------- src/coreclr/vm/i386/jithelp.S | 17 ++++----- src/coreclr/vm/i386/jithelp.asm | 17 ++++----- src/coreclr/vm/i386/jitinterfacex86.cpp | 4 +-- 5 files changed, 59 insertions(+), 49 deletions(-) diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 63518357d2f6f..24c8fdea7a8d0 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -259,25 +259,33 @@ DEFINE_FIELD(DELEGATE, METHOD_PTR_AUX, _methodPtrAux) DEFINE_METHOD(DELEGATE, CONSTRUCT_DELEGATE, DelegateConstruct, IM_Obj_IntPtr_RetVoid) DEFINE_METHOD(DELEGATE, GET_INVOKE_METHOD, GetInvokeMethod, IM_RetIntPtr) -DEFINE_CLASS(DOUBLE_SPC, System, Double) -DEFINE_METHOD(DOUBLE_SPC, CONVERT_TO_INT32, ConvertToInt32, NoSig) -DEFINE_METHOD(DOUBLE_SPC, CONVERT_TO_UINT64, ConvertToUInt64, NoSig) -DEFINE_METHOD(DOUBLE_SPC, CONVERT_TO_INT32_OVERFLOW,ConvertToInt32Overflow, NoSig) -DEFINE_METHOD(DOUBLE_SPC, CONVERT_TO_UINT32_OVERFLOW,ConvertToUInt32Overflow, NoSig) -DEFINE_METHOD(DOUBLE_SPC, CONVERT_TO_INT64_OVERFLOW,ConvertToInt64Overflow, NoSig) -DEFINE_METHOD(DOUBLE_SPC, CONVERT_TO_UINT64_OVERFLOW,ConvertToUInt64Overflow, NoSig) -DEFINE_METHOD(DOUBLE_SPC, CONVERT_FROM_INT64, ConvertFromInt64, NoSig) -DEFINE_METHOD(DOUBLE_SPC, CONVERT_FROM_UINT64, ConvertFromUInt64, NoSig) -DEFINE_METHOD(DOUBLE_SPC, REMAINDER, Remainder, NoSig) - -DEFINE_CLASS(SINGLE_SPC, System, Single) -DEFINE_METHOD(SINGLE_SPC, REMAINDER, Remainder, NoSig) - -DEFINE_CLASS(INT64_SPC, System, Int64) -DEFINE_METHOD(INT64_SPC, MULTIPLY_OVERFLOW, MultiplyOverflow, NoSig) - -DEFINE_CLASS(UINT64_SPC, System, UInt64) -DEFINE_METHOD(UINT64_SPC, MULTIPLY_OVERFLOW, MultiplyOverflow, NoSig) +#ifdef FOR_ILLINK +DEFINE_CLASS(DOUBLE, System, Double) +#endif +DEFINE_METHOD(DOUBLE, CONVERT_TO_INT32, ConvertToInt32, NoSig) +DEFINE_METHOD(DOUBLE, CONVERT_TO_UINT64, ConvertToUInt64, NoSig) +DEFINE_METHOD(DOUBLE, CONVERT_TO_INT32_OVERFLOW,ConvertToInt32Overflow, NoSig) +DEFINE_METHOD(DOUBLE, CONVERT_TO_UINT32_OVERFLOW,ConvertToUInt32Overflow, NoSig) +DEFINE_METHOD(DOUBLE, CONVERT_TO_INT64_OVERFLOW,ConvertToInt64Overflow, NoSig) +DEFINE_METHOD(DOUBLE, CONVERT_TO_UINT64_OVERFLOW,ConvertToUInt64Overflow, NoSig) +DEFINE_METHOD(DOUBLE, CONVERT_FROM_INT64, ConvertFromInt64, NoSig) +DEFINE_METHOD(DOUBLE, CONVERT_FROM_UINT64, ConvertFromUInt64, NoSig) +DEFINE_METHOD(DOUBLE, REMAINDER, Remainder, NoSig) + +#ifdef FOR_ILLINK +DEFINE_CLASS(SINGLE, System, Single) +#endif +DEFINE_METHOD(SINGLE, REMAINDER, Remainder, NoSig) + +#ifdef FOR_ILLINK +DEFINE_CLASS(INT64, System, Int64) +#endif +DEFINE_METHOD(INT64, MULTIPLY_OVERFLOW, MultiplyOverflow, NoSig) + +#ifdef FOR_ILLINK +DEFINE_CLASS(UINT64, System, UInt64) +#endif +DEFINE_METHOD(UINT64, MULTIPLY_OVERFLOW, MultiplyOverflow, NoSig) DEFINE_CLASS(INT128, System, Int128) DEFINE_CLASS(UINT128, System, UInt128) diff --git a/src/coreclr/vm/ecall.cpp b/src/coreclr/vm/ecall.cpp index 28533ba901777..970653e1a2705 100644 --- a/src/coreclr/vm/ecall.cpp +++ b/src/coreclr/vm/ecall.cpp @@ -157,51 +157,51 @@ void ECall::PopulateManagedHelpers() pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_MEMCPY, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE_SPC__CONVERT_TO_INT32)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE__CONVERT_TO_INT32)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBL2INT, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE_SPC__CONVERT_TO_UINT64)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE__CONVERT_TO_UINT64)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBL2ULNG, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE_SPC__CONVERT_TO_INT32_OVERFLOW)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE__CONVERT_TO_INT32_OVERFLOW)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBL2INT_OVF, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE_SPC__CONVERT_TO_UINT32_OVERFLOW)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE__CONVERT_TO_UINT32_OVERFLOW)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBL2UINT_OVF, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE_SPC__CONVERT_TO_INT64_OVERFLOW)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE__CONVERT_TO_INT64_OVERFLOW)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBL2LNG_OVF, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE_SPC__CONVERT_TO_UINT64_OVERFLOW)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE__CONVERT_TO_UINT64_OVERFLOW)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBL2ULNG_OVF, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE_SPC__CONVERT_FROM_INT64)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE__CONVERT_FROM_INT64)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_LNG2DBL, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE_SPC__CONVERT_FROM_UINT64)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE__CONVERT_FROM_UINT64)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_ULNG2DBL, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE_SPC__REMAINDER)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE__REMAINDER)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBLREM, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__SINGLE_SPC__REMAINDER)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__SINGLE__REMAINDER)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_FLTREM, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__INT64_SPC__MULTIPLY_OVERFLOW)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__INT64__MULTIPLY_OVERFLOW)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_LMUL_OVF, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__UINT64_SPC__MULTIPLY_OVERFLOW)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__UINT64__MULTIPLY_OVERFLOW)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_ULMUL_OVF, pDest); diff --git a/src/coreclr/vm/i386/jithelp.S b/src/coreclr/vm/i386/jithelp.S index 873669bfedde1..8eeb25ae592d3 100644 --- a/src/coreclr/vm/i386/jithelp.S +++ b/src/coreclr/vm/i386/jithelp.S @@ -552,29 +552,30 @@ LOCAL_LABEL(LRszMORE32): LEAF_END JIT_LRsz, _TEXT // *********************************************************************/ -// JIT_Dbl2LngFpu +// JIT_Dbl2LngSse3 // // Purpose: -// converts a double to a long truncating toward zero (C semantics) +// Converts a double to a long truncating toward zero (C semantics) // -// uses stdcall calling conventions +// Uses stdcall calling convention // -// This code is faster than C++ even on modern CPUs but it requires SSE3 +// This code is faster than C++ even on modern CPUs despite using the FPU +// but it requires SSE3 // -LEAF_ENTRY JIT_Dbl2LngFpu, _TEXT +LEAF_ENTRY JIT_Dbl2LngSse3, _TEXT // get some local space sub esp, 8 fld QWORD PTR [esp + 0x0C] // fetch arg - fisttp QWORD PTR [esp] // convert - mov eax, DWORD PTR [esp] // reload FP result + fisttp QWORD PTR [esp] // convert + mov eax, DWORD PTR [esp] // reload FP result mov edx, DWORD PTR [esp + 4] // restore stack add esp, 8 ret -LEAF_END JIT_Dbl2LngFpu, _TEXT +LEAF_END JIT_Dbl2LngSse3, _TEXT // *********************************************************************/ // JIT_StackProbe diff --git a/src/coreclr/vm/i386/jithelp.asm b/src/coreclr/vm/i386/jithelp.asm index 1c8bc129f7d32..c67b7d94c335d 100644 --- a/src/coreclr/vm/i386/jithelp.asm +++ b/src/coreclr/vm/i386/jithelp.asm @@ -36,7 +36,7 @@ JIT_LLsh TEXTEQU <_JIT_LLsh@0> JIT_LRsh TEXTEQU <_JIT_LRsh@0> JIT_LRsz TEXTEQU <_JIT_LRsz@0> JIT_LMul TEXTEQU <@JIT_LMul@16> -JIT_Dbl2LngFpu TEXTEQU <@JIT_Dbl2LngFpu@8> +JIT_Dbl2LngSse3 TEXTEQU <@JIT_Dbl2LngSse3@8> JIT_InternalThrowFromHelper TEXTEQU <@JIT_InternalThrowFromHelper@4> JIT_WriteBarrierReg_PreGrow TEXTEQU <_JIT_WriteBarrierReg_PreGrow@0> JIT_WriteBarrierReg_PostGrow TEXTEQU <_JIT_WriteBarrierReg_PostGrow@0> @@ -634,19 +634,20 @@ LMul_hard: JIT_LMul ENDP ;*********************************************************************/ -; JIT_Dbl2LngFpu +; JIT_Dbl2LngSse3 ; ;Purpose: -; converts a double to a long truncating toward zero (C semantics) +; Converts a double to a long truncating toward zero (C semantics) ; -; uses stdcall calling conventions +; Uses stdcall calling convention ; -; This code is faster than C++ even on modern CPUs but it requires SSE3 +; This code is faster than C++ even on modern CPUs despite using the FPU +; but it requires SSE3 ; .686P .XMM -PUBLIC JIT_Dbl2LngFpu -JIT_Dbl2LngFpu PROC +PUBLIC JIT_Dbl2LngSse3 +JIT_Dbl2LngSse3 PROC arg1 equ <[esp+0Ch]> sub esp, 8 ; get some local space @@ -659,7 +660,7 @@ arg1 equ <[esp+0Ch]> add esp, 8 ; restore stack ret 8 -JIT_Dbl2LngFpu ENDP +JIT_Dbl2LngSse3 ENDP .586 ;*********************************************************************/ diff --git a/src/coreclr/vm/i386/jitinterfacex86.cpp b/src/coreclr/vm/i386/jitinterfacex86.cpp index cd7ee25bdbcec..8e759e6e25753 100644 --- a/src/coreclr/vm/i386/jitinterfacex86.cpp +++ b/src/coreclr/vm/i386/jitinterfacex86.cpp @@ -952,8 +952,8 @@ void InitJITHelpers1() if (dwCPUFeaturesECX & 1) // check SSE3 { - SetJitHelperFunction(CORINFO_HELP_DBL2UINT, JIT_Dbl2LngFpu); - SetJitHelperFunction(CORINFO_HELP_DBL2LNG, JIT_Dbl2LngFpu); + SetJitHelperFunction(CORINFO_HELP_DBL2UINT, JIT_Dbl2LngSse3); + SetJitHelperFunction(CORINFO_HELP_DBL2LNG, JIT_Dbl2LngSse3); } if (!(TrackAllocationsEnabled() From 7943ef7ab5bfd27c75aff19a9016480d241b9f1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Thu, 14 Mar 2024 19:03:08 +0100 Subject: [PATCH 17/29] Update jitinterface.h --- src/coreclr/vm/jitinterface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index f09c0fc899131..fcdcf288f02ba 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -324,7 +324,7 @@ EXTERN_C FCDECL2(Object*, JIT_NewArr1OBJ_MP_InlineGetThread, CORINFO_CLASS_HANDL #endif // HOST_64BIT EXTERN_C FCDECL2_VV(INT64, JIT_LMul, INT64 val1, INT64 val2); -EXTERN_C FCDECL1_V(INT64, JIT_Dbl2LngFpu, double val); +EXTERN_C FCDECL1_V(INT64, JIT_Dbl2LngSse3, double val); #ifndef HOST_64BIT #ifdef TARGET_X86 From 334838b8a5d19fbef465c8f54e168132b0257cb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Thu, 14 Mar 2024 21:35:11 +0100 Subject: [PATCH 18/29] Rename to Checked --- .../aot/ILCompiler.Compiler/Compiler/JitHelper.cs | 12 ++++++------ src/coreclr/vm/corelib.h | 12 ++++++------ src/coreclr/vm/ecall.cpp | 12 ++++++------ .../System.Private.CoreLib/src/System/Double.cs | 8 ++++---- .../System.Private.CoreLib/src/System/Int64.cs | 2 +- .../System.Private.CoreLib/src/System/UInt64.cs | 2 +- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs index b0236385037fd..e85bb00adf8b4 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs @@ -172,16 +172,16 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, break; case ReadyToRunHelper.Dbl2IntOvf: - methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToInt32Overflow", null); + methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToInt32Checked", null); break; case ReadyToRunHelper.Dbl2UIntOvf: - methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToUInt32Overflow", null); + methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToUInt32Checked", null); break; case ReadyToRunHelper.Dbl2LngOvf: - methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToInt64Overflow", null); + methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToInt64Checked", null); break; case ReadyToRunHelper.Dbl2ULngOvf: - methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToUInt64Overflow", null); + methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToUInt64Checked", null); break; case ReadyToRunHelper.Lng2Dbl: @@ -199,10 +199,10 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, break; case ReadyToRunHelper.LMulOfv: - methodDesc = context.SystemModule.GetKnownType("System", "Int64").GetKnownMethod("MultiplyOverflow", null); + methodDesc = context.SystemModule.GetKnownType("System", "Int64").GetKnownMethod("MultiplyChecked", null); break; case ReadyToRunHelper.ULMulOvf: - methodDesc = context.SystemModule.GetKnownType("System", "UInt64").GetKnownMethod("MultiplyOverflow", null); + methodDesc = context.SystemModule.GetKnownType("System", "UInt64").GetKnownMethod("MultiplyChecked", null); break; case ReadyToRunHelper.DblRound: diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 24c8fdea7a8d0..1b06e6de5081b 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -264,10 +264,10 @@ DEFINE_CLASS(DOUBLE, System, Double) #endif DEFINE_METHOD(DOUBLE, CONVERT_TO_INT32, ConvertToInt32, NoSig) DEFINE_METHOD(DOUBLE, CONVERT_TO_UINT64, ConvertToUInt64, NoSig) -DEFINE_METHOD(DOUBLE, CONVERT_TO_INT32_OVERFLOW,ConvertToInt32Overflow, NoSig) -DEFINE_METHOD(DOUBLE, CONVERT_TO_UINT32_OVERFLOW,ConvertToUInt32Overflow, NoSig) -DEFINE_METHOD(DOUBLE, CONVERT_TO_INT64_OVERFLOW,ConvertToInt64Overflow, NoSig) -DEFINE_METHOD(DOUBLE, CONVERT_TO_UINT64_OVERFLOW,ConvertToUInt64Overflow, NoSig) +DEFINE_METHOD(DOUBLE, CONVERT_TO_INT32_CHECKED,ConvertToInt32Checked, NoSig) +DEFINE_METHOD(DOUBLE, CONVERT_TO_UINT32_CHECKED,ConvertToUInt32Checked, NoSig) +DEFINE_METHOD(DOUBLE, CONVERT_TO_INT64_CHECKED,ConvertToInt64Checked, NoSig) +DEFINE_METHOD(DOUBLE, CONVERT_TO_UINT64_CHECKED,ConvertToUInt64Checked, NoSig) DEFINE_METHOD(DOUBLE, CONVERT_FROM_INT64, ConvertFromInt64, NoSig) DEFINE_METHOD(DOUBLE, CONVERT_FROM_UINT64, ConvertFromUInt64, NoSig) DEFINE_METHOD(DOUBLE, REMAINDER, Remainder, NoSig) @@ -280,12 +280,12 @@ DEFINE_METHOD(SINGLE, REMAINDER, Remainder, #ifdef FOR_ILLINK DEFINE_CLASS(INT64, System, Int64) #endif -DEFINE_METHOD(INT64, MULTIPLY_OVERFLOW, MultiplyOverflow, NoSig) +DEFINE_METHOD(INT64, MULTIPLY_CHECKED, MultiplyChecked, NoSig) #ifdef FOR_ILLINK DEFINE_CLASS(UINT64, System, UInt64) #endif -DEFINE_METHOD(UINT64, MULTIPLY_OVERFLOW, MultiplyOverflow, NoSig) +DEFINE_METHOD(UINT64, MULTIPLY_CHECKED, MultiplyChecked, NoSig) DEFINE_CLASS(INT128, System, Int128) DEFINE_CLASS(UINT128, System, UInt128) diff --git a/src/coreclr/vm/ecall.cpp b/src/coreclr/vm/ecall.cpp index 970653e1a2705..577d187f5c908 100644 --- a/src/coreclr/vm/ecall.cpp +++ b/src/coreclr/vm/ecall.cpp @@ -165,19 +165,19 @@ void ECall::PopulateManagedHelpers() pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBL2ULNG, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE__CONVERT_TO_INT32_OVERFLOW)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE__CONVERT_TO_INT32_CHECKED)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBL2INT_OVF, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE__CONVERT_TO_UINT32_OVERFLOW)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE__CONVERT_TO_UINT32_CHECKED)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBL2UINT_OVF, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE__CONVERT_TO_INT64_OVERFLOW)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE__CONVERT_TO_INT64_CHECKED)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBL2LNG_OVF, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE__CONVERT_TO_UINT64_OVERFLOW)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE__CONVERT_TO_UINT64_CHECKED)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBL2ULNG_OVF, pDest); @@ -197,11 +197,11 @@ void ECall::PopulateManagedHelpers() pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_FLTREM, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__INT64__MULTIPLY_OVERFLOW)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__INT64__MULTIPLY_CHECKED)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_LMUL_OVF, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__UINT64__MULTIPLY_OVERFLOW)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__UINT64__MULTIPLY_CHECKED)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_ULMUL_OVF, pDest); diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs index 5226761a85ff7..1c1ab49b6c860 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Double.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs @@ -468,7 +468,7 @@ private static ulong ConvertToUInt64(double val) } [StackTraceHidden] - private static int ConvertToInt32Overflow(double val) + private static int ConvertToInt32Checked(double val) { // Note that this expression also works properly for val = NaN case if (val is > -IntMaxValueOffset - 1 and < IntMaxValueOffset) @@ -485,7 +485,7 @@ private static int ConvertToInt32Overflow(double val) } [StackTraceHidden] - private static uint ConvertToUInt32Overflow(double val) + private static uint ConvertToUInt32Checked(double val) { // Note that this expression also works properly for val = NaN case if (val is > -1.0 and < UIntMaxValueOffset) @@ -502,7 +502,7 @@ private static uint ConvertToUInt32Overflow(double val) } [StackTraceHidden] - private static long ConvertToInt64Overflow(double val) + private static long ConvertToInt64Checked(double val) { const double two63 = IntMaxValueOffset * UIntMaxValueOffset; @@ -522,7 +522,7 @@ private static long ConvertToInt64Overflow(double val) } [StackTraceHidden] - private static ulong ConvertToUInt64Overflow(double val) + private static ulong ConvertToUInt64Checked(double val) { const double two64 = UIntMaxValueOffset * UIntMaxValueOffset; // Note that this expression also works properly for val = NaN case diff --git a/src/libraries/System.Private.CoreLib/src/System/Int64.cs b/src/libraries/System.Private.CoreLib/src/System/Int64.cs index d21ab0ac1a94f..9d8b866141fe9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int64.cs @@ -184,7 +184,7 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro // [StackTraceHidden] - private static long MultiplyOverflow(long i, long j) + private static long MultiplyChecked(long i, long j) { [MethodImpl(MethodImplOptions.AggressiveInlining)] static uint High32Bits(ulong a) diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt64.cs b/src/libraries/System.Private.CoreLib/src/System/UInt64.cs index e03c340f270f2..4650620149684 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt64.cs @@ -182,7 +182,7 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro // [StackTraceHidden] - private static ulong MultiplyOverflow(ulong i, ulong j) + private static ulong MultiplyChecked(ulong i, ulong j) { [MethodImpl(MethodImplOptions.AggressiveInlining)] static uint High32Bits(ulong a) From 1cdcf5e8fb6f2cf7e2f4b5b627c18188a78ec8c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Thu, 14 Mar 2024 22:19:09 +0100 Subject: [PATCH 19/29] Cleanup NativeAOT, fix parameter names --- .../Runtime/CompilerHelpers/MathHelpers.cs | 133 +++++++++--------- .../ILCompiler.Compiler/Compiler/JitHelper.cs | 6 +- .../IL/ILImporter.Scanner.cs | 4 + src/coreclr/vm/corelib.h | 1 + .../src/System/Double.cs | 63 +++++---- .../src/System/Int64.cs | 22 +-- .../src/System/Single.cs | 2 +- .../src/System/UInt64.cs | 16 +-- 8 files changed, 124 insertions(+), 123 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/MathHelpers.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/MathHelpers.cs index f2226c0ff33fb..3b2dd9ad0f279 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/MathHelpers.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/MathHelpers.cs @@ -9,8 +9,7 @@ namespace Internal.Runtime.CompilerHelpers { /// - /// Math helpers for generated code. The helpers marked with [RuntimeExport] and the type - /// itself need to be public because they constitute a public contract with the .NET Native toolchain. + /// Math helpers for generated code. The helpers here are referenced by the runtime. /// internal static partial class MathHelpers { @@ -19,107 +18,107 @@ internal static partial class MathHelpers [LibraryImport(RuntimeLibrary)] [SuppressGCTransition] - private static partial ulong RhpULMod(ulong i, ulong j); + private static partial ulong RhpULMod(ulong dividend, ulong divisor); - public static ulong ULMod(ulong i, ulong j) + public static ulong ULMod(ulong dividend, ulong divisor) { - if (j == 0) - return ThrowULngDivByZero(); - else - return RhpULMod(i, j); + if (divisor == 0) + ThrowULngDivByZero(); + + return RhpULMod(dividend, divisor); } [LibraryImport(RuntimeLibrary)] [SuppressGCTransition] - private static partial long RhpLMod(long i, long j); + private static partial long RhpLMod(long dividend, long divisor); - public static long LMod(long i, long j) + public static long LMod(long dividend, long divisor) { - if (j == 0) - return ThrowLngDivByZero(); - else if (j == -1 && i == long.MinValue) - return ThrowLngOvf(); - else - return RhpLMod(i, j); + if (divisor == 0) + ThrowLngDivByZero(); + if (divisor == -1 && dividend == long.MinValue) + ThrowLngOvf(); + + return RhpLMod(dividend, divisor); } [LibraryImport(RuntimeLibrary)] [SuppressGCTransition] - private static partial ulong RhpULDiv(ulong i, ulong j); + private static partial ulong RhpULDiv(ulong dividend, ulong divisor); - public static ulong ULDiv(ulong i, ulong j) + public static ulong ULDiv(ulong dividend, ulong divisor) { - if (j == 0) - return ThrowULngDivByZero(); - else - return RhpULDiv(i, j); + if (divisor == 0) + ThrowULngDivByZero(); + + return RhpULDiv(dividend, divisor); } [LibraryImport(RuntimeLibrary)] [SuppressGCTransition] - private static partial long RhpLDiv(long i, long j); + private static partial long RhpLDiv(long dividend, long divisor); - public static long LDiv(long i, long j) + public static long LDiv(long dividend, long divisor) { - if (j == 0) - return ThrowLngDivByZero(); - else if (j == -1 && i == long.MinValue) - return ThrowLngOvf(); - else - return RhpLDiv(i, j); + if (divisor == 0) + ThrowLngDivByZero(); + if (divisor == -1 && dividend == long.MinValue) + ThrowLngOvf(); + + return RhpLDiv(dividend, divisor); } #if TARGET_ARM [RuntimeImport(RuntimeLibrary, "RhpIDiv")] [MethodImpl(MethodImplOptions.InternalCall)] - private static extern int RhpIDiv(int i, int j); + private static extern int RhpIDiv(int dividend, int j); - public static int IDiv(int i, int j) + public static int IDiv(int dividend, int divisor) { - if (j == 0) - return ThrowIntDivByZero(); - else if (j == -1 && i == int.MinValue) - return ThrowIntOvf(); - else - return RhpIDiv(i, j); + if (divisor == 0) + ThrowIntDivByZero(); + if (divisor == -1 && dividend == int.MinValue) + ThrowIntOvf(); + + return RhpIDiv(dividend, divisor); } [RuntimeImport(RuntimeLibrary, "RhpUDiv")] [MethodImpl(MethodImplOptions.InternalCall)] - private static extern uint RhpUDiv(uint i, uint j); + private static extern uint RhpUDiv(uint dividend, uint divisor); - public static long UDiv(uint i, uint j) + public static long UDiv(uint dividend, uint divisor) { - if (j == 0) - return ThrowUIntDivByZero(); - else - return RhpUDiv(i, j); + if (divisor == 0) + ThrowUIntDivByZero(); + + return RhpUDiv(dividend, divisor); } [RuntimeImport(RuntimeLibrary, "RhpIMod")] [MethodImpl(MethodImplOptions.InternalCall)] - private static extern int RhpIMod(int i, int j); + private static extern int RhpIMod(int dividend, int divisor); - public static int IMod(int i, int j) + public static int IMod(int dividend, int divisor) { - if (j == 0) - return ThrowIntDivByZero(); - else if (j == -1 && i == int.MinValue) - return ThrowIntOvf(); - else - return RhpIMod(i, j); + if (divisor == 0) + ThrowIntDivByZero(); + if (divisor == -1 && dividend == int.MinValue) + ThrowIntOvf(); + + return RhpIMod(dividend, divisor); } [RuntimeImport(RuntimeLibrary, "RhpUMod")] [MethodImpl(MethodImplOptions.InternalCall)] - private static extern uint RhpUMod(uint i, uint j); + private static extern uint RhpUMod(uint dividend, uint divisor); - public static long UMod(uint i, uint j) + public static long UMod(uint dividend, uint divisor) { - if (j == 0) - return ThrowUIntDivByZero(); - else - return RhpUMod(i, j); + if (divisor == 0) + ThrowUIntDivByZero(); + + return RhpUMod(dividend, divisor); } #endif // TARGET_ARM @@ -127,39 +126,33 @@ public static long UMod(uint i, uint j) // Matching return types of throw helpers enables tailcalling them. It improves performance // of the hot path because of it does not need to raise full stackframe. // - [MethodImpl(MethodImplOptions.NoInlining)] - private static long ThrowLngOvf() + private static void ThrowLngOvf() { throw new OverflowException(); } - [MethodImpl(MethodImplOptions.NoInlining)] - private static long ThrowLngDivByZero() + private static void ThrowLngDivByZero() { throw new DivideByZeroException(); } - [MethodImpl(MethodImplOptions.NoInlining)] - private static ulong ThrowULngDivByZero() + private static void ThrowULngDivByZero() { throw new DivideByZeroException(); } #if TARGET_ARM - [MethodImpl(MethodImplOptions.NoInlining)] - private static int ThrowIntOvf() + private static void ThrowIntOvf() { throw new OverflowException(); } - [MethodImpl(MethodImplOptions.NoInlining)] - private static int ThrowIntDivByZero() + private static void ThrowIntDivByZero() { throw new DivideByZeroException(); } - [MethodImpl(MethodImplOptions.NoInlining)] - private static uint ThrowUIntDivByZero() + private static void ThrowUIntDivByZero() { throw new DivideByZeroException(); } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs index e85bb00adf8b4..bfe286c17d0c2 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs @@ -167,6 +167,9 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, case ReadyToRunHelper.Dbl2Int: methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToInt32", null); break; + case ReadyToRunHelper.Dbl2UInt: + methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToUInt32", null); + break; case ReadyToRunHelper.Dbl2ULng: methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToUInt64", null); break; @@ -219,9 +222,6 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, case ReadyToRunHelper.Dbl2Lng: mangledName = "RhpDbl2Lng"; break; - case ReadyToRunHelper.Dbl2UInt: - mangledName = "RhpDbl2Lng"; - break; case ReadyToRunHelper.LMul: mangledName = "RhpLMul"; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs index d6d6f5259ad95..e09c32809ce1c 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs @@ -1290,6 +1290,10 @@ private void ImportConvert(WellKnownType wellKnownType, bool checkOverflow, bool { _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Dbl2UIntOvf), "conv_u4_ovf"); } + else + { + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Dbl2UInt), "conv_u4"); + } break; case WellKnownType.UInt64: if (checkOverflow) diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 1b06e6de5081b..f4fbcf63214c6 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -263,6 +263,7 @@ DEFINE_METHOD(DELEGATE, GET_INVOKE_METHOD, GetInvokeMethod, DEFINE_CLASS(DOUBLE, System, Double) #endif DEFINE_METHOD(DOUBLE, CONVERT_TO_INT32, ConvertToInt32, NoSig) +DEFINE_METHOD(DOUBLE, CONVERT_TO_UINT32, ConvertToUInt32, NoSig) DEFINE_METHOD(DOUBLE, CONVERT_TO_UINT64, ConvertToUInt64, NoSig) DEFINE_METHOD(DOUBLE, CONVERT_TO_INT32_CHECKED,ConvertToInt32Checked, NoSig) DEFINE_METHOD(DOUBLE, CONVERT_TO_UINT32_CHECKED,ConvertToUInt32Checked, NoSig) diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs index 1c1ab49b6c860..fe7a2caaea291 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Double.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs @@ -448,35 +448,36 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro private const double UIntMaxValueOffset = 4294967296.0; // 2^32, uint.MaxValue + 1 // TODO: make the helpers saturating when implementing https://github.com/dotnet/runtime/issues/61885 - private static int ConvertToInt32(double val) => (int)(long)val; + private static int ConvertToInt32(double value) => (int)(long)value; + private static uint ConvertToUInt32(double value) => (uint)(long)value; - private static ulong ConvertToUInt64(double val) + private static ulong ConvertToUInt64(double value) { const double two63 = IntMaxValueOffset * UIntMaxValueOffset; ulong ret; // don't remove the double casts, the runtime would call this method recursively without them - if (val < two63) + if (value < two63) { - ret = (ulong)(long)val; + ret = (ulong)(long)value; } else { // subtract 0x8000000000000000, do the convert then add it back again - ret = (ulong)(long)(val - two63) + 0x8000000000000000UL; + ret = (ulong)(long)(value - two63) + 0x8000000000000000UL; } return ret; } [StackTraceHidden] - private static int ConvertToInt32Checked(double val) + private static int ConvertToInt32Checked(double value) { // Note that this expression also works properly for val = NaN case - if (val is > -IntMaxValueOffset - 1 and < IntMaxValueOffset) + if (value is > -IntMaxValueOffset - 1 and < IntMaxValueOffset) { - int ret = (int)val; + int ret = (int)value; // since no overflow can occur, the value always has to be within 1 - Debug.Assert(val - 1.0 <= ret); - Debug.Assert(ret <= val + 1.0); + Debug.Assert(value - 1.0 <= ret); + Debug.Assert(ret <= value + 1.0); return ret; } @@ -485,15 +486,15 @@ private static int ConvertToInt32Checked(double val) } [StackTraceHidden] - private static uint ConvertToUInt32Checked(double val) + private static uint ConvertToUInt32Checked(double value) { // Note that this expression also works properly for val = NaN case - if (val is > -1.0 and < UIntMaxValueOffset) + if (value is > -1.0 and < UIntMaxValueOffset) { - uint ret = (uint)val; + uint ret = (uint)value; // since no overflow can occur, the value always has to be within 1 - Debug.Assert(val - 1.0 <= ret); - Debug.Assert(ret <= val + 1.0); + Debug.Assert(value - 1.0 <= ret); + Debug.Assert(ret <= value + 1.0); return ret; } @@ -502,18 +503,18 @@ private static uint ConvertToUInt32Checked(double val) } [StackTraceHidden] - private static long ConvertToInt64Checked(double val) + private static long ConvertToInt64Checked(double value) { const double two63 = IntMaxValueOffset * UIntMaxValueOffset; // Note that this expression also works properly for val = NaN case // We need to compare with the very next double to two63. 0x402 is epsilon to get us there. - if (val is > -two63 - 0x402 and < two63) + if (value is > -two63 - 0x402 and < two63) { - long ret = (long)val; + long ret = (long)value; // since no overflow can occur, the value always has to be within 1 - Debug.Assert(val - 1.0 <= ret); - Debug.Assert(ret <= val + 1.0); + Debug.Assert(value - 1.0 <= ret); + Debug.Assert(ret <= value + 1.0); return ret; } @@ -522,16 +523,16 @@ private static long ConvertToInt64Checked(double val) } [StackTraceHidden] - private static ulong ConvertToUInt64Checked(double val) + private static ulong ConvertToUInt64Checked(double value) { const double two64 = UIntMaxValueOffset * UIntMaxValueOffset; // Note that this expression also works properly for val = NaN case - if (val is > -1.0 and < two64) + if (value is > -1.0 and < two64) { - ulong ret = (ulong)val; + ulong ret = (ulong)value; // since no overflow can occur, the value always has to be within 1 - Debug.Assert(val - 1.0 <= ret); - Debug.Assert(ret <= val + 1.0); + Debug.Assert(value - 1.0 <= ret); + Debug.Assert(ret <= value + 1.0); return ret; } @@ -541,10 +542,10 @@ private static ulong ConvertToUInt64Checked(double val) private static ref double DoubleConversionTable => ref MemoryMarshal.GetReference([0.0, UIntMaxValueOffset]); - private static double ConvertFromInt64(long val) + private static double ConvertFromInt64(long value) { - uint upper = (uint)(val >>> 32); - uint lower = (uint)val; + uint upper = (uint)(value >>> 32); + uint lower = (uint)value; double a = (int)upper; // X86 has no uint -> double casts, we need to do this to avoid recursion here #if TARGET_X86 @@ -556,10 +557,10 @@ private static double ConvertFromInt64(long val) return a * UIntMaxValueOffset + b; } - private static double ConvertFromUInt64(ulong val) + private static double ConvertFromUInt64(ulong value) { - uint upper = (uint)(val >> 32); - uint lower = (uint)val; + uint upper = (uint)(value >> 32); + uint lower = (uint)value; // X86 has no uint -> double casts, we need to do this to avoid recursion here #if TARGET_X86 double a = (int)upper; diff --git a/src/libraries/System.Private.CoreLib/src/System/Int64.cs b/src/libraries/System.Private.CoreLib/src/System/Int64.cs index 9d8b866141fe9..f7661fcc93fe0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int64.cs @@ -184,7 +184,7 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro // [StackTraceHidden] - private static long MultiplyChecked(long i, long j) + private static long MultiplyChecked(long left, long right) { [MethodImpl(MethodImplOptions.AggressiveInlining)] static uint High32Bits(ulong a) @@ -193,40 +193,42 @@ static uint High32Bits(ulong a) } #if DEBUG - long result = i * j; + long result = left * right; #endif // Remember the sign of the result - int sign = (int)(High32Bits((ulong)i) ^ High32Bits((ulong)j)); + int sign = (int)(High32Bits((ulong)left) ^ High32Bits((ulong)right)); // Convert to unsigned multiplication - if (i < 0) i = -i; - if (j < 0) j = -j; + if (left < 0) + left = -left; + if (right < 0) + right = -right; // Get the upper 32 bits of the numbers - uint val1High = High32Bits((ulong)i); - uint val2High = High32Bits((ulong)j); + uint val1High = High32Bits((ulong)left); + uint val2High = High32Bits((ulong)right); ulong valMid; if (val1High == 0) { // Compute the 'middle' bits of the long multiplication - valMid = Math.BigMul(val2High, (uint)i); + valMid = Math.BigMul(val2High, (uint)left); } else { if (val2High != 0) goto Overflow; // Compute the 'middle' bits of the long multiplication - valMid = Math.BigMul(val1High, (uint)j); + valMid = Math.BigMul(val1High, (uint)right); } // See if any bits after bit 32 are set if (High32Bits(valMid) != 0) goto Overflow; - long ret = (long)(Math.BigMul((uint)i, (uint)j) + (valMid << 32)); + long ret = (long)(Math.BigMul((uint)left, (uint)right) + (valMid << 32)); // check for overflow if (High32Bits((ulong)ret) < (uint)valMid) diff --git a/src/libraries/System.Private.CoreLib/src/System/Single.cs b/src/libraries/System.Private.CoreLib/src/System/Single.cs index c02d9d39d111d..cee3c004573b4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Single.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Single.cs @@ -451,7 +451,7 @@ private static float Remainder(float dividend, float divisor) // ***"negated for -infinity" has been removed from the spec if (divisor == 0 || !IsFinite(dividend)) { - return float.NaN; + return NaN; } if (!IsFinite(divisor) && !IsNaN(divisor)) diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt64.cs b/src/libraries/System.Private.CoreLib/src/System/UInt64.cs index 4650620149684..f3ff6903aa24a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt64.cs @@ -182,7 +182,7 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro // [StackTraceHidden] - private static ulong MultiplyChecked(ulong i, ulong j) + private static ulong MultiplyChecked(ulong left, ulong right) { [MethodImpl(MethodImplOptions.AggressiveInlining)] static uint High32Bits(ulong a) @@ -191,37 +191,37 @@ static uint High32Bits(ulong a) } // Get the upper 32 bits of the numbers - uint val1High = High32Bits(i); - uint val2High = High32Bits(j); + uint val1High = High32Bits(left); + uint val2High = High32Bits(right); ulong valMid; if (val1High == 0) { if (val2High == 0) - return Math.BigMul((uint)i, (uint)j); + return Math.BigMul((uint)left, (uint)right); // Compute the 'middle' bits of the long multiplication - valMid = Math.BigMul(val2High, (uint)i); + valMid = Math.BigMul(val2High, (uint)left); } else { if (val2High != 0) goto Overflow; // Compute the 'middle' bits of the long multiplication - valMid = Math.BigMul(val1High, (uint)j); + valMid = Math.BigMul(val1High, (uint)right); } // See if any bits after bit 32 are set if (High32Bits(valMid) != 0) goto Overflow; - ulong ret = Math.BigMul((uint)i, (uint)j) + (valMid << 32); + ulong ret = Math.BigMul((uint)left, (uint)right) + (valMid << 32); // check for overflow if (High32Bits(ret) < (uint)valMid) goto Overflow; - Debug.Assert(ret == i * j, $"Multiply overflow got: {ret}, expected: {i * j}"); + Debug.Assert(ret == left * right, $"Multiply overflow got: {ret}, expected: {left * right}"); return ret; Overflow: From e22180988ecea321b85444edec11f20ee808b1e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Thu, 14 Mar 2024 22:22:09 +0100 Subject: [PATCH 20/29] Update jitinterface.cpp --- src/coreclr/vm/jitinterface.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index bfc3b0efee456..cdabb28c24fe0 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -10715,18 +10715,19 @@ void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */ dynamicFtnNum == DYNAMIC_CORINFO_HELP_MEMSET || dynamicFtnNum == DYNAMIC_CORINFO_HELP_MEMZERO || dynamicFtnNum == DYNAMIC_CORINFO_HELP_MEMCPY || - dynamicFtnNum == DYNAMIC_CORINFO_HELP_LMUL_OVF || - dynamicFtnNum == DYNAMIC_CORINFO_HELP_ULMUL_OVF || - dynamicFtnNum == DYNAMIC_CORINFO_HELP_LNG2DBL || - dynamicFtnNum == DYNAMIC_CORINFO_HELP_ULNG2DBL || - dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2ULNG || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2INT || + dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2UINT || + dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2ULNG || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2INT_OVF || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2UINT_OVF || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2LNG_OVF || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2ULNG_OVF || + dynamicFtnNum == DYNAMIC_CORINFO_HELP_LNG2DBL || + dynamicFtnNum == DYNAMIC_CORINFO_HELP_ULNG2DBL || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBLREM || - dynamicFtnNum == DYNAMIC_CORINFO_HELP_FLTREM) + dynamicFtnNum == DYNAMIC_CORINFO_HELP_FLTREM || + dynamicFtnNum == DYNAMIC_CORINFO_HELP_LMUL_OVF || + dynamicFtnNum == DYNAMIC_CORINFO_HELP_ULMUL_OVF) { Precode* pPrecode = Precode::GetPrecodeFromEntryPoint((PCODE)hlpDynamicFuncTable[dynamicFtnNum].pfnHelper); _ASSERTE(pPrecode->GetType() == PRECODE_FIXUP); From 2188fe8ab95b1989134d671e4ffbd53383a112c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Thu, 14 Mar 2024 22:57:36 +0100 Subject: [PATCH 21/29] Cleanup throw helpers --- .../Runtime/CompilerHelpers/MathHelpers.cs | 62 ++++--------------- 1 file changed, 13 insertions(+), 49 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/MathHelpers.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/MathHelpers.cs index 3b2dd9ad0f279..83f8a4722ee37 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/MathHelpers.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/MathHelpers.cs @@ -23,7 +23,7 @@ internal static partial class MathHelpers public static ulong ULMod(ulong dividend, ulong divisor) { if (divisor == 0) - ThrowULngDivByZero(); + ThrowHelper.ThrowDivideByZeroException(); return RhpULMod(dividend, divisor); } @@ -35,9 +35,9 @@ public static ulong ULMod(ulong dividend, ulong divisor) public static long LMod(long dividend, long divisor) { if (divisor == 0) - ThrowLngDivByZero(); + ThrowHelper.ThrowDivideByZeroException(); if (divisor == -1 && dividend == long.MinValue) - ThrowLngOvf(); + ThrowHelper.ThrowOverflowException(); return RhpLMod(dividend, divisor); } @@ -49,7 +49,7 @@ public static long LMod(long dividend, long divisor) public static ulong ULDiv(ulong dividend, ulong divisor) { if (divisor == 0) - ThrowULngDivByZero(); + ThrowHelper.ThrowDivideByZeroException(); return RhpULDiv(dividend, divisor); } @@ -61,9 +61,9 @@ public static ulong ULDiv(ulong dividend, ulong divisor) public static long LDiv(long dividend, long divisor) { if (divisor == 0) - ThrowLngDivByZero(); + ThrowHelper.ThrowDivideByZeroException(); if (divisor == -1 && dividend == long.MinValue) - ThrowLngOvf(); + ThrowHelper.ThrowOverflowException(); return RhpLDiv(dividend, divisor); } @@ -71,14 +71,14 @@ public static long LDiv(long dividend, long divisor) #if TARGET_ARM [RuntimeImport(RuntimeLibrary, "RhpIDiv")] [MethodImpl(MethodImplOptions.InternalCall)] - private static extern int RhpIDiv(int dividend, int j); + private static extern int RhpIDiv(int dividend, int divisor); public static int IDiv(int dividend, int divisor) { if (divisor == 0) - ThrowIntDivByZero(); + ThrowHelper.ThrowDivideByZeroException(); if (divisor == -1 && dividend == int.MinValue) - ThrowIntOvf(); + ThrowHelper.ThrowOverflowException(); return RhpIDiv(dividend, divisor); } @@ -90,7 +90,7 @@ public static int IDiv(int dividend, int divisor) public static long UDiv(uint dividend, uint divisor) { if (divisor == 0) - ThrowUIntDivByZero(); + ThrowHelper.ThrowDivideByZeroException(); return RhpUDiv(dividend, divisor); } @@ -102,9 +102,9 @@ public static long UDiv(uint dividend, uint divisor) public static int IMod(int dividend, int divisor) { if (divisor == 0) - ThrowIntDivByZero(); + ThrowHelper.ThrowDivideByZeroException(); if (divisor == -1 && dividend == int.MinValue) - ThrowIntOvf(); + ThrowHelper.ThrowOverflowException(); return RhpIMod(dividend, divisor); } @@ -116,47 +116,11 @@ public static int IMod(int dividend, int divisor) public static long UMod(uint dividend, uint divisor) { if (divisor == 0) - ThrowUIntDivByZero(); + ThrowHelper.ThrowDivideByZeroException(); return RhpUMod(dividend, divisor); } #endif // TARGET_ARM - - // - // Matching return types of throw helpers enables tailcalling them. It improves performance - // of the hot path because of it does not need to raise full stackframe. - // - private static void ThrowLngOvf() - { - throw new OverflowException(); - } - - private static void ThrowLngDivByZero() - { - throw new DivideByZeroException(); - } - - private static void ThrowULngDivByZero() - { - throw new DivideByZeroException(); - } - -#if TARGET_ARM - private static void ThrowIntOvf() - { - throw new OverflowException(); - } - - private static void ThrowIntDivByZero() - { - throw new DivideByZeroException(); - } - - private static void ThrowUIntDivByZero() - { - throw new DivideByZeroException(); - } -#endif // TARGET_ARM #endif // TARGET_64BIT } } From b4a55118738917b0176f00934cf21ded2943d9cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Fri, 15 Mar 2024 03:23:08 +0100 Subject: [PATCH 22/29] Remove the unmanaged helper from the tiering optimization --- src/coreclr/vm/jitinterface.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index cdabb28c24fe0..5bc710e5dc939 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -10716,7 +10716,6 @@ void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */ dynamicFtnNum == DYNAMIC_CORINFO_HELP_MEMZERO || dynamicFtnNum == DYNAMIC_CORINFO_HELP_MEMCPY || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2INT || - dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2UINT || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2ULNG || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2INT_OVF || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2UINT_OVF || From ffabbe74f4bacbd9b6265491c81ee152a1b837a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Fri, 15 Mar 2024 22:30:05 +0100 Subject: [PATCH 23/29] Go back to C++ helper for doubles, root things with scanner, add fmod --- src/coreclr/nativeaot/Runtime/MathHelpers.cpp | 13 ++++++ .../ILCompiler.Compiler/Compiler/JitHelper.cs | 6 +-- .../IL/ILImporter.Scanner.cs | 46 ++++++------------- src/coreclr/vm/corelib.h | 1 - .../src/System/Double.cs | 1 - 5 files changed, 31 insertions(+), 36 deletions(-) diff --git a/src/coreclr/nativeaot/Runtime/MathHelpers.cpp b/src/coreclr/nativeaot/Runtime/MathHelpers.cpp index b598e8a59de1d..6b7ae4511c73b 100644 --- a/src/coreclr/nativeaot/Runtime/MathHelpers.cpp +++ b/src/coreclr/nativeaot/Runtime/MathHelpers.cpp @@ -38,6 +38,11 @@ EXTERN_C uint64_t QCALLTYPE RhpULMod(uint64_t i, uint64_t j) return i % j; } +FCIMPL1_D(uint32_t, RhpDbl2UInt, double val) +{ + return (uint32_t)val; +} + FCIMPL1_D(int64_t, RhpDbl2Lng, double val) { return (int64_t)val; @@ -271,6 +276,14 @@ FCIMPL1_F(float, tanhf, float x) return std::tanhf(x); FCIMPLEND +FCIMPL2_DD(double, fmod, double x, double y) + return std::fmod(x, y); +FCIMPLEND + +FCIMPL2_FF(float, fmodf, float x, float y) + return std::fmodf(x, y); +FCIMPLEND + FCIMPL3_DDD(double, fma, double x, double y, double z) return std::fma(x, y, z); FCIMPLEND diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs index bfe286c17d0c2..58dca2eef74db 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs @@ -167,9 +167,6 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, case ReadyToRunHelper.Dbl2Int: methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToInt32", null); break; - case ReadyToRunHelper.Dbl2UInt: - methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToUInt32", null); - break; case ReadyToRunHelper.Dbl2ULng: methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToUInt64", null); break; @@ -219,6 +216,9 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, new MethodSignature(MethodSignatureFlags.Static, 0, floatType, [floatType])); break; + case ReadyToRunHelper.Dbl2UInt: + mangledName = "RhpDbl2ULng"; + break; case ReadyToRunHelper.Dbl2Lng: mangledName = "RhpDbl2Lng"; break; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs index e09c32809ce1c..a87fa2bfcc140 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs @@ -1224,43 +1224,31 @@ private void ImportBinaryOperation(ILOpcode opcode) break; case ILOpcode.mul_ovf: case ILOpcode.mul_ovf_un: - if (_compilation.TypeSystemContext.Target.Architecture == TargetArchitecture.ARM) - { - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.LMulOfv), "_lmulovf"); - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ULMulOvf), "_ulmulovf"); - } + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.LMulOfv), "_lmulovf"); + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ULMulOvf), "_ulmulovf"); _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Overflow), "_ovf"); break; case ILOpcode.div: case ILOpcode.div_un: - if (_compilation.TypeSystemContext.Target.Architecture == TargetArchitecture.ARM) - { - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ULDiv), "_uldiv"); - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.LDiv), "_ldiv"); - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.UDiv), "_udiv"); - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Div), "_div"); - } - else if (_compilation.TypeSystemContext.Target.Architecture == TargetArchitecture.ARM64) - { - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ThrowDivZero), "_divbyzero"); - } + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ULDiv), "_uldiv"); + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.LDiv), "_ldiv"); + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.UDiv), "_udiv"); + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Div), "_div"); + + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ThrowDivZero), "_divbyzero"); break; case ILOpcode.rem: case ILOpcode.rem_un: - if (_compilation.TypeSystemContext.Target.Architecture == TargetArchitecture.ARM) - { - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ULMod), "_ulmod"); - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.LMod), "_lmod"); - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.UMod), "_umod"); - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Mod), "_mod"); - } - else if (_compilation.TypeSystemContext.Target.Architecture == TargetArchitecture.ARM64) - { - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ThrowDivZero), "_divbyzero"); - } + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ULMod), "_ulmod"); + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.LMod), "_lmod"); + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.UMod), "_umod"); + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Mod), "_mod"); + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.DblRem), "rem"); _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.FltRem), "rem"); + + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ThrowDivZero), "_divbyzero"); break; } } @@ -1290,10 +1278,6 @@ private void ImportConvert(WellKnownType wellKnownType, bool checkOverflow, bool { _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Dbl2UIntOvf), "conv_u4_ovf"); } - else - { - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Dbl2UInt), "conv_u4"); - } break; case WellKnownType.UInt64: if (checkOverflow) diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index f4fbcf63214c6..1b06e6de5081b 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -263,7 +263,6 @@ DEFINE_METHOD(DELEGATE, GET_INVOKE_METHOD, GetInvokeMethod, DEFINE_CLASS(DOUBLE, System, Double) #endif DEFINE_METHOD(DOUBLE, CONVERT_TO_INT32, ConvertToInt32, NoSig) -DEFINE_METHOD(DOUBLE, CONVERT_TO_UINT32, ConvertToUInt32, NoSig) DEFINE_METHOD(DOUBLE, CONVERT_TO_UINT64, ConvertToUInt64, NoSig) DEFINE_METHOD(DOUBLE, CONVERT_TO_INT32_CHECKED,ConvertToInt32Checked, NoSig) DEFINE_METHOD(DOUBLE, CONVERT_TO_UINT32_CHECKED,ConvertToUInt32Checked, NoSig) diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs index fe7a2caaea291..079e122a56320 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Double.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs @@ -449,7 +449,6 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro // TODO: make the helpers saturating when implementing https://github.com/dotnet/runtime/issues/61885 private static int ConvertToInt32(double value) => (int)(long)value; - private static uint ConvertToUInt32(double value) => (uint)(long)value; private static ulong ConvertToUInt64(double value) { From 68c39a42d174aeeab1e6b08cec5cfc68a2126502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Fri, 15 Mar 2024 22:51:08 +0100 Subject: [PATCH 24/29] Update MathHelpers.cpp --- src/coreclr/nativeaot/Runtime/MathHelpers.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreclr/nativeaot/Runtime/MathHelpers.cpp b/src/coreclr/nativeaot/Runtime/MathHelpers.cpp index 6b7ae4511c73b..76fc37fe2cafb 100644 --- a/src/coreclr/nativeaot/Runtime/MathHelpers.cpp +++ b/src/coreclr/nativeaot/Runtime/MathHelpers.cpp @@ -42,6 +42,7 @@ FCIMPL1_D(uint32_t, RhpDbl2UInt, double val) { return (uint32_t)val; } +FCIMPLEND FCIMPL1_D(int64_t, RhpDbl2Lng, double val) { From 02c53352bc55d41dc9e60919396f97a01341d11a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Fri, 15 Mar 2024 23:41:54 +0100 Subject: [PATCH 25/29] Move unused helper back to C++, restore scanner ifs --- src/coreclr/inc/jithelpers.h | 2 +- src/coreclr/nativeaot/Runtime/MathHelpers.cpp | 6 +++ .../ILCompiler.Compiler/Compiler/JitHelper.cs | 8 ++-- .../IL/ILImporter.Scanner.cs | 40 +++++++++++++------ src/coreclr/vm/corelib.h | 1 - src/coreclr/vm/ecall.cpp | 4 -- src/coreclr/vm/jithelpers.cpp | 8 ++++ src/coreclr/vm/jitinterface.cpp | 1 - .../src/System/Double.cs | 4 +- 9 files changed, 47 insertions(+), 27 deletions(-) diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index c7fd8eb31e88f..f6c2d532e78ce 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -53,7 +53,7 @@ JITHELPER(CORINFO_HELP_ULMOD, JIT_ULMod, CORINFO_HELP_SIG_16_STACK) DYNAMICJITHELPER(CORINFO_HELP_LNG2DBL, NULL, CORINFO_HELP_SIG_8_STACK) DYNAMICJITHELPER(CORINFO_HELP_ULNG2DBL, NULL, CORINFO_HELP_SIG_8_STACK) - DYNAMICJITHELPER(CORINFO_HELP_DBL2INT, NULL, CORINFO_HELP_SIG_8_STACK) + JITHELPER(CORINFO_HELP_DBL2INT, JIT_Dbl2Int, CORINFO_HELP_SIG_8_STACK) DYNAMICJITHELPER(CORINFO_HELP_DBL2INT_OVF, NULL, CORINFO_HELP_SIG_8_STACK) // CORINFO_HELP_DBL2LNG and CORINFO_HELP_DBL2UINT get patched for CPUs with SSE3 in jitinterfacex86.cpp DYNAMICJITHELPER(CORINFO_HELP_DBL2LNG, JIT_Dbl2Lng, CORINFO_HELP_SIG_8_STACK) diff --git a/src/coreclr/nativeaot/Runtime/MathHelpers.cpp b/src/coreclr/nativeaot/Runtime/MathHelpers.cpp index 76fc37fe2cafb..f334351acf3b0 100644 --- a/src/coreclr/nativeaot/Runtime/MathHelpers.cpp +++ b/src/coreclr/nativeaot/Runtime/MathHelpers.cpp @@ -38,6 +38,12 @@ EXTERN_C uint64_t QCALLTYPE RhpULMod(uint64_t i, uint64_t j) return i % j; } +FCIMPL1_D(int32_t, RhpDbl2Int, double val) +{ + return (int32_t)val; +} +FCIMPLEND + FCIMPL1_D(uint32_t, RhpDbl2UInt, double val) { return (uint32_t)val; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs index 58dca2eef74db..7ca76f49e84fa 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs @@ -164,9 +164,6 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, methodDesc = context.GetHelperEntryPoint("LdTokenHelpers", "GetRuntimeFieldHandle"); break; - case ReadyToRunHelper.Dbl2Int: - methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToInt32", null); - break; case ReadyToRunHelper.Dbl2ULng: methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertToUInt64", null); break; @@ -216,8 +213,11 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, new MethodSignature(MethodSignatureFlags.Static, 0, floatType, [floatType])); break; + case ReadyToRunHelper.Dbl2Int: + mangledName = "RhpDbl2Int"; + break; case ReadyToRunHelper.Dbl2UInt: - mangledName = "RhpDbl2ULng"; + mangledName = "RhpDbl2UInt"; break; case ReadyToRunHelper.Dbl2Lng: mangledName = "RhpDbl2Lng"; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs index a87fa2bfcc140..da88c6375316f 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs @@ -1224,31 +1224,45 @@ private void ImportBinaryOperation(ILOpcode opcode) break; case ILOpcode.mul_ovf: case ILOpcode.mul_ovf_un: - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.LMulOfv), "_lmulovf"); - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ULMulOvf), "_ulmulovf"); + if (_compilation.TypeSystemContext.Target.PointerSize == 4) + { + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.LMulOfv), "_lmulovf"); + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ULMulOvf), "_ulmulovf"); + } _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Overflow), "_ovf"); break; case ILOpcode.div: case ILOpcode.div_un: - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ULDiv), "_uldiv"); - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.LDiv), "_ldiv"); - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.UDiv), "_udiv"); - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Div), "_div"); + if (_compilation.TypeSystemContext.Target.Architecture == TargetArchitecture.ARM) + { + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ULDiv), "_uldiv"); + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.LDiv), "_ldiv"); + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.UDiv), "_udiv"); + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Div), "_div"); + } + else if (_compilation.TypeSystemContext.Target.Architecture == TargetArchitecture.ARM64) + { + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ThrowDivZero), "_divbyzero"); + } - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ThrowDivZero), "_divbyzero"); break; case ILOpcode.rem: case ILOpcode.rem_un: - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ULMod), "_ulmod"); - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.LMod), "_lmod"); - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.UMod), "_umod"); - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Mod), "_mod"); + if (_compilation.TypeSystemContext.Target.Architecture == TargetArchitecture.ARM) + { + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ULMod), "_ulmod"); + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.LMod), "_lmod"); + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.UMod), "_umod"); + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Mod), "_mod"); + } + else if (_compilation.TypeSystemContext.Target.Architecture == TargetArchitecture.ARM64) + { + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ThrowDivZero), "_divbyzero"); + } _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.DblRem), "rem"); _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.FltRem), "rem"); - - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ThrowDivZero), "_divbyzero"); break; } } diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 1b06e6de5081b..9e88036bc907b 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -262,7 +262,6 @@ DEFINE_METHOD(DELEGATE, GET_INVOKE_METHOD, GetInvokeMethod, #ifdef FOR_ILLINK DEFINE_CLASS(DOUBLE, System, Double) #endif -DEFINE_METHOD(DOUBLE, CONVERT_TO_INT32, ConvertToInt32, NoSig) DEFINE_METHOD(DOUBLE, CONVERT_TO_UINT64, ConvertToUInt64, NoSig) DEFINE_METHOD(DOUBLE, CONVERT_TO_INT32_CHECKED,ConvertToInt32Checked, NoSig) DEFINE_METHOD(DOUBLE, CONVERT_TO_UINT32_CHECKED,ConvertToUInt32Checked, NoSig) diff --git a/src/coreclr/vm/ecall.cpp b/src/coreclr/vm/ecall.cpp index 577d187f5c908..781fb9bf74204 100644 --- a/src/coreclr/vm/ecall.cpp +++ b/src/coreclr/vm/ecall.cpp @@ -157,10 +157,6 @@ void ECall::PopulateManagedHelpers() pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_MEMCPY, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE__CONVERT_TO_INT32)); - pDest = pMD->GetMultiCallableAddrOfCode(); - SetJitHelperFunction(CORINFO_HELP_DBL2INT, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE__CONVERT_TO_UINT64)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBL2ULNG, pDest); diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 529cf7e6fd9cb..9ed1b39b48d35 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -379,6 +379,14 @@ HCIMPLEND /*********************************************************************/ // needed for ARM and x86 +HCIMPL1_V(INT32, JIT_Dbl2Int, double val) +{ + FCALL_CONTRACT; + + return (INT32)val; +} +HCIMPLEND + HCIMPL1_V(INT64, JIT_Dbl2Lng, double val) { FCALL_CONTRACT; diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 5bc710e5dc939..ecdac196e0229 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -10715,7 +10715,6 @@ void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */ dynamicFtnNum == DYNAMIC_CORINFO_HELP_MEMSET || dynamicFtnNum == DYNAMIC_CORINFO_HELP_MEMZERO || dynamicFtnNum == DYNAMIC_CORINFO_HELP_MEMCPY || - dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2INT || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2ULNG || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2INT_OVF || dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2UINT_OVF || diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs index 079e122a56320..ede3cd1ca314c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Double.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs @@ -447,9 +447,7 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro private const double IntMaxValueOffset = 2147483648.0; // 2^31, int.MaxValue + 1 private const double UIntMaxValueOffset = 4294967296.0; // 2^32, uint.MaxValue + 1 - // TODO: make the helpers saturating when implementing https://github.com/dotnet/runtime/issues/61885 - private static int ConvertToInt32(double value) => (int)(long)value; - + // TODO: make the helper saturating when implementing https://github.com/dotnet/runtime/issues/61885 private static ulong ConvertToUInt64(double value) { const double two63 = IntMaxValueOffset * UIntMaxValueOffset; From 1c3626276ff308ea38f0e76579351da5df8753a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Fri, 15 Mar 2024 23:48:15 +0100 Subject: [PATCH 26/29] Update ILImporter.Scanner.cs --- .../tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs index da88c6375316f..545a673fb3aca 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs @@ -1245,7 +1245,6 @@ private void ImportBinaryOperation(ILOpcode opcode) { _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ThrowDivZero), "_divbyzero"); } - break; case ILOpcode.rem: case ILOpcode.rem_un: From 8fcb99f564df53f3e1abb080b43a3eb1eea32ede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Sat, 16 Mar 2024 00:11:35 +0100 Subject: [PATCH 27/29] Update ILImporter.Scanner.cs --- .../aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs index 545a673fb3aca..88f80ae4e8491 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs @@ -1245,6 +1245,10 @@ private void ImportBinaryOperation(ILOpcode opcode) { _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ThrowDivZero), "_divbyzero"); } + if (opcode == ILOpcode.rem) + { + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Overflow), "_ovf"); + } break; case ILOpcode.rem: case ILOpcode.rem_un: @@ -1259,6 +1263,10 @@ private void ImportBinaryOperation(ILOpcode opcode) { _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ThrowDivZero), "_divbyzero"); } + if (opcode == ILOpcode.rem) + { + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Overflow), "_ovf"); + } _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.DblRem), "rem"); _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.FltRem), "rem"); @@ -1308,6 +1316,10 @@ private void ImportConvert(WellKnownType wellKnownType, bool checkOverflow, bool _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ULng2Dbl), "conv_r"); break; } + if (checkOverflow) + { + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Overflow), "_ovf"); + } } private void ImportFallthrough(BasicBlock next) From f7769d7e527da83da187546c307813c0b21d4e03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Sat, 16 Mar 2024 00:14:08 +0100 Subject: [PATCH 28/29] Update src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs Co-authored-by: Jan Kotas --- .../tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs index 88f80ae4e8491..aa971734b5b70 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs @@ -1245,7 +1245,7 @@ private void ImportBinaryOperation(ILOpcode opcode) { _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.ThrowDivZero), "_divbyzero"); } - if (opcode == ILOpcode.rem) + if (opcode == ILOpcode.div) { _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Overflow), "_ovf"); } From be4c607afbc95a3038334ec1867ed68a667d3f32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Sat, 16 Mar 2024 19:34:37 +0100 Subject: [PATCH 29/29] Call FMod directly --- .../src/System/Math.CoreCLR.cs | 2 +- .../src/System/MathF.CoreCLR.cs | 2 +- .../src/System/Math.NativeAot.cs | 2 +- .../src/System/MathF.NativeAot.cs | 2 +- .../ILCompiler.Compiler/Compiler/JitHelper.cs | 14 +++++----- src/coreclr/vm/corelib.h | 8 ++---- src/coreclr/vm/ecall.cpp | 4 +-- src/coreclr/vm/jitinterface.cpp | 2 -- .../src/System/Double.cs | 23 ---------------- .../src/System/Single.cs | 27 ------------------- .../src/System/Math.Mono.cs | 2 +- .../src/System/MathF.Mono.cs | 2 +- 12 files changed, 17 insertions(+), 73 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Math.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Math.CoreCLR.cs index ec5b0121590f1..a619dc4b1ca79 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Math.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Math.CoreCLR.cs @@ -117,7 +117,7 @@ public static unsafe (double Sin, double Cos) SinCos(double x) [Intrinsic] [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern double FMod(double x, double y); + private static extern double FMod(double x, double y); [MethodImpl(MethodImplOptions.InternalCall)] private static extern unsafe double ModF(double x, double* intptr); diff --git a/src/coreclr/System.Private.CoreLib/src/System/MathF.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/MathF.CoreCLR.cs index a2d8055c661bb..855a1b1e7ef15 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/MathF.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/MathF.CoreCLR.cs @@ -114,7 +114,7 @@ public static unsafe (float Sin, float Cos) SinCos(float x) [Intrinsic] [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern float FMod(float x, float y); + private static extern float FMod(float x, float y); [MethodImpl(MethodImplOptions.InternalCall)] private static extern unsafe float ModF(float x, float* intptr); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Math.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Math.NativeAot.cs index 842013a1b4312..15b629dbee219 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Math.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Math.NativeAot.cs @@ -155,7 +155,7 @@ public static double Tanh(double value) } [Intrinsic] - internal static double FMod(double x, double y) + private static double FMod(double x, double y) { return RuntimeImports.fmod(x, y); } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/MathF.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/MathF.NativeAot.cs index 5fb0054cb3f5a..2f42ad90e94c3 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/MathF.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/MathF.NativeAot.cs @@ -155,7 +155,7 @@ public static float Tanh(float x) } [Intrinsic] - internal static float FMod(float x, float y) + private static float FMod(float x, float y) { return RuntimeImports.fmodf(x, y); } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs index 7ca76f49e84fa..edb21b3bc21cf 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs @@ -188,13 +188,6 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("ConvertFromUInt64", null); break; - case ReadyToRunHelper.DblRem: - methodDesc = context.SystemModule.GetKnownType("System", "Double").GetKnownMethod("Remainder", null); - break; - case ReadyToRunHelper.FltRem: - methodDesc = context.SystemModule.GetKnownType("System", "Single").GetKnownMethod("Remainder", null); - break; - case ReadyToRunHelper.LMulOfv: methodDesc = context.SystemModule.GetKnownType("System", "Int64").GetKnownMethod("MultiplyChecked", null); break; @@ -213,6 +206,13 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, new MethodSignature(MethodSignatureFlags.Static, 0, floatType, [floatType])); break; + case ReadyToRunHelper.DblRem: + methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("FMod", null); + break; + case ReadyToRunHelper.FltRem: + methodDesc = context.SystemModule.GetKnownType("System", "MathF").GetKnownMethod("FMod", null); + break; + case ReadyToRunHelper.Dbl2Int: mangledName = "RhpDbl2Int"; break; diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 9e88036bc907b..54b41edf3f36f 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -269,12 +269,6 @@ DEFINE_METHOD(DOUBLE, CONVERT_TO_INT64_CHECKED,ConvertToInt64Check DEFINE_METHOD(DOUBLE, CONVERT_TO_UINT64_CHECKED,ConvertToUInt64Checked, NoSig) DEFINE_METHOD(DOUBLE, CONVERT_FROM_INT64, ConvertFromInt64, NoSig) DEFINE_METHOD(DOUBLE, CONVERT_FROM_UINT64, ConvertFromUInt64, NoSig) -DEFINE_METHOD(DOUBLE, REMAINDER, Remainder, NoSig) - -#ifdef FOR_ILLINK -DEFINE_CLASS(SINGLE, System, Single) -#endif -DEFINE_METHOD(SINGLE, REMAINDER, Remainder, NoSig) #ifdef FOR_ILLINK DEFINE_CLASS(INT64, System, Int64) @@ -291,9 +285,11 @@ DEFINE_CLASS(UINT128, System, UInt128) DEFINE_CLASS(MATH, System, Math) DEFINE_METHOD(MATH, ROUND, Round, SM_Dbl_RetDbl) +DEFINE_METHOD(MATH, FMOD, FMod, NoSig) DEFINE_CLASS(MATHF, System, MathF) DEFINE_METHOD(MATHF, ROUND, Round, SM_Flt_RetFlt) +DEFINE_METHOD(MATHF, FMOD, FMod, NoSig) DEFINE_CLASS(DYNAMICMETHOD, ReflectionEmit, DynamicMethod) DEFINE_CLASS(DYNAMICRESOLVER, ReflectionEmit, DynamicResolver) diff --git a/src/coreclr/vm/ecall.cpp b/src/coreclr/vm/ecall.cpp index 781fb9bf74204..e4e2457e1700e 100644 --- a/src/coreclr/vm/ecall.cpp +++ b/src/coreclr/vm/ecall.cpp @@ -185,11 +185,11 @@ void ECall::PopulateManagedHelpers() pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_ULNG2DBL, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__DOUBLE__REMAINDER)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__FMOD)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_DBLREM, pDest); - pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__SINGLE__REMAINDER)); + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATHF__FMOD)); pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_FLTREM, pDest); diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index ecdac196e0229..ae7ec625000da 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -10722,8 +10722,6 @@ void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */ dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBL2ULNG_OVF || dynamicFtnNum == DYNAMIC_CORINFO_HELP_LNG2DBL || dynamicFtnNum == DYNAMIC_CORINFO_HELP_ULNG2DBL || - dynamicFtnNum == DYNAMIC_CORINFO_HELP_DBLREM || - dynamicFtnNum == DYNAMIC_CORINFO_HELP_FLTREM || dynamicFtnNum == DYNAMIC_CORINFO_HELP_LMUL_OVF || dynamicFtnNum == DYNAMIC_CORINFO_HELP_ULMUL_OVF) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs index ede3cd1ca314c..81ad7b87311e6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Double.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs @@ -571,29 +571,6 @@ private static double ConvertFromUInt64(ulong value) return a * UIntMaxValueOffset + b; } - private static double Remainder(double dividend, double divisor) - { - // From the ECMA standard: - // - // If [divisor] is zero or [dividend] is infinity - // the result is NaN. - // If [divisor] is infinity, - // the result is [dividend] (negated for -infinity***). - // - // ***"negated for -infinity" has been removed from the spec - if (divisor == 0 || !IsFinite(dividend)) - { - return NaN; - } - - if (!IsFinite(divisor) && !IsNaN(divisor)) - { - return dividend; - } - - return Math.FMod(dividend, divisor); - } - // // IConvertible implementation // diff --git a/src/libraries/System.Private.CoreLib/src/System/Single.cs b/src/libraries/System.Private.CoreLib/src/System/Single.cs index cee3c004573b4..9cc7c6b56c0ad 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Single.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Single.cs @@ -435,33 +435,6 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro return Number.TryParseFloat(s, style, NumberFormatInfo.GetInstance(provider), out result); } - // - // Helpers, those methods are referenced from the JIT - // - - private static float Remainder(float dividend, float divisor) - { - // From the ECMA standard: - // - // If [divisor] is zero or [dividend] is infinity - // the result is NaN. - // If [divisor] is infinity, - // the result is [dividend] (negated for -infinity***). - // - // ***"negated for -infinity" has been removed from the spec - if (divisor == 0 || !IsFinite(dividend)) - { - return NaN; - } - - if (!IsFinite(divisor) && !IsNaN(divisor)) - { - return dividend; - } - - return MathF.FMod(dividend, divisor); - } - // // IConvertible implementation // diff --git a/src/mono/System.Private.CoreLib/src/System/Math.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Math.Mono.cs index a4b691e8b7946..eb0024f983e64 100644 --- a/src/mono/System.Private.CoreLib/src/System/Math.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Math.Mono.cs @@ -80,7 +80,7 @@ public partial class Math public static extern double Log2(double x); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern double FMod(double x, double y); + private static extern double FMod(double x, double y); [MethodImpl(MethodImplOptions.InternalCall)] private static extern unsafe double ModF(double x, double* intptr); diff --git a/src/mono/System.Private.CoreLib/src/System/MathF.Mono.cs b/src/mono/System.Private.CoreLib/src/System/MathF.Mono.cs index 1e6ab8155d148..4fd4dc614458b 100644 --- a/src/mono/System.Private.CoreLib/src/System/MathF.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/MathF.Mono.cs @@ -80,7 +80,7 @@ public partial class MathF public static extern float Log2(float x); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern float FMod(float x, float y); + private static extern float FMod(float x, float y); [MethodImpl(MethodImplOptions.InternalCall)] private static extern unsafe float ModF(float x, float* intptr);