143322804SJonas Hahnfeld //===----------- rtl.cpp - Target independent OpenMP target RTL -----------===//
243322804SJonas Hahnfeld //
357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
643322804SJonas Hahnfeld //
743322804SJonas Hahnfeld //===----------------------------------------------------------------------===//
843322804SJonas Hahnfeld //
943322804SJonas Hahnfeld // Functionality for handling RTL plugins.
1043322804SJonas Hahnfeld //
1143322804SJonas Hahnfeld //===----------------------------------------------------------------------===//
1243322804SJonas Hahnfeld 
139cd1e222SJohannes Doerfert #include "rtl.h"
1443322804SJonas Hahnfeld #include "device.h"
1543322804SJonas Hahnfeld #include "private.h"
1643322804SJonas Hahnfeld 
17fbcb1ee7SJoseph Huber #include "llvm/Object/OffloadBinary.h"
18fbcb1ee7SJoseph Huber 
1943322804SJonas Hahnfeld #include <cassert>
209f49676aSDimitry Andric #include <cstdlib>
2143322804SJonas Hahnfeld #include <cstring>
2243322804SJonas Hahnfeld #include <dlfcn.h>
2343322804SJonas Hahnfeld #include <mutex>
24e5499111SJonas Hahnfeld #include <string>
2543322804SJonas Hahnfeld 
2643322804SJonas Hahnfeld // List of all plugins that can support offloading.
2743322804SJonas Hahnfeld static const char *RTLNames[] = {
2843322804SJonas Hahnfeld     /* PowerPC target       */ "libomptarget.rtl.ppc64.so",
2943322804SJonas Hahnfeld     /* x86_64 target        */ "libomptarget.rtl.x86_64.so",
3043322804SJonas Hahnfeld     /* CUDA target          */ "libomptarget.rtl.cuda.so",
31d0b31295SJon Chesterfield     /* AArch64 target       */ "libomptarget.rtl.aarch64.so",
3232ebdc70SGeorge Rokos     /* SX-Aurora VE target  */ "libomptarget.rtl.ve.so",
33d0b31295SJon Chesterfield     /* AMDGPU target        */ "libomptarget.rtl.amdgpu.so",
34683719bcSAtmn     /* Remote target        */ "libomptarget.rtl.rpc.so",
35d0b31295SJon Chesterfield };
3643322804SJonas Hahnfeld 
37a95b25b2SAtmn Patel PluginManager *PM;
3863cef621SAlexey Bataev 
39e007b328SGiorgis Georgakoudis #if OMPTARGET_PROFILE_ENABLED
40e007b328SGiorgis Georgakoudis static char *ProfileTraceFile = nullptr;
41e007b328SGiorgis Georgakoudis #endif
42e007b328SGiorgis Georgakoudis 
init()43c4a9d976SAlexey Bataev __attribute__((constructor(101))) void init() {
4463cef621SAlexey Bataev   DP("Init target library!\n");
451e447d03SJohannes Doerfert 
461e447d03SJohannes Doerfert   bool UseEventsForAtomicTransfers = true;
471e447d03SJohannes Doerfert   if (const char *ForceAtomicMap = getenv("LIBOMPTARGET_MAP_FORCE_ATOMIC")) {
481e447d03SJohannes Doerfert     std::string ForceAtomicMapStr(ForceAtomicMap);
491e447d03SJohannes Doerfert     if (ForceAtomicMapStr == "false" || ForceAtomicMapStr == "FALSE")
501e447d03SJohannes Doerfert       UseEventsForAtomicTransfers = false;
511e447d03SJohannes Doerfert     else if (ForceAtomicMapStr != "true" && ForceAtomicMapStr != "TRUE")
521e447d03SJohannes Doerfert       fprintf(stderr,
531e447d03SJohannes Doerfert               "Warning: 'LIBOMPTARGET_MAP_FORCE_ATOMIC' accepts only "
541e447d03SJohannes Doerfert               "'true'/'TRUE' or 'false'/'FALSE' as options, '%s' ignored\n",
551e447d03SJohannes Doerfert               ForceAtomicMap);
561e447d03SJohannes Doerfert   }
571e447d03SJohannes Doerfert 
581e447d03SJohannes Doerfert   PM = new PluginManager(UseEventsForAtomicTransfers);
59e007b328SGiorgis Georgakoudis 
60e007b328SGiorgis Georgakoudis #ifdef OMPTARGET_PROFILE_ENABLED
61e007b328SGiorgis Georgakoudis   ProfileTraceFile = getenv("LIBOMPTARGET_PROFILE");
62e007b328SGiorgis Georgakoudis   // TODO: add a configuration option for time granularity
63e007b328SGiorgis Georgakoudis   if (ProfileTraceFile)
64e007b328SGiorgis Georgakoudis     llvm::timeTraceProfilerInitialize(500 /* us */, "libomptarget");
65e007b328SGiorgis Georgakoudis #endif
6663cef621SAlexey Bataev }
6763cef621SAlexey Bataev 
deinit()68c4a9d976SAlexey Bataev __attribute__((destructor(101))) void deinit() {
6963cef621SAlexey Bataev   DP("Deinit target library!\n");
70a95b25b2SAtmn Patel   delete PM;
71e007b328SGiorgis Georgakoudis 
72e007b328SGiorgis Georgakoudis #ifdef OMPTARGET_PROFILE_ENABLED
73e007b328SGiorgis Georgakoudis   if (ProfileTraceFile) {
74e007b328SGiorgis Georgakoudis     // TODO: add env var for file output
75e007b328SGiorgis Georgakoudis     if (auto E = llvm::timeTraceProfilerWrite(ProfileTraceFile, "-"))
76e007b328SGiorgis Georgakoudis       fprintf(stderr, "Error writing out the time trace\n");
77e007b328SGiorgis Georgakoudis 
78e007b328SGiorgis Georgakoudis     llvm::timeTraceProfilerCleanup();
79e007b328SGiorgis Georgakoudis   }
80e007b328SGiorgis Georgakoudis #endif
8163cef621SAlexey Bataev }
8243322804SJonas Hahnfeld 
loadRTLs()83d27d0a67SJoseph Huber void RTLsTy::loadRTLs() {
8443322804SJonas Hahnfeld   // Parse environment variable OMP_TARGET_OFFLOAD (if set)
85a95b25b2SAtmn Patel   PM->TargetOffloadPolicy =
86a95b25b2SAtmn Patel       (kmp_target_offload_kind_t)__kmpc_get_target_offload();
87a95b25b2SAtmn Patel   if (PM->TargetOffloadPolicy == tgt_disabled) {
8843322804SJonas Hahnfeld     return;
8943322804SJonas Hahnfeld   }
9043322804SJonas Hahnfeld 
9143322804SJonas Hahnfeld   DP("Loading RTLs...\n");
9243322804SJonas Hahnfeld 
9343322804SJonas Hahnfeld   // Attempt to open all the plugins and, if they exist, check if the interface
9443322804SJonas Hahnfeld   // is correct and if they are supporting any devices.
9543322804SJonas Hahnfeld   for (auto *Name : RTLNames) {
9643322804SJonas Hahnfeld     DP("Loading library '%s'...\n", Name);
97d27d0a67SJoseph Huber     void *DynlibHandle = dlopen(Name, RTLD_NOW);
9843322804SJonas Hahnfeld 
99d27d0a67SJoseph Huber     if (!DynlibHandle) {
10043322804SJonas Hahnfeld       // Library does not exist or cannot be found.
10143322804SJonas Hahnfeld       DP("Unable to load library '%s': %s!\n", Name, dlerror());
10243322804SJonas Hahnfeld       continue;
10343322804SJonas Hahnfeld     }
10443322804SJonas Hahnfeld 
10543322804SJonas Hahnfeld     DP("Successfully loaded library '%s'!\n", Name);
10643322804SJonas Hahnfeld 
107175c336aSShilei Tian     AllRTLs.emplace_back();
108175c336aSShilei Tian 
10943322804SJonas Hahnfeld     // Retrieve the RTL information from the runtime library.
110175c336aSShilei Tian     RTLInfoTy &R = AllRTLs.back();
111175c336aSShilei Tian 
112410bfa00SJon Chesterfield     // Remove plugin on failure to call optional init_plugin
113410bfa00SJon Chesterfield     *((void **)&R.init_plugin) = dlsym(DynlibHandle, "__tgt_rtl_init_plugin");
114410bfa00SJon Chesterfield     if (R.init_plugin) {
115410bfa00SJon Chesterfield       int32_t Rc = R.init_plugin();
116410bfa00SJon Chesterfield       if (Rc != OFFLOAD_SUCCESS) {
117410bfa00SJon Chesterfield         DP("Unable to initialize library '%s': %u!\n", Name, Rc);
118410bfa00SJon Chesterfield         AllRTLs.pop_back();
119410bfa00SJon Chesterfield         continue;
120410bfa00SJon Chesterfield       }
121410bfa00SJon Chesterfield     }
122410bfa00SJon Chesterfield 
123175c336aSShilei Tian     bool ValidPlugin = true;
124175c336aSShilei Tian 
125175c336aSShilei Tian     if (!(*((void **)&R.is_valid_binary) =
126d27d0a67SJoseph Huber               dlsym(DynlibHandle, "__tgt_rtl_is_valid_binary")))
127175c336aSShilei Tian       ValidPlugin = false;
128175c336aSShilei Tian     if (!(*((void **)&R.number_of_devices) =
129d27d0a67SJoseph Huber               dlsym(DynlibHandle, "__tgt_rtl_number_of_devices")))
130175c336aSShilei Tian       ValidPlugin = false;
131175c336aSShilei Tian     if (!(*((void **)&R.init_device) =
132d27d0a67SJoseph Huber               dlsym(DynlibHandle, "__tgt_rtl_init_device")))
133175c336aSShilei Tian       ValidPlugin = false;
134175c336aSShilei Tian     if (!(*((void **)&R.load_binary) =
135d27d0a67SJoseph Huber               dlsym(DynlibHandle, "__tgt_rtl_load_binary")))
136175c336aSShilei Tian       ValidPlugin = false;
137175c336aSShilei Tian     if (!(*((void **)&R.data_alloc) =
138d27d0a67SJoseph Huber               dlsym(DynlibHandle, "__tgt_rtl_data_alloc")))
139175c336aSShilei Tian       ValidPlugin = false;
140175c336aSShilei Tian     if (!(*((void **)&R.data_submit) =
141d27d0a67SJoseph Huber               dlsym(DynlibHandle, "__tgt_rtl_data_submit")))
142175c336aSShilei Tian       ValidPlugin = false;
143175c336aSShilei Tian     if (!(*((void **)&R.data_retrieve) =
144d27d0a67SJoseph Huber               dlsym(DynlibHandle, "__tgt_rtl_data_retrieve")))
145175c336aSShilei Tian       ValidPlugin = false;
146175c336aSShilei Tian     if (!(*((void **)&R.data_delete) =
147d27d0a67SJoseph Huber               dlsym(DynlibHandle, "__tgt_rtl_data_delete")))
148175c336aSShilei Tian       ValidPlugin = false;
149175c336aSShilei Tian     if (!(*((void **)&R.run_region) =
150d27d0a67SJoseph Huber               dlsym(DynlibHandle, "__tgt_rtl_run_target_region")))
151175c336aSShilei Tian       ValidPlugin = false;
152175c336aSShilei Tian     if (!(*((void **)&R.run_team_region) =
153d27d0a67SJoseph Huber               dlsym(DynlibHandle, "__tgt_rtl_run_target_team_region")))
154175c336aSShilei Tian       ValidPlugin = false;
155175c336aSShilei Tian 
156175c336aSShilei Tian     // Invalid plugin
157175c336aSShilei Tian     if (!ValidPlugin) {
158175c336aSShilei Tian       DP("Invalid plugin as necessary interface is not found.\n");
159175c336aSShilei Tian       AllRTLs.pop_back();
160175c336aSShilei Tian       continue;
161175c336aSShilei Tian     }
162175c336aSShilei Tian 
163175c336aSShilei Tian     // No devices are supported by this RTL?
164175c336aSShilei Tian     if (!(R.NumberOfDevices = R.number_of_devices())) {
165175c336aSShilei Tian       // The RTL is invalid! Will pop the object from the RTLs list.
166175c336aSShilei Tian       DP("No devices supported in this RTL\n");
167175c336aSShilei Tian       AllRTLs.pop_back();
168175c336aSShilei Tian       continue;
169175c336aSShilei Tian     }
17043322804SJonas Hahnfeld 
171d27d0a67SJoseph Huber     R.LibraryHandler = DynlibHandle;
17243322804SJonas Hahnfeld 
17343322804SJonas Hahnfeld #ifdef OMPTARGET_DEBUG
17443322804SJonas Hahnfeld     R.RTLName = Name;
17543322804SJonas Hahnfeld #endif
17643322804SJonas Hahnfeld 
177175c336aSShilei Tian     DP("Registering RTL %s supporting %d devices!\n", R.RTLName.c_str(),
178175c336aSShilei Tian        R.NumberOfDevices);
17943322804SJonas Hahnfeld 
180c5fe030cSGheorghe-Teodor Bercea     // Optional functions
181410bfa00SJon Chesterfield     *((void **)&R.deinit_plugin) =
182410bfa00SJon Chesterfield         dlsym(DynlibHandle, "__tgt_rtl_deinit_plugin");
183fbcb1ee7SJoseph Huber     *((void **)&R.is_valid_binary_info) =
184fbcb1ee7SJoseph Huber         dlsym(DynlibHandle, "__tgt_rtl_is_valid_binary_info");
18510aa83ffSJohannes Doerfert     *((void **)&R.deinit_device) =
186d27d0a67SJoseph Huber         dlsym(DynlibHandle, "__tgt_rtl_deinit_device");
18703ff643dSShilei Tian     *((void **)&R.init_requires) =
188d27d0a67SJoseph Huber         dlsym(DynlibHandle, "__tgt_rtl_init_requires");
18903ff643dSShilei Tian     *((void **)&R.data_submit_async) =
190d27d0a67SJoseph Huber         dlsym(DynlibHandle, "__tgt_rtl_data_submit_async");
19103ff643dSShilei Tian     *((void **)&R.data_retrieve_async) =
192d27d0a67SJoseph Huber         dlsym(DynlibHandle, "__tgt_rtl_data_retrieve_async");
19303ff643dSShilei Tian     *((void **)&R.run_region_async) =
194d27d0a67SJoseph Huber         dlsym(DynlibHandle, "__tgt_rtl_run_target_region_async");
19503ff643dSShilei Tian     *((void **)&R.run_team_region_async) =
196d27d0a67SJoseph Huber         dlsym(DynlibHandle, "__tgt_rtl_run_target_team_region_async");
197d27d0a67SJoseph Huber     *((void **)&R.synchronize) = dlsym(DynlibHandle, "__tgt_rtl_synchronize");
198a014fbbcSShilei Tian     *((void **)&R.data_exchange) =
199d27d0a67SJoseph Huber         dlsym(DynlibHandle, "__tgt_rtl_data_exchange");
200a014fbbcSShilei Tian     *((void **)&R.data_exchange_async) =
201d27d0a67SJoseph Huber         dlsym(DynlibHandle, "__tgt_rtl_data_exchange_async");
202a014fbbcSShilei Tian     *((void **)&R.is_data_exchangable) =
203d27d0a67SJoseph Huber         dlsym(DynlibHandle, "__tgt_rtl_is_data_exchangable");
204d27d0a67SJoseph Huber     *((void **)&R.register_lib) = dlsym(DynlibHandle, "__tgt_rtl_register_lib");
205683719bcSAtmn     *((void **)&R.unregister_lib) =
206d27d0a67SJoseph Huber         dlsym(DynlibHandle, "__tgt_rtl_unregister_lib");
207542d9c21SManoel Roemmer     *((void **)&R.supports_empty_images) =
208d27d0a67SJoseph Huber         dlsym(DynlibHandle, "__tgt_rtl_supports_empty_images");
2092b6f2008SJoseph Huber     *((void **)&R.set_info_flag) =
210d27d0a67SJoseph Huber         dlsym(DynlibHandle, "__tgt_rtl_set_info_flag");
211d2f85d09SJose M Monsalve Diaz     *((void **)&R.print_device_info) =
212d27d0a67SJoseph Huber         dlsym(DynlibHandle, "__tgt_rtl_print_device_info");
213d27d0a67SJoseph Huber     *((void **)&R.create_event) = dlsym(DynlibHandle, "__tgt_rtl_create_event");
214d27d0a67SJoseph Huber     *((void **)&R.record_event) = dlsym(DynlibHandle, "__tgt_rtl_record_event");
215d27d0a67SJoseph Huber     *((void **)&R.wait_event) = dlsym(DynlibHandle, "__tgt_rtl_wait_event");
216d27d0a67SJoseph Huber     *((void **)&R.sync_event) = dlsym(DynlibHandle, "__tgt_rtl_sync_event");
21729df4ab3SShilei Tian     *((void **)&R.destroy_event) =
218d27d0a67SJoseph Huber         dlsym(DynlibHandle, "__tgt_rtl_destroy_event");
219f44e41afSSri Hari Krishna Narayanan     *((void **)&R.release_async_info) =
220d27d0a67SJoseph Huber         dlsym(DynlibHandle, "__tgt_rtl_release_async_info");
221f44e41afSSri Hari Krishna Narayanan     *((void **)&R.init_async_info) =
222d27d0a67SJoseph Huber         dlsym(DynlibHandle, "__tgt_rtl_init_async_info");
223f44e41afSSri Hari Krishna Narayanan     *((void **)&R.init_device_info) =
224d27d0a67SJoseph Huber         dlsym(DynlibHandle, "__tgt_rtl_init_device_info");
22543322804SJonas Hahnfeld   }
22643322804SJonas Hahnfeld 
22743322804SJonas Hahnfeld   DP("RTLs loaded!\n");
22843322804SJonas Hahnfeld 
22943322804SJonas Hahnfeld   return;
23043322804SJonas Hahnfeld }
23143322804SJonas Hahnfeld 
23243322804SJonas Hahnfeld ////////////////////////////////////////////////////////////////////////////////
23343322804SJonas Hahnfeld // Functionality for registering libs
23443322804SJonas Hahnfeld 
registerImageIntoTranslationTable(TranslationTable & TT,RTLInfoTy & RTL,__tgt_device_image * Image)235d27d0a67SJoseph Huber static void registerImageIntoTranslationTable(TranslationTable &TT,
2369cd1e222SJohannes Doerfert                                               RTLInfoTy &RTL,
237d27d0a67SJoseph Huber                                               __tgt_device_image *Image) {
23843322804SJonas Hahnfeld 
23943322804SJonas Hahnfeld   // same size, as when we increase one, we also increase the other.
24043322804SJonas Hahnfeld   assert(TT.TargetsTable.size() == TT.TargetsImages.size() &&
24143322804SJonas Hahnfeld          "We should have as many images as we have tables!");
24243322804SJonas Hahnfeld 
24343322804SJonas Hahnfeld   // Resize the Targets Table and Images to accommodate the new targets if
24443322804SJonas Hahnfeld   // required
24543322804SJonas Hahnfeld   unsigned TargetsTableMinimumSize = RTL.Idx + RTL.NumberOfDevices;
24643322804SJonas Hahnfeld 
24743322804SJonas Hahnfeld   if (TT.TargetsTable.size() < TargetsTableMinimumSize) {
24843322804SJonas Hahnfeld     TT.TargetsImages.resize(TargetsTableMinimumSize, 0);
24943322804SJonas Hahnfeld     TT.TargetsTable.resize(TargetsTableMinimumSize, 0);
25043322804SJonas Hahnfeld   }
25143322804SJonas Hahnfeld 
25243322804SJonas Hahnfeld   // Register the image in all devices for this target type.
253d27d0a67SJoseph Huber   for (int32_t I = 0; I < RTL.NumberOfDevices; ++I) {
25443322804SJonas Hahnfeld     // If we are changing the image we are also invalidating the target table.
255d27d0a67SJoseph Huber     if (TT.TargetsImages[RTL.Idx + I] != Image) {
256d27d0a67SJoseph Huber       TT.TargetsImages[RTL.Idx + I] = Image;
257d27d0a67SJoseph Huber       TT.TargetsTable[RTL.Idx + I] = 0; // lazy initialization of target table.
25843322804SJonas Hahnfeld     }
25943322804SJonas Hahnfeld   }
26043322804SJonas Hahnfeld }
26143322804SJonas Hahnfeld 
26243322804SJonas Hahnfeld ////////////////////////////////////////////////////////////////////////////////
26343322804SJonas Hahnfeld // Functionality for registering Ctors/Dtors
26443322804SJonas Hahnfeld 
registerGlobalCtorsDtorsForImage(__tgt_bin_desc * Desc,__tgt_device_image * Img,RTLInfoTy * RTL)265d27d0a67SJoseph Huber static void registerGlobalCtorsDtorsForImage(__tgt_bin_desc *Desc,
266d27d0a67SJoseph Huber                                              __tgt_device_image *Img,
2679cd1e222SJohannes Doerfert                                              RTLInfoTy *RTL) {
26843322804SJonas Hahnfeld 
269d27d0a67SJoseph Huber   for (int32_t I = 0; I < RTL->NumberOfDevices; ++I) {
270d27d0a67SJoseph Huber     DeviceTy &Device = *PM->Devices[RTL->Idx + I];
27143322804SJonas Hahnfeld     Device.PendingGlobalsMtx.lock();
27243322804SJonas Hahnfeld     Device.HasPendingGlobals = true;
273d27d0a67SJoseph Huber     for (__tgt_offload_entry *Entry = Img->EntriesBegin;
274d27d0a67SJoseph Huber          Entry != Img->EntriesEnd; ++Entry) {
275d27d0a67SJoseph Huber       if (Entry->flags & OMP_DECLARE_TARGET_CTOR) {
27643322804SJonas Hahnfeld         DP("Adding ctor " DPxMOD " to the pending list.\n",
277d27d0a67SJoseph Huber            DPxPTR(Entry->addr));
278d27d0a67SJoseph Huber         Device.PendingCtorsDtors[Desc].PendingCtors.push_back(Entry->addr);
279d27d0a67SJoseph Huber       } else if (Entry->flags & OMP_DECLARE_TARGET_DTOR) {
28043322804SJonas Hahnfeld         // Dtors are pushed in reverse order so they are executed from end
28143322804SJonas Hahnfeld         // to beginning when unregistering the library!
28243322804SJonas Hahnfeld         DP("Adding dtor " DPxMOD " to the pending list.\n",
283d27d0a67SJoseph Huber            DPxPTR(Entry->addr));
284d27d0a67SJoseph Huber         Device.PendingCtorsDtors[Desc].PendingDtors.push_front(Entry->addr);
28543322804SJonas Hahnfeld       }
28643322804SJonas Hahnfeld 
287d27d0a67SJoseph Huber       if (Entry->flags & OMP_DECLARE_TARGET_LINK) {
28843322804SJonas Hahnfeld         DP("The \"link\" attribute is not yet supported!\n");
28943322804SJonas Hahnfeld       }
29043322804SJonas Hahnfeld     }
29143322804SJonas Hahnfeld     Device.PendingGlobalsMtx.unlock();
29243322804SJonas Hahnfeld   }
29343322804SJonas Hahnfeld }
29443322804SJonas Hahnfeld 
getExecutableImage(__tgt_device_image * Image)295fbcb1ee7SJoseph Huber static __tgt_device_image getExecutableImage(__tgt_device_image *Image) {
296fbcb1ee7SJoseph Huber   llvm::StringRef ImageStr(static_cast<char *>(Image->ImageStart),
297fbcb1ee7SJoseph Huber                            static_cast<char *>(Image->ImageEnd) -
298fbcb1ee7SJoseph Huber                                static_cast<char *>(Image->ImageStart));
299fbcb1ee7SJoseph Huber   auto BinaryOrErr =
300fbcb1ee7SJoseph Huber       llvm::object::OffloadBinary::create(llvm::MemoryBufferRef(ImageStr, ""));
301fbcb1ee7SJoseph Huber   if (!BinaryOrErr) {
302fbcb1ee7SJoseph Huber     llvm::consumeError(BinaryOrErr.takeError());
303fbcb1ee7SJoseph Huber     return *Image;
304fbcb1ee7SJoseph Huber   }
305fbcb1ee7SJoseph Huber 
306fbcb1ee7SJoseph Huber   void *Begin = const_cast<void *>(
307fbcb1ee7SJoseph Huber       static_cast<const void *>((*BinaryOrErr)->getImage().bytes_begin()));
308fbcb1ee7SJoseph Huber   void *End = const_cast<void *>(
309fbcb1ee7SJoseph Huber       static_cast<const void *>((*BinaryOrErr)->getImage().bytes_end()));
310fbcb1ee7SJoseph Huber 
311fbcb1ee7SJoseph Huber   return {Begin, End, Image->EntriesBegin, Image->EntriesEnd};
312fbcb1ee7SJoseph Huber }
313fbcb1ee7SJoseph Huber 
getImageInfo(__tgt_device_image * Image)314fbcb1ee7SJoseph Huber static __tgt_image_info getImageInfo(__tgt_device_image *Image) {
315fbcb1ee7SJoseph Huber   llvm::StringRef ImageStr(static_cast<char *>(Image->ImageStart),
316fbcb1ee7SJoseph Huber                            static_cast<char *>(Image->ImageEnd) -
317fbcb1ee7SJoseph Huber                                static_cast<char *>(Image->ImageStart));
318fbcb1ee7SJoseph Huber   auto BinaryOrErr =
319fbcb1ee7SJoseph Huber       llvm::object::OffloadBinary::create(llvm::MemoryBufferRef(ImageStr, ""));
320fbcb1ee7SJoseph Huber   if (!BinaryOrErr) {
321fbcb1ee7SJoseph Huber     llvm::consumeError(BinaryOrErr.takeError());
322fbcb1ee7SJoseph Huber     return __tgt_image_info{};
323fbcb1ee7SJoseph Huber   }
324fbcb1ee7SJoseph Huber 
325fbcb1ee7SJoseph Huber   return __tgt_image_info{(*BinaryOrErr)->getArch().data()};
326fbcb1ee7SJoseph Huber }
327fbcb1ee7SJoseph Huber 
registerRequires(int64_t Flags)328d27d0a67SJoseph Huber void RTLsTy::registerRequires(int64_t Flags) {
3299e9c9182SGheorghe-Teodor Bercea   // TODO: add more elaborate check.
3309e9c9182SGheorghe-Teodor Bercea   // Minimal check: only set requires flags if previous value
3319e9c9182SGheorghe-Teodor Bercea   // is undefined. This ensures that only the first call to this
3329e9c9182SGheorghe-Teodor Bercea   // function will set the requires flags. All subsequent calls
3339e9c9182SGheorghe-Teodor Bercea   // will be checked for compatibility.
334d27d0a67SJoseph Huber   assert(Flags != OMP_REQ_UNDEFINED &&
3359e9c9182SGheorghe-Teodor Bercea          "illegal undefined flag for requires directive!");
3369e9c9182SGheorghe-Teodor Bercea   if (RequiresFlags == OMP_REQ_UNDEFINED) {
337d27d0a67SJoseph Huber     RequiresFlags = Flags;
3389e9c9182SGheorghe-Teodor Bercea     return;
3399e9c9182SGheorghe-Teodor Bercea   }
3409e9c9182SGheorghe-Teodor Bercea 
3419e9c9182SGheorghe-Teodor Bercea   // If multiple compilation units are present enforce
3429e9c9182SGheorghe-Teodor Bercea   // consistency across all of them for require clauses:
3439e9c9182SGheorghe-Teodor Bercea   //  - reverse_offload
3449e9c9182SGheorghe-Teodor Bercea   //  - unified_address
3459e9c9182SGheorghe-Teodor Bercea   //  - unified_shared_memory
3469e9c9182SGheorghe-Teodor Bercea   if ((RequiresFlags & OMP_REQ_REVERSE_OFFLOAD) !=
347d27d0a67SJoseph Huber       (Flags & OMP_REQ_REVERSE_OFFLOAD)) {
3489cd1e222SJohannes Doerfert     FATAL_MESSAGE0(
3499cd1e222SJohannes Doerfert         1, "'#pragma omp requires reverse_offload' not used consistently!");
3509e9c9182SGheorghe-Teodor Bercea   }
3519e9c9182SGheorghe-Teodor Bercea   if ((RequiresFlags & OMP_REQ_UNIFIED_ADDRESS) !=
352d27d0a67SJoseph Huber       (Flags & OMP_REQ_UNIFIED_ADDRESS)) {
3539cd1e222SJohannes Doerfert     FATAL_MESSAGE0(
3549cd1e222SJohannes Doerfert         1, "'#pragma omp requires unified_address' not used consistently!");
3559e9c9182SGheorghe-Teodor Bercea   }
3569e9c9182SGheorghe-Teodor Bercea   if ((RequiresFlags & OMP_REQ_UNIFIED_SHARED_MEMORY) !=
357d27d0a67SJoseph Huber       (Flags & OMP_REQ_UNIFIED_SHARED_MEMORY)) {
3589cd1e222SJohannes Doerfert     FATAL_MESSAGE0(
3599cd1e222SJohannes Doerfert         1,
3609e9c9182SGheorghe-Teodor Bercea         "'#pragma omp requires unified_shared_memory' not used consistently!");
3619e9c9182SGheorghe-Teodor Bercea   }
3629e9c9182SGheorghe-Teodor Bercea 
3639e9c9182SGheorghe-Teodor Bercea   // TODO: insert any other missing checks
3649e9c9182SGheorghe-Teodor Bercea 
36540470eb2SGeorge Rokos   DP("New requires flags %" PRId64 " compatible with existing %" PRId64 "!\n",
366d27d0a67SJoseph Huber      Flags, RequiresFlags);
3679e9c9182SGheorghe-Teodor Bercea }
3689e9c9182SGheorghe-Teodor Bercea 
initRTLonce(RTLInfoTy & R)369313c5239SJose M Monsalve Diaz void RTLsTy::initRTLonce(RTLInfoTy &R) {
37043322804SJonas Hahnfeld   // If this RTL is not already in use, initialize it.
371d27d0a67SJoseph Huber   if (!R.IsUsed && R.NumberOfDevices != 0) {
37243322804SJonas Hahnfeld     // Initialize the device information for the RTL we are about to use.
373c3aecf87SYe Luo     const size_t Start = PM->Devices.size();
374c3aecf87SYe Luo     PM->Devices.reserve(Start + R.NumberOfDevices);
375d27d0a67SJoseph Huber     for (int32_t DeviceId = 0; DeviceId < R.NumberOfDevices; DeviceId++) {
376c3aecf87SYe Luo       PM->Devices.push_back(std::make_unique<DeviceTy>(&R));
37743322804SJonas Hahnfeld       // global device ID
378d27d0a67SJoseph Huber       PM->Devices[Start + DeviceId]->DeviceID = Start + DeviceId;
37943322804SJonas Hahnfeld       // RTL local device ID
380d27d0a67SJoseph Huber       PM->Devices[Start + DeviceId]->RTLDeviceID = DeviceId;
38143322804SJonas Hahnfeld     }
38243322804SJonas Hahnfeld 
38343322804SJonas Hahnfeld     // Initialize the index of this RTL and save it in the used RTLs.
38463cef621SAlexey Bataev     R.Idx = (UsedRTLs.empty())
38543322804SJonas Hahnfeld                 ? 0
38663cef621SAlexey Bataev                 : UsedRTLs.back()->Idx + UsedRTLs.back()->NumberOfDevices;
387a95b25b2SAtmn Patel     assert((size_t)R.Idx == Start &&
38843322804SJonas Hahnfeld            "RTL index should equal the number of devices used so far.");
389d27d0a67SJoseph Huber     R.IsUsed = true;
39063cef621SAlexey Bataev     UsedRTLs.push_back(&R);
39143322804SJonas Hahnfeld 
39243322804SJonas Hahnfeld     DP("RTL " DPxMOD " has index %d!\n", DPxPTR(R.LibraryHandler), R.Idx);
39343322804SJonas Hahnfeld   }
394313c5239SJose M Monsalve Diaz }
395313c5239SJose M Monsalve Diaz 
initAllRTLs()396313c5239SJose M Monsalve Diaz void RTLsTy::initAllRTLs() {
397313c5239SJose M Monsalve Diaz   for (auto &R : AllRTLs)
398313c5239SJose M Monsalve Diaz     initRTLonce(R);
399313c5239SJose M Monsalve Diaz }
400313c5239SJose M Monsalve Diaz 
registerLib(__tgt_bin_desc * Desc)401d27d0a67SJoseph Huber void RTLsTy::registerLib(__tgt_bin_desc *Desc) {
402313c5239SJose M Monsalve Diaz   PM->RTLsMtx.lock();
403fbcb1ee7SJoseph Huber 
404fbcb1ee7SJoseph Huber   // Extract the exectuable image and extra information if availible.
405fbcb1ee7SJoseph Huber   for (int32_t i = 0; i < Desc->NumDeviceImages; ++i)
406fbcb1ee7SJoseph Huber     PM->Images.emplace_back(getExecutableImage(&Desc->DeviceImages[i]),
407fbcb1ee7SJoseph Huber                             getImageInfo(&Desc->DeviceImages[i]));
408fbcb1ee7SJoseph Huber 
409313c5239SJose M Monsalve Diaz   // Register the images with the RTLs that understand them, if any.
410fbcb1ee7SJoseph Huber   for (auto &ImageAndInfo : PM->Images) {
411fbcb1ee7SJoseph Huber     // Obtain the image and information that was previously extracted.
412fbcb1ee7SJoseph Huber     __tgt_device_image *Img = &ImageAndInfo.first;
413fbcb1ee7SJoseph Huber     __tgt_image_info *Info = &ImageAndInfo.second;
414313c5239SJose M Monsalve Diaz 
415313c5239SJose M Monsalve Diaz     RTLInfoTy *FoundRTL = nullptr;
416313c5239SJose M Monsalve Diaz 
417313c5239SJose M Monsalve Diaz     // Scan the RTLs that have associated images until we find one that supports
418313c5239SJose M Monsalve Diaz     // the current image.
419313c5239SJose M Monsalve Diaz     for (auto &R : AllRTLs) {
420fbcb1ee7SJoseph Huber       if (R.is_valid_binary_info) {
421fbcb1ee7SJoseph Huber         if (!R.is_valid_binary_info(Img, Info)) {
422fbcb1ee7SJoseph Huber           DP("Image " DPxMOD " is NOT compatible with RTL %s!\n",
423fbcb1ee7SJoseph Huber              DPxPTR(Img->ImageStart), R.RTLName.c_str());
424fbcb1ee7SJoseph Huber           continue;
425fbcb1ee7SJoseph Huber         }
426fbcb1ee7SJoseph Huber       } else if (!R.is_valid_binary(Img)) {
427313c5239SJose M Monsalve Diaz         DP("Image " DPxMOD " is NOT compatible with RTL %s!\n",
428d27d0a67SJoseph Huber            DPxPTR(Img->ImageStart), R.RTLName.c_str());
429313c5239SJose M Monsalve Diaz         continue;
430313c5239SJose M Monsalve Diaz       }
431313c5239SJose M Monsalve Diaz 
432313c5239SJose M Monsalve Diaz       DP("Image " DPxMOD " is compatible with RTL %s!\n",
433d27d0a67SJoseph Huber          DPxPTR(Img->ImageStart), R.RTLName.c_str());
434313c5239SJose M Monsalve Diaz 
435313c5239SJose M Monsalve Diaz       initRTLonce(R);
43643322804SJonas Hahnfeld 
43743322804SJonas Hahnfeld       // Initialize (if necessary) translation table for this library.
438a95b25b2SAtmn Patel       PM->TrlTblMtx.lock();
439d27d0a67SJoseph Huber       if (!PM->HostEntriesBeginToTransTable.count(Desc->HostEntriesBegin)) {
440d27d0a67SJoseph Huber         PM->HostEntriesBeginRegistrationOrder.push_back(Desc->HostEntriesBegin);
441a95b25b2SAtmn Patel         TranslationTable &TransTable =
442d27d0a67SJoseph Huber             (PM->HostEntriesBeginToTransTable)[Desc->HostEntriesBegin];
443d27d0a67SJoseph Huber         TransTable.HostTable.EntriesBegin = Desc->HostEntriesBegin;
444d27d0a67SJoseph Huber         TransTable.HostTable.EntriesEnd = Desc->HostEntriesEnd;
44543322804SJonas Hahnfeld       }
44643322804SJonas Hahnfeld 
44743322804SJonas Hahnfeld       // Retrieve translation table for this library.
44843322804SJonas Hahnfeld       TranslationTable &TransTable =
449d27d0a67SJoseph Huber           (PM->HostEntriesBeginToTransTable)[Desc->HostEntriesBegin];
45043322804SJonas Hahnfeld 
451d27d0a67SJoseph Huber       DP("Registering image " DPxMOD " with RTL %s!\n", DPxPTR(Img->ImageStart),
4529cd1e222SJohannes Doerfert          R.RTLName.c_str());
453d27d0a67SJoseph Huber       registerImageIntoTranslationTable(TransTable, R, Img);
454a95b25b2SAtmn Patel       PM->TrlTblMtx.unlock();
45543322804SJonas Hahnfeld       FoundRTL = &R;
45643322804SJonas Hahnfeld 
45743322804SJonas Hahnfeld       // Load ctors/dtors for static objects
458d27d0a67SJoseph Huber       registerGlobalCtorsDtorsForImage(Desc, Img, FoundRTL);
45943322804SJonas Hahnfeld 
46043322804SJonas Hahnfeld       // if an RTL was found we are done - proceed to register the next image
46143322804SJonas Hahnfeld       break;
46243322804SJonas Hahnfeld     }
46343322804SJonas Hahnfeld 
46443322804SJonas Hahnfeld     if (!FoundRTL) {
465d27d0a67SJoseph Huber       DP("No RTL found for image " DPxMOD "!\n", DPxPTR(Img->ImageStart));
46643322804SJonas Hahnfeld     }
46743322804SJonas Hahnfeld   }
468a95b25b2SAtmn Patel   PM->RTLsMtx.unlock();
46943322804SJonas Hahnfeld 
47043322804SJonas Hahnfeld   DP("Done registering entries!\n");
47143322804SJonas Hahnfeld }
47243322804SJonas Hahnfeld 
unregisterLib(__tgt_bin_desc * Desc)473d27d0a67SJoseph Huber void RTLsTy::unregisterLib(__tgt_bin_desc *Desc) {
47443322804SJonas Hahnfeld   DP("Unloading target library!\n");
47543322804SJonas Hahnfeld 
476a95b25b2SAtmn Patel   PM->RTLsMtx.lock();
47743322804SJonas Hahnfeld   // Find which RTL understands each image, if any.
478fbcb1ee7SJoseph Huber   for (auto &ImageAndInfo : PM->Images) {
479fbcb1ee7SJoseph Huber     // Obtain the image and information that was previously extracted.
480fbcb1ee7SJoseph Huber     __tgt_device_image *Img = &ImageAndInfo.first;
481fbcb1ee7SJoseph Huber     __tgt_image_info *Info = &ImageAndInfo.second;
48243322804SJonas Hahnfeld 
48343322804SJonas Hahnfeld     RTLInfoTy *FoundRTL = NULL;
48443322804SJonas Hahnfeld 
48543322804SJonas Hahnfeld     // Scan the RTLs that have associated images until we find one that supports
48643322804SJonas Hahnfeld     // the current image. We only need to scan RTLs that are already being used.
48763cef621SAlexey Bataev     for (auto *R : UsedRTLs) {
48843322804SJonas Hahnfeld 
489d27d0a67SJoseph Huber       assert(R->IsUsed && "Expecting used RTLs.");
49043322804SJonas Hahnfeld 
491fbcb1ee7SJoseph Huber       if (R->is_valid_binary_info) {
492fbcb1ee7SJoseph Huber         if (!R->is_valid_binary_info(Img, Info)) {
493fbcb1ee7SJoseph Huber           DP("Image " DPxMOD " is NOT compatible with RTL %s!\n",
494fbcb1ee7SJoseph Huber              DPxPTR(Img->ImageStart), R->RTLName.c_str());
495fbcb1ee7SJoseph Huber           continue;
496fbcb1ee7SJoseph Huber         }
497fbcb1ee7SJoseph Huber       } else if (!R->is_valid_binary(Img)) {
498fbcb1ee7SJoseph Huber         DP("Image " DPxMOD " is NOT compatible with RTL %s!\n",
499fbcb1ee7SJoseph Huber            DPxPTR(Img->ImageStart), R->RTLName.c_str());
50043322804SJonas Hahnfeld         continue;
50143322804SJonas Hahnfeld       }
50243322804SJonas Hahnfeld 
50343322804SJonas Hahnfeld       DP("Image " DPxMOD " is compatible with RTL " DPxMOD "!\n",
504d27d0a67SJoseph Huber          DPxPTR(Img->ImageStart), DPxPTR(R->LibraryHandler));
50543322804SJonas Hahnfeld 
50643322804SJonas Hahnfeld       FoundRTL = R;
50743322804SJonas Hahnfeld 
50843322804SJonas Hahnfeld       // Execute dtors for static objects if the device has been used, i.e.
50943322804SJonas Hahnfeld       // if its PendingCtors list has been emptied.
510d27d0a67SJoseph Huber       for (int32_t I = 0; I < FoundRTL->NumberOfDevices; ++I) {
511d27d0a67SJoseph Huber         DeviceTy &Device = *PM->Devices[FoundRTL->Idx + I];
51243322804SJonas Hahnfeld         Device.PendingGlobalsMtx.lock();
513d27d0a67SJoseph Huber         if (Device.PendingCtorsDtors[Desc].PendingCtors.empty()) {
514758b8499SJohannes Doerfert           AsyncInfoTy AsyncInfo(Device);
515d27d0a67SJoseph Huber           for (auto &Dtor : Device.PendingCtorsDtors[Desc].PendingDtors) {
516d27d0a67SJoseph Huber             int Rc = target(nullptr, Device, Dtor, 0, nullptr, nullptr, nullptr,
517c9353eb4SJoseph Huber                             nullptr, nullptr, nullptr, 1, 1, 0, true /*team*/,
518758b8499SJohannes Doerfert                             AsyncInfo);
519d27d0a67SJoseph Huber             if (Rc != OFFLOAD_SUCCESS) {
520d27d0a67SJoseph Huber               DP("Running destructor " DPxMOD " failed.\n", DPxPTR(Dtor));
52143322804SJonas Hahnfeld             }
52243322804SJonas Hahnfeld           }
52343322804SJonas Hahnfeld           // Remove this library's entry from PendingCtorsDtors
524d27d0a67SJoseph Huber           Device.PendingCtorsDtors.erase(Desc);
525758b8499SJohannes Doerfert           // All constructors have been issued, wait for them now.
526758b8499SJohannes Doerfert           if (AsyncInfo.synchronize() != OFFLOAD_SUCCESS)
527758b8499SJohannes Doerfert             DP("Failed synchronizing destructors kernels.\n");
52843322804SJonas Hahnfeld         }
52943322804SJonas Hahnfeld         Device.PendingGlobalsMtx.unlock();
53043322804SJonas Hahnfeld       }
53143322804SJonas Hahnfeld 
53243322804SJonas Hahnfeld       DP("Unregistered image " DPxMOD " from RTL " DPxMOD "!\n",
533d27d0a67SJoseph Huber          DPxPTR(Img->ImageStart), DPxPTR(R->LibraryHandler));
53443322804SJonas Hahnfeld 
53543322804SJonas Hahnfeld       break;
53643322804SJonas Hahnfeld     }
53743322804SJonas Hahnfeld 
53843322804SJonas Hahnfeld     // if no RTL was found proceed to unregister the next image
53943322804SJonas Hahnfeld     if (!FoundRTL) {
54043322804SJonas Hahnfeld       DP("No RTLs in use support the image " DPxMOD "!\n",
541d27d0a67SJoseph Huber          DPxPTR(Img->ImageStart));
54243322804SJonas Hahnfeld     }
54343322804SJonas Hahnfeld   }
544a95b25b2SAtmn Patel   PM->RTLsMtx.unlock();
54543322804SJonas Hahnfeld   DP("Done unregistering images!\n");
54643322804SJonas Hahnfeld 
547a95b25b2SAtmn Patel   // Remove entries from PM->HostPtrToTableMap
548a95b25b2SAtmn Patel   PM->TblMapMtx.lock();
549d27d0a67SJoseph Huber   for (__tgt_offload_entry *Cur = Desc->HostEntriesBegin;
550d27d0a67SJoseph Huber        Cur < Desc->HostEntriesEnd; ++Cur) {
551d27d0a67SJoseph Huber     PM->HostPtrToTableMap.erase(Cur->addr);
55243322804SJonas Hahnfeld   }
55343322804SJonas Hahnfeld 
55443322804SJonas Hahnfeld   // Remove translation table for this descriptor.
5559cd1e222SJohannes Doerfert   auto TransTable =
556d27d0a67SJoseph Huber       PM->HostEntriesBeginToTransTable.find(Desc->HostEntriesBegin);
557a95b25b2SAtmn Patel   if (TransTable != PM->HostEntriesBeginToTransTable.end()) {
55843322804SJonas Hahnfeld     DP("Removing translation table for descriptor " DPxMOD "\n",
559d27d0a67SJoseph Huber        DPxPTR(Desc->HostEntriesBegin));
560a95b25b2SAtmn Patel     PM->HostEntriesBeginToTransTable.erase(TransTable);
56143322804SJonas Hahnfeld   } else {
56243322804SJonas Hahnfeld     DP("Translation table for descriptor " DPxMOD " cannot be found, probably "
5639cd1e222SJohannes Doerfert        "it has been already removed.\n",
564d27d0a67SJoseph Huber        DPxPTR(Desc->HostEntriesBegin));
56543322804SJonas Hahnfeld   }
56643322804SJonas Hahnfeld 
567a95b25b2SAtmn Patel   PM->TblMapMtx.unlock();
56843322804SJonas Hahnfeld 
56943322804SJonas Hahnfeld   // TODO: Write some RTL->unload_image(...) function?
570*046d5b91SJoseph Huber   for (auto *R : UsedRTLs) {
571*046d5b91SJoseph Huber     if (R->deinit_plugin) {
572*046d5b91SJoseph Huber       if (R->deinit_plugin() != OFFLOAD_SUCCESS) {
573*046d5b91SJoseph Huber         DP("Failure deinitializing RTL %s!\n", R->RTLName.c_str());
574*046d5b91SJoseph Huber       }
575*046d5b91SJoseph Huber     }
576*046d5b91SJoseph Huber   }
57743322804SJonas Hahnfeld 
57843322804SJonas Hahnfeld   DP("Done unregistering library!\n");
57943322804SJonas Hahnfeld }
580