!
! Copyright (C) 2021, MaX CoE
! Distributed under the MIT License 
! (license terms are at http://opensource.org/licenses/MIT).
!
!--
!
!
! Utility functions to perform all memory synchronizations (host to
! host, device to device, host to device and device to host), both
! synchronous and asynchronous, using CUDA-Fortran, OpenACC and
! OpenMP Offload
!
!==================================================================
!==================================================================
! *DO NOT EDIT*: automatically generated from devxlib_memcpy.jf90
!==================================================================
!==================================================================
!
#include<devxlib_macros.h>
#include<devxlib_defs.h>
!
!=======================================
!
! Note about dimensions:
! The lower bound of the assumed shape array passed to the subroutine is 1
! lbound and range instead refer to the indexing in the parent caller.
!
module devxlib_memcpy

   use iso_fortran_env,             only : int32, int64, real32, real64
   use, intrinsic :: iso_c_binding, only : c_ptr, c_loc, c_associated, c_size_t
   use devxlib_environment,         only : devxlib_error
   use devxlib_async,               only : dxl_async_kind
   !
#if defined __DXL_CUDAF
   use cudafor
#elif defined __DXL_OPENACC
   use openacc
   use devxlib_environment,    only : acc_memcpy_device_f, acc_memcpy_from_device_f, acc_memcpy_to_device_f
#elif defined __DXL_OPENMP_GPU
   use omp_lib,                only : omp_get_default_device, omp_get_initial_device, omp_target_memcpy
#endif

   implicit none

   !private :: dxl_async_kind

   interface devxlib_memcpy_d2d
      module procedure &
{%- for t in types %}
{%- for p in kinds[t] %}
{%- for d in range(1,dimensions+1,3) %}
{%- if (d+1)<=dimensions %}
{%- if (d+2)<=dimensions %}
         {{p.name}}_devxlib_memcpy_d2d_{{t[0]|lower}}{{d}}d, {{p.name}}_devxlib_memcpy_d2d_{{t[0]|lower}}{{d+1}}d, {{p.name}}_devxlib_memcpy_d2d_{{t[0]|lower}}{{d+2}}d, &
{%- else %}
         {{p.name}}_devxlib_memcpy_d2d_{{t[0]|lower}}{{d}}d, {{p.name}}_devxlib_memcpy_d2d_{{t[0]|lower}}{{d+1}}d, &
{%- endif %}
{%- else %}
         {{p.name}}_devxlib_memcpy_d2d_{{t[0]|lower}}{{d}}d, &
{%- endif %}
{%- endfor %}
{%- endfor %}
{%- endfor %}

{%- for t in types %}
{%- set outer_loop = loop %}
{%- for p in kinds[t] %}
{%- set medium_loop = loop %}
{%- for d in range(1,dimensions+1,3) %}
{%- if (d+1)<=dimensions %}
{%- if (d+2)<=dimensions %}
         {{p.name}}_devxlib_memcpy_d2d_async_{{t[0]|lower}}{{d}}d, {{p.name}}_devxlib_memcpy_d2d_async_{{t[0]|lower}}{{d+1}}d, {{p.name}}_devxlib_memcpy_d2d_async_{{t[0]|lower}}{{d+2}}d{% if ((not loop.last) or (not medium_loop.last) or (not outer_loop.last))%}, &{%- endif %}
{%- else %}
         {{p.name}}_devxlib_memcpy_d2d_async_{{t[0]|lower}}{{d}}d, {{p.name}}_devxlib_memcpy_d2d_async_{{t[0]|lower}}{{d+1}}d{% if ((not loop.last) or (not medium_loop.last) or (not outer_loop.last))%}, &{%- endif %}
{%- endif %}
{%- else %}
         {{p.name}}_devxlib_memcpy_d2d_async_{{t[0]|lower}}{{d}}d{% if ((not loop.last) or (not medium_loop.last) or (not outer_loop.last))%}, &{%- endif %}
{%- endif %}
{%- endfor %}
{%- endfor %}
{%- endfor %}
   endinterface devxlib_memcpy_d2d

   interface devxlib_memcpy_d2h
      module procedure &
{%- for t in types %}
{%- for p in kinds[t] %}
{%- for d in range(1,dimensions+1,3) %}
{%- if (d+1)<=dimensions %}
{%- if (d+2)<=dimensions %}
         {{p.name}}_devxlib_memcpy_d2h_{{t[0]|lower}}{{d}}d, {{p.name}}_devxlib_memcpy_d2h_{{t[0]|lower}}{{d+1}}d, {{p.name}}_devxlib_memcpy_d2h_{{t[0]|lower}}{{d+2}}d, &
{%- else %}
         {{p.name}}_devxlib_memcpy_d2h_{{t[0]|lower}}{{d}}d, {{p.name}}_devxlib_memcpy_d2h_{{t[0]|lower}}{{d+1}}d, &
{%- endif %}
{%- else %}
         {{p.name}}_devxlib_memcpy_d2h_{{t[0]|lower}}{{d}}d, &
{%- endif %}
{%- endfor %}
{%- endfor %}
{%- endfor %}

{%- for t in types %}
{%- set outer_loop = loop %}
{%- for p in kinds[t] %}
{%- set medium_loop = loop %}
{%- for d in range(1,dimensions+1,3) %}
{%- if (d+1)<=dimensions %}
{%- if (d+2)<=dimensions %}
         {{p.name}}_devxlib_memcpy_d2h_async_{{t[0]|lower}}{{d}}d, {{p.name}}_devxlib_memcpy_d2h_async_{{t[0]|lower}}{{d+1}}d, {{p.name}}_devxlib_memcpy_d2h_async_{{t[0]|lower}}{{d+2}}d{% if ((not loop.last) or (not medium_loop.last) or (not outer_loop.last))%}, &{%- endif %}
{%- else %}
         {{p.name}}_devxlib_memcpy_d2h_async_{{t[0]|lower}}{{d}}d, {{p.name}}_devxlib_memcpy_d2h_async_{{t[0]|lower}}{{d+1}}d{% if ((not loop.last) or (not medium_loop.last) or (not outer_loop.last))%}, &{%- endif %}
{%- endif %}
{%- else %}
         {{p.name}}_devxlib_memcpy_d2h_async_{{t[0]|lower}}{{d}}d{% if ((not loop.last) or (not medium_loop.last) or (not outer_loop.last))%}, &{%- endif %}
{%- endif %}
{%- endfor %}
{%- endfor %}
{%- endfor %}
   endinterface devxlib_memcpy_d2h

   interface devxlib_memcpy_h2d
      module procedure &
{%- for t in types %}
{%- for p in kinds[t] %}
{%- for d in range(1,dimensions+1,3) %}
{%- if (d+1)<=dimensions %}
{%- if (d+2)<=dimensions %}
         {{p.name}}_devxlib_memcpy_h2d_{{t[0]|lower}}{{d}}d, {{p.name}}_devxlib_memcpy_h2d_{{t[0]|lower}}{{d+1}}d, {{p.name}}_devxlib_memcpy_h2d_{{t[0]|lower}}{{d+2}}d, &
{%- else %}
         {{p.name}}_devxlib_memcpy_h2d_{{t[0]|lower}}{{d}}d, {{p.name}}_devxlib_memcpy_h2d_{{t[0]|lower}}{{d+1}}d, &
{%- endif %}
{%- else %}
         {{p.name}}_devxlib_memcpy_h2d_{{t[0]|lower}}{{d}}d, &
{%- endif %}
{%- endfor %}
{%- endfor %}
{%- endfor %}

{%- for t in types %}
{%- set outer_loop = loop %}
{%- for p in kinds[t] %}
{%- set medium_loop = loop %}
{%- for d in range(1,dimensions+1,3) %}
{%- if (d+1)<=dimensions %}
{%- if (d+2)<=dimensions %}
         {{p.name}}_devxlib_memcpy_h2d_async_{{t[0]|lower}}{{d}}d, {{p.name}}_devxlib_memcpy_h2d_async_{{t[0]|lower}}{{d+1}}d, {{p.name}}_devxlib_memcpy_h2d_async_{{t[0]|lower}}{{d+2}}d{% if ((not loop.last) or (not medium_loop.last) or (not outer_loop.last))%}, &{%- endif %}
{%- else %}
         {{p.name}}_devxlib_memcpy_h2d_async_{{t[0]|lower}}{{d}}d, {{p.name}}_devxlib_memcpy_h2d_async_{{t[0]|lower}}{{d+1}}d{% if ((not loop.last) or (not medium_loop.last) or (not outer_loop.last))%}, &{%- endif %}
{%- endif %}
{%- else %}
         {{p.name}}_devxlib_memcpy_h2d_async_{{t[0]|lower}}{{d}}d{% if ((not loop.last) or (not medium_loop.last) or (not outer_loop.last))%}, &{%- endif %}
{%- endif %}
{%- endfor %}
{%- endfor %}
{%- endfor %}
   endinterface devxlib_memcpy_h2d

   interface devxlib_memcpy_h2h
      module procedure &
{%- for t in types %}
{%- for p in kinds[t] %}
{%- for d in range(1,dimensions+1,3) %}
{%- if (d+1)<=dimensions %}
{%- if (d+2)<=dimensions %}
         {{p.name}}_devxlib_memcpy_h2h_{{t[0]|lower}}{{d}}d, {{p.name}}_devxlib_memcpy_h2h_{{t[0]|lower}}{{d+1}}d, {{p.name}}_devxlib_memcpy_h2h_{{t[0]|lower}}{{d+2}}d, &
{%- else %}
         {{p.name}}_devxlib_memcpy_h2h_{{t[0]|lower}}{{d}}d, {{p.name}}_devxlib_memcpy_h2h_{{t[0]|lower}}{{d+1}}d, &
{%- endif %}
{%- else %}
         {{p.name}}_devxlib_memcpy_h2h_{{t[0]|lower}}{{d}}d, &
{%- endif %}
{%- endfor %}
{%- endfor %}
{%- endfor %}

{%- for t in types %}
{%- set outer_loop = loop %}
{%- for p in kinds[t] %}
{%- set medium_loop = loop %}
{%- for d in range(1,dimensions+1,3) %}
{%- if (d+1)<=dimensions %}
{%- if (d+2)<=dimensions %}
         {{p.name}}_devxlib_memcpy_h2h_async_{{t[0]|lower}}{{d}}d, {{p.name}}_devxlib_memcpy_h2h_async_{{t[0]|lower}}{{d+1}}d, {{p.name}}_devxlib_memcpy_h2h_async_{{t[0]|lower}}{{d+2}}d{% if ((not loop.last) or (not medium_loop.last) or (not outer_loop.last))%}, &{%- endif %}
{%- else %}
         {{p.name}}_devxlib_memcpy_h2h_async_{{t[0]|lower}}{{d}}d, {{p.name}}_devxlib_memcpy_h2h_async_{{t[0]|lower}}{{d+1}}d{% if ((not loop.last) or (not medium_loop.last) or (not outer_loop.last))%}, &{%- endif %}
{%- endif %}
{%- else %}
         {{p.name}}_devxlib_memcpy_h2h_async_{{t[0]|lower}}{{d}}d{% if ((not loop.last) or (not medium_loop.last) or (not outer_loop.last))%}, &{%- endif %}
{%- endif %}
{%- endfor %}
{%- endfor %}
{%- endfor %}
   endinterface devxlib_memcpy_h2h

   interface devxlib_memcpy_d2d_p
      module procedure &
{%- for t in types %}
{%- set outer_loop = loop %}
{%- for p in kinds[t] %}
{%- set medium_loop = loop %}
{%- for d in range(1,dimensions+1,3) %}
{%- if (d+1)<=dimensions %}
{%- if (d+2)<=dimensions %}
         {{p.name}}_devxlib_memcpy_d2d_{{t[0]|lower}}{{d}}d_p, {{p.name}}_devxlib_memcpy_d2d_{{t[0]|lower}}{{d+1}}d_p, {{p.name}}_devxlib_memcpy_d2d_{{t[0]|lower}}{{d+2}}d_p{% if ((not loop.last) or (not medium_loop.last) or (not outer_loop.last))%}, &{%- endif %}
{%- else %}
         {{p.name}}_devxlib_memcpy_d2d_{{t[0]|lower}}{{d}}d_p, {{p.name}}_devxlib_memcpy_d2d_{{t[0]|lower}}{{d+1}}d_p{% if ((not loop.last) or (not medium_loop.last) or (not outer_loop.last))%}, &{%- endif %}
{%- endif %}
{%- else %}
         {{p.name}}_devxlib_memcpy_d2d_{{t[0]|lower}}{{d}}d_p{% if ((not loop.last) or (not medium_loop.last) or (not outer_loop.last))%}, &{%- endif %}
{%- endif %}
{%- endfor %}
{%- endfor %}
{%- endfor %}
   endinterface devxlib_memcpy_d2d_p

   interface devxlib_memcpy_d2h_p
      module procedure &
{%- for t in types %}
{%- set outer_loop = loop %}
{%- for p in kinds[t] %}
{%- set medium_loop = loop %}
{%- for d in range(1,dimensions+1,3) %}
{%- if (d+1)<=dimensions %}
{%- if (d+2)<=dimensions %}
         {{p.name}}_devxlib_memcpy_d2h_{{t[0]|lower}}{{d}}d_p, {{p.name}}_devxlib_memcpy_d2h_{{t[0]|lower}}{{d+1}}d_p, {{p.name}}_devxlib_memcpy_d2h_{{t[0]|lower}}{{d+2}}d_p{% if ((not loop.last) or (not medium_loop.last) or (not outer_loop.last))%}, &{%- endif %}
{%- else %}
         {{p.name}}_devxlib_memcpy_d2h_{{t[0]|lower}}{{d}}d_p, {{p.name}}_devxlib_memcpy_d2h_{{t[0]|lower}}{{d+1}}d_p{% if ((not loop.last) or (not medium_loop.last) or (not outer_loop.last))%}, &{%- endif %}
{%- endif %}
{%- else %}
         {{p.name}}_devxlib_memcpy_d2h_{{t[0]|lower}}{{d}}d_p{% if ((not loop.last) or (not medium_loop.last) or (not outer_loop.last))%}, &{%- endif %}
{%- endif %}
{%- endfor %}
{%- endfor %}
{%- endfor %}
   endinterface devxlib_memcpy_d2h_p

   interface devxlib_memcpy_h2d_p
      module procedure &
{%- for t in types %}
{%- set outer_loop = loop %}
{%- for p in kinds[t] %}
{%- set medium_loop = loop %}
{%- for d in range(1,dimensions+1,3) %}
{%- if (d+1)<=dimensions %}
{%- if (d+2)<=dimensions %}
         {{p.name}}_devxlib_memcpy_h2d_{{t[0]|lower}}{{d}}d_p, {{p.name}}_devxlib_memcpy_h2d_{{t[0]|lower}}{{d+1}}d_p, {{p.name}}_devxlib_memcpy_h2d_{{t[0]|lower}}{{d+2}}d_p{% if ((not loop.last) or (not medium_loop.last) or (not outer_loop.last))%}, &{%- endif %}
{%- else %}
         {{p.name}}_devxlib_memcpy_h2d_{{t[0]|lower}}{{d}}d_p, {{p.name}}_devxlib_memcpy_h2d_{{t[0]|lower}}{{d+1}}d_p{% if ((not loop.last) or (not medium_loop.last) or (not outer_loop.last))%}, &{%- endif %}
{%- endif %}
{%- else %}
         {{p.name}}_devxlib_memcpy_h2d_{{t[0]|lower}}{{d}}d_p{% if ((not loop.last) or (not medium_loop.last) or (not outer_loop.last))%}, &{%- endif %}
{%- endif %}
{%- endfor %}
{%- endfor %}
{%- endfor %}
   endinterface devxlib_memcpy_h2d_p

   interface
{%- for t in types %}
{%- for p in kinds[t] %}
{%- for d in range(1,dimensions+1) %}
      module subroutine {{p.name}}_devxlib_memcpy_d2d_{{t[0]|lower}}{{d}}d(array_out, array_in, &
                                            {% for dd in range(d) -%}
                                            {{ "range%s"|format(dd+1) }}, {{ "lbound%s"|format(dd+1) }}{% if not loop.last %}, &
                                            {% endif %}{% endfor %} )
         implicit none
         {{t}}({{p.val}}) DEV_ATTR, intent(inout) :: array_out({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
         {{t}}({{p.val}}) DEV_ATTR, intent(in)    :: array_in({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
         integer, optional, intent(in) :: {% for dd in range(d) %} {{ "range%s(2)"|format(dd+1) }}{% if not loop.last %}, {%- endif %}{% endfor %}
         integer, optional, intent(in) :: {% for dd in range(d) %} {{ "lbound%s"|format(dd+1) }}{% if not loop.last %}, {%- endif %}{% endfor %}
      end subroutine {{p.name}}_devxlib_memcpy_d2d_{{t[0]|lower}}{{d}}d
{%- endfor %}
{%- endfor %}
{%- endfor %}

{%- for t in types %}
{%- for p in kinds[t] %}
{%- for d in range(1,dimensions+1) %}
      module subroutine {{p.name}}_devxlib_memcpy_d2d_async_{{t[0]|lower}}{{d}}d(array_out, array_in, async_id, &
                                                  {% for dd in range(d) -%}
                                                  {{ "range%s"|format(dd+1) }}, {{ "lbound%s"|format(dd+1) }}{% if not loop.last %}, &
                                                  {% endif %}{% endfor %} )
         implicit none
         {{t}}({{p.val}}) DEV_ATTR, intent(inout) :: array_out({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
         {{t}}({{p.val}}) DEV_ATTR, intent(in)    :: array_in({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
         integer(kind=dxl_async_kind), intent(in) :: async_id
         integer, optional, intent(in) :: {% for dd in range(d) %} {{ "range%s(2)"|format(dd+1) }}{% if not loop.last %}, {%- endif %}{% endfor %}
         integer, optional, intent(in) :: {% for dd in range(d) %} {{ "lbound%s"|format(dd+1) }}{% if not loop.last %}, {%- endif %}{% endfor %}
      end subroutine {{p.name}}_devxlib_memcpy_d2d_async_{{t[0]|lower}}{{d}}d
{%- endfor %}
{%- endfor %}
{%- endfor %}
   endinterface

   interface
{%- for t in types %}
{%- for p in kinds[t] %}
{%- for d in range(1,dimensions+1) %}
      module subroutine {{p.name}}_devxlib_memcpy_d2h_{{t[0]|lower}}{{d}}d(array_out, array_in, &
                                             {% for dd in range(d) -%} 
                                             {{ "range%s"|format(dd+1) }}, {{ "lbound%s"|format(dd+1) }} {% if not loop.last %}, &
                                             {% endif %}{% endfor %} )
         implicit none
         {{t}}({{p.val}}), intent(inout) :: array_out({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
         {{t}}({{p.val}}) DEV_ATTR, intent(in)    :: array_in({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
         integer, optional, intent(in) :: {% for dd in range(d) %} {{ "range%s(2)"|format(dd+1) }}{% if not loop.last %}, {%- endif %}{% endfor %}
         integer, optional, intent(in) :: {% for dd in range(d) %} {{ "lbound%s"|format(dd+1) }}{% if not loop.last %}, {%- endif %}{% endfor %}
      end subroutine {{p.name}}_devxlib_memcpy_d2h_{{t[0]|lower}}{{d}}d
{%- endfor %}
{%- endfor %}
{%- endfor %}

{%- for t in types %}
{%- for p in kinds[t] %}
{%- for d in range(1,dimensions+1) %}
      module subroutine {{p.name}}_devxlib_memcpy_d2h_async_{{t[0]|lower}}{{d}}d(array_out, array_in, async_id, &
                                             {% for dd in range(d) -%} 
                                             {{ "range%s"|format(dd+1) }}, {{ "lbound%s"|format(dd+1) }} {% if not loop.last %}, &
                                             {% endif %}{% endfor %} )
         implicit none
         {{t}}({{p.val}}), target, intent(inout)       :: array_out({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
         {{t}}({{p.val}}), target, intent(inout) DEV_ATTR :: array_in({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
         integer(kind=dxl_async_kind), intent(in) :: async_id
         integer, optional, intent(in) :: {% for dd in range(d) %} {{ "range%s(2)"|format(dd+1) }}{% if not loop.last %}, {%- endif %}{% endfor %}
         integer, optional, intent(in) :: {% for dd in range(d) %} {{ "lbound%s"|format(dd+1) }}{% if not loop.last %}, {%- endif %}{% endfor %}
      end subroutine {{p.name}}_devxlib_memcpy_d2h_async_{{t[0]|lower}}{{d}}d
{%- endfor %}
{%- endfor %}
{%- endfor %}
   endinterface

   interface
{%- for t in types %}
{%- for p in kinds[t] %}
{%- for d in range(1,dimensions+1) %}
      module subroutine {{p.name}}_devxlib_memcpy_h2d_{{t[0]|lower}}{{d}}d(array_out, array_in, &
                                             {% for dd in range(d) -%} 
                                             {{ "range%s"|format(dd+1) }}, {{ "lbound%s"|format(dd+1) }} {% if not loop.last %}, &
                                             {% endif %}{% endfor %})
         implicit none
         {{t}}({{p.val}}) DEV_ATTR, intent(inout) :: array_out({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
         {{t}}({{p.val}}), intent(in) :: array_in({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
         integer, optional, intent(in) :: {% for dd in range(d) %} {{ "range%s(2)"|format(dd+1) }}{% if not loop.last %}, {%- endif %}{% endfor %}
         integer, optional, intent(in) :: {% for dd in range(d) %} {{ "lbound%s"|format(dd+1) }}{% if not loop.last %}, {%- endif %}{% endfor %}
      end subroutine {{p.name}}_devxlib_memcpy_h2d_{{t[0]|lower}}{{d}}d
{%- endfor %}
{%- endfor %}
{%- endfor %}

{%- for t in types %}
{%- for p in kinds[t] %}
{%- for d in range(1,dimensions+1) %}
      module subroutine {{p.name}}_devxlib_memcpy_h2d_async_{{t[0]|lower}}{{d}}d(array_out, array_in, async_id, &
                                             {% for dd in range(d) -%} 
                                             {{ "range%s"|format(dd+1) }}, {{ "lbound%s"|format(dd+1) }} {% if not loop.last %}, &
                                             {% endif %}{% endfor %} )
         implicit none
         {{t}}({{p.val}}), target, intent(inout) DEV_ATTR :: array_out({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
         {{t}}({{p.val}}), target, intent(in) :: array_in({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
         integer(kind=dxl_async_kind), intent(in) :: async_id
         integer, optional, intent(in) :: {% for dd in range(d) %} {{ "range%s(2)"|format(dd+1) }}{% if not loop.last %}, {%- endif %}{% endfor %}
         integer, optional, intent(in) :: {% for dd in range(d) %} {{ "lbound%s"|format(dd+1) }}{% if not loop.last %}, {%- endif %}{% endfor %}
      end subroutine {{p.name}}_devxlib_memcpy_h2d_async_{{t[0]|lower}}{{d}}d
{%- endfor %}
{%- endfor %}
{%- endfor %}
   endinterface

   interface
{%- for t in types %}
{%- for p in kinds[t] %}
{%- for d in range(1,dimensions+1) %}
      module subroutine {{p.name}}_devxlib_memcpy_h2h_{{t[0]|lower}}{{d}}d(array_out, array_in, &
                                                  {% for dd in range(d) -%}
                                                  {{ "range%s"|format(dd+1) }}, {{ "lbound%s"|format(dd+1) }}{% if not loop.last %}, &
                                                  {% endif %}{% endfor %} )
         implicit none
         {{t}}({{p.val}}), intent(inout) :: array_out({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
         {{t}}({{p.val}}), intent(in)    :: array_in({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
         integer, optional, intent(in) :: {% for dd in range(d) %} {{ "range%s(2)"|format(dd+1) }}{% if not loop.last %}, {%- endif %}{% endfor %}
         integer, optional, intent(in) :: {% for dd in range(d) %} {{ "lbound%s"|format(dd+1) }}{% if not loop.last %}, {%- endif %}{% endfor %}
      end subroutine {{p.name}}_devxlib_memcpy_h2h_{{t[0]|lower}}{{d}}d
{%- endfor %}
{%- endfor %}
{%- endfor %}

{%- for t in types %}
{%- for p in kinds[t] %}
{%- for d in range(1,dimensions+1) %}
      module subroutine {{p.name}}_devxlib_memcpy_h2h_async_{{t[0]|lower}}{{d}}d(array_out, array_in, async_id, &
                                            {% for dd in range(d) -%}
                                            {{ "range%s"|format(dd+1) }}, {{ "lbound%s"|format(dd+1) }}{% if not loop.last %}, &
                                            {% endif %}{% endfor %} )
         {{t}}({{p.val}}), intent(inout) :: array_out({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
         {{t}}({{p.val}}), intent(in)    :: array_in({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
         integer(kind=dxl_async_kind), intent(in) :: async_id
         integer, optional, intent(in) :: {% for dd in range(d) %} {{ "range%s(2)"|format(dd+1) }}{% if not loop.last %}, {%- endif %}{% endfor %}
         integer, optional, intent(in) :: {% for dd in range(d) %} {{ "lbound%s"|format(dd+1) }}{% if not loop.last %}, {%- endif %}{% endfor %}
      end subroutine {{p.name}}_devxlib_memcpy_h2h_async_{{t[0]|lower}}{{d}}d
{%- endfor %}
{%- endfor %}
{%- endfor %}
   endinterface

   interface
{%- for t in types %}
{%- for p in kinds[t] %}
{%- for d in range(1,dimensions+1) %}
      module subroutine {{p.name}}_devxlib_memcpy_d2d_{{t[0]|lower}}{{d}}d_p(&
#if defined __DXL_OPENMP_GPU
                                            array_out, array_in, device_id_out, device_id_in)
#else
                                            array_out, array_in)
#endif
         implicit none
         {{t}}({{p.val}}), pointer, contiguous, intent(inout) DEV_ATTR :: array_out({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
         {{t}}({{p.val}}), pointer, contiguous, intent(in)    DEV_ATTR :: array_in({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
#if defined __DXL_OPENMP_GPU
         integer, optional, intent(in) :: device_id_out, device_id_in
#endif
      end subroutine {{p.name}}_devxlib_memcpy_d2d_{{t[0]|lower}}{{d}}d_p
{%- endfor %}
{%- endfor %}
{%- endfor %}
   endinterface

   interface
{%- for t in types %}
{%- for p in kinds[t] %}
{%- for d in range(1,dimensions+1) %}
      module subroutine {{p.name}}_devxlib_memcpy_d2h_{{t[0]|lower}}{{d}}d_p(&
#if defined __DXL_OPENMP_GPU
                                             array_out, array_in, device_id)
#else
                                             array_out, array_in)
#endif
         implicit none
         {{t}}({{p.val}}), target,  intent(inout) :: array_out({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
         {{t}}({{p.val}}), pointer, intent(inout) DEV_ATTR :: array_in({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
#if defined __DXL_OPENMP_GPU
         integer, optional, intent(in) :: device_id
#endif
      end subroutine {{p.name}}_devxlib_memcpy_d2h_{{t[0]|lower}}{{d}}d_p
{%- endfor %}
{%- endfor %}
{%- endfor %}
   endinterface

   interface
{%- for t in types %}
{%- for p in kinds[t] %}
{%- for d in range(1,dimensions+1) %}
      module subroutine {{p.name}}_devxlib_memcpy_h2d_{{t[0]|lower}}{{d}}d_p(&
#if defined __DXL_OPENMP_GPU
                                             array_out, array_in, device_id)
#else
                                             array_out, array_in)
#endif
         implicit none
         {{t}}({{p.val}}), pointer, contiguous, intent(inout) DEV_ATTR :: array_out({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
         {{t}}({{p.val}}), target, intent(in) :: array_in({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
#if defined __DXL_OPENMP_GPU
         integer, optional, intent(in) :: device_id
#endif
      end subroutine {{p.name}}_devxlib_memcpy_h2d_{{t[0]|lower}}{{d}}d_p
{%- endfor %}
{%- endfor %}
{%- endfor %}
   endinterface

endmodule devxlib_memcpy
