Update cpu_features, fix integration

This commit is contained in:
Carles Fernandez 2020-10-23 21:36:12 +02:00
parent 292d084478
commit 97224e60d2
No known key found for this signature in database
GPG Key ID: 4C583C52B0C3877D
53 changed files with 1201 additions and 917 deletions

View File

@ -229,8 +229,10 @@ endif()
# cpu_features
if(CMAKE_VERSION VERSION_GREATER 3.0)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(BUILD_PIC ON)
set(BUILD_PIC ON CACHE BOOL
"Build cpu_features with Position Independent Code (PIC)."
FORCE
)
set(USE_CPU_FEATURES ON)
add_subdirectory(cpu_features)
endif()

View File

@ -7,7 +7,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR ARM)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
if(MINGW OR CYGWIN OR WIN32)
set(UTIL_SEARCH_CMD where)

View File

@ -7,7 +7,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR ARM)
set(CMAKE_SYSTEM_PROCESSOR arm)
if(MINGW OR CYGWIN OR WIN32)
set(UTIL_SEARCH_CMD where)

View File

@ -9,19 +9,16 @@ if(POLICY CMP0077)
cmake_policy(SET CMP0077 NEW)
endif()
project(CpuFeatures VERSION 0.1.0 LANGUAGES C)
project(CpuFeatures VERSION 0.6.0 LANGUAGES C)
set(CMAKE_C_STANDARD 99)
if(NOT (CMAKE_VERSION VERSION_LESS "3.1"))
set(CMAKE_C_STANDARD 99)
else()
add_compile_options("$<$<STREQUAL:$<TARGET_PROPERTY:LINKER_LANGUAGE>,C>:-std=gnu99>")
endif()
# Default Build Type to be Release
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
FORCE)
endif()
endif(NOT CMAKE_BUILD_TYPE)
# BUILD_TESTING is a standard CMake variable, but we declare it here to make it
# prominent in the GUI.
@ -120,9 +117,7 @@ setup_include_and_definitions(utils)
if(UNIX)
add_library(unix_based_hardware_detection OBJECT
${PROJECT_SOURCE_DIR}/include/internal/hwcaps.h
${PROJECT_SOURCE_DIR}/include/internal/unix_features_aggregator.h
${PROJECT_SOURCE_DIR}/src/hwcaps.c
${PROJECT_SOURCE_DIR}/src/unix_features_aggregator.c
)
setup_include_and_definitions(unix_based_hardware_detection)
check_include_file(dlfcn.h HAVE_DLFCN_H)
@ -139,8 +134,8 @@ endif()
#
# library : cpu_features
#
set(CPU_FEATURES_HDRS)
set(CPU_FEATURES_SRCS)
set (CPU_FEATURES_HDRS)
set (CPU_FEATURES_SRCS)
add_cpu_features_headers_and_sources(CPU_FEATURES_HDRS CPU_FEATURES_SRCS)
list(APPEND CPU_FEATURES_SRCS $<TARGET_OBJECTS:utils>)
if(NOT PROCESSOR_IS_X86 AND UNIX)
@ -154,6 +149,11 @@ set_property(TARGET cpu_features PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC}
target_include_directories(cpu_features
PUBLIC $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/cpu_features>
)
if(PROCESSOR_IS_X86)
if(APPLE)
target_compile_definitions(cpu_features PRIVATE HAVE_SYSCTLBYNAME)
endif()
endif()
add_library(CpuFeature::cpu_features ALIAS cpu_features)
#
@ -218,9 +218,8 @@ if(BUILD_TESTING)
# Add googletest directly to our build. This defines the gtest and
# gtest_main targets.
add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
${CMAKE_BINARY_DIR}/googletest-build
EXCLUDE_FROM_ALL
)
${CMAKE_BINARY_DIR}/googletest-build
EXCLUDE_FROM_ALL)
endif()
add_subdirectory(test)

View File

@ -6,7 +6,7 @@ SPDX-License-Identifier: Apache-2.0
)
[comment]: # (
SPDX-FileCopyrightText: 2017 Google Inc.
SPDX-FileCopyrightText: 2017 Google LLC
)
<!-- prettier-ignore-end -->
@ -42,6 +42,11 @@ instructions) at runtime.
<a name="codesample"></a>
## Code samples
**Note:** For C++ code, the library functions are defined in the `CpuFeatures`
namespace.
### Checking features at runtime
Here's a simple example that executes a codepath if the CPU supports both the
@ -50,6 +55,7 @@ AES and the SSE4.2 instruction sets:
```c
#include "cpuinfo_x86.h"
// For C++, add `using namespace CpuFeatures;`
static const X86Features features = GetX86Info().features;
void Compute(void) {
@ -71,6 +77,7 @@ features and then check whether AES and NEON are supported.
#include <stdbool.h>
#include "cpuinfo_arm.h"
// For C++, add `using namespace CpuFeatures;`
static const ArmFeatures features = GetArmInfo().features;
static const bool has_aes_and_neon = features.aes && features.neon;
@ -90,6 +97,7 @@ instruction set (e.g., `g++ -mavx`) and sets `has_avx` accordingly.
#include <stdbool.h>
#include "cpuinfo_x86.h"
// For C++, add `using namespace CpuFeatures;`
static const X86Features features = GetX86Info().features;
static const bool has_avx = CPU_FEATURES_COMPILED_X86_AVX || features.avx;
@ -112,6 +120,7 @@ set&mdash;but only if it's not Sandy Bridge.
#include <stdbool.h>
#include "cpuinfo_x86.h"
// For C++, add `using namespace CpuFeatures;`
static const X86Info info = GetX86Info();
static const X86Microarchitecture uarch = GetX86Microarchitecture(&info);
static const bool has_fast_avx = info.features.avx && uarch != INTEL_SNB;
@ -125,7 +134,8 @@ This feature is currently available only for x86 microarchitectures.
### Running sample code
Building `cpu_features` brings a small executable to test the library.
Building `cpu_features` (check [quickstart](#quickstart) below) brings a small
executable to test the library.
```shell
% ./build/list_cpu_features
@ -190,3 +200,23 @@ The cpu_features library is licensed under the terms of the Apache license. See
## Build with CMake
Please check the [CMake build instructions](cmake/README.md).
<a name="quickstart"></a>
### Quickstart with `Ninja`
- build `list_cpu_features`
```
cmake -B/tmp/cpu_features -H. -GNinja -DCMAKE_BUILD_TYPE=Release
ninja -C/tmp/cpu_features
/tmp/cpu_features/list_cpu_features --json
```
- run tests
```
cmake -B/tmp/cpu_features -H. -GNinja -DBUILD_TESTING=ON
ninja -C/tmp/cpu_features
ninja -C/tmp/cpu_features test
```

View File

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2017 Google Inc.
# SPDX-FileCopyrightText: 2017 Google LLC
# SPDX-License-Identifier: Apache-2.0
# CpuFeatures CMake configuration file

View File

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2017 Google Inc.
# SPDX-FileCopyrightText: 2017 Google LLC
# SPDX-License-Identifier: Apache-2.0
# CpuFeaturesNdkCompat CMake configuration file

View File

@ -6,7 +6,7 @@ SPDX-License-Identifier: Apache-2.0
)
[comment]: # (
SPDX-FileCopyrightText: 2017 Google Inc.
SPDX-FileCopyrightText: 2017 Google LLC
)
<!-- prettier-ignore-end -->

View File

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2017 Google Inc.
# SPDX-FileCopyrightText: 2017 Google LLC
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 2.8.2)

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
@ -69,6 +69,10 @@
#define CPU_FEATURES_OS_WINDOWS
#endif
#if (defined(__apple__) || defined(__APPLE__) || defined(__MACH__))
#define CPU_FEATURES_OS_DARWIN
#endif
////////////////////////////////////////////////////////////////////////////////
// Compilers
////////////////////////////////////////////////////////////////////////////////

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
@ -12,38 +12,56 @@ CPU_FEATURES_START_CPP_NAMESPACE
typedef struct
{
int fp : 1; // Floating-point.
int asimd : 1; // Advanced SIMD.
int evtstrm : 1; // Generic timer generated events.
int aes : 1; // Hardware-accelerated Advanced Encryption Standard.
int pmull : 1; // Polynomial multiply long.
int sha1 : 1; // Hardware-accelerated SHA1.
int sha2 : 1; // Hardware-accelerated SHA2-256.
int crc32 : 1; // Hardware-accelerated CRC-32.
int atomics : 1; // Armv8.1 atomic instructions.
int fphp : 1; // Half-precision floating point support.
int asimdhp : 1; // Advanced SIMD half-precision support.
int cpuid : 1; // Access to certain ID registers.
int asimdrdm : 1; // Rounding Double Multiply Accumulate/Subtract.
int jscvt : 1; // Support for JavaScript conversion.
int fcma : 1; // Floating point complex numbers.
int lrcpc : 1; // Support for weaker release consistency.
int dcpop : 1; // Data persistence writeback.
int sha3 : 1; // Hardware-accelerated SHA3.
int sm3 : 1; // Hardware-accelerated SM3.
int sm4 : 1; // Hardware-accelerated SM4.
int asimddp : 1; // Dot product instruction.
int sha512 : 1; // Hardware-accelerated SHA512.
int sve : 1; // Scalable Vector Extension.
int asimdfhm : 1; // Additional half-precision instructions.
int dit : 1; // Data independent timing.
int uscat : 1; // Unaligned atomics support.
int ilrcpc : 1; // Additional support for weaker release consistency.
int flagm : 1; // Flag manipulation instructions.
int ssbs : 1; // Speculative Store Bypass Safe PSTATE bit.
int sb : 1; // Speculation barrier.
int paca : 1; // Address authentication.
int pacg : 1; // Generic authentication.
int fp : 1; // Floating-point.
int asimd : 1; // Advanced SIMD.
int evtstrm : 1; // Generic timer generated events.
int aes : 1; // Hardware-accelerated Advanced Encryption Standard.
int pmull : 1; // Polynomial multiply long.
int sha1 : 1; // Hardware-accelerated SHA1.
int sha2 : 1; // Hardware-accelerated SHA2-256.
int crc32 : 1; // Hardware-accelerated CRC-32.
int atomics : 1; // Armv8.1 atomic instructions.
int fphp : 1; // Half-precision floating point support.
int asimdhp : 1; // Advanced SIMD half-precision support.
int cpuid : 1; // Access to certain ID registers.
int asimdrdm : 1; // Rounding Double Multiply Accumulate/Subtract.
int jscvt : 1; // Support for JavaScript conversion.
int fcma : 1; // Floating point complex numbers.
int lrcpc : 1; // Support for weaker release consistency.
int dcpop : 1; // Data persistence writeback.
int sha3 : 1; // Hardware-accelerated SHA3.
int sm3 : 1; // Hardware-accelerated SM3.
int sm4 : 1; // Hardware-accelerated SM4.
int asimddp : 1; // Dot product instruction.
int sha512 : 1; // Hardware-accelerated SHA512.
int sve : 1; // Scalable Vector Extension.
int asimdfhm : 1; // Additional half-precision instructions.
int dit : 1; // Data independent timing.
int uscat : 1; // Unaligned atomics support.
int ilrcpc : 1; // Additional support for weaker release consistency.
int flagm : 1; // Flag manipulation instructions.
int ssbs : 1; // Speculative Store Bypass Safe PSTATE bit.
int sb : 1; // Speculation barrier.
int paca : 1; // Address authentication.
int pacg : 1; // Generic authentication.
int dcpodp : 1; // Data cache clean to point of persistence.
int sve2 : 1; // Scalable Vector Extension (version 2).
int sveaes : 1; // SVE AES instructions.
int svepmull : 1; // SVE polynomial multiply long instructions.
int svebitperm : 1; // SVE bit permute instructions.
int svesha3 : 1; // SVE SHA3 instructions.
int svesm4 : 1; // SVE SM4 instructions.
int flagm2 : 1; // Additional flag manipulation instructions.
int frint : 1; // Floating point to integer rounding.
int svei8mm : 1; // SVE Int8 matrix multiplication instructions.
int svef32mm : 1; // SVE FP32 matrix multiplication instruction.
int svef64mm : 1; // SVE FP64 matrix multiplication instructions.
int svebf16 : 1; // SVE BFloat16 instructions.
int i8mm : 1; // Int8 matrix multiplication instructions.
int bf16 : 1; // BFloat16 instructions.
int dgh : 1; // Data Gathering Hint instruction.
int rng : 1; // True random number generator support.
int bti : 1; // Branch target identification.
// Make sure to update Aarch64FeaturesEnum below if you add a field here.
} Aarch64Features;
@ -96,6 +114,24 @@ typedef enum
AARCH64_SB,
AARCH64_PACA,
AARCH64_PACG,
AARCH64_DCPODP,
AARCH64_SVE2,
AARCH64_SVEAES,
AARCH64_SVEPMULL,
AARCH64_SVEBITPERM,
AARCH64_SVESHA3,
AARCH64_SVESM4,
AARCH64_FLAGM2,
AARCH64_FRINT,
AARCH64_SVEI8MM,
AARCH64_SVEF32MM,
AARCH64_SVEF64MM,
AARCH64_SVEBF16,
AARCH64_I8MM,
AARCH64_BF16,
AARCH64_DGH,
AARCH64_RNG,
AARCH64_BTI,
AARCH64_LAST_,
} Aarch64FeaturesEnum;

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
@ -16,11 +16,13 @@ typedef struct
int swp : 1; // SWP instruction (atomic read-modify-write)
int half : 1; // Half-word loads and stores
int thumb : 1; // Thumb (16-bit instruction set)
int _26bit : 1; // "26 Bit" Model (Processor status register folded into program counter)
int _26bit : 1; // "26 Bit" Model (Processor status register folded into
// program counter)
int fastmult : 1; // 32x32->64-bit multiplication
int fpa : 1; // Floating point accelerator
int vfp : 1; // Vector Floating Point.
int edsp : 1; // DSP extensions (the 'e' variant of the ARM9 CPUs, and all others above)
int edsp : 1; // DSP extensions (the 'e' variant of the ARM9 CPUs, and all
// others above)
int java : 1; // Jazelle (Java bytecode accelerator)
int iwmmxt : 1; // Intel Wireless MMX Technology.
int crunch : 1; // MaverickCrunch coprocessor
@ -33,7 +35,8 @@ typedef struct
int idiva : 1; // SDIV and UDIV hardware division in ARM mode.
int idivt : 1; // SDIV and UDIV hardware division in Thumb mode.
int vfpd32 : 1; // VFP with 32 D-registers
int lpae : 1; // Large Physical Address Extension (>4GB physical memory on 32-bit architecture)
int lpae : 1; // Large Physical Address Extension (>4GB physical memory on
// 32-bit architecture)
int evtstrm : 1; // kernel event stream using generic architected timer
int aes : 1; // Hardware-accelerated Advanced Encryption Standard.
int pmull : 1; // Polynomial multiply long.

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
@ -60,6 +60,13 @@ typedef struct
int avx512vpopcntdq : 1;
int avx512_4vnniw : 1;
int avx512_4vbmi2 : 1;
int avx512_second_fma : 1;
int avx512_4fmaps : 1;
int avx512_bf16 : 1;
int avx512_vp2intersect : 1;
int amx_bf16 : 1;
int amx_tile : 1;
int amx_int8 : 1;
int pclmulqdq : 1;
int smx : 1;
@ -114,6 +121,8 @@ typedef enum
INTEL_WHL, // WHISKEY LAKE
INTEL_CNL, // CANNON LAKE
INTEL_ICL, // ICE LAKE
INTEL_TGL, // TIGER LAKE
INTEL_SPR, // SAPPHIRE RAPIDS
AMD_HAMMER, // K8
AMD_K10, // K10
AMD_BOBCAT, // K14
@ -180,6 +189,13 @@ typedef enum
X86_AVX512VPOPCNTDQ,
X86_AVX512_4VNNIW,
X86_AVX512_4VBMI2,
X86_AVX512_SECOND_FMA,
X86_AVX512_4FMAPS,
X86_AVX512_BF16,
X86_AVX512_VP2INTERSECT,
X86_AMX_BF16,
X86_AMX_TILE,
X86_AMX_INT8,
X86_PCLMULQDQ,
X86_SMX,
X86_SGX,
@ -205,4 +221,4 @@ CPU_FEATURES_END_CPP_NAMESPACE
#error "Including cpuinfo_x86.h from a non-x86 target."
#endif
#endif // CPU_FEATURES_INCLUDE_CPUINFO_X86_H_
#endif // CPU_FEATURES_INCLUDE_CPUINFO_X86_H

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
@ -16,7 +16,8 @@ typedef struct
uint32_t eax, ebx, ecx, edx;
} Leaf;
Leaf CpuIdEx(uint32_t leaf_id, int ecx);
// Returns the result of a call to the cpuid instruction.
Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx);
// Returns the eax value of the XCR0 register.
uint32_t GetXCR0Eax(void);

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
@ -8,6 +8,7 @@
#define CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_
#include "cpu_features_macros.h"
#include <stdbool.h>
#include <stdint.h>
CPU_FEATURES_START_CPP_NAMESPACE
@ -49,6 +50,25 @@ CPU_FEATURES_START_CPP_NAMESPACE
#define AARCH64_HWCAP_PACA (1UL << 30)
#define AARCH64_HWCAP_PACG (1UL << 31)
#define AARCH64_HWCAP2_DCPODP (1UL << 0)
#define AARCH64_HWCAP2_SVE2 (1UL << 1)
#define AARCH64_HWCAP2_SVEAES (1UL << 2)
#define AARCH64_HWCAP2_SVEPMULL (1UL << 3)
#define AARCH64_HWCAP2_SVEBITPERM (1UL << 4)
#define AARCH64_HWCAP2_SVESHA3 (1UL << 5)
#define AARCH64_HWCAP2_SVESM4 (1UL << 6)
#define AARCH64_HWCAP2_FLAGM2 (1UL << 7)
#define AARCH64_HWCAP2_FRINT (1UL << 8)
#define AARCH64_HWCAP2_SVEI8MM (1UL << 9)
#define AARCH64_HWCAP2_SVEF32MM (1UL << 10)
#define AARCH64_HWCAP2_SVEF64MM (1UL << 11)
#define AARCH64_HWCAP2_SVEBF16 (1UL << 12)
#define AARCH64_HWCAP2_I8MM (1UL << 13)
#define AARCH64_HWCAP2_BF16 (1UL << 14)
#define AARCH64_HWCAP2_DGH (1UL << 15)
#define AARCH64_HWCAP2_RNG (1UL << 16)
#define AARCH64_HWCAP2_BTI (1UL << 17)
// http://elixir.free-electrons.com/linux/latest/source/arch/arm/include/uapi/asm/hwcap.h
#define ARM_HWCAP_SWP (1UL << 0)
#define ARM_HWCAP_HALF (1UL << 1)
@ -141,6 +161,8 @@ typedef struct
} HardwareCapabilities;
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void);
bool CpuFeatures_IsHwCapsSet(const HardwareCapabilities hwcaps_mask,
const HardwareCapabilities hwcaps);
typedef struct
{

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0

View File

@ -1,65 +0,0 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-License-Identifier: Apache-2.0
// CapabilityConfig provides a way to map cpu features to hardware caps and
// /proc/cpuinfo flags. We then provide functions to update capabilities from
// either source.
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_LINUX_FEATURES_AGGREGATOR_H_
#define CPU_FEATURES_INCLUDE_INTERNAL_LINUX_FEATURES_AGGREGATOR_H_
#include "cpu_features_macros.h"
#include "internal/hwcaps.h"
#include "internal/string_view.h"
#include <ctype.h>
#include <stdint.h>
CPU_FEATURES_START_CPP_NAMESPACE
// Use the following macro to declare setter functions to be used in
// CapabilityConfig.
#define DECLARE_SETTER(FeatureType, FeatureName) \
static void set_##FeatureName(void* const features, bool value) \
{ \
((FeatureType*)features)->FeatureName = value; \
}
// Use the following macro to declare getter functions to be used in
// CapabilityConfig.
#define DECLARE_GETTER(FeatureType, FeatureName) \
static int get_##FeatureName(void* const features) \
{ \
return ((FeatureType*)features)->FeatureName; \
}
#define DECLARE_SETTER_AND_GETTER(FeatureType, FeatureName) \
DECLARE_SETTER(FeatureType, FeatureName) \
DECLARE_GETTER(FeatureType, FeatureName)
// Describes the relationship between hardware caps and /proc/cpuinfo flags.
typedef struct
{
const HardwareCapabilities hwcaps_mask;
const char* const proc_cpuinfo_flag;
void (*set_bit)(void* const, bool); // setter for the corresponding bit.
int (*get_bit)(void* const); // getter for the corresponding bit.
} CapabilityConfig;
// For every config, looks into flags_line for the presence of the
// corresponding proc_cpuinfo_flag, calls `set_bit` accordingly.
// Note: features is a pointer to the underlying Feature struct.
void CpuFeatures_SetFromFlags(const size_t configs_size,
const CapabilityConfig* configs,
const StringView flags_line,
void* const features);
// For every config, looks into hwcaps for the presence of the feature. Calls
// `set_bit` with true if the hardware capability is found.
// Note: features is a pointer to the underlying Feature struct.
void CpuFeatures_OverrideFromHwCaps(const size_t configs_size,
const CapabilityConfig* configs,
const HardwareCapabilities hwcaps,
void* const features);
CPU_FEATURES_END_CPP_NAMESPACE
#endif // CPU_FEATURES_INCLUDE_INTERNAL_LINUX_FEATURES_AGGREGATOR_H_

View File

@ -5,8 +5,8 @@
# library : NDK compat
#
find_package(Threads REQUIRED)
set(NDK_COMPAT_HDRS cpu-features.h)
set(NDK_COMPAT_SRCS
set (NDK_COMPAT_HDRS cpu-features.h)
set (NDK_COMPAT_SRCS
cpu-features.c
$<TARGET_OBJECTS:utils>
$<TARGET_OBJECTS:unix_based_hardware_detection>
@ -17,6 +17,7 @@ set(NDK_COMPAT_SRCS
add_cpu_features_headers_and_sources(NDK_COMPAT_SRCS NDK_COMPAT_SRCS)
add_library(ndk_compat ${NDK_COMPAT_HDRS} ${NDK_COMPAT_SRCS})
setup_include_and_definitions(ndk_compat)
target_include_directories(ndk_compat PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
target_link_libraries(ndk_compat PUBLIC ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT})
set_target_properties(ndk_compat PROPERTIES PUBLIC_HEADER "${NDK_COMPAT_HDRS}")

View File

@ -1,6 +1,6 @@
#!/usr/bin/env bash
# SPDX-FileCopyrightText: 2017 Google Inc.
# SPDX-FileCopyrightText: 2017 Google LLC
# SPDX-License-Identifier: Apache-2.0
readonly SCRIPT_FOLDER=$(cd -P -- "$(dirname -- "$0")" && pwd -P)

View File

@ -1,6 +1,6 @@
#!/usr/bin/env bash
# SPDX-FileCopyrightText: 2017 Google Inc.
# SPDX-FileCopyrightText: 2017 Google LLC
# SPDX-License-Identifier: Apache-2.0
source "$(dirname -- "$0")"/run_integration.sh

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
#include "cpuinfo_aarch64.h"
@ -6,79 +6,65 @@
#include "internal/hwcaps.h"
#include "internal/stack_line_reader.h"
#include "internal/string_view.h"
#include "internal/unix_features_aggregator.h"
#include <assert.h>
#include <ctype.h>
DECLARE_SETTER_AND_GETTER(Aarch64Features, fp)
DECLARE_SETTER_AND_GETTER(Aarch64Features, asimd)
DECLARE_SETTER_AND_GETTER(Aarch64Features, evtstrm)
DECLARE_SETTER_AND_GETTER(Aarch64Features, aes)
DECLARE_SETTER_AND_GETTER(Aarch64Features, pmull)
DECLARE_SETTER_AND_GETTER(Aarch64Features, sha1)
DECLARE_SETTER_AND_GETTER(Aarch64Features, sha2)
DECLARE_SETTER_AND_GETTER(Aarch64Features, crc32)
DECLARE_SETTER_AND_GETTER(Aarch64Features, atomics)
DECLARE_SETTER_AND_GETTER(Aarch64Features, fphp)
DECLARE_SETTER_AND_GETTER(Aarch64Features, asimdhp)
DECLARE_SETTER_AND_GETTER(Aarch64Features, cpuid)
DECLARE_SETTER_AND_GETTER(Aarch64Features, asimdrdm)
DECLARE_SETTER_AND_GETTER(Aarch64Features, jscvt)
DECLARE_SETTER_AND_GETTER(Aarch64Features, fcma)
DECLARE_SETTER_AND_GETTER(Aarch64Features, lrcpc)
DECLARE_SETTER_AND_GETTER(Aarch64Features, dcpop)
DECLARE_SETTER_AND_GETTER(Aarch64Features, sha3)
DECLARE_SETTER_AND_GETTER(Aarch64Features, sm3)
DECLARE_SETTER_AND_GETTER(Aarch64Features, sm4)
DECLARE_SETTER_AND_GETTER(Aarch64Features, asimddp)
DECLARE_SETTER_AND_GETTER(Aarch64Features, sha512)
DECLARE_SETTER_AND_GETTER(Aarch64Features, sve)
DECLARE_SETTER_AND_GETTER(Aarch64Features, asimdfhm)
DECLARE_SETTER_AND_GETTER(Aarch64Features, dit)
DECLARE_SETTER_AND_GETTER(Aarch64Features, uscat)
DECLARE_SETTER_AND_GETTER(Aarch64Features, ilrcpc)
DECLARE_SETTER_AND_GETTER(Aarch64Features, flagm)
DECLARE_SETTER_AND_GETTER(Aarch64Features, ssbs)
DECLARE_SETTER_AND_GETTER(Aarch64Features, sb)
DECLARE_SETTER_AND_GETTER(Aarch64Features, paca)
DECLARE_SETTER_AND_GETTER(Aarch64Features, pacg)
static const CapabilityConfig kConfigs[] = {
[AARCH64_FP] = {{AARCH64_HWCAP_FP, 0}, "fp", &set_fp, &get_fp},
[AARCH64_ASIMD] = {{AARCH64_HWCAP_ASIMD, 0}, "asimd", &set_asimd, &get_asimd},
[AARCH64_EVTSTRM] = {{AARCH64_HWCAP_EVTSTRM, 0}, "evtstrm", &set_evtstrm, &get_evtstrm},
[AARCH64_AES] = {{AARCH64_HWCAP_AES, 0}, "aes", &set_aes, &get_aes},
[AARCH64_PMULL] = {{AARCH64_HWCAP_PMULL, 0}, "pmull", &set_pmull, &get_pmull},
[AARCH64_SHA1] = {{AARCH64_HWCAP_SHA1, 0}, "sha1", &set_sha1, &get_sha1},
[AARCH64_SHA2] = {{AARCH64_HWCAP_SHA2, 0}, "sha2", &set_sha2, &get_sha2},
[AARCH64_CRC32] = {{AARCH64_HWCAP_CRC32, 0}, "crc32", &set_crc32, &get_crc32},
[AARCH64_ATOMICS] = {{AARCH64_HWCAP_ATOMICS, 0}, "atomics", &set_atomics, &get_atomics},
[AARCH64_FPHP] = {{AARCH64_HWCAP_FPHP, 0}, "fphp", &set_fphp, &get_fphp},
[AARCH64_ASIMDHP] = {{AARCH64_HWCAP_ASIMDHP, 0}, "asimdhp", &set_asimdhp, &get_asimdhp},
[AARCH64_CPUID] = {{AARCH64_HWCAP_CPUID, 0}, "cpuid", &set_cpuid, &get_cpuid},
[AARCH64_ASIMDRDM] = {{AARCH64_HWCAP_ASIMDRDM, 0}, "asimdrdm", &set_asimdrdm, &get_asimdrdm},
[AARCH64_JSCVT] = {{AARCH64_HWCAP_JSCVT, 0}, "jscvt", &set_jscvt, &get_jscvt},
[AARCH64_FCMA] = {{AARCH64_HWCAP_FCMA, 0}, "fcma", &set_fcma, &get_fcma},
[AARCH64_LRCPC] = {{AARCH64_HWCAP_LRCPC, 0}, "lrcpc", &set_lrcpc, &get_lrcpc},
[AARCH64_DCPOP] = {{AARCH64_HWCAP_DCPOP, 0}, "dcpop", &set_dcpop, &get_dcpop},
[AARCH64_SHA3] = {{AARCH64_HWCAP_SHA3, 0}, "sha3", &set_sha3, &get_sha3},
[AARCH64_SM3] = {{AARCH64_HWCAP_SM3, 0}, "sm3", &set_sm3, &get_sm3},
[AARCH64_SM4] = {{AARCH64_HWCAP_SM4, 0}, "sm4", &set_sm4, &get_sm4},
[AARCH64_ASIMDDP] = {{AARCH64_HWCAP_ASIMDDP, 0}, "asimddp", &set_asimddp, &get_asimddp},
[AARCH64_SHA512] = {{AARCH64_HWCAP_SHA512, 0}, "sha512", &set_sha512, &get_sha512},
[AARCH64_SVE] = {{AARCH64_HWCAP_SVE, 0}, "sve", &set_sve, &get_sve},
[AARCH64_ASIMDFHM] = {{AARCH64_HWCAP_ASIMDFHM, 0}, "asimdfhm", &set_asimdfhm, &get_asimdfhm},
[AARCH64_DIT] = {{AARCH64_HWCAP_DIT, 0}, "dit", &set_dit, &get_dit},
[AARCH64_USCAT] = {{AARCH64_HWCAP_USCAT, 0}, "uscat", &set_uscat, &get_uscat},
[AARCH64_ILRCPC] = {{AARCH64_HWCAP_ILRCPC, 0}, "ilrcpc", &set_ilrcpc, &get_ilrcpc},
[AARCH64_FLAGM] = {{AARCH64_HWCAP_FLAGM, 0}, "flagm", &set_flagm, &get_flagm},
[AARCH64_SSBS] = {{AARCH64_HWCAP_SSBS, 0}, "ssbs", &set_ssbs, &get_ssbs},
[AARCH64_SB] = {{AARCH64_HWCAP_SB, 0}, "sb", &set_sb, &get_sb},
[AARCH64_PACA] = {{AARCH64_HWCAP_PACA, 0}, "paca", &set_paca, &get_paca},
[AARCH64_PACG] = {{AARCH64_HWCAP_PACG, 0}, "pacg", &set_pacg, &get_pacg},
};
static const size_t kConfigsSize = sizeof(kConfigs) / sizeof(CapabilityConfig);
// Generation of feature's getters/setters functions and kGetters, kSetters,
// kCpuInfoFlags and kHardwareCapabilities global tables.
#define DEFINE_TABLE_FEATURES \
FEATURE(AARCH64_FP, fp, "fp", AARCH64_HWCAP_FP, 0) \
FEATURE(AARCH64_ASIMD, asimd, "asimd", AARCH64_HWCAP_ASIMD, 0) \
FEATURE(AARCH64_EVTSTRM, evtstrm, "evtstrm", AARCH64_HWCAP_EVTSTRM, 0) \
FEATURE(AARCH64_AES, aes, "aes", AARCH64_HWCAP_AES, 0) \
FEATURE(AARCH64_PMULL, pmull, "pmull", AARCH64_HWCAP_PMULL, 0) \
FEATURE(AARCH64_SHA1, sha1, "sha1", AARCH64_HWCAP_SHA1, 0) \
FEATURE(AARCH64_SHA2, sha2, "sha2", AARCH64_HWCAP_SHA2, 0) \
FEATURE(AARCH64_CRC32, crc32, "crc32", AARCH64_HWCAP_CRC32, 0) \
FEATURE(AARCH64_ATOMICS, atomics, "atomics", AARCH64_HWCAP_ATOMICS, 0) \
FEATURE(AARCH64_FPHP, fphp, "fphp", AARCH64_HWCAP_FPHP, 0) \
FEATURE(AARCH64_ASIMDHP, asimdhp, "asimdhp", AARCH64_HWCAP_ASIMDHP, 0) \
FEATURE(AARCH64_CPUID, cpuid, "cpuid", AARCH64_HWCAP_CPUID, 0) \
FEATURE(AARCH64_ASIMDRDM, asimdrdm, "asimdrdm", AARCH64_HWCAP_ASIMDRDM, 0) \
FEATURE(AARCH64_JSCVT, jscvt, "jscvt", AARCH64_HWCAP_JSCVT, 0) \
FEATURE(AARCH64_FCMA, fcma, "fcma", AARCH64_HWCAP_FCMA, 0) \
FEATURE(AARCH64_LRCPC, lrcpc, "lrcpc", AARCH64_HWCAP_LRCPC, 0) \
FEATURE(AARCH64_DCPOP, dcpop, "dcpop", AARCH64_HWCAP_DCPOP, 0) \
FEATURE(AARCH64_SHA3, sha3, "sha3", AARCH64_HWCAP_SHA3, 0) \
FEATURE(AARCH64_SM3, sm3, "sm3", AARCH64_HWCAP_SM3, 0) \
FEATURE(AARCH64_SM4, sm4, "sm4", AARCH64_HWCAP_SM4, 0) \
FEATURE(AARCH64_ASIMDDP, asimddp, "asimddp", AARCH64_HWCAP_ASIMDDP, 0) \
FEATURE(AARCH64_SHA512, sha512, "sha512", AARCH64_HWCAP_SHA512, 0) \
FEATURE(AARCH64_SVE, sve, "sve", AARCH64_HWCAP_SVE, 0) \
FEATURE(AARCH64_ASIMDFHM, asimdfhm, "asimdfhm", AARCH64_HWCAP_ASIMDFHM, 0) \
FEATURE(AARCH64_DIT, dit, "dit", AARCH64_HWCAP_DIT, 0) \
FEATURE(AARCH64_USCAT, uscat, "uscat", AARCH64_HWCAP_USCAT, 0) \
FEATURE(AARCH64_ILRCPC, ilrcpc, "ilrcpc", AARCH64_HWCAP_ILRCPC, 0) \
FEATURE(AARCH64_FLAGM, flagm, "flagm", AARCH64_HWCAP_FLAGM, 0) \
FEATURE(AARCH64_SSBS, ssbs, "ssbs", AARCH64_HWCAP_SSBS, 0) \
FEATURE(AARCH64_SB, sb, "sb", AARCH64_HWCAP_SB, 0) \
FEATURE(AARCH64_PACA, paca, "paca", AARCH64_HWCAP_PACA, 0) \
FEATURE(AARCH64_PACG, pacg, "pacg", AARCH64_HWCAP_PACG, 0) \
FEATURE(AARCH64_DCPODP, dcpodp, "dcpodp", 0, AARCH64_HWCAP2_DCPODP) \
FEATURE(AARCH64_SVE2, sve2, "sve2", 0, AARCH64_HWCAP2_SVE2) \
FEATURE(AARCH64_SVEAES, sveaes, "sveaes", 0, AARCH64_HWCAP2_SVEAES) \
FEATURE(AARCH64_SVEPMULL, svepmull, "svepmull", 0, AARCH64_HWCAP2_SVEPMULL) \
FEATURE(AARCH64_SVEBITPERM, svebitperm, "svebitperm", 0, \
AARCH64_HWCAP2_SVEBITPERM) \
FEATURE(AARCH64_SVESHA3, svesha3, "svesha3", 0, AARCH64_HWCAP2_SVESHA3) \
FEATURE(AARCH64_SVESM4, svesm4, "svesm4", 0, AARCH64_HWCAP2_SVESM4) \
FEATURE(AARCH64_FLAGM2, flagm2, "flagm2", 0, AARCH64_HWCAP2_FLAGM2) \
FEATURE(AARCH64_FRINT, frint, "frint", 0, AARCH64_HWCAP2_FRINT) \
FEATURE(AARCH64_SVEI8MM, svei8mm, "svei8mm", 0, AARCH64_HWCAP2_SVEI8MM) \
FEATURE(AARCH64_SVEF32MM, svef32mm, "svef32mm", 0, AARCH64_HWCAP2_SVEF32MM) \
FEATURE(AARCH64_SVEF64MM, svef64mm, "svef64mm", 0, AARCH64_HWCAP2_SVEF64MM) \
FEATURE(AARCH64_SVEBF16, svebf16, "svebf16", 0, AARCH64_HWCAP2_SVEBF16) \
FEATURE(AARCH64_I8MM, i8mm, "i8mm", 0, AARCH64_HWCAP2_I8MM) \
FEATURE(AARCH64_BF16, bf16, "bf16", 0, AARCH64_HWCAP2_BF16) \
FEATURE(AARCH64_DGH, dgh, "dgh", 0, AARCH64_HWCAP2_DGH) \
FEATURE(AARCH64_RNG, rng, "rng", 0, AARCH64_HWCAP2_RNG) \
FEATURE(AARCH64_BTI, bti, "bti", 0, AARCH64_HWCAP2_BTI)
#define DEFINE_TABLE_FEATURE_TYPE Aarch64Features
#include "define_tables.h"
static bool HandleAarch64Line(const LineResult result,
Aarch64Info* const info)
@ -89,7 +75,11 @@ static bool HandleAarch64Line(const LineResult result,
{
if (CpuFeatures_StringView_IsEquals(key, str("Features")))
{
CpuFeatures_SetFromFlags(kConfigsSize, kConfigs, value, &info->features);
for (size_t i = 0; i < AARCH64_LAST_; ++i)
{
kSetters[i](&info->features,
CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i]));
}
}
else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer")))
{
@ -133,17 +123,20 @@ static const Aarch64Info kEmptyAarch64Info;
Aarch64Info GetAarch64Info(void)
{
assert(kConfigsSize == AARCH64_LAST_);
// capabilities are fetched from both getauxval and /proc/cpuinfo so we can
// have some information if the executable is sandboxed (aka no access to
// /proc/cpuinfo).
Aarch64Info info = kEmptyAarch64Info;
FillProcCpuInfoData(&info);
CpuFeatures_OverrideFromHwCaps(kConfigsSize, kConfigs,
CpuFeatures_GetHardwareCapabilities(),
&info.features);
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
for (size_t i = 0; i < AARCH64_LAST_; ++i)
{
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps))
{
kSetters[i](&info.features, true);
}
}
return info;
}
@ -154,14 +147,12 @@ Aarch64Info GetAarch64Info(void)
int GetAarch64FeaturesEnumValue(const Aarch64Features* features,
Aarch64FeaturesEnum value)
{
if (value >= kConfigsSize)
return false;
return kConfigs[value].get_bit((Aarch64Features*)features);
if (value >= AARCH64_LAST_) return false;
return kGetters[value](features);
}
const char* GetAarch64FeaturesEnumName(Aarch64FeaturesEnum value)
{
if (value >= kConfigsSize)
return "unknown feature";
return kConfigs[value].proc_cpuinfo_flag;
if (value >= AARCH64_LAST_) return "unknown feature";
return kCpuInfoFlags[value];
}

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
#include "cpuinfo_arm.h"
@ -7,69 +7,41 @@
#include "internal/hwcaps.h"
#include "internal/stack_line_reader.h"
#include "internal/string_view.h"
#include "internal/unix_features_aggregator.h"
#include <assert.h>
#include <ctype.h>
DECLARE_SETTER_AND_GETTER(ArmFeatures, swp)
DECLARE_SETTER_AND_GETTER(ArmFeatures, half)
DECLARE_SETTER_AND_GETTER(ArmFeatures, thumb)
DECLARE_SETTER_AND_GETTER(ArmFeatures, _26bit)
DECLARE_SETTER_AND_GETTER(ArmFeatures, fastmult)
DECLARE_SETTER_AND_GETTER(ArmFeatures, fpa)
DECLARE_SETTER_AND_GETTER(ArmFeatures, vfp)
DECLARE_SETTER_AND_GETTER(ArmFeatures, edsp)
DECLARE_SETTER_AND_GETTER(ArmFeatures, java)
DECLARE_SETTER_AND_GETTER(ArmFeatures, iwmmxt)
DECLARE_SETTER_AND_GETTER(ArmFeatures, crunch)
DECLARE_SETTER_AND_GETTER(ArmFeatures, thumbee)
DECLARE_SETTER_AND_GETTER(ArmFeatures, neon)
DECLARE_SETTER_AND_GETTER(ArmFeatures, vfpv3)
DECLARE_SETTER_AND_GETTER(ArmFeatures, vfpv3d16)
DECLARE_SETTER_AND_GETTER(ArmFeatures, tls)
DECLARE_SETTER_AND_GETTER(ArmFeatures, vfpv4)
DECLARE_SETTER_AND_GETTER(ArmFeatures, idiva)
DECLARE_SETTER_AND_GETTER(ArmFeatures, idivt)
DECLARE_SETTER_AND_GETTER(ArmFeatures, vfpd32)
DECLARE_SETTER_AND_GETTER(ArmFeatures, lpae)
DECLARE_SETTER_AND_GETTER(ArmFeatures, evtstrm)
DECLARE_SETTER_AND_GETTER(ArmFeatures, aes)
DECLARE_SETTER_AND_GETTER(ArmFeatures, pmull)
DECLARE_SETTER_AND_GETTER(ArmFeatures, sha1)
DECLARE_SETTER_AND_GETTER(ArmFeatures, sha2)
DECLARE_SETTER_AND_GETTER(ArmFeatures, crc32)
static const CapabilityConfig kConfigs[] = {
[ARM_SWP] = {{ARM_HWCAP_SWP, 0}, "swp", &set_swp, &get_swp}, //
[ARM_HALF] = {{ARM_HWCAP_HALF, 0}, "half", &set_half, &get_half}, //
[ARM_THUMB] = {{ARM_HWCAP_THUMB, 0}, "thumb", &set_thumb, &get_thumb}, //
[ARM_26BIT] = {{ARM_HWCAP_26BIT, 0}, "26bit", &set__26bit, &get__26bit}, //
[ARM_FASTMULT] = {{ARM_HWCAP_FAST_MULT, 0}, "fastmult", &set_fastmult, &get_fastmult}, //
[ARM_FPA] = {{ARM_HWCAP_FPA, 0}, "fpa", &set_fpa, &get_fpa}, //
[ARM_VFP] = {{ARM_HWCAP_VFP, 0}, "vfp", &set_vfp, &get_vfp}, //
[ARM_EDSP] = {{ARM_HWCAP_EDSP, 0}, "edsp", &set_edsp, &get_edsp}, //
[ARM_JAVA] = {{ARM_HWCAP_JAVA, 0}, "java", &set_java, &get_java}, //
[ARM_IWMMXT] = {{ARM_HWCAP_IWMMXT, 0}, "iwmmxt", &set_iwmmxt, &get_iwmmxt}, //
[ARM_CRUNCH] = {{ARM_HWCAP_CRUNCH, 0}, "crunch", &set_crunch, &get_crunch}, //
[ARM_THUMBEE] = {{ARM_HWCAP_THUMBEE, 0}, "thumbee", &set_thumbee, &get_thumbee}, //
[ARM_NEON] = {{ARM_HWCAP_NEON, 0}, "neon", &set_neon, &get_neon}, //
[ARM_VFPV3] = {{ARM_HWCAP_VFPV3, 0}, "vfpv3", &set_vfpv3, &get_vfpv3}, //
[ARM_VFPV3D16] = {{ARM_HWCAP_VFPV3D16, 0}, "vfpv3d16", &set_vfpv3d16, &get_vfpv3d16}, //
[ARM_TLS] = {{ARM_HWCAP_TLS, 0}, "tls", &set_tls, &get_tls}, //
[ARM_VFPV4] = {{ARM_HWCAP_VFPV4, 0}, "vfpv4", &set_vfpv4, &get_vfpv4}, //
[ARM_IDIVA] = {{ARM_HWCAP_IDIVA, 0}, "idiva", &set_idiva, &get_idiva}, //
[ARM_IDIVT] = {{ARM_HWCAP_IDIVT, 0}, "idivt", &set_idivt, &get_idivt}, //
[ARM_VFPD32] = {{ARM_HWCAP_VFPD32, 0}, "vfpd32", &set_vfpd32, &get_vfpd32}, //
[ARM_LPAE] = {{ARM_HWCAP_LPAE, 0}, "lpae", &set_lpae, &get_lpae}, //
[ARM_EVTSTRM] = {{ARM_HWCAP_EVTSTRM, 0}, "evtstrm", &set_evtstrm, &get_evtstrm}, //
[ARM_AES] = {{0, ARM_HWCAP2_AES}, "aes", &set_aes, &get_aes}, //
[ARM_PMULL] = {{0, ARM_HWCAP2_PMULL}, "pmull", &set_pmull, &get_pmull}, //
[ARM_SHA1] = {{0, ARM_HWCAP2_SHA1}, "sha1", &set_sha1, &get_sha1}, //
[ARM_SHA2] = {{0, ARM_HWCAP2_SHA2}, "sha2", &set_sha2, &get_sha2}, //
[ARM_CRC32] = {{0, ARM_HWCAP2_CRC32}, "crc32", &set_crc32, &get_crc32}, //
};
static const size_t kConfigsSize = sizeof(kConfigs) / sizeof(CapabilityConfig);
// Generation of feature's getters/setters functions and kGetters, kSetters,
// kCpuInfoFlags and kHardwareCapabilities global tables.
#define DEFINE_TABLE_FEATURES \
FEATURE(ARM_SWP, swp, "swp", ARM_HWCAP_SWP, 0) \
FEATURE(ARM_HALF, half, "half", ARM_HWCAP_HALF, 0) \
FEATURE(ARM_THUMB, thumb, "thumb", ARM_HWCAP_THUMB, 0) \
FEATURE(ARM_26BIT, _26bit, "26bit", ARM_HWCAP_26BIT, 0) \
FEATURE(ARM_FASTMULT, fastmult, "fastmult", ARM_HWCAP_FAST_MULT, 0) \
FEATURE(ARM_FPA, fpa, "fpa", ARM_HWCAP_FPA, 0) \
FEATURE(ARM_VFP, vfp, "vfp", ARM_HWCAP_VFP, 0) \
FEATURE(ARM_EDSP, edsp, "edsp", ARM_HWCAP_EDSP, 0) \
FEATURE(ARM_JAVA, java, "java", ARM_HWCAP_JAVA, 0) \
FEATURE(ARM_IWMMXT, iwmmxt, "iwmmxt", ARM_HWCAP_IWMMXT, 0) \
FEATURE(ARM_CRUNCH, crunch, "crunch", ARM_HWCAP_CRUNCH, 0) \
FEATURE(ARM_THUMBEE, thumbee, "thumbee", ARM_HWCAP_THUMBEE, 0) \
FEATURE(ARM_NEON, neon, "neon", ARM_HWCAP_NEON, 0) \
FEATURE(ARM_VFPV3, vfpv3, "vfpv3", ARM_HWCAP_VFPV3, 0) \
FEATURE(ARM_VFPV3D16, vfpv3d16, "vfpv3d16", ARM_HWCAP_VFPV3D16, 0) \
FEATURE(ARM_TLS, tls, "tls", ARM_HWCAP_TLS, 0) \
FEATURE(ARM_VFPV4, vfpv4, "vfpv4", ARM_HWCAP_VFPV4, 0) \
FEATURE(ARM_IDIVA, idiva, "idiva", ARM_HWCAP_IDIVA, 0) \
FEATURE(ARM_IDIVT, idivt, "idivt", ARM_HWCAP_IDIVT, 0) \
FEATURE(ARM_VFPD32, vfpd32, "vfpd32", ARM_HWCAP_VFPD32, 0) \
FEATURE(ARM_LPAE, lpae, "lpae", ARM_HWCAP_LPAE, 0) \
FEATURE(ARM_EVTSTRM, evtstrm, "evtstrm", ARM_HWCAP_EVTSTRM, 0) \
FEATURE(ARM_AES, aes, "aes", 0, ARM_HWCAP2_AES) \
FEATURE(ARM_PMULL, pmull, "pmull", 0, ARM_HWCAP2_PMULL) \
FEATURE(ARM_SHA1, sha1, "sha1", 0, ARM_HWCAP2_SHA1) \
FEATURE(ARM_SHA2, sha2, "sha2", 0, ARM_HWCAP2_SHA2) \
FEATURE(ARM_CRC32, crc32, "crc32", 0, ARM_HWCAP2_CRC32)
#define DEFINE_TABLE_FEATURE_TYPE ArmFeatures
#include "define_tables.h"
typedef struct
{
@ -97,7 +69,11 @@ static bool HandleArmLine(const LineResult result, ArmInfo* const info,
{
if (CpuFeatures_StringView_IsEquals(key, str("Features")))
{
CpuFeatures_SetFromFlags(kConfigsSize, kConfigs, value, &info->features);
for (size_t i = 0; i < ARM_LAST_; ++i)
{
kSetters[i](&info->features,
CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i]));
}
}
else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer")))
{
@ -123,7 +99,8 @@ static bool HandleArmLine(const LineResult result, ArmInfo* const info,
CpuFeatures_StringView_KeepFront(value, IndexOfNonDigit(value));
info->architecture = CpuFeatures_StringView_ParsePositiveNumber(digits);
}
else if (CpuFeatures_StringView_IsEquals(key, str("Processor")) || CpuFeatures_StringView_IsEquals(key, str("model name")))
else if (CpuFeatures_StringView_IsEquals(key, str("Processor")) ||
CpuFeatures_StringView_IsEquals(key, str("model name")))
{
// Android reports this in a non-Linux standard "Processor" but sometimes
// also in "model name", Linux reports it only in "model name"
@ -226,9 +203,14 @@ ArmInfo GetArmInfo(void)
ProcCpuInfoData proc_cpu_info_data = kEmptyProcCpuInfoData;
FillProcCpuInfoData(&info, &proc_cpu_info_data);
CpuFeatures_OverrideFromHwCaps(kConfigsSize, kConfigs,
CpuFeatures_GetHardwareCapabilities(),
&info.features);
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
for (size_t i = 0; i < ARM_LAST_; ++i)
{
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps))
{
kSetters[i](&info.features, true);
}
}
FixErrors(&info, &proc_cpu_info_data);
@ -241,14 +223,12 @@ ArmInfo GetArmInfo(void)
int GetArmFeaturesEnumValue(const ArmFeatures* features,
ArmFeaturesEnum value)
{
if (value >= kConfigsSize)
return false;
return kConfigs[value].get_bit((ArmFeatures*)features);
if (value >= ARM_LAST_) return false;
return kGetters[value](features);
}
const char* GetArmFeaturesEnumName(ArmFeaturesEnum value)
{
if (value >= kConfigsSize)
return "unknown feature";
return kConfigs[value].proc_cpuinfo_flag;
if (value >= ARM_LAST_) return "unknown feature";
return kCpuInfoFlags[value];
}

View File

@ -1,23 +1,21 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
#include "cpuinfo_mips.h"
#include "internal/filesystem.h"
#include "internal/hwcaps.h"
#include "internal/stack_line_reader.h"
#include "internal/string_view.h"
#include "internal/unix_features_aggregator.h"
#include <assert.h>
DECLARE_SETTER_AND_GETTER(MipsFeatures, msa)
DECLARE_SETTER_AND_GETTER(MipsFeatures, eva)
DECLARE_SETTER_AND_GETTER(MipsFeatures, r6)
static const CapabilityConfig kConfigs[] = {
[MIPS_MSA] = {{MIPS_HWCAP_MSA, 0}, "msa", &set_msa, &get_msa}, //
[MIPS_EVA] = {{0, 0}, "eva", &set_eva, &get_eva}, //
[MIPS_R6] = {{MIPS_HWCAP_R6, 0}, "r6", &set_r6, &get_r6}, //
};
static const size_t kConfigsSize = sizeof(kConfigs) / sizeof(CapabilityConfig);
// Generation of feature's getters/setters functions and kGetters, kSetters,
// kCpuInfoFlags and kHardwareCapabilities global tables.
#define DEFINE_TABLE_FEATURES \
FEATURE(MIPS_MSA, msa, "msa", MIPS_HWCAP_MSA, 0) \
FEATURE(MIPS_EVA, eva, "eva", 0, 0) \
FEATURE(MIPS_R6, r6, "r6", MIPS_HWCAP_R6, 0)
#define DEFINE_TABLE_FEATURE_TYPE MipsFeatures
#include "define_tables.h"
static bool HandleMipsLine(const LineResult result,
MipsFeatures* const features)
@ -28,7 +26,11 @@ static bool HandleMipsLine(const LineResult result,
{
if (CpuFeatures_StringView_IsEquals(key, str("ASEs implemented")))
{
CpuFeatures_SetFromFlags(kConfigsSize, kConfigs, value, features);
for (size_t i = 0; i < MIPS_LAST_; ++i)
{
kSetters[i](features,
CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i]));
}
}
}
return !result.eof;
@ -56,17 +58,20 @@ static const MipsInfo kEmptyMipsInfo;
MipsInfo GetMipsInfo(void)
{
assert(kConfigsSize == MIPS_LAST_);
// capabilities are fetched from both getauxval and /proc/cpuinfo so we can
// have some information if the executable is sandboxed (aka no access to
// /proc/cpuinfo).
MipsInfo info = kEmptyMipsInfo;
FillProcCpuInfoData(&info.features);
CpuFeatures_OverrideFromHwCaps(kConfigsSize, kConfigs,
CpuFeatures_GetHardwareCapabilities(),
&info.features);
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
for (size_t i = 0; i < MIPS_LAST_; ++i)
{
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps))
{
kSetters[i](&info.features, true);
}
}
return info;
}
@ -76,14 +81,12 @@ MipsInfo GetMipsInfo(void)
int GetMipsFeaturesEnumValue(const MipsFeatures* features,
MipsFeaturesEnum value)
{
if (value >= kConfigsSize)
return false;
return kConfigs[value].get_bit((MipsFeatures*)features);
if (value >= MIPS_LAST_) return false;
return kGetters[value](features);
}
const char* GetMipsFeaturesEnumName(MipsFeaturesEnum value)
{
if (value >= kConfigsSize)
return "unknown feature";
return kConfigs[value].proc_cpuinfo_flag;
if (value >= MIPS_LAST_) return "unknown feature";
return kCpuInfoFlags[value];
}

View File

@ -6,99 +6,62 @@
#include "internal/filesystem.h"
#include "internal/stack_line_reader.h"
#include "internal/string_view.h"
#include "internal/unix_features_aggregator.h"
#include <assert.h>
#include <stdbool.h>
#include <string.h>
DECLARE_SETTER_AND_GETTER(PPCFeatures, ppc32)
DECLARE_SETTER_AND_GETTER(PPCFeatures, ppc64)
DECLARE_SETTER_AND_GETTER(PPCFeatures, ppc601)
DECLARE_SETTER_AND_GETTER(PPCFeatures, altivec)
DECLARE_SETTER_AND_GETTER(PPCFeatures, fpu)
DECLARE_SETTER_AND_GETTER(PPCFeatures, mmu)
DECLARE_SETTER_AND_GETTER(PPCFeatures, mac_4xx)
DECLARE_SETTER_AND_GETTER(PPCFeatures, unifiedcache)
DECLARE_SETTER_AND_GETTER(PPCFeatures, spe)
DECLARE_SETTER_AND_GETTER(PPCFeatures, efpsingle)
DECLARE_SETTER_AND_GETTER(PPCFeatures, efpdouble)
DECLARE_SETTER_AND_GETTER(PPCFeatures, no_tb)
DECLARE_SETTER_AND_GETTER(PPCFeatures, power4)
DECLARE_SETTER_AND_GETTER(PPCFeatures, power5)
DECLARE_SETTER_AND_GETTER(PPCFeatures, power5plus)
DECLARE_SETTER_AND_GETTER(PPCFeatures, cell)
DECLARE_SETTER_AND_GETTER(PPCFeatures, booke)
DECLARE_SETTER_AND_GETTER(PPCFeatures, smt)
DECLARE_SETTER_AND_GETTER(PPCFeatures, icachesnoop)
DECLARE_SETTER_AND_GETTER(PPCFeatures, arch205)
DECLARE_SETTER_AND_GETTER(PPCFeatures, pa6t)
DECLARE_SETTER_AND_GETTER(PPCFeatures, dfp)
DECLARE_SETTER_AND_GETTER(PPCFeatures, power6ext)
DECLARE_SETTER_AND_GETTER(PPCFeatures, arch206)
DECLARE_SETTER_AND_GETTER(PPCFeatures, vsx)
DECLARE_SETTER_AND_GETTER(PPCFeatures, pseries_perfmon_compat)
DECLARE_SETTER_AND_GETTER(PPCFeatures, truele)
DECLARE_SETTER_AND_GETTER(PPCFeatures, ppcle)
DECLARE_SETTER_AND_GETTER(PPCFeatures, arch207)
DECLARE_SETTER_AND_GETTER(PPCFeatures, htm)
DECLARE_SETTER_AND_GETTER(PPCFeatures, dscr)
DECLARE_SETTER_AND_GETTER(PPCFeatures, ebb)
DECLARE_SETTER_AND_GETTER(PPCFeatures, isel)
DECLARE_SETTER_AND_GETTER(PPCFeatures, tar)
DECLARE_SETTER_AND_GETTER(PPCFeatures, vcrypto)
DECLARE_SETTER_AND_GETTER(PPCFeatures, htm_nosc)
DECLARE_SETTER_AND_GETTER(PPCFeatures, arch300)
DECLARE_SETTER_AND_GETTER(PPCFeatures, ieee128)
DECLARE_SETTER_AND_GETTER(PPCFeatures, darn)
DECLARE_SETTER_AND_GETTER(PPCFeatures, scv)
DECLARE_SETTER_AND_GETTER(PPCFeatures, htm_no_suspend)
static const CapabilityConfig kConfigs[] = {
[PPC_32] = {{PPC_FEATURE_32, 0}, "ppc32", &set_ppc32, &get_ppc32},
[PPC_64] = {{PPC_FEATURE_64, 0}, "ppc64", &set_ppc64, &get_ppc64},
[PPC_601_INSTR] = {{PPC_FEATURE_601_INSTR, 0}, "ppc601", &set_ppc601, &get_ppc601},
[PPC_HAS_ALTIVEC] = {{PPC_FEATURE_HAS_ALTIVEC, 0}, "altivec", &set_altivec, &get_altivec},
[PPC_HAS_FPU] = {{PPC_FEATURE_HAS_FPU, 0}, "fpu", &set_fpu, &get_fpu},
[PPC_HAS_MMU] = {{PPC_FEATURE_HAS_MMU, 0}, "mmu", &set_mmu, &get_mmu},
[PPC_HAS_4xxMAC] = {{PPC_FEATURE_HAS_4xxMAC, 0}, "4xxmac", &set_mac_4xx, &get_mac_4xx},
[PPC_UNIFIED_CACHE] = {{PPC_FEATURE_UNIFIED_CACHE, 0}, "ucache", &set_unifiedcache, &get_unifiedcache},
[PPC_HAS_SPE] = {{PPC_FEATURE_HAS_SPE, 0}, "spe", &set_spe, &get_spe},
[PPC_HAS_EFP_SINGLE] = {{PPC_FEATURE_HAS_EFP_SINGLE, 0}, "efpsingle", &set_efpsingle, &get_efpsingle},
[PPC_HAS_EFP_DOUBLE] = {{PPC_FEATURE_HAS_EFP_DOUBLE, 0}, "efpdouble", &set_efpdouble, &get_efpdouble},
[PPC_NO_TB] = {{PPC_FEATURE_NO_TB, 0}, "notb", &set_no_tb, &get_no_tb},
[PPC_POWER4] = {{PPC_FEATURE_POWER4, 0}, "power4", &set_power4, &get_power4},
[PPC_POWER5] = {{PPC_FEATURE_POWER5, 0}, "power5", &set_power5, &get_power5},
[PPC_POWER5_PLUS] = {{PPC_FEATURE_POWER5_PLUS, 0}, "power5+", &set_power5plus, &get_power5plus},
[PPC_CELL] = {{PPC_FEATURE_CELL, 0}, "cellbe", &set_cell, &get_cell},
[PPC_BOOKE] = {{PPC_FEATURE_BOOKE, 0}, "booke", &set_booke, &get_booke},
[PPC_SMT] = {{PPC_FEATURE_SMT, 0}, "smt", &set_smt, &get_smt},
[PPC_ICACHE_SNOOP] = {{PPC_FEATURE_ICACHE_SNOOP, 0}, "ic_snoop", &set_icachesnoop, &get_icachesnoop},
[PPC_ARCH_2_05] = {{PPC_FEATURE_ARCH_2_05, 0}, "arch_2_05", &set_arch205, &get_arch205},
[PPC_PA6T] = {{PPC_FEATURE_PA6T, 0}, "pa6t", &set_pa6t, &get_pa6t},
[PPC_HAS_DFP] = {{PPC_FEATURE_HAS_DFP, 0}, "dfp", &set_dfp, &get_dfp},
[PPC_POWER6_EXT] = {{PPC_FEATURE_POWER6_EXT, 0}, "power6x", &set_power6ext, &get_power6ext},
[PPC_ARCH_2_06] = {{PPC_FEATURE_ARCH_2_06, 0}, "arch_2_06", &set_arch206, &get_arch206},
[PPC_HAS_VSX] = {{PPC_FEATURE_HAS_VSX, 0}, "vsx", &set_vsx, &get_vsx},
[PPC_PSERIES_PERFMON_COMPAT] = {{PPC_FEATURE_PSERIES_PERFMON_COMPAT, 0}, "archpmu",
&set_pseries_perfmon_compat, &get_pseries_perfmon_compat},
[PPC_TRUE_LE] = {{PPC_FEATURE_TRUE_LE, 0}, "true_le", &set_truele, &get_truele},
[PPC_PPC_LE] = {{PPC_FEATURE_PPC_LE, 0}, "ppcle", &set_ppcle, &get_ppcle},
[PPC_ARCH_2_07] = {{0, PPC_FEATURE2_ARCH_2_07}, "arch_2_07", &set_arch207, &get_arch207},
[PPC_HTM] = {{0, PPC_FEATURE2_HTM}, "htm", &set_htm, &get_htm},
[PPC_DSCR] = {{0, PPC_FEATURE2_DSCR}, "dscr", &set_dscr, &get_dscr},
[PPC_EBB] = {{0, PPC_FEATURE2_EBB}, "ebb", &set_ebb, &get_ebb},
[PPC_ISEL] = {{0, PPC_FEATURE2_ISEL}, "isel", &set_isel, &get_isel},
[PPC_TAR] = {{0, PPC_FEATURE2_TAR}, "tar", &set_tar, &get_tar},
[PPC_VEC_CRYPTO] = {{0, PPC_FEATURE2_VEC_CRYPTO}, "vcrypto", &set_vcrypto, &get_vcrypto},
[PPC_HTM_NOSC] = {{0, PPC_FEATURE2_HTM_NOSC}, "htm-nosc", &set_htm_nosc, &get_htm_nosc},
[PPC_ARCH_3_00] = {{0, PPC_FEATURE2_ARCH_3_00}, "arch_3_00", &set_arch300, &get_arch300},
[PPC_HAS_IEEE128] = {{0, PPC_FEATURE2_HAS_IEEE128}, "ieee128", &set_ieee128, &get_ieee128},
[PPC_DARN] = {{0, PPC_FEATURE2_DARN}, "darn", &set_darn, &get_darn},
[PPC_SCV] = {{0, PPC_FEATURE2_SCV}, "scv", &set_scv, &get_scv},
[PPC_HTM_NO_SUSPEND] = {{0, PPC_FEATURE2_HTM_NO_SUSPEND}, "htm-no-suspend", &set_htm_no_suspend,
&get_htm_no_suspend},
};
static const size_t kConfigsSize = sizeof(kConfigs) / sizeof(CapabilityConfig);
// Generation of feature's getters/setters functions and kGetters, kSetters,
// kCpuInfoFlags and kHardwareCapabilities global tables.
#define DEFINE_TABLE_FEATURES \
FEATURE(PPC_32, ppc32, "ppc32", PPC_FEATURE_32, 0) \
FEATURE(PPC_64, ppc64, "ppc64", PPC_FEATURE_64, 0) \
FEATURE(PPC_601_INSTR, ppc601, "ppc601", PPC_FEATURE_601_INSTR, 0) \
FEATURE(PPC_HAS_ALTIVEC, altivec, "altivec", PPC_FEATURE_HAS_ALTIVEC, 0) \
FEATURE(PPC_HAS_FPU, fpu, "fpu", PPC_FEATURE_HAS_FPU, 0) \
FEATURE(PPC_HAS_MMU, mmu, "mmu", PPC_FEATURE_HAS_MMU, 0) \
FEATURE(PPC_HAS_4xxMAC, mac_4xx, "4xxmac", PPC_FEATURE_HAS_4xxMAC, 0) \
FEATURE(PPC_UNIFIED_CACHE, unifiedcache, "ucache", \
PPC_FEATURE_UNIFIED_CACHE, 0) \
FEATURE(PPC_HAS_SPE, spe, "spe", PPC_FEATURE_HAS_SPE, 0) \
FEATURE(PPC_HAS_EFP_SINGLE, efpsingle, "efpsingle", \
PPC_FEATURE_HAS_EFP_SINGLE, 0) \
FEATURE(PPC_HAS_EFP_DOUBLE, efpdouble, "efpdouble", \
PPC_FEATURE_HAS_EFP_DOUBLE, 0) \
FEATURE(PPC_NO_TB, no_tb, "notb", PPC_FEATURE_NO_TB, 0) \
FEATURE(PPC_POWER4, power4, "power4", PPC_FEATURE_POWER4, 0) \
FEATURE(PPC_POWER5, power5, "power5", PPC_FEATURE_POWER5, 0) \
FEATURE(PPC_POWER5_PLUS, power5plus, "power5+", PPC_FEATURE_POWER5_PLUS, 0) \
FEATURE(PPC_CELL, cell, "cellbe", PPC_FEATURE_CELL, 0) \
FEATURE(PPC_BOOKE, booke, "booke", PPC_FEATURE_BOOKE, 0) \
FEATURE(PPC_SMT, smt, "smt", PPC_FEATURE_SMT, 0) \
FEATURE(PPC_ICACHE_SNOOP, icachesnoop, "ic_snoop", PPC_FEATURE_ICACHE_SNOOP, \
0) \
FEATURE(PPC_ARCH_2_05, arch205, "arch_2_05", PPC_FEATURE_ARCH_2_05, 0) \
FEATURE(PPC_PA6T, pa6t, "pa6t", PPC_FEATURE_PA6T, 0) \
FEATURE(PPC_HAS_DFP, dfp, "dfp", PPC_FEATURE_HAS_DFP, 0) \
FEATURE(PPC_POWER6_EXT, power6ext, "power6x", PPC_FEATURE_POWER6_EXT, 0) \
FEATURE(PPC_ARCH_2_06, arch206, "arch_2_06", PPC_FEATURE_ARCH_2_06, 0) \
FEATURE(PPC_HAS_VSX, vsx, "vsx", PPC_FEATURE_HAS_VSX, 0) \
FEATURE(PPC_PSERIES_PERFMON_COMPAT, pseries_perfmon_compat, "archpmu", \
PPC_FEATURE_PSERIES_PERFMON_COMPAT, 0) \
FEATURE(PPC_TRUE_LE, truele, "true_le", PPC_FEATURE_TRUE_LE, 0) \
FEATURE(PPC_PPC_LE, ppcle, "ppcle", PPC_FEATURE_PPC_LE, 0) \
FEATURE(PPC_ARCH_2_07, arch207, "arch_2_07", 0, PPC_FEATURE2_ARCH_2_07) \
FEATURE(PPC_HTM, htm, "htm", 0, PPC_FEATURE2_HTM) \
FEATURE(PPC_DSCR, dscr, "dscr", 0, PPC_FEATURE2_DSCR) \
FEATURE(PPC_EBB, ebb, "ebb", 0, PPC_FEATURE2_EBB) \
FEATURE(PPC_ISEL, isel, "isel", 0, PPC_FEATURE2_ISEL) \
FEATURE(PPC_TAR, tar, "tar", 0, PPC_FEATURE2_TAR) \
FEATURE(PPC_VEC_CRYPTO, vcrypto, "vcrypto", 0, PPC_FEATURE2_VEC_CRYPTO) \
FEATURE(PPC_HTM_NOSC, htm_nosc, "htm-nosc", 0, PPC_FEATURE2_HTM_NOSC) \
FEATURE(PPC_ARCH_3_00, arch300, "arch_3_00", 0, PPC_FEATURE2_ARCH_3_00) \
FEATURE(PPC_HAS_IEEE128, ieee128, "ieee128", 0, PPC_FEATURE2_HAS_IEEE128) \
FEATURE(PPC_DARN, darn, "darn", 0, PPC_FEATURE2_DARN) \
FEATURE(PPC_SCV, scv, "scv", 0, PPC_FEATURE2_SCV) \
FEATURE(PPC_HTM_NO_SUSPEND, htm_no_suspend, "htm-no-suspend", 0, \
PPC_FEATURE2_HTM_NO_SUSPEND)
#define DEFINE_TABLE_FEATURE_TYPE PPCFeatures
#include "define_tables.h"
static bool HandlePPCLine(const LineResult result,
PPCPlatformStrings* const strings)
@ -158,10 +121,14 @@ PPCInfo GetPPCInfo(void)
* the auxilary vector.
*/
PPCInfo info = kEmptyPPCInfo;
CpuFeatures_OverrideFromHwCaps(kConfigsSize, kConfigs,
CpuFeatures_GetHardwareCapabilities(),
&info.features);
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
for (size_t i = 0; i < PPC_LAST_; ++i)
{
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps))
{
kSetters[i](&info.features, true);
}
}
return info;
}
@ -182,14 +149,12 @@ PPCPlatformStrings GetPPCPlatformStrings(void)
int GetPPCFeaturesEnumValue(const PPCFeatures* features,
PPCFeaturesEnum value)
{
if (value >= kConfigsSize)
return false;
return kConfigs[value].get_bit((PPCFeatures*)features);
if (value >= PPC_LAST_) return false;
return kGetters[value](features);
}
const char* GetPPCFeaturesEnumName(PPCFeaturesEnum value)
{
if (value >= kConfigsSize)
return "unknown feature";
return kConfigs[value].proc_cpuinfo_flag;
if (value >= PPC_LAST_) return "unknown feature";
return kCpuInfoFlags[value];
}

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
#include "cpuinfo_x86.h"
@ -11,6 +11,91 @@
#error "Cannot compile cpuinfo_x86 on a non x86 platform."
#endif
// Generation of feature's getters/setters functions and kGetters, kSetters,
// kCpuInfoFlags global tables.
#define DEFINE_TABLE_FEATURES \
FEATURE(X86_FPU, fpu, "fpu", 0, 0) \
FEATURE(X86_TSC, tsc, "tsc", 0, 0) \
FEATURE(X86_CX8, cx8, "cx8", 0, 0) \
FEATURE(X86_CLFSH, clfsh, "clfsh", 0, 0) \
FEATURE(X86_MMX, mmx, "mmx", 0, 0) \
FEATURE(X86_AES, aes, "aes", 0, 0) \
FEATURE(X86_ERMS, erms, "erms", 0, 0) \
FEATURE(X86_F16C, f16c, "f16c", 0, 0) \
FEATURE(X86_FMA4, fma4, "fma4", 0, 0) \
FEATURE(X86_FMA3, fma3, "fma3", 0, 0) \
FEATURE(X86_VAES, vaes, "vaes", 0, 0) \
FEATURE(X86_VPCLMULQDQ, vpclmulqdq, "vpclmulqdq", 0, 0) \
FEATURE(X86_BMI1, bmi1, "bmi1", 0, 0) \
FEATURE(X86_HLE, hle, "hle", 0, 0) \
FEATURE(X86_BMI2, bmi2, "bmi2", 0, 0) \
FEATURE(X86_RTM, rtm, "rtm", 0, 0) \
FEATURE(X86_RDSEED, rdseed, "rdseed", 0, 0) \
FEATURE(X86_CLFLUSHOPT, clflushopt, "clflushopt", 0, 0) \
FEATURE(X86_CLWB, clwb, "clwb", 0, 0) \
FEATURE(X86_SSE, sse, "sse", 0, 0) \
FEATURE(X86_SSE2, sse2, "sse2", 0, 0) \
FEATURE(X86_SSE3, sse3, "sse3", 0, 0) \
FEATURE(X86_SSSE3, ssse3, "ssse3", 0, 0) \
FEATURE(X86_SSE4_1, sse4_1, "sse4_1", 0, 0) \
FEATURE(X86_SSE4_2, sse4_2, "sse4_2", 0, 0) \
FEATURE(X86_SSE4A, sse4a, "sse4a", 0, 0) \
FEATURE(X86_AVX, avx, "avx", 0, 0) \
FEATURE(X86_AVX2, avx2, "avx2", 0, 0) \
FEATURE(X86_AVX512F, avx512f, "avx512f", 0, 0) \
FEATURE(X86_AVX512CD, avx512cd, "avx512cd", 0, 0) \
FEATURE(X86_AVX512ER, avx512er, "avx512er", 0, 0) \
FEATURE(X86_AVX512PF, avx512pf, "avx512pf", 0, 0) \
FEATURE(X86_AVX512BW, avx512bw, "avx512bw", 0, 0) \
FEATURE(X86_AVX512DQ, avx512dq, "avx512dq", 0, 0) \
FEATURE(X86_AVX512VL, avx512vl, "avx512vl", 0, 0) \
FEATURE(X86_AVX512IFMA, avx512ifma, "avx512ifma", 0, 0) \
FEATURE(X86_AVX512VBMI, avx512vbmi, "avx512vbmi", 0, 0) \
FEATURE(X86_AVX512VBMI2, avx512vbmi2, "avx512vbmi2", 0, 0) \
FEATURE(X86_AVX512VNNI, avx512vnni, "avx512vnni", 0, 0) \
FEATURE(X86_AVX512BITALG, avx512bitalg, "avx512bitalg", 0, 0) \
FEATURE(X86_AVX512VPOPCNTDQ, avx512vpopcntdq, "avx512vpopcntdq", 0, 0) \
FEATURE(X86_AVX512_4VNNIW, avx512_4vnniw, "avx512_4vnniw", 0, 0) \
FEATURE(X86_AVX512_4VBMI2, avx512_4vbmi2, "avx512_4vbmi2", 0, 0) \
FEATURE(X86_AVX512_SECOND_FMA, avx512_second_fma, "avx512_second_fma", 0, 0) \
FEATURE(X86_AVX512_4FMAPS, avx512_4fmaps, "avx512_4fmaps", 0, 0) \
FEATURE(X86_AVX512_BF16, avx512_bf16, "avx512_bf16", 0, 0) \
FEATURE(X86_AVX512_VP2INTERSECT, avx512_vp2intersect, "avx512_vp2intersect", \
0, 0) \
FEATURE(X86_AMX_BF16, amx_bf16, "amx_bf16", 0, 0) \
FEATURE(X86_AMX_TILE, amx_tile, "amx_tile", 0, 0) \
FEATURE(X86_AMX_INT8, amx_int8, "amx_int8", 0, 0) \
FEATURE(X86_PCLMULQDQ, pclmulqdq, "pclmulqdq", 0, 0) \
FEATURE(X86_SMX, smx, "smx", 0, 0) \
FEATURE(X86_SGX, sgx, "sgx", 0, 0) \
FEATURE(X86_CX16, cx16, "cx16", 0, 0) \
FEATURE(X86_SHA, sha, "sha", 0, 0) \
FEATURE(X86_POPCNT, popcnt, "popcnt", 0, 0) \
FEATURE(X86_MOVBE, movbe, "movbe", 0, 0) \
FEATURE(X86_RDRND, rdrnd, "rdrnd", 0, 0) \
FEATURE(X86_DCA, dca, "dca", 0, 0) \
FEATURE(X86_SS, ss, "ss", 0, 0)
#define DEFINE_TABLE_FEATURE_TYPE X86Features
#define DEFINE_TABLE_DONT_GENERATE_HWCAPS
#include "define_tables.h"
// The following includes are necessary to provide SSE detections on pre-AVX
// microarchitectures.
#if defined(CPU_FEATURES_OS_WINDOWS)
#include <windows.h> // IsProcessorFeaturePresent
#elif defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
#include "internal/filesystem.h" // Needed to parse /proc/cpuinfo
#include "internal/stack_line_reader.h" // Needed to parse /proc/cpuinfo
#include "internal/string_view.h" // Needed to parse /proc/cpuinfo
#elif defined(CPU_FEATURES_OS_DARWIN)
#if !defined(HAVE_SYSCTLBYNAME)
#error "Darwin needs support for sysctlbyname"
#endif
#include <sys/sysctl.h>
#else
#error "Unsupported OS"
#endif // CPU_FEATURES_OS
////////////////////////////////////////////////////////////////////////////////
// Definitions for CpuId and GetXCR0Eax.
////////////////////////////////////////////////////////////////////////////////
@ -21,7 +106,7 @@
#include <cpuid.h>
Leaf CpuIdEx(uint32_t leaf_id, int ecx)
Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx)
{
Leaf leaf;
__cpuid_count(leaf_id, ecx, leaf.eax, leaf.ebx, leaf.ecx, leaf.edx);
@ -45,7 +130,7 @@ uint32_t GetXCR0Eax(void)
#include <immintrin.h>
#include <intrin.h> // For __cpuidex()
Leaf CpuIdEx(uint32_t leaf_id, int ecx)
Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx)
{
Leaf leaf;
int data[4];
@ -65,7 +150,7 @@ uint32_t GetXCR0Eax(void) { return (uint32_t)_xgetbv(0); }
static Leaf CpuId(uint32_t leaf_id)
{
return CpuIdEx(leaf_id, 0);
return GetCpuidLeaf(leaf_id, 0);
}
static const Leaf kEmptyLeaf;
@ -74,7 +159,7 @@ static Leaf SafeCpuIdEx(uint32_t max_cpuid_leaf, uint32_t leaf_id, int ecx)
{
if (leaf_id <= max_cpuid_leaf)
{
return CpuIdEx(leaf_id, ecx);
return GetCpuidLeaf(leaf_id, ecx);
}
else
{
@ -92,6 +177,8 @@ static Leaf SafeCpuId(uint32_t max_cpuid_leaf, uint32_t leaf_id)
#define MASK_MASKREG 0x20
#define MASK_ZMM0_15 0x40
#define MASK_ZMM16_31 0x80
#define MASK_XTILECFG 0x20000
#define MASK_XTILEDATA 0x40000
static bool HasMask(uint32_t value, uint32_t mask)
{
@ -120,6 +207,46 @@ static bool HasZmmOsXSave(uint32_t xcr0_eax)
MASK_ZMM16_31);
}
// Checks that operating system saves and restores AMX/TMUL state during context
// switches.
static bool HasTmmOsXSave(uint32_t xcr0_eax)
{
return HasMask(xcr0_eax, MASK_XMM | MASK_YMM | MASK_MASKREG | MASK_ZMM0_15 |
MASK_ZMM16_31 | MASK_XTILECFG | MASK_XTILEDATA);
}
static bool HasSecondFMA(uint32_t model)
{
// Skylake server
if (model == 0x55)
{
char proc_name[49] = {0};
FillX86BrandString(proc_name);
// detect Xeon
if (proc_name[9] == 'X')
{
// detect Silver or Bronze
if (proc_name[17] == 'S' || proc_name[17] == 'B') return false;
// detect Gold 5_20 and below, except for Gold 53__
if (proc_name[17] == 'G' && proc_name[22] == '5')
return ((proc_name[23] == '3') ||
(proc_name[24] == '2' && proc_name[25] == '2'));
// detect Xeon W 210x
if (proc_name[17] == 'W' && proc_name[21] == '0') return false;
// detect Xeon D 2xxx
if (proc_name[17] == 'D' && proc_name[19] == '2' && proc_name[20] == '1')
return false;
}
return true;
}
// Cannon Lake client
if (model == 0x66) return false;
// Ice Lake client
if (model == 0x7d || model == 0x7e) return false;
// This is the right default...
return true;
}
static void SetVendor(const Leaf leaf, char* const vendor)
{
*(uint32_t*)(vendor) = leaf.ebx;
@ -1061,23 +1188,126 @@ static void ParseLeaf4(const int max_cpuid_leaf, CacheInfo* info)
// Avoid to recompute them since each call to cpuid is ~100 cycles.
typedef struct
{
bool have_sse;
bool have_sse_via_os;
bool have_sse_via_cpuid;
bool have_avx;
bool have_avx512;
bool have_amx;
} OsSupport;
static const OsSupport kEmptyOsSupport;
static OsSupport CheckOsSupport(const uint32_t max_cpuid_leaf)
{
const Leaf leaf_1 = SafeCpuId(max_cpuid_leaf, 1);
const bool have_xsave = IsBitSet(leaf_1.ecx, 26);
const bool have_osxsave = IsBitSet(leaf_1.ecx, 27);
const bool have_xcr0 = have_xsave && have_osxsave;
OsSupport os_support = kEmptyOsSupport;
if (have_xcr0)
{
// AVX capable cpu will expose XCR0.
const uint32_t xcr0_eax = GetXCR0Eax();
os_support.have_sse_via_cpuid = HasXmmOsXSave(xcr0_eax);
os_support.have_avx = HasYmmOsXSave(xcr0_eax);
os_support.have_avx512 = HasZmmOsXSave(xcr0_eax);
os_support.have_amx = HasTmmOsXSave(xcr0_eax);
}
else
{
// Atom based or older cpus need to ask the OS for sse support.
os_support.have_sse_via_os = true;
}
return os_support;
}
#if defined(CPU_FEATURES_OS_WINDOWS)
#if defined(CPU_FEATURES_MOCK_CPUID_X86)
extern bool GetWindowsIsProcessorFeaturePresent(DWORD);
#else // CPU_FEATURES_MOCK_CPUID_X86
static bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature)
{
return IsProcessorFeaturePresent(ProcessorFeature);
}
#endif
#endif // CPU_FEATURES_OS_WINDOWS
#if defined(CPU_FEATURES_OS_DARWIN)
#if defined(CPU_FEATURES_MOCK_CPUID_X86)
extern bool GetDarwinSysCtlByName(const char*);
#else // CPU_FEATURES_MOCK_CPUID_X86
static bool GetDarwinSysCtlByName(const char* name)
{
int enabled;
size_t enabled_len = sizeof(enabled);
const int failure = sysctlbyname(name, &enabled, &enabled_len, NULL, 0);
return failure ? false : enabled;
}
#endif
#endif // CPU_FEATURES_OS_DARWIN
static void DetectSseViaOs(X86Features* features)
{
#if defined(CPU_FEATURES_OS_WINDOWS)
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent
features->sse =
GetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE);
features->sse2 =
GetWindowsIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE);
features->sse3 =
GetWindowsIsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE);
#elif defined(CPU_FEATURES_OS_DARWIN)
// Handling Darwin platform through sysctlbyname.
features->sse = GetDarwinSysCtlByName("hw.optional.sse");
features->sse2 = GetDarwinSysCtlByName("hw.optional.sse2");
features->sse3 = GetDarwinSysCtlByName("hw.optional.sse3");
features->ssse3 = GetDarwinSysCtlByName("hw.optional.supplementalsse3");
features->sse4_1 = GetDarwinSysCtlByName("hw.optional.sse4_1");
features->sse4_2 = GetDarwinSysCtlByName("hw.optional.sse4_2");
#elif defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
// Handling Linux platform through /proc/cpuinfo.
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
if (fd >= 0)
{
StackLineReader reader;
StackLineReader_Initialize(&reader, fd);
for (;;)
{
const LineResult result = StackLineReader_NextLine(&reader);
const StringView line = result.line;
StringView key, value;
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value))
{
if (CpuFeatures_StringView_IsEquals(key, str("flags")))
{
features->sse = CpuFeatures_StringView_HasWord(value, "sse");
features->sse2 = CpuFeatures_StringView_HasWord(value, "sse2");
features->sse3 = CpuFeatures_StringView_HasWord(value, "sse3");
features->ssse3 = CpuFeatures_StringView_HasWord(value, "ssse3");
features->sse4_1 = CpuFeatures_StringView_HasWord(value, "sse4_1");
features->sse4_2 = CpuFeatures_StringView_HasWord(value, "sse4_2");
break;
}
}
if (result.eof) break;
}
CpuFeatures_CloseFile(fd);
}
#else
#error "Unsupported fallback detection of SSE OS support."
#endif
}
// Reference https://en.wikipedia.org/wiki/CPUID.
static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info, OsSupport* os_support)
static void ParseCpuId(const uint32_t max_cpuid_leaf,
const OsSupport os_support, X86Info* info)
{
const Leaf leaf_1 = SafeCpuId(max_cpuid_leaf, 1);
const Leaf leaf_7 = SafeCpuId(max_cpuid_leaf, 7);
const bool have_xsave = IsBitSet(leaf_1.ecx, 26);
const bool have_osxsave = IsBitSet(leaf_1.ecx, 27);
const uint32_t xcr0_eax = (have_xsave && have_osxsave) ? GetXCR0Eax() : 0;
os_support->have_sse = HasXmmOsXSave(xcr0_eax);
os_support->have_avx = HasYmmOsXSave(xcr0_eax);
os_support->have_avx512 = HasZmmOsXSave(xcr0_eax);
const Leaf leaf_7_1 = SafeCpuIdEx(max_cpuid_leaf, 7, 1);
const uint32_t family = ExtractBitRange(leaf_1.eax, 11, 8);
const uint32_t extended_family = ExtractBitRange(leaf_1.eax, 27, 20);
@ -1118,7 +1348,11 @@ static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info, OsSupport*
features->vaes = IsBitSet(leaf_7.ecx, 9);
features->vpclmulqdq = IsBitSet(leaf_7.ecx, 10);
if (os_support->have_sse)
if (os_support.have_sse_via_os)
{
DetectSseViaOs(features);
}
else if (os_support.have_sse_via_cpuid)
{
features->sse = IsBitSet(leaf_1.edx, 25);
features->sse2 = IsBitSet(leaf_1.edx, 26);
@ -1128,14 +1362,14 @@ static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info, OsSupport*
features->sse4_2 = IsBitSet(leaf_1.ecx, 20);
}
if (os_support->have_avx)
if (os_support.have_avx)
{
features->fma3 = IsBitSet(leaf_1.ecx, 12);
features->avx = IsBitSet(leaf_1.ecx, 28);
features->avx2 = IsBitSet(leaf_7.ebx, 5);
}
if (os_support->have_avx512)
if (os_support.have_avx512)
{
features->avx512f = IsBitSet(leaf_7.ebx, 16);
features->avx512cd = IsBitSet(leaf_7.ebx, 28);
@ -1152,18 +1386,31 @@ static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info, OsSupport*
features->avx512vpopcntdq = IsBitSet(leaf_7.ecx, 14);
features->avx512_4vnniw = IsBitSet(leaf_7.edx, 2);
features->avx512_4vbmi2 = IsBitSet(leaf_7.edx, 3);
features->avx512_second_fma = HasSecondFMA(info->model);
features->avx512_4fmaps = IsBitSet(leaf_7.edx, 3);
features->avx512_bf16 = IsBitSet(leaf_7_1.eax, 5);
features->avx512_vp2intersect = IsBitSet(leaf_7.edx, 8);
}
if (os_support.have_amx)
{
features->amx_bf16 = IsBitSet(leaf_7.edx, 22);
features->amx_tile = IsBitSet(leaf_7.edx, 24);
features->amx_int8 = IsBitSet(leaf_7.edx, 25);
}
}
// Reference https://en.wikipedia.org/wiki/CPUID#EAX=80000000h:_Get_Highest_Extended_Function_Implemented.
static void ParseExtraAMDCpuId(const uint32_t max_cpuid_leaf, X86Info* info, OsSupport os_support)
// Reference
// https://en.wikipedia.org/wiki/CPUID#EAX=80000000h:_Get_Highest_Extended_Function_Implemented.
static void ParseExtraAMDCpuId(X86Info* info, OsSupport os_support)
{
const Leaf leaf_80000000 = CpuId(0x80000000);
const Leaf leaf_80000001 = SafeCpuId(leaf_80000000.eax, 0x80000001);
const uint32_t max_extended_cpuid_leaf = leaf_80000000.eax;
const Leaf leaf_80000001 = SafeCpuId(max_extended_cpuid_leaf, 0x80000001);
X86Features* const features = &info->features;
if (os_support.have_sse)
if (os_support.have_sse_via_cpuid)
{
features->sse4a = IsBitSet(leaf_80000001.ecx, 6);
}
@ -1175,23 +1422,24 @@ static void ParseExtraAMDCpuId(const uint32_t max_cpuid_leaf, X86Info* info, OsS
}
static const X86Info kEmptyX86Info;
static const OsSupport kEmptyOsSupport;
static const CacheInfo kEmptyCacheInfo;
X86Info GetX86Info(void)
{
X86Info info = kEmptyX86Info;
OsSupport os_support = kEmptyOsSupport;
const Leaf leaf_0 = CpuId(0);
const uint32_t max_cpuid_leaf = leaf_0.eax;
const bool is_intel = IsVendor(leaf_0, "GenuineIntel");
const bool is_amd = IsVendor(leaf_0, "AuthenticAMD");
SetVendor(leaf_0, info.vendor);
if (IsVendor(leaf_0, "GenuineIntel") || IsVendor(leaf_0, "AuthenticAMD"))
if (is_intel || is_amd)
{
ParseCpuId(max_cpuid_leaf, &info, &os_support);
}
if (IsVendor(leaf_0, "AuthenticAMD"))
{
ParseExtraAMDCpuId(max_cpuid_leaf, &info, os_support);
const uint32_t max_cpuid_leaf = leaf_0.eax;
const OsSupport os_support = CheckOsSupport(max_cpuid_leaf);
ParseCpuId(max_cpuid_leaf, os_support, &info);
if (is_amd)
{
ParseExtraAMDCpuId(&info, os_support);
}
}
return info;
}
@ -1275,9 +1523,20 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info)
case CPUID(0x06, 0x66):
// https://en.wikipedia.org/wiki/Cannon_Lake_(microarchitecture)
return INTEL_CNL;
case CPUID(0x06, 0x7E):
case CPUID(0x06, 0x7D): // client
case CPUID(0x06, 0x7E): // client
case CPUID(0x06, 0x9D): // NNP-I
case CPUID(0x06, 0x6A): // server
case CPUID(0x06, 0x6C): // server
// https://en.wikipedia.org/wiki/Ice_Lake_(microprocessor)
return INTEL_ICL;
case CPUID(0x06, 0x8C):
case CPUID(0x06, 0x8D):
// https://en.wikipedia.org/wiki/Tiger_Lake_(microarchitecture)
return INTEL_TGL;
case CPUID(0x06, 0x8F):
// https://en.wikipedia.org/wiki/Sapphire_Rapids
return INTEL_SPR;
case CPUID(0x06, 0x8E):
switch (info->stepping)
{
@ -1354,234 +1613,14 @@ void FillX86BrandString(char brand_string[49])
int GetX86FeaturesEnumValue(const X86Features* features,
X86FeaturesEnum value)
{
switch (value)
{
case X86_FPU:
return features->fpu;
case X86_TSC:
return features->tsc;
case X86_CX8:
return features->cx8;
case X86_CLFSH:
return features->clfsh;
case X86_MMX:
return features->mmx;
case X86_AES:
return features->aes;
case X86_ERMS:
return features->erms;
case X86_F16C:
return features->f16c;
case X86_FMA4:
return features->fma4;
case X86_FMA3:
return features->fma3;
case X86_VAES:
return features->vaes;
case X86_VPCLMULQDQ:
return features->vpclmulqdq;
case X86_BMI1:
return features->bmi1;
case X86_HLE:
return features->hle;
case X86_BMI2:
return features->bmi2;
case X86_RTM:
return features->rtm;
case X86_RDSEED:
return features->rdseed;
case X86_CLFLUSHOPT:
return features->clflushopt;
case X86_CLWB:
return features->clwb;
case X86_SSE:
return features->sse;
case X86_SSE2:
return features->sse2;
case X86_SSE3:
return features->sse3;
case X86_SSSE3:
return features->ssse3;
case X86_SSE4_1:
return features->sse4_1;
case X86_SSE4_2:
return features->sse4_2;
case X86_SSE4A:
return features->sse4a;
case X86_AVX:
return features->avx;
case X86_AVX2:
return features->avx2;
case X86_AVX512F:
return features->avx512f;
case X86_AVX512CD:
return features->avx512cd;
case X86_AVX512ER:
return features->avx512er;
case X86_AVX512PF:
return features->avx512pf;
case X86_AVX512BW:
return features->avx512bw;
case X86_AVX512DQ:
return features->avx512dq;
case X86_AVX512VL:
return features->avx512vl;
case X86_AVX512IFMA:
return features->avx512ifma;
case X86_AVX512VBMI:
return features->avx512vbmi;
case X86_AVX512VBMI2:
return features->avx512vbmi2;
case X86_AVX512VNNI:
return features->avx512vnni;
case X86_AVX512BITALG:
return features->avx512bitalg;
case X86_AVX512VPOPCNTDQ:
return features->avx512vpopcntdq;
case X86_AVX512_4VNNIW:
return features->avx512_4vnniw;
case X86_AVX512_4VBMI2:
return features->avx512_4vbmi2;
case X86_PCLMULQDQ:
return features->pclmulqdq;
case X86_SMX:
return features->smx;
case X86_SGX:
return features->sgx;
case X86_CX16:
return features->cx16;
case X86_SHA:
return features->sha;
case X86_POPCNT:
return features->popcnt;
case X86_MOVBE:
return features->movbe;
case X86_RDRND:
return features->rdrnd;
case X86_DCA:
return features->dca;
case X86_SS:
return features->ss;
case X86_LAST_:
break;
}
return false;
if (value >= X86_LAST_) return false;
return kGetters[value](features);
}
const char* GetX86FeaturesEnumName(X86FeaturesEnum value)
{
switch (value)
{
case X86_FPU:
return "fpu";
case X86_TSC:
return "tsc";
case X86_CX8:
return "cx8";
case X86_CLFSH:
return "clfsh";
case X86_MMX:
return "mmx";
case X86_AES:
return "aes";
case X86_ERMS:
return "erms";
case X86_F16C:
return "f16c";
case X86_FMA4:
return "fma4";
case X86_FMA3:
return "fma3";
case X86_VAES:
return "vaes";
case X86_VPCLMULQDQ:
return "vpclmulqdq";
case X86_BMI1:
return "bmi1";
case X86_HLE:
return "hle";
case X86_BMI2:
return "bmi2";
case X86_RTM:
return "rtm";
case X86_RDSEED:
return "rdseed";
case X86_CLFLUSHOPT:
return "clflushopt";
case X86_CLWB:
return "clwb";
case X86_SSE:
return "sse";
case X86_SSE2:
return "sse2";
case X86_SSE3:
return "sse3";
case X86_SSSE3:
return "ssse3";
case X86_SSE4_1:
return "sse4_1";
case X86_SSE4_2:
return "sse4_2";
case X86_SSE4A:
return "sse4a";
case X86_AVX:
return "avx";
case X86_AVX2:
return "avx2";
case X86_AVX512F:
return "avx512f";
case X86_AVX512CD:
return "avx512cd";
case X86_AVX512ER:
return "avx512er";
case X86_AVX512PF:
return "avx512pf";
case X86_AVX512BW:
return "avx512bw";
case X86_AVX512DQ:
return "avx512dq";
case X86_AVX512VL:
return "avx512vl";
case X86_AVX512IFMA:
return "avx512ifma";
case X86_AVX512VBMI:
return "avx512vbmi";
case X86_AVX512VBMI2:
return "avx512vbmi2";
case X86_AVX512VNNI:
return "avx512vnni";
case X86_AVX512BITALG:
return "avx512bitalg";
case X86_AVX512VPOPCNTDQ:
return "avx512vpopcntdq";
case X86_AVX512_4VNNIW:
return "avx512_4vnniw";
case X86_AVX512_4VBMI2:
return "avx512_4vbmi2";
case X86_PCLMULQDQ:
return "pclmulqdq";
case X86_SMX:
return "smx";
case X86_SGX:
return "sgx";
case X86_CX16:
return "cx16";
case X86_SHA:
return "sha";
case X86_POPCNT:
return "popcnt";
case X86_MOVBE:
return "movbe";
case X86_RDRND:
return "rdrnd";
case X86_DCA:
return "dca";
case X86_SS:
return "ss";
case X86_LAST_:
break;
}
return "unknown_feature";
if (value >= X86_LAST_) return "unknown_feature";
return kCpuInfoFlags[value];
}
const char* GetX86MicroarchitectureName(X86Microarchitecture uarch)
@ -1624,6 +1663,10 @@ const char* GetX86MicroarchitectureName(X86Microarchitecture uarch)
return "INTEL_CNL";
case INTEL_ICL:
return "INTEL_ICL";
case INTEL_TGL:
return "INTEL_TGL";
case INTEL_SPR:
return "INTEL_SPR";
case AMD_HAMMER:
return "AMD_HAMMER";
case AMD_K10:

View File

@ -0,0 +1,58 @@
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
// The following preprocessor constants must be defined before including this
// file:
// - DEFINE_TABLE_FEATURE_TYPE, the underlying type (e.g. X86Features)
// - DEFINE_TABLE_FEATURES, the list of FEATURE macros to be inserted.
// This file is to be included once per `cpuinfo_XXX.c` in order to construct
// feature getters and setters functions as well as several enum indexed tables
// from the db file.
// - `kGetters` a table of getters function pointers from feature enum to
// retrieve a feature,
// - `kSetters` a table of setters function pointers from feature enum to set a
// feature,
// - `kCpuInfoFlags` a table of strings from feature enum to /proc/cpuinfo
// flags,
// - `kHardwareCapabilities` a table of HardwareCapabilities structs indexed by
// their feature enum.
#ifndef SRC_DEFINE_TABLES_H_
#define SRC_DEFINE_TABLES_H_
#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) [ENUM] = CPUINFO_FLAG,
static const char* kCpuInfoFlags[] = {DEFINE_TABLE_FEATURES};
#undef FEATURE
#ifndef DEFINE_TABLE_DONT_GENERATE_HWCAPS
#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) \
[ENUM] = (HardwareCapabilities){HWCAP, HWCAP2},
static const HardwareCapabilities kHardwareCapabilities[] = {
DEFINE_TABLE_FEATURES};
#undef FEATURE
#endif // DEFINE_TABLE_DONT_GENERATE_HWCAPS
#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) \
static void set_##ENUM(DEFINE_TABLE_FEATURE_TYPE* features, bool value) \
{ \
features->NAME = value; \
} \
static int get_##ENUM(const DEFINE_TABLE_FEATURE_TYPE* features) \
{ \
return features->NAME; \
}
DEFINE_TABLE_FEATURES
#undef FEATURE
#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) [ENUM] = set_##ENUM,
static void (*const kSetters[])(DEFINE_TABLE_FEATURE_TYPE*,
bool) = {DEFINE_TABLE_FEATURES};
#undef FEATURE
#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) [ENUM] = get_##ENUM,
static int (*const kGetters[])(const DEFINE_TABLE_FEATURE_TYPE*) = {
DEFINE_TABLE_FEATURES};
#undef FEATURE
#endif // SRC_DEFINE_TABLES_H_

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
#include "internal/filesystem.h"

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
#include "internal/hwcaps.h"
@ -8,6 +8,26 @@
#include <stdlib.h>
#include <string.h>
static bool IsSet(const uint32_t mask, const uint32_t value)
{
if (mask == 0) return false;
return (value & mask) == mask;
}
bool CpuFeatures_IsHwCapsSet(const HardwareCapabilities hwcaps_mask,
const HardwareCapabilities hwcaps)
{
return IsSet(hwcaps_mask.hwcaps, hwcaps.hwcaps) ||
IsSet(hwcaps_mask.hwcaps2, hwcaps.hwcaps2);
}
#ifdef CPU_FEATURES_TEST
// In test mode, hwcaps_for_testing will define the following functions.
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void);
PlatformType CpuFeatures_GetPlatformType(void);
#else
// Debug facilities
#if defined(NDEBUG)
#define D(...)
#else
@ -25,9 +45,12 @@
// Implementation of GetElfHwcapFromGetauxval
////////////////////////////////////////////////////////////////////////////////
#if defined(CPU_FEATURES_MOCK_GET_ELF_HWCAP_FROM_GETAUXVAL)
// Implementation will be provided by test/hwcaps_for_testing.cc.
#elif defined(HAVE_STRONG_GETAUXVAL)
#define AT_HWCAP 16
#define AT_HWCAP2 26
#define AT_PLATFORM 15
#define AT_BASE_PLATFORM 24
#if defined(HAVE_STRONG_GETAUXVAL)
#include <sys/auxv.h>
static unsigned long GetElfHwcapFromGetauxval(uint32_t hwcap_type)
{
@ -50,10 +73,6 @@ static unsigned long GetElfHwcapFromGetauxval(uint32_t hwcap_type)
// initialization layer.
#include <dlfcn.h>
#define AT_HWCAP 16
#define AT_HWCAP2 26
#define AT_PLATFORM 15
#define AT_BASE_PLATFORM 24
typedef unsigned long getauxval_func_t(unsigned long);
@ -167,3 +186,5 @@ PlatformType CpuFeatures_GetPlatformType(void)
sizeof(type.base_platform));
return type;
}
#endif // CPU_FEATURES_TEST

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
#include "internal/stack_line_reader.h"

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
#include "internal/string_view.h"

View File

@ -1,49 +0,0 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-License-Identifier: Apache-2.0
#include "internal/unix_features_aggregator.h"
#include "internal/string_view.h"
void CpuFeatures_SetFromFlags(const size_t configs_size,
const CapabilityConfig* configs,
const StringView flags_line,
void* const features)
{
size_t i = 0;
for (; i < configs_size; ++i)
{
const CapabilityConfig config = configs[i];
config.set_bit(features, CpuFeatures_StringView_HasWord(
flags_line, config.proc_cpuinfo_flag));
}
}
static bool IsSet(const uint32_t mask, const uint32_t value)
{
if (mask == 0) return false;
return (value & mask) == mask;
}
static bool IsHwCapsSet(const HardwareCapabilities hwcaps_mask,
const HardwareCapabilities hwcaps)
{
return IsSet(hwcaps_mask.hwcaps, hwcaps.hwcaps) ||
IsSet(hwcaps_mask.hwcaps2, hwcaps.hwcaps2);
}
void CpuFeatures_OverrideFromHwCaps(const size_t configs_size,
const CapabilityConfig* configs,
const HardwareCapabilities hwcaps,
void* const features)
{
size_t i = 0;
for (; i < configs_size; ++i)
{
const CapabilityConfig* config = &configs[i];
if (IsHwCapsSet(config->hwcaps_mask, hwcaps))
{
config->set_bit(features, true);
}
}
}

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
// This program dumps current host data to the standard output.
@ -32,7 +32,7 @@
// the data accordingly.
// We use a bump allocator to allocate strings and nodes of the tree,
// Memory is not intented to be reclaimed.
// Memory is not intended to be reclaimed.
typedef struct
{
char* ptr;

View File

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2017 Google Inc.
# SPDX-FileCopyrightText: 2017 Google LLC
# SPDX-License-Identifier: Apache-2.0
#
@ -15,7 +15,6 @@ add_library(filesystem_for_testing filesystem_for_testing.cc)
target_compile_definitions(filesystem_for_testing PUBLIC CPU_FEATURES_MOCK_FILESYSTEM)
##------------------------------------------------------------------------------
add_library(hwcaps_for_testing hwcaps_for_testing.cc)
target_compile_definitions(hwcaps_for_testing PUBLIC CPU_FEATURES_MOCK_GET_ELF_HWCAP_FROM_GETAUXVAL)
target_link_libraries(hwcaps_for_testing filesystem_for_testing)
##------------------------------------------------------------------------------
add_library(stack_line_reader ../src/stack_line_reader.c)
@ -26,7 +25,7 @@ add_library(stack_line_reader_for_test ../src/stack_line_reader.c)
target_compile_definitions(stack_line_reader_for_test PUBLIC STACK_LINE_READER_BUFFER_SIZE=16)
target_link_libraries(stack_line_reader_for_test string_view filesystem_for_testing)
##------------------------------------------------------------------------------
add_library(all_libraries ../src/stack_line_reader.c ../src/unix_features_aggregator.c)
add_library(all_libraries ../src/hwcaps.c ../src/stack_line_reader.c)
target_link_libraries(all_libraries hwcaps_for_testing stack_line_reader string_view)
#
@ -49,15 +48,13 @@ add_executable(stack_line_reader_test stack_line_reader_test.cc)
target_link_libraries(stack_line_reader_test stack_line_reader_for_test)
add_test(NAME stack_line_reader_test COMMAND stack_line_reader_test)
##------------------------------------------------------------------------------
## unix_features_aggregator_test
add_executable(unix_features_aggregator_test unix_features_aggregator_test.cc)
target_link_libraries(unix_features_aggregator_test all_libraries)
add_test(NAME unix_features_aggregator_test COMMAND unix_features_aggregator_test)
##------------------------------------------------------------------------------
## cpuinfo_x86_test
if(PROCESSOR_IS_X86)
add_executable(cpuinfo_x86_test cpuinfo_x86_test.cc ../src/cpuinfo_x86.c)
target_compile_definitions(cpuinfo_x86_test PUBLIC CPU_FEATURES_MOCK_CPUID_X86)
if(APPLE)
target_compile_definitions(cpuinfo_x86_test PRIVATE HAVE_SYSCTLBYNAME)
endif()
target_link_libraries(cpuinfo_x86_test all_libraries)
add_test(NAME cpuinfo_x86_test COMMAND cpuinfo_x86_test)
endif()

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
#include "gtest/gtest.h"

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
#include "cpuinfo_aarch64.h"
@ -51,6 +51,35 @@ TEST(CpuinfoAarch64Test, FromHardwareCap)
EXPECT_FALSE(info.features.pacg);
}
TEST(CpuinfoAarch64Test, FromHardwareCap2)
{
SetHardwareCapabilities(AARCH64_HWCAP_FP,
AARCH64_HWCAP2_SVE2 | AARCH64_HWCAP2_BTI);
GetEmptyFilesystem(); // disabling /proc/cpuinfo
const auto info = GetAarch64Info();
EXPECT_TRUE(info.features.fp);
EXPECT_TRUE(info.features.sve2);
EXPECT_TRUE(info.features.bti);
EXPECT_FALSE(info.features.dcpodp);
EXPECT_FALSE(info.features.sveaes);
EXPECT_FALSE(info.features.svepmull);
EXPECT_FALSE(info.features.svebitperm);
EXPECT_FALSE(info.features.svesha3);
EXPECT_FALSE(info.features.svesm4);
EXPECT_FALSE(info.features.flagm2);
EXPECT_FALSE(info.features.frint);
EXPECT_FALSE(info.features.svei8mm);
EXPECT_FALSE(info.features.svef32mm);
EXPECT_FALSE(info.features.svef64mm);
EXPECT_FALSE(info.features.svebf16);
EXPECT_FALSE(info.features.i8mm);
EXPECT_FALSE(info.features.bf16);
EXPECT_FALSE(info.features.dgh);
EXPECT_FALSE(info.features.rng);
}
TEST(CpuinfoAarch64Test, ARMCortexA53)
{
DisableHardwareCapabilities();
@ -110,6 +139,24 @@ CPU revision : 3)");
EXPECT_FALSE(info.features.sb);
EXPECT_FALSE(info.features.paca);
EXPECT_FALSE(info.features.pacg);
EXPECT_FALSE(info.features.dcpodp);
EXPECT_FALSE(info.features.sve2);
EXPECT_FALSE(info.features.sveaes);
EXPECT_FALSE(info.features.svepmull);
EXPECT_FALSE(info.features.svebitperm);
EXPECT_FALSE(info.features.svesha3);
EXPECT_FALSE(info.features.svesm4);
EXPECT_FALSE(info.features.flagm2);
EXPECT_FALSE(info.features.frint);
EXPECT_FALSE(info.features.svei8mm);
EXPECT_FALSE(info.features.svef32mm);
EXPECT_FALSE(info.features.svef64mm);
EXPECT_FALSE(info.features.svebf16);
EXPECT_FALSE(info.features.i8mm);
EXPECT_FALSE(info.features.bf16);
EXPECT_FALSE(info.features.dgh);
EXPECT_FALSE(info.features.rng);
EXPECT_FALSE(info.features.bti);
}
} // namespace

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
#include "cpuinfo_arm.h"
@ -104,7 +104,6 @@ CPU architecture: 7
CPU variant : 0x0
CPU part : 0xb76
CPU revision : 7
Hardware : BCM2835
Revision : 9000c1
Serial : 000000006cd946f3)");
@ -157,7 +156,6 @@ CPU architecture: 7
CPU variant : 0x4
CPU part : 0xc09
CPU revision : 1
processor : 1
model name : ARMv7 Processor rev 1 (v7l)
BogoMIPS : 50.00
@ -167,7 +165,6 @@ CPU architecture: 7
CPU variant : 0x4
CPU part : 0xc09
CPU revision : 1
Hardware : Marvell Armada 380/385 (Device Tree)
Revision : 0000
Serial : 0000000000000000)");
@ -222,7 +219,6 @@ CPU architecture: 7
CPU variant : 0x0
CPU part : 0xb76
CPU revision : 6
Hardware : SPICA
Revision : 0020
Serial : 33323613546d00ec )");
@ -267,17 +263,14 @@ TEST(CpuinfoArmTest, InvalidNeon)
R"(Processor: ARMv7 Processory rev 0 (v71)
processor: 0
BogoMIPS: 13.50
Processor: 1
BogoMIPS: 13.50
Features: swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt
CPU implementer : 0x51
CPU architecture: 7
CPU variant: 0x1
CPU part: 0x04d
CPU revision: 0
Hardware: SAMSUNG M2
Revision: 0010
Serial: 00001e030000354e)");
@ -340,7 +333,6 @@ CPU architecture: 7
CPU variant : 0x0
CPU part : 0xc08
CPU revision : 0
Hardware : Goldfish
Revision : 0000
Serial : 0000000000000000)");

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
#include "cpuinfo_mips.h"

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
#include "cpuinfo_ppc.h"
@ -38,12 +38,10 @@ TEST(CpustringsPPCTest, Blade)
cpu : POWER7 (architected), altivec supported
clock : 3000.000000MHz
revision : 2.1 (pvr 003f 0201)
processor : 15
cpu : POWER7 (architected), altivec supported
clock : 3000.000000MHz
revision : 2.1 (pvr 003f 0201)
timebase : 512000000
platform : pSeries
model : IBM,8406-70Y
@ -67,12 +65,10 @@ TEST(CpustringsPPCTest, Firestone)
cpu : POWER8 (raw), altivec supported
clock : 2061.000000MHz
revision : 2.0 (pvr 004d 0200)
processor : 127
cpu : POWER8 (raw), altivec supported
clock : 2061.000000MHz
revision : 2.0 (pvr 004d 0200)
timebase : 512000000
platform : PowerNV
model : 8335-GTA
@ -94,7 +90,6 @@ TEST(CpustringsPPCTest, w8)
cpu : POWER9, altivec supported
clock : 2300.000000MHz
revision : 2.2 (pvr 004e 1202)
timebase : 512000000
platform : PowerNV
model : 0000000000000000

View File

@ -1,19 +1,25 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
#include "cpuinfo_x86.h"
#include "gtest/gtest.h"
#include "internal/cpuid_x86.h"
#include <cassert>
#include <cstdio>
#include <map>
#include <set>
#if defined(CPU_FEATURES_OS_WINDOWS)
#include <windows.h> // IsProcessorFeaturePresent
#endif // CPU_FEATURES_OS_WINDOWS
#include "filesystem_for_testing.h"
#include "gtest/gtest.h"
#include "internal/cpuid_x86.h"
namespace cpu_features
{
class FakeCpu
{
public:
Leaf CpuIdEx(uint32_t leaf_id, int ecx) const
Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx) const
{
const auto itr = cpuid_leaves_.find(std::make_pair(leaf_id, ecx));
if (itr != cpuid_leaves_.end())
@ -35,23 +41,74 @@ public:
xcr0_eax_ = os_backups_extended_registers ? -1 : 0;
}
#if defined(CPU_FEATURES_OS_DARWIN)
bool GetDarwinSysCtlByName(std::string name) const
{
return darwin_sysctlbyname_.count(name);
}
void SetDarwinSysCtlByName(std::string name)
{
darwin_sysctlbyname_.insert(name);
}
#endif // CPU_FEATURES_OS_DARWIN
#if defined(CPU_FEATURES_OS_WINDOWS)
bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature)
{
return windows_isprocessorfeaturepresent_.count(ProcessorFeature);
}
void SetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature)
{
windows_isprocessorfeaturepresent_.insert(ProcessorFeature);
}
#endif // CPU_FEATURES_OS_WINDOWS
private:
std::map<std::pair<uint32_t, int>, Leaf> cpuid_leaves_;
#if defined(CPU_FEATURES_OS_DARWIN)
std::set<std::string> darwin_sysctlbyname_;
#endif // CPU_FEATURES_OS_DARWIN
#if defined(CPU_FEATURES_OS_WINDOWS)
std::set<DWORD> windows_isprocessorfeaturepresent_;
#endif // CPU_FEATURES_OS_WINDOWS
uint32_t xcr0_eax_;
};
auto* g_fake_cpu = new FakeCpu();
FakeCpu* g_fake_cpu = nullptr;
extern "C" Leaf CpuIdEx(uint32_t leaf_id, int ecx)
extern "C" Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx)
{
return g_fake_cpu->CpuIdEx(leaf_id, ecx);
return g_fake_cpu->GetCpuidLeaf(leaf_id, ecx);
}
extern "C" uint32_t GetXCR0Eax(void) { return g_fake_cpu->GetXCR0Eax(); }
#if defined(CPU_FEATURES_OS_DARWIN)
extern "C" bool GetDarwinSysCtlByName(const char* name)
{
return g_fake_cpu->GetDarwinSysCtlByName(name);
}
#endif // CPU_FEATURES_OS_DARWIN
#if defined(CPU_FEATURES_OS_WINDOWS)
extern "C" bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature)
{
return g_fake_cpu->GetWindowsIsProcessorFeaturePresent(ProcessorFeature);
}
#endif // CPU_FEATURES_OS_WINDOWS
namespace
{
TEST(CpuidX86Test, SandyBridge)
class CpuidX86Test : public ::testing::Test
{
protected:
void SetUp() override { g_fake_cpu = new FakeCpu(); }
void TearDown() override { delete g_fake_cpu; }
};
TEST_F(CpuidX86Test, SandyBridge)
{
g_fake_cpu->SetOsBackupsExtendedRegisters(true);
g_fake_cpu->SetLeaves({
@ -82,7 +139,7 @@ TEST(CpuidX86Test, SandyBridge)
EXPECT_FALSE(features.avx512bitalg);
EXPECT_FALSE(features.avx512vpopcntdq);
EXPECT_FALSE(features.avx512_4vnniw);
EXPECT_FALSE(features.avx512_4vbmi2);
EXPECT_FALSE(features.avx512_4fmaps);
// All old cpu features should be set.
EXPECT_TRUE(features.aes);
EXPECT_TRUE(features.ssse3);
@ -98,7 +155,7 @@ TEST(CpuidX86Test, SandyBridge)
const int KiB = 1024;
const int MiB = 1024 * KiB;
TEST(CpuidX86Test, SandyBridgeTestOsSupport)
TEST_F(CpuidX86Test, SandyBridgeTestOsSupport)
{
g_fake_cpu->SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}},
@ -113,7 +170,7 @@ TEST(CpuidX86Test, SandyBridgeTestOsSupport)
EXPECT_TRUE(GetX86Info().features.avx);
}
TEST(CpuidX86Test, SkyLake)
TEST_F(CpuidX86Test, SkyLake)
{
g_fake_cpu->SetOsBackupsExtendedRegisters(true);
g_fake_cpu->SetLeaves({
@ -129,7 +186,7 @@ TEST(CpuidX86Test, SkyLake)
EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_SKL);
}
TEST(CpuidX86Test, Branding)
TEST_F(CpuidX86Test, Branding)
{
g_fake_cpu->SetLeaves({
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
@ -146,7 +203,7 @@ TEST(CpuidX86Test, Branding)
EXPECT_STREQ(brand_string, "Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz");
}
TEST(CpuidX86Test, KabyLakeCache)
TEST_F(CpuidX86Test, KabyLakeCache)
{
g_fake_cpu->SetLeaves({
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
@ -196,7 +253,7 @@ TEST(CpuidX86Test, KabyLakeCache)
EXPECT_EQ(info.levels[3].partitioning, 1);
}
TEST(CpuidX86Test, HSWCache)
TEST_F(CpuidX86Test, HSWCache)
{
g_fake_cpu->SetLeaves({
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
@ -245,8 +302,9 @@ TEST(CpuidX86Test, HSWCache)
EXPECT_EQ(info.levels[3].tlb_entries, 8192);
EXPECT_EQ(info.levels[3].partitioning, 1);
}
// http://users.atw.hu/instlatx64/AuthenticAMD0630F81_K15_Godavari_CPUID.txt
TEST(CpuidX86Test, AMD_K15)
TEST_F(CpuidX86Test, AMD_K15)
{
g_fake_cpu->SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
@ -273,6 +331,211 @@ TEST(CpuidX86Test, AMD_K15)
EXPECT_STREQ(brand_string, "AMD A8-7670K Radeon R7, 10 Compute Cores 4C+6G ");
}
// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel00106A1_Nehalem_CPUID.txt
TEST_F(CpuidX86Test, Nehalem)
{
// Pre AVX cpus don't have xsave
g_fake_cpu->SetOsBackupsExtendedRegisters(false);
#if defined(CPU_FEATURES_OS_WINDOWS)
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
PF_XMMI_INSTRUCTIONS_AVAILABLE);
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
PF_XMMI64_INSTRUCTIONS_AVAILABLE);
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
PF_SSE3_INSTRUCTIONS_AVAILABLE);
#endif // CPU_FEATURES_OS_WINDOWS
#if defined(CPU_FEATURES_OS_DARWIN)
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse2");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse3");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.supplementalsse3");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_1");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_2");
#endif // CPU_FEATURES_OS_DARWIN
#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo", R"(processor :
flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
)");
#endif // CPU_FEATURES_OS_LINUX_OR_ANDROID
g_fake_cpu->SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000106A2, 0x00100800, 0x00BCE3BD, 0xBFEBFBFF}},
{{0x00000002, 0}, Leaf{0x55035A01, 0x00F0B0E3, 0x00000000, 0x09CA212C}},
{{0x00000003, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
{{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}},
{{0x00000004, 0}, Leaf{0x1C004122, 0x00C0003F, 0x0000007F, 0x00000000}},
{{0x00000004, 0}, Leaf{0x1C004143, 0x01C0003F, 0x000001FF, 0x00000000}},
{{0x00000004, 0}, Leaf{0x1C03C163, 0x03C0003F, 0x00000FFF, 0x00000002}},
{{0x00000005, 0}, Leaf{0x00000040, 0x00000040, 0x00000003, 0x00021120}},
{{0x00000006, 0}, Leaf{0x00000001, 0x00000002, 0x00000001, 0x00000000}},
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
{{0x00000008, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
{{0x00000009, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
{{0x0000000A, 0}, Leaf{0x07300403, 0x00000000, 0x00000000, 0x00000603}},
{{0x0000000B, 0}, Leaf{0x00000001, 0x00000001, 0x00000100, 0x00000000}},
{{0x0000000B, 0}, Leaf{0x00000004, 0x00000002, 0x00000201, 0x00000000}},
{{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
{{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000001, 0x28100000}},
{{0x80000002, 0}, Leaf{0x756E6547, 0x20656E69, 0x65746E49, 0x2952286C}},
{{0x80000003, 0}, Leaf{0x55504320, 0x20202020, 0x20202020, 0x40202020}},
{{0x80000004, 0}, Leaf{0x30303020, 0x20402030, 0x37382E31, 0x007A4847}},
{{0x80000005, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
{{0x80000006, 0}, Leaf{0x00000000, 0x00000000, 0x01006040, 0x00000000}},
{{0x80000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000100}},
{{0x80000008, 0}, Leaf{0x00003028, 0x00000000, 0x00000000, 0x00000000}},
});
const auto info = GetX86Info();
EXPECT_STREQ(info.vendor, "GenuineIntel");
EXPECT_EQ(info.family, 0x06);
EXPECT_EQ(info.model, 0x1A);
EXPECT_EQ(info.stepping, 0x02);
EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_NHM);
char brand_string[49];
FillX86BrandString(brand_string);
EXPECT_STREQ(brand_string, "Genuine Intel(R) CPU @ 0000 @ 1.87GHz");
EXPECT_TRUE(info.features.sse);
EXPECT_TRUE(info.features.sse2);
EXPECT_TRUE(info.features.sse3);
#ifndef CPU_FEATURES_OS_WINDOWS
// Currently disabled on Windows as IsProcessorFeaturePresent do not support
// feature detection > sse3.
EXPECT_TRUE(info.features.ssse3);
EXPECT_TRUE(info.features.sse4_1);
EXPECT_TRUE(info.features.sse4_2);
#endif // CPU_FEATURES_OS_WINDOWS
}
// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0030673_Silvermont3_CPUID.txt
TEST_F(CpuidX86Test, Atom)
{
// Pre AVX cpus don't have xsave
g_fake_cpu->SetOsBackupsExtendedRegisters(false);
#if defined(CPU_FEATURES_OS_WINDOWS)
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
PF_XMMI_INSTRUCTIONS_AVAILABLE);
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
PF_XMMI64_INSTRUCTIONS_AVAILABLE);
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
PF_SSE3_INSTRUCTIONS_AVAILABLE);
#endif // CPU_FEATURES_OS_WINDOWS
#if defined(CPU_FEATURES_OS_DARWIN)
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse2");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse3");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.supplementalsse3");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_1");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_2");
#endif // CPU_FEATURES_OS_DARWIN
#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo", R"(
flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
)");
#endif // CPU_FEATURES_OS_LINUX_OR_ANDROID
g_fake_cpu->SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x00030673, 0x00100800, 0x41D8E3BF, 0xBFEBFBFF}},
{{0x00000002, 0}, Leaf{0x61B3A001, 0x0000FFC2, 0x00000000, 0x00000000}},
{{0x00000003, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
{{0x00000004, 0}, Leaf{0x1C000121, 0x0140003F, 0x0000003F, 0x00000001}},
{{0x00000004, 1}, Leaf{0x1C000122, 0x01C0003F, 0x0000003F, 0x00000001}},
{{0x00000004, 2}, Leaf{0x1C00C143, 0x03C0003F, 0x000003FF, 0x00000001}},
{{0x00000005, 0}, Leaf{0x00000040, 0x00000040, 0x00000003, 0x33000020}},
{{0x00000006, 0}, Leaf{0x00000005, 0x00000002, 0x00000009, 0x00000000}},
{{0x00000007, 0}, Leaf{0x00000000, 0x00002282, 0x00000000, 0x00000000}},
{{0x00000008, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
{{0x00000009, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
{{0x0000000A, 0}, Leaf{0x07280203, 0x00000000, 0x00000000, 0x00004503}},
{{0x0000000B, 0}, Leaf{0x00000001, 0x00000001, 0x00000100, 0x00000000}},
{{0x0000000B, 1}, Leaf{0x00000004, 0x00000004, 0x00000201, 0x00000000}},
{{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
{{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000101, 0x28100000}},
{{0x80000002, 0}, Leaf{0x20202020, 0x6E492020, 0x286C6574, 0x43202952}},
{{0x80000003, 0}, Leaf{0x72656C65, 0x52286E6F, 0x50432029, 0x4A202055}},
{{0x80000004, 0}, Leaf{0x30303931, 0x20402020, 0x39392E31, 0x007A4847}},
{{0x80000005, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
{{0x80000006, 0}, Leaf{0x00000000, 0x00000000, 0x04008040, 0x00000000}},
{{0x80000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000100}},
{{0x80000008, 0}, Leaf{0x00003024, 0x00000000, 0x00000000, 0x00000000}},
});
const auto info = GetX86Info();
EXPECT_STREQ(info.vendor, "GenuineIntel");
EXPECT_EQ(info.family, 0x06);
EXPECT_EQ(info.model, 0x37);
EXPECT_EQ(info.stepping, 0x03);
EXPECT_EQ(GetX86Microarchitecture(&info),
X86Microarchitecture::INTEL_ATOM_SMT);
char brand_string[49];
FillX86BrandString(brand_string);
EXPECT_STREQ(brand_string, " Intel(R) Celeron(R) CPU J1900 @ 1.99GHz");
EXPECT_TRUE(info.features.sse);
EXPECT_TRUE(info.features.sse2);
EXPECT_TRUE(info.features.sse3);
#ifndef CPU_FEATURES_OS_WINDOWS
// Currently disabled on Windows as IsProcessorFeaturePresent do not support
// feature detection > sse3.
EXPECT_TRUE(info.features.ssse3);
EXPECT_TRUE(info.features.sse4_1);
EXPECT_TRUE(info.features.sse4_2);
#endif // CPU_FEATURES_OS_WINDOWS
}
// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0000673_P3_KatmaiDP_CPUID.txt
TEST_F(CpuidX86Test, P3)
{
// Pre AVX cpus don't have xsave
g_fake_cpu->SetOsBackupsExtendedRegisters(false);
#if defined(CPU_FEATURES_OS_WINDOWS)
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
PF_XMMI_INSTRUCTIONS_AVAILABLE);
#endif // CPU_FEATURES_OS_WINDOWS
#if defined(CPU_FEATURES_OS_DARWIN)
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse");
#endif // CPU_FEATURES_OS_DARWIN
#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo", R"(
flags : fpu mmx sse
)");
#endif // CPU_FEATURES_OS_LINUX_OR_ANDROID
g_fake_cpu->SetLeaves({
{{0x00000000, 0}, Leaf{0x00000003, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x00000673, 0x00000000, 0x00000000, 0x0387FBFF}},
{{0x00000002, 0}, Leaf{0x03020101, 0x00000000, 0x00000000, 0x0C040843}},
{{0x00000003, 0}, Leaf{0x00000000, 0x00000000, 0x4CECC782, 0x00006778}},
});
const auto info = GetX86Info();
EXPECT_STREQ(info.vendor, "GenuineIntel");
EXPECT_EQ(info.family, 0x06);
EXPECT_EQ(info.model, 0x07);
EXPECT_EQ(info.stepping, 0x03);
EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::X86_UNKNOWN);
char brand_string[49];
FillX86BrandString(brand_string);
EXPECT_STREQ(brand_string, "");
EXPECT_TRUE(info.features.mmx);
EXPECT_TRUE(info.features.sse);
EXPECT_FALSE(info.features.sse2);
EXPECT_FALSE(info.features.sse3);
#ifndef CPU_FEATURES_OS_WINDOWS
// Currently disabled on Windows as IsProcessorFeaturePresent do not support
// feature detection > sse3.
EXPECT_FALSE(info.features.ssse3);
EXPECT_FALSE(info.features.sse4_1);
EXPECT_FALSE(info.features.sse4_2);
#endif // CPU_FEATURES_OS_WINDOWS
}
// TODO(user): test what happens when xsave/osxsave are not present.
// TODO(user): test what happens when xmm/ymm/zmm os support are not
// present.

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
#include "filesystem_for_testing.h"

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
// Implements a fake filesystem, useful for tests.

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
#include "hwcaps_for_testing.h"

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
#ifndef CPU_FEATURES_TEST_HWCAPS_FOR_TESTING_H_

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
#include "filesystem_for_testing.h"

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-FileCopyrightText: 2017 Google LLC
// SPDX-License-Identifier: Apache-2.0
#include "gtest/gtest.h"
@ -30,6 +30,8 @@ TEST(StringViewTest, CpuFeatures_StringView_IndexOfChar)
{
// Found.
EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 'e'), 1);
EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 't'), 0);
EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("beef"), 'e'), 1);
// Not found.
EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 'z'), -1);
// Empty.
@ -40,6 +42,8 @@ TEST(StringViewTest, CpuFeatures_StringView_IndexOf)
{
// Found.
EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("es")), 1);
EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("test")), 0);
EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("tesstest"), str("test")), 4);
// Not found.
EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("aa")), -1);
// Empty.
@ -50,6 +54,9 @@ TEST(StringViewTest, CpuFeatures_StringView_IndexOf)
TEST(StringViewTest, CpuFeatures_StringView_StartsWith)
{
EXPECT_TRUE(CpuFeatures_StringView_StartsWith(str("test"), str("te")));
EXPECT_TRUE(CpuFeatures_StringView_StartsWith(str("test"), str("test")));
EXPECT_FALSE(CpuFeatures_StringView_StartsWith(str("test"), str("st")));
EXPECT_FALSE(CpuFeatures_StringView_StartsWith(str("test"), str("est")));
EXPECT_FALSE(CpuFeatures_StringView_StartsWith(str("test"), str("")));
EXPECT_FALSE(
CpuFeatures_StringView_StartsWith(str("test"), kEmptyStringView));
@ -63,8 +70,11 @@ TEST(StringViewTest, CpuFeatures_StringView_IsEquals)
CpuFeatures_StringView_IsEquals(kEmptyStringView, kEmptyStringView));
EXPECT_TRUE(CpuFeatures_StringView_IsEquals(kEmptyStringView, str("")));
EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str(""), kEmptyStringView));
EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str("test"), str("test")));
EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str("a"), str("a")));
EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), str("b")));
EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("aa"), str("a")));
EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), str("aa")));
EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), kEmptyStringView));
EXPECT_FALSE(CpuFeatures_StringView_IsEquals(kEmptyStringView, str("a")));
}
@ -77,12 +87,55 @@ TEST(StringViewTest, CpuFeatures_StringView_PopFront)
EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 100), str(""));
}
TEST(StringViewTest, CpuFeatures_StringView_PopBack)
{
EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 2), str("te"));
EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 0), str("test"));
EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 4), str(""));
EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 100), str(""));
}
TEST(StringViewTest, CpuFeatures_StringView_KeepFront)
{
EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 2), str("te"));
EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 0), str(""));
EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 4), str("test"));
EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 6), str("test"));
}
TEST(StringViewTest, CpuFeatures_StringView_Front)
{
EXPECT_EQ(CpuFeatures_StringView_Front(str("apple")), 'a');
EXPECT_EQ(CpuFeatures_StringView_Front(str("a")), 'a');
}
TEST(StringViewTest, CpuFeatures_StringView_Back)
{
EXPECT_EQ(CpuFeatures_StringView_Back(str("apple")), 'e');
EXPECT_EQ(CpuFeatures_StringView_Back(str("a")), 'a');
}
TEST(StringViewTest, CpuFeatures_StringView_TrimWhitespace)
{
EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str(" first middle last ")),
str("first middle last"));
EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str("first middle last ")),
str("first middle last"));
EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str(" first middle last")),
str("first middle last"));
EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str("first middle last")),
str("first middle last"));
}
TEST(StringViewTest, CpuFeatures_StringView_ParsePositiveNumber)
{
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("42")), 42);
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2a")), 42);
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2A")), 42);
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2A2a")), 10794);
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2a2A")), 10794);
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("-10")), -1);
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("-0x2A")), -1);
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("abc")), -1);
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("")), -1);

View File

@ -1,103 +0,0 @@
// SPDX-FileCopyrightText: 2017 Google Inc.
// SPDX-License-Identifier: Apache-2.0
#include "gtest/gtest.h"
#include "internal/unix_features_aggregator.h"
#include <array>
namespace cpu_features
{
namespace
{
struct Features
{
bool a = false;
bool b = false;
bool c = false;
};
enum eFeatures
{
TEST_a,
TEST_b,
TEST_c
};
DECLARE_SETTER_AND_GETTER(Features, a)
DECLARE_SETTER_AND_GETTER(Features, b)
DECLARE_SETTER_AND_GETTER(Features, c)
class LinuxFeatureAggregatorTest : public testing::Test
{
public:
const std::array<CapabilityConfig, 3> kConfigs = {{{{0b0001, 0b0000}, "a", &set_a, &get_a},
{{0b0010, 0b0000}, "b", &set_b, &get_b},
{{0b0000, 0b1100}, "c", &set_c, &get_c}}};
};
TEST_F(LinuxFeatureAggregatorTest, FromFlagsEmpty)
{
Features features;
CpuFeatures_SetFromFlags(kConfigs.size(), kConfigs.data(), str(""),
&features);
EXPECT_FALSE(features.a);
EXPECT_FALSE(features.b);
EXPECT_FALSE(features.c);
EXPECT_FALSE(kConfigs[TEST_a].get_bit(&features));
}
TEST_F(LinuxFeatureAggregatorTest, FromFlagsAllSet)
{
Features features;
CpuFeatures_SetFromFlags(kConfigs.size(), kConfigs.data(), str("a c b"),
&features);
EXPECT_TRUE(features.a);
EXPECT_TRUE(features.b);
EXPECT_TRUE(features.c);
EXPECT_TRUE(kConfigs[TEST_a].get_bit(&features));
}
TEST_F(LinuxFeatureAggregatorTest, FromFlagsOnlyA)
{
Features features;
CpuFeatures_SetFromFlags(kConfigs.size(), kConfigs.data(), str("a"),
&features);
EXPECT_TRUE(features.a);
EXPECT_FALSE(features.b);
EXPECT_FALSE(features.c);
EXPECT_TRUE(kConfigs[TEST_a].get_bit(&features));
EXPECT_FALSE(kConfigs[TEST_b].get_bit(&features));
EXPECT_FALSE(kConfigs[TEST_c].get_bit(&features));
}
TEST_F(LinuxFeatureAggregatorTest, FromHwcapsNone)
{
HardwareCapabilities capability;
capability.hwcaps = 0; // matches none
capability.hwcaps2 = 0; // matches none
Features features;
CpuFeatures_OverrideFromHwCaps(kConfigs.size(), kConfigs.data(), capability,
&features);
EXPECT_FALSE(features.a);
EXPECT_FALSE(features.b);
EXPECT_FALSE(features.c);
}
TEST_F(LinuxFeatureAggregatorTest, FromHwcapsSet)
{
HardwareCapabilities capability;
capability.hwcaps = 0b0010; // matches b but not a
capability.hwcaps2 = 0b1111; // matches c
Features features;
CpuFeatures_OverrideFromHwCaps(kConfigs.size(), kConfigs.data(), capability,
&features);
EXPECT_FALSE(features.a);
EXPECT_TRUE(features.b);
EXPECT_TRUE(features.c);
}
} // namespace
} // namespace cpu_features

View File

@ -42,6 +42,13 @@ if(MSVC) # its not set otherwise
set(COMPILER_NAME MSVC)
endif()
# Assume "AppleClang == Clang".
string(TOLOWER ${COMPILER_NAME} COMPILER_NAME_LOWER)
string(REGEX MATCH "clang" COMPILER_NAME_LOWER ${COMPILER_NAME_LOWER})
if(${COMPILER_NAME_LOWER} MATCHES "clang")
set(COMPILER_NAME "Clang")
endif()
message(STATUS "Compiler name: ${COMPILER_NAME}")
if(NOT DEFINED COMPILER_NAME)
@ -143,33 +150,8 @@ endmacro()
# the xgetbv instruction, or {if not cross-compiling and the xgetbv
# executable does not function correctly}.
########################################################################
set(HAVE_XGETBV 0)
set(HAVE_AVX_CVTPI32_PS 0)
if(CPU_IS_x86)
# check to see if the compiler/linker works with xgetb instruction
if(NOT MSVC)
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/test_xgetbv.c "#include <volk_gnsssdr/volk_gnsssdr_common.h>\n unsigned long long _xgetbv(unsigned int index) { unsigned int eax, edx; __VOLK_ASM __VOLK_VOLATILE(\"xgetbv\" : \"=a\"(eax), \"=d\"(edx) : \"c\"(index)); return ((unsigned long long)edx << 32) | eax; } int main (void) { (void) _xgetbv(0); return (0); }")
set(_AUX_INCLUDE_FLAG -I${PROJECT_SOURCE_DIR}/include)
else()
# MSVC defines an intrinsic
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/test_xgetbv.c "#include <stdio.h> \n #include <intrin.h> \n int main() { int avxSupported = 0; \n#if (_MSC_FULL_VER >= 160040219) \nint cpuInfo[4]; __cpuid(cpuInfo, 1);\nif ((cpuInfo[2] & (1 << 27) || 0) && (cpuInfo[2] & (1 << 28) || 0)) \n{\nunsigned long long xcrFeatureMask = _xgetbv(_XCR_XFEATURE_ENABLED_MASK);\n avxSupported = (xcrFeatureMask & 0x6) == 6;}\n#endif \n return 1- avxSupported; }")
endif()
execute_process(COMMAND ${CMAKE_C_COMPILER} ${_AUX_INCLUDE_FLAG} -o
${CMAKE_CURRENT_BINARY_DIR}/test_xgetbv
${CMAKE_CURRENT_BINARY_DIR}/test_xgetbv.c
OUTPUT_QUIET ERROR_QUIET
RESULT_VARIABLE avx_compile_result
)
if(NOT ${avx_compile_result} EQUAL 0)
overrule_arch(avx "Compiler or linker missing xgetbv instruction")
else()
# compiler/linker seems to work; assume working
set(HAVE_XGETBV 1)
endif()
file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/test_xgetbv
${CMAKE_CURRENT_BINARY_DIR}/test_xgetbv.c
)
#########################################################################
# eliminate AVX if cvtpi32_ps intrinsic fails like some versions of clang
#########################################################################
@ -215,10 +197,6 @@ if(CPU_IS_x86)
endif()
endif()
if(${HAVE_XGETBV})
add_definitions(-DHAVE_XGETBV)
endif()
if(${HAVE_AVX_CVTPI32_PS})
add_definitions(-DHAVE_AVX_CVTPI32_PS)
endif()
@ -569,6 +547,7 @@ if(NOT (CMAKE_GENERATOR STREQUAL Xcode))
PRIVATE $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>
PRIVATE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
PRIVATE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/kernels>
PRIVATE $<TARGET_PROPERTY:cpu_features,INTERFACE_INCLUDE_DIRECTORIES>
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
)