diff options
| author | Johannes Doerfert <johannes@jdoerfert.de> | 2024-04-22 09:51:33 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-22 09:51:33 -0700 |
| commit | 330d8983d25d08580fc1642fea48b2473f47a9da (patch) | |
| tree | 25994a04a5acd171f41e2ab7dd9780016f22237a /offload/DeviceRTL/include | |
| parent | b6628c24ef017138b8d6eb288e94c141e7c846b0 (diff) | |
[Offload] Move `/openmp/libomptarget` to `/offload` (#75125)
In a nutshell, this moves our libomptarget code to populate the offload
subproject.
With this commit, users need to enable the new LLVM/Offload subproject
as a runtime in their cmake configuration.
No further changes are expected for downstream code.
Tests and other components still depend on OpenMP and have also not been
renamed. The results below are for a build in which OpenMP and Offload
are enabled runtimes. In addition to the pure `git mv`, we needed to
adjust some CMake files. Nothing is intended to change semantics.
```
ninja check-offload
```
Works with the X86 and AMDGPU offload tests
```
ninja check-openmp
```
Still works but doesn't build offload tests anymore.
```
ls install/lib
```
Shows all expected libraries, incl.
- `libomptarget.devicertl.a`
- `libomptarget-nvptx-sm_90.bc`
- `libomptarget.rtl.amdgpu.so` -> `libomptarget.rtl.amdgpu.so.18git`
- `libomptarget.so` -> `libomptarget.so.18git`
Fixes: https://github.com/llvm/llvm-project/issues/75124
---------
Co-authored-by: Saiyedul Islam <Saiyedul.Islam@amd.com>
Diffstat (limited to 'offload/DeviceRTL/include')
| -rw-r--r-- | offload/DeviceRTL/include/Allocator.h | 44 | ||||
| -rw-r--r-- | offload/DeviceRTL/include/Configuration.h | 68 | ||||
| -rw-r--r-- | offload/DeviceRTL/include/Debug.h | 49 | ||||
| -rw-r--r-- | offload/DeviceRTL/include/Interface.h | 365 | ||||
| -rw-r--r-- | offload/DeviceRTL/include/LibC.h | 25 | ||||
| -rw-r--r-- | offload/DeviceRTL/include/Mapping.h | 112 | ||||
| -rw-r--r-- | offload/DeviceRTL/include/State.h | 385 | ||||
| -rw-r--r-- | offload/DeviceRTL/include/Synchronization.h | 140 | ||||
| -rw-r--r-- | offload/DeviceRTL/include/Types.h | 213 | ||||
| -rw-r--r-- | offload/DeviceRTL/include/Utils.h | 96 | ||||
| -rw-r--r-- | offload/DeviceRTL/include/generated_microtask_cases.gen | 797 |
11 files changed, 2294 insertions, 0 deletions
diff --git a/offload/DeviceRTL/include/Allocator.h b/offload/DeviceRTL/include/Allocator.h new file mode 100644 index 000000000000..a28eb0fb2977 --- /dev/null +++ b/offload/DeviceRTL/include/Allocator.h @@ -0,0 +1,44 @@ +//===-------- Allocator.h - OpenMP memory allocator interface ---- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +#ifndef OMPTARGET_ALLOCATOR_H +#define OMPTARGET_ALLOCATOR_H + +#include "Types.h" + +// Forward declaration. +struct KernelEnvironmentTy; + +#pragma omp begin declare target device_type(nohost) + +namespace ompx { + +namespace allocator { + +static uint64_t constexpr ALIGNMENT = 16; + +/// Initialize the allocator according to \p KernelEnvironment +void init(bool IsSPMD, KernelEnvironmentTy &KernelEnvironment); + +/// Allocate \p Size bytes. +[[gnu::alloc_size(1), gnu::assume_aligned(ALIGNMENT), gnu::malloc]] void * +alloc(uint64_t Size); + +/// Free the allocation pointed to by \p Ptr. +void free(void *Ptr); + +} // namespace allocator + +} // namespace ompx + +#pragma omp end declare target + +#endif diff --git a/offload/DeviceRTL/include/Configuration.h b/offload/DeviceRTL/include/Configuration.h new file mode 100644 index 000000000000..8e6f5c89cbf2 --- /dev/null +++ b/offload/DeviceRTL/include/Configuration.h @@ -0,0 +1,68 @@ +//===--- Configuration.h - OpenMP device configuration interface -- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// API to query the global (constant) device environment. +// +//===----------------------------------------------------------------------===// + +#ifndef OMPTARGET_CONFIGURATION_H +#define OMPTARGET_CONFIGURATION_H + +#include "Shared/Environment.h" + +#include "Types.h" + +namespace ompx { +namespace config { + +/// Return the number of devices in the system, same number as returned on the +/// host by omp_get_num_devices. +uint32_t getNumDevices(); + +/// Return the device number in the system for omp_get_device_num. +uint32_t getDeviceNum(); + +/// Return the user choosen debug level. +uint32_t getDebugKind(); + +/// Return if teams oversubscription is assumed +uint32_t getAssumeTeamsOversubscription(); + +/// Return if threads oversubscription is assumed +uint32_t getAssumeThreadsOversubscription(); + +/// Return the amount of dynamic shared memory that was allocated at launch. +uint64_t getDynamicMemorySize(); + +/// Returns the cycles per second of the device's fixed frequency clock. +uint64_t getClockFrequency(); + +/// Returns the pointer to the beginning of the indirect call table. +void *getIndirectCallTablePtr(); + +/// Returns the size of the indirect call table. +uint64_t getIndirectCallTableSize(); + +/// Returns the size of the indirect call table. +uint64_t getHardwareParallelism(); + +/// Return if debugging is enabled for the given debug kind. +bool isDebugMode(DeviceDebugKind Level); + +/// Indicates if this kernel may require thread-specific states, or if it was +/// explicitly disabled by the user. +bool mayUseThreadStates(); + +/// Indicates if this kernel may require data environments for nested +/// parallelism, or if it was explicitly disabled by the user. +bool mayUseNestedParallelism(); + +} // namespace config +} // namespace ompx + +#endif diff --git a/offload/DeviceRTL/include/Debug.h b/offload/DeviceRTL/include/Debug.h new file mode 100644 index 000000000000..22998f44a5be --- /dev/null +++ b/offload/DeviceRTL/include/Debug.h @@ -0,0 +1,49 @@ +//===-------- Debug.h ---- Debug utilities ------------------------ C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +#ifndef OMPTARGET_DEVICERTL_DEBUG_H +#define OMPTARGET_DEVICERTL_DEBUG_H + +#include "Configuration.h" +#include "LibC.h" + +/// Assertion +/// +/// { +extern "C" { +void __assert_assume(bool condition); +void __assert_fail(const char *expr, const char *file, unsigned line, + const char *function); +void __assert_fail_internal(const char *expr, const char *msg, const char *file, + unsigned line, const char *function); +} + +#define ASSERT(expr, msg) \ + { \ + if (config::isDebugMode(DeviceDebugKind::Assertion) && !(expr)) \ + __assert_fail_internal(#expr, msg, __FILE__, __LINE__, \ + __PRETTY_FUNCTION__); \ + else \ + __assert_assume(expr); \ + } +#define UNREACHABLE(msg) \ + PRINT(msg); \ + __builtin_trap(); \ + __builtin_unreachable(); + +///} + +#define PRINTF(fmt, ...) (void)printf(fmt, ##__VA_ARGS__); +#define PRINT(str) PRINTF("%s", str) + +///} + +#endif diff --git a/offload/DeviceRTL/include/Interface.h b/offload/DeviceRTL/include/Interface.h new file mode 100644 index 000000000000..f4854ed3d167 --- /dev/null +++ b/offload/DeviceRTL/include/Interface.h @@ -0,0 +1,365 @@ +//===-------- Interface.h - OpenMP interface ---------------------- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +#ifndef OMPTARGET_DEVICERTL_INTERFACE_H +#define OMPTARGET_DEVICERTL_INTERFACE_H + +#include "Shared/Environment.h" + +#include "Types.h" + +/// External API +/// +///{ + +extern "C" { + +/// ICV: dyn-var, constant 0 +/// +/// setter: ignored. +/// getter: returns 0. +/// +///{ +void omp_set_dynamic(int); +int omp_get_dynamic(void); +///} + +/// ICV: nthreads-var, integer +/// +/// scope: data environment +/// +/// setter: ignored. +/// getter: returns false. +/// +/// implementation notes: +/// +/// +///{ +void omp_set_num_threads(int); +int omp_get_max_threads(void); +///} + +/// ICV: thread-limit-var, computed +/// +/// getter: returns thread limited defined during launch. +/// +///{ +int omp_get_thread_limit(void); +///} + +/// ICV: max-active-level-var, constant 1 +/// +/// setter: ignored. +/// getter: returns 1. +/// +///{ +void omp_set_max_active_levels(int); +int omp_get_max_active_levels(void); +///} + +/// ICV: places-partition-var +/// +/// +///{ +///} + +/// ICV: active-level-var, 0 or 1 +/// +/// getter: returns 0 or 1. +/// +///{ +int omp_get_active_level(void); +///} + +/// ICV: level-var +/// +/// getter: returns parallel region nesting +/// +///{ +int omp_get_level(void); +///} + +/// ICV: run-sched-var +/// +/// +///{ +void omp_set_schedule(omp_sched_t, int); +void omp_get_schedule(omp_sched_t *, int *); +///} + +/// TODO this is incomplete. +int omp_get_num_threads(void); +int omp_get_thread_num(void); +void omp_set_nested(int); + +int omp_get_nested(void); + +void omp_set_max_active_levels(int Level); + +int omp_get_max_active_levels(void); + +omp_proc_bind_t omp_get_proc_bind(void); + +int omp_get_num_places(void); + +int omp_get_place_num_procs(int place_num); + +void omp_get_place_proc_ids(int place_num, int *ids); + +int omp_get_place_num(void); + +int omp_get_partition_num_places(void); + +void omp_get_partition_place_nums(int *place_nums); + +int omp_get_cancellation(void); + +void omp_set_default_device(int deviceId); + +int omp_get_default_device(void); + +int omp_get_num_devices(void); + +int omp_get_device_num(void); + +int omp_get_num_teams(void); + +int omp_get_team_num(); + +int omp_get_initial_device(void); + +void *llvm_omp_target_dynamic_shared_alloc(); + +/// Synchronization +/// +///{ +void omp_init_lock(omp_lock_t *Lock); + +void omp_destroy_lock(omp_lock_t *Lock); + +void omp_set_lock(omp_lock_t *Lock); + +void omp_unset_lock(omp_lock_t *Lock); + +int omp_test_lock(omp_lock_t *Lock); +///} + +/// Tasking +/// +///{ +int omp_in_final(void); + +int omp_get_max_task_priority(void); +///} + +/// Misc +/// +///{ +double omp_get_wtick(void); + +double omp_get_wtime(void); +///} +} + +extern "C" { +/// Allocate \p Bytes in "shareable" memory and return the address. Needs to be +/// called balanced with __kmpc_free_shared like a stack (push/pop). Can be +/// called by any thread, allocation happens *per thread*. +void *__kmpc_alloc_shared(uint64_t Bytes); + +/// Deallocate \p Ptr. Needs to be called balanced with __kmpc_alloc_shared like +/// a stack (push/pop). Can be called by any thread. \p Ptr has to be the +/// allocated by __kmpc_alloc_shared by the same thread. +void __kmpc_free_shared(void *Ptr, uint64_t Bytes); + +/// Get a pointer to the memory buffer containing dynamically allocated shared +/// memory configured at launch. +void *__kmpc_get_dynamic_shared(); + +/// Allocate sufficient space for \p NumArgs sequential `void*` and store the +/// allocation address in \p GlobalArgs. +/// +/// Called by the main thread prior to a parallel region. +/// +/// We also remember it in GlobalArgsPtr to ensure the worker threads and +/// deallocation function know the allocation address too. +void __kmpc_begin_sharing_variables(void ***GlobalArgs, uint64_t NumArgs); + +/// Deallocate the memory allocated by __kmpc_begin_sharing_variables. +/// +/// Called by the main thread after a parallel region. +void __kmpc_end_sharing_variables(); + +/// Store the allocation address obtained via __kmpc_begin_sharing_variables in +/// \p GlobalArgs. +/// +/// Called by the worker threads in the parallel region (function). +void __kmpc_get_shared_variables(void ***GlobalArgs); + +/// External interface to get the thread ID. +uint32_t __kmpc_get_hardware_thread_id_in_block(); + +/// External interface to get the number of threads. +uint32_t __kmpc_get_hardware_num_threads_in_block(); + +/// External interface to get the warp size. +uint32_t __kmpc_get_warp_size(); + +/// Kernel +/// +///{ +// Forward declaration +struct KernelEnvironmentTy; + +int8_t __kmpc_is_spmd_exec_mode(); + +int32_t __kmpc_target_init(KernelEnvironmentTy &KernelEnvironment, + KernelLaunchEnvironmentTy &KernelLaunchEnvironment); + +void __kmpc_target_deinit(); + +///} + +/// Reduction +/// +///{ +void *__kmpc_reduction_get_fixed_buffer(); + +int32_t __kmpc_nvptx_parallel_reduce_nowait_v2(IdentTy *Loc, + uint64_t reduce_data_size, + void *reduce_data, + ShuffleReductFnTy shflFct, + InterWarpCopyFnTy cpyFct); + +int32_t __kmpc_nvptx_teams_reduce_nowait_v2( + IdentTy *Loc, void *GlobalBuffer, uint32_t num_of_records, + uint64_t reduce_data_size, void *reduce_data, ShuffleReductFnTy shflFct, + InterWarpCopyFnTy cpyFct, ListGlobalFnTy lgcpyFct, ListGlobalFnTy lgredFct, + ListGlobalFnTy glcpyFct, ListGlobalFnTy glredFct); +///} + +/// Synchronization +/// +///{ +void __kmpc_ordered(IdentTy *Loc, int32_t TId); + +void __kmpc_end_ordered(IdentTy *Loc, int32_t TId); + +int32_t __kmpc_cancel_barrier(IdentTy *Loc_ref, int32_t TId); + +void __kmpc_barrier(IdentTy *Loc_ref, int32_t TId); + +void __kmpc_barrier_simple_spmd(IdentTy *Loc_ref, int32_t TId); + +void __kmpc_barrier_simple_generic(IdentTy *Loc_ref, int32_t TId); + +int32_t __kmpc_master(IdentTy *Loc, int32_t TId); + +void __kmpc_end_master(IdentTy *Loc, int32_t TId); + +int32_t __kmpc_masked(IdentTy *Loc, int32_t TId, int32_t Filter); + +void __kmpc_end_masked(IdentTy *Loc, int32_t TId); + +int32_t __kmpc_single(IdentTy *Loc, int32_t TId); + +void __kmpc_end_single(IdentTy *Loc, int32_t TId); + +void __kmpc_flush(IdentTy *Loc); + +uint64_t __kmpc_warp_active_thread_mask(void); + +void __kmpc_syncwarp(uint64_t Mask); + +void __kmpc_critical(IdentTy *Loc, int32_t TId, CriticalNameTy *Name); + +void __kmpc_end_critical(IdentTy *Loc, int32_t TId, CriticalNameTy *Name); +///} + +/// Parallelism +/// +///{ +/// TODO +void __kmpc_kernel_prepare_parallel(ParallelRegionFnTy WorkFn); + +/// TODO +bool __kmpc_kernel_parallel(ParallelRegionFnTy *WorkFn); + +/// TODO +void __kmpc_kernel_end_parallel(); + +/// TODO +void __kmpc_push_proc_bind(IdentTy *Loc, uint32_t TId, int ProcBind); + +/// TODO +void __kmpc_push_num_teams(IdentTy *Loc, int32_t TId, int32_t NumTeams, + int32_t ThreadLimit); + +/// TODO +uint16_t __kmpc_parallel_level(IdentTy *Loc, uint32_t); + +///} + +/// Tasking +/// +///{ +TaskDescriptorTy *__kmpc_omp_task_alloc(IdentTy *, int32_t, int32_t, + size_t TaskSizeInclPrivateValues, + size_t SharedValuesSize, + TaskFnTy TaskFn); + +int32_t __kmpc_omp_task(IdentTy *Loc, uint32_t TId, + TaskDescriptorTy *TaskDescriptor); + +int32_t __kmpc_omp_task_with_deps(IdentTy *Loc, uint32_t TId, + TaskDescriptorTy *TaskDescriptor, int32_t, + void *, int32_t, void *); + +void __kmpc_omp_task_begin_if0(IdentTy *Loc, uint32_t TId, + TaskDescriptorTy *TaskDescriptor); + +void __kmpc_omp_task_complete_if0(IdentTy *Loc, uint32_t TId, + TaskDescriptorTy *TaskDescriptor); + +void __kmpc_omp_wait_deps(IdentTy *Loc, uint32_t TId, int32_t, void *, int32_t, + void *); + +void __kmpc_taskgroup(IdentTy *Loc, uint32_t TId); + +void __kmpc_end_taskgroup(IdentTy *Loc, uint32_t TId); + +int32_t __kmpc_omp_taskyield(IdentTy *Loc, uint32_t TId, int); + +int32_t __kmpc_omp_taskwait(IdentTy *Loc, uint32_t TId); + +void __kmpc_taskloop(IdentTy *Loc, uint32_t TId, + TaskDescriptorTy *TaskDescriptor, int, + uint64_t *LowerBound, uint64_t *UpperBound, int64_t, int, + int32_t, uint64_t, void *); +///} + +/// Misc +/// +///{ +int32_t __kmpc_cancellationpoint(IdentTy *Loc, int32_t TId, int32_t CancelVal); + +int32_t __kmpc_cancel(IdentTy *Loc, int32_t TId, int32_t CancelVal); +///} + +/// Shuffle +/// +///{ +int32_t __kmpc_shuffle_int32(int32_t val, int16_t delta, int16_t size); +int64_t __kmpc_shuffle_int64(int64_t val, int16_t delta, int16_t size); +///} +} + +#endif diff --git a/offload/DeviceRTL/include/LibC.h b/offload/DeviceRTL/include/LibC.h new file mode 100644 index 000000000000..dde86af783af --- /dev/null +++ b/offload/DeviceRTL/include/LibC.h @@ -0,0 +1,25 @@ +//===--------- LibC.h - Simple implementation of libc functions --- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +#ifndef OMPTARGET_LIBC_H +#define OMPTARGET_LIBC_H + +#include "Types.h" + +extern "C" { + +int memcmp(const void *lhs, const void *rhs, size_t count); +void memset(void *dst, int C, size_t count); + +int printf(const char *format, ...); +} + +#endif diff --git a/offload/DeviceRTL/include/Mapping.h b/offload/DeviceRTL/include/Mapping.h new file mode 100644 index 000000000000..165904644dbb --- /dev/null +++ b/offload/DeviceRTL/include/Mapping.h @@ -0,0 +1,112 @@ +//===--------- Mapping.h - OpenMP device runtime mapping helpers -- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +#ifndef OMPTARGET_MAPPING_H +#define OMPTARGET_MAPPING_H + +#include "Types.h" + +namespace ompx { + +namespace mapping { + +enum { + DIM_X = 0, + DIM_Y = 1, + DIM_Z = 2, +}; + +#pragma omp begin declare target device_type(nohost) + +inline constexpr uint32_t MaxThreadsPerTeam = 1024; + +#pragma omp end declare target + +/// Initialize the mapping machinery. +void init(bool IsSPMD); + +/// Return true if the kernel is executed in SPMD mode. +bool isSPMDMode(); + +/// Return true if the kernel is executed in generic mode. +bool isGenericMode(); + +/// Return true if the executing thread is the main thread in generic mode. +/// These functions will lookup state and it is required that that is OK for the +/// thread and location. See also `isInitialThreadInLevel0` for a stateless +/// alternative for certain situations, e.g. during initialization. +bool isMainThreadInGenericMode(); +bool isMainThreadInGenericMode(bool IsSPMD); + +/// Return true if this thread is the initial thread in parallel level 0. +/// +/// The thread for which this returns true should be used for single threaded +/// initialization tasks. We pick a special thread to ensure there are no +/// races between the initialization and the first read of initialized state. +bool isInitialThreadInLevel0(bool IsSPMD); + +/// Return true if the executing thread has the lowest Id of the active threads +/// in the warp. +bool isLeaderInWarp(); + +/// Return a mask describing all active threads in the warp. +LaneMaskTy activemask(); + +/// Return a mask describing all threads with a smaller Id in the warp. +LaneMaskTy lanemaskLT(); + +/// Return a mask describing all threads with a larget Id in the warp. +LaneMaskTy lanemaskGT(); + +/// Return the thread Id in the warp, in [0, getWarpSize()). +uint32_t getThreadIdInWarp(); + +/// Return the warp size, thus number of threads in the warp. +uint32_t getWarpSize(); + +/// Return the warp id in the block, in [0, getNumberOfWarpsInBlock()] +uint32_t getWarpIdInBlock(); + +/// Return the number of warps in the block. +uint32_t getNumberOfWarpsInBlock(); + +/// Return the thread Id in the block, in [0, getNumberOfThreadsInBlock(Dim)). +uint32_t getThreadIdInBlock(int32_t Dim = DIM_X); + +/// Return the block size, thus number of threads in the block. +uint32_t getNumberOfThreadsInBlock(int32_t Dim = DIM_X); + +/// Return the block Id in the kernel, in [0, getNumberOfBlocksInKernel(Dim)). +uint32_t getBlockIdInKernel(int32_t Dim = DIM_X); + +/// Return the number of blocks in the kernel. +uint32_t getNumberOfBlocksInKernel(int32_t Dim = DIM_X); + +/// Return the kernel size, thus number of threads in the kernel. +uint32_t getNumberOfThreadsInKernel(); + +/// Return the maximal number of threads in the block usable for a team (= +/// parallel region). +/// +/// Note: The version taking \p IsSPMD mode explicitly can be used during the +/// initialization of the target region, that is before `mapping::isSPMDMode()` +/// can be called by any thread other than the main one. +uint32_t getMaxTeamThreads(); +uint32_t getMaxTeamThreads(bool IsSPMD); + +/// Return the number of processing elements on the device. +uint32_t getNumberOfProcessorElements(); + +} // namespace mapping + +} // namespace ompx + +#endif diff --git a/offload/DeviceRTL/include/State.h b/offload/DeviceRTL/include/State.h new file mode 100644 index 000000000000..1a3490394458 --- /dev/null +++ b/offload/DeviceRTL/include/State.h @@ -0,0 +1,385 @@ +//===-------- State.h - OpenMP State & ICV interface ------------- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +#ifndef OMPTARGET_STATE_H +#define OMPTARGET_STATE_H + +#include "Shared/Environment.h" + +#include "Debug.h" +#include "Mapping.h" +#include "Types.h" +#include "Utils.h" + +// Forward declaration. +struct KernelEnvironmentTy; + +#pragma omp begin declare target device_type(nohost) + +namespace ompx { + +namespace memory { + +/// Alloca \p Size bytes in shared memory, if possible, for \p Reason. +/// +/// Note: See the restrictions on __kmpc_alloc_shared for proper usage. +void *allocShared(uint64_t Size, const char *Reason); + +/// Free \p Ptr, alloated via allocShared, for \p Reason. +/// +/// Note: See the restrictions on __kmpc_free_shared for proper usage. +void freeShared(void *Ptr, uint64_t Bytes, const char *Reason); + +/// Alloca \p Size bytes in global memory, if possible, for \p Reason. +void *allocGlobal(uint64_t Size, const char *Reason); + +/// Return a pointer to the dynamic shared memory buffer. +void *getDynamicBuffer(); + +/// Free \p Ptr, alloated via allocGlobal, for \p Reason. +void freeGlobal(void *Ptr, const char *Reason); + +} // namespace memory + +namespace state { + +inline constexpr uint32_t SharedScratchpadSize = SHARED_SCRATCHPAD_SIZE; + +struct ICVStateTy { + uint32_t NThreadsVar; + uint32_t LevelVar; + uint32_t ActiveLevelVar; + uint32_t Padding0Val; + uint32_t MaxActiveLevelsVar; + uint32_t RunSchedVar; + uint32_t RunSchedChunkVar; + + bool operator==(const ICVStateTy &Other) const; + + void assertEqual(const ICVStateTy &Other) const; +}; + +struct TeamStateTy { + void init(bool IsSPMD); + + bool operator==(const TeamStateTy &) const; + + void assertEqual(TeamStateTy &Other) const; + + /// ICVs + /// + /// Preallocated storage for ICV values that are used if the threads have not + /// set a custom default. The latter is supported but unlikely and slow(er). + /// + ///{ + ICVStateTy ICVState; + ///} + + uint32_t ParallelTeamSize; + uint32_t HasThreadState; + ParallelRegionFnTy ParallelRegionFnVar; +}; + +extern TeamStateTy TeamState; +#pragma omp allocate(TeamState) allocator(omp_pteam_mem_alloc) + +struct ThreadStateTy { + + /// ICVs have preallocated storage in the TeamStateTy which is used if a + /// thread has not set a custom value. The latter is supported but unlikely. + /// When it happens we will allocate dynamic memory to hold the values of all + /// ICVs. Thus, the first time an ICV is set by a thread we will allocate an + /// ICV struct to hold them all. This is slower than alternatives but allows + /// users to pay only for what they use. + /// + state::ICVStateTy ICVState; + + ThreadStateTy *PreviousThreadState; + + void init() { + ICVState = TeamState.ICVState; + PreviousThreadState = nullptr; + } + + void init(ThreadStateTy *PreviousTS) { + ICVState = PreviousTS ? PreviousTS->ICVState : TeamState.ICVState; + PreviousThreadState = PreviousTS; + } +}; + +extern ThreadStateTy **ThreadStates; +#pragma omp allocate(ThreadStates) allocator(omp_pteam_mem_alloc) + +/// Initialize the state machinery. Must be called by all threads. +void init(bool IsSPMD, KernelEnvironmentTy &KernelEnvironment, + KernelLaunchEnvironmentTy &KernelLaunchEnvironment); + +/// Return the kernel and kernel launch environment associated with the current +/// kernel. The former is static and contains compile time information that +/// holds for all instances of the kernel. The latter is dynamic and provides +/// per-launch information. +KernelEnvironmentTy &getKernelEnvironment(); +KernelLaunchEnvironmentTy &getKernelLaunchEnvironment(); + +/// TODO +enum ValueKind { + VK_NThreads, + VK_Level, + VK_ActiveLevel, + VK_MaxActiveLevels, + VK_RunSched, + // --- + VK_RunSchedChunk, + VK_ParallelRegionFn, + VK_ParallelTeamSize, + VK_HasThreadState, +}; + +/// TODO +void enterDataEnvironment(IdentTy *Ident); + +/// TODO +void exitDataEnvironment(); + +/// TODO +struct DateEnvironmentRAII { + DateEnvironmentRAII(IdentTy *Ident) { enterDataEnvironment(Ident); } + ~DateEnvironmentRAII() { exitDataEnvironment(); } +}; + +/// TODO +void resetStateForThread(uint32_t TId); + +inline uint32_t &lookupForModify32Impl(uint32_t state::ICVStateTy::*Var, + IdentTy *Ident, bool ForceTeamState) { + if (OMP_LIKELY(ForceTeamState || !config::mayUseThreadStates() || + !TeamState.HasThreadState)) + return TeamState.ICVState.*Var; + uint32_t TId = mapping::getThreadIdInBlock(); + if (OMP_UNLIKELY(!ThreadStates[TId])) { + ThreadStates[TId] = reinterpret_cast<ThreadStateTy *>(memory::allocGlobal( + sizeof(ThreadStateTy), "ICV modification outside data environment")); + ASSERT(ThreadStates[TId] != nullptr, "Nullptr returned by malloc!"); + TeamState.HasThreadState = true; + ThreadStates[TId]->init(); + } + return ThreadStates[TId]->ICVState.*Var; +} + +inline uint32_t &lookupImpl(uint32_t state::ICVStateTy::*Var, + bool ForceTeamState) { + auto TId = mapping::getThreadIdInBlock(); + if (OMP_UNLIKELY(!ForceTeamState && config::mayUseThreadStates() && + TeamState.HasThreadState && ThreadStates[TId])) + return ThreadStates[TId]->ICVState.*Var; + return TeamState.ICVState.*Var; +} + +[[gnu::always_inline, gnu::flatten]] inline uint32_t & +lookup32(ValueKind Kind, bool IsReadonly, IdentTy *Ident, bool ForceTeamState) { + switch (Kind) { + case state::VK_NThreads: + if (IsReadonly) + return lookupImpl(&ICVStateTy::NThreadsVar, ForceTeamState); + return lookupForModify32Impl(&ICVStateTy::NThreadsVar, Ident, + ForceTeamState); + case state::VK_Level: + if (IsReadonly) + return lookupImpl(&ICVStateTy::LevelVar, ForceTeamState); + return lookupForModify32Impl(&ICVStateTy::LevelVar, Ident, ForceTeamState); + case state::VK_ActiveLevel: + if (IsReadonly) + return lookupImpl(&ICVStateTy::ActiveLevelVar, ForceTeamState); + return lookupForModify32Impl(&ICVStateTy::ActiveLevelVar, Ident, + ForceTeamState); + case state::VK_MaxActiveLevels: + if (IsReadonly) + return lookupImpl(&ICVStateTy::MaxActiveLevelsVar, ForceTeamState); + return lookupForModify32Impl(&ICVStateTy::MaxActiveLevelsVar, Ident, + ForceTeamState); + case state::VK_RunSched: + if (IsReadonly) + return lookupImpl(&ICVStateTy::RunSchedVar, ForceTeamState); + return lookupForModify32Impl(&ICVStateTy::RunSchedVar, Ident, + ForceTeamState); + case state::VK_RunSchedChunk: + if (IsReadonly) + return lookupImpl(&ICVStateTy::RunSchedChunkVar, ForceTeamState); + return lookupForModify32Impl(&ICVStateTy::RunSchedChunkVar, Ident, + ForceTeamState); + case state::VK_ParallelTeamSize: + return TeamState.ParallelTeamSize; + case state::VK_HasThreadState: + return TeamState.HasThreadState; + default: + break; + } + __builtin_unreachable(); +} + +[[gnu::always_inline, gnu::flatten]] inline void *& +lookupPtr(ValueKind Kind, bool IsReadonly, bool ForceTeamState) { + switch (Kind) { + case state::VK_ParallelRegionFn: + return TeamState.ParallelRegionFnVar; + default: + break; + } + __builtin_unreachable(); +} + +/// A class without actual state used to provide a nice interface to lookup and +/// update ICV values we can declare in global scope. +template <typename Ty, ValueKind Kind> struct Value { + [[gnu::flatten, gnu::always_inline]] operator Ty() { + return lookup(/*IsReadonly=*/true, /*IdentTy=*/nullptr, + /*ForceTeamState=*/false); + } + + [[gnu::flatten, gnu::always_inline]] Value &operator=(const Ty &Other) { + set(Other, /*IdentTy=*/nullptr); + return *this; + } + + [[gnu::flatten, gnu::always_inline]] Value &operator++() { + inc(1, /*IdentTy=*/nullptr); + return *this; + } + + [[gnu::flatten, gnu::always_inline]] Value &operator--() { + inc(-1, /*IdentTy=*/nullptr); + return *this; + } + + [[gnu::flatten, gnu::always_inline]] void + assert_eq(const Ty &V, IdentTy *Ident = nullptr, + bool ForceTeamState = false) { + ASSERT(lookup(/*IsReadonly=*/true, Ident, ForceTeamState) == V, nullptr); + } + +private: + [[gnu::flatten, gnu::always_inline]] Ty & + lookup(bool IsReadonly, IdentTy *Ident, bool ForceTeamState) { + Ty &t = lookup32(Kind, IsReadonly, Ident, ForceTeamState); + return t; + } + + [[gnu::flatten, gnu::always_inline]] Ty &inc(int UpdateVal, IdentTy *Ident) { + return (lookup(/*IsReadonly=*/false, Ident, /*ForceTeamState=*/false) += + UpdateVal); + } + + [[gnu::flatten, gnu::always_inline]] Ty &set(Ty UpdateVal, IdentTy *Ident) { + return (lookup(/*IsReadonly=*/false, Ident, /*ForceTeamState=*/false) = + UpdateVal); + } + + template <typename VTy, typename Ty2> friend struct ValueRAII; +}; + +/// A mookup class without actual state used to provide +/// a nice interface to lookup and update ICV values +/// we can declare in global scope. +template <typename Ty, ValueKind Kind> struct PtrValue { + [[gnu::flatten, gnu::always_inline]] operator Ty() { + return lookup(/*IsReadonly=*/true, /*IdentTy=*/nullptr, + /*ForceTeamState=*/false); + } + + [[gnu::flatten, gnu::always_inline]] PtrValue &operator=(const Ty Other) { + set(Other); + return *this; + } + +private: + Ty &lookup(bool IsReadonly, IdentTy *, bool ForceTeamState) { + return lookupPtr(Kind, IsReadonly, ForceTeamState); + } + + Ty &set(Ty UpdateVal) { + return (lookup(/*IsReadonly=*/false, /*IdentTy=*/nullptr, + /*ForceTeamState=*/false) = UpdateVal); + } + + template <typename VTy, typename Ty2> friend struct ValueRAII; +}; + +template <typename VTy, typename Ty> struct ValueRAII { + ValueRAII(VTy &V, Ty NewValue, Ty OldValue, bool Active, IdentTy *Ident, + bool ForceTeamState = false) + : Ptr(Active ? &V.lookup(/*IsReadonly=*/false, Ident, ForceTeamState) + : (Ty *)utils::UndefPtr), + Val(OldValue), Active(Active) { + if (!Active) + return; + ASSERT(*Ptr == OldValue, "ValueRAII initialization with wrong old value!"); + *Ptr = NewValue; + } + ~ValueRAII() { + if (Active) + *Ptr = Val; + } + +private: + Ty *Ptr; + Ty Val; + bool Active; +}; + +/// TODO +inline state::Value<uint32_t, state::VK_RunSchedChunk> RunSchedChunk; + +/// TODO +inline state::Value<uint32_t, state::VK_ParallelTeamSize> ParallelTeamSize; + +/// TODO +inline state::Value<uint32_t, state::VK_HasThreadState> HasThreadState; + +/// TODO +inline state::PtrValue<ParallelRegionFnTy, state::VK_ParallelRegionFn> + ParallelRegionFn; + +void runAndCheckState(void(Func(void))); + +void assumeInitialState(bool IsSPMD); + +/// Return the value of the ParallelTeamSize ICV. +int getEffectivePTeamSize(); + +} // namespace state + +namespace icv { + +/// TODO +inline state::Value<uint32_t, state::VK_NThreads> NThreads; + +/// TODO +inline state::Value<uint32_t, state::VK_Level> Level; + +/// The `active-level` describes which of the parallel level counted with the +/// `level-var` is active. There can only be one. +/// +/// active-level-var is 1, if ActiveLevelVar is not 0, otherweise it is 0. +inline state::Value<uint32_t, state::VK_ActiveLevel> ActiveLevel; + +/// TODO +inline state::Value<uint32_t, state::VK_MaxActiveLevels> MaxActiveLevels; + +/// TODO +inline state::Value<uint32_t, state::VK_RunSched> RunSched; + +} // namespace icv + +} // namespace ompx + +#pragma omp end declare target + +#endif diff --git a/offload/DeviceRTL/include/Synchronization.h b/offload/DeviceRTL/include/Synchronization.h new file mode 100644 index 000000000000..af9e1a673e6a --- /dev/null +++ b/offload/DeviceRTL/include/Synchronization.h @@ -0,0 +1,140 @@ +//===- Synchronization.h - OpenMP synchronization utilities ------- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +#ifndef OMPTARGET_DEVICERTL_SYNCHRONIZATION_H +#define OMPTARGET_DEVICERTL_SYNCHRONIZATION_H + +#include "Types.h" + +namespace ompx { + +namespace atomic { + +enum OrderingTy { + relaxed = __ATOMIC_RELAXED, + aquire = __ATOMIC_ACQUIRE, + release = __ATOMIC_RELEASE, + acq_rel = __ATOMIC_ACQ_REL, + seq_cst = __ATOMIC_SEQ_CST, +}; + +enum MemScopeTy { + all, // All threads on all devices + device, // All threads on the device + cgroup // All threads in the contention group, e.g. the team +}; + +/// Atomically increment \p *Addr and wrap at \p V with \p Ordering semantics. +uint32_t inc(uint32_t *Addr, uint32_t V, OrderingTy Ordering, + MemScopeTy MemScope = MemScopeTy::all); + +/// Atomically perform <op> on \p V and \p *Addr with \p Ordering semantics. The +/// result is stored in \p *Addr; +/// { + +#define ATOMIC_COMMON_OP(TY) \ + TY add(TY *Addr, TY V, OrderingTy Ordering); \ + TY mul(TY *Addr, TY V, OrderingTy Ordering); \ + TY load(TY *Addr, OrderingTy Ordering); \ + void store(TY *Addr, TY V, OrderingTy Ordering); \ + bool cas(TY *Addr, TY ExpectedV, TY DesiredV, OrderingTy OrderingSucc, \ + OrderingTy OrderingFail); + +#define ATOMIC_FP_ONLY_OP(TY) \ + TY min(TY *Addr, TY V, OrderingTy Ordering); \ + TY max(TY *Addr, TY V, OrderingTy Ordering); + +#define ATOMIC_INT_ONLY_OP(TY) \ + TY min(TY *Addr, TY V, OrderingTy Ordering); \ + TY max(TY *Addr, TY V, OrderingTy Ordering); \ + TY bit_or(TY *Addr, TY V, OrderingTy Ordering); \ + TY bit_and(TY *Addr, TY V, OrderingTy Ordering); \ + TY bit_xor(TY *Addr, TY V, OrderingTy Ordering); + +#define ATOMIC_FP_OP(TY) \ + ATOMIC_FP_ONLY_OP(TY) \ + ATOMIC_COMMON_OP(TY) + +#define ATOMIC_INT_OP(TY) \ + ATOMIC_INT_ONLY_OP(TY) \ + ATOMIC_COMMON_OP(TY) + +// This needs to be kept in sync with the header. Also the reason we don't use +// templates here. +ATOMIC_INT_OP(int8_t) +ATOMIC_INT_OP(int16_t) +ATOMIC_INT_OP(int32_t) +ATOMIC_INT_OP(int64_t) +ATOMIC_INT_OP(uint8_t) +ATOMIC_INT_OP(uint16_t) +ATOMIC_INT_OP(uint32_t) +ATOMIC_INT_OP(uint64_t) +ATOMIC_FP_OP(float) +ATOMIC_FP_OP(double) + +#undef ATOMIC_INT_ONLY_OP +#undef ATOMIC_FP_ONLY_OP +#undef ATOMIC_COMMON_OP +#undef ATOMIC_INT_OP +#undef ATOMIC_FP_OP + +///} + +} // namespace atomic + +namespace synchronize { + +/// Initialize the synchronization machinery. Must be called by all threads. +void init(bool IsSPMD); + +/// Synchronize all threads in a warp identified by \p Mask. +void warp(LaneMaskTy Mask); + +/// Synchronize all threads in a block and perform a fence before and after the +/// barrier according to \p Ordering. Note that the fence might be part of the +/// barrier. +void threads(atomic::OrderingTy Ordering); + +/// Synchronizing threads is allowed even if they all hit different instances of +/// `synchronize::threads()`. However, `synchronize::threadsAligned()` is more +/// restrictive in that it requires all threads to hit the same instance. The +/// noinline is removed by the openmp-opt pass and helps to preserve the +/// information till then. +///{ +#pragma omp begin assumes ext_aligned_barrier + +/// Synchronize all threads in a block, they are reaching the same instruction +/// (hence all threads in the block are "aligned"). Also perform a fence before +/// and after the barrier according to \p Ordering. Note that the +/// fence might be part of the barrier if the target offers this. +[[gnu::noinline]] void threadsAligned(atomic::OrderingTy Ordering); + +#pragma omp end assumes +///} + +} // namespace synchronize + +namespace fence { + +/// Memory fence with \p Ordering semantics for the team. +void team(atomic::OrderingTy Ordering); + +/// Memory fence with \p Ordering semantics for the contention group. +void kernel(atomic::OrderingTy Ordering); + +/// Memory fence with \p Ordering semantics for the system. +void system(atomic::OrderingTy Ordering); + +} // namespace fence + +} // namespace ompx + +#endif diff --git a/offload/DeviceRTL/include/Types.h b/offload/DeviceRTL/include/Types.h new file mode 100644 index 000000000000..2e12d9da0353 --- /dev/null +++ b/offload/DeviceRTL/include/Types.h @@ -0,0 +1,213 @@ +//===---------- Types.h - OpenMP types ---------------------------- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +#ifndef OMPTARGET_TYPES_H +#define OMPTARGET_TYPES_H + +// Tell the compiler that we do not have any "call-like" inline assembly in the +// device rutime. That means we cannot have inline assembly which will call +// another function but only inline assembly that performs some operation or +// side-effect and then continues execution with something on the existing call +// stack. +// +// TODO: Find a good place for this +#pragma omp assumes ext_no_call_asm + +/// Base type declarations for freestanding mode +/// +///{ +using int8_t = char; +using uint8_t = unsigned char; +using int16_t = short; +using uint16_t = unsigned short; +using int32_t = int; +using uint32_t = unsigned int; +using int64_t = long; +using uint64_t = unsigned long; +using size_t = decltype(sizeof(char)); +// TODO: Properly implement this +using intptr_t = int64_t; +using uintptr_t = uint64_t; + +static_assert(sizeof(int8_t) == 1, "type size mismatch"); +static_assert(sizeof(uint8_t) == 1, "type size mismatch"); +static_assert(sizeof(int16_t) == 2, "type size mismatch"); +static_assert(sizeof(uint16_t) == 2, "type size mismatch"); +static_assert(sizeof(int32_t) == 4, "type size mismatch"); +static_assert(sizeof(uint32_t) == 4, "type size mismatch"); +static_assert(sizeof(int64_t) == 8, "type size mismatch"); +static_assert(sizeof(uint64_t) == 8, "type size mismatch"); +///} + +enum omp_proc_bind_t { + omp_proc_bind_false = 0, + omp_proc_bind_true = 1, + omp_proc_bind_master = 2, + omp_proc_bind_close = 3, + omp_proc_bind_spread = 4 +}; + +enum omp_sched_t { + omp_sched_static = 1, /* chunkSize >0 */ + omp_sched_dynamic = 2, /* chunkSize >0 */ + omp_sched_guided = 3, /* chunkSize >0 */ + omp_sched_auto = 4, /* no chunkSize */ +}; + +enum kmp_sched_t { + kmp_sched_static_chunk = 33, + kmp_sched_static_nochunk = 34, + kmp_sched_dynamic = 35, + kmp_sched_guided = 36, + kmp_sched_runtime = 37, + kmp_sched_auto = 38, + + kmp_sched_static_balanced_chunk = 45, + + kmp_sched_static_ordered = 65, + kmp_sched_static_nochunk_ordered = 66, + kmp_sched_dynamic_ordered = 67, + kmp_sched_guided_ordered = 68, + kmp_sched_runtime_ordered = 69, + kmp_sched_auto_ordered = 70, + + kmp_sched_distr_static_chunk = 91, + kmp_sched_distr_static_nochunk = 92, + kmp_sched_distr_static_chunk_sched_static_chunkone = 93, + + kmp_sched_default = kmp_sched_static_nochunk, + kmp_sched_unordered_first = kmp_sched_static_chunk, + kmp_sched_unordered_last = kmp_sched_auto, + kmp_sched_ordered_first = kmp_sched_static_ordered, + kmp_sched_ordered_last = kmp_sched_auto_ordered, + kmp_sched_distribute_first = kmp_sched_distr_static_chunk, + kmp_sched_distribute_last = + kmp_sched_distr_static_chunk_sched_static_chunkone, + + /* Support for OpenMP 4.5 monotonic and nonmonotonic schedule modifiers. + * Since we need to distinguish the three possible cases (no modifier, + * monotonic modifier, nonmonotonic modifier), we need separate bits for + * each modifier. The absence of monotonic does not imply nonmonotonic, + * especially since 4.5 says that the behaviour of the "no modifier" case + * is implementation defined in 4.5, but will become "nonmonotonic" in 5.0. + * + * Since we're passing a full 32 bit value, we can use a couple of high + * bits for these flags; out of paranoia we avoid the sign bit. + * + * These modifiers can be or-ed into non-static schedules by the compiler + * to pass the additional information. They will be stripped early in the + * processing in __kmp_dispatch_init when setting up schedules, so + * most of the code won't ever see schedules with these bits set. + */ + kmp_sched_modifier_monotonic = (1 << 29), + /**< Set if the monotonic schedule modifier was present */ + kmp_sched_modifier_nonmonotonic = (1 << 30), +/**< Set if the nonmonotonic schedule modifier was present */ + +#define SCHEDULE_WITHOUT_MODIFIERS(s) \ + (enum kmp_sched_t)( \ + (s) & ~(kmp_sched_modifier_nonmonotonic | kmp_sched_modifier_monotonic)) +#define SCHEDULE_HAS_MONOTONIC(s) (((s)&kmp_sched_modifier_monotonic) != 0) +#define SCHEDULE_HAS_NONMONOTONIC(s) \ + (((s)&kmp_sched_modifier_nonmonotonic) != 0) +#define SCHEDULE_HAS_NO_MODIFIERS(s) \ + (((s) & (kmp_sched_modifier_nonmonotonic | kmp_sched_modifier_monotonic)) == \ + 0) + +}; + +struct TaskDescriptorTy; +using TaskFnTy = int32_t (*)(int32_t global_tid, TaskDescriptorTy *taskDescr); +struct TaskDescriptorTy { + void *Payload; + TaskFnTy TaskFn; +}; + +#pragma omp begin declare variant match(device = {arch(amdgcn)}) +using LaneMaskTy = uint64_t; +#pragma omp end declare variant + +#pragma omp begin declare variant match( \ + device = {arch(amdgcn)}, implementation = {extension(match_none)}) +using LaneMaskTy = uint64_t; +#pragma omp end declare variant + +namespace lanes { +enum : LaneMaskTy { All = ~(LaneMaskTy)0 }; +} // namespace lanes + +/// The ident structure that describes a source location. The struct is +/// identical to the one in the kmp.h file. We maintain the same data structure +/// for compatibility. +struct IdentTy { + int32_t reserved_1; /**< might be used in Fortran; see above */ + int32_t flags; /**< also f.flags; KMP_IDENT_xxx flags; KMP_IDENT_KMPC + identifies this union member */ + int32_t reserved_2; /**< not really used in Fortran any more; see above */ + int32_t reserved_3; /**< source[4] in Fortran, do not use for C++ */ + char const *psource; /**< String describing the source location. + The string is composed of semi-colon separated fields + which describe the source file, the function and a pair + of line numbers that delimit the construct. */ +}; + +using __kmpc_impl_lanemask_t = LaneMaskTy; + +using ParallelRegionFnTy = void *; + +using CriticalNameTy = int32_t[8]; + +struct omp_lock_t { + void *Lock; +}; + +using InterWarpCopyFnTy = void (*)(void *src, int32_t warp_num); +using ShuffleReductFnTy = void (*)(void *rhsData, int16_t lane_id, + int16_t lane_offset, int16_t shortCircuit); +using ListGlobalFnTy = void (*)(void *buffer, int idx, void *reduce_data); + +/// Macros for allocating variables in different address spaces. +///{ + +// Follows the pattern in interface.h +typedef enum omp_allocator_handle_t { + omp_null_allocator = 0, + omp_default_mem_alloc = 1, + omp_large_cap_mem_alloc = 2, + omp_const_mem_alloc = 3, + omp_high_bw_mem_alloc = 4, + omp_low_lat_mem_alloc = 5, + omp_cgroup_mem_alloc = 6, + omp_pteam_mem_alloc = 7, + omp_thread_mem_alloc = 8, + KMP_ALLOCATOR_MAX_HANDLE = ~(0U) +} omp_allocator_handle_t; + +#define __PRAGMA(STR) _Pragma(#STR) +#define OMP_PRAGMA(STR) __PRAGMA(omp STR) + +#define SHARED(NAME) \ + NAME [[clang::loader_uninitialized]]; \ + OMP_PRAGMA(allocate(NAME) allocator(omp_pteam_mem_alloc)) + +// TODO: clang should use address space 5 for omp_thread_mem_alloc, but right +// now that's not the case. +#define THREAD_LOCAL(NAME) \ + [[clang::address_space(5)]] NAME [[clang::loader_uninitialized]] + +// TODO: clang should use address space 4 for omp_const_mem_alloc, maybe it +// does? +#define CONSTANT(NAME) \ + [[clang::address_space(4)]] NAME [[clang::loader_uninitialized]] + +///} + +#endif diff --git a/offload/DeviceRTL/include/Utils.h b/offload/DeviceRTL/include/Utils.h new file mode 100644 index 000000000000..4ab0aea46eea --- /dev/null +++ b/offload/DeviceRTL/include/Utils.h @@ -0,0 +1,96 @@ +//===--------- Utils.h - OpenMP device runtime utility functions -- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +#ifndef OMPTARGET_DEVICERTL_UTILS_H +#define OMPTARGET_DEVICERTL_UTILS_H + +#include "Types.h" + +#pragma omp begin declare target device_type(nohost) + +namespace ompx { +namespace utils { + +/// Return the value \p Var from thread Id \p SrcLane in the warp if the thread +/// is identified by \p Mask. +int32_t shuffle(uint64_t Mask, int32_t Var, int32_t SrcLane); + +int32_t shuffleDown(uint64_t Mask, int32_t Var, uint32_t Delta, int32_t Width); + +/// Return \p LowBits and \p HighBits packed into a single 64 bit value. +uint64_t pack(uint32_t LowBits, uint32_t HighBits); + +/// Unpack \p Val into \p LowBits and \p HighBits. +void unpack(uint64_t Val, uint32_t &LowBits, uint32_t &HighBits); + +/// Round up \p V to a \p Boundary. +template <typename Ty> inline Ty roundUp(Ty V, Ty Boundary) { + return (V + Boundary - 1) / Boundary * Boundary; +} + +/// Advance \p Ptr by \p Bytes bytes. +template <typename Ty1, typename Ty2> inline Ty1 *advance(Ty1 Ptr, Ty2 Bytes) { + return reinterpret_cast<Ty1 *>(reinterpret_cast<char *>(Ptr) + Bytes); +} + +/// Return the first bit set in \p V. +inline uint32_t ffs(uint32_t V) { + static_assert(sizeof(int) == sizeof(uint32_t), "type size mismatch"); + return __builtin_ffs(V); +} + +/// Return the first bit set in \p V. +inline uint32_t ffs(uint64_t V) { + static_assert(sizeof(long) == sizeof(uint64_t), "type size mismatch"); + return __builtin_ffsl(V); +} + +/// Return the number of bits set in \p V. +inline uint32_t popc(uint32_t V) { + static_assert(sizeof(int) == sizeof(uint32_t), "type size mismatch"); + return __builtin_popcount(V); +} + +/// Return the number of bits set in \p V. +inline uint32_t popc(uint64_t V) { + static_assert(sizeof(long) == sizeof(uint64_t), "type size mismatch"); + return __builtin_popcountl(V); +} + +/// Return \p V aligned "upwards" according to \p Align. +template <typename Ty1, typename Ty2> inline Ty1 align_up(Ty1 V, Ty2 Align) { + return ((V + Ty1(Align) - 1) / Ty1(Align)) * Ty1(Align); +} +/// Return \p V aligned "downwards" according to \p Align. +template <typename Ty1, typename Ty2> inline Ty1 align_down(Ty1 V, Ty2 Align) { + return V - V % Align; +} + +/// Return true iff \p Ptr is pointing into shared (local) memory (AS(3)). +bool isSharedMemPtr(void *Ptr); + +/// Return \p V typed punned as \p DstTy. +template <typename DstTy, typename SrcTy> inline DstTy convertViaPun(SrcTy V) { + return *((DstTy *)(&V)); +} + +/// A pointer variable that has by design an `undef` value. Use with care. +[[clang::loader_uninitialized]] static void *const UndefPtr; + +#define OMP_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true) +#define OMP_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false) + +} // namespace utils +} // namespace ompx + +#pragma omp end declare target + +#endif diff --git a/offload/DeviceRTL/include/generated_microtask_cases.gen b/offload/DeviceRTL/include/generated_microtask_cases.gen new file mode 100644 index 000000000000..a05f6da2f84f --- /dev/null +++ b/offload/DeviceRTL/include/generated_microtask_cases.gen @@ -0,0 +1,797 @@ +case 0: +((void (*)(int32_t *, int32_t *))fn)(&global_tid, &bound_tid); +break; +case 1: +((void (*)(int32_t *, int32_t *, void *))fn)(&global_tid, &bound_tid, args[0]); +break; +case 2: +((void (*)(int32_t *, int32_t *, void *, void *))fn)(&global_tid, &bound_tid, + args[0], args[1]); +break; +case 3: +((void (*)(int32_t *, int32_t *, void *, void *, + void *))fn)(&global_tid, &bound_tid, args[0], args[1], args[2]); +break; +case 4: +((void (*)(int32_t *, int32_t *, void *, void *, void *, + void *))fn)(&global_tid, &bound_tid, args[0], args[1], args[2], + args[3]); +break; +case 5: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, + void *))fn)(&global_tid, &bound_tid, args[0], args[1], args[2], + args[3], args[4]); +break; +case 6: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, + void *))fn)(&global_tid, &bound_tid, args[0], args[1], args[2], + args[3], args[4], args[5]); +break; +case 7: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *))fn)(&global_tid, &bound_tid, args[0], args[1], args[2], + args[3], args[4], args[5], args[6]); +break; +case 8: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *))fn)(&global_tid, &bound_tid, args[0], args[1], + args[2], args[3], args[4], args[5], args[6], + args[7]); +break; +case 9: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *))fn)(&global_tid, &bound_tid, args[0], + args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8]); +break; +case 10: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *))fn)(&global_tid, &bound_tid, args[0], + args[1], args[2], args[3], + args[4], args[5], args[6], + args[7], args[8], args[9]); +break; +case 11: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, + void *))fn)(&global_tid, &bound_tid, args[0], args[1], args[2], + args[3], args[4], args[5], args[6], args[7], args[8], + args[9], args[10]); +break; +case 12: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, + void *))fn)(&global_tid, &bound_tid, args[0], args[1], args[2], + args[3], args[4], args[5], args[6], args[7], args[8], + args[9], args[10], args[11]); +break; +case 13: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, + void *))fn)(&global_tid, &bound_tid, args[0], args[1], args[2], + args[3], args[4], args[5], args[6], args[7], args[8], + args[9], args[10], args[11], args[12]); +break; +case 14: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, + void *))fn)(&global_tid, &bound_tid, args[0], args[1], args[2], + args[3], args[4], args[5], args[6], args[7], args[8], + args[9], args[10], args[11], args[12], args[13]); +break; +case 15: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *))fn)(&global_tid, &bound_tid, args[0], args[1], args[2], + args[3], args[4], args[5], args[6], args[7], args[8], + args[9], args[10], args[11], args[12], args[13], + args[14]); +break; +case 16: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *))fn)(&global_tid, &bound_tid, args[0], args[1], + args[2], args[3], args[4], args[5], args[6], + args[7], args[8], args[9], args[10], args[11], + args[12], args[13], args[14], args[15]); +break; +case 17: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *))fn)(&global_tid, &bound_tid, args[0], + args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], + args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16]); +break; +case 18: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, + void *))fn)(&global_tid, &bound_tid, args[0], args[1], args[2], + args[3], args[4], args[5], args[6], args[7], args[8], + args[9], args[10], args[11], args[12], args[13], + args[14], args[15], args[16], args[17]); +break; +case 19: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, + void *))fn)(&global_tid, &bound_tid, args[0], args[1], args[2], + args[3], args[4], args[5], args[6], args[7], args[8], + args[9], args[10], args[11], args[12], args[13], + args[14], args[15], args[16], args[17], args[18]); +break; +case 20: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19]); +break; +case 21: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, + void *))fn)(&global_tid, &bound_tid, args[0], args[1], args[2], + args[3], args[4], args[5], args[6], args[7], args[8], + args[9], args[10], args[11], args[12], args[13], + args[14], args[15], args[16], args[17], args[18], + args[19], args[20]); +break; +case 22: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, + void *))fn)(&global_tid, &bound_tid, args[0], args[1], args[2], + args[3], args[4], args[5], args[6], args[7], args[8], + args[9], args[10], args[11], args[12], args[13], + args[14], args[15], args[16], args[17], args[18], + args[19], args[20], args[21]); +break; +case 23: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *))fn)(&global_tid, &bound_tid, args[0], args[1], args[2], + args[3], args[4], args[5], args[6], args[7], args[8], + args[9], args[10], args[11], args[12], args[13], + args[14], args[15], args[16], args[17], args[18], + args[19], args[20], args[21], args[22]); +break; +case 24: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *))fn)(&global_tid, &bound_tid, args[0], args[1], + args[2], args[3], args[4], args[5], args[6], + args[7], args[8], args[9], args[10], args[11], + args[12], args[13], args[14], args[15], args[16], + args[17], args[18], args[19], args[20], args[21], + args[22], args[23]); +break; +case 25: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *))fn)(&global_tid, &bound_tid, args[0], + args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], + args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], + args[17], args[18], args[19], args[20], + args[21], args[22], args[23], args[24]); +break; +case 26: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25]); +break; +case 27: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26]); +break; +case 28: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, + void *))fn)(&global_tid, &bound_tid, args[0], args[1], args[2], + args[3], args[4], args[5], args[6], args[7], args[8], + args[9], args[10], args[11], args[12], args[13], + args[14], args[15], args[16], args[17], args[18], + args[19], args[20], args[21], args[22], args[23], + args[24], args[25], args[26], args[27]); +break; +case 29: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, + void *))fn)(&global_tid, &bound_tid, args[0], args[1], args[2], + args[3], args[4], args[5], args[6], args[7], args[8], + args[9], args[10], args[11], args[12], args[13], + args[14], args[15], args[16], args[17], args[18], + args[19], args[20], args[21], args[22], args[23], + args[24], args[25], args[26], args[27], args[28]); +break; +case 30: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29]); +break; +case 31: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *))fn)(&global_tid, &bound_tid, args[0], args[1], args[2], + args[3], args[4], args[5], args[6], args[7], args[8], + args[9], args[10], args[11], args[12], args[13], + args[14], args[15], args[16], args[17], args[18], + args[19], args[20], args[21], args[22], args[23], + args[24], args[25], args[26], args[27], args[28], + args[29], args[30]); +break; +case 32: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *))fn)(&global_tid, &bound_tid, args[0], args[1], + args[2], args[3], args[4], args[5], args[6], + args[7], args[8], args[9], args[10], args[11], + args[12], args[13], args[14], args[15], args[16], + args[17], args[18], args[19], args[20], args[21], + args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], + args[31]); +break; +case 33: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32]); +break; +case 34: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33]); +break; +case 35: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34]); +break; +case 36: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35]); +break; +case 37: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36]); +break; +case 38: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37]); +break; +case 39: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *))fn)(&global_tid, &bound_tid, args[0], args[1], args[2], + args[3], args[4], args[5], args[6], args[7], args[8], + args[9], args[10], args[11], args[12], args[13], + args[14], args[15], args[16], args[17], args[18], + args[19], args[20], args[21], args[22], args[23], + args[24], args[25], args[26], args[27], args[28], + args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38]); +break; +case 40: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *))fn)(&global_tid, &bound_tid, args[0], args[1], + args[2], args[3], args[4], args[5], args[6], + args[7], args[8], args[9], args[10], args[11], + args[12], args[13], args[14], args[15], args[16], + args[17], args[18], args[19], args[20], args[21], + args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], + args[32], args[33], args[34], args[35], args[36], + args[37], args[38], args[39]); +break; +case 41: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], args[39], args[40]); +break; +case 42: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], args[39], args[40], + args[41]); +break; +case 43: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], args[39], args[40], + args[41], args[42]); +break; +case 44: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], args[39], args[40], + args[41], args[42], args[43]); +break; +case 45: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], args[39], args[40], + args[41], args[42], args[43], args[44]); +break; +case 46: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], args[39], args[40], + args[41], args[42], args[43], args[44], args[45]); +break; +/// DONE TO HERE +case 47: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *))fn)(&global_tid, &bound_tid, args[0], args[1], args[2], + args[3], args[4], args[5], args[6], args[7], args[8], + args[9], args[10], args[11], args[12], args[13], + args[14], args[15], args[16], args[17], args[18], + args[19], args[20], args[21], args[22], args[23], + args[24], args[25], args[26], args[27], args[28], + args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], + args[39], args[40], args[41], args[42], args[43], + args[44], args[45], args[46]); +break; +case 48: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], args[39], args[40], + args[41], args[42], args[43], args[44], args[45], args[46], args[47]); +break; +case 49: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], args[39], args[40], + args[41], args[42], args[43], args[44], args[45], args[46], args[47], + args[48]); +break; +case 50: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], args[39], args[40], + args[41], args[42], args[43], args[44], args[45], args[46], args[47], + args[48], args[49]); +break; +case 51: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], args[39], args[40], + args[41], args[42], args[43], args[44], args[45], args[46], args[47], + args[48], args[49], args[50]); +break; +case 52: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], args[39], args[40], + args[41], args[42], args[43], args[44], args[45], args[46], args[47], + args[48], args[49], args[50], args[51]); +break; +case 53: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], args[39], args[40], + args[41], args[42], args[43], args[44], args[45], args[46], args[47], + args[48], args[49], args[50], args[51], args[52]); +break; +case 54: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], args[39], args[40], + args[41], args[42], args[43], args[44], args[45], args[46], args[47], + args[48], args[49], args[50], args[51], args[52], args[53]); +break; +case 55: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], args[39], args[40], + args[41], args[42], args[43], args[44], args[45], args[46], args[47], + args[48], args[49], args[50], args[51], args[52], args[53], args[54]); +break; +case 56: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *))fn)(&global_tid, &bound_tid, args[0], args[1], + args[2], args[3], args[4], args[5], args[6], + args[7], args[8], args[9], args[10], args[11], + args[12], args[13], args[14], args[15], args[16], + args[17], args[18], args[19], args[20], args[21], + args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], + args[32], args[33], args[34], args[35], args[36], + args[37], args[38], args[39], args[40], args[41], + args[42], args[43], args[44], args[45], args[46], + args[47], args[48], args[49], args[50], args[51], + args[52], args[53], args[54], args[55]); +break; +case 57: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], args[39], args[40], + args[41], args[42], args[43], args[44], args[45], args[46], args[47], + args[48], args[49], args[50], args[51], args[52], args[53], args[54], + args[55], args[56]); +break; +case 58: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], args[39], args[40], + args[41], args[42], args[43], args[44], args[45], args[46], args[47], + args[48], args[49], args[50], args[51], args[52], args[53], args[54], + args[55], args[56], args[57]); +break; +case 59: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], args[39], args[40], + args[41], args[42], args[43], args[44], args[45], args[46], args[47], + args[48], args[49], args[50], args[51], args[52], args[53], args[54], + args[55], args[56], args[57], args[58]); +break; +case 60: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], args[39], args[40], + args[41], args[42], args[43], args[44], args[45], args[46], args[47], + args[48], args[49], args[50], args[51], args[52], args[53], args[54], + args[55], args[56], args[57], args[58], args[59]); +break; +case 61: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], args[39], args[40], + args[41], args[42], args[43], args[44], args[45], args[46], args[47], + args[48], args[49], args[50], args[51], args[52], args[53], args[54], + args[55], args[56], args[57], args[58], args[59], args[60]); +break; +case 62: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], args[39], args[40], + args[41], args[42], args[43], args[44], args[45], args[46], args[47], + args[48], args[49], args[50], args[51], args[52], args[53], args[54], + args[55], args[56], args[57], args[58], args[59], args[60], args[61]); +break; +case 63: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *))fn)(&global_tid, &bound_tid, args[0], args[1], args[2], + args[3], args[4], args[5], args[6], args[7], args[8], + args[9], args[10], args[11], args[12], args[13], + args[14], args[15], args[16], args[17], args[18], + args[19], args[20], args[21], args[22], args[23], + args[24], args[25], args[26], args[27], args[28], + args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], + args[39], args[40], args[41], args[42], args[43], + args[44], args[45], args[46], args[47], args[48], + args[49], args[50], args[51], args[52], args[53], + args[54], args[55], args[56], args[57], args[58], + args[59], args[60], args[61], args[62]); +break; +case 64: +((void (*)(int32_t *, int32_t *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *, void *, void *, void *, void *, void *, void *, + void *, void *))fn)( + &global_tid, &bound_tid, args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], + args[13], args[14], args[15], args[16], args[17], args[18], args[19], + args[20], args[21], args[22], args[23], args[24], args[25], args[26], + args[27], args[28], args[29], args[30], args[31], args[32], args[33], + args[34], args[35], args[36], args[37], args[38], args[39], args[40], + args[41], args[42], args[43], args[44], args[45], args[46], args[47], + args[48], args[49], args[50], args[51], args[52], args[53], args[54], + args[55], args[56], args[57], args[58], args[59], args[60], args[61], + args[62], args[63]); +break; |
