diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c52e778..18e89815 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,6 +91,19 @@ macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME) endif() endmacro() +if(UNIX AND PROCESSOR_IS_X86) + include(CheckCSourceCompiles) + check_c_source_compiles(" + #include + int main(void) + { + __builtin_cpu_init(); + }" HAVE_CPU_INIT) + if(NOT HAVE_CPU_INIT) + check_include_file(sys/utsname.h HAVE_UTSNAME_H) + endif() +endif() + # # library : utils # @@ -148,6 +161,18 @@ set_property(TARGET cpu_features PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC} target_include_directories(cpu_features PUBLIC $ ) +if(PROCESSOR_IS_X86) + if(HAVE_CPU_INIT) + target_compile_definitions(cpu_features PRIVATE HAVE_CPU_INIT) + else() + if(HAVE_UTSNAME_H) + target_compile_definitions(cpu_features PRIVATE HAVE_UTSNAME_H) + endif() + if(APPLE) + target_compile_definitions(cpu_features PRIVATE HAVE_SYSCTLBYNAME) + endif() + endif() +endif() add_library(CpuFeature::cpu_features ALIAS cpu_features) # diff --git a/src/cpuinfo_x86.c b/src/cpuinfo_x86.c index 1f27e143..c44f533b 100644 --- a/src/cpuinfo_x86.c +++ b/src/cpuinfo_x86.c @@ -1047,6 +1047,24 @@ typedef struct { bool have_avx512; } OsSupport; +#if defined(CPU_FEATURES_COMPILER_CLANG) || defined(CPU_FEATURES_COMPILER_GCC) +#if defined(HAVE_CPU_INIT) +#include +#else +#if defined(HAVE_UTSNAME_H) +#include "internal/filesystem.h" +#include "internal/stack_line_reader.h" +#include "internal/string_view.h" +#include +#if defined(HAVE_SYSCTLBYNAME) +#include +#endif +#endif +#endif +#elif defined(CPU_FEATURES_COMPILER_MSC) +#include +#endif + // Reference https://en.wikipedia.org/wiki/CPUID. static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info, OsSupport* os_support) { const Leaf leaf_1 = SafeCpuId(max_cpuid_leaf, 1); @@ -1055,9 +1073,57 @@ static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info, OsSupport* const bool have_xsave = IsBitSet(leaf_1.ecx, 26); const bool have_osxsave = IsBitSet(leaf_1.ecx, 27); const uint32_t xcr0_eax = (have_xsave && have_osxsave) ? GetXCR0Eax() : 0; - os_support->have_sse = HasXmmOsXSave(xcr0_eax); - os_support->have_avx = HasYmmOsXSave(xcr0_eax); - os_support->have_avx512 = HasZmmOsXSave(xcr0_eax); + if (xcr0_eax) { + os_support->have_sse = HasXmmOsXSave(xcr0_eax); + os_support->have_avx = HasYmmOsXSave(xcr0_eax); + os_support->have_avx512 = HasZmmOsXSave(xcr0_eax); + } else { +#if defined(CPU_FEATURES_COMPILER_CLANG) || defined(CPU_FEATURES_COMPILER_GCC) +#if defined(HAVE_CPU_INIT) + __builtin_cpu_init(); + os_support->have_sse = __builtin_cpu_supports("sse"); +#else +#if defined(HAVE_UTSNAME_H) + struct utsname buf; + uname(&buf); + if (strncmp(buf.sysname, "Darwin", sizeof(buf.sysname)) == 0) { +#if defined(HAVE_SYSCTLBYNAME) + int enabled, result; + size_t len = sizeof(enabled); + result = sysctlbyname("hw.optional.sse", &enabled, &len, NULL, 0); + if (result == 0) { + os_support->have_sse = enabled; + } +#endif + } else if (strncmp(buf.sysname, "Linux", sizeof(buf.sysname)) == 0) { + const int fd = CpuFeatures_OpenFile("/proc/cpuinfo"); + if (fd >= 0) { + StackLineReader reader; + StackLineReader_Initialize(&reader, fd); + for (;;) { + const LineResult result = StackLineReader_NextLine(&reader); + StringView line = result.line; + StringView key, value; + if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) { + if (CpuFeatures_StringView_IsEquals(key, str("flags"))) { + os_support->have_sse = CpuFeatures_StringView_HasWord(value, "sse"); + break; + } + } + if (result.eof) { + break; + } + } + CpuFeatures_CloseFile(fd); + } + } +#endif // defined(HAVE_UTSNAME_H) +#endif // defined(CPU_FEATURES_COMPILER_CLANG) || defined(CPU_FEATURES_COMPILER_GCC) +#elif defined(CPU_FEATURES_COMPILER_MSC) + // see: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent + os_support->have_sse = IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE); +#endif + } const uint32_t family = ExtractBitRange(leaf_1.eax, 11, 8); const uint32_t extended_family = ExtractBitRange(leaf_1.eax, 27, 20);