@@ -3478,29 +3478,34 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
34783478 {
34793479 ni = lookupNamedIntrinsic(method);
34803480
3481- #ifdef FEATURE_HW_INTRINSICS
3481+ // We specially support the following on all platforms to allow for dead
3482+ // code optimization and to more generally support recursive intrinsics.
3483+
34823484 if (ni == NI_IsSupported_True)
34833485 {
3486+ assert(sig->numArgs == 0);
34843487 return gtNewIconNode(true);
34853488 }
34863489
34873490 if (ni == NI_IsSupported_False)
34883491 {
3492+ assert(sig->numArgs == 0);
34893493 return gtNewIconNode(false);
34903494 }
34913495
34923496 if (ni == NI_Throw_PlatformNotSupportedException)
34933497 {
3494- return impUnsupportedHWIntrinsic (CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
3498+ return impUnsupportedNamedIntrinsic (CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
34953499 }
34963500
3501+ #ifdef FEATURE_HW_INTRINSICS
34973502 if ((ni > NI_HW_INTRINSIC_START) && (ni < NI_HW_INTRINSIC_END))
34983503 {
34993504 GenTree* hwintrinsic = impHWIntrinsic(ni, clsHnd, method, sig, mustExpand);
35003505
35013506 if (mustExpand && (hwintrinsic == nullptr))
35023507 {
3503- return impUnsupportedHWIntrinsic (CORINFO_HELP_THROW_NOT_IMPLEMENTED, method, sig, mustExpand);
3508+ return impUnsupportedNamedIntrinsic (CORINFO_HELP_THROW_NOT_IMPLEMENTED, method, sig, mustExpand);
35043509 }
35053510
35063511 return hwintrinsic;
@@ -4273,14 +4278,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
42734278 if (mustExpand && (retNode == nullptr))
42744279 {
42754280 assert(!"Unhandled must expand intrinsic, throwing PlatformNotSupportedException");
4276-
4277- for (unsigned i = 0; i < sig->numArgs; i++)
4278- {
4279- impPopStack();
4280- }
4281-
4282- return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, JITtype2varType(sig->retType),
4283- sig->retTypeClass);
4281+ return impUnsupportedNamedIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
42844282 }
42854283
42864284 // Optionally report if this intrinsic is special
@@ -4497,8 +4495,13 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
44974495
44984496 result = SimdAsHWIntrinsicInfo::lookupId(&sig, className, methodName, enclosingClassName, sizeOfVectorT);
44994497 }
4498+ #endif // FEATURE_HW_INTRINSICS
45004499 else if (strncmp(namespaceName, "System.Runtime.Intrinsics", 25) == 0)
45014500 {
4501+ // We go down this path even when FEATURE_HW_INTRINSICS isn't enabled
4502+ // so we can specially handle IsSupported and recursive calls.
4503+
4504+ #ifdef FEATURE_HW_INTRINSICS
45024505 namespaceName += 25;
45034506 const char* platformNamespaceName;
45044507
@@ -4517,29 +4520,91 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
45174520
45184521 result = HWIntrinsicInfo::lookupId(this, &sig, className, methodName, enclosingClassName);
45194522 }
4523+ #endif // FEATURE_HW_INTRINSICS
45204524
45214525 if (result == NI_Illegal)
45224526 {
45234527 if (strcmp(methodName, "get_IsSupported") == 0)
45244528 {
4525- return NI_IsSupported_False;
4529+ // This allows the relevant code paths to be dropped as dead code even
4530+ // on platforms where FEATURE_HW_INTRINSICS is not supported.
4531+
4532+ result = NI_IsSupported_False;
4533+ }
4534+ else if (gtIsRecursiveCall(method))
4535+ {
4536+ // For the framework itself, any recursive intrinsics will either be
4537+ // only supported on a single platform or will be guarded by a relevant
4538+ // IsSupported check so the throw PNSE will be valid or dropped.
4539+
4540+ result = NI_Throw_PlatformNotSupportedException;
45264541 }
4527- return gtIsRecursiveCall(method) ? NI_Throw_PlatformNotSupportedException : NI_Illegal;
45284542 }
45294543 }
4530- #endif // FEATURE_HW_INTRINSICS
45314544
45324545 if (result == NI_Illegal)
45334546 {
45344547 JITDUMP("Not recognized\n");
45354548 }
4549+ else if (result == NI_IsSupported_False)
4550+ {
4551+ JITDUMP("Unsupported - return false");
4552+ }
4553+ else if (result == NI_Throw_PlatformNotSupportedException)
4554+ {
4555+ JITDUMP("Unsupported - throw PlatformNotSupportedException");
4556+ }
45364557 else
45374558 {
45384559 JITDUMP("Recognized\n");
45394560 }
45404561 return result;
45414562}
45424563
4564+ //------------------------------------------------------------------------
4565+ // impUnsupportedNamedIntrinsic: Throws an exception for an unsupported named intrinsic
4566+ //
4567+ // Arguments:
4568+ // helper - JIT helper ID for the exception to be thrown
4569+ // method - method handle of the intrinsic function.
4570+ // sig - signature of the intrinsic call
4571+ // mustExpand - true if the intrinsic must return a GenTree*; otherwise, false
4572+ //
4573+ // Return Value:
4574+ // a gtNewMustThrowException if mustExpand is true; otherwise, nullptr
4575+ //
4576+ GenTree* Compiler::impUnsupportedNamedIntrinsic(unsigned helper,
4577+ CORINFO_METHOD_HANDLE method,
4578+ CORINFO_SIG_INFO* sig,
4579+ bool mustExpand)
4580+ {
4581+ // We've hit some error case and may need to return a node for the given error.
4582+ //
4583+ // When `mustExpand=false`, we are attempting to inline the intrinsic directly into another method. In this
4584+ // scenario, we need to return `nullptr` so that a GT_CALL to the intrinsic is emitted instead. This is to
4585+ // ensure that everything continues to behave correctly when optimizations are enabled (e.g. things like the
4586+ // inliner may expect the node we return to have a certain signature, and the `MustThrowException` node won't
4587+ // match that).
4588+ //
4589+ // When `mustExpand=true`, we are in a GT_CALL to the intrinsic and are attempting to JIT it. This will generally
4590+ // be in response to an indirect call (e.g. done via reflection) or in response to an earlier attempt returning
4591+ // `nullptr` (under `mustExpand=false`). In that scenario, we are safe to return the `MustThrowException` node.
4592+
4593+ if (mustExpand)
4594+ {
4595+ for (unsigned i = 0; i < sig->numArgs; i++)
4596+ {
4597+ impPopStack();
4598+ }
4599+
4600+ return gtNewMustThrowException(helper, JITtype2varType(sig->retType), sig->retTypeClass);
4601+ }
4602+ else
4603+ {
4604+ return nullptr;
4605+ }
4606+ }
4607+
45434608/*****************************************************************************/
45444609
45454610GenTree* Compiler::impArrayAccessIntrinsic(
0 commit comments