aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Chatelet <gchatelet@google.com>2022-01-14 14:14:07 +0100
committerGitHub <noreply@github.com>2022-01-14 14:14:07 +0100
commit5ed8ef4bbec90ce165cbb77457f42edebc44de51 (patch)
tree105c36e65c331332b4abd3db29f785ac0887d11c
parent69d39934e83be9a0133d2850f15f5debd5eba06f (diff)
downloadcpu_features-5ed8ef4bbec90ce165cbb77457f42edebc44de51.tar.gz
[NFC][x86] Read all cpuid leaves at once (#213)
This patch reads the most important cpuid leaves and stores the data in a struct. A followup patch will inline micro architecture detection and brand string inside X86Info so we don't have to call `ReadLeaves` multiple times. This wil allow further simplification of `HasSecondFMA` and help fix https://github.com/google/cpu_features/issues/200.
-rw-r--r--src/impl_x86__base_implementation.inl114
1 files changed, 68 insertions, 46 deletions
diff --git a/src/impl_x86__base_implementation.inl b/src/impl_x86__base_implementation.inl
index 0ac6609..e1b8f82 100644
--- a/src/impl_x86__base_implementation.inl
+++ b/src/impl_x86__base_implementation.inl
@@ -73,8 +73,6 @@ uint32_t GetXCR0Eax(void) { return (uint32_t)_xgetbv(0); }
#error "Unsupported compiler, x86 cpuid requires either GCC, Clang or MSVC."
#endif
-static Leaf CpuId(uint32_t leaf_id) { return GetCpuidLeaf(leaf_id, 0); }
-
static const Leaf kEmptyLeaf;
static Leaf SafeCpuIdEx(uint32_t max_cpuid_leaf, uint32_t leaf_id, int ecx) {
@@ -85,8 +83,40 @@ static Leaf SafeCpuIdEx(uint32_t max_cpuid_leaf, uint32_t leaf_id, int ecx) {
}
}
-static Leaf SafeCpuId(uint32_t max_cpuid_leaf, uint32_t leaf_id) {
- return SafeCpuIdEx(max_cpuid_leaf, leaf_id, 0);
+typedef struct {
+ uint32_t max_cpuid_leaf;
+ Leaf leaf_0; // Root
+ Leaf leaf_1; // Family, Model, Stepping
+ Leaf leaf_2; // Intel cache info + features
+ Leaf leaf_7; // Features
+ Leaf leaf_7_1; // Features
+ uint32_t max_cpuid_leaf_ext;
+ Leaf leaf_80000000; // Root for extended leaves
+ Leaf leaf_80000001; // AMD features features and cache
+ Leaf leaf_80000002; // brand string
+ Leaf leaf_80000003; // brand string
+ Leaf leaf_80000004; // brand string
+} Leaves;
+
+static Leaves ReadLeaves() {
+ const Leaf leaf_0 = GetCpuidLeaf(0, 0);
+ const uint32_t max_cpuid_leaf = leaf_0.eax;
+ const Leaf leaf_80000000 = GetCpuidLeaf(0x80000000, 0);
+ const uint32_t max_cpuid_leaf_ext = leaf_80000000.eax;
+ return (Leaves){
+ .max_cpuid_leaf = max_cpuid_leaf,
+ .leaf_0 = leaf_0,
+ .leaf_1 = SafeCpuIdEx(max_cpuid_leaf, 0x00000001, 0),
+ .leaf_2 = SafeCpuIdEx(max_cpuid_leaf, 0x00000002, 0),
+ .leaf_7 = SafeCpuIdEx(max_cpuid_leaf, 0x00000007, 0),
+ .leaf_7_1 = SafeCpuIdEx(max_cpuid_leaf, 0x00000007, 1),
+ .max_cpuid_leaf_ext = max_cpuid_leaf_ext,
+ .leaf_80000000 = leaf_80000000,
+ .leaf_80000001 = SafeCpuIdEx(max_cpuid_leaf_ext, 0x80000001, 0),
+ .leaf_80000002 = SafeCpuIdEx(max_cpuid_leaf_ext, 0x80000002, 0),
+ .leaf_80000003 = SafeCpuIdEx(max_cpuid_leaf_ext, 0x80000003, 0),
+ .leaf_80000004 = SafeCpuIdEx(max_cpuid_leaf_ext, 0x80000004, 0),
+ };
}
////////////////////////////////////////////////////////////////////////////////
@@ -155,17 +185,16 @@ static int IsVendorByX86Info(const X86Info* info, const char* const name) {
}
void FillX86BrandString(char brand_string[49]) {
- const Leaf leaf_ext_0 = CpuId(0x80000000);
- const uint32_t max_cpuid_leaf_ext = leaf_ext_0.eax;
- const Leaf leaves[3] = {
- SafeCpuId(max_cpuid_leaf_ext, 0x80000002),
- SafeCpuId(max_cpuid_leaf_ext, 0x80000003),
- SafeCpuId(max_cpuid_leaf_ext, 0x80000004),
+ const Leaves leaves = ReadLeaves();
+ const Leaf packed[3] = {
+ leaves.leaf_80000002,
+ leaves.leaf_80000003,
+ leaves.leaf_80000004,
};
#if __STDC_VERSION__ >= 201112L
- _Static_assert(sizeof(leaves) == 48, "Leaves must be packed");
+ _Static_assert(sizeof(packed) == 48, "Leaves must be packed");
#endif
- copy(brand_string, (const char*)(leaves), 48);
+ copy(brand_string, (const char*)(packed), 48);
brand_string[48] = '\0';
}
@@ -217,11 +246,11 @@ static void OverrideOsPreserves(OsPreserves* os_preserves);
static void DetectFeaturesFromOs(X86Features* features);
// Reference https://en.wikipedia.org/wiki/CPUID.
-static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info,
+static void ParseCpuId(const Leaves* leaves, X86Info* info,
OsPreserves* os_preserves) {
- const Leaf leaf_1 = SafeCpuId(max_cpuid_leaf, 1);
- const Leaf leaf_7 = SafeCpuId(max_cpuid_leaf, 7);
- const Leaf leaf_7_1 = SafeCpuIdEx(max_cpuid_leaf, 7, 1);
+ const Leaf leaf_1 = leaves->leaf_1;
+ const Leaf leaf_7 = leaves->leaf_7;
+ const Leaf leaf_7_1 = leaves->leaf_7_1;
const bool have_xsave = IsBitSet(leaf_1.ecx, 26);
const bool have_osxsave = IsBitSet(leaf_1.ecx, 27);
@@ -333,15 +362,9 @@ static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info,
}
}
-// Reference
-// https://en.wikipedia.org/wiki/CPUID#EAX=80000000h:_Get_Highest_Extended_Function_Implemented.
-static Leaf GetLeafByIdAMD(uint32_t leaf_id) {
- uint32_t max_extended = CpuId(0x80000000).eax;
- return SafeCpuId(max_extended, leaf_id);
-}
-
-static void ParseExtraAMDCpuId(X86Info* info, OsPreserves os_preserves) {
- const Leaf leaf_80000001 = GetLeafByIdAMD(0x80000001);
+static void ParseExtraAMDCpuId(const Leaves* leaves, X86Info* info,
+ OsPreserves os_preserves) {
+ const Leaf leaf_80000001 = leaves->leaf_80000001;
X86Features* const features = &info->features;
@@ -359,17 +382,19 @@ static const OsPreserves kEmptyOsPreserves;
X86Info GetX86Info(void) {
X86Info info = kEmptyX86Info;
- const Leaf leaf_0 = CpuId(0);
- const bool is_intel = IsVendor(leaf_0, CPU_FEATURES_VENDOR_GENUINE_INTEL);
- const bool is_amd = IsVendor(leaf_0, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
- const bool is_hygon = IsVendor(leaf_0, CPU_FEATURES_VENDOR_HYGON_GENUINE);
- SetVendor(leaf_0, info.vendor);
+ const Leaves leaves = ReadLeaves();
+ const bool is_intel =
+ IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_GENUINE_INTEL);
+ const bool is_amd =
+ IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
+ const bool is_hygon =
+ IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_HYGON_GENUINE);
+ SetVendor(leaves.leaf_0, info.vendor);
if (is_intel || is_amd || is_hygon) {
OsPreserves os_preserves = kEmptyOsPreserves;
- const uint32_t max_cpuid_leaf = leaf_0.eax;
- ParseCpuId(max_cpuid_leaf, &info, &os_preserves);
+ ParseCpuId(&leaves, &info, &os_preserves);
if (is_amd || is_hygon) {
- ParseExtraAMDCpuId(&info, os_preserves);
+ ParseExtraAMDCpuId(&leaves, &info, os_preserves);
}
}
return info;
@@ -1510,8 +1535,8 @@ static CacheLevelInfo GetCacheLevelInfo(const uint32_t reg) {
}
// From https://www.felixcloutier.com/x86/cpuid#tbl-3-12
-static void ParseLeaf2(const int max_cpuid_leaf, CacheInfo* info) {
- Leaf leaf = SafeCpuId(max_cpuid_leaf, 2);
+static void ParseLeaf2(const Leaves* leaves, CacheInfo* info) {
+ Leaf leaf = leaves->leaf_2;
// The least-significant byte in register EAX (register AL) will always return
// 01H. Software should ignore this value and not interpret it as an
// informational descriptor.
@@ -1580,20 +1605,17 @@ static void ParseCacheInfo(const int max_cpuid_leaf, uint32_t leaf_id,
CacheInfo GetX86CacheInfo(void) {
CacheInfo info = kEmptyCacheInfo;
- const Leaf leaf_0 = CpuId(0);
- if (IsVendor(leaf_0, CPU_FEATURES_VENDOR_GENUINE_INTEL)) {
- ParseLeaf2(leaf_0.eax, &info);
- ParseCacheInfo(leaf_0.eax, 4, &info);
- } else if (IsVendor(leaf_0, CPU_FEATURES_VENDOR_AUTHENTIC_AMD) ||
- IsVendor(leaf_0, CPU_FEATURES_VENDOR_HYGON_GENUINE)) {
- const uint32_t max_ext = CpuId(0x80000000).eax;
- const uint32_t cpuid_ext = SafeCpuId(max_ext, 0x80000001).ecx;
-
+ const Leaves leaves = ReadLeaves();
+ if (IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_GENUINE_INTEL)) {
+ ParseLeaf2(&leaves, &info);
+ ParseCacheInfo(leaves.max_cpuid_leaf, 4, &info);
+ } else if (IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_AUTHENTIC_AMD) ||
+ IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_HYGON_GENUINE)) {
// If CPUID Fn8000_0001_ECX[TopologyExtensions]==0
// then CPUID Fn8000_0001_E[D,C,B,A]X is reserved.
// https://www.amd.com/system/files/TechDocs/25481.pdf
- if (IsBitSet(cpuid_ext, 22)) {
- ParseCacheInfo(max_ext, 0x8000001D, &info);
+ if (IsBitSet(leaves.leaf_80000001.ecx, 22)) {
+ ParseCacheInfo(leaves.max_cpuid_leaf_ext, 0x8000001D, &info);
}
}
return info;