13de4cd12SGeorge Rokos //===----RTLs/cuda/src/rtl.cpp - Target RTLs Implementation ------- C++ -*-===//
23de4cd12SGeorge Rokos //
33de4cd12SGeorge Rokos //                     The LLVM Compiler Infrastructure
43de4cd12SGeorge Rokos //
53de4cd12SGeorge Rokos // This file is dual licensed under the MIT and the University of Illinois Open
63de4cd12SGeorge Rokos // Source Licenses. See LICENSE.txt for details.
73de4cd12SGeorge Rokos //
83de4cd12SGeorge Rokos //===----------------------------------------------------------------------===//
93de4cd12SGeorge Rokos //
103de4cd12SGeorge Rokos // RTL for CUDA machine
113de4cd12SGeorge Rokos //
123de4cd12SGeorge Rokos //===----------------------------------------------------------------------===//
133de4cd12SGeorge Rokos 
143de4cd12SGeorge Rokos #include <cassert>
153de4cd12SGeorge Rokos #include <cstddef>
163de4cd12SGeorge Rokos #include <cuda.h>
173de4cd12SGeorge Rokos #include <cuda_runtime_api.h>
183de4cd12SGeorge Rokos #include <list>
193de4cd12SGeorge Rokos #include <string>
203de4cd12SGeorge Rokos #include <vector>
213de4cd12SGeorge Rokos 
221546d319SGeorge Rokos #include "omptargetplugin.h"
233de4cd12SGeorge Rokos 
243de4cd12SGeorge Rokos #ifndef TARGET_NAME
253de4cd12SGeorge Rokos #define TARGET_NAME CUDA
263de4cd12SGeorge Rokos #endif
273de4cd12SGeorge Rokos 
28*b305d26bSSergey Dmitriev #ifdef OMPTARGET_DEBUG
29*b305d26bSSergey Dmitriev static int DebugLevel = 0;
30*b305d26bSSergey Dmitriev 
313de4cd12SGeorge Rokos #define GETNAME2(name) #name
323de4cd12SGeorge Rokos #define GETNAME(name) GETNAME2(name)
33*b305d26bSSergey Dmitriev #define DP(...) \
34*b305d26bSSergey Dmitriev   do { \
35*b305d26bSSergey Dmitriev     if (DebugLevel > 0) { \
36*b305d26bSSergey Dmitriev       DEBUGP("Target " GETNAME(TARGET_NAME) " RTL", __VA_ARGS__); \
37*b305d26bSSergey Dmitriev     } \
38*b305d26bSSergey Dmitriev   } while (false)
39*b305d26bSSergey Dmitriev #else // OMPTARGET_DEBUG
40*b305d26bSSergey Dmitriev #define DP(...) {}
41*b305d26bSSergey Dmitriev #endif // OMPTARGET_DEBUG
423de4cd12SGeorge Rokos 
433de4cd12SGeorge Rokos #include "../../common/elf_common.c"
443de4cd12SGeorge Rokos 
453de4cd12SGeorge Rokos // Utility for retrieving and printing CUDA error string.
463de4cd12SGeorge Rokos #ifdef CUDA_ERROR_REPORT
473de4cd12SGeorge Rokos #define CUDA_ERR_STRING(err)                                                   \
483de4cd12SGeorge Rokos   do {                                                                         \
493de4cd12SGeorge Rokos     const char *errStr;                                                        \
503de4cd12SGeorge Rokos     cuGetErrorString(err, &errStr);                                            \
513de4cd12SGeorge Rokos     DP("CUDA error is: %s\n", errStr);                                         \
523de4cd12SGeorge Rokos   } while (0)
533de4cd12SGeorge Rokos #else
543de4cd12SGeorge Rokos #define CUDA_ERR_STRING(err)                                                   \
553de4cd12SGeorge Rokos   {}
563de4cd12SGeorge Rokos #endif
573de4cd12SGeorge Rokos 
583de4cd12SGeorge Rokos /// Keep entries table per device.
593de4cd12SGeorge Rokos struct FuncOrGblEntryTy {
603de4cd12SGeorge Rokos   __tgt_target_table Table;
613de4cd12SGeorge Rokos   std::vector<__tgt_offload_entry> Entries;
623de4cd12SGeorge Rokos };
633de4cd12SGeorge Rokos 
643de4cd12SGeorge Rokos enum ExecutionModeType {
65c13df8e5SGeorge Rokos   SPMD, // constructors, destructors,
66c13df8e5SGeorge Rokos         // combined constructs (`teams distribute parallel for [simd]`)
67c13df8e5SGeorge Rokos   GENERIC, // everything else
683de4cd12SGeorge Rokos   NONE
693de4cd12SGeorge Rokos };
703de4cd12SGeorge Rokos 
713de4cd12SGeorge Rokos /// Use a single entity to encode a kernel and a set of flags
723de4cd12SGeorge Rokos struct KernelTy {
733de4cd12SGeorge Rokos   CUfunction Func;
743de4cd12SGeorge Rokos 
753de4cd12SGeorge Rokos   // execution mode of kernel
763de4cd12SGeorge Rokos   // 0 - SPMD mode (without master warp)
773de4cd12SGeorge Rokos   // 1 - Generic mode (with master warp)
783de4cd12SGeorge Rokos   int8_t ExecutionMode;
793de4cd12SGeorge Rokos 
803de4cd12SGeorge Rokos   KernelTy(CUfunction _Func, int8_t _ExecutionMode)
813de4cd12SGeorge Rokos       : Func(_Func), ExecutionMode(_ExecutionMode) {}
823de4cd12SGeorge Rokos };
833de4cd12SGeorge Rokos 
843de4cd12SGeorge Rokos /// List that contains all the kernels.
853de4cd12SGeorge Rokos /// FIXME: we may need this to be per device and per library.
863de4cd12SGeorge Rokos std::list<KernelTy> KernelsList;
873de4cd12SGeorge Rokos 
883de4cd12SGeorge Rokos /// Class containing all the device information.
893de4cd12SGeorge Rokos class RTLDeviceInfoTy {
903de4cd12SGeorge Rokos   std::vector<FuncOrGblEntryTy> FuncGblEntries;
913de4cd12SGeorge Rokos 
923de4cd12SGeorge Rokos public:
933de4cd12SGeorge Rokos   int NumberOfDevices;
943de4cd12SGeorge Rokos   std::vector<CUmodule> Modules;
953de4cd12SGeorge Rokos   std::vector<CUcontext> Contexts;
963de4cd12SGeorge Rokos 
973de4cd12SGeorge Rokos   // Device properties
983de4cd12SGeorge Rokos   std::vector<int> ThreadsPerBlock;
993de4cd12SGeorge Rokos   std::vector<int> BlocksPerGrid;
1003de4cd12SGeorge Rokos   std::vector<int> WarpSize;
1013de4cd12SGeorge Rokos 
1023de4cd12SGeorge Rokos   // OpenMP properties
1033de4cd12SGeorge Rokos   std::vector<int> NumTeams;
1043de4cd12SGeorge Rokos   std::vector<int> NumThreads;
1053de4cd12SGeorge Rokos 
1063de4cd12SGeorge Rokos   // OpenMP Environment properties
1073de4cd12SGeorge Rokos   int EnvNumTeams;
1083de4cd12SGeorge Rokos   int EnvTeamLimit;
1093de4cd12SGeorge Rokos 
1103de4cd12SGeorge Rokos   //static int EnvNumThreads;
1113de4cd12SGeorge Rokos   static const int HardTeamLimit = 1<<16; // 64k
1123de4cd12SGeorge Rokos   static const int HardThreadLimit = 1024;
1133de4cd12SGeorge Rokos   static const int DefaultNumTeams = 128;
114c13df8e5SGeorge Rokos   static const int DefaultNumThreads = 128;
1153de4cd12SGeorge Rokos 
1163de4cd12SGeorge Rokos   // Record entry point associated with device
1173de4cd12SGeorge Rokos   void addOffloadEntry(int32_t device_id, __tgt_offload_entry entry) {
1183de4cd12SGeorge Rokos     assert(device_id < (int32_t)FuncGblEntries.size() &&
1193de4cd12SGeorge Rokos            "Unexpected device id!");
1203de4cd12SGeorge Rokos     FuncOrGblEntryTy &E = FuncGblEntries[device_id];
1213de4cd12SGeorge Rokos 
1223de4cd12SGeorge Rokos     E.Entries.push_back(entry);
1233de4cd12SGeorge Rokos   }
1243de4cd12SGeorge Rokos 
1253de4cd12SGeorge Rokos   // Return true if the entry is associated with device
1263de4cd12SGeorge Rokos   bool findOffloadEntry(int32_t device_id, void *addr) {
1273de4cd12SGeorge Rokos     assert(device_id < (int32_t)FuncGblEntries.size() &&
1283de4cd12SGeorge Rokos            "Unexpected device id!");
1293de4cd12SGeorge Rokos     FuncOrGblEntryTy &E = FuncGblEntries[device_id];
1303de4cd12SGeorge Rokos 
1313de4cd12SGeorge Rokos     for (auto &it : E.Entries) {
1323de4cd12SGeorge Rokos       if (it.addr == addr)
1333de4cd12SGeorge Rokos         return true;
1343de4cd12SGeorge Rokos     }
1353de4cd12SGeorge Rokos 
1363de4cd12SGeorge Rokos     return false;
1373de4cd12SGeorge Rokos   }
1383de4cd12SGeorge Rokos 
1393de4cd12SGeorge Rokos   // Return the pointer to the target entries table
1403de4cd12SGeorge Rokos   __tgt_target_table *getOffloadEntriesTable(int32_t device_id) {
1413de4cd12SGeorge Rokos     assert(device_id < (int32_t)FuncGblEntries.size() &&
1423de4cd12SGeorge Rokos            "Unexpected device id!");
1433de4cd12SGeorge Rokos     FuncOrGblEntryTy &E = FuncGblEntries[device_id];
1443de4cd12SGeorge Rokos 
1453de4cd12SGeorge Rokos     int32_t size = E.Entries.size();
1463de4cd12SGeorge Rokos 
1473de4cd12SGeorge Rokos     // Table is empty
1483de4cd12SGeorge Rokos     if (!size)
1493de4cd12SGeorge Rokos       return 0;
1503de4cd12SGeorge Rokos 
1513de4cd12SGeorge Rokos     __tgt_offload_entry *begin = &E.Entries[0];
1523de4cd12SGeorge Rokos     __tgt_offload_entry *end = &E.Entries[size - 1];
1533de4cd12SGeorge Rokos 
1543de4cd12SGeorge Rokos     // Update table info according to the entries and return the pointer
1553de4cd12SGeorge Rokos     E.Table.EntriesBegin = begin;
1563de4cd12SGeorge Rokos     E.Table.EntriesEnd = ++end;
1573de4cd12SGeorge Rokos 
1583de4cd12SGeorge Rokos     return &E.Table;
1593de4cd12SGeorge Rokos   }
1603de4cd12SGeorge Rokos 
1613de4cd12SGeorge Rokos   // Clear entries table for a device
1623de4cd12SGeorge Rokos   void clearOffloadEntriesTable(int32_t device_id) {
1633de4cd12SGeorge Rokos     assert(device_id < (int32_t)FuncGblEntries.size() &&
1643de4cd12SGeorge Rokos            "Unexpected device id!");
1653de4cd12SGeorge Rokos     FuncOrGblEntryTy &E = FuncGblEntries[device_id];
1663de4cd12SGeorge Rokos     E.Entries.clear();
1673de4cd12SGeorge Rokos     E.Table.EntriesBegin = E.Table.EntriesEnd = 0;
1683de4cd12SGeorge Rokos   }
1693de4cd12SGeorge Rokos 
1703de4cd12SGeorge Rokos   RTLDeviceInfoTy() {
171*b305d26bSSergey Dmitriev #ifdef OMPTARGET_DEBUG
172*b305d26bSSergey Dmitriev     if (char *envStr = getenv("LIBOMPTARGET_DEBUG")) {
173*b305d26bSSergey Dmitriev       DebugLevel = std::stoi(envStr);
174*b305d26bSSergey Dmitriev     }
175*b305d26bSSergey Dmitriev #endif // OMPTARGET_DEBUG
176*b305d26bSSergey Dmitriev 
1773de4cd12SGeorge Rokos     DP("Start initializing CUDA\n");
1783de4cd12SGeorge Rokos 
1793de4cd12SGeorge Rokos     CUresult err = cuInit(0);
1803de4cd12SGeorge Rokos     if (err != CUDA_SUCCESS) {
1813de4cd12SGeorge Rokos       DP("Error when initializing CUDA\n");
1823de4cd12SGeorge Rokos       CUDA_ERR_STRING(err);
1833de4cd12SGeorge Rokos       return;
1843de4cd12SGeorge Rokos     }
1853de4cd12SGeorge Rokos 
1863de4cd12SGeorge Rokos     NumberOfDevices = 0;
1873de4cd12SGeorge Rokos 
1883de4cd12SGeorge Rokos     err = cuDeviceGetCount(&NumberOfDevices);
1893de4cd12SGeorge Rokos     if (err != CUDA_SUCCESS) {
1903de4cd12SGeorge Rokos       DP("Error when getting CUDA device count\n");
1913de4cd12SGeorge Rokos       CUDA_ERR_STRING(err);
1923de4cd12SGeorge Rokos       return;
1933de4cd12SGeorge Rokos     }
1943de4cd12SGeorge Rokos 
1953de4cd12SGeorge Rokos     if (NumberOfDevices == 0) {
1963de4cd12SGeorge Rokos       DP("There are no devices supporting CUDA.\n");
1973de4cd12SGeorge Rokos       return;
1983de4cd12SGeorge Rokos     }
1993de4cd12SGeorge Rokos 
2003de4cd12SGeorge Rokos     FuncGblEntries.resize(NumberOfDevices);
2013de4cd12SGeorge Rokos     Contexts.resize(NumberOfDevices);
2023de4cd12SGeorge Rokos     ThreadsPerBlock.resize(NumberOfDevices);
2033de4cd12SGeorge Rokos     BlocksPerGrid.resize(NumberOfDevices);
2043de4cd12SGeorge Rokos     WarpSize.resize(NumberOfDevices);
2053de4cd12SGeorge Rokos     NumTeams.resize(NumberOfDevices);
2063de4cd12SGeorge Rokos     NumThreads.resize(NumberOfDevices);
2073de4cd12SGeorge Rokos 
2083de4cd12SGeorge Rokos     // Get environment variables regarding teams
2093de4cd12SGeorge Rokos     char *envStr = getenv("OMP_TEAM_LIMIT");
2103de4cd12SGeorge Rokos     if (envStr) {
2113de4cd12SGeorge Rokos       // OMP_TEAM_LIMIT has been set
2123de4cd12SGeorge Rokos       EnvTeamLimit = std::stoi(envStr);
2133de4cd12SGeorge Rokos       DP("Parsed OMP_TEAM_LIMIT=%d\n", EnvTeamLimit);
2143de4cd12SGeorge Rokos     } else {
2153de4cd12SGeorge Rokos       EnvTeamLimit = -1;
2163de4cd12SGeorge Rokos     }
2173de4cd12SGeorge Rokos     envStr = getenv("OMP_NUM_TEAMS");
2183de4cd12SGeorge Rokos     if (envStr) {
2193de4cd12SGeorge Rokos       // OMP_NUM_TEAMS has been set
2203de4cd12SGeorge Rokos       EnvNumTeams = std::stoi(envStr);
2213de4cd12SGeorge Rokos       DP("Parsed OMP_NUM_TEAMS=%d\n", EnvNumTeams);
2223de4cd12SGeorge Rokos     } else {
2233de4cd12SGeorge Rokos       EnvNumTeams = -1;
2243de4cd12SGeorge Rokos     }
2253de4cd12SGeorge Rokos   }
2263de4cd12SGeorge Rokos 
2273de4cd12SGeorge Rokos   ~RTLDeviceInfoTy() {
2283de4cd12SGeorge Rokos     // Close modules
2293de4cd12SGeorge Rokos     for (auto &module : Modules)
2303de4cd12SGeorge Rokos       if (module) {
2313de4cd12SGeorge Rokos         CUresult err = cuModuleUnload(module);
2323de4cd12SGeorge Rokos         if (err != CUDA_SUCCESS) {
2333de4cd12SGeorge Rokos           DP("Error when unloading CUDA module\n");
2343de4cd12SGeorge Rokos           CUDA_ERR_STRING(err);
2353de4cd12SGeorge Rokos         }
2363de4cd12SGeorge Rokos       }
2373de4cd12SGeorge Rokos 
2383de4cd12SGeorge Rokos     // Destroy contexts
2393de4cd12SGeorge Rokos     for (auto &ctx : Contexts)
2403de4cd12SGeorge Rokos       if (ctx) {
2413de4cd12SGeorge Rokos         CUresult err = cuCtxDestroy(ctx);
2423de4cd12SGeorge Rokos         if (err != CUDA_SUCCESS) {
2433de4cd12SGeorge Rokos           DP("Error when destroying CUDA context\n");
2443de4cd12SGeorge Rokos           CUDA_ERR_STRING(err);
2453de4cd12SGeorge Rokos         }
2463de4cd12SGeorge Rokos       }
2473de4cd12SGeorge Rokos   }
2483de4cd12SGeorge Rokos };
2493de4cd12SGeorge Rokos 
2503de4cd12SGeorge Rokos static RTLDeviceInfoTy DeviceInfo;
2513de4cd12SGeorge Rokos 
2523de4cd12SGeorge Rokos #ifdef __cplusplus
2533de4cd12SGeorge Rokos extern "C" {
2543de4cd12SGeorge Rokos #endif
2553de4cd12SGeorge Rokos 
2563de4cd12SGeorge Rokos int32_t __tgt_rtl_is_valid_binary(__tgt_device_image *image) {
2573de4cd12SGeorge Rokos   return elf_check_machine(image, 190); // EM_CUDA = 190.
2583de4cd12SGeorge Rokos }
2593de4cd12SGeorge Rokos 
2603de4cd12SGeorge Rokos int32_t __tgt_rtl_number_of_devices() { return DeviceInfo.NumberOfDevices; }
2613de4cd12SGeorge Rokos 
2623de4cd12SGeorge Rokos int32_t __tgt_rtl_init_device(int32_t device_id) {
2633de4cd12SGeorge Rokos 
2643de4cd12SGeorge Rokos   CUdevice cuDevice;
2653de4cd12SGeorge Rokos   DP("Getting device %d\n", device_id);
2663de4cd12SGeorge Rokos   CUresult err = cuDeviceGet(&cuDevice, device_id);
2673de4cd12SGeorge Rokos   if (err != CUDA_SUCCESS) {
2683de4cd12SGeorge Rokos     DP("Error when getting CUDA device with id = %d\n", device_id);
2693de4cd12SGeorge Rokos     CUDA_ERR_STRING(err);
2703de4cd12SGeorge Rokos     return OFFLOAD_FAIL;
2713de4cd12SGeorge Rokos   }
2723de4cd12SGeorge Rokos 
2733de4cd12SGeorge Rokos   // Create the context and save it to use whenever this device is selected.
2743de4cd12SGeorge Rokos   err = cuCtxCreate(&DeviceInfo.Contexts[device_id], CU_CTX_SCHED_BLOCKING_SYNC,
2753de4cd12SGeorge Rokos                     cuDevice);
2763de4cd12SGeorge Rokos   if (err != CUDA_SUCCESS) {
2773de4cd12SGeorge Rokos     DP("Error when creating a CUDA context\n");
2783de4cd12SGeorge Rokos     CUDA_ERR_STRING(err);
2793de4cd12SGeorge Rokos     return OFFLOAD_FAIL;
2803de4cd12SGeorge Rokos   }
2813de4cd12SGeorge Rokos 
2823de4cd12SGeorge Rokos   // scan properties to determine number of threads/block and blocks/grid.
2833de4cd12SGeorge Rokos   struct cudaDeviceProp Properties;
2843de4cd12SGeorge Rokos   cudaError_t error = cudaGetDeviceProperties(&Properties, device_id);
2853de4cd12SGeorge Rokos   if (error != cudaSuccess) {
2863de4cd12SGeorge Rokos     DP("Error getting device Properties, use defaults\n");
2873de4cd12SGeorge Rokos     DeviceInfo.BlocksPerGrid[device_id] = RTLDeviceInfoTy::DefaultNumTeams;
2883de4cd12SGeorge Rokos     DeviceInfo.ThreadsPerBlock[device_id] = RTLDeviceInfoTy::DefaultNumThreads;
2893de4cd12SGeorge Rokos     DeviceInfo.WarpSize[device_id] = 32;
2903de4cd12SGeorge Rokos   } else {
2913de4cd12SGeorge Rokos     // Get blocks per grid
2923de4cd12SGeorge Rokos     if (Properties.maxGridSize[0] <= RTLDeviceInfoTy::HardTeamLimit) {
2933de4cd12SGeorge Rokos       DeviceInfo.BlocksPerGrid[device_id] = Properties.maxGridSize[0];
2943de4cd12SGeorge Rokos       DP("Using %d CUDA blocks per grid\n", Properties.maxGridSize[0]);
2953de4cd12SGeorge Rokos     } else {
2963de4cd12SGeorge Rokos       DeviceInfo.BlocksPerGrid[device_id] = RTLDeviceInfoTy::HardTeamLimit;
2973de4cd12SGeorge Rokos       DP("Max CUDA blocks per grid %d exceeds the hard team limit %d, capping "
2983de4cd12SGeorge Rokos           "at the hard limit\n", Properties.maxGridSize[0],
2993de4cd12SGeorge Rokos           RTLDeviceInfoTy::HardTeamLimit);
3003de4cd12SGeorge Rokos     }
3013de4cd12SGeorge Rokos 
3023de4cd12SGeorge Rokos     // Get threads per block, exploit threads only along x axis
3033de4cd12SGeorge Rokos     if (Properties.maxThreadsDim[0] <= RTLDeviceInfoTy::HardThreadLimit) {
3043de4cd12SGeorge Rokos       DeviceInfo.ThreadsPerBlock[device_id] = Properties.maxThreadsDim[0];
3053de4cd12SGeorge Rokos       DP("Using %d CUDA threads per block\n", Properties.maxThreadsDim[0]);
3063de4cd12SGeorge Rokos       if (Properties.maxThreadsDim[0] < Properties.maxThreadsPerBlock) {
3073de4cd12SGeorge Rokos         DP("(fewer than max per block along all xyz dims %d)\n",
3083de4cd12SGeorge Rokos             Properties.maxThreadsPerBlock);
3093de4cd12SGeorge Rokos       }
3103de4cd12SGeorge Rokos     } else {
3113de4cd12SGeorge Rokos       DeviceInfo.ThreadsPerBlock[device_id] = RTLDeviceInfoTy::HardThreadLimit;
3123de4cd12SGeorge Rokos       DP("Max CUDA threads per block %d exceeds the hard thread limit %d, "
3133de4cd12SGeorge Rokos           "capping at the hard limit\n", Properties.maxThreadsDim[0],
3143de4cd12SGeorge Rokos           RTLDeviceInfoTy::HardThreadLimit);
3153de4cd12SGeorge Rokos     }
3163de4cd12SGeorge Rokos 
3173de4cd12SGeorge Rokos     // Get warp size
3183de4cd12SGeorge Rokos     DeviceInfo.WarpSize[device_id] = Properties.warpSize;
3193de4cd12SGeorge Rokos   }
3203de4cd12SGeorge Rokos 
3213de4cd12SGeorge Rokos   // Adjust teams to the env variables
3223de4cd12SGeorge Rokos   if (DeviceInfo.EnvTeamLimit > 0 &&
3233de4cd12SGeorge Rokos       DeviceInfo.BlocksPerGrid[device_id] > DeviceInfo.EnvTeamLimit) {
3243de4cd12SGeorge Rokos     DeviceInfo.BlocksPerGrid[device_id] = DeviceInfo.EnvTeamLimit;
3253de4cd12SGeorge Rokos     DP("Capping max CUDA blocks per grid to OMP_TEAM_LIMIT=%d\n",
3263de4cd12SGeorge Rokos         DeviceInfo.EnvTeamLimit);
3273de4cd12SGeorge Rokos   }
3283de4cd12SGeorge Rokos 
3293de4cd12SGeorge Rokos   DP("Max number of CUDA blocks %d, threads %d & warp size %d\n",
3303de4cd12SGeorge Rokos      DeviceInfo.BlocksPerGrid[device_id], DeviceInfo.ThreadsPerBlock[device_id],
3313de4cd12SGeorge Rokos      DeviceInfo.WarpSize[device_id]);
3323de4cd12SGeorge Rokos 
3333de4cd12SGeorge Rokos   // Set default number of teams
3343de4cd12SGeorge Rokos   if (DeviceInfo.EnvNumTeams > 0) {
3353de4cd12SGeorge Rokos     DeviceInfo.NumTeams[device_id] = DeviceInfo.EnvNumTeams;
3363de4cd12SGeorge Rokos     DP("Default number of teams set according to environment %d\n",
3373de4cd12SGeorge Rokos         DeviceInfo.EnvNumTeams);
3383de4cd12SGeorge Rokos   } else {
3393de4cd12SGeorge Rokos     DeviceInfo.NumTeams[device_id] = RTLDeviceInfoTy::DefaultNumTeams;
3403de4cd12SGeorge Rokos     DP("Default number of teams set according to library's default %d\n",
3413de4cd12SGeorge Rokos         RTLDeviceInfoTy::DefaultNumTeams);
3423de4cd12SGeorge Rokos   }
3433de4cd12SGeorge Rokos   if (DeviceInfo.NumTeams[device_id] > DeviceInfo.BlocksPerGrid[device_id]) {
3443de4cd12SGeorge Rokos     DeviceInfo.NumTeams[device_id] = DeviceInfo.BlocksPerGrid[device_id];
3453de4cd12SGeorge Rokos     DP("Default number of teams exceeds device limit, capping at %d\n",
3463de4cd12SGeorge Rokos         DeviceInfo.BlocksPerGrid[device_id]);
3473de4cd12SGeorge Rokos   }
3483de4cd12SGeorge Rokos 
3493de4cd12SGeorge Rokos   // Set default number of threads
3503de4cd12SGeorge Rokos   DeviceInfo.NumThreads[device_id] = RTLDeviceInfoTy::DefaultNumThreads;
3513de4cd12SGeorge Rokos   DP("Default number of threads set according to library's default %d\n",
3523de4cd12SGeorge Rokos           RTLDeviceInfoTy::DefaultNumThreads);
3533de4cd12SGeorge Rokos   if (DeviceInfo.NumThreads[device_id] >
3543de4cd12SGeorge Rokos       DeviceInfo.ThreadsPerBlock[device_id]) {
3553de4cd12SGeorge Rokos     DeviceInfo.NumTeams[device_id] = DeviceInfo.ThreadsPerBlock[device_id];
3563de4cd12SGeorge Rokos     DP("Default number of threads exceeds device limit, capping at %d\n",
3573de4cd12SGeorge Rokos         DeviceInfo.ThreadsPerBlock[device_id]);
3583de4cd12SGeorge Rokos   }
3593de4cd12SGeorge Rokos 
3603de4cd12SGeorge Rokos   return OFFLOAD_SUCCESS;
3613de4cd12SGeorge Rokos }
3623de4cd12SGeorge Rokos 
3633de4cd12SGeorge Rokos __tgt_target_table *__tgt_rtl_load_binary(int32_t device_id,
3643de4cd12SGeorge Rokos     __tgt_device_image *image) {
3653de4cd12SGeorge Rokos 
3663de4cd12SGeorge Rokos   // Set the context we are using.
3673de4cd12SGeorge Rokos   CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]);
3683de4cd12SGeorge Rokos   if (err != CUDA_SUCCESS) {
3693de4cd12SGeorge Rokos     DP("Error when setting a CUDA context for device %d\n", device_id);
3703de4cd12SGeorge Rokos     CUDA_ERR_STRING(err);
3713de4cd12SGeorge Rokos     return NULL;
3723de4cd12SGeorge Rokos   }
3733de4cd12SGeorge Rokos 
3743de4cd12SGeorge Rokos   // Clear the offload table as we are going to create a new one.
3753de4cd12SGeorge Rokos   DeviceInfo.clearOffloadEntriesTable(device_id);
3763de4cd12SGeorge Rokos 
3773de4cd12SGeorge Rokos   // Create the module and extract the function pointers.
3783de4cd12SGeorge Rokos 
3793de4cd12SGeorge Rokos   CUmodule cumod;
3803de4cd12SGeorge Rokos   DP("Load data from image " DPxMOD "\n", DPxPTR(image->ImageStart));
3813de4cd12SGeorge Rokos   err = cuModuleLoadDataEx(&cumod, image->ImageStart, 0, NULL, NULL);
3823de4cd12SGeorge Rokos   if (err != CUDA_SUCCESS) {
3833de4cd12SGeorge Rokos     DP("Error when loading CUDA module\n");
3843de4cd12SGeorge Rokos     CUDA_ERR_STRING(err);
3853de4cd12SGeorge Rokos     return NULL;
3863de4cd12SGeorge Rokos   }
3873de4cd12SGeorge Rokos 
3883de4cd12SGeorge Rokos   DP("CUDA module successfully loaded!\n");
3893de4cd12SGeorge Rokos   DeviceInfo.Modules.push_back(cumod);
3903de4cd12SGeorge Rokos 
3913de4cd12SGeorge Rokos   // Find the symbols in the module by name.
3923de4cd12SGeorge Rokos   __tgt_offload_entry *HostBegin = image->EntriesBegin;
3933de4cd12SGeorge Rokos   __tgt_offload_entry *HostEnd = image->EntriesEnd;
3943de4cd12SGeorge Rokos 
3953de4cd12SGeorge Rokos   for (__tgt_offload_entry *e = HostBegin; e != HostEnd; ++e) {
3963de4cd12SGeorge Rokos 
3973de4cd12SGeorge Rokos     if (!e->addr) {
3983de4cd12SGeorge Rokos       // We return NULL when something like this happens, the host should have
3993de4cd12SGeorge Rokos       // always something in the address to uniquely identify the target region.
4003de4cd12SGeorge Rokos       DP("Invalid binary: host entry '<null>' (size = %zd)...\n", e->size);
4013de4cd12SGeorge Rokos 
4023de4cd12SGeorge Rokos       return NULL;
4033de4cd12SGeorge Rokos     }
4043de4cd12SGeorge Rokos 
4053de4cd12SGeorge Rokos     if (e->size) {
4063de4cd12SGeorge Rokos       __tgt_offload_entry entry = *e;
4073de4cd12SGeorge Rokos 
4083de4cd12SGeorge Rokos       CUdeviceptr cuptr;
4093de4cd12SGeorge Rokos       size_t cusize;
4103de4cd12SGeorge Rokos       err = cuModuleGetGlobal(&cuptr, &cusize, cumod, e->name);
4113de4cd12SGeorge Rokos 
4123de4cd12SGeorge Rokos       if (err != CUDA_SUCCESS) {
4133de4cd12SGeorge Rokos         DP("Loading global '%s' (Failed)\n", e->name);
4143de4cd12SGeorge Rokos         CUDA_ERR_STRING(err);
4153de4cd12SGeorge Rokos         return NULL;
4163de4cd12SGeorge Rokos       }
4173de4cd12SGeorge Rokos 
4183de4cd12SGeorge Rokos       if (cusize != e->size) {
4193de4cd12SGeorge Rokos         DP("Loading global '%s' - size mismatch (%zd != %zd)\n", e->name,
4203de4cd12SGeorge Rokos             cusize, e->size);
4213de4cd12SGeorge Rokos         CUDA_ERR_STRING(err);
4223de4cd12SGeorge Rokos         return NULL;
4233de4cd12SGeorge Rokos       }
4243de4cd12SGeorge Rokos 
4253de4cd12SGeorge Rokos       DP("Entry point " DPxMOD " maps to global %s (" DPxMOD ")\n",
4263de4cd12SGeorge Rokos           DPxPTR(e - HostBegin), e->name, DPxPTR(cuptr));
4273de4cd12SGeorge Rokos       entry.addr = (void *)cuptr;
4283de4cd12SGeorge Rokos 
4293de4cd12SGeorge Rokos       DeviceInfo.addOffloadEntry(device_id, entry);
4303de4cd12SGeorge Rokos 
4313de4cd12SGeorge Rokos       continue;
4323de4cd12SGeorge Rokos     }
4333de4cd12SGeorge Rokos 
4343de4cd12SGeorge Rokos     CUfunction fun;
4353de4cd12SGeorge Rokos     err = cuModuleGetFunction(&fun, cumod, e->name);
4363de4cd12SGeorge Rokos 
4373de4cd12SGeorge Rokos     if (err != CUDA_SUCCESS) {
4383de4cd12SGeorge Rokos       DP("Loading '%s' (Failed)\n", e->name);
4393de4cd12SGeorge Rokos       CUDA_ERR_STRING(err);
4403de4cd12SGeorge Rokos       return NULL;
4413de4cd12SGeorge Rokos     }
4423de4cd12SGeorge Rokos 
4433de4cd12SGeorge Rokos     DP("Entry point " DPxMOD " maps to %s (" DPxMOD ")\n",
4443de4cd12SGeorge Rokos         DPxPTR(e - HostBegin), e->name, DPxPTR(fun));
4453de4cd12SGeorge Rokos 
4463de4cd12SGeorge Rokos     // default value GENERIC (in case symbol is missing from cubin file)
4473de4cd12SGeorge Rokos     int8_t ExecModeVal = ExecutionModeType::GENERIC;
4483de4cd12SGeorge Rokos     std::string ExecModeNameStr (e->name);
4493de4cd12SGeorge Rokos     ExecModeNameStr += "_exec_mode";
4503de4cd12SGeorge Rokos     const char *ExecModeName = ExecModeNameStr.c_str();
4513de4cd12SGeorge Rokos 
4523de4cd12SGeorge Rokos     CUdeviceptr ExecModePtr;
4533de4cd12SGeorge Rokos     size_t cusize;
4543de4cd12SGeorge Rokos     err = cuModuleGetGlobal(&ExecModePtr, &cusize, cumod, ExecModeName);
4553de4cd12SGeorge Rokos     if (err == CUDA_SUCCESS) {
4563de4cd12SGeorge Rokos       if ((size_t)cusize != sizeof(int8_t)) {
4573de4cd12SGeorge Rokos         DP("Loading global exec_mode '%s' - size mismatch (%zd != %zd)\n",
4583de4cd12SGeorge Rokos            ExecModeName, cusize, sizeof(int8_t));
4593de4cd12SGeorge Rokos         CUDA_ERR_STRING(err);
4603de4cd12SGeorge Rokos         return NULL;
4613de4cd12SGeorge Rokos       }
4623de4cd12SGeorge Rokos 
4633de4cd12SGeorge Rokos       err = cuMemcpyDtoH(&ExecModeVal, ExecModePtr, cusize);
4643de4cd12SGeorge Rokos       if (err != CUDA_SUCCESS) {
4653de4cd12SGeorge Rokos         DP("Error when copying data from device to host. Pointers: "
4663de4cd12SGeorge Rokos            "host = " DPxMOD ", device = " DPxMOD ", size = %zd\n",
4673de4cd12SGeorge Rokos            DPxPTR(&ExecModeVal), DPxPTR(ExecModePtr), cusize);
4683de4cd12SGeorge Rokos         CUDA_ERR_STRING(err);
4693de4cd12SGeorge Rokos         return NULL;
4703de4cd12SGeorge Rokos       }
4713de4cd12SGeorge Rokos 
4723de4cd12SGeorge Rokos       if (ExecModeVal < 0 || ExecModeVal > 1) {
4733de4cd12SGeorge Rokos         DP("Error wrong exec_mode value specified in cubin file: %d\n",
4743de4cd12SGeorge Rokos            ExecModeVal);
4753de4cd12SGeorge Rokos         return NULL;
4763de4cd12SGeorge Rokos       }
4773de4cd12SGeorge Rokos     } else {
4783de4cd12SGeorge Rokos       DP("Loading global exec_mode '%s' - symbol missing, using default value "
4793de4cd12SGeorge Rokos           "GENERIC (1)\n", ExecModeName);
4803de4cd12SGeorge Rokos       CUDA_ERR_STRING(err);
4813de4cd12SGeorge Rokos     }
4823de4cd12SGeorge Rokos 
4833de4cd12SGeorge Rokos     KernelsList.push_back(KernelTy(fun, ExecModeVal));
4843de4cd12SGeorge Rokos 
4853de4cd12SGeorge Rokos     __tgt_offload_entry entry = *e;
4863de4cd12SGeorge Rokos     entry.addr = (void *)&KernelsList.back();
4873de4cd12SGeorge Rokos     DeviceInfo.addOffloadEntry(device_id, entry);
4883de4cd12SGeorge Rokos   }
4893de4cd12SGeorge Rokos 
4903de4cd12SGeorge Rokos   return DeviceInfo.getOffloadEntriesTable(device_id);
4913de4cd12SGeorge Rokos }
4923de4cd12SGeorge Rokos 
4931546d319SGeorge Rokos void *__tgt_rtl_data_alloc(int32_t device_id, int64_t size, void *hst_ptr) {
4943de4cd12SGeorge Rokos   if (size == 0) {
4953de4cd12SGeorge Rokos     return NULL;
4963de4cd12SGeorge Rokos   }
4973de4cd12SGeorge Rokos 
4983de4cd12SGeorge Rokos   // Set the context we are using.
4993de4cd12SGeorge Rokos   CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]);
5003de4cd12SGeorge Rokos   if (err != CUDA_SUCCESS) {
5013de4cd12SGeorge Rokos     DP("Error while trying to set CUDA current context\n");
5023de4cd12SGeorge Rokos     CUDA_ERR_STRING(err);
5033de4cd12SGeorge Rokos     return NULL;
5043de4cd12SGeorge Rokos   }
5053de4cd12SGeorge Rokos 
5063de4cd12SGeorge Rokos   CUdeviceptr ptr;
5073de4cd12SGeorge Rokos   err = cuMemAlloc(&ptr, size);
5083de4cd12SGeorge Rokos   if (err != CUDA_SUCCESS) {
5093de4cd12SGeorge Rokos     DP("Error while trying to allocate %d\n", err);
5103de4cd12SGeorge Rokos     CUDA_ERR_STRING(err);
5113de4cd12SGeorge Rokos     return NULL;
5123de4cd12SGeorge Rokos   }
5133de4cd12SGeorge Rokos 
5143de4cd12SGeorge Rokos   void *vptr = (void *)ptr;
5153de4cd12SGeorge Rokos   return vptr;
5163de4cd12SGeorge Rokos }
5173de4cd12SGeorge Rokos 
5183de4cd12SGeorge Rokos int32_t __tgt_rtl_data_submit(int32_t device_id, void *tgt_ptr, void *hst_ptr,
5193de4cd12SGeorge Rokos     int64_t size) {
5203de4cd12SGeorge Rokos   // Set the context we are using.
5213de4cd12SGeorge Rokos   CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]);
5223de4cd12SGeorge Rokos   if (err != CUDA_SUCCESS) {
5233de4cd12SGeorge Rokos     DP("Error when setting CUDA context\n");
5243de4cd12SGeorge Rokos     CUDA_ERR_STRING(err);
5253de4cd12SGeorge Rokos     return OFFLOAD_FAIL;
5263de4cd12SGeorge Rokos   }
5273de4cd12SGeorge Rokos 
5283de4cd12SGeorge Rokos   err = cuMemcpyHtoD((CUdeviceptr)tgt_ptr, hst_ptr, size);
5293de4cd12SGeorge Rokos   if (err != CUDA_SUCCESS) {
5303de4cd12SGeorge Rokos     DP("Error when copying data from host to device. Pointers: host = " DPxMOD
5313de4cd12SGeorge Rokos        ", device = " DPxMOD ", size = %" PRId64 "\n", DPxPTR(hst_ptr),
5323de4cd12SGeorge Rokos        DPxPTR(tgt_ptr), size);
5333de4cd12SGeorge Rokos     CUDA_ERR_STRING(err);
5343de4cd12SGeorge Rokos     return OFFLOAD_FAIL;
5353de4cd12SGeorge Rokos   }
5363de4cd12SGeorge Rokos   return OFFLOAD_SUCCESS;
5373de4cd12SGeorge Rokos }
5383de4cd12SGeorge Rokos 
5393de4cd12SGeorge Rokos int32_t __tgt_rtl_data_retrieve(int32_t device_id, void *hst_ptr, void *tgt_ptr,
5403de4cd12SGeorge Rokos     int64_t size) {
5413de4cd12SGeorge Rokos   // Set the context we are using.
5423de4cd12SGeorge Rokos   CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]);
5433de4cd12SGeorge Rokos   if (err != CUDA_SUCCESS) {
5443de4cd12SGeorge Rokos     DP("Error when setting CUDA context\n");
5453de4cd12SGeorge Rokos     CUDA_ERR_STRING(err);
5463de4cd12SGeorge Rokos     return OFFLOAD_FAIL;
5473de4cd12SGeorge Rokos   }
5483de4cd12SGeorge Rokos 
5493de4cd12SGeorge Rokos   err = cuMemcpyDtoH(hst_ptr, (CUdeviceptr)tgt_ptr, size);
5503de4cd12SGeorge Rokos   if (err != CUDA_SUCCESS) {
5513de4cd12SGeorge Rokos     DP("Error when copying data from device to host. Pointers: host = " DPxMOD
5523de4cd12SGeorge Rokos         ", device = " DPxMOD ", size = %" PRId64 "\n", DPxPTR(hst_ptr),
5533de4cd12SGeorge Rokos         DPxPTR(tgt_ptr), size);
5543de4cd12SGeorge Rokos     CUDA_ERR_STRING(err);
5553de4cd12SGeorge Rokos     return OFFLOAD_FAIL;
5563de4cd12SGeorge Rokos   }
5573de4cd12SGeorge Rokos   return OFFLOAD_SUCCESS;
5583de4cd12SGeorge Rokos }
5593de4cd12SGeorge Rokos 
5603de4cd12SGeorge Rokos int32_t __tgt_rtl_data_delete(int32_t device_id, void *tgt_ptr) {
5613de4cd12SGeorge Rokos   // Set the context we are using.
5623de4cd12SGeorge Rokos   CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]);
5633de4cd12SGeorge Rokos   if (err != CUDA_SUCCESS) {
5643de4cd12SGeorge Rokos     DP("Error when setting CUDA context\n");
5653de4cd12SGeorge Rokos     CUDA_ERR_STRING(err);
5663de4cd12SGeorge Rokos     return OFFLOAD_FAIL;
5673de4cd12SGeorge Rokos   }
5683de4cd12SGeorge Rokos 
5693de4cd12SGeorge Rokos   err = cuMemFree((CUdeviceptr)tgt_ptr);
5703de4cd12SGeorge Rokos   if (err != CUDA_SUCCESS) {
5713de4cd12SGeorge Rokos     DP("Error when freeing CUDA memory\n");
5723de4cd12SGeorge Rokos     CUDA_ERR_STRING(err);
5733de4cd12SGeorge Rokos     return OFFLOAD_FAIL;
5743de4cd12SGeorge Rokos   }
5753de4cd12SGeorge Rokos   return OFFLOAD_SUCCESS;
5763de4cd12SGeorge Rokos }
5773de4cd12SGeorge Rokos 
5783de4cd12SGeorge Rokos int32_t __tgt_rtl_run_target_team_region(int32_t device_id, void *tgt_entry_ptr,
5791546d319SGeorge Rokos     void **tgt_args, ptrdiff_t *tgt_offsets, int32_t arg_num, int32_t team_num,
5801546d319SGeorge Rokos     int32_t thread_limit, uint64_t loop_tripcount) {
5813de4cd12SGeorge Rokos   // Set the context we are using.
5823de4cd12SGeorge Rokos   CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]);
5833de4cd12SGeorge Rokos   if (err != CUDA_SUCCESS) {
5843de4cd12SGeorge Rokos     DP("Error when setting CUDA context\n");
5853de4cd12SGeorge Rokos     CUDA_ERR_STRING(err);
5863de4cd12SGeorge Rokos     return OFFLOAD_FAIL;
5873de4cd12SGeorge Rokos   }
5883de4cd12SGeorge Rokos 
5893de4cd12SGeorge Rokos   // All args are references.
5903de4cd12SGeorge Rokos   std::vector<void *> args(arg_num);
5911546d319SGeorge Rokos   std::vector<void *> ptrs(arg_num);
5923de4cd12SGeorge Rokos 
5931546d319SGeorge Rokos   for (int32_t i = 0; i < arg_num; ++i) {
5941546d319SGeorge Rokos     ptrs[i] = (void *)((intptr_t)tgt_args[i] + tgt_offsets[i]);
5951546d319SGeorge Rokos     args[i] = &ptrs[i];
5961546d319SGeorge Rokos   }
5973de4cd12SGeorge Rokos 
5983de4cd12SGeorge Rokos   KernelTy *KernelInfo = (KernelTy *)tgt_entry_ptr;
5993de4cd12SGeorge Rokos 
6003de4cd12SGeorge Rokos   int cudaThreadsPerBlock;
6013de4cd12SGeorge Rokos 
6023de4cd12SGeorge Rokos   if (thread_limit > 0) {
6033de4cd12SGeorge Rokos     cudaThreadsPerBlock = thread_limit;
6043de4cd12SGeorge Rokos     DP("Setting CUDA threads per block to requested %d\n", thread_limit);
6053de4cd12SGeorge Rokos     // Add master warp if necessary
6063de4cd12SGeorge Rokos     if (KernelInfo->ExecutionMode == GENERIC) {
6073de4cd12SGeorge Rokos       cudaThreadsPerBlock += DeviceInfo.WarpSize[device_id];
6083de4cd12SGeorge Rokos       DP("Adding master warp: +%d threads\n", DeviceInfo.WarpSize[device_id]);
6093de4cd12SGeorge Rokos     }
610c13df8e5SGeorge Rokos   } else {
611c13df8e5SGeorge Rokos     cudaThreadsPerBlock = DeviceInfo.NumThreads[device_id];
612c13df8e5SGeorge Rokos     DP("Setting CUDA threads per block to default %d\n",
613c13df8e5SGeorge Rokos         DeviceInfo.NumThreads[device_id]);
614c13df8e5SGeorge Rokos   }
6153de4cd12SGeorge Rokos 
6163de4cd12SGeorge Rokos   if (cudaThreadsPerBlock > DeviceInfo.ThreadsPerBlock[device_id]) {
6173de4cd12SGeorge Rokos     cudaThreadsPerBlock = DeviceInfo.ThreadsPerBlock[device_id];
6183de4cd12SGeorge Rokos     DP("Threads per block capped at device limit %d\n",
6193de4cd12SGeorge Rokos         DeviceInfo.ThreadsPerBlock[device_id]);
6203de4cd12SGeorge Rokos   }
6213de4cd12SGeorge Rokos 
6223de4cd12SGeorge Rokos   int kernel_limit;
6233de4cd12SGeorge Rokos   err = cuFuncGetAttribute(&kernel_limit,
6243de4cd12SGeorge Rokos       CU_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK, KernelInfo->Func);
6253de4cd12SGeorge Rokos   if (err == CUDA_SUCCESS) {
6263de4cd12SGeorge Rokos     if (kernel_limit < cudaThreadsPerBlock) {
6273de4cd12SGeorge Rokos       cudaThreadsPerBlock = kernel_limit;
6283de4cd12SGeorge Rokos       DP("Threads per block capped at kernel limit %d\n", kernel_limit);
6293de4cd12SGeorge Rokos     }
6303de4cd12SGeorge Rokos   }
6313de4cd12SGeorge Rokos 
6323de4cd12SGeorge Rokos   int cudaBlocksPerGrid;
6333de4cd12SGeorge Rokos   if (team_num <= 0) {
6343de4cd12SGeorge Rokos     if (loop_tripcount > 0 && DeviceInfo.EnvNumTeams < 0) {
635c13df8e5SGeorge Rokos       if (KernelInfo->ExecutionMode == SPMD) {
636c13df8e5SGeorge Rokos         // We have a combined construct, i.e. `target teams distribute parallel
637c13df8e5SGeorge Rokos         // for [simd]`. We launch so many teams so that each thread will
638c13df8e5SGeorge Rokos         // execute one iteration of the loop.
6393de4cd12SGeorge Rokos         // round up to the nearest integer
6403de4cd12SGeorge Rokos         cudaBlocksPerGrid = ((loop_tripcount - 1) / cudaThreadsPerBlock) + 1;
641c13df8e5SGeorge Rokos       } else {
642c13df8e5SGeorge Rokos         // If we reach this point, then we have a non-combined construct, i.e.
643c13df8e5SGeorge Rokos         // `teams distribute` with a nested `parallel for` and each team is
644c13df8e5SGeorge Rokos         // assigned one iteration of the `distribute` loop. E.g.:
645c13df8e5SGeorge Rokos         //
646c13df8e5SGeorge Rokos         // #pragma omp target teams distribute
647c13df8e5SGeorge Rokos         // for(...loop_tripcount...) {
648c13df8e5SGeorge Rokos         //   #pragma omp parallel for
649c13df8e5SGeorge Rokos         //   for(...) {}
650c13df8e5SGeorge Rokos         // }
651c13df8e5SGeorge Rokos         //
652c13df8e5SGeorge Rokos         // Threads within a team will execute the iterations of the `parallel`
653c13df8e5SGeorge Rokos         // loop.
654c13df8e5SGeorge Rokos         cudaBlocksPerGrid = loop_tripcount;
655c13df8e5SGeorge Rokos       }
6563de4cd12SGeorge Rokos       DP("Using %d teams due to loop trip count %" PRIu64 " and number of "
6573de4cd12SGeorge Rokos           "threads per block %d\n", cudaBlocksPerGrid, loop_tripcount,
6583de4cd12SGeorge Rokos           cudaThreadsPerBlock);
6593de4cd12SGeorge Rokos     } else {
6603de4cd12SGeorge Rokos       cudaBlocksPerGrid = DeviceInfo.NumTeams[device_id];
6613de4cd12SGeorge Rokos       DP("Using default number of teams %d\n", DeviceInfo.NumTeams[device_id]);
6623de4cd12SGeorge Rokos     }
6633de4cd12SGeorge Rokos   } else if (team_num > DeviceInfo.BlocksPerGrid[device_id]) {
6643de4cd12SGeorge Rokos     cudaBlocksPerGrid = DeviceInfo.BlocksPerGrid[device_id];
6653de4cd12SGeorge Rokos     DP("Capping number of teams to team limit %d\n",
6663de4cd12SGeorge Rokos         DeviceInfo.BlocksPerGrid[device_id]);
6673de4cd12SGeorge Rokos   } else {
6683de4cd12SGeorge Rokos     cudaBlocksPerGrid = team_num;
6693de4cd12SGeorge Rokos     DP("Using requested number of teams %d\n", team_num);
6703de4cd12SGeorge Rokos   }
6713de4cd12SGeorge Rokos 
6723de4cd12SGeorge Rokos   // Run on the device.
6733de4cd12SGeorge Rokos   DP("Launch kernel with %d blocks and %d threads\n", cudaBlocksPerGrid,
6743de4cd12SGeorge Rokos      cudaThreadsPerBlock);
6753de4cd12SGeorge Rokos 
6763de4cd12SGeorge Rokos   err = cuLaunchKernel(KernelInfo->Func, cudaBlocksPerGrid, 1, 1,
6773de4cd12SGeorge Rokos       cudaThreadsPerBlock, 1, 1, 0 /*bytes of shared memory*/, 0, &args[0], 0);
6783de4cd12SGeorge Rokos   if (err != CUDA_SUCCESS) {
6793de4cd12SGeorge Rokos     DP("Device kernel launch failed!\n");
6803de4cd12SGeorge Rokos     CUDA_ERR_STRING(err);
6813de4cd12SGeorge Rokos     assert(err == CUDA_SUCCESS && "Unable to launch target execution!");
6823de4cd12SGeorge Rokos     return OFFLOAD_FAIL;
6833de4cd12SGeorge Rokos   }
6843de4cd12SGeorge Rokos 
6853de4cd12SGeorge Rokos   DP("Launch of entry point at " DPxMOD " successful!\n",
6863de4cd12SGeorge Rokos       DPxPTR(tgt_entry_ptr));
6873de4cd12SGeorge Rokos 
68801954092SGeorge Rokos   cudaError_t sync_error = cudaDeviceSynchronize();
68901954092SGeorge Rokos   if (sync_error != cudaSuccess) {
69001954092SGeorge Rokos   DP("Kernel execution error at " DPxMOD ", %s.\n", DPxPTR(tgt_entry_ptr),
69101954092SGeorge Rokos       cudaGetErrorString(sync_error));
6923de4cd12SGeorge Rokos     return OFFLOAD_FAIL;
6933de4cd12SGeorge Rokos   } else {
6943de4cd12SGeorge Rokos     DP("Kernel execution at " DPxMOD " successful!\n", DPxPTR(tgt_entry_ptr));
6953de4cd12SGeorge Rokos   }
6963de4cd12SGeorge Rokos 
6973de4cd12SGeorge Rokos   return OFFLOAD_SUCCESS;
6983de4cd12SGeorge Rokos }
6993de4cd12SGeorge Rokos 
7003de4cd12SGeorge Rokos int32_t __tgt_rtl_run_target_region(int32_t device_id, void *tgt_entry_ptr,
7011546d319SGeorge Rokos     void **tgt_args, ptrdiff_t *tgt_offsets, int32_t arg_num) {
7023de4cd12SGeorge Rokos   // use one team and the default number of threads.
7033de4cd12SGeorge Rokos   const int32_t team_num = 1;
7043de4cd12SGeorge Rokos   const int32_t thread_limit = 0;
7053de4cd12SGeorge Rokos   return __tgt_rtl_run_target_team_region(device_id, tgt_entry_ptr, tgt_args,
7061546d319SGeorge Rokos       tgt_offsets, arg_num, team_num, thread_limit, 0);
7073de4cd12SGeorge Rokos }
7083de4cd12SGeorge Rokos 
7093de4cd12SGeorge Rokos #ifdef __cplusplus
7103de4cd12SGeorge Rokos }
7113de4cd12SGeorge Rokos #endif
712