pax_global_header00006660000000000000000000000064145005745450014523gustar00rootroot0000000000000052 comment=ba4bffa86cbb5456bdb34426ad22b9551278e2c0 cpu-features-0.9.0/000077500000000000000000000000001450057454500141345ustar00rootroot00000000000000cpu-features-0.9.0/.clang-format000066400000000000000000000000631450057454500165060ustar00rootroot00000000000000--- Language: Cpp BasedOnStyle: Google ... cpu-features-0.9.0/.dockerignore000066400000000000000000000006301450057454500166070ustar00rootroot00000000000000# Project Files unneeded by docker .git .gitignore .github .dockerignore .clang-format appveyor.yml .travis.yml AUTHORS CONTRIBUTING.md CONTRIBUTORS LICENSE README.md bazel/ci/Makefile bazel/ci/docker bazel/ci/doc cmake/ci/Makefile cmake/ci/docker cmake/ci/doc cmake/ci/cache build/ cmake_build/ build_cross/ cmake-build-*/ out/ # Editor directories and files .idea/ .vagrant/ .vscode/ .vs/ *.user *.swp cpu-features-0.9.0/.github/000077500000000000000000000000001450057454500154745ustar00rootroot00000000000000cpu-features-0.9.0/.github/workflows/000077500000000000000000000000001450057454500175315ustar00rootroot00000000000000cpu-features-0.9.0/.github/workflows/Dockerfile000066400000000000000000000003641450057454500215260ustar00rootroot00000000000000# 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-extra-tools RUN git config --global --add safe.directory /repo cpu-features-0.9.0/.github/workflows/aarch64_linux_bazel.yml000066400000000000000000000011601450057454500240760ustar00rootroot00000000000000name: AArch64 Linux Bazel on: push: pull_request: schedule: # min hours day(month) month day(week) - cron: '0 0 7,22 * *' jobs: # Building using the github runner environement directly. bazel: runs-on: ubuntu-latest steps: - name: Check out repository code uses: actions/checkout@v3 - name: Set up QEMU uses: docker/setup-qemu-action@v2 - name: Check docker run: | docker info docker buildx ls - name: Build run: make --directory=bazel/ci arm64_build - name: Test run: make --directory=bazel/ci arm64_test cpu-features-0.9.0/.github/workflows/aarch64_linux_cmake.yml000066400000000000000000000012221450057454500240600ustar00rootroot00000000000000name: AArch64 Linux CMake on: push: pull_request: schedule: # min hours day(month) month day(week) - cron: '0 0 7,22 * *' jobs: # Building using the github runner environement directly. make: runs-on: ubuntu-latest strategy: matrix: targets: [ [aarch64], [aarch64be], [aarch64-linux-gnu], [aarch64_be-linux-gnu] ] fail-fast: false env: TARGET: ${{ matrix.targets[0] }} steps: - uses: actions/checkout@v2 - name: Build run: make --directory=cmake/ci ${TARGET}_build - name: Test run: make --directory=cmake/ci ${TARGET}_test cpu-features-0.9.0/.github/workflows/amd64_freebsd_cmake.yml000066400000000000000000000010751450057454500240240ustar00rootroot00000000000000name: amd64 FreeBSD CMake on: push: pull_request: schedule: # min hours day(month) month day(week) - cron: '0 0 7,22 * *' jobs: # Only MacOS hosted runner provides virtualisation with vagrant/virtualbox installed. # see: https://github.com/actions/virtual-environments/tree/main/images/macos make: runs-on: macos-latest steps: - uses: actions/checkout@v2 - name: vagrant version run: Vagrant --version - name: VirtualBox version run: virtualbox -h - name: Build run: cd cmake/ci/vagrant/freebsd && vagrant up cpu-features-0.9.0/.github/workflows/amd64_linux_bazel.yml000066400000000000000000000011561450057454500235660ustar00rootroot00000000000000name: amd64 Linux Bazel on: push: pull_request: schedule: # min hours day(month) month day(week) - cron: '0 0 7,22 * *' jobs: # Building using the github runner environement directly. bazel: runs-on: ubuntu-latest steps: - name: Check out repository code uses: actions/checkout@v3 - name: Set up QEMU uses: docker/setup-qemu-action@v2 - name: Check docker run: | docker info docker buildx ls - name: Build run: make --directory=bazel/ci amd64_build - name: Test run: make --directory=bazel/ci amd64_test cpu-features-0.9.0/.github/workflows/amd64_linux_cmake.yml000066400000000000000000000015441450057454500235520ustar00rootroot00000000000000name: amd64 Linux CMake on: push: pull_request: schedule: # min hours day(month) month day(week) - cron: '0 0 7,22 * *' jobs: # Building using the github runner environement directly. make: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Env run: make --directory=cmake/ci amd64_env - name: Devel run: make --directory=cmake/ci amd64_devel - name: Build run: make --directory=cmake/ci amd64_build - name: Test run: make --directory=cmake/ci amd64_test - name: Install Env run: make --directory=cmake/ci amd64_install_env - name: Install Devel run: make --directory=cmake/ci amd64_install_devel - name: Install Build run: make --directory=cmake/ci amd64_install_build - name: Install Test run: make --directory=cmake/ci amd64_install_test cpu-features-0.9.0/.github/workflows/amd64_macos_bazel.yml000066400000000000000000000013361450057454500235310ustar00rootroot00000000000000name: amd64 MacOS Bazel on: push: pull_request: schedule: # min hours day(month) month day(week) - cron: '0 0 7,22 * *' jobs: # Building using the github runner environement directly. bazel: runs-on: macos-latest steps: - name: Check out repository code uses: actions/checkout@v3 - name: Install Bazel run: | brew update brew unlink bazelisk brew install bazel - name: Check Bazel run: bazel version - name: Build run: > bazel build -c opt --subcommands=true ... - name: Test run: > bazel test -c opt --test_output=errors ... cpu-features-0.9.0/.github/workflows/amd64_macos_cmake.yml000066400000000000000000000022371450057454500235150ustar00rootroot00000000000000name: amd64 MacOS CMake on: push: pull_request: schedule: # min hours day(month) month day(week) - cron: '0 0 7,22 * *' jobs: # Building using the github runner environement directly. xcode: runs-on: macos-latest env: CTEST_OUTPUT_ON_FAILURE: 1 steps: - uses: actions/checkout@v2 - name: Check cmake run: cmake --version - name: Configure run: cmake -S. -Bbuild -G "Xcode" -DCMAKE_CONFIGURATION_TYPES=Release - name: Build run: cmake --build build --config Release --target ALL_BUILD -v - name: Test run: cmake --build build --config Release --target RUN_TESTS -v - name: Install run: cmake --build build --config Release --target install -v make: runs-on: macos-latest env: CTEST_OUTPUT_ON_FAILURE: 1 steps: - uses: actions/checkout@v2 - name: Check cmake run: cmake --version - name: Configure run: cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release - name: Build run: cmake --build build --target all -v - name: Test run: cmake --build build --target test -v - name: Install run: cmake --build build --target install -v cpu-features-0.9.0/.github/workflows/amd64_windows_cmake.yml000066400000000000000000000013451450057454500241040ustar00rootroot00000000000000name: amd64 Windows CMake on: push: pull_request: schedule: # min hours day(month) month day(week) - cron: '0 0 7,22 * *' jobs: # Building using the github runner environement directly. msvc: runs-on: windows-latest env: CTEST_OUTPUT_ON_FAILURE: 1 steps: - uses: actions/checkout@v2 - name: Configure run: cmake -S. -Bbuild -G "Visual Studio 17 2022" -DCMAKE_CONFIGURATION_TYPES=Release - name: Build run: cmake --build build --config Release --target ALL_BUILD -- /maxcpucount - name: Test run: cmake --build build --config Release --target RUN_TESTS -- /maxcpucount - name: Install run: cmake --build build --config Release --target INSTALL -- /maxcpucount cpu-features-0.9.0/.github/workflows/arm_linux_cmake.yml000066400000000000000000000013111450057454500234060ustar00rootroot00000000000000name: ARM Linux CMake on: push: pull_request: schedule: # min hours day(month) month day(week) - cron: '0 0 7,22 * *' jobs: # Building using the github runner environement directly. make: runs-on: ubuntu-latest strategy: matrix: targets: [ [arm-linux-gnueabihf], [armv8l-linux-gnueabihf], [arm-linux-gnueabi], [armeb-linux-gnueabihf], [armeb-linux-gnueabi] ] fail-fast: false env: TARGET: ${{ matrix.targets[0] }} steps: - uses: actions/checkout@v2 - name: Build run: make --directory=cmake/ci ${TARGET}_build - name: Test run: make --directory=cmake/ci ${TARGET}_test cpu-features-0.9.0/.github/workflows/clang_format.yml000066400000000000000000000016341450057454500227140ustar00rootroot00000000000000name: 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@v4 - name: Fetch origin/main run: git fetch origin main - 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 " cpu-features-0.9.0/.github/workflows/mips_linux_cmake.yml000066400000000000000000000011661450057454500236070ustar00rootroot00000000000000name: MIPS Linux CMake on: push: pull_request: schedule: # min hours day(month) month day(week) - cron: '0 0 7,22 * *' jobs: # Building using the github runner environement directly. make: runs-on: ubuntu-latest strategy: matrix: targets: [ [mips32], [mips32el], [mips64], [mips64el] ] fail-fast: false env: TARGET: ${{ matrix.targets[0] }} steps: - uses: actions/checkout@v2 - name: Build run: make --directory=cmake/ci ${TARGET}_build - name: Test run: make --directory=cmake/ci ${TARGET}_test cpu-features-0.9.0/.github/workflows/power_linux_cmake.yml000066400000000000000000000011351450057454500237670ustar00rootroot00000000000000name: POWER Linux CMake on: push: pull_request: schedule: # min hours day(month) month day(week) - cron: '0 0 7,22 * *' jobs: # Building using the github runner environement directly. make: runs-on: ubuntu-latest strategy: matrix: targets: [ [ppc], [ppc64], [ppc64le], ] fail-fast: false env: TARGET: ${{ matrix.targets[0] }} steps: - uses: actions/checkout@v2 - name: Build run: make --directory=cmake/ci ${TARGET}_build - name: Test run: make --directory=cmake/ci ${TARGET}_test cpu-features-0.9.0/.github/workflows/riscv_linux_cmake.yml000066400000000000000000000011161450057454500237600ustar00rootroot00000000000000name: RISCV Linux CMake on: push: pull_request: schedule: # min hours day(month) month day(week) - cron: '0 0 7,22 * *' jobs: # Building using the github runner environement directly. make: runs-on: ubuntu-latest strategy: matrix: targets: [ [riscv32], [riscv64], ] fail-fast: false env: TARGET: ${{ matrix.targets[0] }} steps: - uses: actions/checkout@v2 - name: Build run: make --directory=cmake/ci ${TARGET}_build - name: Test run: make --directory=cmake/ci ${TARGET}_test cpu-features-0.9.0/.github/workflows/s390x_linux_cmake.yml000066400000000000000000000010671450057454500235250ustar00rootroot00000000000000name: s390x Linux CMake on: push: pull_request: schedule: # min hours day(month) month day(week) - cron: '0 0 7,22 * *' jobs: # Building using the github runner environement directly. make: runs-on: ubuntu-latest strategy: matrix: targets: [ [s390x], ] fail-fast: false env: TARGET: ${{ matrix.targets[0] }} steps: - uses: actions/checkout@v2 - name: Build run: make --directory=cmake/ci ${TARGET}_build - name: Test run: make --directory=cmake/ci ${TARGET}_test cpu-features-0.9.0/.gitignore000066400000000000000000000003071450057454500161240ustar00rootroot00000000000000# Build folders build/ cmake_build/ build_cross/ cmake-build-*/ out/ # IDEs / CI temp files .idea/ .vagrant/ .vscode/ .vs/ *.swp # Bazel artifacts **/bazel-* # Per-user bazelrc files user.bazelrc cpu-features-0.9.0/.grenrc.yml000066400000000000000000000006041450057454500162150ustar00rootroot00000000000000--- dataSource: "prs" ignoreLabels: - "Apple M1" - "duplicate" - "help wanted" - "invalid" - "question" - "wontfix" onlyMilestones: false groupBy: "API Change": - "API Change" "New features / Enhancements": - "enhancement" - "internal" "Bug Fixes": - "bug" "Misc": - "misc" changelogFilename: "CHANGELOG.md" cpu-features-0.9.0/BUILD.bazel000066400000000000000000000242171450057454500160200ustar00rootroot00000000000000# cpu_features, a cross platform C99 library to get cpu features at runtime. load("@bazel_skylib//lib:selects.bzl", "selects") load("//:bazel/platforms.bzl", "PLATFORM_CPU_ARM", "PLATFORM_CPU_ARM64", "PLATFORM_CPU_MIPS", "PLATFORM_CPU_PPC", "PLATFORM_CPU_RISCV32", "PLATFORM_CPU_RISCV64", "PLATFORM_CPU_X86_64") load("//:bazel/platforms.bzl", "PLATFORM_OS_MACOS") package( default_visibility = ["//visibility:public"], licenses = ["notice"], ) exports_files(["LICENSE"]) INCLUDES = ["include"] C99_FLAGS = [ "-std=c99", "-Wall", "-Wextra", "-Wmissing-declarations", "-Wmissing-prototypes", "-Wno-implicit-fallthrough", "-Wno-unused-function", "-Wold-style-definition", "-Wshadow", "-Wsign-compare", "-Wstrict-prototypes", ] cc_library( name = "cpu_features_macros", copts = C99_FLAGS, includes = INCLUDES, textual_hdrs = ["include/cpu_features_macros.h"], ) cc_library( name = "cpu_features_cache_info", copts = C99_FLAGS, includes = INCLUDES, textual_hdrs = ["include/cpu_features_cache_info.h"], deps = [":cpu_features_macros"], ) cc_library( name = "bit_utils", copts = C99_FLAGS, includes = INCLUDES, textual_hdrs = ["include/internal/bit_utils.h"], deps = [":cpu_features_macros"], ) cc_test( name = "bit_utils_test", srcs = ["test/bit_utils_test.cc"], includes = INCLUDES, deps = [ ":bit_utils", "@com_google_googletest//:gtest_main", ], ) cc_library( name = "memory_utils", copts = C99_FLAGS, includes = INCLUDES, textual_hdrs = [ "src/copy.inl", "src/equals.inl", ], ) cc_library( name = "string_view", srcs = [ "src/string_view.c", ], copts = C99_FLAGS, includes = INCLUDES, textual_hdrs = ["include/internal/string_view.h"], deps = [ ":cpu_features_macros", ":memory_utils", ], ) cc_test( name = "string_view_test", srcs = ["test/string_view_test.cc"], includes = INCLUDES, deps = [ ":string_view", "@com_google_googletest//:gtest_main", ], ) cc_library( name = "filesystem", srcs = ["src/filesystem.c"], copts = C99_FLAGS, includes = INCLUDES, textual_hdrs = ["include/internal/filesystem.h"], deps = [":cpu_features_macros"], ) cc_library( name = "filesystem_for_testing", testonly = 1, srcs = [ "src/filesystem.c", "test/filesystem_for_testing.cc", ], hdrs = [ "include/internal/filesystem.h", "test/filesystem_for_testing.h", ], defines = ["CPU_FEATURES_MOCK_FILESYSTEM"], includes = INCLUDES, deps = [ ":cpu_features_macros", ], ) cc_library( name = "stack_line_reader", srcs = ["src/stack_line_reader.c"], copts = C99_FLAGS, defines = ["STACK_LINE_READER_BUFFER_SIZE=1024"], includes = INCLUDES, textual_hdrs = ["include/internal/stack_line_reader.h"], deps = [ ":cpu_features_macros", ":filesystem", ":string_view", ], ) cc_test( name = "stack_line_reader_test", srcs = [ "include/internal/stack_line_reader.h", "src/stack_line_reader.c", "test/stack_line_reader_test.cc", ], defines = ["STACK_LINE_READER_BUFFER_SIZE=16"], includes = INCLUDES, deps = [ ":cpu_features_macros", ":filesystem_for_testing", ":string_view", "@com_google_googletest//:gtest_main", ], ) cc_library( name = "stack_line_reader_to_use_with_filesystem_for_testing", testonly = 1, srcs = ["src/stack_line_reader.c"], hdrs = ["include/internal/stack_line_reader.h"], copts = C99_FLAGS, defines = ["STACK_LINE_READER_BUFFER_SIZE=1024"], includes = INCLUDES, deps = [ ":cpu_features_macros", ":filesystem_for_testing", ":string_view", ], ) cc_library( name = "hwcaps", srcs = ["src/hwcaps.c"], copts = C99_FLAGS, defines = selects.with_or({ PLATFORM_OS_MACOS: ["HAVE_DLFCN_H"], "//conditions:default": ["HAVE_STRONG_GETAUXVAL"], }), includes = INCLUDES, textual_hdrs = ["include/internal/hwcaps.h"], deps = [ ":cpu_features_macros", ":filesystem", ":string_view", ], ) cc_library( name = "hwcaps_for_testing", testonly = 1, srcs = [ "src/hwcaps.c", "test/hwcaps_for_testing.cc", ], hdrs = [ "include/internal/hwcaps.h", "test/hwcaps_for_testing.h", ], defines = [ "CPU_FEATURES_MOCK_GET_ELF_HWCAP_FROM_GETAUXVAL", "CPU_FEATURES_TEST", ], includes = INCLUDES, deps = [ ":cpu_features_macros", ":filesystem_for_testing", ":string_view", ], ) cc_library( name = "cpuinfo", srcs = selects.with_or({ PLATFORM_CPU_X86_64: [ "src/impl_x86_freebsd.c", "src/impl_x86_linux_or_android.c", "src/impl_x86_macos.c", "src/impl_x86_windows.c", ], PLATFORM_CPU_ARM: ["src/impl_arm_linux_or_android.c"], PLATFORM_CPU_ARM64: [ "src/impl_aarch64_linux_or_android.c", "src/impl_aarch64_macos_or_iphone.c", "src/impl_aarch64_windows.c", ], PLATFORM_CPU_MIPS: ["src/impl_mips_linux_or_android.c"], PLATFORM_CPU_PPC: ["src/impl_ppc_linux.c"], PLATFORM_CPU_RISCV32: ["src/impl_riscv_linux.c"], PLATFORM_CPU_RISCV64: ["src/impl_riscv_linux.c"], }), hdrs = selects.with_or({ PLATFORM_CPU_X86_64: [ "include/cpuinfo_x86.h", "include/internal/cpuid_x86.h", "include/internal/windows_utils.h", ], PLATFORM_CPU_ARM: ["include/cpuinfo_arm.h"], PLATFORM_CPU_ARM64: ["include/cpuinfo_aarch64.h"], PLATFORM_CPU_MIPS: ["include/cpuinfo_mips.h"], PLATFORM_CPU_PPC: ["include/cpuinfo_ppc.h"], PLATFORM_CPU_RISCV32: ["include/cpuinfo_riscv.h"], PLATFORM_CPU_RISCV64: ["include/cpuinfo_riscv.h"], }), copts = C99_FLAGS, defines = selects.with_or({ PLATFORM_OS_MACOS: ["HAVE_SYSCTLBYNAME"], "//conditions:default": [], }), includes = INCLUDES, textual_hdrs = selects.with_or({ PLATFORM_CPU_X86_64: ["src/impl_x86__base_implementation.inl"], PLATFORM_CPU_ARM64: ["src/impl_aarch64__base_implementation.inl"], "//conditions:default": [], }) + [ "src/define_introspection.inl", "src/define_introspection_and_hwcaps.inl", ], deps = [ ":bit_utils", ":cpu_features_cache_info", ":cpu_features_macros", ":filesystem", ":hwcaps", ":memory_utils", ":stack_line_reader", ":string_view", ], ) cc_library( name = "cpuinfo_for_testing", testonly = 1, srcs = selects.with_or({ PLATFORM_CPU_X86_64: [ "src/impl_x86_freebsd.c", "src/impl_x86_linux_or_android.c", "src/impl_x86_macos.c", "src/impl_x86_windows.c", ], PLATFORM_CPU_ARM: ["src/impl_arm_linux_or_android.c"], PLATFORM_CPU_ARM64: [ "src/impl_aarch64_linux_or_android.c", "src/impl_aarch64_macos_or_iphone.c", "src/impl_aarch64_windows.c", ], PLATFORM_CPU_MIPS: ["src/impl_mips_linux_or_android.c"], PLATFORM_CPU_PPC: ["src/impl_ppc_linux.c"], PLATFORM_CPU_RISCV32: ["src/impl_riscv_linux.c"], PLATFORM_CPU_RISCV64: ["src/impl_riscv_linux.c"], }), hdrs = selects.with_or({ PLATFORM_CPU_X86_64: [ "include/cpuinfo_x86.h", "include/internal/cpuid_x86.h", "include/internal/windows_utils.h", ], PLATFORM_CPU_ARM: ["include/cpuinfo_arm.h"], PLATFORM_CPU_ARM64: ["include/cpuinfo_aarch64.h"], PLATFORM_CPU_MIPS: ["include/cpuinfo_mips.h"], PLATFORM_CPU_PPC: ["include/cpuinfo_ppc.h"], PLATFORM_CPU_RISCV32: ["include/cpuinfo_riscv.h"], PLATFORM_CPU_RISCV64: ["include/cpuinfo_riscv.h"], }), copts = C99_FLAGS, defines = selects.with_or({ PLATFORM_CPU_X86_64: ["CPU_FEATURES_MOCK_CPUID_X86"], "//conditions:default": [], }) + selects.with_or({ PLATFORM_OS_MACOS: ["HAVE_SYSCTLBYNAME"], "//conditions:default": [], }), includes = INCLUDES, textual_hdrs = selects.with_or({ PLATFORM_CPU_X86_64: ["src/impl_x86__base_implementation.inl"], PLATFORM_CPU_ARM64: ["src/impl_aarch64__base_implementation.inl"], "//conditions:default": [], }) + [ "src/define_introspection.inl", "src/define_introspection_and_hwcaps.inl", ], deps = [ ":bit_utils", ":cpu_features_cache_info", ":cpu_features_macros", ":filesystem_for_testing", ":hwcaps_for_testing", ":memory_utils", ":stack_line_reader_to_use_with_filesystem_for_testing", ":string_view", ], ) cc_test( name = "cpuinfo_test", srcs = selects.with_or({ PLATFORM_CPU_ARM64: ["test/cpuinfo_aarch64_test.cc"], PLATFORM_CPU_ARM: ["test/cpuinfo_arm_test.cc"], PLATFORM_CPU_MIPS: ["test/cpuinfo_mips_test.cc"], PLATFORM_CPU_PPC: ["test/cpuinfo_ppc_test.cc"], PLATFORM_CPU_RISCV32: ["test/cpuinfo_riscv_test.cc"], PLATFORM_CPU_RISCV64: ["test/cpuinfo_riscv_test.cc"], PLATFORM_CPU_X86_64: ["test/cpuinfo_x86_test.cc"], }), includes = INCLUDES, deps = [ ":cpuinfo_for_testing", ":filesystem_for_testing", ":hwcaps_for_testing", ":string_view", "@com_google_googletest//:gtest_main", ], ) cc_binary( name = "list_cpu_features", srcs = ["src/utils/list_cpu_features.c"], copts = C99_FLAGS, includes = INCLUDES, deps = [ ":bit_utils", ":cpu_features_macros", ":cpuinfo", ], ) cc_library( name = "ndk_compat", srcs = ["ndk_compat/cpu-features.c"], copts = C99_FLAGS, includes = INCLUDES + ["ndk_compat"], textual_hdrs = ["ndk_compat/cpu-features.h"], deps = [ ":cpu_features_macros", ":cpuinfo", ":filesystem", ":stack_line_reader", ":string_view", ], ) cpu-features-0.9.0/CMakeLists.txt000066400000000000000000000245661450057454500167110ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.13) # option() honors normal variables. # see: https://cmake.org/cmake/help/git-stage/policy/CMP0077.html if(POLICY CMP0077) cmake_policy(SET CMP0077 NEW) endif() project(CpuFeatures VERSION 0.9.0 LANGUAGES C) set(CMAKE_C_STANDARD 99) # when cpu_features is included as subproject (i.e. using add_subdirectory(cpu_features)) # in the source tree of a project that uses it, test rules are disabled. if(NOT CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) option(BUILD_TESTING "Enable test rule" OFF) else() option(BUILD_TESTING "Enable test rule" ON) endif() # Default Build Type to be Release if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) endif(NOT CMAKE_BUILD_TYPE) # An option to enable/disable the executable target list_cpu_features. # Disable it by default if the project is included as a subproject. if(NOT CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) option(BUILD_EXECUTABLE "Build list_cpu_features executable." OFF) else() option(BUILD_EXECUTABLE "Build list_cpu_features executable." ON) endif() # An option which allows to switch off install steps. Useful for embedding. # Disable it by default if the project is included as a subproject. if(NOT CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) option(ENABLE_INSTALL "Enable install targets" OFF) else() option(ENABLE_INSTALL "Enable install targets" ON) endif() # 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. # Prefer static linking from source whenever possible. option(BUILD_SHARED_LIBS "Build library as shared." OFF) # Force PIC on unix when building shared libs # see: https://en.wikipedia.org/wiki/Position-independent_code if(BUILD_SHARED_LIBS AND UNIX) option(CMAKE_POSITION_INDEPENDENT_CODE "Build with Position Independant Code." ON) endif() include(CheckIncludeFile) include(CheckSymbolExists) include(GNUInstallDirs) macro(setup_include_and_definitions TARGET_NAME) target_include_directories(${TARGET_NAME} PUBLIC $ PRIVATE $ ) target_compile_definitions(${TARGET_NAME} PUBLIC STACK_LINE_READER_BUFFER_SIZE=1024 ) endmacro() set(PROCESSOR_IS_MIPS FALSE) set(PROCESSOR_IS_ARM FALSE) set(PROCESSOR_IS_AARCH64 FALSE) set(PROCESSOR_IS_X86 FALSE) set(PROCESSOR_IS_POWER FALSE) set(PROCESSOR_IS_S390X FALSE) set(PROCESSOR_IS_RISCV FALSE) set(PROCESSOR_IS_LOONGARCH FALSE) if(CMAKE_SYSTEM_PROCESSOR MATCHES "^mips") set(PROCESSOR_IS_MIPS TRUE) elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(^aarch64)|(^arm64)|(^ARM64)") set(PROCESSOR_IS_AARCH64 TRUE) elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm") set(PROCESSOR_IS_ARM TRUE) elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(x86_64)|(AMD64|amd64)|(^i.86$)") set(PROCESSOR_IS_X86 TRUE) elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)") set(PROCESSOR_IS_POWER TRUE) elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(s390x)") set(PROCESSOR_IS_S390X TRUE) elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^riscv") set(PROCESSOR_IS_RISCV TRUE) elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^loongarch") set(PROCESSOR_IS_LOONGARCH TRUE) endif() macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpu_features_macros.h) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpu_features_cache_info.h) file(GLOB IMPL_SOURCES CONFIGURE_DEPENDS "${PROJECT_SOURCE_DIR}/src/impl_*.c") list(APPEND ${SRCS_LIST_NAME} ${IMPL_SOURCES}) if(PROCESSOR_IS_MIPS) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_mips.h) elseif(PROCESSOR_IS_ARM) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_arm.h) elseif(PROCESSOR_IS_AARCH64) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_aarch64.h) list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/internal/windows_utils.h) elseif(PROCESSOR_IS_X86) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_x86.h) list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/internal/cpuid_x86.h) list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/internal/windows_utils.h) elseif(PROCESSOR_IS_POWER) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_ppc.h) elseif(PROCESSOR_IS_S390X) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_s390x.h) elseif(PROCESSOR_IS_RISCV) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_riscv.h) elseif(PROCESSOR_IS_LOONGARCH) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_loongarch.h) else() message(FATAL_ERROR "Unsupported architectures ${CMAKE_SYSTEM_PROCESSOR}") endif() endmacro() # # library : utils # add_library(utils OBJECT ${PROJECT_SOURCE_DIR}/include/internal/bit_utils.h ${PROJECT_SOURCE_DIR}/include/internal/filesystem.h ${PROJECT_SOURCE_DIR}/include/internal/stack_line_reader.h ${PROJECT_SOURCE_DIR}/include/internal/string_view.h ${PROJECT_SOURCE_DIR}/src/filesystem.c ${PROJECT_SOURCE_DIR}/src/stack_line_reader.c ${PROJECT_SOURCE_DIR}/src/string_view.c ) setup_include_and_definitions(utils) # # library : unix_based_hardware_detection # if(UNIX) add_library(unix_based_hardware_detection OBJECT ${PROJECT_SOURCE_DIR}/include/internal/hwcaps.h ${PROJECT_SOURCE_DIR}/src/hwcaps.c ) setup_include_and_definitions(unix_based_hardware_detection) check_include_file(dlfcn.h HAVE_DLFCN_H) if(HAVE_DLFCN_H) target_compile_definitions(unix_based_hardware_detection PRIVATE HAVE_DLFCN_H) endif() check_symbol_exists(getauxval "sys/auxv.h" HAVE_STRONG_GETAUXVAL) if(HAVE_STRONG_GETAUXVAL) target_compile_definitions(unix_based_hardware_detection PRIVATE HAVE_STRONG_GETAUXVAL) endif() endif() # # library : cpu_features # set (CPU_FEATURES_HDRS) set (CPU_FEATURES_SRCS) add_cpu_features_headers_and_sources(CPU_FEATURES_HDRS CPU_FEATURES_SRCS) list(APPEND CPU_FEATURES_SRCS $) if(NOT PROCESSOR_IS_X86 AND UNIX) list(APPEND CPU_FEATURES_SRCS $) endif() add_library(cpu_features ${CPU_FEATURES_HDRS} ${CPU_FEATURES_SRCS}) set_target_properties(cpu_features PROPERTIES PUBLIC_HEADER "${CPU_FEATURES_HDRS}") setup_include_and_definitions(cpu_features) target_link_libraries(cpu_features PUBLIC ${CMAKE_DL_LIBS}) target_include_directories(cpu_features PUBLIC $ ) if(APPLE) target_compile_definitions(cpu_features PRIVATE HAVE_SYSCTLBYNAME) endif() add_library(CpuFeatures::cpu_features ALIAS cpu_features) # # program : list_cpu_features # if(BUILD_EXECUTABLE) add_executable(list_cpu_features ${PROJECT_SOURCE_DIR}/src/utils/list_cpu_features.c) target_link_libraries(list_cpu_features PRIVATE cpu_features) add_executable(CpuFeatures::list_cpu_features ALIAS list_cpu_features) endif() # # ndk_compat # if(ANDROID) add_subdirectory(ndk_compat) endif() # # tests # include(CTest) if(BUILD_TESTING) # Automatically incorporate googletest into the CMake Project if target not # found. enable_language(CXX) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # prefer use of -std14 instead of -gnustd14 if(NOT TARGET gtest OR NOT TARGET gmock_main) # Download and unpack googletest at configure time. configure_file( cmake/googletest.CMakeLists.txt.in googletest-download/CMakeLists.txt ) execute_process( COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . RESULT_VARIABLE result WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download) if(result) message(FATAL_ERROR "CMake step for googletest failed: ${result}") endif() execute_process( COMMAND ${CMAKE_COMMAND} --build . RESULT_VARIABLE result WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download) if(result) message(FATAL_ERROR "Build step for googletest failed: ${result}") endif() # Prevent overriding the parent project's compiler/linker settings on # Windows. set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) # Add googletest directly to our build. This defines the gtest and # gtest_main targets. add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src ${CMAKE_BINARY_DIR}/googletest-build EXCLUDE_FROM_ALL) endif() add_subdirectory(test) endif() # # Install cpu_features and list_cpu_features # if(ENABLE_INSTALL) include(GNUInstallDirs) install(TARGETS cpu_features EXPORT CpuFeaturesTargets PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/cpu_features ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} ) if(BUILD_EXECUTABLE) install(TARGETS list_cpu_features EXPORT CpuFeaturesTargets PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/cpu_features ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} ) endif() install(EXPORT CpuFeaturesTargets NAMESPACE CpuFeatures:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeatures COMPONENT Devel ) include(CMakePackageConfigHelpers) configure_package_config_file(cmake/CpuFeaturesConfig.cmake.in "${PROJECT_BINARY_DIR}/CpuFeaturesConfig.cmake" INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeatures" NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO ) write_basic_package_version_file( "${PROJECT_BINARY_DIR}/CpuFeaturesConfigVersion.cmake" COMPATIBILITY SameMajorVersion ) install( FILES "${PROJECT_BINARY_DIR}/CpuFeaturesConfig.cmake" "${PROJECT_BINARY_DIR}/CpuFeaturesConfigVersion.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeatures" COMPONENT Devel ) endif() cpu-features-0.9.0/CONTRIBUTING.md000066400000000000000000000017111450057454500163650ustar00rootroot00000000000000# How to Contribute We'd love to accept your patches and contributions to this project. There are just a few small guidelines you need to follow. ## Contributor License Agreement Contributions to this project must be accompanied by a Contributor License Agreement. You (or your employer) retain the copyright to your contribution; this simply gives us permission to use and redistribute your contributions as part of the project. Head over to to see your current agreements on file or to sign a new one. You generally only need to submit a CLA once, so if you've already submitted one (even if it was for a different project), you probably don't need to do it again. ## Code reviews All submissions, including submissions by project members, require review. We use GitHub pull requests for this purpose. Consult [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more information on using pull requests. cpu-features-0.9.0/LICENSE000066400000000000000000000311141450057454500151410ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. -------------------------------------------------------------------------------- For files in the `ndk_compat` folder: -------------------------------------------------------------------------------- Copyright (C) 2010 The Android Open Source Project All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. cpu-features-0.9.0/README.md000066400000000000000000000357371450057454500154320ustar00rootroot00000000000000# cpu_features A cross-platform C library to retrieve CPU features (such as available instructions) at runtime. # GitHub-CI Status [comment]: <> (The following lines are generated by "scripts/generate_badges.d" that you can run online https://run.dlang.io/) | | Linux | FreeBSD | MacOS | Windows | | :-- | --: | --: | --: | --: | | amd64 | [![CMake][i1a0]][l1a0]
[![Bazel][i1a1]][l1a1] | [![CMake][i2a0]][l2a0]
![Bazel][d1] | [![CMake][i3a0]][l3a0]
[![Bazel][i3a1]][l3a1] | [![CMake][i4a0]][l4a0]
![Bazel][d1] | | AArch64 | [![CMake][i1b0]][l1b0]
[![Bazel][i1b1]][l1b1] | ![CMake][d0]
![Bazel][d1] | ![CMake][d0]
![Bazel][d1] | ![CMake][d0]
![Bazel][d1] | | ARM | [![CMake][i1c0]][l1c0]
![Bazel][d1] | ![CMake][d0]
![Bazel][d1] | ![CMake][d0]
![Bazel][d1] | ![CMake][d0]
![Bazel][d1] | | MIPS | [![CMake][i1d0]][l1d0]
![Bazel][d1] | ![CMake][d0]
![Bazel][d1] | ![CMake][d0]
![Bazel][d1] | ![CMake][d0]
![Bazel][d1] | | POWER | [![CMake][i1e0]][l1e0]
![Bazel][d1] | ![CMake][d0]
![Bazel][d1] | ![CMake][d0]
![Bazel][d1] | ![CMake][d0]
![Bazel][d1] | | RISCV | [![CMake][i1f0]][l1f0]
![Bazel][d1] | ![CMake][d0]
![Bazel][d1] | ![CMake][d0]
![Bazel][d1] | ![CMake][d0]
![Bazel][d1] | | LOONGARCH | ![CMake][d0]
![Bazel][d1] | ![CMake][d0]
![Bazel][d1] | ![CMake][d0]
![Bazel][d1] | ![CMake][d0]
![Bazel][d1] | | s390x | [![CMake][i1h0]][l1h0]
![Bazel][d1] | ![CMake][d0]
![Bazel][d1] | ![CMake][d0]
![Bazel][d1] | ![CMake][d0]
![Bazel][d1] | [d0]: https://img.shields.io/badge/n%2Fa-lightgrey?&logo=cmake [d1]: https://img.shields.io/badge/n%2Fa-lightgrey?&logo=data:image/svg%2bxml;base64,PHN2ZyByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNiAuMTZsNS43ODYgNS43ODZMNiAxMS43MzIuMjE0IDUuOTQ2IDYgLjE2MXpNMCA2LjIxNFYxMmw1Ljc4NiA1Ljc4NlYxMkwwIDYuMjE0ek0xOCAuMTZsNS43ODYgNS43ODZMMTggMTEuNzMybC01Ljc4Ni01Ljc4NkwxOCAuMTYxek0yNCA2LjIxNFYxMmwtNS43ODYgNS43ODZWMTJMMjQgNi4yMTR6TTEyIDYuMTZsNS43ODYgNS43ODZMMTIgMTcuNzMybC01Ljc4Ni01Ljc4NkwxMiA2LjE2MXpNMTEuODQgMTguMDU0djUuNzg1bC01Ljc4Ni01Ljc4NXYtNS43ODZsNS43ODUgNS43ODZ6TTEyLjE2IDE4LjA1NGw1Ljc4Ni01Ljc4NnY1Ljc4NmwtNS43ODUgNS43ODV2LTUuNzg1eiIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgZmlsbD0id2hpdGUiLz48L3N2Zz4= [i1a0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_linux_cmake.yml?branch=main&event=push&label=&logo=cmake [i1a1]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_linux_bazel.yml?branch=main&event=push&label=&logo=data:image/svg%2bxml;base64,PHN2ZyByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNiAuMTZsNS43ODYgNS43ODZMNiAxMS43MzIuMjE0IDUuOTQ2IDYgLjE2MXpNMCA2LjIxNFYxMmw1Ljc4NiA1Ljc4NlYxMkwwIDYuMjE0ek0xOCAuMTZsNS43ODYgNS43ODZMMTggMTEuNzMybC01Ljc4Ni01Ljc4NkwxOCAuMTYxek0yNCA2LjIxNFYxMmwtNS43ODYgNS43ODZWMTJMMjQgNi4yMTR6TTEyIDYuMTZsNS43ODYgNS43ODZMMTIgMTcuNzMybC01Ljc4Ni01Ljc4NkwxMiA2LjE2MXpNMTEuODQgMTguMDU0djUuNzg1bC01Ljc4Ni01Ljc4NXYtNS43ODZsNS43ODUgNS43ODZ6TTEyLjE2IDE4LjA1NGw1Ljc4Ni01Ljc4NnY1Ljc4NmwtNS43ODUgNS43ODV2LTUuNzg1eiIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgZmlsbD0id2hpdGUiLz48L3N2Zz4= [i1b0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/aarch64_linux_cmake.yml?branch=main&event=push&label=&logo=cmake [i1b1]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/aarch64_linux_bazel.yml?branch=main&event=push&label=&logo=data:image/svg%2bxml;base64,PHN2ZyByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNiAuMTZsNS43ODYgNS43ODZMNiAxMS43MzIuMjE0IDUuOTQ2IDYgLjE2MXpNMCA2LjIxNFYxMmw1Ljc4NiA1Ljc4NlYxMkwwIDYuMjE0ek0xOCAuMTZsNS43ODYgNS43ODZMMTggMTEuNzMybC01Ljc4Ni01Ljc4NkwxOCAuMTYxek0yNCA2LjIxNFYxMmwtNS43ODYgNS43ODZWMTJMMjQgNi4yMTR6TTEyIDYuMTZsNS43ODYgNS43ODZMMTIgMTcuNzMybC01Ljc4Ni01Ljc4NkwxMiA2LjE2MXpNMTEuODQgMTguMDU0djUuNzg1bC01Ljc4Ni01Ljc4NXYtNS43ODZsNS43ODUgNS43ODZ6TTEyLjE2IDE4LjA1NGw1Ljc4Ni01Ljc4NnY1Ljc4NmwtNS43ODUgNS43ODV2LTUuNzg1eiIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgZmlsbD0id2hpdGUiLz48L3N2Zz4= [i1c0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/arm_linux_cmake.yml?branch=main&event=push&label=&logo=cmake [i1d0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/mips_linux_cmake.yml?branch=main&event=push&label=&logo=cmake [i1e0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/power_linux_cmake.yml?branch=main&event=push&label=&logo=cmake [i1f0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/riscv_linux_cmake.yml?branch=main&event=push&label=&logo=cmake [i1h0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/s390x_linux_cmake.yml?branch=main&event=push&label=&logo=cmake [i2a0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_freebsd_cmake.yml?branch=main&event=push&label=&logo=cmake [i3a0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_macos_cmake.yml?branch=main&event=push&label=&logo=cmake [i3a1]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_macos_bazel.yml?branch=main&event=push&label=&logo=data:image/svg%2bxml;base64,PHN2ZyByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNiAuMTZsNS43ODYgNS43ODZMNiAxMS43MzIuMjE0IDUuOTQ2IDYgLjE2MXpNMCA2LjIxNFYxMmw1Ljc4NiA1Ljc4NlYxMkwwIDYuMjE0ek0xOCAuMTZsNS43ODYgNS43ODZMMTggMTEuNzMybC01Ljc4Ni01Ljc4NkwxOCAuMTYxek0yNCA2LjIxNFYxMmwtNS43ODYgNS43ODZWMTJMMjQgNi4yMTR6TTEyIDYuMTZsNS43ODYgNS43ODZMMTIgMTcuNzMybC01Ljc4Ni01Ljc4NkwxMiA2LjE2MXpNMTEuODQgMTguMDU0djUuNzg1bC01Ljc4Ni01Ljc4NXYtNS43ODZsNS43ODUgNS43ODZ6TTEyLjE2IDE4LjA1NGw1Ljc4Ni01Ljc4NnY1Ljc4NmwtNS43ODUgNS43ODV2LTUuNzg1eiIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgZmlsbD0id2hpdGUiLz48L3N2Zz4= [i4a0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_windows_cmake.yml?branch=main&event=push&label=&logo=cmake [l1a0]: https://github.com/google/cpu_features/actions/workflows/amd64_linux_cmake.yml [l1a1]: https://github.com/google/cpu_features/actions/workflows/amd64_linux_bazel.yml [l1b0]: https://github.com/google/cpu_features/actions/workflows/aarch64_linux_cmake.yml [l1b1]: https://github.com/google/cpu_features/actions/workflows/aarch64_linux_bazel.yml [l1c0]: https://github.com/google/cpu_features/actions/workflows/arm_linux_cmake.yml [l1d0]: https://github.com/google/cpu_features/actions/workflows/mips_linux_cmake.yml [l1e0]: https://github.com/google/cpu_features/actions/workflows/power_linux_cmake.yml [l1f0]: https://github.com/google/cpu_features/actions/workflows/riscv_linux_cmake.yml [l1h0]: https://github.com/google/cpu_features/actions/workflows/s390x_linux_cmake.yml [l2a0]: https://github.com/google/cpu_features/actions/workflows/amd64_freebsd_cmake.yml [l3a0]: https://github.com/google/cpu_features/actions/workflows/amd64_macos_cmake.yml [l3a1]: https://github.com/google/cpu_features/actions/workflows/amd64_macos_bazel.yml [l4a0]: https://github.com/google/cpu_features/actions/workflows/amd64_windows_cmake.yml ## Table of Contents - [Design Rationale](#rationale) - [Code samples](#codesample) - [Running sample code](#usagesample) - [What's supported](#support) - [Android NDK's drop in replacement](#ndk) - [License](#license) - [Build with cmake](#cmake) - [Community Bindings](#bindings) ## Design Rationale - **Simple to use.** See the snippets below for examples. - **Extensible.** Easy to add missing features or architectures. - **Compatible with old compilers** and available on many architectures so it can be used widely. To ensure that cpu_features works on as many platforms as possible, we implemented it in a highly portable version of C: C99. - **Sandbox-compatible.** The library uses a variety of strategies to cope with sandboxed environments or when `cpuid` is unavailable. This is useful when running integration tests in hermetic environments. - **Thread safe, no memory allocation, and raises no exceptions.** cpu_features is suitable for implementing fundamental libc functions like `malloc`, `memcpy`, and `memcmp`. - **Unit tested.** ## Code samples **Note:** For C++ code, the library functions are defined in the `cpu_features` namespace. ### Checking features at runtime Here's a simple example that executes a codepath if the CPU supports both the AES and the SSE4.2 instruction sets: ```c #include "cpuinfo_x86.h" // For C++, add `using namespace cpu_features;` static const X86Features features = GetX86Info().features; void Compute(void) { if (features.aes && features.sse4_2) { // Run optimized code. } else { // Run standard code. } } ``` ### Caching for faster evaluation of complex checks If you wish, you can read all the features at once into a global variable, and then query for the specific features you care about. Below, we store all the ARM features and then check whether AES and NEON are supported. ```c #include #include "cpuinfo_arm.h" // For C++, add `using namespace cpu_features;` static const ArmFeatures features = GetArmInfo().features; static const bool has_aes_and_neon = features.aes && features.neon; // use has_aes_and_neon. ``` This is a good approach to take if you're checking for combinations of features when using a compiler that is slow to extract individual bits from bit-packed structures. ### Checking compile time flags The following code determines whether the compiler was told to use the AVX instruction set (e.g., `g++ -mavx`) and sets `has_avx` accordingly. ```c #include #include "cpuinfo_x86.h" // For C++, add `using namespace cpu_features;` static const X86Features features = GetX86Info().features; static const bool has_avx = CPU_FEATURES_COMPILED_X86_AVX || features.avx; // use has_avx. ``` `CPU_FEATURES_COMPILED_X86_AVX` is set to 1 if the compiler was instructed to use AVX and 0 otherwise, combining compile time and runtime knowledge. ### Rejecting poor hardware implementations based on microarchitecture On x86, the first incarnation of a feature in a microarchitecture might not be the most efficient (e.g. AVX on Sandy Bridge). We provide a function to retrieve the underlying microarchitecture so you can decide whether to use it. Below, `has_fast_avx` is set to 1 if the CPU supports the AVX instruction set—but only if it's not Sandy Bridge. ```c #include #include "cpuinfo_x86.h" // For C++, add `using namespace cpu_features;` static const X86Info info = GetX86Info(); static const X86Microarchitecture uarch = GetX86Microarchitecture(&info); static const bool has_fast_avx = info.features.avx && uarch != INTEL_SNB; // use has_fast_avx. ``` 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 arch : x86 brand : Intel(R) Xeon(R) CPU E5-1650 0 @ 3.20GHz family : 6 (0x06) model : 45 (0x2D) stepping : 7 (0x07) uarch : INTEL_SNB flags : aes,avx,cx16,smx,sse4_1,sse4_2,ssse3 ``` ```shell % ./build/list_cpu_features --json {"arch":"x86","brand":" Intel(R) Xeon(R) CPU E5-1650 0 @ 3.20GHz","family":6,"model":45,"stepping":7,"uarch":"INTEL_SNB","flags":["aes","avx","cx16","smx","sse4_1","sse4_2","ssse3"]} ``` ## What's supported | | x86³ | AArch64 | ARM | MIPS⁴ | POWER | RISCV | Loongarch | s390x | |---------|:----:|:-------:|:-------:|:-------:|:-------:|:-------:|:---------:|:-------:| | Linux | yes² | yes¹ | yes¹ | yes¹ | yes¹ | yes¹ | yes¹ | yes¹ | | FreeBSD | yes² | not yet | not yet | not yet | not yet | N/A | not yet | not yet | | MacOs | yes² | yes⁵ | N/A | N/A | N/A | N/A | N/A | N/A | | Windows | yes² | not yet | not yet | N/A | N/A | N/A | N/A | N/A | | Android | yes² | yes¹ | yes¹ | yes¹ | N/A | N/A | N/A | N/A | | iOS | N/A | not yet | not yet | N/A | N/A | N/A | N/A | N/A | 1. **Features revealed from Linux.** We gather data from several sources depending on availability: + from glibc's [getauxval](https://www.gnu.org/software/libc/manual/html_node/Auxiliary-Vector.html) + by parsing `/proc/self/auxv` + by parsing `/proc/cpuinfo` 2. **Features revealed from CPU.** features are retrieved by using the `cpuid` instruction. 3. **Microarchitecture detection.** On x86 some features are not always implemented efficiently in hardware (e.g. AVX on Sandybridge). Exposing the microarchitecture allows the client to reject particular microarchitectures. 4. All flavors of Mips are supported, little and big endian as well as 32/64 bits. 5. **Features revealed from sysctl.** features are retrieved by the `sysctl` instruction. ## Android NDK's drop in replacement [cpu_features](https://github.com/google/cpu_features) is now officially supporting Android and offers a drop in replacement of for the NDK's [cpu-features.h](https://android.googlesource.com/platform/ndk/+/main/sources/android/cpufeatures/cpu-features.h) , see [ndk_compat](ndk_compat) folder for details. ## License The cpu_features library is licensed under the terms of the Apache license. See [LICENSE](LICENSE) for more information. ## Build with CMake Please check the [CMake build instructions](cmake/README.md). ### Quickstart - Run `list_cpu_features` ```sh cmake -S. -Bbuild -DBUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=Release cmake --build build --config Release -j ./build/list_cpu_features --json ``` _Note_: Use `--target ALL_BUILD` on the second line for `Visual Studio` and `XCode`. - run tests ```sh cmake -S. -Bbuild -DBUILD_TESTING=ON -DCMAKE_BUILD_TYPE=Debug cmake --build build --config Debug -j cmake --build build --config Debug --target test ``` _Note_: Use `--target RUN_TESTS` on the last line for `Visual Studio` and `--target RUN_TEST` for `XCode`. - install `cpu_features` ```sh cmake --build build --config Release --target install -v ``` _Note_: Use `--target INSTALL` for `Visual Studio`. _Note_: When using `Makefile` or `XCode` generator, you can use [`DESTDIR`](https://www.gnu.org/software/make/manual/html_node/DESTDIR.html) to install on a local repository.
e.g. ```sh cmake --build build --config Release --target install -v -- DESTDIR=install ``` ## Community bindings Links provided here are not affiliated with Google but are kindly provided by the OSS Community. - .Net - https://github.com/toor1245/cpu_features.NET - Python - https://github.com/Narasimha1997/py_cpu - Java - https://github.com/aecsocket/cpu-features-java _Send PR to showcase your wrapper here_ cpu-features-0.9.0/WORKSPACE000066400000000000000000000007311450057454500154160ustar00rootroot00000000000000workspace(name = "com_google_cpufeatures") load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") git_repository( name = "com_google_googletest", tag = "release-1.11.0", remote = "https://github.com/google/googletest.git", ) git_repository( name = "bazel_skylib", tag = "1.2.0", remote = "https://github.com/bazelbuild/bazel-skylib.git", ) load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") bazel_skylib_workspace() cpu-features-0.9.0/bazel/000077500000000000000000000000001450057454500152315ustar00rootroot00000000000000cpu-features-0.9.0/bazel/ci/000077500000000000000000000000001450057454500156245ustar00rootroot00000000000000cpu-features-0.9.0/bazel/ci/Makefile000066400000000000000000000071601450057454500172700ustar00rootroot00000000000000PROJECT := cpu_features BRANCH := $(shell git rev-parse --abbrev-ref HEAD) SHA1 := $(shell git rev-parse --verify HEAD) # General commands .PHONY: help BOLD=\e[1m RESET=\e[0m help: @echo -e "${BOLD}SYNOPSIS${RESET}" @echo -e "\tmake [NOCACHE=1]" @echo @echo -e "${BOLD}DESCRIPTION${RESET}" @echo -e "\ttest build inside docker container to have a reproductible build." @echo @echo -e "${BOLD}MAKE TARGETS${RESET}" @echo -e "\t${BOLD}help${RESET}: display this help and exit." @echo @echo -e "\t${BOLD}_${RESET}: build docker image using an Ubuntu:latest x86_64 base image." @echo -e "\t${BOLD}save__${RESET}: Save the docker image." @echo -e "\t${BOLD}sh__${RESET}: run a container using the docker image (debug purpose)." @echo -e "\t${BOLD}clean__${RESET}: Remove cache and docker image." @echo @echo -e "\tWith ${BOLD}${RESET}:" @echo -e "\t\t${BOLD}amd64${RESET} (linux/amd64)" @echo -e "\t\t${BOLD}arm64${RESET} (linux/arm64)" @echo @echo -e "\tWith ${BOLD}${RESET}:" @echo -e "\t\t${BOLD}env${RESET}" @echo -e "\t\t${BOLD}devel${RESET}" @echo -e "\t\t${BOLD}build${RESET}" @echo -e "\t\t${BOLD}test${RESET}" @echo -e "\te.g. 'make amd64_build'" @echo @echo -e "\t${BOLD}clean${RESET}: Remove cache and ALL docker images." @echo @echo -e "\t${BOLD}NOCACHE=1${RESET}: use 'docker build --no-cache' when building container (default use cache)." @echo -e "\t${BOLD}VERBOSE=1${RESET}: use 'docker build --progress=plain' when building container." @echo @echo -e "branch: $(BRANCH)" @echo -e "sha1: $(SHA1)" # Need to add cmd_platform to PHONY otherwise target are ignored since they do not # contain recipe (using FORCE do not work here) .PHONY: all all: build # Delete all implicit rules to speed up makefile MAKEFLAGS += --no-builtin-rules .SUFFIXES: # Remove some rules from gmake that .SUFFIXES does not remove. SUFFIXES = # Keep all intermediate files # ToDo: try to remove it later .SECONDARY: # Docker image name prefix. IMAGE := ${PROJECT} DOCKER_BUILDX_CMD := docker buildx build ifdef NOCACHE DOCKER_BUILDX_CMD := ${DOCKER_BUILDX_CMD} --no-cache endif ifdef VERBOSE DOCKER_BUILDX_CMD := ${DOCKER_BUILDX_CMD} --progress=plain endif DOCKER_RUN_CMD := docker run --rm --init --net=host ############ ## NATIVE ## ############ # ref: https://go.dev/doc/install/source#environment # ref: https://github.com/containerd/containerd/blob/269548fa27e0089a8b8278fc4fc781d7f65a939b/platforms/platforms.go#L80-L94 PLATFORMS := amd64 arm64 STAGES := env devel build test define make-platform-stage-target = $1_$2: docker/Dockerfile ${DOCKER_BUILDX_CMD} \ --platform linux/$1 \ --build-arg PLATFORM="$1" \ --target=$2 \ --tag ${IMAGE}:$1_$2 \ -f $$< ../.. save_$1_$2: cache/$1/docker_$2.tar cache/$1/docker_$2.tar: $1_$2 @rm -f $$@ mkdir -p cache/$1 docker save ${IMAGE}:$1_$2 -o $$@ sh_$1_$2: $1_$2 ${DOCKER_RUN_CMD} --platform linux/$1 -it --name ${IMAGE}_$1_$2 ${IMAGE}:$1_$2 clean_$1_$2: docker image rm -f ${IMAGE}:$1_$2 2>/dev/null rm -f cache/$1/docker_$2.tar endef define make-platform-target = $(foreach stage,$(STAGES),$(eval $(call make-platform-stage-target,$1,$(stage)))) # merge .PHONY: clean_$1 clean_$1: $(addprefix clean_$1_, $(STAGES)) -rmdir cache/$1 endef $(foreach platform,$(PLATFORMS),$(eval $(call make-platform-target,$(platform)))) ## MERGE ## .PHONY: clean clean: $(addprefix clean_, $(PLATFORMS)) docker container prune -f docker image prune -f -rmdir cache .PHONY: distclean distclean: clean -docker container rm -f $$(docker container ls -aq) -docker image rm -f $$(docker image ls -aq) cpu-features-0.9.0/bazel/ci/README.md000066400000000000000000000001241450057454500171000ustar00rootroot00000000000000## Usage To build tests with bazel ```sh bazel test -s --verbose_failures //... ``` cpu-features-0.9.0/bazel/ci/docker/000077500000000000000000000000001450057454500170735ustar00rootroot00000000000000cpu-features-0.9.0/bazel/ci/docker/Dockerfile000066400000000000000000000015621450057454500210710ustar00rootroot00000000000000# Create a virtual environment with all tools installed # ref: https://hub.docker.com/_/ubuntu FROM ubuntu:latest AS env # Install system build dependencies ENV PATH=/usr/local/bin:$PATH RUN apt-get update -qq \ && DEBIAN_FRONTEND=noninteractive apt-get install -yq \ git wget build-essential \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* ENTRYPOINT ["/usr/bin/bash", "-c"] CMD ["/usr/bin/bash"] # Install Bazelisk ARG PLATFORM RUN wget \ "https://github.com/bazelbuild/bazelisk/releases/download/v1.18.0/bazelisk-linux-${PLATFORM}" \ && chmod +x "bazelisk-linux-${PLATFORM}" \ && mv "bazelisk-linux-${PLATFORM}" /usr/local/bin/bazel FROM env AS devel WORKDIR /home/project COPY . . FROM devel AS build RUN bazel version RUN bazel build \ -c opt \ --subcommands=true \ ... FROM build AS test RUN bazel test \ -c opt \ --test_output=errors \ ... cpu-features-0.9.0/bazel/platforms.bzl000066400000000000000000000006671450057454500177620ustar00rootroot00000000000000"""Defines global variables that lists target cpus""" PLATFORM_CPU_X86_64 = ("@platforms//cpu:x86_64") PLATFORM_CPU_ARM = ("@platforms//cpu:arm") PLATFORM_CPU_ARM64 = ("@platforms//cpu:arm64") PLATFORM_CPU_MIPS = ("@platforms//cpu:mips64") PLATFORM_CPU_PPC = ("@platforms//cpu:ppc") PLATFORM_CPU_RISCV32 = ("@platforms//cpu:riscv32") PLATFORM_CPU_RISCV64 = ("@platforms//cpu:riscv64") PLATFORM_OS_MACOS = ("@platforms//os:macos") cpu-features-0.9.0/cmake/000077500000000000000000000000001450057454500152145ustar00rootroot00000000000000cpu-features-0.9.0/cmake/CpuFeaturesConfig.cmake.in000066400000000000000000000001461450057454500222000ustar00rootroot00000000000000# CpuFeatures CMake configuration file include("${CMAKE_CURRENT_LIST_DIR}/CpuFeaturesTargets.cmake") cpu-features-0.9.0/cmake/CpuFeaturesNdkCompatConfig.cmake.in000066400000000000000000000001701450057454500237760ustar00rootroot00000000000000# CpuFeaturesNdkCompat CMake configuration file include("${CMAKE_CURRENT_LIST_DIR}/CpuFeaturesNdkCompatTargets.cmake") cpu-features-0.9.0/cmake/README.md000066400000000000000000000020211450057454500164660ustar00rootroot00000000000000# CMake build instructions ## Recommended usage : Incorporating cpu_features into a CMake project For API / ABI compatibility reasons, it is recommended to build and use cpu_features in a subdirectory of your project or as an embedded dependency. This is similar to the recommended usage of the googletest framework ( https://github.com/google/googletest/blob/main/googletest/README.md ) Build and use step-by-step 1- Download cpu_features and copy it in a sub-directory in your project. or add cpu_features as a git-submodule in your project 2- You can then use the cmake command `add_subdirectory()` to include cpu_features directly and use the `cpu_features` target in your project. 3- Add the `CpuFeatures::cpu_features` target to the `target_link_libraries()` section of your executable or of your library. ## Disabling tests CMake default options for cpu_features is `Release` built type with tests enabled. To disable testing set cmake `BUILD_TESTING` variable to `OFF`. e.g. ```sh cmake -S. -Bbuild -DBUILD_TESTING=OFF ``` cpu-features-0.9.0/cmake/ci/000077500000000000000000000000001450057454500156075ustar00rootroot00000000000000cpu-features-0.9.0/cmake/ci/Makefile000066400000000000000000000217511450057454500172550ustar00rootroot00000000000000PROJECT := cpu_features BRANCH := $(shell git rev-parse --abbrev-ref HEAD) SHA1 := $(shell git rev-parse --verify HEAD) # General commands .PHONY: help BOLD=\e[1m RESET=\e[0m help: @echo -e "${BOLD}SYNOPSIS${RESET}" @echo -e "\tmake [NOCACHE=1]" @echo @echo -e "${BOLD}DESCRIPTION${RESET}" @echo -e "\ttest build inside docker container to have a reproductible build." @echo @echo -e "${BOLD}MAKE TARGETS${RESET}" @echo -e "\t${BOLD}help${RESET}: display this help and exit." @echo @echo -e "\t${BOLD}amd64_${RESET}: build docker image using an Ubuntu:latest x86_64 base image." @echo -e "\t${BOLD}save_amd64_${RESET}: Save the docker image." @echo -e "\t${BOLD}sh_amd64_${RESET}: run a container using the docker image (debug purpose)." @echo -e "\t${BOLD}clean_amd64_${RESET}: Remove cache and docker image." @echo @echo -e "\tWith ${BOLD}${RESET}:" @echo -e "\t\t${BOLD}env${RESET}" @echo -e "\t\t${BOLD}devel${RESET}" @echo -e "\t\t${BOLD}build${RESET}" @echo -e "\t\t${BOLD}test${RESET}" @echo -e "\t\t${BOLD}install_env${RESET}" @echo -e "\t\t${BOLD}install_devel${RESET}" @echo -e "\t\t${BOLD}install_build${RESET}" @echo -e "\t\t${BOLD}install_test${RESET}" @echo -e "\te.g. 'make amd64_build'" @echo @echo -e "\t${BOLD}_${RESET}: build docker image for a specific toolchain target." @echo -e "\t${BOLD}save__${RESET}: Save the docker image for a specific platform." @echo -e "\t${BOLD}sh__${RESET}: run a container using the docker image specified (debug purpose)." @echo -e "\t${BOLD}clean__${RESET}: Remove cache and docker image." @echo @echo -e "\tWith ${BOLD}${RESET}:" @echo -e "\t\t${BOLD}arm-linux-gnueabihf${RESET} (linaro toolchain)" @echo -e "\t\t${BOLD}armv8l-linux-gnueabihf${RESET} (linaro toolchain)" @echo -e "\t\t${BOLD}arm-linux-gnueabi${RESET} (linaro toolchain)" @echo -e "\t\t${BOLD}armeb-linux-gnueabihf${RESET} (linaro toolchain)" @echo -e "\t\t${BOLD}armeb-linux-gnueabi${RESET} (linaro toolchain)" @echo -e "\t\t${BOLD}aarch64-linux-gnu${RESET} (linaro toolchain)" @echo -e "\t\t${BOLD}aarch64${RESET} (bootlin toolchain)" @echo -e "\t\t${BOLD}aarch64_be-linux-gnu${RESET} (linaro toolchain)" @echo -e "\t\t${BOLD}aarch64be${RESET} (bootlin toolchain)" @echo -e "\t\t${BOLD}mips32${RESET} (codespace toolchain)" @echo -e "\t\t${BOLD}mips64${RESET} (codespace toolchain)" @echo -e "\t\t${BOLD}mips32el${RESET} (codespace toolchain)" @echo -e "\t\t${BOLD}mips64el${RESET} (codespace toolchain)" @echo -e "\t\t${BOLD}ppc${RESET} (bootlin toolchain)" @echo -e "\t\t${BOLD}ppc64${RESET} (bootlin toolchain)" @echo -e "\t\t${BOLD}ppc64le${RESET} (bootlin toolchain)" @echo -e "\t\t${BOLD}riscv32${RESET} (bootlin toolchain)" @echo -e "\t\t${BOLD}riscv64${RESET} (bootlin toolchain)" @echo -e "\t\t${BOLD}s390x${RESET} (bootlin toolchain)" @echo @echo -e "\tWith ${BOLD}${RESET}:" @echo -e "\t\t${BOLD}env${RESET}" @echo -e "\t\t${BOLD}devel${RESET}" @echo -e "\t\t${BOLD}build${RESET}" @echo -e "\t\t${BOLD}test${RESET}" @echo -e "\te.g. 'make aarch64_test'" @echo @echo -e "\t${BOLD}${RESET}: build the vagrant virtual machine." @echo -e "\t${BOLD}clean_${RESET}: Remove virtual machine for the specified vm." @echo @echo -e "\t${BOLD}${RESET}:" @echo -e "\t\t${BOLD}freebsd${RESET} (FreeBSD)" @echo @echo -e "\t${BOLD}clean${RESET}: Remove cache and ALL docker images." @echo @echo -e "\t${BOLD}NOCACHE=1${RESET}: use 'docker build --no-cache' when building container (default use cache)." @echo @echo -e "branch: $(BRANCH)" @echo -e "sha1: $(SHA1)" # Need to add cmd_platform to PHONY otherwise target are ignored since they do not # contain recipe (using FORCE do not work here) .PHONY: all all: build # Delete all implicit rules to speed up makefile MAKEFLAGS += --no-builtin-rules .SUFFIXES: # Remove some rules from gmake that .SUFFIXES does not remove. SUFFIXES = # Keep all intermediate files # ToDo: try to remove it later .SECONDARY: # Docker image name prefix. IMAGE := ${PROJECT} ifdef NOCACHE DOCKER_BUILD_CMD := docker build --no-cache else DOCKER_BUILD_CMD := docker build endif DOCKER_RUN_CMD := docker run --rm --init --net=host # $* stem # $< first prerequist # $@ target name ############ ## NATIVE ## ############ STAGES = env devel build test install_env install_devel install_build install_test targets_amd64 = $(addprefix amd64_, $(STAGES)) .PHONY: $(targets_amd64) $(targets_amd64): amd64_%: docker/amd64/Dockerfile #@docker image rm -f ${IMAGE}:amd64_$* 2>/dev/null ${DOCKER_BUILD_CMD} \ --tag ${IMAGE}:amd64_$* \ --target=$* \ -f $< \ ../.. #$(info Create targets: save_amd64 $(addprefix save_amd64_, $(STAGES)) (debug).) save_targets_amd64 = $(addprefix save_amd64_, $(STAGES)) .PHONY: $(save_targets_amd64) $(save_targets_amd64): save_amd64_%: cache/amd64/docker_%.tar cache/amd64/docker_%.tar: amd64_% @rm -f $@ mkdir -p cache/amd64 docker save ${IMAGE}:amd64_$* -o $@ #$(info Create targets: $(addprefix sh_amd64_, $(STAGES)) (debug).) sh_targets_amd64 = $(addprefix sh_amd64_, $(STAGES)) .PHONY: $(sh_targets_amd64) $(sh_targets_amd64): sh_amd64_%: amd64_% ${DOCKER_RUN_CMD} -it --name ${IMAGE}_amd64_$* ${IMAGE}:amd64_$* #$(info Create targets: $(addprefix clean_amd64_, $(STAGES)).) clean_targets_amd64 = $(addprefix clean_amd64_, $(STAGES)) .PHONY: clean_amd64 $(clean_targets_amd64) clean_amd64: $(clean_targets_amd64) $(clean_targets_amd64): clean_amd64_%: docker image rm -f ${IMAGE}:amd64_$* 2>/dev/null rm -f cache/amd64/docker_$*.tar ############### ## TOOLCHAIN ## ############### TOOLCHAIN_TARGETS = \ aarch64 aarch64be \ arm-linux-gnueabihf armv8l-linux-gnueabihf arm-linux-gnueabi armeb-linux-gnueabihf armeb-linux-gnueabi \ aarch64-linux-gnu aarch64_be-linux-gnu \ mips32 mips32el mips64 mips64el \ ppc ppc64 ppc64le \ riscv32 riscv64 \ s390x TOOLCHAIN_STAGES = env devel build test define toolchain-stage-target = #$$(info STAGE: $1) #$$(info Create targets: toolchain_$1 $(addsuffix _$1, $(TOOLCHAIN_TARGETS)).) targets_toolchain_$1 = $(addsuffix _$1, $(TOOLCHAIN_TARGETS)) .PHONY: toolchain_$1 $$(targets_toolchain_$1) toolchain_$1: $$(targets_toolchain_$1) $$(targets_toolchain_$1): %_$1: docker/toolchain/Dockerfile #@docker image rm -f ${IMAGE}:$$*_$1 2>/dev/null ${DOCKER_BUILD_CMD} \ --tag ${IMAGE}:$$*_$1 \ --build-arg TARGET=$$* \ --target=$1 \ -f $$< \ ../.. #$$(info Create targets: save_toolchain_$1 $(addprefix save_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS))) (debug).) save_targets_toolchain_$1 = $(addprefix save_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS))) .PHONY: save_toolchain_$1 $$(save_targets_toolchain_$1) save_toolchain_$1: $$(save_targets_toolchain_$1) $$(save_targets_toolchain_$1): save_%_$1: cache/%/docker_$1.tar cache/%/docker_$1.tar: %_$1 @rm -f $$@ mkdir -p cache/$$* docker save ${IMAGE}:$$*_$1 -o $$@ #$$(info Create targets: $(addprefix sh_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS))) (debug).) sh_targets_toolchain_$1 = $(addprefix sh_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS))) .PHONY: $$(sh_targets_toolchain_$1) $$(sh_targets_toolchain_$1): sh_%_$1: %_$1 ${DOCKER_RUN_CMD} -it --name ${IMAGE}_$$*_$1 ${IMAGE}:$$*_$1 #$$(info Create targets: clean_toolchain_$1 $(addprefix clean_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS))).) clean_targets_toolchain_$1 = $(addprefix clean_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS))) .PHONY: clean_toolchain_$1 $$(clean_targets_toolchain_$1) clean_toolchain_$1: $$(clean_targets_toolchain_$1) $$(clean_targets_toolchain_$1): clean_%_$1: docker image rm -f ${IMAGE}:$$*_$1 2>/dev/null rm -f cache/$$*/docker_$1.tar endef $(foreach stage,$(TOOLCHAIN_STAGES),$(eval $(call toolchain-stage-target,$(stage)))) ## MERGE ## .PHONY: clean_toolchain clean_toolchain: $(addprefix clean_toolchain_, $(TOOLCHAIN_STAGES)) -rmdir $(addprefix cache/, $(TOOLCHAIN_TARGETS)) .PHONY: env devel build test env: amd64_env toolchain_env devel: amd64_devel toolchain_devel build: amd64_build toolchain_build test: amd64_test toolchain_test .PHONY: install_env install_devel install_build install_test install_env: amd64_install_env install_devel: amd64_install_devel install_build: amd64_install_build install_test: amd64_install_test ############# ## VAGRANT ## ############# VMS = freebsd vms_targets = $(addsuffix _build, $(VMS)) .PHONY: $(vms_targets) $(vms_targets): %_build: vagrant/%/Vagrantfile @cd vagrant/$* && vagrant destroy -f cd vagrant/$* && vagrant up clean_vms_targets = $(addprefix clean_, $(VMS)) .PHONY: clean_vms $(clean_vms_targets) clean_vms: $(clean_vms_targets) $(clean_vms_targets): clean_%: cd vagrant/$* && vagrant destroy -f -rm -rf vagrant/$*/.vagrant ########### ## CLEAN ## ########### .PHONY: clean clean: clean_amd64 clean_toolchain clean_vms docker container prune -f docker image prune -f -rmdir cache .PHONY: distclean distclean: clean -docker container rm -f $$(docker container ls -aq) -docker image rm -f $$(docker image ls -aq) -vagrant box remove -f generic/freebsd12 cpu-features-0.9.0/cmake/ci/README.md000066400000000000000000000017071450057454500170730ustar00rootroot00000000000000## Makefile/Docker testing To test the build on various distro, we are using docker containers and a Makefile for orchestration. pros: * You are independent of third party CI runner config (e.g. [github action virtual-environnments](https://github.com/actions/virtual-environments)). * You can run it locally on your linux system. * Most CI provide runners with docker and Makefile installed. cons: * Only GNU/Linux distro supported. ### Usage To get the help simply type: ```sh make ``` note: you can also use from top directory ```sh make --directory=cmake/ci ``` ### Example For example to test mips32 inside an container: ```sh make mips32_test ``` ### Docker layers Dockerfile is splitted in several stages. ![docker](doc/docker.svg) ## Makefile/Vagrant testing To test build for FreeBSD we are using Vagrant and VirtualBox box. This is similar to the docker stuff but use `vagrant` as `docker` cli and VirtuaBox to replace the docker engine daemon. cpu-features-0.9.0/cmake/ci/doc/000077500000000000000000000000001450057454500163545ustar00rootroot00000000000000cpu-features-0.9.0/cmake/ci/doc/docker.dot000066400000000000000000000051221450057454500203330ustar00rootroot00000000000000@startdot digraph DockerDeps { //rankdir=BT; rankdir=TD; node [shape=cylinder, style="rounded,filled", color=black, fillcolor=royalblue]; DISTRO_IMG [label="ubuntu:latest"]; PKG [label="packages\ne.g. cmake, g++", shape=box3d]; SRC [label="git repo", shape=folder]; SPL [label="sample", shape=folder]; subgraph clusterDockerfile { ENV_IMG [label="cpu_features:amd64_env\nenv"]; DEVEL_IMG [label="cpu_features:amd64_devel\ndevel"]; BUILD_IMG [label="cpu_features:amd64_build\nbuild"]; TEST_IMG [label="cpu_features:amd64_test\ntest"]; INSTALL_ENV_IMG [label="cpu_features:amd64_install_env\ninstall_env"]; INSTALL_DEVEL_IMG [label="cpu_features:amd64_install_devel\ninstall_devel"]; INSTALL_BUILD_IMG [label="cpu_features:amd64_install_build\ninstall_build"]; INSTALL_TEST_IMG [label="cpu_features:amd64_install_test\ninstall_test"]; ENV_IMG -> DEVEL_IMG; DEVEL_IMG -> BUILD_IMG; BUILD_IMG -> TEST_IMG; ENV_IMG -> INSTALL_ENV_IMG; BUILD_IMG -> INSTALL_ENV_IMG [label="copy install", style="dashed"]; INSTALL_ENV_IMG -> INSTALL_DEVEL_IMG; SPL -> INSTALL_DEVEL_IMG [label="copy", style="dashed"]; INSTALL_DEVEL_IMG -> INSTALL_BUILD_IMG; INSTALL_BUILD_IMG -> INSTALL_TEST_IMG; color=royalblue; label = "docker/amd64/Dockerfile"; } DISTRO_IMG -> ENV_IMG; PKG -> ENV_IMG [label="install", style="dashed"]; SRC -> DEVEL_IMG [label="copy", style="dashed"]; subgraph clusterCache { node [shape=note, style="rounded,filled", color=black, fillcolor=royalblue]; ENV_TAR [label="docker_amd64_env.tar"]; DEVEL_TAR [label="docker_amd64_devel.tar"]; BUILD_TAR [label="docker_amd64_build.tar"]; TEST_TAR [label="docker_amd64_test.tar"]; INSTALL_ENV_TAR [label="docker_amd64_install_env.tar"]; INSTALL_DEVEL_TAR [label="docker_amd64_install_devel.tar"]; INSTALL_BUILD_TAR [label="docker_amd64_install_build.tar"]; INSTALL_TEST_TAR [label="docker_amd64_install_test.tar"]; edge [color=red]; ENV_IMG -> ENV_TAR [label="make save_amd64_env"]; DEVEL_IMG -> DEVEL_TAR [label="make save_amd64_devel"]; BUILD_IMG -> BUILD_TAR [label="make save_amd64_build"]; TEST_IMG -> TEST_TAR [label="make save_amd64_test"]; INSTALL_ENV_IMG -> INSTALL_ENV_TAR [label="make save_amd64_install_env"]; INSTALL_DEVEL_IMG -> INSTALL_DEVEL_TAR [label="make save_amd64_install_devel"]; INSTALL_BUILD_IMG -> INSTALL_BUILD_TAR [label="make save_amd64_install_build"]; INSTALL_TEST_IMG -> INSTALL_TEST_TAR [label="make save_amd64_install_test"]; color=royalblue; label = "cache/amd64/"; } } @enddot cpu-features-0.9.0/cmake/ci/doc/docker.svg000066400000000000000000000515531450057454500203550ustar00rootroot00000000000000 DockerDeps clusterDockerfile docker/amd64/Dockerfile clusterCache cache/amd64/ DISTRO_IMG ubuntu:latest ENV_IMG cpu_features:amd64_env env DISTRO_IMG->ENV_IMG PKG packages e.g. cmake, g++ PKG->ENV_IMG install SRC git repo DEVEL_IMG cpu_features:amd64_devel devel SRC->DEVEL_IMG copy SPL sample INSTALL_DEVEL_IMG cpu_features:amd64_install_devel install_devel SPL->INSTALL_DEVEL_IMG copy ENV_IMG->DEVEL_IMG INSTALL_ENV_IMG cpu_features:amd64_install_env install_env ENV_IMG->INSTALL_ENV_IMG ENV_TAR docker_amd64_env.tar ENV_IMG->ENV_TAR make save_amd64_env BUILD_IMG cpu_features:amd64_build build DEVEL_IMG->BUILD_IMG DEVEL_TAR docker_amd64_devel.tar DEVEL_IMG->DEVEL_TAR make save_amd64_devel TEST_IMG cpu_features:amd64_test test BUILD_IMG->TEST_IMG BUILD_IMG->INSTALL_ENV_IMG copy install BUILD_TAR docker_amd64_build.tar BUILD_IMG->BUILD_TAR make save_amd64_build TEST_TAR docker_amd64_test.tar TEST_IMG->TEST_TAR make save_amd64_test INSTALL_ENV_IMG->INSTALL_DEVEL_IMG INSTALL_ENV_TAR docker_amd64_install_env.tar INSTALL_ENV_IMG->INSTALL_ENV_TAR make save_amd64_install_env INSTALL_BUILD_IMG cpu_features:amd64_install_build install_build INSTALL_DEVEL_IMG->INSTALL_BUILD_IMG INSTALL_DEVEL_TAR docker_amd64_install_devel.tar INSTALL_DEVEL_IMG->INSTALL_DEVEL_TAR make save_amd64_install_devel INSTALL_TEST_IMG cpu_features:amd64_install_test install_test INSTALL_BUILD_IMG->INSTALL_TEST_IMG INSTALL_BUILD_TAR docker_amd64_install_build.tar INSTALL_BUILD_IMG->INSTALL_BUILD_TAR make save_amd64_install_build INSTALL_TEST_TAR docker_amd64_install_test.tar INSTALL_TEST_IMG->INSTALL_TEST_TAR make save_amd64_install_test cpu-features-0.9.0/cmake/ci/doc/generate_image.sh000077500000000000000000000001421450057454500216440ustar00rootroot00000000000000#!/usr/bin/env bash set -ex rm -f ./*.svg ./*.png for i in *.dot; do plantuml -Tsvg "$i"; done cpu-features-0.9.0/cmake/ci/docker/000077500000000000000000000000001450057454500170565ustar00rootroot00000000000000cpu-features-0.9.0/cmake/ci/docker/amd64/000077500000000000000000000000001450057454500177715ustar00rootroot00000000000000cpu-features-0.9.0/cmake/ci/docker/amd64/Dockerfile000066400000000000000000000025541450057454500217710ustar00rootroot00000000000000# Create a virtual environment with all tools installed # ref: https://hub.docker.com/_/ubuntu FROM ubuntu:latest AS env LABEL maintainer="corentinl@google.com" # Install system build dependencies ENV PATH=/usr/local/bin:$PATH RUN apt-get update -qq \ && DEBIAN_FRONTEND=noninteractive apt-get install -yq git wget libssl-dev build-essential \ ninja-build python3 pkgconf libglib2.0-dev \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* ENTRYPOINT ["/usr/bin/bash", "-c"] CMD ["/usr/bin/bash"] # Install CMake 3.21.3 RUN wget "https://cmake.org/files/v3.21/cmake-3.21.3-linux-x86_64.sh" \ && chmod a+x cmake-3.21.3-linux-x86_64.sh \ && ./cmake-3.21.3-linux-x86_64.sh --prefix=/usr/local/ --skip-license \ && rm cmake-3.21.3-linux-x86_64.sh FROM env AS devel WORKDIR /home/project COPY . . FROM devel AS build RUN cmake -version RUN cmake -S. -Bbuild RUN cmake --build build --target all -v RUN cmake --build build --target install -v FROM build AS test ENV CTEST_OUTPUT_ON_FAILURE=1 RUN cmake --build build --target test -v # Test install rules FROM env AS install_env COPY --from=build /usr/local /usr/local/ FROM install_env AS install_devel WORKDIR /home/sample COPY cmake/ci/sample . FROM install_devel AS install_build RUN cmake -S. -Bbuild RUN cmake --build build --target all -v FROM install_build AS install_test RUN cmake --build build --target test cpu-features-0.9.0/cmake/ci/docker/toolchain/000077500000000000000000000000001450057454500210365ustar00rootroot00000000000000cpu-features-0.9.0/cmake/ci/docker/toolchain/Dockerfile000066400000000000000000000020051450057454500230250ustar00rootroot00000000000000# Create a virtual environment with all tools installed # ref: https://hub.docker.com/_/ubuntu FROM ubuntu:latest AS env LABEL maintainer="corentinl@google.com" # Install system build dependencies ENV PATH=/usr/local/bin:$PATH RUN apt-get update -qq \ && DEBIAN_FRONTEND=noninteractive apt-get install -yq git wget libssl-dev build-essential \ ninja-build python3 pkgconf libglib2.0-dev \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* ENTRYPOINT ["/usr/bin/bash", "-c"] CMD ["/usr/bin/bash"] # Install CMake 3.21.3 RUN wget "https://cmake.org/files/v3.21/cmake-3.21.3-linux-x86_64.sh" \ && chmod a+x cmake-3.21.3-linux-x86_64.sh \ && ./cmake-3.21.3-linux-x86_64.sh --prefix=/usr/local/ --skip-license \ && rm cmake-3.21.3-linux-x86_64.sh FROM env AS devel WORKDIR /home/project COPY . . ARG TARGET ENV TARGET ${TARGET:-unknown} FROM devel AS build RUN cmake -version RUN ./scripts/run_integration.sh build FROM build AS test RUN ./scripts/run_integration.sh qemu RUN ./scripts/run_integration.sh test cpu-features-0.9.0/cmake/ci/sample/000077500000000000000000000000001450057454500170705ustar00rootroot00000000000000cpu-features-0.9.0/cmake/ci/sample/CMakeLists.txt000066400000000000000000000011001450057454500216200ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.15) project(Sample VERSION 1.0.0 LANGUAGES CXX) include(CTest) find_package(CpuFeatures REQUIRED) add_executable(sample main.cpp) target_compile_features(sample PUBLIC cxx_std_11) set_target_properties(sample PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED ON VERSION ${PROJECT_VERSION}) target_link_libraries(sample PRIVATE CpuFeatures::cpu_features) if(BUILD_TESTING) add_test(NAME sample_test COMMAND sample) endif() include(GNUInstallDirs) install(TARGETS sample EXPORT SampleTargets DESTINATION ${CMAKE_INSTALL_BIN_DIR}) cpu-features-0.9.0/cmake/ci/sample/main.cpp000066400000000000000000000003351450057454500205210ustar00rootroot00000000000000#include #include "cpuinfo_x86.h" using namespace cpu_features; int main(int /*argc*/, char** /*argv*/) { static const X86Features features = GetX86Info().features; std::cout << std::endl; return 0; } cpu-features-0.9.0/cmake/ci/vagrant/000077500000000000000000000000001450057454500172515ustar00rootroot00000000000000cpu-features-0.9.0/cmake/ci/vagrant/freebsd/000077500000000000000000000000001450057454500206635ustar00rootroot00000000000000cpu-features-0.9.0/cmake/ci/vagrant/freebsd/Vagrantfile000066400000000000000000000102621450057454500230510ustar00rootroot00000000000000# -*- mode: ruby -*- # vi: set ft=ruby : # All Vagrant configuration is done below. The "2" in Vagrant.configure # configures the configuration version (we support older styles for # backwards compatibility). Please don't change it unless you know what # you're doing. Vagrant.configure("2") do |config| # The most common configuration options are documented and commented below. # For a complete reference, please see the online documentation at # https://docs.vagrantup.com. # Every Vagrant development environment requires a box. You can search for # boxes at https://vagrantcloud.com/search. config.vm.guest = :freebsd config.vm.box = "generic/freebsd12" config.ssh.shell = "sh" # Disable automatic box update checking. If you disable this, then # boxes will only be checked for updates when the user runs # `vagrant box outdated`. This is not recommended. # config.vm.box_check_update = false # Create a forwarded port mapping which allows access to a specific port # within the machine from a port on the host machine. In the example below, # accessing "localhost:8080" will access port 80 on the guest machine. # NOTE: This will enable public access to the opened port # config.vm.network "forwarded_port", guest: 80, host: 8080 # Create a forwarded port mapping which allows access to a specific port # within the machine from a port on the host machine and only allow access # via 127.0.0.1 to disable public access # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1" # Create a private network, which allows host-only access to the machine # using a specific IP. # config.vm.network "private_network", ip: "192.168.33.10" # Create a public network, which generally matched to bridged network. # Bridged networks make the machine appear as another physical device on # your network. # config.vm.network "public_network" # Share an additional folder to the guest VM. The first argument is # the path on the host to the actual folder. The second argument is # the path on the guest to mount the folder. And the optional third # argument is a set of non-required options. #config.vm.synced_folder "../../..", "/home/vagrant/project" config.vm.synced_folder ".", "/vagrant", id: "vagrant-root", disabled: true config.vm.provision "file", source: "../../../../CMakeLists.txt", destination: "$HOME/project/" config.vm.provision "file", source: "../../../../cmake", destination: "$HOME/project/" config.vm.provision "file", source: "../../../../include", destination: "$HOME/project/" config.vm.provision "file", source: "../../../../src", destination: "$HOME/project/" config.vm.provision "file", source: "../../../../test", destination: "$HOME/project/" # Provider-specific configuration so you can fine-tune various # backing providers for Vagrant. These expose provider-specific options. # Example for VirtualBox: # # config.vm.provider "virtualbox" do |vb| # # Display the VirtualBox GUI when booting the machine # vb.gui = true # # # Customize the amount of memory on the VM: # vb.memory = "1024" # end # # View the documentation for the provider you are using for more # information on available options. # Enable provisioning with a shell script. Additional provisioners such as # Ansible, Chef, Docker, Puppet and Salt are also available. Please see the # documentation for more information about their specific syntax and use. # note: clang installed by default config.vm.provision "env", type: "shell", inline:<<-SHELL set -x pkg update -f pkg install -y git cmake SHELL config.vm.provision "devel", type: "shell", inline:<<-SHELL set -x cd project ls SHELL config.vm.provision "configure", type: "shell", inline:<<-SHELL set -x cd project cmake -S. -Bbuild -DBUILD_TESTING=ON SHELL config.vm.provision "build", type: "shell", inline:<<-SHELL set -x cd project cmake --build build -v SHELL config.vm.provision "test", type: "shell", inline:<<-SHELL set -x cd project cmake --build build --target test -v SHELL config.vm.provision "test", type: "shell", inline:<<-SHELL set -x cd project cmake --build build --target install -v SHELL end cpu-features-0.9.0/cmake/googletest.CMakeLists.txt.in000066400000000000000000000006511450057454500225360ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8.2) project(googletest-download NONE) include(ExternalProject) ExternalProject_Add(googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG main SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src" BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" TEST_COMMAND "" )cpu-features-0.9.0/include/000077500000000000000000000000001450057454500155575ustar00rootroot00000000000000cpu-features-0.9.0/include/cpu_features_cache_info.h000066400000000000000000000032351450057454500225560ustar00rootroot00000000000000// 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. // 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. #ifndef CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_ #define CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_ #include "cpu_features_macros.h" CPU_FEATURES_START_CPP_NAMESPACE typedef enum { CPU_FEATURE_CACHE_NULL = 0, CPU_FEATURE_CACHE_DATA = 1, CPU_FEATURE_CACHE_INSTRUCTION = 2, CPU_FEATURE_CACHE_UNIFIED = 3, CPU_FEATURE_CACHE_TLB = 4, CPU_FEATURE_CACHE_DTLB = 5, CPU_FEATURE_CACHE_STLB = 6, CPU_FEATURE_CACHE_PREFETCH = 7 } CacheType; typedef struct { int level; CacheType cache_type; int cache_size; // Cache size in bytes int ways; // Associativity, 0 undefined, 0xFF fully associative int line_size; // Cache line size in bytes int tlb_entries; // number of entries for TLB int partitioning; // number of lines per sector } CacheLevelInfo; // Increase this value if more cache levels are needed. #ifndef CPU_FEATURES_MAX_CACHE_LEVEL #define CPU_FEATURES_MAX_CACHE_LEVEL 10 #endif typedef struct { int size; CacheLevelInfo levels[CPU_FEATURES_MAX_CACHE_LEVEL]; } CacheInfo; CPU_FEATURES_END_CPP_NAMESPACE #endif // CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_ cpu-features-0.9.0/include/cpu_features_macros.h000066400000000000000000000243661450057454500217740ustar00rootroot00000000000000// 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. // 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. #ifndef CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_ #define CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_ //////////////////////////////////////////////////////////////////////////////// // Architectures //////////////////////////////////////////////////////////////////////////////// #if defined(__pnacl__) || defined(__CLR_VER) #define CPU_FEATURES_ARCH_VM #endif #if (defined(_M_IX86) || defined(__i386__)) && !defined(CPU_FEATURES_ARCH_VM) #define CPU_FEATURES_ARCH_X86_32 #endif #if (defined(_M_X64) || defined(__x86_64__)) && !defined(CPU_FEATURES_ARCH_VM) #define CPU_FEATURES_ARCH_X86_64 #endif #if defined(CPU_FEATURES_ARCH_X86_32) || defined(CPU_FEATURES_ARCH_X86_64) #define CPU_FEATURES_ARCH_X86 #endif #if (defined(__arm__) || defined(_M_ARM)) #define CPU_FEATURES_ARCH_ARM #endif #if (defined(__aarch64__) || defined(_M_ARM64)) #define CPU_FEATURES_ARCH_AARCH64 #endif #if (defined(CPU_FEATURES_ARCH_AARCH64) || defined(CPU_FEATURES_ARCH_ARM)) #define CPU_FEATURES_ARCH_ANY_ARM #endif #if defined(__mips64) #define CPU_FEATURES_ARCH_MIPS64 #endif #if defined(__mips__) && !defined(__mips64) // mips64 also declares __mips__ #define CPU_FEATURES_ARCH_MIPS32 #endif #if defined(CPU_FEATURES_ARCH_MIPS32) || defined(CPU_FEATURES_ARCH_MIPS64) #define CPU_FEATURES_ARCH_MIPS #endif #if defined(__powerpc__) #define CPU_FEATURES_ARCH_PPC #endif #if defined(__s390x__) #define CPU_FEATURES_ARCH_S390X #endif #if defined(__riscv) #define CPU_FEATURES_ARCH_RISCV #endif #if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 32 #define CPU_FEATURES_ARCH_RISCV32 #endif #if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64 #define CPU_FEATURES_ARCH_RISCV64 #endif #if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 128 #define CPU_FEATURES_ARCH_RISCV128 #endif #if defined(__loongarch64) #define CPU_FEATURES_ARCH_LOONGARCH #endif //////////////////////////////////////////////////////////////////////////////// // Os //////////////////////////////////////////////////////////////////////////////// #if (defined(__freebsd__) || defined(__FreeBSD__)) #define CPU_FEATURES_OS_FREEBSD #endif #if defined(__ANDROID__) #define CPU_FEATURES_OS_ANDROID #endif #if defined(__linux__) && !defined(CPU_FEATURES_OS_FREEBSD) && \ !defined(CPU_FEATURES_OS_ANDROID) #define CPU_FEATURES_OS_LINUX #endif #if (defined(_WIN64) || defined(_WIN32)) #define CPU_FEATURES_OS_WINDOWS #endif #if (defined(__apple__) || defined(__APPLE__) || defined(__MACH__)) // From https://stackoverflow.com/a/49560690 #include "TargetConditionals.h" #if defined(TARGET_OS_OSX) #define CPU_FEATURES_OS_MACOS #endif #if defined(TARGET_OS_IPHONE) // This is set for any non-Mac Apple products (IOS, TV, WATCH) #define CPU_FEATURES_OS_IPHONE #endif #endif //////////////////////////////////////////////////////////////////////////////// // Compilers //////////////////////////////////////////////////////////////////////////////// #if defined(__clang__) #define CPU_FEATURES_COMPILER_CLANG #endif #if defined(__GNUC__) && !defined(__clang__) #define CPU_FEATURES_COMPILER_GCC #endif #if defined(_MSC_VER) #define CPU_FEATURES_COMPILER_MSC #endif //////////////////////////////////////////////////////////////////////////////// // Cpp //////////////////////////////////////////////////////////////////////////////// #if defined(__cplusplus) #define CPU_FEATURES_START_CPP_NAMESPACE \ namespace cpu_features { \ extern "C" { #define CPU_FEATURES_END_CPP_NAMESPACE \ } \ } #else #define CPU_FEATURES_START_CPP_NAMESPACE #define CPU_FEATURES_END_CPP_NAMESPACE #endif //////////////////////////////////////////////////////////////////////////////// // Compiler flags //////////////////////////////////////////////////////////////////////////////// // Use the following to check if a feature is known to be available at // compile time. See README.md for an example. #if defined(CPU_FEATURES_ARCH_X86) #if defined(__AES__) #define CPU_FEATURES_COMPILED_X86_AES 1 #else #define CPU_FEATURES_COMPILED_X86_AES 0 #endif // defined(__AES__) #if defined(__F16C__) #define CPU_FEATURES_COMPILED_X86_F16C 1 #else #define CPU_FEATURES_COMPILED_X86_F16C 0 #endif // defined(__F16C__) #if defined(__BMI__) #define CPU_FEATURES_COMPILED_X86_BMI 1 #else #define CPU_FEATURES_COMPILED_X86_BMI 0 #endif // defined(__BMI__) #if defined(__BMI2__) #define CPU_FEATURES_COMPILED_X86_BMI2 1 #else #define CPU_FEATURES_COMPILED_X86_BMI2 0 #endif // defined(__BMI2__) #if (defined(__SSE__) || (_M_IX86_FP >= 1)) #define CPU_FEATURES_COMPILED_X86_SSE 1 #else #define CPU_FEATURES_COMPILED_X86_SSE 0 #endif #if (defined(__SSE2__) || (_M_IX86_FP >= 2)) #define CPU_FEATURES_COMPILED_X86_SSE2 1 #else #define CPU_FEATURES_COMPILED_X86_SSE2 0 #endif #if defined(__SSE3__) #define CPU_FEATURES_COMPILED_X86_SSE3 1 #else #define CPU_FEATURES_COMPILED_X86_SSE3 0 #endif // defined(__SSE3__) #if defined(__SSSE3__) #define CPU_FEATURES_COMPILED_X86_SSSE3 1 #else #define CPU_FEATURES_COMPILED_X86_SSSE3 0 #endif // defined(__SSSE3__) #if defined(__SSE4_1__) #define CPU_FEATURES_COMPILED_X86_SSE4_1 1 #else #define CPU_FEATURES_COMPILED_X86_SSE4_1 0 #endif // defined(__SSE4_1__) #if defined(__SSE4_2__) #define CPU_FEATURES_COMPILED_X86_SSE4_2 1 #else #define CPU_FEATURES_COMPILED_X86_SSE4_2 0 #endif // defined(__SSE4_2__) #if defined(__AVX__) #define CPU_FEATURES_COMPILED_X86_AVX 1 #else #define CPU_FEATURES_COMPILED_X86_AVX 0 #endif // defined(__AVX__) #if defined(__AVX2__) #define CPU_FEATURES_COMPILED_X86_AVX2 1 #else #define CPU_FEATURES_COMPILED_X86_AVX2 0 #endif // defined(__AVX2__) #endif // defined(CPU_FEATURES_ARCH_X86) #if defined(CPU_FEATURES_ARCH_ANY_ARM) #if defined(__ARM_NEON__) #define CPU_FEATURES_COMPILED_ANY_ARM_NEON 1 #else #define CPU_FEATURES_COMPILED_ANY_ARM_NEON 0 #endif // defined(__ARM_NEON__) #endif // defined(CPU_FEATURES_ARCH_ANY_ARM) #if defined(CPU_FEATURES_ARCH_MIPS) #if defined(__mips_msa) #define CPU_FEATURES_COMPILED_MIPS_MSA 1 #else #define CPU_FEATURES_COMPILED_MIPS_MSA 0 #endif // defined(__mips_msa) #if defined(__mips3d) #define CPU_FEATURES_COMPILED_MIPS_MIPS3D 1 #else #define CPU_FEATURES_COMPILED_MIPS_MIPS3D 0 #endif #endif // defined(CPU_FEATURES_ARCH_MIPS) #if defined(CPU_FEATURES_ARCH_RISCV) #if defined(__riscv_e) #define CPU_FEATURES_COMPILED_RISCV_E 1 #else #define CPU_FEATURES_COMPILED_RISCV_E 0 #endif #if defined(__riscv_i) #define CPU_FEATURES_COMPILED_RISCV_I 1 #else #define CPU_FEATURES_COMPILED_RISCV_I 0 #endif #if defined(__riscv_m) #define CPU_FEATURES_COMPILED_RISCV_M 1 #else #define CPU_FEATURES_COMPILED_RISCV_M 0 #endif #if defined(__riscv_a) #define CPU_FEATURES_COMPILED_RISCV_A 1 #else #define CPU_FEATURES_COMPILED_RISCV_A 0 #endif #if defined(__riscv_f) #define CPU_FEATURES_COMPILED_RISCV_F 1 #else #define CPU_FEATURES_COMPILED_RISCV_F 0 #endif #if defined(__riscv_d) #define CPU_FEATURES_COMPILED_RISCV_D 1 #else #define CPU_FEATURES_COMPILED_RISCV_D 0 #endif #if defined(__riscv_q) #define CPU_FEATURES_COMPILED_RISCV_Q 1 #else #define CPU_FEATURES_COMPILED_RISCV_Q 0 #endif #if defined(__riscv_c) #define CPU_FEATURES_COMPILED_RISCV_C 1 #else #define CPU_FEATURES_COMPILED_RISCV_C 0 #endif #if defined(__riscv_v) #define CPU_FEATURES_COMPILED_RISCV_V 1 #else #define CPU_FEATURES_COMPILED_RISCV_V 0 #endif #if defined(__riscv_zba) #define CPU_FEATURES_COMPILED_RISCV_ZBA 1 #else #define CPU_FEATURES_COMPILED_RISCV_ZBA 0 #endif #if defined(__riscv_zbb) #define CPU_FEATURES_COMPILED_RISCV_ZBB 1 #else #define CPU_FEATURES_COMPILED_RISCV_ZBB 0 #endif #if defined(__riscv_zbc) #define CPU_FEATURES_COMPILED_RISCV_ZBC 1 #else #define CPU_FEATURES_COMPILED_RISCV_ZBC 0 #endif #if defined(__riscv_zbs) #define CPU_FEATURES_COMPILED_RISCV_ZBS 1 #else #define CPU_FEATURES_COMPILED_RISCV_ZBS 0 #endif #if defined(__riscv_zfh) #define CPU_FEATURES_COMPILED_RISCV_ZFH 1 #else #define CPU_FEATURES_COMPILED_RISCV_ZFH 0 #endif #if defined(__riscv_zfhmin) #define CPU_FEATURES_COMPILED_RISCV_ZFHMIN 1 #else #define CPU_FEATURES_COMPILED_RISCV_ZFHMIN 0 #endif #if defined(__riscv_zknd) #define CPU_FEATURES_COMPILED_RISCV_ZKND 1 #else #define CPU_FEATURES_COMPILED_RISCV_ZKND 0 #endif #if defined(__riscv_zkne) #define CPU_FEATURES_COMPILED_RISCV_ZKNE 1 #else #define CPU_FEATURES_COMPILED_RISCV_ZKNE 0 #endif #if defined(__riscv_zknh) #define CPU_FEATURES_COMPILED_RISCV_ZKNH 1 #else #define CPU_FEATURES_COMPILED_RISCV_ZKNH 0 #endif #if defined(__riscv_zksed) #define CPU_FEATURES_COMPILED_RISCV_ZKSED 1 #else #define CPU_FEATURES_COMPILED_RISCV_ZKSED 0 #endif #if defined(__riscv_zksh) #define CPU_FEATURES_COMPILED_RISCV_ZKSH 1 #else #define CPU_FEATURES_COMPILED_RISCV_ZKSH 0 #endif #if defined(__riscv_zkr) #define CPU_FEATURES_COMPILED_RISCV_ZKR 1 #else #define CPU_FEATURES_COMPILED_RISCV_ZKR 0 #endif #endif // defined(CPU_FEATURES_ARCH_RISCV) //////////////////////////////////////////////////////////////////////////////// // Utils //////////////////////////////////////////////////////////////////////////////// // Communicates to the compiler that the block is unreachable #if defined(CPU_FEATURES_COMPILER_CLANG) || defined(CPU_FEATURES_COMPILER_GCC) #define CPU_FEATURES_UNREACHABLE() __builtin_unreachable() #elif defined(CPU_FEATURES_COMPILER_MSC) #define CPU_FEATURES_UNREACHABLE() __assume(0) #else #define CPU_FEATURES_UNREACHABLE() #endif // Communicates to the compiler that the function is now deprecated #if defined(CPU_FEATURES_COMPILER_CLANG) || defined(CPU_FEATURES_COMPILER_GCC) #define CPU_FEATURES_DEPRECATED(message) __attribute__((deprecated(message))) #elif defined(CPU_FEATURES_COMPILER_MSC) #define CPU_FEATURES_DEPRECATED(message) __declspec(deprecated(message)) #else #define CPU_FEATURES_DEPRECATED(message) #endif #endif // CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_ cpu-features-0.9.0/include/cpuinfo_aarch64.h000066400000000000000000000274231450057454500207130ustar00rootroot00000000000000// 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. // 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. //////////////////////////////////////////////////////////////////////////////// // A note on Windows AArch64 implementation //////////////////////////////////////////////////////////////////////////////// // Getting cpu info via EL1 system registers is not possible, so we delegate it // to the Windows API (i.e., IsProcessorFeaturePresent and GetNativeSystemInfo). // The `implementer`, `variant` and `part` fields of the `Aarch64Info` struct // are not used, so they are set to 0. To get `revision` we use // `wProcessorRevision` from `SYSTEM_INFO`. // // Cryptographic Extension: // ----------------------------------------------------------------------------- // According to documentation Arm Architecture Reference Manual for // A-profile architecture. A2.3 The Armv8 Cryptographic Extension. The Armv8.0 // Cryptographic Extension provides instructions for the acceleration of // encryption and decryption, and includes the following features: FEAT_AES, // FEAT_PMULL, FEAT_SHA1, FEAT_SHA256. // see: https://developer.arm.com/documentation/ddi0487/latest // // We use `PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE` to detect all Armv8.0 crypto // features. This value reports all features or nothing, so even if you only // have support FEAT_AES and FEAT_PMULL, it will still return false. // // From Armv8.2, an implementation of the Armv8.0 Cryptographic Extension can // include either or both of: // // • The AES functionality, including support for multiplication of 64-bit // polynomials. The ID_AA64ISAR0_EL1.AES field indicates whether this // functionality is supported. // • The SHA1 and SHA2-256 functionality. The ID_AA64ISAR0_EL1.{SHA2, SHA1} // fields indicate whether this functionality is supported. // // ID_AA64ISAR0_EL1.AES, bits [7:4]: // Indicates support for AES instructions in AArch64 state. Defined values are: // - 0b0000 No AES instructions implemented. // - 0b0001 AESE, AESD, AESMC, and AESIMC instructions implemented. // - 0b0010 As for 0b0001, plus PMULL/PMULL2 instructions operating on 64-bit // data quantities. // // FEAT_AES implements the functionality identified by the value 0b0001. // FEAT_PMULL implements the functionality identified by the value 0b0010. // From Armv8, the permitted values are 0b0000 and 0b0010. // // ID_AA64ISAR0_EL1.SHA1, bits [11:8]: // Indicates support for SHA1 instructions in AArch64 state. Defined values are: // - 0b0000 No SHA1 instructions implemented. // - 0b0001 SHA1C, SHA1P, SHA1M, SHA1H, SHA1SU0, and SHA1SU1 instructions // implemented. // // FEAT_SHA1 implements the functionality identified by the value 0b0001. // From Armv8, the permitted values are 0b0000 and 0b0001. // If the value of ID_AA64ISAR0_EL1.SHA2 is 0b0000, this field must have the // value 0b0000. // // ID_AA64ISAR0_EL1.SHA2, bits [15:12]: // Indicates support for SHA2 instructions in AArch64 state. Defined values are: // - 0b0000 No SHA2 instructions implemented. // - 0b0001 Implements instructions: SHA256H, SHA256H2, SHA256SU0, and // SHA256SU1. // - 0b0010 Implements instructions: // • SHA256H, SHA256H2, SHA256SU0, and SHA256SU1. // • SHA512H, SHA512H2, SHA512SU0, and SHA512SU1. // // FEAT_SHA256 implements the functionality identified by the value 0b0001. // FEAT_SHA512 implements the functionality identified by the value 0b0010. // // In Armv8, the permitted values are 0b0000 and 0b0001. // From Armv8.2, the permitted values are 0b0000, 0b0001, and 0b0010. // // If the value of ID_AA64ISAR0_EL1.SHA1 is 0b0000, this field must have the // value 0b0000. // // If the value of this field is 0b0010, ID_AA64ISAR0_EL1.SHA3 // must have the value 0b0001. // // Other cryptographic features that we cannot detect such as sha512, sha3, sm3, // sm4, sveaes, svepmull, svesha3, svesm4 we set to 0. // // FP/SIMD: // ----------------------------------------------------------------------------- // FP/SIMD must be implemented on all Armv8.0 implementations, but // implementations targeting specialized markets may support the following // combinations: // // • No NEON or floating-point. // • Full floating-point and SIMD support with exception trapping. // • Full floating-point and SIMD support without exception trapping. // // ref: // https://developer.arm.com/documentation/den0024/a/AArch64-Floating-point-and-NEON // // So, we use `PF_ARM_VFP_32_REGISTERS_AVAILABLE`, // `PF_ARM_NEON_INSTRUCTIONS_AVAILABLE` to detect `asimd` and `fp` #ifndef CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_ #define CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_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 mte : 1; // Memory tagging extension. int ecv : 1; // Enhanced counter virtualization. int afp : 1; // Alternate floating-point behaviour. int rpres : 1; // 12-bit reciprocal (square root) estimate precision. int mte3 : 1; // MTE asymmetric fault handling. int sme : 1; // Scalable Matrix Extension. int smei16i64 : 1; // 16-bit to 64-bit integer widening outer product. int smef64f64 : 1; // FP64 to FP64 outer product. int smei8i32 : 1; // 8-bit to 32-bit integer widening outer product. int smef16f32 : 1; // FP16 to FP32 outer product. int smeb16f32 : 1; // BFloat16 to FP32 outper product. int smef32f32 : 1; // FP32 to FP32 outer product. int smefa64 : 1; // Full A64 support for SME in streaming mode. int wfxt : 1; // WFE and WFI with timeout. int ebf16 : 1; // Extended BFloat16 instructions. int sveebf16 : 1; // SVE BFloat16 instructions. int cssc : 1; // Common short sequence compression instructions. int rprfm : 1; // Range Prefetch Memory hint instruction. int sve2p1 : 1; // Scalable Vector Extension (version 2.1). int sme2 : 1; // Scalable Matrix Extension (version 2). int sme2p1 : 1; // Scalable Matrix Extension (version 2.1). int smei16i32 : 1; // 16-bit to 64-bit integer widening outer product. int smebi32i32 : 1; // 1-bit binary to 32-bit integer outer product. int smeb16b16 : 1; // SME2.1 BFloat16 instructions. int smef16f16 : 1; // FP16 to FP16 outer product. // Make sure to update Aarch64FeaturesEnum below if you add a field here. } Aarch64Features; typedef struct { Aarch64Features features; int implementer; // We set 0 for Windows. int variant; // We set 0 for Windows. int part; // We set 0 for Windows. int revision; // We use GetNativeSystemInfo to get processor revision for // Windows. } Aarch64Info; Aarch64Info GetAarch64Info(void); //////////////////////////////////////////////////////////////////////////////// // Introspection functions typedef enum { AARCH64_FP, AARCH64_ASIMD, AARCH64_EVTSTRM, AARCH64_AES, AARCH64_PMULL, AARCH64_SHA1, AARCH64_SHA2, AARCH64_CRC32, AARCH64_ATOMICS, AARCH64_FPHP, AARCH64_ASIMDHP, AARCH64_CPUID, AARCH64_ASIMDRDM, AARCH64_JSCVT, AARCH64_FCMA, AARCH64_LRCPC, AARCH64_DCPOP, AARCH64_SHA3, AARCH64_SM3, AARCH64_SM4, AARCH64_ASIMDDP, AARCH64_SHA512, AARCH64_SVE, AARCH64_ASIMDFHM, AARCH64_DIT, AARCH64_USCAT, AARCH64_ILRCPC, AARCH64_FLAGM, AARCH64_SSBS, AARCH64_SB, AARCH64_PACA, AARCH64_PACG, AARCH64_DCPODP, AARCH64_SVE2, AARCH64_SVEAES, AARCH64_SVEPMULL, AARCH64_SVEBITPERM, AARCH64_SVESHA3, AARCH64_SVESM4, AARCH64_FLAGM2, AARCH64_FRINT, AARCH64_SVEI8MM, AARCH64_SVEF32MM, AARCH64_SVEF64MM, AARCH64_SVEBF16, AARCH64_I8MM, AARCH64_BF16, AARCH64_DGH, AARCH64_RNG, AARCH64_BTI, AARCH64_MTE, AARCH64_ECV, AARCH64_AFP, AARCH64_RPRES, AARCH64_MTE3, AARCH64_SME, AARCH64_SME_I16I64, AARCH64_SME_F64F64, AARCH64_SME_I8I32, AARCH64_SME_F16F32, AARCH64_SME_B16F32, AARCH64_SME_F32F32, AARCH64_SME_FA64, AARCH64_WFXT, AARCH64_EBF16, AARCH64_SVE_EBF16, AARCH64_CSSC, AARCH64_RPRFM, AARCH64_SVE2P1, AARCH64_SME2, AARCH64_SME2P1, AARCH64_SME_I16I32, AARCH64_SME_BI32I32, AARCH64_SME_B16B16, AARCH64_SME_F16F16, AARCH64_LAST_, } Aarch64FeaturesEnum; int GetAarch64FeaturesEnumValue(const Aarch64Features* features, Aarch64FeaturesEnum value); const char* GetAarch64FeaturesEnumName(Aarch64FeaturesEnum); CPU_FEATURES_END_CPP_NAMESPACE #if !defined(CPU_FEATURES_ARCH_AARCH64) #error "Including cpuinfo_aarch64.h from a non-aarch64 target." #endif #endif // CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_ cpu-features-0.9.0/include/cpuinfo_arm.h000066400000000000000000000072131450057454500202350ustar00rootroot00000000000000// 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. // 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. #ifndef CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_ #define CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_ #include // uint32_t #include "cpu_features_cache_info.h" #include "cpu_features_macros.h" CPU_FEATURES_START_CPP_NAMESPACE 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 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 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. // Make sure to update ArmFeaturesEnum below if you add a field here. } ArmFeatures; typedef struct { ArmFeatures features; int implementer; int architecture; int variant; int part; int revision; } ArmInfo; // TODO(user): Add macros to know which features are present at compile // time. ArmInfo GetArmInfo(void); // Compute CpuId from ArmInfo. uint32_t GetArmCpuId(const ArmInfo* const info); //////////////////////////////////////////////////////////////////////////////// // Introspection functions typedef enum { ARM_SWP, ARM_HALF, ARM_THUMB, ARM_26BIT, ARM_FASTMULT, ARM_FPA, ARM_VFP, ARM_EDSP, ARM_JAVA, ARM_IWMMXT, ARM_CRUNCH, ARM_THUMBEE, ARM_NEON, ARM_VFPV3, ARM_VFPV3D16, ARM_TLS, ARM_VFPV4, ARM_IDIVA, ARM_IDIVT, ARM_VFPD32, ARM_LPAE, ARM_EVTSTRM, ARM_AES, ARM_PMULL, ARM_SHA1, ARM_SHA2, ARM_CRC32, ARM_LAST_, } ArmFeaturesEnum; int GetArmFeaturesEnumValue(const ArmFeatures* features, ArmFeaturesEnum value); const char* GetArmFeaturesEnumName(ArmFeaturesEnum); CPU_FEATURES_END_CPP_NAMESPACE #if !defined(CPU_FEATURES_ARCH_ARM) #error "Including cpuinfo_arm.h from a non-arm target." #endif #endif // CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_ cpu-features-0.9.0/include/cpuinfo_loongarch.h000066400000000000000000000051261450057454500214330ustar00rootroot00000000000000// Copyright 2023 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. #ifndef CPU_FEATURES_INCLUDE_CPUINFO_LOONGARCH_H_ #define CPU_FEATURES_INCLUDE_CPUINFO_LOONGARCH_H_ #include "cpu_features_cache_info.h" #include "cpu_features_macros.h" #if !defined(CPU_FEATURES_ARCH_LOONGARCH) #error "Including cpuinfo_loongarch.h from a non-loongarch target." #endif CPU_FEATURES_START_CPP_NAMESPACE typedef struct { // Base int CPUCFG : 1; // Instruction for Identify CPU Features // Extension int LAM : 1; // Extension for Atomic Memory Access Instructions int UAL : 1; // Extension for Non-Aligned Memory Access int FPU : 1; // Extension for Basic Floating-Point Instructions int LSX : 1; // Extension for Loongson SIMD eXtension int LASX : 1; // Extension for Loongson Advanced SIMD eXtension int CRC32 : 1; // Extension for Cyclic Redundancy Check Instructions int COMPLEX : 1; // Extension for Complex Vector Operation Instructions int CRYPTO : 1; // Extension for Encryption And Decryption Vector Instructions int LVZ : 1; // Extension for Virtualization int LBT_X86 : 1; // Extension for X86 Binary Translation Extension int LBT_ARM : 1; // Extension for ARM Binary Translation Extension int LBT_MIPS : 1; // Extension for MIPS Binary Translation Extension int PTW : 1; // Extension for Page Table Walker } LoongArchFeatures; typedef struct { LoongArchFeatures features; } LoongArchInfo; typedef enum { LOONGARCH_CPUCFG, LOONGARCH_LAM, LOONGARCH_UAL, LOONGARCH_FPU, LOONGARCH_LSX, LOONGARCH_LASX, LOONGARCH_CRC32, LOONGARCH_COMPLEX, LOONGARCH_CRYPTO, LOONGARCH_LVZ, LOONGARCH_LBT_X86, LOONGARCH_LBT_ARM, LOONGARCH_LBT_MIPS, LOONGARCH_PTW, LOONGARCH_LAST_, } LoongArchFeaturesEnum; LoongArchInfo GetLoongArchInfo(void); int GetLoongArchFeaturesEnumValue(const LoongArchFeatures* features, LoongArchFeaturesEnum value); const char* GetLoongArchFeaturesEnumName(LoongArchFeaturesEnum); CPU_FEATURES_END_CPP_NAMESPACE #endif // CPU_FEATURES_INCLUDE_CPUINFO_LOONGARCH_H_ cpu-features-0.9.0/include/cpuinfo_mips.h000066400000000000000000000045541450057454500204330ustar00rootroot00000000000000// 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. // 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. #ifndef CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_ #define CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_ #include "cpu_features_cache_info.h" #include "cpu_features_macros.h" CPU_FEATURES_START_CPP_NAMESPACE typedef struct { int msa : 1; // MIPS SIMD Architecture // https://www.mips.com/products/architectures/ase/simd/ int eva : 1; // Enhanced Virtual Addressing // https://www.mips.com/products/architectures/mips64/ int r6 : 1; // True if is release 6 of the processor. int mips16 : 1; // Compressed instructions int mdmx : 1; // MIPS Digital Media Extension int mips3d : 1; // 3D graphics acceleration // MIPS(r) Architecture for Programmers, Volume IV-c int smart : 1; // Smart-card cryptography // MIPS(r) Architecture for Programmers, Volume IV-d int dsp : 1; // Digital Signal Processing // MIPS(r) Architecture for Programmers, Volume IV-e // https://www.mips.com/products/architectures/ase/dsp/ // Make sure to update MipsFeaturesEnum below if you add a field here. } MipsFeatures; typedef struct { MipsFeatures features; } MipsInfo; MipsInfo GetMipsInfo(void); //////////////////////////////////////////////////////////////////////////////// // Introspection functions typedef enum { MIPS_MSA, MIPS_EVA, MIPS_R6, MIPS_MIPS16, MIPS_MDMX, MIPS_MIPS3D, MIPS_SMART, MIPS_DSP, MIPS_LAST_, } MipsFeaturesEnum; int GetMipsFeaturesEnumValue(const MipsFeatures* features, MipsFeaturesEnum value); const char* GetMipsFeaturesEnumName(MipsFeaturesEnum); CPU_FEATURES_END_CPP_NAMESPACE #if !defined(CPU_FEATURES_ARCH_MIPS) #error "Including cpuinfo_mips.h from a non-mips target." #endif #endif // CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_ cpu-features-0.9.0/include/cpuinfo_ppc.h000066400000000000000000000106151450057454500202400ustar00rootroot00000000000000// Copyright 2018 IBM // // 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. #ifndef CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_ #define CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_ #include "cpu_features_cache_info.h" #include "cpu_features_macros.h" CPU_FEATURES_START_CPP_NAMESPACE typedef struct { int ppc32 : 1; int ppc64 : 1; int ppc601 : 1; int altivec : 1; int fpu : 1; int mmu : 1; int mac_4xx : 1; int unifiedcache : 1; int spe : 1; int efpsingle : 1; int efpdouble : 1; int no_tb : 1; int power4 : 1; int power5 : 1; int power5plus : 1; int cell : 1; int booke : 1; int smt : 1; int icachesnoop : 1; int arch205 : 1; int pa6t : 1; int dfp : 1; int power6ext : 1; int arch206 : 1; int vsx : 1; int pseries_perfmon_compat : 1; int truele : 1; int ppcle : 1; int arch207 : 1; int htm : 1; int dscr : 1; int ebb : 1; int isel : 1; int tar : 1; int vcrypto : 1; int htm_nosc : 1; int arch300 : 1; int ieee128 : 1; int darn : 1; int scv : 1; int htm_no_suspend : 1; // Make sure to update PPCFeaturesEnum below if you add a field here. } PPCFeatures; typedef struct { PPCFeatures features; } PPCInfo; PPCInfo GetPPCInfo(void); typedef struct { char platform[64]; // 0 terminated string char base_platform[64]; // 0 terminated string } PPCPlatformTypeStrings; typedef struct { char platform[64]; // 0 terminated string char model[64]; // 0 terminated string char machine[64]; // 0 terminated string char cpu[64]; // 0 terminated string PPCPlatformTypeStrings type; } PPCPlatformStrings; PPCPlatformStrings GetPPCPlatformStrings(void); //////////////////////////////////////////////////////////////////////////////// // Introspection functions typedef enum { PPC_32, /* 32 bit mode execution */ PPC_64, /* 64 bit mode execution */ PPC_601_INSTR, /* Old POWER ISA */ PPC_HAS_ALTIVEC, /* SIMD Unit*/ PPC_HAS_FPU, /* Floating Point Unit */ PPC_HAS_MMU, /* Memory management unit */ PPC_HAS_4xxMAC, PPC_UNIFIED_CACHE, /* Unified instruction and data cache */ PPC_HAS_SPE, /* Signal processing extention unit */ PPC_HAS_EFP_SINGLE, /* SPE single precision fpu */ PPC_HAS_EFP_DOUBLE, /* SPE double precision fpu */ PPC_NO_TB, /* No timebase */ PPC_POWER4, PPC_POWER5, PPC_POWER5_PLUS, PPC_CELL, /* Cell broadband engine */ PPC_BOOKE, /* Embedded ISA */ PPC_SMT, /* Simultaneous multi-threading */ PPC_ICACHE_SNOOP, PPC_ARCH_2_05, /* ISA 2.05 - POWER6 */ PPC_PA6T, /* PA Semi 6T core ISA */ PPC_HAS_DFP, /* Decimal floating point unit */ PPC_POWER6_EXT, PPC_ARCH_2_06, /* ISA 2.06 - POWER7 */ PPC_HAS_VSX, /* Vector-scalar extension */ PPC_PSERIES_PERFMON_COMPAT, /* Set of backwards compatibile performance monitoring events */ PPC_TRUE_LE, PPC_PPC_LE, PPC_ARCH_2_07, /* ISA 2.07 - POWER8 */ PPC_HTM, /* Hardware Transactional Memory */ PPC_DSCR, /* Data stream control register */ PPC_EBB, /* Event base branching */ PPC_ISEL, /* Integer select instructions */ PPC_TAR, /* Target address register */ PPC_VEC_CRYPTO, /* Vector cryptography instructions */ PPC_HTM_NOSC, /* Transactions aborted when syscall made*/ PPC_ARCH_3_00, /* ISA 3.00 - POWER9 */ PPC_HAS_IEEE128, /* VSX IEEE Binary Float 128-bit */ PPC_DARN, /* Deliver a random number instruction */ PPC_SCV, /* scv syscall */ PPC_HTM_NO_SUSPEND, /* TM w/out suspended state */ PPC_LAST_, } PPCFeaturesEnum; int GetPPCFeaturesEnumValue(const PPCFeatures* features, PPCFeaturesEnum value); const char* GetPPCFeaturesEnumName(PPCFeaturesEnum); CPU_FEATURES_END_CPP_NAMESPACE #if !defined(CPU_FEATURES_ARCH_PPC) #error "Including cpuinfo_ppc.h from a non-ppc target." #endif #endif // CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_ cpu-features-0.9.0/include/cpuinfo_riscv.h000066400000000000000000000044121450057454500206020ustar00rootroot00000000000000// Copyright 2022 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. #ifndef CPU_FEATURES_INCLUDE_CPUINFO_RISCV_H_ #define CPU_FEATURES_INCLUDE_CPUINFO_RISCV_H_ #include "cpu_features_cache_info.h" #include "cpu_features_macros.h" #if !defined(CPU_FEATURES_ARCH_RISCV) #error "Including cpuinfo_riscv.h from a non-riscv target." #endif CPU_FEATURES_START_CPP_NAMESPACE typedef struct { // Base int RV32I : 1; // Base Integer Instruction Set, 32-bit int RV64I : 1; // Base Integer Instruction Set, 64-bit // Extension int M : 1; // Standard Extension for Integer Multiplication/Division int A : 1; // Standard Extension for Atomic Instructions int F : 1; // Standard Extension for Single-Precision Floating-Point int D : 1; // Standard Extension for Double-Precision Floating-Point int Q : 1; // Standard Extension for Quad-Precision Floating-Point int C : 1; // Standard Extension for Compressed Instructions int V : 1; // Standard Extension for Vector Instructions int Zicsr : 1; // Control and Status Register (CSR) int Zifencei : 1; // Instruction-Fetch Fence } RiscvFeatures; typedef struct { RiscvFeatures features; char uarch[64]; // 0 terminated string char vendor[64]; // 0 terminated string } RiscvInfo; typedef enum { RISCV_RV32I, RISCV_RV64I, RISCV_M, RISCV_A, RISCV_F, RISCV_D, RISCV_Q, RISCV_C, RISCV_V, RISCV_Zicsr, RISCV_Zifencei, RISCV_LAST_, } RiscvFeaturesEnum; RiscvInfo GetRiscvInfo(void); int GetRiscvFeaturesEnumValue(const RiscvFeatures* features, RiscvFeaturesEnum value); const char* GetRiscvFeaturesEnumName(RiscvFeaturesEnum); CPU_FEATURES_END_CPP_NAMESPACE #endif // CPU_FEATURES_INCLUDE_CPUINFO_RISCV_H_ cpu-features-0.9.0/include/cpuinfo_s390x.h000066400000000000000000000063201450057454500203420ustar00rootroot00000000000000// Copyright 2022 IBM // // 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. #ifndef CPU_FEATURES_INCLUDE_CPUINFO_S390X_H_ #define CPU_FEATURES_INCLUDE_CPUINFO_S390X_H_ #include "cpu_features_cache_info.h" #include "cpu_features_macros.h" CPU_FEATURES_START_CPP_NAMESPACE typedef struct { int esan3: 1; // instructions named N3, "backported" to esa-mode int zarch: 1; // z/Architecture mode active int stfle: 1; // store-facility-list-extended int msa: 1; // message-security assist int ldisp: 1; // long-displacement int eimm: 1; // extended-immediate int dfp: 1; // decimal floating point & perform floating point operation int edat: 1; // huge page support int etf3eh: 1; // extended-translation facility 3 enhancement int highgprs: 1; // 64-bit register support for 31-bit processes int te: 1; // transactional execution int vx: 1; // vector extension facility int vxd: 1; // vector-packed-decimal facility int vxe: 1; // vector-enhancement facility 1 int gs: 1; // guarded-storage facility int vxe2: 1; // vector-enhancements facility 2 int vxp: 1; // vector-packed-decimal-enhancement facility int sort: 1; // enhanced-sort facility int dflt: 1; // deflate-conversion facility int vxp2: 1; // vector-packed-decimal-enhancement facility 2 int nnpa: 1; // neural network processing assist facility int pcimio: 1; // PCI mio facility int sie: 1; // virtualization support // Make sure to update S390XFeaturesEnum below if you add a field here. } S390XFeatures; typedef struct { S390XFeatures features; } S390XInfo; S390XInfo GetS390XInfo(void); typedef struct { char platform[64]; // 0 terminated string } S390XPlatformTypeStrings; typedef struct { int num_processors; // -1 if N/A S390XPlatformTypeStrings type; } S390XPlatformStrings; S390XPlatformStrings GetS390XPlatformStrings(void); //////////////////////////////////////////////////////////////////////////////// // Introspection functions typedef enum { S390_ESAN3, S390_ZARCH, S390_STFLE, S390_MSA, S390_LDISP, S390_EIMM, S390_DFP, S390_EDAT, S390_ETF3EH, S390_HIGHGPRS, S390_TE, S390_VX, S390_VXD, S390_VXE, S390_GS, S390_VXE2, S390_VXP, S390_SORT, S390_DFLT, S390_VXP2, S390_NNPA, S390_PCIMIO, S390_SIE, S390X_LAST_, } S390XFeaturesEnum; int GetS390XFeaturesEnumValue(const S390XFeatures* features, S390XFeaturesEnum value); const char* GetS390XFeaturesEnumName(S390XFeaturesEnum); CPU_FEATURES_END_CPP_NAMESPACE #if !defined(CPU_FEATURES_ARCH_S390X) #error "Including cpuinfo_s390x.h from a non-s390x target." #endif #endif // CPU_FEATURES_INCLUDE_CPUINFO_S390X_H_ cpu-features-0.9.0/include/cpuinfo_x86.h000066400000000000000000000170331450057454500201040ustar00rootroot00000000000000// Copyright 2017 Google LLC // Copyright 2020 Intel Corporation // // 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. #ifndef CPU_FEATURES_INCLUDE_CPUINFO_X86_H_ #define CPU_FEATURES_INCLUDE_CPUINFO_X86_H_ #include "cpu_features_cache_info.h" #include "cpu_features_macros.h" CPU_FEATURES_START_CPP_NAMESPACE // CPUID Vendors #define CPU_FEATURES_VENDOR_GENUINE_INTEL "GenuineIntel" #define CPU_FEATURES_VENDOR_AUTHENTIC_AMD "AuthenticAMD" #define CPU_FEATURES_VENDOR_HYGON_GENUINE "HygonGenuine" #define CPU_FEATURES_VENDOR_CENTAUR_HAULS "CentaurHauls" #define CPU_FEATURES_VENDOR_SHANGHAI " Shanghai " // See https://en.wikipedia.org/wiki/CPUID for a list of x86 cpu features. // The field names are based on the short name provided in the wikipedia tables. typedef struct { int fpu : 1; int tsc : 1; int cx8 : 1; int clfsh : 1; int mmx : 1; int aes : 1; int erms : 1; int f16c : 1; int fma4 : 1; int fma3 : 1; int vaes : 1; int vpclmulqdq : 1; int bmi1 : 1; int hle : 1; int bmi2 : 1; int rtm : 1; int rdseed : 1; int clflushopt : 1; int clwb : 1; int sse : 1; int sse2 : 1; int sse3 : 1; int ssse3 : 1; int sse4_1 : 1; int sse4_2 : 1; int sse4a : 1; int avx : 1; int avx_vnni : 1; int avx2 : 1; int avx512f : 1; int avx512cd : 1; int avx512er : 1; int avx512pf : 1; int avx512bw : 1; int avx512dq : 1; int avx512vl : 1; int avx512ifma : 1; int avx512vbmi : 1; int avx512vbmi2 : 1; int avx512vnni : 1; int avx512bitalg : 1; int avx512vpopcntdq : 1; int avx512_4vnniw : 1; int avx512_4vbmi2 : 1; // Note: this is an alias to avx512_4fmaps. int avx512_second_fma : 1; int avx512_4fmaps : 1; int avx512_bf16 : 1; int avx512_vp2intersect : 1; int avx512_fp16 : 1; int amx_bf16 : 1; int amx_tile : 1; int amx_int8 : 1; int amx_fp16 : 1; int pclmulqdq : 1; int smx : 1; int sgx : 1; int cx16 : 1; // aka. CMPXCHG16B int sha : 1; int popcnt : 1; int movbe : 1; int rdrnd : 1; int dca : 1; int ss : 1; int adx : 1; int lzcnt : 1; // Note: this flag is called ABM for AMD, LZCNT for Intel. int gfni : 1; int movdiri : 1; int movdir64b : 1; int fs_rep_mov : 1; // Fast short REP MOV int fz_rep_movsb : 1; // Fast zero-length REP MOVSB int fs_rep_stosb : 1; // Fast short REP STOSB int fs_rep_cmpsb_scasb : 1; // Fast short REP CMPSB/SCASB int lam: 1; // Intel Linear Address Mask int uai: 1; // AMD Upper Address Ignore // Make sure to update X86FeaturesEnum below if you add a field here. } X86Features; typedef struct { X86Features features; int family; int model; int stepping; char vendor[13]; // 0 terminated string char brand_string[49]; // 0 terminated string } X86Info; // Calls cpuid and returns an initialized X86info. X86Info GetX86Info(void); // Returns cache hierarchy informations. // Can call cpuid multiple times. CacheInfo GetX86CacheInfo(void); typedef enum { X86_UNKNOWN, ZHAOXIN_ZHANGJIANG, // ZhangJiang ZHAOXIN_WUDAOKOU, // WuDaoKou ZHAOXIN_LUJIAZUI, // LuJiaZui ZHAOXIN_YONGFENG, // YongFeng INTEL_80486, // 80486 INTEL_P5, // P5 INTEL_LAKEMONT, // LAKEMONT INTEL_CORE, // CORE INTEL_PNR, // PENRYN INTEL_NHM, // NEHALEM INTEL_ATOM_BNL, // BONNELL INTEL_WSM, // WESTMERE INTEL_SNB, // SANDYBRIDGE INTEL_IVB, // IVYBRIDGE INTEL_ATOM_SMT, // SILVERMONT INTEL_HSW, // HASWELL INTEL_BDW, // BROADWELL INTEL_SKL, // SKYLAKE INTEL_CCL, // CASCADELAKE INTEL_ATOM_GMT, // GOLDMONT INTEL_ATOM_GMT_PLUS, // GOLDMONT+ INTEL_ATOM_TMT, // TREMONT INTEL_KBL, // KABY LAKE INTEL_CFL, // COFFEE LAKE INTEL_WHL, // WHISKEY LAKE INTEL_CML, // COMET LAKE INTEL_CNL, // CANNON LAKE INTEL_ICL, // ICE LAKE INTEL_TGL, // TIGER LAKE INTEL_SPR, // SAPPHIRE RAPIDS INTEL_ADL, // ALDER LAKE INTEL_RCL, // ROCKET LAKE INTEL_RPL, // RAPTOR LAKE INTEL_KNIGHTS_M, // KNIGHTS MILL INTEL_KNIGHTS_L, // KNIGHTS LANDING INTEL_KNIGHTS_F, // KNIGHTS FERRY INTEL_KNIGHTS_C, // KNIGHTS CORNER INTEL_NETBURST, // NETBURST AMD_HAMMER, // K8 HAMMER AMD_K10, // K10 AMD_K11, // K11 AMD_K12, // K12 LLANO AMD_BOBCAT, // K14 BOBCAT AMD_PILEDRIVER, // K15 PILEDRIVER AMD_STREAMROLLER, // K15 STREAMROLLER AMD_EXCAVATOR, // K15 EXCAVATOR AMD_BULLDOZER, // K15 BULLDOZER AMD_JAGUAR, // K16 JAGUAR AMD_PUMA, // K16 PUMA AMD_ZEN, // K17 ZEN AMD_ZEN_PLUS, // K17 ZEN+ AMD_ZEN2, // K17 ZEN 2 AMD_ZEN3, // K19 ZEN 3 AMD_ZEN4, // K19 ZEN 4 X86_MICROARCHITECTURE_LAST_, } X86Microarchitecture; // Returns the underlying microarchitecture by looking at X86Info's vendor, // family and model. X86Microarchitecture GetX86Microarchitecture(const X86Info* info); // Calls cpuid and fills the brand_string. // - brand_string *must* be of size 49 (beware of array decaying). // - brand_string will be zero terminated. CPU_FEATURES_DEPRECATED("brand_string is now embedded in X86Info by default") void FillX86BrandString(char brand_string[49]); //////////////////////////////////////////////////////////////////////////////// // Introspection functions typedef enum { X86_FPU, X86_TSC, X86_CX8, X86_CLFSH, X86_MMX, X86_AES, X86_ERMS, X86_F16C, X86_FMA4, X86_FMA3, X86_VAES, X86_VPCLMULQDQ, X86_BMI1, X86_HLE, X86_BMI2, X86_RTM, X86_RDSEED, X86_CLFLUSHOPT, X86_CLWB, X86_SSE, X86_SSE2, X86_SSE3, X86_SSSE3, X86_SSE4_1, X86_SSE4_2, X86_SSE4A, X86_AVX, X86_AVX_VNNI, X86_AVX2, X86_AVX512F, X86_AVX512CD, X86_AVX512ER, X86_AVX512PF, X86_AVX512BW, X86_AVX512DQ, X86_AVX512VL, X86_AVX512IFMA, X86_AVX512VBMI, X86_AVX512VBMI2, X86_AVX512VNNI, X86_AVX512BITALG, X86_AVX512VPOPCNTDQ, X86_AVX512_4VNNIW, X86_AVX512_4VBMI2, // Note: this is an alias to X86_AVX512_4FMAPS. X86_AVX512_SECOND_FMA, X86_AVX512_4FMAPS, X86_AVX512_BF16, X86_AVX512_VP2INTERSECT, X86_AVX512_FP16, X86_AMX_BF16, X86_AMX_TILE, X86_AMX_INT8, X86_AMX_FP16, X86_PCLMULQDQ, X86_SMX, X86_SGX, X86_CX16, X86_SHA, X86_POPCNT, X86_MOVBE, X86_RDRND, X86_DCA, X86_SS, X86_ADX, X86_LZCNT, X86_GFNI, X86_MOVDIRI, X86_MOVDIR64B, X86_FS_REP_MOV, X86_FZ_REP_MOVSB, X86_FS_REP_STOSB, X86_FS_REP_CMPSB_SCASB, X86_LAM, X86_UAI, X86_LAST_, } X86FeaturesEnum; int GetX86FeaturesEnumValue(const X86Features* features, X86FeaturesEnum value); const char* GetX86FeaturesEnumName(X86FeaturesEnum); const char* GetX86MicroarchitectureName(X86Microarchitecture); CPU_FEATURES_END_CPP_NAMESPACE #if !defined(CPU_FEATURES_ARCH_X86) #error "Including cpuinfo_x86.h from a non-x86 target." #endif #endif // CPU_FEATURES_INCLUDE_CPUINFO_X86_H_ cpu-features-0.9.0/include/internal/000077500000000000000000000000001450057454500173735ustar00rootroot00000000000000cpu-features-0.9.0/include/internal/bit_utils.h000066400000000000000000000023561450057454500215500ustar00rootroot00000000000000// 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. // 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. #ifndef CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_ #define CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_ #include #include #include #include "cpu_features_macros.h" CPU_FEATURES_START_CPP_NAMESPACE inline static bool IsBitSet(uint32_t reg, uint32_t bit) { return (reg >> bit) & 0x1; } inline static uint32_t ExtractBitRange(uint32_t reg, uint32_t msb, uint32_t lsb) { const uint64_t bits = msb - lsb + 1ULL; const uint64_t mask = (1ULL << bits) - 1ULL; assert(msb >= lsb); return (reg >> lsb) & mask; } CPU_FEATURES_END_CPP_NAMESPACE #endif // CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_ cpu-features-0.9.0/include/internal/cpuid_x86.h000066400000000000000000000022011450057454500213500ustar00rootroot00000000000000// 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. // 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. #ifndef CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_ #define CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_ #include #include "cpu_features_macros.h" CPU_FEATURES_START_CPP_NAMESPACE // A struct to hold the result of a call to cpuid. typedef struct { uint32_t eax, ebx, ecx, edx; } Leaf; // 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); CPU_FEATURES_END_CPP_NAMESPACE #endif // CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_ cpu-features-0.9.0/include/internal/filesystem.h000066400000000000000000000025361450057454500217360ustar00rootroot00000000000000// 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. // 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. // An interface for the filesystem that allows mocking the filesystem in // unittests. #ifndef CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_ #define CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_ #include #include #include "cpu_features_macros.h" CPU_FEATURES_START_CPP_NAMESPACE // Same as linux "open(filename, O_RDONLY)", retries automatically on EINTR. int CpuFeatures_OpenFile(const char* filename); // Same as linux "read(file_descriptor, buffer, buffer_size)", retries // automatically on EINTR. int CpuFeatures_ReadFile(int file_descriptor, void* buffer, size_t buffer_size); // Same as linux "close(file_descriptor)". void CpuFeatures_CloseFile(int file_descriptor); CPU_FEATURES_END_CPP_NAMESPACE #endif // CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_ cpu-features-0.9.0/include/internal/hwcaps.h000066400000000000000000000245441450057454500210420ustar00rootroot00000000000000// 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. // 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. // Interface to retrieve hardware capabilities. It relies on Linux's getauxval // or `/proc/self/auxval` under the hood. #ifndef CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_ #define CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_ #include #include #include "cpu_features_macros.h" CPU_FEATURES_START_CPP_NAMESPACE // To avoid depending on the linux kernel we reproduce the architecture specific // constants here. // http://elixir.free-electrons.com/linux/latest/source/arch/arm64/include/uapi/asm/hwcap.h #define AARCH64_HWCAP_FP (1UL << 0) #define AARCH64_HWCAP_ASIMD (1UL << 1) #define AARCH64_HWCAP_EVTSTRM (1UL << 2) #define AARCH64_HWCAP_AES (1UL << 3) #define AARCH64_HWCAP_PMULL (1UL << 4) #define AARCH64_HWCAP_SHA1 (1UL << 5) #define AARCH64_HWCAP_SHA2 (1UL << 6) #define AARCH64_HWCAP_CRC32 (1UL << 7) #define AARCH64_HWCAP_ATOMICS (1UL << 8) #define AARCH64_HWCAP_FPHP (1UL << 9) #define AARCH64_HWCAP_ASIMDHP (1UL << 10) #define AARCH64_HWCAP_CPUID (1UL << 11) #define AARCH64_HWCAP_ASIMDRDM (1UL << 12) #define AARCH64_HWCAP_JSCVT (1UL << 13) #define AARCH64_HWCAP_FCMA (1UL << 14) #define AARCH64_HWCAP_LRCPC (1UL << 15) #define AARCH64_HWCAP_DCPOP (1UL << 16) #define AARCH64_HWCAP_SHA3 (1UL << 17) #define AARCH64_HWCAP_SM3 (1UL << 18) #define AARCH64_HWCAP_SM4 (1UL << 19) #define AARCH64_HWCAP_ASIMDDP (1UL << 20) #define AARCH64_HWCAP_SHA512 (1UL << 21) #define AARCH64_HWCAP_SVE (1UL << 22) #define AARCH64_HWCAP_ASIMDFHM (1UL << 23) #define AARCH64_HWCAP_DIT (1UL << 24) #define AARCH64_HWCAP_USCAT (1UL << 25) #define AARCH64_HWCAP_ILRCPC (1UL << 26) #define AARCH64_HWCAP_FLAGM (1UL << 27) #define AARCH64_HWCAP_SSBS (1UL << 28) #define AARCH64_HWCAP_SB (1UL << 29) #define AARCH64_HWCAP_PACA (1UL << 30) #define AARCH64_HWCAP_PACG (1UL << 31) #define AARCH64_HWCAP2_DCPODP (1UL << 0) #define AARCH64_HWCAP2_SVE2 (1UL << 1) #define AARCH64_HWCAP2_SVEAES (1UL << 2) #define AARCH64_HWCAP2_SVEPMULL (1UL << 3) #define AARCH64_HWCAP2_SVEBITPERM (1UL << 4) #define AARCH64_HWCAP2_SVESHA3 (1UL << 5) #define AARCH64_HWCAP2_SVESM4 (1UL << 6) #define AARCH64_HWCAP2_FLAGM2 (1UL << 7) #define AARCH64_HWCAP2_FRINT (1UL << 8) #define AARCH64_HWCAP2_SVEI8MM (1UL << 9) #define AARCH64_HWCAP2_SVEF32MM (1UL << 10) #define AARCH64_HWCAP2_SVEF64MM (1UL << 11) #define AARCH64_HWCAP2_SVEBF16 (1UL << 12) #define AARCH64_HWCAP2_I8MM (1UL << 13) #define AARCH64_HWCAP2_BF16 (1UL << 14) #define AARCH64_HWCAP2_DGH (1UL << 15) #define AARCH64_HWCAP2_RNG (1UL << 16) #define AARCH64_HWCAP2_BTI (1UL << 17) #define AARCH64_HWCAP2_MTE (1UL << 18) #define AARCH64_HWCAP2_ECV (1UL << 19) #define AARCH64_HWCAP2_AFP (1UL << 20) #define AARCH64_HWCAP2_RPRES (1UL << 21) #define AARCH64_HWCAP2_MTE3 (1UL << 22) #define AARCH64_HWCAP2_SME (1UL << 23) #define AARCH64_HWCAP2_SME_I16I64 (1UL << 24) #define AARCH64_HWCAP2_SME_F64F64 (1UL << 25) #define AARCH64_HWCAP2_SME_I8I32 (1UL << 26) #define AARCH64_HWCAP2_SME_F16F32 (1UL << 27) #define AARCH64_HWCAP2_SME_B16F32 (1UL << 28) #define AARCH64_HWCAP2_SME_F32F32 (1UL << 29) #define AARCH64_HWCAP2_SME_FA64 (1UL << 30) #define AARCH64_HWCAP2_WFXT (1UL << 31) #define AARCH64_HWCAP2_EBF16 (1UL << 32) #define AARCH64_HWCAP2_SVE_EBF16 (1UL << 33) #define AARCH64_HWCAP2_CSSC (1UL << 34) #define AARCH64_HWCAP2_RPRFM (1UL << 35) #define AARCH64_HWCAP2_SVE2P1 (1UL << 36) #define AARCH64_HWCAP2_SME2 (1UL << 37) #define AARCH64_HWCAP2_SME2P1 (1UL << 38) #define AARCH64_HWCAP2_SME_I16I32 (1UL << 39) #define AARCH64_HWCAP2_SME_BI32I32 (1UL << 40) #define AARCH64_HWCAP2_SME_B16B16 (1UL << 41) #define AARCH64_HWCAP2_SME_F16F16 (1UL << 42) // http://elixir.free-electrons.com/linux/latest/source/arch/arm/include/uapi/asm/hwcap.h #define ARM_HWCAP_SWP (1UL << 0) #define ARM_HWCAP_HALF (1UL << 1) #define ARM_HWCAP_THUMB (1UL << 2) #define ARM_HWCAP_26BIT (1UL << 3) #define ARM_HWCAP_FAST_MULT (1UL << 4) #define ARM_HWCAP_FPA (1UL << 5) #define ARM_HWCAP_VFP (1UL << 6) #define ARM_HWCAP_EDSP (1UL << 7) #define ARM_HWCAP_JAVA (1UL << 8) #define ARM_HWCAP_IWMMXT (1UL << 9) #define ARM_HWCAP_CRUNCH (1UL << 10) #define ARM_HWCAP_THUMBEE (1UL << 11) #define ARM_HWCAP_NEON (1UL << 12) #define ARM_HWCAP_VFPV3 (1UL << 13) #define ARM_HWCAP_VFPV3D16 (1UL << 14) #define ARM_HWCAP_TLS (1UL << 15) #define ARM_HWCAP_VFPV4 (1UL << 16) #define ARM_HWCAP_IDIVA (1UL << 17) #define ARM_HWCAP_IDIVT (1UL << 18) #define ARM_HWCAP_VFPD32 (1UL << 19) #define ARM_HWCAP_LPAE (1UL << 20) #define ARM_HWCAP_EVTSTRM (1UL << 21) #define ARM_HWCAP2_AES (1UL << 0) #define ARM_HWCAP2_PMULL (1UL << 1) #define ARM_HWCAP2_SHA1 (1UL << 2) #define ARM_HWCAP2_SHA2 (1UL << 3) #define ARM_HWCAP2_CRC32 (1UL << 4) // http://elixir.free-electrons.com/linux/latest/source/arch/mips/include/uapi/asm/hwcap.h #define MIPS_HWCAP_R6 (1UL << 0) #define MIPS_HWCAP_MSA (1UL << 1) #define MIPS_HWCAP_CRC32 (1UL << 2) #define MIPS_HWCAP_MIPS16 (1UL << 3) #define MIPS_HWCAP_MDMX (1UL << 4) #define MIPS_HWCAP_MIPS3D (1UL << 5) #define MIPS_HWCAP_SMARTMIPS (1UL << 6) #define MIPS_HWCAP_DSP (1UL << 7) #define MIPS_HWCAP_DSP2 (1UL << 8) #define MIPS_HWCAP_DSP3 (1UL << 9) // http://elixir.free-electrons.com/linux/latest/source/arch/powerpc/include/uapi/asm/cputable.h #ifndef _UAPI__ASM_POWERPC_CPUTABLE_H /* in AT_HWCAP */ #define PPC_FEATURE_32 0x80000000 #define PPC_FEATURE_64 0x40000000 #define PPC_FEATURE_601_INSTR 0x20000000 #define PPC_FEATURE_HAS_ALTIVEC 0x10000000 #define PPC_FEATURE_HAS_FPU 0x08000000 #define PPC_FEATURE_HAS_MMU 0x04000000 #define PPC_FEATURE_HAS_4xxMAC 0x02000000 #define PPC_FEATURE_UNIFIED_CACHE 0x01000000 #define PPC_FEATURE_HAS_SPE 0x00800000 #define PPC_FEATURE_HAS_EFP_SINGLE 0x00400000 #define PPC_FEATURE_HAS_EFP_DOUBLE 0x00200000 #define PPC_FEATURE_NO_TB 0x00100000 #define PPC_FEATURE_POWER4 0x00080000 #define PPC_FEATURE_POWER5 0x00040000 #define PPC_FEATURE_POWER5_PLUS 0x00020000 #define PPC_FEATURE_CELL 0x00010000 #define PPC_FEATURE_BOOKE 0x00008000 #define PPC_FEATURE_SMT 0x00004000 #define PPC_FEATURE_ICACHE_SNOOP 0x00002000 #define PPC_FEATURE_ARCH_2_05 0x00001000 #define PPC_FEATURE_PA6T 0x00000800 #define PPC_FEATURE_HAS_DFP 0x00000400 #define PPC_FEATURE_POWER6_EXT 0x00000200 #define PPC_FEATURE_ARCH_2_06 0x00000100 #define PPC_FEATURE_HAS_VSX 0x00000080 #define PPC_FEATURE_PSERIES_PERFMON_COMPAT 0x00000040 /* Reserved - do not use 0x00000004 */ #define PPC_FEATURE_TRUE_LE 0x00000002 #define PPC_FEATURE_PPC_LE 0x00000001 /* in AT_HWCAP2 */ #define PPC_FEATURE2_ARCH_2_07 0x80000000 #define PPC_FEATURE2_HTM 0x40000000 #define PPC_FEATURE2_DSCR 0x20000000 #define PPC_FEATURE2_EBB 0x10000000 #define PPC_FEATURE2_ISEL 0x08000000 #define PPC_FEATURE2_TAR 0x04000000 #define PPC_FEATURE2_VEC_CRYPTO 0x02000000 #define PPC_FEATURE2_HTM_NOSC 0x01000000 #define PPC_FEATURE2_ARCH_3_00 0x00800000 #define PPC_FEATURE2_HAS_IEEE128 0x00400000 #define PPC_FEATURE2_DARN 0x00200000 #define PPC_FEATURE2_SCV 0x00100000 #define PPC_FEATURE2_HTM_NO_SUSPEND 0x00080000 #endif // https://elixir.bootlin.com/linux/v6.0-rc6/source/arch/s390/include/asm/elf.h #define HWCAP_S390_ESAN3 1 #define HWCAP_S390_ZARCH 2 #define HWCAP_S390_STFLE 4 #define HWCAP_S390_MSA 8 #define HWCAP_S390_LDISP 16 #define HWCAP_S390_EIMM 32 #define HWCAP_S390_DFP 64 #define HWCAP_S390_HPAGE 128 #define HWCAP_S390_ETF3EH 256 #define HWCAP_S390_HIGH_GPRS 512 #define HWCAP_S390_TE 1024 #define HWCAP_S390_VX 2048 #define HWCAP_S390_VXRS HWCAP_S390_VX #define HWCAP_S390_VXD 4096 #define HWCAP_S390_VXRS_BCD HWCAP_S390_VXD #define HWCAP_S390_VXE 8192 #define HWCAP_S390_VXRS_EXT HWCAP_S390_VXE #define HWCAP_S390_GS 16384 #define HWCAP_S390_VXRS_EXT2 32768 #define HWCAP_S390_VXRS_PDE 65536 #define HWCAP_S390_SORT 131072 #define HWCAP_S390_DFLT 262144 #define HWCAP_S390_VXRS_PDE2 524288 #define HWCAP_S390_NNPA 1048576 #define HWCAP_S390_PCI_MIO 2097152 #define HWCAP_S390_SIE 4194304 // https://elixir.bootlin.com/linux/latest/source/arch/riscv/include/uapi/asm/hwcap.h #define RISCV_HWCAP_32 0x32 #define RISCV_HWCAP_64 0x64 #define RISCV_HWCAP_128 0x128 #define RISCV_HWCAP_M (1UL << ('M' - 'A')) #define RISCV_HWCAP_A (1UL << ('A' - 'A')) #define RISCV_HWCAP_F (1UL << ('F' - 'A')) #define RISCV_HWCAP_D (1UL << ('D' - 'A')) #define RISCV_HWCAP_Q (1UL << ('Q' - 'A')) #define RISCV_HWCAP_C (1UL << ('C' - 'A')) #define RISCV_HWCAP_V (1UL << ('V' - 'A')) // https://github.com/torvalds/linux/blob/master/arch/loongarch/include/uapi/asm/hwcap.h #define HWCAP_LOONGARCH_CPUCFG (1 << 0) #define HWCAP_LOONGARCH_LAM (1 << 1) #define HWCAP_LOONGARCH_UAL (1 << 2) #define HWCAP_LOONGARCH_FPU (1 << 3) #define HWCAP_LOONGARCH_LSX (1 << 4) #define HWCAP_LOONGARCH_LASX (1 << 5) #define HWCAP_LOONGARCH_CRC32 (1 << 6) #define HWCAP_LOONGARCH_COMPLEX (1 << 7) #define HWCAP_LOONGARCH_CRYPTO (1 << 8) #define HWCAP_LOONGARCH_LVZ (1 << 9) #define HWCAP_LOONGARCH_LBT_X86 (1 << 10) #define HWCAP_LOONGARCH_LBT_ARM (1 << 11) #define HWCAP_LOONGARCH_LBT_MIPS (1 << 12) #define HWCAP_LOONGARCH_PTW (1 << 13) typedef struct { unsigned long hwcaps; unsigned long hwcaps2; } HardwareCapabilities; // Retrieves values from auxiliary vector for types AT_HWCAP and AT_HWCAP2. // First tries to call getauxval(), if not available falls back to reading // "/proc/self/auxv". HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void); // Checks whether value for AT_HWCAP (or AT_HWCAP2) match hwcaps_mask. bool CpuFeatures_IsHwCapsSet(const HardwareCapabilities hwcaps_mask, const HardwareCapabilities hwcaps); // Get pointer for the AT_PLATFORM type. const char* CpuFeatures_GetPlatformPointer(void); // Get pointer for the AT_BASE_PLATFORM type. const char* CpuFeatures_GetBasePlatformPointer(void); CPU_FEATURES_END_CPP_NAMESPACE #endif // CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_ cpu-features-0.9.0/include/internal/stack_line_reader.h000066400000000000000000000031661450057454500232100ustar00rootroot00000000000000// 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. // 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. // Reads a file line by line and stores the data on the stack. This allows // parsing files in one go without allocating. #ifndef CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_ #define CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_ #include #include "cpu_features_macros.h" #include "internal/string_view.h" CPU_FEATURES_START_CPP_NAMESPACE typedef struct { char buffer[STACK_LINE_READER_BUFFER_SIZE]; StringView view; int fd; bool skip_mode; } StackLineReader; // Initializes a StackLineReader. void StackLineReader_Initialize(StackLineReader* reader, int fd); typedef struct { StringView line; // A view of the line. bool eof; // Nothing more to read, we reached EOF. bool full_line; // If false the line was truncated to // STACK_LINE_READER_BUFFER_SIZE. } LineResult; // Reads the file pointed to by fd and tries to read a full line. LineResult StackLineReader_NextLine(StackLineReader* reader); CPU_FEATURES_END_CPP_NAMESPACE #endif // CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_ cpu-features-0.9.0/include/internal/string_view.h000066400000000000000000000100371450057454500221050ustar00rootroot00000000000000// 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. // 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. // A view over a piece of string. The view is not 0 terminated. #ifndef CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_ #define CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_ #include #include #include #include "cpu_features_macros.h" CPU_FEATURES_START_CPP_NAMESPACE typedef struct { const char* ptr; size_t size; } StringView; #ifdef __cplusplus static const StringView kEmptyStringView = {NULL, 0}; #else static const StringView kEmptyStringView; #endif // Returns a StringView from the provided string. // Passing NULL is valid only if size is 0. static inline StringView view(const char* str, const size_t size) { StringView view; view.ptr = str; view.size = size; return view; } static inline StringView str(const char* str) { return view(str, strlen(str)); } // Returns the index of the first occurrence of c in view or -1 if not found. int CpuFeatures_StringView_IndexOfChar(const StringView view, char c); // Returns the index of the first occurrence of sub_view in view or -1 if not // found. int CpuFeatures_StringView_IndexOf(const StringView view, const StringView sub_view); // Returns whether a is equal to b (same content). bool CpuFeatures_StringView_IsEquals(const StringView a, const StringView b); // Returns whether a starts with b. bool CpuFeatures_StringView_StartsWith(const StringView a, const StringView b); // Removes count characters from the beginning of view or kEmptyStringView if // count if greater than view.size. StringView CpuFeatures_StringView_PopFront(const StringView str_view, size_t count); // Removes count characters from the end of view or kEmptyStringView if count if // greater than view.size. StringView CpuFeatures_StringView_PopBack(const StringView str_view, size_t count); // Keeps the count first characters of view or view if count if greater than // view.size. StringView CpuFeatures_StringView_KeepFront(const StringView str_view, size_t count); // Retrieves the first character of view. If view is empty the behavior is // undefined. char CpuFeatures_StringView_Front(const StringView view); // Retrieves the last character of view. If view is empty the behavior is // undefined. char CpuFeatures_StringView_Back(const StringView view); // Removes leading and tailing space characters. StringView CpuFeatures_StringView_TrimWhitespace(StringView view); // Convert StringView to positive integer. e.g. "42", "0x2a". // Returns -1 on error. int CpuFeatures_StringView_ParsePositiveNumber(const StringView view); // Copies src StringView to dst buffer. void CpuFeatures_StringView_CopyString(const StringView src, char* dst, size_t dst_size); // Checks if line contains the specified whitespace separated word. bool CpuFeatures_StringView_HasWord(const StringView line, const char* const word, const char separator); // Get key/value from line. key and value are separated by ": ". // key and value are cleaned up from leading and trailing whitespaces. bool CpuFeatures_StringView_GetAttributeKeyValue(const StringView line, StringView* key, StringView* value); CPU_FEATURES_END_CPP_NAMESPACE #endif // CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_ cpu-features-0.9.0/include/internal/windows_utils.h000066400000000000000000000041471450057454500224640ustar00rootroot00000000000000// Copyright 2022 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. #ifndef CPU_FEATURES_INCLUDE_INTERNAL_WINDOWS_UTILS_H_ #define CPU_FEATURES_INCLUDE_INTERNAL_WINDOWS_UTILS_H_ #include "cpu_features_macros.h" #ifdef CPU_FEATURES_OS_WINDOWS #include // IsProcessorFeaturePresent // modern WinSDK winnt.h contains newer features detection definitions #if !defined(PF_SSSE3_INSTRUCTIONS_AVAILABLE) #define PF_SSSE3_INSTRUCTIONS_AVAILABLE 36 #endif #if !defined(PF_SSE4_1_INSTRUCTIONS_AVAILABLE) #define PF_SSE4_1_INSTRUCTIONS_AVAILABLE 37 #endif #if !defined(PF_SSE4_2_INSTRUCTIONS_AVAILABLE) #define PF_SSE4_2_INSTRUCTIONS_AVAILABLE 38 #endif #if !defined(PF_ARM_VFP_32_REGISTERS_AVAILABLE) #define PF_ARM_VFP_32_REGISTERS_AVAILABLE 18 #endif #if !defined(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) #define PF_ARM_NEON_INSTRUCTIONS_AVAILABLE 19 #endif #if !defined(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) #define PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE 30 #endif #if !defined(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) #define PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE 31 #endif #if !defined(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE) #define PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE 34 #endif #if !defined(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE) #define PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE 43 #endif #if !defined(PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE) #define PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE 44 #endif #if !defined(PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE) #define PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE 45 #endif #endif // CPU_FEATURES_OS_WINDOWS #endif // CPU_FEATURES_INCLUDE_INTERNAL_WINDOWS_UTILS_H_ cpu-features-0.9.0/ndk_compat/000077500000000000000000000000001450057454500162535ustar00rootroot00000000000000cpu-features-0.9.0/ndk_compat/CMakeLists.txt000066400000000000000000000041651450057454500210210ustar00rootroot00000000000000 # # library : NDK compat # find_package(Threads REQUIRED) set (NDK_COMPAT_HDRS cpu-features.h) set (NDK_COMPAT_SRCS cpu-features.c $ $ ) # Note that following `add_cpu_features_headers_and_sources` will use # NDK_COMPAT_SRCS in lieu of NDK_COMPAT_HDRS because we don't want cpu_features # headers to be installed alongside ndk_compat. add_cpu_features_headers_and_sources(NDK_COMPAT_SRCS NDK_COMPAT_SRCS) add_library(ndk_compat ${NDK_COMPAT_HDRS} ${NDK_COMPAT_SRCS}) setup_include_and_definitions(ndk_compat) target_include_directories(ndk_compat PUBLIC $) target_link_libraries(ndk_compat PUBLIC ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT}) set_target_properties(ndk_compat PROPERTIES PUBLIC_HEADER "${NDK_COMPAT_HDRS}") include(GNUInstallDirs) install(TARGETS ndk_compat EXPORT CpuFeaturesNdkCompatTargets PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ndk_compat ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) install(EXPORT CpuFeaturesNdkCompatTargets NAMESPACE CpuFeatures:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeaturesNdkCompat COMPONENT Devel ) include(CMakePackageConfigHelpers) configure_package_config_file(${PROJECT_SOURCE_DIR}/cmake/CpuFeaturesNdkCompatConfig.cmake.in "${PROJECT_BINARY_DIR}/CpuFeaturesNdkCompatConfig.cmake" INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeaturesNdkCompat" NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO ) write_basic_package_version_file( "${PROJECT_BINARY_DIR}/CpuFeaturesNdkCompatConfigVersion.cmake" COMPATIBILITY SameMajorVersion ) install( FILES "${PROJECT_BINARY_DIR}/CpuFeaturesNdkCompatConfig.cmake" "${PROJECT_BINARY_DIR}/CpuFeaturesNdkCompatConfigVersion.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeaturesNdkCompat" COMPONENT Devel ) # # program : NDK compat test program # if(BUILD_TESTING) add_executable(ndk-compat-test ndk-compat-test.c) target_link_libraries(ndk-compat-test PRIVATE ndk_compat) endif() cpu-features-0.9.0/ndk_compat/README.md000066400000000000000000000005241450057454500175330ustar00rootroot00000000000000Provides a header compatible with [android's NDK cpu-features.h](https://android.googlesource.com/platform/ndk/+/master/sources/android/cpufeatures/cpu-features.h). It is intended to be a drop in replacement for this header and help users transition from the NDK to [Google's cpu_features library](https://github.com/google/cpu_features). cpu-features-0.9.0/ndk_compat/cpu-features.c000066400000000000000000000165321450057454500210310ustar00rootroot00000000000000#include "cpu-features.h" #include #include "cpu_features_macros.h" #include "internal/filesystem.h" #include "internal/stack_line_reader.h" #include "internal/string_view.h" #if defined(CPU_FEATURES_ARCH_ARM) #include "cpuinfo_arm.h" #elif defined(CPU_FEATURES_ARCH_X86) #include "cpuinfo_x86.h" #elif defined(CPU_FEATURES_ARCH_MIPS) #include "cpuinfo_mips.h" #elif defined(CPU_FEATURES_ARCH_AARCH64) #include "cpuinfo_aarch64.h" #endif static pthread_once_t g_once; static int g_inited; static uint64_t g_cpuFeatures; static int g_cpuCount; #ifdef CPU_FEATURES_ARCH_ARM static uint32_t g_cpuIdArm; #endif static void set_cpu_mask_bit(uint32_t index, uint32_t* cpu_mask) { *cpu_mask |= 1UL << index; } // Examples of valid inputs: "31", "4-31" static void parse_cpu_mask(const StringView text, uint32_t* cpu_mask) { int separator_index = CpuFeatures_StringView_IndexOfChar(text, '-'); if (separator_index < 0) { // A single cpu index int cpu_index = CpuFeatures_StringView_ParsePositiveNumber(text); if (cpu_index < 0) return; set_cpu_mask_bit(cpu_index, cpu_mask); } else { int cpu_index_a = CpuFeatures_StringView_ParsePositiveNumber( CpuFeatures_StringView_KeepFront(text, separator_index)); int cpu_index_b = CpuFeatures_StringView_ParsePositiveNumber( CpuFeatures_StringView_PopFront(text, separator_index + 1)); int i; if (cpu_index_a < 0 || cpu_index_b < 0) return; for (i = cpu_index_a; i <= cpu_index_b; ++i) { if (i < 32) { set_cpu_mask_bit(i, cpu_mask); } } } } // Format specification from // https://www.kernel.org/doc/Documentation/cputopology.txt // Examples of valid inputs: "31", "2,4-31,32-63", "0-1,3" static void parse_cpu_mask_line(const LineResult result, uint32_t* cpu_mask) { if (!result.full_line || result.eof) return; StringView line = result.line; for (; line.size > 0;) { int next_entry_index = CpuFeatures_StringView_IndexOfChar(line, ','); if (next_entry_index < 0) { parse_cpu_mask(line, cpu_mask); break; } StringView entry = CpuFeatures_StringView_KeepFront(line, next_entry_index); parse_cpu_mask(entry, cpu_mask); line = CpuFeatures_StringView_PopFront(line, next_entry_index + 1); } } static void update_cpu_mask_from_file(const char* filename, uint32_t* cpu_mask) { const int fd = CpuFeatures_OpenFile(filename); if (fd >= 0) { StackLineReader reader; StackLineReader_Initialize(&reader, fd); parse_cpu_mask_line(StackLineReader_NextLine(&reader), cpu_mask); CpuFeatures_CloseFile(fd); } } static int get_cpu_count(void) { uint32_t cpu_mask = 0; update_cpu_mask_from_file("/sys/devices/system/cpu/present", &cpu_mask); update_cpu_mask_from_file("/sys/devices/system/cpu/possible", &cpu_mask); return __builtin_popcount(cpu_mask); } static void android_cpuInit(void) { g_cpuFeatures = 0; g_cpuCount = 1; g_inited = 1; g_cpuCount = get_cpu_count(); if (g_cpuCount == 0) { g_cpuCount = 1; } #if defined(CPU_FEATURES_ARCH_ARM) ArmInfo info = GetArmInfo(); if (info.architecture == 7) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_ARMv7; if (info.features.vfpv3) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3; if (info.features.neon) { g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON; g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFP_D32; } if (info.features.vfpv3d16) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFP_FP16; if (info.features.idiva) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_ARM; if (info.features.idivt) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2; if (info.features.iwmmxt) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_iWMMXt; if (info.features.aes) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_AES; if (info.features.pmull) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_PMULL; if (info.features.sha1) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_SHA1; if (info.features.sha2) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_SHA2; if (info.features.crc32) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_CRC32; if (info.architecture >= 6) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_LDREX_STREX; if (info.features.vfp) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv2; if (info.features.vfpv4) { g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFP_FMA; g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON_FMA; } g_cpuIdArm = GetArmCpuId(&info); #elif defined(CPU_FEATURES_ARCH_X86) X86Info info = GetX86Info(); if (info.features.ssse3) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSSE3; if (info.features.popcnt) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_POPCNT; if (info.features.movbe) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_MOVBE; if (info.features.sse4_1) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSE4_1; if (info.features.sse4_2) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSE4_2; if (info.features.aes) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AES_NI; if (info.features.avx) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AVX; if (info.features.rdrnd) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_RDRAND; if (info.features.avx2) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AVX2; if (info.features.sha) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SHA_NI; #elif defined(CPU_FEATURES_ARCH_MIPS) MipsInfo info = GetMipsInfo(); if (info.features.r6) g_cpuFeatures |= ANDROID_CPU_MIPS_FEATURE_R6; if (info.features.msa) g_cpuFeatures |= ANDROID_CPU_MIPS_FEATURE_MSA; #elif defined(CPU_FEATURES_ARCH_AARCH64) Aarch64Info info = GetAarch64Info(); if (info.features.fp) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_FP; if (info.features.asimd) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_ASIMD; if (info.features.aes) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_AES; if (info.features.pmull) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_PMULL; if (info.features.sha1) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_SHA1; if (info.features.sha2) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_SHA2; if (info.features.crc32) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_CRC32; #endif } AndroidCpuFamily android_getCpuFamily(void) { #if defined(CPU_FEATURES_ARCH_ARM) return ANDROID_CPU_FAMILY_ARM; #elif defined(CPU_FEATURES_ARCH_X86_32) return ANDROID_CPU_FAMILY_X86; #elif defined(CPU_FEATURES_ARCH_MIPS64) return ANDROID_CPU_FAMILY_MIPS64; #elif defined(CPU_FEATURES_ARCH_MIPS32) return ANDROID_CPU_FAMILY_MIPS; #elif defined(CPU_FEATURES_ARCH_AARCH64) return ANDROID_CPU_FAMILY_ARM64; #elif defined(CPU_FEATURES_ARCH_X86_64) return ANDROID_CPU_FAMILY_X86_64; #else return ANDROID_CPU_FAMILY_UNKNOWN; #endif } uint64_t android_getCpuFeatures(void) { pthread_once(&g_once, android_cpuInit); return g_cpuFeatures; } int android_getCpuCount(void) { pthread_once(&g_once, android_cpuInit); return g_cpuCount; } static void android_cpuInitDummy(void) { g_inited = 1; } int android_setCpu(int cpu_count, uint64_t cpu_features) { /* Fail if the library was already initialized. */ if (g_inited) return 0; g_cpuCount = (cpu_count <= 0 ? 1 : cpu_count); g_cpuFeatures = cpu_features; pthread_once(&g_once, android_cpuInitDummy); return 1; } #ifdef CPU_FEATURES_ARCH_ARM uint32_t android_getCpuIdArm(void) { pthread_once(&g_once, android_cpuInit); return g_cpuIdArm; } int android_setCpuArm(int cpu_count, uint64_t cpu_features, uint32_t cpu_id) { if (!android_setCpu(cpu_count, cpu_features)) return 0; g_cpuIdArm = cpu_id; return 1; } #endif // CPU_FEATURES_ARCH_ARM cpu-features-0.9.0/ndk_compat/cpu-features.h000066400000000000000000000264571450057454500210450ustar00rootroot00000000000000/* * Copyright (C) 2010 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef GOOGLE_CPU_FEATURES_H #define GOOGLE_CPU_FEATURES_H #include #include __BEGIN_DECLS /* A list of valid values returned by android_getCpuFamily(). * They describe the CPU Architecture of the current process. */ typedef enum { ANDROID_CPU_FAMILY_UNKNOWN = 0, ANDROID_CPU_FAMILY_ARM, ANDROID_CPU_FAMILY_X86, ANDROID_CPU_FAMILY_MIPS, ANDROID_CPU_FAMILY_ARM64, ANDROID_CPU_FAMILY_X86_64, ANDROID_CPU_FAMILY_MIPS64, ANDROID_CPU_FAMILY_MAX /* do not remove */ } AndroidCpuFamily; /* Return the CPU family of the current process. * * Note that this matches the bitness of the current process. I.e. when * running a 32-bit binary on a 64-bit capable CPU, this will return the * 32-bit CPU family value. */ extern AndroidCpuFamily android_getCpuFamily(void); /* Return a bitmap describing a set of optional CPU features that are * supported by the current device's CPU. The exact bit-flags returned * depend on the value returned by android_getCpuFamily(). See the * documentation for the ANDROID_CPU_*_FEATURE_* flags below for details. */ extern uint64_t android_getCpuFeatures(void); /* The list of feature flags for ANDROID_CPU_FAMILY_ARM that can be * recognized by the library (see note below for 64-bit ARM). Value details * are: * * VFPv2: * CPU supports the VFPv2 instruction set. Many, but not all, ARMv6 CPUs * support these instructions. VFPv2 is a subset of VFPv3 so this will * be set whenever VFPv3 is set too. * * ARMv7: * CPU supports the ARMv7-A basic instruction set. * This feature is mandated by the 'armeabi-v7a' ABI. * * VFPv3: * CPU supports the VFPv3-D16 instruction set, providing hardware FPU * support for single and double precision floating point registers. * Note that only 16 FPU registers are available by default, unless * the D32 bit is set too. This feature is also mandated by the * 'armeabi-v7a' ABI. * * VFP_D32: * CPU VFP optional extension that provides 32 FPU registers, * instead of 16. Note that ARM mandates this feature is the 'NEON' * feature is implemented by the CPU. * * NEON: * CPU FPU supports "ARM Advanced SIMD" instructions, also known as * NEON. Note that this mandates the VFP_D32 feature as well, per the * ARM Architecture specification. * * VFP_FP16: * Half-width floating precision VFP extension. If set, the CPU * supports instructions to perform floating-point operations on * 16-bit registers. This is part of the VFPv4 specification, but * not mandated by any Android ABI. * * VFP_FMA: * Fused multiply-accumulate VFP instructions extension. Also part of * the VFPv4 specification, but not mandated by any Android ABI. * * NEON_FMA: * Fused multiply-accumulate NEON instructions extension. Optional * extension from the VFPv4 specification, but not mandated by any * Android ABI. * * IDIV_ARM: * Integer division available in ARM mode. Only available * on recent CPUs (e.g. Cortex-A15). * * IDIV_THUMB2: * Integer division available in Thumb-2 mode. Only available * on recent CPUs (e.g. Cortex-A15). * * iWMMXt: * Optional extension that adds MMX registers and operations to an * ARM CPU. This is only available on a few XScale-based CPU designs * sold by Marvell. Pretty rare in practice. * * AES: * CPU supports AES instructions. These instructions are only * available for 32-bit applications running on ARMv8 CPU. * * CRC32: * CPU supports CRC32 instructions. These instructions are only * available for 32-bit applications running on ARMv8 CPU. * * SHA2: * CPU supports SHA2 instructions. These instructions are only * available for 32-bit applications running on ARMv8 CPU. * * SHA1: * CPU supports SHA1 instructions. These instructions are only * available for 32-bit applications running on ARMv8 CPU. * * PMULL: * CPU supports 64-bit PMULL and PMULL2 instructions. These * instructions are only available for 32-bit applications * running on ARMv8 CPU. * * If you want to tell the compiler to generate code that targets one of * the feature set above, you should probably use one of the following * flags (for more details, see technical note at the end of this file): * * -mfpu=vfp * -mfpu=vfpv2 * These are equivalent and tell GCC to use VFPv2 instructions for * floating-point operations. Use this if you want your code to * run on *some* ARMv6 devices, and any ARMv7-A device supported * by Android. * * Generated code requires VFPv2 feature. * * -mfpu=vfpv3-d16 * Tell GCC to use VFPv3 instructions (using only 16 FPU registers). * This should be generic code that runs on any CPU that supports the * 'armeabi-v7a' Android ABI. Note that no ARMv6 CPU supports this. * * Generated code requires VFPv3 feature. * * -mfpu=vfpv3 * Tell GCC to use VFPv3 instructions with 32 FPU registers. * Generated code requires VFPv3|VFP_D32 features. * * -mfpu=neon * Tell GCC to use VFPv3 instructions with 32 FPU registers, and * also support NEON intrinsics (see ). * Generated code requires VFPv3|VFP_D32|NEON features. * * -mfpu=vfpv4-d16 * Generated code requires VFPv3|VFP_FP16|VFP_FMA features. * * -mfpu=vfpv4 * Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32 features. * * -mfpu=neon-vfpv4 * Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32|NEON|NEON_FMA * features. * * -mcpu=cortex-a7 * -mcpu=cortex-a15 * Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32| * NEON|NEON_FMA|IDIV_ARM|IDIV_THUMB2 * This flag implies -mfpu=neon-vfpv4. * * -mcpu=iwmmxt * Allows the use of iWMMXt instrinsics with GCC. * * IMPORTANT NOTE: These flags should only be tested when * android_getCpuFamily() returns ANDROID_CPU_FAMILY_ARM, i.e. this is a * 32-bit process. * * When running a 64-bit ARM process on an ARMv8 CPU, * android_getCpuFeatures() will return a different set of bitflags */ enum { ANDROID_CPU_ARM_FEATURE_ARMv7 = (1 << 0), ANDROID_CPU_ARM_FEATURE_VFPv3 = (1 << 1), ANDROID_CPU_ARM_FEATURE_NEON = (1 << 2), ANDROID_CPU_ARM_FEATURE_LDREX_STREX = (1 << 3), ANDROID_CPU_ARM_FEATURE_VFPv2 = (1 << 4), ANDROID_CPU_ARM_FEATURE_VFP_D32 = (1 << 5), ANDROID_CPU_ARM_FEATURE_VFP_FP16 = (1 << 6), ANDROID_CPU_ARM_FEATURE_VFP_FMA = (1 << 7), ANDROID_CPU_ARM_FEATURE_NEON_FMA = (1 << 8), ANDROID_CPU_ARM_FEATURE_IDIV_ARM = (1 << 9), ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2 = (1 << 10), ANDROID_CPU_ARM_FEATURE_iWMMXt = (1 << 11), ANDROID_CPU_ARM_FEATURE_AES = (1 << 12), ANDROID_CPU_ARM_FEATURE_PMULL = (1 << 13), ANDROID_CPU_ARM_FEATURE_SHA1 = (1 << 14), ANDROID_CPU_ARM_FEATURE_SHA2 = (1 << 15), ANDROID_CPU_ARM_FEATURE_CRC32 = (1 << 16), }; /* The bit flags corresponding to the output of android_getCpuFeatures() * when android_getCpuFamily() returns ANDROID_CPU_FAMILY_ARM64. Value details * are: * * FP: * CPU has Floating-point unit. * * ASIMD: * CPU has Advanced SIMD unit. * * AES: * CPU supports AES instructions. * * CRC32: * CPU supports CRC32 instructions. * * SHA2: * CPU supports SHA2 instructions. * * SHA1: * CPU supports SHA1 instructions. * * PMULL: * CPU supports 64-bit PMULL and PMULL2 instructions. */ enum { ANDROID_CPU_ARM64_FEATURE_FP = (1 << 0), ANDROID_CPU_ARM64_FEATURE_ASIMD = (1 << 1), ANDROID_CPU_ARM64_FEATURE_AES = (1 << 2), ANDROID_CPU_ARM64_FEATURE_PMULL = (1 << 3), ANDROID_CPU_ARM64_FEATURE_SHA1 = (1 << 4), ANDROID_CPU_ARM64_FEATURE_SHA2 = (1 << 5), ANDROID_CPU_ARM64_FEATURE_CRC32 = (1 << 6), }; /* The bit flags corresponding to the output of android_getCpuFeatures() * when android_getCpuFamily() returns ANDROID_CPU_FAMILY_X86 or * ANDROID_CPU_FAMILY_X86_64. */ enum { ANDROID_CPU_X86_FEATURE_SSSE3 = (1 << 0), ANDROID_CPU_X86_FEATURE_POPCNT = (1 << 1), ANDROID_CPU_X86_FEATURE_MOVBE = (1 << 2), ANDROID_CPU_X86_FEATURE_SSE4_1 = (1 << 3), ANDROID_CPU_X86_FEATURE_SSE4_2 = (1 << 4), ANDROID_CPU_X86_FEATURE_AES_NI = (1 << 5), ANDROID_CPU_X86_FEATURE_AVX = (1 << 6), ANDROID_CPU_X86_FEATURE_RDRAND = (1 << 7), ANDROID_CPU_X86_FEATURE_AVX2 = (1 << 8), ANDROID_CPU_X86_FEATURE_SHA_NI = (1 << 9), }; /* The bit flags corresponding to the output of android_getCpuFeatures() * when android_getCpuFamily() returns ANDROID_CPU_FAMILY_MIPS * or ANDROID_CPU_FAMILY_MIPS64. Values are: * * R6: * CPU executes MIPS Release 6 instructions natively, and * supports obsoleted R1..R5 instructions only via kernel traps. * * MSA: * CPU supports Mips SIMD Architecture instructions. */ enum { ANDROID_CPU_MIPS_FEATURE_R6 = (1 << 0), ANDROID_CPU_MIPS_FEATURE_MSA = (1 << 1), }; /* Return the number of CPU cores detected on this device. * Please note the current implementation supports up to 32 cpus. */ extern int android_getCpuCount(void); /* The following is used to force the CPU count and features * mask in sandboxed processes. Under 4.1 and higher, these processes * cannot access /proc, which is the only way to get information from * the kernel about the current hardware (at least on ARM). * * It _must_ be called only once, and before any android_getCpuXXX * function, any other case will fail. * * This function return 1 on success, and 0 on failure. */ extern int android_setCpu(int cpu_count, uint64_t cpu_features); #ifdef __arm__ /* Retrieve the ARM 32-bit CPUID value from the kernel. * Note that this cannot work on sandboxed processes under 4.1 and * higher, unless you called android_setCpuArm() before. */ extern uint32_t android_getCpuIdArm(void); /* An ARM-specific variant of android_setCpu() that also allows you * to set the ARM CPUID field. */ extern int android_setCpuArm(int cpu_count, uint64_t cpu_features, uint32_t cpu_id); #endif __END_DECLS #endif /* GOOGLE_CPU_FEATURES_H */ cpu-features-0.9.0/ndk_compat/ndk-compat-test.c000066400000000000000000000005551450057454500214360ustar00rootroot00000000000000#include #include "cpu-features.h" int main() { printf("android_getCpuFamily()=%d\n", android_getCpuFamily()); printf("android_getCpuFeatures()=0x%08llx\n", android_getCpuFeatures()); printf("android_getCpuCount()=%d\n", android_getCpuCount()); #ifdef __arm__ printf("android_getCpuIdArm()=0x%04x\n", android_getCpuIdArm()); #endif //__arm__ } cpu-features-0.9.0/scripts/000077500000000000000000000000001450057454500156235ustar00rootroot00000000000000cpu-features-0.9.0/scripts/generate_badges.d000077500000000000000000000107451450057454500211010ustar00rootroot00000000000000#!/usr/bin/env -S docker run --rm -v ${PWD}/scripts:/scripts -v ${PWD}/.github/workflows:/.github/workflows dlanguage/dmd dmd -run /scripts/generate_badges.d // To run this script: // cd /path/to/cpu_features // ./scripts/generate_badges.d import std.algorithm : each, map, cartesianProduct, filter, joiner, sort, uniq; import std.array; import std.base64 : Base64; import std.conv : to; import std.file : exists; import std.format; import std.range : chain, only; import std.stdio; import std.string : representation; import std.traits : EnumMembers; immutable string bazel_svg = ``; const string bazel_svg_base64 = Base64.encode(representation(bazel_svg)); enum BuildSystem { CMake, Bazel } enum Cpu { amd64, AArch64, ARM, MIPS, POWER, RISCV, LOONGARCH, s390x, } enum Os { Linux, FreeBSD, MacOS, Windows, } struct Badge { const: Cpu cpu; Os os; BuildSystem build_system; private: string id() { return format("%d%c%d", cast(uint)(os) + 1, cast(char)('a' + cpu), cast(uint)(build_system)); } string link_ref() { return format("[l%s]", id()); } string image_ref() { return format("[i%s]", id()); } string filename() { import std.uni : toLower; return toLower(format("%s_%s_%s.yml", cpu, os, build_system)); } bool enabled() { return exists("../.github/workflows/" ~ filename()); } string append_logo(string url) { final switch (build_system) { case BuildSystem.CMake: return url ~ "&logo=cmake"; case BuildSystem.Bazel: return url ~ "&logo=data:image/svg%2bxml;base64," ~ bazel_svg_base64; } } public: string disabled_image_ref() { return format("[d%d]", cast(uint)(build_system)); } string text() { if (enabled()) return format("[![%s]%s]%s", build_system, image_ref, link_ref); return format("![%s]%s", build_system, disabled_image_ref); } string disabled_image_link() { return append_logo(format("%s: https://img.shields.io/badge/n%%2Fa-lightgrey?", disabled_image_ref)); } string link_decl() { return format("%s: https://github.com/google/cpu_features/actions/workflows/%s", link_ref, filename()); } string image_decl() { return append_logo(format("%s: https://img.shields.io/github/actions/workflow/status/google/cpu_features/%s?branch=main&event=push&label=", image_ref, filename())); } } auto tableHeader(in Os[] oses) { return chain(only(""), oses.map!(to!string)).array; } auto tableAlignment(in Os[] oses) { return chain(only(":--"), oses.map!(v => "--:")).array; } auto tableCell(Range)(in Os os, in Cpu cpu, Range badges) { return badges.filter!(b => b.cpu == cpu && b.os == os) .map!(b => b.text()) .joiner("
").to!string; } auto tableRow(Range)(in Cpu cpu, in Os[] oses, Range badges) { return chain(only(cpu.to!string), oses.map!(os => tableCell(os, cpu, badges))).array; } auto tableRows(Range)(in Os[] oses, in Cpu[] cpus, Range badges) { return cpus.map!(cpu => tableRow(cpu, oses, badges)).array; } auto table(Range)(in Os[] oses, in Cpu[] cpus, Range badges) { return chain(only(tableHeader(oses)), only(tableAlignment(oses)), tableRows(oses, cpus, badges)); } void main() { immutable allCpus = [EnumMembers!Cpu]; immutable allOses = [EnumMembers!Os]; immutable allBuildSystems = [EnumMembers!BuildSystem]; auto badges = cartesianProduct(allCpus, allOses, allBuildSystems).map!( t => Badge(t[0], t[1], t[2])); writefln("%(|%-( %s |%) |\n%) |", table(allOses, allCpus, badges)); writeln(); badges.filter!(b => !b.enabled) .map!(b => b.disabled_image_link()) .array .sort .uniq .each!writeln; badges.filter!(b => b.enabled) .map!(b => [b.link_decl(), b.image_decl()]) .joiner().array.sort.uniq.each!writeln; } cpu-features-0.9.0/scripts/make_release.sh000077500000000000000000000040071450057454500206000ustar00rootroot00000000000000#!/usr/bin/env bash set -e # Fail on error set -u # Treat unset variables as an error and exit immediately ACTION='\033[1;90m' FINISHED='\033[1;96m' NOCOLOR='\033[0m' ERROR='\033[0;31m' echo -e "${ACTION}Checking environnement${NOCOLOR}" if [[ ! $1 =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] then echo -e "${ERROR}Invalid version number. Aborting. ${NOCOLOR}" exit 1 fi declare -r VERSION=$1 declare -r GIT_TAG="v$1" BRANCH=$(git rev-parse --abbrev-ref HEAD) if [[ "${BRANCH}" != "main" ]] then echo -e "${ERROR}Not on main. Aborting. ${NOCOLOR}" echo exit 1 fi git fetch HEADHASH=$(git rev-parse HEAD) UPSTREAMHASH=$(git rev-parse main@{upstream}) if [[ "${HEADHASH}" != "${UPSTREAMHASH}" ]] then echo -e "${ERROR}Not up to date with origin. Aborting.${NOCOLOR}" echo exit 1 fi git update-index -q --refresh if ! git diff-index --quiet HEAD -- then echo -e "${ERROR}Branch has uncommited changes. Aborting.${NOCOLOR}" exit 1 fi if [ ! -z "$(git ls-files --exclude-standard --others)" ] then echo -e "${ERROR}Branch has untracked files. Aborting.${NOCOLOR}" exit 1 fi declare -r LATEST_GIT_TAG=$(git describe --tags --abbrev=0) declare -r LATEST_VERSION=${LATEST_GIT_TAG#"v"} if ! dpkg --compare-versions "${VERSION}" "gt" "${LATEST_VERSION}" then echo -e "${ERROR}Invalid version ${VERSION} <= ${LATEST_VERSION} (latest). Aborting.${NOCOLOR}" exit 1 fi echo -e "${ACTION}Modifying CMakeLists.txt${NOCOLOR}" sed -i "s/CpuFeatures VERSION ${LATEST_VERSION}/CpuFeatures VERSION ${VERSION}/g" CMakeLists.txt echo -e "${ACTION}Commit new revision${NOCOLOR}" git add CMakeLists.txt git commit -m"Release ${GIT_TAG}" echo -e "${ACTION}Create new tag${NOCOLOR}" git tag ${GIT_TAG} echo -e "${FINISHED}Manual steps:${NOCOLOR}" echo -e "${FINISHED} - Push the tag upstream 'git push origin ${GIT_TAG}'${NOCOLOR}" echo -e "${FINISHED} - Create a new release https://github.com/google/cpu_features/releases/new${NOCOLOR}" echo -e "${FINISHED} - Update the Release Notes 'gren release --override'${NOCOLOR}" cpu-features-0.9.0/scripts/run_integration.sh000077500000000000000000000366401450057454500214020ustar00rootroot00000000000000#!/usr/bin/env bash set -eo pipefail function extract() { echo "Extracting ${1}..." case $1 in *.tar.bz2) tar xjf "$1" ;; *.tar.xz) tar xJf "$1" ;; *.tar.gz) tar xzf "$1" ;; *) >&2 echo "don't know how to extract '$1'..." exit 1 esac } function unpack() { mkdir -p "${ARCHIVE_DIR}" cd "${ARCHIVE_DIR}" || exit 2 local -r URL=$1 local -r RELATIVE_DIR=$2 local -r DESTINATION="${ARCHIVE_DIR}/${RELATIVE_DIR}" if [[ ! -d "${DESTINATION}" ]] ; then echo "Downloading ${URL}..." local -r ARCHIVE_NAME=$(basename "${URL}") [[ -f "${ARCHIVE_NAME}" ]] || wget --no-verbose "${URL}" extract "${ARCHIVE_NAME}" rm -f "${ARCHIVE_NAME}" fi } function install_qemu() { if [[ "${QEMU_ARCH}" == "DISABLED" ]]; then >&2 echo 'QEMU is disabled !' return 0 fi local -r QEMU_VERSION=${QEMU_VERSION:=7.1.0} local -r QEMU_TARGET=${QEMU_ARCH}-linux-user if echo "${QEMU_VERSION} ${QEMU_TARGET}" | cmp --silent "${QEMU_INSTALL}/.build" -; then echo "qemu ${QEMU_VERSION} up to date!" return 0 fi echo "QEMU_VERSION: ${QEMU_VERSION}" echo "QEMU_TARGET: ${QEMU_TARGET}" rm -rf "${QEMU_INSTALL}" # Checking for a tarball before downloading makes testing easier :-) local -r QEMU_URL="http://wiki.qemu-project.org/download/qemu-${QEMU_VERSION}.tar.xz" local -r QEMU_DIR="qemu-${QEMU_VERSION}" unpack ${QEMU_URL} ${QEMU_DIR} cd ${QEMU_DIR} || exit 2 # Qemu (meson based build) depends on: pkgconf, libglib2.0, python3, ninja ./configure \ --prefix="${QEMU_INSTALL}" \ --target-list="${QEMU_TARGET}" \ --audio-drv-list= \ --disable-brlapi \ --disable-curl \ --disable-curses \ --disable-docs \ --disable-gcrypt \ --disable-gnutls \ --disable-gtk \ --disable-libnfs \ --disable-libssh \ --disable-nettle \ --disable-opengl \ --disable-sdl \ --disable-virglrenderer \ --disable-vte # wrapper on ninja make -j8 make install echo "$QEMU_VERSION $QEMU_TARGET" > "${QEMU_INSTALL}/.build" } function assert_defined(){ if [[ -z "${!1}" ]]; then >&2 echo "Variable '${1}' must be defined" exit 1 fi } function clean_build() { # Cleanup previous build rm -rf "${BUILD_DIR}" mkdir -p "${BUILD_DIR}" } function expand_linaro_config() { #ref: https://releases.linaro.org/components/toolchain/binaries/ local -r LINARO_VERSION=7.5-2019.12 local -r LINARO_ROOT_URL=https://releases.linaro.org/components/toolchain/binaries/${LINARO_VERSION} local -r GCC_VERSION=7.5.0-2019.12 local -r GCC_URL=${LINARO_ROOT_URL}/${TARGET}/gcc-linaro-${GCC_VERSION}-x86_64_${TARGET}.tar.xz local -r GCC_RELATIVE_DIR="gcc-linaro-${GCC_VERSION}-x86_64_${TARGET}" unpack "${GCC_URL}" "${GCC_RELATIVE_DIR}" local -r SYSROOT_VERSION=2.25-2019.12 local -r SYSROOT_URL=${LINARO_ROOT_URL}/${TARGET}/sysroot-glibc-linaro-${SYSROOT_VERSION}-${TARGET}.tar.xz local -r SYSROOT_RELATIVE_DIR=sysroot-glibc-linaro-${SYSROOT_VERSION}-${TARGET} unpack "${SYSROOT_URL}" "${SYSROOT_RELATIVE_DIR}" local -r SYSROOT_DIR=${ARCHIVE_DIR}/${SYSROOT_RELATIVE_DIR} local -r STAGING_DIR=${ARCHIVE_DIR}/${SYSROOT_RELATIVE_DIR}-stage local -r GCC_DIR=${ARCHIVE_DIR}/${GCC_RELATIVE_DIR} # Write a Toolchain file # note: This is manadatory to use a file in order to have the CMake variable # 'CMAKE_CROSSCOMPILING' set to TRUE. # ref: https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-linux cat >"$TOOLCHAIN_FILE" <&2 echo 'unknown power platform' exit 1 ;; esac local -r TOOLCHAIN_RELATIVE_DIR="${TARGET}" unpack "${TOOLCHAIN_URL}" "${TOOLCHAIN_RELATIVE_DIR}" local -r EXTRACT_DIR="${ARCHIVE_DIR}/$(basename ${TOOLCHAIN_URL%.tar.bz2})" local -r TOOLCHAIN_DIR=${ARCHIVE_DIR}/${TOOLCHAIN_RELATIVE_DIR} if [[ -d "${EXTRACT_DIR}" ]]; then mv "${EXTRACT_DIR}" "${TOOLCHAIN_DIR}" fi local -r SYSROOT_DIR="${TOOLCHAIN_DIR}/${GCC_PREFIX}-buildroot-linux-gnu/sysroot" #local -r STAGING_DIR=${SYSROOT_DIR}-stage # Write a Toolchain file # note: This is manadatory to use a file in order to have the CMake variable # 'CMAKE_CROSSCOMPILING' set to TRUE. # ref: https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-linux cat >"${TOOLCHAIN_FILE}" <&2 echo 'unknown mips platform' exit 1 ;; esac local -r SYSROOT_DIR=${GCC_DIR}/sysroot local -r STAGING_DIR=${SYSROOT_DIR}-stage # Write a Toolchain file # note: This is manadatory to use a file in order to have the CMake variable # 'CMAKE_CROSSCOMPILING' set to TRUE. # ref: https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-linux cat >"${TOOLCHAIN_FILE}" <&2 echo "QEMU is disabled for ${TARGET}" return fi install_qemu RUN_CMD="${QEMU_INSTALL}/bin/qemu-${QEMU_ARCH} ${QEMU_ARGS[*]}" cd "${BUILD_DIR}" || exit 2 declare -a TEST_BINARIES=() TEST_BINARIES+=($(find "${BUILD_DIR}"/test -executable -type f)) TEST_BINARIES+=($(find "${BUILD_DIR}" -maxdepth 1 -executable -type f)) set -x set -e for test_binary in ${TEST_BINARIES[*]} ; do ${RUN_CMD} "${test_binary}" done set +e set +x } function usage() { local -r NAME=$(basename "$0") echo -e "$NAME - Build using a cross toolchain. SYNOPSIS \t$NAME [-h|--help] [toolchain|build|qemu|test|all] DESCRIPTION \tCross compile using a cross toolchain. \tYou MUST define the following variables before running this script: \t* TARGET: \t\tx86_64 \t\taarch64 aarch64be (bootlin) \t\taarch64-linux-gnu aarch64_be-linux-gnu (linaro) \t\tarm-linux-gnueabihf armv8l-linux-gnueabihf arm-linux-gnueabi (linaro) \t\tarmeb-linux-gnueabihf armeb-linux-gnueabi (linaro) \t\tmips32 mips32el (codespace) \t\tmips64 mips64el (codespace) \t\tppc (bootlin) \t\tppc64 ppc64le (bootlin) \t\triscv32 riscv64 (bootlin) \t\ts390x (bootlin) OPTIONS \t-h --help: show this help text \ttoolchain: download, unpack toolchain and generate CMake toolchain file \tbuild: toolchain + build the project using the toolchain file (note: remove previous build dir) \tqemu: download, unpack and build qemu \ttest: qemu + run all executable using qemu (note: don't build !) \tall: build + test (default) EXAMPLES * Using export: export TARGET=aarch64-linux-gnu $0 * One-liner: TARGET=aarch64-linux-gnu $0" } # Main function main() { case ${1} in -h | --help) usage; exit ;; esac assert_defined TARGET declare -r PROJECT_DIR="$(cd -P -- "$(dirname -- "$0")/.." && pwd -P)" declare -r ARCHIVE_DIR="${PROJECT_DIR}/build_cross/archives" declare -r BUILD_DIR="${PROJECT_DIR}/build_cross/${TARGET}" declare -r TOOLCHAIN_FILE=${ARCHIVE_DIR}/toolchain_${TARGET}.cmake echo "Target: '${TARGET}'" echo "Project dir: '${PROJECT_DIR}'" echo "Archive dir: '${ARCHIVE_DIR}'" echo "Build dir: '${BUILD_DIR}'" echo "toolchain file: '${TOOLCHAIN_FILE}'" declare -a CMAKE_DEFAULT_ARGS=( -G ${CMAKE_GENERATOR:-"Ninja"} ) declare -a CMAKE_ADDITIONAL_ARGS=() declare -a QEMU_ARGS=() case ${TARGET} in x86_64) declare -r QEMU_ARCH=x86_64 ;; arm-linux-gnueabihf | armv8l-linux-gnueabihf | arm-linux-gnueabi) expand_linaro_config declare -r QEMU_ARCH=arm ;; armeb-linux-gnueabihf | armeb-linux-gnueabi) expand_linaro_config declare -r QEMU_ARCH=DISABLED ;; aarch64-linux-gnu) expand_linaro_config declare -r QEMU_ARCH=aarch64 ;; aarch64_be-linux-gnu) expand_linaro_config declare -r QEMU_ARCH=aarch64_be ;; aarch64) expand_bootlin_config declare -r QEMU_ARCH=aarch64 ;; aarch64be) expand_bootlin_config declare -r QEMU_ARCH=aarch64_be ;; mips32) expand_codescape_config declare -r QEMU_ARCH=mips ;; mips32el) expand_codescape_config declare -r QEMU_ARCH=mipsel ;; mips64) expand_codescape_config declare -r QEMU_ARCH=mips64 ;; mips64el) expand_codescape_config declare -r QEMU_ARCH=mips64el ;; ppc64le) expand_bootlin_config declare -r QEMU_ARCH=ppc64le ;; ppc64) expand_bootlin_config declare -r QEMU_ARCH=ppc64 ;; ppc) expand_bootlin_config declare -r QEMU_ARCH=ppc ;; riscv32) expand_bootlin_config declare -r QEMU_ARCH=riscv32 ;; riscv64) expand_bootlin_config declare -r QEMU_ARCH=riscv64 ;; s390x) expand_bootlin_config declare -r QEMU_ARCH=s390x ;; *) >&2 echo "Unknown TARGET '${TARGET}'..." exit 1 ;; esac declare -r QEMU_INSTALL=${ARCHIVE_DIR}/qemu-${QEMU_ARCH} case ${1} in toolchain) exit ;; build) build ;; qemu) install_qemu ;; test) run_test ;; *) build run_test ;; esac } main "${1:-all}" cpu-features-0.9.0/scripts/test_integration.sh000077500000000000000000000034171450057454500215510ustar00rootroot00000000000000#!/usr/bin/env bash # Toolchains for little-endian, 64-bit ARMv8 for GNU/Linux systems function set_aarch64-linux-gnu() { export TARGET=aarch64-linux-gnu } # Toolchains for little-endian, hard-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems function set_arm-linux-gnueabihf() { export TARGET=arm-linux-gnueabihf } # Toolchains for little-endian, 32-bit ARMv8 for GNU/Linux systems function set_armv8l-linux-gnueabihf() { export TARGET=armv8l-linux-gnueabihf } # Toolchains for little-endian, soft-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems function set_arm-linux-gnueabi() { export TARGET=arm-linux-gnueabi } # Toolchains for big-endian, 64-bit ARMv8 for GNU/Linux systems function set_aarch64_be-linux-gnu() { export TARGET=aarch64_be-linux-gnu } # Toolchains for big-endian, hard-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems function set_armeb-linux-gnueabihf() { export TARGET=armeb-linux-gnueabihf } # Toolchains for big-endian, soft-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems function set_armeb-linux-gnueabi() { export TARGET=armeb-linux-gnueabi } function set_mips32() { export TARGET=mips32 } function set_mips32el() { export TARGET=mips32el } function set_mips64() { export TARGET=mips64 } function set_mips64el() { export TARGET=mips64el } function set_x86_64() { export TARGET=x86_64 } ENVIRONMENTS=" set_aarch64-linux-gnu set_arm-linux-gnueabihf set_armv8l-linux-gnueabihf set_arm-linux-gnueabi set_aarch64_be-linux-gnu set_armeb-linux-gnueabihf set_armeb-linux-gnueabi set_mips32 set_mips32el set_mips64 set_mips64el set_x86_64 " set -e for SET_ENVIRONMENT in ${ENVIRONMENTS}; do echo "testing ${SET_ENVIRONMENT}" ${SET_ENVIRONMENT} ./"$(dirname -- "$0")"/run_integration.sh done cpu-features-0.9.0/src/000077500000000000000000000000001450057454500147235ustar00rootroot00000000000000cpu-features-0.9.0/src/copy.inl000066400000000000000000000013401450057454500163770ustar00rootroot00000000000000// Copyright 2021 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. #include static void copy(char *__restrict dst, const char *src, size_t count) { for (size_t i = 0; i < count; ++i) dst[i] = src[i]; } cpu-features-0.9.0/src/define_introspection.inl000066400000000000000000000060661450057454500216510ustar00rootroot00000000000000// 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. // 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. #ifndef INTROSPECTION_PREFIX #error "missing INTROSPECTION_PREFIX" #endif #ifndef INTROSPECTION_ENUM_PREFIX #error "missing INTROSPECTION_ENUM_PREFIX" #endif #ifndef INTROSPECTION_TABLE #error "missing INTROSPECTION_TABLE" #endif #include #define STRINGIZE_(s) #s #define STRINGIZE(s) STRINGIZE_(s) #define FEAT_TYPE_NAME__(X) X##Features #define FEAT_TYPE_NAME_(X) FEAT_TYPE_NAME__(X) #define FEAT_TYPE_NAME FEAT_TYPE_NAME_(INTROSPECTION_PREFIX) #define FEAT_ENUM_NAME__(X) X##FeaturesEnum #define FEAT_ENUM_NAME_(X) FEAT_ENUM_NAME__(X) #define FEAT_ENUM_NAME FEAT_ENUM_NAME_(INTROSPECTION_PREFIX) #define GET_FEAT_ENUM_VALUE__(X) Get##X##FeaturesEnumValue #define GET_FEAT_ENUM_VALUE_(X) GET_FEAT_ENUM_VALUE__(X) #define GET_FEAT_ENUM_VALUE GET_FEAT_ENUM_VALUE_(INTROSPECTION_PREFIX) #define GET_FEAT_ENUM_NAME__(X) Get##X##FeaturesEnumName #define GET_FEAT_ENUM_NAME_(X) GET_FEAT_ENUM_NAME__(X) #define GET_FEAT_ENUM_NAME GET_FEAT_ENUM_NAME_(INTROSPECTION_PREFIX) #define FEAT_ENUM_LAST__(X) X##_LAST_ #define FEAT_ENUM_LAST_(X) FEAT_ENUM_LAST__(X) #define FEAT_ENUM_LAST FEAT_ENUM_LAST_(INTROSPECTION_ENUM_PREFIX) // Generate individual getters and setters. #define LINE(ENUM, NAME, A, B, C) \ static void set_##ENUM(FEAT_TYPE_NAME* features, bool value) { \ features->NAME = value; \ } \ static int get_##ENUM(const FEAT_TYPE_NAME* features) { \ return features->NAME; \ } INTROSPECTION_TABLE #undef LINE // Generate getters table #define LINE(ENUM, NAME, A, B, C) [ENUM] = get_##ENUM, static int (*const kGetters[])(const FEAT_TYPE_NAME*) = {INTROSPECTION_TABLE}; #undef LINE // Generate setters table #define LINE(ENUM, NAME, A, B, C) [ENUM] = set_##ENUM, static void (*const kSetters[])(FEAT_TYPE_NAME*, bool) = {INTROSPECTION_TABLE}; #undef LINE // Implements the `GetXXXFeaturesEnumValue` API. int GET_FEAT_ENUM_VALUE(const FEAT_TYPE_NAME* features, FEAT_ENUM_NAME value) { if (value >= FEAT_ENUM_LAST) return false; return kGetters[value](features); } // Generate feature name table. #define LINE(ENUM, NAME, A, B, C) [ENUM] = STRINGIZE(NAME), static const char* kFeatureNames[] = {INTROSPECTION_TABLE}; #undef LINE // Implements the `GetXXXFeaturesEnumName` API. const char* GET_FEAT_ENUM_NAME(FEAT_ENUM_NAME value) { if (value >= FEAT_ENUM_LAST) return "unknown_feature"; return kFeatureNames[value]; } cpu-features-0.9.0/src/define_introspection_and_hwcaps.inl000066400000000000000000000017611450057454500240350ustar00rootroot00000000000000// 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. // 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 "define_introspection.inl" #include "internal/hwcaps.h" #define LINE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) \ [ENUM] = (HardwareCapabilities){HWCAP, HWCAP2}, static const HardwareCapabilities kHardwareCapabilities[] = { INTROSPECTION_TABLE}; #undef LINE #define LINE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) [ENUM] = CPUINFO_FLAG, static const char* kCpuInfoFlags[] = {INTROSPECTION_TABLE}; #undef LINE cpu-features-0.9.0/src/equals.inl000066400000000000000000000014301450057454500167170ustar00rootroot00000000000000// Copyright 2021 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. #include #include static bool equals(const char *lhs, const char *rhs, size_t count) { for (size_t i = 0; i < count; ++i) if (lhs[i] != rhs[i]) return false; return true; } cpu-features-0.9.0/src/filesystem.c000066400000000000000000000034201450057454500172520ustar00rootroot00000000000000// 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. // 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/filesystem.h" #include #include #include #include #include #if defined(CPU_FEATURES_MOCK_FILESYSTEM) // Implementation will be provided by test/filesystem_for_testing.cc. #elif defined(_MSC_VER) #include int CpuFeatures_OpenFile(const char* filename) { int fd = -1; _sopen_s(&fd, filename, _O_RDONLY, _SH_DENYWR, _S_IREAD); return fd; } void CpuFeatures_CloseFile(int file_descriptor) { _close(file_descriptor); } int CpuFeatures_ReadFile(int file_descriptor, void* buffer, size_t buffer_size) { return _read(file_descriptor, buffer, (unsigned int)buffer_size); } #else #include int CpuFeatures_OpenFile(const char* filename) { int result; do { result = open(filename, O_RDONLY); } while (result == -1L && errno == EINTR); return result; } void CpuFeatures_CloseFile(int file_descriptor) { close(file_descriptor); } int CpuFeatures_ReadFile(int file_descriptor, void* buffer, size_t buffer_size) { int result; do { result = read(file_descriptor, buffer, buffer_size); } while (result == -1L && errno == EINTR); return result; } #endif cpu-features-0.9.0/src/hwcaps.c000066400000000000000000000120711450057454500163550ustar00rootroot00000000000000// 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. // 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/hwcaps.h" #include #include #include "cpu_features_macros.h" #include "internal/filesystem.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); const char* CpuFeatures_GetPlatformPointer(void); const char* CpuFeatures_GetBasePlatformPointer(void); #else // Debug facilities #if defined(NDEBUG) #define D(...) #else #include #define D(...) \ do { \ printf(__VA_ARGS__); \ fflush(stdout); \ } while (0) #endif //////////////////////////////////////////////////////////////////////////////// // Implementation of GetElfHwcapFromGetauxval //////////////////////////////////////////////////////////////////////////////// #define AT_HWCAP 16 #define AT_HWCAP2 26 #define AT_PLATFORM 15 #define AT_BASE_PLATFORM 24 #if defined(HAVE_STRONG_GETAUXVAL) #include static unsigned long GetElfHwcapFromGetauxval(uint32_t hwcap_type) { return getauxval(hwcap_type); } #elif defined(HAVE_DLFCN_H) // On Android we probe the system's C library for a 'getauxval' function and // call it if it exits, or return 0 for failure. This function is available // since API level 18. // // Note that getauxval() can't really be re-implemented here, because its // implementation does not parse /proc/self/auxv. Instead it depends on values // that are passed by the kernel at process-init time to the C runtime // initialization layer. #include 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; dlerror(); // Cleaning error state before calling dlopen. libc_handle = dlopen("libc.so", RTLD_NOW); if (!libc_handle) { D("Could not dlopen() C library: %s\n", dlerror()); return 0; } func = (getauxval_func_t *)dlsym(libc_handle, "getauxval"); if (!func) { D("Could not find getauxval() in C library\n"); } else { // Note: getauxval() returns 0 on failure. Doesn't touch errno. ret = (uint32_t)(*func)(hwcap_type); } dlclose(libc_handle); return ret; } #else #error "This platform does not provide hardware capabilities." #endif // Implementation of GetHardwareCapabilities for OS that provide // GetElfHwcapFromGetauxval(). // Fallback when getauxval is not available, retrieves hwcaps from // "/proc/self/auxv". static uint32_t GetElfHwcapFromProcSelfAuxv(uint32_t hwcap_type) { struct { uint32_t tag; uint32_t value; } entry; uint32_t result = 0; const char filepath[] = "/proc/self/auxv"; const int fd = CpuFeatures_OpenFile(filepath); if (fd < 0) { D("Could not open %s\n", filepath); return 0; } for (;;) { const int ret = CpuFeatures_ReadFile(fd, (char *)&entry, sizeof entry); if (ret < 0) { D("Error while reading %s\n", filepath); break; } // Detect end of list. if (ret == 0 || (entry.tag == 0 && entry.value == 0)) { break; } if (entry.tag == hwcap_type) { result = entry.value; break; } } CpuFeatures_CloseFile(fd); return result; } // Retrieves hardware capabilities by first trying to call getauxval, if not // available falls back to reading "/proc/self/auxv". static unsigned long GetHardwareCapabilitiesFor(uint32_t type) { unsigned long hwcaps = GetElfHwcapFromGetauxval(type); if (!hwcaps) { D("Parsing /proc/self/auxv to extract ELF hwcaps!\n"); hwcaps = GetElfHwcapFromProcSelfAuxv(type); } return hwcaps; } HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void) { HardwareCapabilities capabilities; capabilities.hwcaps = GetHardwareCapabilitiesFor(AT_HWCAP); capabilities.hwcaps2 = GetHardwareCapabilitiesFor(AT_HWCAP2); return capabilities; } const char *CpuFeatures_GetPlatformPointer(void) { return (const char *)GetHardwareCapabilitiesFor(AT_PLATFORM); } const char *CpuFeatures_GetBasePlatformPointer(void) { return (const char *)GetHardwareCapabilitiesFor(AT_BASE_PLATFORM); } #endif // CPU_FEATURES_TEST cpu-features-0.9.0/src/impl_aarch64__base_implementation.inl000066400000000000000000000174321450057454500241450ustar00rootroot00000000000000// Copyright 2021 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. #include #include "cpu_features_macros.h" #include "cpuinfo_aarch64.h" #include "internal/bit_utils.h" #include "internal/filesystem.h" #include "internal/stack_line_reader.h" #include "internal/string_view.h" #if !defined(CPU_FEATURES_ARCH_AARCH64) #error "Cannot compile aarch64_base on a non aarch64 platform." #endif //////////////////////////////////////////////////////////////////////////////// // Definitions for introspection. //////////////////////////////////////////////////////////////////////////////// #define INTROSPECTION_TABLE \ LINE(AARCH64_FP, fp, "fp", AARCH64_HWCAP_FP, 0) \ LINE(AARCH64_ASIMD, asimd, "asimd", AARCH64_HWCAP_ASIMD, 0) \ LINE(AARCH64_EVTSTRM, evtstrm, "evtstrm", AARCH64_HWCAP_EVTSTRM, 0) \ LINE(AARCH64_AES, aes, "aes", AARCH64_HWCAP_AES, 0) \ LINE(AARCH64_PMULL, pmull, "pmull", AARCH64_HWCAP_PMULL, 0) \ LINE(AARCH64_SHA1, sha1, "sha1", AARCH64_HWCAP_SHA1, 0) \ LINE(AARCH64_SHA2, sha2, "sha2", AARCH64_HWCAP_SHA2, 0) \ LINE(AARCH64_CRC32, crc32, "crc32", AARCH64_HWCAP_CRC32, 0) \ LINE(AARCH64_ATOMICS, atomics, "atomics", AARCH64_HWCAP_ATOMICS, 0) \ LINE(AARCH64_FPHP, fphp, "fphp", AARCH64_HWCAP_FPHP, 0) \ LINE(AARCH64_ASIMDHP, asimdhp, "asimdhp", AARCH64_HWCAP_ASIMDHP, 0) \ LINE(AARCH64_CPUID, cpuid, "cpuid", AARCH64_HWCAP_CPUID, 0) \ LINE(AARCH64_ASIMDRDM, asimdrdm, "asimdrdm", AARCH64_HWCAP_ASIMDRDM, 0) \ LINE(AARCH64_JSCVT, jscvt, "jscvt", AARCH64_HWCAP_JSCVT, 0) \ LINE(AARCH64_FCMA, fcma, "fcma", AARCH64_HWCAP_FCMA, 0) \ LINE(AARCH64_LRCPC, lrcpc, "lrcpc", AARCH64_HWCAP_LRCPC, 0) \ LINE(AARCH64_DCPOP, dcpop, "dcpop", AARCH64_HWCAP_DCPOP, 0) \ LINE(AARCH64_SHA3, sha3, "sha3", AARCH64_HWCAP_SHA3, 0) \ LINE(AARCH64_SM3, sm3, "sm3", AARCH64_HWCAP_SM3, 0) \ LINE(AARCH64_SM4, sm4, "sm4", AARCH64_HWCAP_SM4, 0) \ LINE(AARCH64_ASIMDDP, asimddp, "asimddp", AARCH64_HWCAP_ASIMDDP, 0) \ LINE(AARCH64_SHA512, sha512, "sha512", AARCH64_HWCAP_SHA512, 0) \ LINE(AARCH64_SVE, sve, "sve", AARCH64_HWCAP_SVE, 0) \ LINE(AARCH64_ASIMDFHM, asimdfhm, "asimdfhm", AARCH64_HWCAP_ASIMDFHM, 0) \ LINE(AARCH64_DIT, dit, "dit", AARCH64_HWCAP_DIT, 0) \ LINE(AARCH64_USCAT, uscat, "uscat", AARCH64_HWCAP_USCAT, 0) \ LINE(AARCH64_ILRCPC, ilrcpc, "ilrcpc", AARCH64_HWCAP_ILRCPC, 0) \ LINE(AARCH64_FLAGM, flagm, "flagm", AARCH64_HWCAP_FLAGM, 0) \ LINE(AARCH64_SSBS, ssbs, "ssbs", AARCH64_HWCAP_SSBS, 0) \ LINE(AARCH64_SB, sb, "sb", AARCH64_HWCAP_SB, 0) \ LINE(AARCH64_PACA, paca, "paca", AARCH64_HWCAP_PACA, 0) \ LINE(AARCH64_PACG, pacg, "pacg", AARCH64_HWCAP_PACG, 0) \ LINE(AARCH64_DCPODP, dcpodp, "dcpodp", 0, AARCH64_HWCAP2_DCPODP) \ LINE(AARCH64_SVE2, sve2, "sve2", 0, AARCH64_HWCAP2_SVE2) \ LINE(AARCH64_SVEAES, sveaes, "sveaes", 0, AARCH64_HWCAP2_SVEAES) \ LINE(AARCH64_SVEPMULL, svepmull, "svepmull", 0, AARCH64_HWCAP2_SVEPMULL) \ LINE(AARCH64_SVEBITPERM, svebitperm, "svebitperm", 0, \ AARCH64_HWCAP2_SVEBITPERM) \ LINE(AARCH64_SVESHA3, svesha3, "svesha3", 0, AARCH64_HWCAP2_SVESHA3) \ LINE(AARCH64_SVESM4, svesm4, "svesm4", 0, AARCH64_HWCAP2_SVESM4) \ LINE(AARCH64_FLAGM2, flagm2, "flagm2", 0, AARCH64_HWCAP2_FLAGM2) \ LINE(AARCH64_FRINT, frint, "frint", 0, AARCH64_HWCAP2_FRINT) \ LINE(AARCH64_SVEI8MM, svei8mm, "svei8mm", 0, AARCH64_HWCAP2_SVEI8MM) \ LINE(AARCH64_SVEF32MM, svef32mm, "svef32mm", 0, AARCH64_HWCAP2_SVEF32MM) \ LINE(AARCH64_SVEF64MM, svef64mm, "svef64mm", 0, AARCH64_HWCAP2_SVEF64MM) \ LINE(AARCH64_SVEBF16, svebf16, "svebf16", 0, AARCH64_HWCAP2_SVEBF16) \ LINE(AARCH64_I8MM, i8mm, "i8mm", 0, AARCH64_HWCAP2_I8MM) \ LINE(AARCH64_BF16, bf16, "bf16", 0, AARCH64_HWCAP2_BF16) \ LINE(AARCH64_DGH, dgh, "dgh", 0, AARCH64_HWCAP2_DGH) \ LINE(AARCH64_RNG, rng, "rng", 0, AARCH64_HWCAP2_RNG) \ LINE(AARCH64_BTI, bti, "bti", 0, AARCH64_HWCAP2_BTI) \ LINE(AARCH64_MTE, mte, "mte", 0, AARCH64_HWCAP2_MTE) \ LINE(AARCH64_ECV, ecv, "ecv", 0, AARCH64_HWCAP2_ECV) \ LINE(AARCH64_AFP, afp, "afp", 0, AARCH64_HWCAP2_AFP) \ LINE(AARCH64_RPRES, rpres, "rpres", 0, AARCH64_HWCAP2_RPRES) \ LINE(AARCH64_MTE3, mte3, "mte3", 0, AARCH64_HWCAP2_MTE3) \ LINE(AARCH64_SME, sme, "sme", 0, AARCH64_HWCAP2_SME) \ LINE(AARCH64_SME_I16I64, smei16i64, "smei16i64", 0, \ AARCH64_HWCAP2_SME_I16I64) \ LINE(AARCH64_SME_F64F64, smef64f64, "smef64f64", 0, \ AARCH64_HWCAP2_SME_F64F64) \ LINE(AARCH64_SME_I8I32, smei8i32, "smei8i32", 0, AARCH64_HWCAP2_SME_I8I32) \ LINE(AARCH64_SME_F16F32, smef16f32, "smef16f32", 0, \ AARCH64_HWCAP2_SME_F16F32) \ LINE(AARCH64_SME_B16F32, smeb16f32, "smeb16f32", 0, \ AARCH64_HWCAP2_SME_B16F32) \ LINE(AARCH64_SME_F32F32, smef32f32, "smef32f32", 0, \ AARCH64_HWCAP2_SME_F32F32) \ LINE(AARCH64_SME_FA64, smefa64, "smefa64", 0, AARCH64_HWCAP2_SME_FA64) \ LINE(AARCH64_WFXT, wfxt, "wfxt", 0, AARCH64_HWCAP2_WFXT) \ LINE(AARCH64_EBF16, ebf16, "ebf16", 0, AARCH64_HWCAP2_EBF16) \ LINE(AARCH64_SVE_EBF16, sveebf16, "sveebf16", 0, AARCH64_HWCAP2_SVE_EBF16) \ LINE(AARCH64_CSSC, cssc, "cssc", 0, AARCH64_HWCAP2_CSSC) \ LINE(AARCH64_RPRFM, rprfm, "rprfm", 0, AARCH64_HWCAP2_RPRFM) \ LINE(AARCH64_SVE2P1, sve2p1, "sve2p1", 0, AARCH64_HWCAP2_SVE2P1) \ LINE(AARCH64_SME2, sme2, "sme2", 0, AARCH64_HWCAP2_SME2) \ LINE(AARCH64_SME2P1, sme2p1, "sme2p1", 0, AARCH64_HWCAP2_SME2P1) \ LINE(AARCH64_SME_I16I32, smei16i32, "smei16i32", 0, \ AARCH64_HWCAP2_SME_I16I32) \ LINE(AARCH64_SME_BI32I32, smebi32i32, "smebi32i32", 0, \ AARCH64_HWCAP2_SME_BI32I32) \ LINE(AARCH64_SME_B16B16, smeb16b16, "smeb16b16", 0, \ AARCH64_HWCAP2_SME_B16B16) \ LINE(AARCH64_SME_F16F16, smef16f16, "smef16f16", 0, AARCH64_HWCAP2_SME_F16F16) #define INTROSPECTION_PREFIX Aarch64 #define INTROSPECTION_ENUM_PREFIX AARCH64 #include "define_introspection_and_hwcaps.inl" cpu-features-0.9.0/src/impl_aarch64_linux_or_android.c000066400000000000000000000056441450057454500227700ustar00rootroot00000000000000// 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. // 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 "cpu_features_macros.h" #ifdef CPU_FEATURES_ARCH_AARCH64 #if defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID) #include "impl_aarch64__base_implementation.inl" static bool HandleAarch64Line(const LineResult result, Aarch64Info* const info) { StringView line = result.line; StringView key, value; if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) { if (CpuFeatures_StringView_IsEquals(key, str("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"))) { info->variant = CpuFeatures_StringView_ParsePositiveNumber(value); } else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) { info->part = CpuFeatures_StringView_ParsePositiveNumber(value); } else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) { info->revision = CpuFeatures_StringView_ParsePositiveNumber(value); } } return !result.eof; } static void FillProcCpuInfoData(Aarch64Info* const info) { const int fd = CpuFeatures_OpenFile("/proc/cpuinfo"); if (fd >= 0) { StackLineReader reader; StackLineReader_Initialize(&reader, fd); for (;;) { if (!HandleAarch64Line(StackLineReader_NextLine(&reader), info)) { break; } } CpuFeatures_CloseFile(fd); } } static const Aarch64Info kEmptyAarch64Info; Aarch64Info GetAarch64Info(void) { // 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); 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; } #endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID) #endif // CPU_FEATURES_ARCH_AARCH64 cpu-features-0.9.0/src/impl_aarch64_macos_or_iphone.c000066400000000000000000000100501450057454500225600ustar00rootroot00000000000000// Copyright 2021 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. #include "cpu_features_macros.h" #ifdef CPU_FEATURES_ARCH_AARCH64 #if defined(CPU_FEATURES_OS_MACOS) || defined(CPU_FEATURES_OS_IPHONE) #include "impl_aarch64__base_implementation.inl" #if !defined(HAVE_SYSCTLBYNAME) #error "Darwin needs support for sysctlbyname" #endif #include #if defined(CPU_FEATURES_MOCK_SYSCTL_AARCH64) extern bool GetDarwinSysCtlByName(const char*); extern int GetDarwinSysCtlByNameValue(const char* name); #else static int GetDarwinSysCtlByNameValue(const char* name) { int enabled; size_t enabled_len = sizeof(enabled); const int failure = sysctlbyname(name, &enabled, &enabled_len, NULL, 0); return failure ? 0 : enabled; } static bool GetDarwinSysCtlByName(const char* name) { return GetDarwinSysCtlByNameValue(name) != 0; } #endif static const Aarch64Info kEmptyAarch64Info; Aarch64Info GetAarch64Info(void) { Aarch64Info info = kEmptyAarch64Info; // Handling Darwin platform through sysctlbyname. info.implementer = GetDarwinSysCtlByNameValue("hw.cputype"); info.variant = GetDarwinSysCtlByNameValue("hw.cpusubtype"); info.part = GetDarwinSysCtlByNameValue("hw.cpufamily"); info.revision = GetDarwinSysCtlByNameValue("hw.cpusubfamily"); info.features.fp = GetDarwinSysCtlByName("hw.optional.floatingpoint"); info.features.asimd = GetDarwinSysCtlByName("hw.optional.AdvSIMD"); info.features.aes = GetDarwinSysCtlByName("hw.optional.arm.FEAT_AES"); info.features.pmull = GetDarwinSysCtlByName("hw.optional.arm.FEAT_PMULL"); info.features.sha1 = GetDarwinSysCtlByName("hw.optional.arm.FEAT_SHA1"); info.features.sha2 = GetDarwinSysCtlByName("hw.optional.arm.FEAT_SHA256"); info.features.crc32 = GetDarwinSysCtlByName("hw.optional.armv8_crc32"); info.features.atomics = GetDarwinSysCtlByName("hw.optional.arm.FEAT_LSE"); info.features.fphp = GetDarwinSysCtlByName("hw.optional.arm.FEAT_FP16"); info.features.asimdhp = GetDarwinSysCtlByName("hw.optional.arm.AdvSIMD_HPFPCvt"); info.features.asimdrdm = GetDarwinSysCtlByName("hw.optional.arm.FEAT_RDM"); info.features.jscvt = GetDarwinSysCtlByName("hw.optional.arm.FEAT_JSCVT"); info.features.fcma = GetDarwinSysCtlByName("hw.optional.arm.FEAT_FCMA"); info.features.lrcpc = GetDarwinSysCtlByName("hw.optional.arm.FEAT_LRCPC"); info.features.dcpop = GetDarwinSysCtlByName("hw.optional.arm.FEAT_DPB"); info.features.sha3 = GetDarwinSysCtlByName("hw.optional.arm.FEAT_SHA3"); info.features.asimddp = GetDarwinSysCtlByName("hw.optional.arm.FEAT_DotProd"); info.features.sha512 = GetDarwinSysCtlByName("hw.optional.arm.FEAT_SHA512"); info.features.asimdfhm = GetDarwinSysCtlByName("hw.optional.arm.FEAT_FHM"); info.features.dit = GetDarwinSysCtlByName("hw.optional.arm.FEAT_DIT"); info.features.uscat = GetDarwinSysCtlByName("hw.optional.arm.FEAT_LSE2"); info.features.flagm = GetDarwinSysCtlByName("hw.optional.arm.FEAT_FlagM"); info.features.ssbs = GetDarwinSysCtlByName("hw.optional.arm.FEAT_SSBS"); info.features.sb = GetDarwinSysCtlByName("hw.optional.arm.FEAT_SB"); info.features.flagm2 = GetDarwinSysCtlByName("hw.optional.arm.FEAT_FlagM2"); info.features.frint = GetDarwinSysCtlByName("hw.optional.arm.FEAT_FRINTTS"); info.features.i8mm = GetDarwinSysCtlByName("hw.optional.arm.FEAT_I8MM"); info.features.bf16 = GetDarwinSysCtlByName("hw.optional.arm.FEAT_BF16"); info.features.bti = GetDarwinSysCtlByName("hw.optional.arm.FEAT_BTI"); return info; } #endif // defined(CPU_FEATURES_OS_MACOS) || defined(CPU_FEATURES_OS_IPHONE) #endif // CPU_FEATURES_ARCH_AARCH64 cpu-features-0.9.0/src/impl_aarch64_windows.c000066400000000000000000000130361450057454500211150ustar00rootroot00000000000000// Copyright 2023 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. #include "cpu_features_macros.h" #ifdef CPU_FEATURES_ARCH_AARCH64 #ifdef CPU_FEATURES_OS_WINDOWS #include "cpuinfo_aarch64.h" //////////////////////////////////////////////////////////////////////////////// // Definitions for introspection. //////////////////////////////////////////////////////////////////////////////// #define INTROSPECTION_TABLE \ LINE(AARCH64_FP, fp, , , ) \ LINE(AARCH64_ASIMD, asimd, , , ) \ LINE(AARCH64_EVTSTRM, evtstrm, , , ) \ LINE(AARCH64_AES, aes, , , ) \ LINE(AARCH64_PMULL, pmull, , , ) \ LINE(AARCH64_SHA1, sha1, , , ) \ LINE(AARCH64_SHA2, sha2, , , ) \ LINE(AARCH64_CRC32, crc32, , , ) \ LINE(AARCH64_ATOMICS, atomics, , , ) \ LINE(AARCH64_FPHP, fphp, , , ) \ LINE(AARCH64_ASIMDHP, asimdhp, , , ) \ LINE(AARCH64_CPUID, cpuid, , , ) \ LINE(AARCH64_ASIMDRDM, asimdrdm, , , ) \ LINE(AARCH64_JSCVT, jscvt, , , ) \ LINE(AARCH64_FCMA, fcma, , , ) \ LINE(AARCH64_LRCPC, lrcpc, , , ) \ LINE(AARCH64_DCPOP, dcpop, , , ) \ LINE(AARCH64_SHA3, sha3, , , ) \ LINE(AARCH64_SM3, sm3, , , ) \ LINE(AARCH64_SM4, sm4, , , ) \ LINE(AARCH64_ASIMDDP, asimddp, , , ) \ LINE(AARCH64_SHA512, sha512, , , ) \ LINE(AARCH64_SVE, sve, , , ) \ LINE(AARCH64_ASIMDFHM, asimdfhm, , , ) \ LINE(AARCH64_DIT, dit, , , ) \ LINE(AARCH64_USCAT, uscat, , , ) \ LINE(AARCH64_ILRCPC, ilrcpc, , , ) \ LINE(AARCH64_FLAGM, flagm, , , ) \ LINE(AARCH64_SSBS, ssbs, , , ) \ LINE(AARCH64_SB, sb, , , ) \ LINE(AARCH64_PACA, paca, , , ) \ LINE(AARCH64_PACG, pacg, , , ) \ LINE(AARCH64_DCPODP, dcpodp, , , ) \ LINE(AARCH64_SVE2, sve2, , , ) \ LINE(AARCH64_SVEAES, sveaes, , , ) \ LINE(AARCH64_SVEPMULL, svepmull, , , ) \ LINE(AARCH64_SVEBITPERM, svebitperm, , , ) \ LINE(AARCH64_SVESHA3, svesha3, , , ) \ LINE(AARCH64_SVESM4, svesm4, , , ) \ LINE(AARCH64_FLAGM2, flagm2, , , ) \ LINE(AARCH64_FRINT, frint, , , ) \ LINE(AARCH64_SVEI8MM, svei8mm, , , ) \ LINE(AARCH64_SVEF32MM, svef32mm, , , ) \ LINE(AARCH64_SVEF64MM, svef64mm, , , ) \ LINE(AARCH64_SVEBF16, svebf16, , , ) \ LINE(AARCH64_I8MM, i8mm, , , ) \ LINE(AARCH64_BF16, bf16, , , ) \ LINE(AARCH64_DGH, dgh, , , ) \ LINE(AARCH64_RNG, rng, , , ) \ LINE(AARCH64_BTI, bti, , , ) \ LINE(AARCH64_MTE, mte, , , ) \ LINE(AARCH64_ECV, ecv, , , ) \ LINE(AARCH64_AFP, afp, , , ) \ LINE(AARCH64_RPRES, rpres, , , ) #define INTROSPECTION_PREFIX Aarch64 #define INTROSPECTION_ENUM_PREFIX AARCH64 #include "define_introspection.inl" //////////////////////////////////////////////////////////////////////////////// // Implementation. //////////////////////////////////////////////////////////////////////////////// #include #include "internal/windows_utils.h" #ifdef CPU_FEATURES_MOCK_CPUID_AARCH64 extern bool GetWindowsIsProcessorFeaturePresent(DWORD); extern WORD GetWindowsNativeSystemInfoProcessorRevision(); #else // CPU_FEATURES_MOCK_CPUID_AARCH64 static bool GetWindowsIsProcessorFeaturePresent(DWORD dwProcessorFeature) { return IsProcessorFeaturePresent(dwProcessorFeature); } static WORD GetWindowsNativeSystemInfoProcessorRevision() { SYSTEM_INFO system_info; GetNativeSystemInfo(&system_info); return system_info.wProcessorRevision; } #endif static const Aarch64Info kEmptyAarch64Info; Aarch64Info GetAarch64Info(void) { Aarch64Info info = kEmptyAarch64Info; info.revision = GetWindowsNativeSystemInfoProcessorRevision(); info.features.fp = GetWindowsIsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE); info.features.asimd = GetWindowsIsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE); info.features.crc32 = GetWindowsIsProcessorFeaturePresent( PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE); info.features.asimddp = GetWindowsIsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE); info.features.jscvt = GetWindowsIsProcessorFeaturePresent( PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE); info.features.lrcpc = GetWindowsIsProcessorFeaturePresent( PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE); info.features.atomics = GetWindowsIsProcessorFeaturePresent( PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE); bool is_crypto_available = GetWindowsIsProcessorFeaturePresent( PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE); info.features.aes = is_crypto_available; info.features.sha1 = is_crypto_available; info.features.sha2 = is_crypto_available; info.features.pmull = is_crypto_available; return info; } #endif // CPU_FEATURES_OS_WINDOWS #endif // CPU_FEATURES_ARCH_AARCH64 cpu-features-0.9.0/src/impl_arm_linux_or_android.c000066400000000000000000000215701450057454500223130ustar00rootroot00000000000000// 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. // 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 "cpu_features_macros.h" #ifdef CPU_FEATURES_ARCH_ARM #if defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID) #include "cpuinfo_arm.h" //////////////////////////////////////////////////////////////////////////////// // Definitions for introspection. //////////////////////////////////////////////////////////////////////////////// #define INTROSPECTION_TABLE \ LINE(ARM_SWP, swp, "swp", ARM_HWCAP_SWP, 0) \ LINE(ARM_HALF, half, "half", ARM_HWCAP_HALF, 0) \ LINE(ARM_THUMB, thumb, "thumb", ARM_HWCAP_THUMB, 0) \ LINE(ARM_26BIT, _26bit, "26bit", ARM_HWCAP_26BIT, 0) \ LINE(ARM_FASTMULT, fastmult, "fastmult", ARM_HWCAP_FAST_MULT, 0) \ LINE(ARM_FPA, fpa, "fpa", ARM_HWCAP_FPA, 0) \ LINE(ARM_VFP, vfp, "vfp", ARM_HWCAP_VFP, 0) \ LINE(ARM_EDSP, edsp, "edsp", ARM_HWCAP_EDSP, 0) \ LINE(ARM_JAVA, java, "java", ARM_HWCAP_JAVA, 0) \ LINE(ARM_IWMMXT, iwmmxt, "iwmmxt", ARM_HWCAP_IWMMXT, 0) \ LINE(ARM_CRUNCH, crunch, "crunch", ARM_HWCAP_CRUNCH, 0) \ LINE(ARM_THUMBEE, thumbee, "thumbee", ARM_HWCAP_THUMBEE, 0) \ LINE(ARM_NEON, neon, "neon", ARM_HWCAP_NEON, 0) \ LINE(ARM_VFPV3, vfpv3, "vfpv3", ARM_HWCAP_VFPV3, 0) \ LINE(ARM_VFPV3D16, vfpv3d16, "vfpv3d16", ARM_HWCAP_VFPV3D16, 0) \ LINE(ARM_TLS, tls, "tls", ARM_HWCAP_TLS, 0) \ LINE(ARM_VFPV4, vfpv4, "vfpv4", ARM_HWCAP_VFPV4, 0) \ LINE(ARM_IDIVA, idiva, "idiva", ARM_HWCAP_IDIVA, 0) \ LINE(ARM_IDIVT, idivt, "idivt", ARM_HWCAP_IDIVT, 0) \ LINE(ARM_VFPD32, vfpd32, "vfpd32", ARM_HWCAP_VFPD32, 0) \ LINE(ARM_LPAE, lpae, "lpae", ARM_HWCAP_LPAE, 0) \ LINE(ARM_EVTSTRM, evtstrm, "evtstrm", ARM_HWCAP_EVTSTRM, 0) \ LINE(ARM_AES, aes, "aes", 0, ARM_HWCAP2_AES) \ LINE(ARM_PMULL, pmull, "pmull", 0, ARM_HWCAP2_PMULL) \ LINE(ARM_SHA1, sha1, "sha1", 0, ARM_HWCAP2_SHA1) \ LINE(ARM_SHA2, sha2, "sha2", 0, ARM_HWCAP2_SHA2) \ LINE(ARM_CRC32, crc32, "crc32", 0, ARM_HWCAP2_CRC32) #define INTROSPECTION_PREFIX Arm #define INTROSPECTION_ENUM_PREFIX ARM #include "define_introspection_and_hwcaps.inl" //////////////////////////////////////////////////////////////////////////////// // Implementation. //////////////////////////////////////////////////////////////////////////////// #include #include #include "internal/bit_utils.h" #include "internal/filesystem.h" #include "internal/stack_line_reader.h" #include "internal/string_view.h" typedef struct { bool processor_reports_armv6; bool hardware_reports_goldfish; } ProcCpuInfoData; static int IndexOfNonDigit(StringView str) { size_t index = 0; while (str.size && isdigit(CpuFeatures_StringView_Front(str))) { str = CpuFeatures_StringView_PopFront(str, 1); ++index; } return index; } static bool HandleArmLine(const LineResult result, ArmInfo* const info, ProcCpuInfoData* const proc_info) { StringView line = result.line; StringView key, value; if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) { if (CpuFeatures_StringView_IsEquals(key, str("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"))) { info->variant = CpuFeatures_StringView_ParsePositiveNumber(value); } else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) { info->part = CpuFeatures_StringView_ParsePositiveNumber(value); } else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) { info->revision = CpuFeatures_StringView_ParsePositiveNumber(value); } else if (CpuFeatures_StringView_IsEquals(key, str("CPU architecture"))) { // CPU architecture is a number that may be followed by letters. e.g. // "6TEJ", "7". 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"))) { // 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 proc_info->processor_reports_armv6 = CpuFeatures_StringView_IndexOf(value, str("(v6l)")) >= 0; } else if (CpuFeatures_StringView_IsEquals(key, str("Hardware"))) { proc_info->hardware_reports_goldfish = CpuFeatures_StringView_IsEquals(value, str("Goldfish")); } } return !result.eof; } uint32_t GetArmCpuId(const ArmInfo* const info) { return (ExtractBitRange(info->implementer, 7, 0) << 24) | (ExtractBitRange(info->variant, 3, 0) << 20) | (ExtractBitRange(info->part, 11, 0) << 4) | (ExtractBitRange(info->revision, 3, 0) << 0); } static void FixErrors(ArmInfo* const info, ProcCpuInfoData* const proc_cpu_info_data) { // Fixing Samsung kernel reporting invalid cpu architecture. // http://code.google.com/p/android/issues/detail?id=10812 if (proc_cpu_info_data->processor_reports_armv6 && info->architecture >= 7) { info->architecture = 6; } // Handle kernel configuration bugs that prevent the correct reporting of CPU // features. switch (GetArmCpuId(info)) { case 0x4100C080: // Special case: The emulator-specific Android 4.2 kernel fails to report // support for the 32-bit ARM IDIV instruction. Technically, this is a // feature of the virtual CPU implemented by the emulator. Note that it // could also support Thumb IDIV in the future, and this will have to be // slightly updated. if (info->architecture >= 7 && proc_cpu_info_data->hardware_reports_goldfish) { info->features.idiva = true; } break; case 0x511004D0: // https://crbug.com/341598. info->features.neon = false; break; } // Some Qualcomm Krait kernels forget to report IDIV support. // https://github.com/torvalds/linux/commit/120ecfafabec382c4feb79ff159ef42a39b6d33b if (info->implementer == 0x51 && info->architecture == 7 && (info->part == 0x4d || info->part == 0x6f)) { info->features.idiva = true; info->features.idivt = true; } // Propagate cpu features. if (info->features.vfpv4) info->features.vfpv3 = true; if (info->features.neon) info->features.vfpv3 = true; if (info->features.vfpv3) info->features.vfp = true; } static void FillProcCpuInfoData(ArmInfo* const info, ProcCpuInfoData* proc_cpu_info_data) { const int fd = CpuFeatures_OpenFile("/proc/cpuinfo"); if (fd >= 0) { StackLineReader reader; StackLineReader_Initialize(&reader, fd); for (;;) { if (!HandleArmLine(StackLineReader_NextLine(&reader), info, proc_cpu_info_data)) { break; } } CpuFeatures_CloseFile(fd); } } static const ArmInfo kEmptyArmInfo; static const ProcCpuInfoData kEmptyProcCpuInfoData; ArmInfo GetArmInfo(void) { // 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). ArmInfo info = kEmptyArmInfo; ProcCpuInfoData proc_cpu_info_data = kEmptyProcCpuInfoData; FillProcCpuInfoData(&info, &proc_cpu_info_data); 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); return info; } #endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID) #endif // CPU_FEATURES_ARCH_ARM cpu-features-0.9.0/src/impl_loongarch_linux.c000066400000000000000000000066171450057454500213150ustar00rootroot00000000000000// Copyright 2023 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. #include "cpu_features_macros.h" #ifdef CPU_FEATURES_ARCH_LOONGARCH #if defined(CPU_FEATURES_OS_LINUX) #include "cpuinfo_loongarch.h" //////////////////////////////////////////////////////////////////////////////// // Definitions for introspection. //////////////////////////////////////////////////////////////////////////////// #define INTROSPECTION_TABLE \ LINE(LOONGARCH_CPUCFG, CPUCFG, "cfg", HWCAP_LOONGARCH_CPUCFG, 0) \ LINE(LOONGARCH_LAM, LAM, "lam", HWCAP_LOONGARCH_LAM, 0) \ LINE(LOONGARCH_UAL, UAL, "ual", HWCAP_LOONGARCH_UAL, 0) \ LINE(LOONGARCH_FPU, FPU, "fpu", HWCAP_LOONGARCH_FPU, 0) \ LINE(LOONGARCH_LSX, LSX, "lsx", HWCAP_LOONGARCH_LSX, 0) \ LINE(LOONGARCH_LASX, LASX, "lasx", HWCAP_LOONGARCH_LASX, 0) \ LINE(LOONGARCH_CRC32, CRC32, "crc32", HWCAP_LOONGARCH_CRC32, 0) \ LINE(LOONGARCH_COMPLEX, COMPLEX, "complex", HWCAP_LOONGARCH_COMPLEX, 0) \ LINE(LOONGARCH_CRYPTO, CRYPTO, "crypto", HWCAP_LOONGARCH_CRYPTO, 0) \ LINE(LOONGARCH_LVZ, LVZ, "lvz", HWCAP_LOONGARCH_LVZ, 0) \ LINE(LOONGARCH_LBT_X86, LBT_X86, "lbt_x86", HWCAP_LOONGARCH_LBT_X86, 0) \ LINE(LOONGARCH_LBT_ARM, LBT_ARM, "lbt_arm", HWCAP_LOONGARCH_LBT_ARM, 0) \ LINE(LOONGARCH_LBT_MIPS, LBT_MIPS, "lbt_mips", HWCAP_LOONGARCH_LBT_MIPS, 0) \ LINE(LOONGARCH_PTW, PTW, "ptw", HWCAP_LOONGARCH_PTW, 0) #define INTROSPECTION_PREFIX LoongArch #define INTROSPECTION_ENUM_PREFIX LOONGARCH #include "define_introspection_and_hwcaps.inl" //////////////////////////////////////////////////////////////////////////////// // Implementation. //////////////////////////////////////////////////////////////////////////////// #include #include #include "internal/filesystem.h" #include "internal/stack_line_reader.h" static const LoongArchInfo kEmptyLoongArchInfo; static bool HandleLoongArchLine(const LineResult result, LoongArchInfo* const info) { StringView line = result.line; StringView key, value; if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) { if (CpuFeatures_StringView_IsEquals(key, str("Features"))) { for (size_t i = 0; i < LOONGARCH_LAST_; ++i) { kSetters[i](&info->features, CpuFeatures_StringView_HasWord( value, kCpuInfoFlags[i], ' ')); } } } return !result.eof; } static void FillProcCpuInfoData(LoongArchInfo* const info) { const int fd = CpuFeatures_OpenFile("/proc/cpuinfo"); if (fd >= 0) { StackLineReader reader; StackLineReader_Initialize(&reader, fd); for (;;) { if (!HandleLoongArchLine(StackLineReader_NextLine(&reader), info)) break; } CpuFeatures_CloseFile(fd); } } LoongArchInfo GetLoongArchInfo(void) { LoongArchInfo info = kEmptyLoongArchInfo; FillProcCpuInfoData(&info); return info; } #endif // defined(CPU_FEATURES_OS_LINUX) #endif // CPU_FEATURES_ARCH_LOONGARCH cpu-features-0.9.0/src/impl_mips_linux_or_android.c000066400000000000000000000067041450057454500225060ustar00rootroot00000000000000// 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 "cpu_features_macros.h" #ifdef CPU_FEATURES_ARCH_MIPS #if defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID) #include "cpuinfo_mips.h" //////////////////////////////////////////////////////////////////////////////// // Definitions for introspection. //////////////////////////////////////////////////////////////////////////////// #define INTROSPECTION_TABLE \ LINE(MIPS_MSA, msa, "msa", MIPS_HWCAP_MSA, 0) \ LINE(MIPS_EVA, eva, "eva", 0, 0) \ LINE(MIPS_R6, r6, "r6", MIPS_HWCAP_R6, 0) \ LINE(MIPS_MIPS16, mips16, "mips16", MIPS_HWCAP_MIPS16, 0) \ LINE(MIPS_MDMX, mdmx, "mdmx", MIPS_HWCAP_MDMX, 0) \ LINE(MIPS_MIPS3D, mips3d, "mips3d", MIPS_HWCAP_MIPS3D, 0) \ LINE(MIPS_SMART, smart, "smartmips", MIPS_HWCAP_SMARTMIPS, 0) \ LINE(MIPS_DSP, dsp, "dsp", MIPS_HWCAP_DSP, 0) #define INTROSPECTION_PREFIX Mips #define INTROSPECTION_ENUM_PREFIX MIPS #include "define_introspection_and_hwcaps.inl" //////////////////////////////////////////////////////////////////////////////// // Implementation. //////////////////////////////////////////////////////////////////////////////// #include "internal/filesystem.h" #include "internal/hwcaps.h" #include "internal/stack_line_reader.h" #include "internal/string_view.h" static bool HandleMipsLine(const LineResult result, MipsFeatures* const features) { StringView key, value; // See tests for an example. if (CpuFeatures_StringView_GetAttributeKeyValue(result.line, &key, &value)) { if (CpuFeatures_StringView_IsEquals(key, str("ASEs implemented"))) { for (size_t i = 0; i < MIPS_LAST_; ++i) { kSetters[i](features, CpuFeatures_StringView_HasWord( value, kCpuInfoFlags[i], ' ')); } } } return !result.eof; } static void FillProcCpuInfoData(MipsFeatures* const features) { const int fd = CpuFeatures_OpenFile("/proc/cpuinfo"); if (fd >= 0) { StackLineReader reader; StackLineReader_Initialize(&reader, fd); for (;;) { if (!HandleMipsLine(StackLineReader_NextLine(&reader), features)) { break; } } CpuFeatures_CloseFile(fd); } } static const MipsInfo kEmptyMipsInfo; MipsInfo GetMipsInfo(void) { // 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); 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; } #endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID) #endif // CPU_FEATURES_ARCH_MIPS cpu-features-0.9.0/src/impl_ppc_linux.c000066400000000000000000000174071450057454500201220ustar00rootroot00000000000000// Copyright 2018 IBM. // // 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 "cpu_features_macros.h" #ifdef CPU_FEATURES_ARCH_PPC #ifdef CPU_FEATURES_OS_LINUX #include "cpuinfo_ppc.h" //////////////////////////////////////////////////////////////////////////////// // Definitions for introspection. //////////////////////////////////////////////////////////////////////////////// #define INTROSPECTION_TABLE \ LINE(PPC_32, ppc32, "ppc32", PPC_FEATURE_32, 0) \ LINE(PPC_64, ppc64, "ppc64", PPC_FEATURE_64, 0) \ LINE(PPC_601_INSTR, ppc601, "ppc601", PPC_FEATURE_601_INSTR, 0) \ LINE(PPC_HAS_ALTIVEC, altivec, "altivec", PPC_FEATURE_HAS_ALTIVEC, 0) \ LINE(PPC_HAS_FPU, fpu, "fpu", PPC_FEATURE_HAS_FPU, 0) \ LINE(PPC_HAS_MMU, mmu, "mmu", PPC_FEATURE_HAS_MMU, 0) \ LINE(PPC_HAS_4xxMAC, mac_4xx, "4xxmac", PPC_FEATURE_HAS_4xxMAC, 0) \ LINE(PPC_UNIFIED_CACHE, unifiedcache, "ucache", PPC_FEATURE_UNIFIED_CACHE, \ 0) \ LINE(PPC_HAS_SPE, spe, "spe", PPC_FEATURE_HAS_SPE, 0) \ LINE(PPC_HAS_EFP_SINGLE, efpsingle, "efpsingle", PPC_FEATURE_HAS_EFP_SINGLE, \ 0) \ LINE(PPC_HAS_EFP_DOUBLE, efpdouble, "efpdouble", PPC_FEATURE_HAS_EFP_DOUBLE, \ 0) \ LINE(PPC_NO_TB, no_tb, "notb", PPC_FEATURE_NO_TB, 0) \ LINE(PPC_POWER4, power4, "power4", PPC_FEATURE_POWER4, 0) \ LINE(PPC_POWER5, power5, "power5", PPC_FEATURE_POWER5, 0) \ LINE(PPC_POWER5_PLUS, power5plus, "power5+", PPC_FEATURE_POWER5_PLUS, 0) \ LINE(PPC_CELL, cell, "cellbe", PPC_FEATURE_CELL, 0) \ LINE(PPC_BOOKE, booke, "booke", PPC_FEATURE_BOOKE, 0) \ LINE(PPC_SMT, smt, "smt", PPC_FEATURE_SMT, 0) \ LINE(PPC_ICACHE_SNOOP, icachesnoop, "ic_snoop", PPC_FEATURE_ICACHE_SNOOP, 0) \ LINE(PPC_ARCH_2_05, arch205, "arch_2_05", PPC_FEATURE_ARCH_2_05, 0) \ LINE(PPC_PA6T, pa6t, "pa6t", PPC_FEATURE_PA6T, 0) \ LINE(PPC_HAS_DFP, dfp, "dfp", PPC_FEATURE_HAS_DFP, 0) \ LINE(PPC_POWER6_EXT, power6ext, "power6x", PPC_FEATURE_POWER6_EXT, 0) \ LINE(PPC_ARCH_2_06, arch206, "arch_2_06", PPC_FEATURE_ARCH_2_06, 0) \ LINE(PPC_HAS_VSX, vsx, "vsx", PPC_FEATURE_HAS_VSX, 0) \ LINE(PPC_PSERIES_PERFMON_COMPAT, pseries_perfmon_compat, "archpmu", \ PPC_FEATURE_PSERIES_PERFMON_COMPAT, 0) \ LINE(PPC_TRUE_LE, truele, "true_le", PPC_FEATURE_TRUE_LE, 0) \ LINE(PPC_PPC_LE, ppcle, "ppcle", PPC_FEATURE_PPC_LE, 0) \ LINE(PPC_ARCH_2_07, arch207, "arch_2_07", 0, PPC_FEATURE2_ARCH_2_07) \ LINE(PPC_HTM, htm, "htm", 0, PPC_FEATURE2_HTM) \ LINE(PPC_DSCR, dscr, "dscr", 0, PPC_FEATURE2_DSCR) \ LINE(PPC_EBB, ebb, "ebb", 0, PPC_FEATURE2_EBB) \ LINE(PPC_ISEL, isel, "isel", 0, PPC_FEATURE2_ISEL) \ LINE(PPC_TAR, tar, "tar", 0, PPC_FEATURE2_TAR) \ LINE(PPC_VEC_CRYPTO, vcrypto, "vcrypto", 0, PPC_FEATURE2_VEC_CRYPTO) \ LINE(PPC_HTM_NOSC, htm_nosc, "htm-nosc", 0, PPC_FEATURE2_HTM_NOSC) \ LINE(PPC_ARCH_3_00, arch300, "arch_3_00", 0, PPC_FEATURE2_ARCH_3_00) \ LINE(PPC_HAS_IEEE128, ieee128, "ieee128", 0, PPC_FEATURE2_HAS_IEEE128) \ LINE(PPC_DARN, darn, "darn", 0, PPC_FEATURE2_DARN) \ LINE(PPC_SCV, scv, "scv", 0, PPC_FEATURE2_SCV) \ LINE(PPC_HTM_NO_SUSPEND, htm_no_suspend, "htm-no-suspend", 0, \ PPC_FEATURE2_HTM_NO_SUSPEND) #undef PPC // Remove conflict with compiler generated preprocessor #define INTROSPECTION_PREFIX PPC #define INTROSPECTION_ENUM_PREFIX PPC #include "define_introspection_and_hwcaps.inl" //////////////////////////////////////////////////////////////////////////////// // Implementation. //////////////////////////////////////////////////////////////////////////////// #include #include "internal/bit_utils.h" #include "internal/filesystem.h" #include "internal/hwcaps.h" #include "internal/stack_line_reader.h" #include "internal/string_view.h" static bool HandlePPCLine(const LineResult result, PPCPlatformStrings* const strings) { StringView line = result.line; StringView key, value; if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) { if (CpuFeatures_StringView_HasWord(key, "platform", ' ')) { CpuFeatures_StringView_CopyString(value, strings->platform, sizeof(strings->platform)); } else if (CpuFeatures_StringView_IsEquals(key, str("model"))) { CpuFeatures_StringView_CopyString(value, strings->model, sizeof(strings->platform)); } else if (CpuFeatures_StringView_IsEquals(key, str("machine"))) { CpuFeatures_StringView_CopyString(value, strings->machine, sizeof(strings->platform)); } else if (CpuFeatures_StringView_IsEquals(key, str("cpu"))) { CpuFeatures_StringView_CopyString(value, strings->cpu, sizeof(strings->platform)); } } return !result.eof; } static void FillProcCpuInfoData(PPCPlatformStrings* const strings) { const int fd = CpuFeatures_OpenFile("/proc/cpuinfo"); if (fd >= 0) { StackLineReader reader; StackLineReader_Initialize(&reader, fd); for (;;) { if (!HandlePPCLine(StackLineReader_NextLine(&reader), strings)) { break; } } CpuFeatures_CloseFile(fd); } } static const PPCInfo kEmptyPPCInfo; PPCInfo GetPPCInfo(void) { /* * On Power feature flags aren't currently in cpuinfo so we only look at * the auxilary vector. */ PPCInfo info = kEmptyPPCInfo; 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; } static const PPCPlatformStrings kEmptyPPCPlatformStrings; PPCPlatformStrings GetPPCPlatformStrings(void) { PPCPlatformStrings strings = kEmptyPPCPlatformStrings; const char* platform = CpuFeatures_GetPlatformPointer(); const char* base_platform = CpuFeatures_GetBasePlatformPointer(); FillProcCpuInfoData(&strings); if (platform != NULL) CpuFeatures_StringView_CopyString(str(platform), strings.type.platform, sizeof(strings.type.platform)); if (base_platform != NULL) CpuFeatures_StringView_CopyString(str(base_platform), strings.type.base_platform, sizeof(strings.type.base_platform)); return strings; } #endif // CPU_FEATURES_OS_LINUX #endif // CPU_FEATURES_ARCH_PPC cpu-features-0.9.0/src/impl_riscv_linux.c000066400000000000000000000102541450057454500204570ustar00rootroot00000000000000// Copyright 2022 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. #include "cpu_features_macros.h" #ifdef CPU_FEATURES_ARCH_RISCV #if defined(CPU_FEATURES_OS_LINUX) #include "cpuinfo_riscv.h" // According to // https://elixir.bootlin.com/linux/latest/source/Documentation/devicetree/bindings/riscv/cpus.yaml // isa string should match the following regex // ^rv(?:64|32)imaf?d?q?c?b?v?k?h?(?:_[hsxz](?:[a-z])+)*$ // // This means we can test for features in this exact order except for Z // extensions. //////////////////////////////////////////////////////////////////////////////// // Definitions for introspection. //////////////////////////////////////////////////////////////////////////////// #define INTROSPECTION_TABLE \ LINE(RISCV_RV32I, RV32I, "rv32i", RISCV_HWCAP_32, 0) \ LINE(RISCV_RV64I, RV64I, "rv64i", RISCV_HWCAP_64, 0) \ LINE(RISCV_M, M, "m", RISCV_HWCAP_M, 0) \ LINE(RISCV_A, A, "a", RISCV_HWCAP_A, 0) \ LINE(RISCV_F, F, "f", RISCV_HWCAP_F, 0) \ LINE(RISCV_D, D, "d", RISCV_HWCAP_D, 0) \ LINE(RISCV_Q, Q, "q", RISCV_HWCAP_Q, 0) \ LINE(RISCV_C, C, "c", RISCV_HWCAP_C, 0) \ LINE(RISCV_V, V, "v", RISCV_HWCAP_V, 0) \ LINE(RISCV_Zicsr, Zicsr, "_zicsr", 0, 0) \ LINE(RISCV_Zifencei, Zifencei, "_zifencei", 0, 0) #define INTROSPECTION_PREFIX Riscv #define INTROSPECTION_ENUM_PREFIX RISCV #include "define_introspection_and_hwcaps.inl" //////////////////////////////////////////////////////////////////////////////// // Implementation. //////////////////////////////////////////////////////////////////////////////// #include #include #include "internal/filesystem.h" #include "internal/stack_line_reader.h" static const RiscvInfo kEmptyRiscvInfo; static void HandleRiscVIsaLine(StringView line, RiscvFeatures* const features) { for (size_t i = 0; i < RISCV_LAST_; ++i) { StringView flag = str(kCpuInfoFlags[i]); int index_of_flag = CpuFeatures_StringView_IndexOf(line, flag); bool is_set = index_of_flag != -1; kSetters[i](features, is_set); if (is_set) line = CpuFeatures_StringView_PopFront(line, index_of_flag + flag.size); } } static bool HandleRiscVLine(const LineResult result, RiscvInfo* const info) { StringView line = result.line; StringView key, value; if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) { if (CpuFeatures_StringView_IsEquals(key, str("isa"))) { HandleRiscVIsaLine(value, &info->features); } else if (CpuFeatures_StringView_IsEquals(key, str("uarch"))) { int index = CpuFeatures_StringView_IndexOfChar(value, ','); if (index == -1) return true; StringView vendor = CpuFeatures_StringView_KeepFront(value, index); StringView uarch = CpuFeatures_StringView_PopFront(value, index + 1); CpuFeatures_StringView_CopyString(vendor, info->vendor, sizeof(info->vendor)); CpuFeatures_StringView_CopyString(uarch, info->uarch, sizeof(info->uarch)); } } return !result.eof; } static void FillProcCpuInfoData(RiscvInfo* const info) { const int fd = CpuFeatures_OpenFile("/proc/cpuinfo"); if (fd >= 0) { StackLineReader reader; StackLineReader_Initialize(&reader, fd); for (;;) { if (!HandleRiscVLine(StackLineReader_NextLine(&reader), info)) break; } CpuFeatures_CloseFile(fd); } } RiscvInfo GetRiscvInfo(void) { RiscvInfo info = kEmptyRiscvInfo; FillProcCpuInfoData(&info); return info; } #endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID) #endif // CPU_FEATURES_ARCH_RISCV cpu-features-0.9.0/src/impl_s390x_linux.c000066400000000000000000000120351450057454500202160ustar00rootroot00000000000000// Copyright 2022 IBM. // // 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 "cpu_features_macros.h" #ifdef CPU_FEATURES_ARCH_S390X #ifdef CPU_FEATURES_OS_LINUX #include "cpuinfo_s390x.h" //////////////////////////////////////////////////////////////////////////////// // Definitions for introspection. //////////////////////////////////////////////////////////////////////////////// #define INTROSPECTION_TABLE \ LINE(S390_ESAN3, esan3, "esan3", HWCAP_S390_ESAN3, 0) \ LINE(S390_ZARCH, zarch, "zarch", HWCAP_S390_ZARCH, 0) \ LINE(S390_STFLE, stfle, "stfle", HWCAP_S390_STFLE, 0) \ LINE(S390_MSA, msa, "msa", HWCAP_S390_MSA, 0) \ LINE(S390_LDISP, ldisp, "ldisp", HWCAP_S390_LDISP, 0) \ LINE(S390_EIMM, eimm, "eimm", HWCAP_S390_EIMM, 0) \ LINE(S390_DFP, dfp, "dfp", HWCAP_S390_DFP, 0) \ LINE(S390_EDAT, edat, "edat", HWCAP_S390_HPAGE, 0) \ LINE(S390_ETF3EH, etf3eh, "etf3eh", HWCAP_S390_ETF3EH, 0) \ LINE(S390_HIGHGPRS, highgprs, "highgprs", HWCAP_S390_HIGH_GPRS, 0) \ LINE(S390_TE, te, "te", HWCAP_S390_TE, 0) \ LINE(S390_VX, vx, "vx", HWCAP_S390_VXRS, 0) \ LINE(S390_VXD, vxd, "vxd", HWCAP_S390_VXRS_BCD, 0) \ LINE(S390_VXE, vxe, "vxe", HWCAP_S390_VXRS_EXT, 0) \ LINE(S390_GS, gs, "gs", HWCAP_S390_GS, 0) \ LINE(S390_VXE2, vxe2, "vxe2", HWCAP_S390_VXRS_EXT2, 0) \ LINE(S390_VXP, vxp, "vxp", HWCAP_S390_VXRS_PDE, 0) \ LINE(S390_SORT, sort, "sort", HWCAP_S390_SORT, 0) \ LINE(S390_DFLT, dflt, "dflt", HWCAP_S390_DFLT, 0) \ LINE(S390_VXP2, vxp2, "vxp2", HWCAP_S390_VXRS_PDE2, 0) \ LINE(S390_NNPA, nnpa, "nnpa", HWCAP_S390_NNPA, 0) \ LINE(S390_PCIMIO, pcimio, "pcimio", HWCAP_S390_PCI_MIO, 0) \ LINE(S390_SIE, sie, "sie", HWCAP_S390_SIE, 0) #define INTROSPECTION_PREFIX S390X #define INTROSPECTION_ENUM_PREFIX S390X #include "define_introspection_and_hwcaps.inl" //////////////////////////////////////////////////////////////////////////////// // Implementation. //////////////////////////////////////////////////////////////////////////////// #include #include "internal/bit_utils.h" #include "internal/filesystem.h" #include "internal/hwcaps.h" #include "internal/stack_line_reader.h" #include "internal/string_view.h" static bool HandleS390XLine(const LineResult result, S390XPlatformStrings* const strings) { StringView line = result.line; StringView key, value; if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) { if (CpuFeatures_StringView_IsEquals(key, str("# processors"))) { strings->num_processors = CpuFeatures_StringView_ParsePositiveNumber(value); } } return !result.eof; } static void FillProcCpuInfoData(S390XPlatformStrings* const strings) { const int fd = CpuFeatures_OpenFile("/proc/cpuinfo"); if (fd >= 0) { StackLineReader reader; StackLineReader_Initialize(&reader, fd); for (;;) { if (!HandleS390XLine(StackLineReader_NextLine(&reader), strings)) { break; } } CpuFeatures_CloseFile(fd); } } static const S390XInfo kEmptyS390XInfo; S390XInfo GetS390XInfo(void) { S390XInfo info = kEmptyS390XInfo; const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities(); for (size_t i = 0; i < S390X_LAST_; ++i) { if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) { kSetters[i](&info.features, true); } } return info; } static const S390XPlatformStrings kEmptyS390XPlatformStrings; S390XPlatformStrings GetS390XPlatformStrings(void) { S390XPlatformStrings strings = kEmptyS390XPlatformStrings; const char* platform = CpuFeatures_GetPlatformPointer(); FillProcCpuInfoData(&strings); if (platform != NULL) CpuFeatures_StringView_CopyString(str(platform), strings.type.platform, sizeof(strings.type.platform)); return strings; } #endif // CPU_FEATURES_OS_LINUX #endif // CPU_FEATURES_ARCH_S390X cpu-features-0.9.0/src/impl_x86__base_implementation.inl000066400000000000000000002534661450057454500233530ustar00rootroot00000000000000// Copyright 2017 Google LLC // Copyright 2020 Intel Corporation // // 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. // A note on x86 SIMD instructions availability // ----------------------------------------------------------------------------- // A number of conditions need to be met for an application to use SIMD // instructions: // 1. The CPU itself must support the instruction. // - we use `CPUID` to check whether the feature is supported. // 2. The OS must save and restore the associated SIMD register across context // switches, we check that: // - the CPU reports supporting hardware context switching instructions via // CPUID.1:ECX.XSAVE[bit 26] // - the OS reports supporting hardware context switching instructions via // CPUID.1:ECX.OSXSAVE[bit 27] // - the CPU extended control register 0 (XCR0) is set to save and restore the // needed SIMD registers // // Note that if `XSAVE`/`OSXSAVE` are missing, we delegate the detection to the // OS via the `DetectFeaturesFromOs` function or via microarchitecture // heuristics. // // Encoding // ----------------------------------------------------------------------------- // X86Info contains fields such as vendor and brand_string that are ASCII // encoded strings. `vendor` length of characters is 13 and `brand_string` is 49 // (with null terminated string). We use CPUID.1:E[D,C,B]X to get `vendor` and // CPUID.8000_000[4:2]:E[D,C,B,A]X to get `brand_string` // // Microarchitecture // ----------------------------------------------------------------------------- // `GetX86Microarchitecture` function consists of check on vendor via // `IsVendorByX86Info`. We use `CPUID(family, model)` to define the vendor's // microarchitecture. In cases where the `family` and `model` is the same for // several microarchitectures we do a stepping check or in the worst case we // rely on parsing brand_string (see HasSecondFMA for an example). Details of // identification by `brand_string` can be found by reference: // https://en.wikichip.org/wiki/intel/microarchitectures/cascade_lake // https://www.intel.com/content/www/us/en/processors/processor-numbers.html // CacheInfo X86 // ----------------------------------------------------------------------------- // We use the CacheInfo struct to store information about cache levels. The // maximum number of levels is hardcoded but can be increased if needed. We have // full support of cache identification for the following processors: // • Intel: // ◦ modern processors: // we use `ParseCacheInfo` function with `leaf_id` 0x00000004. // ◦ old processors: // we parse descriptors via `GetCacheLevelInfo`, see Application Note // 485: Intel Processor Identification and CPUID Instruction. // • AMD: // ◦ modern processors: // we use `ParseCacheInfo` function with `leaf_id` 0x8000001D. // ◦ old processors: // we parse cache info using Fn8000_0005_E[A,B,C,D]X and // Fn8000_0006_E[A,B,C,D]X. See AMD CPUID Specification: // https://www.amd.com/system/files/TechDocs/25481.pdf. // • Hygon: // we reuse AMD cache detection implementation. // • Zhaoxin: // we reuse Intel cache detection implementation. // // Internal structures // ----------------------------------------------------------------------------- // We use internal structures such as `Leaves` and `OsPreserves` to cache the // result of cpuid info and support of registers, since latency of CPUID // instruction is around ~100 cycles, see // https://www.agner.org/optimize/instruction_tables.pdf. Hence, we use // `ReadLeaves` function for `GetX86Info`, `GetCacheInfo` and // `FillX86BrandString` to read leaves and hold these values to avoid redundant // call on the same leaf. #include #include #include "copy.inl" #include "cpuinfo_x86.h" #include "equals.inl" #include "internal/bit_utils.h" #include "internal/cpuid_x86.h" #if !defined(CPU_FEATURES_ARCH_X86) #error "Cannot compile cpuinfo_x86 on a non x86 platform." #endif //////////////////////////////////////////////////////////////////////////////// // Definitions for CpuId and GetXCR0Eax. //////////////////////////////////////////////////////////////////////////////// #if defined(CPU_FEATURES_MOCK_CPUID_X86) // Implementation will be provided by test/cpuinfo_x86_test.cc. #elif defined(CPU_FEATURES_COMPILER_CLANG) || defined(CPU_FEATURES_COMPILER_GCC) #include 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; } uint32_t GetXCR0Eax(void) { uint32_t eax, edx; /* named form of xgetbv not supported on OSX, so must use byte form, see: https://github.com/asmjit/asmjit/issues/78 */ __asm(".byte 0x0F, 0x01, 0xd0" : "=a"(eax), "=d"(edx) : "c"(0)); return eax; } #elif defined(CPU_FEATURES_COMPILER_MSC) #include #include // For __cpuidex() Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx) { Leaf leaf; int data[4]; __cpuidex(data, leaf_id, ecx); leaf.eax = data[0]; leaf.ebx = data[1]; leaf.ecx = data[2]; leaf.edx = data[3]; return leaf; } uint32_t GetXCR0Eax(void) { return (uint32_t)_xgetbv(0); } #else #error "Unsupported compiler, x86 cpuid requires either GCC, Clang or MSVC." #endif 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 GetCpuidLeaf(leaf_id, ecx); } else { return kEmptyLeaf; } } typedef struct { uint32_t max_cpuid_leaf; Leaf leaf_0; // Root Leaf leaf_1; // Family, Model, Stepping Leaf leaf_2; // Intel cache info + features Leaf leaf_7; // Features Leaf leaf_7_1; // Features uint32_t max_cpuid_leaf_ext; Leaf leaf_80000000; // Root for extended leaves Leaf leaf_80000001; // AMD features features and cache Leaf leaf_80000002; // brand string Leaf leaf_80000003; // brand string Leaf leaf_80000004; // brand string Leaf leaf_80000021; // AMD Extended Feature Identification 2 } Leaves; static Leaves ReadLeaves(void) { const Leaf leaf_0 = GetCpuidLeaf(0, 0); const uint32_t max_cpuid_leaf = leaf_0.eax; const Leaf leaf_80000000 = GetCpuidLeaf(0x80000000, 0); const uint32_t max_cpuid_leaf_ext = leaf_80000000.eax; return (Leaves){ .max_cpuid_leaf = max_cpuid_leaf, .leaf_0 = leaf_0, .leaf_1 = SafeCpuIdEx(max_cpuid_leaf, 0x00000001, 0), .leaf_2 = SafeCpuIdEx(max_cpuid_leaf, 0x00000002, 0), .leaf_7 = SafeCpuIdEx(max_cpuid_leaf, 0x00000007, 0), .leaf_7_1 = SafeCpuIdEx(max_cpuid_leaf, 0x00000007, 1), .max_cpuid_leaf_ext = max_cpuid_leaf_ext, .leaf_80000000 = leaf_80000000, .leaf_80000001 = SafeCpuIdEx(max_cpuid_leaf_ext, 0x80000001, 0), .leaf_80000002 = SafeCpuIdEx(max_cpuid_leaf_ext, 0x80000002, 0), .leaf_80000003 = SafeCpuIdEx(max_cpuid_leaf_ext, 0x80000003, 0), .leaf_80000004 = SafeCpuIdEx(max_cpuid_leaf_ext, 0x80000004, 0), .leaf_80000021 = SafeCpuIdEx(max_cpuid_leaf_ext, 0x80000021, 0), }; } //////////////////////////////////////////////////////////////////////////////// // OS support //////////////////////////////////////////////////////////////////////////////// #define MASK_XMM 0x2 #define MASK_YMM 0x4 #define MASK_MASKREG 0x20 #define MASK_ZMM0_15 0x40 #define MASK_ZMM16_31 0x80 #define MASK_XTILECFG 0x20000 #define MASK_XTILEDATA 0x40000 static bool HasMask(uint32_t value, uint32_t mask) { return (value & mask) == mask; } // Checks that operating system saves and restores xmm registers during context // switches. static bool HasXmmOsXSave(uint32_t xcr0_eax) { return HasMask(xcr0_eax, MASK_XMM); } // Checks that operating system saves and restores ymm registers during context // switches. static bool HasYmmOsXSave(uint32_t xcr0_eax) { return HasMask(xcr0_eax, MASK_XMM | MASK_YMM); } // Checks that operating system saves and restores zmm registers during context // switches. static bool HasZmmOsXSave(uint32_t xcr0_eax) { return HasMask(xcr0_eax, MASK_XMM | MASK_YMM | MASK_MASKREG | MASK_ZMM0_15 | MASK_ZMM16_31); } // Checks that operating system saves and restores AMX/TMUL state during context // switches. static bool HasTmmOsXSave(uint32_t xcr0_eax) { return HasMask(xcr0_eax, MASK_XMM | MASK_YMM | MASK_MASKREG | MASK_ZMM0_15 | MASK_ZMM16_31 | MASK_XTILECFG | MASK_XTILEDATA); } //////////////////////////////////////////////////////////////////////////////// // Vendor //////////////////////////////////////////////////////////////////////////////// static void SetVendor(const Leaf leaf, char* const vendor) { *(uint32_t*)(vendor) = leaf.ebx; *(uint32_t*)(vendor + 4) = leaf.edx; *(uint32_t*)(vendor + 8) = leaf.ecx; vendor[12] = '\0'; } static int IsVendor(const Leaf leaf, const char* const name) { const uint32_t ebx = *(const uint32_t*)(name); const uint32_t edx = *(const uint32_t*)(name + 4); const uint32_t ecx = *(const uint32_t*)(name + 8); return leaf.ebx == ebx && leaf.ecx == ecx && leaf.edx == edx; } static int IsVendorByX86Info(const X86Info* info, const char* const name) { return equals(info->vendor, name, sizeof(info->vendor)); } // TODO: Remove when deprecation period is over, void FillX86BrandString(char brand_string[49]) { const Leaves leaves = ReadLeaves(); const Leaf packed[3] = { leaves.leaf_80000002, leaves.leaf_80000003, leaves.leaf_80000004, }; #if __STDC_VERSION__ >= 201112L _Static_assert(sizeof(packed) == 48, "Leaves must be packed"); #endif copy(brand_string, (const char*)(packed), 48); brand_string[48] = '\0'; } //////////////////////////////////////////////////////////////////////////////// // CpuId //////////////////////////////////////////////////////////////////////////////// static bool HasSecondFMA(const X86Info* info) { // Skylake server if (info->model == 0x55) { // detect Xeon if (info->brand_string[9] == 'X') { // detect Silver or Bronze if (info->brand_string[17] == 'S' || info->brand_string[17] == 'B') return false; // detect Gold 5_20 and below, except for Gold 53__ if (info->brand_string[17] == 'G' && info->brand_string[22] == '5') return ( (info->brand_string[23] == '3') || (info->brand_string[24] == '2' && info->brand_string[25] == '2')); // detect Xeon W 210x if (info->brand_string[17] == 'W' && info->brand_string[21] == '0') return false; // detect Xeon D 2xxx if (info->brand_string[17] == 'D' && info->brand_string[19] == '2' && info->brand_string[20] == '1') return false; } return true; } // Cannon Lake client if (info->model == 0x66) return false; // Ice Lake client if (info->model == 0x7d || info->model == 0x7e) return false; // This is the right default... return true; } // 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 sse_registers; bool avx_registers; bool avx512_registers; bool amx_registers; } OsPreserves; // These two functions have to be implemented by the OS, that is the file // including this file. static void OverrideOsPreserves(OsPreserves* os_preserves); static void DetectFeaturesFromOs(X86Info* info, X86Features* features); // Reference https://en.wikipedia.org/wiki/CPUID. static void ParseCpuId(const Leaves* leaves, X86Info* info, OsPreserves* os_preserves) { const Leaf leaf_1 = leaves->leaf_1; const Leaf leaf_7 = leaves->leaf_7; const Leaf leaf_7_1 = leaves->leaf_7_1; const Leaf leaf_80000001 = leaves->leaf_80000001; const bool have_xsave = IsBitSet(leaf_1.ecx, 26); const bool have_osxsave = IsBitSet(leaf_1.ecx, 27); const bool have_xcr0 = have_xsave && have_osxsave; 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); const uint32_t extended_model = ExtractBitRange(leaf_1.eax, 19, 16); X86Features* const features = &info->features; // Fill Family, Model and Stepping. info->family = extended_family + family; info->model = (extended_model << 4) + model; info->stepping = ExtractBitRange(leaf_1.eax, 3, 0); // Fill Brand String. const Leaf packed[3] = { leaves->leaf_80000002, leaves->leaf_80000003, leaves->leaf_80000004, }; #if __STDC_VERSION__ >= 201112L _Static_assert(sizeof(packed) == 48, "Leaves must be packed"); #endif copy(info->brand_string, (const char*)(packed), 48); info->brand_string[48] = '\0'; // Fill cpu features. features->fpu = IsBitSet(leaf_1.edx, 0); features->tsc = IsBitSet(leaf_1.edx, 4); features->cx8 = IsBitSet(leaf_1.edx, 8); features->clfsh = IsBitSet(leaf_1.edx, 19); features->mmx = IsBitSet(leaf_1.edx, 23); features->ss = IsBitSet(leaf_1.edx, 27); features->pclmulqdq = IsBitSet(leaf_1.ecx, 1); features->smx = IsBitSet(leaf_1.ecx, 6); features->cx16 = IsBitSet(leaf_1.ecx, 13); features->dca = IsBitSet(leaf_1.ecx, 18); features->movbe = IsBitSet(leaf_1.ecx, 22); features->popcnt = IsBitSet(leaf_1.ecx, 23); features->aes = IsBitSet(leaf_1.ecx, 25); features->f16c = IsBitSet(leaf_1.ecx, 29); features->rdrnd = IsBitSet(leaf_1.ecx, 30); features->sgx = IsBitSet(leaf_7.ebx, 2); features->bmi1 = IsBitSet(leaf_7.ebx, 3); features->hle = IsBitSet(leaf_7.ebx, 4); features->bmi2 = IsBitSet(leaf_7.ebx, 8); features->erms = IsBitSet(leaf_7.ebx, 9); features->rtm = IsBitSet(leaf_7.ebx, 11); features->rdseed = IsBitSet(leaf_7.ebx, 18); features->clflushopt = IsBitSet(leaf_7.ebx, 23); features->clwb = IsBitSet(leaf_7.ebx, 24); features->sha = IsBitSet(leaf_7.ebx, 29); features->gfni = IsBitSet(leaf_7.ecx, 8); features->vaes = IsBitSet(leaf_7.ecx, 9); features->vpclmulqdq = IsBitSet(leaf_7.ecx, 10); features->movdiri = IsBitSet(leaf_7.ecx, 27); features->movdir64b = IsBitSet(leaf_7.ecx, 28); features->fs_rep_mov = IsBitSet(leaf_7.edx, 4); features->fz_rep_movsb = IsBitSet(leaf_7_1.eax, 10); features->fs_rep_stosb = IsBitSet(leaf_7_1.eax, 11); features->fs_rep_cmpsb_scasb = IsBitSet(leaf_7_1.eax, 12); features->adx = IsBitSet(leaf_7.ebx, 19); features->lzcnt = IsBitSet(leaf_80000001.ecx, 5); features->lam = IsBitSet(leaf_7_1.eax, 26); ///////////////////////////////////////////////////////////////////////////// // The following section is devoted to Vector Extensions. ///////////////////////////////////////////////////////////////////////////// // CPU with AVX expose XCR0 which enables checking vector extensions OS // support through cpuid. if (have_xcr0) { // Here we rely exclusively on cpuid for both CPU and OS support of vector // extensions. const uint32_t xcr0_eax = GetXCR0Eax(); os_preserves->sse_registers = HasXmmOsXSave(xcr0_eax); os_preserves->avx_registers = HasYmmOsXSave(xcr0_eax); os_preserves->avx512_registers = HasZmmOsXSave(xcr0_eax); os_preserves->amx_registers = HasTmmOsXSave(xcr0_eax); OverrideOsPreserves(os_preserves); if (os_preserves->sse_registers) { features->sse = IsBitSet(leaf_1.edx, 25); features->sse2 = IsBitSet(leaf_1.edx, 26); features->sse3 = IsBitSet(leaf_1.ecx, 0); features->ssse3 = IsBitSet(leaf_1.ecx, 9); features->sse4_1 = IsBitSet(leaf_1.ecx, 19); features->sse4_2 = IsBitSet(leaf_1.ecx, 20); } if (os_preserves->avx_registers) { features->fma3 = IsBitSet(leaf_1.ecx, 12); features->avx = IsBitSet(leaf_1.ecx, 28); features->avx_vnni = IsBitSet(leaf_7_1.eax, 4); features->avx2 = IsBitSet(leaf_7.ebx, 5); } if (os_preserves->avx512_registers) { features->avx512f = IsBitSet(leaf_7.ebx, 16); features->avx512cd = IsBitSet(leaf_7.ebx, 28); features->avx512er = IsBitSet(leaf_7.ebx, 27); features->avx512pf = IsBitSet(leaf_7.ebx, 26); features->avx512bw = IsBitSet(leaf_7.ebx, 30); features->avx512dq = IsBitSet(leaf_7.ebx, 17); features->avx512vl = IsBitSet(leaf_7.ebx, 31); features->avx512ifma = IsBitSet(leaf_7.ebx, 21); features->avx512vbmi = IsBitSet(leaf_7.ecx, 1); features->avx512vbmi2 = IsBitSet(leaf_7.ecx, 6); features->avx512vnni = IsBitSet(leaf_7.ecx, 11); features->avx512bitalg = IsBitSet(leaf_7.ecx, 12); features->avx512vpopcntdq = IsBitSet(leaf_7.ecx, 14); features->avx512_4vnniw = IsBitSet(leaf_7.edx, 2); features->avx512_4vbmi2 = IsBitSet(leaf_7.edx, 3); features->avx512_second_fma = HasSecondFMA(info); features->avx512_4fmaps = IsBitSet(leaf_7.edx, 3); features->avx512_bf16 = IsBitSet(leaf_7_1.eax, 5); features->avx512_vp2intersect = IsBitSet(leaf_7.edx, 8); features->avx512_fp16 = IsBitSet(leaf_7.edx, 23); } if (os_preserves->amx_registers) { features->amx_bf16 = IsBitSet(leaf_7.edx, 22); features->amx_tile = IsBitSet(leaf_7.edx, 24); features->amx_int8 = IsBitSet(leaf_7.edx, 25); features->amx_fp16 = IsBitSet(leaf_7_1.eax, 21); } } else { // When XCR0 is not available (Atom based or older cpus) we need to defer to // the OS via custom code. DetectFeaturesFromOs(info, features); // Now that we have queried the OS for SSE support, we report this back to // os_preserves. This is needed in case of AMD CPU's to enable testing of // sse4a (See ParseExtraAMDCpuId below). if (features->sse) os_preserves->sse_registers = true; } } static void ParseExtraAMDCpuId(const Leaves* leaves, X86Info* info, OsPreserves os_preserves) { const Leaf leaf_80000001 = leaves->leaf_80000001; const Leaf leaf_80000021 = leaves->leaf_80000021; X86Features* const features = &info->features; if (os_preserves.sse_registers) { features->sse4a = IsBitSet(leaf_80000001.ecx, 6); } if (os_preserves.avx_registers) { features->fma4 = IsBitSet(leaf_80000001.ecx, 16); } features->uai = IsBitSet(leaf_80000021.eax, 7); } static const X86Info kEmptyX86Info; static const OsPreserves kEmptyOsPreserves; X86Info GetX86Info(void) { X86Info info = kEmptyX86Info; const Leaves leaves = ReadLeaves(); const bool is_intel = IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_GENUINE_INTEL); const bool is_amd = IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); const bool is_hygon = IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_HYGON_GENUINE); const bool is_zhaoxin = (IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_CENTAUR_HAULS) || IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_SHANGHAI)); SetVendor(leaves.leaf_0, info.vendor); if (is_intel || is_amd || is_hygon || is_zhaoxin) { OsPreserves os_preserves = kEmptyOsPreserves; ParseCpuId(&leaves, &info, &os_preserves); if (is_amd || is_hygon) { ParseExtraAMDCpuId(&leaves, &info, os_preserves); } } return info; } //////////////////////////////////////////////////////////////////////////////// // Microarchitecture //////////////////////////////////////////////////////////////////////////////// #define CPUID(FAMILY, MODEL) ((((FAMILY)&0xFF) << 8) | ((MODEL)&0xFF)) X86Microarchitecture GetX86Microarchitecture(const X86Info* info) { if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_GENUINE_INTEL)) { switch (CPUID(info->family, info->model)) { case CPUID(0x04, 0x01): case CPUID(0x04, 0x02): case CPUID(0x04, 0x03): case CPUID(0x04, 0x04): case CPUID(0x04, 0x05): case CPUID(0x04, 0x07): case CPUID(0x04, 0x08): case CPUID(0x04, 0x09): // https://en.wikichip.org/wiki/intel/microarchitectures/80486 return INTEL_80486; case CPUID(0x05, 0x01): case CPUID(0x05, 0x02): case CPUID(0x05, 0x04): case CPUID(0x05, 0x07): case CPUID(0x05, 0x08): // https://en.wikichip.org/wiki/intel/microarchitectures/p5 return INTEL_P5; case CPUID(0x05, 0x09): case CPUID(0x05, 0x0A): // https://en.wikichip.org/wiki/intel/quark return INTEL_LAKEMONT; case CPUID(0x06, 0x1C): // Intel(R) Atom(TM) CPU 230 @ 1.60GHz case CPUID(0x06, 0x35): case CPUID(0x06, 0x36): case CPUID(0x06, 0x70): // https://en.wikichip.org/wiki/intel/atom/230 // https://en.wikipedia.org/wiki/Bonnell_(microarchitecture) return INTEL_ATOM_BNL; case CPUID(0x06, 0x37): case CPUID(0x06, 0x4C): // https://en.wikipedia.org/wiki/Silvermont return INTEL_ATOM_SMT; case CPUID(0x06, 0x5C): // https://en.wikipedia.org/wiki/Goldmont return INTEL_ATOM_GMT; case CPUID(0x06, 0x7A): // https://en.wikichip.org/wiki/intel/microarchitectures/goldmont_plus return INTEL_ATOM_GMT_PLUS; case CPUID(0x06, 0x8A): case CPUID(0x06, 0x96): case CPUID(0x06, 0x9C): // https://en.wikichip.org/wiki/intel/microarchitectures/tremont return INTEL_ATOM_TMT; case CPUID(0x06, 0x0E): case CPUID(0x06, 0x0F): case CPUID(0x06, 0x16): // https://en.wikipedia.org/wiki/Intel_Core_(microarchitecture) return INTEL_CORE; case CPUID(0x06, 0x17): case CPUID(0x06, 0x1D): // https://en.wikipedia.org/wiki/Penryn_(microarchitecture) return INTEL_PNR; case CPUID(0x06, 0x1A): case CPUID(0x06, 0x1E): case CPUID(0x06, 0x1F): case CPUID(0x06, 0x2E): // https://en.wikipedia.org/wiki/Nehalem_(microarchitecture) return INTEL_NHM; case CPUID(0x06, 0x25): case CPUID(0x06, 0x2C): case CPUID(0x06, 0x2F): // https://en.wikipedia.org/wiki/Westmere_(microarchitecture) return INTEL_WSM; case CPUID(0x06, 0x2A): case CPUID(0x06, 0x2D): // https://en.wikipedia.org/wiki/Sandy_Bridge#Models_and_steppings return INTEL_SNB; case CPUID(0x06, 0x3A): case CPUID(0x06, 0x3E): // https://en.wikipedia.org/wiki/Ivy_Bridge_(microarchitecture)#Models_and_steppings return INTEL_IVB; case CPUID(0x06, 0x3C): case CPUID(0x06, 0x3F): case CPUID(0x06, 0x45): case CPUID(0x06, 0x46): // https://en.wikipedia.org/wiki/Haswell_(microarchitecture) return INTEL_HSW; case CPUID(0x06, 0x3D): case CPUID(0x06, 0x47): case CPUID(0x06, 0x4F): case CPUID(0x06, 0x56): // https://en.wikipedia.org/wiki/Broadwell_(microarchitecture) return INTEL_BDW; case CPUID(0x06, 0x4E): case CPUID(0x06, 0x5E): // https://en.wikipedia.org/wiki/Skylake_(microarchitecture) return INTEL_SKL; case CPUID(0x06, 0x55): if (info->stepping >= 6 && info->stepping <= 7) { // https://en.wikipedia.org/wiki/Cascade_Lake_(microprocessor) return INTEL_CCL; } return INTEL_SKL; case CPUID(0x06, 0x66): // https://en.wikipedia.org/wiki/Cannon_Lake_(microarchitecture) return INTEL_CNL; case CPUID(0x06, 0x7D): // client case CPUID(0x06, 0x7E): // client case CPUID(0x06, 0x9D): // NNP-I case CPUID(0x06, 0x6A): // server case CPUID(0x06, 0x6C): // server // https://en.wikipedia.org/wiki/Ice_Lake_(microprocessor) return INTEL_ICL; case CPUID(0x06, 0x8C): case CPUID(0x06, 0x8D): // https://en.wikipedia.org/wiki/Tiger_Lake_(microarchitecture) return INTEL_TGL; case CPUID(0x06, 0x8F): // https://en.wikipedia.org/wiki/Sapphire_Rapids return INTEL_SPR; case CPUID(0x06, 0x8E): switch (info->stepping) { case 9: return INTEL_KBL; // https://en.wikipedia.org/wiki/Kaby_Lake case 10: return INTEL_CFL; // https://en.wikipedia.org/wiki/Coffee_Lake case 11: return INTEL_WHL; // https://en.wikipedia.org/wiki/Whiskey_Lake_(microarchitecture) case 12: return INTEL_CML; // https://en.wikichip.org/wiki/intel/microarchitectures/comet_lake default: return X86_UNKNOWN; } case CPUID(0x06, 0x9E): if (info->stepping > 9) { // https://en.wikipedia.org/wiki/Coffee_Lake return INTEL_CFL; } else { // https://en.wikipedia.org/wiki/Kaby_Lake return INTEL_KBL; } case CPUID(0x06, 0x97): case CPUID(0x06, 0x9A): case CPUID(0x06, 0xBE): // https://en.wikichip.org/wiki/intel/microarchitectures/alder_lake return INTEL_ADL; case CPUID(0x06, 0xA5): case CPUID(0x06, 0xA6): // https://en.wikichip.org/wiki/intel/microarchitectures/comet_lake return INTEL_CML; case CPUID(0x06, 0xA7): // https://en.wikichip.org/wiki/intel/microarchitectures/rocket_lake return INTEL_RCL; case CPUID(0x06, 0xB7): case CPUID(0x06, 0xBA): case CPUID(0x06, 0xBF): // https://en.wikichip.org/wiki/intel/microarchitectures/raptor_lake return INTEL_RPL; case CPUID(0x06, 0x85): // https://en.wikichip.org/wiki/intel/microarchitectures/knights_mill return INTEL_KNIGHTS_M; case CPUID(0x06, 0x57): // https://en.wikichip.org/wiki/intel/microarchitectures/knights_landing return INTEL_KNIGHTS_L; case CPUID(0x0B, 0x00): // https://en.wikichip.org/wiki/intel/microarchitectures/knights_ferry return INTEL_KNIGHTS_F; case CPUID(0x0B, 0x01): // https://en.wikichip.org/wiki/intel/microarchitectures/knights_corner return INTEL_KNIGHTS_C; case CPUID(0x0F, 0x01): case CPUID(0x0F, 0x02): case CPUID(0x0F, 0x03): case CPUID(0x0F, 0x04): case CPUID(0x0F, 0x06): // https://en.wikichip.org/wiki/intel/microarchitectures/netburst return INTEL_NETBURST; default: return X86_UNKNOWN; } } if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_CENTAUR_HAULS)) { switch (CPUID(info->family, info->model)) { case CPUID(0x06, 0x0F): case CPUID(0x06, 0x19): // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/zhangjiang return ZHAOXIN_ZHANGJIANG; case CPUID(0x07, 0x1B): // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/wudaokou return ZHAOXIN_WUDAOKOU; case CPUID(0x07, 0x3B): // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/lujiazui return ZHAOXIN_LUJIAZUI; case CPUID(0x07, 0x5B): return ZHAOXIN_YONGFENG; default: return X86_UNKNOWN; } } if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_SHANGHAI)) { switch (CPUID(info->family, info->model)) { case CPUID(0x06, 0x0F): case CPUID(0x06, 0x19): // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/zhangjiang return ZHAOXIN_ZHANGJIANG; case CPUID(0x07, 0x1B): // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/wudaokou return ZHAOXIN_WUDAOKOU; case CPUID(0x07, 0x3B): // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/lujiazui return ZHAOXIN_LUJIAZUI; case CPUID(0x07, 0x5B): return ZHAOXIN_YONGFENG; default: return X86_UNKNOWN; } } if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_AUTHENTIC_AMD)) { switch (CPUID(info->family, info->model)) { // https://en.wikichip.org/wiki/amd/cpuid case CPUID(0xF, 0x04): case CPUID(0xF, 0x05): case CPUID(0xF, 0x07): case CPUID(0xF, 0x08): case CPUID(0xF, 0x0C): case CPUID(0xF, 0x0E): case CPUID(0xF, 0x0F): case CPUID(0xF, 0x14): case CPUID(0xF, 0x15): case CPUID(0xF, 0x17): case CPUID(0xF, 0x18): case CPUID(0xF, 0x1B): case CPUID(0xF, 0x1C): case CPUID(0xF, 0x1F): case CPUID(0xF, 0x21): case CPUID(0xF, 0x23): case CPUID(0xF, 0x24): case CPUID(0xF, 0x25): case CPUID(0xF, 0x27): case CPUID(0xF, 0x2B): case CPUID(0xF, 0x2C): case CPUID(0xF, 0x2F): case CPUID(0xF, 0x41): case CPUID(0xF, 0x43): case CPUID(0xF, 0x48): case CPUID(0xF, 0x4B): case CPUID(0xF, 0x4C): case CPUID(0xF, 0x4F): case CPUID(0xF, 0x5D): case CPUID(0xF, 0x5F): case CPUID(0xF, 0x68): case CPUID(0xF, 0x6B): case CPUID(0xF, 0x6F): case CPUID(0xF, 0x7F): case CPUID(0xF, 0xC1): return AMD_HAMMER; case CPUID(0x10, 0x02): case CPUID(0x10, 0x04): case CPUID(0x10, 0x05): case CPUID(0x10, 0x06): case CPUID(0x10, 0x08): case CPUID(0x10, 0x09): case CPUID(0x10, 0x0A): return AMD_K10; case CPUID(0x11, 0x03): // http://developer.amd.com/wordpress/media/2012/10/41788.pdf return AMD_K11; case CPUID(0x12, 0x00): case CPUID(0x12, 0x01): // https://www.amd.com/system/files/TechDocs/44739_12h_Rev_Gd.pdf return AMD_K12; case CPUID(0x14, 0x00): case CPUID(0x14, 0x01): case CPUID(0x14, 0x02): // https://www.amd.com/system/files/TechDocs/47534_14h_Mod_00h-0Fh_Rev_Guide.pdf return AMD_BOBCAT; case CPUID(0x15, 0x01): // https://en.wikichip.org/wiki/amd/microarchitectures/bulldozer return AMD_BULLDOZER; case CPUID(0x15, 0x02): case CPUID(0x15, 0x10): case CPUID(0x15, 0x11): case CPUID(0x15, 0x13): // https://en.wikichip.org/wiki/amd/microarchitectures/piledriver // https://www.amd.com/system/files/TechDocs/48931_15h_Mod_10h-1Fh_Rev_Guide.pdf return AMD_PILEDRIVER; case CPUID(0x15, 0x30): case CPUID(0x15, 0x38): // https://en.wikichip.org/wiki/amd/microarchitectures/steamroller return AMD_STREAMROLLER; case CPUID(0x15, 0x60): case CPUID(0x15, 0x65): case CPUID(0x15, 0x70): // https://en.wikichip.org/wiki/amd/microarchitectures/excavator return AMD_EXCAVATOR; case CPUID(0x16, 0x00): case CPUID(0x16, 0x26): return AMD_JAGUAR; case CPUID(0x16, 0x30): return AMD_PUMA; case CPUID(0x17, 0x01): case CPUID(0x17, 0x11): case CPUID(0x17, 0x18): case CPUID(0x17, 0x20): // https://en.wikichip.org/wiki/amd/microarchitectures/zen return AMD_ZEN; case CPUID(0x17, 0x08): // https://en.wikichip.org/wiki/amd/microarchitectures/zen%2B return AMD_ZEN_PLUS; case CPUID(0x17, 0x31): case CPUID(0x17, 0x47): case CPUID(0x17, 0x60): case CPUID(0x17, 0x68): case CPUID(0x17, 0x71): case CPUID(0x17, 0x84): case CPUID(0x17, 0x90): case CPUID(0x17, 0x98): case CPUID(0x17, 0xA0): // https://en.wikichip.org/wiki/amd/microarchitectures/zen_2 return AMD_ZEN2; case CPUID(0x19, 0x00): case CPUID(0x19, 0x01): case CPUID(0x19, 0x08): case CPUID(0x19, 0x21): case CPUID(0x19, 0x30): case CPUID(0x19, 0x40): case CPUID(0x19, 0x44): case CPUID(0x19, 0x50): // https://en.wikichip.org/wiki/amd/microarchitectures/zen_3 return AMD_ZEN3; case CPUID(0x19, 0x10): case CPUID(0x19, 0x11): case CPUID(0x19, 0x61): case CPUID(0x19, 0x74): // https://en.wikichip.org/wiki/amd/microarchitectures/zen_4 return AMD_ZEN4; default: return X86_UNKNOWN; } } if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_HYGON_GENUINE)) { switch (CPUID(info->family, info->model)) { case CPUID(0x18, 0x00): case CPUID(0x18, 0x01): return AMD_ZEN; } } return X86_UNKNOWN; } //////////////////////////////////////////////////////////////////////////////// // CacheInfo //////////////////////////////////////////////////////////////////////////////// static const CacheLevelInfo kEmptyCacheLevelInfo; static CacheLevelInfo GetCacheLevelInfo(const uint32_t reg) { const int UNDEF = -1; const int KiB = 1024; const int MiB = 1024 * KiB; switch (reg) { case 0x01: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * KiB, .ways = 4, .line_size = UNDEF, .tlb_entries = 32, .partitioning = 0}; case 0x02: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * MiB, .ways = 0xFF, .line_size = UNDEF, .tlb_entries = 2, .partitioning = 0}; case 0x03: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * KiB, .ways = 4, .line_size = UNDEF, .tlb_entries = 64, .partitioning = 0}; case 0x04: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * MiB, .ways = 4, .line_size = UNDEF, .tlb_entries = 8, .partitioning = 0}; case 0x05: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * MiB, .ways = 4, .line_size = UNDEF, .tlb_entries = 32, .partitioning = 0}; case 0x06: return (CacheLevelInfo){.level = 1, .cache_type = CPU_FEATURE_CACHE_INSTRUCTION, .cache_size = 8 * KiB, .ways = 4, .line_size = 32, .tlb_entries = UNDEF, .partitioning = 0}; case 0x08: return (CacheLevelInfo){.level = 1, .cache_type = CPU_FEATURE_CACHE_INSTRUCTION, .cache_size = 16 * KiB, .ways = 4, .line_size = 32, .tlb_entries = UNDEF, .partitioning = 0}; case 0x09: return (CacheLevelInfo){.level = 1, .cache_type = CPU_FEATURE_CACHE_INSTRUCTION, .cache_size = 32 * KiB, .ways = 4, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x0A: return (CacheLevelInfo){.level = 1, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 8 * KiB, .ways = 2, .line_size = 32, .tlb_entries = UNDEF, .partitioning = 0}; case 0x0B: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * MiB, .ways = 4, .line_size = UNDEF, .tlb_entries = 4, .partitioning = 0}; case 0x0C: return (CacheLevelInfo){.level = 1, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 16 * KiB, .ways = 4, .line_size = 32, .tlb_entries = UNDEF, .partitioning = 0}; case 0x0D: return (CacheLevelInfo){.level = 1, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 16 * KiB, .ways = 4, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x0E: return (CacheLevelInfo){.level = 1, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 24 * KiB, .ways = 6, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x1D: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 128 * KiB, .ways = 2, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x21: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 256 * KiB, .ways = 8, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x22: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 512 * KiB, .ways = 4, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 2}; case 0x23: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 1 * MiB, .ways = 8, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 2}; case 0x24: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 1 * MiB, .ways = 16, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x25: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 2 * MiB, .ways = 8, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 2}; case 0x29: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 4 * MiB, .ways = 8, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 2}; case 0x2C: return (CacheLevelInfo){.level = 1, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 32 * KiB, .ways = 8, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x30: return (CacheLevelInfo){.level = 1, .cache_type = CPU_FEATURE_CACHE_INSTRUCTION, .cache_size = 32 * KiB, .ways = 8, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x40: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = UNDEF, .ways = UNDEF, .line_size = UNDEF, .tlb_entries = UNDEF, .partitioning = 0}; case 0x41: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 128 * KiB, .ways = 4, .line_size = 32, .tlb_entries = UNDEF, .partitioning = 0}; case 0x42: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 256 * KiB, .ways = 4, .line_size = 32, .tlb_entries = UNDEF, .partitioning = 0}; case 0x43: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 512 * KiB, .ways = 4, .line_size = 32, .tlb_entries = UNDEF, .partitioning = 0}; case 0x44: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 1 * MiB, .ways = 4, .line_size = 32, .tlb_entries = UNDEF, .partitioning = 0}; case 0x45: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 2 * MiB, .ways = 4, .line_size = 32, .tlb_entries = UNDEF, .partitioning = 0}; case 0x46: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 4 * MiB, .ways = 4, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x47: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 8 * MiB, .ways = 8, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x48: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 3 * MiB, .ways = 12, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x49: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 4 * MiB, .ways = 16, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case (0x49 | (1 << 8)): return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 4 * MiB, .ways = 16, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x4A: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 6 * MiB, .ways = 12, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x4B: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 8 * MiB, .ways = 16, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x4C: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 12 * MiB, .ways = 12, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x4D: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 16 * MiB, .ways = 16, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x4E: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 6 * MiB, .ways = 24, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x4F: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * KiB, .ways = UNDEF, .line_size = UNDEF, .tlb_entries = 32, .partitioning = 0}; case 0x50: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * KiB, .ways = UNDEF, .line_size = UNDEF, .tlb_entries = 64, .partitioning = 0}; case 0x51: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * KiB, .ways = UNDEF, .line_size = UNDEF, .tlb_entries = 128, .partitioning = 0}; case 0x52: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * KiB, .ways = UNDEF, .line_size = UNDEF, .tlb_entries = 256, .partitioning = 0}; case 0x55: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 2 * MiB, .ways = 0xFF, .line_size = UNDEF, .tlb_entries = 7, .partitioning = 0}; case 0x56: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * MiB, .ways = 4, .line_size = UNDEF, .tlb_entries = 16, .partitioning = 0}; case 0x57: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * KiB, .ways = 4, .line_size = UNDEF, .tlb_entries = 16, .partitioning = 0}; case 0x59: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * KiB, .ways = 0xFF, .line_size = UNDEF, .tlb_entries = 16, .partitioning = 0}; case 0x5A: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 2 * MiB, .ways = 4, .line_size = UNDEF, .tlb_entries = 32, .partitioning = 0}; case 0x5B: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * KiB, .ways = UNDEF, .line_size = UNDEF, .tlb_entries = 64, .partitioning = 0}; case 0x5C: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * KiB, .ways = UNDEF, .line_size = UNDEF, .tlb_entries = 128, .partitioning = 0}; case 0x5D: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4, .ways = UNDEF, .line_size = UNDEF, .tlb_entries = 256, .partitioning = 0}; case 0x60: return (CacheLevelInfo){.level = 1, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 16 * KiB, .ways = 8, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x61: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * KiB, .ways = 0xFF, .line_size = UNDEF, .tlb_entries = 48, .partitioning = 0}; case 0x63: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 2 * MiB, .ways = 4, .line_size = UNDEF, .tlb_entries = 4, .partitioning = 0}; case 0x66: return (CacheLevelInfo){.level = 1, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 8 * KiB, .ways = 4, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x67: return (CacheLevelInfo){.level = 1, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 16 * KiB, .ways = 4, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x68: return (CacheLevelInfo){.level = 1, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 32 * KiB, .ways = 4, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x70: return (CacheLevelInfo){.level = 1, .cache_type = CPU_FEATURE_CACHE_INSTRUCTION, .cache_size = 12 * KiB, .ways = 8, .line_size = UNDEF, .tlb_entries = UNDEF, .partitioning = 0}; case 0x71: return (CacheLevelInfo){.level = 1, .cache_type = CPU_FEATURE_CACHE_INSTRUCTION, .cache_size = 16 * KiB, .ways = 8, .line_size = UNDEF, .tlb_entries = UNDEF, .partitioning = 0}; case 0x72: return (CacheLevelInfo){.level = 1, .cache_type = CPU_FEATURE_CACHE_INSTRUCTION, .cache_size = 32 * KiB, .ways = 8, .line_size = UNDEF, .tlb_entries = UNDEF, .partitioning = 0}; case 0x76: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 2 * MiB, .ways = 0xFF, .line_size = UNDEF, .tlb_entries = 8, .partitioning = 0}; case 0x78: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 1 * MiB, .ways = 4, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x79: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 128 * KiB, .ways = 8, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 2}; case 0x7A: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 256 * KiB, .ways = 8, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 2}; case 0x7B: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 512 * KiB, .ways = 8, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 2}; case 0x7C: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 1 * MiB, .ways = 8, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 2}; case 0x7D: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 2 * MiB, .ways = 8, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x7F: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 512 * KiB, .ways = 2, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x80: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 512 * KiB, .ways = 8, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0x82: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 256 * KiB, .ways = 8, .line_size = 32, .tlb_entries = UNDEF, .partitioning = 0}; case 0x83: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 512 * KiB, .ways = 8, .line_size = 32, .tlb_entries = UNDEF, .partitioning = 0}; case 0x84: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 1 * MiB, .ways = 8, .line_size = 32, .tlb_entries = UNDEF, .partitioning = 0}; case 0x85: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 2 * MiB, .ways = 8, .line_size = 32, .tlb_entries = UNDEF, .partitioning = 0}; case 0x86: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 512 * KiB, .ways = 4, .line_size = 32, .tlb_entries = UNDEF, .partitioning = 0}; case 0x87: return (CacheLevelInfo){.level = 2, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 1 * MiB, .ways = 8, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0xA0: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_DTLB, .cache_size = 4 * KiB, .ways = 0xFF, .line_size = UNDEF, .tlb_entries = 32, .partitioning = 0}; case 0xB0: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * KiB, .ways = 4, .line_size = UNDEF, .tlb_entries = 128, .partitioning = 0}; case 0xB1: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 2 * MiB, .ways = 4, .line_size = UNDEF, .tlb_entries = 8, .partitioning = 0}; case 0xB2: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * KiB, .ways = 4, .line_size = UNDEF, .tlb_entries = 64, .partitioning = 0}; case 0xB3: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * KiB, .ways = 4, .line_size = UNDEF, .tlb_entries = 128, .partitioning = 0}; case 0xB4: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * KiB, .ways = 4, .line_size = UNDEF, .tlb_entries = 256, .partitioning = 0}; case 0xB5: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * KiB, .ways = 8, .line_size = UNDEF, .tlb_entries = 64, .partitioning = 0}; case 0xB6: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * KiB, .ways = 8, .line_size = UNDEF, .tlb_entries = 128, .partitioning = 0}; case 0xBA: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * KiB, .ways = 4, .line_size = UNDEF, .tlb_entries = 64, .partitioning = 0}; case 0xC0: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_TLB, .cache_size = 4 * KiB, .ways = 4, .line_size = UNDEF, .tlb_entries = 8, .partitioning = 0}; case 0xC1: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_STLB, .cache_size = 4 * KiB, .ways = 8, .line_size = UNDEF, .tlb_entries = 1024, .partitioning = 0}; case 0xC2: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_DTLB, .cache_size = 4 * KiB, .ways = 4, .line_size = UNDEF, .tlb_entries = 16, .partitioning = 0}; case 0xC3: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_STLB, .cache_size = 4 * KiB, .ways = 6, .line_size = UNDEF, .tlb_entries = 1536, .partitioning = 0}; case 0xCA: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_STLB, .cache_size = 4 * KiB, .ways = 4, .line_size = UNDEF, .tlb_entries = 512, .partitioning = 0}; case 0xD0: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 512 * KiB, .ways = 4, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0xD1: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 1 * MiB, .ways = 4, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0xD2: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 2 * MiB, .ways = 4, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0xD6: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 1 * MiB, .ways = 8, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0xD7: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 2 * MiB, .ways = 8, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0xD8: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 4 * MiB, .ways = 8, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0xDC: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 1 * 1536 * KiB, .ways = 12, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0xDD: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 3 * MiB, .ways = 12, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0xDE: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 6 * MiB, .ways = 12, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0xE2: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 2 * MiB, .ways = 16, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0xE3: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 4 * MiB, .ways = 16, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0xE4: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 8 * MiB, .ways = 16, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0xEA: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 12 * MiB, .ways = 24, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0xEB: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 18 * MiB, .ways = 24, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0xEC: return (CacheLevelInfo){.level = 3, .cache_type = CPU_FEATURE_CACHE_DATA, .cache_size = 24 * MiB, .ways = 24, .line_size = 64, .tlb_entries = UNDEF, .partitioning = 0}; case 0xF0: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_PREFETCH, .cache_size = 64 * KiB, .ways = UNDEF, .line_size = UNDEF, .tlb_entries = UNDEF, .partitioning = 0}; case 0xF1: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_PREFETCH, .cache_size = 128 * KiB, .ways = UNDEF, .line_size = UNDEF, .tlb_entries = UNDEF, .partitioning = 0}; case 0xFF: return (CacheLevelInfo){.level = UNDEF, .cache_type = CPU_FEATURE_CACHE_NULL, .cache_size = UNDEF, .ways = UNDEF, .line_size = UNDEF, .tlb_entries = UNDEF, .partitioning = 0}; default: return kEmptyCacheLevelInfo; } } // From https://www.felixcloutier.com/x86/cpuid#tbl-3-12 static void ParseLeaf2(const Leaves* leaves, CacheInfo* info) { Leaf leaf = leaves->leaf_2; // The least-significant byte in register EAX (register AL) will always return // 01H. Software should ignore this value and not interpret it as an // informational descriptor. leaf.eax &= 0xFFFFFF00; // Zeroing out AL. 0 is the empty descriptor. // The most significant bit (bit 31) of each register indicates whether the // register contains valid information (set to 0) or is reserved (set to 1). if (IsBitSet(leaf.eax, 31)) leaf.eax = 0; if (IsBitSet(leaf.ebx, 31)) leaf.ebx = 0; if (IsBitSet(leaf.ecx, 31)) leaf.ecx = 0; if (IsBitSet(leaf.edx, 31)) leaf.edx = 0; uint8_t data[16]; #if __STDC_VERSION__ >= 201112L _Static_assert(sizeof(Leaf) == sizeof(data), "Leaf must be 16 bytes"); #endif copy((char*)(data), (const char*)(&leaf), sizeof(data)); for (size_t i = 0; i < sizeof(data); ++i) { const uint8_t descriptor = data[i]; if (descriptor == 0) continue; info->levels[info->size] = GetCacheLevelInfo(descriptor); info->size++; } } static const CacheInfo kEmptyCacheInfo; // For newer Intel CPUs uses "CPUID, eax=0x00000004". // https://www.felixcloutier.com/x86/cpuid#input-eax-=-04h--returns-deterministic-cache-parameters-for-each-level // For newer AMD CPUs uses "CPUID, eax=0x8000001D" static void ParseCacheInfo(const int max_cpuid_leaf, uint32_t leaf_id, CacheInfo* old_info) { CacheInfo info = kEmptyCacheInfo; for (int index = 0; info.size < CPU_FEATURES_MAX_CACHE_LEVEL; ++index) { const Leaf leaf = SafeCpuIdEx(max_cpuid_leaf, leaf_id, index); int cache_type_field = ExtractBitRange(leaf.eax, 4, 0); CacheType cache_type; if (cache_type_field == 1) cache_type = CPU_FEATURE_CACHE_DATA; else if (cache_type_field == 2) cache_type = CPU_FEATURE_CACHE_INSTRUCTION; else if (cache_type_field == 3) cache_type = CPU_FEATURE_CACHE_UNIFIED; else // Intel Processor Identification and the CPUID Instruction Application // Note 485 page 37 Table 5-10. Deterministic Cache Parameters. // We skip cache parsing in case null of cache type or cache type in the // range of 4-31 according to documentation. break; int level = ExtractBitRange(leaf.eax, 7, 5); int line_size = ExtractBitRange(leaf.ebx, 11, 0) + 1; int partitioning = ExtractBitRange(leaf.ebx, 21, 12) + 1; int ways = ExtractBitRange(leaf.ebx, 31, 22) + 1; int tlb_entries = leaf.ecx + 1; int cache_size = ways * partitioning * line_size * tlb_entries; info.levels[info.size] = (CacheLevelInfo){.level = level, .cache_type = cache_type, .cache_size = cache_size, .ways = ways, .line_size = line_size, .tlb_entries = tlb_entries, .partitioning = partitioning}; ++info.size; } // Override CacheInfo if we successfully extracted Deterministic Cache // Parameters. if (info.size > 0) *old_info = info; } typedef struct { int level; int cache_id; CacheType cache_type; } CacheLevelInfoLegacyAMD; static int GetWaysLegacyAMD(int cache_level, const uint32_t cache_id) { // https://www.amd.com/system/files/TechDocs/25481.pdf page 23 // CPUID.8000_0005_ECX[23:16] L1 data cache associativity. // CPUID.8000_0005_EDX[23:16] L1 instruction cache associativity. if (cache_level == 1) { return ExtractBitRange(cache_id, 23, 16); } // https://www.amd.com/system/files/TechDocs/25481.pdf page 24 // See Table 4: L2/L3 Cache and TLB Associativity Field Definition. // CPUID.8000_0006_ECX[15:12] L2 cache associativity. // CPUID.8000_0006_EDX[15:12] L3 cache associativity. const int ways = ExtractBitRange(cache_id, 15, 12); switch (ways) { case 0x0: case 0x1: case 0x2: case 0x4: return ways; case 0x6: return 8; case 0x8: return 16; case 0xA: return 32; case 0xB: return 48; case 0xC: return 64; case 0xD: return 96; case 0xE: return 128; case 0xF: return 255; default: return -1; // Reserved } } static int GetCacheSizeLegacyAMD(int cache_level, const uint32_t cache_id) { switch (cache_level) { case 1: // https://www.amd.com/system/files/TechDocs/25481.pdf page 23 // CPUID.8000_0005_ECX[31:24] L1 data cache size in KB. // CPUID.8000_0005_EDX[31:24] L1 instruction cache size KB. return ExtractBitRange(cache_id, 31, 24); case 2: // https://www.amd.com/system/files/TechDocs/25481.pdf page 25 // CPUID.8000_0006_ECX[31:16] L2 cache size in KB. return ExtractBitRange(cache_id, 31, 16); case 3: // https://www.amd.com/system/files/TechDocs/25481.pdf page 25 // CPUID.8000_0006_EDX[31:18] L3 cache size. // Specifies the L3 cache size is within the following range: // (L3Size[31:18] * 512KB) <= L3 cache size < ((L3Size[31:18]+1) * 512KB). return ExtractBitRange(cache_id, 31, 18) * 512; default: return 0; } } #define LEGACY_AMD_MAX_CACHE_LEVEL 4 // https://www.amd.com/system/files/TechDocs/25481.pdf // CPUID Fn8000_0005_E[A,B,C,D]X, Fn8000_0006_E[A,B,C,D]X - TLB and Cache info static void ParseCacheInfoLegacyAMD(const uint32_t max_ext, CacheInfo* info) { const Leaf cache_tlb_leaf1 = SafeCpuIdEx(max_ext, 0x80000005, 0); const Leaf cache_tlb_leaf2 = SafeCpuIdEx(max_ext, 0x80000006, 0); const CacheLevelInfoLegacyAMD legacy_cache_info[LEGACY_AMD_MAX_CACHE_LEVEL] = {(CacheLevelInfoLegacyAMD){.cache_id = cache_tlb_leaf1.ecx, .cache_type = CPU_FEATURE_CACHE_DATA, .level = 1}, (CacheLevelInfoLegacyAMD){.cache_id = cache_tlb_leaf1.edx, .cache_type = CPU_FEATURE_CACHE_INSTRUCTION, .level = 1}, (CacheLevelInfoLegacyAMD){.cache_id = cache_tlb_leaf2.ecx, .cache_type = CPU_FEATURE_CACHE_UNIFIED, .level = 2}, (CacheLevelInfoLegacyAMD){.cache_id = cache_tlb_leaf2.edx, .cache_type = CPU_FEATURE_CACHE_UNIFIED, .level = 3}}; const int KiB = 1024; const int UNDEF = -1; for (int i = 0; i < LEGACY_AMD_MAX_CACHE_LEVEL; ++i) { const int level = legacy_cache_info[i].level; const int cache_id = legacy_cache_info[i].cache_id; const CacheType cache_type = legacy_cache_info[i].cache_type; const int cache_size = GetCacheSizeLegacyAMD(level, cache_id); if (cache_size == 0) break; info->levels[i] = (CacheLevelInfo){.level = level, .cache_type = cache_type, .cache_size = cache_size * KiB, .ways = GetWaysLegacyAMD(level, cache_id), .line_size = ExtractBitRange(cache_id, 7, 0), .tlb_entries = UNDEF, .partitioning = UNDEF}; ++info->size; } } CacheInfo GetX86CacheInfo(void) { CacheInfo info = kEmptyCacheInfo; const Leaves leaves = ReadLeaves(); if (IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_GENUINE_INTEL) || IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_CENTAUR_HAULS) || IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_SHANGHAI)) { ParseLeaf2(&leaves, &info); ParseCacheInfo(leaves.max_cpuid_leaf, 4, &info); } else if (IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_AUTHENTIC_AMD) || IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_HYGON_GENUINE)) { // If CPUID Fn8000_0001_ECX[TopologyExtensions]==0 // then CPUID Fn8000_0001_E[D,C,B,A]X is reserved. // https://www.amd.com/system/files/TechDocs/25481.pdf if (IsBitSet(leaves.leaf_80000001.ecx, 22)) { ParseCacheInfo(leaves.max_cpuid_leaf_ext, 0x8000001D, &info); } else { ParseCacheInfoLegacyAMD(leaves.max_cpuid_leaf_ext, &info); } } return info; } //////////////////////////////////////////////////////////////////////////////// // Definitions for introspection. //////////////////////////////////////////////////////////////////////////////// #define INTROSPECTION_TABLE \ LINE(X86_FPU, fpu, , , ) \ LINE(X86_TSC, tsc, , , ) \ LINE(X86_CX8, cx8, , , ) \ LINE(X86_CLFSH, clfsh, , , ) \ LINE(X86_MMX, mmx, , , ) \ LINE(X86_AES, aes, , , ) \ LINE(X86_ERMS, erms, , , ) \ LINE(X86_F16C, f16c, , , ) \ LINE(X86_FMA4, fma4, , , ) \ LINE(X86_FMA3, fma3, , , ) \ LINE(X86_VAES, vaes, , , ) \ LINE(X86_VPCLMULQDQ, vpclmulqdq, , , ) \ LINE(X86_BMI1, bmi1, , , ) \ LINE(X86_HLE, hle, , , ) \ LINE(X86_BMI2, bmi2, , , ) \ LINE(X86_RTM, rtm, , , ) \ LINE(X86_RDSEED, rdseed, , , ) \ LINE(X86_CLFLUSHOPT, clflushopt, , , ) \ LINE(X86_CLWB, clwb, , , ) \ LINE(X86_SSE, sse, , , ) \ LINE(X86_SSE2, sse2, , , ) \ LINE(X86_SSE3, sse3, , , ) \ LINE(X86_SSSE3, ssse3, , , ) \ LINE(X86_SSE4_1, sse4_1, , , ) \ LINE(X86_SSE4_2, sse4_2, , , ) \ LINE(X86_SSE4A, sse4a, , , ) \ LINE(X86_AVX, avx, , , ) \ LINE(X86_AVX_VNNI, avx_vnni, , , ) \ LINE(X86_AVX2, avx2, , , ) \ LINE(X86_AVX512F, avx512f, , , ) \ LINE(X86_AVX512CD, avx512cd, , , ) \ LINE(X86_AVX512ER, avx512er, , , ) \ LINE(X86_AVX512PF, avx512pf, , , ) \ LINE(X86_AVX512BW, avx512bw, , , ) \ LINE(X86_AVX512DQ, avx512dq, , , ) \ LINE(X86_AVX512VL, avx512vl, , , ) \ LINE(X86_AVX512IFMA, avx512ifma, , , ) \ LINE(X86_AVX512VBMI, avx512vbmi, , , ) \ LINE(X86_AVX512VBMI2, avx512vbmi2, , , ) \ LINE(X86_AVX512VNNI, avx512vnni, , , ) \ LINE(X86_AVX512BITALG, avx512bitalg, , , ) \ LINE(X86_AVX512VPOPCNTDQ, avx512vpopcntdq, , , ) \ LINE(X86_AVX512_4VNNIW, avx512_4vnniw, , , ) \ LINE(X86_AVX512_4VBMI2, avx512_4vbmi2, , , ) \ LINE(X86_AVX512_SECOND_FMA, avx512_second_fma, , , ) \ LINE(X86_AVX512_4FMAPS, avx512_4fmaps, , , ) \ LINE(X86_AVX512_BF16, avx512_bf16, , , ) \ LINE(X86_AVX512_VP2INTERSECT, avx512_vp2intersect, , , ) \ LINE(X86_AVX512_FP16, avx512_fp16, , , ) \ LINE(X86_AMX_BF16, amx_bf16, , , ) \ LINE(X86_AMX_TILE, amx_tile, , , ) \ LINE(X86_AMX_INT8, amx_int8, , , ) \ LINE(X86_AMX_FP16, amx_fp16, , , ) \ LINE(X86_PCLMULQDQ, pclmulqdq, , , ) \ LINE(X86_SMX, smx, , , ) \ LINE(X86_SGX, sgx, , , ) \ LINE(X86_CX16, cx16, , , ) \ LINE(X86_SHA, sha, , , ) \ LINE(X86_POPCNT, popcnt, , , ) \ LINE(X86_MOVBE, movbe, , , ) \ LINE(X86_RDRND, rdrnd, , , ) \ LINE(X86_DCA, dca, , , ) \ LINE(X86_SS, ss, , , ) \ LINE(X86_ADX, adx, , , ) \ LINE(X86_LZCNT, lzcnt, , , ) \ LINE(X86_GFNI, gfni, , , ) \ LINE(X86_MOVDIRI, movdiri, , , ) \ LINE(X86_MOVDIR64B, movdir64b, , , ) \ LINE(X86_FS_REP_MOV, fs_rep_mov, , , ) \ LINE(X86_FZ_REP_MOVSB, fz_rep_movsb, , , ) \ LINE(X86_FS_REP_STOSB, fs_rep_stosb, , , ) \ LINE(X86_FS_REP_CMPSB_SCASB, fs_rep_cmpsb_scasb, , , ) \ LINE(X86_LAM, lam, , , ) \ LINE(X86_UAI, uai, , , ) #define INTROSPECTION_PREFIX X86 #define INTROSPECTION_ENUM_PREFIX X86 #include "define_introspection.inl" #define X86_MICROARCHITECTURE_NAMES \ LINE(X86_UNKNOWN) \ LINE(ZHAOXIN_ZHANGJIANG) \ LINE(ZHAOXIN_WUDAOKOU) \ LINE(ZHAOXIN_LUJIAZUI) \ LINE(ZHAOXIN_YONGFENG) \ LINE(INTEL_80486) \ LINE(INTEL_P5) \ LINE(INTEL_LAKEMONT) \ LINE(INTEL_CORE) \ LINE(INTEL_PNR) \ LINE(INTEL_NHM) \ LINE(INTEL_ATOM_BNL) \ LINE(INTEL_WSM) \ LINE(INTEL_SNB) \ LINE(INTEL_IVB) \ LINE(INTEL_ATOM_SMT) \ LINE(INTEL_HSW) \ LINE(INTEL_BDW) \ LINE(INTEL_SKL) \ LINE(INTEL_CCL) \ LINE(INTEL_ATOM_GMT) \ LINE(INTEL_ATOM_GMT_PLUS) \ LINE(INTEL_ATOM_TMT) \ LINE(INTEL_KBL) \ LINE(INTEL_CFL) \ LINE(INTEL_WHL) \ LINE(INTEL_CML) \ LINE(INTEL_CNL) \ LINE(INTEL_ICL) \ LINE(INTEL_TGL) \ LINE(INTEL_SPR) \ LINE(INTEL_ADL) \ LINE(INTEL_RCL) \ LINE(INTEL_RPL) \ LINE(INTEL_KNIGHTS_M) \ LINE(INTEL_KNIGHTS_L) \ LINE(INTEL_KNIGHTS_F) \ LINE(INTEL_KNIGHTS_C) \ LINE(INTEL_NETBURST) \ LINE(AMD_HAMMER) \ LINE(AMD_K10) \ LINE(AMD_K11) \ LINE(AMD_K12) \ LINE(AMD_BOBCAT) \ LINE(AMD_PILEDRIVER) \ LINE(AMD_STREAMROLLER) \ LINE(AMD_EXCAVATOR) \ LINE(AMD_BULLDOZER) \ LINE(AMD_JAGUAR) \ LINE(AMD_PUMA) \ LINE(AMD_ZEN) \ LINE(AMD_ZEN_PLUS) \ LINE(AMD_ZEN2) \ LINE(AMD_ZEN3) \ LINE(AMD_ZEN4) const char* GetX86MicroarchitectureName(X86Microarchitecture value) { #define LINE(ENUM) [ENUM] = STRINGIZE(ENUM), static const char* kMicroarchitectureNames[] = {X86_MICROARCHITECTURE_NAMES}; #undef LINE if (value >= X86_MICROARCHITECTURE_LAST_) return "unknown microarchitecture"; return kMicroarchitectureNames[value]; } cpu-features-0.9.0/src/impl_x86_freebsd.c000066400000000000000000000051441450057454500202330ustar00rootroot00000000000000// 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. // 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 "cpu_features_macros.h" #ifdef CPU_FEATURES_ARCH_X86 #ifdef CPU_FEATURES_OS_FREEBSD #include "impl_x86__base_implementation.inl" static void OverrideOsPreserves(OsPreserves* os_preserves) { (void)os_preserves; // No override } #include "internal/filesystem.h" #include "internal/stack_line_reader.h" #include "internal/string_view.h" static void DetectFeaturesFromOs(X86Info* info, X86Features* features) { (void)info; // Handling FreeBSD platform through parsing /var/run/dmesg.boot. const int fd = CpuFeatures_OpenFile("/var/run/dmesg.boot"); if (fd >= 0) { StackLineReader reader; StackLineReader_Initialize(&reader, fd); for (bool stop = false; !stop;) { const LineResult result = StackLineReader_NextLine(&reader); if (result.eof) stop = true; const StringView line = result.line; if (!CpuFeatures_StringView_StartsWith(line, str(" Features"))) continue; // Lines of interests are of the following form: // " Features=0x1783fbff" // We first extract the comma separated values between angle brackets. StringView csv = result.line; int index = CpuFeatures_StringView_IndexOfChar(csv, '<'); if (index >= 0) csv = CpuFeatures_StringView_PopFront(csv, index + 1); if (csv.size > 0 && CpuFeatures_StringView_Back(csv) == '>') csv = CpuFeatures_StringView_PopBack(csv, 1); if (CpuFeatures_StringView_HasWord(csv, "SSE", ',')) features->sse = true; if (CpuFeatures_StringView_HasWord(csv, "SSE2", ',')) features->sse2 = true; if (CpuFeatures_StringView_HasWord(csv, "SSE3", ',')) features->sse3 = true; if (CpuFeatures_StringView_HasWord(csv, "SSSE3", ',')) features->ssse3 = true; if (CpuFeatures_StringView_HasWord(csv, "SSE4.1", ',')) features->sse4_1 = true; if (CpuFeatures_StringView_HasWord(csv, "SSE4.2", ',')) features->sse4_2 = true; } CpuFeatures_CloseFile(fd); } } #endif // CPU_FEATURES_OS_FREEBSD #endif // CPU_FEATURES_ARCH_X86 cpu-features-0.9.0/src/impl_x86_linux_or_android.c000066400000000000000000000043331450057454500221570ustar00rootroot00000000000000// 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. // 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 "cpu_features_macros.h" #ifdef CPU_FEATURES_ARCH_X86 #if defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID) #include "impl_x86__base_implementation.inl" static void OverrideOsPreserves(OsPreserves* os_preserves) { (void)os_preserves; // No override } #include "internal/filesystem.h" #include "internal/stack_line_reader.h" #include "internal/string_view.h" static void DetectFeaturesFromOs(X86Info* info, X86Features* features) { (void)info; // Handling Linux platform through /proc/cpuinfo. const int fd = CpuFeatures_OpenFile("/proc/cpuinfo"); if (fd >= 0) { StackLineReader reader; StackLineReader_Initialize(&reader, fd); for (bool stop = false; !stop;) { const LineResult result = StackLineReader_NextLine(&reader); if (result.eof) stop = true; const StringView line = result.line; StringView key, value; if (!CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) continue; if (!CpuFeatures_StringView_IsEquals(key, str("flags"))) continue; features->sse = CpuFeatures_StringView_HasWord(value, "sse", ' '); features->sse2 = CpuFeatures_StringView_HasWord(value, "sse2", ' '); features->sse3 = CpuFeatures_StringView_HasWord(value, "pni", ' '); 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; } CpuFeatures_CloseFile(fd); } } #endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID) #endif // CPU_FEATURES_ARCH_X86 cpu-features-0.9.0/src/impl_x86_macos.c000066400000000000000000000041751450057454500177260ustar00rootroot00000000000000// 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. // 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 "cpu_features_macros.h" #ifdef CPU_FEATURES_ARCH_X86 #ifdef CPU_FEATURES_OS_MACOS #include "impl_x86__base_implementation.inl" #if !defined(HAVE_SYSCTLBYNAME) #error "Darwin needs support for sysctlbyname" #endif #include #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 static void OverrideOsPreserves(OsPreserves* os_preserves) { // On Darwin AVX512 support is On-demand. // We have to query the OS instead of querying the Zmm save/restore state. // https://github.com/apple/darwin-xnu/blob/8f02f2a044b9bb1ad951987ef5bab20ec9486310/osfmk/i386/fpu.c#L173-L199 os_preserves->avx512_registers = GetDarwinSysCtlByName("hw.optional.avx512f"); } static void DetectFeaturesFromOs(X86Info* info, X86Features* features) { (void)info; // 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"); } #endif // CPU_FEATURES_OS_MACOS #endif // CPU_FEATURES_ARCH_X86 cpu-features-0.9.0/src/impl_x86_windows.c000066400000000000000000000042041450057454500203070ustar00rootroot00000000000000// 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. // 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 "cpu_features_macros.h" #ifdef CPU_FEATURES_ARCH_X86 #ifdef CPU_FEATURES_OS_WINDOWS #include "impl_x86__base_implementation.inl" static void OverrideOsPreserves(OsPreserves* os_preserves) { (void)os_preserves; // No override } #include "internal/windows_utils.h" #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 static void DetectFeaturesFromOs(X86Info* info, X86Features* features) { // Handling Windows platform through IsProcessorFeaturePresent. // 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); features->ssse3 = GetWindowsIsProcessorFeaturePresent(PF_SSSE3_INSTRUCTIONS_AVAILABLE); features->sse4_1 = GetWindowsIsProcessorFeaturePresent(PF_SSE4_1_INSTRUCTIONS_AVAILABLE); features->sse4_2 = GetWindowsIsProcessorFeaturePresent(PF_SSE4_2_INSTRUCTIONS_AVAILABLE); // do not bother checking PF_AVX* // cause AVX enabled processor will have XCR0 be exposed and this function will be skipped at all } #endif // CPU_FEATURES_OS_WINDOWS #endif // CPU_FEATURES_ARCH_X86 cpu-features-0.9.0/src/stack_line_reader.c000066400000000000000000000100501450057454500205210ustar00rootroot00000000000000// 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. // 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/stack_line_reader.h" #include #include #include #include "internal/filesystem.h" void StackLineReader_Initialize(StackLineReader* reader, int fd) { reader->view.ptr = reader->buffer; reader->view.size = 0; reader->skip_mode = false; reader->fd = fd; } // Replaces the content of buffer with bytes from the file. static int LoadFullBuffer(StackLineReader* reader) { const int read = CpuFeatures_ReadFile(reader->fd, reader->buffer, STACK_LINE_READER_BUFFER_SIZE); assert(read >= 0); reader->view.ptr = reader->buffer; reader->view.size = read; return read; } // Appends with bytes from the file to buffer, filling the remaining space. static int LoadMore(StackLineReader* reader) { char* const ptr = reader->buffer + reader->view.size; const size_t size_to_read = STACK_LINE_READER_BUFFER_SIZE - reader->view.size; const int read = CpuFeatures_ReadFile(reader->fd, ptr, size_to_read); assert(read >= 0); assert(read <= (int)size_to_read); reader->view.size += read; return read; } static int IndexOfEol(StackLineReader* reader) { return CpuFeatures_StringView_IndexOfChar(reader->view, '\n'); } // Relocate buffer's pending bytes at the beginning of the array and fills the // remaining space with bytes from the file. static int BringToFrontAndLoadMore(StackLineReader* reader) { if (reader->view.size && reader->view.ptr != reader->buffer) { memmove(reader->buffer, reader->view.ptr, reader->view.size); } reader->view.ptr = reader->buffer; return LoadMore(reader); } // Loads chunks of buffer size from disks until it contains a newline character // or end of file. static void SkipToNextLine(StackLineReader* reader) { for (;;) { const int read = LoadFullBuffer(reader); if (read == 0) { break; } else { const int eol_index = IndexOfEol(reader); if (eol_index >= 0) { reader->view = CpuFeatures_StringView_PopFront(reader->view, eol_index + 1); break; } } } } static LineResult CreateLineResult(bool eof, bool full_line, StringView view) { LineResult result; result.eof = eof; result.full_line = full_line; result.line = view; return result; } // Helper methods to provide clearer semantic in StackLineReader_NextLine. static LineResult CreateEOFLineResult(StringView view) { return CreateLineResult(true, true, view); } static LineResult CreateTruncatedLineResult(StringView view) { return CreateLineResult(false, false, view); } static LineResult CreateValidLineResult(StringView view) { return CreateLineResult(false, true, view); } LineResult StackLineReader_NextLine(StackLineReader* reader) { if (reader->skip_mode) { SkipToNextLine(reader); reader->skip_mode = false; } { const bool can_load_more = reader->view.size < STACK_LINE_READER_BUFFER_SIZE; int eol_index = IndexOfEol(reader); if (eol_index < 0 && can_load_more) { const int read = BringToFrontAndLoadMore(reader); if (read == 0) { return CreateEOFLineResult(reader->view); } eol_index = IndexOfEol(reader); } if (eol_index < 0) { reader->skip_mode = true; return CreateTruncatedLineResult(reader->view); } { StringView line = CpuFeatures_StringView_KeepFront(reader->view, eol_index); reader->view = CpuFeatures_StringView_PopFront(reader->view, eol_index + 1); return CreateValidLineResult(line); } } } cpu-features-0.9.0/src/string_view.c000066400000000000000000000147131450057454500174350ustar00rootroot00000000000000// 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. // 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/string_view.h" #include #include #include "copy.inl" #include "equals.inl" static const char* CpuFeatures_memchr(const char* const ptr, const size_t size, const char c) { for (size_t i = 0; ptr && ptr[i] != '\0' && i < size; ++i) if (ptr[i] == c) return ptr + i; return NULL; } int CpuFeatures_StringView_IndexOfChar(const StringView view, char c) { if (view.ptr && view.size) { const char* const found = CpuFeatures_memchr(view.ptr, view.size, c); if (found) { return (int)(found - view.ptr); } } return -1; } int CpuFeatures_StringView_IndexOf(const StringView view, const StringView sub_view) { if (sub_view.size) { StringView remainder = view; while (remainder.size >= sub_view.size) { const int found_index = CpuFeatures_StringView_IndexOfChar(remainder, sub_view.ptr[0]); if (found_index < 0) break; remainder = CpuFeatures_StringView_PopFront(remainder, found_index); if (CpuFeatures_StringView_StartsWith(remainder, sub_view)) { return (int)(remainder.ptr - view.ptr); } remainder = CpuFeatures_StringView_PopFront(remainder, 1); } } return -1; } bool CpuFeatures_StringView_IsEquals(const StringView a, const StringView b) { if (a.size == b.size) { return a.ptr == b.ptr || equals(a.ptr, b.ptr, b.size); } return false; } bool CpuFeatures_StringView_StartsWith(const StringView a, const StringView b) { return a.ptr && b.ptr && b.size && a.size >= b.size ? equals(a.ptr, b.ptr, b.size) : false; } StringView CpuFeatures_StringView_PopFront(const StringView str_view, size_t count) { if (count > str_view.size) { return kEmptyStringView; } return view(str_view.ptr + count, str_view.size - count); } StringView CpuFeatures_StringView_PopBack(const StringView str_view, size_t count) { if (count > str_view.size) { return kEmptyStringView; } return view(str_view.ptr, str_view.size - count); } StringView CpuFeatures_StringView_KeepFront(const StringView str_view, size_t count) { return count <= str_view.size ? view(str_view.ptr, count) : str_view; } char CpuFeatures_StringView_Front(const StringView view) { assert(view.size); assert(view.ptr); return view.ptr[0]; } char CpuFeatures_StringView_Back(const StringView view) { assert(view.size); return view.ptr[view.size - 1]; } StringView CpuFeatures_StringView_TrimWhitespace(StringView view) { while (view.size && isspace(CpuFeatures_StringView_Front(view))) view = CpuFeatures_StringView_PopFront(view, 1); while (view.size && isspace(CpuFeatures_StringView_Back(view))) view = CpuFeatures_StringView_PopBack(view, 1); return view; } static int HexValue(const char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; } // Returns -1 if view contains non digits. static int ParsePositiveNumberWithBase(const StringView view, int base) { int result = 0; StringView remainder = view; for (; remainder.size; remainder = CpuFeatures_StringView_PopFront(remainder, 1)) { const int value = HexValue(CpuFeatures_StringView_Front(remainder)); if (value < 0 || value >= base) return -1; result = (result * base) + value; } return result; } int CpuFeatures_StringView_ParsePositiveNumber(const StringView view) { if (view.size) { const StringView hex_prefix = str("0x"); if (CpuFeatures_StringView_StartsWith(view, hex_prefix)) { const StringView span_no_prefix = CpuFeatures_StringView_PopFront(view, hex_prefix.size); return ParsePositiveNumberWithBase(span_no_prefix, 16); } return ParsePositiveNumberWithBase(view, 10); } return -1; } void CpuFeatures_StringView_CopyString(const StringView src, char* dst, size_t dst_size) { if (dst_size > 0) { const size_t max_copy_size = dst_size - 1; const size_t copy_size = src.size > max_copy_size ? max_copy_size : src.size; copy(dst, src.ptr, copy_size); dst[copy_size] = '\0'; } } bool CpuFeatures_StringView_HasWord(const StringView line, const char* const word_str, const char separator) { const StringView word = str(word_str); StringView remainder = line; for (;;) { const int index_of_word = CpuFeatures_StringView_IndexOf(remainder, word); if (index_of_word < 0) { return false; } else { const StringView before = CpuFeatures_StringView_KeepFront(line, index_of_word); const StringView after = CpuFeatures_StringView_PopFront(line, index_of_word + word.size); const bool valid_before = before.size == 0 || CpuFeatures_StringView_Back(before) == separator; const bool valid_after = after.size == 0 || CpuFeatures_StringView_Front(after) == separator; if (valid_before && valid_after) return true; remainder = CpuFeatures_StringView_PopFront(remainder, index_of_word + word.size); } } return false; } bool CpuFeatures_StringView_GetAttributeKeyValue(const StringView line, StringView* key, StringView* value) { const StringView sep = str(": "); const int index_of_separator = CpuFeatures_StringView_IndexOf(line, sep); if (index_of_separator < 0) return false; *value = CpuFeatures_StringView_TrimWhitespace( CpuFeatures_StringView_PopFront(line, index_of_separator + sep.size)); *key = CpuFeatures_StringView_TrimWhitespace( CpuFeatures_StringView_KeepFront(line, index_of_separator)); return true; } cpu-features-0.9.0/src/utils/000077500000000000000000000000001450057454500160635ustar00rootroot00000000000000cpu-features-0.9.0/src/utils/list_cpu_features.c000066400000000000000000000360621450057454500217560ustar00rootroot00000000000000// 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. // 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. // This program dumps current host data to the standard output. // Output can be text or json if the `--json` flag is passed. #include #include #include #include #include #include #include #include "cpu_features_macros.h" #if defined(CPU_FEATURES_ARCH_X86) #include "cpuinfo_x86.h" #elif defined(CPU_FEATURES_ARCH_ARM) #include "cpuinfo_arm.h" #elif defined(CPU_FEATURES_ARCH_AARCH64) #include "cpuinfo_aarch64.h" #elif defined(CPU_FEATURES_ARCH_MIPS) #include "cpuinfo_mips.h" #elif defined(CPU_FEATURES_ARCH_PPC) #include "cpuinfo_ppc.h" #elif defined(CPU_FEATURES_ARCH_S390X) #include "cpuinfo_s390x.h" #elif defined(CPU_FEATURES_ARCH_RISCV) #include "cpuinfo_riscv.h" #elif defined(CPU_FEATURES_ARCH_LOONGARCH) #include "cpuinfo_loongarch.h" #endif // Design principles // ----------------- // We build a tree structure containing all the data to be displayed. // Then depending on the output type (text or json) we walk the tree and display // the data accordingly. // We use a bump allocator to allocate strings and nodes of the tree, // Memory is not intended to be reclaimed. typedef struct { char* ptr; size_t size; } BumpAllocator; char gGlobalBuffer[64 * 1024]; BumpAllocator gBumpAllocator = {.ptr = gGlobalBuffer, .size = sizeof(gGlobalBuffer)}; static void internal_error(void) { fputs("internal error\n", stderr); exit(EXIT_FAILURE); } #define ALIGN 8 static void assertAligned(void) { if ((uintptr_t)(gBumpAllocator.ptr) % ALIGN) internal_error(); } static void BA_Align(void) { while (gBumpAllocator.size && (uintptr_t)(gBumpAllocator.ptr) % ALIGN) { --gBumpAllocator.size; ++gBumpAllocator.ptr; } assertAligned(); } // Update the available memory left in the BumpAllocator. static void* BA_Bump(size_t size) { assertAligned(); // Align size to next 8B boundary. size = (size + ALIGN - 1) / ALIGN * ALIGN; if (gBumpAllocator.size < size) internal_error(); void* ptr = gBumpAllocator.ptr; gBumpAllocator.size -= size; gBumpAllocator.ptr += size; return ptr; } // The type of the nodes in the tree. typedef enum { NT_INVALID, NT_INT, NT_MAP, NT_MAP_ENTRY, NT_ARRAY, NT_ARRAY_ELEMENT, NT_STRING, } NodeType; // The node in the tree. typedef struct Node { NodeType type; unsigned integer; const char* string; struct Node* value; struct Node* next; } Node; // Creates an initialized Node. static Node* BA_CreateNode(NodeType type) { Node* tv = (Node*)BA_Bump(sizeof(Node)); assert(tv); *tv = (Node){.type = type}; return tv; } // Adds an integer node. static Node* CreateInt(int value) { Node* tv = BA_CreateNode(NT_INT); tv->integer = value; return tv; } // Adds a string node. // `value` must outlive the tree. static Node* CreateConstantString(const char* value) { Node* tv = BA_CreateNode(NT_STRING); tv->string = value; return tv; } // Adds a map node. static Node* CreateMap(void) { return BA_CreateNode(NT_MAP); } // Adds an array node. static Node* CreateArray(void) { return BA_CreateNode(NT_ARRAY); } // Adds a formatted string node. static Node* CreatePrintfString(const char* format, ...) { va_list arglist; va_start(arglist, format); char* const ptr = gBumpAllocator.ptr; const int written = vsnprintf(ptr, gBumpAllocator.size, format, arglist); va_end(arglist); if (written < 0 || written >= (int)gBumpAllocator.size) internal_error(); return CreateConstantString((char*)BA_Bump(written)); } // Adds a string node. static Node* CreateString(const char* value) { return CreatePrintfString("%s", value); } // Adds a map entry node. static void AddMapEntry(Node* map, const char* key, Node* value) { assert(map && map->type == NT_MAP); Node* current = map; while (current->next) current = current->next; current->next = (Node*)BA_Bump(sizeof(Node)); *current->next = (Node){.type = NT_MAP_ENTRY, .string = key, .value = value}; } // Adds an array element node. static void AddArrayElement(Node* array, Node* value) { assert(array && array->type == NT_ARRAY); Node* current = array; while (current->next) current = current->next; current->next = (Node*)BA_Bump(sizeof(Node)); *current->next = (Node){.type = NT_ARRAY_ELEMENT, .value = value}; } static int cmp(const void* p1, const void* p2) { return strcmp(*(const char* const*)p1, *(const char* const*)p2); } #define DEFINE_ADD_FLAGS(HasFeature, FeatureName, FeatureType, LastEnum) \ static void AddFlags(Node* map, const FeatureType* features) { \ size_t i; \ const char* ptrs[LastEnum] = {0}; \ size_t count = 0; \ for (i = 0; i < LastEnum; ++i) { \ if (HasFeature(features, i)) { \ ptrs[count] = FeatureName(i); \ ++count; \ } \ } \ qsort((void*)ptrs, count, sizeof(char*), cmp); \ Node* const array = CreateArray(); \ for (i = 0; i < count; ++i) \ AddArrayElement(array, CreateConstantString(ptrs[i])); \ AddMapEntry(map, "flags", array); \ } #if defined(CPU_FEATURES_ARCH_X86) DEFINE_ADD_FLAGS(GetX86FeaturesEnumValue, GetX86FeaturesEnumName, X86Features, X86_LAST_) #elif defined(CPU_FEATURES_ARCH_ARM) DEFINE_ADD_FLAGS(GetArmFeaturesEnumValue, GetArmFeaturesEnumName, ArmFeatures, ARM_LAST_) #elif defined(CPU_FEATURES_ARCH_AARCH64) DEFINE_ADD_FLAGS(GetAarch64FeaturesEnumValue, GetAarch64FeaturesEnumName, Aarch64Features, AARCH64_LAST_) #elif defined(CPU_FEATURES_ARCH_MIPS) DEFINE_ADD_FLAGS(GetMipsFeaturesEnumValue, GetMipsFeaturesEnumName, MipsFeatures, MIPS_LAST_) #elif defined(CPU_FEATURES_ARCH_PPC) DEFINE_ADD_FLAGS(GetPPCFeaturesEnumValue, GetPPCFeaturesEnumName, PPCFeatures, PPC_LAST_) #elif defined(CPU_FEATURES_ARCH_S390X) DEFINE_ADD_FLAGS(GetS390XFeaturesEnumValue, GetS390XFeaturesEnumName, S390XFeatures, S390X_LAST_) #elif defined(CPU_FEATURES_ARCH_RISCV) DEFINE_ADD_FLAGS(GetRiscvFeaturesEnumValue, GetRiscvFeaturesEnumName, RiscvFeatures, RISCV_LAST_) #elif defined(CPU_FEATURES_ARCH_LOONGARCH) DEFINE_ADD_FLAGS(GetLoongArchFeaturesEnumValue, GetLoongArchFeaturesEnumName, LoongArchFeatures, LOONGARCH_LAST_) #endif // Prints a json string with characters escaping. static void printJsonString(const char* str) { putchar('"'); for (; str && *str; ++str) { switch (*str) { case '\"': case '\\': case '/': case '\b': case '\f': case '\n': case '\r': case '\t': putchar('\\'); } putchar(*str); } putchar('"'); } // Walks a Node and print it as json. static void printJson(const Node* current) { assert(current); switch (current->type) { case NT_INVALID: break; case NT_INT: printf("%d", current->integer); break; case NT_STRING: printJsonString(current->string); break; case NT_ARRAY: putchar('['); if (current->next) printJson(current->next); putchar(']'); break; case NT_MAP: putchar('{'); if (current->next) printJson(current->next); putchar('}'); break; case NT_MAP_ENTRY: printf("\"%s\":", current->string); printJson(current->value); if (current->next) { putchar(','); printJson(current->next); } break; case NT_ARRAY_ELEMENT: printJson(current->value); if (current->next) { putchar(','); printJson(current->next); } break; } } // Walks a Node and print it as text. static void printTextField(const Node* current) { switch (current->type) { case NT_INVALID: break; case NT_INT: printf("%3d (0x%02X)", current->integer, current->integer); break; case NT_STRING: fputs(current->string, stdout); break; case NT_ARRAY: if (current->next) printTextField(current->next); break; case NT_MAP: if (current->next) { printf("{"); printJson(current->next); printf("}"); } break; case NT_MAP_ENTRY: printf("%-15s : ", current->string); printTextField(current->value); if (current->next) { putchar('\n'); printTextField(current->next); } break; case NT_ARRAY_ELEMENT: printTextField(current->value); if (current->next) { putchar(','); printTextField(current->next); } break; } } static void printTextRoot(const Node* current) { if (current->type == NT_MAP && current->next) printTextField(current->next); } static void showUsage(const char* name) { printf( "\n" "Usage: %s [options]\n" " Options:\n" " -h | --help Show help message.\n" " -j | --json Format output as json instead of plain text.\n" "\n", name); } static Node* GetCacheTypeString(CacheType cache_type) { switch (cache_type) { case CPU_FEATURE_CACHE_NULL: return CreateConstantString("null"); case CPU_FEATURE_CACHE_DATA: return CreateConstantString("data"); case CPU_FEATURE_CACHE_INSTRUCTION: return CreateConstantString("instruction"); case CPU_FEATURE_CACHE_UNIFIED: return CreateConstantString("unified"); case CPU_FEATURE_CACHE_TLB: return CreateConstantString("tlb"); case CPU_FEATURE_CACHE_DTLB: return CreateConstantString("dtlb"); case CPU_FEATURE_CACHE_STLB: return CreateConstantString("stlb"); case CPU_FEATURE_CACHE_PREFETCH: return CreateConstantString("prefetch"); } CPU_FEATURES_UNREACHABLE(); } static void AddCacheInfo(Node* root, const CacheInfo* cache_info) { Node* array = CreateArray(); for (int i = 0; i < cache_info->size; ++i) { CacheLevelInfo info = cache_info->levels[i]; Node* map = CreateMap(); AddMapEntry(map, "level", CreateInt(info.level)); AddMapEntry(map, "cache_type", GetCacheTypeString(info.cache_type)); AddMapEntry(map, "cache_size", CreateInt(info.cache_size)); AddMapEntry(map, "ways", CreateInt(info.ways)); AddMapEntry(map, "line_size", CreateInt(info.line_size)); AddMapEntry(map, "tlb_entries", CreateInt(info.tlb_entries)); AddMapEntry(map, "partitioning", CreateInt(info.partitioning)); AddArrayElement(array, map); } AddMapEntry(root, "cache_info", array); } static Node* CreateTree(void) { Node* root = CreateMap(); #if defined(CPU_FEATURES_ARCH_X86) const X86Info info = GetX86Info(); const CacheInfo cache_info = GetX86CacheInfo(); AddMapEntry(root, "arch", CreateString("x86")); AddMapEntry(root, "brand", CreateString(info.brand_string)); AddMapEntry(root, "family", CreateInt(info.family)); AddMapEntry(root, "model", CreateInt(info.model)); AddMapEntry(root, "stepping", CreateInt(info.stepping)); AddMapEntry(root, "uarch", CreateString( GetX86MicroarchitectureName(GetX86Microarchitecture(&info)))); AddFlags(root, &info.features); AddCacheInfo(root, &cache_info); #elif defined(CPU_FEATURES_ARCH_ARM) const ArmInfo info = GetArmInfo(); AddMapEntry(root, "arch", CreateString("ARM")); AddMapEntry(root, "implementer", CreateInt(info.implementer)); AddMapEntry(root, "architecture", CreateInt(info.architecture)); AddMapEntry(root, "variant", CreateInt(info.variant)); AddMapEntry(root, "part", CreateInt(info.part)); AddMapEntry(root, "revision", CreateInt(info.revision)); AddFlags(root, &info.features); #elif defined(CPU_FEATURES_ARCH_AARCH64) const Aarch64Info info = GetAarch64Info(); AddMapEntry(root, "arch", CreateString("aarch64")); AddMapEntry(root, "implementer", CreateInt(info.implementer)); AddMapEntry(root, "variant", CreateInt(info.variant)); AddMapEntry(root, "part", CreateInt(info.part)); AddMapEntry(root, "revision", CreateInt(info.revision)); AddFlags(root, &info.features); #elif defined(CPU_FEATURES_ARCH_MIPS) const MipsInfo info = GetMipsInfo(); AddMapEntry(root, "arch", CreateString("mips")); AddFlags(root, &info.features); #elif defined(CPU_FEATURES_ARCH_PPC) const PPCInfo info = GetPPCInfo(); const PPCPlatformStrings strings = GetPPCPlatformStrings(); AddMapEntry(root, "arch", CreateString("ppc")); AddMapEntry(root, "platform", CreateString(strings.platform)); AddMapEntry(root, "model", CreateString(strings.model)); AddMapEntry(root, "machine", CreateString(strings.machine)); AddMapEntry(root, "cpu", CreateString(strings.cpu)); AddMapEntry(root, "instruction", CreateString(strings.type.platform)); AddMapEntry(root, "microarchitecture", CreateString(strings.type.base_platform)); AddFlags(root, &info.features); #elif defined(CPU_FEATURES_ARCH_S390X) const S390XInfo info = GetS390XInfo(); const S390XPlatformStrings strings = GetS390XPlatformStrings(); AddMapEntry(root, "arch", CreateString("s390x")); AddMapEntry(root, "platform", CreateString("zSeries")); AddMapEntry(root, "model", CreateString(strings.type.platform)); AddMapEntry(root, "# processors", CreateInt(strings.num_processors)); AddFlags(root, &info.features); #elif defined(CPU_FEATURES_ARCH_RISCV) const RiscvInfo info = GetRiscvInfo(); AddMapEntry(root, "arch", CreateString("risc-v")); AddMapEntry(root, "vendor", CreateString(info.vendor)); AddMapEntry(root, "microarchitecture", CreateString(info.uarch)); AddFlags(root, &info.features); #elif defined(CPU_FEATURES_ARCH_LOONGARCH) const LoongArchInfo info = GetLoongArchInfo(); AddMapEntry(root, "arch", CreateString("loongarch")); AddFlags(root, &info.features); #endif return root; } int main(int argc, char** argv) { BA_Align(); const Node* const root = CreateTree(); bool outputJson = false; int i = 1; for (; i < argc; ++i) { const char* arg = argv[i]; if (strcmp(arg, "-j") == 0 || strcmp(arg, "--json") == 0) { outputJson = true; } else { showUsage(argv[0]); if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) return EXIT_SUCCESS; return EXIT_FAILURE; } } if (outputJson) printJson(root); else printTextRoot(root); putchar('\n'); return EXIT_SUCCESS; } cpu-features-0.9.0/test/000077500000000000000000000000001450057454500151135ustar00rootroot00000000000000cpu-features-0.9.0/test/CMakeLists.txt000066400000000000000000000131371450057454500176600ustar00rootroot00000000000000# # libraries for tests # include_directories(../include) add_definitions(-DCPU_FEATURES_TEST) ##------------------------------------------------------------------------------ add_library(string_view ../src/string_view.c) ##------------------------------------------------------------------------------ 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_link_libraries(hwcaps_for_testing filesystem_for_testing) ##------------------------------------------------------------------------------ add_library(stack_line_reader ../src/stack_line_reader.c) target_compile_definitions(stack_line_reader PUBLIC STACK_LINE_READER_BUFFER_SIZE=1024) target_link_libraries(stack_line_reader string_view) ##------------------------------------------------------------------------------ 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/hwcaps.c ../src/stack_line_reader.c) target_link_libraries(all_libraries hwcaps_for_testing stack_line_reader string_view) # # tests # link_libraries(gtest gmock_main) ## bit_utils_test add_executable(bit_utils_test bit_utils_test.cc) target_link_libraries(bit_utils_test) add_test(NAME bit_utils_test COMMAND bit_utils_test) ##------------------------------------------------------------------------------ ## string_view_test add_executable(string_view_test string_view_test.cc ../src/string_view.c) target_link_libraries(string_view_test string_view) add_test(NAME string_view_test COMMAND string_view_test) ##------------------------------------------------------------------------------ ## stack_line_reader_test 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) ##------------------------------------------------------------------------------ ## cpuinfo_x86_test if(PROCESSOR_IS_X86) add_executable(cpuinfo_x86_test cpuinfo_x86_test.cc ../src/impl_x86_freebsd.c ../src/impl_x86_linux_or_android.c ../src/impl_x86_macos.c ../src/impl_x86_windows.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() ##------------------------------------------------------------------------------ ## cpuinfo_arm_test if(PROCESSOR_IS_ARM) add_executable(cpuinfo_arm_test cpuinfo_arm_test.cc ../src/impl_arm_linux_or_android.c) target_link_libraries(cpuinfo_arm_test all_libraries) add_test(NAME cpuinfo_arm_test COMMAND cpuinfo_arm_test) endif() ##------------------------------------------------------------------------------ ## cpuinfo_aarch64_test if(PROCESSOR_IS_AARCH64) add_executable(cpuinfo_aarch64_test cpuinfo_aarch64_test.cc ../src/impl_aarch64_linux_or_android.c ../src/impl_aarch64_windows.c ../src/impl_aarch64_macos_or_iphone.c ) if(APPLE) target_compile_definitions(cpuinfo_aarch64_test PUBLIC CPU_FEATURES_MOCK_SYSCTL_AARCH64) target_compile_definitions(cpuinfo_aarch64_test PRIVATE HAVE_SYSCTLBYNAME) else() target_compile_definitions(cpuinfo_aarch64_test PUBLIC CPU_FEATURES_MOCK_CPUID_AARCH64) endif() target_link_libraries(cpuinfo_aarch64_test all_libraries) add_test(NAME cpuinfo_aarch64_test COMMAND cpuinfo_aarch64_test) endif() ##------------------------------------------------------------------------------ ## cpuinfo_mips_test if(PROCESSOR_IS_MIPS) add_executable(cpuinfo_mips_test cpuinfo_mips_test.cc ../src/impl_mips_linux_or_android.c) target_link_libraries(cpuinfo_mips_test all_libraries) add_test(NAME cpuinfo_mips_test COMMAND cpuinfo_mips_test) endif() ##------------------------------------------------------------------------------ ## cpuinfo_ppc_test if(PROCESSOR_IS_POWER) add_executable(cpuinfo_ppc_test cpuinfo_ppc_test.cc ../src/impl_ppc_linux.c) target_link_libraries(cpuinfo_ppc_test all_libraries) add_test(NAME cpuinfo_ppc_test COMMAND cpuinfo_ppc_test) endif() ##------------------------------------------------------------------------------ ## cpuinfo_s390x_test if(PROCESSOR_IS_S390X) add_executable(cpuinfo_s390x_test cpuinfo_s390x_test.cc ../src/impl_s390x_linux.c) target_link_libraries(cpuinfo_s390x_test all_libraries) add_test(NAME cpuinfo_s390x_test COMMAND cpuinfo_s390x_test) endif() ##------------------------------------------------------------------------------ ## cpuinfo_riscv_test if(PROCESSOR_IS_RISCV) add_executable(cpuinfo_riscv_test cpuinfo_riscv_test.cc ../src/impl_riscv_linux.c) target_link_libraries(cpuinfo_riscv_test all_libraries) add_test(NAME cpuinfo_riscv_test COMMAND cpuinfo_riscv_test) endif() ##------------------------------------------------------------------------------ ## cpuinfo_loongarch_test if(PROCESSOR_IS_LOONGARCH) add_executable(cpuinfo_loongarch_test cpuinfo_loongarch_test.cc ../src/impl_loongarch_linux.c) target_link_libraries(cpuinfo_loongarch_test all_libraries) add_test(NAME cpuinfo_loongarch_test COMMAND cpuinfo_loongarch_test) endif() cpu-features-0.9.0/test/bit_utils_test.cc000066400000000000000000000030141450057454500204550ustar00rootroot00000000000000// 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. // 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/bit_utils.h" #include "gtest/gtest.h" namespace cpu_features { namespace { TEST(UtilsTest, IsBitSet) { for (size_t bit_set = 0; bit_set < 32; ++bit_set) { const uint32_t value = 1UL << bit_set; for (uint32_t i = 0; i < 32; ++i) { EXPECT_EQ(IsBitSet(value, i), i == bit_set); } } // testing 0, all bits should be 0. for (uint32_t i = 0; i < 32; ++i) { EXPECT_FALSE(IsBitSet(0, i)); } // testing ~0, all bits should be 1. for (uint32_t i = 0; i < 32; ++i) { EXPECT_TRUE(IsBitSet(-1, i)); } } TEST(UtilsTest, ExtractBitRange) { // Extracting all bits gives the same number. EXPECT_EQ(ExtractBitRange(123, 31, 0), 123); // Extracting 1 bit gives parity. EXPECT_EQ(ExtractBitRange(123, 0, 0), 1); EXPECT_EQ(ExtractBitRange(122, 0, 0), 0); EXPECT_EQ(ExtractBitRange(0xF0, 7, 4), 0xF); EXPECT_EQ(ExtractBitRange(0x42 << 2, 10, 2), 0x42); } } // namespace } // namespace cpu_features cpu-features-0.9.0/test/cpuinfo_aarch64_test.cc000066400000000000000000000317571450057454500214510ustar00rootroot00000000000000// 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. // 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 "cpuinfo_aarch64.h" #include #include "filesystem_for_testing.h" #include "gtest/gtest.h" #include "hwcaps_for_testing.h" #if defined(CPU_FEATURES_OS_WINDOWS) #include "internal/windows_utils.h" #endif // CPU_FEATURES_OS_WINDOWS namespace cpu_features { class FakeCpuAarch64 { #if defined(CPU_FEATURES_OS_LINUX) // No particular implementation for Linux as we use /proc/cpuinfo #elif defined(CPU_FEATURES_OS_MACOS) std::set darwin_sysctlbyname_; std::map darwin_sysctlbynamevalue_; public: bool GetDarwinSysCtlByName(std::string name) const { return darwin_sysctlbyname_.count(name); } int GetDarwinSysCtlByNameValue(std::string name) const { const auto iter = darwin_sysctlbynamevalue_.find(name); if (iter != darwin_sysctlbynamevalue_.end()) return iter->second; return 0; } void SetDarwinSysCtlByName(std::string name) { darwin_sysctlbyname_.insert(name); } void SetDarwinSysCtlByNameValue(std::string name, int value) { darwin_sysctlbynamevalue_[name] = value; } #elif defined(CPU_FEATURES_OS_WINDOWS) std::set windows_isprocessorfeaturepresent_; WORD processor_revision_{}; public: bool GetWindowsIsProcessorFeaturePresent(DWORD dwProcessorFeature) { return windows_isprocessorfeaturepresent_.count(dwProcessorFeature); } void SetWindowsIsProcessorFeaturePresent(DWORD dwProcessorFeature) { windows_isprocessorfeaturepresent_.insert(dwProcessorFeature); } WORD GetWindowsNativeSystemInfoProcessorRevision() const { return processor_revision_; } void SetWindowsNativeSystemInfoProcessorRevision(WORD wProcessorRevision) { processor_revision_ = wProcessorRevision; } #endif }; static FakeCpuAarch64* g_fake_cpu_instance = nullptr; static FakeCpuAarch64& cpu() { assert(g_fake_cpu_instance != nullptr); return *g_fake_cpu_instance; } // Define OS dependent mock functions #if defined(CPU_FEATURES_OS_LINUX) // No particular functions to implement for Linux as we use /proc/cpuinfo #elif defined(CPU_FEATURES_OS_MACOS) extern "C" bool GetDarwinSysCtlByName(const char* name) { return cpu().GetDarwinSysCtlByName(name); } extern "C" int GetDarwinSysCtlByNameValue(const char* name) { return cpu().GetDarwinSysCtlByNameValue(name); } #elif defined(CPU_FEATURES_OS_WINDOWS) extern "C" bool GetWindowsIsProcessorFeaturePresent(DWORD dwProcessorFeature) { return cpu().GetWindowsIsProcessorFeaturePresent(dwProcessorFeature); } extern "C" WORD GetWindowsNativeSystemInfoProcessorRevision() { return cpu().GetWindowsNativeSystemInfoProcessorRevision(); } #endif namespace { class CpuidAarch64Test : public ::testing::Test { protected: void SetUp() override { assert(g_fake_cpu_instance == nullptr); g_fake_cpu_instance = new FakeCpuAarch64(); } void TearDown() override { delete g_fake_cpu_instance; g_fake_cpu_instance = nullptr; } }; TEST_F(CpuidAarch64Test, Aarch64FeaturesEnum) { const char* last_name = GetAarch64FeaturesEnumName(AARCH64_LAST_); EXPECT_STREQ(last_name, "unknown_feature"); for (int i = static_cast(AARCH64_FP); i != static_cast(AARCH64_LAST_); ++i) { const auto feature = static_cast(i); const char* name = GetAarch64FeaturesEnumName(feature); ASSERT_FALSE(name == nullptr); EXPECT_STRNE(name, ""); EXPECT_STRNE(name, last_name); } } // OS dependent tests #if defined(CPU_FEATURES_OS_LINUX) TEST_F(CpuidAarch64Test, FromHardwareCap) { ResetHwcaps(); SetHardwareCapabilities(AARCH64_HWCAP_FP | AARCH64_HWCAP_AES, 0); GetEmptyFilesystem(); // disabling /proc/cpuinfo const auto info = GetAarch64Info(); EXPECT_TRUE(info.features.fp); EXPECT_FALSE(info.features.asimd); EXPECT_FALSE(info.features.evtstrm); EXPECT_TRUE(info.features.aes); EXPECT_FALSE(info.features.pmull); EXPECT_FALSE(info.features.sha1); EXPECT_FALSE(info.features.sha2); EXPECT_FALSE(info.features.crc32); EXPECT_FALSE(info.features.atomics); EXPECT_FALSE(info.features.fphp); EXPECT_FALSE(info.features.asimdhp); EXPECT_FALSE(info.features.cpuid); EXPECT_FALSE(info.features.asimdrdm); EXPECT_FALSE(info.features.jscvt); EXPECT_FALSE(info.features.fcma); EXPECT_FALSE(info.features.lrcpc); EXPECT_FALSE(info.features.dcpop); EXPECT_FALSE(info.features.sha3); EXPECT_FALSE(info.features.sm3); EXPECT_FALSE(info.features.sm4); EXPECT_FALSE(info.features.asimddp); EXPECT_FALSE(info.features.sha512); EXPECT_FALSE(info.features.sve); EXPECT_FALSE(info.features.asimdfhm); EXPECT_FALSE(info.features.dit); EXPECT_FALSE(info.features.uscat); EXPECT_FALSE(info.features.ilrcpc); EXPECT_FALSE(info.features.flagm); EXPECT_FALSE(info.features.ssbs); EXPECT_FALSE(info.features.sb); EXPECT_FALSE(info.features.paca); EXPECT_FALSE(info.features.pacg); } TEST_F(CpuidAarch64Test, FromHardwareCap2) { ResetHwcaps(); SetHardwareCapabilities(AARCH64_HWCAP_FP, AARCH64_HWCAP2_SVE2 | AARCH64_HWCAP2_BTI); GetEmptyFilesystem(); // disabling /proc/cpuinfo const auto info = GetAarch64Info(); EXPECT_TRUE(info.features.fp); EXPECT_TRUE(info.features.sve2); EXPECT_TRUE(info.features.bti); EXPECT_FALSE(info.features.dcpodp); EXPECT_FALSE(info.features.sveaes); EXPECT_FALSE(info.features.svepmull); EXPECT_FALSE(info.features.svebitperm); EXPECT_FALSE(info.features.svesha3); EXPECT_FALSE(info.features.svesm4); EXPECT_FALSE(info.features.flagm2); EXPECT_FALSE(info.features.frint); EXPECT_FALSE(info.features.svei8mm); EXPECT_FALSE(info.features.svef32mm); EXPECT_FALSE(info.features.svef64mm); EXPECT_FALSE(info.features.svebf16); EXPECT_FALSE(info.features.i8mm); EXPECT_FALSE(info.features.bf16); EXPECT_FALSE(info.features.dgh); EXPECT_FALSE(info.features.rng); } TEST_F(CpuidAarch64Test, ARMCortexA53) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"(Processor : AArch64 Processor rev 3 (aarch64) processor : 0 processor : 1 processor : 2 processor : 3 processor : 4 processor : 5 processor : 6 processor : 7 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 CPU implementer : 0x41 CPU architecture: AArch64 CPU variant : 0x0 CPU part : 0xd03 CPU revision : 3)"); const auto info = GetAarch64Info(); EXPECT_EQ(info.implementer, 0x41); EXPECT_EQ(info.variant, 0x0); EXPECT_EQ(info.part, 0xd03); EXPECT_EQ(info.revision, 3); EXPECT_TRUE(info.features.fp); EXPECT_TRUE(info.features.asimd); EXPECT_TRUE(info.features.evtstrm); EXPECT_TRUE(info.features.aes); EXPECT_TRUE(info.features.pmull); EXPECT_TRUE(info.features.sha1); EXPECT_TRUE(info.features.sha2); EXPECT_TRUE(info.features.crc32); EXPECT_FALSE(info.features.atomics); EXPECT_FALSE(info.features.fphp); EXPECT_FALSE(info.features.asimdhp); EXPECT_FALSE(info.features.cpuid); EXPECT_FALSE(info.features.asimdrdm); EXPECT_FALSE(info.features.jscvt); EXPECT_FALSE(info.features.fcma); EXPECT_FALSE(info.features.lrcpc); EXPECT_FALSE(info.features.dcpop); EXPECT_FALSE(info.features.sha3); EXPECT_FALSE(info.features.sm3); EXPECT_FALSE(info.features.sm4); EXPECT_FALSE(info.features.asimddp); EXPECT_FALSE(info.features.sha512); EXPECT_FALSE(info.features.sve); EXPECT_FALSE(info.features.asimdfhm); EXPECT_FALSE(info.features.dit); EXPECT_FALSE(info.features.uscat); EXPECT_FALSE(info.features.ilrcpc); EXPECT_FALSE(info.features.flagm); EXPECT_FALSE(info.features.ssbs); EXPECT_FALSE(info.features.sb); EXPECT_FALSE(info.features.paca); EXPECT_FALSE(info.features.pacg); EXPECT_FALSE(info.features.dcpodp); EXPECT_FALSE(info.features.sve2); EXPECT_FALSE(info.features.sveaes); EXPECT_FALSE(info.features.svepmull); EXPECT_FALSE(info.features.svebitperm); EXPECT_FALSE(info.features.svesha3); EXPECT_FALSE(info.features.svesm4); EXPECT_FALSE(info.features.flagm2); EXPECT_FALSE(info.features.frint); EXPECT_FALSE(info.features.svei8mm); EXPECT_FALSE(info.features.svef32mm); EXPECT_FALSE(info.features.svef64mm); EXPECT_FALSE(info.features.svebf16); EXPECT_FALSE(info.features.i8mm); EXPECT_FALSE(info.features.bf16); EXPECT_FALSE(info.features.dgh); EXPECT_FALSE(info.features.rng); EXPECT_FALSE(info.features.bti); EXPECT_FALSE(info.features.mte); EXPECT_FALSE(info.features.ecv); EXPECT_FALSE(info.features.afp); EXPECT_FALSE(info.features.rpres); EXPECT_FALSE(info.features.mte3); EXPECT_FALSE(info.features.sme); EXPECT_FALSE(info.features.smei16i64); EXPECT_FALSE(info.features.smef64f64); EXPECT_FALSE(info.features.smei8i32); EXPECT_FALSE(info.features.smef16f32); EXPECT_FALSE(info.features.smeb16f32); EXPECT_FALSE(info.features.smef32f32); EXPECT_FALSE(info.features.smefa64); EXPECT_FALSE(info.features.wfxt); EXPECT_FALSE(info.features.ebf16); EXPECT_FALSE(info.features.sveebf16); EXPECT_FALSE(info.features.cssc); EXPECT_FALSE(info.features.rprfm); EXPECT_FALSE(info.features.sve2p1); EXPECT_FALSE(info.features.sme2); EXPECT_FALSE(info.features.sme2p1); EXPECT_FALSE(info.features.smei16i32); EXPECT_FALSE(info.features.smebi32i32); EXPECT_FALSE(info.features.smeb16b16); EXPECT_FALSE(info.features.smef16f16); } #elif defined(CPU_FEATURES_OS_MACOS) TEST_F(CpuidAarch64Test, FromDarwinSysctlFromName) { cpu().SetDarwinSysCtlByName("hw.optional.floatingpoint"); cpu().SetDarwinSysCtlByName("hw.optional.neon"); cpu().SetDarwinSysCtlByName("hw.optional.AdvSIMD_HPFPCvt"); cpu().SetDarwinSysCtlByName("hw.optional.arm.FEAT_FP16"); cpu().SetDarwinSysCtlByName("hw.optional.arm.FEAT_LSE"); cpu().SetDarwinSysCtlByName("hw.optional.armv8_crc32"); cpu().SetDarwinSysCtlByName("hw.optional.arm.FEAT_FHM"); cpu().SetDarwinSysCtlByName("hw.optional.arm.FEAT_SHA512"); cpu().SetDarwinSysCtlByName("hw.optional.arm.FEAT_SHA3"); cpu().SetDarwinSysCtlByName("hw.optional.amx_version"); cpu().SetDarwinSysCtlByName("hw.optional.ucnormal_mem"); cpu().SetDarwinSysCtlByName("hw.optional.arm64"); cpu().SetDarwinSysCtlByNameValue("hw.cputype", 16777228); cpu().SetDarwinSysCtlByNameValue("hw.cpusubtype", 2); cpu().SetDarwinSysCtlByNameValue("hw.cpu64bit", 1); cpu().SetDarwinSysCtlByNameValue("hw.cpufamily", 458787763); cpu().SetDarwinSysCtlByNameValue("hw.cpusubfamily", 2); const auto info = GetAarch64Info(); EXPECT_EQ(info.implementer, 0x100000C); EXPECT_EQ(info.variant, 2); EXPECT_EQ(info.part, 0x1B588BB3); EXPECT_EQ(info.revision, 2); EXPECT_TRUE(info.features.fp); EXPECT_FALSE(info.features.asimd); EXPECT_FALSE(info.features.evtstrm); EXPECT_FALSE(info.features.aes); EXPECT_FALSE(info.features.pmull); EXPECT_FALSE(info.features.sha1); EXPECT_FALSE(info.features.sha2); EXPECT_TRUE(info.features.crc32); EXPECT_TRUE(info.features.atomics); EXPECT_TRUE(info.features.fphp); EXPECT_FALSE(info.features.asimdhp); EXPECT_FALSE(info.features.cpuid); EXPECT_FALSE(info.features.asimdrdm); EXPECT_FALSE(info.features.jscvt); EXPECT_FALSE(info.features.fcma); EXPECT_FALSE(info.features.lrcpc); EXPECT_FALSE(info.features.dcpop); EXPECT_TRUE(info.features.sha3); EXPECT_FALSE(info.features.sm3); EXPECT_FALSE(info.features.sm4); EXPECT_FALSE(info.features.asimddp); EXPECT_TRUE(info.features.sha512); EXPECT_FALSE(info.features.sve); EXPECT_TRUE(info.features.asimdfhm); EXPECT_FALSE(info.features.dit); EXPECT_FALSE(info.features.uscat); EXPECT_FALSE(info.features.ilrcpc); EXPECT_FALSE(info.features.flagm); EXPECT_FALSE(info.features.ssbs); EXPECT_FALSE(info.features.sb); EXPECT_FALSE(info.features.paca); EXPECT_FALSE(info.features.pacg); } #elif defined(CPU_FEATURES_OS_WINDOWS) TEST_F(CpuidAarch64Test, WINDOWS_AARCH64_RPI4) { cpu().SetWindowsNativeSystemInfoProcessorRevision(0x03); cpu().SetWindowsIsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE); cpu().SetWindowsIsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE); cpu().SetWindowsIsProcessorFeaturePresent( PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE); const auto info = GetAarch64Info(); EXPECT_EQ(info.revision, 0x03); EXPECT_TRUE(info.features.fp); EXPECT_TRUE(info.features.asimd); EXPECT_TRUE(info.features.crc32); EXPECT_FALSE(info.features.aes); EXPECT_FALSE(info.features.sha1); EXPECT_FALSE(info.features.sha2); EXPECT_FALSE(info.features.pmull); EXPECT_FALSE(info.features.atomics); EXPECT_FALSE(info.features.asimddp); EXPECT_FALSE(info.features.jscvt); EXPECT_FALSE(info.features.lrcpc); } #endif // CPU_FEATURES_OS_WINDOWS } // namespace } // namespace cpu_features cpu-features-0.9.0/test/cpuinfo_arm_test.cc000066400000000000000000000274741450057454500210010ustar00rootroot00000000000000// 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. // 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 "cpuinfo_arm.h" #include "filesystem_for_testing.h" #include "gtest/gtest.h" #include "hwcaps_for_testing.h" namespace cpu_features { namespace { TEST(CpuinfoArmTest, ArmFeaturesEnum) { const char *last_name = GetArmFeaturesEnumName(ARM_LAST_); EXPECT_STREQ(last_name, "unknown_feature"); for (int i = static_cast(ARM_SWP); i != static_cast(ARM_LAST_); ++i) { const auto feature = static_cast(i); const char *name = GetArmFeaturesEnumName(feature); ASSERT_FALSE(name == nullptr); EXPECT_STRNE(name, ""); EXPECT_STRNE(name, last_name); } } TEST(CpuinfoArmTest, FromHardwareCap) { ResetHwcaps(); SetHardwareCapabilities(ARM_HWCAP_NEON, ARM_HWCAP2_AES | ARM_HWCAP2_CRC32); GetEmptyFilesystem(); // disabling /proc/cpuinfo const auto info = GetArmInfo(); EXPECT_TRUE(info.features.vfp); // triggered by vfpv3 EXPECT_TRUE(info.features.vfpv3); // triggered by neon EXPECT_TRUE(info.features.neon); EXPECT_TRUE(info.features.aes); EXPECT_TRUE(info.features.crc32); EXPECT_FALSE(info.features.vfpv4); EXPECT_FALSE(info.features.iwmmxt); EXPECT_FALSE(info.features.crunch); EXPECT_FALSE(info.features.thumbee); EXPECT_FALSE(info.features.vfpv3d16); EXPECT_FALSE(info.features.idiva); EXPECT_FALSE(info.features.idivt); EXPECT_FALSE(info.features.pmull); EXPECT_FALSE(info.features.sha1); EXPECT_FALSE(info.features.sha2); // check some random features with EnumValue(): EXPECT_TRUE(GetArmFeaturesEnumValue(&info.features, ARM_VFP)); EXPECT_FALSE(GetArmFeaturesEnumValue(&info.features, ARM_VFPV4)); // out of bound EnumValue() check EXPECT_FALSE(GetArmFeaturesEnumValue(&info.features, (ArmFeaturesEnum)~0x0)); } TEST(CpuinfoArmTest, ODroidFromCpuInfo) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"(processor : 0 model name : ARMv7 Processor rev 3 (v71) BogoMIPS : 120.00 Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x2 CPU part : 0xc0f CPU revision : 3)"); const auto info = GetArmInfo(); EXPECT_EQ(info.implementer, 0x41); EXPECT_EQ(info.variant, 0x2); EXPECT_EQ(info.part, 0xc0f); EXPECT_EQ(info.revision, 3); EXPECT_EQ(info.architecture, 7); EXPECT_FALSE(info.features.swp); EXPECT_TRUE(info.features.half); EXPECT_TRUE(info.features.thumb); EXPECT_FALSE(info.features._26bit); EXPECT_TRUE(info.features.fastmult); EXPECT_FALSE(info.features.fpa); EXPECT_TRUE(info.features.vfp); EXPECT_TRUE(info.features.edsp); EXPECT_FALSE(info.features.java); EXPECT_FALSE(info.features.iwmmxt); EXPECT_FALSE(info.features.crunch); EXPECT_FALSE(info.features.thumbee); EXPECT_TRUE(info.features.neon); EXPECT_TRUE(info.features.vfpv3); EXPECT_FALSE(info.features.vfpv3d16); EXPECT_TRUE(info.features.tls); EXPECT_TRUE(info.features.vfpv4); EXPECT_TRUE(info.features.idiva); EXPECT_TRUE(info.features.idivt); EXPECT_TRUE(info.features.vfpd32); EXPECT_TRUE(info.features.lpae); EXPECT_FALSE(info.features.evtstrm); EXPECT_FALSE(info.features.aes); EXPECT_FALSE(info.features.pmull); EXPECT_FALSE(info.features.sha1); EXPECT_FALSE(info.features.sha2); EXPECT_FALSE(info.features.crc32); } // Linux test-case TEST(CpuinfoArmTest, RaspberryPiZeroFromCpuInfo) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"(processor : 0 model name : ARMv6-compatible processor rev 7 (v6l) BogoMIPS : 697.95 Features : half thumb fastmult vfp edsp java tls CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xb76 CPU revision : 7 Hardware : BCM2835 Revision : 9000c1 Serial : 000000006cd946f3)"); const auto info = GetArmInfo(); EXPECT_EQ(info.implementer, 0x41); EXPECT_EQ(info.variant, 0x0); EXPECT_EQ(info.part, 0xb76); EXPECT_EQ(info.revision, 7); EXPECT_EQ(info.architecture, 6); EXPECT_FALSE(info.features.swp); EXPECT_TRUE(info.features.half); EXPECT_TRUE(info.features.thumb); EXPECT_FALSE(info.features._26bit); EXPECT_TRUE(info.features.fastmult); EXPECT_FALSE(info.features.fpa); EXPECT_TRUE(info.features.vfp); EXPECT_TRUE(info.features.edsp); EXPECT_TRUE(info.features.java); EXPECT_FALSE(info.features.iwmmxt); EXPECT_FALSE(info.features.crunch); EXPECT_FALSE(info.features.thumbee); EXPECT_FALSE(info.features.neon); EXPECT_FALSE(info.features.vfpv3); EXPECT_FALSE(info.features.vfpv3d16); EXPECT_TRUE(info.features.tls); EXPECT_FALSE(info.features.vfpv4); EXPECT_FALSE(info.features.idiva); EXPECT_FALSE(info.features.idivt); EXPECT_FALSE(info.features.vfpd32); EXPECT_FALSE(info.features.lpae); EXPECT_FALSE(info.features.evtstrm); EXPECT_FALSE(info.features.aes); EXPECT_FALSE(info.features.pmull); EXPECT_FALSE(info.features.sha1); EXPECT_FALSE(info.features.sha2); EXPECT_FALSE(info.features.crc32); } TEST(CpuinfoArmTest, MarvellArmadaFromCpuInfo) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"(processor : 0 model name : ARMv7 Processor rev 1 (v7l) BogoMIPS : 50.00 Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpd32 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x4 CPU part : 0xc09 CPU revision : 1 processor : 1 model name : ARMv7 Processor rev 1 (v7l) BogoMIPS : 50.00 Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpd32 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x4 CPU part : 0xc09 CPU revision : 1 Hardware : Marvell Armada 380/385 (Device Tree) Revision : 0000 Serial : 0000000000000000)"); const auto info = GetArmInfo(); EXPECT_EQ(info.implementer, 0x41); EXPECT_EQ(info.variant, 0x4); EXPECT_EQ(info.part, 0xc09); EXPECT_EQ(info.revision, 1); EXPECT_EQ(info.architecture, 7); EXPECT_FALSE(info.features.swp); EXPECT_TRUE(info.features.half); EXPECT_TRUE(info.features.thumb); EXPECT_FALSE(info.features._26bit); EXPECT_TRUE(info.features.fastmult); EXPECT_FALSE(info.features.fpa); EXPECT_TRUE(info.features.vfp); EXPECT_TRUE(info.features.edsp); EXPECT_FALSE(info.features.java); EXPECT_FALSE(info.features.iwmmxt); EXPECT_FALSE(info.features.crunch); EXPECT_FALSE(info.features.thumbee); EXPECT_TRUE(info.features.neon); EXPECT_TRUE(info.features.vfpv3); EXPECT_FALSE(info.features.vfpv3d16); EXPECT_TRUE(info.features.tls); EXPECT_FALSE(info.features.vfpv4); EXPECT_FALSE(info.features.idiva); EXPECT_FALSE(info.features.idivt); EXPECT_TRUE(info.features.vfpd32); EXPECT_FALSE(info.features.lpae); EXPECT_FALSE(info.features.evtstrm); EXPECT_FALSE(info.features.aes); EXPECT_FALSE(info.features.pmull); EXPECT_FALSE(info.features.sha1); EXPECT_FALSE(info.features.sha2); EXPECT_FALSE(info.features.crc32); } // Android test-case // http://code.google.com/p/android/issues/detail?id=10812 TEST(CpuinfoArmTest, InvalidArmv7) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"(Processor : ARMv6-compatible processor rev 6 (v6l) BogoMIPS : 199.47 Features : swp half thumb fastmult vfp edsp java CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xb76 CPU revision : 6 Hardware : SPICA Revision : 0020 Serial : 33323613546d00ec )"); const auto info = GetArmInfo(); EXPECT_EQ(info.architecture, 6); EXPECT_TRUE(info.features.swp); EXPECT_TRUE(info.features.half); EXPECT_TRUE(info.features.thumb); EXPECT_FALSE(info.features._26bit); EXPECT_TRUE(info.features.fastmult); EXPECT_FALSE(info.features.fpa); EXPECT_TRUE(info.features.vfp); EXPECT_TRUE(info.features.edsp); EXPECT_TRUE(info.features.java); EXPECT_FALSE(info.features.iwmmxt); EXPECT_FALSE(info.features.crunch); EXPECT_FALSE(info.features.thumbee); EXPECT_FALSE(info.features.neon); EXPECT_FALSE(info.features.vfpv3); EXPECT_FALSE(info.features.vfpv3d16); EXPECT_FALSE(info.features.tls); EXPECT_FALSE(info.features.vfpv4); EXPECT_FALSE(info.features.idiva); EXPECT_FALSE(info.features.idivt); EXPECT_FALSE(info.features.vfpd32); EXPECT_FALSE(info.features.lpae); EXPECT_FALSE(info.features.evtstrm); EXPECT_FALSE(info.features.aes); EXPECT_FALSE(info.features.pmull); EXPECT_FALSE(info.features.sha1); EXPECT_FALSE(info.features.sha2); EXPECT_FALSE(info.features.crc32); } // Android test-case // https://crbug.com/341598. TEST(CpuinfoArmTest, InvalidNeon) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"(Processor: ARMv7 Processory rev 0 (v71) processor: 0 BogoMIPS: 13.50 Processor: 1 BogoMIPS: 13.50 Features: swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt CPU implementer : 0x51 CPU architecture: 7 CPU variant: 0x1 CPU part: 0x04d CPU revision: 0 Hardware: SAMSUNG M2 Revision: 0010 Serial: 00001e030000354e)"); const auto info = GetArmInfo(); EXPECT_TRUE(info.features.swp); EXPECT_FALSE(info.features.neon); } // The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report IDIV // support. TEST(CpuinfoArmTest, Nexus4_0x510006f2) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"(CPU implementer : 0x51 CPU architecture: 7 CPU variant : 0x0 CPU part : 0x6f CPU revision : 2)"); const auto info = GetArmInfo(); EXPECT_TRUE(info.features.idiva); EXPECT_TRUE(info.features.idivt); EXPECT_EQ(GetArmCpuId(&info), 0x510006f2); } // The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report IDIV // support. TEST(CpuinfoArmTest, Nexus4_0x510006f3) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"(CPU implementer : 0x51 CPU architecture: 7 CPU variant : 0x0 CPU part : 0x6f CPU revision : 3)"); const auto info = GetArmInfo(); EXPECT_TRUE(info.features.idiva); EXPECT_TRUE(info.features.idivt); EXPECT_EQ(GetArmCpuId(&info), 0x510006f3); } // The 2013 Nexus 7 (Qualcomm Krait) kernel configuration forgets to report IDIV // support. TEST(CpuinfoArmTest, Nexus7_2013_0x511006f0) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"(CPU implementer : 0x51 CPU architecture: 7 CPU variant : 0x1 CPU part : 0x06f CPU revision : 0)"); const auto info = GetArmInfo(); EXPECT_TRUE(info.features.idiva); EXPECT_TRUE(info.features.idivt); EXPECT_EQ(GetArmCpuId(&info), 0x511006f0); } // The emulator-specific Android 4.2 kernel fails to report support for the // 32-bit ARM IDIV instruction. Technically, this is a feature of the virtual // CPU implemented by the emulator. TEST(CpuinfoArmTest, EmulatorSpecificIdiv) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"(Processor : ARMv7 Processor rev 0 (v7l) BogoMIPS : 629.14 Features : swp half thumb fastmult vfp edsp neon vfpv3 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xc08 CPU revision : 0 Hardware : Goldfish Revision : 0000 Serial : 0000000000000000)"); const auto info = GetArmInfo(); EXPECT_TRUE(info.features.idiva); } } // namespace } // namespace cpu_features cpu-features-0.9.0/test/cpuinfo_loongarch_test.cc000066400000000000000000000120561450057454500221640ustar00rootroot00000000000000// Copyright 2022 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. #include "cpuinfo_loongarch.h" #include "filesystem_for_testing.h" #include "gtest/gtest.h" #include "hwcaps_for_testing.h" namespace cpu_features { namespace { TEST(CpuinfoLoongArchvTest, UnknownFromCpuInfo) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"( system type : generic-loongson-machine processor : 0 package : 0 core : 0 CPU Family : Loongson-64bit Model Name : Loongson-3A5000-HV CPU Revision : 0x11 FPU Revision : 0x00 CPU MHz : 2500.00 BogoMIPS : 5000.00 TLB Entries : 2112 Address Sizes : 48 bits physical, 48 bits virtual ISA : loongarch32 loongarch64 Features : cpucfg lam ual fpu lsx lasx crc32 complex crypto lvz lbt_x86 lbt_arm lbt_mips Hardware Watchpoint : yes, iwatch count: 8, dwatch count: 8 processor : 1 package : 0 core : 1 CPU Family : Loongson-64bit Model Name : Loongson-3A5000-HV CPU Revision : 0x11 FPU Revision : 0x00 CPU MHz : 2500.00 BogoMIPS : 5000.00 TLB Entries : 2112 Address Sizes : 48 bits physical, 48 bits virtual ISA : loongarch32 loongarch64 Features : cpucfg lam ual fpu lsx lasx crc32 complex crypto lvz lbt_x86 lbt_arm lbt_mips Hardware Watchpoint : yes, iwatch count: 8, dwatch count: 8 processor : 2 package : 0 core : 2 CPU Family : Loongson-64bit Model Name : Loongson-3A5000-HV CPU Revision : 0x11 FPU Revision : 0x00 CPU MHz : 2500.00 BogoMIPS : 5000.00 TLB Entries : 2112 Address Sizes : 48 bits physical, 48 bits virtual ISA : loongarch32 loongarch64 Features : cpucfg lam ual fpu lsx lasx crc32 complex crypto lvz lbt_x86 lbt_arm lbt_mips Hardware Watchpoint : yes, iwatch count: 8, dwatch count: 8 processor : 3 package : 0 core : 3 CPU Family : Loongson-64bit Model Name : Loongson-3A5000-HV CPU Revision : 0x11 FPU Revision : 0x00 CPU MHz : 2500.00 BogoMIPS : 5000.00 TLB Entries : 2112 Address Sizes : 48 bits physical, 48 bits virtual ISA : loongarch32 loongarch64 Features : cpucfg lam ual fpu lsx lasx crc32 complex crypto lvz lbt_x86 lbt_arm lbt_mips Hardware Watchpoint : yes, iwatch count: 8, dwatch count: 8)"); const auto info = GetLoongArchInfo(); EXPECT_FALSE(info.features.CPUCFG); EXPECT_TRUE(info.features.LAM); EXPECT_TRUE(info.features.UAL); EXPECT_TRUE(info.features.FPU); EXPECT_TRUE(info.features.LSX); EXPECT_TRUE(info.features.LASX); EXPECT_TRUE(info.features.CRC32); EXPECT_TRUE(info.features.COMPLEX); EXPECT_TRUE(info.features.CRYPTO); EXPECT_TRUE(info.features.LVZ); EXPECT_TRUE(info.features.LBT_X86); EXPECT_TRUE(info.features.LBT_ARM); EXPECT_TRUE(info.features.LBT_MIPS); } TEST(CpuinfoLoongArchvTest, QemuCpuInfo) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"( system type : generic-loongson-machine processor : 0 package : 0 core : 0 CPU Family : Loongson-64bit Model Name : Loongson-3A5000 CPU Revision : 0x10 FPU Revision : 0x01 CPU MHz : 2000.00 BogoMIPS : 4000.00 TLB Entries : 2112 Address Sizes : 48 bits physical, 48 bits virtual ISA : loongarch32 loongarch64 Features : cpucfg lam ual fpu crc32 Hardware Watchpoint : yes, iwatch count: 0, dwatch count: 0 processor : 1 package : 0 core : 1 CPU Family : Loongson-64bit Model Name : Loongson-3A5000 CPU Revision : 0x10 FPU Revision : 0x01 CPU MHz : 2000.00 BogoMIPS : 4000.00 TLB Entries : 2112 Address Sizes : 48 bits physical, 48 bits virtual ISA : loongarch32 loongarch64 Features : cpucfg lam ual fpu crc32 Hardware Watchpoint : yes, iwatch count: 0, dwatch count: 0 processor : 2 package : 0 core : 2 CPU Family : Loongson-64bit Model Name : Loongson-3A5000 CPU Revision : 0x10 FPU Revision : 0x01 CPU MHz : 2000.00 BogoMIPS : 4000.00 TLB Entries : 2112 Address Sizes : 48 bits physical, 48 bits virtual ISA : loongarch32 loongarch64 Features : cpucfg lam ual fpu crc32 Hardware Watchpoint : yes, iwatch count: 0, dwatch count: 0 processor : 3 package : 0 core : 3 CPU Family : Loongson-64bit Model Name : Loongson-3A5000 CPU Revision : 0x10 FPU Revision : 0x01 CPU MHz : 2000.00 BogoMIPS : 4000.00 TLB Entries : 2112 Address Sizes : 48 bits physical, 48 bits virtual ISA : loongarch32 loongarch64 Features : cpucfg lam ual fpu crc32 Hardware Watchpoint : yes, iwatch count: 0, dwatch count: 0)"); const auto info = GetLoongArchInfo(); EXPECT_FALSE(info.features.CPUCFG); EXPECT_TRUE(info.features.LAM); EXPECT_TRUE(info.features.UAL); EXPECT_TRUE(info.features.FPU); EXPECT_TRUE(info.features.CRC32); } } // namespace } // namespace cpu_features cpu-features-0.9.0/test/cpuinfo_mips_test.cc000066400000000000000000000126501450057454500211600ustar00rootroot00000000000000// 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. // 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 "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" namespace cpu_features { namespace { TEST(CpuinfoMipsTest, MipsFeaturesEnum) { const char *last_name = GetMipsFeaturesEnumName(MIPS_LAST_); EXPECT_STREQ(last_name, "unknown_feature"); for (int i = static_cast(MIPS_MSA); i != static_cast(MIPS_LAST_); ++i) { const auto feature = static_cast(i); const char *name = GetMipsFeaturesEnumName(feature); ASSERT_FALSE(name == nullptr); EXPECT_STRNE(name, ""); EXPECT_STRNE(name, last_name); } } TEST(CpuinfoMipsTest, FromHardwareCapBoth) { ResetHwcaps(); SetHardwareCapabilities(MIPS_HWCAP_MSA | MIPS_HWCAP_R6, 0); GetEmptyFilesystem(); // disabling /proc/cpuinfo const auto info = GetMipsInfo(); EXPECT_TRUE(info.features.msa); EXPECT_FALSE(info.features.eva); EXPECT_TRUE(info.features.r6); } TEST(CpuinfoMipsTest, FromHardwareCapOnlyOne) { ResetHwcaps(); SetHardwareCapabilities(MIPS_HWCAP_MSA, 0); GetEmptyFilesystem(); // disabling /proc/cpuinfo const auto info = GetMipsInfo(); EXPECT_TRUE(info.features.msa); EXPECT_FALSE(info.features.eva); } TEST(CpuinfoMipsTest, Ci40) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"(system type : IMG Pistachio SoC (B0) machine : IMG Marduk – Ci40 with cc2520 processor : 0 cpu model : MIPS interAptiv (multi) V2.0 FPU V0.0 BogoMIPS : 363.72 wait instruction : yes microsecond timers : yes tlb_entries : 64 extra interrupt vector : yes hardware watchpoint : yes, count: 4, address/irw mask: [0x0ffc, 0x0ffc, 0x0ffb, 0x0ffb] isa : mips1 mips2 mips32r1 mips32r2 ASEs implemented : mips16 dsp mt eva shadow register sets : 1 kscratch registers : 0 package : 0 core : 0 VCED exceptions : not available VCEI exceptions : not available VPE : 0 )"); const auto info = GetMipsInfo(); EXPECT_FALSE(info.features.msa); EXPECT_TRUE(info.features.eva); EXPECT_FALSE(info.features.r6); EXPECT_TRUE(info.features.mips16); EXPECT_FALSE(info.features.mdmx); EXPECT_FALSE(info.features.mips3d); EXPECT_FALSE(info.features.smart); EXPECT_TRUE(info.features.dsp); } TEST(CpuinfoMipsTest, AR7161) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"(system type : Atheros AR7161 rev 2 machine : NETGEAR WNDR3700/WNDR3800/WNDRMAC processor : 0 cpu model : MIPS 24Kc V7.4 BogoMIPS : 452.19 wait instruction : yes microsecond timers : yes tlb_entries : 16 extra interrupt vector : yes hardware watchpoint : yes, count: 4, address/irw mask: [0x0000, 0x0f98, 0x0f78, 0x0df8] ASEs implemented : mips16 shadow register sets : 1 kscratch registers : 0 core : 0 VCED exceptions : not available VCEI exceptions : not available )"); const auto info = GetMipsInfo(); EXPECT_FALSE(info.features.msa); EXPECT_FALSE(info.features.eva); EXPECT_TRUE(info.features.mips16); } TEST(CpuinfoMipsTest, Goldfish) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"(system type : MIPS-Goldfish Hardware : goldfish Revison : 1 processor : 0 cpu model : MIPS 24Kc V0.0 FPU V0.0 BogoMIPS : 1042.02 wait instruction : yes microsecond timers : yes tlb_entries : 16 extra interrupt vector : yes hardware watchpoint : yes, count: 1, address/irw mask: [0x0ff8] ASEs implemented : shadow register sets : 1 core : 0 VCED exceptions : not available VCEI exceptions : not available )"); const auto info = GetMipsInfo(); EXPECT_FALSE(info.features.msa); EXPECT_FALSE(info.features.eva); } TEST(CpuinfoMipsTest, BCM1250) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"(system type : SiByte BCM91250A (SWARM) processor : 0 cpu model : SiByte SB1 V0.2 FPU V0.2 BogoMIPS : 532.48 wait instruction : no microsecond timers : yes tlb_entries : 64 extra interrupt vector : yes hardware watchpoint : yes, count: 1, address/irw mask: [0x0ff8] isa : mips1 mips2 mips3 mips4 mips5 mips32r1 mips32r2 mips64r1 mips64r2 ASEs implemented : mdmx mips3d shadow register sets : 1 kscratch registers : 0 package : 0 core : 0 VCED exceptions : not available VCEI exceptions : not available )"); const auto info = GetMipsInfo(); EXPECT_FALSE(info.features.msa); EXPECT_FALSE(info.features.eva); EXPECT_FALSE(info.features.mips16); EXPECT_TRUE(info.features.mdmx); EXPECT_TRUE(info.features.mips3d); EXPECT_FALSE(info.features.smart); EXPECT_FALSE(info.features.dsp); } } // namespace } // namespace cpu_features cpu-features-0.9.0/test/cpuinfo_ppc_test.cc000066400000000000000000000104601450057454500207670ustar00rootroot00000000000000// Copyright 2018 IBM. // // 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 "cpuinfo_ppc.h" #include "filesystem_for_testing.h" #include "gtest/gtest.h" #include "hwcaps_for_testing.h" #include "internal/string_view.h" namespace cpu_features { namespace { TEST(CpustringsPPCTest, PPCFeaturesEnum) { const char *last_name = GetPPCFeaturesEnumName(PPC_LAST_); EXPECT_STREQ(last_name, "unknown_feature"); for (int i = static_cast(PPC_32); i != static_cast(PPC_LAST_); ++i) { const auto feature = static_cast(i); const char *name = GetPPCFeaturesEnumName(feature); ASSERT_FALSE(name == nullptr); EXPECT_STRNE(name, ""); EXPECT_STRNE(name, last_name); } } TEST(CpustringsPPCTest, FromHardwareCap) { ResetHwcaps(); SetHardwareCapabilities(PPC_FEATURE_HAS_FPU | PPC_FEATURE_HAS_VSX, PPC_FEATURE2_ARCH_3_00); GetEmptyFilesystem(); // disabling /proc/cpuinfo const auto info = GetPPCInfo(); EXPECT_TRUE(info.features.fpu); EXPECT_FALSE(info.features.mmu); EXPECT_TRUE(info.features.vsx); EXPECT_TRUE(info.features.arch300); EXPECT_FALSE(info.features.power4); EXPECT_FALSE(info.features.altivec); EXPECT_FALSE(info.features.vcrypto); EXPECT_FALSE(info.features.htm); } TEST(CpustringsPPCTest, Blade) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"(processor : 14 cpu : POWER7 (architected), altivec supported clock : 3000.000000MHz revision : 2.1 (pvr 003f 0201) processor : 15 cpu : POWER7 (architected), altivec supported clock : 3000.000000MHz revision : 2.1 (pvr 003f 0201) timebase : 512000000 platform : pSeries model : IBM,8406-70Y machine : CHRP IBM,8406-70Y)"); SetPlatformPointer("power7"); SetBasePlatformPointer("power8"); const auto strings = GetPPCPlatformStrings(); ASSERT_STREQ(strings.platform, "pSeries"); ASSERT_STREQ(strings.model, "IBM,8406-70Y"); ASSERT_STREQ(strings.machine, "CHRP IBM,8406-70Y"); ASSERT_STREQ(strings.cpu, "POWER7 (architected), altivec supported"); ASSERT_STREQ(strings.type.platform, "power7"); ASSERT_STREQ(strings.type.base_platform, "power8"); } TEST(CpustringsPPCTest, Firestone) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"(processor : 126 cpu : POWER8 (raw), altivec supported clock : 2061.000000MHz revision : 2.0 (pvr 004d 0200) processor : 127 cpu : POWER8 (raw), altivec supported clock : 2061.000000MHz revision : 2.0 (pvr 004d 0200) timebase : 512000000 platform : PowerNV model : 8335-GTA machine : PowerNV 8335-GTA firmware : OPAL v3)"); const auto strings = GetPPCPlatformStrings(); ASSERT_STREQ(strings.platform, "PowerNV"); ASSERT_STREQ(strings.model, "8335-GTA"); ASSERT_STREQ(strings.machine, "PowerNV 8335-GTA"); ASSERT_STREQ(strings.cpu, "POWER8 (raw), altivec supported"); } TEST(CpustringsPPCTest, w8) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"(processor : 143 cpu : POWER9, altivec supported clock : 2300.000000MHz revision : 2.2 (pvr 004e 1202) timebase : 512000000 platform : PowerNV model : 0000000000000000 machine : PowerNV 0000000000000000 firmware : OPAL MMU : Radix)"); const auto strings = GetPPCPlatformStrings(); ASSERT_STREQ(strings.platform, "PowerNV"); ASSERT_STREQ(strings.model, "0000000000000000"); ASSERT_STREQ(strings.machine, "PowerNV 0000000000000000"); ASSERT_STREQ(strings.cpu, "POWER9, altivec supported"); } } // namespace } // namespace cpu_features cpu-features-0.9.0/test/cpuinfo_riscv_test.cc000066400000000000000000000112401450057454500213300ustar00rootroot00000000000000// Copyright 2022 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. #include "cpuinfo_riscv.h" #include "filesystem_for_testing.h" #include "gtest/gtest.h" #include "hwcaps_for_testing.h" namespace cpu_features { namespace { TEST(CpuinfoRiscvTest, Sipeed_Lichee_RV_FromCpuInfo) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"(processor : 0 hart : 0 isa : rv64imafdc mmu : sv39 uarch : thead,c906)"); const auto info = GetRiscvInfo(); EXPECT_STREQ(info.uarch, "c906"); EXPECT_STREQ(info.vendor, "thead"); EXPECT_FALSE(info.features.RV32I); EXPECT_TRUE(info.features.RV64I); EXPECT_TRUE(info.features.M); EXPECT_TRUE(info.features.A); EXPECT_TRUE(info.features.F); EXPECT_TRUE(info.features.D); EXPECT_FALSE(info.features.Q); EXPECT_TRUE(info.features.C); EXPECT_FALSE(info.features.V); } // https://github.com/ThomasKaiser/sbc-bench/blob/284e82b016ec1beeac42a5fcbe556b670f68441a/results/Kendryte-K510-4.17.0.cpuinfo TEST(CpuinfoRiscvTest, Kendryte_K510_FromCpuInfo) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"( hart : 0 isa : rv64i2p0m2p0a2p0f2p0d2p0c2p0xv5-0p0 mmu : sv39 hart : 1 isa : rv64i2p0m2p0a2p0f2p0d2p0c2p0xv5-0p0 mmu : sv39"); const auto info = GetRiscvInfo(); EXPECT_STREQ(info.uarch, ""); EXPECT_STREQ(info.vendor, ""); EXPECT_FALSE(info.features.RV32I); EXPECT_TRUE(info.features.RV64I); EXPECT_TRUE(info.features.M); EXPECT_TRUE(info.features.A); EXPECT_TRUE(info.features.F); EXPECT_TRUE(info.features.D); EXPECT_FALSE(info.features.Q); EXPECT_TRUE(info.features.C); EXPECT_FALSE(info.features.V); } // https://github.com/ThomasKaiser/sbc-bench/blob/284e82b016ec1beeac42a5fcbe556b670f68441a/results/T-Head-C910-5.10.4.cpuinfo TEST(CpuinfoRiscvTest, T_Head_C910_FromCpuInfo) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"( processor : 0 hart : 0 isa : rv64imafdcsu mmu : sv39 cpu-freq : 1.2Ghz cpu-icache : 64KB cpu-dcache : 64KB cpu-l2cache : 2MB cpu-tlb : 1024 4-ways cpu-cacheline : 64Bytes cpu-vector : 0.7.1 processor : 1 hart : 1 isa : rv64imafdcsu mmu : sv39 cpu-freq : 1.2Ghz cpu-icache : 64KB cpu-dcache : 64KB cpu-l2cache : 2MB cpu-tlb : 1024 4-ways cpu-cacheline : 64Bytes cpu-vector : 0.7.1"); const auto info = GetRiscvInfo(); EXPECT_STREQ(info.uarch, ""); EXPECT_STREQ(info.vendor, ""); EXPECT_FALSE(info.features.RV32I); EXPECT_TRUE(info.features.RV64I); EXPECT_TRUE(info.features.M); EXPECT_TRUE(info.features.A); EXPECT_TRUE(info.features.F); EXPECT_TRUE(info.features.D); EXPECT_FALSE(info.features.Q); EXPECT_TRUE(info.features.C); EXPECT_FALSE(info.features.V); } TEST(CpuinfoRiscvTest, UnknownFromCpuInfo) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"( processor : 0 hart : 2 isa : rv64imafdc mmu : sv39 uarch : sifive,bullet0 processor : 1 hart : 1 isa : rv64imafdc mmu : sv39 uarch : sifive,bullet0 processor : 2 hart : 3 isa : rv64imafdc mmu : sv39 uarch : sifive,bullet0 processor : 3 hart : 4 isa : rv64imafdc mmu : sv39 uarch : sifive,bullet0)"); const auto info = GetRiscvInfo(); EXPECT_STREQ(info.uarch, "bullet0"); EXPECT_STREQ(info.vendor, "sifive"); EXPECT_FALSE(info.features.RV32I); EXPECT_TRUE(info.features.RV64I); EXPECT_TRUE(info.features.M); EXPECT_TRUE(info.features.A); EXPECT_TRUE(info.features.F); EXPECT_TRUE(info.features.D); EXPECT_FALSE(info.features.Q); EXPECT_TRUE(info.features.C); EXPECT_FALSE(info.features.V); } TEST(CpuinfoRiscvTest, QemuCpuInfo) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"( processor : 0 hart : 0 isa : rv64imafdcvh_zba_zbb_zbc_zbs mmu : sv48)"); const auto info = GetRiscvInfo(); EXPECT_FALSE(info.features.RV32I); EXPECT_TRUE(info.features.RV64I); EXPECT_TRUE(info.features.M); EXPECT_TRUE(info.features.A); EXPECT_TRUE(info.features.F); EXPECT_TRUE(info.features.D); EXPECT_FALSE(info.features.Q); EXPECT_TRUE(info.features.C); EXPECT_TRUE(info.features.V); } } // namespace } // namespace cpu_features cpu-features-0.9.0/test/cpuinfo_s390x_test.cc000066400000000000000000000054621450057454500211010ustar00rootroot00000000000000// Copyright 2022 IBM. // // 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 "cpuinfo_s390x.h" #include "filesystem_for_testing.h" #include "gtest/gtest.h" #include "hwcaps_for_testing.h" namespace cpu_features { namespace { TEST(CpustringsS390XTest, S390XFeaturesEnum) { const char *last_name = GetS390XFeaturesEnumName(S390X_LAST_); EXPECT_STREQ(last_name, "unknown_feature"); for (int i = static_cast(S390_ZARCH); i != static_cast(S390X_LAST_); ++i) { const auto feature = static_cast(i); const char *name = GetS390XFeaturesEnumName(feature); ASSERT_FALSE(name == nullptr); EXPECT_STRNE(name, ""); EXPECT_STRNE(name, last_name); } } TEST(CpustringsS390XTest, FromHardwareCap) { ResetHwcaps(); SetHardwareCapabilities(HWCAP_S390_ESAN3 | HWCAP_S390_HPAGE | HWCAP_S390_NNPA | HWCAP_S390_SIE, 0); GetEmptyFilesystem(); // disabling /proc/cpuinfo const auto info = GetS390XInfo(); EXPECT_TRUE(info.features.esan3); EXPECT_TRUE(info.features.edat); EXPECT_TRUE(info.features.nnpa); EXPECT_TRUE(info.features.sie); EXPECT_FALSE(info.features.msa); EXPECT_FALSE(info.features.stfle); EXPECT_FALSE(info.features.vxp2); EXPECT_FALSE(info.features.pcimio); } TEST(CpustringsS390XTest, z16) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"(vendor_id : IBM/S390 # processors : 24 bogomips per cpu: 26315.00 max thread id : 1 features : esan3 zarch stfle msa ldisp eimm dfp edat etf3eh highgprs te vx vxd vxe gs vxe2 vxp sort dflt vxp2 nnpa pcimio sie )"); SetPlatformPointer("z16"); const auto strings = GetS390XPlatformStrings(); EXPECT_EQ(strings.num_processors, 24); ASSERT_STREQ(strings.type.platform, "z16"); } TEST(CpustringsS390XTest, z15) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"(vendor_id : IBM/S390 # processors : 2 bogomips per cpu: 24038.00 max thread id : 1 features : esan3 zarch stfle msa ldisp eimm dfp edat etf3eh highgprs te vx vxd vxe gs vxe2 vxp sort dflt sie)"); SetPlatformPointer("z15"); const auto strings = GetS390XPlatformStrings(); EXPECT_EQ(strings.num_processors, 2); ASSERT_STREQ(strings.type.platform, "z15"); } } // namespace } // namespace cpu_features cpu-features-0.9.0/test/cpuinfo_x86_test.cc000066400000000000000000002337141450057454500206430ustar00rootroot00000000000000// 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. // 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 "cpuinfo_x86.h" #include #include #include #include #if defined(CPU_FEATURES_OS_WINDOWS) #include "internal/windows_utils.h" #endif // CPU_FEATURES_OS_WINDOWS #include "filesystem_for_testing.h" #include "gtest/gtest.h" #include "internal/cpuid_x86.h" namespace cpu_features { class FakeCpu { public: Leaf 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; } return {0, 0, 0, 0}; } uint32_t GetXCR0Eax() const { return xcr0_eax_; } void SetLeaves(std::map, Leaf> configuration) { cpuid_leaves_ = std::move(configuration); } void SetOsBackupsExtendedRegisters(bool os_backups_extended_registers) { xcr0_eax_ = os_backups_extended_registers ? -1 : 0; } #if defined(CPU_FEATURES_OS_MACOS) bool GetDarwinSysCtlByName(std::string name) const { return darwin_sysctlbyname_.count(name); } void SetDarwinSysCtlByName(std::string name) { darwin_sysctlbyname_.insert(name); } #endif // CPU_FEATURES_OS_MACOS #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, Leaf> cpuid_leaves_; #if defined(CPU_FEATURES_OS_MACOS) std::set darwin_sysctlbyname_; #endif // CPU_FEATURES_OS_MACOS #if defined(CPU_FEATURES_OS_WINDOWS) std::set windows_isprocessorfeaturepresent_; #endif // CPU_FEATURES_OS_WINDOWS uint32_t xcr0_eax_; }; static FakeCpu* g_fake_cpu_instance = nullptr; static FakeCpu& cpu() { assert(g_fake_cpu_instance != nullptr); return *g_fake_cpu_instance; } extern "C" Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx) { return cpu().GetCpuidLeaf(leaf_id, ecx); } extern "C" uint32_t GetXCR0Eax(void) { return cpu().GetXCR0Eax(); } #if defined(CPU_FEATURES_OS_MACOS) extern "C" bool GetDarwinSysCtlByName(const char* name) { return cpu().GetDarwinSysCtlByName(name); } #endif // CPU_FEATURES_OS_MACOS #if defined(CPU_FEATURES_OS_WINDOWS) extern "C" bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) { return cpu().GetWindowsIsProcessorFeaturePresent(ProcessorFeature); } #endif // CPU_FEATURES_OS_WINDOWS namespace { class CpuidX86Test : public ::testing::Test { protected: void SetUp() override { assert(g_fake_cpu_instance == nullptr); g_fake_cpu_instance = new FakeCpu(); } void TearDown() override { delete g_fake_cpu_instance; g_fake_cpu_instance = nullptr; } }; TEST_F(CpuidX86Test, X86MicroarchitectureEnum) { const char *last_name = GetX86MicroarchitectureName(X86_MICROARCHITECTURE_LAST_); EXPECT_STREQ(last_name, "unknown microarchitecture"); for (int i = static_cast(X86_UNKNOWN); i != static_cast(X86_MICROARCHITECTURE_LAST_); ++i) { const auto micro = static_cast(i); const char *name = GetX86MicroarchitectureName(micro); ASSERT_FALSE(name == nullptr); EXPECT_STRNE(name, ""); EXPECT_STRNE(name, last_name); } } TEST_F(CpuidX86Test, X86FeaturesEnum) { const char *last_name = GetX86FeaturesEnumName(X86_LAST_); EXPECT_STREQ(last_name, "unknown_feature"); for (int i = static_cast(X86_FPU); i != static_cast(X86_LAST_); ++i) { const auto feature = static_cast(i); const char *name = GetX86FeaturesEnumName(feature); ASSERT_FALSE(name == nullptr); EXPECT_STRNE(name, ""); EXPECT_STRNE(name, last_name); } } TEST_F(CpuidX86Test, SandyBridge) { cpu().SetOsBackupsExtendedRegisters(true); cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}}, {{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x02A); EXPECT_EQ(info.stepping, 0x06); // Leaf 7 is zeroed out so none of the Leaf 7 flags are set. const auto features = info.features; EXPECT_FALSE(features.erms); EXPECT_FALSE(features.avx2); EXPECT_FALSE(features.avx512f); EXPECT_FALSE(features.avx512cd); EXPECT_FALSE(features.avx512er); EXPECT_FALSE(features.avx512pf); EXPECT_FALSE(features.avx512bw); EXPECT_FALSE(features.avx512dq); EXPECT_FALSE(features.avx512vl); EXPECT_FALSE(features.avx512ifma); EXPECT_FALSE(features.avx512vbmi); EXPECT_FALSE(features.avx512vbmi2); EXPECT_FALSE(features.avx512vnni); EXPECT_FALSE(features.avx512bitalg); EXPECT_FALSE(features.avx512vpopcntdq); EXPECT_FALSE(features.avx512_4vnniw); EXPECT_FALSE(features.avx512_4fmaps); // All old cpu features should be set. EXPECT_TRUE(features.aes); EXPECT_TRUE(features.ssse3); EXPECT_TRUE(features.sse4_1); EXPECT_TRUE(features.sse4_2); EXPECT_TRUE(features.avx); EXPECT_FALSE(features.sha); EXPECT_TRUE(features.popcnt); EXPECT_FALSE(features.movbe); EXPECT_FALSE(features.rdrnd); EXPECT_FALSE(features.adx); EXPECT_FALSE(features.lam); EXPECT_FALSE(features.uai); } const int UNDEF = -1; const int KiB = 1024; const int MiB = 1024 * KiB; TEST_F(CpuidX86Test, SandyBridgeTestOsSupport) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}}, {{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, }); // avx is disabled if os does not support backing up ymm registers. cpu().SetOsBackupsExtendedRegisters(false); EXPECT_FALSE(GetX86Info().features.avx); // avx is disabled if os does not support backing up ymm registers. cpu().SetOsBackupsExtendedRegisters(true); EXPECT_TRUE(GetX86Info().features.avx); } TEST_F(CpuidX86Test, SkyLake) { cpu().SetOsBackupsExtendedRegisters(true); cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}}, {{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x04E); EXPECT_EQ(info.stepping, 0x03); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_SKL); } // http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel0050654_SkylakeXeon_CPUID8.txt TEST_F(CpuidX86Test, SkyLakeXeon) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x00050654, 0x00100800, 0x7FFEFBFF, 0xBFEBFBFF}} }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x055); EXPECT_EQ(info.stepping, 0x04); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_SKL); } // http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel0050657_CascadeLakeXeon_CPUID.txt TEST_F(CpuidX86Test, CascadeLake) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x00050657, 0x00400800, 0x7FFEFBFF, 0xBFEBFBFF}} }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x055); EXPECT_EQ(info.stepping, 0x07); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_CCL); } TEST_F(CpuidX86Test, Branding) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}}, {{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}}, {{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}}, {{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}}, {{0x80000002, 0}, Leaf{0x65746E49, 0x2952286C, 0x726F4320, 0x4D542865}}, {{0x80000003, 0}, Leaf{0x37692029, 0x3035362D, 0x43205530, 0x40205550}}, {{0x80000004, 0}, Leaf{0x352E3220, 0x7A484730, 0x00000000, 0x00000000}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.brand_string, "Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz"); } TEST_F(CpuidX86Test, KabyLakeCache) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}}, {{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}}, {{0x00000004, 1}, Leaf{0x1C004122, 0x01C0003F, 0x0000003F, 0x00000000}}, {{0x00000004, 2}, Leaf{0x1C004143, 0x00C0003F, 0x000003FF, 0x00000000}}, {{0x00000004, 3}, Leaf{0x1C03C163, 0x02C0003F, 0x00001FFF, 0x00000002}}, {{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}}, {{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}}, {{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}}, {{0x80000002, 0}, Leaf{0x65746E49, 0x2952286C, 0x726F4320, 0x4D542865}}, {{0x80000003, 0}, Leaf{0x37692029, 0x3035362D, 0x43205530, 0x40205550}}, }); const auto info = GetX86CacheInfo(); EXPECT_EQ(info.size, 4); EXPECT_EQ(info.levels[0].level, 1); EXPECT_EQ(info.levels[0].cache_type, CacheType::CPU_FEATURE_CACHE_DATA); EXPECT_EQ(info.levels[0].cache_size, 32 * KiB); EXPECT_EQ(info.levels[0].ways, 8); EXPECT_EQ(info.levels[0].line_size, 64); EXPECT_EQ(info.levels[0].tlb_entries, 64); EXPECT_EQ(info.levels[0].partitioning, 1); EXPECT_EQ(info.levels[1].level, 1); EXPECT_EQ(info.levels[1].cache_type, CacheType::CPU_FEATURE_CACHE_INSTRUCTION); EXPECT_EQ(info.levels[1].cache_size, 32 * KiB); EXPECT_EQ(info.levels[1].ways, 8); EXPECT_EQ(info.levels[1].line_size, 64); EXPECT_EQ(info.levels[1].tlb_entries, 64); EXPECT_EQ(info.levels[1].partitioning, 1); EXPECT_EQ(info.levels[2].level, 2); EXPECT_EQ(info.levels[2].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED); EXPECT_EQ(info.levels[2].cache_size, 256 * KiB); EXPECT_EQ(info.levels[2].ways, 4); EXPECT_EQ(info.levels[2].line_size, 64); EXPECT_EQ(info.levels[2].tlb_entries, 1024); EXPECT_EQ(info.levels[2].partitioning, 1); EXPECT_EQ(info.levels[3].level, 3); EXPECT_EQ(info.levels[3].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED); EXPECT_EQ(info.levels[3].cache_size, 6 * MiB); EXPECT_EQ(info.levels[3].ways, 12); EXPECT_EQ(info.levels[3].line_size, 64); EXPECT_EQ(info.levels[3].tlb_entries, 8192); EXPECT_EQ(info.levels[3].partitioning, 1); } TEST_F(CpuidX86Test, HSWCache) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}}, {{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}}, {{0x00000004, 1}, Leaf{0x1C004122, 0x01C0003F, 0x0000003F, 0x00000000}}, {{0x00000004, 2}, Leaf{0x1C004143, 0x01C0003F, 0x000001FF, 0x00000000}}, {{0x00000004, 3}, Leaf{0x1C03C163, 0x02C0003F, 0x00001FFF, 0x00000006}}, {{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}}, {{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}}, {{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}}, {{0x80000002, 0}, Leaf{0x65746E49, 0x2952286C, 0x726F4320, 0x4D542865}}, {{0x80000003, 0}, Leaf{0x37692029, 0x3035362D, 0x43205530, 0x40205550}}, }); const auto info = GetX86CacheInfo(); EXPECT_EQ(info.size, 4); EXPECT_EQ(info.levels[0].level, 1); EXPECT_EQ(info.levels[0].cache_type, CacheType::CPU_FEATURE_CACHE_DATA); EXPECT_EQ(info.levels[0].cache_size, 32 * KiB); EXPECT_EQ(info.levels[0].ways, 8); EXPECT_EQ(info.levels[0].line_size, 64); EXPECT_EQ(info.levels[0].tlb_entries, 64); EXPECT_EQ(info.levels[0].partitioning, 1); EXPECT_EQ(info.levels[1].level, 1); EXPECT_EQ(info.levels[1].cache_type, CacheType::CPU_FEATURE_CACHE_INSTRUCTION); EXPECT_EQ(info.levels[1].cache_size, 32 * KiB); EXPECT_EQ(info.levels[1].ways, 8); EXPECT_EQ(info.levels[1].line_size, 64); EXPECT_EQ(info.levels[1].tlb_entries, 64); EXPECT_EQ(info.levels[1].partitioning, 1); EXPECT_EQ(info.levels[2].level, 2); EXPECT_EQ(info.levels[2].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED); EXPECT_EQ(info.levels[2].cache_size, 256 * KiB); EXPECT_EQ(info.levels[2].ways, 8); EXPECT_EQ(info.levels[2].line_size, 64); EXPECT_EQ(info.levels[2].tlb_entries, 512); EXPECT_EQ(info.levels[2].partitioning, 1); EXPECT_EQ(info.levels[3].level, 3); EXPECT_EQ(info.levels[3].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED); EXPECT_EQ(info.levels[3].cache_size, 6 * MiB); EXPECT_EQ(info.levels[3].ways, 12); EXPECT_EQ(info.levels[3].line_size, 64); EXPECT_EQ(info.levels[3].tlb_entries, 8192); EXPECT_EQ(info.levels[3].partitioning, 1); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0200F30_K11_Griffin_CPUID.txt TEST_F(CpuidX86Test, AMD_K11_GRIFFIN) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000001, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00200F30, 0x00020800, 0x00002001, 0x178BFBFF}}, {{0x80000000, 0}, Leaf{0x8000001A, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00200F30, 0x20000000, 0x0000131F, 0xEBD3FBFF}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x11); EXPECT_EQ(info.model, 0x03); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_K11); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0300F10_K12_Llano_CPUID.txt TEST_F(CpuidX86Test, AMD_K12_LLANO) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000006, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00300F10, 0x00040800, 0x00802009, 0x178BFBFF}}, {{0x80000000, 0}, Leaf{0x8000001B, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00300F10, 0x20002B31, 0x000037FF, 0xEFD3FBFF}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x12); EXPECT_EQ(info.model, 0x01); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_K12); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0500F01_K14_Bobcat_CPUID.txt TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F01) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000006, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00500F01, 0x00020800, 0x00802209, 0x178BFBFF}}, {{0x80000000, 0}, Leaf{0x8000001B, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00500F01, 0x00000000, 0x000035FF, 0x2FD3FBFF}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x14); EXPECT_EQ(info.model, 0x00); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_BOBCAT); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0500F10_K14_Bobcat_CPUID.txt TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F10) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000006, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00500F10, 0x00020800, 0x00802209, 0x178BFBFF}}, {{0x00000002, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, {{0x00000003, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, {{0x00000005, 0}, Leaf{0x00000040, 0x00000040, 0x00000003, 0x00000000}}, {{0x00000006, 0}, Leaf{0x00000000, 0x00000000, 0x00000001, 0x00000000}}, {{0x80000000, 0}, Leaf{0x8000001B, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00500F10, 0x00001242, 0x000035FF, 0x2FD3FBFF}}, {{0x80000002, 0}, Leaf{0x20444D41, 0x35332D45, 0x72502030, 0x7365636F}}, {{0x80000003, 0}, Leaf{0x00726F73, 0x00000000, 0x00000000, 0x00000000}}, {{0x80000004, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, {{0x80000005, 0}, Leaf{0xFF08FF08, 0xFF280000, 0x20080140, 0x20020140}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x14); EXPECT_EQ(info.model, 0x01); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_BOBCAT); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0500F20_K14_Bobcat_CPUID.txt TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F20) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000006, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00500F20, 0x00020800, 0x00802209, 0x178BFBFF}}, {{0x80000000, 0}, Leaf{0x8000001B, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00500F20, 0x000012E9, 0x000035FF, 0x2FD3FBFF}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x14); EXPECT_EQ(info.model, 0x02); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_BOBCAT); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0670F00_K15_StoneyRidge_CPUID.txt TEST_F(CpuidX86Test, AMD_K15_EXCAVATOR_STONEY_RIDGE) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00670F00, 0x00020800, 0x7ED8320B, 0x178BFBFF}}, {{0x00000007, 0}, Leaf{0x00000000, 0x000001A9, 0x00000000, 0x00000000}}, {{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00670F00, 0x00000000, 0x2FABBFFF, 0x2FD3FBFF}}, {{0x80000002, 0}, Leaf{0x20444D41, 0x392D3941, 0x20303134, 0x45444152}}, {{0x80000003, 0}, Leaf{0x52204E4F, 0x35202C35, 0x4D4F4320, 0x45545550}}, {{0x80000004, 0}, Leaf{0x524F4320, 0x32205345, 0x47332B43, 0x00202020}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x15); EXPECT_EQ(info.model, 0x70); EXPECT_STREQ(info.brand_string, "AMD A9-9410 RADEON R5, 5 COMPUTE CORES 2C+3G "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_EXCAVATOR); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F20_K15_AbuDhabi_CPUID0.txt TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_ABU_DHABI) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00600F20, 0x00100800, 0x3E98320B, 0x178BFBFF}}, {{0x00000007, 0}, Leaf{0x00000000, 0x00000008, 0x00000000, 0x00000000}}, {{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00600F20, 0x30000000, 0x01EBBFFF, 0x2FD3FBFF}}, {{0x80000002, 0}, Leaf{0x20444D41, 0x6574704F, 0x286E6F72, 0x20296D74}}, {{0x80000003, 0}, Leaf{0x636F7250, 0x6F737365, 0x33362072, 0x20203637}}, {{0x80000004, 0}, Leaf{0x20202020, 0x20202020, 0x20202020, 0x00202020}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x15); EXPECT_EQ(info.model, 0x02); EXPECT_STREQ(info.brand_string, "AMD Opteron(tm) Processor 6376 "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_PILEDRIVER); EXPECT_STREQ(info.brand_string, "AMD Opteron(tm) Processor 6376 "); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F20_K15_AbuDhabi_CPUID0.txt TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_ABU_DHABI_CACHE_INFO) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00600F20, 0x00100800, 0x3E98320B, 0x178BFBFF}}, {{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00600F20, 0x30000000, 0x01EBBFFF, 0x2FD3FBFF}}, {{0x8000001D, 0}, Leaf{0x00000121, 0x00C0003F, 0x0000003F, 0x00000000}}, {{0x8000001D, 1}, Leaf{0x00004122, 0x0040003F, 0x000001FF, 0x00000000}}, {{0x8000001D, 2}, Leaf{0x00004143, 0x03C0003F, 0x000007FF, 0x00000001}}, {{0x8000001D, 3}, Leaf{0x0001C163, 0x0BC0003F, 0x000007FF, 0x00000001}}, }); const auto info = GetX86CacheInfo(); EXPECT_EQ(info.size, 4); EXPECT_EQ(info.levels[0].level, 1); EXPECT_EQ(info.levels[0].cache_type, CacheType::CPU_FEATURE_CACHE_DATA); EXPECT_EQ(info.levels[0].cache_size, 16 * KiB); EXPECT_EQ(info.levels[0].ways, 4); EXPECT_EQ(info.levels[0].line_size, 64); EXPECT_EQ(info.levels[0].tlb_entries, 64); EXPECT_EQ(info.levels[0].partitioning, 1); EXPECT_EQ(info.levels[1].level, 1); EXPECT_EQ(info.levels[1].cache_type, CacheType::CPU_FEATURE_CACHE_INSTRUCTION); EXPECT_EQ(info.levels[1].cache_size, 64 * KiB); EXPECT_EQ(info.levels[1].ways, 2); EXPECT_EQ(info.levels[1].line_size, 64); EXPECT_EQ(info.levels[1].tlb_entries, 512); EXPECT_EQ(info.levels[1].partitioning, 1); EXPECT_EQ(info.levels[2].level, 2); EXPECT_EQ(info.levels[2].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED); EXPECT_EQ(info.levels[2].cache_size, 2 * MiB); EXPECT_EQ(info.levels[2].ways, 16); EXPECT_EQ(info.levels[2].line_size, 64); EXPECT_EQ(info.levels[2].tlb_entries, 2048); EXPECT_EQ(info.levels[2].partitioning, 1); EXPECT_EQ(info.levels[3].level, 3); EXPECT_EQ(info.levels[3].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED); EXPECT_EQ(info.levels[3].cache_size, 6 * MiB); EXPECT_EQ(info.levels[3].ways, 48); EXPECT_EQ(info.levels[3].line_size, 64); EXPECT_EQ(info.levels[3].tlb_entries, 2048); EXPECT_EQ(info.levels[3].partitioning, 1); } // https://github.com/InstLatx64/InstLatx64/blob/master/AuthenticAMD/AuthenticAMD0610F01_K15_Piledriver_CPUID.txt TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_A10) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00610F01, 0x00040800, 0x3E98320B, 0x178BFBFF}}, {{0x00000007, 0}, Leaf{0x00000000, 0x00000008, 0x00000000, 0x00000000}}, {{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00610F01, 0x20000000, 0x01EBBFFF, 0x2FD3FBFF}}, {{0x80000002, 0}, Leaf{0x20444D41, 0x2D303141, 0x30303835, 0x5041204B}}, {{0x80000003, 0}, Leaf{0x69772055, 0x52206874, 0x6F656461, 0x6D74286E}}, {{0x80000004, 0}, Leaf{0x44482029, 0x61724720, 0x63696870, 0x00202073}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x15); EXPECT_EQ(info.model, 0x10); EXPECT_STREQ(info.brand_string, "AMD A10-5800K APU with Radeon(tm) HD Graphics "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_PILEDRIVER); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F12_K15_Interlagos_CPUID3.txt TEST_F(CpuidX86Test, AMD_K15_BULLDOZER_INTERLAGOS) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00600F12, 0x000C0800, 0x1E98220B, 0x178BFBFF}}, {{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, {{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00600F12, 0x30000000, 0x01C9BFFF, 0x2FD3FBFF}}, {{0x80000002, 0}, Leaf{0x20444D41, 0x6574704F, 0x286E6F72, 0x20294D54}}, {{0x80000003, 0}, Leaf{0x636F7250, 0x6F737365, 0x32362072, 0x20203833}}, {{0x80000004, 0}, Leaf{0x20202020, 0x20202020, 0x20202020, 0x00202020}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x15); EXPECT_EQ(info.model, 0x01); EXPECT_STREQ(info.brand_string, "AMD Opteron(TM) Processor 6238 "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_BULLDOZER); } // http://users.atw.hu/instlatx64/AuthenticAMD0630F81_K15_Godavari_CPUID.txt TEST_F(CpuidX86Test, AMD_K15_STREAMROLLER_GODAVARI) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00630F81, 0x00040800, 0x3E98320B, 0x178BFBFF}}, {{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, {{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00630F81, 0x10000000, 0x0FEBBFFF, 0x2FD3FBFF}}, {{0x80000002, 0}, Leaf{0x20444D41, 0x372D3841, 0x4B303736, 0x64615220}}, {{0x80000003, 0}, Leaf{0x206E6F65, 0x202C3752, 0x43203031, 0x75706D6F}}, {{0x80000004, 0}, Leaf{0x43206574, 0x7365726F, 0x2B433420, 0x00204736}}, {{0x80000005, 0}, Leaf{0xFF40FF18, 0xFF40FF30, 0x10040140, 0x60030140}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x15); EXPECT_EQ(info.model, 0x38); EXPECT_EQ(info.stepping, 0x01); EXPECT_STREQ(info.brand_string, "AMD A8-7670K Radeon R7, 10 Compute Cores 4C+6G "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_STREAMROLLER); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F12_K15_Zambezi8C_CPUID.txt TEST_F(CpuidX86Test, AMD_K15_BULLDOZER_ZAMBEZI_ABM) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00600F12, 0x00080800, 0x1E98220B, 0x178BFBFF}}, {{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, {{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00600F12, 0x10000000, 0x01C9BFFF, 0x2FD3FBFF}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x15); EXPECT_EQ(info.model, 0x01); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_BULLDOZER); EXPECT_TRUE(info.features.lzcnt); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0700F01_K16_Kabini_CPUID.txt TEST_F(CpuidX86Test, AMD_K16_JAGUAR_KABINI) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00700F01, 0x00040800, 0x3ED8220B, 0x178BFBFF}}, {{0x00000007, 0}, Leaf{0x00000000, 0x00000008, 0x00000000, 0x00000000}}, {{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00700F01, 0x00000000, 0x154037FF, 0x2FD3FBFF}}, {{0x80000002, 0}, Leaf{0x20444D41, 0x352D3441, 0x20303030, 0x20555041}}, {{0x80000003, 0}, Leaf{0x68746977, 0x64615220, 0x286E6F65, 0x20294D54}}, {{0x80000004, 0}, Leaf{0x47204448, 0x68706172, 0x20736369, 0x00202020}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x16); EXPECT_EQ(info.model, 0x00); EXPECT_STREQ(info.brand_string, "AMD A4-5000 APU with Radeon(TM) HD Graphics "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_JAGUAR); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0730F01_K16_Beema_CPUID2.txt TEST_F(CpuidX86Test, AMD_K16_PUMA_BEEMA) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00730F01, 0x00040800, 0x7ED8220B, 0x178BFBFF}}, {{0x00000007, 0}, Leaf{0x00000000, 0x00000008, 0x00000000, 0x00000000}}, {{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00730F01, 0x00000000, 0x1D4037FF, 0x2FD3FBFF}}, {{0x80000002, 0}, Leaf{0x20444D41, 0x362D3641, 0x20303133, 0x20555041}}, {{0x80000003, 0}, Leaf{0x68746977, 0x444D4120, 0x64615220, 0x206E6F65}}, {{0x80000004, 0}, Leaf{0x47203452, 0x68706172, 0x20736369, 0x00202020}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x16); EXPECT_EQ(info.model, 0x30); EXPECT_STREQ(info.brand_string, "AMD A6-6310 APU with AMD Radeon R4 Graphics "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_PUMA); } // https://github.com/InstLatx64/InstLatx64/blob/master/AuthenticAMD/AuthenticAMD0720F61_K16_Cato_CPUID.txt TEST_F(CpuidX86Test, AMD_K16_CATO) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00720F61, 0x00080800, 0x3ED8220B, 0x178BFBFF}}, {{0x00000007, 0}, Leaf{0x00000000, 0x00000008, 0x00000000, 0x00000000}}, {{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00720F61, 0x00000000, 0x154837FF, 0x2FD3FBFF}}, {{0x80000002, 0}, Leaf{0x20444D41, 0x392D3941, 0x20303238, 0x636F7250}}, {{0x80000003, 0}, Leaf{0x6F737365, 0x00000072, 0x00000000, 0x00000000}}, {{0x80000004, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x16); EXPECT_EQ(info.model, 0x26); EXPECT_STREQ(info.brand_string, "AMD A9-9820 Processor"); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_JAGUAR); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0820F01_K17_Dali_CPUID.txt TEST_F(CpuidX86Test, AMD_K17_ZEN_DALI) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00820F01, 0x00020800, 0x7ED8320B, 0x178BFBFF}}, {{0x00000007, 0}, Leaf{0x00000000, 0x209C01A9, 0x00000000, 0x00000000}}, {{0x80000000, 0}, Leaf{0x8000001F, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00820F01, 0x00000000, 0x35C233FF, 0x2FD3FBFF}}, {{0x80000002, 0}, Leaf{0x20444D41, 0x30323033, 0x69772065, 0x52206874}}, {{0x80000003, 0}, Leaf{0x6F656461, 0x7247206E, 0x69687061, 0x20207363}}, {{0x80000004, 0}, Leaf{0x20202020, 0x20202020, 0x20202020, 0x00202020}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x17); EXPECT_EQ(info.model, 0x20); EXPECT_STREQ(info.brand_string, "AMD 3020e with Radeon Graphics "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0800F82_K17_ZenP_CPUID.txt TEST_F(CpuidX86Test, AMD_K17_ZEN_PLUS_PINNACLE_RIDGE) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00800F82, 0x00100800, 0x7ED8320B, 0x178BFBFF}}, {{0x00000007, 0}, Leaf{0x00000000, 0x209C01A9, 0x00000000, 0x00000000}}, {{0x80000000, 0}, Leaf{0x8000001F, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00800F82, 0x20000000, 0x35C233FF, 0x2FD3FBFF}}, {{0x80000002, 0}, Leaf{0x20444D41, 0x657A7952, 0x2037206E, 0x30303732}}, {{0x80000003, 0}, Leaf{0x69452058, 0x2D746867, 0x65726F43, 0x6F725020}}, {{0x80000004, 0}, Leaf{0x73736563, 0x2020726F, 0x20202020, 0x00202020}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x17); EXPECT_EQ(info.model, 0x08); EXPECT_STREQ(info.brand_string, "AMD Ryzen 7 2700X Eight-Core Processor "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN_PLUS); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0840F70_K17_CPUID.txt TEST_F(CpuidX86Test, AMD_K17_ZEN2_XBOX_SERIES_X) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000010, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00840F70, 0x00100800, 0x7ED8320B, 0x178BFBFF}}, {{0x00000007, 0}, Leaf{0x00000000, 0x219C91A9, 0x00400004, 0x00000000}}, {{0x80000000, 0}, Leaf{0x80000020, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00840F70, 0x00000000, 0xF5C2B7FF, 0x2FD3FBFF}}, {{0x80000002, 0}, Leaf{0x20444D41, 0x30303734, 0x2D382053, 0x65726F43}}, {{0x80000003, 0}, Leaf{0x6F725020, 0x73736563, 0x4420726F, 0x746B7365}}, {{0x80000004, 0}, Leaf{0x4B20706F, 0x00007469, 0x00000000, 0x00000000}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x17); EXPECT_EQ(info.model, 0x47); EXPECT_STREQ(info.brand_string, "AMD 4700S 8-Core Processor Desktop Kit"); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN2); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0880F40_K17_CPUID.txt TEST_F(CpuidX86Test, AMD_K17_ZEN2_4800S) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000010, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00880F40, 0x00100800, 0x7ED8320B, 0x178BFBFF}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x17); EXPECT_EQ(info.model, 0x84); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN2); } // http://users.atw.hu/instlatx64/HygonGenuine/HygonGenuine0900F02_Hygon_CPUID3.txt TEST_F(CpuidX86Test, AMD_K18_ZEN_DHYANA) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000000D, 0x6F677948, 0x656E6975, 0x6E65476E}}, {{0x00000001, 0}, Leaf{0x00900F02, 0x00100800, 0x74D83209, 0x178BFBFF}}, {{0x00000007, 0}, Leaf{0x00000000, 0x009C01A9, 0x0040068C, 0x00000000}}, {{0x80000000, 0}, Leaf{0x8000001F, 0x6F677948, 0x656E6975, 0x6E65476E}}, {{0x80000001, 0}, Leaf{0x00900F02, 0x60000000, 0x35C233FF, 0x2FD3FBFF}}, {{0x80000002, 0}, Leaf{0x6F677948, 0x3843206E, 0x31332036, 0x20203538}}, {{0x80000003, 0}, Leaf{0x6F632D38, 0x50206572, 0x65636F72, 0x726F7373}}, {{0x80000004, 0}, Leaf{0x20202020, 0x20202020, 0x20202020, 0x00202020}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_HYGON_GENUINE); EXPECT_EQ(info.family, 0x18); EXPECT_EQ(info.model, 0x00); EXPECT_STREQ(info.brand_string, "Hygon C86 3185 8-core Processor "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN); } // http://users.atw.hu/instlatx64/HygonGenuine/HygonGenuine0900F02_Hygon_CPUID.txt TEST_F(CpuidX86Test, AMD_K18_ZEN_DHYANA_CACHE_INFO) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000000D, 0x6F677948, 0x656E6975, 0x6E65476E}}, {{0x00000001, 0}, Leaf{0x00900F02, 0x00100800, 0x74D83209, 0x178BFBFF}}, {{0x80000000, 0}, Leaf{0x8000001F, 0x6F677948, 0x656E6975, 0x6E65476E}}, {{0x80000001, 0}, Leaf{0x00900F02, 0x60000000, 0x35C233FF, 0x2FD3FBFF}}, {{0x8000001D, 0}, Leaf{0x00004121, 0x01C0003F, 0x0000003F, 0x00000000}}, {{0x8000001D, 1}, Leaf{0x00004122, 0x00C0003F, 0x000000FF, 0x00000000}}, {{0x8000001D, 2}, Leaf{0x00004143, 0x01C0003F, 0x000003FF, 0x00000002}}, {{0x8000001D, 3}, Leaf{0x0001C163, 0x03C0003F, 0x00001FFF, 0x00000001}}, }); const auto info = GetX86CacheInfo(); EXPECT_EQ(info.size, 4); EXPECT_EQ(info.levels[0].level, 1); EXPECT_EQ(info.levels[0].cache_type, CacheType::CPU_FEATURE_CACHE_DATA); EXPECT_EQ(info.levels[0].cache_size, 32 * KiB); EXPECT_EQ(info.levels[0].ways, 8); EXPECT_EQ(info.levels[0].line_size, 64); EXPECT_EQ(info.levels[0].tlb_entries, 64); EXPECT_EQ(info.levels[0].partitioning, 1); EXPECT_EQ(info.levels[1].level, 1); EXPECT_EQ(info.levels[1].cache_type, CacheType::CPU_FEATURE_CACHE_INSTRUCTION); EXPECT_EQ(info.levels[1].cache_size, 64 * KiB); EXPECT_EQ(info.levels[1].ways, 4); EXPECT_EQ(info.levels[1].line_size, 64); EXPECT_EQ(info.levels[1].tlb_entries, 256); EXPECT_EQ(info.levels[1].partitioning, 1); EXPECT_EQ(info.levels[2].level, 2); EXPECT_EQ(info.levels[2].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED); EXPECT_EQ(info.levels[2].cache_size, 512 * KiB); EXPECT_EQ(info.levels[2].ways, 8); EXPECT_EQ(info.levels[2].line_size, 64); EXPECT_EQ(info.levels[2].tlb_entries, 1024); EXPECT_EQ(info.levels[2].partitioning, 1); EXPECT_EQ(info.levels[3].level, 3); EXPECT_EQ(info.levels[3].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED); EXPECT_EQ(info.levels[3].cache_size, 8 * MiB); EXPECT_EQ(info.levels[3].ways, 16); EXPECT_EQ(info.levels[3].line_size, 64); EXPECT_EQ(info.levels[3].tlb_entries, 8192); EXPECT_EQ(info.levels[3].partitioning, 1); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0A20F10_K19_Vermeer2_CPUID.txt TEST_F(CpuidX86Test, AMD_K19_ZEN3_VERMEER) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000010, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00A20F10, 0x01180800, 0x7ED8320B, 0x178BFBFF}}, {{0x00000007, 0}, Leaf{0x00000000, 0x219C97A9, 0x0040068C, 0x00000000}}, {{0x80000000, 0}, Leaf{0x80000023, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00A20F10, 0x20000000, 0x75C237FF, 0x2FD3FBFF}}, {{0x80000002, 0}, Leaf{0x20444D41, 0x657A7952, 0x2039206E, 0x30303935}}, {{0x80000003, 0}, Leaf{0x32312058, 0x726F432D, 0x72502065, 0x7365636F}}, {{0x80000004, 0}, Leaf{0x20726F73, 0x20202020, 0x20202020, 0x00202020}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x19); EXPECT_EQ(info.model, 0x21); EXPECT_STREQ(info.brand_string, "AMD Ryzen 9 5900X 12-Core Processor "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN3); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0A40F41_K19_Rembrandt_03_CPUID.txt TEST_F(CpuidX86Test, AMD_K19_ZEN3) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000010, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00A40F41, 0x00100800, 0x7EF8320B, 0x178BFBFF}}, {{0x80000000, 0}, Leaf{0x80000023, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00A40F41, 0x50000000, 0x75C237FF, 0x2FD3FBFF}}, {{0x80000002, 0}, Leaf{0x20444D41, 0x657A7952, 0x2039206E, 0x30303936}}, {{0x80000003, 0}, Leaf{0x77205848, 0x20687469, 0x65646152, 0x47206E6F}}, {{0x80000004, 0}, Leaf{0x68706172, 0x20736369, 0x20202020, 0x00202020}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x19); EXPECT_EQ(info.model, 0x44); EXPECT_STREQ(info.brand_string, "AMD Ryzen 9 6900HX with Radeon Graphics "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN3); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0A60F12_K19_Raphael_01_CPUID.txt TEST_F(CpuidX86Test, AMD_K19_ZEN4_RAPHAEL) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000010, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00A60F12, 0x000C0800, 0x7EF8320B, 0x178BFBFF}}, {{0x80000000, 0}, Leaf{0x80000028, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00A60F12, 0x00000000, 0x75C237FF, 0x2FD3FBFF}}, {{0x80000002, 0}, Leaf{0x20444D41, 0x657A7952, 0x2035206E, 0x30303637}}, {{0x80000003, 0}, Leaf{0x2D362058, 0x65726F43, 0x6F725020, 0x73736563}}, {{0x80000004, 0}, Leaf{0x2020726F, 0x20202020, 0x20202020, 0x00202020}}, {{0x80000021, 0}, Leaf{0x00062FCF, 0x0000015C, 0x00000000, 0x00000000}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x19); EXPECT_EQ(info.model, 0x61); EXPECT_STREQ(info.brand_string, "AMD Ryzen 5 7600X 6-Core Processor "); EXPECT_TRUE(info.features.uai); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN4); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0A70F41_K19_Phoenix_03_CPUID.txt TEST_F(CpuidX86Test, AMD_K19_ZEN4_PHOENIX) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000010, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00A70F41, 0x00100800, 0x7EF8320B, 0x178BFBFF}}, {{0x80000000, 0}, Leaf{0x80000028, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00A70F41, 0x50000000, 0x75C237FF, 0x2FD3FBFF}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x19); EXPECT_EQ(info.model, 0x74); } // http://users.atw.hu/instlatx64/HygonGenuine/HygonGenuine0900F11_Hygon_01_CPUID.txt TEST_F(CpuidX86Test, AMD_K18_ZEN_DHYANA_OCTAL_CORE_C86_3250) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000000D, 0x6F677948, 0x656E6975, 0x6E65476E}}, {{0x00000001, 0}, Leaf{0x00900F11, 0x00100800, 0x76D8320B, 0x178BFBFF}}, {{0x80000000, 0}, Leaf{0x8000001F, 0x6F677948, 0x656E6975, 0x6E65476E}}, {{0x80000001, 0}, Leaf{0x00900F11, 0x60000000, 0x35C233FF, 0x2FD3FBFF}}, {{0x80000002, 0}, Leaf{0x6F677948, 0x3843206E, 0x32332036, 0x20203035}}, {{0x80000003, 0}, Leaf{0x6F632D38, 0x50206572, 0x65636F72, 0x726F7373}}, {{0x80000004, 0}, Leaf{0x20202020, 0x20202020, 0x20202020, 0x00202020}}, }); const auto info = GetX86Info(); EXPECT_EQ(info.model, 0x01); EXPECT_EQ(info.family, 0x18); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_HYGON_GENUINE); EXPECT_STREQ(info.brand_string, "Hygon C86 3250 8-core Processor "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD08A0F00_K17_Mendocino_01_CPUID.txt TEST_F(CpuidX86Test, AMD_ZEN2_MENDOCINO) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000010, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x008A0F00, 0x00080800, 0x7EF8320B, 0x178BFBFF}}, }); const auto info = GetX86Info(); EXPECT_EQ(info.model, 0xA0); EXPECT_EQ(info.family, 0x17); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN2); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0A10F11_K19_Genoa_02_CPUID.txt TEST_F(CpuidX86Test, AMD_K19_ZEN4_GENOA) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000010, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x00000001, 0}, Leaf{0x00A10F11, 0x00200800, 0x7EFA320B, 0x178BFBFF}}, }); const auto info = GetX86Info(); EXPECT_EQ(info.model, 0x11); EXPECT_EQ(info.family, 0x19); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN4); } // http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00906A4_AlderLakeP_00_CPUID.txt TEST_F(CpuidX86Test, INTEL_ALDER_LAKE_AVX_VNNI) { cpu().SetOsBackupsExtendedRegisters(true); cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000020, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000906A4, 0x00400800, 0x7FFAFBBF, 0xBFEBFBFF}}, {{0x00000007, 0}, Leaf{0x00000001, 0x239CA7EB, 0x984007AC, 0xFC18C410}}, {{0x00000007, 1}, Leaf{0x00400810, 0x00000000, 0x00000000, 0x00000000}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x9A); EXPECT_TRUE(info.features.avx_vnni); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_ADL); } // https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0090672_AlderLake_BC_AVX512_CPUID01.txt TEST_F(CpuidX86Test, INTEL_ALDER_LAKE_AVX512) { cpu().SetOsBackupsExtendedRegisters(true); #if defined(CPU_FEATURES_OS_MACOS) cpu().SetDarwinSysCtlByName("hw.optional.avx512f"); #endif cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000020, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000906A4, 0x00400800, 0x7FFAFBBF, 0xBFEBFBFF}}, {{0x00000007, 0}, Leaf{0x00000001, 0xF3BFA7EB, 0x98C07FEE, 0xFC9CC510}}, {{0x00000007, 1}, Leaf{0x00401C30, 0x00000000, 0x00000000, 0x00000000}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x9A); EXPECT_TRUE(info.features.avx512f); EXPECT_TRUE(info.features.avx512bw); EXPECT_TRUE(info.features.avx512dq); EXPECT_TRUE(info.features.avx512cd); EXPECT_TRUE(info.features.avx512vl); EXPECT_TRUE(info.features.avx512_vp2intersect); EXPECT_TRUE(info.features.avx512vbmi); EXPECT_TRUE(info.features.avx512vbmi2); EXPECT_TRUE(info.features.avx512bitalg); EXPECT_TRUE(info.features.avx512vpopcntdq); EXPECT_TRUE(info.features.avx512ifma); EXPECT_TRUE(info.features.avx512_bf16); EXPECT_TRUE(info.features.avx512_fp16); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_ADL); } // https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel00806C1_TigerLake_CPUID3.txt TEST_F(CpuidX86Test, INTEL_TIGER_LAKE_AVX512) { cpu().SetOsBackupsExtendedRegisters(true); #if defined(CPU_FEATURES_OS_MACOS) cpu().SetDarwinSysCtlByName("hw.optional.avx512f"); #endif cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000001B, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000806C1, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}}, {{0x00000007, 0}, Leaf{0x00000000, 0xF3BFA7EB, 0x18C05FCE, 0xFC100510}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x8C); EXPECT_TRUE(info.features.avx512f); EXPECT_TRUE(info.features.avx512bw); EXPECT_TRUE(info.features.avx512dq); EXPECT_TRUE(info.features.avx512cd); EXPECT_TRUE(info.features.avx512vl); EXPECT_TRUE(info.features.avx512_vp2intersect); EXPECT_TRUE(info.features.avx512vbmi); EXPECT_TRUE(info.features.avx512vbmi2); EXPECT_TRUE(info.features.avx512bitalg); EXPECT_TRUE(info.features.avx512vpopcntdq); EXPECT_TRUE(info.features.avx512ifma); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_TGL); } // http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00706E5_IceLakeY_CPUID.txt TEST_F(CpuidX86Test, INTEL_ICE_LAKE_GFNI) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000001B, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000706E5, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}}, {{0x00000007, 0}, Leaf{0x00000000, 0xF2BF27EF, 0x40405F4E, 0xBC000410}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x7E); EXPECT_TRUE(info.features.gfni); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_ICL); } // http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00906C0_JasperLake_CPUID01.txt TEST_F(CpuidX86Test, INTEL_TREMONT_JASPER_LAKE_MOVDR) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000001B, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x00090661, 0x00800800, 0x4FF8EBBF, 0xBFEBFBFF}}, {{0x00000007, 0}, Leaf{0x00000000, 0x2394A2C3, 0x18400124, 0xFC000400}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x96); EXPECT_TRUE(info.features.movdiri); EXPECT_TRUE(info.features.movdir64b); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_ATOM_TMT); } // http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel0090672_AlderLake_LC_BC_CPUID01.txt TEST_F(CpuidX86Test, INTEL_ALDER_LAKE_REP) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000020, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x00090672, 0x00800800, 0x7FFAFBFF, 0xBFEBFBFF}}, {{0x00000007, 0}, Leaf{0x00000001, 0x239CA7EB, 0x98C027AC, 0xFC1CC410}}, {{0x00000007, 1}, Leaf{0x00400810, 0x00000000, 0x00000000, 0x00000000}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x97); EXPECT_TRUE(info.features.erms); EXPECT_TRUE(info.features.fs_rep_mov); EXPECT_FALSE(info.features.fz_rep_movsb); EXPECT_TRUE(info.features.fs_rep_stosb); EXPECT_FALSE(info.features.fs_rep_cmpsb_scasb); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_ADL); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0100FA0_K10_Thuban_CPUID.txt TEST_F(CpuidX86Test, AMD_THUBAN_CACHE_INFO) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000006, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000000, 0}, Leaf{0x8000001B, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00100FA0, 0x10000050, 0x000037FF, 0xEFD3FBFF}}, {{0x80000005, 0}, Leaf{0xFF30FF10, 0xFF30FF20, 0x40020140, 0x40020140}}, {{0x80000006, 0}, Leaf{0x20800000, 0x42004200, 0x02008140, 0x0030B140}}, }); const auto info = GetX86CacheInfo(); EXPECT_EQ(info.size, 4); EXPECT_EQ(info.levels[0].level, 1); EXPECT_EQ(info.levels[0].cache_type, CacheType::CPU_FEATURE_CACHE_DATA); EXPECT_EQ(info.levels[0].cache_size, 64 * KiB); EXPECT_EQ(info.levels[0].ways, 2); EXPECT_EQ(info.levels[0].line_size, 64); EXPECT_EQ(info.levels[1].level, 1); EXPECT_EQ(info.levels[1].cache_type, CacheType::CPU_FEATURE_CACHE_INSTRUCTION); EXPECT_EQ(info.levels[1].cache_size, 64 * KiB); EXPECT_EQ(info.levels[1].ways, 2); EXPECT_EQ(info.levels[1].line_size, 64); EXPECT_EQ(info.levels[2].level, 2); EXPECT_EQ(info.levels[2].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED); EXPECT_EQ(info.levels[2].cache_size, 512 * KiB); EXPECT_EQ(info.levels[2].ways, 16); EXPECT_EQ(info.levels[2].line_size, 64); EXPECT_EQ(info.levels[3].level, 3); EXPECT_EQ(info.levels[3].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED); EXPECT_EQ(info.levels[3].cache_size, 6 * MiB); EXPECT_EQ(info.levels[3].ways, 48); EXPECT_EQ(info.levels[3].line_size, 64); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0020FB1_K8_Manchester_CPUID.txt TEST_F(CpuidX86Test, AMD_MANCHESTER_CACHE_INFO) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000001, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000000, 0}, Leaf{0x80000018, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00020FB1, 0x00000150, 0x00000003, 0xE3D3FBFF}}, {{0x80000005, 0}, Leaf{0xFF08FF08, 0xFF20FF20, 0x40020140, 0x40020140}}, {{0x80000006, 0}, Leaf{0x00000000, 0x42004200, 0x02008140, 0x00000000}}, }); const auto info = GetX86CacheInfo(); EXPECT_EQ(info.size, 3); EXPECT_EQ(info.levels[0].level, 1); EXPECT_EQ(info.levels[0].cache_type, CacheType::CPU_FEATURE_CACHE_DATA); EXPECT_EQ(info.levels[0].cache_size, 64 * KiB); EXPECT_EQ(info.levels[0].ways, 2); EXPECT_EQ(info.levels[0].line_size, 64); EXPECT_EQ(info.levels[1].level, 1); EXPECT_EQ(info.levels[1].cache_type, CacheType::CPU_FEATURE_CACHE_INSTRUCTION); EXPECT_EQ(info.levels[1].cache_size, 64 * KiB); EXPECT_EQ(info.levels[1].ways, 2); EXPECT_EQ(info.levels[1].line_size, 64); EXPECT_EQ(info.levels[2].level, 2); EXPECT_EQ(info.levels[2].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED); EXPECT_EQ(info.levels[2].cache_size, 512 * KiB); EXPECT_EQ(info.levels[2].ways, 16); EXPECT_EQ(info.levels[2].line_size, 64); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0100F22_K10_Agena_CPUID.txt TEST_F(CpuidX86Test, AMD_AGENA_CACHE_INFO) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000005, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000000, 0}, Leaf{0x8000001A, 0x68747541, 0x444D4163, 0x69746E65}}, {{0x80000001, 0}, Leaf{0x00100F22, 0x10000000, 0x000007FF, 0xEFD3FBFF}}, {{0x80000005, 0}, Leaf{0xFF30FF10, 0xFF30FF20, 0x40020140, 0x40020140}}, {{0x80000006, 0}, Leaf{0x20800000, 0x42004200, 0x02008140, 0x0010A140}}, }); const auto info = GetX86CacheInfo(); EXPECT_EQ(info.size, 4); EXPECT_EQ(info.levels[0].level, 1); EXPECT_EQ(info.levels[0].cache_type, CacheType::CPU_FEATURE_CACHE_DATA); EXPECT_EQ(info.levels[0].cache_size, 64 * KiB); EXPECT_EQ(info.levels[0].ways, 2); EXPECT_EQ(info.levels[0].line_size, 64); EXPECT_EQ(info.levels[1].level, 1); EXPECT_EQ(info.levels[1].cache_type, CacheType::CPU_FEATURE_CACHE_INSTRUCTION); EXPECT_EQ(info.levels[1].cache_size, 64 * KiB); EXPECT_EQ(info.levels[1].ways, 2); EXPECT_EQ(info.levels[1].line_size, 64); EXPECT_EQ(info.levels[2].level, 2); EXPECT_EQ(info.levels[2].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED); EXPECT_EQ(info.levels[2].cache_size, 512 * KiB); EXPECT_EQ(info.levels[2].ways, 16); EXPECT_EQ(info.levels[2].line_size, 64); EXPECT_EQ(info.levels[3].level, 3); EXPECT_EQ(info.levels[3].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED); EXPECT_EQ(info.levels[3].cache_size, 2 * MiB); EXPECT_EQ(info.levels[3].ways, 32); EXPECT_EQ(info.levels[3].line_size, 64); } // https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel00106A1_Nehalem_CPUID.txt TEST_F(CpuidX86Test, Nehalem) { // Pre AVX cpus don't have xsave cpu().SetOsBackupsExtendedRegisters(false); #if defined(CPU_FEATURES_OS_WINDOWS) cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE); cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE); cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE); cpu().SetWindowsIsProcessorFeaturePresent(PF_SSSE3_INSTRUCTIONS_AVAILABLE); cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE4_1_INSTRUCTIONS_AVAILABLE); cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE4_2_INSTRUCTIONS_AVAILABLE); #elif defined(CPU_FEATURES_OS_MACOS) cpu().SetDarwinSysCtlByName("hw.optional.sse"); cpu().SetDarwinSysCtlByName("hw.optional.sse2"); cpu().SetDarwinSysCtlByName("hw.optional.sse3"); cpu().SetDarwinSysCtlByName("hw.optional.supplementalsse3"); cpu().SetDarwinSysCtlByName("hw.optional.sse4_1"); cpu().SetDarwinSysCtlByName("hw.optional.sse4_2"); #elif defined(CPU_FEATURES_OS_FREEBSD) auto& fs = GetEmptyFilesystem(); fs.CreateFile("/var/run/dmesg.boot", R"( ---<>--- Copyright (c) 1992-2020 The FreeBSD Project. FreeBSD is a registered trademark of The FreeBSD Foundation. Features=0x1783fbff Features2=0x5eda2203 real memory = 2147418112 (2047 MB) )"); #elif defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID) auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"(processor : flags : fpu mmx sse sse2 pni ssse3 sse4_1 sse4_2 )"); #endif 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, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x1A); EXPECT_EQ(info.stepping, 0x02); EXPECT_STREQ(info.brand_string, "Genuine Intel(R) CPU @ 0000 @ 1.87GHz"); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_NHM); EXPECT_TRUE(info.features.sse); EXPECT_TRUE(info.features.sse2); EXPECT_TRUE(info.features.sse3); EXPECT_TRUE(info.features.ssse3); EXPECT_TRUE(info.features.sse4_1); EXPECT_TRUE(info.features.sse4_2); } // https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0030673_Silvermont3_CPUID.txt TEST_F(CpuidX86Test, Atom) { // Pre AVX cpus don't have xsave cpu().SetOsBackupsExtendedRegisters(false); #if defined(CPU_FEATURES_OS_WINDOWS) cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE); cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE); cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE); cpu().SetWindowsIsProcessorFeaturePresent(PF_SSSE3_INSTRUCTIONS_AVAILABLE); cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE4_1_INSTRUCTIONS_AVAILABLE); cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE4_2_INSTRUCTIONS_AVAILABLE); #elif defined(CPU_FEATURES_OS_MACOS) cpu().SetDarwinSysCtlByName("hw.optional.sse"); cpu().SetDarwinSysCtlByName("hw.optional.sse2"); cpu().SetDarwinSysCtlByName("hw.optional.sse3"); cpu().SetDarwinSysCtlByName("hw.optional.supplementalsse3"); cpu().SetDarwinSysCtlByName("hw.optional.sse4_1"); cpu().SetDarwinSysCtlByName("hw.optional.sse4_2"); #elif defined(CPU_FEATURES_OS_FREEBSD) auto& fs = GetEmptyFilesystem(); fs.CreateFile("/var/run/dmesg.boot", R"( ---<>--- Copyright (c) 1992-2020 The FreeBSD Project. FreeBSD is a registered trademark of The FreeBSD Foundation. Features=0x1783fbff Features2=0x5eda2203 real memory = 2147418112 (2047 MB) )"); #elif defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID) auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"( flags : fpu mmx sse sse2 pni ssse3 sse4_1 sse4_2 )"); #endif 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, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x37); EXPECT_EQ(info.stepping, 0x03); EXPECT_STREQ(info.brand_string, " Intel(R) Celeron(R) CPU J1900 @ 1.99GHz"); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_ATOM_SMT); EXPECT_TRUE(info.features.sse); EXPECT_TRUE(info.features.sse2); EXPECT_TRUE(info.features.sse3); EXPECT_TRUE(info.features.ssse3); EXPECT_TRUE(info.features.sse4_1); EXPECT_TRUE(info.features.sse4_2); } // https://www.felixcloutier.com/x86/cpuid#example-3-1--example-of-cache-and-tlb-interpretation TEST_F(CpuidX86Test, P4_CacheInfo) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000002, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x00000F0A, 0x00010808, 0x00000000, 0x3FEBFBFF}}, {{0x00000002, 0}, Leaf{0x665B5001, 0x00000000, 0x00000000, 0x007A7000}}, }); const auto info = GetX86CacheInfo(); EXPECT_EQ(info.size, 5); EXPECT_EQ(info.levels[0].level, UNDEF); EXPECT_EQ(info.levels[0].cache_type, CacheType::CPU_FEATURE_CACHE_TLB); EXPECT_EQ(info.levels[0].cache_size, 4 * KiB); EXPECT_EQ(info.levels[0].ways, UNDEF); EXPECT_EQ(info.levels[0].line_size, UNDEF); EXPECT_EQ(info.levels[0].tlb_entries, 64); EXPECT_EQ(info.levels[0].partitioning, 0); EXPECT_EQ(info.levels[1].level, UNDEF); EXPECT_EQ(info.levels[1].cache_type, CacheType::CPU_FEATURE_CACHE_TLB); EXPECT_EQ(info.levels[1].cache_size, 4 * KiB); EXPECT_EQ(info.levels[1].ways, UNDEF); EXPECT_EQ(info.levels[1].line_size, UNDEF); EXPECT_EQ(info.levels[1].tlb_entries, 64); EXPECT_EQ(info.levels[1].partitioning, 0); EXPECT_EQ(info.levels[2].level, 1); EXPECT_EQ(info.levels[2].cache_type, CacheType::CPU_FEATURE_CACHE_DATA); EXPECT_EQ(info.levels[2].cache_size, 8 * KiB); EXPECT_EQ(info.levels[2].ways, 4); EXPECT_EQ(info.levels[2].line_size, 64); EXPECT_EQ(info.levels[2].tlb_entries, UNDEF); EXPECT_EQ(info.levels[2].partitioning, 0); EXPECT_EQ(info.levels[3].level, 1); EXPECT_EQ(info.levels[3].cache_type, CacheType::CPU_FEATURE_CACHE_INSTRUCTION); EXPECT_EQ(info.levels[3].cache_size, 12 * KiB); EXPECT_EQ(info.levels[3].ways, 8); EXPECT_EQ(info.levels[3].line_size, UNDEF); EXPECT_EQ(info.levels[3].tlb_entries, UNDEF); EXPECT_EQ(info.levels[3].partitioning, 0); EXPECT_EQ(info.levels[4].level, 2); EXPECT_EQ(info.levels[4].cache_type, CacheType::CPU_FEATURE_CACHE_DATA); EXPECT_EQ(info.levels[4].cache_size, 256 * KiB); EXPECT_EQ(info.levels[4].ways, 8); EXPECT_EQ(info.levels[4].line_size, 64); EXPECT_EQ(info.levels[4].tlb_entries, UNDEF); EXPECT_EQ(info.levels[4].partitioning, 2); } // https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0000673_P3_KatmaiDP_CPUID.txt TEST_F(CpuidX86Test, P3) { // Pre AVX cpus don't have xsave cpu().SetOsBackupsExtendedRegisters(false); #if defined(CPU_FEATURES_OS_WINDOWS) cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE); #elif defined(CPU_FEATURES_OS_MACOS) cpu().SetDarwinSysCtlByName("hw.optional.sse"); #elif defined(CPU_FEATURES_OS_FREEBSD) auto& fs = GetEmptyFilesystem(); fs.CreateFile("/var/run/dmesg.boot", R"( ---<>--- Copyright (c) 1992-2020 The FreeBSD Project. FreeBSD is a registered trademark of The FreeBSD Foundation. Features=0x1783fbff real memory = 2147418112 (2047 MB) )"); #elif defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID) auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", R"( flags : fpu mmx sse )"); #endif 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, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x07); EXPECT_EQ(info.stepping, 0x03); EXPECT_STREQ(info.brand_string, ""); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::X86_UNKNOWN); EXPECT_TRUE(info.features.mmx); EXPECT_TRUE(info.features.sse); EXPECT_FALSE(info.features.sse2); EXPECT_FALSE(info.features.sse3); EXPECT_FALSE(info.features.ssse3); EXPECT_FALSE(info.features.sse4_1); EXPECT_FALSE(info.features.sse4_2); } // https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0000480_486_CPUID.txt TEST_F(CpuidX86Test, INTEL_80486) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000001, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x00000480, 0x00000000, 0x00000000, 0x00000003}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x04); EXPECT_EQ(info.model, 0x08); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_80486); } // https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0000526_P54C_CPUID.txt TEST_F(CpuidX86Test, INTEL_P54C) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000001, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x00000525, 0x00000000, 0x00000000, 0x000001BF}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x05); EXPECT_EQ(info.model, 0x02); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_P5); } // https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0000590_Lakemont_CPUID2.txt TEST_F(CpuidX86Test, INTEL_LAKEMONT) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000002, 0x756E6547, 0x6c65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x00000590, 0x00000000, 0x00010200, 0x8000237B}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x05); EXPECT_EQ(info.model, 0x09); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_LAKEMONT); } // https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel00006E8_PM_Yonah_CPUID.txt TEST_F(CpuidX86Test, INTEL_CORE_YONAH) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000000A, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000006E8, 0x00010800, 0x0000C109, 0xAFE9FBFF}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x0E); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_CORE); } // https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel00706A8_GoldmontPlus_CPUID.txt TEST_F(CpuidX86Test, INTEL_GOLDMONT_PLUS) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000018, 0x756E6547, 0x6c65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000706A8, 0x00400800, 0x4FF8EBBF, 0xBFEBFBFF}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x7A); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_ATOM_GMT_PLUS); } // https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0050670_KnightsLanding_CPUID.txt TEST_F(CpuidX86Test, INTEL_KNIGHTS_LANDING) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x00050670, 0x02FF0800, 0x7FF8F3BF, 0xBFEBFBFF}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x57); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_KNIGHTS_L); } // http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00806EC_CometLake_CPUID2.txt TEST_F(CpuidX86Test, INTEL_CML_U) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000806EC, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x8E); EXPECT_EQ(info.stepping, 0x0C); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_CML); } // http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00A0652_CometLake_CPUID1.txt TEST_F(CpuidX86Test, INTEL_CML_H) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000A0652, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0xA5); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_CML); } // https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel00A0660_CometLake_CPUID1.txt TEST_F(CpuidX86Test, INTEL_CML_U2) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000A0660, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0xA6); EXPECT_EQ(info.stepping, 0x00); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_CML); } // http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00806A1_Lakefield_CPUID.txt TEST_F(CpuidX86Test, INTEL_ATOM_TMT_LAKEFIELD) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000001B, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000806A1, 0x00100800, 0x4FD8EBBF, 0xBFEBFBFF}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x8A); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_ATOM_TMT); } // https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0090661_ElkhartLake_CPUID01.txt TEST_F(CpuidX86Test, INTEL_ATOM_TMT_ELKHART_LAKE) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000001B, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x00090661, 0x00800800, 0x4FF8EBBF, 0xBFEBFBFF}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x96); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_ATOM_TMT); } // https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel00906C0_JasperLake_01_CPUID.txt TEST_F(CpuidX86Test, INTEL_ATOM_TMT_JASPER_LAKE) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000001B, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000906C0, 0x00800800, 0x4FF8EBBF, 0xBFEBFBFF}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x9C); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_ATOM_TMT); } // http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00B0671_RaptorLake_02_CPUID.txt TEST_F(CpuidX86Test, INTEL_RAPTOR_LAKE) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000020, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000B0671, 0x00800800, 0x7FFAFBBF, 0xBFEBFBFF}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0xB7); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_RPL); } // http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00306F2_HaswellEP2_CPUID.txt TEST_F(CpuidX86Test, INTEL_HASWELL_LZCNT) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000000F, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000306F2, 0x00200800, 0x7FFEFBFF, 0xBFEBFBFF}}, {{0x00000007, 0}, Leaf{0x00000000, 0x000037AB, 0x00000000, 0x00000000}}, {{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}}, {{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000021, 0x2C100000}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x3F); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_HSW); EXPECT_TRUE(info.features.lzcnt); } // http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00B06A2_RaptorLakeP_03_CPUID.txt TEST_F(CpuidX86Test, INTEL_RAPTOR_LAKE_P) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000020, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000B06A3, 0x00400800, 0x7FFAFBFF, 0xBFEBFBFF}}, {{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}}, {{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0xBA); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_RPL); } // http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00B06F2_RaptorLakeS_02_CPUID.txt TEST_F(CpuidX86Test, INTEL_RAPTOR_LAKE_S) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000020, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000B06F2, 0x00800800, 0x7FFAFBFF, 0xBFEBFBFF}}, {{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}}, {{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0xBF); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_RPL); } // http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00B06E0_AlderLakeN_03_CPUID.txt TEST_F(CpuidX86Test, INTEL_ALDER_LAKE_N) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000020, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000B06E0, 0x00800800, 0x7FFAFBBF, 0xBFEBFBFF}}, }); const auto info = GetX86Info(); EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0xBE); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_ADL); } // https://github.com/google/cpu_features/issues/200 // http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00206F2_Eagleton_CPUID.txt #if defined(CPU_FEATURES_OS_WINDOWS) TEST_F(CpuidX86Test, WIN_INTEL_WESTMERE_EX) { // Pre AVX cpus don't have xsave cpu().SetOsBackupsExtendedRegisters(false); cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE); cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE); cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE); cpu().SetWindowsIsProcessorFeaturePresent(PF_SSSE3_INSTRUCTIONS_AVAILABLE); cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE4_1_INSTRUCTIONS_AVAILABLE); cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE4_2_INSTRUCTIONS_AVAILABLE); cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}}, {{0x00000001, 0}, Leaf{0x000206F2, 0x00400800, 0x02BEE3FF, 0xBFEBFBFF}}, }); const auto info = GetX86Info(); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x2F); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_WSM); EXPECT_TRUE(info.features.sse); EXPECT_TRUE(info.features.sse2); EXPECT_TRUE(info.features.sse3); EXPECT_TRUE(info.features.ssse3); EXPECT_TRUE(info.features.sse4_1); EXPECT_TRUE(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. } // namespace } // namespace cpu_features cpu-features-0.9.0/test/filesystem_for_testing.cc000066400000000000000000000056361450057454500222230ustar00rootroot00000000000000// 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. // 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 "filesystem_for_testing.h" #include #include #include #include #include namespace cpu_features { FakeFile::FakeFile(int file_descriptor, const char* content) : file_descriptor_(file_descriptor), content_(content) {} FakeFile::~FakeFile() { assert(!opened_); } void FakeFile::Open() { assert(!opened_); opened_ = true; } void FakeFile::Close() { assert(opened_); opened_ = false; } int FakeFile::Read(int fd, void* buf, size_t count) { assert(count < INT_MAX); assert(fd == file_descriptor_); const size_t remainder = content_.size() - head_index_; const size_t read = count > remainder ? remainder : count; memcpy(buf, content_.data() + head_index_, read); head_index_ += read; assert(read < INT_MAX); return (int)read; } void FakeFilesystem::Reset() { files_.clear(); } FakeFile* FakeFilesystem::CreateFile(const std::string& filename, const char* content) { auto& file = files_[filename]; file = std::unique_ptr(new FakeFile(next_file_descriptor_++, content)); return file.get(); } FakeFile* FakeFilesystem::FindFileOrNull(const std::string& filename) const { const auto itr = files_.find(filename); return itr == files_.end() ? nullptr : itr->second.get(); } FakeFile* FakeFilesystem::FindFileOrDie(const int file_descriptor) const { for (const auto& filename_file_pair : files_) { FakeFile* const file_ptr = filename_file_pair.second.get(); if (file_ptr->GetFileDescriptor() == file_descriptor) { return file_ptr; } } assert(false); return nullptr; } static FakeFilesystem* kFilesystem = new FakeFilesystem(); FakeFilesystem& GetEmptyFilesystem() { kFilesystem->Reset(); return *kFilesystem; } extern "C" int CpuFeatures_OpenFile(const char* filename) { auto* const file = kFilesystem->FindFileOrNull(filename); if (file) { file->Open(); return file->GetFileDescriptor(); } return -1; } extern "C" void CpuFeatures_CloseFile(int file_descriptor) { kFilesystem->FindFileOrDie(file_descriptor)->Close(); } extern "C" int CpuFeatures_ReadFile(int file_descriptor, void* buffer, size_t buffer_size) { return kFilesystem->FindFileOrDie(file_descriptor) ->Read(file_descriptor, buffer, buffer_size); } } // namespace cpu_features cpu-features-0.9.0/test/filesystem_for_testing.h000066400000000000000000000032671450057454500220630ustar00rootroot00000000000000// 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. // 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. // Implements a fake filesystem, useful for tests. #ifndef CPU_FEATURES_TEST_FILESYSTEM_FOR_TESTING_H_ #define CPU_FEATURES_TEST_FILESYSTEM_FOR_TESTING_H_ #include #include #include #include "internal/filesystem.h" namespace cpu_features { class FakeFile { public: explicit FakeFile(int file_descriptor, const char* content); ~FakeFile(); void Open(); void Close(); int Read(int fd, void* buf, size_t count); int GetFileDescriptor() const { return file_descriptor_; } private: const int file_descriptor_; const std::string content_; bool opened_ = false; size_t head_index_ = 0; }; class FakeFilesystem { public: void Reset(); FakeFile* CreateFile(const std::string& filename, const char* content); FakeFile* FindFileOrDie(const int file_descriptor) const; FakeFile* FindFileOrNull(const std::string& filename) const; private: int next_file_descriptor_ = 0; std::unordered_map> files_; }; FakeFilesystem& GetEmptyFilesystem(); } // namespace cpu_features #endif // CPU_FEATURES_TEST_FILESYSTEM_FOR_TESTING_H_ cpu-features-0.9.0/test/hwcaps_for_testing.cc000066400000000000000000000031711450057454500213140ustar00rootroot00000000000000// 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. // 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 "hwcaps_for_testing.h" #include #include "internal/string_view.h" namespace cpu_features { namespace { static auto* const g_hardware_capabilities = new HardwareCapabilities(); static const char* g_platform_pointer = nullptr; static const char* g_base_platform_pointer = nullptr; } // namespace void SetHardwareCapabilities(uint32_t hwcaps, uint32_t hwcaps2) { g_hardware_capabilities->hwcaps = hwcaps; g_hardware_capabilities->hwcaps2 = hwcaps2; } void SetPlatformPointer(const char* string) { g_platform_pointer = string; } void SetBasePlatformPointer(const char* string) { g_base_platform_pointer = string; } void ResetHwcaps() { SetHardwareCapabilities(0, 0); SetPlatformPointer(nullptr); SetBasePlatformPointer(nullptr); } HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void) { return *g_hardware_capabilities; } const char* CpuFeatures_GetPlatformPointer(void) { return g_platform_pointer; } const char* CpuFeatures_GetBasePlatformPointer(void) { return g_base_platform_pointer; } } // namespace cpu_features cpu-features-0.9.0/test/hwcaps_for_testing.h000066400000000000000000000020141450057454500211510ustar00rootroot00000000000000// 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. // 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. #ifndef CPU_FEATURES_TEST_HWCAPS_FOR_TESTING_H_ #define CPU_FEATURES_TEST_HWCAPS_FOR_TESTING_H_ #include "internal/hwcaps.h" namespace cpu_features { void SetHardwareCapabilities(uint32_t hwcaps, uint32_t hwcaps2); void SetPlatformPointer(const char* string); void SetBasePlatformPointer(const char* string); // To be called before each test. void ResetHwcaps(); } // namespace cpu_features #endif // CPU_FEATURES_TEST_HWCAPS_FOR_TESTING_H_ cpu-features-0.9.0/test/stack_line_reader_test.cc000066400000000000000000000075031450057454500221240ustar00rootroot00000000000000// 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. // 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/stack_line_reader.h" #include "filesystem_for_testing.h" #include "gtest/gtest.h" namespace cpu_features { bool operator==(const StringView& a, const StringView& b) { return CpuFeatures_StringView_IsEquals(a, b); } namespace { std::string ToString(StringView view) { return {view.ptr, view.size}; } TEST(StackLineReaderTest, Empty) { auto& fs = GetEmptyFilesystem(); auto* file = fs.CreateFile("/proc/cpuinfo", ""); StackLineReader reader; StackLineReader_Initialize(&reader, file->GetFileDescriptor()); { const auto result = StackLineReader_NextLine(&reader); EXPECT_TRUE(result.eof); EXPECT_TRUE(result.full_line); EXPECT_EQ(result.line, str("")); } } TEST(StackLineReaderTest, ManySmallLines) { auto& fs = GetEmptyFilesystem(); auto* file = fs.CreateFile("/proc/cpuinfo", "a\nb\nc"); StackLineReader reader; StackLineReader_Initialize(&reader, file->GetFileDescriptor()); { const auto result = StackLineReader_NextLine(&reader); EXPECT_FALSE(result.eof); EXPECT_TRUE(result.full_line); EXPECT_EQ(result.line, str("a")); } { const auto result = StackLineReader_NextLine(&reader); EXPECT_FALSE(result.eof); EXPECT_TRUE(result.full_line); EXPECT_EQ(result.line, str("b")); } { const auto result = StackLineReader_NextLine(&reader); EXPECT_TRUE(result.eof); EXPECT_TRUE(result.full_line); EXPECT_EQ(result.line, str("c")); } } TEST(StackLineReaderTest, TruncatedLine) { auto& fs = GetEmptyFilesystem(); auto* file = fs.CreateFile("/proc/cpuinfo", R"(First Second More than 16 characters, this will be truncated. last)"); StackLineReader reader; StackLineReader_Initialize(&reader, file->GetFileDescriptor()); { const auto result = StackLineReader_NextLine(&reader); EXPECT_FALSE(result.eof); EXPECT_TRUE(result.full_line); EXPECT_EQ(result.line, str("First")); } { const auto result = StackLineReader_NextLine(&reader); EXPECT_FALSE(result.eof); EXPECT_TRUE(result.full_line); EXPECT_EQ(result.line, str("Second")); } { const auto result = StackLineReader_NextLine(&reader); EXPECT_FALSE(result.eof); EXPECT_FALSE(result.full_line); EXPECT_EQ(result.line, str("More than 16 cha")); } { const auto result = StackLineReader_NextLine(&reader); EXPECT_TRUE(result.eof); EXPECT_TRUE(result.full_line); EXPECT_EQ(result.line, str("last")); } } TEST(StackLineReaderTest, TruncatedLines) { auto& fs = GetEmptyFilesystem(); auto* file = fs.CreateFile("/proc/cpuinfo", R"(More than 16 characters Another line that is too long)"); StackLineReader reader; StackLineReader_Initialize(&reader, file->GetFileDescriptor()); { const auto result = StackLineReader_NextLine(&reader); EXPECT_FALSE(result.eof); EXPECT_FALSE(result.full_line); EXPECT_EQ(result.line, str("More than 16 cha")); } { const auto result = StackLineReader_NextLine(&reader); EXPECT_FALSE(result.eof); EXPECT_FALSE(result.full_line); EXPECT_EQ(result.line, str("Another line tha")); } { const auto result = StackLineReader_NextLine(&reader); EXPECT_TRUE(result.eof); EXPECT_TRUE(result.full_line); EXPECT_EQ(result.line, str("")); } } } // namespace } // namespace cpu_features cpu-features-0.9.0/test/string_view_test.cc000066400000000000000000000201371450057454500210240ustar00rootroot00000000000000// 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. // 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/string_view.h" #include "gtest/gtest.h" namespace cpu_features { bool operator==(const StringView& a, const StringView& b) { return CpuFeatures_StringView_IsEquals(a, b); } namespace { TEST(StringViewTest, Empty) { EXPECT_EQ(kEmptyStringView.ptr, nullptr); EXPECT_EQ(kEmptyStringView.size, 0); } TEST(StringViewTest, Build) { const auto view = str("test"); EXPECT_EQ(view.ptr[0], 't'); EXPECT_EQ(view.size, 4); } TEST(StringViewTest, CpuFeatures_StringView_IndexOfChar) { // Found. EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 'e'), 1); EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 't'), 0); EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("beef"), 'e'), 1); // Not found. EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 'z'), -1); // Empty. EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(kEmptyStringView, 'z'), -1); } TEST(StringViewTest, CpuFeatures_StringView_IndexOf) { // Found. EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("es")), 1); EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("test")), 0); EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("tesstest"), str("test")), 4); // Not found. EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("aa")), -1); // Empty. EXPECT_EQ(CpuFeatures_StringView_IndexOf(kEmptyStringView, str("aa")), -1); EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("aa"), kEmptyStringView), -1); } TEST(StringViewTest, CpuFeatures_StringView_StartsWith) { EXPECT_TRUE(CpuFeatures_StringView_StartsWith(str("test"), str("te"))); EXPECT_TRUE(CpuFeatures_StringView_StartsWith(str("test"), str("test"))); EXPECT_FALSE(CpuFeatures_StringView_StartsWith(str("test"), str("st"))); EXPECT_FALSE(CpuFeatures_StringView_StartsWith(str("test"), str("est"))); EXPECT_FALSE(CpuFeatures_StringView_StartsWith(str("test"), str(""))); EXPECT_FALSE( CpuFeatures_StringView_StartsWith(str("test"), kEmptyStringView)); EXPECT_FALSE( CpuFeatures_StringView_StartsWith(kEmptyStringView, str("test"))); } TEST(StringViewTest, CpuFeatures_StringView_IsEquals) { EXPECT_TRUE( CpuFeatures_StringView_IsEquals(kEmptyStringView, kEmptyStringView)); EXPECT_TRUE(CpuFeatures_StringView_IsEquals(kEmptyStringView, str(""))); EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str(""), kEmptyStringView)); EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str("test"), str("test"))); EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str("a"), str("a"))); EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), str("b"))); EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("aa"), str("a"))); EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), str("aa"))); EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), kEmptyStringView)); EXPECT_FALSE(CpuFeatures_StringView_IsEquals(kEmptyStringView, str("a"))); } TEST(StringViewTest, CpuFeatures_StringView_PopFront) { EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 2), str("st")); EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 0), str("test")); EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 4), str("")); EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 100), str("")); } TEST(StringViewTest, CpuFeatures_StringView_PopBack) { EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 2), str("te")); EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 0), str("test")); EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 4), str("")); EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 100), str("")); } TEST(StringViewTest, CpuFeatures_StringView_KeepFront) { EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 2), str("te")); EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 0), str("")); EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 4), str("test")); EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 6), str("test")); } TEST(StringViewTest, CpuFeatures_StringView_Front) { EXPECT_EQ(CpuFeatures_StringView_Front(str("apple")), 'a'); EXPECT_EQ(CpuFeatures_StringView_Front(str("a")), 'a'); } TEST(StringViewTest, CpuFeatures_StringView_Back) { EXPECT_EQ(CpuFeatures_StringView_Back(str("apple")), 'e'); EXPECT_EQ(CpuFeatures_StringView_Back(str("a")), 'a'); } TEST(StringViewTest, CpuFeatures_StringView_TrimWhitespace) { EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str(" first middle last ")), str("first middle last")); EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str("first middle last ")), str("first middle last")); EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str(" first middle last")), str("first middle last")); EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str("first middle last")), str("first middle last")); } TEST(StringViewTest, CpuFeatures_StringView_ParsePositiveNumber) { EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("42")), 42); EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2a")), 42); EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2A")), 42); EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2A2a")), 10794); EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2a2A")), 10794); EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("-10")), -1); EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("-0x2A")), -1); EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("abc")), -1); EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("")), -1); } TEST(StringViewTest, CpuFeatures_StringView_CopyString) { char buf[4]; buf[0] = 'X'; // Empty CpuFeatures_StringView_CopyString(str(""), buf, sizeof(buf)); EXPECT_STREQ(buf, ""); // Less CpuFeatures_StringView_CopyString(str("a"), buf, sizeof(buf)); EXPECT_STREQ(buf, "a"); // exact CpuFeatures_StringView_CopyString(str("abc"), buf, sizeof(buf)); EXPECT_STREQ(buf, "abc"); // More CpuFeatures_StringView_CopyString(str("abcd"), buf, sizeof(buf)); EXPECT_STREQ(buf, "abc"); } TEST(StringViewTest, CpuFeatures_StringView_HasWord) { // Find flags at beginning, middle and end. EXPECT_TRUE( CpuFeatures_StringView_HasWord(str("first middle last"), "first", ' ')); EXPECT_TRUE( CpuFeatures_StringView_HasWord(str("first middle last"), "middle", ' ')); EXPECT_TRUE( CpuFeatures_StringView_HasWord(str("first middle last"), "last", ' ')); // Find flags at beginning, middle and end with a different separator EXPECT_TRUE( CpuFeatures_StringView_HasWord(str("first-middle-last"), "first", '-')); EXPECT_TRUE( CpuFeatures_StringView_HasWord(str("first-middle-last"), "middle", '-')); EXPECT_TRUE( CpuFeatures_StringView_HasWord(str("first-middle-last"), "last", '-')); // Do not match partial flags EXPECT_FALSE( CpuFeatures_StringView_HasWord(str("first middle last"), "irst", ' ')); EXPECT_FALSE( CpuFeatures_StringView_HasWord(str("first middle last"), "mid", ' ')); EXPECT_FALSE( CpuFeatures_StringView_HasWord(str("first middle last"), "las", ' ')); } TEST(StringViewTest, CpuFeatures_StringView_GetAttributeKeyValue) { const StringView line = str(" key : first middle last "); StringView key, value; EXPECT_TRUE(CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)); EXPECT_EQ(key, str("key")); EXPECT_EQ(value, str("first middle last")); } TEST(StringViewTest, FailingGetAttributeKeyValue) { const StringView line = str("key first middle last"); StringView key, value; EXPECT_FALSE(CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)); } } // namespace } // namespace cpu_features