diff --git a/openmp/runtime/src/dllexports b/openmp/runtime/src/dllexports --- a/openmp/runtime/src/dllexports +++ b/openmp/runtime/src/dllexports @@ -518,6 +518,7 @@ __kmpc_get_default_allocator __kmpc_alloc __kmpc_calloc + __kmpc_realloc __kmpc_free __kmpc_init_allocator __kmpc_destroy_allocator @@ -536,6 +537,7 @@ omp_fulfill_event 759 omp_display_env 733 omp_calloc 776 + omp_realloc 777 omp_null_allocator DATA omp_default_mem_alloc DATA diff --git a/openmp/runtime/src/include/omp.h.var b/openmp/runtime/src/include/omp.h.var --- a/openmp/runtime/src/include/omp.h.var +++ b/openmp/runtime/src/include/omp.h.var @@ -324,10 +324,15 @@ # ifdef __cplusplus extern void *__KAI_KMPC_CONVENTION omp_alloc(size_t size, omp_allocator_handle_t a = omp_null_allocator); extern void *__KAI_KMPC_CONVENTION omp_calloc(size_t nmemb, size_t size, omp_allocator_handle_t a = omp_null_allocator); + extern void *__KAI_KMPC_CONVENTION omp_realloc(void *ptr, size_t size, + omp_allocator_handle_t allocator = omp_null_allocator, + omp_allocator_handle_t free_allocator = omp_null_allocator); extern void __KAI_KMPC_CONVENTION omp_free(void * ptr, omp_allocator_handle_t a = omp_null_allocator); # else extern void *__KAI_KMPC_CONVENTION omp_alloc(size_t size, omp_allocator_handle_t a); extern void *__KAI_KMPC_CONVENTION omp_calloc(size_t nmemb, size_t size, omp_allocator_handle_t a); + extern void *__KAI_KMPC_CONVENTION omp_realloc(void *ptr, size_t size, omp_allocator_handle_t allocator, + omp_allocator_handle_t free_allocator); extern void __KAI_KMPC_CONVENTION omp_free(void *ptr, omp_allocator_handle_t a); # endif diff --git a/openmp/runtime/src/kmp.h b/openmp/runtime/src/kmp.h --- a/openmp/runtime/src/kmp.h +++ b/openmp/runtime/src/kmp.h @@ -965,6 +965,9 @@ extern void *__kmpc_alloc(int gtid, size_t sz, omp_allocator_handle_t al); extern void *__kmpc_calloc(int gtid, size_t nmemb, size_t sz, omp_allocator_handle_t al); +extern void *__kmpc_realloc(int gtid, void *ptr, size_t sz, + omp_allocator_handle_t al, + omp_allocator_handle_t free_al); extern void __kmpc_free(int gtid, void *ptr, omp_allocator_handle_t al); extern void __kmp_init_memkind(); diff --git a/openmp/runtime/src/kmp_alloc.cpp b/openmp/runtime/src/kmp_alloc.cpp --- a/openmp/runtime/src/kmp_alloc.cpp +++ b/openmp/runtime/src/kmp_alloc.cpp @@ -1436,6 +1436,7 @@ typedef struct kmp_mem_desc { // Memory block descriptor void *ptr_alloc; // Pointer returned by allocator size_t size_a; // Size of allocated memory block (initial+descriptor+align) + size_t size_orig; // Original size requested void *ptr_align; // Pointer to aligned memory, returned kmp_allocator_t *allocator; // allocator } kmp_mem_desc_t; @@ -1464,6 +1465,7 @@ if (allocator > kmp_max_mem_alloc && al->alignment > 0) { align = al->alignment; // alignment requested by user } + desc.size_orig = size; desc.size_a = size + sz_desc + align; if (__kmp_memkind_available) { @@ -1612,6 +1614,47 @@ return ptr; } +void *__kmpc_realloc(int gtid, void *ptr, size_t size, + omp_allocator_handle_t allocator, + omp_allocator_handle_t free_allocator) { + void *nptr = NULL; + KMP_DEBUG_ASSERT(__kmp_init_serial); + + if (size == 0) { + if (ptr != NULL) + __kmpc_free(gtid, ptr, free_allocator); + return nptr; + } + + KE_TRACE(25, ("__kmpc_realloc: T#%d (%p, %d, %p, %p)\n", gtid, ptr, (int)size, + allocator, free_allocator)); + + nptr = __kmpc_alloc(gtid, size, allocator); + + if (nptr != NULL && ptr != NULL) { + kmp_mem_desc_t desc; + kmp_uintptr_t addr_align; // address to return to caller + kmp_uintptr_t addr_descr; // address of memory block descriptor + + addr_align = (kmp_uintptr_t)ptr; + addr_descr = addr_align - sizeof(kmp_mem_desc_t); + desc = *((kmp_mem_desc_t *)addr_descr); // read descriptor + + KMP_DEBUG_ASSERT(desc.ptr_align == ptr); + KMP_DEBUG_ASSERT(desc.size_orig > 0); + KMP_DEBUG_ASSERT(desc.size_orig < desc.size_a); + KMP_MEMCPY((char *)nptr, (char *)ptr, + (size_t)((size < desc.size_orig) ? size : desc.size_orig)); + } + + if (nptr != NULL) { + __kmpc_free(gtid, ptr, free_allocator); + } + + KE_TRACE(25, ("__kmpc_realloc returns %p, T#%d\n", nptr, gtid)); + return nptr; +} + void __kmpc_free(int gtid, void *ptr, const omp_allocator_handle_t allocator) { KE_TRACE(25, ("__kmpc_free: T#%d free(%p,%p)\n", gtid, ptr, allocator)); if (ptr == NULL) diff --git a/openmp/runtime/src/kmp_csupport.cpp b/openmp/runtime/src/kmp_csupport.cpp --- a/openmp/runtime/src/kmp_csupport.cpp +++ b/openmp/runtime/src/kmp_csupport.cpp @@ -4213,6 +4213,12 @@ return __kmpc_calloc(__kmp_entry_gtid(), nmemb, size, allocator); } +void *omp_realloc(void *ptr, size_t size, omp_allocator_handle_t allocator, + omp_allocator_handle_t free_allocator) { + return __kmpc_realloc(__kmp_entry_gtid(), ptr, size, allocator, + free_allocator); +} + void omp_free(void *ptr, omp_allocator_handle_t allocator) { __kmpc_free(__kmp_entry_gtid(), ptr, allocator); } diff --git a/openmp/runtime/src/kmp_stub.cpp b/openmp/runtime/src/kmp_stub.cpp --- a/openmp/runtime/src/kmp_stub.cpp +++ b/openmp/runtime/src/kmp_stub.cpp @@ -371,6 +371,12 @@ i; return calloc(nmemb, size); } +void *omp_realloc(void *ptr, size_t size, + const omp_allocator_handle_t allocator, + const omp_allocator_handle_t free_allocator) { + i; + return realloc(ptr, size); +} void omp_free(void *ptr, const omp_allocator_handle_t allocator) { i; free(ptr); diff --git a/openmp/runtime/test/api/omp_calloc_def_fb.c b/openmp/runtime/test/api/omp_calloc_def_fb.c --- a/openmp/runtime/test/api/omp_calloc_def_fb.c +++ b/openmp/runtime/test/api/omp_calloc_def_fb.c @@ -12,7 +12,7 @@ at[1].key = omp_atk_fallback; at[1].value = omp_atv_default_mem_fb; a = omp_init_allocator(omp_large_cap_mem_space, 2, at); - printf("allocator large created: %p\n", a); + printf("allocator large created: %p\n", (void *)a); #pragma omp parallel num_threads(2) { int i = omp_get_thread_num(); diff --git a/openmp/runtime/test/api/omp_calloc_size_0.c b/openmp/runtime/test/api/omp_calloc_size_0.c --- a/openmp/runtime/test/api/omp_calloc_size_0.c +++ b/openmp/runtime/test/api/omp_calloc_size_0.c @@ -13,7 +13,7 @@ at[1].key = omp_atk_fallback; at[1].value = omp_atv_default_mem_fb; a = omp_init_allocator(omp_large_cap_mem_space, 2, at); - printf("allocator large created: %p\n", a); + printf("allocator large created: %p\n", (void *)a); #pragma omp parallel num_threads(2) { int i = omp_get_thread_num(); diff --git a/openmp/runtime/test/api/omp_calloc_def_fb.c b/openmp/runtime/test/api/omp_realloc_def_fb.c copy from openmp/runtime/test/api/omp_calloc_def_fb.c copy to openmp/runtime/test/api/omp_realloc_def_fb.c --- a/openmp/runtime/test/api/omp_calloc_def_fb.c +++ b/openmp/runtime/test/api/omp_realloc_def_fb.c @@ -6,27 +6,35 @@ int main() { omp_alloctrait_t at[2]; omp_allocator_handle_t a; - void *p[2]; + omp_allocator_handle_t f_a; + void *ptr[2]; + void *nptr[2]; at[0].key = omp_atk_pool_size; at[0].value = 2 * 1024 * 1024; at[1].key = omp_atk_fallback; at[1].value = omp_atv_default_mem_fb; + a = omp_init_allocator(omp_large_cap_mem_space, 2, at); - printf("allocator large created: %p\n", a); + f_a = omp_init_allocator(omp_default_mem_space, 2, at); + printf("allocator large created: %p\n", (void *)a); + printf("allocator default created: %p\n", (void *)f_a); + #pragma omp parallel num_threads(2) { int i = omp_get_thread_num(); - p[i] = omp_calloc(1024, 1024, a); + ptr[i] = omp_alloc(1024 * 1024, f_a); + #pragma omp barrier + nptr[i] = omp_realloc(ptr[i], 1024 * 1024, a, f_a); #pragma omp barrier - printf("th %d, ptr %p\n", i, p[i]); - omp_free(p[i], a); + printf("th %d, nptr %p\n", i, nptr[i]); + omp_free(nptr[i], a); } // Both pointers should be non-NULL - if (p[0] != NULL && p[1] != NULL) { + if (nptr[0] != NULL && nptr[1] != NULL) { printf("passed\n"); return 0; } else { - printf("failed: pointers %p %p\n", p[0], p[1]); + printf("failed: pointers %p %p\n", nptr[0], nptr[1]); return 1; } } diff --git a/openmp/runtime/test/api/omp_realloc_null_ptr.c b/openmp/runtime/test/api/omp_realloc_null_ptr.c new file mode 100644 --- /dev/null +++ b/openmp/runtime/test/api/omp_realloc_null_ptr.c @@ -0,0 +1,46 @@ +// RUN: %libomp-compile-and-run + +#include +#include + +int main() +{ + omp_alloctrait_t at[2]; + omp_allocator_handle_t a; + omp_allocator_handle_t f_a; + void *ptr[2]; + void *nptr[2]; + at[0].key = omp_atk_pool_size; + at[0].value = 2*1024*1024; + at[1].key = omp_atk_fallback; + at[1].value = omp_atv_default_mem_fb; + + a = omp_init_allocator(omp_large_cap_mem_space, 2, at); + f_a = omp_init_allocator(omp_default_mem_space, 2, at); + printf("allocator large created: %p\n", (void *)a); + printf("allocator default created: %p\n", (void *)f_a); + + #pragma omp parallel num_threads(2) + { + int i = omp_get_thread_num(); + ptr[i] = omp_alloc(0, f_a); + #pragma omp barrier + nptr[i] = omp_realloc(ptr[i], 1024 * 1024, a, f_a); + #pragma omp barrier + printf("th %d, nptr %p\n", i, nptr[i]); + omp_free(nptr[i], a); + } + + // Both ptr pointers should be NULL + if (ptr[0] != NULL || ptr[1] != NULL) { + printf("failed: pointers %p %p\n", ptr[0], ptr[1]); + return 1; + } + // Both nptr pointers should be non-NULL + if (nptr[0] == NULL || nptr[1] == NULL) { + printf("failed: pointers %p %p\n", nptr[0], nptr[1]); + return 1; + } + printf("passed\n"); + return 0; +} diff --git a/openmp/runtime/test/api/omp_realloc_size_0.c b/openmp/runtime/test/api/omp_realloc_size_0.c new file mode 100644 --- /dev/null +++ b/openmp/runtime/test/api/omp_realloc_size_0.c @@ -0,0 +1,46 @@ +// RUN: %libomp-compile-and-run + +#include +#include + +int main() +{ + omp_alloctrait_t at[2]; + omp_allocator_handle_t a; + omp_allocator_handle_t f_a; + void *ptr[2]; + void *nptr[2]; + at[0].key = omp_atk_pool_size; + at[0].value = 2*1024*1024; + at[1].key = omp_atk_fallback; + at[1].value = omp_atv_default_mem_fb; + + a = omp_init_allocator(omp_large_cap_mem_space, 2, at); + f_a = omp_init_allocator(omp_default_mem_space, 2, at); + printf("allocator large created: %p\n", (void *)a); + printf("allocator default created: %p\n", (void *)f_a); + + #pragma omp parallel num_threads(2) + { + int i = omp_get_thread_num(); + ptr[i] = omp_alloc(1024 * 1024, f_a); + #pragma omp barrier + nptr[i] = omp_realloc(ptr[i], 0, a, f_a); + #pragma omp barrier + printf("th %d, nptr %p\n", i, nptr[i]); + omp_free(nptr[i], a); + } + + // Both ptr pointers should be non-NULL + if (ptr[0] == NULL || ptr[1] == NULL) { + printf("failed: pointers %p %p\n", ptr[0], ptr[1]); + return 1; + } + // Both nptr pointers should be NULL + if (nptr[0] != NULL || nptr[1] != NULL) { + printf("failed: pointers %p %p\n", nptr[0], nptr[1]); + return 1; + } + printf("passed\n"); + return 0; +} diff --git a/openmp/runtime/tools/generate-def.pl b/openmp/runtime/tools/generate-def.pl --- a/openmp/runtime/tools/generate-def.pl +++ b/openmp/runtime/tools/generate-def.pl @@ -108,8 +108,9 @@ foreach my $entry ( keys( %$entries ) ) { if ( not $entries->{ $entry }->{ obsolete } ) { my $ordinal = $entries->{ $entry }->{ ordinal }; - # omp_alloc, omp_calloc and omp_free are C/C++ only functions, skip "1000+ordinal" for them - if ( $entry =~ m{\A[ok]mp_} and $entry ne "omp_alloc" and $entry ne "omp_calloc" and $entry ne "omp_free" ) { + # omp_alloc, omp_calloc, omp_realloc and omp_free are C/C++ only functions, skip "1000+ordinal" for them + if ( $entry =~ m{\A[ok]mp_} and $entry ne "omp_alloc" and $entry ne "omp_calloc" and + $entry ne "omp_realloc" and $entry ne "omp_free" ) { if ( not defined( $ordinal ) ) { runtime_error( "Bad entry \"$entry\": ordinal number is not specified."