resultflags.RemoveInstructionSet(InstructionSet_X86Serialize);
if (resultflags.HasInstructionSet(InstructionSet_AVX512F) && !resultflags.HasInstructionSet(InstructionSet_AVX2))
resultflags.RemoveInstructionSet(InstructionSet_AVX512F);
+ if (resultflags.HasInstructionSet(InstructionSet_AVX512F) && !resultflags.HasInstructionSet(InstructionSet_FMA))
+ resultflags.RemoveInstructionSet(InstructionSet_AVX512F);
if (resultflags.HasInstructionSet(InstructionSet_AVX512F_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F))
resultflags.RemoveInstructionSet(InstructionSet_AVX512F_VL);
if (resultflags.HasInstructionSet(InstructionSet_AVX512CD) && !resultflags.HasInstructionSet(InstructionSet_AVX512F))
resultflags.RemoveInstructionSet(InstructionSet_AVX512CD);
+ if (resultflags.HasInstructionSet(InstructionSet_AVX512CD_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512CD))
+ resultflags.RemoveInstructionSet(InstructionSet_AVX512CD_VL);
if (resultflags.HasInstructionSet(InstructionSet_AVX512CD_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F_VL))
resultflags.RemoveInstructionSet(InstructionSet_AVX512CD_VL);
if (resultflags.HasInstructionSet(InstructionSet_AVX512BW) && !resultflags.HasInstructionSet(InstructionSet_AVX512F))
resultflags.RemoveInstructionSet(InstructionSet_AVX512BW);
+ if (resultflags.HasInstructionSet(InstructionSet_AVX512BW_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512BW))
+ resultflags.RemoveInstructionSet(InstructionSet_AVX512BW_VL);
if (resultflags.HasInstructionSet(InstructionSet_AVX512BW_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F_VL))
resultflags.RemoveInstructionSet(InstructionSet_AVX512BW_VL);
if (resultflags.HasInstructionSet(InstructionSet_AVX512DQ) && !resultflags.HasInstructionSet(InstructionSet_AVX512F))
resultflags.RemoveInstructionSet(InstructionSet_AVX512DQ);
+ if (resultflags.HasInstructionSet(InstructionSet_AVX512DQ_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512DQ))
+ resultflags.RemoveInstructionSet(InstructionSet_AVX512DQ_VL);
if (resultflags.HasInstructionSet(InstructionSet_AVX512DQ_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F_VL))
resultflags.RemoveInstructionSet(InstructionSet_AVX512DQ_VL);
if (resultflags.HasInstructionSet(InstructionSet_AVX512VBMI) && !resultflags.HasInstructionSet(InstructionSet_AVX512BW))
resultflags.RemoveInstructionSet(InstructionSet_AVX512VBMI);
+ if (resultflags.HasInstructionSet(InstructionSet_AVX512VBMI_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512VBMI))
+ resultflags.RemoveInstructionSet(InstructionSet_AVX512VBMI_VL);
if (resultflags.HasInstructionSet(InstructionSet_AVX512VBMI_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512BW_VL))
resultflags.RemoveInstructionSet(InstructionSet_AVX512VBMI_VL);
+ if (resultflags.HasInstructionSet(InstructionSet_AVX512F) && !resultflags.HasInstructionSet(InstructionSet_AVX512BW_VL))
+ resultflags.RemoveInstructionSet(InstructionSet_AVX512F);
+ if (resultflags.HasInstructionSet(InstructionSet_AVX512F) && !resultflags.HasInstructionSet(InstructionSet_AVX512CD_VL))
+ resultflags.RemoveInstructionSet(InstructionSet_AVX512F);
+ if (resultflags.HasInstructionSet(InstructionSet_AVX512F) && !resultflags.HasInstructionSet(InstructionSet_AVX512DQ_VL))
+ resultflags.RemoveInstructionSet(InstructionSet_AVX512F);
#endif // TARGET_AMD64
#ifdef TARGET_X86
if (resultflags.HasInstructionSet(InstructionSet_SSE) && !resultflags.HasInstructionSet(InstructionSet_X86Base))
resultflags.RemoveInstructionSet(InstructionSet_X86Serialize);
if (resultflags.HasInstructionSet(InstructionSet_AVX512F) && !resultflags.HasInstructionSet(InstructionSet_AVX2))
resultflags.RemoveInstructionSet(InstructionSet_AVX512F);
+ if (resultflags.HasInstructionSet(InstructionSet_AVX512F) && !resultflags.HasInstructionSet(InstructionSet_FMA))
+ resultflags.RemoveInstructionSet(InstructionSet_AVX512F);
if (resultflags.HasInstructionSet(InstructionSet_AVX512F_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F))
resultflags.RemoveInstructionSet(InstructionSet_AVX512F_VL);
if (resultflags.HasInstructionSet(InstructionSet_AVX512CD) && !resultflags.HasInstructionSet(InstructionSet_AVX512F))
resultflags.RemoveInstructionSet(InstructionSet_AVX512CD);
+ if (resultflags.HasInstructionSet(InstructionSet_AVX512CD_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512CD))
+ resultflags.RemoveInstructionSet(InstructionSet_AVX512CD_VL);
if (resultflags.HasInstructionSet(InstructionSet_AVX512CD_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F_VL))
resultflags.RemoveInstructionSet(InstructionSet_AVX512CD_VL);
if (resultflags.HasInstructionSet(InstructionSet_AVX512BW) && !resultflags.HasInstructionSet(InstructionSet_AVX512F))
resultflags.RemoveInstructionSet(InstructionSet_AVX512BW);
+ if (resultflags.HasInstructionSet(InstructionSet_AVX512BW_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512BW))
+ resultflags.RemoveInstructionSet(InstructionSet_AVX512BW_VL);
if (resultflags.HasInstructionSet(InstructionSet_AVX512BW_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F_VL))
resultflags.RemoveInstructionSet(InstructionSet_AVX512BW_VL);
if (resultflags.HasInstructionSet(InstructionSet_AVX512DQ) && !resultflags.HasInstructionSet(InstructionSet_AVX512F))
resultflags.RemoveInstructionSet(InstructionSet_AVX512DQ);
+ if (resultflags.HasInstructionSet(InstructionSet_AVX512DQ_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512DQ))
+ resultflags.RemoveInstructionSet(InstructionSet_AVX512DQ_VL);
if (resultflags.HasInstructionSet(InstructionSet_AVX512DQ_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F_VL))
resultflags.RemoveInstructionSet(InstructionSet_AVX512DQ_VL);
if (resultflags.HasInstructionSet(InstructionSet_AVX512VBMI) && !resultflags.HasInstructionSet(InstructionSet_AVX512BW))
resultflags.RemoveInstructionSet(InstructionSet_AVX512VBMI);
+ if (resultflags.HasInstructionSet(InstructionSet_AVX512VBMI_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512VBMI))
+ resultflags.RemoveInstructionSet(InstructionSet_AVX512VBMI_VL);
if (resultflags.HasInstructionSet(InstructionSet_AVX512VBMI_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512BW_VL))
resultflags.RemoveInstructionSet(InstructionSet_AVX512VBMI_VL);
+ if (resultflags.HasInstructionSet(InstructionSet_AVX512F) && !resultflags.HasInstructionSet(InstructionSet_AVX512BW_VL))
+ resultflags.RemoveInstructionSet(InstructionSet_AVX512F);
+ if (resultflags.HasInstructionSet(InstructionSet_AVX512F) && !resultflags.HasInstructionSet(InstructionSet_AVX512CD_VL))
+ resultflags.RemoveInstructionSet(InstructionSet_AVX512F);
+ if (resultflags.HasInstructionSet(InstructionSet_AVX512F) && !resultflags.HasInstructionSet(InstructionSet_AVX512DQ_VL))
+ resultflags.RemoveInstructionSet(InstructionSet_AVX512F);
#endif // TARGET_X86
} while (!oldflags.Equals(resultflags));
#define GUID_DEFINED
#endif // !GUID_DEFINED
-constexpr GUID JITEEVersionIdentifier = { /* dfc41bc9-f134-4c50-897e-fc9304a82059 */
- 0xdfc41bc9,
- 0xf134,
- 0x4c50,
- {0x89, 0x7e, 0xfc, 0x93, 0x04, 0xa8, 0x20, 0x59}
+constexpr GUID JITEEVersionIdentifier = { /* d4414be1-70e4-46ac-8866-ca3a6c2f8422 */
+ 0xd4414be1,
+ 0x70e4,
+ 0x46ac,
+ {0x88, 0x66, 0xca, 0x3a, 0x6c, 0x2f, 0x84, 0x22}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// the overall JIT implementation, we currently require the entire set of ISAs to be
// supported and disable AVX512 support otherwise.
- if (instructionSetFlags.HasInstructionSet(InstructionSet_AVX512BW_VL) &&
- instructionSetFlags.HasInstructionSet(InstructionSet_AVX512CD_VL) &&
- instructionSetFlags.HasInstructionSet(InstructionSet_AVX512DQ_VL))
+ if (instructionSetFlags.HasInstructionSet(InstructionSet_AVX512F))
{
+ assert(instructionSetFlags.HasInstructionSet(InstructionSet_AVX512F));
+ assert(instructionSetFlags.HasInstructionSet(InstructionSet_AVX512F_VL));
assert(instructionSetFlags.HasInstructionSet(InstructionSet_AVX512BW));
+ assert(instructionSetFlags.HasInstructionSet(InstructionSet_AVX512BW_VL));
assert(instructionSetFlags.HasInstructionSet(InstructionSet_AVX512CD));
+ assert(instructionSetFlags.HasInstructionSet(InstructionSet_AVX512CD_VL));
assert(instructionSetFlags.HasInstructionSet(InstructionSet_AVX512DQ));
- assert(instructionSetFlags.HasInstructionSet(InstructionSet_AVX512F));
- assert(instructionSetFlags.HasInstructionSet(InstructionSet_AVX512F_VL));
+ assert(instructionSetFlags.HasInstructionSet(InstructionSet_AVX512DQ_VL));
instructionSetFlags.AddInstructionSet(InstructionSet_Vector512);
preferredVectorByteLength = 256 / 8;
}
}
- else
- {
- instructionSetFlags.RemoveInstructionSet(InstructionSet_AVX512F);
- instructionSetFlags.RemoveInstructionSet(InstructionSet_AVX512F_VL);
- instructionSetFlags.RemoveInstructionSet(InstructionSet_AVX512BW);
- instructionSetFlags.RemoveInstructionSet(InstructionSet_AVX512BW_VL);
- instructionSetFlags.RemoveInstructionSet(InstructionSet_AVX512CD);
- instructionSetFlags.RemoveInstructionSet(InstructionSet_AVX512CD_VL);
- instructionSetFlags.RemoveInstructionSet(InstructionSet_AVX512DQ);
- instructionSetFlags.RemoveInstructionSet(InstructionSet_AVX512DQ_VL);
- instructionSetFlags.RemoveInstructionSet(InstructionSet_AVX512VBMI);
- instructionSetFlags.RemoveInstructionSet(InstructionSet_AVX512VBMI_VL);
-
-#ifdef TARGET_AMD64
- instructionSetFlags.RemoveInstructionSet(InstructionSet_AVX512F_X64);
- instructionSetFlags.RemoveInstructionSet(InstructionSet_AVX512F_VL_X64);
- instructionSetFlags.RemoveInstructionSet(InstructionSet_AVX512BW_X64);
- instructionSetFlags.RemoveInstructionSet(InstructionSet_AVX512BW_VL_X64);
- instructionSetFlags.RemoveInstructionSet(InstructionSet_AVX512CD_X64);
- instructionSetFlags.RemoveInstructionSet(InstructionSet_AVX512CD_VL_X64);
- instructionSetFlags.RemoveInstructionSet(InstructionSet_AVX512DQ_X64);
- instructionSetFlags.RemoveInstructionSet(InstructionSet_AVX512DQ_VL_X64);
- instructionSetFlags.RemoveInstructionSet(InstructionSet_AVX512VBMI_X64);
- instructionSetFlags.RemoveInstructionSet(InstructionSet_AVX512VBMI_VL_X64);
-#endif // TARGET_AMD64
- }
opts.preferredVectorByteLength = preferredVectorByteLength;
#elif defined(TARGET_ARM64)
// Get the number of bytes in a System.Numeric.Vector<T> for the current compilation.
// Note - cannot be used for System.Runtime.Intrinsic
- unsigned getVectorTByteLength()
+ uint32_t getVectorTByteLength()
{
// We need to report the ISA dependency to the VM so that scenarios
// such as R2R work correctly for larger vector sizes, so we always
return NI_Illegal;
}
- bool isIsaSupported = comp->compSupportsHWIntrinsic(isa);
-
+ bool isIsaSupported = comp->compSupportsHWIntrinsic(isa);
bool isHardwareAcceleratedProp = (strcmp(methodName, "get_IsHardwareAccelerated") == 0);
+
#ifdef TARGET_XARCH
if (isHardwareAcceleratedProp)
{
//
// When the target hardware does support the instruction set, we can return a
// constant true. When it doesn't then we want to report the check as dynamically
- // supported instead. This allows some targets, such as AOT, to emit a check against
- // a cached CPU query so lightup can still happen (such as for SSE4.1 when the target
- // hardware is SSE2).
+ // supported instead if the opportunistic support does exist. This allows some targets,
+ // such as AOT, to emit a check against a cached CPU query so lightup can still happen
+ // (such as for SSE4.1 when the target hardware is SSE2).
//
// When the compiler doesn't support ISA or when it does but the target hardware does
// not and we aren't in a scenario with support for a dynamic check, we want to return false.
- if (isIsaSupported)
+ if (isIsaSupported && comp->compSupportsHWIntrinsic(isa))
{
- if (comp->compExactlyDependsOn(isa))
+ if (!comp->IsTargetAbi(CORINFO_NATIVEAOT_ABI) || comp->compExactlyDependsOn(isa))
{
return NI_IsSupported_True;
}
-
- if (comp->IsTargetAbi(CORINFO_NATIVEAOT_ABI))
+ else
{
+ assert(comp->IsTargetAbi(CORINFO_NATIVEAOT_ABI));
return NI_IsSupported_Dynamic;
}
}
XArchIntrinsicConstants_Avx512dq_vl = 0x400000,
XArchIntrinsicConstants_Avx512Vbmi = 0x800000,
XArchIntrinsicConstants_Avx512Vbmi_vl = 0x1000000,
+ XArchIntrinsicConstants_Serialize = 0x2000000,
};
#endif //HOST_X86 || HOST_AMD64
{
__cpuid(cpuidInfo, 0x00000001);
- if (((cpuidInfo[CPUID_EDX] & (1 << 25)) != 0) && ((cpuidInfo[CPUID_EDX] & (1 << 26)) != 0)) // SSE & SSE2
+ const int requiredBaselineEdxFlags = (1 << 25) // SSE
+ | (1 << 26); // SSE2
+
+ if ((cpuidInfo[CPUID_EDX] & requiredBaselineEdxFlags) == requiredBaselineEdxFlags)
{
- if ((cpuidInfo[CPUID_ECX] & (1 << 25)) != 0) // AESNI
+ if ((cpuidInfo[CPUID_ECX] & (1 << 25)) != 0) // AESNI
{
g_cpuFeatures |= XArchIntrinsicConstants_Aes;
}
- if ((cpuidInfo[CPUID_ECX] & (1 << 1)) != 0) // PCLMULQDQ
+ if ((cpuidInfo[CPUID_ECX] & (1 << 1)) != 0) // PCLMULQDQ
{
g_cpuFeatures |= XArchIntrinsicConstants_Pclmulqdq;
}
- if ((cpuidInfo[CPUID_ECX] & (1 << 0)) != 0) // SSE3
+ if ((cpuidInfo[CPUID_ECX] & (1 << 0)) != 0) // SSE3
{
g_cpuFeatures |= XArchIntrinsicConstants_Sse3;
- if ((cpuidInfo[CPUID_ECX] & (1 << 9)) != 0) // SSSE3
+ if ((cpuidInfo[CPUID_ECX] & (1 << 9)) != 0) // SSSE3
{
g_cpuFeatures |= XArchIntrinsicConstants_Ssse3;
- if ((cpuidInfo[CPUID_ECX] & (1 << 19)) != 0) // SSE4.1
+ if ((cpuidInfo[CPUID_ECX] & (1 << 19)) != 0) // SSE4.1
{
g_cpuFeatures |= XArchIntrinsicConstants_Sse41;
- if ((cpuidInfo[CPUID_ECX] & (1 << 20)) != 0) // SSE4.2
+ if ((cpuidInfo[CPUID_ECX] & (1 << 20)) != 0) // SSE4.2
{
g_cpuFeatures |= XArchIntrinsicConstants_Sse42;
- if ((cpuidInfo[CPUID_ECX] & (1 << 22)) != 0) // MOVBE
+ if ((cpuidInfo[CPUID_ECX] & (1 << 22)) != 0) // MOVBE
{
g_cpuFeatures |= XArchIntrinsicConstants_Movbe;
}
- if ((cpuidInfo[CPUID_ECX] & (1 << 23)) != 0) // POPCNT
+ if ((cpuidInfo[CPUID_ECX] & (1 << 23)) != 0) // POPCNT
{
g_cpuFeatures |= XArchIntrinsicConstants_Popcnt;
}
- if (((cpuidInfo[CPUID_ECX] & (1 << 27)) != 0) && ((cpuidInfo[CPUID_ECX] & (1 << 28)) != 0)) // OSXSAVE & AVX
+ const int requiredAvxEcxFlags = (1 << 27) // OSXSAVE
+ | (1 << 28); // AVX
+
+ if ((cpuidInfo[CPUID_ECX] & requiredAvxEcxFlags) == requiredAvxEcxFlags)
{
- if (PalIsAvxEnabled() && (xmmYmmStateSupport() == 1))
+ if (PalIsAvxEnabled() && (xmmYmmStateSupport() == 1)) // XGETBV == 11
{
g_cpuFeatures |= XArchIntrinsicConstants_Avx;
- if ((cpuidInfo[CPUID_ECX] & (1 << 12)) != 0) // FMA
+ if ((cpuidInfo[CPUID_ECX] & (1 << 12)) != 0) // FMA
{
g_cpuFeatures |= XArchIntrinsicConstants_Fma;
}
{
__cpuidex(cpuidInfo, 0x00000007, 0x00000000);
- if ((cpuidInfo[CPUID_EBX] & (1 << 5)) != 0) // AVX2
+ if ((cpuidInfo[CPUID_EBX] & (1 << 5)) != 0) // AVX2
{
g_cpuFeatures |= XArchIntrinsicConstants_Avx2;
- __cpuidex(cpuidInfo, 0x00000007, 0x00000001);
- if ((cpuidInfo[CPUID_EAX] & (1 << 4)) != 0) // AVX-VNNI
- {
- g_cpuFeatures |= XArchIntrinsicConstants_AvxVnni;
- }
-
- if (PalIsAvx512Enabled() && (avx512StateSupport() == 1)) // XGETBV XRC0[7:5] == 111
+ if (PalIsAvx512Enabled() && (avx512StateSupport() == 1)) // XGETBV XRC0[7:5] == 111
{
- if ((cpuidInfo[CPUID_EBX] & (1 << 16)) != 0) // AVX512F
+ if ((cpuidInfo[CPUID_EBX] & (1 << 16)) != 0) // AVX512F
{
g_cpuFeatures |= XArchIntrinsicConstants_Avx512f;
bool isAVX512_VLSupported = false;
- if ((cpuidInfo[CPUID_EBX] & (1 << 31)) != 0) // AVX512VL
+ if ((cpuidInfo[CPUID_EBX] & (1 << 31)) != 0) // AVX512VL
{
g_cpuFeatures |= XArchIntrinsicConstants_Avx512f_vl;
isAVX512_VLSupported = true;
}
- if ((cpuidInfo[CPUID_EBX] & (1 << 30)) != 0) // AVX512BW
+ if ((cpuidInfo[CPUID_EBX] & (1 << 30)) != 0) // AVX512BW
{
g_cpuFeatures |= XArchIntrinsicConstants_Avx512bw;
- if (isAVX512_VLSupported)
+ if (isAVX512_VLSupported) // AVX512BW_VL
{
g_cpuFeatures |= XArchIntrinsicConstants_Avx512bw_vl;
}
}
- if ((cpuidInfo[CPUID_EBX] & (1 << 28)) != 0) // AVX512CD
+ if ((cpuidInfo[CPUID_EBX] & (1 << 28)) != 0) // AVX512CD
{
g_cpuFeatures |= XArchIntrinsicConstants_Avx512cd;
- if (isAVX512_VLSupported)
+ if (isAVX512_VLSupported) // AVX512CD_VL
{
g_cpuFeatures |= XArchIntrinsicConstants_Avx512cd_vl;
}
}
- if ((cpuidInfo[CPUID_EBX] & (1 << 17)) != 0) // AVX512DQ
+ if ((cpuidInfo[CPUID_EBX] & (1 << 17)) != 0) // AVX512DQ
{
g_cpuFeatures |= XArchIntrinsicConstants_Avx512dq;
- if (isAVX512_VLSupported)
+ if (isAVX512_VLSupported) // AVX512DQ_VL
{
g_cpuFeatures |= XArchIntrinsicConstants_Avx512dq_vl;
}
}
- if ((cpuidInfo[CPUID_ECX] & (1 << 1)) != 0) // AVX512VBMI
+ if ((cpuidInfo[CPUID_ECX] & (1 << 1)) != 0) // AVX512VBMI
{
g_cpuFeatures |= XArchIntrinsicConstants_Avx512Vbmi;
- if (isAVX512_VLSupported)
+ if (isAVX512_VLSupported) // AVX512VBMI_VL
{
g_cpuFeatures |= XArchIntrinsicConstants_Avx512Vbmi_vl;
}
}
}
}
+
+ __cpuidex(cpuidInfo, 0x00000007, 0x00000001);
+
+ if ((cpuidInfo[CPUID_EAX] & (1 << 4)) != 0) // AVX-VNNI
+ {
+ g_cpuFeatures |= XArchIntrinsicConstants_AvxVnni;
+ }
}
}
}
{
g_cpuFeatures |= XArchIntrinsicConstants_Bmi2;
}
+
+ if ((cpuidInfo[CPUID_EDX] & (1 << 14)) != 0)
+ {
+ g_cpuFeatures |= XArchIntrinsicConstants_Serialize; // SERIALIZE
+ }
}
}
optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("movbe");
optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("popcnt");
optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("lzcnt");
+ optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("serialize");
// If AVX was enabled, we can opportunistically enable instruction sets which use the VEX encodings
Debug.Assert(InstructionSet.X64_AVX == InstructionSet.X86_AVX);
if (supportedInstructionSet.HasInstructionSet(InstructionSet.X64_AVX))
{
+ // TODO: Enable optimistic usage of AVX2 once we validate it doesn't break Vector<T> usage
+ // optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("avx2");
+
+ if (supportedInstructionSet.HasInstructionSet(InstructionSet.X64_AVX2))
+ {
+ optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("avxvnni");
+ }
+
optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("fma");
optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("bmi");
optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("bmi2");
- optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("avxvnni");
+ }
+
+ if (supportedInstructionSet.HasInstructionSet(InstructionSet.X64_AVX2))
+ {
+ }
+
+ Debug.Assert(InstructionSet.X64_AVX512F == InstructionSet.X86_AVX512F);
+ if (supportedInstructionSet.HasInstructionSet(InstructionSet.X64_AVX512F))
+ {
+ Debug.Assert(supportedInstructionSet.HasInstructionSet(InstructionSet.X64_AVX512F_VL));
+ Debug.Assert(supportedInstructionSet.HasInstructionSet(InstructionSet.X64_AVX512BW));
+ Debug.Assert(supportedInstructionSet.HasInstructionSet(InstructionSet.X64_AVX512BW_VL));
+ Debug.Assert(supportedInstructionSet.HasInstructionSet(InstructionSet.X64_AVX512CD));
+ Debug.Assert(supportedInstructionSet.HasInstructionSet(InstructionSet.X64_AVX512CD_VL));
+ Debug.Assert(supportedInstructionSet.HasInstructionSet(InstructionSet.X64_AVX512DQ));
+ Debug.Assert(supportedInstructionSet.HasInstructionSet(InstructionSet.X64_AVX512DQ_VL));
+
+ optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("avx512vbmi");
+ optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("avx512vbmi_vl");
}
}
else if (targetArchitecture == TargetArchitecture.ARM64)
optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("sha1");
optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("sha2");
optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("lse");
+ optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("dotprod");
+ optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("rdma");
+ optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("rcpc");
}
optimisticInstructionSetSupportBuilder.ComputeInstructionSetFlags(out var optimisticInstructionSet, out _,
resultflags.AddInstructionSet(InstructionSet.X64_X86Base);
if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F))
resultflags.AddInstructionSet(InstructionSet.X64_AVX2);
+ if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F))
+ resultflags.AddInstructionSet(InstructionSet.X64_FMA);
if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F_VL))
resultflags.AddInstructionSet(InstructionSet.X64_AVX512F);
if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512CD))
resultflags.AddInstructionSet(InstructionSet.X64_AVX512F);
if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512CD_VL))
+ resultflags.AddInstructionSet(InstructionSet.X64_AVX512CD);
+ if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512CD_VL))
resultflags.AddInstructionSet(InstructionSet.X64_AVX512F_VL);
if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512BW))
resultflags.AddInstructionSet(InstructionSet.X64_AVX512F);
if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512BW_VL))
+ resultflags.AddInstructionSet(InstructionSet.X64_AVX512BW);
+ if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512BW_VL))
resultflags.AddInstructionSet(InstructionSet.X64_AVX512F_VL);
if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512DQ))
resultflags.AddInstructionSet(InstructionSet.X64_AVX512F);
if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512DQ_VL))
+ resultflags.AddInstructionSet(InstructionSet.X64_AVX512DQ);
+ if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512DQ_VL))
resultflags.AddInstructionSet(InstructionSet.X64_AVX512F_VL);
if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512VBMI))
resultflags.AddInstructionSet(InstructionSet.X64_AVX512BW);
if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512VBMI_VL))
+ resultflags.AddInstructionSet(InstructionSet.X64_AVX512VBMI);
+ if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512VBMI_VL))
+ resultflags.AddInstructionSet(InstructionSet.X64_AVX512BW_VL);
+ if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F))
resultflags.AddInstructionSet(InstructionSet.X64_AVX512BW_VL);
+ if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F))
+ resultflags.AddInstructionSet(InstructionSet.X64_AVX512CD_VL);
+ if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F))
+ resultflags.AddInstructionSet(InstructionSet.X64_AVX512DQ_VL);
break;
case TargetArchitecture.X86:
resultflags.AddInstructionSet(InstructionSet.X86_X86Base);
if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F))
resultflags.AddInstructionSet(InstructionSet.X86_AVX2);
+ if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F))
+ resultflags.AddInstructionSet(InstructionSet.X86_FMA);
if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F_VL))
resultflags.AddInstructionSet(InstructionSet.X86_AVX512F);
if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512CD))
resultflags.AddInstructionSet(InstructionSet.X86_AVX512F);
if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512CD_VL))
+ resultflags.AddInstructionSet(InstructionSet.X86_AVX512CD);
+ if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512CD_VL))
resultflags.AddInstructionSet(InstructionSet.X86_AVX512F_VL);
if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512BW))
resultflags.AddInstructionSet(InstructionSet.X86_AVX512F);
if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512BW_VL))
+ resultflags.AddInstructionSet(InstructionSet.X86_AVX512BW);
+ if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512BW_VL))
resultflags.AddInstructionSet(InstructionSet.X86_AVX512F_VL);
if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512DQ))
resultflags.AddInstructionSet(InstructionSet.X86_AVX512F);
if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512DQ_VL))
+ resultflags.AddInstructionSet(InstructionSet.X86_AVX512DQ);
+ if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512DQ_VL))
resultflags.AddInstructionSet(InstructionSet.X86_AVX512F_VL);
if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512VBMI))
resultflags.AddInstructionSet(InstructionSet.X86_AVX512BW);
if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512VBMI_VL))
+ resultflags.AddInstructionSet(InstructionSet.X86_AVX512VBMI);
+ if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512VBMI_VL))
+ resultflags.AddInstructionSet(InstructionSet.X86_AVX512BW_VL);
+ if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F))
resultflags.AddInstructionSet(InstructionSet.X86_AVX512BW_VL);
+ if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F))
+ resultflags.AddInstructionSet(InstructionSet.X86_AVX512CD_VL);
+ if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F))
+ resultflags.AddInstructionSet(InstructionSet.X86_AVX512DQ_VL);
break;
}
} while (!oldflags.Equals(resultflags));
resultflags.AddInstructionSet(InstructionSet.X64_X86Serialize);
if (resultflags.HasInstructionSet(InstructionSet.X64_AVX2))
resultflags.AddInstructionSet(InstructionSet.X64_AVX512F);
+ if (resultflags.HasInstructionSet(InstructionSet.X64_FMA))
+ resultflags.AddInstructionSet(InstructionSet.X64_AVX512F);
if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F))
resultflags.AddInstructionSet(InstructionSet.X64_AVX512F_VL);
if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F))
resultflags.AddInstructionSet(InstructionSet.X64_AVX512CD);
+ if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512CD))
+ resultflags.AddInstructionSet(InstructionSet.X64_AVX512CD_VL);
if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F_VL))
resultflags.AddInstructionSet(InstructionSet.X64_AVX512CD_VL);
if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F))
resultflags.AddInstructionSet(InstructionSet.X64_AVX512BW);
+ if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512BW))
+ resultflags.AddInstructionSet(InstructionSet.X64_AVX512BW_VL);
if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F_VL))
resultflags.AddInstructionSet(InstructionSet.X64_AVX512BW_VL);
if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F))
resultflags.AddInstructionSet(InstructionSet.X64_AVX512DQ);
+ if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512DQ))
+ resultflags.AddInstructionSet(InstructionSet.X64_AVX512DQ_VL);
if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F_VL))
resultflags.AddInstructionSet(InstructionSet.X64_AVX512DQ_VL);
if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512BW))
resultflags.AddInstructionSet(InstructionSet.X64_AVX512VBMI);
+ if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512VBMI))
+ resultflags.AddInstructionSet(InstructionSet.X64_AVX512VBMI_VL);
if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512BW_VL))
resultflags.AddInstructionSet(InstructionSet.X64_AVX512VBMI_VL);
+ if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512BW_VL))
+ resultflags.AddInstructionSet(InstructionSet.X64_AVX512F);
+ if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512CD_VL))
+ resultflags.AddInstructionSet(InstructionSet.X64_AVX512F);
+ if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512DQ_VL))
+ resultflags.AddInstructionSet(InstructionSet.X64_AVX512F);
break;
case TargetArchitecture.X86:
resultflags.AddInstructionSet(InstructionSet.X86_X86Serialize);
if (resultflags.HasInstructionSet(InstructionSet.X86_AVX2))
resultflags.AddInstructionSet(InstructionSet.X86_AVX512F);
+ if (resultflags.HasInstructionSet(InstructionSet.X86_FMA))
+ resultflags.AddInstructionSet(InstructionSet.X86_AVX512F);
if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F))
resultflags.AddInstructionSet(InstructionSet.X86_AVX512F_VL);
if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F))
resultflags.AddInstructionSet(InstructionSet.X86_AVX512CD);
+ if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512CD))
+ resultflags.AddInstructionSet(InstructionSet.X86_AVX512CD_VL);
if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F_VL))
resultflags.AddInstructionSet(InstructionSet.X86_AVX512CD_VL);
if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F))
resultflags.AddInstructionSet(InstructionSet.X86_AVX512BW);
+ if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512BW))
+ resultflags.AddInstructionSet(InstructionSet.X86_AVX512BW_VL);
if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F_VL))
resultflags.AddInstructionSet(InstructionSet.X86_AVX512BW_VL);
if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F))
resultflags.AddInstructionSet(InstructionSet.X86_AVX512DQ);
+ if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512DQ))
+ resultflags.AddInstructionSet(InstructionSet.X86_AVX512DQ_VL);
if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F_VL))
resultflags.AddInstructionSet(InstructionSet.X86_AVX512DQ_VL);
if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512BW))
resultflags.AddInstructionSet(InstructionSet.X86_AVX512VBMI);
+ if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512VBMI))
+ resultflags.AddInstructionSet(InstructionSet.X86_AVX512VBMI_VL);
if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512BW_VL))
resultflags.AddInstructionSet(InstructionSet.X86_AVX512VBMI_VL);
+ if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512BW_VL))
+ resultflags.AddInstructionSet(InstructionSet.X86_AVX512F);
+ if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512CD_VL))
+ resultflags.AddInstructionSet(InstructionSet.X86_AVX512F);
+ if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512DQ_VL))
+ resultflags.AddInstructionSet(InstructionSet.X86_AVX512F);
break;
}
} while (!oldflags.Equals(resultflags));
{ ("x86-x64-v3", TargetArchitecture.X86), "x86-x64-v2 avx2 bmi bmi2 lzcnt movbe fma" },
{ ("skylake", TargetArchitecture.X64), "x86-x64-v3" },
{ ("skylake", TargetArchitecture.X86), "x86-x64-v3" },
- { ("x86-x64-v4", TargetArchitecture.X64), "x86-x64-v3 avx512f avx512f_vl avx512bw avx512bw_vl avx512cd avx512cd_vl" },
- { ("x86-x64-v4", TargetArchitecture.X86), "x86-x64-v3 avx512f avx512f_vl avx512bw avx512bw_vl avx512cd avx512cd_vl" },
+ { ("x86-x64-v4", TargetArchitecture.X64), "x86-x64-v3 avx512f avx512f_vl avx512bw avx512bw_vl avx512cd avx512cd_vl avx512dq avx512dq_vl" },
+ { ("x86-x64-v4", TargetArchitecture.X86), "x86-x64-v3 avx512f avx512f_vl avx512bw avx512bw_vl avx512cd avx512cd_vl avx512dq avx512dq_vl" },
{ ("armv8-a", TargetArchitecture.ARM64), "neon" },
{ ("armv8.1-a", TargetArchitecture.ARM64), "armv8-a lse crc rdma" },
{ ("armv8.2-a", TargetArchitecture.ARM64), "armv8.1-a" },
implication ,X86 ,MOVBE ,SSE42
implication ,X86 ,X86Serialize ,X86Base
implication ,X86 ,AVX512F ,AVX2
+implication ,X86 ,AVX512F ,FMA
implication ,X86 ,AVX512F_VL ,AVX512F
implication ,X86 ,AVX512CD ,AVX512F
+implication ,X86 ,AVX512CD_VL ,AVX512CD
implication ,X86 ,AVX512CD_VL ,AVX512F_VL
implication ,X86 ,AVX512BW ,AVX512F
+implication ,X86 ,AVX512BW_VL ,AVX512BW
implication ,X86 ,AVX512BW_VL ,AVX512F_VL
implication ,X86 ,AVX512DQ ,AVX512F
+implication ,X86 ,AVX512DQ_VL ,AVX512DQ
implication ,X86 ,AVX512DQ_VL ,AVX512F_VL
implication ,X86 ,AVX512VBMI ,AVX512BW
+implication ,X86 ,AVX512VBMI_VL ,AVX512VBMI
implication ,X86 ,AVX512VBMI_VL ,AVX512BW_VL
+; While the AVX-512 ISAs can be individually lit-up, they really
+; need F, BW, CD, DQ, and VL to be fully functional without adding
+; significant complexity into the JIT. Additionally, unlike AVX/AVX2
+; there was never really any hardware that didn't provide all 5 at
+; once, with the notable exception being Knight's Landing which
+; provided a similar but not quite the same feature.
+implication ,X86 ,AVX512F ,AVX512BW_VL
+implication ,X86 ,AVX512F ,AVX512CD_VL
+implication ,X86 ,AVX512F ,AVX512DQ_VL
+
; Definition of X64 instruction sets
definearch ,X64 ,64Bit ,X64, X64
instructionsetgroup ,x86-x64-v2 ,X64 X86 ,sse4.2 popcnt
instructionsetgroup ,x86-x64-v3 ,X64 X86 ,x86-x64-v2 avx2 bmi bmi2 lzcnt movbe fma
instructionsetgroup ,skylake ,X64 X86 ,x86-x64-v3
-instructionsetgroup ,x86-x64-v4 ,X64 X86 ,x86-x64-v3 avx512f avx512f_vl avx512bw avx512bw_vl avx512cd avx512cd_vl
+instructionsetgroup ,x86-x64-v4 ,X64 X86 ,x86-x64-v3 avx512f avx512f_vl avx512bw avx512bw_vl avx512cd avx512cd_vl avx512dq avx512dq_vl
instructionsetgroup ,armv8-a ,ARM64 ,neon
instructionsetgroup ,armv8.1-a ,ARM64 ,armv8-a lse crc rdma
public const int Avx512dq_vl = 0x400000;
public const int Avx512Vbmi = 0x800000;
public const int Avx512Vbmi_vl = 0x1000000;
+ public const int Serialize = 0x2000000;
public static int FromInstructionSet(InstructionSet instructionSet)
{
InstructionSet.X64_AVX512VBMI_X64 => Avx512Vbmi,
InstructionSet.X64_AVX512VBMI_VL => Avx512Vbmi_vl,
InstructionSet.X64_AVX512VBMI_VL_X64 => Avx512Vbmi_vl,
+ InstructionSet.X64_X86Serialize => Serialize,
+ InstructionSet.X64_X86Serialize_X64 => Serialize,
// SSE and SSE2 are baseline ISAs - they're always available
InstructionSet.X64_SSE => 0,
// AMD64 Architecture Programmer’s Manual. Volume 3
// For more information, please refer to the CPUID instruction in the respective manuals
- // We will set the following flags:
- // CORJIT_FLAG_USE_SSE2 is required
- // SSE - EDX bit 25
- // SSE2 - EDX bit 26
- // CORJIT_FLAG_USE_AES
- // CORJIT_FLAG_USE_SSE2
- // AES - ECX bit 25
- // CORJIT_FLAG_USE_PCLMULQDQ
- // CORJIT_FLAG_USE_SSE2
- // PCLMULQDQ - ECX bit 1
- // CORJIT_FLAG_USE_SSE3 if the following feature bits are set (input EAX of 1)
- // CORJIT_FLAG_USE_SSE2
- // SSE3 - ECX bit 0
- // CORJIT_FLAG_USE_SSSE3 if the following feature bits are set (input EAX of 1)
- // CORJIT_FLAG_USE_SSE3
- // SSSE3 - ECX bit 9
- // CORJIT_FLAG_USE_SSE41 if the following feature bits are set (input EAX of 1)
- // CORJIT_FLAG_USE_SSSE3
- // SSE4.1 - ECX bit 19
- // CORJIT_FLAG_USE_SSE42 if the following feature bits are set (input EAX of 1)
- // CORJIT_FLAG_USE_SSE41
- // SSE4.2 - ECX bit 20
- // CORJIT_FLAG_USE_MOVBE if the following feature bits are set (input EAX of 1)
- // CORJIT_FLAG_USE_SSE42
- // MOVBE - ECX bit 22
- // CORJIT_FLAG_USE_POPCNT if the following feature bits are set (input EAX of 1)
- // CORJIT_FLAG_USE_SSE42
- // POPCNT - ECX bit 23
- // CORJIT_FLAG_USE_AVX if the following feature bits are set (input EAX of 1), and xmmYmmStateSupport returns 1:
- // CORJIT_FLAG_USE_SSE42
- // OSXSAVE - ECX bit 27
- // AVX - ECX bit 28
- // XGETBV - XCR0[2:1] 11b
- // CORJIT_FLAG_USE_FMA if the following feature bits are set (input EAX of 1), and xmmYmmStateSupport returns 1:
- // CORJIT_FLAG_USE_AVX
- // FMA - ECX bit 12
- // CORJIT_FLAG_USE_AVX2 if the following feature bit is set (input EAX of 0x07 and input ECX of 0):
- // CORJIT_FLAG_USE_AVX
- // AVX2 - EBX bit 5
- // CORJIT_FLAG_USE_AVXVNNI if the following feature bit is set (input EAX of 0x07 and input ECX of 1):
- // CORJIT_FLAG_USE_AVX2
- // AVXVNNI - EAX bit 4
- // CORJIT_FLAG_USE_AVX_512F if the following feature bit is set (input EAX of 0x07 and input ECX of 0), and avx512StateSupport returns 1:
- // CORJIT_FLAG_USE_AVX2
- // AVX512F - EBX bit 16
- // XGETBV - XRC0[7:5] 111b
- // CORJIT_FLAG_USE_AVX_512F_VL if the following feature bit is set (input EAX of 0x07 and input ECX of 0):
- // CORJIT_FLAG_USE_AVX512F
- // AVX512VL - EBX bit 31
- // CORJIT_FLAG_USE_AVX_512BW if the following feature bit is set (input EAX of 0x07 and input ECX of 0):
- // CORJIT_FLAG_USE_AVX512F
- // AVX512BW - EBX bit 30
- // CORJIT_FLAG_USE_AVX_512BW_VL if the following feature bit is set (input EAX of 0x07 and input ECX of 0):
- // CORJIT_FLAG_USE_AVX512F_VL
- // CORJIT_FLAG_USE_AVX_512BW
- // CORJIT_FLAG_USE_AVX_512CD if the following feature bit is set (input EAX of 0x07 and input ECX of 0):
- // CORJIT_FLAG_USE_AVX512F
- // AVX512CD - EBX bit 28
- // CORJIT_FLAG_USE_AVX_512CD_VL if the following feature bit is set (input EAX of 0x07 and input ECX of 0):
- // CORJIT_FLAG_USE_AVX512F_VL
- // CORJIT_FLAG_USE_AVX_512CD
- // CORJIT_FLAG_USE_AVX_512DQ if the following feature bit is set (input EAX of 0x07 and input ECX of 0):
- // CORJIT_FLAG_USE_AVX512F
- // AVX512DQ - EBX bit 7
- // CORJIT_FLAG_USE_AVX_512DQ_VL if the following feature bit is set (input EAX of 0x07 and input ECX of 0):
- // CORJIT_FLAG_USE_AVX512F_VL
- // CORJIT_FLAG_USE_AVX_512DQ
- // CORJIT_FLAG_USE_AVX_512VBMI if the following feature bit is set (input EAX of 0x07 and input ECX of 0):
- // CORJIT_FLAG_USE_AVX512F
- // AVX512VBMI - ECX bit 1
- // CORJIT_FLAG_USE_BMI1 if the following feature bit is set (input EAX of 0x07 and input ECX of 0):
- // BMI1 - EBX bit 3
- // CORJIT_FLAG_USE_BMI2 if the following feature bit is set (input EAX of 0x07 and input ECX of 0):
- // BMI2 - EBX bit 8
- // CORJIT_FLAG_USE_LZCNT if the following feature bits are set (input EAX of 80000001H)
- // LZCNT - ECX bit 5
- // synchronously updating VM and JIT.
-
union XarchCpuInfo
{
struct {
CPUCompileFlags.Set(InstructionSet_POPCNT);
}
- if (((cpuidInfo[CPUID_ECX] & (1 << 27)) != 0) && ((cpuidInfo[CPUID_ECX] & (1 << 28)) != 0)) // OSXSAVE & AVX
+ const int requiredAvxEcxFlags = (1 << 27) // OSXSAVE
+ | (1 << 28); // AVX
+
+ if ((cpuidInfo[CPUID_ECX] & requiredAvxEcxFlags) == requiredAvxEcxFlags)
{
- if(DoesOSSupportAVX() && (xmmYmmStateSupport() == 1)) // XGETBV == 11
+ if(DoesOSSupportAVX() && (xmmYmmStateSupport() == 1)) // XGETBV == 11
{
CPUCompileFlags.Set(InstructionSet_AVX);
{
CPUCompileFlags.Set(InstructionSet_AVX2);
- if (DoesOSSupportAVX512() && (avx512StateSupport() == 1)) // XGETBV XRC0[7:5] == 111
+ if (DoesOSSupportAVX512() && (avx512StateSupport() == 1)) // XGETBV XRC0[7:5] == 111
{
- if ((cpuidInfo[CPUID_EBX] & (1 << 16)) != 0) // AVX512F
+ if ((cpuidInfo[CPUID_EBX] & (1 << 16)) != 0) // AVX512F
{
CPUCompileFlags.Set(InstructionSet_AVX512F);
bool isAVX512_VLSupported = false;
- if ((cpuidInfo[CPUID_EBX] & (1 << 31)) != 0) // AVX512VL
+ if ((cpuidInfo[CPUID_EBX] & (1 << 31)) != 0) // AVX512VL
{
CPUCompileFlags.Set(InstructionSet_AVX512F_VL);
isAVX512_VLSupported = true;
}
- if ((cpuidInfo[CPUID_EBX] & (1 << 30)) != 0) // AVX512BW
+ if ((cpuidInfo[CPUID_EBX] & (1 << 30)) != 0) // AVX512BW
{
CPUCompileFlags.Set(InstructionSet_AVX512BW);
- if (isAVX512_VLSupported) // AVX512BW_VL
+ if (isAVX512_VLSupported) // AVX512BW_VL
{
CPUCompileFlags.Set(InstructionSet_AVX512BW_VL);
}
}
- if ((cpuidInfo[CPUID_EBX] & (1 << 28)) != 0) // AVX512CD
+ if ((cpuidInfo[CPUID_EBX] & (1 << 28)) != 0) // AVX512CD
{
CPUCompileFlags.Set(InstructionSet_AVX512CD);
- if (isAVX512_VLSupported) // AVX512CD_VL
+ if (isAVX512_VLSupported) // AVX512CD_VL
{
CPUCompileFlags.Set(InstructionSet_AVX512CD_VL);
}
}
- if ((cpuidInfo[CPUID_EBX] & (1 << 17)) != 0) // AVX512DQ
+ if ((cpuidInfo[CPUID_EBX] & (1 << 17)) != 0) // AVX512DQ
{
CPUCompileFlags.Set(InstructionSet_AVX512DQ);
- if (isAVX512_VLSupported) // AVX512DQ_VL
+ if (isAVX512_VLSupported) // AVX512DQ_VL
{
CPUCompileFlags.Set(InstructionSet_AVX512DQ_VL);
}
}
- if ((cpuidInfo[CPUID_ECX] & (1 << 1)) != 0) // AVX512VBMI
+ if ((cpuidInfo[CPUID_ECX] & (1 << 1)) != 0) // AVX512VBMI
{
CPUCompileFlags.Set(InstructionSet_AVX512VBMI);
- if (isAVX512_VLSupported) // AVX512VBMI_VL
+ if (isAVX512_VLSupported) // AVX512VBMI_VL
{
CPUCompileFlags.Set(InstructionSet_AVX512VBMI_VL);
}
{
__cpuidex(cpuidInfo, 0x00000007, 0x00000000);
- if ((cpuidInfo[CPUID_EBX] & (1 << 3)) != 0) // BMI1
+ if ((cpuidInfo[CPUID_EBX] & (1 << 3)) != 0) // BMI1
{
CPUCompileFlags.Set(InstructionSet_BMI1);
}
- if ((cpuidInfo[CPUID_EBX] & (1 << 8)) != 0) // BMI2
+ if ((cpuidInfo[CPUID_EBX] & (1 << 8)) != 0) // BMI2
{
CPUCompileFlags.Set(InstructionSet_BMI2);
}
if ((cpuidInfo[CPUID_EDX] & (1 << 14)) != 0)
{
- CPUCompileFlags.Set(InstructionSet_X86Serialize); // SERIALIZE
+ CPUCompileFlags.Set(InstructionSet_X86Serialize); // SERIALIZE
}
}
{
__cpuid(cpuidInfo, 0x80000001);
- if ((cpuidInfo[CPUID_ECX] & (1 << 5)) != 0) // LZCNT
+ if ((cpuidInfo[CPUID_ECX] & (1 << 5)) != 0) // LZCNT
{
CPUCompileFlags.Set(InstructionSet_LZCNT);
}
//
using System;
+using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics.X86;
using System.Runtime.Intrinsics;
+using System.Reflection;
using Xunit;
namespace IntelHardwareIntrinsicTest._CpuId
const int Fail = 0;
[Fact]
+ [SkipOnMono("Mono does not currently have full support for intrinsics on xarch", TestPlatforms.Any)]
public unsafe static void CpuId()
{
int testResult = Pass;
testResult = Fail;
}
- int maxFunctionId = eax;
+ uint maxFunctionId = (uint)eax;
- if ((maxFunctionId < 0x00000001) || (Environment.GetEnvironmentVariable("DOTNET_EnableHWIntrinsic") is null))
+ if (maxFunctionId < 0x00000001)
{
Assert.Equal(Pass, testResult);
return;
}
+ bool isX86BaseDisabled = !GetDotnetEnable("HWINTRINSIC");
+ bool isHierarchyDisabled = isX86BaseDisabled;
+
(eax, ebx, ecx, edx) = X86Base.CpuId(0x00000001, 0x00000000);
- if (IsBitIncorrect(ecx, 28, Avx.IsSupported, "AVX"))
+ if (IsBitIncorrect(edx, 25, typeof(Sse), Sse.IsSupported, "SSE", ref isHierarchyDisabled))
{
- Console.WriteLine("CPUID Fn0000_0001_ECX:AVX != Avx.IsSupported");
testResult = Fail;
}
- if (IsBitIncorrect(ecx, 25, Aes.IsSupported, "AES"))
+ if (IsBitIncorrect(edx, 26, typeof(Sse2), Sse2.IsSupported, "SSE2", ref isHierarchyDisabled))
{
- Console.WriteLine("CPUID Fn0000_0001_ECX:AES != Aes.IsSupported");
testResult = Fail;
}
- if (IsBitIncorrect(ecx, 23, Popcnt.IsSupported, "POPCNT"))
+ bool isSse2HierarchyDisabled = isHierarchyDisabled;
+
+ if (IsBitIncorrect(ecx, 25, typeof(Aes), Aes.IsSupported, "AES", ref isHierarchyDisabled))
{
- Console.WriteLine("CPUID Fn0000_0001_ECX:POPCNT != Popcnt.IsSupported");
testResult = Fail;
}
- if (IsBitIncorrect(ecx, 20, Sse42.IsSupported, "SSE42"))
+ isHierarchyDisabled = isSse2HierarchyDisabled;
+
+ if (IsBitIncorrect(ecx, 1, typeof(Pclmulqdq), Pclmulqdq.IsSupported, "PCLMULQDQ", ref isHierarchyDisabled))
{
- Console.WriteLine("CPUID Fn0000_0001_ECX:SSE42 != Sse42.IsSupported");
testResult = Fail;
}
- if (IsBitIncorrect(ecx, 19, Sse41.IsSupported, "SSE41"))
+ isHierarchyDisabled = isSse2HierarchyDisabled;
+
+ if (IsBitIncorrect(ecx, 0, typeof(Sse3), Sse3.IsSupported, "SSE3", ref isHierarchyDisabled))
{
- Console.WriteLine("CPUID Fn0000_0001_ECX:SSE41 != Sse41.IsSupported");
testResult = Fail;
}
- if (IsBitIncorrect(ecx, 12, Fma.IsSupported, "FMA"))
+ if (IsBitIncorrect(ecx, 9, typeof(Ssse3), Ssse3.IsSupported, "SSSE3", ref isHierarchyDisabled))
{
- Console.WriteLine("CPUID Fn0000_0001_ECX:FMA != Fma.IsSupported");
testResult = Fail;
}
- if (IsBitIncorrect(ecx, 9, Ssse3.IsSupported, "SSSE3"))
+ if (IsBitIncorrect(ecx, 19, typeof(Sse41), Sse41.IsSupported, "SSE41", ref isHierarchyDisabled))
{
- Console.WriteLine("CPUID Fn0000_0001_ECX:SSSE3 != Ssse3.IsSupported");
testResult = Fail;
}
- if (IsBitIncorrect(ecx, 1, Pclmulqdq.IsSupported, "PCLMULQDQ"))
+ if (IsBitIncorrect(ecx, 20, typeof(Sse42), Sse42.IsSupported, "SSE42", ref isHierarchyDisabled))
{
- Console.WriteLine("CPUID Fn0000_0001_ECX:PCLMULQDQ != Pclmulqdq.IsSupported");
testResult = Fail;
}
- if (IsBitIncorrect(ecx, 0, Sse3.IsSupported, "SSE3"))
+ bool isSse42HierarchyDisabled = isHierarchyDisabled;
+
+ if (IsBitIncorrect(ecx, 23, typeof(Popcnt), Popcnt.IsSupported, "POPCNT", ref isHierarchyDisabled))
{
- Console.WriteLine("CPUID Fn0000_0001_ECX:SSE3 != Sse3.IsSupported");
testResult = Fail;
}
- if (IsBitIncorrect(edx, 26, Sse2.IsSupported, "SSE2"))
+ isHierarchyDisabled = isSse42HierarchyDisabled;
+
+ if (IsBitIncorrect(ecx, 28, typeof(Avx), Avx.IsSupported, "AVX", ref isHierarchyDisabled))
{
- Console.WriteLine("CPUID Fn0000_0001_ECX:SSE2 != Sse2.IsSupported");
testResult = Fail;
}
- if (IsBitIncorrect(edx, 25, Sse.IsSupported, "SSE"))
+ bool isAvxHierarchyDisabled = isHierarchyDisabled;
+
+ if (IsBitIncorrect(ecx, 12, typeof(Fma), Fma.IsSupported, "FMA", ref isHierarchyDisabled))
{
- Console.WriteLine("CPUID Fn0000_0001_ECX:SSE != Sse.IsSupported");
testResult = Fail;
}
+ bool isFmaHierarchyDisabled = isHierarchyDisabled;
+
if (maxFunctionId < 0x00000007)
{
Assert.Equal(Pass, testResult);
(eax, ebx, ecx, edx) = X86Base.CpuId(0x00000007, 0x00000000);
- if (IsBitIncorrect(ebx, 8, Bmi2.IsSupported, "BMI2"))
+ isHierarchyDisabled = isAvxHierarchyDisabled;
+
+ if (IsBitIncorrect(ebx, 5, typeof(Avx2), Avx2.IsSupported, "AVX2", ref isHierarchyDisabled))
{
- Console.WriteLine("CPUID Fn0000_0007_EBX:BMI2 != Bmi2.IsSupported");
testResult = Fail;
}
- if (IsBitIncorrect(ebx, 5, Avx2.IsSupported, "AVX2"))
+ bool isAvx2HierarchyDisabled = isHierarchyDisabled;
+
+ if (IsBitIncorrect(ebx, 3, typeof(Bmi1), Bmi1.IsSupported, "BMI1", ref isHierarchyDisabled))
{
- Console.WriteLine("CPUID Fn0000_0007_EBX:AVX2 != Avx2.IsSupported");
testResult = Fail;
}
- if (IsBitIncorrect(ebx, 3, Bmi1.IsSupported, "BMI1"))
+ isHierarchyDisabled = isAvx2HierarchyDisabled;
+
+ if (IsBitIncorrect(ebx, 8, typeof(Bmi2), Bmi2.IsSupported, "BMI2", ref isHierarchyDisabled))
{
- Console.WriteLine("CPUID Fn0000_0001_EBX:BMI1 != Bmi1.IsSupported");
testResult = Fail;
}
- (eax, ebx, ecx, edx) = X86Base.CpuId(unchecked((int)0x80000000), 0x00000000);
+ isHierarchyDisabled = isAvx2HierarchyDisabled | isFmaHierarchyDisabled | OperatingSystem.IsMacOS();
+
+ for (int i = 0; i < 2; i++)
+ {
+ // The runtime currently requires that all of F + BW + CD + DQ + VL be supported together or none
+ // are supported. To handle this we simple check them all twice so that if any of them are disabled
+ // the first time around, we'll then assert that they are all actually disabled the second time around
+
+ if (IsBitIncorrect(ebx, 16, typeof(Avx512F), Avx512F.IsSupported, "AVX512F", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsBitIncorrect(ebx, 31, typeof(Avx512F.VL), Avx512F.VL.IsSupported, "AVX512F_VL", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsBitIncorrect(ebx, 30, typeof(Avx512BW), Avx512BW.IsSupported, "AVX512BW", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsBitIncorrect(ebx, 30, typeof(Avx512BW.VL), Avx512BW.VL.IsSupported, "AVX512BW_VL", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsBitIncorrect(ebx, 28, typeof(Avx512CD), Avx512CD.IsSupported, "AVX512CD", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsBitIncorrect(ebx, 28, typeof(Avx512CD.VL), Avx512CD.VL.IsSupported, "AVX512CD_VL", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsBitIncorrect(ebx, 17, typeof(Avx512DQ), Avx512DQ.IsSupported, "AVX512DQ", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsBitIncorrect(ebx, 17, typeof(Avx512DQ.VL), Avx512DQ.VL.IsSupported, "AVX512DQ_VL", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+ }
+
+ bool isAvx512HierarchyDisabled = isHierarchyDisabled;
+
+ if (IsBitIncorrect(ecx, 1, typeof(Avx512Vbmi), Avx512Vbmi.IsSupported, "AVX512VBMI", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsBitIncorrect(ecx, 1, typeof(Avx512Vbmi.VL), Avx512Vbmi.VL.IsSupported, "AVX512VBMI_VL", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ isHierarchyDisabled = isX86BaseDisabled;
- if (isAuthenticAmd && ((ebx != 0x68747541) || (ecx != 0x444D4163) || (edx != 0x69746E65)))
+ if (IsBitIncorrect(edx, 14, typeof(X86Serialize), X86Serialize.IsSupported, "SERIALIZE", ref isHierarchyDisabled))
{
- Console.WriteLine("CPUID Fn8000_0000 reported different vendor info from Fn0000_0000");
testResult = Fail;
}
- if (isGenuineIntel && ((ebx != 0x756E6547) && (ecx != 0x6C65746E) && (edx != 0x6C656E69)))
+ (eax, ebx, ecx, edx) = X86Base.CpuId(0x00000007, 0x00000001);
+
+ isHierarchyDisabled = isAvx2HierarchyDisabled;
+
+#pragma warning disable CA2252 // No need to opt into preview feature for an internal test
+ if (IsBitIncorrect(eax, 4, typeof(AvxVnni), AvxVnni.IsSupported, "AVXVNNI", ref isHierarchyDisabled))
{
- Console.WriteLine("CPUID Fn8000_0000 reported different vendor info from Fn0000_0000");
testResult = Fail;
}
+#pragma warning restore CA2252
+
+ (eax, ebx, ecx, edx) = X86Base.CpuId(unchecked((int)0x80000000), 0x00000000);
- int maxFunctionIdEx = eax;
+ uint maxFunctionIdEx = (uint)eax;
if (maxFunctionIdEx < 0x00000001)
{
(eax, ebx, ecx, edx) = X86Base.CpuId(unchecked((int)0x80000001), 0x00000000);
- if (IsBitIncorrect(ecx, 5, Lzcnt.IsSupported, "LZCNT"))
+ isHierarchyDisabled = isX86BaseDisabled;
+
+ if (IsBitIncorrect(ecx, 5, typeof(Lzcnt), Lzcnt.IsSupported, "LZCNT", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsIncorrect(typeof(Vector64), Vector64.IsHardwareAccelerated, isHierarchyDisabled: true))
+ {
+ testResult = Fail;
+ }
+
+ if (IsIncorrect(typeof(Vector128), Vector128.IsHardwareAccelerated, isSse2HierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsIncorrect(typeof(Vector256), Vector256.IsHardwareAccelerated, isAvx2HierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsIncorrect(typeof(Vector512), Vector512.IsHardwareAccelerated, isAvx512HierarchyDisabled))
{
- Console.WriteLine("CPUID Fn8000_0001_ECX:LZCNT != Lzcnt.IsSupported");
+ testResult = Fail;
+ }
+
+ if (IsIncorrect(typeof(Vector), Vector.IsHardwareAccelerated, isSse2HierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (Vector<byte>.Count == 16)
+ {
+ if (!isAvx2HierarchyDisabled)
+ {
+ Console.WriteLine($"{typeof(Vector).FullName}.Count returned 16 but the hardware returned 32");
+ testResult = Fail;
+ }
+ }
+ else if (Vector<byte>.Count == 32)
+ {
+ if (isAvx2HierarchyDisabled)
+ {
+ Console.WriteLine($"{typeof(Vector).FullName}.Count returned 32 but the hardware returned 16");
+ testResult = Fail;
+ }
+ }
+ else
+ {
+ Console.WriteLine($"{typeof(Vector).FullName}.Count returned {Vector<byte>.Count} which is unexpected");
+ testResult = Fail;
+ }
+
+ if (Vector<byte>.Count != (int)typeof(Vector<byte>).GetProperty("Count")!.GetValue(null)!)
+ {
+ Console.WriteLine($"{typeof(Vector).FullName}.Count returned a different result when called via reflection");
testResult = Fail;
}
return;
}
- static bool IsBitIncorrect(int register, int bitNumber, bool expectedResult, string name)
+ static bool IsBitIncorrect(int register, int bitNumber, Type isa, bool isSupported, string name, ref bool isHierarchyDisabled)
{
- return ((register & (1 << bitNumber)) != ((expectedResult ? 1 : 0) << bitNumber))
- && (Environment.GetEnvironmentVariable($"DOTNET_Enable{name}") is null);
+ bool isSupportedByHardware = (register & (1 << bitNumber)) != 0;
+ isHierarchyDisabled |= !GetDotnetEnable(name);
+
+ if (isSupported)
+ {
+ if (!isSupportedByHardware)
+ {
+ Console.WriteLine($"{isa.FullName}.IsSupported returned true but the hardware returned false");
+ return true;
+ }
+
+ if (isHierarchyDisabled)
+ {
+ Console.WriteLine($"{isa.FullName}.IsSupported returned true but the runtime returned false");
+ return true;
+ }
+ }
+ else if (isSupportedByHardware)
+ {
+ if (!isHierarchyDisabled)
+ {
+ Console.WriteLine($"{isa.FullName}.IsSupported returned false but the hardware and runtime returned true");
+ return true;
+ }
+ }
+ else
+ {
+ // The IsSupported query returned false and the hardware
+ // says its unsupported, so we're all good
+ }
+
+ if (isSupported != (bool)isa.GetProperty("IsSupported")!.GetValue(null)!)
+ {
+ Console.WriteLine($"{isa.FullName}.IsSupported returned a different result when called via reflection");
+ return true;
+ }
+
+ return false;
+ }
+
+ static bool IsIncorrect(Type isa, bool isHardwareAccelerated, bool isHierarchyDisabled)
+ {
+ if (isHardwareAccelerated)
+ {
+ if (isHierarchyDisabled)
+ {
+ Console.WriteLine($"{isa.FullName}.IsHardwareAccelerated returned true but the runtime returned false");
+ return true;
+ }
+ }
+ else if (!isHierarchyDisabled)
+ {
+ Console.WriteLine($"{isa.FullName}.IsHardwareAccelerated returned false but the hardware and runtime returned true");
+ return true;
+ }
+
+ if (isHardwareAccelerated != (bool)isa.GetProperty("IsHardwareAccelerated")!.GetValue(null)!)
+ {
+ Console.WriteLine($"{isa.FullName}.IsHardwareAccelerated returned a different result when called via reflection");
+ return true;
+ }
+
+ return false;
+ }
+
+ static bool GetDotnetEnable(string name)
+ {
+ string? stringValue = Environment.GetEnvironmentVariable($"DOTNET_Enable{name}");
+
+ if ((stringValue is null) || !int.TryParse(stringValue, out int value))
+ {
+ // Hardware Intrinsic configuration knobs default to true
+ return true;
+ }
+
+ return value != 0;
}
}
}
//
// The test is compiled with multiple defines to test this.
+ bool ExpectedVectorsAccelerated = true;
+
+ bool? ExpectedSse = true;
+ bool? ExpectedSse2 = true;
+
#if BASELINE_INTRINSICS
- bool vectorsAccelerated = true;
- int byteVectorLength = 16;
- bool? Sse2AndBelow = true;
- bool? Sse3Group = null;
- bool? AesLzPcl = null;
- bool? Sse4142 = null;
- bool? PopCnt = null;
- bool? Avx12 = false;
- bool? FmaBmi12 = false;
- bool? Avxvnni = false;
-#elif NON_VEX_INTRINSICS
- bool vectorsAccelerated = true;
+ bool? ExpectedSse3 = null;
+ bool? ExpectedSsse3 = null;
+ bool? ExpectedAes = null;
+ bool? ExpectedLzcnt = null;
+ bool? ExpectedPclmulqdq = null;
+ bool? ExpectedSse41 = null;
+ bool? ExpectedSse42 = null;
+ bool? ExpectedPopcnt = null;
+ bool? ExpectedAvx = false;
+ bool? ExpectedAvx2 = false;
+ bool? ExpectedFma = false;
+ bool? ExpectedBmi1 = false;
+ bool? ExpectedBmi2 = false;
+ bool? ExpectedAvxVnni = false;
+ bool? ExpectedAvx512F = false;
+ bool? ExpectedAvx512BW = false;
+ bool? ExpectedAvx512CD = false;
+ bool? ExpectedAvx512DQ = false;
+ bool? ExpectedAvx512Vbmi = false;
+ bool? ExpectedX86Serialize = null;
+#elif SSE42_INTRINSICS
+ bool? ExpectedSse3 = true;
+ bool? ExpectedSsse3 = true;
+ bool? ExpectedAes = null;
+ bool? ExpectedLzcnt = null;
+ bool? ExpectedPclmulqdq = null;
+ bool? ExpectedSse41 = true;
+ bool? ExpectedSse42 = true;
+ bool? ExpectedPopcnt = null;
+ bool? ExpectedAvx = false;
+ bool? ExpectedAvx2 = false;
+ bool? ExpectedFma = false;
+ bool? ExpectedBmi1 = false;
+ bool? ExpectedBmi2 = false;
+ bool? ExpectedAvxVnni = false;
+ bool? ExpectedAvx512F = false;
+ bool? ExpectedAvx512BW = false;
+ bool? ExpectedAvx512CD = false;
+ bool? ExpectedAvx512DQ = false;
+ bool? ExpectedAvx512Vbmi = false;
+ bool? ExpectedX86Serialize = null;
+#elif AVX_INTRINSICS
+ bool? ExpectedSse3 = true;
+ bool? ExpectedSsse3 = true;
+ bool? ExpectedAes = null;
+ bool? ExpectedLzcnt = null;
+ bool? ExpectedPclmulqdq = null;
+ bool? ExpectedSse41 = true;
+ bool? ExpectedSse42 = true;
+ bool? ExpectedPopcnt = null;
+ bool? ExpectedAvx = true;
+ bool? ExpectedAvx2 = false; // TODO: Fix once opportunistic Avx2 is allowed
+ bool? ExpectedFma = null;
+ bool? ExpectedBmi1 = null;
+ bool? ExpectedBmi2 = null;
+ bool? ExpectedAvxVnni = false; // TODO: Fix once opportunistic Avx2 is allowed
+ bool? ExpectedAvx512F = false;
+ bool? ExpectedAvx512BW = false;
+ bool? ExpectedAvx512CD = false;
+ bool? ExpectedAvx512DQ = false;
+ bool? ExpectedAvx512Vbmi = false;
+ bool? ExpectedX86Serialize = null;
+#elif AVX2_INTRINSICS
+ bool? ExpectedSse3 = true;
+ bool? ExpectedSsse3 = true;
+ bool? ExpectedAes = null;
+ bool? ExpectedLzcnt = null;
+ bool? ExpectedPclmulqdq = null;
+ bool? ExpectedSse41 = true;
+ bool? ExpectedSse42 = true;
+ bool? ExpectedPopcnt = null;
+ bool? ExpectedAvx = true;
+ bool? ExpectedAvx2 = true;
+ bool? ExpectedFma = null;
+ bool? ExpectedBmi1 = null;
+ bool? ExpectedBmi2 = null;
+ bool? ExpectedAvxVnni = null;
+ bool? ExpectedAvx512F = false;
+ bool? ExpectedAvx512BW = false;
+ bool? ExpectedAvx512CD = false;
+ bool? ExpectedAvx512DQ = false;
+ bool? ExpectedAvx512Vbmi = false;
+ bool? ExpectedX86Serialize = null;
+#elif AVX512_INTRINSICS
+ bool? ExpectedSse3 = true;
+ bool? ExpectedSsse3 = true;
+ bool? ExpectedAes = null;
+ bool? ExpectedLzcnt = null;
+ bool? ExpectedPclmulqdq = null;
+ bool? ExpectedSse41 = true;
+ bool? ExpectedSse42 = true;
+ bool? ExpectedPopcnt = null;
+ bool? ExpectedAvx = true;
+ bool? ExpectedAvx2 = true;
+ bool? ExpectedFma = true;
+ bool? ExpectedBmi1 = null;
+ bool? ExpectedBmi2 = null;
+ bool? ExpectedAvxVnni = null;
+ bool? ExpectedAvx512F = true;
+ bool? ExpectedAvx512BW = true;
+ bool? ExpectedAvx512CD = true;
+ bool? ExpectedAvx512DQ = true;
+ bool? ExpectedAvx512Vbmi = null;
+ bool? ExpectedX86Serialize = null;
+#else
+#error Who dis?
+#endif
+
+#if VECTORT128_INTRINSICS
int byteVectorLength = 16;
- bool? Sse2AndBelow = true;
- bool? Sse3Group = true;
- bool? AesLzPcl = null;
- bool? Sse4142 = true;
- bool? PopCnt = null;
- bool? Avx12 = false;
- bool? FmaBmi12 = false;
- bool? Avxvnni = false;
-#elif VEX_INTRINSICS
- bool vectorsAccelerated = true;
+#elif VECTORT256_INTRINSICS
int byteVectorLength = 32;
- bool? Sse2AndBelow = true;
- bool? Sse3Group = true;
- bool? AesLzPcl = null;
- bool? Sse4142 = true;
- bool? PopCnt = null;
- bool? Avx12 = true;
- bool? FmaBmi12 = null;
- bool? Avxvnni = null;
#else
#error Who dis?
#endif
- if (vectorsAccelerated != Vector.IsHardwareAccelerated)
+ if (ExpectedVectorsAccelerated != Vector.IsHardwareAccelerated)
{
- throw new Exception($"Vectors HW acceleration state unexpected - expected {vectorsAccelerated}, got {Vector.IsHardwareAccelerated}");
+ throw new Exception($"Vectors HW acceleration state unexpected - expected {ExpectedVectorsAccelerated}, got {Vector.IsHardwareAccelerated}");
}
if (byteVectorLength != Vector<byte>.Count)
throw new Exception($"Unexpected vector length - expected {byteVectorLength}, got {Vector<byte>.Count}");
}
- Check("Sse", Sse2AndBelow, &SseIsSupported, Sse.IsSupported, () => Sse.Subtract(Vector128<float>.Zero, Vector128<float>.Zero).Equals(Vector128<float>.Zero));
- Check("Sse.X64", Sse2AndBelow, &SseX64IsSupported, Sse.X64.IsSupported, () => Sse.X64.ConvertToInt64WithTruncation(Vector128<float>.Zero) == 0);
+ Check("Sse", ExpectedSse, &SseIsSupported, Sse.IsSupported, () => Sse.Subtract(Vector128<float>.Zero, Vector128<float>.Zero).Equals(Vector128<float>.Zero));
+ Check("Sse.X64", ExpectedSse, &SseX64IsSupported, Sse.X64.IsSupported, () => Sse.X64.ConvertToInt64WithTruncation(Vector128<float>.Zero) == 0);
+
+ Check("Sse2", ExpectedSse2, &Sse2IsSupported, Sse2.IsSupported, () => Sse2.Extract(Vector128<ushort>.Zero, 0) == 0);
+ Check("Sse2.X64", ExpectedSse2, &Sse2X64IsSupported, Sse2.X64.IsSupported, () => Sse2.X64.ConvertToInt64(Vector128<double>.Zero) == 0);
+
+ Check("Sse3", ExpectedSse3, &Sse3IsSupported, Sse3.IsSupported, () => Sse3.MoveHighAndDuplicate(Vector128<float>.Zero).Equals(Vector128<float>.Zero));
+ Check("Sse3.X64", ExpectedSse3, &Sse3X64IsSupported, Sse3.X64.IsSupported, null);
+
+ Check("Ssse3", ExpectedSsse3, &Ssse3IsSupported, Ssse3.IsSupported, () => Ssse3.Abs(Vector128<short>.Zero).Equals(Vector128<ushort>.Zero));
+ Check("Ssse3.X64", ExpectedSsse3, &Ssse3X64IsSupported, Ssse3.X64.IsSupported, null);
+
+ Check("Sse41", ExpectedSse41, &Sse41IsSupported, Sse41.IsSupported, () => Sse41.Max(Vector128<int>.Zero, Vector128<int>.Zero).Equals(Vector128<int>.Zero));
+ Check("Sse41.X64", ExpectedSse41, &Sse41X64IsSupported, Sse41.X64.IsSupported, () => Sse41.X64.Extract(Vector128<long>.Zero, 0) == 0);
+
+ Check("Sse42", ExpectedSse42, &Sse42IsSupported, Sse42.IsSupported, () => Sse42.Crc32(0, 0) == 0);
+ Check("Sse42.X64", ExpectedSse42, &Sse42X64IsSupported, Sse42.X64.IsSupported, () => Sse42.X64.Crc32(0, 0) == 0);
+
+ Check("Aes", ExpectedAes, &AesIsSupported, Aes.IsSupported, () => Aes.KeygenAssist(Vector128<byte>.Zero, 0).Equals(Vector128.Create((byte)99)));
+ Check("Aes.X64", ExpectedAes, &AesX64IsSupported, Aes.X64.IsSupported, null);
- Check("Sse2", Sse2AndBelow, &Sse2IsSupported, Sse2.IsSupported, () => Sse2.Extract(Vector128<ushort>.Zero, 0) == 0);
- Check("Sse2.X64", Sse2AndBelow, &Sse2X64IsSupported, Sse2.X64.IsSupported, () => Sse2.X64.ConvertToInt64(Vector128<double>.Zero) == 0);
+ Check("Avx", ExpectedAvx, &AvxIsSupported, Avx.IsSupported, () => Avx.Add(Vector256<double>.Zero, Vector256<double>.Zero).Equals(Vector256<double>.Zero));
+ Check("Avx.X64", ExpectedAvx, &AvxX64IsSupported, Avx.X64.IsSupported, null);
- Check("Sse3", Sse3Group, &Sse3IsSupported, Sse3.IsSupported, () => Sse3.MoveHighAndDuplicate(Vector128<float>.Zero).Equals(Vector128<float>.Zero));
- Check("Sse3.X64", Sse3Group, &Sse3X64IsSupported, Sse3.X64.IsSupported, null);
+ Check("Avx2", ExpectedAvx2, &Avx2IsSupported, Avx2.IsSupported, () => Avx2.Abs(Vector256<int>.Zero).Equals(Vector256<uint>.Zero));
+ Check("Avx2.X64", ExpectedAvx2, &Avx2X64IsSupported, Avx2.X64.IsSupported, null);
- Check("Ssse3", Sse3Group, &Ssse3IsSupported, Ssse3.IsSupported, () => Ssse3.Abs(Vector128<short>.Zero).Equals(Vector128<ushort>.Zero));
- Check("Ssse3.X64", Sse3Group, &Ssse3X64IsSupported, Ssse3.X64.IsSupported, null);
+ Check("Bmi1", ExpectedBmi1, &Bmi1IsSupported, Bmi1.IsSupported, () => Bmi1.AndNot(0, 0) == 0);
+ Check("Bmi1.X64", ExpectedBmi1, &Bmi1X64IsSupported, Bmi1.X64.IsSupported, () => Bmi1.X64.AndNot(0, 0) == 0);
- Check("Sse41", Sse4142, &Sse41IsSupported, Sse41.IsSupported, () => Sse41.Max(Vector128<int>.Zero, Vector128<int>.Zero).Equals(Vector128<int>.Zero));
- Check("Sse41.X64", Sse4142, &Sse41X64IsSupported, Sse41.X64.IsSupported, () => Sse41.X64.Extract(Vector128<long>.Zero, 0) == 0);
+ Check("Bmi2", ExpectedBmi2, &Bmi2IsSupported, Bmi2.IsSupported, () => Bmi2.MultiplyNoFlags(0, 0) == 0);
+ Check("Bmi2.X64", ExpectedBmi2, &Bmi2X64IsSupported, Bmi2.X64.IsSupported, () => Bmi2.X64.MultiplyNoFlags(0, 0) == 0);
- Check("Sse42", Sse4142, &Sse42IsSupported, Sse42.IsSupported, () => Sse42.Crc32(0, 0) == 0);
- Check("Sse42.X64", Sse4142, &Sse42X64IsSupported, Sse42.X64.IsSupported, () => Sse42.X64.Crc32(0, 0) == 0);
+ Check("Fma", ExpectedFma, &FmaIsSupported, Fma.IsSupported, () => Fma.MultiplyAdd(Vector128<float>.Zero, Vector128<float>.Zero, Vector128<float>.Zero).Equals(Vector128<float>.Zero));
+ Check("Fma.X64", ExpectedFma, &FmaX64IsSupported, Fma.X64.IsSupported, null);
- Check("Aes", AesLzPcl, &AesIsSupported, Aes.IsSupported, () => Aes.KeygenAssist(Vector128<byte>.Zero, 0).Equals(Vector128.Create((byte)99)));
- Check("Aes.X64", AesLzPcl, &AesX64IsSupported, Aes.X64.IsSupported, null);
+ Check("Lzcnt", ExpectedLzcnt, &LzcntIsSupported, Lzcnt.IsSupported, () => Lzcnt.LeadingZeroCount(0) == 32);
+ Check("Lzcnt.X64", ExpectedLzcnt, &LzcntX64IsSupported, Lzcnt.X64.IsSupported, () => Lzcnt.X64.LeadingZeroCount(0) == 64);
- Check("Avx", Avx12, &AvxIsSupported, Avx.IsSupported, () => Avx.Add(Vector256<double>.Zero, Vector256<double>.Zero).Equals(Vector256<double>.Zero));
- Check("Avx.X64", Avx12, &AvxX64IsSupported, Avx.X64.IsSupported, null);
+ Check("Pclmulqdq", ExpectedPclmulqdq, &PclmulqdqIsSupported, Pclmulqdq.IsSupported, () => Pclmulqdq.CarrylessMultiply(Vector128<long>.Zero, Vector128<long>.Zero, 0).Equals(Vector128<long>.Zero));
+ Check("Pclmulqdq.X64", ExpectedPclmulqdq, &PclmulqdqX64IsSupported, Pclmulqdq.X64.IsSupported, null);
- Check("Avx2", Avx12, &Avx2IsSupported, Avx2.IsSupported, () => Avx2.Abs(Vector256<int>.Zero).Equals(Vector256<uint>.Zero));
- Check("Avx2.X64", Avx12, &Avx2X64IsSupported, Avx2.X64.IsSupported, null);
+ Check("Popcnt", ExpectedPopcnt, &PopcntIsSupported, Popcnt.IsSupported, () => Popcnt.PopCount(0) == 0);
+ Check("Popcnt.X64", ExpectedPopcnt, &PopcntX64IsSupported, Popcnt.X64.IsSupported, () => Popcnt.X64.PopCount(0) == 0);
- Check("Bmi1", FmaBmi12, &Bmi1IsSupported, Bmi1.IsSupported, () => Bmi1.AndNot(0, 0) == 0);
- Check("Bmi1.X64", FmaBmi12, &Bmi1X64IsSupported, Bmi1.X64.IsSupported, () => Bmi1.X64.AndNot(0, 0) == 0);
+ Check("AvxVnni", ExpectedAvxVnni, &AvxVnniIsSupported, AvxVnni.IsSupported, () => AvxVnni.MultiplyWideningAndAdd(Vector128<int>.Zero, Vector128<byte>.Zero, Vector128<sbyte>.Zero).Equals(Vector128<int>.Zero));
+ Check("AvxVnni.X64", ExpectedAvxVnni, &AvxVnniX64IsSupported, AvxVnni.X64.IsSupported, null);
- Check("Bmi2", FmaBmi12, &Bmi2IsSupported, Bmi2.IsSupported, () => Bmi2.MultiplyNoFlags(0, 0) == 0);
- Check("Bmi2.X64", FmaBmi12, &Bmi2X64IsSupported, Bmi2.X64.IsSupported, () => Bmi2.X64.MultiplyNoFlags(0, 0) == 0);
+ Check("Avx512F", ExpectedAvx512F, &Avx512FIsSupported, Avx512F.IsSupported, () => Avx512F.Abs(Vector512<int>.Zero).Equals(Vector512<uint>.Zero));
+ Check("Avx512F.VL", ExpectedAvx512F, &Avx512FVLIsSupported, Avx512F.VL.IsSupported, null);
+ Check("Avx512F.X64", ExpectedAvx512F, &Avx512FX64IsSupported, Avx512F.X64.IsSupported, null);
- Check("Fma", FmaBmi12, &FmaIsSupported, Fma.IsSupported, () => Fma.MultiplyAdd(Vector128<float>.Zero, Vector128<float>.Zero, Vector128<float>.Zero).Equals(Vector128<float>.Zero));
- Check("Fma.X64", FmaBmi12, &FmaX64IsSupported, Fma.X64.IsSupported, null);
+ Check("Avx512BW", ExpectedAvx512BW, &Avx512BWIsSupported, Avx512BW.IsSupported, () => Avx512BW.Abs(Vector512<sbyte>.Zero).Equals(Vector512<byte>.Zero));
+ Check("Avx512BW.VL", ExpectedAvx512BW, &Avx512BWVLIsSupported, Avx512BW.VL.IsSupported, null);
+ Check("Avx512BW.X64", ExpectedAvx512BW, &Avx512BWX64IsSupported, Avx512BW.X64.IsSupported, null);
- Check("Lzcnt", AesLzPcl, &LzcntIsSupported, Lzcnt.IsSupported, () => Lzcnt.LeadingZeroCount(0) == 32);
- Check("Lzcnt.X64", AesLzPcl, &LzcntX64IsSupported, Lzcnt.X64.IsSupported, () => Lzcnt.X64.LeadingZeroCount(0) == 64);
+ Check("Avx512CD", ExpectedAvx512CD, &Avx512CDIsSupported, Avx512CD.IsSupported, () => Avx512CD.LeadingZeroCount(Vector512<uint>.AllBitsSet) == Vector512<uint>.Zero);
+ Check("Avx512CD.VL", ExpectedAvx512CD, &Avx512CDVLIsSupported, Avx512CD.VL.IsSupported, null);
+ Check("Avx512CD.X64", ExpectedAvx512CD, &Avx512CDX64IsSupported, Avx512CD.X64.IsSupported, null);
- Check("Pclmulqdq", AesLzPcl, &PclmulqdqIsSupported, Pclmulqdq.IsSupported, () => Pclmulqdq.CarrylessMultiply(Vector128<long>.Zero, Vector128<long>.Zero, 0).Equals(Vector128<long>.Zero));
- Check("Pclmulqdq.X64", AesLzPcl, &PclmulqdqX64IsSupported, Pclmulqdq.X64.IsSupported, null);
+ Check("Avx512DQ", ExpectedAvx512DQ, &Avx512DQIsSupported, Avx512DQ.IsSupported, () => Avx512DQ.And(Vector512<float>.Zero, Vector512<float>.Zero).Equals(Vector512<float>.Zero));
+ Check("Avx512DQ.VL", ExpectedAvx512DQ, &Avx512DQVLIsSupported, Avx512DQ.VL.IsSupported, null);
+ Check("Avx512DQ.X64", ExpectedAvx512DQ, &Avx512DQX64IsSupported, Avx512DQ.X64.IsSupported, null);
- Check("Popcnt", PopCnt, &PopcntIsSupported, Popcnt.IsSupported, () => Popcnt.PopCount(0) == 0);
- Check("Popcnt.X64", PopCnt, &PopcntX64IsSupported, Popcnt.X64.IsSupported, () => Popcnt.X64.PopCount(0) == 0);
+ Check("Avx512Vbmi", ExpectedAvx512Vbmi, &Avx512VbmiIsSupported, Avx512Vbmi.IsSupported, () => Avx512Vbmi.PermuteVar64x8(Vector512<sbyte>.Zero, Vector512<sbyte>.Zero).Equals(Vector512<sbyte>.Zero));
+ Check("Avx512Vbmi.VL", ExpectedAvx512Vbmi, &Avx512VbmiVLIsSupported, Avx512Vbmi.VL.IsSupported, null);
+ Check("Avx512Vbmi.X64", ExpectedAvx512Vbmi, &Avx512VbmiX64IsSupported, Avx512Vbmi.X64.IsSupported, null);
- Check("AvxVnni", Avxvnni, &AvxVnniIsSupported, AvxVnni.IsSupported, () => AvxVnni.MultiplyWideningAndAdd(Vector128<int>.Zero, Vector128<byte>.Zero, Vector128<sbyte>.Zero).Equals(Vector128<int>.Zero));
- Check("AvxVnni.X64", Avxvnni, &AvxVnniX64IsSupported, AvxVnni.X64.IsSupported, null);
+ Check("X86Serialize", ExpectedX86Serialize, &X86SerializeIsSupported, X86Serialize.IsSupported, () => { X86Serialize.Serialize(); return true; } );
+ Check("X86Serialize.X64", ExpectedX86Serialize, &X86SerializeX64IsSupported, X86Serialize.X64.IsSupported, null);
return s_success ? 100 : 1;
}
static bool PopcntX64IsSupported() => Popcnt.X64.IsSupported;
static bool AvxVnniIsSupported() => AvxVnni.IsSupported;
static bool AvxVnniX64IsSupported() => AvxVnni.X64.IsSupported;
+ static bool Avx512FIsSupported() => Avx512F.IsSupported;
+ static bool Avx512FVLIsSupported() => Avx512F.VL.IsSupported;
+ static bool Avx512FX64IsSupported() => Avx512F.X64.IsSupported;
+ static bool Avx512BWIsSupported() => Avx512BW.IsSupported;
+ static bool Avx512BWVLIsSupported() => Avx512BW.VL.IsSupported;
+ static bool Avx512BWX64IsSupported() => Avx512BW.X64.IsSupported;
+ static bool Avx512CDIsSupported() => Avx512CD.IsSupported;
+ static bool Avx512CDVLIsSupported() => Avx512CD.VL.IsSupported;
+ static bool Avx512CDX64IsSupported() => Avx512CD.X64.IsSupported;
+ static bool Avx512DQIsSupported() => Avx512DQ.IsSupported;
+ static bool Avx512DQVLIsSupported() => Avx512DQ.VL.IsSupported;
+ static bool Avx512DQX64IsSupported() => Avx512DQ.X64.IsSupported;
+ static bool Avx512VbmiIsSupported() => Avx512Vbmi.IsSupported;
+ static bool Avx512VbmiVLIsSupported() => Avx512Vbmi.VL.IsSupported;
+ static bool Avx512VbmiX64IsSupported() => Avx512Vbmi.X64.IsSupported;
+ static bool X86SerializeIsSupported() => X86Serialize.IsSupported;
+ static bool X86SerializeX64IsSupported() => X86Serialize.X64.IsSupported;
static bool IsConstantTrue(delegate*<bool> code)
{
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <CLRTestKind>BuildAndRun</CLRTestKind>
+ <CLRTestPriority>0</CLRTestPriority>
+ <CLRTestTargetUnsupported Condition="'$(TargetArchitecture)' != 'x64'">true</CLRTestTargetUnsupported>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <DefineConstants>$(DefineConstants);AVX_INTRINSICS;VECTORT128_INTRINSICS</DefineConstants>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <IlcArg Include="--instruction-set:avx" />
+ </ItemGroup>
+
+ <PropertyGroup>
+ <CLRTestBashPreCommands><![CDATA[
+$(CLRTestBashPreCommands)
+ if [[ "$OSTYPE" == "darwin"* ]]; then
+ sysctl -a
+ sysctl -a | grep machdep.cpu.leaf7_features | grep AVX >/dev/null
+ if [ $? -ne 0 ]; then
+ echo No support for AVX, test not applicable.
+ exit 0
+ fi
+ fi
+ if [[ "$OSTYPE" == "linux"* ]]; then
+ if ! grep -q '^flags.*avx' /proc/cpuinfo 2>/dev/null; then
+ echo No support for AVX, test not applicable.
+ exit 0
+ fi
+ fi
+]]></CLRTestBashPreCommands>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <Compile Include="Program.cs" />
+ </ItemGroup>
+</Project>
<CLRTestPriority>0</CLRTestPriority>
<CLRTestTargetUnsupported Condition="'$(TargetArchitecture)' != 'x64'">true</CLRTestTargetUnsupported>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
- <DefineConstants>$(DefineConstants);VEX_INTRINSICS</DefineConstants>
+ <DefineConstants>$(DefineConstants);AVX2_INTRINSICS;VECTORT256_INTRINSICS</DefineConstants>
</PropertyGroup>
<ItemGroup>
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <CLRTestKind>BuildAndRun</CLRTestKind>
+ <CLRTestPriority>0</CLRTestPriority>
+ <CLRTestTargetUnsupported Condition="'$(TargetArchitecture)' != 'x64' OR '$(TargetsOSX)' == 'true'">true</CLRTestTargetUnsupported>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <DefineConstants>$(DefineConstants);AVX512_INTRINSICS;VECTORT256_INTRINSICS</DefineConstants>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <IlcArg Include="--instruction-set:avx512f,avx512f_vl,avx512bw,avx512bw_vl,avx512cd,avx512cd_vl,avx512dq,avx512dq_vl" />
+ </ItemGroup>
+
+ <PropertyGroup>
+ <CLRTestBashPreCommands><![CDATA[
+$(CLRTestBashPreCommands)
+ if [[ "$OSTYPE" == "linux"* ]]; then
+ if ! grep -q '^flags.*avx512' /proc/cpuinfo 2>/dev/null; then
+ echo No support for AVX512, test not applicable.
+ exit 0
+ fi
+ fi
+]]></CLRTestBashPreCommands>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <Compile Include="Program.cs" />
+ </ItemGroup>
+</Project>
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <CLRTestKind>BuildAndRun</CLRTestKind>
+ <CLRTestPriority>0</CLRTestPriority>
+ <CLRTestTargetUnsupported Condition="'$(TargetArchitecture)' != 'x64'">true</CLRTestTargetUnsupported>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <DefineConstants>$(DefineConstants);AVX_INTRINSICS;VECTORT128_INTRINSICS</DefineConstants>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <IlcArg Include="--instruction-set:avx,-avx2" />
+ </ItemGroup>
+
+ <PropertyGroup>
+ <CLRTestBashPreCommands><![CDATA[
+$(CLRTestBashPreCommands)
+ if [[ "$OSTYPE" == "darwin"* ]]; then
+ sysctl -a
+ sysctl -a | grep machdep.cpu.leaf7_features | grep AVX >/dev/null
+ if [ $? -ne 0 ]; then
+ echo No support for AVX, test not applicable.
+ exit 0
+ fi
+ fi
+ if [[ "$OSTYPE" == "linux"* ]]; then
+ if ! grep -q '^flags.*avx' /proc/cpuinfo 2>/dev/null; then
+ echo No support for AVX, test not applicable.
+ exit 0
+ fi
+ fi
+]]></CLRTestBashPreCommands>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <Compile Include="Program.cs" />
+ </ItemGroup>
+</Project>
<CLRTestPriority>0</CLRTestPriority>
<CLRTestTargetUnsupported Condition="'$(TargetArchitecture)' != 'x64'">true</CLRTestTargetUnsupported>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
- <DefineConstants>$(DefineConstants);BASELINE_INTRINSICS</DefineConstants>
+ <DefineConstants>$(DefineConstants);BASELINE_INTRINSICS;VECTORT128_INTRINSICS</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<CLRTestPriority>0</CLRTestPriority>
<CLRTestTargetUnsupported Condition="'$(TargetArchitecture)' != 'x64'">true</CLRTestTargetUnsupported>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
- <DefineConstants>$(DefineConstants);NON_VEX_INTRINSICS</DefineConstants>
+ <DefineConstants>$(DefineConstants);SSE42_INTRINSICS;VECTORT128_INTRINSICS</DefineConstants>
</PropertyGroup>
<ItemGroup>
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+
+using System;
+using System.Numerics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics.X86;
+using System.Runtime.Intrinsics;
+using System.Reflection;
+
+namespace IntelHardwareIntrinsicTest._CpuId
+{
+ public class Program
+ {
+ const int Pass = 100;
+ const int Fail = 0;
+
+ public unsafe static int Main()
+ {
+ int testResult = Pass;
+
+ if (!X86Base.IsSupported)
+ {
+ return testResult;
+ }
+
+ (int eax, int ebx, int ecx, int edx) = X86Base.CpuId(0x00000000, 0x00000000);
+
+ bool isAuthenticAmd = (ebx == 0x68747541) && (ecx == 0x444D4163) && (edx == 0x69746E65);
+ bool isGenuineIntel = (ebx == 0x756E6547) && (ecx == 0x6C65746E) && (edx == 0x49656E69);
+ bool isVirtualCPU = (ebx == 0x74726956) && (ecx == 0x20555043) && (edx == 0x206C6175);
+
+ if (!isAuthenticAmd && !isGenuineIntel && !isVirtualCPU)
+ {
+ // CPUID checks are vendor specific and aren't guaranteed to match up, even across Intel/AMD
+ // as such, we limit ourselves to just AuthenticAMD, GenuineIntel and "Virtual CPU" right now. Any other
+ // vendors would need to be validated against the checks below and added to the list as necessary.
+
+ // An example of a difference is Intel/AMD for LZCNT. While the same underlying bit is used to
+ // represent presence of the LZCNT instruction, AMD began using this bit around 2007 for its
+ // ABM instruction set, which indicates LZCNT and POPCNT. Intel introduced a separate bit for
+ // POPCNT and didn't actually implement LZCNT and begin using the LZCNT bit until 2013. So
+ // while everything happens to line up today, it doesn't always and may not always do so.
+
+ Console.WriteLine($"Unrecognized CPU vendor: EBX: {ebx:X8}, ECX: {ecx:X8}, EDX: {edx:X8}");
+ testResult = Fail;
+ }
+
+ uint maxFunctionId = (uint)eax;
+
+ if (maxFunctionId < 0x00000001)
+ {
+ return testResult;
+ }
+
+ bool isX86BaseDisabled = !GetDotnetEnable("HWINTRINSIC");
+ bool isHierarchyDisabled = isX86BaseDisabled;
+
+ (eax, ebx, ecx, edx) = X86Base.CpuId(0x00000001, 0x00000000);
+
+ if (IsBitIncorrect(edx, 25, typeof(Sse), Sse.IsSupported, "SSE", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsBitIncorrect(edx, 26, typeof(Sse2), Sse2.IsSupported, "SSE2", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ bool isSse2HierarchyDisabled = isHierarchyDisabled;
+
+ if (IsBitIncorrect(ecx, 25, typeof(Aes), Aes.IsSupported, "AES", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ isHierarchyDisabled = isSse2HierarchyDisabled;
+
+ if (IsBitIncorrect(ecx, 1, typeof(Pclmulqdq), Pclmulqdq.IsSupported, "PCLMULQDQ", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ isHierarchyDisabled = isSse2HierarchyDisabled;
+
+ if (IsBitIncorrect(ecx, 0, typeof(Sse3), Sse3.IsSupported, "SSE3", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsBitIncorrect(ecx, 9, typeof(Ssse3), Ssse3.IsSupported, "SSSE3", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsBitIncorrect(ecx, 19, typeof(Sse41), Sse41.IsSupported, "SSE41", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsBitIncorrect(ecx, 20, typeof(Sse42), Sse42.IsSupported, "SSE42", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ bool isSse42HierarchyDisabled = isHierarchyDisabled;
+
+ if (IsBitIncorrect(ecx, 23, typeof(Popcnt), Popcnt.IsSupported, "POPCNT", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ isHierarchyDisabled = isSse42HierarchyDisabled;
+
+ if (IsBitIncorrect(ecx, 28, typeof(Avx), Avx.IsSupported, "AVX", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ bool isAvxHierarchyDisabled = isHierarchyDisabled;
+
+ if (IsBitIncorrect(ecx, 12, typeof(Fma), Fma.IsSupported, "FMA", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ bool isFmaHierarchyDisabled = isHierarchyDisabled;
+
+ if (maxFunctionId < 0x00000007)
+ {
+ return testResult;
+ }
+
+ (eax, ebx, ecx, edx) = X86Base.CpuId(0x00000007, 0x00000000);
+
+ isHierarchyDisabled = isAvxHierarchyDisabled;
+
+ if (IsBitIncorrect(ebx, 5, typeof(Avx2), Avx2.IsSupported, "AVX2", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ bool isAvx2HierarchyDisabled = isHierarchyDisabled;
+
+ if (IsBitIncorrect(ebx, 3, typeof(Bmi1), Bmi1.IsSupported, "BMI1", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ isHierarchyDisabled = isAvx2HierarchyDisabled;
+
+ if (IsBitIncorrect(ebx, 8, typeof(Bmi2), Bmi2.IsSupported, "BMI2", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ isHierarchyDisabled = isAvx2HierarchyDisabled | isFmaHierarchyDisabled | OperatingSystem.IsMacOS();
+
+ for (int i = 0; i < 2; i++)
+ {
+ // The runtime currently requires that all of F + BW + CD + DQ + VL be supported together or none
+ // are supported. To handle this we simple check them all twice so that if any of them are disabled
+ // the first time around, we'll then assert that they are all actually disabled the second time around
+
+ if (IsBitIncorrect(ebx, 16, typeof(Avx512F), Avx512F.IsSupported, "AVX512F", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsBitIncorrect(ebx, 31, typeof(Avx512F.VL), Avx512F.VL.IsSupported, "AVX512F_VL", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsBitIncorrect(ebx, 30, typeof(Avx512BW), Avx512BW.IsSupported, "AVX512BW", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsBitIncorrect(ebx, 30, typeof(Avx512BW.VL), Avx512BW.VL.IsSupported, "AVX512BW_VL", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsBitIncorrect(ebx, 28, typeof(Avx512CD), Avx512CD.IsSupported, "AVX512CD", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsBitIncorrect(ebx, 28, typeof(Avx512CD.VL), Avx512CD.VL.IsSupported, "AVX512CD_VL", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsBitIncorrect(ebx, 17, typeof(Avx512DQ), Avx512DQ.IsSupported, "AVX512DQ", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsBitIncorrect(ebx, 17, typeof(Avx512DQ.VL), Avx512DQ.VL.IsSupported, "AVX512DQ_VL", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+ }
+
+ bool isAvx512HierarchyDisabled = isHierarchyDisabled;
+
+ if (IsBitIncorrect(ecx, 1, typeof(Avx512Vbmi), Avx512Vbmi.IsSupported, "AVX512VBMI", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsBitIncorrect(ecx, 1, typeof(Avx512Vbmi.VL), Avx512Vbmi.VL.IsSupported, "AVX512VBMI_VL", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ isHierarchyDisabled = isX86BaseDisabled;
+
+ if (IsBitIncorrect(edx, 14, typeof(X86Serialize), X86Serialize.IsSupported, "SERIALIZE", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ (eax, ebx, ecx, edx) = X86Base.CpuId(0x00000007, 0x00000001);
+
+ isHierarchyDisabled = isAvx2HierarchyDisabled;
+
+#pragma warning disable CA2252 // No need to opt into preview feature for an internal test
+ if (IsBitIncorrect(eax, 4, typeof(AvxVnni), AvxVnni.IsSupported, "AVXVNNI", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+#pragma warning restore CA2252
+
+ (eax, ebx, ecx, edx) = X86Base.CpuId(unchecked((int)0x80000000), 0x00000000);
+
+ uint maxFunctionIdEx = (uint)eax;
+
+ if (maxFunctionIdEx < 0x00000001)
+ {
+ return testResult;
+ }
+
+ (eax, ebx, ecx, edx) = X86Base.CpuId(unchecked((int)0x80000001), 0x00000000);
+
+ isHierarchyDisabled = isX86BaseDisabled;
+
+ if (IsBitIncorrect(ecx, 5, typeof(Lzcnt), Lzcnt.IsSupported, "LZCNT", ref isHierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsIncorrect(typeof(Vector64), Vector64.IsHardwareAccelerated, isHierarchyDisabled: true))
+ {
+ testResult = Fail;
+ }
+
+ if (IsIncorrect(typeof(Vector128), Vector128.IsHardwareAccelerated, isSse2HierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsIncorrect(typeof(Vector256), Vector256.IsHardwareAccelerated, isAvx2HierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsIncorrect(typeof(Vector512), Vector512.IsHardwareAccelerated, isAvx512HierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (IsIncorrect(typeof(Vector), Vector.IsHardwareAccelerated, isSse2HierarchyDisabled))
+ {
+ testResult = Fail;
+ }
+
+ if (Vector<byte>.Count == 16)
+ {
+ if (!isAvx2HierarchyDisabled)
+ {
+ Console.WriteLine($"{typeof(Vector).FullName}.Count returned 16 but the hardware returned 32");
+ testResult = Fail;
+ }
+ }
+ else if (Vector<byte>.Count == 32)
+ {
+ if (isAvx2HierarchyDisabled)
+ {
+ Console.WriteLine($"{typeof(Vector).FullName}.Count returned 32 but the hardware returned 16");
+ testResult = Fail;
+ }
+ }
+ else
+ {
+ Console.WriteLine($"{typeof(Vector).FullName}.Count returned {Vector<byte>.Count} which is unexpected");
+ testResult = Fail;
+ }
+
+ if (Vector<byte>.Count != (int)typeof(Vector<byte>).GetProperty("Count")!.GetValue(null)!)
+ {
+ Console.WriteLine($"{typeof(Vector).FullName}.Count returned a different result when called via reflection");
+ testResult = Fail;
+ }
+
+ return testResult;
+ }
+
+ static bool IsBitIncorrect(int register, int bitNumber, Type isa, bool isSupported, string name, ref bool isHierarchyDisabled)
+ {
+ bool isSupportedByHardware = (register & (1 << bitNumber)) != 0;
+ isHierarchyDisabled |= !GetDotnetEnable(name);
+
+ if (isSupported)
+ {
+ if (!isSupportedByHardware)
+ {
+ Console.WriteLine($"{isa.FullName}.IsSupported returned true but the hardware returned false");
+ return true;
+ }
+
+ if (isHierarchyDisabled)
+ {
+ Console.WriteLine($"{isa.FullName}.IsSupported returned true but the runtime returned false");
+ return true;
+ }
+ }
+ else if (isSupportedByHardware)
+ {
+ if (!isHierarchyDisabled)
+ {
+ Console.WriteLine($"{isa.FullName}.IsSupported returned false but the hardware and runtime returned true");
+ return true;
+ }
+ }
+ else
+ {
+ // The IsSupported query returned false and the hardware
+ // says its unsupported, so we're all good
+ }
+
+ if (isSupported != (bool)isa.GetProperty("IsSupported")!.GetValue(null)!)
+ {
+ Console.WriteLine($"{isa.FullName}.IsSupported returned a different result when called via reflection");
+ return true;
+ }
+
+ return false;
+ }
+
+ static bool IsIncorrect(Type isa, bool isHardwareAccelerated, bool isHierarchyDisabled)
+ {
+ if (isHardwareAccelerated)
+ {
+ if (isHierarchyDisabled)
+ {
+ Console.WriteLine($"{isa.FullName}.IsHardwareAccelerated returned true but the runtime returned false");
+ return true;
+ }
+ }
+ else if (!isHierarchyDisabled)
+ {
+ Console.WriteLine($"{isa.FullName}.IsHardwareAccelerated returned false but the hardware and runtime returned true");
+ return true;
+ }
+
+ if (isHardwareAccelerated != (bool)isa.GetProperty("IsHardwareAccelerated")!.GetValue(null)!)
+ {
+ Console.WriteLine($"{isa.FullName}.IsHardwareAccelerated returned a different result when called via reflection");
+ return true;
+ }
+
+ return false;
+ }
+
+ static bool GetDotnetEnable(string name)
+ {
+ string? stringValue = Environment.GetEnvironmentVariable($"DOTNET_Enable{name}");
+
+ if ((stringValue is null) || !int.TryParse(stringValue, out int value))
+ {
+ // Hardware Intrinsic configuration knobs default to true
+ return true;
+ }
+
+ return value != 0;
+ }
+ }
+}
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <CLRTestKind>BuildAndRun</CLRTestKind>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <CLRTestTargetUnsupported Condition="('$(TargetArchitecture)' != 'x64' AND '$(TargetArchitecture)' != 'x86') OR ('$(RuntimeFlavor)' != 'coreclr')">true</CLRTestTargetUnsupported>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <AlwaysUseCrossGen2>true</AlwaysUseCrossGen2>
+ <IlasmRoundTripIncompatible>true</IlasmRoundTripIncompatible>
+ <NativeAotIncompatible>true</NativeAotIncompatible>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <CrossGen2TestExtraArguments>$(CrossGen2TestExtraArguments) --instruction-set:avx</CrossGen2TestExtraArguments>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <Compile Include="CpuId.cs" />
+ </ItemGroup>
+</Project>
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <CLRTestKind>BuildAndRun</CLRTestKind>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <CLRTestTargetUnsupported Condition="('$(TargetArchitecture)' != 'x64' AND '$(TargetArchitecture)' != 'x86') OR ('$(RuntimeFlavor)' != 'coreclr')">true</CLRTestTargetUnsupported>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <AlwaysUseCrossGen2>true</AlwaysUseCrossGen2>
+ <IlasmRoundTripIncompatible>true</IlasmRoundTripIncompatible>
+ <NativeAotIncompatible>true</NativeAotIncompatible>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <CrossGen2TestExtraArguments>$(CrossGen2TestExtraArguments) --instruction-set:avx2</CrossGen2TestExtraArguments>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <Compile Include="CpuId.cs" />
+ </ItemGroup>
+</Project>
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <CLRTestKind>BuildAndRun</CLRTestKind>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <CLRTestTargetUnsupported Condition="('$(TargetArchitecture)' != 'x64' AND '$(TargetArchitecture)' != 'x86') OR ('$(RuntimeFlavor)' != 'coreclr')">true</CLRTestTargetUnsupported>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <AlwaysUseCrossGen2>true</AlwaysUseCrossGen2>
+ <IlasmRoundTripIncompatible>true</IlasmRoundTripIncompatible>
+ <NativeAotIncompatible>true</NativeAotIncompatible>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <CrossGen2TestExtraArguments>$(CrossGen2TestExtraArguments) --instruction-set:avx512f,avx512f_vl,avx512bw,avx512bw_vl,avx512cd,avx512cd_vl,avx512dq,avx512dq_vl</CrossGen2TestExtraArguments>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <Compile Include="CpuId.cs" />
+ </ItemGroup>
+</Project>
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <CLRTestKind>BuildAndRun</CLRTestKind>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <CLRTestTargetUnsupported Condition="('$(TargetArchitecture)' != 'x64' AND '$(TargetArchitecture)' != 'x86') OR ('$(RuntimeFlavor)' != 'coreclr')">true</CLRTestTargetUnsupported>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <AlwaysUseCrossGen2>true</AlwaysUseCrossGen2>
+ <IlasmRoundTripIncompatible>true</IlasmRoundTripIncompatible>
+ <NativeAotIncompatible>true</NativeAotIncompatible>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <CrossGen2TestExtraArguments>$(CrossGen2TestExtraArguments) --instruction-set:avx,-avx2</CrossGen2TestExtraArguments>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <Compile Include="CpuId.cs" />
+ </ItemGroup>
+</Project>
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <CLRTestKind>BuildAndRun</CLRTestKind>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <CLRTestTargetUnsupported Condition="('$(TargetArchitecture)' != 'x64' AND '$(TargetArchitecture)' != 'x86') OR ('$(RuntimeFlavor)' != 'coreclr')">true</CLRTestTargetUnsupported>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <AlwaysUseCrossGen2>true</AlwaysUseCrossGen2>
+ <IlasmRoundTripIncompatible>true</IlasmRoundTripIncompatible>
+ <NativeAotIncompatible>true</NativeAotIncompatible>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <Compile Include="CpuId.cs" />
+ </ItemGroup>
+</Project>
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <CLRTestKind>BuildAndRun</CLRTestKind>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <CLRTestTargetUnsupported Condition="('$(TargetArchitecture)' != 'x64' AND '$(TargetArchitecture)' != 'x86') OR ('$(RuntimeFlavor)' != 'coreclr')">true</CLRTestTargetUnsupported>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <AlwaysUseCrossGen2>true</AlwaysUseCrossGen2>
+ <IlasmRoundTripIncompatible>true</IlasmRoundTripIncompatible>
+ <NativeAotIncompatible>true</NativeAotIncompatible>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <CrossGen2TestExtraArguments>$(CrossGen2TestExtraArguments) --instruction-set:sse4.2</CrossGen2TestExtraArguments>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <Compile Include="CpuId.cs" />
+ </ItemGroup>
+</Project>