!
! Copyright (C) 2021, MaX CoE
! Distributed under the MIT License 
! (license terms are at http://opensource.org/licenses/MIT).
!
!--
!
! Module for direct memory access on the device (allocation, deallocation
! and allocation check) using CUDA-Fortran, OpenACC or OpenMP Offload
!
!==================================================================
!==================================================================
! *DO NOT EDIT*: automatically generated from device_malloc.jf90
!==================================================================
!==================================================================
!
#include<devxlib_macros.h>
#include<devxlib_defs.h>
!
!=======================================
!
module devxlib_malloc

   use iso_fortran_env,             only : int32, int64, real32, real64
   use, intrinsic :: iso_c_binding, only : c_loc, c_ptr, c_size_t, c_f_pointer, c_associated
#if defined __DXL_CUDAF || defined __DXL_OPENACC
   use devxlib_environment
#elif defined __DXL_OPENMP_GPU
   use omp_lib, only : omp_get_default_device, omp_target_is_present, omp_target_alloc, omp_target_free
#endif

   implicit none

   interface devxlib_alloc
      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_malloc_alloc_{{t[0]|lower}}{{d}}d, {{p.name}}_devxlib_malloc_alloc_{{t[0]|lower}}{{d+1}}d, {{p.name}}_devxlib_malloc_alloc_{{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_malloc_alloc_{{t[0]|lower}}{{d}}d, {{p.name}}_devxlib_malloc_alloc_{{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_malloc_alloc_{{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_alloc

   interface devxlib_free
      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_malloc_free_{{t[0]|lower}}{{d}}d, {{p.name}}_devxlib_malloc_free_{{t[0]|lower}}{{d+1}}d, {{p.name}}_devxlib_malloc_free_{{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_malloc_free_{{t[0]|lower}}{{d}}d, {{p.name}}_devxlib_malloc_free_{{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_malloc_free_{{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_free

   interface devxlib_allocated
      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_malloc_allocated_{{t[0]|lower}}{{d}}d, {{p.name}}_devxlib_malloc_allocated_{{t[0]|lower}}{{d+1}}d, {{p.name}}_devxlib_malloc_allocated_{{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_malloc_allocated_{{t[0]|lower}}{{d}}d, {{p.name}}_devxlib_malloc_allocated_{{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_malloc_allocated_{{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_allocated

   interface devxlib_allocated_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_malloc_allocated_{{t[0]|lower}}{{d}}d_p, {{p.name}}_devxlib_malloc_allocated_{{t[0]|lower}}{{d+1}}d_p, {{p.name}}_devxlib_malloc_allocated_{{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_malloc_allocated_{{t[0]|lower}}{{d}}d_p, {{p.name}}_devxlib_malloc_allocated_{{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_malloc_allocated_{{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_allocated_p


   interface
   {%- for t in types %}
   {%- for p in kinds[t] %}
   {%- for d in range(1,dimensions+1) %}
      module subroutine {{p.name}}_devxlib_malloc_alloc_{{t[0]|lower}}{{d}}d(dev_ptr, dimensions, ierr, device_id, lbounds)
         implicit none
         {{t}}({{p.val}}), pointer, contiguous, intent(out) DEV_ATTR :: dev_ptr({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
{%- if d == 1 %}
         integer(int64), intent(in)           :: dimensions
{%- else %}
         integer(int64), intent(in)           :: dimensions({{d}})
{%- endif %}
         integer(int32), intent(out)          :: ierr
         integer(int32), intent(in), optional :: device_id
{%- if d == 1 %}
         integer(int64), intent(in), optional :: lbounds
{%- else %}
         integer(int64), intent(in), optional :: lbounds({{d}})
{%- endif %}
      end subroutine {{p.name}}_devxlib_malloc_alloc_{{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_malloc_free_{{t[0]|lower}}{{d}}d(dev_ptr, device_id)
         implicit none
         {{t}}({{p.val}}), pointer, contiguous, intent(inout) DEV_ATTR :: dev_ptr({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
         integer, optional, intent(in)  :: device_id
      end subroutine {{p.name}}_devxlib_malloc_free_{{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 function {{p.name}}_devxlib_malloc_allocated_{{t[0]|lower}}{{d}}d(array) result(res)
         implicit none
         logical :: res
         {{t}}({{p.val}}), allocatable, intent(in) DEV_ATTR :: array({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
      end function {{p.name}}_devxlib_malloc_allocated_{{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 function {{p.name}}_devxlib_malloc_allocated_{{t[0]|lower}}{{d}}d_p(dev_ptr) result(res)
         implicit none
         logical :: res
         {{t}}({{p.val}}), pointer, intent(in) DEV_ATTR :: dev_ptr({% for dd in range(d) %}:{% if not loop.last %}, {%- endif %}{% endfor %})
      end function {{p.name}}_devxlib_malloc_allocated_{{t[0]|lower}}{{d}}d_p
   {%- endfor %}
   {%- endfor %}
   {%- endfor %}
   endinterface
endmodule devxlib_malloc
