--- a/ggml/src/ggml-cpu/arch/x86/cpu-feats.cpp +++ b/ggml/src/ggml-cpu/arch/x86/cpu-feats.cpp @@ -261,10 +261,30 @@ #endif static int ggml_backend_cpu_x86_score() { - // FIXME: this does not check for OS support - int score = 1; cpuid_x86 is; + // CPUID describes hardware; AVX also requires OS-managed XMM/YMM state. + // Keep this selector compiled without architecture flags (upstream design). + unsigned long long xcr0 = 0; + if (is.XSAVE() && is.OSXSAVE()) { +#ifdef _MSC_VER + xcr0 = _xgetbv(0); +#else + unsigned int eax, edx; + __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0)); + xcr0 = (static_cast(edx) << 32) | eax; +#endif + } +#if defined(GGML_AVX) || defined(GGML_AVX2) || defined(GGML_FMA) || defined(GGML_F16C) || defined(GGML_AVX_VNNI) || defined(GGML_AVX512) || defined(GGML_AVX512_VBMI) || defined(GGML_AVX512_BF16) || defined(GGML_AVX512_VNNI) + if (!is.AVX() || (xcr0 & 0x6) != 0x6) { return 0; } +#endif +#if defined(GGML_AVX512) || defined(GGML_AVX512_VBMI) || defined(GGML_AVX512_BF16) || defined(GGML_AVX512_VNNI) + if ((xcr0 & 0xe6) != 0xe6) { return 0; } +#endif +#ifdef GGML_AMX_INT8 + // Tile state also needs OS permission. Searchi does not request it. + return 0; +#endif #ifdef GGML_FMA if (!is.FMA()) { return 0; } --- a/ggml/src/ggml-backend-reg.cpp +++ b/ggml/src/ggml-backend-reg.cpp @@ -582,6 +582,11 @@ bool silent = false; #endif + const char * cpu_only = std::getenv("GGML_CPU_ONLY"); + if (cpu_only && std::strcmp(cpu_only, "1") == 0) { + ggml_backend_load_best("cpu", silent, dir_path); + return; + } ggml_backend_load_best("blas", silent, dir_path); ggml_backend_load_best("zendnn", silent, dir_path); ggml_backend_load_best("cann", silent, dir_path); @@ -590,7 +595,10 @@ ggml_backend_load_best("metal", silent, dir_path); ggml_backend_load_best("rpc", silent, dir_path); ggml_backend_load_best("sycl", silent, dir_path); - ggml_backend_load_best("vulkan", silent, dir_path); + const char * disable_vulkan = std::getenv("GGML_DISABLE_VULKAN"); + if (!disable_vulkan || std::strcmp(disable_vulkan, "1") != 0) { + ggml_backend_load_best("vulkan", silent, dir_path); + } ggml_backend_load_best("virtgpu", silent, dir_path); ggml_backend_load_best("opencl", silent, dir_path); ggml_backend_load_best("hexagon", silent, dir_path); @@ -599,7 +607,7 @@ ggml_backend_load_best("cpu", silent, dir_path); // check the environment variable GGML_BACKEND_PATH to load an out-of-tree backend const char * backend_path = std::getenv("GGML_BACKEND_PATH"); - if (backend_path) { + if (backend_path && dir_path == nullptr) { ggml_backend_load(backend_path); } } --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,9 @@ # Add path to modules list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +if (NOT DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +endif() set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) --- a/ggml/src/ggml-cpu/CMakeLists.txt +++ b/ggml/src/ggml-cpu/CMakeLists.txt @@ -13,7 +13,11 @@ # from inlining architecture-specific instructions into the score function. # Without this, LTO can cause SIGILL when loading backends on older CPUs # (e.g., loading power10 backend on power9 crashes before feature check runs). - target_compile_options(${GGML_CPU_FEATS_NAME} PRIVATE -fno-lto) + if (MSVC) + target_compile_options(${GGML_CPU_FEATS_NAME} PRIVATE /GL-) + else() + target_compile_options(${GGML_CPU_FEATS_NAME} PRIVATE -fno-lto) + endif() target_link_libraries(${cpu_name} PRIVATE ${GGML_CPU_FEATS_NAME}) endfunction()