Merge v0.8.0 into master. am: 50b79af61d

Original change: https://android-review.googlesource.com/c/platform/external/cpu_features/+/2567814

Change-Id: Ie1b6563d82b42e384d5cb5d068e81271271bcfb1
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/.dockerignore b/.dockerignore
index 716b782..65950ea 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,8 +1,8 @@
 # Project Files unneeded by docker
-ci/Makefile
-ci/docker
-ci/doc
-ci/cache
+cmake/ci/Makefile
+cmake/ci/docker
+cmake/ci/doc
+cmake/ci/cache
 .git
 .gitignore
 .github
diff --git a/.github/workflows/aarch64_linux.yml b/.github/workflows/aarch64_linux_cmake.yml
similarity index 72%
rename from .github/workflows/aarch64_linux.yml
rename to .github/workflows/aarch64_linux_cmake.yml
index 2de7289..3e2d53c 100644
--- a/.github/workflows/aarch64_linux.yml
+++ b/.github/workflows/aarch64_linux_cmake.yml
@@ -1,4 +1,4 @@
-name: aarch64 Linux
+name: AArch64 Linux CMake
 
 on:
   push:
@@ -9,11 +9,13 @@
 
 jobs:
   # Building using the github runner environement directly.
-  aarch64:
+  make:
     runs-on: ubuntu-latest
     strategy:
       matrix:
         targets: [
+          [aarch64],
+          [aarch64be],
           [aarch64-linux-gnu],
           [aarch64_be-linux-gnu]
         ]
@@ -23,6 +25,6 @@
     steps:
     - uses: actions/checkout@v2
     - name: Build
-      run: make --directory=ci ${TARGET}_build
+      run: make --directory=cmake/ci ${TARGET}_build
     - name: Test
-      run: make --directory=ci ${TARGET}_test
+      run: make --directory=cmake/ci ${TARGET}_test
diff --git a/.github/workflows/amd64_freebsd.yml b/.github/workflows/amd64_freebsd_cmake.yml
similarity index 84%
rename from .github/workflows/amd64_freebsd.yml
rename to .github/workflows/amd64_freebsd_cmake.yml
index eeab380..8bad4f8 100644
--- a/.github/workflows/amd64_freebsd.yml
+++ b/.github/workflows/amd64_freebsd_cmake.yml
@@ -1,4 +1,4 @@
-name: amd64 FreeBSD
+name: amd64 FreeBSD CMake
 
 on:
   push:
@@ -10,7 +10,7 @@
 jobs:
   # Only MacOS hosted runner provides virtualisation with vagrant/virtualbox installed.
   # see: https://github.com/actions/virtual-environments/tree/main/images/macos
-  freebsd:
+  make:
     runs-on: macos-10.15
     steps:
     - uses: actions/checkout@v2
@@ -19,4 +19,4 @@
     - name: VirtualBox version
       run: virtualbox -h
     - name: Build
-      run: cd ci/vagrant/freebsd && vagrant up
+      run: cd cmake/ci/vagrant/freebsd && vagrant up
diff --git a/.github/workflows/amd64_linux.yml b/.github/workflows/amd64_linux.yml
deleted file mode 100644
index 21f4f90..0000000
--- a/.github/workflows/amd64_linux.yml
+++ /dev/null
@@ -1,31 +0,0 @@
-name: amd64 Linux
-
-on:
-  push:
-  pull_request:
-  schedule:
-    # min hours day(month) month day(week)
-    - cron: '0 0 7,22 * *'
-
-jobs:
-  # Building using the github runner environement directly.
-  make:
-    runs-on: ubuntu-latest
-    steps:
-    - uses: actions/checkout@v2
-    - name: Env
-      run: make --directory=ci amd64_env
-    - name: Devel
-      run: make --directory=ci amd64_devel
-    - name: Build
-      run: make --directory=ci amd64_build
-    - name: Test
-      run: make --directory=ci amd64_test
-    - name: Install Env
-      run: make --directory=ci amd64_install_env
-    - name: Install Devel
-      run: make --directory=ci amd64_install_devel
-    - name: Install Build
-      run: make --directory=ci amd64_install_build
-    - name: Install Test
-      run: make --directory=ci amd64_install_test
diff --git a/.github/workflows/amd64_linux_bazel.yml b/.github/workflows/amd64_linux_bazel.yml
new file mode 100644
index 0000000..599faf5
--- /dev/null
+++ b/.github/workflows/amd64_linux_bazel.yml
@@ -0,0 +1,26 @@
+name: amd64 Linux Bazel
+
+on:
+  push:
+  pull_request:
+  schedule:
+    # min hours day(month) month day(week)
+    - cron: '0 0 7,22 * *'
+
+jobs:
+  # Building using the github runner environement directly.
+  bazel:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Check out repository code
+        uses: actions/checkout@v2
+      - name: Install Bazel
+        run: |
+          curl -fsSL https://bazel.build/bazel-release.pub.gpg | gpg --dearmor > bazel.gpg
+          sudo mv bazel.gpg /etc/apt/trusted.gpg.d/
+          echo "deb [arch=amd64] https://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list
+          sudo apt-get update
+          sudo apt-get install bazel
+          bazel --version
+      - name: Test
+        run: bazel test -s --verbose_failures //...
diff --git a/.github/workflows/amd64_linux_cmake.yml b/.github/workflows/amd64_linux_cmake.yml
new file mode 100644
index 0000000..90ccc80
--- /dev/null
+++ b/.github/workflows/amd64_linux_cmake.yml
@@ -0,0 +1,31 @@
+name: amd64 Linux CMake
+
+on:
+  push:
+  pull_request:
+  schedule:
+    # min hours day(month) month day(week)
+    - cron: '0 0 7,22 * *'
+
+jobs:
+  # Building using the github runner environement directly.
+  make:
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v2
+    - name: Env
+      run: make --directory=cmake/ci amd64_env
+    - name: Devel
+      run: make --directory=cmake/ci amd64_devel
+    - name: Build
+      run: make --directory=cmake/ci amd64_build
+    - name: Test
+      run: make --directory=cmake/ci amd64_test
+    - name: Install Env
+      run: make --directory=cmake/ci amd64_install_env
+    - name: Install Devel
+      run: make --directory=cmake/ci amd64_install_devel
+    - name: Install Build
+      run: make --directory=cmake/ci amd64_install_build
+    - name: Install Test
+      run: make --directory=cmake/ci amd64_install_test
diff --git a/.github/workflows/amd64_macos.yml b/.github/workflows/amd64_macos_cmake.yml
similarity index 97%
rename from .github/workflows/amd64_macos.yml
rename to .github/workflows/amd64_macos_cmake.yml
index 19ec18c..3756500 100644
--- a/.github/workflows/amd64_macos.yml
+++ b/.github/workflows/amd64_macos_cmake.yml
@@ -1,4 +1,4 @@
-name: amd64 macOS
+name: amd64 MacOS CMake
 
 on:
   push:
diff --git a/.github/workflows/amd64_windows.yml b/.github/workflows/amd64_windows_cmake.yml
similarity index 96%
rename from .github/workflows/amd64_windows.yml
rename to .github/workflows/amd64_windows_cmake.yml
index 7ff1ac0..7118533 100644
--- a/.github/workflows/amd64_windows.yml
+++ b/.github/workflows/amd64_windows_cmake.yml
@@ -1,4 +1,4 @@
-name: amd64 Windows
+name: amd64 Windows CMake
 
 on:
   push:
diff --git a/.github/workflows/arm_linux.yml b/.github/workflows/arm_linux_cmake.yml
similarity index 80%
rename from .github/workflows/arm_linux.yml
rename to .github/workflows/arm_linux_cmake.yml
index 2272188..87bb6bb 100644
--- a/.github/workflows/arm_linux.yml
+++ b/.github/workflows/arm_linux_cmake.yml
@@ -1,4 +1,4 @@
-name: arm Linux
+name: ARM Linux CMake
 
 on:
   push:
@@ -9,7 +9,7 @@
 
 jobs:
   # Building using the github runner environement directly.
-  arm:
+  make:
     runs-on: ubuntu-latest
     strategy:
       matrix:
@@ -26,6 +26,6 @@
     steps:
     - uses: actions/checkout@v2
     - name: Build
-      run: make --directory=ci ${TARGET}_build
+      run: make --directory=cmake/ci ${TARGET}_build
     - name: Test
-      run: make --directory=ci ${TARGET}_test
+      run: make --directory=cmake/ci ${TARGET}_test
diff --git a/.github/workflows/mips_linux.yml b/.github/workflows/mips_linux_cmake.yml
similarity index 78%
rename from .github/workflows/mips_linux.yml
rename to .github/workflows/mips_linux_cmake.yml
index 571de3a..9ce7901 100644
--- a/.github/workflows/mips_linux.yml
+++ b/.github/workflows/mips_linux_cmake.yml
@@ -1,4 +1,4 @@
-name: mips Linux
+name: MIPS Linux CMake
 
 on:
   push:
@@ -9,7 +9,7 @@
 
 jobs:
   # Building using the github runner environement directly.
-  mips:
+  make:
     runs-on: ubuntu-latest
     strategy:
       matrix:
@@ -25,6 +25,6 @@
     steps:
     - uses: actions/checkout@v2
     - name: Build
-      run: make --directory=ci ${TARGET}_build
+      run: make --directory=cmake/ci ${TARGET}_build
     - name: Test
-      run: make --directory=ci ${TARGET}_test
+      run: make --directory=cmake/ci ${TARGET}_test
diff --git a/.github/workflows/mips_linux.yml b/.github/workflows/power_linux_cmake.yml
similarity index 67%
copy from .github/workflows/mips_linux.yml
copy to .github/workflows/power_linux_cmake.yml
index 571de3a..bc890e2 100644
--- a/.github/workflows/mips_linux.yml
+++ b/.github/workflows/power_linux_cmake.yml
@@ -1,4 +1,4 @@
-name: mips Linux
+name: POWER Linux CMake
 
 on:
   push:
@@ -9,15 +9,14 @@
 
 jobs:
   # Building using the github runner environement directly.
-  mips:
+  make:
     runs-on: ubuntu-latest
     strategy:
       matrix:
         targets: [
-          [mips32],
-          [mips32el],
-          [mips64],
-          [mips64el]
+          [ppc],
+          [ppc64],
+          [ppc64le],
         ]
       fail-fast: false
     env:
@@ -25,6 +24,6 @@
     steps:
     - uses: actions/checkout@v2
     - name: Build
-      run: make --directory=ci ${TARGET}_build
+      run: make --directory=cmake/ci ${TARGET}_build
     - name: Test
-      run: make --directory=ci ${TARGET}_test
+      run: make --directory=cmake/ci ${TARGET}_test
diff --git a/.github/workflows/aarch64_linux.yml b/.github/workflows/riscv_linux_cmake.yml
similarity index 68%
copy from .github/workflows/aarch64_linux.yml
copy to .github/workflows/riscv_linux_cmake.yml
index 2de7289..ef7586a 100644
--- a/.github/workflows/aarch64_linux.yml
+++ b/.github/workflows/riscv_linux_cmake.yml
@@ -1,4 +1,4 @@
-name: aarch64 Linux
+name: RISCV Linux CMake
 
 on:
   push:
@@ -9,13 +9,13 @@
 
 jobs:
   # Building using the github runner environement directly.
-  aarch64:
+  make:
     runs-on: ubuntu-latest
     strategy:
       matrix:
         targets: [
-          [aarch64-linux-gnu],
-          [aarch64_be-linux-gnu]
+          [riscv32],
+          [riscv64],
         ]
       fail-fast: false
     env:
@@ -23,6 +23,6 @@
     steps:
     - uses: actions/checkout@v2
     - name: Build
-      run: make --directory=ci ${TARGET}_build
+      run: make --directory=cmake/ci ${TARGET}_build
     - name: Test
-      run: make --directory=ci ${TARGET}_test
+      run: make --directory=cmake/ci ${TARGET}_test
diff --git a/.github/workflows/aarch64_linux.yml b/.github/workflows/s390x_linux_cmake.yml
similarity index 68%
copy from .github/workflows/aarch64_linux.yml
copy to .github/workflows/s390x_linux_cmake.yml
index 2de7289..5be96a1 100644
--- a/.github/workflows/aarch64_linux.yml
+++ b/.github/workflows/s390x_linux_cmake.yml
@@ -1,4 +1,4 @@
-name: aarch64 Linux
+name: s390x Linux CMake
 
 on:
   push:
@@ -9,13 +9,12 @@
 
 jobs:
   # Building using the github runner environement directly.
-  aarch64:
+  make:
     runs-on: ubuntu-latest
     strategy:
       matrix:
         targets: [
-          [aarch64-linux-gnu],
-          [aarch64_be-linux-gnu]
+          [s390x],
         ]
       fail-fast: false
     env:
@@ -23,6 +22,6 @@
     steps:
     - uses: actions/checkout@v2
     - name: Build
-      run: make --directory=ci ${TARGET}_build
+      run: make --directory=cmake/ci ${TARGET}_build
     - name: Test
-      run: make --directory=ci ${TARGET}_test
+      run: make --directory=cmake/ci ${TARGET}_test
diff --git a/.grenrc.yml b/.grenrc.yml
new file mode 100644
index 0000000..77dd755
--- /dev/null
+++ b/.grenrc.yml
@@ -0,0 +1,21 @@
+---
+  dataSource: "prs"
+  ignoreLabels:
+    - "Apple M1"
+    - "duplicate"
+    - "help wanted"
+    - "invalid"
+    - "question"
+    - "wontfix"
+  onlyMilestones: false
+  groupBy:
+    "API Change":
+      - "API Change"
+    "New features / Enhancements":
+      - "enhancement"
+      - "internal"
+    "Bug Fixes":
+      - "bug"
+    "Misc":
+      - "misc"
+  changelogFilename: "CHANGELOG.md"
diff --git a/BUILD.bazel b/BUILD.bazel
index 1b62d66..116ef6a 100644
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -28,24 +28,24 @@
 
 cc_library(
     name = "cpu_features_macros",
-    hdrs = ["include/cpu_features_macros.h"],
     copts = C99_FLAGS,
     includes = INCLUDES,
+    textual_hdrs = ["include/cpu_features_macros.h"],
 )
 
 cc_library(
     name = "cpu_features_cache_info",
-    hdrs = ["include/cpu_features_cache_info.h"],
     copts = C99_FLAGS,
     includes = INCLUDES,
+    textual_hdrs = ["include/cpu_features_cache_info.h"],
     deps = [":cpu_features_macros"],
 )
 
 cc_library(
     name = "bit_utils",
-    hdrs = ["include/internal/bit_utils.h"],
     copts = C99_FLAGS,
     includes = INCLUDES,
+    textual_hdrs = ["include/internal/bit_utils.h"],
     deps = [":cpu_features_macros"],
 )
 
@@ -74,9 +74,9 @@
     srcs = [
         "src/string_view.c",
     ],
-    hdrs = ["include/internal/string_view.h"],
     copts = C99_FLAGS,
     includes = INCLUDES,
+    textual_hdrs = ["include/internal/string_view.h"],
     deps = [
         ":cpu_features_macros",
         ":memory_utils",
@@ -96,9 +96,9 @@
 cc_library(
     name = "filesystem",
     srcs = ["src/filesystem.c"],
-    hdrs = ["include/internal/filesystem.h"],
     copts = C99_FLAGS,
     includes = INCLUDES,
+    textual_hdrs = ["include/internal/filesystem.h"],
     deps = [":cpu_features_macros"],
 )
 
@@ -113,8 +113,8 @@
         "include/internal/filesystem.h",
         "test/filesystem_for_testing.h",
     ],
-    includes = INCLUDES,
     defines = ["CPU_FEATURES_MOCK_FILESYSTEM"],
+    includes = INCLUDES,
     deps = [
         ":cpu_features_macros",
     ],
@@ -123,10 +123,10 @@
 cc_library(
     name = "stack_line_reader",
     srcs = ["src/stack_line_reader.c"],
-    hdrs = ["include/internal/stack_line_reader.h"],
     copts = C99_FLAGS,
-    includes = INCLUDES,
     defines = ["STACK_LINE_READER_BUFFER_SIZE=1024"],
+    includes = INCLUDES,
+    textual_hdrs = ["include/internal/stack_line_reader.h"],
     deps = [
         ":cpu_features_macros",
         ":filesystem",
@@ -141,8 +141,8 @@
         "src/stack_line_reader.c",
         "test/stack_line_reader_test.cc",
     ],
-    includes = INCLUDES,
     defines = ["STACK_LINE_READER_BUFFER_SIZE=16"],
+    includes = INCLUDES,
     deps = [
         ":cpu_features_macros",
         ":filesystem_for_testing",
@@ -157,8 +157,8 @@
     srcs = ["src/stack_line_reader.c"],
     hdrs = ["include/internal/stack_line_reader.h"],
     copts = C99_FLAGS,
-    includes = INCLUDES,
     defines = ["STACK_LINE_READER_BUFFER_SIZE=1024"],
+    includes = INCLUDES,
     deps = [
         ":cpu_features_macros",
         ":filesystem_for_testing",
@@ -169,10 +169,10 @@
 cc_library(
     name = "hwcaps",
     srcs = ["src/hwcaps.c"],
-    hdrs = ["include/internal/hwcaps.h"],
     copts = C99_FLAGS,
-    includes = INCLUDES,
     defines = ["HAVE_STRONG_GETAUXVAL"],
+    includes = INCLUDES,
+    textual_hdrs = ["include/internal/hwcaps.h"],
     deps = [
         ":cpu_features_macros",
         ":filesystem",
@@ -191,11 +191,11 @@
         "include/internal/hwcaps.h",
         "test/hwcaps_for_testing.h",
     ],
-    includes = INCLUDES,
     defines = [
         "CPU_FEATURES_MOCK_GET_ELF_HWCAP_FROM_GETAUXVAL",
         "CPU_FEATURES_TEST",
     ],
+    includes = INCLUDES,
     deps = [
         ":cpu_features_macros",
         ":filesystem_for_testing",
@@ -217,21 +217,19 @@
         PLATFORM_CPU_MIPS: ["src/impl_mips_linux_or_android.c"],
         PLATFORM_CPU_PPC: ["src/impl_ppc_linux.c"],
     }),
-    hdrs = selects.with_or({
+    copts = C99_FLAGS,
+    includes = INCLUDES,
+    textual_hdrs = selects.with_or({
         PLATFORM_CPU_X86_64: [
+            "src/impl_x86__base_implementation.inl",
             "include/cpuinfo_x86.h",
             "include/internal/cpuid_x86.h",
+            "include/internal/windows_utils.h",
         ],
         PLATFORM_CPU_ARM: ["include/cpuinfo_arm.h"],
         PLATFORM_CPU_ARM64: ["include/cpuinfo_aarch64.h"],
         PLATFORM_CPU_MIPS: ["include/cpuinfo_mips.h"],
         PLATFORM_CPU_PPC: ["include/cpuinfo_ppc.h"],
-    }),
-    copts = C99_FLAGS,
-    includes = INCLUDES,
-    textual_hdrs = selects.with_or({
-        PLATFORM_CPU_X86_64: ["src/impl_x86__base_implementation.inl"],
-        "//conditions:default": [],
     }) + [
         "src/define_introspection.inl",
         "src/define_introspection_and_hwcaps.inl",
@@ -267,6 +265,7 @@
         PLATFORM_CPU_X86_64: [
             "include/cpuinfo_x86.h",
             "include/internal/cpuid_x86.h",
+            "include/internal/windows_utils.h",
         ],
         PLATFORM_CPU_ARM: ["include/cpuinfo_arm.h"],
         PLATFORM_CPU_ARM64: ["include/cpuinfo_aarch64.h"],
@@ -274,11 +273,11 @@
         PLATFORM_CPU_PPC: ["include/cpuinfo_ppc.h"],
     }),
     copts = C99_FLAGS,
-    includes = INCLUDES,
     defines = selects.with_or({
         PLATFORM_CPU_X86_64: ["CPU_FEATURES_MOCK_CPUID_X86"],
         "//conditions:default": [],
     }),
+    includes = INCLUDES,
     textual_hdrs = selects.with_or({
         PLATFORM_CPU_X86_64: ["src/impl_x86__base_implementation.inl"],
         "//conditions:default": [],
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 81451d4..bcc9bb0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,7 +6,7 @@
   cmake_policy(SET CMP0077 NEW)
 endif()
 
-project(CpuFeatures VERSION 0.7.0 LANGUAGES C)
+project(CpuFeatures VERSION 0.8.0 LANGUAGES C)
 
 set(CMAKE_C_STANDARD 99)
 
@@ -49,6 +49,8 @@
 set(PROCESSOR_IS_AARCH64 FALSE)
 set(PROCESSOR_IS_X86 FALSE)
 set(PROCESSOR_IS_POWER FALSE)
+set(PROCESSOR_IS_S390X FALSE)
+set(PROCESSOR_IS_RISCV FALSE)
 
 if(CMAKE_SYSTEM_PROCESSOR MATCHES "^mips")
   set(PROCESSOR_IS_MIPS TRUE)
@@ -60,6 +62,10 @@
   set(PROCESSOR_IS_X86 TRUE)
 elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)")
   set(PROCESSOR_IS_POWER TRUE)
+elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(s390x)")
+  set(PROCESSOR_IS_S390X TRUE)
+elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^riscv")
+  set(PROCESSOR_IS_RISCV TRUE)
 endif()
 
 macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME)
@@ -73,11 +79,17 @@
       list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_arm.h)
   elseif(PROCESSOR_IS_AARCH64)
       list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_aarch64.h)
+      list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/internal/windows_utils.h)
   elseif(PROCESSOR_IS_X86)
       list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_x86.h)
       list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/internal/cpuid_x86.h)
+      list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/internal/windows_utils.h)
   elseif(PROCESSOR_IS_POWER)
       list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_ppc.h)
+  elseif(PROCESSOR_IS_S390X)
+      list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_s390x.h)
+  elseif(PROCESSOR_IS_RISCV)
+      list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_riscv.h)
   else()
     message(FATAL_ERROR "Unsupported architectures ${CMAKE_SYSTEM_PROCESSOR}")
   endif()
@@ -168,9 +180,9 @@
   # found.
   enable_language(CXX)
 
-  set(CMAKE_CXX_STANDARD 11)
+  set(CMAKE_CXX_STANDARD 14)
   set(CMAKE_CXX_STANDARD_REQUIRED ON)
-  set(CMAKE_CXX_EXTENSIONS OFF) # prefer use of -std11 instead of -gnustd11
+  set(CMAKE_CXX_EXTENSIONS OFF) # prefer use of -std14 instead of -gnustd14
 
   if(NOT TARGET gtest OR NOT TARGET gmock_main)
     # Download and unpack googletest at configure time.
diff --git a/METADATA b/METADATA
index eac4f3d..ab7bdf7 100644
--- a/METADATA
+++ b/METADATA
@@ -9,11 +9,11 @@
     type: GIT
     value: "https://github.com/google/cpu_features.git"
   }
-  version: "v0.7.0"
+  version: "v0.8.0"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2022
-    month: 3
-    day: 8
+    year: 2023
+    month: 4
+    day: 27
   }
 }
diff --git a/README.md b/README.md
index 6091845..ee0ce70 100644
--- a/README.md
+++ b/README.md
@@ -1,18 +1,44 @@
 # cpu_features
-[![Linux Status][linux_svg]][linux_link]
-[![Macos Status][macos_svg]][macos_link]
-[![Windows Status][windows_svg]][windows_link]
-
-[linux_svg]: https://github.com/google/cpu_features/actions/workflows/amd64_linux.yml/badge.svg?branch=main
-[linux_link]: https://github.com/google/cpu_features/actions/workflows/amd64_linux.yml
-[macos_svg]: https://github.com/google/cpu_features/actions/workflows/amd64_macos.yml/badge.svg?branch=main
-[macos_link]: https://github.com/google/cpu_features/actions/workflows/amd64_macos.yml
-[windows_svg]: https://github.com/google/cpu_features/actions/workflows/amd64_windows.yml/badge.svg?branch=main
-[windows_link]: https://github.com/google/cpu_features/actions/workflows/amd64_windows.yml
 
 A cross-platform C library to retrieve CPU features (such as available
 instructions) at runtime.
 
+# GitHub-CI Status
+
+[comment]: <> (The following lines are generated by "scripts/generate_badges.d" that you can run online https://run.dlang.io/)
+
+| Os | amd64 | AArch64 | ARM | MIPS | POWER | RISCV | s390x |
+| :-- | --: | --: | --: | --: | --: | --: | --: |
+| Linux | [![][i1a0]][l1a0]<br/>[![][i1a1]][l1a1] | [![][i1b0]][l1b0]<br/>![][d1] | [![][i1c0]][l1c0]<br/>![][d1] | [![][i1d0]][l1d0]<br/>![][d1] | [![][i1e0]][l1e0]<br/>![][d1] | [![][i1f0]][l1f0]<br/>![][d1] | [![][i1g0]][l1g0]<br/>![][d1] |
+| FreeBSD | [![][i2a0]][l2a0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] |
+| MacOS | [![][i3a0]][l3a0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] |
+| Windows | [![][i4a0]][l4a0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] | ![][d0]<br/>![][d1] |
+
+[d0]: https://img.shields.io/badge/CMake-N%2FA-lightgrey
+[d1]: https://img.shields.io/badge/Bazel-N%2FA-lightgrey
+[i1a0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_linux_cmake.yml?branch=main&label=CMake
+[i1a1]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_linux_bazel.yml?branch=main&label=Bazel
+[i1b0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/aarch64_linux_cmake.yml?branch=main&label=CMake
+[i1c0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/arm_linux_cmake.yml?branch=main&label=CMake
+[i1d0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/mips_linux_cmake.yml?branch=main&label=CMake
+[i1e0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/power_linux_cmake.yml?branch=main&label=CMake
+[i1f0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/riscv_linux_cmake.yml?branch=main&label=CMake
+[i1g0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/s390x_linux_cmake.yml?branch=main&label=CMake
+[i2a0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_freebsd_cmake.yml?branch=main&label=CMake
+[i3a0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_macos_cmake.yml?branch=main&label=CMake
+[i4a0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_windows_cmake.yml?branch=main&label=CMake
+[l1a0]: https://github.com/google/cpu_features/actions/workflows/amd64_linux_cmake.yml
+[l1a1]: https://github.com/google/cpu_features/actions/workflows/amd64_linux_bazel.yml
+[l1b0]: https://github.com/google/cpu_features/actions/workflows/aarch64_linux_cmake.yml
+[l1c0]: https://github.com/google/cpu_features/actions/workflows/arm_linux_cmake.yml
+[l1d0]: https://github.com/google/cpu_features/actions/workflows/mips_linux_cmake.yml
+[l1e0]: https://github.com/google/cpu_features/actions/workflows/power_linux_cmake.yml
+[l1f0]: https://github.com/google/cpu_features/actions/workflows/riscv_linux_cmake.yml
+[l1g0]: https://github.com/google/cpu_features/actions/workflows/s390x_linux_cmake.yml
+[l2a0]: https://github.com/google/cpu_features/actions/workflows/amd64_freebsd_cmake.yml
+[l3a0]: https://github.com/google/cpu_features/actions/workflows/amd64_macos_cmake.yml
+[l4a0]: https://github.com/google/cpu_features/actions/workflows/amd64_windows_cmake.yml
+
 ## Table of Contents
 
 - [Design Rationale](#rationale)
@@ -152,14 +178,14 @@
 <a name="support"></a>
 ## What's supported
 
-|         | x86³ | ARM     | AArch64 | MIPS⁴   | POWER   |
-|---------|:----:|:-------:|:-------:|:-------:|:-------:|
-| Android | yes² | yes¹    | yes¹    | yes¹    | N/A     |
-| iOS     | N/A  | not yet | not yet | N/A     | N/A     |
-| Linux   | yes² | yes¹    | yes¹    | yes¹    | yes¹    |
-| MacOs   | yes² | N/A     | not yet | N/A     | no      |
-| Windows | yes² | not yet | not yet | N/A     | N/A     |
-| FreeBSD | yes² | not yet | not yet | not yet | not yet |
+|         | x86³ | AArch64 | ARM     | MIPS⁴   | POWER   | RISCV   | s390x   |
+|---------|:----:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|
+| Linux   | yes² | yes¹    | yes¹    | yes¹    | yes¹    | yes¹    | yes¹    |
+| FreeBSD | yes² | not yet | not yet | not yet | not yet | N/A     | not yet |
+| MacOs   | yes² | not yet | N/A     | N/A     | no      | N/A     | no      |
+| Windows | yes² | not yet | not yet | N/A     | N/A     | N/A     | N/A     |
+| Android | yes² | yes¹    | yes¹    | yes¹    | N/A     | N/A     | N/A     |
+| iOS     | N/A  | not yet | not yet | N/A     | N/A     | N/A     | N/A     |
 
 1.  **Features revealed from Linux.** We gather data from several sources
     depending on availability:
@@ -196,23 +222,39 @@
 <a name="quickstart"></a>
 ### Quickstart
 
- - Run `list_cpu_features`
-```sh
-cmake -S. -Bbuild -DBUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=Release
-cmake --build build --config Release -j
-./build/list_cpu_features --json
-```
+- Run `list_cpu_features`
+  ```sh
+  cmake -S. -Bbuild -DBUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=Release
+  cmake --build build --config Release -j
+  ./build/list_cpu_features --json
+  ```
 
-_Note_: Use `--target ALL_BUILD` on the second line for `Visual Studio` and `XCode`.
+  _Note_: Use `--target ALL_BUILD` on the second line for `Visual Studio` and `XCode`.
 
- - run tests
-```sh
-cmake -S. -Bbuild -DBUILD_TESTING=ON -DCMAKE_BUILD_TYPE=Debug
-cmake --build build --config Debug -j
-cmake --build build --config Debug --target test
-```
+- run tests
+  ```sh
+  cmake -S. -Bbuild -DBUILD_TESTING=ON -DCMAKE_BUILD_TYPE=Debug
+  cmake --build build --config Debug -j
+  cmake --build build --config Debug --target test
+  ```
 
-_Note_: Use `--target RUN_TESTS` on the last line for `Visual Studio` and `--target RUN_TEST` for `XCode`.
+  _Note_: Use `--target RUN_TESTS` on the last line for `Visual Studio` and `--target RUN_TEST` for `XCode`.
+
+
+- install `cpu_features`
+  ```sh
+  cmake --build build --config Release --target install -v
+  ```
+
+  _Note_: Use `--target INSTALL` for `Visual Studio`.
+
+  _Note_: When using `Makefile` or `XCode` generator, you can use
+  [`DESTDIR`](https://www.gnu.org/software/make/manual/html_node/DESTDIR.html)
+  to install on a local repository.<br>
+  e.g.
+  ```sh
+  cmake --build build --config Release --target install -v -- DESTDIR=install
+  ```
 
 <a name="bindings"></a>
 ## Community bindings
@@ -223,6 +265,8 @@
    - https://github.com/toor1245/cpu_features.NET
  - Python
    - https://github.com/Narasimha1997/py_cpu
+ - Java
+   - https://github.com/aecsocket/cpu-features-java
 
 
 _Send PR to showcase your wrapper here_
diff --git a/WORKSPACE b/WORKSPACE
index 104c459..c26a772 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -1,21 +1,17 @@
 workspace(name = "com_google_cpufeatures")
 
-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
 
-http_archive(
+git_repository(
     name = "com_google_googletest",
-    sha256 = "269cebe2be1f607f91f52630ff5bec3275b948c65d4bac323ebd05e90d84f7a9",
-    strip_prefix = "googletest-e2239ee6043f73722e7aa812a459f54a28552929",
-    urls = ["https://github.com/google/googletest/archive/e2239ee6043f73722e7aa812a459f54a28552929.zip"],
+    tag = "release-1.11.0",
+    remote = "https://github.com/google/googletest.git",
 )
 
-http_archive(
+git_repository(
     name = "bazel_skylib",
-    sha256 = "c6966ec828da198c5d9adbaa94c05e3a1c7f21bd012a0b29ba8ddbccb2c93b0d",
-    urls = [
-        "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.1.1/bazel-skylib-1.1.1.tar.gz",
-        "https://github.com/bazelbuild/bazel-skylib/releases/download/1.1.1/bazel-skylib-1.1.1.tar.gz",
-    ],
+    tag = "1.2.0",
+    remote = "https://github.com/bazelbuild/bazel-skylib.git",
 )
 
 load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
diff --git a/bazel/ci/README.md b/bazel/ci/README.md
new file mode 100644
index 0000000..c5fcde9
--- /dev/null
+++ b/bazel/ci/README.md
@@ -0,0 +1,5 @@
+## Usage
+To build tests with bazel
+```sh
+bazel test -s --verbose_failures //...
+```
diff --git a/ci/README.md b/ci/README.md
deleted file mode 100644
index e370136..0000000
--- a/ci/README.md
+++ /dev/null
@@ -1,66 +0,0 @@
-# GitHub-CI Status
-| OS       | amd64 | AArch64 | ARM | MIPS |
-|:-------- | :----: | :-----: | :-: | :--: |
-| FreeBSD    | [![Status][freebsd_svg]][freebsd_link] | N/A | N/A | N/A |
-| Linux    | [![Status][linux_svg]][linux_link] | [![Status][linux_aarch64_svg]][linux_aarch64_link] | [![Status][linux_arm_svg]][linux_arm_link] | [![Status][linux_mips_svg]][linux_mips_link] |
-| MacOS    | [![Status][macos_svg]][macos_link] | N/A | N/A | N/A |
-| Windows  | [![Status][windows_svg]][windows_link] | N/A | N/A | N/A |
-
-[freebsd_svg]: https://github.com/google/cpu_features/actions/workflows/amd64_freebsd.yml/badge.svg?branch=main
-[freebsd_link]: https://github.com/google/cpu_features/actions/workflows/amd64_freebsd.yml
-
-[linux_svg]: https://github.com/google/cpu_features/actions/workflows/amd64_linux.yml/badge.svg?branch=main
-[linux_link]: https://github.com/google/cpu_features/actions/workflows/amd64_linux.yml
-[linux_aarch64_svg]: https://github.com/google/cpu_features/actions/workflows/aarch64_linux.yml/badge.svg?branch=main
-[linux_aarch64_link]: https://github.com/google/cpu_features/actions/workflows/aarch64_linux.yml
-[linux_arm_svg]: https://github.com/google/cpu_features/actions/workflows/arm_linux.yml/badge.svg?branch=main
-[linux_arm_link]: https://github.com/google/cpu_features/actions/workflows/arm_linux.yml
-[linux_mips_svg]: https://github.com/google/cpu_features/actions/workflows/mips_linux.yml/badge.svg?branch=main
-[linux_mips_link]: https://github.com/google/cpu_features/actions/workflows/mips_linux.yml
-
-[macos_svg]: https://github.com/google/cpu_features/actions/workflows/amd64_macos.yml/badge.svg?branch=main
-[macos_link]: https://github.com/google/cpu_features/actions/workflows/amd64_macos.yml
-
-[windows_svg]: https://github.com/google/cpu_features/actions/workflows/amd64_windows.yml/badge.svg?branch=main
-[windows_link]: https://github.com/google/cpu_features/actions/workflows/amd64_windows.yml
-
-## Makefile/Docker testing
-To test the build on various distro, we are using docker containers and a Makefile for orchestration.
-
-pros:
-* You are independent of third party CI runner config
-  (e.g. [github action virtual-environnments](https://github.com/actions/virtual-environments)).
-* You can run it locally on your linux system.
-* Most CI provide runners with docker and Makefile installed.
-
-cons:
-* Only GNU/Linux distro supported.
-
-### Usage
-To get the help simply type:
-```sh
-make
-```
-
-note: you can also use from top directory
-```sh
-make --directory=ci
-```
-
-### Example
-For example to test mips32 inside an container:
-```sh
-make mips32_test
-```
-
-### Docker layers
-Dockerfile is splitted in several stages.
-
-![docker](doc/docker.svg)
-
-
-## Makefile/Vagrant testing
-To test build for FreeBSD we are using Vagrant and VirtualBox box.
-
-This is similar to the docker stuff but use `vagrant` as `docker` cli and
-VirtuaBox to replace the docker engine daemon.
diff --git a/cmake/README.md b/cmake/README.md
index b2d96c4..de33b23 100644
--- a/cmake/README.md
+++ b/cmake/README.md
@@ -17,7 +17,7 @@
 2- You can then use the cmake command `add_subdirectory()` to include
 cpu_features directly and use the `cpu_features` target in your project.
 
-3- Add the `cpu_features` target to the `target_link_libraries()` section of
+3- Add the `CpuFeature::cpu_features` target to the `target_link_libraries()` section of
 your executable or of your library.
 
 ## Disabling tests
diff --git a/ci/Makefile b/cmake/ci/Makefile
similarity index 93%
rename from ci/Makefile
rename to cmake/ci/Makefile
index 47ea30a..f655fc3 100644
--- a/ci/Makefile
+++ b/cmake/ci/Makefile
@@ -45,11 +45,19 @@
 	@echo -e "\t\t${BOLD}armeb-linux-gnueabihf${RESET} (linaro toolchain)"
 	@echo -e "\t\t${BOLD}armeb-linux-gnueabi${RESET} (linaro toolchain)"
 	@echo -e "\t\t${BOLD}aarch64-linux-gnu${RESET} (linaro toolchain)"
+	@echo -e "\t\t${BOLD}aarch64${RESET} (bootlin toolchain)"
 	@echo -e "\t\t${BOLD}aarch64_be-linux-gnu${RESET} (linaro toolchain)"
+	@echo -e "\t\t${BOLD}aarch64be${RESET} (bootlin toolchain)"
 	@echo -e "\t\t${BOLD}mips32${RESET} (codespace toolchain)"
 	@echo -e "\t\t${BOLD}mips64${RESET} (codespace toolchain)"
 	@echo -e "\t\t${BOLD}mips32el${RESET} (codespace toolchain)"
 	@echo -e "\t\t${BOLD}mips64el${RESET} (codespace toolchain)"
+	@echo -e "\t\t${BOLD}ppc${RESET} (bootlin toolchain)"
+	@echo -e "\t\t${BOLD}ppc64${RESET} (bootlin toolchain)"
+	@echo -e "\t\t${BOLD}ppc64le${RESET} (bootlin toolchain)"
+	@echo -e "\t\t${BOLD}riscv32${RESET} (bootlin toolchain)"
+	@echo -e "\t\t${BOLD}riscv64${RESET} (bootlin toolchain)"
+	@echo -e "\t\t${BOLD}s390x${RESET} (bootlin toolchain)"
 	@echo
 	@echo -e "\tWith ${BOLD}<toolchain_stage>${RESET}:"
 	@echo -e "\t\t${BOLD}env${RESET}"
@@ -113,7 +121,7 @@
  --tag ${IMAGE}:amd64_$* \
  --target=$* \
  -f $< \
- ..
+ ../..
 
 #$(info Create targets: save_amd64 $(addprefix save_amd64_, $(STAGES)) (debug).)
 save_targets_amd64 = $(addprefix save_amd64_, $(STAGES))
@@ -143,9 +151,13 @@
 ## TOOLCHAIN ##
 ###############
 TOOLCHAIN_TARGETS = \
+ aarch64 aarch64be \
  arm-linux-gnueabihf armv8l-linux-gnueabihf arm-linux-gnueabi armeb-linux-gnueabihf armeb-linux-gnueabi \
  aarch64-linux-gnu aarch64_be-linux-gnu \
- mips32 mips32el mips64 mips64el
+ mips32 mips32el mips64 mips64el \
+ ppc ppc64 ppc64le \
+ riscv32 riscv64 \
+ s390x
 TOOLCHAIN_STAGES = env devel build test
 define toolchain-stage-target =
 #$$(info STAGE: $1)
@@ -160,7 +172,7 @@
  --build-arg TARGET=$$* \
  --target=$1 \
  -f $$< \
- ..
+ ../..
 
 #$$(info Create targets: save_toolchain_$1 $(addprefix save_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS))) (debug).)
 save_targets_toolchain_$1 = $(addprefix save_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS)))
diff --git a/cmake/ci/README.md b/cmake/ci/README.md
new file mode 100644
index 0000000..0d898d8
--- /dev/null
+++ b/cmake/ci/README.md
@@ -0,0 +1,40 @@
+## Makefile/Docker testing
+To test the build on various distro, we are using docker containers and a Makefile for orchestration.
+
+pros:
+* You are independent of third party CI runner config
+  (e.g. [github action virtual-environnments](https://github.com/actions/virtual-environments)).
+* You can run it locally on your linux system.
+* Most CI provide runners with docker and Makefile installed.
+
+cons:
+* Only GNU/Linux distro supported.
+
+### Usage
+To get the help simply type:
+```sh
+make
+```
+
+note: you can also use from top directory
+```sh
+make --directory=cmake/ci
+```
+
+### Example
+For example to test mips32 inside an container:
+```sh
+make mips32_test
+```
+
+### Docker layers
+Dockerfile is splitted in several stages.
+
+![docker](doc/docker.svg)
+
+
+## Makefile/Vagrant testing
+To test build for FreeBSD we are using Vagrant and VirtualBox box.
+
+This is similar to the docker stuff but use `vagrant` as `docker` cli and
+VirtuaBox to replace the docker engine daemon.
diff --git a/ci/doc/docker.dot b/cmake/ci/doc/docker.dot
similarity index 100%
rename from ci/doc/docker.dot
rename to cmake/ci/doc/docker.dot
diff --git a/ci/doc/docker.svg b/cmake/ci/doc/docker.svg
similarity index 100%
rename from ci/doc/docker.svg
rename to cmake/ci/doc/docker.svg
diff --git a/ci/doc/generate_image.sh b/cmake/ci/doc/generate_image.sh
similarity index 100%
rename from ci/doc/generate_image.sh
rename to cmake/ci/doc/generate_image.sh
diff --git a/ci/docker/amd64/Dockerfile b/cmake/ci/docker/amd64/Dockerfile
similarity index 98%
rename from ci/docker/amd64/Dockerfile
rename to cmake/ci/docker/amd64/Dockerfile
index 9b25e28..2cc3270 100644
--- a/ci/docker/amd64/Dockerfile
+++ b/cmake/ci/docker/amd64/Dockerfile
@@ -38,7 +38,7 @@
 
 FROM install_env AS install_devel
 WORKDIR /home/sample
-COPY ci/sample .
+COPY cmake/ci/sample .
 
 FROM install_devel AS install_build
 RUN cmake -S. -Bbuild
diff --git a/ci/docker/toolchain/Dockerfile b/cmake/ci/docker/toolchain/Dockerfile
similarity index 100%
rename from ci/docker/toolchain/Dockerfile
rename to cmake/ci/docker/toolchain/Dockerfile
diff --git a/ci/sample/CMakeLists.txt b/cmake/ci/sample/CMakeLists.txt
similarity index 100%
rename from ci/sample/CMakeLists.txt
rename to cmake/ci/sample/CMakeLists.txt
diff --git a/ci/sample/main.cpp b/cmake/ci/sample/main.cpp
similarity index 100%
rename from ci/sample/main.cpp
rename to cmake/ci/sample/main.cpp
diff --git a/ci/vagrant/freebsd/Vagrantfile b/cmake/ci/vagrant/freebsd/Vagrantfile
similarity index 86%
rename from ci/vagrant/freebsd/Vagrantfile
rename to cmake/ci/vagrant/freebsd/Vagrantfile
index 7ef7bfa..6234ff6 100644
--- a/ci/vagrant/freebsd/Vagrantfile
+++ b/cmake/ci/vagrant/freebsd/Vagrantfile
@@ -49,11 +49,11 @@
   #config.vm.synced_folder "../../..", "/home/vagrant/project"
   config.vm.synced_folder ".", "/vagrant", id: "vagrant-root", disabled: true
 
-  config.vm.provision "file", source: "../../../CMakeLists.txt", destination: "$HOME/project/"
-  config.vm.provision "file", source: "../../../cmake", destination: "$HOME/project/"
-  config.vm.provision "file", source: "../../../include", destination: "$HOME/project/"
-  config.vm.provision "file", source: "../../../src", destination: "$HOME/project/"
-  config.vm.provision "file", source: "../../../test", destination: "$HOME/project/"
+  config.vm.provision "file", source: "../../../../CMakeLists.txt", destination: "$HOME/project/"
+  config.vm.provision "file", source: "../../../../cmake", destination: "$HOME/project/"
+  config.vm.provision "file", source: "../../../../include", destination: "$HOME/project/"
+  config.vm.provision "file", source: "../../../../src", destination: "$HOME/project/"
+  config.vm.provision "file", source: "../../../../test", destination: "$HOME/project/"
 
   # Provider-specific configuration so you can fine-tune various
   # backing providers for Vagrant. These expose provider-specific options.
@@ -99,4 +99,9 @@
   cd project
   cmake --build build --target test -v
   SHELL
+  config.vm.provision "test", type: "shell", inline:<<-SHELL
+  set -x
+  cd project
+  cmake --build build --target install -v
+  SHELL
 end
diff --git a/include/cpu_features_macros.h b/include/cpu_features_macros.h
index 6a2f76a..215b567 100644
--- a/include/cpu_features_macros.h
+++ b/include/cpu_features_macros.h
@@ -39,7 +39,7 @@
 #define CPU_FEATURES_ARCH_ARM
 #endif
 
-#if defined(__aarch64__)
+#if (defined(__aarch64__) || defined(_M_ARM64))
 #define CPU_FEATURES_ARCH_AARCH64
 #endif
 
@@ -63,6 +63,26 @@
 #define CPU_FEATURES_ARCH_PPC
 #endif
 
+#if defined(__s390x__)
+#define CPU_FEATURES_ARCH_S390X
+#endif
+
+#if defined(__riscv)
+#define CPU_FEATURES_ARCH_RISCV
+#endif
+
+#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 32
+#define CPU_FEATURES_ARCH_RISCV32
+#endif
+
+#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64
+#define CPU_FEATURES_ARCH_RISCV64
+#endif
+
+#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 128
+#define CPU_FEATURES_ARCH_RISCV128
+#endif
+
 ////////////////////////////////////////////////////////////////////////////////
 // Os
 ////////////////////////////////////////////////////////////////////////////////
@@ -224,8 +244,121 @@
 #else
 #define CPU_FEATURES_COMPILED_MIPS_MSA 0
 #endif  //  defined(__mips_msa)
+#if defined(__mips3d)
+#define CPU_FEATURES_COMPILED_MIPS_MIPS3D 1
+#else
+#define CPU_FEATURES_COMPILED_MIPS_MIPS3D 0
+#endif
 #endif  //  defined(CPU_FEATURES_ARCH_MIPS)
 
+#if defined(CPU_FEATURES_ARCH_RISCV)
+#if defined(__riscv_e)
+#define CPU_FEATURES_COMPILED_RISCV_E 1
+#else
+#define CPU_FEATURES_COMPILED_RISCV_E 0
+#endif
+#if defined(__riscv_i)
+#define CPU_FEATURES_COMPILED_RISCV_I 1
+#else
+#define CPU_FEATURES_COMPILED_RISCV_I 0
+#endif
+#if defined(__riscv_m)
+#define CPU_FEATURES_COMPILED_RISCV_M 1
+#else
+#define CPU_FEATURES_COMPILED_RISCV_M 0
+#endif
+#if defined(__riscv_a)
+#define CPU_FEATURES_COMPILED_RISCV_A 1
+#else
+#define CPU_FEATURES_COMPILED_RISCV_A 0
+#endif
+#if defined(__riscv_f)
+#define CPU_FEATURES_COMPILED_RISCV_F 1
+#else
+#define CPU_FEATURES_COMPILED_RISCV_F 0
+#endif
+#if defined(__riscv_d)
+#define CPU_FEATURES_COMPILED_RISCV_D 1
+#else
+#define CPU_FEATURES_COMPILED_RISCV_D 0
+#endif
+#if defined(__riscv_q)
+#define CPU_FEATURES_COMPILED_RISCV_Q 1
+#else
+#define CPU_FEATURES_COMPILED_RISCV_Q 0
+#endif
+#if defined(__riscv_c)
+#define CPU_FEATURES_COMPILED_RISCV_C 1
+#else
+#define CPU_FEATURES_COMPILED_RISCV_C 0
+#endif
+#if defined(__riscv_v)
+#define CPU_FEATURES_COMPILED_RISCV_V 1
+#else
+#define CPU_FEATURES_COMPILED_RISCV_V 0
+#endif
+#if defined(__riscv_zba)
+#define CPU_FEATURES_COMPILED_RISCV_ZBA 1
+#else
+#define CPU_FEATURES_COMPILED_RISCV_ZBA 0
+#endif
+#if defined(__riscv_zbb)
+#define CPU_FEATURES_COMPILED_RISCV_ZBB 1
+#else
+#define CPU_FEATURES_COMPILED_RISCV_ZBB 0
+#endif
+#if defined(__riscv_zbc)
+#define CPU_FEATURES_COMPILED_RISCV_ZBC 1
+#else
+#define CPU_FEATURES_COMPILED_RISCV_ZBC 0
+#endif
+#if defined(__riscv_zbs)
+#define CPU_FEATURES_COMPILED_RISCV_ZBS 1
+#else
+#define CPU_FEATURES_COMPILED_RISCV_ZBS 0
+#endif
+#if defined(__riscv_zfh)
+#define CPU_FEATURES_COMPILED_RISCV_ZFH 1
+#else
+#define CPU_FEATURES_COMPILED_RISCV_ZFH 0
+#endif
+#if defined(__riscv_zfhmin)
+#define CPU_FEATURES_COMPILED_RISCV_ZFHMIN 1
+#else
+#define CPU_FEATURES_COMPILED_RISCV_ZFHMIN 0
+#endif
+#if defined(__riscv_zknd)
+#define CPU_FEATURES_COMPILED_RISCV_ZKND 1
+#else
+#define CPU_FEATURES_COMPILED_RISCV_ZKND 0
+#endif
+#if defined(__riscv_zkne)
+#define CPU_FEATURES_COMPILED_RISCV_ZKNE 1
+#else
+#define CPU_FEATURES_COMPILED_RISCV_ZKNE 0
+#endif
+#if defined(__riscv_zknh)
+#define CPU_FEATURES_COMPILED_RISCV_ZKNH 1
+#else
+#define CPU_FEATURES_COMPILED_RISCV_ZKNH 0
+#endif
+#if defined(__riscv_zksed)
+#define CPU_FEATURES_COMPILED_RISCV_ZKSED 1
+#else
+#define CPU_FEATURES_COMPILED_RISCV_ZKSED 0
+#endif
+#if defined(__riscv_zksh)
+#define CPU_FEATURES_COMPILED_RISCV_ZKSH 1
+#else
+#define CPU_FEATURES_COMPILED_RISCV_ZKSH 0
+#endif
+#if defined(__riscv_zkr)
+#define CPU_FEATURES_COMPILED_RISCV_ZKR 1
+#else
+#define CPU_FEATURES_COMPILED_RISCV_ZKR 0
+#endif
+#endif  //  defined(CPU_FEATURES_ARCH_RISCV)
+
 ////////////////////////////////////////////////////////////////////////////////
 // Utils
 ////////////////////////////////////////////////////////////////////////////////
@@ -242,6 +375,8 @@
 // Communicates to the compiler that the function is now deprecated
 #if defined(CPU_FEATURES_COMPILER_CLANG) || defined(CPU_FEATURES_COMPILER_GCC)
 #define CPU_FEATURES_DEPRECATED(message) __attribute__((deprecated(message)))
+#elif defined(CPU_FEATURES_COMPILER_MSC)
+#define CPU_FEATURES_DEPRECATED(message) __declspec(deprecated(message))
 #else
 #define CPU_FEATURES_DEPRECATED(message)
 #endif
diff --git a/include/cpuinfo_aarch64.h b/include/cpuinfo_aarch64.h
index 1b57d21..d124b5f 100644
--- a/include/cpuinfo_aarch64.h
+++ b/include/cpuinfo_aarch64.h
@@ -12,6 +12,100 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+////////////////////////////////////////////////////////////////////////////////
+// A note on Windows AArch64 implementation
+////////////////////////////////////////////////////////////////////////////////
+
+// Getting cpu info via EL1 system registers is not possible, so we delegate it
+// to the Windows API (i.e., IsProcessorFeaturePresent and GetNativeSystemInfo).
+// The `implementer`, `variant` and `part` fields of the `Aarch64Info` struct
+// are not used, so they are set to 0. To get `revision` we use
+// `wProcessorRevision` from `SYSTEM_INFO`.
+//
+// Cryptographic Extension:
+// -----------------------------------------------------------------------------
+// According to documentation Arm Architecture Reference Manual for
+// A-profile architecture. A2.3 The Armv8 Cryptographic Extension. The Armv8.0
+// Cryptographic Extension provides instructions for the acceleration of
+// encryption and decryption, and includes the following features: FEAT_AES,
+// FEAT_PMULL, FEAT_SHA1, FEAT_SHA256.
+// see: https://developer.arm.com/documentation/ddi0487/latest
+//
+// We use `PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE` to detect all Armv8.0 crypto
+// features. This value reports all features or nothing, so even if you only
+// have support FEAT_AES and FEAT_PMULL, it will still return false.
+//
+// From Armv8.2, an implementation of the Armv8.0 Cryptographic Extension can
+// include either or both of:
+//
+// • The AES functionality, including support for multiplication of 64-bit
+//   polynomials. The ID_AA64ISAR0_EL1.AES field indicates whether this
+//   functionality is supported.
+// • The SHA1 and SHA2-256 functionality. The ID_AA64ISAR0_EL1.{SHA2, SHA1}
+//   fields indicate whether this functionality is supported.
+//
+// ID_AA64ISAR0_EL1.AES, bits [7:4]:
+// Indicates support for AES instructions in AArch64 state. Defined values are:
+// - 0b0000 No AES instructions implemented.
+// - 0b0001 AESE, AESD, AESMC, and AESIMC instructions implemented.
+// - 0b0010 As for 0b0001, plus PMULL/PMULL2 instructions operating on 64-bit
+//   data quantities.
+//
+// FEAT_AES implements the functionality identified by the value 0b0001.
+// FEAT_PMULL implements the functionality identified by the value 0b0010.
+// From Armv8, the permitted values are 0b0000 and 0b0010.
+//
+// ID_AA64ISAR0_EL1.SHA1, bits [11:8]:
+// Indicates support for SHA1 instructions in AArch64 state. Defined values are:
+// - 0b0000 No SHA1 instructions implemented.
+// - 0b0001 SHA1C, SHA1P, SHA1M, SHA1H, SHA1SU0, and SHA1SU1 instructions
+//   implemented.
+//
+// FEAT_SHA1 implements the functionality identified by the value 0b0001.
+// From Armv8, the permitted values are 0b0000 and 0b0001.
+// If the value of ID_AA64ISAR0_EL1.SHA2 is 0b0000, this field must have the
+// value 0b0000.
+//
+// ID_AA64ISAR0_EL1.SHA2, bits [15:12]:
+// Indicates support for SHA2 instructions in AArch64 state. Defined values are:
+// - 0b0000 No SHA2 instructions implemented.
+// - 0b0001 Implements instructions: SHA256H, SHA256H2, SHA256SU0, and
+//   SHA256SU1.
+// - 0b0010 Implements instructions:
+//          • SHA256H, SHA256H2, SHA256SU0, and SHA256SU1.
+//          • SHA512H, SHA512H2, SHA512SU0, and SHA512SU1.
+//
+// FEAT_SHA256 implements the functionality identified by the value 0b0001.
+// FEAT_SHA512 implements the functionality identified by the value 0b0010.
+//
+// In Armv8, the permitted values are 0b0000 and 0b0001.
+// From Armv8.2, the permitted values are 0b0000, 0b0001, and 0b0010.
+//
+// If the value of ID_AA64ISAR0_EL1.SHA1 is 0b0000, this field must have the
+// value 0b0000.
+//
+// If the value of this field is 0b0010, ID_AA64ISAR0_EL1.SHA3
+// must have the value 0b0001.
+//
+// Other cryptographic features that we cannot detect such as sha512, sha3, sm3,
+// sm4, sveaes, svepmull, svesha3, svesm4 we set to 0.
+//
+// FP/SIMD:
+// -----------------------------------------------------------------------------
+// FP/SIMD must be implemented on all Armv8.0 implementations, but
+// implementations targeting specialized markets may support the following
+// combinations:
+//
+// • No NEON or floating-point.
+// • Full floating-point and SIMD support with exception trapping.
+// • Full floating-point and SIMD support without exception trapping.
+//
+// ref:
+// https://developer.arm.com/documentation/den0024/a/AArch64-Floating-point-and-NEON
+//
+// So, we use `PF_ARM_VFP_32_REGISTERS_AVAILABLE`,
+// `PF_ARM_NEON_INSTRUCTIONS_AVAILABLE` to detect `asimd` and `fp`
+
 #ifndef CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_
 #define CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_
 
@@ -72,16 +166,20 @@
   int rng : 1;         // True random number generator support.
   int bti : 1;         // Branch target identification.
   int mte : 1;         // Memory tagging extension.
+  int ecv : 1;         // Enhanced counter virtualization.
+  int afp : 1;         // Alternate floating-point behaviour.
+  int rpres : 1;       // 12-bit reciprocal (square root) estimate precision.
 
   // Make sure to update Aarch64FeaturesEnum below if you add a field here.
 } Aarch64Features;
 
 typedef struct {
   Aarch64Features features;
-  int implementer;
-  int variant;
-  int part;
-  int revision;
+  int implementer;  // We set 0 for Windows.
+  int variant;      // We set 0 for Windows.
+  int part;         // We set 0 for Windows.
+  int revision;     // We use GetNativeSystemInfo to get processor revision for
+                    // Windows.
 } Aarch64Info;
 
 Aarch64Info GetAarch64Info(void);
@@ -141,6 +239,9 @@
   AARCH64_RNG,
   AARCH64_BTI,
   AARCH64_MTE,
+  AARCH64_ECV,
+  AARCH64_AFP,
+  AARCH64_RPRES,
   AARCH64_LAST_,
 } Aarch64FeaturesEnum;
 
diff --git a/include/cpuinfo_mips.h b/include/cpuinfo_mips.h
index 9e5e7fc..321d3c8 100644
--- a/include/cpuinfo_mips.h
+++ b/include/cpuinfo_mips.h
@@ -21,11 +21,20 @@
 CPU_FEATURES_START_CPP_NAMESPACE
 
 typedef struct {
-  int msa : 1;  // MIPS SIMD Architecture
-                // https://www.mips.com/products/architectures/ase/simd/
-  int eva : 1;  // Enhanced Virtual Addressing
-                // https://www.mips.com/products/architectures/mips64/
-  int r6 : 1;   // True if is release 6 of the processor.
+  int msa : 1;    // MIPS SIMD Architecture
+                  // https://www.mips.com/products/architectures/ase/simd/
+  int eva : 1;    // Enhanced Virtual Addressing
+                  // https://www.mips.com/products/architectures/mips64/
+  int r6 : 1;     // True if is release 6 of the processor.
+  int mips16 : 1; // Compressed instructions
+  int mdmx : 1;   // MIPS Digital Media Extension
+  int mips3d : 1; // 3D graphics acceleration
+                  // MIPS(r) Architecture for Programmers, Volume IV-c
+  int smart : 1;  // Smart-card cryptography
+                  // MIPS(r) Architecture for Programmers, Volume IV-d
+  int dsp : 1;    // Digital Signal Processing
+                  // MIPS(r) Architecture for Programmers, Volume IV-e
+                  // https://www.mips.com/products/architectures/ase/dsp/
 
   // Make sure to update MipsFeaturesEnum below if you add a field here.
 } MipsFeatures;
@@ -43,6 +52,11 @@
   MIPS_MSA,
   MIPS_EVA,
   MIPS_R6,
+  MIPS_MIPS16,
+  MIPS_MDMX,
+  MIPS_MIPS3D,
+  MIPS_SMART,
+  MIPS_DSP,
   MIPS_LAST_,
 } MipsFeaturesEnum;
 
diff --git a/include/cpuinfo_riscv.h b/include/cpuinfo_riscv.h
new file mode 100644
index 0000000..1fa7aa5
--- /dev/null
+++ b/include/cpuinfo_riscv.h
@@ -0,0 +1,72 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CPU_FEATURES_INCLUDE_CPUINFO_RISCV_H_
+#define CPU_FEATURES_INCLUDE_CPUINFO_RISCV_H_
+
+#include "cpu_features_cache_info.h"
+#include "cpu_features_macros.h"
+
+#if !defined(CPU_FEATURES_ARCH_RISCV)
+#error "Including cpuinfo_riscv.h from a non-riscv target."
+#endif
+
+CPU_FEATURES_START_CPP_NAMESPACE
+
+typedef struct {
+  // Base
+  int RV32I : 1;  // Base Integer Instruction Set, 32-bit
+  int RV64I : 1;  // Base Integer Instruction Set, 64-bit
+
+  // Extension
+  int M : 1;         // Standard Extension for Integer Multiplication/Division
+  int A : 1;         // Standard Extension for Atomic Instructions
+  int F : 1;         // Standard Extension for Single-Precision Floating-Point
+  int D : 1;         // Standard Extension for Double-Precision Floating-Point
+  int Q : 1;         // Standard Extension for Quad-Precision Floating-Point
+  int C : 1;         // Standard Extension for Compressed Instructions
+  int V : 1;         // Standard Extension for Vector Instructions
+  int Zicsr : 1;     // Control and Status Register (CSR)
+  int Zifencei : 1;  // Instruction-Fetch Fence
+} RiscvFeatures;
+
+typedef struct {
+  RiscvFeatures features;
+  char uarch[64];   // 0 terminated string
+  char vendor[64];  // 0 terminated string
+} RiscvInfo;
+
+typedef enum {
+  RISCV_RV32I,
+  RISCV_RV64I,
+  RISCV_M,
+  RISCV_A,
+  RISCV_F,
+  RISCV_D,
+  RISCV_Q,
+  RISCV_C,
+  RISCV_V,
+  RISCV_Zicsr,
+  RISCV_Zifencei,
+  RISCV_LAST_,
+} RiscvFeaturesEnum;
+
+RiscvInfo GetRiscvInfo(void);
+int GetRiscvFeaturesEnumValue(const RiscvFeatures* features,
+                              RiscvFeaturesEnum value);
+const char* GetRiscvFeaturesEnumName(RiscvFeaturesEnum);
+
+CPU_FEATURES_END_CPP_NAMESPACE
+
+#endif  // CPU_FEATURES_INCLUDE_CPUINFO_RISCV_H_
diff --git a/include/cpuinfo_s390x.h b/include/cpuinfo_s390x.h
new file mode 100644
index 0000000..48864de
--- /dev/null
+++ b/include/cpuinfo_s390x.h
@@ -0,0 +1,108 @@
+// Copyright 2022 IBM
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CPU_FEATURES_INCLUDE_CPUINFO_S390X_H_
+#define CPU_FEATURES_INCLUDE_CPUINFO_S390X_H_
+
+#include "cpu_features_cache_info.h"
+#include "cpu_features_macros.h"
+
+CPU_FEATURES_START_CPP_NAMESPACE
+
+typedef struct {
+  int esan3: 1;     // instructions named N3, "backported" to esa-mode
+  int zarch: 1;     // z/Architecture mode active
+  int stfle: 1;     // store-facility-list-extended
+  int msa: 1;       // message-security assist
+  int ldisp: 1;     // long-displacement
+  int eimm: 1;      // extended-immediate
+  int dfp: 1;       // decimal floating point & perform floating point operation
+  int edat: 1;      // huge page support
+  int etf3eh: 1;    // extended-translation facility 3 enhancement
+  int highgprs: 1;  // 64-bit register support for 31-bit processes
+  int te: 1;        // transactional execution
+  int vx: 1;        // vector extension facility
+  int vxd: 1;       // vector-packed-decimal facility
+  int vxe: 1;       // vector-enhancement facility 1
+  int gs: 1;        // guarded-storage facility
+  int vxe2: 1;      // vector-enhancements facility 2
+  int vxp: 1;       // vector-packed-decimal-enhancement facility
+  int sort: 1;      // enhanced-sort facility
+  int dflt: 1;      // deflate-conversion facility
+  int vxp2: 1;      // vector-packed-decimal-enhancement facility 2
+  int nnpa: 1;      // neural network processing assist facility
+  int pcimio: 1;    // PCI mio facility
+  int sie: 1;       // virtualization support
+
+  // Make sure to update S390XFeaturesEnum below if you add a field here.
+} S390XFeatures;
+
+typedef struct {
+  S390XFeatures features;
+} S390XInfo;
+
+S390XInfo GetS390XInfo(void);
+
+typedef struct {
+  char platform[64];       // 0 terminated string
+} S390XPlatformTypeStrings;
+
+typedef struct {
+  int num_processors;      // -1 if N/A
+  S390XPlatformTypeStrings type;
+} S390XPlatformStrings;
+
+S390XPlatformStrings GetS390XPlatformStrings(void);
+
+////////////////////////////////////////////////////////////////////////////////
+// Introspection functions
+
+typedef enum {
+  S390_ESAN3,
+  S390_ZARCH,
+  S390_STFLE,
+  S390_MSA,
+  S390_LDISP,
+  S390_EIMM,
+  S390_DFP,
+  S390_EDAT,
+  S390_ETF3EH,
+  S390_HIGHGPRS,
+  S390_TE,
+  S390_VX,
+  S390_VXD,
+  S390_VXE,
+  S390_GS,
+  S390_VXE2,
+  S390_VXP,
+  S390_SORT,
+  S390_DFLT,
+  S390_VXP2,
+  S390_NNPA,
+  S390_PCIMIO,
+  S390_SIE,
+  S390X_LAST_,
+} S390XFeaturesEnum;
+
+int GetS390XFeaturesEnumValue(const S390XFeatures* features, S390XFeaturesEnum value);
+
+const char* GetS390XFeaturesEnumName(S390XFeaturesEnum);
+
+CPU_FEATURES_END_CPP_NAMESPACE
+
+#if !defined(CPU_FEATURES_ARCH_S390X)
+#error "Including cpuinfo_s390x.h from a non-s390x target."
+#endif
+
+#endif  // CPU_FEATURES_INCLUDE_CPUINFO_S390X_H_
diff --git a/include/cpuinfo_x86.h b/include/cpuinfo_x86.h
index 88daca4..e897500 100644
--- a/include/cpuinfo_x86.h
+++ b/include/cpuinfo_x86.h
@@ -60,6 +60,7 @@
   int sse4a : 1;
 
   int avx : 1;
+  int avx_vnni : 1;
   int avx2 : 1;
 
   int avx512f : 1;
@@ -76,11 +77,12 @@
   int avx512bitalg : 1;
   int avx512vpopcntdq : 1;
   int avx512_4vnniw : 1;
-  int avx512_4vbmi2 : 1;
+  int avx512_4vbmi2 : 1;  // Note: this is an alias to avx512_4fmaps.
   int avx512_second_fma : 1;
   int avx512_4fmaps : 1;
   int avx512_bf16 : 1;
   int avx512_vp2intersect : 1;
+  int avx512_fp16 : 1;
   int amx_bf16 : 1;
   int amx_tile : 1;
   int amx_int8 : 1;
@@ -97,6 +99,14 @@
   int dca : 1;
   int ss : 1;
   int adx : 1;
+  int lzcnt : 1;  // Note: this flag is called ABM for AMD, LZCNT for Intel.
+  int gfni : 1;
+  int movdiri : 1;
+  int movdir64b : 1;
+  int fs_rep_mov : 1;          // Fast short REP MOV
+  int fz_rep_movsb : 1;        // Fast zero-length REP MOVSB
+  int fs_rep_stosb : 1;        // Fast short REP STOSB
+  int fs_rep_cmpsb_scasb : 1;  // Fast short REP CMPSB/SCASB
   // Make sure to update X86FeaturesEnum below if you add a field here.
 } X86Features;
 
@@ -114,59 +124,64 @@
 
 // Returns cache hierarchy informations.
 // Can call cpuid multiple times.
-// Only works on Intel CPU at the moment.
 CacheInfo GetX86CacheInfo(void);
 
 typedef enum {
   X86_UNKNOWN,
-  ZHAOXIN_ZHANGJIANG,  // ZhangJiang
-  ZHAOXIN_WUDAOKOU,    // WuDaoKou
-  ZHAOXIN_LUJIAZUI,    // LuJiaZui
-  ZHAOXIN_YONGFENG,    // YongFeng
-  INTEL_80486,         // 80486
-  INTEL_P5,            // P5
-  INTEL_LAKEMONT,      // LAKEMONT
-  INTEL_CORE,          // CORE
-  INTEL_PNR,           // PENRYN
-  INTEL_NHM,           // NEHALEM
-  INTEL_ATOM_BNL,      // BONNELL
-  INTEL_WSM,           // WESTMERE
-  INTEL_SNB,           // SANDYBRIDGE
-  INTEL_IVB,           // IVYBRIDGE
-  INTEL_ATOM_SMT,      // SILVERMONT
-  INTEL_HSW,           // HASWELL
-  INTEL_BDW,           // BROADWELL
-  INTEL_SKL,           // SKYLAKE
-  INTEL_ATOM_GMT,      // GOLDMONT
-  INTEL_KBL,           // KABY LAKE
-  INTEL_CFL,           // COFFEE LAKE
-  INTEL_WHL,           // WHISKEY LAKE
-  INTEL_CNL,           // CANNON LAKE
-  INTEL_ICL,           // ICE LAKE
-  INTEL_TGL,           // TIGER LAKE
-  INTEL_SPR,           // SAPPHIRE RAPIDS
-  INTEL_ADL,           // ALDER LAKE
-  INTEL_RCL,           // ROCKET LAKE
-  INTEL_KNIGHTS_M,     // KNIGHTS MILL
-  INTEL_KNIGHTS_L,     // KNIGHTS LANDING
-  INTEL_KNIGHTS_F,     // KNIGHTS FERRY
-  INTEL_KNIGHTS_C,     // KNIGHTS CORNER
-  INTEL_NETBURST,      // NETBURST
-  AMD_HAMMER,          // K8  HAMMER
-  AMD_K10,             // K10
-  AMD_K11,             // K11
-  AMD_K12,             // K12
-  AMD_BOBCAT,          // K14 BOBCAT
-  AMD_PILEDRIVER,      // K15 PILEDRIVER
-  AMD_STREAMROLLER,    // K15 STREAMROLLER
-  AMD_EXCAVATOR,       // K15 EXCAVATOR
-  AMD_BULLDOZER,       // K15 BULLDOZER
-  AMD_JAGUAR,          // K16 JAGUAR
-  AMD_PUMA,            // K16 PUMA
-  AMD_ZEN,             // K17 ZEN
-  AMD_ZEN_PLUS,        // K17 ZEN+
-  AMD_ZEN2,            // K17 ZEN 2
-  AMD_ZEN3,            // K19 ZEN 3
+  ZHAOXIN_ZHANGJIANG,   // ZhangJiang
+  ZHAOXIN_WUDAOKOU,     // WuDaoKou
+  ZHAOXIN_LUJIAZUI,     // LuJiaZui
+  ZHAOXIN_YONGFENG,     // YongFeng
+  INTEL_80486,          // 80486
+  INTEL_P5,             // P5
+  INTEL_LAKEMONT,       // LAKEMONT
+  INTEL_CORE,           // CORE
+  INTEL_PNR,            // PENRYN
+  INTEL_NHM,            // NEHALEM
+  INTEL_ATOM_BNL,       // BONNELL
+  INTEL_WSM,            // WESTMERE
+  INTEL_SNB,            // SANDYBRIDGE
+  INTEL_IVB,            // IVYBRIDGE
+  INTEL_ATOM_SMT,       // SILVERMONT
+  INTEL_HSW,            // HASWELL
+  INTEL_BDW,            // BROADWELL
+  INTEL_SKL,            // SKYLAKE
+  INTEL_CCL,            // CASCADELAKE
+  INTEL_ATOM_GMT,       // GOLDMONT
+  INTEL_ATOM_GMT_PLUS,  // GOLDMONT+
+  INTEL_ATOM_TMT,       // TREMONT
+  INTEL_KBL,            // KABY LAKE
+  INTEL_CFL,            // COFFEE LAKE
+  INTEL_WHL,            // WHISKEY LAKE
+  INTEL_CML,            // COMET LAKE
+  INTEL_CNL,            // CANNON LAKE
+  INTEL_ICL,            // ICE LAKE
+  INTEL_TGL,            // TIGER LAKE
+  INTEL_SPR,            // SAPPHIRE RAPIDS
+  INTEL_ADL,            // ALDER LAKE
+  INTEL_RCL,            // ROCKET LAKE
+  INTEL_RPL,            // RAPTOR LAKE
+  INTEL_KNIGHTS_M,      // KNIGHTS MILL
+  INTEL_KNIGHTS_L,      // KNIGHTS LANDING
+  INTEL_KNIGHTS_F,      // KNIGHTS FERRY
+  INTEL_KNIGHTS_C,      // KNIGHTS CORNER
+  INTEL_NETBURST,       // NETBURST
+  AMD_HAMMER,           // K8  HAMMER
+  AMD_K10,              // K10
+  AMD_K11,              // K11
+  AMD_K12,              // K12 LLANO
+  AMD_BOBCAT,           // K14 BOBCAT
+  AMD_PILEDRIVER,       // K15 PILEDRIVER
+  AMD_STREAMROLLER,     // K15 STREAMROLLER
+  AMD_EXCAVATOR,        // K15 EXCAVATOR
+  AMD_BULLDOZER,        // K15 BULLDOZER
+  AMD_JAGUAR,           // K16 JAGUAR
+  AMD_PUMA,             // K16 PUMA
+  AMD_ZEN,              // K17 ZEN
+  AMD_ZEN_PLUS,         // K17 ZEN+
+  AMD_ZEN2,             // K17 ZEN 2
+  AMD_ZEN3,             // K19 ZEN 3
+  AMD_ZEN4,             // K19 ZEN 4
   X86_MICROARCHITECTURE_LAST_,
 } X86Microarchitecture;
 
@@ -211,6 +226,7 @@
   X86_SSE4_2,
   X86_SSE4A,
   X86_AVX,
+  X86_AVX_VNNI,
   X86_AVX2,
   X86_AVX512F,
   X86_AVX512CD,
@@ -226,11 +242,12 @@
   X86_AVX512BITALG,
   X86_AVX512VPOPCNTDQ,
   X86_AVX512_4VNNIW,
-  X86_AVX512_4VBMI2,
+  X86_AVX512_4VBMI2,  // Note: this is an alias to X86_AVX512_4FMAPS.
   X86_AVX512_SECOND_FMA,
   X86_AVX512_4FMAPS,
   X86_AVX512_BF16,
   X86_AVX512_VP2INTERSECT,
+  X86_AVX512_FP16,
   X86_AMX_BF16,
   X86_AMX_TILE,
   X86_AMX_INT8,
@@ -245,6 +262,14 @@
   X86_DCA,
   X86_SS,
   X86_ADX,
+  X86_LZCNT,
+  X86_GFNI,
+  X86_MOVDIRI,
+  X86_MOVDIR64B,
+  X86_FS_REP_MOV,
+  X86_FZ_REP_MOVSB,
+  X86_FS_REP_STOSB,
+  X86_FS_REP_CMPSB_SCASB,
   X86_LAST_,
 } X86FeaturesEnum;
 
diff --git a/include/internal/hwcaps.h b/include/internal/hwcaps.h
index d7fc782..3290cc9 100644
--- a/include/internal/hwcaps.h
+++ b/include/internal/hwcaps.h
@@ -80,6 +80,9 @@
 #define AARCH64_HWCAP2_RNG (1UL << 16)
 #define AARCH64_HWCAP2_BTI (1UL << 17)
 #define AARCH64_HWCAP2_MTE (1UL << 18)
+#define AARCH64_HWCAP2_ECV (1UL << 19)
+#define AARCH64_HWCAP2_AFP (1UL << 20)
+#define AARCH64_HWCAP2_RPRES (1UL << 21)
 
 // http://elixir.free-electrons.com/linux/latest/source/arch/arm/include/uapi/asm/hwcap.h
 #define ARM_HWCAP_SWP (1UL << 0)
@@ -114,6 +117,13 @@
 #define MIPS_HWCAP_R6 (1UL << 0)
 #define MIPS_HWCAP_MSA (1UL << 1)
 #define MIPS_HWCAP_CRC32 (1UL << 2)
+#define MIPS_HWCAP_MIPS16 (1UL << 3)
+#define MIPS_HWCAP_MDMX (1UL << 4)
+#define MIPS_HWCAP_MIPS3D (1UL << 5)
+#define MIPS_HWCAP_SMARTMIPS (1UL << 6)
+#define MIPS_HWCAP_DSP (1UL << 7)
+#define MIPS_HWCAP_DSP2 (1UL << 8)
+#define MIPS_HWCAP_DSP3 (1UL << 9)
 
 // http://elixir.free-electrons.com/linux/latest/source/arch/powerpc/include/uapi/asm/cputable.h
 #ifndef _UAPI__ASM_POWERPC_CPUTABLE_H
@@ -166,6 +176,46 @@
 #define PPC_FEATURE2_HTM_NO_SUSPEND 0x00080000
 #endif
 
+// https://elixir.bootlin.com/linux/v6.0-rc6/source/arch/s390/include/asm/elf.h
+#define HWCAP_S390_ESAN3        1
+#define HWCAP_S390_ZARCH        2
+#define HWCAP_S390_STFLE        4
+#define HWCAP_S390_MSA          8
+#define HWCAP_S390_LDISP        16
+#define HWCAP_S390_EIMM         32
+#define HWCAP_S390_DFP          64
+#define HWCAP_S390_HPAGE        128
+#define HWCAP_S390_ETF3EH       256
+#define HWCAP_S390_HIGH_GPRS    512
+#define HWCAP_S390_TE           1024
+#define HWCAP_S390_VX           2048
+#define HWCAP_S390_VXRS         HWCAP_S390_VX
+#define HWCAP_S390_VXD          4096
+#define HWCAP_S390_VXRS_BCD     HWCAP_S390_VXD
+#define HWCAP_S390_VXE          8192
+#define HWCAP_S390_VXRS_EXT     HWCAP_S390_VXE
+#define HWCAP_S390_GS           16384
+#define HWCAP_S390_VXRS_EXT2    32768
+#define HWCAP_S390_VXRS_PDE     65536
+#define HWCAP_S390_SORT         131072
+#define HWCAP_S390_DFLT         262144
+#define HWCAP_S390_VXRS_PDE2    524288
+#define HWCAP_S390_NNPA         1048576
+#define HWCAP_S390_PCI_MIO      2097152
+#define HWCAP_S390_SIE          4194304
+
+// https://elixir.bootlin.com/linux/latest/source/arch/riscv/include/uapi/asm/hwcap.h
+#define RISCV_HWCAP_32 0x32
+#define RISCV_HWCAP_64 0x64
+#define RISCV_HWCAP_128 0x128
+#define RISCV_HWCAP_M (1UL << ('M' - 'A'))
+#define RISCV_HWCAP_A (1UL << ('A' - 'A'))
+#define RISCV_HWCAP_F (1UL << ('F' - 'A'))
+#define RISCV_HWCAP_D (1UL << ('D' - 'A'))
+#define RISCV_HWCAP_Q (1UL << ('Q' - 'A'))
+#define RISCV_HWCAP_C (1UL << ('C' - 'A'))
+#define RISCV_HWCAP_V (1UL << ('V' - 'A'))
+
 typedef struct {
   unsigned long hwcaps;
   unsigned long hwcaps2;
diff --git a/include/internal/windows_utils.h b/include/internal/windows_utils.h
new file mode 100644
index 0000000..3348c52
--- /dev/null
+++ b/include/internal/windows_utils.h
@@ -0,0 +1,70 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CPU_FEATURES_INCLUDE_INTERNAL_WINDOWS_UTILS_H_
+#define CPU_FEATURES_INCLUDE_INTERNAL_WINDOWS_UTILS_H_
+
+#include "cpu_features_macros.h"
+
+#ifdef CPU_FEATURES_OS_WINDOWS
+
+#include <windows.h>  // IsProcessorFeaturePresent
+
+// modern WinSDK winnt.h contains newer features detection definitions
+#if !defined(PF_SSSE3_INSTRUCTIONS_AVAILABLE)
+#define PF_SSSE3_INSTRUCTIONS_AVAILABLE 36
+#endif
+
+#if !defined(PF_SSE4_1_INSTRUCTIONS_AVAILABLE)
+#define PF_SSE4_1_INSTRUCTIONS_AVAILABLE 37
+#endif
+
+#if !defined(PF_SSE4_2_INSTRUCTIONS_AVAILABLE)
+#define PF_SSE4_2_INSTRUCTIONS_AVAILABLE 38
+#endif
+
+#if !defined(PF_ARM_VFP_32_REGISTERS_AVAILABLE)
+#define PF_ARM_VFP_32_REGISTERS_AVAILABLE 18
+#endif
+
+#if !defined(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE)
+#define PF_ARM_NEON_INSTRUCTIONS_AVAILABLE 19
+#endif
+
+#if !defined(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE)
+#define PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE 30
+#endif
+
+#if !defined(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE)
+#define PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE 31
+#endif
+
+#if !defined(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE)
+#define PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE 34
+#endif
+
+#if !defined(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE)
+#define PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE 43
+#endif
+
+#if !defined(PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE)
+#define PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE 44
+#endif
+
+#if !defined(PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE)
+#define PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE 45
+#endif
+
+#endif  // CPU_FEATURES_OS_WINDOWS
+#endif  // CPU_FEATURES_INCLUDE_INTERNAL_WINDOWS_UTILS_H_
diff --git a/scripts/generate_badges.d b/scripts/generate_badges.d
new file mode 100644
index 0000000..bf5aa54
--- /dev/null
+++ b/scripts/generate_badges.d
@@ -0,0 +1,165 @@
+import std.algorithm : each, map, cartesianProduct, filter, joiner, sort, uniq;
+import std.array : array;
+import std.conv : to;
+import std.format;
+import std.range : chain, only;
+import std.stdio;
+import std.traits : EnumMembers;
+
+enum BuildSystem
+{
+    CMake,
+    Bazel
+}
+
+enum Cpu
+{
+    amd64,
+    AArch64,
+    ARM,
+    MIPS,
+    POWER,
+    RISCV,
+    s390x,
+}
+
+enum Os
+{
+    Linux,
+    FreeBSD,
+    MacOS,
+    Windows,
+}
+
+struct Badge
+{
+const:
+
+    Cpu cpu;
+    Os os;
+    BuildSystem build_system;
+
+    string id()
+    {
+        return format("%d%c%d", cast(uint)(os) + 1, cast(char)('a' + cpu), cast(uint)(build_system));
+    }
+
+    string disabled_image_ref()
+    {
+        return format("[d%d]", cast(uint)(build_system));
+    }
+
+    string link_ref()
+    {
+        return format("[l%s]", id());
+    }
+
+    string image_ref()
+    {
+        return format("[i%s]", id());
+    }
+
+    bool enabled()
+    {
+        final switch (build_system)
+        {
+        case BuildSystem.CMake:
+            return os == Os.Linux || cpu == Cpu.amd64;
+        case BuildSystem.Bazel:
+            return os == Os.Linux && cpu == Cpu.amd64;
+        }
+    }
+
+    string text()
+    {
+        if (enabled())
+            return format("[![]%s]%s", image_ref, link_ref);
+        return format("![]%s", disabled_image_ref);
+    }
+
+    string disabled_image_link()
+    {
+        return format("%s: https://img.shields.io/badge/%s-N%%2FA-lightgrey", disabled_image_ref, build_system);
+    }
+
+    string filename()
+    {
+        import std.uni : toLower;
+
+        return toLower(format("%s_%s_%s.yml", cpu, os, build_system));
+    }
+
+    string link_decl()
+    {
+        return format("%s: https://github.com/google/cpu_features/actions/workflows/%s", link_ref, filename());
+    }
+
+    string image_decl()
+    {
+        return format(
+            "%s: https://img.shields.io/github/actions/workflow/status/google/cpu_features/%s?branch=main&label=%s", image_ref, filename(), build_system);
+    }
+}
+
+auto tableHeader(in Cpu[] cpus)
+{
+    return chain(only("Os"), cpus.map!(to!string)).array;
+}
+
+auto tableAlignment(in Cpu[] cpus)
+{
+    return chain(only(":--"), cpus.map!(v => "--:")).array;
+}
+
+auto tableCell(Range)(in Os os, in Cpu cpu, Range badges)
+{
+    return badges
+        .filter!(b => b.cpu == cpu && b.os == os)
+        .map!(b => b.text())
+        .joiner("<br/>")
+        .to!string;
+}
+
+auto tableRow(Range)(in Os os, in Cpu[] cpus, Range badges)
+{
+    return chain(only(os.to!string), cpus.map!(cpu => tableCell(os, cpu, badges))).array;
+}
+
+auto tableRows(Range)(in Os[] oses, in Cpu[] cpus, Range badges)
+{
+    return oses.map!(os => tableRow(os, cpus, badges)).array;
+}
+
+auto table(Range)(in Os[] oses, in Cpu[] cpus, Range badges)
+{
+    return chain(only(tableHeader(cpus)), only(tableAlignment(cpus)), tableRows(oses, cpus, badges));
+}
+
+void main()
+{
+    immutable allCpus = [EnumMembers!Cpu];
+    immutable allOses = [EnumMembers!Os];
+    immutable allBuildSystems = [EnumMembers!BuildSystem];
+
+    auto badges = cartesianProduct(allCpus, allOses, allBuildSystems).map!(
+        t => Badge(t[0], t[1], t[2]));
+
+    writefln("%(|%-( %s |%) |\n%) |", table(allOses, allCpus, badges));
+    writeln();
+    badges
+        .filter!(b => !b.enabled)
+        .map!(b => b.disabled_image_link())
+        .array
+        .sort
+        .uniq
+        .each!writeln;
+
+    badges
+        .filter!(b => b.enabled)
+        .map!(b => [b.link_decl(), b.image_decl()])
+        .joiner()
+        .array
+        .sort
+        .uniq
+        .each!writeln;
+}
diff --git a/scripts/make_release.sh b/scripts/make_release.sh
index 01e85f7..25b59f9 100755
--- a/scripts/make_release.sh
+++ b/scripts/make_release.sh
@@ -69,4 +69,7 @@
 echo -e "${ACTION}Create new tag${NOCOLOR}"
 git tag ${GIT_TAG}
 
-echo -e "${FINISHED}Local release is ready. Run `git push origin --tags`${NOCOLOR}"
+echo -e "${FINISHED}Manual steps:${NOCOLOR}"
+echo -e "${FINISHED} - Push the tag upstream 'git push origin ${GIT_TAG}'${NOCOLOR}"
+echo -e "${FINISHED} - Create a new release https://github.com/google/cpu_features/releases/new${NOCOLOR}"
+echo -e "${FINISHED} - Update the Release Notes 'gren release --override'${NOCOLOR}"
diff --git a/scripts/run_integration.sh b/scripts/run_integration.sh
index 645cb6a..053ffa9 100755
--- a/scripts/run_integration.sh
+++ b/scripts/run_integration.sh
@@ -22,7 +22,7 @@
   if [[  ! -d "${DESTINATION}" ]] ; then
     echo "Downloading ${URL}..."
     local -r ARCHIVE_NAME=$(basename "${URL}")
-    test -f "${ARCHIVE_NAME}" || wget --no-verbose "${URL}"
+    [[ -f "${ARCHIVE_NAME}" ]] || wget --no-verbose "${URL}"
     extract "${ARCHIVE_NAME}"
     rm -f "${ARCHIVE_NAME}"
   fi
@@ -33,7 +33,7 @@
     >&2 echo 'QEMU is disabled !'
     return 0
   fi
-  local -r QEMU_VERSION=${QEMU_VERSION:=5.2.0}
+  local -r QEMU_VERSION=${QEMU_VERSION:=7.1.0}
   local -r QEMU_TARGET=${QEMU_ARCH}-linux-user
 
   if echo "${QEMU_VERSION} ${QEMU_TARGET}" | cmp --silent "${QEMU_INSTALL}/.build" -; then
@@ -70,11 +70,7 @@
     --disable-opengl \
     --disable-sdl \
     --disable-virglrenderer \
-    --disable-vte \
-    --enable-modules
-
-  # --static Not supported on Archlinux
-  # so we use --enable-modules
+    --disable-vte
 
   # wrapper on ninja
   make -j8
@@ -140,16 +136,107 @@
 QEMU_ARGS+=( -E LD_LIBRARY_PATH=/lib )
 }
 
+function expand_bootlin_config() {
+  # ref: https://toolchains.bootlin.com/
+  local -r GCC_DIR=${ARCHIVE_DIR}/${GCC_RELATIVE_DIR}
+
+  case "${TARGET}" in
+    "aarch64")
+      local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/aarch64/tarballs/aarch64--glibc--stable-2021.11-1.tar.bz2"
+      local -r GCC_PREFIX="aarch64"
+      ;;
+    "aarch64be")
+      local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/aarch64be/tarballs/aarch64be--glibc--stable-2021.11-1.tar.bz2"
+      local -r GCC_PREFIX="aarch64_be"
+      ;;
+    "ppc64le")
+      local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/powerpc64le-power8/tarballs/powerpc64le-power8--glibc--stable-2021.11-1.tar.bz2"
+      local -r GCC_PREFIX="powerpc64le"
+      ;;
+    "ppc64")
+      local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/powerpc64-power8/tarballs/powerpc64-power8--glibc--stable-2021.11-1.tar.bz2"
+      local -r GCC_PREFIX="powerpc64"
+      ;;
+    "ppc")
+      #local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/powerpc-e500mc/tarballs/powerpc-e500mc--glibc--stable-2021.11-1.tar.bz2"
+      local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/powerpc-440fp/tarballs/powerpc-440fp--glibc--stable-2021.11-1.tar.bz2"
+      local -r GCC_PREFIX="powerpc"
+      ;;
+    "riscv32")
+      local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/riscv32-ilp32d/tarballs/riscv32-ilp32d--glibc--bleeding-edge-2022.08-1.tar.bz2"
+      local -r GCC_PREFIX="riscv32"
+      ;;
+    "riscv64")
+      local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/riscv64-lp64d/tarballs/riscv64-lp64d--glibc--stable-2022.08-1.tar.bz2"
+      local -r GCC_PREFIX="riscv64"
+      ;;
+    "s390x")
+      local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/s390x-z13/tarballs/s390x-z13--glibc--stable-2022.08-1.tar.bz2"
+      local -r GCC_PREFIX="s390x"
+      ;;
+    *)
+      >&2 echo 'unknown power platform'
+      exit 1 ;;
+  esac
+
+  local -r TOOLCHAIN_RELATIVE_DIR="${TARGET}"
+  unpack "${TOOLCHAIN_URL}" "${TOOLCHAIN_RELATIVE_DIR}"
+  local -r EXTRACT_DIR="${ARCHIVE_DIR}/$(basename ${TOOLCHAIN_URL%.tar.bz2})"
+
+  local -r TOOLCHAIN_DIR=${ARCHIVE_DIR}/${TOOLCHAIN_RELATIVE_DIR}
+  if [[ -d "${EXTRACT_DIR}" ]]; then
+    mv "${EXTRACT_DIR}" "${TOOLCHAIN_DIR}"
+  fi
+
+  local -r SYSROOT_DIR="${TOOLCHAIN_DIR}/${GCC_PREFIX}-buildroot-linux-gnu/sysroot"
+  #local -r STAGING_DIR=${SYSROOT_DIR}-stage
+
+  # Write a Toolchain file
+  # note: This is manadatory to use a file in order to have the CMake variable
+  # 'CMAKE_CROSSCOMPILING' set to TRUE.
+  # ref: https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-linux
+  cat >"${TOOLCHAIN_FILE}" <<EOL
+set(CMAKE_SYSTEM_NAME Linux)
+set(CMAKE_SYSTEM_PROCESSOR ${GCC_PREFIX})
+
+set(CMAKE_SYSROOT ${SYSROOT_DIR})
+#set(CMAKE_STAGING_PREFIX ${STAGING_DIR})
+
+set(tools ${TOOLCHAIN_DIR})
+
+set(CMAKE_C_COMPILER \${tools}/bin/${GCC_PREFIX}-linux-gcc)
+set(CMAKE_C_FLAGS "${POWER_FLAGS}")
+set(CMAKE_CXX_COMPILER \${tools}/bin/${GCC_PREFIX}-linux-g++)
+set(CMAKE_CXX_FLAGS "${POWER_FLAGS} -L${SYSROOT_DIR}/lib")
+
+set(CMAKE_FIND_ROOT_PATH ${TOOLCHAIN_DIR})
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
+EOL
+
+CMAKE_ADDITIONAL_ARGS+=( -DCMAKE_TOOLCHAIN_FILE="${TOOLCHAIN_FILE}" )
+QEMU_ARGS+=( -L "${SYSROOT_DIR}" )
+QEMU_ARGS+=( -E LD_PRELOAD="${SYSROOT_DIR}/usr/lib/libstdc++.so.6:${SYSROOT_DIR}/lib/libgcc_s.so.1" )
+}
+
 function expand_codescape_config() {
+  # https://www.mips.com/develop/tools/codescape-mips-sdk/mips-toolchain-configurations/
+  # mips-mti: MIPS32R6 and MIPS64R6
+  # mips-img: MIPS32R2 and MIPS64R2
+
   # ref: https://codescape.mips.com/components/toolchain/2020.06-01/downloads.html
-  # ref: https://codescape.mips.com/components/toolchain/2019.02-04/downloads.html
   local -r DATE=2020.06-01
-  #local -r DATE=2019.02-04
   local -r CODESCAPE_URL=https://codescape.mips.com/components/toolchain/${DATE}/Codescape.GNU.Tools.Package.${DATE}.for.MIPS.MTI.Linux.CentOS-6.x86_64.tar.gz
-  #local -r CODESCAPE_URL=https://codescape.mips.com/components/toolchain/${DATE}/Codescape.GNU.Tools.Package.${DATE}.for.MIPS.IMG.Linux.CentOS-6.x86_64.tar.gz
-  local -r GCC_URL=${CODESCAPE_URL}
   local -r GCC_RELATIVE_DIR="mips-mti-linux-gnu/${DATE}"
+
+  # ref: https://codescape.mips.com/components/toolchain/2019.02-04/downloads.html
+  #local -r DATE=2019.02-04
+  #local -r CODESCAPE_URL=https://codescape.mips.com/components/toolchain/${DATE}/Codescape.GNU.Tools.Package.${DATE}.for.MIPS.IMG.Linux.CentOS-6.x86_64.tar.gz
   #local -r GCC_RELATIVE_DIR="mips-img-linux-gnu/${DATE}"
+
+  local -r GCC_URL=${CODESCAPE_URL}
   unpack "${GCC_URL}" "${GCC_RELATIVE_DIR}"
 
   local -r GCC_DIR=${ARCHIVE_DIR}/${GCC_RELATIVE_DIR}
@@ -174,12 +261,14 @@
     "mips64")
       MIPS_FLAGS="-EB -mips64r6 -mabi=64"
       FLAVOUR="mips-r6-hard"
+      #MIPS_FLAGS="-EB -mips64r2 -mabi=64"
       #FLAVOUR="mips-r2-hard"
       LIBC_DIR_SUFFIX="lib64"
       ;;
     "mips64el")
       MIPS_FLAGS="-EL -mips64r6 -mabi=64"
       FLAVOUR="mipsel-r6-hard"
+      #MIPS_FLAGS="-EL -mips64r2 -mabi=64"
       #FLAVOUR="mipsel-r2-hard"
       LIBC_DIR_SUFFIX="lib64"
       ;;
@@ -203,13 +292,17 @@
 
 set(tools ${GCC_DIR})
 
+# R6
 set(CMAKE_C_COMPILER \${tools}/bin/mips-mti-linux-gnu-gcc)
-#set(CMAKE_C_COMPILER \${tools}/bin/mips-img-linux-gnu-gcc)
 set(CMAKE_C_FLAGS "${MIPS_FLAGS}")
-
 set(CMAKE_CXX_COMPILER \${tools}/bin/mips-mti-linux-gnu-g++)
+set(CMAKE_CXX_FLAGS "${MIPS_FLAGS} -L${SYSROOT_DIR}/usr/lib64")
+
+# R2
+#set(CMAKE_C_COMPILER \${tools}/bin/mips-img-linux-gnu-gcc)
+#set(CMAKE_C_FLAGS "${MIPS_FLAGS}")
 #set(CMAKE_CXX_COMPILER \${tools}/bin/mips-img-linux-gnu-g++)
-set(CMAKE_CXX_FLAGS "${MIPS_FLAGS}")
+#set(CMAKE_CXX_FLAGS "${MIPS_FLAGS}")
 
 set(CMAKE_FIND_ROOT_PATH ${GCC_DIR})
 set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
@@ -244,10 +337,15 @@
   RUN_CMD="${QEMU_INSTALL}/bin/qemu-${QEMU_ARCH} ${QEMU_ARGS[*]}"
 
   cd "${BUILD_DIR}" || exit 2
+  declare -a TEST_BINARIES=()
+  TEST_BINARIES+=($(find "${BUILD_DIR}"/test -executable -type f))
+  TEST_BINARIES+=($(find "${BUILD_DIR}" -maxdepth 1 -executable -type f))
   set -x
-  for test_binary in "${BUILD_DIR}"/list_cpu_feature* ; do
+  set -e
+  for test_binary in ${TEST_BINARIES[*]} ; do
       ${RUN_CMD} "${test_binary}"
   done
+  set +e
   set +x
 }
 
@@ -264,11 +362,16 @@
 \tYou MUST define the following variables before running this script:
 \t* TARGET:
 \t\tx86_64
-\t\taarch64-linux-gnu aarch64_be-linux-gnu
-\t\tarm-linux-gnueabihf armv8l-linux-gnueabihf arm-linux-gnueabi
-\t\tarmeb-linux-gnueabihf armeb-linux-gnueabi
-\t\tmips32 mips32el
-\t\tmips64 mips64el
+\t\taarch64 aarch64be (bootlin)
+\t\taarch64-linux-gnu aarch64_be-linux-gnu (linaro)
+\t\tarm-linux-gnueabihf armv8l-linux-gnueabihf arm-linux-gnueabi (linaro)
+\t\tarmeb-linux-gnueabihf armeb-linux-gnueabi (linaro)
+\t\tmips32 mips32el (codespace)
+\t\tmips64 mips64el (codespace)
+\t\tppc (bootlin)
+\t\tppc64 ppc64le (bootlin)
+\t\triscv32 riscv64 (bootlin)
+\t\ts390x (bootlin)
 
 OPTIONS
 \t-h --help: show this help text
@@ -326,7 +429,13 @@
       declare -r QEMU_ARCH=aarch64 ;;
     aarch64_be-linux-gnu)
       expand_linaro_config
-      declare -r QEMU_ARCH=DISABLED ;;
+      declare -r QEMU_ARCH=aarch64_be ;;
+    aarch64)
+      expand_bootlin_config
+      declare -r QEMU_ARCH=aarch64 ;;
+    aarch64be)
+      expand_bootlin_config
+      declare -r QEMU_ARCH=aarch64_be ;;
     mips32)
       expand_codescape_config
       declare -r QEMU_ARCH=mips ;;
@@ -339,6 +448,24 @@
     mips64el)
       expand_codescape_config
       declare -r QEMU_ARCH=mips64el ;;
+    ppc64le)
+      expand_bootlin_config
+      declare -r QEMU_ARCH=ppc64le ;;
+    ppc64)
+      expand_bootlin_config
+      declare -r QEMU_ARCH=ppc64 ;;
+    ppc)
+      expand_bootlin_config
+      declare -r QEMU_ARCH=ppc ;;
+    riscv32)
+      expand_bootlin_config
+      declare -r QEMU_ARCH=riscv32 ;;
+    riscv64)
+      expand_bootlin_config
+      declare -r QEMU_ARCH=riscv64 ;;
+    s390x)
+      expand_bootlin_config
+      declare -r QEMU_ARCH=s390x ;;
     *)
       >&2 echo "Unknown TARGET '${TARGET}'..."
       exit 1 ;;
diff --git a/src/impl_aarch64_linux_or_android.c b/src/impl_aarch64_linux_or_android.c
index 745beb9..ef923d9 100644
--- a/src/impl_aarch64_linux_or_android.c
+++ b/src/impl_aarch64_linux_or_android.c
@@ -74,7 +74,10 @@
   LINE(AARCH64_DGH, dgh, "dgh", 0, AARCH64_HWCAP2_DGH)                     \
   LINE(AARCH64_RNG, rng, "rng", 0, AARCH64_HWCAP2_RNG)                     \
   LINE(AARCH64_BTI, bti, "bti", 0, AARCH64_HWCAP2_BTI)                     \
-  LINE(AARCH64_MTE, mte, "mte", 0, AARCH64_HWCAP2_MTE)
+  LINE(AARCH64_MTE, mte, "mte", 0, AARCH64_HWCAP2_MTE)                     \
+  LINE(AARCH64_ECV, ecv, "ecv", 0, AARCH64_HWCAP2_ECV)                     \
+  LINE(AARCH64_AFP, afp, "afp", 0, AARCH64_HWCAP2_AFP)                     \
+  LINE(AARCH64_RPRES, rpres, "rpres", 0, AARCH64_HWCAP2_RPRES)
 #define INTROSPECTION_PREFIX Aarch64
 #define INTROSPECTION_ENUM_PREFIX AARCH64
 #include "define_introspection_and_hwcaps.inl"
diff --git a/src/impl_aarch64_windows.c b/src/impl_aarch64_windows.c
new file mode 100644
index 0000000..f103909
--- /dev/null
+++ b/src/impl_aarch64_windows.c
@@ -0,0 +1,138 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cpu_features_macros.h"
+
+#ifdef CPU_FEATURES_ARCH_AARCH64
+#ifdef CPU_FEATURES_OS_WINDOWS
+
+#include "cpuinfo_aarch64.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// Definitions for introspection.
+////////////////////////////////////////////////////////////////////////////////
+#define INTROSPECTION_TABLE                  \
+  LINE(AARCH64_FP, fp, , , )                 \
+  LINE(AARCH64_ASIMD, asimd, , , )           \
+  LINE(AARCH64_EVTSTRM, evtstrm, , , )       \
+  LINE(AARCH64_AES, aes, , , )               \
+  LINE(AARCH64_PMULL, pmull, , , )           \
+  LINE(AARCH64_SHA1, sha1, , , )             \
+  LINE(AARCH64_SHA2, sha2, , , )             \
+  LINE(AARCH64_CRC32, crc32, , , )           \
+  LINE(AARCH64_ATOMICS, atomics, , , )       \
+  LINE(AARCH64_FPHP, fphp, , , )             \
+  LINE(AARCH64_ASIMDHP, asimdhp, , , )       \
+  LINE(AARCH64_CPUID, cpuid, , , )           \
+  LINE(AARCH64_ASIMDRDM, asimdrdm, , , )     \
+  LINE(AARCH64_JSCVT, jscvt, , , )           \
+  LINE(AARCH64_FCMA, fcma, , , )             \
+  LINE(AARCH64_LRCPC, lrcpc, , , )           \
+  LINE(AARCH64_DCPOP, dcpop, , , )           \
+  LINE(AARCH64_SHA3, sha3, , , )             \
+  LINE(AARCH64_SM3, sm3, , , )               \
+  LINE(AARCH64_SM4, sm4, , , )               \
+  LINE(AARCH64_ASIMDDP, asimddp, , , )       \
+  LINE(AARCH64_SHA512, sha512, , , )         \
+  LINE(AARCH64_SVE, sve, , , )               \
+  LINE(AARCH64_ASIMDFHM, asimdfhm, , , )     \
+  LINE(AARCH64_DIT, dit, , , )               \
+  LINE(AARCH64_USCAT, uscat, , , )           \
+  LINE(AARCH64_ILRCPC, ilrcpc, , , )         \
+  LINE(AARCH64_FLAGM, flagm, , , )           \
+  LINE(AARCH64_SSBS, ssbs, , , )             \
+  LINE(AARCH64_SB, sb, , , )                 \
+  LINE(AARCH64_PACA, paca, , , )             \
+  LINE(AARCH64_PACG, pacg, , , )             \
+  LINE(AARCH64_DCPODP, dcpodp, , , )         \
+  LINE(AARCH64_SVE2, sve2, , , )             \
+  LINE(AARCH64_SVEAES, sveaes, , , )         \
+  LINE(AARCH64_SVEPMULL, svepmull, , , )     \
+  LINE(AARCH64_SVEBITPERM, svebitperm, , , ) \
+  LINE(AARCH64_SVESHA3, svesha3, , , )       \
+  LINE(AARCH64_SVESM4, svesm4, , , )         \
+  LINE(AARCH64_FLAGM2, flagm2, , , )         \
+  LINE(AARCH64_FRINT, frint, , , )           \
+  LINE(AARCH64_SVEI8MM, svei8mm, , , )       \
+  LINE(AARCH64_SVEF32MM, svef32mm, , , )     \
+  LINE(AARCH64_SVEF64MM, svef64mm, , , )     \
+  LINE(AARCH64_SVEBF16, svebf16, , , )       \
+  LINE(AARCH64_I8MM, i8mm, , , )             \
+  LINE(AARCH64_BF16, bf16, , , )             \
+  LINE(AARCH64_DGH, dgh, , , )               \
+  LINE(AARCH64_RNG, rng, , , )               \
+  LINE(AARCH64_BTI, bti, , , )               \
+  LINE(AARCH64_MTE, mte, , , )               \
+  LINE(AARCH64_ECV, ecv, , , )               \
+  LINE(AARCH64_AFP, afp, , , )               \
+  LINE(AARCH64_RPRES, rpres, , , )
+#define INTROSPECTION_PREFIX Aarch64
+#define INTROSPECTION_ENUM_PREFIX AARCH64
+#include "define_introspection.inl"
+
+////////////////////////////////////////////////////////////////////////////////
+// Implementation.
+////////////////////////////////////////////////////////////////////////////////
+
+#include <stdbool.h>
+
+#include "internal/windows_utils.h"
+
+#ifdef CPU_FEATURES_MOCK_CPUID_AARCH64
+extern bool GetWindowsIsProcessorFeaturePresent(DWORD);
+extern WORD GetWindowsNativeSystemInfoProcessorRevision();
+#else  // CPU_FEATURES_MOCK_CPUID_AARCH64
+static bool GetWindowsIsProcessorFeaturePresent(DWORD dwProcessorFeature) {
+  return IsProcessorFeaturePresent(dwProcessorFeature);
+}
+
+static WORD GetWindowsNativeSystemInfoProcessorRevision() {
+  SYSTEM_INFO system_info;
+  GetNativeSystemInfo(&system_info);
+  return system_info.wProcessorRevision;
+}
+#endif
+
+static const Aarch64Info kEmptyAarch64Info;
+
+Aarch64Info GetAarch64Info(void) {
+  Aarch64Info info = kEmptyAarch64Info;
+  info.revision = GetWindowsNativeSystemInfoProcessorRevision();
+  info.features.fp =
+      GetWindowsIsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE);
+  info.features.asimd =
+      GetWindowsIsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE);
+  info.features.crc32 = GetWindowsIsProcessorFeaturePresent(
+      PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);
+  info.features.asimddp =
+      GetWindowsIsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE);
+  info.features.jscvt = GetWindowsIsProcessorFeaturePresent(
+      PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE);
+  info.features.lrcpc = GetWindowsIsProcessorFeaturePresent(
+      PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE);
+  info.features.atomics = GetWindowsIsProcessorFeaturePresent(
+      PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE);
+
+
+  bool is_crypto_available = GetWindowsIsProcessorFeaturePresent(
+      PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
+  info.features.aes = is_crypto_available;
+  info.features.sha1 = is_crypto_available;
+  info.features.sha2 = is_crypto_available;
+  info.features.pmull = is_crypto_available;
+  return info;
+}
+
+#endif  // CPU_FEATURES_OS_WINDOWS
+#endif  // CPU_FEATURES_ARCH_AARCH64
diff --git a/src/impl_mips_linux_or_android.c b/src/impl_mips_linux_or_android.c
index 9a3dc2f..2322ecf 100644
--- a/src/impl_mips_linux_or_android.c
+++ b/src/impl_mips_linux_or_android.c
@@ -20,10 +20,15 @@
 ////////////////////////////////////////////////////////////////////////////////
 // Definitions for introspection.
 ////////////////////////////////////////////////////////////////////////////////
-#define INTROSPECTION_TABLE                     \
-  LINE(MIPS_MSA, msa, "msa", MIPS_HWCAP_MSA, 0) \
-  LINE(MIPS_EVA, eva, "eva", 0, 0)              \
-  LINE(MIPS_R6, r6, "r6", MIPS_HWCAP_R6, 0)
+#define INTROSPECTION_TABLE                                     \
+  LINE(MIPS_MSA, msa, "msa", MIPS_HWCAP_MSA, 0)                 \
+  LINE(MIPS_EVA, eva, "eva", 0, 0)                              \
+  LINE(MIPS_R6, r6, "r6", MIPS_HWCAP_R6, 0)                     \
+  LINE(MIPS_MIPS16, mips16, "mips16", MIPS_HWCAP_MIPS16, 0)     \
+  LINE(MIPS_MDMX, mdmx, "mdmx", MIPS_HWCAP_MDMX, 0)             \
+  LINE(MIPS_MIPS3D, mips3d, "mips3d", MIPS_HWCAP_MIPS3D, 0)     \
+  LINE(MIPS_SMART, smart, "smartmips", MIPS_HWCAP_SMARTMIPS, 0) \
+  LINE(MIPS_DSP, dsp, "dsp", MIPS_HWCAP_DSP, 0)
 #define INTROSPECTION_PREFIX Mips
 #define INTROSPECTION_ENUM_PREFIX MIPS
 #include "define_introspection_and_hwcaps.inl"
diff --git a/src/impl_ppc_linux.c b/src/impl_ppc_linux.c
index 13a381a..46a72d7 100644
--- a/src/impl_ppc_linux.c
+++ b/src/impl_ppc_linux.c
@@ -69,6 +69,7 @@
   LINE(PPC_SCV, scv, "scv", 0, PPC_FEATURE2_SCV)                               \
   LINE(PPC_HTM_NO_SUSPEND, htm_no_suspend, "htm-no-suspend", 0,                \
        PPC_FEATURE2_HTM_NO_SUSPEND)
+#undef PPC // Remove conflict with compiler generated preprocessor
 #define INTROSPECTION_PREFIX PPC
 #define INTROSPECTION_ENUM_PREFIX PPC
 #include "define_introspection_and_hwcaps.inl"
diff --git a/src/impl_riscv_linux.c b/src/impl_riscv_linux.c
new file mode 100644
index 0000000..8abec6e
--- /dev/null
+++ b/src/impl_riscv_linux.c
@@ -0,0 +1,111 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cpu_features_macros.h"
+
+#ifdef CPU_FEATURES_ARCH_RISCV
+#if defined(CPU_FEATURES_OS_LINUX)
+
+#include "cpuinfo_riscv.h"
+
+// According to
+// https://elixir.bootlin.com/linux/latest/source/Documentation/devicetree/bindings/riscv/cpus.yaml
+// isa string should match the following regex
+// ^rv(?:64|32)imaf?d?q?c?b?v?k?h?(?:_[hsxz](?:[a-z])+)*$
+//
+// This means we can test for features in this exact order except for Z
+// extensions.
+
+////////////////////////////////////////////////////////////////////////////////
+// Definitions for introspection.
+////////////////////////////////////////////////////////////////////////////////
+#define INTROSPECTION_TABLE                            \
+  LINE(RISCV_RV32I, RV32I, "rv32i", RISCV_HWCAP_32, 0) \
+  LINE(RISCV_RV64I, RV64I, "rv64i", RISCV_HWCAP_64, 0) \
+  LINE(RISCV_M, M, "m", RISCV_HWCAP_M, 0)              \
+  LINE(RISCV_A, A, "a", RISCV_HWCAP_A, 0)              \
+  LINE(RISCV_F, F, "f", RISCV_HWCAP_F, 0)              \
+  LINE(RISCV_D, D, "d", RISCV_HWCAP_D, 0)              \
+  LINE(RISCV_Q, Q, "q", RISCV_HWCAP_Q, 0)              \
+  LINE(RISCV_C, C, "c", RISCV_HWCAP_C, 0)              \
+  LINE(RISCV_V, V, "v", RISCV_HWCAP_V, 0)              \
+  LINE(RISCV_Zicsr, Zicsr, "_zicsr", 0, 0)             \
+  LINE(RISCV_Zifencei, Zifencei, "_zifencei", 0, 0)
+#define INTROSPECTION_PREFIX Riscv
+#define INTROSPECTION_ENUM_PREFIX RISCV
+#include "define_introspection_and_hwcaps.inl"
+
+////////////////////////////////////////////////////////////////////////////////
+// Implementation.
+////////////////////////////////////////////////////////////////////////////////
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#include "internal/filesystem.h"
+#include "internal/stack_line_reader.h"
+
+static const RiscvInfo kEmptyRiscvInfo;
+
+static void HandleRiscVIsaLine(StringView line, RiscvFeatures* const features) {
+  for (size_t i = 0; i < RISCV_LAST_; ++i) {
+    StringView flag = str(kCpuInfoFlags[i]);
+    int index_of_flag = CpuFeatures_StringView_IndexOf(line, flag);
+    bool is_set = index_of_flag != -1;
+    kSetters[i](features, is_set);
+    if (is_set)
+      line = CpuFeatures_StringView_PopFront(line, index_of_flag + flag.size);
+  }
+}
+
+static bool HandleRiscVLine(const LineResult result, RiscvInfo* const info) {
+  StringView line = result.line;
+  StringView key, value;
+  if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
+    if (CpuFeatures_StringView_IsEquals(key, str("isa"))) {
+      HandleRiscVIsaLine(value, &info->features);
+    } else if (CpuFeatures_StringView_IsEquals(key, str("uarch"))) {
+      int index = CpuFeatures_StringView_IndexOfChar(value, ',');
+      if (index == -1) return true;
+      StringView vendor = CpuFeatures_StringView_KeepFront(value, index);
+      StringView uarch = CpuFeatures_StringView_PopFront(value, index + 1);
+      CpuFeatures_StringView_CopyString(vendor, info->vendor,
+                                        sizeof(info->vendor));
+      CpuFeatures_StringView_CopyString(uarch, info->uarch,
+                                        sizeof(info->uarch));
+    }
+  }
+  return !result.eof;
+}
+
+static void FillProcCpuInfoData(RiscvInfo* const info) {
+  const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
+  if (fd >= 0) {
+    StackLineReader reader;
+    StackLineReader_Initialize(&reader, fd);
+    for (;;) {
+      if (!HandleRiscVLine(StackLineReader_NextLine(&reader), info)) break;
+    }
+    CpuFeatures_CloseFile(fd);
+  }
+}
+
+RiscvInfo GetRiscvInfo(void) {
+  RiscvInfo info = kEmptyRiscvInfo;
+  FillProcCpuInfoData(&info);
+  return info;
+}
+
+#endif  //  defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
+#endif  // CPU_FEATURES_ARCH_RISCV
diff --git a/src/impl_s390x_linux.c b/src/impl_s390x_linux.c
new file mode 100644
index 0000000..2b8b865
--- /dev/null
+++ b/src/impl_s390x_linux.c
@@ -0,0 +1,120 @@
+// Copyright 2022 IBM.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cpu_features_macros.h"
+
+#ifdef CPU_FEATURES_ARCH_S390X
+#ifdef CPU_FEATURES_OS_LINUX
+
+#include "cpuinfo_s390x.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// Definitions for introspection.
+////////////////////////////////////////////////////////////////////////////////
+#define INTROSPECTION_TABLE                                                    \
+  LINE(S390_ESAN3, esan3, "esan3", HWCAP_S390_ESAN3, 0)                              \
+  LINE(S390_ZARCH, zarch, "zarch", HWCAP_S390_ZARCH, 0)                              \
+  LINE(S390_STFLE, stfle, "stfle", HWCAP_S390_STFLE, 0)                              \
+  LINE(S390_MSA, msa, "msa", HWCAP_S390_MSA, 0)                                      \
+  LINE(S390_LDISP, ldisp, "ldisp", HWCAP_S390_LDISP, 0)                              \
+  LINE(S390_EIMM, eimm, "eimm", HWCAP_S390_EIMM, 0)                                  \
+  LINE(S390_DFP, dfp, "dfp", HWCAP_S390_DFP, 0)                                      \
+  LINE(S390_EDAT, edat, "edat", HWCAP_S390_HPAGE, 0)                                 \
+  LINE(S390_ETF3EH, etf3eh, "etf3eh", HWCAP_S390_ETF3EH, 0)                          \
+  LINE(S390_HIGHGPRS, highgprs, "highgprs", HWCAP_S390_HIGH_GPRS, 0)                 \
+  LINE(S390_TE, te, "te", HWCAP_S390_TE, 0)                                          \
+  LINE(S390_VX, vx, "vx", HWCAP_S390_VXRS, 0)                                        \
+  LINE(S390_VXD, vxd, "vxd", HWCAP_S390_VXRS_BCD, 0)                                 \
+  LINE(S390_VXE, vxe, "vxe", HWCAP_S390_VXRS_EXT, 0)                                 \
+  LINE(S390_GS, gs, "gs", HWCAP_S390_GS, 0)                                          \
+  LINE(S390_VXE2, vxe2, "vxe2", HWCAP_S390_VXRS_EXT2, 0)                             \
+  LINE(S390_VXP, vxp, "vxp", HWCAP_S390_VXRS_PDE, 0)                                 \
+  LINE(S390_SORT, sort, "sort", HWCAP_S390_SORT, 0)                                  \
+  LINE(S390_DFLT, dflt, "dflt", HWCAP_S390_DFLT, 0)                                  \
+  LINE(S390_VXP2, vxp2, "vxp2", HWCAP_S390_VXRS_PDE2, 0)                             \
+  LINE(S390_NNPA, nnpa, "nnpa", HWCAP_S390_NNPA, 0)                                  \
+  LINE(S390_PCIMIO, pcimio, "pcimio", HWCAP_S390_PCI_MIO, 0)                         \
+  LINE(S390_SIE, sie, "sie", HWCAP_S390_SIE, 0)
+#define INTROSPECTION_PREFIX S390X
+#define INTROSPECTION_ENUM_PREFIX S390X
+#include "define_introspection_and_hwcaps.inl"
+
+////////////////////////////////////////////////////////////////////////////////
+// Implementation.
+////////////////////////////////////////////////////////////////////////////////
+
+#include <stdbool.h>
+
+#include "internal/bit_utils.h"
+#include "internal/filesystem.h"
+#include "internal/hwcaps.h"
+#include "internal/stack_line_reader.h"
+#include "internal/string_view.h"
+
+static bool HandleS390XLine(const LineResult result,
+                          S390XPlatformStrings* const strings) {
+  StringView line = result.line;
+  StringView key, value;
+  if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
+    if (CpuFeatures_StringView_IsEquals(key, str("# processors"))) {
+        strings->num_processors = CpuFeatures_StringView_ParsePositiveNumber(value);
+    }
+  }
+  return !result.eof;
+}
+
+static void FillProcCpuInfoData(S390XPlatformStrings* const strings) {
+  const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
+  if (fd >= 0) {
+    StackLineReader reader;
+    StackLineReader_Initialize(&reader, fd);
+    for (;;) {
+      if (!HandleS390XLine(StackLineReader_NextLine(&reader), strings)) {
+        break;
+      }
+    }
+    CpuFeatures_CloseFile(fd);
+  }
+}
+
+static const S390XInfo kEmptyS390XInfo;
+
+S390XInfo GetS390XInfo(void) {
+  S390XInfo info = kEmptyS390XInfo;
+  const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
+  for (size_t i = 0; i < S390X_LAST_; ++i) {
+    if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
+      kSetters[i](&info.features, true);
+    }
+  }
+  return info;
+}
+
+static const S390XPlatformStrings kEmptyS390XPlatformStrings;
+
+S390XPlatformStrings GetS390XPlatformStrings(void) {
+  S390XPlatformStrings strings = kEmptyS390XPlatformStrings;
+  const char* platform = CpuFeatures_GetPlatformPointer();
+
+  FillProcCpuInfoData(&strings);
+
+  if (platform != NULL)
+    CpuFeatures_StringView_CopyString(str(platform), strings.type.platform,
+                                      sizeof(strings.type.platform));
+
+  return strings;
+}
+
+#endif  // CPU_FEATURES_OS_LINUX
+#endif  // CPU_FEATURES_ARCH_S390X
diff --git a/src/impl_x86__base_implementation.inl b/src/impl_x86__base_implementation.inl
index 09f24b2..6a34bff 100644
--- a/src/impl_x86__base_implementation.inl
+++ b/src/impl_x86__base_implementation.inl
@@ -13,6 +13,76 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+// A note on x86 SIMD instructions availability
+// -----------------------------------------------------------------------------
+// A number of conditions need to be met for an application to use SIMD
+// instructions:
+// 1. The CPU itself must support the instruction.
+// - we use `CPUID` to check whether the feature is supported.
+// 2. The OS must save and restore the associated SIMD register across context
+//    switches, we check that:
+// - the CPU reports supporting hardware context switching instructions via
+//   CPUID.1:ECX.XSAVE[bit 26]
+// - the OS reports supporting hardware context switching instructions via
+//   CPUID.1:ECX.OSXSAVE[bit 27]
+// - the CPU extended control register 0 (XCR0) is set to save and restore the
+//   needed SIMD registers
+//
+// Note that if `XSAVE`/`OSXSAVE` are missing, we delegate the detection to the
+// OS via the `DetectFeaturesFromOs` function or via microarchitecture
+// heuristics.
+//
+// Encoding
+// -----------------------------------------------------------------------------
+// X86Info contains fields such as vendor and brand_string that are ASCII
+// encoded strings. `vendor` length of characters is 13 and `brand_string` is 49
+// (with null terminated string). We use CPUID.1:E[D,C,B]X to get `vendor` and
+// CPUID.8000_000[4:2]:E[D,C,B,A]X to get `brand_string`
+//
+// Microarchitecture
+// -----------------------------------------------------------------------------
+// `GetX86Microarchitecture` function consists of check on vendor via
+// `IsVendorByX86Info`. We use `CPUID(family, model)` to define the vendor's
+//  microarchitecture. In cases where the `family` and `model` is the same for
+//  several microarchitectures we do a stepping check or in the worst case we
+//  rely on parsing brand_string (see HasSecondFMA for an example). Details of
+//  identification by `brand_string` can be found by reference:
+//  https://en.wikichip.org/wiki/intel/microarchitectures/cascade_lake
+//  https://www.intel.com/content/www/us/en/processors/processor-numbers.html
+
+// CacheInfo X86
+// -----------------------------------------------------------------------------
+// We use the CacheInfo struct to store information about cache levels. The
+// maximum number of levels is hardcoded but can be increased if needed. We have
+// full support of cache identification for the following processors:
+// • Intel:
+//    ◦ modern processors:
+//        we use `ParseCacheInfo` function with `leaf_id` 0x00000004.
+//    ◦ old processors:
+//        we parse descriptors via `GetCacheLevelInfo`, see Application Note
+//        485: Intel Processor Identification and CPUID Instruction.
+// • AMD:
+//    ◦ modern processors:
+//        we use `ParseCacheInfo` function with `leaf_id` 0x8000001D.
+//    ◦ old processors:
+//        we parse cache info using Fn8000_0005_E[A,B,C,D]X and
+//        Fn8000_0006_E[A,B,C,D]X. See AMD CPUID Specification:
+//        https://www.amd.com/system/files/TechDocs/25481.pdf.
+// • Hygon:
+//    we reuse AMD cache detection implementation.
+// • Zhaoxin:
+//    we reuse Intel cache detection implementation.
+//
+// Internal structures
+// -----------------------------------------------------------------------------
+// We use internal structures such as `Leaves` and `OsPreserves` to cache the
+// result of cpuid info and support of registers, since latency of CPUID
+// instruction is around ~100 cycles, see
+// https://www.agner.org/optimize/instruction_tables.pdf. Hence, we use
+// `ReadLeaves` function for `GetX86Info`, `GetCacheInfo` and
+// `FillX86BrandString` to read leaves and hold these values to avoid redundant
+// call on the same leaf.
+
 #include <stdbool.h>
 #include <string.h>
 
@@ -98,7 +168,7 @@
   Leaf leaf_80000004;  // brand string
 } Leaves;
 
-static Leaves ReadLeaves() {
+static Leaves ReadLeaves(void) {
   const Leaf leaf_0 = GetCpuidLeaf(0, 0);
   const uint32_t max_cpuid_leaf = leaf_0.eax;
   const Leaf leaf_80000000 = GetCpuidLeaf(0x80000000, 0);
@@ -121,7 +191,6 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 // OS support
-// TODO: Add documentation
 ////////////////////////////////////////////////////////////////////////////////
 
 #define MASK_XMM 0x2
@@ -254,6 +323,7 @@
   const Leaf leaf_1 = leaves->leaf_1;
   const Leaf leaf_7 = leaves->leaf_7;
   const Leaf leaf_7_1 = leaves->leaf_7_1;
+  const Leaf leaf_80000001 = leaves->leaf_80000001;
 
   const bool have_xsave = IsBitSet(leaf_1.ecx, 26);
   const bool have_osxsave = IsBitSet(leaf_1.ecx, 27);
@@ -309,9 +379,17 @@
   features->clflushopt = IsBitSet(leaf_7.ebx, 23);
   features->clwb = IsBitSet(leaf_7.ebx, 24);
   features->sha = IsBitSet(leaf_7.ebx, 29);
+  features->gfni = IsBitSet(leaf_7.ecx, 8);
   features->vaes = IsBitSet(leaf_7.ecx, 9);
   features->vpclmulqdq = IsBitSet(leaf_7.ecx, 10);
+  features->movdiri = IsBitSet(leaf_7.ecx, 27);
+  features->movdir64b = IsBitSet(leaf_7.ecx, 28);
+  features->fs_rep_mov = IsBitSet(leaf_7.edx, 4);
+  features->fz_rep_movsb = IsBitSet(leaf_7_1.eax, 10);
+  features->fs_rep_stosb = IsBitSet(leaf_7_1.eax, 11);
+  features->fs_rep_cmpsb_scasb = IsBitSet(leaf_7_1.eax, 12);
   features->adx = IsBitSet(leaf_7.ebx, 19);
+  features->lzcnt = IsBitSet(leaf_80000001.ecx, 5);
 
   /////////////////////////////////////////////////////////////////////////////
   // The following section is devoted to Vector Extensions.
@@ -340,6 +418,7 @@
     if (os_preserves->avx_registers) {
       features->fma3 = IsBitSet(leaf_1.ecx, 12);
       features->avx = IsBitSet(leaf_1.ecx, 28);
+      features->avx_vnni = IsBitSet(leaf_7_1.eax, 4);
       features->avx2 = IsBitSet(leaf_7.ebx, 5);
     }
     if (os_preserves->avx512_registers) {
@@ -362,6 +441,7 @@
       features->avx512_4fmaps = IsBitSet(leaf_7.edx, 3);
       features->avx512_bf16 = IsBitSet(leaf_7_1.eax, 5);
       features->avx512_vp2intersect = IsBitSet(leaf_7.edx, 8);
+      features->avx512_fp16 = IsBitSet(leaf_7.edx, 23);
     }
     if (os_preserves->amx_registers) {
       features->amx_bf16 = IsBitSet(leaf_7.edx, 22);
@@ -406,8 +486,8 @@
       IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
   const bool is_hygon =
       IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_HYGON_GENUINE);
-  const bool is_zhaoxin = 
-      (IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_CENTAUR_HAULS) || 
+  const bool is_zhaoxin =
+      (IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_CENTAUR_HAULS) ||
        IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_SHANGHAI));
   SetVendor(leaves.leaf_0, info.vendor);
   if (is_intel || is_amd || is_hygon || is_zhaoxin) {
@@ -463,6 +543,15 @@
       case CPUID(0x06, 0x5C):
         // https://en.wikipedia.org/wiki/Goldmont
         return INTEL_ATOM_GMT;
+      case CPUID(0x06, 0x7A):
+        // https://en.wikichip.org/wiki/intel/microarchitectures/goldmont_plus
+        return INTEL_ATOM_GMT_PLUS;
+      case CPUID(0x06, 0x8A):
+      case CPUID(0x06, 0x96):
+      case CPUID(0x06, 0x9C):
+        // https://en.wikichip.org/wiki/intel/microarchitectures/tremont
+        return INTEL_ATOM_TMT;
+      case CPUID(0x06, 0x0E):
       case CPUID(0x06, 0x0F):
       case CPUID(0x06, 0x16):
         // https://en.wikipedia.org/wiki/Intel_Core_(microarchitecture)
@@ -503,10 +592,15 @@
         // https://en.wikipedia.org/wiki/Broadwell_(microarchitecture)
         return INTEL_BDW;
       case CPUID(0x06, 0x4E):
-      case CPUID(0x06, 0x55):
       case CPUID(0x06, 0x5E):
         // https://en.wikipedia.org/wiki/Skylake_(microarchitecture)
         return INTEL_SKL;
+      case CPUID(0x06, 0x55):
+        if (info->stepping >= 6 && info->stepping <= 7) {
+          // https://en.wikipedia.org/wiki/Cascade_Lake_(microprocessor)
+          return INTEL_CCL;
+        }
+        return INTEL_SKL;
       case CPUID(0x06, 0x66):
         // https://en.wikipedia.org/wiki/Cannon_Lake_(microarchitecture)
         return INTEL_CNL;
@@ -532,6 +626,8 @@
             return INTEL_CFL;  // https://en.wikipedia.org/wiki/Coffee_Lake
           case 11:
             return INTEL_WHL;  // https://en.wikipedia.org/wiki/Whiskey_Lake_(microarchitecture)
+          case 12:
+            return INTEL_CML;  // https://en.wikichip.org/wiki/intel/microarchitectures/comet_lake
           default:
             return X86_UNKNOWN;
         }
@@ -547,9 +643,18 @@
       case CPUID(0x06, 0x9A):
         // https://en.wikichip.org/wiki/intel/microarchitectures/alder_lake
         return INTEL_ADL;
+      case CPUID(0x06, 0xA5):
+      case CPUID(0x06, 0xA6):
+        // https://en.wikichip.org/wiki/intel/microarchitectures/comet_lake
+        return INTEL_CML;
       case CPUID(0x06, 0xA7):
         // https://en.wikichip.org/wiki/intel/microarchitectures/rocket_lake
         return INTEL_RCL;
+      case CPUID(0x06, 0xB7):
+      case CPUID(0x06, 0xBA):
+      case CPUID(0x06, 0xBF):
+        // https://en.wikichip.org/wiki/intel/microarchitectures/raptor_lake
+        return INTEL_RPL;
       case CPUID(0x06, 0x85):
         // https://en.wikichip.org/wiki/intel/microarchitectures/knights_mill
         return INTEL_KNIGHTS_M;
@@ -580,15 +685,15 @@
         // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/zhangjiang
         return ZHAOXIN_ZHANGJIANG;
       case CPUID(0x07, 0x1B):
-	// https://en.wikichip.org/wiki/zhaoxin/microarchitectures/wudaokou
-	return ZHAOXIN_WUDAOKOU;
+        // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/wudaokou
+        return ZHAOXIN_WUDAOKOU;
       case CPUID(0x07, 0x3B):
-	// https://en.wikichip.org/wiki/zhaoxin/microarchitectures/lujiazui
-	return ZHAOXIN_LUJIAZUI;
+        // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/lujiazui
+        return ZHAOXIN_LUJIAZUI;
       case CPUID(0x07, 0x5B):
-	return ZHAOXIN_YONGFENG;
+        return ZHAOXIN_YONGFENG;
       default:
-	return X86_UNKNOWN;
+        return X86_UNKNOWN;
     }
   }
   if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_SHANGHAI)) {
@@ -598,15 +703,15 @@
         // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/zhangjiang
         return ZHAOXIN_ZHANGJIANG;
       case CPUID(0x07, 0x1B):
-	// https://en.wikichip.org/wiki/zhaoxin/microarchitectures/wudaokou
-	return ZHAOXIN_WUDAOKOU;
+        // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/wudaokou
+        return ZHAOXIN_WUDAOKOU;
       case CPUID(0x07, 0x3B):
-	// https://en.wikichip.org/wiki/zhaoxin/microarchitectures/lujiazui
-	return ZHAOXIN_LUJIAZUI;
+        // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/lujiazui
+        return ZHAOXIN_LUJIAZUI;
       case CPUID(0x07, 0x5B):
-	return ZHAOXIN_YONGFENG;
+        return ZHAOXIN_YONGFENG;
       default:
-	return X86_UNKNOWN;
+        return X86_UNKNOWN;
     }
   }
   if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_AUTHENTIC_AMD)) {
@@ -659,6 +764,7 @@
       case CPUID(0x11, 0x03):
         // http://developer.amd.com/wordpress/media/2012/10/41788.pdf
         return AMD_K11;
+      case CPUID(0x12, 0x00):
       case CPUID(0x12, 0x01):
         // https://www.amd.com/system/files/TechDocs/44739_12h_Rev_Gd.pdf
         return AMD_K12;
@@ -671,9 +777,11 @@
         // https://en.wikichip.org/wiki/amd/microarchitectures/bulldozer
         return AMD_BULLDOZER;
       case CPUID(0x15, 0x02):
+      case CPUID(0x15, 0x10):
       case CPUID(0x15, 0x11):
       case CPUID(0x15, 0x13):
         // https://en.wikichip.org/wiki/amd/microarchitectures/piledriver
+        // https://www.amd.com/system/files/TechDocs/48931_15h_Mod_10h-1Fh_Rev_Guide.pdf
         return AMD_PILEDRIVER;
       case CPUID(0x15, 0x30):
       case CPUID(0x15, 0x38):
@@ -685,6 +793,7 @@
         // https://en.wikichip.org/wiki/amd/microarchitectures/excavator
         return AMD_EXCAVATOR;
       case CPUID(0x16, 0x00):
+      case CPUID(0x16, 0x26):
         return AMD_JAGUAR;
       case CPUID(0x16, 0x30):
         return AMD_PUMA;
@@ -704,15 +813,23 @@
       case CPUID(0x17, 0x71):
       case CPUID(0x17, 0x90):
       case CPUID(0x17, 0x98):
+      case CPUID(0x17, 0xA0):
         // https://en.wikichip.org/wiki/amd/microarchitectures/zen_2
         return AMD_ZEN2;
+      case CPUID(0x19, 0x00):
       case CPUID(0x19, 0x01):
+      case CPUID(0x19, 0x08):
       case CPUID(0x19, 0x21):
       case CPUID(0x19, 0x30):
       case CPUID(0x19, 0x40):
+      case CPUID(0x19, 0x44):
       case CPUID(0x19, 0x50):
         // https://en.wikichip.org/wiki/amd/microarchitectures/zen_3
         return AMD_ZEN3;
+      case CPUID(0x19, 0x10):
+      case CPUID(0x19, 0x61):
+        // https://en.wikichip.org/wiki/amd/microarchitectures/zen_4
+        return AMD_ZEN4;
       default:
         return X86_UNKNOWN;
     }
@@ -720,6 +837,7 @@
   if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_HYGON_GENUINE)) {
     switch (CPUID(info->family, info->model)) {
       case CPUID(0x18, 0x00):
+      case CPUID(0x18, 0x01):
         return AMD_ZEN;
     }
   }
@@ -1629,16 +1747,18 @@
     const Leaf leaf = SafeCpuIdEx(max_cpuid_leaf, leaf_id, index);
     int cache_type_field = ExtractBitRange(leaf.eax, 4, 0);
     CacheType cache_type;
-    if (cache_type_field == 0)
-      break;
-    else if (cache_type_field == 1)
+    if (cache_type_field == 1)
       cache_type = CPU_FEATURE_CACHE_DATA;
     else if (cache_type_field == 2)
       cache_type = CPU_FEATURE_CACHE_INSTRUCTION;
     else if (cache_type_field == 3)
       cache_type = CPU_FEATURE_CACHE_UNIFIED;
     else
-      break;  // Should not occur as per documentation.
+      // Intel Processor Identification and the CPUID Instruction Application
+      // Note 485 page 37 Table 5-10. Deterministic Cache Parameters.
+      // We skip cache parsing in case null of cache type or cache type in the
+      // range of 4-31 according to documentation.
+      break;
     int level = ExtractBitRange(leaf.eax, 7, 5);
     int line_size = ExtractBitRange(leaf.ebx, 11, 0) + 1;
     int partitioning = ExtractBitRange(leaf.ebx, 21, 12) + 1;
@@ -1659,6 +1779,115 @@
   if (info.size > 0) *old_info = info;
 }
 
+typedef struct {
+  int level;
+  int cache_id;
+  CacheType cache_type;
+} CacheLevelInfoLegacyAMD;
+
+static int GetWaysLegacyAMD(int cache_level, const uint32_t cache_id) {
+  // https://www.amd.com/system/files/TechDocs/25481.pdf page 23
+  // CPUID.8000_0005_ECX[23:16] L1 data cache associativity.
+  // CPUID.8000_0005_EDX[23:16] L1 instruction cache associativity.
+  if (cache_level == 1) {
+    return ExtractBitRange(cache_id, 23, 16);
+  }
+  // https://www.amd.com/system/files/TechDocs/25481.pdf page 24
+  // See Table 4: L2/L3 Cache and TLB Associativity Field Definition.
+  // CPUID.8000_0006_ECX[15:12] L2 cache associativity.
+  // CPUID.8000_0006_EDX[15:12] L3 cache associativity.
+  const int ways = ExtractBitRange(cache_id, 15, 12);
+  switch (ways) {
+    case 0x0:
+    case 0x1:
+    case 0x2:
+    case 0x4:
+      return ways;
+    case 0x6:
+      return 8;
+    case 0x8:
+      return 16;
+    case 0xA:
+      return 32;
+    case 0xB:
+      return 48;
+    case 0xC:
+      return 64;
+    case 0xD:
+      return 96;
+    case 0xE:
+      return 128;
+    case 0xF:
+      return 255;
+    default:
+      return -1;  // Reserved
+  }
+}
+
+static int GetCacheSizeLegacyAMD(int cache_level, const uint32_t cache_id) {
+  switch (cache_level) {
+    case 1:
+      // https://www.amd.com/system/files/TechDocs/25481.pdf page 23
+      // CPUID.8000_0005_ECX[31:24] L1 data cache size in KB.
+      // CPUID.8000_0005_EDX[31:24] L1 instruction cache size KB.
+      return ExtractBitRange(cache_id, 31, 24);
+    case 2:
+      // https://www.amd.com/system/files/TechDocs/25481.pdf page 25
+      // CPUID.8000_0006_ECX[31:16] L2 cache size in KB.
+      return ExtractBitRange(cache_id, 31, 16);
+    case 3:
+      // https://www.amd.com/system/files/TechDocs/25481.pdf page 25
+      // CPUID.8000_0006_EDX[31:18] L3 cache size.
+      // Specifies the L3 cache size is within the following range:
+      // (L3Size[31:18] * 512KB) <= L3 cache size < ((L3Size[31:18]+1) * 512KB).
+      return ExtractBitRange(cache_id, 31, 18) * 512;
+    default:
+      return 0;
+  }
+}
+
+#define LEGACY_AMD_MAX_CACHE_LEVEL 4
+
+// https://www.amd.com/system/files/TechDocs/25481.pdf
+// CPUID Fn8000_0005_E[A,B,C,D]X, Fn8000_0006_E[A,B,C,D]X - TLB and Cache info
+static void ParseCacheInfoLegacyAMD(const uint32_t max_ext, CacheInfo* info) {
+  const Leaf cache_tlb_leaf1 = SafeCpuIdEx(max_ext, 0x80000005, 0);
+  const Leaf cache_tlb_leaf2 = SafeCpuIdEx(max_ext, 0x80000006, 0);
+
+  const CacheLevelInfoLegacyAMD legacy_cache_info[LEGACY_AMD_MAX_CACHE_LEVEL] =
+      {(CacheLevelInfoLegacyAMD){.cache_id = cache_tlb_leaf1.ecx,
+                                 .cache_type = CPU_FEATURE_CACHE_DATA,
+                                 .level = 1},
+       (CacheLevelInfoLegacyAMD){.cache_id = cache_tlb_leaf1.edx,
+                                 .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
+                                 .level = 1},
+       (CacheLevelInfoLegacyAMD){.cache_id = cache_tlb_leaf2.ecx,
+                                 .cache_type = CPU_FEATURE_CACHE_UNIFIED,
+                                 .level = 2},
+       (CacheLevelInfoLegacyAMD){.cache_id = cache_tlb_leaf2.edx,
+                                 .cache_type = CPU_FEATURE_CACHE_UNIFIED,
+                                 .level = 3}};
+
+  const int KiB = 1024;
+  const int UNDEF = -1;
+  for (int i = 0; i < LEGACY_AMD_MAX_CACHE_LEVEL; ++i) {
+    const int level = legacy_cache_info[i].level;
+    const int cache_id = legacy_cache_info[i].cache_id;
+    const CacheType cache_type = legacy_cache_info[i].cache_type;
+    const int cache_size = GetCacheSizeLegacyAMD(level, cache_id);
+    if (cache_size == 0) break;
+    info->levels[i] =
+        (CacheLevelInfo){.level = level,
+                         .cache_type = cache_type,
+                         .cache_size = cache_size * KiB,
+                         .ways = GetWaysLegacyAMD(level, cache_id),
+                         .line_size = ExtractBitRange(cache_id, 7, 0),
+                         .tlb_entries = UNDEF,
+                         .partitioning = UNDEF};
+    ++info->size;
+  }
+}
+
 CacheInfo GetX86CacheInfo(void) {
   CacheInfo info = kEmptyCacheInfo;
   const Leaves leaves = ReadLeaves();
@@ -1674,6 +1903,8 @@
     // https://www.amd.com/system/files/TechDocs/25481.pdf
     if (IsBitSet(leaves.leaf_80000001.ecx, 22)) {
       ParseCacheInfo(leaves.max_cpuid_leaf_ext, 0x8000001D, &info);
+    } else {
+      ParseCacheInfoLegacyAMD(leaves.max_cpuid_leaf_ext, &info);
     }
   }
   return info;
@@ -1710,6 +1941,7 @@
   LINE(X86_SSE4_2, sse4_2, , , )                           \
   LINE(X86_SSE4A, sse4a, , , )                             \
   LINE(X86_AVX, avx, , , )                                 \
+  LINE(X86_AVX_VNNI, avx_vnni, , , )                       \
   LINE(X86_AVX2, avx2, , , )                               \
   LINE(X86_AVX512F, avx512f, , , )                         \
   LINE(X86_AVX512CD, avx512cd, , , )                       \
@@ -1730,6 +1962,7 @@
   LINE(X86_AVX512_4FMAPS, avx512_4fmaps, , , )             \
   LINE(X86_AVX512_BF16, avx512_bf16, , , )                 \
   LINE(X86_AVX512_VP2INTERSECT, avx512_vp2intersect, , , ) \
+  LINE(X86_AVX512_FP16, avx512_fp16, , , )                 \
   LINE(X86_AMX_BF16, amx_bf16, , , )                       \
   LINE(X86_AMX_TILE, amx_tile, , , )                       \
   LINE(X86_AMX_INT8, amx_int8, , , )                       \
@@ -1743,7 +1976,15 @@
   LINE(X86_RDRND, rdrnd, , , )                             \
   LINE(X86_DCA, dca, , , )                                 \
   LINE(X86_SS, ss, , , )                                   \
-  LINE(X86_ADX, adx, , , )
+  LINE(X86_ADX, adx, , , )                                 \
+  LINE(X86_LZCNT, lzcnt, , , )                             \
+  LINE(X86_GFNI, gfni, , , )                               \
+  LINE(X86_MOVDIRI, movdiri, , , )                         \
+  LINE(X86_MOVDIR64B, movdir64b, , , )                     \
+  LINE(X86_FS_REP_MOV, fs_rep_mov, , , )                   \
+  LINE(X86_FZ_REP_MOVSB, fz_rep_movsb, , , )               \
+  LINE(X86_FS_REP_STOSB, fs_rep_stosb, , , )               \
+  LINE(X86_FS_REP_CMPSB_SCASB, fs_rep_cmpsb_scasb, , , )
 #define INTROSPECTION_PREFIX X86
 #define INTROSPECTION_ENUM_PREFIX X86
 #include "define_introspection.inl"
@@ -1768,16 +2009,21 @@
   LINE(INTEL_HSW)                   \
   LINE(INTEL_BDW)                   \
   LINE(INTEL_SKL)                   \
+  LINE(INTEL_CCL)                   \
   LINE(INTEL_ATOM_GMT)              \
+  LINE(INTEL_ATOM_GMT_PLUS)         \
+  LINE(INTEL_ATOM_TMT)              \
   LINE(INTEL_KBL)                   \
   LINE(INTEL_CFL)                   \
   LINE(INTEL_WHL)                   \
+  LINE(INTEL_CML)                   \
   LINE(INTEL_CNL)                   \
   LINE(INTEL_ICL)                   \
   LINE(INTEL_TGL)                   \
   LINE(INTEL_SPR)                   \
   LINE(INTEL_ADL)                   \
   LINE(INTEL_RCL)                   \
+  LINE(INTEL_RPL)                   \
   LINE(INTEL_KNIGHTS_M)             \
   LINE(INTEL_KNIGHTS_L)             \
   LINE(INTEL_KNIGHTS_F)             \
@@ -1797,7 +2043,8 @@
   LINE(AMD_ZEN)                     \
   LINE(AMD_ZEN_PLUS)                \
   LINE(AMD_ZEN2)                    \
-  LINE(AMD_ZEN3)
+  LINE(AMD_ZEN3)                    \
+  LINE(AMD_ZEN4)
 
 const char* GetX86MicroarchitectureName(X86Microarchitecture value) {
 #define LINE(ENUM) [ENUM] = STRINGIZE(ENUM),
diff --git a/src/impl_x86_windows.c b/src/impl_x86_windows.c
index 0b330d0..8a82823 100644
--- a/src/impl_x86_windows.c
+++ b/src/impl_x86_windows.c
@@ -24,7 +24,7 @@
   // No override
 }
 
-#include <windows.h>  // IsProcessorFeaturePresent
+#include "internal/windows_utils.h"
 
 #if defined(CPU_FEATURES_MOCK_CPUID_X86)
 extern bool GetWindowsIsProcessorFeaturePresent(DWORD);
@@ -43,15 +43,15 @@
       GetWindowsIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE);
   features->sse3 =
       GetWindowsIsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE);
+  features->ssse3 =
+      GetWindowsIsProcessorFeaturePresent(PF_SSSE3_INSTRUCTIONS_AVAILABLE);
+  features->sse4_1 =
+      GetWindowsIsProcessorFeaturePresent(PF_SSE4_1_INSTRUCTIONS_AVAILABLE);
+  features->sse4_2 =
+      GetWindowsIsProcessorFeaturePresent(PF_SSE4_2_INSTRUCTIONS_AVAILABLE);
 
-// 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
+// do not bother checking PF_AVX*
+// cause AVX enabled processor will have XCR0 be exposed and this function will be skipped at all
 }
 
 #endif  // CPU_FEATURES_OS_WINDOWS
diff --git a/src/utils/list_cpu_features.c b/src/utils/list_cpu_features.c
index 0b4eb7a..8226d85 100644
--- a/src/utils/list_cpu_features.c
+++ b/src/utils/list_cpu_features.c
@@ -35,6 +35,10 @@
 #include "cpuinfo_mips.h"
 #elif defined(CPU_FEATURES_ARCH_PPC)
 #include "cpuinfo_ppc.h"
+#elif defined(CPU_FEATURES_ARCH_S390X)
+#include "cpuinfo_s390x.h"
+#elif defined(CPU_FEATURES_ARCH_RISCV)
+#include "cpuinfo_riscv.h"
 #endif
 
 // Design principles
@@ -54,18 +58,18 @@
 BumpAllocator gBumpAllocator = {.ptr = gGlobalBuffer,
                                 .size = sizeof(gGlobalBuffer)};
 
-static void internal_error() {
+static void internal_error(void) {
   fputs("internal error\n", stderr);
   exit(EXIT_FAILURE);
 }
 
 #define ALIGN 8
 
-static void assertAligned() {
+static void assertAligned(void) {
   if ((uintptr_t)(gBumpAllocator.ptr) % ALIGN) internal_error();
 }
 
-static void BA_Align() {
+static void BA_Align(void) {
   while (gBumpAllocator.size && (uintptr_t)(gBumpAllocator.ptr) % ALIGN) {
     --gBumpAllocator.size;
     ++gBumpAllocator.ptr;
@@ -129,10 +133,10 @@
 }
 
 // Adds a map node.
-static Node* CreateMap() { return BA_CreateNode(NT_MAP); }
+static Node* CreateMap(void) { return BA_CreateNode(NT_MAP); }
 
 // Adds an array node.
-static Node* CreateArray() { return BA_CreateNode(NT_ARRAY); }
+static Node* CreateArray(void) { return BA_CreateNode(NT_ARRAY); }
 
 // Adds a formatted string node.
 static Node* CreatePrintfString(const char* format, ...) {
@@ -205,6 +209,12 @@
 #elif defined(CPU_FEATURES_ARCH_PPC)
 DEFINE_ADD_FLAGS(GetPPCFeaturesEnumValue, GetPPCFeaturesEnumName, PPCFeatures,
                  PPC_LAST_)
+#elif defined(CPU_FEATURES_ARCH_S390X)
+DEFINE_ADD_FLAGS(GetS390XFeaturesEnumValue, GetS390XFeaturesEnumName, S390XFeatures,
+                 S390X_LAST_)
+#elif defined(CPU_FEATURES_ARCH_RISCV)
+DEFINE_ADD_FLAGS(GetRiscvFeaturesEnumValue, GetRiscvFeaturesEnumName, RiscvFeatures,
+                 RISCV_LAST_)
 #endif
 
 // Prints a json string with characters escaping.
@@ -360,15 +370,13 @@
   AddMapEntry(root, "cache_info", array);
 }
 
-static Node* CreateTree() {
+static Node* CreateTree(void) {
   Node* root = CreateMap();
 #if defined(CPU_FEATURES_ARCH_X86)
-  char brand_string[49];
   const X86Info info = GetX86Info();
   const CacheInfo cache_info = GetX86CacheInfo();
-  FillX86BrandString(brand_string);
   AddMapEntry(root, "arch", CreateString("x86"));
-  AddMapEntry(root, "brand", CreateString(brand_string));
+  AddMapEntry(root, "brand", CreateString(info.brand_string));
   AddMapEntry(root, "family", CreateInt(info.family));
   AddMapEntry(root, "model", CreateInt(info.model));
   AddMapEntry(root, "stepping", CreateInt(info.stepping));
@@ -410,6 +418,20 @@
   AddMapEntry(root, "microarchitecture",
               CreateString(strings.type.base_platform));
   AddFlags(root, &info.features);
+#elif defined(CPU_FEATURES_ARCH_S390X)
+  const S390XInfo info = GetS390XInfo();
+  const S390XPlatformStrings strings = GetS390XPlatformStrings();
+  AddMapEntry(root, "arch", CreateString("s390x"));
+  AddMapEntry(root, "platform", CreateString("zSeries"));
+  AddMapEntry(root, "model", CreateString(strings.type.platform));
+  AddMapEntry(root, "# processors", CreateInt(strings.num_processors));
+  AddFlags(root, &info.features);
+#elif defined(CPU_FEATURES_ARCH_RISCV)
+  const RiscvInfo info = GetRiscvInfo();
+  AddMapEntry(root, "arch", CreateString("risc-v"));
+  AddMapEntry(root, "vendor", CreateString(info.vendor));
+  AddMapEntry(root, "microarchitecture", CreateString(info.uarch));
+  AddFlags(root, &info.features); 
 #endif
   return root;
 }
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 8e8f72a..f627d74 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -71,7 +71,11 @@
 ##------------------------------------------------------------------------------
 ## cpuinfo_aarch64_test
 if(PROCESSOR_IS_AARCH64)
-  add_executable(cpuinfo_aarch64_test cpuinfo_aarch64_test.cc ../src/impl_aarch64_linux_or_android.c)
+  add_executable(cpuinfo_aarch64_test
+    cpuinfo_aarch64_test.cc
+    ../src/impl_aarch64_linux_or_android.c
+    ../src/impl_aarch64_windows.c)
+  target_compile_definitions(cpuinfo_aarch64_test PUBLIC CPU_FEATURES_MOCK_CPUID_AARCH64)
   target_link_libraries(cpuinfo_aarch64_test all_libraries)
   add_test(NAME cpuinfo_aarch64_test COMMAND cpuinfo_aarch64_test)
 endif()
@@ -89,3 +93,17 @@
   target_link_libraries(cpuinfo_ppc_test all_libraries)
   add_test(NAME cpuinfo_ppc_test COMMAND cpuinfo_ppc_test)
 endif()
+##------------------------------------------------------------------------------
+## cpuinfo_s390x_test
+if(PROCESSOR_IS_S390X)
+  add_executable(cpuinfo_s390x_test cpuinfo_s390x_test.cc  ../src/impl_s390x_linux.c)
+  target_link_libraries(cpuinfo_s390x_test all_libraries)
+  add_test(NAME cpuinfo_s390x_test COMMAND cpuinfo_s390x_test)
+endif()
+##------------------------------------------------------------------------------
+## cpuinfo_riscv_test
+if(PROCESSOR_IS_RISCV)
+  add_executable(cpuinfo_riscv_test cpuinfo_riscv_test.cc  ../src/impl_riscv_linux.c)
+  target_link_libraries(cpuinfo_riscv_test all_libraries)
+  add_test(NAME cpuinfo_riscv_test COMMAND cpuinfo_riscv_test)
+endif()
diff --git a/test/cpuinfo_aarch64_test.cc b/test/cpuinfo_aarch64_test.cc
index 04b6143..ef9abae 100644
--- a/test/cpuinfo_aarch64_test.cc
+++ b/test/cpuinfo_aarch64_test.cc
@@ -14,13 +14,86 @@
 
 #include "cpuinfo_aarch64.h"
 
+#include <set>
+
 #include "filesystem_for_testing.h"
 #include "gtest/gtest.h"
 #include "hwcaps_for_testing.h"
+#if defined(CPU_FEATURES_OS_WINDOWS)
+#include "internal/windows_utils.h"
+#endif  // CPU_FEATURES_OS_WINDOWS
 
 namespace cpu_features {
+class FakeCpuAarch64 {
+ public:
+#if defined(CPU_FEATURES_OS_WINDOWS)
+  bool GetWindowsIsProcessorFeaturePresent(DWORD dwProcessorFeature) {
+    return windows_isprocessorfeaturepresent_.count(dwProcessorFeature);
+  }
+
+  void SetWindowsIsProcessorFeaturePresent(DWORD dwProcessorFeature) {
+    windows_isprocessorfeaturepresent_.insert(dwProcessorFeature);
+  }
+
+  WORD GetWindowsNativeSystemInfoProcessorRevision() const {
+    return processor_revision_;
+  }
+
+  void SetWindowsNativeSystemInfoProcessorRevision(WORD wProcessorRevision) {
+    processor_revision_ = wProcessorRevision;
+  }
+
+ private:
+  std::set<DWORD> windows_isprocessorfeaturepresent_;
+  WORD processor_revision_{};
+#endif  // CPU_FEATURES_OS_WINDOWS
+};
+
+static FakeCpuAarch64* g_fake_cpu_instance = nullptr;
+
+static FakeCpuAarch64& cpu() {
+  assert(g_fake_cpu_instance != nullptr);
+  return *g_fake_cpu_instance;
+}
+
+#if defined(CPU_FEATURES_OS_WINDOWS)
+extern "C" bool GetWindowsIsProcessorFeaturePresent(DWORD dwProcessorFeature) {
+  return cpu().GetWindowsIsProcessorFeaturePresent(dwProcessorFeature);
+}
+
+extern "C" WORD GetWindowsNativeSystemInfoProcessorRevision() {
+  return cpu().GetWindowsNativeSystemInfoProcessorRevision();
+}
+#endif  // CPU_FEATURES_OS_WINDOWS
+
 namespace {
 
+class CpuidAarch64Test : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    assert(g_fake_cpu_instance == nullptr);
+    g_fake_cpu_instance = new FakeCpuAarch64();
+  }
+  void TearDown() override {
+    delete g_fake_cpu_instance;
+    g_fake_cpu_instance = nullptr;
+  }
+};
+
+TEST(CpuinfoAarch64Test, Aarch64FeaturesEnum) {
+  const char* last_name = GetAarch64FeaturesEnumName(AARCH64_LAST_);
+  EXPECT_STREQ(last_name, "unknown_feature");
+  for (int i = static_cast<int>(AARCH64_FP);
+       i != static_cast<int>(AARCH64_LAST_); ++i) {
+    const auto feature = static_cast<Aarch64FeaturesEnum>(i);
+    const char* name = GetAarch64FeaturesEnumName(feature);
+    ASSERT_FALSE(name == nullptr);
+    EXPECT_STRNE(name, "");
+    EXPECT_STRNE(name, last_name);
+  }
+}
+
+#if defined(CPU_FEATURES_OS_LINUX)
 void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); }
 
 TEST(CpuinfoAarch64Test, FromHardwareCap) {
@@ -168,7 +241,36 @@
   EXPECT_FALSE(info.features.rng);
   EXPECT_FALSE(info.features.bti);
   EXPECT_FALSE(info.features.mte);
+  EXPECT_FALSE(info.features.ecv);
+  EXPECT_FALSE(info.features.afp);
+  EXPECT_FALSE(info.features.rpres);
 }
+#endif  // CPU_FEATURES_OS_LINUX
+
+#if defined(CPU_FEATURES_OS_WINDOWS)
+TEST_F(CpuidAarch64Test, WINDOWS_AARCH64_RPI4) {
+  cpu().SetWindowsNativeSystemInfoProcessorRevision(0x03);
+  cpu().SetWindowsIsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE);
+  cpu().SetWindowsIsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE);
+  cpu().SetWindowsIsProcessorFeaturePresent(
+      PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);
+
+  const auto info = GetAarch64Info();
+
+  EXPECT_EQ(info.revision, 0x03);
+  EXPECT_TRUE(info.features.fp);
+  EXPECT_TRUE(info.features.asimd);
+  EXPECT_TRUE(info.features.crc32);
+  EXPECT_FALSE(info.features.aes);
+  EXPECT_FALSE(info.features.sha1);
+  EXPECT_FALSE(info.features.sha2);
+  EXPECT_FALSE(info.features.pmull);
+  EXPECT_FALSE(info.features.atomics);
+  EXPECT_FALSE(info.features.asimddp);
+  EXPECT_FALSE(info.features.jscvt);
+  EXPECT_FALSE(info.features.lrcpc);
+}
+#endif  // CPU_FEATURES_OS_WINDOWS
 
 }  // namespace
 }  // namespace cpu_features
diff --git a/test/cpuinfo_arm_test.cc b/test/cpuinfo_arm_test.cc
index ad7f4e8..745b2af 100644
--- a/test/cpuinfo_arm_test.cc
+++ b/test/cpuinfo_arm_test.cc
@@ -21,6 +21,18 @@
 namespace cpu_features {
 namespace {
 
+TEST(CpuinfoArmTest, ArmFeaturesEnum) {
+   const char *last_name = GetArmFeaturesEnumName(ARM_LAST_);
+   EXPECT_STREQ(last_name, "unknown_feature");
+   for (int i = static_cast<int>(ARM_SWP); i != static_cast<int>(ARM_LAST_); ++i) {
+      const auto feature = static_cast<ArmFeaturesEnum>(i);
+      const char *name = GetArmFeaturesEnumName(feature);
+      ASSERT_FALSE(name == nullptr);
+      EXPECT_STRNE(name, "");
+      EXPECT_STRNE(name, last_name);
+   }
+}
+
 TEST(CpuinfoArmTest, FromHardwareCap) {
   ResetHwcaps();
   SetHardwareCapabilities(ARM_HWCAP_NEON, ARM_HWCAP2_AES | ARM_HWCAP2_CRC32);
diff --git a/test/cpuinfo_mips_test.cc b/test/cpuinfo_mips_test.cc
index a01624a..02ca6c9 100644
--- a/test/cpuinfo_mips_test.cc
+++ b/test/cpuinfo_mips_test.cc
@@ -24,6 +24,18 @@
 
 namespace {
 
+TEST(CpuinfoMipsTest, MipsFeaturesEnum) {
+   const char *last_name = GetMipsFeaturesEnumName(MIPS_LAST_);
+   EXPECT_STREQ(last_name, "unknown_feature");
+   for (int i = static_cast<int>(MIPS_MSA); i != static_cast<int>(MIPS_LAST_); ++i) {
+      const auto feature = static_cast<MipsFeaturesEnum>(i);
+      const char *name = GetMipsFeaturesEnumName(feature);
+      ASSERT_FALSE(name == nullptr);
+      EXPECT_STRNE(name, "");
+      EXPECT_STRNE(name, last_name);
+   }
+}
+
 TEST(CpuinfoMipsTest, FromHardwareCapBoth) {
   ResetHwcaps();
   SetHardwareCapabilities(MIPS_HWCAP_MSA | MIPS_HWCAP_R6, 0);
@@ -69,6 +81,12 @@
   const auto info = GetMipsInfo();
   EXPECT_FALSE(info.features.msa);
   EXPECT_TRUE(info.features.eva);
+  EXPECT_FALSE(info.features.r6);
+  EXPECT_TRUE(info.features.mips16);
+  EXPECT_FALSE(info.features.mdmx);
+  EXPECT_FALSE(info.features.mips3d);
+  EXPECT_FALSE(info.features.smart);
+  EXPECT_TRUE(info.features.dsp);
 }
 
 TEST(CpuinfoMipsTest, AR7161) {
@@ -95,6 +113,7 @@
   const auto info = GetMipsInfo();
   EXPECT_FALSE(info.features.msa);
   EXPECT_FALSE(info.features.eva);
+  EXPECT_TRUE(info.features.mips16);
 }
 
 TEST(CpuinfoMipsTest, Goldfish) {
@@ -122,5 +141,36 @@
   EXPECT_FALSE(info.features.eva);
 }
 
+TEST(CpuinfoMipsTest, BCM1250) {
+  ResetHwcaps();
+  auto& fs = GetEmptyFilesystem();
+  fs.CreateFile("/proc/cpuinfo", R"(system type		: SiByte BCM91250A (SWARM)
+processor		: 0
+cpu model               : SiByte SB1 V0.2  FPU V0.2
+BogoMIPS                : 532.48
+wait instruction        : no
+microsecond timers      : yes
+tlb_entries             : 64
+extra interrupt vector  : yes
+hardware watchpoint     : yes, count: 1, address/irw mask: [0x0ff8]
+isa                     : mips1 mips2 mips3 mips4 mips5 mips32r1 mips32r2 mips64r1 mips64r2
+ASEs implemented        : mdmx mips3d
+shadow register sets    : 1
+kscratch registers      : 0
+package                 : 0
+core                    : 0
+VCED exceptions         : not available
+VCEI exceptions         : not available
+)");
+  const auto info = GetMipsInfo();
+  EXPECT_FALSE(info.features.msa);
+  EXPECT_FALSE(info.features.eva);
+  EXPECT_FALSE(info.features.mips16);
+  EXPECT_TRUE(info.features.mdmx);
+  EXPECT_TRUE(info.features.mips3d);
+  EXPECT_FALSE(info.features.smart);
+  EXPECT_FALSE(info.features.dsp);
+}
+
 }  // namespace
 }  // namespace cpu_features
diff --git a/test/cpuinfo_ppc_test.cc b/test/cpuinfo_ppc_test.cc
index b43a7c8..fc8d288 100644
--- a/test/cpuinfo_ppc_test.cc
+++ b/test/cpuinfo_ppc_test.cc
@@ -22,6 +22,18 @@
 namespace cpu_features {
 namespace {
 
+TEST(CpustringsPPCTest, PPCFeaturesEnum) {
+   const char *last_name = GetPPCFeaturesEnumName(PPC_LAST_);
+   EXPECT_STREQ(last_name, "unknown_feature");
+   for (int i = static_cast<int>(PPC_32); i != static_cast<int>(PPC_LAST_); ++i) {
+      const auto feature = static_cast<PPCFeaturesEnum>(i);
+      const char *name = GetPPCFeaturesEnumName(feature);
+      ASSERT_FALSE(name == nullptr);
+      EXPECT_STRNE(name, "");
+      EXPECT_STRNE(name, last_name);
+   }
+}
+
 TEST(CpustringsPPCTest, FromHardwareCap) {
   ResetHwcaps();
   SetHardwareCapabilities(PPC_FEATURE_HAS_FPU | PPC_FEATURE_HAS_VSX,
diff --git a/test/cpuinfo_riscv_test.cc b/test/cpuinfo_riscv_test.cc
new file mode 100644
index 0000000..2ffe2b3
--- /dev/null
+++ b/test/cpuinfo_riscv_test.cc
@@ -0,0 +1,180 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cpuinfo_riscv.h"
+
+#include "filesystem_for_testing.h"
+#include "gtest/gtest.h"
+#include "hwcaps_for_testing.h"
+
+namespace cpu_features {
+namespace {
+
+TEST(CpuinfoRiscvTest, Sipeed_Lichee_RV_FromCpuInfo) {
+  ResetHwcaps();
+  auto& fs = GetEmptyFilesystem();
+  fs.CreateFile("/proc/cpuinfo", R"(processor	: 0 
+hart  : 0
+isa   : rv64imafdc
+mmu   : sv39
+uarch : thead,c906)");
+  const auto info = GetRiscvInfo();
+  EXPECT_STREQ(info.uarch, "c906");
+  EXPECT_STREQ(info.vendor, "thead");
+
+  EXPECT_FALSE(info.features.RV32I);
+  EXPECT_TRUE(info.features.RV64I);
+  EXPECT_TRUE(info.features.M);
+  EXPECT_TRUE(info.features.A);
+  EXPECT_TRUE(info.features.F);
+  EXPECT_TRUE(info.features.D);
+  EXPECT_FALSE(info.features.Q);
+  EXPECT_TRUE(info.features.C);
+  EXPECT_FALSE(info.features.V);
+}
+
+// https://github.com/ThomasKaiser/sbc-bench/blob/284e82b016ec1beeac42a5fcbe556b670f68441a/results/Kendryte-K510-4.17.0.cpuinfo
+TEST(CpuinfoRiscvTest, Kendryte_K510_FromCpuInfo) {
+  ResetHwcaps();
+  auto& fs = GetEmptyFilesystem();
+  fs.CreateFile("/proc/cpuinfo", R"(
+hart	: 0
+isa	: rv64i2p0m2p0a2p0f2p0d2p0c2p0xv5-0p0
+mmu	: sv39
+
+hart	: 1
+isa	: rv64i2p0m2p0a2p0f2p0d2p0c2p0xv5-0p0
+mmu	: sv39");
+  const auto info = GetRiscvInfo();
+  EXPECT_STREQ(info.uarch, "");
+  EXPECT_STREQ(info.vendor, "");
+
+  EXPECT_FALSE(info.features.RV32I);
+  EXPECT_TRUE(info.features.RV64I);
+  EXPECT_TRUE(info.features.M);
+  EXPECT_TRUE(info.features.A);
+  EXPECT_TRUE(info.features.F);
+  EXPECT_TRUE(info.features.D);
+  EXPECT_FALSE(info.features.Q);
+  EXPECT_TRUE(info.features.C);
+  EXPECT_FALSE(info.features.V);
+}
+
+// https://github.com/ThomasKaiser/sbc-bench/blob/284e82b016ec1beeac42a5fcbe556b670f68441a/results/T-Head-C910-5.10.4.cpuinfo
+TEST(CpuinfoRiscvTest, T_Head_C910_FromCpuInfo) {
+  ResetHwcaps();
+  auto& fs = GetEmptyFilesystem();
+  fs.CreateFile("/proc/cpuinfo", R"(
+processor	: 0
+hart		: 0
+isa		: rv64imafdcsu
+mmu		: sv39
+cpu-freq	: 1.2Ghz
+cpu-icache	: 64KB
+cpu-dcache	: 64KB
+cpu-l2cache	: 2MB
+cpu-tlb		: 1024 4-ways
+cpu-cacheline	: 64Bytes
+cpu-vector	: 0.7.1
+
+processor	: 1
+hart		: 1
+isa		: rv64imafdcsu
+mmu		: sv39
+cpu-freq	: 1.2Ghz
+cpu-icache	: 64KB
+cpu-dcache	: 64KB
+cpu-l2cache	: 2MB
+cpu-tlb		: 1024 4-ways
+cpu-cacheline	: 64Bytes
+cpu-vector	: 0.7.1");
+  const auto info = GetRiscvInfo();
+  EXPECT_STREQ(info.uarch, "");
+  EXPECT_STREQ(info.vendor, "");
+
+  EXPECT_FALSE(info.features.RV32I);
+  EXPECT_TRUE(info.features.RV64I);
+  EXPECT_TRUE(info.features.M);
+  EXPECT_TRUE(info.features.A);
+  EXPECT_TRUE(info.features.F);
+  EXPECT_TRUE(info.features.D);
+  EXPECT_FALSE(info.features.Q);
+  EXPECT_TRUE(info.features.C);
+  EXPECT_FALSE(info.features.V);
+}
+
+TEST(CpuinfoRiscvTest, UnknownFromCpuInfo) {
+  ResetHwcaps();
+  auto& fs = GetEmptyFilesystem();
+  fs.CreateFile("/proc/cpuinfo", R"(
+processor : 0
+hart      : 2
+isa       : rv64imafdc
+mmu       : sv39
+uarch     : sifive,bullet0
+
+processor : 1
+hart      : 1
+isa       : rv64imafdc
+mmu       : sv39
+uarch     : sifive,bullet0
+
+processor : 2
+hart      : 3
+isa       : rv64imafdc
+mmu       : sv39
+uarch     : sifive,bullet0
+
+processor : 3
+hart      : 4
+isa       : rv64imafdc
+mmu       : sv39
+uarch     : sifive,bullet0)");
+  const auto info = GetRiscvInfo();
+  EXPECT_STREQ(info.uarch, "bullet0");
+  EXPECT_STREQ(info.vendor, "sifive");
+
+  EXPECT_FALSE(info.features.RV32I);
+  EXPECT_TRUE(info.features.RV64I);
+  EXPECT_TRUE(info.features.M);
+  EXPECT_TRUE(info.features.A);
+  EXPECT_TRUE(info.features.F);
+  EXPECT_TRUE(info.features.D);
+  EXPECT_FALSE(info.features.Q);
+  EXPECT_TRUE(info.features.C);
+  EXPECT_FALSE(info.features.V);
+}
+
+TEST(CpuinfoRiscvTest, QemuCpuInfo) {
+  ResetHwcaps();
+  auto& fs = GetEmptyFilesystem();
+  fs.CreateFile("/proc/cpuinfo", R"(
+processor	: 0
+hart		: 0
+isa		: rv64imafdcvh_zba_zbb_zbc_zbs
+mmu		: sv48)");
+  const auto info = GetRiscvInfo();
+  EXPECT_FALSE(info.features.RV32I);
+  EXPECT_TRUE(info.features.RV64I);
+  EXPECT_TRUE(info.features.M);
+  EXPECT_TRUE(info.features.A);
+  EXPECT_TRUE(info.features.F);
+  EXPECT_TRUE(info.features.D);
+  EXPECT_FALSE(info.features.Q);
+  EXPECT_TRUE(info.features.C);
+  EXPECT_TRUE(info.features.V);
+}
+
+}  // namespace
+}  // namespace cpu_features
diff --git a/test/cpuinfo_s390x_test.cc b/test/cpuinfo_s390x_test.cc
new file mode 100644
index 0000000..800d3e9
--- /dev/null
+++ b/test/cpuinfo_s390x_test.cc
@@ -0,0 +1,82 @@
+// Copyright 2022 IBM.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cpuinfo_s390x.h"
+#include "filesystem_for_testing.h"
+#include "gtest/gtest.h"
+#include "hwcaps_for_testing.h"
+
+namespace cpu_features {
+namespace {
+
+TEST(CpustringsS390XTest, S390XFeaturesEnum) {
+   const char *last_name = GetS390XFeaturesEnumName(S390X_LAST_);
+   EXPECT_STREQ(last_name, "unknown_feature");
+   for (int i = static_cast<int>(S390_ZARCH); i != static_cast<int>(S390X_LAST_); ++i) {
+      const auto feature = static_cast<S390XFeaturesEnum>(i);
+      const char *name = GetS390XFeaturesEnumName(feature);
+      ASSERT_FALSE(name == nullptr);
+      EXPECT_STRNE(name, "");
+      EXPECT_STRNE(name, last_name);
+   }
+}
+
+TEST(CpustringsS390XTest, FromHardwareCap) {
+  ResetHwcaps();
+  SetHardwareCapabilities(HWCAP_S390_ESAN3 | HWCAP_S390_HPAGE |
+          HWCAP_S390_NNPA | HWCAP_S390_SIE, 0);
+  GetEmptyFilesystem();  // disabling /proc/cpuinfo
+  const auto info = GetS390XInfo();
+  EXPECT_TRUE(info.features.esan3);
+  EXPECT_TRUE(info.features.edat);
+  EXPECT_TRUE(info.features.nnpa);
+  EXPECT_TRUE(info.features.sie);
+  EXPECT_FALSE(info.features.msa);
+  EXPECT_FALSE(info.features.stfle);
+  EXPECT_FALSE(info.features.vxp2);
+  EXPECT_FALSE(info.features.pcimio);
+}
+
+TEST(CpustringsS390XTest, z16) {
+  ResetHwcaps();
+  auto& fs = GetEmptyFilesystem();
+  fs.CreateFile("/proc/cpuinfo",
+                R"(vendor_id       : IBM/S390
+# processors    : 24
+bogomips per cpu: 26315.00
+max thread id   : 1
+features	: esan3 zarch stfle msa ldisp eimm dfp edat etf3eh highgprs te vx vxd vxe gs vxe2 vxp sort dflt vxp2 nnpa pcimio sie )");
+  SetPlatformPointer("z16");
+  const auto strings = GetS390XPlatformStrings();
+  EXPECT_EQ(strings.num_processors, 24);
+  ASSERT_STREQ(strings.type.platform, "z16");
+}
+
+TEST(CpustringsS390XTest, z15) {
+  ResetHwcaps();
+  auto& fs = GetEmptyFilesystem();
+  fs.CreateFile("/proc/cpuinfo",
+                R"(vendor_id       : IBM/S390
+# processors    : 2
+bogomips per cpu: 24038.00
+max thread id   : 1
+features    : esan3 zarch stfle msa ldisp eimm dfp edat etf3eh highgprs te vx vxd vxe gs vxe2 vxp sort dflt sie)");
+  SetPlatformPointer("z15");
+  const auto strings = GetS390XPlatformStrings();
+  EXPECT_EQ(strings.num_processors, 2);
+  ASSERT_STREQ(strings.type.platform, "z15");
+}
+
+}  // namespace
+}  // namespace cpu_features
diff --git a/test/cpuinfo_x86_test.cc b/test/cpuinfo_x86_test.cc
index 56243b9..de271cc 100644
--- a/test/cpuinfo_x86_test.cc
+++ b/test/cpuinfo_x86_test.cc
@@ -19,8 +19,8 @@
 #include <map>
 #include <set>
 #if defined(CPU_FEATURES_OS_WINDOWS)
-#include <windows.h>  // IsProcessorFeaturePresent
-#endif                // CPU_FEATURES_OS_WINDOWS
+#include "internal/windows_utils.h"
+#endif  // CPU_FEATURES_OS_WINDOWS
 
 #include "filesystem_for_testing.h"
 #include "gtest/gtest.h"
@@ -118,6 +118,30 @@
   }
 };
 
+TEST_F(CpuidX86Test, X86MicroarchitectureEnum) {
+   const char *last_name = GetX86MicroarchitectureName(X86_MICROARCHITECTURE_LAST_);
+   EXPECT_STREQ(last_name, "unknown microarchitecture");
+   for (int i = static_cast<int>(X86_UNKNOWN); i != static_cast<int>(X86_MICROARCHITECTURE_LAST_); ++i) {
+      const auto micro = static_cast<X86Microarchitecture>(i);
+      const char *name = GetX86MicroarchitectureName(micro);
+      ASSERT_FALSE(name == nullptr);
+      EXPECT_STRNE(name, "");
+      EXPECT_STRNE(name, last_name);
+   }
+}
+
+TEST_F(CpuidX86Test, X86FeaturesEnum) {
+   const char *last_name = GetX86FeaturesEnumName(X86_LAST_);
+   EXPECT_STREQ(last_name, "unknown_feature");
+   for (int i = static_cast<int>(X86_FPU); i != static_cast<int>(X86_LAST_); ++i) {
+      const auto feature = static_cast<X86FeaturesEnum>(i);
+      const char *name = GetX86FeaturesEnumName(feature);
+      ASSERT_FALSE(name == nullptr);
+      EXPECT_STRNE(name, "");
+      EXPECT_STRNE(name, last_name);
+   }
+}
+
 TEST_F(CpuidX86Test, SandyBridge) {
   cpu().SetOsBackupsExtendedRegisters(true);
   cpu().SetLeaves({
@@ -126,7 +150,7 @@
       {{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
   });
   const auto info = GetX86Info();
-  EXPECT_STREQ(info.vendor, "GenuineIntel");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
   EXPECT_EQ(info.family, 0x06);
   EXPECT_EQ(info.model, 0x02A);
   EXPECT_EQ(info.stepping, 0x06);
@@ -188,13 +212,41 @@
       {{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
   });
   const auto info = GetX86Info();
-  EXPECT_STREQ(info.vendor, "GenuineIntel");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
   EXPECT_EQ(info.family, 0x06);
   EXPECT_EQ(info.model, 0x04E);
   EXPECT_EQ(info.stepping, 0x03);
   EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_SKL);
 }
 
+// http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel0050654_SkylakeXeon_CPUID8.txt
+TEST_F(CpuidX86Test, SkyLakeXeon) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
+      {{0x00000001, 0}, Leaf{0x00050654, 0x00100800, 0x7FFEFBFF, 0xBFEBFBFF}}
+  });
+  const auto info = GetX86Info();
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
+  EXPECT_EQ(info.family, 0x06);
+  EXPECT_EQ(info.model, 0x055);
+  EXPECT_EQ(info.stepping, 0x04);
+  EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_SKL);
+}
+
+// http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel0050657_CascadeLakeXeon_CPUID.txt
+TEST_F(CpuidX86Test, CascadeLake) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
+      {{0x00000001, 0}, Leaf{0x00050657, 0x00400800, 0x7FFEFBFF, 0xBFEBFBFF}}
+  });
+  const auto info = GetX86Info();
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
+  EXPECT_EQ(info.family, 0x06);
+  EXPECT_EQ(info.model, 0x055);
+  EXPECT_EQ(info.stepping, 0x07);
+  EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_CCL);
+}
+
 TEST_F(CpuidX86Test, Branding) {
   cpu().SetLeaves({
       {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
@@ -206,9 +258,8 @@
       {{0x80000003, 0}, Leaf{0x37692029, 0x3035362D, 0x43205530, 0x40205550}},
       {{0x80000004, 0}, Leaf{0x352E3220, 0x7A484730, 0x00000000, 0x00000000}},
   });
-  char brand_string[49];
-  FillX86BrandString(brand_string);
-  EXPECT_STREQ(brand_string, "Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz");
+  const auto info = GetX86Info();
+  EXPECT_STREQ(info.brand_string, "Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz");
 }
 
 TEST_F(CpuidX86Test, KabyLakeCache) {
@@ -228,7 +279,7 @@
   const auto info = GetX86CacheInfo();
   EXPECT_EQ(info.size, 4);
   EXPECT_EQ(info.levels[0].level, 1);
-  EXPECT_EQ(info.levels[0].cache_type, 1);
+  EXPECT_EQ(info.levels[0].cache_type, CacheType::CPU_FEATURE_CACHE_DATA);
   EXPECT_EQ(info.levels[0].cache_size, 32 * KiB);
   EXPECT_EQ(info.levels[0].ways, 8);
   EXPECT_EQ(info.levels[0].line_size, 64);
@@ -236,7 +287,8 @@
   EXPECT_EQ(info.levels[0].partitioning, 1);
 
   EXPECT_EQ(info.levels[1].level, 1);
-  EXPECT_EQ(info.levels[1].cache_type, 2);
+  EXPECT_EQ(info.levels[1].cache_type,
+            CacheType::CPU_FEATURE_CACHE_INSTRUCTION);
   EXPECT_EQ(info.levels[1].cache_size, 32 * KiB);
   EXPECT_EQ(info.levels[1].ways, 8);
   EXPECT_EQ(info.levels[1].line_size, 64);
@@ -244,7 +296,7 @@
   EXPECT_EQ(info.levels[1].partitioning, 1);
 
   EXPECT_EQ(info.levels[2].level, 2);
-  EXPECT_EQ(info.levels[2].cache_type, 3);
+  EXPECT_EQ(info.levels[2].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED);
   EXPECT_EQ(info.levels[2].cache_size, 256 * KiB);
   EXPECT_EQ(info.levels[2].ways, 4);
   EXPECT_EQ(info.levels[2].line_size, 64);
@@ -252,7 +304,7 @@
   EXPECT_EQ(info.levels[2].partitioning, 1);
 
   EXPECT_EQ(info.levels[3].level, 3);
-  EXPECT_EQ(info.levels[3].cache_type, 3);
+  EXPECT_EQ(info.levels[3].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED);
   EXPECT_EQ(info.levels[3].cache_size, 6 * MiB);
   EXPECT_EQ(info.levels[3].ways, 12);
   EXPECT_EQ(info.levels[3].line_size, 64);
@@ -277,7 +329,7 @@
   const auto info = GetX86CacheInfo();
   EXPECT_EQ(info.size, 4);
   EXPECT_EQ(info.levels[0].level, 1);
-  EXPECT_EQ(info.levels[0].cache_type, 1);
+  EXPECT_EQ(info.levels[0].cache_type, CacheType::CPU_FEATURE_CACHE_DATA);
   EXPECT_EQ(info.levels[0].cache_size, 32 * KiB);
   EXPECT_EQ(info.levels[0].ways, 8);
   EXPECT_EQ(info.levels[0].line_size, 64);
@@ -285,7 +337,8 @@
   EXPECT_EQ(info.levels[0].partitioning, 1);
 
   EXPECT_EQ(info.levels[1].level, 1);
-  EXPECT_EQ(info.levels[1].cache_type, 2);
+  EXPECT_EQ(info.levels[1].cache_type,
+            CacheType::CPU_FEATURE_CACHE_INSTRUCTION);
   EXPECT_EQ(info.levels[1].cache_size, 32 * KiB);
   EXPECT_EQ(info.levels[1].ways, 8);
   EXPECT_EQ(info.levels[1].line_size, 64);
@@ -293,7 +346,7 @@
   EXPECT_EQ(info.levels[1].partitioning, 1);
 
   EXPECT_EQ(info.levels[2].level, 2);
-  EXPECT_EQ(info.levels[2].cache_type, 3);
+  EXPECT_EQ(info.levels[2].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED);
   EXPECT_EQ(info.levels[2].cache_size, 256 * KiB);
   EXPECT_EQ(info.levels[2].ways, 8);
   EXPECT_EQ(info.levels[2].line_size, 64);
@@ -301,7 +354,7 @@
   EXPECT_EQ(info.levels[2].partitioning, 1);
 
   EXPECT_EQ(info.levels[3].level, 3);
-  EXPECT_EQ(info.levels[3].cache_type, 3);
+  EXPECT_EQ(info.levels[3].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED);
   EXPECT_EQ(info.levels[3].cache_size, 6 * MiB);
   EXPECT_EQ(info.levels[3].ways, 12);
   EXPECT_EQ(info.levels[3].line_size, 64);
@@ -319,7 +372,7 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "AuthenticAMD");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
   EXPECT_EQ(info.family, 0x11);
   EXPECT_EQ(info.model, 0x03);
   EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_K11);
@@ -335,7 +388,7 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "AuthenticAMD");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
   EXPECT_EQ(info.family, 0x12);
   EXPECT_EQ(info.model, 0x01);
   EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_K12);
@@ -351,7 +404,7 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "AuthenticAMD");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
   EXPECT_EQ(info.family, 0x14);
   EXPECT_EQ(info.model, 0x00);
   EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_BOBCAT);
@@ -375,7 +428,7 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "AuthenticAMD");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
   EXPECT_EQ(info.family, 0x14);
   EXPECT_EQ(info.model, 0x01);
   EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_BOBCAT);
@@ -391,7 +444,7 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "AuthenticAMD");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
   EXPECT_EQ(info.family, 0x14);
   EXPECT_EQ(info.model, 0x02);
   EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_BOBCAT);
@@ -411,17 +464,13 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "AuthenticAMD");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
   EXPECT_EQ(info.family, 0x15);
   EXPECT_EQ(info.model, 0x70);
   EXPECT_STREQ(info.brand_string,
                "AMD A9-9410 RADEON R5, 5 COMPUTE CORES 2C+3G   ");
   EXPECT_EQ(GetX86Microarchitecture(&info),
             X86Microarchitecture::AMD_EXCAVATOR);
-
-  char brand_string[49];
-  FillX86BrandString(brand_string);
-  EXPECT_STREQ(brand_string, "AMD A9-9410 RADEON R5, 5 COMPUTE CORES 2C+3G   ");
 }
 
 // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F20_K15_AbuDhabi_CPUID0.txt
@@ -438,7 +487,7 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "AuthenticAMD");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
   EXPECT_EQ(info.family, 0x15);
   EXPECT_EQ(info.model, 0x02);
   EXPECT_STREQ(info.brand_string,
@@ -446,9 +495,7 @@
   EXPECT_EQ(GetX86Microarchitecture(&info),
             X86Microarchitecture::AMD_PILEDRIVER);
 
-  char brand_string[49];
-  FillX86BrandString(brand_string);
-  EXPECT_STREQ(brand_string, "AMD Opteron(tm) Processor 6376                 ");
+  EXPECT_STREQ(info.brand_string, "AMD Opteron(tm) Processor 6376                 ");
 }
 
 // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F20_K15_AbuDhabi_CPUID0.txt
@@ -467,7 +514,7 @@
 
   EXPECT_EQ(info.size, 4);
   EXPECT_EQ(info.levels[0].level, 1);
-  EXPECT_EQ(info.levels[0].cache_type, 1);
+  EXPECT_EQ(info.levels[0].cache_type, CacheType::CPU_FEATURE_CACHE_DATA);
   EXPECT_EQ(info.levels[0].cache_size, 16 * KiB);
   EXPECT_EQ(info.levels[0].ways, 4);
   EXPECT_EQ(info.levels[0].line_size, 64);
@@ -475,7 +522,8 @@
   EXPECT_EQ(info.levels[0].partitioning, 1);
 
   EXPECT_EQ(info.levels[1].level, 1);
-  EXPECT_EQ(info.levels[1].cache_type, 2);
+  EXPECT_EQ(info.levels[1].cache_type,
+            CacheType::CPU_FEATURE_CACHE_INSTRUCTION);
   EXPECT_EQ(info.levels[1].cache_size, 64 * KiB);
   EXPECT_EQ(info.levels[1].ways, 2);
   EXPECT_EQ(info.levels[1].line_size, 64);
@@ -483,7 +531,7 @@
   EXPECT_EQ(info.levels[1].partitioning, 1);
 
   EXPECT_EQ(info.levels[2].level, 2);
-  EXPECT_EQ(info.levels[2].cache_type, 3);
+  EXPECT_EQ(info.levels[2].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED);
   EXPECT_EQ(info.levels[2].cache_size, 2 * MiB);
   EXPECT_EQ(info.levels[2].ways, 16);
   EXPECT_EQ(info.levels[2].line_size, 64);
@@ -491,7 +539,7 @@
   EXPECT_EQ(info.levels[2].partitioning, 1);
 
   EXPECT_EQ(info.levels[3].level, 3);
-  EXPECT_EQ(info.levels[3].cache_type, 3);
+  EXPECT_EQ(info.levels[3].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED);
   EXPECT_EQ(info.levels[3].cache_size, 6 * MiB);
   EXPECT_EQ(info.levels[3].ways, 48);
   EXPECT_EQ(info.levels[3].line_size, 64);
@@ -499,6 +547,29 @@
   EXPECT_EQ(info.levels[3].partitioning, 1);
 }
 
+// https://github.com/InstLatx64/InstLatx64/blob/master/AuthenticAMD/AuthenticAMD0610F01_K15_Piledriver_CPUID.txt
+TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_A10) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
+      {{0x00000001, 0}, Leaf{0x00610F01, 0x00040800, 0x3E98320B, 0x178BFBFF}},
+      {{0x00000007, 0}, Leaf{0x00000000, 0x00000008, 0x00000000, 0x00000000}},
+      {{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}},
+      {{0x80000001, 0}, Leaf{0x00610F01, 0x20000000, 0x01EBBFFF, 0x2FD3FBFF}},
+      {{0x80000002, 0}, Leaf{0x20444D41, 0x2D303141, 0x30303835, 0x5041204B}},
+      {{0x80000003, 0}, Leaf{0x69772055, 0x52206874, 0x6F656461, 0x6D74286E}},
+      {{0x80000004, 0}, Leaf{0x44482029, 0x61724720, 0x63696870, 0x00202073}},
+  });
+  const auto info = GetX86Info();
+
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
+  EXPECT_EQ(info.family, 0x15);
+  EXPECT_EQ(info.model, 0x10);
+  EXPECT_STREQ(info.brand_string,
+               "AMD A10-5800K APU with Radeon(tm) HD Graphics  ");
+  EXPECT_EQ(GetX86Microarchitecture(&info),
+            X86Microarchitecture::AMD_PILEDRIVER);
+}
+
 // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F12_K15_Interlagos_CPUID3.txt
 TEST_F(CpuidX86Test, AMD_K15_BULLDOZER_INTERLAGOS) {
   cpu().SetLeaves({
@@ -513,17 +584,13 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "AuthenticAMD");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
   EXPECT_EQ(info.family, 0x15);
   EXPECT_EQ(info.model, 0x01);
   EXPECT_STREQ(info.brand_string,
                "AMD Opteron(TM) Processor 6238                 ");
   EXPECT_EQ(GetX86Microarchitecture(&info),
             X86Microarchitecture::AMD_BULLDOZER);
-
-  char brand_string[49];
-  FillX86BrandString(brand_string);
-  EXPECT_STREQ(brand_string, "AMD Opteron(TM) Processor 6238                 ");
 }
 
 // http://users.atw.hu/instlatx64/AuthenticAMD0630F81_K15_Godavari_CPUID.txt
@@ -541,7 +608,7 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "AuthenticAMD");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
   EXPECT_EQ(info.family, 0x15);
   EXPECT_EQ(info.model, 0x38);
   EXPECT_EQ(info.stepping, 0x01);
@@ -549,10 +616,27 @@
                "AMD A8-7670K Radeon R7, 10 Compute Cores 4C+6G ");
   EXPECT_EQ(GetX86Microarchitecture(&info),
             X86Microarchitecture::AMD_STREAMROLLER);
+}
 
-  char brand_string[49];
-  FillX86BrandString(brand_string);
-  EXPECT_STREQ(brand_string, "AMD A8-7670K Radeon R7, 10 Compute Cores 4C+6G ");
+// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F12_K15_Zambezi8C_CPUID.txt
+TEST_F(CpuidX86Test, AMD_K15_BULLDOZER_ZAMBEZI_ABM) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
+      {{0x00000001, 0}, Leaf{0x00600F12, 0x00080800, 0x1E98220B, 0x178BFBFF}},
+      {{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+      {{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}},
+      {{0x80000001, 0}, Leaf{0x00600F12, 0x10000000, 0x01C9BFFF, 0x2FD3FBFF}},
+  });
+  const auto info = GetX86Info();
+
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
+  EXPECT_EQ(info.family, 0x15);
+  EXPECT_EQ(info.model, 0x01);
+
+  EXPECT_EQ(GetX86Microarchitecture(&info),
+            X86Microarchitecture::AMD_BULLDOZER);
+
+  EXPECT_TRUE(info.features.lzcnt);
 }
 
 // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0700F01_K16_Kabini_CPUID.txt
@@ -569,16 +653,12 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "AuthenticAMD");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
   EXPECT_EQ(info.family, 0x16);
   EXPECT_EQ(info.model, 0x00);
   EXPECT_STREQ(info.brand_string,
                "AMD A4-5000 APU with Radeon(TM) HD Graphics    ");
   EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_JAGUAR);
-
-  char brand_string[49];
-  FillX86BrandString(brand_string);
-  EXPECT_STREQ(brand_string, "AMD A4-5000 APU with Radeon(TM) HD Graphics    ");
 }
 
 // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0730F01_K16_Beema_CPUID2.txt
@@ -595,16 +675,34 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "AuthenticAMD");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
   EXPECT_EQ(info.family, 0x16);
   EXPECT_EQ(info.model, 0x30);
   EXPECT_STREQ(info.brand_string,
                "AMD A6-6310 APU with AMD Radeon R4 Graphics    ");
   EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_PUMA);
+}
 
-  char brand_string[49];
-  FillX86BrandString(brand_string);
-  EXPECT_STREQ(brand_string, "AMD A6-6310 APU with AMD Radeon R4 Graphics    ");
+// https://github.com/InstLatx64/InstLatx64/blob/master/AuthenticAMD/AuthenticAMD0720F61_K16_Cato_CPUID.txt
+TEST_F(CpuidX86Test, AMD_K16_CATO) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
+      {{0x00000001, 0}, Leaf{0x00720F61, 0x00080800, 0x3ED8220B, 0x178BFBFF}},
+      {{0x00000007, 0}, Leaf{0x00000000, 0x00000008, 0x00000000, 0x00000000}},
+      {{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}},
+      {{0x80000001, 0}, Leaf{0x00720F61, 0x00000000, 0x154837FF, 0x2FD3FBFF}},
+      {{0x80000002, 0}, Leaf{0x20444D41, 0x392D3941, 0x20303238, 0x636F7250}},
+      {{0x80000003, 0}, Leaf{0x6F737365, 0x00000072, 0x00000000, 0x00000000}},
+      {{0x80000004, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+  });
+  const auto info = GetX86Info();
+
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
+  EXPECT_EQ(info.family, 0x16);
+  EXPECT_EQ(info.model, 0x26);
+  EXPECT_STREQ(info.brand_string,
+               "AMD A9-9820 Processor");
+  EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_JAGUAR);
 }
 
 // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0820F01_K17_Dali_CPUID.txt
@@ -621,16 +719,12 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "AuthenticAMD");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
   EXPECT_EQ(info.family, 0x17);
   EXPECT_EQ(info.model, 0x20);
   EXPECT_STREQ(info.brand_string,
                "AMD 3020e with Radeon Graphics                 ");
   EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN);
-
-  char brand_string[49];
-  FillX86BrandString(brand_string);
-  EXPECT_STREQ(brand_string, "AMD 3020e with Radeon Graphics                 ");
 }
 
 // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0800F82_K17_ZenP_CPUID.txt
@@ -647,16 +741,12 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "AuthenticAMD");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
   EXPECT_EQ(info.family, 0x17);
   EXPECT_EQ(info.model, 0x08);
   EXPECT_STREQ(info.brand_string,
                "AMD Ryzen 7 2700X Eight-Core Processor         ");
   EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN_PLUS);
-
-  char brand_string[49];
-  FillX86BrandString(brand_string);
-  EXPECT_STREQ(brand_string, "AMD Ryzen 7 2700X Eight-Core Processor         ");
 }
 
 // http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0840F70_K17_CPUID.txt
@@ -673,15 +763,11 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "AuthenticAMD");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
   EXPECT_EQ(info.family, 0x17);
   EXPECT_EQ(info.model, 0x47);
   EXPECT_STREQ(info.brand_string, "AMD 4700S 8-Core Processor Desktop Kit");
   EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN2);
-
-  char brand_string[49];
-  FillX86BrandString(brand_string);
-  EXPECT_STREQ(brand_string, "AMD 4700S 8-Core Processor Desktop Kit");
 }
 
 // http://users.atw.hu/instlatx64/HygonGenuine/HygonGenuine0900F02_Hygon_CPUID3.txt
@@ -698,16 +784,12 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "HygonGenuine");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_HYGON_GENUINE);
   EXPECT_EQ(info.family, 0x18);
   EXPECT_EQ(info.model, 0x00);
   EXPECT_STREQ(info.brand_string,
                "Hygon C86 3185  8-core Processor               ");
   EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN);
-
-  char brand_string[49];
-  FillX86BrandString(brand_string);
-  EXPECT_STREQ(brand_string, "Hygon C86 3185  8-core Processor               ");
 }
 
 // http://users.atw.hu/instlatx64/HygonGenuine/HygonGenuine0900F02_Hygon_CPUID.txt
@@ -726,7 +808,7 @@
 
   EXPECT_EQ(info.size, 4);
   EXPECT_EQ(info.levels[0].level, 1);
-  EXPECT_EQ(info.levels[0].cache_type, 1);
+  EXPECT_EQ(info.levels[0].cache_type, CacheType::CPU_FEATURE_CACHE_DATA);
   EXPECT_EQ(info.levels[0].cache_size, 32 * KiB);
   EXPECT_EQ(info.levels[0].ways, 8);
   EXPECT_EQ(info.levels[0].line_size, 64);
@@ -734,7 +816,8 @@
   EXPECT_EQ(info.levels[0].partitioning, 1);
 
   EXPECT_EQ(info.levels[1].level, 1);
-  EXPECT_EQ(info.levels[1].cache_type, 2);
+  EXPECT_EQ(info.levels[1].cache_type,
+            CacheType::CPU_FEATURE_CACHE_INSTRUCTION);
   EXPECT_EQ(info.levels[1].cache_size, 64 * KiB);
   EXPECT_EQ(info.levels[1].ways, 4);
   EXPECT_EQ(info.levels[1].line_size, 64);
@@ -742,7 +825,7 @@
   EXPECT_EQ(info.levels[1].partitioning, 1);
 
   EXPECT_EQ(info.levels[2].level, 2);
-  EXPECT_EQ(info.levels[2].cache_type, 3);
+  EXPECT_EQ(info.levels[2].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED);
   EXPECT_EQ(info.levels[2].cache_size, 512 * KiB);
   EXPECT_EQ(info.levels[2].ways, 8);
   EXPECT_EQ(info.levels[2].line_size, 64);
@@ -750,7 +833,7 @@
   EXPECT_EQ(info.levels[2].partitioning, 1);
 
   EXPECT_EQ(info.levels[3].level, 3);
-  EXPECT_EQ(info.levels[3].cache_type, 3);
+  EXPECT_EQ(info.levels[3].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED);
   EXPECT_EQ(info.levels[3].cache_size, 8 * MiB);
   EXPECT_EQ(info.levels[3].ways, 16);
   EXPECT_EQ(info.levels[3].line_size, 64);
@@ -772,16 +855,342 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "AuthenticAMD");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
   EXPECT_EQ(info.family, 0x19);
   EXPECT_EQ(info.model, 0x21);
   EXPECT_STREQ(info.brand_string,
                "AMD Ryzen 9 5900X 12-Core Processor            ");
   EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN3);
+}
 
-  char brand_string[49];
-  FillX86BrandString(brand_string);
-  EXPECT_STREQ(brand_string, "AMD Ryzen 9 5900X 12-Core Processor            ");
+// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0A40F41_K19_Rembrandt_03_CPUID.txt
+TEST_F(CpuidX86Test, AMD_K19_ZEN3) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x00000010, 0x68747541, 0x444D4163, 0x69746E65}},
+      {{0x00000001, 0}, Leaf{0x00A40F41, 0x00100800, 0x7EF8320B, 0x178BFBFF}},
+      {{0x80000000, 0}, Leaf{0x80000023, 0x68747541, 0x444D4163, 0x69746E65}},
+      {{0x80000001, 0}, Leaf{0x00A40F41, 0x50000000, 0x75C237FF, 0x2FD3FBFF}},
+      {{0x80000002, 0}, Leaf{0x20444D41, 0x657A7952, 0x2039206E, 0x30303936}},
+      {{0x80000003, 0}, Leaf{0x77205848, 0x20687469, 0x65646152, 0x47206E6F}},
+      {{0x80000004, 0}, Leaf{0x68706172, 0x20736369, 0x20202020, 0x00202020}},
+  });
+  const auto info = GetX86Info();
+
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
+  EXPECT_EQ(info.family, 0x19);
+  EXPECT_EQ(info.model, 0x44);
+  EXPECT_STREQ(info.brand_string,
+               "AMD Ryzen 9 6900HX with Radeon Graphics        ");
+  EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN3);
+}
+
+// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0A60F12_K19_Raphael_01_CPUID.txt
+TEST_F(CpuidX86Test, AMD_K19_ZEN4_RAPHAEL) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x00000010, 0x68747541, 0x444D4163, 0x69746E65}},
+      {{0x00000001, 0}, Leaf{0x00A60F12, 0x000C0800, 0x7EF8320B, 0x178BFBFF}},
+      {{0x80000000, 0}, Leaf{0x80000028, 0x68747541, 0x444D4163, 0x69746E65}},
+      {{0x80000001, 0}, Leaf{0x00A60F12, 0x00000000, 0x75C237FF, 0x2FD3FBFF}},
+      {{0x80000002, 0}, Leaf{0x20444D41, 0x657A7952, 0x2035206E, 0x30303637}},
+      {{0x80000003, 0}, Leaf{0x2D362058, 0x65726F43, 0x6F725020, 0x73736563}},
+      {{0x80000004, 0}, Leaf{0x2020726F, 0x20202020, 0x20202020, 0x00202020}},
+  });
+  const auto info = GetX86Info();
+
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
+  EXPECT_EQ(info.family, 0x19);
+  EXPECT_EQ(info.model, 0x61);
+  EXPECT_STREQ(info.brand_string,
+               "AMD Ryzen 5 7600X 6-Core Processor             ");
+  EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN4);
+}
+
+// http://users.atw.hu/instlatx64/HygonGenuine/HygonGenuine0900F11_Hygon_01_CPUID.txt
+TEST_F(CpuidX86Test, AMD_K18_ZEN_DHYANA_OCTAL_CORE_C86_3250) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x0000000D, 0x6F677948, 0x656E6975, 0x6E65476E}},
+      {{0x00000001, 0}, Leaf{0x00900F11, 0x00100800, 0x76D8320B, 0x178BFBFF}},
+      {{0x80000000, 0}, Leaf{0x8000001F, 0x6F677948, 0x656E6975, 0x6E65476E}},
+      {{0x80000001, 0}, Leaf{0x00900F11, 0x60000000, 0x35C233FF, 0x2FD3FBFF}},
+      {{0x80000002, 0}, Leaf{0x6F677948, 0x3843206E, 0x32332036, 0x20203035}},
+      {{0x80000003, 0}, Leaf{0x6F632D38, 0x50206572, 0x65636F72, 0x726F7373}},
+      {{0x80000004, 0}, Leaf{0x20202020, 0x20202020, 0x20202020, 0x00202020}},
+  });
+  const auto info = GetX86Info();
+
+  EXPECT_EQ(info.model, 0x01);
+  EXPECT_EQ(info.family, 0x18);
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_HYGON_GENUINE);
+  EXPECT_STREQ(info.brand_string,
+               "Hygon C86 3250  8-core Processor               ");
+  EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN);
+}
+
+// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD08A0F00_K17_Mendocino_01_CPUID.txt
+TEST_F(CpuidX86Test, AMD_ZEN2_MENDOCINO) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x00000010, 0x68747541, 0x444D4163, 0x69746E65}},
+      {{0x00000001, 0}, Leaf{0x008A0F00, 0x00080800, 0x7EF8320B, 0x178BFBFF}},
+  });
+  const auto info = GetX86Info();
+
+  EXPECT_EQ(info.model, 0xA0);
+  EXPECT_EQ(info.family, 0x17);
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
+  EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN2);
+}
+
+// http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00906A4_AlderLakeP_00_CPUID.txt
+TEST_F(CpuidX86Test, INTEL_ALDER_LAKE_AVX_VNNI) {
+  cpu().SetOsBackupsExtendedRegisters(true);
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x00000020, 0x756E6547, 0x6C65746E, 0x49656E69}},
+      {{0x00000001, 0}, Leaf{0x000906A4, 0x00400800, 0x7FFAFBBF, 0xBFEBFBFF}},
+      {{0x00000007, 0}, Leaf{0x00000001, 0x239CA7EB, 0x984007AC, 0xFC18C410}},
+      {{0x00000007, 1}, Leaf{0x00400810, 0x00000000, 0x00000000, 0x00000000}},
+  });
+  const auto info = GetX86Info();
+
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
+  EXPECT_EQ(info.family, 0x06);
+  EXPECT_EQ(info.model, 0x9A);
+  EXPECT_TRUE(info.features.avx_vnni);
+  EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_ADL);
+}
+
+// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0090672_AlderLake_BC_AVX512_CPUID01.txt
+TEST_F(CpuidX86Test, INTEL_ALDER_LAKE_AVX512) {
+  cpu().SetOsBackupsExtendedRegisters(true);
+#if defined(CPU_FEATURES_OS_MACOS)
+  cpu().SetDarwinSysCtlByName("hw.optional.avx512f");
+#endif
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x00000020, 0x756E6547, 0x6C65746E, 0x49656E69}},
+      {{0x00000001, 0}, Leaf{0x000906A4, 0x00400800, 0x7FFAFBBF, 0xBFEBFBFF}},
+      {{0x00000007, 0}, Leaf{0x00000001, 0xF3BFA7EB, 0x98C07FEE, 0xFC9CC510}},
+      {{0x00000007, 1}, Leaf{0x00401C30, 0x00000000, 0x00000000, 0x00000000}},
+  });
+
+  const auto info = GetX86Info();
+
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
+  EXPECT_EQ(info.family, 0x06);
+  EXPECT_EQ(info.model, 0x9A);
+  EXPECT_TRUE(info.features.avx512f);
+  EXPECT_TRUE(info.features.avx512bw);
+  EXPECT_TRUE(info.features.avx512dq);
+  EXPECT_TRUE(info.features.avx512cd);
+  EXPECT_TRUE(info.features.avx512vl);
+  EXPECT_TRUE(info.features.avx512_vp2intersect);
+  EXPECT_TRUE(info.features.avx512vbmi);
+  EXPECT_TRUE(info.features.avx512vbmi2);
+  EXPECT_TRUE(info.features.avx512bitalg);
+  EXPECT_TRUE(info.features.avx512vpopcntdq);
+  EXPECT_TRUE(info.features.avx512ifma);
+  EXPECT_TRUE(info.features.avx512_bf16);
+  EXPECT_TRUE(info.features.avx512_fp16);
+
+  EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_ADL);
+}
+
+// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel00806C1_TigerLake_CPUID3.txt
+TEST_F(CpuidX86Test, INTEL_TIGER_LAKE_AVX512) {
+  cpu().SetOsBackupsExtendedRegisters(true);
+#if defined(CPU_FEATURES_OS_MACOS)
+  cpu().SetDarwinSysCtlByName("hw.optional.avx512f");
+#endif
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x0000001B, 0x756E6547, 0x6C65746E, 0x49656E69}},
+      {{0x00000001, 0}, Leaf{0x000806C1, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
+      {{0x00000007, 0}, Leaf{0x00000000, 0xF3BFA7EB, 0x18C05FCE, 0xFC100510}},
+  });
+
+  const auto info = GetX86Info();
+
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
+  EXPECT_EQ(info.family, 0x06);
+  EXPECT_EQ(info.model, 0x8C);
+  EXPECT_TRUE(info.features.avx512f);
+  EXPECT_TRUE(info.features.avx512bw);
+  EXPECT_TRUE(info.features.avx512dq);
+  EXPECT_TRUE(info.features.avx512cd);
+  EXPECT_TRUE(info.features.avx512vl);
+  EXPECT_TRUE(info.features.avx512_vp2intersect);
+  EXPECT_TRUE(info.features.avx512vbmi);
+  EXPECT_TRUE(info.features.avx512vbmi2);
+  EXPECT_TRUE(info.features.avx512bitalg);
+  EXPECT_TRUE(info.features.avx512vpopcntdq);
+  EXPECT_TRUE(info.features.avx512ifma);
+
+  EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_TGL);
+}
+
+// http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00706E5_IceLakeY_CPUID.txt
+TEST_F(CpuidX86Test, INTEL_ICE_LAKE_GFNI) {
+    cpu().SetLeaves({
+        {{0x00000000, 0}, Leaf{0x0000001B, 0x756E6547, 0x6C65746E, 0x49656E69}},
+        {{0x00000001, 0}, Leaf{0x000706E5, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
+        {{0x00000007, 0}, Leaf{0x00000000, 0xF2BF27EF, 0x40405F4E, 0xBC000410}},
+    });
+
+    const auto info = GetX86Info();
+
+    EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
+    EXPECT_EQ(info.family, 0x06);
+    EXPECT_EQ(info.model, 0x7E);
+    EXPECT_TRUE(info.features.gfni);
+
+    EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_ICL);
+}
+
+// http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00906C0_JasperLake_CPUID01.txt
+TEST_F(CpuidX86Test, INTEL_TREMONT_JASPER_LAKE_MOVDR) {
+    cpu().SetLeaves({
+        {{0x00000000, 0}, Leaf{0x0000001B, 0x756E6547, 0x6C65746E, 0x49656E69}},
+        {{0x00000001, 0}, Leaf{0x00090661, 0x00800800, 0x4FF8EBBF, 0xBFEBFBFF}},
+        {{0x00000007, 0}, Leaf{0x00000000, 0x2394A2C3, 0x18400124, 0xFC000400}},
+    });
+
+    const auto info = GetX86Info();
+
+    EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
+    EXPECT_EQ(info.family, 0x06);
+    EXPECT_EQ(info.model, 0x96);
+    EXPECT_TRUE(info.features.movdiri);
+    EXPECT_TRUE(info.features.movdir64b);
+
+    EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_ATOM_TMT);
+}
+
+// http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel0090672_AlderLake_LC_BC_CPUID01.txt
+TEST_F(CpuidX86Test, INTEL_ALDER_LAKE_REP) {
+    cpu().SetLeaves({
+        {{0x00000000, 0}, Leaf{0x00000020, 0x756E6547, 0x6C65746E, 0x49656E69}},
+        {{0x00000001, 0}, Leaf{0x00090672, 0x00800800, 0x7FFAFBFF, 0xBFEBFBFF}},
+        {{0x00000007, 0}, Leaf{0x00000001, 0x239CA7EB, 0x98C027AC, 0xFC1CC410}},
+        {{0x00000007, 1}, Leaf{0x00400810, 0x00000000, 0x00000000, 0x00000000}},
+    });
+
+    const auto info = GetX86Info();
+
+    EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
+    EXPECT_EQ(info.family, 0x06);
+    EXPECT_EQ(info.model, 0x97);
+    EXPECT_TRUE(info.features.erms);
+    EXPECT_TRUE(info.features.fs_rep_mov);
+    EXPECT_FALSE(info.features.fz_rep_movsb);
+    EXPECT_TRUE(info.features.fs_rep_stosb);
+    EXPECT_FALSE(info.features.fs_rep_cmpsb_scasb);
+
+    EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_ADL);
+}
+
+// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0100FA0_K10_Thuban_CPUID.txt
+TEST_F(CpuidX86Test, AMD_THUBAN_CACHE_INFO) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x00000006, 0x68747541, 0x444D4163, 0x69746E65}},
+      {{0x80000000, 0}, Leaf{0x8000001B, 0x68747541, 0x444D4163, 0x69746E65}},
+      {{0x80000001, 0}, Leaf{0x00100FA0, 0x10000050, 0x000037FF, 0xEFD3FBFF}},
+      {{0x80000005, 0}, Leaf{0xFF30FF10, 0xFF30FF20, 0x40020140, 0x40020140}},
+      {{0x80000006, 0}, Leaf{0x20800000, 0x42004200, 0x02008140, 0x0030B140}},
+  });
+  const auto info = GetX86CacheInfo();
+
+  EXPECT_EQ(info.size, 4);
+  EXPECT_EQ(info.levels[0].level, 1);
+  EXPECT_EQ(info.levels[0].cache_type, CacheType::CPU_FEATURE_CACHE_DATA);
+  EXPECT_EQ(info.levels[0].cache_size, 64 * KiB);
+  EXPECT_EQ(info.levels[0].ways, 2);
+  EXPECT_EQ(info.levels[0].line_size, 64);
+
+  EXPECT_EQ(info.levels[1].level, 1);
+  EXPECT_EQ(info.levels[1].cache_type,
+            CacheType::CPU_FEATURE_CACHE_INSTRUCTION);
+  EXPECT_EQ(info.levels[1].cache_size, 64 * KiB);
+  EXPECT_EQ(info.levels[1].ways, 2);
+  EXPECT_EQ(info.levels[1].line_size, 64);
+
+  EXPECT_EQ(info.levels[2].level, 2);
+  EXPECT_EQ(info.levels[2].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED);
+  EXPECT_EQ(info.levels[2].cache_size, 512 * KiB);
+  EXPECT_EQ(info.levels[2].ways, 16);
+  EXPECT_EQ(info.levels[2].line_size, 64);
+
+  EXPECT_EQ(info.levels[3].level, 3);
+  EXPECT_EQ(info.levels[3].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED);
+  EXPECT_EQ(info.levels[3].cache_size, 6 * MiB);
+  EXPECT_EQ(info.levels[3].ways, 48);
+  EXPECT_EQ(info.levels[3].line_size, 64);
+}
+
+// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0020FB1_K8_Manchester_CPUID.txt
+TEST_F(CpuidX86Test, AMD_MANCHESTER_CACHE_INFO) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x00000001, 0x68747541, 0x444D4163, 0x69746E65}},
+      {{0x80000000, 0}, Leaf{0x80000018, 0x68747541, 0x444D4163, 0x69746E65}},
+      {{0x80000001, 0}, Leaf{0x00020FB1, 0x00000150, 0x00000003, 0xE3D3FBFF}},
+      {{0x80000005, 0}, Leaf{0xFF08FF08, 0xFF20FF20, 0x40020140, 0x40020140}},
+      {{0x80000006, 0}, Leaf{0x00000000, 0x42004200, 0x02008140, 0x00000000}},
+  });
+  const auto info = GetX86CacheInfo();
+
+  EXPECT_EQ(info.size, 3);
+  EXPECT_EQ(info.levels[0].level, 1);
+  EXPECT_EQ(info.levels[0].cache_type, CacheType::CPU_FEATURE_CACHE_DATA);
+  EXPECT_EQ(info.levels[0].cache_size, 64 * KiB);
+  EXPECT_EQ(info.levels[0].ways, 2);
+  EXPECT_EQ(info.levels[0].line_size, 64);
+
+  EXPECT_EQ(info.levels[1].level, 1);
+  EXPECT_EQ(info.levels[1].cache_type,
+            CacheType::CPU_FEATURE_CACHE_INSTRUCTION);
+  EXPECT_EQ(info.levels[1].cache_size, 64 * KiB);
+  EXPECT_EQ(info.levels[1].ways, 2);
+  EXPECT_EQ(info.levels[1].line_size, 64);
+
+  EXPECT_EQ(info.levels[2].level, 2);
+  EXPECT_EQ(info.levels[2].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED);
+  EXPECT_EQ(info.levels[2].cache_size, 512 * KiB);
+  EXPECT_EQ(info.levels[2].ways, 16);
+  EXPECT_EQ(info.levels[2].line_size, 64);
+}
+
+// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0100F22_K10_Agena_CPUID.txt
+TEST_F(CpuidX86Test, AMD_AGENA_CACHE_INFO) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x00000005, 0x68747541, 0x444D4163, 0x69746E65}},
+      {{0x80000000, 0}, Leaf{0x8000001A, 0x68747541, 0x444D4163, 0x69746E65}},
+      {{0x80000001, 0}, Leaf{0x00100F22, 0x10000000, 0x000007FF, 0xEFD3FBFF}},
+      {{0x80000005, 0}, Leaf{0xFF30FF10, 0xFF30FF20, 0x40020140, 0x40020140}},
+      {{0x80000006, 0}, Leaf{0x20800000, 0x42004200, 0x02008140, 0x0010A140}},
+  });
+  const auto info = GetX86CacheInfo();
+
+  EXPECT_EQ(info.size, 4);
+  EXPECT_EQ(info.levels[0].level, 1);
+  EXPECT_EQ(info.levels[0].cache_type, CacheType::CPU_FEATURE_CACHE_DATA);
+  EXPECT_EQ(info.levels[0].cache_size, 64 * KiB);
+  EXPECT_EQ(info.levels[0].ways, 2);
+  EXPECT_EQ(info.levels[0].line_size, 64);
+
+  EXPECT_EQ(info.levels[1].level, 1);
+  EXPECT_EQ(info.levels[1].cache_type,
+            CacheType::CPU_FEATURE_CACHE_INSTRUCTION);
+  EXPECT_EQ(info.levels[1].cache_size, 64 * KiB);
+  EXPECT_EQ(info.levels[1].ways, 2);
+  EXPECT_EQ(info.levels[1].line_size, 64);
+
+  EXPECT_EQ(info.levels[2].level, 2);
+  EXPECT_EQ(info.levels[2].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED);
+  EXPECT_EQ(info.levels[2].cache_size, 512 * KiB);
+  EXPECT_EQ(info.levels[2].ways, 16);
+  EXPECT_EQ(info.levels[2].line_size, 64);
+
+  EXPECT_EQ(info.levels[3].level, 3);
+  EXPECT_EQ(info.levels[3].cache_type, CacheType::CPU_FEATURE_CACHE_UNIFIED);
+  EXPECT_EQ(info.levels[3].cache_size, 2 * MiB);
+  EXPECT_EQ(info.levels[3].ways, 32);
+  EXPECT_EQ(info.levels[3].line_size, 64);
 }
 
 // https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel00106A1_Nehalem_CPUID.txt
@@ -792,6 +1201,9 @@
   cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE);
   cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE);
   cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE);
+  cpu().SetWindowsIsProcessorFeaturePresent(PF_SSSE3_INSTRUCTIONS_AVAILABLE);
+  cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE4_1_INSTRUCTIONS_AVAILABLE);
+  cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE4_2_INSTRUCTIONS_AVAILABLE);
 #elif defined(CPU_FEATURES_OS_MACOS)
   cpu().SetDarwinSysCtlByName("hw.optional.sse");
   cpu().SetDarwinSysCtlByName("hw.optional.sse2");
@@ -844,7 +1256,7 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "GenuineIntel");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
   EXPECT_EQ(info.family, 0x06);
   EXPECT_EQ(info.model, 0x1A);
   EXPECT_EQ(info.stepping, 0x02);
@@ -852,20 +1264,12 @@
                "Genuine Intel(R) CPU           @ 0000 @ 1.87GHz");
   EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_NHM);
 
-  char brand_string[49];
-  FillX86BrandString(brand_string);
-  EXPECT_STREQ(brand_string, "Genuine Intel(R) CPU           @ 0000 @ 1.87GHz");
-
   EXPECT_TRUE(info.features.sse);
   EXPECT_TRUE(info.features.sse2);
   EXPECT_TRUE(info.features.sse3);
-#if !defined(CPU_FEATURES_OS_WINDOWS)
-  // Currently disabled on Windows as IsProcessorFeaturePresent do not support
-  // feature detection > sse3.
   EXPECT_TRUE(info.features.ssse3);
   EXPECT_TRUE(info.features.sse4_1);
   EXPECT_TRUE(info.features.sse4_2);
-#endif  // !defined(CPU_FEATURES_OS_WINDOWS)
 }
 
 // https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0030673_Silvermont3_CPUID.txt
@@ -876,6 +1280,9 @@
   cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE);
   cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE);
   cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE);
+  cpu().SetWindowsIsProcessorFeaturePresent(PF_SSSE3_INSTRUCTIONS_AVAILABLE);
+  cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE4_1_INSTRUCTIONS_AVAILABLE);
+  cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE4_2_INSTRUCTIONS_AVAILABLE);
 #elif defined(CPU_FEATURES_OS_MACOS)
   cpu().SetDarwinSysCtlByName("hw.optional.sse");
   cpu().SetDarwinSysCtlByName("hw.optional.sse2");
@@ -927,7 +1334,7 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "GenuineIntel");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
   EXPECT_EQ(info.family, 0x06);
   EXPECT_EQ(info.model, 0x37);
   EXPECT_EQ(info.stepping, 0x03);
@@ -936,20 +1343,12 @@
   EXPECT_EQ(GetX86Microarchitecture(&info),
             X86Microarchitecture::INTEL_ATOM_SMT);
 
-  char brand_string[49];
-  FillX86BrandString(brand_string);
-  EXPECT_STREQ(brand_string, "      Intel(R) Celeron(R) CPU  J1900  @ 1.99GHz");
-
   EXPECT_TRUE(info.features.sse);
   EXPECT_TRUE(info.features.sse2);
   EXPECT_TRUE(info.features.sse3);
-#if !defined(CPU_FEATURES_OS_WINDOWS)
-  // Currently disabled on Windows as IsProcessorFeaturePresent do not support
-  // feature detection > sse3.
   EXPECT_TRUE(info.features.ssse3);
   EXPECT_TRUE(info.features.sse4_1);
   EXPECT_TRUE(info.features.sse4_2);
-#endif  // !defined(CPU_FEATURES_OS_WINDOWS)
 }
 
 // https://www.felixcloutier.com/x86/cpuid#example-3-1--example-of-cache-and-tlb-interpretation
@@ -964,7 +1363,7 @@
   EXPECT_EQ(info.size, 5);
 
   EXPECT_EQ(info.levels[0].level, UNDEF);
-  EXPECT_EQ(info.levels[0].cache_type, CPU_FEATURE_CACHE_TLB);
+  EXPECT_EQ(info.levels[0].cache_type, CacheType::CPU_FEATURE_CACHE_TLB);
   EXPECT_EQ(info.levels[0].cache_size, 4 * KiB);
   EXPECT_EQ(info.levels[0].ways, UNDEF);
   EXPECT_EQ(info.levels[0].line_size, UNDEF);
@@ -972,7 +1371,7 @@
   EXPECT_EQ(info.levels[0].partitioning, 0);
 
   EXPECT_EQ(info.levels[1].level, UNDEF);
-  EXPECT_EQ(info.levels[1].cache_type, CPU_FEATURE_CACHE_TLB);
+  EXPECT_EQ(info.levels[1].cache_type, CacheType::CPU_FEATURE_CACHE_TLB);
   EXPECT_EQ(info.levels[1].cache_size, 4 * KiB);
   EXPECT_EQ(info.levels[1].ways, UNDEF);
   EXPECT_EQ(info.levels[1].line_size, UNDEF);
@@ -980,7 +1379,7 @@
   EXPECT_EQ(info.levels[1].partitioning, 0);
 
   EXPECT_EQ(info.levels[2].level, 1);
-  EXPECT_EQ(info.levels[2].cache_type, CPU_FEATURE_CACHE_DATA);
+  EXPECT_EQ(info.levels[2].cache_type, CacheType::CPU_FEATURE_CACHE_DATA);
   EXPECT_EQ(info.levels[2].cache_size, 8 * KiB);
   EXPECT_EQ(info.levels[2].ways, 4);
   EXPECT_EQ(info.levels[2].line_size, 64);
@@ -988,7 +1387,8 @@
   EXPECT_EQ(info.levels[2].partitioning, 0);
 
   EXPECT_EQ(info.levels[3].level, 1);
-  EXPECT_EQ(info.levels[3].cache_type, CPU_FEATURE_CACHE_INSTRUCTION);
+  EXPECT_EQ(info.levels[3].cache_type,
+            CacheType::CPU_FEATURE_CACHE_INSTRUCTION);
   EXPECT_EQ(info.levels[3].cache_size, 12 * KiB);
   EXPECT_EQ(info.levels[3].ways, 8);
   EXPECT_EQ(info.levels[3].line_size, UNDEF);
@@ -996,7 +1396,7 @@
   EXPECT_EQ(info.levels[3].partitioning, 0);
 
   EXPECT_EQ(info.levels[4].level, 2);
-  EXPECT_EQ(info.levels[4].cache_type, CPU_FEATURE_CACHE_DATA);
+  EXPECT_EQ(info.levels[4].cache_type, CacheType::CPU_FEATURE_CACHE_DATA);
   EXPECT_EQ(info.levels[4].cache_size, 256 * KiB);
   EXPECT_EQ(info.levels[4].ways, 8);
   EXPECT_EQ(info.levels[4].line_size, 64);
@@ -1035,28 +1435,20 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "GenuineIntel");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
   EXPECT_EQ(info.family, 0x06);
   EXPECT_EQ(info.model, 0x07);
   EXPECT_EQ(info.stepping, 0x03);
   EXPECT_STREQ(info.brand_string, "");
   EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::X86_UNKNOWN);
 
-  char brand_string[49];
-  FillX86BrandString(brand_string);
-  EXPECT_STREQ(brand_string, "");
-
   EXPECT_TRUE(info.features.mmx);
   EXPECT_TRUE(info.features.sse);
   EXPECT_FALSE(info.features.sse2);
   EXPECT_FALSE(info.features.sse3);
-#if !defined(CPU_FEATURES_OS_WINDOWS)
-  // Currently disabled on Windows as IsProcessorFeaturePresent do not support
-  // feature detection > sse3.
   EXPECT_FALSE(info.features.ssse3);
   EXPECT_FALSE(info.features.sse4_1);
   EXPECT_FALSE(info.features.sse4_2);
-#endif  // !defined(CPU_FEATURES_OS_WINDOWS)
 }
 
 // https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0000480_486_CPUID.txt
@@ -1067,7 +1459,7 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "GenuineIntel");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
   EXPECT_EQ(info.family, 0x04);
   EXPECT_EQ(info.model, 0x08);
   EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_80486);
@@ -1081,7 +1473,7 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "GenuineIntel");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
   EXPECT_EQ(info.family, 0x05);
   EXPECT_EQ(info.model, 0x02);
   EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_P5);
@@ -1095,13 +1487,42 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "GenuineIntel");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
   EXPECT_EQ(info.family, 0x05);
   EXPECT_EQ(info.model, 0x09);
   EXPECT_EQ(GetX86Microarchitecture(&info),
             X86Microarchitecture::INTEL_LAKEMONT);
 }
 
+// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel00006E8_PM_Yonah_CPUID.txt
+TEST_F(CpuidX86Test, INTEL_CORE_YONAH) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x0000000A, 0x756E6547, 0x6C65746E, 0x49656E69}},
+      {{0x00000001, 0}, Leaf{0x000006E8, 0x00010800, 0x0000C109, 0xAFE9FBFF}},
+  });
+  const auto info = GetX86Info();
+
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
+  EXPECT_EQ(info.family, 0x06);
+  EXPECT_EQ(info.model, 0x0E);
+  EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_CORE);
+}
+
+// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel00706A8_GoldmontPlus_CPUID.txt
+TEST_F(CpuidX86Test, INTEL_GOLDMONT_PLUS) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x00000018, 0x756E6547, 0x6c65746E, 0x49656E69}},
+      {{0x00000001, 0}, Leaf{0x000706A8, 0x00400800, 0x4FF8EBBF, 0xBFEBFBFF}},
+  });
+  const auto info = GetX86Info();
+
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
+  EXPECT_EQ(info.family, 0x06);
+  EXPECT_EQ(info.model, 0x7A);
+  EXPECT_EQ(GetX86Microarchitecture(&info),
+            X86Microarchitecture::INTEL_ATOM_GMT_PLUS);
+}
+
 // https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0050670_KnightsLanding_CPUID.txt
 TEST_F(CpuidX86Test, INTEL_KNIGHTS_LANDING) {
   cpu().SetLeaves({
@@ -1110,17 +1531,177 @@
   });
   const auto info = GetX86Info();
 
-  EXPECT_STREQ(info.vendor, "GenuineIntel");
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
   EXPECT_EQ(info.family, 0x06);
   EXPECT_EQ(info.model, 0x57);
   EXPECT_EQ(GetX86Microarchitecture(&info),
             X86Microarchitecture::INTEL_KNIGHTS_L);
 }
 
+// http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00806EC_CometLake_CPUID2.txt
+TEST_F(CpuidX86Test, INTEL_CML_U) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
+      {{0x00000001, 0}, Leaf{0x000806EC, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
+  });
+  const auto info = GetX86Info();
+
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
+  EXPECT_EQ(info.family, 0x06);
+  EXPECT_EQ(info.model, 0x8E);
+  EXPECT_EQ(info.stepping, 0x0C);
+  EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_CML);
+}
+
+// http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00A0652_CometLake_CPUID1.txt
+TEST_F(CpuidX86Test, INTEL_CML_H) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
+      {{0x00000001, 0}, Leaf{0x000A0652, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
+  });
+  const auto info = GetX86Info();
+
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
+  EXPECT_EQ(info.family, 0x06);
+  EXPECT_EQ(info.model, 0xA5);
+  EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_CML);
+}
+
+// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel00A0660_CometLake_CPUID1.txt
+TEST_F(CpuidX86Test, INTEL_CML_U2) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
+      {{0x00000001, 0}, Leaf{0x000A0660, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
+  });
+  const auto info = GetX86Info();
+
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
+  EXPECT_EQ(info.family, 0x06);
+  EXPECT_EQ(info.model, 0xA6);
+  EXPECT_EQ(info.stepping, 0x00);
+  EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_CML);
+}
+
+// http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00806A1_Lakefield_CPUID.txt
+TEST_F(CpuidX86Test, INTEL_ATOM_TMT_LAKEFIELD) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x0000001B, 0x756E6547, 0x6C65746E, 0x49656E69}},
+      {{0x00000001, 0}, Leaf{0x000806A1, 0x00100800, 0x4FD8EBBF, 0xBFEBFBFF}},
+  });
+  const auto info = GetX86Info();
+
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
+  EXPECT_EQ(info.family, 0x06);
+  EXPECT_EQ(info.model, 0x8A);
+  EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_ATOM_TMT);
+}
+
+// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0090661_ElkhartLake_CPUID01.txt
+TEST_F(CpuidX86Test, INTEL_ATOM_TMT_ELKHART_LAKE) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x0000001B, 0x756E6547, 0x6C65746E, 0x49656E69}},
+      {{0x00000001, 0}, Leaf{0x00090661, 0x00800800, 0x4FF8EBBF, 0xBFEBFBFF}},
+  });
+  const auto info = GetX86Info();
+
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
+  EXPECT_EQ(info.family, 0x06);
+  EXPECT_EQ(info.model, 0x96);
+  EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_ATOM_TMT);
+}
+
+// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel00906C0_JasperLake_01_CPUID.txt
+TEST_F(CpuidX86Test, INTEL_ATOM_TMT_JASPER_LAKE) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x0000001B, 0x756E6547, 0x6C65746E, 0x49656E69}},
+      {{0x00000001, 0}, Leaf{0x000906C0, 0x00800800, 0x4FF8EBBF, 0xBFEBFBFF}},
+  });
+  const auto info = GetX86Info();
+
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
+  EXPECT_EQ(info.family, 0x06);
+  EXPECT_EQ(info.model, 0x9C);
+  EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_ATOM_TMT);
+}
+
+// http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00B0671_RaptorLake_02_CPUID.txt
+TEST_F(CpuidX86Test, INTEL_RAPTOR_LAKE) {
+    cpu().SetLeaves({
+        {{0x00000000, 0}, Leaf{0x00000020, 0x756E6547, 0x6C65746E, 0x49656E69}},
+        {{0x00000001, 0}, Leaf{0x000B0671, 0x00800800, 0x7FFAFBBF, 0xBFEBFBFF}},
+    });
+    const auto info = GetX86Info();
+
+    EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
+    EXPECT_EQ(info.family, 0x06);
+    EXPECT_EQ(info.model, 0xB7);
+    EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_RPL);
+}
+
+// http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00306F2_HaswellEP2_CPUID.txt
+TEST_F(CpuidX86Test, INTEL_HASWELL_LZCNT) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x0000000F, 0x756E6547, 0x6C65746E, 0x49656E69}},
+      {{0x00000001, 0}, Leaf{0x000306F2, 0x00200800, 0x7FFEFBFF, 0xBFEBFBFF}},
+      {{0x00000007, 0}, Leaf{0x00000000, 0x000037AB, 0x00000000, 0x00000000}},
+      {{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
+      {{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000021, 0x2C100000}},
+  });
+  const auto info = GetX86Info();
+
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
+  EXPECT_EQ(info.family, 0x06);
+  EXPECT_EQ(info.model, 0x3F);
+  EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_HSW);
+
+  EXPECT_TRUE(info.features.lzcnt);
+}
+
+// http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00B06A2_RaptorLakeP_03_CPUID.txt
+TEST_F(CpuidX86Test, INTEL_RAPTOR_LAKE_P) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x00000020, 0x756E6547, 0x6C65746E, 0x49656E69}},
+      {{0x00000001, 0}, Leaf{0x000B06A3, 0x00400800, 0x7FFAFBFF, 0xBFEBFBFF}},
+      {{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
+      {{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}},
+  });
+  const auto info = GetX86Info();
+
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
+  EXPECT_EQ(info.family, 0x06);
+  EXPECT_EQ(info.model, 0xBA);
+  EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_RPL);
+}
+
+// http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00B06F2_RaptorLakeS_02_CPUID.txt
+TEST_F(CpuidX86Test, INTEL_RAPTOR_LAKE_S) {
+  cpu().SetLeaves({
+      {{0x00000000, 0}, Leaf{0x00000020, 0x756E6547, 0x6C65746E, 0x49656E69}},
+      {{0x00000001, 0}, Leaf{0x000B06F2, 0x00800800, 0x7FFAFBFF, 0xBFEBFBFF}},
+      {{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
+      {{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}},
+  });
+  const auto info = GetX86Info();
+
+  EXPECT_STREQ(info.vendor, CPU_FEATURES_VENDOR_GENUINE_INTEL);
+  EXPECT_EQ(info.family, 0x06);
+  EXPECT_EQ(info.model, 0xBF);
+  EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_RPL);
+}
+
 // https://github.com/google/cpu_features/issues/200
 // http://users.atw.hu/instlatx64/GenuineIntel/GenuineIntel00206F2_Eagleton_CPUID.txt
 #if defined(CPU_FEATURES_OS_WINDOWS)
 TEST_F(CpuidX86Test, WIN_INTEL_WESTMERE_EX) {
+  // Pre AVX cpus don't have xsave
+  cpu().SetOsBackupsExtendedRegisters(false);
+  cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE);
+  cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE);
+  cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE);
+  cpu().SetWindowsIsProcessorFeaturePresent(PF_SSSE3_INSTRUCTIONS_AVAILABLE);
+  cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE4_1_INSTRUCTIONS_AVAILABLE);
+  cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE4_2_INSTRUCTIONS_AVAILABLE);
+
   cpu().SetLeaves({
       {{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}},
       {{0x00000001, 0}, Leaf{0x000206F2, 0x00400800, 0x02BEE3FF, 0xBFEBFBFF}},
@@ -1131,15 +1712,12 @@
   EXPECT_EQ(info.model, 0x2F);
   EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_WSM);
 
-#if (_WIN32_WINNT < 0x0601)  // before Win7
-  EXPECT_FALSE(info.features.ssse3);
-  EXPECT_FALSE(info.features.sse4_1);
-  EXPECT_FALSE(info.features.sse4_2);
-#else
+  EXPECT_TRUE(info.features.sse);
+  EXPECT_TRUE(info.features.sse2);
+  EXPECT_TRUE(info.features.sse3);
   EXPECT_TRUE(info.features.ssse3);
   EXPECT_TRUE(info.features.sse4_1);
   EXPECT_TRUE(info.features.sse4_2);
-#endif
 }
 #endif  // CPU_FEATURES_OS_WINDOWS