Implement IsSuppoored for all ISA classes
authorFei Peng <fei.peng@intel.com>
Fri, 15 Sep 2017 20:01:13 +0000 (13:01 -0700)
committerJan Kotas <jkotas@microsoft.com>
Fri, 29 Sep 2017 21:23:43 +0000 (14:23 -0700)
17 files changed:
src/inc/corinfo.h
src/inc/corjit.h
src/jit/CMakeLists.txt
src/jit/compiler.cpp
src/jit/compiler.h
src/jit/hwintrinsiclistxarch.h [new file with mode: 0644]
src/jit/hwintrinsicxarch.cpp [new file with mode: 0644]
src/jit/importer.cpp
src/jit/instr.h
src/jit/jit.settings.targets
src/jit/jitee.h
src/jit/namedintrinsiclist.h
src/vm/codeman.cpp
src/vm/methodtablebuilder.cpp
tests/src/Common/test_dependencies/test_dependencies.csproj
tests/src/JIT/HardwareIntrinsics/IsSupported.cs [new file with mode: 0644]
tests/src/JIT/HardwareIntrinsics/IsSupported.csproj [new file with mode: 0644]

index aa024e0..b03f045 100644 (file)
@@ -213,11 +213,12 @@ TODO: Talk about initializing strutures before use
     #define SELECTANY extern __declspec(selectany)
 #endif
 
-SELECTANY const GUID JITEEVersionIdentifier = { /* 76a743cd-8a07-471e-9ac4-cd5806a8ffac */
-    0x76a743cd,
-    0x8a07,
-    0x471e,
-    {0x9a, 0xc4, 0xcd, 0x58, 0x06, 0xa8, 0xff, 0xac}
+// {CFEC7B89-D5FF-4A67-823A-EF99FE0286F4}
+SELECTANY const GUID JITEEVersionIdentifier = { 
+    0xcfec7b89, 
+    0xd5ff, 
+    0x4a67, 
+    { 0x82, 0x3a, 0xef, 0x99, 0xfe, 0x2, 0x86, 0xf4 } 
 };
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////////
index 39eafe2..6149859 100644 (file)
@@ -155,7 +155,38 @@ public:
         CORJIT_FLAG_UNUSED11                = 41,
 #endif // !defined(_TARGET_ARM_)
 
-        CORJIT_FLAG_NO_INLINING             = 42 // JIT should not inline any called method into this method
+        CORJIT_FLAG_NO_INLINING             = 42, // JIT should not inline any called method into this method
+
+#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
+
+        CORJIT_FLAG_USE_SSE3                = 43,
+        CORJIT_FLAG_USE_SSSE3               = 44,
+        CORJIT_FLAG_USE_SSE41               = 45,
+        CORJIT_FLAG_USE_SSE42               = 46,
+        CORJIT_FLAG_USE_AES                 = 47,
+        CORJIT_FLAG_USE_BMI1                = 48,
+        CORJIT_FLAG_USE_BMI2                = 49,
+        CORJIT_FLAG_USE_FMA                 = 50,
+        CORJIT_FLAG_USE_LZCNT               = 51,
+        CORJIT_FLAG_USE_PCLMULQDQ           = 52,
+        CORJIT_FLAG_USE_POPCNT              = 53
+        
+
+#else // !defined(_TARGET_X86_) && !defined(_TARGET_AMD64_)
+
+        CORJIT_FLAG_UNUSED12                = 43,
+        CORJIT_FLAG_UNUSED13                = 44,
+        CORJIT_FLAG_UNUSED14                = 45,
+        CORJIT_FLAG_UNUSED15                = 46,
+        CORJIT_FLAG_UNUSED16                = 47,
+        CORJIT_FLAG_UNUSED17                = 48,
+        CORJIT_FLAG_UNUSED18                = 49,
+        CORJIT_FLAG_UNUSED19                = 50,
+        CORJIT_FLAG_UNUSED20                = 51,
+        CORJIT_FLAG_UNUSED21                = 52,
+        CORJIT_FLAG_UNUSED22                = 53
+
+#endif // !defined(_TARGET_X86_) && !defined(_TARGET_AMD64_)
     };
 
     CORJIT_FLAGS()
index 87c47b5..a6efcd8 100644 (file)
@@ -100,6 +100,7 @@ set( JIT_AMD64_SOURCES
   simdcodegenxarch.cpp
   targetamd64.cpp
   unwindamd64.cpp
+  hwintrinsicxarch.cpp
 )
 
 set( JIT_ARM_SOURCES
@@ -127,6 +128,7 @@ set( JIT_I386_SOURCES
   simdcodegenxarch.cpp
   targetx86.cpp
   unwindx86.cpp
+  hwintrinsicxarch.cpp
 )
 
 set( JIT_ARM64_SOURCES
index 552a6df..86179ec 100644 (file)
@@ -2560,6 +2560,72 @@ void Compiler::compSetProcessor()
 #endif // DEBUG
 
 #endif // _TARGET_X86_
+
+// Instruction set flags fo// Instruction set flags for Intel hardware intrinsics
+#ifdef _TARGET_XARCH_
+    opts.compSupportsISA = 0;
+
+    if (!jitFlags.IsSet(JitFlags::JIT_FLAG_PREJIT))
+    {
+        if (opts.compCanUseSSE2)
+        {
+            opts.setSupportedISA(InstructionSet_SSE);
+            opts.setSupportedISA(InstructionSet_SSE2);
+            if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_AES))
+            {
+                opts.setSupportedISA(InstructionSet_AES);
+            }
+            if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_AVX))
+            {
+                opts.setSupportedISA(InstructionSet_AVX);
+            }
+            if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_AVX2))
+            {
+                opts.setSupportedISA(InstructionSet_AVX2);
+            }
+            if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_BMI1))
+            {
+                opts.setSupportedISA(InstructionSet_BMI1);
+            }
+            if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_BMI2))
+            {
+                opts.setSupportedISA(InstructionSet_BMI2);
+            }
+            if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_FMA))
+            {
+                opts.setSupportedISA(InstructionSet_FMA);
+            }
+            if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_LZCNT))
+            {
+                opts.setSupportedISA(InstructionSet_LZCNT);
+            }
+            if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_PCLMULQDQ))
+            {
+                opts.setSupportedISA(InstructionSet_PCLMULQDQ);
+            }
+            if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_POPCNT))
+            {
+                opts.setSupportedISA(InstructionSet_POPCNT);
+            }
+            if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSE3))
+            {
+                opts.setSupportedISA(InstructionSet_SSE3);
+            }
+            if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSE41))
+            {
+                opts.setSupportedISA(InstructionSet_SSE41);
+            }
+            if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSE42))
+            {
+                opts.setSupportedISA(InstructionSet_SSE42);
+            }
+            if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSSE3))
+            {
+                opts.setSupportedISA(InstructionSet_SSSE3);
+            }
+        }
+    }
+#endif
 }
 
 #ifdef PROFILING_SUPPORTED
index 21a2697..dfc50ee 100644 (file)
@@ -3016,6 +3016,28 @@ protected:
                               CorInfoIntrinsics     intrinsicID,
                               bool                  tailCall);
     NamedIntrinsic lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method);
+
+#ifdef _TARGET_XARCH_
+    InstructionSet lookupHWIntrinsicISA(const char* className);
+    NamedIntrinsic lookupHWIntrinsic(const char* methodName, InstructionSet isa);
+    InstructionSet isaOfHWIntrinsic(NamedIntrinsic intrinsic);
+    GenTree* impX86HWIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method);
+    GenTree* impSSEIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method);
+    GenTree* impSSE2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method);
+    GenTree* impSSE3Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method);
+    GenTree* impSSSE3Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method);
+    GenTree* impSSE41Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method);
+    GenTree* impSSE42Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method);
+    GenTree* impAVXIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method);
+    GenTree* impAVX2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method);
+    GenTree* impAESIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method);
+    GenTree* impBMI1Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method);
+    GenTree* impBMI2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method);
+    GenTree* impFMAIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method);
+    GenTree* impLZCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method);
+    GenTree* impPCLMULQDQIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method);
+    GenTree* impPOPCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method);
+#endif
     GenTreePtr impArrayAccessIntrinsic(CORINFO_CLASS_HANDLE clsHnd,
                                        CORINFO_SIG_INFO*    sig,
                                        int                  memberRef,
@@ -7915,6 +7937,19 @@ public:
 #endif                      // FEATURE_AVX_SUPPORT
 #endif                      // _TARGET_XARCH_
 
+#ifdef _TARGET_XARCH_
+        // only for Intel hardware intrinsics
+        uint64_t compSupportsISA;
+        void setSupportedISA(InstructionSet isa)
+        {
+            compSupportsISA |= 1 << isa;
+        }
+        bool compSupports(InstructionSet isa)
+        {
+            return (compSupportsISA & (1 << isa)) != 0;
+        }
+#endif
+
 // optimize maximally and/or favor speed over size?
 
 #define DEFAULT_MIN_OPTS_CODE_SIZE 60000
diff --git a/src/jit/hwintrinsiclistxarch.h b/src/jit/hwintrinsiclistxarch.h
new file mode 100644 (file)
index 0000000..d066d10
--- /dev/null
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*****************************************************************************/
+#ifndef HARDWARE_INTRINSIC
+#error Define HARDWARE_INTRINSIC before including this file
+#endif
+/*****************************************************************************/
+
+// clang-format off
+
+#ifdef _TARGET_XARCH_
+//                  Intrinsic ID                   Function name                ISA   
+//  SSE Intrinsics          
+HARDWARE_INTRINSIC(SSE_IsSupported,             "get_IsSupported",              SSE)
+
+//  SSE2 Intrinsics 
+HARDWARE_INTRINSIC(SSE2_IsSupported,            "get_IsSupported",              SSE2)
+
+//  SSE3 Intrinsics 
+HARDWARE_INTRINSIC(SSE3_IsSupported,            "get_IsSupported",              SSE3)
+
+//  SSSE3 Intrinsics 
+HARDWARE_INTRINSIC(SSSE3_IsSupported,           "get_IsSupported",              SSSE3)
+
+//  SSE41 Intrinsics 
+HARDWARE_INTRINSIC(SSE41_IsSupported,           "get_IsSupported",              SSE41)
+
+//  SSE42 Intrinsics 
+HARDWARE_INTRINSIC(SSE42_IsSupported,           "get_IsSupported",              SSE42)
+
+//  AVX Intrinsics 
+HARDWARE_INTRINSIC(AVX_IsSupported,             "get_IsSupported",              AVX)
+
+//  AVX2 Intrinsics 
+HARDWARE_INTRINSIC(AVX2_IsSupported,            "get_IsSupported",              AVX2)
+
+//  AES Intrinsics 
+HARDWARE_INTRINSIC(AES_IsSupported,             "get_IsSupported",              AES)
+
+//  BMI1 Intrinsics 
+HARDWARE_INTRINSIC(BMI1_IsSupported,            "get_IsSupported",              BMI1)
+
+//  BMI2 Intrinsics 
+HARDWARE_INTRINSIC(BMI2_IsSupported,            "get_IsSupported",              BMI2)
+
+//  FMA Intrinsics 
+HARDWARE_INTRINSIC(FMA_IsSupported,             "get_IsSupported",              FMA)
+
+//  LZCNT Intrinsics 
+HARDWARE_INTRINSIC(LZCNT_IsSupported,           "get_IsSupported",              LZCNT)
+
+//  PCLMULQDQ Intrinsics 
+HARDWARE_INTRINSIC(PCLMULQDQ_IsSupported,       "get_IsSupported",              PCLMULQDQ)
+
+//  POPCNT Intrinsics 
+HARDWARE_INTRINSIC(POPCNT_IsSupported,          "get_IsSupported",              POPCNT)
+#endif
+
+#undef HARDWARE_INTRINSIC
+
+// clang-format on
diff --git a/src/jit/hwintrinsicxarch.cpp b/src/jit/hwintrinsicxarch.cpp
new file mode 100644 (file)
index 0000000..4a1ca85
--- /dev/null
@@ -0,0 +1,382 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "jitpch.h"
+
+#ifdef _TARGET_XARCH_
+
+struct HWIntrinsicInfo
+{
+    NamedIntrinsic intrinsicID;
+    const char*    intrinsicName;
+    InstructionSet isa;
+}
+
+static const hwIntrinsicInfoArray[] = {
+#define HARDWARE_INTRINSIC(id, name, isa) {NI_##id, name, InstructionSet_##isa},
+#include "hwintrinsiclistxarch.h"
+};
+
+//------------------------------------------------------------------------
+// lookupHWIntrinsicISA: map class name to InstructionSet value
+//
+// Arguments:
+//    className -- class name in System.Runtime.Intrinsics.X86
+//
+// Return Value:
+//    Id for the ISA class.
+//
+InstructionSet Compiler::lookupHWIntrinsicISA(const char* className)
+{
+    if (className != nullptr)
+    {
+        if (className[0] == 'A')
+        {
+            if (strcmp(className, "Aes") == 0)
+            {
+                return InstructionSet_AES;
+            }
+            else if (strcmp(className, "Avx") == 0)
+            {
+                return InstructionSet_AVX;
+            }
+            else if (strcmp(className, "Avx2") == 0)
+            {
+                return InstructionSet_AVX2;
+            }
+        }
+        if (className[0] == 'S')
+        {
+            if (strcmp(className, "Sse") == 0)
+            {
+                return InstructionSet_SSE;
+            }
+            else if (strcmp(className, "Sse2") == 0)
+            {
+                return InstructionSet_SSE2;
+            }
+            else if (strcmp(className, "Sse3") == 0)
+            {
+                return InstructionSet_SSE3;
+            }
+            else if (strcmp(className, "Ssse3") == 0)
+            {
+                return InstructionSet_SSSE3;
+            }
+            else if (strcmp(className, "Sse41") == 0)
+            {
+                return InstructionSet_SSE41;
+            }
+            else if (strcmp(className, "Sse42") == 0)
+            {
+                return InstructionSet_SSE42;
+            }
+        }
+
+        if (strcmp(className, "Bmi1") == 0)
+        {
+            return InstructionSet_BMI1;
+        }
+        else if (strcmp(className, "Bmi2") == 0)
+        {
+            return InstructionSet_BMI2;
+        }
+        else if (strcmp(className, "Fma") == 0)
+        {
+            return InstructionSet_FMA;
+        }
+        else if (strcmp(className, "Lzcnt") == 0)
+        {
+            return InstructionSet_LZCNT;
+        }
+        else if (strcmp(className, "Pclmulqdq") == 0)
+        {
+            return InstructionSet_PCLMULQDQ;
+        }
+        else if (strcmp(className, "Popcnt") == 0)
+        {
+            return InstructionSet_POPCNT;
+        }
+    }
+
+    JITDUMP("Unsupported ISA.\n");
+    return InstructionSet_ILLEGAL;
+}
+
+//------------------------------------------------------------------------
+// lookupHWIntrinsic: map intrinsic name to named intrinsic value
+//
+// Arguments:
+//    methodName -- name of the intrinsic function.
+//    isa        -- instruction set of the intrinsic.
+//
+// Return Value:
+//    Id for the hardware intrinsic.
+//
+// TODO-Throughput: replace sequential search by binary search
+NamedIntrinsic Compiler::lookupHWIntrinsic(const char* methodName, InstructionSet isa)
+{
+    NamedIntrinsic result = NI_Illegal;
+    if (isa != InstructionSet_ILLEGAL)
+    {
+        for (int i = 0; i < NI_HW_INTRINSIC_END - NI_HW_INTRINSIC_START; i++)
+        {
+            if (isa == hwIntrinsicInfoArray[i].isa && strcmp(methodName, hwIntrinsicInfoArray[i].intrinsicName) == 0)
+            {
+                result = hwIntrinsicInfoArray[i].intrinsicID;
+            }
+        }
+    }
+    return result;
+}
+
+//------------------------------------------------------------------------
+// isaOfHWIntrinsic: map named intrinsic value to its instruction set
+//
+// Arguments:
+//    intrinsic -- id of the intrinsic function.
+//
+// Return Value:
+//    instruction set of the intrinsic.
+//
+InstructionSet Compiler::isaOfHWIntrinsic(NamedIntrinsic intrinsic)
+{
+    assert(intrinsic != NI_Illegal);
+    assert(intrinsic > NI_HW_INTRINSIC_START && intrinsic < NI_HW_INTRINSIC_END);
+    return hwIntrinsicInfoArray[intrinsic - NI_HW_INTRINSIC_START - 1].isa;
+}
+
+//------------------------------------------------------------------------
+// impX86HWIntrinsic: dispatch hardware intrinsics to their own implementation
+// function
+//
+// Arguments:
+//    intrinsic -- id of the intrinsic function.
+//    method    -- method handle of the intrinsic function.
+//
+// Return Value:
+//    the expanded intrinsic.
+//
+GenTree* Compiler::impX86HWIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method)
+{
+    InstructionSet isa = isaOfHWIntrinsic(intrinsic);
+    switch (isa)
+    {
+        case InstructionSet_SSE:
+            return impSSEIntrinsic(intrinsic, method);
+        case InstructionSet_SSE2:
+            return impSSE2Intrinsic(intrinsic, method);
+        case InstructionSet_SSE3:
+            return impSSE3Intrinsic(intrinsic, method);
+        case InstructionSet_SSSE3:
+            return impSSSE3Intrinsic(intrinsic, method);
+        case InstructionSet_SSE41:
+            return impSSE41Intrinsic(intrinsic, method);
+        case InstructionSet_SSE42:
+            return impSSE42Intrinsic(intrinsic, method);
+        case InstructionSet_AVX:
+            return impAVXIntrinsic(intrinsic, method);
+        case InstructionSet_AVX2:
+            return impAVX2Intrinsic(intrinsic, method);
+
+        case InstructionSet_AES:
+            return impAESIntrinsic(intrinsic, method);
+        case InstructionSet_BMI1:
+            return impBMI1Intrinsic(intrinsic, method);
+        case InstructionSet_BMI2:
+            return impBMI2Intrinsic(intrinsic, method);
+        case InstructionSet_FMA:
+            return impFMAIntrinsic(intrinsic, method);
+        case InstructionSet_LZCNT:
+            return impLZCNTIntrinsic(intrinsic, method);
+        case InstructionSet_PCLMULQDQ:
+            return impPCLMULQDQIntrinsic(intrinsic, method);
+        case InstructionSet_POPCNT:
+            return impPOPCNTIntrinsic(intrinsic, method);
+        default:
+            return nullptr;
+    }
+}
+
+GenTree* Compiler::impSSEIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method)
+{
+    switch (intrinsic)
+    {
+        case NI_SSE_IsSupported:
+            return gtNewIconNode(opts.compSupports(InstructionSet_SSE));
+
+        default:
+            return nullptr;
+    }
+}
+
+GenTree* Compiler::impSSE2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method)
+{
+    switch (intrinsic)
+    {
+        case NI_SSE2_IsSupported:
+            return gtNewIconNode(opts.compSupports(InstructionSet_SSE2));
+
+        default:
+            return nullptr;
+    }
+}
+
+GenTree* Compiler::impSSE3Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method)
+{
+    switch (intrinsic)
+    {
+        case NI_SSE3_IsSupported:
+            return gtNewIconNode(opts.compSupports(InstructionSet_SSE3));
+
+        default:
+            return nullptr;
+    }
+}
+
+GenTree* Compiler::impSSSE3Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method)
+{
+    switch (intrinsic)
+    {
+        case NI_SSSE3_IsSupported:
+            return gtNewIconNode(opts.compSupports(InstructionSet_SSSE3));
+
+        default:
+            return nullptr;
+    }
+}
+
+GenTree* Compiler::impSSE41Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method)
+{
+    switch (intrinsic)
+    {
+        case NI_SSE41_IsSupported:
+            return gtNewIconNode(opts.compSupports(InstructionSet_SSE41));
+
+        default:
+            return nullptr;
+    }
+}
+
+GenTree* Compiler::impSSE42Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method)
+{
+    switch (intrinsic)
+    {
+        case NI_SSE42_IsSupported:
+            return gtNewIconNode(opts.compSupports(InstructionSet_SSE42));
+
+        default:
+            return nullptr;
+    }
+}
+
+GenTree* Compiler::impAVXIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method)
+{
+    switch (intrinsic)
+    {
+        case NI_AVX_IsSupported:
+            return gtNewIconNode(opts.compSupports(InstructionSet_AVX));
+
+        default:
+            return nullptr;
+    }
+}
+
+GenTree* Compiler::impAVX2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method)
+{
+    switch (intrinsic)
+    {
+        case NI_AVX2_IsSupported:
+            return gtNewIconNode(opts.compSupports(InstructionSet_AVX2));
+
+        default:
+            return nullptr;
+    }
+}
+
+GenTree* Compiler::impAESIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method)
+{
+    switch (intrinsic)
+    {
+        case NI_AES_IsSupported:
+            return gtNewIconNode(opts.compSupports(InstructionSet_AES));
+
+        default:
+            return nullptr;
+    }
+}
+
+GenTree* Compiler::impBMI1Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method)
+{
+    switch (intrinsic)
+    {
+        case NI_BMI1_IsSupported:
+            return gtNewIconNode(opts.compSupports(InstructionSet_BMI1));
+
+        default:
+            return nullptr;
+    }
+}
+
+GenTree* Compiler::impBMI2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method)
+{
+    switch (intrinsic)
+    {
+        case NI_BMI2_IsSupported:
+            return gtNewIconNode(opts.compSupports(InstructionSet_BMI2));
+
+        default:
+            return nullptr;
+    }
+}
+
+GenTree* Compiler::impFMAIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method)
+{
+    switch (intrinsic)
+    {
+        case NI_FMA_IsSupported:
+            return gtNewIconNode(opts.compSupports(InstructionSet_FMA));
+
+        default:
+            return nullptr;
+    }
+}
+
+GenTree* Compiler::impLZCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method)
+{
+    switch (intrinsic)
+    {
+        case NI_LZCNT_IsSupported:
+            return gtNewIconNode(opts.compSupports(InstructionSet_LZCNT));
+
+        default:
+            return nullptr;
+    }
+}
+
+GenTree* Compiler::impPCLMULQDQIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method)
+{
+    switch (intrinsic)
+    {
+        case NI_PCLMULQDQ_IsSupported:
+            return gtNewIconNode(opts.compSupports(InstructionSet_PCLMULQDQ));
+
+        default:
+            return nullptr;
+    }
+}
+
+GenTree* Compiler::impPOPCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method)
+{
+    switch (intrinsic)
+    {
+        case NI_POPCNT_IsSupported:
+            return gtNewIconNode(opts.compSupports(InstructionSet_POPCNT));
+
+        default:
+            return nullptr;
+    }
+}
+
+#endif // _TARGET_XARCH_
\ No newline at end of file
index fcf3ddc..d16dfe3 100644 (file)
@@ -3735,7 +3735,12 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr            newobjThis,
     {
         assert(retNode == nullptr);
         const NamedIntrinsic ni = lookupNamedIntrinsic(method);
-
+#ifdef _TARGET_XARCH_
+        if (ni > NI_HW_INTRINSIC_START && ni < NI_HW_INTRINSIC_END)
+        {
+            retNode = impX86HWIntrinsic(ni, method);
+        }
+#endif
         switch (ni)
         {
             case NI_System_Enum_HasFlag:
@@ -3958,6 +3963,13 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
         }
     }
 
+#ifdef _TARGET_XARCH_
+    if ((namespaceName != nullptr) && strcmp(namespaceName, "System.Runtime.Intrinsics.X86") == 0)
+    {
+        InstructionSet isa = lookupHWIntrinsicISA(className);
+        result             = lookupHWIntrinsic(methodName, isa);
+    }
+#endif
     return result;
 }
 
index 309a2f5..e364fbc 100644 (file)
@@ -280,10 +280,29 @@ enum emitAttr : unsigned
 enum InstructionSet
 {
 #ifdef _TARGET_XARCH_
-    InstructionSet_SSE2,      // SSE2 Instruction set
-    InstructionSet_SSE3_4,    // SSE3, SSSE3, SSE4.1 and SSE4.2 instruction set
-    InstructionSet_AVX,       // AVX2 instruction set
-                              // TODO-Cleaup - This should be named as InstructionSet_AVX2
+    // Linear order start
+    InstructionSet_ILLEGAL = 0,
+    InstructionSet_SSE     = 1,
+    InstructionSet_SSE2    = 2,
+    InstructionSet_SSE3    = 3,
+    InstructionSet_SSSE3   = 4,
+    InstructionSet_SSE41   = 5,
+    InstructionSet_SSE42   = 6,
+    InstructionSet_SSE3_4  = 7,    // SSE3, SSSE3, SSE4.1 and SSE4.2 instruction set
+    InstructionSet_AVX     = 8,
+    InstructionSet_AVX2    = 9,
+    // Linear order end
+    // Instruction sets have the linear order only in above area.
+    // Values of InstructionSet not in this area cannot be compared 
+    // (i.e. compiler->getSIMDInstructionSet() >= InstructionSet_SSE3_4).
+
+    InstructionSet_AES     = 32,
+    InstructionSet_BMI1    = 33,
+    InstructionSet_BMI2    = 34,
+    InstructionSet_FMA     = 35,
+    InstructionSet_LZCNT   = 36,
+    InstructionSet_PCLMULQDQ  = 37,
+    InstructionSet_POPCNT  = 38,
 #elif defined(_TARGET_ARM_)
     InstructionSet_NEON,
 #endif
index bde6395..ee1df74 100644 (file)
         <CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'"  Include="..\CodeGenXArch.cpp" />
         <CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'"  Include="..\SIMD.cpp" />
         <CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'"  Include="..\SIMDCodeGenXArch.cpp" />
+        <CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'"  Include="..\hwintrinsicxarch.cpp" />
     </ItemGroup>
     <ItemGroup Condition="'$(TargetArch)'=='amd64'">
         <!-- AMD64 target is always RyuJIT backend -->
         <CppCompile Include="..\SIMD.cpp" />
         <CppCompile Include="..\SIMDCodeGenXArch.cpp" />
         <CppCompile Include="..\unwindAmd64.cpp" />
+        <CppCompile Include="..\hwintrinsicxarch.cpp" />
     </ItemGroup>
     <ItemGroup Condition="'$(TargetArch)'=='arm'">
         <CppCompile Include="..\emitarm.cpp" />
index 5fc2c2c..4c2359a 100644 (file)
@@ -88,6 +88,37 @@ public:
 #endif // !defined(_TARGET_ARM_)
 
         JIT_FLAG_NO_INLINING             = 42, // JIT should not inline any called method into this method
+
+#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
+
+        JIT_FLAG_USE_SSE3                = 43,
+        JIT_FLAG_USE_SSSE3               = 44,
+        JIT_FLAG_USE_SSE41               = 45,
+        JIT_FLAG_USE_SSE42               = 46,
+        JIT_FLAG_USE_AES                 = 47,
+        JIT_FLAG_USE_BMI1                = 48,
+        JIT_FLAG_USE_BMI2                = 49,
+        JIT_FLAG_USE_FMA                 = 50,
+        JIT_FLAG_USE_LZCNT               = 51,
+        JIT_FLAG_USE_PCLMULQDQ           = 52,
+        JIT_FLAG_USE_POPCNT              = 53
+        
+
+#else // !defined(_TARGET_X86_) && !defined(_TARGET_AMD64_)
+
+        JIT_FLAG_UNUSED12                = 43,
+        JIT_FLAG_UNUSED13                = 44,
+        JIT_FLAG_UNUSED14                = 45,
+        JIT_FLAG_UNUSED15                = 46,
+        JIT_FLAG_UNUSED16                = 47,
+        JIT_FLAG_UNUSED17                = 48,
+        JIT_FLAG_UNUSED18                = 49,
+        JIT_FLAG_UNUSED19                = 50,
+        JIT_FLAG_UNUSED20                = 51,
+        JIT_FLAG_UNUSED21                = 52,
+        JIT_FLAG_UNUSED22                = 53
+
+#endif // !defined(_TARGET_X86_) && !defined(_TARGET_AMD64_)
     };
     // clang-format on
 
@@ -208,6 +239,20 @@ public:
 
         FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_NO_INLINING, JIT_FLAG_NO_INLINING);
 
+#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
+        FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_SSE3, JIT_FLAG_USE_SSE3);
+        FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_SSSE3, JIT_FLAG_USE_SSSE3);
+        FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_SSE41, JIT_FLAG_USE_SSE41);
+        FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_SSE42, JIT_FLAG_USE_SSE42);
+        FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_AES, JIT_FLAG_USE_AES);
+        FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_BMI1, JIT_FLAG_USE_BMI1);
+        FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_BMI2, JIT_FLAG_USE_BMI2);
+        FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_FMA, JIT_FLAG_USE_FMA);
+        FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_LZCNT, JIT_FLAG_USE_LZCNT);
+        FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_PCLMULQDQ, JIT_FLAG_USE_PCLMULQDQ);
+        FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_POPCNT, JIT_FLAG_USE_POPCNT);
+#endif // _TARGET_X86_ || _TARGET_AMD64_
+
 #undef FLAGS_EQUAL
     }
 
index fa75cc2..42786a0 100644 (file)
@@ -7,13 +7,19 @@
 
 // Named jit intrinsics
 
-enum NamedIntrinsic
+enum NamedIntrinsic : unsigned int
 {
     NI_Illegal                                                 = 0,
     NI_System_Enum_HasFlag                                     = 1,
     NI_MathF_Round                                             = 2,
     NI_Math_Round                                              = 3,
-    NI_System_Collections_Generic_EqualityComparer_get_Default = 4
+    NI_System_Collections_Generic_EqualityComparer_get_Default = 4,
+#ifdef _TARGET_XARCH_
+    NI_HW_INTRINSIC_START,
+#define HARDWARE_INTRINSIC(id, name, isa) NI_##id,
+#include "hwintrinsiclistxarch.h"
+    NI_HW_INTRINSIC_END
+#endif
 };
 
 #endif // _NAMEDINTRINSICLIST_H_
index 7d90ce9..878119c 100644 (file)
@@ -1313,6 +1313,24 @@ void EEJitManager::SetCpuInfo()
         // It returns the resulting eax in buffer[0-3], ebx in buffer[4-7], ecx in buffer[8-11],
         // and edx in buffer[12-15].
         // We will set the following flags:
+        // CORJIT_FLAG_USE_SSE3 if the following feature bits are set (input EAX of 1)
+        //    SSE3 - ECX bit 0     (buffer[8]  & 0x01)
+        // CORJIT_FLAG_USE_SSSE3 if the following feature bits are set (input EAX of 1)
+        //    SSE3 - ECX bit 0     (buffer[8]  & 0x01)
+        //    SSSE3 - ECX bit 9    (buffer[9]  & 0x02)
+        // CORJIT_FLAG_USE_SSE41 if the following feature bits are set (input EAX of 1)
+        //    SSE3 - ECX bit 0     (buffer[8]  & 0x01)
+        //    SSSE3 - ECX bit 9    (buffer[9]  & 0x02)
+        //    SSE4.1 - ECX bit 19  (buffer[10] & 0x08)
+        // CORJIT_FLAG_USE_SSE42 if the following feature bits are set (input EAX of 1)
+        //    SSE3 - ECX bit 0     (buffer[8]  & 0x01)
+        //    SSSE3 - ECX bit 9    (buffer[9]  & 0x02)
+        //    SSE4.2 - ECX bit 20  (buffer[10] & 0x10)
+        // CORJIT_FLAG_USE_POPCNT if the following feature bits are set (input EAX of 1)
+        //    SSE3 - ECX bit 0     (buffer[8]  & 0x01)
+        //    SSSE3 - ECX bit 9    (buffer[9]  & 0x02)
+        //    SSE4.2 - ECX bit 20  (buffer[10] & 0x10)
+        //    POPCNT - ECX bit 23  (buffer[10] & 0x80)
         // CORJIT_FLAG_USE_SSE3_4 if the following feature bits are set (input EAX of 1)
         //    SSE3 - ECX bit 0     (buffer[8]  & 0x01)
         //    SSSE3 - ECX bit 9    (buffer[9]  & 0x02)
@@ -1321,9 +1339,17 @@ void EEJitManager::SetCpuInfo()
         // CORJIT_FLAG_USE_AVX if the following feature bits are set (input EAX of 1), and xmmYmmStateSupport returns 1:
         //    OSXSAVE - ECX bit 27 (buffer[11] & 0x08)
         //    AVX - ECX bit 28     (buffer[11] & 0x10)
+        // CORJIT_FLAG_USE_FMA if the following feature bits are set (input EAX of 1), and xmmYmmStateSupport returns 1:
+        //    FMA - ECX bit 12     (buffer[9]  & 0x10)
         // CORJIT_FLAG_USE_AVX2 if the following feature bit is set (input EAX of 0x07 and input ECX of 0):
         //    AVX2 - EBX bit 5     (buffer[4]  & 0x20)
         // CORJIT_FLAG_USE_AVX_512 is not currently set, but defined so that it can be used in future without
+        // CORJIT_FLAG_USE_BMI1 if the following feature bit is set (input EAX of 0x07 and input ECX of 0):
+        //    BMI1 - EBX bit 3     (buffer[4]  & 0x08)
+        // CORJIT_FLAG_USE_BMI2 if the following feature bit is set (input EAX of 0x07 and input ECX of 0):
+        //    BMI2 - EBX bit 8     (buffer[5]  & 0x01)
+        // CORJIT_FLAG_USE_LZCNT if the following feature bits are set (input EAX of 80000001H)
+        //    LZCNT - ECX bit 5    (buffer[8]  & 0x20)
         // synchronously updating VM and JIT.
         (void) getcpuid(1, buffer);
         // If SSE2 is not enabled, there is no point in checking the rest.
@@ -1331,24 +1357,56 @@ void EEJitManager::SetCpuInfo()
         // TODO: Determine whether we should break out the various SSE options further.
         if ((buffer[15] & 0x04) != 0)               // SSE2
         {
-            if (((buffer[8]  & 0x01) != 0) &&       // SSE3
-                ((buffer[9]  & 0x02) != 0) &&       // SSSE3
-                ((buffer[10] & 0x08) != 0) &&       // SSE4.1
-                ((buffer[10] & 0x10) != 0))         // SSE4.2
+            if ((buffer[8]  & 0x01) != 0)           // SSE3
+            {
+                CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_SSE3);
+                if ((buffer[9]  & 0x02) != 0)           // SSSE3
+                {
+                    CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_SSSE3);
+                    if ((buffer[10] & 0x08) != 0)           // SSE4.1
+                    {
+                        CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_SSE41);
+                    }
+                    if ((buffer[10] & 0x10) != 0)           // SSE4.2
+                    {
+                        CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_SSE42);
+                        if ((buffer[10] & 0x80) != 0)       // POPCNT
+                        {
+                            CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_POPCNT);
+                        }
+                    }
+
+                    if (((buffer[10] & 0x08) != 0) &&       // SSE4.1
+                        ((buffer[10] & 0x10) != 0))         // SSE4.2
+                    {
+                        CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_SSE3_4);
+                    }
+                }
+            }
+            
+            if ((buffer[11] & 0x01) != 0)           // AESNI
             {
-                CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_SSE3_4);
+                CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_AES);
             }
-            if ((buffer[11] & 0x18) == 0x18)
+            if ((buffer[8] & 0x02) != 0)            // PCLMULQDQ 
+            {
+                CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_PCLMULQDQ);
+            }
+            if ((buffer[11] & 0x18) == 0x18)        // AVX
             {
                 if(DoesOSSupportAVX())
                 {
                     if (xmmYmmStateSupport() == 1)
                     {
                         CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_AVX);
+                        if ((buffer[9]  & 0x10) != 0) // FMA
+                        {
+                            CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_FMA);
+                        }
                         if (maxCpuId >= 0x07)
                         {
                             (void) getextcpuid(0, 0x07, buffer);
-                            if ((buffer[4]  & 0x20) != 0)
+                            if ((buffer[4]  & 0x20) != 0) // AVX2
                             {
                                 CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_AVX2);
                             }
@@ -1356,6 +1414,22 @@ void EEJitManager::SetCpuInfo()
                     }
                 }
             }
+            (void) getextcpuid(0, 0x07, buffer);
+            if ((buffer[4]  & 0x08) != 0)           // BMI1
+            {
+                CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_BMI1);
+            }
+            if ((buffer[5]  & 0x01) != 0)           //BMI2
+            {
+                CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_BMI2);
+            }
+
+            (void) getcpuid(0x80000001, buffer);
+            if ((buffer[8]  & 0x20) != 0)           // LZCNT
+            {
+                CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_LZCNT);
+            }
+
             static ConfigDWORD fFeatureSIMD;
             if (fFeatureSIMD.val(CLRConfig::EXTERNAL_FeatureSIMD) != 0)
             {
index cdee2d8..8a96e68 100644 (file)
@@ -5094,6 +5094,19 @@ MethodTableBuilder::InitNewMethodDesc(
         {
             pNewMD->SetIsJitIntrinsic();
         }
+
+        // All the funtions in System.Runtime.Intrinsics.X86 are hardware intrinsics.
+        // We specially treat them here to reduce the disk footprint of mscorlib.
+        LPCUTF8 className;
+        LPCUTF8 nameSpace;
+
+        HRESULT hrns = GetMDImport()->GetNameOfTypeDef(bmtInternal->pType->GetTypeDefToken(), &className, &nameSpace);
+
+        if (hrns == S_OK && strcmp(nameSpace, "System.Runtime.Intrinsics.X86") == 0)
+        {
+            pNewMD->SetIsJitIntrinsic();
+        }
+
     }
 
     pNewMD->SetSlot(pMethod->GetSlotIndex());
index 9eefab2..e9d78ec 100644 (file)
@@ -22,6 +22,9 @@
     <PackageReference Include="System.Security.Permissions">
       <Version>$(CoreFxPackageVersion)</Version>
     </PackageReference>
+    <PackageReference Include="System.Runtime.Intrinsics.X86">
+      <Version>4.5.0-preview1-25718-03</Version>
+    </PackageReference>
   </ItemGroup>
   <PropertyGroup>
     <TargetFramework>netcoreapp2.1</TargetFramework>
diff --git a/tests/src/JIT/HardwareIntrinsics/IsSupported.cs b/tests/src/JIT/HardwareIntrinsics/IsSupported.cs
new file mode 100644 (file)
index 0000000..9f6d924
--- /dev/null
@@ -0,0 +1,89 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.Intrinsics.X86;
+
+namespace IntelHardwareIntrinsicTest
+{
+    class Program
+    {
+        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 (Aes.IsSupported && Bmi1.IsSupported && Bmi2.IsSupported && Fma.IsSupported && 
+                        Lzcnt.IsSupported && Popcnt.IsSupported && Pclmulqdq.IsSupported)
+                    {
+                        result = result && true;
+                    }
+                    else
+                    {
+                        result = false;
+                    }
+            }
+
+            // Non-X86 platforms
+            if (!(Sse.IsSupported))
+            {
+                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;
+                }
+            }
+            return result ? 100 : 0;
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/tests/src/JIT/HardwareIntrinsics/IsSupported.csproj b/tests/src/JIT/HardwareIntrinsics/IsSupported.csproj
new file mode 100644 (file)
index 0000000..e8f88b5
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+  </PropertyGroup>
+  <!-- Default configurations to help VS understand the configurations -->
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " />
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+  <PropertyGroup>
+    <DebugType>None</DebugType>
+    <Optimize>True</Optimize>
+  </PropertyGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="IsSupported.cs" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+  <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
+</Project>
\ No newline at end of file