cmake_minimum_required(VERSION 3.21)
option(BUILD_FORTRAN_EXAMPLES "Whether to build fortran examples" ON)
set(CMAKE_C_COMPILER icx)
set(CMAKE_CXX_COMPILER icpx)
set(_languages C CXX)

if (BUILD_FORTRAN_EXAMPLES)
  set(_languages ${_languages} Fortran)
  set(CMAKE_Fortran_COMPILER ifx)
endif()

enable_testing()

project(GPUOptGuide
  LANGUAGES ${_languages}
  DESCRIPTION "Code examples from Intel GPU Optimization guide")

set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)

find_package(IntelSYCL REQUIRED)

set(MKL_THREADING tbb_thread)
set(MKL_INTERFACE "ilp64")
set(DPCPP_COMPILER ON)

set(MKL_VERSION_2024 FALSE)
find_package(MKL QUIET)
if(MKL_FOUND)
    if(MKL_VERSION VERSION_GREATER_EQUAL "2024.0.0")
        set(MKL_VERSION_2024 TRUE)
    endif()
endif()
find_package(MKL REQUIRED)

string(CONCAT WARNING_CXX_FLAGS_STR
  "-Wall "
  "-Wextra "
  "-Winit-self "
  "-Wunused-function "
  "-Wuninitialized "
  "-Wmissing-declarations "
  "-fdiagnostics-color=auto "
)
string(REPLACE " " ";" COMMON_CXX_FLAGS "${WARNING_CXX_FLAGS_STR}")

function(add_example_with_mkl name)
  set(_sources ${name}.cpp)
  add_executable(${name} ${_sources})
  add_sycl_to_target(TARGET ${name} SOURCES ${_sources})
  target_compile_options(${name} PRIVATE ${COMMON_CXX_FLAGS})
  if (MKL_VERSION_2024)
    target_link_libraries(${name} PUBLIC MKL::MKL_SYCL)
  else()
    target_link_libraries(${name} PUBLIC MKL::MKL_DPCPP)
  endif()
  add_test(NAME ${name} COMMAND ${name} ${ARGN})
endfunction(add_example_with_mkl)

function(add_fortran_example_with_mkl name)
  if(CMAKE_Fortran_COMPILER)
    set(_sources ${name}.f)
    add_executable(${name} ${_sources})
    add_sycl_to_target(TARGET ${name} SOURCES ${_sources})
    target_compile_options(${name} PRIVATE -warn all)
    target_compile_options(${name} PRIVATE -fpp -free -DMKL_ILP64 -i8)
    set_target_properties(${name} PROPERTIES LINKER_LANGUAGE Fortran)
    if (MKL_VERSION_2024)
      target_link_libraries(${name} PUBLIC MKL::MKL_SYCL)
    else()
      target_link_libraries(${name} PUBLIC MKL::MKL_DPCPP)
    endif()
    add_test(NAME ${name} COMMAND ${name} ${ARGN})
  endif()
endfunction(add_fortran_example_with_mkl)

function(add_example name)
  set(_sources ${name}.cpp)
  add_executable(${name} ${_sources})
  add_sycl_to_target(TARGET ${name} SOURCES ${_sources})
  target_compile_options(${name} PRIVATE ${COMMON_CXX_FLAGS})
  target_link_options(${name} PRIVATE -fsycl-device-code-split=per_kernel)
  add_test(NAME ${name} COMMAND ${name} ${ARGN})
endfunction(add_example)

function(add_openmp_example name)
  set(_sources ${name}.cpp)
  add_executable(${name} ${_sources})
  target_compile_options(${name} PRIVATE ${COMMON_CXX_FLAGS})
  add_test(NAME ${name} COMMAND ${name} ${ARGN})
endfunction(add_openmp_example)

function(add_fortran_example name)
  if(CMAKE_Fortran_COMPILER)
    set(_sources ${name}.f90)
    add_executable(${name} ${_sources})
    add_sycl_to_target(TARGET ${name} SOURCES ${_sources})
    target_compile_options(${name} PRIVATE -warn all)
    set_target_properties(${name} PROPERTIES LINKER_LANGUAGE Fortran)
    add_test(NAME ${name} COMMAND ${name} ${ARGN})
  endif()
endfunction(add_fortran_example)

function(add_fixed_fortran_example name)
  if(CMAKE_Fortran_COMPILER)
    set(_sources ${name}.f)
    add_executable(${name} ${_sources})
    target_compile_options(${name} PRIVATE -warn all)
    set_target_properties(${name} PROPERTIES LINKER_LANGUAGE Fortran)
    add_test(NAME ${name} COMMAND ${name} ${ARGN})
  endif()
endfunction(add_fixed_fortran_example)

function(add_mpi_example name)
  if(MPI_FOUND)
    set(_sources ${name}.cpp)
    add_executable(${name} ${_sources})
    add_sycl_to_target(TARGET ${name} SOURCES ${_sources})
    target_link_libraries(${name} PRIVATE MPI::MPI_CXX)
    add_test(NAME ${name} COMMAND ${name} ${ARGN})
  endif()
endfunction(add_mpi_example)

include_directories(${CMAKE_CURRENT_SOURCE_DIR})

add_subdirectory(atomics)
add_subdirectory(matrix)
add_subdirectory(exec-model)
add_subdirectory(explicit-scaling)
add_subdirectory(io-kernel)
add_subdirectory(jitting)
add_subdirectory(kernels)
add_subdirectory(memory-movement)
add_subdirectory(restrict)
add_subdirectory(slm)
add_subdirectory(usm)
add_subdirectory(sub-group)
add_subdirectory(buffers)
add_subdirectory(buffer-accessors)
add_subdirectory(reduction)
add_subdirectory(conditionals)
add_subdirectory(libraries-kernel)
add_subdirectory(libraries-stdlib)
add_subdirectory(libraries-fcorr)
add_subdirectory(multiple-queue-submission)
add_subdirectory(multiple-devices)
add_subdirectory(multiple-kernel-execution)
add_subdirectory(work-group-size)
add_subdirectory(registers)
add_subdirectory(OpenMP)
add_subdirectory(optimize-data-transfers)
add_subdirectory(MPI)
add_subdirectory(grf-mode-selection)
add_subdirectory(fp-computations)
add_subdirectory(host-device-memory)
add_subdirectory(joint-matrix)
add_subdirectory(local-global-sync)
#add_subdirectory(memory-sharing-with-media)
add_subdirectory(redundant-queues)
add_subdirectory(implicit-scaling)
