Add COMPlus_EnableIncompleteISAClass and streamline IsSupported
authorFei Peng <fei.peng@intel.com>
Wed, 20 Dec 2017 22:13:47 +0000 (14:13 -0800)
committerFei Peng <fei.peng@intel.com>
Wed, 20 Dec 2017 22:13:47 +0000 (14:13 -0800)
src/jit/compiler.h
src/jit/hwintrinsicxarch.cpp
src/jit/jitconfigvalues.h
tests/src/JIT/HardwareIntrinsics/X86/IsSupported.cs

index 813f344..904d993 100644 (file)
@@ -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,
index f2f98b4..719ac45 100644 (file)
@@ -187,6 +187,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
index e9b9f0d..64dfe9c 100644 (file)
@@ -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
index e828a44..bca3803 100644 (file)
@@ -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";