aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 05:10:17 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 05:10:17 +0000
commitf7d79e27dd8a224ff7f74d5ffca3b26681dc50f3 (patch)
tree69f578706d7adc704ef6026d51ba239aa31ce2b1
parent8a269f8eb4163c6b5aa0cfebfc4bd5dc5e9e436e (diff)
parent6d28abb49625745335bfa37dc3d0e704b21cd5f3 (diff)
downloadcpu_features-android14-mainline-uwb-release.tar.gz
Change-Id: I245ada7adcaf8d79518c2962e38da83be48870ff
-rw-r--r--.dockerignore31
-rw-r--r--.github/workflows/Dockerfile2
-rw-r--r--.github/workflows/aarch64_linux.yml28
-rw-r--r--.github/workflows/amd64_freebsd.yml22
-rw-r--r--.github/workflows/amd64_linux.yml31
-rw-r--r--.github/workflows/amd64_macos.yml43
-rw-r--r--.github/workflows/amd64_windows.yml25
-rw-r--r--.github/workflows/arm_linux.yml31
-rw-r--r--.github/workflows/clang_format.yml4
-rw-r--r--.github/workflows/mips_linux.yml30
-rw-r--r--.gitignore17
-rw-r--r--.travis.yml121
-rw-r--r--Android.bp28
-rw-r--r--BUILD.bazel330
-rw-r--r--CMakeLists.txt24
-rw-r--r--METADATA8
-rw-r--r--README.md77
-rw-r--r--WORKSPACE24
-rw-r--r--appveyor.yml24
-rw-r--r--bazel/platforms.bzl11
-rw-r--r--ci/Makefile240
-rw-r--r--ci/README.md66
-rw-r--r--ci/doc/docker.dot64
-rw-r--r--ci/doc/docker.svg312
-rwxr-xr-xci/doc/generate_image.sh7
-rw-r--r--ci/docker/amd64/Dockerfile48
-rw-r--r--ci/docker/toolchain/Dockerfile34
-rw-r--r--ci/sample/CMakeLists.txt22
-rw-r--r--ci/sample/main.cpp11
-rw-r--r--ci/vagrant/freebsd/Vagrantfile102
-rw-r--r--cmake/README.md34
-rw-r--r--cmake/googletest.CMakeLists.txt.in2
-rw-r--r--include/cpu_features_macros.h39
-rw-r--r--include/cpuinfo_aarch64.h2
-rw-r--r--include/cpuinfo_ppc.h9
-rw-r--r--include/cpuinfo_x86.h90
-rw-r--r--include/internal/hwcaps.h16
-rw-r--r--include/internal/string_view.h3
-rw-r--r--ndk_compat/CMakeLists.txt2
-rwxr-xr-xscripts/make_release.sh72
-rwxr-xr-xscripts/run_integration.sh448
-rwxr-xr-xscripts/test_integration.sh59
-rw-r--r--src/copy.inl19
-rw-r--r--src/cpuinfo_aarch64.c150
-rw-r--r--src/cpuinfo_ppc.c154
-rw-r--r--src/define_introspection.inl86
-rw-r--r--src/define_introspection_and_hwcaps.inl26
-rw-r--r--src/define_tables.h67
-rw-r--r--src/equals.inl22
-rw-r--r--src/hwcaps.c29
-rw-r--r--src/impl_aarch64_linux_or_android.c150
-rw-r--r--src/impl_arm_linux_or_android.c (renamed from src/cpuinfo_arm.c)114
-rw-r--r--src/impl_mips_linux_or_android.c (renamed from src/cpuinfo_mips.c)50
-rw-r--r--src/impl_ppc_linux.c162
-rw-r--r--src/impl_x86__base_implementation.inl (renamed from src/cpuinfo_x86.c)1374
-rw-r--r--src/impl_x86_freebsd.c68
-rw-r--r--src/impl_x86_linux_or_android.c58
-rw-r--r--src/impl_x86_macos.c57
-rw-r--r--src/impl_x86_windows.c58
-rw-r--r--src/string_view.c26
-rw-r--r--src/utils/list_cpu_features.c1
-rw-r--r--test/CMakeLists.txt16
-rw-r--r--test/cpuinfo_aarch64_test.cc5
-rw-r--r--test/cpuinfo_arm_test.cc36
-rw-r--r--test/cpuinfo_mips_test.cc10
-rw-r--r--test/cpuinfo_ppc_test.cc12
-rw-r--r--test/cpuinfo_x86_test.cc782
-rw-r--r--test/hwcaps_for_testing.cc24
-rw-r--r--test/hwcaps_for_testing.h6
-rw-r--r--test/string_view_test.cc22
70 files changed, 4519 insertions, 1658 deletions
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..716b782
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,31 @@
+# Project Files unneeded by docker
+ci/Makefile
+ci/docker
+ci/doc
+ci/cache
+.git
+.gitignore
+.github
+.dockerignore
+.clang-format
+appveyor.yml
+.travis.yml
+AUTHORS
+CONTRIBUTING.md
+CONTRIBUTORS
+LICENSE
+README.md
+
+build/
+cmake_build/
+build_cross/
+cmake-build-*/
+out/
+
+# Editor directories and files
+.idea/
+.vagrant/
+.vscode/
+.vs/
+*.user
+*.swp
diff --git a/.github/workflows/Dockerfile b/.github/workflows/Dockerfile
index 41dfc93..8d6f3dc 100644
--- a/.github/workflows/Dockerfile
+++ b/.github/workflows/Dockerfile
@@ -2,4 +2,4 @@
# ref: https://hub.docker.com/_/alpine
FROM alpine:edge
# Install system build dependencies
-RUN apk add --no-cache git clang
+RUN apk add --no-cache git clang-extra-tools
diff --git a/.github/workflows/aarch64_linux.yml b/.github/workflows/aarch64_linux.yml
new file mode 100644
index 0000000..2de7289
--- /dev/null
+++ b/.github/workflows/aarch64_linux.yml
@@ -0,0 +1,28 @@
+name: aarch64 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.
+ aarch64:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ targets: [
+ [aarch64-linux-gnu],
+ [aarch64_be-linux-gnu]
+ ]
+ fail-fast: false
+ env:
+ TARGET: ${{ matrix.targets[0] }}
+ steps:
+ - uses: actions/checkout@v2
+ - name: Build
+ run: make --directory=ci ${TARGET}_build
+ - name: Test
+ run: make --directory=ci ${TARGET}_test
diff --git a/.github/workflows/amd64_freebsd.yml b/.github/workflows/amd64_freebsd.yml
new file mode 100644
index 0000000..eeab380
--- /dev/null
+++ b/.github/workflows/amd64_freebsd.yml
@@ -0,0 +1,22 @@
+name: amd64 FreeBSD
+
+on:
+ push:
+ pull_request:
+ schedule:
+ # min hours day(month) month day(week)
+ - cron: '0 0 7,22 * *'
+
+jobs:
+ # Only MacOS hosted runner provides virtualisation with vagrant/virtualbox installed.
+ # see: https://github.com/actions/virtual-environments/tree/main/images/macos
+ freebsd:
+ runs-on: macos-10.15
+ steps:
+ - uses: actions/checkout@v2
+ - name: vagrant version
+ run: Vagrant --version
+ - name: VirtualBox version
+ run: virtualbox -h
+ - name: Build
+ run: cd ci/vagrant/freebsd && vagrant up
diff --git a/.github/workflows/amd64_linux.yml b/.github/workflows/amd64_linux.yml
new file mode 100644
index 0000000..21f4f90
--- /dev/null
+++ b/.github/workflows/amd64_linux.yml
@@ -0,0 +1,31 @@
+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_macos.yml b/.github/workflows/amd64_macos.yml
new file mode 100644
index 0000000..19ec18c
--- /dev/null
+++ b/.github/workflows/amd64_macos.yml
@@ -0,0 +1,43 @@
+name: amd64 macOS
+
+on:
+ push:
+ pull_request:
+ schedule:
+ # min hours day(month) month day(week)
+ - cron: '0 0 7,22 * *'
+
+jobs:
+ # Building using the github runner environement directly.
+ xcode:
+ runs-on: macos-latest
+ env:
+ CTEST_OUTPUT_ON_FAILURE: 1
+ steps:
+ - uses: actions/checkout@v2
+ - name: Check cmake
+ run: cmake --version
+ - name: Configure
+ run: cmake -S. -Bbuild -G "Xcode" -DCMAKE_CONFIGURATION_TYPES=Release
+ - name: Build
+ run: cmake --build build --config Release --target ALL_BUILD -v
+ - name: Test
+ run: cmake --build build --config Release --target RUN_TESTS -v
+ - name: Install
+ run: cmake --build build --config Release --target install -v
+ make:
+ runs-on: macos-latest
+ env:
+ CTEST_OUTPUT_ON_FAILURE: 1
+ steps:
+ - uses: actions/checkout@v2
+ - name: Check cmake
+ run: cmake --version
+ - name: Configure
+ run: cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release
+ - name: Build
+ run: cmake --build build --target all -v
+ - name: Test
+ run: cmake --build build --target test -v
+ - name: Install
+ run: cmake --build build --target install -v
diff --git a/.github/workflows/amd64_windows.yml b/.github/workflows/amd64_windows.yml
new file mode 100644
index 0000000..7ff1ac0
--- /dev/null
+++ b/.github/workflows/amd64_windows.yml
@@ -0,0 +1,25 @@
+name: amd64 Windows
+
+on:
+ push:
+ pull_request:
+ schedule:
+ # min hours day(month) month day(week)
+ - cron: '0 0 7,22 * *'
+
+jobs:
+ # Building using the github runner environement directly.
+ msvc:
+ runs-on: windows-latest
+ env:
+ CTEST_OUTPUT_ON_FAILURE: 1
+ steps:
+ - uses: actions/checkout@v2
+ - name: Configure
+ run: cmake -S. -Bbuild -G "Visual Studio 17 2022" -DCMAKE_CONFIGURATION_TYPES=Release
+ - name: Build
+ run: cmake --build build --config Release --target ALL_BUILD -- /maxcpucount
+ - name: Test
+ run: cmake --build build --config Release --target RUN_TESTS -- /maxcpucount
+ - name: Install
+ run: cmake --build build --config Release --target INSTALL -- /maxcpucount
diff --git a/.github/workflows/arm_linux.yml b/.github/workflows/arm_linux.yml
new file mode 100644
index 0000000..2272188
--- /dev/null
+++ b/.github/workflows/arm_linux.yml
@@ -0,0 +1,31 @@
+name: arm 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.
+ arm:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ targets: [
+ [arm-linux-gnueabihf],
+ [armv8l-linux-gnueabihf],
+ [arm-linux-gnueabi],
+ [armeb-linux-gnueabihf],
+ [armeb-linux-gnueabi]
+ ]
+ fail-fast: false
+ env:
+ TARGET: ${{ matrix.targets[0] }}
+ steps:
+ - uses: actions/checkout@v2
+ - name: Build
+ run: make --directory=ci ${TARGET}_build
+ - name: Test
+ run: make --directory=ci ${TARGET}_test
diff --git a/.github/workflows/clang_format.yml b/.github/workflows/clang_format.yml
index 17d1567..1afd391 100644
--- a/.github/workflows/clang_format.yml
+++ b/.github/workflows/clang_format.yml
@@ -8,8 +8,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- - name: Fetch origin/master
- run: git fetch origin master
+ - name: Fetch origin/main
+ run: git fetch origin main
- name: List of changed file(s)
run: git diff --name-only FETCH_HEAD
diff --git a/.github/workflows/mips_linux.yml b/.github/workflows/mips_linux.yml
new file mode 100644
index 0000000..571de3a
--- /dev/null
+++ b/.github/workflows/mips_linux.yml
@@ -0,0 +1,30 @@
+name: mips 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.
+ mips:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ targets: [
+ [mips32],
+ [mips32el],
+ [mips64],
+ [mips64el]
+ ]
+ fail-fast: false
+ env:
+ TARGET: ${{ matrix.targets[0] }}
+ steps:
+ - uses: actions/checkout@v2
+ - name: Build
+ run: make --directory=ci ${TARGET}_build
+ - name: Test
+ run: make --directory=ci ${TARGET}_test
diff --git a/.gitignore b/.gitignore
index 6285424..f918154 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,19 @@
-cmake_build/
+# Build folders
build/
+cmake_build/
+build_cross/
+cmake-build-*/
+out/
+# IDEs / CI temp files
+.idea/
+.vagrant/
+.vscode/
+.vs/
*.swp
+
+# Bazel artifacts
+**/bazel-*
+
+# Per-user bazelrc files
+user.bazelrc
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index b5845be..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,121 +0,0 @@
-language: c
-
-sudo: false
-
-cache:
- timeout: 1000
- directories:
- - $HOME/cpu_features_archives
-
-addons:
- apt_packages:
- - ninja-build
-
-env:
- global:
- TOOLCHAIN=NATIVE
- CMAKE_GENERATOR=Ninja
-
-matrix:
- include:
- - os: linux
- compiler: gcc
- env:
- TARGET=x86_64-linux-gnu
- - os: linux
- compiler: clang
- env:
- TARGET=x86_64-linux-gnu
- - os: osx
- compiler: gcc
- env:
- TARGET=x86_64-osx
- CMAKE_GENERATOR="Unix Makefiles"
- - os: osx
- compiler: clang
- env:
- TARGET=x86_64-osx
- CMAKE_GENERATOR="Unix Makefiles"
- - os: windows
- env:
- TARGET=x86_64-windows
- CMAKE_GENERATOR="Visual Studio 15 2017 Win64"
-
- # see: https://docs.travis-ci.com/user/multi-cpu-architectures/
- - os: linux
- arch: ppc64le
- compiler: gcc
- env:
- TARGET=ppc64le-linux-gnu
- - os: linux
- arch: ppc64le
- compiler: clang
- env:
- TARGET=ppc64le-linux-gnu
-
- # Toolchains for little-endian, 64-bit ARMv8 for GNU/Linux systems
- - os: linux
- env:
- TOOLCHAIN=LINARO
- TARGET=aarch64-linux-gnu
- QEMU_ARCH=aarch64
- # Toolchains for little-endian, hard-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
- - os: linux
- env:
- TOOLCHAIN=LINARO
- TARGET=arm-linux-gnueabihf
- QEMU_ARCH=arm
- # Toolchains for little-endian, 32-bit ARMv8 for GNU/Linux systems
- - os: linux
- env:
- TOOLCHAIN=LINARO
- TARGET=armv8l-linux-gnueabihf
- QEMU_ARCH=arm
- # Toolchains for little-endian, soft-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
- - os: linux
- env:
- TOOLCHAIN=LINARO
- TARGET=arm-linux-gnueabi
- QEMU_ARCH=arm
- # Toolchains for big-endian, 64-bit ARMv8 for GNU/Linux systems
- - os: linux
- env:
- TOOLCHAIN=LINARO
- TARGET=aarch64_be-linux-gnu
- QEMU_ARCH=DISABLED
- # Toolchains for big-endian, hard-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
- - os: linux
- env:
- TOOLCHAIN=LINARO
- TARGET=armeb-linux-gnueabihf
- QEMU_ARCH=DISABLED
- # Toolchains for big-endian, soft-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
- - os: linux
- env:
- TOOLCHAIN=LINARO
- TARGET=armeb-linux-gnueabi
- QEMU_ARCH=DISABLED
- - os: linux
- env:
- TOOLCHAIN=CODESCAPE
- TARGET=mips32
- QEMU_ARCH=mips
- - os: linux
- env:
- TOOLCHAIN=CODESCAPE
- TARGET=mips32el
- QEMU_ARCH=mipsel
- - os: linux
- env:
- TOOLCHAIN=CODESCAPE
- TARGET=mips64
- QEMU_ARCH=mips64
- - os: linux
- env:
- TOOLCHAIN=CODESCAPE
- TARGET=mips64el
- QEMU_ARCH=mips64el
-
-script:
- - cmake --version
- - bash -e -x ./scripts/run_integration.sh
diff --git a/Android.bp b/Android.bp
index 7f70060..57e3804 100644
--- a/Android.bp
+++ b/Android.bp
@@ -101,7 +101,7 @@ cc_library {
arch: {
arm: {
srcs: [
- "src/cpuinfo_arm.c",
+ "src/impl_arm_linux_or_android.c",
],
whole_static_libs: [
"libcpu_features-hwcaps",
@@ -109,7 +109,7 @@ cc_library {
},
arm64: {
srcs: [
- "src/cpuinfo_aarch64.c",
+ "src/impl_aarch64_linux_or_android.c",
],
whole_static_libs: [
"libcpu_features-hwcaps",
@@ -120,7 +120,7 @@ cc_library {
},
x86: {
srcs: [
- "src/cpuinfo_x86.c",
+ "src/impl_x86_linux_or_android.c",
],
cflags: [
"-Wno-unused-variable",
@@ -128,7 +128,7 @@ cc_library {
},
x86_64: {
srcs: [
- "src/cpuinfo_x86.c",
+ "src/impl_x86_linux_or_android.c",
],
cflags: [
"-Wno-unused-variable",
@@ -171,6 +171,16 @@ cc_binary {
"-Wno-unused-function",
],
},
+ x86: {
+ cflags: [
+ "-Wno-deprecated-declarations",
+ ],
+ },
+ x86_64: {
+ cflags: [
+ "-Wno-deprecated-declarations",
+ ],
+ },
},
}
@@ -334,26 +344,28 @@ cc_test {
cflags: [
"-DCPU_FEATURES_MOCK_CPUID_X86",
"-Wno-unused-variable",
+ "-Wno-deprecated-declarations",
],
srcs: [
"test/cpuinfo_x86_test.cc",
- "src/cpuinfo_x86.c",
+ "src/impl_x86_linux_or_android.c",
],
},
x86_64: {
cflags: [
"-DCPU_FEATURES_MOCK_CPUID_X86",
"-Wno-unused-variable",
+ "-Wno-deprecated-declarations",
],
srcs: [
"test/cpuinfo_x86_test.cc",
- "src/cpuinfo_x86.c",
+ "src/impl_x86_linux_or_android.c",
],
},
arm: {
srcs: [
"test/cpuinfo_arm_test.cc",
- "src/cpuinfo_arm.c",
+ "src/impl_arm_linux_or_android.c",
],
},
arm64: {
@@ -362,7 +374,7 @@ cc_test {
],
srcs: [
"test/cpuinfo_aarch64_test.cc",
- "src/cpuinfo_aarch64.c",
+ "src/impl_aarch64_linux_or_android.c",
],
},
},
diff --git a/BUILD.bazel b/BUILD.bazel
new file mode 100644
index 0000000..1b62d66
--- /dev/null
+++ b/BUILD.bazel
@@ -0,0 +1,330 @@
+# cpu_features, a cross platform C99 library to get cpu features at runtime.
+
+load("@bazel_skylib//lib:selects.bzl", "selects")
+load("//:bazel/platforms.bzl", "PLATFORM_CPU_ARM", "PLATFORM_CPU_ARM64", "PLATFORM_CPU_MIPS", "PLATFORM_CPU_PPC", "PLATFORM_CPU_X86_64")
+
+package(
+ default_visibility = ["//visibility:public"],
+ licenses = ["notice"],
+)
+
+exports_files(["LICENSE"])
+
+INCLUDES = ["include"]
+
+C99_FLAGS = [
+ "-std=c99",
+ "-Wall",
+ "-Wextra",
+ "-Wmissing-declarations",
+ "-Wmissing-prototypes",
+ "-Wno-implicit-fallthrough",
+ "-Wno-unused-function",
+ "-Wold-style-definition",
+ "-Wshadow",
+ "-Wsign-compare",
+ "-Wstrict-prototypes",
+]
+
+cc_library(
+ name = "cpu_features_macros",
+ hdrs = ["include/cpu_features_macros.h"],
+ copts = C99_FLAGS,
+ includes = INCLUDES,
+)
+
+cc_library(
+ name = "cpu_features_cache_info",
+ hdrs = ["include/cpu_features_cache_info.h"],
+ copts = C99_FLAGS,
+ includes = INCLUDES,
+ deps = [":cpu_features_macros"],
+)
+
+cc_library(
+ name = "bit_utils",
+ hdrs = ["include/internal/bit_utils.h"],
+ copts = C99_FLAGS,
+ includes = INCLUDES,
+ deps = [":cpu_features_macros"],
+)
+
+cc_test(
+ name = "bit_utils_test",
+ srcs = ["test/bit_utils_test.cc"],
+ includes = INCLUDES,
+ deps = [
+ ":bit_utils",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_library(
+ name = "memory_utils",
+ copts = C99_FLAGS,
+ includes = INCLUDES,
+ textual_hdrs = [
+ "src/copy.inl",
+ "src/equals.inl",
+ ],
+)
+
+cc_library(
+ name = "string_view",
+ srcs = [
+ "src/string_view.c",
+ ],
+ hdrs = ["include/internal/string_view.h"],
+ copts = C99_FLAGS,
+ includes = INCLUDES,
+ deps = [
+ ":cpu_features_macros",
+ ":memory_utils",
+ ],
+)
+
+cc_test(
+ name = "string_view_test",
+ srcs = ["test/string_view_test.cc"],
+ includes = INCLUDES,
+ deps = [
+ ":string_view",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_library(
+ name = "filesystem",
+ srcs = ["src/filesystem.c"],
+ hdrs = ["include/internal/filesystem.h"],
+ copts = C99_FLAGS,
+ includes = INCLUDES,
+ deps = [":cpu_features_macros"],
+)
+
+cc_library(
+ name = "filesystem_for_testing",
+ testonly = 1,
+ srcs = [
+ "src/filesystem.c",
+ "test/filesystem_for_testing.cc",
+ ],
+ hdrs = [
+ "include/internal/filesystem.h",
+ "test/filesystem_for_testing.h",
+ ],
+ includes = INCLUDES,
+ defines = ["CPU_FEATURES_MOCK_FILESYSTEM"],
+ deps = [
+ ":cpu_features_macros",
+ ],
+)
+
+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"],
+ deps = [
+ ":cpu_features_macros",
+ ":filesystem",
+ ":string_view",
+ ],
+)
+
+cc_test(
+ name = "stack_line_reader_test",
+ srcs = [
+ "include/internal/stack_line_reader.h",
+ "src/stack_line_reader.c",
+ "test/stack_line_reader_test.cc",
+ ],
+ includes = INCLUDES,
+ defines = ["STACK_LINE_READER_BUFFER_SIZE=16"],
+ deps = [
+ ":cpu_features_macros",
+ ":filesystem_for_testing",
+ ":string_view",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_library(
+ name = "stack_line_reader_to_use_with_filesystem_for_testing",
+ testonly = 1,
+ srcs = ["src/stack_line_reader.c"],
+ hdrs = ["include/internal/stack_line_reader.h"],
+ copts = C99_FLAGS,
+ includes = INCLUDES,
+ defines = ["STACK_LINE_READER_BUFFER_SIZE=1024"],
+ deps = [
+ ":cpu_features_macros",
+ ":filesystem_for_testing",
+ ":string_view",
+ ],
+)
+
+cc_library(
+ name = "hwcaps",
+ srcs = ["src/hwcaps.c"],
+ hdrs = ["include/internal/hwcaps.h"],
+ copts = C99_FLAGS,
+ includes = INCLUDES,
+ defines = ["HAVE_STRONG_GETAUXVAL"],
+ deps = [
+ ":cpu_features_macros",
+ ":filesystem",
+ ":string_view",
+ ],
+)
+
+cc_library(
+ name = "hwcaps_for_testing",
+ testonly = 1,
+ srcs = [
+ "src/hwcaps.c",
+ "test/hwcaps_for_testing.cc",
+ ],
+ hdrs = [
+ "include/internal/hwcaps.h",
+ "test/hwcaps_for_testing.h",
+ ],
+ includes = INCLUDES,
+ defines = [
+ "CPU_FEATURES_MOCK_GET_ELF_HWCAP_FROM_GETAUXVAL",
+ "CPU_FEATURES_TEST",
+ ],
+ deps = [
+ ":cpu_features_macros",
+ ":filesystem_for_testing",
+ ":string_view",
+ ],
+)
+
+cc_library(
+ name = "cpuinfo",
+ srcs = selects.with_or({
+ PLATFORM_CPU_X86_64: [
+ "src/impl_x86_freebsd.c",
+ "src/impl_x86_linux_or_android.c",
+ "src/impl_x86_macos.c",
+ "src/impl_x86_windows.c",
+ ],
+ PLATFORM_CPU_ARM: ["src/impl_arm_linux_or_android.c"],
+ PLATFORM_CPU_ARM64: ["src/impl_aarch64_linux_or_android.c"],
+ PLATFORM_CPU_MIPS: ["src/impl_mips_linux_or_android.c"],
+ PLATFORM_CPU_PPC: ["src/impl_ppc_linux.c"],
+ }),
+ hdrs = selects.with_or({
+ PLATFORM_CPU_X86_64: [
+ "include/cpuinfo_x86.h",
+ "include/internal/cpuid_x86.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",
+ ],
+ deps = [
+ ":bit_utils",
+ ":cpu_features_cache_info",
+ ":cpu_features_macros",
+ ":filesystem",
+ ":hwcaps",
+ ":memory_utils",
+ ":stack_line_reader",
+ ":string_view",
+ ],
+)
+
+cc_library(
+ name = "cpuinfo_for_testing",
+ testonly = 1,
+ srcs = selects.with_or({
+ PLATFORM_CPU_X86_64: [
+ "src/impl_x86_freebsd.c",
+ "src/impl_x86_linux_or_android.c",
+ "src/impl_x86_macos.c",
+ "src/impl_x86_windows.c",
+ ],
+ PLATFORM_CPU_ARM: ["src/impl_arm_linux_or_android.c"],
+ PLATFORM_CPU_ARM64: ["src/impl_aarch64_linux_or_android.c"],
+ PLATFORM_CPU_MIPS: ["src/impl_mips_linux_or_android.c"],
+ PLATFORM_CPU_PPC: ["src/impl_ppc_linux.c"],
+ }),
+ hdrs = selects.with_or({
+ PLATFORM_CPU_X86_64: [
+ "include/cpuinfo_x86.h",
+ "include/internal/cpuid_x86.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,
+ defines = selects.with_or({
+ PLATFORM_CPU_X86_64: ["CPU_FEATURES_MOCK_CPUID_X86"],
+ "//conditions:default": [],
+ }),
+ 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",
+ ],
+ deps = [
+ ":bit_utils",
+ ":cpu_features_cache_info",
+ ":cpu_features_macros",
+ ":filesystem_for_testing",
+ ":hwcaps_for_testing",
+ ":memory_utils",
+ ":stack_line_reader_to_use_with_filesystem_for_testing",
+ ":string_view",
+ ],
+)
+
+cc_test(
+ name = "cpuinfo_test",
+ srcs = selects.with_or({
+ PLATFORM_CPU_ARM64: ["test/cpuinfo_aarch64_test.cc"],
+ PLATFORM_CPU_ARM: ["test/cpuinfo_arm_test.cc"],
+ PLATFORM_CPU_MIPS: ["test/cpuinfo_mips_test.cc"],
+ PLATFORM_CPU_PPC: ["test/cpuinfo_ppc_test.cc"],
+ PLATFORM_CPU_X86_64: ["test/cpuinfo_x86_test.cc"],
+ }),
+ includes = INCLUDES,
+ deps = [
+ ":cpuinfo_for_testing",
+ ":filesystem_for_testing",
+ ":hwcaps_for_testing",
+ ":string_view",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_binary(
+ name = "list_cpu_features",
+ srcs = ["src/utils/list_cpu_features.c"],
+ copts = C99_FLAGS,
+ includes = INCLUDES,
+ deps = [
+ ":bit_utils",
+ ":cpu_features_macros",
+ ":cpuinfo",
+ ],
+)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f9daeac..81451d4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,7 +6,7 @@ if(POLICY CMP0077)
cmake_policy(SET CMP0077 NEW)
endif()
-project(CpuFeatures VERSION 0.6.0 LANGUAGES C)
+project(CpuFeatures VERSION 0.7.0 LANGUAGES C)
set(CMAKE_C_STANDARD 99)
@@ -17,22 +17,17 @@ if(NOT CMAKE_BUILD_TYPE)
FORCE)
endif(NOT CMAKE_BUILD_TYPE)
-# BUILD_TESTING is a standard CMake variable, but we declare it here to make it
-# prominent in the GUI.
-option(BUILD_TESTING "Enable test (depends on googletest)." OFF)
# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to make
# it prominent in the GUI.
# cpu_features uses bit-fields which are - to some extends - implementation-defined (see https://en.cppreference.com/w/c/language/bit_field).
# As a consequence it is discouraged to use cpu_features as a shared library because different compilers may interpret the code in different ways.
# Prefer static linking from source whenever possible.
option(BUILD_SHARED_LIBS "Build library as shared." OFF)
-# PIC
-option(BUILD_PIC "Build with Position Independant Code." OFF) # Default is off at least for GCC
# Force PIC on unix when building shared libs
# see: https://en.wikipedia.org/wiki/Position-independent_code
if(BUILD_SHARED_LIBS AND UNIX)
- set(BUILD_PIC ON)
+ option(CMAKE_POSITION_INDEPENDENT_CODE "Build with Position Independant Code." ON)
endif()
include(CheckIncludeFile)
@@ -57,10 +52,10 @@ set(PROCESSOR_IS_POWER FALSE)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^mips")
set(PROCESSOR_IS_MIPS TRUE)
+elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64)")
+ set(PROCESSOR_IS_AARCH64 TRUE)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm")
set(PROCESSOR_IS_ARM TRUE)
-elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^aarch64")
- set(PROCESSOR_IS_AARCH64 TRUE)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64)|(AMD64|amd64)|(^i.86$)")
set(PROCESSOR_IS_X86 TRUE)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)")
@@ -70,22 +65,19 @@ endif()
macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpu_features_macros.h)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpu_features_cache_info.h)
+ file(GLOB IMPL_SOURCES CONFIGURE_DEPENDS "${PROJECT_SOURCE_DIR}/src/impl_*.c")
+ list(APPEND ${SRCS_LIST_NAME} ${IMPL_SOURCES})
if(PROCESSOR_IS_MIPS)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_mips.h)
- list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_mips.c)
elseif(PROCESSOR_IS_ARM)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_arm.h)
- list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_arm.c)
elseif(PROCESSOR_IS_AARCH64)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_aarch64.h)
- list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_aarch64.c)
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}/src/cpuinfo_x86.c)
elseif(PROCESSOR_IS_POWER)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_ppc.h)
- list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_ppc.c)
else()
message(FATAL_ERROR "Unsupported architectures ${CMAKE_SYSTEM_PROCESSOR}")
endif()
@@ -104,7 +96,6 @@ add_library(utils OBJECT
${PROJECT_SOURCE_DIR}/src/stack_line_reader.c
${PROJECT_SOURCE_DIR}/src/string_view.c
)
-set_property(TARGET utils PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC})
setup_include_and_definitions(utils)
#
@@ -125,7 +116,6 @@ if(UNIX)
if(HAVE_STRONG_GETAUXVAL)
target_compile_definitions(unix_based_hardware_detection PRIVATE HAVE_STRONG_GETAUXVAL)
endif()
- set_property(TARGET unix_based_hardware_detection PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC})
endif()
#
@@ -142,7 +132,6 @@ add_library(cpu_features ${CPU_FEATURES_HDRS} ${CPU_FEATURES_SRCS})
set_target_properties(cpu_features PROPERTIES PUBLIC_HEADER "${CPU_FEATURES_HDRS}")
setup_include_and_definitions(cpu_features)
target_link_libraries(cpu_features PUBLIC ${CMAKE_DL_LIBS})
-set_property(TARGET cpu_features PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC})
target_include_directories(cpu_features
PUBLIC $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/cpu_features>
)
@@ -233,6 +222,7 @@ install(TARGETS cpu_features list_cpu_features
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR}
)
install(EXPORT CpuFeaturesTargets
NAMESPACE CpuFeatures::
diff --git a/METADATA b/METADATA
index 5e2b871..eac4f3d 100644
--- a/METADATA
+++ b/METADATA
@@ -9,11 +9,11 @@ third_party {
type: GIT
value: "https://github.com/google/cpu_features.git"
}
- version: "v0.6.0"
+ version: "v0.7.0"
license_type: NOTICE
last_upgrade_date {
- year: 2020
- month: 10
- day: 15
+ year: 2022
+ month: 3
+ day: 8
}
}
diff --git a/README.md b/README.md
index 8a34168..6091845 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,14 @@
-# cpu_features [![Build Status](https://travis-ci.org/google/cpu_features.svg?branch=master)](https://travis-ci.org/google/cpu_features) [![Build status](https://ci.appveyor.com/api/projects/status/46d1owsj7n8dsylq/branch/master?svg=true)](https://ci.appveyor.com/project/gchatelet/cpu-features/branch/master)
+# 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.
@@ -12,6 +22,7 @@ instructions) at runtime.
- [Android NDK's drop in replacement](#ndk)
- [License](#license)
- [Build with cmake](#cmake)
+- [Community Bindings](#bindings)
<a name="rationale"></a>
## Design Rationale
@@ -32,7 +43,7 @@ instructions) at runtime.
<a name="codesample"></a>
## Code samples
-**Note:** For C++ code, the library functions are defined in the `CpuFeatures` namespace.
+**Note:** For C++ code, the library functions are defined in the `cpu_features` namespace.
### Checking features at runtime
@@ -42,7 +53,7 @@ AES and the SSE4.2 instruction sets:
```c
#include "cpuinfo_x86.h"
-// For C++, add `using namespace CpuFeatures;`
+// For C++, add `using namespace cpu_features;`
static const X86Features features = GetX86Info().features;
void Compute(void) {
@@ -64,7 +75,7 @@ features and then check whether AES and NEON are supported.
#include <stdbool.h>
#include "cpuinfo_arm.h"
-// For C++, add `using namespace CpuFeatures;`
+// For C++, add `using namespace cpu_features;`
static const ArmFeatures features = GetArmInfo().features;
static const bool has_aes_and_neon = features.aes && features.neon;
@@ -84,7 +95,7 @@ instruction set (e.g., `g++ -mavx`) and sets `has_avx` accordingly.
#include <stdbool.h>
#include "cpuinfo_x86.h"
-// For C++, add `using namespace CpuFeatures;`
+// For C++, add `using namespace cpu_features;`
static const X86Features features = GetX86Info().features;
static const bool has_avx = CPU_FEATURES_COMPILED_X86_AVX || features.avx;
@@ -107,7 +118,7 @@ set&mdash;but only if it's not Sandy Bridge.
#include <stdbool.h>
#include "cpuinfo_x86.h"
-// For C++, add `using namespace CpuFeatures;`
+// For C++, add `using namespace cpu_features;`
static const X86Info info = GetX86Info();
static const X86Microarchitecture uarch = GetX86Microarchitecture(&info);
static const bool has_fast_avx = info.features.avx && uarch != INTEL_SNB;
@@ -141,13 +152,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 |
+| | 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 |
1. **Features revealed from Linux.** We gather data from several sources
depending on availability:
@@ -167,7 +179,7 @@ flags : aes,avx,cx16,smx,sse4_1,sse4_2,ssse3
## Android NDK's drop in replacement
[cpu_features](https://github.com/google/cpu_features) is now officially
-supporting Android and offers a drop in replacement of for the NDK's [cpu-features.h](https://android.googlesource.com/platform/ndk/+/master/sources/android/cpufeatures/cpu-features.h)
+supporting Android and offers a drop in replacement of for the NDK's [cpu-features.h](https://android.googlesource.com/platform/ndk/+/main/sources/android/cpufeatures/cpu-features.h)
, see [ndk_compat](ndk_compat) folder for details.
<a name="license"></a>
@@ -182,18 +194,35 @@ See [LICENSE](LICENSE) for more information.
Please check the [CMake build instructions](cmake/README.md).
<a name="quickstart"></a>
-### Quickstart with `Ninja`
+### Quickstart
- - build `list_cpu_features`
-```
- cmake -B/tmp/cpu_features -H. -GNinja -DCMAKE_BUILD_TYPE=Release
- ninja -C/tmp/cpu_features
- /tmp/cpu_features/list_cpu_features --json
+ - Run `list_cpu_features`
+```sh
+cmake -S. -Bbuild -DBUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=Release
+cmake --build build --config Release -j
+./build/list_cpu_features --json
```
+_Note_: Use `--target ALL_BUILD` on the second line for `Visual Studio` and `XCode`.
+
- run tests
+```sh
+cmake -S. -Bbuild -DBUILD_TESTING=ON -DCMAKE_BUILD_TYPE=Debug
+cmake --build build --config Debug -j
+cmake --build build --config Debug --target test
```
- cmake -B/tmp/cpu_features -H. -GNinja -DBUILD_TESTING=ON
- ninja -C/tmp/cpu_features
- ninja -C/tmp/cpu_features test
-```
+
+_Note_: Use `--target RUN_TESTS` on the last line for `Visual Studio` and `--target RUN_TEST` for `XCode`.
+
+<a name="bindings"></a>
+## Community bindings
+
+Links provided here are not affiliated with Google but are kindly provided by the OSS Community.
+
+ - .Net
+ - https://github.com/toor1245/cpu_features.NET
+ - Python
+ - https://github.com/Narasimha1997/py_cpu
+
+
+_Send PR to showcase your wrapper here_
diff --git a/WORKSPACE b/WORKSPACE
index 8ea8a8b..104c459 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -1,7 +1,23 @@
-# ===== googletest =====
+workspace(name = "com_google_cpufeatures")
-git_repository(
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+http_archive(
name = "com_google_googletest",
- remote = "https://github.com/google/googletest.git",
- commit = "c3f65335b79f47b05629e79a54685d899bc53b93",
+ sha256 = "269cebe2be1f607f91f52630ff5bec3275b948c65d4bac323ebd05e90d84f7a9",
+ strip_prefix = "googletest-e2239ee6043f73722e7aa812a459f54a28552929",
+ urls = ["https://github.com/google/googletest/archive/e2239ee6043f73722e7aa812a459f54a28552929.zip"],
+)
+
+http_archive(
+ 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",
+ ],
)
+
+load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
+
+bazel_skylib_workspace()
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index f18635a..0000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-version: '{build}'
-shallow_clone: true
-
-platform: x64
-
-environment:
- matrix:
- - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
- CMAKE_GENERATOR: "Visual Studio 15 2017 Win64"
- - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
- CMAKE_GENERATOR: "Visual Studio 14 2015 Win64"
-
-matrix:
- fast_finish: true
-
-before_build:
- - cmake --version
- - cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON -H. -Bcmake_build -G "%CMAKE_GENERATOR%"
-
-build_script:
- - cmake --build cmake_build --config Debug --target ALL_BUILD
-
-test_script:
- - cmake --build cmake_build --config Debug --target RUN_TESTS
diff --git a/bazel/platforms.bzl b/bazel/platforms.bzl
new file mode 100644
index 0000000..5671add
--- /dev/null
+++ b/bazel/platforms.bzl
@@ -0,0 +1,11 @@
+"""Defines global variables that lists target cpus"""
+
+PLATFORM_CPU_X86_64 = ("@platforms//cpu:x86_64")
+
+PLATFORM_CPU_ARM = ("@platforms//cpu:arm")
+
+PLATFORM_CPU_ARM64 = ("@platforms//cpu:arm64")
+
+PLATFORM_CPU_MIPS = ("@platforms//cpu:mips64")
+
+PLATFORM_CPU_PPC = ("@platforms//cpu:ppc")
diff --git a/ci/Makefile b/ci/Makefile
new file mode 100644
index 0000000..47ea30a
--- /dev/null
+++ b/ci/Makefile
@@ -0,0 +1,240 @@
+PROJECT := cpu_features
+BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
+SHA1 := $(shell git rev-parse --verify HEAD)
+
+# General commands
+.PHONY: help
+BOLD=\e[1m
+RESET=\e[0m
+
+help:
+ @echo -e "${BOLD}SYNOPSIS${RESET}"
+ @echo -e "\tmake <target> [NOCACHE=1]"
+ @echo
+ @echo -e "${BOLD}DESCRIPTION${RESET}"
+ @echo -e "\ttest build inside docker container to have a reproductible build."
+ @echo
+ @echo -e "${BOLD}MAKE TARGETS${RESET}"
+ @echo -e "\t${BOLD}help${RESET}: display this help and exit."
+ @echo
+ @echo -e "\t${BOLD}amd64_<stage>${RESET}: build <stage> docker image using an Ubuntu:latest x86_64 base image."
+ @echo -e "\t${BOLD}save_amd64_<stage>${RESET}: Save the <stage> docker image."
+ @echo -e "\t${BOLD}sh_amd64_<stage>${RESET}: run a container using the <stage> docker image (debug purpose)."
+ @echo -e "\t${BOLD}clean_amd64_<stage>${RESET}: Remove cache and docker image."
+ @echo
+ @echo -e "\tWith ${BOLD}<stage>${RESET}:"
+ @echo -e "\t\t${BOLD}env${RESET}"
+ @echo -e "\t\t${BOLD}devel${RESET}"
+ @echo -e "\t\t${BOLD}build${RESET}"
+ @echo -e "\t\t${BOLD}test${RESET}"
+ @echo -e "\t\t${BOLD}install_env${RESET}"
+ @echo -e "\t\t${BOLD}install_devel${RESET}"
+ @echo -e "\t\t${BOLD}install_build${RESET}"
+ @echo -e "\t\t${BOLD}install_test${RESET}"
+ @echo -e "\te.g. 'make amd64_build'"
+ @echo
+ @echo -e "\t${BOLD}<target>_<toolchain_stage>${RESET}: build <stage> docker image for a specific toolchain target."
+ @echo -e "\t${BOLD}save_<target>_<toolchain_stage>${RESET}: Save the <stage> docker image for a specific platform."
+ @echo -e "\t${BOLD}sh_<target>_<toolchain_stage>${RESET}: run a container using the <stage> docker image specified (debug purpose)."
+ @echo -e "\t${BOLD}clean_<target>_<toolchain_stage>${RESET}: Remove cache and docker image."
+ @echo
+ @echo -e "\tWith ${BOLD}<target>${RESET}:"
+ @echo -e "\t\t${BOLD}arm-linux-gnueabihf${RESET} (linaro toolchain)"
+ @echo -e "\t\t${BOLD}armv8l-linux-gnueabihf${RESET} (linaro toolchain)"
+ @echo -e "\t\t${BOLD}arm-linux-gnueabi${RESET} (linaro toolchain)"
+ @echo -e "\t\t${BOLD}armeb-linux-gnueabihf${RESET} (linaro toolchain)"
+ @echo -e "\t\t${BOLD}armeb-linux-gnueabi${RESET} (linaro toolchain)"
+ @echo -e "\t\t${BOLD}aarch64-linux-gnu${RESET} (linaro toolchain)"
+ @echo -e "\t\t${BOLD}aarch64_be-linux-gnu${RESET} (linaro 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
+ @echo -e "\tWith ${BOLD}<toolchain_stage>${RESET}:"
+ @echo -e "\t\t${BOLD}env${RESET}"
+ @echo -e "\t\t${BOLD}devel${RESET}"
+ @echo -e "\t\t${BOLD}build${RESET}"
+ @echo -e "\t\t${BOLD}test${RESET}"
+ @echo -e "\te.g. 'make aarch64_test'"
+ @echo
+ @echo -e "\t${BOLD}<VM>${RESET}: build the vagrant <VM> virtual machine."
+ @echo -e "\t${BOLD}clean_<VM>${RESET}: Remove virtual machine for the specified vm."
+ @echo
+ @echo -e "\t${BOLD}<VM>${RESET}:"
+ @echo -e "\t\t${BOLD}freebsd${RESET} (FreeBSD)"
+ @echo
+ @echo -e "\t${BOLD}clean${RESET}: Remove cache and ALL docker images."
+ @echo
+ @echo -e "\t${BOLD}NOCACHE=1${RESET}: use 'docker build --no-cache' when building container (default use cache)."
+ @echo
+ @echo -e "branch: $(BRANCH)"
+ @echo -e "sha1: $(SHA1)"
+
+# Need to add cmd_platform to PHONY otherwise target are ignored since they do not
+# contain recipe (using FORCE do not work here)
+.PHONY: all
+all: build
+
+# Delete all implicit rules to speed up makefile
+MAKEFLAGS += --no-builtin-rules
+.SUFFIXES:
+# Remove some rules from gmake that .SUFFIXES does not remove.
+SUFFIXES =
+# Keep all intermediate files
+# ToDo: try to remove it later
+.SECONDARY:
+
+# Docker image name prefix.
+IMAGE := ${PROJECT}
+
+ifdef NOCACHE
+DOCKER_BUILD_CMD := docker build --no-cache
+else
+DOCKER_BUILD_CMD := docker build
+endif
+
+DOCKER_RUN_CMD := docker run --rm --init --net=host
+
+# $* stem
+# $< first prerequist
+# $@ target name
+
+############
+## NATIVE ##
+############
+STAGES = env devel build test install_env install_devel install_build install_test
+
+targets_amd64 = $(addprefix amd64_, $(STAGES))
+.PHONY: $(targets_amd64)
+$(targets_amd64): amd64_%: docker/amd64/Dockerfile
+ #@docker image rm -f ${IMAGE}:amd64_$* 2>/dev/null
+ ${DOCKER_BUILD_CMD} \
+ --tag ${IMAGE}:amd64_$* \
+ --target=$* \
+ -f $< \
+ ..
+
+#$(info Create targets: save_amd64 $(addprefix save_amd64_, $(STAGES)) (debug).)
+save_targets_amd64 = $(addprefix save_amd64_, $(STAGES))
+.PHONY: $(save_targets_amd64)
+$(save_targets_amd64): save_amd64_%: cache/amd64/docker_%.tar
+cache/amd64/docker_%.tar: amd64_%
+ @rm -f $@
+ mkdir -p cache/amd64
+ docker save ${IMAGE}:amd64_$* -o $@
+
+#$(info Create targets: $(addprefix sh_amd64_, $(STAGES)) (debug).)
+sh_targets_amd64 = $(addprefix sh_amd64_, $(STAGES))
+.PHONY: $(sh_targets_amd64)
+$(sh_targets_amd64): sh_amd64_%: amd64_%
+ ${DOCKER_RUN_CMD} -it --name ${IMAGE}_amd64_$* ${IMAGE}:amd64_$*
+
+#$(info Create targets: $(addprefix clean_amd64_, $(STAGES)).)
+clean_targets_amd64 = $(addprefix clean_amd64_, $(STAGES))
+.PHONY: clean_amd64 $(clean_targets_amd64)
+clean_amd64: $(clean_targets_amd64)
+$(clean_targets_amd64): clean_amd64_%:
+ docker image rm -f ${IMAGE}:amd64_$* 2>/dev/null
+ rm -f cache/amd64/docker_$*.tar
+
+
+###############
+## TOOLCHAIN ##
+###############
+TOOLCHAIN_TARGETS = \
+ 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
+TOOLCHAIN_STAGES = env devel build test
+define toolchain-stage-target =
+#$$(info STAGE: $1)
+#$$(info Create targets: toolchain_$1 $(addsuffix _$1, $(TOOLCHAIN_TARGETS)).)
+targets_toolchain_$1 = $(addsuffix _$1, $(TOOLCHAIN_TARGETS))
+.PHONY: toolchain_$1 $$(targets_toolchain_$1)
+toolchain_$1: $$(targets_toolchain_$1)
+$$(targets_toolchain_$1): %_$1: docker/toolchain/Dockerfile
+ #@docker image rm -f ${IMAGE}:$$*_$1 2>/dev/null
+ ${DOCKER_BUILD_CMD} \
+ --tag ${IMAGE}:$$*_$1 \
+ --build-arg TARGET=$$* \
+ --target=$1 \
+ -f $$< \
+ ..
+
+#$$(info Create targets: save_toolchain_$1 $(addprefix save_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS))) (debug).)
+save_targets_toolchain_$1 = $(addprefix save_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS)))
+.PHONY: save_toolchain_$1 $$(save_targets_toolchain_$1)
+save_toolchain_$1: $$(save_targets_toolchain_$1)
+$$(save_targets_toolchain_$1): save_%_$1: cache/%/docker_$1.tar
+cache/%/docker_$1.tar: %_$1
+ @rm -f $$@
+ mkdir -p cache/$$*
+ docker save ${IMAGE}:$$*_$1 -o $$@
+
+#$$(info Create targets: $(addprefix sh_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS))) (debug).)
+sh_targets_toolchain_$1 = $(addprefix sh_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS)))
+.PHONY: $$(sh_targets_toolchain_$1)
+$$(sh_targets_toolchain_$1): sh_%_$1: %_$1
+ ${DOCKER_RUN_CMD} -it --name ${IMAGE}_$$*_$1 ${IMAGE}:$$*_$1
+
+#$$(info Create targets: clean_toolchain_$1 $(addprefix clean_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS))).)
+clean_targets_toolchain_$1 = $(addprefix clean_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS)))
+.PHONY: clean_toolchain_$1 $$(clean_targets_toolchain_$1)
+clean_toolchain_$1: $$(clean_targets_toolchain_$1)
+$$(clean_targets_toolchain_$1): clean_%_$1:
+ docker image rm -f ${IMAGE}:$$*_$1 2>/dev/null
+ rm -f cache/$$*/docker_$1.tar
+endef
+
+$(foreach stage,$(TOOLCHAIN_STAGES),$(eval $(call toolchain-stage-target,$(stage))))
+
+## MERGE ##
+.PHONY: clean_toolchain
+clean_toolchain: $(addprefix clean_toolchain_, $(TOOLCHAIN_STAGES))
+ -rmdir $(addprefix cache/, $(TOOLCHAIN_TARGETS))
+
+.PHONY: env devel build test
+env: amd64_env toolchain_env
+devel: amd64_devel toolchain_devel
+build: amd64_build toolchain_build
+test: amd64_test toolchain_test
+
+.PHONY: install_env install_devel install_build install_test
+install_env: amd64_install_env
+install_devel: amd64_install_devel
+install_build: amd64_install_build
+install_test: amd64_install_test
+
+#############
+## VAGRANT ##
+#############
+VMS = freebsd
+
+vms_targets = $(addsuffix _build, $(VMS))
+.PHONY: $(vms_targets)
+$(vms_targets): %_build: vagrant/%/Vagrantfile
+ @cd vagrant/$* && vagrant destroy -f
+ cd vagrant/$* && vagrant up
+
+clean_vms_targets = $(addprefix clean_, $(VMS))
+.PHONY: clean_vms $(clean_vms_targets)
+clean_vms: $(clean_vms_targets)
+$(clean_vms_targets): clean_%:
+ cd vagrant/$* && vagrant destroy -f
+ -rm -rf vagrant/$*/.vagrant
+
+###########
+## CLEAN ##
+###########
+.PHONY: clean
+clean: clean_amd64 clean_toolchain clean_vms
+ docker container prune -f
+ docker image prune -f
+ -rmdir cache
+
+.PHONY: distclean
+distclean: clean
+ -docker container rm -f $$(docker container ls -aq)
+ -docker image rm -f $$(docker image ls -aq)
+ -vagrant box remove -f generic/freebsd12
diff --git a/ci/README.md b/ci/README.md
new file mode 100644
index 0000000..e370136
--- /dev/null
+++ b/ci/README.md
@@ -0,0 +1,66 @@
+# 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/ci/doc/docker.dot b/ci/doc/docker.dot
new file mode 100644
index 0000000..a00ef1f
--- /dev/null
+++ b/ci/doc/docker.dot
@@ -0,0 +1,64 @@
+@startdot
+digraph DockerDeps {
+ //rankdir=BT;
+ rankdir=TD;
+ node [shape=cylinder, style="rounded,filled", color=black, fillcolor=royalblue];
+ DISTRO_IMG [label="ubuntu:latest"];
+ PKG [label="packages\ne.g. cmake, g++", shape=box3d];
+ SRC [label="git repo", shape=folder];
+ SPL [label="sample", shape=folder];
+
+ subgraph clusterDockerfile {
+ ENV_IMG [label="cpu_features:amd64_env\nenv"];
+ DEVEL_IMG [label="cpu_features:amd64_devel\ndevel"];
+ BUILD_IMG [label="cpu_features:amd64_build\nbuild"];
+ TEST_IMG [label="cpu_features:amd64_test\ntest"];
+ INSTALL_ENV_IMG [label="cpu_features:amd64_install_env\ninstall_env"];
+ INSTALL_DEVEL_IMG [label="cpu_features:amd64_install_devel\ninstall_devel"];
+ INSTALL_BUILD_IMG [label="cpu_features:amd64_install_build\ninstall_build"];
+ INSTALL_TEST_IMG [label="cpu_features:amd64_install_test\ninstall_test"];
+
+ ENV_IMG -> DEVEL_IMG;
+ DEVEL_IMG -> BUILD_IMG;
+ BUILD_IMG -> TEST_IMG;
+
+ ENV_IMG -> INSTALL_ENV_IMG;
+ BUILD_IMG -> INSTALL_ENV_IMG [label="copy install", style="dashed"];
+ INSTALL_ENV_IMG -> INSTALL_DEVEL_IMG;
+ SPL -> INSTALL_DEVEL_IMG [label="copy", style="dashed"];
+ INSTALL_DEVEL_IMG -> INSTALL_BUILD_IMG;
+ INSTALL_BUILD_IMG -> INSTALL_TEST_IMG;
+
+ color=royalblue;
+ label = "docker/amd64/Dockerfile";
+ }
+ DISTRO_IMG -> ENV_IMG;
+ PKG -> ENV_IMG [label="install", style="dashed"];
+ SRC -> DEVEL_IMG [label="copy", style="dashed"];
+
+ subgraph clusterCache {
+ node [shape=note, style="rounded,filled", color=black, fillcolor=royalblue];
+ ENV_TAR [label="docker_amd64_env.tar"];
+ DEVEL_TAR [label="docker_amd64_devel.tar"];
+ BUILD_TAR [label="docker_amd64_build.tar"];
+ TEST_TAR [label="docker_amd64_test.tar"];
+ INSTALL_ENV_TAR [label="docker_amd64_install_env.tar"];
+ INSTALL_DEVEL_TAR [label="docker_amd64_install_devel.tar"];
+ INSTALL_BUILD_TAR [label="docker_amd64_install_build.tar"];
+ INSTALL_TEST_TAR [label="docker_amd64_install_test.tar"];
+
+ edge [color=red];
+ ENV_IMG -> ENV_TAR [label="make save_amd64_env"];
+ DEVEL_IMG -> DEVEL_TAR [label="make save_amd64_devel"];
+ BUILD_IMG -> BUILD_TAR [label="make save_amd64_build"];
+ TEST_IMG -> TEST_TAR [label="make save_amd64_test"];
+ INSTALL_ENV_IMG -> INSTALL_ENV_TAR [label="make save_amd64_install_env"];
+ INSTALL_DEVEL_IMG -> INSTALL_DEVEL_TAR [label="make save_amd64_install_devel"];
+ INSTALL_BUILD_IMG -> INSTALL_BUILD_TAR [label="make save_amd64_install_build"];
+ INSTALL_TEST_IMG -> INSTALL_TEST_TAR [label="make save_amd64_install_test"];
+
+ color=royalblue;
+ label = "cache/amd64/";
+ }
+}
+@enddot
diff --git a/ci/doc/docker.svg b/ci/doc/docker.svg
new file mode 100644
index 0000000..bd9bd6d
--- /dev/null
+++ b/ci/doc/docker.svg
@@ -0,0 +1,312 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.49.2 (0)
+ -->
+<!-- Title: DockerDeps Pages: 1 -->
+<svg width="1904pt" height="900pt"
+ viewBox="0.00 0.00 1904.00 899.75" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 895.75)">
+<title>DockerDeps</title>
+<polygon fill="white" stroke="transparent" points="-4,4 -4,-895.75 1900,-895.75 1900,4 -4,4"/>
+<g id="clust1" class="cluster">
+<title>clusterDockerfile</title>
+<polygon fill="none" stroke="royalblue" points="691,-116 691,-812.75 1253,-812.75 1253,-116 691,-116"/>
+<text text-anchor="middle" x="972" y="-797.55" font-family="Times,serif" font-size="14.00">docker/amd64/Dockerfile</text>
+</g>
+<g id="clust2" class="cluster">
+<title>clusterCache</title>
+<polygon fill="none" stroke="royalblue" points="8,-8 8,-83 1826,-83 1826,-8 8,-8"/>
+<text text-anchor="middle" x="917" y="-67.8" font-family="Times,serif" font-size="14.00">cache/amd64/</text>
+</g>
+<!-- DISTRO_IMG -->
+<g id="node1" class="node">
+<title>DISTRO_IMG</title>
+<path fill="royalblue" stroke="black" d="M893.5,-887.48C893.5,-889.28 868.18,-890.75 837,-890.75 805.82,-890.75 780.5,-889.28 780.5,-887.48 780.5,-887.48 780.5,-858.02 780.5,-858.02 780.5,-856.22 805.82,-854.75 837,-854.75 868.18,-854.75 893.5,-856.22 893.5,-858.02 893.5,-858.02 893.5,-887.48 893.5,-887.48"/>
+<path fill="none" stroke="black" d="M893.5,-887.48C893.5,-885.67 868.18,-884.2 837,-884.2 805.82,-884.2 780.5,-885.67 780.5,-887.48"/>
+<text text-anchor="middle" x="837" y="-869.05" font-family="Times,serif" font-size="14.00">ubuntu:latest</text>
+</g>
+<!-- ENV_IMG -->
+<g id="node5" class="node">
+<title>ENV_IMG</title>
+<path fill="royalblue" stroke="black" d="M1005,-777.1C1005,-779.74 961.52,-781.88 908,-781.88 854.48,-781.88 811,-779.74 811,-777.1 811,-777.1 811,-734.15 811,-734.15 811,-731.51 854.48,-729.37 908,-729.37 961.52,-729.37 1005,-731.51 1005,-734.15 1005,-734.15 1005,-777.1 1005,-777.1"/>
+<path fill="none" stroke="black" d="M1005,-777.1C1005,-774.47 961.52,-772.33 908,-772.33 854.48,-772.33 811,-774.47 811,-777.1"/>
+<text text-anchor="middle" x="908" y="-759.42" font-family="Times,serif" font-size="14.00">cpu_features:amd64_env</text>
+<text text-anchor="middle" x="908" y="-744.42" font-family="Times,serif" font-size="14.00">env</text>
+</g>
+<!-- DISTRO_IMG&#45;&gt;ENV_IMG -->
+<g id="edge10" class="edge">
+<title>DISTRO_IMG&#45;&gt;ENV_IMG</title>
+<path fill="none" stroke="black" d="M847.78,-854.26C858.17,-837.42 874.16,-811.49 887.05,-790.59"/>
+<polygon fill="black" stroke="black" points="890.09,-792.33 892.37,-781.98 884.14,-788.65 890.09,-792.33"/>
+</g>
+<!-- PKG -->
+<g id="node2" class="node">
+<title>PKG</title>
+<polygon fill="royalblue" stroke="black" points="1046.5,-891.75 915.5,-891.75 911.5,-887.75 911.5,-853.75 1042.5,-853.75 1046.5,-857.75 1046.5,-891.75"/>
+<polyline fill="none" stroke="black" points="1042.5,-887.75 911.5,-887.75 "/>
+<polyline fill="none" stroke="black" points="1042.5,-887.75 1042.5,-853.75 "/>
+<polyline fill="none" stroke="black" points="1042.5,-887.75 1046.5,-891.75 "/>
+<text text-anchor="middle" x="979" y="-876.55" font-family="Times,serif" font-size="14.00">packages</text>
+<text text-anchor="middle" x="979" y="-861.55" font-family="Times,serif" font-size="14.00">e.g. cmake, g++</text>
+</g>
+<!-- PKG&#45;&gt;ENV_IMG -->
+<g id="edge11" class="edge">
+<title>PKG&#45;&gt;ENV_IMG</title>
+<path fill="none" stroke="black" stroke-dasharray="5,2" d="M967.75,-853.51C957.4,-836.72 941.77,-811.38 929.09,-790.83"/>
+<polygon fill="black" stroke="black" points="931.91,-788.73 923.69,-782.06 925.96,-792.41 931.91,-788.73"/>
+<text text-anchor="middle" x="978.5" y="-824.55" font-family="Times,serif" font-size="14.00">install</text>
+</g>
+<!-- SRC -->
+<g id="node3" class="node">
+<title>SRC</title>
+<polygon fill="royalblue" stroke="black" points="1334.5,-773.62 1331.5,-777.62 1310.5,-777.62 1307.5,-773.62 1261.5,-773.62 1261.5,-737.62 1334.5,-737.62 1334.5,-773.62"/>
+<text text-anchor="middle" x="1298" y="-751.92" font-family="Times,serif" font-size="14.00">git repo</text>
+</g>
+<!-- DEVEL_IMG -->
+<g id="node6" class="node">
+<title>DEVEL_IMG</title>
+<path fill="royalblue" stroke="black" d="M1189,-673.85C1189,-676.49 1142.83,-678.63 1086,-678.63 1029.17,-678.63 983,-676.49 983,-673.85 983,-673.85 983,-630.9 983,-630.9 983,-628.26 1029.17,-626.12 1086,-626.12 1142.83,-626.12 1189,-628.26 1189,-630.9 1189,-630.9 1189,-673.85 1189,-673.85"/>
+<path fill="none" stroke="black" d="M1189,-673.85C1189,-671.22 1142.83,-669.08 1086,-669.08 1029.17,-669.08 983,-671.22 983,-673.85"/>
+<text text-anchor="middle" x="1086" y="-656.17" font-family="Times,serif" font-size="14.00">cpu_features:amd64_devel</text>
+<text text-anchor="middle" x="1086" y="-641.17" font-family="Times,serif" font-size="14.00">devel</text>
+</g>
+<!-- SRC&#45;&gt;DEVEL_IMG -->
+<g id="edge12" class="edge">
+<title>SRC&#45;&gt;DEVEL_IMG</title>
+<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1271.39,-737.62C1266.66,-734.8 1261.73,-731.99 1257,-729.5 1224.81,-712.57 1188.08,-695.89 1156.94,-682.48"/>
+<polygon fill="black" stroke="black" points="1158.03,-679.14 1147.46,-678.43 1155.28,-685.58 1158.03,-679.14"/>
+<text text-anchor="middle" x="1237" y="-700.3" font-family="Times,serif" font-size="14.00">copy</text>
+</g>
+<!-- SPL -->
+<g id="node4" class="node">
+<title>SPL</title>
+<polygon fill="royalblue" stroke="black" points="767,-477.88 764,-481.88 743,-481.88 740,-477.88 699,-477.88 699,-441.88 767,-441.88 767,-477.88"/>
+<text text-anchor="middle" x="733" y="-456.18" font-family="Times,serif" font-size="14.00">sample</text>
+</g>
+<!-- INSTALL_DEVEL_IMG -->
+<g id="node10" class="node">
+<title>INSTALL_DEVEL_IMG</title>
+<path fill="royalblue" stroke="black" d="M956.5,-378.1C956.5,-380.74 898.9,-382.88 828,-382.88 757.1,-382.88 699.5,-380.74 699.5,-378.1 699.5,-378.1 699.5,-335.15 699.5,-335.15 699.5,-332.51 757.1,-330.37 828,-330.37 898.9,-330.37 956.5,-332.51 956.5,-335.15 956.5,-335.15 956.5,-378.1 956.5,-378.1"/>
+<path fill="none" stroke="black" d="M956.5,-378.1C956.5,-375.47 898.9,-373.33 828,-373.33 757.1,-373.33 699.5,-375.47 699.5,-378.1"/>
+<text text-anchor="middle" x="828" y="-360.43" font-family="Times,serif" font-size="14.00">cpu_features:amd64_install_devel</text>
+<text text-anchor="middle" x="828" y="-345.43" font-family="Times,serif" font-size="14.00">install_devel</text>
+</g>
+<!-- SPL&#45;&gt;INSTALL_DEVEL_IMG -->
+<g id="edge7" class="edge">
+<title>SPL&#45;&gt;INSTALL_DEVEL_IMG</title>
+<path fill="none" stroke="black" stroke-dasharray="5,2" d="M749.12,-441.7C762.24,-427.71 781.16,-407.54 797.18,-390.47"/>
+<polygon fill="black" stroke="black" points="800.02,-392.56 804.31,-382.87 794.91,-387.77 800.02,-392.56"/>
+<text text-anchor="middle" x="803" y="-404.55" font-family="Times,serif" font-size="14.00">copy</text>
+</g>
+<!-- ENV_IMG&#45;&gt;DEVEL_IMG -->
+<g id="edge1" class="edge">
+<title>ENV_IMG&#45;&gt;DEVEL_IMG</title>
+<path fill="none" stroke="black" d="M952.46,-729.34C976.87,-715.45 1007.3,-698.14 1032.95,-683.55"/>
+<polygon fill="black" stroke="black" points="1034.84,-686.5 1041.8,-678.52 1031.38,-680.42 1034.84,-686.5"/>
+</g>
+<!-- INSTALL_ENV_IMG -->
+<g id="node9" class="node">
+<title>INSTALL_ENV_IMG</title>
+<path fill="royalblue" stroke="black" d="M1030.5,-481.35C1030.5,-483.99 975.59,-486.13 908,-486.13 840.41,-486.13 785.5,-483.99 785.5,-481.35 785.5,-481.35 785.5,-438.4 785.5,-438.4 785.5,-435.76 840.41,-433.62 908,-433.62 975.59,-433.62 1030.5,-435.76 1030.5,-438.4 1030.5,-438.4 1030.5,-481.35 1030.5,-481.35"/>
+<path fill="none" stroke="black" d="M1030.5,-481.35C1030.5,-478.72 975.59,-476.58 908,-476.58 840.41,-476.58 785.5,-478.72 785.5,-481.35"/>
+<text text-anchor="middle" x="908" y="-463.68" font-family="Times,serif" font-size="14.00">cpu_features:amd64_install_env</text>
+<text text-anchor="middle" x="908" y="-448.68" font-family="Times,serif" font-size="14.00">install_env</text>
+</g>
+<!-- ENV_IMG&#45;&gt;INSTALL_ENV_IMG -->
+<g id="edge4" class="edge">
+<title>ENV_IMG&#45;&gt;INSTALL_ENV_IMG</title>
+<path fill="none" stroke="black" d="M908,-729.33C908,-676.94 908,-556.49 908,-496.37"/>
+<polygon fill="black" stroke="black" points="911.5,-496.22 908,-486.22 904.5,-496.22 911.5,-496.22"/>
+</g>
+<!-- ENV_TAR -->
+<g id="node13" class="node">
+<title>ENV_TAR</title>
+<polygon fill="royalblue" stroke="black" points="186,-52 16,-52 16,-16 192,-16 192,-46 186,-52"/>
+<polyline fill="none" stroke="black" points="186,-52 186,-46 "/>
+<polyline fill="none" stroke="black" points="192,-46 186,-46 "/>
+<text text-anchor="middle" x="104" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_env.tar</text>
+</g>
+<!-- ENV_IMG&#45;&gt;ENV_TAR -->
+<g id="edge13" class="edge">
+<title>ENV_IMG&#45;&gt;ENV_TAR</title>
+<path fill="none" stroke="red" d="M810.87,-751.31C609.47,-743.14 165,-717.82 165,-653.38 165,-653.38 165,-653.38 165,-149.12 165,-115.26 143.85,-81.71 126.46,-59.84"/>
+<polygon fill="red" stroke="red" points="129.09,-57.54 120.03,-52.05 123.7,-61.99 129.09,-57.54"/>
+<text text-anchor="middle" x="246.5" y="-404.55" font-family="Times,serif" font-size="14.00">make save_amd64_env</text>
+</g>
+<!-- BUILD_IMG -->
+<g id="node7" class="node">
+<title>BUILD_IMG</title>
+<path fill="royalblue" stroke="black" d="M1245,-584.6C1245,-587.24 1199.28,-589.38 1143,-589.38 1086.72,-589.38 1041,-587.24 1041,-584.6 1041,-584.6 1041,-541.65 1041,-541.65 1041,-539.01 1086.72,-536.87 1143,-536.87 1199.28,-536.87 1245,-539.01 1245,-541.65 1245,-541.65 1245,-584.6 1245,-584.6"/>
+<path fill="none" stroke="black" d="M1245,-584.6C1245,-581.97 1199.28,-579.83 1143,-579.83 1086.72,-579.83 1041,-581.97 1041,-584.6"/>
+<text text-anchor="middle" x="1143" y="-566.92" font-family="Times,serif" font-size="14.00">cpu_features:amd64_build</text>
+<text text-anchor="middle" x="1143" y="-551.92" font-family="Times,serif" font-size="14.00">build</text>
+</g>
+<!-- DEVEL_IMG&#45;&gt;BUILD_IMG -->
+<g id="edge2" class="edge">
+<title>DEVEL_IMG&#45;&gt;BUILD_IMG</title>
+<path fill="none" stroke="black" d="M1102.49,-626.14C1108.28,-617.28 1114.88,-607.17 1121.04,-597.73"/>
+<polygon fill="black" stroke="black" points="1124.01,-599.59 1126.55,-589.3 1118.15,-595.76 1124.01,-599.59"/>
+</g>
+<!-- DEVEL_TAR -->
+<g id="node14" class="node">
+<title>DEVEL_TAR</title>
+<polygon fill="royalblue" stroke="black" points="395.5,-52 210.5,-52 210.5,-16 401.5,-16 401.5,-46 395.5,-52"/>
+<polyline fill="none" stroke="black" points="395.5,-52 395.5,-46 "/>
+<polyline fill="none" stroke="black" points="401.5,-46 395.5,-46 "/>
+<text text-anchor="middle" x="306" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_devel.tar</text>
+</g>
+<!-- DEVEL_IMG&#45;&gt;DEVEL_TAR -->
+<g id="edge14" class="edge">
+<title>DEVEL_IMG&#45;&gt;DEVEL_TAR</title>
+<path fill="none" stroke="red" d="M982.94,-648.59C792.56,-642.05 405,-621.67 405,-564.12 405,-564.12 405,-564.12 405,-149.12 405,-110.26 371.83,-78.15 343.9,-58"/>
+<polygon fill="red" stroke="red" points="345.65,-54.96 335.44,-52.14 341.66,-60.71 345.65,-54.96"/>
+<text text-anchor="middle" x="493" y="-352.93" font-family="Times,serif" font-size="14.00">make save_amd64_devel</text>
+</g>
+<!-- TEST_IMG -->
+<g id="node8" class="node">
+<title>TEST_IMG</title>
+<path fill="royalblue" stroke="black" d="M1245,-481.35C1245,-483.99 1201.07,-486.13 1147,-486.13 1092.93,-486.13 1049,-483.99 1049,-481.35 1049,-481.35 1049,-438.4 1049,-438.4 1049,-435.76 1092.93,-433.62 1147,-433.62 1201.07,-433.62 1245,-435.76 1245,-438.4 1245,-438.4 1245,-481.35 1245,-481.35"/>
+<path fill="none" stroke="black" d="M1245,-481.35C1245,-478.72 1201.07,-476.58 1147,-476.58 1092.93,-476.58 1049,-478.72 1049,-481.35"/>
+<text text-anchor="middle" x="1147" y="-463.68" font-family="Times,serif" font-size="14.00">cpu_features:amd64_test</text>
+<text text-anchor="middle" x="1147" y="-448.68" font-family="Times,serif" font-size="14.00">test</text>
+</g>
+<!-- BUILD_IMG&#45;&gt;TEST_IMG -->
+<g id="edge3" class="edge">
+<title>BUILD_IMG&#45;&gt;TEST_IMG</title>
+<path fill="none" stroke="black" d="M1144,-536.84C1144.48,-524.63 1145.07,-509.79 1145.59,-496.47"/>
+<polygon fill="black" stroke="black" points="1149.1,-496.32 1146,-486.19 1142.11,-496.05 1149.1,-496.32"/>
+</g>
+<!-- BUILD_IMG&#45;&gt;INSTALL_ENV_IMG -->
+<g id="edge5" class="edge">
+<title>BUILD_IMG&#45;&gt;INSTALL_ENV_IMG</title>
+<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1084.61,-536.97C1051.68,-522.78 1010.38,-504.99 976,-490.17"/>
+<polygon fill="black" stroke="black" points="977.07,-486.82 966.5,-486.08 974.3,-493.25 977.07,-486.82"/>
+<text text-anchor="middle" x="1080" y="-507.8" font-family="Times,serif" font-size="14.00">copy install</text>
+</g>
+<!-- BUILD_TAR -->
+<g id="node15" class="node">
+<title>BUILD_TAR</title>
+<polygon fill="royalblue" stroke="black" points="1812,-52 1630,-52 1630,-16 1818,-16 1818,-46 1812,-52"/>
+<polyline fill="none" stroke="black" points="1812,-52 1812,-46 "/>
+<polyline fill="none" stroke="black" points="1818,-46 1812,-46 "/>
+<text text-anchor="middle" x="1724" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_build.tar</text>
+</g>
+<!-- BUILD_IMG&#45;&gt;BUILD_TAR -->
+<g id="edge15" class="edge">
+<title>BUILD_IMG&#45;&gt;BUILD_TAR</title>
+<path fill="none" stroke="red" d="M1245.18,-554.53C1411.4,-540.79 1722,-508.71 1722,-460.88 1722,-460.88 1722,-460.88 1722,-149.12 1722,-119.36 1722.69,-85.23 1723.26,-62.11"/>
+<polygon fill="red" stroke="red" points="1726.76,-62.1 1723.52,-52.01 1719.76,-61.92 1726.76,-62.1"/>
+<text text-anchor="middle" x="1809" y="-301.3" font-family="Times,serif" font-size="14.00">make save_amd64_build</text>
+</g>
+<!-- TEST_TAR -->
+<g id="node16" class="node">
+<title>TEST_TAR</title>
+<polygon fill="royalblue" stroke="black" points="1606,-52 1432,-52 1432,-16 1612,-16 1612,-46 1606,-52"/>
+<polyline fill="none" stroke="black" points="1606,-52 1606,-46 "/>
+<polyline fill="none" stroke="black" points="1612,-46 1606,-46 "/>
+<text text-anchor="middle" x="1522" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_test.tar</text>
+</g>
+<!-- TEST_IMG&#45;&gt;TEST_TAR -->
+<g id="edge16" class="edge">
+<title>TEST_IMG&#45;&gt;TEST_TAR</title>
+<path fill="none" stroke="red" d="M1245.07,-451.87C1356.77,-441.13 1524,-415.4 1524,-357.62 1524,-357.62 1524,-357.62 1524,-149.12 1524,-119.36 1523.31,-85.23 1522.74,-62.11"/>
+<polygon fill="red" stroke="red" points="1526.24,-61.92 1522.48,-52.01 1519.24,-62.1 1526.24,-61.92"/>
+<text text-anchor="middle" x="1607" y="-249.68" font-family="Times,serif" font-size="14.00">make save_amd64_test</text>
+</g>
+<!-- INSTALL_ENV_IMG&#45;&gt;INSTALL_DEVEL_IMG -->
+<g id="edge6" class="edge">
+<title>INSTALL_ENV_IMG&#45;&gt;INSTALL_DEVEL_IMG</title>
+<path fill="none" stroke="black" d="M888.02,-433.59C877.81,-420.66 865.25,-404.76 854.26,-390.86"/>
+<polygon fill="black" stroke="black" points="856.95,-388.62 848,-382.94 851.46,-392.96 856.95,-388.62"/>
+</g>
+<!-- INSTALL_ENV_TAR -->
+<g id="node17" class="node">
+<title>INSTALL_ENV_TAR</title>
+<polygon fill="royalblue" stroke="black" points="1407.5,-52 1186.5,-52 1186.5,-16 1413.5,-16 1413.5,-46 1407.5,-52"/>
+<polyline fill="none" stroke="black" points="1407.5,-52 1407.5,-46 "/>
+<polyline fill="none" stroke="black" points="1413.5,-46 1407.5,-46 "/>
+<text text-anchor="middle" x="1300" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_install_env.tar</text>
+</g>
+<!-- INSTALL_ENV_IMG&#45;&gt;INSTALL_ENV_TAR -->
+<g id="edge17" class="edge">
+<title>INSTALL_ENV_IMG&#45;&gt;INSTALL_ENV_TAR</title>
+<path fill="none" stroke="red" d="M1012.88,-434.97C1121.03,-409.58 1274,-371.26 1274,-357.62 1274,-357.62 1274,-357.62 1274,-149.12 1274,-118.64 1282.93,-84.69 1290.32,-61.81"/>
+<polygon fill="red" stroke="red" points="1293.71,-62.72 1293.57,-52.12 1287.07,-60.49 1293.71,-62.72"/>
+<text text-anchor="middle" x="1381" y="-249.68" font-family="Times,serif" font-size="14.00">make save_amd64_install_env</text>
+</g>
+<!-- INSTALL_BUILD_IMG -->
+<g id="node11" class="node">
+<title>INSTALL_BUILD_IMG</title>
+<path fill="royalblue" stroke="black" d="M955.5,-274.85C955.5,-277.49 898.35,-279.63 828,-279.63 757.65,-279.63 700.5,-277.49 700.5,-274.85 700.5,-274.85 700.5,-231.9 700.5,-231.9 700.5,-229.26 757.65,-227.12 828,-227.12 898.35,-227.12 955.5,-229.26 955.5,-231.9 955.5,-231.9 955.5,-274.85 955.5,-274.85"/>
+<path fill="none" stroke="black" d="M955.5,-274.85C955.5,-272.22 898.35,-270.08 828,-270.08 757.65,-270.08 700.5,-272.22 700.5,-274.85"/>
+<text text-anchor="middle" x="828" y="-257.18" font-family="Times,serif" font-size="14.00">cpu_features:amd64_install_build</text>
+<text text-anchor="middle" x="828" y="-242.18" font-family="Times,serif" font-size="14.00">install_build</text>
+</g>
+<!-- INSTALL_DEVEL_IMG&#45;&gt;INSTALL_BUILD_IMG -->
+<g id="edge8" class="edge">
+<title>INSTALL_DEVEL_IMG&#45;&gt;INSTALL_BUILD_IMG</title>
+<path fill="none" stroke="black" d="M828,-330.34C828,-318.13 828,-303.29 828,-289.97"/>
+<polygon fill="black" stroke="black" points="831.5,-289.69 828,-279.69 824.5,-289.69 831.5,-289.69"/>
+</g>
+<!-- INSTALL_DEVEL_TAR -->
+<g id="node18" class="node">
+<title>INSTALL_DEVEL_TAR</title>
+<polygon fill="royalblue" stroke="black" points="656,-52 420,-52 420,-16 662,-16 662,-46 656,-52"/>
+<polyline fill="none" stroke="black" points="656,-52 656,-46 "/>
+<polyline fill="none" stroke="black" points="662,-46 656,-46 "/>
+<text text-anchor="middle" x="541" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_install_devel.tar</text>
+</g>
+<!-- INSTALL_DEVEL_IMG&#45;&gt;INSTALL_DEVEL_TAR -->
+<g id="edge18" class="edge">
+<title>INSTALL_DEVEL_IMG&#45;&gt;INSTALL_DEVEL_TAR</title>
+<path fill="none" stroke="red" d="M761.39,-330.48C708.37,-307.05 636.42,-266.99 595,-209.25 562.63,-164.12 549.27,-99.06 544.06,-62.54"/>
+<polygon fill="red" stroke="red" points="547.47,-61.64 542.7,-52.18 540.53,-62.55 547.47,-61.64"/>
+<text text-anchor="middle" x="708.5" y="-198.05" font-family="Times,serif" font-size="14.00">make save_amd64_install_devel</text>
+</g>
+<!-- INSTALL_TEST_IMG -->
+<g id="node12" class="node">
+<title>INSTALL_TEST_IMG</title>
+<path fill="royalblue" stroke="black" d="M948.5,-171.6C948.5,-174.24 893.15,-176.38 825,-176.38 756.85,-176.38 701.5,-174.24 701.5,-171.6 701.5,-171.6 701.5,-128.65 701.5,-128.65 701.5,-126.01 756.85,-123.87 825,-123.87 893.15,-123.87 948.5,-126.01 948.5,-128.65 948.5,-128.65 948.5,-171.6 948.5,-171.6"/>
+<path fill="none" stroke="black" d="M948.5,-171.6C948.5,-168.97 893.15,-166.83 825,-166.83 756.85,-166.83 701.5,-168.97 701.5,-171.6"/>
+<text text-anchor="middle" x="825" y="-153.93" font-family="Times,serif" font-size="14.00">cpu_features:amd64_install_test</text>
+<text text-anchor="middle" x="825" y="-138.93" font-family="Times,serif" font-size="14.00">install_test</text>
+</g>
+<!-- INSTALL_BUILD_IMG&#45;&gt;INSTALL_TEST_IMG -->
+<g id="edge9" class="edge">
+<title>INSTALL_BUILD_IMG&#45;&gt;INSTALL_TEST_IMG</title>
+<path fill="none" stroke="black" d="M827.25,-227.09C826.89,-214.88 826.45,-200.04 826.05,-186.72"/>
+<polygon fill="black" stroke="black" points="829.54,-186.33 825.75,-176.44 822.55,-186.54 829.54,-186.33"/>
+</g>
+<!-- INSTALL_BUILD_TAR -->
+<g id="node19" class="node">
+<title>INSTALL_BUILD_TAR</title>
+<polygon fill="royalblue" stroke="black" points="1162.5,-52 929.5,-52 929.5,-16 1168.5,-16 1168.5,-46 1162.5,-52"/>
+<polyline fill="none" stroke="black" points="1162.5,-52 1162.5,-46 "/>
+<polyline fill="none" stroke="black" points="1168.5,-46 1162.5,-46 "/>
+<text text-anchor="middle" x="1049" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_install_build.tar</text>
+</g>
+<!-- INSTALL_BUILD_IMG&#45;&gt;INSTALL_BUILD_TAR -->
+<g id="edge19" class="edge">
+<title>INSTALL_BUILD_IMG&#45;&gt;INSTALL_BUILD_TAR</title>
+<path fill="none" stroke="red" d="M882.76,-227.11C907.43,-214.09 935.91,-196.66 958,-176.25 994.16,-142.85 1022.19,-92.11 1037.09,-61.41"/>
+<polygon fill="red" stroke="red" points="1040.34,-62.72 1041.46,-52.19 1034.02,-59.72 1040.34,-62.72"/>
+<text text-anchor="middle" x="1117.5" y="-146.43" font-family="Times,serif" font-size="14.00">make save_amd64_install_build</text>
+</g>
+<!-- INSTALL_TEST_TAR -->
+<g id="node20" class="node">
+<title>INSTALL_TEST_TAR</title>
+<polygon fill="royalblue" stroke="black" points="905.5,-52 680.5,-52 680.5,-16 911.5,-16 911.5,-46 905.5,-52"/>
+<polyline fill="none" stroke="black" points="905.5,-52 905.5,-46 "/>
+<polyline fill="none" stroke="black" points="911.5,-46 905.5,-46 "/>
+<text text-anchor="middle" x="796" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_install_test.tar</text>
+</g>
+<!-- INSTALL_TEST_IMG&#45;&gt;INSTALL_TEST_TAR -->
+<g id="edge20" class="edge">
+<title>INSTALL_TEST_IMG&#45;&gt;INSTALL_TEST_TAR</title>
+<path fill="none" stroke="red" d="M799.99,-123.98C795.9,-118.47 792.26,-112.36 790,-106 785.07,-92.11 786.03,-75.77 788.46,-62.27"/>
+<polygon fill="red" stroke="red" points="791.96,-62.66 790.65,-52.15 785.12,-61.19 791.96,-62.66"/>
+<text text-anchor="middle" x="898.5" y="-94.8" font-family="Times,serif" font-size="14.00">make save_amd64_install_test</text>
+</g>
+</g>
+</svg>
diff --git a/ci/doc/generate_image.sh b/ci/doc/generate_image.sh
new file mode 100755
index 0000000..15f1774
--- /dev/null
+++ b/ci/doc/generate_image.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+set -ex
+
+rm -f ./*.svg ./*.png
+for i in *.dot; do
+ plantuml -Tsvg "$i";
+done
diff --git a/ci/docker/amd64/Dockerfile b/ci/docker/amd64/Dockerfile
new file mode 100644
index 0000000..9b25e28
--- /dev/null
+++ b/ci/docker/amd64/Dockerfile
@@ -0,0 +1,48 @@
+# Create a virtual environment with all tools installed
+# ref: https://hub.docker.com/_/ubuntu
+FROM ubuntu:latest AS env
+LABEL maintainer="corentinl@google.com"
+# Install system build dependencies
+ENV PATH=/usr/local/bin:$PATH
+RUN apt-get update -qq \
+&& DEBIAN_FRONTEND=noninteractive apt-get install -yq git wget libssl-dev build-essential \
+ ninja-build python3 pkgconf libglib2.0-dev \
+&& apt-get clean \
+&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
+ENTRYPOINT ["/usr/bin/bash", "-c"]
+CMD ["/usr/bin/bash"]
+
+# Install CMake 3.21.3
+RUN wget "https://cmake.org/files/v3.21/cmake-3.21.3-linux-x86_64.sh" \
+&& chmod a+x cmake-3.21.3-linux-x86_64.sh \
+&& ./cmake-3.21.3-linux-x86_64.sh --prefix=/usr/local/ --skip-license \
+&& rm cmake-3.21.3-linux-x86_64.sh
+
+FROM env AS devel
+WORKDIR /home/project
+COPY . .
+
+FROM devel AS build
+RUN cmake -version
+RUN cmake -S. -Bbuild
+RUN cmake --build build --target all -v
+RUN cmake --build build --target install -v
+
+FROM build AS test
+ENV CTEST_OUTPUT_ON_FAILURE=1
+RUN cmake --build build --target test -v
+
+# Test install rules
+FROM env AS install_env
+COPY --from=build /usr/local /usr/local/
+
+FROM install_env AS install_devel
+WORKDIR /home/sample
+COPY ci/sample .
+
+FROM install_devel AS install_build
+RUN cmake -S. -Bbuild
+RUN cmake --build build --target all -v
+
+FROM install_build AS install_test
+RUN cmake --build build --target test
diff --git a/ci/docker/toolchain/Dockerfile b/ci/docker/toolchain/Dockerfile
new file mode 100644
index 0000000..1bf25ed
--- /dev/null
+++ b/ci/docker/toolchain/Dockerfile
@@ -0,0 +1,34 @@
+# Create a virtual environment with all tools installed
+# ref: https://hub.docker.com/_/ubuntu
+FROM ubuntu:latest AS env
+LABEL maintainer="corentinl@google.com"
+# Install system build dependencies
+ENV PATH=/usr/local/bin:$PATH
+RUN apt-get update -qq \
+&& DEBIAN_FRONTEND=noninteractive apt-get install -yq git wget libssl-dev build-essential \
+ ninja-build python3 pkgconf libglib2.0-dev \
+&& apt-get clean \
+&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
+ENTRYPOINT ["/usr/bin/bash", "-c"]
+CMD ["/usr/bin/bash"]
+
+# Install CMake 3.21.3
+RUN wget "https://cmake.org/files/v3.21/cmake-3.21.3-linux-x86_64.sh" \
+&& chmod a+x cmake-3.21.3-linux-x86_64.sh \
+&& ./cmake-3.21.3-linux-x86_64.sh --prefix=/usr/local/ --skip-license \
+&& rm cmake-3.21.3-linux-x86_64.sh
+
+FROM env AS devel
+WORKDIR /home/project
+COPY . .
+
+ARG TARGET
+ENV TARGET ${TARGET:-unknown}
+
+FROM devel AS build
+RUN cmake -version
+RUN ./scripts/run_integration.sh build
+
+FROM build AS test
+RUN ./scripts/run_integration.sh qemu
+RUN ./scripts/run_integration.sh test
diff --git a/ci/sample/CMakeLists.txt b/ci/sample/CMakeLists.txt
new file mode 100644
index 0000000..b60e92f
--- /dev/null
+++ b/ci/sample/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 3.15)
+project(Sample VERSION 1.0.0 LANGUAGES CXX)
+
+include(CTest)
+find_package(CpuFeatures REQUIRED)
+
+add_executable(sample main.cpp)
+target_compile_features(sample PUBLIC cxx_std_11)
+set_target_properties(sample PROPERTIES
+ CXX_STANDARD 11
+ CXX_STANDARD_REQUIRED ON
+ VERSION ${PROJECT_VERSION})
+target_link_libraries(sample PRIVATE CpuFeatures::cpu_features)
+
+if(BUILD_TESTING)
+ add_test(NAME sample_test COMMAND sample)
+endif()
+
+include(GNUInstallDirs)
+install(TARGETS sample
+ EXPORT SampleTargets
+ DESTINATION ${CMAKE_INSTALL_BIN_DIR})
diff --git a/ci/sample/main.cpp b/ci/sample/main.cpp
new file mode 100644
index 0000000..45ec651
--- /dev/null
+++ b/ci/sample/main.cpp
@@ -0,0 +1,11 @@
+#include <iostream>
+
+#include "cpuinfo_x86.h"
+
+using namespace cpu_features;
+
+int main(int /*argc*/, char** /*argv*/) {
+ static const X86Features features = GetX86Info().features;
+ std::cout << std::endl;
+ return 0;
+}
diff --git a/ci/vagrant/freebsd/Vagrantfile b/ci/vagrant/freebsd/Vagrantfile
new file mode 100644
index 0000000..7ef7bfa
--- /dev/null
+++ b/ci/vagrant/freebsd/Vagrantfile
@@ -0,0 +1,102 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+# All Vagrant configuration is done below. The "2" in Vagrant.configure
+# configures the configuration version (we support older styles for
+# backwards compatibility). Please don't change it unless you know what
+# you're doing.
+Vagrant.configure("2") do |config|
+ # The most common configuration options are documented and commented below.
+ # For a complete reference, please see the online documentation at
+ # https://docs.vagrantup.com.
+
+ # Every Vagrant development environment requires a box. You can search for
+ # boxes at https://vagrantcloud.com/search.
+ config.vm.guest = :freebsd
+ config.vm.box = "generic/freebsd12"
+
+ config.ssh.shell = "sh"
+
+ # Disable automatic box update checking. If you disable this, then
+ # boxes will only be checked for updates when the user runs
+ # `vagrant box outdated`. This is not recommended.
+ # config.vm.box_check_update = false
+
+ # Create a forwarded port mapping which allows access to a specific port
+ # within the machine from a port on the host machine. In the example below,
+ # accessing "localhost:8080" will access port 80 on the guest machine.
+ # NOTE: This will enable public access to the opened port
+ # config.vm.network "forwarded_port", guest: 80, host: 8080
+
+ # Create a forwarded port mapping which allows access to a specific port
+ # within the machine from a port on the host machine and only allow access
+ # via 127.0.0.1 to disable public access
+ # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"
+
+ # Create a private network, which allows host-only access to the machine
+ # using a specific IP.
+ # config.vm.network "private_network", ip: "192.168.33.10"
+
+ # Create a public network, which generally matched to bridged network.
+ # Bridged networks make the machine appear as another physical device on
+ # your network.
+ # config.vm.network "public_network"
+
+ # Share an additional folder to the guest VM. The first argument is
+ # the path on the host to the actual folder. The second argument is
+ # the path on the guest to mount the folder. And the optional third
+ # argument is a set of non-required options.
+ #config.vm.synced_folder "../../..", "/home/vagrant/project"
+ config.vm.synced_folder ".", "/vagrant", id: "vagrant-root", disabled: true
+
+ config.vm.provision "file", source: "../../../CMakeLists.txt", destination: "$HOME/project/"
+ config.vm.provision "file", source: "../../../cmake", destination: "$HOME/project/"
+ config.vm.provision "file", source: "../../../include", destination: "$HOME/project/"
+ config.vm.provision "file", source: "../../../src", destination: "$HOME/project/"
+ config.vm.provision "file", source: "../../../test", destination: "$HOME/project/"
+
+ # Provider-specific configuration so you can fine-tune various
+ # backing providers for Vagrant. These expose provider-specific options.
+ # Example for VirtualBox:
+ #
+ # config.vm.provider "virtualbox" do |vb|
+ # # Display the VirtualBox GUI when booting the machine
+ # vb.gui = true
+ #
+ # # Customize the amount of memory on the VM:
+ # vb.memory = "1024"
+ # end
+ #
+ # View the documentation for the provider you are using for more
+ # information on available options.
+
+ # Enable provisioning with a shell script. Additional provisioners such as
+ # Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
+ # documentation for more information about their specific syntax and use.
+ # note: clang installed by default
+ config.vm.provision "env", type: "shell", inline:<<-SHELL
+ set -x
+ pkg update -f
+ pkg install -y git cmake
+ SHELL
+ config.vm.provision "devel", type: "shell", inline:<<-SHELL
+ set -x
+ cd project
+ ls
+ SHELL
+ config.vm.provision "configure", type: "shell", inline:<<-SHELL
+ set -x
+ cd project
+ cmake -S. -Bbuild -DBUILD_TESTING=ON
+ SHELL
+ config.vm.provision "build", type: "shell", inline:<<-SHELL
+ set -x
+ cd project
+ cmake --build build -v
+ SHELL
+ config.vm.provision "test", type: "shell", inline:<<-SHELL
+ set -x
+ cd project
+ cmake --build build --target test -v
+ SHELL
+end
diff --git a/cmake/README.md b/cmake/README.md
index b6baeaa..b2d96c4 100644
--- a/cmake/README.md
+++ b/cmake/README.md
@@ -2,27 +2,29 @@
## Recommended usage : Incorporating cpu_features into a CMake project
- For API / ABI compatibility reasons, it is recommended to build and use
- cpu_features in a subdirectory of your project or as an embedded dependency.
+For API / ABI compatibility reasons, it is recommended to build and use
+cpu_features in a subdirectory of your project or as an embedded dependency.
- This is similar to the recommended usage of the googletest framework
- ( https://github.com/google/googletest/blob/master/googletest/README.md )
+This is similar to the recommended usage of the googletest framework
+( https://github.com/google/googletest/blob/main/googletest/README.md )
- Build and use step-by-step
+Build and use step-by-step
- 1- Download cpu_features and copy it in a sub-directory in your project.
- or add cpu_features as a git-submodule in your project
+1- Download cpu_features and copy it in a sub-directory in your project.
+or add cpu_features as a git-submodule in your project
- 2- You can then use the cmake command `add_subdirectory()` to include
- cpu_features directly and use the `cpu_features` target in your project.
+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
- your executable or of your library.
+3- Add the `cpu_features` target to the `target_link_libraries()` section of
+your executable or of your library.
-## Enabling tests
+## Disabling tests
- CMake default options for cpu_features is Release built type with tests
- disabled. To enable testing set cmake `BUILD_TESTING` variable to `ON`,
- [.travis.yml](../.travis.yml) and [appveyor.yml](../appveyor.yml) have up to
- date examples.
+CMake default options for cpu_features is `Release` built type with tests
+enabled. To disable testing set cmake `BUILD_TESTING` variable to `OFF`.
+e.g.
+```sh
+cmake -S. -Bbuild -DBUILD_TESTING=OFF
+```
diff --git a/cmake/googletest.CMakeLists.txt.in b/cmake/googletest.CMakeLists.txt.in
index d60a33e..8003c2c 100644
--- a/cmake/googletest.CMakeLists.txt.in
+++ b/cmake/googletest.CMakeLists.txt.in
@@ -5,7 +5,7 @@ project(googletest-download NONE)
include(ExternalProject)
ExternalProject_Add(googletest
GIT_REPOSITORY https://github.com/google/googletest.git
- GIT_TAG master
+ GIT_TAG main
SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src"
BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build"
CONFIGURE_COMMAND ""
diff --git a/include/cpu_features_macros.h b/include/cpu_features_macros.h
index 4b231a1..6a2f76a 100644
--- a/include/cpu_features_macros.h
+++ b/include/cpu_features_macros.h
@@ -67,20 +67,33 @@
// Os
////////////////////////////////////////////////////////////////////////////////
-#if defined(__linux__)
-#define CPU_FEATURES_OS_LINUX_OR_ANDROID
+#if (defined(__freebsd__) || defined(__FreeBSD__))
+#define CPU_FEATURES_OS_FREEBSD
#endif
#if defined(__ANDROID__)
#define CPU_FEATURES_OS_ANDROID
#endif
+#if defined(__linux__) && !defined(CPU_FEATURES_OS_FREEBSD) && \
+ !defined(CPU_FEATURES_OS_ANDROID)
+#define CPU_FEATURES_OS_LINUX
+#endif
+
#if (defined(_WIN64) || defined(_WIN32))
#define CPU_FEATURES_OS_WINDOWS
#endif
#if (defined(__apple__) || defined(__APPLE__) || defined(__MACH__))
-#define CPU_FEATURES_OS_DARWIN
+// From https://stackoverflow.com/a/49560690
+#include "TargetConditionals.h"
+#if defined(TARGET_OS_OSX)
+#define CPU_FEATURES_OS_MACOS
+#endif
+#if defined(TARGET_OS_IPHONE)
+// This is set for any non-Mac Apple products (IOS, TV, WATCH)
+#define CPU_FEATURES_OS_IPHONE
+#endif
#endif
////////////////////////////////////////////////////////////////////////////////
@@ -213,4 +226,24 @@
#endif // defined(__mips_msa)
#endif // defined(CPU_FEATURES_ARCH_MIPS)
+////////////////////////////////////////////////////////////////////////////////
+// Utils
+////////////////////////////////////////////////////////////////////////////////
+
+// Communicates to the compiler that the block is unreachable
+#if defined(CPU_FEATURES_COMPILER_CLANG) || defined(CPU_FEATURES_COMPILER_GCC)
+#define CPU_FEATURES_UNREACHABLE() __builtin_unreachable()
+#elif defined(CPU_FEATURES_COMPILER_MSC)
+#define CPU_FEATURES_UNREACHABLE() __assume(0)
+#else
+#define CPU_FEATURES_UNREACHABLE()
+#endif
+
+// Communicates to the compiler that the function is now deprecated
+#if defined(CPU_FEATURES_COMPILER_CLANG) || defined(CPU_FEATURES_COMPILER_GCC)
+#define CPU_FEATURES_DEPRECATED(message) __attribute__((deprecated(message)))
+#else
+#define CPU_FEATURES_DEPRECATED(message)
+#endif
+
#endif // CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_
diff --git a/include/cpuinfo_aarch64.h b/include/cpuinfo_aarch64.h
index d85d46d..1b57d21 100644
--- a/include/cpuinfo_aarch64.h
+++ b/include/cpuinfo_aarch64.h
@@ -71,6 +71,7 @@ typedef struct {
int dgh : 1; // Data Gathering Hint instruction.
int rng : 1; // True random number generator support.
int bti : 1; // Branch target identification.
+ int mte : 1; // Memory tagging extension.
// Make sure to update Aarch64FeaturesEnum below if you add a field here.
} Aarch64Features;
@@ -139,6 +140,7 @@ typedef enum {
AARCH64_DGH,
AARCH64_RNG,
AARCH64_BTI,
+ AARCH64_MTE,
AARCH64_LAST_,
} Aarch64FeaturesEnum;
diff --git a/include/cpuinfo_ppc.h b/include/cpuinfo_ppc.h
index f691194..da3e696 100644
--- a/include/cpuinfo_ppc.h
+++ b/include/cpuinfo_ppc.h
@@ -17,7 +17,6 @@
#include "cpu_features_cache_info.h"
#include "cpu_features_macros.h"
-#include "internal/hwcaps.h"
CPU_FEATURES_START_CPP_NAMESPACE
@@ -71,15 +70,19 @@ typedef struct {
PPCFeatures features;
} PPCInfo;
-// This function is guaranteed to be malloc, memset and memcpy free.
PPCInfo GetPPCInfo(void);
typedef struct {
+ char platform[64]; // 0 terminated string
+ char base_platform[64]; // 0 terminated string
+} PPCPlatformTypeStrings;
+
+typedef struct {
char platform[64]; // 0 terminated string
char model[64]; // 0 terminated string
char machine[64]; // 0 terminated string
char cpu[64]; // 0 terminated string
- PlatformType type;
+ PPCPlatformTypeStrings type;
} PPCPlatformStrings;
PPCPlatformStrings GetPPCPlatformStrings(void);
diff --git a/include/cpuinfo_x86.h b/include/cpuinfo_x86.h
index 8d40f71..88daca4 100644
--- a/include/cpuinfo_x86.h
+++ b/include/cpuinfo_x86.h
@@ -21,6 +21,13 @@
CPU_FEATURES_START_CPP_NAMESPACE
+// CPUID Vendors
+#define CPU_FEATURES_VENDOR_GENUINE_INTEL "GenuineIntel"
+#define CPU_FEATURES_VENDOR_AUTHENTIC_AMD "AuthenticAMD"
+#define CPU_FEATURES_VENDOR_HYGON_GENUINE "HygonGenuine"
+#define CPU_FEATURES_VENDOR_CENTAUR_HAULS "CentaurHauls"
+#define CPU_FEATURES_VENDOR_SHANGHAI " Shanghai "
+
// See https://en.wikipedia.org/wiki/CPUID for a list of x86 cpu features.
// The field names are based on the short name provided in the wikipedia tables.
typedef struct {
@@ -89,6 +96,7 @@ typedef struct {
int dca : 1;
int ss : 1;
+ int adx : 1;
// Make sure to update X86FeaturesEnum below if you add a field here.
} X86Features;
@@ -97,46 +105,69 @@ typedef struct {
int family;
int model;
int stepping;
- char vendor[13]; // 0 terminated string
+ char vendor[13]; // 0 terminated string
+ char brand_string[49]; // 0 terminated string
} X86Info;
// Calls cpuid and returns an initialized X86info.
-// This function is guaranteed to be malloc, memset and memcpy free.
X86Info GetX86Info(void);
// Returns cache hierarchy informations.
// Can call cpuid multiple times.
// Only works on Intel CPU at the moment.
-// This function is guaranteed to be malloc, memset and memcpy free.
CacheInfo GetX86CacheInfo(void);
typedef enum {
X86_UNKNOWN,
- 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
- AMD_HAMMER, // K8
- AMD_K10, // K10
- AMD_BOBCAT, // K14
- AMD_BULLDOZER, // K15
- AMD_JAGUAR, // K16
- AMD_ZEN, // K17
+ 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
+ X86_MICROARCHITECTURE_LAST_,
} X86Microarchitecture;
// Returns the underlying microarchitecture by looking at X86Info's vendor,
@@ -146,7 +177,7 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info);
// Calls cpuid and fills the brand_string.
// - brand_string *must* be of size 49 (beware of array decaying).
// - brand_string will be zero terminated.
-// - This function calls memcpy.
+CPU_FEATURES_DEPRECATED("brand_string is now embedded in X86Info by default")
void FillX86BrandString(char brand_string[49]);
////////////////////////////////////////////////////////////////////////////////
@@ -213,6 +244,7 @@ typedef enum {
X86_RDRND,
X86_DCA,
X86_SS,
+ X86_ADX,
X86_LAST_,
} X86FeaturesEnum;
diff --git a/include/internal/hwcaps.h b/include/internal/hwcaps.h
index 62037c8..d7fc782 100644
--- a/include/internal/hwcaps.h
+++ b/include/internal/hwcaps.h
@@ -79,6 +79,7 @@ CPU_FEATURES_START_CPP_NAMESPACE
#define AARCH64_HWCAP2_DGH (1UL << 15)
#define AARCH64_HWCAP2_RNG (1UL << 16)
#define AARCH64_HWCAP2_BTI (1UL << 17)
+#define AARCH64_HWCAP2_MTE (1UL << 18)
// http://elixir.free-electrons.com/linux/latest/source/arch/arm/include/uapi/asm/hwcap.h
#define ARM_HWCAP_SWP (1UL << 0)
@@ -170,16 +171,19 @@ typedef struct {
unsigned long hwcaps2;
} HardwareCapabilities;
+// Retrieves values from auxiliary vector for types AT_HWCAP and AT_HWCAP2.
+// First tries to call getauxval(), if not available falls back to reading
+// "/proc/self/auxv".
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void);
+
+// Checks whether value for AT_HWCAP (or AT_HWCAP2) match hwcaps_mask.
bool CpuFeatures_IsHwCapsSet(const HardwareCapabilities hwcaps_mask,
const HardwareCapabilities hwcaps);
-typedef struct {
- char platform[64]; // 0 terminated string
- char base_platform[64]; // 0 terminated string
-} PlatformType;
-
-PlatformType CpuFeatures_GetPlatformType(void);
+// Get pointer for the AT_PLATFORM type.
+const char* CpuFeatures_GetPlatformPointer(void);
+// Get pointer for the AT_BASE_PLATFORM type.
+const char* CpuFeatures_GetBasePlatformPointer(void);
CPU_FEATURES_END_CPP_NAMESPACE
diff --git a/include/internal/string_view.h b/include/internal/string_view.h
index 64fed40..a109d45 100644
--- a/include/internal/string_view.h
+++ b/include/internal/string_view.h
@@ -96,7 +96,8 @@ void CpuFeatures_StringView_CopyString(const StringView src, char* dst,
// Checks if line contains the specified whitespace separated word.
bool CpuFeatures_StringView_HasWord(const StringView line,
- const char* const word);
+ const char* const word,
+ const char separator);
// Get key/value from line. key and value are separated by ": ".
// key and value are cleaned up from leading and trailing whitespaces.
diff --git a/ndk_compat/CMakeLists.txt b/ndk_compat/CMakeLists.txt
index 186708a..37b3866 100644
--- a/ndk_compat/CMakeLists.txt
+++ b/ndk_compat/CMakeLists.txt
@@ -54,7 +54,7 @@ install(
#
# program : NDK compat test program
#
-if(ENABLE_TESTING)
+if(BUILD_TESTING)
add_executable(ndk-compat-test ndk-compat-test.c)
target_link_libraries(ndk-compat-test PRIVATE ndk_compat)
endif()
diff --git a/scripts/make_release.sh b/scripts/make_release.sh
new file mode 100755
index 0000000..01e85f7
--- /dev/null
+++ b/scripts/make_release.sh
@@ -0,0 +1,72 @@
+#!/usr/bin/env bash
+
+set -e # Fail on error
+set -u # Treat unset variables as an error and exit immediately
+
+ACTION='\033[1;90m'
+FINISHED='\033[1;96m'
+NOCOLOR='\033[0m'
+ERROR='\033[0;31m'
+
+echo -e "${ACTION}Checking environnement${NOCOLOR}"
+if [[ ! $1 =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]
+then
+ echo -e "${ERROR}Invalid version number. Aborting. ${NOCOLOR}"
+ exit 1
+fi
+
+declare -r VERSION=$1
+declare -r GIT_TAG="v$1"
+
+BRANCH=$(git rev-parse --abbrev-ref HEAD)
+if [[ "${BRANCH}" != "main" ]]
+then
+ echo -e "${ERROR}Not on main. Aborting. ${NOCOLOR}"
+ echo
+ exit 1
+fi
+
+git fetch
+HEADHASH=$(git rev-parse HEAD)
+UPSTREAMHASH=$(git rev-parse main@{upstream})
+
+if [[ "${HEADHASH}" != "${UPSTREAMHASH}" ]]
+then
+ echo -e "${ERROR}Not up to date with origin. Aborting.${NOCOLOR}"
+ echo
+ exit 1
+fi
+
+git update-index -q --refresh
+if ! git diff-index --quiet HEAD --
+then
+ echo -e "${ERROR}Branch has uncommited changes. Aborting.${NOCOLOR}"
+ exit 1
+fi
+
+if [ ! -z "$(git ls-files --exclude-standard --others)" ]
+then
+ echo -e "${ERROR}Branch has untracked files. Aborting.${NOCOLOR}"
+ exit 1
+fi
+
+declare -r LATEST_GIT_TAG=$(git describe --tags --abbrev=0)
+declare -r LATEST_VERSION=${LATEST_GIT_TAG#"v"}
+
+if ! dpkg --compare-versions "${VERSION}" "gt" "${LATEST_VERSION}"
+then
+ echo -e "${ERROR}Invalid version ${VERSION} <= ${LATEST_VERSION} (latest). Aborting.${NOCOLOR}"
+ exit 1
+fi
+
+echo -e "${ACTION}Modifying CMakeLists.txt${NOCOLOR}"
+sed -i "s/CpuFeatures VERSION ${LATEST_VERSION}/CpuFeatures VERSION ${VERSION}/g" CMakeLists.txt
+
+echo -e "${ACTION}Commit new revision${NOCOLOR}"
+git add CMakeLists.txt
+git commit -m"Release ${GIT_TAG}"
+
+echo -e "${ACTION}Create new tag${NOCOLOR}"
+git tag ${GIT_TAG}
+
+echo -e "${FINISHED}Local release is ready. Run `git push origin --tags`${NOCOLOR}"
diff --git a/scripts/run_integration.sh b/scripts/run_integration.sh
index fd88d60..645cb6a 100755
--- a/scripts/run_integration.sh
+++ b/scripts/run_integration.sh
@@ -1,209 +1,363 @@
#!/usr/bin/env bash
-
-readonly SCRIPT_FOLDER=$(cd -P -- "$(dirname -- "$0")" && pwd -P)
-readonly PROJECT_FOLDER="${SCRIPT_FOLDER}/.."
-readonly ARCHIVE_FOLDER=~/cpu_features_archives
-readonly QEMU_INSTALL=${ARCHIVE_FOLDER}/qemu
-readonly DEFAULT_CMAKE_ARGS=" -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON"
+set -eo pipefail
function extract() {
+ echo "Extracting ${1}..."
case $1 in
*.tar.bz2) tar xjf "$1" ;;
*.tar.xz) tar xJf "$1" ;;
*.tar.gz) tar xzf "$1" ;;
*)
- echo "don't know how to extract '$1'..."
+ >&2 echo "don't know how to extract '$1'..."
exit 1
esac
}
-function unpackifnotexists() {
- mkdir -p "${ARCHIVE_FOLDER}"
- cd "${ARCHIVE_FOLDER}" || exit
- local URL=$1
- local RELATIVE_FOLDER=$2
- local DESTINATION="${ARCHIVE_FOLDER}/${RELATIVE_FOLDER}"
+function unpack() {
+ mkdir -p "${ARCHIVE_DIR}"
+ cd "${ARCHIVE_DIR}" || exit 2
+ local -r URL=$1
+ local -r RELATIVE_DIR=$2
+ local -r DESTINATION="${ARCHIVE_DIR}/${RELATIVE_DIR}"
if [[ ! -d "${DESTINATION}" ]] ; then
- local ARCHIVE_NAME=$(echo ${URL} | sed 's/.*\///')
- test -f "${ARCHIVE_NAME}" || wget -q "${URL}"
+ echo "Downloading ${URL}..."
+ local -r ARCHIVE_NAME=$(basename "${URL}")
+ test -f "${ARCHIVE_NAME}" || wget --no-verbose "${URL}"
extract "${ARCHIVE_NAME}"
rm -f "${ARCHIVE_NAME}"
fi
}
-function installqemuifneeded() {
- local VERSION=${QEMU_VERSION:=2.11.1}
- local ARCHES=${QEMU_ARCHES:=arm aarch64 i386 x86_64 mips mipsel mips64 mips64el}
- local TARGETS=${QEMU_TARGETS:=$(echo "$ARCHES" | sed 's#$# #;s#\([^ ]*\) #\1-linux-user #g')}
+function install_qemu() {
+ if [[ "${QEMU_ARCH}" == "DISABLED" ]]; then
+ >&2 echo 'QEMU is disabled !'
+ return 0
+ fi
+ local -r QEMU_VERSION=${QEMU_VERSION:=5.2.0}
+ local -r QEMU_TARGET=${QEMU_ARCH}-linux-user
- if echo "${VERSION} ${TARGETS}" | cmp --silent ${QEMU_INSTALL}/.build -; then
- echo "qemu ${VERSION} up to date!"
+ if echo "${QEMU_VERSION} ${QEMU_TARGET}" | cmp --silent "${QEMU_INSTALL}/.build" -; then
+ echo "qemu ${QEMU_VERSION} up to date!"
return 0
fi
- echo "VERSION: ${VERSION}"
- echo "TARGETS: ${TARGETS}"
+ echo "QEMU_VERSION: ${QEMU_VERSION}"
+ echo "QEMU_TARGET: ${QEMU_TARGET}"
- rm -rf ${QEMU_INSTALL}
+ rm -rf "${QEMU_INSTALL}"
# Checking for a tarball before downloading makes testing easier :-)
- local QEMU_URL="http://wiki.qemu-project.org/download/qemu-${VERSION}.tar.xz"
- local QEMU_FOLDER="qemu-${VERSION}"
- unpackifnotexists ${QEMU_URL} ${QEMU_FOLDER}
- cd ${QEMU_FOLDER} || exit
+ local -r QEMU_URL="http://wiki.qemu-project.org/download/qemu-${QEMU_VERSION}.tar.xz"
+ local -r QEMU_DIR="qemu-${QEMU_VERSION}"
+ unpack ${QEMU_URL} ${QEMU_DIR}
+ cd ${QEMU_DIR} || exit 2
+ # Qemu (meson based build) depends on: pkgconf, libglib2.0, python3, ninja
./configure \
--prefix="${QEMU_INSTALL}" \
- --target-list="${TARGETS}" \
+ --target-list="${QEMU_TARGET}" \
+ --audio-drv-list= \
+ --disable-brlapi \
+ --disable-curl \
+ --disable-curses \
--disable-docs \
- --disable-sdl \
- --disable-gtk \
- --disable-gnutls \
--disable-gcrypt \
+ --disable-gnutls \
+ --disable-gtk \
+ --disable-libnfs \
+ --disable-libssh \
--disable-nettle \
- --disable-curses \
- --static
+ --disable-opengl \
+ --disable-sdl \
+ --disable-virglrenderer \
+ --disable-vte \
+ --enable-modules
+
+ # --static Not supported on Archlinux
+ # so we use --enable-modules
- make -j4
+ # wrapper on ninja
+ make -j8
make install
- echo "$VERSION $TARGETS" > ${QEMU_INSTALL}/.build
+ echo "$QEMU_VERSION $QEMU_TARGET" > "${QEMU_INSTALL}/.build"
}
function assert_defined(){
- local VALUE=${1}
- : "${VALUE?"${1} needs to be defined"}"
+ if [[ -z "${!1}" ]]; then
+ >&2 echo "Variable '${1}' must be defined"
+ exit 1
+ fi
}
-function integrate() {
- cd "${PROJECT_FOLDER}"
- case "${OS}" in
- "Windows_NT") CMAKE_BUILD_ARGS="--config Debug --target ALL_BUILD"
- CMAKE_TEST_FILES="${BUILD_DIR}/test/Debug/*_test.exe"
- DEMO=${BUILD_DIR}/Debug/list_cpu_features.exe
- ;;
- *) CMAKE_BUILD_ARGS="--target all"
- CMAKE_TEST_FILES="${BUILD_DIR}/test/*_test"
- DEMO=${BUILD_DIR}/list_cpu_features
- ;;
- esac
-
- # Generating CMake configuration
- cmake -H. -B"${BUILD_DIR}" ${DEFAULT_CMAKE_ARGS} "${CMAKE_ADDITIONAL_ARGS[@]}" -G"${CMAKE_GENERATOR:-Unix Makefiles}"
-
- # Building
- cmake --build "${BUILD_DIR}" ${CMAKE_BUILD_ARGS}
-
- # Running tests if needed
- if [[ "${QEMU_ARCH}" == "DISABLED" ]]; then
- return
- fi
- RUN_CMD=""
- if [[ -n "${QEMU_ARCH}" ]]; then
- installqemuifneeded
- RUN_CMD="${QEMU_INSTALL}/bin/qemu-${QEMU_ARCH} ${QEMU_ARGS[@]}"
- fi
- for test_binary in ${CMAKE_TEST_FILES}; do
- ${RUN_CMD} ${test_binary}
- done
- ${RUN_CMD} ${DEMO}
+function clean_build() {
+ # Cleanup previous build
+ rm -rf "${BUILD_DIR}"
+ mkdir -p "${BUILD_DIR}"
}
function expand_linaro_config() {
- assert_defined TARGET
- local LINARO_ROOT_URL=https://releases.linaro.org/components/toolchain/binaries/7.2-2017.11
-
- local GCC_URL=${LINARO_ROOT_URL}/${TARGET}/gcc-linaro-7.2.1-2017.11-x86_64_${TARGET}.tar.xz
- local GCC_RELATIVE_FOLDER="gcc-linaro-7.2.1-2017.11-x86_64_${TARGET}"
- unpackifnotexists "${GCC_URL}" "${GCC_RELATIVE_FOLDER}"
-
- local SYSROOT_URL=${LINARO_ROOT_URL}/${TARGET}/sysroot-glibc-linaro-2.25-2017.11-${TARGET}.tar.xz
- local SYSROOT_RELATIVE_FOLDER=sysroot-glibc-linaro-2.25-2017.11-${TARGET}
- unpackifnotexists "${SYSROOT_URL}" "${SYSROOT_RELATIVE_FOLDER}"
-
- local SYSROOT_FOLDER=${ARCHIVE_FOLDER}/${SYSROOT_RELATIVE_FOLDER}
- local GCC_FOLDER=${ARCHIVE_FOLDER}/${GCC_RELATIVE_FOLDER}
-
- CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSTEM_NAME=Linux)
- CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSTEM_PROCESSOR=${TARGET})
-
- CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSROOT=${SYSROOT_FOLDER})
- CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_C_COMPILER=${GCC_FOLDER}/bin/${TARGET}-gcc)
- CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_CXX_COMPILER=${GCC_FOLDER}/bin/${TARGET}-g++)
-
- CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER)
- CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY)
- CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY)
-
- QEMU_ARGS+=(-L ${SYSROOT_FOLDER})
- QEMU_ARGS+=(-E LD_LIBRARY_PATH=/lib)
+ #ref: https://releases.linaro.org/components/toolchain/binaries/
+ local -r LINARO_VERSION=7.5-2019.12
+ local -r LINARO_ROOT_URL=https://releases.linaro.org/components/toolchain/binaries/${LINARO_VERSION}
+
+ local -r GCC_VERSION=7.5.0-2019.12
+ local -r GCC_URL=${LINARO_ROOT_URL}/${TARGET}/gcc-linaro-${GCC_VERSION}-x86_64_${TARGET}.tar.xz
+ local -r GCC_RELATIVE_DIR="gcc-linaro-${GCC_VERSION}-x86_64_${TARGET}"
+ unpack "${GCC_URL}" "${GCC_RELATIVE_DIR}"
+
+ local -r SYSROOT_VERSION=2.25-2019.12
+ local -r SYSROOT_URL=${LINARO_ROOT_URL}/${TARGET}/sysroot-glibc-linaro-${SYSROOT_VERSION}-${TARGET}.tar.xz
+ local -r SYSROOT_RELATIVE_DIR=sysroot-glibc-linaro-${SYSROOT_VERSION}-${TARGET}
+ unpack "${SYSROOT_URL}" "${SYSROOT_RELATIVE_DIR}"
+
+ local -r SYSROOT_DIR=${ARCHIVE_DIR}/${SYSROOT_RELATIVE_DIR}
+ local -r STAGING_DIR=${ARCHIVE_DIR}/${SYSROOT_RELATIVE_DIR}-stage
+ local -r GCC_DIR=${ARCHIVE_DIR}/${GCC_RELATIVE_DIR}
+
+ # Write a Toolchain file
+ # note: This is manadatory to use a file in order to have the CMake variable
+ # 'CMAKE_CROSSCOMPILING' set to TRUE.
+ # ref: https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-linux
+ cat >"$TOOLCHAIN_FILE" <<EOL
+set(CMAKE_SYSTEM_NAME Linux)
+set(CMAKE_SYSTEM_PROCESSOR ${TARGET})
+
+set(CMAKE_SYSROOT ${SYSROOT_DIR})
+set(CMAKE_STAGING_PREFIX ${STAGING_DIR})
+
+set(tools ${GCC_DIR})
+set(CMAKE_C_COMPILER \${tools}/bin/${TARGET}-gcc)
+set(CMAKE_CXX_COMPILER \${tools}/bin/${TARGET}-g++)
+
+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_LIBRARY_PATH=/lib )
}
function expand_codescape_config() {
- assert_defined TARGET
- local DATE=2017.10-08
- local CODESCAPE_URL=https://codescape.mips.com/components/toolchain/${DATE}/Codescape.GNU.Tools.Package.${DATE}.for.MIPS.MTI.Linux.CentOS-5.x86_64.tar.gz
- local GCC_URL=${CODESCAPE_URL}
- local GCC_RELATIVE_FOLDER="mips-mti-linux-gnu/${DATE}"
- unpackifnotexists "${GCC_URL}" "${GCC_RELATIVE_FOLDER}"
-
- local GCC_FOLDER=${ARCHIVE_FOLDER}/${GCC_RELATIVE_FOLDER}
+ # 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}"
+ #local -r GCC_RELATIVE_DIR="mips-img-linux-gnu/${DATE}"
+ unpack "${GCC_URL}" "${GCC_RELATIVE_DIR}"
+
+ local -r GCC_DIR=${ARCHIVE_DIR}/${GCC_RELATIVE_DIR}
local MIPS_FLAGS=""
- local LIBC_FOLDER_SUFFIX=""
+ local LIBC_DIR_SUFFIX=""
local FLAVOUR=""
case "${TARGET}" in
- "mips32") MIPS_FLAGS="-EB -mabi=32"; FLAVOUR="mips-r2-hard"; LIBC_FOLDER_SUFFIX="lib" ;;
- "mips32el") MIPS_FLAGS="-EL -mabi=32"; FLAVOUR="mipsel-r2-hard"; LIBC_FOLDER_SUFFIX="lib" ;;
- "mips64") MIPS_FLAGS="-EB -mabi=64"; FLAVOUR="mips-r2-hard"; LIBC_FOLDER_SUFFIX="lib64" ;;
- "mips64el") MIPS_FLAGS="-EL -mabi=64"; FLAVOUR="mipsel-r2-hard"; LIBC_FOLDER_SUFFIX="lib64" ;;
- *) echo 'unknown mips platform'; exit 1;;
+ "mips32")
+ MIPS_FLAGS="-EB -mips32r6 -mabi=32"
+ FLAVOUR="mips-r6-hard"
+ #MIPS_FLAGS="-EB -mips32r2 -mabi=32"
+ #FLAVOUR="mips-r2-hard"
+ LIBC_DIR_SUFFIX="lib"
+ ;;
+ "mips32el")
+ MIPS_FLAGS="-EL -mips32r6 -mabi=32"
+ FLAVOUR="mipsel-r6-hard"
+ #MIPS_FLAGS="-EL -mips32r2 -mabi=32"
+ #FLAVOUR="mipsel-r2-hard"
+ LIBC_DIR_SUFFIX="lib"
+ ;;
+ "mips64")
+ MIPS_FLAGS="-EB -mips64r6 -mabi=64"
+ FLAVOUR="mips-r6-hard"
+ #FLAVOUR="mips-r2-hard"
+ LIBC_DIR_SUFFIX="lib64"
+ ;;
+ "mips64el")
+ MIPS_FLAGS="-EL -mips64r6 -mabi=64"
+ FLAVOUR="mipsel-r6-hard"
+ #FLAVOUR="mipsel-r2-hard"
+ LIBC_DIR_SUFFIX="lib64"
+ ;;
+ *)
+ >&2 echo 'unknown mips platform'
+ exit 1 ;;
esac
+ local -r SYSROOT_DIR=${GCC_DIR}/sysroot
+ local -r STAGING_DIR=${SYSROOT_DIR}-stage
+
+ # Write a Toolchain file
+ # note: This is manadatory to use a file in order to have the CMake variable
+ # 'CMAKE_CROSSCOMPILING' set to TRUE.
+ # ref: https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-linux
+ cat >"${TOOLCHAIN_FILE}" <<EOL
+set(CMAKE_SYSTEM_NAME Linux)
+set(CMAKE_SYSTEM_PROCESSOR ${TARGET})
+
+set(CMAKE_SYSROOT ${SYSROOT_DIR})
+set(CMAKE_STAGING_PREFIX ${STAGING_DIR})
+
+set(tools ${GCC_DIR})
+
+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_COMPILER \${tools}/bin/mips-img-linux-gnu-g++)
+set(CMAKE_CXX_FLAGS "${MIPS_FLAGS}")
+
+set(CMAKE_FIND_ROOT_PATH ${GCC_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}/${FLAVOUR}" )
+local -r LIBC_DIR=${GCC_DIR}/mips-mti-linux-gnu/lib/${FLAVOUR}/${LIBC_DIR_SUFFIX}
+#local -r LIBC_DIR=${GCC_DIR}/mips-img-linux-gnu/lib/${FLAVOUR}/${LIBC_DIR_SUFFIX}
+QEMU_ARGS+=( -E LD_PRELOAD="${LIBC_DIR}/libstdc++.so.6:${LIBC_DIR}/libgcc_s.so.1" )
+}
+
+function build() {
+ cd "${PROJECT_DIR}" || exit 2
+ set -x
+ clean_build
+ cmake -S. -B"${BUILD_DIR}" "${CMAKE_DEFAULT_ARGS[@]}" "${CMAKE_ADDITIONAL_ARGS[@]}"
+ cmake --build "${BUILD_DIR}" --target all -j8 -v
+ set +x
+}
- CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_FIND_ROOT_PATH=${GCC_FOLDER})
- CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSTEM_NAME=Linux)
- CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSTEM_PROCESSOR=${TARGET})
- CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_C_COMPILER=mips-mti-linux-gnu-gcc)
- CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_CXX_COMPILER=mips-mti-linux-gnu-g++)
- CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_C_COMPILER_ARG1="${MIPS_FLAGS}")
- CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_CXX_COMPILER_ARG1="${MIPS_FLAGS}")
-
- local SYSROOT_FOLDER=${GCC_FOLDER}/sysroot/${FLAVOUR}
-
- # Keeping only the sysroot of interest to save on travis cache.
- if [[ "${CONTINUOUS_INTEGRATION}" = "true" ]]; then
- for folder in ${GCC_FOLDER}/sysroot/*; do
- if [[ "${folder}" != "${SYSROOT_FOLDER}" ]]; then
- rm -rf ${folder}
- fi
- done
+function run_test() {
+ assert_defined QEMU_ARCH
+ if [[ "${QEMU_ARCH}" == "DISABLED" ]]; then
+ >&2 echo "QEMU is disabled for ${TARGET}"
+ return
fi
+ install_qemu
+ RUN_CMD="${QEMU_INSTALL}/bin/qemu-${QEMU_ARCH} ${QEMU_ARGS[*]}"
- local LIBC_FOLDER=${GCC_FOLDER}/mips-mti-linux-gnu/lib/${FLAVOUR}/${LIBC_FOLDER_SUFFIX}
- QEMU_ARGS+=(-L ${SYSROOT_FOLDER})
- QEMU_ARGS+=(-E LD_PRELOAD=${LIBC_FOLDER}/libstdc++.so.6:${LIBC_FOLDER}/libgcc_s.so.1)
+ cd "${BUILD_DIR}" || exit 2
+ set -x
+ for test_binary in "${BUILD_DIR}"/list_cpu_feature* ; do
+ ${RUN_CMD} "${test_binary}"
+ done
+ set +x
+}
+
+function usage() {
+ local -r NAME=$(basename "$0")
+ echo -e "$NAME - Build using a cross toolchain.
+
+SYNOPSIS
+\t$NAME [-h|--help] [toolchain|build|qemu|test|all]
+
+DESCRIPTION
+\tCross compile using a cross toolchain.
+
+\tYou MUST define the following variables before running this script:
+\t* TARGET:
+\t\tx86_64
+\t\taarch64-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
+
+OPTIONS
+\t-h --help: show this help text
+\ttoolchain: download, unpack toolchain and generate CMake toolchain file
+\tbuild: toolchain + build the project using the toolchain file (note: remove previous build dir)
+\tqemu: download, unpack and build qemu
+\ttest: qemu + run all executable using qemu (note: don't build !)
+\tall: build + test (default)
+
+EXAMPLES
+* Using export:
+export TARGET=aarch64-linux-gnu
+$0
+
+* One-liner:
+TARGET=aarch64-linux-gnu $0"
}
-function expand_environment_and_integrate() {
- assert_defined PROJECT_FOLDER
+# Main
+function main() {
+ case ${1} in
+ -h | --help)
+ usage; exit ;;
+ esac
+
assert_defined TARGET
- BUILD_DIR="${PROJECT_FOLDER}/cmake_build/${TARGET}"
- mkdir -p "${BUILD_DIR}"
+ declare -r PROJECT_DIR="$(cd -P -- "$(dirname -- "$0")/.." && pwd -P)"
+ declare -r ARCHIVE_DIR="${PROJECT_DIR}/build_cross/archives"
+ declare -r BUILD_DIR="${PROJECT_DIR}/build_cross/${TARGET}"
+ declare -r TOOLCHAIN_FILE=${ARCHIVE_DIR}/toolchain_${TARGET}.cmake
- declare -a CONFIG_NAMES=()
- declare -a QEMU_ARGS=()
+ echo "Target: '${TARGET}'"
+
+ echo "Project dir: '${PROJECT_DIR}'"
+ echo "Archive dir: '${ARCHIVE_DIR}'"
+ echo "Build dir: '${BUILD_DIR}'"
+ echo "toolchain file: '${TOOLCHAIN_FILE}'"
+
+ declare -a CMAKE_DEFAULT_ARGS=( -G ${CMAKE_GENERATOR:-"Ninja"} )
declare -a CMAKE_ADDITIONAL_ARGS=()
- case ${TOOLCHAIN} in
- LINARO) expand_linaro_config ;;
- CODESCAPE) expand_codescape_config ;;
- NATIVE) QEMU_ARCH="" ;;
- *) echo "Unknown toolchain '${TOOLCHAIN}'..."; exit 1;;
+ declare -a QEMU_ARGS=()
+ case ${TARGET} in
+ x86_64)
+ declare -r QEMU_ARCH=x86_64 ;;
+ arm-linux-gnueabihf | armv8l-linux-gnueabihf | arm-linux-gnueabi)
+ expand_linaro_config
+ declare -r QEMU_ARCH=arm ;;
+ armeb-linux-gnueabihf | armeb-linux-gnueabi)
+ expand_linaro_config
+ declare -r QEMU_ARCH=DISABLED ;;
+ aarch64-linux-gnu)
+ expand_linaro_config
+ declare -r QEMU_ARCH=aarch64 ;;
+ aarch64_be-linux-gnu)
+ expand_linaro_config
+ declare -r QEMU_ARCH=DISABLED ;;
+ mips32)
+ expand_codescape_config
+ declare -r QEMU_ARCH=mips ;;
+ mips32el)
+ expand_codescape_config
+ declare -r QEMU_ARCH=mipsel ;;
+ mips64)
+ expand_codescape_config
+ declare -r QEMU_ARCH=mips64 ;;
+ mips64el)
+ expand_codescape_config
+ declare -r QEMU_ARCH=mips64el ;;
+ *)
+ >&2 echo "Unknown TARGET '${TARGET}'..."
+ exit 1 ;;
+ esac
+ declare -r QEMU_INSTALL=${ARCHIVE_DIR}/qemu-${QEMU_ARCH}
+
+ case ${1} in
+ toolchain)
+ exit ;;
+ build)
+ build ;;
+ qemu)
+ install_qemu ;;
+ test)
+ run_test ;;
+ *)
+ build
+ run_test ;;
esac
- integrate
}
-if [ "${CONTINUOUS_INTEGRATION}" = "true" ]; then
- QEMU_ARCHES=${QEMU_ARCH}
- expand_environment_and_integrate
-fi
+main "${1:-all}"
diff --git a/scripts/test_integration.sh b/scripts/test_integration.sh
index d1c61b0..0947e36 100755
--- a/scripts/test_integration.sh
+++ b/scripts/test_integration.sh
@@ -1,84 +1,58 @@
#!/usr/bin/env bash
-source "$(dirname -- "$0")"/run_integration.sh
-
# Toolchains for little-endian, 64-bit ARMv8 for GNU/Linux systems
function set_aarch64-linux-gnu() {
- TOOLCHAIN=LINARO
- TARGET=aarch64-linux-gnu
- QEMU_ARCH=aarch64
+ export TARGET=aarch64-linux-gnu
}
# Toolchains for little-endian, hard-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
function set_arm-linux-gnueabihf() {
- TOOLCHAIN=LINARO
- TARGET=arm-linux-gnueabihf
- QEMU_ARCH=arm
+ export TARGET=arm-linux-gnueabihf
}
# Toolchains for little-endian, 32-bit ARMv8 for GNU/Linux systems
function set_armv8l-linux-gnueabihf() {
- TOOLCHAIN=LINARO
- TARGET=armv8l-linux-gnueabihf
- QEMU_ARCH=arm
+ export TARGET=armv8l-linux-gnueabihf
}
# Toolchains for little-endian, soft-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
function set_arm-linux-gnueabi() {
- TOOLCHAIN=LINARO
- TARGET=arm-linux-gnueabi
- QEMU_ARCH=arm
+ export TARGET=arm-linux-gnueabi
}
# Toolchains for big-endian, 64-bit ARMv8 for GNU/Linux systems
function set_aarch64_be-linux-gnu() {
- TOOLCHAIN=LINARO
- TARGET=aarch64_be-linux-gnu
- QEMU_ARCH=DISABLED
+ export TARGET=aarch64_be-linux-gnu
}
# Toolchains for big-endian, hard-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
function set_armeb-linux-gnueabihf() {
- TOOLCHAIN=LINARO
- TARGET=armeb-linux-gnueabihf
- QEMU_ARCH=DISABLED
+ export TARGET=armeb-linux-gnueabihf
}
# Toolchains for big-endian, soft-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
function set_armeb-linux-gnueabi() {
- TOOLCHAIN=LINARO
- TARGET=armeb-linux-gnueabi
- QEMU_ARCH=DISABLED
+ export TARGET=armeb-linux-gnueabi
}
function set_mips32() {
- TOOLCHAIN=CODESCAPE
- TARGET=mips32
- QEMU_ARCH=mips
+ export TARGET=mips32
}
function set_mips32el() {
- TOOLCHAIN=CODESCAPE
- TARGET=mips32el
- QEMU_ARCH=mipsel
+ export TARGET=mips32el
}
function set_mips64() {
- TOOLCHAIN=CODESCAPE
- TARGET=mips64
- QEMU_ARCH=mips64
+ export TARGET=mips64
}
function set_mips64el() {
- TOOLCHAIN=CODESCAPE
- TARGET=mips64el
- QEMU_ARCH=mips64el
+ export TARGET=mips64el
}
-function set_native() {
- TOOLCHAIN=NATIVE
- TARGET=native
- QEMU_ARCH=""
+function set_x86_64() {
+ export TARGET=x86_64
}
ENVIRONMENTS="
@@ -93,14 +67,13 @@ ENVIRONMENTS="
set_mips32el
set_mips64
set_mips64el
- set_native
+ set_x86_64
"
set -e
-CMAKE_GENERATOR="Ninja"
-
for SET_ENVIRONMENT in ${ENVIRONMENTS}; do
+ echo "testing ${SET_ENVIRONMENT}"
${SET_ENVIRONMENT}
- expand_environment_and_integrate
+ ./"$(dirname -- "$0")"/run_integration.sh
done
diff --git a/src/copy.inl b/src/copy.inl
new file mode 100644
index 0000000..47771d4
--- /dev/null
+++ b/src/copy.inl
@@ -0,0 +1,19 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <stddef.h>
+
+static void copy(char *__restrict dst, const char *src, size_t count) {
+ for (size_t i = 0; i < count; ++i) dst[i] = src[i];
+}
diff --git a/src/cpuinfo_aarch64.c b/src/cpuinfo_aarch64.c
deleted file mode 100644
index 0a52718..0000000
--- a/src/cpuinfo_aarch64.c
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright 2017 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "cpuinfo_aarch64.h"
-
-#include <assert.h>
-#include <ctype.h>
-
-#include "internal/filesystem.h"
-#include "internal/hwcaps.h"
-#include "internal/stack_line_reader.h"
-#include "internal/string_view.h"
-
-// Generation of feature's getters/setters functions and kGetters, kSetters,
-// kCpuInfoFlags and kHardwareCapabilities global tables.
-#define DEFINE_TABLE_FEATURES \
- FEATURE(AARCH64_FP, fp, "fp", AARCH64_HWCAP_FP, 0) \
- FEATURE(AARCH64_ASIMD, asimd, "asimd", AARCH64_HWCAP_ASIMD, 0) \
- FEATURE(AARCH64_EVTSTRM, evtstrm, "evtstrm", AARCH64_HWCAP_EVTSTRM, 0) \
- FEATURE(AARCH64_AES, aes, "aes", AARCH64_HWCAP_AES, 0) \
- FEATURE(AARCH64_PMULL, pmull, "pmull", AARCH64_HWCAP_PMULL, 0) \
- FEATURE(AARCH64_SHA1, sha1, "sha1", AARCH64_HWCAP_SHA1, 0) \
- FEATURE(AARCH64_SHA2, sha2, "sha2", AARCH64_HWCAP_SHA2, 0) \
- FEATURE(AARCH64_CRC32, crc32, "crc32", AARCH64_HWCAP_CRC32, 0) \
- FEATURE(AARCH64_ATOMICS, atomics, "atomics", AARCH64_HWCAP_ATOMICS, 0) \
- FEATURE(AARCH64_FPHP, fphp, "fphp", AARCH64_HWCAP_FPHP, 0) \
- FEATURE(AARCH64_ASIMDHP, asimdhp, "asimdhp", AARCH64_HWCAP_ASIMDHP, 0) \
- FEATURE(AARCH64_CPUID, cpuid, "cpuid", AARCH64_HWCAP_CPUID, 0) \
- FEATURE(AARCH64_ASIMDRDM, asimdrdm, "asimdrdm", AARCH64_HWCAP_ASIMDRDM, 0) \
- FEATURE(AARCH64_JSCVT, jscvt, "jscvt", AARCH64_HWCAP_JSCVT, 0) \
- FEATURE(AARCH64_FCMA, fcma, "fcma", AARCH64_HWCAP_FCMA, 0) \
- FEATURE(AARCH64_LRCPC, lrcpc, "lrcpc", AARCH64_HWCAP_LRCPC, 0) \
- FEATURE(AARCH64_DCPOP, dcpop, "dcpop", AARCH64_HWCAP_DCPOP, 0) \
- FEATURE(AARCH64_SHA3, sha3, "sha3", AARCH64_HWCAP_SHA3, 0) \
- FEATURE(AARCH64_SM3, sm3, "sm3", AARCH64_HWCAP_SM3, 0) \
- FEATURE(AARCH64_SM4, sm4, "sm4", AARCH64_HWCAP_SM4, 0) \
- FEATURE(AARCH64_ASIMDDP, asimddp, "asimddp", AARCH64_HWCAP_ASIMDDP, 0) \
- FEATURE(AARCH64_SHA512, sha512, "sha512", AARCH64_HWCAP_SHA512, 0) \
- FEATURE(AARCH64_SVE, sve, "sve", AARCH64_HWCAP_SVE, 0) \
- FEATURE(AARCH64_ASIMDFHM, asimdfhm, "asimdfhm", AARCH64_HWCAP_ASIMDFHM, 0) \
- FEATURE(AARCH64_DIT, dit, "dit", AARCH64_HWCAP_DIT, 0) \
- FEATURE(AARCH64_USCAT, uscat, "uscat", AARCH64_HWCAP_USCAT, 0) \
- FEATURE(AARCH64_ILRCPC, ilrcpc, "ilrcpc", AARCH64_HWCAP_ILRCPC, 0) \
- FEATURE(AARCH64_FLAGM, flagm, "flagm", AARCH64_HWCAP_FLAGM, 0) \
- FEATURE(AARCH64_SSBS, ssbs, "ssbs", AARCH64_HWCAP_SSBS, 0) \
- FEATURE(AARCH64_SB, sb, "sb", AARCH64_HWCAP_SB, 0) \
- FEATURE(AARCH64_PACA, paca, "paca", AARCH64_HWCAP_PACA, 0) \
- FEATURE(AARCH64_PACG, pacg, "pacg", AARCH64_HWCAP_PACG, 0) \
- FEATURE(AARCH64_DCPODP, dcpodp, "dcpodp", 0, AARCH64_HWCAP2_DCPODP) \
- FEATURE(AARCH64_SVE2, sve2, "sve2", 0, AARCH64_HWCAP2_SVE2) \
- FEATURE(AARCH64_SVEAES, sveaes, "sveaes", 0, AARCH64_HWCAP2_SVEAES) \
- FEATURE(AARCH64_SVEPMULL, svepmull, "svepmull", 0, AARCH64_HWCAP2_SVEPMULL) \
- FEATURE(AARCH64_SVEBITPERM, svebitperm, "svebitperm", 0, \
- AARCH64_HWCAP2_SVEBITPERM) \
- FEATURE(AARCH64_SVESHA3, svesha3, "svesha3", 0, AARCH64_HWCAP2_SVESHA3) \
- FEATURE(AARCH64_SVESM4, svesm4, "svesm4", 0, AARCH64_HWCAP2_SVESM4) \
- FEATURE(AARCH64_FLAGM2, flagm2, "flagm2", 0, AARCH64_HWCAP2_FLAGM2) \
- FEATURE(AARCH64_FRINT, frint, "frint", 0, AARCH64_HWCAP2_FRINT) \
- FEATURE(AARCH64_SVEI8MM, svei8mm, "svei8mm", 0, AARCH64_HWCAP2_SVEI8MM) \
- FEATURE(AARCH64_SVEF32MM, svef32mm, "svef32mm", 0, AARCH64_HWCAP2_SVEF32MM) \
- FEATURE(AARCH64_SVEF64MM, svef64mm, "svef64mm", 0, AARCH64_HWCAP2_SVEF64MM) \
- FEATURE(AARCH64_SVEBF16, svebf16, "svebf16", 0, AARCH64_HWCAP2_SVEBF16) \
- FEATURE(AARCH64_I8MM, i8mm, "i8mm", 0, AARCH64_HWCAP2_I8MM) \
- FEATURE(AARCH64_BF16, bf16, "bf16", 0, AARCH64_HWCAP2_BF16) \
- FEATURE(AARCH64_DGH, dgh, "dgh", 0, AARCH64_HWCAP2_DGH) \
- FEATURE(AARCH64_RNG, rng, "rng", 0, AARCH64_HWCAP2_RNG) \
- FEATURE(AARCH64_BTI, bti, "bti", 0, AARCH64_HWCAP2_BTI)
-#define DEFINE_TABLE_FEATURE_TYPE Aarch64Features
-#include "define_tables.h"
-
-static bool HandleAarch64Line(const LineResult result,
- Aarch64Info* const info) {
- StringView line = result.line;
- StringView key, value;
- if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
- if (CpuFeatures_StringView_IsEquals(key, str("Features"))) {
- for (size_t i = 0; i < AARCH64_LAST_; ++i) {
- kSetters[i](&info->features,
- CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i]));
- }
- } else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) {
- info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value);
- } else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) {
- info->variant = CpuFeatures_StringView_ParsePositiveNumber(value);
- } else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) {
- info->part = CpuFeatures_StringView_ParsePositiveNumber(value);
- } else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) {
- info->revision = CpuFeatures_StringView_ParsePositiveNumber(value);
- }
- }
- return !result.eof;
-}
-
-static void FillProcCpuInfoData(Aarch64Info* const info) {
- const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
- if (fd >= 0) {
- StackLineReader reader;
- StackLineReader_Initialize(&reader, fd);
- for (;;) {
- if (!HandleAarch64Line(StackLineReader_NextLine(&reader), info)) {
- break;
- }
- }
- CpuFeatures_CloseFile(fd);
- }
-}
-
-static const Aarch64Info kEmptyAarch64Info;
-
-Aarch64Info GetAarch64Info(void) {
- // capabilities are fetched from both getauxval and /proc/cpuinfo so we can
- // have some information if the executable is sandboxed (aka no access to
- // /proc/cpuinfo).
- Aarch64Info info = kEmptyAarch64Info;
-
- FillProcCpuInfoData(&info);
- const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
- for (size_t i = 0; i < AARCH64_LAST_; ++i) {
- if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
- kSetters[i](&info.features, true);
- }
- }
-
- return info;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Introspection functions
-
-int GetAarch64FeaturesEnumValue(const Aarch64Features* features,
- Aarch64FeaturesEnum value) {
- if (value >= AARCH64_LAST_) return false;
- return kGetters[value](features);
-}
-
-const char* GetAarch64FeaturesEnumName(Aarch64FeaturesEnum value) {
- if (value >= AARCH64_LAST_) return "unknown feature";
- return kCpuInfoFlags[value];
-}
diff --git a/src/cpuinfo_ppc.c b/src/cpuinfo_ppc.c
deleted file mode 100644
index 24401f9..0000000
--- a/src/cpuinfo_ppc.c
+++ /dev/null
@@ -1,154 +0,0 @@
-// Copyright 2018 IBM.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "cpuinfo_ppc.h"
-
-#include <assert.h>
-#include <stdbool.h>
-#include <string.h>
-
-#include "internal/bit_utils.h"
-#include "internal/filesystem.h"
-#include "internal/stack_line_reader.h"
-#include "internal/string_view.h"
-
-// Generation of feature's getters/setters functions and kGetters, kSetters,
-// kCpuInfoFlags and kHardwareCapabilities global tables.
-#define DEFINE_TABLE_FEATURES \
- FEATURE(PPC_32, ppc32, "ppc32", PPC_FEATURE_32, 0) \
- FEATURE(PPC_64, ppc64, "ppc64", PPC_FEATURE_64, 0) \
- FEATURE(PPC_601_INSTR, ppc601, "ppc601", PPC_FEATURE_601_INSTR, 0) \
- FEATURE(PPC_HAS_ALTIVEC, altivec, "altivec", PPC_FEATURE_HAS_ALTIVEC, 0) \
- FEATURE(PPC_HAS_FPU, fpu, "fpu", PPC_FEATURE_HAS_FPU, 0) \
- FEATURE(PPC_HAS_MMU, mmu, "mmu", PPC_FEATURE_HAS_MMU, 0) \
- FEATURE(PPC_HAS_4xxMAC, mac_4xx, "4xxmac", PPC_FEATURE_HAS_4xxMAC, 0) \
- FEATURE(PPC_UNIFIED_CACHE, unifiedcache, "ucache", \
- PPC_FEATURE_UNIFIED_CACHE, 0) \
- FEATURE(PPC_HAS_SPE, spe, "spe", PPC_FEATURE_HAS_SPE, 0) \
- FEATURE(PPC_HAS_EFP_SINGLE, efpsingle, "efpsingle", \
- PPC_FEATURE_HAS_EFP_SINGLE, 0) \
- FEATURE(PPC_HAS_EFP_DOUBLE, efpdouble, "efpdouble", \
- PPC_FEATURE_HAS_EFP_DOUBLE, 0) \
- FEATURE(PPC_NO_TB, no_tb, "notb", PPC_FEATURE_NO_TB, 0) \
- FEATURE(PPC_POWER4, power4, "power4", PPC_FEATURE_POWER4, 0) \
- FEATURE(PPC_POWER5, power5, "power5", PPC_FEATURE_POWER5, 0) \
- FEATURE(PPC_POWER5_PLUS, power5plus, "power5+", PPC_FEATURE_POWER5_PLUS, 0) \
- FEATURE(PPC_CELL, cell, "cellbe", PPC_FEATURE_CELL, 0) \
- FEATURE(PPC_BOOKE, booke, "booke", PPC_FEATURE_BOOKE, 0) \
- FEATURE(PPC_SMT, smt, "smt", PPC_FEATURE_SMT, 0) \
- FEATURE(PPC_ICACHE_SNOOP, icachesnoop, "ic_snoop", PPC_FEATURE_ICACHE_SNOOP, \
- 0) \
- FEATURE(PPC_ARCH_2_05, arch205, "arch_2_05", PPC_FEATURE_ARCH_2_05, 0) \
- FEATURE(PPC_PA6T, pa6t, "pa6t", PPC_FEATURE_PA6T, 0) \
- FEATURE(PPC_HAS_DFP, dfp, "dfp", PPC_FEATURE_HAS_DFP, 0) \
- FEATURE(PPC_POWER6_EXT, power6ext, "power6x", PPC_FEATURE_POWER6_EXT, 0) \
- FEATURE(PPC_ARCH_2_06, arch206, "arch_2_06", PPC_FEATURE_ARCH_2_06, 0) \
- FEATURE(PPC_HAS_VSX, vsx, "vsx", PPC_FEATURE_HAS_VSX, 0) \
- FEATURE(PPC_PSERIES_PERFMON_COMPAT, pseries_perfmon_compat, "archpmu", \
- PPC_FEATURE_PSERIES_PERFMON_COMPAT, 0) \
- FEATURE(PPC_TRUE_LE, truele, "true_le", PPC_FEATURE_TRUE_LE, 0) \
- FEATURE(PPC_PPC_LE, ppcle, "ppcle", PPC_FEATURE_PPC_LE, 0) \
- FEATURE(PPC_ARCH_2_07, arch207, "arch_2_07", 0, PPC_FEATURE2_ARCH_2_07) \
- FEATURE(PPC_HTM, htm, "htm", 0, PPC_FEATURE2_HTM) \
- FEATURE(PPC_DSCR, dscr, "dscr", 0, PPC_FEATURE2_DSCR) \
- FEATURE(PPC_EBB, ebb, "ebb", 0, PPC_FEATURE2_EBB) \
- FEATURE(PPC_ISEL, isel, "isel", 0, PPC_FEATURE2_ISEL) \
- FEATURE(PPC_TAR, tar, "tar", 0, PPC_FEATURE2_TAR) \
- FEATURE(PPC_VEC_CRYPTO, vcrypto, "vcrypto", 0, PPC_FEATURE2_VEC_CRYPTO) \
- FEATURE(PPC_HTM_NOSC, htm_nosc, "htm-nosc", 0, PPC_FEATURE2_HTM_NOSC) \
- FEATURE(PPC_ARCH_3_00, arch300, "arch_3_00", 0, PPC_FEATURE2_ARCH_3_00) \
- FEATURE(PPC_HAS_IEEE128, ieee128, "ieee128", 0, PPC_FEATURE2_HAS_IEEE128) \
- FEATURE(PPC_DARN, darn, "darn", 0, PPC_FEATURE2_DARN) \
- FEATURE(PPC_SCV, scv, "scv", 0, PPC_FEATURE2_SCV) \
- FEATURE(PPC_HTM_NO_SUSPEND, htm_no_suspend, "htm-no-suspend", 0, \
- PPC_FEATURE2_HTM_NO_SUSPEND)
-#define DEFINE_TABLE_FEATURE_TYPE PPCFeatures
-#include "define_tables.h"
-
-static bool HandlePPCLine(const LineResult result,
- PPCPlatformStrings* const strings) {
- StringView line = result.line;
- StringView key, value;
- if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
- if (CpuFeatures_StringView_HasWord(key, "platform")) {
- CpuFeatures_StringView_CopyString(value, strings->platform,
- sizeof(strings->platform));
- } else if (CpuFeatures_StringView_IsEquals(key, str("model"))) {
- CpuFeatures_StringView_CopyString(value, strings->model,
- sizeof(strings->platform));
- } else if (CpuFeatures_StringView_IsEquals(key, str("machine"))) {
- CpuFeatures_StringView_CopyString(value, strings->machine,
- sizeof(strings->platform));
- } else if (CpuFeatures_StringView_IsEquals(key, str("cpu"))) {
- CpuFeatures_StringView_CopyString(value, strings->cpu,
- sizeof(strings->platform));
- }
- }
- return !result.eof;
-}
-
-static void FillProcCpuInfoData(PPCPlatformStrings* const strings) {
- const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
- if (fd >= 0) {
- StackLineReader reader;
- StackLineReader_Initialize(&reader, fd);
- for (;;) {
- if (!HandlePPCLine(StackLineReader_NextLine(&reader), strings)) {
- break;
- }
- }
- CpuFeatures_CloseFile(fd);
- }
-}
-
-static const PPCInfo kEmptyPPCInfo;
-
-PPCInfo GetPPCInfo(void) {
- /*
- * On Power feature flags aren't currently in cpuinfo so we only look at
- * the auxilary vector.
- */
- PPCInfo info = kEmptyPPCInfo;
- const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
- for (size_t i = 0; i < PPC_LAST_; ++i) {
- if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
- kSetters[i](&info.features, true);
- }
- }
- return info;
-}
-
-static const PPCPlatformStrings kEmptyPPCPlatformStrings;
-
-PPCPlatformStrings GetPPCPlatformStrings(void) {
- PPCPlatformStrings strings = kEmptyPPCPlatformStrings;
-
- FillProcCpuInfoData(&strings);
- strings.type = CpuFeatures_GetPlatformType();
- return strings;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Introspection functions
-
-int GetPPCFeaturesEnumValue(const PPCFeatures* features,
- PPCFeaturesEnum value) {
- if (value >= PPC_LAST_) return false;
- return kGetters[value](features);
-}
-
-const char* GetPPCFeaturesEnumName(PPCFeaturesEnum value) {
- if (value >= PPC_LAST_) return "unknown feature";
- return kCpuInfoFlags[value];
-}
diff --git a/src/define_introspection.inl b/src/define_introspection.inl
new file mode 100644
index 0000000..c0eb916
--- /dev/null
+++ b/src/define_introspection.inl
@@ -0,0 +1,86 @@
+// Copyright 2017 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef INTROSPECTION_PREFIX
+#error "missing INTROSPECTION_PREFIX"
+#endif
+#ifndef INTROSPECTION_ENUM_PREFIX
+#error "missing INTROSPECTION_ENUM_PREFIX"
+#endif
+#ifndef INTROSPECTION_TABLE
+#error "missing INTROSPECTION_TABLE"
+#endif
+
+#include <stdbool.h>
+
+#define STRINGIZE_(s) #s
+#define STRINGIZE(s) STRINGIZE_(s)
+
+#define FEAT_TYPE_NAME__(X) X##Features
+#define FEAT_TYPE_NAME_(X) FEAT_TYPE_NAME__(X)
+#define FEAT_TYPE_NAME FEAT_TYPE_NAME_(INTROSPECTION_PREFIX)
+
+#define FEAT_ENUM_NAME__(X) X##FeaturesEnum
+#define FEAT_ENUM_NAME_(X) FEAT_ENUM_NAME__(X)
+#define FEAT_ENUM_NAME FEAT_ENUM_NAME_(INTROSPECTION_PREFIX)
+
+#define GET_FEAT_ENUM_VALUE__(X) Get##X##FeaturesEnumValue
+#define GET_FEAT_ENUM_VALUE_(X) GET_FEAT_ENUM_VALUE__(X)
+#define GET_FEAT_ENUM_VALUE GET_FEAT_ENUM_VALUE_(INTROSPECTION_PREFIX)
+
+#define GET_FEAT_ENUM_NAME__(X) Get##X##FeaturesEnumName
+#define GET_FEAT_ENUM_NAME_(X) GET_FEAT_ENUM_NAME__(X)
+#define GET_FEAT_ENUM_NAME GET_FEAT_ENUM_NAME_(INTROSPECTION_PREFIX)
+
+#define FEAT_ENUM_LAST__(X) X##_LAST_
+#define FEAT_ENUM_LAST_(X) FEAT_ENUM_LAST__(X)
+#define FEAT_ENUM_LAST FEAT_ENUM_LAST_(INTROSPECTION_ENUM_PREFIX)
+
+// Generate individual getters and setters.
+#define LINE(ENUM, NAME, A, B, C) \
+ static void set_##ENUM(FEAT_TYPE_NAME* features, bool value) { \
+ features->NAME = value; \
+ } \
+ static int get_##ENUM(const FEAT_TYPE_NAME* features) { \
+ return features->NAME; \
+ }
+INTROSPECTION_TABLE
+#undef LINE
+
+// Generate getters table
+#define LINE(ENUM, NAME, A, B, C) [ENUM] = get_##ENUM,
+static int (*const kGetters[])(const FEAT_TYPE_NAME*) = {INTROSPECTION_TABLE};
+#undef LINE
+
+// Generate setters table
+#define LINE(ENUM, NAME, A, B, C) [ENUM] = set_##ENUM,
+static void (*const kSetters[])(FEAT_TYPE_NAME*, bool) = {INTROSPECTION_TABLE};
+#undef LINE
+
+// Implements the `GetXXXFeaturesEnumValue` API.
+int GET_FEAT_ENUM_VALUE(const FEAT_TYPE_NAME* features, FEAT_ENUM_NAME value) {
+ if (value >= FEAT_ENUM_LAST) return false;
+ return kGetters[value](features);
+}
+
+// Generate feature name table.
+#define LINE(ENUM, NAME, A, B, C) [ENUM] = STRINGIZE(NAME),
+static const char* kFeatureNames[] = {INTROSPECTION_TABLE};
+#undef LINE
+
+// Implements the `GetXXXFeaturesEnumName` API.
+const char* GET_FEAT_ENUM_NAME(FEAT_ENUM_NAME value) {
+ if (value >= FEAT_ENUM_LAST) return "unknown_feature";
+ return kFeatureNames[value];
+}
diff --git a/src/define_introspection_and_hwcaps.inl b/src/define_introspection_and_hwcaps.inl
new file mode 100644
index 0000000..c31b60d
--- /dev/null
+++ b/src/define_introspection_and_hwcaps.inl
@@ -0,0 +1,26 @@
+// Copyright 2017 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "define_introspection.inl"
+#include "internal/hwcaps.h"
+
+#define LINE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) \
+ [ENUM] = (HardwareCapabilities){HWCAP, HWCAP2},
+static const HardwareCapabilities kHardwareCapabilities[] = {
+ INTROSPECTION_TABLE};
+#undef LINE
+
+#define LINE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) [ENUM] = CPUINFO_FLAG,
+static const char* kCpuInfoFlags[] = {INTROSPECTION_TABLE};
+#undef LINE
diff --git a/src/define_tables.h b/src/define_tables.h
deleted file mode 100644
index dc1485c..0000000
--- a/src/define_tables.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// The following preprocessor constants must be defined before including this
-// file:
-// - DEFINE_TABLE_FEATURE_TYPE, the underlying type (e.g. X86Features)
-// - DEFINE_TABLE_FEATURES, the list of FEATURE macros to be inserted.
-
-// This file is to be included once per `cpuinfo_XXX.c` in order to construct
-// feature getters and setters functions as well as several enum indexed tables
-// from the db file.
-// - `kGetters` a table of getters function pointers from feature enum to
-// retrieve a feature,
-// - `kSetters` a table of setters function pointers from feature enum to set a
-// feature,
-// - `kCpuInfoFlags` a table of strings from feature enum to /proc/cpuinfo
-// flags,
-// - `kHardwareCapabilities` a table of HardwareCapabilities structs indexed by
-// their feature enum.
-
-#ifndef SRC_DEFINE_TABLES_H_
-#define SRC_DEFINE_TABLES_H_
-
-#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) [ENUM] = CPUINFO_FLAG,
-static const char* kCpuInfoFlags[] = {DEFINE_TABLE_FEATURES};
-#undef FEATURE
-
-#ifndef DEFINE_TABLE_DONT_GENERATE_HWCAPS
-#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) \
- [ENUM] = (HardwareCapabilities){HWCAP, HWCAP2},
-static const HardwareCapabilities kHardwareCapabilities[] = {
- DEFINE_TABLE_FEATURES};
-#undef FEATURE
-#endif // DEFINE_TABLE_DONT_GENERATE_HWCAPS
-
-#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) \
- static void set_##ENUM(DEFINE_TABLE_FEATURE_TYPE* features, bool value) { \
- features->NAME = value; \
- } \
- static int get_##ENUM(const DEFINE_TABLE_FEATURE_TYPE* features) { \
- return features->NAME; \
- }
-DEFINE_TABLE_FEATURES
-#undef FEATURE
-
-#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) [ENUM] = set_##ENUM,
-static void (*const kSetters[])(DEFINE_TABLE_FEATURE_TYPE*,
- bool) = {DEFINE_TABLE_FEATURES};
-#undef FEATURE
-
-#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) [ENUM] = get_##ENUM,
-static int (*const kGetters[])(const DEFINE_TABLE_FEATURE_TYPE*) = {
- DEFINE_TABLE_FEATURES};
-#undef FEATURE
-
-#endif // SRC_DEFINE_TABLES_H_
diff --git a/src/equals.inl b/src/equals.inl
new file mode 100644
index 0000000..67a115f
--- /dev/null
+++ b/src/equals.inl
@@ -0,0 +1,22 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <stdbool.h>
+#include <stddef.h>
+
+static bool equals(const char *lhs, const char *rhs, size_t count) {
+ for (size_t i = 0; i < count; ++i)
+ if (lhs[i] != rhs[i]) return false;
+ return true;
+}
diff --git a/src/hwcaps.c b/src/hwcaps.c
index dd17e3b..f44f6c3 100644
--- a/src/hwcaps.c
+++ b/src/hwcaps.c
@@ -35,7 +35,8 @@ bool CpuFeatures_IsHwCapsSet(const HardwareCapabilities hwcaps_mask,
#ifdef CPU_FEATURES_TEST
// In test mode, hwcaps_for_testing will define the following functions.
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void);
-PlatformType CpuFeatures_GetPlatformType(void);
+const char* CpuFeatures_GetPlatformPointer(void);
+const char* CpuFeatures_GetBasePlatformPointer(void);
#else
// Debug facilities
@@ -67,13 +68,7 @@ static unsigned long GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
#elif defined(HAVE_DLFCN_H)
// On Android we probe the system's C library for a 'getauxval' function and
// call it if it exits, or return 0 for failure. This function is available
-// since API level 20.
-//
-// This code does *NOT* check for '__ANDROID_API__ >= 20' to support the edge
-// case where some NDK developers use headers for a platform that is newer than
-// the one really targetted by their application. This is typically done to use
-// newer native APIs only when running on more recent Android versions, and
-// requires careful symbol management.
+// since API level 18.
//
// Note that getauxval() can't really be re-implemented here, because its
// implementation does not parse /proc/self/auxv. Instead it depends on values
@@ -163,20 +158,12 @@ HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void) {
return capabilities;
}
-PlatformType kEmptyPlatformType;
-
-PlatformType CpuFeatures_GetPlatformType(void) {
- PlatformType type = kEmptyPlatformType;
- char *platform = (char *)GetHardwareCapabilitiesFor(AT_PLATFORM);
- char *base_platform = (char *)GetHardwareCapabilitiesFor(AT_BASE_PLATFORM);
+const char *CpuFeatures_GetPlatformPointer(void) {
+ return (const char *)GetHardwareCapabilitiesFor(AT_PLATFORM);
+}
- if (platform != NULL)
- CpuFeatures_StringView_CopyString(str(platform), type.platform,
- sizeof(type.platform));
- if (base_platform != NULL)
- CpuFeatures_StringView_CopyString(str(base_platform), type.base_platform,
- sizeof(type.base_platform));
- return type;
+const char *CpuFeatures_GetBasePlatformPointer(void) {
+ return (const char *)GetHardwareCapabilitiesFor(AT_BASE_PLATFORM);
}
#endif // CPU_FEATURES_TEST
diff --git a/src/impl_aarch64_linux_or_android.c b/src/impl_aarch64_linux_or_android.c
new file mode 100644
index 0000000..745beb9
--- /dev/null
+++ b/src/impl_aarch64_linux_or_android.c
@@ -0,0 +1,150 @@
+// Copyright 2017 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cpu_features_macros.h"
+
+#ifdef CPU_FEATURES_ARCH_AARCH64
+#if defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
+
+#include "cpuinfo_aarch64.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// Definitions for introspection.
+////////////////////////////////////////////////////////////////////////////////
+#define INTROSPECTION_TABLE \
+ LINE(AARCH64_FP, fp, "fp", AARCH64_HWCAP_FP, 0) \
+ LINE(AARCH64_ASIMD, asimd, "asimd", AARCH64_HWCAP_ASIMD, 0) \
+ LINE(AARCH64_EVTSTRM, evtstrm, "evtstrm", AARCH64_HWCAP_EVTSTRM, 0) \
+ LINE(AARCH64_AES, aes, "aes", AARCH64_HWCAP_AES, 0) \
+ LINE(AARCH64_PMULL, pmull, "pmull", AARCH64_HWCAP_PMULL, 0) \
+ LINE(AARCH64_SHA1, sha1, "sha1", AARCH64_HWCAP_SHA1, 0) \
+ LINE(AARCH64_SHA2, sha2, "sha2", AARCH64_HWCAP_SHA2, 0) \
+ LINE(AARCH64_CRC32, crc32, "crc32", AARCH64_HWCAP_CRC32, 0) \
+ LINE(AARCH64_ATOMICS, atomics, "atomics", AARCH64_HWCAP_ATOMICS, 0) \
+ LINE(AARCH64_FPHP, fphp, "fphp", AARCH64_HWCAP_FPHP, 0) \
+ LINE(AARCH64_ASIMDHP, asimdhp, "asimdhp", AARCH64_HWCAP_ASIMDHP, 0) \
+ LINE(AARCH64_CPUID, cpuid, "cpuid", AARCH64_HWCAP_CPUID, 0) \
+ LINE(AARCH64_ASIMDRDM, asimdrdm, "asimdrdm", AARCH64_HWCAP_ASIMDRDM, 0) \
+ LINE(AARCH64_JSCVT, jscvt, "jscvt", AARCH64_HWCAP_JSCVT, 0) \
+ LINE(AARCH64_FCMA, fcma, "fcma", AARCH64_HWCAP_FCMA, 0) \
+ LINE(AARCH64_LRCPC, lrcpc, "lrcpc", AARCH64_HWCAP_LRCPC, 0) \
+ LINE(AARCH64_DCPOP, dcpop, "dcpop", AARCH64_HWCAP_DCPOP, 0) \
+ LINE(AARCH64_SHA3, sha3, "sha3", AARCH64_HWCAP_SHA3, 0) \
+ LINE(AARCH64_SM3, sm3, "sm3", AARCH64_HWCAP_SM3, 0) \
+ LINE(AARCH64_SM4, sm4, "sm4", AARCH64_HWCAP_SM4, 0) \
+ LINE(AARCH64_ASIMDDP, asimddp, "asimddp", AARCH64_HWCAP_ASIMDDP, 0) \
+ LINE(AARCH64_SHA512, sha512, "sha512", AARCH64_HWCAP_SHA512, 0) \
+ LINE(AARCH64_SVE, sve, "sve", AARCH64_HWCAP_SVE, 0) \
+ LINE(AARCH64_ASIMDFHM, asimdfhm, "asimdfhm", AARCH64_HWCAP_ASIMDFHM, 0) \
+ LINE(AARCH64_DIT, dit, "dit", AARCH64_HWCAP_DIT, 0) \
+ LINE(AARCH64_USCAT, uscat, "uscat", AARCH64_HWCAP_USCAT, 0) \
+ LINE(AARCH64_ILRCPC, ilrcpc, "ilrcpc", AARCH64_HWCAP_ILRCPC, 0) \
+ LINE(AARCH64_FLAGM, flagm, "flagm", AARCH64_HWCAP_FLAGM, 0) \
+ LINE(AARCH64_SSBS, ssbs, "ssbs", AARCH64_HWCAP_SSBS, 0) \
+ LINE(AARCH64_SB, sb, "sb", AARCH64_HWCAP_SB, 0) \
+ LINE(AARCH64_PACA, paca, "paca", AARCH64_HWCAP_PACA, 0) \
+ LINE(AARCH64_PACG, pacg, "pacg", AARCH64_HWCAP_PACG, 0) \
+ LINE(AARCH64_DCPODP, dcpodp, "dcpodp", 0, AARCH64_HWCAP2_DCPODP) \
+ LINE(AARCH64_SVE2, sve2, "sve2", 0, AARCH64_HWCAP2_SVE2) \
+ LINE(AARCH64_SVEAES, sveaes, "sveaes", 0, AARCH64_HWCAP2_SVEAES) \
+ LINE(AARCH64_SVEPMULL, svepmull, "svepmull", 0, AARCH64_HWCAP2_SVEPMULL) \
+ LINE(AARCH64_SVEBITPERM, svebitperm, "svebitperm", 0, \
+ AARCH64_HWCAP2_SVEBITPERM) \
+ LINE(AARCH64_SVESHA3, svesha3, "svesha3", 0, AARCH64_HWCAP2_SVESHA3) \
+ LINE(AARCH64_SVESM4, svesm4, "svesm4", 0, AARCH64_HWCAP2_SVESM4) \
+ LINE(AARCH64_FLAGM2, flagm2, "flagm2", 0, AARCH64_HWCAP2_FLAGM2) \
+ LINE(AARCH64_FRINT, frint, "frint", 0, AARCH64_HWCAP2_FRINT) \
+ LINE(AARCH64_SVEI8MM, svei8mm, "svei8mm", 0, AARCH64_HWCAP2_SVEI8MM) \
+ LINE(AARCH64_SVEF32MM, svef32mm, "svef32mm", 0, AARCH64_HWCAP2_SVEF32MM) \
+ LINE(AARCH64_SVEF64MM, svef64mm, "svef64mm", 0, AARCH64_HWCAP2_SVEF64MM) \
+ LINE(AARCH64_SVEBF16, svebf16, "svebf16", 0, AARCH64_HWCAP2_SVEBF16) \
+ LINE(AARCH64_I8MM, i8mm, "i8mm", 0, AARCH64_HWCAP2_I8MM) \
+ LINE(AARCH64_BF16, bf16, "bf16", 0, AARCH64_HWCAP2_BF16) \
+ LINE(AARCH64_DGH, dgh, "dgh", 0, AARCH64_HWCAP2_DGH) \
+ LINE(AARCH64_RNG, rng, "rng", 0, AARCH64_HWCAP2_RNG) \
+ LINE(AARCH64_BTI, bti, "bti", 0, AARCH64_HWCAP2_BTI) \
+ LINE(AARCH64_MTE, mte, "mte", 0, AARCH64_HWCAP2_MTE)
+#define INTROSPECTION_PREFIX Aarch64
+#define INTROSPECTION_ENUM_PREFIX AARCH64
+#include "define_introspection_and_hwcaps.inl"
+
+////////////////////////////////////////////////////////////////////////////////
+// Implementation.
+////////////////////////////////////////////////////////////////////////////////
+
+#include <stdbool.h>
+
+#include "internal/bit_utils.h"
+#include "internal/filesystem.h"
+#include "internal/stack_line_reader.h"
+#include "internal/string_view.h"
+
+static bool HandleAarch64Line(const LineResult result,
+ Aarch64Info* const info) {
+ StringView line = result.line;
+ StringView key, value;
+ if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
+ if (CpuFeatures_StringView_IsEquals(key, str("Features"))) {
+ for (size_t i = 0; i < AARCH64_LAST_; ++i) {
+ kSetters[i](&info->features, CpuFeatures_StringView_HasWord(
+ value, kCpuInfoFlags[i], ' '));
+ }
+ } else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) {
+ info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value);
+ } else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) {
+ info->variant = CpuFeatures_StringView_ParsePositiveNumber(value);
+ } else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) {
+ info->part = CpuFeatures_StringView_ParsePositiveNumber(value);
+ } else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) {
+ info->revision = CpuFeatures_StringView_ParsePositiveNumber(value);
+ }
+ }
+ return !result.eof;
+}
+
+static void FillProcCpuInfoData(Aarch64Info* const info) {
+ const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
+ if (fd >= 0) {
+ StackLineReader reader;
+ StackLineReader_Initialize(&reader, fd);
+ for (;;) {
+ if (!HandleAarch64Line(StackLineReader_NextLine(&reader), info)) {
+ break;
+ }
+ }
+ CpuFeatures_CloseFile(fd);
+ }
+}
+
+static const Aarch64Info kEmptyAarch64Info;
+
+Aarch64Info GetAarch64Info(void) {
+ // capabilities are fetched from both getauxval and /proc/cpuinfo so we can
+ // have some information if the executable is sandboxed (aka no access to
+ // /proc/cpuinfo).
+ Aarch64Info info = kEmptyAarch64Info;
+
+ FillProcCpuInfoData(&info);
+ const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
+ for (size_t i = 0; i < AARCH64_LAST_; ++i) {
+ if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
+ kSetters[i](&info.features, true);
+ }
+ }
+
+ return info;
+}
+
+#endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
+#endif // CPU_FEATURES_ARCH_AARCH64
diff --git a/src/cpuinfo_arm.c b/src/impl_arm_linux_or_android.c
index 0f216bf..997ef93 100644
--- a/src/cpuinfo_arm.c
+++ b/src/impl_arm_linux_or_android.c
@@ -12,50 +12,60 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "cpu_features_macros.h"
+
+#ifdef CPU_FEATURES_ARCH_ARM
+#if defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
+
#include "cpuinfo_arm.h"
-#include <assert.h>
+////////////////////////////////////////////////////////////////////////////////
+// Definitions for introspection.
+////////////////////////////////////////////////////////////////////////////////
+#define INTROSPECTION_TABLE \
+ LINE(ARM_SWP, swp, "swp", ARM_HWCAP_SWP, 0) \
+ LINE(ARM_HALF, half, "half", ARM_HWCAP_HALF, 0) \
+ LINE(ARM_THUMB, thumb, "thumb", ARM_HWCAP_THUMB, 0) \
+ LINE(ARM_26BIT, _26bit, "26bit", ARM_HWCAP_26BIT, 0) \
+ LINE(ARM_FASTMULT, fastmult, "fastmult", ARM_HWCAP_FAST_MULT, 0) \
+ LINE(ARM_FPA, fpa, "fpa", ARM_HWCAP_FPA, 0) \
+ LINE(ARM_VFP, vfp, "vfp", ARM_HWCAP_VFP, 0) \
+ LINE(ARM_EDSP, edsp, "edsp", ARM_HWCAP_EDSP, 0) \
+ LINE(ARM_JAVA, java, "java", ARM_HWCAP_JAVA, 0) \
+ LINE(ARM_IWMMXT, iwmmxt, "iwmmxt", ARM_HWCAP_IWMMXT, 0) \
+ LINE(ARM_CRUNCH, crunch, "crunch", ARM_HWCAP_CRUNCH, 0) \
+ LINE(ARM_THUMBEE, thumbee, "thumbee", ARM_HWCAP_THUMBEE, 0) \
+ LINE(ARM_NEON, neon, "neon", ARM_HWCAP_NEON, 0) \
+ LINE(ARM_VFPV3, vfpv3, "vfpv3", ARM_HWCAP_VFPV3, 0) \
+ LINE(ARM_VFPV3D16, vfpv3d16, "vfpv3d16", ARM_HWCAP_VFPV3D16, 0) \
+ LINE(ARM_TLS, tls, "tls", ARM_HWCAP_TLS, 0) \
+ LINE(ARM_VFPV4, vfpv4, "vfpv4", ARM_HWCAP_VFPV4, 0) \
+ LINE(ARM_IDIVA, idiva, "idiva", ARM_HWCAP_IDIVA, 0) \
+ LINE(ARM_IDIVT, idivt, "idivt", ARM_HWCAP_IDIVT, 0) \
+ LINE(ARM_VFPD32, vfpd32, "vfpd32", ARM_HWCAP_VFPD32, 0) \
+ LINE(ARM_LPAE, lpae, "lpae", ARM_HWCAP_LPAE, 0) \
+ LINE(ARM_EVTSTRM, evtstrm, "evtstrm", ARM_HWCAP_EVTSTRM, 0) \
+ LINE(ARM_AES, aes, "aes", 0, ARM_HWCAP2_AES) \
+ LINE(ARM_PMULL, pmull, "pmull", 0, ARM_HWCAP2_PMULL) \
+ LINE(ARM_SHA1, sha1, "sha1", 0, ARM_HWCAP2_SHA1) \
+ LINE(ARM_SHA2, sha2, "sha2", 0, ARM_HWCAP2_SHA2) \
+ LINE(ARM_CRC32, crc32, "crc32", 0, ARM_HWCAP2_CRC32)
+#define INTROSPECTION_PREFIX Arm
+#define INTROSPECTION_ENUM_PREFIX ARM
+#include "define_introspection_and_hwcaps.inl"
+
+////////////////////////////////////////////////////////////////////////////////
+// Implementation.
+////////////////////////////////////////////////////////////////////////////////
+
#include <ctype.h>
+#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"
-// Generation of feature's getters/setters functions and kGetters, kSetters,
-// kCpuInfoFlags and kHardwareCapabilities global tables.
-#define DEFINE_TABLE_FEATURES \
- FEATURE(ARM_SWP, swp, "swp", ARM_HWCAP_SWP, 0) \
- FEATURE(ARM_HALF, half, "half", ARM_HWCAP_HALF, 0) \
- FEATURE(ARM_THUMB, thumb, "thumb", ARM_HWCAP_THUMB, 0) \
- FEATURE(ARM_26BIT, _26bit, "26bit", ARM_HWCAP_26BIT, 0) \
- FEATURE(ARM_FASTMULT, fastmult, "fastmult", ARM_HWCAP_FAST_MULT, 0) \
- FEATURE(ARM_FPA, fpa, "fpa", ARM_HWCAP_FPA, 0) \
- FEATURE(ARM_VFP, vfp, "vfp", ARM_HWCAP_VFP, 0) \
- FEATURE(ARM_EDSP, edsp, "edsp", ARM_HWCAP_EDSP, 0) \
- FEATURE(ARM_JAVA, java, "java", ARM_HWCAP_JAVA, 0) \
- FEATURE(ARM_IWMMXT, iwmmxt, "iwmmxt", ARM_HWCAP_IWMMXT, 0) \
- FEATURE(ARM_CRUNCH, crunch, "crunch", ARM_HWCAP_CRUNCH, 0) \
- FEATURE(ARM_THUMBEE, thumbee, "thumbee", ARM_HWCAP_THUMBEE, 0) \
- FEATURE(ARM_NEON, neon, "neon", ARM_HWCAP_NEON, 0) \
- FEATURE(ARM_VFPV3, vfpv3, "vfpv3", ARM_HWCAP_VFPV3, 0) \
- FEATURE(ARM_VFPV3D16, vfpv3d16, "vfpv3d16", ARM_HWCAP_VFPV3D16, 0) \
- FEATURE(ARM_TLS, tls, "tls", ARM_HWCAP_TLS, 0) \
- FEATURE(ARM_VFPV4, vfpv4, "vfpv4", ARM_HWCAP_VFPV4, 0) \
- FEATURE(ARM_IDIVA, idiva, "idiva", ARM_HWCAP_IDIVA, 0) \
- FEATURE(ARM_IDIVT, idivt, "idivt", ARM_HWCAP_IDIVT, 0) \
- FEATURE(ARM_VFPD32, vfpd32, "vfpd32", ARM_HWCAP_VFPD32, 0) \
- FEATURE(ARM_LPAE, lpae, "lpae", ARM_HWCAP_LPAE, 0) \
- FEATURE(ARM_EVTSTRM, evtstrm, "evtstrm", ARM_HWCAP_EVTSTRM, 0) \
- FEATURE(ARM_AES, aes, "aes", 0, ARM_HWCAP2_AES) \
- FEATURE(ARM_PMULL, pmull, "pmull", 0, ARM_HWCAP2_PMULL) \
- FEATURE(ARM_SHA1, sha1, "sha1", 0, ARM_HWCAP2_SHA1) \
- FEATURE(ARM_SHA2, sha2, "sha2", 0, ARM_HWCAP2_SHA2) \
- FEATURE(ARM_CRC32, crc32, "crc32", 0, ARM_HWCAP2_CRC32)
-#define DEFINE_TABLE_FEATURE_TYPE ArmFeatures
-#include "define_tables.h"
-
typedef struct {
bool processor_reports_armv6;
bool hardware_reports_goldfish;
@@ -77,8 +87,8 @@ static bool HandleArmLine(const LineResult result, ArmInfo* const info,
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
if (CpuFeatures_StringView_IsEquals(key, str("Features"))) {
for (size_t i = 0; i < ARM_LAST_; ++i) {
- kSetters[i](&info->features,
- CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i]));
+ kSetters[i](&info->features, CpuFeatures_StringView_HasWord(
+ value, kCpuInfoFlags[i], ' '));
}
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) {
info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value);
@@ -142,13 +152,14 @@ static void FixErrors(ArmInfo* const info,
// https://crbug.com/341598.
info->features.neon = false;
break;
- case 0x510006F2:
- case 0x510006F3:
- // The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report
- // IDIV support.
- info->features.idiva = true;
- info->features.idivt = true;
- break;
+ }
+
+ // Some Qualcomm Krait kernels forget to report IDIV support.
+ // https://github.com/torvalds/linux/commit/120ecfafabec382c4feb79ff159ef42a39b6d33b
+ if (info->implementer == 0x51 && info->architecture == 7 &&
+ (info->part == 0x4d || info->part == 0x6f)) {
+ info->features.idiva = true;
+ info->features.idivt = true;
}
// Propagate cpu features.
@@ -197,16 +208,5 @@ ArmInfo GetArmInfo(void) {
return info;
}
-////////////////////////////////////////////////////////////////////////////////
-// Introspection functions
-
-int GetArmFeaturesEnumValue(const ArmFeatures* features,
- ArmFeaturesEnum value) {
- if (value >= ARM_LAST_) return false;
- return kGetters[value](features);
-}
-
-const char* GetArmFeaturesEnumName(ArmFeaturesEnum value) {
- if (value >= ARM_LAST_) return "unknown feature";
- return kCpuInfoFlags[value];
-}
+#endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
+#endif // CPU_FEATURES_ARCH_ARM
diff --git a/src/cpuinfo_mips.c b/src/impl_mips_linux_or_android.c
index 83e959f..9a3dc2f 100644
--- a/src/cpuinfo_mips.c
+++ b/src/impl_mips_linux_or_android.c
@@ -1,5 +1,3 @@
-// Copyright 2017 Google LLC
-//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -12,24 +10,33 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "cpu_features_macros.h"
+
+#ifdef CPU_FEATURES_ARCH_MIPS
+#if defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
+
#include "cpuinfo_mips.h"
-#include <assert.h>
+////////////////////////////////////////////////////////////////////////////////
+// Definitions for introspection.
+////////////////////////////////////////////////////////////////////////////////
+#define INTROSPECTION_TABLE \
+ LINE(MIPS_MSA, msa, "msa", MIPS_HWCAP_MSA, 0) \
+ LINE(MIPS_EVA, eva, "eva", 0, 0) \
+ LINE(MIPS_R6, r6, "r6", MIPS_HWCAP_R6, 0)
+#define INTROSPECTION_PREFIX Mips
+#define INTROSPECTION_ENUM_PREFIX MIPS
+#include "define_introspection_and_hwcaps.inl"
+
+////////////////////////////////////////////////////////////////////////////////
+// Implementation.
+////////////////////////////////////////////////////////////////////////////////
#include "internal/filesystem.h"
#include "internal/hwcaps.h"
#include "internal/stack_line_reader.h"
#include "internal/string_view.h"
-// Generation of feature's getters/setters functions and kGetters, kSetters,
-// kCpuInfoFlags and kHardwareCapabilities global tables.
-#define DEFINE_TABLE_FEATURES \
- FEATURE(MIPS_MSA, msa, "msa", MIPS_HWCAP_MSA, 0) \
- FEATURE(MIPS_EVA, eva, "eva", 0, 0) \
- FEATURE(MIPS_R6, r6, "r6", MIPS_HWCAP_R6, 0)
-#define DEFINE_TABLE_FEATURE_TYPE MipsFeatures
-#include "define_tables.h"
-
static bool HandleMipsLine(const LineResult result,
MipsFeatures* const features) {
StringView key, value;
@@ -37,8 +44,8 @@ static bool HandleMipsLine(const LineResult result,
if (CpuFeatures_StringView_GetAttributeKeyValue(result.line, &key, &value)) {
if (CpuFeatures_StringView_IsEquals(key, str("ASEs implemented"))) {
for (size_t i = 0; i < MIPS_LAST_; ++i) {
- kSetters[i](features,
- CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i]));
+ kSetters[i](features, CpuFeatures_StringView_HasWord(
+ value, kCpuInfoFlags[i], ' '));
}
}
}
@@ -77,16 +84,5 @@ MipsInfo GetMipsInfo(void) {
return info;
}
-////////////////////////////////////////////////////////////////////////////////
-// Introspection functions
-
-int GetMipsFeaturesEnumValue(const MipsFeatures* features,
- MipsFeaturesEnum value) {
- if (value >= MIPS_LAST_) return false;
- return kGetters[value](features);
-}
-
-const char* GetMipsFeaturesEnumName(MipsFeaturesEnum value) {
- if (value >= MIPS_LAST_) return "unknown feature";
- return kCpuInfoFlags[value];
-}
+#endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
+#endif // CPU_FEATURES_ARCH_MIPS
diff --git a/src/impl_ppc_linux.c b/src/impl_ppc_linux.c
new file mode 100644
index 0000000..13a381a
--- /dev/null
+++ b/src/impl_ppc_linux.c
@@ -0,0 +1,162 @@
+// Copyright 2018 IBM.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cpu_features_macros.h"
+
+#ifdef CPU_FEATURES_ARCH_PPC
+#ifdef CPU_FEATURES_OS_LINUX
+
+#include "cpuinfo_ppc.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// Definitions for introspection.
+////////////////////////////////////////////////////////////////////////////////
+#define INTROSPECTION_TABLE \
+ LINE(PPC_32, ppc32, "ppc32", PPC_FEATURE_32, 0) \
+ LINE(PPC_64, ppc64, "ppc64", PPC_FEATURE_64, 0) \
+ LINE(PPC_601_INSTR, ppc601, "ppc601", PPC_FEATURE_601_INSTR, 0) \
+ LINE(PPC_HAS_ALTIVEC, altivec, "altivec", PPC_FEATURE_HAS_ALTIVEC, 0) \
+ LINE(PPC_HAS_FPU, fpu, "fpu", PPC_FEATURE_HAS_FPU, 0) \
+ LINE(PPC_HAS_MMU, mmu, "mmu", PPC_FEATURE_HAS_MMU, 0) \
+ LINE(PPC_HAS_4xxMAC, mac_4xx, "4xxmac", PPC_FEATURE_HAS_4xxMAC, 0) \
+ LINE(PPC_UNIFIED_CACHE, unifiedcache, "ucache", PPC_FEATURE_UNIFIED_CACHE, \
+ 0) \
+ LINE(PPC_HAS_SPE, spe, "spe", PPC_FEATURE_HAS_SPE, 0) \
+ LINE(PPC_HAS_EFP_SINGLE, efpsingle, "efpsingle", PPC_FEATURE_HAS_EFP_SINGLE, \
+ 0) \
+ LINE(PPC_HAS_EFP_DOUBLE, efpdouble, "efpdouble", PPC_FEATURE_HAS_EFP_DOUBLE, \
+ 0) \
+ LINE(PPC_NO_TB, no_tb, "notb", PPC_FEATURE_NO_TB, 0) \
+ LINE(PPC_POWER4, power4, "power4", PPC_FEATURE_POWER4, 0) \
+ LINE(PPC_POWER5, power5, "power5", PPC_FEATURE_POWER5, 0) \
+ LINE(PPC_POWER5_PLUS, power5plus, "power5+", PPC_FEATURE_POWER5_PLUS, 0) \
+ LINE(PPC_CELL, cell, "cellbe", PPC_FEATURE_CELL, 0) \
+ LINE(PPC_BOOKE, booke, "booke", PPC_FEATURE_BOOKE, 0) \
+ LINE(PPC_SMT, smt, "smt", PPC_FEATURE_SMT, 0) \
+ LINE(PPC_ICACHE_SNOOP, icachesnoop, "ic_snoop", PPC_FEATURE_ICACHE_SNOOP, 0) \
+ LINE(PPC_ARCH_2_05, arch205, "arch_2_05", PPC_FEATURE_ARCH_2_05, 0) \
+ LINE(PPC_PA6T, pa6t, "pa6t", PPC_FEATURE_PA6T, 0) \
+ LINE(PPC_HAS_DFP, dfp, "dfp", PPC_FEATURE_HAS_DFP, 0) \
+ LINE(PPC_POWER6_EXT, power6ext, "power6x", PPC_FEATURE_POWER6_EXT, 0) \
+ LINE(PPC_ARCH_2_06, arch206, "arch_2_06", PPC_FEATURE_ARCH_2_06, 0) \
+ LINE(PPC_HAS_VSX, vsx, "vsx", PPC_FEATURE_HAS_VSX, 0) \
+ LINE(PPC_PSERIES_PERFMON_COMPAT, pseries_perfmon_compat, "archpmu", \
+ PPC_FEATURE_PSERIES_PERFMON_COMPAT, 0) \
+ LINE(PPC_TRUE_LE, truele, "true_le", PPC_FEATURE_TRUE_LE, 0) \
+ LINE(PPC_PPC_LE, ppcle, "ppcle", PPC_FEATURE_PPC_LE, 0) \
+ LINE(PPC_ARCH_2_07, arch207, "arch_2_07", 0, PPC_FEATURE2_ARCH_2_07) \
+ LINE(PPC_HTM, htm, "htm", 0, PPC_FEATURE2_HTM) \
+ LINE(PPC_DSCR, dscr, "dscr", 0, PPC_FEATURE2_DSCR) \
+ LINE(PPC_EBB, ebb, "ebb", 0, PPC_FEATURE2_EBB) \
+ LINE(PPC_ISEL, isel, "isel", 0, PPC_FEATURE2_ISEL) \
+ LINE(PPC_TAR, tar, "tar", 0, PPC_FEATURE2_TAR) \
+ LINE(PPC_VEC_CRYPTO, vcrypto, "vcrypto", 0, PPC_FEATURE2_VEC_CRYPTO) \
+ LINE(PPC_HTM_NOSC, htm_nosc, "htm-nosc", 0, PPC_FEATURE2_HTM_NOSC) \
+ LINE(PPC_ARCH_3_00, arch300, "arch_3_00", 0, PPC_FEATURE2_ARCH_3_00) \
+ LINE(PPC_HAS_IEEE128, ieee128, "ieee128", 0, PPC_FEATURE2_HAS_IEEE128) \
+ LINE(PPC_DARN, darn, "darn", 0, PPC_FEATURE2_DARN) \
+ LINE(PPC_SCV, scv, "scv", 0, PPC_FEATURE2_SCV) \
+ LINE(PPC_HTM_NO_SUSPEND, htm_no_suspend, "htm-no-suspend", 0, \
+ PPC_FEATURE2_HTM_NO_SUSPEND)
+#define INTROSPECTION_PREFIX PPC
+#define INTROSPECTION_ENUM_PREFIX PPC
+#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 HandlePPCLine(const LineResult result,
+ PPCPlatformStrings* const strings) {
+ StringView line = result.line;
+ StringView key, value;
+ if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
+ if (CpuFeatures_StringView_HasWord(key, "platform", ' ')) {
+ CpuFeatures_StringView_CopyString(value, strings->platform,
+ sizeof(strings->platform));
+ } else if (CpuFeatures_StringView_IsEquals(key, str("model"))) {
+ CpuFeatures_StringView_CopyString(value, strings->model,
+ sizeof(strings->platform));
+ } else if (CpuFeatures_StringView_IsEquals(key, str("machine"))) {
+ CpuFeatures_StringView_CopyString(value, strings->machine,
+ sizeof(strings->platform));
+ } else if (CpuFeatures_StringView_IsEquals(key, str("cpu"))) {
+ CpuFeatures_StringView_CopyString(value, strings->cpu,
+ sizeof(strings->platform));
+ }
+ }
+ return !result.eof;
+}
+
+static void FillProcCpuInfoData(PPCPlatformStrings* const strings) {
+ const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
+ if (fd >= 0) {
+ StackLineReader reader;
+ StackLineReader_Initialize(&reader, fd);
+ for (;;) {
+ if (!HandlePPCLine(StackLineReader_NextLine(&reader), strings)) {
+ break;
+ }
+ }
+ CpuFeatures_CloseFile(fd);
+ }
+}
+
+static const PPCInfo kEmptyPPCInfo;
+
+PPCInfo GetPPCInfo(void) {
+ /*
+ * On Power feature flags aren't currently in cpuinfo so we only look at
+ * the auxilary vector.
+ */
+ PPCInfo info = kEmptyPPCInfo;
+ const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
+ for (size_t i = 0; i < PPC_LAST_; ++i) {
+ if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
+ kSetters[i](&info.features, true);
+ }
+ }
+ return info;
+}
+
+static const PPCPlatformStrings kEmptyPPCPlatformStrings;
+
+PPCPlatformStrings GetPPCPlatformStrings(void) {
+ PPCPlatformStrings strings = kEmptyPPCPlatformStrings;
+ const char* platform = CpuFeatures_GetPlatformPointer();
+ const char* base_platform = CpuFeatures_GetBasePlatformPointer();
+
+ FillProcCpuInfoData(&strings);
+
+ if (platform != NULL)
+ CpuFeatures_StringView_CopyString(str(platform), strings.type.platform,
+ sizeof(strings.type.platform));
+ if (base_platform != NULL)
+ CpuFeatures_StringView_CopyString(str(base_platform),
+ strings.type.base_platform,
+ sizeof(strings.type.base_platform));
+
+ return strings;
+}
+
+#endif // CPU_FEATURES_OS_LINUX
+#endif // CPU_FEATURES_ARCH_PPC
diff --git a/src/cpuinfo_x86.c b/src/impl_x86__base_implementation.inl
index 378ed05..09f24b2 100644
--- a/src/cpuinfo_x86.c
+++ b/src/impl_x86__base_implementation.inl
@@ -13,11 +13,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "cpuinfo_x86.h"
-
#include <stdbool.h>
#include <string.h>
+#include "copy.inl"
+#include "cpuinfo_x86.h"
+#include "equals.inl"
#include "internal/bit_utils.h"
#include "internal/cpuid_x86.h"
@@ -25,91 +26,6 @@
#error "Cannot compile cpuinfo_x86 on a non x86 platform."
#endif
-// Generation of feature's getters/setters functions and kGetters, kSetters,
-// kCpuInfoFlags global tables.
-#define DEFINE_TABLE_FEATURES \
- FEATURE(X86_FPU, fpu, "fpu", 0, 0) \
- FEATURE(X86_TSC, tsc, "tsc", 0, 0) \
- FEATURE(X86_CX8, cx8, "cx8", 0, 0) \
- FEATURE(X86_CLFSH, clfsh, "clfsh", 0, 0) \
- FEATURE(X86_MMX, mmx, "mmx", 0, 0) \
- FEATURE(X86_AES, aes, "aes", 0, 0) \
- FEATURE(X86_ERMS, erms, "erms", 0, 0) \
- FEATURE(X86_F16C, f16c, "f16c", 0, 0) \
- FEATURE(X86_FMA4, fma4, "fma4", 0, 0) \
- FEATURE(X86_FMA3, fma3, "fma3", 0, 0) \
- FEATURE(X86_VAES, vaes, "vaes", 0, 0) \
- FEATURE(X86_VPCLMULQDQ, vpclmulqdq, "vpclmulqdq", 0, 0) \
- FEATURE(X86_BMI1, bmi1, "bmi1", 0, 0) \
- FEATURE(X86_HLE, hle, "hle", 0, 0) \
- FEATURE(X86_BMI2, bmi2, "bmi2", 0, 0) \
- FEATURE(X86_RTM, rtm, "rtm", 0, 0) \
- FEATURE(X86_RDSEED, rdseed, "rdseed", 0, 0) \
- FEATURE(X86_CLFLUSHOPT, clflushopt, "clflushopt", 0, 0) \
- FEATURE(X86_CLWB, clwb, "clwb", 0, 0) \
- FEATURE(X86_SSE, sse, "sse", 0, 0) \
- FEATURE(X86_SSE2, sse2, "sse2", 0, 0) \
- FEATURE(X86_SSE3, sse3, "sse3", 0, 0) \
- FEATURE(X86_SSSE3, ssse3, "ssse3", 0, 0) \
- FEATURE(X86_SSE4_1, sse4_1, "sse4_1", 0, 0) \
- FEATURE(X86_SSE4_2, sse4_2, "sse4_2", 0, 0) \
- FEATURE(X86_SSE4A, sse4a, "sse4a", 0, 0) \
- FEATURE(X86_AVX, avx, "avx", 0, 0) \
- FEATURE(X86_AVX2, avx2, "avx2", 0, 0) \
- FEATURE(X86_AVX512F, avx512f, "avx512f", 0, 0) \
- FEATURE(X86_AVX512CD, avx512cd, "avx512cd", 0, 0) \
- FEATURE(X86_AVX512ER, avx512er, "avx512er", 0, 0) \
- FEATURE(X86_AVX512PF, avx512pf, "avx512pf", 0, 0) \
- FEATURE(X86_AVX512BW, avx512bw, "avx512bw", 0, 0) \
- FEATURE(X86_AVX512DQ, avx512dq, "avx512dq", 0, 0) \
- FEATURE(X86_AVX512VL, avx512vl, "avx512vl", 0, 0) \
- FEATURE(X86_AVX512IFMA, avx512ifma, "avx512ifma", 0, 0) \
- FEATURE(X86_AVX512VBMI, avx512vbmi, "avx512vbmi", 0, 0) \
- FEATURE(X86_AVX512VBMI2, avx512vbmi2, "avx512vbmi2", 0, 0) \
- FEATURE(X86_AVX512VNNI, avx512vnni, "avx512vnni", 0, 0) \
- FEATURE(X86_AVX512BITALG, avx512bitalg, "avx512bitalg", 0, 0) \
- FEATURE(X86_AVX512VPOPCNTDQ, avx512vpopcntdq, "avx512vpopcntdq", 0, 0) \
- FEATURE(X86_AVX512_4VNNIW, avx512_4vnniw, "avx512_4vnniw", 0, 0) \
- FEATURE(X86_AVX512_4VBMI2, avx512_4vbmi2, "avx512_4vbmi2", 0, 0) \
- FEATURE(X86_AVX512_SECOND_FMA, avx512_second_fma, "avx512_second_fma", 0, 0) \
- FEATURE(X86_AVX512_4FMAPS, avx512_4fmaps, "avx512_4fmaps", 0, 0) \
- FEATURE(X86_AVX512_BF16, avx512_bf16, "avx512_bf16", 0, 0) \
- FEATURE(X86_AVX512_VP2INTERSECT, avx512_vp2intersect, "avx512_vp2intersect", \
- 0, 0) \
- FEATURE(X86_AMX_BF16, amx_bf16, "amx_bf16", 0, 0) \
- FEATURE(X86_AMX_TILE, amx_tile, "amx_tile", 0, 0) \
- FEATURE(X86_AMX_INT8, amx_int8, "amx_int8", 0, 0) \
- FEATURE(X86_PCLMULQDQ, pclmulqdq, "pclmulqdq", 0, 0) \
- FEATURE(X86_SMX, smx, "smx", 0, 0) \
- FEATURE(X86_SGX, sgx, "sgx", 0, 0) \
- FEATURE(X86_CX16, cx16, "cx16", 0, 0) \
- FEATURE(X86_SHA, sha, "sha", 0, 0) \
- FEATURE(X86_POPCNT, popcnt, "popcnt", 0, 0) \
- FEATURE(X86_MOVBE, movbe, "movbe", 0, 0) \
- FEATURE(X86_RDRND, rdrnd, "rdrnd", 0, 0) \
- FEATURE(X86_DCA, dca, "dca", 0, 0) \
- FEATURE(X86_SS, ss, "ss", 0, 0)
-#define DEFINE_TABLE_FEATURE_TYPE X86Features
-#define DEFINE_TABLE_DONT_GENERATE_HWCAPS
-#include "define_tables.h"
-
-// The following includes are necessary to provide SSE detections on pre-AVX
-// microarchitectures.
-#if defined(CPU_FEATURES_OS_WINDOWS)
-#include <windows.h> // IsProcessorFeaturePresent
-#elif defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
-#include "internal/filesystem.h" // Needed to parse /proc/cpuinfo
-#include "internal/stack_line_reader.h" // Needed to parse /proc/cpuinfo
-#include "internal/string_view.h" // Needed to parse /proc/cpuinfo
-#elif defined(CPU_FEATURES_OS_DARWIN)
-#if !defined(HAVE_SYSCTLBYNAME)
-#error "Darwin needs support for sysctlbyname"
-#endif
-#include <sys/sysctl.h>
-#else
-#error "Unsupported OS"
-#endif // CPU_FEATURES_OS
-
////////////////////////////////////////////////////////////////////////////////
// Definitions for CpuId and GetXCR0Eax.
////////////////////////////////////////////////////////////////////////////////
@@ -157,8 +73,6 @@ uint32_t GetXCR0Eax(void) { return (uint32_t)_xgetbv(0); }
#error "Unsupported compiler, x86 cpuid requires either GCC, Clang or MSVC."
#endif
-static Leaf CpuId(uint32_t leaf_id) { return GetCpuidLeaf(leaf_id, 0); }
-
static const Leaf kEmptyLeaf;
static Leaf SafeCpuIdEx(uint32_t max_cpuid_leaf, uint32_t leaf_id, int ecx) {
@@ -169,10 +83,47 @@ static Leaf SafeCpuIdEx(uint32_t max_cpuid_leaf, uint32_t leaf_id, int ecx) {
}
}
-static Leaf SafeCpuId(uint32_t max_cpuid_leaf, uint32_t leaf_id) {
- return SafeCpuIdEx(max_cpuid_leaf, leaf_id, 0);
+typedef struct {
+ uint32_t max_cpuid_leaf;
+ Leaf leaf_0; // Root
+ Leaf leaf_1; // Family, Model, Stepping
+ Leaf leaf_2; // Intel cache info + features
+ Leaf leaf_7; // Features
+ Leaf leaf_7_1; // Features
+ uint32_t max_cpuid_leaf_ext;
+ Leaf leaf_80000000; // Root for extended leaves
+ Leaf leaf_80000001; // AMD features features and cache
+ Leaf leaf_80000002; // brand string
+ Leaf leaf_80000003; // brand string
+ Leaf leaf_80000004; // brand string
+} Leaves;
+
+static Leaves ReadLeaves() {
+ const Leaf leaf_0 = GetCpuidLeaf(0, 0);
+ const uint32_t max_cpuid_leaf = leaf_0.eax;
+ const Leaf leaf_80000000 = GetCpuidLeaf(0x80000000, 0);
+ const uint32_t max_cpuid_leaf_ext = leaf_80000000.eax;
+ return (Leaves){
+ .max_cpuid_leaf = max_cpuid_leaf,
+ .leaf_0 = leaf_0,
+ .leaf_1 = SafeCpuIdEx(max_cpuid_leaf, 0x00000001, 0),
+ .leaf_2 = SafeCpuIdEx(max_cpuid_leaf, 0x00000002, 0),
+ .leaf_7 = SafeCpuIdEx(max_cpuid_leaf, 0x00000007, 0),
+ .leaf_7_1 = SafeCpuIdEx(max_cpuid_leaf, 0x00000007, 1),
+ .max_cpuid_leaf_ext = max_cpuid_leaf_ext,
+ .leaf_80000000 = leaf_80000000,
+ .leaf_80000001 = SafeCpuIdEx(max_cpuid_leaf_ext, 0x80000001, 0),
+ .leaf_80000002 = SafeCpuIdEx(max_cpuid_leaf_ext, 0x80000002, 0),
+ .leaf_80000003 = SafeCpuIdEx(max_cpuid_leaf_ext, 0x80000003, 0),
+ .leaf_80000004 = SafeCpuIdEx(max_cpuid_leaf_ext, 0x80000004, 0),
+ };
}
+////////////////////////////////////////////////////////////////////////////////
+// OS support
+// TODO: Add documentation
+////////////////////////////////////////////////////////////////////////////////
+
#define MASK_XMM 0x2
#define MASK_YMM 0x4
#define MASK_MASKREG 0x20
@@ -211,49 +162,574 @@ static bool HasTmmOsXSave(uint32_t xcr0_eax) {
MASK_ZMM16_31 | MASK_XTILECFG | MASK_XTILEDATA);
}
-static bool HasSecondFMA(uint32_t model) {
+////////////////////////////////////////////////////////////////////////////////
+// Vendor
+////////////////////////////////////////////////////////////////////////////////
+
+static void SetVendor(const Leaf leaf, char* const vendor) {
+ *(uint32_t*)(vendor) = leaf.ebx;
+ *(uint32_t*)(vendor + 4) = leaf.edx;
+ *(uint32_t*)(vendor + 8) = leaf.ecx;
+ vendor[12] = '\0';
+}
+
+static int IsVendor(const Leaf leaf, const char* const name) {
+ const uint32_t ebx = *(const uint32_t*)(name);
+ const uint32_t edx = *(const uint32_t*)(name + 4);
+ const uint32_t ecx = *(const uint32_t*)(name + 8);
+ return leaf.ebx == ebx && leaf.ecx == ecx && leaf.edx == edx;
+}
+
+static int IsVendorByX86Info(const X86Info* info, const char* const name) {
+ return equals(info->vendor, name, sizeof(info->vendor));
+}
+
+// TODO: Remove when deprecation period is over,
+void FillX86BrandString(char brand_string[49]) {
+ const Leaves leaves = ReadLeaves();
+ const Leaf packed[3] = {
+ leaves.leaf_80000002,
+ leaves.leaf_80000003,
+ leaves.leaf_80000004,
+ };
+#if __STDC_VERSION__ >= 201112L
+ _Static_assert(sizeof(packed) == 48, "Leaves must be packed");
+#endif
+ copy(brand_string, (const char*)(packed), 48);
+ brand_string[48] = '\0';
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CpuId
+////////////////////////////////////////////////////////////////////////////////
+
+static bool HasSecondFMA(const X86Info* info) {
// Skylake server
- if (model == 0x55) {
- char proc_name[49] = {0};
- FillX86BrandString(proc_name);
+ if (info->model == 0x55) {
// detect Xeon
- if (proc_name[9] == 'X') {
+ if (info->brand_string[9] == 'X') {
// detect Silver or Bronze
- if (proc_name[17] == 'S' || proc_name[17] == 'B') return false;
+ if (info->brand_string[17] == 'S' || info->brand_string[17] == 'B')
+ return false;
// detect Gold 5_20 and below, except for Gold 53__
- if (proc_name[17] == 'G' && proc_name[22] == '5')
- return ((proc_name[23] == '3') ||
- (proc_name[24] == '2' && proc_name[25] == '2'));
+ if (info->brand_string[17] == 'G' && info->brand_string[22] == '5')
+ return (
+ (info->brand_string[23] == '3') ||
+ (info->brand_string[24] == '2' && info->brand_string[25] == '2'));
// detect Xeon W 210x
- if (proc_name[17] == 'W' && proc_name[21] == '0') return false;
+ if (info->brand_string[17] == 'W' && info->brand_string[21] == '0')
+ return false;
// detect Xeon D 2xxx
- if (proc_name[17] == 'D' && proc_name[19] == '2' && proc_name[20] == '1')
+ if (info->brand_string[17] == 'D' && info->brand_string[19] == '2' &&
+ info->brand_string[20] == '1')
return false;
}
return true;
}
// Cannon Lake client
- if (model == 0x66) return false;
+ if (info->model == 0x66) return false;
// Ice Lake client
- if (model == 0x7d || model == 0x7e) return false;
+ if (info->model == 0x7d || info->model == 0x7e) return false;
// This is the right default...
return true;
}
-static void SetVendor(const Leaf leaf, char* const vendor) {
- *(uint32_t*)(vendor) = leaf.ebx;
- *(uint32_t*)(vendor + 4) = leaf.edx;
- *(uint32_t*)(vendor + 8) = leaf.ecx;
- vendor[12] = '\0';
+// Internal structure to hold the OS support for vector operations.
+// Avoid to recompute them since each call to cpuid is ~100 cycles.
+typedef struct {
+ bool sse_registers;
+ bool avx_registers;
+ bool avx512_registers;
+ bool amx_registers;
+} OsPreserves;
+
+// These two functions have to be implemented by the OS, that is the file
+// including this file.
+static void OverrideOsPreserves(OsPreserves* os_preserves);
+static void DetectFeaturesFromOs(X86Info* info, X86Features* features);
+
+// Reference https://en.wikipedia.org/wiki/CPUID.
+static void ParseCpuId(const Leaves* leaves, X86Info* info,
+ OsPreserves* os_preserves) {
+ const Leaf leaf_1 = leaves->leaf_1;
+ const Leaf leaf_7 = leaves->leaf_7;
+ const Leaf leaf_7_1 = leaves->leaf_7_1;
+
+ const bool have_xsave = IsBitSet(leaf_1.ecx, 26);
+ const bool have_osxsave = IsBitSet(leaf_1.ecx, 27);
+ const bool have_xcr0 = have_xsave && have_osxsave;
+
+ const uint32_t family = ExtractBitRange(leaf_1.eax, 11, 8);
+ const uint32_t extended_family = ExtractBitRange(leaf_1.eax, 27, 20);
+ const uint32_t model = ExtractBitRange(leaf_1.eax, 7, 4);
+ const uint32_t extended_model = ExtractBitRange(leaf_1.eax, 19, 16);
+
+ X86Features* const features = &info->features;
+
+ // Fill Family, Model and Stepping.
+ info->family = extended_family + family;
+ info->model = (extended_model << 4) + model;
+ info->stepping = ExtractBitRange(leaf_1.eax, 3, 0);
+
+ // Fill Brand String.
+ const Leaf packed[3] = {
+ leaves->leaf_80000002,
+ leaves->leaf_80000003,
+ leaves->leaf_80000004,
+ };
+#if __STDC_VERSION__ >= 201112L
+ _Static_assert(sizeof(packed) == 48, "Leaves must be packed");
+#endif
+ copy(info->brand_string, (const char*)(packed), 48);
+ info->brand_string[48] = '\0';
+
+ // Fill cpu features.
+ features->fpu = IsBitSet(leaf_1.edx, 0);
+ features->tsc = IsBitSet(leaf_1.edx, 4);
+ features->cx8 = IsBitSet(leaf_1.edx, 8);
+ features->clfsh = IsBitSet(leaf_1.edx, 19);
+ features->mmx = IsBitSet(leaf_1.edx, 23);
+ features->ss = IsBitSet(leaf_1.edx, 27);
+ features->pclmulqdq = IsBitSet(leaf_1.ecx, 1);
+ features->smx = IsBitSet(leaf_1.ecx, 6);
+ features->cx16 = IsBitSet(leaf_1.ecx, 13);
+ features->dca = IsBitSet(leaf_1.ecx, 18);
+ features->movbe = IsBitSet(leaf_1.ecx, 22);
+ features->popcnt = IsBitSet(leaf_1.ecx, 23);
+ features->aes = IsBitSet(leaf_1.ecx, 25);
+ features->f16c = IsBitSet(leaf_1.ecx, 29);
+ features->rdrnd = IsBitSet(leaf_1.ecx, 30);
+ features->sgx = IsBitSet(leaf_7.ebx, 2);
+ features->bmi1 = IsBitSet(leaf_7.ebx, 3);
+ features->hle = IsBitSet(leaf_7.ebx, 4);
+ features->bmi2 = IsBitSet(leaf_7.ebx, 8);
+ features->erms = IsBitSet(leaf_7.ebx, 9);
+ features->rtm = IsBitSet(leaf_7.ebx, 11);
+ features->rdseed = IsBitSet(leaf_7.ebx, 18);
+ features->clflushopt = IsBitSet(leaf_7.ebx, 23);
+ features->clwb = IsBitSet(leaf_7.ebx, 24);
+ features->sha = IsBitSet(leaf_7.ebx, 29);
+ features->vaes = IsBitSet(leaf_7.ecx, 9);
+ features->vpclmulqdq = IsBitSet(leaf_7.ecx, 10);
+ features->adx = IsBitSet(leaf_7.ebx, 19);
+
+ /////////////////////////////////////////////////////////////////////////////
+ // The following section is devoted to Vector Extensions.
+ /////////////////////////////////////////////////////////////////////////////
+
+ // CPU with AVX expose XCR0 which enables checking vector extensions OS
+ // support through cpuid.
+ if (have_xcr0) {
+ // Here we rely exclusively on cpuid for both CPU and OS support of vector
+ // extensions.
+ const uint32_t xcr0_eax = GetXCR0Eax();
+ os_preserves->sse_registers = HasXmmOsXSave(xcr0_eax);
+ os_preserves->avx_registers = HasYmmOsXSave(xcr0_eax);
+ os_preserves->avx512_registers = HasZmmOsXSave(xcr0_eax);
+ os_preserves->amx_registers = HasTmmOsXSave(xcr0_eax);
+ OverrideOsPreserves(os_preserves);
+
+ if (os_preserves->sse_registers) {
+ features->sse = IsBitSet(leaf_1.edx, 25);
+ features->sse2 = IsBitSet(leaf_1.edx, 26);
+ features->sse3 = IsBitSet(leaf_1.ecx, 0);
+ features->ssse3 = IsBitSet(leaf_1.ecx, 9);
+ features->sse4_1 = IsBitSet(leaf_1.ecx, 19);
+ features->sse4_2 = IsBitSet(leaf_1.ecx, 20);
+ }
+ if (os_preserves->avx_registers) {
+ features->fma3 = IsBitSet(leaf_1.ecx, 12);
+ features->avx = IsBitSet(leaf_1.ecx, 28);
+ features->avx2 = IsBitSet(leaf_7.ebx, 5);
+ }
+ if (os_preserves->avx512_registers) {
+ features->avx512f = IsBitSet(leaf_7.ebx, 16);
+ features->avx512cd = IsBitSet(leaf_7.ebx, 28);
+ features->avx512er = IsBitSet(leaf_7.ebx, 27);
+ features->avx512pf = IsBitSet(leaf_7.ebx, 26);
+ features->avx512bw = IsBitSet(leaf_7.ebx, 30);
+ features->avx512dq = IsBitSet(leaf_7.ebx, 17);
+ features->avx512vl = IsBitSet(leaf_7.ebx, 31);
+ features->avx512ifma = IsBitSet(leaf_7.ebx, 21);
+ features->avx512vbmi = IsBitSet(leaf_7.ecx, 1);
+ features->avx512vbmi2 = IsBitSet(leaf_7.ecx, 6);
+ features->avx512vnni = IsBitSet(leaf_7.ecx, 11);
+ features->avx512bitalg = IsBitSet(leaf_7.ecx, 12);
+ features->avx512vpopcntdq = IsBitSet(leaf_7.ecx, 14);
+ features->avx512_4vnniw = IsBitSet(leaf_7.edx, 2);
+ features->avx512_4vbmi2 = IsBitSet(leaf_7.edx, 3);
+ features->avx512_second_fma = HasSecondFMA(info);
+ features->avx512_4fmaps = IsBitSet(leaf_7.edx, 3);
+ features->avx512_bf16 = IsBitSet(leaf_7_1.eax, 5);
+ features->avx512_vp2intersect = IsBitSet(leaf_7.edx, 8);
+ }
+ if (os_preserves->amx_registers) {
+ features->amx_bf16 = IsBitSet(leaf_7.edx, 22);
+ features->amx_tile = IsBitSet(leaf_7.edx, 24);
+ features->amx_int8 = IsBitSet(leaf_7.edx, 25);
+ }
+ } else {
+ // When XCR0 is not available (Atom based or older cpus) we need to defer to
+ // the OS via custom code.
+ DetectFeaturesFromOs(info, features);
+ // Now that we have queried the OS for SSE support, we report this back to
+ // os_preserves. This is needed in case of AMD CPU's to enable testing of
+ // sse4a (See ParseExtraAMDCpuId below).
+ if (features->sse) os_preserves->sse_registers = true;
+ }
}
-static int IsVendor(const Leaf leaf, const char* const name) {
- const uint32_t ebx = *(const uint32_t*)(name);
- const uint32_t edx = *(const uint32_t*)(name + 4);
- const uint32_t ecx = *(const uint32_t*)(name + 8);
- return leaf.ebx == ebx && leaf.ecx == ecx && leaf.edx == edx;
+static void ParseExtraAMDCpuId(const Leaves* leaves, X86Info* info,
+ OsPreserves os_preserves) {
+ const Leaf leaf_80000001 = leaves->leaf_80000001;
+
+ X86Features* const features = &info->features;
+
+ if (os_preserves.sse_registers) {
+ features->sse4a = IsBitSet(leaf_80000001.ecx, 6);
+ }
+
+ if (os_preserves.avx_registers) {
+ features->fma4 = IsBitSet(leaf_80000001.ecx, 16);
+ }
+}
+
+static const X86Info kEmptyX86Info;
+static const OsPreserves kEmptyOsPreserves;
+
+X86Info GetX86Info(void) {
+ X86Info info = kEmptyX86Info;
+ const Leaves leaves = ReadLeaves();
+ const bool is_intel =
+ IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_GENUINE_INTEL);
+ const bool is_amd =
+ IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
+ const bool is_hygon =
+ IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_HYGON_GENUINE);
+ const bool is_zhaoxin =
+ (IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_CENTAUR_HAULS) ||
+ IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_SHANGHAI));
+ SetVendor(leaves.leaf_0, info.vendor);
+ if (is_intel || is_amd || is_hygon || is_zhaoxin) {
+ OsPreserves os_preserves = kEmptyOsPreserves;
+ ParseCpuId(&leaves, &info, &os_preserves);
+ if (is_amd || is_hygon) {
+ ParseExtraAMDCpuId(&leaves, &info, os_preserves);
+ }
+ }
+ return info;
}
+////////////////////////////////////////////////////////////////////////////////
+// Microarchitecture
+////////////////////////////////////////////////////////////////////////////////
+
+#define CPUID(FAMILY, MODEL) ((((FAMILY)&0xFF) << 8) | ((MODEL)&0xFF))
+
+X86Microarchitecture GetX86Microarchitecture(const X86Info* info) {
+ if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_GENUINE_INTEL)) {
+ switch (CPUID(info->family, info->model)) {
+ case CPUID(0x04, 0x01):
+ case CPUID(0x04, 0x02):
+ case CPUID(0x04, 0x03):
+ case CPUID(0x04, 0x04):
+ case CPUID(0x04, 0x05):
+ case CPUID(0x04, 0x07):
+ case CPUID(0x04, 0x08):
+ case CPUID(0x04, 0x09):
+ // https://en.wikichip.org/wiki/intel/microarchitectures/80486
+ return INTEL_80486;
+ case CPUID(0x05, 0x01):
+ case CPUID(0x05, 0x02):
+ case CPUID(0x05, 0x04):
+ case CPUID(0x05, 0x07):
+ case CPUID(0x05, 0x08):
+ // https://en.wikichip.org/wiki/intel/microarchitectures/p5
+ return INTEL_P5;
+ case CPUID(0x05, 0x09):
+ case CPUID(0x05, 0x0A):
+ // https://en.wikichip.org/wiki/intel/quark
+ return INTEL_LAKEMONT;
+ case CPUID(0x06, 0x1C): // Intel(R) Atom(TM) CPU 230 @ 1.60GHz
+ case CPUID(0x06, 0x35):
+ case CPUID(0x06, 0x36):
+ case CPUID(0x06, 0x70): // https://en.wikichip.org/wiki/intel/atom/230
+ // https://en.wikipedia.org/wiki/Bonnell_(microarchitecture)
+ return INTEL_ATOM_BNL;
+ case CPUID(0x06, 0x37):
+ case CPUID(0x06, 0x4C):
+ // https://en.wikipedia.org/wiki/Silvermont
+ return INTEL_ATOM_SMT;
+ case CPUID(0x06, 0x5C):
+ // https://en.wikipedia.org/wiki/Goldmont
+ return INTEL_ATOM_GMT;
+ case CPUID(0x06, 0x0F):
+ case CPUID(0x06, 0x16):
+ // https://en.wikipedia.org/wiki/Intel_Core_(microarchitecture)
+ return INTEL_CORE;
+ case CPUID(0x06, 0x17):
+ case CPUID(0x06, 0x1D):
+ // https://en.wikipedia.org/wiki/Penryn_(microarchitecture)
+ return INTEL_PNR;
+ case CPUID(0x06, 0x1A):
+ case CPUID(0x06, 0x1E):
+ case CPUID(0x06, 0x1F):
+ case CPUID(0x06, 0x2E):
+ // https://en.wikipedia.org/wiki/Nehalem_(microarchitecture)
+ return INTEL_NHM;
+ case CPUID(0x06, 0x25):
+ case CPUID(0x06, 0x2C):
+ case CPUID(0x06, 0x2F):
+ // https://en.wikipedia.org/wiki/Westmere_(microarchitecture)
+ return INTEL_WSM;
+ case CPUID(0x06, 0x2A):
+ case CPUID(0x06, 0x2D):
+ // https://en.wikipedia.org/wiki/Sandy_Bridge#Models_and_steppings
+ return INTEL_SNB;
+ case CPUID(0x06, 0x3A):
+ case CPUID(0x06, 0x3E):
+ // https://en.wikipedia.org/wiki/Ivy_Bridge_(microarchitecture)#Models_and_steppings
+ return INTEL_IVB;
+ case CPUID(0x06, 0x3C):
+ case CPUID(0x06, 0x3F):
+ case CPUID(0x06, 0x45):
+ case CPUID(0x06, 0x46):
+ // https://en.wikipedia.org/wiki/Haswell_(microarchitecture)
+ return INTEL_HSW;
+ case CPUID(0x06, 0x3D):
+ case CPUID(0x06, 0x47):
+ case CPUID(0x06, 0x4F):
+ case CPUID(0x06, 0x56):
+ // https://en.wikipedia.org/wiki/Broadwell_(microarchitecture)
+ return INTEL_BDW;
+ case CPUID(0x06, 0x4E):
+ case CPUID(0x06, 0x55):
+ case CPUID(0x06, 0x5E):
+ // https://en.wikipedia.org/wiki/Skylake_(microarchitecture)
+ return INTEL_SKL;
+ case CPUID(0x06, 0x66):
+ // https://en.wikipedia.org/wiki/Cannon_Lake_(microarchitecture)
+ return INTEL_CNL;
+ case CPUID(0x06, 0x7D): // client
+ case CPUID(0x06, 0x7E): // client
+ case CPUID(0x06, 0x9D): // NNP-I
+ case CPUID(0x06, 0x6A): // server
+ case CPUID(0x06, 0x6C): // server
+ // https://en.wikipedia.org/wiki/Ice_Lake_(microprocessor)
+ return INTEL_ICL;
+ case CPUID(0x06, 0x8C):
+ case CPUID(0x06, 0x8D):
+ // https://en.wikipedia.org/wiki/Tiger_Lake_(microarchitecture)
+ return INTEL_TGL;
+ case CPUID(0x06, 0x8F):
+ // https://en.wikipedia.org/wiki/Sapphire_Rapids
+ return INTEL_SPR;
+ case CPUID(0x06, 0x8E):
+ switch (info->stepping) {
+ case 9:
+ return INTEL_KBL; // https://en.wikipedia.org/wiki/Kaby_Lake
+ case 10:
+ return INTEL_CFL; // https://en.wikipedia.org/wiki/Coffee_Lake
+ case 11:
+ return INTEL_WHL; // https://en.wikipedia.org/wiki/Whiskey_Lake_(microarchitecture)
+ default:
+ return X86_UNKNOWN;
+ }
+ case CPUID(0x06, 0x9E):
+ if (info->stepping > 9) {
+ // https://en.wikipedia.org/wiki/Coffee_Lake
+ return INTEL_CFL;
+ } else {
+ // https://en.wikipedia.org/wiki/Kaby_Lake
+ return INTEL_KBL;
+ }
+ case CPUID(0x06, 0x97):
+ case CPUID(0x06, 0x9A):
+ // https://en.wikichip.org/wiki/intel/microarchitectures/alder_lake
+ return INTEL_ADL;
+ case CPUID(0x06, 0xA7):
+ // https://en.wikichip.org/wiki/intel/microarchitectures/rocket_lake
+ return INTEL_RCL;
+ case CPUID(0x06, 0x85):
+ // https://en.wikichip.org/wiki/intel/microarchitectures/knights_mill
+ return INTEL_KNIGHTS_M;
+ case CPUID(0x06, 0x57):
+ // https://en.wikichip.org/wiki/intel/microarchitectures/knights_landing
+ return INTEL_KNIGHTS_L;
+ case CPUID(0x0B, 0x00):
+ // https://en.wikichip.org/wiki/intel/microarchitectures/knights_ferry
+ return INTEL_KNIGHTS_F;
+ case CPUID(0x0B, 0x01):
+ // https://en.wikichip.org/wiki/intel/microarchitectures/knights_corner
+ return INTEL_KNIGHTS_C;
+ case CPUID(0x0F, 0x01):
+ case CPUID(0x0F, 0x02):
+ case CPUID(0x0F, 0x03):
+ case CPUID(0x0F, 0x04):
+ case CPUID(0x0F, 0x06):
+ // https://en.wikichip.org/wiki/intel/microarchitectures/netburst
+ return INTEL_NETBURST;
+ default:
+ return X86_UNKNOWN;
+ }
+ }
+ if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_CENTAUR_HAULS)) {
+ switch (CPUID(info->family, info->model)) {
+ case CPUID(0x06, 0x0F):
+ case CPUID(0x06, 0x19):
+ // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/zhangjiang
+ return ZHAOXIN_ZHANGJIANG;
+ case CPUID(0x07, 0x1B):
+ // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/wudaokou
+ return ZHAOXIN_WUDAOKOU;
+ case CPUID(0x07, 0x3B):
+ // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/lujiazui
+ return ZHAOXIN_LUJIAZUI;
+ case CPUID(0x07, 0x5B):
+ return ZHAOXIN_YONGFENG;
+ default:
+ return X86_UNKNOWN;
+ }
+ }
+ if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_SHANGHAI)) {
+ switch (CPUID(info->family, info->model)) {
+ case CPUID(0x06, 0x0F):
+ case CPUID(0x06, 0x19):
+ // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/zhangjiang
+ return ZHAOXIN_ZHANGJIANG;
+ case CPUID(0x07, 0x1B):
+ // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/wudaokou
+ return ZHAOXIN_WUDAOKOU;
+ case CPUID(0x07, 0x3B):
+ // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/lujiazui
+ return ZHAOXIN_LUJIAZUI;
+ case CPUID(0x07, 0x5B):
+ return ZHAOXIN_YONGFENG;
+ default:
+ return X86_UNKNOWN;
+ }
+ }
+ if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_AUTHENTIC_AMD)) {
+ switch (CPUID(info->family, info->model)) {
+ // https://en.wikichip.org/wiki/amd/cpuid
+ case CPUID(0xF, 0x04):
+ case CPUID(0xF, 0x05):
+ case CPUID(0xF, 0x07):
+ case CPUID(0xF, 0x08):
+ case CPUID(0xF, 0x0C):
+ case CPUID(0xF, 0x0E):
+ case CPUID(0xF, 0x0F):
+ case CPUID(0xF, 0x14):
+ case CPUID(0xF, 0x15):
+ case CPUID(0xF, 0x17):
+ case CPUID(0xF, 0x18):
+ case CPUID(0xF, 0x1B):
+ case CPUID(0xF, 0x1C):
+ case CPUID(0xF, 0x1F):
+ case CPUID(0xF, 0x21):
+ case CPUID(0xF, 0x23):
+ case CPUID(0xF, 0x24):
+ case CPUID(0xF, 0x25):
+ case CPUID(0xF, 0x27):
+ case CPUID(0xF, 0x2B):
+ case CPUID(0xF, 0x2C):
+ case CPUID(0xF, 0x2F):
+ case CPUID(0xF, 0x41):
+ case CPUID(0xF, 0x43):
+ case CPUID(0xF, 0x48):
+ case CPUID(0xF, 0x4B):
+ case CPUID(0xF, 0x4C):
+ case CPUID(0xF, 0x4F):
+ case CPUID(0xF, 0x5D):
+ case CPUID(0xF, 0x5F):
+ case CPUID(0xF, 0x68):
+ case CPUID(0xF, 0x6B):
+ case CPUID(0xF, 0x6F):
+ case CPUID(0xF, 0x7F):
+ case CPUID(0xF, 0xC1):
+ return AMD_HAMMER;
+ case CPUID(0x10, 0x02):
+ case CPUID(0x10, 0x04):
+ case CPUID(0x10, 0x05):
+ case CPUID(0x10, 0x06):
+ case CPUID(0x10, 0x08):
+ case CPUID(0x10, 0x09):
+ case CPUID(0x10, 0x0A):
+ return AMD_K10;
+ case CPUID(0x11, 0x03):
+ // http://developer.amd.com/wordpress/media/2012/10/41788.pdf
+ return AMD_K11;
+ case CPUID(0x12, 0x01):
+ // https://www.amd.com/system/files/TechDocs/44739_12h_Rev_Gd.pdf
+ return AMD_K12;
+ case CPUID(0x14, 0x00):
+ case CPUID(0x14, 0x01):
+ case CPUID(0x14, 0x02):
+ // https://www.amd.com/system/files/TechDocs/47534_14h_Mod_00h-0Fh_Rev_Guide.pdf
+ return AMD_BOBCAT;
+ case CPUID(0x15, 0x01):
+ // https://en.wikichip.org/wiki/amd/microarchitectures/bulldozer
+ return AMD_BULLDOZER;
+ case CPUID(0x15, 0x02):
+ case CPUID(0x15, 0x11):
+ case CPUID(0x15, 0x13):
+ // https://en.wikichip.org/wiki/amd/microarchitectures/piledriver
+ return AMD_PILEDRIVER;
+ case CPUID(0x15, 0x30):
+ case CPUID(0x15, 0x38):
+ // https://en.wikichip.org/wiki/amd/microarchitectures/steamroller
+ return AMD_STREAMROLLER;
+ case CPUID(0x15, 0x60):
+ case CPUID(0x15, 0x65):
+ case CPUID(0x15, 0x70):
+ // https://en.wikichip.org/wiki/amd/microarchitectures/excavator
+ return AMD_EXCAVATOR;
+ case CPUID(0x16, 0x00):
+ return AMD_JAGUAR;
+ case CPUID(0x16, 0x30):
+ return AMD_PUMA;
+ case CPUID(0x17, 0x01):
+ case CPUID(0x17, 0x11):
+ case CPUID(0x17, 0x18):
+ case CPUID(0x17, 0x20):
+ // https://en.wikichip.org/wiki/amd/microarchitectures/zen
+ return AMD_ZEN;
+ case CPUID(0x17, 0x08):
+ // https://en.wikichip.org/wiki/amd/microarchitectures/zen%2B
+ return AMD_ZEN_PLUS;
+ case CPUID(0x17, 0x31):
+ case CPUID(0x17, 0x47):
+ case CPUID(0x17, 0x60):
+ case CPUID(0x17, 0x68):
+ case CPUID(0x17, 0x71):
+ case CPUID(0x17, 0x90):
+ case CPUID(0x17, 0x98):
+ // https://en.wikichip.org/wiki/amd/microarchitectures/zen_2
+ return AMD_ZEN2;
+ case CPUID(0x19, 0x01):
+ case CPUID(0x19, 0x21):
+ case CPUID(0x19, 0x30):
+ case CPUID(0x19, 0x40):
+ case CPUID(0x19, 0x50):
+ // https://en.wikichip.org/wiki/amd/microarchitectures/zen_3
+ return AMD_ZEN3;
+ default:
+ return X86_UNKNOWN;
+ }
+ }
+ if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_HYGON_GENUINE)) {
+ switch (CPUID(info->family, info->model)) {
+ case CPUID(0x18, 0x00):
+ return AMD_ZEN;
+ }
+ }
+ return X86_UNKNOWN;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CacheInfo
+////////////////////////////////////////////////////////////////////////////////
+
static const CacheLevelInfo kEmptyCacheLevelInfo;
static CacheLevelInfo GetCacheLevelInfo(const uint32_t reg) {
@@ -1114,509 +1590,219 @@ static CacheLevelInfo GetCacheLevelInfo(const uint32_t reg) {
}
}
-static void GetByteArrayFromRegister(uint32_t result[4], const uint32_t reg) {
- for (int i = 0; i < 4; ++i) {
- result[i] = ExtractBitRange(reg, (i + 1) * 8, i * 8);
- }
-}
-
-static void ParseLeaf2(const int max_cpuid_leaf, CacheInfo* info) {
- Leaf leaf = SafeCpuId(max_cpuid_leaf, 2);
- uint32_t registers[] = {leaf.eax, leaf.ebx, leaf.ecx, leaf.edx};
- for (int i = 0; i < 4; ++i) {
- if (registers[i] & (1U << 31)) {
- continue; // register does not contains valid information
- }
- uint32_t bytes[4];
- GetByteArrayFromRegister(bytes, registers[i]);
- for (int j = 0; j < 4; ++j) {
- if (bytes[j] == 0xFF)
- break; // leaf 4 should be used to fetch cache information
- info->levels[info->size] = GetCacheLevelInfo(bytes[j]);
- }
+// From https://www.felixcloutier.com/x86/cpuid#tbl-3-12
+static void ParseLeaf2(const Leaves* leaves, CacheInfo* info) {
+ Leaf leaf = leaves->leaf_2;
+ // The least-significant byte in register EAX (register AL) will always return
+ // 01H. Software should ignore this value and not interpret it as an
+ // informational descriptor.
+ leaf.eax &= 0xFFFFFF00; // Zeroing out AL. 0 is the empty descriptor.
+ // The most significant bit (bit 31) of each register indicates whether the
+ // register contains valid information (set to 0) or is reserved (set to 1).
+ if (IsBitSet(leaf.eax, 31)) leaf.eax = 0;
+ if (IsBitSet(leaf.ebx, 31)) leaf.ebx = 0;
+ if (IsBitSet(leaf.ecx, 31)) leaf.ecx = 0;
+ if (IsBitSet(leaf.edx, 31)) leaf.edx = 0;
+
+ uint8_t data[16];
+#if __STDC_VERSION__ >= 201112L
+ _Static_assert(sizeof(Leaf) == sizeof(data), "Leaf must be 16 bytes");
+#endif
+ copy((char*)(data), (const char*)(&leaf), sizeof(data));
+ for (size_t i = 0; i < sizeof(data); ++i) {
+ const uint8_t descriptor = data[i];
+ if (descriptor == 0) continue;
+ info->levels[info->size] = GetCacheLevelInfo(descriptor);
info->size++;
}
}
-static void ParseLeaf4(const int max_cpuid_leaf, CacheInfo* info) {
- info->size = 0;
- for (int cache_id = 0; cache_id < CPU_FEATURES_MAX_CACHE_LEVEL; cache_id++) {
- const Leaf leaf = SafeCpuIdEx(max_cpuid_leaf, 4, cache_id);
- CacheType cache_type = ExtractBitRange(leaf.eax, 4, 0);
- if (cache_type == CPU_FEATURE_CACHE_NULL) {
- info->levels[cache_id] = kEmptyCacheLevelInfo;
- continue;
- }
+static const CacheInfo kEmptyCacheInfo;
+
+// For newer Intel CPUs uses "CPUID, eax=0x00000004".
+// https://www.felixcloutier.com/x86/cpuid#input-eax-=-04h--returns-deterministic-cache-parameters-for-each-level
+// For newer AMD CPUs uses "CPUID, eax=0x8000001D"
+static void ParseCacheInfo(const int max_cpuid_leaf, uint32_t leaf_id,
+ CacheInfo* old_info) {
+ CacheInfo info = kEmptyCacheInfo;
+ for (int index = 0; info.size < CPU_FEATURES_MAX_CACHE_LEVEL; ++index) {
+ const Leaf leaf = SafeCpuIdEx(max_cpuid_leaf, leaf_id, index);
+ int cache_type_field = ExtractBitRange(leaf.eax, 4, 0);
+ CacheType cache_type;
+ if (cache_type_field == 0)
+ break;
+ else 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.
int level = ExtractBitRange(leaf.eax, 7, 5);
int line_size = ExtractBitRange(leaf.ebx, 11, 0) + 1;
int partitioning = ExtractBitRange(leaf.ebx, 21, 12) + 1;
int ways = ExtractBitRange(leaf.ebx, 31, 22) + 1;
int tlb_entries = leaf.ecx + 1;
- int cache_size = (ways * partitioning * line_size * (tlb_entries));
- info->levels[cache_id] = (CacheLevelInfo){.level = level,
+ int cache_size = ways * partitioning * line_size * tlb_entries;
+ info.levels[info.size] = (CacheLevelInfo){.level = level,
.cache_type = cache_type,
.cache_size = cache_size,
.ways = ways,
.line_size = line_size,
.tlb_entries = tlb_entries,
.partitioning = partitioning};
- info->size++;
- }
-}
-
-// Internal structure to hold the OS support for vector operations.
-// Avoid to recompute them since each call to cpuid is ~100 cycles.
-typedef struct {
- bool have_sse_via_os;
- bool have_sse_via_cpuid;
- bool have_avx;
- bool have_avx512;
- bool have_amx;
-} OsSupport;
-
-static const OsSupport kEmptyOsSupport;
-
-static OsSupport CheckOsSupport(const uint32_t max_cpuid_leaf) {
- const Leaf leaf_1 = SafeCpuId(max_cpuid_leaf, 1);
- const bool have_xsave = IsBitSet(leaf_1.ecx, 26);
- const bool have_osxsave = IsBitSet(leaf_1.ecx, 27);
- const bool have_xcr0 = have_xsave && have_osxsave;
-
- OsSupport os_support = kEmptyOsSupport;
-
- if (have_xcr0) {
- // AVX capable cpu will expose XCR0.
- const uint32_t xcr0_eax = GetXCR0Eax();
- os_support.have_sse_via_cpuid = HasXmmOsXSave(xcr0_eax);
- os_support.have_avx = HasYmmOsXSave(xcr0_eax);
- os_support.have_avx512 = HasZmmOsXSave(xcr0_eax);
- os_support.have_amx = HasTmmOsXSave(xcr0_eax);
- } else {
- // Atom based or older cpus need to ask the OS for sse support.
- os_support.have_sse_via_os = true;
- }
-
- return os_support;
-}
-
-#if defined(CPU_FEATURES_OS_WINDOWS)
-#if defined(CPU_FEATURES_MOCK_CPUID_X86)
-extern bool GetWindowsIsProcessorFeaturePresent(DWORD);
-#else // CPU_FEATURES_MOCK_CPUID_X86
-static bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) {
- return IsProcessorFeaturePresent(ProcessorFeature);
-}
-#endif
-#endif // CPU_FEATURES_OS_WINDOWS
-
-#if defined(CPU_FEATURES_OS_DARWIN)
-#if defined(CPU_FEATURES_MOCK_CPUID_X86)
-extern bool GetDarwinSysCtlByName(const char*);
-#else // CPU_FEATURES_MOCK_CPUID_X86
-static bool GetDarwinSysCtlByName(const char* name) {
- int enabled;
- size_t enabled_len = sizeof(enabled);
- const int failure = sysctlbyname(name, &enabled, &enabled_len, NULL, 0);
- return failure ? false : enabled;
-}
-#endif
-#endif // CPU_FEATURES_OS_DARWIN
-
-static void DetectSseViaOs(X86Features* features) {
-#if defined(CPU_FEATURES_OS_WINDOWS)
- // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent
- features->sse =
- GetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE);
- features->sse2 =
- GetWindowsIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE);
- features->sse3 =
- GetWindowsIsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE);
-#elif defined(CPU_FEATURES_OS_DARWIN)
- // Handling Darwin platform through sysctlbyname.
- features->sse = GetDarwinSysCtlByName("hw.optional.sse");
- features->sse2 = GetDarwinSysCtlByName("hw.optional.sse2");
- features->sse3 = GetDarwinSysCtlByName("hw.optional.sse3");
- features->ssse3 = GetDarwinSysCtlByName("hw.optional.supplementalsse3");
- features->sse4_1 = GetDarwinSysCtlByName("hw.optional.sse4_1");
- features->sse4_2 = GetDarwinSysCtlByName("hw.optional.sse4_2");
-#elif defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
- // Handling Linux platform through /proc/cpuinfo.
- const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
- if (fd >= 0) {
- StackLineReader reader;
- StackLineReader_Initialize(&reader, fd);
- for (;;) {
- const LineResult result = StackLineReader_NextLine(&reader);
- const StringView line = result.line;
- StringView key, value;
- if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
- if (CpuFeatures_StringView_IsEquals(key, str("flags"))) {
- features->sse = CpuFeatures_StringView_HasWord(value, "sse");
- features->sse2 = CpuFeatures_StringView_HasWord(value, "sse2");
- features->sse3 = CpuFeatures_StringView_HasWord(value, "sse3");
- features->ssse3 = CpuFeatures_StringView_HasWord(value, "ssse3");
- features->sse4_1 = CpuFeatures_StringView_HasWord(value, "sse4_1");
- features->sse4_2 = CpuFeatures_StringView_HasWord(value, "sse4_2");
- break;
- }
- }
- if (result.eof) break;
- }
- CpuFeatures_CloseFile(fd);
- }
-#else
-#error "Unsupported fallback detection of SSE OS support."
-#endif
-}
-
-// Reference https://en.wikipedia.org/wiki/CPUID.
-static void ParseCpuId(const uint32_t max_cpuid_leaf,
- const OsSupport os_support, X86Info* info) {
- const Leaf leaf_1 = SafeCpuId(max_cpuid_leaf, 1);
- const Leaf leaf_7 = SafeCpuId(max_cpuid_leaf, 7);
- const Leaf leaf_7_1 = SafeCpuIdEx(max_cpuid_leaf, 7, 1);
-
- const uint32_t family = ExtractBitRange(leaf_1.eax, 11, 8);
- const uint32_t extended_family = ExtractBitRange(leaf_1.eax, 27, 20);
- const uint32_t model = ExtractBitRange(leaf_1.eax, 7, 4);
- const uint32_t extended_model = ExtractBitRange(leaf_1.eax, 19, 16);
-
- X86Features* const features = &info->features;
-
- info->family = extended_family + family;
- info->model = (extended_model << 4) + model;
- info->stepping = ExtractBitRange(leaf_1.eax, 3, 0);
-
- features->fpu = IsBitSet(leaf_1.edx, 0);
- features->tsc = IsBitSet(leaf_1.edx, 4);
- features->cx8 = IsBitSet(leaf_1.edx, 8);
- features->clfsh = IsBitSet(leaf_1.edx, 19);
- features->mmx = IsBitSet(leaf_1.edx, 23);
- features->ss = IsBitSet(leaf_1.edx, 27);
- features->pclmulqdq = IsBitSet(leaf_1.ecx, 1);
- features->smx = IsBitSet(leaf_1.ecx, 6);
- features->cx16 = IsBitSet(leaf_1.ecx, 13);
- features->dca = IsBitSet(leaf_1.ecx, 18);
- features->movbe = IsBitSet(leaf_1.ecx, 22);
- features->popcnt = IsBitSet(leaf_1.ecx, 23);
- features->aes = IsBitSet(leaf_1.ecx, 25);
- features->f16c = IsBitSet(leaf_1.ecx, 29);
- features->rdrnd = IsBitSet(leaf_1.ecx, 30);
- features->sgx = IsBitSet(leaf_7.ebx, 2);
- features->bmi1 = IsBitSet(leaf_7.ebx, 3);
- features->hle = IsBitSet(leaf_7.ebx, 4);
- features->bmi2 = IsBitSet(leaf_7.ebx, 8);
- features->erms = IsBitSet(leaf_7.ebx, 9);
- features->rtm = IsBitSet(leaf_7.ebx, 11);
- features->rdseed = IsBitSet(leaf_7.ebx, 18);
- features->clflushopt = IsBitSet(leaf_7.ebx, 23);
- features->clwb = IsBitSet(leaf_7.ebx, 24);
- features->sha = IsBitSet(leaf_7.ebx, 29);
- features->vaes = IsBitSet(leaf_7.ecx, 9);
- features->vpclmulqdq = IsBitSet(leaf_7.ecx, 10);
-
- if (os_support.have_sse_via_os) {
- DetectSseViaOs(features);
- } else if (os_support.have_sse_via_cpuid) {
- features->sse = IsBitSet(leaf_1.edx, 25);
- features->sse2 = IsBitSet(leaf_1.edx, 26);
- features->sse3 = IsBitSet(leaf_1.ecx, 0);
- features->ssse3 = IsBitSet(leaf_1.ecx, 9);
- features->sse4_1 = IsBitSet(leaf_1.ecx, 19);
- features->sse4_2 = IsBitSet(leaf_1.ecx, 20);
- }
-
- if (os_support.have_avx) {
- features->fma3 = IsBitSet(leaf_1.ecx, 12);
- features->avx = IsBitSet(leaf_1.ecx, 28);
- features->avx2 = IsBitSet(leaf_7.ebx, 5);
- }
-
- if (os_support.have_avx512) {
- features->avx512f = IsBitSet(leaf_7.ebx, 16);
- features->avx512cd = IsBitSet(leaf_7.ebx, 28);
- features->avx512er = IsBitSet(leaf_7.ebx, 27);
- features->avx512pf = IsBitSet(leaf_7.ebx, 26);
- features->avx512bw = IsBitSet(leaf_7.ebx, 30);
- features->avx512dq = IsBitSet(leaf_7.ebx, 17);
- features->avx512vl = IsBitSet(leaf_7.ebx, 31);
- features->avx512ifma = IsBitSet(leaf_7.ebx, 21);
- features->avx512vbmi = IsBitSet(leaf_7.ecx, 1);
- features->avx512vbmi2 = IsBitSet(leaf_7.ecx, 6);
- features->avx512vnni = IsBitSet(leaf_7.ecx, 11);
- features->avx512bitalg = IsBitSet(leaf_7.ecx, 12);
- features->avx512vpopcntdq = IsBitSet(leaf_7.ecx, 14);
- features->avx512_4vnniw = IsBitSet(leaf_7.edx, 2);
- features->avx512_4vbmi2 = IsBitSet(leaf_7.edx, 3);
- features->avx512_second_fma = HasSecondFMA(info->model);
- features->avx512_4fmaps = IsBitSet(leaf_7.edx, 3);
- features->avx512_bf16 = IsBitSet(leaf_7_1.eax, 5);
- features->avx512_vp2intersect = IsBitSet(leaf_7.edx, 8);
- }
-
- if (os_support.have_amx) {
- features->amx_bf16 = IsBitSet(leaf_7.edx, 22);
- features->amx_tile = IsBitSet(leaf_7.edx, 24);
- features->amx_int8 = IsBitSet(leaf_7.edx, 25);
+ ++info.size;
}
-}
-
-// Reference
-// https://en.wikipedia.org/wiki/CPUID#EAX=80000000h:_Get_Highest_Extended_Function_Implemented.
-static void ParseExtraAMDCpuId(X86Info* info, OsSupport os_support) {
- const Leaf leaf_80000000 = CpuId(0x80000000);
- const uint32_t max_extended_cpuid_leaf = leaf_80000000.eax;
- const Leaf leaf_80000001 = SafeCpuId(max_extended_cpuid_leaf, 0x80000001);
-
- X86Features* const features = &info->features;
-
- if (os_support.have_sse_via_cpuid) {
- features->sse4a = IsBitSet(leaf_80000001.ecx, 6);
- }
-
- if (os_support.have_avx) {
- features->fma4 = IsBitSet(leaf_80000001.ecx, 16);
- }
-}
-
-static const X86Info kEmptyX86Info;
-static const CacheInfo kEmptyCacheInfo;
-
-X86Info GetX86Info(void) {
- X86Info info = kEmptyX86Info;
- const Leaf leaf_0 = CpuId(0);
- const bool is_intel = IsVendor(leaf_0, "GenuineIntel");
- const bool is_amd = IsVendor(leaf_0, "AuthenticAMD");
- SetVendor(leaf_0, info.vendor);
- if (is_intel || is_amd) {
- const uint32_t max_cpuid_leaf = leaf_0.eax;
- const OsSupport os_support = CheckOsSupport(max_cpuid_leaf);
- ParseCpuId(max_cpuid_leaf, os_support, &info);
- if (is_amd) {
- ParseExtraAMDCpuId(&info, os_support);
- }
- }
- return info;
+ // Override CacheInfo if we successfully extracted Deterministic Cache
+ // Parameters.
+ if (info.size > 0) *old_info = info;
}
CacheInfo GetX86CacheInfo(void) {
CacheInfo info = kEmptyCacheInfo;
- const Leaf leaf_0 = CpuId(0);
- const uint32_t max_cpuid_leaf = leaf_0.eax;
- if (IsVendor(leaf_0, "GenuineIntel")) {
- ParseLeaf2(max_cpuid_leaf, &info);
- ParseLeaf4(max_cpuid_leaf, &info);
- }
- return info;
-}
-
-#define CPUID(FAMILY, MODEL) ((((FAMILY)&0xFF) << 8) | ((MODEL)&0xFF))
-
-X86Microarchitecture GetX86Microarchitecture(const X86Info* info) {
- if (memcmp(info->vendor, "GenuineIntel", sizeof(info->vendor)) == 0) {
- switch (CPUID(info->family, info->model)) {
- case CPUID(0x06, 0x35):
- case CPUID(0x06, 0x36):
- // https://en.wikipedia.org/wiki/Bonnell_(microarchitecture)
- return INTEL_ATOM_BNL;
- case CPUID(0x06, 0x37):
- case CPUID(0x06, 0x4C):
- // https://en.wikipedia.org/wiki/Silvermont
- return INTEL_ATOM_SMT;
- case CPUID(0x06, 0x5C):
- // https://en.wikipedia.org/wiki/Goldmont
- return INTEL_ATOM_GMT;
- case CPUID(0x06, 0x0F):
- case CPUID(0x06, 0x16):
- // https://en.wikipedia.org/wiki/Intel_Core_(microarchitecture)
- return INTEL_CORE;
- case CPUID(0x06, 0x17):
- case CPUID(0x06, 0x1D):
- // https://en.wikipedia.org/wiki/Penryn_(microarchitecture)
- return INTEL_PNR;
- case CPUID(0x06, 0x1A):
- case CPUID(0x06, 0x1E):
- case CPUID(0x06, 0x1F):
- case CPUID(0x06, 0x2E):
- // https://en.wikipedia.org/wiki/Nehalem_(microarchitecture)
- return INTEL_NHM;
- case CPUID(0x06, 0x25):
- case CPUID(0x06, 0x2C):
- case CPUID(0x06, 0x2F):
- // https://en.wikipedia.org/wiki/Westmere_(microarchitecture)
- return INTEL_WSM;
- case CPUID(0x06, 0x2A):
- case CPUID(0x06, 0x2D):
- // https://en.wikipedia.org/wiki/Sandy_Bridge#Models_and_steppings
- return INTEL_SNB;
- case CPUID(0x06, 0x3A):
- case CPUID(0x06, 0x3E):
- // https://en.wikipedia.org/wiki/Ivy_Bridge_(microarchitecture)#Models_and_steppings
- return INTEL_IVB;
- case CPUID(0x06, 0x3C):
- case CPUID(0x06, 0x3F):
- case CPUID(0x06, 0x45):
- case CPUID(0x06, 0x46):
- // https://en.wikipedia.org/wiki/Haswell_(microarchitecture)
- return INTEL_HSW;
- case CPUID(0x06, 0x3D):
- case CPUID(0x06, 0x47):
- case CPUID(0x06, 0x4F):
- case CPUID(0x06, 0x56):
- // https://en.wikipedia.org/wiki/Broadwell_(microarchitecture)
- return INTEL_BDW;
- case CPUID(0x06, 0x4E):
- case CPUID(0x06, 0x55):
- case CPUID(0x06, 0x5E):
- // https://en.wikipedia.org/wiki/Skylake_(microarchitecture)
- return INTEL_SKL;
- case CPUID(0x06, 0x66):
- // https://en.wikipedia.org/wiki/Cannon_Lake_(microarchitecture)
- return INTEL_CNL;
- case CPUID(0x06, 0x7D): // client
- case CPUID(0x06, 0x7E): // client
- case CPUID(0x06, 0x9D): // NNP-I
- case CPUID(0x06, 0x6A): // server
- case CPUID(0x06, 0x6C): // server
- // https://en.wikipedia.org/wiki/Ice_Lake_(microprocessor)
- return INTEL_ICL;
- case CPUID(0x06, 0x8C):
- case CPUID(0x06, 0x8D):
- // https://en.wikipedia.org/wiki/Tiger_Lake_(microarchitecture)
- return INTEL_TGL;
- case CPUID(0x06, 0x8F):
- // https://en.wikipedia.org/wiki/Sapphire_Rapids
- return INTEL_SPR;
- case CPUID(0x06, 0x8E):
- switch (info->stepping) {
- case 9:
- return INTEL_KBL; // https://en.wikipedia.org/wiki/Kaby_Lake
- case 10:
- return INTEL_CFL; // https://en.wikipedia.org/wiki/Coffee_Lake
- case 11:
- return INTEL_WHL; // https://en.wikipedia.org/wiki/Whiskey_Lake_(microarchitecture)
- default:
- return X86_UNKNOWN;
- }
- case CPUID(0x06, 0x9E):
- if (info->stepping > 9) {
- // https://en.wikipedia.org/wiki/Coffee_Lake
- return INTEL_CFL;
- } else {
- // https://en.wikipedia.org/wiki/Kaby_Lake
- return INTEL_KBL;
- }
- default:
- return X86_UNKNOWN;
- }
- }
- if (memcmp(info->vendor, "AuthenticAMD", sizeof(info->vendor)) == 0) {
- switch (info->family) {
- // https://en.wikipedia.org/wiki/List_of_AMD_CPU_microarchitectures
- case 0x0F:
- return AMD_HAMMER;
- case 0x10:
- return AMD_K10;
- case 0x14:
- return AMD_BOBCAT;
- case 0x15:
- return AMD_BULLDOZER;
- case 0x16:
- return AMD_JAGUAR;
- case 0x17:
- return AMD_ZEN;
- default:
- return X86_UNKNOWN;
+ const Leaves leaves = ReadLeaves();
+ if (IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_GENUINE_INTEL) ||
+ IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_CENTAUR_HAULS) ||
+ IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_SHANGHAI)) {
+ ParseLeaf2(&leaves, &info);
+ ParseCacheInfo(leaves.max_cpuid_leaf, 4, &info);
+ } else if (IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_AUTHENTIC_AMD) ||
+ IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_HYGON_GENUINE)) {
+ // If CPUID Fn8000_0001_ECX[TopologyExtensions]==0
+ // then CPUID Fn8000_0001_E[D,C,B,A]X is reserved.
+ // https://www.amd.com/system/files/TechDocs/25481.pdf
+ if (IsBitSet(leaves.leaf_80000001.ecx, 22)) {
+ ParseCacheInfo(leaves.max_cpuid_leaf_ext, 0x8000001D, &info);
}
}
- return X86_UNKNOWN;
-}
-
-static void SetString(const uint32_t max_cpuid_ext_leaf, const uint32_t leaf_id,
- char* buffer) {
- const Leaf leaf = SafeCpuId(max_cpuid_ext_leaf, leaf_id);
- // We allow calling memcpy from SetString which is only called when requesting
- // X86BrandString.
- memcpy(buffer, &leaf, sizeof(Leaf));
-}
-
-void FillX86BrandString(char brand_string[49]) {
- const Leaf leaf_ext_0 = CpuId(0x80000000);
- const uint32_t max_cpuid_leaf_ext = leaf_ext_0.eax;
- SetString(max_cpuid_leaf_ext, 0x80000002, brand_string);
- SetString(max_cpuid_leaf_ext, 0x80000003, brand_string + 16);
- SetString(max_cpuid_leaf_ext, 0x80000004, brand_string + 32);
- brand_string[48] = '\0';
+ return info;
}
////////////////////////////////////////////////////////////////////////////////
-// Introspection functions
-
-int GetX86FeaturesEnumValue(const X86Features* features,
- X86FeaturesEnum value) {
- if (value >= X86_LAST_) return false;
- return kGetters[value](features);
-}
-
-const char* GetX86FeaturesEnumName(X86FeaturesEnum value) {
- if (value >= X86_LAST_) return "unknown_feature";
- return kCpuInfoFlags[value];
-}
-
-const char* GetX86MicroarchitectureName(X86Microarchitecture uarch) {
- switch (uarch) {
- case X86_UNKNOWN:
- return "X86_UNKNOWN";
- case INTEL_CORE:
- return "INTEL_CORE";
- case INTEL_PNR:
- return "INTEL_PNR";
- case INTEL_NHM:
- return "INTEL_NHM";
- case INTEL_ATOM_BNL:
- return "INTEL_ATOM_BNL";
- case INTEL_WSM:
- return "INTEL_WSM";
- case INTEL_SNB:
- return "INTEL_SNB";
- case INTEL_IVB:
- return "INTEL_IVB";
- case INTEL_ATOM_SMT:
- return "INTEL_ATOM_SMT";
- case INTEL_HSW:
- return "INTEL_HSW";
- case INTEL_BDW:
- return "INTEL_BDW";
- case INTEL_SKL:
- return "INTEL_SKL";
- case INTEL_ATOM_GMT:
- return "INTEL_ATOM_GMT";
- case INTEL_KBL:
- return "INTEL_KBL";
- case INTEL_CFL:
- return "INTEL_CFL";
- case INTEL_WHL:
- return "INTEL_WHL";
- case INTEL_CNL:
- return "INTEL_CNL";
- case INTEL_ICL:
- return "INTEL_ICL";
- case INTEL_TGL:
- return "INTEL_TGL";
- case INTEL_SPR:
- return "INTEL_SPR";
- case AMD_HAMMER:
- return "AMD_HAMMER";
- case AMD_K10:
- return "AMD_K10";
- case AMD_BOBCAT:
- return "AMD_BOBCAT";
- case AMD_BULLDOZER:
- return "AMD_BULLDOZER";
- case AMD_JAGUAR:
- return "AMD_JAGUAR";
- case AMD_ZEN:
- return "AMD_ZEN";
- }
- return "unknown microarchitecture";
+// Definitions for introspection.
+////////////////////////////////////////////////////////////////////////////////
+#define INTROSPECTION_TABLE \
+ LINE(X86_FPU, fpu, , , ) \
+ LINE(X86_TSC, tsc, , , ) \
+ LINE(X86_CX8, cx8, , , ) \
+ LINE(X86_CLFSH, clfsh, , , ) \
+ LINE(X86_MMX, mmx, , , ) \
+ LINE(X86_AES, aes, , , ) \
+ LINE(X86_ERMS, erms, , , ) \
+ LINE(X86_F16C, f16c, , , ) \
+ LINE(X86_FMA4, fma4, , , ) \
+ LINE(X86_FMA3, fma3, , , ) \
+ LINE(X86_VAES, vaes, , , ) \
+ LINE(X86_VPCLMULQDQ, vpclmulqdq, , , ) \
+ LINE(X86_BMI1, bmi1, , , ) \
+ LINE(X86_HLE, hle, , , ) \
+ LINE(X86_BMI2, bmi2, , , ) \
+ LINE(X86_RTM, rtm, , , ) \
+ LINE(X86_RDSEED, rdseed, , , ) \
+ LINE(X86_CLFLUSHOPT, clflushopt, , , ) \
+ LINE(X86_CLWB, clwb, , , ) \
+ LINE(X86_SSE, sse, , , ) \
+ LINE(X86_SSE2, sse2, , , ) \
+ LINE(X86_SSE3, sse3, , , ) \
+ LINE(X86_SSSE3, ssse3, , , ) \
+ LINE(X86_SSE4_1, sse4_1, , , ) \
+ LINE(X86_SSE4_2, sse4_2, , , ) \
+ LINE(X86_SSE4A, sse4a, , , ) \
+ LINE(X86_AVX, avx, , , ) \
+ LINE(X86_AVX2, avx2, , , ) \
+ LINE(X86_AVX512F, avx512f, , , ) \
+ LINE(X86_AVX512CD, avx512cd, , , ) \
+ LINE(X86_AVX512ER, avx512er, , , ) \
+ LINE(X86_AVX512PF, avx512pf, , , ) \
+ LINE(X86_AVX512BW, avx512bw, , , ) \
+ LINE(X86_AVX512DQ, avx512dq, , , ) \
+ LINE(X86_AVX512VL, avx512vl, , , ) \
+ LINE(X86_AVX512IFMA, avx512ifma, , , ) \
+ LINE(X86_AVX512VBMI, avx512vbmi, , , ) \
+ LINE(X86_AVX512VBMI2, avx512vbmi2, , , ) \
+ LINE(X86_AVX512VNNI, avx512vnni, , , ) \
+ LINE(X86_AVX512BITALG, avx512bitalg, , , ) \
+ LINE(X86_AVX512VPOPCNTDQ, avx512vpopcntdq, , , ) \
+ LINE(X86_AVX512_4VNNIW, avx512_4vnniw, , , ) \
+ LINE(X86_AVX512_4VBMI2, avx512_4vbmi2, , , ) \
+ LINE(X86_AVX512_SECOND_FMA, avx512_second_fma, , , ) \
+ LINE(X86_AVX512_4FMAPS, avx512_4fmaps, , , ) \
+ LINE(X86_AVX512_BF16, avx512_bf16, , , ) \
+ LINE(X86_AVX512_VP2INTERSECT, avx512_vp2intersect, , , ) \
+ LINE(X86_AMX_BF16, amx_bf16, , , ) \
+ LINE(X86_AMX_TILE, amx_tile, , , ) \
+ LINE(X86_AMX_INT8, amx_int8, , , ) \
+ LINE(X86_PCLMULQDQ, pclmulqdq, , , ) \
+ LINE(X86_SMX, smx, , , ) \
+ LINE(X86_SGX, sgx, , , ) \
+ LINE(X86_CX16, cx16, , , ) \
+ LINE(X86_SHA, sha, , , ) \
+ LINE(X86_POPCNT, popcnt, , , ) \
+ LINE(X86_MOVBE, movbe, , , ) \
+ LINE(X86_RDRND, rdrnd, , , ) \
+ LINE(X86_DCA, dca, , , ) \
+ LINE(X86_SS, ss, , , ) \
+ LINE(X86_ADX, adx, , , )
+#define INTROSPECTION_PREFIX X86
+#define INTROSPECTION_ENUM_PREFIX X86
+#include "define_introspection.inl"
+
+#define X86_MICROARCHITECTURE_NAMES \
+ LINE(X86_UNKNOWN) \
+ LINE(ZHAOXIN_ZHANGJIANG) \
+ LINE(ZHAOXIN_WUDAOKOU) \
+ LINE(ZHAOXIN_LUJIAZUI) \
+ LINE(ZHAOXIN_YONGFENG) \
+ LINE(INTEL_80486) \
+ LINE(INTEL_P5) \
+ LINE(INTEL_LAKEMONT) \
+ LINE(INTEL_CORE) \
+ LINE(INTEL_PNR) \
+ LINE(INTEL_NHM) \
+ LINE(INTEL_ATOM_BNL) \
+ LINE(INTEL_WSM) \
+ LINE(INTEL_SNB) \
+ LINE(INTEL_IVB) \
+ LINE(INTEL_ATOM_SMT) \
+ LINE(INTEL_HSW) \
+ LINE(INTEL_BDW) \
+ LINE(INTEL_SKL) \
+ LINE(INTEL_ATOM_GMT) \
+ LINE(INTEL_KBL) \
+ LINE(INTEL_CFL) \
+ LINE(INTEL_WHL) \
+ LINE(INTEL_CNL) \
+ LINE(INTEL_ICL) \
+ LINE(INTEL_TGL) \
+ LINE(INTEL_SPR) \
+ LINE(INTEL_ADL) \
+ LINE(INTEL_RCL) \
+ LINE(INTEL_KNIGHTS_M) \
+ LINE(INTEL_KNIGHTS_L) \
+ LINE(INTEL_KNIGHTS_F) \
+ LINE(INTEL_KNIGHTS_C) \
+ LINE(INTEL_NETBURST) \
+ LINE(AMD_HAMMER) \
+ LINE(AMD_K10) \
+ LINE(AMD_K11) \
+ LINE(AMD_K12) \
+ LINE(AMD_BOBCAT) \
+ LINE(AMD_PILEDRIVER) \
+ LINE(AMD_STREAMROLLER) \
+ LINE(AMD_EXCAVATOR) \
+ LINE(AMD_BULLDOZER) \
+ LINE(AMD_JAGUAR) \
+ LINE(AMD_PUMA) \
+ LINE(AMD_ZEN) \
+ LINE(AMD_ZEN_PLUS) \
+ LINE(AMD_ZEN2) \
+ LINE(AMD_ZEN3)
+
+const char* GetX86MicroarchitectureName(X86Microarchitecture value) {
+#define LINE(ENUM) [ENUM] = STRINGIZE(ENUM),
+ static const char* kMicroarchitectureNames[] = {X86_MICROARCHITECTURE_NAMES};
+#undef LINE
+ if (value >= X86_MICROARCHITECTURE_LAST_) return "unknown microarchitecture";
+ return kMicroarchitectureNames[value];
}
diff --git a/src/impl_x86_freebsd.c b/src/impl_x86_freebsd.c
new file mode 100644
index 0000000..ba6c6e3
--- /dev/null
+++ b/src/impl_x86_freebsd.c
@@ -0,0 +1,68 @@
+// Copyright 2017 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cpu_features_macros.h"
+
+#ifdef CPU_FEATURES_ARCH_X86
+#ifdef CPU_FEATURES_OS_FREEBSD
+
+#include "impl_x86__base_implementation.inl"
+
+static void OverrideOsPreserves(OsPreserves* os_preserves) {
+ (void)os_preserves;
+ // No override
+}
+
+#include "internal/filesystem.h"
+#include "internal/stack_line_reader.h"
+#include "internal/string_view.h"
+
+static void DetectFeaturesFromOs(X86Info* info, X86Features* features) {
+ (void)info;
+ // Handling FreeBSD platform through parsing /var/run/dmesg.boot.
+ const int fd = CpuFeatures_OpenFile("/var/run/dmesg.boot");
+ if (fd >= 0) {
+ StackLineReader reader;
+ StackLineReader_Initialize(&reader, fd);
+ for (bool stop = false; !stop;) {
+ const LineResult result = StackLineReader_NextLine(&reader);
+ if (result.eof) stop = true;
+ const StringView line = result.line;
+ if (!CpuFeatures_StringView_StartsWith(line, str(" Features"))) continue;
+ // Lines of interests are of the following form:
+ // " Features=0x1783fbff<PSE36,MMX,FXSR,SSE,SSE2,HTT>"
+ // We first extract the comma separated values between angle brackets.
+ StringView csv = result.line;
+ int index = CpuFeatures_StringView_IndexOfChar(csv, '<');
+ if (index >= 0) csv = CpuFeatures_StringView_PopFront(csv, index + 1);
+ if (csv.size > 0 && CpuFeatures_StringView_Back(csv) == '>')
+ csv = CpuFeatures_StringView_PopBack(csv, 1);
+ if (CpuFeatures_StringView_HasWord(csv, "SSE", ',')) features->sse = true;
+ if (CpuFeatures_StringView_HasWord(csv, "SSE2", ','))
+ features->sse2 = true;
+ if (CpuFeatures_StringView_HasWord(csv, "SSE3", ','))
+ features->sse3 = true;
+ if (CpuFeatures_StringView_HasWord(csv, "SSSE3", ','))
+ features->ssse3 = true;
+ if (CpuFeatures_StringView_HasWord(csv, "SSE4.1", ','))
+ features->sse4_1 = true;
+ if (CpuFeatures_StringView_HasWord(csv, "SSE4.2", ','))
+ features->sse4_2 = true;
+ }
+ CpuFeatures_CloseFile(fd);
+ }
+}
+
+#endif // CPU_FEATURES_OS_FREEBSD
+#endif // CPU_FEATURES_ARCH_X86
diff --git a/src/impl_x86_linux_or_android.c b/src/impl_x86_linux_or_android.c
new file mode 100644
index 0000000..a4d07f3
--- /dev/null
+++ b/src/impl_x86_linux_or_android.c
@@ -0,0 +1,58 @@
+// Copyright 2017 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cpu_features_macros.h"
+
+#ifdef CPU_FEATURES_ARCH_X86
+#if defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
+
+#include "impl_x86__base_implementation.inl"
+
+static void OverrideOsPreserves(OsPreserves* os_preserves) {
+ (void)os_preserves;
+ // No override
+}
+
+#include "internal/filesystem.h"
+#include "internal/stack_line_reader.h"
+#include "internal/string_view.h"
+static void DetectFeaturesFromOs(X86Info* info, X86Features* features) {
+ (void)info;
+ // Handling Linux platform through /proc/cpuinfo.
+ const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
+ if (fd >= 0) {
+ StackLineReader reader;
+ StackLineReader_Initialize(&reader, fd);
+ for (bool stop = false; !stop;) {
+ const LineResult result = StackLineReader_NextLine(&reader);
+ if (result.eof) stop = true;
+ const StringView line = result.line;
+ StringView key, value;
+ if (!CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value))
+ continue;
+ if (!CpuFeatures_StringView_IsEquals(key, str("flags"))) continue;
+ features->sse = CpuFeatures_StringView_HasWord(value, "sse", ' ');
+ features->sse2 = CpuFeatures_StringView_HasWord(value, "sse2", ' ');
+ features->sse3 = CpuFeatures_StringView_HasWord(value, "pni", ' ');
+ features->ssse3 = CpuFeatures_StringView_HasWord(value, "ssse3", ' ');
+ features->sse4_1 = CpuFeatures_StringView_HasWord(value, "sse4_1", ' ');
+ features->sse4_2 = CpuFeatures_StringView_HasWord(value, "sse4_2", ' ');
+ break;
+ }
+ CpuFeatures_CloseFile(fd);
+ }
+}
+
+#endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
+#endif // CPU_FEATURES_ARCH_X86
diff --git a/src/impl_x86_macos.c b/src/impl_x86_macos.c
new file mode 100644
index 0000000..e5a5c35
--- /dev/null
+++ b/src/impl_x86_macos.c
@@ -0,0 +1,57 @@
+// Copyright 2017 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cpu_features_macros.h"
+
+#ifdef CPU_FEATURES_ARCH_X86
+#ifdef CPU_FEATURES_OS_MACOS
+
+#include "impl_x86__base_implementation.inl"
+
+#if !defined(HAVE_SYSCTLBYNAME)
+#error "Darwin needs support for sysctlbyname"
+#endif
+#include <sys/sysctl.h>
+
+#if defined(CPU_FEATURES_MOCK_CPUID_X86)
+extern bool GetDarwinSysCtlByName(const char*);
+#else // CPU_FEATURES_MOCK_CPUID_X86
+static bool GetDarwinSysCtlByName(const char* name) {
+ int enabled;
+ size_t enabled_len = sizeof(enabled);
+ const int failure = sysctlbyname(name, &enabled, &enabled_len, NULL, 0);
+ return failure ? false : enabled;
+}
+#endif
+
+static void OverrideOsPreserves(OsPreserves* os_preserves) {
+ // On Darwin AVX512 support is On-demand.
+ // We have to query the OS instead of querying the Zmm save/restore state.
+ // https://github.com/apple/darwin-xnu/blob/8f02f2a044b9bb1ad951987ef5bab20ec9486310/osfmk/i386/fpu.c#L173-L199
+ os_preserves->avx512_registers = GetDarwinSysCtlByName("hw.optional.avx512f");
+}
+
+static void DetectFeaturesFromOs(X86Info* info, X86Features* features) {
+ (void)info;
+ // Handling Darwin platform through sysctlbyname.
+ features->sse = GetDarwinSysCtlByName("hw.optional.sse");
+ features->sse2 = GetDarwinSysCtlByName("hw.optional.sse2");
+ features->sse3 = GetDarwinSysCtlByName("hw.optional.sse3");
+ features->ssse3 = GetDarwinSysCtlByName("hw.optional.supplementalsse3");
+ features->sse4_1 = GetDarwinSysCtlByName("hw.optional.sse4_1");
+ features->sse4_2 = GetDarwinSysCtlByName("hw.optional.sse4_2");
+}
+
+#endif // CPU_FEATURES_OS_MACOS
+#endif // CPU_FEATURES_ARCH_X86
diff --git a/src/impl_x86_windows.c b/src/impl_x86_windows.c
new file mode 100644
index 0000000..0b330d0
--- /dev/null
+++ b/src/impl_x86_windows.c
@@ -0,0 +1,58 @@
+// Copyright 2017 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cpu_features_macros.h"
+
+#ifdef CPU_FEATURES_ARCH_X86
+#ifdef CPU_FEATURES_OS_WINDOWS
+
+#include "impl_x86__base_implementation.inl"
+
+static void OverrideOsPreserves(OsPreserves* os_preserves) {
+ (void)os_preserves;
+ // No override
+}
+
+#include <windows.h> // IsProcessorFeaturePresent
+
+#if defined(CPU_FEATURES_MOCK_CPUID_X86)
+extern bool GetWindowsIsProcessorFeaturePresent(DWORD);
+#else // CPU_FEATURES_MOCK_CPUID_X86
+static bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) {
+ return IsProcessorFeaturePresent(ProcessorFeature);
+}
+#endif
+
+static void DetectFeaturesFromOs(X86Info* info, X86Features* features) {
+ // Handling Windows platform through IsProcessorFeaturePresent.
+ // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent
+ features->sse =
+ GetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE);
+ features->sse2 =
+ GetWindowsIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE);
+ features->sse3 =
+ GetWindowsIsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE);
+
+// 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
+}
+
+#endif // CPU_FEATURES_OS_WINDOWS
+#endif // CPU_FEATURES_ARCH_X86
diff --git a/src/string_view.c b/src/string_view.c
index dc3158f..2cac9da 100644
--- a/src/string_view.c
+++ b/src/string_view.c
@@ -16,11 +16,20 @@
#include <assert.h>
#include <ctype.h>
-#include <string.h>
+
+#include "copy.inl"
+#include "equals.inl"
+
+static const char* CpuFeatures_memchr(const char* const ptr, const size_t size,
+ const char c) {
+ for (size_t i = 0; ptr && ptr[i] != '\0' && i < size; ++i)
+ if (ptr[i] == c) return ptr + i;
+ return NULL;
+}
int CpuFeatures_StringView_IndexOfChar(const StringView view, char c) {
if (view.ptr && view.size) {
- const char* const found = (const char*)memchr(view.ptr, c, view.size);
+ const char* const found = CpuFeatures_memchr(view.ptr, view.size, c);
if (found) {
return (int)(found - view.ptr);
}
@@ -48,14 +57,14 @@ int CpuFeatures_StringView_IndexOf(const StringView view,
bool CpuFeatures_StringView_IsEquals(const StringView a, const StringView b) {
if (a.size == b.size) {
- return a.ptr == b.ptr || memcmp(a.ptr, b.ptr, b.size) == 0;
+ return a.ptr == b.ptr || equals(a.ptr, b.ptr, b.size);
}
return false;
}
bool CpuFeatures_StringView_StartsWith(const StringView a, const StringView b) {
return a.ptr && b.ptr && b.size && a.size >= b.size
- ? memcmp(a.ptr, b.ptr, b.size) == 0
+ ? equals(a.ptr, b.ptr, b.size)
: false;
}
@@ -138,13 +147,14 @@ void CpuFeatures_StringView_CopyString(const StringView src, char* dst,
const size_t max_copy_size = dst_size - 1;
const size_t copy_size =
src.size > max_copy_size ? max_copy_size : src.size;
- memcpy(dst, src.ptr, copy_size);
+ copy(dst, src.ptr, copy_size);
dst[copy_size] = '\0';
}
}
bool CpuFeatures_StringView_HasWord(const StringView line,
- const char* const word_str) {
+ const char* const word_str,
+ const char separator) {
const StringView word = str(word_str);
StringView remainder = line;
for (;;) {
@@ -157,9 +167,9 @@ bool CpuFeatures_StringView_HasWord(const StringView line,
const StringView after =
CpuFeatures_StringView_PopFront(line, index_of_word + word.size);
const bool valid_before =
- before.size == 0 || CpuFeatures_StringView_Back(before) == ' ';
+ before.size == 0 || CpuFeatures_StringView_Back(before) == separator;
const bool valid_after =
- after.size == 0 || CpuFeatures_StringView_Front(after) == ' ';
+ after.size == 0 || CpuFeatures_StringView_Front(after) == separator;
if (valid_before && valid_after) return true;
remainder =
CpuFeatures_StringView_PopFront(remainder, index_of_word + word.size);
diff --git a/src/utils/list_cpu_features.c b/src/utils/list_cpu_features.c
index c80ffc5..0b4eb7a 100644
--- a/src/utils/list_cpu_features.c
+++ b/src/utils/list_cpu_features.c
@@ -340,6 +340,7 @@ static Node* GetCacheTypeString(CacheType cache_type) {
case CPU_FEATURE_CACHE_PREFETCH:
return CreateConstantString("prefetch");
}
+ CPU_FEATURES_UNREACHABLE();
}
static void AddCacheInfo(Node* root, const CacheInfo* cache_info) {
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index c10e617..8e8f72a 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -47,7 +47,13 @@ add_test(NAME stack_line_reader_test COMMAND stack_line_reader_test)
##------------------------------------------------------------------------------
## cpuinfo_x86_test
if(PROCESSOR_IS_X86)
- add_executable(cpuinfo_x86_test cpuinfo_x86_test.cc ../src/cpuinfo_x86.c)
+ add_executable(cpuinfo_x86_test
+ cpuinfo_x86_test.cc
+ ../src/impl_x86_freebsd.c
+ ../src/impl_x86_linux_or_android.c
+ ../src/impl_x86_macos.c
+ ../src/impl_x86_windows.c
+ )
target_compile_definitions(cpuinfo_x86_test PUBLIC CPU_FEATURES_MOCK_CPUID_X86)
if(APPLE)
target_compile_definitions(cpuinfo_x86_test PRIVATE HAVE_SYSCTLBYNAME)
@@ -58,28 +64,28 @@ endif()
##------------------------------------------------------------------------------
## cpuinfo_arm_test
if(PROCESSOR_IS_ARM)
- add_executable(cpuinfo_arm_test cpuinfo_arm_test.cc ../src/cpuinfo_arm.c)
+ add_executable(cpuinfo_arm_test cpuinfo_arm_test.cc ../src/impl_arm_linux_or_android.c)
target_link_libraries(cpuinfo_arm_test all_libraries)
add_test(NAME cpuinfo_arm_test COMMAND cpuinfo_arm_test)
endif()
##------------------------------------------------------------------------------
## cpuinfo_aarch64_test
if(PROCESSOR_IS_AARCH64)
- add_executable(cpuinfo_aarch64_test cpuinfo_aarch64_test.cc ../src/cpuinfo_aarch64.c)
+ add_executable(cpuinfo_aarch64_test cpuinfo_aarch64_test.cc ../src/impl_aarch64_linux_or_android.c)
target_link_libraries(cpuinfo_aarch64_test all_libraries)
add_test(NAME cpuinfo_aarch64_test COMMAND cpuinfo_aarch64_test)
endif()
##------------------------------------------------------------------------------
## cpuinfo_mips_test
if(PROCESSOR_IS_MIPS)
- add_executable(cpuinfo_mips_test cpuinfo_mips_test.cc ../src/cpuinfo_mips.c)
+ add_executable(cpuinfo_mips_test cpuinfo_mips_test.cc ../src/impl_mips_linux_or_android.c)
target_link_libraries(cpuinfo_mips_test all_libraries)
add_test(NAME cpuinfo_mips_test COMMAND cpuinfo_mips_test)
endif()
##------------------------------------------------------------------------------
## cpuinfo_ppc_test
if(PROCESSOR_IS_POWER)
- add_executable(cpuinfo_ppc_test cpuinfo_ppc_test.cc ../src/cpuinfo_ppc.c)
+ add_executable(cpuinfo_ppc_test cpuinfo_ppc_test.cc ../src/impl_ppc_linux.c)
target_link_libraries(cpuinfo_ppc_test all_libraries)
add_test(NAME cpuinfo_ppc_test COMMAND cpuinfo_ppc_test)
endif()
diff --git a/test/cpuinfo_aarch64_test.cc b/test/cpuinfo_aarch64_test.cc
index 5afaaa8..04b6143 100644
--- a/test/cpuinfo_aarch64_test.cc
+++ b/test/cpuinfo_aarch64_test.cc
@@ -24,6 +24,7 @@ namespace {
void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); }
TEST(CpuinfoAarch64Test, FromHardwareCap) {
+ ResetHwcaps();
SetHardwareCapabilities(AARCH64_HWCAP_FP | AARCH64_HWCAP_AES, 0);
GetEmptyFilesystem(); // disabling /proc/cpuinfo
const auto info = GetAarch64Info();
@@ -62,6 +63,7 @@ TEST(CpuinfoAarch64Test, FromHardwareCap) {
}
TEST(CpuinfoAarch64Test, FromHardwareCap2) {
+ ResetHwcaps();
SetHardwareCapabilities(AARCH64_HWCAP_FP,
AARCH64_HWCAP2_SVE2 | AARCH64_HWCAP2_BTI);
GetEmptyFilesystem(); // disabling /proc/cpuinfo
@@ -90,7 +92,7 @@ TEST(CpuinfoAarch64Test, FromHardwareCap2) {
}
TEST(CpuinfoAarch64Test, ARMCortexA53) {
- DisableHardwareCapabilities();
+ ResetHwcaps();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo",
R"(Processor : AArch64 Processor rev 3 (aarch64)
@@ -165,6 +167,7 @@ CPU revision : 3)");
EXPECT_FALSE(info.features.dgh);
EXPECT_FALSE(info.features.rng);
EXPECT_FALSE(info.features.bti);
+ EXPECT_FALSE(info.features.mte);
}
} // namespace
diff --git a/test/cpuinfo_arm_test.cc b/test/cpuinfo_arm_test.cc
index e0b08a4..ad7f4e8 100644
--- a/test/cpuinfo_arm_test.cc
+++ b/test/cpuinfo_arm_test.cc
@@ -21,9 +21,8 @@
namespace cpu_features {
namespace {
-void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); }
-
TEST(CpuinfoArmTest, FromHardwareCap) {
+ ResetHwcaps();
SetHardwareCapabilities(ARM_HWCAP_NEON, ARM_HWCAP2_AES | ARM_HWCAP2_CRC32);
GetEmptyFilesystem(); // disabling /proc/cpuinfo
const auto info = GetArmInfo();
@@ -52,7 +51,7 @@ TEST(CpuinfoArmTest, FromHardwareCap) {
}
TEST(CpuinfoArmTest, ODroidFromCpuInfo) {
- DisableHardwareCapabilities();
+ ResetHwcaps();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo", R"(processor : 0
model name : ARMv7 Processor rev 3 (v71)
@@ -101,7 +100,7 @@ CPU revision : 3)");
// Linux test-case
TEST(CpuinfoArmTest, RaspberryPiZeroFromCpuInfo) {
- DisableHardwareCapabilities();
+ ResetHwcaps();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo", R"(processor : 0
model name : ARMv6-compatible processor rev 7 (v6l)
@@ -153,7 +152,7 @@ Serial : 000000006cd946f3)");
}
TEST(CpuinfoArmTest, MarvellArmadaFromCpuInfo) {
- DisableHardwareCapabilities();
+ ResetHwcaps();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo", R"(processor : 0
model name : ARMv7 Processor rev 1 (v7l)
@@ -217,7 +216,7 @@ Serial : 0000000000000000)");
// Android test-case
// http://code.google.com/p/android/issues/detail?id=10812
TEST(CpuinfoArmTest, InvalidArmv7) {
- DisableHardwareCapabilities();
+ ResetHwcaps();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo",
R"(Processor : ARMv6-compatible processor rev 6 (v6l)
@@ -267,6 +266,7 @@ Serial : 33323613546d00ec )");
// Android test-case
// https://crbug.com/341598.
TEST(CpuinfoArmTest, InvalidNeon) {
+ ResetHwcaps();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo",
R"(Processor: ARMv7 Processory rev 0 (v71)
@@ -294,7 +294,7 @@ Serial: 00001e030000354e)");
// The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report IDIV
// support.
TEST(CpuinfoArmTest, Nexus4_0x510006f2) {
- DisableHardwareCapabilities();
+ ResetHwcaps();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo",
R"(CPU implementer : 0x51
@@ -312,7 +312,7 @@ CPU revision : 2)");
// The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report IDIV
// support.
TEST(CpuinfoArmTest, Nexus4_0x510006f3) {
- DisableHardwareCapabilities();
+ ResetHwcaps();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo",
R"(CPU implementer : 0x51
@@ -327,11 +327,29 @@ CPU revision : 3)");
EXPECT_EQ(GetArmCpuId(&info), 0x510006f3);
}
+// The 2013 Nexus 7 (Qualcomm Krait) kernel configuration forgets to report IDIV
+// support.
+TEST(CpuinfoArmTest, Nexus7_2013_0x511006f0) {
+ ResetHwcaps();
+ auto& fs = GetEmptyFilesystem();
+ fs.CreateFile("/proc/cpuinfo",
+ R"(CPU implementer : 0x51
+CPU architecture: 7
+CPU variant : 0x1
+CPU part : 0x06f
+CPU revision : 0)");
+ const auto info = GetArmInfo();
+ EXPECT_TRUE(info.features.idiva);
+ EXPECT_TRUE(info.features.idivt);
+
+ EXPECT_EQ(GetArmCpuId(&info), 0x511006f0);
+}
+
// The emulator-specific Android 4.2 kernel fails to report support for the
// 32-bit ARM IDIV instruction. Technically, this is a feature of the virtual
// CPU implemented by the emulator.
TEST(CpuinfoArmTest, EmulatorSpecificIdiv) {
- DisableHardwareCapabilities();
+ ResetHwcaps();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo",
R"(Processor : ARMv7 Processor rev 0 (v7l)
diff --git a/test/cpuinfo_mips_test.cc b/test/cpuinfo_mips_test.cc
index d734058..a01624a 100644
--- a/test/cpuinfo_mips_test.cc
+++ b/test/cpuinfo_mips_test.cc
@@ -24,9 +24,8 @@ namespace cpu_features {
namespace {
-void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); }
-
TEST(CpuinfoMipsTest, FromHardwareCapBoth) {
+ ResetHwcaps();
SetHardwareCapabilities(MIPS_HWCAP_MSA | MIPS_HWCAP_R6, 0);
GetEmptyFilesystem(); // disabling /proc/cpuinfo
const auto info = GetMipsInfo();
@@ -36,6 +35,7 @@ TEST(CpuinfoMipsTest, FromHardwareCapBoth) {
}
TEST(CpuinfoMipsTest, FromHardwareCapOnlyOne) {
+ ResetHwcaps();
SetHardwareCapabilities(MIPS_HWCAP_MSA, 0);
GetEmptyFilesystem(); // disabling /proc/cpuinfo
const auto info = GetMipsInfo();
@@ -44,7 +44,7 @@ TEST(CpuinfoMipsTest, FromHardwareCapOnlyOne) {
}
TEST(CpuinfoMipsTest, Ci40) {
- DisableHardwareCapabilities();
+ ResetHwcaps();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo", R"(system type : IMG Pistachio SoC (B0)
machine : IMG Marduk – Ci40 with cc2520
@@ -72,7 +72,7 @@ VPE : 0
}
TEST(CpuinfoMipsTest, AR7161) {
- DisableHardwareCapabilities();
+ ResetHwcaps();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo",
R"(system type : Atheros AR7161 rev 2
@@ -98,7 +98,7 @@ VCEI exceptions : not available
}
TEST(CpuinfoMipsTest, Goldfish) {
- DisableHardwareCapabilities();
+ ResetHwcaps();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo", R"(system type : MIPS-Goldfish
Hardware : goldfish
diff --git a/test/cpuinfo_ppc_test.cc b/test/cpuinfo_ppc_test.cc
index 8f0cb65..b43a7c8 100644
--- a/test/cpuinfo_ppc_test.cc
+++ b/test/cpuinfo_ppc_test.cc
@@ -22,9 +22,8 @@
namespace cpu_features {
namespace {
-void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); }
-
TEST(CpustringsPPCTest, FromHardwareCap) {
+ ResetHwcaps();
SetHardwareCapabilities(PPC_FEATURE_HAS_FPU | PPC_FEATURE_HAS_VSX,
PPC_FEATURE2_ARCH_3_00);
GetEmptyFilesystem(); // disabling /proc/cpuinfo
@@ -40,7 +39,7 @@ TEST(CpustringsPPCTest, FromHardwareCap) {
}
TEST(CpustringsPPCTest, Blade) {
- DisableHardwareCapabilities();
+ ResetHwcaps();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo",
R"(processor : 14
@@ -57,7 +56,8 @@ timebase : 512000000
platform : pSeries
model : IBM,8406-70Y
machine : CHRP IBM,8406-70Y)");
- SetPlatformTypes("power7", "power8");
+ SetPlatformPointer("power7");
+ SetBasePlatformPointer("power8");
const auto strings = GetPPCPlatformStrings();
ASSERT_STREQ(strings.platform, "pSeries");
ASSERT_STREQ(strings.model, "IBM,8406-70Y");
@@ -68,7 +68,7 @@ machine : CHRP IBM,8406-70Y)");
}
TEST(CpustringsPPCTest, Firestone) {
- DisableHardwareCapabilities();
+ ResetHwcaps();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo",
R"(processor : 126
@@ -94,7 +94,7 @@ firmware : OPAL v3)");
}
TEST(CpustringsPPCTest, w8) {
- DisableHardwareCapabilities();
+ ResetHwcaps();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo",
R"(processor : 143
diff --git a/test/cpuinfo_x86_test.cc b/test/cpuinfo_x86_test.cc
index 636d0f9..56243b9 100644
--- a/test/cpuinfo_x86_test.cc
+++ b/test/cpuinfo_x86_test.cc
@@ -48,7 +48,7 @@ class FakeCpu {
xcr0_eax_ = os_backups_extended_registers ? -1 : 0;
}
-#if defined(CPU_FEATURES_OS_DARWIN)
+#if defined(CPU_FEATURES_OS_MACOS)
bool GetDarwinSysCtlByName(std::string name) const {
return darwin_sysctlbyname_.count(name);
}
@@ -56,7 +56,7 @@ class FakeCpu {
void SetDarwinSysCtlByName(std::string name) {
darwin_sysctlbyname_.insert(name);
}
-#endif // CPU_FEATURES_OS_DARWIN
+#endif // CPU_FEATURES_OS_MACOS
#if defined(CPU_FEATURES_OS_WINDOWS)
bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) {
@@ -70,32 +70,37 @@ class FakeCpu {
private:
std::map<std::pair<uint32_t, int>, Leaf> cpuid_leaves_;
-#if defined(CPU_FEATURES_OS_DARWIN)
+#if defined(CPU_FEATURES_OS_MACOS)
std::set<std::string> darwin_sysctlbyname_;
-#endif // CPU_FEATURES_OS_DARWIN
+#endif // CPU_FEATURES_OS_MACOS
#if defined(CPU_FEATURES_OS_WINDOWS)
std::set<DWORD> windows_isprocessorfeaturepresent_;
#endif // CPU_FEATURES_OS_WINDOWS
uint32_t xcr0_eax_;
};
-FakeCpu* g_fake_cpu = nullptr;
+static FakeCpu* g_fake_cpu_instance = nullptr;
+
+static FakeCpu& cpu() {
+ assert(g_fake_cpu_instance != nullptr);
+ return *g_fake_cpu_instance;
+}
extern "C" Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx) {
- return g_fake_cpu->GetCpuidLeaf(leaf_id, ecx);
+ return cpu().GetCpuidLeaf(leaf_id, ecx);
}
-extern "C" uint32_t GetXCR0Eax(void) { return g_fake_cpu->GetXCR0Eax(); }
+extern "C" uint32_t GetXCR0Eax(void) { return cpu().GetXCR0Eax(); }
-#if defined(CPU_FEATURES_OS_DARWIN)
+#if defined(CPU_FEATURES_OS_MACOS)
extern "C" bool GetDarwinSysCtlByName(const char* name) {
- return g_fake_cpu->GetDarwinSysCtlByName(name);
+ return cpu().GetDarwinSysCtlByName(name);
}
-#endif // CPU_FEATURES_OS_DARWIN
+#endif // CPU_FEATURES_OS_MACOS
#if defined(CPU_FEATURES_OS_WINDOWS)
extern "C" bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) {
- return g_fake_cpu->GetWindowsIsProcessorFeaturePresent(ProcessorFeature);
+ return cpu().GetWindowsIsProcessorFeaturePresent(ProcessorFeature);
}
#endif // CPU_FEATURES_OS_WINDOWS
@@ -103,13 +108,19 @@ namespace {
class CpuidX86Test : public ::testing::Test {
protected:
- void SetUp() override { g_fake_cpu = new FakeCpu(); }
- void TearDown() override { delete g_fake_cpu; }
+ void SetUp() override {
+ assert(g_fake_cpu_instance == nullptr);
+ g_fake_cpu_instance = new FakeCpu();
+ }
+ void TearDown() override {
+ delete g_fake_cpu_instance;
+ g_fake_cpu_instance = nullptr;
+ }
};
TEST_F(CpuidX86Test, SandyBridge) {
- g_fake_cpu->SetOsBackupsExtendedRegisters(true);
- g_fake_cpu->SetLeaves({
+ cpu().SetOsBackupsExtendedRegisters(true);
+ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
@@ -148,28 +159,30 @@ TEST_F(CpuidX86Test, SandyBridge) {
EXPECT_TRUE(features.popcnt);
EXPECT_FALSE(features.movbe);
EXPECT_FALSE(features.rdrnd);
+ EXPECT_FALSE(features.adx);
}
+const int UNDEF = -1;
const int KiB = 1024;
const int MiB = 1024 * KiB;
TEST_F(CpuidX86Test, SandyBridgeTestOsSupport) {
- g_fake_cpu->SetLeaves({
+ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
});
// avx is disabled if os does not support backing up ymm registers.
- g_fake_cpu->SetOsBackupsExtendedRegisters(false);
+ cpu().SetOsBackupsExtendedRegisters(false);
EXPECT_FALSE(GetX86Info().features.avx);
// avx is disabled if os does not support backing up ymm registers.
- g_fake_cpu->SetOsBackupsExtendedRegisters(true);
+ cpu().SetOsBackupsExtendedRegisters(true);
EXPECT_TRUE(GetX86Info().features.avx);
}
TEST_F(CpuidX86Test, SkyLake) {
- g_fake_cpu->SetOsBackupsExtendedRegisters(true);
- g_fake_cpu->SetLeaves({
+ cpu().SetOsBackupsExtendedRegisters(true);
+ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
@@ -183,7 +196,7 @@ TEST_F(CpuidX86Test, SkyLake) {
}
TEST_F(CpuidX86Test, Branding) {
- g_fake_cpu->SetLeaves({
+ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
@@ -199,7 +212,7 @@ TEST_F(CpuidX86Test, Branding) {
}
TEST_F(CpuidX86Test, KabyLakeCache) {
- g_fake_cpu->SetLeaves({
+ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
{{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}},
@@ -248,7 +261,7 @@ TEST_F(CpuidX86Test, KabyLakeCache) {
}
TEST_F(CpuidX86Test, HSWCache) {
- g_fake_cpu->SetLeaves({
+ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
{{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}},
@@ -296,9 +309,226 @@ TEST_F(CpuidX86Test, HSWCache) {
EXPECT_EQ(info.levels[3].partitioning, 1);
}
+// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0200F30_K11_Griffin_CPUID.txt
+TEST_F(CpuidX86Test, AMD_K11_GRIFFIN) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x00000001, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x00000001, 0}, Leaf{0x00200F30, 0x00020800, 0x00002001, 0x178BFBFF}},
+ {{0x80000000, 0}, Leaf{0x8000001A, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x80000001, 0}, Leaf{0x00200F30, 0x20000000, 0x0000131F, 0xEBD3FBFF}},
+ });
+ const auto info = GetX86Info();
+
+ EXPECT_STREQ(info.vendor, "AuthenticAMD");
+ EXPECT_EQ(info.family, 0x11);
+ EXPECT_EQ(info.model, 0x03);
+ EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_K11);
+}
+
+// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0300F10_K12_Llano_CPUID.txt
+TEST_F(CpuidX86Test, AMD_K12_LLANO) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x00000006, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x00000001, 0}, Leaf{0x00300F10, 0x00040800, 0x00802009, 0x178BFBFF}},
+ {{0x80000000, 0}, Leaf{0x8000001B, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x80000001, 0}, Leaf{0x00300F10, 0x20002B31, 0x000037FF, 0xEFD3FBFF}},
+ });
+ const auto info = GetX86Info();
+
+ EXPECT_STREQ(info.vendor, "AuthenticAMD");
+ EXPECT_EQ(info.family, 0x12);
+ EXPECT_EQ(info.model, 0x01);
+ EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_K12);
+}
+
+// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0500F01_K14_Bobcat_CPUID.txt
+TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F01) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x00000006, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x00000001, 0}, Leaf{0x00500F01, 0x00020800, 0x00802209, 0x178BFBFF}},
+ {{0x80000000, 0}, Leaf{0x8000001B, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x80000001, 0}, Leaf{0x00500F01, 0x00000000, 0x000035FF, 0x2FD3FBFF}},
+ });
+ const auto info = GetX86Info();
+
+ EXPECT_STREQ(info.vendor, "AuthenticAMD");
+ EXPECT_EQ(info.family, 0x14);
+ EXPECT_EQ(info.model, 0x00);
+ EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_BOBCAT);
+}
+
+// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0500F10_K14_Bobcat_CPUID.txt
+TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F10) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x00000006, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x00000001, 0}, Leaf{0x00500F10, 0x00020800, 0x00802209, 0x178BFBFF}},
+ {{0x00000002, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+ {{0x00000003, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+ {{0x00000005, 0}, Leaf{0x00000040, 0x00000040, 0x00000003, 0x00000000}},
+ {{0x00000006, 0}, Leaf{0x00000000, 0x00000000, 0x00000001, 0x00000000}},
+ {{0x80000000, 0}, Leaf{0x8000001B, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x80000001, 0}, Leaf{0x00500F10, 0x00001242, 0x000035FF, 0x2FD3FBFF}},
+ {{0x80000002, 0}, Leaf{0x20444D41, 0x35332D45, 0x72502030, 0x7365636F}},
+ {{0x80000003, 0}, Leaf{0x00726F73, 0x00000000, 0x00000000, 0x00000000}},
+ {{0x80000004, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+ {{0x80000005, 0}, Leaf{0xFF08FF08, 0xFF280000, 0x20080140, 0x20020140}},
+ });
+ const auto info = GetX86Info();
+
+ EXPECT_STREQ(info.vendor, "AuthenticAMD");
+ EXPECT_EQ(info.family, 0x14);
+ EXPECT_EQ(info.model, 0x01);
+ EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_BOBCAT);
+}
+
+// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0500F20_K14_Bobcat_CPUID.txt
+TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F20) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x00000006, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x00000001, 0}, Leaf{0x00500F20, 0x00020800, 0x00802209, 0x178BFBFF}},
+ {{0x80000000, 0}, Leaf{0x8000001B, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x80000001, 0}, Leaf{0x00500F20, 0x000012E9, 0x000035FF, 0x2FD3FBFF}},
+ });
+ const auto info = GetX86Info();
+
+ EXPECT_STREQ(info.vendor, "AuthenticAMD");
+ EXPECT_EQ(info.family, 0x14);
+ EXPECT_EQ(info.model, 0x02);
+ EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_BOBCAT);
+}
+
+// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0670F00_K15_StoneyRidge_CPUID.txt
+TEST_F(CpuidX86Test, AMD_K15_EXCAVATOR_STONEY_RIDGE) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x00000001, 0}, Leaf{0x00670F00, 0x00020800, 0x7ED8320B, 0x178BFBFF}},
+ {{0x00000007, 0}, Leaf{0x00000000, 0x000001A9, 0x00000000, 0x00000000}},
+ {{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x80000001, 0}, Leaf{0x00670F00, 0x00000000, 0x2FABBFFF, 0x2FD3FBFF}},
+ {{0x80000002, 0}, Leaf{0x20444D41, 0x392D3941, 0x20303134, 0x45444152}},
+ {{0x80000003, 0}, Leaf{0x52204E4F, 0x35202C35, 0x4D4F4320, 0x45545550}},
+ {{0x80000004, 0}, Leaf{0x524F4320, 0x32205345, 0x47332B43, 0x00202020}},
+ });
+ const auto info = GetX86Info();
+
+ EXPECT_STREQ(info.vendor, "AuthenticAMD");
+ 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
+TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_ABU_DHABI) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x00000001, 0}, Leaf{0x00600F20, 0x00100800, 0x3E98320B, 0x178BFBFF}},
+ {{0x00000007, 0}, Leaf{0x00000000, 0x00000008, 0x00000000, 0x00000000}},
+ {{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x80000001, 0}, Leaf{0x00600F20, 0x30000000, 0x01EBBFFF, 0x2FD3FBFF}},
+ {{0x80000002, 0}, Leaf{0x20444D41, 0x6574704F, 0x286E6F72, 0x20296D74}},
+ {{0x80000003, 0}, Leaf{0x636F7250, 0x6F737365, 0x33362072, 0x20203637}},
+ {{0x80000004, 0}, Leaf{0x20202020, 0x20202020, 0x20202020, 0x00202020}},
+ });
+ const auto info = GetX86Info();
+
+ EXPECT_STREQ(info.vendor, "AuthenticAMD");
+ EXPECT_EQ(info.family, 0x15);
+ EXPECT_EQ(info.model, 0x02);
+ EXPECT_STREQ(info.brand_string,
+ "AMD Opteron(tm) Processor 6376 ");
+ EXPECT_EQ(GetX86Microarchitecture(&info),
+ X86Microarchitecture::AMD_PILEDRIVER);
+
+ char brand_string[49];
+ FillX86BrandString(brand_string);
+ EXPECT_STREQ(brand_string, "AMD Opteron(tm) Processor 6376 ");
+}
+
+// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F20_K15_AbuDhabi_CPUID0.txt
+TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_ABU_DHABI_CACHE_INFO) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x00000001, 0}, Leaf{0x00600F20, 0x00100800, 0x3E98320B, 0x178BFBFF}},
+ {{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x80000001, 0}, Leaf{0x00600F20, 0x30000000, 0x01EBBFFF, 0x2FD3FBFF}},
+ {{0x8000001D, 0}, Leaf{0x00000121, 0x00C0003F, 0x0000003F, 0x00000000}},
+ {{0x8000001D, 1}, Leaf{0x00004122, 0x0040003F, 0x000001FF, 0x00000000}},
+ {{0x8000001D, 2}, Leaf{0x00004143, 0x03C0003F, 0x000007FF, 0x00000001}},
+ {{0x8000001D, 3}, Leaf{0x0001C163, 0x0BC0003F, 0x000007FF, 0x00000001}},
+ });
+ const auto info = GetX86CacheInfo();
+
+ EXPECT_EQ(info.size, 4);
+ EXPECT_EQ(info.levels[0].level, 1);
+ EXPECT_EQ(info.levels[0].cache_type, 1);
+ EXPECT_EQ(info.levels[0].cache_size, 16 * KiB);
+ EXPECT_EQ(info.levels[0].ways, 4);
+ EXPECT_EQ(info.levels[0].line_size, 64);
+ EXPECT_EQ(info.levels[0].tlb_entries, 64);
+ EXPECT_EQ(info.levels[0].partitioning, 1);
+
+ EXPECT_EQ(info.levels[1].level, 1);
+ EXPECT_EQ(info.levels[1].cache_type, 2);
+ EXPECT_EQ(info.levels[1].cache_size, 64 * KiB);
+ EXPECT_EQ(info.levels[1].ways, 2);
+ EXPECT_EQ(info.levels[1].line_size, 64);
+ EXPECT_EQ(info.levels[1].tlb_entries, 512);
+ EXPECT_EQ(info.levels[1].partitioning, 1);
+
+ EXPECT_EQ(info.levels[2].level, 2);
+ EXPECT_EQ(info.levels[2].cache_type, 3);
+ EXPECT_EQ(info.levels[2].cache_size, 2 * MiB);
+ EXPECT_EQ(info.levels[2].ways, 16);
+ EXPECT_EQ(info.levels[2].line_size, 64);
+ EXPECT_EQ(info.levels[2].tlb_entries, 2048);
+ EXPECT_EQ(info.levels[2].partitioning, 1);
+
+ EXPECT_EQ(info.levels[3].level, 3);
+ EXPECT_EQ(info.levels[3].cache_type, 3);
+ EXPECT_EQ(info.levels[3].cache_size, 6 * MiB);
+ EXPECT_EQ(info.levels[3].ways, 48);
+ EXPECT_EQ(info.levels[3].line_size, 64);
+ EXPECT_EQ(info.levels[3].tlb_entries, 2048);
+ EXPECT_EQ(info.levels[3].partitioning, 1);
+}
+
+// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F12_K15_Interlagos_CPUID3.txt
+TEST_F(CpuidX86Test, AMD_K15_BULLDOZER_INTERLAGOS) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x00000001, 0}, Leaf{0x00600F12, 0x000C0800, 0x1E98220B, 0x178BFBFF}},
+ {{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+ {{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x80000001, 0}, Leaf{0x00600F12, 0x30000000, 0x01C9BFFF, 0x2FD3FBFF}},
+ {{0x80000002, 0}, Leaf{0x20444D41, 0x6574704F, 0x286E6F72, 0x20294D54}},
+ {{0x80000003, 0}, Leaf{0x636F7250, 0x6F737365, 0x32362072, 0x20203833}},
+ {{0x80000004, 0}, Leaf{0x20202020, 0x20202020, 0x20202020, 0x00202020}},
+ });
+ const auto info = GetX86Info();
+
+ EXPECT_STREQ(info.vendor, "AuthenticAMD");
+ 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
-TEST_F(CpuidX86Test, AMD_K15) {
- g_fake_cpu->SetLeaves({
+TEST_F(CpuidX86Test, AMD_K15_STREAMROLLER_GODAVARI) {
+ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
{{0x00000001, 0}, Leaf{0x00630F81, 0x00040800, 0x3E98320B, 0x178BFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
@@ -315,41 +545,277 @@ TEST_F(CpuidX86Test, AMD_K15) {
EXPECT_EQ(info.family, 0x15);
EXPECT_EQ(info.model, 0x38);
EXPECT_EQ(info.stepping, 0x01);
+ EXPECT_STREQ(info.brand_string,
+ "AMD A8-7670K Radeon R7, 10 Compute Cores 4C+6G ");
EXPECT_EQ(GetX86Microarchitecture(&info),
- X86Microarchitecture::AMD_BULLDOZER);
+ 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/AuthenticAMD0700F01_K16_Kabini_CPUID.txt
+TEST_F(CpuidX86Test, AMD_K16_JAGUAR_KABINI) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x00000001, 0}, Leaf{0x00700F01, 0x00040800, 0x3ED8220B, 0x178BFBFF}},
+ {{0x00000007, 0}, Leaf{0x00000000, 0x00000008, 0x00000000, 0x00000000}},
+ {{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x80000001, 0}, Leaf{0x00700F01, 0x00000000, 0x154037FF, 0x2FD3FBFF}},
+ {{0x80000002, 0}, Leaf{0x20444D41, 0x352D3441, 0x20303030, 0x20555041}},
+ {{0x80000003, 0}, Leaf{0x68746977, 0x64615220, 0x286E6F65, 0x20294D54}},
+ {{0x80000004, 0}, Leaf{0x47204448, 0x68706172, 0x20736369, 0x00202020}},
+ });
+ const auto info = GetX86Info();
+
+ EXPECT_STREQ(info.vendor, "AuthenticAMD");
+ 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
+TEST_F(CpuidX86Test, AMD_K16_PUMA_BEEMA) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x00000001, 0}, Leaf{0x00730F01, 0x00040800, 0x7ED8220B, 0x178BFBFF}},
+ {{0x00000007, 0}, Leaf{0x00000000, 0x00000008, 0x00000000, 0x00000000}},
+ {{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x80000001, 0}, Leaf{0x00730F01, 0x00000000, 0x1D4037FF, 0x2FD3FBFF}},
+ {{0x80000002, 0}, Leaf{0x20444D41, 0x362D3641, 0x20303133, 0x20555041}},
+ {{0x80000003, 0}, Leaf{0x68746977, 0x444D4120, 0x64615220, 0x206E6F65}},
+ {{0x80000004, 0}, Leaf{0x47203452, 0x68706172, 0x20736369, 0x00202020}},
+ });
+ const auto info = GetX86Info();
+
+ EXPECT_STREQ(info.vendor, "AuthenticAMD");
+ 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);
+
+ char brand_string[49];
+ FillX86BrandString(brand_string);
+ EXPECT_STREQ(brand_string, "AMD A6-6310 APU with AMD Radeon R4 Graphics ");
+}
+
+// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0820F01_K17_Dali_CPUID.txt
+TEST_F(CpuidX86Test, AMD_K17_ZEN_DALI) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x00000001, 0}, Leaf{0x00820F01, 0x00020800, 0x7ED8320B, 0x178BFBFF}},
+ {{0x00000007, 0}, Leaf{0x00000000, 0x209C01A9, 0x00000000, 0x00000000}},
+ {{0x80000000, 0}, Leaf{0x8000001F, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x80000001, 0}, Leaf{0x00820F01, 0x00000000, 0x35C233FF, 0x2FD3FBFF}},
+ {{0x80000002, 0}, Leaf{0x20444D41, 0x30323033, 0x69772065, 0x52206874}},
+ {{0x80000003, 0}, Leaf{0x6F656461, 0x7247206E, 0x69687061, 0x20207363}},
+ {{0x80000004, 0}, Leaf{0x20202020, 0x20202020, 0x20202020, 0x00202020}},
+ });
+ const auto info = GetX86Info();
+
+ EXPECT_STREQ(info.vendor, "AuthenticAMD");
+ 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
+TEST_F(CpuidX86Test, AMD_K17_ZEN_PLUS_PINNACLE_RIDGE) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x00000001, 0}, Leaf{0x00800F82, 0x00100800, 0x7ED8320B, 0x178BFBFF}},
+ {{0x00000007, 0}, Leaf{0x00000000, 0x209C01A9, 0x00000000, 0x00000000}},
+ {{0x80000000, 0}, Leaf{0x8000001F, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x80000001, 0}, Leaf{0x00800F82, 0x20000000, 0x35C233FF, 0x2FD3FBFF}},
+ {{0x80000002, 0}, Leaf{0x20444D41, 0x657A7952, 0x2037206E, 0x30303732}},
+ {{0x80000003, 0}, Leaf{0x69452058, 0x2D746867, 0x65726F43, 0x6F725020}},
+ {{0x80000004, 0}, Leaf{0x73736563, 0x2020726F, 0x20202020, 0x00202020}},
+ });
+ const auto info = GetX86Info();
+
+ EXPECT_STREQ(info.vendor, "AuthenticAMD");
+ 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
+TEST_F(CpuidX86Test, AMD_K17_ZEN2_XBOX_SERIES_X) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x00000010, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x00000001, 0}, Leaf{0x00840F70, 0x00100800, 0x7ED8320B, 0x178BFBFF}},
+ {{0x00000007, 0}, Leaf{0x00000000, 0x219C91A9, 0x00400004, 0x00000000}},
+ {{0x80000000, 0}, Leaf{0x80000020, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x80000001, 0}, Leaf{0x00840F70, 0x00000000, 0xF5C2B7FF, 0x2FD3FBFF}},
+ {{0x80000002, 0}, Leaf{0x20444D41, 0x30303734, 0x2D382053, 0x65726F43}},
+ {{0x80000003, 0}, Leaf{0x6F725020, 0x73736563, 0x4420726F, 0x746B7365}},
+ {{0x80000004, 0}, Leaf{0x4B20706F, 0x00007469, 0x00000000, 0x00000000}},
+ });
+ const auto info = GetX86Info();
+
+ EXPECT_STREQ(info.vendor, "AuthenticAMD");
+ 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
+TEST_F(CpuidX86Test, AMD_K18_ZEN_DHYANA) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x0000000D, 0x6F677948, 0x656E6975, 0x6E65476E}},
+ {{0x00000001, 0}, Leaf{0x00900F02, 0x00100800, 0x74D83209, 0x178BFBFF}},
+ {{0x00000007, 0}, Leaf{0x00000000, 0x009C01A9, 0x0040068C, 0x00000000}},
+ {{0x80000000, 0}, Leaf{0x8000001F, 0x6F677948, 0x656E6975, 0x6E65476E}},
+ {{0x80000001, 0}, Leaf{0x00900F02, 0x60000000, 0x35C233FF, 0x2FD3FBFF}},
+ {{0x80000002, 0}, Leaf{0x6F677948, 0x3843206E, 0x31332036, 0x20203538}},
+ {{0x80000003, 0}, Leaf{0x6F632D38, 0x50206572, 0x65636F72, 0x726F7373}},
+ {{0x80000004, 0}, Leaf{0x20202020, 0x20202020, 0x20202020, 0x00202020}},
+ });
+ const auto info = GetX86Info();
+
+ EXPECT_STREQ(info.vendor, "HygonGenuine");
+ 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
+TEST_F(CpuidX86Test, AMD_K18_ZEN_DHYANA_CACHE_INFO) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x0000000D, 0x6F677948, 0x656E6975, 0x6E65476E}},
+ {{0x00000001, 0}, Leaf{0x00900F02, 0x00100800, 0x74D83209, 0x178BFBFF}},
+ {{0x80000000, 0}, Leaf{0x8000001F, 0x6F677948, 0x656E6975, 0x6E65476E}},
+ {{0x80000001, 0}, Leaf{0x00900F02, 0x60000000, 0x35C233FF, 0x2FD3FBFF}},
+ {{0x8000001D, 0}, Leaf{0x00004121, 0x01C0003F, 0x0000003F, 0x00000000}},
+ {{0x8000001D, 1}, Leaf{0x00004122, 0x00C0003F, 0x000000FF, 0x00000000}},
+ {{0x8000001D, 2}, Leaf{0x00004143, 0x01C0003F, 0x000003FF, 0x00000002}},
+ {{0x8000001D, 3}, Leaf{0x0001C163, 0x03C0003F, 0x00001FFF, 0x00000001}},
+ });
+ const auto info = GetX86CacheInfo();
+
+ EXPECT_EQ(info.size, 4);
+ EXPECT_EQ(info.levels[0].level, 1);
+ EXPECT_EQ(info.levels[0].cache_type, 1);
+ EXPECT_EQ(info.levels[0].cache_size, 32 * KiB);
+ EXPECT_EQ(info.levels[0].ways, 8);
+ EXPECT_EQ(info.levels[0].line_size, 64);
+ EXPECT_EQ(info.levels[0].tlb_entries, 64);
+ EXPECT_EQ(info.levels[0].partitioning, 1);
+
+ EXPECT_EQ(info.levels[1].level, 1);
+ EXPECT_EQ(info.levels[1].cache_type, 2);
+ EXPECT_EQ(info.levels[1].cache_size, 64 * KiB);
+ EXPECT_EQ(info.levels[1].ways, 4);
+ EXPECT_EQ(info.levels[1].line_size, 64);
+ EXPECT_EQ(info.levels[1].tlb_entries, 256);
+ EXPECT_EQ(info.levels[1].partitioning, 1);
+
+ EXPECT_EQ(info.levels[2].level, 2);
+ EXPECT_EQ(info.levels[2].cache_type, 3);
+ EXPECT_EQ(info.levels[2].cache_size, 512 * KiB);
+ EXPECT_EQ(info.levels[2].ways, 8);
+ EXPECT_EQ(info.levels[2].line_size, 64);
+ EXPECT_EQ(info.levels[2].tlb_entries, 1024);
+ EXPECT_EQ(info.levels[2].partitioning, 1);
+
+ EXPECT_EQ(info.levels[3].level, 3);
+ EXPECT_EQ(info.levels[3].cache_type, 3);
+ EXPECT_EQ(info.levels[3].cache_size, 8 * MiB);
+ EXPECT_EQ(info.levels[3].ways, 16);
+ EXPECT_EQ(info.levels[3].line_size, 64);
+ EXPECT_EQ(info.levels[3].tlb_entries, 8192);
+ EXPECT_EQ(info.levels[3].partitioning, 1);
+}
+
+// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0A20F10_K19_Vermeer2_CPUID.txt
+TEST_F(CpuidX86Test, AMD_K19_ZEN3_VERMEER) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x00000010, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x00000001, 0}, Leaf{0x00A20F10, 0x01180800, 0x7ED8320B, 0x178BFBFF}},
+ {{0x00000007, 0}, Leaf{0x00000000, 0x219C97A9, 0x0040068C, 0x00000000}},
+ {{0x80000000, 0}, Leaf{0x80000023, 0x68747541, 0x444D4163, 0x69746E65}},
+ {{0x80000001, 0}, Leaf{0x00A20F10, 0x20000000, 0x75C237FF, 0x2FD3FBFF}},
+ {{0x80000002, 0}, Leaf{0x20444D41, 0x657A7952, 0x2039206E, 0x30303935}},
+ {{0x80000003, 0}, Leaf{0x32312058, 0x726F432D, 0x72502065, 0x7365636F}},
+ {{0x80000004, 0}, Leaf{0x20726F73, 0x20202020, 0x20202020, 0x00202020}},
+ });
+ const auto info = GetX86Info();
+
+ EXPECT_STREQ(info.vendor, "AuthenticAMD");
+ 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);
+
+ char brand_string[49];
+ FillX86BrandString(brand_string);
+ EXPECT_STREQ(brand_string, "AMD Ryzen 9 5900X 12-Core Processor ");
+}
+
// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel00106A1_Nehalem_CPUID.txt
TEST_F(CpuidX86Test, Nehalem) {
// Pre AVX cpus don't have xsave
- g_fake_cpu->SetOsBackupsExtendedRegisters(false);
+ cpu().SetOsBackupsExtendedRegisters(false);
#if defined(CPU_FEATURES_OS_WINDOWS)
- g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
- PF_XMMI_INSTRUCTIONS_AVAILABLE);
- g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
- PF_XMMI64_INSTRUCTIONS_AVAILABLE);
- g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
- PF_SSE3_INSTRUCTIONS_AVAILABLE);
-#endif // CPU_FEATURES_OS_WINDOWS
-#if defined(CPU_FEATURES_OS_DARWIN)
- g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse");
- g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse2");
- g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse3");
- g_fake_cpu->SetDarwinSysCtlByName("hw.optional.supplementalsse3");
- g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_1");
- g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_2");
-#endif // CPU_FEATURES_OS_DARWIN
-#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
+ cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE);
+ cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE);
+ cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE);
+#elif defined(CPU_FEATURES_OS_MACOS)
+ cpu().SetDarwinSysCtlByName("hw.optional.sse");
+ cpu().SetDarwinSysCtlByName("hw.optional.sse2");
+ cpu().SetDarwinSysCtlByName("hw.optional.sse3");
+ cpu().SetDarwinSysCtlByName("hw.optional.supplementalsse3");
+ cpu().SetDarwinSysCtlByName("hw.optional.sse4_1");
+ cpu().SetDarwinSysCtlByName("hw.optional.sse4_2");
+#elif defined(CPU_FEATURES_OS_FREEBSD)
+ auto& fs = GetEmptyFilesystem();
+ fs.CreateFile("/var/run/dmesg.boot", R"(
+ ---<<BOOT>>---
+Copyright (c) 1992-2020 The FreeBSD Project.
+FreeBSD is a registered trademark of The FreeBSD Foundation.
+ Features=0x1783fbff<FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,MMX,FXSR,SSE,SSE2,HTT>
+ Features2=0x5eda2203<SSE3,PCLMULQDQ,SSSE3,CX16,PCID,SSE4.1,SSE4.2,MOVBE,POPCNT,AESNI,XSAVE,OSXSAVE,RDRAND>
+real memory = 2147418112 (2047 MB)
+)");
+#elif defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo", R"(processor :
-flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
+flags : fpu mmx sse sse2 pni ssse3 sse4_1 sse4_2
)");
-#endif // CPU_FEATURES_OS_LINUX_OR_ANDROID
- g_fake_cpu->SetLeaves({
+#endif
+ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000106A2, 0x00100800, 0x00BCE3BD, 0xBFEBFBFF}},
{{0x00000002, 0}, Leaf{0x55035A01, 0x00F0B0E3, 0x00000000, 0x09CA212C}},
@@ -382,6 +848,8 @@ flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
EXPECT_EQ(info.family, 0x06);
EXPECT_EQ(info.model, 0x1A);
EXPECT_EQ(info.stepping, 0x02);
+ EXPECT_STREQ(info.brand_string,
+ "Genuine Intel(R) CPU @ 0000 @ 1.87GHz");
EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_NHM);
char brand_string[49];
@@ -391,42 +859,47 @@ flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
EXPECT_TRUE(info.features.sse);
EXPECT_TRUE(info.features.sse2);
EXPECT_TRUE(info.features.sse3);
-#ifndef CPU_FEATURES_OS_WINDOWS
+#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 // CPU_FEATURES_OS_WINDOWS
+#endif // !defined(CPU_FEATURES_OS_WINDOWS)
}
// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0030673_Silvermont3_CPUID.txt
TEST_F(CpuidX86Test, Atom) {
// Pre AVX cpus don't have xsave
- g_fake_cpu->SetOsBackupsExtendedRegisters(false);
+ cpu().SetOsBackupsExtendedRegisters(false);
#if defined(CPU_FEATURES_OS_WINDOWS)
- g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
- PF_XMMI_INSTRUCTIONS_AVAILABLE);
- g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
- PF_XMMI64_INSTRUCTIONS_AVAILABLE);
- g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
- PF_SSE3_INSTRUCTIONS_AVAILABLE);
-#endif // CPU_FEATURES_OS_WINDOWS
-#if defined(CPU_FEATURES_OS_DARWIN)
- g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse");
- g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse2");
- g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse3");
- g_fake_cpu->SetDarwinSysCtlByName("hw.optional.supplementalsse3");
- g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_1");
- g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_2");
-#endif // CPU_FEATURES_OS_DARWIN
-#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
+ cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE);
+ cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE);
+ cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE);
+#elif defined(CPU_FEATURES_OS_MACOS)
+ cpu().SetDarwinSysCtlByName("hw.optional.sse");
+ cpu().SetDarwinSysCtlByName("hw.optional.sse2");
+ cpu().SetDarwinSysCtlByName("hw.optional.sse3");
+ cpu().SetDarwinSysCtlByName("hw.optional.supplementalsse3");
+ cpu().SetDarwinSysCtlByName("hw.optional.sse4_1");
+ cpu().SetDarwinSysCtlByName("hw.optional.sse4_2");
+#elif defined(CPU_FEATURES_OS_FREEBSD)
+ auto& fs = GetEmptyFilesystem();
+ fs.CreateFile("/var/run/dmesg.boot", R"(
+ ---<<BOOT>>---
+Copyright (c) 1992-2020 The FreeBSD Project.
+FreeBSD is a registered trademark of The FreeBSD Foundation.
+ Features=0x1783fbff<FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,MMX,FXSR,SSE,SSE2,HTT>
+ Features2=0x5eda2203<SSE3,PCLMULQDQ,SSSE3,CX16,PCID,SSE4.1,SSE4.2,MOVBE,POPCNT,AESNI,XSAVE,OSXSAVE,RDRAND>
+real memory = 2147418112 (2047 MB)
+)");
+#elif defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo", R"(
-flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
+flags : fpu mmx sse sse2 pni ssse3 sse4_1 sse4_2
)");
-#endif // CPU_FEATURES_OS_LINUX_OR_ANDROID
- g_fake_cpu->SetLeaves({
+#endif
+ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x00030673, 0x00100800, 0x41D8E3BF, 0xBFEBFBFF}},
{{0x00000002, 0}, Leaf{0x61B3A001, 0x0000FFC2, 0x00000000, 0x00000000}},
@@ -458,6 +931,8 @@ flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
EXPECT_EQ(info.family, 0x06);
EXPECT_EQ(info.model, 0x37);
EXPECT_EQ(info.stepping, 0x03);
+ EXPECT_STREQ(info.brand_string,
+ " Intel(R) Celeron(R) CPU J1900 @ 1.99GHz");
EXPECT_EQ(GetX86Microarchitecture(&info),
X86Microarchitecture::INTEL_ATOM_SMT);
@@ -468,33 +943,91 @@ flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
EXPECT_TRUE(info.features.sse);
EXPECT_TRUE(info.features.sse2);
EXPECT_TRUE(info.features.sse3);
-#ifndef CPU_FEATURES_OS_WINDOWS
+#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 // CPU_FEATURES_OS_WINDOWS
+#endif // !defined(CPU_FEATURES_OS_WINDOWS)
+}
+
+// https://www.felixcloutier.com/x86/cpuid#example-3-1--example-of-cache-and-tlb-interpretation
+TEST_F(CpuidX86Test, P4_CacheInfo) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x00000002, 0x756E6547, 0x6C65746E, 0x49656E69}},
+ {{0x00000001, 0}, Leaf{0x00000F0A, 0x00010808, 0x00000000, 0x3FEBFBFF}},
+ {{0x00000002, 0}, Leaf{0x665B5001, 0x00000000, 0x00000000, 0x007A7000}},
+ });
+
+ const auto info = GetX86CacheInfo();
+ EXPECT_EQ(info.size, 5);
+
+ EXPECT_EQ(info.levels[0].level, UNDEF);
+ EXPECT_EQ(info.levels[0].cache_type, CPU_FEATURE_CACHE_TLB);
+ EXPECT_EQ(info.levels[0].cache_size, 4 * KiB);
+ EXPECT_EQ(info.levels[0].ways, UNDEF);
+ EXPECT_EQ(info.levels[0].line_size, UNDEF);
+ EXPECT_EQ(info.levels[0].tlb_entries, 64);
+ EXPECT_EQ(info.levels[0].partitioning, 0);
+
+ EXPECT_EQ(info.levels[1].level, UNDEF);
+ EXPECT_EQ(info.levels[1].cache_type, CPU_FEATURE_CACHE_TLB);
+ EXPECT_EQ(info.levels[1].cache_size, 4 * KiB);
+ EXPECT_EQ(info.levels[1].ways, UNDEF);
+ EXPECT_EQ(info.levels[1].line_size, UNDEF);
+ EXPECT_EQ(info.levels[1].tlb_entries, 64);
+ EXPECT_EQ(info.levels[1].partitioning, 0);
+
+ EXPECT_EQ(info.levels[2].level, 1);
+ EXPECT_EQ(info.levels[2].cache_type, CPU_FEATURE_CACHE_DATA);
+ EXPECT_EQ(info.levels[2].cache_size, 8 * KiB);
+ EXPECT_EQ(info.levels[2].ways, 4);
+ EXPECT_EQ(info.levels[2].line_size, 64);
+ EXPECT_EQ(info.levels[2].tlb_entries, UNDEF);
+ EXPECT_EQ(info.levels[2].partitioning, 0);
+
+ EXPECT_EQ(info.levels[3].level, 1);
+ EXPECT_EQ(info.levels[3].cache_type, CPU_FEATURE_CACHE_INSTRUCTION);
+ EXPECT_EQ(info.levels[3].cache_size, 12 * KiB);
+ EXPECT_EQ(info.levels[3].ways, 8);
+ EXPECT_EQ(info.levels[3].line_size, UNDEF);
+ EXPECT_EQ(info.levels[3].tlb_entries, UNDEF);
+ EXPECT_EQ(info.levels[3].partitioning, 0);
+
+ EXPECT_EQ(info.levels[4].level, 2);
+ EXPECT_EQ(info.levels[4].cache_type, CPU_FEATURE_CACHE_DATA);
+ EXPECT_EQ(info.levels[4].cache_size, 256 * KiB);
+ EXPECT_EQ(info.levels[4].ways, 8);
+ EXPECT_EQ(info.levels[4].line_size, 64);
+ EXPECT_EQ(info.levels[4].tlb_entries, UNDEF);
+ EXPECT_EQ(info.levels[4].partitioning, 2);
}
// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0000673_P3_KatmaiDP_CPUID.txt
TEST_F(CpuidX86Test, P3) {
// Pre AVX cpus don't have xsave
- g_fake_cpu->SetOsBackupsExtendedRegisters(false);
+ cpu().SetOsBackupsExtendedRegisters(false);
#if defined(CPU_FEATURES_OS_WINDOWS)
- g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
- PF_XMMI_INSTRUCTIONS_AVAILABLE);
-#endif // CPU_FEATURES_OS_WINDOWS
-#if defined(CPU_FEATURES_OS_DARWIN)
- g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse");
-#endif // CPU_FEATURES_OS_DARWIN
-#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
+ cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE);
+#elif defined(CPU_FEATURES_OS_MACOS)
+ cpu().SetDarwinSysCtlByName("hw.optional.sse");
+#elif defined(CPU_FEATURES_OS_FREEBSD)
+ auto& fs = GetEmptyFilesystem();
+ fs.CreateFile("/var/run/dmesg.boot", R"(
+ ---<<BOOT>>---
+Copyright (c) 1992-2020 The FreeBSD Project.
+FreeBSD is a registered trademark of The FreeBSD Foundation.
+ Features=0x1783fbff<FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,MMX,FXSR,SSE>
+real memory = 2147418112 (2047 MB)
+)");
+#elif defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo", R"(
flags : fpu mmx sse
)");
-#endif // CPU_FEATURES_OS_LINUX_OR_ANDROID
- g_fake_cpu->SetLeaves({
+#endif
+ cpu().SetLeaves({
{{0x00000000, 0}, Leaf{0x00000003, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x00000673, 0x00000000, 0x00000000, 0x0387FBFF}},
{{0x00000002, 0}, Leaf{0x03020101, 0x00000000, 0x00000000, 0x0C040843}},
@@ -506,6 +1039,7 @@ flags : fpu mmx sse
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];
@@ -516,15 +1050,99 @@ flags : fpu mmx sse
EXPECT_TRUE(info.features.sse);
EXPECT_FALSE(info.features.sse2);
EXPECT_FALSE(info.features.sse3);
-#ifndef CPU_FEATURES_OS_WINDOWS
+#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 // CPU_FEATURES_OS_WINDOWS
+#endif // !defined(CPU_FEATURES_OS_WINDOWS)
+}
+
+// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0000480_486_CPUID.txt
+TEST_F(CpuidX86Test, INTEL_80486) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x00000001, 0x756E6547, 0x6C65746E, 0x49656E69}},
+ {{0x00000001, 0}, Leaf{0x00000480, 0x00000000, 0x00000000, 0x00000003}},
+ });
+ const auto info = GetX86Info();
+
+ EXPECT_STREQ(info.vendor, "GenuineIntel");
+ EXPECT_EQ(info.family, 0x04);
+ EXPECT_EQ(info.model, 0x08);
+ EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_80486);
+}
+
+// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0000526_P54C_CPUID.txt
+TEST_F(CpuidX86Test, INTEL_P54C) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x00000001, 0x756E6547, 0x6C65746E, 0x49656E69}},
+ {{0x00000001, 0}, Leaf{0x00000525, 0x00000000, 0x00000000, 0x000001BF}},
+ });
+ const auto info = GetX86Info();
+
+ EXPECT_STREQ(info.vendor, "GenuineIntel");
+ EXPECT_EQ(info.family, 0x05);
+ EXPECT_EQ(info.model, 0x02);
+ EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_P5);
+}
+
+// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0000590_Lakemont_CPUID2.txt
+TEST_F(CpuidX86Test, INTEL_LAKEMONT) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x00000002, 0x756E6547, 0x6c65746E, 0x49656E69}},
+ {{0x00000001, 0}, Leaf{0x00000590, 0x00000000, 0x00010200, 0x8000237B}},
+ });
+ const auto info = GetX86Info();
+
+ EXPECT_STREQ(info.vendor, "GenuineIntel");
+ 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/GenuineIntel0050670_KnightsLanding_CPUID.txt
+TEST_F(CpuidX86Test, INTEL_KNIGHTS_LANDING) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}},
+ {{0x00000001, 0}, Leaf{0x00050670, 0x02FF0800, 0x7FF8F3BF, 0xBFEBFBFF}},
+ });
+ const auto info = GetX86Info();
+
+ EXPECT_STREQ(info.vendor, "GenuineIntel");
+ EXPECT_EQ(info.family, 0x06);
+ EXPECT_EQ(info.model, 0x57);
+ EXPECT_EQ(GetX86Microarchitecture(&info),
+ X86Microarchitecture::INTEL_KNIGHTS_L);
}
+// 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) {
+ cpu().SetLeaves({
+ {{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}},
+ {{0x00000001, 0}, Leaf{0x000206F2, 0x00400800, 0x02BEE3FF, 0xBFEBFBFF}},
+ });
+ const auto info = GetX86Info();
+
+ EXPECT_EQ(info.family, 0x06);
+ EXPECT_EQ(info.model, 0x2F);
+ EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_WSM);
+
+#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.ssse3);
+ EXPECT_TRUE(info.features.sse4_1);
+ EXPECT_TRUE(info.features.sse4_2);
+#endif
+}
+#endif // CPU_FEATURES_OS_WINDOWS
+
// TODO(user): test what happens when xsave/osxsave are not present.
// TODO(user): test what happens when xmm/ymm/zmm os support are not
// present.
diff --git a/test/hwcaps_for_testing.cc b/test/hwcaps_for_testing.cc
index a8086a0..fc0013d 100644
--- a/test/hwcaps_for_testing.cc
+++ b/test/hwcaps_for_testing.cc
@@ -22,25 +22,31 @@ namespace cpu_features {
namespace {
static auto* const g_hardware_capabilities = new HardwareCapabilities();
-static auto* const g_platform_types = new PlatformType();
+static const char* g_platform_pointer = nullptr;
+static const char* g_base_platform_pointer = nullptr;
} // namespace
void SetHardwareCapabilities(uint32_t hwcaps, uint32_t hwcaps2) {
g_hardware_capabilities->hwcaps = hwcaps;
g_hardware_capabilities->hwcaps2 = hwcaps2;
}
+void SetPlatformPointer(const char* string) { g_platform_pointer = string; }
+void SetBasePlatformPointer(const char* string) {
+ g_base_platform_pointer = string;
+}
+
+void ResetHwcaps() {
+ SetHardwareCapabilities(0, 0);
+ SetPlatformPointer(nullptr);
+ SetBasePlatformPointer(nullptr);
+}
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void) {
return *g_hardware_capabilities;
}
-
-void SetPlatformTypes(const char* platform, const char* base_platform) {
- CpuFeatures_StringView_CopyString(str(platform), g_platform_types->platform,
- sizeof(g_platform_types->platform));
- CpuFeatures_StringView_CopyString(str(base_platform),
- g_platform_types->base_platform,
- sizeof(g_platform_types->base_platform));
+const char* CpuFeatures_GetPlatformPointer(void) { return g_platform_pointer; }
+const char* CpuFeatures_GetBasePlatformPointer(void) {
+ return g_base_platform_pointer;
}
-PlatformType CpuFeatures_GetPlatformType(void) { return *g_platform_types; }
} // namespace cpu_features
diff --git a/test/hwcaps_for_testing.h b/test/hwcaps_for_testing.h
index bcab82e..2138bac 100644
--- a/test/hwcaps_for_testing.h
+++ b/test/hwcaps_for_testing.h
@@ -20,7 +20,11 @@
namespace cpu_features {
void SetHardwareCapabilities(uint32_t hwcaps, uint32_t hwcaps2);
-void SetPlatformTypes(const char *platform, const char *base_platform);
+void SetPlatformPointer(const char* string);
+void SetBasePlatformPointer(const char* string);
+
+// To be called before each test.
+void ResetHwcaps();
} // namespace cpu_features
diff --git a/test/string_view_test.cc b/test/string_view_test.cc
index ca3e023..772ac3f 100644
--- a/test/string_view_test.cc
+++ b/test/string_view_test.cc
@@ -163,15 +163,25 @@ TEST(StringViewTest, CpuFeatures_StringView_CopyString) {
TEST(StringViewTest, CpuFeatures_StringView_HasWord) {
// Find flags at beginning, middle and end.
EXPECT_TRUE(
- CpuFeatures_StringView_HasWord(str("first middle last"), "first"));
+ CpuFeatures_StringView_HasWord(str("first middle last"), "first", ' '));
EXPECT_TRUE(
- CpuFeatures_StringView_HasWord(str("first middle last"), "middle"));
- EXPECT_TRUE(CpuFeatures_StringView_HasWord(str("first middle last"), "last"));
+ CpuFeatures_StringView_HasWord(str("first middle last"), "middle", ' '));
+ EXPECT_TRUE(
+ CpuFeatures_StringView_HasWord(str("first middle last"), "last", ' '));
+ // Find flags at beginning, middle and end with a different separator
+ EXPECT_TRUE(
+ CpuFeatures_StringView_HasWord(str("first-middle-last"), "first", '-'));
+ EXPECT_TRUE(
+ CpuFeatures_StringView_HasWord(str("first-middle-last"), "middle", '-'));
+ EXPECT_TRUE(
+ CpuFeatures_StringView_HasWord(str("first-middle-last"), "last", '-'));
// Do not match partial flags
EXPECT_FALSE(
- CpuFeatures_StringView_HasWord(str("first middle last"), "irst"));
- EXPECT_FALSE(CpuFeatures_StringView_HasWord(str("first middle last"), "mid"));
- EXPECT_FALSE(CpuFeatures_StringView_HasWord(str("first middle last"), "las"));
+ CpuFeatures_StringView_HasWord(str("first middle last"), "irst", ' '));
+ EXPECT_FALSE(
+ CpuFeatures_StringView_HasWord(str("first middle last"), "mid", ' '));
+ EXPECT_FALSE(
+ CpuFeatures_StringView_HasWord(str("first middle last"), "las", ' '));
}
TEST(StringViewTest, CpuFeatures_StringView_GetAttributeKeyValue) {