diff --git a/src/coreclr/nativeaot/Runtime/IntrinsicConstants.h b/src/coreclr/nativeaot/Runtime/IntrinsicConstants.h index d3ea7a17bc0423..8ce413315e81c6 100644 --- a/src/coreclr/nativeaot/Runtime/IntrinsicConstants.h +++ b/src/coreclr/nativeaot/Runtime/IntrinsicConstants.h @@ -22,6 +22,7 @@ enum XArchIntrinsicConstants XArchIntrinsicConstants_Bmi1 = 0x0400, XArchIntrinsicConstants_Bmi2 = 0x0800, XArchIntrinsicConstants_Lzcnt = 0x1000, + XArchIntrinsicConstants_AvxVnni = 0x2000, }; #endif //HOST_X86 || HOST_AMD64 diff --git a/src/coreclr/nativeaot/Runtime/startup.cpp b/src/coreclr/nativeaot/Runtime/startup.cpp index af4a025050e479..ada010f8a573e6 100644 --- a/src/coreclr/nativeaot/Runtime/startup.cpp +++ b/src/coreclr/nativeaot/Runtime/startup.cpp @@ -198,6 +198,12 @@ bool DetectCPUFeatures() if ((cpuidInfo[EBX] & (1 << 5)) != 0) // AVX2 { g_cpuFeatures |= XArchIntrinsicConstants_Avx2; + + __cpuidex(cpuidInfo, 0x00000007, 0x00000001); + if ((cpuidInfo[EAX] & (1 << 4)) != 0) // AVX-VNNI + { + g_cpuFeatures |= XArchIntrinsicConstants_AvxVnni; + } } } } 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 7c12cf6c8a3da5..188d44c3f65fb8 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/HardwareIntrinsicHelpers.Aot.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/HardwareIntrinsicHelpers.Aot.cs @@ -95,6 +95,7 @@ private static class XArchIntrinsicConstants public const int Bmi1 = 0x0400; public const int Bmi2 = 0x0800; public const int Lzcnt = 0x1000; + public const int AvxVnni = 0x2000; public static int FromHardwareIntrinsicId(string id) { @@ -113,6 +114,7 @@ public static int FromHardwareIntrinsicId(string id) "Bmi1" => Bmi1, "Bmi2" => Bmi2, "Lzcnt" => Lzcnt, + "AvxVnni" => AvxVnni, _ => throw new NotSupportedException(), }; } @@ -155,6 +157,8 @@ public static int FromInstructionSetFlags(InstructionSetFlags instructionSets) InstructionSet.X64_BMI2_X64 => Bmi2, InstructionSet.X64_LZCNT => Lzcnt, InstructionSet.X64_LZCNT_X64 => Popcnt, + InstructionSet.X64_AVXVNNI => AvxVnni, + InstructionSet.X64_AVXVNNI_X64 => AvxVnni, // SSE and SSE2 are baseline ISAs - they're always available InstructionSet.X64_SSE => 0, diff --git a/src/coreclr/tools/aot/ILCompiler/Program.cs b/src/coreclr/tools/aot/ILCompiler/Program.cs index e196567ca7c882..5d774ce90c0117 100644 --- a/src/coreclr/tools/aot/ILCompiler/Program.cs +++ b/src/coreclr/tools/aot/ILCompiler/Program.cs @@ -420,13 +420,14 @@ private int Run(string[] args) optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("popcnt"); optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("lzcnt"); - // If AVX was enabled, we can opportunistically enable FMA/BMI + // If AVX was enabled, we can opportunistically enable FMA/BMI/VNNI Debug.Assert(InstructionSet.X64_AVX == InstructionSet.X86_AVX); if (supportedInstructionSet.HasInstructionSet(InstructionSet.X64_AVX)) { optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("fma"); optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("bmi"); optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("bmi2"); + optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("avxvnni"); } } else if (_targetArchitecture == TargetArchitecture.ARM64) diff --git a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs index 933e1c01c09d26..c29e55cd27f8d6 100644 --- a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs +++ b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs @@ -30,6 +30,7 @@ static int Main() bool? PopCnt = null; bool? Avx12 = false; bool? FmaBmi12 = false; + bool? Avxvnni = false; #elif NON_VEX_INTRINSICS bool vectorsAccelerated = true; int byteVectorLength = 16; @@ -40,6 +41,7 @@ static int Main() bool? PopCnt = null; bool? Avx12 = false; bool? FmaBmi12 = false; + bool? Avxvnni = false; #elif VEX_INTRINSICS bool vectorsAccelerated = true; int byteVectorLength = 32; @@ -50,6 +52,7 @@ static int Main() bool? PopCnt = null; bool? Avx12 = true; bool? FmaBmi12 = null; + bool? Avxvnni = null; #else #error Who dis? #endif @@ -109,6 +112,9 @@ static int Main() Check("Popcnt", PopCnt, &PopcntIsSupported, Popcnt.IsSupported, () => Popcnt.PopCount(0) == 0); Check("Popcnt.X64", PopCnt, &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); + return s_success ? 100 : 1; } @@ -145,6 +151,8 @@ static int Main() static bool PclmulqdqX64IsSupported() => Pclmulqdq.X64.IsSupported; static bool PopcntIsSupported() => Popcnt.IsSupported; static bool PopcntX64IsSupported() => Popcnt.X64.IsSupported; + static bool AvxVnniIsSupported() => AvxVnni.IsSupported; + static bool AvxVnniX64IsSupported() => AvxVnni.X64.IsSupported; static bool IsConstantTrue(delegate* code) {