Update to spice2x-25-04-25 (pre-apply)

> broken commit
This commit is contained in:
[ ]
2025-05-07 00:25:31 +09:00
parent 04dee88276
commit c94de456b5
543 changed files with 78491 additions and 91698 deletions
-8614
View File
File diff suppressed because it is too large Load Diff
+11 -1
View File
@@ -7,6 +7,7 @@
#include "cardio_window.h"
bool CARDIO_RUNNER_FLIP = false;
bool CARDIO_RUNNER_TOGGLE = false;
static bool CARDIO_RUNNER_INITIALIZED = false;
static std::thread* CARDIO_RUNNER_THREAD = nullptr;
static HWND CARDIO_RUNNER_HWND = NULL;
@@ -71,8 +72,17 @@ void cardio_runner_start(bool scan_hid) {
// if card not empty
if (*((uint64_t*) &device->usage_value[0]) > 0) {
bool flip_order = CARDIO_RUNNER_FLIP;
if (CARDIO_RUNNER_FLIP) {
log_info("cardio", "Flip order of readers since flip option is set");
}
if (CARDIO_RUNNER_TOGGLE && (GetKeyState(VK_NUMLOCK) & 1) > 0) {
log_info("cardio", "Flip order of readers since Num Lock is on");
flip_order = !flip_order;
}
// insert card
if (CARDIO_RUNNER_FLIP)
if (flip_order)
eamuse_card_insert((int) (device_no + 1) & 1, &device->usage_value[0]);
else
eamuse_card_insert((int) device_no & 1, &device->usage_value[0]);
+1
View File
@@ -2,6 +2,7 @@
#define SPICETOOLS_CARDIO_RUNNER_H
extern bool CARDIO_RUNNER_FLIP;
extern bool CARDIO_RUNNER_TOGGLE;
void cardio_runner_start(bool scan_hid);
void cardio_runner_stop();
+4
View File
@@ -0,0 +1,4 @@
---
Language: Cpp
BasedOnStyle: Google
...
+36
View File
@@ -0,0 +1,36 @@
# Project Files unneeded by docker
.git
.gitignore
.github
.dockerignore
.clang-format
appveyor.yml
.travis.yml
AUTHORS
CONTRIBUTING.md
CONTRIBUTORS
LICENSE
README.md
bazel/ci/Makefile
bazel/ci/docker
bazel/ci/doc
cmake/ci/Makefile
cmake/ci/docker
cmake/ci/doc
cmake/ci/cache
build/
cmake_build/
build_cross/
cmake-build-*/
out/
# Editor directories and files
.idea/
.vagrant/
.vscode/
.vs/
*.user
*.swp
+19
View File
@@ -0,0 +1,19 @@
# Build folders
build/
cmake_build/
build_cross/
cmake-build-*/
out/
# IDEs / CI temp files
.idea/
.vagrant/
.vscode/
.vs/
*.swp
# Bazel artifacts
**/bazel-*
# Per-user bazelrc files
user.bazelrc
+21
View File
@@ -0,0 +1,21 @@
---
dataSource: "prs"
ignoreLabels:
- "Apple M1"
- "duplicate"
- "help wanted"
- "invalid"
- "question"
- "wontfix"
onlyMilestones: false
groupBy:
"API Change":
- "API Change"
"New features / Enhancements":
- "enhancement"
- "internal"
"Bug Fixes":
- "bug"
"Misc":
- "misc"
changelogFilename: "CHANGELOG.md"
+378
View File
@@ -0,0 +1,378 @@
# cpu_features, a cross platform C99 library to get cpu features at runtime.
load("@bazel_skylib//lib:selects.bzl", "selects")
load("//:bazel/platforms.bzl", "PLATFORM_CPU_ARM", "PLATFORM_CPU_ARM64", "PLATFORM_CPU_MIPS", "PLATFORM_CPU_PPC", "PLATFORM_CPU_RISCV32", "PLATFORM_CPU_RISCV64", "PLATFORM_CPU_X86_64")
load("//:bazel/platforms.bzl", "PLATFORM_OS_MACOS")
package(
default_visibility = ["//visibility:public"],
licenses = ["notice"],
)
exports_files(["LICENSE"])
INCLUDES = ["include"]
C99_FLAGS = [
"-std=c99",
"-Wall",
"-Wextra",
"-Wmissing-declarations",
"-Wmissing-prototypes",
"-Wno-implicit-fallthrough",
"-Wno-unused-function",
"-Wold-style-definition",
"-Wshadow",
"-Wsign-compare",
"-Wstrict-prototypes",
]
cc_library(
name = "cpu_features_macros",
copts = C99_FLAGS,
includes = INCLUDES,
textual_hdrs = ["include/cpu_features_macros.h"],
)
cc_library(
name = "cpu_features_cache_info",
copts = C99_FLAGS,
includes = INCLUDES,
textual_hdrs = ["include/cpu_features_cache_info.h"],
deps = [":cpu_features_macros"],
)
cc_library(
name = "bit_utils",
copts = C99_FLAGS,
includes = INCLUDES,
textual_hdrs = ["include/internal/bit_utils.h"],
deps = [":cpu_features_macros"],
)
cc_test(
name = "bit_utils_test",
srcs = ["test/bit_utils_test.cc"],
includes = INCLUDES,
deps = [
":bit_utils",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "memory_utils",
copts = C99_FLAGS,
includes = INCLUDES,
textual_hdrs = [
"src/copy.inl",
"src/equals.inl",
],
)
cc_library(
name = "string_view",
srcs = [
"src/string_view.c",
],
copts = C99_FLAGS,
includes = INCLUDES,
textual_hdrs = ["include/internal/string_view.h"],
deps = [
":cpu_features_macros",
":memory_utils",
],
)
cc_test(
name = "string_view_test",
srcs = ["test/string_view_test.cc"],
includes = INCLUDES,
deps = [
":string_view",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "filesystem",
srcs = ["src/filesystem.c"],
copts = C99_FLAGS,
includes = INCLUDES,
textual_hdrs = ["include/internal/filesystem.h"],
deps = [":cpu_features_macros"],
)
cc_library(
name = "filesystem_for_testing",
testonly = 1,
srcs = [
"src/filesystem.c",
"test/filesystem_for_testing.cc",
],
hdrs = [
"include/internal/filesystem.h",
"test/filesystem_for_testing.h",
],
defines = ["CPU_FEATURES_MOCK_FILESYSTEM"],
includes = INCLUDES,
deps = [
":cpu_features_macros",
],
)
cc_library(
name = "stack_line_reader",
srcs = ["src/stack_line_reader.c"],
copts = C99_FLAGS,
defines = ["STACK_LINE_READER_BUFFER_SIZE=1024"],
includes = INCLUDES,
textual_hdrs = ["include/internal/stack_line_reader.h"],
deps = [
":cpu_features_macros",
":filesystem",
":string_view",
],
)
cc_test(
name = "stack_line_reader_test",
srcs = [
"include/internal/stack_line_reader.h",
"src/stack_line_reader.c",
"test/stack_line_reader_test.cc",
],
defines = ["STACK_LINE_READER_BUFFER_SIZE=16"],
includes = INCLUDES,
deps = [
":cpu_features_macros",
":filesystem_for_testing",
":string_view",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "stack_line_reader_to_use_with_filesystem_for_testing",
testonly = 1,
srcs = ["src/stack_line_reader.c"],
hdrs = ["include/internal/stack_line_reader.h"],
copts = C99_FLAGS,
defines = ["STACK_LINE_READER_BUFFER_SIZE=1024"],
includes = INCLUDES,
deps = [
":cpu_features_macros",
":filesystem_for_testing",
":string_view",
],
)
cc_library(
name = "hwcaps",
srcs = ["src/hwcaps.c"],
copts = C99_FLAGS,
defines = selects.with_or({
PLATFORM_OS_MACOS: ["HAVE_DLFCN_H"],
"//conditions:default": ["HAVE_STRONG_GETAUXVAL"],
}),
includes = INCLUDES,
textual_hdrs = ["include/internal/hwcaps.h"],
deps = [
":cpu_features_macros",
":filesystem",
":string_view",
],
)
cc_library(
name = "hwcaps_for_testing",
testonly = 1,
srcs = [
"src/hwcaps.c",
"test/hwcaps_for_testing.cc",
],
hdrs = [
"include/internal/hwcaps.h",
"test/hwcaps_for_testing.h",
],
defines = [
"CPU_FEATURES_MOCK_GET_ELF_HWCAP_FROM_GETAUXVAL",
"CPU_FEATURES_TEST",
],
includes = INCLUDES,
deps = [
":cpu_features_macros",
":filesystem_for_testing",
":string_view",
],
)
cc_library(
name = "cpuinfo",
srcs = selects.with_or({
PLATFORM_CPU_X86_64: [
"src/impl_x86_freebsd.c",
"src/impl_x86_linux_or_android.c",
"src/impl_x86_macos.c",
"src/impl_x86_windows.c",
],
PLATFORM_CPU_ARM: ["src/impl_arm_linux_or_android.c"],
PLATFORM_CPU_ARM64: [
"src/impl_aarch64_linux_or_android.c",
"src/impl_aarch64_macos_or_iphone.c",
"src/impl_aarch64_windows.c",
],
PLATFORM_CPU_MIPS: ["src/impl_mips_linux_or_android.c"],
PLATFORM_CPU_PPC: ["src/impl_ppc_linux.c"],
PLATFORM_CPU_RISCV32: ["src/impl_riscv_linux.c"],
PLATFORM_CPU_RISCV64: ["src/impl_riscv_linux.c"],
}),
hdrs = selects.with_or({
PLATFORM_CPU_X86_64: [
"include/cpuinfo_x86.h",
"include/internal/cpuid_x86.h",
"include/internal/windows_utils.h",
],
PLATFORM_CPU_ARM: ["include/cpuinfo_arm.h"],
PLATFORM_CPU_ARM64: ["include/cpuinfo_aarch64.h"],
PLATFORM_CPU_MIPS: ["include/cpuinfo_mips.h"],
PLATFORM_CPU_PPC: ["include/cpuinfo_ppc.h"],
PLATFORM_CPU_RISCV32: ["include/cpuinfo_riscv.h"],
PLATFORM_CPU_RISCV64: ["include/cpuinfo_riscv.h"],
}),
copts = C99_FLAGS,
defines = selects.with_or({
PLATFORM_OS_MACOS: ["HAVE_SYSCTLBYNAME"],
"//conditions:default": [],
}),
includes = INCLUDES,
textual_hdrs = selects.with_or({
PLATFORM_CPU_X86_64: ["src/impl_x86__base_implementation.inl"],
PLATFORM_CPU_ARM64: ["src/impl_aarch64__base_implementation.inl"],
"//conditions:default": [],
}) + [
"src/define_introspection.inl",
"src/define_introspection_and_hwcaps.inl",
],
deps = [
":bit_utils",
":cpu_features_cache_info",
":cpu_features_macros",
":filesystem",
":hwcaps",
":memory_utils",
":stack_line_reader",
":string_view",
],
)
cc_library(
name = "cpuinfo_for_testing",
testonly = 1,
srcs = selects.with_or({
PLATFORM_CPU_X86_64: [
"src/impl_x86_freebsd.c",
"src/impl_x86_linux_or_android.c",
"src/impl_x86_macos.c",
"src/impl_x86_windows.c",
],
PLATFORM_CPU_ARM: ["src/impl_arm_linux_or_android.c"],
PLATFORM_CPU_ARM64: [
"src/impl_aarch64_linux_or_android.c",
"src/impl_aarch64_macos_or_iphone.c",
"src/impl_aarch64_windows.c",
],
PLATFORM_CPU_MIPS: ["src/impl_mips_linux_or_android.c"],
PLATFORM_CPU_PPC: ["src/impl_ppc_linux.c"],
PLATFORM_CPU_RISCV32: ["src/impl_riscv_linux.c"],
PLATFORM_CPU_RISCV64: ["src/impl_riscv_linux.c"],
}),
hdrs = selects.with_or({
PLATFORM_CPU_X86_64: [
"include/cpuinfo_x86.h",
"include/internal/cpuid_x86.h",
"include/internal/windows_utils.h",
],
PLATFORM_CPU_ARM: ["include/cpuinfo_arm.h"],
PLATFORM_CPU_ARM64: ["include/cpuinfo_aarch64.h"],
PLATFORM_CPU_MIPS: ["include/cpuinfo_mips.h"],
PLATFORM_CPU_PPC: ["include/cpuinfo_ppc.h"],
PLATFORM_CPU_RISCV32: ["include/cpuinfo_riscv.h"],
PLATFORM_CPU_RISCV64: ["include/cpuinfo_riscv.h"],
}),
copts = C99_FLAGS,
defines = selects.with_or({
PLATFORM_CPU_X86_64: ["CPU_FEATURES_MOCK_CPUID_X86"],
"//conditions:default": [],
}) + selects.with_or({
PLATFORM_OS_MACOS: ["HAVE_SYSCTLBYNAME"],
"//conditions:default": [],
}),
includes = INCLUDES,
textual_hdrs = selects.with_or({
PLATFORM_CPU_X86_64: ["src/impl_x86__base_implementation.inl"],
PLATFORM_CPU_ARM64: ["src/impl_aarch64__base_implementation.inl"],
"//conditions:default": [],
}) + [
"src/define_introspection.inl",
"src/define_introspection_and_hwcaps.inl",
],
deps = [
":bit_utils",
":cpu_features_cache_info",
":cpu_features_macros",
":filesystem_for_testing",
":hwcaps_for_testing",
":memory_utils",
":stack_line_reader_to_use_with_filesystem_for_testing",
":string_view",
],
)
cc_test(
name = "cpuinfo_test",
srcs = selects.with_or({
PLATFORM_CPU_ARM64: ["test/cpuinfo_aarch64_test.cc"],
PLATFORM_CPU_ARM: ["test/cpuinfo_arm_test.cc"],
PLATFORM_CPU_MIPS: ["test/cpuinfo_mips_test.cc"],
PLATFORM_CPU_PPC: ["test/cpuinfo_ppc_test.cc"],
PLATFORM_CPU_RISCV32: ["test/cpuinfo_riscv_test.cc"],
PLATFORM_CPU_RISCV64: ["test/cpuinfo_riscv_test.cc"],
PLATFORM_CPU_X86_64: ["test/cpuinfo_x86_test.cc"],
}),
includes = INCLUDES,
deps = [
":cpuinfo_for_testing",
":filesystem_for_testing",
":hwcaps_for_testing",
":string_view",
"@com_google_googletest//:gtest_main",
],
)
cc_binary(
name = "list_cpu_features",
srcs = ["src/utils/list_cpu_features.c"],
copts = C99_FLAGS,
includes = INCLUDES,
deps = [
":bit_utils",
":cpu_features_macros",
":cpuinfo",
],
)
cc_library(
name = "ndk_compat",
srcs = ["ndk_compat/cpu-features.c"],
copts = C99_FLAGS,
includes = INCLUDES + ["ndk_compat"],
textual_hdrs = ["ndk_compat/cpu-features.h"],
deps = [
":cpu_features_macros",
":cpuinfo",
":filesystem",
":stack_line_reader",
":string_view",
],
)
+302
View File
@@ -0,0 +1,302 @@
cmake_minimum_required(VERSION 3.13)
# option() honors normal variables.
# see: https://cmake.org/cmake/help/git-stage/policy/CMP0077.html
if(POLICY CMP0077)
cmake_policy(SET CMP0077 NEW)
endif()
project(CpuFeatures VERSION 0.9.0 LANGUAGES C)
set(CMAKE_C_STANDARD 99)
# when cpu_features is included as subproject (i.e. using add_subdirectory(cpu_features))
# in the source tree of a project that uses it, test rules are disabled.
if(NOT CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
option(BUILD_TESTING "Enable test rule" OFF)
else()
option(BUILD_TESTING "Enable test rule" ON)
endif()
# Default Build Type to be Release
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
FORCE)
endif(NOT CMAKE_BUILD_TYPE)
# An option to enable/disable the executable target list_cpu_features.
# Disable it by default if the project is included as a subproject.
if(NOT CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
option(BUILD_EXECUTABLE "Build list_cpu_features executable." OFF)
else()
option(BUILD_EXECUTABLE "Build list_cpu_features executable." ON)
endif()
# An option which allows to switch off install steps. Useful for embedding.
# Disable it by default if the project is included as a subproject.
if(NOT CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
option(ENABLE_INSTALL "Enable install targets" OFF)
else()
option(ENABLE_INSTALL "Enable install targets" ON)
endif()
# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to make
# it prominent in the GUI.
# cpu_features uses bit-fields which are - to some extends - implementation-defined (see https://en.cppreference.com/w/c/language/bit_field).
# As a consequence it is discouraged to use cpu_features as a shared library because different compilers may interpret the code in different ways.
# Prefer static linking from source whenever possible.
option(BUILD_SHARED_LIBS "Build library as shared." OFF)
# Force PIC on unix when building shared libs
# see: https://en.wikipedia.org/wiki/Position-independent_code
if(BUILD_SHARED_LIBS AND UNIX)
option(CMAKE_POSITION_INDEPENDENT_CODE "Build with Position Independant Code." ON)
endif()
include(CheckIncludeFile)
include(CheckSymbolExists)
include(GNUInstallDirs)
macro(setup_include_and_definitions TARGET_NAME)
target_include_directories(${TARGET_NAME}
PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
PRIVATE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include/internal>
)
target_compile_definitions(${TARGET_NAME}
PUBLIC STACK_LINE_READER_BUFFER_SIZE=1024
)
endmacro()
set(PROCESSOR_IS_MIPS FALSE)
set(PROCESSOR_IS_ARM FALSE)
set(PROCESSOR_IS_AARCH64 FALSE)
set(PROCESSOR_IS_X86 FALSE)
set(PROCESSOR_IS_POWER FALSE)
set(PROCESSOR_IS_S390X FALSE)
set(PROCESSOR_IS_RISCV FALSE)
set(PROCESSOR_IS_LOONGARCH FALSE)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^mips")
set(PROCESSOR_IS_MIPS TRUE)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(^aarch64)|(^arm64)|(^ARM64)")
set(PROCESSOR_IS_AARCH64 TRUE)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm")
set(PROCESSOR_IS_ARM TRUE)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(x86_64)|(AMD64|amd64)|(^i.86$)")
set(PROCESSOR_IS_X86 TRUE)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)")
set(PROCESSOR_IS_POWER TRUE)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(s390x)")
set(PROCESSOR_IS_S390X TRUE)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^riscv")
set(PROCESSOR_IS_RISCV TRUE)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^loongarch")
set(PROCESSOR_IS_LOONGARCH TRUE)
endif()
macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpu_features_macros.h)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpu_features_cache_info.h)
file(GLOB IMPL_SOURCES CONFIGURE_DEPENDS "${PROJECT_SOURCE_DIR}/src/impl_*.c")
list(APPEND ${SRCS_LIST_NAME} ${IMPL_SOURCES})
if(PROCESSOR_IS_MIPS)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_mips.h)
elseif(PROCESSOR_IS_ARM)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_arm.h)
elseif(PROCESSOR_IS_AARCH64)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_aarch64.h)
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/internal/windows_utils.h)
elseif(PROCESSOR_IS_X86)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_x86.h)
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/internal/cpuid_x86.h)
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/internal/windows_utils.h)
elseif(PROCESSOR_IS_POWER)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_ppc.h)
elseif(PROCESSOR_IS_S390X)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_s390x.h)
elseif(PROCESSOR_IS_RISCV)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_riscv.h)
elseif(PROCESSOR_IS_LOONGARCH)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_loongarch.h)
else()
message(FATAL_ERROR "Unsupported architectures ${CMAKE_SYSTEM_PROCESSOR}")
endif()
endmacro()
#
# library : utils
#
add_library(utils OBJECT
${PROJECT_SOURCE_DIR}/include/internal/bit_utils.h
${PROJECT_SOURCE_DIR}/include/internal/filesystem.h
${PROJECT_SOURCE_DIR}/include/internal/stack_line_reader.h
${PROJECT_SOURCE_DIR}/include/internal/string_view.h
${PROJECT_SOURCE_DIR}/src/filesystem.c
${PROJECT_SOURCE_DIR}/src/stack_line_reader.c
${PROJECT_SOURCE_DIR}/src/string_view.c
)
setup_include_and_definitions(utils)
#
# library : unix_based_hardware_detection
#
if(UNIX)
add_library(unix_based_hardware_detection OBJECT
${PROJECT_SOURCE_DIR}/include/internal/hwcaps.h
${PROJECT_SOURCE_DIR}/src/hwcaps.c
)
setup_include_and_definitions(unix_based_hardware_detection)
check_include_file(dlfcn.h HAVE_DLFCN_H)
if(HAVE_DLFCN_H)
target_compile_definitions(unix_based_hardware_detection PRIVATE HAVE_DLFCN_H)
endif()
check_symbol_exists(getauxval "sys/auxv.h" HAVE_STRONG_GETAUXVAL)
if(HAVE_STRONG_GETAUXVAL)
target_compile_definitions(unix_based_hardware_detection PRIVATE HAVE_STRONG_GETAUXVAL)
endif()
endif()
#
# library : cpu_features
#
set (CPU_FEATURES_HDRS)
set (CPU_FEATURES_SRCS)
add_cpu_features_headers_and_sources(CPU_FEATURES_HDRS CPU_FEATURES_SRCS)
list(APPEND CPU_FEATURES_SRCS $<TARGET_OBJECTS:utils>)
if(NOT PROCESSOR_IS_X86 AND UNIX)
list(APPEND CPU_FEATURES_SRCS $<TARGET_OBJECTS:unix_based_hardware_detection>)
endif()
add_library(cpu_features ${CPU_FEATURES_HDRS} ${CPU_FEATURES_SRCS})
set_target_properties(cpu_features PROPERTIES PUBLIC_HEADER "${CPU_FEATURES_HDRS}")
setup_include_and_definitions(cpu_features)
target_link_libraries(cpu_features PUBLIC ${CMAKE_DL_LIBS})
target_include_directories(cpu_features
PUBLIC $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/cpu_features>
)
if(APPLE)
target_compile_definitions(cpu_features PRIVATE HAVE_SYSCTLBYNAME)
endif()
add_library(CpuFeatures::cpu_features ALIAS cpu_features)
#
# program : list_cpu_features
#
if(BUILD_EXECUTABLE)
add_executable(list_cpu_features ${PROJECT_SOURCE_DIR}/src/utils/list_cpu_features.c)
target_link_libraries(list_cpu_features PRIVATE cpu_features)
add_executable(CpuFeatures::list_cpu_features ALIAS list_cpu_features)
endif()
#
# ndk_compat
#
if(ANDROID)
add_subdirectory(ndk_compat)
endif()
#
# tests
#
include(CTest)
if(BUILD_TESTING)
# Automatically incorporate googletest into the CMake Project if target not
# found.
enable_language(CXX)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) # prefer use of -std14 instead of -gnustd14
if(NOT TARGET gtest OR NOT TARGET gmock_main)
# Download and unpack googletest at configure time.
configure_file(
cmake/googletest.CMakeLists.txt.in
googletest-download/CMakeLists.txt
)
execute_process(
COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download)
if(result)
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
endif()
execute_process(
COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download)
if(result)
message(FATAL_ERROR "Build step for googletest failed: ${result}")
endif()
# Prevent overriding the parent project's compiler/linker settings on
# Windows.
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
# Add googletest directly to our build. This defines the gtest and
# gtest_main targets.
add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
${CMAKE_BINARY_DIR}/googletest-build
EXCLUDE_FROM_ALL)
endif()
add_subdirectory(test)
endif()
#
# Install cpu_features and list_cpu_features
#
if(ENABLE_INSTALL)
include(GNUInstallDirs)
install(TARGETS cpu_features
EXPORT CpuFeaturesTargets
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/cpu_features
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR}
)
if(BUILD_EXECUTABLE)
install(TARGETS list_cpu_features
EXPORT CpuFeaturesTargets
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/cpu_features
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR}
)
endif()
install(EXPORT CpuFeaturesTargets
NAMESPACE CpuFeatures::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeatures
COMPONENT Devel
)
include(CMakePackageConfigHelpers)
configure_package_config_file(cmake/CpuFeaturesConfig.cmake.in
"${PROJECT_BINARY_DIR}/CpuFeaturesConfig.cmake"
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeatures"
NO_SET_AND_CHECK_MACRO
NO_CHECK_REQUIRED_COMPONENTS_MACRO
)
write_basic_package_version_file(
"${PROJECT_BINARY_DIR}/CpuFeaturesConfigVersion.cmake"
COMPATIBILITY SameMajorVersion
)
install(
FILES
"${PROJECT_BINARY_DIR}/CpuFeaturesConfig.cmake"
"${PROJECT_BINARY_DIR}/CpuFeaturesConfigVersion.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeatures"
COMPONENT Devel
)
endif()
+23
View File
@@ -0,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 <https://cla.developers.google.com/> 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.
+230
View File
@@ -0,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.
+282
View File
@@ -0,0 +1,282 @@
# cpu_features
A cross-platform C library to retrieve CPU features (such as available
instructions) at runtime.
# GitHub-CI Status
[comment]: <> (The following lines are generated by "scripts/generate_badges.d" that you can run online https://run.dlang.io/)
| | Linux | FreeBSD | MacOS | Windows |
| :-- | --: | --: | --: | --: |
| amd64 | [![CMake][i1a0]][l1a0]<br/>[![Bazel][i1a1]][l1a1] | [![CMake][i2a0]][l2a0]<br/>![Bazel][d1] | [![CMake][i3a0]][l3a0]<br/>[![Bazel][i3a1]][l3a1] | [![CMake][i4a0]][l4a0]<br/>![Bazel][d1] |
| AArch64 | [![CMake][i1b0]][l1b0]<br/>[![Bazel][i1b1]][l1b1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] |
| ARM | [![CMake][i1c0]][l1c0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] |
| MIPS | [![CMake][i1d0]][l1d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] |
| POWER | [![CMake][i1e0]][l1e0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] |
| RISCV | [![CMake][i1f0]][l1f0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] |
| LOONGARCH | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] |
| s390x | [![CMake][i1h0]][l1h0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] |
[d0]: https://img.shields.io/badge/n%2Fa-lightgrey?&logo=cmake
[d1]: https://img.shields.io/badge/n%2Fa-lightgrey?&logo=data:image/svg%2bxml;base64,PHN2ZyByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNiAuMTZsNS43ODYgNS43ODZMNiAxMS43MzIuMjE0IDUuOTQ2IDYgLjE2MXpNMCA2LjIxNFYxMmw1Ljc4NiA1Ljc4NlYxMkwwIDYuMjE0ek0xOCAuMTZsNS43ODYgNS43ODZMMTggMTEuNzMybC01Ljc4Ni01Ljc4NkwxOCAuMTYxek0yNCA2LjIxNFYxMmwtNS43ODYgNS43ODZWMTJMMjQgNi4yMTR6TTEyIDYuMTZsNS43ODYgNS43ODZMMTIgMTcuNzMybC01Ljc4Ni01Ljc4NkwxMiA2LjE2MXpNMTEuODQgMTguMDU0djUuNzg1bC01Ljc4Ni01Ljc4NXYtNS43ODZsNS43ODUgNS43ODZ6TTEyLjE2IDE4LjA1NGw1Ljc4Ni01Ljc4NnY1Ljc4NmwtNS43ODUgNS43ODV2LTUuNzg1eiIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgZmlsbD0id2hpdGUiLz48L3N2Zz4=
[i1a0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_linux_cmake.yml?branch=main&event=push&label=&logo=cmake
[i1a1]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_linux_bazel.yml?branch=main&event=push&label=&logo=data:image/svg%2bxml;base64,PHN2ZyByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNiAuMTZsNS43ODYgNS43ODZMNiAxMS43MzIuMjE0IDUuOTQ2IDYgLjE2MXpNMCA2LjIxNFYxMmw1Ljc4NiA1Ljc4NlYxMkwwIDYuMjE0ek0xOCAuMTZsNS43ODYgNS43ODZMMTggMTEuNzMybC01Ljc4Ni01Ljc4NkwxOCAuMTYxek0yNCA2LjIxNFYxMmwtNS43ODYgNS43ODZWMTJMMjQgNi4yMTR6TTEyIDYuMTZsNS43ODYgNS43ODZMMTIgMTcuNzMybC01Ljc4Ni01Ljc4NkwxMiA2LjE2MXpNMTEuODQgMTguMDU0djUuNzg1bC01Ljc4Ni01Ljc4NXYtNS43ODZsNS43ODUgNS43ODZ6TTEyLjE2IDE4LjA1NGw1Ljc4Ni01Ljc4NnY1Ljc4NmwtNS43ODUgNS43ODV2LTUuNzg1eiIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgZmlsbD0id2hpdGUiLz48L3N2Zz4=
[i1b0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/aarch64_linux_cmake.yml?branch=main&event=push&label=&logo=cmake
[i1b1]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/aarch64_linux_bazel.yml?branch=main&event=push&label=&logo=data:image/svg%2bxml;base64,PHN2ZyByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNiAuMTZsNS43ODYgNS43ODZMNiAxMS43MzIuMjE0IDUuOTQ2IDYgLjE2MXpNMCA2LjIxNFYxMmw1Ljc4NiA1Ljc4NlYxMkwwIDYuMjE0ek0xOCAuMTZsNS43ODYgNS43ODZMMTggMTEuNzMybC01Ljc4Ni01Ljc4NkwxOCAuMTYxek0yNCA2LjIxNFYxMmwtNS43ODYgNS43ODZWMTJMMjQgNi4yMTR6TTEyIDYuMTZsNS43ODYgNS43ODZMMTIgMTcuNzMybC01Ljc4Ni01Ljc4NkwxMiA2LjE2MXpNMTEuODQgMTguMDU0djUuNzg1bC01Ljc4Ni01Ljc4NXYtNS43ODZsNS43ODUgNS43ODZ6TTEyLjE2IDE4LjA1NGw1Ljc4Ni01Ljc4NnY1Ljc4NmwtNS43ODUgNS43ODV2LTUuNzg1eiIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgZmlsbD0id2hpdGUiLz48L3N2Zz4=
[i1c0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/arm_linux_cmake.yml?branch=main&event=push&label=&logo=cmake
[i1d0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/mips_linux_cmake.yml?branch=main&event=push&label=&logo=cmake
[i1e0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/power_linux_cmake.yml?branch=main&event=push&label=&logo=cmake
[i1f0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/riscv_linux_cmake.yml?branch=main&event=push&label=&logo=cmake
[i1h0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/s390x_linux_cmake.yml?branch=main&event=push&label=&logo=cmake
[i2a0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_freebsd_cmake.yml?branch=main&event=push&label=&logo=cmake
[i3a0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_macos_cmake.yml?branch=main&event=push&label=&logo=cmake
[i3a1]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_macos_bazel.yml?branch=main&event=push&label=&logo=data:image/svg%2bxml;base64,PHN2ZyByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNiAuMTZsNS43ODYgNS43ODZMNiAxMS43MzIuMjE0IDUuOTQ2IDYgLjE2MXpNMCA2LjIxNFYxMmw1Ljc4NiA1Ljc4NlYxMkwwIDYuMjE0ek0xOCAuMTZsNS43ODYgNS43ODZMMTggMTEuNzMybC01Ljc4Ni01Ljc4NkwxOCAuMTYxek0yNCA2LjIxNFYxMmwtNS43ODYgNS43ODZWMTJMMjQgNi4yMTR6TTEyIDYuMTZsNS43ODYgNS43ODZMMTIgMTcuNzMybC01Ljc4Ni01Ljc4NkwxMiA2LjE2MXpNMTEuODQgMTguMDU0djUuNzg1bC01Ljc4Ni01Ljc4NXYtNS43ODZsNS43ODUgNS43ODZ6TTEyLjE2IDE4LjA1NGw1Ljc4Ni01Ljc4NnY1Ljc4NmwtNS43ODUgNS43ODV2LTUuNzg1eiIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgZmlsbD0id2hpdGUiLz48L3N2Zz4=
[i4a0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_windows_cmake.yml?branch=main&event=push&label=&logo=cmake
[l1a0]: https://github.com/google/cpu_features/actions/workflows/amd64_linux_cmake.yml
[l1a1]: https://github.com/google/cpu_features/actions/workflows/amd64_linux_bazel.yml
[l1b0]: https://github.com/google/cpu_features/actions/workflows/aarch64_linux_cmake.yml
[l1b1]: https://github.com/google/cpu_features/actions/workflows/aarch64_linux_bazel.yml
[l1c0]: https://github.com/google/cpu_features/actions/workflows/arm_linux_cmake.yml
[l1d0]: https://github.com/google/cpu_features/actions/workflows/mips_linux_cmake.yml
[l1e0]: https://github.com/google/cpu_features/actions/workflows/power_linux_cmake.yml
[l1f0]: https://github.com/google/cpu_features/actions/workflows/riscv_linux_cmake.yml
[l1h0]: https://github.com/google/cpu_features/actions/workflows/s390x_linux_cmake.yml
[l2a0]: https://github.com/google/cpu_features/actions/workflows/amd64_freebsd_cmake.yml
[l3a0]: https://github.com/google/cpu_features/actions/workflows/amd64_macos_cmake.yml
[l3a1]: https://github.com/google/cpu_features/actions/workflows/amd64_macos_bazel.yml
[l4a0]: https://github.com/google/cpu_features/actions/workflows/amd64_windows_cmake.yml
## Table of Contents
- [Design Rationale](#rationale)
- [Code samples](#codesample)
- [Running sample code](#usagesample)
- [What's supported](#support)
- [Android NDK's drop in replacement](#ndk)
- [License](#license)
- [Build with cmake](#cmake)
- [Community Bindings](#bindings)
<a name="rationale"></a>
## 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.**
<a name="codesample"></a>
## Code samples
**Note:** For C++ code, the library functions are defined in the `cpu_features` namespace.
### Checking features at runtime
Here's a simple example that executes a codepath if the CPU supports both the
AES and the SSE4.2 instruction sets:
```c
#include "cpuinfo_x86.h"
// For C++, add `using namespace cpu_features;`
static const X86Features features = GetX86Info().features;
void Compute(void) {
if (features.aes && features.sse4_2) {
// Run optimized code.
} else {
// Run standard code.
}
}
```
### Caching for faster evaluation of complex checks
If you wish, you can read all the features at once into a global variable, and
then query for the specific features you care about. Below, we store all the ARM
features and then check whether AES and NEON are supported.
```c
#include <stdbool.h>
#include "cpuinfo_arm.h"
// For C++, add `using namespace cpu_features;`
static const ArmFeatures features = GetArmInfo().features;
static const bool has_aes_and_neon = features.aes && features.neon;
// use has_aes_and_neon.
```
This is a good approach to take if you're checking for combinations of features
when using a compiler that is slow to extract individual bits from bit-packed
structures.
### Checking compile time flags
The following code determines whether the compiler was told to use the AVX
instruction set (e.g., `g++ -mavx`) and sets `has_avx` accordingly.
```c
#include <stdbool.h>
#include "cpuinfo_x86.h"
// For C++, add `using namespace cpu_features;`
static const X86Features features = GetX86Info().features;
static const bool has_avx = CPU_FEATURES_COMPILED_X86_AVX || features.avx;
// use has_avx.
```
`CPU_FEATURES_COMPILED_X86_AVX` is set to 1 if the compiler was instructed to
use AVX and 0 otherwise, combining compile time and runtime knowledge.
### Rejecting poor hardware implementations based on microarchitecture
On x86, the first incarnation of a feature in a microarchitecture might not be
the most efficient (e.g. AVX on Sandy Bridge). We provide a function to retrieve
the underlying microarchitecture so you can decide whether to use it.
Below, `has_fast_avx` is set to 1 if the CPU supports the AVX instruction
set&mdash;but only if it's not Sandy Bridge.
```c
#include <stdbool.h>
#include "cpuinfo_x86.h"
// For C++, add `using namespace cpu_features;`
static const X86Info info = GetX86Info();
static const X86Microarchitecture uarch = GetX86Microarchitecture(&info);
static const bool has_fast_avx = info.features.avx && uarch != INTEL_SNB;
// use has_fast_avx.
```
This feature is currently available only for x86 microarchitectures.
<a name="usagesample"></a>
### 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"]}
```
<a name="support"></a>
## What's supported
| | x86³ | AArch64 | ARM | MIPS⁴ | POWER | RISCV | Loongarch | s390x |
|---------|:----:|:-------:|:-------:|:-------:|:-------:|:-------:|:---------:|:-------:|
| Linux | yes² | yes¹ | yes¹ | yes¹ | yes¹ | yes¹ | yes¹ | yes¹ |
| FreeBSD | yes² | not yet | not yet | not yet | not yet | N/A | not yet | not yet |
| MacOs | yes² | yes⁵ | N/A | N/A | N/A | N/A | N/A | N/A |
| Windows | yes² | not yet | not yet | N/A | N/A | N/A | N/A | N/A |
| Android | yes² | yes¹ | yes¹ | yes¹ | N/A | N/A | N/A | N/A |
| iOS | N/A | not yet | not yet | N/A | N/A | N/A | N/A | N/A |
1. **Features revealed from Linux.** We gather data from several sources
depending on availability:
+ from glibc's
[getauxval](https://www.gnu.org/software/libc/manual/html_node/Auxiliary-Vector.html)
+ by parsing `/proc/self/auxv`
+ by parsing `/proc/cpuinfo`
2. **Features revealed from CPU.** features are retrieved by using the `cpuid`
instruction.
3. **Microarchitecture detection.** On x86 some features are not always
implemented efficiently in hardware (e.g. AVX on Sandybridge). Exposing the
microarchitecture allows the client to reject particular microarchitectures.
4. All flavors of Mips are supported, little and big endian as well as 32/64
bits.
5. **Features revealed from sysctl.** features are retrieved by the `sysctl`
instruction.
<a name="ndk"></a>
## Android NDK's drop in replacement
[cpu_features](https://github.com/google/cpu_features) is now officially
supporting Android and offers a drop in replacement of for the NDK's [cpu-features.h](https://android.googlesource.com/platform/ndk/+/main/sources/android/cpufeatures/cpu-features.h)
, see [ndk_compat](ndk_compat) folder for details.
<a name="license"></a>
## License
The cpu_features library is licensed under the terms of the Apache license.
See [LICENSE](LICENSE) for more information.
<a name="cmake"></a>
## Build with CMake
Please check the [CMake build instructions](cmake/README.md).
<a name="quickstart"></a>
### Quickstart
- Run `list_cpu_features`
```sh
cmake -S. -Bbuild -DBUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release -j
./build/list_cpu_features --json
```
_Note_: Use `--target ALL_BUILD` on the second line for `Visual Studio` and `XCode`.
- run tests
```sh
cmake -S. -Bbuild -DBUILD_TESTING=ON -DCMAKE_BUILD_TYPE=Debug
cmake --build build --config Debug -j
cmake --build build --config Debug --target test
```
_Note_: Use `--target RUN_TESTS` on the last line for `Visual Studio` and `--target RUN_TEST` for `XCode`.
- install `cpu_features`
```sh
cmake --build build --config Release --target install -v
```
_Note_: Use `--target INSTALL` for `Visual Studio`.
_Note_: When using `Makefile` or `XCode` generator, you can use
[`DESTDIR`](https://www.gnu.org/software/make/manual/html_node/DESTDIR.html)
to install on a local repository.<br>
e.g.
```sh
cmake --build build --config Release --target install -v -- DESTDIR=install
```
<a name="bindings"></a>
## Community bindings
Links provided here are not affiliated with Google but are kindly provided by the OSS Community.
- .Net
- https://github.com/toor1245/cpu_features.NET
- Python
- https://github.com/Narasimha1997/py_cpu
- Java
- https://github.com/aecsocket/cpu-features-java
_Send PR to showcase your wrapper here_
+19
View File
@@ -0,0 +1,19 @@
workspace(name = "com_google_cpufeatures")
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
git_repository(
name = "com_google_googletest",
tag = "release-1.11.0",
remote = "https://github.com/google/googletest.git",
)
git_repository(
name = "bazel_skylib",
tag = "1.2.0",
remote = "https://github.com/bazelbuild/bazel-skylib.git",
)
load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
bazel_skylib_workspace()
@@ -0,0 +1,3 @@
# CpuFeatures CMake configuration file
include("${CMAKE_CURRENT_LIST_DIR}/CpuFeaturesTargets.cmake")
@@ -0,0 +1,3 @@
# CpuFeaturesNdkCompat CMake configuration file
include("${CMAKE_CURRENT_LIST_DIR}/CpuFeaturesNdkCompatTargets.cmake")
+30
View File
@@ -0,0 +1,30 @@
# CMake build instructions
## Recommended usage : Incorporating cpu_features into a CMake project
For API / ABI compatibility reasons, it is recommended to build and use
cpu_features in a subdirectory of your project or as an embedded dependency.
This is similar to the recommended usage of the googletest framework
( https://github.com/google/googletest/blob/main/googletest/README.md )
Build and use step-by-step
1- Download cpu_features and copy it in a sub-directory in your project.
or add cpu_features as a git-submodule in your project
2- You can then use the cmake command `add_subdirectory()` to include
cpu_features directly and use the `cpu_features` target in your project.
3- Add the `CpuFeatures::cpu_features` target to the `target_link_libraries()` section of
your executable or of your library.
## Disabling tests
CMake default options for cpu_features is `Release` built type with tests
enabled. To disable testing set cmake `BUILD_TESTING` variable to `OFF`.
e.g.
```sh
cmake -S. -Bbuild -DBUILD_TESTING=OFF
```
+252
View File
@@ -0,0 +1,252 @@
PROJECT := cpu_features
BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
SHA1 := $(shell git rev-parse --verify HEAD)
# General commands
.PHONY: help
BOLD=\e[1m
RESET=\e[0m
help:
@echo -e "${BOLD}SYNOPSIS${RESET}"
@echo -e "\tmake <target> [NOCACHE=1]"
@echo
@echo -e "${BOLD}DESCRIPTION${RESET}"
@echo -e "\ttest build inside docker container to have a reproductible build."
@echo
@echo -e "${BOLD}MAKE TARGETS${RESET}"
@echo -e "\t${BOLD}help${RESET}: display this help and exit."
@echo
@echo -e "\t${BOLD}amd64_<stage>${RESET}: build <stage> docker image using an Ubuntu:latest x86_64 base image."
@echo -e "\t${BOLD}save_amd64_<stage>${RESET}: Save the <stage> docker image."
@echo -e "\t${BOLD}sh_amd64_<stage>${RESET}: run a container using the <stage> docker image (debug purpose)."
@echo -e "\t${BOLD}clean_amd64_<stage>${RESET}: Remove cache and docker image."
@echo
@echo -e "\tWith ${BOLD}<stage>${RESET}:"
@echo -e "\t\t${BOLD}env${RESET}"
@echo -e "\t\t${BOLD}devel${RESET}"
@echo -e "\t\t${BOLD}build${RESET}"
@echo -e "\t\t${BOLD}test${RESET}"
@echo -e "\t\t${BOLD}install_env${RESET}"
@echo -e "\t\t${BOLD}install_devel${RESET}"
@echo -e "\t\t${BOLD}install_build${RESET}"
@echo -e "\t\t${BOLD}install_test${RESET}"
@echo -e "\te.g. 'make amd64_build'"
@echo
@echo -e "\t${BOLD}<target>_<toolchain_stage>${RESET}: build <stage> docker image for a specific toolchain target."
@echo -e "\t${BOLD}save_<target>_<toolchain_stage>${RESET}: Save the <stage> docker image for a specific platform."
@echo -e "\t${BOLD}sh_<target>_<toolchain_stage>${RESET}: run a container using the <stage> docker image specified (debug purpose)."
@echo -e "\t${BOLD}clean_<target>_<toolchain_stage>${RESET}: Remove cache and docker image."
@echo
@echo -e "\tWith ${BOLD}<target>${RESET}:"
@echo -e "\t\t${BOLD}arm-linux-gnueabihf${RESET} (linaro toolchain)"
@echo -e "\t\t${BOLD}armv8l-linux-gnueabihf${RESET} (linaro toolchain)"
@echo -e "\t\t${BOLD}arm-linux-gnueabi${RESET} (linaro toolchain)"
@echo -e "\t\t${BOLD}armeb-linux-gnueabihf${RESET} (linaro toolchain)"
@echo -e "\t\t${BOLD}armeb-linux-gnueabi${RESET} (linaro toolchain)"
@echo -e "\t\t${BOLD}aarch64-linux-gnu${RESET} (linaro toolchain)"
@echo -e "\t\t${BOLD}aarch64${RESET} (bootlin toolchain)"
@echo -e "\t\t${BOLD}aarch64_be-linux-gnu${RESET} (linaro toolchain)"
@echo -e "\t\t${BOLD}aarch64be${RESET} (bootlin toolchain)"
@echo -e "\t\t${BOLD}mips32${RESET} (codespace toolchain)"
@echo -e "\t\t${BOLD}mips64${RESET} (codespace toolchain)"
@echo -e "\t\t${BOLD}mips32el${RESET} (codespace toolchain)"
@echo -e "\t\t${BOLD}mips64el${RESET} (codespace toolchain)"
@echo -e "\t\t${BOLD}ppc${RESET} (bootlin toolchain)"
@echo -e "\t\t${BOLD}ppc64${RESET} (bootlin toolchain)"
@echo -e "\t\t${BOLD}ppc64le${RESET} (bootlin toolchain)"
@echo -e "\t\t${BOLD}riscv32${RESET} (bootlin toolchain)"
@echo -e "\t\t${BOLD}riscv64${RESET} (bootlin toolchain)"
@echo -e "\t\t${BOLD}s390x${RESET} (bootlin toolchain)"
@echo
@echo -e "\tWith ${BOLD}<toolchain_stage>${RESET}:"
@echo -e "\t\t${BOLD}env${RESET}"
@echo -e "\t\t${BOLD}devel${RESET}"
@echo -e "\t\t${BOLD}build${RESET}"
@echo -e "\t\t${BOLD}test${RESET}"
@echo -e "\te.g. 'make aarch64_test'"
@echo
@echo -e "\t${BOLD}<VM>${RESET}: build the vagrant <VM> virtual machine."
@echo -e "\t${BOLD}clean_<VM>${RESET}: Remove virtual machine for the specified vm."
@echo
@echo -e "\t${BOLD}<VM>${RESET}:"
@echo -e "\t\t${BOLD}freebsd${RESET} (FreeBSD)"
@echo
@echo -e "\t${BOLD}clean${RESET}: Remove cache and ALL docker images."
@echo
@echo -e "\t${BOLD}NOCACHE=1${RESET}: use 'docker build --no-cache' when building container (default use cache)."
@echo
@echo -e "branch: $(BRANCH)"
@echo -e "sha1: $(SHA1)"
# Need to add cmd_platform to PHONY otherwise target are ignored since they do not
# contain recipe (using FORCE do not work here)
.PHONY: all
all: build
# Delete all implicit rules to speed up makefile
MAKEFLAGS += --no-builtin-rules
.SUFFIXES:
# Remove some rules from gmake that .SUFFIXES does not remove.
SUFFIXES =
# Keep all intermediate files
# ToDo: try to remove it later
.SECONDARY:
# Docker image name prefix.
IMAGE := ${PROJECT}
ifdef NOCACHE
DOCKER_BUILD_CMD := docker build --no-cache
else
DOCKER_BUILD_CMD := docker build
endif
DOCKER_RUN_CMD := docker run --rm --init --net=host
# $* stem
# $< first prerequist
# $@ target name
############
## NATIVE ##
############
STAGES = env devel build test install_env install_devel install_build install_test
targets_amd64 = $(addprefix amd64_, $(STAGES))
.PHONY: $(targets_amd64)
$(targets_amd64): amd64_%: docker/amd64/Dockerfile
#@docker image rm -f ${IMAGE}:amd64_$* 2>/dev/null
${DOCKER_BUILD_CMD} \
--tag ${IMAGE}:amd64_$* \
--target=$* \
-f $< \
../..
#$(info Create targets: save_amd64 $(addprefix save_amd64_, $(STAGES)) (debug).)
save_targets_amd64 = $(addprefix save_amd64_, $(STAGES))
.PHONY: $(save_targets_amd64)
$(save_targets_amd64): save_amd64_%: cache/amd64/docker_%.tar
cache/amd64/docker_%.tar: amd64_%
@rm -f $@
mkdir -p cache/amd64
docker save ${IMAGE}:amd64_$* -o $@
#$(info Create targets: $(addprefix sh_amd64_, $(STAGES)) (debug).)
sh_targets_amd64 = $(addprefix sh_amd64_, $(STAGES))
.PHONY: $(sh_targets_amd64)
$(sh_targets_amd64): sh_amd64_%: amd64_%
${DOCKER_RUN_CMD} -it --name ${IMAGE}_amd64_$* ${IMAGE}:amd64_$*
#$(info Create targets: $(addprefix clean_amd64_, $(STAGES)).)
clean_targets_amd64 = $(addprefix clean_amd64_, $(STAGES))
.PHONY: clean_amd64 $(clean_targets_amd64)
clean_amd64: $(clean_targets_amd64)
$(clean_targets_amd64): clean_amd64_%:
docker image rm -f ${IMAGE}:amd64_$* 2>/dev/null
rm -f cache/amd64/docker_$*.tar
###############
## TOOLCHAIN ##
###############
TOOLCHAIN_TARGETS = \
aarch64 aarch64be \
arm-linux-gnueabihf armv8l-linux-gnueabihf arm-linux-gnueabi armeb-linux-gnueabihf armeb-linux-gnueabi \
aarch64-linux-gnu aarch64_be-linux-gnu \
mips32 mips32el mips64 mips64el \
ppc ppc64 ppc64le \
riscv32 riscv64 \
s390x
TOOLCHAIN_STAGES = env devel build test
define toolchain-stage-target =
#$$(info STAGE: $1)
#$$(info Create targets: toolchain_$1 $(addsuffix _$1, $(TOOLCHAIN_TARGETS)).)
targets_toolchain_$1 = $(addsuffix _$1, $(TOOLCHAIN_TARGETS))
.PHONY: toolchain_$1 $$(targets_toolchain_$1)
toolchain_$1: $$(targets_toolchain_$1)
$$(targets_toolchain_$1): %_$1: docker/toolchain/Dockerfile
#@docker image rm -f ${IMAGE}:$$*_$1 2>/dev/null
${DOCKER_BUILD_CMD} \
--tag ${IMAGE}:$$*_$1 \
--build-arg TARGET=$$* \
--target=$1 \
-f $$< \
../..
#$$(info Create targets: save_toolchain_$1 $(addprefix save_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS))) (debug).)
save_targets_toolchain_$1 = $(addprefix save_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS)))
.PHONY: save_toolchain_$1 $$(save_targets_toolchain_$1)
save_toolchain_$1: $$(save_targets_toolchain_$1)
$$(save_targets_toolchain_$1): save_%_$1: cache/%/docker_$1.tar
cache/%/docker_$1.tar: %_$1
@rm -f $$@
mkdir -p cache/$$*
docker save ${IMAGE}:$$*_$1 -o $$@
#$$(info Create targets: $(addprefix sh_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS))) (debug).)
sh_targets_toolchain_$1 = $(addprefix sh_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS)))
.PHONY: $$(sh_targets_toolchain_$1)
$$(sh_targets_toolchain_$1): sh_%_$1: %_$1
${DOCKER_RUN_CMD} -it --name ${IMAGE}_$$*_$1 ${IMAGE}:$$*_$1
#$$(info Create targets: clean_toolchain_$1 $(addprefix clean_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS))).)
clean_targets_toolchain_$1 = $(addprefix clean_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS)))
.PHONY: clean_toolchain_$1 $$(clean_targets_toolchain_$1)
clean_toolchain_$1: $$(clean_targets_toolchain_$1)
$$(clean_targets_toolchain_$1): clean_%_$1:
docker image rm -f ${IMAGE}:$$*_$1 2>/dev/null
rm -f cache/$$*/docker_$1.tar
endef
$(foreach stage,$(TOOLCHAIN_STAGES),$(eval $(call toolchain-stage-target,$(stage))))
## MERGE ##
.PHONY: clean_toolchain
clean_toolchain: $(addprefix clean_toolchain_, $(TOOLCHAIN_STAGES))
-rmdir $(addprefix cache/, $(TOOLCHAIN_TARGETS))
.PHONY: env devel build test
env: amd64_env toolchain_env
devel: amd64_devel toolchain_devel
build: amd64_build toolchain_build
test: amd64_test toolchain_test
.PHONY: install_env install_devel install_build install_test
install_env: amd64_install_env
install_devel: amd64_install_devel
install_build: amd64_install_build
install_test: amd64_install_test
#############
## VAGRANT ##
#############
VMS = freebsd
vms_targets = $(addsuffix _build, $(VMS))
.PHONY: $(vms_targets)
$(vms_targets): %_build: vagrant/%/Vagrantfile
@cd vagrant/$* && vagrant destroy -f
cd vagrant/$* && vagrant up
clean_vms_targets = $(addprefix clean_, $(VMS))
.PHONY: clean_vms $(clean_vms_targets)
clean_vms: $(clean_vms_targets)
$(clean_vms_targets): clean_%:
cd vagrant/$* && vagrant destroy -f
-rm -rf vagrant/$*/.vagrant
###########
## CLEAN ##
###########
.PHONY: clean
clean: clean_amd64 clean_toolchain clean_vms
docker container prune -f
docker image prune -f
-rmdir cache
.PHONY: distclean
distclean: clean
-docker container rm -f $$(docker container ls -aq)
-docker image rm -f $$(docker image ls -aq)
-vagrant box remove -f generic/freebsd12
+40
View File
@@ -0,0 +1,40 @@
## Makefile/Docker testing
To test the build on various distro, we are using docker containers and a Makefile for orchestration.
pros:
* You are independent of third party CI runner config
(e.g. [github action virtual-environnments](https://github.com/actions/virtual-environments)).
* You can run it locally on your linux system.
* Most CI provide runners with docker and Makefile installed.
cons:
* Only GNU/Linux distro supported.
### Usage
To get the help simply type:
```sh
make
```
note: you can also use from top directory
```sh
make --directory=cmake/ci
```
### Example
For example to test mips32 inside an container:
```sh
make mips32_test
```
### Docker layers
Dockerfile is splitted in several stages.
![docker](doc/docker.svg)
## Makefile/Vagrant testing
To test build for FreeBSD we are using Vagrant and VirtualBox box.
This is similar to the docker stuff but use `vagrant` as `docker` cli and
VirtuaBox to replace the docker engine daemon.
+64
View File
@@ -0,0 +1,64 @@
@startdot
digraph DockerDeps {
//rankdir=BT;
rankdir=TD;
node [shape=cylinder, style="rounded,filled", color=black, fillcolor=royalblue];
DISTRO_IMG [label="ubuntu:latest"];
PKG [label="packages\ne.g. cmake, g++", shape=box3d];
SRC [label="git repo", shape=folder];
SPL [label="sample", shape=folder];
subgraph clusterDockerfile {
ENV_IMG [label="cpu_features:amd64_env\nenv"];
DEVEL_IMG [label="cpu_features:amd64_devel\ndevel"];
BUILD_IMG [label="cpu_features:amd64_build\nbuild"];
TEST_IMG [label="cpu_features:amd64_test\ntest"];
INSTALL_ENV_IMG [label="cpu_features:amd64_install_env\ninstall_env"];
INSTALL_DEVEL_IMG [label="cpu_features:amd64_install_devel\ninstall_devel"];
INSTALL_BUILD_IMG [label="cpu_features:amd64_install_build\ninstall_build"];
INSTALL_TEST_IMG [label="cpu_features:amd64_install_test\ninstall_test"];
ENV_IMG -> DEVEL_IMG;
DEVEL_IMG -> BUILD_IMG;
BUILD_IMG -> TEST_IMG;
ENV_IMG -> INSTALL_ENV_IMG;
BUILD_IMG -> INSTALL_ENV_IMG [label="copy install", style="dashed"];
INSTALL_ENV_IMG -> INSTALL_DEVEL_IMG;
SPL -> INSTALL_DEVEL_IMG [label="copy", style="dashed"];
INSTALL_DEVEL_IMG -> INSTALL_BUILD_IMG;
INSTALL_BUILD_IMG -> INSTALL_TEST_IMG;
color=royalblue;
label = "docker/amd64/Dockerfile";
}
DISTRO_IMG -> ENV_IMG;
PKG -> ENV_IMG [label="install", style="dashed"];
SRC -> DEVEL_IMG [label="copy", style="dashed"];
subgraph clusterCache {
node [shape=note, style="rounded,filled", color=black, fillcolor=royalblue];
ENV_TAR [label="docker_amd64_env.tar"];
DEVEL_TAR [label="docker_amd64_devel.tar"];
BUILD_TAR [label="docker_amd64_build.tar"];
TEST_TAR [label="docker_amd64_test.tar"];
INSTALL_ENV_TAR [label="docker_amd64_install_env.tar"];
INSTALL_DEVEL_TAR [label="docker_amd64_install_devel.tar"];
INSTALL_BUILD_TAR [label="docker_amd64_install_build.tar"];
INSTALL_TEST_TAR [label="docker_amd64_install_test.tar"];
edge [color=red];
ENV_IMG -> ENV_TAR [label="make save_amd64_env"];
DEVEL_IMG -> DEVEL_TAR [label="make save_amd64_devel"];
BUILD_IMG -> BUILD_TAR [label="make save_amd64_build"];
TEST_IMG -> TEST_TAR [label="make save_amd64_test"];
INSTALL_ENV_IMG -> INSTALL_ENV_TAR [label="make save_amd64_install_env"];
INSTALL_DEVEL_IMG -> INSTALL_DEVEL_TAR [label="make save_amd64_install_devel"];
INSTALL_BUILD_IMG -> INSTALL_BUILD_TAR [label="make save_amd64_install_build"];
INSTALL_TEST_IMG -> INSTALL_TEST_TAR [label="make save_amd64_install_test"];
color=royalblue;
label = "cache/amd64/";
}
}
@enddot
+312
View File
@@ -0,0 +1,312 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.49.2 (0)
-->
<!-- Title: DockerDeps Pages: 1 -->
<svg width="1904pt" height="900pt"
viewBox="0.00 0.00 1904.00 899.75" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 895.75)">
<title>DockerDeps</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-895.75 1900,-895.75 1900,4 -4,4"/>
<g id="clust1" class="cluster">
<title>clusterDockerfile</title>
<polygon fill="none" stroke="royalblue" points="691,-116 691,-812.75 1253,-812.75 1253,-116 691,-116"/>
<text text-anchor="middle" x="972" y="-797.55" font-family="Times,serif" font-size="14.00">docker/amd64/Dockerfile</text>
</g>
<g id="clust2" class="cluster">
<title>clusterCache</title>
<polygon fill="none" stroke="royalblue" points="8,-8 8,-83 1826,-83 1826,-8 8,-8"/>
<text text-anchor="middle" x="917" y="-67.8" font-family="Times,serif" font-size="14.00">cache/amd64/</text>
</g>
<!-- DISTRO_IMG -->
<g id="node1" class="node">
<title>DISTRO_IMG</title>
<path fill="royalblue" stroke="black" d="M893.5,-887.48C893.5,-889.28 868.18,-890.75 837,-890.75 805.82,-890.75 780.5,-889.28 780.5,-887.48 780.5,-887.48 780.5,-858.02 780.5,-858.02 780.5,-856.22 805.82,-854.75 837,-854.75 868.18,-854.75 893.5,-856.22 893.5,-858.02 893.5,-858.02 893.5,-887.48 893.5,-887.48"/>
<path fill="none" stroke="black" d="M893.5,-887.48C893.5,-885.67 868.18,-884.2 837,-884.2 805.82,-884.2 780.5,-885.67 780.5,-887.48"/>
<text text-anchor="middle" x="837" y="-869.05" font-family="Times,serif" font-size="14.00">ubuntu:latest</text>
</g>
<!-- ENV_IMG -->
<g id="node5" class="node">
<title>ENV_IMG</title>
<path fill="royalblue" stroke="black" d="M1005,-777.1C1005,-779.74 961.52,-781.88 908,-781.88 854.48,-781.88 811,-779.74 811,-777.1 811,-777.1 811,-734.15 811,-734.15 811,-731.51 854.48,-729.37 908,-729.37 961.52,-729.37 1005,-731.51 1005,-734.15 1005,-734.15 1005,-777.1 1005,-777.1"/>
<path fill="none" stroke="black" d="M1005,-777.1C1005,-774.47 961.52,-772.33 908,-772.33 854.48,-772.33 811,-774.47 811,-777.1"/>
<text text-anchor="middle" x="908" y="-759.42" font-family="Times,serif" font-size="14.00">cpu_features:amd64_env</text>
<text text-anchor="middle" x="908" y="-744.42" font-family="Times,serif" font-size="14.00">env</text>
</g>
<!-- DISTRO_IMG&#45;&gt;ENV_IMG -->
<g id="edge10" class="edge">
<title>DISTRO_IMG&#45;&gt;ENV_IMG</title>
<path fill="none" stroke="black" d="M847.78,-854.26C858.17,-837.42 874.16,-811.49 887.05,-790.59"/>
<polygon fill="black" stroke="black" points="890.09,-792.33 892.37,-781.98 884.14,-788.65 890.09,-792.33"/>
</g>
<!-- PKG -->
<g id="node2" class="node">
<title>PKG</title>
<polygon fill="royalblue" stroke="black" points="1046.5,-891.75 915.5,-891.75 911.5,-887.75 911.5,-853.75 1042.5,-853.75 1046.5,-857.75 1046.5,-891.75"/>
<polyline fill="none" stroke="black" points="1042.5,-887.75 911.5,-887.75 "/>
<polyline fill="none" stroke="black" points="1042.5,-887.75 1042.5,-853.75 "/>
<polyline fill="none" stroke="black" points="1042.5,-887.75 1046.5,-891.75 "/>
<text text-anchor="middle" x="979" y="-876.55" font-family="Times,serif" font-size="14.00">packages</text>
<text text-anchor="middle" x="979" y="-861.55" font-family="Times,serif" font-size="14.00">e.g. cmake, g++</text>
</g>
<!-- PKG&#45;&gt;ENV_IMG -->
<g id="edge11" class="edge">
<title>PKG&#45;&gt;ENV_IMG</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M967.75,-853.51C957.4,-836.72 941.77,-811.38 929.09,-790.83"/>
<polygon fill="black" stroke="black" points="931.91,-788.73 923.69,-782.06 925.96,-792.41 931.91,-788.73"/>
<text text-anchor="middle" x="978.5" y="-824.55" font-family="Times,serif" font-size="14.00">install</text>
</g>
<!-- SRC -->
<g id="node3" class="node">
<title>SRC</title>
<polygon fill="royalblue" stroke="black" points="1334.5,-773.62 1331.5,-777.62 1310.5,-777.62 1307.5,-773.62 1261.5,-773.62 1261.5,-737.62 1334.5,-737.62 1334.5,-773.62"/>
<text text-anchor="middle" x="1298" y="-751.92" font-family="Times,serif" font-size="14.00">git repo</text>
</g>
<!-- DEVEL_IMG -->
<g id="node6" class="node">
<title>DEVEL_IMG</title>
<path fill="royalblue" stroke="black" d="M1189,-673.85C1189,-676.49 1142.83,-678.63 1086,-678.63 1029.17,-678.63 983,-676.49 983,-673.85 983,-673.85 983,-630.9 983,-630.9 983,-628.26 1029.17,-626.12 1086,-626.12 1142.83,-626.12 1189,-628.26 1189,-630.9 1189,-630.9 1189,-673.85 1189,-673.85"/>
<path fill="none" stroke="black" d="M1189,-673.85C1189,-671.22 1142.83,-669.08 1086,-669.08 1029.17,-669.08 983,-671.22 983,-673.85"/>
<text text-anchor="middle" x="1086" y="-656.17" font-family="Times,serif" font-size="14.00">cpu_features:amd64_devel</text>
<text text-anchor="middle" x="1086" y="-641.17" font-family="Times,serif" font-size="14.00">devel</text>
</g>
<!-- SRC&#45;&gt;DEVEL_IMG -->
<g id="edge12" class="edge">
<title>SRC&#45;&gt;DEVEL_IMG</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1271.39,-737.62C1266.66,-734.8 1261.73,-731.99 1257,-729.5 1224.81,-712.57 1188.08,-695.89 1156.94,-682.48"/>
<polygon fill="black" stroke="black" points="1158.03,-679.14 1147.46,-678.43 1155.28,-685.58 1158.03,-679.14"/>
<text text-anchor="middle" x="1237" y="-700.3" font-family="Times,serif" font-size="14.00">copy</text>
</g>
<!-- SPL -->
<g id="node4" class="node">
<title>SPL</title>
<polygon fill="royalblue" stroke="black" points="767,-477.88 764,-481.88 743,-481.88 740,-477.88 699,-477.88 699,-441.88 767,-441.88 767,-477.88"/>
<text text-anchor="middle" x="733" y="-456.18" font-family="Times,serif" font-size="14.00">sample</text>
</g>
<!-- INSTALL_DEVEL_IMG -->
<g id="node10" class="node">
<title>INSTALL_DEVEL_IMG</title>
<path fill="royalblue" stroke="black" d="M956.5,-378.1C956.5,-380.74 898.9,-382.88 828,-382.88 757.1,-382.88 699.5,-380.74 699.5,-378.1 699.5,-378.1 699.5,-335.15 699.5,-335.15 699.5,-332.51 757.1,-330.37 828,-330.37 898.9,-330.37 956.5,-332.51 956.5,-335.15 956.5,-335.15 956.5,-378.1 956.5,-378.1"/>
<path fill="none" stroke="black" d="M956.5,-378.1C956.5,-375.47 898.9,-373.33 828,-373.33 757.1,-373.33 699.5,-375.47 699.5,-378.1"/>
<text text-anchor="middle" x="828" y="-360.43" font-family="Times,serif" font-size="14.00">cpu_features:amd64_install_devel</text>
<text text-anchor="middle" x="828" y="-345.43" font-family="Times,serif" font-size="14.00">install_devel</text>
</g>
<!-- SPL&#45;&gt;INSTALL_DEVEL_IMG -->
<g id="edge7" class="edge">
<title>SPL&#45;&gt;INSTALL_DEVEL_IMG</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M749.12,-441.7C762.24,-427.71 781.16,-407.54 797.18,-390.47"/>
<polygon fill="black" stroke="black" points="800.02,-392.56 804.31,-382.87 794.91,-387.77 800.02,-392.56"/>
<text text-anchor="middle" x="803" y="-404.55" font-family="Times,serif" font-size="14.00">copy</text>
</g>
<!-- ENV_IMG&#45;&gt;DEVEL_IMG -->
<g id="edge1" class="edge">
<title>ENV_IMG&#45;&gt;DEVEL_IMG</title>
<path fill="none" stroke="black" d="M952.46,-729.34C976.87,-715.45 1007.3,-698.14 1032.95,-683.55"/>
<polygon fill="black" stroke="black" points="1034.84,-686.5 1041.8,-678.52 1031.38,-680.42 1034.84,-686.5"/>
</g>
<!-- INSTALL_ENV_IMG -->
<g id="node9" class="node">
<title>INSTALL_ENV_IMG</title>
<path fill="royalblue" stroke="black" d="M1030.5,-481.35C1030.5,-483.99 975.59,-486.13 908,-486.13 840.41,-486.13 785.5,-483.99 785.5,-481.35 785.5,-481.35 785.5,-438.4 785.5,-438.4 785.5,-435.76 840.41,-433.62 908,-433.62 975.59,-433.62 1030.5,-435.76 1030.5,-438.4 1030.5,-438.4 1030.5,-481.35 1030.5,-481.35"/>
<path fill="none" stroke="black" d="M1030.5,-481.35C1030.5,-478.72 975.59,-476.58 908,-476.58 840.41,-476.58 785.5,-478.72 785.5,-481.35"/>
<text text-anchor="middle" x="908" y="-463.68" font-family="Times,serif" font-size="14.00">cpu_features:amd64_install_env</text>
<text text-anchor="middle" x="908" y="-448.68" font-family="Times,serif" font-size="14.00">install_env</text>
</g>
<!-- ENV_IMG&#45;&gt;INSTALL_ENV_IMG -->
<g id="edge4" class="edge">
<title>ENV_IMG&#45;&gt;INSTALL_ENV_IMG</title>
<path fill="none" stroke="black" d="M908,-729.33C908,-676.94 908,-556.49 908,-496.37"/>
<polygon fill="black" stroke="black" points="911.5,-496.22 908,-486.22 904.5,-496.22 911.5,-496.22"/>
</g>
<!-- ENV_TAR -->
<g id="node13" class="node">
<title>ENV_TAR</title>
<polygon fill="royalblue" stroke="black" points="186,-52 16,-52 16,-16 192,-16 192,-46 186,-52"/>
<polyline fill="none" stroke="black" points="186,-52 186,-46 "/>
<polyline fill="none" stroke="black" points="192,-46 186,-46 "/>
<text text-anchor="middle" x="104" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_env.tar</text>
</g>
<!-- ENV_IMG&#45;&gt;ENV_TAR -->
<g id="edge13" class="edge">
<title>ENV_IMG&#45;&gt;ENV_TAR</title>
<path fill="none" stroke="red" d="M810.87,-751.31C609.47,-743.14 165,-717.82 165,-653.38 165,-653.38 165,-653.38 165,-149.12 165,-115.26 143.85,-81.71 126.46,-59.84"/>
<polygon fill="red" stroke="red" points="129.09,-57.54 120.03,-52.05 123.7,-61.99 129.09,-57.54"/>
<text text-anchor="middle" x="246.5" y="-404.55" font-family="Times,serif" font-size="14.00">make save_amd64_env</text>
</g>
<!-- BUILD_IMG -->
<g id="node7" class="node">
<title>BUILD_IMG</title>
<path fill="royalblue" stroke="black" d="M1245,-584.6C1245,-587.24 1199.28,-589.38 1143,-589.38 1086.72,-589.38 1041,-587.24 1041,-584.6 1041,-584.6 1041,-541.65 1041,-541.65 1041,-539.01 1086.72,-536.87 1143,-536.87 1199.28,-536.87 1245,-539.01 1245,-541.65 1245,-541.65 1245,-584.6 1245,-584.6"/>
<path fill="none" stroke="black" d="M1245,-584.6C1245,-581.97 1199.28,-579.83 1143,-579.83 1086.72,-579.83 1041,-581.97 1041,-584.6"/>
<text text-anchor="middle" x="1143" y="-566.92" font-family="Times,serif" font-size="14.00">cpu_features:amd64_build</text>
<text text-anchor="middle" x="1143" y="-551.92" font-family="Times,serif" font-size="14.00">build</text>
</g>
<!-- DEVEL_IMG&#45;&gt;BUILD_IMG -->
<g id="edge2" class="edge">
<title>DEVEL_IMG&#45;&gt;BUILD_IMG</title>
<path fill="none" stroke="black" d="M1102.49,-626.14C1108.28,-617.28 1114.88,-607.17 1121.04,-597.73"/>
<polygon fill="black" stroke="black" points="1124.01,-599.59 1126.55,-589.3 1118.15,-595.76 1124.01,-599.59"/>
</g>
<!-- DEVEL_TAR -->
<g id="node14" class="node">
<title>DEVEL_TAR</title>
<polygon fill="royalblue" stroke="black" points="395.5,-52 210.5,-52 210.5,-16 401.5,-16 401.5,-46 395.5,-52"/>
<polyline fill="none" stroke="black" points="395.5,-52 395.5,-46 "/>
<polyline fill="none" stroke="black" points="401.5,-46 395.5,-46 "/>
<text text-anchor="middle" x="306" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_devel.tar</text>
</g>
<!-- DEVEL_IMG&#45;&gt;DEVEL_TAR -->
<g id="edge14" class="edge">
<title>DEVEL_IMG&#45;&gt;DEVEL_TAR</title>
<path fill="none" stroke="red" d="M982.94,-648.59C792.56,-642.05 405,-621.67 405,-564.12 405,-564.12 405,-564.12 405,-149.12 405,-110.26 371.83,-78.15 343.9,-58"/>
<polygon fill="red" stroke="red" points="345.65,-54.96 335.44,-52.14 341.66,-60.71 345.65,-54.96"/>
<text text-anchor="middle" x="493" y="-352.93" font-family="Times,serif" font-size="14.00">make save_amd64_devel</text>
</g>
<!-- TEST_IMG -->
<g id="node8" class="node">
<title>TEST_IMG</title>
<path fill="royalblue" stroke="black" d="M1245,-481.35C1245,-483.99 1201.07,-486.13 1147,-486.13 1092.93,-486.13 1049,-483.99 1049,-481.35 1049,-481.35 1049,-438.4 1049,-438.4 1049,-435.76 1092.93,-433.62 1147,-433.62 1201.07,-433.62 1245,-435.76 1245,-438.4 1245,-438.4 1245,-481.35 1245,-481.35"/>
<path fill="none" stroke="black" d="M1245,-481.35C1245,-478.72 1201.07,-476.58 1147,-476.58 1092.93,-476.58 1049,-478.72 1049,-481.35"/>
<text text-anchor="middle" x="1147" y="-463.68" font-family="Times,serif" font-size="14.00">cpu_features:amd64_test</text>
<text text-anchor="middle" x="1147" y="-448.68" font-family="Times,serif" font-size="14.00">test</text>
</g>
<!-- BUILD_IMG&#45;&gt;TEST_IMG -->
<g id="edge3" class="edge">
<title>BUILD_IMG&#45;&gt;TEST_IMG</title>
<path fill="none" stroke="black" d="M1144,-536.84C1144.48,-524.63 1145.07,-509.79 1145.59,-496.47"/>
<polygon fill="black" stroke="black" points="1149.1,-496.32 1146,-486.19 1142.11,-496.05 1149.1,-496.32"/>
</g>
<!-- BUILD_IMG&#45;&gt;INSTALL_ENV_IMG -->
<g id="edge5" class="edge">
<title>BUILD_IMG&#45;&gt;INSTALL_ENV_IMG</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1084.61,-536.97C1051.68,-522.78 1010.38,-504.99 976,-490.17"/>
<polygon fill="black" stroke="black" points="977.07,-486.82 966.5,-486.08 974.3,-493.25 977.07,-486.82"/>
<text text-anchor="middle" x="1080" y="-507.8" font-family="Times,serif" font-size="14.00">copy install</text>
</g>
<!-- BUILD_TAR -->
<g id="node15" class="node">
<title>BUILD_TAR</title>
<polygon fill="royalblue" stroke="black" points="1812,-52 1630,-52 1630,-16 1818,-16 1818,-46 1812,-52"/>
<polyline fill="none" stroke="black" points="1812,-52 1812,-46 "/>
<polyline fill="none" stroke="black" points="1818,-46 1812,-46 "/>
<text text-anchor="middle" x="1724" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_build.tar</text>
</g>
<!-- BUILD_IMG&#45;&gt;BUILD_TAR -->
<g id="edge15" class="edge">
<title>BUILD_IMG&#45;&gt;BUILD_TAR</title>
<path fill="none" stroke="red" d="M1245.18,-554.53C1411.4,-540.79 1722,-508.71 1722,-460.88 1722,-460.88 1722,-460.88 1722,-149.12 1722,-119.36 1722.69,-85.23 1723.26,-62.11"/>
<polygon fill="red" stroke="red" points="1726.76,-62.1 1723.52,-52.01 1719.76,-61.92 1726.76,-62.1"/>
<text text-anchor="middle" x="1809" y="-301.3" font-family="Times,serif" font-size="14.00">make save_amd64_build</text>
</g>
<!-- TEST_TAR -->
<g id="node16" class="node">
<title>TEST_TAR</title>
<polygon fill="royalblue" stroke="black" points="1606,-52 1432,-52 1432,-16 1612,-16 1612,-46 1606,-52"/>
<polyline fill="none" stroke="black" points="1606,-52 1606,-46 "/>
<polyline fill="none" stroke="black" points="1612,-46 1606,-46 "/>
<text text-anchor="middle" x="1522" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_test.tar</text>
</g>
<!-- TEST_IMG&#45;&gt;TEST_TAR -->
<g id="edge16" class="edge">
<title>TEST_IMG&#45;&gt;TEST_TAR</title>
<path fill="none" stroke="red" d="M1245.07,-451.87C1356.77,-441.13 1524,-415.4 1524,-357.62 1524,-357.62 1524,-357.62 1524,-149.12 1524,-119.36 1523.31,-85.23 1522.74,-62.11"/>
<polygon fill="red" stroke="red" points="1526.24,-61.92 1522.48,-52.01 1519.24,-62.1 1526.24,-61.92"/>
<text text-anchor="middle" x="1607" y="-249.68" font-family="Times,serif" font-size="14.00">make save_amd64_test</text>
</g>
<!-- INSTALL_ENV_IMG&#45;&gt;INSTALL_DEVEL_IMG -->
<g id="edge6" class="edge">
<title>INSTALL_ENV_IMG&#45;&gt;INSTALL_DEVEL_IMG</title>
<path fill="none" stroke="black" d="M888.02,-433.59C877.81,-420.66 865.25,-404.76 854.26,-390.86"/>
<polygon fill="black" stroke="black" points="856.95,-388.62 848,-382.94 851.46,-392.96 856.95,-388.62"/>
</g>
<!-- INSTALL_ENV_TAR -->
<g id="node17" class="node">
<title>INSTALL_ENV_TAR</title>
<polygon fill="royalblue" stroke="black" points="1407.5,-52 1186.5,-52 1186.5,-16 1413.5,-16 1413.5,-46 1407.5,-52"/>
<polyline fill="none" stroke="black" points="1407.5,-52 1407.5,-46 "/>
<polyline fill="none" stroke="black" points="1413.5,-46 1407.5,-46 "/>
<text text-anchor="middle" x="1300" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_install_env.tar</text>
</g>
<!-- INSTALL_ENV_IMG&#45;&gt;INSTALL_ENV_TAR -->
<g id="edge17" class="edge">
<title>INSTALL_ENV_IMG&#45;&gt;INSTALL_ENV_TAR</title>
<path fill="none" stroke="red" d="M1012.88,-434.97C1121.03,-409.58 1274,-371.26 1274,-357.62 1274,-357.62 1274,-357.62 1274,-149.12 1274,-118.64 1282.93,-84.69 1290.32,-61.81"/>
<polygon fill="red" stroke="red" points="1293.71,-62.72 1293.57,-52.12 1287.07,-60.49 1293.71,-62.72"/>
<text text-anchor="middle" x="1381" y="-249.68" font-family="Times,serif" font-size="14.00">make save_amd64_install_env</text>
</g>
<!-- INSTALL_BUILD_IMG -->
<g id="node11" class="node">
<title>INSTALL_BUILD_IMG</title>
<path fill="royalblue" stroke="black" d="M955.5,-274.85C955.5,-277.49 898.35,-279.63 828,-279.63 757.65,-279.63 700.5,-277.49 700.5,-274.85 700.5,-274.85 700.5,-231.9 700.5,-231.9 700.5,-229.26 757.65,-227.12 828,-227.12 898.35,-227.12 955.5,-229.26 955.5,-231.9 955.5,-231.9 955.5,-274.85 955.5,-274.85"/>
<path fill="none" stroke="black" d="M955.5,-274.85C955.5,-272.22 898.35,-270.08 828,-270.08 757.65,-270.08 700.5,-272.22 700.5,-274.85"/>
<text text-anchor="middle" x="828" y="-257.18" font-family="Times,serif" font-size="14.00">cpu_features:amd64_install_build</text>
<text text-anchor="middle" x="828" y="-242.18" font-family="Times,serif" font-size="14.00">install_build</text>
</g>
<!-- INSTALL_DEVEL_IMG&#45;&gt;INSTALL_BUILD_IMG -->
<g id="edge8" class="edge">
<title>INSTALL_DEVEL_IMG&#45;&gt;INSTALL_BUILD_IMG</title>
<path fill="none" stroke="black" d="M828,-330.34C828,-318.13 828,-303.29 828,-289.97"/>
<polygon fill="black" stroke="black" points="831.5,-289.69 828,-279.69 824.5,-289.69 831.5,-289.69"/>
</g>
<!-- INSTALL_DEVEL_TAR -->
<g id="node18" class="node">
<title>INSTALL_DEVEL_TAR</title>
<polygon fill="royalblue" stroke="black" points="656,-52 420,-52 420,-16 662,-16 662,-46 656,-52"/>
<polyline fill="none" stroke="black" points="656,-52 656,-46 "/>
<polyline fill="none" stroke="black" points="662,-46 656,-46 "/>
<text text-anchor="middle" x="541" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_install_devel.tar</text>
</g>
<!-- INSTALL_DEVEL_IMG&#45;&gt;INSTALL_DEVEL_TAR -->
<g id="edge18" class="edge">
<title>INSTALL_DEVEL_IMG&#45;&gt;INSTALL_DEVEL_TAR</title>
<path fill="none" stroke="red" d="M761.39,-330.48C708.37,-307.05 636.42,-266.99 595,-209.25 562.63,-164.12 549.27,-99.06 544.06,-62.54"/>
<polygon fill="red" stroke="red" points="547.47,-61.64 542.7,-52.18 540.53,-62.55 547.47,-61.64"/>
<text text-anchor="middle" x="708.5" y="-198.05" font-family="Times,serif" font-size="14.00">make save_amd64_install_devel</text>
</g>
<!-- INSTALL_TEST_IMG -->
<g id="node12" class="node">
<title>INSTALL_TEST_IMG</title>
<path fill="royalblue" stroke="black" d="M948.5,-171.6C948.5,-174.24 893.15,-176.38 825,-176.38 756.85,-176.38 701.5,-174.24 701.5,-171.6 701.5,-171.6 701.5,-128.65 701.5,-128.65 701.5,-126.01 756.85,-123.87 825,-123.87 893.15,-123.87 948.5,-126.01 948.5,-128.65 948.5,-128.65 948.5,-171.6 948.5,-171.6"/>
<path fill="none" stroke="black" d="M948.5,-171.6C948.5,-168.97 893.15,-166.83 825,-166.83 756.85,-166.83 701.5,-168.97 701.5,-171.6"/>
<text text-anchor="middle" x="825" y="-153.93" font-family="Times,serif" font-size="14.00">cpu_features:amd64_install_test</text>
<text text-anchor="middle" x="825" y="-138.93" font-family="Times,serif" font-size="14.00">install_test</text>
</g>
<!-- INSTALL_BUILD_IMG&#45;&gt;INSTALL_TEST_IMG -->
<g id="edge9" class="edge">
<title>INSTALL_BUILD_IMG&#45;&gt;INSTALL_TEST_IMG</title>
<path fill="none" stroke="black" d="M827.25,-227.09C826.89,-214.88 826.45,-200.04 826.05,-186.72"/>
<polygon fill="black" stroke="black" points="829.54,-186.33 825.75,-176.44 822.55,-186.54 829.54,-186.33"/>
</g>
<!-- INSTALL_BUILD_TAR -->
<g id="node19" class="node">
<title>INSTALL_BUILD_TAR</title>
<polygon fill="royalblue" stroke="black" points="1162.5,-52 929.5,-52 929.5,-16 1168.5,-16 1168.5,-46 1162.5,-52"/>
<polyline fill="none" stroke="black" points="1162.5,-52 1162.5,-46 "/>
<polyline fill="none" stroke="black" points="1168.5,-46 1162.5,-46 "/>
<text text-anchor="middle" x="1049" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_install_build.tar</text>
</g>
<!-- INSTALL_BUILD_IMG&#45;&gt;INSTALL_BUILD_TAR -->
<g id="edge19" class="edge">
<title>INSTALL_BUILD_IMG&#45;&gt;INSTALL_BUILD_TAR</title>
<path fill="none" stroke="red" d="M882.76,-227.11C907.43,-214.09 935.91,-196.66 958,-176.25 994.16,-142.85 1022.19,-92.11 1037.09,-61.41"/>
<polygon fill="red" stroke="red" points="1040.34,-62.72 1041.46,-52.19 1034.02,-59.72 1040.34,-62.72"/>
<text text-anchor="middle" x="1117.5" y="-146.43" font-family="Times,serif" font-size="14.00">make save_amd64_install_build</text>
</g>
<!-- INSTALL_TEST_TAR -->
<g id="node20" class="node">
<title>INSTALL_TEST_TAR</title>
<polygon fill="royalblue" stroke="black" points="905.5,-52 680.5,-52 680.5,-16 911.5,-16 911.5,-46 905.5,-52"/>
<polyline fill="none" stroke="black" points="905.5,-52 905.5,-46 "/>
<polyline fill="none" stroke="black" points="911.5,-46 905.5,-46 "/>
<text text-anchor="middle" x="796" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_install_test.tar</text>
</g>
<!-- INSTALL_TEST_IMG&#45;&gt;INSTALL_TEST_TAR -->
<g id="edge20" class="edge">
<title>INSTALL_TEST_IMG&#45;&gt;INSTALL_TEST_TAR</title>
<path fill="none" stroke="red" d="M799.99,-123.98C795.9,-118.47 792.26,-112.36 790,-106 785.07,-92.11 786.03,-75.77 788.46,-62.27"/>
<polygon fill="red" stroke="red" points="791.96,-62.66 790.65,-52.15 785.12,-61.19 791.96,-62.66"/>
<text text-anchor="middle" x="898.5" y="-94.8" font-family="Times,serif" font-size="14.00">make save_amd64_install_test</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 21 KiB

+7
View File
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -ex
rm -f ./*.svg ./*.png
for i in *.dot; do
plantuml -Tsvg "$i";
done
+48
View File
@@ -0,0 +1,48 @@
# Create a virtual environment with all tools installed
# ref: https://hub.docker.com/_/ubuntu
FROM ubuntu:latest AS env
LABEL maintainer="corentinl@google.com"
# Install system build dependencies
ENV PATH=/usr/local/bin:$PATH
RUN apt-get update -qq \
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq git wget libssl-dev build-essential \
ninja-build python3 pkgconf libglib2.0-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
ENTRYPOINT ["/usr/bin/bash", "-c"]
CMD ["/usr/bin/bash"]
# Install CMake 3.21.3
RUN wget "https://cmake.org/files/v3.21/cmake-3.21.3-linux-x86_64.sh" \
&& chmod a+x cmake-3.21.3-linux-x86_64.sh \
&& ./cmake-3.21.3-linux-x86_64.sh --prefix=/usr/local/ --skip-license \
&& rm cmake-3.21.3-linux-x86_64.sh
FROM env AS devel
WORKDIR /home/project
COPY . .
FROM devel AS build
RUN cmake -version
RUN cmake -S. -Bbuild
RUN cmake --build build --target all -v
RUN cmake --build build --target install -v
FROM build AS test
ENV CTEST_OUTPUT_ON_FAILURE=1
RUN cmake --build build --target test -v
# Test install rules
FROM env AS install_env
COPY --from=build /usr/local /usr/local/
FROM install_env AS install_devel
WORKDIR /home/sample
COPY cmake/ci/sample .
FROM install_devel AS install_build
RUN cmake -S. -Bbuild
RUN cmake --build build --target all -v
FROM install_build AS install_test
RUN cmake --build build --target test
@@ -0,0 +1,34 @@
# Create a virtual environment with all tools installed
# ref: https://hub.docker.com/_/ubuntu
FROM ubuntu:latest AS env
LABEL maintainer="corentinl@google.com"
# Install system build dependencies
ENV PATH=/usr/local/bin:$PATH
RUN apt-get update -qq \
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq git wget libssl-dev build-essential \
ninja-build python3 pkgconf libglib2.0-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
ENTRYPOINT ["/usr/bin/bash", "-c"]
CMD ["/usr/bin/bash"]
# Install CMake 3.21.3
RUN wget "https://cmake.org/files/v3.21/cmake-3.21.3-linux-x86_64.sh" \
&& chmod a+x cmake-3.21.3-linux-x86_64.sh \
&& ./cmake-3.21.3-linux-x86_64.sh --prefix=/usr/local/ --skip-license \
&& rm cmake-3.21.3-linux-x86_64.sh
FROM env AS devel
WORKDIR /home/project
COPY . .
ARG TARGET
ENV TARGET ${TARGET:-unknown}
FROM devel AS build
RUN cmake -version
RUN ./scripts/run_integration.sh build
FROM build AS test
RUN ./scripts/run_integration.sh qemu
RUN ./scripts/run_integration.sh test
+22
View File
@@ -0,0 +1,22 @@
cmake_minimum_required(VERSION 3.15)
project(Sample VERSION 1.0.0 LANGUAGES CXX)
include(CTest)
find_package(CpuFeatures REQUIRED)
add_executable(sample main.cpp)
target_compile_features(sample PUBLIC cxx_std_11)
set_target_properties(sample PROPERTIES
CXX_STANDARD 11
CXX_STANDARD_REQUIRED ON
VERSION ${PROJECT_VERSION})
target_link_libraries(sample PRIVATE CpuFeatures::cpu_features)
if(BUILD_TESTING)
add_test(NAME sample_test COMMAND sample)
endif()
include(GNUInstallDirs)
install(TARGETS sample
EXPORT SampleTargets
DESTINATION ${CMAKE_INSTALL_BIN_DIR})
+11
View File
@@ -0,0 +1,11 @@
#include <iostream>
#include "cpuinfo_x86.h"
using namespace cpu_features;
int main(int /*argc*/, char** /*argv*/) {
static const X86Features features = GetX86Info().features;
std::cout << std::endl;
return 0;
}
@@ -0,0 +1,107 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
# The most common configuration options are documented and commented below.
# For a complete reference, please see the online documentation at
# https://docs.vagrantup.com.
# Every Vagrant development environment requires a box. You can search for
# boxes at https://vagrantcloud.com/search.
config.vm.guest = :freebsd
config.vm.box = "generic/freebsd12"
config.ssh.shell = "sh"
# Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs
# `vagrant box outdated`. This is not recommended.
# config.vm.box_check_update = false
# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine. In the example below,
# accessing "localhost:8080" will access port 80 on the guest machine.
# NOTE: This will enable public access to the opened port
# config.vm.network "forwarded_port", guest: 80, host: 8080
# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine and only allow access
# via 127.0.0.1 to disable public access
# config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"
# Create a private network, which allows host-only access to the machine
# using a specific IP.
# config.vm.network "private_network", ip: "192.168.33.10"
# Create a public network, which generally matched to bridged network.
# Bridged networks make the machine appear as another physical device on
# your network.
# config.vm.network "public_network"
# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
# argument is a set of non-required options.
#config.vm.synced_folder "../../..", "/home/vagrant/project"
config.vm.synced_folder ".", "/vagrant", id: "vagrant-root", disabled: true
config.vm.provision "file", source: "../../../../CMakeLists.txt", destination: "$HOME/project/"
config.vm.provision "file", source: "../../../../cmake", destination: "$HOME/project/"
config.vm.provision "file", source: "../../../../include", destination: "$HOME/project/"
config.vm.provision "file", source: "../../../../src", destination: "$HOME/project/"
config.vm.provision "file", source: "../../../../test", destination: "$HOME/project/"
# Provider-specific configuration so you can fine-tune various
# backing providers for Vagrant. These expose provider-specific options.
# Example for VirtualBox:
#
# config.vm.provider "virtualbox" do |vb|
# # Display the VirtualBox GUI when booting the machine
# vb.gui = true
#
# # Customize the amount of memory on the VM:
# vb.memory = "1024"
# end
#
# View the documentation for the provider you are using for more
# information on available options.
# Enable provisioning with a shell script. Additional provisioners such as
# Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
# documentation for more information about their specific syntax and use.
# note: clang installed by default
config.vm.provision "env", type: "shell", inline:<<-SHELL
set -x
pkg update -f
pkg install -y git cmake
SHELL
config.vm.provision "devel", type: "shell", inline:<<-SHELL
set -x
cd project
ls
SHELL
config.vm.provision "configure", type: "shell", inline:<<-SHELL
set -x
cd project
cmake -S. -Bbuild -DBUILD_TESTING=ON
SHELL
config.vm.provision "build", type: "shell", inline:<<-SHELL
set -x
cd project
cmake --build build -v
SHELL
config.vm.provision "test", type: "shell", inline:<<-SHELL
set -x
cd project
cmake --build build --target test -v
SHELL
config.vm.provision "test", type: "shell", inline:<<-SHELL
set -x
cd project
cmake --build build --target install -v
SHELL
end
@@ -0,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 main
SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src"
BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)
+54
View File
@@ -0,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_
+388
View File
@@ -0,0 +1,388 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_
#define CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_
////////////////////////////////////////////////////////////////////////////////
// Architectures
////////////////////////////////////////////////////////////////////////////////
#if defined(__pnacl__) || defined(__CLR_VER)
#define CPU_FEATURES_ARCH_VM
#endif
#if (defined(_M_IX86) || defined(__i386__)) && !defined(CPU_FEATURES_ARCH_VM)
#define CPU_FEATURES_ARCH_X86_32
#endif
#if (defined(_M_X64) || defined(__x86_64__)) && !defined(CPU_FEATURES_ARCH_VM)
#define CPU_FEATURES_ARCH_X86_64
#endif
#if defined(CPU_FEATURES_ARCH_X86_32) || defined(CPU_FEATURES_ARCH_X86_64)
#define CPU_FEATURES_ARCH_X86
#endif
#if (defined(__arm__) || defined(_M_ARM))
#define CPU_FEATURES_ARCH_ARM
#endif
#if (defined(__aarch64__) || defined(_M_ARM64))
#define CPU_FEATURES_ARCH_AARCH64
#endif
#if (defined(CPU_FEATURES_ARCH_AARCH64) || defined(CPU_FEATURES_ARCH_ARM))
#define CPU_FEATURES_ARCH_ANY_ARM
#endif
#if defined(__mips64)
#define CPU_FEATURES_ARCH_MIPS64
#endif
#if defined(__mips__) && !defined(__mips64) // mips64 also declares __mips__
#define CPU_FEATURES_ARCH_MIPS32
#endif
#if defined(CPU_FEATURES_ARCH_MIPS32) || defined(CPU_FEATURES_ARCH_MIPS64)
#define CPU_FEATURES_ARCH_MIPS
#endif
#if defined(__powerpc__)
#define CPU_FEATURES_ARCH_PPC
#endif
#if defined(__s390x__)
#define CPU_FEATURES_ARCH_S390X
#endif
#if defined(__riscv)
#define CPU_FEATURES_ARCH_RISCV
#endif
#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 32
#define CPU_FEATURES_ARCH_RISCV32
#endif
#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64
#define CPU_FEATURES_ARCH_RISCV64
#endif
#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 128
#define CPU_FEATURES_ARCH_RISCV128
#endif
#if defined(__loongarch64)
#define CPU_FEATURES_ARCH_LOONGARCH
#endif
////////////////////////////////////////////////////////////////////////////////
// Os
////////////////////////////////////////////////////////////////////////////////
#if (defined(__freebsd__) || defined(__FreeBSD__))
#define CPU_FEATURES_OS_FREEBSD
#endif
#if defined(__ANDROID__)
#define CPU_FEATURES_OS_ANDROID
#endif
#if defined(__linux__) && !defined(CPU_FEATURES_OS_FREEBSD) && \
!defined(CPU_FEATURES_OS_ANDROID)
#define CPU_FEATURES_OS_LINUX
#endif
#if (defined(_WIN64) || defined(_WIN32))
#define CPU_FEATURES_OS_WINDOWS
#endif
#if (defined(__apple__) || defined(__APPLE__) || defined(__MACH__))
// From https://stackoverflow.com/a/49560690
#include "TargetConditionals.h"
#if defined(TARGET_OS_OSX)
#define CPU_FEATURES_OS_MACOS
#endif
#if defined(TARGET_OS_IPHONE)
// This is set for any non-Mac Apple products (IOS, TV, WATCH)
#define CPU_FEATURES_OS_IPHONE
#endif
#endif
////////////////////////////////////////////////////////////////////////////////
// Compilers
////////////////////////////////////////////////////////////////////////////////
#if defined(__clang__)
#define CPU_FEATURES_COMPILER_CLANG
#endif
#if defined(__GNUC__) && !defined(__clang__)
#define CPU_FEATURES_COMPILER_GCC
#endif
#if defined(_MSC_VER)
#define CPU_FEATURES_COMPILER_MSC
#endif
////////////////////////////////////////////////////////////////////////////////
// Cpp
////////////////////////////////////////////////////////////////////////////////
#if defined(__cplusplus)
#define CPU_FEATURES_START_CPP_NAMESPACE \
namespace cpu_features { \
extern "C" {
#define CPU_FEATURES_END_CPP_NAMESPACE \
} \
}
#else
#define CPU_FEATURES_START_CPP_NAMESPACE
#define CPU_FEATURES_END_CPP_NAMESPACE
#endif
////////////////////////////////////////////////////////////////////////////////
// Compiler flags
////////////////////////////////////////////////////////////////////////////////
// Use the following to check if a feature is known to be available at
// compile time. See README.md for an example.
#if defined(CPU_FEATURES_ARCH_X86)
#if defined(__AES__)
#define CPU_FEATURES_COMPILED_X86_AES 1
#else
#define CPU_FEATURES_COMPILED_X86_AES 0
#endif // defined(__AES__)
#if defined(__F16C__)
#define CPU_FEATURES_COMPILED_X86_F16C 1
#else
#define CPU_FEATURES_COMPILED_X86_F16C 0
#endif // defined(__F16C__)
#if defined(__BMI__)
#define CPU_FEATURES_COMPILED_X86_BMI 1
#else
#define CPU_FEATURES_COMPILED_X86_BMI 0
#endif // defined(__BMI__)
#if defined(__BMI2__)
#define CPU_FEATURES_COMPILED_X86_BMI2 1
#else
#define CPU_FEATURES_COMPILED_X86_BMI2 0
#endif // defined(__BMI2__)
#if (defined(__SSE__) || (_M_IX86_FP >= 1))
#define CPU_FEATURES_COMPILED_X86_SSE 1
#else
#define CPU_FEATURES_COMPILED_X86_SSE 0
#endif
#if (defined(__SSE2__) || (_M_IX86_FP >= 2))
#define CPU_FEATURES_COMPILED_X86_SSE2 1
#else
#define CPU_FEATURES_COMPILED_X86_SSE2 0
#endif
#if defined(__SSE3__)
#define CPU_FEATURES_COMPILED_X86_SSE3 1
#else
#define CPU_FEATURES_COMPILED_X86_SSE3 0
#endif // defined(__SSE3__)
#if defined(__SSSE3__)
#define CPU_FEATURES_COMPILED_X86_SSSE3 1
#else
#define CPU_FEATURES_COMPILED_X86_SSSE3 0
#endif // defined(__SSSE3__)
#if defined(__SSE4_1__)
#define CPU_FEATURES_COMPILED_X86_SSE4_1 1
#else
#define CPU_FEATURES_COMPILED_X86_SSE4_1 0
#endif // defined(__SSE4_1__)
#if defined(__SSE4_2__)
#define CPU_FEATURES_COMPILED_X86_SSE4_2 1
#else
#define CPU_FEATURES_COMPILED_X86_SSE4_2 0
#endif // defined(__SSE4_2__)
#if defined(__AVX__)
#define CPU_FEATURES_COMPILED_X86_AVX 1
#else
#define CPU_FEATURES_COMPILED_X86_AVX 0
#endif // defined(__AVX__)
#if defined(__AVX2__)
#define CPU_FEATURES_COMPILED_X86_AVX2 1
#else
#define CPU_FEATURES_COMPILED_X86_AVX2 0
#endif // defined(__AVX2__)
#endif // defined(CPU_FEATURES_ARCH_X86)
#if defined(CPU_FEATURES_ARCH_ANY_ARM)
#if defined(__ARM_NEON__)
#define CPU_FEATURES_COMPILED_ANY_ARM_NEON 1
#else
#define CPU_FEATURES_COMPILED_ANY_ARM_NEON 0
#endif // defined(__ARM_NEON__)
#endif // defined(CPU_FEATURES_ARCH_ANY_ARM)
#if defined(CPU_FEATURES_ARCH_MIPS)
#if defined(__mips_msa)
#define CPU_FEATURES_COMPILED_MIPS_MSA 1
#else
#define CPU_FEATURES_COMPILED_MIPS_MSA 0
#endif // defined(__mips_msa)
#if defined(__mips3d)
#define CPU_FEATURES_COMPILED_MIPS_MIPS3D 1
#else
#define CPU_FEATURES_COMPILED_MIPS_MIPS3D 0
#endif
#endif // defined(CPU_FEATURES_ARCH_MIPS)
#if defined(CPU_FEATURES_ARCH_RISCV)
#if defined(__riscv_e)
#define CPU_FEATURES_COMPILED_RISCV_E 1
#else
#define CPU_FEATURES_COMPILED_RISCV_E 0
#endif
#if defined(__riscv_i)
#define CPU_FEATURES_COMPILED_RISCV_I 1
#else
#define CPU_FEATURES_COMPILED_RISCV_I 0
#endif
#if defined(__riscv_m)
#define CPU_FEATURES_COMPILED_RISCV_M 1
#else
#define CPU_FEATURES_COMPILED_RISCV_M 0
#endif
#if defined(__riscv_a)
#define CPU_FEATURES_COMPILED_RISCV_A 1
#else
#define CPU_FEATURES_COMPILED_RISCV_A 0
#endif
#if defined(__riscv_f)
#define CPU_FEATURES_COMPILED_RISCV_F 1
#else
#define CPU_FEATURES_COMPILED_RISCV_F 0
#endif
#if defined(__riscv_d)
#define CPU_FEATURES_COMPILED_RISCV_D 1
#else
#define CPU_FEATURES_COMPILED_RISCV_D 0
#endif
#if defined(__riscv_q)
#define CPU_FEATURES_COMPILED_RISCV_Q 1
#else
#define CPU_FEATURES_COMPILED_RISCV_Q 0
#endif
#if defined(__riscv_c)
#define CPU_FEATURES_COMPILED_RISCV_C 1
#else
#define CPU_FEATURES_COMPILED_RISCV_C 0
#endif
#if defined(__riscv_v)
#define CPU_FEATURES_COMPILED_RISCV_V 1
#else
#define CPU_FEATURES_COMPILED_RISCV_V 0
#endif
#if defined(__riscv_zba)
#define CPU_FEATURES_COMPILED_RISCV_ZBA 1
#else
#define CPU_FEATURES_COMPILED_RISCV_ZBA 0
#endif
#if defined(__riscv_zbb)
#define CPU_FEATURES_COMPILED_RISCV_ZBB 1
#else
#define CPU_FEATURES_COMPILED_RISCV_ZBB 0
#endif
#if defined(__riscv_zbc)
#define CPU_FEATURES_COMPILED_RISCV_ZBC 1
#else
#define CPU_FEATURES_COMPILED_RISCV_ZBC 0
#endif
#if defined(__riscv_zbs)
#define CPU_FEATURES_COMPILED_RISCV_ZBS 1
#else
#define CPU_FEATURES_COMPILED_RISCV_ZBS 0
#endif
#if defined(__riscv_zfh)
#define CPU_FEATURES_COMPILED_RISCV_ZFH 1
#else
#define CPU_FEATURES_COMPILED_RISCV_ZFH 0
#endif
#if defined(__riscv_zfhmin)
#define CPU_FEATURES_COMPILED_RISCV_ZFHMIN 1
#else
#define CPU_FEATURES_COMPILED_RISCV_ZFHMIN 0
#endif
#if defined(__riscv_zknd)
#define CPU_FEATURES_COMPILED_RISCV_ZKND 1
#else
#define CPU_FEATURES_COMPILED_RISCV_ZKND 0
#endif
#if defined(__riscv_zkne)
#define CPU_FEATURES_COMPILED_RISCV_ZKNE 1
#else
#define CPU_FEATURES_COMPILED_RISCV_ZKNE 0
#endif
#if defined(__riscv_zknh)
#define CPU_FEATURES_COMPILED_RISCV_ZKNH 1
#else
#define CPU_FEATURES_COMPILED_RISCV_ZKNH 0
#endif
#if defined(__riscv_zksed)
#define CPU_FEATURES_COMPILED_RISCV_ZKSED 1
#else
#define CPU_FEATURES_COMPILED_RISCV_ZKSED 0
#endif
#if defined(__riscv_zksh)
#define CPU_FEATURES_COMPILED_RISCV_ZKSH 1
#else
#define CPU_FEATURES_COMPILED_RISCV_ZKSH 0
#endif
#if defined(__riscv_zkr)
#define CPU_FEATURES_COMPILED_RISCV_ZKR 1
#else
#define CPU_FEATURES_COMPILED_RISCV_ZKR 0
#endif
#endif // defined(CPU_FEATURES_ARCH_RISCV)
////////////////////////////////////////////////////////////////////////////////
// Utils
////////////////////////////////////////////////////////////////////////////////
// Communicates to the compiler that the block is unreachable
#if defined(CPU_FEATURES_COMPILER_CLANG) || defined(CPU_FEATURES_COMPILER_GCC)
#define CPU_FEATURES_UNREACHABLE() __builtin_unreachable()
#elif defined(CPU_FEATURES_COMPILER_MSC)
#define CPU_FEATURES_UNREACHABLE() __assume(0)
#else
#define CPU_FEATURES_UNREACHABLE()
#endif
// Communicates to the compiler that the function is now deprecated
#if defined(CPU_FEATURES_COMPILER_CLANG) || defined(CPU_FEATURES_COMPILER_GCC)
#define CPU_FEATURES_DEPRECATED(message) __attribute__((deprecated(message)))
#elif defined(CPU_FEATURES_COMPILER_MSC)
#define CPU_FEATURES_DEPRECATED(message) __declspec(deprecated(message))
#else
#define CPU_FEATURES_DEPRECATED(message)
#endif
#endif // CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_
+301
View File
@@ -0,0 +1,301 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
////////////////////////////////////////////////////////////////////////////////
// A note on Windows AArch64 implementation
////////////////////////////////////////////////////////////////////////////////
// Getting cpu info via EL1 system registers is not possible, so we delegate it
// to the Windows API (i.e., IsProcessorFeaturePresent and GetNativeSystemInfo).
// The `implementer`, `variant` and `part` fields of the `Aarch64Info` struct
// are not used, so they are set to 0. To get `revision` we use
// `wProcessorRevision` from `SYSTEM_INFO`.
//
// Cryptographic Extension:
// -----------------------------------------------------------------------------
// According to documentation Arm Architecture Reference Manual for
// A-profile architecture. A2.3 The Armv8 Cryptographic Extension. The Armv8.0
// Cryptographic Extension provides instructions for the acceleration of
// encryption and decryption, and includes the following features: FEAT_AES,
// FEAT_PMULL, FEAT_SHA1, FEAT_SHA256.
// see: https://developer.arm.com/documentation/ddi0487/latest
//
// We use `PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE` to detect all Armv8.0 crypto
// features. This value reports all features or nothing, so even if you only
// have support FEAT_AES and FEAT_PMULL, it will still return false.
//
// From Armv8.2, an implementation of the Armv8.0 Cryptographic Extension can
// include either or both of:
//
// • The AES functionality, including support for multiplication of 64-bit
// polynomials. The ID_AA64ISAR0_EL1.AES field indicates whether this
// functionality is supported.
// • The SHA1 and SHA2-256 functionality. The ID_AA64ISAR0_EL1.{SHA2, SHA1}
// fields indicate whether this functionality is supported.
//
// ID_AA64ISAR0_EL1.AES, bits [7:4]:
// Indicates support for AES instructions in AArch64 state. Defined values are:
// - 0b0000 No AES instructions implemented.
// - 0b0001 AESE, AESD, AESMC, and AESIMC instructions implemented.
// - 0b0010 As for 0b0001, plus PMULL/PMULL2 instructions operating on 64-bit
// data quantities.
//
// FEAT_AES implements the functionality identified by the value 0b0001.
// FEAT_PMULL implements the functionality identified by the value 0b0010.
// From Armv8, the permitted values are 0b0000 and 0b0010.
//
// ID_AA64ISAR0_EL1.SHA1, bits [11:8]:
// Indicates support for SHA1 instructions in AArch64 state. Defined values are:
// - 0b0000 No SHA1 instructions implemented.
// - 0b0001 SHA1C, SHA1P, SHA1M, SHA1H, SHA1SU0, and SHA1SU1 instructions
// implemented.
//
// FEAT_SHA1 implements the functionality identified by the value 0b0001.
// From Armv8, the permitted values are 0b0000 and 0b0001.
// If the value of ID_AA64ISAR0_EL1.SHA2 is 0b0000, this field must have the
// value 0b0000.
//
// ID_AA64ISAR0_EL1.SHA2, bits [15:12]:
// Indicates support for SHA2 instructions in AArch64 state. Defined values are:
// - 0b0000 No SHA2 instructions implemented.
// - 0b0001 Implements instructions: SHA256H, SHA256H2, SHA256SU0, and
// SHA256SU1.
// - 0b0010 Implements instructions:
// • SHA256H, SHA256H2, SHA256SU0, and SHA256SU1.
// • SHA512H, SHA512H2, SHA512SU0, and SHA512SU1.
//
// FEAT_SHA256 implements the functionality identified by the value 0b0001.
// FEAT_SHA512 implements the functionality identified by the value 0b0010.
//
// In Armv8, the permitted values are 0b0000 and 0b0001.
// From Armv8.2, the permitted values are 0b0000, 0b0001, and 0b0010.
//
// If the value of ID_AA64ISAR0_EL1.SHA1 is 0b0000, this field must have the
// value 0b0000.
//
// If the value of this field is 0b0010, ID_AA64ISAR0_EL1.SHA3
// must have the value 0b0001.
//
// Other cryptographic features that we cannot detect such as sha512, sha3, sm3,
// sm4, sveaes, svepmull, svesha3, svesm4 we set to 0.
//
// FP/SIMD:
// -----------------------------------------------------------------------------
// FP/SIMD must be implemented on all Armv8.0 implementations, but
// implementations targeting specialized markets may support the following
// combinations:
//
// • No NEON or floating-point.
// • Full floating-point and SIMD support with exception trapping.
// • Full floating-point and SIMD support without exception trapping.
//
// ref:
// https://developer.arm.com/documentation/den0024/a/AArch64-Floating-point-and-NEON
//
// So, we use `PF_ARM_VFP_32_REGISTERS_AVAILABLE`,
// `PF_ARM_NEON_INSTRUCTIONS_AVAILABLE` to detect `asimd` and `fp`
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_
#define CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_
#include "cpu_features_cache_info.h"
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
typedef struct {
int fp : 1; // Floating-point.
int asimd : 1; // Advanced SIMD.
int evtstrm : 1; // Generic timer generated events.
int aes : 1; // Hardware-accelerated Advanced Encryption Standard.
int pmull : 1; // Polynomial multiply long.
int sha1 : 1; // Hardware-accelerated SHA1.
int sha2 : 1; // Hardware-accelerated SHA2-256.
int crc32 : 1; // Hardware-accelerated CRC-32.
int atomics : 1; // Armv8.1 atomic instructions.
int fphp : 1; // Half-precision floating point support.
int asimdhp : 1; // Advanced SIMD half-precision support.
int cpuid : 1; // Access to certain ID registers.
int asimdrdm : 1; // Rounding Double Multiply Accumulate/Subtract.
int jscvt : 1; // Support for JavaScript conversion.
int fcma : 1; // Floating point complex numbers.
int lrcpc : 1; // Support for weaker release consistency.
int dcpop : 1; // Data persistence writeback.
int sha3 : 1; // Hardware-accelerated SHA3.
int sm3 : 1; // Hardware-accelerated SM3.
int sm4 : 1; // Hardware-accelerated SM4.
int asimddp : 1; // Dot product instruction.
int sha512 : 1; // Hardware-accelerated SHA512.
int sve : 1; // Scalable Vector Extension.
int asimdfhm : 1; // Additional half-precision instructions.
int dit : 1; // Data independent timing.
int uscat : 1; // Unaligned atomics support.
int ilrcpc : 1; // Additional support for weaker release consistency.
int flagm : 1; // Flag manipulation instructions.
int ssbs : 1; // Speculative Store Bypass Safe PSTATE bit.
int sb : 1; // Speculation barrier.
int paca : 1; // Address authentication.
int pacg : 1; // Generic authentication.
int dcpodp : 1; // Data cache clean to point of persistence.
int sve2 : 1; // Scalable Vector Extension (version 2).
int sveaes : 1; // SVE AES instructions.
int svepmull : 1; // SVE polynomial multiply long instructions.
int svebitperm : 1; // SVE bit permute instructions.
int svesha3 : 1; // SVE SHA3 instructions.
int svesm4 : 1; // SVE SM4 instructions.
int flagm2 : 1; // Additional flag manipulation instructions.
int frint : 1; // Floating point to integer rounding.
int svei8mm : 1; // SVE Int8 matrix multiplication instructions.
int svef32mm : 1; // SVE FP32 matrix multiplication instruction.
int svef64mm : 1; // SVE FP64 matrix multiplication instructions.
int svebf16 : 1; // SVE BFloat16 instructions.
int i8mm : 1; // Int8 matrix multiplication instructions.
int bf16 : 1; // BFloat16 instructions.
int dgh : 1; // Data Gathering Hint instruction.
int rng : 1; // True random number generator support.
int bti : 1; // Branch target identification.
int mte : 1; // Memory tagging extension.
int ecv : 1; // Enhanced counter virtualization.
int afp : 1; // Alternate floating-point behaviour.
int rpres : 1; // 12-bit reciprocal (square root) estimate precision.
int mte3 : 1; // MTE asymmetric fault handling.
int sme : 1; // Scalable Matrix Extension.
int smei16i64 : 1; // 16-bit to 64-bit integer widening outer product.
int smef64f64 : 1; // FP64 to FP64 outer product.
int smei8i32 : 1; // 8-bit to 32-bit integer widening outer product.
int smef16f32 : 1; // FP16 to FP32 outer product.
int smeb16f32 : 1; // BFloat16 to FP32 outper product.
int smef32f32 : 1; // FP32 to FP32 outer product.
int smefa64 : 1; // Full A64 support for SME in streaming mode.
int wfxt : 1; // WFE and WFI with timeout.
int ebf16 : 1; // Extended BFloat16 instructions.
int sveebf16 : 1; // SVE BFloat16 instructions.
int cssc : 1; // Common short sequence compression instructions.
int rprfm : 1; // Range Prefetch Memory hint instruction.
int sve2p1 : 1; // Scalable Vector Extension (version 2.1).
int sme2 : 1; // Scalable Matrix Extension (version 2).
int sme2p1 : 1; // Scalable Matrix Extension (version 2.1).
int smei16i32 : 1; // 16-bit to 64-bit integer widening outer product.
int smebi32i32 : 1; // 1-bit binary to 32-bit integer outer product.
int smeb16b16 : 1; // SME2.1 BFloat16 instructions.
int smef16f16 : 1; // FP16 to FP16 outer product.
// Make sure to update Aarch64FeaturesEnum below if you add a field here.
} Aarch64Features;
typedef struct {
Aarch64Features features;
int implementer; // We set 0 for Windows.
int variant; // We set 0 for Windows.
int part; // We set 0 for Windows.
int revision; // We use GetNativeSystemInfo to get processor revision for
// Windows.
} Aarch64Info;
Aarch64Info GetAarch64Info(void);
////////////////////////////////////////////////////////////////////////////////
// Introspection functions
typedef enum {
AARCH64_FP,
AARCH64_ASIMD,
AARCH64_EVTSTRM,
AARCH64_AES,
AARCH64_PMULL,
AARCH64_SHA1,
AARCH64_SHA2,
AARCH64_CRC32,
AARCH64_ATOMICS,
AARCH64_FPHP,
AARCH64_ASIMDHP,
AARCH64_CPUID,
AARCH64_ASIMDRDM,
AARCH64_JSCVT,
AARCH64_FCMA,
AARCH64_LRCPC,
AARCH64_DCPOP,
AARCH64_SHA3,
AARCH64_SM3,
AARCH64_SM4,
AARCH64_ASIMDDP,
AARCH64_SHA512,
AARCH64_SVE,
AARCH64_ASIMDFHM,
AARCH64_DIT,
AARCH64_USCAT,
AARCH64_ILRCPC,
AARCH64_FLAGM,
AARCH64_SSBS,
AARCH64_SB,
AARCH64_PACA,
AARCH64_PACG,
AARCH64_DCPODP,
AARCH64_SVE2,
AARCH64_SVEAES,
AARCH64_SVEPMULL,
AARCH64_SVEBITPERM,
AARCH64_SVESHA3,
AARCH64_SVESM4,
AARCH64_FLAGM2,
AARCH64_FRINT,
AARCH64_SVEI8MM,
AARCH64_SVEF32MM,
AARCH64_SVEF64MM,
AARCH64_SVEBF16,
AARCH64_I8MM,
AARCH64_BF16,
AARCH64_DGH,
AARCH64_RNG,
AARCH64_BTI,
AARCH64_MTE,
AARCH64_ECV,
AARCH64_AFP,
AARCH64_RPRES,
AARCH64_MTE3,
AARCH64_SME,
AARCH64_SME_I16I64,
AARCH64_SME_F64F64,
AARCH64_SME_I8I32,
AARCH64_SME_F16F32,
AARCH64_SME_B16F32,
AARCH64_SME_F32F32,
AARCH64_SME_FA64,
AARCH64_WFXT,
AARCH64_EBF16,
AARCH64_SVE_EBF16,
AARCH64_CSSC,
AARCH64_RPRFM,
AARCH64_SVE2P1,
AARCH64_SME2,
AARCH64_SME2P1,
AARCH64_SME_I16I32,
AARCH64_SME_BI32I32,
AARCH64_SME_B16B16,
AARCH64_SME_F16F16,
AARCH64_LAST_,
} Aarch64FeaturesEnum;
int GetAarch64FeaturesEnumValue(const Aarch64Features* features,
Aarch64FeaturesEnum value);
const char* GetAarch64FeaturesEnumName(Aarch64FeaturesEnum);
CPU_FEATURES_END_CPP_NAMESPACE
#if !defined(CPU_FEATURES_ARCH_AARCH64)
#error "Including cpuinfo_aarch64.h from a non-aarch64 target."
#endif
#endif // CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_
+121
View File
@@ -0,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 <stdint.h> // 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_
+77
View File
@@ -0,0 +1,77 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_LOONGARCH_H_
#define CPU_FEATURES_INCLUDE_CPUINFO_LOONGARCH_H_
#include "cpu_features_cache_info.h"
#include "cpu_features_macros.h"
#if !defined(CPU_FEATURES_ARCH_LOONGARCH)
#error "Including cpuinfo_loongarch.h from a non-loongarch target."
#endif
CPU_FEATURES_START_CPP_NAMESPACE
typedef struct {
// Base
int CPUCFG : 1; // Instruction for Identify CPU Features
// Extension
int LAM : 1; // Extension for Atomic Memory Access Instructions
int UAL : 1; // Extension for Non-Aligned Memory Access
int FPU : 1; // Extension for Basic Floating-Point Instructions
int LSX : 1; // Extension for Loongson SIMD eXtension
int LASX : 1; // Extension for Loongson Advanced SIMD eXtension
int CRC32 : 1; // Extension for Cyclic Redundancy Check Instructions
int COMPLEX : 1; // Extension for Complex Vector Operation Instructions
int CRYPTO : 1; // Extension for Encryption And Decryption Vector Instructions
int LVZ : 1; // Extension for Virtualization
int LBT_X86 : 1; // Extension for X86 Binary Translation Extension
int LBT_ARM : 1; // Extension for ARM Binary Translation Extension
int LBT_MIPS : 1; // Extension for MIPS Binary Translation Extension
int PTW : 1; // Extension for Page Table Walker
} LoongArchFeatures;
typedef struct {
LoongArchFeatures features;
} LoongArchInfo;
typedef enum {
LOONGARCH_CPUCFG,
LOONGARCH_LAM,
LOONGARCH_UAL,
LOONGARCH_FPU,
LOONGARCH_LSX,
LOONGARCH_LASX,
LOONGARCH_CRC32,
LOONGARCH_COMPLEX,
LOONGARCH_CRYPTO,
LOONGARCH_LVZ,
LOONGARCH_LBT_X86,
LOONGARCH_LBT_ARM,
LOONGARCH_LBT_MIPS,
LOONGARCH_PTW,
LOONGARCH_LAST_,
} LoongArchFeaturesEnum;
LoongArchInfo GetLoongArchInfo(void);
int GetLoongArchFeaturesEnumValue(const LoongArchFeatures* features,
LoongArchFeaturesEnum value);
const char* GetLoongArchFeaturesEnumName(LoongArchFeaturesEnum);
CPU_FEATURES_END_CPP_NAMESPACE
#endif // CPU_FEATURES_INCLUDE_CPUINFO_LOONGARCH_H_
+74
View File
@@ -0,0 +1,74 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_
#define CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_
#include "cpu_features_cache_info.h"
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
typedef struct {
int msa : 1; // MIPS SIMD Architecture
// https://www.mips.com/products/architectures/ase/simd/
int eva : 1; // Enhanced Virtual Addressing
// https://www.mips.com/products/architectures/mips64/
int r6 : 1; // True if is release 6 of the processor.
int mips16 : 1; // Compressed instructions
int mdmx : 1; // MIPS Digital Media Extension
int mips3d : 1; // 3D graphics acceleration
// MIPS(r) Architecture for Programmers, Volume IV-c
int smart : 1; // Smart-card cryptography
// MIPS(r) Architecture for Programmers, Volume IV-d
int dsp : 1; // Digital Signal Processing
// MIPS(r) Architecture for Programmers, Volume IV-e
// https://www.mips.com/products/architectures/ase/dsp/
// Make sure to update MipsFeaturesEnum below if you add a field here.
} MipsFeatures;
typedef struct {
MipsFeatures features;
} MipsInfo;
MipsInfo GetMipsInfo(void);
////////////////////////////////////////////////////////////////////////////////
// Introspection functions
typedef enum {
MIPS_MSA,
MIPS_EVA,
MIPS_R6,
MIPS_MIPS16,
MIPS_MDMX,
MIPS_MIPS3D,
MIPS_SMART,
MIPS_DSP,
MIPS_LAST_,
} MipsFeaturesEnum;
int GetMipsFeaturesEnumValue(const MipsFeatures* features,
MipsFeaturesEnum value);
const char* GetMipsFeaturesEnumName(MipsFeaturesEnum);
CPU_FEATURES_END_CPP_NAMESPACE
#if !defined(CPU_FEATURES_ARCH_MIPS)
#error "Including cpuinfo_mips.h from a non-mips target."
#endif
#endif // CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_
+149
View File
@@ -0,0 +1,149 @@
// Copyright 2018 IBM
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_
#define CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_
#include "cpu_features_cache_info.h"
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
typedef struct {
int ppc32 : 1;
int ppc64 : 1;
int ppc601 : 1;
int altivec : 1;
int fpu : 1;
int mmu : 1;
int mac_4xx : 1;
int unifiedcache : 1;
int spe : 1;
int efpsingle : 1;
int efpdouble : 1;
int no_tb : 1;
int power4 : 1;
int power5 : 1;
int power5plus : 1;
int cell : 1;
int booke : 1;
int smt : 1;
int icachesnoop : 1;
int arch205 : 1;
int pa6t : 1;
int dfp : 1;
int power6ext : 1;
int arch206 : 1;
int vsx : 1;
int pseries_perfmon_compat : 1;
int truele : 1;
int ppcle : 1;
int arch207 : 1;
int htm : 1;
int dscr : 1;
int ebb : 1;
int isel : 1;
int tar : 1;
int vcrypto : 1;
int htm_nosc : 1;
int arch300 : 1;
int ieee128 : 1;
int darn : 1;
int scv : 1;
int htm_no_suspend : 1;
// Make sure to update PPCFeaturesEnum below if you add a field here.
} PPCFeatures;
typedef struct {
PPCFeatures features;
} PPCInfo;
PPCInfo GetPPCInfo(void);
typedef struct {
char platform[64]; // 0 terminated string
char base_platform[64]; // 0 terminated string
} PPCPlatformTypeStrings;
typedef struct {
char platform[64]; // 0 terminated string
char model[64]; // 0 terminated string
char machine[64]; // 0 terminated string
char cpu[64]; // 0 terminated string
PPCPlatformTypeStrings type;
} PPCPlatformStrings;
PPCPlatformStrings GetPPCPlatformStrings(void);
////////////////////////////////////////////////////////////////////////////////
// Introspection functions
typedef enum {
PPC_32, /* 32 bit mode execution */
PPC_64, /* 64 bit mode execution */
PPC_601_INSTR, /* Old POWER ISA */
PPC_HAS_ALTIVEC, /* SIMD Unit*/
PPC_HAS_FPU, /* Floating Point Unit */
PPC_HAS_MMU, /* Memory management unit */
PPC_HAS_4xxMAC,
PPC_UNIFIED_CACHE, /* Unified instruction and data cache */
PPC_HAS_SPE, /* Signal processing extention unit */
PPC_HAS_EFP_SINGLE, /* SPE single precision fpu */
PPC_HAS_EFP_DOUBLE, /* SPE double precision fpu */
PPC_NO_TB, /* No timebase */
PPC_POWER4,
PPC_POWER5,
PPC_POWER5_PLUS,
PPC_CELL, /* Cell broadband engine */
PPC_BOOKE, /* Embedded ISA */
PPC_SMT, /* Simultaneous multi-threading */
PPC_ICACHE_SNOOP,
PPC_ARCH_2_05, /* ISA 2.05 - POWER6 */
PPC_PA6T, /* PA Semi 6T core ISA */
PPC_HAS_DFP, /* Decimal floating point unit */
PPC_POWER6_EXT,
PPC_ARCH_2_06, /* ISA 2.06 - POWER7 */
PPC_HAS_VSX, /* Vector-scalar extension */
PPC_PSERIES_PERFMON_COMPAT, /* Set of backwards compatibile performance
monitoring events */
PPC_TRUE_LE,
PPC_PPC_LE,
PPC_ARCH_2_07, /* ISA 2.07 - POWER8 */
PPC_HTM, /* Hardware Transactional Memory */
PPC_DSCR, /* Data stream control register */
PPC_EBB, /* Event base branching */
PPC_ISEL, /* Integer select instructions */
PPC_TAR, /* Target address register */
PPC_VEC_CRYPTO, /* Vector cryptography instructions */
PPC_HTM_NOSC, /* Transactions aborted when syscall made*/
PPC_ARCH_3_00, /* ISA 3.00 - POWER9 */
PPC_HAS_IEEE128, /* VSX IEEE Binary Float 128-bit */
PPC_DARN, /* Deliver a random number instruction */
PPC_SCV, /* scv syscall */
PPC_HTM_NO_SUSPEND, /* TM w/out suspended state */
PPC_LAST_,
} PPCFeaturesEnum;
int GetPPCFeaturesEnumValue(const PPCFeatures* features, PPCFeaturesEnum value);
const char* GetPPCFeaturesEnumName(PPCFeaturesEnum);
CPU_FEATURES_END_CPP_NAMESPACE
#if !defined(CPU_FEATURES_ARCH_PPC)
#error "Including cpuinfo_ppc.h from a non-ppc target."
#endif
#endif // CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_
+72
View File
@@ -0,0 +1,72 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_RISCV_H_
#define CPU_FEATURES_INCLUDE_CPUINFO_RISCV_H_
#include "cpu_features_cache_info.h"
#include "cpu_features_macros.h"
#if !defined(CPU_FEATURES_ARCH_RISCV)
#error "Including cpuinfo_riscv.h from a non-riscv target."
#endif
CPU_FEATURES_START_CPP_NAMESPACE
typedef struct {
// Base
int RV32I : 1; // Base Integer Instruction Set, 32-bit
int RV64I : 1; // Base Integer Instruction Set, 64-bit
// Extension
int M : 1; // Standard Extension for Integer Multiplication/Division
int A : 1; // Standard Extension for Atomic Instructions
int F : 1; // Standard Extension for Single-Precision Floating-Point
int D : 1; // Standard Extension for Double-Precision Floating-Point
int Q : 1; // Standard Extension for Quad-Precision Floating-Point
int C : 1; // Standard Extension for Compressed Instructions
int V : 1; // Standard Extension for Vector Instructions
int Zicsr : 1; // Control and Status Register (CSR)
int Zifencei : 1; // Instruction-Fetch Fence
} RiscvFeatures;
typedef struct {
RiscvFeatures features;
char uarch[64]; // 0 terminated string
char vendor[64]; // 0 terminated string
} RiscvInfo;
typedef enum {
RISCV_RV32I,
RISCV_RV64I,
RISCV_M,
RISCV_A,
RISCV_F,
RISCV_D,
RISCV_Q,
RISCV_C,
RISCV_V,
RISCV_Zicsr,
RISCV_Zifencei,
RISCV_LAST_,
} RiscvFeaturesEnum;
RiscvInfo GetRiscvInfo(void);
int GetRiscvFeaturesEnumValue(const RiscvFeatures* features,
RiscvFeaturesEnum value);
const char* GetRiscvFeaturesEnumName(RiscvFeaturesEnum);
CPU_FEATURES_END_CPP_NAMESPACE
#endif // CPU_FEATURES_INCLUDE_CPUINFO_RISCV_H_
+108
View File
@@ -0,0 +1,108 @@
// Copyright 2022 IBM
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_S390X_H_
#define CPU_FEATURES_INCLUDE_CPUINFO_S390X_H_
#include "cpu_features_cache_info.h"
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
typedef struct {
int esan3: 1; // instructions named N3, "backported" to esa-mode
int zarch: 1; // z/Architecture mode active
int stfle: 1; // store-facility-list-extended
int msa: 1; // message-security assist
int ldisp: 1; // long-displacement
int eimm: 1; // extended-immediate
int dfp: 1; // decimal floating point & perform floating point operation
int edat: 1; // huge page support
int etf3eh: 1; // extended-translation facility 3 enhancement
int highgprs: 1; // 64-bit register support for 31-bit processes
int te: 1; // transactional execution
int vx: 1; // vector extension facility
int vxd: 1; // vector-packed-decimal facility
int vxe: 1; // vector-enhancement facility 1
int gs: 1; // guarded-storage facility
int vxe2: 1; // vector-enhancements facility 2
int vxp: 1; // vector-packed-decimal-enhancement facility
int sort: 1; // enhanced-sort facility
int dflt: 1; // deflate-conversion facility
int vxp2: 1; // vector-packed-decimal-enhancement facility 2
int nnpa: 1; // neural network processing assist facility
int pcimio: 1; // PCI mio facility
int sie: 1; // virtualization support
// Make sure to update S390XFeaturesEnum below if you add a field here.
} S390XFeatures;
typedef struct {
S390XFeatures features;
} S390XInfo;
S390XInfo GetS390XInfo(void);
typedef struct {
char platform[64]; // 0 terminated string
} S390XPlatformTypeStrings;
typedef struct {
int num_processors; // -1 if N/A
S390XPlatformTypeStrings type;
} S390XPlatformStrings;
S390XPlatformStrings GetS390XPlatformStrings(void);
////////////////////////////////////////////////////////////////////////////////
// Introspection functions
typedef enum {
S390_ESAN3,
S390_ZARCH,
S390_STFLE,
S390_MSA,
S390_LDISP,
S390_EIMM,
S390_DFP,
S390_EDAT,
S390_ETF3EH,
S390_HIGHGPRS,
S390_TE,
S390_VX,
S390_VXD,
S390_VXE,
S390_GS,
S390_VXE2,
S390_VXP,
S390_SORT,
S390_DFLT,
S390_VXP2,
S390_NNPA,
S390_PCIMIO,
S390_SIE,
S390X_LAST_,
} S390XFeaturesEnum;
int GetS390XFeaturesEnumValue(const S390XFeatures* features, S390XFeaturesEnum value);
const char* GetS390XFeaturesEnumName(S390XFeaturesEnum);
CPU_FEATURES_END_CPP_NAMESPACE
#if !defined(CPU_FEATURES_ARCH_S390X)
#error "Including cpuinfo_s390x.h from a non-s390x target."
#endif
#endif // CPU_FEATURES_INCLUDE_CPUINFO_S390X_H_
+295
View File
@@ -0,0 +1,295 @@
// Copyright 2017 Google LLC
// Copyright 2020 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_X86_H_
#define CPU_FEATURES_INCLUDE_CPUINFO_X86_H_
#include "cpu_features_cache_info.h"
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
// CPUID Vendors
#define CPU_FEATURES_VENDOR_GENUINE_INTEL "GenuineIntel"
#define CPU_FEATURES_VENDOR_AUTHENTIC_AMD "AuthenticAMD"
#define CPU_FEATURES_VENDOR_HYGON_GENUINE "HygonGenuine"
#define CPU_FEATURES_VENDOR_CENTAUR_HAULS "CentaurHauls"
#define CPU_FEATURES_VENDOR_SHANGHAI " Shanghai "
// See https://en.wikipedia.org/wiki/CPUID for a list of x86 cpu features.
// The field names are based on the short name provided in the wikipedia tables.
typedef struct {
int fpu : 1;
int tsc : 1;
int cx8 : 1;
int clfsh : 1;
int mmx : 1;
int aes : 1;
int erms : 1;
int f16c : 1;
int fma4 : 1;
int fma3 : 1;
int vaes : 1;
int vpclmulqdq : 1;
int bmi1 : 1;
int hle : 1;
int bmi2 : 1;
int rtm : 1;
int rdseed : 1;
int clflushopt : 1;
int clwb : 1;
int sse : 1;
int sse2 : 1;
int sse3 : 1;
int ssse3 : 1;
int sse4_1 : 1;
int sse4_2 : 1;
int sse4a : 1;
int avx : 1;
int avx_vnni : 1;
int avx2 : 1;
int avx512f : 1;
int avx512cd : 1;
int avx512er : 1;
int avx512pf : 1;
int avx512bw : 1;
int avx512dq : 1;
int avx512vl : 1;
int avx512ifma : 1;
int avx512vbmi : 1;
int avx512vbmi2 : 1;
int avx512vnni : 1;
int avx512bitalg : 1;
int avx512vpopcntdq : 1;
int avx512_4vnniw : 1;
int avx512_4vbmi2 : 1; // Note: this is an alias to avx512_4fmaps.
int avx512_second_fma : 1;
int avx512_4fmaps : 1;
int avx512_bf16 : 1;
int avx512_vp2intersect : 1;
int avx512_fp16 : 1;
int amx_bf16 : 1;
int amx_tile : 1;
int amx_int8 : 1;
int amx_fp16 : 1;
int pclmulqdq : 1;
int smx : 1;
int sgx : 1;
int cx16 : 1; // aka. CMPXCHG16B
int sha : 1;
int popcnt : 1;
int movbe : 1;
int rdrnd : 1;
int dca : 1;
int ss : 1;
int adx : 1;
int lzcnt : 1; // Note: this flag is called ABM for AMD, LZCNT for Intel.
int gfni : 1;
int movdiri : 1;
int movdir64b : 1;
int fs_rep_mov : 1; // Fast short REP MOV
int fz_rep_movsb : 1; // Fast zero-length REP MOVSB
int fs_rep_stosb : 1; // Fast short REP STOSB
int fs_rep_cmpsb_scasb : 1; // Fast short REP CMPSB/SCASB
int lam: 1; // Intel Linear Address Mask
int uai: 1; // AMD Upper Address Ignore
// Make sure to update X86FeaturesEnum below if you add a field here.
} X86Features;
typedef struct {
X86Features features;
int family;
int model;
int stepping;
char vendor[13]; // 0 terminated string
char brand_string[49]; // 0 terminated string
} X86Info;
// Calls cpuid and returns an initialized X86info.
X86Info GetX86Info(void);
// Returns cache hierarchy informations.
// Can call cpuid multiple times.
CacheInfo GetX86CacheInfo(void);
typedef enum {
X86_UNKNOWN,
ZHAOXIN_ZHANGJIANG, // ZhangJiang
ZHAOXIN_WUDAOKOU, // WuDaoKou
ZHAOXIN_LUJIAZUI, // LuJiaZui
ZHAOXIN_YONGFENG, // YongFeng
INTEL_80486, // 80486
INTEL_P5, // P5
INTEL_LAKEMONT, // LAKEMONT
INTEL_CORE, // CORE
INTEL_PNR, // PENRYN
INTEL_NHM, // NEHALEM
INTEL_ATOM_BNL, // BONNELL
INTEL_WSM, // WESTMERE
INTEL_SNB, // SANDYBRIDGE
INTEL_IVB, // IVYBRIDGE
INTEL_ATOM_SMT, // SILVERMONT
INTEL_HSW, // HASWELL
INTEL_BDW, // BROADWELL
INTEL_SKL, // SKYLAKE
INTEL_CCL, // CASCADELAKE
INTEL_ATOM_GMT, // GOLDMONT
INTEL_ATOM_GMT_PLUS, // GOLDMONT+
INTEL_ATOM_TMT, // TREMONT
INTEL_KBL, // KABY LAKE
INTEL_CFL, // COFFEE LAKE
INTEL_WHL, // WHISKEY LAKE
INTEL_CML, // COMET LAKE
INTEL_CNL, // CANNON LAKE
INTEL_ICL, // ICE LAKE
INTEL_TGL, // TIGER LAKE
INTEL_SPR, // SAPPHIRE RAPIDS
INTEL_ADL, // ALDER LAKE
INTEL_RCL, // ROCKET LAKE
INTEL_RPL, // RAPTOR LAKE
INTEL_KNIGHTS_M, // KNIGHTS MILL
INTEL_KNIGHTS_L, // KNIGHTS LANDING
INTEL_KNIGHTS_F, // KNIGHTS FERRY
INTEL_KNIGHTS_C, // KNIGHTS CORNER
INTEL_NETBURST, // NETBURST
AMD_HAMMER, // K8 HAMMER
AMD_K10, // K10
AMD_K11, // K11
AMD_K12, // K12 LLANO
AMD_BOBCAT, // K14 BOBCAT
AMD_PILEDRIVER, // K15 PILEDRIVER
AMD_STREAMROLLER, // K15 STREAMROLLER
AMD_EXCAVATOR, // K15 EXCAVATOR
AMD_BULLDOZER, // K15 BULLDOZER
AMD_JAGUAR, // K16 JAGUAR
AMD_PUMA, // K16 PUMA
AMD_ZEN, // K17 ZEN
AMD_ZEN_PLUS, // K17 ZEN+
AMD_ZEN2, // K17 ZEN 2
AMD_ZEN3, // K19 ZEN 3
AMD_ZEN4, // K19 ZEN 4
X86_MICROARCHITECTURE_LAST_,
} X86Microarchitecture;
// Returns the underlying microarchitecture by looking at X86Info's vendor,
// family and model.
X86Microarchitecture GetX86Microarchitecture(const X86Info* info);
// Calls cpuid and fills the brand_string.
// - brand_string *must* be of size 49 (beware of array decaying).
// - brand_string will be zero terminated.
CPU_FEATURES_DEPRECATED("brand_string is now embedded in X86Info by default")
void FillX86BrandString(char brand_string[49]);
////////////////////////////////////////////////////////////////////////////////
// Introspection functions
typedef enum {
X86_FPU,
X86_TSC,
X86_CX8,
X86_CLFSH,
X86_MMX,
X86_AES,
X86_ERMS,
X86_F16C,
X86_FMA4,
X86_FMA3,
X86_VAES,
X86_VPCLMULQDQ,
X86_BMI1,
X86_HLE,
X86_BMI2,
X86_RTM,
X86_RDSEED,
X86_CLFLUSHOPT,
X86_CLWB,
X86_SSE,
X86_SSE2,
X86_SSE3,
X86_SSSE3,
X86_SSE4_1,
X86_SSE4_2,
X86_SSE4A,
X86_AVX,
X86_AVX_VNNI,
X86_AVX2,
X86_AVX512F,
X86_AVX512CD,
X86_AVX512ER,
X86_AVX512PF,
X86_AVX512BW,
X86_AVX512DQ,
X86_AVX512VL,
X86_AVX512IFMA,
X86_AVX512VBMI,
X86_AVX512VBMI2,
X86_AVX512VNNI,
X86_AVX512BITALG,
X86_AVX512VPOPCNTDQ,
X86_AVX512_4VNNIW,
X86_AVX512_4VBMI2, // Note: this is an alias to X86_AVX512_4FMAPS.
X86_AVX512_SECOND_FMA,
X86_AVX512_4FMAPS,
X86_AVX512_BF16,
X86_AVX512_VP2INTERSECT,
X86_AVX512_FP16,
X86_AMX_BF16,
X86_AMX_TILE,
X86_AMX_INT8,
X86_AMX_FP16,
X86_PCLMULQDQ,
X86_SMX,
X86_SGX,
X86_CX16,
X86_SHA,
X86_POPCNT,
X86_MOVBE,
X86_RDRND,
X86_DCA,
X86_SS,
X86_ADX,
X86_LZCNT,
X86_GFNI,
X86_MOVDIRI,
X86_MOVDIR64B,
X86_FS_REP_MOV,
X86_FZ_REP_MOVSB,
X86_FS_REP_STOSB,
X86_FS_REP_CMPSB_SCASB,
X86_LAM,
X86_UAI,
X86_LAST_,
} X86FeaturesEnum;
int GetX86FeaturesEnumValue(const X86Features* features, X86FeaturesEnum value);
const char* GetX86FeaturesEnumName(X86FeaturesEnum);
const char* GetX86MicroarchitectureName(X86Microarchitecture);
CPU_FEATURES_END_CPP_NAMESPACE
#if !defined(CPU_FEATURES_ARCH_X86)
#error "Including cpuinfo_x86.h from a non-x86 target."
#endif
#endif // CPU_FEATURES_INCLUDE_CPUINFO_X86_H_
+40
View File
@@ -0,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 <assert.h>
#include <stdbool.h>
#include <stdint.h>
#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_
+37
View File
@@ -0,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 <stdint.h>
#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_
+39
View File
@@ -0,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 <stddef.h>
#include <stdint.h>
#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_
+277
View File
@@ -0,0 +1,277 @@
// 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 <stdbool.h>
#include <stdint.h>
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
// To avoid depending on the linux kernel we reproduce the architecture specific
// constants here.
// http://elixir.free-electrons.com/linux/latest/source/arch/arm64/include/uapi/asm/hwcap.h
#define AARCH64_HWCAP_FP (1UL << 0)
#define AARCH64_HWCAP_ASIMD (1UL << 1)
#define AARCH64_HWCAP_EVTSTRM (1UL << 2)
#define AARCH64_HWCAP_AES (1UL << 3)
#define AARCH64_HWCAP_PMULL (1UL << 4)
#define AARCH64_HWCAP_SHA1 (1UL << 5)
#define AARCH64_HWCAP_SHA2 (1UL << 6)
#define AARCH64_HWCAP_CRC32 (1UL << 7)
#define AARCH64_HWCAP_ATOMICS (1UL << 8)
#define AARCH64_HWCAP_FPHP (1UL << 9)
#define AARCH64_HWCAP_ASIMDHP (1UL << 10)
#define AARCH64_HWCAP_CPUID (1UL << 11)
#define AARCH64_HWCAP_ASIMDRDM (1UL << 12)
#define AARCH64_HWCAP_JSCVT (1UL << 13)
#define AARCH64_HWCAP_FCMA (1UL << 14)
#define AARCH64_HWCAP_LRCPC (1UL << 15)
#define AARCH64_HWCAP_DCPOP (1UL << 16)
#define AARCH64_HWCAP_SHA3 (1UL << 17)
#define AARCH64_HWCAP_SM3 (1UL << 18)
#define AARCH64_HWCAP_SM4 (1UL << 19)
#define AARCH64_HWCAP_ASIMDDP (1UL << 20)
#define AARCH64_HWCAP_SHA512 (1UL << 21)
#define AARCH64_HWCAP_SVE (1UL << 22)
#define AARCH64_HWCAP_ASIMDFHM (1UL << 23)
#define AARCH64_HWCAP_DIT (1UL << 24)
#define AARCH64_HWCAP_USCAT (1UL << 25)
#define AARCH64_HWCAP_ILRCPC (1UL << 26)
#define AARCH64_HWCAP_FLAGM (1UL << 27)
#define AARCH64_HWCAP_SSBS (1UL << 28)
#define AARCH64_HWCAP_SB (1UL << 29)
#define AARCH64_HWCAP_PACA (1UL << 30)
#define AARCH64_HWCAP_PACG (1UL << 31)
#define AARCH64_HWCAP2_DCPODP (1UL << 0)
#define AARCH64_HWCAP2_SVE2 (1UL << 1)
#define AARCH64_HWCAP2_SVEAES (1UL << 2)
#define AARCH64_HWCAP2_SVEPMULL (1UL << 3)
#define AARCH64_HWCAP2_SVEBITPERM (1UL << 4)
#define AARCH64_HWCAP2_SVESHA3 (1UL << 5)
#define AARCH64_HWCAP2_SVESM4 (1UL << 6)
#define AARCH64_HWCAP2_FLAGM2 (1UL << 7)
#define AARCH64_HWCAP2_FRINT (1UL << 8)
#define AARCH64_HWCAP2_SVEI8MM (1UL << 9)
#define AARCH64_HWCAP2_SVEF32MM (1UL << 10)
#define AARCH64_HWCAP2_SVEF64MM (1UL << 11)
#define AARCH64_HWCAP2_SVEBF16 (1UL << 12)
#define AARCH64_HWCAP2_I8MM (1UL << 13)
#define AARCH64_HWCAP2_BF16 (1UL << 14)
#define AARCH64_HWCAP2_DGH (1UL << 15)
#define AARCH64_HWCAP2_RNG (1UL << 16)
#define AARCH64_HWCAP2_BTI (1UL << 17)
#define AARCH64_HWCAP2_MTE (1UL << 18)
#define AARCH64_HWCAP2_ECV (1UL << 19)
#define AARCH64_HWCAP2_AFP (1UL << 20)
#define AARCH64_HWCAP2_RPRES (1UL << 21)
#define AARCH64_HWCAP2_MTE3 (1UL << 22)
#define AARCH64_HWCAP2_SME (1UL << 23)
#define AARCH64_HWCAP2_SME_I16I64 (1UL << 24)
#define AARCH64_HWCAP2_SME_F64F64 (1UL << 25)
#define AARCH64_HWCAP2_SME_I8I32 (1UL << 26)
#define AARCH64_HWCAP2_SME_F16F32 (1UL << 27)
#define AARCH64_HWCAP2_SME_B16F32 (1UL << 28)
#define AARCH64_HWCAP2_SME_F32F32 (1UL << 29)
#define AARCH64_HWCAP2_SME_FA64 (1UL << 30)
#define AARCH64_HWCAP2_WFXT (1UL << 31)
#define AARCH64_HWCAP2_EBF16 (1UL << 32)
#define AARCH64_HWCAP2_SVE_EBF16 (1UL << 33)
#define AARCH64_HWCAP2_CSSC (1UL << 34)
#define AARCH64_HWCAP2_RPRFM (1UL << 35)
#define AARCH64_HWCAP2_SVE2P1 (1UL << 36)
#define AARCH64_HWCAP2_SME2 (1UL << 37)
#define AARCH64_HWCAP2_SME2P1 (1UL << 38)
#define AARCH64_HWCAP2_SME_I16I32 (1UL << 39)
#define AARCH64_HWCAP2_SME_BI32I32 (1UL << 40)
#define AARCH64_HWCAP2_SME_B16B16 (1UL << 41)
#define AARCH64_HWCAP2_SME_F16F16 (1UL << 42)
// http://elixir.free-electrons.com/linux/latest/source/arch/arm/include/uapi/asm/hwcap.h
#define ARM_HWCAP_SWP (1UL << 0)
#define ARM_HWCAP_HALF (1UL << 1)
#define ARM_HWCAP_THUMB (1UL << 2)
#define ARM_HWCAP_26BIT (1UL << 3)
#define ARM_HWCAP_FAST_MULT (1UL << 4)
#define ARM_HWCAP_FPA (1UL << 5)
#define ARM_HWCAP_VFP (1UL << 6)
#define ARM_HWCAP_EDSP (1UL << 7)
#define ARM_HWCAP_JAVA (1UL << 8)
#define ARM_HWCAP_IWMMXT (1UL << 9)
#define ARM_HWCAP_CRUNCH (1UL << 10)
#define ARM_HWCAP_THUMBEE (1UL << 11)
#define ARM_HWCAP_NEON (1UL << 12)
#define ARM_HWCAP_VFPV3 (1UL << 13)
#define ARM_HWCAP_VFPV3D16 (1UL << 14)
#define ARM_HWCAP_TLS (1UL << 15)
#define ARM_HWCAP_VFPV4 (1UL << 16)
#define ARM_HWCAP_IDIVA (1UL << 17)
#define ARM_HWCAP_IDIVT (1UL << 18)
#define ARM_HWCAP_VFPD32 (1UL << 19)
#define ARM_HWCAP_LPAE (1UL << 20)
#define ARM_HWCAP_EVTSTRM (1UL << 21)
#define ARM_HWCAP2_AES (1UL << 0)
#define ARM_HWCAP2_PMULL (1UL << 1)
#define ARM_HWCAP2_SHA1 (1UL << 2)
#define ARM_HWCAP2_SHA2 (1UL << 3)
#define ARM_HWCAP2_CRC32 (1UL << 4)
// http://elixir.free-electrons.com/linux/latest/source/arch/mips/include/uapi/asm/hwcap.h
#define MIPS_HWCAP_R6 (1UL << 0)
#define MIPS_HWCAP_MSA (1UL << 1)
#define MIPS_HWCAP_CRC32 (1UL << 2)
#define MIPS_HWCAP_MIPS16 (1UL << 3)
#define MIPS_HWCAP_MDMX (1UL << 4)
#define MIPS_HWCAP_MIPS3D (1UL << 5)
#define MIPS_HWCAP_SMARTMIPS (1UL << 6)
#define MIPS_HWCAP_DSP (1UL << 7)
#define MIPS_HWCAP_DSP2 (1UL << 8)
#define MIPS_HWCAP_DSP3 (1UL << 9)
// http://elixir.free-electrons.com/linux/latest/source/arch/powerpc/include/uapi/asm/cputable.h
#ifndef _UAPI__ASM_POWERPC_CPUTABLE_H
/* in AT_HWCAP */
#define PPC_FEATURE_32 0x80000000
#define PPC_FEATURE_64 0x40000000
#define PPC_FEATURE_601_INSTR 0x20000000
#define PPC_FEATURE_HAS_ALTIVEC 0x10000000
#define PPC_FEATURE_HAS_FPU 0x08000000
#define PPC_FEATURE_HAS_MMU 0x04000000
#define PPC_FEATURE_HAS_4xxMAC 0x02000000
#define PPC_FEATURE_UNIFIED_CACHE 0x01000000
#define PPC_FEATURE_HAS_SPE 0x00800000
#define PPC_FEATURE_HAS_EFP_SINGLE 0x00400000
#define PPC_FEATURE_HAS_EFP_DOUBLE 0x00200000
#define PPC_FEATURE_NO_TB 0x00100000
#define PPC_FEATURE_POWER4 0x00080000
#define PPC_FEATURE_POWER5 0x00040000
#define PPC_FEATURE_POWER5_PLUS 0x00020000
#define PPC_FEATURE_CELL 0x00010000
#define PPC_FEATURE_BOOKE 0x00008000
#define PPC_FEATURE_SMT 0x00004000
#define PPC_FEATURE_ICACHE_SNOOP 0x00002000
#define PPC_FEATURE_ARCH_2_05 0x00001000
#define PPC_FEATURE_PA6T 0x00000800
#define PPC_FEATURE_HAS_DFP 0x00000400
#define PPC_FEATURE_POWER6_EXT 0x00000200
#define PPC_FEATURE_ARCH_2_06 0x00000100
#define PPC_FEATURE_HAS_VSX 0x00000080
#define PPC_FEATURE_PSERIES_PERFMON_COMPAT 0x00000040
/* Reserved - do not use 0x00000004 */
#define PPC_FEATURE_TRUE_LE 0x00000002
#define PPC_FEATURE_PPC_LE 0x00000001
/* in AT_HWCAP2 */
#define PPC_FEATURE2_ARCH_2_07 0x80000000
#define PPC_FEATURE2_HTM 0x40000000
#define PPC_FEATURE2_DSCR 0x20000000
#define PPC_FEATURE2_EBB 0x10000000
#define PPC_FEATURE2_ISEL 0x08000000
#define PPC_FEATURE2_TAR 0x04000000
#define PPC_FEATURE2_VEC_CRYPTO 0x02000000
#define PPC_FEATURE2_HTM_NOSC 0x01000000
#define PPC_FEATURE2_ARCH_3_00 0x00800000
#define PPC_FEATURE2_HAS_IEEE128 0x00400000
#define PPC_FEATURE2_DARN 0x00200000
#define PPC_FEATURE2_SCV 0x00100000
#define PPC_FEATURE2_HTM_NO_SUSPEND 0x00080000
#endif
// https://elixir.bootlin.com/linux/v6.0-rc6/source/arch/s390/include/asm/elf.h
#define HWCAP_S390_ESAN3 1
#define HWCAP_S390_ZARCH 2
#define HWCAP_S390_STFLE 4
#define HWCAP_S390_MSA 8
#define HWCAP_S390_LDISP 16
#define HWCAP_S390_EIMM 32
#define HWCAP_S390_DFP 64
#define HWCAP_S390_HPAGE 128
#define HWCAP_S390_ETF3EH 256
#define HWCAP_S390_HIGH_GPRS 512
#define HWCAP_S390_TE 1024
#define HWCAP_S390_VX 2048
#define HWCAP_S390_VXRS HWCAP_S390_VX
#define HWCAP_S390_VXD 4096
#define HWCAP_S390_VXRS_BCD HWCAP_S390_VXD
#define HWCAP_S390_VXE 8192
#define HWCAP_S390_VXRS_EXT HWCAP_S390_VXE
#define HWCAP_S390_GS 16384
#define HWCAP_S390_VXRS_EXT2 32768
#define HWCAP_S390_VXRS_PDE 65536
#define HWCAP_S390_SORT 131072
#define HWCAP_S390_DFLT 262144
#define HWCAP_S390_VXRS_PDE2 524288
#define HWCAP_S390_NNPA 1048576
#define HWCAP_S390_PCI_MIO 2097152
#define HWCAP_S390_SIE 4194304
// https://elixir.bootlin.com/linux/latest/source/arch/riscv/include/uapi/asm/hwcap.h
#define RISCV_HWCAP_32 0x32
#define RISCV_HWCAP_64 0x64
#define RISCV_HWCAP_128 0x128
#define RISCV_HWCAP_M (1UL << ('M' - 'A'))
#define RISCV_HWCAP_A (1UL << ('A' - 'A'))
#define RISCV_HWCAP_F (1UL << ('F' - 'A'))
#define RISCV_HWCAP_D (1UL << ('D' - 'A'))
#define RISCV_HWCAP_Q (1UL << ('Q' - 'A'))
#define RISCV_HWCAP_C (1UL << ('C' - 'A'))
#define RISCV_HWCAP_V (1UL << ('V' - 'A'))
// https://github.com/torvalds/linux/blob/master/arch/loongarch/include/uapi/asm/hwcap.h
#define HWCAP_LOONGARCH_CPUCFG (1 << 0)
#define HWCAP_LOONGARCH_LAM (1 << 1)
#define HWCAP_LOONGARCH_UAL (1 << 2)
#define HWCAP_LOONGARCH_FPU (1 << 3)
#define HWCAP_LOONGARCH_LSX (1 << 4)
#define HWCAP_LOONGARCH_LASX (1 << 5)
#define HWCAP_LOONGARCH_CRC32 (1 << 6)
#define HWCAP_LOONGARCH_COMPLEX (1 << 7)
#define HWCAP_LOONGARCH_CRYPTO (1 << 8)
#define HWCAP_LOONGARCH_LVZ (1 << 9)
#define HWCAP_LOONGARCH_LBT_X86 (1 << 10)
#define HWCAP_LOONGARCH_LBT_ARM (1 << 11)
#define HWCAP_LOONGARCH_LBT_MIPS (1 << 12)
#define HWCAP_LOONGARCH_PTW (1 << 13)
typedef struct {
unsigned long hwcaps;
unsigned long hwcaps2;
} HardwareCapabilities;
// Retrieves values from auxiliary vector for types AT_HWCAP and AT_HWCAP2.
// First tries to call getauxval(), if not available falls back to reading
// "/proc/self/auxv".
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void);
// Checks whether value for AT_HWCAP (or AT_HWCAP2) match hwcaps_mask.
bool CpuFeatures_IsHwCapsSet(const HardwareCapabilities hwcaps_mask,
const HardwareCapabilities hwcaps);
// Get pointer for the AT_PLATFORM type.
const char* CpuFeatures_GetPlatformPointer(void);
// Get pointer for the AT_BASE_PLATFORM type.
const char* CpuFeatures_GetBasePlatformPointer(void);
CPU_FEATURES_END_CPP_NAMESPACE
#endif // CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_
@@ -0,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 <stdbool.h>
#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_
+110
View File
@@ -0,0 +1,110 @@
// 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 <stdbool.h>
#include <stddef.h>
#include <string.h>
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
typedef struct {
const char* ptr;
size_t size;
} StringView;
#ifdef __cplusplus
static const StringView kEmptyStringView = {NULL, 0};
#else
static const StringView kEmptyStringView;
#endif
// Returns a StringView from the provided string.
// Passing NULL is valid only if size is 0.
static inline StringView view(const char* str, const size_t size) {
StringView view;
view.ptr = str;
view.size = size;
return view;
}
static inline StringView str(const char* str) { return view(str, strlen(str)); }
// Returns the index of the first occurrence of c in view or -1 if not found.
int CpuFeatures_StringView_IndexOfChar(const StringView view, char c);
// Returns the index of the first occurrence of sub_view in view or -1 if not
// found.
int CpuFeatures_StringView_IndexOf(const StringView view,
const StringView sub_view);
// Returns whether a is equal to b (same content).
bool CpuFeatures_StringView_IsEquals(const StringView a, const StringView b);
// Returns whether a starts with b.
bool CpuFeatures_StringView_StartsWith(const StringView a, const StringView b);
// Removes count characters from the beginning of view or kEmptyStringView if
// count if greater than view.size.
StringView CpuFeatures_StringView_PopFront(const StringView str_view,
size_t count);
// Removes count characters from the end of view or kEmptyStringView if count if
// greater than view.size.
StringView CpuFeatures_StringView_PopBack(const StringView str_view,
size_t count);
// Keeps the count first characters of view or view if count if greater than
// view.size.
StringView CpuFeatures_StringView_KeepFront(const StringView str_view,
size_t count);
// Retrieves the first character of view. If view is empty the behavior is
// undefined.
char CpuFeatures_StringView_Front(const StringView view);
// Retrieves the last character of view. If view is empty the behavior is
// undefined.
char CpuFeatures_StringView_Back(const StringView view);
// Removes leading and tailing space characters.
StringView CpuFeatures_StringView_TrimWhitespace(StringView view);
// Convert StringView to positive integer. e.g. "42", "0x2a".
// Returns -1 on error.
int CpuFeatures_StringView_ParsePositiveNumber(const StringView view);
// Copies src StringView to dst buffer.
void CpuFeatures_StringView_CopyString(const StringView src, char* dst,
size_t dst_size);
// Checks if line contains the specified whitespace separated word.
bool CpuFeatures_StringView_HasWord(const StringView line,
const char* const word,
const char separator);
// Get key/value from line. key and value are separated by ": ".
// key and value are cleaned up from leading and trailing whitespaces.
bool CpuFeatures_StringView_GetAttributeKeyValue(const StringView line,
StringView* key,
StringView* value);
CPU_FEATURES_END_CPP_NAMESPACE
#endif // CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_
+70
View File
@@ -0,0 +1,70 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_WINDOWS_UTILS_H_
#define CPU_FEATURES_INCLUDE_INTERNAL_WINDOWS_UTILS_H_
#include "cpu_features_macros.h"
#ifdef CPU_FEATURES_OS_WINDOWS
#include <windows.h> // IsProcessorFeaturePresent
// modern WinSDK winnt.h contains newer features detection definitions
#if !defined(PF_SSSE3_INSTRUCTIONS_AVAILABLE)
#define PF_SSSE3_INSTRUCTIONS_AVAILABLE 36
#endif
#if !defined(PF_SSE4_1_INSTRUCTIONS_AVAILABLE)
#define PF_SSE4_1_INSTRUCTIONS_AVAILABLE 37
#endif
#if !defined(PF_SSE4_2_INSTRUCTIONS_AVAILABLE)
#define PF_SSE4_2_INSTRUCTIONS_AVAILABLE 38
#endif
#if !defined(PF_ARM_VFP_32_REGISTERS_AVAILABLE)
#define PF_ARM_VFP_32_REGISTERS_AVAILABLE 18
#endif
#if !defined(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE)
#define PF_ARM_NEON_INSTRUCTIONS_AVAILABLE 19
#endif
#if !defined(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE)
#define PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE 30
#endif
#if !defined(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE)
#define PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE 31
#endif
#if !defined(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE)
#define PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE 34
#endif
#if !defined(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE)
#define PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE 43
#endif
#if !defined(PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE)
#define PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE 44
#endif
#if !defined(PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE)
#define PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE 45
#endif
#endif // CPU_FEATURES_OS_WINDOWS
#endif // CPU_FEATURES_INCLUDE_INTERNAL_WINDOWS_UTILS_H_
+19
View File
@@ -0,0 +1,19 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stddef.h>
static void copy(char *__restrict dst, const char *src, size_t count) {
for (size_t i = 0; i < count; ++i) dst[i] = src[i];
}
+86
View File
@@ -0,0 +1,86 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef INTROSPECTION_PREFIX
#error "missing INTROSPECTION_PREFIX"
#endif
#ifndef INTROSPECTION_ENUM_PREFIX
#error "missing INTROSPECTION_ENUM_PREFIX"
#endif
#ifndef INTROSPECTION_TABLE
#error "missing INTROSPECTION_TABLE"
#endif
#include <stdbool.h>
#define STRINGIZE_(s) #s
#define STRINGIZE(s) STRINGIZE_(s)
#define FEAT_TYPE_NAME__(X) X##Features
#define FEAT_TYPE_NAME_(X) FEAT_TYPE_NAME__(X)
#define FEAT_TYPE_NAME FEAT_TYPE_NAME_(INTROSPECTION_PREFIX)
#define FEAT_ENUM_NAME__(X) X##FeaturesEnum
#define FEAT_ENUM_NAME_(X) FEAT_ENUM_NAME__(X)
#define FEAT_ENUM_NAME FEAT_ENUM_NAME_(INTROSPECTION_PREFIX)
#define GET_FEAT_ENUM_VALUE__(X) Get##X##FeaturesEnumValue
#define GET_FEAT_ENUM_VALUE_(X) GET_FEAT_ENUM_VALUE__(X)
#define GET_FEAT_ENUM_VALUE GET_FEAT_ENUM_VALUE_(INTROSPECTION_PREFIX)
#define GET_FEAT_ENUM_NAME__(X) Get##X##FeaturesEnumName
#define GET_FEAT_ENUM_NAME_(X) GET_FEAT_ENUM_NAME__(X)
#define GET_FEAT_ENUM_NAME GET_FEAT_ENUM_NAME_(INTROSPECTION_PREFIX)
#define FEAT_ENUM_LAST__(X) X##_LAST_
#define FEAT_ENUM_LAST_(X) FEAT_ENUM_LAST__(X)
#define FEAT_ENUM_LAST FEAT_ENUM_LAST_(INTROSPECTION_ENUM_PREFIX)
// Generate individual getters and setters.
#define LINE(ENUM, NAME, A, B, C) \
static void set_##ENUM(FEAT_TYPE_NAME* features, bool value) { \
features->NAME = value; \
} \
static int get_##ENUM(const FEAT_TYPE_NAME* features) { \
return features->NAME; \
}
INTROSPECTION_TABLE
#undef LINE
// Generate getters table
#define LINE(ENUM, NAME, A, B, C) [ENUM] = get_##ENUM,
static int (*const kGetters[])(const FEAT_TYPE_NAME*) = {INTROSPECTION_TABLE};
#undef LINE
// Generate setters table
#define LINE(ENUM, NAME, A, B, C) [ENUM] = set_##ENUM,
static void (*const kSetters[])(FEAT_TYPE_NAME*, bool) = {INTROSPECTION_TABLE};
#undef LINE
// Implements the `GetXXXFeaturesEnumValue` API.
int GET_FEAT_ENUM_VALUE(const FEAT_TYPE_NAME* features, FEAT_ENUM_NAME value) {
if (value >= FEAT_ENUM_LAST) return false;
return kGetters[value](features);
}
// Generate feature name table.
#define LINE(ENUM, NAME, A, B, C) [ENUM] = STRINGIZE(NAME),
static const char* kFeatureNames[] = {INTROSPECTION_TABLE};
#undef LINE
// Implements the `GetXXXFeaturesEnumName` API.
const char* GET_FEAT_ENUM_NAME(FEAT_ENUM_NAME value) {
if (value >= FEAT_ENUM_LAST) return "unknown_feature";
return kFeatureNames[value];
}
@@ -0,0 +1,26 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "define_introspection.inl"
#include "internal/hwcaps.h"
#define LINE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) \
[ENUM] = (HardwareCapabilities){HWCAP, HWCAP2},
static const HardwareCapabilities kHardwareCapabilities[] = {
INTROSPECTION_TABLE};
#undef LINE
#define LINE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) [ENUM] = CPUINFO_FLAG,
static const char* kCpuInfoFlags[] = {INTROSPECTION_TABLE};
#undef LINE
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdbool.h>
#include <stddef.h>
static bool equals(const char *lhs, const char *rhs, size_t count) {
for (size_t i = 0; i < count; ++i)
if (lhs[i] != rhs[i]) return false;
return true;
}
+62
View File
@@ -0,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 <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#if defined(CPU_FEATURES_MOCK_FILESYSTEM)
// Implementation will be provided by test/filesystem_for_testing.cc.
#elif defined(_MSC_VER)
#include <io.h>
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 <unistd.h>
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
+169
View File
@@ -0,0 +1,169 @@
// 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 <stdlib.h>
#include <string.h>
#include "cpu_features_macros.h"
#include "internal/filesystem.h"
#include "internal/string_view.h"
static bool IsSet(const uint32_t mask, const uint32_t value) {
if (mask == 0) return false;
return (value & mask) == mask;
}
bool CpuFeatures_IsHwCapsSet(const HardwareCapabilities hwcaps_mask,
const HardwareCapabilities hwcaps) {
return IsSet(hwcaps_mask.hwcaps, hwcaps.hwcaps) ||
IsSet(hwcaps_mask.hwcaps2, hwcaps.hwcaps2);
}
#ifdef CPU_FEATURES_TEST
// In test mode, hwcaps_for_testing will define the following functions.
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void);
const char* CpuFeatures_GetPlatformPointer(void);
const char* CpuFeatures_GetBasePlatformPointer(void);
#else
// Debug facilities
#if defined(NDEBUG)
#define D(...)
#else
#include <stdio.h>
#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 <sys/auxv.h>
static unsigned long GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
return getauxval(hwcap_type);
}
#elif defined(HAVE_DLFCN_H)
// On Android we probe the system's C library for a 'getauxval' function and
// call it if it exits, or return 0 for failure. This function is available
// since API level 18.
//
// Note that getauxval() can't really be re-implemented here, because its
// implementation does not parse /proc/self/auxv. Instead it depends on values
// that are passed by the kernel at process-init time to the C runtime
// initialization layer.
#include <dlfcn.h>
typedef unsigned long getauxval_func_t(unsigned long);
static uint32_t GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
uint32_t ret = 0;
void *libc_handle = NULL;
getauxval_func_t *func = NULL;
dlerror(); // Cleaning error state before calling dlopen.
libc_handle = dlopen("libc.so", RTLD_NOW);
if (!libc_handle) {
D("Could not dlopen() C library: %s\n", dlerror());
return 0;
}
func = (getauxval_func_t *)dlsym(libc_handle, "getauxval");
if (!func) {
D("Could not find getauxval() in C library\n");
} else {
// Note: getauxval() returns 0 on failure. Doesn't touch errno.
ret = (uint32_t)(*func)(hwcap_type);
}
dlclose(libc_handle);
return ret;
}
#else
#error "This platform does not provide hardware capabilities."
#endif
// Implementation of GetHardwareCapabilities for OS that provide
// GetElfHwcapFromGetauxval().
// Fallback when getauxval is not available, retrieves hwcaps from
// "/proc/self/auxv".
static uint32_t GetElfHwcapFromProcSelfAuxv(uint32_t hwcap_type) {
struct {
uint32_t tag;
uint32_t value;
} entry;
uint32_t result = 0;
const char filepath[] = "/proc/self/auxv";
const int fd = CpuFeatures_OpenFile(filepath);
if (fd < 0) {
D("Could not open %s\n", filepath);
return 0;
}
for (;;) {
const int ret = CpuFeatures_ReadFile(fd, (char *)&entry, sizeof entry);
if (ret < 0) {
D("Error while reading %s\n", filepath);
break;
}
// Detect end of list.
if (ret == 0 || (entry.tag == 0 && entry.value == 0)) {
break;
}
if (entry.tag == hwcap_type) {
result = entry.value;
break;
}
}
CpuFeatures_CloseFile(fd);
return result;
}
// Retrieves hardware capabilities by first trying to call getauxval, if not
// available falls back to reading "/proc/self/auxv".
static unsigned long GetHardwareCapabilitiesFor(uint32_t type) {
unsigned long hwcaps = GetElfHwcapFromGetauxval(type);
if (!hwcaps) {
D("Parsing /proc/self/auxv to extract ELF hwcaps!\n");
hwcaps = GetElfHwcapFromProcSelfAuxv(type);
}
return hwcaps;
}
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void) {
HardwareCapabilities capabilities;
capabilities.hwcaps = GetHardwareCapabilitiesFor(AT_HWCAP);
capabilities.hwcaps2 = GetHardwareCapabilitiesFor(AT_HWCAP2);
return capabilities;
}
const char *CpuFeatures_GetPlatformPointer(void) {
return (const char *)GetHardwareCapabilitiesFor(AT_PLATFORM);
}
const char *CpuFeatures_GetBasePlatformPointer(void) {
return (const char *)GetHardwareCapabilitiesFor(AT_BASE_PLATFORM);
}
#endif // CPU_FEATURES_TEST
@@ -0,0 +1,118 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdbool.h>
#include "cpu_features_macros.h"
#include "cpuinfo_aarch64.h"
#include "internal/bit_utils.h"
#include "internal/filesystem.h"
#include "internal/stack_line_reader.h"
#include "internal/string_view.h"
#if !defined(CPU_FEATURES_ARCH_AARCH64)
#error "Cannot compile aarch64_base on a non aarch64 platform."
#endif
////////////////////////////////////////////////////////////////////////////////
// Definitions for introspection.
////////////////////////////////////////////////////////////////////////////////
#define INTROSPECTION_TABLE \
LINE(AARCH64_FP, fp, "fp", AARCH64_HWCAP_FP, 0) \
LINE(AARCH64_ASIMD, asimd, "asimd", AARCH64_HWCAP_ASIMD, 0) \
LINE(AARCH64_EVTSTRM, evtstrm, "evtstrm", AARCH64_HWCAP_EVTSTRM, 0) \
LINE(AARCH64_AES, aes, "aes", AARCH64_HWCAP_AES, 0) \
LINE(AARCH64_PMULL, pmull, "pmull", AARCH64_HWCAP_PMULL, 0) \
LINE(AARCH64_SHA1, sha1, "sha1", AARCH64_HWCAP_SHA1, 0) \
LINE(AARCH64_SHA2, sha2, "sha2", AARCH64_HWCAP_SHA2, 0) \
LINE(AARCH64_CRC32, crc32, "crc32", AARCH64_HWCAP_CRC32, 0) \
LINE(AARCH64_ATOMICS, atomics, "atomics", AARCH64_HWCAP_ATOMICS, 0) \
LINE(AARCH64_FPHP, fphp, "fphp", AARCH64_HWCAP_FPHP, 0) \
LINE(AARCH64_ASIMDHP, asimdhp, "asimdhp", AARCH64_HWCAP_ASIMDHP, 0) \
LINE(AARCH64_CPUID, cpuid, "cpuid", AARCH64_HWCAP_CPUID, 0) \
LINE(AARCH64_ASIMDRDM, asimdrdm, "asimdrdm", AARCH64_HWCAP_ASIMDRDM, 0) \
LINE(AARCH64_JSCVT, jscvt, "jscvt", AARCH64_HWCAP_JSCVT, 0) \
LINE(AARCH64_FCMA, fcma, "fcma", AARCH64_HWCAP_FCMA, 0) \
LINE(AARCH64_LRCPC, lrcpc, "lrcpc", AARCH64_HWCAP_LRCPC, 0) \
LINE(AARCH64_DCPOP, dcpop, "dcpop", AARCH64_HWCAP_DCPOP, 0) \
LINE(AARCH64_SHA3, sha3, "sha3", AARCH64_HWCAP_SHA3, 0) \
LINE(AARCH64_SM3, sm3, "sm3", AARCH64_HWCAP_SM3, 0) \
LINE(AARCH64_SM4, sm4, "sm4", AARCH64_HWCAP_SM4, 0) \
LINE(AARCH64_ASIMDDP, asimddp, "asimddp", AARCH64_HWCAP_ASIMDDP, 0) \
LINE(AARCH64_SHA512, sha512, "sha512", AARCH64_HWCAP_SHA512, 0) \
LINE(AARCH64_SVE, sve, "sve", AARCH64_HWCAP_SVE, 0) \
LINE(AARCH64_ASIMDFHM, asimdfhm, "asimdfhm", AARCH64_HWCAP_ASIMDFHM, 0) \
LINE(AARCH64_DIT, dit, "dit", AARCH64_HWCAP_DIT, 0) \
LINE(AARCH64_USCAT, uscat, "uscat", AARCH64_HWCAP_USCAT, 0) \
LINE(AARCH64_ILRCPC, ilrcpc, "ilrcpc", AARCH64_HWCAP_ILRCPC, 0) \
LINE(AARCH64_FLAGM, flagm, "flagm", AARCH64_HWCAP_FLAGM, 0) \
LINE(AARCH64_SSBS, ssbs, "ssbs", AARCH64_HWCAP_SSBS, 0) \
LINE(AARCH64_SB, sb, "sb", AARCH64_HWCAP_SB, 0) \
LINE(AARCH64_PACA, paca, "paca", AARCH64_HWCAP_PACA, 0) \
LINE(AARCH64_PACG, pacg, "pacg", AARCH64_HWCAP_PACG, 0) \
LINE(AARCH64_DCPODP, dcpodp, "dcpodp", 0, AARCH64_HWCAP2_DCPODP) \
LINE(AARCH64_SVE2, sve2, "sve2", 0, AARCH64_HWCAP2_SVE2) \
LINE(AARCH64_SVEAES, sveaes, "sveaes", 0, AARCH64_HWCAP2_SVEAES) \
LINE(AARCH64_SVEPMULL, svepmull, "svepmull", 0, AARCH64_HWCAP2_SVEPMULL) \
LINE(AARCH64_SVEBITPERM, svebitperm, "svebitperm", 0, \
AARCH64_HWCAP2_SVEBITPERM) \
LINE(AARCH64_SVESHA3, svesha3, "svesha3", 0, AARCH64_HWCAP2_SVESHA3) \
LINE(AARCH64_SVESM4, svesm4, "svesm4", 0, AARCH64_HWCAP2_SVESM4) \
LINE(AARCH64_FLAGM2, flagm2, "flagm2", 0, AARCH64_HWCAP2_FLAGM2) \
LINE(AARCH64_FRINT, frint, "frint", 0, AARCH64_HWCAP2_FRINT) \
LINE(AARCH64_SVEI8MM, svei8mm, "svei8mm", 0, AARCH64_HWCAP2_SVEI8MM) \
LINE(AARCH64_SVEF32MM, svef32mm, "svef32mm", 0, AARCH64_HWCAP2_SVEF32MM) \
LINE(AARCH64_SVEF64MM, svef64mm, "svef64mm", 0, AARCH64_HWCAP2_SVEF64MM) \
LINE(AARCH64_SVEBF16, svebf16, "svebf16", 0, AARCH64_HWCAP2_SVEBF16) \
LINE(AARCH64_I8MM, i8mm, "i8mm", 0, AARCH64_HWCAP2_I8MM) \
LINE(AARCH64_BF16, bf16, "bf16", 0, AARCH64_HWCAP2_BF16) \
LINE(AARCH64_DGH, dgh, "dgh", 0, AARCH64_HWCAP2_DGH) \
LINE(AARCH64_RNG, rng, "rng", 0, AARCH64_HWCAP2_RNG) \
LINE(AARCH64_BTI, bti, "bti", 0, AARCH64_HWCAP2_BTI) \
LINE(AARCH64_MTE, mte, "mte", 0, AARCH64_HWCAP2_MTE) \
LINE(AARCH64_ECV, ecv, "ecv", 0, AARCH64_HWCAP2_ECV) \
LINE(AARCH64_AFP, afp, "afp", 0, AARCH64_HWCAP2_AFP) \
LINE(AARCH64_RPRES, rpres, "rpres", 0, AARCH64_HWCAP2_RPRES) \
LINE(AARCH64_MTE3, mte3, "mte3", 0, AARCH64_HWCAP2_MTE3) \
LINE(AARCH64_SME, sme, "sme", 0, AARCH64_HWCAP2_SME) \
LINE(AARCH64_SME_I16I64, smei16i64, "smei16i64", 0, \
AARCH64_HWCAP2_SME_I16I64) \
LINE(AARCH64_SME_F64F64, smef64f64, "smef64f64", 0, \
AARCH64_HWCAP2_SME_F64F64) \
LINE(AARCH64_SME_I8I32, smei8i32, "smei8i32", 0, AARCH64_HWCAP2_SME_I8I32) \
LINE(AARCH64_SME_F16F32, smef16f32, "smef16f32", 0, \
AARCH64_HWCAP2_SME_F16F32) \
LINE(AARCH64_SME_B16F32, smeb16f32, "smeb16f32", 0, \
AARCH64_HWCAP2_SME_B16F32) \
LINE(AARCH64_SME_F32F32, smef32f32, "smef32f32", 0, \
AARCH64_HWCAP2_SME_F32F32) \
LINE(AARCH64_SME_FA64, smefa64, "smefa64", 0, AARCH64_HWCAP2_SME_FA64) \
LINE(AARCH64_WFXT, wfxt, "wfxt", 0, AARCH64_HWCAP2_WFXT) \
LINE(AARCH64_EBF16, ebf16, "ebf16", 0, AARCH64_HWCAP2_EBF16) \
LINE(AARCH64_SVE_EBF16, sveebf16, "sveebf16", 0, AARCH64_HWCAP2_SVE_EBF16) \
LINE(AARCH64_CSSC, cssc, "cssc", 0, AARCH64_HWCAP2_CSSC) \
LINE(AARCH64_RPRFM, rprfm, "rprfm", 0, AARCH64_HWCAP2_RPRFM) \
LINE(AARCH64_SVE2P1, sve2p1, "sve2p1", 0, AARCH64_HWCAP2_SVE2P1) \
LINE(AARCH64_SME2, sme2, "sme2", 0, AARCH64_HWCAP2_SME2) \
LINE(AARCH64_SME2P1, sme2p1, "sme2p1", 0, AARCH64_HWCAP2_SME2P1) \
LINE(AARCH64_SME_I16I32, smei16i32, "smei16i32", 0, \
AARCH64_HWCAP2_SME_I16I32) \
LINE(AARCH64_SME_BI32I32, smebi32i32, "smebi32i32", 0, \
AARCH64_HWCAP2_SME_BI32I32) \
LINE(AARCH64_SME_B16B16, smeb16b16, "smeb16b16", 0, \
AARCH64_HWCAP2_SME_B16B16) \
LINE(AARCH64_SME_F16F16, smef16f16, "smef16f16", 0, AARCH64_HWCAP2_SME_F16F16)
#define INTROSPECTION_PREFIX Aarch64
#define INTROSPECTION_ENUM_PREFIX AARCH64
#include "define_introspection_and_hwcaps.inl"
@@ -0,0 +1,79 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpu_features_macros.h"
#ifdef CPU_FEATURES_ARCH_AARCH64
#if defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
#include "impl_aarch64__base_implementation.inl"
static bool HandleAarch64Line(const LineResult result,
Aarch64Info* const info) {
StringView line = result.line;
StringView key, value;
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
if (CpuFeatures_StringView_IsEquals(key, str("Features"))) {
for (size_t i = 0; i < AARCH64_LAST_; ++i) {
kSetters[i](&info->features, CpuFeatures_StringView_HasWord(
value, kCpuInfoFlags[i], ' '));
}
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) {
info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) {
info->variant = CpuFeatures_StringView_ParsePositiveNumber(value);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) {
info->part = CpuFeatures_StringView_ParsePositiveNumber(value);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) {
info->revision = CpuFeatures_StringView_ParsePositiveNumber(value);
}
}
return !result.eof;
}
static void FillProcCpuInfoData(Aarch64Info* const info) {
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
if (fd >= 0) {
StackLineReader reader;
StackLineReader_Initialize(&reader, fd);
for (;;) {
if (!HandleAarch64Line(StackLineReader_NextLine(&reader), info)) {
break;
}
}
CpuFeatures_CloseFile(fd);
}
}
static const Aarch64Info kEmptyAarch64Info;
Aarch64Info GetAarch64Info(void) {
// capabilities are fetched from both getauxval and /proc/cpuinfo so we can
// have some information if the executable is sandboxed (aka no access to
// /proc/cpuinfo).
Aarch64Info info = kEmptyAarch64Info;
FillProcCpuInfoData(&info);
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
for (size_t i = 0; i < AARCH64_LAST_; ++i) {
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
kSetters[i](&info.features, true);
}
}
return info;
}
#endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
#endif // CPU_FEATURES_ARCH_AARCH64
@@ -0,0 +1,88 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpu_features_macros.h"
#ifdef CPU_FEATURES_ARCH_AARCH64
#if defined(CPU_FEATURES_OS_MACOS) || defined(CPU_FEATURES_OS_IPHONE)
#include "impl_aarch64__base_implementation.inl"
#if !defined(HAVE_SYSCTLBYNAME)
#error "Darwin needs support for sysctlbyname"
#endif
#include <sys/sysctl.h>
#if defined(CPU_FEATURES_MOCK_SYSCTL_AARCH64)
extern bool GetDarwinSysCtlByName(const char*);
extern int GetDarwinSysCtlByNameValue(const char* name);
#else
static int GetDarwinSysCtlByNameValue(const char* name) {
int enabled;
size_t enabled_len = sizeof(enabled);
const int failure = sysctlbyname(name, &enabled, &enabled_len, NULL, 0);
return failure ? 0 : enabled;
}
static bool GetDarwinSysCtlByName(const char* name) {
return GetDarwinSysCtlByNameValue(name) != 0;
}
#endif
static const Aarch64Info kEmptyAarch64Info;
Aarch64Info GetAarch64Info(void) {
Aarch64Info info = kEmptyAarch64Info;
// Handling Darwin platform through sysctlbyname.
info.implementer = GetDarwinSysCtlByNameValue("hw.cputype");
info.variant = GetDarwinSysCtlByNameValue("hw.cpusubtype");
info.part = GetDarwinSysCtlByNameValue("hw.cpufamily");
info.revision = GetDarwinSysCtlByNameValue("hw.cpusubfamily");
info.features.fp = GetDarwinSysCtlByName("hw.optional.floatingpoint");
info.features.asimd = GetDarwinSysCtlByName("hw.optional.AdvSIMD");
info.features.aes = GetDarwinSysCtlByName("hw.optional.arm.FEAT_AES");
info.features.pmull = GetDarwinSysCtlByName("hw.optional.arm.FEAT_PMULL");
info.features.sha1 = GetDarwinSysCtlByName("hw.optional.arm.FEAT_SHA1");
info.features.sha2 = GetDarwinSysCtlByName("hw.optional.arm.FEAT_SHA256");
info.features.crc32 = GetDarwinSysCtlByName("hw.optional.armv8_crc32");
info.features.atomics = GetDarwinSysCtlByName("hw.optional.arm.FEAT_LSE");
info.features.fphp = GetDarwinSysCtlByName("hw.optional.arm.FEAT_FP16");
info.features.asimdhp = GetDarwinSysCtlByName("hw.optional.arm.AdvSIMD_HPFPCvt");
info.features.asimdrdm = GetDarwinSysCtlByName("hw.optional.arm.FEAT_RDM");
info.features.jscvt = GetDarwinSysCtlByName("hw.optional.arm.FEAT_JSCVT");
info.features.fcma = GetDarwinSysCtlByName("hw.optional.arm.FEAT_FCMA");
info.features.lrcpc = GetDarwinSysCtlByName("hw.optional.arm.FEAT_LRCPC");
info.features.dcpop = GetDarwinSysCtlByName("hw.optional.arm.FEAT_DPB");
info.features.sha3 = GetDarwinSysCtlByName("hw.optional.arm.FEAT_SHA3");
info.features.asimddp = GetDarwinSysCtlByName("hw.optional.arm.FEAT_DotProd");
info.features.sha512 = GetDarwinSysCtlByName("hw.optional.arm.FEAT_SHA512");
info.features.asimdfhm = GetDarwinSysCtlByName("hw.optional.arm.FEAT_FHM");
info.features.dit = GetDarwinSysCtlByName("hw.optional.arm.FEAT_DIT");
info.features.uscat = GetDarwinSysCtlByName("hw.optional.arm.FEAT_LSE2");
info.features.flagm = GetDarwinSysCtlByName("hw.optional.arm.FEAT_FlagM");
info.features.ssbs = GetDarwinSysCtlByName("hw.optional.arm.FEAT_SSBS");
info.features.sb = GetDarwinSysCtlByName("hw.optional.arm.FEAT_SB");
info.features.flagm2 = GetDarwinSysCtlByName("hw.optional.arm.FEAT_FlagM2");
info.features.frint = GetDarwinSysCtlByName("hw.optional.arm.FEAT_FRINTTS");
info.features.i8mm = GetDarwinSysCtlByName("hw.optional.arm.FEAT_I8MM");
info.features.bf16 = GetDarwinSysCtlByName("hw.optional.arm.FEAT_BF16");
info.features.bti = GetDarwinSysCtlByName("hw.optional.arm.FEAT_BTI");
return info;
}
#endif // defined(CPU_FEATURES_OS_MACOS) || defined(CPU_FEATURES_OS_IPHONE)
#endif // CPU_FEATURES_ARCH_AARCH64
+138
View File
@@ -0,0 +1,138 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpu_features_macros.h"
#ifdef CPU_FEATURES_ARCH_AARCH64
#ifdef CPU_FEATURES_OS_WINDOWS
#include "cpuinfo_aarch64.h"
////////////////////////////////////////////////////////////////////////////////
// Definitions for introspection.
////////////////////////////////////////////////////////////////////////////////
#define INTROSPECTION_TABLE \
LINE(AARCH64_FP, fp, , , ) \
LINE(AARCH64_ASIMD, asimd, , , ) \
LINE(AARCH64_EVTSTRM, evtstrm, , , ) \
LINE(AARCH64_AES, aes, , , ) \
LINE(AARCH64_PMULL, pmull, , , ) \
LINE(AARCH64_SHA1, sha1, , , ) \
LINE(AARCH64_SHA2, sha2, , , ) \
LINE(AARCH64_CRC32, crc32, , , ) \
LINE(AARCH64_ATOMICS, atomics, , , ) \
LINE(AARCH64_FPHP, fphp, , , ) \
LINE(AARCH64_ASIMDHP, asimdhp, , , ) \
LINE(AARCH64_CPUID, cpuid, , , ) \
LINE(AARCH64_ASIMDRDM, asimdrdm, , , ) \
LINE(AARCH64_JSCVT, jscvt, , , ) \
LINE(AARCH64_FCMA, fcma, , , ) \
LINE(AARCH64_LRCPC, lrcpc, , , ) \
LINE(AARCH64_DCPOP, dcpop, , , ) \
LINE(AARCH64_SHA3, sha3, , , ) \
LINE(AARCH64_SM3, sm3, , , ) \
LINE(AARCH64_SM4, sm4, , , ) \
LINE(AARCH64_ASIMDDP, asimddp, , , ) \
LINE(AARCH64_SHA512, sha512, , , ) \
LINE(AARCH64_SVE, sve, , , ) \
LINE(AARCH64_ASIMDFHM, asimdfhm, , , ) \
LINE(AARCH64_DIT, dit, , , ) \
LINE(AARCH64_USCAT, uscat, , , ) \
LINE(AARCH64_ILRCPC, ilrcpc, , , ) \
LINE(AARCH64_FLAGM, flagm, , , ) \
LINE(AARCH64_SSBS, ssbs, , , ) \
LINE(AARCH64_SB, sb, , , ) \
LINE(AARCH64_PACA, paca, , , ) \
LINE(AARCH64_PACG, pacg, , , ) \
LINE(AARCH64_DCPODP, dcpodp, , , ) \
LINE(AARCH64_SVE2, sve2, , , ) \
LINE(AARCH64_SVEAES, sveaes, , , ) \
LINE(AARCH64_SVEPMULL, svepmull, , , ) \
LINE(AARCH64_SVEBITPERM, svebitperm, , , ) \
LINE(AARCH64_SVESHA3, svesha3, , , ) \
LINE(AARCH64_SVESM4, svesm4, , , ) \
LINE(AARCH64_FLAGM2, flagm2, , , ) \
LINE(AARCH64_FRINT, frint, , , ) \
LINE(AARCH64_SVEI8MM, svei8mm, , , ) \
LINE(AARCH64_SVEF32MM, svef32mm, , , ) \
LINE(AARCH64_SVEF64MM, svef64mm, , , ) \
LINE(AARCH64_SVEBF16, svebf16, , , ) \
LINE(AARCH64_I8MM, i8mm, , , ) \
LINE(AARCH64_BF16, bf16, , , ) \
LINE(AARCH64_DGH, dgh, , , ) \
LINE(AARCH64_RNG, rng, , , ) \
LINE(AARCH64_BTI, bti, , , ) \
LINE(AARCH64_MTE, mte, , , ) \
LINE(AARCH64_ECV, ecv, , , ) \
LINE(AARCH64_AFP, afp, , , ) \
LINE(AARCH64_RPRES, rpres, , , )
#define INTROSPECTION_PREFIX Aarch64
#define INTROSPECTION_ENUM_PREFIX AARCH64
#include "define_introspection.inl"
////////////////////////////////////////////////////////////////////////////////
// Implementation.
////////////////////////////////////////////////////////////////////////////////
#include <stdbool.h>
#include "internal/windows_utils.h"
#ifdef CPU_FEATURES_MOCK_CPUID_AARCH64
extern bool GetWindowsIsProcessorFeaturePresent(DWORD);
extern WORD GetWindowsNativeSystemInfoProcessorRevision();
#else // CPU_FEATURES_MOCK_CPUID_AARCH64
static bool GetWindowsIsProcessorFeaturePresent(DWORD dwProcessorFeature) {
return IsProcessorFeaturePresent(dwProcessorFeature);
}
static WORD GetWindowsNativeSystemInfoProcessorRevision() {
SYSTEM_INFO system_info;
GetNativeSystemInfo(&system_info);
return system_info.wProcessorRevision;
}
#endif
static const Aarch64Info kEmptyAarch64Info;
Aarch64Info GetAarch64Info(void) {
Aarch64Info info = kEmptyAarch64Info;
info.revision = GetWindowsNativeSystemInfoProcessorRevision();
info.features.fp =
GetWindowsIsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE);
info.features.asimd =
GetWindowsIsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE);
info.features.crc32 = GetWindowsIsProcessorFeaturePresent(
PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);
info.features.asimddp =
GetWindowsIsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE);
info.features.jscvt = GetWindowsIsProcessorFeaturePresent(
PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE);
info.features.lrcpc = GetWindowsIsProcessorFeaturePresent(
PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE);
info.features.atomics = GetWindowsIsProcessorFeaturePresent(
PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE);
bool is_crypto_available = GetWindowsIsProcessorFeaturePresent(
PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
info.features.aes = is_crypto_available;
info.features.sha1 = is_crypto_available;
info.features.sha2 = is_crypto_available;
info.features.pmull = is_crypto_available;
return info;
}
#endif // CPU_FEATURES_OS_WINDOWS
#endif // CPU_FEATURES_ARCH_AARCH64
+212
View File
@@ -0,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 "cpu_features_macros.h"
#ifdef CPU_FEATURES_ARCH_ARM
#if defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
#include "cpuinfo_arm.h"
////////////////////////////////////////////////////////////////////////////////
// Definitions for introspection.
////////////////////////////////////////////////////////////////////////////////
#define INTROSPECTION_TABLE \
LINE(ARM_SWP, swp, "swp", ARM_HWCAP_SWP, 0) \
LINE(ARM_HALF, half, "half", ARM_HWCAP_HALF, 0) \
LINE(ARM_THUMB, thumb, "thumb", ARM_HWCAP_THUMB, 0) \
LINE(ARM_26BIT, _26bit, "26bit", ARM_HWCAP_26BIT, 0) \
LINE(ARM_FASTMULT, fastmult, "fastmult", ARM_HWCAP_FAST_MULT, 0) \
LINE(ARM_FPA, fpa, "fpa", ARM_HWCAP_FPA, 0) \
LINE(ARM_VFP, vfp, "vfp", ARM_HWCAP_VFP, 0) \
LINE(ARM_EDSP, edsp, "edsp", ARM_HWCAP_EDSP, 0) \
LINE(ARM_JAVA, java, "java", ARM_HWCAP_JAVA, 0) \
LINE(ARM_IWMMXT, iwmmxt, "iwmmxt", ARM_HWCAP_IWMMXT, 0) \
LINE(ARM_CRUNCH, crunch, "crunch", ARM_HWCAP_CRUNCH, 0) \
LINE(ARM_THUMBEE, thumbee, "thumbee", ARM_HWCAP_THUMBEE, 0) \
LINE(ARM_NEON, neon, "neon", ARM_HWCAP_NEON, 0) \
LINE(ARM_VFPV3, vfpv3, "vfpv3", ARM_HWCAP_VFPV3, 0) \
LINE(ARM_VFPV3D16, vfpv3d16, "vfpv3d16", ARM_HWCAP_VFPV3D16, 0) \
LINE(ARM_TLS, tls, "tls", ARM_HWCAP_TLS, 0) \
LINE(ARM_VFPV4, vfpv4, "vfpv4", ARM_HWCAP_VFPV4, 0) \
LINE(ARM_IDIVA, idiva, "idiva", ARM_HWCAP_IDIVA, 0) \
LINE(ARM_IDIVT, idivt, "idivt", ARM_HWCAP_IDIVT, 0) \
LINE(ARM_VFPD32, vfpd32, "vfpd32", ARM_HWCAP_VFPD32, 0) \
LINE(ARM_LPAE, lpae, "lpae", ARM_HWCAP_LPAE, 0) \
LINE(ARM_EVTSTRM, evtstrm, "evtstrm", ARM_HWCAP_EVTSTRM, 0) \
LINE(ARM_AES, aes, "aes", 0, ARM_HWCAP2_AES) \
LINE(ARM_PMULL, pmull, "pmull", 0, ARM_HWCAP2_PMULL) \
LINE(ARM_SHA1, sha1, "sha1", 0, ARM_HWCAP2_SHA1) \
LINE(ARM_SHA2, sha2, "sha2", 0, ARM_HWCAP2_SHA2) \
LINE(ARM_CRC32, crc32, "crc32", 0, ARM_HWCAP2_CRC32)
#define INTROSPECTION_PREFIX Arm
#define INTROSPECTION_ENUM_PREFIX ARM
#include "define_introspection_and_hwcaps.inl"
////////////////////////////////////////////////////////////////////////////////
// Implementation.
////////////////////////////////////////////////////////////////////////////////
#include <ctype.h>
#include <stdbool.h>
#include "internal/bit_utils.h"
#include "internal/filesystem.h"
#include "internal/stack_line_reader.h"
#include "internal/string_view.h"
typedef struct {
bool processor_reports_armv6;
bool hardware_reports_goldfish;
} ProcCpuInfoData;
static int IndexOfNonDigit(StringView str) {
size_t index = 0;
while (str.size && isdigit(CpuFeatures_StringView_Front(str))) {
str = CpuFeatures_StringView_PopFront(str, 1);
++index;
}
return index;
}
static bool HandleArmLine(const LineResult result, ArmInfo* const info,
ProcCpuInfoData* const proc_info) {
StringView line = result.line;
StringView key, value;
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
if (CpuFeatures_StringView_IsEquals(key, str("Features"))) {
for (size_t i = 0; i < ARM_LAST_; ++i) {
kSetters[i](&info->features, CpuFeatures_StringView_HasWord(
value, kCpuInfoFlags[i], ' '));
}
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) {
info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) {
info->variant = CpuFeatures_StringView_ParsePositiveNumber(value);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) {
info->part = CpuFeatures_StringView_ParsePositiveNumber(value);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) {
info->revision = CpuFeatures_StringView_ParsePositiveNumber(value);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU architecture"))) {
// CPU architecture is a number that may be followed by letters. e.g.
// "6TEJ", "7".
const StringView digits =
CpuFeatures_StringView_KeepFront(value, IndexOfNonDigit(value));
info->architecture = CpuFeatures_StringView_ParsePositiveNumber(digits);
} else if (CpuFeatures_StringView_IsEquals(key, str("Processor")) ||
CpuFeatures_StringView_IsEquals(key, str("model name"))) {
// Android reports this in a non-Linux standard "Processor" but sometimes
// also in "model name", Linux reports it only in "model name"
// see RaspberryPiZero (Linux) vs InvalidArmv7 (Android) test-cases
proc_info->processor_reports_armv6 =
CpuFeatures_StringView_IndexOf(value, str("(v6l)")) >= 0;
} else if (CpuFeatures_StringView_IsEquals(key, str("Hardware"))) {
proc_info->hardware_reports_goldfish =
CpuFeatures_StringView_IsEquals(value, str("Goldfish"));
}
}
return !result.eof;
}
uint32_t GetArmCpuId(const ArmInfo* const info) {
return (ExtractBitRange(info->implementer, 7, 0) << 24) |
(ExtractBitRange(info->variant, 3, 0) << 20) |
(ExtractBitRange(info->part, 11, 0) << 4) |
(ExtractBitRange(info->revision, 3, 0) << 0);
}
static void FixErrors(ArmInfo* const info,
ProcCpuInfoData* const proc_cpu_info_data) {
// Fixing Samsung kernel reporting invalid cpu architecture.
// http://code.google.com/p/android/issues/detail?id=10812
if (proc_cpu_info_data->processor_reports_armv6 && info->architecture >= 7) {
info->architecture = 6;
}
// Handle kernel configuration bugs that prevent the correct reporting of CPU
// features.
switch (GetArmCpuId(info)) {
case 0x4100C080:
// Special case: The emulator-specific Android 4.2 kernel fails to report
// support for the 32-bit ARM IDIV instruction. Technically, this is a
// feature of the virtual CPU implemented by the emulator. Note that it
// could also support Thumb IDIV in the future, and this will have to be
// slightly updated.
if (info->architecture >= 7 &&
proc_cpu_info_data->hardware_reports_goldfish) {
info->features.idiva = true;
}
break;
case 0x511004D0:
// https://crbug.com/341598.
info->features.neon = false;
break;
}
// Some Qualcomm Krait kernels forget to report IDIV support.
// https://github.com/torvalds/linux/commit/120ecfafabec382c4feb79ff159ef42a39b6d33b
if (info->implementer == 0x51 && info->architecture == 7 &&
(info->part == 0x4d || info->part == 0x6f)) {
info->features.idiva = true;
info->features.idivt = true;
}
// Propagate cpu features.
if (info->features.vfpv4) info->features.vfpv3 = true;
if (info->features.neon) info->features.vfpv3 = true;
if (info->features.vfpv3) info->features.vfp = true;
}
static void FillProcCpuInfoData(ArmInfo* const info,
ProcCpuInfoData* proc_cpu_info_data) {
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
if (fd >= 0) {
StackLineReader reader;
StackLineReader_Initialize(&reader, fd);
for (;;) {
if (!HandleArmLine(StackLineReader_NextLine(&reader), info,
proc_cpu_info_data)) {
break;
}
}
CpuFeatures_CloseFile(fd);
}
}
static const ArmInfo kEmptyArmInfo;
static const ProcCpuInfoData kEmptyProcCpuInfoData;
ArmInfo GetArmInfo(void) {
// capabilities are fetched from both getauxval and /proc/cpuinfo so we can
// have some information if the executable is sandboxed (aka no access to
// /proc/cpuinfo).
ArmInfo info = kEmptyArmInfo;
ProcCpuInfoData proc_cpu_info_data = kEmptyProcCpuInfoData;
FillProcCpuInfoData(&info, &proc_cpu_info_data);
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
for (size_t i = 0; i < ARM_LAST_; ++i) {
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
kSetters[i](&info.features, true);
}
}
FixErrors(&info, &proc_cpu_info_data);
return info;
}
#endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
#endif // CPU_FEATURES_ARCH_ARM
+89
View File
@@ -0,0 +1,89 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpu_features_macros.h"
#ifdef CPU_FEATURES_ARCH_LOONGARCH
#if defined(CPU_FEATURES_OS_LINUX)
#include "cpuinfo_loongarch.h"
////////////////////////////////////////////////////////////////////////////////
// Definitions for introspection.
////////////////////////////////////////////////////////////////////////////////
#define INTROSPECTION_TABLE \
LINE(LOONGARCH_CPUCFG, CPUCFG, "cfg", HWCAP_LOONGARCH_CPUCFG, 0) \
LINE(LOONGARCH_LAM, LAM, "lam", HWCAP_LOONGARCH_LAM, 0) \
LINE(LOONGARCH_UAL, UAL, "ual", HWCAP_LOONGARCH_UAL, 0) \
LINE(LOONGARCH_FPU, FPU, "fpu", HWCAP_LOONGARCH_FPU, 0) \
LINE(LOONGARCH_LSX, LSX, "lsx", HWCAP_LOONGARCH_LSX, 0) \
LINE(LOONGARCH_LASX, LASX, "lasx", HWCAP_LOONGARCH_LASX, 0) \
LINE(LOONGARCH_CRC32, CRC32, "crc32", HWCAP_LOONGARCH_CRC32, 0) \
LINE(LOONGARCH_COMPLEX, COMPLEX, "complex", HWCAP_LOONGARCH_COMPLEX, 0) \
LINE(LOONGARCH_CRYPTO, CRYPTO, "crypto", HWCAP_LOONGARCH_CRYPTO, 0) \
LINE(LOONGARCH_LVZ, LVZ, "lvz", HWCAP_LOONGARCH_LVZ, 0) \
LINE(LOONGARCH_LBT_X86, LBT_X86, "lbt_x86", HWCAP_LOONGARCH_LBT_X86, 0) \
LINE(LOONGARCH_LBT_ARM, LBT_ARM, "lbt_arm", HWCAP_LOONGARCH_LBT_ARM, 0) \
LINE(LOONGARCH_LBT_MIPS, LBT_MIPS, "lbt_mips", HWCAP_LOONGARCH_LBT_MIPS, 0) \
LINE(LOONGARCH_PTW, PTW, "ptw", HWCAP_LOONGARCH_PTW, 0)
#define INTROSPECTION_PREFIX LoongArch
#define INTROSPECTION_ENUM_PREFIX LOONGARCH
#include "define_introspection_and_hwcaps.inl"
////////////////////////////////////////////////////////////////////////////////
// Implementation.
////////////////////////////////////////////////////////////////////////////////
#include <stdbool.h>
#include <stdio.h>
#include "internal/filesystem.h"
#include "internal/stack_line_reader.h"
static const LoongArchInfo kEmptyLoongArchInfo;
static bool HandleLoongArchLine(const LineResult result, LoongArchInfo* const info) {
StringView line = result.line;
StringView key, value;
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
if (CpuFeatures_StringView_IsEquals(key, str("Features"))) {
for (size_t i = 0; i < LOONGARCH_LAST_; ++i) {
kSetters[i](&info->features, CpuFeatures_StringView_HasWord(
value, kCpuInfoFlags[i], ' '));
}
}
}
return !result.eof;
}
static void FillProcCpuInfoData(LoongArchInfo* const info) {
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
if (fd >= 0) {
StackLineReader reader;
StackLineReader_Initialize(&reader, fd);
for (;;) {
if (!HandleLoongArchLine(StackLineReader_NextLine(&reader), info)) break;
}
CpuFeatures_CloseFile(fd);
}
}
LoongArchInfo GetLoongArchInfo(void) {
LoongArchInfo info = kEmptyLoongArchInfo;
FillProcCpuInfoData(&info);
return info;
}
#endif // defined(CPU_FEATURES_OS_LINUX)
#endif // CPU_FEATURES_ARCH_LOONGARCH
+93
View File
@@ -0,0 +1,93 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpu_features_macros.h"
#ifdef CPU_FEATURES_ARCH_MIPS
#if defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
#include "cpuinfo_mips.h"
////////////////////////////////////////////////////////////////////////////////
// Definitions for introspection.
////////////////////////////////////////////////////////////////////////////////
#define INTROSPECTION_TABLE \
LINE(MIPS_MSA, msa, "msa", MIPS_HWCAP_MSA, 0) \
LINE(MIPS_EVA, eva, "eva", 0, 0) \
LINE(MIPS_R6, r6, "r6", MIPS_HWCAP_R6, 0) \
LINE(MIPS_MIPS16, mips16, "mips16", MIPS_HWCAP_MIPS16, 0) \
LINE(MIPS_MDMX, mdmx, "mdmx", MIPS_HWCAP_MDMX, 0) \
LINE(MIPS_MIPS3D, mips3d, "mips3d", MIPS_HWCAP_MIPS3D, 0) \
LINE(MIPS_SMART, smart, "smartmips", MIPS_HWCAP_SMARTMIPS, 0) \
LINE(MIPS_DSP, dsp, "dsp", MIPS_HWCAP_DSP, 0)
#define INTROSPECTION_PREFIX Mips
#define INTROSPECTION_ENUM_PREFIX MIPS
#include "define_introspection_and_hwcaps.inl"
////////////////////////////////////////////////////////////////////////////////
// Implementation.
////////////////////////////////////////////////////////////////////////////////
#include "internal/filesystem.h"
#include "internal/hwcaps.h"
#include "internal/stack_line_reader.h"
#include "internal/string_view.h"
static bool HandleMipsLine(const LineResult result,
MipsFeatures* const features) {
StringView key, value;
// See tests for an example.
if (CpuFeatures_StringView_GetAttributeKeyValue(result.line, &key, &value)) {
if (CpuFeatures_StringView_IsEquals(key, str("ASEs implemented"))) {
for (size_t i = 0; i < MIPS_LAST_; ++i) {
kSetters[i](features, CpuFeatures_StringView_HasWord(
value, kCpuInfoFlags[i], ' '));
}
}
}
return !result.eof;
}
static void FillProcCpuInfoData(MipsFeatures* const features) {
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
if (fd >= 0) {
StackLineReader reader;
StackLineReader_Initialize(&reader, fd);
for (;;) {
if (!HandleMipsLine(StackLineReader_NextLine(&reader), features)) {
break;
}
}
CpuFeatures_CloseFile(fd);
}
}
static const MipsInfo kEmptyMipsInfo;
MipsInfo GetMipsInfo(void) {
// capabilities are fetched from both getauxval and /proc/cpuinfo so we can
// have some information if the executable is sandboxed (aka no access to
// /proc/cpuinfo).
MipsInfo info = kEmptyMipsInfo;
FillProcCpuInfoData(&info.features);
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
for (size_t i = 0; i < MIPS_LAST_; ++i) {
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
kSetters[i](&info.features, true);
}
}
return info;
}
#endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
#endif // CPU_FEATURES_ARCH_MIPS
+163
View File
@@ -0,0 +1,163 @@
// Copyright 2018 IBM.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpu_features_macros.h"
#ifdef CPU_FEATURES_ARCH_PPC
#ifdef CPU_FEATURES_OS_LINUX
#include "cpuinfo_ppc.h"
////////////////////////////////////////////////////////////////////////////////
// Definitions for introspection.
////////////////////////////////////////////////////////////////////////////////
#define INTROSPECTION_TABLE \
LINE(PPC_32, ppc32, "ppc32", PPC_FEATURE_32, 0) \
LINE(PPC_64, ppc64, "ppc64", PPC_FEATURE_64, 0) \
LINE(PPC_601_INSTR, ppc601, "ppc601", PPC_FEATURE_601_INSTR, 0) \
LINE(PPC_HAS_ALTIVEC, altivec, "altivec", PPC_FEATURE_HAS_ALTIVEC, 0) \
LINE(PPC_HAS_FPU, fpu, "fpu", PPC_FEATURE_HAS_FPU, 0) \
LINE(PPC_HAS_MMU, mmu, "mmu", PPC_FEATURE_HAS_MMU, 0) \
LINE(PPC_HAS_4xxMAC, mac_4xx, "4xxmac", PPC_FEATURE_HAS_4xxMAC, 0) \
LINE(PPC_UNIFIED_CACHE, unifiedcache, "ucache", PPC_FEATURE_UNIFIED_CACHE, \
0) \
LINE(PPC_HAS_SPE, spe, "spe", PPC_FEATURE_HAS_SPE, 0) \
LINE(PPC_HAS_EFP_SINGLE, efpsingle, "efpsingle", PPC_FEATURE_HAS_EFP_SINGLE, \
0) \
LINE(PPC_HAS_EFP_DOUBLE, efpdouble, "efpdouble", PPC_FEATURE_HAS_EFP_DOUBLE, \
0) \
LINE(PPC_NO_TB, no_tb, "notb", PPC_FEATURE_NO_TB, 0) \
LINE(PPC_POWER4, power4, "power4", PPC_FEATURE_POWER4, 0) \
LINE(PPC_POWER5, power5, "power5", PPC_FEATURE_POWER5, 0) \
LINE(PPC_POWER5_PLUS, power5plus, "power5+", PPC_FEATURE_POWER5_PLUS, 0) \
LINE(PPC_CELL, cell, "cellbe", PPC_FEATURE_CELL, 0) \
LINE(PPC_BOOKE, booke, "booke", PPC_FEATURE_BOOKE, 0) \
LINE(PPC_SMT, smt, "smt", PPC_FEATURE_SMT, 0) \
LINE(PPC_ICACHE_SNOOP, icachesnoop, "ic_snoop", PPC_FEATURE_ICACHE_SNOOP, 0) \
LINE(PPC_ARCH_2_05, arch205, "arch_2_05", PPC_FEATURE_ARCH_2_05, 0) \
LINE(PPC_PA6T, pa6t, "pa6t", PPC_FEATURE_PA6T, 0) \
LINE(PPC_HAS_DFP, dfp, "dfp", PPC_FEATURE_HAS_DFP, 0) \
LINE(PPC_POWER6_EXT, power6ext, "power6x", PPC_FEATURE_POWER6_EXT, 0) \
LINE(PPC_ARCH_2_06, arch206, "arch_2_06", PPC_FEATURE_ARCH_2_06, 0) \
LINE(PPC_HAS_VSX, vsx, "vsx", PPC_FEATURE_HAS_VSX, 0) \
LINE(PPC_PSERIES_PERFMON_COMPAT, pseries_perfmon_compat, "archpmu", \
PPC_FEATURE_PSERIES_PERFMON_COMPAT, 0) \
LINE(PPC_TRUE_LE, truele, "true_le", PPC_FEATURE_TRUE_LE, 0) \
LINE(PPC_PPC_LE, ppcle, "ppcle", PPC_FEATURE_PPC_LE, 0) \
LINE(PPC_ARCH_2_07, arch207, "arch_2_07", 0, PPC_FEATURE2_ARCH_2_07) \
LINE(PPC_HTM, htm, "htm", 0, PPC_FEATURE2_HTM) \
LINE(PPC_DSCR, dscr, "dscr", 0, PPC_FEATURE2_DSCR) \
LINE(PPC_EBB, ebb, "ebb", 0, PPC_FEATURE2_EBB) \
LINE(PPC_ISEL, isel, "isel", 0, PPC_FEATURE2_ISEL) \
LINE(PPC_TAR, tar, "tar", 0, PPC_FEATURE2_TAR) \
LINE(PPC_VEC_CRYPTO, vcrypto, "vcrypto", 0, PPC_FEATURE2_VEC_CRYPTO) \
LINE(PPC_HTM_NOSC, htm_nosc, "htm-nosc", 0, PPC_FEATURE2_HTM_NOSC) \
LINE(PPC_ARCH_3_00, arch300, "arch_3_00", 0, PPC_FEATURE2_ARCH_3_00) \
LINE(PPC_HAS_IEEE128, ieee128, "ieee128", 0, PPC_FEATURE2_HAS_IEEE128) \
LINE(PPC_DARN, darn, "darn", 0, PPC_FEATURE2_DARN) \
LINE(PPC_SCV, scv, "scv", 0, PPC_FEATURE2_SCV) \
LINE(PPC_HTM_NO_SUSPEND, htm_no_suspend, "htm-no-suspend", 0, \
PPC_FEATURE2_HTM_NO_SUSPEND)
#undef PPC // Remove conflict with compiler generated preprocessor
#define INTROSPECTION_PREFIX PPC
#define INTROSPECTION_ENUM_PREFIX PPC
#include "define_introspection_and_hwcaps.inl"
////////////////////////////////////////////////////////////////////////////////
// Implementation.
////////////////////////////////////////////////////////////////////////////////
#include <stdbool.h>
#include "internal/bit_utils.h"
#include "internal/filesystem.h"
#include "internal/hwcaps.h"
#include "internal/stack_line_reader.h"
#include "internal/string_view.h"
static bool HandlePPCLine(const LineResult result,
PPCPlatformStrings* const strings) {
StringView line = result.line;
StringView key, value;
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
if (CpuFeatures_StringView_HasWord(key, "platform", ' ')) {
CpuFeatures_StringView_CopyString(value, strings->platform,
sizeof(strings->platform));
} else if (CpuFeatures_StringView_IsEquals(key, str("model"))) {
CpuFeatures_StringView_CopyString(value, strings->model,
sizeof(strings->platform));
} else if (CpuFeatures_StringView_IsEquals(key, str("machine"))) {
CpuFeatures_StringView_CopyString(value, strings->machine,
sizeof(strings->platform));
} else if (CpuFeatures_StringView_IsEquals(key, str("cpu"))) {
CpuFeatures_StringView_CopyString(value, strings->cpu,
sizeof(strings->platform));
}
}
return !result.eof;
}
static void FillProcCpuInfoData(PPCPlatformStrings* const strings) {
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
if (fd >= 0) {
StackLineReader reader;
StackLineReader_Initialize(&reader, fd);
for (;;) {
if (!HandlePPCLine(StackLineReader_NextLine(&reader), strings)) {
break;
}
}
CpuFeatures_CloseFile(fd);
}
}
static const PPCInfo kEmptyPPCInfo;
PPCInfo GetPPCInfo(void) {
/*
* On Power feature flags aren't currently in cpuinfo so we only look at
* the auxilary vector.
*/
PPCInfo info = kEmptyPPCInfo;
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
for (size_t i = 0; i < PPC_LAST_; ++i) {
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
kSetters[i](&info.features, true);
}
}
return info;
}
static const PPCPlatformStrings kEmptyPPCPlatformStrings;
PPCPlatformStrings GetPPCPlatformStrings(void) {
PPCPlatformStrings strings = kEmptyPPCPlatformStrings;
const char* platform = CpuFeatures_GetPlatformPointer();
const char* base_platform = CpuFeatures_GetBasePlatformPointer();
FillProcCpuInfoData(&strings);
if (platform != NULL)
CpuFeatures_StringView_CopyString(str(platform), strings.type.platform,
sizeof(strings.type.platform));
if (base_platform != NULL)
CpuFeatures_StringView_CopyString(str(base_platform),
strings.type.base_platform,
sizeof(strings.type.base_platform));
return strings;
}
#endif // CPU_FEATURES_OS_LINUX
#endif // CPU_FEATURES_ARCH_PPC
+111
View File
@@ -0,0 +1,111 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpu_features_macros.h"
#ifdef CPU_FEATURES_ARCH_RISCV
#if defined(CPU_FEATURES_OS_LINUX)
#include "cpuinfo_riscv.h"
// According to
// https://elixir.bootlin.com/linux/latest/source/Documentation/devicetree/bindings/riscv/cpus.yaml
// isa string should match the following regex
// ^rv(?:64|32)imaf?d?q?c?b?v?k?h?(?:_[hsxz](?:[a-z])+)*$
//
// This means we can test for features in this exact order except for Z
// extensions.
////////////////////////////////////////////////////////////////////////////////
// Definitions for introspection.
////////////////////////////////////////////////////////////////////////////////
#define INTROSPECTION_TABLE \
LINE(RISCV_RV32I, RV32I, "rv32i", RISCV_HWCAP_32, 0) \
LINE(RISCV_RV64I, RV64I, "rv64i", RISCV_HWCAP_64, 0) \
LINE(RISCV_M, M, "m", RISCV_HWCAP_M, 0) \
LINE(RISCV_A, A, "a", RISCV_HWCAP_A, 0) \
LINE(RISCV_F, F, "f", RISCV_HWCAP_F, 0) \
LINE(RISCV_D, D, "d", RISCV_HWCAP_D, 0) \
LINE(RISCV_Q, Q, "q", RISCV_HWCAP_Q, 0) \
LINE(RISCV_C, C, "c", RISCV_HWCAP_C, 0) \
LINE(RISCV_V, V, "v", RISCV_HWCAP_V, 0) \
LINE(RISCV_Zicsr, Zicsr, "_zicsr", 0, 0) \
LINE(RISCV_Zifencei, Zifencei, "_zifencei", 0, 0)
#define INTROSPECTION_PREFIX Riscv
#define INTROSPECTION_ENUM_PREFIX RISCV
#include "define_introspection_and_hwcaps.inl"
////////////////////////////////////////////////////////////////////////////////
// Implementation.
////////////////////////////////////////////////////////////////////////////////
#include <stdbool.h>
#include <stdio.h>
#include "internal/filesystem.h"
#include "internal/stack_line_reader.h"
static const RiscvInfo kEmptyRiscvInfo;
static void HandleRiscVIsaLine(StringView line, RiscvFeatures* const features) {
for (size_t i = 0; i < RISCV_LAST_; ++i) {
StringView flag = str(kCpuInfoFlags[i]);
int index_of_flag = CpuFeatures_StringView_IndexOf(line, flag);
bool is_set = index_of_flag != -1;
kSetters[i](features, is_set);
if (is_set)
line = CpuFeatures_StringView_PopFront(line, index_of_flag + flag.size);
}
}
static bool HandleRiscVLine(const LineResult result, RiscvInfo* const info) {
StringView line = result.line;
StringView key, value;
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
if (CpuFeatures_StringView_IsEquals(key, str("isa"))) {
HandleRiscVIsaLine(value, &info->features);
} else if (CpuFeatures_StringView_IsEquals(key, str("uarch"))) {
int index = CpuFeatures_StringView_IndexOfChar(value, ',');
if (index == -1) return true;
StringView vendor = CpuFeatures_StringView_KeepFront(value, index);
StringView uarch = CpuFeatures_StringView_PopFront(value, index + 1);
CpuFeatures_StringView_CopyString(vendor, info->vendor,
sizeof(info->vendor));
CpuFeatures_StringView_CopyString(uarch, info->uarch,
sizeof(info->uarch));
}
}
return !result.eof;
}
static void FillProcCpuInfoData(RiscvInfo* const info) {
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
if (fd >= 0) {
StackLineReader reader;
StackLineReader_Initialize(&reader, fd);
for (;;) {
if (!HandleRiscVLine(StackLineReader_NextLine(&reader), info)) break;
}
CpuFeatures_CloseFile(fd);
}
}
RiscvInfo GetRiscvInfo(void) {
RiscvInfo info = kEmptyRiscvInfo;
FillProcCpuInfoData(&info);
return info;
}
#endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
#endif // CPU_FEATURES_ARCH_RISCV
+120
View File
@@ -0,0 +1,120 @@
// Copyright 2022 IBM.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpu_features_macros.h"
#ifdef CPU_FEATURES_ARCH_S390X
#ifdef CPU_FEATURES_OS_LINUX
#include "cpuinfo_s390x.h"
////////////////////////////////////////////////////////////////////////////////
// Definitions for introspection.
////////////////////////////////////////////////////////////////////////////////
#define INTROSPECTION_TABLE \
LINE(S390_ESAN3, esan3, "esan3", HWCAP_S390_ESAN3, 0) \
LINE(S390_ZARCH, zarch, "zarch", HWCAP_S390_ZARCH, 0) \
LINE(S390_STFLE, stfle, "stfle", HWCAP_S390_STFLE, 0) \
LINE(S390_MSA, msa, "msa", HWCAP_S390_MSA, 0) \
LINE(S390_LDISP, ldisp, "ldisp", HWCAP_S390_LDISP, 0) \
LINE(S390_EIMM, eimm, "eimm", HWCAP_S390_EIMM, 0) \
LINE(S390_DFP, dfp, "dfp", HWCAP_S390_DFP, 0) \
LINE(S390_EDAT, edat, "edat", HWCAP_S390_HPAGE, 0) \
LINE(S390_ETF3EH, etf3eh, "etf3eh", HWCAP_S390_ETF3EH, 0) \
LINE(S390_HIGHGPRS, highgprs, "highgprs", HWCAP_S390_HIGH_GPRS, 0) \
LINE(S390_TE, te, "te", HWCAP_S390_TE, 0) \
LINE(S390_VX, vx, "vx", HWCAP_S390_VXRS, 0) \
LINE(S390_VXD, vxd, "vxd", HWCAP_S390_VXRS_BCD, 0) \
LINE(S390_VXE, vxe, "vxe", HWCAP_S390_VXRS_EXT, 0) \
LINE(S390_GS, gs, "gs", HWCAP_S390_GS, 0) \
LINE(S390_VXE2, vxe2, "vxe2", HWCAP_S390_VXRS_EXT2, 0) \
LINE(S390_VXP, vxp, "vxp", HWCAP_S390_VXRS_PDE, 0) \
LINE(S390_SORT, sort, "sort", HWCAP_S390_SORT, 0) \
LINE(S390_DFLT, dflt, "dflt", HWCAP_S390_DFLT, 0) \
LINE(S390_VXP2, vxp2, "vxp2", HWCAP_S390_VXRS_PDE2, 0) \
LINE(S390_NNPA, nnpa, "nnpa", HWCAP_S390_NNPA, 0) \
LINE(S390_PCIMIO, pcimio, "pcimio", HWCAP_S390_PCI_MIO, 0) \
LINE(S390_SIE, sie, "sie", HWCAP_S390_SIE, 0)
#define INTROSPECTION_PREFIX S390X
#define INTROSPECTION_ENUM_PREFIX S390X
#include "define_introspection_and_hwcaps.inl"
////////////////////////////////////////////////////////////////////////////////
// Implementation.
////////////////////////////////////////////////////////////////////////////////
#include <stdbool.h>
#include "internal/bit_utils.h"
#include "internal/filesystem.h"
#include "internal/hwcaps.h"
#include "internal/stack_line_reader.h"
#include "internal/string_view.h"
static bool HandleS390XLine(const LineResult result,
S390XPlatformStrings* const strings) {
StringView line = result.line;
StringView key, value;
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
if (CpuFeatures_StringView_IsEquals(key, str("# processors"))) {
strings->num_processors = CpuFeatures_StringView_ParsePositiveNumber(value);
}
}
return !result.eof;
}
static void FillProcCpuInfoData(S390XPlatformStrings* const strings) {
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
if (fd >= 0) {
StackLineReader reader;
StackLineReader_Initialize(&reader, fd);
for (;;) {
if (!HandleS390XLine(StackLineReader_NextLine(&reader), strings)) {
break;
}
}
CpuFeatures_CloseFile(fd);
}
}
static const S390XInfo kEmptyS390XInfo;
S390XInfo GetS390XInfo(void) {
S390XInfo info = kEmptyS390XInfo;
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
for (size_t i = 0; i < S390X_LAST_; ++i) {
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
kSetters[i](&info.features, true);
}
}
return info;
}
static const S390XPlatformStrings kEmptyS390XPlatformStrings;
S390XPlatformStrings GetS390XPlatformStrings(void) {
S390XPlatformStrings strings = kEmptyS390XPlatformStrings;
const char* platform = CpuFeatures_GetPlatformPointer();
FillProcCpuInfoData(&strings);
if (platform != NULL)
CpuFeatures_StringView_CopyString(str(platform), strings.type.platform,
sizeof(strings.type.platform));
return strings;
}
#endif // CPU_FEATURES_OS_LINUX
#endif // CPU_FEATURES_ARCH_S390X
File diff suppressed because it is too large Load Diff
+68
View File
@@ -0,0 +1,68 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpu_features_macros.h"
#ifdef CPU_FEATURES_ARCH_X86
#ifdef CPU_FEATURES_OS_FREEBSD
#include "impl_x86__base_implementation.inl"
static void OverrideOsPreserves(OsPreserves* os_preserves) {
(void)os_preserves;
// No override
}
#include "internal/filesystem.h"
#include "internal/stack_line_reader.h"
#include "internal/string_view.h"
static void DetectFeaturesFromOs(X86Info* info, X86Features* features) {
(void)info;
// Handling FreeBSD platform through parsing /var/run/dmesg.boot.
const int fd = CpuFeatures_OpenFile("/var/run/dmesg.boot");
if (fd >= 0) {
StackLineReader reader;
StackLineReader_Initialize(&reader, fd);
for (bool stop = false; !stop;) {
const LineResult result = StackLineReader_NextLine(&reader);
if (result.eof) stop = true;
const StringView line = result.line;
if (!CpuFeatures_StringView_StartsWith(line, str(" Features"))) continue;
// Lines of interests are of the following form:
// " Features=0x1783fbff<PSE36,MMX,FXSR,SSE,SSE2,HTT>"
// We first extract the comma separated values between angle brackets.
StringView csv = result.line;
int index = CpuFeatures_StringView_IndexOfChar(csv, '<');
if (index >= 0) csv = CpuFeatures_StringView_PopFront(csv, index + 1);
if (csv.size > 0 && CpuFeatures_StringView_Back(csv) == '>')
csv = CpuFeatures_StringView_PopBack(csv, 1);
if (CpuFeatures_StringView_HasWord(csv, "SSE", ',')) features->sse = true;
if (CpuFeatures_StringView_HasWord(csv, "SSE2", ','))
features->sse2 = true;
if (CpuFeatures_StringView_HasWord(csv, "SSE3", ','))
features->sse3 = true;
if (CpuFeatures_StringView_HasWord(csv, "SSSE3", ','))
features->ssse3 = true;
if (CpuFeatures_StringView_HasWord(csv, "SSE4.1", ','))
features->sse4_1 = true;
if (CpuFeatures_StringView_HasWord(csv, "SSE4.2", ','))
features->sse4_2 = true;
}
CpuFeatures_CloseFile(fd);
}
}
#endif // CPU_FEATURES_OS_FREEBSD
#endif // CPU_FEATURES_ARCH_X86
+58
View File
@@ -0,0 +1,58 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpu_features_macros.h"
#ifdef CPU_FEATURES_ARCH_X86
#if defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
#include "impl_x86__base_implementation.inl"
static void OverrideOsPreserves(OsPreserves* os_preserves) {
(void)os_preserves;
// No override
}
#include "internal/filesystem.h"
#include "internal/stack_line_reader.h"
#include "internal/string_view.h"
static void DetectFeaturesFromOs(X86Info* info, X86Features* features) {
(void)info;
// Handling Linux platform through /proc/cpuinfo.
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
if (fd >= 0) {
StackLineReader reader;
StackLineReader_Initialize(&reader, fd);
for (bool stop = false; !stop;) {
const LineResult result = StackLineReader_NextLine(&reader);
if (result.eof) stop = true;
const StringView line = result.line;
StringView key, value;
if (!CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value))
continue;
if (!CpuFeatures_StringView_IsEquals(key, str("flags"))) continue;
features->sse = CpuFeatures_StringView_HasWord(value, "sse", ' ');
features->sse2 = CpuFeatures_StringView_HasWord(value, "sse2", ' ');
features->sse3 = CpuFeatures_StringView_HasWord(value, "pni", ' ');
features->ssse3 = CpuFeatures_StringView_HasWord(value, "ssse3", ' ');
features->sse4_1 = CpuFeatures_StringView_HasWord(value, "sse4_1", ' ');
features->sse4_2 = CpuFeatures_StringView_HasWord(value, "sse4_2", ' ');
break;
}
CpuFeatures_CloseFile(fd);
}
}
#endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
#endif // CPU_FEATURES_ARCH_X86
+57
View File
@@ -0,0 +1,57 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpu_features_macros.h"
#ifdef CPU_FEATURES_ARCH_X86
#ifdef CPU_FEATURES_OS_MACOS
#include "impl_x86__base_implementation.inl"
#if !defined(HAVE_SYSCTLBYNAME)
#error "Darwin needs support for sysctlbyname"
#endif
#include <sys/sysctl.h>
#if defined(CPU_FEATURES_MOCK_CPUID_X86)
extern bool GetDarwinSysCtlByName(const char*);
#else // CPU_FEATURES_MOCK_CPUID_X86
static bool GetDarwinSysCtlByName(const char* name) {
int enabled;
size_t enabled_len = sizeof(enabled);
const int failure = sysctlbyname(name, &enabled, &enabled_len, NULL, 0);
return failure ? false : enabled;
}
#endif
static void OverrideOsPreserves(OsPreserves* os_preserves) {
// On Darwin AVX512 support is On-demand.
// We have to query the OS instead of querying the Zmm save/restore state.
// https://github.com/apple/darwin-xnu/blob/8f02f2a044b9bb1ad951987ef5bab20ec9486310/osfmk/i386/fpu.c#L173-L199
os_preserves->avx512_registers = GetDarwinSysCtlByName("hw.optional.avx512f");
}
static void DetectFeaturesFromOs(X86Info* info, X86Features* features) {
(void)info;
// Handling Darwin platform through sysctlbyname.
features->sse = GetDarwinSysCtlByName("hw.optional.sse");
features->sse2 = GetDarwinSysCtlByName("hw.optional.sse2");
features->sse3 = GetDarwinSysCtlByName("hw.optional.sse3");
features->ssse3 = GetDarwinSysCtlByName("hw.optional.supplementalsse3");
features->sse4_1 = GetDarwinSysCtlByName("hw.optional.sse4_1");
features->sse4_2 = GetDarwinSysCtlByName("hw.optional.sse4_2");
}
#endif // CPU_FEATURES_OS_MACOS
#endif // CPU_FEATURES_ARCH_X86
+58
View File
@@ -0,0 +1,58 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpu_features_macros.h"
#ifdef CPU_FEATURES_ARCH_X86
#ifdef CPU_FEATURES_OS_WINDOWS
#include "impl_x86__base_implementation.inl"
static void OverrideOsPreserves(OsPreserves* os_preserves) {
(void)os_preserves;
// No override
}
#include "internal/windows_utils.h"
#if defined(CPU_FEATURES_MOCK_CPUID_X86)
extern bool GetWindowsIsProcessorFeaturePresent(DWORD);
#else // CPU_FEATURES_MOCK_CPUID_X86
static bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) {
return IsProcessorFeaturePresent(ProcessorFeature);
}
#endif
static void DetectFeaturesFromOs(X86Info* info, X86Features* features) {
// Handling Windows platform through IsProcessorFeaturePresent.
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent
features->sse =
GetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE);
features->sse2 =
GetWindowsIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE);
features->sse3 =
GetWindowsIsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE);
features->ssse3 =
GetWindowsIsProcessorFeaturePresent(PF_SSSE3_INSTRUCTIONS_AVAILABLE);
features->sse4_1 =
GetWindowsIsProcessorFeaturePresent(PF_SSE4_1_INSTRUCTIONS_AVAILABLE);
features->sse4_2 =
GetWindowsIsProcessorFeaturePresent(PF_SSE4_2_INSTRUCTIONS_AVAILABLE);
// do not bother checking PF_AVX*
// cause AVX enabled processor will have XCR0 be exposed and this function will be skipped at all
}
#endif // CPU_FEATURES_OS_WINDOWS
#endif // CPU_FEATURES_ARCH_X86
+132
View File
@@ -0,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 <assert.h>
#include <errno.h>
#include <stdio.h>
#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);
}
}
}
+192
View File
@@ -0,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 <assert.h>
#include <ctype.h>
#include "copy.inl"
#include "equals.inl"
static const char* CpuFeatures_memchr(const char* const ptr, const size_t size,
const char c) {
for (size_t i = 0; ptr && ptr[i] != '\0' && i < size; ++i)
if (ptr[i] == c) return ptr + i;
return NULL;
}
int CpuFeatures_StringView_IndexOfChar(const StringView view, char c) {
if (view.ptr && view.size) {
const char* const found = CpuFeatures_memchr(view.ptr, view.size, c);
if (found) {
return (int)(found - view.ptr);
}
}
return -1;
}
int CpuFeatures_StringView_IndexOf(const StringView view,
const StringView sub_view) {
if (sub_view.size) {
StringView remainder = view;
while (remainder.size >= sub_view.size) {
const int found_index =
CpuFeatures_StringView_IndexOfChar(remainder, sub_view.ptr[0]);
if (found_index < 0) break;
remainder = CpuFeatures_StringView_PopFront(remainder, found_index);
if (CpuFeatures_StringView_StartsWith(remainder, sub_view)) {
return (int)(remainder.ptr - view.ptr);
}
remainder = CpuFeatures_StringView_PopFront(remainder, 1);
}
}
return -1;
}
bool CpuFeatures_StringView_IsEquals(const StringView a, const StringView b) {
if (a.size == b.size) {
return a.ptr == b.ptr || equals(a.ptr, b.ptr, b.size);
}
return false;
}
bool CpuFeatures_StringView_StartsWith(const StringView a, const StringView b) {
return a.ptr && b.ptr && b.size && a.size >= b.size
? equals(a.ptr, b.ptr, b.size)
: false;
}
StringView CpuFeatures_StringView_PopFront(const StringView str_view,
size_t count) {
if (count > str_view.size) {
return kEmptyStringView;
}
return view(str_view.ptr + count, str_view.size - count);
}
StringView CpuFeatures_StringView_PopBack(const StringView str_view,
size_t count) {
if (count > str_view.size) {
return kEmptyStringView;
}
return view(str_view.ptr, str_view.size - count);
}
StringView CpuFeatures_StringView_KeepFront(const StringView str_view,
size_t count) {
return count <= str_view.size ? view(str_view.ptr, count) : str_view;
}
char CpuFeatures_StringView_Front(const StringView view) {
assert(view.size);
assert(view.ptr);
return view.ptr[0];
}
char CpuFeatures_StringView_Back(const StringView view) {
assert(view.size);
return view.ptr[view.size - 1];
}
StringView CpuFeatures_StringView_TrimWhitespace(StringView view) {
while (view.size && isspace(CpuFeatures_StringView_Front(view)))
view = CpuFeatures_StringView_PopFront(view, 1);
while (view.size && isspace(CpuFeatures_StringView_Back(view)))
view = CpuFeatures_StringView_PopBack(view, 1);
return view;
}
static int HexValue(const char c) {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
return -1;
}
// Returns -1 if view contains non digits.
static int ParsePositiveNumberWithBase(const StringView view, int base) {
int result = 0;
StringView remainder = view;
for (; remainder.size;
remainder = CpuFeatures_StringView_PopFront(remainder, 1)) {
const int value = HexValue(CpuFeatures_StringView_Front(remainder));
if (value < 0 || value >= base) return -1;
result = (result * base) + value;
}
return result;
}
int CpuFeatures_StringView_ParsePositiveNumber(const StringView view) {
if (view.size) {
const StringView hex_prefix = str("0x");
if (CpuFeatures_StringView_StartsWith(view, hex_prefix)) {
const StringView span_no_prefix =
CpuFeatures_StringView_PopFront(view, hex_prefix.size);
return ParsePositiveNumberWithBase(span_no_prefix, 16);
}
return ParsePositiveNumberWithBase(view, 10);
}
return -1;
}
void CpuFeatures_StringView_CopyString(const StringView src, char* dst,
size_t dst_size) {
if (dst_size > 0) {
const size_t max_copy_size = dst_size - 1;
const size_t copy_size =
src.size > max_copy_size ? max_copy_size : src.size;
copy(dst, src.ptr, copy_size);
dst[copy_size] = '\0';
}
}
bool CpuFeatures_StringView_HasWord(const StringView line,
const char* const word_str,
const char separator) {
const StringView word = str(word_str);
StringView remainder = line;
for (;;) {
const int index_of_word = CpuFeatures_StringView_IndexOf(remainder, word);
if (index_of_word < 0) {
return false;
} else {
const StringView before =
CpuFeatures_StringView_KeepFront(line, index_of_word);
const StringView after =
CpuFeatures_StringView_PopFront(line, index_of_word + word.size);
const bool valid_before =
before.size == 0 || CpuFeatures_StringView_Back(before) == separator;
const bool valid_after =
after.size == 0 || CpuFeatures_StringView_Front(after) == separator;
if (valid_before && valid_after) return true;
remainder =
CpuFeatures_StringView_PopFront(remainder, index_of_word + word.size);
}
}
return false;
}
bool CpuFeatures_StringView_GetAttributeKeyValue(const StringView line,
StringView* key,
StringView* value) {
const StringView sep = str(": ");
const int index_of_separator = CpuFeatures_StringView_IndexOf(line, sep);
if (index_of_separator < 0) return false;
*value = CpuFeatures_StringView_TrimWhitespace(
CpuFeatures_StringView_PopFront(line, index_of_separator + sep.size));
*key = CpuFeatures_StringView_TrimWhitespace(
CpuFeatures_StringView_KeepFront(line, index_of_separator));
return true;
}
+470
View File
@@ -0,0 +1,470 @@
// 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 <assert.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cpu_features_macros.h"
#if defined(CPU_FEATURES_ARCH_X86)
#include "cpuinfo_x86.h"
#elif defined(CPU_FEATURES_ARCH_ARM)
#include "cpuinfo_arm.h"
#elif defined(CPU_FEATURES_ARCH_AARCH64)
#include "cpuinfo_aarch64.h"
#elif defined(CPU_FEATURES_ARCH_MIPS)
#include "cpuinfo_mips.h"
#elif defined(CPU_FEATURES_ARCH_PPC)
#include "cpuinfo_ppc.h"
#elif defined(CPU_FEATURES_ARCH_S390X)
#include "cpuinfo_s390x.h"
#elif defined(CPU_FEATURES_ARCH_RISCV)
#include "cpuinfo_riscv.h"
#elif defined(CPU_FEATURES_ARCH_LOONGARCH)
#include "cpuinfo_loongarch.h"
#endif
// Design principles
// -----------------
// We build a tree structure containing all the data to be displayed.
// Then depending on the output type (text or json) we walk the tree and display
// the data accordingly.
// We use a bump allocator to allocate strings and nodes of the tree,
// Memory is not intended to be reclaimed.
typedef struct {
char* ptr;
size_t size;
} BumpAllocator;
char gGlobalBuffer[64 * 1024];
BumpAllocator gBumpAllocator = {.ptr = gGlobalBuffer,
.size = sizeof(gGlobalBuffer)};
static void internal_error(void) {
fputs("internal error\n", stderr);
exit(EXIT_FAILURE);
}
#define ALIGN 8
static void assertAligned(void) {
if ((uintptr_t)(gBumpAllocator.ptr) % ALIGN) internal_error();
}
static void BA_Align(void) {
while (gBumpAllocator.size && (uintptr_t)(gBumpAllocator.ptr) % ALIGN) {
--gBumpAllocator.size;
++gBumpAllocator.ptr;
}
assertAligned();
}
// Update the available memory left in the BumpAllocator.
static void* BA_Bump(size_t size) {
assertAligned();
// Align size to next 8B boundary.
size = (size + ALIGN - 1) / ALIGN * ALIGN;
if (gBumpAllocator.size < size) internal_error();
void* ptr = gBumpAllocator.ptr;
gBumpAllocator.size -= size;
gBumpAllocator.ptr += size;
return ptr;
}
// The type of the nodes in the tree.
typedef enum {
NT_INVALID,
NT_INT,
NT_MAP,
NT_MAP_ENTRY,
NT_ARRAY,
NT_ARRAY_ELEMENT,
NT_STRING,
} NodeType;
// The node in the tree.
typedef struct Node {
NodeType type;
unsigned integer;
const char* string;
struct Node* value;
struct Node* next;
} Node;
// Creates an initialized Node.
static Node* BA_CreateNode(NodeType type) {
Node* tv = (Node*)BA_Bump(sizeof(Node));
assert(tv);
*tv = (Node){.type = type};
return tv;
}
// Adds an integer node.
static Node* CreateInt(int value) {
Node* tv = BA_CreateNode(NT_INT);
tv->integer = value;
return tv;
}
// Adds a string node.
// `value` must outlive the tree.
static Node* CreateConstantString(const char* value) {
Node* tv = BA_CreateNode(NT_STRING);
tv->string = value;
return tv;
}
// Adds a map node.
static Node* CreateMap(void) { return BA_CreateNode(NT_MAP); }
// Adds an array node.
static Node* CreateArray(void) { return BA_CreateNode(NT_ARRAY); }
// Adds a formatted string node.
static Node* CreatePrintfString(const char* format, ...) {
va_list arglist;
va_start(arglist, format);
char* const ptr = gBumpAllocator.ptr;
const int written = vsnprintf(ptr, gBumpAllocator.size, format, arglist);
va_end(arglist);
if (written < 0 || written >= (int)gBumpAllocator.size) internal_error();
return CreateConstantString((char*)BA_Bump(written));
}
// Adds a string node.
static Node* CreateString(const char* value) {
return CreatePrintfString("%s", value);
}
// Adds a map entry node.
static void AddMapEntry(Node* map, const char* key, Node* value) {
assert(map && map->type == NT_MAP);
Node* current = map;
while (current->next) current = current->next;
current->next = (Node*)BA_Bump(sizeof(Node));
*current->next = (Node){.type = NT_MAP_ENTRY, .string = key, .value = value};
}
// Adds an array element node.
static void AddArrayElement(Node* array, Node* value) {
assert(array && array->type == NT_ARRAY);
Node* current = array;
while (current->next) current = current->next;
current->next = (Node*)BA_Bump(sizeof(Node));
*current->next = (Node){.type = NT_ARRAY_ELEMENT, .value = value};
}
static int cmp(const void* p1, const void* p2) {
return strcmp(*(const char* const*)p1, *(const char* const*)p2);
}
#define DEFINE_ADD_FLAGS(HasFeature, FeatureName, FeatureType, LastEnum) \
static void AddFlags(Node* map, const FeatureType* features) { \
size_t i; \
const char* ptrs[LastEnum] = {0}; \
size_t count = 0; \
for (i = 0; i < LastEnum; ++i) { \
if (HasFeature(features, i)) { \
ptrs[count] = FeatureName(i); \
++count; \
} \
} \
qsort((void*)ptrs, count, sizeof(char*), cmp); \
Node* const array = CreateArray(); \
for (i = 0; i < count; ++i) \
AddArrayElement(array, CreateConstantString(ptrs[i])); \
AddMapEntry(map, "flags", array); \
}
#if defined(CPU_FEATURES_ARCH_X86)
DEFINE_ADD_FLAGS(GetX86FeaturesEnumValue, GetX86FeaturesEnumName, X86Features,
X86_LAST_)
#elif defined(CPU_FEATURES_ARCH_ARM)
DEFINE_ADD_FLAGS(GetArmFeaturesEnumValue, GetArmFeaturesEnumName, ArmFeatures,
ARM_LAST_)
#elif defined(CPU_FEATURES_ARCH_AARCH64)
DEFINE_ADD_FLAGS(GetAarch64FeaturesEnumValue, GetAarch64FeaturesEnumName,
Aarch64Features, AARCH64_LAST_)
#elif defined(CPU_FEATURES_ARCH_MIPS)
DEFINE_ADD_FLAGS(GetMipsFeaturesEnumValue, GetMipsFeaturesEnumName,
MipsFeatures, MIPS_LAST_)
#elif defined(CPU_FEATURES_ARCH_PPC)
DEFINE_ADD_FLAGS(GetPPCFeaturesEnumValue, GetPPCFeaturesEnumName, PPCFeatures,
PPC_LAST_)
#elif defined(CPU_FEATURES_ARCH_S390X)
DEFINE_ADD_FLAGS(GetS390XFeaturesEnumValue, GetS390XFeaturesEnumName, S390XFeatures,
S390X_LAST_)
#elif defined(CPU_FEATURES_ARCH_RISCV)
DEFINE_ADD_FLAGS(GetRiscvFeaturesEnumValue, GetRiscvFeaturesEnumName, RiscvFeatures,
RISCV_LAST_)
#elif defined(CPU_FEATURES_ARCH_LOONGARCH)
DEFINE_ADD_FLAGS(GetLoongArchFeaturesEnumValue, GetLoongArchFeaturesEnumName, LoongArchFeatures,
LOONGARCH_LAST_)
#endif
// Prints a json string with characters escaping.
static void printJsonString(const char* str) {
putchar('"');
for (; str && *str; ++str) {
switch (*str) {
case '\"':
case '\\':
case '/':
case '\b':
case '\f':
case '\n':
case '\r':
case '\t':
putchar('\\');
}
putchar(*str);
}
putchar('"');
}
// Walks a Node and print it as json.
static void printJson(const Node* current) {
assert(current);
switch (current->type) {
case NT_INVALID:
break;
case NT_INT:
printf("%d", current->integer);
break;
case NT_STRING:
printJsonString(current->string);
break;
case NT_ARRAY:
putchar('[');
if (current->next) printJson(current->next);
putchar(']');
break;
case NT_MAP:
putchar('{');
if (current->next) printJson(current->next);
putchar('}');
break;
case NT_MAP_ENTRY:
printf("\"%s\":", current->string);
printJson(current->value);
if (current->next) {
putchar(',');
printJson(current->next);
}
break;
case NT_ARRAY_ELEMENT:
printJson(current->value);
if (current->next) {
putchar(',');
printJson(current->next);
}
break;
}
}
// Walks a Node and print it as text.
static void printTextField(const Node* current) {
switch (current->type) {
case NT_INVALID:
break;
case NT_INT:
printf("%3d (0x%02X)", current->integer, current->integer);
break;
case NT_STRING:
fputs(current->string, stdout);
break;
case NT_ARRAY:
if (current->next) printTextField(current->next);
break;
case NT_MAP:
if (current->next) {
printf("{");
printJson(current->next);
printf("}");
}
break;
case NT_MAP_ENTRY:
printf("%-15s : ", current->string);
printTextField(current->value);
if (current->next) {
putchar('\n');
printTextField(current->next);
}
break;
case NT_ARRAY_ELEMENT:
printTextField(current->value);
if (current->next) {
putchar(',');
printTextField(current->next);
}
break;
}
}
static void printTextRoot(const Node* current) {
if (current->type == NT_MAP && current->next) printTextField(current->next);
}
static void showUsage(const char* name) {
printf(
"\n"
"Usage: %s [options]\n"
" Options:\n"
" -h | --help Show help message.\n"
" -j | --json Format output as json instead of plain text.\n"
"\n",
name);
}
static Node* GetCacheTypeString(CacheType cache_type) {
switch (cache_type) {
case CPU_FEATURE_CACHE_NULL:
return CreateConstantString("null");
case CPU_FEATURE_CACHE_DATA:
return CreateConstantString("data");
case CPU_FEATURE_CACHE_INSTRUCTION:
return CreateConstantString("instruction");
case CPU_FEATURE_CACHE_UNIFIED:
return CreateConstantString("unified");
case CPU_FEATURE_CACHE_TLB:
return CreateConstantString("tlb");
case CPU_FEATURE_CACHE_DTLB:
return CreateConstantString("dtlb");
case CPU_FEATURE_CACHE_STLB:
return CreateConstantString("stlb");
case CPU_FEATURE_CACHE_PREFETCH:
return CreateConstantString("prefetch");
}
CPU_FEATURES_UNREACHABLE();
}
static void AddCacheInfo(Node* root, const CacheInfo* cache_info) {
Node* array = CreateArray();
for (int i = 0; i < cache_info->size; ++i) {
CacheLevelInfo info = cache_info->levels[i];
Node* map = CreateMap();
AddMapEntry(map, "level", CreateInt(info.level));
AddMapEntry(map, "cache_type", GetCacheTypeString(info.cache_type));
AddMapEntry(map, "cache_size", CreateInt(info.cache_size));
AddMapEntry(map, "ways", CreateInt(info.ways));
AddMapEntry(map, "line_size", CreateInt(info.line_size));
AddMapEntry(map, "tlb_entries", CreateInt(info.tlb_entries));
AddMapEntry(map, "partitioning", CreateInt(info.partitioning));
AddArrayElement(array, map);
}
AddMapEntry(root, "cache_info", array);
}
static Node* CreateTree(void) {
Node* root = CreateMap();
#if defined(CPU_FEATURES_ARCH_X86)
const X86Info info = GetX86Info();
const CacheInfo cache_info = GetX86CacheInfo();
AddMapEntry(root, "arch", CreateString("x86"));
AddMapEntry(root, "brand", CreateString(info.brand_string));
AddMapEntry(root, "family", CreateInt(info.family));
AddMapEntry(root, "model", CreateInt(info.model));
AddMapEntry(root, "stepping", CreateInt(info.stepping));
AddMapEntry(root, "uarch",
CreateString(
GetX86MicroarchitectureName(GetX86Microarchitecture(&info))));
AddFlags(root, &info.features);
AddCacheInfo(root, &cache_info);
#elif defined(CPU_FEATURES_ARCH_ARM)
const ArmInfo info = GetArmInfo();
AddMapEntry(root, "arch", CreateString("ARM"));
AddMapEntry(root, "implementer", CreateInt(info.implementer));
AddMapEntry(root, "architecture", CreateInt(info.architecture));
AddMapEntry(root, "variant", CreateInt(info.variant));
AddMapEntry(root, "part", CreateInt(info.part));
AddMapEntry(root, "revision", CreateInt(info.revision));
AddFlags(root, &info.features);
#elif defined(CPU_FEATURES_ARCH_AARCH64)
const Aarch64Info info = GetAarch64Info();
AddMapEntry(root, "arch", CreateString("aarch64"));
AddMapEntry(root, "implementer", CreateInt(info.implementer));
AddMapEntry(root, "variant", CreateInt(info.variant));
AddMapEntry(root, "part", CreateInt(info.part));
AddMapEntry(root, "revision", CreateInt(info.revision));
AddFlags(root, &info.features);
#elif defined(CPU_FEATURES_ARCH_MIPS)
const MipsInfo info = GetMipsInfo();
AddMapEntry(root, "arch", CreateString("mips"));
AddFlags(root, &info.features);
#elif defined(CPU_FEATURES_ARCH_PPC)
const PPCInfo info = GetPPCInfo();
const PPCPlatformStrings strings = GetPPCPlatformStrings();
AddMapEntry(root, "arch", CreateString("ppc"));
AddMapEntry(root, "platform", CreateString(strings.platform));
AddMapEntry(root, "model", CreateString(strings.model));
AddMapEntry(root, "machine", CreateString(strings.machine));
AddMapEntry(root, "cpu", CreateString(strings.cpu));
AddMapEntry(root, "instruction", CreateString(strings.type.platform));
AddMapEntry(root, "microarchitecture",
CreateString(strings.type.base_platform));
AddFlags(root, &info.features);
#elif defined(CPU_FEATURES_ARCH_S390X)
const S390XInfo info = GetS390XInfo();
const S390XPlatformStrings strings = GetS390XPlatformStrings();
AddMapEntry(root, "arch", CreateString("s390x"));
AddMapEntry(root, "platform", CreateString("zSeries"));
AddMapEntry(root, "model", CreateString(strings.type.platform));
AddMapEntry(root, "# processors", CreateInt(strings.num_processors));
AddFlags(root, &info.features);
#elif defined(CPU_FEATURES_ARCH_RISCV)
const RiscvInfo info = GetRiscvInfo();
AddMapEntry(root, "arch", CreateString("risc-v"));
AddMapEntry(root, "vendor", CreateString(info.vendor));
AddMapEntry(root, "microarchitecture", CreateString(info.uarch));
AddFlags(root, &info.features);
#elif defined(CPU_FEATURES_ARCH_LOONGARCH)
const LoongArchInfo info = GetLoongArchInfo();
AddMapEntry(root, "arch", CreateString("loongarch"));
AddFlags(root, &info.features);
#endif
return root;
}
int main(int argc, char** argv) {
BA_Align();
const Node* const root = CreateTree();
bool outputJson = false;
int i = 1;
for (; i < argc; ++i) {
const char* arg = argv[i];
if (strcmp(arg, "-j") == 0 || strcmp(arg, "--json") == 0) {
outputJson = true;
} else {
showUsage(argv[0]);
if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0)
return EXIT_SUCCESS;
return EXIT_FAILURE;
}
}
if (outputJson)
printJson(root);
else
printTextRoot(root);
putchar('\n');
return EXIT_SUCCESS;
}
-9
View File
@@ -1,9 +0,0 @@
cv2pdb.exe
dbghelp.dll
msobj140.dll
mspdb140.dll
mspdbcmf.exe
mspdbcore.dll
mspdbsrv.exe
mspdbst.dll
vcruntime140.dll
-36
View File
@@ -1,36 +0,0 @@
# cv2pdb
This exists to convert the DWARF debug information to PDB and helps us
to get more precise stackstraces on program crashes.
Sadly this program is for windows only, but we can get it running using
WINE. You'll not only need wine and cv2pdb, but also Microsoft's PDB
helper libraries and dependencies.
Because of licensing issues I can't supply the needed files for you
here. What files work for me:
- cv2pdb.exe
- dbghelp.dll
- msobj140.dll
- mspdb140.dll
- mspdbcmf.exe
- mspdbcore.dll
- mspdbsrv.exe
- mspdbst.dll
- vcruntime140.dll
I found those libraries in my Visual Studio 2017 install:
..\2017\Community\VC\Tools\MSVC\14.11.25503\bin\Hostx86\x86
You can find cv2pdb binaries here:
https://github.com/rainers/cv2pdb/releases
Apparently cv2pdb also supports older versions of mspdb:
- mspdb80
- mspdb100
- mspdb110
- mspdb120
- mspdb140
-1
View File
@@ -45,7 +45,6 @@ IncludeCategories:
- Regex: '.*'
Priority: 3
IncludeIsMainRegex: '(_test|_win|_linux|_mac|_ios|_osx|_null)?$'
IndentCaseLabels: false
IndentWidth: 4
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
+1 -1
View File
@@ -1,4 +1,4 @@
cmake_minimum_required (VERSION 3.2.0)
cmake_minimum_required (VERSION 3.12)
project (DiscordRPC)
include(GNUInstallDirs)
+6 -13
View File
@@ -1,24 +1,17 @@
FROM archlinux:base
FROM ghcr.io/archlinux/archlinux:base-devel
RUN pacman --noconfirm -Syu gettext \
git \
RUN pacman --noconfirm -Syu git \
bash \
zip \
upx \
sudo \
binutils \
file \
make \
gcc \
fakeroot \
diffutils \
ninja \
cmake \
awk \
unzip \
mingw-w64-crt \
mingw-w64-winpthreads \
mingw-w64-gcc \
mingw-w64-headers \
mingw-w64-binutils
mingw-w64-binutils \
ccache
RUN useradd user -m && echo "ALL ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
RUN su user -c "cd /tmp/ && git clone https://aur.archlinux.org/yay.git --depth=1 && cd yay && makepkg --noconfirm -si && yay --noconfirm -S mingw-w64-cmake"
RUN su user -c "cd /tmp/ && git clone https://aur.archlinux.org/yay-bin.git --depth=1 && cd yay-bin && makepkg --noconfirm -si && yay --noconfirm -S mingw-w64-cmake"
+5
View File
@@ -1527,6 +1527,9 @@ FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg<Context> {
return arg;
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdangling-reference"
// The type template parameter is there to avoid an ODR violation when using
// a fallback formatter in one translation unit and an implicit conversion in
// another (not recommended).
@@ -1541,6 +1544,8 @@ FMT_CONSTEXPR FMT_INLINE auto make_arg(const T& val) -> value<Context> {
return arg;
}
#pragma GCC diagnostic pop
template <bool IS_PACKED, typename Context, type, typename T,
FMT_ENABLE_IF(!IS_PACKED)>
inline auto make_arg(const T& value) -> basic_format_arg<Context> {
+1 -1
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.9)
cmake_minimum_required(VERSION 3.12)
project(imgui CXX)
set(HASH_LIBRARY_HEADERS
+1 -1
View File
@@ -1467,7 +1467,7 @@ void basic_tcp_server::accept_thread()
if (handshake(conn))
{
if (newClient = accept(conn))
if ((newClient = accept(conn)))
{
newClient->on_accept();
+5 -1
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.9)
cmake_minimum_required(VERSION 3.12)
project(imgui CXX)
# dear imgui uses the C++ virtual interfaces for DirectX
@@ -8,6 +8,8 @@ set(IMGUI_HEADERS
imconfig.h
imgui.h
imgui_internal.h
backends/imgui_impl_dx9.h
misc/cpp/imgui_stdlib.h
)
set(IMGUI_SOURCES
imgui.cpp
@@ -15,6 +17,8 @@ set(IMGUI_SOURCES
imgui_tables.cpp
imgui_widgets.cpp
imgui_demo.cpp
backends/imgui_impl_dx9.cpp
misc/cpp/imgui_stdlib.cpp
)
add_library(imgui STATIC ${IMGUI_HEADERS} ${IMGUI_SOURCES})
+360
View File
@@ -0,0 +1,360 @@
// dear imgui: Renderer for DirectX9
// This needs to be used along with a Platform Binding (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2019-05-29: DirectX9: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
// 2019-04-30: DirectX9: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
// 2019-03-29: Misc: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects().
// 2019-01-16: Misc: Disabled fog before drawing UI's. Fixes issue #2288.
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
// 2018-06-08: Misc: Extracted imgui_impl_dx9.cpp/.h away from the old combined DX9+Win32 example.
// 2018-06-08: DirectX9: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
// 2018-05-07: Render: Saving/restoring Transform because they don't seem to be included in the StateBlock. Setting shading mode to Gouraud.
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself.
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
#include "imgui_impl_dx9.h"
#include <algorithm>
// DirectX
#include <d3d9.h>
#include "imgui.h"
// allow std::min use
#ifdef min
#undef min
#endif
// DirectX data
static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;
static LPDIRECT3DINDEXBUFFER9 g_pIB = NULL;
static LPDIRECT3DTEXTURE9 g_FontTexture = NULL;
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
// Render function.
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
void ImGui_ImplDX9_RenderDrawData(ImDrawData *draw_data) {
// Avoid rendering when minimized
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
return;
// Create and grow buffers if needed
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount) {
if (g_pVB) {
g_pVB->Release();
g_pVB = NULL;
}
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
if (g_pd3dDevice->CreateVertexBuffer(g_VertexBufferSize * sizeof(ImDrawVert),
D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT, &g_pVB, NULL) < 0)
return;
}
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount) {
if (g_pIB) {
g_pIB->Release();
g_pIB = NULL;
}
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
if (g_pd3dDevice->CreateIndexBuffer(g_IndexBufferSize * sizeof(ImDrawIdx),
D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY,
sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32,
D3DPOOL_DEFAULT, &g_pIB, NULL) < 0)
return;
}
// Backup the DX9 state
IDirect3DStateBlock9 *d3d9_state_block = NULL;
if (g_pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0)
return;
// Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to)
D3DMATRIX last_world, last_view, last_projection;
g_pd3dDevice->GetTransform(D3DTS_WORLD, &last_world);
g_pd3dDevice->GetTransform(D3DTS_VIEW, &last_view);
g_pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection);
// Copy all vertices into a single contiguous buffer
ImDrawVert *vtx_dst;
ImDrawIdx *idx_dst;
if (g_pVB->Lock(0, (UINT) (draw_data->TotalVtxCount * sizeof(ImDrawVert)), (void **) &vtx_dst,
D3DLOCK_DISCARD) < 0)
return;
if (g_pIB->Lock(0, (UINT) (draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void **) &idx_dst,
D3DLOCK_DISCARD) < 0)
return;
for (int n = 0; n < draw_data->CmdListsCount; n++) {
const ImDrawList *cmd_list = draw_data->CmdLists[n];
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
vtx_dst += cmd_list->VtxBuffer.Size;
idx_dst += cmd_list->IdxBuffer.Size;
}
g_pVB->Unlock();
g_pIB->Unlock();
g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(ImDrawVert));
g_pd3dDevice->SetIndices(g_pIB);
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
// Setup viewport
D3DVIEWPORT9 vp;
vp.X = vp.Y = 0;
vp.Width = (DWORD) draw_data->DisplaySize.x;
vp.Height = (DWORD) draw_data->DisplaySize.y;
vp.MinZ = 0.0f;
vp.MaxZ = 1.0f;
g_pd3dDevice->SetViewport(&vp);
g_pd3dDevice->SetPixelShader(nullptr);
g_pd3dDevice->SetVertexShader(nullptr);
D3DCAPS9 caps {};
if (FAILED(g_pd3dDevice->GetDeviceCaps(&caps))) {
caps.NumSimultaneousRTs = 0UL;
}
IDirect3DSurface9 *back_buffer = nullptr;
IDirect3DSurface9 *depth_stencil = nullptr;
IDirect3DSurface9 *render_targets[8];
// save all previous render target state
for (size_t target = 0; target < std::min(8UL, caps.NumSimultaneousRTs); target++) {
if (FAILED(g_pd3dDevice->GetRenderTarget(target, &render_targets[target]))) {
render_targets[target] = nullptr;
}
}
// get the previous depth stencil
if (FAILED(g_pd3dDevice->GetDepthStencilSurface(&depth_stencil))) {
depth_stencil = nullptr;
}
// set the back buffer as the current render target
if (SUCCEEDED(g_pd3dDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &back_buffer))) {
g_pd3dDevice->SetRenderTarget(0, back_buffer);
g_pd3dDevice->SetDepthStencilSurface(nullptr);
for (size_t target = 1; target < std::min(8UL, caps.NumSimultaneousRTs); target++) {
g_pd3dDevice->SetRenderTarget(target, nullptr);
}
} else {
back_buffer = nullptr;
}
// Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient)
g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, false);
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, false);
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
g_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, false);
g_pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, true);
g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
g_pd3dDevice->SetRenderState(D3DRS_FOGENABLE, false);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
// Setup orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
// Being agnostic of whether <d3dx9.h> or <DirectXMath.h> can be used, we aren't relying on D3DXMatrixIdentity()/D3DXMatrixOrthoOffCenterLH() or DirectX::XMMatrixIdentity()/DirectX::XMMatrixOrthographicOffCenterLH()
{
float L = draw_data->DisplayPos.x + 0.5f;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x + 0.5f;
float T = draw_data->DisplayPos.y + 0.5f;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y + 0.5f;
D3DMATRIX mat_identity = {{{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}}};
D3DMATRIX mat_projection =
{{{
2.0f / (R - L), 0.0f, 0.0f, 0.0f,
0.0f, 2.0f / (T - B), 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.0f,
(L + R) / (L - R), (T + B) / (B - T), 0.5f, 1.0f
}}};
g_pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity);
g_pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_projection);
}
// Render command lists
// (Because we merged all buffers into a single one, we maintain our own offset into them)
int global_vtx_offset = 0;
int global_idx_offset = 0;
ImVec2 clip_off = draw_data->DisplayPos;
for (int n = 0; n < draw_data->CmdListsCount; n++) {
const ImDrawList *cmd_list = draw_data->CmdLists[n];
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) {
const ImDrawCmd *pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback != NULL) {
pcmd->UserCallback(cmd_list, pcmd);
} else {
const RECT r = {(LONG) (pcmd->ClipRect.x - clip_off.x), (LONG) (pcmd->ClipRect.y - clip_off.y),
(LONG) (pcmd->ClipRect.z - clip_off.x), (LONG) (pcmd->ClipRect.w - clip_off.y)};
auto texture = reinterpret_cast<IDirect3DBaseTexture9 *>(pcmd->TextureId);
g_pd3dDevice->SetTexture(0, texture);
g_pd3dDevice->SetScissorRect(&r);
g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
pcmd->VtxOffset + global_vtx_offset, 0,
(UINT) cmd_list->VtxBuffer.Size,
pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3);
}
}
global_idx_offset += cmd_list->IdxBuffer.Size;
global_vtx_offset += cmd_list->VtxBuffer.Size;
}
if (back_buffer) {
back_buffer->Release();
back_buffer = nullptr;
}
// restore previous depth stencil
if (depth_stencil) {
g_pd3dDevice->SetDepthStencilSurface(depth_stencil);
depth_stencil->Release();
depth_stencil = nullptr;
}
// restore all render target state
for (size_t target = 0; target < std::min(8UL, caps.NumSimultaneousRTs); target++) {
auto render_target = render_targets[target];
if (render_target) {
g_pd3dDevice->SetRenderTarget(target, render_target);
render_target->Release();
}
}
// restore the DX9 transform
g_pd3dDevice->SetTransform(D3DTS_WORLD, &last_world);
g_pd3dDevice->SetTransform(D3DTS_VIEW, &last_view);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &last_projection);
// restore the DX9 state
d3d9_state_block->Apply();
d3d9_state_block->Release();
}
bool ImGui_ImplDX9_Init(IDirect3DDevice9 *device) {
// Setup back-end capabilities flags
auto &io = ImGui::GetIO();
io.BackendRendererName = "imgui_impl_dx9";
// We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;
g_pd3dDevice = device;
g_pd3dDevice->AddRef();
return true;
}
void ImGui_ImplDX9_Shutdown() {
ImGui_ImplDX9_InvalidateDeviceObjects();
if (g_pd3dDevice) {
g_pd3dDevice->Release();
g_pd3dDevice = NULL;
}
}
static bool ImGui_ImplDX9_CreateFontsTexture() {
// Build texture atlas
ImGuiIO &io = ImGui::GetIO();
unsigned char *pixels;
int width, height, bytes_per_pixel;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel);
// Upload texture to graphics system
g_FontTexture = NULL;
if (g_pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT, &g_FontTexture, NULL) < 0)
return false;
D3DLOCKED_RECT tex_locked_rect;
if (g_FontTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK)
return false;
for (int y = 0; y < height; y++)
memcpy((unsigned char *) tex_locked_rect.pBits + tex_locked_rect.Pitch * y,
pixels + (width * bytes_per_pixel) * y, (width * bytes_per_pixel));
g_FontTexture->UnlockRect(0);
// Store our identifier
io.Fonts->TexID = (ImTextureID) g_FontTexture;
return true;
}
bool ImGui_ImplDX9_CreateDeviceObjects() {
if (!g_pd3dDevice) {
return false;
}
return ImGui_ImplDX9_CreateFontsTexture();
}
void ImGui_ImplDX9_InvalidateDeviceObjects() {
if (!g_pd3dDevice)
return;
if (g_pVB) {
g_pVB->Release();
g_pVB = NULL;
}
if (g_pIB) {
g_pIB->Release();
g_pIB = NULL;
}
if (g_FontTexture) {
g_FontTexture->Release();
g_FontTexture = NULL;
ImGui::GetIO().Fonts->TexID = 0;
} // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
}
void ImGui_ImplDX9_NewFrame() {
if (!g_FontTexture) {
ImGui_ImplDX9_CreateDeviceObjects();
}
IDirect3DSwapChain9 *swap_chain = nullptr;
if (SUCCEEDED(g_pd3dDevice->GetSwapChain(0, &swap_chain))) {
auto &io = ImGui::GetIO();
D3DPRESENT_PARAMETERS present_params {};
if (SUCCEEDED(swap_chain->GetPresentParameters(&present_params))) {
if (present_params.BackBufferWidth != 0 && present_params.BackBufferHeight != 0) {
io.DisplaySize.x = static_cast<float>(present_params.BackBufferWidth);
io.DisplaySize.y = static_cast<float>(present_params.BackBufferHeight);
} else {
RECT rect {};
GetClientRect(present_params.hDeviceWindow, &rect);
io.DisplaySize.x = static_cast<float>(rect.right - rect.left);
io.DisplaySize.y = static_cast<float>(rect.bottom - rect.top);
}
}
swap_chain->Release();
}
}
+25
View File
@@ -0,0 +1,25 @@
// dear imgui: Renderer for DirectX9
// This needs to be used along with a Platform Binding (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
#pragma once
#include "imgui.h"
struct IDirect3DDevice9;
IMGUI_IMPL_API bool ImGui_ImplDX9_Init(IDirect3DDevice9 *device);
IMGUI_IMPL_API void ImGui_ImplDX9_Shutdown();
IMGUI_IMPL_API void ImGui_ImplDX9_NewFrame();
IMGUI_IMPL_API void ImGui_ImplDX9_RenderDrawData(ImDrawData *draw_data);
// Use if you want to reset your rendering device without losing ImGui state.
IMGUI_IMPL_API bool ImGui_ImplDX9_CreateDeviceObjects();
IMGUI_IMPL_API void ImGui_ImplDX9_InvalidateDeviceObjects();
+33 -16
View File
@@ -1,5 +1,5 @@
//-----------------------------------------------------------------------------
// COMPILE-TIME OPTIONS FOR DEAR IMGUI
// DEAR IMGUI COMPILE-TIME OPTIONS
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
//-----------------------------------------------------------------------------
@@ -9,7 +9,7 @@
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
// Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using.
// Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using.
//-----------------------------------------------------------------------------
#pragma once
@@ -21,27 +21,29 @@
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
//#define IMGUI_API __declspec( dllexport )
//#define IMGUI_API __declspec( dllimport )
// - Windows DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
//#define IMGUI_API __declspec(dllexport) // MSVC Windows: DLL export
//#define IMGUI_API __declspec(dllimport) // MSVC Windows: DLL import
//#define IMGUI_API __attribute__((visibility("default"))) // GCC/Clang: override visibility when set is hidden
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions.
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87+ disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This is automatically done by IMGUI_DISABLE_OBSOLETE_FUNCTIONS.
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowStackToolWindow() will be empty (this was called IMGUI_DISABLE_METRICS_WINDOW before 1.88).
#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowIDStackToolWindow() will be empty.
//---- Don't implement some functions to reduce linkage requirements.
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime).
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME).
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
//#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS // Don't implement default platform_io.Platform_OpenInShellFn() handler (Win32: ShellExecute(), require shell32.lib/.a, Mac/Linux: use system("")).
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
@@ -49,8 +51,13 @@
#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
//---- Enable Test Engine / Automation features.
//#define IMGUI_ENABLE_TEST_ENGINE // Enable imgui_test_engine hooks. Generally set automatically by include "imgui_te_config.h", see Test Engine for details.
//---- Include imgui_user.h at the end of imgui.h as a convenience
// May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included.
//#define IMGUI_INCLUDE_IMGUI_USER_H
//#define IMGUI_USER_H_FILENAME "my_folder/my_imgui_user.h"
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
#define IMGUI_USE_BGRA_PACKED_COLOR
@@ -58,16 +65,17 @@
//---- Performance optimization for DX9
#define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; }
//---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
//---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
//#define IMGUI_USE_WCHAR32
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if enabled
//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if IMGUI_USE_STB_SPRINTF is defined.
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
//#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined.
//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
@@ -78,6 +86,15 @@
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
//#define IMGUI_ENABLE_FREETYPE
//---- Use FreeType + plutosvg or lunasvg to render OpenType SVG fonts (SVGinOT)
// Only works in combination with IMGUI_ENABLE_FREETYPE.
// - lunasvg is currently easier to acquire/install, as e.g. it is part of vcpkg.
// - plutosvg will support more fonts and may load them faster. It currently requires to be built manually but it is fairly easy. See misc/freetype/README for instructions.
// - Both require headers to be available in the include path + program to be linked with the library code (not provided).
// - (note: lunasvg implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
//#define IMGUI_ENABLE_FREETYPE_PLUTOSVG
//#define IMGUI_ENABLE_FREETYPE_LUNASVG
//---- Use stb_truetype to build and rasterize the font atlas (default)
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
//#define IMGUI_ENABLE_STB_TRUETYPE
@@ -108,7 +125,7 @@
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
//#define ImDrawCallback MyImDrawCallback
//---- Debug Tools: Macro to break in Debugger
//---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase)
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
//#define IM_DEBUG_BREAK IM_ASSERT(0)
//#define IM_DEBUG_BREAK __debugbreak()
@@ -116,10 +133,10 @@
//---- Debug Tools: Enable slower asserts
//#define IMGUI_DEBUG_PARANOID
//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
//---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files)
/*
namespace ImGui
{
void MyFunction(const char* name, const MyMatrix44& v);
void MyFunction(const char* name, MyMatrix44* mtx);
}
*/
+4650 -2300
View File
File diff suppressed because it is too large Load Diff
+1497 -902
View File
File diff suppressed because it is too large Load Diff
+3015 -663
View File
File diff suppressed because it is too large Load Diff
+621 -129
View File
File diff suppressed because it is too large Load Diff
+938 -658
View File
File diff suppressed because it is too large Load Diff
+584 -235
View File
File diff suppressed because it is too large Load Diff
+2536 -870
View File
File diff suppressed because it is too large Load Diff
+139 -107
View File
@@ -2,8 +2,11 @@
// This is a slightly modified version of stb_textedit.h 1.14.
// Those changes would need to be pushed into nothings/stb:
// - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321)
// - Fix in stb_textedit_find_charpos to handle last line (see https://github.com/ocornut/imgui/issues/6000)
// - Fix in stb_textedit_find_charpos to handle last line (see https://github.com/ocornut/imgui/issues/6000 + #6783)
// - Added name to struct or it may be forward declared in our code.
// - Added UTF-8 support (see https://github.com/nothings/stb/issues/188 + https://github.com/ocornut/imgui/pull/7925)
// Grep for [DEAR IMGUI] to find the changes.
// - Also renamed macros used or defined outside of IMSTB_TEXTEDIT_IMPLEMENTATION block from STB_TEXTEDIT_* to IMSTB_TEXTEDIT_*
// stb_textedit.h - v1.14 - public domain - Sean Barrett
// Development of this library was sponsored by RAD Game Tools
@@ -30,7 +33,7 @@
// DEPENDENCIES
//
// Uses the C runtime function 'memmove', which you can override
// by defining STB_TEXTEDIT_memmove before the implementation.
// by defining IMSTB_TEXTEDIT_memmove before the implementation.
// Uses no other functions. Performs no runtime allocations.
//
//
@@ -40,7 +43,7 @@
// 1.13 (2019-02-07) fix bug in undo size management
// 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash
// 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield
// 1.10 (2016-10-25) supress warnings about casting away const with -Wcast-qual
// 1.10 (2016-10-25) suppress warnings about casting away const with -Wcast-qual
// 1.9 (2016-08-27) customizable move-by-word
// 1.8 (2016-04-02) better keyboard handling when mouse button is down
// 1.7 (2015-09-13) change y range handling in case baseline is non-0
@@ -208,6 +211,7 @@
// int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
// int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len)
// void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXEDIT_KEYTYPE key)
// void stb_textedit_text(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int text_len)
//
// Each of these functions potentially updates the string and updates the
// state.
@@ -242,7 +246,12 @@
// various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit
// set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is
// clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to
// anything other type you wante before including.
// anything other type you want before including.
// if the STB_TEXTEDIT_KEYTOTEXT function is defined, selected keys are
// transformed into text and stb_textedit_text() is automatically called.
//
// text: [DEAR IMGUI] added 2024-09
// call this to text inputs sent to the textfield.
//
//
// When rendering, you can read the cursor position and selection state from
@@ -274,8 +283,8 @@
////
////
#ifndef INCLUDE_STB_TEXTEDIT_H
#define INCLUDE_STB_TEXTEDIT_H
#ifndef INCLUDE_IMSTB_TEXTEDIT_H
#define INCLUDE_IMSTB_TEXTEDIT_H
////////////////////////////////////////////////////////////////////////
//
@@ -286,38 +295,38 @@
// and undo state.
//
#ifndef STB_TEXTEDIT_UNDOSTATECOUNT
#define STB_TEXTEDIT_UNDOSTATECOUNT 99
#ifndef IMSTB_TEXTEDIT_UNDOSTATECOUNT
#define IMSTB_TEXTEDIT_UNDOSTATECOUNT 99
#endif
#ifndef STB_TEXTEDIT_UNDOCHARCOUNT
#define STB_TEXTEDIT_UNDOCHARCOUNT 999
#ifndef IMSTB_TEXTEDIT_UNDOCHARCOUNT
#define IMSTB_TEXTEDIT_UNDOCHARCOUNT 999
#endif
#ifndef STB_TEXTEDIT_CHARTYPE
#define STB_TEXTEDIT_CHARTYPE int
#ifndef IMSTB_TEXTEDIT_CHARTYPE
#define IMSTB_TEXTEDIT_CHARTYPE int
#endif
#ifndef STB_TEXTEDIT_POSITIONTYPE
#define STB_TEXTEDIT_POSITIONTYPE int
#ifndef IMSTB_TEXTEDIT_POSITIONTYPE
#define IMSTB_TEXTEDIT_POSITIONTYPE int
#endif
typedef struct
{
// private data
STB_TEXTEDIT_POSITIONTYPE where;
STB_TEXTEDIT_POSITIONTYPE insert_length;
STB_TEXTEDIT_POSITIONTYPE delete_length;
IMSTB_TEXTEDIT_POSITIONTYPE where;
IMSTB_TEXTEDIT_POSITIONTYPE insert_length;
IMSTB_TEXTEDIT_POSITIONTYPE delete_length;
int char_storage;
} StbUndoRecord;
typedef struct
{
// private data
StbUndoRecord undo_rec [STB_TEXTEDIT_UNDOSTATECOUNT];
STB_TEXTEDIT_CHARTYPE undo_char[STB_TEXTEDIT_UNDOCHARCOUNT];
StbUndoRecord undo_rec [IMSTB_TEXTEDIT_UNDOSTATECOUNT];
IMSTB_TEXTEDIT_CHARTYPE undo_char[IMSTB_TEXTEDIT_UNDOCHARCOUNT];
short undo_point, redo_point;
int undo_char_point, redo_char_point;
} StbUndoState;
typedef struct
typedef struct STB_TexteditState
{
/////////////////////
//
@@ -371,7 +380,7 @@ typedef struct
float ymin,ymax; // height of row above and below baseline
int num_chars;
} StbTexteditRow;
#endif //INCLUDE_STB_TEXTEDIT_H
#endif //INCLUDE_IMSTB_TEXTEDIT_H
////////////////////////////////////////////////////////////////////////////
@@ -384,11 +393,11 @@ typedef struct
// implementation isn't include-guarded, since it might have indirectly
// included just the "header" portion
#ifdef STB_TEXTEDIT_IMPLEMENTATION
#ifdef IMSTB_TEXTEDIT_IMPLEMENTATION
#ifndef STB_TEXTEDIT_memmove
#ifndef IMSTB_TEXTEDIT_memmove
#include <string.h>
#define STB_TEXTEDIT_memmove memmove
#define IMSTB_TEXTEDIT_memmove memmove
#endif
@@ -398,7 +407,7 @@ typedef struct
//
// traverse the layout to locate the nearest character to a display position
static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y)
static int stb_text_locate_coord(IMSTB_TEXTEDIT_STRING *str, float x, float y)
{
StbTexteditRow r;
int n = STB_TEXTEDIT_STRINGLEN(str);
@@ -437,13 +446,13 @@ static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y)
if (x < r.x1) {
// search characters in row for one that straddles 'x'
prev_x = r.x0;
for (k=0; k < r.num_chars; ++k) {
for (k=0; k < r.num_chars; k = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k) - i) {
float w = STB_TEXTEDIT_GETWIDTH(str, i, k);
if (x < prev_x+w) {
if (x < prev_x+w/2)
return k+i;
else
return k+i+1;
return IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k);
}
prev_x += w;
}
@@ -458,7 +467,7 @@ static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y)
}
// API click: on mouse down, move the cursor to the clicked location, and reset the selection
static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
static void stb_textedit_click(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
{
// In single-line mode, just always make y = 0. This lets the drag keep working if the mouse
// goes off the top or bottom of the text
@@ -476,7 +485,7 @@ static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *stat
}
// API drag: on mouse drag, move the cursor and selection endpoint to the clicked location
static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
static void stb_textedit_drag(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
{
int p = 0;
@@ -502,11 +511,11 @@ static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state
//
// forward declarations
static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state);
static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state);
static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length);
static void stb_text_undo(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state);
static void stb_text_redo(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state);
static void stb_text_makeundo_delete(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length);
static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length);
static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length);
static void stb_text_makeundo_replace(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length);
typedef struct
{
@@ -518,7 +527,7 @@ typedef struct
// find the x/y location of a character, and remember info about the previous row in
// case we get a move-up event (for page up, we'll have to rescan)
static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *str, int n, int single_line)
static void stb_textedit_find_charpos(StbFindState *find, IMSTB_TEXTEDIT_STRING *str, int n, int single_line)
{
StbTexteditRow r;
int prev_start = 0;
@@ -549,7 +558,10 @@ static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *s
i += r.num_chars;
find->y += r.baseline_y_delta;
if (i == z) // [DEAR IMGUI]
{
r.num_chars = 0; // [DEAR IMGUI]
break; // [DEAR IMGUI]
}
}
find->first_char = first = i;
@@ -559,14 +571,14 @@ static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *s
// now scan to find xpos
find->x = r.x0;
for (i=0; first+i < n; ++i)
for (i=0; first+i < n; i = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, first + i) - first)
find->x += STB_TEXTEDIT_GETWIDTH(str, first, i);
}
#define STB_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end)
// make the selection/cursor state valid if client altered the string
static void stb_textedit_clamp(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
static void stb_textedit_clamp(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
{
int n = STB_TEXTEDIT_STRINGLEN(str);
if (STB_TEXT_HAS_SELECTION(state)) {
@@ -580,7 +592,7 @@ static void stb_textedit_clamp(STB_TEXTEDIT_STRING *str, STB_TexteditState *stat
}
// delete characters while updating undo
static void stb_textedit_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int len)
static void stb_textedit_delete(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int len)
{
stb_text_makeundo_delete(str, state, where, len);
STB_TEXTEDIT_DELETECHARS(str, where, len);
@@ -588,7 +600,7 @@ static void stb_textedit_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *sta
}
// delete the section
static void stb_textedit_delete_selection(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
static void stb_textedit_delete_selection(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
{
stb_textedit_clamp(str, state);
if (STB_TEXT_HAS_SELECTION(state)) {
@@ -625,7 +637,7 @@ static void stb_textedit_move_to_first(STB_TexteditState *state)
}
// move cursor to last character of selection
static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
static void stb_textedit_move_to_last(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
{
if (STB_TEXT_HAS_SELECTION(state)) {
stb_textedit_sortselection(state);
@@ -636,14 +648,25 @@ static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditStat
}
}
// [DEAR IMGUI]
// Functions must be implemented for UTF8 support
// Code in this file that uses those functions is modified for [DEAR IMGUI] and deviates from the original stb_textedit.
// There is not necessarily a '[DEAR IMGUI]' at the usage sites.
#ifndef IMSTB_TEXTEDIT_GETPREVCHARINDEX
#define IMSTB_TEXTEDIT_GETPREVCHARINDEX(obj, idx) (idx - 1)
#endif
#ifndef IMSTB_TEXTEDIT_GETNEXTCHARINDEX
#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx) (idx + 1)
#endif
#ifdef STB_TEXTEDIT_IS_SPACE
static int is_word_boundary( STB_TEXTEDIT_STRING *str, int idx )
static int is_word_boundary( IMSTB_TEXTEDIT_STRING *str, int idx )
{
return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1;
}
#ifndef STB_TEXTEDIT_MOVEWORDLEFT
static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c )
static int stb_textedit_move_to_word_previous( IMSTB_TEXTEDIT_STRING *str, int c )
{
--c; // always move at least one character
while( c >= 0 && !is_word_boundary( str, c ) )
@@ -658,7 +681,7 @@ static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c )
#endif
#ifndef STB_TEXTEDIT_MOVEWORDRIGHT
static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str, int c )
static int stb_textedit_move_to_word_next( IMSTB_TEXTEDIT_STRING *str, int c )
{
const int len = STB_TEXTEDIT_STRINGLEN(str);
++c; // always move at least one character
@@ -685,7 +708,7 @@ static void stb_textedit_prep_selection_at_cursor(STB_TexteditState *state)
}
// API cut: delete selection
static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
static int stb_textedit_cut(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
{
if (STB_TEXT_HAS_SELECTION(state)) {
stb_textedit_delete_selection(str,state); // implicitly clamps
@@ -696,7 +719,7 @@ static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
}
// API paste: replace existing selection with passed-in text
static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len)
static int stb_textedit_paste_internal(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, IMSTB_TEXTEDIT_CHARTYPE *text, int len)
{
// if there's a selection, the paste should delete it
stb_textedit_clamp(str, state);
@@ -716,36 +739,44 @@ static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditSta
#define STB_TEXTEDIT_KEYTYPE int
#endif
// [DEAR IMGUI] Added stb_textedit_text(), extracted out and called by stb_textedit_key() for backward compatibility.
static void stb_textedit_text(IMSTB_TEXTEDIT_STRING* str, STB_TexteditState* state, const IMSTB_TEXTEDIT_CHARTYPE* text, int text_len)
{
// can't add newline in single-line mode
if (text[0] == '\n' && state->single_line)
return;
if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) {
state->cursor += text_len;
state->has_preferred_x = 0;
}
}
else {
stb_textedit_delete_selection(str, state); // implicitly clamps
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) {
stb_text_makeundo_insert(state, state->cursor, text_len);
state->cursor += text_len;
state->has_preferred_x = 0;
}
}
}
// API key: process a keyboard input
static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key)
static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key)
{
retry:
switch (key) {
default: {
#ifdef STB_TEXTEDIT_KEYTOTEXT
int c = STB_TEXTEDIT_KEYTOTEXT(key);
if (c > 0) {
STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE) c;
// can't add newline in single-line mode
if (c == '\n' && state->single_line)
break;
if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
++state->cursor;
state->has_preferred_x = 0;
}
} else {
stb_textedit_delete_selection(str,state); // implicitly clamps
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
stb_text_makeundo_insert(state, state->cursor, 1);
++state->cursor;
state->has_preferred_x = 0;
}
}
IMSTB_TEXTEDIT_CHARTYPE ch = (IMSTB_TEXTEDIT_CHARTYPE)c;
stb_textedit_text(str, state, &ch, 1);
}
#endif
break;
}
@@ -771,7 +802,7 @@ retry:
stb_textedit_move_to_first(state);
else
if (state->cursor > 0)
--state->cursor;
state->cursor = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
state->has_preferred_x = 0;
break;
@@ -780,7 +811,7 @@ retry:
if (STB_TEXT_HAS_SELECTION(state))
stb_textedit_move_to_last(str, state);
else
++state->cursor;
state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
stb_textedit_clamp(str, state);
state->has_preferred_x = 0;
break;
@@ -790,7 +821,7 @@ retry:
stb_textedit_prep_selection_at_cursor(state);
// move selection left
if (state->select_end > 0)
--state->select_end;
state->select_end = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->select_end);
state->cursor = state->select_end;
state->has_preferred_x = 0;
break;
@@ -840,7 +871,7 @@ retry:
case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT:
stb_textedit_prep_selection_at_cursor(state);
// move selection right
++state->select_end;
state->select_end = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->select_end);
stb_textedit_clamp(str, state);
state->cursor = state->select_end;
state->has_preferred_x = 0;
@@ -889,14 +920,14 @@ retry:
x = row.x0;
for (i=0; i < row.num_chars; ++i) {
float dx = STB_TEXTEDIT_GETWIDTH(str, start, i);
#ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE
if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)
#ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE
if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
break;
#endif
x += dx;
if (x > goal_x)
break;
++state->cursor;
state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
}
stb_textedit_clamp(str, state);
@@ -951,14 +982,14 @@ retry:
x = row.x0;
for (i=0; i < row.num_chars; ++i) {
float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);
#ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE
if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)
#ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE
if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
break;
#endif
x += dx;
if (x > goal_x)
break;
++state->cursor;
state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
}
stb_textedit_clamp(str, state);
@@ -986,7 +1017,7 @@ retry:
else {
int n = STB_TEXTEDIT_STRINGLEN(str);
if (state->cursor < n)
stb_textedit_delete(str, state, state->cursor, 1);
stb_textedit_delete(str, state, state->cursor, IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor) - state->cursor);
}
state->has_preferred_x = 0;
break;
@@ -998,8 +1029,9 @@ retry:
else {
stb_textedit_clamp(str, state);
if (state->cursor > 0) {
stb_textedit_delete(str, state, state->cursor-1, 1);
--state->cursor;
int prev = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
stb_textedit_delete(str, state, prev, state->cursor - prev);
state->cursor = prev;
}
}
state->has_preferred_x = 0;
@@ -1109,8 +1141,8 @@ retry:
static void stb_textedit_flush_redo(StbUndoState *state)
{
state->redo_point = STB_TEXTEDIT_UNDOSTATECOUNT;
state->redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT;
state->redo_point = IMSTB_TEXTEDIT_UNDOSTATECOUNT;
state->redo_char_point = IMSTB_TEXTEDIT_UNDOCHARCOUNT;
}
// discard the oldest entry in the undo list
@@ -1122,13 +1154,13 @@ static void stb_textedit_discard_undo(StbUndoState *state)
int n = state->undo_rec[0].insert_length, i;
// delete n characters from all other records
state->undo_char_point -= n;
STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) (state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE)));
IMSTB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) (state->undo_char_point*sizeof(IMSTB_TEXTEDIT_CHARTYPE)));
for (i=0; i < state->undo_point; ++i)
if (state->undo_rec[i].char_storage >= 0)
state->undo_rec[i].char_storage -= n; // @OPTIMIZE: get rid of char_storage and infer it
}
--state->undo_point;
STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0])));
IMSTB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0])));
}
}
@@ -1138,7 +1170,7 @@ static void stb_textedit_discard_undo(StbUndoState *state)
// fill up even though the undo buffer didn't
static void stb_textedit_discard_redo(StbUndoState *state)
{
int k = STB_TEXTEDIT_UNDOSTATECOUNT-1;
int k = IMSTB_TEXTEDIT_UNDOSTATECOUNT-1;
if (state->redo_point <= k) {
// if the k'th undo state has characters, clean those up
@@ -1146,7 +1178,7 @@ static void stb_textedit_discard_redo(StbUndoState *state)
int n = state->undo_rec[k].insert_length, i;
// move the remaining redo character data to the end of the buffer
state->redo_char_point += n;
STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE)));
IMSTB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((IMSTB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*sizeof(IMSTB_TEXTEDIT_CHARTYPE)));
// adjust the position of all the other records to account for above memmove
for (i=state->redo_point; i < k; ++i)
if (state->undo_rec[i].char_storage >= 0)
@@ -1154,12 +1186,12 @@ static void stb_textedit_discard_redo(StbUndoState *state)
}
// now move all the redo records towards the end of the buffer; the first one is at 'redo_point'
// [DEAR IMGUI]
size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0]));
size_t move_size = (size_t)((IMSTB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0]));
const char* buf_begin = (char*)state->undo_rec; (void)buf_begin;
const char* buf_end = (char*)state->undo_rec + sizeof(state->undo_rec); (void)buf_end;
IM_ASSERT(((char*)(state->undo_rec + state->redo_point)) >= buf_begin);
IM_ASSERT(((char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end);
STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size);
IMSTB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size);
// now move redo_point to point to the new one
++state->redo_point;
@@ -1173,32 +1205,32 @@ static StbUndoRecord *stb_text_create_undo_record(StbUndoState *state, int numch
// if we have no free records, we have to make room, by sliding the
// existing records down
if (state->undo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
if (state->undo_point == IMSTB_TEXTEDIT_UNDOSTATECOUNT)
stb_textedit_discard_undo(state);
// if the characters to store won't possibly fit in the buffer, we can't undo
if (numchars > STB_TEXTEDIT_UNDOCHARCOUNT) {
if (numchars > IMSTB_TEXTEDIT_UNDOCHARCOUNT) {
state->undo_point = 0;
state->undo_char_point = 0;
return NULL;
}
// if we don't have enough free characters in the buffer, we have to make room
while (state->undo_char_point + numchars > STB_TEXTEDIT_UNDOCHARCOUNT)
while (state->undo_char_point + numchars > IMSTB_TEXTEDIT_UNDOCHARCOUNT)
stb_textedit_discard_undo(state);
return &state->undo_rec[state->undo_point++];
}
static STB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos, int insert_len, int delete_len)
static IMSTB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos, int insert_len, int delete_len)
{
StbUndoRecord *r = stb_text_create_undo_record(state, insert_len);
if (r == NULL)
return NULL;
r->where = pos;
r->insert_length = (STB_TEXTEDIT_POSITIONTYPE) insert_len;
r->delete_length = (STB_TEXTEDIT_POSITIONTYPE) delete_len;
r->insert_length = (IMSTB_TEXTEDIT_POSITIONTYPE) insert_len;
r->delete_length = (IMSTB_TEXTEDIT_POSITIONTYPE) delete_len;
if (insert_len == 0) {
r->char_storage = -1;
@@ -1210,7 +1242,7 @@ static STB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos,
}
}
static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
static void stb_text_undo(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
{
StbUndoState *s = &state->undostate;
StbUndoRecord u, *r;
@@ -1237,7 +1269,7 @@ static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
// characters stored for *undoing* don't leave room for redo
// if the last is true, we have to bail
if (s->undo_char_point + u.delete_length >= STB_TEXTEDIT_UNDOCHARCOUNT) {
if (s->undo_char_point + u.delete_length >= IMSTB_TEXTEDIT_UNDOCHARCOUNT) {
// the undo records take up too much character space; there's no space to store the redo characters
r->insert_length = 0;
} else {
@@ -1246,7 +1278,7 @@ static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
// there's definitely room to store the characters eventually
while (s->undo_char_point + u.delete_length > s->redo_char_point) {
// should never happen:
if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
if (s->redo_point == IMSTB_TEXTEDIT_UNDOSTATECOUNT)
return;
// there's currently not enough room, so discard a redo record
stb_textedit_discard_redo(s);
@@ -1278,11 +1310,11 @@ static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
s->redo_point--;
}
static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
static void stb_text_redo(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
{
StbUndoState *s = &state->undostate;
StbUndoRecord *u, r;
if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
if (s->redo_point == IMSTB_TEXTEDIT_UNDOSTATECOUNT)
return;
// we need to do two things: apply the redo record, and create an undo record
@@ -1334,20 +1366,20 @@ static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int le
stb_text_createundo(&state->undostate, where, 0, length);
}
static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length)
static void stb_text_makeundo_delete(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length)
{
int i;
STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0);
IMSTB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0);
if (p) {
for (i=0; i < length; ++i)
p[i] = STB_TEXTEDIT_GETCHAR(str, where+i);
}
}
static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length)
static void stb_text_makeundo_replace(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length)
{
int i;
STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length);
IMSTB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length);
if (p) {
for (i=0; i < old_length; ++i)
p[i] = STB_TEXTEDIT_GETCHAR(str, where+i);
@@ -1359,8 +1391,8 @@ static void stb_textedit_clear_state(STB_TexteditState *state, int is_single_lin
{
state->undostate.undo_point = 0;
state->undostate.undo_char_point = 0;
state->undostate.redo_point = STB_TEXTEDIT_UNDOSTATECOUNT;
state->undostate.redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT;
state->undostate.redo_point = IMSTB_TEXTEDIT_UNDOSTATECOUNT;
state->undostate.redo_char_point = IMSTB_TEXTEDIT_UNDOCHARCOUNT;
state->select_end = state->select_start = 0;
state->cursor = 0;
state->has_preferred_x = 0;
@@ -1383,16 +1415,16 @@ static void stb_textedit_initialize_state(STB_TexteditState *state, int is_singl
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len)
static int stb_textedit_paste(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, IMSTB_TEXTEDIT_CHARTYPE const *ctext, int len)
{
return stb_textedit_paste_internal(str, state, (STB_TEXTEDIT_CHARTYPE *) ctext, len);
return stb_textedit_paste_internal(str, state, (IMSTB_TEXTEDIT_CHARTYPE *) ctext, len);
}
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
#endif//STB_TEXTEDIT_IMPLEMENTATION
#endif//IMSTB_TEXTEDIT_IMPLEMENTATION
/*
------------------------------------------------------------------------------
+1 -1
View File
@@ -656,7 +656,7 @@ STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h
STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip);
// If skip != 0, this tells stb_truetype to skip any codepoints for which
// there is no corresponding glyph. If skip=0, which is the default, then
// codepoints without a glyph recived the font's "missing character" glyph,
// codepoints without a glyph received the font's "missing character" glyph,
// typically an empty box by convention.
STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above
+85
View File
@@ -0,0 +1,85 @@
// dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.)
// This is also an example of how you may wrap your own similar types.
// Changelog:
// - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string
// See more C++ related extension (fmt, RAII, syntaxis sugar) on Wiki:
// https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness
#include "imgui.h"
#include "imgui_stdlib.h"
// Clang warnings with -Weverything
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
#endif
struct InputTextCallback_UserData
{
std::string* Str;
ImGuiInputTextCallback ChainCallback;
void* ChainCallbackUserData;
};
static int InputTextCallback(ImGuiInputTextCallbackData* data)
{
InputTextCallback_UserData* user_data = (InputTextCallback_UserData*)data->UserData;
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
{
// Resize string callback
// If for some reason we refuse the new length (BufTextLen) and/or capacity (BufSize) we need to set them back to what we want.
std::string* str = user_data->Str;
IM_ASSERT(data->Buf == str->c_str());
str->resize(data->BufTextLen);
data->Buf = (char*)str->c_str();
}
else if (user_data->ChainCallback)
{
// Forward to user callback, if any
data->UserData = user_data->ChainCallbackUserData;
return user_data->ChainCallback(data);
}
return 0;
}
bool ImGui::InputText(const char* label, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
{
IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
flags |= ImGuiInputTextFlags_CallbackResize;
InputTextCallback_UserData cb_user_data;
cb_user_data.Str = str;
cb_user_data.ChainCallback = callback;
cb_user_data.ChainCallbackUserData = user_data;
return InputText(label, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data);
}
bool ImGui::InputTextMultiline(const char* label, std::string* str, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
{
IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
flags |= ImGuiInputTextFlags_CallbackResize;
InputTextCallback_UserData cb_user_data;
cb_user_data.Str = str;
cb_user_data.ChainCallback = callback;
cb_user_data.ChainCallbackUserData = user_data;
return InputTextMultiline(label, (char*)str->c_str(), str->capacity() + 1, size, flags, InputTextCallback, &cb_user_data);
}
bool ImGui::InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
{
IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
flags |= ImGuiInputTextFlags_CallbackResize;
InputTextCallback_UserData cb_user_data;
cb_user_data.Str = str;
cb_user_data.ChainCallback = callback;
cb_user_data.ChainCallbackUserData = user_data;
return InputTextWithHint(label, hint, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data);
}
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
+21
View File
@@ -0,0 +1,21 @@
// dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.)
// This is also an example of how you may wrap your own similar types.
// Changelog:
// - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string
// See more C++ related extension (fmt, RAII, syntaxis sugar) on Wiki:
// https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness
#pragma once
#include <string>
namespace ImGui
{
// ImGui::InputText() with std::string
// Because text input needs dynamic resizing, we need to setup a callback to grow the capacity
IMGUI_API bool InputText(const char* label, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
IMGUI_API bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
IMGUI_API bool InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
}
-643
View File
@@ -1,643 +0,0 @@
/** @file GuillotineBinPack.cpp
@author Jukka Jylänki
@brief Implements different bin packer algorithms that use the GUILLOTINE data structure.
This work is released to Public Domain, do whatever you want with it.
*/
#include <utility>
#include <iostream>
#include <limits>
#include <algorithm>
#include <cassert>
#include <cstring>
#include <cmath>
#include "GuillotineBinPack.h"
#pragma warning( disable : 4267 )
namespace rbp {
using namespace std;
GuillotineBinPack::GuillotineBinPack()
:binWidth(0),
binHeight(0)
{
}
GuillotineBinPack::GuillotineBinPack(int width, int height)
{
Init(width, height);
}
void GuillotineBinPack::Init(int width, int height)
{
binWidth = width;
binHeight = height;
#ifdef _DEBUG
disjointRects.Clear();
#endif
// Clear any memory of previously packed rectangles.
usedRectangles.clear();
// We start with a single big free rectangle that spans the whole bin.
Rect n;
n.x = 0;
n.y = 0;
n.width = width;
n.height = height;
freeRectangles.clear();
freeRectangles.push_back(n);
}
void GuillotineBinPack::Insert(std::vector<RectSize> &rects, bool merge,
FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod)
{
// Remember variables about the best packing choice we have made so far during the iteration process.
int bestFreeRect = 0;
int bestRect = 0;
bool bestFlipped = false;
// Pack rectangles one at a time until we have cleared the rects array of all rectangles.
// rects will get destroyed in the process.
while(rects.size() > 0)
{
// Stores the penalty score of the best rectangle placement - bigger=worse, smaller=better.
int bestScore = std::numeric_limits<int>::max();
for(size_t i = 0; i < freeRectangles.size(); ++i)
{
for(size_t j = 0; j < rects.size(); ++j)
{
// If this rectangle is a perfect match, we pick it instantly.
if (rects[j].width == freeRectangles[i].width && rects[j].height == freeRectangles[i].height)
{
bestFreeRect = i;
bestRect = j;
bestFlipped = false;
bestScore = std::numeric_limits<int>::min();
i = freeRectangles.size(); // Force a jump out of the outer loop as well - we got an instant fit.
break;
}
// If flipping this rectangle is a perfect match, pick that then.
/*else if (rects[j].height == freeRectangles[i].width && rects[j].width == freeRectangles[i].height)
{
bestFreeRect = i;
bestRect = j;
bestFlipped = true;
bestScore = std::numeric_limits<int>::min();
i = freeRectangles.size(); // Force a jump out of the outer loop as well - we got an instant fit.
break;
}*/
// Try if we can fit the rectangle upright.
else if (rects[j].width <= freeRectangles[i].width && rects[j].height <= freeRectangles[i].height)
{
int score = ScoreByHeuristic(rects[j].width, rects[j].height, freeRectangles[i], rectChoice);
if (score < bestScore)
{
bestFreeRect = i;
bestRect = j;
bestFlipped = false;
bestScore = score;
}
}
// If not, then perhaps flipping sideways will make it fit?
/*else if (rects[j].height <= freeRectangles[i].width && rects[j].width <= freeRectangles[i].height)
{
int score = ScoreByHeuristic(rects[j].height, rects[j].width, freeRectangles[i], rectChoice);
if (score < bestScore)
{
bestFreeRect = i;
bestRect = j;
bestFlipped = true;
bestScore = score;
}
}*/
}
}
// If we didn't manage to find any rectangle to pack, abort.
if (bestScore == std::numeric_limits<int>::max())
return;
// Otherwise, we're good to go and do the actual packing.
Rect newNode;
newNode.x = freeRectangles[bestFreeRect].x;
newNode.y = freeRectangles[bestFreeRect].y;
newNode.width = rects[bestRect].width;
newNode.height = rects[bestRect].height;
if (bestFlipped)
std::swap(newNode.width, newNode.height);
// Remove the free space we lost in the bin.
SplitFreeRectByHeuristic(freeRectangles[bestFreeRect], newNode, splitMethod);
freeRectangles.erase(freeRectangles.begin() + bestFreeRect);
// Remove the rectangle we just packed from the input list.
rects.erase(rects.begin() + bestRect);
// Perform a Rectangle Merge step if desired.
if (merge)
MergeFreeList();
// Remember the new used rectangle.
usedRectangles.push_back(newNode);
// Check that we're really producing correct packings here.
debug_assert(disjointRects.Add(newNode) == true);
}
}
/// @return True if r fits inside freeRect (possibly rotated).
bool Fits(const RectSize &r, const Rect &freeRect)
{
return (r.width <= freeRect.width && r.height <= freeRect.height) ||
(r.height <= freeRect.width && r.width <= freeRect.height);
}
/// @return True if r fits perfectly inside freeRect, i.e. the leftover area is 0.
bool FitsPerfectly(const RectSize &r, const Rect &freeRect)
{
return (r.width == freeRect.width && r.height == freeRect.height) ||
(r.height == freeRect.width && r.width == freeRect.height);
}
/*
// A helper function for GUILLOTINE-MAXFITTING. Counts how many rectangles fit into the given rectangle
// after it has been split.
void CountNumFitting(const Rect &freeRect, int width, int height, const std::vector<RectSize> &rects,
int usedRectIndex, bool splitHorizontal, int &score1, int &score2)
{
const int w = freeRect.width - width;
const int h = freeRect.height - height;
Rect bottom;
bottom.x = freeRect.x;
bottom.y = freeRect.y + height;
bottom.height = h;
Rect right;
right.x = freeRect.x + width;
right.y = freeRect.y;
right.width = w;
if (splitHorizontal)
{
bottom.width = freeRect.width;
right.height = height;
}
else // Split vertically
{
bottom.width = width;
right.height = freeRect.height;
}
int fitBottom = 0;
int fitRight = 0;
for(size_t i = 0; i < rects.size(); ++i)
if (i != usedRectIndex)
{
if (FitsPerfectly(rects[i], bottom))
fitBottom |= 0x10000000;
if (FitsPerfectly(rects[i], right))
fitRight |= 0x10000000;
if (Fits(rects[i], bottom))
++fitBottom;
if (Fits(rects[i], right))
++fitRight;
}
score1 = min(fitBottom, fitRight);
score2 = max(fitBottom, fitRight);
}
*/
/*
// Implements GUILLOTINE-MAXFITTING, an experimental heuristic that's really cool but didn't quite work in practice.
void GuillotineBinPack::InsertMaxFitting(std::vector<RectSize> &rects, std::vector<Rect> &dst, bool merge,
FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod)
{
dst.clear();
int bestRect = 0;
bool bestFlipped = false;
bool bestSplitHorizontal = false;
// Pick rectangles one at a time and pack the one that leaves the most choices still open.
while(rects.size() > 0 && freeRectangles.size() > 0)
{
int bestScore1 = -1;
int bestScore2 = -1;
///\todo Different sort predicates.
clb::sort::QuickSort(&freeRectangles[0], freeRectangles.size(), CompareRectShortSide);
Rect &freeRect = freeRectangles[0];
for(size_t j = 0; j < rects.size(); ++j)
{
int score1;
int score2;
if (rects[j].width == freeRect.width && rects[j].height == freeRect.height)
{
bestRect = j;
bestFlipped = false;
bestScore1 = bestScore2 = std::numeric_limits<int>::max();
break;
}
else if (rects[j].width <= freeRect.width && rects[j].height <= freeRect.height)
{
CountNumFitting(freeRect, rects[j].width, rects[j].height, rects, j, false, score1, score2);
if (score1 > bestScore1 || (score1 == bestScore1 && score2 > bestScore2))
{
bestRect = j;
bestScore1 = score1;
bestScore2 = score2;
bestFlipped = false;
bestSplitHorizontal = false;
}
CountNumFitting(freeRect, rects[j].width, rects[j].height, rects, j, true, score1, score2);
if (score1 > bestScore1 || (score1 == bestScore1 && score2 > bestScore2))
{
bestRect = j;
bestScore1 = score1;
bestScore2 = score2;
bestFlipped = false;
bestSplitHorizontal = true;
}
}
if (rects[j].height == freeRect.width && rects[j].width == freeRect.height)
{
bestRect = j;
bestFlipped = true;
bestScore1 = bestScore2 = std::numeric_limits<int>::max();
break;
}
else if (rects[j].height <= freeRect.width && rects[j].width <= freeRect.height)
{
CountNumFitting(freeRect, rects[j].height, rects[j].width, rects, j, false, score1, score2);
if (score1 > bestScore1 || (score1 == bestScore1 && score2 > bestScore2))
{
bestRect = j;
bestScore1 = score1;
bestScore2 = score2;
bestFlipped = true;
bestSplitHorizontal = false;
}
CountNumFitting(freeRect, rects[j].height, rects[j].width, rects, j, true, score1, score2);
if (score1 > bestScore1 || (score1 == bestScore1 && score2 > bestScore2))
{
bestRect = j;
bestScore1 = score1;
bestScore2 = score2;
bestFlipped = true;
bestSplitHorizontal = true;
}
}
}
if (bestScore1 >= 0)
{
Rect newNode;
newNode.x = freeRect.x;
newNode.y = freeRect.y;
newNode.width = rects[bestRect].width;
newNode.height = rects[bestRect].height;
if (bestFlipped)
std::swap(newNode.width, newNode.height);
assert(disjointRects.Disjoint(newNode));
SplitFreeRectAlongAxis(freeRect, newNode, bestSplitHorizontal);
rects.erase(rects.begin() + bestRect);
if (merge)
MergeFreeList();
usedRectangles.push_back(newNode);
#ifdef _DEBUG
disjointRects.Add(newNode);
#endif
}
freeRectangles.erase(freeRectangles.begin());
}
}
*/
Rect GuillotineBinPack::Insert(int width, int height, bool merge, FreeRectChoiceHeuristic rectChoice,
GuillotineSplitHeuristic splitMethod)
{
// Find where to put the new rectangle.
int freeNodeIndex = 0;
Rect newRect = FindPositionForNewNode(width, height, rectChoice, &freeNodeIndex);
// Abort if we didn't have enough space in the bin.
if (newRect.height == 0)
return newRect;
// Remove the space that was just consumed by the new rectangle.
SplitFreeRectByHeuristic(freeRectangles[freeNodeIndex], newRect, splitMethod);
freeRectangles.erase(freeRectangles.begin() + freeNodeIndex);
// Perform a Rectangle Merge step if desired.
if (merge)
MergeFreeList();
// Remember the new used rectangle.
usedRectangles.push_back(newRect);
// Check that we're really producing correct packings here.
debug_assert(disjointRects.Add(newRect) == true);
return newRect;
}
/// Computes the ratio of used surface area to the total bin area.
float GuillotineBinPack::Occupancy() const
{
///\todo The occupancy rate could be cached/tracked incrementally instead
/// of looping through the list of packed rectangles here.
unsigned long usedSurfaceArea = 0;
for(size_t i = 0; i < usedRectangles.size(); ++i)
usedSurfaceArea += usedRectangles[i].width * usedRectangles[i].height;
return (float)usedSurfaceArea / (binWidth * binHeight);
}
/// Returns the heuristic score value for placing a rectangle of size width*height into freeRect. Does not try to rotate.
int GuillotineBinPack::ScoreByHeuristic(int width, int height, const Rect &freeRect, FreeRectChoiceHeuristic rectChoice)
{
switch(rectChoice)
{
case RectBestAreaFit: return ScoreBestAreaFit(width, height, freeRect);
case RectBestShortSideFit: return ScoreBestShortSideFit(width, height, freeRect);
case RectBestLongSideFit: return ScoreBestLongSideFit(width, height, freeRect);
case RectWorstAreaFit: return ScoreWorstAreaFit(width, height, freeRect);
case RectWorstShortSideFit: return ScoreWorstShortSideFit(width, height, freeRect);
case RectWorstLongSideFit: return ScoreWorstLongSideFit(width, height, freeRect);
default: assert(false); return std::numeric_limits<int>::max();
}
}
int GuillotineBinPack::ScoreBestAreaFit(int width, int height, const Rect &freeRect)
{
return freeRect.width * freeRect.height - width * height;
}
int GuillotineBinPack::ScoreBestShortSideFit(int width, int height, const Rect &freeRect)
{
int leftoverHoriz = abs(freeRect.width - width);
int leftoverVert = abs(freeRect.height - height);
int leftover = min(leftoverHoriz, leftoverVert);
return leftover;
}
int GuillotineBinPack::ScoreBestLongSideFit(int width, int height, const Rect &freeRect)
{
int leftoverHoriz = abs(freeRect.width - width);
int leftoverVert = abs(freeRect.height - height);
int leftover = max(leftoverHoriz, leftoverVert);
return leftover;
}
int GuillotineBinPack::ScoreWorstAreaFit(int width, int height, const Rect &freeRect)
{
return -ScoreBestAreaFit(width, height, freeRect);
}
int GuillotineBinPack::ScoreWorstShortSideFit(int width, int height, const Rect &freeRect)
{
return -ScoreBestShortSideFit(width, height, freeRect);
}
int GuillotineBinPack::ScoreWorstLongSideFit(int width, int height, const Rect &freeRect)
{
return -ScoreBestLongSideFit(width, height, freeRect);
}
Rect GuillotineBinPack::FindPositionForNewNode(int width, int height, FreeRectChoiceHeuristic rectChoice, int *nodeIndex)
{
Rect bestNode;
memset(&bestNode, 0, sizeof(Rect));
int bestScore = std::numeric_limits<int>::max();
/// Try each free rectangle to find the best one for placement.
for(size_t i = 0; i < freeRectangles.size(); ++i)
{
// If this is a perfect fit upright, choose it immediately.
if (width == freeRectangles[i].width && height == freeRectangles[i].height)
{
bestNode.x = freeRectangles[i].x;
bestNode.y = freeRectangles[i].y;
bestNode.width = width;
bestNode.height = height;
bestScore = std::numeric_limits<int>::min();
*nodeIndex = i;
debug_assert(disjointRects.Disjoint(bestNode));
break;
}
// If this is a perfect fit sideways, choose it.
else if (height == freeRectangles[i].width && width == freeRectangles[i].height)
{
bestNode.x = freeRectangles[i].x;
bestNode.y = freeRectangles[i].y;
bestNode.width = height;
bestNode.height = width;
bestScore = std::numeric_limits<int>::min();
*nodeIndex = i;
debug_assert(disjointRects.Disjoint(bestNode));
break;
}
// Does the rectangle fit upright?
else if (width <= freeRectangles[i].width && height <= freeRectangles[i].height)
{
int score = ScoreByHeuristic(width, height, freeRectangles[i], rectChoice);
if (score < bestScore)
{
bestNode.x = freeRectangles[i].x;
bestNode.y = freeRectangles[i].y;
bestNode.width = width;
bestNode.height = height;
bestScore = score;
*nodeIndex = i;
debug_assert(disjointRects.Disjoint(bestNode));
}
}
// Does the rectangle fit sideways?
else if (height <= freeRectangles[i].width && width <= freeRectangles[i].height)
{
int score = ScoreByHeuristic(height, width, freeRectangles[i], rectChoice);
if (score < bestScore)
{
bestNode.x = freeRectangles[i].x;
bestNode.y = freeRectangles[i].y;
bestNode.width = height;
bestNode.height = width;
bestScore = score;
*nodeIndex = i;
debug_assert(disjointRects.Disjoint(bestNode));
}
}
}
return bestNode;
}
void GuillotineBinPack::SplitFreeRectByHeuristic(const Rect &freeRect, const Rect &placedRect, GuillotineSplitHeuristic method)
{
// Compute the lengths of the leftover area.
const int w = freeRect.width - placedRect.width;
const int h = freeRect.height - placedRect.height;
// Placing placedRect into freeRect results in an L-shaped free area, which must be split into
// two disjoint rectangles. This can be achieved with by splitting the L-shape using a single line.
// We have two choices: horizontal or vertical.
// Use the given heuristic to decide which choice to make.
bool splitHorizontal;
switch(method)
{
case SplitShorterLeftoverAxis:
// Split along the shorter leftover axis.
splitHorizontal = (w <= h);
break;
case SplitLongerLeftoverAxis:
// Split along the longer leftover axis.
splitHorizontal = (w > h);
break;
case SplitMinimizeArea:
// Maximize the larger area == minimize the smaller area.
// Tries to make the single bigger rectangle.
splitHorizontal = (placedRect.width * h > w * placedRect.height);
break;
case SplitMaximizeArea:
// Maximize the smaller area == minimize the larger area.
// Tries to make the rectangles more even-sized.
splitHorizontal = (placedRect.width * h <= w * placedRect.height);
break;
case SplitShorterAxis:
// Split along the shorter total axis.
splitHorizontal = (freeRect.width <= freeRect.height);
break;
case SplitLongerAxis:
// Split along the longer total axis.
splitHorizontal = (freeRect.width > freeRect.height);
break;
default:
splitHorizontal = true;
assert(false);
}
// Perform the actual split.
SplitFreeRectAlongAxis(freeRect, placedRect, splitHorizontal);
}
/// This function will add the two generated rectangles into the freeRectangles array. The caller is expected to
/// remove the original rectangle from the freeRectangles array after that.
void GuillotineBinPack::SplitFreeRectAlongAxis(const Rect &freeRect, const Rect &placedRect, bool splitHorizontal)
{
// Form the two new rectangles.
Rect bottom;
bottom.x = freeRect.x;
bottom.y = freeRect.y + placedRect.height;
bottom.height = freeRect.height - placedRect.height;
Rect right;
right.x = freeRect.x + placedRect.width;
right.y = freeRect.y;
right.width = freeRect.width - placedRect.width;
if (splitHorizontal)
{
bottom.width = freeRect.width;
right.height = placedRect.height;
}
else // Split vertically
{
bottom.width = placedRect.width;
right.height = freeRect.height;
}
// Add the new rectangles into the free rectangle pool if they weren't degenerate.
if (bottom.width > 0 && bottom.height > 0)
freeRectangles.push_back(bottom);
if (right.width > 0 && right.height > 0)
freeRectangles.push_back(right);
debug_assert(disjointRects.Disjoint(bottom));
debug_assert(disjointRects.Disjoint(right));
}
void GuillotineBinPack::MergeFreeList()
{
#ifdef _DEBUG
DisjointRectCollection test;
for(size_t i = 0; i < freeRectangles.size(); ++i)
assert(test.Add(freeRectangles[i]) == true);
#endif
// Do a Theta(n^2) loop to see if any pair of free rectangles could me merged into one.
// Note that we miss any opportunities to merge three rectangles into one. (should call this function again to detect that)
for(size_t i = 0; i < freeRectangles.size(); ++i)
for(size_t j = i+1; j < freeRectangles.size(); ++j)
{
if (freeRectangles[i].width == freeRectangles[j].width && freeRectangles[i].x == freeRectangles[j].x)
{
if (freeRectangles[i].y == freeRectangles[j].y + freeRectangles[j].height)
{
freeRectangles[i].y -= freeRectangles[j].height;
freeRectangles[i].height += freeRectangles[j].height;
freeRectangles.erase(freeRectangles.begin() + j);
--j;
}
else if (freeRectangles[i].y + freeRectangles[i].height == freeRectangles[j].y)
{
freeRectangles[i].height += freeRectangles[j].height;
freeRectangles.erase(freeRectangles.begin() + j);
--j;
}
}
else if (freeRectangles[i].height == freeRectangles[j].height && freeRectangles[i].y == freeRectangles[j].y)
{
if (freeRectangles[i].x == freeRectangles[j].x + freeRectangles[j].width)
{
freeRectangles[i].x -= freeRectangles[j].width;
freeRectangles[i].width += freeRectangles[j].width;
freeRectangles.erase(freeRectangles.begin() + j);
--j;
}
else if (freeRectangles[i].x + freeRectangles[i].width == freeRectangles[j].x)
{
freeRectangles[i].width += freeRectangles[j].width;
freeRectangles.erase(freeRectangles.begin() + j);
--j;
}
}
}
#ifdef _DEBUG
test.Clear();
for(size_t i = 0; i < freeRectangles.size(); ++i)
assert(test.Add(freeRectangles[i]) == true);
#endif
}
}
-134
View File
@@ -1,134 +0,0 @@
/** @file GuillotineBinPack.h
@author Jukka Jylänki
@brief Implements different bin packer algorithms that use the GUILLOTINE data structure.
This work is released to Public Domain, do whatever you want with it.
*/
#pragma once
#include <vector>
#include "Rect.h"
namespace rbp {
/** GuillotineBinPack implements different variants of bin packer algorithms that use the GUILLOTINE data structure
to keep track of the free space of the bin where rectangles may be placed. */
class GuillotineBinPack
{
public:
/// The initial bin size will be (0,0). Call Init to set the bin size.
GuillotineBinPack();
/// Initializes a new bin of the given size.
GuillotineBinPack(int width, int height);
/// (Re)initializes the packer to an empty bin of width x height units. Call whenever
/// you need to restart with a new bin.
void Init(int width, int height);
/// Specifies the different choice heuristics that can be used when deciding which of the free subrectangles
/// to place the to-be-packed rectangle into.
enum FreeRectChoiceHeuristic
{
RectBestAreaFit, ///< -BAF
RectBestShortSideFit, ///< -BSSF
RectBestLongSideFit, ///< -BLSF
RectWorstAreaFit, ///< -WAF
RectWorstShortSideFit, ///< -WSSF
RectWorstLongSideFit ///< -WLSF
};
/// Specifies the different choice heuristics that can be used when the packer needs to decide whether to
/// subdivide the remaining free space in horizontal or vertical direction.
enum GuillotineSplitHeuristic
{
SplitShorterLeftoverAxis, ///< -SLAS
SplitLongerLeftoverAxis, ///< -LLAS
SplitMinimizeArea, ///< -MINAS, Try to make a single big rectangle at the expense of making the other small.
SplitMaximizeArea, ///< -MAXAS, Try to make both remaining rectangles as even-sized as possible.
SplitShorterAxis, ///< -SAS
SplitLongerAxis ///< -LAS
};
/// Inserts a single rectangle into the bin. The packer might rotate the rectangle, in which case the returned
/// struct will have the width and height values swapped.
/// @param merge If true, performs free Rectangle Merge procedure after packing the new rectangle. This procedure
/// tries to defragment the list of disjoint free rectangles to improve packing performance, but also takes up
/// some extra time.
/// @param rectChoice The free rectangle choice heuristic rule to use.
/// @param splitMethod The free rectangle split heuristic rule to use.
Rect Insert(int width, int height, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod);
/// Inserts a list of rectangles into the bin.
/// @param rects The list of rectangles to add. This list will be destroyed in the packing process.
/// @param merge If true, performs Rectangle Merge operations during the packing process.
/// @param rectChoice The free rectangle choice heuristic rule to use.
/// @param splitMethod The free rectangle split heuristic rule to use.
void Insert(std::vector<RectSize> &rects, bool merge,
FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod);
// Implements GUILLOTINE-MAXFITTING, an experimental heuristic that's really cool but didn't quite work in practice.
// void InsertMaxFitting(std::vector<RectSize> &rects, std::vector<Rect> &dst, bool merge,
// FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod);
/// Computes the ratio of used/total surface area. 0.00 means no space is yet used, 1.00 means the whole bin is used.
float Occupancy() const;
/// Returns the internal list of disjoint rectangles that track the free area of the bin. You may alter this vector
/// any way desired, as long as the end result still is a list of disjoint rectangles.
std::vector<Rect> &GetFreeRectangles() { return freeRectangles; }
/// Returns the list of packed rectangles. You may alter this vector at will, for example, you can move a Rect from
/// this list to the Free Rectangles list to free up space on-the-fly, but notice that this causes fragmentation.
std::vector<Rect> &GetUsedRectangles() { return usedRectangles; }
/// Performs a Rectangle Merge operation. This procedure looks for adjacent free rectangles and merges them if they
/// can be represented with a single rectangle. Takes up Theta(|freeRectangles|^2) time.
void MergeFreeList();
private:
int binWidth;
int binHeight;
/// Stores a list of all the rectangles that we have packed so far. This is used only to compute the Occupancy ratio,
/// so if you want to have the packer consume less memory, this can be removed.
std::vector<Rect> usedRectangles;
/// Stores a list of rectangles that represents the free area of the bin. This rectangles in this list are disjoint.
std::vector<Rect> freeRectangles;
#ifdef _DEBUG
/// Used to track that the packer produces proper packings.
DisjointRectCollection disjointRects;
#endif
/// Goes through the list of free rectangles and finds the best one to place a rectangle of given size into.
/// Running time is Theta(|freeRectangles|).
/// @param nodeIndex [out] The index of the free rectangle in the freeRectangles array into which the new
/// rect was placed.
/// @return A Rect structure that represents the placement of the new rect into the best free rectangle.
Rect FindPositionForNewNode(int width, int height, FreeRectChoiceHeuristic rectChoice, int *nodeIndex);
static int ScoreByHeuristic(int width, int height, const Rect &freeRect, FreeRectChoiceHeuristic rectChoice);
// The following functions compute (penalty) score values if a rect of the given size was placed into the
// given free rectangle. In these score values, smaller is better.
static int ScoreBestAreaFit(int width, int height, const Rect &freeRect);
static int ScoreBestShortSideFit(int width, int height, const Rect &freeRect);
static int ScoreBestLongSideFit(int width, int height, const Rect &freeRect);
static int ScoreWorstAreaFit(int width, int height, const Rect &freeRect);
static int ScoreWorstShortSideFit(int width, int height, const Rect &freeRect);
static int ScoreWorstLongSideFit(int width, int height, const Rect &freeRect);
/// Splits the given L-shaped free rectangle into two new free rectangles after placedRect has been placed into it.
/// Determines the split axis by using the given heuristic.
void SplitFreeRectByHeuristic(const Rect &freeRect, const Rect &placedRect, GuillotineSplitHeuristic method);
/// Splits the given L-shaped free rectangle into two new free rectangles along the given fixed split axis.
void SplitFreeRectAlongAxis(const Rect &freeRect, const Rect &placedRect, bool splitHorizontal);
};
}
-51
View File
@@ -1,51 +0,0 @@
/** @file Rect.cpp
@author Jukka Jylänki
This work is released to Public Domain, do whatever you want with it.
*/
#include <utility>
#include "Rect.h"
namespace rbp {
/*
#include "clb/Algorithm/Sort.h"
int CompareRectShortSide(const Rect &a, const Rect &b)
{
using namespace std;
int smallerSideA = min(a.width, a.height);
int smallerSideB = min(b.width, b.height);
if (smallerSideA != smallerSideB)
return clb::sort::TriCmp(smallerSideA, smallerSideB);
// Tie-break on the larger side.
int largerSideA = max(a.width, a.height);
int largerSideB = max(b.width, b.height);
return clb::sort::TriCmp(largerSideA, largerSideB);
}
*/
/*
int NodeSortCmp(const Rect &a, const Rect &b)
{
if (a.x != b.x)
return clb::sort::TriCmp(a.x, b.x);
if (a.y != b.y)
return clb::sort::TriCmp(a.y, b.y);
if (a.width != b.width)
return clb::sort::TriCmp(a.width, b.width);
return clb::sort::TriCmp(a.height, b.height);
}
*/
bool IsContainedIn(const Rect &a, const Rect &b)
{
return a.x >= b.x && a.y >= b.y
&& a.x+a.width <= b.x+b.width
&& a.y+a.height <= b.y+b.height;
}
}
-94
View File
@@ -1,94 +0,0 @@
/** @file Rect.h
@author Jukka Jylänki
This work is released to Public Domain, do whatever you want with it.
*/
#pragma once
#include <vector>
#include <cassert>
#include <cstdlib>
#ifdef _DEBUG
/// debug_assert is an assert that also requires debug mode to be defined.
#define debug_assert(x) assert(x)
#else
#define debug_assert(x)
#endif
//using namespace std;
namespace rbp {
struct RectSize
{
int width;
int height;
};
struct Rect
{
int x;
int y;
int width;
int height;
};
/// Performs a lexicographic compare on (rect short side, rect long side).
/// @return -1 if the smaller side of a is shorter than the smaller side of b, 1 if the other way around.
/// If they are equal, the larger side length is used as a tie-breaker.
/// If the rectangles are of same size, returns 0.
int CompareRectShortSide(const Rect &a, const Rect &b);
/// Performs a lexicographic compare on (x, y, width, height).
int NodeSortCmp(const Rect &a, const Rect &b);
/// Returns true if a is contained in b.
bool IsContainedIn(const Rect &a, const Rect &b);
class DisjointRectCollection
{
public:
std::vector<Rect> rects;
bool Add(const Rect &r)
{
// Degenerate rectangles are ignored.
if (r.width == 0 || r.height == 0)
return true;
if (!Disjoint(r))
return false;
rects.push_back(r);
return true;
}
void Clear()
{
rects.clear();
}
bool Disjoint(const Rect &r) const
{
// Degenerate rectangles are ignored.
if (r.width == 0 || r.height == 0)
return true;
for(size_t i = 0; i < rects.size(); ++i)
if (!Disjoint(rects[i], r))
return false;
return true;
}
static bool Disjoint(const Rect &a, const Rect &b)
{
if (a.x + a.width <= b.x ||
b.x + b.width <= a.x ||
a.y + a.height <= b.y ||
b.y + b.height <= a.y)
return true;
return false;
}
};
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-446
View File
@@ -1,446 +0,0 @@
#ifndef RAPIDXML_PRINT_HPP_INCLUDED
#define RAPIDXML_PRINT_HPP_INCLUDED
// Copyright (C) 2006, 2009 Marcin Kalicinski
// Version 1.13
// Revision $DateTime: 2009/05/13 01:46:17 $
//! \file rapidxml_print.hpp This file contains rapidxml printer implementation
#include "rapidxml.hpp"
// Only include streams if not disabled
#ifndef RAPIDXML_NO_STREAMS
#include <ostream>
#include <iterator>
#endif
namespace rapidxml
{
///////////////////////////////////////////////////////////////////////
// Printing flags
const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
///////////////////////////////////////////////////////////////////////
// Internal
//! \cond internal
namespace internal
{
///////////////////////////////////////////////////////////////////////////
// Internal character operations
// Copy characters from given range to given output iterator
template<class OutIt, class Ch>
inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
{
while (begin != end)
*out++ = *begin++;
return out;
}
// Copy characters from given range to given output iterator and expand
// characters into references (&lt; &gt; &apos; &quot; &amp;)
template<class OutIt, class Ch>
inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
{
while (begin != end)
{
if (*begin == noexpand)
{
*out++ = *begin; // No expansion, copy character
}
else
{
switch (*begin)
{
case Ch('<'):
*out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
break;
case Ch('>'):
*out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
break;
case Ch('\''):
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';');
break;
case Ch('"'):
*out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
break;
case Ch('&'):
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
break;
default:
*out++ = *begin; // No expansion, copy character
}
}
++begin; // Step to next character
}
return out;
}
// Fill given output iterator with repetitions of the same character
template<class OutIt, class Ch>
inline OutIt fill_chars(OutIt out, int n, Ch ch)
{
for (int i = 0; i < n; ++i)
*out++ = ch;
return out;
}
// Find character
template<class Ch, Ch ch>
inline bool find_char(const Ch *begin, const Ch *end)
{
while (begin != end)
if (*begin++ == ch)
return true;
return false;
}
///////////////////////////////////////////////////////////////////////////
// Internal printing operations
template<class OutIt, class Ch>
inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent);
template<class OutIt, class Ch>
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags);
template<class OutIt, class Ch>
inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
template<class OutIt, class Ch>
inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
template<class OutIt, class Ch>
inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
template<class OutIt, class Ch>
inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
template<class OutIt, class Ch>
inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
template<class OutIt, class Ch>
inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
template<class OutIt, class Ch>
inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
// Print node
template<class OutIt, class Ch>
inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
// Print proper node type
switch (node->type())
{
// Document
case node_document:
out = print_children(out, node, flags, indent);
break;
// Element
case node_element:
out = print_element_node(out, node, flags, indent);
break;
// Data
case node_data:
out = print_data_node(out, node, flags, indent);
break;
// CDATA
case node_cdata:
out = print_cdata_node(out, node, flags, indent);
break;
// Declaration
case node_declaration:
out = print_declaration_node(out, node, flags, indent);
break;
// Comment
case node_comment:
out = print_comment_node(out, node, flags, indent);
break;
// Doctype
case node_doctype:
out = print_doctype_node(out, node, flags, indent);
break;
// Pi
case node_pi:
out = print_pi_node(out, node, flags, indent);
break;
// Unknown
default:
assert(0);
break;
}
// If indenting not disabled, add line break after node
if (!(flags & print_no_indenting))
*out = Ch('\n'), ++out;
// Return modified iterator
return out;
}
// Print children of the node
template<class OutIt, class Ch>
inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
out = print_node(out, child, flags, indent);
return out;
}
// Print attributes of the node
template<class OutIt, class Ch>
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
{
for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
{
if (attribute->name() && attribute->value())
{
// Print attribute name
*out = Ch(' '), ++out;
out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
*out = Ch('='), ++out;
// Print attribute value using appropriate quote type
if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
{
*out = Ch('\''), ++out;
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
*out = Ch('\''), ++out;
}
else
{
*out = Ch('"'), ++out;
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
*out = Ch('"'), ++out;
}
}
}
return out;
}
// Print data node
template<class OutIt, class Ch>
inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_data);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
return out;
}
// Print data node
template<class OutIt, class Ch>
inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_cdata);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'); ++out;
*out = Ch('!'); ++out;
*out = Ch('['); ++out;
*out = Ch('C'); ++out;
*out = Ch('D'); ++out;
*out = Ch('A'); ++out;
*out = Ch('T'); ++out;
*out = Ch('A'); ++out;
*out = Ch('['); ++out;
out = copy_chars(node->value(), node->value() + node->value_size(), out);
*out = Ch(']'); ++out;
*out = Ch(']'); ++out;
*out = Ch('>'); ++out;
return out;
}
// Print element node
template<class OutIt, class Ch>
inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_element);
// Print element name and attributes, if any
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
out = copy_chars(node->name(), node->name() + node->name_size(), out);
out = print_attributes(out, node, flags);
// If node is childless
if (node->value_size() == 0 && !node->first_node())
{
// Print childless node tag ending
*out = Ch('/'), ++out;
*out = Ch('>'), ++out;
}
else
{
// Print normal node tag ending
*out = Ch('>'), ++out;
// Test if node contains a single data node only (and no other nodes)
xml_node<Ch> *child = node->first_node();
if (!child)
{
// If node has no children, only print its value without indenting
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
}
else if (child->next_sibling() == 0 && child->type() == node_data)
{
// If node has a sole data child, only print its value without indenting
out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
}
else
{
// Print all children with full indenting
if (!(flags & print_no_indenting))
*out = Ch('\n'), ++out;
out = print_children(out, node, flags, indent + 1);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
}
// Print node end
*out = Ch('<'), ++out;
*out = Ch('/'), ++out;
out = copy_chars(node->name(), node->name() + node->name_size(), out);
*out = Ch('>'), ++out;
}
return out;
}
// Print declaration node
template<class OutIt, class Ch>
inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
// Print declaration start
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
*out = Ch('?'), ++out;
*out = Ch('x'), ++out;
*out = Ch('m'), ++out;
*out = Ch('l'), ++out;
// Print attributes
out = print_attributes(out, node, flags);
// Print declaration end
*out = Ch('?'), ++out;
*out = Ch('>'), ++out;
return out;
}
// Print comment node
template<class OutIt, class Ch>
inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_comment);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
*out = Ch('!'), ++out;
*out = Ch('-'), ++out;
*out = Ch('-'), ++out;
out = copy_chars(node->value(), node->value() + node->value_size(), out);
*out = Ch('-'), ++out;
*out = Ch('-'), ++out;
*out = Ch('>'), ++out;
return out;
}
// Print doctype node
template<class OutIt, class Ch>
inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_doctype);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
*out = Ch('!'), ++out;
*out = Ch('D'), ++out;
*out = Ch('O'), ++out;
*out = Ch('C'), ++out;
*out = Ch('T'), ++out;
*out = Ch('Y'), ++out;
*out = Ch('P'), ++out;
*out = Ch('E'), ++out;
*out = Ch(' '), ++out;
out = copy_chars(node->value(), node->value() + node->value_size(), out);
*out = Ch('>'), ++out;
return out;
}
// Print pi node
template<class OutIt, class Ch>
inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_pi);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
*out = Ch('?'), ++out;
out = copy_chars(node->name(), node->name() + node->name_size(), out);
*out = Ch(' '), ++out;
out = copy_chars(node->value(), node->value() + node->value_size(), out);
*out = Ch('?'), ++out;
*out = Ch('>'), ++out;
return out;
}
}
//! \endcond
///////////////////////////////////////////////////////////////////////////
// Printing
//! Prints XML to given output iterator.
//! \param out Output iterator to print to.
//! \param node Node to be printed. Pass xml_document to print entire document.
//! \param flags Flags controlling how XML is printed.
//! \return Output iterator pointing to position immediately after last character of printed text.
template<class OutIt, class Ch>
inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
{
return internal::print_node(out, &node, flags, 0);
}
#ifndef RAPIDXML_NO_STREAMS
//! Prints XML to given output stream.
//! \param out Output stream to print to.
//! \param node Node to be printed. Pass xml_document to print entire document.
//! \param flags Flags controlling how XML is printed.
//! \return Output stream.
template<class Ch>
inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
{
print(std::ostream_iterator<Ch>(out), node, flags);
return out;
}
//! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
//! \param out Output stream to print to.
//! \param node Node to be printed.
//! \return Output stream.
template<class Ch>
inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
{
return print(out, node);
}
#endif
}
#endif
-37
View File
@@ -1,37 +0,0 @@
// stb_dxt.cpp - Real-Time DXT1/DXT5 compressor
// Based on original by fabian "ryg" giesen v1.04
// Custom version, modified by Yann Collet
//
/*
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
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.
You can contact the author at :
- RygsDXTc source repository : http://code.google.com/p/rygsdxtc/
*/
#define STB_DXT_IMPLEMENTATION
#include "stb_dxt.h"

Some files were not shown because too many files have changed in this diff Show More