diff options
author | Roland Levillain <rpl@google.com> | 2023-04-28 19:12:56 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-04-28 19:12:56 +0000 |
commit | bb1a16125208eba8004e5e62f902ac1d68ac63e9 (patch) | |
tree | 274e1e79e270c332b8d055d5e25b0b0e33c78365 | |
parent | 6d28abb49625745335bfa37dc3d0e704b21cd5f3 (diff) | |
parent | ecbbbe7a858e3f09d2966add7a9c6229f2fa03aa (diff) | |
download | cpu_features-bb1a16125208eba8004e5e62f902ac1d68ac63e9.tar.gz |
Merge v0.8.0 into master. am: 50b79af61d am: 925e059f65 am: ecbbbe7a85
Original change: https://android-review.googlesource.com/c/platform/external/cpu_features/+/2567814
Change-Id: Icb5e46623b6a3e9d25c8f25a13ed3944e3a6acf4
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
60 files changed, 3182 insertions, 451 deletions
diff --git a/.dockerignore b/.dockerignore index 716b782..65950ea 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,8 +1,8 @@ # Project Files unneeded by docker -ci/Makefile -ci/docker -ci/doc -ci/cache +cmake/ci/Makefile +cmake/ci/docker +cmake/ci/doc +cmake/ci/cache .git .gitignore .github diff --git a/.github/workflows/aarch64_linux.yml b/.github/workflows/aarch64_linux_cmake.yml index 2de7289..3e2d53c 100644 --- a/.github/workflows/aarch64_linux.yml +++ b/.github/workflows/aarch64_linux_cmake.yml @@ -1,4 +1,4 @@ -name: aarch64 Linux +name: AArch64 Linux CMake on: push: @@ -9,11 +9,13 @@ on: jobs: # Building using the github runner environement directly. - aarch64: + make: runs-on: ubuntu-latest strategy: matrix: targets: [ + [aarch64], + [aarch64be], [aarch64-linux-gnu], [aarch64_be-linux-gnu] ] @@ -23,6 +25,6 @@ jobs: steps: - uses: actions/checkout@v2 - name: Build - run: make --directory=ci ${TARGET}_build + run: make --directory=cmake/ci ${TARGET}_build - name: Test - run: make --directory=ci ${TARGET}_test + run: make --directory=cmake/ci ${TARGET}_test diff --git a/.github/workflows/amd64_freebsd.yml b/.github/workflows/amd64_freebsd_cmake.yml index eeab380..8bad4f8 100644 --- a/.github/workflows/amd64_freebsd.yml +++ b/.github/workflows/amd64_freebsd_cmake.yml @@ -1,4 +1,4 @@ -name: amd64 FreeBSD +name: amd64 FreeBSD CMake on: push: @@ -10,7 +10,7 @@ on: jobs: # Only MacOS hosted runner provides virtualisation with vagrant/virtualbox installed. # see: https://github.com/actions/virtual-environments/tree/main/images/macos - freebsd: + make: runs-on: macos-10.15 steps: - uses: actions/checkout@v2 @@ -19,4 +19,4 @@ jobs: - name: VirtualBox version run: virtualbox -h - name: Build - run: cd ci/vagrant/freebsd && vagrant up + run: cd cmake/ci/vagrant/freebsd && vagrant up diff --git a/.github/workflows/amd64_linux.yml b/.github/workflows/amd64_linux.yml deleted file mode 100644 index 21f4f90..0000000 --- a/.github/workflows/amd64_linux.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: amd64 Linux - -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=ci amd64_env - - name: Devel - run: make --directory=ci amd64_devel - - name: Build - run: make --directory=ci amd64_build - - name: Test - run: make --directory=ci amd64_test - - name: Install Env - run: make --directory=ci amd64_install_env - - name: Install Devel - run: make --directory=ci amd64_install_devel - - name: Install Build - run: make --directory=ci amd64_install_build - - name: Install Test - run: make --directory=ci amd64_install_test diff --git a/.github/workflows/amd64_linux_bazel.yml b/.github/workflows/amd64_linux_bazel.yml new file mode 100644 index 0000000..599faf5 --- /dev/null +++ b/.github/workflows/amd64_linux_bazel.yml @@ -0,0 +1,26 @@ +name: 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@v2 + - name: Install Bazel + run: | + curl -fsSL https://bazel.build/bazel-release.pub.gpg | gpg --dearmor > bazel.gpg + sudo mv bazel.gpg /etc/apt/trusted.gpg.d/ + echo "deb [arch=amd64] https://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list + sudo apt-get update + sudo apt-get install bazel + bazel --version + - name: Test + run: bazel test -s --verbose_failures //... diff --git a/.github/workflows/amd64_linux_cmake.yml b/.github/workflows/amd64_linux_cmake.yml new file mode 100644 index 0000000..90ccc80 --- /dev/null +++ b/.github/workflows/amd64_linux_cmake.yml @@ -0,0 +1,31 @@ +name: 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 diff --git a/.github/workflows/amd64_macos.yml b/.github/workflows/amd64_macos_cmake.yml index 19ec18c..3756500 100644 --- a/.github/workflows/amd64_macos.yml +++ b/.github/workflows/amd64_macos_cmake.yml @@ -1,4 +1,4 @@ -name: amd64 macOS +name: amd64 MacOS CMake on: push: diff --git a/.github/workflows/amd64_windows.yml b/.github/workflows/amd64_windows_cmake.yml index 7ff1ac0..7118533 100644 --- a/.github/workflows/amd64_windows.yml +++ b/.github/workflows/amd64_windows_cmake.yml @@ -1,4 +1,4 @@ -name: amd64 Windows +name: amd64 Windows CMake on: push: diff --git a/.github/workflows/arm_linux.yml b/.github/workflows/arm_linux_cmake.yml index 2272188..87bb6bb 100644 --- a/.github/workflows/arm_linux.yml +++ b/.github/workflows/arm_linux_cmake.yml @@ -1,4 +1,4 @@ -name: arm Linux +name: ARM Linux CMake on: push: @@ -9,7 +9,7 @@ on: jobs: # Building using the github runner environement directly. - arm: + make: runs-on: ubuntu-latest strategy: matrix: @@ -26,6 +26,6 @@ jobs: steps: - uses: actions/checkout@v2 - name: Build - run: make --directory=ci ${TARGET}_build + run: make --directory=cmake/ci ${TARGET}_build - name: Test - run: make --directory=ci ${TARGET}_test + run: make --directory=cmake/ci ${TARGET}_test diff --git a/.github/workflows/mips_linux.yml b/.github/workflows/mips_linux_cmake.yml index 571de3a..9ce7901 100644 --- a/.github/workflows/mips_linux.yml +++ b/.github/workflows/mips_linux_cmake.yml @@ -1,4 +1,4 @@ -name: mips Linux +name: MIPS Linux CMake on: push: @@ -9,7 +9,7 @@ on: jobs: # Building using the github runner environement directly. - mips: + make: runs-on: ubuntu-latest strategy: matrix: @@ -25,6 +25,6 @@ jobs: steps: - uses: actions/checkout@v2 - name: Build - run: make --directory=ci ${TARGET}_build + run: make --directory=cmake/ci ${TARGET}_build - name: Test - run: make --directory=ci ${TARGET}_test + run: make --directory=cmake/ci ${TARGET}_test diff --git a/.github/workflows/power_linux_cmake.yml b/.github/workflows/power_linux_cmake.yml new file mode 100644 index 0000000..bc890e2 --- /dev/null +++ b/.github/workflows/power_linux_cmake.yml @@ -0,0 +1,29 @@ +name: 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 diff --git a/.github/workflows/riscv_linux_cmake.yml b/.github/workflows/riscv_linux_cmake.yml new file mode 100644 index 0000000..ef7586a --- /dev/null +++ b/.github/workflows/riscv_linux_cmake.yml @@ -0,0 +1,28 @@ +name: 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 diff --git a/.github/workflows/s390x_linux_cmake.yml b/.github/workflows/s390x_linux_cmake.yml new file mode 100644 index 0000000..5be96a1 --- /dev/null +++ b/.github/workflows/s390x_linux_cmake.yml @@ -0,0 +1,27 @@ +name: 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 diff --git a/.grenrc.yml b/.grenrc.yml new file mode 100644 index 0000000..77dd755 --- /dev/null +++ b/.grenrc.yml @@ -0,0 +1,21 @@ +--- + 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" diff --git a/BUILD.bazel b/BUILD.bazel index 1b62d66..116ef6a 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -28,24 +28,24 @@ C99_FLAGS = [ cc_library( name = "cpu_features_macros", - hdrs = ["include/cpu_features_macros.h"], copts = C99_FLAGS, includes = INCLUDES, + textual_hdrs = ["include/cpu_features_macros.h"], ) cc_library( name = "cpu_features_cache_info", - hdrs = ["include/cpu_features_cache_info.h"], copts = C99_FLAGS, includes = INCLUDES, + textual_hdrs = ["include/cpu_features_cache_info.h"], deps = [":cpu_features_macros"], ) cc_library( name = "bit_utils", - hdrs = ["include/internal/bit_utils.h"], copts = C99_FLAGS, includes = INCLUDES, + textual_hdrs = ["include/internal/bit_utils.h"], deps = [":cpu_features_macros"], ) @@ -74,9 +74,9 @@ cc_library( srcs = [ "src/string_view.c", ], - hdrs = ["include/internal/string_view.h"], copts = C99_FLAGS, includes = INCLUDES, + textual_hdrs = ["include/internal/string_view.h"], deps = [ ":cpu_features_macros", ":memory_utils", @@ -96,9 +96,9 @@ cc_test( cc_library( name = "filesystem", srcs = ["src/filesystem.c"], - hdrs = ["include/internal/filesystem.h"], copts = C99_FLAGS, includes = INCLUDES, + textual_hdrs = ["include/internal/filesystem.h"], deps = [":cpu_features_macros"], ) @@ -113,8 +113,8 @@ cc_library( "include/internal/filesystem.h", "test/filesystem_for_testing.h", ], - includes = INCLUDES, defines = ["CPU_FEATURES_MOCK_FILESYSTEM"], + includes = INCLUDES, deps = [ ":cpu_features_macros", ], @@ -123,10 +123,10 @@ cc_library( cc_library( name = "stack_line_reader", srcs = ["src/stack_line_reader.c"], - hdrs = ["include/internal/stack_line_reader.h"], copts = C99_FLAGS, - includes = INCLUDES, defines = ["STACK_LINE_READER_BUFFER_SIZE=1024"], + includes = INCLUDES, + textual_hdrs = ["include/internal/stack_line_reader.h"], deps = [ ":cpu_features_macros", ":filesystem", @@ -141,8 +141,8 @@ cc_test( "src/stack_line_reader.c", "test/stack_line_reader_test.cc", ], - includes = INCLUDES, defines = ["STACK_LINE_READER_BUFFER_SIZE=16"], + includes = INCLUDES, deps = [ ":cpu_features_macros", ":filesystem_for_testing", @@ -157,8 +157,8 @@ cc_library( srcs = ["src/stack_line_reader.c"], hdrs = ["include/internal/stack_line_reader.h"], copts = C99_FLAGS, - includes = INCLUDES, defines = ["STACK_LINE_READER_BUFFER_SIZE=1024"], + includes = INCLUDES, deps = [ ":cpu_features_macros", ":filesystem_for_testing", @@ -169,10 +169,10 @@ cc_library( cc_library( name = "hwcaps", srcs = ["src/hwcaps.c"], - hdrs = ["include/internal/hwcaps.h"], copts = C99_FLAGS, - includes = INCLUDES, defines = ["HAVE_STRONG_GETAUXVAL"], + includes = INCLUDES, + textual_hdrs = ["include/internal/hwcaps.h"], deps = [ ":cpu_features_macros", ":filesystem", @@ -191,11 +191,11 @@ cc_library( "include/internal/hwcaps.h", "test/hwcaps_for_testing.h", ], - includes = INCLUDES, defines = [ "CPU_FEATURES_MOCK_GET_ELF_HWCAP_FROM_GETAUXVAL", "CPU_FEATURES_TEST", ], + includes = INCLUDES, deps = [ ":cpu_features_macros", ":filesystem_for_testing", @@ -217,21 +217,19 @@ cc_library( PLATFORM_CPU_MIPS: ["src/impl_mips_linux_or_android.c"], PLATFORM_CPU_PPC: ["src/impl_ppc_linux.c"], }), - hdrs = selects.with_or({ + copts = C99_FLAGS, + includes = INCLUDES, + textual_hdrs = selects.with_or({ PLATFORM_CPU_X86_64: [ + "src/impl_x86__base_implementation.inl", "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"], - }), - copts = C99_FLAGS, - includes = INCLUDES, - textual_hdrs = selects.with_or({ - PLATFORM_CPU_X86_64: ["src/impl_x86__base_implementation.inl"], - "//conditions:default": [], }) + [ "src/define_introspection.inl", "src/define_introspection_and_hwcaps.inl", @@ -267,6 +265,7 @@ cc_library( 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"], @@ -274,11 +273,11 @@ cc_library( PLATFORM_CPU_PPC: ["include/cpuinfo_ppc.h"], }), copts = C99_FLAGS, - includes = INCLUDES, defines = selects.with_or({ PLATFORM_CPU_X86_64: ["CPU_FEATURES_MOCK_CPUID_X86"], "//conditions:default": [], }), + includes = INCLUDES, textual_hdrs = selects.with_or({ PLATFORM_CPU_X86_64: ["src/impl_x86__base_implementation.inl"], "//conditions:default": [], diff --git a/CMakeLists.txt b/CMakeLists.txt index 81451d4..bcc9bb0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if(POLICY CMP0077) cmake_policy(SET CMP0077 NEW) endif() -project(CpuFeatures VERSION 0.7.0 LANGUAGES C) +project(CpuFeatures VERSION 0.8.0 LANGUAGES C) set(CMAKE_C_STANDARD 99) @@ -49,6 +49,8 @@ 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) if(CMAKE_SYSTEM_PROCESSOR MATCHES "^mips") set(PROCESSOR_IS_MIPS TRUE) @@ -60,6 +62,10 @@ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(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) endif() macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME) @@ -73,11 +79,17 @@ macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME) 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) else() message(FATAL_ERROR "Unsupported architectures ${CMAKE_SYSTEM_PROCESSOR}") endif() @@ -168,9 +180,9 @@ if(BUILD_TESTING) # found. enable_language(CXX) - set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) - set(CMAKE_CXX_EXTENSIONS OFF) # prefer use of -std11 instead of -gnustd11 + 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. @@ -9,11 +9,11 @@ third_party { type: GIT value: "https://github.com/google/cpu_features.git" } - version: "v0.7.0" + version: "v0.8.0" license_type: NOTICE last_upgrade_date { - year: 2022 - month: 3 - day: 8 + year: 2023 + month: 4 + day: 27 } } @@ -1,18 +1,44 @@ # cpu_features -[![Linux Status][linux_svg]][linux_link] -[![Macos Status][macos_svg]][macos_link] -[![Windows Status][windows_svg]][windows_link] - -[linux_svg]: https://github.com/google/cpu_features/actions/workflows/amd64_linux.yml/badge.svg?branch=main -[linux_link]: https://github.com/google/cpu_features/actions/workflows/amd64_linux.yml -[macos_svg]: https://github.com/google/cpu_features/actions/workflows/amd64_macos.yml/badge.svg?branch=main -[macos_link]: https://github.com/google/cpu_features/actions/workflows/amd64_macos.yml -[windows_svg]: https://github.com/google/cpu_features/actions/workflows/amd64_windows.yml/badge.svg?branch=main -[windows_link]: https://github.com/google/cpu_features/actions/workflows/amd64_windows.yml 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/) + +| Os | amd64 | AArch64 | ARM | MIPS | POWER | RISCV | s390x | +| :-- | --: | --: | --: | --: | --: | --: | --: | +| Linux | [![][i1a0]][l1a0]<br/>[![][i1a1]][l1a1] | [![][i1b0]][l1b0]<br/>![][d1] | [![][i1c0]][l1c0]<br/>![][d1] | [![][i1d0]][l1d0]<br/>![][d1] | [![][i1e0]][l1e0]<br/>![][d1] | [![][i1f0]][l1f0]<br/>![][d1] | [![][i1g0]][l1g0]<br/>![][d1] | +| FreeBSD | [![][i2a0]][l2a0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | +| MacOS | [![][i3a0]][l3a0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | +| Windows | [![][i4a0]][l4a0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | + +[d0]: https://img.shields.io/badge/CMake-N%2FA-lightgrey +[d1]: https://img.shields.io/badge/Bazel-N%2FA-lightgrey +[i1a0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_linux_cmake.yml?branch=main&label=CMake +[i1a1]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_linux_bazel.yml?branch=main&label=Bazel +[i1b0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/aarch64_linux_cmake.yml?branch=main&label=CMake +[i1c0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/arm_linux_cmake.yml?branch=main&label=CMake +[i1d0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/mips_linux_cmake.yml?branch=main&label=CMake +[i1e0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/power_linux_cmake.yml?branch=main&label=CMake +[i1f0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/riscv_linux_cmake.yml?branch=main&label=CMake +[i1g0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/s390x_linux_cmake.yml?branch=main&label=CMake +[i2a0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_freebsd_cmake.yml?branch=main&label=CMake +[i3a0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_macos_cmake.yml?branch=main&label=CMake +[i4a0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_windows_cmake.yml?branch=main&label=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 +[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 +[l1g0]: 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 +[l4a0]: https://github.com/google/cpu_features/actions/workflows/amd64_windows_cmake.yml + ## Table of Contents - [Design Rationale](#rationale) @@ -152,14 +178,14 @@ flags : aes,avx,cx16,smx,sse4_1,sse4_2,ssse3 <a name="support"></a> ## What's supported -| | x86³ | ARM | AArch64 | MIPS⁴ | POWER | -|---------|:----:|:-------:|:-------:|:-------:|:-------:| -| Android | yes² | yes¹ | yes¹ | yes¹ | N/A | -| iOS | N/A | not yet | not yet | N/A | N/A | -| Linux | yes² | yes¹ | yes¹ | yes¹ | yes¹ | -| MacOs | yes² | N/A | not yet | N/A | no | -| Windows | yes² | not yet | not yet | N/A | N/A | -| FreeBSD | yes² | not yet | not yet | not yet | not yet | +| | x86³ | AArch64 | ARM | MIPS⁴ | POWER | RISCV | s390x | +|---------|:----:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:| +| Linux | yes² | yes¹ | yes¹ | yes¹ | yes¹ | yes¹ | yes¹ | +| FreeBSD | yes² | not yet | not yet | not yet | not yet | N/A | not yet | +| MacOs | yes² | not yet | N/A | N/A | no | N/A | no | +| Windows | yes² | not yet | not yet | N/A | N/A | N/A | N/A | +| Android | yes² | yes¹ | yes¹ | yes¹ | N/A | N/A | N/A | +| iOS | N/A | not yet | not yet | N/A | N/A | N/A | N/A | 1. **Features revealed from Linux.** We gather data from several sources depending on availability: @@ -196,23 +222,39 @@ Please check the [CMake build instructions](cmake/README.md). <a name="quickstart"></a> ### 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 -``` +- 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`. + _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 -``` +- 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_: Use `--target RUN_TESTS` on the last line for `Visual Studio` and `--target RUN_TEST` for `XCode`. + _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.<br> + e.g. + ```sh + cmake --build build --config Release --target install -v -- DESTDIR=install + ``` <a name="bindings"></a> ## Community bindings @@ -223,6 +265,8 @@ Links provided here are not affiliated with Google but are kindly provided by th - 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_ @@ -1,21 +1,17 @@ workspace(name = "com_google_cpufeatures") -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") -http_archive( +git_repository( name = "com_google_googletest", - sha256 = "269cebe2be1f607f91f52630ff5bec3275b948c65d4bac323ebd05e90d84f7a9", - strip_prefix = "googletest-e2239ee6043f73722e7aa812a459f54a28552929", - urls = ["https://github.com/google/googletest/archive/e2239ee6043f73722e7aa812a459f54a28552929.zip"], + tag = "release-1.11.0", + remote = "https://github.com/google/googletest.git", ) -http_archive( +git_repository( name = "bazel_skylib", - sha256 = "c6966ec828da198c5d9adbaa94c05e3a1c7f21bd012a0b29ba8ddbccb2c93b0d", - urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.1.1/bazel-skylib-1.1.1.tar.gz", - "https://github.com/bazelbuild/bazel-skylib/releases/download/1.1.1/bazel-skylib-1.1.1.tar.gz", - ], + tag = "1.2.0", + remote = "https://github.com/bazelbuild/bazel-skylib.git", ) load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") diff --git a/bazel/ci/README.md b/bazel/ci/README.md new file mode 100644 index 0000000..c5fcde9 --- /dev/null +++ b/bazel/ci/README.md @@ -0,0 +1,5 @@ +## Usage +To build tests with bazel +```sh +bazel test -s --verbose_failures //... +``` diff --git a/ci/README.md b/ci/README.md deleted file mode 100644 index e370136..0000000 --- a/ci/README.md +++ /dev/null @@ -1,66 +0,0 @@ -# GitHub-CI Status -| OS | amd64 | AArch64 | ARM | MIPS | -|:-------- | :----: | :-----: | :-: | :--: | -| FreeBSD | [![Status][freebsd_svg]][freebsd_link] | N/A | N/A | N/A | -| Linux | [![Status][linux_svg]][linux_link] | [![Status][linux_aarch64_svg]][linux_aarch64_link] | [![Status][linux_arm_svg]][linux_arm_link] | [![Status][linux_mips_svg]][linux_mips_link] | -| MacOS | [![Status][macos_svg]][macos_link] | N/A | N/A | N/A | -| Windows | [![Status][windows_svg]][windows_link] | N/A | N/A | N/A | - -[freebsd_svg]: https://github.com/google/cpu_features/actions/workflows/amd64_freebsd.yml/badge.svg?branch=main -[freebsd_link]: https://github.com/google/cpu_features/actions/workflows/amd64_freebsd.yml - -[linux_svg]: https://github.com/google/cpu_features/actions/workflows/amd64_linux.yml/badge.svg?branch=main -[linux_link]: https://github.com/google/cpu_features/actions/workflows/amd64_linux.yml -[linux_aarch64_svg]: https://github.com/google/cpu_features/actions/workflows/aarch64_linux.yml/badge.svg?branch=main -[linux_aarch64_link]: https://github.com/google/cpu_features/actions/workflows/aarch64_linux.yml -[linux_arm_svg]: https://github.com/google/cpu_features/actions/workflows/arm_linux.yml/badge.svg?branch=main -[linux_arm_link]: https://github.com/google/cpu_features/actions/workflows/arm_linux.yml -[linux_mips_svg]: https://github.com/google/cpu_features/actions/workflows/mips_linux.yml/badge.svg?branch=main -[linux_mips_link]: https://github.com/google/cpu_features/actions/workflows/mips_linux.yml - -[macos_svg]: https://github.com/google/cpu_features/actions/workflows/amd64_macos.yml/badge.svg?branch=main -[macos_link]: https://github.com/google/cpu_features/actions/workflows/amd64_macos.yml - -[windows_svg]: https://github.com/google/cpu_features/actions/workflows/amd64_windows.yml/badge.svg?branch=main -[windows_link]: https://github.com/google/cpu_features/actions/workflows/amd64_windows.yml - -## 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=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. diff --git a/cmake/README.md b/cmake/README.md index b2d96c4..de33b23 100644 --- a/cmake/README.md +++ b/cmake/README.md @@ -17,7 +17,7 @@ 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 `cpu_features` target to the `target_link_libraries()` section of +3- Add the `CpuFeature::cpu_features` target to the `target_link_libraries()` section of your executable or of your library. ## Disabling tests diff --git a/ci/Makefile b/cmake/ci/Makefile index 47ea30a..f655fc3 100644 --- a/ci/Makefile +++ b/cmake/ci/Makefile @@ -45,11 +45,19 @@ help: @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}<toolchain_stage>${RESET}:" @echo -e "\t\t${BOLD}env${RESET}" @@ -113,7 +121,7 @@ $(targets_amd64): amd64_%: docker/amd64/Dockerfile --tag ${IMAGE}:amd64_$* \ --target=$* \ -f $< \ - .. + ../.. #$(info Create targets: save_amd64 $(addprefix save_amd64_, $(STAGES)) (debug).) save_targets_amd64 = $(addprefix save_amd64_, $(STAGES)) @@ -143,9 +151,13 @@ $(clean_targets_amd64): clean_amd64_%: ## 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 + mips32 mips32el mips64 mips64el \ + ppc ppc64 ppc64le \ + riscv32 riscv64 \ + s390x TOOLCHAIN_STAGES = env devel build test define toolchain-stage-target = #$$(info STAGE: $1) @@ -160,7 +172,7 @@ $$(targets_toolchain_$1): %_$1: docker/toolchain/Dockerfile --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))) diff --git a/cmake/ci/README.md b/cmake/ci/README.md new file mode 100644 index 0000000..0d898d8 --- /dev/null +++ b/cmake/ci/README.md @@ -0,0 +1,40 @@ +## 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. diff --git a/ci/doc/docker.dot b/cmake/ci/doc/docker.dot index a00ef1f..a00ef1f 100644 --- a/ci/doc/docker.dot +++ b/cmake/ci/doc/docker.dot diff --git a/ci/doc/docker.svg b/cmake/ci/doc/docker.svg index bd9bd6d..bd9bd6d 100644 --- a/ci/doc/docker.svg +++ b/cmake/ci/doc/docker.svg diff --git a/ci/doc/generate_image.sh b/cmake/ci/doc/generate_image.sh index 15f1774..15f1774 100755 --- a/ci/doc/generate_image.sh +++ b/cmake/ci/doc/generate_image.sh diff --git a/ci/docker/amd64/Dockerfile b/cmake/ci/docker/amd64/Dockerfile index 9b25e28..2cc3270 100644 --- a/ci/docker/amd64/Dockerfile +++ b/cmake/ci/docker/amd64/Dockerfile @@ -38,7 +38,7 @@ COPY --from=build /usr/local /usr/local/ FROM install_env AS install_devel WORKDIR /home/sample -COPY ci/sample . +COPY cmake/ci/sample . FROM install_devel AS install_build RUN cmake -S. -Bbuild diff --git a/ci/docker/toolchain/Dockerfile b/cmake/ci/docker/toolchain/Dockerfile index 1bf25ed..1bf25ed 100644 --- a/ci/docker/toolchain/Dockerfile +++ b/cmake/ci/docker/toolchain/Dockerfile diff --git a/ci/sample/CMakeLists.txt b/cmake/ci/sample/CMakeLists.txt index b60e92f..b60e92f 100644 --- a/ci/sample/CMakeLists.txt +++ b/cmake/ci/sample/CMakeLists.txt diff --git a/ci/sample/main.cpp b/cmake/ci/sample/main.cpp index 45ec651..45ec651 100644 --- a/ci/sample/main.cpp +++ b/cmake/ci/sample/main.cpp diff --git a/ci/vagrant/freebsd/Vagrantfile b/cmake/ci/vagrant/freebsd/Vagrantfile index 7ef7bfa..6234ff6 100644 --- a/ci/vagrant/freebsd/Vagrantfile +++ b/cmake/ci/vagrant/freebsd/Vagrantfile @@ -49,11 +49,11 @@ Vagrant.configure("2") do |config| #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/" + 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. @@ -99,4 +99,9 @@ Vagrant.configure("2") do |config| 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 diff --git a/include/cpu_features_macros.h b/include/cpu_features_macros.h index 6a2f76a..215b567 100644 --- a/include/cpu_features_macros.h +++ b/include/cpu_features_macros.h @@ -39,7 +39,7 @@ #define CPU_FEATURES_ARCH_ARM #endif -#if defined(__aarch64__) +#if (defined(__aarch64__) || defined(_M_ARM64)) #define CPU_FEATURES_ARCH_AARCH64 #endif @@ -63,6 +63,26 @@ #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 + //////////////////////////////////////////////////////////////////////////////// // Os //////////////////////////////////////////////////////////////////////////////// @@ -224,8 +244,121 @@ #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 //////////////////////////////////////////////////////////////////////////////// @@ -242,6 +375,8 @@ // 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 diff --git a/include/cpuinfo_aarch64.h b/include/cpuinfo_aarch64.h index 1b57d21..d124b5f 100644 --- a/include/cpuinfo_aarch64.h +++ b/include/cpuinfo_aarch64.h @@ -12,6 +12,100 @@ // 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_ @@ -72,16 +166,20 @@ typedef struct { 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. // Make sure to update Aarch64FeaturesEnum below if you add a field here. } Aarch64Features; typedef struct { Aarch64Features features; - int implementer; - int variant; - int part; - int revision; + 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); @@ -141,6 +239,9 @@ typedef enum { AARCH64_RNG, AARCH64_BTI, AARCH64_MTE, + AARCH64_ECV, + AARCH64_AFP, + AARCH64_RPRES, AARCH64_LAST_, } Aarch64FeaturesEnum; diff --git a/include/cpuinfo_mips.h b/include/cpuinfo_mips.h index 9e5e7fc..321d3c8 100644 --- a/include/cpuinfo_mips.h +++ b/include/cpuinfo_mips.h @@ -21,11 +21,20 @@ 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 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; @@ -43,6 +52,11 @@ typedef enum { MIPS_MSA, MIPS_EVA, MIPS_R6, + MIPS_MIPS16, + MIPS_MDMX, + MIPS_MIPS3D, + MIPS_SMART, + MIPS_DSP, MIPS_LAST_, } MipsFeaturesEnum; diff --git a/include/cpuinfo_riscv.h b/include/cpuinfo_riscv.h new file mode 100644 index 0000000..1fa7aa5 --- /dev/null +++ b/include/cpuinfo_riscv.h @@ -0,0 +1,72 @@ +// 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_ diff --git a/include/cpuinfo_s390x.h b/include/cpuinfo_s390x.h new file mode 100644 index 0000000..48864de --- /dev/null +++ b/include/cpuinfo_s390x.h @@ -0,0 +1,108 @@ +// 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_ diff --git a/include/cpuinfo_x86.h b/include/cpuinfo_x86.h index 88daca4..e897500 100644 --- a/include/cpuinfo_x86.h +++ b/include/cpuinfo_x86.h @@ -60,6 +60,7 @@ typedef struct { int sse4a : 1; int avx : 1; + int avx_vnni : 1; int avx2 : 1; int avx512f : 1; @@ -76,11 +77,12 @@ typedef struct { int avx512bitalg : 1; int avx512vpopcntdq : 1; int avx512_4vnniw : 1; - int avx512_4vbmi2 : 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; @@ -97,6 +99,14 @@ typedef struct { int dca : 1; int ss : 1; int adx : 1; + int lzcnt : 1; // Note: this flag is called ABM for AMD, LZCNT for Intel. + 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 // Make sure to update X86FeaturesEnum below if you add a field here. } X86Features; @@ -114,59 +124,64 @@ X86Info GetX86Info(void); // Returns cache hierarchy informations. // Can call cpuid multiple times. -// Only works on Intel CPU at the moment. 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_ATOM_GMT, // GOLDMONT - INTEL_KBL, // KABY LAKE - INTEL_CFL, // COFFEE LAKE - INTEL_WHL, // WHISKEY 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_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 - 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 + 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; @@ -211,6 +226,7 @@ typedef enum { X86_SSE4_2, X86_SSE4A, X86_AVX, + X86_AVX_VNNI, X86_AVX2, X86_AVX512F, X86_AVX512CD, @@ -226,11 +242,12 @@ typedef enum { X86_AVX512BITALG, X86_AVX512VPOPCNTDQ, X86_AVX512_4VNNIW, - X86_AVX512_4VBMI2, + 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, @@ -245,6 +262,14 @@ typedef enum { 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_LAST_, } X86FeaturesEnum; diff --git a/include/internal/hwcaps.h b/include/internal/hwcaps.h index d7fc782..3290cc9 100644 --- a/include/internal/hwcaps.h +++ b/include/internal/hwcaps.h @@ -80,6 +80,9 @@ CPU_FEATURES_START_CPP_NAMESPACE #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) // http://elixir.free-electrons.com/linux/latest/source/arch/arm/include/uapi/asm/hwcap.h #define ARM_HWCAP_SWP (1UL << 0) @@ -114,6 +117,13 @@ CPU_FEATURES_START_CPP_NAMESPACE #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 @@ -166,6 +176,46 @@ CPU_FEATURES_START_CPP_NAMESPACE #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')) + typedef struct { unsigned long hwcaps; unsigned long hwcaps2; diff --git a/include/internal/windows_utils.h b/include/internal/windows_utils.h new file mode 100644 index 0000000..3348c52 --- /dev/null +++ b/include/internal/windows_utils.h @@ -0,0 +1,70 @@ +// 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 <windows.h> // 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_ diff --git a/scripts/generate_badges.d b/scripts/generate_badges.d new file mode 100644 index 0000000..bf5aa54 --- /dev/null +++ b/scripts/generate_badges.d @@ -0,0 +1,165 @@ +import std.algorithm : each, map, cartesianProduct, filter, joiner, sort, uniq; +import std.array : array; +import std.conv : to; +import std.format; +import std.range : chain, only; +import std.stdio; +import std.traits : EnumMembers; + +enum BuildSystem +{ + CMake, + Bazel +} + +enum Cpu +{ + amd64, + AArch64, + ARM, + MIPS, + POWER, + RISCV, + s390x, +} + +enum Os +{ + Linux, + FreeBSD, + MacOS, + Windows, +} + +struct Badge +{ +const: + + Cpu cpu; + Os os; + BuildSystem build_system; + + string id() + { + return format("%d%c%d", cast(uint)(os) + 1, cast(char)('a' + cpu), cast(uint)(build_system)); + } + + string disabled_image_ref() + { + return format("[d%d]", cast(uint)(build_system)); + } + + string link_ref() + { + return format("[l%s]", id()); + } + + string image_ref() + { + return format("[i%s]", id()); + } + + bool enabled() + { + final switch (build_system) + { + case BuildSystem.CMake: + return os == Os.Linux || cpu == Cpu.amd64; + case BuildSystem.Bazel: + return os == Os.Linux && cpu == Cpu.amd64; + } + } + + string text() + { + if (enabled()) + return format("[![]%s]%s", image_ref, link_ref); + return format("![]%s", disabled_image_ref); + } + + string disabled_image_link() + { + return format("%s: https://img.shields.io/badge/%s-N%%2FA-lightgrey", disabled_image_ref, build_system); + } + + string filename() + { + import std.uni : toLower; + + return toLower(format("%s_%s_%s.yml", cpu, os, build_system)); + } + + string link_decl() + { + return format("%s: https://github.com/google/cpu_features/actions/workflows/%s", link_ref, filename()); + } + + string image_decl() + { + return format( + "%s: https://img.shields.io/github/actions/workflow/status/google/cpu_features/%s?branch=main&label=%s", image_ref, filename(), build_system); + } +} + +auto tableHeader(in Cpu[] cpus) +{ + return chain(only("Os"), cpus.map!(to!string)).array; +} + +auto tableAlignment(in Cpu[] cpus) +{ + return chain(only(":--"), cpus.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("<br/>") + .to!string; +} + +auto tableRow(Range)(in Os os, in Cpu[] cpus, Range badges) +{ + return chain(only(os.to!string), cpus.map!(cpu => tableCell(os, cpu, badges))).array; +} + +auto tableRows(Range)(in Os[] oses, in Cpu[] cpus, Range badges) +{ + return oses.map!(os => tableRow(os, cpus, badges)).array; +} + +auto table(Range)(in Os[] oses, in Cpu[] cpus, Range badges) +{ + return chain(only(tableHeader(cpus)), only(tableAlignment(cpus)), 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; +} diff --git a/scripts/make_release.sh b/scripts/make_release.sh index 01e85f7..25b59f9 100755 --- a/scripts/make_release.sh +++ b/scripts/make_release.sh @@ -69,4 +69,7 @@ git commit -m"Release ${GIT_TAG}" echo -e "${ACTION}Create new tag${NOCOLOR}" git tag ${GIT_TAG} -echo -e "${FINISHED}Local release is ready. Run `git push origin --tags`${NOCOLOR}" +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}" diff --git a/scripts/run_integration.sh b/scripts/run_integration.sh index 645cb6a..053ffa9 100755 --- a/scripts/run_integration.sh +++ b/scripts/run_integration.sh @@ -22,7 +22,7 @@ function unpack() { if [[ ! -d "${DESTINATION}" ]] ; then echo "Downloading ${URL}..." local -r ARCHIVE_NAME=$(basename "${URL}") - test -f "${ARCHIVE_NAME}" || wget --no-verbose "${URL}" + [[ -f "${ARCHIVE_NAME}" ]] || wget --no-verbose "${URL}" extract "${ARCHIVE_NAME}" rm -f "${ARCHIVE_NAME}" fi @@ -33,7 +33,7 @@ function install_qemu() { >&2 echo 'QEMU is disabled !' return 0 fi - local -r QEMU_VERSION=${QEMU_VERSION:=5.2.0} + 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 @@ -70,11 +70,7 @@ function install_qemu() { --disable-opengl \ --disable-sdl \ --disable-virglrenderer \ - --disable-vte \ - --enable-modules - - # --static Not supported on Archlinux - # so we use --enable-modules + --disable-vte # wrapper on ninja make -j8 @@ -140,16 +136,107 @@ QEMU_ARGS+=( -L "${SYSROOT_DIR}" ) QEMU_ARGS+=( -E LD_LIBRARY_PATH=/lib ) } +function expand_bootlin_config() { + # ref: https://toolchains.bootlin.com/ + local -r GCC_DIR=${ARCHIVE_DIR}/${GCC_RELATIVE_DIR} + + case "${TARGET}" in + "aarch64") + local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/aarch64/tarballs/aarch64--glibc--stable-2021.11-1.tar.bz2" + local -r GCC_PREFIX="aarch64" + ;; + "aarch64be") + local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/aarch64be/tarballs/aarch64be--glibc--stable-2021.11-1.tar.bz2" + local -r GCC_PREFIX="aarch64_be" + ;; + "ppc64le") + local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/powerpc64le-power8/tarballs/powerpc64le-power8--glibc--stable-2021.11-1.tar.bz2" + local -r GCC_PREFIX="powerpc64le" + ;; + "ppc64") + local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/powerpc64-power8/tarballs/powerpc64-power8--glibc--stable-2021.11-1.tar.bz2" + local -r GCC_PREFIX="powerpc64" + ;; + "ppc") + #local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/powerpc-e500mc/tarballs/powerpc-e500mc--glibc--stable-2021.11-1.tar.bz2" + local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/powerpc-440fp/tarballs/powerpc-440fp--glibc--stable-2021.11-1.tar.bz2" + local -r GCC_PREFIX="powerpc" + ;; + "riscv32") + local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/riscv32-ilp32d/tarballs/riscv32-ilp32d--glibc--bleeding-edge-2022.08-1.tar.bz2" + local -r GCC_PREFIX="riscv32" + ;; + "riscv64") + local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/riscv64-lp64d/tarballs/riscv64-lp64d--glibc--stable-2022.08-1.tar.bz2" + local -r GCC_PREFIX="riscv64" + ;; + "s390x") + local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/s390x-z13/tarballs/s390x-z13--glibc--stable-2022.08-1.tar.bz2" + local -r GCC_PREFIX="s390x" + ;; + *) + >&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}" <<EOL +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR ${GCC_PREFIX}) + +set(CMAKE_SYSROOT ${SYSROOT_DIR}) +#set(CMAKE_STAGING_PREFIX ${STAGING_DIR}) + +set(tools ${TOOLCHAIN_DIR}) + +set(CMAKE_C_COMPILER \${tools}/bin/${GCC_PREFIX}-linux-gcc) +set(CMAKE_C_FLAGS "${POWER_FLAGS}") +set(CMAKE_CXX_COMPILER \${tools}/bin/${GCC_PREFIX}-linux-g++) +set(CMAKE_CXX_FLAGS "${POWER_FLAGS} -L${SYSROOT_DIR}/lib") + +set(CMAKE_FIND_ROOT_PATH ${TOOLCHAIN_DIR}) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) +EOL + +CMAKE_ADDITIONAL_ARGS+=( -DCMAKE_TOOLCHAIN_FILE="${TOOLCHAIN_FILE}" ) +QEMU_ARGS+=( -L "${SYSROOT_DIR}" ) +QEMU_ARGS+=( -E LD_PRELOAD="${SYSROOT_DIR}/usr/lib/libstdc++.so.6:${SYSROOT_DIR}/lib/libgcc_s.so.1" ) +} + function expand_codescape_config() { + # https://www.mips.com/develop/tools/codescape-mips-sdk/mips-toolchain-configurations/ + # mips-mti: MIPS32R6 and MIPS64R6 + # mips-img: MIPS32R2 and MIPS64R2 + # ref: https://codescape.mips.com/components/toolchain/2020.06-01/downloads.html - # ref: https://codescape.mips.com/components/toolchain/2019.02-04/downloads.html local -r DATE=2020.06-01 - #local -r DATE=2019.02-04 local -r CODESCAPE_URL=https://codescape.mips.com/components/toolchain/${DATE}/Codescape.GNU.Tools.Package.${DATE}.for.MIPS.MTI.Linux.CentOS-6.x86_64.tar.gz - #local -r CODESCAPE_URL=https://codescape.mips.com/components/toolchain/${DATE}/Codescape.GNU.Tools.Package.${DATE}.for.MIPS.IMG.Linux.CentOS-6.x86_64.tar.gz - local -r GCC_URL=${CODESCAPE_URL} local -r GCC_RELATIVE_DIR="mips-mti-linux-gnu/${DATE}" + + # ref: https://codescape.mips.com/components/toolchain/2019.02-04/downloads.html + #local -r DATE=2019.02-04 + #local -r CODESCAPE_URL=https://codescape.mips.com/components/toolchain/${DATE}/Codescape.GNU.Tools.Package.${DATE}.for.MIPS.IMG.Linux.CentOS-6.x86_64.tar.gz #local -r GCC_RELATIVE_DIR="mips-img-linux-gnu/${DATE}" + + local -r GCC_URL=${CODESCAPE_URL} unpack "${GCC_URL}" "${GCC_RELATIVE_DIR}" local -r GCC_DIR=${ARCHIVE_DIR}/${GCC_RELATIVE_DIR} @@ -174,12 +261,14 @@ function expand_codescape_config() { "mips64") MIPS_FLAGS="-EB -mips64r6 -mabi=64" FLAVOUR="mips-r6-hard" + #MIPS_FLAGS="-EB -mips64r2 -mabi=64" #FLAVOUR="mips-r2-hard" LIBC_DIR_SUFFIX="lib64" ;; "mips64el") MIPS_FLAGS="-EL -mips64r6 -mabi=64" FLAVOUR="mipsel-r6-hard" + #MIPS_FLAGS="-EL -mips64r2 -mabi=64" #FLAVOUR="mipsel-r2-hard" LIBC_DIR_SUFFIX="lib64" ;; @@ -203,13 +292,17 @@ set(CMAKE_STAGING_PREFIX ${STAGING_DIR}) set(tools ${GCC_DIR}) +# R6 set(CMAKE_C_COMPILER \${tools}/bin/mips-mti-linux-gnu-gcc) -#set(CMAKE_C_COMPILER \${tools}/bin/mips-img-linux-gnu-gcc) set(CMAKE_C_FLAGS "${MIPS_FLAGS}") - set(CMAKE_CXX_COMPILER \${tools}/bin/mips-mti-linux-gnu-g++) +set(CMAKE_CXX_FLAGS "${MIPS_FLAGS} -L${SYSROOT_DIR}/usr/lib64") + +# R2 +#set(CMAKE_C_COMPILER \${tools}/bin/mips-img-linux-gnu-gcc) +#set(CMAKE_C_FLAGS "${MIPS_FLAGS}") #set(CMAKE_CXX_COMPILER \${tools}/bin/mips-img-linux-gnu-g++) -set(CMAKE_CXX_FLAGS "${MIPS_FLAGS}") +#set(CMAKE_CXX_FLAGS "${MIPS_FLAGS}") set(CMAKE_FIND_ROOT_PATH ${GCC_DIR}) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) @@ -244,10 +337,15 @@ function run_test() { 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 - for test_binary in "${BUILD_DIR}"/list_cpu_feature* ; do + set -e + for test_binary in ${TEST_BINARIES[*]} ; do ${RUN_CMD} "${test_binary}" done + set +e set +x } @@ -264,11 +362,16 @@ DESCRIPTION \tYou MUST define the following variables before running this script: \t* TARGET: \t\tx86_64 -\t\taarch64-linux-gnu aarch64_be-linux-gnu -\t\tarm-linux-gnueabihf armv8l-linux-gnueabihf arm-linux-gnueabi -\t\tarmeb-linux-gnueabihf armeb-linux-gnueabi -\t\tmips32 mips32el -\t\tmips64 mips64el +\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 @@ -326,7 +429,13 @@ function main() { declare -r QEMU_ARCH=aarch64 ;; aarch64_be-linux-gnu) expand_linaro_config - declare -r QEMU_ARCH=DISABLED ;; + 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 ;; @@ -339,6 +448,24 @@ function main() { 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 ;; diff --git a/src/impl_aarch64_linux_or_android.c b/src/impl_aarch64_linux_or_android.c index 745beb9..ef923d9 100644 --- a/src/impl_aarch64_linux_or_android.c +++ b/src/impl_aarch64_linux_or_android.c @@ -74,7 +74,10 @@ 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_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) #define INTROSPECTION_PREFIX Aarch64 #define INTROSPECTION_ENUM_PREFIX AARCH64 #include "define_introspection_and_hwcaps.inl" diff --git a/src/impl_aarch64_windows.c b/src/impl_aarch64_windows.c new file mode 100644 index 0000000..f103909 --- /dev/null +++ b/src/impl_aarch64_windows.c @@ -0,0 +1,138 @@ +// 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 <stdbool.h> + +#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 diff --git a/src/impl_mips_linux_or_android.c b/src/impl_mips_linux_or_android.c index 9a3dc2f..2322ecf 100644 --- a/src/impl_mips_linux_or_android.c +++ b/src/impl_mips_linux_or_android.c @@ -20,10 +20,15 @@ //////////////////////////////////////////////////////////////////////////////// // 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) +#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" diff --git a/src/impl_ppc_linux.c b/src/impl_ppc_linux.c index 13a381a..46a72d7 100644 --- a/src/impl_ppc_linux.c +++ b/src/impl_ppc_linux.c @@ -69,6 +69,7 @@ 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" diff --git a/src/impl_riscv_linux.c b/src/impl_riscv_linux.c new file mode 100644 index 0000000..8abec6e --- /dev/null +++ b/src/impl_riscv_linux.c @@ -0,0 +1,111 @@ +// 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 <stdbool.h> +#include <stdio.h> + +#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 diff --git a/src/impl_s390x_linux.c b/src/impl_s390x_linux.c new file mode 100644 index 0000000..2b8b865 --- /dev/null +++ b/src/impl_s390x_linux.c @@ -0,0 +1,120 @@ +// 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 <stdbool.h> + +#include "internal/bit_utils.h" +#include "internal/filesystem.h" +#include "internal/hwcaps.h" +#include "internal/stack_line_reader.h" +#include "internal/string_view.h" + +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 diff --git a/src/impl_x86__base_implementation.inl b/src/impl_x86__base_implementation.inl index 09f24b2..6a34bff 100644 --- a/src/impl_x86__base_implementation.inl +++ b/src/impl_x86__base_implementation.inl @@ -13,6 +13,76 @@ // 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 <stdbool.h> #include <string.h> @@ -98,7 +168,7 @@ typedef struct { Leaf leaf_80000004; // brand string } Leaves; -static Leaves ReadLeaves() { +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); @@ -121,7 +191,6 @@ static Leaves ReadLeaves() { //////////////////////////////////////////////////////////////////////////////// // OS support -// TODO: Add documentation //////////////////////////////////////////////////////////////////////////////// #define MASK_XMM 0x2 @@ -254,6 +323,7 @@ static void ParseCpuId(const Leaves* leaves, X86Info* info, const Leaf leaf_1 = leaves->leaf_1; const Leaf leaf_7 = leaves->leaf_7; const Leaf leaf_7_1 = leaves->leaf_7_1; + const Leaf leaf_80000001 = leaves->leaf_80000001; const bool have_xsave = IsBitSet(leaf_1.ecx, 26); const bool have_osxsave = IsBitSet(leaf_1.ecx, 27); @@ -309,9 +379,17 @@ static void ParseCpuId(const Leaves* leaves, X86Info* info, 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); ///////////////////////////////////////////////////////////////////////////// // The following section is devoted to Vector Extensions. @@ -340,6 +418,7 @@ static void ParseCpuId(const Leaves* leaves, X86Info* info, 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) { @@ -362,6 +441,7 @@ static void ParseCpuId(const Leaves* leaves, X86Info* 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); @@ -406,8 +486,8 @@ X86Info GetX86Info(void) { IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); const bool is_hygon = IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_HYGON_GENUINE); - const bool is_zhaoxin = - (IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_CENTAUR_HAULS) || + const bool is_zhaoxin = + (IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_CENTAUR_HAULS) || IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_SHANGHAI)); SetVendor(leaves.leaf_0, info.vendor); if (is_intel || is_amd || is_hygon || is_zhaoxin) { @@ -463,6 +543,15 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info) { 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) @@ -503,10 +592,15 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info) { // https://en.wikipedia.org/wiki/Broadwell_(microarchitecture) return INTEL_BDW; case CPUID(0x06, 0x4E): - case CPUID(0x06, 0x55): 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; @@ -532,6 +626,8 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info) { 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; } @@ -547,9 +643,18 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info) { case CPUID(0x06, 0x9A): // 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; @@ -580,15 +685,15 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info) { // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/zhangjiang return ZHAOXIN_ZHANGJIANG; case CPUID(0x07, 0x1B): - // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/wudaokou - return ZHAOXIN_WUDAOKOU; + // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/wudaokou + return ZHAOXIN_WUDAOKOU; case CPUID(0x07, 0x3B): - // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/lujiazui - return ZHAOXIN_LUJIAZUI; + // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/lujiazui + return ZHAOXIN_LUJIAZUI; case CPUID(0x07, 0x5B): - return ZHAOXIN_YONGFENG; + return ZHAOXIN_YONGFENG; default: - return X86_UNKNOWN; + return X86_UNKNOWN; } } if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_SHANGHAI)) { @@ -598,15 +703,15 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info) { // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/zhangjiang return ZHAOXIN_ZHANGJIANG; case CPUID(0x07, 0x1B): - // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/wudaokou - return ZHAOXIN_WUDAOKOU; + // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/wudaokou + return ZHAOXIN_WUDAOKOU; case CPUID(0x07, 0x3B): - // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/lujiazui - return ZHAOXIN_LUJIAZUI; + // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/lujiazui + return ZHAOXIN_LUJIAZUI; case CPUID(0x07, 0x5B): - return ZHAOXIN_YONGFENG; + return ZHAOXIN_YONGFENG; default: - return X86_UNKNOWN; + return X86_UNKNOWN; } } if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_AUTHENTIC_AMD)) { @@ -659,6 +764,7 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info) { 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; @@ -671,9 +777,11 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info) { // 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): @@ -685,6 +793,7 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info) { // 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; @@ -704,15 +813,23 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info) { case CPUID(0x17, 0x71): 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, 0x61): + // https://en.wikichip.org/wiki/amd/microarchitectures/zen_4 + return AMD_ZEN4; default: return X86_UNKNOWN; } @@ -720,6 +837,7 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info) { 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; } } @@ -1629,16 +1747,18 @@ static void ParseCacheInfo(const int max_cpuid_leaf, uint32_t leaf_id, 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 == 0) - break; - else if (cache_type_field == 1) + 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 - break; // Should not occur as per documentation. + // 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; @@ -1659,6 +1779,115 @@ static void ParseCacheInfo(const int max_cpuid_leaf, uint32_t leaf_id, 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(); @@ -1674,6 +1903,8 @@ CacheInfo GetX86CacheInfo(void) { // 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; @@ -1710,6 +1941,7 @@ CacheInfo GetX86CacheInfo(void) { 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, , , ) \ @@ -1730,6 +1962,7 @@ CacheInfo GetX86CacheInfo(void) { 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, , , ) \ @@ -1743,7 +1976,15 @@ CacheInfo GetX86CacheInfo(void) { LINE(X86_RDRND, rdrnd, , , ) \ LINE(X86_DCA, dca, , , ) \ LINE(X86_SS, ss, , , ) \ - LINE(X86_ADX, adx, , , ) + LINE(X86_ADX, adx, , , ) \ + LINE(X86_LZCNT, lzcnt, , , ) \ + 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, , , ) #define INTROSPECTION_PREFIX X86 #define INTROSPECTION_ENUM_PREFIX X86 #include "define_introspection.inl" @@ -1768,16 +2009,21 @@ CacheInfo GetX86CacheInfo(void) { 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) \ @@ -1797,7 +2043,8 @@ CacheInfo GetX86CacheInfo(void) { LINE(AMD_ZEN) \ LINE(AMD_ZEN_PLUS) \ LINE(AMD_ZEN2) \ - LINE(AMD_ZEN3) + LINE(AMD_ZEN3) \ + LINE(AMD_ZEN4) const char* GetX86MicroarchitectureName(X86Microarchitecture value) { #define LINE(ENUM) [ENUM] = STRINGIZE(ENUM), diff --git a/src/impl_x86_windows.c b/src/impl_x86_windows.c index 0b330d0..8a82823 100644 --- a/src/impl_x86_windows.c +++ b/src/impl_x86_windows.c @@ -24,7 +24,7 @@ static void OverrideOsPreserves(OsPreserves* os_preserves) { // No override } -#include <windows.h> // IsProcessorFeaturePresent +#include "internal/windows_utils.h" #if defined(CPU_FEATURES_MOCK_CPUID_X86) extern bool GetWindowsIsProcessorFeaturePresent(DWORD); @@ -43,15 +43,15 @@ static void DetectFeaturesFromOs(X86Info* info, X86Features* features) { GetWindowsIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE); features->sse3 = GetWindowsIsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE); - -// https://github.com/google/cpu_features/issues/200 -#if (_WIN32_WINNT >= 0x0601) // Win7+ - if (GetX86Microarchitecture(info) == INTEL_WSM) { - features->ssse3 = true; - features->sse4_1 = true; - features->sse4_2 = true; - } -#endif + 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 diff --git a/src/utils/list_cpu_features.c b/src/utils/list_cpu_features.c index 0b4eb7a..8226d85 100644 --- a/src/utils/list_cpu_features.c +++ b/src/utils/list_cpu_features.c @@ -35,6 +35,10 @@ #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" #endif // Design principles @@ -54,18 +58,18 @@ char gGlobalBuffer[64 * 1024]; BumpAllocator gBumpAllocator = {.ptr = gGlobalBuffer, .size = sizeof(gGlobalBuffer)}; -static void internal_error() { +static void internal_error(void) { fputs("internal error\n", stderr); exit(EXIT_FAILURE); } #define ALIGN 8 -static void assertAligned() { +static void assertAligned(void) { if ((uintptr_t)(gBumpAllocator.ptr) % ALIGN) internal_error(); } -static void BA_Align() { +static void BA_Align(void) { while (gBumpAllocator.size && (uintptr_t)(gBumpAllocator.ptr) % ALIGN) { --gBumpAllocator.size; ++gBumpAllocator.ptr; @@ -129,10 +133,10 @@ static Node* CreateConstantString(const char* value) { } // Adds a map node. -static Node* CreateMap() { return BA_CreateNode(NT_MAP); } +static Node* CreateMap(void) { return BA_CreateNode(NT_MAP); } // Adds an array node. -static Node* CreateArray() { return BA_CreateNode(NT_ARRAY); } +static Node* CreateArray(void) { return BA_CreateNode(NT_ARRAY); } // Adds a formatted string node. static Node* CreatePrintfString(const char* format, ...) { @@ -205,6 +209,12 @@ DEFINE_ADD_FLAGS(GetMipsFeaturesEnumValue, GetMipsFeaturesEnumName, #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_) #endif // Prints a json string with characters escaping. @@ -360,15 +370,13 @@ static void AddCacheInfo(Node* root, const CacheInfo* cache_info) { AddMapEntry(root, "cache_info", array); } -static Node* CreateTree() { +static Node* CreateTree(void) { Node* root = CreateMap(); #if defined(CPU_FEATURES_ARCH_X86) - char brand_string[49]; const X86Info info = GetX86Info(); const CacheInfo cache_info = GetX86CacheInfo(); - FillX86BrandString(brand_string); AddMapEntry(root, "arch", CreateString("x86")); - AddMapEntry(root, "brand", CreateString(brand_string)); + 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)); @@ -410,6 +418,20 @@ static Node* CreateTree() { 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); #endif return root; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8e8f72a..f627d74 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -71,7 +71,11 @@ endif() ##------------------------------------------------------------------------------ ## cpuinfo_aarch64_test if(PROCESSOR_IS_AARCH64) - add_executable(cpuinfo_aarch64_test cpuinfo_aarch64_test.cc ../src/impl_aarch64_linux_or_android.c) + add_executable(cpuinfo_aarch64_test + cpuinfo_aarch64_test.cc + ../src/impl_aarch64_linux_or_android.c + ../src/impl_aarch64_windows.c) + target_compile_definitions(cpuinfo_aarch64_test PUBLIC CPU_FEATURES_MOCK_CPUID_AARCH64) target_link_libraries(cpuinfo_aarch64_test all_libraries) add_test(NAME cpuinfo_aarch64_test COMMAND cpuinfo_aarch64_test) endif() @@ -89,3 +93,17 @@ if(PROCESSOR_IS_POWER) 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() diff --git a/test/cpuinfo_aarch64_test.cc b/test/cpuinfo_aarch64_test.cc index 04b6143..ef9abae 100644 --- a/test/cpuinfo_aarch64_test.cc +++ b/test/cpuinfo_aarch64_test.cc @@ -14,13 +14,86 @@ #include "cpuinfo_aarch64.h" +#include <set> + #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 { + public: +#if defined(CPU_FEATURES_OS_WINDOWS) + 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; + } + + private: + std::set<DWORD> windows_isprocessorfeaturepresent_; + WORD processor_revision_{}; +#endif // CPU_FEATURES_OS_WINDOWS +}; + +static FakeCpuAarch64* g_fake_cpu_instance = nullptr; + +static FakeCpuAarch64& cpu() { + assert(g_fake_cpu_instance != nullptr); + return *g_fake_cpu_instance; +} + +#if defined(CPU_FEATURES_OS_WINDOWS) +extern "C" bool GetWindowsIsProcessorFeaturePresent(DWORD dwProcessorFeature) { + return cpu().GetWindowsIsProcessorFeaturePresent(dwProcessorFeature); +} + +extern "C" WORD GetWindowsNativeSystemInfoProcessorRevision() { + return cpu().GetWindowsNativeSystemInfoProcessorRevision(); +} +#endif // CPU_FEATURES_OS_WINDOWS + 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(CpuinfoAarch64Test, Aarch64FeaturesEnum) { + const char* last_name = GetAarch64FeaturesEnumName(AARCH64_LAST_); + EXPECT_STREQ(last_name, "unknown_feature"); + for (int i = static_cast<int>(AARCH64_FP); + i != static_cast<int>(AARCH64_LAST_); ++i) { + const auto feature = static_cast<Aarch64FeaturesEnum>(i); + const char* name = GetAarch64FeaturesEnumName(feature); + ASSERT_FALSE(name == nullptr); + EXPECT_STRNE(name, ""); + EXPECT_STRNE(name, last_name); + } +} + +#if defined(CPU_FEATURES_OS_LINUX) void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); } TEST(CpuinfoAarch64Test, FromHardwareCap) { @@ -168,7 +241,36 @@ CPU revision : 3)"); 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); +} +#endif // CPU_FEATURES_OS_LINUX + +#if 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 diff --git a/test/cpuinfo_arm_test.cc b/test/cpuinfo_arm_test.cc index ad7f4e8..745b2af 100644 --- a/test/cpuinfo_arm_test.cc +++ b/test/cpuinfo_arm_test.cc @@ -21,6 +21,18 @@ 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<int>(ARM_SWP); i != static_cast<int>(ARM_LAST_); ++i) { + const auto feature = static_cast<ArmFeaturesEnum>(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); diff --git a/test/cpuinfo_mips_test.cc b/test/cpuinfo_mips_test.cc index a01624a..02ca6c9 100644 --- a/test/cpuinfo_mips_test.cc +++ b/test/cpuinfo_mips_test.cc @@ -24,6 +24,18 @@ 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<int>(MIPS_MSA); i != static_cast<int>(MIPS_LAST_); ++i) { + const auto feature = static_cast<MipsFeaturesEnum>(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); @@ -69,6 +81,12 @@ 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) { @@ -95,6 +113,7 @@ 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) { @@ -122,5 +141,36 @@ VCEI exceptions : not available 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 diff --git a/test/cpuinfo_ppc_test.cc b/test/cpuinfo_ppc_test.cc index b43a7c8..fc8d288 100644 --- a/test/cpuinfo_ppc_test.cc +++ b/test/cpuinfo_ppc_test.cc @@ -22,6 +22,18 @@ 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<int>(PPC_32); i != static_cast<int>(PPC_LAST_); ++i) { + const auto feature = static_cast<PPCFeaturesEnum>(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, diff --git a/test/cpuinfo_riscv_test.cc b/test/cpuinfo_riscv_test.cc new file mode 100644 index 0000000..2ffe2b3 --- /dev/null +++ b/test/cpuinfo_riscv_test.cc @@ -0,0 +1,180 @@ +// 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 diff --git a/test/cpuinfo_s390x_test.cc b/test/cpuinfo_s390x_test.cc new file mode 100644 index 0000000..800d3e9 --- /dev/null +++ b/test/cpuinfo_s390x_test.cc @@ -0,0 +1,82 @@ +// 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<int>(S390_ZARCH); i != static_cast<int>(S390X_LAST_); ++i) { + const auto feature = static_cast<S390XFeaturesEnum>(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 diff --git a/test/cpuinfo_x86_test.cc b/test/cpuinfo_x86_test.cc index 56243b9..de271cc 100644 --- a/test/cpuinfo_x86_test.cc +++ b/test/cpuinfo_x86_test.cc @@ -19,8 +19,8 @@ #include <map> #include <set> #if defined(CPU_FEATURES_OS_WINDOWS) -#include <windows.h> // IsProcessorFeaturePresent -#endif // CPU_FEATURES_OS_WINDOWS +#include "internal/windows_utils.h" +#endif // CPU_FEATURES_OS_WINDOWS #include "filesystem_for_testing.h" #include "gtest/gtest.h" @@ -118,6 +118,30 @@ class CpuidX86Test : public ::testing::Test { } }; +TEST_F(CpuidX86Test, X86MicroarchitectureEnum) { + const char *last_name = GetX86MicroarchitectureName(X86_MICROARCHITECTURE_LAST_); + EXPECT_STREQ(last_name, "unknown microarchitecture"); + for (int i = static_cast<int>(X86_UNKNOWN); i != static_cast<int>(X86_MICROARCHITECTURE_LAST_); ++i) { + const auto micro = static_cast<X86Microarchitecture>(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<int>(X86_FPU); i != static_cast<int>(X86_LAST_); ++i) { + const auto feature = static_cast<X86FeaturesEnum>(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({ @@ -126,7 +150,7 @@ TEST_F(CpuidX86Test, SandyBridge) { {{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "GenuineIntel"); + EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x02A); EXPECT_EQ(info.stepping, 0x06); @@ -188,13 +212,41 @@ TEST_F(CpuidX86Test, SkyLake) { {{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}}, }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "GenuineIntel"); + 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}}, @@ -206,9 +258,8 @@ TEST_F(CpuidX86Test, Branding) { {{0x80000003, 0}, Leaf{0x37692029, 0x3035362D, 0x43205530, 0x40205550}}, {{0x80000004, 0}, Leaf{0x352E3220, 0x7A484730, 0x00000000, 0x00000000}}, }); - char brand_string[49]; - FillX86BrandString(brand_string); - EXPECT_STREQ(brand_string, "Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz"); + const auto info = GetX86Info(); + EXPECT_STREQ(info.brand_string, "Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz"); } TEST_F(CpuidX86Test, KabyLakeCache) { @@ -228,7 +279,7 @@ TEST_F(CpuidX86Test, KabyLakeCache) { const auto info = GetX86CacheInfo(); EXPECT_EQ(info.size, 4); EXPECT_EQ(info.levels[0].level, 1); - EXPECT_EQ(info.levels[0].cache_type, 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); @@ -236,7 +287,8 @@ TEST_F(CpuidX86Test, KabyLakeCache) { EXPECT_EQ(info.levels[0].partitioning, 1); EXPECT_EQ(info.levels[1].level, 1); - EXPECT_EQ(info.levels[1].cache_type, 2); + 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); @@ -244,7 +296,7 @@ TEST_F(CpuidX86Test, KabyLakeCache) { EXPECT_EQ(info.levels[1].partitioning, 1); EXPECT_EQ(info.levels[2].level, 2); - EXPECT_EQ(info.levels[2].cache_type, 3); + 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); @@ -252,7 +304,7 @@ TEST_F(CpuidX86Test, KabyLakeCache) { EXPECT_EQ(info.levels[2].partitioning, 1); EXPECT_EQ(info.levels[3].level, 3); - EXPECT_EQ(info.levels[3].cache_type, 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); @@ -277,7 +329,7 @@ TEST_F(CpuidX86Test, HSWCache) { const auto info = GetX86CacheInfo(); EXPECT_EQ(info.size, 4); EXPECT_EQ(info.levels[0].level, 1); - EXPECT_EQ(info.levels[0].cache_type, 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); @@ -285,7 +337,8 @@ TEST_F(CpuidX86Test, HSWCache) { EXPECT_EQ(info.levels[0].partitioning, 1); EXPECT_EQ(info.levels[1].level, 1); - EXPECT_EQ(info.levels[1].cache_type, 2); + 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); @@ -293,7 +346,7 @@ TEST_F(CpuidX86Test, HSWCache) { EXPECT_EQ(info.levels[1].partitioning, 1); EXPECT_EQ(info.levels[2].level, 2); - EXPECT_EQ(info.levels[2].cache_type, 3); + 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); @@ -301,7 +354,7 @@ TEST_F(CpuidX86Test, HSWCache) { EXPECT_EQ(info.levels[2].partitioning, 1); EXPECT_EQ(info.levels[3].level, 3); - EXPECT_EQ(info.levels[3].cache_type, 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); @@ -319,7 +372,7 @@ TEST_F(CpuidX86Test, AMD_K11_GRIFFIN) { }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "AuthenticAMD"); + 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); @@ -335,7 +388,7 @@ TEST_F(CpuidX86Test, AMD_K12_LLANO) { }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "AuthenticAMD"); + 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); @@ -351,7 +404,7 @@ TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F01) { }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "AuthenticAMD"); + 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); @@ -375,7 +428,7 @@ TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F10) { }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "AuthenticAMD"); + 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); @@ -391,7 +444,7 @@ TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F20) { }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "AuthenticAMD"); + 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); @@ -411,17 +464,13 @@ TEST_F(CpuidX86Test, AMD_K15_EXCAVATOR_STONEY_RIDGE) { }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "AuthenticAMD"); + 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); - - char brand_string[49]; - FillX86BrandString(brand_string); - EXPECT_STREQ(brand_string, "AMD A9-9410 RADEON R5, 5 COMPUTE CORES 2C+3G "); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F20_K15_AbuDhabi_CPUID0.txt @@ -438,7 +487,7 @@ TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_ABU_DHABI) { }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "AuthenticAMD"); + EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x15); EXPECT_EQ(info.model, 0x02); EXPECT_STREQ(info.brand_string, @@ -446,9 +495,7 @@ TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_ABU_DHABI) { EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_PILEDRIVER); - char brand_string[49]; - FillX86BrandString(brand_string); - EXPECT_STREQ(brand_string, "AMD Opteron(tm) Processor 6376 "); + EXPECT_STREQ(info.brand_string, "AMD Opteron(tm) Processor 6376 "); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F20_K15_AbuDhabi_CPUID0.txt @@ -467,7 +514,7 @@ TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_ABU_DHABI_CACHE_INFO) { EXPECT_EQ(info.size, 4); EXPECT_EQ(info.levels[0].level, 1); - EXPECT_EQ(info.levels[0].cache_type, 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); @@ -475,7 +522,8 @@ TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_ABU_DHABI_CACHE_INFO) { EXPECT_EQ(info.levels[0].partitioning, 1); EXPECT_EQ(info.levels[1].level, 1); - EXPECT_EQ(info.levels[1].cache_type, 2); + 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); @@ -483,7 +531,7 @@ TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_ABU_DHABI_CACHE_INFO) { EXPECT_EQ(info.levels[1].partitioning, 1); EXPECT_EQ(info.levels[2].level, 2); - EXPECT_EQ(info.levels[2].cache_type, 3); + 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); @@ -491,7 +539,7 @@ TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_ABU_DHABI_CACHE_INFO) { EXPECT_EQ(info.levels[2].partitioning, 1); EXPECT_EQ(info.levels[3].level, 3); - EXPECT_EQ(info.levels[3].cache_type, 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); @@ -499,6 +547,29 @@ TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_ABU_DHABI_CACHE_INFO) { 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({ @@ -513,17 +584,13 @@ TEST_F(CpuidX86Test, AMD_K15_BULLDOZER_INTERLAGOS) { }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "AuthenticAMD"); + 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); - - char brand_string[49]; - FillX86BrandString(brand_string); - EXPECT_STREQ(brand_string, "AMD Opteron(TM) Processor 6238 "); } // http://users.atw.hu/instlatx64/AuthenticAMD0630F81_K15_Godavari_CPUID.txt @@ -541,7 +608,7 @@ TEST_F(CpuidX86Test, AMD_K15_STREAMROLLER_GODAVARI) { }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "AuthenticAMD"); + EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD); EXPECT_EQ(info.family, 0x15); EXPECT_EQ(info.model, 0x38); EXPECT_EQ(info.stepping, 0x01); @@ -549,10 +616,27 @@ TEST_F(CpuidX86Test, AMD_K15_STREAMROLLER_GODAVARI) { "AMD A8-7670K Radeon R7, 10 Compute Cores 4C+6G "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_STREAMROLLER); +} - char brand_string[49]; - FillX86BrandString(brand_string); - EXPECT_STREQ(brand_string, "AMD A8-7670K Radeon R7, 10 Compute Cores 4C+6G "); +// 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 @@ -569,16 +653,12 @@ TEST_F(CpuidX86Test, AMD_K16_JAGUAR_KABINI) { }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "AuthenticAMD"); + 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); - - char brand_string[49]; - FillX86BrandString(brand_string); - EXPECT_STREQ(brand_string, "AMD A4-5000 APU with Radeon(TM) HD Graphics "); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0730F01_K16_Beema_CPUID2.txt @@ -595,16 +675,34 @@ TEST_F(CpuidX86Test, AMD_K16_PUMA_BEEMA) { }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "AuthenticAMD"); + 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(); - char brand_string[49]; - FillX86BrandString(brand_string); - EXPECT_STREQ(brand_string, "AMD A6-6310 APU with AMD Radeon R4 Graphics "); + 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 @@ -621,16 +719,12 @@ TEST_F(CpuidX86Test, AMD_K17_ZEN_DALI) { }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "AuthenticAMD"); + 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); - - char brand_string[49]; - FillX86BrandString(brand_string); - EXPECT_STREQ(brand_string, "AMD 3020e with Radeon Graphics "); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0800F82_K17_ZenP_CPUID.txt @@ -647,16 +741,12 @@ TEST_F(CpuidX86Test, AMD_K17_ZEN_PLUS_PINNACLE_RIDGE) { }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "AuthenticAMD"); + 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); - - char brand_string[49]; - FillX86BrandString(brand_string); - EXPECT_STREQ(brand_string, "AMD Ryzen 7 2700X Eight-Core Processor "); } // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0840F70_K17_CPUID.txt @@ -673,15 +763,11 @@ TEST_F(CpuidX86Test, AMD_K17_ZEN2_XBOX_SERIES_X) { }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "AuthenticAMD"); + 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); - - char brand_string[49]; - FillX86BrandString(brand_string); - EXPECT_STREQ(brand_string, "AMD 4700S 8-Core Processor Desktop Kit"); } // http://users.atw.hu/instlatx64/HygonGenuine/HygonGenuine0900F02_Hygon_CPUID3.txt @@ -698,16 +784,12 @@ TEST_F(CpuidX86Test, AMD_K18_ZEN_DHYANA) { }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "HygonGenuine"); + 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); - - char brand_string[49]; - FillX86BrandString(brand_string); - EXPECT_STREQ(brand_string, "Hygon C86 3185 8-core Processor "); } // http://users.atw.hu/instlatx64/HygonGenuine/HygonGenuine0900F02_Hygon_CPUID.txt @@ -726,7 +808,7 @@ TEST_F(CpuidX86Test, AMD_K18_ZEN_DHYANA_CACHE_INFO) { EXPECT_EQ(info.size, 4); EXPECT_EQ(info.levels[0].level, 1); - EXPECT_EQ(info.levels[0].cache_type, 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); @@ -734,7 +816,8 @@ TEST_F(CpuidX86Test, AMD_K18_ZEN_DHYANA_CACHE_INFO) { EXPECT_EQ(info.levels[0].partitioning, 1); EXPECT_EQ(info.levels[1].level, 1); - EXPECT_EQ(info.levels[1].cache_type, 2); + 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); @@ -742,7 +825,7 @@ TEST_F(CpuidX86Test, AMD_K18_ZEN_DHYANA_CACHE_INFO) { EXPECT_EQ(info.levels[1].partitioning, 1); EXPECT_EQ(info.levels[2].level, 2); - EXPECT_EQ(info.levels[2].cache_type, 3); + 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); @@ -750,7 +833,7 @@ TEST_F(CpuidX86Test, AMD_K18_ZEN_DHYANA_CACHE_INFO) { EXPECT_EQ(info.levels[2].partitioning, 1); EXPECT_EQ(info.levels[3].level, 3); - EXPECT_EQ(info.levels[3].cache_type, 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); @@ -772,16 +855,342 @@ TEST_F(CpuidX86Test, AMD_K19_ZEN3_VERMEER) { }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "AuthenticAMD"); + 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}}, + }); + 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_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN4); +} + +// 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/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); - char brand_string[49]; - FillX86BrandString(brand_string); - EXPECT_STREQ(brand_string, "AMD Ryzen 9 5900X 12-Core Processor "); + 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 @@ -792,6 +1201,9 @@ TEST_F(CpuidX86Test, Nehalem) { 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"); @@ -844,7 +1256,7 @@ flags : fpu mmx sse sse2 pni ssse3 sse4_1 sse4_2 }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "GenuineIntel"); + EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x1A); EXPECT_EQ(info.stepping, 0x02); @@ -852,20 +1264,12 @@ flags : fpu mmx sse sse2 pni ssse3 sse4_1 sse4_2 "Genuine Intel(R) CPU @ 0000 @ 1.87GHz"); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_NHM); - char brand_string[49]; - FillX86BrandString(brand_string); - EXPECT_STREQ(brand_string, "Genuine Intel(R) CPU @ 0000 @ 1.87GHz"); - EXPECT_TRUE(info.features.sse); EXPECT_TRUE(info.features.sse2); EXPECT_TRUE(info.features.sse3); -#if !defined(CPU_FEATURES_OS_WINDOWS) - // Currently disabled on Windows as IsProcessorFeaturePresent do not support - // feature detection > sse3. EXPECT_TRUE(info.features.ssse3); EXPECT_TRUE(info.features.sse4_1); EXPECT_TRUE(info.features.sse4_2); -#endif // !defined(CPU_FEATURES_OS_WINDOWS) } // https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0030673_Silvermont3_CPUID.txt @@ -876,6 +1280,9 @@ TEST_F(CpuidX86Test, Atom) { 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"); @@ -927,7 +1334,7 @@ flags : fpu mmx sse sse2 pni ssse3 sse4_1 sse4_2 }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "GenuineIntel"); + EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL); EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x37); EXPECT_EQ(info.stepping, 0x03); @@ -936,20 +1343,12 @@ flags : fpu mmx sse sse2 pni ssse3 sse4_1 sse4_2 EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_ATOM_SMT); - char brand_string[49]; - FillX86BrandString(brand_string); - EXPECT_STREQ(brand_string, " Intel(R) Celeron(R) CPU J1900 @ 1.99GHz"); - EXPECT_TRUE(info.features.sse); EXPECT_TRUE(info.features.sse2); EXPECT_TRUE(info.features.sse3); -#if !defined(CPU_FEATURES_OS_WINDOWS) - // Currently disabled on Windows as IsProcessorFeaturePresent do not support - // feature detection > sse3. EXPECT_TRUE(info.features.ssse3); EXPECT_TRUE(info.features.sse4_1); EXPECT_TRUE(info.features.sse4_2); -#endif // !defined(CPU_FEATURES_OS_WINDOWS) } // https://www.felixcloutier.com/x86/cpuid#example-3-1--example-of-cache-and-tlb-interpretation @@ -964,7 +1363,7 @@ TEST_F(CpuidX86Test, P4_CacheInfo) { EXPECT_EQ(info.size, 5); EXPECT_EQ(info.levels[0].level, UNDEF); - EXPECT_EQ(info.levels[0].cache_type, CPU_FEATURE_CACHE_TLB); + 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); @@ -972,7 +1371,7 @@ TEST_F(CpuidX86Test, P4_CacheInfo) { EXPECT_EQ(info.levels[0].partitioning, 0); EXPECT_EQ(info.levels[1].level, UNDEF); - EXPECT_EQ(info.levels[1].cache_type, CPU_FEATURE_CACHE_TLB); + 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); @@ -980,7 +1379,7 @@ TEST_F(CpuidX86Test, P4_CacheInfo) { EXPECT_EQ(info.levels[1].partitioning, 0); EXPECT_EQ(info.levels[2].level, 1); - EXPECT_EQ(info.levels[2].cache_type, CPU_FEATURE_CACHE_DATA); + 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); @@ -988,7 +1387,8 @@ TEST_F(CpuidX86Test, P4_CacheInfo) { EXPECT_EQ(info.levels[2].partitioning, 0); EXPECT_EQ(info.levels[3].level, 1); - EXPECT_EQ(info.levels[3].cache_type, CPU_FEATURE_CACHE_INSTRUCTION); + 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); @@ -996,7 +1396,7 @@ TEST_F(CpuidX86Test, P4_CacheInfo) { EXPECT_EQ(info.levels[3].partitioning, 0); EXPECT_EQ(info.levels[4].level, 2); - EXPECT_EQ(info.levels[4].cache_type, CPU_FEATURE_CACHE_DATA); + 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); @@ -1035,28 +1435,20 @@ flags : fpu mmx sse }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "GenuineIntel"); + 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); - char brand_string[49]; - FillX86BrandString(brand_string); - EXPECT_STREQ(brand_string, ""); - EXPECT_TRUE(info.features.mmx); EXPECT_TRUE(info.features.sse); EXPECT_FALSE(info.features.sse2); EXPECT_FALSE(info.features.sse3); -#if !defined(CPU_FEATURES_OS_WINDOWS) - // Currently disabled on Windows as IsProcessorFeaturePresent do not support - // feature detection > sse3. EXPECT_FALSE(info.features.ssse3); EXPECT_FALSE(info.features.sse4_1); EXPECT_FALSE(info.features.sse4_2); -#endif // !defined(CPU_FEATURES_OS_WINDOWS) } // https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0000480_486_CPUID.txt @@ -1067,7 +1459,7 @@ TEST_F(CpuidX86Test, INTEL_80486) { }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "GenuineIntel"); + 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); @@ -1081,7 +1473,7 @@ TEST_F(CpuidX86Test, INTEL_P54C) { }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "GenuineIntel"); + 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); @@ -1095,13 +1487,42 @@ TEST_F(CpuidX86Test, INTEL_LAKEMONT) { }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "GenuineIntel"); + 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({ @@ -1110,17 +1531,177 @@ TEST_F(CpuidX86Test, INTEL_KNIGHTS_LANDING) { }); const auto info = GetX86Info(); - EXPECT_STREQ(info.vendor, "GenuineIntel"); + 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); +} + // 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}}, @@ -1131,15 +1712,12 @@ TEST_F(CpuidX86Test, WIN_INTEL_WESTMERE_EX) { EXPECT_EQ(info.model, 0x2F); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_WSM); -#if (_WIN32_WINNT < 0x0601) // before Win7 - EXPECT_FALSE(info.features.ssse3); - EXPECT_FALSE(info.features.sse4_1); - EXPECT_FALSE(info.features.sse4_2); -#else + 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 } #endif // CPU_FEATURES_OS_WINDOWS |