mirror of
https://github.com/opencv/opencv.git
synced 2026-07-30 15:53:03 +04:00
37c9ab1815
Fix MLAS 32-bit x86 build by integrating missing upstream assembly files #29226 ### Pull Request Readiness Checklist This resolves the 32-bit x86 build failure for MLAS. Related to: https://github.com/opencv/opencv/pull/29218 * Added the required `x86` assembly files and headers from upstream. * Added `__x86_64__` guards around the AMX `syscall` and the FMA3/AVX512F kernel assignments to prevent 32-bit compilation crashes. See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x] The feature is well documented and sample code can be built with the project CMake
269 lines
12 KiB
CMake
269 lines
12 KiB
CMake
# Vendored from microsoft/onnxruntime onnxruntime/core/mlas/. License: MIT.
|
|
# See LICENSE and README.md in this directory for provenance.
|
|
#
|
|
# Vendored subset: SGEMM (sgemm.cpp + arch kernels) plus MlasFlashAttention
|
|
# (flashattn.cpp) and the portable softmax kernels it needs from compute.cpp.
|
|
# Non-SGEMM / non-FlashAttention dispatch lines in lib/platform.cpp are
|
|
# `#if 0`'d out (search for "MLAS_GEMM_ONLY"). Re-vendoring upstream
|
|
# requires re-applying that patch.
|
|
#
|
|
# Local patches against upstream:
|
|
# - lib/threading.cpp -> modules/dnn/src/layers/cpu_kernels/mlas_threading.cpp
|
|
# (cv::parallel_for_).
|
|
# - mlasi.h: MlasGetMaximumThreadCount() returns cv::getNumThreads().
|
|
# - lib/core/common/{narrow,common}.h shims for ORT internals MLAS uses.
|
|
# - lib/platform.cpp: non-SGEMM dispatch removed (`#if 0` blocks), and
|
|
# ReduceMaximumF32Kernel / ComputeSumExpF32Kernel initialized to the
|
|
# portable compute.cpp fallbacks.
|
|
|
|
set(MLAS_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lib)
|
|
set(MLAS_INC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/inc)
|
|
|
|
# Hardware-agnostic core: SGEMM dispatch + softmax/exp kernels + flash-attention.
|
|
set(mlas_common_srcs
|
|
${MLAS_SRC_DIR}/platform.cpp
|
|
${CMAKE_SOURCE_DIR}/modules/dnn/src/layers/cpu_kernels/mlas_threading.cpp
|
|
${MLAS_SRC_DIR}/sgemm.cpp
|
|
${MLAS_SRC_DIR}/compute.cpp
|
|
${MLAS_SRC_DIR}/flashattn.cpp
|
|
)
|
|
|
|
# Architecture detection — same as ORT's onnxruntime_mlas.cmake.
|
|
set(MLAS_ARM FALSE CACHE INTERNAL "" FORCE)
|
|
set(MLAS_ARM64 FALSE CACHE INTERNAL "" FORCE)
|
|
set(MLAS_POWER FALSE CACHE INTERNAL "" FORCE)
|
|
set(MLAS_X86 FALSE CACHE INTERNAL "" FORCE)
|
|
set(MLAS_X86_64 FALSE CACHE INTERNAL "" FORCE)
|
|
set(MLAS_RISCV64 FALSE CACHE INTERNAL "" FORCE)
|
|
set(MLAS_LOONGARCH64 FALSE CACHE INTERNAL "" FORCE)
|
|
set(MLAS_S390X FALSE CACHE INTERNAL "" FORCE)
|
|
set(MLAS_WASM FALSE CACHE INTERNAL "" FORCE)
|
|
|
|
if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
|
|
set(MLAS_WASM TRUE CACHE INTERNAL "" FORCE)
|
|
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm64.*")
|
|
set(MLAS_ARM64 TRUE CACHE INTERNAL "" FORCE)
|
|
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^aarch64.*")
|
|
set(MLAS_ARM64 TRUE CACHE INTERNAL "" FORCE)
|
|
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm.*")
|
|
set(MLAS_ARM TRUE CACHE INTERNAL "" FORCE)
|
|
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc.*|ppc.*)")
|
|
set(MLAS_POWER TRUE CACHE INTERNAL "" FORCE)
|
|
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(i.86|x86?)$")
|
|
set(MLAS_X86 TRUE CACHE INTERNAL "" FORCE)
|
|
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|AMD64)$")
|
|
set(MLAS_X86_64 TRUE CACHE INTERNAL "" FORCE)
|
|
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^riscv64.*")
|
|
set(MLAS_RISCV64 TRUE CACHE INTERNAL "" FORCE)
|
|
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^loongarch64.*")
|
|
set(MLAS_LOONGARCH64 TRUE CACHE INTERNAL "" FORCE)
|
|
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^s390x$")
|
|
set(MLAS_S390X TRUE CACHE INTERNAL "" FORCE)
|
|
endif()
|
|
|
|
set(mlas_platform_srcs)
|
|
|
|
# State flags consumed by the top-level config summary's PNG-style chain:
|
|
# OPENCV_DNN_MLAS_ENABLED — 1 if MLAS compiled in, 0 if skipped/unavailable
|
|
# OPENCV_DNN_MLAS_SKIP_REASON — human-readable reason for the NO case
|
|
# Cleared in modules/dnn/CMakeLists.txt before add_subdirectory() so stale
|
|
# values don't survive a config where MLAS is no longer reached.
|
|
set(OPENCV_DNN_MLAS_ENABLED 0 CACHE INTERNAL "" FORCE)
|
|
set(OPENCV_DNN_MLAS_SKIP_REASON "" CACHE INTERNAL "" FORCE)
|
|
|
|
# Probe ASM language once. check_language(ASM) is a no-op when
|
|
# CMAKE_ASM_COMPILER is already set in cache — and the Android NDK toolchain
|
|
# pre-sets it for every ABI. So on Android the guard falls through to
|
|
# enable_language(ASM), which then fails at generate time with
|
|
# "CMAKE_ASM_COMPILE_OBJECT not set" on the NDK + CMake 3.22.1 combo CI uses.
|
|
# Skip MLAS on Android for the ASM-using arches; the DNN module falls back to
|
|
# its built-in SGEMM. Android armv7a stays enabled via the C++-only
|
|
# sgemmc.cpp path under MLAS_ARM below.
|
|
set(_MLAS_REQUIRES_ASM FALSE)
|
|
if(MLAS_X86_64 OR MLAS_X86 OR MLAS_ARM64 OR MLAS_LOONGARCH64)
|
|
set(_MLAS_REQUIRES_ASM TRUE)
|
|
endif()
|
|
|
|
include(CheckLanguage)
|
|
set(MLAS_HAS_ASM FALSE CACHE INTERNAL "" FORCE)
|
|
check_language(ASM)
|
|
if(CMAKE_ASM_COMPILER)
|
|
enable_language(ASM)
|
|
set(MLAS_HAS_ASM TRUE CACHE INTERNAL "" FORCE)
|
|
elseif(_MLAS_REQUIRES_ASM)
|
|
set(OPENCV_DNN_MLAS_SKIP_REASON
|
|
"no ASM compiler available for ${CMAKE_SYSTEM_PROCESSOR}"
|
|
CACHE INTERNAL "" FORCE)
|
|
message(WARNING "MLAS: ASM language unavailable on ${CMAKE_SYSTEM_PROCESSOR}; "
|
|
"MLAS disabled (DNN will use its built-in SGEMM)")
|
|
return()
|
|
endif()
|
|
|
|
# x86_64 SGEMM kernels: MlasGemmFloatKernelSse / Avx / Fma3 / Avx512F
|
|
# plus the M=1 fast paths and B-packing helpers.
|
|
if(MLAS_X86_64)
|
|
list(APPEND mlas_platform_srcs
|
|
${MLAS_SRC_DIR}/x86_64/SgemmKernelSse2.S
|
|
${MLAS_SRC_DIR}/x86_64/SgemmTransposePackB16x4Sse2.S
|
|
${MLAS_SRC_DIR}/x86_64/SgemmKernelAvx.S
|
|
${MLAS_SRC_DIR}/x86_64/SgemmKernelM1Avx.S
|
|
${MLAS_SRC_DIR}/x86_64/SgemmKernelM1TransposeBAvx.S
|
|
${MLAS_SRC_DIR}/x86_64/SgemmTransposePackB16x4Avx.S
|
|
${MLAS_SRC_DIR}/x86_64/SgemmKernelFma3.S
|
|
${MLAS_SRC_DIR}/x86_64/SgemmKernelAvx512F.S
|
|
)
|
|
set_source_files_properties(${MLAS_SRC_DIR}/x86_64/SgemmKernelSse2.S
|
|
${MLAS_SRC_DIR}/x86_64/SgemmTransposePackB16x4Sse2.S
|
|
PROPERTIES COMPILE_FLAGS "-msse2")
|
|
set_source_files_properties(${MLAS_SRC_DIR}/x86_64/SgemmKernelAvx.S
|
|
${MLAS_SRC_DIR}/x86_64/SgemmKernelM1Avx.S
|
|
${MLAS_SRC_DIR}/x86_64/SgemmKernelM1TransposeBAvx.S
|
|
${MLAS_SRC_DIR}/x86_64/SgemmTransposePackB16x4Avx.S
|
|
PROPERTIES COMPILE_FLAGS "-mavx")
|
|
set_source_files_properties(${MLAS_SRC_DIR}/x86_64/SgemmKernelFma3.S
|
|
PROPERTIES COMPILE_FLAGS "-mavx2 -mfma -mf16c")
|
|
set_source_files_properties(${MLAS_SRC_DIR}/x86_64/SgemmKernelAvx512F.S
|
|
PROPERTIES COMPILE_FLAGS "-mavx512f")
|
|
endif()
|
|
|
|
# i386 / 32-bit x86 SGEMM kernels.
|
|
if(MLAS_X86)
|
|
list(APPEND mlas_platform_srcs
|
|
${MLAS_SRC_DIR}/x86/SgemmKernelSse2.S
|
|
${MLAS_SRC_DIR}/x86/SgemmKernelAvx.S
|
|
)
|
|
set_source_files_properties(${MLAS_SRC_DIR}/x86/SgemmKernelSse2.S PROPERTIES COMPILE_FLAGS "-msse2")
|
|
set_source_files_properties(${MLAS_SRC_DIR}/x86/SgemmKernelAvx.S PROPERTIES COMPILE_FLAGS "-mavx")
|
|
if(ANDROID)
|
|
list(APPEND mlas_platform_srcs ${MLAS_SRC_DIR}/x86/x86.get_pc_thunk.S)
|
|
endif()
|
|
endif()
|
|
|
|
# ARM 32-bit: pure C++ sgemmc (no .S kernels).
|
|
if(MLAS_ARM)
|
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=neon")
|
|
list(APPEND mlas_platform_srcs ${MLAS_SRC_DIR}/arm/sgemmc.cpp)
|
|
endif()
|
|
|
|
# ARM64 / AArch64.
|
|
if(MLAS_ARM64)
|
|
list(APPEND mlas_platform_srcs
|
|
${MLAS_SRC_DIR}/aarch64/SgemmKernelNeon.S
|
|
${MLAS_SRC_DIR}/aarch64/SgemvKernelNeon.S
|
|
)
|
|
endif()
|
|
|
|
# POWER (ppc64le / AIX). Always compile the base SgemmKernelPower; opt-in
|
|
# POWER10 if the compiler supports -mcpu=power10.
|
|
if(MLAS_POWER)
|
|
list(APPEND mlas_platform_srcs ${MLAS_SRC_DIR}/power/SgemmKernelPower.cpp)
|
|
set_source_files_properties(${MLAS_SRC_DIR}/power/SgemmKernelPower.cpp
|
|
PROPERTIES COMPILE_FLAGS "-DSINGLE")
|
|
include(CheckCXXCompilerFlag)
|
|
check_cxx_compiler_flag("-mcpu=power10" MLAS_HAS_POWER10)
|
|
set(MLAS_HAS_POWER10 ${MLAS_HAS_POWER10} CACHE INTERNAL "" FORCE)
|
|
if(MLAS_HAS_POWER10 AND MLAS_HAS_ASM)
|
|
list(APPEND mlas_platform_srcs ${MLAS_SRC_DIR}/power/SgemmKernelPOWER10.cpp)
|
|
if(NOT AIX)
|
|
list(APPEND mlas_platform_srcs ${MLAS_SRC_DIR}/power/SgemmKernelPackA.S)
|
|
set_source_files_properties(${MLAS_SRC_DIR}/power/SgemmKernelPackA.S
|
|
PROPERTIES COMPILE_FLAGS "-O2 -mcpu=power10")
|
|
endif()
|
|
set_source_files_properties(${MLAS_SRC_DIR}/power/SgemmKernelPOWER10.cpp
|
|
PROPERTIES COMPILE_FLAGS "-O2 -mcpu=power10 -DSINGLE")
|
|
endif()
|
|
endif()
|
|
|
|
# LoongArch 64 (LSX + LASX).
|
|
if(MLAS_LOONGARCH64)
|
|
list(APPEND mlas_platform_srcs
|
|
${MLAS_SRC_DIR}/loongarch64/SgemmKernelLsx.S
|
|
${MLAS_SRC_DIR}/loongarch64/SgemmTransposePackB16x4LSX.S
|
|
${MLAS_SRC_DIR}/loongarch64/SgemmKernelLasx.S
|
|
${MLAS_SRC_DIR}/loongarch64/SgemmTransposePackB16x4Lasx.S
|
|
)
|
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mlsx -mlasx")
|
|
endif()
|
|
|
|
# IBM s390x (z/Architecture, ZVECTOR).
|
|
if(MLAS_S390X)
|
|
list(APPEND mlas_platform_srcs
|
|
${MLAS_SRC_DIR}/s390x/SgemmKernel.cpp
|
|
${MLAS_SRC_DIR}/s390x/SgemmKernelZVECTOR.cpp
|
|
)
|
|
set_source_files_properties(${MLAS_SRC_DIR}/s390x/SgemmKernel.cpp PROPERTIES COMPILE_FLAGS "-DSINGLE")
|
|
set_source_files_properties(${MLAS_SRC_DIR}/s390x/SgemmKernelZVECTOR.cpp PROPERTIES COMPILE_FLAGS "-DSINGLE")
|
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mvx -mzvector -march=z15")
|
|
endif()
|
|
|
|
# RISC-V 64. RVV vector kernels iff the compiler supports rv64gcv.
|
|
if(MLAS_RISCV64)
|
|
include(CheckCXXSourceCompiles)
|
|
set(_old "${CMAKE_REQUIRED_FLAGS}")
|
|
set(CMAKE_REQUIRED_FLAGS "-march=rv64gcv -mabi=lp64d")
|
|
check_cxx_source_compiles("
|
|
#include <stddef.h>
|
|
#include <riscv_vector.h>
|
|
int main() { size_t vl = __riscv_vsetvl_e32m1(4); return static_cast<int>(vl == 0); }"
|
|
MLAS_HAS_RISCV64_RVV)
|
|
set(CMAKE_REQUIRED_FLAGS "${_old}")
|
|
set(MLAS_HAS_RISCV64_RVV ${MLAS_HAS_RISCV64_RVV} CACHE INTERNAL "" FORCE)
|
|
if(MLAS_HAS_RISCV64_RVV)
|
|
list(APPEND mlas_platform_srcs
|
|
${MLAS_SRC_DIR}/riscv64/sgemm_pack_b_rvv.cpp
|
|
${MLAS_SRC_DIR}/riscv64/sgemm_kernel_rvv.cpp
|
|
)
|
|
foreach(f
|
|
${MLAS_SRC_DIR}/riscv64/sgemm_pack_b_rvv.cpp
|
|
${MLAS_SRC_DIR}/riscv64/sgemm_kernel_rvv.cpp)
|
|
set_source_files_properties(${f} PROPERTIES COMPILE_FLAGS "-march=rv64gcv -mabi=lp64d")
|
|
endforeach()
|
|
endif()
|
|
# Scalar MlasSgemmKernelZero/Add fallback for non-RVV runtime/build.
|
|
list(APPEND mlas_platform_srcs ${MLAS_SRC_DIR}/scalar/SgemmKernelScalar.cpp)
|
|
endif()
|
|
|
|
# WASM / unknown archs use the scalar sgemm path; link its kernel.
|
|
if(MLAS_WASM OR NOT (MLAS_X86 OR MLAS_X86_64 OR MLAS_ARM OR MLAS_ARM64
|
|
OR MLAS_POWER OR MLAS_LOONGARCH64 OR MLAS_S390X
|
|
OR MLAS_RISCV64))
|
|
list(APPEND mlas_platform_srcs ${MLAS_SRC_DIR}/scalar/SgemmKernelScalar.cpp)
|
|
endif()
|
|
|
|
add_library(opencv_dnn_mlas OBJECT ${mlas_common_srcs} ${mlas_platform_srcs})
|
|
set_target_properties(opencv_dnn_mlas PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
|
target_include_directories(opencv_dnn_mlas PUBLIC ${MLAS_INC_DIR})
|
|
target_include_directories(opencv_dnn_mlas PRIVATE ${MLAS_SRC_DIR})
|
|
target_include_directories(opencv_dnn_mlas PRIVATE ${CMAKE_SOURCE_DIR}/modules/core/include)
|
|
|
|
target_compile_definitions(opencv_dnn_mlas PRIVATE
|
|
BUILD_MLAS_NO_ONNXRUNTIME=1
|
|
MLAS_OPENCV_THREADING=1
|
|
MLAS_GEMM_ONLY=1
|
|
)
|
|
|
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
|
target_compile_options(opencv_dnn_mlas PRIVATE
|
|
"$<$<COMPILE_LANGUAGE:CXX>:-w>"
|
|
"$<$<COMPILE_LANGUAGE:CXX>:-include>"
|
|
"$<$<COMPILE_LANGUAGE:CXX>:cstring>"
|
|
)
|
|
# MLAS .S files lack .note.GNU-stack; tell the assembler the stack is non-exec.
|
|
target_compile_options(opencv_dnn_mlas PRIVATE
|
|
"$<$<COMPILE_LANGUAGE:ASM>:-Wa,--noexecstack>"
|
|
)
|
|
endif()
|
|
# platform.cpp's MlasInitAMX() calls syscall() but only includes <sys/syscall.h>,
|
|
# not <unistd.h> where glibc declares it. It's compiled on both x86 and x86_64
|
|
# (shared MLAS_TARGET_AMD64_IX86 block), so force-include unistd.h on both.
|
|
# MSVC has no unistd.h and its _WIN32 path doesn't use syscall() anyway.
|
|
if((MLAS_X86_64 OR MLAS_X86) AND NOT WIN32)
|
|
set_source_files_properties(${MLAS_SRC_DIR}/platform.cpp
|
|
PROPERTIES COMPILE_FLAGS "-include unistd.h")
|
|
endif()
|
|
|
|
set(HAVE_MLAS 1 PARENT_SCOPE)
|
|
set(MLAS_OBJECTS $<TARGET_OBJECTS:opencv_dnn_mlas> PARENT_SCOPE)
|
|
set(MLAS_INCLUDE_DIRS ${MLAS_INC_DIR} PARENT_SCOPE)
|
|
set(OPENCV_DNN_MLAS_ENABLED 1 CACHE INTERNAL "" FORCE)
|