cmake_minimum_required(VERSION 3.21)
include(${PROJECT_SOURCE_DIR}/cmake/template_instantiation.cmake)
add_instantiation_files(${PROJECT_SOURCE_DIR}/common/cuda_hip matrix/csr_kernels.instantiate.cpp CSR_INSTANTIATE)
add_instantiation_files(${PROJECT_SOURCE_DIR}/common/cuda_hip matrix/fbcsr_kernels.instantiate.cpp FBCSR_INSTANTIATE)
add_instantiation_files(${PROJECT_SOURCE_DIR}/common/cuda_hip solver/batch_bicgstab_launch.instantiate.cpp BATCH_BICGSTAB_INSTANTIATE)
add_instantiation_files(${PROJECT_SOURCE_DIR}/common/cuda_hip solver/batch_cg_launch.instantiate.cpp BATCH_CG_INSTANTIATE)
# we don't split up the dense kernels into distinct compilations
list(
    APPEND
    GKO_UNIFIED_COMMON_SOURCES
    ${PROJECT_SOURCE_DIR}/common/unified/matrix/dense_kernels.instantiate.cpp
)
set(GINKGO_HIP_SOURCES
    base/device.hip.cpp
    base/exception.hip.cpp
    base/executor.hip.cpp
    base/memory.hip.cpp
    base/roctx.hip.cpp
    base/scoped_device_id.hip.cpp
    base/stream.hip.cpp
    base/timer.hip.cpp
    base/version.hip.cpp
    ${CSR_INSTANTIATE}
    ${FBCSR_INSTANTIATE}
    preconditioner/batch_jacobi_kernels.hip.cpp
    solver/batch_bicgstab_kernels.hip.cpp
    ${BATCH_BICGSTAB_INSTANTIATE}
    solver/batch_cg_kernels.hip.cpp
    ${BATCH_CG_INSTANTIATE}
    solver/lower_trs_kernels.hip.cpp
    solver/upper_trs_kernels.hip.cpp
    ${GKO_UNIFIED_COMMON_SOURCES}
    ${GKO_CUDA_HIP_COMMON_SOURCES}
)

if(hipfft_FOUND)
    list(APPEND GINKGO_HIP_SOURCES matrix/fft_kernels.hip.cpp)
else()
    list(APPEND GINKGO_HIP_SOURCES matrix/fft_kernels_stub.hip.cpp)
endif()

set(GKO_HIP_JACOBI_MAX_BLOCK_SIZE 64)
if(GINKGO_JACOBI_FULL_OPTIMIZATIONS)
    set(GKO_HIP_JACOBI_BLOCK_SIZES)
    foreach(blocksize RANGE 1 ${GKO_HIP_JACOBI_MAX_BLOCK_SIZE})
        list(APPEND GKO_HIP_JACOBI_BLOCK_SIZES ${blocksize})
    endforeach()
else()
    set(GKO_HIP_JACOBI_BLOCK_SIZES
        1
        2
        4
        8
        13
        16
        32
        ${GKO_HIP_JACOBI_MAX_BLOCK_SIZE}
    )
    list(REMOVE_DUPLICATES GKO_HIP_JACOBI_BLOCK_SIZES)
endif()
jacobi_generated_files(GKO_HIP_JACOBI_SOURCES "${GKO_HIP_JACOBI_BLOCK_SIZES}")
# The 3D indexing used in Jacobi kernel triggers an instruction selection bug in Debug builds
# Probably the same as https://github.com/llvm/llvm-project/issues/67574
# Fixed in ROCm 6.0 https://github.com/ROCm/llvm-project/commit/cd7f574a1fd1d3f3e8b9c1cae61fa8133a51de5f
# and in LLVM trunk https://github.com/llvm/llvm-project/commit/cc3d2533cc2e4ea06981b86ede5087fbf801e789
set_source_files_properties(
    ${GKO_HIP_JACOBI_SOURCES}
    PROPERTIES COMPILE_OPTIONS $<$<CONFIG:Debug>:-O2>
)
list(APPEND GINKGO_HIP_SOURCES ${GKO_HIP_JACOBI_SOURCES})
string(
    REPLACE
    ";"
    ","
    GKO_JACOBI_BLOCK_SIZES_CODE
    "${GKO_HIP_JACOBI_BLOCK_SIZES}"
)
configure_file(
    ${Ginkgo_SOURCE_DIR}/common/cuda_hip/preconditioner/jacobi_common.hpp.in
    common/cuda_hip/preconditioner/jacobi_common.hpp
)

set_source_files_properties(${GINKGO_HIP_SOURCES} PROPERTIES LANGUAGE HIP)
add_library(
    ginkgo_hip
    $<TARGET_OBJECTS:ginkgo_hip_device>
    ${GINKGO_HIP_SOURCES}
)

target_include_directories(
    ginkgo_hip
    PRIVATE
        ${CMAKE_CURRENT_BINARY_DIR} # for generated headers like jacobi_common.hip.hpp
)
target_compile_definitions(
    ginkgo_hip
    PRIVATE GKO_COMPILING_HIP GKO_DEVICE_NAMESPACE=hip
)
if(GINKGO_HIP_CUSTOM_THRUST_NAMESPACE)
    target_compile_definitions(
        ginkgo_hip
        PRIVATE THRUST_CUB_WRAPPED_NAMESPACE=gko
    )
endif()

target_link_libraries(ginkgo_hip PUBLIC ginkgo_device)
target_link_libraries(
    ginkgo_hip
    PRIVATE
        hip::host
        roc::hipblas
        roc::hipsparse
        hip::hiprand
        roc::rocrand
        roc::rocthrust
)
if(hipfft_FOUND)
    target_link_libraries(ginkgo_hip PRIVATE hip::hipfft)
endif()
if(GINKGO_HAVE_ROCTX)
    target_link_libraries(ginkgo_hip PRIVATE roc::roctx)
endif()

target_compile_options(
    ginkgo_hip
    PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${GINKGO_COMPILER_FLAGS}>
)

ginkgo_compile_features(ginkgo_hip)
ginkgo_default_includes(ginkgo_hip)
ginkgo_install_library(ginkgo_hip)

if(GINKGO_CHECK_CIRCULAR_DEPS)
    set(check_header_def "GKO_COMPILING_HIP;GKO_DEVICE_NAMESPACE=hip")
    if(GINKGO_HIP_CUSTOM_THRUST_NAMESPACE)
        set(check_header_def
            "${check_header_def};THRUST_CUB_WRAPPED_NAMESPACE=gko"
        )
    endif()
    ginkgo_check_headers(ginkgo_hip "${check_header_def}")
endif()

if(GINKGO_BUILD_TESTS)
    add_subdirectory(test)
endif()
