diff --git a/include/cpuinfo_x86.h b/include/cpuinfo_x86.h index 9cb56e5..a7ca2c6 100644 --- a/include/cpuinfo_x86.h +++ b/include/cpuinfo_x86.h @@ -97,6 +97,7 @@ typedef struct { int dca : 1; int ss : 1; int adx : 1; + int lzcnt : 1; // Note: this flag is called ABM for AMD, LZCNT for Intel. // Make sure to update X86FeaturesEnum below if you add a field here. } X86Features; @@ -247,6 +248,7 @@ typedef enum { X86_DCA, X86_SS, X86_ADX, + X86_LZCNT, X86_LAST_, } X86FeaturesEnum; diff --git a/src/impl_x86__base_implementation.inl b/src/impl_x86__base_implementation.inl index fb29547..8b97449 100644 --- a/src/impl_x86__base_implementation.inl +++ b/src/impl_x86__base_implementation.inl @@ -254,6 +254,7 @@ static void ParseCpuId(const Leaves* leaves, X86Info* info, const Leaf leaf_1 = leaves->leaf_1; const Leaf leaf_7 = leaves->leaf_7; const Leaf leaf_7_1 = leaves->leaf_7_1; + const Leaf leaf_80000001 = leaves->leaf_80000001; const bool have_xsave = IsBitSet(leaf_1.ecx, 26); const bool have_osxsave = IsBitSet(leaf_1.ecx, 27); @@ -312,6 +313,7 @@ static void ParseCpuId(const Leaves* leaves, X86Info* info, features->vaes = IsBitSet(leaf_7.ecx, 9); features->vpclmulqdq = IsBitSet(leaf_7.ecx, 10); features->adx = IsBitSet(leaf_7.ebx, 19); + features->lzcnt = IsBitSet(leaf_80000001.ecx, 5); ///////////////////////////////////////////////////////////////////////////// // The following section is devoted to Vector Extensions. @@ -406,8 +408,8 @@ X86Info GetX86Info(void) { IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); const bool is_hygon = IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_HYGON_GENUINE); - const bool is_zhaoxin = - (IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_CENTAUR_HAULS) || + const bool is_zhaoxin = + (IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_CENTAUR_HAULS) || IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_SHANGHAI)); SetVendor(leaves.leaf_0, info.vendor); if (is_intel || is_amd || is_hygon || is_zhaoxin) { @@ -585,15 +587,15 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info) { // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/zhangjiang return ZHAOXIN_ZHANGJIANG; case CPUID(0x07, 0x1B): - // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/wudaokou - return ZHAOXIN_WUDAOKOU; + // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/wudaokou + return ZHAOXIN_WUDAOKOU; case CPUID(0x07, 0x3B): - // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/lujiazui - return ZHAOXIN_LUJIAZUI; + // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/lujiazui + return ZHAOXIN_LUJIAZUI; case CPUID(0x07, 0x5B): - return ZHAOXIN_YONGFENG; + return ZHAOXIN_YONGFENG; default: - return X86_UNKNOWN; + return X86_UNKNOWN; } } if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_SHANGHAI)) { @@ -603,15 +605,15 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info) { // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/zhangjiang return ZHAOXIN_ZHANGJIANG; case CPUID(0x07, 0x1B): - // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/wudaokou - return ZHAOXIN_WUDAOKOU; + // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/wudaokou + return ZHAOXIN_WUDAOKOU; case CPUID(0x07, 0x3B): - // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/lujiazui - return ZHAOXIN_LUJIAZUI; + // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/lujiazui + return ZHAOXIN_LUJIAZUI; case CPUID(0x07, 0x5B): - return ZHAOXIN_YONGFENG; + return ZHAOXIN_YONGFENG; default: - return X86_UNKNOWN; + return X86_UNKNOWN; } } if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_AUTHENTIC_AMD)) { @@ -1755,7 +1757,8 @@ CacheInfo GetX86CacheInfo(void) { LINE(X86_RDRND, rdrnd, , , ) \ LINE(X86_DCA, dca, , , ) \ LINE(X86_SS, ss, , , ) \ - LINE(X86_ADX, adx, , , ) + LINE(X86_ADX, adx, , , ) \ + LINE(X86_LZCNT, lzcnt, , , ) #define INTROSPECTION_PREFIX X86 #define INTROSPECTION_ENUM_PREFIX X86 #include "define_introspection.inl" diff --git a/test/cpuinfo_x86_test.cc b/test/cpuinfo_x86_test.cc index 97a4beb..7814a02 100644 --- a/test/cpuinfo_x86_test.cc +++ b/test/cpuinfo_x86_test.cc @@ -20,7 +20,7 @@ #include #if defined(CPU_FEATURES_OS_WINDOWS) #include "internal/windows_utils.h" -#endif // CPU_FEATURES_OS_WINDOWS +#endif // CPU_FEATURES_OS_WINDOWS #include "filesystem_for_testing.h" #include "gtest/gtest.h" @@ -540,6 +540,27 @@ TEST_F(CpuidX86Test, AMD_K15_STREAMROLLER_GODAVARI) { X86Microarchitecture::AMD_STREAMROLLER); } +// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F12_K15_Zambezi8C_CPUID.txt +TEST_F(CpuidX86Test, AMD_K15_BULLDOZER_ZAMBEZI_ABM) { + cpu().SetLeaves({ + {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}}, + {{0x00000001, 0}, Leaf{0x00600F12, 0x00080800, 0x1E98220B, 0x178BFBFF}}, + {{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, + {{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}}, + {{0x80000001, 0}, Leaf{0x00600F12, 0x10000000, 0x01C9BFFF, 0x2FD3FBFF}}, + }); + const auto info = GetX86Info(); + + EXPECT_STREQ(info.vendor, "AuthenticAMD"); + EXPECT_EQ(info.family, 0x15); + EXPECT_EQ(info.model, 0x01); + + EXPECT_EQ(GetX86Microarchitecture(&info), + X86Microarchitecture::AMD_BULLDOZER); + + EXPECT_TRUE(info.features.lzcnt); +} + // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0700F01_K16_Kabini_CPUID.txt TEST_F(CpuidX86Test, AMD_K16_JAGUAR_KABINI) { cpu().SetLeaves({ @@ -1110,8 +1131,7 @@ TEST_F(CpuidX86Test, INTEL_CML_U) { EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x8E); EXPECT_EQ(info.stepping, 0x0C); - EXPECT_EQ(GetX86Microarchitecture(&info), - X86Microarchitecture::INTEL_CML); + EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_CML); } // http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00A0652_CometLake_CPUID1.txt @@ -1125,8 +1145,26 @@ TEST_F(CpuidX86Test, INTEL_CML_H) { EXPECT_STREQ(info.vendor, "GenuineIntel"); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0xA5); - EXPECT_EQ(GetX86Microarchitecture(&info), - X86Microarchitecture::INTEL_CML); + EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_CML); +} + +// http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00306F2_HaswellEP2_CPUID.txt +TEST_F(CpuidX86Test, INTEL_HASWELL_LZCNT) { + cpu().SetLeaves({ + {{0x00000000, 0}, Leaf{0x0000000F, 0x756E6547, 0x6C65746E, 0x49656E69}}, + {{0x00000001, 0}, Leaf{0x000306F2, 0x00200800, 0x7FFEFBFF, 0xBFEBFBFF}}, + {{0x00000007, 0}, Leaf{0x00000000, 0x000037AB, 0x00000000, 0x00000000}}, + {{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}}, + {{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000021, 0x2C100000}}, + }); + const auto info = GetX86Info(); + + EXPECT_STREQ(info.vendor, "GenuineIntel"); + EXPECT_EQ(info.family, 0x06); + EXPECT_EQ(info.model, 0x3F); + EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_HSW); + + EXPECT_TRUE(info.features.lzcnt); } // https://github.com/google/cpu_features/issues/200