set(IMC_BENCH_NAME "vAes" CACHE STRING "")
set(IMC_BENCH_INFINITE_LOOP 0 CACHE BOOL "")
set(IMC_PRINT_RECOVERY_MESSAGE 0 CACHE BOOL "")
set(IMC_ENABLE_STATIC_LOOP_PASS_COUNT 1 CACHE BOOL "")
set(IMC_ENABLE_ADAPTIVE_LOOP_PASS_COUNT 0 CACHE BOOL "")
set(IMC_MAX_LOOP_IDS 1 CACHE STRING "")
set(IMC_LOOP_PASS_COUNT 10 CACHE BOOL "")
set(IMC_BENCH_REPEAT_COUNT 1 CACHE BOOL "")
set(IMC_PRINT_STATS 0 CACHE BOOL "")
set(IMC_CUSTOM_UNROLL 0 CACHE BOOL "")
set(IMC_LOOP_OPT_DEBUG 0 CACHE BOOL "")
set(IMC_PRINT_INIT_TIME 0 CACHE BOOL "")
set(IMC_PRINT_LATENCY_OVERHEAD 0 CACHE BOOL "")
set(IMC_ENABLE_DYNAMIC_CHECKPOINT 0 CACHE BOOL "")

set(IMC_DUPLICATION_RATIO 100 CACHE BOOL "")

set(AVAILABLE_BENCHES "vBasicMath" "vStringSearch" "vFFT" "vSha" "vCrc" "vMatMul" "vConv2d" "adc_demo" "vAes" "fmc_expr" "vrefint_expr")
if(NOT IMC_BENCH_NAME IN_LIST AVAILABLE_BENCHES)
    message( FATAL_ERROR "incorrect benchmark name: ${IMC_BENCH_NAME}")
endif()

if(IMC_ENABLE_STATIC_LOOP_PASS_COUNT AND IMC_ENABLE_ADAPTIVE_LOOP_PASS_COUNT)
    mesage( FATAL_ERROR "static and adaptive loop pass count are enalbed simultaneously")
endif()

add_compile_definitions(imcBENCH_NAME=${IMC_BENCH_NAME})
add_compile_definitions(imcBENCH_REPEAT_COUNT=${IMC_BENCH_REPEAT_COUNT})
add_compile_definitions(imcCUSTOM_UNROLL=${IMC_CUSTOM_UNROLL})
add_compile_definitions(imcLOOP_OPT_DEBUG=${IMC_LOOP_OPT_DEBUG})
add_compile_definitions(imcPRINT_INIT_TIME=${IMC_PRINT_INIT_TIME})
add_compile_definitions(imcPRINT_LATENCY_OVERHEAD=${IMC_PRINT_LATENCY_OVERHEAD})

# add_compile_definitions(imcUSE_IMC_KERNEL=${IMC_INSERT_COMPILER_CHECKPOINTS})
add_compile_definitions(imcUSE_IMC_KERNEL=1)
add_compile_definitions(imcENABLE_DYNAMIC_CHECKPOINT=${IMC_ENABLE_DYNAMIC_CHECKPOINT})

if(IMC_BENCH_INFINITE_LOOP)
    add_compile_definitions(imcBENCH_INFINITE_LOOP=1)
endif()
if(IMC_PRINT_RECOVERY_MESSAGE)
    add_compile_definitions(imcPRINT_RECOVERY_MESSAGE=1)
endif()

add_compile_definitions(imcPRINT_STATS=${IMC_PRINT_STATS})

list(APPEND SRC_FILES
    Core/Src/ImC/imc_extension.c
)

if(IMC_BENCH_NAME MATCHES "vConv2d")
    set(BENCHMARK_SRC_FILES
    )
    set(IMC_APP_FILES
        Core/Src/benchmarks/conv2d/conv2d.c
    )
    set(IMC_LINK_OBJS
    )
endif()

if(IMC_BENCH_NAME MATCHES "adc_demo")
    set(BENCHMARK_SRC_FILES
        Core/Src/benchmarks/adc_demo/adc_demo.c
    )
    set(IMC_APP_FILES
    )
    set(IMC_LINK_OBJS
    )
endif()

if(IMC_BENCH_NAME MATCHES "fmc_expr")
    set(BENCHMARK_SRC_FILES
        Core/Src/benchmarks/fmc_expr/fmc_expr.c
    )
    set(IMC_APP_FILES
    )
    set(IMC_LINK_OBJS
    )
endif()

if(IMC_BENCH_NAME MATCHES "vrefint_expr")
    set(BENCHMARK_SRC_FILES
        Core/Src/benchmarks/vrefint_expr/vrefint_expr.c
    )
    set(IMC_APP_FILES
    )
    set(IMC_LINK_OBJS
    )
endif()

if(IMC_BENCH_NAME MATCHES "vBasicMath")
    set(BENCHMARK_SRC_FILES
        Core/Src/benchmarks/basicmath/cubic.c
        Core/Src/benchmarks/basicmath/isqrt.c
        Core/Src/benchmarks/basicmath/rad2deg.c
    )
    set(IMC_APP_FILES
        Core/Src/benchmarks/basicmath/basicmath.c
    )
    set(IMC_LINK_OBJS
    )
    include_directories(
        Core/Inc/benchmarks/basicmath
    )
endif()

if(IMC_BENCH_NAME MATCHES "vCrc")
    set(BENCHMARK_SRC_FILES
    )
    set(IMC_APP_FILES
        Core/Src/benchmarks/crc/crc_32.c
    )
    set(IMC_LINK_OBJS
        ${CMAKE_SOURCE_DIR}/Core/Src/benchmarks/crc/crc_input.o
    )
    include_directories(
        Core/Inc/benchmarks/crc
    )
endif()

if(IMC_BENCH_NAME MATCHES "vFFT")
    set(BENCHMARK_SRC_FILES
        Core/Src/benchmarks/fft/fftmisc.c
        Core/Src/benchmarks/fft/fourierf.c
    )
    set(IMC_APP_FILES
        Core/Src/benchmarks/fft/fft.c
    )
    set(IMC_LINK_OBJS
    )
    include_directories(
        Core/Inc/benchmarks/fft
    )
endif()

if(IMC_BENCH_NAME MATCHES "vSha")
    set(BENCHMARK_SRC_FILES
    )
    set(IMC_APP_FILES
        Core/Src/benchmarks/sha/sha.c
    )
    set(IMC_LINK_OBJS
        ${CMAKE_SOURCE_DIR}/Core/Src/benchmarks/sha/sha_input.o
    )
    include_directories(
        Core/Inc/benchmarks/sha
    )
endif()

if(IMC_BENCH_NAME MATCHES "vMatMul")
    set(BENCHMARK_SRC_FILES
    )
    set(IMC_APP_FILES
        Core/Src/benchmarks/matmul/matmul.c
    )
    set(IMC_LINK_OBJS
    )
endif()

if(IMC_BENCH_NAME MATCHES "vStringSearch")
    set(BENCHMARK_SRC_FILES
    )
    set(IMC_APP_FILES
        Core/Src/benchmarks/stringsearch/stringsearch_local.c
    )
    set(IMC_LINK_OBJS
    )
endif()

if(IMC_BENCH_NAME MATCHES "vAes")
    set(BENCHMARK_SRC_FILES
    )
    set(IMC_APP_FILES
        Core/Src/benchmarks/aes/aes.c
    )
    set(IMC_LINK_OBJS
    )
    include_directories(
        Core/Inc/benchmarks/aes
    )
endif()

foreach(BENCH_SRC ${BENCHMARK_SRC_FILES})
    list(APPEND SRC_FILES ${BENCH_SRC})
endforeach()

function(compile_imc_files)
    # message("compile_imc_files called")
    get_target_property(SRC_INCLUDES imc_freeRTOS INCLUDE_DIRECTORIES)
    foreach(dir ${SRC_INCLUDES})
        list(APPEND INCLUDE_DIRS "-I${dir}")
    endforeach()
    string(REPLACE " " ";" C_FLAGS ${CMAKE_C_FLAGS})

    set(BASIC_OPT_PASSES "mem2reg,indvars,instnamer,unify-loop-exits,lcssa,simplifycfg,loop-simplify")
    set(IMC_OPT_PASSES "")
    set(PLUGINS "")

    if(IMC_CUSTOM_UNROLL)
        list(APPEND IMC_OPT_PASSES "imc-loop-unroll")
        list(APPEND PLUGINS /home/ybkim/workspace/imc/loop_duplication/build/lib/libImcLoopUnroll.so)
    endif()

    if(IMC_SPLIT_LOOP)
        list(APPEND IMC_OPT_PASSES "imc-loop-opt")
        list(APPEND PLUGINS /home/ybkim/workspace/imc/loop_duplication/build/lib/libImcLoopOpt.so)
        add_compile_definitions(imcENABLE_STATIC_LOOP_PASS_COUNT=${IMC_ENABLE_STATIC_LOOP_PASS_COUNT})
        add_compile_definitions(imcENABLE_ADAPTIVE_LOOP_PASS_COUNT=${IMC_ENABLE_ADAPTIVE_LOOP_PASS_COUNT})
        add_compile_definitions(imcMAX_LOOP_IDS=${IMC_MAX_LOOP_IDS})
        add_compile_definitions(imcLOOP_PASS_COUNT=${IMC_LOOP_PASS_COUNT})
    endif()

    if(IMC_INSERT_COMPILER_CHECKPOINTS)
        list(APPEND IMC_OPT_PASSES "imc-insert-checkpoints")
        list(APPEND PLUGINS /home/ybkim/workspace/imc/loop_duplication/build/lib/libImcInsertCheckpoints.so)
    endif()

    list(JOIN IMC_OPT_PASSES "," IMC_OPT_PASSES)
    set(PLUGIN_OPTIONS "")
    foreach(PLUGIN ${PLUGINS})
        list(APPEND PLUGIN_OPTIONS -load-pass-plugin=${PLUGIN})
    endforeach()

    set(OPT_OPTIONS "-imc-loop-opt-duplication-ratio=${IMC_DUPLICATION_RATIO}")

    set(ADDITIONAL_DEFS
        "-D imcBENCH_REPEAT_COUNT=${IMC_BENCH_REPEAT_COUNT}"
        "-D imcCUSTOM_UNROLL=${IMC_CUSTOM_UNROLL}"
    )

    set(ADDITIONAL_OPT_FLAGS
        # "--disable-loop-unrolling"
    )

    foreach(APP_SRC ${IMC_APP_FILES})
        add_custom_command(
            OUTPUT ${PROJECT_BINARY_DIR}/${APP_SRC}.s
            DEPENDS ${APP_SRC}
            COMMAND ${CMAKE_C_COMPILER} -g ${C_FLAGS} -O0 -Xclang -disable-O0-optnone ${INCLUDE_DIRS} -D USE_HAL_DRIVER -D STM32L552xx ${ADDITIONAL_DEFS} -c -emit-llvm ${PROJECT_SOURCE_DIR}/${APP_SRC} -o ${PROJECT_BINARY_DIR}/${APP_SRC}.bc
            COMMAND ${OPT_BIN} -o ${PROJECT_BINARY_DIR}/${APP_SRC}_imc.bc ${PLUGIN_OPTIONS} -passes=${BASIC_OPT_PASSES},${IMC_OPT_PASSES} ${OPT_OPTIONS} ${PROJECT_BINARY_DIR}/${APP_SRC}.bc
            COMMAND ${OPT_BIN} ${OPT} ${ADDITIONAL_OPT_FLAGS} -o ${PROJECT_BINARY_DIR}/${APP_SRC}.opt.bc ${PROJECT_BINARY_DIR}/${APP_SRC}_imc.bc
            COMMAND ${LLC_BIN} ${CPU} ${OPT} -o ${PROJECT_BINARY_DIR}/${APP_SRC}.s ${PROJECT_BINARY_DIR}/${APP_SRC}.opt.bc
        )
        list(APPEND APP_OPTS ${PROJECT_BINARY_DIR}/${APP_SRC}.s)
    endforeach()
    add_library(imc_apps OBJECT "${APP_OPTS}")
endfunction()