cmake_minimum_required(VERSION 3.18)

# CMake must know the deployment target before the first project()/language
# initialization.  Otherwise a native build silently inherits the build
# machine's macOS version and the resulting wheel becomes needlessly tied to
# that host.  Respect every explicit user, environment, toolchain, cross-build
# and subproject policy; only supply portable defaults for native top-level
# macOS builds.
if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}"
        AND CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin"
        AND (NOT DEFINED CMAKE_SYSTEM_NAME
             OR "${CMAKE_SYSTEM_NAME}" STREQUAL "")
        AND (NOT DEFINED CMAKE_TOOLCHAIN_FILE
             OR "${CMAKE_TOOLCHAIN_FILE}" STREQUAL "")
        AND (NOT DEFINED ENV{CMAKE_TOOLCHAIN_FILE}
             OR "$ENV{CMAKE_TOOLCHAIN_FILE}" STREQUAL ""))
    set(SESUM_MACOS_X86_64_DEPLOYMENT_TARGET "10.15" CACHE STRING
        "Default minimum macOS version for Sesum x86-64 builds")
    set(SESUM_MACOS_ARM64_DEPLOYMENT_TARGET "11.0" CACHE STRING
        "Default minimum macOS version for Sesum ARM64 builds")

    if("${CMAKE_OSX_DEPLOYMENT_TARGET}" STREQUAL ""
            AND "$ENV{MACOSX_DEPLOYMENT_TARGET}" STREQUAL "")
        set(SESUM_OSX_REQUESTED_ARCHITECTURES "")
        if(NOT "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "")
            set(SESUM_OSX_REQUESTED_ARCHITECTURES
                "${CMAKE_OSX_ARCHITECTURES}")
        elseif(NOT "$ENV{CMAKE_OSX_ARCHITECTURES}" STREQUAL "")
            set(SESUM_OSX_REQUESTED_ARCHITECTURES
                "$ENV{CMAKE_OSX_ARCHITECTURES}")
        endif()

        if(NOT "${SESUM_OSX_REQUESTED_ARCHITECTURES}" STREQUAL "")
            set(SESUM_OSX_ARCH_LIST
                "${SESUM_OSX_REQUESTED_ARCHITECTURES}")
            list(LENGTH SESUM_OSX_ARCH_LIST SESUM_OSX_ARCH_COUNT)
            if(NOT SESUM_OSX_ARCH_COUNT EQUAL 1)
                message(FATAL_ERROR
                    "Sesum libraries must be thin binaries; requested "
                    "macOS architectures: "
                    "'${SESUM_OSX_REQUESTED_ARCHITECTURES}'.")
            endif()
            list(GET SESUM_OSX_ARCH_LIST 0 SESUM_OSX_BUILD_ARCH)
        elseif(NOT "${CMAKE_APPLE_SILICON_PROCESSOR}" STREQUAL "")
            set(SESUM_OSX_BUILD_ARCH
                "${CMAKE_APPLE_SILICON_PROCESSOR}")
        elseif(NOT "$ENV{CMAKE_APPLE_SILICON_PROCESSOR}" STREQUAL "")
            set(SESUM_OSX_BUILD_ARCH
                "$ENV{CMAKE_APPLE_SILICON_PROCESSOR}")
        else()
            execute_process(
                COMMAND /usr/bin/uname -m
                RESULT_VARIABLE SESUM_OSX_UNAME_RESULT
                OUTPUT_VARIABLE SESUM_OSX_BUILD_ARCH
                OUTPUT_STRIP_TRAILING_WHITESPACE)
            if(NOT SESUM_OSX_UNAME_RESULT EQUAL 0)
                message(FATAL_ERROR
                    "Failed to determine the native macOS architecture.")
            endif()
        endif()

        string(TOLOWER "${SESUM_OSX_BUILD_ARCH}" SESUM_OSX_BUILD_ARCH)
        if(SESUM_OSX_BUILD_ARCH MATCHES "^(arm64|aarch64)$")
            set(SESUM_OSX_DEFAULT_DEPLOYMENT_TARGET
                "${SESUM_MACOS_ARM64_DEPLOYMENT_TARGET}")
        elseif(SESUM_OSX_BUILD_ARCH MATCHES "^(x86_64|amd64)$")
            set(SESUM_OSX_DEFAULT_DEPLOYMENT_TARGET
                "${SESUM_MACOS_X86_64_DEPLOYMENT_TARGET}")
        else()
            message(FATAL_ERROR
                "Unsupported native macOS architecture "
                "'${SESUM_OSX_BUILD_ARCH}'.")
        endif()

        # FORCE is restricted to an empty value so an older CMake/CLion cache
        # containing CMAKE_OSX_DEPLOYMENT_TARGET:STRING= is repaired, while a
        # non-empty user value above is never overwritten.
        set(CMAKE_OSX_DEPLOYMENT_TARGET
            "${SESUM_OSX_DEFAULT_DEPLOYMENT_TARGET}" CACHE STRING
            "Minimum macOS version targeted by Sesum" FORCE)
    endif()
endif()

project(Sesum LANGUAGES C CXX)

if(APPLE)
    message(STATUS
        "Sesum macOS deployment target: ${CMAKE_OSX_DEPLOYMENT_TARGET}")
endif()

option(SESUM_USE_COMPILER_CACHE "Use ccache/sccache when available" ON)
option(SESUM_ENABLE_PCH "Enable SESUM precompiled headers" OFF)
option(SRING_ENABLE_PCH "Enable SRing precompiled headers" OFF)

# CMake emits Apple's Clang-only -Xarch_arm64 flag for PCH builds. Homebrew
# GCC rejects that flag, so also repair older CLion caches which still contain
# the former ON default.
if(APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
    set(SESUM_ENABLE_PCH OFF CACHE BOOL "Enable SESUM precompiled headers" FORCE)
    set(SRING_ENABLE_PCH OFF CACHE BOOL "Enable SRing precompiled headers" FORCE)
endif()

if(SESUM_USE_COMPILER_CACHE)
    find_program(SESUM_CCACHE ccache)
    find_program(SESUM_SCCACHE sccache)
    if(SESUM_CCACHE)
        set(CMAKE_C_COMPILER_LAUNCHER "${SESUM_CCACHE}")
        set(CMAKE_CXX_COMPILER_LAUNCHER "${SESUM_CCACHE}")
    elseif(SESUM_SCCACHE)
        set(CMAKE_C_COMPILER_LAUNCHER "${SESUM_SCCACHE}")
        set(CMAKE_CXX_COMPILER_LAUNCHER "${SESUM_SCCACHE}")
    endif()
endif()

set(IS_WINDOWS_ARM64_CLANG_TARGET OFF)
if(WIN32 AND CMAKE_SYSTEM_PROCESSOR MATCHES
        "^(arm64|ARM64|aarch64|AARCH64)$")
    set(IS_WINDOWS_ARM64_CLANG_TARGET ON)
endif()

if(IS_WINDOWS_ARM64_CLANG_TARGET)
    if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
        message(FATAL_ERROR "Windows ARM64 requires clang/clang++.")
    endif()
else()
    if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
        message(FATAL_ERROR "Only g++/GNU is supported on non-Windows-ARM64 targets.")
    endif()
endif()
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
    message(FATAL_ERROR "Only 64-bit systems are supported!")
endif()

# The package directory is selected from CMAKE_SYSTEM_PROCESSOR.  A fat or
# contradictory Darwin override would otherwise place a differently sliced
# dylib in a misleading mac_arm64/mac_avx* directory.
if(APPLE AND NOT "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "")
    set(SESUM_OSX_ARCHITECTURES ${CMAKE_OSX_ARCHITECTURES})
    list(LENGTH SESUM_OSX_ARCHITECTURES SESUM_OSX_ARCHITECTURE_COUNT)
    if(NOT SESUM_OSX_ARCHITECTURE_COUNT EQUAL 1)
        message(FATAL_ERROR
            "Sesum libraries must be thin binaries; CMAKE_OSX_ARCHITECTURES="
            "'${CMAKE_OSX_ARCHITECTURES}' selects multiple architectures.")
    endif()
    list(GET SESUM_OSX_ARCHITECTURES 0 SESUM_OSX_ARCHITECTURE)
    if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|ARM64|aarch64|AARCH64)$")
        set(SESUM_EXPECTED_OSX_ARCHITECTURE "arm64")
    elseif(CMAKE_SYSTEM_PROCESSOR MATCHES
            "^(x86_64|X86_64|amd64|AMD64)$")
        set(SESUM_EXPECTED_OSX_ARCHITECTURE "x86_64")
    else()
        message(FATAL_ERROR
            "Unsupported Darwin build processor '${CMAKE_SYSTEM_PROCESSOR}'.")
    endif()
    if(NOT "${SESUM_OSX_ARCHITECTURE}" STREQUAL
            "${SESUM_EXPECTED_OSX_ARCHITECTURE}")
        message(FATAL_ERROR
            "CMAKE_OSX_ARCHITECTURES='${SESUM_OSX_ARCHITECTURE}' conflicts "
            "with CMAKE_SYSTEM_PROCESSOR='${CMAKE_SYSTEM_PROCESSOR}'; "
            "refusing to write a mislabeled Sesum package directory.")
    endif()
endif()

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp -std=c++17 -Ofast -Wall -ftree-vectorize -funroll-loops -DNDEBUG -fno-strict-aliasing -Wno-format -Wno-class-memaccess -Wno-deprecated-declarations -fvisibility=hidden")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Ofast -Wall -ftree-vectorize -funroll-loops -DNDEBUG -fvisibility=hidden")
if(NOT WIN32)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static-libgcc")
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffunction-sections -fdata-sections")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections")
endif()
if(IS_WINDOWS_ARM64_CLANG_TARGET AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
    add_compile_definitions(NOMINMAX)
endif()

set(SESUM_X86_TARGET "avx2" CACHE STRING "x86 ISA target: avx2, avx512, or native")
set_property(CACHE SESUM_X86_TARGET PROPERTY STRINGS avx2 avx512 native)
set(SESUM_LINUX_ARM64_TARGET "portable" CACHE STRING
    "Linux ARM64 ISA target: portable or native")
set_property(CACHE SESUM_LINUX_ARM64_TARGET PROPERTY STRINGS portable native)
set(SESUM_BUILD_X86_VARIANT "")
set(SESUM_BUILD_ARM64_VARIANT "arm64")
set(SESUM_ARCH_CXX_FLAGS "")
set(SESUM_ARCH_C_FLAGS "")
set(SESUM_X86_AVX2_BASE_FLAGS
    "-march=x86-64 -mavx2 -mfma -mbmi -mbmi2 -mf16c -maes -mpclmul -mpopcnt -mlzcnt")

function(sesum_reject_external_machine_flags SESUM_PROFILE_SELECTOR)
    # Portable variants are a closed ISA contract.  Silently accepting an
    # environment/toolchain -march or feature switch would make the output
    # depend on flag ordering and could broaden a packaged library.
    set(SESUM_MACHINE_FLAG_VARIABLES
        CMAKE_C_FLAGS
        CMAKE_CXX_FLAGS
        CMAKE_ASM_FLAGS
        CMAKE_C_FLAGS_DEBUG
        CMAKE_CXX_FLAGS_DEBUG
        CMAKE_ASM_FLAGS_DEBUG
        CMAKE_C_FLAGS_RELEASE
        CMAKE_CXX_FLAGS_RELEASE
        CMAKE_ASM_FLAGS_RELEASE
        CMAKE_C_FLAGS_RELWITHDEBINFO
        CMAKE_CXX_FLAGS_RELWITHDEBINFO
        CMAKE_ASM_FLAGS_RELWITHDEBINFO
        CMAKE_C_FLAGS_MINSIZEREL
        CMAKE_CXX_FLAGS_MINSIZEREL
        CMAKE_ASM_FLAGS_MINSIZEREL)
    foreach(SESUM_FLAG_VARIABLE IN LISTS SESUM_MACHINE_FLAG_VARIABLES)
        if(DEFINED ${SESUM_FLAG_VARIABLE})
            separate_arguments(SESUM_EXTERNAL_FLAGS NATIVE_COMMAND
                "${${SESUM_FLAG_VARIABLE}}")
            foreach(SESUM_EXTERNAL_FLAG IN LISTS SESUM_EXTERNAL_FLAGS)
                # Fail closed for every GCC/Clang machine option, not just a
                # list of currently known ISA extensions.  -m64 fixes the
                # already-required ABI, while the macOS deployment flag sets
                # an OS version rather than a CPU feature.
                set(SESUM_FLAG_IS_MACHINE_OPTION OFF)
                if(SESUM_EXTERNAL_FLAG MATCHES "^-m")
                    set(SESUM_FLAG_IS_MACHINE_OPTION ON)
                    if(SESUM_EXTERNAL_FLAG STREQUAL "-m64"
                            AND CMAKE_SYSTEM_PROCESSOR MATCHES
                                "(x86_64|X86_64|amd64|AMD64)")
                        set(SESUM_FLAG_IS_MACHINE_OPTION OFF)
                    elseif(APPLE AND SESUM_EXTERNAL_FLAG MATCHES
                            "^-mmacosx-version-min=")
                        set(SESUM_FLAG_IS_MACHINE_OPTION OFF)
                    endif()
                elseif(SESUM_EXTERNAL_FLAG MATCHES "^/[Aa][Rr][Cc][Hh]:"
                        OR SESUM_EXTERNAL_FLAG MATCHES "^-Xarch_"
                        OR SESUM_EXTERNAL_FLAG MATCHES "^-Wa,.*-m"
                        OR SESUM_EXTERNAL_FLAG STREQUAL "-Xassembler"
                        OR SESUM_EXTERNAL_FLAG STREQUAL "-arch"
                        OR SESUM_EXTERNAL_FLAG STREQUAL "-target"
                        OR SESUM_EXTERNAL_FLAG MATCHES "^--target=")
                    set(SESUM_FLAG_IS_MACHINE_OPTION ON)
                endif()
                if(SESUM_FLAG_IS_MACHINE_OPTION)
                    message(FATAL_ERROR
                        "${SESUM_FLAG_VARIABLE} contains external machine "
                        "flag '${SESUM_EXTERNAL_FLAG}'. Portable Sesum builds "
                        "accept machine/ISA flags only through "
                        "${SESUM_PROFILE_SELECTOR}. Remove the external "
                        "flag; host tuning is allowed only through a platform "
                        "profile that explicitly supports a native target.")
                endif()
            endforeach()
        endif()
    endforeach()

    # ASM is enabled later by vendored OpenBLAS, so CMake has not necessarily
    # imported ASMFLAGS yet.  Inspect the raw environment as well as the
    # initialized C/C++ variables above.
    foreach(SESUM_ENV_FLAG_VARIABLE IN ITEMS CFLAGS CXXFLAGS CPPFLAGS ASMFLAGS)
        if(DEFINED ENV{${SESUM_ENV_FLAG_VARIABLE}})
            separate_arguments(SESUM_EXTERNAL_ENV_FLAGS NATIVE_COMMAND
                "$ENV{${SESUM_ENV_FLAG_VARIABLE}}")
            foreach(SESUM_EXTERNAL_FLAG IN LISTS SESUM_EXTERNAL_ENV_FLAGS)
                set(SESUM_FLAG_IS_MACHINE_OPTION OFF)
                if(SESUM_EXTERNAL_FLAG MATCHES "^-m")
                    set(SESUM_FLAG_IS_MACHINE_OPTION ON)
                    if(SESUM_EXTERNAL_FLAG STREQUAL "-m64"
                            AND CMAKE_SYSTEM_PROCESSOR MATCHES
                                "(x86_64|X86_64|amd64|AMD64)")
                        set(SESUM_FLAG_IS_MACHINE_OPTION OFF)
                    elseif(APPLE AND SESUM_EXTERNAL_FLAG MATCHES
                            "^-mmacosx-version-min=")
                        set(SESUM_FLAG_IS_MACHINE_OPTION OFF)
                    endif()
                elseif(SESUM_EXTERNAL_FLAG MATCHES "^/[Aa][Rr][Cc][Hh]:"
                        OR SESUM_EXTERNAL_FLAG MATCHES "^-Xarch_"
                        OR SESUM_EXTERNAL_FLAG MATCHES "^-Wa,.*-m"
                        OR SESUM_EXTERNAL_FLAG STREQUAL "-Xassembler"
                        OR SESUM_EXTERNAL_FLAG STREQUAL "-arch"
                        OR SESUM_EXTERNAL_FLAG STREQUAL "-target"
                        OR SESUM_EXTERNAL_FLAG MATCHES "^--target=")
                    set(SESUM_FLAG_IS_MACHINE_OPTION ON)
                endif()
                if(SESUM_FLAG_IS_MACHINE_OPTION)
                    message(FATAL_ERROR
                        "Environment ${SESUM_ENV_FLAG_VARIABLE} contains "
                        "external machine flag '${SESUM_EXTERNAL_FLAG}'. "
                        "Portable Sesum builds accept machine/ISA flags only "
                        "through ${SESUM_PROFILE_SELECTOR}.")
                endif()
            endforeach()
        endif()
    endforeach()
endfunction()

if(APPLE AND CMAKE_SYSTEM_PROCESSOR MATCHES
        "^(arm64|ARM64|aarch64|AARCH64)$")
    sesum_reject_external_machine_flags("the Apple ARM64 portable profile")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flax-vector-conversions")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -flax-vector-conversions")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES
        "^(x86_64|X86_64|amd64|AMD64)$")
    if(SESUM_X86_TARGET STREQUAL "native")
        # Native builds are intentionally kept out of distributable ISA
        # directories: -march=native may enable features beyond the loader's
        # portable AVX2/AVX-512 contracts.
        set(SESUM_BUILD_X86_VARIANT "native")
        set(SESUM_ARCH_CXX_FLAGS "-march=native -mtune=native")
        set(SESUM_ARCH_C_FLAGS "-march=native -mtune=native")
    elseif(SESUM_X86_TARGET STREQUAL "avx2")
        sesum_reject_external_machine_flags(
            "SESUM_X86_TARGET=avx2|avx512")
        set(SESUM_BUILD_X86_VARIANT "avx2")
        # Host-independent Haswell-class AVX2 contract.  Keep the feature
        # switches explicit so configuring on an AVX-512 host cannot leak
        # AVX-512 instructions into this variant.
        set(SESUM_ARCH_CXX_FLAGS
            "${SESUM_X86_AVX2_BASE_FLAGS} -mno-avx512f -mtune=haswell")
        set(SESUM_ARCH_C_FLAGS
            "${SESUM_X86_AVX2_BASE_FLAGS} -mno-avx512f -mtune=haswell")
    elseif(SESUM_X86_TARGET STREQUAL "avx512")
        sesum_reject_external_machine_flags(
            "SESUM_X86_TARGET=avx2|avx512")
        set(SESUM_BUILD_X86_VARIANT "avx512")
        # Host-independent Skylake-X contract.  AVX512CD is required by
        # Highway's AVX3 target in addition to F/DQ/BW/VL.
        set(SESUM_ARCH_CXX_FLAGS
            "${SESUM_X86_AVX2_BASE_FLAGS} -mavx512f -mavx512cd -mavx512dq -mavx512bw -mavx512vl -mtune=skylake-avx512")
        set(SESUM_ARCH_C_FLAGS
            "${SESUM_X86_AVX2_BASE_FLAGS} -mavx512f -mavx512cd -mavx512dq -mavx512bw -mavx512vl -mtune=skylake-avx512")
    else()
        message(FATAL_ERROR "SESUM_X86_TARGET must be native, avx2, or avx512")
    endif()
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SESUM_ARCH_CXX_FLAGS}")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SESUM_ARCH_C_FLAGS}")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES
        "^(arm64|ARM64|aarch64|AARCH64)$")
    if(IS_WINDOWS_ARM64_CLANG_TARGET)
        # Keep the existing portable Windows ARM64 compiler defaults.
        sesum_reject_external_machine_flags(
            "the Windows ARM64 portable profile")
    elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
        if(SESUM_LINUX_ARM64_TARGET STREQUAL "portable")
            sesum_reject_external_machine_flags(
                "SESUM_LINUX_ARM64_TARGET=portable")
            set(SESUM_ARCH_CXX_FLAGS "-march=armv8-a")
            set(SESUM_ARCH_C_FLAGS "-march=armv8-a")
        elseif(SESUM_LINUX_ARM64_TARGET STREQUAL "native")
            # As on x86, a host-tuned build has a separate, non-packageable
            # output directory.
            set(SESUM_BUILD_ARM64_VARIANT "native")
            set(SESUM_ARCH_CXX_FLAGS "-march=native -mtune=native")
            set(SESUM_ARCH_C_FLAGS "-march=native -mtune=native")
        else()
            message(FATAL_ERROR
                "SESUM_LINUX_ARM64_TARGET must be portable or native")
        endif()
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SESUM_ARCH_CXX_FLAGS}")
        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SESUM_ARCH_C_FLAGS}")
    else()
        # Preserve the previous behavior for other non-Apple ARM64 Unix
        # targets, but do not label the result as a portable ARM64 package.
        set(SESUM_BUILD_ARM64_VARIANT "native")
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -mtune=native")
        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native -mtune=native")
    endif()
elseif(NOT IS_WINDOWS_ARM64_CLANG_TARGET)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -mtune=native")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native -mtune=native")
endif()

# CMAKE_<LANG>_FLAGS_<CONFIG> is emitted after CMAKE_<LANG>_FLAGS and may be
# supplied by an existing cache or the environment.  Re-apply the selected
# contract as directory compile options so a trailing host-tuned config flag
# cannot broaden a portable build.  The initial CMAKE_*_FLAGS copy above is
# still needed by dependency configure checks.
if(SESUM_ARCH_CXX_FLAGS)
    separate_arguments(SESUM_ARCH_CXX_OPTIONS NATIVE_COMMAND
        "${SESUM_ARCH_CXX_FLAGS}")
    foreach(SESUM_ARCH_OPTION IN LISTS SESUM_ARCH_CXX_OPTIONS)
        add_compile_options(
            "$<$<COMPILE_LANGUAGE:CXX>:${SESUM_ARCH_OPTION}>")
    endforeach()
endif()
if(SESUM_ARCH_C_FLAGS)
    separate_arguments(SESUM_ARCH_C_OPTIONS NATIVE_COMMAND
        "${SESUM_ARCH_C_FLAGS}")
    foreach(SESUM_ARCH_OPTION IN LISTS SESUM_ARCH_C_OPTIONS)
        add_compile_options(
            "$<$<COMPILE_LANGUAGE:C>:${SESUM_ARCH_OPTION}>")
    endforeach()
endif()

# Validate both the compiler feature macros and Highway's resulting static
# target.  Highway's AVX3 detection alone does not prove AVX512CD, and a
# partial newer feature (for example VNNI) would not necessarily promote the
# Highway target even though the compiler could emit that instruction.
if(SESUM_BUILD_X86_VARIANT STREQUAL "avx2"
        OR SESUM_BUILD_X86_VARIANT STREQUAL "avx512")
    include(CheckCXXSourceCompiles)
    set(CMAKE_REQUIRED_FLAGS "${SESUM_ARCH_CXX_FLAGS}")
    set(CMAKE_REQUIRED_DEFINITIONS -DHWY_COMPILE_ONLY_STATIC)
    set(CMAKE_REQUIRED_INCLUDES "${CMAKE_SOURCE_DIR}/sring/highway")

    set(SESUM_X86_COMMON_PROFILE_CHECK [=[
#if !defined(__SSE3__) || !defined(__SSSE3__) || !defined(__SSE4_1__) || !defined(__SSE4_2__) || !defined(__AVX__) || !defined(__AVX2__) || !defined(__FMA__) || !defined(__BMI__) || !defined(__BMI2__) || !defined(__F16C__) || !defined(__AES__) || !defined(__PCLMUL__) || !defined(__POPCNT__) || !defined(__LZCNT__)
#error "incomplete Sesum AVX2 base profile"
#endif
]=])
    if(SESUM_BUILD_X86_VARIANT STREQUAL "avx2")
        unset(SESUM_X86_AVX2_PROFILE_IS_EXACT CACHE)
        set(SESUM_X86_PROFILE_CHECK_SOURCE [=[
#include "hwy/detect_targets.h"
]=])
        string(APPEND SESUM_X86_PROFILE_CHECK_SOURCE
            "${SESUM_X86_COMMON_PROFILE_CHECK}")
        string(APPEND SESUM_X86_PROFILE_CHECK_SOURCE [=[
#if defined(__AVX512F__)
#error "AVX-512 is forbidden in the Sesum AVX2 profile"
#endif
#if HWY_STATIC_TARGET != HWY_AVX2 || HWY_TARGETS != HWY_STATIC_TARGET
#error "Highway is not restricted to its static AVX2 target"
#endif
int main() { return 0; }
]=])
        check_cxx_source_compiles(
            "${SESUM_X86_PROFILE_CHECK_SOURCE}"
            SESUM_X86_AVX2_PROFILE_IS_EXACT)
        if(NOT SESUM_X86_AVX2_PROFILE_IS_EXACT)
            message(FATAL_ERROR
                "The compiler/Highway AVX2 macros do not match Sesum's exact "
                "portable profile.")
        endif()
    else()
        unset(SESUM_X86_AVX512_PROFILE_IS_EXACT CACHE)
        set(SESUM_X86_PROFILE_CHECK_SOURCE [=[
#include "hwy/detect_targets.h"
]=])
        string(APPEND SESUM_X86_PROFILE_CHECK_SOURCE
            "${SESUM_X86_COMMON_PROFILE_CHECK}")
        string(APPEND SESUM_X86_PROFILE_CHECK_SOURCE [=[
#if !defined(__AVX512F__) || !defined(__AVX512CD__) || !defined(__AVX512DQ__) || !defined(__AVX512BW__) || !defined(__AVX512VL__)
#error "incomplete Sesum AVX-512 profile"
#endif
#if defined(__AVX512ER__) || defined(__AVX512PF__) || defined(__AVX512IFMA__) || defined(__AVX512VBMI__) || defined(__AVX512VBMI2__) || defined(__AVX512VNNI__) || defined(__AVX512BITALG__) || defined(__AVX512VPOPCNTDQ__) || defined(__AVX5124VNNIW__) || defined(__AVX5124FMAPS__) || defined(__AVX512VP2INTERSECT__) || defined(__AVX512BF16__) || defined(__AVX512FP16__) || defined(__GFNI__) || defined(__VAES__) || defined(__VPCLMULQDQ__) || defined(__AVXVNNI__)
#error "feature outside Sesum's AVX-512F/CD/DQ/BW/VL profile"
#endif
#if HWY_STATIC_TARGET != HWY_AVX3 || HWY_TARGETS != HWY_STATIC_TARGET
#error "Highway is not restricted to its static AVX3 target"
#endif
int main() { return 0; }
]=])
        check_cxx_source_compiles(
            "${SESUM_X86_PROFILE_CHECK_SOURCE}"
            SESUM_X86_AVX512_PROFILE_IS_EXACT)
        if(NOT SESUM_X86_AVX512_PROFILE_IS_EXACT)
            message(FATAL_ERROR
                "The compiler/Highway AVX-512 macros do not match Sesum's "
                "exact F/CD/DQ/BW/VL profile.")
        endif()
    endif()
    unset(CMAKE_REQUIRED_FLAGS)
    unset(CMAKE_REQUIRED_DEFINITIONS)
    unset(CMAKE_REQUIRED_INCLUDES)
endif()

add_subdirectory(contract)
add_subdirectory(sring)
add_subdirectory(sparse)
add_subdirectory(sesum_impl)
# final dynamic library
add_subdirectory(cwrapper)
