From d5e1c77f98d4c0c923e7ce5e428fad0fc588bc0e Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Thu, 18 May 2023 22:37:44 -0700 Subject: [PATCH 01/24] Fixing the InstructionSetDesc implications --- src/coreclr/inc/corinfoinstructionset.h | 32 +++++++++ src/coreclr/inc/jiteeversionguid.h | 10 +-- .../nativeaot/Runtime/IntrinsicConstants.h | 1 + src/coreclr/nativeaot/Runtime/startup.cpp | 72 +++++++++++-------- .../tools/Common/InstructionSetHelpers.cs | 21 ++++++ .../JitInterface/CorInfoInstructionSet.cs | 68 +++++++++++++++++- .../ThunkGenerator/InstructionSetDesc.txt | 17 ++++- .../Compiler/HardwareIntrinsicHelpers.Aot.cs | 3 + src/coreclr/vm/codeman.cpp | 37 +++++----- 9 files changed, 206 insertions(+), 55 deletions(-) diff --git a/src/coreclr/inc/corinfoinstructionset.h b/src/coreclr/inc/corinfoinstructionset.h index 8462ab33413ef..d19a6ad75b9c9 100644 --- a/src/coreclr/inc/corinfoinstructionset.h +++ b/src/coreclr/inc/corinfoinstructionset.h @@ -566,24 +566,40 @@ inline CORINFO_InstructionSetFlags EnsureInstructionSetFlagsAreValid(CORINFO_Ins 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)) @@ -630,24 +646,40 @@ inline CORINFO_InstructionSetFlags EnsureInstructionSetFlagsAreValid(CORINFO_Ins 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)); diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index eee46d6068395..9bb39b00de8d7 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID; #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} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/nativeaot/Runtime/IntrinsicConstants.h b/src/coreclr/nativeaot/Runtime/IntrinsicConstants.h index 67ba547488e96..ad7d2e11ee69a 100644 --- a/src/coreclr/nativeaot/Runtime/IntrinsicConstants.h +++ b/src/coreclr/nativeaot/Runtime/IntrinsicConstants.h @@ -34,6 +34,7 @@ enum XArchIntrinsicConstants XArchIntrinsicConstants_Avx512dq_vl = 0x400000, XArchIntrinsicConstants_Avx512Vbmi = 0x800000, XArchIntrinsicConstants_Avx512Vbmi_vl = 0x1000000, + XArchIntrinsicConstants_Serialize = 0x2000000, }; #endif //HOST_X86 || HOST_AMD64 diff --git a/src/coreclr/nativeaot/Runtime/startup.cpp b/src/coreclr/nativeaot/Runtime/startup.cpp index ed44c9e948a48..a713af3b906b8 100644 --- a/src/coreclr/nativeaot/Runtime/startup.cpp +++ b/src/coreclr/nativeaot/Runtime/startup.cpp @@ -197,51 +197,57 @@ bool DetectCPUFeatures() { __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; } @@ -250,66 +256,67 @@ bool DetectCPUFeatures() { __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; + } } } } @@ -333,6 +340,11 @@ bool DetectCPUFeatures() { g_cpuFeatures |= XArchIntrinsicConstants_Bmi2; } + + if ((cpuidInfo[CPUID_EDX] & (1 << 14)) != 0) + { + g_cpuFeatures |= XArchIntrinsicConstants_Serialize; // SERIALIZE + } } } diff --git a/src/coreclr/tools/Common/InstructionSetHelpers.cs b/src/coreclr/tools/Common/InstructionSetHelpers.cs index 8aa5705916ded..6c9c574c843b7 100644 --- a/src/coreclr/tools/Common/InstructionSetHelpers.cs +++ b/src/coreclr/tools/Common/InstructionSetHelpers.cs @@ -93,16 +93,34 @@ public static InstructionSetSupport ConfigureInstructionSetSupport(string instru 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 usage + // optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("avx2"); optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("fma"); optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("bmi"); optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("bmi2"); optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("avxvnni"); } + + 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) { @@ -111,6 +129,9 @@ public static InstructionSetSupport ConfigureInstructionSetSupport(string instru optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("sha1"); optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("sha2"); optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("lse"); + optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("dotprod"); + optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("rdma"); + optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("rcpc"); } optimisticInstructionSetSupportBuilder.ComputeInstructionSetFlags(out var optimisticInstructionSet, out _, diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoInstructionSet.cs b/src/coreclr/tools/Common/JitInterface/CorInfoInstructionSet.cs index df6c06206bf84..1557059b76ab6 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoInstructionSet.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoInstructionSet.cs @@ -690,24 +690,40 @@ public static InstructionSetFlags ExpandInstructionSetByImplicationHelper(Target 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: @@ -755,24 +771,40 @@ public static InstructionSetFlags ExpandInstructionSetByImplicationHelper(Target 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)); @@ -935,24 +967,40 @@ private static InstructionSetFlags ExpandInstructionSetByReverseImplicationHelpe 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: @@ -1000,24 +1048,40 @@ private static InstructionSetFlags ExpandInstructionSetByReverseImplicationHelpe 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)); @@ -1035,8 +1099,8 @@ private static InstructionSetFlags ExpandInstructionSetByReverseImplicationHelpe { ("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" }, diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt index d5f74271ed13f..929abc3643c85 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt @@ -115,16 +115,31 @@ implication ,X86 ,AVXVNNI ,AVX2 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 the 5 following 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 @@ -176,7 +191,7 @@ instructionsetgroup ,x86-x64 ,X64 X86 ,sse2 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 diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/HardwareIntrinsicHelpers.Aot.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/HardwareIntrinsicHelpers.Aot.cs index 1411ca7b6c794..b7e4ee14e57ac 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/HardwareIntrinsicHelpers.Aot.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/HardwareIntrinsicHelpers.Aot.cs @@ -111,6 +111,7 @@ private static class XArchIntrinsicConstants 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) { @@ -170,6 +171,8 @@ 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, diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index eba0c2cd1e88f..9371681c58af2 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -1516,9 +1516,12 @@ void EEJitManager::SetCpuInfo() 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); @@ -1535,50 +1538,50 @@ void EEJitManager::SetCpuInfo() { 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); } @@ -1610,19 +1613,19 @@ void EEJitManager::SetCpuInfo() { __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 } } @@ -1633,7 +1636,7 @@ void EEJitManager::SetCpuInfo() { __cpuid(cpuidInfo, 0x80000001); - if ((cpuidInfo[CPUID_ECX] & (1 << 5)) != 0) // LZCNT + if ((cpuidInfo[CPUID_ECX] & (1 << 5)) != 0) // LZCNT { CPUCompileFlags.Set(InstructionSet_LZCNT); } From 8e518a60306bb2f455716f7b0d8c42f0f9f8c69b Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 19 May 2023 07:06:15 -0700 Subject: [PATCH 02/24] Adding more NAOT smoke tests covering the missed instruction sets --- .../SmokeTests/HardwareIntrinsics/Program.cs | 145 ++++++++++++++---- .../HardwareIntrinsics/X64Avx.csproj | 38 +++++ .../{x64Vex.csproj => X64Avx2.csproj} | 2 +- .../HardwareIntrinsics/X64Avx512.csproj | 33 ++++ .../HardwareIntrinsics/X64Baseline.csproj | 2 +- .../{x64NonVex.csproj => X64Sse42.csproj} | 2 +- 6 files changed, 188 insertions(+), 34 deletions(-) create mode 100644 src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx.csproj rename src/tests/nativeaot/SmokeTests/HardwareIntrinsics/{x64Vex.csproj => X64Avx2.csproj} (91%) create mode 100644 src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx512.csproj rename src/tests/nativeaot/SmokeTests/HardwareIntrinsics/{x64NonVex.csproj => X64Sse42.csproj} (83%) diff --git a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs index 06f6a027c94dd..9817ccc1b8760 100644 --- a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs +++ b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs @@ -50,39 +50,82 @@ static int Main() // // The test is compiled with multiple defines to test this. -#if BASELINE_INTRINSICS bool vectorsAccelerated = true; - int byteVectorLength = 16; - bool? Sse2AndBelow = true; + bool? Sse12 = true; + +#if BASELINE_INTRINSICS bool? Sse3Group = null; bool? AesLzPcl = null; bool? Sse4142 = null; bool? PopCnt = null; - bool? Avx12 = false; - bool? FmaBmi12 = false; + bool? Avx1 = false; + bool? Avx2 = false; + bool? Fma = null; + bool? Bmi12 = null; bool? Avxvnni = false; -#elif NON_VEX_INTRINSICS - bool vectorsAccelerated = true; - int byteVectorLength = 16; - bool? Sse2AndBelow = true; + bool? Avx512Group = false; + bool? Avx512Vbmi = false; + bool? X86Serialize = null; +#elif SSE42_INTRINSICS bool? Sse3Group = true; bool? AesLzPcl = null; bool? Sse4142 = true; bool? PopCnt = null; - bool? Avx12 = false; - bool? FmaBmi12 = false; + bool? Avx1 = false; + bool? Avx2 = false; + bool? Fma = null; + bool? Bmi12 = null; bool? Avxvnni = false; -#elif VEX_INTRINSICS - bool vectorsAccelerated = true; - int byteVectorLength = 32; - bool? Sse2AndBelow = true; + bool? Avx512Group = false; + bool? Avx512Vbmi = false; + bool? X86Serialize = null; +#elif AVX_INTRINSIC + bool? Sse3Group = true; + bool? AesLzPcl = null; + bool? Sse4142 = true; + bool? PopCnt = null; + bool? Avx1 = true; + bool? Avx2 = false; + bool? Fma = null; + bool? Bmi12 = null; + bool? Avxvnni = null; + bool? Avx512Group = false; + bool? Avx512Vbmi = false; + bool? X86Serialize = null; +#elif AVX2_INTRINSICS + bool? Sse3Group = true; + bool? AesLzPcl = null; + bool? Sse4142 = true; + bool? PopCnt = null; + bool? Avx1 = true; + bool? Avx2 = true; + bool? Fma = null; + bool? Bmi12 = null; + bool? Avxvnni = null; + bool? Avx512Group = false; + bool? Avx512Vbmi = false; + bool? X86Serialize = null; +#elif AVX512_INTRINSICS bool? Sse3Group = true; bool? AesLzPcl = null; bool? Sse4142 = true; bool? PopCnt = null; - bool? Avx12 = true; - bool? FmaBmi12 = null; + bool? Avx1 = true; + bool? Avx2 = true; + bool? Fma = true; + bool? Bmi12 = null; bool? Avxvnni = null; + bool? Avx512Group = true; + bool? Avx512Vbmi = null; + bool? X86Serialize = null; +#else +#error Who dis? +#endif + +#if VECTORT128_INTRINSICS + int byteVectorLength = 16; +#elif VECTORT256_INTRINSICS + int byteVectorLength = 32; #else #error Who dis? #endif @@ -97,11 +140,11 @@ static int Main() throw new Exception($"Unexpected vector length - expected {byteVectorLength}, got {Vector.Count}"); } - Check("Sse", Sse2AndBelow, &SseIsSupported, Sse.IsSupported, () => Sse.Subtract(Vector128.Zero, Vector128.Zero).Equals(Vector128.Zero)); - Check("Sse.X64", Sse2AndBelow, &SseX64IsSupported, Sse.X64.IsSupported, () => Sse.X64.ConvertToInt64WithTruncation(Vector128.Zero) == 0); + Check("Sse", Sse12, &SseIsSupported, Sse.IsSupported, () => Sse.Subtract(Vector128.Zero, Vector128.Zero).Equals(Vector128.Zero)); + Check("Sse.X64", Sse12, &SseX64IsSupported, Sse.X64.IsSupported, () => Sse.X64.ConvertToInt64WithTruncation(Vector128.Zero) == 0); - Check("Sse2", Sse2AndBelow, &Sse2IsSupported, Sse2.IsSupported, () => Sse2.Extract(Vector128.Zero, 0) == 0); - Check("Sse2.X64", Sse2AndBelow, &Sse2X64IsSupported, Sse2.X64.IsSupported, () => Sse2.X64.ConvertToInt64(Vector128.Zero) == 0); + Check("Sse2", Sse12, &Sse2IsSupported, Sse2.IsSupported, () => Sse2.Extract(Vector128.Zero, 0) == 0); + Check("Sse2.X64", Sse12, &Sse2X64IsSupported, Sse2.X64.IsSupported, () => Sse2.X64.ConvertToInt64(Vector128.Zero) == 0); Check("Sse3", Sse3Group, &Sse3IsSupported, Sse3.IsSupported, () => Sse3.MoveHighAndDuplicate(Vector128.Zero).Equals(Vector128.Zero)); Check("Sse3.X64", Sse3Group, &Sse3X64IsSupported, Sse3.X64.IsSupported, null); @@ -118,20 +161,20 @@ static int Main() Check("Aes", AesLzPcl, &AesIsSupported, Aes.IsSupported, () => Aes.KeygenAssist(Vector128.Zero, 0).Equals(Vector128.Create((byte)99))); Check("Aes.X64", AesLzPcl, &AesX64IsSupported, Aes.X64.IsSupported, null); - Check("Avx", Avx12, &AvxIsSupported, Avx.IsSupported, () => Avx.Add(Vector256.Zero, Vector256.Zero).Equals(Vector256.Zero)); - Check("Avx.X64", Avx12, &AvxX64IsSupported, Avx.X64.IsSupported, null); + Check("Avx", Avx1, &AvxIsSupported, Avx.IsSupported, () => Avx.Add(Vector256.Zero, Vector256.Zero).Equals(Vector256.Zero)); + Check("Avx.X64", Avx1, &AvxX64IsSupported, Avx.X64.IsSupported, null); - Check("Avx2", Avx12, &Avx2IsSupported, Avx2.IsSupported, () => Avx2.Abs(Vector256.Zero).Equals(Vector256.Zero)); - Check("Avx2.X64", Avx12, &Avx2X64IsSupported, Avx2.X64.IsSupported, null); + Check("Avx2", Avx2, &Avx2IsSupported, Avx2.IsSupported, () => Avx2.Abs(Vector256.Zero).Equals(Vector256.Zero)); + Check("Avx2.X64", Avx2, &Avx2X64IsSupported, Avx2.X64.IsSupported, null); - 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("Bmi1", Bmi12, &Bmi1IsSupported, Bmi1.IsSupported, () => Bmi1.AndNot(0, 0) == 0); + Check("Bmi1.X64", Bmi12, &Bmi1X64IsSupported, Bmi1.X64.IsSupported, () => Bmi1.X64.AndNot(0, 0) == 0); - 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("Bmi2", Bmi12, &Bmi2IsSupported, Bmi2.IsSupported, () => Bmi2.MultiplyNoFlags(0, 0) == 0); + Check("Bmi2.X64", Bmi12, &Bmi2X64IsSupported, Bmi2.X64.IsSupported, () => Bmi2.X64.MultiplyNoFlags(0, 0) == 0); - Check("Fma", FmaBmi12, &FmaIsSupported, Fma.IsSupported, () => Fma.MultiplyAdd(Vector128.Zero, Vector128.Zero, Vector128.Zero).Equals(Vector128.Zero)); - Check("Fma.X64", FmaBmi12, &FmaX64IsSupported, Fma.X64.IsSupported, null); + Check("Fma", Fma, &FmaIsSupported, Fma.IsSupported, () => Fma.MultiplyAdd(Vector128.Zero, Vector128.Zero, Vector128.Zero).Equals(Vector128.Zero)); + Check("Fma.X64", Fma, &FmaX64IsSupported, Fma.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); @@ -145,6 +188,29 @@ static int Main() Check("AvxVnni", Avxvnni, &AvxVnniIsSupported, AvxVnni.IsSupported, () => AvxVnni.MultiplyWideningAndAdd(Vector128.Zero, Vector128.Zero, Vector128.Zero).Equals(Vector128.Zero)); Check("AvxVnni.X64", Avxvnni, &AvxVnniX64IsSupported, AvxVnni.X64.IsSupported, null); + Check("Avx512F", Avx512Group, &Avx512FIsSupported, Avx512F.IsSupported, () => Avx512F.Abs(Vector512.Zero).Equals(Vector512.Zero)); + Check("Avx512F.VL", Avx512Group, &Avx512FVLIsSupported, Avx512F.VL.IsSupported, null); + Check("Avx512F.X64", Avx512Group, &Avx512FX64IsSupported, Avx512F.X64.IsSupported, null); + + Check("Avx512BW", Avx512Group, &Avx512BWIsSupported, Avx512BW.IsSupported, () => Avx512F.Abs(Vector512.Zero).Equals(Vector512.Zero)); + Check("Avx512BW.VL", Avx512Group, &Avx512BWVLIsSupported, Avx512BW.VL.IsSupported, null); + Check("Avx512BW.X64", Avx512Group, &Avx512BWX64IsSupported, Avx512BW.X64.IsSupported, null); + + Check("Avx512CD", Avx512Group, &Avx512CDIsSupported, Avx512CD.IsSupported, null); + Check("Avx512CD.VL", Avx512Group, &Avx512CDVLIsSupported, Avx512CD.VL.IsSupported, null); + Check("Avx512CD.X64", Avx512Group, &Avx512CDX64IsSupported, Avx512CD.X64.IsSupported, null); + + Check("Avx512DQ", Avx512Group, &Avx512DQIsSupported, Avx512DQ.IsSupported, () => Avx512F.And(Vector512.Zero, Vector512.Zero).Equals(Vector512.Zero)); + Check("Avx512DQ.VL", Avx512Group, &Avx512DQVLIsSupported, Avx512DQ.VL.IsSupported, null); + Check("Avx512DQ.X64", Avx512Group, &Avx512DQX64IsSupported, Avx512DQ.X64.IsSupported, null); + + Check("Avx512Vbmi", Avx512Group, &Avx512VbmiIsSupported, Avx512Vbmi.IsSupported, () => Avx512F.PermuteVar64x8(Vector512.Zero, Vector512.Zero).Equals(Vector512.Zero)); + Check("Avx512Vbmi.VL", Avx512Group, &Avx512VbmiVLIsSupported, Avx512Vbmi.VL.IsSupported, null); + Check("Avx512Vbmi.X64", Avx512Group, &Avx512VbmiX64IsSupported, Avx512Vbmi.X64.IsSupported, null); + + Check("X86Serialize", X86Serialize, &X86SerializeIsSupported, X86Serialize.IsSupported, () => X86Serialize.Serialize()); + Check("X86Serialize.X64", X86Serialize, &X86SerializeX64IsSupported, X86Serialize.X64.IsSupported, () => null); + return s_success ? 100 : 1; } @@ -183,6 +249,23 @@ static int Main() 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* code) { diff --git a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx.csproj b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx.csproj new file mode 100644 index 0000000000000..3cf9043e062df --- /dev/null +++ b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx.csproj @@ -0,0 +1,38 @@ + + + Exe + BuildAndRun + 0 + true + true + $(DefineConstants);AVX_INTRINSICS;VECTORT128_INTRINSICS + + + + + + + + /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 +]]> + + + + + + diff --git a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/x64Vex.csproj b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx2.csproj similarity index 91% rename from src/tests/nativeaot/SmokeTests/HardwareIntrinsics/x64Vex.csproj rename to src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx2.csproj index 983436eab7d79..626f88edc7278 100644 --- a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/x64Vex.csproj +++ b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx2.csproj @@ -5,7 +5,7 @@ 0 true true - $(DefineConstants);VEX_INTRINSICS + $(DefineConstants);AVX2_INTRINSICS;VECTORT256_INTRINSICS diff --git a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx512.csproj b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx512.csproj new file mode 100644 index 0000000000000..2d89fea81c22d --- /dev/null +++ b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx512.csproj @@ -0,0 +1,33 @@ + + + Exe + BuildAndRun + 0 + true + true + $(DefineConstants);AVX512_INTRINSICS;VECTORT256_INTRINSICS + + + + + + + + /dev/null; then + echo No support for AVX512, test not applicable. + exit 0 + fi + fi +]]> + + + + + + \ No newline at end of file diff --git a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Baseline.csproj b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Baseline.csproj index e49eb84629044..9e5d0c79e268e 100644 --- a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Baseline.csproj +++ b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Baseline.csproj @@ -5,7 +5,7 @@ 0 true true - $(DefineConstants);BASELINE_INTRINSICS + $(DefineConstants);BASELINE_INTRINSICS;VECTORT128_INTRINSICS diff --git a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/x64NonVex.csproj b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Sse42.csproj similarity index 83% rename from src/tests/nativeaot/SmokeTests/HardwareIntrinsics/x64NonVex.csproj rename to src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Sse42.csproj index 5e8d35d67bf3d..bf1a725b11a44 100644 --- a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/x64NonVex.csproj +++ b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Sse42.csproj @@ -5,7 +5,7 @@ 0 true true - $(DefineConstants);NON_VEX_INTRINSICS + $(DefineConstants);SSE42_INTRINSICS;VECTORT128_INTRINSICS From 5e4eb47ad25370f64ec65b86f6694e96ef36542a Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 19 May 2023 07:33:24 -0700 Subject: [PATCH 03/24] Simplify the HasInstructionSet(Avx512F) check in compSetProcessor --- src/coreclr/jit/compiler.cpp | 37 ++++++------------------------------ src/coreclr/jit/compiler.h | 2 +- 2 files changed, 7 insertions(+), 32 deletions(-) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 1d7fbbffeab82..6b17c6fffde4d 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -2287,15 +2287,16 @@ void Compiler::compSetProcessor() // 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); @@ -2310,32 +2311,6 @@ void Compiler::compSetProcessor() preferredVectorByteLength = 256; } } - 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) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index a342604b9572b..070b115d6449f 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -8642,7 +8642,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // Get the number of bytes in a System.Numeric.Vector for the current compilation. // Note - cannot be used for System.Runtime.Intrinsic - unsigned getSIMDVectorRegisterByteLength() + uint32_t getSIMDVectorRegisterByteLength() { #if defined(TARGET_XARCH) if (compExactlyDependsOn(InstructionSet_AVX2)) From 89b5aff36ec6bb35c145777e55977305ef7e6806 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 19 May 2023 08:23:30 -0700 Subject: [PATCH 04/24] Fixing the NAOT smoke tests --- .../SmokeTests/HardwareIntrinsics/Program.cs | 270 ++++++++++-------- 1 file changed, 156 insertions(+), 114 deletions(-) diff --git a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs index 9817ccc1b8760..b1a56bf4882dc 100644 --- a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs +++ b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs @@ -50,74 +50,116 @@ static int Main() // // The test is compiled with multiple defines to test this. - bool vectorsAccelerated = true; - bool? Sse12 = true; + bool ExpectedVectorsAccelerated = true; + + bool? ExpectedSse = true; + bool? ExpectedSse2 = true; #if BASELINE_INTRINSICS - bool? Sse3Group = null; - bool? AesLzPcl = null; - bool? Sse4142 = null; - bool? PopCnt = null; - bool? Avx1 = false; - bool? Avx2 = false; - bool? Fma = null; - bool? Bmi12 = null; - bool? Avxvnni = false; - bool? Avx512Group = false; - bool? Avx512Vbmi = false; - bool? X86Serialize = null; + 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? Sse3Group = true; - bool? AesLzPcl = null; - bool? Sse4142 = true; - bool? PopCnt = null; - bool? Avx1 = false; - bool? Avx2 = false; - bool? Fma = null; - bool? Bmi12 = null; - bool? Avxvnni = false; - bool? Avx512Group = false; - bool? Avx512Vbmi = false; - bool? X86Serialize = null; -#elif AVX_INTRINSIC - bool? Sse3Group = true; - bool? AesLzPcl = null; - bool? Sse4142 = true; - bool? PopCnt = null; - bool? Avx1 = true; - bool? Avx2 = false; - bool? Fma = null; - bool? Bmi12 = null; - bool? Avxvnni = null; - bool? Avx512Group = false; - bool? Avx512Vbmi = false; - bool? X86Serialize = null; + 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 = null; + 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 AVX2_INTRINSICS - bool? Sse3Group = true; - bool? AesLzPcl = null; - bool? Sse4142 = true; - bool? PopCnt = null; - bool? Avx1 = true; - bool? Avx2 = true; - bool? Fma = null; - bool? Bmi12 = null; - bool? Avxvnni = null; - bool? Avx512Group = false; - bool? Avx512Vbmi = false; - bool? X86Serialize = null; + 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? Sse3Group = true; - bool? AesLzPcl = null; - bool? Sse4142 = true; - bool? PopCnt = null; - bool? Avx1 = true; - bool? Avx2 = true; - bool? Fma = true; - bool? Bmi12 = null; - bool? Avxvnni = null; - bool? Avx512Group = true; - bool? Avx512Vbmi = null; - bool? X86Serialize = null; + 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 @@ -130,9 +172,9 @@ static int Main() #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.Count) @@ -140,76 +182,76 @@ static int Main() throw new Exception($"Unexpected vector length - expected {byteVectorLength}, got {Vector.Count}"); } - Check("Sse", Sse12, &SseIsSupported, Sse.IsSupported, () => Sse.Subtract(Vector128.Zero, Vector128.Zero).Equals(Vector128.Zero)); - Check("Sse.X64", Sse12, &SseX64IsSupported, Sse.X64.IsSupported, () => Sse.X64.ConvertToInt64WithTruncation(Vector128.Zero) == 0); + Check("Sse", ExpectedSse, &SseIsSupported, Sse.IsSupported, () => Sse.Subtract(Vector128.Zero, Vector128.Zero).Equals(Vector128.Zero)); + Check("Sse.X64", ExpectedSse, &SseX64IsSupported, Sse.X64.IsSupported, () => Sse.X64.ConvertToInt64WithTruncation(Vector128.Zero) == 0); - Check("Sse2", Sse12, &Sse2IsSupported, Sse2.IsSupported, () => Sse2.Extract(Vector128.Zero, 0) == 0); - Check("Sse2.X64", Sse12, &Sse2X64IsSupported, Sse2.X64.IsSupported, () => Sse2.X64.ConvertToInt64(Vector128.Zero) == 0); + Check("Sse2", ExpectedSse2, &Sse2IsSupported, Sse2.IsSupported, () => Sse2.Extract(Vector128.Zero, 0) == 0); + Check("Sse2.X64", ExpectedSse2, &Sse2X64IsSupported, Sse2.X64.IsSupported, () => Sse2.X64.ConvertToInt64(Vector128.Zero) == 0); - Check("Sse3", Sse3Group, &Sse3IsSupported, Sse3.IsSupported, () => Sse3.MoveHighAndDuplicate(Vector128.Zero).Equals(Vector128.Zero)); - Check("Sse3.X64", Sse3Group, &Sse3X64IsSupported, Sse3.X64.IsSupported, null); + Check("Sse3", ExpectedSse3, &Sse3IsSupported, Sse3.IsSupported, () => Sse3.MoveHighAndDuplicate(Vector128.Zero).Equals(Vector128.Zero)); + Check("Sse3.X64", ExpectedSse3, &Sse3X64IsSupported, Sse3.X64.IsSupported, null); - Check("Ssse3", Sse3Group, &Ssse3IsSupported, Ssse3.IsSupported, () => Ssse3.Abs(Vector128.Zero).Equals(Vector128.Zero)); - Check("Ssse3.X64", Sse3Group, &Ssse3X64IsSupported, Ssse3.X64.IsSupported, null); + Check("Ssse3", ExpectedSsse3, &Ssse3IsSupported, Ssse3.IsSupported, () => Ssse3.Abs(Vector128.Zero).Equals(Vector128.Zero)); + Check("Ssse3.X64", ExpectedSsse3, &Ssse3X64IsSupported, Ssse3.X64.IsSupported, null); - Check("Sse41", Sse4142, &Sse41IsSupported, Sse41.IsSupported, () => Sse41.Max(Vector128.Zero, Vector128.Zero).Equals(Vector128.Zero)); - Check("Sse41.X64", Sse4142, &Sse41X64IsSupported, Sse41.X64.IsSupported, () => Sse41.X64.Extract(Vector128.Zero, 0) == 0); + Check("Sse41", ExpectedSse41, &Sse41IsSupported, Sse41.IsSupported, () => Sse41.Max(Vector128.Zero, Vector128.Zero).Equals(Vector128.Zero)); + Check("Sse41.X64", ExpectedSse41, &Sse41X64IsSupported, Sse41.X64.IsSupported, () => Sse41.X64.Extract(Vector128.Zero, 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("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", AesLzPcl, &AesIsSupported, Aes.IsSupported, () => Aes.KeygenAssist(Vector128.Zero, 0).Equals(Vector128.Create((byte)99))); - Check("Aes.X64", AesLzPcl, &AesX64IsSupported, Aes.X64.IsSupported, null); + Check("Aes", ExpectedAes, &AesIsSupported, Aes.IsSupported, () => Aes.KeygenAssist(Vector128.Zero, 0).Equals(Vector128.Create((byte)99))); + Check("Aes.X64", ExpectedAes, &AesX64IsSupported, Aes.X64.IsSupported, null); - Check("Avx", Avx1, &AvxIsSupported, Avx.IsSupported, () => Avx.Add(Vector256.Zero, Vector256.Zero).Equals(Vector256.Zero)); - Check("Avx.X64", Avx1, &AvxX64IsSupported, Avx.X64.IsSupported, null); + Check("Avx", ExpectedAvx, &AvxIsSupported, Avx.IsSupported, () => Avx.Add(Vector256.Zero, Vector256.Zero).Equals(Vector256.Zero)); + Check("Avx.X64", ExpectedAvx, &AvxX64IsSupported, Avx.X64.IsSupported, null); - Check("Avx2", Avx2, &Avx2IsSupported, Avx2.IsSupported, () => Avx2.Abs(Vector256.Zero).Equals(Vector256.Zero)); - Check("Avx2.X64", Avx2, &Avx2X64IsSupported, Avx2.X64.IsSupported, null); + Check("Avx2", ExpectedAvx2, &Avx2IsSupported, Avx2.IsSupported, () => Avx2.Abs(Vector256.Zero).Equals(Vector256.Zero)); + Check("Avx2.X64", ExpectedAvx, &Avx2X64IsSupported, Avx2.X64.IsSupported, null); - Check("Bmi1", Bmi12, &Bmi1IsSupported, Bmi1.IsSupported, () => Bmi1.AndNot(0, 0) == 0); - Check("Bmi1.X64", Bmi12, &Bmi1X64IsSupported, Bmi1.X64.IsSupported, () => Bmi1.X64.AndNot(0, 0) == 0); + 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("Bmi2", Bmi12, &Bmi2IsSupported, Bmi2.IsSupported, () => Bmi2.MultiplyNoFlags(0, 0) == 0); - Check("Bmi2.X64", Bmi12, &Bmi2X64IsSupported, Bmi2.X64.IsSupported, () => Bmi2.X64.MultiplyNoFlags(0, 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("Fma", Fma, &FmaIsSupported, Fma.IsSupported, () => Fma.MultiplyAdd(Vector128.Zero, Vector128.Zero, Vector128.Zero).Equals(Vector128.Zero)); - Check("Fma.X64", Fma, &FmaX64IsSupported, Fma.X64.IsSupported, null); + Check("Fma", ExpectedFma, &FmaIsSupported, Fma.IsSupported, () => Fma.MultiplyAdd(Vector128.Zero, Vector128.Zero, Vector128.Zero).Equals(Vector128.Zero)); + Check("Fma.X64", ExpectedFma, &FmaX64IsSupported, Fma.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("Lzcnt", ExpectedLzcnt, &LzcntIsSupported, Lzcnt.IsSupported, () => Lzcnt.LeadingZeroCount(0) == 32); + Check("Lzcnt.X64", ExpectedLzcnt, &LzcntX64IsSupported, Lzcnt.X64.IsSupported, () => Lzcnt.X64.LeadingZeroCount(0) == 64); - Check("Pclmulqdq", AesLzPcl, &PclmulqdqIsSupported, Pclmulqdq.IsSupported, () => Pclmulqdq.CarrylessMultiply(Vector128.Zero, Vector128.Zero, 0).Equals(Vector128.Zero)); - Check("Pclmulqdq.X64", AesLzPcl, &PclmulqdqX64IsSupported, Pclmulqdq.X64.IsSupported, null); + Check("Pclmulqdq", ExpectedPclmulqdq, &PclmulqdqIsSupported, Pclmulqdq.IsSupported, () => Pclmulqdq.CarrylessMultiply(Vector128.Zero, Vector128.Zero, 0).Equals(Vector128.Zero)); + Check("Pclmulqdq.X64", ExpectedPclmulqdq, &PclmulqdqX64IsSupported, Pclmulqdq.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("Popcnt", ExpectedPopcnt, &PopcntIsSupported, Popcnt.IsSupported, () => Popcnt.PopCount(0) == 0); + Check("Popcnt.X64", ExpectedPopcnt, &PopcntX64IsSupported, Popcnt.X64.IsSupported, () => Popcnt.X64.PopCount(0) == 0); - Check("AvxVnni", Avxvnni, &AvxVnniIsSupported, AvxVnni.IsSupported, () => AvxVnni.MultiplyWideningAndAdd(Vector128.Zero, Vector128.Zero, Vector128.Zero).Equals(Vector128.Zero)); - Check("AvxVnni.X64", Avxvnni, &AvxVnniX64IsSupported, AvxVnni.X64.IsSupported, null); + Check("AvxVnni", ExpectedAvxVnni, &AvxVnniIsSupported, AvxVnni.IsSupported, () => AvxVnni.MultiplyWideningAndAdd(Vector128.Zero, Vector128.Zero, Vector128.Zero).Equals(Vector128.Zero)); + Check("AvxVnni.X64", ExpectedAvxVnni, &AvxVnniX64IsSupported, AvxVnni.X64.IsSupported, null); - Check("Avx512F", Avx512Group, &Avx512FIsSupported, Avx512F.IsSupported, () => Avx512F.Abs(Vector512.Zero).Equals(Vector512.Zero)); - Check("Avx512F.VL", Avx512Group, &Avx512FVLIsSupported, Avx512F.VL.IsSupported, null); - Check("Avx512F.X64", Avx512Group, &Avx512FX64IsSupported, Avx512F.X64.IsSupported, null); + Check("Avx512F", ExpectedAvx512F, &Avx512FIsSupported, Avx512F.IsSupported, () => Avx512F.Abs(Vector512.Zero).Equals(Vector512.Zero)); + Check("Avx512F.VL", ExpectedAvx512F, &Avx512FVLIsSupported, Avx512F.VL.IsSupported, null); + Check("Avx512F.X64", ExpectedAvx512F, &Avx512FX64IsSupported, Avx512F.X64.IsSupported, null); - Check("Avx512BW", Avx512Group, &Avx512BWIsSupported, Avx512BW.IsSupported, () => Avx512F.Abs(Vector512.Zero).Equals(Vector512.Zero)); - Check("Avx512BW.VL", Avx512Group, &Avx512BWVLIsSupported, Avx512BW.VL.IsSupported, null); - Check("Avx512BW.X64", Avx512Group, &Avx512BWX64IsSupported, Avx512BW.X64.IsSupported, null); + Check("Avx512BW", ExpectedAvx512BW, &Avx512BWIsSupported, Avx512BW.IsSupported, () => Avx512F.Abs(Vector512.Zero).Equals(Vector512.Zero)); + Check("Avx512BW.VL", ExpectedAvx512BW && ExpectedAvx512VL, &Avx512BWVLIsSupported, Avx512BW.VL.IsSupported, null); + Check("Avx512BW.X64", ExpectedAvx512BW, &Avx512BWX64IsSupported, Avx512BW.X64.IsSupported, null); - Check("Avx512CD", Avx512Group, &Avx512CDIsSupported, Avx512CD.IsSupported, null); - Check("Avx512CD.VL", Avx512Group, &Avx512CDVLIsSupported, Avx512CD.VL.IsSupported, null); - Check("Avx512CD.X64", Avx512Group, &Avx512CDX64IsSupported, Avx512CD.X64.IsSupported, null); + Check("Avx512CD", ExpectedAvx512CD, &Avx512CDIsSupported, Avx512CD.IsSupported, null); + Check("Avx512CD.VL", ExpectedAvx512CD && ExpectedAvx512VL, &Avx512CDVLIsSupported, Avx512CD.VL.IsSupported, null); + Check("Avx512CD.X64", ExpectedAvx512CD, &Avx512CDX64IsSupported, Avx512CD.X64.IsSupported, null); - Check("Avx512DQ", Avx512Group, &Avx512DQIsSupported, Avx512DQ.IsSupported, () => Avx512F.And(Vector512.Zero, Vector512.Zero).Equals(Vector512.Zero)); - Check("Avx512DQ.VL", Avx512Group, &Avx512DQVLIsSupported, Avx512DQ.VL.IsSupported, null); - Check("Avx512DQ.X64", Avx512Group, &Avx512DQX64IsSupported, Avx512DQ.X64.IsSupported, null); + Check("Avx512DQ", ExpectedAvx512DQ, &Avx512DQIsSupported, Avx512DQ.IsSupported, () => Avx512F.And(Vector512.Zero, Vector512.Zero).Equals(Vector512.Zero)); + Check("Avx512DQ.VL", ExpectedAvx512DQ, &Avx512DQVLIsSupported, Avx512DQ.VL.IsSupported, null); + Check("Avx512DQ.X64", ExpectedAvx512DQ, &Avx512DQX64IsSupported, Avx512DQ.X64.IsSupported, null); - Check("Avx512Vbmi", Avx512Group, &Avx512VbmiIsSupported, Avx512Vbmi.IsSupported, () => Avx512F.PermuteVar64x8(Vector512.Zero, Vector512.Zero).Equals(Vector512.Zero)); - Check("Avx512Vbmi.VL", Avx512Group, &Avx512VbmiVLIsSupported, Avx512Vbmi.VL.IsSupported, null); - Check("Avx512Vbmi.X64", Avx512Group, &Avx512VbmiX64IsSupported, Avx512Vbmi.X64.IsSupported, null); + Check("Avx512Vbmi", ExpectedAvx512Vbmi, &Avx512VbmiIsSupported, Avx512Vbmi.IsSupported, () => Avx512F.PermuteVar64x8(Vector512.Zero, Vector512.Zero).Equals(Vector512.Zero)); + Check("Avx512Vbmi.VL", ExpectedAvx512Vbmi, &Avx512VbmiVLIsSupported, Avx512Vbmi.VL.IsSupported, null); + Check("Avx512Vbmi.X64", ExpectedAvx512Vbmi, &Avx512VbmiX64IsSupported, Avx512Vbmi.X64.IsSupported, null); - Check("X86Serialize", X86Serialize, &X86SerializeIsSupported, X86Serialize.IsSupported, () => X86Serialize.Serialize()); - Check("X86Serialize.X64", X86Serialize, &X86SerializeX64IsSupported, X86Serialize.X64.IsSupported, () => null); + Check("X86Serialize", ExpectedX86Serialize, &X86SerializeIsSupported, X86Serialize.IsSupported, () => X86Serialize.Serialize()); + Check("X86Serialize.X64", ExpectedX86Serialize, &X86SerializeX64IsSupported, X86Serialize.X64.IsSupported, () => null); return s_success ? 100 : 1; } From e4831f230bd526778d2a438e0d4e4e23290a738d Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 19 May 2023 10:21:18 -0700 Subject: [PATCH 05/24] Fixing some stale comments --- .../ThunkGenerator/InstructionSetDesc.txt | 2 +- src/coreclr/vm/codeman.cpp | 78 ------------------- 2 files changed, 1 insertion(+), 79 deletions(-) diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt index 929abc3643c85..1b8b2c1ce973a 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt @@ -131,7 +131,7 @@ implication ,X86 ,AVX512VBMI_VL ,AVX512VBMI implication ,X86 ,AVX512VBMI_VL ,AVX512BW_VL ; While the AVX-512 ISAs can be individually lit-up, they really -; need the 5 following to be fully functional without adding +; 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 diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index 9371681c58af2..cea589081e5b3 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -1347,84 +1347,6 @@ void EEJitManager::SetCpuInfo() // 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 { From a3fc57d989107fa6ed34cc1bfae86f3f8a5d4279 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 19 May 2023 10:23:24 -0700 Subject: [PATCH 06/24] Fixing build failure --- .../nativeaot/SmokeTests/HardwareIntrinsics/Program.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs index b1a56bf4882dc..91f598a11f71a 100644 --- a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs +++ b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs @@ -234,19 +234,19 @@ static int Main() Check("Avx512F.VL", ExpectedAvx512F, &Avx512FVLIsSupported, Avx512F.VL.IsSupported, null); Check("Avx512F.X64", ExpectedAvx512F, &Avx512FX64IsSupported, Avx512F.X64.IsSupported, null); - Check("Avx512BW", ExpectedAvx512BW, &Avx512BWIsSupported, Avx512BW.IsSupported, () => Avx512F.Abs(Vector512.Zero).Equals(Vector512.Zero)); - Check("Avx512BW.VL", ExpectedAvx512BW && ExpectedAvx512VL, &Avx512BWVLIsSupported, Avx512BW.VL.IsSupported, null); + Check("Avx512BW", ExpectedAvx512BW, &Avx512BWIsSupported, Avx512BW.IsSupported, () => Avx512BW.Abs(Vector512.Zero).Equals(Vector512.Zero)); + Check("Avx512BW.VL", ExpectedAvx512BW, &Avx512BWVLIsSupported, Avx512BW.VL.IsSupported, null); Check("Avx512BW.X64", ExpectedAvx512BW, &Avx512BWX64IsSupported, Avx512BW.X64.IsSupported, null); Check("Avx512CD", ExpectedAvx512CD, &Avx512CDIsSupported, Avx512CD.IsSupported, null); - Check("Avx512CD.VL", ExpectedAvx512CD && ExpectedAvx512VL, &Avx512CDVLIsSupported, Avx512CD.VL.IsSupported, null); + Check("Avx512CD.VL", ExpectedAvx512CD, &Avx512CDVLIsSupported, Avx512CD.VL.IsSupported, null); Check("Avx512CD.X64", ExpectedAvx512CD, &Avx512CDX64IsSupported, Avx512CD.X64.IsSupported, null); - Check("Avx512DQ", ExpectedAvx512DQ, &Avx512DQIsSupported, Avx512DQ.IsSupported, () => Avx512F.And(Vector512.Zero, Vector512.Zero).Equals(Vector512.Zero)); + Check("Avx512DQ", ExpectedAvx512DQ, &Avx512DQIsSupported, Avx512DQ.IsSupported, () => Avx512DQ.And(Vector512.Zero, Vector512.Zero).Equals(Vector512.Zero)); Check("Avx512DQ.VL", ExpectedAvx512DQ, &Avx512DQVLIsSupported, Avx512DQ.VL.IsSupported, null); Check("Avx512DQ.X64", ExpectedAvx512DQ, &Avx512DQX64IsSupported, Avx512DQ.X64.IsSupported, null); - Check("Avx512Vbmi", ExpectedAvx512Vbmi, &Avx512VbmiIsSupported, Avx512Vbmi.IsSupported, () => Avx512F.PermuteVar64x8(Vector512.Zero, Vector512.Zero).Equals(Vector512.Zero)); + Check("Avx512Vbmi", ExpectedAvx512Vbmi, &Avx512VbmiIsSupported, Avx512Vbmi.IsSupported, () => Avx512Vbmi.PermuteVar64x8(Vector512.Zero, Vector512.Zero).Equals(Vector512.Zero)); Check("Avx512Vbmi.VL", ExpectedAvx512Vbmi, &Avx512VbmiVLIsSupported, Avx512Vbmi.VL.IsSupported, null); Check("Avx512Vbmi.X64", ExpectedAvx512Vbmi, &Avx512VbmiX64IsSupported, Avx512Vbmi.X64.IsSupported, null); From 25843cb0d0fbcb3da873927dcf0a1ee30c8869e0 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 19 May 2023 13:29:45 -0700 Subject: [PATCH 07/24] Ensure the X86Serialize test lambda returns a bool --- src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs index 91f598a11f71a..f0a16ed7e8c5f 100644 --- a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs +++ b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs @@ -238,7 +238,7 @@ static int Main() Check("Avx512BW.VL", ExpectedAvx512BW, &Avx512BWVLIsSupported, Avx512BW.VL.IsSupported, null); Check("Avx512BW.X64", ExpectedAvx512BW, &Avx512BWX64IsSupported, Avx512BW.X64.IsSupported, null); - Check("Avx512CD", ExpectedAvx512CD, &Avx512CDIsSupported, Avx512CD.IsSupported, null); + Check("Avx512CD", ExpectedAvx512CD, &Avx512CDIsSupported, Avx512CD.IsSupported, () => Avx512CD.LeadingZeroCount(Vector512.AllBitsSet) == Vector512.Zero); Check("Avx512CD.VL", ExpectedAvx512CD, &Avx512CDVLIsSupported, Avx512CD.VL.IsSupported, null); Check("Avx512CD.X64", ExpectedAvx512CD, &Avx512CDX64IsSupported, Avx512CD.X64.IsSupported, null); @@ -250,7 +250,7 @@ static int Main() Check("Avx512Vbmi.VL", ExpectedAvx512Vbmi, &Avx512VbmiVLIsSupported, Avx512Vbmi.VL.IsSupported, null); Check("Avx512Vbmi.X64", ExpectedAvx512Vbmi, &Avx512VbmiX64IsSupported, Avx512Vbmi.X64.IsSupported, null); - Check("X86Serialize", ExpectedX86Serialize, &X86SerializeIsSupported, X86Serialize.IsSupported, () => X86Serialize.Serialize()); + Check("X86Serialize", ExpectedX86Serialize, &X86SerializeIsSupported, X86Serialize.IsSupported, () => { X86Serialize.Serialize(); return true; } ); Check("X86Serialize.X64", ExpectedX86Serialize, &X86SerializeX64IsSupported, X86Serialize.X64.IsSupported, () => null); return s_success ? 100 : 1; From 83cdd1930091cee9a5e2b8c490d35ef24f8971bc Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 19 May 2023 14:11:38 -0700 Subject: [PATCH 08/24] Fixing build failure --- src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs index f0a16ed7e8c5f..8a177ac8d5e61 100644 --- a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs +++ b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs @@ -251,7 +251,7 @@ static int Main() Check("Avx512Vbmi.X64", ExpectedAvx512Vbmi, &Avx512VbmiX64IsSupported, Avx512Vbmi.X64.IsSupported, null); Check("X86Serialize", ExpectedX86Serialize, &X86SerializeIsSupported, X86Serialize.IsSupported, () => { X86Serialize.Serialize(); return true; } ); - Check("X86Serialize.X64", ExpectedX86Serialize, &X86SerializeX64IsSupported, X86Serialize.X64.IsSupported, () => null); + Check("X86Serialize.X64", ExpectedX86Serialize, &X86SerializeX64IsSupported, X86Serialize.X64.IsSupported, null); return s_success ? 100 : 1; } From c4e9163edc814bd95ee9639327b20946129b0758 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Sat, 20 May 2023 10:26:06 -0700 Subject: [PATCH 09/24] Ensure AVX2 isn't opportunistically supported and that dynamic checks work correctly for Vector128/256/512.IsHardwareAccelerated --- src/coreclr/jit/hwintrinsic.cpp | 14 +++++++------- src/coreclr/tools/Common/InstructionSetHelpers.cs | 3 ++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index 35d1b6aa249bd..5c9ed7f64aae2 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -541,22 +541,22 @@ NamedIntrinsic HWIntrinsicInfo::lookupId(Compiler* comp, // // 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->compOpportunisticallyDependsOn(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; } } diff --git a/src/coreclr/tools/Common/InstructionSetHelpers.cs b/src/coreclr/tools/Common/InstructionSetHelpers.cs index 6c9c574c843b7..842cf978827a2 100644 --- a/src/coreclr/tools/Common/InstructionSetHelpers.cs +++ b/src/coreclr/tools/Common/InstructionSetHelpers.cs @@ -101,10 +101,11 @@ public static InstructionSetSupport ConfigureInstructionSetSupport(string instru { // TODO: Enable optimistic usage of AVX2 once we validate it doesn't break Vector usage // optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("avx2"); + // optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("avxvnni"); + optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("fma"); optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("bmi"); optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("bmi2"); - optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("avxvnni"); } Debug.Assert(InstructionSet.X64_AVX512F == InstructionSet.X86_AVX512F); From 3f771fd684a875e5a86002859733e17cba124c97 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Sun, 21 May 2023 06:57:33 -0700 Subject: [PATCH 10/24] Ensure Avx512Vbmi has [Intrinsic] on the right members --- .../Runtime/Intrinsics/X86/Avx512Vbmi.PlatformNotSupported.cs | 3 --- .../src/System/Runtime/Intrinsics/X86/Avx512Vbmi.cs | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Avx512Vbmi.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Avx512Vbmi.PlatformNotSupported.cs index a8e20ae997ad4..c4d60ffb6dee1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Avx512Vbmi.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Avx512Vbmi.PlatformNotSupported.cs @@ -7,7 +7,6 @@ namespace System.Runtime.Intrinsics.X86 { /// This class provides access to X86 AVX512VBMI hardware instructions via intrinsics - [Intrinsic] [CLSCompliant(false)] public abstract class Avx512Vbmi : Avx512BW { @@ -15,7 +14,6 @@ internal Avx512Vbmi() { } public static new bool IsSupported { [Intrinsic] get { return false; } } - [Intrinsic] public new abstract class VL : Avx512BW.VL { internal VL() { } @@ -71,7 +69,6 @@ internal VL() { } public static Vector256 PermuteVar32x8x2(Vector256 lower, Vector256 indices, Vector256 upper) { throw new PlatformNotSupportedException(); } } - [Intrinsic] public new abstract class X64 : Avx512BW.X64 { internal X64() { } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Avx512Vbmi.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Avx512Vbmi.cs index 633e1e5639e41..677bcdf479014 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Avx512Vbmi.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Avx512Vbmi.cs @@ -9,6 +9,7 @@ namespace System.Runtime.Intrinsics.X86 { /// This class provides access to X86 AVX512VBMI hardware instructions via intrinsics + [Intrinsic] [CLSCompliant(false)] public abstract class Avx512Vbmi : Avx512BW { @@ -16,6 +17,7 @@ internal Avx512Vbmi() { } public static new bool IsSupported { get => IsSupported; } + [Intrinsic] public new abstract class VL : Avx512BW.VL { internal VL() { } @@ -71,6 +73,7 @@ internal VL() { } public static Vector256 PermuteVar32x8x2(Vector256 lower, Vector256 indices, Vector256 upper) => PermuteVar32x8x2(lower, indices, upper); } + [Intrinsic] public new abstract class X64 : Avx512BW.X64 { internal X64() { } From c54994983a147c30270bc72f9b156b66fad111f1 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Mon, 22 May 2023 06:38:47 -0700 Subject: [PATCH 11/24] Fix the secondary isIsaSupported check to be properly opportunistic for NAOT --- src/coreclr/jit/hwintrinsic.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index 5c9ed7f64aae2..24d37bc03f0b2 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -495,9 +495,9 @@ NamedIntrinsic HWIntrinsicInfo::lookupId(Compiler* comp, 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) { @@ -548,7 +548,7 @@ NamedIntrinsic HWIntrinsicInfo::lookupId(Compiler* comp, // 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 && comp->compOpportunisticallyDependsOn(isa)) + if (isIsaSupported && comp->compSupportsHWIntrinsic(isa)) { if (!comp->IsTargetAbi(CORINFO_NATIVEAOT_ABI) || comp->compExactlyDependsOn(isa)) { From 569d624bb33883c3ab33ffcfd9b92d8ce33b6455 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Mon, 22 May 2023 12:18:39 -0700 Subject: [PATCH 12/24] Ensure vpermb is covered --- src/coreclr/jit/emitxarch.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index ce54be61350e7..6b9154d864a75 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -18825,6 +18825,7 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins case INS_vinserti32x8: case INS_vinserti64x2: case INS_vinserti64x4: + case INS_vpermb: case INS_vpermi2d: case INS_vpermi2pd: case INS_vpermi2ps: From 8b464faeeb8c0cecef700196bd2c29ddfee2314b Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Mon, 22 May 2023 13:45:24 -0700 Subject: [PATCH 13/24] Allow opportunistic AvxVnni when Avx2 is opted into --- src/coreclr/tools/Common/InstructionSetHelpers.cs | 10 +++++++++- .../src/ILLink/ILLink.Substitutions.NoX86Intrinsics.xm | 0 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.NoX86Intrinsics.xm diff --git a/src/coreclr/tools/Common/InstructionSetHelpers.cs b/src/coreclr/tools/Common/InstructionSetHelpers.cs index 842cf978827a2..93b04a1f7dbdd 100644 --- a/src/coreclr/tools/Common/InstructionSetHelpers.cs +++ b/src/coreclr/tools/Common/InstructionSetHelpers.cs @@ -101,13 +101,21 @@ public static InstructionSetSupport ConfigureInstructionSetSupport(string instru { // TODO: Enable optimistic usage of AVX2 once we validate it doesn't break Vector usage // optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("avx2"); - // optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("avxvnni"); + + if (supportedInstructionSet.HasInstructionSet(InstructionSet.X64_AVX2)) + { + optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("avxvnni"); + } optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("fma"); optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("bmi"); optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("bmi2"); } + if (supportedInstructionSet.HasInstructionSet(InstructionSet.X64_AVX2)) + { + } + Debug.Assert(InstructionSet.X64_AVX512F == InstructionSet.X86_AVX512F); if (supportedInstructionSet.HasInstructionSet(InstructionSet.X64_AVX512F)) { diff --git a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.NoX86Intrinsics.xm b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.NoX86Intrinsics.xm new file mode 100644 index 0000000000000..e69de29bb2d1d From 49ec14da42aadebb4551a3628aa6f3456d92e2d0 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Mon, 22 May 2023 14:27:32 -0700 Subject: [PATCH 14/24] Don't expect opportunistic Avx2 or AvxVnni in the smoke tests --- src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs index 8a177ac8d5e61..26f1f5532cc74 100644 --- a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs +++ b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs @@ -107,11 +107,11 @@ static int Main() bool? ExpectedSse42 = true; bool? ExpectedPopcnt = null; bool? ExpectedAvx = true; - bool? ExpectedAvx2 = null; + bool? ExpectedAvx2 = false; // TODO: Fix once opportunistic Avx2 is allowed bool? ExpectedFma = null; bool? ExpectedBmi1 = null; bool? ExpectedBmi2 = null; - bool? ExpectedAvxVnni = null; + bool? ExpectedAvxVnni = false; // TODO: Fix once opportunistic Avx2 is allowed bool? ExpectedAvx512F = false; bool? ExpectedAvx512BW = false; bool? ExpectedAvx512CD = false; From e7d71464bc18e4bd96cdc2562af16219074833e2 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Mon, 22 May 2023 15:08:17 -0700 Subject: [PATCH 15/24] Ensure Avx2.X64 checks ExpectedAvx2, not ExpectedAvx --- src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs index 26f1f5532cc74..d46d9071bea61 100644 --- a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs +++ b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs @@ -207,7 +207,7 @@ static int Main() Check("Avx.X64", ExpectedAvx, &AvxX64IsSupported, Avx.X64.IsSupported, null); Check("Avx2", ExpectedAvx2, &Avx2IsSupported, Avx2.IsSupported, () => Avx2.Abs(Vector256.Zero).Equals(Vector256.Zero)); - Check("Avx2.X64", ExpectedAvx, &Avx2X64IsSupported, Avx2.X64.IsSupported, null); + Check("Avx2.X64", ExpectedAvx2, &Avx2X64IsSupported, Avx2.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); From ba1316eac314c88314a1f0ec1054c15995d59037 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Tue, 23 May 2023 08:57:18 -0700 Subject: [PATCH 16/24] Change the filter the AVX512 NAOT smoke test on OSX --- .../SmokeTests/HardwareIntrinsics/X64Avx512.csproj | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx512.csproj b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx512.csproj index 2d89fea81c22d..24da060cc6622 100644 --- a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx512.csproj +++ b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx512.csproj @@ -3,7 +3,7 @@ Exe BuildAndRun 0 - true + true true $(DefineConstants);AVX512_INTRINSICS;VECTORT256_INTRINSICS @@ -15,9 +15,6 @@ /dev/null; then echo No support for AVX512, test not applicable. @@ -30,4 +27,4 @@ $(CLRTestBashPreCommands) - \ No newline at end of file + From 86ed734f95bc3d6cf2daecb496b1f0b71a13a59c Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Thu, 1 Jun 2023 07:56:59 -0700 Subject: [PATCH 17/24] Updating the CPUID test to cover new ISAs and correctly validate the hierarchy --- .../HardwareIntrinsics/X86/X86Base/CpuId.cs | 289 +++++++++++++++--- 1 file changed, 253 insertions(+), 36 deletions(-) diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId.cs index abef01eb32fe1..c4da315971fc0 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId.cs @@ -7,6 +7,7 @@ using System.Runtime.InteropServices; using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics; +using System.Reflection; using Xunit; namespace IntelHardwareIntrinsicTest._CpuId @@ -48,82 +49,88 @@ public unsafe static void CpuId() 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); @@ -132,24 +139,106 @@ public unsafe static void CpuId() (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; } + isHierarchyDisabled = isAvx2HierarchyDisabled | isFmaHierarchyDisabled; + + 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); if (isAuthenticAmd && ((ebx != 0x68747541) || (ecx != 0x444D4163) || (edx != 0x69746E65))) @@ -164,7 +253,7 @@ public unsafe static void CpuId() testResult = Fail; } - int maxFunctionIdEx = eax; + uint maxFunctionIdEx = (uint)eax; if (maxFunctionIdEx < 0x00000001) { @@ -174,9 +263,63 @@ public unsafe static void CpuId() (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)) { - Console.WriteLine("CPUID Fn8000_0001_ECX:LZCNT != Lzcnt.IsSupported"); + testResult = Fail; + } + + if (IsIncorrect(typeof(Vector512), Vector512.IsHardwareAccelerated, isAvx512HierarchyDisabled)) + { + testResult = Fail; + } + + if (IsIncorrect(typeof(Vector), Vector.IsHardwareAccelerated, isSse2HierarchyDisabled)) + { + testResult = Fail; + } + + if (Vector.Count == 16) + { + if (!isAvx2HierarchyDisabled) + { + Console.WriteLine($"{typeof(Vector).FullName}.Count returned 16 but the hardware returned 32"); + testResult = Fail; + } + } + else if (Vector.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.Count} which is unexpected"); + testResult = Fail; + } + + if (Vector.Count != (int)typeof(Vector).GetProperty("Count")!.GetValue(null)!) + { + Console.WriteLine($"{typeof(Vector).FullName}.Count returned a different result when called via reflection"); testResult = Fail; } @@ -184,10 +327,84 @@ public unsafe static void CpuId() 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) + { + 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) { - return ((register & (1 << bitNumber)) != ((expectedResult ? 1 : 0) << bitNumber)) - && (Environment.GetEnvironmentVariable($"DOTNET_Enable{name}") is null); + 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; } } } From 53e78583bfaa6e850fbc6c35455ee9c1b8f3769f Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Thu, 1 Jun 2023 09:40:43 -0700 Subject: [PATCH 18/24] Add two more NAOT smoke tests which cover explicit ISA exclusion --- .../X64Avx512_NoAvx512CD.csproj | 30 +++++++++++++++ .../HardwareIntrinsics/X64Avx_NoAvx2.csproj | 38 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx512_NoAvx512CD.csproj create mode 100644 src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx_NoAvx2.csproj diff --git a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx512_NoAvx512CD.csproj b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx512_NoAvx512CD.csproj new file mode 100644 index 0000000000000..85fd1945bd717 --- /dev/null +++ b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx512_NoAvx512CD.csproj @@ -0,0 +1,30 @@ + + + Exe + BuildAndRun + 0 + true + true + $(DefineConstants);AVX2_INTRINSICS;VECTORT256_INTRINSICS + + + + + + + + /dev/null; then + echo No support for AVX512, test not applicable. + exit 0 + fi + fi +]]> + + + + + + diff --git a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx_NoAvx2.csproj b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx_NoAvx2.csproj new file mode 100644 index 0000000000000..9565259240f01 --- /dev/null +++ b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx_NoAvx2.csproj @@ -0,0 +1,38 @@ + + + Exe + BuildAndRun + 0 + true + true + $(DefineConstants);AVX_INTRINSICS;VECTORT128_INTRINSICS + + + + + + + + /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 +]]> + + + + + + From 2447b217709bd8e91168034de2cf2c73d4715d62 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Thu, 1 Jun 2023 10:22:44 -0700 Subject: [PATCH 19/24] Add additional CpuId validation covering R2R scenarios using various ISA opt-in --- .../HardwareIntrinsics/X86/X86Base/CpuId.cs | 1 + .../X86/X86Base/CpuId_R2R_Avx.csproj | 20 +++++++++++++++++++ .../X86/X86Base/CpuId_R2R_Avx2.csproj | 20 +++++++++++++++++++ .../X86/X86Base/CpuId_R2R_Avx512.csproj | 20 +++++++++++++++++++ .../CpuId_R2R_Avx512_NoAvx512CD.csproj | 20 +++++++++++++++++++ .../X86/X86Base/CpuId_R2R_Avx_NoAvx2.csproj | 20 +++++++++++++++++++ .../X86/X86Base/CpuId_R2R_Baseline.csproj | 16 +++++++++++++++ .../X86/X86Base/CpuId_R2R_Sse42.csproj | 20 +++++++++++++++++++ 8 files changed, 137 insertions(+) create mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx.csproj create mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx2.csproj create mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx512.csproj create mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx512_NoAvx512CD.csproj create mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx_NoAvx2.csproj create mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Baseline.csproj create mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Sse42.csproj diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId.cs index c4da315971fc0..bf54bbaca8046 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId.cs @@ -3,6 +3,7 @@ // using System; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics.X86; diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx.csproj new file mode 100644 index 0000000000000..de863506c5cbf --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx.csproj @@ -0,0 +1,20 @@ + + + X86_CpuId_R2R_Avx + true + + + + true + true + true + + + + + + + + + + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx2.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx2.csproj new file mode 100644 index 0000000000000..c24e1ffae3704 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx2.csproj @@ -0,0 +1,20 @@ + + + X86_CpuId_R2R_Avx2 + true + + + + true + true + true + + + + + + + + + + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx512.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx512.csproj new file mode 100644 index 0000000000000..01c0f2a7d983b --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx512.csproj @@ -0,0 +1,20 @@ + + + X86_CpuId_R2R_Avx512 + true + + + + true + true + true + + + + + + + + + + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx512_NoAvx512CD.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx512_NoAvx512CD.csproj new file mode 100644 index 0000000000000..64faeab537d49 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx512_NoAvx512CD.csproj @@ -0,0 +1,20 @@ + + + X86_CpuId_R2R_Avx512_NoAvx512CD + true + + + + true + true + true + + + + + + + + + + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx_NoAvx2.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx_NoAvx2.csproj new file mode 100644 index 0000000000000..d675cfe7dc29f --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx_NoAvx2.csproj @@ -0,0 +1,20 @@ + + + X86_CpuId_R2R_Avx_NoAvx2 + true + + + + true + true + true + + + + + + + + + + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Baseline.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Baseline.csproj new file mode 100644 index 0000000000000..1fe725e4d3a9b --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Baseline.csproj @@ -0,0 +1,16 @@ + + + X86_CpuId_R2R_Baseline + true + + + + true + true + true + + + + + + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Sse42.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Sse42.csproj new file mode 100644 index 0000000000000..8a4de53b3a859 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Sse42.csproj @@ -0,0 +1,20 @@ + + + X86_CpuId_R2R_Sse42 + true + + + + true + true + true + + + + + + + + + + From e9f8b88dfb2bdae907dca97d676c82c48f707f30 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Thu, 1 Jun 2023 11:53:33 -0700 Subject: [PATCH 20/24] Ensure new R2R tests actually use R2R --- .../HardwareIntrinsics/X86/CpuId.cs | 405 ++++++++++++++++++ .../X86}/CpuId_R2R_Avx.csproj | 9 +- .../X86}/CpuId_R2R_Avx2.csproj | 9 +- .../X86}/CpuId_R2R_Avx512.csproj | 9 +- .../X86}/CpuId_R2R_Avx512_NoAvx512CD.csproj | 9 +- .../X86}/CpuId_R2R_Avx_NoAvx2.csproj | 9 +- .../X86}/CpuId_R2R_Baseline.csproj | 3 +- .../X86}/CpuId_R2R_Sse42.csproj | 9 +- 8 files changed, 437 insertions(+), 25 deletions(-) create mode 100644 src/tests/readytorun/HardwareIntrinsics/X86/CpuId.cs rename src/tests/{JIT/HardwareIntrinsics/X86/X86Base => readytorun/HardwareIntrinsics/X86}/CpuId_R2R_Avx.csproj (63%) rename src/tests/{JIT/HardwareIntrinsics/X86/X86Base => readytorun/HardwareIntrinsics/X86}/CpuId_R2R_Avx2.csproj (63%) rename src/tests/{JIT/HardwareIntrinsics/X86/X86Base => readytorun/HardwareIntrinsics/X86}/CpuId_R2R_Avx512.csproj (56%) rename src/tests/{JIT/HardwareIntrinsics/X86/X86Base => readytorun/HardwareIntrinsics/X86}/CpuId_R2R_Avx512_NoAvx512CD.csproj (56%) rename src/tests/{JIT/HardwareIntrinsics/X86/X86Base => readytorun/HardwareIntrinsics/X86}/CpuId_R2R_Avx_NoAvx2.csproj (63%) rename src/tests/{JIT/HardwareIntrinsics/X86/X86Base => readytorun/HardwareIntrinsics/X86}/CpuId_R2R_Baseline.csproj (84%) rename src/tests/{JIT/HardwareIntrinsics/X86/X86Base => readytorun/HardwareIntrinsics/X86}/CpuId_R2R_Sse42.csproj (63%) diff --git a/src/tests/readytorun/HardwareIntrinsics/X86/CpuId.cs b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId.cs new file mode 100644 index 0000000000000..3c3643ab6baac --- /dev/null +++ b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId.cs @@ -0,0 +1,405 @@ +// 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; + + 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); + + if (isAuthenticAmd && ((ebx != 0x68747541) || (ecx != 0x444D4163) || (edx != 0x69746E65))) + { + Console.WriteLine("CPUID Fn8000_0000 reported different vendor info from Fn0000_0000"); + testResult = Fail; + } + + if (isGenuineIntel && ((ebx != 0x756E6547) && (ecx != 0x6C65746E) && (edx != 0x6C656E69))) + { + Console.WriteLine("CPUID Fn8000_0000 reported different vendor info from Fn0000_0000"); + testResult = Fail; + } + + 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.Count == 16) + { + if (!isAvx2HierarchyDisabled) + { + Console.WriteLine($"{typeof(Vector).FullName}.Count returned 16 but the hardware returned 32"); + testResult = Fail; + } + } + else if (Vector.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.Count} which is unexpected"); + testResult = Fail; + } + + if (Vector.Count != (int)typeof(Vector).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; + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx.csproj b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx.csproj similarity index 63% rename from src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx.csproj rename to src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx.csproj index de863506c5cbf..7ab4f5e14ecb5 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx.csproj +++ b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx.csproj @@ -1,6 +1,7 @@ - X86_CpuId_R2R_Avx + Exe + BuildAndRun true @@ -10,9 +11,9 @@ true - - - + + $(CrossGen2TestExtraArguments) --instruction-set:avx + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx2.csproj b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx2.csproj similarity index 63% rename from src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx2.csproj rename to src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx2.csproj index c24e1ffae3704..38c16061f5037 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx2.csproj +++ b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx2.csproj @@ -1,6 +1,7 @@ - X86_CpuId_R2R_Avx2 + Exe + BuildAndRun true @@ -10,9 +11,9 @@ true - - - + + $(CrossGen2TestExtraArguments) --instruction-set:avx2 + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx512.csproj b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx512.csproj similarity index 56% rename from src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx512.csproj rename to src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx512.csproj index 01c0f2a7d983b..166ef0198b188 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx512.csproj +++ b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx512.csproj @@ -1,6 +1,7 @@ - X86_CpuId_R2R_Avx512 + Exe + BuildAndRun true @@ -10,9 +11,9 @@ true - - - + + $(CrossGen2TestExtraArguments) --instruction-set:avx512f,avx512f_vl,avx512bw,avx512bw_vl,avx512cd,avx512cd_vl,avx512dq,avx512dq_vl + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx512_NoAvx512CD.csproj b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx512_NoAvx512CD.csproj similarity index 56% rename from src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx512_NoAvx512CD.csproj rename to src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx512_NoAvx512CD.csproj index 64faeab537d49..3348cb8f4c224 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx512_NoAvx512CD.csproj +++ b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx512_NoAvx512CD.csproj @@ -1,6 +1,7 @@ - X86_CpuId_R2R_Avx512_NoAvx512CD + Exe + BuildAndRun true @@ -10,9 +11,9 @@ true - - - + + $(CrossGen2TestExtraArguments) --instruction-set:avx512f,avx512f_vl,avx512bw,avx512bw_vl,-avx512cd,avx512cd_vl,avx512dq,avx512dq_vl + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx_NoAvx2.csproj b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx_NoAvx2.csproj similarity index 63% rename from src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx_NoAvx2.csproj rename to src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx_NoAvx2.csproj index d675cfe7dc29f..4c062e49f15cd 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Avx_NoAvx2.csproj +++ b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx_NoAvx2.csproj @@ -1,6 +1,7 @@ - X86_CpuId_R2R_Avx_NoAvx2 + Exe + BuildAndRun true @@ -10,9 +11,9 @@ true - - - + + $(CrossGen2TestExtraArguments) --instruction-set:avx,-avx2 + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Baseline.csproj b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Baseline.csproj similarity index 84% rename from src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Baseline.csproj rename to src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Baseline.csproj index 1fe725e4d3a9b..89c9cdeb2bfd0 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Baseline.csproj +++ b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Baseline.csproj @@ -1,6 +1,7 @@ - X86_CpuId_R2R_Baseline + Exe + BuildAndRun true diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Sse42.csproj b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Sse42.csproj similarity index 63% rename from src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Sse42.csproj rename to src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Sse42.csproj index 8a4de53b3a859..2d98ac1c69b4d 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId_R2R_Sse42.csproj +++ b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Sse42.csproj @@ -1,6 +1,7 @@ - X86_CpuId_R2R_Sse42 + Exe + BuildAndRun true @@ -10,9 +11,9 @@ true - - - + + $(CrossGen2TestExtraArguments) --instruction-set:sse4.2 + From da584c5bebfade856d3cb63fbb4907042fd6d513 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Thu, 1 Jun 2023 12:36:40 -0700 Subject: [PATCH 21/24] Don't try to expose an invalid --instruction-set combination --- .../X64Avx512_NoAvx512CD.csproj | 30 ------------------- .../X86/CpuId_R2R_Avx512_NoAvx512CD.csproj | 21 ------------- 2 files changed, 51 deletions(-) delete mode 100644 src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx512_NoAvx512CD.csproj delete mode 100644 src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx512_NoAvx512CD.csproj diff --git a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx512_NoAvx512CD.csproj b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx512_NoAvx512CD.csproj deleted file mode 100644 index 85fd1945bd717..0000000000000 --- a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Avx512_NoAvx512CD.csproj +++ /dev/null @@ -1,30 +0,0 @@ - - - Exe - BuildAndRun - 0 - true - true - $(DefineConstants);AVX2_INTRINSICS;VECTORT256_INTRINSICS - - - - - - - - /dev/null; then - echo No support for AVX512, test not applicable. - exit 0 - fi - fi -]]> - - - - - - diff --git a/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx512_NoAvx512CD.csproj b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx512_NoAvx512CD.csproj deleted file mode 100644 index 3348cb8f4c224..0000000000000 --- a/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx512_NoAvx512CD.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - Exe - BuildAndRun - true - - - - true - true - true - - - - $(CrossGen2TestExtraArguments) --instruction-set:avx512f,avx512f_vl,avx512bw,avx512bw_vl,-avx512cd,avx512cd_vl,avx512dq,avx512dq_vl - - - - - - From 67f309ba25e90cc4d4d5fdb1e8b0f882216304bd Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Thu, 1 Jun 2023 15:39:52 -0700 Subject: [PATCH 22/24] Ensure xarch r2r tests only run on xarch --- src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx.csproj | 1 + .../readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx2.csproj | 1 + .../readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx512.csproj | 1 + .../HardwareIntrinsics/X86/CpuId_R2R_Avx_NoAvx2.csproj | 1 + .../readytorun/HardwareIntrinsics/X86/CpuId_R2R_Baseline.csproj | 1 + .../readytorun/HardwareIntrinsics/X86/CpuId_R2R_Sse42.csproj | 1 + 6 files changed, 6 insertions(+) diff --git a/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx.csproj b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx.csproj index 7ab4f5e14ecb5..eb0459feb7ec3 100644 --- a/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx.csproj +++ b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx.csproj @@ -3,6 +3,7 @@ Exe BuildAndRun true + true diff --git a/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx2.csproj b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx2.csproj index 38c16061f5037..71375daa1cc40 100644 --- a/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx2.csproj +++ b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx2.csproj @@ -3,6 +3,7 @@ Exe BuildAndRun true + true diff --git a/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx512.csproj b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx512.csproj index 166ef0198b188..ebdb4f54d3cd3 100644 --- a/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx512.csproj +++ b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx512.csproj @@ -3,6 +3,7 @@ Exe BuildAndRun true + true diff --git a/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx_NoAvx2.csproj b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx_NoAvx2.csproj index 4c062e49f15cd..6bad67a726a56 100644 --- a/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx_NoAvx2.csproj +++ b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Avx_NoAvx2.csproj @@ -3,6 +3,7 @@ Exe BuildAndRun true + true diff --git a/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Baseline.csproj b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Baseline.csproj index 89c9cdeb2bfd0..cfcfb9483b87f 100644 --- a/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Baseline.csproj +++ b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Baseline.csproj @@ -3,6 +3,7 @@ Exe BuildAndRun true + true diff --git a/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Sse42.csproj b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Sse42.csproj index 2d98ac1c69b4d..39fa7fc965a22 100644 --- a/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Sse42.csproj +++ b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId_R2R_Sse42.csproj @@ -3,6 +3,7 @@ Exe BuildAndRun true + true From 0c69dbddbf01de68d87e6dd7bfa33545bb204a92 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Thu, 1 Jun 2023 15:42:58 -0700 Subject: [PATCH 23/24] Don't compare manufacturer name of CPUID 0x00000000 to 0x80000000 --- .../JIT/HardwareIntrinsics/X86/X86Base/CpuId.cs | 12 ------------ src/tests/readytorun/HardwareIntrinsics/X86/CpuId.cs | 12 ------------ 2 files changed, 24 deletions(-) diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId.cs index bf54bbaca8046..e01b56830b7cf 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId.cs @@ -242,18 +242,6 @@ public unsafe static void CpuId() (eax, ebx, ecx, edx) = X86Base.CpuId(unchecked((int)0x80000000), 0x00000000); - if (isAuthenticAmd && ((ebx != 0x68747541) || (ecx != 0x444D4163) || (edx != 0x69746E65))) - { - Console.WriteLine("CPUID Fn8000_0000 reported different vendor info from Fn0000_0000"); - testResult = Fail; - } - - if (isGenuineIntel && ((ebx != 0x756E6547) && (ecx != 0x6C65746E) && (edx != 0x6C656E69))) - { - Console.WriteLine("CPUID Fn8000_0000 reported different vendor info from Fn0000_0000"); - testResult = Fail; - } - uint maxFunctionIdEx = (uint)eax; if (maxFunctionIdEx < 0x00000001) diff --git a/src/tests/readytorun/HardwareIntrinsics/X86/CpuId.cs b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId.cs index 3c3643ab6baac..6025048310745 100644 --- a/src/tests/readytorun/HardwareIntrinsics/X86/CpuId.cs +++ b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId.cs @@ -238,18 +238,6 @@ public unsafe static int Main() (eax, ebx, ecx, edx) = X86Base.CpuId(unchecked((int)0x80000000), 0x00000000); - if (isAuthenticAmd && ((ebx != 0x68747541) || (ecx != 0x444D4163) || (edx != 0x69746E65))) - { - Console.WriteLine("CPUID Fn8000_0000 reported different vendor info from Fn0000_0000"); - testResult = Fail; - } - - if (isGenuineIntel && ((ebx != 0x756E6547) && (ecx != 0x6C65746E) && (edx != 0x6C656E69))) - { - Console.WriteLine("CPUID Fn8000_0000 reported different vendor info from Fn0000_0000"); - testResult = Fail; - } - uint maxFunctionIdEx = (uint)eax; if (maxFunctionIdEx < 0x00000001) From 5c473168e0ae15d8f226d4e8d8954153de6da2f6 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Thu, 1 Jun 2023 17:40:54 -0700 Subject: [PATCH 24/24] Filter out the CPUID test on Mono and account for AVX-512 being unsupported on MacOS --- src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId.cs | 3 ++- src/tests/readytorun/HardwareIntrinsics/X86/CpuId.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId.cs index e01b56830b7cf..7044a90ad715c 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/CpuId.cs @@ -19,6 +19,7 @@ public class Program 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; @@ -161,7 +162,7 @@ public unsafe static void CpuId() testResult = Fail; } - isHierarchyDisabled = isAvx2HierarchyDisabled | isFmaHierarchyDisabled; + isHierarchyDisabled = isAvx2HierarchyDisabled | isFmaHierarchyDisabled | OperatingSystem.IsMacOS(); for (int i = 0; i < 2; i++) { diff --git a/src/tests/readytorun/HardwareIntrinsics/X86/CpuId.cs b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId.cs index 6025048310745..38c22a67fa3a4 100644 --- a/src/tests/readytorun/HardwareIntrinsics/X86/CpuId.cs +++ b/src/tests/readytorun/HardwareIntrinsics/X86/CpuId.cs @@ -157,7 +157,7 @@ public unsafe static int Main() testResult = Fail; } - isHierarchyDisabled = isAvx2HierarchyDisabled | isFmaHierarchyDisabled; + isHierarchyDisabled = isAvx2HierarchyDisabled | isFmaHierarchyDisabled | OperatingSystem.IsMacOS(); for (int i = 0; i < 2; i++) {