cmake_minimum_required(VERSION 2.7.8)

project(dot)

if(CMAKE_VERSION VERSION_LESS "2.8.12")
    function(add_compile_options)
        add_definitions(${ARGN})
    endfunction(add_compile_options)
endif()

add_compile_options(-std=c99 -Wall -Wextra -Wno-unused-parameter -Wconversion -Wshadow -pedantic)

SET(DOT_USEFMA 0)
SET(DOT_USEAVX512 0)

if (CMAKE_COMPILER_IS_GNUCC)
    execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
    string(FIND ${GCC_VERSION} "." GCC_VERSION_HAS_DOT)
    if (${GCC_VERSION_HAS_DOT} EQUAL -1)
        execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpfullversion OUTPUT_VARIABLE GCC_VERSION)
    endif()
    if (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7)
        message(STATUS "GCC version >= 4.7")
        SET(DOT_USEFMA 1)
    endif()
    if (GCC_VERSION VERSION_GREATER 7.1 OR GCC_VERSION VERSION_EQUAL 7.1)
        message(STATUS "GCC version >= 7.1")
        add_compile_options(-Wimplicit-fallthrough=0)
        SET(DOT_USEAVX512 1)
    endif()
endif()

add_library(dot src/dot.c)
add_library(dot_naive src/dot_naive.c)
add_library(dot_sse2 src/dot_sse2.c)
add_library(dot_avx src/dot_avx.c)
if(DOT_USEFMA AND DOT_USEAVX512)
    add_library(dot_avxfma src/dot_avx.c)
    add_library(dot_avx512 src/dot_avx512.c)
    add_library(dot_avx512fma src/dot_avx512.c)
    target_link_libraries(dot dot_naive dot_sse2 dot_avx dot_avxfma dot_avx512 dot_avx512fma cpuinfo ${CARET_QT5_LINK})
elseif(DOT_USEFMA)
    add_library(dot_avxfma src/dot_avx.c)
    target_link_libraries(dot dot_naive dot_sse2 dot_avx dot_avxfma cpuinfo ${CARET_QT5_LINK})
elseif(DOT_USEAVX512)
    add_library(dot_avx512 src/dot_avx512.c)
    target_link_libraries(dot dot_naive dot_sse2 dot_avx dot_avx512 cpuinfo ${CARET_QT5_LINK})
else()
    target_link_libraries(dot dot_naive dot_sse2 dot_avx cpuinfo ${CARET_QT5_LINK})
endif()

if(CMAKE_VERSION VERSION_LESS "2.8.12")
    if(DOT_USEFMA AND DOT_USEAVX512)
        set_target_properties(dot_avxfma PROPERTIES COMPILE_FLAGS "-mfma -mavx -funroll-loops")
        set_target_properties(dot_avx512 PROPERTIES COMPILE_FLAGS "-mavx512f -funroll-loops")
        set_target_properties(dot_avx512fma PROPERTIES COMPILE_FLAGS "-mavx512f -mfma -funroll-loops")
    elseif(DOT_USEFMA)
        set_target_properties(dot_avxfma PROPERTIES COMPILE_FLAGS "-mfma -mavx -funroll-loops")
        set_target_properties(dot PROPERTIES COMPILE_FLAGS "-DDOT_NOAVX512")
    elseif(DOT_USEAVX512)
        set_target_properties(dot_avx512 PROPERTIES COMPILE_FLAGS "-mavx512f -funroll-loops")
        set_target_properties(dot PROPERTIES COMPILE_FLAGS "-DDOT_NOFMA")
    else()
        set_target_properties(dot PROPERTIES COMPILE_FLAGS "-DDOT_NOFMA -DDOT_NOAVX512")
    endif()
    set_target_properties(dot_avx PROPERTIES COMPILE_FLAGS "-mavx -funroll-loops")
    set_target_properties(dot_sse2 PROPERTIES COMPILE_FLAGS "-msse2")
    include_directories(../cpuinfo/src)
else()
    if(DOT_USEFMA AND DOT_USEAVX512)
        target_compile_options(dot_avxfma PRIVATE -mfma -mavx -funroll-loops)
        target_compile_options(dot_avx512 PRIVATE -mavx512f -funroll-loops)
        target_compile_options(dot_avx512fma PRIVATE -mavx512f -mfma -funroll-loops)
    elseif(DOT_USEFMA)
        target_compile_options(dot_avxfma PRIVATE -mfma -mavx -funroll-loops)
        target_compile_definitions(dot PRIVATE "DOT_NOAVX512")
    elseif(DOT_USEAVX512)
        target_compile_options(dot_avx512 PRIVATE -mavx512f -funroll-loops)
        target_compile_definitions(dot PRIVATE "DOT_NOFMA")
    else()
        target_compile_definitions(dot PRIVATE "DOT_NOFMA" "DOT_NOAVX512")
    endif()
    target_compile_options(dot_avx PRIVATE -mavx -funroll-loops)
    target_compile_options(dot_sse2 PRIVATE -msse2)
    target_include_directories(dot PRIVATE ../cpuinfo/src)
endif()
