diff options
author | Roland Levillain <rpl@google.com> | 2020-10-15 17:46:27 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-10-15 17:46:27 +0000 |
commit | 607db9b85105297574b0cb84da1ebda7f2c0c3ee (patch) | |
tree | aad9356ab58e4885f8393de3ce23f744194af8b0 | |
parent | 1e0cc1fb030178ec0a3d61427ed621f858969915 (diff) | |
parent | 1fb67bca22774bfb5cb19d5195052efc37c63c28 (diff) | |
download | cpu_features-607db9b85105297574b0cb84da1ebda7f2c0c3ee.tar.gz |
Merge v0.6.0 into master. am: 1fb67bca22
Original change: https://android-review.googlesource.com/c/platform/external/cpu_features/+/1460885
Change-Id: I0fa9c30b0901a9f38042a46000542c28ef919950
49 files changed, 978 insertions, 1026 deletions
diff --git a/.github/workflows/Dockerfile b/.github/workflows/Dockerfile new file mode 100644 index 0000000..41dfc93 --- /dev/null +++ b/.github/workflows/Dockerfile @@ -0,0 +1,5 @@ +# Create a virtual environment with all tools installed +# ref: https://hub.docker.com/_/alpine +FROM alpine:edge +# Install system build dependencies +RUN apk add --no-cache git clang diff --git a/.github/workflows/clang_format.yml b/.github/workflows/clang_format.yml new file mode 100644 index 0000000..17d1567 --- /dev/null +++ b/.github/workflows/clang_format.yml @@ -0,0 +1,24 @@ +name: clang-format Check + +on: [push, pull_request] + +jobs: + # Building using the github runner environement directly. + clang-format: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Fetch origin/master + run: git fetch origin master + - name: List of changed file(s) + run: git diff --name-only FETCH_HEAD + + - name: Build clang-format docker + run: cd .github/workflows && docker build --tag=linter . + - name: Check clang-format + run: docker run --rm --init -v $(pwd):/repo linter:latest clang-format --version + - name: clang-format help + run: docker run --rm --init -v $(pwd):/repo linter:latest clang-format --help + + - name: Check current commit + run: docker run --rm --init -v $(pwd):/repo -w /repo linter:latest sh -c "git diff --diff-filter=d --name-only FETCH_HEAD | grep '\.c$\|\.h$\|\.cc$' | xargs clang-format --style=file --dry-run --Werror " @@ -34,11 +34,10 @@ cc_library { } cc_library { - name: "libcpu_features-unix_based_hardware_detection", + name: "libcpu_features-hwcaps", defaults: ["cpu_features-defaults"], srcs: [ "src/hwcaps.c", - "src/unix_features_aggregator.c", ], cflags: [ "-DHAVE_DLFCN_H", @@ -74,7 +73,7 @@ cc_library { "src/cpuinfo_arm.c", ], whole_static_libs: [ - "libcpu_features-unix_based_hardware_detection", + "libcpu_features-hwcaps", ], }, arm64: { @@ -82,7 +81,7 @@ cc_library { "src/cpuinfo_aarch64.c", ], whole_static_libs: [ - "libcpu_features-unix_based_hardware_detection", + "libcpu_features-hwcaps", ], cflags: [ "-Wno-gnu-designator", @@ -186,8 +185,10 @@ cc_test_library { defaults: ["cpu_features-test-defaults"], cflags: [ "-DCPU_FEATURES_MOCK_GET_ELF_HWCAP_FROM_GETAUXVAL", + "-DCPU_FEATURES_TEST", ], srcs: [ + "src/hwcaps.c", "test/hwcaps_for_testing.cc", ], static_libs: [ @@ -239,9 +240,6 @@ cc_test_library { "cpu_features-test-defaults", "stack_line_reader-defaults", ], - srcs: [ - "src/unix_features_aggregator.c", - ], whole_static_libs: [ "libcpu_features-filesystem_for_testing", "libcpu_features-hwcaps_for_testing", @@ -290,17 +288,6 @@ cc_test { } cc_test { - name: "cpu_features-unix_features_aggregator_test", - defaults: ["cpu_features-test-defaults"], - srcs: [ - "test/unix_features_aggregator_test.cc", - ], - static_libs: [ - "libcpu_features-all_libraries", - ], -} - -cc_test { name: "cpu_features-cpuinfo_test", defaults: [ "cpu_features-test-defaults", @@ -308,6 +295,9 @@ cc_test { static_libs: [ "libcpu_features-all_libraries", ], + cflags: [ + "-DSTACK_LINE_READER_BUFFER_SIZE=1024", + ], arch: { x86: { cflags: [ @@ -330,9 +320,6 @@ cc_test { ], }, arm: { - cflags: [ - "-DSTACK_LINE_READER_BUFFER_SIZE=1024", - ], srcs: [ "test/cpuinfo_arm_test.cc", "src/cpuinfo_arm.c", @@ -340,7 +327,6 @@ cc_test { }, arm64: { cflags: [ - "-DSTACK_LINE_READER_BUFFER_SIZE=1024", "-Wno-gnu-designator", ], srcs: [ diff --git a/CMakeLists.txt b/CMakeLists.txt index 85102c7..f9daeac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if(POLICY CMP0077) cmake_policy(SET CMP0077 NEW) endif() -project(CpuFeatures VERSION 0.5.0 LANGUAGES C) +project(CpuFeatures VERSION 0.6.0 LANGUAGES C) set(CMAKE_C_STANDARD 99) @@ -22,8 +22,8 @@ endif(NOT CMAKE_BUILD_TYPE) option(BUILD_TESTING "Enable test (depends on googletest)." OFF) # BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to make # it prominent in the GUI. -# cpu_features uses bit-fields which are - to some extends - implementation-defined (see https://en.cppreference.com/w/c/language/bit_field). -# As a consequence it is discouraged to use cpu_features as a shared library because different compilers may interpret the code in different ways. +# cpu_features uses bit-fields which are - to some extends - implementation-defined (see https://en.cppreference.com/w/c/language/bit_field). +# As a consequence it is discouraged to use cpu_features as a shared library because different compilers may interpret the code in different ways. # Prefer static linking from source whenever possible. option(BUILD_SHARED_LIBS "Build library as shared." OFF) # PIC @@ -114,9 +114,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) @@ -148,6 +146,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) # @@ -175,11 +178,11 @@ if(BUILD_TESTING) # Automatically incorporate googletest into the CMake Project if target not # found. enable_language(CXX) - + set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # prefer use of -std11 instead of -gnustd11 - + if(NOT TARGET gtest OR NOT TARGET gmock_main) # Download and unpack googletest at configure time. configure_file( @@ -9,11 +9,11 @@ third_party { type: GIT value: "https://github.com/google/cpu_features.git" } - version: "v0.5.0" + version: "v0.6.0" license_type: NOTICE last_upgrade_date { year: 2020 - month: 9 - day: 22 + month: 10 + day: 15 } } @@ -121,7 +121,6 @@ This feature is currently available only for x86 microarchitectures. ### Running sample code Building `cpu_features` (check [quickstart](#quickstart) below) brings a small executable to test the library. -. ```shell % ./build/list_cpu_features @@ -185,7 +184,7 @@ Please check the [CMake build instructions](cmake/README.md). <a name="quickstart"></a> ### Quickstart with `Ninja` - - build `list_cpu_features` + - build `list_cpu_features` ``` cmake -B/tmp/cpu_features -H. -GNinja -DCMAKE_BUILD_TYPE=Release ninja -C/tmp/cpu_features @@ -197,5 +196,4 @@ Please check the [CMake build instructions](cmake/README.md). cmake -B/tmp/cpu_features -H. -GNinja -DBUILD_TESTING=ON ninja -C/tmp/cpu_features ninja -C/tmp/cpu_features test - ``` diff --git a/TEST_MAPPING b/TEST_MAPPING index 0af6ef9..824f432 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -22,13 +22,6 @@ "name": "cpu_features-stack_line_reader_test" }, { - "name": "cpu_features-unix_features_aggregator_test", - "host": true - }, - { - "name": "cpu_features-unix_features_aggregator_test" - }, - { "name": "cpu_features-cpuinfo_test", "host": true }, diff --git a/include/cpu_features_cache_info.h b/include/cpu_features_cache_info.h index b7cc046..1a61ee1 100644 --- a/include/cpu_features_cache_info.h +++ b/include/cpu_features_cache_info.h @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/cpu_features_macros.h b/include/cpu_features_macros.h index fae9f70..4b231a1 100644 --- a/include/cpu_features_macros.h +++ b/include/cpu_features_macros.h @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -79,6 +79,10 @@ #define CPU_FEATURES_OS_WINDOWS #endif +#if (defined(__apple__) || defined(__APPLE__) || defined(__MACH__)) +#define CPU_FEATURES_OS_DARWIN +#endif + //////////////////////////////////////////////////////////////////////////////// // Compilers //////////////////////////////////////////////////////////////////////////////// diff --git a/include/cpuinfo_aarch64.h b/include/cpuinfo_aarch64.h index a42ecdf..d85d46d 100644 --- a/include/cpuinfo_aarch64.h +++ b/include/cpuinfo_aarch64.h @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,62 +15,62 @@ #ifndef CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_ #define CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_ -#include "cpu_features_macros.h" #include "cpu_features_cache_info.h" +#include "cpu_features_macros.h" 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 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. + 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; diff --git a/include/cpuinfo_arm.h b/include/cpuinfo_arm.h index d15471f..0952d7c 100644 --- a/include/cpuinfo_arm.h +++ b/include/cpuinfo_arm.h @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,8 +16,9 @@ #define CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_ #include <stdint.h> // uint32_t -#include "cpu_features_macros.h" + #include "cpu_features_cache_info.h" +#include "cpu_features_macros.h" CPU_FEATURES_START_CPP_NAMESPACE @@ -25,30 +26,33 @@ 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 java : 1; // Jazelle (Java bytecode accelerator) - int iwmmxt : 1; // Intel Wireless MMX Technology. - int crunch : 1; // MaverickCrunch coprocessor - int thumbee : 1; // ThumbEE - int neon : 1; // Advanced SIMD. - int vfpv3 : 1; // VFP version 3 + 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 + int thumbee : 1; // ThumbEE + int neon : 1; // Advanced SIMD. + int vfpv3 : 1; // VFP version 3 int vfpv3d16 : 1; // VFP version 3 with 16 D-registers int tls : 1; // TLS register int vfpv4 : 1; // VFP version 4 with fast context switching 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 evtstrm : 1; // kernel event stream using generic architected timer - 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 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. + int sha1 : 1; // Hardware-accelerated SHA1. + int sha2 : 1; // Hardware-accelerated SHA2-256. + int crc32 : 1; // Hardware-accelerated CRC-32. // Make sure to update ArmFeaturesEnum below if you add a field here. } ArmFeatures; diff --git a/include/cpuinfo_mips.h b/include/cpuinfo_mips.h index d82ae85..9e5e7fc 100644 --- a/include/cpuinfo_mips.h +++ b/include/cpuinfo_mips.h @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,8 +15,8 @@ #ifndef CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_ #define CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_ -#include "cpu_features_macros.h" #include "cpu_features_cache_info.h" +#include "cpu_features_macros.h" CPU_FEATURES_START_CPP_NAMESPACE diff --git a/include/cpuinfo_ppc.h b/include/cpuinfo_ppc.h index eaac7da..f691194 100644 --- a/include/cpuinfo_ppc.h +++ b/include/cpuinfo_ppc.h @@ -15,8 +15,8 @@ #ifndef CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_ #define CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_ -#include "cpu_features_macros.h" #include "cpu_features_cache_info.h" +#include "cpu_features_macros.h" #include "internal/hwcaps.h" CPU_FEATURES_START_CPP_NAMESPACE diff --git a/include/cpuinfo_x86.h b/include/cpuinfo_x86.h index c21a46a..8d40f71 100644 --- a/include/cpuinfo_x86.h +++ b/include/cpuinfo_x86.h @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // Copyright 2020 Intel Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/include/internal/bit_utils.h b/include/internal/bit_utils.h index bc965cb..3467ff9 100644 --- a/include/internal/bit_utils.h +++ b/include/internal/bit_utils.h @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ #include <assert.h> #include <stdbool.h> #include <stdint.h> + #include "cpu_features_macros.h" CPU_FEATURES_START_CPP_NAMESPACE diff --git a/include/internal/cpuid_x86.h b/include/internal/cpuid_x86.h index 754ca38..33327a4 100644 --- a/include/internal/cpuid_x86.h +++ b/include/internal/cpuid_x86.h @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -26,7 +26,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); diff --git a/include/internal/filesystem.h b/include/internal/filesystem.h index 3378881..d8f2f6a 100644 --- a/include/internal/filesystem.h +++ b/include/internal/filesystem.h @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ #include <stddef.h> #include <stdint.h> + #include "cpu_features_macros.h" CPU_FEATURES_START_CPP_NAMESPACE diff --git a/include/internal/hwcaps.h b/include/internal/hwcaps.h index f0e91b3..62037c8 100644 --- a/include/internal/hwcaps.h +++ b/include/internal/hwcaps.h @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,7 +17,9 @@ #ifndef CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_ #define CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_ +#include <stdbool.h> #include <stdint.h> + #include "cpu_features_macros.h" CPU_FEATURES_START_CPP_NAMESPACE @@ -169,6 +171,8 @@ typedef struct { } HardwareCapabilities; HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void); +bool CpuFeatures_IsHwCapsSet(const HardwareCapabilities hwcaps_mask, + const HardwareCapabilities hwcaps); typedef struct { char platform[64]; // 0 terminated string diff --git a/include/internal/stack_line_reader.h b/include/internal/stack_line_reader.h index c540f6b..39c1b8b 100644 --- a/include/internal/stack_line_reader.h +++ b/include/internal/stack_line_reader.h @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/internal/string_view.h b/include/internal/string_view.h index aa3779c..64fed40 100644 --- a/include/internal/string_view.h +++ b/include/internal/string_view.h @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ #include <stdbool.h> #include <stddef.h> #include <string.h> + #include "cpu_features_macros.h" CPU_FEATURES_START_CPP_NAMESPACE diff --git a/include/internal/unix_features_aggregator.h b/include/internal/unix_features_aggregator.h deleted file mode 100644 index bed668d..0000000 --- a/include/internal/unix_features_aggregator.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// 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 <ctype.h> -#include <stdint.h> -#include "cpu_features_macros.h" -#include "internal/hwcaps.h" -#include "internal/string_view.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_ diff --git a/ndk_compat/cpu-features.c b/ndk_compat/cpu-features.c index ca49ac3..27ff7bb 100644 --- a/ndk_compat/cpu-features.c +++ b/ndk_compat/cpu-features.c @@ -1,11 +1,12 @@ #include "cpu-features.h" + +#include <pthread.h> + #include "cpu_features_macros.h" #include "internal/filesystem.h" #include "internal/stack_line_reader.h" #include "internal/string_view.h" -#include <pthread.h> - #if defined(CPU_FEATURES_ARCH_ARM) #include "cpuinfo_arm.h" #elif defined(CPU_FEATURES_ARCH_X86) diff --git a/ndk_compat/ndk-compat-test.c b/ndk_compat/ndk-compat-test.c index 782dbbf..e4005d4 100644 --- a/ndk_compat/ndk-compat-test.c +++ b/ndk_compat/ndk-compat-test.c @@ -1,4 +1,5 @@ #include <stdio.h> + #include "cpu-features.h" int main() { diff --git a/src/cpuinfo_aarch64.c b/src/cpuinfo_aarch64.c index 6cd5308..0a52718 100644 --- a/src/cpuinfo_aarch64.c +++ b/src/cpuinfo_aarch64.c @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,120 +14,70 @@ #include "cpuinfo_aarch64.h" +#include <assert.h> +#include <ctype.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> -#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) -DECLARE_SETTER_AND_GETTER(Aarch64Features, dcpodp) -DECLARE_SETTER_AND_GETTER(Aarch64Features, sve2) -DECLARE_SETTER_AND_GETTER(Aarch64Features, sveaes) -DECLARE_SETTER_AND_GETTER(Aarch64Features, svepmull) -DECLARE_SETTER_AND_GETTER(Aarch64Features, svebitperm) -DECLARE_SETTER_AND_GETTER(Aarch64Features, svesha3) -DECLARE_SETTER_AND_GETTER(Aarch64Features, svesm4) -DECLARE_SETTER_AND_GETTER(Aarch64Features, flagm2) -DECLARE_SETTER_AND_GETTER(Aarch64Features, frint) -DECLARE_SETTER_AND_GETTER(Aarch64Features, svei8mm) -DECLARE_SETTER_AND_GETTER(Aarch64Features, svef32mm) -DECLARE_SETTER_AND_GETTER(Aarch64Features, svef64mm) -DECLARE_SETTER_AND_GETTER(Aarch64Features, svebf16) -DECLARE_SETTER_AND_GETTER(Aarch64Features, i8mm) -DECLARE_SETTER_AND_GETTER(Aarch64Features, bf16) -DECLARE_SETTER_AND_GETTER(Aarch64Features, dgh) -DECLARE_SETTER_AND_GETTER(Aarch64Features, rng) -DECLARE_SETTER_AND_GETTER(Aarch64Features, bti) - -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}, - [AARCH64_DCPODP] = {{0, AARCH64_HWCAP2_DCPODP}, "dcpodp", &set_dcpodp, &get_dcpodp}, - [AARCH64_SVE2] = {{0, AARCH64_HWCAP2_SVE2}, "sve2", &set_sve2, &get_sve2}, - [AARCH64_SVEAES] = {{0, AARCH64_HWCAP2_SVEAES}, "sveaes", &set_sveaes, &get_sveaes}, - [AARCH64_SVEPMULL] = {{0, AARCH64_HWCAP2_SVEPMULL}, "svepmull", &set_svepmull, &get_svepmull}, - [AARCH64_SVEBITPERM] = {{0, AARCH64_HWCAP2_SVEBITPERM}, "svebitperm", &set_svebitperm, &get_svebitperm}, - [AARCH64_SVESHA3] = {{0, AARCH64_HWCAP2_SVESHA3}, "svesha3", &set_svesha3, &get_svesha3}, - [AARCH64_SVESM4] = {{0, AARCH64_HWCAP2_SVESM4}, "svesm4", &set_svesm4, &get_svesm4}, - [AARCH64_FLAGM2] = {{0, AARCH64_HWCAP2_FLAGM2}, "flagm2", &set_flagm2, &get_flagm2}, - [AARCH64_FRINT] = {{0, AARCH64_HWCAP2_FRINT}, "frint", &set_frint, &get_frint}, - [AARCH64_SVEI8MM] = {{0, AARCH64_HWCAP2_SVEI8MM}, "svei8mm", &set_svei8mm, &get_svei8mm}, - [AARCH64_SVEF32MM] = {{0, AARCH64_HWCAP2_SVEF32MM}, "svef32mm", &set_svef32mm, &get_svef32mm}, - [AARCH64_SVEF64MM] = {{0, AARCH64_HWCAP2_SVEF64MM}, "svef64mm", &set_svef64mm, &get_svef64mm}, - [AARCH64_SVEBF16] = {{0, AARCH64_HWCAP2_SVEBF16}, "svebf16", &set_svebf16, &get_svebf16}, - [AARCH64_I8MM] = {{0, AARCH64_HWCAP2_I8MM}, "i8mm", &set_i8mm, &get_i8mm}, - [AARCH64_BF16] = {{0, AARCH64_HWCAP2_BF16}, "bf16", &set_bf16, &get_bf16}, - [AARCH64_DGH] = {{0, AARCH64_HWCAP2_DGH}, "dgh", &set_dgh, &get_dgh}, - [AARCH64_RNG] = {{0, AARCH64_HWCAP2_RNG}, "rng", &set_rng, &get_rng}, - [AARCH64_BTI] = {{0, AARCH64_HWCAP2_BTI}, "bti", &set_bti, &get_bti}, -}; - -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) { @@ -135,7 +85,10 @@ static bool HandleAarch64Line(const LineResult result, StringView key, value; if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) { 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"))) { info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value); } else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) { @@ -166,17 +119,18 @@ static void FillProcCpuInfoData(Aarch64Info* const info) { 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; } @@ -186,13 +140,11 @@ 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]; } diff --git a/src/cpuinfo_arm.c b/src/cpuinfo_arm.c index 741c99a..0f216bf 100644 --- a/src/cpuinfo_arm.c +++ b/src/cpuinfo_arm.c @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,75 +14,47 @@ #include "cpuinfo_arm.h" +#include <assert.h> +#include <ctype.h> + #include "internal/bit_utils.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> -#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 { bool processor_reports_armv6; @@ -104,7 +76,10 @@ static bool HandleArmLine(const LineResult result, ArmInfo* const info, StringView key, value; if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) { 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"))) { info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value); } else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) { @@ -119,8 +94,8 @@ static bool HandleArmLine(const LineResult result, ArmInfo* const info, const StringView digits = 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" // see RaspberryPiZero (Linux) vs InvalidArmv7 (Android) test-cases @@ -210,9 +185,12 @@ 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); @@ -224,13 +202,11 @@ 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]; } diff --git a/src/cpuinfo_mips.c b/src/cpuinfo_mips.c index 0564bb8..83e959f 100644 --- a/src/cpuinfo_mips.c +++ b/src/cpuinfo_mips.c @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,23 +14,21 @@ #include "cpuinfo_mips.h" +#include <assert.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) { @@ -38,7 +36,10 @@ static bool HandleMipsLine(const LineResult result, // See tests for an example. if (CpuFeatures_StringView_GetAttributeKeyValue(result.line, &key, &value)) { 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; @@ -61,17 +62,18 @@ static void FillProcCpuInfoData(MipsFeatures* const features) { 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; } @@ -80,13 +82,11 @@ 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]; } diff --git a/src/cpuinfo_ppc.c b/src/cpuinfo_ppc.c index c088f86..24401f9 100644 --- a/src/cpuinfo_ppc.c +++ b/src/cpuinfo_ppc.c @@ -12,105 +12,69 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "cpuinfo_ppc.h" + #include <assert.h> #include <stdbool.h> #include <string.h> -#include "cpuinfo_ppc.h" #include "internal/bit_utils.h" #include "internal/filesystem.h" #include "internal/stack_line_reader.h" #include "internal/string_view.h" -#include "internal/unix_features_aggregator.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) { @@ -156,10 +120,12 @@ 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; } @@ -178,13 +144,11 @@ 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]; } diff --git a/src/cpuinfo_x86.c b/src/cpuinfo_x86.c index d5edd30..378ed05 100644 --- a/src/cpuinfo_x86.c +++ b/src/cpuinfo_x86.c @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // Copyright 2020 Intel Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,6 +25,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. //////////////////////////////////////////////////////////////////////////////// @@ -35,7 +120,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); return leaf; @@ -55,7 +140,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]; __cpuidex(data, leaf_id, ecx); @@ -72,13 +157,13 @@ uint32_t GetXCR0Eax(void) { return (uint32_t)_xgetbv(0); } #error "Unsupported compiler, x86 cpuid requires either GCC, Clang or MSVC." #endif -static Leaf CpuId(uint32_t leaf_id) { return CpuIdEx(leaf_id, 0); } +static Leaf CpuId(uint32_t leaf_id) { return GetCpuidLeaf(leaf_id, 0); } static const Leaf kEmptyLeaf; static Leaf SafeCpuIdEx(uint32_t max_cpuid_leaf, uint32_t leaf_id, int ecx) { if (leaf_id <= max_cpuid_leaf) { - return CpuIdEx(leaf_id, ecx); + return GetCpuidLeaf(leaf_id, ecx); } else { return kEmptyLeaf; } @@ -1082,27 +1167,115 @@ static void ParseLeaf4(const int max_cpuid_leaf, CacheInfo* info) { // Internal structure to hold the OS support for vector operations. // 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 Leaf leaf_7_1 = SafeCpuIdEx(max_cpuid_leaf, 7, 1); - 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); - os_support->have_amx = HasTmmOsXSave(xcr0_eax); - const uint32_t family = ExtractBitRange(leaf_1.eax, 11, 8); const uint32_t extended_family = ExtractBitRange(leaf_1.eax, 27, 20); const uint32_t model = ExtractBitRange(leaf_1.eax, 7, 4); @@ -1142,7 +1315,9 @@ static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info, 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); features->sse3 = IsBitSet(leaf_1.ecx, 0); @@ -1151,13 +1326,13 @@ static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info, 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); features->avx512er = IsBitSet(leaf_7.ebx, 27); @@ -1179,7 +1354,7 @@ static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info, features->avx512_vp2intersect = IsBitSet(leaf_7.edx, 8); } - if (os_support->have_amx) { + 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); @@ -1195,7 +1370,7 @@ static void ParseExtraAMDCpuId(X86Info* info, OsSupport os_support) { X86Features* const features = &info->features; - if (os_support.have_sse) { + if (os_support.have_sse_via_cpuid) { features->sse4a = IsBitSet(leaf_80000001.ecx, 6); } @@ -1205,22 +1380,21 @@ static void ParseExtraAMDCpuId(X86Info* info, OsSupport os_support) { } 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 bool is_intel = IsVendor(leaf_0, "GenuineIntel"); const bool is_amd = IsVendor(leaf_0, "AuthenticAMD"); SetVendor(leaf_0, info.vendor); if (is_intel || is_amd) { const uint32_t max_cpuid_leaf = leaf_0.eax; - ParseCpuId(max_cpuid_leaf, &info, &os_support); - } - if (is_amd) { - ParseExtraAMDCpuId(&info, os_support); + const OsSupport os_support = CheckOsSupport(max_cpuid_leaf); + ParseCpuId(max_cpuid_leaf, os_support, &info); + if (is_amd) { + ParseExtraAMDCpuId(&info, os_support); + } } return info; } @@ -1380,259 +1554,13 @@ 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_AVX512_SECOND_FMA: - return features->avx512_second_fma; - case X86_AVX512_4FMAPS: - return features->avx512_4fmaps; - case X86_AVX512_BF16: - return features->avx512_bf16; - case X86_AVX512_VP2INTERSECT: - return features->avx512_vp2intersect; - case X86_AMX_BF16: - return features->amx_bf16; - case X86_AMX_TILE: - return features->amx_tile; - case X86_AMX_INT8: - return features->amx_int8; - 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_AVX512_SECOND_FMA: - return "avx512_second_fma"; - case X86_AVX512_4FMAPS: - return "avx512_4fmaps"; - case X86_AVX512_BF16: - return "avx512_bf16"; - case X86_AVX512_VP2INTERSECT: - return "avx512_vp2intersect"; - case X86_AMX_BF16: - return "amx_bf16"; - case X86_AMX_TILE: - return "amx_tile"; - case X86_AMX_INT8: - return "amx_int8"; - 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) { diff --git a/src/define_tables.h b/src/define_tables.h new file mode 100644 index 0000000..dc1485c --- /dev/null +++ b/src/define_tables.h @@ -0,0 +1,67 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// 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_ diff --git a/src/filesystem.c b/src/filesystem.c index 2f7083b..46c9906 100644 --- a/src/filesystem.c +++ b/src/filesystem.c @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/src/hwcaps.c b/src/hwcaps.c index 815e5c1..dd17e3b 100644 --- a/src/hwcaps.c +++ b/src/hwcaps.c @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,14 +12,33 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "internal/hwcaps.h" + #include <stdlib.h> #include <string.h> #include "cpu_features_macros.h" #include "internal/filesystem.h" -#include "internal/hwcaps.h" #include "internal/string_view.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 @@ -35,9 +54,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) { return getauxval(hwcap_type); @@ -59,17 +81,13 @@ 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); static uint32_t GetElfHwcapFromGetauxval(uint32_t hwcap_type) { uint32_t ret = 0; - void* libc_handle = NULL; - getauxval_func_t* func = NULL; + void *libc_handle = NULL; + getauxval_func_t *func = NULL; dlerror(); // Cleaning error state before calling dlopen. libc_handle = dlopen("libc.so", RTLD_NOW); @@ -77,7 +95,7 @@ static uint32_t GetElfHwcapFromGetauxval(uint32_t hwcap_type) { D("Could not dlopen() C library: %s\n", dlerror()); return 0; } - func = (getauxval_func_t*)dlsym(libc_handle, "getauxval"); + func = (getauxval_func_t *)dlsym(libc_handle, "getauxval"); if (!func) { D("Could not find getauxval() in C library\n"); } else { @@ -109,7 +127,7 @@ static uint32_t GetElfHwcapFromProcSelfAuxv(uint32_t hwcap_type) { return 0; } for (;;) { - const int ret = CpuFeatures_ReadFile(fd, (char*)&entry, sizeof entry); + const int ret = CpuFeatures_ReadFile(fd, (char *)&entry, sizeof entry); if (ret < 0) { D("Error while reading %s\n", filepath); break; @@ -160,3 +178,5 @@ PlatformType CpuFeatures_GetPlatformType(void) { sizeof(type.base_platform)); return type; } + +#endif // CPU_FEATURES_TEST diff --git a/src/stack_line_reader.c b/src/stack_line_reader.c index b2c48ba..ffc778d 100644 --- a/src/stack_line_reader.c +++ b/src/stack_line_reader.c @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,12 +13,13 @@ // limitations under the License. #include "internal/stack_line_reader.h" -#include "internal/filesystem.h" #include <assert.h> #include <errno.h> #include <stdio.h> +#include "internal/filesystem.h" + void StackLineReader_Initialize(StackLineReader* reader, int fd) { reader->view.ptr = reader->buffer; reader->view.size = 0; diff --git a/src/string_view.c b/src/string_view.c index 856731c..dc3158f 100644 --- a/src/string_view.c +++ b/src/string_view.c @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/src/unix_features_aggregator.c b/src/unix_features_aggregator.c deleted file mode 100644 index 1b43a36..0000000 --- a/src/unix_features_aggregator.c +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#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); - } - } -} diff --git a/src/utils/list_cpu_features.c b/src/utils/list_cpu_features.c index 0783648..c80ffc5 100644 --- a/src/utils/list_cpu_features.c +++ b/src/utils/list_cpu_features.c @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -44,7 +44,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; size_t size; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index eb67ac0..c10e617 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -12,7 +12,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) @@ -23,7 +22,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) # @@ -46,15 +45,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() diff --git a/test/bit_utils_test.cc b/test/bit_utils_test.cc index 9c8c1bb..3874e13 100644 --- a/test/bit_utils_test.cc +++ b/test/bit_utils_test.cc @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/test/cpuinfo_aarch64_test.cc b/test/cpuinfo_aarch64_test.cc index 1bd0648..5afaaa8 100644 --- a/test/cpuinfo_aarch64_test.cc +++ b/test/cpuinfo_aarch64_test.cc @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,10 +13,10 @@ // limitations under the License. #include "cpuinfo_aarch64.h" -#include "filesystem_for_testing.h" -#include "hwcaps_for_testing.h" +#include "filesystem_for_testing.h" #include "gtest/gtest.h" +#include "hwcaps_for_testing.h" namespace cpu_features { namespace { @@ -62,7 +62,8 @@ TEST(CpuinfoAarch64Test, FromHardwareCap) { } TEST(CpuinfoAarch64Test, FromHardwareCap2) { - SetHardwareCapabilities(AARCH64_HWCAP_FP, AARCH64_HWCAP2_SVE2 | AARCH64_HWCAP2_BTI); + SetHardwareCapabilities(AARCH64_HWCAP_FP, + AARCH64_HWCAP2_SVE2 | AARCH64_HWCAP2_BTI); GetEmptyFilesystem(); // disabling /proc/cpuinfo const auto info = GetAarch64Info(); EXPECT_TRUE(info.features.fp); diff --git a/test/cpuinfo_arm_test.cc b/test/cpuinfo_arm_test.cc index fa92e11..e0b08a4 100644 --- a/test/cpuinfo_arm_test.cc +++ b/test/cpuinfo_arm_test.cc @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,10 +13,10 @@ // limitations under the License. #include "cpuinfo_arm.h" -#include "filesystem_for_testing.h" -#include "hwcaps_for_testing.h" +#include "filesystem_for_testing.h" #include "gtest/gtest.h" +#include "hwcaps_for_testing.h" namespace cpu_features { namespace { diff --git a/test/cpuinfo_mips_test.cc b/test/cpuinfo_mips_test.cc index fbec04d..d734058 100644 --- a/test/cpuinfo_mips_test.cc +++ b/test/cpuinfo_mips_test.cc @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,13 +13,13 @@ // limitations under the License. #include "cpuinfo_mips.h" + #include "filesystem_for_testing.h" +#include "gtest/gtest.h" #include "hwcaps_for_testing.h" #include "internal/stack_line_reader.h" #include "internal/string_view.h" -#include "gtest/gtest.h" - namespace cpu_features { namespace { diff --git a/test/cpuinfo_ppc_test.cc b/test/cpuinfo_ppc_test.cc index 5d5e798..8f0cb65 100644 --- a/test/cpuinfo_ppc_test.cc +++ b/test/cpuinfo_ppc_test.cc @@ -13,12 +13,12 @@ // limitations under the License. #include "cpuinfo_ppc.h" + #include "filesystem_for_testing.h" +#include "gtest/gtest.h" #include "hwcaps_for_testing.h" #include "internal/string_view.h" -#include "gtest/gtest.h" - namespace cpu_features { namespace { diff --git a/test/cpuinfo_x86_test.cc b/test/cpuinfo_x86_test.cc index 3c80eee..636d0f9 100644 --- a/test/cpuinfo_x86_test.cc +++ b/test/cpuinfo_x86_test.cc @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,20 +12,25 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "cpuinfo_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 "cpuinfo_x86.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()) { return itr->second; @@ -43,22 +48,66 @@ class FakeCpu { 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) { - return g_fake_cpu->CpuIdEx(leaf_id, ecx); +extern "C" Leaf GetCpuidLeaf(uint32_t leaf_id, int 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({ {{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}}, @@ -104,7 +153,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}}, {{0x00000001, 0}, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}}, @@ -118,7 +167,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({ {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}}, @@ -133,7 +182,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}}, {{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}}, @@ -149,7 +198,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}}, {{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}}, @@ -198,7 +247,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}}, {{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}}, @@ -246,8 +295,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}}, {{0x00000001, 0}, Leaf{0x00630F81, 0x00040800, 0x3E98320B, 0x178BFBFF}}, @@ -273,6 +323,208 @@ 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. diff --git a/test/filesystem_for_testing.cc b/test/filesystem_for_testing.cc index 0a11416..648a53e 100644 --- a/test/filesystem_for_testing.cc +++ b/test/filesystem_for_testing.cc @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/test/filesystem_for_testing.h b/test/filesystem_for_testing.h index 7474b5f..ef717fd 100644 --- a/test/filesystem_for_testing.h +++ b/test/filesystem_for_testing.h @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/test/hwcaps_for_testing.cc b/test/hwcaps_for_testing.cc index 07f68e8..a8086a0 100644 --- a/test/hwcaps_for_testing.cc +++ b/test/hwcaps_for_testing.cc @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,9 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "hwcaps_for_testing.h" + #include <string.h> -#include "hwcaps_for_testing.h" #include "internal/string_view.h" namespace cpu_features { diff --git a/test/hwcaps_for_testing.h b/test/hwcaps_for_testing.h index 0d03777..bcab82e 100644 --- a/test/hwcaps_for_testing.h +++ b/test/hwcaps_for_testing.h @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/test/stack_line_reader_test.cc b/test/stack_line_reader_test.cc index c8f9691..9ac5388 100644 --- a/test/stack_line_reader_test.cc +++ b/test/stack_line_reader_test.cc @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,8 +13,8 @@ // limitations under the License. #include "internal/stack_line_reader.h" -#include "filesystem_for_testing.h" +#include "filesystem_for_testing.h" #include "gtest/gtest.h" namespace cpu_features { diff --git a/test/string_view_test.cc b/test/string_view_test.cc index 0b6c7c2..ca3e023 100644 --- a/test/string_view_test.cc +++ b/test/string_view_test.cc @@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. +// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -117,13 +117,13 @@ TEST(StringViewTest, CpuFeatures_StringView_Back) { TEST(StringViewTest, CpuFeatures_StringView_TrimWhitespace) { EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str(" first middle last ")), - str("first middle last")); + str("first middle last")); EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str("first middle last ")), - str("first middle last")); + str("first middle last")); EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str(" first middle last")), - str("first middle last")); + str("first middle last")); EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str("first middle last")), - str("first middle last")); + str("first middle last")); } TEST(StringViewTest, CpuFeatures_StringView_ParsePositiveNumber) { diff --git a/test/unix_features_aggregator_test.cc b/test/unix_features_aggregator_test.cc deleted file mode 100644 index 9017644..0000000 --- a/test/unix_features_aggregator_test.cc +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include <array> - -#include "internal/unix_features_aggregator.h" - -#include "gtest/gtest.h" - -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 |