Ensure that the various Min and Max APIs are accelerated where possible (#87641)
authorTanner Gooding <tagoo@outlook.com>
Tue, 20 Jun 2023 00:55:56 +0000 (17:55 -0700)
committerGitHub <noreply@github.com>
Tue, 20 Jun 2023 00:55:56 +0000 (17:55 -0700)
* Updating Math.Max and Math.Min to utilize AVX512 when available

* Ensure that Single/Double APIs can be directly handled as intrinsic

* Ensure that the various Min and Max APIs are accelerated where possible

* Don't include ILogB for the time being

* Ensure FixupScalar is passed all 4 parameters

* Apply suggestions from code review

14 files changed:
src/coreclr/jit/codegenarmarch.cpp
src/coreclr/jit/compiler.h
src/coreclr/jit/gentree.cpp
src/coreclr/jit/importercalls.cpp
src/coreclr/jit/lsraarm64.cpp
src/coreclr/jit/namedintrinsiclist.h
src/coreclr/jit/utils.cpp
src/coreclr/jit/utils.h
src/coreclr/jit/valuenum.cpp
src/coreclr/jit/valuenumfuncs.h
src/libraries/System.Private.CoreLib/src/System/Double.cs
src/libraries/System.Private.CoreLib/src/System/Math.cs
src/libraries/System.Private.CoreLib/src/System/MathF.cs
src/libraries/System.Private.CoreLib/src/System/Single.cs

index c0581ee..22f170d 100644 (file)
@@ -690,16 +690,36 @@ void CodeGen::genIntrinsic(GenTreeIntrinsic* treeNode)
             break;
 
         case NI_System_Math_Max:
+        {
             genConsumeOperands(treeNode->AsOp());
             GetEmitter()->emitIns_R_R_R(INS_fmax, emitActualTypeSize(treeNode), treeNode->GetRegNum(),
                                         srcNode->GetRegNum(), treeNode->gtGetOp2()->GetRegNum());
             break;
+        }
+
+        case NI_System_Math_MaxNumber:
+        {
+            genConsumeOperands(treeNode->AsOp());
+            GetEmitter()->emitIns_R_R_R(INS_fmaxnm, emitActualTypeSize(treeNode), treeNode->GetRegNum(),
+                                        srcNode->GetRegNum(), treeNode->gtGetOp2()->GetRegNum());
+            break;
+        }
 
         case NI_System_Math_Min:
+        {
             genConsumeOperands(treeNode->AsOp());
             GetEmitter()->emitIns_R_R_R(INS_fmin, emitActualTypeSize(treeNode), treeNode->GetRegNum(),
                                         srcNode->GetRegNum(), treeNode->gtGetOp2()->GetRegNum());
             break;
+        }
+
+        case NI_System_Math_MinNumber:
+        {
+            genConsumeOperands(treeNode->AsOp());
+            GetEmitter()->emitIns_R_R_R(INS_fminnm, emitActualTypeSize(treeNode), treeNode->GetRegNum(),
+                                        srcNode->GetRegNum(), treeNode->gtGetOp2()->GetRegNum());
+            break;
+        }
 #endif // TARGET_ARM64
 
         case NI_System_Math_Sqrt:
index e8f293b..0d24478 100644 (file)
@@ -3957,8 +3957,17 @@ protected:
                               var_types             callType,
                               NamedIntrinsic        intrinsicName,
                               bool                  tailCall);
+    GenTree* impMinMaxIntrinsic(CORINFO_METHOD_HANDLE method,
+                                CORINFO_SIG_INFO*     sig,
+                                CorInfoType           callJitType,
+                                NamedIntrinsic        intrinsicName,
+                                bool                  tailCall,
+                                bool                  isMax,
+                                bool                  isMagnitude,
+                                bool                  isNumber);
     NamedIntrinsic lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method);
-    NamedIntrinsic lookupPrimitiveNamedIntrinsic(CORINFO_METHOD_HANDLE method, const char* methodName);
+    NamedIntrinsic lookupPrimitiveFloatNamedIntrinsic(CORINFO_METHOD_HANDLE method, const char* methodName);
+    NamedIntrinsic lookupPrimitiveIntNamedIntrinsic(CORINFO_METHOD_HANDLE method, const char* methodName);
     GenTree* impUnsupportedNamedIntrinsic(unsigned              helper,
                                           CORINFO_METHOD_HANDLE method,
                                           CORINFO_SIG_INFO*     sig,
index 17b2026..d8b4e87 100644 (file)
@@ -5477,7 +5477,13 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
                         case NI_System_Math_Log2:
                         case NI_System_Math_Log10:
                         case NI_System_Math_Max:
+                        case NI_System_Math_MaxMagnitude:
+                        case NI_System_Math_MaxMagnitudeNumber:
+                        case NI_System_Math_MaxNumber:
                         case NI_System_Math_Min:
+                        case NI_System_Math_MinMagnitude:
+                        case NI_System_Math_MinMagnitudeNumber:
+                        case NI_System_Math_MinNumber:
                         case NI_System_Math_Pow:
                         case NI_System_Math_Round:
                         case NI_System_Math_Sin:
@@ -5824,9 +5830,17 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
                         break;
 
                     case NI_System_Math_Max:
+                    case NI_System_Math_MaxMagnitude:
+                    case NI_System_Math_MaxMagnitudeNumber:
+                    case NI_System_Math_MaxNumber:
                     case NI_System_Math_Min:
+                    case NI_System_Math_MinMagnitude:
+                    case NI_System_Math_MinMagnitudeNumber:
+                    case NI_System_Math_MinNumber:
+                    {
                         level++;
                         break;
+                    }
 
                     default:
                         assert(!"Unknown binary GT_INTRINSIC operator");
@@ -12235,9 +12249,27 @@ void Compiler::gtDispTree(GenTree*     tree,
                 case NI_System_Math_Max:
                     printf(" max");
                     break;
+                case NI_System_Math_MaxMagnitude:
+                    printf(" maxMagnitude");
+                    break;
+                case NI_System_Math_MaxMagnitudeNumber:
+                    printf(" maxMagnitudeNumber");
+                    break;
+                case NI_System_Math_MaxNumber:
+                    printf(" maxNumber");
+                    break;
                 case NI_System_Math_Min:
                     printf(" min");
                     break;
+                case NI_System_Math_MinMagnitude:
+                    printf(" minMagnitude");
+                    break;
+                case NI_System_Math_MinMagnitudeNumber:
+                    printf(" minMagnitudeNumber");
+                    break;
+                case NI_System_Math_MinNumber:
+                    printf(" minNumber");
+                    break;
                 case NI_System_Math_Pow:
                     printf(" pow");
                     break;
index 14f1ba6..eb67240 100644 (file)
@@ -3398,161 +3398,86 @@ GenTree* Compiler::impIntrinsic(GenTree*                newobjThis,
                 retNode = impMathIntrinsic(method, sig, callType, ni, tailCall);
                 break;
             }
-#if defined(TARGET_ARM64)
-            // ARM64 has fmax/fmin which are IEEE754:2019 minimum/maximum compatible
-            case NI_System_Math_Max:
-            case NI_System_Math_Min:
-#endif
 
-#if defined(FEATURE_HW_INTRINSICS) && defined(TARGET_XARCH)
             case NI_System_Math_Max:
-            case NI_System_Math_Min:
             {
-                assert(varTypeIsFloating(callType));
-                assert(sig->numArgs == 2);
-
-                GenTreeDblCon* cnsNode   = nullptr;
-                GenTree*       otherNode = nullptr;
-
-                GenTree* op2 = impStackTop().val;
-                GenTree* op1 = impStackTop(1).val;
-
-                if (op2->IsCnsFltOrDbl())
-                {
-                    cnsNode   = op2->AsDblCon();
-                    otherNode = op1;
-                }
-                else if (op1->IsCnsFltOrDbl())
-                {
-                    cnsNode   = op1->AsDblCon();
-                    otherNode = op2;
-                }
-
-                if (cnsNode == nullptr)
-                {
-                    // no constant node, nothing to do
-                    break;
-                }
-
-                if (otherNode->IsCnsFltOrDbl())
-                {
-                    // both are constant, we can fold this operation completely. Pop both peeked values
-
-                    if (ni == NI_System_Math_Max)
-                    {
-                        cnsNode->SetDconValue(
-                            FloatingPointUtils::maximum(cnsNode->DconValue(), otherNode->AsDblCon()->DconValue()));
-                    }
-                    else
-                    {
-                        assert(ni == NI_System_Math_Min);
-                        cnsNode->SetDconValue(
-                            FloatingPointUtils::minimum(cnsNode->DconValue(), otherNode->AsDblCon()->DconValue()));
-                    }
-
-                    retNode = cnsNode;
-
-                    impPopStack();
-                    impPopStack();
-                    DEBUG_DESTROY_NODE(otherNode);
-
-                    break;
-                }
+                const bool isMax       = true;
+                const bool isMagnitude = false;
+                const bool isNumber    = false;
 
-                // only one is constant, we can fold in specialized scenarios
-
-                if (cnsNode->IsFloatNaN())
-                {
-                    impSpillSideEffects(false, CHECK_SPILL_ALL DEBUGARG("spill side effects before propagating NaN"));
-
-                    // maxsd, maxss, minsd, and minss all return op2 if either is NaN
-                    // we require NaN to be propagated so ensure the known NaN is op2
-
-                    impPopStack();
-                    impPopStack();
-                    DEBUG_DESTROY_NODE(otherNode);
-
-                    retNode = cnsNode;
-                    break;
-                }
-
-                if (!compOpportunisticallyDependsOn(InstructionSet_SSE2))
-                {
-                    break;
-                }
-
-                if (ni == NI_System_Math_Max)
-                {
-                    // maxsd, maxss return op2 if both inputs are 0 of either sign
-                    // we require +0 to be greater than -0, so we can't handle if
-                    // the known constant is +0. This is because if the unknown value
-                    // is -0, we'd need the cns to be op2. But if the unknown value
-                    // is NaN, we'd need the cns to be op1 instead.
-
-                    if (cnsNode->IsFloatPositiveZero())
-                    {
-                        break;
-                    }
-
-                    // Given the checks, op1 can safely be the cns and op2 the other node
-
-                    ni = (callType == TYP_DOUBLE) ? NI_SSE2_Max : NI_SSE_Max;
-
-                    // one is constant and we know its something we can handle, so pop both peeked values
+                retNode = impMinMaxIntrinsic(method, sig, callJitType, ni, tailCall, isMax, isMagnitude, isNumber);
+                break;
+            }
 
-                    op1 = cnsNode;
-                    op2 = otherNode;
-                }
-                else
-                {
-                    assert(ni == NI_System_Math_Min);
+            case NI_System_Math_Min:
+            {
+                const bool isMax       = false;
+                const bool isMagnitude = false;
+                const bool isNumber    = false;
 
-                    // minsd, minss return op2 if both inputs are 0 of either sign
-                    // we require -0 to be lesser than +0, so we can't handle if
-                    // the known constant is -0. This is because if the unknown value
-                    // is +0, we'd need the cns to be op2. But if the unknown value
-                    // is NaN, we'd need the cns to be op1 instead.
+                retNode = impMinMaxIntrinsic(method, sig, callJitType, ni, tailCall, isMax, isMagnitude, isNumber);
+                break;
+            }
 
-                    if (cnsNode->IsFloatNegativeZero())
-                    {
-                        break;
-                    }
+            case NI_System_Math_MaxMagnitude:
+            {
+                const bool isMax       = true;
+                const bool isMagnitude = true;
+                const bool isNumber    = false;
 
-                    // Given the checks, op1 can safely be the cns and op2 the other node
+                retNode = impMinMaxIntrinsic(method, sig, callJitType, ni, tailCall, isMax, isMagnitude, isNumber);
+                break;
+            }
 
-                    ni = (callType == TYP_DOUBLE) ? NI_SSE2_Min : NI_SSE_Min;
+            case NI_System_Math_MinMagnitude:
+            {
+                const bool isMax       = false;
+                const bool isMagnitude = true;
+                const bool isNumber    = false;
 
-                    // one is constant and we know its something we can handle, so pop both peeked values
+                retNode = impMinMaxIntrinsic(method, sig, callJitType, ni, tailCall, isMax, isMagnitude, isNumber);
+                break;
+            }
 
-                    op1 = cnsNode;
-                    op2 = otherNode;
-                }
+            case NI_System_Math_MaxMagnitudeNumber:
+            {
+                const bool isMax       = true;
+                const bool isMagnitude = true;
+                const bool isNumber    = true;
 
-                assert(op1->IsCnsFltOrDbl() && !op2->IsCnsFltOrDbl());
+                retNode = impMinMaxIntrinsic(method, sig, callJitType, ni, tailCall, isMax, isMagnitude, isNumber);
+                break;
+            }
 
-                impPopStack();
-                impPopStack();
+            case NI_System_Math_MinMagnitudeNumber:
+            {
+                const bool isMax       = false;
+                const bool isMagnitude = true;
+                const bool isNumber    = true;
 
-                GenTreeVecCon* vecCon = gtNewVconNode(TYP_SIMD16);
+                retNode = impMinMaxIntrinsic(method, sig, callJitType, ni, tailCall, isMax, isMagnitude, isNumber);
+                break;
+            }
 
-                if (callJitType == CORINFO_TYPE_FLOAT)
-                {
-                    vecCon->gtSimdVal.f32[0] = (float)op1->AsDblCon()->DconValue();
-                }
-                else
-                {
-                    vecCon->gtSimdVal.f64[0] = op1->AsDblCon()->DconValue();
-                }
+            case NI_System_Math_MaxNumber:
+            {
+                const bool isMax       = true;
+                const bool isMagnitude = false;
+                const bool isNumber    = true;
 
-                op1 = vecCon;
-                op2 = gtNewSimdCreateScalarUnsafeNode(TYP_SIMD16, op2, callJitType, 16);
+                retNode = impMinMaxIntrinsic(method, sig, callJitType, ni, tailCall, isMax, isMagnitude, isNumber);
+                break;
+            }
 
-                retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, op2, ni, callJitType, 16);
-                retNode = gtNewSimdHWIntrinsicNode(callType, retNode, NI_Vector128_ToScalar, callJitType, 16);
+            case NI_System_Math_MinNumber:
+            {
+                const bool isMax       = false;
+                const bool isMagnitude = false;
+                const bool isNumber    = true;
 
+                retNode = impMinMaxIntrinsic(method, sig, callJitType, ni, tailCall, isMax, isMagnitude, isNumber);
                 break;
             }
-#endif
 
             case NI_System_Math_Pow:
             case NI_System_Math_Round:
@@ -6720,7 +6645,13 @@ bool Compiler::IsMathIntrinsic(NamedIntrinsic intrinsicName)
         case NI_System_Math_Log2:
         case NI_System_Math_Log10:
         case NI_System_Math_Max:
+        case NI_System_Math_MaxMagnitude:
+        case NI_System_Math_MaxMagnitudeNumber:
+        case NI_System_Math_MaxNumber:
         case NI_System_Math_Min:
+        case NI_System_Math_MinMagnitude:
+        case NI_System_Math_MinMagnitudeNumber:
+        case NI_System_Math_MinNumber:
         case NI_System_Math_Pow:
         case NI_System_Math_Round:
         case NI_System_Math_Sin:
@@ -7994,173 +7925,651 @@ GenTree* Compiler::impMathIntrinsic(CORINFO_METHOD_HANDLE method,
 }
 
 //------------------------------------------------------------------------
-// lookupNamedIntrinsic: map method to jit named intrinsic value
+// impMinMaxIntrinsic: Imports a min or max intrinsic
 //
 // Arguments:
-//    method -- method handle for method
-//
-// Return Value:
-//    Id for the named intrinsic, or Illegal if none.
-//
-// Notes:
-//    method should have CORINFO_FLG_INTRINSIC set in its attributes,
-//    otherwise it is not a named jit intrinsic.
+//   method        - The handle of the method being imported
+//   callType      - The underlying type for the call
+//   intrinsicName - The intrinsic being imported
+//   tailCall      - true if the method is a tail call; otherwise false
+//   isMax         - true if the intrinsic computes the max; false for the min
+//   isMagnitude   - true if the intrinsic compares using the absolute value of the inputs
+//   isNumber      - true if the intrinsic propagates the number; false for NaN
 //
-NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
+GenTree* Compiler::impMinMaxIntrinsic(CORINFO_METHOD_HANDLE method,
+                                      CORINFO_SIG_INFO*     sig,
+                                      CorInfoType           callJitType,
+                                      NamedIntrinsic        intrinsicName,
+                                      bool                  tailCall,
+                                      bool                  isMax,
+                                      bool                  isMagnitude,
+                                      bool                  isNumber)
 {
-    const char* className          = nullptr;
-    const char* namespaceName      = nullptr;
-    const char* enclosingClassName = nullptr;
-    const char* methodName =
-        info.compCompHnd->getMethodNameFromMetadata(method, &className, &namespaceName, &enclosingClassName);
+    var_types callType = JITtype2varType(callJitType);
 
-    JITDUMP("Named Intrinsic ");
+    assert(varTypeIsFloating(callType));
+    assert(sig->numArgs == 2);
 
-    if (namespaceName != nullptr)
-    {
-        JITDUMP("%s.", namespaceName);
-    }
-    if (enclosingClassName != nullptr)
-    {
-        JITDUMP("%s.", enclosingClassName);
-    }
-    if (className != nullptr)
+    GenTreeDblCon* cnsNode   = nullptr;
+    GenTree*       otherNode = nullptr;
+
+    GenTree* op2 = impStackTop().val;
+    GenTree* op1 = impStackTop(1).val;
+
+    if (op2->IsCnsFltOrDbl())
     {
-        JITDUMP("%s.", className);
+        cnsNode   = op2->AsDblCon();
+        otherNode = op1;
     }
-    if (methodName != nullptr)
+    else if (op1->IsCnsFltOrDbl())
     {
-        JITDUMP("%s", methodName);
+        cnsNode   = op1->AsDblCon();
+        otherNode = op2;
     }
 
-    if ((namespaceName == nullptr) || (className == nullptr) || (methodName == nullptr))
+    if (cnsNode != nullptr)
     {
-        // Check if we are dealing with an MD array's known runtime method
-        CorInfoArrayIntrinsic arrayFuncIndex = info.compCompHnd->getArrayIntrinsicID(method);
-        switch (arrayFuncIndex)
+        if (otherNode->IsCnsFltOrDbl())
         {
-            case CorInfoArrayIntrinsic::GET:
-                JITDUMP("ARRAY_FUNC_GET: Recognized\n");
-                return NI_Array_Get;
-            case CorInfoArrayIntrinsic::SET:
-                JITDUMP("ARRAY_FUNC_SET: Recognized\n");
-                return NI_Array_Set;
-            case CorInfoArrayIntrinsic::ADDRESS:
-                JITDUMP("ARRAY_FUNC_ADDRESS: Recognized\n");
-                return NI_Array_Address;
-            default:
-                break;
-        }
-
-        JITDUMP(": Not recognized, not enough metadata\n");
-        return NI_Illegal;
-    }
-
-    JITDUMP(": ");
-
-    NamedIntrinsic result = NI_Illegal;
+            // both are constant, we can fold this operation completely. Pop both peeked values
 
-    if (strncmp(namespaceName, "System", 6) == 0)
-    {
-        namespaceName += 6;
+            double x = cnsNode->DconValue();
+            double y = otherNode->AsDblCon()->DconValue();
+            double z;
 
-        if (namespaceName[0] == '\0')
-        {
-            switch (className[0])
+            if (isMax)
             {
-                case 'A':
+                if (isMagnitude)
                 {
-                    if (strcmp(className, "Activator") == 0)
+                    if (isNumber)
                     {
-                        if (strcmp(methodName, "AllocatorOf") == 0)
-                        {
-                            result = NI_System_Activator_AllocatorOf;
-                        }
-                        else if (strcmp(methodName, "DefaultConstructorOf") == 0)
-                        {
-                            result = NI_System_Activator_DefaultConstructorOf;
-                        }
+                        z = FloatingPointUtils::maximumMagnitudeNumber(x, y);
                     }
-                    else if (strcmp(className, "Array") == 0)
+                    else
                     {
-                        if (strcmp(methodName, "Clone") == 0)
-                        {
-                            result = NI_System_Array_Clone;
-                        }
-                        else if (strcmp(methodName, "GetLength") == 0)
-                        {
-                            result = NI_System_Array_GetLength;
-                        }
-                        else if (strcmp(methodName, "GetLowerBound") == 0)
-                        {
-                            result = NI_System_Array_GetLowerBound;
-                        }
-                        else if (strcmp(methodName, "GetUpperBound") == 0)
-                        {
-                            result = NI_System_Array_GetUpperBound;
-                        }
+                        z = FloatingPointUtils::maximumMagnitude(x, y);
                     }
-                    break;
                 }
-
-                case 'B':
+                else if (isNumber)
                 {
-                    if (strcmp(className, "BitConverter") == 0)
+                    z = FloatingPointUtils::maximumNumber(x, y);
+                }
+                else
+                {
+                    z = FloatingPointUtils::maximum(x, y);
+                }
+            }
+            else
+            {
+                if (isMagnitude)
+                {
+                    if (isNumber)
                     {
-                        if (strcmp(methodName, "DoubleToInt64Bits") == 0)
-                        {
-                            result = NI_System_BitConverter_DoubleToInt64Bits;
-                        }
-                        else if (strcmp(methodName, "DoubleToUInt64Bits") == 0)
-                        {
-                            result = NI_System_BitConverter_DoubleToInt64Bits;
-                        }
-                        else if (strcmp(methodName, "Int32BitsToSingle") == 0)
-                        {
-                            result = NI_System_BitConverter_Int32BitsToSingle;
-                        }
-                        else if (strcmp(methodName, "Int64BitsToDouble") == 0)
-                        {
-                            result = NI_System_BitConverter_Int64BitsToDouble;
-                        }
-                        else if (strcmp(methodName, "SingleToInt32Bits") == 0)
-                        {
-                            result = NI_System_BitConverter_SingleToInt32Bits;
-                        }
-                        else if (strcmp(methodName, "SingleToUInt32Bits") == 0)
-                        {
-                            result = NI_System_BitConverter_SingleToInt32Bits;
-                        }
-                        else if (strcmp(methodName, "UInt32BitsToSingle") == 0)
-                        {
-                            result = NI_System_BitConverter_Int32BitsToSingle;
-                        }
-                        else if (strcmp(methodName, "UInt64BitsToDouble") == 0)
-                        {
-                            result = NI_System_BitConverter_Int64BitsToDouble;
-                        }
+                        z = FloatingPointUtils::minimumMagnitudeNumber(x, y);
                     }
-                    else if (strcmp(className, "Buffer") == 0)
+                    else
                     {
-                        if (strcmp(methodName, "Memmove") == 0)
-                        {
-                            result = NI_System_Buffer_Memmove;
-                        }
+                        z = FloatingPointUtils::minimumMagnitude(x, y);
                     }
-                    break;
                 }
-
-                case 'E':
+                else if (isNumber)
                 {
-                    if (strcmp(className, "Enum") == 0)
-                    {
-                        if (strcmp(methodName, "HasFlag") == 0)
-                        {
-                            result = NI_System_Enum_HasFlag;
-                        }
-                    }
-                    else if (strcmp(className, "EETypePtr") == 0)
-                    {
+                    z = FloatingPointUtils::minimumNumber(x, y);
+                }
+                else
+                {
+                    z = FloatingPointUtils::minimum(x, y);
+                }
+            }
+            cnsNode->SetDconValue(z);
+
+            impPopStack();
+            impPopStack();
+
+            DEBUG_DESTROY_NODE(otherNode);
+            return cnsNode;
+        }
+
+        // only one is constant, we can fold in specialized scenarios
+
+        if (cnsNode->IsFloatNaN())
+        {
+            impSpillSideEffects(false, CHECK_SPILL_ALL DEBUGARG("spill side effects before propagating NaN"));
+
+            impPopStack();
+            impPopStack();
+
+            if (isNumber)
+            {
+                DEBUG_DESTROY_NODE(cnsNode);
+                return otherNode;
+            }
+            else
+            {
+                DEBUG_DESTROY_NODE(otherNode);
+                return cnsNode;
+            }
+        }
+
+#if defined(FEATURE_HW_INTRINSICS) && defined(TARGET_XARCH)
+        if (!isMagnitude && compOpportunisticallyDependsOn(InstructionSet_SSE2))
+        {
+            bool needsFixup = false;
+            bool canHandle  = false;
+
+            if (isMax)
+            {
+                // maxsd, maxss return op2 if both inputs are 0 of either sign
+                // we require +0 to be greater than -0 we also require NaN to
+                // not be propagated for isNumber and to be propagated otherwise.
+                //
+                // This means for isNumber we want to do `max other, cns` and
+                // can only handle cns being -0 if Avx512F is supported. This is
+                // because if other was NaN, we want to return the non-NaN cns.
+                // But if cns was -0 and other was +0 we'd want to return +0 and
+                // so need to be able to fixup the result.
+                //
+                // For !isNumber we have the inverse and want `max cns, other` and
+                // can only handle cns being +0 if Avx512F is supported. This is
+                // because if other was NaN, we want to return other and if cns
+                // was +0 and other was -0 we'd want to return +0 and so need
+                // so need to be able to fixup the result.
+
+                if (isNumber)
+                {
+                    needsFixup = cnsNode->IsFloatNegativeZero();
+                }
+                else
+                {
+                    needsFixup = cnsNode->IsFloatPositiveZero();
+                }
+
+                if (!needsFixup || compOpportunisticallyDependsOn(InstructionSet_AVX512F))
+                {
+                    // Given the checks, op1 can safely be the cns and op2 the other node
+
+                    intrinsicName = (callType == TYP_DOUBLE) ? NI_SSE2_Max : NI_SSE_Max;
+
+                    // one is constant and we know its something we can handle, so pop both peeked values
+
+                    op1 = cnsNode;
+                    op2 = otherNode;
+
+                    canHandle = true;
+                }
+            }
+            else
+            {
+                // minsd, minss return op2 if both inputs are 0 of either sign
+                // we require -0 to be lesser than +0, we also require NaN to
+                // not be propagated for isNumber and to be propagated otherwise.
+                //
+                // This means for isNumber we want to do `min other, cns` and
+                // can only handle cns being +0 if Avx512F is supported. This is
+                // because if other was NaN, we want to return the non-NaN cns.
+                // But if cns was +0 and other was -0 we'd want to return -0 and
+                // so need to be able to fixup the result.
+                //
+                // For !isNumber we have the inverse and want `min cns, other` and
+                // can only handle cns being -0 if Avx512F is supported. This is
+                // because if other was NaN, we want to return other and if cns
+                // was -0 and other was +0 we'd want to return -0 and so need
+                // so need to be able to fixup the result.
+
+                if (isNumber)
+                {
+                    needsFixup = cnsNode->IsFloatNegativeZero();
+                }
+                else
+                {
+                    needsFixup = cnsNode->IsFloatPositiveZero();
+                }
+
+                if (!needsFixup || compOpportunisticallyDependsOn(InstructionSet_AVX512F))
+                {
+                    // Given the checks, op1 can safely be the cns and op2 the other node
+
+                    intrinsicName = (callType == TYP_DOUBLE) ? NI_SSE2_Min : NI_SSE_Min;
+
+                    // one is constant and we know its something we can handle, so pop both peeked values
+
+                    op1 = cnsNode;
+                    op2 = otherNode;
+
+                    canHandle = true;
+                }
+            }
+
+            if (canHandle)
+            {
+                assert(op1->IsCnsFltOrDbl() && !op2->IsCnsFltOrDbl());
+
+                impPopStack();
+                impPopStack();
+
+                GenTreeVecCon* vecCon = gtNewVconNode(TYP_SIMD16);
+
+                if (callJitType == CORINFO_TYPE_FLOAT)
+                {
+                    vecCon->gtSimdVal.f32[0] = static_cast<float>(op1->AsDblCon()->DconValue());
+                }
+                else
+                {
+                    vecCon->gtSimdVal.f64[0] = op1->AsDblCon()->DconValue();
+                }
+
+                op1 = vecCon;
+                op2 = gtNewSimdCreateScalarUnsafeNode(TYP_SIMD16, op2, callJitType, 16);
+
+                GenTree* retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, op2, intrinsicName, callJitType, 16);
+
+                if (needsFixup)
+                {
+                    GenTree* op2Clone;
+                    op2 = impCloneExpr(op2, &op2Clone, CHECK_SPILL_ALL,
+                                       nullptr DEBUGARG("Cloning non-constant for Math.Max/Min"));
+
+                    retNode->AsHWIntrinsic()->Op(2) = op2;
+
+                    GenTreeVecCon* tbl = gtNewVconNode(TYP_SIMD16);
+
+                    // FixupScalar(left, right, table, control) computes the input type of right
+                    // adjusts it based on the table and then returns
+                    //
+                    // In our case, left is going to be the result of the RangeScalar operation
+                    // and right is going to be op1 or op2. In the case op1/op2 is QNaN or SNaN
+                    // we want to preserve it instead. Otherwise we want to preserve the original
+                    // result computed by RangeScalar.
+                    //
+                    // If both inputs are NaN, then we'll end up taking op1 by virtue of it being
+                    // the latter fixup.
+
+                    if (isMax)
+                    {
+                        // QNAN: 0b0000:  Preserve left
+                        // SNAN: 0b0000
+                        // ZERO: 0b1000:  +0
+                        // +ONE: 0b0000
+                        // -INF: 0b0000
+                        // +INF: 0b0000
+                        // -VAL: 0b0000
+                        // +VAL: 0b0000
+                        tbl->gtSimdVal.i32[0] = 0x0800;
+                    }
+                    else
+                    {
+                        // QNAN: 0b0000:  Preserve left
+                        // SNAN: 0b0000
+                        // ZERO: 0b0111:  -0
+                        // +ONE: 0b0000
+                        // -INF: 0b0000
+                        // +INF: 0b0000
+                        // -VAL: 0b0000
+                        // +VAL: 0b0000
+                        tbl->gtSimdVal.i32[0] = 0x0700;
+                    }
+
+                    retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, retNode, op2Clone, tbl, gtNewIconNode(0),
+                                                       NI_AVX512F_FixupScalar, callJitType, 16);
+                }
+
+                if (isNumber)
+                {
+                    std::swap(op1, op2);
+
+                    retNode->AsHWIntrinsic()->Op(1) = op2;
+                    retNode->AsHWIntrinsic()->Op(2) = op1;
+                }
+
+                return gtNewSimdHWIntrinsicNode(callType, retNode, NI_Vector128_ToScalar, callJitType, 16);
+            }
+        }
+#endif // FEATURE_HW_INTRINSICS && TARGET_XARCH
+    }
+
+#if defined(FEATURE_HW_INTRINSICS) && defined(TARGET_XARCH)
+    if (compOpportunisticallyDependsOn(InstructionSet_AVX512DQ))
+    {
+        // We are constructing a chain of intrinsics similar to:
+        //    var op1 = Vector128.CreateScalarUnsafe(x);
+        //    var op2 = Vector128.CreateScalarUnsafe(y);
+        //
+        //    var tmp = Avx512DQ.RangeScalar(op1, op2, imm8);
+        //    var tbl = Vector128.CreateScalarUnsafe(0x00);
+        //
+        //    tmp = Avx512F.FixupScalar(tmp, op2, tbl, 0x00);
+        //    tmp = Avx512F.FixupScalar(tmp, op1, tbl, 0x00);
+        //
+        //    return tmp.ToScalar();
+
+        // RangeScalar operates by default almost as MaxNumber or MinNumber
+        // but, it propagates sNaN and does not propagate qNaN. So we need
+        // an additional fixup to ensure we propagate qNaN as well.
+
+        uint8_t imm8;
+
+        if (isMax)
+        {
+            if (isMagnitude)
+            {
+                // 0b01_11: Sign(CompareResult), Max-Abs Value
+                imm8 = 0x07;
+            }
+            else
+            {
+                // 0b01_01: Sign(CompareResult), Max Value
+                imm8 = 0x05;
+            }
+        }
+        else if (isMagnitude)
+        {
+            // 0b01_10: Sign(CompareResult), Min-Abs Value
+            imm8 = 0x06;
+        }
+        else
+        {
+            // 0b01_00: Sign(CompareResult), Min Value
+            imm8 = 0x04;
+        }
+
+        GenTree* op3 = gtNewIconNode(imm8);
+        GenTree* op2 = gtNewSimdCreateScalarUnsafeNode(TYP_SIMD16, impPopStack().val, callJitType, 16);
+        GenTree* op1 = gtNewSimdCreateScalarUnsafeNode(TYP_SIMD16, impPopStack().val, callJitType, 16);
+
+        GenTree* op2Clone;
+        op2 = impCloneExpr(op2, &op2Clone, CHECK_SPILL_ALL, nullptr DEBUGARG("Cloning op2 for Math.Max/Min"));
+
+        GenTree* op1Clone;
+        op1 = impCloneExpr(op1, &op1Clone, CHECK_SPILL_ALL, nullptr DEBUGARG("Cloning op1 for Math.Max/Min"));
+
+        GenTree* tmp = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, op2, op3, NI_AVX512DQ_RangeScalar, callJitType, 16);
+
+        // FixupScalar(left, right, table, control) computes the input type of right
+        // adjusts it based on the table and then returns
+        //
+        // In our case, left is going to be the result of the RangeScalar operation,
+        // which is either sNaN or a normal value, and right is going to be op1 or op2.
+
+        GenTree* tbl1 = gtNewVconNode(TYP_SIMD16);
+        GenTree* tbl2;
+
+        // We currently have (commutative)
+        // * snan, snan = snan
+        // * snan, qnan = snan
+        // * snan, norm = snan
+        // * qnan, qnan = qnan
+        // * qnan, norm = norm
+        // * norm, norm = norm
+
+        if (isNumber)
+        {
+            // We need to fixup the case of:
+            // * snan, norm = snan
+            //
+            // Instead, it should be:
+            // * snan, norm = norm
+
+            // First look at op1 and op2 using op2 as the classification
+            //
+            // If op2 is norm, we take op2 (norm)
+            // If op2 is  nan, we take op1 ( nan or norm)
+            //
+            // Thus, if one input was norm the fixup is now norm
+
+            // QNAN: 0b0000:  Preserve left
+            // SNAN: 0b0000
+            // ZERO: 0b0001:  Preserve right
+            // +ONE: 0b0001
+            // -INF: 0b0001
+            // +INF: 0b0001
+            // -VAL: 0b0001
+            // +VAL: 0b0001
+            tbl1->AsVecCon()->gtSimdVal.i32[0] = 0x11111100;
+
+            // Next look at result and fixup using result as the classification
+            //
+            // If result is norm, we take the result (norm)
+            // If result is  nan, we take the fixup  ( nan or norm)
+            //
+            // Thus if either input was snan, we now have norm as expected
+            // Otherwise, the result was already correct
+
+            tbl1 = impCloneExpr(tbl1, &tbl2, CHECK_SPILL_ALL, nullptr DEBUGARG("Cloning tbl for Math.Max/Min"));
+
+            op1Clone = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1Clone, op2Clone, tbl1, gtNewIconNode(0),
+                                                NI_AVX512F_FixupScalar, callJitType, 16);
+
+            tmp = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1Clone, tmp, tbl2, gtNewIconNode(0), NI_AVX512F_FixupScalar,
+                                           callJitType, 16);
+        }
+        else
+        {
+            // We need to fixup the case of:
+            // * qnan, norm = norm
+            //
+            // Instead, it should be:
+            // * qnan, norm = qnan
+
+            // First look at op1 and op2 using op2 as the classification
+            //
+            // If op2 is norm, we take op1 ( nan or norm)
+            // If op2 is snan, we take op1 ( nan or norm)
+            // If op2 is qnan, we take op2 (qnan)
+            //
+            // Thus, if either input was qnan the fixup is now qnan
+
+            // QNAN: 0b0001:  Preserve right
+            // SNAN: 0b0000:  Preserve left
+            // ZERO: 0b0000
+            // +ONE: 0b0000
+            // -INF: 0b0000
+            // +INF: 0b0000
+            // -VAL: 0b0000
+            // +VAL: 0b0000
+            tbl1->AsVecCon()->gtSimdVal.i32[0] = 0x00000001;
+
+            // Next look at result and fixup using fixup as the classification
+            //
+            // If fixup is norm, we take the result (norm)
+            // If fixup is sNaN, we take the result (sNaN)
+            // If fixup is qNaN, we take the fixup  (qNaN)
+            //
+            // Thus if the fixup was qnan, we now have qnan as expected
+            // Otherwise, the result was already correct
+
+            tbl1 = impCloneExpr(tbl1, &tbl2, CHECK_SPILL_ALL, nullptr DEBUGARG("Cloning tbl for Math.Max/Min"));
+
+            op1Clone = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1Clone, op2Clone, tbl1, gtNewIconNode(0),
+                                                NI_AVX512F_FixupScalar, callJitType, 16);
+
+            tmp = gtNewSimdHWIntrinsicNode(TYP_SIMD16, tmp, op1Clone, tbl2, gtNewIconNode(0), NI_AVX512F_FixupScalar,
+                                           callJitType, 16);
+        }
+
+        return gtNewSimdHWIntrinsicNode(callType, tmp, NI_Vector128_ToScalar, callJitType, 16);
+    }
+#endif // FEATURE_HW_INTRINSICS && TARGET_XARCH
+
+    return impMathIntrinsic(method, sig, callType, intrinsicName, tailCall);
+}
+
+//------------------------------------------------------------------------
+// lookupNamedIntrinsic: map method to jit named intrinsic value
+//
+// Arguments:
+//    method -- method handle for method
+//
+// Return Value:
+//    Id for the named intrinsic, or Illegal if none.
+//
+// Notes:
+//    method should have CORINFO_FLG_INTRINSIC set in its attributes,
+//    otherwise it is not a named jit intrinsic.
+//
+NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
+{
+    const char* className          = nullptr;
+    const char* namespaceName      = nullptr;
+    const char* enclosingClassName = nullptr;
+    const char* methodName =
+        info.compCompHnd->getMethodNameFromMetadata(method, &className, &namespaceName, &enclosingClassName);
+
+    JITDUMP("Named Intrinsic ");
+
+    if (namespaceName != nullptr)
+    {
+        JITDUMP("%s.", namespaceName);
+    }
+    if (enclosingClassName != nullptr)
+    {
+        JITDUMP("%s.", enclosingClassName);
+    }
+    if (className != nullptr)
+    {
+        JITDUMP("%s.", className);
+    }
+    if (methodName != nullptr)
+    {
+        JITDUMP("%s", methodName);
+    }
+
+    if ((namespaceName == nullptr) || (className == nullptr) || (methodName == nullptr))
+    {
+        // Check if we are dealing with an MD array's known runtime method
+        CorInfoArrayIntrinsic arrayFuncIndex = info.compCompHnd->getArrayIntrinsicID(method);
+        switch (arrayFuncIndex)
+        {
+            case CorInfoArrayIntrinsic::GET:
+                JITDUMP("ARRAY_FUNC_GET: Recognized\n");
+                return NI_Array_Get;
+            case CorInfoArrayIntrinsic::SET:
+                JITDUMP("ARRAY_FUNC_SET: Recognized\n");
+                return NI_Array_Set;
+            case CorInfoArrayIntrinsic::ADDRESS:
+                JITDUMP("ARRAY_FUNC_ADDRESS: Recognized\n");
+                return NI_Array_Address;
+            default:
+                break;
+        }
+
+        JITDUMP(": Not recognized, not enough metadata\n");
+        return NI_Illegal;
+    }
+
+    JITDUMP(": ");
+
+    NamedIntrinsic result = NI_Illegal;
+
+    if (strncmp(namespaceName, "System", 6) == 0)
+    {
+        namespaceName += 6;
+
+        if (namespaceName[0] == '\0')
+        {
+            switch (className[0])
+            {
+                case 'A':
+                {
+                    if (strcmp(className, "Activator") == 0)
+                    {
+                        if (strcmp(methodName, "AllocatorOf") == 0)
+                        {
+                            result = NI_System_Activator_AllocatorOf;
+                        }
+                        else if (strcmp(methodName, "DefaultConstructorOf") == 0)
+                        {
+                            result = NI_System_Activator_DefaultConstructorOf;
+                        }
+                    }
+                    else if (strcmp(className, "Array") == 0)
+                    {
+                        if (strcmp(methodName, "Clone") == 0)
+                        {
+                            result = NI_System_Array_Clone;
+                        }
+                        else if (strcmp(methodName, "GetLength") == 0)
+                        {
+                            result = NI_System_Array_GetLength;
+                        }
+                        else if (strcmp(methodName, "GetLowerBound") == 0)
+                        {
+                            result = NI_System_Array_GetLowerBound;
+                        }
+                        else if (strcmp(methodName, "GetUpperBound") == 0)
+                        {
+                            result = NI_System_Array_GetUpperBound;
+                        }
+                    }
+                    break;
+                }
+
+                case 'B':
+                {
+                    if (strcmp(className, "BitConverter") == 0)
+                    {
+                        if (strcmp(methodName, "DoubleToInt64Bits") == 0)
+                        {
+                            result = NI_System_BitConverter_DoubleToInt64Bits;
+                        }
+                        else if (strcmp(methodName, "DoubleToUInt64Bits") == 0)
+                        {
+                            result = NI_System_BitConverter_DoubleToInt64Bits;
+                        }
+                        else if (strcmp(methodName, "Int32BitsToSingle") == 0)
+                        {
+                            result = NI_System_BitConverter_Int32BitsToSingle;
+                        }
+                        else if (strcmp(methodName, "Int64BitsToDouble") == 0)
+                        {
+                            result = NI_System_BitConverter_Int64BitsToDouble;
+                        }
+                        else if (strcmp(methodName, "SingleToInt32Bits") == 0)
+                        {
+                            result = NI_System_BitConverter_SingleToInt32Bits;
+                        }
+                        else if (strcmp(methodName, "SingleToUInt32Bits") == 0)
+                        {
+                            result = NI_System_BitConverter_SingleToInt32Bits;
+                        }
+                        else if (strcmp(methodName, "UInt32BitsToSingle") == 0)
+                        {
+                            result = NI_System_BitConverter_Int32BitsToSingle;
+                        }
+                        else if (strcmp(methodName, "UInt64BitsToDouble") == 0)
+                        {
+                            result = NI_System_BitConverter_Int64BitsToDouble;
+                        }
+                    }
+                    else if (strcmp(className, "Buffer") == 0)
+                    {
+                        if (strcmp(methodName, "Memmove") == 0)
+                        {
+                            result = NI_System_Buffer_Memmove;
+                        }
+                    }
+                    break;
+                }
+
+                case 'D':
+                {
+                    if (strcmp(className, "Double") == 0)
+                    {
+                        result = lookupPrimitiveFloatNamedIntrinsic(method, methodName);
+                    }
+                    break;
+                }
+
+                case 'E':
+                {
+                    if (strcmp(className, "Enum") == 0)
+                    {
+                        if (strcmp(methodName, "HasFlag") == 0)
+                        {
+                            result = NI_System_Enum_HasFlag;
+                        }
+                    }
+                    else if (strcmp(className, "EETypePtr") == 0)
+                    {
                         if (strcmp(methodName, "EETypePtrOf") == 0)
                         {
                             result = NI_System_EETypePtr_EETypePtrOf;
@@ -8186,7 +8595,7 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
                     if ((strcmp(className, "Int32") == 0) || (strcmp(className, "Int64") == 0) ||
                         (strcmp(className, "IntPtr") == 0))
                     {
-                        result = lookupPrimitiveNamedIntrinsic(method, methodName);
+                        result = lookupPrimitiveIntNamedIntrinsic(method, methodName);
                     }
                     break;
                 }
@@ -8195,126 +8604,7 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
                 {
                     if ((strcmp(className, "Math") == 0) || (strcmp(className, "MathF") == 0))
                     {
-                        if (strcmp(methodName, "Abs") == 0)
-                        {
-                            result = NI_System_Math_Abs;
-                        }
-                        else if (strcmp(methodName, "Acos") == 0)
-                        {
-                            result = NI_System_Math_Acos;
-                        }
-                        else if (strcmp(methodName, "Acosh") == 0)
-                        {
-                            result = NI_System_Math_Acosh;
-                        }
-                        else if (strcmp(methodName, "Asin") == 0)
-                        {
-                            result = NI_System_Math_Asin;
-                        }
-                        else if (strcmp(methodName, "Asinh") == 0)
-                        {
-                            result = NI_System_Math_Asinh;
-                        }
-                        else if (strcmp(methodName, "Atan") == 0)
-                        {
-                            result = NI_System_Math_Atan;
-                        }
-                        else if (strcmp(methodName, "Atanh") == 0)
-                        {
-                            result = NI_System_Math_Atanh;
-                        }
-                        else if (strcmp(methodName, "Atan2") == 0)
-                        {
-                            result = NI_System_Math_Atan2;
-                        }
-                        else if (strcmp(methodName, "Cbrt") == 0)
-                        {
-                            result = NI_System_Math_Cbrt;
-                        }
-                        else if (strcmp(methodName, "Ceiling") == 0)
-                        {
-                            result = NI_System_Math_Ceiling;
-                        }
-                        else if (strcmp(methodName, "Cos") == 0)
-                        {
-                            result = NI_System_Math_Cos;
-                        }
-                        else if (strcmp(methodName, "Cosh") == 0)
-                        {
-                            result = NI_System_Math_Cosh;
-                        }
-                        else if (strcmp(methodName, "Exp") == 0)
-                        {
-                            result = NI_System_Math_Exp;
-                        }
-                        else if (strcmp(methodName, "Floor") == 0)
-                        {
-                            result = NI_System_Math_Floor;
-                        }
-                        else if (strcmp(methodName, "FMod") == 0)
-                        {
-                            result = NI_System_Math_FMod;
-                        }
-                        else if (strcmp(methodName, "FusedMultiplyAdd") == 0)
-                        {
-                            result = NI_System_Math_FusedMultiplyAdd;
-                        }
-                        else if (strcmp(methodName, "ILogB") == 0)
-                        {
-                            result = NI_System_Math_ILogB;
-                        }
-                        else if (strcmp(methodName, "Log") == 0)
-                        {
-                            result = NI_System_Math_Log;
-                        }
-                        else if (strcmp(methodName, "Log2") == 0)
-                        {
-                            result = NI_System_Math_Log2;
-                        }
-                        else if (strcmp(methodName, "Log10") == 0)
-                        {
-                            result = NI_System_Math_Log10;
-                        }
-                        else if (strcmp(methodName, "Max") == 0)
-                        {
-                            result = NI_System_Math_Max;
-                        }
-                        else if (strcmp(methodName, "Min") == 0)
-                        {
-                            result = NI_System_Math_Min;
-                        }
-                        else if (strcmp(methodName, "Pow") == 0)
-                        {
-                            result = NI_System_Math_Pow;
-                        }
-                        else if (strcmp(methodName, "Round") == 0)
-                        {
-                            result = NI_System_Math_Round;
-                        }
-                        else if (strcmp(methodName, "Sin") == 0)
-                        {
-                            result = NI_System_Math_Sin;
-                        }
-                        else if (strcmp(methodName, "Sinh") == 0)
-                        {
-                            result = NI_System_Math_Sinh;
-                        }
-                        else if (strcmp(methodName, "Sqrt") == 0)
-                        {
-                            result = NI_System_Math_Sqrt;
-                        }
-                        else if (strcmp(methodName, "Tan") == 0)
-                        {
-                            result = NI_System_Math_Tan;
-                        }
-                        else if (strcmp(methodName, "Tanh") == 0)
-                        {
-                            result = NI_System_Math_Tanh;
-                        }
-                        else if (strcmp(methodName, "Truncate") == 0)
-                        {
-                            result = NI_System_Math_Truncate;
-                        }
+                        result = lookupPrimitiveFloatNamedIntrinsic(method, methodName);
                     }
                     else if (strcmp(className, "MemoryExtensions") == 0)
                     {
@@ -8390,7 +8680,11 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
 
                 case 'S':
                 {
-                    if (strcmp(className, "Span`1") == 0)
+                    if (strcmp(className, "Single") == 0)
+                    {
+                        result = lookupPrimitiveFloatNamedIntrinsic(method, methodName);
+                    }
+                    else if (strcmp(className, "Span`1") == 0)
                     {
                         if (strcmp(methodName, "get_Item") == 0)
                         {
@@ -8487,7 +8781,7 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
                     if ((strcmp(className, "UInt32") == 0) || (strcmp(className, "UInt64") == 0) ||
                         (strcmp(className, "UIntPtr") == 0))
                     {
-                        result = lookupPrimitiveNamedIntrinsic(method, methodName);
+                        result = lookupPrimitiveIntNamedIntrinsic(method, methodName);
                     }
                     break;
                 }
@@ -8534,7 +8828,7 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
             {
                 if (strcmp(className, "BitOperations") == 0)
                 {
-                    result = lookupPrimitiveNamedIntrinsic(method, methodName);
+                    result = lookupPrimitiveIntNamedIntrinsic(method, methodName);
                 }
                 else
                 {
@@ -8895,7 +9189,311 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
 }
 
 //------------------------------------------------------------------------
-// lookupPrimitiveNamedIntrinsic: map method to jit named intrinsic value
+// lookupPrimitiveFloatNamedIntrinsic: map method to jit named intrinsic value
+//
+// Arguments:
+//    method -- method handle for method
+//
+// Return Value:
+//    Id for the named intrinsic, or Illegal if none.
+//
+// Notes:
+//    method should have CORINFO_FLG_INTRINSIC set in its attributes,
+//    otherwise it is not a named jit intrinsic.
+//
+NamedIntrinsic Compiler::lookupPrimitiveFloatNamedIntrinsic(CORINFO_METHOD_HANDLE method, const char* methodName)
+{
+    NamedIntrinsic result = NI_Illegal;
+
+    switch (methodName[0])
+    {
+        case 'A':
+        {
+            if (strcmp(methodName, "Abs") == 0)
+            {
+                result = NI_System_Math_Abs;
+            }
+            else if (strncmp(methodName, "Acos", 4) == 0)
+            {
+                methodName += 4;
+
+                if (methodName[0] == '\0')
+                {
+                    result = NI_System_Math_Acos;
+                }
+                else if (methodName[1] == '\0')
+                {
+                    if (methodName[0] == 'h')
+                    {
+                        result = NI_System_Math_Acosh;
+                    }
+                }
+            }
+            else if (strncmp(methodName, "Asin", 4) == 0)
+            {
+                methodName += 4;
+
+                if (methodName[0] == '\0')
+                {
+                    result = NI_System_Math_Asin;
+                }
+                else if (methodName[1] == '\0')
+                {
+                    if (methodName[0] == 'h')
+                    {
+                        result = NI_System_Math_Asinh;
+                    }
+                }
+            }
+            else if (strncmp(methodName, "Atan", 4) == 0)
+            {
+                methodName += 4;
+
+                if (methodName[0] == '\0')
+                {
+                    result = NI_System_Math_Atan;
+                }
+                else if (methodName[1] == '\0')
+                {
+                    if (methodName[0] == 'h')
+                    {
+                        result = NI_System_Math_Atanh;
+                    }
+                    else if (methodName[0] == '2')
+                    {
+                        result = NI_System_Math_Atan2;
+                    }
+                }
+            }
+            break;
+        }
+
+        case 'C':
+        {
+            if (strcmp(methodName, "Cbrt") == 0)
+            {
+                result = NI_System_Math_Cbrt;
+            }
+            else if (strcmp(methodName, "Ceiling") == 0)
+            {
+                result = NI_System_Math_Ceiling;
+            }
+            else if (strncmp(methodName, "Cos", 3) == 0)
+            {
+                methodName += 3;
+
+                if (methodName[0] == '\0')
+                {
+                    result = NI_System_Math_Cos;
+                }
+                else if (methodName[1] == '\0')
+                {
+                    if (methodName[0] == 'h')
+                    {
+                        result = NI_System_Math_Cosh;
+                    }
+                }
+            }
+            break;
+        }
+
+        case 'E':
+        {
+            if (strcmp(methodName, "Exp") == 0)
+            {
+                result = NI_System_Math_Exp;
+            }
+            break;
+        }
+
+        case 'F':
+        {
+            if (strcmp(methodName, "Floor") == 0)
+            {
+                result = NI_System_Math_Floor;
+            }
+            else if (strcmp(methodName, "FMod") == 0)
+            {
+                result = NI_System_Math_FMod;
+            }
+            else if (strcmp(methodName, "FusedMultiplyAdd") == 0)
+            {
+                result = NI_System_Math_FusedMultiplyAdd;
+            }
+            break;
+        }
+
+        case 'I':
+        {
+            if (strcmp(methodName, "ILogB") == 0)
+            {
+                result = NI_System_Math_ILogB;
+            }
+            break;
+        }
+
+        case 'L':
+        {
+            if (strncmp(methodName, "Log", 3) == 0)
+            {
+                methodName += 3;
+
+                if (methodName[0] == '\0')
+                {
+                    result = NI_System_Math_Log;
+                }
+                else if (methodName[1] == '\0')
+                {
+                    if (methodName[0] == '2')
+                    {
+                        result = NI_System_Math_Log2;
+                    }
+                }
+                else if (strcmp(methodName, "10") == 0)
+                {
+                    result = NI_System_Math_Log10;
+                }
+            }
+            break;
+        }
+
+        case 'M':
+        {
+            if (strncmp(methodName, "Max", 3) == 0)
+            {
+                methodName += 3;
+
+                if (methodName[0] == '\0')
+                {
+                    result = NI_System_Math_Max;
+                }
+                else if (strncmp(methodName, "Magnitude", 9) == 0)
+                {
+                    methodName += 9;
+
+                    if (methodName[0] == '\0')
+                    {
+                        result = NI_System_Math_MaxMagnitude;
+                    }
+                    else if (strcmp(methodName, "Number") == 0)
+                    {
+                        result = NI_System_Math_MaxMagnitudeNumber;
+                    }
+                }
+                else if (strcmp(methodName, "Number") == 0)
+                {
+                    result = NI_System_Math_MaxNumber;
+                }
+            }
+            else if (strncmp(methodName, "Min", 3) == 0)
+            {
+                methodName += 3;
+
+                if (methodName[0] == '\0')
+                {
+                    result = NI_System_Math_Min;
+                }
+                else if (strncmp(methodName, "Magnitude", 9) == 0)
+                {
+                    methodName += 9;
+
+                    if (methodName[0] == '\0')
+                    {
+                        result = NI_System_Math_MinMagnitude;
+                    }
+                    else if (strcmp(methodName, "Number") == 0)
+                    {
+                        result = NI_System_Math_MinMagnitudeNumber;
+                    }
+                }
+                else if (strcmp(methodName, "Number") == 0)
+                {
+                    result = NI_System_Math_MinNumber;
+                }
+            }
+            break;
+        }
+
+        case 'P':
+        {
+            if (strcmp(methodName, "Pow") == 0)
+            {
+                result = NI_System_Math_Pow;
+            }
+            break;
+        }
+
+        case 'R':
+        {
+            if (strcmp(methodName, "Round") == 0)
+            {
+                result = NI_System_Math_Round;
+            }
+            break;
+        }
+
+        case 'S':
+        {
+            if (strncmp(methodName, "Sin", 3) == 0)
+            {
+                methodName += 3;
+
+                if (methodName[0] == '\0')
+                {
+                    result = NI_System_Math_Sin;
+                }
+                else if (methodName[1] == '\0')
+                {
+                    if (methodName[0] == 'h')
+                    {
+                        result = NI_System_Math_Sinh;
+                    }
+                }
+            }
+            else if (strcmp(methodName, "Sqrt") == 0)
+            {
+                result = NI_System_Math_Sqrt;
+            }
+            break;
+        }
+
+        case 'T':
+        {
+            if (strncmp(methodName, "Tan", 3) == 0)
+            {
+                methodName += 3;
+
+                if (methodName[0] == '\0')
+                {
+                    result = NI_System_Math_Tan;
+                }
+                else if (methodName[1] == '\0')
+                {
+                    if (methodName[0] == 'h')
+                    {
+                        result = NI_System_Math_Tanh;
+                    }
+                }
+                result = NI_System_Math_Tan;
+            }
+            else if (strcmp(methodName, "Truncate") == 0)
+            {
+                result = NI_System_Math_Truncate;
+            }
+            break;
+        }
+
+        default:
+        {
+            break;
+        }
+    }
+
+    return result;
+}
+
+//------------------------------------------------------------------------
+// lookupPrimitiveIntNamedIntrinsic: map method to jit named intrinsic value
 //
 // Arguments:
 //    method -- method handle for method
@@ -8907,7 +9505,7 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
 //    method should have CORINFO_FLG_INTRINSIC set in its attributes,
 //    otherwise it is not a named jit intrinsic.
 //
-NamedIntrinsic Compiler::lookupPrimitiveNamedIntrinsic(CORINFO_METHOD_HANDLE method, const char* methodName)
+NamedIntrinsic Compiler::lookupPrimitiveIntNamedIntrinsic(CORINFO_METHOD_HANDLE method, const char* methodName)
 {
     NamedIntrinsic result = NI_Illegal;
 
index 23be483..1d22c19 100644 (file)
@@ -873,6 +873,9 @@ int LinearScan::BuildNode(GenTree* tree)
             {
                 case NI_System_Math_Max:
                 case NI_System_Math_Min:
+                case NI_System_Math_MaxNumber:
+                case NI_System_Math_MinNumber:
+                {
                     assert(varTypeIsFloating(tree->gtGetOp1()));
                     assert(varTypeIsFloating(tree->gtGetOp2()));
                     assert(tree->gtGetOp1()->TypeIs(tree->TypeGet()));
@@ -881,6 +884,7 @@ int LinearScan::BuildNode(GenTree* tree)
                     assert(dstCount == 1);
                     BuildDef(tree);
                     break;
+                }
 
                 case NI_System_Math_Abs:
                 case NI_System_Math_Ceiling:
@@ -888,6 +892,7 @@ int LinearScan::BuildNode(GenTree* tree)
                 case NI_System_Math_Truncate:
                 case NI_System_Math_Round:
                 case NI_System_Math_Sqrt:
+                {
                     assert(varTypeIsFloating(tree->gtGetOp1()));
                     assert(tree->gtGetOp1()->TypeIs(tree->TypeGet()));
 
@@ -896,6 +901,7 @@ int LinearScan::BuildNode(GenTree* tree)
                     assert(dstCount == 1);
                     BuildDef(tree);
                     break;
+                }
 
                 default:
                     unreached();
index 6bc31d3..1fcfc09 100644 (file)
@@ -44,7 +44,13 @@ enum NamedIntrinsic : unsigned short
     NI_System_Math_Log2,
     NI_System_Math_Log10,
     NI_System_Math_Max,
+    NI_System_Math_MaxMagnitude,
+    NI_System_Math_MaxMagnitudeNumber,
+    NI_System_Math_MaxNumber,
     NI_System_Math_Min,
+    NI_System_Math_MinMagnitude,
+    NI_System_Math_MinMagnitudeNumber,
+    NI_System_Math_MinNumber,
     NI_System_Math_Pow,
     NI_System_Math_Round,
     NI_System_Math_Sin,
index 76fa1dd..93a8292 100644 (file)
@@ -2423,9 +2423,10 @@ bool FloatingPointUtils::isPositiveZero(double val)
 
 //------------------------------------------------------------------------
 // maximum: This matches the IEEE 754:2019 `maximum` function
-//    It propagates NaN inputs back to the caller and
-//    otherwise returns the larger of the inputs. It
-//    treats +0 as larger than -0 as per the specification.
+//
+// It propagates NaN inputs back to the caller and
+// otherwise returns the greater of the inputs. It
+// treats +0 as greater than -0 as per the specification.
 //
 // Arguments:
 //    val1 - left operand
@@ -2434,7 +2435,6 @@ bool FloatingPointUtils::isPositiveZero(double val)
 // Return Value:
 //    Either val1 or val2
 //
-
 double FloatingPointUtils::maximum(double val1, double val2)
 {
     if (val1 != val2)
@@ -2443,16 +2443,112 @@ double FloatingPointUtils::maximum(double val1, double val2)
         {
             return val2 < val1 ? val1 : val2;
         }
+
         return val1;
     }
+
     return isNegative(val2) ? val1 : val2;
 }
 
 //------------------------------------------------------------------------
+// maximumMagnitude: This matches the IEEE 754:2019 `maximumMagnitude` function
+//
+// It propagates NaN inputs back to the caller and
+// otherwise returns the input with a greater magnitude.
+// It treats +0 as greater than -0 as per the specification.
+//
+// Arguments:
+//    x - left operand
+//    y - right operand
+//
+// Return Value:
+//    Either x or y
+//
+double FloatingPointUtils::maximumMagnitude(double x, double y)
+{
+    double ax = fabs(x);
+    double ay = fabs(y);
+
+    if ((ax > ay) || isNaN(ax))
+    {
+        return x;
+    }
+
+    if (ax == ay)
+    {
+        return isNegative(x) ? y : x;
+    }
+
+    return y;
+}
+
+//------------------------------------------------------------------------
+// maximumMagnitudeNumber: // This matches the IEEE 754:2019 `maximumMagnitudeNumber` function
+//
+// It does not propagate NaN inputs back to the caller and
+// otherwise returns the input with a larger magnitude.
+// It treats +0 as larger than -0 as per the specification.
+//
+// Arguments:
+//    x - left operand
+//    y - right operand
+//
+// Return Value:
+//    Either x or y
+//
+double FloatingPointUtils::maximumMagnitudeNumber(double x, double y)
+{
+    double ax = fabs(x);
+    double ay = fabs(y);
+
+    if ((ax > ay) || isNaN(ay))
+    {
+        return x;
+    }
+
+    if (ax == ay)
+    {
+        return isNegative(x) ? y : x;
+    }
+
+    return y;
+}
+
+//------------------------------------------------------------------------
+// maximumNumber: This matches the IEEE 754:2019 `maximumNumber` function
+//
+// It does not propagate NaN inputs back to the caller and
+// otherwise returns the larger of the inputs. It
+// treats +0 as larger than -0 as per the specification.
+//
+// Arguments:
+//    x - left operand
+//    y - right operand
+//
+// Return Value:
+//    Either x or y
+//
+double FloatingPointUtils::maximumNumber(double x, double y)
+{
+    if (x != y)
+    {
+        if (!isNaN(y))
+        {
+            return y < x ? x : y;
+        }
+
+        return x;
+    }
+
+    return isNegative(y) ? x : y;
+}
+
+//------------------------------------------------------------------------
 // maximum: This matches the IEEE 754:2019 `maximum` function
-//    It propagates NaN inputs back to the caller and
-//    otherwise returns the larger of the inputs. It
-//    treats +0 as larger than -0 as per the specification.
+//
+// It propagates NaN inputs back to the caller and
+// otherwise returns the greater of the inputs. It
+// treats +0 as greater than -0 as per the specification.
 //
 // Arguments:
 //    val1 - left operand
@@ -2461,7 +2557,6 @@ double FloatingPointUtils::maximum(double val1, double val2)
 // Return Value:
 //    Either val1 or val2
 //
-
 float FloatingPointUtils::maximum(float val1, float val2)
 {
     if (val1 != val2)
@@ -2470,16 +2565,112 @@ float FloatingPointUtils::maximum(float val1, float val2)
         {
             return val2 < val1 ? val1 : val2;
         }
+
         return val1;
     }
+
     return isNegative(val2) ? val1 : val2;
 }
 
 //------------------------------------------------------------------------
+// maximumMagnitude: This matches the IEEE 754:2019 `maximumMagnitude` function
+//
+// It propagates NaN inputs back to the caller and
+// otherwise returns the input with a greater magnitude.
+// It treats +0 as greater than -0 as per the specification.
+//
+// Arguments:
+//    x - left operand
+//    y - right operand
+//
+// Return Value:
+//    Either x or y
+//
+float FloatingPointUtils::maximumMagnitude(float x, float y)
+{
+    float ax = fabsf(x);
+    float ay = fabsf(y);
+
+    if ((ax > ay) || isNaN(ax))
+    {
+        return x;
+    }
+
+    if (ax == ay)
+    {
+        return isNegative(x) ? y : x;
+    }
+
+    return y;
+}
+
+//------------------------------------------------------------------------
+// maximumMagnitudeNumber: This matches the IEEE 754:2019 `maximumMagnitudeNumber` function
+//
+// It does not propagate NaN inputs back to the caller and
+// otherwise returns the input with a larger magnitude.
+// It treats +0 as larger than -0 as per the specification.
+//
+// Arguments:
+//    x - left operand
+//    y - right operand
+//
+// Return Value:
+//    Either x or y
+//
+float FloatingPointUtils::maximumMagnitudeNumber(float x, float y)
+{
+    float ax = fabsf(x);
+    float ay = fabsf(y);
+
+    if ((ax > ay) || isNaN(ay))
+    {
+        return x;
+    }
+
+    if (ax == ay)
+    {
+        return isNegative(x) ? y : x;
+    }
+
+    return y;
+}
+
+//------------------------------------------------------------------------
+// maximumNumber: This matches the IEEE 754:2019 `maximumNumber` function
+//
+// It does not propagate NaN inputs back to the caller and
+// otherwise returns the larger of the inputs. It
+// treats +0 as larger than -0 as per the specification.
+//
+// Arguments:
+//    x - left operand
+//    y - right operand
+//
+// Return Value:
+//    Either x or y
+//
+float FloatingPointUtils::maximumNumber(float x, float y)
+{
+    if (x != y)
+    {
+        if (!isNaN(y))
+        {
+            return y < x ? x : y;
+        }
+
+        return x;
+    }
+
+    return isNegative(y) ? x : y;
+}
+
+//------------------------------------------------------------------------
 // minimum: This matches the IEEE 754:2019 `minimum` function
-//    It propagates NaN inputs back to the caller and
-//    otherwise returns the larger of the inputs. It
-//    treats +0 as larger than -0 as per the specification.
+//
+// It propagates NaN inputs back to the caller and
+// otherwise returns the lesser of the inputs. It
+// treats +0 as lesser than -0 as per the specification.
 //
 // Arguments:
 //    val1 - left operand
@@ -2488,21 +2679,120 @@ float FloatingPointUtils::maximum(float val1, float val2)
 // Return Value:
 //    Either val1 or val2
 //
-
 double FloatingPointUtils::minimum(double val1, double val2)
 {
-    if (val1 != val2 && !isNaN(val1))
+    if (val1 != val2)
     {
-        return val1 < val2 ? val1 : val2;
+        if (!isNaN(val1))
+        {
+            return val1 < val2 ? val1 : val2;
+        }
+
+        return val1;
     }
+
     return isNegative(val1) ? val1 : val2;
 }
 
 //------------------------------------------------------------------------
+// minimumMagnitude: This matches the IEEE 754:2019 `minimumMagnitude` function
+//
+// It propagates NaN inputs back to the caller and
+// otherwise returns the input with a lesser magnitude.
+// It treats +0 as lesser than -0 as per the specification.
+//
+// Arguments:
+//    x - left operand
+//    y - right operand
+//
+// Return Value:
+//    Either x or y
+//
+double FloatingPointUtils::minimumMagnitude(double x, double y)
+{
+    double ax = fabs(x);
+    double ay = fabs(y);
+
+    if ((ax < ay) || isNaN(ax))
+    {
+        return x;
+    }
+
+    if (ax == ay)
+    {
+        return isNegative(x) ? x : y;
+    }
+
+    return y;
+}
+
+//------------------------------------------------------------------------
+// minimumMagnitudeNumber: This matches the IEEE 754:2019 `minimumMagnitudeNumber` function
+//
+// It does not propagate NaN inputs back to the caller and
+// otherwise returns the input with a larger magnitude.
+// It treats +0 as larger than -0 as per the specification.
+//
+// Arguments:
+//    x - left operand
+//    y - right operand
+//
+// Return Value:
+//    Either x or y
+//
+double FloatingPointUtils::minimumMagnitudeNumber(double x, double y)
+{
+    double ax = fabs(x);
+    double ay = fabs(y);
+
+    if ((ax < ay) || isNaN(ay))
+    {
+        return x;
+    }
+
+    if (ax == ay)
+    {
+        return isNegative(x) ? x : y;
+    }
+
+    return y;
+}
+
+//------------------------------------------------------------------------
+// minimumNumber: This matches the IEEE 754:2019 `minimumNumber` function
+//
+// It does not propagate NaN inputs back to the caller and
+// otherwise returns the larger of the inputs. It
+// treats +0 as larger than -0 as per the specification.
+//
+// Arguments:
+//    x - left operand
+//    y - right operand
+//
+// Return Value:
+//    Either x or y
+//
+double FloatingPointUtils::minimumNumber(double x, double y)
+{
+    if (x != y)
+    {
+        if (!isNaN(y))
+        {
+            return x < y ? x : y;
+        }
+
+        return x;
+    }
+
+    return isNegative(x) ? x : y;
+}
+
+//------------------------------------------------------------------------
 // minimum: This matches the IEEE 754:2019 `minimum` function
-//    It propagates NaN inputs back to the caller and
-//    otherwise returns the larger of the inputs. It
-//    treats +0 as larger than -0 as per the specification.
+//
+// It propagates NaN inputs back to the caller and
+// otherwise returns the lesser of the inputs. It
+// treats +0 as lesser than -0 as per the specification.
 //
 // Arguments:
 //    val1 - left operand
@@ -2513,14 +2803,113 @@ double FloatingPointUtils::minimum(double val1, double val2)
 //
 float FloatingPointUtils::minimum(float val1, float val2)
 {
-    if (val1 != val2 && !isNaN(val1))
+    if (val1 != val2)
     {
-        return val1 < val2 ? val1 : val2;
+        if (!isNaN(val1))
+        {
+            return val1 < val2 ? val1 : val2;
+        }
+
+        return val1;
     }
+
     return isNegative(val1) ? val1 : val2;
 }
 
 //------------------------------------------------------------------------
+// minimumMagnitude: This matches the IEEE 754:2019 `minimumMagnitude` function
+//
+// It propagates NaN inputs back to the caller and
+// otherwise returns the input with a lesser magnitude.
+// It treats +0 as lesser than -0 as per the specification.
+//
+// Arguments:
+//    x - left operand
+//    y - right operand
+//
+// Return Value:
+//    Either x or y
+//
+float FloatingPointUtils::minimumMagnitude(float x, float y)
+{
+    float ax = fabsf(x);
+    float ay = fabsf(y);
+
+    if ((ax < ay) || isNaN(ax))
+    {
+        return x;
+    }
+
+    if (ax == ay)
+    {
+        return isNegative(x) ? x : y;
+    }
+
+    return y;
+}
+
+//------------------------------------------------------------------------
+// minimumMagnitudeNumber: This matches the IEEE 754:2019 `minimumMagnitudeNumber` function
+//
+// It does not propagate NaN inputs back to the caller and
+// otherwise returns the input with a larger magnitude.
+// It treats +0 as larger than -0 as per the specification.
+//
+// Arguments:
+//    x - left operand
+//    y - right operand
+//
+// Return Value:
+//    Either x or y
+//
+float FloatingPointUtils::minimumMagnitudeNumber(float x, float y)
+{
+    float ax = fabsf(x);
+    float ay = fabsf(y);
+
+    if ((ax < ay) || isNaN(ay))
+    {
+        return x;
+    }
+
+    if (ax == ay)
+    {
+        return isNegative(x) ? x : y;
+    }
+
+    return y;
+}
+
+//------------------------------------------------------------------------
+// minimumNumber: This matches the IEEE 754:2019 `minimumNumber` function
+//
+// It does not propagate NaN inputs back to the caller and
+// otherwise returns the larger of the inputs. It
+// treats +0 as larger than -0 as per the specification.
+//
+// Arguments:
+//    x - left operand
+//    y - right operand
+//
+// Return Value:
+//    Either x or y
+//
+float FloatingPointUtils::minimumNumber(float x, float y)
+{
+    if (x != y)
+    {
+        if (!isNaN(y))
+        {
+            return x < y ? x : y;
+        }
+
+        return x;
+    }
+
+    return isNegative(x) ? x : y;
+}
+
+//------------------------------------------------------------------------
 // normalize: Normalize a floating point value.
 //
 // Arguments:
index 32afd1a..5cf3501 100644 (file)
@@ -763,12 +763,36 @@ public:
 
     static double maximum(double val1, double val2);
 
+    static double maximumMagnitude(double val1, double val2);
+
+    static double maximumMagnitudeNumber(double val1, double val2);
+
+    static double maximumNumber(double val1, double val2);
+
     static float maximum(float val1, float val2);
 
+    static float maximumMagnitude(float val1, float val2);
+
+    static float maximumMagnitudeNumber(float val1, float val2);
+
+    static float maximumNumber(float val1, float val2);
+
     static double minimum(double val1, double val2);
 
+    static double minimumMagnitude(double val1, double val2);
+
+    static double minimumMagnitudeNumber(double val1, double val2);
+
+    static double minimumNumber(double val1, double val2);
+
     static float minimum(float val1, float val2);
 
+    static float minimumMagnitude(float val1, float val2);
+
+    static float minimumMagnitudeNumber(float val1, float val2);
+
+    static float minimumNumber(float val1, float val2);
+
     static double normalize(double x);
 };
 
index 9951fc1..51b97de 100644 (file)
@@ -8357,6 +8357,30 @@ ValueNum ValueNumStore::EvalMathFuncBinary(var_types typ, NamedIntrinsic gtMathF
                     break;
                 }
 
+                case NI_System_Math_MaxMagnitude:
+                {
+                    assert(typ == TypeOfVN(arg1VN));
+                    double arg1Val = GetConstantDouble(arg1VN);
+                    res            = FloatingPointUtils::maximumMagnitude(arg0Val, arg1Val);
+                    break;
+                }
+
+                case NI_System_Math_MaxMagnitudeNumber:
+                {
+                    assert(typ == TypeOfVN(arg1VN));
+                    double arg1Val = GetConstantDouble(arg1VN);
+                    res            = FloatingPointUtils::maximumMagnitudeNumber(arg0Val, arg1Val);
+                    break;
+                }
+
+                case NI_System_Math_MaxNumber:
+                {
+                    assert(typ == TypeOfVN(arg1VN));
+                    double arg1Val = GetConstantDouble(arg1VN);
+                    res            = FloatingPointUtils::maximumNumber(arg0Val, arg1Val);
+                    break;
+                }
+
                 case NI_System_Math_Min:
                 {
                     assert(typ == TypeOfVN(arg1VN));
@@ -8365,6 +8389,30 @@ ValueNum ValueNumStore::EvalMathFuncBinary(var_types typ, NamedIntrinsic gtMathF
                     break;
                 }
 
+                case NI_System_Math_MinMagnitude:
+                {
+                    assert(typ == TypeOfVN(arg1VN));
+                    double arg1Val = GetConstantDouble(arg1VN);
+                    res            = FloatingPointUtils::minimumMagnitude(arg0Val, arg1Val);
+                    break;
+                }
+
+                case NI_System_Math_MinMagnitudeNumber:
+                {
+                    assert(typ == TypeOfVN(arg1VN));
+                    double arg1Val = GetConstantDouble(arg1VN);
+                    res            = FloatingPointUtils::minimumMagnitudeNumber(arg0Val, arg1Val);
+                    break;
+                }
+
+                case NI_System_Math_MinNumber:
+                {
+                    assert(typ == TypeOfVN(arg1VN));
+                    double arg1Val = GetConstantDouble(arg1VN);
+                    res            = FloatingPointUtils::minimumNumber(arg0Val, arg1Val);
+                    break;
+                }
+
                 default:
                     // the above are the only binary math intrinsics at the time of this writing.
                     unreached();
@@ -8448,10 +8496,34 @@ ValueNum ValueNumStore::EvalMathFuncBinary(var_types typ, NamedIntrinsic gtMathF
                 vnf = VNF_Max;
                 break;
 
+            case NI_System_Math_MaxMagnitude:
+                vnf = VNF_MaxMagnitude;
+                break;
+
+            case NI_System_Math_MaxMagnitudeNumber:
+                vnf = VNF_MaxMagnitudeNumber;
+                break;
+
+            case NI_System_Math_MaxNumber:
+                vnf = VNF_MaxNumber;
+                break;
+
             case NI_System_Math_Min:
                 vnf = VNF_Min;
                 break;
 
+            case NI_System_Math_MinMagnitude:
+                vnf = VNF_MinMagnitude;
+                break;
+
+            case NI_System_Math_MinMagnitudeNumber:
+                vnf = VNF_MinMagnitudeNumber;
+                break;
+
+            case NI_System_Math_MinNumber:
+                vnf = VNF_MinNumber;
+                break;
+
             case NI_System_Math_Pow:
                 vnf = VNF_Pow;
                 break;
index de0c347..f875f3a 100644 (file)
@@ -92,7 +92,13 @@ ValueNumFuncDef(Log, 1, false, false, false, false)
 ValueNumFuncDef(Log2, 1, false, false, false, false)
 ValueNumFuncDef(Log10, 1, false, false, false, false)
 ValueNumFuncDef(Max, 2, false, false, false, false)
+ValueNumFuncDef(MaxMagnitude, 2, false, false, false, false)
+ValueNumFuncDef(MaxMagnitudeNumber, 2, false, false, false, false)
+ValueNumFuncDef(MaxNumber, 2, false, false, false, false)
 ValueNumFuncDef(Min, 2, false, false, false, false)
+ValueNumFuncDef(MinMagnitude, 2, false, false, false, false)
+ValueNumFuncDef(MinMagnitudeNumber, 2, false, false, false, false)
+ValueNumFuncDef(MinNumber, 2, false, false, false, false)
 ValueNumFuncDef(Pow, 2, false, false, false, false)
 ValueNumFuncDef(RoundDouble, 1, false, false, false, false)
 ValueNumFuncDef(RoundInt32, 1, false, false, false, false)
index aaa637a..9058eae 100644 (file)
@@ -571,6 +571,7 @@ namespace System
         }
 
         /// <inheritdoc cref="IBinaryNumber{TSelf}.Log2(TSelf)" />
+        [Intrinsic]
         public static double Log2(double value) => Math.Log2(value);
 
         //
@@ -624,6 +625,7 @@ namespace System
         //
 
         /// <inheritdoc cref="IExponentialFunctions{TSelf}.Exp" />
+        [Intrinsic]
         public static double Exp(double x) => Math.Exp(x);
 
         /// <inheritdoc cref="IExponentialFunctions{TSelf}.ExpM1(TSelf)" />
@@ -646,12 +648,15 @@ namespace System
         //
 
         /// <inheritdoc cref="IFloatingPoint{TSelf}.Ceiling(TSelf)" />
+        [Intrinsic]
         public static double Ceiling(double x) => Math.Ceiling(x);
 
         /// <inheritdoc cref="IFloatingPoint{TSelf}.Floor(TSelf)" />
+        [Intrinsic]
         public static double Floor(double x) => Math.Floor(x);
 
         /// <inheritdoc cref="IFloatingPoint{TSelf}.Round(TSelf)" />
+        [Intrinsic]
         public static double Round(double x) => Math.Round(x);
 
         /// <inheritdoc cref="IFloatingPoint{TSelf}.Round(TSelf, int)" />
@@ -664,6 +669,7 @@ namespace System
         public static double Round(double x, int digits, MidpointRounding mode) => Math.Round(x, digits, mode);
 
         /// <inheritdoc cref="IFloatingPoint{TSelf}.Truncate(TSelf)" />
+        [Intrinsic]
         public static double Truncate(double x) => Math.Truncate(x);
 
         /// <inheritdoc cref="IFloatingPoint{TSelf}.GetExponentByteCount()" />
@@ -819,6 +825,7 @@ namespace System
         static double IFloatingPointIeee754<double>.PositiveInfinity => PositiveInfinity;
 
         /// <inheritdoc cref="IFloatingPointIeee754{TSelf}.Atan2(TSelf, TSelf)" />
+        [Intrinsic]
         public static double Atan2(double y, double x) => Math.Atan2(y, x);
 
         /// <inheritdoc cref="IFloatingPointIeee754{TSelf}.Atan2Pi(TSelf, TSelf)" />
@@ -831,6 +838,7 @@ namespace System
         public static double BitIncrement(double x) => Math.BitIncrement(x);
 
         /// <inheritdoc cref="IFloatingPointIeee754{TSelf}.FusedMultiplyAdd(TSelf, TSelf, TSelf)" />
+        [Intrinsic]
         public static double FusedMultiplyAdd(double left, double right, double addend) => Math.FusedMultiplyAdd(left, right, addend);
 
         /// <inheritdoc cref="IFloatingPointIeee754{TSelf}.Ieee754Remainder(TSelf, TSelf)" />
@@ -859,21 +867,27 @@ namespace System
         //
 
         /// <inheritdoc cref="IHyperbolicFunctions{TSelf}.Acosh(TSelf)" />
+        [Intrinsic]
         public static double Acosh(double x) => Math.Acosh(x);
 
         /// <inheritdoc cref="IHyperbolicFunctions{TSelf}.Asinh(TSelf)" />
+        [Intrinsic]
         public static double Asinh(double x) => Math.Asinh(x);
 
         /// <inheritdoc cref="IHyperbolicFunctions{TSelf}.Atanh(TSelf)" />
+        [Intrinsic]
         public static double Atanh(double x) => Math.Atanh(x);
 
         /// <inheritdoc cref="IHyperbolicFunctions{TSelf}.Cosh(TSelf)" />
+        [Intrinsic]
         public static double Cosh(double x) => Math.Cosh(x);
 
         /// <inheritdoc cref="IHyperbolicFunctions{TSelf}.Sinh(TSelf)" />
+        [Intrinsic]
         public static double Sinh(double x) => Math.Sinh(x);
 
         /// <inheritdoc cref="IHyperbolicFunctions{TSelf}.Tanh(TSelf)" />
+        [Intrinsic]
         public static double Tanh(double x) => Math.Tanh(x);
 
         //
@@ -888,6 +902,7 @@ namespace System
         //
 
         /// <inheritdoc cref="ILogarithmicFunctions{TSelf}.Log(TSelf)" />
+        [Intrinsic]
         public static double Log(double x) => Math.Log(x);
 
         /// <inheritdoc cref="ILogarithmicFunctions{TSelf}.Log(TSelf, TSelf)" />
@@ -900,6 +915,7 @@ namespace System
         public static double Log2P1(double x) => Math.Log2(x + 1);
 
         /// <inheritdoc cref="ILogarithmicFunctions{TSelf}.Log10(TSelf)" />
+        [Intrinsic]
         public static double Log10(double x) => Math.Log10(x);
 
         /// <inheritdoc cref="ILogarithmicFunctions{TSelf}.Log10P1(TSelf)" />
@@ -947,9 +963,11 @@ namespace System
         public static double CopySign(double value, double sign) => Math.CopySign(value, sign);
 
         /// <inheritdoc cref="INumber{TSelf}.Max(TSelf, TSelf)" />
+        [Intrinsic]
         public static double Max(double x, double y) => Math.Max(x, y);
 
         /// <inheritdoc cref="INumber{TSelf}.MaxNumber(TSelf, TSelf)" />
+        [Intrinsic]
         public static double MaxNumber(double x, double y)
         {
             // This matches the IEEE 754:2019 `maximumNumber` function
@@ -972,9 +990,11 @@ namespace System
         }
 
         /// <inheritdoc cref="INumber{TSelf}.Min(TSelf, TSelf)" />
+        [Intrinsic]
         public static double Min(double x, double y) => Math.Min(x, y);
 
         /// <inheritdoc cref="INumber{TSelf}.MinNumber(TSelf, TSelf)" />
+        [Intrinsic]
         public static double MinNumber(double x, double y)
         {
             // This matches the IEEE 754:2019 `minimumNumber` function
@@ -1013,6 +1033,7 @@ namespace System
         static double INumberBase<double>.Zero => Zero;
 
         /// <inheritdoc cref="INumberBase{TSelf}.Abs(TSelf)" />
+        [Intrinsic]
         public static double Abs(double value) => Math.Abs(value);
 
         /// <inheritdoc cref="INumberBase{TSelf}.CreateChecked{TOther}(TOther)" />
@@ -1108,9 +1129,11 @@ namespace System
         static bool INumberBase<double>.IsZero(double value) => (value == 0);
 
         /// <inheritdoc cref="INumberBase{TSelf}.MaxMagnitude(TSelf, TSelf)" />
+        [Intrinsic]
         public static double MaxMagnitude(double x, double y) => Math.MaxMagnitude(x, y);
 
         /// <inheritdoc cref="INumberBase{TSelf}.MaxMagnitudeNumber(TSelf, TSelf)" />
+        [Intrinsic]
         public static double MaxMagnitudeNumber(double x, double y)
         {
             // This matches the IEEE 754:2019 `maximumMagnitudeNumber` function
@@ -1136,9 +1159,11 @@ namespace System
         }
 
         /// <inheritdoc cref="INumberBase{TSelf}.MinMagnitude(TSelf, TSelf)" />
+        [Intrinsic]
         public static double MinMagnitude(double x, double y) => Math.MinMagnitude(x, y);
 
         /// <inheritdoc cref="INumberBase{TSelf}.MinMagnitudeNumber(TSelf, TSelf)" />
+        [Intrinsic]
         public static double MinMagnitudeNumber(double x, double y)
         {
             // This matches the IEEE 754:2019 `minimumMagnitudeNumber` function
@@ -1429,6 +1454,7 @@ namespace System
         //
 
         /// <inheritdoc cref="IPowerFunctions{TSelf}.Pow(TSelf, TSelf)" />
+        [Intrinsic]
         public static double Pow(double x, double y) => Math.Pow(x, y);
 
         //
@@ -1436,6 +1462,7 @@ namespace System
         //
 
         /// <inheritdoc cref="IRootFunctions{TSelf}.Cbrt(TSelf)" />
+        [Intrinsic]
         public static double Cbrt(double x) => Math.Cbrt(x);
 
         /// <inheritdoc cref="IRootFunctions{TSelf}.Hypot(TSelf, TSelf)" />
@@ -1719,6 +1746,7 @@ namespace System
         }
 
         /// <inheritdoc cref="IRootFunctions{TSelf}.Sqrt(TSelf)" />
+        [Intrinsic]
         public static double Sqrt(double x) => Math.Sqrt(x);
 
         //
@@ -1750,6 +1778,7 @@ namespace System
         //
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.Acos(TSelf)" />
+        [Intrinsic]
         public static double Acos(double x) => Math.Acos(x);
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.AcosPi(TSelf)" />
@@ -1759,6 +1788,7 @@ namespace System
         }
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.Asin(TSelf)" />
+        [Intrinsic]
         public static double Asin(double x) => Math.Asin(x);
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.AsinPi(TSelf)" />
@@ -1768,6 +1798,7 @@ namespace System
         }
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.Atan(TSelf)" />
+        [Intrinsic]
         public static double Atan(double x) => Math.Atan(x);
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.AtanPi(TSelf)" />
@@ -1777,6 +1808,7 @@ namespace System
         }
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.Cos(TSelf)" />
+        [Intrinsic]
         public static double Cos(double x) => Math.Cos(x);
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.CosPi(TSelf)" />
@@ -1869,6 +1901,7 @@ namespace System
         }
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.Sin(TSelf)" />
+        [Intrinsic]
         public static double Sin(double x) => Math.Sin(x);
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.SinCos(TSelf)" />
@@ -2076,6 +2109,7 @@ namespace System
         }
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.Tan(TSelf)" />
+        [Intrinsic]
         public static double Tan(double x) => Math.Tan(x);
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.TanPi(TSelf)" />
index 5c7252b..db55090 100644 (file)
@@ -994,6 +994,7 @@ namespace System
             return (val1 >= val2) ? val1 : val2;
         }
 
+        [Intrinsic]
         public static double MaxMagnitude(double x, double y)
         {
             // This matches the IEEE 754:2019 `maximumMagnitude` function
@@ -1143,6 +1144,7 @@ namespace System
             return (val1 <= val2) ? val1 : val2;
         }
 
+        [Intrinsic]
         public static double MinMagnitude(double x, double y)
         {
             // This matches the IEEE 754:2019 `minimumMagnitude` function
index 31ae24f..17f466b 100644 (file)
@@ -47,6 +47,7 @@ namespace System
 
         private const int ILogB_Zero = (-1 - 0x7fffffff);
 
+        [Intrinsic]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static float Abs(float x)
         {
@@ -241,12 +242,14 @@ namespace System
             return Log(x) / Log(y);
         }
 
+        [Intrinsic]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static float Max(float x, float y)
         {
             return Math.Max(x, y);
         }
 
+        [Intrinsic]
         public static float MaxMagnitude(float x, float y)
         {
             // This matches the IEEE 754:2019 `maximumMagnitude` function
@@ -271,12 +274,14 @@ namespace System
             return y;
         }
 
+        [Intrinsic]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static float Min(float x, float y)
         {
             return Math.Min(x, y);
         }
 
+        [Intrinsic]
         public static float MinMagnitude(float x, float y)
         {
             // This matches the IEEE 754:2019 `minimumMagnitude` function
index 42d63de..42f5861 100644 (file)
@@ -563,6 +563,7 @@ namespace System
         }
 
         /// <inheritdoc cref="IBinaryNumber{TSelf}.Log2(TSelf)" />
+        [Intrinsic]
         public static float Log2(float value) => MathF.Log2(value);
 
         //
@@ -616,6 +617,7 @@ namespace System
         //
 
         /// <inheritdoc cref="IExponentialFunctions{TSelf}.Exp" />
+        [Intrinsic]
         public static float Exp(float x) => MathF.Exp(x);
 
         /// <inheritdoc cref="IExponentialFunctions{TSelf}.ExpM1(TSelf)" />
@@ -638,12 +640,15 @@ namespace System
         //
 
         /// <inheritdoc cref="IFloatingPoint{TSelf}.Ceiling(TSelf)" />
+        [Intrinsic]
         public static float Ceiling(float x) => MathF.Ceiling(x);
 
         /// <inheritdoc cref="IFloatingPoint{TSelf}.Floor(TSelf)" />
+        [Intrinsic]
         public static float Floor(float x) => MathF.Floor(x);
 
         /// <inheritdoc cref="IFloatingPoint{TSelf}.Round(TSelf)" />
+        [Intrinsic]
         public static float Round(float x) => MathF.Round(x);
 
         /// <inheritdoc cref="IFloatingPoint{TSelf}.Round(TSelf, int)" />
@@ -656,6 +661,7 @@ namespace System
         public static float Round(float x, int digits, MidpointRounding mode) => MathF.Round(x, digits, mode);
 
         /// <inheritdoc cref="IFloatingPoint{TSelf}.Truncate(TSelf)" />
+        [Intrinsic]
         public static float Truncate(float x) => MathF.Truncate(x);
 
         /// <inheritdoc cref="IFloatingPoint{TSelf}.GetExponentByteCount()" />
@@ -799,6 +805,7 @@ namespace System
         static float IFloatingPointIeee754<float>.PositiveInfinity => PositiveInfinity;
 
         /// <inheritdoc cref="IFloatingPointIeee754{TSelf}.Atan2(TSelf, TSelf)" />
+        [Intrinsic]
         public static float Atan2(float y, float x) => MathF.Atan2(y, x);
 
         /// <inheritdoc cref="IFloatingPointIeee754{TSelf}.Atan2Pi(TSelf, TSelf)" />
@@ -811,6 +818,7 @@ namespace System
         public static float BitIncrement(float x) => MathF.BitIncrement(x);
 
         /// <inheritdoc cref="IFloatingPointIeee754{TSelf}.FusedMultiplyAdd(TSelf, TSelf, TSelf)" />
+        [Intrinsic]
         public static float FusedMultiplyAdd(float left, float right, float addend) => MathF.FusedMultiplyAdd(left, right, addend);
 
         /// <inheritdoc cref="IFloatingPointIeee754{TSelf}.Ieee754Remainder(TSelf, TSelf)" />
@@ -839,21 +847,27 @@ namespace System
         //
 
         /// <inheritdoc cref="IHyperbolicFunctions{TSelf}.Acosh(TSelf)" />
+        [Intrinsic]
         public static float Acosh(float x) => MathF.Acosh(x);
 
         /// <inheritdoc cref="IHyperbolicFunctions{TSelf}.Asinh(TSelf)" />
+        [Intrinsic]
         public static float Asinh(float x) => MathF.Asinh(x);
 
         /// <inheritdoc cref="IHyperbolicFunctions{TSelf}.Atanh(TSelf)" />
+        [Intrinsic]
         public static float Atanh(float x) => MathF.Atanh(x);
 
         /// <inheritdoc cref="IHyperbolicFunctions{TSelf}.Cosh(TSelf)" />
+        [Intrinsic]
         public static float Cosh(float x) => MathF.Cosh(x);
 
         /// <inheritdoc cref="IHyperbolicFunctions{TSelf}.Sinh(TSelf)" />
+        [Intrinsic]
         public static float Sinh(float x) => MathF.Sinh(x);
 
         /// <inheritdoc cref="IHyperbolicFunctions{TSelf}.Tanh(TSelf)" />
+        [Intrinsic]
         public static float Tanh(float x) => MathF.Tanh(x);
 
         //
@@ -868,6 +882,7 @@ namespace System
         //
 
         /// <inheritdoc cref="ILogarithmicFunctions{TSelf}.Log(TSelf)" />
+        [Intrinsic]
         public static float Log(float x) => MathF.Log(x);
 
         /// <inheritdoc cref="ILogarithmicFunctions{TSelf}.Log(TSelf, TSelf)" />
@@ -877,6 +892,7 @@ namespace System
         public static float LogP1(float x) => MathF.Log(x + 1);
 
         /// <inheritdoc cref="ILogarithmicFunctions{TSelf}.Log10(TSelf)" />
+        [Intrinsic]
         public static float Log10(float x) => MathF.Log10(x);
 
         /// <inheritdoc cref="ILogarithmicFunctions{TSelf}.Log2P1(TSelf)" />
@@ -927,9 +943,11 @@ namespace System
         public static float CopySign(float value, float sign) => MathF.CopySign(value, sign);
 
         /// <inheritdoc cref="INumber{TSelf}.Max(TSelf, TSelf)" />
+        [Intrinsic]
         public static float Max(float x, float y) => MathF.Max(x, y);
 
         /// <inheritdoc cref="INumber{TSelf}.MaxNumber(TSelf, TSelf)" />
+        [Intrinsic]
         public static float MaxNumber(float x, float y)
         {
             // This matches the IEEE 754:2019 `maximumNumber` function
@@ -952,9 +970,11 @@ namespace System
         }
 
         /// <inheritdoc cref="INumber{TSelf}.Min(TSelf, TSelf)" />
+        [Intrinsic]
         public static float Min(float x, float y) => MathF.Min(x, y);
 
         /// <inheritdoc cref="INumber{TSelf}.MinNumber(TSelf, TSelf)" />
+        [Intrinsic]
         public static float MinNumber(float x, float y)
         {
             // This matches the IEEE 754:2019 `minimumNumber` function
@@ -993,6 +1013,7 @@ namespace System
         static float INumberBase<float>.Zero => Zero;
 
         /// <inheritdoc cref="INumberBase{TSelf}.Abs(TSelf)" />
+        [Intrinsic]
         public static float Abs(float value) => MathF.Abs(value);
 
         /// <inheritdoc cref="INumberBase{TSelf}.CreateChecked{TOther}(TOther)" />
@@ -1088,9 +1109,11 @@ namespace System
         static bool INumberBase<float>.IsZero(float value) => (value == 0);
 
         /// <inheritdoc cref="INumberBase{TSelf}.MaxMagnitude(TSelf, TSelf)" />
+        [Intrinsic]
         public static float MaxMagnitude(float x, float y) => MathF.MaxMagnitude(x, y);
 
         /// <inheritdoc cref="INumberBase{TSelf}.MaxMagnitudeNumber(TSelf, TSelf)" />
+        [Intrinsic]
         public static float MaxMagnitudeNumber(float x, float y)
         {
             // This matches the IEEE 754:2019 `maximumMagnitudeNumber` function
@@ -1116,9 +1139,11 @@ namespace System
         }
 
         /// <inheritdoc cref="INumberBase{TSelf}.MinMagnitude(TSelf, TSelf)" />
+        [Intrinsic]
         public static float MinMagnitude(float x, float y) => MathF.MinMagnitude(x, y);
 
         /// <inheritdoc cref="INumberBase{TSelf}.MinMagnitudeNumber(TSelf, TSelf)" />
+        [Intrinsic]
         public static float MinMagnitudeNumber(float x, float y)
         {
             // This matches the IEEE 754:2019 `minimumMagnitudeNumber` function
@@ -1409,6 +1434,7 @@ namespace System
         //
 
         /// <inheritdoc cref="IPowerFunctions{TSelf}.Pow(TSelf, TSelf)" />
+        [Intrinsic]
         public static float Pow(float x, float y) => MathF.Pow(x, y);
 
         //
@@ -1416,6 +1442,7 @@ namespace System
         //
 
         /// <inheritdoc cref="IRootFunctions{TSelf}.Cbrt(TSelf)" />
+        [Intrinsic]
         public static float Cbrt(float x) => MathF.Cbrt(x);
 
         /// <inheritdoc cref="IRootFunctions{TSelf}.Hypot(TSelf, TSelf)" />
@@ -1596,6 +1623,7 @@ namespace System
         }
 
         /// <inheritdoc cref="IRootFunctions{TSelf}.Sqrt(TSelf)" />
+        [Intrinsic]
         public static float Sqrt(float x) => MathF.Sqrt(x);
 
         //
@@ -1627,6 +1655,7 @@ namespace System
         //
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.Acos(TSelf)" />
+        [Intrinsic]
         public static float Acos(float x) => MathF.Acos(x);
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.AcosPi(TSelf)" />
@@ -1636,6 +1665,7 @@ namespace System
         }
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.Asin(TSelf)" />
+        [Intrinsic]
         public static float Asin(float x) => MathF.Asin(x);
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.AsinPi(TSelf)" />
@@ -1645,6 +1675,7 @@ namespace System
         }
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.Atan(TSelf)" />
+        [Intrinsic]
         public static float Atan(float x) => MathF.Atan(x);
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.AtanPi(TSelf)" />
@@ -1654,6 +1685,7 @@ namespace System
         }
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.Cos(TSelf)" />
+        [Intrinsic]
         public static float Cos(float x) => MathF.Cos(x);
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.CosPi(TSelf)" />
@@ -1746,6 +1778,7 @@ namespace System
         }
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.Sin(TSelf)" />
+        [Intrinsic]
         public static float Sin(float x) => MathF.Sin(x);
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.SinCos(TSelf)" />
@@ -1953,6 +1986,7 @@ namespace System
         }
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.Tan(TSelf)" />
+        [Intrinsic]
         public static float Tan(float x) => MathF.Tan(x);
 
         /// <inheritdoc cref="ITrigonometricFunctions{TSelf}.TanPi(TSelf)" />