#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 }
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
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()
simdcodegenxarch.cpp
targetamd64.cpp
unwindamd64.cpp
+ hwintrinsicxarch.cpp
)
set( JIT_ARM_SOURCES
simdcodegenxarch.cpp
targetx86.cpp
unwindx86.cpp
+ hwintrinsicxarch.cpp
)
set( JIT_ARM64_SOURCES
#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
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,
#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
--- /dev/null
+// 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
--- /dev/null
+// 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
{
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:
}
}
+#ifdef _TARGET_XARCH_
+ if ((namespaceName != nullptr) && strcmp(namespaceName, "System.Runtime.Intrinsics.X86") == 0)
+ {
+ InstructionSet isa = lookupHWIntrinsicISA(className);
+ result = lookupHWIntrinsic(methodName, isa);
+ }
+#endif
return result;
}
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
<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" />
#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
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
}
// 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_
// 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)
// 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.
// 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);
}
}
}
}
+ (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)
{
{
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());
<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>
--- /dev/null
+// 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
--- /dev/null
+<?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