cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
project(sring LANGUAGES CXX)

set(SRING_SOURCES
        sring_impl.h
        sring_kernel_impl.h
        sring_impl.cpp
        sring_standard_char.cpp
        sring_standard_int8.cpp
        sring_standard_uint8.cpp
        sring_standard_int16.cpp
        sring_standard_uint16.cpp
        sring_standard_int32.cpp
        sring_standard_uint32.cpp
        sring_standard_int64.cpp
        sring_standard_uint64.cpp
        sring_standard_int128.cpp
        sring_standard_uint128.cpp
        sring_standard_fp32.cpp
        sring_standard_fp64.cpp
        sring_standard_cfp32.cpp
        sring_standard_cfp64.cpp
        sring_standard_bigint.cpp
        sring_boolean_int8.cpp
        sring_maxplus_char.cpp
        sring_maxplus_int8.cpp
        sring_maxplus_uint8.cpp
        sring_maxplus_int16.cpp
        sring_maxplus_uint16.cpp
        sring_maxplus_int32.cpp
        sring_maxplus_uint32.cpp
        sring_maxplus_int64.cpp
        sring_maxplus_uint64.cpp
        sring_maxplus_int128.cpp
        sring_maxplus_uint128.cpp
        sring_maxplus_fp32.cpp
        sring_maxplus_fp64.cpp
)

# GCC 9 introduced loop versioning for runtime strides at -O3.  For the
# recursive 8/16-bit reorder kernels this more than doubles the generated hot
# code and slows real contraction paths down substantially.  GCC also enables
# extra per-loop/function alignment which further bloats these already large
# kernels.  Keep the legacy compact code generation for all affected
# small-integer semiring translation units; wider types and ARM are unaffected.
set(SRING_GCC_SMALL_INTEGER_SOURCES
        sring_standard_char.cpp
        sring_standard_int8.cpp
        sring_standard_uint8.cpp
        sring_standard_int16.cpp
        sring_standard_uint16.cpp
        sring_boolean_int8.cpp
        sring_maxplus_char.cpp
        sring_maxplus_int8.cpp
        sring_maxplus_uint8.cpp
        sring_maxplus_int16.cpp
        sring_maxplus_uint16.cpp
)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
        AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "9"
        AND CMAKE_SYSTEM_PROCESSOR MATCHES
            "^(x86_64|X86_64|amd64|AMD64)$")
    set_source_files_properties(
            ${SRING_GCC_SMALL_INTEGER_SOURCES}
            PROPERTIES COMPILE_OPTIONS
            "-fno-version-loops-for-strides;-fno-align-functions;-fno-align-jumps;-fno-align-loops")
endif()

if(NOT APPLE)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static")
endif()

add_library(sring STATIC ${SRING_SOURCES})

set(SRING_ENABLE_PCH_DEFAULT ON)
if(MINGW)
    set(SRING_ENABLE_PCH_DEFAULT OFF)
endif()
option(SRING_ENABLE_PCH "Enable SRing precompiled headers"
       ${SRING_ENABLE_PCH_DEFAULT})
if(SRING_ENABLE_PCH AND COMMAND target_precompile_headers)
    target_precompile_headers(sring PRIVATE sring_kernel_impl.h)
    set_source_files_properties(sring_impl.cpp PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
endif()

add_subdirectory(highway)
if(SESUM_BUILD_X86_VARIANT STREQUAL "avx2")
    # The wheel already dispatches between complete ISA-specific libraries.
    # Prevent Highway from embedding newer runtime-dispatch targets and expose
    # the selected profile to SRing's compile-time validation below.
    target_compile_definitions(hwy PUBLIC
            HWY_COMPILE_ONLY_STATIC
            SESUM_X86_PROFILE_AVX2)
elseif(SESUM_BUILD_X86_VARIANT STREQUAL "avx512")
    target_compile_definitions(hwy PUBLIC
            HWY_COMPILE_ONLY_STATIC
            SESUM_X86_PROFILE_AVX512)
endif()
add_subdirectory(hptt)
add_subdirectory(pprint)
add_subdirectory(large_types)

if(APPLE AND CMAKE_SYSTEM_PROCESSOR MATCHES
        "^(arm64|ARM64|aarch64|AARCH64)$")
    find_library(ACCELERATE_LIBRARY Accelerate REQUIRED)
    target_include_directories(sring PUBLIC ./)
    target_link_libraries(sring PUBLIC hwy hptt pprint large_types ${ACCELERATE_LIBRARY})
else ()
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-uninitialized -Wno-maybe-uninitialized -Wno-unused-variable -Wno-unused-function -Wno-int-to-pointer-cast")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-uninitialized -Wno-maybe-uninitialized -Wno-unused-variable -Wno-unused-function -Wno-int-to-pointer-cast")
    set(BUILD_STATIC_LIBS ON CACHE BOOL "Build OpenBLAS static libraries" FORCE)
    set(BUILD_WITHOUT_LAPACK ON CACHE BOOL "Build OpenBLAS without LAPACK" FORCE)
    set(BUILD_LAPACK_DEPRECATED OFF CACHE BOOL "Build deprecated LAPACK routines" FORCE)
    set(BUILD_TESTING OFF CACHE BOOL "Build dependency tests" FORCE)
    set(NO_LAPACK ON CACHE BOOL "Disable LAPACK" FORCE)
    set(ONLY_CBLAS ON CACHE BOOL "Build only the CBLAS interface" FORCE)
    set(NUM_THREADS 256 CACHE STRING "Maximum number of OpenBLAS threads" FORCE)
    if(SESUM_BUILD_X86_VARIANT STREQUAL "avx2")
        set(DYNAMIC_ARCH OFF CACHE BOOL
            "Disable OpenBLAS runtime ISA dispatch" FORCE)
        set(TARGET HASWELL CACHE STRING "OpenBLAS target" FORCE)
        set(NO_AVX OFF CACHE BOOL "Enable AVX" FORCE)
        set(NO_AVX2 OFF CACHE BOOL "Enable AVX2" FORCE)
        set(NO_AVX512 ON CACHE BOOL "Disable AVX-512" FORCE)
    elseif(SESUM_BUILD_X86_VARIANT STREQUAL "avx512")
        set(DYNAMIC_ARCH OFF CACHE BOOL
            "Disable OpenBLAS runtime ISA dispatch" FORCE)
        set(TARGET SKYLAKEX CACHE STRING "OpenBLAS target" FORCE)
        set(NO_AVX OFF CACHE BOOL "Enable AVX" FORCE)
        set(NO_AVX2 OFF CACHE BOOL "Enable AVX2" FORCE)
        set(NO_AVX512 OFF CACHE BOOL "Enable AVX-512" FORCE)
    elseif(CMAKE_SYSTEM_PROCESSOR MATCHES
            "^(arm64|ARM64|aarch64|AARCH64)$"
            AND SESUM_BUILD_ARM64_VARIANT STREQUAL "arm64")
        # Do not let OpenBLAS probe the build host and select an SVE- or
        # microarchitecture-specific kernel for a portable ARM64 package.
        # This also covers native Windows ARM64, where OpenBLAS is used in
        # place of Apple's Accelerate framework.
        set(DYNAMIC_ARCH OFF CACHE BOOL
            "Disable OpenBLAS runtime ISA dispatch" FORCE)
        set(TARGET ARMV8 CACHE STRING "OpenBLAS target" FORCE)
    endif()
    # OpenBLAS enables ASM in its nested project.  CMake propagates the
    # deployment target automatically to C/C++, but not to these Darwin
    # assembly invocations.  Without the explicit flag, Homebrew GCC builds
    # the selected x86 kernel objects for the host macOS version; linking
    # those objects into a lower-target dylib can silently break the Haswell
    # double-precision GEMM kernel.  Set only the OS floor here—the selected
    # OpenBLAS target still controls the AVX2/AVX-512 instruction contract.
    if(APPLE)
        if("${CMAKE_OSX_DEPLOYMENT_TARGET}" STREQUAL "")
            message(FATAL_ERROR
                "Apple OpenBLAS assembly requires a deployment target.")
        endif()
        # Replace a stale value rather than appending on every reconfigure.
        string(REGEX REPLACE
            "(^|[ \t])-mmacosx-version-min=[^ \t]+" ""
            SESUM_MACOS_ASM_FLAGS "${CMAKE_ASM_FLAGS}")
        string(STRIP "${SESUM_MACOS_ASM_FLAGS}" SESUM_MACOS_ASM_FLAGS)
        set(CMAKE_ASM_FLAGS
            "${SESUM_MACOS_ASM_FLAGS} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}")
    endif()
    add_subdirectory(OpenBLAS)
    target_include_directories(sring PUBLIC ./ "${CMAKE_CURRENT_SOURCE_DIR}/OpenBLAS"
            "${CMAKE_CURRENT_BINARY_DIR}/OpenBLAS")
    target_link_libraries(sring PUBLIC hwy hptt pprint large_types openblas)
endif()
