From: A. Maitland Bottoms Date: Fri, 4 Dec 2020 01:43:29 +0000 (+0000) Subject: volk (2.4.0-3) unstable; urgency=medium X-Git-Tag: archive/raspbian/2.4.0-3+rpi1^2~5 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=a5cd86b15217b8fe01bf55ba382e7e9d511c847d;p=volk.git volk (2.4.0-3) unstable; urgency=medium * Fix binary-indep build (Closes: #976300) * Upload to unstable [dgit import unpatched volk 2.4.0-3] --- a5cd86b15217b8fe01bf55ba382e7e9d511c847d diff --cc cpu-features/.clang-format index 0000000,0000000,0000000..06ea346 new file mode 100644 --- /dev/null +++ b/cpu-features/.clang-format @@@@ -1,0 -1,0 -1,0 +1,4 @@@@ +++--- +++Language: Cpp +++BasedOnStyle: Google +++... diff --cc cpu-features/.github/workflows/Dockerfile index 0000000,0000000,0000000..41dfc93 new file mode 100644 --- /dev/null +++ b/cpu-features/.github/workflows/Dockerfile @@@@ -1,0 -1,0 -1,0 +1,5 @@@@ +++# Create a virtual environment with all tools installed +++# ref: https://hub.docker.com/_/alpine +++FROM alpine:edge +++# Install system build dependencies +++RUN apk add --no-cache git clang diff --cc cpu-features/.github/workflows/clang_format.yml index 0000000,0000000,0000000..17d1567 new file mode 100644 --- /dev/null +++ b/cpu-features/.github/workflows/clang_format.yml @@@@ -1,0 -1,0 -1,0 +1,24 @@@@ +++name: clang-format Check +++ +++on: [push, pull_request] +++ +++jobs: +++ # Building using the github runner environement directly. +++ clang-format: +++ runs-on: ubuntu-latest +++ steps: +++ - uses: actions/checkout@v2 +++ - name: Fetch origin/master +++ run: git fetch origin master +++ - name: List of changed file(s) +++ run: git diff --name-only FETCH_HEAD +++ +++ - name: Build clang-format docker +++ run: cd .github/workflows && docker build --tag=linter . +++ - name: Check clang-format +++ run: docker run --rm --init -v $(pwd):/repo linter:latest clang-format --version +++ - name: clang-format help +++ run: docker run --rm --init -v $(pwd):/repo linter:latest clang-format --help +++ +++ - name: Check current commit +++ run: docker run --rm --init -v $(pwd):/repo -w /repo linter:latest sh -c "git diff --diff-filter=d --name-only FETCH_HEAD | grep '\.c$\|\.h$\|\.cc$' | xargs clang-format --style=file --dry-run --Werror " diff --cc cpu-features/.gitignore index 0000000,0000000,0000000..6285424 new file mode 100644 --- /dev/null +++ b/cpu-features/.gitignore @@@@ -1,0 -1,0 -1,0 +1,4 @@@@ +++cmake_build/ +++build/ +++ +++*.swp diff --cc cpu-features/.travis.yml index 0000000,0000000,0000000..b5845be new file mode 100644 --- /dev/null +++ b/cpu-features/.travis.yml @@@@ -1,0 -1,0 -1,0 +1,121 @@@@ +++language: c +++ +++sudo: false +++ +++cache: +++ timeout: 1000 +++ directories: +++ - $HOME/cpu_features_archives +++ +++addons: +++ apt_packages: +++ - ninja-build +++ +++env: +++ global: +++ TOOLCHAIN=NATIVE +++ CMAKE_GENERATOR=Ninja +++ +++matrix: +++ include: +++ - os: linux +++ compiler: gcc +++ env: +++ TARGET=x86_64-linux-gnu +++ - os: linux +++ compiler: clang +++ env: +++ TARGET=x86_64-linux-gnu +++ - os: osx +++ compiler: gcc +++ env: +++ TARGET=x86_64-osx +++ CMAKE_GENERATOR="Unix Makefiles" +++ - os: osx +++ compiler: clang +++ env: +++ TARGET=x86_64-osx +++ CMAKE_GENERATOR="Unix Makefiles" +++ - os: windows +++ env: +++ TARGET=x86_64-windows +++ CMAKE_GENERATOR="Visual Studio 15 2017 Win64" +++ +++ # see: https://docs.travis-ci.com/user/multi-cpu-architectures/ +++ - os: linux +++ arch: ppc64le +++ compiler: gcc +++ env: +++ TARGET=ppc64le-linux-gnu +++ - os: linux +++ arch: ppc64le +++ compiler: clang +++ env: +++ TARGET=ppc64le-linux-gnu +++ +++ # Toolchains for little-endian, 64-bit ARMv8 for GNU/Linux systems +++ - os: linux +++ env: +++ TOOLCHAIN=LINARO +++ TARGET=aarch64-linux-gnu +++ QEMU_ARCH=aarch64 +++ # Toolchains for little-endian, hard-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems +++ - os: linux +++ env: +++ TOOLCHAIN=LINARO +++ TARGET=arm-linux-gnueabihf +++ QEMU_ARCH=arm +++ # Toolchains for little-endian, 32-bit ARMv8 for GNU/Linux systems +++ - os: linux +++ env: +++ TOOLCHAIN=LINARO +++ TARGET=armv8l-linux-gnueabihf +++ QEMU_ARCH=arm +++ # Toolchains for little-endian, soft-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems +++ - os: linux +++ env: +++ TOOLCHAIN=LINARO +++ TARGET=arm-linux-gnueabi +++ QEMU_ARCH=arm +++ # Toolchains for big-endian, 64-bit ARMv8 for GNU/Linux systems +++ - os: linux +++ env: +++ TOOLCHAIN=LINARO +++ TARGET=aarch64_be-linux-gnu +++ QEMU_ARCH=DISABLED +++ # Toolchains for big-endian, hard-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems +++ - os: linux +++ env: +++ TOOLCHAIN=LINARO +++ TARGET=armeb-linux-gnueabihf +++ QEMU_ARCH=DISABLED +++ # Toolchains for big-endian, soft-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems +++ - os: linux +++ env: +++ TOOLCHAIN=LINARO +++ TARGET=armeb-linux-gnueabi +++ QEMU_ARCH=DISABLED +++ - os: linux +++ env: +++ TOOLCHAIN=CODESCAPE +++ TARGET=mips32 +++ QEMU_ARCH=mips +++ - os: linux +++ env: +++ TOOLCHAIN=CODESCAPE +++ TARGET=mips32el +++ QEMU_ARCH=mipsel +++ - os: linux +++ env: +++ TOOLCHAIN=CODESCAPE +++ TARGET=mips64 +++ QEMU_ARCH=mips64 +++ - os: linux +++ env: +++ TOOLCHAIN=CODESCAPE +++ TARGET=mips64el +++ QEMU_ARCH=mips64el +++ +++script: +++ - cmake --version +++ - bash -e -x ./scripts/run_integration.sh diff --cc cpu-features/CMakeLists.txt index 0000000,0000000,0000000..f9daeac new file mode 100644 --- /dev/null +++ b/cpu-features/CMakeLists.txt @@@@ -1,0 -1,0 -1,0 +1,259 @@@@ +++cmake_minimum_required(VERSION 3.0) +++ +++# option() honors normal variables. +++# see: https://cmake.org/cmake/help/git-stage/policy/CMP0077.html +++if(POLICY CMP0077) +++ cmake_policy(SET CMP0077 NEW) +++endif() +++ +++project(CpuFeatures VERSION 0.6.0 LANGUAGES C) +++ +++set(CMAKE_C_STANDARD 99) +++ +++# Default Build Type to be Release +++if(NOT CMAKE_BUILD_TYPE) +++ set(CMAKE_BUILD_TYPE "Release" CACHE STRING +++ "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." +++ FORCE) +++endif(NOT CMAKE_BUILD_TYPE) +++ +++# BUILD_TESTING is a standard CMake variable, but we declare it here to make it +++# prominent in the GUI. +++option(BUILD_TESTING "Enable test (depends on googletest)." OFF) +++# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to make +++# it prominent in the GUI. +++# cpu_features uses bit-fields which are - to some extends - implementation-defined (see https://en.cppreference.com/w/c/language/bit_field). +++# As a consequence it is discouraged to use cpu_features as a shared library because different compilers may interpret the code in different ways. +++# Prefer static linking from source whenever possible. +++option(BUILD_SHARED_LIBS "Build library as shared." OFF) +++# PIC +++option(BUILD_PIC "Build with Position Independant Code." OFF) # Default is off at least for GCC +++ +++# Force PIC on unix when building shared libs +++# see: https://en.wikipedia.org/wiki/Position-independent_code +++if(BUILD_SHARED_LIBS AND UNIX) +++ set(BUILD_PIC ON) +++endif() +++ +++include(CheckIncludeFile) +++include(CheckSymbolExists) +++include(GNUInstallDirs) +++ +++macro(setup_include_and_definitions TARGET_NAME) +++ target_include_directories(${TARGET_NAME} +++ PUBLIC $ +++ PRIVATE $ +++ ) +++ target_compile_definitions(${TARGET_NAME} +++ PUBLIC STACK_LINE_READER_BUFFER_SIZE=1024 +++ ) +++endmacro() +++ +++set(PROCESSOR_IS_MIPS FALSE) +++set(PROCESSOR_IS_ARM FALSE) +++set(PROCESSOR_IS_AARCH64 FALSE) +++set(PROCESSOR_IS_X86 FALSE) +++set(PROCESSOR_IS_POWER FALSE) +++ +++if(CMAKE_SYSTEM_PROCESSOR MATCHES "^mips") +++ set(PROCESSOR_IS_MIPS TRUE) +++elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm") +++ set(PROCESSOR_IS_ARM TRUE) +++elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^aarch64") +++ set(PROCESSOR_IS_AARCH64 TRUE) +++elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64)|(AMD64|amd64)|(^i.86$)") +++ set(PROCESSOR_IS_X86 TRUE) +++elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)") +++ set(PROCESSOR_IS_POWER TRUE) +++endif() +++ +++macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME) +++ list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpu_features_macros.h) +++ list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpu_features_cache_info.h) +++ if(PROCESSOR_IS_MIPS) +++ list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_mips.h) +++ list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_mips.c) +++ elseif(PROCESSOR_IS_ARM) +++ list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_arm.h) +++ list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_arm.c) +++ elseif(PROCESSOR_IS_AARCH64) +++ list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_aarch64.h) +++ list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_aarch64.c) +++ elseif(PROCESSOR_IS_X86) +++ list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_x86.h) +++ list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/internal/cpuid_x86.h) +++ list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_x86.c) +++ elseif(PROCESSOR_IS_POWER) +++ list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_ppc.h) +++ list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_ppc.c) +++ else() +++ message(FATAL_ERROR "Unsupported architectures ${CMAKE_SYSTEM_PROCESSOR}") +++ endif() +++endmacro() +++ +++# +++# library : utils +++# +++ +++add_library(utils OBJECT +++ ${PROJECT_SOURCE_DIR}/include/internal/bit_utils.h +++ ${PROJECT_SOURCE_DIR}/include/internal/filesystem.h +++ ${PROJECT_SOURCE_DIR}/include/internal/stack_line_reader.h +++ ${PROJECT_SOURCE_DIR}/include/internal/string_view.h +++ ${PROJECT_SOURCE_DIR}/src/filesystem.c +++ ${PROJECT_SOURCE_DIR}/src/stack_line_reader.c +++ ${PROJECT_SOURCE_DIR}/src/string_view.c +++) +++set_property(TARGET utils PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC}) +++setup_include_and_definitions(utils) +++ +++# +++# library : unix_based_hardware_detection +++# +++ +++if(UNIX) +++ add_library(unix_based_hardware_detection OBJECT +++ ${PROJECT_SOURCE_DIR}/include/internal/hwcaps.h +++ ${PROJECT_SOURCE_DIR}/src/hwcaps.c +++ ) +++ setup_include_and_definitions(unix_based_hardware_detection) +++ check_include_file(dlfcn.h HAVE_DLFCN_H) +++ if(HAVE_DLFCN_H) +++ target_compile_definitions(unix_based_hardware_detection PRIVATE HAVE_DLFCN_H) +++ endif() +++ check_symbol_exists(getauxval "sys/auxv.h" HAVE_STRONG_GETAUXVAL) +++ if(HAVE_STRONG_GETAUXVAL) +++ target_compile_definitions(unix_based_hardware_detection PRIVATE HAVE_STRONG_GETAUXVAL) +++ endif() +++ set_property(TARGET unix_based_hardware_detection PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC}) +++endif() +++ +++# +++# library : cpu_features +++# +++set (CPU_FEATURES_HDRS) +++set (CPU_FEATURES_SRCS) +++add_cpu_features_headers_and_sources(CPU_FEATURES_HDRS CPU_FEATURES_SRCS) +++list(APPEND CPU_FEATURES_SRCS $) +++if(NOT PROCESSOR_IS_X86 AND UNIX) +++ list(APPEND CPU_FEATURES_SRCS $) +++endif() +++add_library(cpu_features ${CPU_FEATURES_HDRS} ${CPU_FEATURES_SRCS}) +++set_target_properties(cpu_features PROPERTIES PUBLIC_HEADER "${CPU_FEATURES_HDRS}") +++setup_include_and_definitions(cpu_features) +++target_link_libraries(cpu_features PUBLIC ${CMAKE_DL_LIBS}) +++set_property(TARGET cpu_features PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC}) +++target_include_directories(cpu_features +++ PUBLIC $ +++) +++if(PROCESSOR_IS_X86) +++ if(APPLE) +++ target_compile_definitions(cpu_features PRIVATE HAVE_SYSCTLBYNAME) +++ endif() +++endif() +++add_library(CpuFeature::cpu_features ALIAS cpu_features) +++ +++# +++# program : list_cpu_features +++# +++ +++add_executable(list_cpu_features ${PROJECT_SOURCE_DIR}/src/utils/list_cpu_features.c) +++target_link_libraries(list_cpu_features PRIVATE cpu_features) +++add_executable(CpuFeature::list_cpu_features ALIAS list_cpu_features) +++ +++# +++# ndk_compat +++# +++ +++if(ANDROID) +++add_subdirectory(ndk_compat) +++endif() +++ +++# +++# tests +++# +++ +++include(CTest) +++if(BUILD_TESTING) +++ # Automatically incorporate googletest into the CMake Project if target not +++ # found. +++ enable_language(CXX) +++ +++ set(CMAKE_CXX_STANDARD 11) +++ set(CMAKE_CXX_STANDARD_REQUIRED ON) +++ set(CMAKE_CXX_EXTENSIONS OFF) # prefer use of -std11 instead of -gnustd11 +++ +++ if(NOT TARGET gtest OR NOT TARGET gmock_main) +++ # Download and unpack googletest at configure time. +++ configure_file( +++ cmake/googletest.CMakeLists.txt.in +++ googletest-download/CMakeLists.txt +++ ) +++ +++ execute_process( +++ COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . +++ RESULT_VARIABLE result +++ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download) +++ +++ if(result) +++ message(FATAL_ERROR "CMake step for googletest failed: ${result}") +++ endif() +++ +++ execute_process( +++ COMMAND ${CMAKE_COMMAND} --build . +++ RESULT_VARIABLE result +++ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download) +++ +++ if(result) +++ message(FATAL_ERROR "Build step for googletest failed: ${result}") +++ endif() +++ +++ # Prevent overriding the parent project's compiler/linker settings on +++ # Windows. +++ set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +++ +++ # Add googletest directly to our build. This defines the gtest and +++ # gtest_main targets. +++ add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src +++ ${CMAKE_BINARY_DIR}/googletest-build +++ EXCLUDE_FROM_ALL) +++ endif() +++ +++ add_subdirectory(test) +++endif() +++ +++# +++# Install cpu_features and list_cpu_features +++# +++ +++include(GNUInstallDirs) +++install(TARGETS cpu_features list_cpu_features +++ EXPORT CpuFeaturesTargets +++ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/cpu_features +++ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +++ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} +++ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +++) +++install(EXPORT CpuFeaturesTargets +++ NAMESPACE CpuFeatures:: +++ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeatures +++ COMPONENT Devel +++) +++include(CMakePackageConfigHelpers) +++configure_package_config_file(cmake/CpuFeaturesConfig.cmake.in +++ "${PROJECT_BINARY_DIR}/CpuFeaturesConfig.cmake" +++ INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeatures" +++ NO_SET_AND_CHECK_MACRO +++ NO_CHECK_REQUIRED_COMPONENTS_MACRO +++) +++write_basic_package_version_file( +++ "${PROJECT_BINARY_DIR}/CpuFeaturesConfigVersion.cmake" +++ COMPATIBILITY SameMajorVersion +++) +++install( +++ FILES +++ "${PROJECT_BINARY_DIR}/CpuFeaturesConfig.cmake" +++ "${PROJECT_BINARY_DIR}/CpuFeaturesConfigVersion.cmake" +++ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeatures" +++ COMPONENT Devel +++) diff --cc cpu-features/CONTRIBUTING.md index 0000000,0000000,0000000..c980350 new file mode 100644 --- /dev/null +++ b/cpu-features/CONTRIBUTING.md @@@@ -1,0 -1,0 -1,0 +1,23 @@@@ +++# How to Contribute +++ +++We'd love to accept your patches and contributions to this project. There are +++just a few small guidelines you need to follow. +++ +++## Contributor License Agreement +++ +++Contributions to this project must be accompanied by a Contributor License +++Agreement. You (or your employer) retain the copyright to your contribution; +++this simply gives us permission to use and redistribute your contributions as +++part of the project. Head over to to see +++your current agreements on file or to sign a new one. +++ +++You generally only need to submit a CLA once, so if you've already submitted one +++(even if it was for a different project), you probably don't need to do it +++again. +++ +++## Code reviews +++ +++All submissions, including submissions by project members, require review. We +++use GitHub pull requests for this purpose. Consult +++[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more +++information on using pull requests. diff --cc cpu-features/LICENSE index 0000000,0000000,0000000..a7043c6 new file mode 100644 --- /dev/null +++ b/cpu-features/LICENSE @@@@ -1,0 -1,0 -1,0 +1,230 @@@@ +++ +++ Apache License +++ Version 2.0, January 2004 +++ http://www.apache.org/licenses/ +++ +++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +++ +++ 1. Definitions. +++ +++ "License" shall mean the terms and conditions for use, reproduction, +++ and distribution as defined by Sections 1 through 9 of this document. +++ +++ "Licensor" shall mean the copyright owner or entity authorized by +++ the copyright owner that is granting the License. +++ +++ "Legal Entity" shall mean the union of the acting entity and all +++ other entities that control, are controlled by, or are under common +++ control with that entity. For the purposes of this definition, +++ "control" means (i) the power, direct or indirect, to cause the +++ direction or management of such entity, whether by contract or +++ otherwise, or (ii) ownership of fifty percent (50%) or more of the +++ outstanding shares, or (iii) beneficial ownership of such entity. +++ +++ "You" (or "Your") shall mean an individual or Legal Entity +++ exercising permissions granted by this License. +++ +++ "Source" form shall mean the preferred form for making modifications, +++ including but not limited to software source code, documentation +++ source, and configuration files. +++ +++ "Object" form shall mean any form resulting from mechanical +++ transformation or translation of a Source form, including but +++ not limited to compiled object code, generated documentation, +++ and conversions to other media types. +++ +++ "Work" shall mean the work of authorship, whether in Source or +++ Object form, made available under the License, as indicated by a +++ copyright notice that is included in or attached to the work +++ (an example is provided in the Appendix below). +++ +++ "Derivative Works" shall mean any work, whether in Source or Object +++ form, that is based on (or derived from) the Work and for which the +++ editorial revisions, annotations, elaborations, or other modifications +++ represent, as a whole, an original work of authorship. For the purposes +++ of this License, Derivative Works shall not include works that remain +++ separable from, or merely link (or bind by name) to the interfaces of, +++ the Work and Derivative Works thereof. +++ +++ "Contribution" shall mean any work of authorship, including +++ the original version of the Work and any modifications or additions +++ to that Work or Derivative Works thereof, that is intentionally +++ submitted to Licensor for inclusion in the Work by the copyright owner +++ or by an individual or Legal Entity authorized to submit on behalf of +++ the copyright owner. For the purposes of this definition, "submitted" +++ means any form of electronic, verbal, or written communication sent +++ to the Licensor or its representatives, including but not limited to +++ communication on electronic mailing lists, source code control systems, +++ and issue tracking systems that are managed by, or on behalf of, the +++ Licensor for the purpose of discussing and improving the Work, but +++ excluding communication that is conspicuously marked or otherwise +++ designated in writing by the copyright owner as "Not a Contribution." +++ +++ "Contributor" shall mean Licensor and any individual or Legal Entity +++ on behalf of whom a Contribution has been received by Licensor and +++ subsequently incorporated within the Work. +++ +++ 2. Grant of Copyright License. Subject to the terms and conditions of +++ this License, each Contributor hereby grants to You a perpetual, +++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable +++ copyright license to reproduce, prepare Derivative Works of, +++ publicly display, publicly perform, sublicense, and distribute the +++ Work and such Derivative Works in Source or Object form. +++ +++ 3. Grant of Patent License. Subject to the terms and conditions of +++ this License, each Contributor hereby grants to You a perpetual, +++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable +++ (except as stated in this section) patent license to make, have made, +++ use, offer to sell, sell, import, and otherwise transfer the Work, +++ where such license applies only to those patent claims licensable +++ by such Contributor that are necessarily infringed by their +++ Contribution(s) alone or by combination of their Contribution(s) +++ with the Work to which such Contribution(s) was submitted. If You +++ institute patent litigation against any entity (including a +++ cross-claim or counterclaim in a lawsuit) alleging that the Work +++ or a Contribution incorporated within the Work constitutes direct +++ or contributory patent infringement, then any patent licenses +++ granted to You under this License for that Work shall terminate +++ as of the date such litigation is filed. +++ +++ 4. Redistribution. You may reproduce and distribute copies of the +++ Work or Derivative Works thereof in any medium, with or without +++ modifications, and in Source or Object form, provided that You +++ meet the following conditions: +++ +++ (a) You must give any other recipients of the Work or +++ Derivative Works a copy of this License; and +++ +++ (b) You must cause any modified files to carry prominent notices +++ stating that You changed the files; and +++ +++ (c) You must retain, in the Source form of any Derivative Works +++ that You distribute, all copyright, patent, trademark, and +++ attribution notices from the Source form of the Work, +++ excluding those notices that do not pertain to any part of +++ the Derivative Works; and +++ +++ (d) If the Work includes a "NOTICE" text file as part of its +++ distribution, then any Derivative Works that You distribute must +++ include a readable copy of the attribution notices contained +++ within such NOTICE file, excluding those notices that do not +++ pertain to any part of the Derivative Works, in at least one +++ of the following places: within a NOTICE text file distributed +++ as part of the Derivative Works; within the Source form or +++ documentation, if provided along with the Derivative Works; or, +++ within a display generated by the Derivative Works, if and +++ wherever such third-party notices normally appear. The contents +++ of the NOTICE file are for informational purposes only and +++ do not modify the License. You may add Your own attribution +++ notices within Derivative Works that You distribute, alongside +++ or as an addendum to the NOTICE text from the Work, provided +++ that such additional attribution notices cannot be construed +++ as modifying the License. +++ +++ You may add Your own copyright statement to Your modifications and +++ may provide additional or different license terms and conditions +++ for use, reproduction, or distribution of Your modifications, or +++ for any such Derivative Works as a whole, provided Your use, +++ reproduction, and distribution of the Work otherwise complies with +++ the conditions stated in this License. +++ +++ 5. Submission of Contributions. Unless You explicitly state otherwise, +++ any Contribution intentionally submitted for inclusion in the Work +++ by You to the Licensor shall be under the terms and conditions of +++ this License, without any additional terms or conditions. +++ Notwithstanding the above, nothing herein shall supersede or modify +++ the terms of any separate license agreement you may have executed +++ with Licensor regarding such Contributions. +++ +++ 6. Trademarks. This License does not grant permission to use the trade +++ names, trademarks, service marks, or product names of the Licensor, +++ except as required for reasonable and customary use in describing the +++ origin of the Work and reproducing the content of the NOTICE file. +++ +++ 7. Disclaimer of Warranty. Unless required by applicable law or +++ agreed to in writing, Licensor provides the Work (and each +++ Contributor provides its Contributions) on an "AS IS" BASIS, +++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +++ implied, including, without limitation, any warranties or conditions +++ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +++ PARTICULAR PURPOSE. You are solely responsible for determining the +++ appropriateness of using or redistributing the Work and assume any +++ risks associated with Your exercise of permissions under this License. +++ +++ 8. Limitation of Liability. In no event and under no legal theory, +++ whether in tort (including negligence), contract, or otherwise, +++ unless required by applicable law (such as deliberate and grossly +++ negligent acts) or agreed to in writing, shall any Contributor be +++ liable to You for damages, including any direct, indirect, special, +++ incidental, or consequential damages of any character arising as a +++ result of this License or out of the use or inability to use the +++ Work (including but not limited to damages for loss of goodwill, +++ work stoppage, computer failure or malfunction, or any and all +++ other commercial damages or losses), even if such Contributor +++ has been advised of the possibility of such damages. +++ +++ 9. Accepting Warranty or Additional Liability. While redistributing +++ the Work or Derivative Works thereof, You may choose to offer, +++ and charge a fee for, acceptance of support, warranty, indemnity, +++ or other liability obligations and/or rights consistent with this +++ License. However, in accepting such obligations, You may act only +++ on Your own behalf and on Your sole responsibility, not on behalf +++ of any other Contributor, and only if You agree to indemnify, +++ defend, and hold each Contributor harmless for any liability +++ incurred by, or claims asserted against, such Contributor by reason +++ of your accepting any such warranty or additional liability. +++ +++ END OF TERMS AND CONDITIONS +++ +++ APPENDIX: How to apply the Apache License to your work. +++ +++ To apply the Apache License to your work, attach the following +++ boilerplate notice, with the fields enclosed by brackets "[]" +++ replaced with your own identifying information. (Don't include +++ the brackets!) The text should be enclosed in the appropriate +++ comment syntax for the file format. We also recommend that a +++ file or class name and description of purpose be included on the +++ same "printed page" as the copyright notice for easier +++ identification within third-party archives. +++ +++ Copyright [yyyy] [name of copyright owner] +++ +++ Licensed under the Apache License, Version 2.0 (the "License"); +++ you may not use this file except in compliance with the License. +++ You may obtain a copy of the License at +++ +++ http://www.apache.org/licenses/LICENSE-2.0 +++ +++ Unless required by applicable law or agreed to in writing, software +++ distributed under the License is distributed on an "AS IS" BASIS, +++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++ See the License for the specific language governing permissions and +++ limitations under the License. +++ +++-------------------------------------------------------------------------------- +++For files in the `ndk_compat` folder: +++-------------------------------------------------------------------------------- +++ +++Copyright (C) 2010 The Android Open Source Project +++All rights reserved. +++Redistribution and use in source and binary forms, with or without +++modification, are permitted provided that the following conditions +++are met: +++ * Redistributions of source code must retain the above copyright +++ notice, this list of conditions and the following disclaimer. +++ * Redistributions in binary form must reproduce the above copyright +++ notice, this list of conditions and the following disclaimer in +++ the documentation and/or other materials provided with the +++ distribution. +++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +++"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +++LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +++FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +++COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +++INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +++BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +++OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +++AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +++OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +++OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +++SUCH DAMAGE. diff --cc cpu-features/README.md index 0000000,0000000,0000000..8a34168 new file mode 100644 --- /dev/null +++ b/cpu-features/README.md @@@@ -1,0 -1,0 -1,0 +1,199 @@@@ +++# cpu_features [![Build Status](https://travis-ci.org/google/cpu_features.svg?branch=master)](https://travis-ci.org/google/cpu_features) [![Build status](https://ci.appveyor.com/api/projects/status/46d1owsj7n8dsylq/branch/master?svg=true)](https://ci.appveyor.com/project/gchatelet/cpu-features/branch/master) +++ +++A cross-platform C library to retrieve CPU features (such as available +++instructions) at runtime. +++ +++## Table of Contents +++ +++- [Design Rationale](#rationale) +++- [Code samples](#codesample) +++- [Running sample code](#usagesample) +++- [What's supported](#support) +++- [Android NDK's drop in replacement](#ndk) +++- [License](#license) +++- [Build with cmake](#cmake) +++ +++ +++## Design Rationale +++ +++- **Simple to use.** See the snippets below for examples. +++- **Extensible.** Easy to add missing features or architectures. +++- **Compatible with old compilers** and available on many architectures so it +++ can be used widely. To ensure that cpu_features works on as many platforms +++ as possible, we implemented it in a highly portable version of C: C99. +++- **Sandbox-compatible.** The library uses a variety of strategies to cope +++ with sandboxed environments or when `cpuid` is unavailable. This is useful +++ when running integration tests in hermetic environments. +++- **Thread safe, no memory allocation, and raises no exceptions.** +++ cpu_features is suitable for implementing fundamental libc functions like +++ `malloc`, `memcpy`, and `memcmp`. +++- **Unit tested.** +++ +++ +++## Code samples +++ +++**Note:** For C++ code, the library functions are defined in the `CpuFeatures` namespace. +++ +++### Checking features at runtime +++ +++Here's a simple example that executes a codepath if the CPU supports both the +++AES and the SSE4.2 instruction sets: +++ +++```c +++#include "cpuinfo_x86.h" +++ +++// For C++, add `using namespace CpuFeatures;` +++static const X86Features features = GetX86Info().features; +++ +++void Compute(void) { +++ if (features.aes && features.sse4_2) { +++ // Run optimized code. +++ } else { +++ // Run standard code. +++ } +++} +++``` +++ +++### Caching for faster evaluation of complex checks +++ +++If you wish, you can read all the features at once into a global variable, and +++then query for the specific features you care about. Below, we store all the ARM +++features and then check whether AES and NEON are supported. +++ +++```c +++#include +++#include "cpuinfo_arm.h" +++ +++// For C++, add `using namespace CpuFeatures;` +++static const ArmFeatures features = GetArmInfo().features; +++static const bool has_aes_and_neon = features.aes && features.neon; +++ +++// use has_aes_and_neon. +++``` +++ +++This is a good approach to take if you're checking for combinations of features +++when using a compiler that is slow to extract individual bits from bit-packed +++structures. +++ +++### Checking compile time flags +++ +++The following code determines whether the compiler was told to use the AVX +++instruction set (e.g., `g++ -mavx`) and sets `has_avx` accordingly. +++ +++```c +++#include +++#include "cpuinfo_x86.h" +++ +++// For C++, add `using namespace CpuFeatures;` +++static const X86Features features = GetX86Info().features; +++static const bool has_avx = CPU_FEATURES_COMPILED_X86_AVX || features.avx; +++ +++// use has_avx. +++``` +++ +++`CPU_FEATURES_COMPILED_X86_AVX` is set to 1 if the compiler was instructed to +++use AVX and 0 otherwise, combining compile time and runtime knowledge. +++ +++### Rejecting poor hardware implementations based on microarchitecture +++ +++On x86, the first incarnation of a feature in a microarchitecture might not be +++the most efficient (e.g. AVX on Sandy Bridge). We provide a function to retrieve +++the underlying microarchitecture so you can decide whether to use it. +++ +++Below, `has_fast_avx` is set to 1 if the CPU supports the AVX instruction +++set—but only if it's not Sandy Bridge. +++ +++```c +++#include +++#include "cpuinfo_x86.h" +++ +++// For C++, add `using namespace CpuFeatures;` +++static const X86Info info = GetX86Info(); +++static const X86Microarchitecture uarch = GetX86Microarchitecture(&info); +++static const bool has_fast_avx = info.features.avx && uarch != INTEL_SNB; +++ +++// use has_fast_avx. +++``` +++ +++This feature is currently available only for x86 microarchitectures. +++ +++ +++### Running sample code +++ +++Building `cpu_features` (check [quickstart](#quickstart) below) brings a small executable to test the library. +++ +++```shell +++ % ./build/list_cpu_features +++arch : x86 +++brand : Intel(R) Xeon(R) CPU E5-1650 0 @ 3.20GHz +++family : 6 (0x06) +++model : 45 (0x2D) +++stepping : 7 (0x07) +++uarch : INTEL_SNB +++flags : aes,avx,cx16,smx,sse4_1,sse4_2,ssse3 +++``` +++ +++```shell +++% ./build/list_cpu_features --json +++{"arch":"x86","brand":" Intel(R) Xeon(R) CPU E5-1650 0 @ 3.20GHz","family":6,"model":45,"stepping":7,"uarch":"INTEL_SNB","flags":["aes","avx","cx16","smx","sse4_1","sse4_2","ssse3"]} +++``` +++ +++ +++## What's supported +++ +++| | x86³ | 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 | +++ +++1. **Features revealed from Linux.** We gather data from several sources +++ depending on availability: +++ + from glibc's +++ [getauxval](https://www.gnu.org/software/libc/manual/html_node/Auxiliary-Vector.html) +++ + by parsing `/proc/self/auxv` +++ + by parsing `/proc/cpuinfo` +++2. **Features revealed from CPU.** features are retrieved by using the `cpuid` +++ instruction. +++3. **Microarchitecture detection.** On x86 some features are not always +++ implemented efficiently in hardware (e.g. AVX on Sandybridge). Exposing the +++ microarchitecture allows the client to reject particular microarchitectures. +++4. All flavors of Mips are supported, little and big endian as well as 32/64 +++ bits. +++ +++ +++## Android NDK's drop in replacement +++ +++[cpu_features](https://github.com/google/cpu_features) is now officially +++supporting Android and offers a drop in replacement of for the NDK's [cpu-features.h](https://android.googlesource.com/platform/ndk/+/master/sources/android/cpufeatures/cpu-features.h) +++, see [ndk_compat](ndk_compat) folder for details. +++ +++ +++## License +++ +++The cpu_features library is licensed under the terms of the Apache license. +++See [LICENSE](LICENSE) for more information. +++ +++ +++## Build with CMake +++ +++Please check the [CMake build instructions](cmake/README.md). +++ +++ +++### Quickstart with `Ninja` +++ +++ - build `list_cpu_features` +++``` +++ cmake -B/tmp/cpu_features -H. -GNinja -DCMAKE_BUILD_TYPE=Release +++ ninja -C/tmp/cpu_features +++ /tmp/cpu_features/list_cpu_features --json +++``` +++ +++ - run tests +++``` +++ cmake -B/tmp/cpu_features -H. -GNinja -DBUILD_TESTING=ON +++ ninja -C/tmp/cpu_features +++ ninja -C/tmp/cpu_features test +++``` diff --cc cpu-features/WORKSPACE index 0000000,0000000,0000000..8ea8a8b new file mode 100644 --- /dev/null +++ b/cpu-features/WORKSPACE @@@@ -1,0 -1,0 -1,0 +1,7 @@@@ +++# ===== googletest ===== +++ +++git_repository( +++ name = "com_google_googletest", +++ remote = "https://github.com/google/googletest.git", +++ commit = "c3f65335b79f47b05629e79a54685d899bc53b93", +++) diff --cc cpu-features/appveyor.yml index 0000000,0000000,0000000..f18635a new file mode 100644 --- /dev/null +++ b/cpu-features/appveyor.yml @@@@ -1,0 -1,0 -1,0 +1,24 @@@@ +++version: '{build}' +++shallow_clone: true +++ +++platform: x64 +++ +++environment: +++ matrix: +++ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 +++ CMAKE_GENERATOR: "Visual Studio 15 2017 Win64" +++ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 +++ CMAKE_GENERATOR: "Visual Studio 14 2015 Win64" +++ +++matrix: +++ fast_finish: true +++ +++before_build: +++ - cmake --version +++ - cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON -H. -Bcmake_build -G "%CMAKE_GENERATOR%" +++ +++build_script: +++ - cmake --build cmake_build --config Debug --target ALL_BUILD +++ +++test_script: +++ - cmake --build cmake_build --config Debug --target RUN_TESTS diff --cc cpu-features/cmake/CpuFeaturesConfig.cmake.in index 0000000,0000000,0000000..e0bf10e new file mode 100644 --- /dev/null +++ b/cpu-features/cmake/CpuFeaturesConfig.cmake.in @@@@ -1,0 -1,0 -1,0 +1,3 @@@@ +++# CpuFeatures CMake configuration file +++ +++include("${CMAKE_CURRENT_LIST_DIR}/CpuFeaturesTargets.cmake") diff --cc cpu-features/cmake/CpuFeaturesNdkCompatConfig.cmake.in index 0000000,0000000,0000000..5a53ffd new file mode 100644 --- /dev/null +++ b/cpu-features/cmake/CpuFeaturesNdkCompatConfig.cmake.in @@@@ -1,0 -1,0 -1,0 +1,3 @@@@ +++# CpuFeaturesNdkCompat CMake configuration file +++ +++include("${CMAKE_CURRENT_LIST_DIR}/CpuFeaturesNdkCompatTargets.cmake") diff --cc cpu-features/cmake/README.md index 0000000,0000000,0000000..b6baeaa new file mode 100644 --- /dev/null +++ b/cpu-features/cmake/README.md @@@@ -1,0 -1,0 -1,0 +1,28 @@@@ +++# CMake build instructions +++ +++## Recommended usage : Incorporating cpu_features into a CMake project +++ +++ For API / ABI compatibility reasons, it is recommended to build and use +++ cpu_features in a subdirectory of your project or as an embedded dependency. +++ +++ This is similar to the recommended usage of the googletest framework +++ ( https://github.com/google/googletest/blob/master/googletest/README.md ) +++ +++ Build and use step-by-step +++ +++ +++ 1- Download cpu_features and copy it in a sub-directory in your project. +++ or add cpu_features as a git-submodule in your project +++ +++ 2- You can then use the cmake command `add_subdirectory()` to include +++ cpu_features directly and use the `cpu_features` target in your project. +++ +++ 3- Add the `cpu_features` target to the `target_link_libraries()` section of +++ your executable or of your library. +++ +++## Enabling tests +++ +++ CMake default options for cpu_features is Release built type with tests +++ disabled. To enable testing set cmake `BUILD_TESTING` variable to `ON`, +++ [.travis.yml](../.travis.yml) and [appveyor.yml](../appveyor.yml) have up to +++ date examples. diff --cc cpu-features/cmake/googletest.CMakeLists.txt.in index 0000000,0000000,0000000..d60a33e new file mode 100644 --- /dev/null +++ b/cpu-features/cmake/googletest.CMakeLists.txt.in @@@@ -1,0 -1,0 -1,0 +1,15 @@@@ +++cmake_minimum_required(VERSION 2.8.2) +++ +++project(googletest-download NONE) +++ +++include(ExternalProject) +++ExternalProject_Add(googletest +++ GIT_REPOSITORY https://github.com/google/googletest.git +++ GIT_TAG master +++ SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src" +++ BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build" +++ CONFIGURE_COMMAND "" +++ BUILD_COMMAND "" +++ INSTALL_COMMAND "" +++ TEST_COMMAND "" +++) diff --cc cpu-features/include/cpu_features_cache_info.h index 0000000,0000000,0000000..1a61ee1 new file mode 100644 --- /dev/null +++ b/cpu-features/include/cpu_features_cache_info.h @@@@ -1,0 -1,0 -1,0 +1,54 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#ifndef CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_ +++#define CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_ +++ +++#include "cpu_features_macros.h" +++ +++CPU_FEATURES_START_CPP_NAMESPACE +++ +++typedef enum { +++ CPU_FEATURE_CACHE_NULL = 0, +++ CPU_FEATURE_CACHE_DATA = 1, +++ CPU_FEATURE_CACHE_INSTRUCTION = 2, +++ CPU_FEATURE_CACHE_UNIFIED = 3, +++ CPU_FEATURE_CACHE_TLB = 4, +++ CPU_FEATURE_CACHE_DTLB = 5, +++ CPU_FEATURE_CACHE_STLB = 6, +++ CPU_FEATURE_CACHE_PREFETCH = 7 +++} CacheType; +++ +++typedef struct { +++ int level; +++ CacheType cache_type; +++ int cache_size; // Cache size in bytes +++ int ways; // Associativity, 0 undefined, 0xFF fully associative +++ int line_size; // Cache line size in bytes +++ int tlb_entries; // number of entries for TLB +++ int partitioning; // number of lines per sector +++} CacheLevelInfo; +++ +++// Increase this value if more cache levels are needed. +++#ifndef CPU_FEATURES_MAX_CACHE_LEVEL +++#define CPU_FEATURES_MAX_CACHE_LEVEL 10 +++#endif +++typedef struct { +++ int size; +++ CacheLevelInfo levels[CPU_FEATURES_MAX_CACHE_LEVEL]; +++} CacheInfo; +++ +++CPU_FEATURES_END_CPP_NAMESPACE +++ +++#endif // CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_ diff --cc cpu-features/include/cpu_features_macros.h index 0000000,0000000,0000000..4b231a1 new file mode 100644 --- /dev/null +++ b/cpu-features/include/cpu_features_macros.h @@@@ -1,0 -1,0 -1,0 +1,216 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#ifndef CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_ +++#define CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_ +++ +++//////////////////////////////////////////////////////////////////////////////// +++// Architectures +++//////////////////////////////////////////////////////////////////////////////// +++ +++#if defined(__pnacl__) || defined(__CLR_VER) +++#define CPU_FEATURES_ARCH_VM +++#endif +++ +++#if (defined(_M_IX86) || defined(__i386__)) && !defined(CPU_FEATURES_ARCH_VM) +++#define CPU_FEATURES_ARCH_X86_32 +++#endif +++ +++#if (defined(_M_X64) || defined(__x86_64__)) && !defined(CPU_FEATURES_ARCH_VM) +++#define CPU_FEATURES_ARCH_X86_64 +++#endif +++ +++#if defined(CPU_FEATURES_ARCH_X86_32) || defined(CPU_FEATURES_ARCH_X86_64) +++#define CPU_FEATURES_ARCH_X86 +++#endif +++ +++#if (defined(__arm__) || defined(_M_ARM)) +++#define CPU_FEATURES_ARCH_ARM +++#endif +++ +++#if defined(__aarch64__) +++#define CPU_FEATURES_ARCH_AARCH64 +++#endif +++ +++#if (defined(CPU_FEATURES_ARCH_AARCH64) || defined(CPU_FEATURES_ARCH_ARM)) +++#define CPU_FEATURES_ARCH_ANY_ARM +++#endif +++ +++#if defined(__mips64) +++#define CPU_FEATURES_ARCH_MIPS64 +++#endif +++ +++#if defined(__mips__) && !defined(__mips64) // mips64 also declares __mips__ +++#define CPU_FEATURES_ARCH_MIPS32 +++#endif +++ +++#if defined(CPU_FEATURES_ARCH_MIPS32) || defined(CPU_FEATURES_ARCH_MIPS64) +++#define CPU_FEATURES_ARCH_MIPS +++#endif +++ +++#if defined(__powerpc__) +++#define CPU_FEATURES_ARCH_PPC +++#endif +++ +++//////////////////////////////////////////////////////////////////////////////// +++// Os +++//////////////////////////////////////////////////////////////////////////////// +++ +++#if defined(__linux__) +++#define CPU_FEATURES_OS_LINUX_OR_ANDROID +++#endif +++ +++#if defined(__ANDROID__) +++#define CPU_FEATURES_OS_ANDROID +++#endif +++ +++#if (defined(_WIN64) || defined(_WIN32)) +++#define CPU_FEATURES_OS_WINDOWS +++#endif +++ +++#if (defined(__apple__) || defined(__APPLE__) || defined(__MACH__)) +++#define CPU_FEATURES_OS_DARWIN +++#endif +++ +++//////////////////////////////////////////////////////////////////////////////// +++// Compilers +++//////////////////////////////////////////////////////////////////////////////// +++ +++#if defined(__clang__) +++#define CPU_FEATURES_COMPILER_CLANG +++#endif +++ +++#if defined(__GNUC__) && !defined(__clang__) +++#define CPU_FEATURES_COMPILER_GCC +++#endif +++ +++#if defined(_MSC_VER) +++#define CPU_FEATURES_COMPILER_MSC +++#endif +++ +++//////////////////////////////////////////////////////////////////////////////// +++// Cpp +++//////////////////////////////////////////////////////////////////////////////// +++ +++#if defined(__cplusplus) +++#define CPU_FEATURES_START_CPP_NAMESPACE \ +++ namespace cpu_features { \ +++ extern "C" { +++#define CPU_FEATURES_END_CPP_NAMESPACE \ +++ } \ +++ } +++#else +++#define CPU_FEATURES_START_CPP_NAMESPACE +++#define CPU_FEATURES_END_CPP_NAMESPACE +++#endif +++ +++//////////////////////////////////////////////////////////////////////////////// +++// Compiler flags +++//////////////////////////////////////////////////////////////////////////////// +++ +++// Use the following to check if a feature is known to be available at +++// compile time. See README.md for an example. +++#if defined(CPU_FEATURES_ARCH_X86) +++ +++#if defined(__AES__) +++#define CPU_FEATURES_COMPILED_X86_AES 1 +++#else +++#define CPU_FEATURES_COMPILED_X86_AES 0 +++#endif // defined(__AES__) +++ +++#if defined(__F16C__) +++#define CPU_FEATURES_COMPILED_X86_F16C 1 +++#else +++#define CPU_FEATURES_COMPILED_X86_F16C 0 +++#endif // defined(__F16C__) +++ +++#if defined(__BMI__) +++#define CPU_FEATURES_COMPILED_X86_BMI 1 +++#else +++#define CPU_FEATURES_COMPILED_X86_BMI 0 +++#endif // defined(__BMI__) +++ +++#if defined(__BMI2__) +++#define CPU_FEATURES_COMPILED_X86_BMI2 1 +++#else +++#define CPU_FEATURES_COMPILED_X86_BMI2 0 +++#endif // defined(__BMI2__) +++ +++#if (defined(__SSE__) || (_M_IX86_FP >= 1)) +++#define CPU_FEATURES_COMPILED_X86_SSE 1 +++#else +++#define CPU_FEATURES_COMPILED_X86_SSE 0 +++#endif +++ +++#if (defined(__SSE2__) || (_M_IX86_FP >= 2)) +++#define CPU_FEATURES_COMPILED_X86_SSE2 1 +++#else +++#define CPU_FEATURES_COMPILED_X86_SSE2 0 +++#endif +++ +++#if defined(__SSE3__) +++#define CPU_FEATURES_COMPILED_X86_SSE3 1 +++#else +++#define CPU_FEATURES_COMPILED_X86_SSE3 0 +++#endif // defined(__SSE3__) +++ +++#if defined(__SSSE3__) +++#define CPU_FEATURES_COMPILED_X86_SSSE3 1 +++#else +++#define CPU_FEATURES_COMPILED_X86_SSSE3 0 +++#endif // defined(__SSSE3__) +++ +++#if defined(__SSE4_1__) +++#define CPU_FEATURES_COMPILED_X86_SSE4_1 1 +++#else +++#define CPU_FEATURES_COMPILED_X86_SSE4_1 0 +++#endif // defined(__SSE4_1__) +++ +++#if defined(__SSE4_2__) +++#define CPU_FEATURES_COMPILED_X86_SSE4_2 1 +++#else +++#define CPU_FEATURES_COMPILED_X86_SSE4_2 0 +++#endif // defined(__SSE4_2__) +++ +++#if defined(__AVX__) +++#define CPU_FEATURES_COMPILED_X86_AVX 1 +++#else +++#define CPU_FEATURES_COMPILED_X86_AVX 0 +++#endif // defined(__AVX__) +++ +++#if defined(__AVX2__) +++#define CPU_FEATURES_COMPILED_X86_AVX2 1 +++#else +++#define CPU_FEATURES_COMPILED_X86_AVX2 0 +++#endif // defined(__AVX2__) +++ +++#endif // defined(CPU_FEATURES_ARCH_X86) +++ +++#if defined(CPU_FEATURES_ARCH_ANY_ARM) +++#if defined(__ARM_NEON__) +++#define CPU_FEATURES_COMPILED_ANY_ARM_NEON 1 +++#else +++#define CPU_FEATURES_COMPILED_ANY_ARM_NEON 0 +++#endif // defined(__ARM_NEON__) +++#endif // defined(CPU_FEATURES_ARCH_ANY_ARM) +++ +++#if defined(CPU_FEATURES_ARCH_MIPS) +++#if defined(__mips_msa) +++#define CPU_FEATURES_COMPILED_MIPS_MSA 1 +++#else +++#define CPU_FEATURES_COMPILED_MIPS_MSA 0 +++#endif // defined(__mips_msa) +++#endif // defined(CPU_FEATURES_ARCH_MIPS) +++ +++#endif // CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_ diff --cc cpu-features/include/cpuinfo_aarch64.h index 0000000,0000000,0000000..d85d46d new file mode 100644 --- /dev/null +++ b/cpu-features/include/cpuinfo_aarch64.h @@@@ -1,0 -1,0 -1,0 +1,156 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#ifndef CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_ +++#define CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_ +++ +++#include "cpu_features_cache_info.h" +++#include "cpu_features_macros.h" +++ +++CPU_FEATURES_START_CPP_NAMESPACE +++ +++typedef struct { +++ int fp : 1; // Floating-point. +++ int asimd : 1; // Advanced SIMD. +++ int evtstrm : 1; // Generic timer generated events. +++ int aes : 1; // Hardware-accelerated Advanced Encryption Standard. +++ int pmull : 1; // Polynomial multiply long. +++ int sha1 : 1; // Hardware-accelerated SHA1. +++ int sha2 : 1; // Hardware-accelerated SHA2-256. +++ int crc32 : 1; // Hardware-accelerated CRC-32. +++ int atomics : 1; // Armv8.1 atomic instructions. +++ int fphp : 1; // Half-precision floating point support. +++ int asimdhp : 1; // Advanced SIMD half-precision support. +++ int cpuid : 1; // Access to certain ID registers. +++ int asimdrdm : 1; // Rounding Double Multiply Accumulate/Subtract. +++ int jscvt : 1; // Support for JavaScript conversion. +++ int fcma : 1; // Floating point complex numbers. +++ int lrcpc : 1; // Support for weaker release consistency. +++ int dcpop : 1; // Data persistence writeback. +++ int sha3 : 1; // Hardware-accelerated SHA3. +++ int sm3 : 1; // Hardware-accelerated SM3. +++ int sm4 : 1; // Hardware-accelerated SM4. +++ int asimddp : 1; // Dot product instruction. +++ int sha512 : 1; // Hardware-accelerated SHA512. +++ int sve : 1; // Scalable Vector Extension. +++ int asimdfhm : 1; // Additional half-precision instructions. +++ int dit : 1; // Data independent timing. +++ int uscat : 1; // Unaligned atomics support. +++ int ilrcpc : 1; // Additional support for weaker release consistency. +++ int flagm : 1; // Flag manipulation instructions. +++ int ssbs : 1; // Speculative Store Bypass Safe PSTATE bit. +++ int sb : 1; // Speculation barrier. +++ int paca : 1; // Address authentication. +++ int pacg : 1; // Generic authentication. +++ int dcpodp : 1; // Data cache clean to point of persistence. +++ int sve2 : 1; // Scalable Vector Extension (version 2). +++ int sveaes : 1; // SVE AES instructions. +++ int svepmull : 1; // SVE polynomial multiply long instructions. +++ int svebitperm : 1; // SVE bit permute instructions. +++ int svesha3 : 1; // SVE SHA3 instructions. +++ int svesm4 : 1; // SVE SM4 instructions. +++ int flagm2 : 1; // Additional flag manipulation instructions. +++ int frint : 1; // Floating point to integer rounding. +++ int svei8mm : 1; // SVE Int8 matrix multiplication instructions. +++ int svef32mm : 1; // SVE FP32 matrix multiplication instruction. +++ int svef64mm : 1; // SVE FP64 matrix multiplication instructions. +++ int svebf16 : 1; // SVE BFloat16 instructions. +++ int i8mm : 1; // Int8 matrix multiplication instructions. +++ int bf16 : 1; // BFloat16 instructions. +++ int dgh : 1; // Data Gathering Hint instruction. +++ int rng : 1; // True random number generator support. +++ int bti : 1; // Branch target identification. +++ +++ // 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; +++} Aarch64Info; +++ +++Aarch64Info GetAarch64Info(void); +++ +++//////////////////////////////////////////////////////////////////////////////// +++// Introspection functions +++ +++typedef enum { +++ AARCH64_FP, +++ AARCH64_ASIMD, +++ AARCH64_EVTSTRM, +++ AARCH64_AES, +++ AARCH64_PMULL, +++ AARCH64_SHA1, +++ AARCH64_SHA2, +++ AARCH64_CRC32, +++ AARCH64_ATOMICS, +++ AARCH64_FPHP, +++ AARCH64_ASIMDHP, +++ AARCH64_CPUID, +++ AARCH64_ASIMDRDM, +++ AARCH64_JSCVT, +++ AARCH64_FCMA, +++ AARCH64_LRCPC, +++ AARCH64_DCPOP, +++ AARCH64_SHA3, +++ AARCH64_SM3, +++ AARCH64_SM4, +++ AARCH64_ASIMDDP, +++ AARCH64_SHA512, +++ AARCH64_SVE, +++ AARCH64_ASIMDFHM, +++ AARCH64_DIT, +++ AARCH64_USCAT, +++ AARCH64_ILRCPC, +++ AARCH64_FLAGM, +++ AARCH64_SSBS, +++ AARCH64_SB, +++ AARCH64_PACA, +++ AARCH64_PACG, +++ AARCH64_DCPODP, +++ AARCH64_SVE2, +++ AARCH64_SVEAES, +++ AARCH64_SVEPMULL, +++ AARCH64_SVEBITPERM, +++ AARCH64_SVESHA3, +++ AARCH64_SVESM4, +++ AARCH64_FLAGM2, +++ AARCH64_FRINT, +++ AARCH64_SVEI8MM, +++ AARCH64_SVEF32MM, +++ AARCH64_SVEF64MM, +++ AARCH64_SVEBF16, +++ AARCH64_I8MM, +++ AARCH64_BF16, +++ AARCH64_DGH, +++ AARCH64_RNG, +++ AARCH64_BTI, +++ AARCH64_LAST_, +++} Aarch64FeaturesEnum; +++ +++int GetAarch64FeaturesEnumValue(const Aarch64Features* features, +++ Aarch64FeaturesEnum value); +++ +++const char* GetAarch64FeaturesEnumName(Aarch64FeaturesEnum); +++ +++CPU_FEATURES_END_CPP_NAMESPACE +++ +++#if !defined(CPU_FEATURES_ARCH_AARCH64) +++#error "Including cpuinfo_aarch64.h from a non-aarch64 target." +++#endif +++ +++#endif // CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_ diff --cc cpu-features/include/cpuinfo_arm.h index 0000000,0000000,0000000..0952d7c new file mode 100644 --- /dev/null +++ b/cpu-features/include/cpuinfo_arm.h @@@@ -1,0 -1,0 -1,0 +1,121 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#ifndef CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_ +++#define CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_ +++ +++#include // uint32_t +++ +++#include "cpu_features_cache_info.h" +++#include "cpu_features_macros.h" +++ +++CPU_FEATURES_START_CPP_NAMESPACE +++ +++typedef struct { +++ int swp : 1; // SWP instruction (atomic read-modify-write) +++ int half : 1; // Half-word loads and stores +++ int thumb : 1; // Thumb (16-bit instruction set) +++ int _26bit : 1; // "26 Bit" Model (Processor status register folded into +++ // program counter) +++ int fastmult : 1; // 32x32->64-bit multiplication +++ int fpa : 1; // Floating point accelerator +++ int vfp : 1; // Vector Floating Point. +++ int edsp : 1; // DSP extensions (the 'e' variant of the ARM9 CPUs, and all +++ // others above) +++ int java : 1; // Jazelle (Java bytecode accelerator) +++ int iwmmxt : 1; // Intel Wireless MMX Technology. +++ int crunch : 1; // MaverickCrunch coprocessor +++ int thumbee : 1; // ThumbEE +++ int neon : 1; // Advanced SIMD. +++ int vfpv3 : 1; // VFP version 3 +++ int vfpv3d16 : 1; // VFP version 3 with 16 D-registers +++ int tls : 1; // TLS register +++ int vfpv4 : 1; // VFP version 4 with fast context switching +++ int idiva : 1; // SDIV and UDIV hardware division in ARM mode. +++ int idivt : 1; // SDIV and UDIV hardware division in Thumb mode. +++ int vfpd32 : 1; // VFP with 32 D-registers +++ int lpae : 1; // Large Physical Address Extension (>4GB physical memory on +++ // 32-bit architecture) +++ int evtstrm : 1; // kernel event stream using generic architected timer +++ int aes : 1; // Hardware-accelerated Advanced Encryption Standard. +++ int pmull : 1; // Polynomial multiply long. +++ int sha1 : 1; // Hardware-accelerated SHA1. +++ int sha2 : 1; // Hardware-accelerated SHA2-256. +++ int crc32 : 1; // Hardware-accelerated CRC-32. +++ +++ // Make sure to update ArmFeaturesEnum below if you add a field here. +++} ArmFeatures; +++ +++typedef struct { +++ ArmFeatures features; +++ int implementer; +++ int architecture; +++ int variant; +++ int part; +++ int revision; +++} ArmInfo; +++ +++// TODO(user): Add macros to know which features are present at compile +++// time. +++ +++ArmInfo GetArmInfo(void); +++ +++// Compute CpuId from ArmInfo. +++uint32_t GetArmCpuId(const ArmInfo* const info); +++ +++//////////////////////////////////////////////////////////////////////////////// +++// Introspection functions +++ +++typedef enum { +++ ARM_SWP, +++ ARM_HALF, +++ ARM_THUMB, +++ ARM_26BIT, +++ ARM_FASTMULT, +++ ARM_FPA, +++ ARM_VFP, +++ ARM_EDSP, +++ ARM_JAVA, +++ ARM_IWMMXT, +++ ARM_CRUNCH, +++ ARM_THUMBEE, +++ ARM_NEON, +++ ARM_VFPV3, +++ ARM_VFPV3D16, +++ ARM_TLS, +++ ARM_VFPV4, +++ ARM_IDIVA, +++ ARM_IDIVT, +++ ARM_VFPD32, +++ ARM_LPAE, +++ ARM_EVTSTRM, +++ ARM_AES, +++ ARM_PMULL, +++ ARM_SHA1, +++ ARM_SHA2, +++ ARM_CRC32, +++ ARM_LAST_, +++} ArmFeaturesEnum; +++ +++int GetArmFeaturesEnumValue(const ArmFeatures* features, ArmFeaturesEnum value); +++ +++const char* GetArmFeaturesEnumName(ArmFeaturesEnum); +++ +++CPU_FEATURES_END_CPP_NAMESPACE +++ +++#if !defined(CPU_FEATURES_ARCH_ARM) +++#error "Including cpuinfo_arm.h from a non-arm target." +++#endif +++ +++#endif // CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_ diff --cc cpu-features/include/cpuinfo_mips.h index 0000000,0000000,0000000..9e5e7fc new file mode 100644 --- /dev/null +++ b/cpu-features/include/cpuinfo_mips.h @@@@ -1,0 -1,0 -1,0 +1,60 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#ifndef CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_ +++#define CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_ +++ +++#include "cpu_features_cache_info.h" +++#include "cpu_features_macros.h" +++ +++CPU_FEATURES_START_CPP_NAMESPACE +++ +++typedef struct { +++ int msa : 1; // MIPS SIMD Architecture +++ // https://www.mips.com/products/architectures/ase/simd/ +++ int eva : 1; // Enhanced Virtual Addressing +++ // https://www.mips.com/products/architectures/mips64/ +++ int r6 : 1; // True if is release 6 of the processor. +++ +++ // Make sure to update MipsFeaturesEnum below if you add a field here. +++} MipsFeatures; +++ +++typedef struct { +++ MipsFeatures features; +++} MipsInfo; +++ +++MipsInfo GetMipsInfo(void); +++ +++//////////////////////////////////////////////////////////////////////////////// +++// Introspection functions +++ +++typedef enum { +++ MIPS_MSA, +++ MIPS_EVA, +++ MIPS_R6, +++ MIPS_LAST_, +++} MipsFeaturesEnum; +++ +++int GetMipsFeaturesEnumValue(const MipsFeatures* features, +++ MipsFeaturesEnum value); +++ +++const char* GetMipsFeaturesEnumName(MipsFeaturesEnum); +++ +++CPU_FEATURES_END_CPP_NAMESPACE +++ +++#if !defined(CPU_FEATURES_ARCH_MIPS) +++#error "Including cpuinfo_mips.h from a non-mips target." +++#endif +++ +++#endif // CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_ diff --cc cpu-features/include/cpuinfo_ppc.h index 0000000,0000000,0000000..f691194 new file mode 100644 --- /dev/null +++ b/cpu-features/include/cpuinfo_ppc.h @@@@ -1,0 -1,0 -1,0 +1,146 @@@@ +++// Copyright 2018 IBM +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#ifndef CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_ +++#define CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_ +++ +++#include "cpu_features_cache_info.h" +++#include "cpu_features_macros.h" +++#include "internal/hwcaps.h" +++ +++CPU_FEATURES_START_CPP_NAMESPACE +++ +++typedef struct { +++ int ppc32 : 1; +++ int ppc64 : 1; +++ int ppc601 : 1; +++ int altivec : 1; +++ int fpu : 1; +++ int mmu : 1; +++ int mac_4xx : 1; +++ int unifiedcache : 1; +++ int spe : 1; +++ int efpsingle : 1; +++ int efpdouble : 1; +++ int no_tb : 1; +++ int power4 : 1; +++ int power5 : 1; +++ int power5plus : 1; +++ int cell : 1; +++ int booke : 1; +++ int smt : 1; +++ int icachesnoop : 1; +++ int arch205 : 1; +++ int pa6t : 1; +++ int dfp : 1; +++ int power6ext : 1; +++ int arch206 : 1; +++ int vsx : 1; +++ int pseries_perfmon_compat : 1; +++ int truele : 1; +++ int ppcle : 1; +++ int arch207 : 1; +++ int htm : 1; +++ int dscr : 1; +++ int ebb : 1; +++ int isel : 1; +++ int tar : 1; +++ int vcrypto : 1; +++ int htm_nosc : 1; +++ int arch300 : 1; +++ int ieee128 : 1; +++ int darn : 1; +++ int scv : 1; +++ int htm_no_suspend : 1; +++ +++ // Make sure to update PPCFeaturesEnum below if you add a field here. +++} PPCFeatures; +++ +++typedef struct { +++ PPCFeatures features; +++} PPCInfo; +++ +++// This function is guaranteed to be malloc, memset and memcpy free. +++PPCInfo GetPPCInfo(void); +++ +++typedef struct { +++ char platform[64]; // 0 terminated string +++ char model[64]; // 0 terminated string +++ char machine[64]; // 0 terminated string +++ char cpu[64]; // 0 terminated string +++ PlatformType type; +++} PPCPlatformStrings; +++ +++PPCPlatformStrings GetPPCPlatformStrings(void); +++ +++//////////////////////////////////////////////////////////////////////////////// +++// Introspection functions +++ +++typedef enum { +++ PPC_32, /* 32 bit mode execution */ +++ PPC_64, /* 64 bit mode execution */ +++ PPC_601_INSTR, /* Old POWER ISA */ +++ PPC_HAS_ALTIVEC, /* SIMD Unit*/ +++ PPC_HAS_FPU, /* Floating Point Unit */ +++ PPC_HAS_MMU, /* Memory management unit */ +++ PPC_HAS_4xxMAC, +++ PPC_UNIFIED_CACHE, /* Unified instruction and data cache */ +++ PPC_HAS_SPE, /* Signal processing extention unit */ +++ PPC_HAS_EFP_SINGLE, /* SPE single precision fpu */ +++ PPC_HAS_EFP_DOUBLE, /* SPE double precision fpu */ +++ PPC_NO_TB, /* No timebase */ +++ PPC_POWER4, +++ PPC_POWER5, +++ PPC_POWER5_PLUS, +++ PPC_CELL, /* Cell broadband engine */ +++ PPC_BOOKE, /* Embedded ISA */ +++ PPC_SMT, /* Simultaneous multi-threading */ +++ PPC_ICACHE_SNOOP, +++ PPC_ARCH_2_05, /* ISA 2.05 - POWER6 */ +++ PPC_PA6T, /* PA Semi 6T core ISA */ +++ PPC_HAS_DFP, /* Decimal floating point unit */ +++ PPC_POWER6_EXT, +++ PPC_ARCH_2_06, /* ISA 2.06 - POWER7 */ +++ PPC_HAS_VSX, /* Vector-scalar extension */ +++ PPC_PSERIES_PERFMON_COMPAT, /* Set of backwards compatibile performance +++ monitoring events */ +++ PPC_TRUE_LE, +++ PPC_PPC_LE, +++ PPC_ARCH_2_07, /* ISA 2.07 - POWER8 */ +++ PPC_HTM, /* Hardware Transactional Memory */ +++ PPC_DSCR, /* Data stream control register */ +++ PPC_EBB, /* Event base branching */ +++ PPC_ISEL, /* Integer select instructions */ +++ PPC_TAR, /* Target address register */ +++ PPC_VEC_CRYPTO, /* Vector cryptography instructions */ +++ PPC_HTM_NOSC, /* Transactions aborted when syscall made*/ +++ PPC_ARCH_3_00, /* ISA 3.00 - POWER9 */ +++ PPC_HAS_IEEE128, /* VSX IEEE Binary Float 128-bit */ +++ PPC_DARN, /* Deliver a random number instruction */ +++ PPC_SCV, /* scv syscall */ +++ PPC_HTM_NO_SUSPEND, /* TM w/out suspended state */ +++ PPC_LAST_, +++} PPCFeaturesEnum; +++ +++int GetPPCFeaturesEnumValue(const PPCFeatures* features, PPCFeaturesEnum value); +++ +++const char* GetPPCFeaturesEnumName(PPCFeaturesEnum); +++ +++CPU_FEATURES_END_CPP_NAMESPACE +++ +++#if !defined(CPU_FEATURES_ARCH_PPC) +++#error "Including cpuinfo_ppc.h from a non-ppc target." +++#endif +++ +++#endif // CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_ diff --cc cpu-features/include/cpuinfo_x86.h index 0000000,0000000,0000000..8d40f71 new file mode 100644 --- /dev/null +++ b/cpu-features/include/cpuinfo_x86.h @@@@ -1,0 -1,0 -1,0 +1,231 @@@@ +++// Copyright 2017 Google LLC +++// Copyright 2020 Intel Corporation +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#ifndef CPU_FEATURES_INCLUDE_CPUINFO_X86_H_ +++#define CPU_FEATURES_INCLUDE_CPUINFO_X86_H_ +++ +++#include "cpu_features_cache_info.h" +++#include "cpu_features_macros.h" +++ +++CPU_FEATURES_START_CPP_NAMESPACE +++ +++// See https://en.wikipedia.org/wiki/CPUID for a list of x86 cpu features. +++// The field names are based on the short name provided in the wikipedia tables. +++typedef struct { +++ int fpu : 1; +++ int tsc : 1; +++ int cx8 : 1; +++ int clfsh : 1; +++ int mmx : 1; +++ int aes : 1; +++ int erms : 1; +++ int f16c : 1; +++ int fma4 : 1; +++ int fma3 : 1; +++ int vaes : 1; +++ int vpclmulqdq : 1; +++ int bmi1 : 1; +++ int hle : 1; +++ int bmi2 : 1; +++ int rtm : 1; +++ int rdseed : 1; +++ int clflushopt : 1; +++ int clwb : 1; +++ +++ int sse : 1; +++ int sse2 : 1; +++ int sse3 : 1; +++ int ssse3 : 1; +++ int sse4_1 : 1; +++ int sse4_2 : 1; +++ int sse4a : 1; +++ +++ int avx : 1; +++ int avx2 : 1; +++ +++ int avx512f : 1; +++ int avx512cd : 1; +++ int avx512er : 1; +++ int avx512pf : 1; +++ int avx512bw : 1; +++ int avx512dq : 1; +++ int avx512vl : 1; +++ int avx512ifma : 1; +++ int avx512vbmi : 1; +++ int avx512vbmi2 : 1; +++ int avx512vnni : 1; +++ int avx512bitalg : 1; +++ int avx512vpopcntdq : 1; +++ int avx512_4vnniw : 1; +++ int avx512_4vbmi2 : 1; +++ int avx512_second_fma : 1; +++ int avx512_4fmaps : 1; +++ int avx512_bf16 : 1; +++ int avx512_vp2intersect : 1; +++ int amx_bf16 : 1; +++ int amx_tile : 1; +++ int amx_int8 : 1; +++ +++ int pclmulqdq : 1; +++ int smx : 1; +++ int sgx : 1; +++ int cx16 : 1; // aka. CMPXCHG16B +++ int sha : 1; +++ int popcnt : 1; +++ int movbe : 1; +++ int rdrnd : 1; +++ +++ int dca : 1; +++ int ss : 1; +++ // Make sure to update X86FeaturesEnum below if you add a field here. +++} X86Features; +++ +++typedef struct { +++ X86Features features; +++ int family; +++ int model; +++ int stepping; +++ char vendor[13]; // 0 terminated string +++} X86Info; +++ +++// Calls cpuid and returns an initialized X86info. +++// This function is guaranteed to be malloc, memset and memcpy free. +++X86Info GetX86Info(void); +++ +++// Returns cache hierarchy informations. +++// Can call cpuid multiple times. +++// Only works on Intel CPU at the moment. +++// This function is guaranteed to be malloc, memset and memcpy free. +++CacheInfo GetX86CacheInfo(void); +++ +++typedef enum { +++ X86_UNKNOWN, +++ INTEL_CORE, // CORE +++ INTEL_PNR, // PENRYN +++ INTEL_NHM, // NEHALEM +++ INTEL_ATOM_BNL, // BONNELL +++ INTEL_WSM, // WESTMERE +++ INTEL_SNB, // SANDYBRIDGE +++ INTEL_IVB, // IVYBRIDGE +++ INTEL_ATOM_SMT, // SILVERMONT +++ INTEL_HSW, // HASWELL +++ INTEL_BDW, // BROADWELL +++ INTEL_SKL, // SKYLAKE +++ INTEL_ATOM_GMT, // GOLDMONT +++ INTEL_KBL, // KABY LAKE +++ INTEL_CFL, // COFFEE LAKE +++ INTEL_WHL, // WHISKEY LAKE +++ INTEL_CNL, // CANNON LAKE +++ INTEL_ICL, // ICE LAKE +++ INTEL_TGL, // TIGER LAKE +++ INTEL_SPR, // SAPPHIRE RAPIDS +++ AMD_HAMMER, // K8 +++ AMD_K10, // K10 +++ AMD_BOBCAT, // K14 +++ AMD_BULLDOZER, // K15 +++ AMD_JAGUAR, // K16 +++ AMD_ZEN, // K17 +++} X86Microarchitecture; +++ +++// Returns the underlying microarchitecture by looking at X86Info's vendor, +++// family and model. +++X86Microarchitecture GetX86Microarchitecture(const X86Info* info); +++ +++// Calls cpuid and fills the brand_string. +++// - brand_string *must* be of size 49 (beware of array decaying). +++// - brand_string will be zero terminated. +++// - This function calls memcpy. +++void FillX86BrandString(char brand_string[49]); +++ +++//////////////////////////////////////////////////////////////////////////////// +++// Introspection functions +++ +++typedef enum { +++ X86_FPU, +++ X86_TSC, +++ X86_CX8, +++ X86_CLFSH, +++ X86_MMX, +++ X86_AES, +++ X86_ERMS, +++ X86_F16C, +++ X86_FMA4, +++ X86_FMA3, +++ X86_VAES, +++ X86_VPCLMULQDQ, +++ X86_BMI1, +++ X86_HLE, +++ X86_BMI2, +++ X86_RTM, +++ X86_RDSEED, +++ X86_CLFLUSHOPT, +++ X86_CLWB, +++ X86_SSE, +++ X86_SSE2, +++ X86_SSE3, +++ X86_SSSE3, +++ X86_SSE4_1, +++ X86_SSE4_2, +++ X86_SSE4A, +++ X86_AVX, +++ X86_AVX2, +++ X86_AVX512F, +++ X86_AVX512CD, +++ X86_AVX512ER, +++ X86_AVX512PF, +++ X86_AVX512BW, +++ X86_AVX512DQ, +++ X86_AVX512VL, +++ X86_AVX512IFMA, +++ X86_AVX512VBMI, +++ X86_AVX512VBMI2, +++ X86_AVX512VNNI, +++ X86_AVX512BITALG, +++ X86_AVX512VPOPCNTDQ, +++ X86_AVX512_4VNNIW, +++ X86_AVX512_4VBMI2, +++ X86_AVX512_SECOND_FMA, +++ X86_AVX512_4FMAPS, +++ X86_AVX512_BF16, +++ X86_AVX512_VP2INTERSECT, +++ X86_AMX_BF16, +++ X86_AMX_TILE, +++ X86_AMX_INT8, +++ X86_PCLMULQDQ, +++ X86_SMX, +++ X86_SGX, +++ X86_CX16, +++ X86_SHA, +++ X86_POPCNT, +++ X86_MOVBE, +++ X86_RDRND, +++ X86_DCA, +++ X86_SS, +++ X86_LAST_, +++} X86FeaturesEnum; +++ +++int GetX86FeaturesEnumValue(const X86Features* features, X86FeaturesEnum value); +++ +++const char* GetX86FeaturesEnumName(X86FeaturesEnum); +++ +++const char* GetX86MicroarchitectureName(X86Microarchitecture); +++ +++CPU_FEATURES_END_CPP_NAMESPACE +++ +++#if !defined(CPU_FEATURES_ARCH_X86) +++#error "Including cpuinfo_x86.h from a non-x86 target." +++#endif +++ +++#endif // CPU_FEATURES_INCLUDE_CPUINFO_X86_H_ diff --cc cpu-features/include/internal/bit_utils.h index 0000000,0000000,0000000..3467ff9 new file mode 100644 --- /dev/null +++ b/cpu-features/include/internal/bit_utils.h @@@@ -1,0 -1,0 -1,0 +1,40 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#ifndef CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_ +++#define CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_ +++ +++#include +++#include +++#include +++ +++#include "cpu_features_macros.h" +++ +++CPU_FEATURES_START_CPP_NAMESPACE +++ +++inline static bool IsBitSet(uint32_t reg, uint32_t bit) { +++ return (reg >> bit) & 0x1; +++} +++ +++inline static uint32_t ExtractBitRange(uint32_t reg, uint32_t msb, +++ uint32_t lsb) { +++ const uint64_t bits = msb - lsb + 1ULL; +++ const uint64_t mask = (1ULL << bits) - 1ULL; +++ assert(msb >= lsb); +++ return (reg >> lsb) & mask; +++} +++ +++CPU_FEATURES_END_CPP_NAMESPACE +++ +++#endif // CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_ diff --cc cpu-features/include/internal/cpuid_x86.h index 0000000,0000000,0000000..33327a4 new file mode 100644 --- /dev/null +++ b/cpu-features/include/internal/cpuid_x86.h @@@@ -1,0 -1,0 -1,0 +1,37 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#ifndef CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_ +++#define CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_ +++ +++#include +++ +++#include "cpu_features_macros.h" +++ +++CPU_FEATURES_START_CPP_NAMESPACE +++ +++// A struct to hold the result of a call to cpuid. +++typedef struct { +++ uint32_t eax, ebx, ecx, edx; +++} Leaf; +++ +++// Returns the result of a call to the cpuid instruction. +++Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx); +++ +++// Returns the eax value of the XCR0 register. +++uint32_t GetXCR0Eax(void); +++ +++CPU_FEATURES_END_CPP_NAMESPACE +++ +++#endif // CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_ diff --cc cpu-features/include/internal/filesystem.h index 0000000,0000000,0000000..d8f2f6a new file mode 100644 --- /dev/null +++ b/cpu-features/include/internal/filesystem.h @@@@ -1,0 -1,0 -1,0 +1,39 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++// An interface for the filesystem that allows mocking the filesystem in +++// unittests. +++#ifndef CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_ +++#define CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_ +++ +++#include +++#include +++ +++#include "cpu_features_macros.h" +++ +++CPU_FEATURES_START_CPP_NAMESPACE +++ +++// Same as linux "open(filename, O_RDONLY)", retries automatically on EINTR. +++int CpuFeatures_OpenFile(const char* filename); +++ +++// Same as linux "read(file_descriptor, buffer, buffer_size)", retries +++// automatically on EINTR. +++int CpuFeatures_ReadFile(int file_descriptor, void* buffer, size_t buffer_size); +++ +++// Same as linux "close(file_descriptor)". +++void CpuFeatures_CloseFile(int file_descriptor); +++ +++CPU_FEATURES_END_CPP_NAMESPACE +++ +++#endif // CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_ diff --cc cpu-features/include/internal/hwcaps.h index 0000000,0000000,0000000..62037c8 new file mode 100644 --- /dev/null +++ b/cpu-features/include/internal/hwcaps.h @@@@ -1,0 -1,0 -1,0 +1,186 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++// Interface to retrieve hardware capabilities. It relies on Linux's getauxval +++// or `/proc/self/auxval` under the hood. +++#ifndef CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_ +++#define CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_ +++ +++#include +++#include +++ +++#include "cpu_features_macros.h" +++ +++CPU_FEATURES_START_CPP_NAMESPACE +++ +++// To avoid depending on the linux kernel we reproduce the architecture specific +++// constants here. +++ +++// http://elixir.free-electrons.com/linux/latest/source/arch/arm64/include/uapi/asm/hwcap.h +++#define AARCH64_HWCAP_FP (1UL << 0) +++#define AARCH64_HWCAP_ASIMD (1UL << 1) +++#define AARCH64_HWCAP_EVTSTRM (1UL << 2) +++#define AARCH64_HWCAP_AES (1UL << 3) +++#define AARCH64_HWCAP_PMULL (1UL << 4) +++#define AARCH64_HWCAP_SHA1 (1UL << 5) +++#define AARCH64_HWCAP_SHA2 (1UL << 6) +++#define AARCH64_HWCAP_CRC32 (1UL << 7) +++#define AARCH64_HWCAP_ATOMICS (1UL << 8) +++#define AARCH64_HWCAP_FPHP (1UL << 9) +++#define AARCH64_HWCAP_ASIMDHP (1UL << 10) +++#define AARCH64_HWCAP_CPUID (1UL << 11) +++#define AARCH64_HWCAP_ASIMDRDM (1UL << 12) +++#define AARCH64_HWCAP_JSCVT (1UL << 13) +++#define AARCH64_HWCAP_FCMA (1UL << 14) +++#define AARCH64_HWCAP_LRCPC (1UL << 15) +++#define AARCH64_HWCAP_DCPOP (1UL << 16) +++#define AARCH64_HWCAP_SHA3 (1UL << 17) +++#define AARCH64_HWCAP_SM3 (1UL << 18) +++#define AARCH64_HWCAP_SM4 (1UL << 19) +++#define AARCH64_HWCAP_ASIMDDP (1UL << 20) +++#define AARCH64_HWCAP_SHA512 (1UL << 21) +++#define AARCH64_HWCAP_SVE (1UL << 22) +++#define AARCH64_HWCAP_ASIMDFHM (1UL << 23) +++#define AARCH64_HWCAP_DIT (1UL << 24) +++#define AARCH64_HWCAP_USCAT (1UL << 25) +++#define AARCH64_HWCAP_ILRCPC (1UL << 26) +++#define AARCH64_HWCAP_FLAGM (1UL << 27) +++#define AARCH64_HWCAP_SSBS (1UL << 28) +++#define AARCH64_HWCAP_SB (1UL << 29) +++#define AARCH64_HWCAP_PACA (1UL << 30) +++#define AARCH64_HWCAP_PACG (1UL << 31) +++ +++#define AARCH64_HWCAP2_DCPODP (1UL << 0) +++#define AARCH64_HWCAP2_SVE2 (1UL << 1) +++#define AARCH64_HWCAP2_SVEAES (1UL << 2) +++#define AARCH64_HWCAP2_SVEPMULL (1UL << 3) +++#define AARCH64_HWCAP2_SVEBITPERM (1UL << 4) +++#define AARCH64_HWCAP2_SVESHA3 (1UL << 5) +++#define AARCH64_HWCAP2_SVESM4 (1UL << 6) +++#define AARCH64_HWCAP2_FLAGM2 (1UL << 7) +++#define AARCH64_HWCAP2_FRINT (1UL << 8) +++#define AARCH64_HWCAP2_SVEI8MM (1UL << 9) +++#define AARCH64_HWCAP2_SVEF32MM (1UL << 10) +++#define AARCH64_HWCAP2_SVEF64MM (1UL << 11) +++#define AARCH64_HWCAP2_SVEBF16 (1UL << 12) +++#define AARCH64_HWCAP2_I8MM (1UL << 13) +++#define AARCH64_HWCAP2_BF16 (1UL << 14) +++#define AARCH64_HWCAP2_DGH (1UL << 15) +++#define AARCH64_HWCAP2_RNG (1UL << 16) +++#define AARCH64_HWCAP2_BTI (1UL << 17) +++ +++// http://elixir.free-electrons.com/linux/latest/source/arch/arm/include/uapi/asm/hwcap.h +++#define ARM_HWCAP_SWP (1UL << 0) +++#define ARM_HWCAP_HALF (1UL << 1) +++#define ARM_HWCAP_THUMB (1UL << 2) +++#define ARM_HWCAP_26BIT (1UL << 3) +++#define ARM_HWCAP_FAST_MULT (1UL << 4) +++#define ARM_HWCAP_FPA (1UL << 5) +++#define ARM_HWCAP_VFP (1UL << 6) +++#define ARM_HWCAP_EDSP (1UL << 7) +++#define ARM_HWCAP_JAVA (1UL << 8) +++#define ARM_HWCAP_IWMMXT (1UL << 9) +++#define ARM_HWCAP_CRUNCH (1UL << 10) +++#define ARM_HWCAP_THUMBEE (1UL << 11) +++#define ARM_HWCAP_NEON (1UL << 12) +++#define ARM_HWCAP_VFPV3 (1UL << 13) +++#define ARM_HWCAP_VFPV3D16 (1UL << 14) +++#define ARM_HWCAP_TLS (1UL << 15) +++#define ARM_HWCAP_VFPV4 (1UL << 16) +++#define ARM_HWCAP_IDIVA (1UL << 17) +++#define ARM_HWCAP_IDIVT (1UL << 18) +++#define ARM_HWCAP_VFPD32 (1UL << 19) +++#define ARM_HWCAP_LPAE (1UL << 20) +++#define ARM_HWCAP_EVTSTRM (1UL << 21) +++#define ARM_HWCAP2_AES (1UL << 0) +++#define ARM_HWCAP2_PMULL (1UL << 1) +++#define ARM_HWCAP2_SHA1 (1UL << 2) +++#define ARM_HWCAP2_SHA2 (1UL << 3) +++#define ARM_HWCAP2_CRC32 (1UL << 4) +++ +++// http://elixir.free-electrons.com/linux/latest/source/arch/mips/include/uapi/asm/hwcap.h +++#define MIPS_HWCAP_R6 (1UL << 0) +++#define MIPS_HWCAP_MSA (1UL << 1) +++#define MIPS_HWCAP_CRC32 (1UL << 2) +++ +++// http://elixir.free-electrons.com/linux/latest/source/arch/powerpc/include/uapi/asm/cputable.h +++#ifndef _UAPI__ASM_POWERPC_CPUTABLE_H +++/* in AT_HWCAP */ +++#define PPC_FEATURE_32 0x80000000 +++#define PPC_FEATURE_64 0x40000000 +++#define PPC_FEATURE_601_INSTR 0x20000000 +++#define PPC_FEATURE_HAS_ALTIVEC 0x10000000 +++#define PPC_FEATURE_HAS_FPU 0x08000000 +++#define PPC_FEATURE_HAS_MMU 0x04000000 +++#define PPC_FEATURE_HAS_4xxMAC 0x02000000 +++#define PPC_FEATURE_UNIFIED_CACHE 0x01000000 +++#define PPC_FEATURE_HAS_SPE 0x00800000 +++#define PPC_FEATURE_HAS_EFP_SINGLE 0x00400000 +++#define PPC_FEATURE_HAS_EFP_DOUBLE 0x00200000 +++#define PPC_FEATURE_NO_TB 0x00100000 +++#define PPC_FEATURE_POWER4 0x00080000 +++#define PPC_FEATURE_POWER5 0x00040000 +++#define PPC_FEATURE_POWER5_PLUS 0x00020000 +++#define PPC_FEATURE_CELL 0x00010000 +++#define PPC_FEATURE_BOOKE 0x00008000 +++#define PPC_FEATURE_SMT 0x00004000 +++#define PPC_FEATURE_ICACHE_SNOOP 0x00002000 +++#define PPC_FEATURE_ARCH_2_05 0x00001000 +++#define PPC_FEATURE_PA6T 0x00000800 +++#define PPC_FEATURE_HAS_DFP 0x00000400 +++#define PPC_FEATURE_POWER6_EXT 0x00000200 +++#define PPC_FEATURE_ARCH_2_06 0x00000100 +++#define PPC_FEATURE_HAS_VSX 0x00000080 +++ +++#define PPC_FEATURE_PSERIES_PERFMON_COMPAT 0x00000040 +++ +++/* Reserved - do not use 0x00000004 */ +++#define PPC_FEATURE_TRUE_LE 0x00000002 +++#define PPC_FEATURE_PPC_LE 0x00000001 +++ +++/* in AT_HWCAP2 */ +++#define PPC_FEATURE2_ARCH_2_07 0x80000000 +++#define PPC_FEATURE2_HTM 0x40000000 +++#define PPC_FEATURE2_DSCR 0x20000000 +++#define PPC_FEATURE2_EBB 0x10000000 +++#define PPC_FEATURE2_ISEL 0x08000000 +++#define PPC_FEATURE2_TAR 0x04000000 +++#define PPC_FEATURE2_VEC_CRYPTO 0x02000000 +++#define PPC_FEATURE2_HTM_NOSC 0x01000000 +++#define PPC_FEATURE2_ARCH_3_00 0x00800000 +++#define PPC_FEATURE2_HAS_IEEE128 0x00400000 +++#define PPC_FEATURE2_DARN 0x00200000 +++#define PPC_FEATURE2_SCV 0x00100000 +++#define PPC_FEATURE2_HTM_NO_SUSPEND 0x00080000 +++#endif +++ +++typedef struct { +++ unsigned long hwcaps; +++ unsigned long hwcaps2; +++} HardwareCapabilities; +++ +++HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void); +++bool CpuFeatures_IsHwCapsSet(const HardwareCapabilities hwcaps_mask, +++ const HardwareCapabilities hwcaps); +++ +++typedef struct { +++ char platform[64]; // 0 terminated string +++ char base_platform[64]; // 0 terminated string +++} PlatformType; +++ +++PlatformType CpuFeatures_GetPlatformType(void); +++ +++CPU_FEATURES_END_CPP_NAMESPACE +++ +++#endif // CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_ diff --cc cpu-features/include/internal/stack_line_reader.h index 0000000,0000000,0000000..39c1b8b new file mode 100644 --- /dev/null +++ b/cpu-features/include/internal/stack_line_reader.h @@@@ -1,0 -1,0 -1,0 +1,49 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++// Reads a file line by line and stores the data on the stack. This allows +++// parsing files in one go without allocating. +++#ifndef CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_ +++#define CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_ +++ +++#include +++ +++#include "cpu_features_macros.h" +++#include "internal/string_view.h" +++ +++CPU_FEATURES_START_CPP_NAMESPACE +++ +++typedef struct { +++ char buffer[STACK_LINE_READER_BUFFER_SIZE]; +++ StringView view; +++ int fd; +++ bool skip_mode; +++} StackLineReader; +++ +++// Initializes a StackLineReader. +++void StackLineReader_Initialize(StackLineReader* reader, int fd); +++ +++typedef struct { +++ StringView line; // A view of the line. +++ bool eof; // Nothing more to read, we reached EOF. +++ bool full_line; // If false the line was truncated to +++ // STACK_LINE_READER_BUFFER_SIZE. +++} LineResult; +++ +++// Reads the file pointed to by fd and tries to read a full line. +++LineResult StackLineReader_NextLine(StackLineReader* reader); +++ +++CPU_FEATURES_END_CPP_NAMESPACE +++ +++#endif // CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_ diff --cc cpu-features/include/internal/string_view.h index 0000000,0000000,0000000..64fed40 new file mode 100644 --- /dev/null +++ b/cpu-features/include/internal/string_view.h @@@@ -1,0 -1,0 -1,0 +1,109 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++// A view over a piece of string. The view is not 0 terminated. +++#ifndef CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_ +++#define CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_ +++ +++#include +++#include +++#include +++ +++#include "cpu_features_macros.h" +++ +++CPU_FEATURES_START_CPP_NAMESPACE +++ +++typedef struct { +++ const char* ptr; +++ size_t size; +++} StringView; +++ +++#ifdef __cplusplus +++static const StringView kEmptyStringView = {NULL, 0}; +++#else +++static const StringView kEmptyStringView; +++#endif +++ +++// Returns a StringView from the provided string. +++// Passing NULL is valid only if size is 0. +++static inline StringView view(const char* str, const size_t size) { +++ StringView view; +++ view.ptr = str; +++ view.size = size; +++ return view; +++} +++ +++static inline StringView str(const char* str) { return view(str, strlen(str)); } +++ +++// Returns the index of the first occurrence of c in view or -1 if not found. +++int CpuFeatures_StringView_IndexOfChar(const StringView view, char c); +++ +++// Returns the index of the first occurrence of sub_view in view or -1 if not +++// found. +++int CpuFeatures_StringView_IndexOf(const StringView view, +++ const StringView sub_view); +++ +++// Returns whether a is equal to b (same content). +++bool CpuFeatures_StringView_IsEquals(const StringView a, const StringView b); +++ +++// Returns whether a starts with b. +++bool CpuFeatures_StringView_StartsWith(const StringView a, const StringView b); +++ +++// Removes count characters from the beginning of view or kEmptyStringView if +++// count if greater than view.size. +++StringView CpuFeatures_StringView_PopFront(const StringView str_view, +++ size_t count); +++ +++// Removes count characters from the end of view or kEmptyStringView if count if +++// greater than view.size. +++StringView CpuFeatures_StringView_PopBack(const StringView str_view, +++ size_t count); +++ +++// Keeps the count first characters of view or view if count if greater than +++// view.size. +++StringView CpuFeatures_StringView_KeepFront(const StringView str_view, +++ size_t count); +++ +++// Retrieves the first character of view. If view is empty the behavior is +++// undefined. +++char CpuFeatures_StringView_Front(const StringView view); +++ +++// Retrieves the last character of view. If view is empty the behavior is +++// undefined. +++char CpuFeatures_StringView_Back(const StringView view); +++ +++// Removes leading and tailing space characters. +++StringView CpuFeatures_StringView_TrimWhitespace(StringView view); +++ +++// Convert StringView to positive integer. e.g. "42", "0x2a". +++// Returns -1 on error. +++int CpuFeatures_StringView_ParsePositiveNumber(const StringView view); +++ +++// Copies src StringView to dst buffer. +++void CpuFeatures_StringView_CopyString(const StringView src, char* dst, +++ size_t dst_size); +++ +++// Checks if line contains the specified whitespace separated word. +++bool CpuFeatures_StringView_HasWord(const StringView line, +++ const char* const word); +++ +++// Get key/value from line. key and value are separated by ": ". +++// key and value are cleaned up from leading and trailing whitespaces. +++bool CpuFeatures_StringView_GetAttributeKeyValue(const StringView line, +++ StringView* key, +++ StringView* value); +++ +++CPU_FEATURES_END_CPP_NAMESPACE +++ +++#endif // CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_ diff --cc cpu-features/ndk_compat/CMakeLists.txt index 0000000,0000000,0000000..186708a new file mode 100644 --- /dev/null +++ b/cpu-features/ndk_compat/CMakeLists.txt @@@@ -1,0 -1,0 -1,0 +1,60 @@@@ +++ +++# +++# library : NDK compat +++# +++find_package(Threads REQUIRED) +++set (NDK_COMPAT_HDRS cpu-features.h) +++set (NDK_COMPAT_SRCS +++ cpu-features.c +++ $ +++ $ +++) +++# Note that following `add_cpu_features_headers_and_sources` will use +++# NDK_COMPAT_SRCS in lieu of NDK_COMPAT_HDRS because we don't want cpu_features +++# headers to be installed alongside ndk_compat. +++add_cpu_features_headers_and_sources(NDK_COMPAT_SRCS NDK_COMPAT_SRCS) +++add_library(ndk_compat ${NDK_COMPAT_HDRS} ${NDK_COMPAT_SRCS}) +++setup_include_and_definitions(ndk_compat) +++target_include_directories(ndk_compat PUBLIC $) +++target_link_libraries(ndk_compat PUBLIC ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT}) +++set_target_properties(ndk_compat PROPERTIES PUBLIC_HEADER "${NDK_COMPAT_HDRS}") +++ +++include(GNUInstallDirs) +++install(TARGETS ndk_compat +++ EXPORT CpuFeaturesNdkCompatTargets +++ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ndk_compat +++ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +++ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} +++ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +++) +++install(EXPORT CpuFeaturesNdkCompatTargets +++ NAMESPACE CpuFeatures:: +++ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeaturesNdkCompat +++ COMPONENT Devel +++) +++include(CMakePackageConfigHelpers) +++configure_package_config_file(${PROJECT_SOURCE_DIR}/cmake/CpuFeaturesNdkCompatConfig.cmake.in +++ "${PROJECT_BINARY_DIR}/CpuFeaturesNdkCompatConfig.cmake" +++ INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeaturesNdkCompat" +++ NO_SET_AND_CHECK_MACRO +++ NO_CHECK_REQUIRED_COMPONENTS_MACRO +++) +++write_basic_package_version_file( +++ "${PROJECT_BINARY_DIR}/CpuFeaturesNdkCompatConfigVersion.cmake" +++ COMPATIBILITY SameMajorVersion +++) +++install( +++ FILES +++ "${PROJECT_BINARY_DIR}/CpuFeaturesNdkCompatConfig.cmake" +++ "${PROJECT_BINARY_DIR}/CpuFeaturesNdkCompatConfigVersion.cmake" +++ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeaturesNdkCompat" +++ COMPONENT Devel +++) +++ +++# +++# program : NDK compat test program +++# +++if(ENABLE_TESTING) +++ add_executable(ndk-compat-test ndk-compat-test.c) +++ target_link_libraries(ndk-compat-test PRIVATE ndk_compat) +++endif() diff --cc cpu-features/ndk_compat/README.md index 0000000,0000000,0000000..38c8393 new file mode 100644 --- /dev/null +++ b/cpu-features/ndk_compat/README.md @@@@ -1,0 -1,0 -1,0 +1,4 @@@@ +++Provides a header compatible with [android's NDK cpu-features.h](https://android.googlesource.com/platform/ndk/+/master/sources/android/cpufeatures/cpu-features.h). +++ +++It is intended to be a drop in replacement for this header and help users +++transition from the NDK to [Google's cpu_features library](https://github.com/google/cpu_features). diff --cc cpu-features/ndk_compat/cpu-features.c index 0000000,0000000,0000000..27ff7bb new file mode 100644 --- /dev/null +++ b/cpu-features/ndk_compat/cpu-features.c @@@@ -1,0 -1,0 -1,0 +1,205 @@@@ +++#include "cpu-features.h" +++ +++#include +++ +++#include "cpu_features_macros.h" +++#include "internal/filesystem.h" +++#include "internal/stack_line_reader.h" +++#include "internal/string_view.h" +++ +++#if defined(CPU_FEATURES_ARCH_ARM) +++#include "cpuinfo_arm.h" +++#elif defined(CPU_FEATURES_ARCH_X86) +++#include "cpuinfo_x86.h" +++#elif defined(CPU_FEATURES_ARCH_MIPS) +++#include "cpuinfo_mips.h" +++#elif defined(CPU_FEATURES_ARCH_AARCH64) +++#include "cpuinfo_aarch64.h" +++#endif +++ +++static pthread_once_t g_once; +++static int g_inited; +++static uint64_t g_cpuFeatures; +++static int g_cpuCount; +++ +++#ifdef CPU_FEATURES_ARCH_ARM +++static uint32_t g_cpuIdArm; +++#endif +++ +++static void set_cpu_mask_bit(uint32_t index, uint32_t* cpu_mask) { +++ *cpu_mask |= 1UL << index; +++} +++ +++// Examples of valid inputs: "31", "4-31" +++static void parse_cpu_mask(const StringView text, uint32_t* cpu_mask) { +++ int separator_index = CpuFeatures_StringView_IndexOfChar(text, '-'); +++ if (separator_index < 0) { // A single cpu index +++ int cpu_index = CpuFeatures_StringView_ParsePositiveNumber(text); +++ if (cpu_index < 0) return; +++ set_cpu_mask_bit(cpu_index, cpu_mask); +++ } else { +++ int cpu_index_a = CpuFeatures_StringView_ParsePositiveNumber( +++ CpuFeatures_StringView_KeepFront(text, separator_index)); +++ int cpu_index_b = CpuFeatures_StringView_ParsePositiveNumber( +++ CpuFeatures_StringView_PopFront(text, separator_index + 1)); +++ int i; +++ if (cpu_index_a < 0 || cpu_index_b < 0) return; +++ for (i = cpu_index_a; i <= cpu_index_b; ++i) { +++ if (i < 32) { +++ set_cpu_mask_bit(i, cpu_mask); +++ } +++ } +++ } +++} +++ +++// Format specification from +++// https://www.kernel.org/doc/Documentation/cputopology.txt +++// Examples of valid inputs: "31", "2,4-31,32-63", "0-1,3" +++static void parse_cpu_mask_line(const LineResult result, uint32_t* cpu_mask) { +++ if (!result.full_line || result.eof) return; +++ StringView line = result.line; +++ for (; line.size > 0;) { +++ int next_entry_index = CpuFeatures_StringView_IndexOfChar(line, ','); +++ if (next_entry_index < 0) { +++ parse_cpu_mask(line, cpu_mask); +++ break; +++ } +++ StringView entry = CpuFeatures_StringView_KeepFront(line, next_entry_index); +++ parse_cpu_mask(entry, cpu_mask); +++ line = CpuFeatures_StringView_PopFront(line, next_entry_index + 1); +++ } +++} +++ +++static void update_cpu_mask_from_file(const char* filename, +++ uint32_t* cpu_mask) { +++ const int fd = CpuFeatures_OpenFile(filename); +++ if (fd >= 0) { +++ StackLineReader reader; +++ StackLineReader_Initialize(&reader, fd); +++ parse_cpu_mask_line(StackLineReader_NextLine(&reader), cpu_mask); +++ CpuFeatures_CloseFile(fd); +++ } +++} +++ +++static int get_cpu_count(void) { +++ uint32_t cpu_mask = 0; +++ update_cpu_mask_from_file("/sys/devices/system/cpu/present", &cpu_mask); +++ update_cpu_mask_from_file("/sys/devices/system/cpu/possible", &cpu_mask); +++ return __builtin_popcount(cpu_mask); +++} +++ +++static void android_cpuInit(void) { +++ g_cpuFeatures = 0; +++ g_cpuCount = 1; +++ g_inited = 1; +++ +++ g_cpuCount = get_cpu_count(); +++ if (g_cpuCount == 0) { +++ g_cpuCount = 1; +++ } +++#if defined(CPU_FEATURES_ARCH_ARM) +++ ArmInfo info = GetArmInfo(); +++ if (info.architecture == 7) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_ARMv7; +++ if (info.features.vfpv3) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3; +++ if (info.features.neon) { +++ g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON; +++ g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFP_D32; +++ } +++ if (info.features.vfpv3d16) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFP_FP16; +++ if (info.features.idiva) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_ARM; +++ if (info.features.idivt) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2; +++ if (info.features.iwmmxt) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_iWMMXt; +++ if (info.features.aes) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_AES; +++ if (info.features.pmull) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_PMULL; +++ if (info.features.sha1) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_SHA1; +++ if (info.features.sha2) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_SHA2; +++ if (info.features.crc32) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_CRC32; +++ if (info.architecture >= 6) +++ g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_LDREX_STREX; +++ if (info.features.vfp) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv2; +++ if (info.features.vfpv4) { +++ g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFP_FMA; +++ g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON_FMA; +++ } +++ g_cpuIdArm = GetArmCpuId(&info); +++#elif defined(CPU_FEATURES_ARCH_X86) +++ X86Info info = GetX86Info(); +++ if (info.features.ssse3) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSSE3; +++ if (info.features.popcnt) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_POPCNT; +++ if (info.features.movbe) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_MOVBE; +++ if (info.features.sse4_1) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSE4_1; +++ if (info.features.sse4_2) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSE4_2; +++ if (info.features.aes) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AES_NI; +++ if (info.features.avx) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AVX; +++ if (info.features.rdrnd) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_RDRAND; +++ if (info.features.avx2) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AVX2; +++ if (info.features.sha) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SHA_NI; +++#elif defined(CPU_FEATURES_ARCH_MIPS) +++ MipsInfo info = GetMipsInfo(); +++ if (info.features.r6) g_cpuFeatures |= ANDROID_CPU_MIPS_FEATURE_R6; +++ if (info.features.msa) g_cpuFeatures |= ANDROID_CPU_MIPS_FEATURE_MSA; +++#elif defined(CPU_FEATURES_ARCH_AARCH64) +++ Aarch64Info info = GetAarch64Info(); +++ if (info.features.fp) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_FP; +++ if (info.features.asimd) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_ASIMD; +++ if (info.features.aes) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_AES; +++ if (info.features.pmull) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_PMULL; +++ if (info.features.sha1) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_SHA1; +++ if (info.features.sha2) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_SHA2; +++ if (info.features.crc32) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_CRC32; +++#endif +++} +++ +++AndroidCpuFamily android_getCpuFamily(void) { +++#if defined(CPU_FEATURES_ARCH_ARM) +++ return ANDROID_CPU_FAMILY_ARM; +++#elif defined(CPU_FEATURES_ARCH_X86_32) +++ return ANDROID_CPU_FAMILY_X86; +++#elif defined(CPU_FEATURES_ARCH_MIPS64) +++ return ANDROID_CPU_FAMILY_MIPS64; +++#elif defined(CPU_FEATURES_ARCH_MIPS32) +++ return ANDROID_CPU_FAMILY_MIPS; +++#elif defined(CPU_FEATURES_ARCH_AARCH64) +++ return ANDROID_CPU_FAMILY_ARM64; +++#elif defined(CPU_FEATURES_ARCH_X86_64) +++ return ANDROID_CPU_FAMILY_X86_64; +++#else +++ return ANDROID_CPU_FAMILY_UNKNOWN; +++#endif +++} +++ +++uint64_t android_getCpuFeatures(void) { +++ pthread_once(&g_once, android_cpuInit); +++ return g_cpuFeatures; +++} +++ +++int android_getCpuCount(void) { +++ pthread_once(&g_once, android_cpuInit); +++ return g_cpuCount; +++} +++ +++static void android_cpuInitDummy(void) { g_inited = 1; } +++ +++int android_setCpu(int cpu_count, uint64_t cpu_features) { +++ /* Fail if the library was already initialized. */ +++ if (g_inited) return 0; +++ g_cpuCount = (cpu_count <= 0 ? 1 : cpu_count); +++ g_cpuFeatures = cpu_features; +++ pthread_once(&g_once, android_cpuInitDummy); +++ return 1; +++} +++ +++#ifdef CPU_FEATURES_ARCH_ARM +++ +++uint32_t android_getCpuIdArm(void) { +++ pthread_once(&g_once, android_cpuInit); +++ return g_cpuIdArm; +++} +++ +++int android_setCpuArm(int cpu_count, uint64_t cpu_features, uint32_t cpu_id) { +++ if (!android_setCpu(cpu_count, cpu_features)) return 0; +++ g_cpuIdArm = cpu_id; +++ return 1; +++} +++ +++#endif // CPU_FEATURES_ARCH_ARM diff --cc cpu-features/ndk_compat/cpu-features.h index 0000000,0000000,0000000..51bea53 new file mode 100644 --- /dev/null +++ b/cpu-features/ndk_compat/cpu-features.h @@@@ -1,0 -1,0 -1,0 +1,320 @@@@ +++/* +++ * Copyright (C) 2010 The Android Open Source Project +++ * All rights reserved. +++ * +++ * Redistribution and use in source and binary forms, with or without +++ * modification, are permitted provided that the following conditions +++ * are met: +++ * * Redistributions of source code must retain the above copyright +++ * notice, this list of conditions and the following disclaimer. +++ * * Redistributions in binary form must reproduce the above copyright +++ * notice, this list of conditions and the following disclaimer in +++ * the documentation and/or other materials provided with the +++ * distribution. +++ * +++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +++ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +++ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +++ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +++ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +++ * SUCH DAMAGE. +++ */ +++#ifndef GOOGLE_CPU_FEATURES_H +++#define GOOGLE_CPU_FEATURES_H +++#include +++#include +++ +++__BEGIN_DECLS +++ +++/* A list of valid values returned by android_getCpuFamily(). +++ * They describe the CPU Architecture of the current process. +++ */ +++typedef enum { +++ ANDROID_CPU_FAMILY_UNKNOWN = 0, +++ ANDROID_CPU_FAMILY_ARM, +++ ANDROID_CPU_FAMILY_X86, +++ ANDROID_CPU_FAMILY_MIPS, +++ ANDROID_CPU_FAMILY_ARM64, +++ ANDROID_CPU_FAMILY_X86_64, +++ ANDROID_CPU_FAMILY_MIPS64, +++ ANDROID_CPU_FAMILY_MAX /* do not remove */ +++} AndroidCpuFamily; +++ +++/* Return the CPU family of the current process. +++ * +++ * Note that this matches the bitness of the current process. I.e. when +++ * running a 32-bit binary on a 64-bit capable CPU, this will return the +++ * 32-bit CPU family value. +++ */ +++extern AndroidCpuFamily android_getCpuFamily(void); +++ +++/* Return a bitmap describing a set of optional CPU features that are +++ * supported by the current device's CPU. The exact bit-flags returned +++ * depend on the value returned by android_getCpuFamily(). See the +++ * documentation for the ANDROID_CPU_*_FEATURE_* flags below for details. +++ */ +++extern uint64_t android_getCpuFeatures(void); +++ +++/* The list of feature flags for ANDROID_CPU_FAMILY_ARM that can be +++ * recognized by the library (see note below for 64-bit ARM). Value details +++ * are: +++ * +++ * VFPv2: +++ * CPU supports the VFPv2 instruction set. Many, but not all, ARMv6 CPUs +++ * support these instructions. VFPv2 is a subset of VFPv3 so this will +++ * be set whenever VFPv3 is set too. +++ * +++ * ARMv7: +++ * CPU supports the ARMv7-A basic instruction set. +++ * This feature is mandated by the 'armeabi-v7a' ABI. +++ * +++ * VFPv3: +++ * CPU supports the VFPv3-D16 instruction set, providing hardware FPU +++ * support for single and double precision floating point registers. +++ * Note that only 16 FPU registers are available by default, unless +++ * the D32 bit is set too. This feature is also mandated by the +++ * 'armeabi-v7a' ABI. +++ * +++ * VFP_D32: +++ * CPU VFP optional extension that provides 32 FPU registers, +++ * instead of 16. Note that ARM mandates this feature is the 'NEON' +++ * feature is implemented by the CPU. +++ * +++ * NEON: +++ * CPU FPU supports "ARM Advanced SIMD" instructions, also known as +++ * NEON. Note that this mandates the VFP_D32 feature as well, per the +++ * ARM Architecture specification. +++ * +++ * VFP_FP16: +++ * Half-width floating precision VFP extension. If set, the CPU +++ * supports instructions to perform floating-point operations on +++ * 16-bit registers. This is part of the VFPv4 specification, but +++ * not mandated by any Android ABI. +++ * +++ * VFP_FMA: +++ * Fused multiply-accumulate VFP instructions extension. Also part of +++ * the VFPv4 specification, but not mandated by any Android ABI. +++ * +++ * NEON_FMA: +++ * Fused multiply-accumulate NEON instructions extension. Optional +++ * extension from the VFPv4 specification, but not mandated by any +++ * Android ABI. +++ * +++ * IDIV_ARM: +++ * Integer division available in ARM mode. Only available +++ * on recent CPUs (e.g. Cortex-A15). +++ * +++ * IDIV_THUMB2: +++ * Integer division available in Thumb-2 mode. Only available +++ * on recent CPUs (e.g. Cortex-A15). +++ * +++ * iWMMXt: +++ * Optional extension that adds MMX registers and operations to an +++ * ARM CPU. This is only available on a few XScale-based CPU designs +++ * sold by Marvell. Pretty rare in practice. +++ * +++ * AES: +++ * CPU supports AES instructions. These instructions are only +++ * available for 32-bit applications running on ARMv8 CPU. +++ * +++ * CRC32: +++ * CPU supports CRC32 instructions. These instructions are only +++ * available for 32-bit applications running on ARMv8 CPU. +++ * +++ * SHA2: +++ * CPU supports SHA2 instructions. These instructions are only +++ * available for 32-bit applications running on ARMv8 CPU. +++ * +++ * SHA1: +++ * CPU supports SHA1 instructions. These instructions are only +++ * available for 32-bit applications running on ARMv8 CPU. +++ * +++ * PMULL: +++ * CPU supports 64-bit PMULL and PMULL2 instructions. These +++ * instructions are only available for 32-bit applications +++ * running on ARMv8 CPU. +++ * +++ * If you want to tell the compiler to generate code that targets one of +++ * the feature set above, you should probably use one of the following +++ * flags (for more details, see technical note at the end of this file): +++ * +++ * -mfpu=vfp +++ * -mfpu=vfpv2 +++ * These are equivalent and tell GCC to use VFPv2 instructions for +++ * floating-point operations. Use this if you want your code to +++ * run on *some* ARMv6 devices, and any ARMv7-A device supported +++ * by Android. +++ * +++ * Generated code requires VFPv2 feature. +++ * +++ * -mfpu=vfpv3-d16 +++ * Tell GCC to use VFPv3 instructions (using only 16 FPU registers). +++ * This should be generic code that runs on any CPU that supports the +++ * 'armeabi-v7a' Android ABI. Note that no ARMv6 CPU supports this. +++ * +++ * Generated code requires VFPv3 feature. +++ * +++ * -mfpu=vfpv3 +++ * Tell GCC to use VFPv3 instructions with 32 FPU registers. +++ * Generated code requires VFPv3|VFP_D32 features. +++ * +++ * -mfpu=neon +++ * Tell GCC to use VFPv3 instructions with 32 FPU registers, and +++ * also support NEON intrinsics (see ). +++ * Generated code requires VFPv3|VFP_D32|NEON features. +++ * +++ * -mfpu=vfpv4-d16 +++ * Generated code requires VFPv3|VFP_FP16|VFP_FMA features. +++ * +++ * -mfpu=vfpv4 +++ * Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32 features. +++ * +++ * -mfpu=neon-vfpv4 +++ * Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32|NEON|NEON_FMA +++ * features. +++ * +++ * -mcpu=cortex-a7 +++ * -mcpu=cortex-a15 +++ * Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32| +++ * NEON|NEON_FMA|IDIV_ARM|IDIV_THUMB2 +++ * This flag implies -mfpu=neon-vfpv4. +++ * +++ * -mcpu=iwmmxt +++ * Allows the use of iWMMXt instrinsics with GCC. +++ * +++ * IMPORTANT NOTE: These flags should only be tested when +++ * android_getCpuFamily() returns ANDROID_CPU_FAMILY_ARM, i.e. this is a +++ * 32-bit process. +++ * +++ * When running a 64-bit ARM process on an ARMv8 CPU, +++ * android_getCpuFeatures() will return a different set of bitflags +++ */ +++enum { +++ ANDROID_CPU_ARM_FEATURE_ARMv7 = (1 << 0), +++ ANDROID_CPU_ARM_FEATURE_VFPv3 = (1 << 1), +++ ANDROID_CPU_ARM_FEATURE_NEON = (1 << 2), +++ ANDROID_CPU_ARM_FEATURE_LDREX_STREX = (1 << 3), +++ ANDROID_CPU_ARM_FEATURE_VFPv2 = (1 << 4), +++ ANDROID_CPU_ARM_FEATURE_VFP_D32 = (1 << 5), +++ ANDROID_CPU_ARM_FEATURE_VFP_FP16 = (1 << 6), +++ ANDROID_CPU_ARM_FEATURE_VFP_FMA = (1 << 7), +++ ANDROID_CPU_ARM_FEATURE_NEON_FMA = (1 << 8), +++ ANDROID_CPU_ARM_FEATURE_IDIV_ARM = (1 << 9), +++ ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2 = (1 << 10), +++ ANDROID_CPU_ARM_FEATURE_iWMMXt = (1 << 11), +++ ANDROID_CPU_ARM_FEATURE_AES = (1 << 12), +++ ANDROID_CPU_ARM_FEATURE_PMULL = (1 << 13), +++ ANDROID_CPU_ARM_FEATURE_SHA1 = (1 << 14), +++ ANDROID_CPU_ARM_FEATURE_SHA2 = (1 << 15), +++ ANDROID_CPU_ARM_FEATURE_CRC32 = (1 << 16), +++}; +++ +++/* The bit flags corresponding to the output of android_getCpuFeatures() +++ * when android_getCpuFamily() returns ANDROID_CPU_FAMILY_ARM64. Value details +++ * are: +++ * +++ * FP: +++ * CPU has Floating-point unit. +++ * +++ * ASIMD: +++ * CPU has Advanced SIMD unit. +++ * +++ * AES: +++ * CPU supports AES instructions. +++ * +++ * CRC32: +++ * CPU supports CRC32 instructions. +++ * +++ * SHA2: +++ * CPU supports SHA2 instructions. +++ * +++ * SHA1: +++ * CPU supports SHA1 instructions. +++ * +++ * PMULL: +++ * CPU supports 64-bit PMULL and PMULL2 instructions. +++ */ +++enum { +++ ANDROID_CPU_ARM64_FEATURE_FP = (1 << 0), +++ ANDROID_CPU_ARM64_FEATURE_ASIMD = (1 << 1), +++ ANDROID_CPU_ARM64_FEATURE_AES = (1 << 2), +++ ANDROID_CPU_ARM64_FEATURE_PMULL = (1 << 3), +++ ANDROID_CPU_ARM64_FEATURE_SHA1 = (1 << 4), +++ ANDROID_CPU_ARM64_FEATURE_SHA2 = (1 << 5), +++ ANDROID_CPU_ARM64_FEATURE_CRC32 = (1 << 6), +++}; +++ +++/* The bit flags corresponding to the output of android_getCpuFeatures() +++ * when android_getCpuFamily() returns ANDROID_CPU_FAMILY_X86 or +++ * ANDROID_CPU_FAMILY_X86_64. +++ */ +++enum { +++ ANDROID_CPU_X86_FEATURE_SSSE3 = (1 << 0), +++ ANDROID_CPU_X86_FEATURE_POPCNT = (1 << 1), +++ ANDROID_CPU_X86_FEATURE_MOVBE = (1 << 2), +++ ANDROID_CPU_X86_FEATURE_SSE4_1 = (1 << 3), +++ ANDROID_CPU_X86_FEATURE_SSE4_2 = (1 << 4), +++ ANDROID_CPU_X86_FEATURE_AES_NI = (1 << 5), +++ ANDROID_CPU_X86_FEATURE_AVX = (1 << 6), +++ ANDROID_CPU_X86_FEATURE_RDRAND = (1 << 7), +++ ANDROID_CPU_X86_FEATURE_AVX2 = (1 << 8), +++ ANDROID_CPU_X86_FEATURE_SHA_NI = (1 << 9), +++}; +++ +++/* The bit flags corresponding to the output of android_getCpuFeatures() +++ * when android_getCpuFamily() returns ANDROID_CPU_FAMILY_MIPS +++ * or ANDROID_CPU_FAMILY_MIPS64. Values are: +++ * +++ * R6: +++ * CPU executes MIPS Release 6 instructions natively, and +++ * supports obsoleted R1..R5 instructions only via kernel traps. +++ * +++ * MSA: +++ * CPU supports Mips SIMD Architecture instructions. +++ */ +++enum { +++ ANDROID_CPU_MIPS_FEATURE_R6 = (1 << 0), +++ ANDROID_CPU_MIPS_FEATURE_MSA = (1 << 1), +++}; +++ +++/* Return the number of CPU cores detected on this device. +++ * Please note the current implementation supports up to 32 cpus. +++ */ +++extern int android_getCpuCount(void); +++ +++/* The following is used to force the CPU count and features +++ * mask in sandboxed processes. Under 4.1 and higher, these processes +++ * cannot access /proc, which is the only way to get information from +++ * the kernel about the current hardware (at least on ARM). +++ * +++ * It _must_ be called only once, and before any android_getCpuXXX +++ * function, any other case will fail. +++ * +++ * This function return 1 on success, and 0 on failure. +++ */ +++extern int android_setCpu(int cpu_count, uint64_t cpu_features); +++ +++#ifdef __arm__ +++ +++/* Retrieve the ARM 32-bit CPUID value from the kernel. +++ * Note that this cannot work on sandboxed processes under 4.1 and +++ * higher, unless you called android_setCpuArm() before. +++ */ +++extern uint32_t android_getCpuIdArm(void); +++ +++/* An ARM-specific variant of android_setCpu() that also allows you +++ * to set the ARM CPUID field. +++ */ +++extern int android_setCpuArm(int cpu_count, uint64_t cpu_features, +++ uint32_t cpu_id); +++ +++#endif +++ +++__END_DECLS +++#endif /* GOOGLE_CPU_FEATURES_H */ diff --cc cpu-features/ndk_compat/ndk-compat-test.c index 0000000,0000000,0000000..e4005d4 new file mode 100644 --- /dev/null +++ b/cpu-features/ndk_compat/ndk-compat-test.c @@@@ -1,0 -1,0 -1,0 +1,12 @@@@ +++#include +++ +++#include "cpu-features.h" +++ +++int main() { +++ printf("android_getCpuFamily()=%d\n", android_getCpuFamily()); +++ printf("android_getCpuFeatures()=0x%08llx\n", android_getCpuFeatures()); +++ printf("android_getCpuCount()=%d\n", android_getCpuCount()); +++#ifdef __arm__ +++ printf("android_getCpuIdArm()=0x%04x\n", android_getCpuIdArm()); +++#endif //__arm__ +++} diff --cc cpu-features/scripts/run_integration.sh index 0000000,0000000,0000000..fd88d60 new file mode 100755 --- /dev/null +++ b/cpu-features/scripts/run_integration.sh @@@@ -1,0 -1,0 -1,0 +1,209 @@@@ +++#!/usr/bin/env bash +++ +++readonly SCRIPT_FOLDER=$(cd -P -- "$(dirname -- "$0")" && pwd -P) +++readonly PROJECT_FOLDER="${SCRIPT_FOLDER}/.." +++readonly ARCHIVE_FOLDER=~/cpu_features_archives +++readonly QEMU_INSTALL=${ARCHIVE_FOLDER}/qemu +++readonly DEFAULT_CMAKE_ARGS=" -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON" +++ +++function extract() { +++ case $1 in +++ *.tar.bz2) tar xjf "$1" ;; +++ *.tar.xz) tar xJf "$1" ;; +++ *.tar.gz) tar xzf "$1" ;; +++ *) +++ echo "don't know how to extract '$1'..." +++ exit 1 +++ esac +++} +++ +++function unpackifnotexists() { +++ mkdir -p "${ARCHIVE_FOLDER}" +++ cd "${ARCHIVE_FOLDER}" || exit +++ local URL=$1 +++ local RELATIVE_FOLDER=$2 +++ local DESTINATION="${ARCHIVE_FOLDER}/${RELATIVE_FOLDER}" +++ if [[ ! -d "${DESTINATION}" ]] ; then +++ local ARCHIVE_NAME=$(echo ${URL} | sed 's/.*\///') +++ test -f "${ARCHIVE_NAME}" || wget -q "${URL}" +++ extract "${ARCHIVE_NAME}" +++ rm -f "${ARCHIVE_NAME}" +++ fi +++} +++ +++function installqemuifneeded() { +++ local VERSION=${QEMU_VERSION:=2.11.1} +++ local ARCHES=${QEMU_ARCHES:=arm aarch64 i386 x86_64 mips mipsel mips64 mips64el} +++ local TARGETS=${QEMU_TARGETS:=$(echo "$ARCHES" | sed 's#$# #;s#\([^ ]*\) #\1-linux-user #g')} +++ +++ if echo "${VERSION} ${TARGETS}" | cmp --silent ${QEMU_INSTALL}/.build -; then +++ echo "qemu ${VERSION} up to date!" +++ return 0 +++ fi +++ +++ echo "VERSION: ${VERSION}" +++ echo "TARGETS: ${TARGETS}" +++ +++ rm -rf ${QEMU_INSTALL} +++ +++ # Checking for a tarball before downloading makes testing easier :-) +++ local QEMU_URL="http://wiki.qemu-project.org/download/qemu-${VERSION}.tar.xz" +++ local QEMU_FOLDER="qemu-${VERSION}" +++ unpackifnotexists ${QEMU_URL} ${QEMU_FOLDER} +++ cd ${QEMU_FOLDER} || exit +++ +++ ./configure \ +++ --prefix="${QEMU_INSTALL}" \ +++ --target-list="${TARGETS}" \ +++ --disable-docs \ +++ --disable-sdl \ +++ --disable-gtk \ +++ --disable-gnutls \ +++ --disable-gcrypt \ +++ --disable-nettle \ +++ --disable-curses \ +++ --static +++ +++ make -j4 +++ make install +++ +++ echo "$VERSION $TARGETS" > ${QEMU_INSTALL}/.build +++} +++ +++function assert_defined(){ +++ local VALUE=${1} +++ : "${VALUE?"${1} needs to be defined"}" +++} +++ +++function integrate() { +++ cd "${PROJECT_FOLDER}" +++ case "${OS}" in +++ "Windows_NT") CMAKE_BUILD_ARGS="--config Debug --target ALL_BUILD" +++ CMAKE_TEST_FILES="${BUILD_DIR}/test/Debug/*_test.exe" +++ DEMO=${BUILD_DIR}/Debug/list_cpu_features.exe +++ ;; +++ *) CMAKE_BUILD_ARGS="--target all" +++ CMAKE_TEST_FILES="${BUILD_DIR}/test/*_test" +++ DEMO=${BUILD_DIR}/list_cpu_features +++ ;; +++ esac +++ +++ # Generating CMake configuration +++ cmake -H. -B"${BUILD_DIR}" ${DEFAULT_CMAKE_ARGS} "${CMAKE_ADDITIONAL_ARGS[@]}" -G"${CMAKE_GENERATOR:-Unix Makefiles}" +++ +++ # Building +++ cmake --build "${BUILD_DIR}" ${CMAKE_BUILD_ARGS} +++ +++ # Running tests if needed +++ if [[ "${QEMU_ARCH}" == "DISABLED" ]]; then +++ return +++ fi +++ RUN_CMD="" +++ if [[ -n "${QEMU_ARCH}" ]]; then +++ installqemuifneeded +++ RUN_CMD="${QEMU_INSTALL}/bin/qemu-${QEMU_ARCH} ${QEMU_ARGS[@]}" +++ fi +++ for test_binary in ${CMAKE_TEST_FILES}; do +++ ${RUN_CMD} ${test_binary} +++ done +++ ${RUN_CMD} ${DEMO} +++} +++ +++function expand_linaro_config() { +++ assert_defined TARGET +++ local LINARO_ROOT_URL=https://releases.linaro.org/components/toolchain/binaries/7.2-2017.11 +++ +++ local GCC_URL=${LINARO_ROOT_URL}/${TARGET}/gcc-linaro-7.2.1-2017.11-x86_64_${TARGET}.tar.xz +++ local GCC_RELATIVE_FOLDER="gcc-linaro-7.2.1-2017.11-x86_64_${TARGET}" +++ unpackifnotexists "${GCC_URL}" "${GCC_RELATIVE_FOLDER}" +++ +++ local SYSROOT_URL=${LINARO_ROOT_URL}/${TARGET}/sysroot-glibc-linaro-2.25-2017.11-${TARGET}.tar.xz +++ local SYSROOT_RELATIVE_FOLDER=sysroot-glibc-linaro-2.25-2017.11-${TARGET} +++ unpackifnotexists "${SYSROOT_URL}" "${SYSROOT_RELATIVE_FOLDER}" +++ +++ local SYSROOT_FOLDER=${ARCHIVE_FOLDER}/${SYSROOT_RELATIVE_FOLDER} +++ local GCC_FOLDER=${ARCHIVE_FOLDER}/${GCC_RELATIVE_FOLDER} +++ +++ CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSTEM_NAME=Linux) +++ CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSTEM_PROCESSOR=${TARGET}) +++ +++ CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSROOT=${SYSROOT_FOLDER}) +++ CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_C_COMPILER=${GCC_FOLDER}/bin/${TARGET}-gcc) +++ CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_CXX_COMPILER=${GCC_FOLDER}/bin/${TARGET}-g++) +++ +++ CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER) +++ CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY) +++ CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY) +++ +++ QEMU_ARGS+=(-L ${SYSROOT_FOLDER}) +++ QEMU_ARGS+=(-E LD_LIBRARY_PATH=/lib) +++} +++ +++function expand_codescape_config() { +++ assert_defined TARGET +++ local DATE=2017.10-08 +++ local CODESCAPE_URL=https://codescape.mips.com/components/toolchain/${DATE}/Codescape.GNU.Tools.Package.${DATE}.for.MIPS.MTI.Linux.CentOS-5.x86_64.tar.gz +++ local GCC_URL=${CODESCAPE_URL} +++ local GCC_RELATIVE_FOLDER="mips-mti-linux-gnu/${DATE}" +++ unpackifnotexists "${GCC_URL}" "${GCC_RELATIVE_FOLDER}" +++ +++ local GCC_FOLDER=${ARCHIVE_FOLDER}/${GCC_RELATIVE_FOLDER} +++ local MIPS_FLAGS="" +++ local LIBC_FOLDER_SUFFIX="" +++ local FLAVOUR="" +++ case "${TARGET}" in +++ "mips32") MIPS_FLAGS="-EB -mabi=32"; FLAVOUR="mips-r2-hard"; LIBC_FOLDER_SUFFIX="lib" ;; +++ "mips32el") MIPS_FLAGS="-EL -mabi=32"; FLAVOUR="mipsel-r2-hard"; LIBC_FOLDER_SUFFIX="lib" ;; +++ "mips64") MIPS_FLAGS="-EB -mabi=64"; FLAVOUR="mips-r2-hard"; LIBC_FOLDER_SUFFIX="lib64" ;; +++ "mips64el") MIPS_FLAGS="-EL -mabi=64"; FLAVOUR="mipsel-r2-hard"; LIBC_FOLDER_SUFFIX="lib64" ;; +++ *) echo 'unknown mips platform'; exit 1;; +++ esac +++ +++ CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_FIND_ROOT_PATH=${GCC_FOLDER}) +++ CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSTEM_NAME=Linux) +++ CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSTEM_PROCESSOR=${TARGET}) +++ CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_C_COMPILER=mips-mti-linux-gnu-gcc) +++ CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_CXX_COMPILER=mips-mti-linux-gnu-g++) +++ CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_C_COMPILER_ARG1="${MIPS_FLAGS}") +++ CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_CXX_COMPILER_ARG1="${MIPS_FLAGS}") +++ +++ local SYSROOT_FOLDER=${GCC_FOLDER}/sysroot/${FLAVOUR} +++ +++ # Keeping only the sysroot of interest to save on travis cache. +++ if [[ "${CONTINUOUS_INTEGRATION}" = "true" ]]; then +++ for folder in ${GCC_FOLDER}/sysroot/*; do +++ if [[ "${folder}" != "${SYSROOT_FOLDER}" ]]; then +++ rm -rf ${folder} +++ fi +++ done +++ fi +++ +++ local LIBC_FOLDER=${GCC_FOLDER}/mips-mti-linux-gnu/lib/${FLAVOUR}/${LIBC_FOLDER_SUFFIX} +++ QEMU_ARGS+=(-L ${SYSROOT_FOLDER}) +++ QEMU_ARGS+=(-E LD_PRELOAD=${LIBC_FOLDER}/libstdc++.so.6:${LIBC_FOLDER}/libgcc_s.so.1) +++} +++ +++function expand_environment_and_integrate() { +++ assert_defined PROJECT_FOLDER +++ assert_defined TARGET +++ +++ BUILD_DIR="${PROJECT_FOLDER}/cmake_build/${TARGET}" +++ mkdir -p "${BUILD_DIR}" +++ +++ declare -a CONFIG_NAMES=() +++ declare -a QEMU_ARGS=() +++ declare -a CMAKE_ADDITIONAL_ARGS=() +++ +++ case ${TOOLCHAIN} in +++ LINARO) expand_linaro_config ;; +++ CODESCAPE) expand_codescape_config ;; +++ NATIVE) QEMU_ARCH="" ;; +++ *) echo "Unknown toolchain '${TOOLCHAIN}'..."; exit 1;; +++ esac +++ integrate +++} +++ +++if [ "${CONTINUOUS_INTEGRATION}" = "true" ]; then +++ QEMU_ARCHES=${QEMU_ARCH} +++ expand_environment_and_integrate +++fi diff --cc cpu-features/scripts/test_integration.sh index 0000000,0000000,0000000..d1c61b0 new file mode 100755 --- /dev/null +++ b/cpu-features/scripts/test_integration.sh @@@@ -1,0 -1,0 -1,0 +1,106 @@@@ +++#!/usr/bin/env bash +++ +++source "$(dirname -- "$0")"/run_integration.sh +++ +++# Toolchains for little-endian, 64-bit ARMv8 for GNU/Linux systems +++function set_aarch64-linux-gnu() { +++ TOOLCHAIN=LINARO +++ TARGET=aarch64-linux-gnu +++ QEMU_ARCH=aarch64 +++} +++ +++# Toolchains for little-endian, hard-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems +++function set_arm-linux-gnueabihf() { +++ TOOLCHAIN=LINARO +++ TARGET=arm-linux-gnueabihf +++ QEMU_ARCH=arm +++} +++ +++# Toolchains for little-endian, 32-bit ARMv8 for GNU/Linux systems +++function set_armv8l-linux-gnueabihf() { +++ TOOLCHAIN=LINARO +++ TARGET=armv8l-linux-gnueabihf +++ QEMU_ARCH=arm +++} +++ +++# Toolchains for little-endian, soft-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems +++function set_arm-linux-gnueabi() { +++ TOOLCHAIN=LINARO +++ TARGET=arm-linux-gnueabi +++ QEMU_ARCH=arm +++} +++ +++# Toolchains for big-endian, 64-bit ARMv8 for GNU/Linux systems +++function set_aarch64_be-linux-gnu() { +++ TOOLCHAIN=LINARO +++ TARGET=aarch64_be-linux-gnu +++ QEMU_ARCH=DISABLED +++} +++ +++# Toolchains for big-endian, hard-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems +++function set_armeb-linux-gnueabihf() { +++ TOOLCHAIN=LINARO +++ TARGET=armeb-linux-gnueabihf +++ QEMU_ARCH=DISABLED +++} +++ +++# Toolchains for big-endian, soft-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems +++function set_armeb-linux-gnueabi() { +++ TOOLCHAIN=LINARO +++ TARGET=armeb-linux-gnueabi +++ QEMU_ARCH=DISABLED +++} +++ +++function set_mips32() { +++ TOOLCHAIN=CODESCAPE +++ TARGET=mips32 +++ QEMU_ARCH=mips +++} +++ +++function set_mips32el() { +++ TOOLCHAIN=CODESCAPE +++ TARGET=mips32el +++ QEMU_ARCH=mipsel +++} +++ +++function set_mips64() { +++ TOOLCHAIN=CODESCAPE +++ TARGET=mips64 +++ QEMU_ARCH=mips64 +++} +++ +++function set_mips64el() { +++ TOOLCHAIN=CODESCAPE +++ TARGET=mips64el +++ QEMU_ARCH=mips64el +++} +++ +++function set_native() { +++ TOOLCHAIN=NATIVE +++ TARGET=native +++ QEMU_ARCH="" +++} +++ +++ENVIRONMENTS=" +++ set_aarch64-linux-gnu +++ set_arm-linux-gnueabihf +++ set_armv8l-linux-gnueabihf +++ set_arm-linux-gnueabi +++ set_aarch64_be-linux-gnu +++ set_armeb-linux-gnueabihf +++ set_armeb-linux-gnueabi +++ set_mips32 +++ set_mips32el +++ set_mips64 +++ set_mips64el +++ set_native +++" +++ +++set -e +++ +++CMAKE_GENERATOR="Ninja" +++ +++for SET_ENVIRONMENT in ${ENVIRONMENTS}; do +++ ${SET_ENVIRONMENT} +++ expand_environment_and_integrate +++done diff --cc cpu-features/src/cpuinfo_aarch64.c index 0000000,0000000,0000000..0a52718 new file mode 100644 --- /dev/null +++ b/cpu-features/src/cpuinfo_aarch64.c @@@@ -1,0 -1,0 -1,0 +1,150 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#include "cpuinfo_aarch64.h" +++ +++#include +++#include +++ +++#include "internal/filesystem.h" +++#include "internal/hwcaps.h" +++#include "internal/stack_line_reader.h" +++#include "internal/string_view.h" +++ +++// Generation of feature's getters/setters functions and kGetters, kSetters, +++// kCpuInfoFlags and kHardwareCapabilities global tables. +++#define DEFINE_TABLE_FEATURES \ +++ FEATURE(AARCH64_FP, fp, "fp", AARCH64_HWCAP_FP, 0) \ +++ FEATURE(AARCH64_ASIMD, asimd, "asimd", AARCH64_HWCAP_ASIMD, 0) \ +++ FEATURE(AARCH64_EVTSTRM, evtstrm, "evtstrm", AARCH64_HWCAP_EVTSTRM, 0) \ +++ FEATURE(AARCH64_AES, aes, "aes", AARCH64_HWCAP_AES, 0) \ +++ FEATURE(AARCH64_PMULL, pmull, "pmull", AARCH64_HWCAP_PMULL, 0) \ +++ FEATURE(AARCH64_SHA1, sha1, "sha1", AARCH64_HWCAP_SHA1, 0) \ +++ FEATURE(AARCH64_SHA2, sha2, "sha2", AARCH64_HWCAP_SHA2, 0) \ +++ FEATURE(AARCH64_CRC32, crc32, "crc32", AARCH64_HWCAP_CRC32, 0) \ +++ FEATURE(AARCH64_ATOMICS, atomics, "atomics", AARCH64_HWCAP_ATOMICS, 0) \ +++ FEATURE(AARCH64_FPHP, fphp, "fphp", AARCH64_HWCAP_FPHP, 0) \ +++ FEATURE(AARCH64_ASIMDHP, asimdhp, "asimdhp", AARCH64_HWCAP_ASIMDHP, 0) \ +++ FEATURE(AARCH64_CPUID, cpuid, "cpuid", AARCH64_HWCAP_CPUID, 0) \ +++ FEATURE(AARCH64_ASIMDRDM, asimdrdm, "asimdrdm", AARCH64_HWCAP_ASIMDRDM, 0) \ +++ FEATURE(AARCH64_JSCVT, jscvt, "jscvt", AARCH64_HWCAP_JSCVT, 0) \ +++ FEATURE(AARCH64_FCMA, fcma, "fcma", AARCH64_HWCAP_FCMA, 0) \ +++ FEATURE(AARCH64_LRCPC, lrcpc, "lrcpc", AARCH64_HWCAP_LRCPC, 0) \ +++ FEATURE(AARCH64_DCPOP, dcpop, "dcpop", AARCH64_HWCAP_DCPOP, 0) \ +++ FEATURE(AARCH64_SHA3, sha3, "sha3", AARCH64_HWCAP_SHA3, 0) \ +++ FEATURE(AARCH64_SM3, sm3, "sm3", AARCH64_HWCAP_SM3, 0) \ +++ FEATURE(AARCH64_SM4, sm4, "sm4", AARCH64_HWCAP_SM4, 0) \ +++ FEATURE(AARCH64_ASIMDDP, asimddp, "asimddp", AARCH64_HWCAP_ASIMDDP, 0) \ +++ FEATURE(AARCH64_SHA512, sha512, "sha512", AARCH64_HWCAP_SHA512, 0) \ +++ FEATURE(AARCH64_SVE, sve, "sve", AARCH64_HWCAP_SVE, 0) \ +++ FEATURE(AARCH64_ASIMDFHM, asimdfhm, "asimdfhm", AARCH64_HWCAP_ASIMDFHM, 0) \ +++ FEATURE(AARCH64_DIT, dit, "dit", AARCH64_HWCAP_DIT, 0) \ +++ FEATURE(AARCH64_USCAT, uscat, "uscat", AARCH64_HWCAP_USCAT, 0) \ +++ FEATURE(AARCH64_ILRCPC, ilrcpc, "ilrcpc", AARCH64_HWCAP_ILRCPC, 0) \ +++ FEATURE(AARCH64_FLAGM, flagm, "flagm", AARCH64_HWCAP_FLAGM, 0) \ +++ FEATURE(AARCH64_SSBS, ssbs, "ssbs", AARCH64_HWCAP_SSBS, 0) \ +++ FEATURE(AARCH64_SB, sb, "sb", AARCH64_HWCAP_SB, 0) \ +++ FEATURE(AARCH64_PACA, paca, "paca", AARCH64_HWCAP_PACA, 0) \ +++ FEATURE(AARCH64_PACG, pacg, "pacg", AARCH64_HWCAP_PACG, 0) \ +++ FEATURE(AARCH64_DCPODP, dcpodp, "dcpodp", 0, AARCH64_HWCAP2_DCPODP) \ +++ FEATURE(AARCH64_SVE2, sve2, "sve2", 0, AARCH64_HWCAP2_SVE2) \ +++ FEATURE(AARCH64_SVEAES, sveaes, "sveaes", 0, AARCH64_HWCAP2_SVEAES) \ +++ FEATURE(AARCH64_SVEPMULL, svepmull, "svepmull", 0, AARCH64_HWCAP2_SVEPMULL) \ +++ FEATURE(AARCH64_SVEBITPERM, svebitperm, "svebitperm", 0, \ +++ AARCH64_HWCAP2_SVEBITPERM) \ +++ FEATURE(AARCH64_SVESHA3, svesha3, "svesha3", 0, AARCH64_HWCAP2_SVESHA3) \ +++ FEATURE(AARCH64_SVESM4, svesm4, "svesm4", 0, AARCH64_HWCAP2_SVESM4) \ +++ FEATURE(AARCH64_FLAGM2, flagm2, "flagm2", 0, AARCH64_HWCAP2_FLAGM2) \ +++ FEATURE(AARCH64_FRINT, frint, "frint", 0, AARCH64_HWCAP2_FRINT) \ +++ FEATURE(AARCH64_SVEI8MM, svei8mm, "svei8mm", 0, AARCH64_HWCAP2_SVEI8MM) \ +++ FEATURE(AARCH64_SVEF32MM, svef32mm, "svef32mm", 0, AARCH64_HWCAP2_SVEF32MM) \ +++ FEATURE(AARCH64_SVEF64MM, svef64mm, "svef64mm", 0, AARCH64_HWCAP2_SVEF64MM) \ +++ FEATURE(AARCH64_SVEBF16, svebf16, "svebf16", 0, AARCH64_HWCAP2_SVEBF16) \ +++ FEATURE(AARCH64_I8MM, i8mm, "i8mm", 0, AARCH64_HWCAP2_I8MM) \ +++ FEATURE(AARCH64_BF16, bf16, "bf16", 0, AARCH64_HWCAP2_BF16) \ +++ FEATURE(AARCH64_DGH, dgh, "dgh", 0, AARCH64_HWCAP2_DGH) \ +++ FEATURE(AARCH64_RNG, rng, "rng", 0, AARCH64_HWCAP2_RNG) \ +++ FEATURE(AARCH64_BTI, bti, "bti", 0, AARCH64_HWCAP2_BTI) +++#define DEFINE_TABLE_FEATURE_TYPE Aarch64Features +++#include "define_tables.h" +++ +++static bool HandleAarch64Line(const LineResult result, +++ Aarch64Info* const info) { +++ StringView line = result.line; +++ StringView key, value; +++ if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) { +++ if (CpuFeatures_StringView_IsEquals(key, str("Features"))) { +++ for (size_t i = 0; i < AARCH64_LAST_; ++i) { +++ kSetters[i](&info->features, +++ CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i])); +++ } +++ } else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) { +++ info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value); +++ } else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) { +++ info->variant = CpuFeatures_StringView_ParsePositiveNumber(value); +++ } else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) { +++ info->part = CpuFeatures_StringView_ParsePositiveNumber(value); +++ } else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) { +++ info->revision = CpuFeatures_StringView_ParsePositiveNumber(value); +++ } +++ } +++ return !result.eof; +++} +++ +++static void FillProcCpuInfoData(Aarch64Info* const info) { +++ const int fd = CpuFeatures_OpenFile("/proc/cpuinfo"); +++ if (fd >= 0) { +++ StackLineReader reader; +++ StackLineReader_Initialize(&reader, fd); +++ for (;;) { +++ if (!HandleAarch64Line(StackLineReader_NextLine(&reader), info)) { +++ break; +++ } +++ } +++ CpuFeatures_CloseFile(fd); +++ } +++} +++ +++static const Aarch64Info kEmptyAarch64Info; +++ +++Aarch64Info GetAarch64Info(void) { +++ // capabilities are fetched from both getauxval and /proc/cpuinfo so we can +++ // have some information if the executable is sandboxed (aka no access to +++ // /proc/cpuinfo). +++ Aarch64Info info = kEmptyAarch64Info; +++ +++ FillProcCpuInfoData(&info); +++ const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities(); +++ for (size_t i = 0; i < AARCH64_LAST_; ++i) { +++ if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) { +++ kSetters[i](&info.features, true); +++ } +++ } +++ +++ return info; +++} +++ +++//////////////////////////////////////////////////////////////////////////////// +++// Introspection functions +++ +++int GetAarch64FeaturesEnumValue(const Aarch64Features* features, +++ Aarch64FeaturesEnum value) { +++ if (value >= AARCH64_LAST_) return false; +++ return kGetters[value](features); +++} +++ +++const char* GetAarch64FeaturesEnumName(Aarch64FeaturesEnum value) { +++ if (value >= AARCH64_LAST_) return "unknown feature"; +++ return kCpuInfoFlags[value]; +++} diff --cc cpu-features/src/cpuinfo_arm.c index 0000000,0000000,0000000..0f216bf new file mode 100644 --- /dev/null +++ b/cpu-features/src/cpuinfo_arm.c @@@@ -1,0 -1,0 -1,0 +1,212 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#include "cpuinfo_arm.h" +++ +++#include +++#include +++ +++#include "internal/bit_utils.h" +++#include "internal/filesystem.h" +++#include "internal/hwcaps.h" +++#include "internal/stack_line_reader.h" +++#include "internal/string_view.h" +++ +++// Generation of feature's getters/setters functions and kGetters, kSetters, +++// kCpuInfoFlags and kHardwareCapabilities global tables. +++#define DEFINE_TABLE_FEATURES \ +++ FEATURE(ARM_SWP, swp, "swp", ARM_HWCAP_SWP, 0) \ +++ FEATURE(ARM_HALF, half, "half", ARM_HWCAP_HALF, 0) \ +++ FEATURE(ARM_THUMB, thumb, "thumb", ARM_HWCAP_THUMB, 0) \ +++ FEATURE(ARM_26BIT, _26bit, "26bit", ARM_HWCAP_26BIT, 0) \ +++ FEATURE(ARM_FASTMULT, fastmult, "fastmult", ARM_HWCAP_FAST_MULT, 0) \ +++ FEATURE(ARM_FPA, fpa, "fpa", ARM_HWCAP_FPA, 0) \ +++ FEATURE(ARM_VFP, vfp, "vfp", ARM_HWCAP_VFP, 0) \ +++ FEATURE(ARM_EDSP, edsp, "edsp", ARM_HWCAP_EDSP, 0) \ +++ FEATURE(ARM_JAVA, java, "java", ARM_HWCAP_JAVA, 0) \ +++ FEATURE(ARM_IWMMXT, iwmmxt, "iwmmxt", ARM_HWCAP_IWMMXT, 0) \ +++ FEATURE(ARM_CRUNCH, crunch, "crunch", ARM_HWCAP_CRUNCH, 0) \ +++ FEATURE(ARM_THUMBEE, thumbee, "thumbee", ARM_HWCAP_THUMBEE, 0) \ +++ FEATURE(ARM_NEON, neon, "neon", ARM_HWCAP_NEON, 0) \ +++ FEATURE(ARM_VFPV3, vfpv3, "vfpv3", ARM_HWCAP_VFPV3, 0) \ +++ FEATURE(ARM_VFPV3D16, vfpv3d16, "vfpv3d16", ARM_HWCAP_VFPV3D16, 0) \ +++ FEATURE(ARM_TLS, tls, "tls", ARM_HWCAP_TLS, 0) \ +++ FEATURE(ARM_VFPV4, vfpv4, "vfpv4", ARM_HWCAP_VFPV4, 0) \ +++ FEATURE(ARM_IDIVA, idiva, "idiva", ARM_HWCAP_IDIVA, 0) \ +++ FEATURE(ARM_IDIVT, idivt, "idivt", ARM_HWCAP_IDIVT, 0) \ +++ FEATURE(ARM_VFPD32, vfpd32, "vfpd32", ARM_HWCAP_VFPD32, 0) \ +++ FEATURE(ARM_LPAE, lpae, "lpae", ARM_HWCAP_LPAE, 0) \ +++ FEATURE(ARM_EVTSTRM, evtstrm, "evtstrm", ARM_HWCAP_EVTSTRM, 0) \ +++ FEATURE(ARM_AES, aes, "aes", 0, ARM_HWCAP2_AES) \ +++ FEATURE(ARM_PMULL, pmull, "pmull", 0, ARM_HWCAP2_PMULL) \ +++ FEATURE(ARM_SHA1, sha1, "sha1", 0, ARM_HWCAP2_SHA1) \ +++ FEATURE(ARM_SHA2, sha2, "sha2", 0, ARM_HWCAP2_SHA2) \ +++ FEATURE(ARM_CRC32, crc32, "crc32", 0, ARM_HWCAP2_CRC32) +++#define DEFINE_TABLE_FEATURE_TYPE ArmFeatures +++#include "define_tables.h" +++ +++typedef struct { +++ bool processor_reports_armv6; +++ bool hardware_reports_goldfish; +++} ProcCpuInfoData; +++ +++static int IndexOfNonDigit(StringView str) { +++ size_t index = 0; +++ while (str.size && isdigit(CpuFeatures_StringView_Front(str))) { +++ str = CpuFeatures_StringView_PopFront(str, 1); +++ ++index; +++ } +++ return index; +++} +++ +++static bool HandleArmLine(const LineResult result, ArmInfo* const info, +++ ProcCpuInfoData* const proc_info) { +++ StringView line = result.line; +++ StringView key, value; +++ if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) { +++ if (CpuFeatures_StringView_IsEquals(key, str("Features"))) { +++ for (size_t i = 0; i < ARM_LAST_; ++i) { +++ kSetters[i](&info->features, +++ CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i])); +++ } +++ } else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) { +++ info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value); +++ } else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) { +++ info->variant = CpuFeatures_StringView_ParsePositiveNumber(value); +++ } else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) { +++ info->part = CpuFeatures_StringView_ParsePositiveNumber(value); +++ } else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) { +++ info->revision = CpuFeatures_StringView_ParsePositiveNumber(value); +++ } else if (CpuFeatures_StringView_IsEquals(key, str("CPU architecture"))) { +++ // CPU architecture is a number that may be followed by letters. e.g. +++ // "6TEJ", "7". +++ const StringView digits = +++ CpuFeatures_StringView_KeepFront(value, IndexOfNonDigit(value)); +++ info->architecture = CpuFeatures_StringView_ParsePositiveNumber(digits); +++ } else if (CpuFeatures_StringView_IsEquals(key, str("Processor")) || +++ CpuFeatures_StringView_IsEquals(key, str("model name"))) { +++ // Android reports this in a non-Linux standard "Processor" but sometimes +++ // also in "model name", Linux reports it only in "model name" +++ // see RaspberryPiZero (Linux) vs InvalidArmv7 (Android) test-cases +++ proc_info->processor_reports_armv6 = +++ CpuFeatures_StringView_IndexOf(value, str("(v6l)")) >= 0; +++ } else if (CpuFeatures_StringView_IsEquals(key, str("Hardware"))) { +++ proc_info->hardware_reports_goldfish = +++ CpuFeatures_StringView_IsEquals(value, str("Goldfish")); +++ } +++ } +++ return !result.eof; +++} +++ +++uint32_t GetArmCpuId(const ArmInfo* const info) { +++ return (ExtractBitRange(info->implementer, 7, 0) << 24) | +++ (ExtractBitRange(info->variant, 3, 0) << 20) | +++ (ExtractBitRange(info->part, 11, 0) << 4) | +++ (ExtractBitRange(info->revision, 3, 0) << 0); +++} +++ +++static void FixErrors(ArmInfo* const info, +++ ProcCpuInfoData* const proc_cpu_info_data) { +++ // Fixing Samsung kernel reporting invalid cpu architecture. +++ // http://code.google.com/p/android/issues/detail?id=10812 +++ if (proc_cpu_info_data->processor_reports_armv6 && info->architecture >= 7) { +++ info->architecture = 6; +++ } +++ +++ // Handle kernel configuration bugs that prevent the correct reporting of CPU +++ // features. +++ switch (GetArmCpuId(info)) { +++ case 0x4100C080: +++ // Special case: The emulator-specific Android 4.2 kernel fails to report +++ // support for the 32-bit ARM IDIV instruction. Technically, this is a +++ // feature of the virtual CPU implemented by the emulator. Note that it +++ // could also support Thumb IDIV in the future, and this will have to be +++ // slightly updated. +++ if (info->architecture >= 7 && +++ proc_cpu_info_data->hardware_reports_goldfish) { +++ info->features.idiva = true; +++ } +++ break; +++ case 0x511004D0: +++ // https://crbug.com/341598. +++ info->features.neon = false; +++ break; +++ case 0x510006F2: +++ case 0x510006F3: +++ // The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report +++ // IDIV support. +++ info->features.idiva = true; +++ info->features.idivt = true; +++ break; +++ } +++ +++ // Propagate cpu features. +++ if (info->features.vfpv4) info->features.vfpv3 = true; +++ if (info->features.neon) info->features.vfpv3 = true; +++ if (info->features.vfpv3) info->features.vfp = true; +++} +++ +++static void FillProcCpuInfoData(ArmInfo* const info, +++ ProcCpuInfoData* proc_cpu_info_data) { +++ const int fd = CpuFeatures_OpenFile("/proc/cpuinfo"); +++ if (fd >= 0) { +++ StackLineReader reader; +++ StackLineReader_Initialize(&reader, fd); +++ for (;;) { +++ if (!HandleArmLine(StackLineReader_NextLine(&reader), info, +++ proc_cpu_info_data)) { +++ break; +++ } +++ } +++ CpuFeatures_CloseFile(fd); +++ } +++} +++ +++static const ArmInfo kEmptyArmInfo; +++ +++static const ProcCpuInfoData kEmptyProcCpuInfoData; +++ +++ArmInfo GetArmInfo(void) { +++ // capabilities are fetched from both getauxval and /proc/cpuinfo so we can +++ // have some information if the executable is sandboxed (aka no access to +++ // /proc/cpuinfo). +++ ArmInfo info = kEmptyArmInfo; +++ ProcCpuInfoData proc_cpu_info_data = kEmptyProcCpuInfoData; +++ +++ FillProcCpuInfoData(&info, &proc_cpu_info_data); +++ const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities(); +++ for (size_t i = 0; i < ARM_LAST_; ++i) { +++ if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) { +++ kSetters[i](&info.features, true); +++ } +++ } +++ +++ FixErrors(&info, &proc_cpu_info_data); +++ +++ return info; +++} +++ +++//////////////////////////////////////////////////////////////////////////////// +++// Introspection functions +++ +++int GetArmFeaturesEnumValue(const ArmFeatures* features, +++ ArmFeaturesEnum value) { +++ if (value >= ARM_LAST_) return false; +++ return kGetters[value](features); +++} +++ +++const char* GetArmFeaturesEnumName(ArmFeaturesEnum value) { +++ if (value >= ARM_LAST_) return "unknown feature"; +++ return kCpuInfoFlags[value]; +++} diff --cc cpu-features/src/cpuinfo_mips.c index 0000000,0000000,0000000..83e959f new file mode 100644 --- /dev/null +++ b/cpu-features/src/cpuinfo_mips.c @@@@ -1,0 -1,0 -1,0 +1,92 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#include "cpuinfo_mips.h" +++ +++#include +++ +++#include "internal/filesystem.h" +++#include "internal/hwcaps.h" +++#include "internal/stack_line_reader.h" +++#include "internal/string_view.h" +++ +++// Generation of feature's getters/setters functions and kGetters, kSetters, +++// kCpuInfoFlags and kHardwareCapabilities global tables. +++#define DEFINE_TABLE_FEATURES \ +++ FEATURE(MIPS_MSA, msa, "msa", MIPS_HWCAP_MSA, 0) \ +++ FEATURE(MIPS_EVA, eva, "eva", 0, 0) \ +++ FEATURE(MIPS_R6, r6, "r6", MIPS_HWCAP_R6, 0) +++#define DEFINE_TABLE_FEATURE_TYPE MipsFeatures +++#include "define_tables.h" +++ +++static bool HandleMipsLine(const LineResult result, +++ MipsFeatures* const features) { +++ StringView key, value; +++ // See tests for an example. +++ if (CpuFeatures_StringView_GetAttributeKeyValue(result.line, &key, &value)) { +++ if (CpuFeatures_StringView_IsEquals(key, str("ASEs implemented"))) { +++ for (size_t i = 0; i < MIPS_LAST_; ++i) { +++ kSetters[i](features, +++ CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i])); +++ } +++ } +++ } +++ return !result.eof; +++} +++ +++static void FillProcCpuInfoData(MipsFeatures* const features) { +++ const int fd = CpuFeatures_OpenFile("/proc/cpuinfo"); +++ if (fd >= 0) { +++ StackLineReader reader; +++ StackLineReader_Initialize(&reader, fd); +++ for (;;) { +++ if (!HandleMipsLine(StackLineReader_NextLine(&reader), features)) { +++ break; +++ } +++ } +++ CpuFeatures_CloseFile(fd); +++ } +++} +++ +++static const MipsInfo kEmptyMipsInfo; +++ +++MipsInfo GetMipsInfo(void) { +++ // capabilities are fetched from both getauxval and /proc/cpuinfo so we can +++ // have some information if the executable is sandboxed (aka no access to +++ // /proc/cpuinfo). +++ MipsInfo info = kEmptyMipsInfo; +++ +++ FillProcCpuInfoData(&info.features); +++ const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities(); +++ for (size_t i = 0; i < MIPS_LAST_; ++i) { +++ if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) { +++ kSetters[i](&info.features, true); +++ } +++ } +++ return info; +++} +++ +++//////////////////////////////////////////////////////////////////////////////// +++// Introspection functions +++ +++int GetMipsFeaturesEnumValue(const MipsFeatures* features, +++ MipsFeaturesEnum value) { +++ if (value >= MIPS_LAST_) return false; +++ return kGetters[value](features); +++} +++ +++const char* GetMipsFeaturesEnumName(MipsFeaturesEnum value) { +++ if (value >= MIPS_LAST_) return "unknown feature"; +++ return kCpuInfoFlags[value]; +++} diff --cc cpu-features/src/cpuinfo_ppc.c index 0000000,0000000,0000000..24401f9 new file mode 100644 --- /dev/null +++ b/cpu-features/src/cpuinfo_ppc.c @@@@ -1,0 -1,0 -1,0 +1,154 @@@@ +++// Copyright 2018 IBM. +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#include "cpuinfo_ppc.h" +++ +++#include +++#include +++#include +++ +++#include "internal/bit_utils.h" +++#include "internal/filesystem.h" +++#include "internal/stack_line_reader.h" +++#include "internal/string_view.h" +++ +++// Generation of feature's getters/setters functions and kGetters, kSetters, +++// kCpuInfoFlags and kHardwareCapabilities global tables. +++#define DEFINE_TABLE_FEATURES \ +++ FEATURE(PPC_32, ppc32, "ppc32", PPC_FEATURE_32, 0) \ +++ FEATURE(PPC_64, ppc64, "ppc64", PPC_FEATURE_64, 0) \ +++ FEATURE(PPC_601_INSTR, ppc601, "ppc601", PPC_FEATURE_601_INSTR, 0) \ +++ FEATURE(PPC_HAS_ALTIVEC, altivec, "altivec", PPC_FEATURE_HAS_ALTIVEC, 0) \ +++ FEATURE(PPC_HAS_FPU, fpu, "fpu", PPC_FEATURE_HAS_FPU, 0) \ +++ FEATURE(PPC_HAS_MMU, mmu, "mmu", PPC_FEATURE_HAS_MMU, 0) \ +++ FEATURE(PPC_HAS_4xxMAC, mac_4xx, "4xxmac", PPC_FEATURE_HAS_4xxMAC, 0) \ +++ FEATURE(PPC_UNIFIED_CACHE, unifiedcache, "ucache", \ +++ PPC_FEATURE_UNIFIED_CACHE, 0) \ +++ FEATURE(PPC_HAS_SPE, spe, "spe", PPC_FEATURE_HAS_SPE, 0) \ +++ FEATURE(PPC_HAS_EFP_SINGLE, efpsingle, "efpsingle", \ +++ PPC_FEATURE_HAS_EFP_SINGLE, 0) \ +++ FEATURE(PPC_HAS_EFP_DOUBLE, efpdouble, "efpdouble", \ +++ PPC_FEATURE_HAS_EFP_DOUBLE, 0) \ +++ FEATURE(PPC_NO_TB, no_tb, "notb", PPC_FEATURE_NO_TB, 0) \ +++ FEATURE(PPC_POWER4, power4, "power4", PPC_FEATURE_POWER4, 0) \ +++ FEATURE(PPC_POWER5, power5, "power5", PPC_FEATURE_POWER5, 0) \ +++ FEATURE(PPC_POWER5_PLUS, power5plus, "power5+", PPC_FEATURE_POWER5_PLUS, 0) \ +++ FEATURE(PPC_CELL, cell, "cellbe", PPC_FEATURE_CELL, 0) \ +++ FEATURE(PPC_BOOKE, booke, "booke", PPC_FEATURE_BOOKE, 0) \ +++ FEATURE(PPC_SMT, smt, "smt", PPC_FEATURE_SMT, 0) \ +++ FEATURE(PPC_ICACHE_SNOOP, icachesnoop, "ic_snoop", PPC_FEATURE_ICACHE_SNOOP, \ +++ 0) \ +++ FEATURE(PPC_ARCH_2_05, arch205, "arch_2_05", PPC_FEATURE_ARCH_2_05, 0) \ +++ FEATURE(PPC_PA6T, pa6t, "pa6t", PPC_FEATURE_PA6T, 0) \ +++ FEATURE(PPC_HAS_DFP, dfp, "dfp", PPC_FEATURE_HAS_DFP, 0) \ +++ FEATURE(PPC_POWER6_EXT, power6ext, "power6x", PPC_FEATURE_POWER6_EXT, 0) \ +++ FEATURE(PPC_ARCH_2_06, arch206, "arch_2_06", PPC_FEATURE_ARCH_2_06, 0) \ +++ FEATURE(PPC_HAS_VSX, vsx, "vsx", PPC_FEATURE_HAS_VSX, 0) \ +++ FEATURE(PPC_PSERIES_PERFMON_COMPAT, pseries_perfmon_compat, "archpmu", \ +++ PPC_FEATURE_PSERIES_PERFMON_COMPAT, 0) \ +++ FEATURE(PPC_TRUE_LE, truele, "true_le", PPC_FEATURE_TRUE_LE, 0) \ +++ FEATURE(PPC_PPC_LE, ppcle, "ppcle", PPC_FEATURE_PPC_LE, 0) \ +++ FEATURE(PPC_ARCH_2_07, arch207, "arch_2_07", 0, PPC_FEATURE2_ARCH_2_07) \ +++ FEATURE(PPC_HTM, htm, "htm", 0, PPC_FEATURE2_HTM) \ +++ FEATURE(PPC_DSCR, dscr, "dscr", 0, PPC_FEATURE2_DSCR) \ +++ FEATURE(PPC_EBB, ebb, "ebb", 0, PPC_FEATURE2_EBB) \ +++ FEATURE(PPC_ISEL, isel, "isel", 0, PPC_FEATURE2_ISEL) \ +++ FEATURE(PPC_TAR, tar, "tar", 0, PPC_FEATURE2_TAR) \ +++ FEATURE(PPC_VEC_CRYPTO, vcrypto, "vcrypto", 0, PPC_FEATURE2_VEC_CRYPTO) \ +++ FEATURE(PPC_HTM_NOSC, htm_nosc, "htm-nosc", 0, PPC_FEATURE2_HTM_NOSC) \ +++ FEATURE(PPC_ARCH_3_00, arch300, "arch_3_00", 0, PPC_FEATURE2_ARCH_3_00) \ +++ FEATURE(PPC_HAS_IEEE128, ieee128, "ieee128", 0, PPC_FEATURE2_HAS_IEEE128) \ +++ FEATURE(PPC_DARN, darn, "darn", 0, PPC_FEATURE2_DARN) \ +++ FEATURE(PPC_SCV, scv, "scv", 0, PPC_FEATURE2_SCV) \ +++ FEATURE(PPC_HTM_NO_SUSPEND, htm_no_suspend, "htm-no-suspend", 0, \ +++ PPC_FEATURE2_HTM_NO_SUSPEND) +++#define DEFINE_TABLE_FEATURE_TYPE PPCFeatures +++#include "define_tables.h" +++ +++static bool HandlePPCLine(const LineResult result, +++ PPCPlatformStrings* const strings) { +++ StringView line = result.line; +++ StringView key, value; +++ if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) { +++ if (CpuFeatures_StringView_HasWord(key, "platform")) { +++ CpuFeatures_StringView_CopyString(value, strings->platform, +++ sizeof(strings->platform)); +++ } else if (CpuFeatures_StringView_IsEquals(key, str("model"))) { +++ CpuFeatures_StringView_CopyString(value, strings->model, +++ sizeof(strings->platform)); +++ } else if (CpuFeatures_StringView_IsEquals(key, str("machine"))) { +++ CpuFeatures_StringView_CopyString(value, strings->machine, +++ sizeof(strings->platform)); +++ } else if (CpuFeatures_StringView_IsEquals(key, str("cpu"))) { +++ CpuFeatures_StringView_CopyString(value, strings->cpu, +++ sizeof(strings->platform)); +++ } +++ } +++ return !result.eof; +++} +++ +++static void FillProcCpuInfoData(PPCPlatformStrings* const strings) { +++ const int fd = CpuFeatures_OpenFile("/proc/cpuinfo"); +++ if (fd >= 0) { +++ StackLineReader reader; +++ StackLineReader_Initialize(&reader, fd); +++ for (;;) { +++ if (!HandlePPCLine(StackLineReader_NextLine(&reader), strings)) { +++ break; +++ } +++ } +++ CpuFeatures_CloseFile(fd); +++ } +++} +++ +++static const PPCInfo kEmptyPPCInfo; +++ +++PPCInfo GetPPCInfo(void) { +++ /* +++ * On Power feature flags aren't currently in cpuinfo so we only look at +++ * the auxilary vector. +++ */ +++ PPCInfo info = kEmptyPPCInfo; +++ const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities(); +++ for (size_t i = 0; i < PPC_LAST_; ++i) { +++ if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) { +++ kSetters[i](&info.features, true); +++ } +++ } +++ return info; +++} +++ +++static const PPCPlatformStrings kEmptyPPCPlatformStrings; +++ +++PPCPlatformStrings GetPPCPlatformStrings(void) { +++ PPCPlatformStrings strings = kEmptyPPCPlatformStrings; +++ +++ FillProcCpuInfoData(&strings); +++ strings.type = CpuFeatures_GetPlatformType(); +++ return strings; +++} +++ +++//////////////////////////////////////////////////////////////////////////////// +++// Introspection functions +++ +++int GetPPCFeaturesEnumValue(const PPCFeatures* features, +++ PPCFeaturesEnum value) { +++ if (value >= PPC_LAST_) return false; +++ return kGetters[value](features); +++} +++ +++const char* GetPPCFeaturesEnumName(PPCFeaturesEnum value) { +++ if (value >= PPC_LAST_) return "unknown feature"; +++ return kCpuInfoFlags[value]; +++} diff --cc cpu-features/src/cpuinfo_x86.c index 0000000,0000000,0000000..378ed05 new file mode 100644 --- /dev/null +++ b/cpu-features/src/cpuinfo_x86.c @@@@ -1,0 -1,0 -1,0 +1,1622 @@@@ +++// Copyright 2017 Google LLC +++// Copyright 2020 Intel Corporation +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#include "cpuinfo_x86.h" +++ +++#include +++#include +++ +++#include "internal/bit_utils.h" +++#include "internal/cpuid_x86.h" +++ +++#if !defined(CPU_FEATURES_ARCH_X86) +++#error "Cannot compile cpuinfo_x86 on a non x86 platform." +++#endif +++ +++// Generation of feature's getters/setters functions and kGetters, kSetters, +++// kCpuInfoFlags global tables. +++#define DEFINE_TABLE_FEATURES \ +++ FEATURE(X86_FPU, fpu, "fpu", 0, 0) \ +++ FEATURE(X86_TSC, tsc, "tsc", 0, 0) \ +++ FEATURE(X86_CX8, cx8, "cx8", 0, 0) \ +++ FEATURE(X86_CLFSH, clfsh, "clfsh", 0, 0) \ +++ FEATURE(X86_MMX, mmx, "mmx", 0, 0) \ +++ FEATURE(X86_AES, aes, "aes", 0, 0) \ +++ FEATURE(X86_ERMS, erms, "erms", 0, 0) \ +++ FEATURE(X86_F16C, f16c, "f16c", 0, 0) \ +++ FEATURE(X86_FMA4, fma4, "fma4", 0, 0) \ +++ FEATURE(X86_FMA3, fma3, "fma3", 0, 0) \ +++ FEATURE(X86_VAES, vaes, "vaes", 0, 0) \ +++ FEATURE(X86_VPCLMULQDQ, vpclmulqdq, "vpclmulqdq", 0, 0) \ +++ FEATURE(X86_BMI1, bmi1, "bmi1", 0, 0) \ +++ FEATURE(X86_HLE, hle, "hle", 0, 0) \ +++ FEATURE(X86_BMI2, bmi2, "bmi2", 0, 0) \ +++ FEATURE(X86_RTM, rtm, "rtm", 0, 0) \ +++ FEATURE(X86_RDSEED, rdseed, "rdseed", 0, 0) \ +++ FEATURE(X86_CLFLUSHOPT, clflushopt, "clflushopt", 0, 0) \ +++ FEATURE(X86_CLWB, clwb, "clwb", 0, 0) \ +++ FEATURE(X86_SSE, sse, "sse", 0, 0) \ +++ FEATURE(X86_SSE2, sse2, "sse2", 0, 0) \ +++ FEATURE(X86_SSE3, sse3, "sse3", 0, 0) \ +++ FEATURE(X86_SSSE3, ssse3, "ssse3", 0, 0) \ +++ FEATURE(X86_SSE4_1, sse4_1, "sse4_1", 0, 0) \ +++ FEATURE(X86_SSE4_2, sse4_2, "sse4_2", 0, 0) \ +++ FEATURE(X86_SSE4A, sse4a, "sse4a", 0, 0) \ +++ FEATURE(X86_AVX, avx, "avx", 0, 0) \ +++ FEATURE(X86_AVX2, avx2, "avx2", 0, 0) \ +++ FEATURE(X86_AVX512F, avx512f, "avx512f", 0, 0) \ +++ FEATURE(X86_AVX512CD, avx512cd, "avx512cd", 0, 0) \ +++ FEATURE(X86_AVX512ER, avx512er, "avx512er", 0, 0) \ +++ FEATURE(X86_AVX512PF, avx512pf, "avx512pf", 0, 0) \ +++ FEATURE(X86_AVX512BW, avx512bw, "avx512bw", 0, 0) \ +++ FEATURE(X86_AVX512DQ, avx512dq, "avx512dq", 0, 0) \ +++ FEATURE(X86_AVX512VL, avx512vl, "avx512vl", 0, 0) \ +++ FEATURE(X86_AVX512IFMA, avx512ifma, "avx512ifma", 0, 0) \ +++ FEATURE(X86_AVX512VBMI, avx512vbmi, "avx512vbmi", 0, 0) \ +++ FEATURE(X86_AVX512VBMI2, avx512vbmi2, "avx512vbmi2", 0, 0) \ +++ FEATURE(X86_AVX512VNNI, avx512vnni, "avx512vnni", 0, 0) \ +++ FEATURE(X86_AVX512BITALG, avx512bitalg, "avx512bitalg", 0, 0) \ +++ FEATURE(X86_AVX512VPOPCNTDQ, avx512vpopcntdq, "avx512vpopcntdq", 0, 0) \ +++ FEATURE(X86_AVX512_4VNNIW, avx512_4vnniw, "avx512_4vnniw", 0, 0) \ +++ FEATURE(X86_AVX512_4VBMI2, avx512_4vbmi2, "avx512_4vbmi2", 0, 0) \ +++ FEATURE(X86_AVX512_SECOND_FMA, avx512_second_fma, "avx512_second_fma", 0, 0) \ +++ FEATURE(X86_AVX512_4FMAPS, avx512_4fmaps, "avx512_4fmaps", 0, 0) \ +++ FEATURE(X86_AVX512_BF16, avx512_bf16, "avx512_bf16", 0, 0) \ +++ FEATURE(X86_AVX512_VP2INTERSECT, avx512_vp2intersect, "avx512_vp2intersect", \ +++ 0, 0) \ +++ FEATURE(X86_AMX_BF16, amx_bf16, "amx_bf16", 0, 0) \ +++ FEATURE(X86_AMX_TILE, amx_tile, "amx_tile", 0, 0) \ +++ FEATURE(X86_AMX_INT8, amx_int8, "amx_int8", 0, 0) \ +++ FEATURE(X86_PCLMULQDQ, pclmulqdq, "pclmulqdq", 0, 0) \ +++ FEATURE(X86_SMX, smx, "smx", 0, 0) \ +++ FEATURE(X86_SGX, sgx, "sgx", 0, 0) \ +++ FEATURE(X86_CX16, cx16, "cx16", 0, 0) \ +++ FEATURE(X86_SHA, sha, "sha", 0, 0) \ +++ FEATURE(X86_POPCNT, popcnt, "popcnt", 0, 0) \ +++ FEATURE(X86_MOVBE, movbe, "movbe", 0, 0) \ +++ FEATURE(X86_RDRND, rdrnd, "rdrnd", 0, 0) \ +++ FEATURE(X86_DCA, dca, "dca", 0, 0) \ +++ FEATURE(X86_SS, ss, "ss", 0, 0) +++#define DEFINE_TABLE_FEATURE_TYPE X86Features +++#define DEFINE_TABLE_DONT_GENERATE_HWCAPS +++#include "define_tables.h" +++ +++// The following includes are necessary to provide SSE detections on pre-AVX +++// microarchitectures. +++#if defined(CPU_FEATURES_OS_WINDOWS) +++#include // IsProcessorFeaturePresent +++#elif defined(CPU_FEATURES_OS_LINUX_OR_ANDROID) +++#include "internal/filesystem.h" // Needed to parse /proc/cpuinfo +++#include "internal/stack_line_reader.h" // Needed to parse /proc/cpuinfo +++#include "internal/string_view.h" // Needed to parse /proc/cpuinfo +++#elif defined(CPU_FEATURES_OS_DARWIN) +++#if !defined(HAVE_SYSCTLBYNAME) +++#error "Darwin needs support for sysctlbyname" +++#endif +++#include +++#else +++#error "Unsupported OS" +++#endif // CPU_FEATURES_OS +++ +++//////////////////////////////////////////////////////////////////////////////// +++// Definitions for CpuId and GetXCR0Eax. +++//////////////////////////////////////////////////////////////////////////////// +++ +++#if defined(CPU_FEATURES_MOCK_CPUID_X86) +++// Implementation will be provided by test/cpuinfo_x86_test.cc. +++#elif defined(CPU_FEATURES_COMPILER_CLANG) || defined(CPU_FEATURES_COMPILER_GCC) +++ +++#include +++ +++Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx) { +++ Leaf leaf; +++ __cpuid_count(leaf_id, ecx, leaf.eax, leaf.ebx, leaf.ecx, leaf.edx); +++ return leaf; +++} +++ +++uint32_t GetXCR0Eax(void) { +++ uint32_t eax, edx; +++ /* named form of xgetbv not supported on OSX, so must use byte form, see: +++ https://github.com/asmjit/asmjit/issues/78 +++ */ +++ __asm(".byte 0x0F, 0x01, 0xd0" : "=a"(eax), "=d"(edx) : "c"(0)); +++ return eax; +++} +++ +++#elif defined(CPU_FEATURES_COMPILER_MSC) +++ +++#include +++#include // For __cpuidex() +++ +++Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx) { +++ Leaf leaf; +++ int data[4]; +++ __cpuidex(data, leaf_id, ecx); +++ leaf.eax = data[0]; +++ leaf.ebx = data[1]; +++ leaf.ecx = data[2]; +++ leaf.edx = data[3]; +++ return leaf; +++} +++ +++uint32_t GetXCR0Eax(void) { return (uint32_t)_xgetbv(0); } +++ +++#else +++#error "Unsupported compiler, x86 cpuid requires either GCC, Clang or MSVC." +++#endif +++ +++static Leaf CpuId(uint32_t leaf_id) { return GetCpuidLeaf(leaf_id, 0); } +++ +++static const Leaf kEmptyLeaf; +++ +++static Leaf SafeCpuIdEx(uint32_t max_cpuid_leaf, uint32_t leaf_id, int ecx) { +++ if (leaf_id <= max_cpuid_leaf) { +++ return GetCpuidLeaf(leaf_id, ecx); +++ } else { +++ return kEmptyLeaf; +++ } +++} +++ +++static Leaf SafeCpuId(uint32_t max_cpuid_leaf, uint32_t leaf_id) { +++ return SafeCpuIdEx(max_cpuid_leaf, leaf_id, 0); +++} +++ +++#define MASK_XMM 0x2 +++#define MASK_YMM 0x4 +++#define MASK_MASKREG 0x20 +++#define MASK_ZMM0_15 0x40 +++#define MASK_ZMM16_31 0x80 +++#define MASK_XTILECFG 0x20000 +++#define MASK_XTILEDATA 0x40000 +++ +++static bool HasMask(uint32_t value, uint32_t mask) { +++ return (value & mask) == mask; +++} +++ +++// Checks that operating system saves and restores xmm registers during context +++// switches. +++static bool HasXmmOsXSave(uint32_t xcr0_eax) { +++ return HasMask(xcr0_eax, MASK_XMM); +++} +++ +++// Checks that operating system saves and restores ymm registers during context +++// switches. +++static bool HasYmmOsXSave(uint32_t xcr0_eax) { +++ return HasMask(xcr0_eax, MASK_XMM | MASK_YMM); +++} +++ +++// Checks that operating system saves and restores zmm registers during context +++// switches. +++static bool HasZmmOsXSave(uint32_t xcr0_eax) { +++ return HasMask(xcr0_eax, MASK_XMM | MASK_YMM | MASK_MASKREG | MASK_ZMM0_15 | +++ MASK_ZMM16_31); +++} +++ +++// Checks that operating system saves and restores AMX/TMUL state during context +++// switches. +++static bool HasTmmOsXSave(uint32_t xcr0_eax) { +++ return HasMask(xcr0_eax, MASK_XMM | MASK_YMM | MASK_MASKREG | MASK_ZMM0_15 | +++ MASK_ZMM16_31 | MASK_XTILECFG | MASK_XTILEDATA); +++} +++ +++static bool HasSecondFMA(uint32_t model) { +++ // Skylake server +++ if (model == 0x55) { +++ char proc_name[49] = {0}; +++ FillX86BrandString(proc_name); +++ // detect Xeon +++ if (proc_name[9] == 'X') { +++ // detect Silver or Bronze +++ if (proc_name[17] == 'S' || proc_name[17] == 'B') return false; +++ // detect Gold 5_20 and below, except for Gold 53__ +++ if (proc_name[17] == 'G' && proc_name[22] == '5') +++ return ((proc_name[23] == '3') || +++ (proc_name[24] == '2' && proc_name[25] == '2')); +++ // detect Xeon W 210x +++ if (proc_name[17] == 'W' && proc_name[21] == '0') return false; +++ // detect Xeon D 2xxx +++ if (proc_name[17] == 'D' && proc_name[19] == '2' && proc_name[20] == '1') +++ return false; +++ } +++ return true; +++ } +++ // Cannon Lake client +++ if (model == 0x66) return false; +++ // Ice Lake client +++ if (model == 0x7d || model == 0x7e) return false; +++ // This is the right default... +++ return true; +++} +++ +++static void SetVendor(const Leaf leaf, char* const vendor) { +++ *(uint32_t*)(vendor) = leaf.ebx; +++ *(uint32_t*)(vendor + 4) = leaf.edx; +++ *(uint32_t*)(vendor + 8) = leaf.ecx; +++ vendor[12] = '\0'; +++} +++ +++static int IsVendor(const Leaf leaf, const char* const name) { +++ const uint32_t ebx = *(const uint32_t*)(name); +++ const uint32_t edx = *(const uint32_t*)(name + 4); +++ const uint32_t ecx = *(const uint32_t*)(name + 8); +++ return leaf.ebx == ebx && leaf.ecx == ecx && leaf.edx == edx; +++} +++ +++static const CacheLevelInfo kEmptyCacheLevelInfo; +++ +++static CacheLevelInfo GetCacheLevelInfo(const uint32_t reg) { +++ const int UNDEF = -1; +++ const int KiB = 1024; +++ const int MiB = 1024 * KiB; +++ switch (reg) { +++ case 0x01: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * KiB, +++ .ways = 4, +++ .line_size = UNDEF, +++ .tlb_entries = 32, +++ .partitioning = 0}; +++ case 0x02: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * MiB, +++ .ways = 0xFF, +++ .line_size = UNDEF, +++ .tlb_entries = 2, +++ .partitioning = 0}; +++ case 0x03: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * KiB, +++ .ways = 4, +++ .line_size = UNDEF, +++ .tlb_entries = 64, +++ .partitioning = 0}; +++ case 0x04: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * MiB, +++ .ways = 4, +++ .line_size = UNDEF, +++ .tlb_entries = 8, +++ .partitioning = 0}; +++ case 0x05: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * MiB, +++ .ways = 4, +++ .line_size = UNDEF, +++ .tlb_entries = 32, +++ .partitioning = 0}; +++ case 0x06: +++ return (CacheLevelInfo){.level = 1, +++ .cache_type = CPU_FEATURE_CACHE_INSTRUCTION, +++ .cache_size = 8 * KiB, +++ .ways = 4, +++ .line_size = 32, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x08: +++ return (CacheLevelInfo){.level = 1, +++ .cache_type = CPU_FEATURE_CACHE_INSTRUCTION, +++ .cache_size = 16 * KiB, +++ .ways = 4, +++ .line_size = 32, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x09: +++ return (CacheLevelInfo){.level = 1, +++ .cache_type = CPU_FEATURE_CACHE_INSTRUCTION, +++ .cache_size = 32 * KiB, +++ .ways = 4, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x0A: +++ return (CacheLevelInfo){.level = 1, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 8 * KiB, +++ .ways = 2, +++ .line_size = 32, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x0B: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * MiB, +++ .ways = 4, +++ .line_size = UNDEF, +++ .tlb_entries = 4, +++ .partitioning = 0}; +++ case 0x0C: +++ return (CacheLevelInfo){.level = 1, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 16 * KiB, +++ .ways = 4, +++ .line_size = 32, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x0D: +++ return (CacheLevelInfo){.level = 1, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 16 * KiB, +++ .ways = 4, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x0E: +++ return (CacheLevelInfo){.level = 1, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 24 * KiB, +++ .ways = 6, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x1D: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 128 * KiB, +++ .ways = 2, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x21: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 256 * KiB, +++ .ways = 8, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x22: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 512 * KiB, +++ .ways = 4, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 2}; +++ case 0x23: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 1 * MiB, +++ .ways = 8, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 2}; +++ case 0x24: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 1 * MiB, +++ .ways = 16, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x25: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 2 * MiB, +++ .ways = 8, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 2}; +++ case 0x29: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 4 * MiB, +++ .ways = 8, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 2}; +++ case 0x2C: +++ return (CacheLevelInfo){.level = 1, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 32 * KiB, +++ .ways = 8, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x30: +++ return (CacheLevelInfo){.level = 1, +++ .cache_type = CPU_FEATURE_CACHE_INSTRUCTION, +++ .cache_size = 32 * KiB, +++ .ways = 8, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x40: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = UNDEF, +++ .ways = UNDEF, +++ .line_size = UNDEF, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x41: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 128 * KiB, +++ .ways = 4, +++ .line_size = 32, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x42: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 256 * KiB, +++ .ways = 4, +++ .line_size = 32, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x43: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 512 * KiB, +++ .ways = 4, +++ .line_size = 32, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x44: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 1 * MiB, +++ .ways = 4, +++ .line_size = 32, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x45: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 2 * MiB, +++ .ways = 4, +++ .line_size = 32, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x46: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 4 * MiB, +++ .ways = 4, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x47: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 8 * MiB, +++ .ways = 8, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x48: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 3 * MiB, +++ .ways = 12, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x49: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 4 * MiB, +++ .ways = 16, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case (0x49 | (1 << 8)): +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 4 * MiB, +++ .ways = 16, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x4A: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 6 * MiB, +++ .ways = 12, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x4B: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 8 * MiB, +++ .ways = 16, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x4C: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 12 * MiB, +++ .ways = 12, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x4D: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 16 * MiB, +++ .ways = 16, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x4E: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 6 * MiB, +++ .ways = 24, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x4F: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * KiB, +++ .ways = UNDEF, +++ .line_size = UNDEF, +++ .tlb_entries = 32, +++ .partitioning = 0}; +++ case 0x50: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * KiB, +++ .ways = UNDEF, +++ .line_size = UNDEF, +++ .tlb_entries = 64, +++ .partitioning = 0}; +++ case 0x51: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * KiB, +++ .ways = UNDEF, +++ .line_size = UNDEF, +++ .tlb_entries = 128, +++ .partitioning = 0}; +++ case 0x52: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * KiB, +++ .ways = UNDEF, +++ .line_size = UNDEF, +++ .tlb_entries = 256, +++ .partitioning = 0}; +++ case 0x55: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 2 * MiB, +++ .ways = 0xFF, +++ .line_size = UNDEF, +++ .tlb_entries = 7, +++ .partitioning = 0}; +++ case 0x56: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * MiB, +++ .ways = 4, +++ .line_size = UNDEF, +++ .tlb_entries = 16, +++ .partitioning = 0}; +++ case 0x57: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * KiB, +++ .ways = 4, +++ .line_size = UNDEF, +++ .tlb_entries = 16, +++ .partitioning = 0}; +++ case 0x59: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * KiB, +++ .ways = 0xFF, +++ .line_size = UNDEF, +++ .tlb_entries = 16, +++ .partitioning = 0}; +++ case 0x5A: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 2 * MiB, +++ .ways = 4, +++ .line_size = UNDEF, +++ .tlb_entries = 32, +++ .partitioning = 0}; +++ case 0x5B: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * KiB, +++ .ways = UNDEF, +++ .line_size = UNDEF, +++ .tlb_entries = 64, +++ .partitioning = 0}; +++ case 0x5C: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * KiB, +++ .ways = UNDEF, +++ .line_size = UNDEF, +++ .tlb_entries = 128, +++ .partitioning = 0}; +++ case 0x5D: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4, +++ .ways = UNDEF, +++ .line_size = UNDEF, +++ .tlb_entries = 256, +++ .partitioning = 0}; +++ case 0x60: +++ return (CacheLevelInfo){.level = 1, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 16 * KiB, +++ .ways = 8, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x61: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * KiB, +++ .ways = 0xFF, +++ .line_size = UNDEF, +++ .tlb_entries = 48, +++ .partitioning = 0}; +++ case 0x63: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 2 * MiB, +++ .ways = 4, +++ .line_size = UNDEF, +++ .tlb_entries = 4, +++ .partitioning = 0}; +++ case 0x66: +++ return (CacheLevelInfo){.level = 1, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 8 * KiB, +++ .ways = 4, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x67: +++ return (CacheLevelInfo){.level = 1, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 16 * KiB, +++ .ways = 4, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x68: +++ return (CacheLevelInfo){.level = 1, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 32 * KiB, +++ .ways = 4, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x70: +++ return (CacheLevelInfo){.level = 1, +++ .cache_type = CPU_FEATURE_CACHE_INSTRUCTION, +++ .cache_size = 12 * KiB, +++ .ways = 8, +++ .line_size = UNDEF, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x71: +++ return (CacheLevelInfo){.level = 1, +++ .cache_type = CPU_FEATURE_CACHE_INSTRUCTION, +++ .cache_size = 16 * KiB, +++ .ways = 8, +++ .line_size = UNDEF, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x72: +++ return (CacheLevelInfo){.level = 1, +++ .cache_type = CPU_FEATURE_CACHE_INSTRUCTION, +++ .cache_size = 32 * KiB, +++ .ways = 8, +++ .line_size = UNDEF, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x76: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 2 * MiB, +++ .ways = 0xFF, +++ .line_size = UNDEF, +++ .tlb_entries = 8, +++ .partitioning = 0}; +++ case 0x78: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 1 * MiB, +++ .ways = 4, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x79: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 128 * KiB, +++ .ways = 8, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 2}; +++ case 0x7A: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 256 * KiB, +++ .ways = 8, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 2}; +++ case 0x7B: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 512 * KiB, +++ .ways = 8, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 2}; +++ case 0x7C: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 1 * MiB, +++ .ways = 8, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 2}; +++ case 0x7D: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 2 * MiB, +++ .ways = 8, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x7F: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 512 * KiB, +++ .ways = 2, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x80: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 512 * KiB, +++ .ways = 8, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x82: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 256 * KiB, +++ .ways = 8, +++ .line_size = 32, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x83: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 512 * KiB, +++ .ways = 8, +++ .line_size = 32, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x84: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 1 * MiB, +++ .ways = 8, +++ .line_size = 32, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x85: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 2 * MiB, +++ .ways = 8, +++ .line_size = 32, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x86: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 512 * KiB, +++ .ways = 4, +++ .line_size = 32, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0x87: +++ return (CacheLevelInfo){.level = 2, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 1 * MiB, +++ .ways = 8, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0xA0: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_DTLB, +++ .cache_size = 4 * KiB, +++ .ways = 0xFF, +++ .line_size = UNDEF, +++ .tlb_entries = 32, +++ .partitioning = 0}; +++ case 0xB0: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * KiB, +++ .ways = 4, +++ .line_size = UNDEF, +++ .tlb_entries = 128, +++ .partitioning = 0}; +++ case 0xB1: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 2 * MiB, +++ .ways = 4, +++ .line_size = UNDEF, +++ .tlb_entries = 8, +++ .partitioning = 0}; +++ case 0xB2: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * KiB, +++ .ways = 4, +++ .line_size = UNDEF, +++ .tlb_entries = 64, +++ .partitioning = 0}; +++ case 0xB3: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * KiB, +++ .ways = 4, +++ .line_size = UNDEF, +++ .tlb_entries = 128, +++ .partitioning = 0}; +++ case 0xB4: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * KiB, +++ .ways = 4, +++ .line_size = UNDEF, +++ .tlb_entries = 256, +++ .partitioning = 0}; +++ case 0xB5: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * KiB, +++ .ways = 8, +++ .line_size = UNDEF, +++ .tlb_entries = 64, +++ .partitioning = 0}; +++ case 0xB6: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * KiB, +++ .ways = 8, +++ .line_size = UNDEF, +++ .tlb_entries = 128, +++ .partitioning = 0}; +++ case 0xBA: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * KiB, +++ .ways = 4, +++ .line_size = UNDEF, +++ .tlb_entries = 64, +++ .partitioning = 0}; +++ case 0xC0: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_TLB, +++ .cache_size = 4 * KiB, +++ .ways = 4, +++ .line_size = UNDEF, +++ .tlb_entries = 8, +++ .partitioning = 0}; +++ case 0xC1: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_STLB, +++ .cache_size = 4 * KiB, +++ .ways = 8, +++ .line_size = UNDEF, +++ .tlb_entries = 1024, +++ .partitioning = 0}; +++ case 0xC2: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_DTLB, +++ .cache_size = 4 * KiB, +++ .ways = 4, +++ .line_size = UNDEF, +++ .tlb_entries = 16, +++ .partitioning = 0}; +++ case 0xC3: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_STLB, +++ .cache_size = 4 * KiB, +++ .ways = 6, +++ .line_size = UNDEF, +++ .tlb_entries = 1536, +++ .partitioning = 0}; +++ case 0xCA: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_STLB, +++ .cache_size = 4 * KiB, +++ .ways = 4, +++ .line_size = UNDEF, +++ .tlb_entries = 512, +++ .partitioning = 0}; +++ case 0xD0: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 512 * KiB, +++ .ways = 4, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0xD1: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 1 * MiB, +++ .ways = 4, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0xD2: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 2 * MiB, +++ .ways = 4, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0xD6: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 1 * MiB, +++ .ways = 8, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0xD7: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 2 * MiB, +++ .ways = 8, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0xD8: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 4 * MiB, +++ .ways = 8, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0xDC: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 1 * 1536 * KiB, +++ .ways = 12, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0xDD: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 3 * MiB, +++ .ways = 12, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0xDE: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 6 * MiB, +++ .ways = 12, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0xE2: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 2 * MiB, +++ .ways = 16, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0xE3: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 4 * MiB, +++ .ways = 16, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0xE4: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 8 * MiB, +++ .ways = 16, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0xEA: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 12 * MiB, +++ .ways = 24, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0xEB: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 18 * MiB, +++ .ways = 24, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0xEC: +++ return (CacheLevelInfo){.level = 3, +++ .cache_type = CPU_FEATURE_CACHE_DATA, +++ .cache_size = 24 * MiB, +++ .ways = 24, +++ .line_size = 64, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0xF0: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_PREFETCH, +++ .cache_size = 64 * KiB, +++ .ways = UNDEF, +++ .line_size = UNDEF, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0xF1: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_PREFETCH, +++ .cache_size = 128 * KiB, +++ .ways = UNDEF, +++ .line_size = UNDEF, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ case 0xFF: +++ return (CacheLevelInfo){.level = UNDEF, +++ .cache_type = CPU_FEATURE_CACHE_NULL, +++ .cache_size = UNDEF, +++ .ways = UNDEF, +++ .line_size = UNDEF, +++ .tlb_entries = UNDEF, +++ .partitioning = 0}; +++ default: +++ return kEmptyCacheLevelInfo; +++ } +++} +++ +++static void GetByteArrayFromRegister(uint32_t result[4], const uint32_t reg) { +++ for (int i = 0; i < 4; ++i) { +++ result[i] = ExtractBitRange(reg, (i + 1) * 8, i * 8); +++ } +++} +++ +++static void ParseLeaf2(const int max_cpuid_leaf, CacheInfo* info) { +++ Leaf leaf = SafeCpuId(max_cpuid_leaf, 2); +++ uint32_t registers[] = {leaf.eax, leaf.ebx, leaf.ecx, leaf.edx}; +++ for (int i = 0; i < 4; ++i) { +++ if (registers[i] & (1U << 31)) { +++ continue; // register does not contains valid information +++ } +++ uint32_t bytes[4]; +++ GetByteArrayFromRegister(bytes, registers[i]); +++ for (int j = 0; j < 4; ++j) { +++ if (bytes[j] == 0xFF) +++ break; // leaf 4 should be used to fetch cache information +++ info->levels[info->size] = GetCacheLevelInfo(bytes[j]); +++ } +++ info->size++; +++ } +++} +++ +++static void ParseLeaf4(const int max_cpuid_leaf, CacheInfo* info) { +++ info->size = 0; +++ for (int cache_id = 0; cache_id < CPU_FEATURES_MAX_CACHE_LEVEL; cache_id++) { +++ const Leaf leaf = SafeCpuIdEx(max_cpuid_leaf, 4, cache_id); +++ CacheType cache_type = ExtractBitRange(leaf.eax, 4, 0); +++ if (cache_type == CPU_FEATURE_CACHE_NULL) { +++ info->levels[cache_id] = kEmptyCacheLevelInfo; +++ continue; +++ } +++ int level = ExtractBitRange(leaf.eax, 7, 5); +++ int line_size = ExtractBitRange(leaf.ebx, 11, 0) + 1; +++ int partitioning = ExtractBitRange(leaf.ebx, 21, 12) + 1; +++ int ways = ExtractBitRange(leaf.ebx, 31, 22) + 1; +++ int tlb_entries = leaf.ecx + 1; +++ int cache_size = (ways * partitioning * line_size * (tlb_entries)); +++ info->levels[cache_id] = (CacheLevelInfo){.level = level, +++ .cache_type = cache_type, +++ .cache_size = cache_size, +++ .ways = ways, +++ .line_size = line_size, +++ .tlb_entries = tlb_entries, +++ .partitioning = partitioning}; +++ info->size++; +++ } +++} +++ +++// Internal structure to hold the OS support for vector operations. +++// Avoid to recompute them since each call to cpuid is ~100 cycles. +++typedef struct { +++ bool have_sse_via_os; +++ bool have_sse_via_cpuid; +++ bool have_avx; +++ bool have_avx512; +++ bool have_amx; +++} OsSupport; +++ +++static const OsSupport kEmptyOsSupport; +++ +++static OsSupport CheckOsSupport(const uint32_t max_cpuid_leaf) { +++ const Leaf leaf_1 = SafeCpuId(max_cpuid_leaf, 1); +++ const bool have_xsave = IsBitSet(leaf_1.ecx, 26); +++ const bool have_osxsave = IsBitSet(leaf_1.ecx, 27); +++ const bool have_xcr0 = have_xsave && have_osxsave; +++ +++ OsSupport os_support = kEmptyOsSupport; +++ +++ if (have_xcr0) { +++ // AVX capable cpu will expose XCR0. +++ const uint32_t xcr0_eax = GetXCR0Eax(); +++ os_support.have_sse_via_cpuid = HasXmmOsXSave(xcr0_eax); +++ os_support.have_avx = HasYmmOsXSave(xcr0_eax); +++ os_support.have_avx512 = HasZmmOsXSave(xcr0_eax); +++ os_support.have_amx = HasTmmOsXSave(xcr0_eax); +++ } else { +++ // Atom based or older cpus need to ask the OS for sse support. +++ os_support.have_sse_via_os = true; +++ } +++ +++ return os_support; +++} +++ +++#if defined(CPU_FEATURES_OS_WINDOWS) +++#if defined(CPU_FEATURES_MOCK_CPUID_X86) +++extern bool GetWindowsIsProcessorFeaturePresent(DWORD); +++#else // CPU_FEATURES_MOCK_CPUID_X86 +++static bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) { +++ return IsProcessorFeaturePresent(ProcessorFeature); +++} +++#endif +++#endif // CPU_FEATURES_OS_WINDOWS +++ +++#if defined(CPU_FEATURES_OS_DARWIN) +++#if defined(CPU_FEATURES_MOCK_CPUID_X86) +++extern bool GetDarwinSysCtlByName(const char*); +++#else // CPU_FEATURES_MOCK_CPUID_X86 +++static bool GetDarwinSysCtlByName(const char* name) { +++ int enabled; +++ size_t enabled_len = sizeof(enabled); +++ const int failure = sysctlbyname(name, &enabled, &enabled_len, NULL, 0); +++ return failure ? false : enabled; +++} +++#endif +++#endif // CPU_FEATURES_OS_DARWIN +++ +++static void DetectSseViaOs(X86Features* features) { +++#if defined(CPU_FEATURES_OS_WINDOWS) +++ // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent +++ features->sse = +++ GetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE); +++ features->sse2 = +++ GetWindowsIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE); +++ features->sse3 = +++ GetWindowsIsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE); +++#elif defined(CPU_FEATURES_OS_DARWIN) +++ // Handling Darwin platform through sysctlbyname. +++ features->sse = GetDarwinSysCtlByName("hw.optional.sse"); +++ features->sse2 = GetDarwinSysCtlByName("hw.optional.sse2"); +++ features->sse3 = GetDarwinSysCtlByName("hw.optional.sse3"); +++ features->ssse3 = GetDarwinSysCtlByName("hw.optional.supplementalsse3"); +++ features->sse4_1 = GetDarwinSysCtlByName("hw.optional.sse4_1"); +++ features->sse4_2 = GetDarwinSysCtlByName("hw.optional.sse4_2"); +++#elif defined(CPU_FEATURES_OS_LINUX_OR_ANDROID) +++ // Handling Linux platform through /proc/cpuinfo. +++ const int fd = CpuFeatures_OpenFile("/proc/cpuinfo"); +++ if (fd >= 0) { +++ StackLineReader reader; +++ StackLineReader_Initialize(&reader, fd); +++ for (;;) { +++ const LineResult result = StackLineReader_NextLine(&reader); +++ const StringView line = result.line; +++ StringView key, value; +++ if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) { +++ if (CpuFeatures_StringView_IsEquals(key, str("flags"))) { +++ features->sse = CpuFeatures_StringView_HasWord(value, "sse"); +++ features->sse2 = CpuFeatures_StringView_HasWord(value, "sse2"); +++ features->sse3 = CpuFeatures_StringView_HasWord(value, "sse3"); +++ features->ssse3 = CpuFeatures_StringView_HasWord(value, "ssse3"); +++ features->sse4_1 = CpuFeatures_StringView_HasWord(value, "sse4_1"); +++ features->sse4_2 = CpuFeatures_StringView_HasWord(value, "sse4_2"); +++ break; +++ } +++ } +++ if (result.eof) break; +++ } +++ CpuFeatures_CloseFile(fd); +++ } +++#else +++#error "Unsupported fallback detection of SSE OS support." +++#endif +++} +++ +++// Reference https://en.wikipedia.org/wiki/CPUID. +++static void ParseCpuId(const uint32_t max_cpuid_leaf, +++ const OsSupport os_support, X86Info* info) { +++ const Leaf leaf_1 = SafeCpuId(max_cpuid_leaf, 1); +++ const Leaf leaf_7 = SafeCpuId(max_cpuid_leaf, 7); +++ const Leaf leaf_7_1 = SafeCpuIdEx(max_cpuid_leaf, 7, 1); +++ +++ const uint32_t family = ExtractBitRange(leaf_1.eax, 11, 8); +++ const uint32_t extended_family = ExtractBitRange(leaf_1.eax, 27, 20); +++ const uint32_t model = ExtractBitRange(leaf_1.eax, 7, 4); +++ const uint32_t extended_model = ExtractBitRange(leaf_1.eax, 19, 16); +++ +++ X86Features* const features = &info->features; +++ +++ info->family = extended_family + family; +++ info->model = (extended_model << 4) + model; +++ info->stepping = ExtractBitRange(leaf_1.eax, 3, 0); +++ +++ features->fpu = IsBitSet(leaf_1.edx, 0); +++ features->tsc = IsBitSet(leaf_1.edx, 4); +++ features->cx8 = IsBitSet(leaf_1.edx, 8); +++ features->clfsh = IsBitSet(leaf_1.edx, 19); +++ features->mmx = IsBitSet(leaf_1.edx, 23); +++ features->ss = IsBitSet(leaf_1.edx, 27); +++ features->pclmulqdq = IsBitSet(leaf_1.ecx, 1); +++ features->smx = IsBitSet(leaf_1.ecx, 6); +++ features->cx16 = IsBitSet(leaf_1.ecx, 13); +++ features->dca = IsBitSet(leaf_1.ecx, 18); +++ features->movbe = IsBitSet(leaf_1.ecx, 22); +++ features->popcnt = IsBitSet(leaf_1.ecx, 23); +++ features->aes = IsBitSet(leaf_1.ecx, 25); +++ features->f16c = IsBitSet(leaf_1.ecx, 29); +++ features->rdrnd = IsBitSet(leaf_1.ecx, 30); +++ features->sgx = IsBitSet(leaf_7.ebx, 2); +++ features->bmi1 = IsBitSet(leaf_7.ebx, 3); +++ features->hle = IsBitSet(leaf_7.ebx, 4); +++ features->bmi2 = IsBitSet(leaf_7.ebx, 8); +++ features->erms = IsBitSet(leaf_7.ebx, 9); +++ features->rtm = IsBitSet(leaf_7.ebx, 11); +++ features->rdseed = IsBitSet(leaf_7.ebx, 18); +++ features->clflushopt = IsBitSet(leaf_7.ebx, 23); +++ features->clwb = IsBitSet(leaf_7.ebx, 24); +++ features->sha = IsBitSet(leaf_7.ebx, 29); +++ features->vaes = IsBitSet(leaf_7.ecx, 9); +++ features->vpclmulqdq = IsBitSet(leaf_7.ecx, 10); +++ +++ if (os_support.have_sse_via_os) { +++ DetectSseViaOs(features); +++ } else if (os_support.have_sse_via_cpuid) { +++ features->sse = IsBitSet(leaf_1.edx, 25); +++ features->sse2 = IsBitSet(leaf_1.edx, 26); +++ features->sse3 = IsBitSet(leaf_1.ecx, 0); +++ features->ssse3 = IsBitSet(leaf_1.ecx, 9); +++ features->sse4_1 = IsBitSet(leaf_1.ecx, 19); +++ features->sse4_2 = IsBitSet(leaf_1.ecx, 20); +++ } +++ +++ if (os_support.have_avx) { +++ features->fma3 = IsBitSet(leaf_1.ecx, 12); +++ features->avx = IsBitSet(leaf_1.ecx, 28); +++ features->avx2 = IsBitSet(leaf_7.ebx, 5); +++ } +++ +++ if (os_support.have_avx512) { +++ features->avx512f = IsBitSet(leaf_7.ebx, 16); +++ features->avx512cd = IsBitSet(leaf_7.ebx, 28); +++ features->avx512er = IsBitSet(leaf_7.ebx, 27); +++ features->avx512pf = IsBitSet(leaf_7.ebx, 26); +++ features->avx512bw = IsBitSet(leaf_7.ebx, 30); +++ features->avx512dq = IsBitSet(leaf_7.ebx, 17); +++ features->avx512vl = IsBitSet(leaf_7.ebx, 31); +++ features->avx512ifma = IsBitSet(leaf_7.ebx, 21); +++ features->avx512vbmi = IsBitSet(leaf_7.ecx, 1); +++ features->avx512vbmi2 = IsBitSet(leaf_7.ecx, 6); +++ features->avx512vnni = IsBitSet(leaf_7.ecx, 11); +++ features->avx512bitalg = IsBitSet(leaf_7.ecx, 12); +++ features->avx512vpopcntdq = IsBitSet(leaf_7.ecx, 14); +++ features->avx512_4vnniw = IsBitSet(leaf_7.edx, 2); +++ features->avx512_4vbmi2 = IsBitSet(leaf_7.edx, 3); +++ features->avx512_second_fma = HasSecondFMA(info->model); +++ features->avx512_4fmaps = IsBitSet(leaf_7.edx, 3); +++ features->avx512_bf16 = IsBitSet(leaf_7_1.eax, 5); +++ features->avx512_vp2intersect = IsBitSet(leaf_7.edx, 8); +++ } +++ +++ if (os_support.have_amx) { +++ features->amx_bf16 = IsBitSet(leaf_7.edx, 22); +++ features->amx_tile = IsBitSet(leaf_7.edx, 24); +++ features->amx_int8 = IsBitSet(leaf_7.edx, 25); +++ } +++} +++ +++// Reference +++// https://en.wikipedia.org/wiki/CPUID#EAX=80000000h:_Get_Highest_Extended_Function_Implemented. +++static void ParseExtraAMDCpuId(X86Info* info, OsSupport os_support) { +++ const Leaf leaf_80000000 = CpuId(0x80000000); +++ const uint32_t max_extended_cpuid_leaf = leaf_80000000.eax; +++ const Leaf leaf_80000001 = SafeCpuId(max_extended_cpuid_leaf, 0x80000001); +++ +++ X86Features* const features = &info->features; +++ +++ if (os_support.have_sse_via_cpuid) { +++ features->sse4a = IsBitSet(leaf_80000001.ecx, 6); +++ } +++ +++ if (os_support.have_avx) { +++ features->fma4 = IsBitSet(leaf_80000001.ecx, 16); +++ } +++} +++ +++static const X86Info kEmptyX86Info; +++static const CacheInfo kEmptyCacheInfo; +++ +++X86Info GetX86Info(void) { +++ X86Info info = kEmptyX86Info; +++ const Leaf leaf_0 = CpuId(0); +++ const bool is_intel = IsVendor(leaf_0, "GenuineIntel"); +++ const bool is_amd = IsVendor(leaf_0, "AuthenticAMD"); +++ SetVendor(leaf_0, info.vendor); +++ if (is_intel || is_amd) { +++ const uint32_t max_cpuid_leaf = leaf_0.eax; +++ const OsSupport os_support = CheckOsSupport(max_cpuid_leaf); +++ ParseCpuId(max_cpuid_leaf, os_support, &info); +++ if (is_amd) { +++ ParseExtraAMDCpuId(&info, os_support); +++ } +++ } +++ return info; +++} +++ +++CacheInfo GetX86CacheInfo(void) { +++ CacheInfo info = kEmptyCacheInfo; +++ const Leaf leaf_0 = CpuId(0); +++ const uint32_t max_cpuid_leaf = leaf_0.eax; +++ if (IsVendor(leaf_0, "GenuineIntel")) { +++ ParseLeaf2(max_cpuid_leaf, &info); +++ ParseLeaf4(max_cpuid_leaf, &info); +++ } +++ return info; +++} +++ +++#define CPUID(FAMILY, MODEL) ((((FAMILY)&0xFF) << 8) | ((MODEL)&0xFF)) +++ +++X86Microarchitecture GetX86Microarchitecture(const X86Info* info) { +++ if (memcmp(info->vendor, "GenuineIntel", sizeof(info->vendor)) == 0) { +++ switch (CPUID(info->family, info->model)) { +++ case CPUID(0x06, 0x35): +++ case CPUID(0x06, 0x36): +++ // https://en.wikipedia.org/wiki/Bonnell_(microarchitecture) +++ return INTEL_ATOM_BNL; +++ case CPUID(0x06, 0x37): +++ case CPUID(0x06, 0x4C): +++ // https://en.wikipedia.org/wiki/Silvermont +++ return INTEL_ATOM_SMT; +++ case CPUID(0x06, 0x5C): +++ // https://en.wikipedia.org/wiki/Goldmont +++ return INTEL_ATOM_GMT; +++ case CPUID(0x06, 0x0F): +++ case CPUID(0x06, 0x16): +++ // https://en.wikipedia.org/wiki/Intel_Core_(microarchitecture) +++ return INTEL_CORE; +++ case CPUID(0x06, 0x17): +++ case CPUID(0x06, 0x1D): +++ // https://en.wikipedia.org/wiki/Penryn_(microarchitecture) +++ return INTEL_PNR; +++ case CPUID(0x06, 0x1A): +++ case CPUID(0x06, 0x1E): +++ case CPUID(0x06, 0x1F): +++ case CPUID(0x06, 0x2E): +++ // https://en.wikipedia.org/wiki/Nehalem_(microarchitecture) +++ return INTEL_NHM; +++ case CPUID(0x06, 0x25): +++ case CPUID(0x06, 0x2C): +++ case CPUID(0x06, 0x2F): +++ // https://en.wikipedia.org/wiki/Westmere_(microarchitecture) +++ return INTEL_WSM; +++ case CPUID(0x06, 0x2A): +++ case CPUID(0x06, 0x2D): +++ // https://en.wikipedia.org/wiki/Sandy_Bridge#Models_and_steppings +++ return INTEL_SNB; +++ case CPUID(0x06, 0x3A): +++ case CPUID(0x06, 0x3E): +++ // https://en.wikipedia.org/wiki/Ivy_Bridge_(microarchitecture)#Models_and_steppings +++ return INTEL_IVB; +++ case CPUID(0x06, 0x3C): +++ case CPUID(0x06, 0x3F): +++ case CPUID(0x06, 0x45): +++ case CPUID(0x06, 0x46): +++ // https://en.wikipedia.org/wiki/Haswell_(microarchitecture) +++ return INTEL_HSW; +++ case CPUID(0x06, 0x3D): +++ case CPUID(0x06, 0x47): +++ case CPUID(0x06, 0x4F): +++ case CPUID(0x06, 0x56): +++ // https://en.wikipedia.org/wiki/Broadwell_(microarchitecture) +++ return INTEL_BDW; +++ case CPUID(0x06, 0x4E): +++ case CPUID(0x06, 0x55): +++ case CPUID(0x06, 0x5E): +++ // https://en.wikipedia.org/wiki/Skylake_(microarchitecture) +++ return INTEL_SKL; +++ case CPUID(0x06, 0x66): +++ // https://en.wikipedia.org/wiki/Cannon_Lake_(microarchitecture) +++ return INTEL_CNL; +++ case CPUID(0x06, 0x7D): // client +++ case CPUID(0x06, 0x7E): // client +++ case CPUID(0x06, 0x9D): // NNP-I +++ case CPUID(0x06, 0x6A): // server +++ case CPUID(0x06, 0x6C): // server +++ // https://en.wikipedia.org/wiki/Ice_Lake_(microprocessor) +++ return INTEL_ICL; +++ case CPUID(0x06, 0x8C): +++ case CPUID(0x06, 0x8D): +++ // https://en.wikipedia.org/wiki/Tiger_Lake_(microarchitecture) +++ return INTEL_TGL; +++ case CPUID(0x06, 0x8F): +++ // https://en.wikipedia.org/wiki/Sapphire_Rapids +++ return INTEL_SPR; +++ case CPUID(0x06, 0x8E): +++ switch (info->stepping) { +++ case 9: +++ return INTEL_KBL; // https://en.wikipedia.org/wiki/Kaby_Lake +++ case 10: +++ return INTEL_CFL; // https://en.wikipedia.org/wiki/Coffee_Lake +++ case 11: +++ return INTEL_WHL; // https://en.wikipedia.org/wiki/Whiskey_Lake_(microarchitecture) +++ default: +++ return X86_UNKNOWN; +++ } +++ case CPUID(0x06, 0x9E): +++ if (info->stepping > 9) { +++ // https://en.wikipedia.org/wiki/Coffee_Lake +++ return INTEL_CFL; +++ } else { +++ // https://en.wikipedia.org/wiki/Kaby_Lake +++ return INTEL_KBL; +++ } +++ default: +++ return X86_UNKNOWN; +++ } +++ } +++ if (memcmp(info->vendor, "AuthenticAMD", sizeof(info->vendor)) == 0) { +++ switch (info->family) { +++ // https://en.wikipedia.org/wiki/List_of_AMD_CPU_microarchitectures +++ case 0x0F: +++ return AMD_HAMMER; +++ case 0x10: +++ return AMD_K10; +++ case 0x14: +++ return AMD_BOBCAT; +++ case 0x15: +++ return AMD_BULLDOZER; +++ case 0x16: +++ return AMD_JAGUAR; +++ case 0x17: +++ return AMD_ZEN; +++ default: +++ return X86_UNKNOWN; +++ } +++ } +++ return X86_UNKNOWN; +++} +++ +++static void SetString(const uint32_t max_cpuid_ext_leaf, const uint32_t leaf_id, +++ char* buffer) { +++ const Leaf leaf = SafeCpuId(max_cpuid_ext_leaf, leaf_id); +++ // We allow calling memcpy from SetString which is only called when requesting +++ // X86BrandString. +++ memcpy(buffer, &leaf, sizeof(Leaf)); +++} +++ +++void FillX86BrandString(char brand_string[49]) { +++ const Leaf leaf_ext_0 = CpuId(0x80000000); +++ const uint32_t max_cpuid_leaf_ext = leaf_ext_0.eax; +++ SetString(max_cpuid_leaf_ext, 0x80000002, brand_string); +++ SetString(max_cpuid_leaf_ext, 0x80000003, brand_string + 16); +++ SetString(max_cpuid_leaf_ext, 0x80000004, brand_string + 32); +++ brand_string[48] = '\0'; +++} +++ +++//////////////////////////////////////////////////////////////////////////////// +++// Introspection functions +++ +++int GetX86FeaturesEnumValue(const X86Features* features, +++ X86FeaturesEnum value) { +++ if (value >= X86_LAST_) return false; +++ return kGetters[value](features); +++} +++ +++const char* GetX86FeaturesEnumName(X86FeaturesEnum value) { +++ if (value >= X86_LAST_) return "unknown_feature"; +++ return kCpuInfoFlags[value]; +++} +++ +++const char* GetX86MicroarchitectureName(X86Microarchitecture uarch) { +++ switch (uarch) { +++ case X86_UNKNOWN: +++ return "X86_UNKNOWN"; +++ case INTEL_CORE: +++ return "INTEL_CORE"; +++ case INTEL_PNR: +++ return "INTEL_PNR"; +++ case INTEL_NHM: +++ return "INTEL_NHM"; +++ case INTEL_ATOM_BNL: +++ return "INTEL_ATOM_BNL"; +++ case INTEL_WSM: +++ return "INTEL_WSM"; +++ case INTEL_SNB: +++ return "INTEL_SNB"; +++ case INTEL_IVB: +++ return "INTEL_IVB"; +++ case INTEL_ATOM_SMT: +++ return "INTEL_ATOM_SMT"; +++ case INTEL_HSW: +++ return "INTEL_HSW"; +++ case INTEL_BDW: +++ return "INTEL_BDW"; +++ case INTEL_SKL: +++ return "INTEL_SKL"; +++ case INTEL_ATOM_GMT: +++ return "INTEL_ATOM_GMT"; +++ case INTEL_KBL: +++ return "INTEL_KBL"; +++ case INTEL_CFL: +++ return "INTEL_CFL"; +++ case INTEL_WHL: +++ return "INTEL_WHL"; +++ case INTEL_CNL: +++ return "INTEL_CNL"; +++ case INTEL_ICL: +++ return "INTEL_ICL"; +++ case INTEL_TGL: +++ return "INTEL_TGL"; +++ case INTEL_SPR: +++ return "INTEL_SPR"; +++ case AMD_HAMMER: +++ return "AMD_HAMMER"; +++ case AMD_K10: +++ return "AMD_K10"; +++ case AMD_BOBCAT: +++ return "AMD_BOBCAT"; +++ case AMD_BULLDOZER: +++ return "AMD_BULLDOZER"; +++ case AMD_JAGUAR: +++ return "AMD_JAGUAR"; +++ case AMD_ZEN: +++ return "AMD_ZEN"; +++ } +++ return "unknown microarchitecture"; +++} diff --cc cpu-features/src/define_tables.h index 0000000,0000000,0000000..dc1485c new file mode 100644 --- /dev/null +++ b/cpu-features/src/define_tables.h @@@@ -1,0 -1,0 -1,0 +1,67 @@@@ +++// Copyright 2020 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++// The following preprocessor constants must be defined before including this +++// file: +++// - DEFINE_TABLE_FEATURE_TYPE, the underlying type (e.g. X86Features) +++// - DEFINE_TABLE_FEATURES, the list of FEATURE macros to be inserted. +++ +++// This file is to be included once per `cpuinfo_XXX.c` in order to construct +++// feature getters and setters functions as well as several enum indexed tables +++// from the db file. +++// - `kGetters` a table of getters function pointers from feature enum to +++// retrieve a feature, +++// - `kSetters` a table of setters function pointers from feature enum to set a +++// feature, +++// - `kCpuInfoFlags` a table of strings from feature enum to /proc/cpuinfo +++// flags, +++// - `kHardwareCapabilities` a table of HardwareCapabilities structs indexed by +++// their feature enum. +++ +++#ifndef SRC_DEFINE_TABLES_H_ +++#define SRC_DEFINE_TABLES_H_ +++ +++#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) [ENUM] = CPUINFO_FLAG, +++static const char* kCpuInfoFlags[] = {DEFINE_TABLE_FEATURES}; +++#undef FEATURE +++ +++#ifndef DEFINE_TABLE_DONT_GENERATE_HWCAPS +++#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) \ +++ [ENUM] = (HardwareCapabilities){HWCAP, HWCAP2}, +++static const HardwareCapabilities kHardwareCapabilities[] = { +++ DEFINE_TABLE_FEATURES}; +++#undef FEATURE +++#endif // DEFINE_TABLE_DONT_GENERATE_HWCAPS +++ +++#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) \ +++ static void set_##ENUM(DEFINE_TABLE_FEATURE_TYPE* features, bool value) { \ +++ features->NAME = value; \ +++ } \ +++ static int get_##ENUM(const DEFINE_TABLE_FEATURE_TYPE* features) { \ +++ return features->NAME; \ +++ } +++DEFINE_TABLE_FEATURES +++#undef FEATURE +++ +++#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) [ENUM] = set_##ENUM, +++static void (*const kSetters[])(DEFINE_TABLE_FEATURE_TYPE*, +++ bool) = {DEFINE_TABLE_FEATURES}; +++#undef FEATURE +++ +++#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) [ENUM] = get_##ENUM, +++static int (*const kGetters[])(const DEFINE_TABLE_FEATURE_TYPE*) = { +++ DEFINE_TABLE_FEATURES}; +++#undef FEATURE +++ +++#endif // SRC_DEFINE_TABLES_H_ diff --cc cpu-features/src/filesystem.c index 0000000,0000000,0000000..46c9906 new file mode 100644 --- /dev/null +++ b/cpu-features/src/filesystem.c @@@@ -1,0 -1,0 -1,0 +1,62 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#include "internal/filesystem.h" +++ +++#include +++#include +++#include +++#include +++#include +++ +++#if defined(CPU_FEATURES_MOCK_FILESYSTEM) +++// Implementation will be provided by test/filesystem_for_testing.cc. +++#elif defined(_MSC_VER) +++#include +++int CpuFeatures_OpenFile(const char* filename) { +++ int fd = -1; +++ _sopen_s(&fd, filename, _O_RDONLY, _SH_DENYWR, _S_IREAD); +++ return fd; +++} +++ +++void CpuFeatures_CloseFile(int file_descriptor) { _close(file_descriptor); } +++ +++int CpuFeatures_ReadFile(int file_descriptor, void* buffer, +++ size_t buffer_size) { +++ return _read(file_descriptor, buffer, (unsigned int)buffer_size); +++} +++ +++#else +++#include +++ +++int CpuFeatures_OpenFile(const char* filename) { +++ int result; +++ do { +++ result = open(filename, O_RDONLY); +++ } while (result == -1L && errno == EINTR); +++ return result; +++} +++ +++void CpuFeatures_CloseFile(int file_descriptor) { close(file_descriptor); } +++ +++int CpuFeatures_ReadFile(int file_descriptor, void* buffer, +++ size_t buffer_size) { +++ int result; +++ do { +++ result = read(file_descriptor, buffer, buffer_size); +++ } while (result == -1L && errno == EINTR); +++ return result; +++} +++ +++#endif diff --cc cpu-features/src/hwcaps.c index 0000000,0000000,0000000..dd17e3b new file mode 100644 --- /dev/null +++ b/cpu-features/src/hwcaps.c @@@@ -1,0 -1,0 -1,0 +1,182 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#include "internal/hwcaps.h" +++ +++#include +++#include +++ +++#include "cpu_features_macros.h" +++#include "internal/filesystem.h" +++#include "internal/string_view.h" +++ +++static bool IsSet(const uint32_t mask, const uint32_t value) { +++ if (mask == 0) return false; +++ return (value & mask) == mask; +++} +++ +++bool CpuFeatures_IsHwCapsSet(const HardwareCapabilities hwcaps_mask, +++ const HardwareCapabilities hwcaps) { +++ return IsSet(hwcaps_mask.hwcaps, hwcaps.hwcaps) || +++ IsSet(hwcaps_mask.hwcaps2, hwcaps.hwcaps2); +++} +++ +++#ifdef CPU_FEATURES_TEST +++// In test mode, hwcaps_for_testing will define the following functions. +++HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void); +++PlatformType CpuFeatures_GetPlatformType(void); +++#else +++ +++// Debug facilities +++#if defined(NDEBUG) +++#define D(...) +++#else +++#include +++#define D(...) \ +++ do { \ +++ printf(__VA_ARGS__); \ +++ fflush(stdout); \ +++ } while (0) +++#endif +++ +++//////////////////////////////////////////////////////////////////////////////// +++// Implementation of GetElfHwcapFromGetauxval +++//////////////////////////////////////////////////////////////////////////////// +++ +++#define AT_HWCAP 16 +++#define AT_HWCAP2 26 +++#define AT_PLATFORM 15 +++#define AT_BASE_PLATFORM 24 +++ +++#if defined(HAVE_STRONG_GETAUXVAL) +++#include +++static unsigned long GetElfHwcapFromGetauxval(uint32_t hwcap_type) { +++ return getauxval(hwcap_type); +++} +++#elif defined(HAVE_DLFCN_H) +++// On Android we probe the system's C library for a 'getauxval' function and +++// call it if it exits, or return 0 for failure. This function is available +++// since API level 20. +++// +++// This code does *NOT* check for '__ANDROID_API__ >= 20' to support the edge +++// case where some NDK developers use headers for a platform that is newer than +++// the one really targetted by their application. This is typically done to use +++// newer native APIs only when running on more recent Android versions, and +++// requires careful symbol management. +++// +++// Note that getauxval() can't really be re-implemented here, because its +++// implementation does not parse /proc/self/auxv. Instead it depends on values +++// that are passed by the kernel at process-init time to the C runtime +++// initialization layer. +++ +++#include +++ +++typedef unsigned long getauxval_func_t(unsigned long); +++ +++static uint32_t GetElfHwcapFromGetauxval(uint32_t hwcap_type) { +++ uint32_t ret = 0; +++ void *libc_handle = NULL; +++ getauxval_func_t *func = NULL; +++ +++ dlerror(); // Cleaning error state before calling dlopen. +++ libc_handle = dlopen("libc.so", RTLD_NOW); +++ if (!libc_handle) { +++ D("Could not dlopen() C library: %s\n", dlerror()); +++ return 0; +++ } +++ func = (getauxval_func_t *)dlsym(libc_handle, "getauxval"); +++ if (!func) { +++ D("Could not find getauxval() in C library\n"); +++ } else { +++ // Note: getauxval() returns 0 on failure. Doesn't touch errno. +++ ret = (uint32_t)(*func)(hwcap_type); +++ } +++ dlclose(libc_handle); +++ return ret; +++} +++#else +++#error "This platform does not provide hardware capabilities." +++#endif +++ +++// Implementation of GetHardwareCapabilities for OS that provide +++// GetElfHwcapFromGetauxval(). +++ +++// Fallback when getauxval is not available, retrieves hwcaps from +++// "/proc/self/auxv". +++static uint32_t GetElfHwcapFromProcSelfAuxv(uint32_t hwcap_type) { +++ struct { +++ uint32_t tag; +++ uint32_t value; +++ } entry; +++ uint32_t result = 0; +++ const char filepath[] = "/proc/self/auxv"; +++ const int fd = CpuFeatures_OpenFile(filepath); +++ if (fd < 0) { +++ D("Could not open %s\n", filepath); +++ return 0; +++ } +++ for (;;) { +++ const int ret = CpuFeatures_ReadFile(fd, (char *)&entry, sizeof entry); +++ if (ret < 0) { +++ D("Error while reading %s\n", filepath); +++ break; +++ } +++ // Detect end of list. +++ if (ret == 0 || (entry.tag == 0 && entry.value == 0)) { +++ break; +++ } +++ if (entry.tag == hwcap_type) { +++ result = entry.value; +++ break; +++ } +++ } +++ CpuFeatures_CloseFile(fd); +++ return result; +++} +++ +++// Retrieves hardware capabilities by first trying to call getauxval, if not +++// available falls back to reading "/proc/self/auxv". +++static unsigned long GetHardwareCapabilitiesFor(uint32_t type) { +++ unsigned long hwcaps = GetElfHwcapFromGetauxval(type); +++ if (!hwcaps) { +++ D("Parsing /proc/self/auxv to extract ELF hwcaps!\n"); +++ hwcaps = GetElfHwcapFromProcSelfAuxv(type); +++ } +++ return hwcaps; +++} +++ +++HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void) { +++ HardwareCapabilities capabilities; +++ capabilities.hwcaps = GetHardwareCapabilitiesFor(AT_HWCAP); +++ capabilities.hwcaps2 = GetHardwareCapabilitiesFor(AT_HWCAP2); +++ return capabilities; +++} +++ +++PlatformType kEmptyPlatformType; +++ +++PlatformType CpuFeatures_GetPlatformType(void) { +++ PlatformType type = kEmptyPlatformType; +++ char *platform = (char *)GetHardwareCapabilitiesFor(AT_PLATFORM); +++ char *base_platform = (char *)GetHardwareCapabilitiesFor(AT_BASE_PLATFORM); +++ +++ if (platform != NULL) +++ CpuFeatures_StringView_CopyString(str(platform), type.platform, +++ sizeof(type.platform)); +++ if (base_platform != NULL) +++ CpuFeatures_StringView_CopyString(str(base_platform), type.base_platform, +++ sizeof(type.base_platform)); +++ return type; +++} +++ +++#endif // CPU_FEATURES_TEST diff --cc cpu-features/src/stack_line_reader.c index 0000000,0000000,0000000..ffc778d new file mode 100644 --- /dev/null +++ b/cpu-features/src/stack_line_reader.c @@@@ -1,0 -1,0 -1,0 +1,132 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#include "internal/stack_line_reader.h" +++ +++#include +++#include +++#include +++ +++#include "internal/filesystem.h" +++ +++void StackLineReader_Initialize(StackLineReader* reader, int fd) { +++ reader->view.ptr = reader->buffer; +++ reader->view.size = 0; +++ reader->skip_mode = false; +++ reader->fd = fd; +++} +++ +++// Replaces the content of buffer with bytes from the file. +++static int LoadFullBuffer(StackLineReader* reader) { +++ const int read = CpuFeatures_ReadFile(reader->fd, reader->buffer, +++ STACK_LINE_READER_BUFFER_SIZE); +++ assert(read >= 0); +++ reader->view.ptr = reader->buffer; +++ reader->view.size = read; +++ return read; +++} +++ +++// Appends with bytes from the file to buffer, filling the remaining space. +++static int LoadMore(StackLineReader* reader) { +++ char* const ptr = reader->buffer + reader->view.size; +++ const size_t size_to_read = STACK_LINE_READER_BUFFER_SIZE - reader->view.size; +++ const int read = CpuFeatures_ReadFile(reader->fd, ptr, size_to_read); +++ assert(read >= 0); +++ assert(read <= (int)size_to_read); +++ reader->view.size += read; +++ return read; +++} +++ +++static int IndexOfEol(StackLineReader* reader) { +++ return CpuFeatures_StringView_IndexOfChar(reader->view, '\n'); +++} +++ +++// Relocate buffer's pending bytes at the beginning of the array and fills the +++// remaining space with bytes from the file. +++static int BringToFrontAndLoadMore(StackLineReader* reader) { +++ if (reader->view.size && reader->view.ptr != reader->buffer) { +++ memmove(reader->buffer, reader->view.ptr, reader->view.size); +++ } +++ reader->view.ptr = reader->buffer; +++ return LoadMore(reader); +++} +++ +++// Loads chunks of buffer size from disks until it contains a newline character +++// or end of file. +++static void SkipToNextLine(StackLineReader* reader) { +++ for (;;) { +++ const int read = LoadFullBuffer(reader); +++ if (read == 0) { +++ break; +++ } else { +++ const int eol_index = IndexOfEol(reader); +++ if (eol_index >= 0) { +++ reader->view = +++ CpuFeatures_StringView_PopFront(reader->view, eol_index + 1); +++ break; +++ } +++ } +++ } +++} +++ +++static LineResult CreateLineResult(bool eof, bool full_line, StringView view) { +++ LineResult result; +++ result.eof = eof; +++ result.full_line = full_line; +++ result.line = view; +++ return result; +++} +++ +++// Helper methods to provide clearer semantic in StackLineReader_NextLine. +++static LineResult CreateEOFLineResult(StringView view) { +++ return CreateLineResult(true, true, view); +++} +++ +++static LineResult CreateTruncatedLineResult(StringView view) { +++ return CreateLineResult(false, false, view); +++} +++ +++static LineResult CreateValidLineResult(StringView view) { +++ return CreateLineResult(false, true, view); +++} +++ +++LineResult StackLineReader_NextLine(StackLineReader* reader) { +++ if (reader->skip_mode) { +++ SkipToNextLine(reader); +++ reader->skip_mode = false; +++ } +++ { +++ const bool can_load_more = +++ reader->view.size < STACK_LINE_READER_BUFFER_SIZE; +++ int eol_index = IndexOfEol(reader); +++ if (eol_index < 0 && can_load_more) { +++ const int read = BringToFrontAndLoadMore(reader); +++ if (read == 0) { +++ return CreateEOFLineResult(reader->view); +++ } +++ eol_index = IndexOfEol(reader); +++ } +++ if (eol_index < 0) { +++ reader->skip_mode = true; +++ return CreateTruncatedLineResult(reader->view); +++ } +++ { +++ StringView line = +++ CpuFeatures_StringView_KeepFront(reader->view, eol_index); +++ reader->view = +++ CpuFeatures_StringView_PopFront(reader->view, eol_index + 1); +++ return CreateValidLineResult(line); +++ } +++ } +++} diff --cc cpu-features/src/string_view.c index 0000000,0000000,0000000..dc3158f new file mode 100644 --- /dev/null +++ b/cpu-features/src/string_view.c @@@@ -1,0 -1,0 -1,0 +1,182 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#include "internal/string_view.h" +++ +++#include +++#include +++#include +++ +++int CpuFeatures_StringView_IndexOfChar(const StringView view, char c) { +++ if (view.ptr && view.size) { +++ const char* const found = (const char*)memchr(view.ptr, c, view.size); +++ if (found) { +++ return (int)(found - view.ptr); +++ } +++ } +++ return -1; +++} +++ +++int CpuFeatures_StringView_IndexOf(const StringView view, +++ const StringView sub_view) { +++ if (sub_view.size) { +++ StringView remainder = view; +++ while (remainder.size >= sub_view.size) { +++ const int found_index = +++ CpuFeatures_StringView_IndexOfChar(remainder, sub_view.ptr[0]); +++ if (found_index < 0) break; +++ remainder = CpuFeatures_StringView_PopFront(remainder, found_index); +++ if (CpuFeatures_StringView_StartsWith(remainder, sub_view)) { +++ return (int)(remainder.ptr - view.ptr); +++ } +++ remainder = CpuFeatures_StringView_PopFront(remainder, 1); +++ } +++ } +++ return -1; +++} +++ +++bool CpuFeatures_StringView_IsEquals(const StringView a, const StringView b) { +++ if (a.size == b.size) { +++ return a.ptr == b.ptr || memcmp(a.ptr, b.ptr, b.size) == 0; +++ } +++ return false; +++} +++ +++bool CpuFeatures_StringView_StartsWith(const StringView a, const StringView b) { +++ return a.ptr && b.ptr && b.size && a.size >= b.size +++ ? memcmp(a.ptr, b.ptr, b.size) == 0 +++ : false; +++} +++ +++StringView CpuFeatures_StringView_PopFront(const StringView str_view, +++ size_t count) { +++ if (count > str_view.size) { +++ return kEmptyStringView; +++ } +++ return view(str_view.ptr + count, str_view.size - count); +++} +++ +++StringView CpuFeatures_StringView_PopBack(const StringView str_view, +++ size_t count) { +++ if (count > str_view.size) { +++ return kEmptyStringView; +++ } +++ return view(str_view.ptr, str_view.size - count); +++} +++ +++StringView CpuFeatures_StringView_KeepFront(const StringView str_view, +++ size_t count) { +++ return count <= str_view.size ? view(str_view.ptr, count) : str_view; +++} +++ +++char CpuFeatures_StringView_Front(const StringView view) { +++ assert(view.size); +++ assert(view.ptr); +++ return view.ptr[0]; +++} +++ +++char CpuFeatures_StringView_Back(const StringView view) { +++ assert(view.size); +++ return view.ptr[view.size - 1]; +++} +++ +++StringView CpuFeatures_StringView_TrimWhitespace(StringView view) { +++ while (view.size && isspace(CpuFeatures_StringView_Front(view))) +++ view = CpuFeatures_StringView_PopFront(view, 1); +++ while (view.size && isspace(CpuFeatures_StringView_Back(view))) +++ view = CpuFeatures_StringView_PopBack(view, 1); +++ return view; +++} +++ +++static int HexValue(const char c) { +++ if (c >= '0' && c <= '9') return c - '0'; +++ if (c >= 'a' && c <= 'f') return c - 'a' + 10; +++ if (c >= 'A' && c <= 'F') return c - 'A' + 10; +++ return -1; +++} +++ +++// Returns -1 if view contains non digits. +++static int ParsePositiveNumberWithBase(const StringView view, int base) { +++ int result = 0; +++ StringView remainder = view; +++ for (; remainder.size; +++ remainder = CpuFeatures_StringView_PopFront(remainder, 1)) { +++ const int value = HexValue(CpuFeatures_StringView_Front(remainder)); +++ if (value < 0 || value >= base) return -1; +++ result = (result * base) + value; +++ } +++ return result; +++} +++ +++int CpuFeatures_StringView_ParsePositiveNumber(const StringView view) { +++ if (view.size) { +++ const StringView hex_prefix = str("0x"); +++ if (CpuFeatures_StringView_StartsWith(view, hex_prefix)) { +++ const StringView span_no_prefix = +++ CpuFeatures_StringView_PopFront(view, hex_prefix.size); +++ return ParsePositiveNumberWithBase(span_no_prefix, 16); +++ } +++ return ParsePositiveNumberWithBase(view, 10); +++ } +++ return -1; +++} +++ +++void CpuFeatures_StringView_CopyString(const StringView src, char* dst, +++ size_t dst_size) { +++ if (dst_size > 0) { +++ const size_t max_copy_size = dst_size - 1; +++ const size_t copy_size = +++ src.size > max_copy_size ? max_copy_size : src.size; +++ memcpy(dst, src.ptr, copy_size); +++ dst[copy_size] = '\0'; +++ } +++} +++ +++bool CpuFeatures_StringView_HasWord(const StringView line, +++ const char* const word_str) { +++ const StringView word = str(word_str); +++ StringView remainder = line; +++ for (;;) { +++ const int index_of_word = CpuFeatures_StringView_IndexOf(remainder, word); +++ if (index_of_word < 0) { +++ return false; +++ } else { +++ const StringView before = +++ CpuFeatures_StringView_KeepFront(line, index_of_word); +++ const StringView after = +++ CpuFeatures_StringView_PopFront(line, index_of_word + word.size); +++ const bool valid_before = +++ before.size == 0 || CpuFeatures_StringView_Back(before) == ' '; +++ const bool valid_after = +++ after.size == 0 || CpuFeatures_StringView_Front(after) == ' '; +++ if (valid_before && valid_after) return true; +++ remainder = +++ CpuFeatures_StringView_PopFront(remainder, index_of_word + word.size); +++ } +++ } +++ return false; +++} +++ +++bool CpuFeatures_StringView_GetAttributeKeyValue(const StringView line, +++ StringView* key, +++ StringView* value) { +++ const StringView sep = str(": "); +++ const int index_of_separator = CpuFeatures_StringView_IndexOf(line, sep); +++ if (index_of_separator < 0) return false; +++ *value = CpuFeatures_StringView_TrimWhitespace( +++ CpuFeatures_StringView_PopFront(line, index_of_separator + sep.size)); +++ *key = CpuFeatures_StringView_TrimWhitespace( +++ CpuFeatures_StringView_KeepFront(line, index_of_separator)); +++ return true; +++} diff --cc cpu-features/src/utils/list_cpu_features.c index 0000000,0000000,0000000..c80ffc5 new file mode 100644 --- /dev/null +++ b/cpu-features/src/utils/list_cpu_features.c @@@@ -1,0 -1,0 -1,0 +1,438 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++// This program dumps current host data to the standard output. +++// Output can be text or json if the `--json` flag is passed. +++ +++#include +++#include +++#include +++#include +++#include +++#include +++#include +++ +++#include "cpu_features_macros.h" +++ +++#if defined(CPU_FEATURES_ARCH_X86) +++#include "cpuinfo_x86.h" +++#elif defined(CPU_FEATURES_ARCH_ARM) +++#include "cpuinfo_arm.h" +++#elif defined(CPU_FEATURES_ARCH_AARCH64) +++#include "cpuinfo_aarch64.h" +++#elif defined(CPU_FEATURES_ARCH_MIPS) +++#include "cpuinfo_mips.h" +++#elif defined(CPU_FEATURES_ARCH_PPC) +++#include "cpuinfo_ppc.h" +++#endif +++ +++// Design principles +++// ----------------- +++// We build a tree structure containing all the data to be displayed. +++// Then depending on the output type (text or json) we walk the tree and display +++// the data accordingly. +++ +++// We use a bump allocator to allocate strings and nodes of the tree, +++// Memory is not intended to be reclaimed. +++typedef struct { +++ char* ptr; +++ size_t size; +++} BumpAllocator; +++ +++char gGlobalBuffer[64 * 1024]; +++BumpAllocator gBumpAllocator = {.ptr = gGlobalBuffer, +++ .size = sizeof(gGlobalBuffer)}; +++ +++static void internal_error() { +++ fputs("internal error\n", stderr); +++ exit(EXIT_FAILURE); +++} +++ +++#define ALIGN 8 +++ +++static void assertAligned() { +++ if ((uintptr_t)(gBumpAllocator.ptr) % ALIGN) internal_error(); +++} +++ +++static void BA_Align() { +++ while (gBumpAllocator.size && (uintptr_t)(gBumpAllocator.ptr) % ALIGN) { +++ --gBumpAllocator.size; +++ ++gBumpAllocator.ptr; +++ } +++ assertAligned(); +++} +++ +++// Update the available memory left in the BumpAllocator. +++static void* BA_Bump(size_t size) { +++ assertAligned(); +++ // Align size to next 8B boundary. +++ size = (size + ALIGN - 1) / ALIGN * ALIGN; +++ if (gBumpAllocator.size < size) internal_error(); +++ void* ptr = gBumpAllocator.ptr; +++ gBumpAllocator.size -= size; +++ gBumpAllocator.ptr += size; +++ return ptr; +++} +++ +++// The type of the nodes in the tree. +++typedef enum { +++ NT_INVALID, +++ NT_INT, +++ NT_MAP, +++ NT_MAP_ENTRY, +++ NT_ARRAY, +++ NT_ARRAY_ELEMENT, +++ NT_STRING, +++} NodeType; +++ +++// The node in the tree. +++typedef struct Node { +++ NodeType type; +++ unsigned integer; +++ const char* string; +++ struct Node* value; +++ struct Node* next; +++} Node; +++ +++// Creates an initialized Node. +++static Node* BA_CreateNode(NodeType type) { +++ Node* tv = (Node*)BA_Bump(sizeof(Node)); +++ assert(tv); +++ *tv = (Node){.type = type}; +++ return tv; +++} +++ +++// Adds an integer node. +++static Node* CreateInt(int value) { +++ Node* tv = BA_CreateNode(NT_INT); +++ tv->integer = value; +++ return tv; +++} +++ +++// Adds a string node. +++// `value` must outlive the tree. +++static Node* CreateConstantString(const char* value) { +++ Node* tv = BA_CreateNode(NT_STRING); +++ tv->string = value; +++ return tv; +++} +++ +++// Adds a map node. +++static Node* CreateMap() { return BA_CreateNode(NT_MAP); } +++ +++// Adds an array node. +++static Node* CreateArray() { return BA_CreateNode(NT_ARRAY); } +++ +++// Adds a formatted string node. +++static Node* CreatePrintfString(const char* format, ...) { +++ va_list arglist; +++ va_start(arglist, format); +++ char* const ptr = gBumpAllocator.ptr; +++ const int written = vsnprintf(ptr, gBumpAllocator.size, format, arglist); +++ va_end(arglist); +++ if (written < 0 || written >= (int)gBumpAllocator.size) internal_error(); +++ return CreateConstantString((char*)BA_Bump(written)); +++} +++ +++// Adds a string node. +++static Node* CreateString(const char* value) { +++ return CreatePrintfString("%s", value); +++} +++ +++// Adds a map entry node. +++static void AddMapEntry(Node* map, const char* key, Node* value) { +++ assert(map && map->type == NT_MAP); +++ Node* current = map; +++ while (current->next) current = current->next; +++ current->next = (Node*)BA_Bump(sizeof(Node)); +++ *current->next = (Node){.type = NT_MAP_ENTRY, .string = key, .value = value}; +++} +++ +++// Adds an array element node. +++static void AddArrayElement(Node* array, Node* value) { +++ assert(array && array->type == NT_ARRAY); +++ Node* current = array; +++ while (current->next) current = current->next; +++ current->next = (Node*)BA_Bump(sizeof(Node)); +++ *current->next = (Node){.type = NT_ARRAY_ELEMENT, .value = value}; +++} +++ +++static int cmp(const void* p1, const void* p2) { +++ return strcmp(*(const char* const*)p1, *(const char* const*)p2); +++} +++ +++#define DEFINE_ADD_FLAGS(HasFeature, FeatureName, FeatureType, LastEnum) \ +++ static void AddFlags(Node* map, const FeatureType* features) { \ +++ size_t i; \ +++ const char* ptrs[LastEnum] = {0}; \ +++ size_t count = 0; \ +++ for (i = 0; i < LastEnum; ++i) { \ +++ if (HasFeature(features, i)) { \ +++ ptrs[count] = FeatureName(i); \ +++ ++count; \ +++ } \ +++ } \ +++ qsort((void*)ptrs, count, sizeof(char*), cmp); \ +++ Node* const array = CreateArray(); \ +++ for (i = 0; i < count; ++i) \ +++ AddArrayElement(array, CreateConstantString(ptrs[i])); \ +++ AddMapEntry(map, "flags", array); \ +++ } +++ +++#if defined(CPU_FEATURES_ARCH_X86) +++DEFINE_ADD_FLAGS(GetX86FeaturesEnumValue, GetX86FeaturesEnumName, X86Features, +++ X86_LAST_) +++#elif defined(CPU_FEATURES_ARCH_ARM) +++DEFINE_ADD_FLAGS(GetArmFeaturesEnumValue, GetArmFeaturesEnumName, ArmFeatures, +++ ARM_LAST_) +++#elif defined(CPU_FEATURES_ARCH_AARCH64) +++DEFINE_ADD_FLAGS(GetAarch64FeaturesEnumValue, GetAarch64FeaturesEnumName, +++ Aarch64Features, AARCH64_LAST_) +++#elif defined(CPU_FEATURES_ARCH_MIPS) +++DEFINE_ADD_FLAGS(GetMipsFeaturesEnumValue, GetMipsFeaturesEnumName, +++ MipsFeatures, MIPS_LAST_) +++#elif defined(CPU_FEATURES_ARCH_PPC) +++DEFINE_ADD_FLAGS(GetPPCFeaturesEnumValue, GetPPCFeaturesEnumName, PPCFeatures, +++ PPC_LAST_) +++#endif +++ +++// Prints a json string with characters escaping. +++static void printJsonString(const char* str) { +++ putchar('"'); +++ for (; str && *str; ++str) { +++ switch (*str) { +++ case '\"': +++ case '\\': +++ case '/': +++ case '\b': +++ case '\f': +++ case '\n': +++ case '\r': +++ case '\t': +++ putchar('\\'); +++ } +++ putchar(*str); +++ } +++ putchar('"'); +++} +++ +++// Walks a Node and print it as json. +++static void printJson(const Node* current) { +++ assert(current); +++ switch (current->type) { +++ case NT_INVALID: +++ break; +++ case NT_INT: +++ printf("%d", current->integer); +++ break; +++ case NT_STRING: +++ printJsonString(current->string); +++ break; +++ case NT_ARRAY: +++ putchar('['); +++ if (current->next) printJson(current->next); +++ putchar(']'); +++ break; +++ case NT_MAP: +++ putchar('{'); +++ if (current->next) printJson(current->next); +++ putchar('}'); +++ break; +++ case NT_MAP_ENTRY: +++ printf("\"%s\":", current->string); +++ printJson(current->value); +++ if (current->next) { +++ putchar(','); +++ printJson(current->next); +++ } +++ break; +++ case NT_ARRAY_ELEMENT: +++ printJson(current->value); +++ if (current->next) { +++ putchar(','); +++ printJson(current->next); +++ } +++ break; +++ } +++} +++ +++// Walks a Node and print it as text. +++static void printTextField(const Node* current) { +++ switch (current->type) { +++ case NT_INVALID: +++ break; +++ case NT_INT: +++ printf("%3d (0x%02X)", current->integer, current->integer); +++ break; +++ case NT_STRING: +++ fputs(current->string, stdout); +++ break; +++ case NT_ARRAY: +++ if (current->next) printTextField(current->next); +++ break; +++ case NT_MAP: +++ if (current->next) { +++ printf("{"); +++ printJson(current->next); +++ printf("}"); +++ } +++ break; +++ case NT_MAP_ENTRY: +++ printf("%-15s : ", current->string); +++ printTextField(current->value); +++ if (current->next) { +++ putchar('\n'); +++ printTextField(current->next); +++ } +++ break; +++ case NT_ARRAY_ELEMENT: +++ printTextField(current->value); +++ if (current->next) { +++ putchar(','); +++ printTextField(current->next); +++ } +++ break; +++ } +++} +++ +++static void printTextRoot(const Node* current) { +++ if (current->type == NT_MAP && current->next) printTextField(current->next); +++} +++ +++static void showUsage(const char* name) { +++ printf( +++ "\n" +++ "Usage: %s [options]\n" +++ " Options:\n" +++ " -h | --help Show help message.\n" +++ " -j | --json Format output as json instead of plain text.\n" +++ "\n", +++ name); +++} +++ +++static Node* GetCacheTypeString(CacheType cache_type) { +++ switch (cache_type) { +++ case CPU_FEATURE_CACHE_NULL: +++ return CreateConstantString("null"); +++ case CPU_FEATURE_CACHE_DATA: +++ return CreateConstantString("data"); +++ case CPU_FEATURE_CACHE_INSTRUCTION: +++ return CreateConstantString("instruction"); +++ case CPU_FEATURE_CACHE_UNIFIED: +++ return CreateConstantString("unified"); +++ case CPU_FEATURE_CACHE_TLB: +++ return CreateConstantString("tlb"); +++ case CPU_FEATURE_CACHE_DTLB: +++ return CreateConstantString("dtlb"); +++ case CPU_FEATURE_CACHE_STLB: +++ return CreateConstantString("stlb"); +++ case CPU_FEATURE_CACHE_PREFETCH: +++ return CreateConstantString("prefetch"); +++ } +++} +++ +++static void AddCacheInfo(Node* root, const CacheInfo* cache_info) { +++ Node* array = CreateArray(); +++ for (int i = 0; i < cache_info->size; ++i) { +++ CacheLevelInfo info = cache_info->levels[i]; +++ Node* map = CreateMap(); +++ AddMapEntry(map, "level", CreateInt(info.level)); +++ AddMapEntry(map, "cache_type", GetCacheTypeString(info.cache_type)); +++ AddMapEntry(map, "cache_size", CreateInt(info.cache_size)); +++ AddMapEntry(map, "ways", CreateInt(info.ways)); +++ AddMapEntry(map, "line_size", CreateInt(info.line_size)); +++ AddMapEntry(map, "tlb_entries", CreateInt(info.tlb_entries)); +++ AddMapEntry(map, "partitioning", CreateInt(info.partitioning)); +++ AddArrayElement(array, map); +++ } +++ AddMapEntry(root, "cache_info", array); +++} +++ +++static Node* CreateTree() { +++ 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, "family", CreateInt(info.family)); +++ AddMapEntry(root, "model", CreateInt(info.model)); +++ AddMapEntry(root, "stepping", CreateInt(info.stepping)); +++ AddMapEntry(root, "uarch", +++ CreateString( +++ GetX86MicroarchitectureName(GetX86Microarchitecture(&info)))); +++ AddFlags(root, &info.features); +++ AddCacheInfo(root, &cache_info); +++#elif defined(CPU_FEATURES_ARCH_ARM) +++ const ArmInfo info = GetArmInfo(); +++ AddMapEntry(root, "arch", CreateString("ARM")); +++ AddMapEntry(root, "implementer", CreateInt(info.implementer)); +++ AddMapEntry(root, "architecture", CreateInt(info.architecture)); +++ AddMapEntry(root, "variant", CreateInt(info.variant)); +++ AddMapEntry(root, "part", CreateInt(info.part)); +++ AddMapEntry(root, "revision", CreateInt(info.revision)); +++ AddFlags(root, &info.features); +++#elif defined(CPU_FEATURES_ARCH_AARCH64) +++ const Aarch64Info info = GetAarch64Info(); +++ AddMapEntry(root, "arch", CreateString("aarch64")); +++ AddMapEntry(root, "implementer", CreateInt(info.implementer)); +++ AddMapEntry(root, "variant", CreateInt(info.variant)); +++ AddMapEntry(root, "part", CreateInt(info.part)); +++ AddMapEntry(root, "revision", CreateInt(info.revision)); +++ AddFlags(root, &info.features); +++#elif defined(CPU_FEATURES_ARCH_MIPS) +++ const MipsInfo info = GetMipsInfo(); +++ AddMapEntry(root, "arch", CreateString("mips")); +++ AddFlags(root, &info.features); +++#elif defined(CPU_FEATURES_ARCH_PPC) +++ const PPCInfo info = GetPPCInfo(); +++ const PPCPlatformStrings strings = GetPPCPlatformStrings(); +++ AddMapEntry(root, "arch", CreateString("ppc")); +++ AddMapEntry(root, "platform", CreateString(strings.platform)); +++ AddMapEntry(root, "model", CreateString(strings.model)); +++ AddMapEntry(root, "machine", CreateString(strings.machine)); +++ AddMapEntry(root, "cpu", CreateString(strings.cpu)); +++ AddMapEntry(root, "instruction", CreateString(strings.type.platform)); +++ AddMapEntry(root, "microarchitecture", +++ CreateString(strings.type.base_platform)); +++ AddFlags(root, &info.features); +++#endif +++ return root; +++} +++ +++int main(int argc, char** argv) { +++ BA_Align(); +++ const Node* const root = CreateTree(); +++ bool outputJson = false; +++ int i = 1; +++ for (; i < argc; ++i) { +++ const char* arg = argv[i]; +++ if (strcmp(arg, "-j") == 0 || strcmp(arg, "--json") == 0) { +++ outputJson = true; +++ } else { +++ showUsage(argv[0]); +++ if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) +++ return EXIT_SUCCESS; +++ return EXIT_FAILURE; +++ } +++ } +++ if (outputJson) +++ printJson(root); +++ else +++ printTextRoot(root); +++ putchar('\n'); +++ return EXIT_SUCCESS; +++} diff --cc cpu-features/test/CMakeLists.txt index 0000000,0000000,0000000..c10e617 new file mode 100644 --- /dev/null +++ b/cpu-features/test/CMakeLists.txt @@@@ -1,0 -1,0 -1,0 +1,85 @@@@ +++# +++# libraries for tests +++# +++ +++include_directories(../include) +++add_definitions(-DCPU_FEATURES_TEST) +++ +++##------------------------------------------------------------------------------ +++add_library(string_view ../src/string_view.c) +++##------------------------------------------------------------------------------ +++add_library(filesystem_for_testing filesystem_for_testing.cc) +++target_compile_definitions(filesystem_for_testing PUBLIC CPU_FEATURES_MOCK_FILESYSTEM) +++##------------------------------------------------------------------------------ +++add_library(hwcaps_for_testing hwcaps_for_testing.cc) +++target_link_libraries(hwcaps_for_testing filesystem_for_testing) +++##------------------------------------------------------------------------------ +++add_library(stack_line_reader ../src/stack_line_reader.c) +++target_compile_definitions(stack_line_reader PUBLIC STACK_LINE_READER_BUFFER_SIZE=1024) +++target_link_libraries(stack_line_reader string_view) +++##------------------------------------------------------------------------------ +++add_library(stack_line_reader_for_test ../src/stack_line_reader.c) +++target_compile_definitions(stack_line_reader_for_test PUBLIC STACK_LINE_READER_BUFFER_SIZE=16) +++target_link_libraries(stack_line_reader_for_test string_view filesystem_for_testing) +++##------------------------------------------------------------------------------ +++add_library(all_libraries ../src/hwcaps.c ../src/stack_line_reader.c) +++target_link_libraries(all_libraries hwcaps_for_testing stack_line_reader string_view) +++ +++# +++# tests +++# +++link_libraries(gtest gmock_main) +++ +++## bit_utils_test +++add_executable(bit_utils_test bit_utils_test.cc) +++target_link_libraries(bit_utils_test) +++add_test(NAME bit_utils_test COMMAND bit_utils_test) +++##------------------------------------------------------------------------------ +++## string_view_test +++add_executable(string_view_test string_view_test.cc ../src/string_view.c) +++target_link_libraries(string_view_test string_view) +++add_test(NAME string_view_test COMMAND string_view_test) +++##------------------------------------------------------------------------------ +++## stack_line_reader_test +++add_executable(stack_line_reader_test stack_line_reader_test.cc) +++target_link_libraries(stack_line_reader_test stack_line_reader_for_test) +++add_test(NAME stack_line_reader_test COMMAND stack_line_reader_test) +++##------------------------------------------------------------------------------ +++## cpuinfo_x86_test +++if(PROCESSOR_IS_X86) +++ add_executable(cpuinfo_x86_test cpuinfo_x86_test.cc ../src/cpuinfo_x86.c) +++ target_compile_definitions(cpuinfo_x86_test PUBLIC CPU_FEATURES_MOCK_CPUID_X86) +++ if(APPLE) +++ target_compile_definitions(cpuinfo_x86_test PRIVATE HAVE_SYSCTLBYNAME) +++ endif() +++ target_link_libraries(cpuinfo_x86_test all_libraries) +++ add_test(NAME cpuinfo_x86_test COMMAND cpuinfo_x86_test) +++endif() +++##------------------------------------------------------------------------------ +++## cpuinfo_arm_test +++if(PROCESSOR_IS_ARM) +++ add_executable(cpuinfo_arm_test cpuinfo_arm_test.cc ../src/cpuinfo_arm.c) +++ target_link_libraries(cpuinfo_arm_test all_libraries) +++ add_test(NAME cpuinfo_arm_test COMMAND cpuinfo_arm_test) +++endif() +++##------------------------------------------------------------------------------ +++## cpuinfo_aarch64_test +++if(PROCESSOR_IS_AARCH64) +++ add_executable(cpuinfo_aarch64_test cpuinfo_aarch64_test.cc ../src/cpuinfo_aarch64.c) +++ target_link_libraries(cpuinfo_aarch64_test all_libraries) +++ add_test(NAME cpuinfo_aarch64_test COMMAND cpuinfo_aarch64_test) +++endif() +++##------------------------------------------------------------------------------ +++## cpuinfo_mips_test +++if(PROCESSOR_IS_MIPS) +++ add_executable(cpuinfo_mips_test cpuinfo_mips_test.cc ../src/cpuinfo_mips.c) +++ target_link_libraries(cpuinfo_mips_test all_libraries) +++ add_test(NAME cpuinfo_mips_test COMMAND cpuinfo_mips_test) +++endif() +++##------------------------------------------------------------------------------ +++## cpuinfo_ppc_test +++if(PROCESSOR_IS_POWER) +++ add_executable(cpuinfo_ppc_test cpuinfo_ppc_test.cc ../src/cpuinfo_ppc.c) +++ target_link_libraries(cpuinfo_ppc_test all_libraries) +++ add_test(NAME cpuinfo_ppc_test COMMAND cpuinfo_ppc_test) +++endif() diff --cc cpu-features/test/bit_utils_test.cc index 0000000,0000000,0000000..3874e13 new file mode 100644 --- /dev/null +++ b/cpu-features/test/bit_utils_test.cc @@@@ -1,0 -1,0 -1,0 +1,53 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#include "internal/bit_utils.h" +++ +++#include "gtest/gtest.h" +++ +++namespace cpu_features { +++namespace { +++ +++TEST(UtilsTest, IsBitSet) { +++ for (size_t bit_set = 0; bit_set < 32; ++bit_set) { +++ const uint32_t value = 1UL << bit_set; +++ for (uint32_t i = 0; i < 32; ++i) { +++ EXPECT_EQ(IsBitSet(value, i), i == bit_set); +++ } +++ } +++ +++ // testing 0, all bits should be 0. +++ for (uint32_t i = 0; i < 32; ++i) { +++ EXPECT_FALSE(IsBitSet(0, i)); +++ } +++ +++ // testing ~0, all bits should be 1. +++ for (uint32_t i = 0; i < 32; ++i) { +++ EXPECT_TRUE(IsBitSet(-1, i)); +++ } +++} +++ +++TEST(UtilsTest, ExtractBitRange) { +++ // Extracting all bits gives the same number. +++ EXPECT_EQ(ExtractBitRange(123, 31, 0), 123); +++ // Extracting 1 bit gives parity. +++ EXPECT_EQ(ExtractBitRange(123, 0, 0), 1); +++ EXPECT_EQ(ExtractBitRange(122, 0, 0), 0); +++ +++ EXPECT_EQ(ExtractBitRange(0xF0, 7, 4), 0xF); +++ EXPECT_EQ(ExtractBitRange(0x42 << 2, 10, 2), 0x42); +++} +++ +++} // namespace +++} // namespace cpu_features diff --cc cpu-features/test/cpuinfo_aarch64_test.cc index 0000000,0000000,0000000..5afaaa8 new file mode 100644 --- /dev/null +++ b/cpu-features/test/cpuinfo_aarch64_test.cc @@@@ -1,0 -1,0 -1,0 +1,171 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#include "cpuinfo_aarch64.h" +++ +++#include "filesystem_for_testing.h" +++#include "gtest/gtest.h" +++#include "hwcaps_for_testing.h" +++ +++namespace cpu_features { +++namespace { +++ +++void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); } +++ +++TEST(CpuinfoAarch64Test, FromHardwareCap) { +++ SetHardwareCapabilities(AARCH64_HWCAP_FP | AARCH64_HWCAP_AES, 0); +++ GetEmptyFilesystem(); // disabling /proc/cpuinfo +++ const auto info = GetAarch64Info(); +++ EXPECT_TRUE(info.features.fp); +++ EXPECT_FALSE(info.features.asimd); +++ EXPECT_FALSE(info.features.evtstrm); +++ EXPECT_TRUE(info.features.aes); +++ EXPECT_FALSE(info.features.pmull); +++ EXPECT_FALSE(info.features.sha1); +++ EXPECT_FALSE(info.features.sha2); +++ EXPECT_FALSE(info.features.crc32); +++ EXPECT_FALSE(info.features.atomics); +++ EXPECT_FALSE(info.features.fphp); +++ EXPECT_FALSE(info.features.asimdhp); +++ EXPECT_FALSE(info.features.cpuid); +++ EXPECT_FALSE(info.features.asimdrdm); +++ EXPECT_FALSE(info.features.jscvt); +++ EXPECT_FALSE(info.features.fcma); +++ EXPECT_FALSE(info.features.lrcpc); +++ EXPECT_FALSE(info.features.dcpop); +++ EXPECT_FALSE(info.features.sha3); +++ EXPECT_FALSE(info.features.sm3); +++ EXPECT_FALSE(info.features.sm4); +++ EXPECT_FALSE(info.features.asimddp); +++ EXPECT_FALSE(info.features.sha512); +++ EXPECT_FALSE(info.features.sve); +++ EXPECT_FALSE(info.features.asimdfhm); +++ EXPECT_FALSE(info.features.dit); +++ EXPECT_FALSE(info.features.uscat); +++ EXPECT_FALSE(info.features.ilrcpc); +++ EXPECT_FALSE(info.features.flagm); +++ EXPECT_FALSE(info.features.ssbs); +++ EXPECT_FALSE(info.features.sb); +++ EXPECT_FALSE(info.features.paca); +++ EXPECT_FALSE(info.features.pacg); +++} +++ +++TEST(CpuinfoAarch64Test, FromHardwareCap2) { +++ SetHardwareCapabilities(AARCH64_HWCAP_FP, +++ AARCH64_HWCAP2_SVE2 | AARCH64_HWCAP2_BTI); +++ GetEmptyFilesystem(); // disabling /proc/cpuinfo +++ const auto info = GetAarch64Info(); +++ EXPECT_TRUE(info.features.fp); +++ +++ EXPECT_TRUE(info.features.sve2); +++ EXPECT_TRUE(info.features.bti); +++ +++ EXPECT_FALSE(info.features.dcpodp); +++ EXPECT_FALSE(info.features.sveaes); +++ EXPECT_FALSE(info.features.svepmull); +++ EXPECT_FALSE(info.features.svebitperm); +++ EXPECT_FALSE(info.features.svesha3); +++ EXPECT_FALSE(info.features.svesm4); +++ EXPECT_FALSE(info.features.flagm2); +++ EXPECT_FALSE(info.features.frint); +++ EXPECT_FALSE(info.features.svei8mm); +++ EXPECT_FALSE(info.features.svef32mm); +++ EXPECT_FALSE(info.features.svef64mm); +++ EXPECT_FALSE(info.features.svebf16); +++ EXPECT_FALSE(info.features.i8mm); +++ EXPECT_FALSE(info.features.bf16); +++ EXPECT_FALSE(info.features.dgh); +++ EXPECT_FALSE(info.features.rng); +++} +++ +++TEST(CpuinfoAarch64Test, ARMCortexA53) { +++ DisableHardwareCapabilities(); +++ auto& fs = GetEmptyFilesystem(); +++ fs.CreateFile("/proc/cpuinfo", +++ R"(Processor : AArch64 Processor rev 3 (aarch64) +++processor : 0 +++processor : 1 +++processor : 2 +++processor : 3 +++processor : 4 +++processor : 5 +++processor : 6 +++processor : 7 +++Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 +++CPU implementer : 0x41 +++CPU architecture: AArch64 +++CPU variant : 0x0 +++CPU part : 0xd03 +++CPU revision : 3)"); +++ const auto info = GetAarch64Info(); +++ EXPECT_EQ(info.implementer, 0x41); +++ EXPECT_EQ(info.variant, 0x0); +++ EXPECT_EQ(info.part, 0xd03); +++ EXPECT_EQ(info.revision, 3); +++ +++ EXPECT_TRUE(info.features.fp); +++ EXPECT_TRUE(info.features.asimd); +++ EXPECT_TRUE(info.features.evtstrm); +++ EXPECT_TRUE(info.features.aes); +++ EXPECT_TRUE(info.features.pmull); +++ EXPECT_TRUE(info.features.sha1); +++ EXPECT_TRUE(info.features.sha2); +++ EXPECT_TRUE(info.features.crc32); +++ +++ EXPECT_FALSE(info.features.atomics); +++ EXPECT_FALSE(info.features.fphp); +++ EXPECT_FALSE(info.features.asimdhp); +++ EXPECT_FALSE(info.features.cpuid); +++ EXPECT_FALSE(info.features.asimdrdm); +++ EXPECT_FALSE(info.features.jscvt); +++ EXPECT_FALSE(info.features.fcma); +++ EXPECT_FALSE(info.features.lrcpc); +++ EXPECT_FALSE(info.features.dcpop); +++ EXPECT_FALSE(info.features.sha3); +++ EXPECT_FALSE(info.features.sm3); +++ EXPECT_FALSE(info.features.sm4); +++ EXPECT_FALSE(info.features.asimddp); +++ EXPECT_FALSE(info.features.sha512); +++ EXPECT_FALSE(info.features.sve); +++ EXPECT_FALSE(info.features.asimdfhm); +++ EXPECT_FALSE(info.features.dit); +++ EXPECT_FALSE(info.features.uscat); +++ EXPECT_FALSE(info.features.ilrcpc); +++ EXPECT_FALSE(info.features.flagm); +++ EXPECT_FALSE(info.features.ssbs); +++ EXPECT_FALSE(info.features.sb); +++ EXPECT_FALSE(info.features.paca); +++ EXPECT_FALSE(info.features.pacg); +++ EXPECT_FALSE(info.features.dcpodp); +++ EXPECT_FALSE(info.features.sve2); +++ EXPECT_FALSE(info.features.sveaes); +++ EXPECT_FALSE(info.features.svepmull); +++ EXPECT_FALSE(info.features.svebitperm); +++ EXPECT_FALSE(info.features.svesha3); +++ EXPECT_FALSE(info.features.svesm4); +++ EXPECT_FALSE(info.features.flagm2); +++ EXPECT_FALSE(info.features.frint); +++ EXPECT_FALSE(info.features.svei8mm); +++ EXPECT_FALSE(info.features.svef32mm); +++ EXPECT_FALSE(info.features.svef64mm); +++ EXPECT_FALSE(info.features.svebf16); +++ EXPECT_FALSE(info.features.i8mm); +++ EXPECT_FALSE(info.features.bf16); +++ EXPECT_FALSE(info.features.dgh); +++ EXPECT_FALSE(info.features.rng); +++ EXPECT_FALSE(info.features.bti); +++} +++ +++} // namespace +++} // namespace cpu_features diff --cc cpu-features/test/cpuinfo_arm_test.cc index 0000000,0000000,0000000..e0b08a4 new file mode 100644 --- /dev/null +++ b/cpu-features/test/cpuinfo_arm_test.cc @@@@ -1,0 -1,0 -1,0 +1,354 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#include "cpuinfo_arm.h" +++ +++#include "filesystem_for_testing.h" +++#include "gtest/gtest.h" +++#include "hwcaps_for_testing.h" +++ +++namespace cpu_features { +++namespace { +++ +++void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); } +++ +++TEST(CpuinfoArmTest, FromHardwareCap) { +++ SetHardwareCapabilities(ARM_HWCAP_NEON, ARM_HWCAP2_AES | ARM_HWCAP2_CRC32); +++ GetEmptyFilesystem(); // disabling /proc/cpuinfo +++ const auto info = GetArmInfo(); +++ EXPECT_TRUE(info.features.vfp); // triggered by vfpv3 +++ EXPECT_TRUE(info.features.vfpv3); // triggered by neon +++ EXPECT_TRUE(info.features.neon); +++ EXPECT_TRUE(info.features.aes); +++ EXPECT_TRUE(info.features.crc32); +++ +++ EXPECT_FALSE(info.features.vfpv4); +++ EXPECT_FALSE(info.features.iwmmxt); +++ EXPECT_FALSE(info.features.crunch); +++ EXPECT_FALSE(info.features.thumbee); +++ EXPECT_FALSE(info.features.vfpv3d16); +++ EXPECT_FALSE(info.features.idiva); +++ EXPECT_FALSE(info.features.idivt); +++ EXPECT_FALSE(info.features.pmull); +++ EXPECT_FALSE(info.features.sha1); +++ EXPECT_FALSE(info.features.sha2); +++ +++ // check some random features with EnumValue(): +++ EXPECT_TRUE(GetArmFeaturesEnumValue(&info.features, ARM_VFP)); +++ EXPECT_FALSE(GetArmFeaturesEnumValue(&info.features, ARM_VFPV4)); +++ // out of bound EnumValue() check +++ EXPECT_FALSE(GetArmFeaturesEnumValue(&info.features, (ArmFeaturesEnum)~0x0)); +++} +++ +++TEST(CpuinfoArmTest, ODroidFromCpuInfo) { +++ DisableHardwareCapabilities(); +++ auto& fs = GetEmptyFilesystem(); +++ fs.CreateFile("/proc/cpuinfo", R"(processor : 0 +++model name : ARMv7 Processor rev 3 (v71) +++BogoMIPS : 120.00 +++Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae +++CPU implementer : 0x41 +++CPU architecture: 7 +++CPU variant : 0x2 +++CPU part : 0xc0f +++CPU revision : 3)"); +++ const auto info = GetArmInfo(); +++ EXPECT_EQ(info.implementer, 0x41); +++ EXPECT_EQ(info.variant, 0x2); +++ EXPECT_EQ(info.part, 0xc0f); +++ EXPECT_EQ(info.revision, 3); +++ EXPECT_EQ(info.architecture, 7); +++ +++ EXPECT_FALSE(info.features.swp); +++ EXPECT_TRUE(info.features.half); +++ EXPECT_TRUE(info.features.thumb); +++ EXPECT_FALSE(info.features._26bit); +++ EXPECT_TRUE(info.features.fastmult); +++ EXPECT_FALSE(info.features.fpa); +++ EXPECT_TRUE(info.features.vfp); +++ EXPECT_TRUE(info.features.edsp); +++ EXPECT_FALSE(info.features.java); +++ EXPECT_FALSE(info.features.iwmmxt); +++ EXPECT_FALSE(info.features.crunch); +++ EXPECT_FALSE(info.features.thumbee); +++ EXPECT_TRUE(info.features.neon); +++ EXPECT_TRUE(info.features.vfpv3); +++ EXPECT_FALSE(info.features.vfpv3d16); +++ EXPECT_TRUE(info.features.tls); +++ EXPECT_TRUE(info.features.vfpv4); +++ EXPECT_TRUE(info.features.idiva); +++ EXPECT_TRUE(info.features.idivt); +++ EXPECT_TRUE(info.features.vfpd32); +++ EXPECT_TRUE(info.features.lpae); +++ EXPECT_FALSE(info.features.evtstrm); +++ EXPECT_FALSE(info.features.aes); +++ EXPECT_FALSE(info.features.pmull); +++ EXPECT_FALSE(info.features.sha1); +++ EXPECT_FALSE(info.features.sha2); +++ EXPECT_FALSE(info.features.crc32); +++} +++ +++// Linux test-case +++TEST(CpuinfoArmTest, RaspberryPiZeroFromCpuInfo) { +++ DisableHardwareCapabilities(); +++ auto& fs = GetEmptyFilesystem(); +++ fs.CreateFile("/proc/cpuinfo", R"(processor : 0 +++model name : ARMv6-compatible processor rev 7 (v6l) +++BogoMIPS : 697.95 +++Features : half thumb fastmult vfp edsp java tls +++CPU implementer : 0x41 +++CPU architecture: 7 +++CPU variant : 0x0 +++CPU part : 0xb76 +++CPU revision : 7 +++ +++Hardware : BCM2835 +++Revision : 9000c1 +++Serial : 000000006cd946f3)"); +++ const auto info = GetArmInfo(); +++ EXPECT_EQ(info.implementer, 0x41); +++ EXPECT_EQ(info.variant, 0x0); +++ EXPECT_EQ(info.part, 0xb76); +++ EXPECT_EQ(info.revision, 7); +++ EXPECT_EQ(info.architecture, 6); +++ +++ EXPECT_FALSE(info.features.swp); +++ EXPECT_TRUE(info.features.half); +++ EXPECT_TRUE(info.features.thumb); +++ EXPECT_FALSE(info.features._26bit); +++ EXPECT_TRUE(info.features.fastmult); +++ EXPECT_FALSE(info.features.fpa); +++ EXPECT_TRUE(info.features.vfp); +++ EXPECT_TRUE(info.features.edsp); +++ EXPECT_TRUE(info.features.java); +++ EXPECT_FALSE(info.features.iwmmxt); +++ EXPECT_FALSE(info.features.crunch); +++ EXPECT_FALSE(info.features.thumbee); +++ EXPECT_FALSE(info.features.neon); +++ EXPECT_FALSE(info.features.vfpv3); +++ EXPECT_FALSE(info.features.vfpv3d16); +++ EXPECT_TRUE(info.features.tls); +++ EXPECT_FALSE(info.features.vfpv4); +++ EXPECT_FALSE(info.features.idiva); +++ EXPECT_FALSE(info.features.idivt); +++ EXPECT_FALSE(info.features.vfpd32); +++ EXPECT_FALSE(info.features.lpae); +++ EXPECT_FALSE(info.features.evtstrm); +++ EXPECT_FALSE(info.features.aes); +++ EXPECT_FALSE(info.features.pmull); +++ EXPECT_FALSE(info.features.sha1); +++ EXPECT_FALSE(info.features.sha2); +++ EXPECT_FALSE(info.features.crc32); +++} +++ +++TEST(CpuinfoArmTest, MarvellArmadaFromCpuInfo) { +++ DisableHardwareCapabilities(); +++ auto& fs = GetEmptyFilesystem(); +++ fs.CreateFile("/proc/cpuinfo", R"(processor : 0 +++model name : ARMv7 Processor rev 1 (v7l) +++BogoMIPS : 50.00 +++Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpd32 +++CPU implementer : 0x41 +++CPU architecture: 7 +++CPU variant : 0x4 +++CPU part : 0xc09 +++CPU revision : 1 +++ +++processor : 1 +++model name : ARMv7 Processor rev 1 (v7l) +++BogoMIPS : 50.00 +++Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpd32 +++CPU implementer : 0x41 +++CPU architecture: 7 +++CPU variant : 0x4 +++CPU part : 0xc09 +++CPU revision : 1 +++ +++Hardware : Marvell Armada 380/385 (Device Tree) +++Revision : 0000 +++Serial : 0000000000000000)"); +++ const auto info = GetArmInfo(); +++ EXPECT_EQ(info.implementer, 0x41); +++ EXPECT_EQ(info.variant, 0x4); +++ EXPECT_EQ(info.part, 0xc09); +++ EXPECT_EQ(info.revision, 1); +++ EXPECT_EQ(info.architecture, 7); +++ +++ EXPECT_FALSE(info.features.swp); +++ EXPECT_TRUE(info.features.half); +++ EXPECT_TRUE(info.features.thumb); +++ EXPECT_FALSE(info.features._26bit); +++ EXPECT_TRUE(info.features.fastmult); +++ EXPECT_FALSE(info.features.fpa); +++ EXPECT_TRUE(info.features.vfp); +++ EXPECT_TRUE(info.features.edsp); +++ EXPECT_FALSE(info.features.java); +++ EXPECT_FALSE(info.features.iwmmxt); +++ EXPECT_FALSE(info.features.crunch); +++ EXPECT_FALSE(info.features.thumbee); +++ EXPECT_TRUE(info.features.neon); +++ EXPECT_TRUE(info.features.vfpv3); +++ EXPECT_FALSE(info.features.vfpv3d16); +++ EXPECT_TRUE(info.features.tls); +++ EXPECT_FALSE(info.features.vfpv4); +++ EXPECT_FALSE(info.features.idiva); +++ EXPECT_FALSE(info.features.idivt); +++ EXPECT_TRUE(info.features.vfpd32); +++ EXPECT_FALSE(info.features.lpae); +++ EXPECT_FALSE(info.features.evtstrm); +++ EXPECT_FALSE(info.features.aes); +++ EXPECT_FALSE(info.features.pmull); +++ EXPECT_FALSE(info.features.sha1); +++ EXPECT_FALSE(info.features.sha2); +++ EXPECT_FALSE(info.features.crc32); +++} +++ +++// Android test-case +++// http://code.google.com/p/android/issues/detail?id=10812 +++TEST(CpuinfoArmTest, InvalidArmv7) { +++ DisableHardwareCapabilities(); +++ auto& fs = GetEmptyFilesystem(); +++ fs.CreateFile("/proc/cpuinfo", +++ R"(Processor : ARMv6-compatible processor rev 6 (v6l) +++BogoMIPS : 199.47 +++Features : swp half thumb fastmult vfp edsp java +++CPU implementer : 0x41 +++CPU architecture: 7 +++CPU variant : 0x0 +++CPU part : 0xb76 +++CPU revision : 6 +++ +++Hardware : SPICA +++Revision : 0020 +++Serial : 33323613546d00ec )"); +++ const auto info = GetArmInfo(); +++ EXPECT_EQ(info.architecture, 6); +++ +++ EXPECT_TRUE(info.features.swp); +++ EXPECT_TRUE(info.features.half); +++ EXPECT_TRUE(info.features.thumb); +++ EXPECT_FALSE(info.features._26bit); +++ EXPECT_TRUE(info.features.fastmult); +++ EXPECT_FALSE(info.features.fpa); +++ EXPECT_TRUE(info.features.vfp); +++ EXPECT_TRUE(info.features.edsp); +++ EXPECT_TRUE(info.features.java); +++ EXPECT_FALSE(info.features.iwmmxt); +++ EXPECT_FALSE(info.features.crunch); +++ EXPECT_FALSE(info.features.thumbee); +++ EXPECT_FALSE(info.features.neon); +++ EXPECT_FALSE(info.features.vfpv3); +++ EXPECT_FALSE(info.features.vfpv3d16); +++ EXPECT_FALSE(info.features.tls); +++ EXPECT_FALSE(info.features.vfpv4); +++ EXPECT_FALSE(info.features.idiva); +++ EXPECT_FALSE(info.features.idivt); +++ EXPECT_FALSE(info.features.vfpd32); +++ EXPECT_FALSE(info.features.lpae); +++ EXPECT_FALSE(info.features.evtstrm); +++ EXPECT_FALSE(info.features.aes); +++ EXPECT_FALSE(info.features.pmull); +++ EXPECT_FALSE(info.features.sha1); +++ EXPECT_FALSE(info.features.sha2); +++ EXPECT_FALSE(info.features.crc32); +++} +++ +++// Android test-case +++// https://crbug.com/341598. +++TEST(CpuinfoArmTest, InvalidNeon) { +++ auto& fs = GetEmptyFilesystem(); +++ fs.CreateFile("/proc/cpuinfo", +++ R"(Processor: ARMv7 Processory rev 0 (v71) +++processor: 0 +++BogoMIPS: 13.50 +++ +++Processor: 1 +++BogoMIPS: 13.50 +++ +++Features: swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt +++CPU implementer : 0x51 +++CPU architecture: 7 +++CPU variant: 0x1 +++CPU part: 0x04d +++CPU revision: 0 +++ +++Hardware: SAMSUNG M2 +++Revision: 0010 +++Serial: 00001e030000354e)"); +++ const auto info = GetArmInfo(); +++ EXPECT_TRUE(info.features.swp); +++ EXPECT_FALSE(info.features.neon); +++} +++ +++// The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report IDIV +++// support. +++TEST(CpuinfoArmTest, Nexus4_0x510006f2) { +++ DisableHardwareCapabilities(); +++ auto& fs = GetEmptyFilesystem(); +++ fs.CreateFile("/proc/cpuinfo", +++ R"(CPU implementer : 0x51 +++CPU architecture: 7 +++CPU variant : 0x0 +++CPU part : 0x6f +++CPU revision : 2)"); +++ const auto info = GetArmInfo(); +++ EXPECT_TRUE(info.features.idiva); +++ EXPECT_TRUE(info.features.idivt); +++ +++ EXPECT_EQ(GetArmCpuId(&info), 0x510006f2); +++} +++ +++// The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report IDIV +++// support. +++TEST(CpuinfoArmTest, Nexus4_0x510006f3) { +++ DisableHardwareCapabilities(); +++ auto& fs = GetEmptyFilesystem(); +++ fs.CreateFile("/proc/cpuinfo", +++ R"(CPU implementer : 0x51 +++CPU architecture: 7 +++CPU variant : 0x0 +++CPU part : 0x6f +++CPU revision : 3)"); +++ const auto info = GetArmInfo(); +++ EXPECT_TRUE(info.features.idiva); +++ EXPECT_TRUE(info.features.idivt); +++ +++ EXPECT_EQ(GetArmCpuId(&info), 0x510006f3); +++} +++ +++// The emulator-specific Android 4.2 kernel fails to report support for the +++// 32-bit ARM IDIV instruction. Technically, this is a feature of the virtual +++// CPU implemented by the emulator. +++TEST(CpuinfoArmTest, EmulatorSpecificIdiv) { +++ DisableHardwareCapabilities(); +++ auto& fs = GetEmptyFilesystem(); +++ fs.CreateFile("/proc/cpuinfo", +++ R"(Processor : ARMv7 Processor rev 0 (v7l) +++BogoMIPS : 629.14 +++Features : swp half thumb fastmult vfp edsp neon vfpv3 +++CPU implementer : 0x41 +++CPU architecture: 7 +++CPU variant : 0x0 +++CPU part : 0xc08 +++CPU revision : 0 +++ +++Hardware : Goldfish +++Revision : 0000 +++Serial : 0000000000000000)"); +++ const auto info = GetArmInfo(); +++ EXPECT_TRUE(info.features.idiva); +++} +++ +++} // namespace +++} // namespace cpu_features diff --cc cpu-features/test/cpuinfo_mips_test.cc index 0000000,0000000,0000000..d734058 new file mode 100644 --- /dev/null +++ b/cpu-features/test/cpuinfo_mips_test.cc @@@@ -1,0 -1,0 -1,0 +1,126 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#include "cpuinfo_mips.h" +++ +++#include "filesystem_for_testing.h" +++#include "gtest/gtest.h" +++#include "hwcaps_for_testing.h" +++#include "internal/stack_line_reader.h" +++#include "internal/string_view.h" +++ +++namespace cpu_features { +++ +++namespace { +++ +++void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); } +++ +++TEST(CpuinfoMipsTest, FromHardwareCapBoth) { +++ SetHardwareCapabilities(MIPS_HWCAP_MSA | MIPS_HWCAP_R6, 0); +++ GetEmptyFilesystem(); // disabling /proc/cpuinfo +++ const auto info = GetMipsInfo(); +++ EXPECT_TRUE(info.features.msa); +++ EXPECT_FALSE(info.features.eva); +++ EXPECT_TRUE(info.features.r6); +++} +++ +++TEST(CpuinfoMipsTest, FromHardwareCapOnlyOne) { +++ SetHardwareCapabilities(MIPS_HWCAP_MSA, 0); +++ GetEmptyFilesystem(); // disabling /proc/cpuinfo +++ const auto info = GetMipsInfo(); +++ EXPECT_TRUE(info.features.msa); +++ EXPECT_FALSE(info.features.eva); +++} +++ +++TEST(CpuinfoMipsTest, Ci40) { +++ DisableHardwareCapabilities(); +++ auto& fs = GetEmptyFilesystem(); +++ fs.CreateFile("/proc/cpuinfo", R"(system type : IMG Pistachio SoC (B0) +++machine : IMG Marduk – Ci40 with cc2520 +++processor : 0 +++cpu model : MIPS interAptiv (multi) V2.0 FPU V0.0 +++BogoMIPS : 363.72 +++wait instruction : yes +++microsecond timers : yes +++tlb_entries : 64 +++extra interrupt vector : yes +++hardware watchpoint : yes, count: 4, address/irw mask: [0x0ffc, 0x0ffc, 0x0ffb, 0x0ffb] +++isa : mips1 mips2 mips32r1 mips32r2 +++ASEs implemented : mips16 dsp mt eva +++shadow register sets : 1 +++kscratch registers : 0 +++package : 0 +++core : 0 +++VCED exceptions : not available +++VCEI exceptions : not available +++VPE : 0 +++)"); +++ const auto info = GetMipsInfo(); +++ EXPECT_FALSE(info.features.msa); +++ EXPECT_TRUE(info.features.eva); +++} +++ +++TEST(CpuinfoMipsTest, AR7161) { +++ DisableHardwareCapabilities(); +++ auto& fs = GetEmptyFilesystem(); +++ fs.CreateFile("/proc/cpuinfo", +++ R"(system type : Atheros AR7161 rev 2 +++machine : NETGEAR WNDR3700/WNDR3800/WNDRMAC +++processor : 0 +++cpu model : MIPS 24Kc V7.4 +++BogoMIPS : 452.19 +++wait instruction : yes +++microsecond timers : yes +++tlb_entries : 16 +++extra interrupt vector : yes +++hardware watchpoint : yes, count: 4, address/irw mask: [0x0000, 0x0f98, 0x0f78, 0x0df8] +++ASEs implemented : mips16 +++shadow register sets : 1 +++kscratch registers : 0 +++core : 0 +++VCED exceptions : not available +++VCEI exceptions : not available +++)"); +++ const auto info = GetMipsInfo(); +++ EXPECT_FALSE(info.features.msa); +++ EXPECT_FALSE(info.features.eva); +++} +++ +++TEST(CpuinfoMipsTest, Goldfish) { +++ DisableHardwareCapabilities(); +++ auto& fs = GetEmptyFilesystem(); +++ fs.CreateFile("/proc/cpuinfo", R"(system type : MIPS-Goldfish +++Hardware : goldfish +++Revison : 1 +++processor : 0 +++cpu model : MIPS 24Kc V0.0 FPU V0.0 +++BogoMIPS : 1042.02 +++wait instruction : yes +++microsecond timers : yes +++tlb_entries : 16 +++extra interrupt vector : yes +++hardware watchpoint : yes, count: 1, address/irw mask: [0x0ff8] +++ASEs implemented : +++shadow register sets : 1 +++core : 0 +++VCED exceptions : not available +++VCEI exceptions : not available +++)"); +++ const auto info = GetMipsInfo(); +++ EXPECT_FALSE(info.features.msa); +++ EXPECT_FALSE(info.features.eva); +++} +++ +++} // namespace +++} // namespace cpu_features diff --cc cpu-features/test/cpuinfo_ppc_test.cc index 0000000,0000000,0000000..8f0cb65 new file mode 100644 --- /dev/null +++ b/cpu-features/test/cpuinfo_ppc_test.cc @@@@ -1,0 -1,0 -1,0 +1,119 @@@@ +++// Copyright 2018 IBM. +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#include "cpuinfo_ppc.h" +++ +++#include "filesystem_for_testing.h" +++#include "gtest/gtest.h" +++#include "hwcaps_for_testing.h" +++#include "internal/string_view.h" +++ +++namespace cpu_features { +++namespace { +++ +++void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); } +++ +++TEST(CpustringsPPCTest, FromHardwareCap) { +++ SetHardwareCapabilities(PPC_FEATURE_HAS_FPU | PPC_FEATURE_HAS_VSX, +++ PPC_FEATURE2_ARCH_3_00); +++ GetEmptyFilesystem(); // disabling /proc/cpuinfo +++ const auto info = GetPPCInfo(); +++ EXPECT_TRUE(info.features.fpu); +++ EXPECT_FALSE(info.features.mmu); +++ EXPECT_TRUE(info.features.vsx); +++ EXPECT_TRUE(info.features.arch300); +++ EXPECT_FALSE(info.features.power4); +++ EXPECT_FALSE(info.features.altivec); +++ EXPECT_FALSE(info.features.vcrypto); +++ EXPECT_FALSE(info.features.htm); +++} +++ +++TEST(CpustringsPPCTest, Blade) { +++ DisableHardwareCapabilities(); +++ auto& fs = GetEmptyFilesystem(); +++ fs.CreateFile("/proc/cpuinfo", +++ R"(processor : 14 +++cpu : POWER7 (architected), altivec supported +++clock : 3000.000000MHz +++revision : 2.1 (pvr 003f 0201) +++ +++processor : 15 +++cpu : POWER7 (architected), altivec supported +++clock : 3000.000000MHz +++revision : 2.1 (pvr 003f 0201) +++ +++timebase : 512000000 +++platform : pSeries +++model : IBM,8406-70Y +++machine : CHRP IBM,8406-70Y)"); +++ SetPlatformTypes("power7", "power8"); +++ const auto strings = GetPPCPlatformStrings(); +++ ASSERT_STREQ(strings.platform, "pSeries"); +++ ASSERT_STREQ(strings.model, "IBM,8406-70Y"); +++ ASSERT_STREQ(strings.machine, "CHRP IBM,8406-70Y"); +++ ASSERT_STREQ(strings.cpu, "POWER7 (architected), altivec supported"); +++ ASSERT_STREQ(strings.type.platform, "power7"); +++ ASSERT_STREQ(strings.type.base_platform, "power8"); +++} +++ +++TEST(CpustringsPPCTest, Firestone) { +++ DisableHardwareCapabilities(); +++ auto& fs = GetEmptyFilesystem(); +++ fs.CreateFile("/proc/cpuinfo", +++ R"(processor : 126 +++cpu : POWER8 (raw), altivec supported +++clock : 2061.000000MHz +++revision : 2.0 (pvr 004d 0200) +++ +++processor : 127 +++cpu : POWER8 (raw), altivec supported +++clock : 2061.000000MHz +++revision : 2.0 (pvr 004d 0200) +++ +++timebase : 512000000 +++platform : PowerNV +++model : 8335-GTA +++machine : PowerNV 8335-GTA +++firmware : OPAL v3)"); +++ const auto strings = GetPPCPlatformStrings(); +++ ASSERT_STREQ(strings.platform, "PowerNV"); +++ ASSERT_STREQ(strings.model, "8335-GTA"); +++ ASSERT_STREQ(strings.machine, "PowerNV 8335-GTA"); +++ ASSERT_STREQ(strings.cpu, "POWER8 (raw), altivec supported"); +++} +++ +++TEST(CpustringsPPCTest, w8) { +++ DisableHardwareCapabilities(); +++ auto& fs = GetEmptyFilesystem(); +++ fs.CreateFile("/proc/cpuinfo", +++ R"(processor : 143 +++cpu : POWER9, altivec supported +++clock : 2300.000000MHz +++revision : 2.2 (pvr 004e 1202) +++ +++timebase : 512000000 +++platform : PowerNV +++model : 0000000000000000 +++machine : PowerNV 0000000000000000 +++firmware : OPAL +++MMU : Radix)"); +++ const auto strings = GetPPCPlatformStrings(); +++ ASSERT_STREQ(strings.platform, "PowerNV"); +++ ASSERT_STREQ(strings.model, "0000000000000000"); +++ ASSERT_STREQ(strings.machine, "PowerNV 0000000000000000"); +++ ASSERT_STREQ(strings.cpu, "POWER9, altivec supported"); +++} +++ +++} // namespace +++} // namespace cpu_features diff --cc cpu-features/test/cpuinfo_x86_test.cc index 0000000,0000000,0000000..636d0f9 new file mode 100644 --- /dev/null +++ b/cpu-features/test/cpuinfo_x86_test.cc @@@@ -1,0 -1,0 -1,0 +1,533 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#include "cpuinfo_x86.h" +++ +++#include +++#include +++#include +++#include +++#if defined(CPU_FEATURES_OS_WINDOWS) +++#include // IsProcessorFeaturePresent +++#endif // CPU_FEATURES_OS_WINDOWS +++ +++#include "filesystem_for_testing.h" +++#include "gtest/gtest.h" +++#include "internal/cpuid_x86.h" +++ +++namespace cpu_features { +++ +++class FakeCpu { +++ public: +++ Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx) const { +++ const auto itr = cpuid_leaves_.find(std::make_pair(leaf_id, ecx)); +++ if (itr != cpuid_leaves_.end()) { +++ return itr->second; +++ } +++ return {0, 0, 0, 0}; +++ } +++ +++ uint32_t GetXCR0Eax() const { return xcr0_eax_; } +++ +++ void SetLeaves(std::map, Leaf> configuration) { +++ cpuid_leaves_ = std::move(configuration); +++ } +++ +++ void SetOsBackupsExtendedRegisters(bool os_backups_extended_registers) { +++ xcr0_eax_ = os_backups_extended_registers ? -1 : 0; +++ } +++ +++#if defined(CPU_FEATURES_OS_DARWIN) +++ bool GetDarwinSysCtlByName(std::string name) const { +++ return darwin_sysctlbyname_.count(name); +++ } +++ +++ void SetDarwinSysCtlByName(std::string name) { +++ darwin_sysctlbyname_.insert(name); +++ } +++#endif // CPU_FEATURES_OS_DARWIN +++ +++#if defined(CPU_FEATURES_OS_WINDOWS) +++ bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) { +++ return windows_isprocessorfeaturepresent_.count(ProcessorFeature); +++ } +++ +++ void SetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) { +++ windows_isprocessorfeaturepresent_.insert(ProcessorFeature); +++ } +++#endif // CPU_FEATURES_OS_WINDOWS +++ +++ private: +++ std::map, Leaf> cpuid_leaves_; +++#if defined(CPU_FEATURES_OS_DARWIN) +++ std::set darwin_sysctlbyname_; +++#endif // CPU_FEATURES_OS_DARWIN +++#if defined(CPU_FEATURES_OS_WINDOWS) +++ std::set windows_isprocessorfeaturepresent_; +++#endif // CPU_FEATURES_OS_WINDOWS +++ uint32_t xcr0_eax_; +++}; +++ +++FakeCpu* g_fake_cpu = nullptr; +++ +++extern "C" Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx) { +++ return g_fake_cpu->GetCpuidLeaf(leaf_id, ecx); +++} +++ +++extern "C" uint32_t GetXCR0Eax(void) { return g_fake_cpu->GetXCR0Eax(); } +++ +++#if defined(CPU_FEATURES_OS_DARWIN) +++extern "C" bool GetDarwinSysCtlByName(const char* name) { +++ return g_fake_cpu->GetDarwinSysCtlByName(name); +++} +++#endif // CPU_FEATURES_OS_DARWIN +++ +++#if defined(CPU_FEATURES_OS_WINDOWS) +++extern "C" bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) { +++ return g_fake_cpu->GetWindowsIsProcessorFeaturePresent(ProcessorFeature); +++} +++#endif // CPU_FEATURES_OS_WINDOWS +++ +++namespace { +++ +++class CpuidX86Test : public ::testing::Test { +++ protected: +++ void SetUp() override { g_fake_cpu = new FakeCpu(); } +++ void TearDown() override { delete g_fake_cpu; } +++}; +++ +++TEST_F(CpuidX86Test, SandyBridge) { +++ g_fake_cpu->SetOsBackupsExtendedRegisters(true); +++ g_fake_cpu->SetLeaves({ +++ {{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}}, +++ {{0x00000001, 0}, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}}, +++ {{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, +++ }); +++ const auto info = GetX86Info(); +++ EXPECT_STREQ(info.vendor, "GenuineIntel"); +++ EXPECT_EQ(info.family, 0x06); +++ EXPECT_EQ(info.model, 0x02A); +++ EXPECT_EQ(info.stepping, 0x06); +++ // Leaf 7 is zeroed out so none of the Leaf 7 flags are set. +++ const auto features = info.features; +++ EXPECT_FALSE(features.erms); +++ EXPECT_FALSE(features.avx2); +++ EXPECT_FALSE(features.avx512f); +++ EXPECT_FALSE(features.avx512cd); +++ EXPECT_FALSE(features.avx512er); +++ EXPECT_FALSE(features.avx512pf); +++ EXPECT_FALSE(features.avx512bw); +++ EXPECT_FALSE(features.avx512dq); +++ EXPECT_FALSE(features.avx512vl); +++ EXPECT_FALSE(features.avx512ifma); +++ EXPECT_FALSE(features.avx512vbmi); +++ EXPECT_FALSE(features.avx512vbmi2); +++ EXPECT_FALSE(features.avx512vnni); +++ EXPECT_FALSE(features.avx512bitalg); +++ EXPECT_FALSE(features.avx512vpopcntdq); +++ EXPECT_FALSE(features.avx512_4vnniw); +++ EXPECT_FALSE(features.avx512_4fmaps); +++ // All old cpu features should be set. +++ EXPECT_TRUE(features.aes); +++ EXPECT_TRUE(features.ssse3); +++ EXPECT_TRUE(features.sse4_1); +++ EXPECT_TRUE(features.sse4_2); +++ EXPECT_TRUE(features.avx); +++ EXPECT_FALSE(features.sha); +++ EXPECT_TRUE(features.popcnt); +++ EXPECT_FALSE(features.movbe); +++ EXPECT_FALSE(features.rdrnd); +++} +++ +++const int KiB = 1024; +++const int MiB = 1024 * KiB; +++ +++TEST_F(CpuidX86Test, SandyBridgeTestOsSupport) { +++ g_fake_cpu->SetLeaves({ +++ {{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}}, +++ {{0x00000001, 0}, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}}, +++ {{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, +++ }); +++ // avx is disabled if os does not support backing up ymm registers. +++ g_fake_cpu->SetOsBackupsExtendedRegisters(false); +++ EXPECT_FALSE(GetX86Info().features.avx); +++ // avx is disabled if os does not support backing up ymm registers. +++ g_fake_cpu->SetOsBackupsExtendedRegisters(true); +++ EXPECT_TRUE(GetX86Info().features.avx); +++} +++ +++TEST_F(CpuidX86Test, SkyLake) { +++ g_fake_cpu->SetOsBackupsExtendedRegisters(true); +++ g_fake_cpu->SetLeaves({ +++ {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}}, +++ {{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}}, +++ {{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}}, +++ }); +++ const auto info = GetX86Info(); +++ EXPECT_STREQ(info.vendor, "GenuineIntel"); +++ EXPECT_EQ(info.family, 0x06); +++ EXPECT_EQ(info.model, 0x04E); +++ EXPECT_EQ(info.stepping, 0x03); +++ EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_SKL); +++} +++ +++TEST_F(CpuidX86Test, Branding) { +++ g_fake_cpu->SetLeaves({ +++ {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}}, +++ {{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}}, +++ {{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}}, +++ {{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}}, +++ {{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}}, +++ {{0x80000002, 0}, Leaf{0x65746E49, 0x2952286C, 0x726F4320, 0x4D542865}}, +++ {{0x80000003, 0}, Leaf{0x37692029, 0x3035362D, 0x43205530, 0x40205550}}, +++ {{0x80000004, 0}, Leaf{0x352E3220, 0x7A484730, 0x00000000, 0x00000000}}, +++ }); +++ char brand_string[49]; +++ FillX86BrandString(brand_string); +++ EXPECT_STREQ(brand_string, "Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz"); +++} +++ +++TEST_F(CpuidX86Test, KabyLakeCache) { +++ g_fake_cpu->SetLeaves({ +++ {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}}, +++ {{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}}, +++ {{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}}, +++ {{0x00000004, 1}, Leaf{0x1C004122, 0x01C0003F, 0x0000003F, 0x00000000}}, +++ {{0x00000004, 2}, Leaf{0x1C004143, 0x00C0003F, 0x000003FF, 0x00000000}}, +++ {{0x00000004, 3}, Leaf{0x1C03C163, 0x02C0003F, 0x00001FFF, 0x00000002}}, +++ {{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}}, +++ {{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}}, +++ {{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}}, +++ {{0x80000002, 0}, Leaf{0x65746E49, 0x2952286C, 0x726F4320, 0x4D542865}}, +++ {{0x80000003, 0}, Leaf{0x37692029, 0x3035362D, 0x43205530, 0x40205550}}, +++ }); +++ const auto info = GetX86CacheInfo(); +++ EXPECT_EQ(info.size, 4); +++ EXPECT_EQ(info.levels[0].level, 1); +++ EXPECT_EQ(info.levels[0].cache_type, 1); +++ EXPECT_EQ(info.levels[0].cache_size, 32 * KiB); +++ EXPECT_EQ(info.levels[0].ways, 8); +++ EXPECT_EQ(info.levels[0].line_size, 64); +++ EXPECT_EQ(info.levels[0].tlb_entries, 64); +++ EXPECT_EQ(info.levels[0].partitioning, 1); +++ +++ EXPECT_EQ(info.levels[1].level, 1); +++ EXPECT_EQ(info.levels[1].cache_type, 2); +++ EXPECT_EQ(info.levels[1].cache_size, 32 * KiB); +++ EXPECT_EQ(info.levels[1].ways, 8); +++ EXPECT_EQ(info.levels[1].line_size, 64); +++ EXPECT_EQ(info.levels[1].tlb_entries, 64); +++ EXPECT_EQ(info.levels[1].partitioning, 1); +++ +++ EXPECT_EQ(info.levels[2].level, 2); +++ EXPECT_EQ(info.levels[2].cache_type, 3); +++ EXPECT_EQ(info.levels[2].cache_size, 256 * KiB); +++ EXPECT_EQ(info.levels[2].ways, 4); +++ EXPECT_EQ(info.levels[2].line_size, 64); +++ EXPECT_EQ(info.levels[2].tlb_entries, 1024); +++ EXPECT_EQ(info.levels[2].partitioning, 1); +++ +++ EXPECT_EQ(info.levels[3].level, 3); +++ EXPECT_EQ(info.levels[3].cache_type, 3); +++ EXPECT_EQ(info.levels[3].cache_size, 6 * MiB); +++ EXPECT_EQ(info.levels[3].ways, 12); +++ EXPECT_EQ(info.levels[3].line_size, 64); +++ EXPECT_EQ(info.levels[3].tlb_entries, 8192); +++ EXPECT_EQ(info.levels[3].partitioning, 1); +++} +++ +++TEST_F(CpuidX86Test, HSWCache) { +++ g_fake_cpu->SetLeaves({ +++ {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}}, +++ {{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}}, +++ {{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}}, +++ {{0x00000004, 1}, Leaf{0x1C004122, 0x01C0003F, 0x0000003F, 0x00000000}}, +++ {{0x00000004, 2}, Leaf{0x1C004143, 0x01C0003F, 0x000001FF, 0x00000000}}, +++ {{0x00000004, 3}, Leaf{0x1C03C163, 0x02C0003F, 0x00001FFF, 0x00000006}}, +++ {{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}}, +++ {{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}}, +++ {{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}}, +++ {{0x80000002, 0}, Leaf{0x65746E49, 0x2952286C, 0x726F4320, 0x4D542865}}, +++ {{0x80000003, 0}, Leaf{0x37692029, 0x3035362D, 0x43205530, 0x40205550}}, +++ }); +++ const auto info = GetX86CacheInfo(); +++ EXPECT_EQ(info.size, 4); +++ EXPECT_EQ(info.levels[0].level, 1); +++ EXPECT_EQ(info.levels[0].cache_type, 1); +++ EXPECT_EQ(info.levels[0].cache_size, 32 * KiB); +++ EXPECT_EQ(info.levels[0].ways, 8); +++ EXPECT_EQ(info.levels[0].line_size, 64); +++ EXPECT_EQ(info.levels[0].tlb_entries, 64); +++ EXPECT_EQ(info.levels[0].partitioning, 1); +++ +++ EXPECT_EQ(info.levels[1].level, 1); +++ EXPECT_EQ(info.levels[1].cache_type, 2); +++ EXPECT_EQ(info.levels[1].cache_size, 32 * KiB); +++ EXPECT_EQ(info.levels[1].ways, 8); +++ EXPECT_EQ(info.levels[1].line_size, 64); +++ EXPECT_EQ(info.levels[1].tlb_entries, 64); +++ EXPECT_EQ(info.levels[1].partitioning, 1); +++ +++ EXPECT_EQ(info.levels[2].level, 2); +++ EXPECT_EQ(info.levels[2].cache_type, 3); +++ EXPECT_EQ(info.levels[2].cache_size, 256 * KiB); +++ EXPECT_EQ(info.levels[2].ways, 8); +++ EXPECT_EQ(info.levels[2].line_size, 64); +++ EXPECT_EQ(info.levels[2].tlb_entries, 512); +++ EXPECT_EQ(info.levels[2].partitioning, 1); +++ +++ EXPECT_EQ(info.levels[3].level, 3); +++ EXPECT_EQ(info.levels[3].cache_type, 3); +++ EXPECT_EQ(info.levels[3].cache_size, 6 * MiB); +++ EXPECT_EQ(info.levels[3].ways, 12); +++ EXPECT_EQ(info.levels[3].line_size, 64); +++ EXPECT_EQ(info.levels[3].tlb_entries, 8192); +++ EXPECT_EQ(info.levels[3].partitioning, 1); +++} +++ +++// http://users.atw.hu/instlatx64/AuthenticAMD0630F81_K15_Godavari_CPUID.txt +++TEST_F(CpuidX86Test, AMD_K15) { +++ g_fake_cpu->SetLeaves({ +++ {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}}, +++ {{0x00000001, 0}, Leaf{0x00630F81, 0x00040800, 0x3E98320B, 0x178BFBFF}}, +++ {{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, +++ {{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}}, +++ {{0x80000001, 0}, Leaf{0x00630F81, 0x10000000, 0x0FEBBFFF, 0x2FD3FBFF}}, +++ {{0x80000002, 0}, Leaf{0x20444D41, 0x372D3841, 0x4B303736, 0x64615220}}, +++ {{0x80000003, 0}, Leaf{0x206E6F65, 0x202C3752, 0x43203031, 0x75706D6F}}, +++ {{0x80000004, 0}, Leaf{0x43206574, 0x7365726F, 0x2B433420, 0x00204736}}, +++ {{0x80000005, 0}, Leaf{0xFF40FF18, 0xFF40FF30, 0x10040140, 0x60030140}}, +++ }); +++ const auto info = GetX86Info(); +++ +++ EXPECT_STREQ(info.vendor, "AuthenticAMD"); +++ EXPECT_EQ(info.family, 0x15); +++ EXPECT_EQ(info.model, 0x38); +++ EXPECT_EQ(info.stepping, 0x01); +++ EXPECT_EQ(GetX86Microarchitecture(&info), +++ X86Microarchitecture::AMD_BULLDOZER); +++ +++ char brand_string[49]; +++ FillX86BrandString(brand_string); +++ EXPECT_STREQ(brand_string, "AMD A8-7670K Radeon R7, 10 Compute Cores 4C+6G "); +++} +++ +++// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel00106A1_Nehalem_CPUID.txt +++TEST_F(CpuidX86Test, Nehalem) { +++ // Pre AVX cpus don't have xsave +++ g_fake_cpu->SetOsBackupsExtendedRegisters(false); +++#if defined(CPU_FEATURES_OS_WINDOWS) +++ g_fake_cpu->SetWindowsIsProcessorFeaturePresent( +++ PF_XMMI_INSTRUCTIONS_AVAILABLE); +++ g_fake_cpu->SetWindowsIsProcessorFeaturePresent( +++ PF_XMMI64_INSTRUCTIONS_AVAILABLE); +++ g_fake_cpu->SetWindowsIsProcessorFeaturePresent( +++ PF_SSE3_INSTRUCTIONS_AVAILABLE); +++#endif // CPU_FEATURES_OS_WINDOWS +++#if defined(CPU_FEATURES_OS_DARWIN) +++ g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse"); +++ g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse2"); +++ g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse3"); +++ g_fake_cpu->SetDarwinSysCtlByName("hw.optional.supplementalsse3"); +++ g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_1"); +++ g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_2"); +++#endif // CPU_FEATURES_OS_DARWIN +++#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID) +++ auto& fs = GetEmptyFilesystem(); +++ fs.CreateFile("/proc/cpuinfo", R"(processor : +++flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2 +++)"); +++#endif // CPU_FEATURES_OS_LINUX_OR_ANDROID +++ g_fake_cpu->SetLeaves({ +++ {{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}}, +++ {{0x00000001, 0}, Leaf{0x000106A2, 0x00100800, 0x00BCE3BD, 0xBFEBFBFF}}, +++ {{0x00000002, 0}, Leaf{0x55035A01, 0x00F0B0E3, 0x00000000, 0x09CA212C}}, +++ {{0x00000003, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, +++ {{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}}, +++ {{0x00000004, 0}, Leaf{0x1C004122, 0x00C0003F, 0x0000007F, 0x00000000}}, +++ {{0x00000004, 0}, Leaf{0x1C004143, 0x01C0003F, 0x000001FF, 0x00000000}}, +++ {{0x00000004, 0}, Leaf{0x1C03C163, 0x03C0003F, 0x00000FFF, 0x00000002}}, +++ {{0x00000005, 0}, Leaf{0x00000040, 0x00000040, 0x00000003, 0x00021120}}, +++ {{0x00000006, 0}, Leaf{0x00000001, 0x00000002, 0x00000001, 0x00000000}}, +++ {{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, +++ {{0x00000008, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, +++ {{0x00000009, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, +++ {{0x0000000A, 0}, Leaf{0x07300403, 0x00000000, 0x00000000, 0x00000603}}, +++ {{0x0000000B, 0}, Leaf{0x00000001, 0x00000001, 0x00000100, 0x00000000}}, +++ {{0x0000000B, 0}, Leaf{0x00000004, 0x00000002, 0x00000201, 0x00000000}}, +++ {{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}}, +++ {{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000001, 0x28100000}}, +++ {{0x80000002, 0}, Leaf{0x756E6547, 0x20656E69, 0x65746E49, 0x2952286C}}, +++ {{0x80000003, 0}, Leaf{0x55504320, 0x20202020, 0x20202020, 0x40202020}}, +++ {{0x80000004, 0}, Leaf{0x30303020, 0x20402030, 0x37382E31, 0x007A4847}}, +++ {{0x80000005, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, +++ {{0x80000006, 0}, Leaf{0x00000000, 0x00000000, 0x01006040, 0x00000000}}, +++ {{0x80000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000100}}, +++ {{0x80000008, 0}, Leaf{0x00003028, 0x00000000, 0x00000000, 0x00000000}}, +++ }); +++ const auto info = GetX86Info(); +++ +++ EXPECT_STREQ(info.vendor, "GenuineIntel"); +++ EXPECT_EQ(info.family, 0x06); +++ EXPECT_EQ(info.model, 0x1A); +++ EXPECT_EQ(info.stepping, 0x02); +++ EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_NHM); +++ +++ char brand_string[49]; +++ FillX86BrandString(brand_string); +++ EXPECT_STREQ(brand_string, "Genuine Intel(R) CPU @ 0000 @ 1.87GHz"); +++ +++ EXPECT_TRUE(info.features.sse); +++ EXPECT_TRUE(info.features.sse2); +++ EXPECT_TRUE(info.features.sse3); +++#ifndef CPU_FEATURES_OS_WINDOWS +++ // Currently disabled on Windows as IsProcessorFeaturePresent do not support +++ // feature detection > sse3. +++ EXPECT_TRUE(info.features.ssse3); +++ EXPECT_TRUE(info.features.sse4_1); +++ EXPECT_TRUE(info.features.sse4_2); +++#endif // CPU_FEATURES_OS_WINDOWS +++} +++ +++// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0030673_Silvermont3_CPUID.txt +++TEST_F(CpuidX86Test, Atom) { +++ // Pre AVX cpus don't have xsave +++ g_fake_cpu->SetOsBackupsExtendedRegisters(false); +++#if defined(CPU_FEATURES_OS_WINDOWS) +++ g_fake_cpu->SetWindowsIsProcessorFeaturePresent( +++ PF_XMMI_INSTRUCTIONS_AVAILABLE); +++ g_fake_cpu->SetWindowsIsProcessorFeaturePresent( +++ PF_XMMI64_INSTRUCTIONS_AVAILABLE); +++ g_fake_cpu->SetWindowsIsProcessorFeaturePresent( +++ PF_SSE3_INSTRUCTIONS_AVAILABLE); +++#endif // CPU_FEATURES_OS_WINDOWS +++#if defined(CPU_FEATURES_OS_DARWIN) +++ g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse"); +++ g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse2"); +++ g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse3"); +++ g_fake_cpu->SetDarwinSysCtlByName("hw.optional.supplementalsse3"); +++ g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_1"); +++ g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_2"); +++#endif // CPU_FEATURES_OS_DARWIN +++#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID) +++ auto& fs = GetEmptyFilesystem(); +++ fs.CreateFile("/proc/cpuinfo", R"( +++flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2 +++)"); +++#endif // CPU_FEATURES_OS_LINUX_OR_ANDROID +++ g_fake_cpu->SetLeaves({ +++ {{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}}, +++ {{0x00000001, 0}, Leaf{0x00030673, 0x00100800, 0x41D8E3BF, 0xBFEBFBFF}}, +++ {{0x00000002, 0}, Leaf{0x61B3A001, 0x0000FFC2, 0x00000000, 0x00000000}}, +++ {{0x00000003, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, +++ {{0x00000004, 0}, Leaf{0x1C000121, 0x0140003F, 0x0000003F, 0x00000001}}, +++ {{0x00000004, 1}, Leaf{0x1C000122, 0x01C0003F, 0x0000003F, 0x00000001}}, +++ {{0x00000004, 2}, Leaf{0x1C00C143, 0x03C0003F, 0x000003FF, 0x00000001}}, +++ {{0x00000005, 0}, Leaf{0x00000040, 0x00000040, 0x00000003, 0x33000020}}, +++ {{0x00000006, 0}, Leaf{0x00000005, 0x00000002, 0x00000009, 0x00000000}}, +++ {{0x00000007, 0}, Leaf{0x00000000, 0x00002282, 0x00000000, 0x00000000}}, +++ {{0x00000008, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, +++ {{0x00000009, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, +++ {{0x0000000A, 0}, Leaf{0x07280203, 0x00000000, 0x00000000, 0x00004503}}, +++ {{0x0000000B, 0}, Leaf{0x00000001, 0x00000001, 0x00000100, 0x00000000}}, +++ {{0x0000000B, 1}, Leaf{0x00000004, 0x00000004, 0x00000201, 0x00000000}}, +++ {{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}}, +++ {{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000101, 0x28100000}}, +++ {{0x80000002, 0}, Leaf{0x20202020, 0x6E492020, 0x286C6574, 0x43202952}}, +++ {{0x80000003, 0}, Leaf{0x72656C65, 0x52286E6F, 0x50432029, 0x4A202055}}, +++ {{0x80000004, 0}, Leaf{0x30303931, 0x20402020, 0x39392E31, 0x007A4847}}, +++ {{0x80000005, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}}, +++ {{0x80000006, 0}, Leaf{0x00000000, 0x00000000, 0x04008040, 0x00000000}}, +++ {{0x80000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000100}}, +++ {{0x80000008, 0}, Leaf{0x00003024, 0x00000000, 0x00000000, 0x00000000}}, +++ }); +++ const auto info = GetX86Info(); +++ +++ EXPECT_STREQ(info.vendor, "GenuineIntel"); +++ EXPECT_EQ(info.family, 0x06); +++ EXPECT_EQ(info.model, 0x37); +++ EXPECT_EQ(info.stepping, 0x03); +++ EXPECT_EQ(GetX86Microarchitecture(&info), +++ X86Microarchitecture::INTEL_ATOM_SMT); +++ +++ char brand_string[49]; +++ FillX86BrandString(brand_string); +++ EXPECT_STREQ(brand_string, " Intel(R) Celeron(R) CPU J1900 @ 1.99GHz"); +++ +++ EXPECT_TRUE(info.features.sse); +++ EXPECT_TRUE(info.features.sse2); +++ EXPECT_TRUE(info.features.sse3); +++#ifndef CPU_FEATURES_OS_WINDOWS +++ // Currently disabled on Windows as IsProcessorFeaturePresent do not support +++ // feature detection > sse3. +++ EXPECT_TRUE(info.features.ssse3); +++ EXPECT_TRUE(info.features.sse4_1); +++ EXPECT_TRUE(info.features.sse4_2); +++#endif // CPU_FEATURES_OS_WINDOWS +++} +++ +++// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0000673_P3_KatmaiDP_CPUID.txt +++TEST_F(CpuidX86Test, P3) { +++ // Pre AVX cpus don't have xsave +++ g_fake_cpu->SetOsBackupsExtendedRegisters(false); +++#if defined(CPU_FEATURES_OS_WINDOWS) +++ g_fake_cpu->SetWindowsIsProcessorFeaturePresent( +++ PF_XMMI_INSTRUCTIONS_AVAILABLE); +++#endif // CPU_FEATURES_OS_WINDOWS +++#if defined(CPU_FEATURES_OS_DARWIN) +++ g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse"); +++#endif // CPU_FEATURES_OS_DARWIN +++#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID) +++ auto& fs = GetEmptyFilesystem(); +++ fs.CreateFile("/proc/cpuinfo", R"( +++flags : fpu mmx sse +++)"); +++#endif // CPU_FEATURES_OS_LINUX_OR_ANDROID +++ g_fake_cpu->SetLeaves({ +++ {{0x00000000, 0}, Leaf{0x00000003, 0x756E6547, 0x6C65746E, 0x49656E69}}, +++ {{0x00000001, 0}, Leaf{0x00000673, 0x00000000, 0x00000000, 0x0387FBFF}}, +++ {{0x00000002, 0}, Leaf{0x03020101, 0x00000000, 0x00000000, 0x0C040843}}, +++ {{0x00000003, 0}, Leaf{0x00000000, 0x00000000, 0x4CECC782, 0x00006778}}, +++ }); +++ const auto info = GetX86Info(); +++ +++ EXPECT_STREQ(info.vendor, "GenuineIntel"); +++ EXPECT_EQ(info.family, 0x06); +++ EXPECT_EQ(info.model, 0x07); +++ EXPECT_EQ(info.stepping, 0x03); +++ EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::X86_UNKNOWN); +++ +++ char brand_string[49]; +++ FillX86BrandString(brand_string); +++ EXPECT_STREQ(brand_string, ""); +++ +++ EXPECT_TRUE(info.features.mmx); +++ EXPECT_TRUE(info.features.sse); +++ EXPECT_FALSE(info.features.sse2); +++ EXPECT_FALSE(info.features.sse3); +++#ifndef CPU_FEATURES_OS_WINDOWS +++ // Currently disabled on Windows as IsProcessorFeaturePresent do not support +++ // feature detection > sse3. +++ EXPECT_FALSE(info.features.ssse3); +++ EXPECT_FALSE(info.features.sse4_1); +++ EXPECT_FALSE(info.features.sse4_2); +++#endif // CPU_FEATURES_OS_WINDOWS +++} +++ +++// TODO(user): test what happens when xsave/osxsave are not present. +++// TODO(user): test what happens when xmm/ymm/zmm os support are not +++// present. +++ +++} // namespace +++} // namespace cpu_features diff --cc cpu-features/test/filesystem_for_testing.cc index 0000000,0000000,0000000..648a53e new file mode 100644 --- /dev/null +++ b/cpu-features/test/filesystem_for_testing.cc @@@@ -1,0 -1,0 -1,0 +1,103 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#include "filesystem_for_testing.h" +++ +++#include +++#include +++#include +++#include +++#include +++ +++namespace cpu_features { +++ +++FakeFile::FakeFile(int file_descriptor, const char* content) +++ : file_descriptor_(file_descriptor), content_(content) {} +++ +++FakeFile::~FakeFile() { assert(!opened_); } +++ +++void FakeFile::Open() { +++ assert(!opened_); +++ opened_ = true; +++} +++ +++void FakeFile::Close() { +++ assert(opened_); +++ opened_ = false; +++} +++ +++int FakeFile::Read(int fd, void* buf, size_t count) { +++ assert(count < INT_MAX); +++ assert(fd == file_descriptor_); +++ const size_t remainder = content_.size() - head_index_; +++ const size_t read = count > remainder ? remainder : count; +++ memcpy(buf, content_.data() + head_index_, read); +++ head_index_ += read; +++ assert(read < INT_MAX); +++ return (int)read; +++} +++ +++void FakeFilesystem::Reset() { files_.clear(); } +++ +++FakeFile* FakeFilesystem::CreateFile(const std::string& filename, +++ const char* content) { +++ auto& file = files_[filename]; +++ file = +++ std::unique_ptr(new FakeFile(next_file_descriptor_++, content)); +++ return file.get(); +++} +++ +++FakeFile* FakeFilesystem::FindFileOrNull(const std::string& filename) const { +++ const auto itr = files_.find(filename); +++ return itr == files_.end() ? nullptr : itr->second.get(); +++} +++ +++FakeFile* FakeFilesystem::FindFileOrDie(const int file_descriptor) const { +++ for (const auto& filename_file_pair : files_) { +++ FakeFile* const file_ptr = filename_file_pair.second.get(); +++ if (file_ptr->GetFileDescriptor() == file_descriptor) { +++ return file_ptr; +++ } +++ } +++ assert(false); +++ return nullptr; +++} +++ +++static FakeFilesystem* kFilesystem = new FakeFilesystem(); +++ +++FakeFilesystem& GetEmptyFilesystem() { +++ kFilesystem->Reset(); +++ return *kFilesystem; +++} +++ +++extern "C" int CpuFeatures_OpenFile(const char* filename) { +++ auto* const file = kFilesystem->FindFileOrNull(filename); +++ if (file) { +++ file->Open(); +++ return file->GetFileDescriptor(); +++ } +++ return -1; +++} +++ +++extern "C" void CpuFeatures_CloseFile(int file_descriptor) { +++ kFilesystem->FindFileOrDie(file_descriptor)->Close(); +++} +++ +++extern "C" int CpuFeatures_ReadFile(int file_descriptor, void* buffer, +++ size_t buffer_size) { +++ return kFilesystem->FindFileOrDie(file_descriptor) +++ ->Read(file_descriptor, buffer, buffer_size); +++} +++ +++} // namespace cpu_features diff --cc cpu-features/test/filesystem_for_testing.h index 0000000,0000000,0000000..ef717fd new file mode 100644 --- /dev/null +++ b/cpu-features/test/filesystem_for_testing.h @@@@ -1,0 -1,0 -1,0 +1,61 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++// Implements a fake filesystem, useful for tests. +++#ifndef CPU_FEATURES_TEST_FILESYSTEM_FOR_TESTING_H_ +++#define CPU_FEATURES_TEST_FILESYSTEM_FOR_TESTING_H_ +++ +++#include +++#include +++#include +++ +++#include "internal/filesystem.h" +++ +++namespace cpu_features { +++ +++class FakeFile { +++ public: +++ explicit FakeFile(int file_descriptor, const char* content); +++ ~FakeFile(); +++ +++ void Open(); +++ void Close(); +++ int Read(int fd, void* buf, size_t count); +++ +++ int GetFileDescriptor() const { return file_descriptor_; } +++ +++ private: +++ const int file_descriptor_; +++ const std::string content_; +++ bool opened_ = false; +++ size_t head_index_ = 0; +++}; +++ +++class FakeFilesystem { +++ public: +++ void Reset(); +++ FakeFile* CreateFile(const std::string& filename, const char* content); +++ FakeFile* FindFileOrDie(const int file_descriptor) const; +++ FakeFile* FindFileOrNull(const std::string& filename) const; +++ +++ private: +++ int next_file_descriptor_ = 0; +++ std::unordered_map> files_; +++}; +++ +++FakeFilesystem& GetEmptyFilesystem(); +++ +++} // namespace cpu_features +++ +++#endif // CPU_FEATURES_TEST_FILESYSTEM_FOR_TESTING_H_ diff --cc cpu-features/test/hwcaps_for_testing.cc index 0000000,0000000,0000000..a8086a0 new file mode 100644 --- /dev/null +++ b/cpu-features/test/hwcaps_for_testing.cc @@@@ -1,0 -1,0 -1,0 +1,46 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#include "hwcaps_for_testing.h" +++ +++#include +++ +++#include "internal/string_view.h" +++ +++namespace cpu_features { +++ +++namespace { +++static auto* const g_hardware_capabilities = new HardwareCapabilities(); +++static auto* const g_platform_types = new PlatformType(); +++} // namespace +++ +++void SetHardwareCapabilities(uint32_t hwcaps, uint32_t hwcaps2) { +++ g_hardware_capabilities->hwcaps = hwcaps; +++ g_hardware_capabilities->hwcaps2 = hwcaps2; +++} +++ +++HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void) { +++ return *g_hardware_capabilities; +++} +++ +++void SetPlatformTypes(const char* platform, const char* base_platform) { +++ CpuFeatures_StringView_CopyString(str(platform), g_platform_types->platform, +++ sizeof(g_platform_types->platform)); +++ CpuFeatures_StringView_CopyString(str(base_platform), +++ g_platform_types->base_platform, +++ sizeof(g_platform_types->base_platform)); +++} +++ +++PlatformType CpuFeatures_GetPlatformType(void) { return *g_platform_types; } +++} // namespace cpu_features diff --cc cpu-features/test/hwcaps_for_testing.h index 0000000,0000000,0000000..bcab82e new file mode 100644 --- /dev/null +++ b/cpu-features/test/hwcaps_for_testing.h @@@@ -1,0 -1,0 -1,0 +1,27 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#ifndef CPU_FEATURES_TEST_HWCAPS_FOR_TESTING_H_ +++#define CPU_FEATURES_TEST_HWCAPS_FOR_TESTING_H_ +++ +++#include "internal/hwcaps.h" +++ +++namespace cpu_features { +++ +++void SetHardwareCapabilities(uint32_t hwcaps, uint32_t hwcaps2); +++void SetPlatformTypes(const char *platform, const char *base_platform); +++ +++} // namespace cpu_features +++ +++#endif // CPU_FEATURES_TEST_HWCAPS_FOR_TESTING_H_ diff --cc cpu-features/test/stack_line_reader_test.cc index 0000000,0000000,0000000..9ac5388 new file mode 100644 --- /dev/null +++ b/cpu-features/test/stack_line_reader_test.cc @@@@ -1,0 -1,0 -1,0 +1,132 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#include "internal/stack_line_reader.h" +++ +++#include "filesystem_for_testing.h" +++#include "gtest/gtest.h" +++ +++namespace cpu_features { +++ +++bool operator==(const StringView& a, const StringView& b) { +++ return CpuFeatures_StringView_IsEquals(a, b); +++} +++ +++namespace { +++ +++std::string ToString(StringView view) { return {view.ptr, view.size}; } +++ +++TEST(StackLineReaderTest, Empty) { +++ auto& fs = GetEmptyFilesystem(); +++ auto* file = fs.CreateFile("/proc/cpuinfo", ""); +++ StackLineReader reader; +++ StackLineReader_Initialize(&reader, file->GetFileDescriptor()); +++ { +++ const auto result = StackLineReader_NextLine(&reader); +++ EXPECT_TRUE(result.eof); +++ EXPECT_TRUE(result.full_line); +++ EXPECT_EQ(result.line, str("")); +++ } +++} +++ +++TEST(StackLineReaderTest, ManySmallLines) { +++ auto& fs = GetEmptyFilesystem(); +++ auto* file = fs.CreateFile("/proc/cpuinfo", "a\nb\nc"); +++ +++ StackLineReader reader; +++ StackLineReader_Initialize(&reader, file->GetFileDescriptor()); +++ { +++ const auto result = StackLineReader_NextLine(&reader); +++ EXPECT_FALSE(result.eof); +++ EXPECT_TRUE(result.full_line); +++ EXPECT_EQ(result.line, str("a")); +++ } +++ { +++ const auto result = StackLineReader_NextLine(&reader); +++ EXPECT_FALSE(result.eof); +++ EXPECT_TRUE(result.full_line); +++ EXPECT_EQ(result.line, str("b")); +++ } +++ { +++ const auto result = StackLineReader_NextLine(&reader); +++ EXPECT_TRUE(result.eof); +++ EXPECT_TRUE(result.full_line); +++ EXPECT_EQ(result.line, str("c")); +++ } +++} +++ +++TEST(StackLineReaderTest, TruncatedLine) { +++ auto& fs = GetEmptyFilesystem(); +++ auto* file = fs.CreateFile("/proc/cpuinfo", R"(First +++Second +++More than 16 characters, this will be truncated. +++last)"); +++ +++ StackLineReader reader; +++ StackLineReader_Initialize(&reader, file->GetFileDescriptor()); +++ { +++ const auto result = StackLineReader_NextLine(&reader); +++ EXPECT_FALSE(result.eof); +++ EXPECT_TRUE(result.full_line); +++ EXPECT_EQ(result.line, str("First")); +++ } +++ { +++ const auto result = StackLineReader_NextLine(&reader); +++ EXPECT_FALSE(result.eof); +++ EXPECT_TRUE(result.full_line); +++ EXPECT_EQ(result.line, str("Second")); +++ } +++ { +++ const auto result = StackLineReader_NextLine(&reader); +++ EXPECT_FALSE(result.eof); +++ EXPECT_FALSE(result.full_line); +++ EXPECT_EQ(result.line, str("More than 16 cha")); +++ } +++ { +++ const auto result = StackLineReader_NextLine(&reader); +++ EXPECT_TRUE(result.eof); +++ EXPECT_TRUE(result.full_line); +++ EXPECT_EQ(result.line, str("last")); +++ } +++} +++ +++TEST(StackLineReaderTest, TruncatedLines) { +++ auto& fs = GetEmptyFilesystem(); +++ auto* file = fs.CreateFile("/proc/cpuinfo", R"(More than 16 characters +++Another line that is too long)"); +++ +++ StackLineReader reader; +++ StackLineReader_Initialize(&reader, file->GetFileDescriptor()); +++ { +++ const auto result = StackLineReader_NextLine(&reader); +++ EXPECT_FALSE(result.eof); +++ EXPECT_FALSE(result.full_line); +++ EXPECT_EQ(result.line, str("More than 16 cha")); +++ } +++ { +++ const auto result = StackLineReader_NextLine(&reader); +++ EXPECT_FALSE(result.eof); +++ EXPECT_FALSE(result.full_line); +++ EXPECT_EQ(result.line, str("Another line tha")); +++ } +++ { +++ const auto result = StackLineReader_NextLine(&reader); +++ EXPECT_TRUE(result.eof); +++ EXPECT_TRUE(result.full_line); +++ EXPECT_EQ(result.line, str("")); +++ } +++} +++ +++} // namespace +++} // namespace cpu_features diff --cc cpu-features/test/string_view_test.cc index 0000000,0000000,0000000..ca3e023 new file mode 100644 --- /dev/null +++ b/cpu-features/test/string_view_test.cc @@@@ -1,0 -1,0 -1,0 +1,192 @@@@ +++// Copyright 2017 Google LLC +++// +++// Licensed under the Apache License, Version 2.0 (the "License"); +++// you may not use this file except in compliance with the License. +++// You may obtain a copy of the License at +++// +++// http://www.apache.org/licenses/LICENSE-2.0 +++// +++// Unless required by applicable law or agreed to in writing, software +++// distributed under the License is distributed on an "AS IS" BASIS, +++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +++// See the License for the specific language governing permissions and +++// limitations under the License. +++ +++#include "internal/string_view.h" +++ +++#include "gtest/gtest.h" +++ +++namespace cpu_features { +++ +++bool operator==(const StringView& a, const StringView& b) { +++ return CpuFeatures_StringView_IsEquals(a, b); +++} +++ +++namespace { +++ +++TEST(StringViewTest, Empty) { +++ EXPECT_EQ(kEmptyStringView.ptr, nullptr); +++ EXPECT_EQ(kEmptyStringView.size, 0); +++} +++ +++TEST(StringViewTest, Build) { +++ const auto view = str("test"); +++ EXPECT_EQ(view.ptr[0], 't'); +++ EXPECT_EQ(view.size, 4); +++} +++ +++TEST(StringViewTest, CpuFeatures_StringView_IndexOfChar) { +++ // Found. +++ EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 'e'), 1); +++ EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 't'), 0); +++ EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("beef"), 'e'), 1); +++ // Not found. +++ EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 'z'), -1); +++ // Empty. +++ EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(kEmptyStringView, 'z'), -1); +++} +++ +++TEST(StringViewTest, CpuFeatures_StringView_IndexOf) { +++ // Found. +++ EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("es")), 1); +++ EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("test")), 0); +++ EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("tesstest"), str("test")), 4); +++ // Not found. +++ EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("aa")), -1); +++ // Empty. +++ EXPECT_EQ(CpuFeatures_StringView_IndexOf(kEmptyStringView, str("aa")), -1); +++ EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("aa"), kEmptyStringView), -1); +++} +++ +++TEST(StringViewTest, CpuFeatures_StringView_StartsWith) { +++ EXPECT_TRUE(CpuFeatures_StringView_StartsWith(str("test"), str("te"))); +++ EXPECT_TRUE(CpuFeatures_StringView_StartsWith(str("test"), str("test"))); +++ EXPECT_FALSE(CpuFeatures_StringView_StartsWith(str("test"), str("st"))); +++ EXPECT_FALSE(CpuFeatures_StringView_StartsWith(str("test"), str("est"))); +++ EXPECT_FALSE(CpuFeatures_StringView_StartsWith(str("test"), str(""))); +++ EXPECT_FALSE( +++ CpuFeatures_StringView_StartsWith(str("test"), kEmptyStringView)); +++ EXPECT_FALSE( +++ CpuFeatures_StringView_StartsWith(kEmptyStringView, str("test"))); +++} +++ +++TEST(StringViewTest, CpuFeatures_StringView_IsEquals) { +++ EXPECT_TRUE( +++ CpuFeatures_StringView_IsEquals(kEmptyStringView, kEmptyStringView)); +++ EXPECT_TRUE(CpuFeatures_StringView_IsEquals(kEmptyStringView, str(""))); +++ EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str(""), kEmptyStringView)); +++ EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str("test"), str("test"))); +++ EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str("a"), str("a"))); +++ EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), str("b"))); +++ EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("aa"), str("a"))); +++ EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), str("aa"))); +++ EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), kEmptyStringView)); +++ EXPECT_FALSE(CpuFeatures_StringView_IsEquals(kEmptyStringView, str("a"))); +++} +++ +++TEST(StringViewTest, CpuFeatures_StringView_PopFront) { +++ EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 2), str("st")); +++ EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 0), str("test")); +++ EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 4), str("")); +++ EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 100), str("")); +++} +++ +++TEST(StringViewTest, CpuFeatures_StringView_PopBack) { +++ EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 2), str("te")); +++ EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 0), str("test")); +++ EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 4), str("")); +++ EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 100), str("")); +++} +++ +++TEST(StringViewTest, CpuFeatures_StringView_KeepFront) { +++ EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 2), str("te")); +++ EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 0), str("")); +++ EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 4), str("test")); +++ EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 6), str("test")); +++} +++ +++TEST(StringViewTest, CpuFeatures_StringView_Front) { +++ EXPECT_EQ(CpuFeatures_StringView_Front(str("apple")), 'a'); +++ EXPECT_EQ(CpuFeatures_StringView_Front(str("a")), 'a'); +++} +++ +++TEST(StringViewTest, CpuFeatures_StringView_Back) { +++ EXPECT_EQ(CpuFeatures_StringView_Back(str("apple")), 'e'); +++ EXPECT_EQ(CpuFeatures_StringView_Back(str("a")), 'a'); +++} +++ +++TEST(StringViewTest, CpuFeatures_StringView_TrimWhitespace) { +++ EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str(" first middle last ")), +++ str("first middle last")); +++ EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str("first middle last ")), +++ str("first middle last")); +++ EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str(" first middle last")), +++ str("first middle last")); +++ EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str("first middle last")), +++ str("first middle last")); +++} +++ +++TEST(StringViewTest, CpuFeatures_StringView_ParsePositiveNumber) { +++ EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("42")), 42); +++ EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2a")), 42); +++ EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2A")), 42); +++ EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2A2a")), 10794); +++ EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2a2A")), 10794); +++ +++ EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("-10")), -1); +++ EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("-0x2A")), -1); +++ EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("abc")), -1); +++ EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("")), -1); +++} +++ +++TEST(StringViewTest, CpuFeatures_StringView_CopyString) { +++ char buf[4]; +++ buf[0] = 'X'; +++ +++ // Empty +++ CpuFeatures_StringView_CopyString(str(""), buf, sizeof(buf)); +++ EXPECT_STREQ(buf, ""); +++ +++ // Less +++ CpuFeatures_StringView_CopyString(str("a"), buf, sizeof(buf)); +++ EXPECT_STREQ(buf, "a"); +++ +++ // exact +++ CpuFeatures_StringView_CopyString(str("abc"), buf, sizeof(buf)); +++ EXPECT_STREQ(buf, "abc"); +++ +++ // More +++ CpuFeatures_StringView_CopyString(str("abcd"), buf, sizeof(buf)); +++ EXPECT_STREQ(buf, "abc"); +++} +++ +++TEST(StringViewTest, CpuFeatures_StringView_HasWord) { +++ // Find flags at beginning, middle and end. +++ EXPECT_TRUE( +++ CpuFeatures_StringView_HasWord(str("first middle last"), "first")); +++ EXPECT_TRUE( +++ CpuFeatures_StringView_HasWord(str("first middle last"), "middle")); +++ EXPECT_TRUE(CpuFeatures_StringView_HasWord(str("first middle last"), "last")); +++ // Do not match partial flags +++ EXPECT_FALSE( +++ CpuFeatures_StringView_HasWord(str("first middle last"), "irst")); +++ EXPECT_FALSE(CpuFeatures_StringView_HasWord(str("first middle last"), "mid")); +++ EXPECT_FALSE(CpuFeatures_StringView_HasWord(str("first middle last"), "las")); +++} +++ +++TEST(StringViewTest, CpuFeatures_StringView_GetAttributeKeyValue) { +++ const StringView line = str(" key : first middle last "); +++ StringView key, value; +++ EXPECT_TRUE(CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)); +++ EXPECT_EQ(key, str("key")); +++ EXPECT_EQ(value, str("first middle last")); +++} +++ +++TEST(StringViewTest, FailingGetAttributeKeyValue) { +++ const StringView line = str("key first middle last"); +++ StringView key, value; +++ EXPECT_FALSE(CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)); +++} +++ +++} // namespace +++} // namespace cpu_features diff --cc debian/changelog index 0000000,0000000,0000000..45f18a6 new file mode 100644 --- /dev/null +++ b/debian/changelog @@@@ -1,0 -1,0 -1,0 +1,491 @@@@ +++volk (2.4.0-3) unstable; urgency=medium +++ +++ * Fix binary-indep build (Closes: #976300) +++ * Upload to unstable +++ +++ -- A. Maitland Bottoms Thu, 03 Dec 2020 20:43:29 -0500 +++ +++volk (2.4.0-2) experimental; urgency=medium +++ +++ * Make use of cpu_features a CMake option with sensible defaults per arch +++ +++ -- A. Maitland Bottoms Mon, 30 Nov 2020 16:19:19 -0500 +++ +++volk (2.4.0-1) experimental; urgency=medium +++ +++ * New upstream release +++ * cpu_features git submodule packaged as cpu-features source component. +++ * Upload to experimental for soversion bump +++ +++ -- A. Maitland Bottoms Sun, 22 Nov 2020 12:35:43 -0500 +++ +++volk (2.3.0-3) unstable; urgency=medium +++ +++ * update to v2.3.0-14-g91e5d07 +++ emit an emms instruction after using the mmx extension +++ +++ -- A. Maitland Bottoms Tue, 30 Jun 2020 19:48:20 -0400 +++ +++volk (2.3.0-2) unstable; urgency=medium +++ +++ * Upload to unstable +++ +++ -- A. Maitland Bottoms Mon, 11 May 2020 07:26:03 -0400 +++ +++volk (2.3.0-1) experimental; urgency=medium +++ +++ * New upstream release, to experimental for soversion bump +++ * Kernels +++ - volk: accurate exp kernel +++ - exp: Rename SSE4.1 to SSE2 kernel +++ - Add 32f_s32f_add_32f kernel +++ - This kernel adds in vector + scalar functionality +++ - Fix the broken index max kernels +++ - Treat the mod_range puppet as such +++ - Add puppet for power spectral density kernel +++ - Updated log10 calcs to use faster log2 approach +++ - fix: Use unaligned load +++ - divide: Optimize complexmultiplyconjugate +++ +++ -- A. Maitland Bottoms Sat, 09 May 2020 15:42:23 -0400 +++ +++volk (2.2.1-3) unstable; urgency=medium +++ +++ * update to v2.2.1-34-gd4756c5 +++ +++ -- A. Maitland Bottoms Sun, 05 Apr 2020 10:37:46 -0400 +++ +++volk (2.2.1-2) unstable; urgency=medium +++ +++ * update to v2.2.1-11-gfaf230e +++ * cmake: Remove the ORC from the VOLK public link interface +++ * Fix the broken index max kernels +++ +++ -- A. Maitland Bottoms Fri, 27 Mar 2020 21:48:10 -0400 +++ +++volk (2.2.1-1) unstable; urgency=high +++ +++ * New upstream bugfix release +++ reason for high urgency: +++ - Fix loop bound in AVX rotator (only one fixed in 2.2.0-3) +++ - Fix out-of-bounds read in AVX2 square dist kernel +++ - Fix length checks in AVX2 index max kernels +++ +++ -- A. Maitland Bottoms Mon, 24 Feb 2020 18:08:05 -0500 +++ +++volk (2.2.0-3) unstable; urgency=high +++ +++ * Update to v2.2.0-6-g5701f8f +++ reason for high urgency: +++ - Fix loop bound in AVX rotator +++ +++ -- A. Maitland Bottoms Sun, 23 Feb 2020 23:49:18 -0500 +++ +++volk (2.2.0-2) unstable; urgency=medium +++ +++ * Upload to unstable +++ +++ -- A. Maitland Bottoms Tue, 18 Feb 2020 17:56:58 -0500 +++ +++volk (2.2.0-1) experimental; urgency=medium +++ +++ * New upstream release +++ - Remove build dependency on python six +++ - Fixup VolkConfigVersion +++ - add volk_version.h +++ +++ -- A. Maitland Bottoms Sun, 16 Feb 2020 18:25:20 -0500 +++ +++volk (2.1.0-2) unstable; urgency=medium +++ +++ * Upload to unstable +++ +++ -- A. Maitland Bottoms Sun, 05 Jan 2020 23:17:57 -0500 +++ +++volk (2.1.0-1) experimental; urgency=medium +++ +++ * New upstream release +++ - The AVX FMA rotator bug is fixed +++ - VOLK offers `volk::vector<>` for C++ to follow RAII +++ - Use C++17 `std::filesystem` +++ - This enables VOLK to be built without Boost if available! +++ - lots of bugfixes +++ - more optimized kernels, especially more NEON versions +++ * Upload to experimental for new ABI library package libvolk2.1 +++ +++ -- A. Maitland Bottoms Sun, 22 Dec 2019 10:27:36 -0500 +++ +++volk (2.0.0-3) unstable; urgency=medium +++ +++ * update to v2.0.0-4-gf04a46f +++ +++ -- A. Maitland Bottoms Thu, 14 Nov 2019 22:47:23 -0500 +++ +++volk (2.0.0-2) unstable; urgency=medium +++ +++ * Upload to unstable +++ +++ -- A. Maitland Bottoms Mon, 12 Aug 2019 22:49:11 -0400 +++ +++volk (2.0.0-1) experimental; urgency=medium +++ +++ * New upstream release +++ +++ -- A. Maitland Bottoms Wed, 07 Aug 2019 23:31:20 -0400 +++ +++volk (1.4-4) unstable; urgency=medium +++ +++ * working volk_modtool with Python 3 +++ * build and install libvolk.a +++ +++ -- A. Maitland Bottoms Mon, 29 Oct 2018 01:32:05 -0400 +++ +++volk (1.4-3) unstable; urgency=medium +++ +++ * update to v1.4-9-g297fefd +++ Added an AVX protokernel for volk_32fc_x2_32f_square_dist_scalar_mult_32f +++ fixed a buffer over-read and over-write in +++ volk_32fc_x2_s32f_square_dist_scalar_mult_32f_a_avx +++ Fix 32u_reverse_32u for ARM +++ +++ -- A. Maitland Bottoms Sat, 12 May 2018 15:25:04 -0400 +++ +++volk (1.4-2) unstable; urgency=medium +++ +++ * Upload to unstable, needed by gnuradio (>= 3.7.12.0) +++ +++ -- A. Maitland Bottoms Tue, 03 Apr 2018 01:03:19 -0400 +++ +++volk (1.4-1) experimental; urgency=medium +++ +++ * New upstream release +++ upstream changelog http://libvolk.org/release-v14.html +++ +++ -- A. Maitland Bottoms Tue, 27 Mar 2018 22:57:42 -0400 +++ +++volk (1.3.1-1) unstable; urgency=medium +++ +++ * New upstream bugfix release +++ * Refresh all debian patches for use with git am +++ +++ -- A. Maitland Bottoms Tue, 27 Mar 2018 21:54:29 -0400 +++ +++volk (1.3-3) unstable; urgency=medium +++ +++ * update to v1.3-23-g0109b2e +++ * update debian/libvolk1-dev.abi.tar.gz.amd64 +++ * Add breaks/replaces gnuradio (<=3.7.2.1) (LP: #1614235) +++ +++ -- A. Maitland Bottoms Sun, 04 Feb 2018 13:12:21 -0500 +++ +++volk (1.3-2) unstable; urgency=medium +++ +++ * update to v1.3-16-g28b03a9 +++ apps: fix profile update reading end of lines +++ qa: lower tolerance for 32fc_mag to fix issue #96 +++ * include upstream master patch to sort input files +++ +++ -- A. Maitland Bottoms Sun, 27 Aug 2017 13:44:55 -0400 +++ +++volk (1.3-1) unstable; urgency=medium +++ +++ * New upstream release +++ * The index_max kernels were named with the wrong output datatype. To +++ fix this there are new kernels that return a 32u (int32_t) and the +++ existing kernels had their signatures changed to return 16u (int16_t). +++ * The output to stdout and stderr has been shuffled around. There is no +++ longer a message that prints what VOLK machine is being used and the +++ warning messages go to stderr rather than stdout. +++ * The 32fc_index_max kernels previously were only accurate to the SSE +++ register width (4 points). This was a pretty serious and long-lived +++ bug that's been fixed and the QA updated appropriately. +++ +++ -- A. Maitland Bottoms Sat, 02 Jul 2016 16:30:47 -0400 +++ +++volk (1.2.2-2) unstable; urgency=medium +++ +++ * update to v1.2.2-11-g78c8bc4 (to follow gnuradio maint branch) +++ +++ -- A. Maitland Bottoms Sun, 19 Jun 2016 14:44:15 -0400 +++ +++volk (1.2.2-1) unstable; urgency=medium +++ +++ * New upstream release +++ +++ -- A. Maitland Bottoms Fri, 08 Apr 2016 00:12:10 -0400 +++ +++volk (1.2.1-2) unstable; urgency=medium +++ +++ * Upstream patches: +++ Fix some CMake complaints +++ The fix for compilation with cmake 3.5 +++ +++ -- A. Maitland Bottoms Wed, 23 Mar 2016 17:47:54 -0400 +++ +++volk (1.2.1-1) unstable; urgency=medium +++ +++ * New upstream release +++ +++ -- A. Maitland Bottoms Sun, 07 Feb 2016 19:38:32 -0500 +++ +++volk (1.2-1) unstable; urgency=medium +++ +++ * New upstream release +++ +++ -- A. Maitland Bottoms Thu, 24 Dec 2015 20:28:13 -0500 +++ +++volk (1.1.1-5) experimental; urgency=medium +++ +++ * update to v1.1.1-22-gef53547 to support gnuradio 3.7.9 +++ +++ -- A. Maitland Bottoms Fri, 11 Dec 2015 13:12:55 -0500 +++ +++volk (1.1.1-4) unstable; urgency=medium +++ +++ * more lintian fixes +++ +++ -- A. Maitland Bottoms Wed, 25 Nov 2015 21:49:58 -0500 +++ +++volk (1.1.1-3) unstable; urgency=medium +++ +++ * Lintian fixes Pre-Depends +++ +++ -- A. Maitland Bottoms Thu, 19 Nov 2015 21:24:27 -0500 +++ +++volk (1.1.1-2) unstable; urgency=medium +++ +++ * Note that libvolk1-dev replaces files in gnuradio-dev versions <<3.7.8 +++ (Closes: #802646) again. Thanks Andreas Beckmann. +++ +++ -- A. Maitland Bottoms Fri, 13 Nov 2015 18:45:49 -0500 +++ +++volk (1.1.1-1) unstable; urgency=medium +++ +++ * New upstream release +++ * New architectures exist for the AVX2 and FMA ISAs. +++ * The profiler now generates buffers that are vlen + a tiny amount and +++ generates random data to fill buffers. This is intended to catch bugs +++ in protokernels that write beyond num_points. +++ * Note that libvolk1-dev replaces files in earlier gnuradio-dev versions +++ (Closes: #802646) +++ +++ -- A. Maitland Bottoms Sun, 01 Nov 2015 18:45:43 -0500 +++ +++volk (1.1-4) unstable; urgency=medium +++ +++ * update to v1.1-12-g264addc +++ +++ -- A. Maitland Bottoms Tue, 29 Sep 2015 23:41:50 -0400 +++ +++volk (1.1-3) unstable; urgency=low +++ +++ * drop dh_acc to get reproducible builds +++ +++ -- A. Maitland Bottoms Fri, 11 Sep 2015 22:57:06 -0400 +++ +++volk (1.1-2) unstable; urgency=low +++ +++ * use dh-acc +++ +++ -- A. Maitland Bottoms Mon, 07 Sep 2015 15:45:20 -0400 +++ +++volk (1.1-1) unstable; urgency=medium +++ +++ * re-organize package naming convention +++ * New upstream release tag v1.1 +++ New architectures exist for the AVX2 and FMA ISAs. Along +++ with the build-system support the following kernels have +++ no proto-kernels taking advantage of these architectures: +++ +++ * 32f_x2_dot_prod_32f +++ * 32fc_x2_multiply_32fc +++ * 64_byteswap +++ * 32f_binary_slicer_8i +++ * 16u_byteswap +++ * 32u_byteswap +++ +++ QA/profiler +++ ----------- +++ +++ The profiler now generates buffers that are vlen + a tiny +++ amount and generates random data to fill buffers. This is +++ intended to catch bugs in protokernels that write beyond +++ num_points. +++ +++ -- A. Maitland Bottoms Wed, 26 Aug 2015 09:22:48 -0400 +++ +++volk (1.0.2-2) unstable; urgency=low +++ +++ * Use SOURCE_DATE_EPOCH from the environment, if defined, +++ rather than current date and time to implement volk_build_date() +++ (embedding build date in a library does not help reproducible builds) +++ * add watch file +++ +++ -- A. Maitland Bottoms Sat, 15 Aug 2015 17:43:15 -0400 +++ +++volk (1.0.2-1) unstable; urgency=medium +++ +++ * Maintenance release 24 Jul 2015 by Nathan West +++ * The major change is the CMake logic to add ASM protokernels. Rather +++ than depending on CFLAGS and ASMFLAGS we use the results of VOLK's +++ built in has_ARCH tests. All configurations should work the same as +++ before, but manually specifying CFLAGS and ASMFLAGS on the cmake call +++ for ARM native builds should no longer be necessary. +++ * The 32fc_s32fc_x2_rotator_32fc generic protokernel now includes a +++ previously implied header. +++ * Finally, there is a fix to return the "best" protokernel to the +++ dispatcher when no volk_config exists. Thanks to Alexandre Raymond for +++ pointing this out. +++ * with maint branch patch: +++ kernels-add-missing-include-arm_neon.h +++ * removed unused build-dependency on liboil0.3-dev (closes: #793626) +++ +++ -- A. Maitland Bottoms Wed, 05 Aug 2015 00:43:40 -0400 +++ +++volk (1.0.1-1) unstable; urgency=low +++ +++ * Maintenance Release v1.0.1 08 Jul 2015 by Nathan West +++ This is a maintenance release with bug fixes since the initial release of +++ v1.0 in April. +++ +++ * Contributors +++ +++ The following authors have contributed code to this release: +++ +++ Doug Geiger doug.geiger@bioradiation.net +++ Elliot Briggs elliot.briggs@gmail.com +++ Marcus Mueller marcus@hostalia.de +++ Nathan West nathan.west@okstate.edu +++ Tom Rondeau tom@trondeau.com +++ +++ * Kernels +++ +++ Several bug fixes in different kernels. The NEON implementations of the +++ following kernels have been fixed: +++ +++ 32f_x2_add_32f +++ 32f_x2_dot_prod_32f +++ 32fc_s32fc_multiply_32fc +++ 32fc_x2_multiply_32fc +++ +++ Additionally the NEON asm based 32f_x2_add_32f protokernels were not being +++ used and are now included and available for use via the dispatcher. +++ +++ The 32f_s32f_x2_fm_detect_32f kernel now has a puppet. This solves QA seg +++ faults on 32-bit machines and provide a better test for this kernel. +++ +++ The 32fc_s32fc_x2_rotator_32fc generic protokernel replaced cabsf with +++ hypotf for better Android support. +++ +++ * Building +++ +++ Static builds now trigger the applications (volk_profile and +++ volk-config-info) to be statically linked. +++ +++ The file gcc_x86_cpuid.h has been removed since it was no longer being +++ used. Previously it provided cpuid functionality for ancient compilers +++ that we do not support. +++ +++ All build types now use -Wall. +++ +++ * QA and Testing +++ +++ The documentation around the --update option to volk_profile now makes it +++ clear that the option will only profile kernels without entries in +++ volk_profile. The signature of run_volk_tests with expanded args changed +++ signed types to unsigned types to reflect the actual input. +++ +++ The remaining changes are all non-functional changes to address issues +++ from Coverity. +++ +++ -- A. Maitland Bottoms Fri, 10 Jul 2015 17:57:42 -0400 +++ +++volk (1.0-5) unstable; urgency=medium +++ +++ * native-armv7-build-support skips neon on Debian armel (Closes: #789972) +++ +++ -- A. Maitland Bottoms Sat, 04 Jul 2015 12:36:36 -0400 +++ +++volk (1.0-4) unstable; urgency=low +++ +++ * update native-armv7-build-support patch from gnuradio volk package +++ +++ -- A. Maitland Bottoms Thu, 25 Jun 2015 16:38:49 -0400 +++ +++volk (1.0-3) unstable; urgency=medium +++ +++ * Add Breaks/Replaces (Closes: #789893, #789894) +++ * Allow failing tests +++ +++ -- A. Maitland Bottoms Thu, 25 Jun 2015 12:46:06 -0400 +++ +++volk (1.0-2) unstable; urgency=medium +++ +++ * kernels-add-missing-math.h-include-to-rotator +++ +++ -- A. Maitland Bottoms Wed, 24 Jun 2015 21:09:32 -0400 +++ +++volk (1.0-1) unstable; urgency=low +++ +++ * Initial package (Closes: #782417) +++ Initial Release 11 Apr 2015 by Nathan West +++ +++ VOLK 1.0 is available. This is the first release of VOLK as an independently +++ tracked sub-project of GNU Radio. +++ +++ * Contributors +++ +++ VOLK has been tracked separately from GNU Radio since 2014 Dec 23. +++ Contributors between the split and the initial release are +++ +++ Albert Holguin aholguin_77@yahoo.com +++ Doug Geiger doug.geiger@bioradiation.net +++ Elliot Briggs elliot.briggs@gmail.com +++ Julien Olivain julien.olivain@lsv.ens-cachan.fr +++ Michael Dickens michael.dickens@ettus.com +++ Nathan West nathan.west@okstate.edu +++ Tom Rondeau tom@trondeau.com +++ +++ * QA +++ +++ The test and profiler have significantly changed. The profiler supports +++ run-time changes to vlen and iters to help kernel development and provide +++ more flexibility on embedded systems. Additionally there is a new option +++ to update an existing volk_profile results file with only new kernels which +++ will save time when updating to newer versions of VOLK +++ +++ The QA system creates a static list of kernels and test cases. The QA +++ testing and profiler iterate over this static list rather than each source +++ file keeping its own list. The QA also emits XML results to +++ lib/.unittest/kernels.xml which is formatted similarly to JUnit results. +++ +++ * Modtool +++ +++ Modtool was updated to support the QA and profiler changes. +++ +++ * Kernels +++ +++ New proto-kernels: +++ +++ 16ic_deinterleave_real_8i_neon +++ 16ic_s32f_deinterleave_32f_neon +++ fix preprocessor errors for some compilers on byteswap and popcount puppets +++ +++ ORC was moved to the asm kernels directory. +++ volk_malloc +++ +++ The posix_memalign implementation of Volk_malloc now falls back to a standard +++ malloc if alignment is 1. +++ +++ * Miscellaneous +++ +++ Several build system and cmake changes have made it possible to build VOLK +++ both independently with proper soname versions and in-tree for projects +++ such as GNU Radio. +++ +++ The static builds take advantage of cmake object libraries to speed up builds. +++ +++ Finally, there are a number of changes to satisfy compiler warnings and make +++ QA work on multiple machines. +++ +++ -- A. Maitland Bottoms Sun, 12 Apr 2015 23:20:41 -0400 diff --cc debian/control index 0000000,0000000,0000000..b045f04 new file mode 100644 --- /dev/null +++ b/debian/control @@@@ -1,0 -1,0 -1,0 +1,80 @@@@ +++Source: volk +++Section: libdevel +++Priority: optional +++Maintainer: A. Maitland Bottoms +++Build-Depends: cmake, +++ debhelper-compat (= 13), +++ dh-python, +++ liborc-0.4-dev, +++ python3-dev, +++ python3-mako +++Build-Depends-Indep: doxygen, graphviz +++Standards-Version: 4.5.0 +++Rules-Requires-Root: no +++Homepage: https://libvolk.org +++Vcs-Browser: https://salsa.debian.org/bottoms/pkg-volk +++Vcs-Git: https://salsa.debian.org/bottoms/pkg-volk.git +++ +++Package: libvolk2.4 +++Section: libs +++Architecture: any +++Pre-Depends: ${misc:Pre-Depends} +++Depends: ${misc:Depends}, ${shlibs:Depends} +++Multi-Arch: same +++Recommends: libvolk2-bin +++Suggests: libvolk2-dev +++Description: vector optimized functions +++ Vector-Optimized Library of Kernels is designed to help +++ applications work with the processor's SIMD instruction sets. These are +++ very powerful vector operations that can give signal processing a +++ huge boost in performance. +++ +++Package: libvolk2-dev +++Architecture: any +++Pre-Depends: ${misc:Pre-Depends} +++Depends: libvolk2.4 (=${binary:Version}), ${misc:Depends} +++Breaks: gnuradio-dev (<<3.7.8), libvolk-dev, libvolk1.0-dev, libvolk1-dev +++Replaces: gnuradio-dev (<<3.7.8), libvolk-dev, libvolk1.0-dev, libvolk1-dev +++Suggests: libvolk2-doc +++Multi-Arch: same +++Description: vector optimized function headers +++ Vector-Optimized Library of Kernels is designed to help +++ applications work with the processor's SIMD instruction sets. These are +++ very powerful vector operations that can give signal processing a +++ huge boost in performance. +++ . +++ This package contains the header files. +++ For documentation, see libvolk-doc. +++ +++Package: libvolk2-bin +++Section: libs +++Architecture: any +++Pre-Depends: ${misc:Pre-Depends} +++Depends: libvolk2.4 (=${binary:Version}), +++ ${misc:Depends}, +++ ${python3:Depends}, +++ ${shlibs:Depends} +++Breaks: libvolk1-bin, libvolk-bin, libvolk1.0-bin, gnuradio (<=3.7.2.1) +++Replaces: libvolk1-bin, libvolk-bin, libvolk1.0-bin, gnuradio (<=3.7.2.1) +++Description: vector optimized runtime tools +++ Vector-Optimized Library of Kernels is designed to help +++ applications work with the processor's SIMD instruction sets. These are +++ very powerful vector operations that can give signal processing a +++ huge boost in performance. +++ . +++ This package includes the volk_profile tool. +++ +++Package: libvolk2-doc +++Section: doc +++Architecture: all +++Multi-Arch: foreign +++Depends: ${misc:Depends} +++Recommends: lynx | www-browser +++Description: vector optimized library documentation +++ Vector-Optimized Library of Kernels is designed to help +++ applications work with the processor's SIMD instruction sets. These are +++ very powerful vector operations that can give signal processing a +++ huge boost in performance. +++ . +++ This package includes the Doxygen generated documentation in +++ /usr/share/doc/libvolk2-dev/html/index.html diff --cc debian/copyright index 0000000,0000000,0000000..92bbc43 new file mode 100644 --- /dev/null +++ b/debian/copyright @@@@ -1,0 -1,0 -1,0 +1,195 @@@@ +++Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +++Upstream-Name: volk +++Upstream-Contact: http://libvolk.org/ +++Source: +++ https://github.com/gnuradio/volk +++ https://github.com/google/cpu_features +++Comment: +++ Debian packages by A. Maitland Bottoms +++ git archive --format=tar --prefix=volk-2.3.0/ v2.3.0 | xz > ../volk_2.3.0.orig.tar.xz +++ git archive --format=tar --prefix=cpu_features/ v0.6.0 | xz > ../volk_2.4.0.orig-cpu_features.tar.xz +++ . +++ Upstream Maintainers: +++ Johannes Demel +++ Michael Dickens +++Copyright: 2014-2020 Free Software Foundation, Inc. +++License: GPL-3+ +++ +++Files: * +++Copyright: 2006, 2009-2020, Free Software Foundation, Inc. +++License: GPL-3+ +++ +++Files: Doxyfile.in +++ DoxygenLayout.xml +++ volk.pc.in +++Copyright: 2014-2020 Free Software Foundation, Inc. +++License: GPL-3+ +++ +++Files: apps/volk_profile.h +++Copyright: 2014-2020 Free Software Foundation, Inc. +++License: GPL-3+ +++ +++Files: appveyor.yml +++Copyright: 2016 Paul Cercueil +++License: GPL-3+ +++ +++Files: cmake/* +++Copyright: 2014-2020 Free Software Foundation, Inc. +++License: GPL-3+ +++ +++Files: cmake/Modules/* +++Copyright: 2006, 2009-2020, Free Software Foundation, Inc. +++License: GPL-3+ +++ +++Files: cpu_features/* +++Copyright: 2020 Google LLC +++License: Apache-2.0 +++ 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. +++ . +++ On Debian systems, the complete text of the Apache-2.0 License +++ can be found in "/usr/share/common-licenses/Apache-2.0". +++ +++Files: cmake/Modules/CMakeParseArgumentsCopy.cmake +++Copyright: 2010 Alexander Neundorf +++License: Kitware-BSD +++ All rights reserved. +++ . +++ Redistribution and use in source and binary forms, with or without +++ modification, are permitted provided that the following conditions +++ are met: +++ . +++ * Redistributions of source code must retain the above copyright +++ notice, this list of conditions and the following disclaimer. +++ . +++ * Redistributions in binary form must reproduce the above copyright +++ notice, this list of conditions and the following disclaimer in the +++ documentation and/or other materials provided with the distribution. +++ . +++ * Neither the names of Kitware, Inc., the Insight Software Consortium, +++ nor the names of their contributors may be used to endorse or promote +++ products derived from this software without specific prior written +++ permission. +++ . +++ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +++ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +++ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +++ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +++ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +++ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +++ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +++ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +++ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +++ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +++ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +++ +++Files: cmake/Modules/FindORC.cmake +++ cmake/Modules/VolkConfig.cmake.in +++Copyright: 2014-2015 Free Software Foundation, Inc. +++License: GPL-3+ +++ +++Files: cmake/msvc/* +++Copyright: 2006-2008, Alexander Chemeris +++License: BSD-2-clause +++ Redistribution and use in source and binary forms, with or without +++ modification, are permitted provided that the following conditions are met: +++ . +++ 1. Redistributions of source code must retain the above copyright notice, +++ this list of conditions and the following disclaimer. +++ . +++ 2. Redistributions in binary form must reproduce the above copyright +++ notice, this list of conditions and the following disclaimer in the +++ documentation and/or other materials provided with the distribution. +++ . +++ 3. The name of the author may be used to endorse or promote products +++ derived from this software without specific prior written permission. +++ . +++ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +++ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +++ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +++ EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +++ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +++ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +++ OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +++ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +++ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +++ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +++ +++Files: debian/* +++Copyright: 2015-2020 Free Software Foundation, Inc +++License: GPL-3+ +++Comment: assigned by A. Maitland Bottoms +++ +++Files: docs/* +++Copyright: 2014-2015 Free Software Foundation, Inc. +++License: GPL-3+ +++ +++Files: gen/archs.xml +++ gen/machines.xml +++Copyright: 2014-2015 Free Software Foundation, Inc. +++License: GPL-3+ +++ +++Files: include/volk/volk_common.h +++ include/volk/volk_complex.h +++ include/volk/volk_prefs.h +++Copyright: 2014-2015 Free Software Foundation, Inc. +++License: GPL-3+ +++ +++Files: kernels/volk/asm/* +++Copyright: 2014-2015 Free Software Foundation, Inc. +++License: GPL-3+ +++ +++Files: kernels/volk/volk_16u_byteswappuppet_16u.h +++ kernels/volk/volk_32u_byteswappuppet_32u.h +++ kernels/volk/volk_64u_byteswappuppet_64u.h +++Copyright: 2014-2015 Free Software Foundation, Inc. +++License: GPL-3+ +++ +++Files: lib/kernel_tests.h +++ lib/qa_utils.cc +++ lib/qa_utils.h +++ lib/volk_prefs.c +++Copyright: 2014-2015 Free Software Foundation, Inc. +++License: GPL-3+ +++ +++License: LGPL-2+ +++ This library is free software; you can redistribute it and/or +++ modify it under the terms of the GNU Library General Public +++ License as published by the Free Software Foundation; either +++ version 2 of the License, or (at your option) any later version. +++ . +++ This library is distributed in the hope that it will be useful, +++ but WITHOUT ANY WARRANTY; without even the implied warranty of +++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +++ Library General Public License for more details. +++ . +++ You should have received a copy of the GNU Library General Public License +++ along with this library; see the file COPYING.LIB. If not, write to +++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +++ Boston, MA 02110-1301, USA. +++ +++License: GPL-3+ +++ This program is free software: you can redistribute it and/or modify +++ it under the terms of the GNU General Public License as published by +++ the Free Software Foundation; either version 3 of the License, or +++ (at your option) any later version. +++ . +++ This program is distributed in the hope that it will be useful, +++ but WITHOUT ANY WARRANTY; without even the implied warranty of +++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +++ GNU General Public License for more details. +++ . +++ You should have received a copy of the GNU General Public License +++ along with this program. If not, see . +++ . +++ On Debian systems, the complete text of the GNU General +++ Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". diff --cc debian/libvolk2-bin.install index 0000000,0000000,0000000..7221b71 new file mode 100644 --- /dev/null +++ b/debian/libvolk2-bin.install @@@@ -1,0 -1,0 -1,0 +1,2 @@@@ +++usr/bin/volk* +++usr/lib/python3/dist-packages diff --cc debian/libvolk2-bin.manpages index 0000000,0000000,0000000..95bae9e new file mode 100644 --- /dev/null +++ b/debian/libvolk2-bin.manpages @@@@ -1,0 -1,0 -1,0 +1,3 @@@@ +++debian/volk-config-info.1 +++debian/volk_modtool.1 +++debian/volk_profile.1 diff --cc debian/libvolk2-dev.acc index 0000000,0000000,0000000..37f5a79 new file mode 100644 --- /dev/null +++ b/debian/libvolk2-dev.acc @@@@ -1,0 -1,0 -1,0 +1,50 @@@@ +++ +++ +++ +++ +++ -DHAVE_CPUID_H +++ -DHAVE_DLFCN_H +++ -DHAVE_FENV_H +++ -DHAVE_POSIX_MEMALIGN +++ -DHAVE_XGETBV +++ -D_GLIBCXX_USE_CXX11_ABI=1 +++ -I/usr/include/orc-0.4 +++ -DNDEBUG +++ -std=gnu11 +++ -m64 +++ -mmmx +++ -msse +++ -msse2 +++ -msse3 +++ -mssse3 +++ -msse4.1 +++ -msse4.2 +++ -mpopcnt +++ -mavx +++ -mfma +++ -mavx2 +++ -mavx512f +++ -mavx512cd +++ -fPIC +++ -g +++ -O2 +++ -fstack-protector-strong +++ -Wformat +++ -Werror=format-security +++ -Wdate-time +++ -D_FORTIFY_SOURCE=2 +++ -fvisibility=hidden +++ -Wsign-compare +++ -Wall +++ -Wno-uninitialized +++ +++ +++ +++debian/libvolk2-dev/usr/include/volk/ +++ +++ +++ +++debian/libvolk2.0/usr/lib/ +++ +++ +++ diff --cc debian/libvolk2-dev.install index 0000000,0000000,0000000..8b14c56 new file mode 100644 --- /dev/null +++ b/debian/libvolk2-dev.install @@@@ -1,0 -1,0 -1,0 +1,5 @@@@ +++usr/include/* +++usr/lib/*/*volk.a +++usr/lib/*/*volk*so +++usr/lib/*/cmake/volk +++usr/lib/*/pkgconfig/*volk* diff --cc debian/libvolk2-doc.doc-base index 0000000,0000000,0000000..3d5fdc8 new file mode 100644 --- /dev/null +++ b/debian/libvolk2-doc.doc-base @@@@ -1,0 -1,0 -1,0 +1,19 @@@@ +++Document: libvolk2-doc +++Title: Vector-Optimized Library of Kernels Reference Manual +++Author: GNU Radio Developers +++Abstract: VOLK is the Vector-Optimized Library of Kernels. +++ It is a library that contains kernels of hand-written SIMD code for +++ different mathematical operations. Since each SIMD architecture can +++ be very different and no compiler has yet come along to handle +++ vectorization properly or highly efficiently, VOLK approaches the +++ problem differently. For each architecture or platform that a +++ developer wishes to vectorize for, a new proto-kernel is added to +++ VOLK. At runtime, VOLK will select the correct proto-kernel. In this +++ way, the users of VOLK call a kernel for performing the operation +++ that is platform/architecture agnostic. This allows us to write +++ portable SIMD code. +++Section: Programming/C++ +++ +++Format: HTML +++Index: /usr/share/doc/libvolk2-dev/html/index.html +++Files: /usr/share/doc/libvolk2-dev/html/*.html diff --cc debian/libvolk2-doc.docs index 0000000,0000000,0000000..87dd314 new file mode 100644 --- /dev/null +++ b/debian/libvolk2-doc.docs @@@@ -1,0 -1,0 -1,0 +1,1 @@@@ +++obj-*/html diff --cc debian/libvolk2.4.install index 0000000,0000000,0000000..e4252f4 new file mode 100644 --- /dev/null +++ b/debian/libvolk2.4.install @@@@ -1,0 -1,0 -1,0 +1,1 @@@@ +++usr/lib/*/libvolk.so.* diff --cc debian/not-installed index 0000000,0000000,0000000..6f354d0 new file mode 100644 --- /dev/null +++ b/debian/not-installed @@@@ -1,0 -1,0 -1,0 +1,6 @@@@ +++usr/bin/list_cpu_features +++usr/lib/*/cmake/CpuFeatures/CpuFeaturesConfig.cmake +++usr/lib/*/cmake/CpuFeatures/CpuFeaturesConfigVersion.cmake +++usr/lib/*/cmake/CpuFeatures/CpuFeaturesTargets-relwithdebinfo.cmake +++usr/lib/*/cmake/CpuFeatures/CpuFeaturesTargets.cmake +++usr/lib/*/libcpu_features.a diff --cc debian/patches/cpu_features-CMake-option index 0000000,0000000,0000000..e30d930 new file mode 100644 --- /dev/null +++ b/debian/patches/cpu_features-CMake-option @@@@ -1,0 -1,0 -1,0 +1,105 @@@@ +++From 21201840dc294affbfc173868bc55569ef114655 Mon Sep 17 00:00:00 2001 +++From: "A. Maitland Bottoms" +++Date: Tue, 1 Dec 2020 11:29:12 -0500 +++Subject: [PATCH] cpu_features CMake option +++ +++Make use of cpu_features a CMake option with sensible defaults per arch. +++(avoiding CMake failures of cpu_features for unknown architectures) +++--- +++ CMakeLists.txt | 23 +++++++++++++++++------ +++ lib/CMakeLists.txt | 12 ++++++++++-- +++ tmpl/volk_cpu.tmpl.c | 2 ++ +++ 3 files changed, 29 insertions(+), 8 deletions(-) +++ +++diff --git a/CMakeLists.txt b/CMakeLists.txt +++index eb73e20..f905230 100644 +++--- a/CMakeLists.txt ++++++ b/CMakeLists.txt +++@@ -114,14 +114,25 @@ endif(MSVC) +++ # Dependencies setup +++ ######################################################################## +++ +++-# cpu_features +++-set(BUILD_PIC ON CACHE BOOL ++++# cpu_features - sensible defaults, user settable option ++++if(CMAKE_SYSTEM_PROCESSOR MATCHES ++++ "(^mips)|(^arm)|(^aarch64)|(x86_64)|(AMD64|amd64)|(^i.86$)|(^powerpc)|(^ppc)") ++++ option(VOLK_CPU_FEATURES "Volk uses cpu_features" ON) ++++else() ++++ option(VOLK_CPU_FEATURES "Volk uses cpu_features" OFF) ++++endif() ++++if (VOLK_CPU_FEATURES) ++++ message(STATUS "Building Volk with cpu_features") ++++ set(BUILD_PIC ON CACHE BOOL +++ "Build cpu_features with Position Independent Code (PIC)." +++ FORCE) +++-set(BUILD_SHARED_LIBS_SAVED "${BUILD_SHARED_LIBS}") +++-set(BUILD_SHARED_LIBS OFF) +++-add_subdirectory(cpu_features) +++-set(BUILD_SHARED_LIBS "${BUILD_SHARED_LIBS_SAVED}") ++++ set(BUILD_SHARED_LIBS_SAVED "${BUILD_SHARED_LIBS}") ++++ set(BUILD_SHARED_LIBS OFF) ++++ add_subdirectory(cpu_features) ++++ set(BUILD_SHARED_LIBS "${BUILD_SHARED_LIBS_SAVED}") ++++else() ++++ message(STATUS "Building Volk without cpu_features") ++++endif() +++ +++ # Python +++ include(VolkPython) #sets PYTHON_EXECUTABLE and PYTHON_DASH_B +++diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt +++index 7458530..9fbdb92 100644 +++--- a/lib/CMakeLists.txt ++++++ b/lib/CMakeLists.txt +++@@ -511,10 +511,15 @@ target_include_directories(volk_obj +++ PRIVATE $ +++ PRIVATE $ +++ PRIVATE $ +++- PRIVATE $ +++ PRIVATE ${CMAKE_CURRENT_BINARY_DIR} +++ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} +++ ) ++++if(VOLK_CPU_FEATURES) ++++ set_source_files_properties(volk_cpu.c PROPERTIES COMPILE_DEFINITIONS "VOLK_CPU_FEATURES=1") ++++ target_include_directories(volk_obj ++++ PRIVATE $ ++++) ++++endif() +++ +++ #Configure object target properties +++ if(NOT MSVC) +++@@ -530,7 +535,10 @@ endif() +++ #include directories is taken as provided; it -might- matter, but +++ #probably doesn't. +++ add_library(volk SHARED $) +++-target_link_libraries(volk PUBLIC ${volk_libraries} PRIVATE cpu_features) ++++target_link_libraries(volk PUBLIC ${volk_libraries}) ++++if(VOLK_CPU_FEATURES) ++++ target_link_libraries(volk PRIVATE cpu_features) ++++endif() +++ target_include_directories(volk +++ PUBLIC $ +++ PUBLIC $ +++diff --git a/tmpl/volk_cpu.tmpl.c b/tmpl/volk_cpu.tmpl.c +++index 1266250..f879eb6 100644 +++--- a/tmpl/volk_cpu.tmpl.c ++++++ b/tmpl/volk_cpu.tmpl.c +++@@ -25,6 +25,7 @@ +++ #include +++ +++ ++++#if defined(VOLK_CPU_FEATURES) +++ #include "cpu_features_macros.h" +++ #if defined(CPU_FEATURES_ARCH_X86) +++ #include "cpuinfo_x86.h" +++@@ -42,6 +43,7 @@ +++ #if defined(__cplusplus) +++ using namespace cpu_features; +++ #endif ++++#endif +++ +++ +++ struct VOLK_CPU volk_cpu; +++-- +++2.20.1 +++ diff --cc debian/patches/make-acc-happy index 0000000,0000000,0000000..7c5c767 new file mode 100644 --- /dev/null +++ b/debian/patches/make-acc-happy @@@@ -1,0 -1,0 -1,0 +1,60 @@@@ +++From 799245ea6e9e05cc0ed0fabe783fbbe1a5054fd4 Mon Sep 17 00:00:00 2001 +++From: "A. Maitland Bottoms" +++Date: Tue, 27 Mar 2018 22:02:59 -0400 +++Subject: [PATCH 2/6] make acc happy +++ +++The abi-compliance-checker grabs all the .h files it finds +++and tries to compile them all. Even though some are not +++appropriate for the architecture being run on. Being careful +++with preprocessor protections avoids problems. +++--- +++ include/volk/volk_neon_intrinsics.h | 2 ++ +++ kernels/volk/volk_32f_8u_polarbutterflypuppet_32f.h | 1 + +++ kernels/volk/volk_8u_x2_encodeframepolar_8u.h | 3 --- +++ 3 files changed, 3 insertions(+), 3 deletions(-) +++ +++--- a/include/volk/volk_neon_intrinsics.h ++++++ b/include/volk/volk_neon_intrinsics.h +++@@ -79,6 +79,7 @@ +++ +++ #ifndef INCLUDE_VOLK_VOLK_NEON_INTRINSICS_H_ +++ #define INCLUDE_VOLK_VOLK_NEON_INTRINSICS_H_ ++++#ifdef LV_HAVE_NEON +++ #include +++ +++ +++@@ -278,4 +279,5 @@ +++ } +++ +++ ++++#endif /*LV_HAVE_NEON*/ +++ #endif /* INCLUDE_VOLK_VOLK_NEON_INTRINSICS_H_ */ +++--- a/kernels/volk/volk_32f_8u_polarbutterflypuppet_32f.h ++++++ b/kernels/volk/volk_32f_8u_polarbutterflypuppet_32f.h +++@@ -31,6 +31,7 @@ +++ #include +++ #include +++ #include ++++#include +++ +++ +++ static inline void sanitize_bytes(unsigned char* u, const int elements) +++--- a/kernels/volk/volk_8u_x2_encodeframepolar_8u.h ++++++ b/kernels/volk/volk_8u_x2_encodeframepolar_8u.h +++@@ -60,8 +60,6 @@ +++ } +++ } +++ +++-#ifdef LV_HAVE_GENERIC +++- +++ static inline void volk_8u_x2_encodeframepolar_8u_generic(unsigned char* frame, +++ unsigned char* temp, +++ unsigned int frame_size) +++@@ -81,7 +79,6 @@ +++ --stage; +++ } +++ } +++-#endif /* LV_HAVE_GENERIC */ +++ +++ #ifdef LV_HAVE_SSSE3 +++ #include diff --cc debian/patches/optional-static-apps index 0000000,0000000,0000000..399ee9b new file mode 100644 --- /dev/null +++ b/debian/patches/optional-static-apps @@@@ -1,0 -1,0 -1,0 +1,20 @@@@ +++--- a/apps/CMakeLists.txt ++++++ b/apps/CMakeLists.txt +++@@ -62,7 +62,7 @@ +++ target_link_libraries(volk_profile PRIVATE std::filesystem) +++ endif() +++ +++-if(ENABLE_STATIC_LIBS) ++++if(ENABLE_STATIC_LIBS AND ENABLE_STATIC_APPS) +++ target_link_libraries(volk_profile PRIVATE volk_static) +++ set_target_properties(volk_profile PROPERTIES LINK_FLAGS "-static") +++ else() +++@@ -79,7 +79,7 @@ +++ add_executable(volk-config-info volk-config-info.cc ${CMAKE_CURRENT_SOURCE_DIR}/volk_option_helpers.cc +++ ) +++ +++-if(ENABLE_STATIC_LIBS) ++++if(ENABLE_STATIC_LIBS AND ENABLE_STATIC_APPS) +++ target_link_libraries(volk-config-info volk_static) +++ set_target_properties(volk-config-info PROPERTIES LINK_FLAGS "-static") +++ else() diff --cc debian/patches/remove-external-HTML-resources index 0000000,0000000,0000000..924c1ad new file mode 100644 --- /dev/null +++ b/debian/patches/remove-external-HTML-resources @@@@ -1,0 -1,0 -1,0 +1,18 @@@@ +++--- a/README.md ++++++ b/README.md +++@@ -1,7 +1,3 @@ +++-[![Build Status](https://travis-ci.org/gnuradio/volk.svg?branch=master)](https://travis-ci.org/gnuradio/volk) [![Build status](https://ci.appveyor.com/api/projects/status/5o56mgw0do20jlh3/branch/master?svg=true)](https://ci.appveyor.com/project/gnuradio/volk/branch/master) +++-![Check PR Formatting](https://github.com/gnuradio/volk/workflows/Check%20PR%20Formatting/badge.svg) +++-![Run VOLK tests](https://github.com/gnuradio/volk/workflows/Run%20VOLK%20tests/badge.svg) +++- +++ ![VOLK Logo](/docs/volk_logo.png) +++ +++ # Welcome to VOLK! +++--- a/cpu-features/README.md ++++++ b/cpu-features/README.md +++@@ -1,4 +1,4 @@ +++-# cpu_features [![Build Status](https://travis-ci.org/google/cpu_features.svg?branch=master)](https://travis-ci.org/google/cpu_features) [![Build status](https://ci.appveyor.com/api/projects/status/46d1owsj7n8dsylq/branch/master?svg=true)](https://ci.appveyor.com/project/gchatelet/cpu-features/branch/master) ++++# cpu_features +++ +++ A cross-platform C library to retrieve CPU features (such as available +++ instructions) at runtime. diff --cc debian/patches/series index 0000000,0000000,0000000..f84bed1 new file mode 100644 --- /dev/null +++ b/debian/patches/series @@@@ -1,0 -1,0 -1,0 +1,4 @@@@ +++make-acc-happy +++optional-static-apps +++remove-external-HTML-resources +++cpu_features-CMake-option diff --cc debian/rules index 0000000,0000000,0000000..94eca1d new file mode 100755 --- /dev/null +++ b/debian/rules @@@@ -1,0 -1,0 -1,0 +1,20 @@@@ +++#!/usr/bin/make -f +++DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) +++export DEB_HOST_MULTIARCH +++#export DH_VERBOSE=1 +++ +++%: +++ dh $@ --with python3 +++ +++override_dh_auto_configure: +++ - mv cpu-features/* cpu_features/ +++ dh_auto_configure -- -DLIB_SUFFIX="/$(DEB_HOST_MULTIARCH)" \ +++ -DENABLE_STATIC_LIBS=On -DPYTHON_EXECUTABLE=/usr/bin/python3 \ +++ -DCMAKE_BUILD_TYPE=RelWithDebInfo +++ +++override_dh_auto_build-indep: +++ cmake --build obj-* --target all +++ cmake --build obj-* --target volk_doc +++ +++override_dh_auto_test: +++ - dh_auto_test -- CTEST_TEST_TIMEOUT=60 diff --cc debian/source/format index 0000000,0000000,0000000..163aaf8 new file mode 100644 --- /dev/null +++ b/debian/source/format @@@@ -1,0 -1,0 -1,0 +1,1 @@@@ +++3.0 (quilt) diff --cc debian/volk-config-info.1 index 0000000,0000000,0000000..e8d6efd new file mode 100644 --- /dev/null +++ b/debian/volk-config-info.1 @@@@ -1,0 -1,0 -1,0 +1,45 @@@@ +++.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.40.10. +++.TH VOLK-CONFIG-INFO "1" "July 2014" "volk-config-info 0.1" "User Commands" +++.SH NAME +++volk-config-info \- pkgconfig-like tool for Vector Optimized Library of Kernels 0.1 +++.SH DESCRIPTION +++.SS "Program options: volk-config-info [options]:" +++.TP +++\fB\-h\fR [ \fB\-\-help\fR ] +++print help message +++.TP +++\fB\-\-prefix\fR +++print VOLK installation prefix +++.TP +++\fB\-\-builddate\fR +++print VOLK build date (RFC2822 format) +++.TP +++\fB\-\-cc\fR +++print VOLK C compiler version +++.TP +++\fB\-\-cflags\fR +++print VOLK CFLAGS +++.TP +++\fB\-\-all\-machines\fR +++print VOLK machines built into library +++.TP +++\fB\-\-avail\-machines\fR +++print VOLK machines the current platform can use +++.TP +++\fB\-\-machine\fR +++print the VOLK machine that will be used +++.TP +++\fB\-v\fR [ \fB\-\-version\fR ] +++print VOLK version +++.SH "SEE ALSO" +++The full documentation for +++.B volk-config-info +++is maintained as a Texinfo manual. If the +++.B info +++and +++.B volk-config-info +++programs are properly installed at your site, the command +++.IP +++.B info volk-config-info +++.PP +++should give you access to the complete manual. diff --cc debian/volk_modtool.1 index 0000000,0000000,0000000..752e7f5 new file mode 100644 --- /dev/null +++ b/debian/volk_modtool.1 @@@@ -1,0 -1,0 -1,0 +1,112 @@@@ +++.TH GNURADIO "1" "August 2013" "volk_modtool 3.7" "User Commands" +++.SH NAME +++volk_modtool \- tailor VOLK modules +++.SH DESCRIPTION +++The volk_modtool tool is installed along with VOLK as a way of helping +++to construct, add to, and interogate the VOLK library or companion +++libraries. +++.P +++volk_modtool is installed into $prefix/bin. +++.P +++VOLK modtool enables creating standalone (out-of-tree) VOLK modules +++and provides a few tools for sharing VOLK kernels between VOLK +++modules. If you need to design or work with VOLK kernels away from +++the canonical VOLK library, this is the tool. If you need to tailor +++your own VOLK library for whatever reason, this is the tool. +++.P +++The canonical VOLK library installs a volk.h and a libvolk.so. Your +++own library will install volk_$name.h and libvolk_$name.so. Ya Gronk? +++Good. +++.P +++There isn't a substantial difference between the canonical VOLK +++module and any other VOLK module. They're all peers. Any module +++created via VOLK modtool will come complete with a default +++volk_modtool.cfg file associating the module with the base from which +++it came, its distinctive $name and its destination (or path). These +++values (created from user input if VOLK modtool runs without a +++user-supplied config file or a default config file) serve as default +++values for some VOLK modtool actions. It's more or less intended for +++the user to change directories to the top level of a created VOLK +++module and then run volk_modtool to take advantage of the values +++stored in the default volk_modtool.cfg file. +++.P +++Apart from creating new VOLK modules, VOLK modtool allows you to list +++the names of kernels in other modules, list the names of kernels in +++the current module, add kernels from another module into the current +++module, and remove kernels from the current module. When moving +++kernels between modules, VOLK modtool does its best to keep the qa +++and profiling code for those kernels intact. If the base has a test +++or a profiling call for some kernel, those calls will follow the +++kernel when VOLK modtool adds that kernel. If QA or profiling +++requires a puppet kernel, the puppet kernel will follow the original +++kernel when VOLK modtool adds that original kernel. VOLK modtool +++respects puppets. +++.P +++====================================================================== +++.P +++.SH Installing a new VOLK Library: +++.P +++Run the command "volk_modtool -i". This will ask you three questions: +++.P +++ name: // the name to give your VOLK library: volk_ +++ destination: // directory new source tree is built under -- must exists. +++ // It will create /volk_ +++ base: // the directory containing the original VOLK source code +++.P +++This will build a new skeleton directory in the destination provided +++with the name volk_. It will contain the necessary structure to +++build: +++.P +++ mkdir build +++ cd build +++ cmake -DCMAKE_INSTALL_PREFIX=/opt/volk ../ +++ make +++ sudo make install +++.P +++Right now, the library is empty and contains no kernels. Kernels can +++be added from another VOLK library using the '-a' option. If not +++specified, the kernel will be extracted from the base VOLK +++directory. Using the '-b' allows us to specify another VOLK library to +++use for this purpose. +++.P +++ volk_modtool -a -n 32fc_x2_conjugate_dot_prod_32fc +++.P +++This will put the code for the new kernel into +++/volk_/kernels/volk_/ +++.P +++Other kernels must be added by hand. See the following webpages for +++more information about creating VOLK kernels: +++ http://gnuradio.org/doc/doxygen/volk_guide.html +++ http://gnuradio.org/redmine/projects/gnuradio/wiki/Volk +++.P +++====================================================================== +++.P +++.SH OPTIONS +++.P +++Options for Adding and Removing Kernels: +++ -a, --add_kernel +++ Add kernel from existing VOLK module. Uses the base VOLK module +++ unless -b is used. Use -n to specify the kernel name. +++ Requires: -n. +++ Optional: -b +++.P +++ -A, --add_all_kernels +++ Add all kernels from existing VOLK module. Uses the base VOLK +++ module unless -b is used. +++ Optional: -b +++.P +++ -x, --remove_kernel +++ Remove kernel from module. +++ Required: -n. +++ Optional: -b +++.P +++Options for Listing Kernels: +++ -l, --list +++ Lists all kernels available in the base VOLK module. +++.P +++ -k, --kernels +++ Lists all kernels in this VOLK module. +++.P +++ -r, --remote-list +++ Lists all kernels in another VOLK module that is specified +++ using the -b option. diff --cc debian/volk_profile.1 index 0000000,0000000,0000000..405facb new file mode 100644 --- /dev/null +++ b/debian/volk_profile.1 @@@@ -1,0 -1,0 -1,0 +1,5 @@@@ +++.TH UHD_FFT "1" "March 2012" "volk_profile 3.5" "User Commands" +++.SH NAME +++volk_profile \- Quality Assurance application for libvolk functions +++.SH DESCRIPTION +++Writes profile results to a file. diff --cc debian/watch index 0000000,0000000,0000000..de9e7d1 new file mode 100644 --- /dev/null +++ b/debian/watch @@@@ -1,0 -1,0 -1,0 +1,4 @@@@ +++version=4 +++ opts="filenamemangle=s%(?:.*?)?volk-?(\d[\d.]*)\.tar\.xz%volk_$1.orig.tar.xz%" \ +++ https://github.com/gnuradio/volk/releases \ +++ (?:.*?/)?volk-?(\d[\d.]*)\.tar\.xz debian uupdate