#include <stdlib.h>

/* A small implementation of the runtime used by the code generated by the
   kernel_load_store and isolate_statement
*/


/* To copy scalars */
void P4A_copy_from_accel(size_t element_size,
			 int *host_address,
			 int *accel_address) {
    host_address[0] = accel_address[0];
}


void P4A_copy_to_accel(size_t element_size,
		       int *host_address,
		       int *accel_address) {
  for(size_t i = 0; i < element_size; i++)
    accel_address[i] = host_address[i];
}

/* To copy parts of 1D arrays */
void P4A_copy_from_accel_1d(size_t element_size,
			    size_t d1_size,
			    size_t d1_block_size,
			    size_t d1_offset,
			    int *host_address,
			    int *accel_address) {
  size_t i;
  for(i = 0; i < d1_block_size; i++)
    host_address[i+d1_offset] = accel_address[i];
}


void P4A_copy_to_accel_1d(size_t element_size,
			  size_t d1_size,
			  size_t d1_block_size,
			  size_t d1_offset,
			  int *host_address,
			  int *accel_address) {
  size_t i;
  for(i = 0; i < d1_block_size; i++)
    accel_address[i] = host_address[i+d1_offset];
}



/* To copy parts of 2D arrays */
void P4A_copy_from_accel_2d(size_t element_size,
			    size_t d1_size, size_t d2_size,
			    size_t d1_block_size, size_t d2_block_size,
			    size_t d1_offset, size_t d2_offset,
			    int host_address[d2_size],
			    int accel_address[d1_block_size][d2_block_size]) {
  size_t i, j;
  for(i = 0; i < d1_block_size; i++)
    for(j = 0; j < d2_block_size; j++)
      host_address[d2_offset+(i+d1_offset)*d2_size+j] =
        accel_address[i][j];
}


void P4A_copy_to_accel_2d(size_t element_size,
			  size_t d1_size, size_t d2_size,
			  size_t d1_block_size, size_t d2_block_size,
			  size_t d1_offset,   size_t d2_offset,
			  int host_address [d2_size],
			  int accel_address [d1_block_size][d2_block_size]) {
  size_t i, j;
  for(i = 0; i < d1_block_size; i++)
    for(j = 0; j < d2_block_size; j++)
      accel_address[i][j] =
        host_address[d2_offset+(i + d1_offset)*d2_size+j];
}

void P4A_copy_to_accel_3d(size_t element_size,
			  size_t d1_size, size_t d2_size, size_t d3_size,
			  size_t d1_block_size, size_t d2_block_size, size_t d3_block_size,
			  size_t d1_offset,   size_t d2_offset, size_t d3_offset,
			  int host_address [d3_size],
			  int accel_address [d1_block_size][d2_block_size][d3_block_size]) {
  size_t i, j,k;
  for(i = 0; i < d1_block_size; i++)
    for(j = 0; j < d2_block_size; j++)
        for(k = 0; k < d3_block_size; k++)
            accel_address[i][j][k] =
                host_address[d3_offset+( (i + d1_offset)*d2_size + j + d2_offset)*d3_size+j];
}

/* Allocate memory on the accelerator */
void P4A_accel_malloc(void **ptr, size_t n) {
    if(n) *ptr=malloc(n);
    else *ptr=NULL;
}

/* Deallocate memory on the accelerator */
void P4A_accel_free(void *ptr) {
    free(ptr);
}
