diff --git a/src/dlls/mscorrc/mscorrc.rc b/src/dlls/mscorrc/mscorrc.rc
index 8dd29ae75f95..8bc7ff00b963 100644
--- a/src/dlls/mscorrc/mscorrc.rc
+++ b/src/dlls/mscorrc/mscorrc.rc
@@ -853,6 +853,7 @@ BEGIN
IDS_EE_SIMD_PARTIAL_TRUST_DISALLOWED "SIMD intrinsics may not be used by partial trust applications."
IDS_IBC_MISSING_EXTERNAL_TYPE "The generic type specified by the IBC data is not available to this assembly"
IDS_IBC_MISSING_EXTERNAL_METHOD "The generic method specified by the IBC data is not available to this assembly"
+ IDS_EE_HWINTRINSIC_NGEN_DISALLOWED "Hardware intrinsics may not be used with ngen."
IDS_INET_E_CANNOT_CONNECT "Cannot connect to URL for '%1'."
IDS_INET_E_RESOURCE_NOT_FOUND "The server or proxy was not found for '%1'."
diff --git a/src/dlls/mscorrc/resource.h b/src/dlls/mscorrc/resource.h
index 205445acbe53..eb1cb293f47a 100644
--- a/src/dlls/mscorrc/resource.h
+++ b/src/dlls/mscorrc/resource.h
@@ -613,6 +613,7 @@
#define IDS_EE_SIMD_PARTIAL_TRUST_DISALLOWED 0x1ac4
#define IDS_IBC_MISSING_EXTERNAL_TYPE 0x1ac5
#define IDS_IBC_MISSING_EXTERNAL_METHOD 0x1ac6
+#define IDS_EE_HWINTRINSIC_NGEN_DISALLOWED 0x1ac7
#define BFA_INVALID_FILE_TOKEN 0x2000
#define BFA_INVALID_TOKEN_TYPE 0x2001
diff --git a/src/inc/corinfo.h b/src/inc/corinfo.h
index aa024e054729..b03f0456ac39 100644
--- a/src/inc/corinfo.h
+++ b/src/inc/corinfo.h
@@ -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 }
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/inc/corjit.h b/src/inc/corjit.h
index 39eafe2a8950..61498594a386 100644
--- a/src/inc/corjit.h
+++ b/src/inc/corjit.h
@@ -155,7 +155,38 @@ class CORJIT_FLAGS
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()
diff --git a/src/jit/CMakeLists.txt b/src/jit/CMakeLists.txt
index 87c47b5aca83..a6efcd8e242b 100644
--- a/src/jit/CMakeLists.txt
+++ b/src/jit/CMakeLists.txt
@@ -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
diff --git a/src/jit/compiler.cpp b/src/jit/compiler.cpp
index 552a6dff9480..6e1323ff2e2a 100644
--- a/src/jit/compiler.cpp
+++ b/src/jit/compiler.cpp
@@ -2560,6 +2560,72 @@ void Compiler::compSetProcessor()
#endif // DEBUG
#endif // _TARGET_X86_
+
+// 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
diff --git a/src/jit/compiler.h b/src/jit/compiler.h
index 21a2697f2f00..4bdb7ac07e67 100644
--- a/src/jit/compiler.h
+++ b/src/jit/compiler.h
@@ -3016,6 +3016,28 @@ class Compiler
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, CORINFO_SIG_INFO* sig);
+ GenTree* impSSEIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
+ GenTree* impSSE2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
+ GenTree* impSSE3Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
+ GenTree* impSSSE3Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
+ GenTree* impSSE41Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
+ GenTree* impSSE42Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
+ GenTree* impAVXIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
+ GenTree* impAVX2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
+ GenTree* impAESIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
+ GenTree* impBMI1Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
+ GenTree* impBMI2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
+ GenTree* impFMAIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
+ 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);
+#endif
GenTreePtr impArrayAccessIntrinsic(CORINFO_CLASS_HANDLE clsHnd,
CORINFO_SIG_INFO* sig,
int memberRef,
@@ -7802,6 +7824,15 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#endif
}
+ bool compSupports(InstructionSet isa)
+ {
+#ifdef _TARGET_XARCH_
+ return (opts.compSupportsISA & (1 << isa)) != 0;
+#else
+ return false;
+#endif
+ }
+
/*
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
@@ -7915,6 +7946,14 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#endif // FEATURE_AVX_SUPPORT
#endif // _TARGET_XARCH_
+#ifdef _TARGET_XARCH_
+ uint64_t compSupportsISA;
+ void setSupportedISA(InstructionSet isa)
+ {
+ compSupportsISA |= 1 << isa;
+ }
+#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
index 000000000000..d066d1028951
--- /dev/null
+++ b/src/jit/hwintrinsiclistxarch.h
@@ -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
index 000000000000..45ee4681742d
--- /dev/null
+++ b/src/jit/hwintrinsicxarch.cpp
@@ -0,0 +1,383 @@
+// 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.
+// sig -- signature of the intrinsic call
+//
+// Return Value:
+// the expanded intrinsic.
+//
+GenTree* Compiler::impX86HWIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
+{
+ InstructionSet isa = isaOfHWIntrinsic(intrinsic);
+ switch (isa)
+ {
+ case InstructionSet_SSE:
+ return impSSEIntrinsic(intrinsic, method, sig);
+ case InstructionSet_SSE2:
+ return impSSE2Intrinsic(intrinsic, method, sig);
+ case InstructionSet_SSE3:
+ return impSSE3Intrinsic(intrinsic, method, sig);
+ case InstructionSet_SSSE3:
+ return impSSSE3Intrinsic(intrinsic, method, sig);
+ case InstructionSet_SSE41:
+ return impSSE41Intrinsic(intrinsic, method, sig);
+ case InstructionSet_SSE42:
+ return impSSE42Intrinsic(intrinsic, method, sig);
+ case InstructionSet_AVX:
+ return impAVXIntrinsic(intrinsic, method, sig);
+ case InstructionSet_AVX2:
+ return impAVX2Intrinsic(intrinsic, method, sig);
+
+ case InstructionSet_AES:
+ return impAESIntrinsic(intrinsic, method, sig);
+ case InstructionSet_BMI1:
+ return impBMI1Intrinsic(intrinsic, method, sig);
+ case InstructionSet_BMI2:
+ return impBMI2Intrinsic(intrinsic, method, sig);
+ case InstructionSet_FMA:
+ return impFMAIntrinsic(intrinsic, method, sig);
+ case InstructionSet_LZCNT:
+ return impLZCNTIntrinsic(intrinsic, method, sig);
+ case InstructionSet_PCLMULQDQ:
+ return impPCLMULQDQIntrinsic(intrinsic, method, sig);
+ case InstructionSet_POPCNT:
+ return impPOPCNTIntrinsic(intrinsic, method, sig);
+ default:
+ return nullptr;
+ }
+}
+
+GenTree* Compiler::impSSEIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
+{
+ switch (intrinsic)
+ {
+ case NI_SSE_IsSupported:
+ return gtNewIconNode(compSupports(InstructionSet_SSE));
+
+ default:
+ return nullptr;
+ }
+}
+
+GenTree* Compiler::impSSE2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
+{
+ switch (intrinsic)
+ {
+ case NI_SSE2_IsSupported:
+ return gtNewIconNode(compSupports(InstructionSet_SSE2));
+
+ default:
+ return nullptr;
+ }
+}
+
+GenTree* Compiler::impSSE3Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
+{
+ switch (intrinsic)
+ {
+ case NI_SSE3_IsSupported:
+ return gtNewIconNode(compSupports(InstructionSet_SSE3));
+
+ default:
+ return nullptr;
+ }
+}
+
+GenTree* Compiler::impSSSE3Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
+{
+ switch (intrinsic)
+ {
+ case NI_SSSE3_IsSupported:
+ return gtNewIconNode(compSupports(InstructionSet_SSSE3));
+
+ default:
+ return nullptr;
+ }
+}
+
+GenTree* Compiler::impSSE41Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
+{
+ switch (intrinsic)
+ {
+ case NI_SSE41_IsSupported:
+ return gtNewIconNode(compSupports(InstructionSet_SSE41));
+
+ default:
+ return nullptr;
+ }
+}
+
+GenTree* Compiler::impSSE42Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
+{
+ switch (intrinsic)
+ {
+ case NI_SSE42_IsSupported:
+ return gtNewIconNode(compSupports(InstructionSet_SSE42));
+
+ default:
+ return nullptr;
+ }
+}
+
+GenTree* Compiler::impAVXIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
+{
+ switch (intrinsic)
+ {
+ case NI_AVX_IsSupported:
+ return gtNewIconNode(compSupports(InstructionSet_AVX));
+
+ default:
+ return nullptr;
+ }
+}
+
+GenTree* Compiler::impAVX2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
+{
+ switch (intrinsic)
+ {
+ case NI_AVX2_IsSupported:
+ return gtNewIconNode(compSupports(InstructionSet_AVX2));
+
+ default:
+ return nullptr;
+ }
+}
+
+GenTree* Compiler::impAESIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
+{
+ switch (intrinsic)
+ {
+ case NI_AES_IsSupported:
+ return gtNewIconNode(compSupports(InstructionSet_AES));
+
+ default:
+ 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;
+ }
+}
+
+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;
+ }
+}
+
+GenTree* Compiler::impFMAIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
+{
+ switch (intrinsic)
+ {
+ case NI_FMA_IsSupported:
+ return gtNewIconNode(compSupports(InstructionSet_FMA));
+
+ default:
+ return nullptr;
+ }
+}
+
+GenTree* Compiler::impLZCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
+{
+ switch (intrinsic)
+ {
+ case NI_LZCNT_IsSupported:
+ return gtNewIconNode(compSupports(InstructionSet_LZCNT));
+
+ default:
+ return nullptr;
+ }
+}
+
+GenTree* Compiler::impPCLMULQDQIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
+{
+ switch (intrinsic)
+ {
+ case NI_PCLMULQDQ_IsSupported:
+ return gtNewIconNode(compSupports(InstructionSet_PCLMULQDQ));
+
+ default:
+ return nullptr;
+ }
+}
+
+GenTree* Compiler::impPOPCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
+{
+ switch (intrinsic)
+ {
+ case NI_POPCNT_IsSupported:
+ return gtNewIconNode(compSupports(InstructionSet_POPCNT));
+
+ default:
+ return nullptr;
+ }
+}
+
+#endif // _TARGET_XARCH_
\ No newline at end of file
diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp
index fcf3ddc1efb8..714e6fe21f58 100644
--- a/src/jit/importer.cpp
+++ b/src/jit/importer.cpp
@@ -3322,9 +3322,11 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr newobjThis,
GenTreePtr retNode = nullptr;
//
- // We disable the inlining of instrinsics for MinOpts.
- //
- if (!mustExpand && (opts.compDbgCode || opts.MinOpts()))
+ // We disable the inlining of intrinsic for MinOpts,
+ // but we should always expand hardware intrinsics whose managed method body
+ // is a directly recursive call site. This design makes hardware intrinsic
+ // be able to work with debugger and reflection.
+ if (!mustExpand && (opts.compDbgCode || opts.MinOpts()) && !gtIsRecursiveCall(method))
{
*pIntrinsicID = CORINFO_INTRINSIC_Illegal;
return retNode;
@@ -3735,7 +3737,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, sig);
+ }
+#endif
switch (ni)
{
case NI_System_Enum_HasFlag:
@@ -3958,6 +3965,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;
}
diff --git a/src/jit/instr.h b/src/jit/instr.h
index 309a2f5dfeac..eac425634ca1 100644
--- a/src/jit/instr.h
+++ b/src/jit/instr.h
@@ -274,16 +274,34 @@ enum emitAttr : unsigned
#define EmitSize(x) (EA_ATTR(genTypeSize(TypeGet(x))))
-// Enum specifying the instruction set for generating floating point or SIMD code.
-// These enums are ordered such that each one is inclusive of previous instruction sets
-// and the VM ensures this as well when setting the CONFIG flags.
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
+ // TODO - Instruction sets have the linear order only in above area.
+ // We should no long compare the return value of getSIMDInstructionSet()
+ // or getFloatingPointInstructionSet() to the InstructionSet values.
+ // Should refactor SIMD code only to be aware of SIMD feature levels
+ // (SSE2, SSE3_4, AVX, and AVX2, etc.) rather than concrete ISA.
+
+ 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
diff --git a/src/jit/jit.settings.targets b/src/jit/jit.settings.targets
index bde639556b47..ee1df74c6238 100644
--- a/src/jit/jit.settings.targets
+++ b/src/jit/jit.settings.targets
@@ -103,6 +103,7 @@
+
@@ -114,6 +115,7 @@
+
diff --git a/src/jit/jitee.h b/src/jit/jitee.h
index 5fc2c2cd8b7d..4c2359a7a303 100644
--- a/src/jit/jitee.h
+++ b/src/jit/jitee.h
@@ -88,6 +88,37 @@ class JitFlags
#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 @@ class JitFlags
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
}
diff --git a/src/jit/namedintrinsiclist.h b/src/jit/namedintrinsiclist.h
index fa75cc27b6f8..42786a0c9eef 100644
--- a/src/jit/namedintrinsiclist.h
+++ b/src/jit/namedintrinsiclist.h
@@ -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_
diff --git a/src/mscorlib/src/System/Runtime/Intrinsics/X86/Lzcnt.cs b/src/mscorlib/src/System/Runtime/Intrinsics/X86/Lzcnt.cs
index 17d7716fc018..6bdc8cc3a09c 100644
--- a/src/mscorlib/src/System/Runtime/Intrinsics/X86/Lzcnt.cs
+++ b/src/mscorlib/src/System/Runtime/Intrinsics/X86/Lzcnt.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Runtime.Intrinsics;
namespace System.Runtime.Intrinsics.X86
{
diff --git a/src/mscorlib/src/System/Runtime/Intrinsics/X86/Popcnt.cs b/src/mscorlib/src/System/Runtime/Intrinsics/X86/Popcnt.cs
index c9e71b3a4752..21cae3170c8f 100644
--- a/src/mscorlib/src/System/Runtime/Intrinsics/X86/Popcnt.cs
+++ b/src/mscorlib/src/System/Runtime/Intrinsics/X86/Popcnt.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Runtime.Intrinsics;
namespace System.Runtime.Intrinsics.X86
{
diff --git a/src/vm/codeman.cpp b/src/vm/codeman.cpp
index 7d90ce9a5e00..878119ca0d4d 100644
--- a/src/vm/codeman.cpp
+++ b/src/vm/codeman.cpp
@@ -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)
{
diff --git a/src/vm/methodtablebuilder.cpp b/src/vm/methodtablebuilder.cpp
index cdee2d86673b..adcf7bbc7987 100644
--- a/src/vm/methodtablebuilder.cpp
+++ b/src/vm/methodtablebuilder.cpp
@@ -1484,6 +1484,26 @@ MethodTableBuilder::BuildMethodTableThrowing(
}
}
+#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
+ // All the funtions in System.Runtime.Intrinsics.X86 are hardware intrinsics.
+ // We specially treat them here to reduce the disk footprint of mscorlib.
+ if (GetModule()->IsSystem() && !bmtGenerics->HasInstantiation())
+ {
+ LPCUTF8 x86className;
+ LPCUTF8 x86nameSpace;
+ HRESULT hr = GetMDImport()->GetNameOfTypeDef(bmtInternal->pType->GetTypeDefToken(), &x86className, &x86nameSpace);
+
+ if (hr == S_OK && strcmp(x86nameSpace, "System.Runtime.Intrinsics.X86") == 0)
+ {
+ if (IsCompilationProcess())
+ {
+ // Disable AOT compiling for managed implementation of hardware intrinsics in mscorlib.
+ COMPlusThrow(kTypeLoadException, IDS_EE_HWINTRINSIC_NGEN_DISALLOWED);
+ }
+ bmtProp->fIsHardwareIntrinsic = true;
+ }
+ }
+#endif
#ifdef FEATURE_COMINTEROP
@@ -5090,10 +5110,11 @@ MethodTableBuilder::InitNewMethodDesc(
NULL,
NULL);
- if (hr == S_OK)
+ if (hr == S_OK || bmtProp->fIsHardwareIntrinsic)
{
pNewMD->SetIsJitIntrinsic();
}
+
}
pNewMD->SetSlot(pMethod->GetSlotIndex());
@@ -9389,7 +9410,7 @@ void MethodTableBuilder::CheckForSystemTypes()
{
BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
}
-
+
if (IsValueClass())
{
//
diff --git a/src/vm/methodtablebuilder.h b/src/vm/methodtablebuilder.h
index a7d7bdd15890..c5ce09f3970b 100644
--- a/src/vm/methodtablebuilder.h
+++ b/src/vm/methodtablebuilder.h
@@ -1333,6 +1333,8 @@ class MethodTableBuilder
bool fDynamicStatics; // Set to true if the statics will be allocated in the dynamic
bool fGenericsStatics; // Set to true if the there are per-instantiation statics
+ bool fIsHardwareIntrinsic; // Set to true if the class is a hardware intrinsic
+
DWORD dwNonGCRegularStaticFieldBytes;
DWORD dwNonGCThreadStaticFieldBytes;
diff --git a/src/zap/zapimage.cpp b/src/zap/zapimage.cpp
index 96fa81fba141..98b9e9224dd0 100644
--- a/src/zap/zapimage.cpp
+++ b/src/zap/zapimage.cpp
@@ -3560,6 +3560,12 @@ void ZapImage::Error(mdToken token, HRESULT hr, UINT resID, LPCWSTR message)
level = CORZAP_LOGLEVEL_INFO;
}
+ if (resID == IDS_EE_HWINTRINSIC_NGEN_DISALLOWED)
+ {
+ // Supress printing of "Hardware intrinsics may not be used with ngen."
+ level = CORZAP_LOGLEVEL_INFO;
+ }
+
#ifdef CROSSGEN_COMPILE
if ((resID == IDS_IBC_MISSING_EXTERNAL_TYPE) ||
(resID == IDS_IBC_MISSING_EXTERNAL_METHOD))
diff --git a/tests/src/Common/test_dependencies/test_dependencies.csproj b/tests/src/Common/test_dependencies/test_dependencies.csproj
index 9eefab2f10ca..1e34f8a3dfe0 100644
--- a/tests/src/Common/test_dependencies/test_dependencies.csproj
+++ b/tests/src/Common/test_dependencies/test_dependencies.csproj
@@ -22,6 +22,9 @@
$(CoreFxPackageVersion)
+
+ $(CoreFxPackageVersion)
+
netcoreapp2.1
diff --git a/tests/src/JIT/HardwareIntrinsics/IsSupported.cs b/tests/src/JIT/HardwareIntrinsics/IsSupported.cs
new file mode 100644
index 000000000000..7e92f189c42b
--- /dev/null
+++ b/tests/src/JIT/HardwareIntrinsics/IsSupported.cs
@@ -0,0 +1,114 @@
+// 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;
+using System.Runtime.Intrinsics.X86;
+using System.Numerics;
+
+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 (Vector.Count == 32 && !Avx2.IsSupported)
+ {
+ result = false;
+ }
+
+ if (Vector.Count == 16 && Vector.IsHardwareAccelerated && !Sse2.IsSupported)
+ {
+ 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;
+ }
+ }
+
+ // Reflection call
+ var issupported = "get_IsSupported";
+ if (Convert.ToBoolean(typeof(Sse).GetMethod(issupported).Invoke(null, null)) != Sse.IsSupported ||
+ Convert.ToBoolean(typeof(Sse2).GetMethod(issupported).Invoke(null, null)) != Sse2.IsSupported ||
+ Convert.ToBoolean(typeof(Sse3).GetMethod(issupported).Invoke(null, null)) != Sse3.IsSupported ||
+ Convert.ToBoolean(typeof(Ssse3).GetMethod(issupported).Invoke(null, null)) != Ssse3.IsSupported ||
+ Convert.ToBoolean(typeof(Sse41).GetMethod(issupported).Invoke(null, null)) != Sse41.IsSupported ||
+ Convert.ToBoolean(typeof(Sse42).GetMethod(issupported).Invoke(null, null)) != Sse42.IsSupported ||
+ Convert.ToBoolean(typeof(Aes).GetMethod(issupported).Invoke(null, null)) != Aes.IsSupported ||
+ Convert.ToBoolean(typeof(Avx).GetMethod(issupported).Invoke(null, null)) != Avx.IsSupported ||
+ Convert.ToBoolean(typeof(Avx2).GetMethod(issupported).Invoke(null, null)) != Avx2.IsSupported ||
+ Convert.ToBoolean(typeof(Fma).GetMethod(issupported).Invoke(null, null)) != Fma.IsSupported ||
+ Convert.ToBoolean(typeof(Lzcnt).GetMethod(issupported).Invoke(null, null)) != Lzcnt.IsSupported ||
+ Convert.ToBoolean(typeof(Bmi1).GetMethod(issupported).Invoke(null, null)) != Bmi1.IsSupported ||
+ Convert.ToBoolean(typeof(Bmi2).GetMethod(issupported).Invoke(null, null)) != Bmi2.IsSupported ||
+ Convert.ToBoolean(typeof(Popcnt).GetMethod(issupported).Invoke(null, null)) != Popcnt.IsSupported ||
+ Convert.ToBoolean(typeof(Pclmulqdq).GetMethod(issupported).Invoke(null, null)) != Pclmulqdq.IsSupported
+ )
+ {
+ result = false;
+ }
+ return result ? 100 : 0;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/tests/src/JIT/HardwareIntrinsics/IsSupported_r.csproj b/tests/src/JIT/HardwareIntrinsics/IsSupported_r.csproj
new file mode 100644
index 000000000000..e77c5dc2ad4a
--- /dev/null
+++ b/tests/src/JIT/HardwareIntrinsics/IsSupported_r.csproj
@@ -0,0 +1,33 @@
+
+
+
+
+ Debug
+ AnyCPU
+ 2.0
+ {95DFC527-4DC1-495E-97D7-E94EE1F7140D}
+ Exe
+ {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ ..\..\
+
+
+
+
+
+
+ False
+
+
+
+ None
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/src/JIT/HardwareIntrinsics/IsSupported_ro.csproj b/tests/src/JIT/HardwareIntrinsics/IsSupported_ro.csproj
new file mode 100644
index 000000000000..e8f88b5a40e6
--- /dev/null
+++ b/tests/src/JIT/HardwareIntrinsics/IsSupported_ro.csproj
@@ -0,0 +1,33 @@
+
+
+
+
+ Debug
+ AnyCPU
+ 2.0
+ {95DFC527-4DC1-495E-97D7-E94EE1F7140D}
+ Exe
+ {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ ..\..\
+
+
+
+
+
+
+ False
+
+
+
+ None
+ True
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file