}
}
+//------------------------------------------------------------------------
+// isFullyImplmentedISAClass: return true if all the hardware intrinsics
+// of this ISA are implemented in RyuJIT.
+//
+// Arguments:
+// isa - Instruction set
+// Return Value:
+// true - all the hardware intrinsics of "isa" are implemented in RyuJIT.
+//
+bool Compiler::isFullyImplmentedISAClass(InstructionSet isa)
+{
+ switch (isa)
+ {
+ case InstructionSet_SSE:
+ case InstructionSet_SSE2:
+ case InstructionSet_SSE3:
+ case InstructionSet_SSSE3:
+ case InstructionSet_SSE41:
+ case InstructionSet_SSE42:
+ case InstructionSet_AVX:
+ case InstructionSet_AVX2:
+ case InstructionSet_AES:
+ case InstructionSet_BMI1:
+ case InstructionSet_BMI2:
+ case InstructionSet_FMA:
+ case InstructionSet_PCLMULQDQ:
+ return false;
+
+ case InstructionSet_LZCNT:
+ case InstructionSet_POPCNT:
+ return true;
+
+ default:
+ unreached();
+ }
+}
+
+//------------------------------------------------------------------------
+// isScalarISA:
+//
+// Arguments:
+// isa - Instruction set
+// Return Value:
+// true - if "isa" only contains scalar instructions
+//
+bool Compiler::isScalarISA(InstructionSet isa)
+{
+ switch (isa)
+ {
+ case InstructionSet_BMI1:
+ case InstructionSet_BMI2:
+ case InstructionSet_LZCNT:
+ case InstructionSet_POPCNT:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+//------------------------------------------------------------------------
+// compSupportsHWIntrinsic: compiler support of hardware intrinsics
+//
+// Arguments:
+// isa - Instruction set
+// Return Value:
+// true if
+// - isa is a scalar ISA
+// - isa is a SIMD ISA and featureSIMD=true
+// - isa is fully implemented or EnableIncompleteISAClass=true
+bool Compiler::compSupportsHWIntrinsic(InstructionSet isa)
+{
+ return (featureSIMD || isScalarISA(isa)) && (
+#ifdef DEBUG
+ JitConfig.EnableIncompleteISAClass() ||
+#endif
+ isFullyImplmentedISAClass(isa));
+}
+
//------------------------------------------------------------------------
// impX86HWIntrinsic: dispatch hardware intrinsics to their own implementation
// function
GenTree* Compiler::impX86HWIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
{
InstructionSet isa = isaOfHWIntrinsic(intrinsic);
- // Will throw PlatformNotSupportedException if
- // - calling hardware intrinsics on unsupported hardware
- // - calling SIMD hardware intrinsics with featureSIMD=false
- if ((!compSupports(isa) || (!featureSIMD && isa != InstructionSet_BMI1 && isa != InstructionSet_BMI2 &&
- isa != InstructionSet_LZCNT && isa != InstructionSet_POPCNT)) &&
- !isIntrinsicAnIsSupportedPropertyGetter(intrinsic))
+
+ // This intrinsic is supported if
+ // - the ISA is available on the underlying hardware (compSupports returns true)
+ // - the compiler supports this hardware intrinsics (compSupportsHWIntrinsic returns true)
+ bool issupported = compSupports(isa) && compSupportsHWIntrinsic(isa);
+
+ if (isIntrinsicAnIsSupportedPropertyGetter(intrinsic))
+ {
+ return gtNewIconNode(issupported);
+ }
+ else if (!issupported)
{
for (unsigned i = 0; i < sig->numArgs; i++)
{
return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, JITtype2varType(sig->retType),
sig->retTypeClass);
}
+
switch (isa)
{
case InstructionSet_SSE:
GenTree* op2 = nullptr;
switch (intrinsic)
{
- case NI_SSE_IsSupported:
- retNode = gtNewIconNode(featureSIMD && compSupports(InstructionSet_SSE));
- break;
-
case NI_SSE_Add:
assert(sig->numArgs == 2);
op2 = impSIMDPopStack(TYP_SIMD16);
var_types baseType = TYP_UNKNOWN;
switch (intrinsic)
{
- case NI_SSE2_IsSupported:
- retNode = gtNewIconNode(featureSIMD && compSupports(InstructionSet_SSE2));
- break;
-
case NI_SSE2_Add:
assert(sig->numArgs == 2);
op2 = impSIMDPopStack(TYP_SIMD16);
GenTree* Compiler::impSSE3Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
{
- switch (intrinsic)
- {
- case NI_SSE3_IsSupported:
- return gtNewIconNode(featureSIMD && compSupports(InstructionSet_SSE3));
-
- default:
- return nullptr;
- }
+ return nullptr;
}
GenTree* Compiler::impSSSE3Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
{
- switch (intrinsic)
- {
- case NI_SSSE3_IsSupported:
- return gtNewIconNode(featureSIMD && compSupports(InstructionSet_SSSE3));
-
- default:
- return nullptr;
- }
+ return nullptr;
}
GenTree* Compiler::impSSE41Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
{
- switch (intrinsic)
- {
- case NI_SSE41_IsSupported:
- return gtNewIconNode(featureSIMD && compSupports(InstructionSet_SSE41));
-
- default:
- return nullptr;
- }
+ return nullptr;
}
GenTree* Compiler::impSSE42Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
CorInfoType corType;
switch (intrinsic)
{
- case NI_SSE42_IsSupported:
- retNode = gtNewIconNode(featureSIMD && compSupports(InstructionSet_SSE42));
- break;
-
case NI_SSE42_Crc32:
assert(sig->numArgs == 2);
op2 = impPopStack().val;
var_types baseType = TYP_UNKNOWN;
switch (intrinsic)
{
- case NI_AVX_IsSupported:
- retNode = gtNewIconNode(featureSIMD && compSupports(InstructionSet_AVX));
- break;
-
case NI_AVX_Add:
assert(sig->numArgs == 2);
op2 = impSIMDPopStack(TYP_SIMD32);
var_types baseType = TYP_UNKNOWN;
switch (intrinsic)
{
- case NI_AVX2_IsSupported:
- retNode = gtNewIconNode(featureSIMD && compSupports(InstructionSet_AVX2));
- break;
-
case NI_AVX2_Add:
assert(sig->numArgs == 2);
op2 = impSIMDPopStack(TYP_SIMD32);
GenTree* Compiler::impAESIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
{
- switch (intrinsic)
- {
- case NI_AES_IsSupported:
- return gtNewIconNode(featureSIMD && compSupports(InstructionSet_AES));
-
- default:
- return nullptr;
- }
+ return nullptr;
}
GenTree* Compiler::impBMI1Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
{
- switch (intrinsic)
- {
- case NI_BMI1_IsSupported:
- return gtNewIconNode(compSupports(InstructionSet_BMI1));
-
- default:
- return nullptr;
- }
+ return nullptr;
}
GenTree* Compiler::impBMI2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
{
- switch (intrinsic)
- {
- case NI_BMI2_IsSupported:
- return gtNewIconNode(compSupports(InstructionSet_BMI2));
-
- default:
- return nullptr;
- }
+ return nullptr;
}
GenTree* Compiler::impFMAIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
{
- switch (intrinsic)
- {
- case NI_FMA_IsSupported:
- return gtNewIconNode(featureSIMD && compSupports(InstructionSet_FMA));
-
- default:
- return nullptr;
- }
+ return nullptr;
}
GenTree* Compiler::impLZCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
{
- GenTree* retNode = nullptr;
- GenTree* op1 = nullptr;
+ assert(sig->numArgs == 1);
+ GenTree* op = impPopStack().val;
var_types callType = JITtype2varType(sig->retType);
-
- switch (intrinsic)
- {
- case NI_LZCNT_IsSupported:
- retNode = gtNewIconNode(compSupports(InstructionSet_LZCNT));
- break;
-
- case NI_LZCNT_LeadingZeroCount:
- assert(sig->numArgs == 1);
- op1 = impPopStack().val;
#ifdef _TARGET_X86_
- if (varTypeIsLong(callType))
- {
- return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, callType, sig->retTypeClass);
- }
-#endif
- retNode = gtNewScalarHWIntrinsicNode(callType, op1, NI_LZCNT_LeadingZeroCount);
- break;
-
- default:
- JITDUMP("Not implemented hardware intrinsic");
- break;
+ if (varTypeIsLong(callType))
+ {
+ return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, callType, sig->retTypeClass);
}
- return retNode;
+#endif
+ return gtNewScalarHWIntrinsicNode(callType, op, NI_LZCNT_LeadingZeroCount);
}
GenTree* Compiler::impPCLMULQDQIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
{
- switch (intrinsic)
- {
- case NI_PCLMULQDQ_IsSupported:
- return gtNewIconNode(featureSIMD && compSupports(InstructionSet_PCLMULQDQ));
-
- default:
- return nullptr;
- }
+ return nullptr;
}
GenTree* Compiler::impPOPCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
{
- GenTree* retNode = nullptr;
- GenTree* op1 = nullptr;
+ assert(sig->numArgs == 1);
+ GenTree* op = impPopStack().val;
var_types callType = JITtype2varType(sig->retType);
-
- switch (intrinsic)
- {
- case NI_POPCNT_IsSupported:
- retNode = gtNewIconNode(compSupports(InstructionSet_POPCNT));
- break;
-
- case NI_POPCNT_PopCount:
- assert(sig->numArgs == 1);
- op1 = impPopStack().val;
#ifdef _TARGET_X86_
- if (varTypeIsLong(callType))
- {
- return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, callType, sig->retTypeClass);
- }
-#endif
- retNode = gtNewScalarHWIntrinsicNode(callType, op1, NI_POPCNT_PopCount);
- break;
-
- default:
- JITDUMP("Not implemented hardware intrinsic");
- break;
+ if (varTypeIsLong(callType))
+ {
+ return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, callType, sig->retTypeClass);
}
- return retNode;
+#endif
+ return gtNewScalarHWIntrinsicNode(callType, op, NI_POPCNT_PopCount);
}
#endif // FEATURE_HW_INTRINSICS