#ifndef INC_IMC_IMC_EXTENSION_H_
#define INC_IMC_IMC_EXTENSION_H_

#ifndef imcBENCH_NAME
    #define imcBENCH_NAME vConv2d
#endif

#ifndef imcBENCH_INFINITE_LOOP
    #define imcBENCH_INFINITE_LOOP 0
#endif

#ifndef imcPRINT_RECOVERY_MESSAGE
    #define imcPRINT_RECOVERY_MESSAGE 0
#endif

#ifndef imcENABLE_STATIC_LOOP_PASS_COUNT
    #define imcENABLE_STATIC_LOOP_PASS_COUNT 0
#endif

#ifndef imcENABLE_ADAPTIVE_LOOP_PASS_COUNT
    #define imcENABLE_ADAPTIVE_LOOP_PASS_COUNT 1
#endif

#ifndef imcMAX_LOOP_IDS
    #define imcMAX_LOOP_IDS 1
#endif

#ifndef imcLOOP_PASS_COUNT
    #define imcLOOP_PASS_COUNT 10
#endif 

#ifndef imcBENCH_REPEAT_COUNT
    #define imcBENCH_REPEAT_COUNT 1
#endif

#ifndef imcPRINT_STATS
    #define imcPRINT_STATS 0
#endif

#ifndef imcPRINT_INIT_TIME
    #define imcPRINT_INIT_TIME 0
#endif

#ifndef imcPRINT_LATENCY_OVERHEAD
    #define imcPRINT_LATENCY_OVERHEAD 0
#endif

#ifndef imcCUSTOM_UNROLL
    #define imcCUSTOM_UNROLL 0 
#endif

#ifndef imcENABLE_DYNAMIC_CHECKPOINT
    #define imcENABLE_DYNAMIC_CHECKPOINT 0
#endif

#define IMC_KERNEL_NVM __attribute__((section(".kernel_nvm")))

#define imcCAP_VOL_HIGH 4800
#define imcCAP_VOL_LOW 3500
#define imcENERGY_TOTAL (imcCAP_VOL_HIGH*imcCAP_VOL_HIGH - imcCAP_VOL_LOW*imcCAP_VOL_LOW)

#if (imcCUSTOM_UNROLL)
// #define STRINGIFY(x) ("clang loop unroll_count(" ##str ")")
#define DO_PRAGMA(x) _Pragma ( #x )
#define IMC_UNROLL(x) DO_PRAGMA( clang loop unroll_count(x+1) )
#define IMC_UNROLL_FULL() DO_PRAGMA( clang loop unroll(full) )
#else
#define IMC_UNROLL(x)
#define IMC_UNROLL_FULL()
#endif

int __imc_get_loop_pass_count(int loop_id);
void __imc_finish_loop_skipping();

void imc_init_energy_estimation();
void imc_recover_estimations();
void imc_backup_estimations();
void imc_print_estimations();

#if (imcPRINT_STATS)
extern int imc_is_passing_loops;
extern int imc_checkpoint_triggered;
extern int imc_checkpoint_executed;
void imc_backup_stats();
void imc_recover_stats();
extern int first_checkpoint;
extern int no_forward_progress;
#endif

#if (imcPRINT_LATENCY_OVERHEAD)
extern unsigned int imc_ticks_init;
extern unsigned int imc_ticks_getCSC;
extern unsigned int imc_ticks_adjust;
extern unsigned int imc_ticks_total;
extern unsigned int imc_last_tick;
void imc_backup_latency_overhead();
void imc_recover_latency_overhead();
#endif

#ifndef imcLOOP_OPT_DEBUG
    #define imcLOOP_OPT_DEBUG 0
#endif

void ckptTask();

#endif
