diff options
Diffstat (limited to 'openmp/offload/src/offload_myo_host.cpp')
-rw-r--r-- | openmp/offload/src/offload_myo_host.cpp | 805 |
1 files changed, 805 insertions, 0 deletions
diff --git a/openmp/offload/src/offload_myo_host.cpp b/openmp/offload/src/offload_myo_host.cpp new file mode 100644 index 00000000000..2e1c186a57a --- /dev/null +++ b/openmp/offload/src/offload_myo_host.cpp @@ -0,0 +1,805 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.txt for details. +// +//===----------------------------------------------------------------------===// + + +#include "offload_myo_host.h" +#include <errno.h> +#include <malloc.h> +#include "offload_host.h" + +#if defined(LINUX) || defined(FREEBSD) +#include <mm_malloc.h> +#endif + +#define MYO_VERSION1 "MYO_1.0" + +extern "C" void __cilkrts_cilk_for_32(void*, void*, uint32_t, int32_t); +extern "C" void __cilkrts_cilk_for_64(void*, void*, uint64_t, int32_t); + +#ifndef TARGET_WINNT +#pragma weak __cilkrts_cilk_for_32 +#pragma weak __cilkrts_cilk_for_64 +#endif // TARGET_WINNT + +#ifdef TARGET_WINNT +#define MYO_TABLE_END_MARKER() reinterpret_cast<const char*>(-1) +#else // TARGET_WINNT +#define MYO_TABLE_END_MARKER() reinterpret_cast<const char*>(0) +#endif // TARGET_WINNT + +class MyoWrapper { +public: + MyoWrapper() : m_lib_handle(0), m_is_available(false) + {} + + bool is_available() const { + return m_is_available; + } + + bool LoadLibrary(void); + + // unloads the library + void UnloadLibrary(void) { +// if (m_lib_handle != 0) { +// DL_close(m_lib_handle); +// m_lib_handle = 0; +// } + } + + // Wrappers for MYO client functions + void LibInit(void *arg, void *func) const { + OFFLOAD_DEBUG_TRACE_1(4, 0, c_offload_myoinit, + "%s(%p, %p)\n", __func__, arg, func); + CheckResult(__func__, m_lib_init(arg, func)); + } + + void LibFini(void) const { + OFFLOAD_DEBUG_TRACE_1(4, 0, c_offload_myofini, "%s()\n", __func__); + m_lib_fini(); + } + + void* SharedMalloc(size_t size) const { + OFFLOAD_DEBUG_TRACE_1(4, 0, c_offload_myosharedmalloc, + "%s(%lld)\n", __func__, size); + return m_shared_malloc(size); + } + + void SharedFree(void *ptr) const { + OFFLOAD_DEBUG_TRACE_1(4, 0, c_offload_myosharedfree, + "%s(%p)\n", __func__, ptr); + m_shared_free(ptr); + } + + void* SharedAlignedMalloc(size_t size, size_t align) const { + OFFLOAD_DEBUG_TRACE_1(4, 0, c_offload_myosharedalignedmalloc, + "%s(%lld, %lld)\n", __func__, size, align); + return m_shared_aligned_malloc(size, align); + } + + void SharedAlignedFree(void *ptr) const { + OFFLOAD_DEBUG_TRACE_1(4, 0, c_offload_myosharedalignedfree, + "%s(%p)\n", __func__, ptr); + m_shared_aligned_free(ptr); + } + + void Acquire(void) const { + OFFLOAD_DEBUG_TRACE_1(4, 0, c_offload_myoacquire, + "%s()\n", __func__); + CheckResult(__func__, m_acquire()); + } + + void Release(void) const { + OFFLOAD_DEBUG_TRACE_1(4, 0, c_offload_myorelease, + "%s()\n", __func__); + CheckResult(__func__, m_release()); + } + + void HostVarTablePropagate(void *table, int num_entries) const { + OFFLOAD_DEBUG_TRACE(4, "%s(%p, %d)\n", __func__, table, num_entries); + CheckResult(__func__, m_host_var_table_propagate(table, num_entries)); + } + + void HostFptrTableRegister(void *table, int num_entries, + int ordered) const { + OFFLOAD_DEBUG_TRACE_1(4, 0, c_offload_myoregister, + "%s(%p, %d, %d)\n", __func__, table, + num_entries, ordered); + CheckResult(__func__, + m_host_fptr_table_register(table, num_entries, ordered)); + } + + void RemoteThunkCall(void *thunk, void *args, int device) { + OFFLOAD_DEBUG_TRACE(4, "%s(%p, %p, %d)\n", __func__, thunk, args, + device); + CheckResult(__func__, m_remote_thunk_call(thunk, args, device)); + } + + MyoiRFuncCallHandle RemoteCall(char *func, void *args, int device) const { + OFFLOAD_DEBUG_TRACE(4, "%s(%s, %p, %d)\n", __func__, func, args, + device); + return m_remote_call(func, args, device); + } + + void GetResult(MyoiRFuncCallHandle handle) const { + OFFLOAD_DEBUG_TRACE(4, "%s(%p)\n", __func__, handle); + CheckResult(__func__, m_get_result(handle)); + } + +private: + void CheckResult(const char *func, MyoError error) const { + if (error != MYO_SUCCESS) { + LIBOFFLOAD_ERROR(c_myowrapper_checkresult, func, error); + exit(1); + } + } + +private: + void* m_lib_handle; + bool m_is_available; + + // pointers to functions from myo library + MyoError (*m_lib_init)(void*, void*); + void (*m_lib_fini)(void); + void* (*m_shared_malloc)(size_t); + void (*m_shared_free)(void*); + void* (*m_shared_aligned_malloc)(size_t, size_t); + void (*m_shared_aligned_free)(void*); + MyoError (*m_acquire)(void); + MyoError (*m_release)(void); + MyoError (*m_host_var_table_propagate)(void*, int); + MyoError (*m_host_fptr_table_register)(void*, int, int); + MyoError (*m_remote_thunk_call)(void*, void*, int); + MyoiRFuncCallHandle (*m_remote_call)(char*, void*, int); + MyoError (*m_get_result)(MyoiRFuncCallHandle); +}; + +bool MyoWrapper::LoadLibrary(void) +{ +#ifndef TARGET_WINNT + const char *lib_name = "libmyo-client.so"; +#else // TARGET_WINNT + const char *lib_name = "myo-client.dll"; +#endif // TARGET_WINNT + + OFFLOAD_DEBUG_TRACE(2, "Loading MYO library %s ...\n", lib_name); + + m_lib_handle = DL_open(lib_name); + if (m_lib_handle == 0) { + OFFLOAD_DEBUG_TRACE(2, "Failed to load the library. errno = %d\n", + errno); + return false; + } + + m_lib_init = (MyoError (*)(void*, void*)) + DL_sym(m_lib_handle, "myoiLibInit", MYO_VERSION1); + if (m_lib_init == 0) { + OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n", + "myoiLibInit"); + UnloadLibrary(); + return false; + } + + m_lib_fini = (void (*)(void)) + DL_sym(m_lib_handle, "myoiLibFini", MYO_VERSION1); + if (m_lib_fini == 0) { + OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n", + "myoiLibFini"); + UnloadLibrary(); + return false; + } + + m_shared_malloc = (void* (*)(size_t)) + DL_sym(m_lib_handle, "myoSharedMalloc", MYO_VERSION1); + if (m_shared_malloc == 0) { + OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n", + "myoSharedMalloc"); + UnloadLibrary(); + return false; + } + + m_shared_free = (void (*)(void*)) + DL_sym(m_lib_handle, "myoSharedFree", MYO_VERSION1); + if (m_shared_free == 0) { + OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n", + "myoSharedFree"); + UnloadLibrary(); + return false; + } + + m_shared_aligned_malloc = (void* (*)(size_t, size_t)) + DL_sym(m_lib_handle, "myoSharedAlignedMalloc", MYO_VERSION1); + if (m_shared_aligned_malloc == 0) { + OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n", + "myoSharedAlignedMalloc"); + UnloadLibrary(); + return false; + } + + m_shared_aligned_free = (void (*)(void*)) + DL_sym(m_lib_handle, "myoSharedAlignedFree", MYO_VERSION1); + if (m_shared_aligned_free == 0) { + OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n", + "myoSharedAlignedFree"); + UnloadLibrary(); + return false; + } + + m_acquire = (MyoError (*)(void)) + DL_sym(m_lib_handle, "myoAcquire", MYO_VERSION1); + if (m_acquire == 0) { + OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n", + "myoAcquire"); + UnloadLibrary(); + return false; + } + + m_release = (MyoError (*)(void)) + DL_sym(m_lib_handle, "myoRelease", MYO_VERSION1); + if (m_release == 0) { + OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n", + "myoRelease"); + UnloadLibrary(); + return false; + } + + m_host_var_table_propagate = (MyoError (*)(void*, int)) + DL_sym(m_lib_handle, "myoiHostVarTablePropagate", MYO_VERSION1); + if (m_host_var_table_propagate == 0) { + OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n", + "myoiHostVarTablePropagate"); + UnloadLibrary(); + return false; + } + + m_host_fptr_table_register = (MyoError (*)(void*, int, int)) + DL_sym(m_lib_handle, "myoiHostFptrTableRegister", MYO_VERSION1); + if (m_host_fptr_table_register == 0) { + OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n", + "myoiHostFptrTableRegister"); + UnloadLibrary(); + return false; + } + + m_remote_thunk_call = (MyoError (*)(void*, void*, int)) + DL_sym(m_lib_handle, "myoiRemoteThunkCall", MYO_VERSION1); + if (m_remote_thunk_call == 0) { + OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n", + "myoiRemoteThunkCall"); + UnloadLibrary(); + return false; + } + + m_remote_call = (MyoiRFuncCallHandle (*)(char*, void*, int)) + DL_sym(m_lib_handle, "myoiRemoteCall", MYO_VERSION1); + if (m_remote_call == 0) { + OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n", + "myoiRemoteCall"); + UnloadLibrary(); + return false; + } + + m_get_result = (MyoError (*)(MyoiRFuncCallHandle)) + DL_sym(m_lib_handle, "myoiGetResult", MYO_VERSION1); + if (m_get_result == 0) { + OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n", + "myoiGetResult"); + UnloadLibrary(); + return false; + } + + OFFLOAD_DEBUG_TRACE(2, "The library was successfully loaded\n"); + + m_is_available = true; + + return true; +} + +static bool myo_is_available; +static MyoWrapper myo_wrapper; + +struct MyoTable +{ + MyoTable(SharedTableEntry *tab, int len) : var_tab(tab), var_tab_len(len) + {} + + SharedTableEntry* var_tab; + int var_tab_len; +}; + +typedef std::list<MyoTable> MyoTableList; +static MyoTableList __myo_table_list; +static mutex_t __myo_table_lock; +static bool __myo_tables = false; + +static void __offload_myo_shared_table_register(SharedTableEntry *entry); +static void __offload_myo_shared_init_table_register(InitTableEntry* entry); +static void __offload_myo_fptr_table_register(FptrTableEntry *entry); + +static void __offload_myoLoadLibrary_once(void) +{ + if (__offload_init_library()) { + myo_wrapper.LoadLibrary(); + } +} + +static bool __offload_myoLoadLibrary(void) +{ + static OffloadOnceControl ctrl = OFFLOAD_ONCE_CONTROL_INIT; + __offload_run_once(&ctrl, __offload_myoLoadLibrary_once); + + return myo_wrapper.is_available(); +} + +static void __offload_myoInit_once(void) +{ + if (!__offload_myoLoadLibrary()) { + return; + } + + // initialize all devices + for (int i = 0; i < mic_engines_total; i++) { + mic_engines[i].init(); + } + + // load and initialize MYO library + OFFLOAD_DEBUG_TRACE(2, "Initializing MYO library ...\n"); + + COIEVENT events[MIC_ENGINES_MAX]; + MyoiUserParams params[MIC_ENGINES_MAX+1]; + + // load target library to all devices + for (int i = 0; i < mic_engines_total; i++) { + mic_engines[i].init_myo(&events[i]); + + params[i].type = MYOI_USERPARAMS_DEVID; + params[i].nodeid = mic_engines[i].get_physical_index() + 1; + } + + params[mic_engines_total].type = MYOI_USERPARAMS_LAST_MSG; + + // initialize myo runtime on host + myo_wrapper.LibInit(params, 0); + + // wait for the target init calls to finish + COIRESULT res; + res = COI::EventWait(mic_engines_total, events, -1, 1, 0, 0); + if (res != COI_SUCCESS) { + LIBOFFLOAD_ERROR(c_event_wait, res); + exit(1); + } + + myo_is_available = true; + + OFFLOAD_DEBUG_TRACE(2, "Initializing MYO library ... done\n"); +} + +static bool __offload_myoInit(void) +{ + static OffloadOnceControl ctrl = OFFLOAD_ONCE_CONTROL_INIT; + __offload_run_once(&ctrl, __offload_myoInit_once); + + // register pending shared var tables + if (myo_is_available && __myo_tables) { + mutex_locker_t locker(__myo_table_lock); + + if (__myo_tables) { + // Register tables with MYO so it can propagate to target. + for(MyoTableList::const_iterator it = __myo_table_list.begin(); + it != __myo_table_list.end(); ++it) { +#ifdef TARGET_WINNT + for (SharedTableEntry *entry = it->var_tab; + entry->varName != MYO_TABLE_END_MARKER(); entry++) { + if (entry->varName == 0) { + continue; + } + myo_wrapper.HostVarTablePropagate(entry, 1); + } +#else // TARGET_WINNT + myo_wrapper.HostVarTablePropagate(it->var_tab, + it->var_tab_len); +#endif // TARGET_WINNT + } + + __myo_table_list.clear(); + __myo_tables = false; + } + } + + return myo_is_available; +} + +static bool shared_table_entries( + SharedTableEntry *entry +) +{ + OFFLOAD_DEBUG_TRACE(3, "%s(%p)\n", __func__, entry); + + for (; entry->varName != MYO_TABLE_END_MARKER(); entry++) { +#ifdef TARGET_WINNT + if (entry->varName == 0) { + continue; + } +#endif // TARGET_WINNT + + return true; + } + + return false; +} + +static bool fptr_table_entries( + FptrTableEntry *entry +) +{ + OFFLOAD_DEBUG_TRACE(3, "%s(%p)\n", __func__, entry); + + for (; entry->funcName != MYO_TABLE_END_MARKER(); entry++) { +#ifdef TARGET_WINNT + if (entry->funcName == 0) { + continue; + } +#endif // TARGET_WINNT + + return true; + } + + return false; +} + +extern "C" void __offload_myoRegisterTables( + InitTableEntry* init_table, + SharedTableEntry *shared_table, + FptrTableEntry *fptr_table +) +{ + // check whether we need to initialize MYO library. It is + // initialized only if at least one myo table is not empty + if (shared_table_entries(shared_table) || fptr_table_entries(fptr_table)) { + // make sure myo library is loaded + __offload_myoLoadLibrary(); + + // register tables + __offload_myo_shared_table_register(shared_table); + __offload_myo_fptr_table_register(fptr_table); + __offload_myo_shared_init_table_register(init_table); + } +} + +void __offload_myoFini(void) +{ + if (myo_is_available) { + OFFLOAD_DEBUG_TRACE(3, "%s\n", __func__); + + COIEVENT events[MIC_ENGINES_MAX]; + + // kick off myoiLibFini calls on all devices + for (int i = 0; i < mic_engines_total; i++) { + mic_engines[i].fini_myo(&events[i]); + } + + // cleanup myo runtime on host + myo_wrapper.LibFini(); + + // wait for the target fini calls to finish + COIRESULT res; + res = COI::EventWait(mic_engines_total, events, -1, 1, 0, 0); + if (res != COI_SUCCESS) { + LIBOFFLOAD_ERROR(c_event_wait, res); + exit(1); + } + } +} + +static void __offload_myo_shared_table_register( + SharedTableEntry *entry +) +{ + OFFLOAD_DEBUG_TRACE(3, "%s(%p)\n", __func__, entry); + + SharedTableEntry *start = entry; + int entries = 0; + + // allocate shared memory for vars + for (; entry->varName != MYO_TABLE_END_MARKER(); entry++) { +#ifdef TARGET_WINNT + if (entry->varName == 0) { + OFFLOAD_DEBUG_TRACE(4, "skip registering a NULL MyoSharedTable entry\n"); + continue; + } +#endif // TARGET_WINNT + + OFFLOAD_DEBUG_TRACE(4, "registering MyoSharedTable entry for %s @%p\n", + entry->varName, entry); + + // Invoke the function to create shared memory + reinterpret_cast<void(*)(void)>(entry->sharedAddr)(); + entries++; + } + + // and table to the list if it is not empty + if (entries > 0) { + mutex_locker_t locker(__myo_table_lock); + __myo_table_list.push_back(MyoTable(start, entries)); + __myo_tables = true; + } +} + +static void __offload_myo_shared_init_table_register(InitTableEntry* entry) +{ + OFFLOAD_DEBUG_TRACE(3, "%s(%p)\n", __func__, entry); + +#ifdef TARGET_WINNT + for (; entry->funcName != MYO_TABLE_END_MARKER(); entry++) { + if (entry->funcName == 0) { + OFFLOAD_DEBUG_TRACE(4, "skip registering a NULL MyoSharedInit entry\n"); + continue; + } + + // Invoke the function to init the shared memory + entry->func(); + } +#else // TARGET_WINNT + for (; entry->func != 0; entry++) { + // Invoke the function to init the shared memory + entry->func(); + } +#endif // TARGET_WINNT +} + +static void __offload_myo_fptr_table_register( + FptrTableEntry *entry +) +{ + OFFLOAD_DEBUG_TRACE(3, "%s(%p)\n", __func__, entry); + + FptrTableEntry *start = entry; + int entries = 0; + + for (; entry->funcName != MYO_TABLE_END_MARKER(); entry++) { +#ifdef TARGET_WINNT + if (entry->funcName == 0) { + OFFLOAD_DEBUG_TRACE(4, "skip registering a NULL MyoFptrTable entry\n"); + continue; + } +#endif // TARGET_WINNT + + if (!myo_wrapper.is_available()) { + *(static_cast<void**>(entry->localThunkAddr)) = entry->funcAddr; + } + + OFFLOAD_DEBUG_TRACE(4, "registering MyoFptrTable entry for %s @%p\n", + entry->funcName, entry); + +#ifdef TARGET_WINNT + if (myo_wrapper.is_available()) { + myo_wrapper.HostFptrTableRegister(entry, 1, false); + } +#endif // TARGET_WINNT + + entries++; + } + +#ifndef TARGET_WINNT + if (myo_wrapper.is_available() && entries > 0) { + myo_wrapper.HostFptrTableRegister(start, entries, false); + } +#endif // TARGET_WINNT +} + +extern "C" int __offload_myoIsAvailable(int target_number) +{ + OFFLOAD_DEBUG_TRACE(3, "%s(%d)\n", __func__, target_number); + + if (target_number >= -2) { + bool is_default_number = (target_number == -2); + + if (__offload_myoInit()) { + if (target_number >= 0) { + // User provided the device number + int num = target_number % mic_engines_total; + + // reserve device in ORSL + target_number = ORSL::reserve(num) ? num : -1; + } + else { + // try to use device 0 + target_number = ORSL::reserve(0) ? 0 : -1; + } + + // make sure device is initialized + if (target_number >= 0) { + mic_engines[target_number].init(); + } + } + else { + // fallback to CPU + target_number = -1; + } + + if (target_number < 0 && !is_default_number) { + LIBOFFLOAD_ERROR(c_device_is_not_available); + exit(1); + } + } + else { + LIBOFFLOAD_ERROR(c_invalid_device_number); + exit(1); + } + + return target_number; +} + +extern "C" void __offload_myoiRemoteIThunkCall( + void *thunk, + void *arg, + int target_number +) +{ + OFFLOAD_DEBUG_TRACE(3, "%s(%p, %p, %d)\n", __func__, thunk, arg, + target_number); + + myo_wrapper.Release(); + myo_wrapper.RemoteThunkCall(thunk, arg, target_number); + myo_wrapper.Acquire(); + + ORSL::release(target_number); +} + +extern "C" void* _Offload_shared_malloc(size_t size) +{ + OFFLOAD_DEBUG_TRACE(3, "%s(%lld)\n", __func__, size); + + if (__offload_myoLoadLibrary()) { + return myo_wrapper.SharedMalloc(size); + } + else { + return malloc(size); + } +} + +extern "C" void _Offload_shared_free(void *ptr) +{ + OFFLOAD_DEBUG_TRACE(3, "%s(%p)\n", __func__, ptr); + + if (__offload_myoLoadLibrary()) { + myo_wrapper.SharedFree(ptr); + } + else { + free(ptr); + } +} + +extern "C" void* _Offload_shared_aligned_malloc(size_t size, size_t align) +{ + OFFLOAD_DEBUG_TRACE(3, "%s(%lld, %lld)\n", __func__, size, align); + + if (__offload_myoLoadLibrary()) { + return myo_wrapper.SharedAlignedMalloc(size, align); + } + else { + if (align < sizeof(void*)) { + align = sizeof(void*); + } + return _mm_malloc(size, align); + } +} + +extern "C" void _Offload_shared_aligned_free(void *ptr) +{ + OFFLOAD_DEBUG_TRACE(3, "%s(%p)\n", __func__, ptr); + + if (__offload_myoLoadLibrary()) { + myo_wrapper.SharedAlignedFree(ptr); + } + else { + _mm_free(ptr); + } +} + +extern "C" void __intel_cilk_for_32_offload( + int size, + void (*copy_constructor)(void*, void*), + int target_number, + void *raddr, + void *closure_object, + unsigned int iters, + unsigned int grain_size) +{ + OFFLOAD_DEBUG_TRACE(3, "%s\n", __func__); + + target_number = __offload_myoIsAvailable(target_number); + if (target_number >= 0) { + struct S { + void *M1; + unsigned int M2; + unsigned int M3; + char closure[]; + } *args; + + args = (struct S*) _Offload_shared_malloc(sizeof(struct S) + size); + args->M1 = raddr; + args->M2 = iters; + args->M3 = grain_size; + + if (copy_constructor == 0) { + memcpy(args->closure, closure_object, size); + } + else { + copy_constructor(args->closure, closure_object); + } + + myo_wrapper.Release(); + myo_wrapper.GetResult( + myo_wrapper.RemoteCall("__intel_cilk_for_32_offload", + args, target_number) + ); + myo_wrapper.Acquire(); + + _Offload_shared_free(args); + + ORSL::release(target_number); + } + else { + __cilkrts_cilk_for_32(raddr, + closure_object, + iters, + grain_size); + } +} + +extern "C" void __intel_cilk_for_64_offload( + int size, + void (*copy_constructor)(void*, void*), + int target_number, + void *raddr, + void *closure_object, + uint64_t iters, + uint64_t grain_size) +{ + OFFLOAD_DEBUG_TRACE(3, "%s\n", __func__); + + target_number = __offload_myoIsAvailable(target_number); + if (target_number >= 0) { + struct S { + void *M1; + uint64_t M2; + uint64_t M3; + char closure[]; + } *args; + + args = (struct S*) _Offload_shared_malloc(sizeof(struct S) + size); + args->M1 = raddr; + args->M2 = iters; + args->M3 = grain_size; + + if (copy_constructor == 0) { + memcpy(args->closure, closure_object, size); + } + else { + copy_constructor(args->closure, closure_object); + } + + myo_wrapper.Release(); + myo_wrapper.GetResult( + myo_wrapper.RemoteCall("__intel_cilk_for_64_offload", args, + target_number) + ); + myo_wrapper.Acquire(); + + _Offload_shared_free(args); + + ORSL::release(target_number); + } + else { + __cilkrts_cilk_for_64(raddr, + closure_object, + iters, + grain_size); + } +} |