@@ -3478,29 +3478,34 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
3478
3478
{
3479
3479
ni = lookupNamedIntrinsic(method);
3480
3480
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
+
3482
3484
if (ni == NI_IsSupported_True)
3483
3485
{
3486
+ assert(sig->numArgs == 0);
3484
3487
return gtNewIconNode(true);
3485
3488
}
3486
3489
3487
3490
if (ni == NI_IsSupported_False)
3488
3491
{
3492
+ assert(sig->numArgs == 0);
3489
3493
return gtNewIconNode(false);
3490
3494
}
3491
3495
3492
3496
if (ni == NI_Throw_PlatformNotSupportedException)
3493
3497
{
3494
- return impUnsupportedHWIntrinsic (CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
3498
+ return impUnsupportedNamedIntrinsic (CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
3495
3499
}
3496
3500
3501
+ #ifdef FEATURE_HW_INTRINSICS
3497
3502
if ((ni > NI_HW_INTRINSIC_START) && (ni < NI_HW_INTRINSIC_END))
3498
3503
{
3499
3504
GenTree* hwintrinsic = impHWIntrinsic(ni, clsHnd, method, sig, mustExpand);
3500
3505
3501
3506
if (mustExpand && (hwintrinsic == nullptr))
3502
3507
{
3503
- return impUnsupportedHWIntrinsic (CORINFO_HELP_THROW_NOT_IMPLEMENTED, method, sig, mustExpand);
3508
+ return impUnsupportedNamedIntrinsic (CORINFO_HELP_THROW_NOT_IMPLEMENTED, method, sig, mustExpand);
3504
3509
}
3505
3510
3506
3511
return hwintrinsic;
@@ -4273,14 +4278,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
4273
4278
if (mustExpand && (retNode == nullptr))
4274
4279
{
4275
4280
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);
4284
4282
}
4285
4283
4286
4284
// Optionally report if this intrinsic is special
@@ -4497,8 +4495,13 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
4497
4495
4498
4496
result = SimdAsHWIntrinsicInfo::lookupId(&sig, className, methodName, enclosingClassName, sizeOfVectorT);
4499
4497
}
4498
+ #endif // FEATURE_HW_INTRINSICS
4500
4499
else if (strncmp(namespaceName, "System.Runtime.Intrinsics", 25) == 0)
4501
4500
{
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
4502
4505
namespaceName += 25;
4503
4506
const char* platformNamespaceName;
4504
4507
@@ -4517,29 +4520,91 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
4517
4520
4518
4521
result = HWIntrinsicInfo::lookupId(this, &sig, className, methodName, enclosingClassName);
4519
4522
}
4523
+ #endif // FEATURE_HW_INTRINSICS
4520
4524
4521
4525
if (result == NI_Illegal)
4522
4526
{
4523
4527
if (strcmp(methodName, "get_IsSupported") == 0)
4524
4528
{
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;
4526
4541
}
4527
- return gtIsRecursiveCall(method) ? NI_Throw_PlatformNotSupportedException : NI_Illegal;
4528
4542
}
4529
4543
}
4530
- #endif // FEATURE_HW_INTRINSICS
4531
4544
4532
4545
if (result == NI_Illegal)
4533
4546
{
4534
4547
JITDUMP("Not recognized\n");
4535
4548
}
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
+ }
4536
4557
else
4537
4558
{
4538
4559
JITDUMP("Recognized\n");
4539
4560
}
4540
4561
return result;
4541
4562
}
4542
4563
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
+
4543
4608
/*****************************************************************************/
4544
4609
4545
4610
GenTree* Compiler::impArrayAccessIntrinsic(
0 commit comments