diff --git a/openmp/libomptarget/include/omptarget.h b/openmp/libomptarget/include/omptarget.h --- a/openmp/libomptarget/include/omptarget.h +++ b/openmp/libomptarget/include/omptarget.h @@ -86,6 +86,13 @@ OMP_REQ_DYNAMIC_ALLOCATORS = 0x010 }; +enum TargetAllocTy : int32_t { + TARGET_ALLOC_DEVICE = 0, + TARGET_ALLOC_HOST, + TARGET_ALLOC_SHARED, + TARGET_ALLOC_DEFAULT +}; + /// This struct is a record of an entry point or global. For a function /// entry point the size is expected to be zero struct __tgt_offload_entry { @@ -190,6 +197,12 @@ size_t device_offset, int device_num); int omp_target_disassociate_ptr(void *host_ptr, int device_num); +/// Explicit target memory allocators +/// Using the llvm_ prefix until they become part of the OpenMP standard. +void *llvm_omp_target_alloc_device(size_t size, int device_num); +void *llvm_omp_target_alloc_host(size_t size, int device_num); +void *llvm_omp_target_alloc_shared(size_t size, int device_num); + /// add the clauses of the requires directives in a given file void __tgt_register_requires(int64_t flags); diff --git a/openmp/libomptarget/include/omptargetplugin.h b/openmp/libomptarget/include/omptargetplugin.h --- a/openmp/libomptarget/include/omptargetplugin.h +++ b/openmp/libomptarget/include/omptargetplugin.h @@ -68,6 +68,9 @@ // case an error occurred on the target device. void *__tgt_rtl_data_alloc(int32_t ID, int64_t Size, void *HostPtr); +// Explicit target memory allocator +void *__tgt_rtl_data_alloc_explicit(int32_t ID, int64_t Size, int32_t Kind); + // Pass the data content to the target device using the target address. In case // of success, return zero. Otherwise, return an error code. int32_t __tgt_rtl_data_submit(int32_t ID, void *TargetPtr, void *HostPtr, diff --git a/openmp/libomptarget/plugins/exports b/openmp/libomptarget/plugins/exports --- a/openmp/libomptarget/plugins/exports +++ b/openmp/libomptarget/plugins/exports @@ -7,6 +7,7 @@ __tgt_rtl_init_device; __tgt_rtl_load_binary; __tgt_rtl_data_alloc; + __tgt_rtl_data_alloc_explicit; __tgt_rtl_data_submit; __tgt_rtl_data_submit_async; __tgt_rtl_data_retrieve; diff --git a/openmp/libomptarget/plugins/generic-elf-64bit/src/rtl.cpp b/openmp/libomptarget/plugins/generic-elf-64bit/src/rtl.cpp --- a/openmp/libomptarget/plugins/generic-elf-64bit/src/rtl.cpp +++ b/openmp/libomptarget/plugins/generic-elf-64bit/src/rtl.cpp @@ -255,6 +255,25 @@ return ptr; } +// Sample implementation of explicit memory allocator. For this plugin all kinds +// are equivalent to each other. +void *__tgt_rtl_data_alloc_explicit(int32_t device_id, int64_t size, + int32_t kind) { + void *ptr = NULL; + + switch (kind) { + case TARGET_ALLOC_DEVICE: + case TARGET_ALLOC_HOST: + case TARGET_ALLOC_SHARED: + ptr = malloc(size); + break; + default: + REPORT("Invalid target data allocation kind"); + } + + return ptr; +} + int32_t __tgt_rtl_data_submit(int32_t device_id, void *tgt_ptr, void *hst_ptr, int64_t size) { memcpy(tgt_ptr, hst_ptr, size); diff --git a/openmp/libomptarget/src/api.cpp b/openmp/libomptarget/src/api.cpp --- a/openmp/libomptarget/src/api.cpp +++ b/openmp/libomptarget/src/api.cpp @@ -326,3 +326,44 @@ DP("omp_target_disassociate_ptr returns %d\n", rc); return rc; } + +static void *targetAllocExplicit(size_t size, int device_num, int kind, + const char *name) { + TIMESCOPE(); + DP("Call to %s for device %d requesting %zu bytes\n", name, device_num, size); + + if (size <= 0) { + DP("Call to %s with non-positive length\n", name); + return NULL; + } + + void *rc = NULL; + + if (device_num == omp_get_initial_device()) { + rc = malloc(size); + DP("%s returns host ptr " DPxMOD "\n", name, DPxPTR(rc)); + return rc; + } + + if (!device_is_ready(device_num)) { + DP("%s returns NULL ptr\n", name); + return NULL; + } + + DeviceTy &Device = PM->Devices[device_num]; + rc = Device.allocDataExplicit(size, kind); + DP("%s returns device ptr " DPxMOD "\n", name, DPxPTR(rc)); + return rc; +} + +EXTERN void *llvm_omp_target_alloc_device(size_t size, int device_num) { + return targetAllocExplicit(size, device_num, TARGET_ALLOC_DEVICE, __func__); +} + +EXTERN void *llvm_omp_target_alloc_host(size_t size, int device_num) { + return targetAllocExplicit(size, device_num, TARGET_ALLOC_HOST, __func__); +} + +EXTERN void *llvm_omp_target_alloc_shared(size_t size, int device_num) { + return targetAllocExplicit(size, device_num, TARGET_ALLOC_SHARED, __func__); +} diff --git a/openmp/libomptarget/src/device.h b/openmp/libomptarget/src/device.h --- a/openmp/libomptarget/src/device.h +++ b/openmp/libomptarget/src/device.h @@ -192,6 +192,9 @@ /// pointer association. Actually, all the __tgt_rtl_data_alloc /// implementations ignore \p HstPtr. void *allocData(int64_t Size, void *HstPtr = nullptr); + /// Allocates \p Size bytes on the host or device or shared memory space, + /// depending on \p Kind. + void *allocDataExplicit(int64_t Size, int32_t Kind); /// Deallocates memory which \p TgtPtrBegin points at and returns /// OFFLOAD_SUCCESS/OFFLOAD_FAIL when succeeds/fails. int32_t deleteData(void *TgtPtrBegin); diff --git a/openmp/libomptarget/src/device.cpp b/openmp/libomptarget/src/device.cpp --- a/openmp/libomptarget/src/device.cpp +++ b/openmp/libomptarget/src/device.cpp @@ -409,6 +409,13 @@ return RTL->data_alloc(RTLDeviceID, Size, HstPtr); } +void *DeviceTy::allocDataExplicit(int64_t Size, int32_t Kind) { + if (RTL->data_alloc_explicit) + return RTL->data_alloc_explicit(RTLDeviceID, Size, Kind); + else + return nullptr; +} + int32_t DeviceTy::deleteData(void *TgtPtrBegin) { return RTL->data_delete(RTLDeviceID, TgtPtrBegin); } diff --git a/openmp/libomptarget/src/exports b/openmp/libomptarget/src/exports --- a/openmp/libomptarget/src/exports +++ b/openmp/libomptarget/src/exports @@ -34,6 +34,9 @@ omp_target_memcpy_rect; omp_target_associate_ptr; omp_target_disassociate_ptr; + llvm_omp_target_alloc_host; + llvm_omp_target_alloc_shared; + llvm_omp_target_alloc_device; __kmpc_push_target_tripcount; local: *; diff --git a/openmp/libomptarget/src/rtl.h b/openmp/libomptarget/src/rtl.h --- a/openmp/libomptarget/src/rtl.h +++ b/openmp/libomptarget/src/rtl.h @@ -31,6 +31,7 @@ typedef int32_t(init_device_ty)(int32_t); typedef __tgt_target_table *(load_binary_ty)(int32_t, void *); typedef void *(data_alloc_ty)(int32_t, int64_t, void *); + typedef void *(data_alloc_explicit_ty)(int32_t, int64_t, int32_t); typedef int32_t(data_submit_ty)(int32_t, void *, void *, int64_t); typedef int32_t(data_submit_async_ty)(int32_t, void *, void *, int64_t, __tgt_async_info *); @@ -75,6 +76,7 @@ init_device_ty *init_device = nullptr; load_binary_ty *load_binary = nullptr; data_alloc_ty *data_alloc = nullptr; + data_alloc_explicit_ty *data_alloc_explicit = nullptr; data_submit_ty *data_submit = nullptr; data_submit_async_ty *data_submit_async = nullptr; data_retrieve_ty *data_retrieve = nullptr; diff --git a/openmp/libomptarget/src/rtl.cpp b/openmp/libomptarget/src/rtl.cpp --- a/openmp/libomptarget/src/rtl.cpp +++ b/openmp/libomptarget/src/rtl.cpp @@ -175,6 +175,8 @@ dlsym(dynlib_handle, "__tgt_rtl_unregister_lib"); *((void **)&R.supports_empty_images) = dlsym(dynlib_handle, "__tgt_rtl_supports_empty_images"); + *((void **)&R.data_alloc_explicit) = + dlsym(dynlib_handle, "__tgt_rtl_data_alloc_explicit"); } DP("RTLs loaded!\n");