From 95c6e74fc8d8b40c883ed373c3ef2335dc23d967 Mon Sep 17 00:00:00 2001 From: Fei Peng Date: Wed, 20 Dec 2017 14:13:47 -0800 Subject: Add COMPlus_EnableIncompleteISAClass and streamline IsSupported --- src/jit/compiler.h | 3 + src/jit/hwintrinsicxarch.cpp | 251 ++++++++++----------- src/jit/jitconfigvalues.h | 4 +- .../src/JIT/HardwareIntrinsics/X86/IsSupported.cs | 61 ----- 4 files changed, 119 insertions(+), 200 deletions(-) diff --git a/src/jit/compiler.h b/src/jit/compiler.h index 813f34460f..904d993f32 100644 --- a/src/jit/compiler.h +++ b/src/jit/compiler.h @@ -3026,6 +3026,7 @@ protected: NamedIntrinsic lookupHWIntrinsic(const char* methodName, InstructionSet isa); InstructionSet isaOfHWIntrinsic(NamedIntrinsic intrinsic); bool isIntrinsicAnIsSupportedPropertyGetter(NamedIntrinsic intrinsic); + bool isFullyImplmentedISAClass(InstructionSet isa); #ifdef _TARGET_XARCH_ GenTree* impX86HWIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig); GenTree* impSSEIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig); @@ -3043,6 +3044,8 @@ protected: GenTree* impLZCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig); GenTree* impPCLMULQDQIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig); GenTree* impPOPCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig); + bool compSupportsHWIntrinsic(InstructionSet isa); + bool isScalarISA(InstructionSet isa); #endif // _TARGET_XARCH_ #endif // FEATURE_HW_INTRINSICS GenTreePtr impArrayAccessIntrinsic(CORINFO_CLASS_HANDLE clsHnd, diff --git a/src/jit/hwintrinsicxarch.cpp b/src/jit/hwintrinsicxarch.cpp index f2f98b41ff..719ac458ec 100644 --- a/src/jit/hwintrinsicxarch.cpp +++ b/src/jit/hwintrinsicxarch.cpp @@ -186,6 +186,85 @@ bool Compiler::isIntrinsicAnIsSupportedPropertyGetter(NamedIntrinsic intrinsic) } } +//------------------------------------------------------------------------ +// 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 @@ -201,12 +280,17 @@ bool Compiler::isIntrinsicAnIsSupportedPropertyGetter(NamedIntrinsic intrinsic) 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++) { @@ -215,6 +299,7 @@ GenTree* Compiler::impX86HWIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HA return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, JITtype2varType(sig->retType), sig->retTypeClass); } + switch (isa) { case InstructionSet_SSE: @@ -322,10 +407,6 @@ GenTree* Compiler::impSSEIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HAND 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); @@ -348,10 +429,6 @@ GenTree* Compiler::impSSE2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HAN 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); @@ -369,38 +446,17 @@ GenTree* Compiler::impSSE2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HAN 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) @@ -415,10 +471,6 @@ GenTree* Compiler::impSSE42Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HA 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; @@ -454,10 +506,6 @@ GenTree* Compiler::impAVXIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HAND 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); @@ -481,10 +529,6 @@ GenTree* Compiler::impAVX2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HAN 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); @@ -502,124 +546,55 @@ GenTree* Compiler::impAVX2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HAN 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 diff --git a/src/jit/jitconfigvalues.h b/src/jit/jitconfigvalues.h index e9b9f0d275..64dfe9ce60 100644 --- a/src/jit/jitconfigvalues.h +++ b/src/jit/jitconfigvalues.h @@ -206,7 +206,9 @@ CONFIG_INTEGER(EnableLZCNT, W("EnableLZCNT"), 1) // Enable AES CONFIG_INTEGER(EnablePCLMULQDQ, W("EnablePCLMULQDQ"), 1) // Enable PCLMULQDQ CONFIG_INTEGER(EnablePOPCNT, W("EnablePOPCNT"), 1) // Enable POPCNT #endif // defined(_TARGET_X86_) || defined(_TARGET_AMD64_) -#endif // defined(DEBUG) +CONFIG_INTEGER(EnableIncompleteISAClass, W("EnableIncompleteISAClass"), 0) // Enable testing not-yet-implemented + // intrinsic classes +#endif // defined(DEBUG) #ifdef FEATURE_ENABLE_NO_RANGE_CHECKS CONFIG_INTEGER(JitNoRangeChks, W("JitNoRngChks"), 0) // If 1, don't generate range checks diff --git a/tests/src/JIT/HardwareIntrinsics/X86/IsSupported.cs b/tests/src/JIT/HardwareIntrinsics/X86/IsSupported.cs index e828a4461e..bca38030cd 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/IsSupported.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/IsSupported.cs @@ -13,46 +13,6 @@ namespace IntelHardwareIntrinsicTest static int Main(string[] args) { bool result = true; - if (Avx2.IsSupported) - { - if (Avx.IsSupported) - { - if (!Sse42.IsSupported) - { - result = false; - } - - if (Sse41.IsSupported) - { - if (Ssse3.IsSupported) - { - if (Sse3.IsSupported) - { - if (Sse2.IsSupported && Sse.IsSupported) - { - result = result && true; - } - else - { - result = false; - } - } - else - { - result = false; - } - } - else - { - result = false; - } - } - else - { - result = false; - } - } - } if (Sse.IsSupported) { @@ -67,27 +27,6 @@ namespace IntelHardwareIntrinsicTest result = false; } } - else - { - // Non-X86 platforms - if (Sse2.IsSupported || - Sse3.IsSupported || - Ssse3.IsSupported || - Sse41.IsSupported || - Sse42.IsSupported || - Avx.IsSupported || - Avx2.IsSupported || - Aes.IsSupported || - Bmi1.IsSupported || - Bmi2.IsSupported || - Fma.IsSupported || - Lzcnt.IsSupported || - Popcnt.IsSupported|| - Pclmulqdq.IsSupported) - { - result = false; - } - } // Reflection call var issupported = "get_IsSupported"; -- cgit v1.2.3