xref: /llvm-project/offload/src/PluginManager.cpp (revision 13dcc95dcd4999ff99f2de89d881f1aed5b21709)
1330d8983SJohannes Doerfert //===-- PluginManager.cpp - Plugin loading and communication API ---------===//
2330d8983SJohannes Doerfert //
3330d8983SJohannes Doerfert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4330d8983SJohannes Doerfert // See https://llvm.org/LICENSE.txt for license information.
5330d8983SJohannes Doerfert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6330d8983SJohannes Doerfert //
7330d8983SJohannes Doerfert //===----------------------------------------------------------------------===//
8330d8983SJohannes Doerfert //
9330d8983SJohannes Doerfert // Functionality for handling plugins.
10330d8983SJohannes Doerfert //
11330d8983SJohannes Doerfert //===----------------------------------------------------------------------===//
12330d8983SJohannes Doerfert 
13330d8983SJohannes Doerfert #include "PluginManager.h"
14330d8983SJohannes Doerfert #include "Shared/Debug.h"
15330d8983SJohannes Doerfert #include "Shared/Profile.h"
167102592aSJohannes Doerfert #include "device.h"
17330d8983SJohannes Doerfert 
18330d8983SJohannes Doerfert #include "llvm/Support/Error.h"
19330d8983SJohannes Doerfert #include "llvm/Support/ErrorHandling.h"
20330d8983SJohannes Doerfert #include <memory>
21330d8983SJohannes Doerfert 
22330d8983SJohannes Doerfert using namespace llvm;
23330d8983SJohannes Doerfert using namespace llvm::sys;
24330d8983SJohannes Doerfert 
25330d8983SJohannes Doerfert PluginManager *PM = nullptr;
26330d8983SJohannes Doerfert 
27fa9e90f5SJoseph Huber // Every plugin exports this method to create an instance of the plugin type.
28fa9e90f5SJoseph Huber #define PLUGIN_TARGET(Name) extern "C" GenericPluginTy *createPlugin_##Name();
29fa9e90f5SJoseph Huber #include "Shared/Targets.def"
30330d8983SJohannes Doerfert 
31330d8983SJohannes Doerfert void PluginManager::init() {
32330d8983SJohannes Doerfert   TIMESCOPE();
33330d8983SJohannes Doerfert   DP("Loading RTLs...\n");
34330d8983SJohannes Doerfert 
35fa9e90f5SJoseph Huber   // Attempt to create an instance of each supported plugin.
36b07177fbSJoseph Huber #define PLUGIN_TARGET(Name)                                                    \
37b07177fbSJoseph Huber   do {                                                                         \
3821f3a609SJoseph Huber     Plugins.emplace_back(                                                      \
3921f3a609SJoseph Huber         std::unique_ptr<GenericPluginTy>(createPlugin_##Name()));              \
40b07177fbSJoseph Huber   } while (false);
41b07177fbSJoseph Huber #include "Shared/Targets.def"
42330d8983SJohannes Doerfert 
43330d8983SJohannes Doerfert   DP("RTLs loaded!\n");
44330d8983SJohannes Doerfert }
45330d8983SJohannes Doerfert 
46fa9e90f5SJoseph Huber void PluginManager::deinit() {
47fa9e90f5SJoseph Huber   TIMESCOPE();
48fa9e90f5SJoseph Huber   DP("Unloading RTLs...\n");
49fa9e90f5SJoseph Huber 
50fa9e90f5SJoseph Huber   for (auto &Plugin : Plugins) {
51435aa766SJoseph Huber     if (!Plugin->is_initialized())
52435aa766SJoseph Huber       continue;
53435aa766SJoseph Huber 
54fa9e90f5SJoseph Huber     if (auto Err = Plugin->deinit()) {
55fa9e90f5SJoseph Huber       [[maybe_unused]] std::string InfoMsg = toString(std::move(Err));
56fa9e90f5SJoseph Huber       DP("Failed to deinit plugin: %s\n", InfoMsg.c_str());
57fa9e90f5SJoseph Huber     }
58fa9e90f5SJoseph Huber     Plugin.release();
59fa9e90f5SJoseph Huber   }
60fa9e90f5SJoseph Huber 
61fa9e90f5SJoseph Huber   DP("RTLs unloaded!\n");
62fa9e90f5SJoseph Huber }
63fa9e90f5SJoseph Huber 
647102592aSJohannes Doerfert bool PluginManager::initializePlugin(GenericPluginTy &Plugin) {
657102592aSJohannes Doerfert   if (Plugin.is_initialized())
667102592aSJohannes Doerfert     return true;
677102592aSJohannes Doerfert 
687102592aSJohannes Doerfert   if (auto Err = Plugin.init()) {
69435aa766SJoseph Huber     [[maybe_unused]] std::string InfoMsg = toString(std::move(Err));
70435aa766SJoseph Huber     DP("Failed to init plugin: %s\n", InfoMsg.c_str());
717102592aSJohannes Doerfert     return false;
72330d8983SJohannes Doerfert   }
737102592aSJohannes Doerfert 
747102592aSJohannes Doerfert   DP("Registered plugin %s with %d visible device(s)\n", Plugin.getName(),
757102592aSJohannes Doerfert      Plugin.number_of_devices());
767102592aSJohannes Doerfert   return true;
777102592aSJohannes Doerfert }
787102592aSJohannes Doerfert 
797102592aSJohannes Doerfert bool PluginManager::initializeDevice(GenericPluginTy &Plugin,
807102592aSJohannes Doerfert                                      int32_t DeviceId) {
81ff12c006SJohannes Doerfert   if (Plugin.is_device_initialized(DeviceId)) {
82ff12c006SJohannes Doerfert     auto ExclusiveDevicesAccessor = getExclusiveDevicesAccessor();
83ff12c006SJohannes Doerfert     (*ExclusiveDevicesAccessor)[PM->DeviceIds[std::make_pair(&Plugin,
84ff12c006SJohannes Doerfert                                                              DeviceId)]]
85ff12c006SJohannes Doerfert         ->setHasPendingImages(true);
867102592aSJohannes Doerfert     return true;
87ff12c006SJohannes Doerfert   }
887102592aSJohannes Doerfert 
897102592aSJohannes Doerfert   // Initialize the device information for the RTL we are about to use.
907102592aSJohannes Doerfert   auto ExclusiveDevicesAccessor = getExclusiveDevicesAccessor();
917102592aSJohannes Doerfert 
927102592aSJohannes Doerfert   int32_t UserId = ExclusiveDevicesAccessor->size();
937102592aSJohannes Doerfert 
947102592aSJohannes Doerfert   // Set the device identifier offset in the plugin.
957102592aSJohannes Doerfert #ifdef OMPT_SUPPORT
967102592aSJohannes Doerfert   Plugin.set_device_identifier(UserId, DeviceId);
977102592aSJohannes Doerfert #endif
987102592aSJohannes Doerfert 
997102592aSJohannes Doerfert   auto Device = std::make_unique<DeviceTy>(&Plugin, UserId, DeviceId);
1007102592aSJohannes Doerfert   if (auto Err = Device->init()) {
1017102592aSJohannes Doerfert     [[maybe_unused]] std::string InfoMsg = toString(std::move(Err));
1027102592aSJohannes Doerfert     DP("Failed to init device %d: %s\n", DeviceId, InfoMsg.c_str());
1037102592aSJohannes Doerfert     return false;
1047102592aSJohannes Doerfert   }
1057102592aSJohannes Doerfert 
1067102592aSJohannes Doerfert   ExclusiveDevicesAccessor->push_back(std::move(Device));
1077102592aSJohannes Doerfert 
1087102592aSJohannes Doerfert   // We need to map between the plugin's device identifier and the one
1097102592aSJohannes Doerfert   // that OpenMP will use.
1107102592aSJohannes Doerfert   PM->DeviceIds[std::make_pair(&Plugin, DeviceId)] = UserId;
1117102592aSJohannes Doerfert 
1127102592aSJohannes Doerfert   return true;
1137102592aSJohannes Doerfert }
1147102592aSJohannes Doerfert 
1157102592aSJohannes Doerfert void PluginManager::initializeAllDevices() {
1167102592aSJohannes Doerfert   for (auto &Plugin : plugins()) {
1177102592aSJohannes Doerfert     if (!initializePlugin(Plugin))
1187102592aSJohannes Doerfert       continue;
1197102592aSJohannes Doerfert 
1207102592aSJohannes Doerfert     for (int32_t DeviceId = 0; DeviceId < Plugin.number_of_devices();
1217102592aSJohannes Doerfert          ++DeviceId) {
1227102592aSJohannes Doerfert       initializeDevice(Plugin, DeviceId);
1237102592aSJohannes Doerfert     }
124330d8983SJohannes Doerfert   }
125330d8983SJohannes Doerfert }
126330d8983SJohannes Doerfert 
127*13dcc95dSJoseph Huber // Returns a pointer to the binary descriptor, upgrading from a legacy format if
128*13dcc95dSJoseph Huber // necessary.
129*13dcc95dSJoseph Huber __tgt_bin_desc *PluginManager::upgradeLegacyEntries(__tgt_bin_desc *Desc) {
130*13dcc95dSJoseph Huber   struct LegacyEntryTy {
131*13dcc95dSJoseph Huber     void *Address;
132*13dcc95dSJoseph Huber     char *SymbolName;
133*13dcc95dSJoseph Huber     size_t Size;
134*13dcc95dSJoseph Huber     int32_t Flags;
135*13dcc95dSJoseph Huber     int32_t Data;
136*13dcc95dSJoseph Huber   };
137*13dcc95dSJoseph Huber 
138*13dcc95dSJoseph Huber   if (UpgradedDescriptors.contains(Desc))
139*13dcc95dSJoseph Huber     return &UpgradedDescriptors[Desc];
140*13dcc95dSJoseph Huber 
141*13dcc95dSJoseph Huber   if (Desc->HostEntriesBegin == Desc->HostEntriesEnd ||
142*13dcc95dSJoseph Huber       Desc->HostEntriesBegin->Reserved == 0)
143*13dcc95dSJoseph Huber     return Desc;
144*13dcc95dSJoseph Huber 
145*13dcc95dSJoseph Huber   // The new format mandates that each entry starts with eight bytes of zeroes.
146*13dcc95dSJoseph Huber   // This allows us to detect the old format as this is a null pointer.
147*13dcc95dSJoseph Huber   llvm::SmallVector<llvm::offloading::EntryTy, 0> &NewEntries =
148*13dcc95dSJoseph Huber       LegacyEntries.emplace_back();
149*13dcc95dSJoseph Huber   for (LegacyEntryTy &Entry : llvm::make_range(
150*13dcc95dSJoseph Huber            reinterpret_cast<LegacyEntryTy *>(Desc->HostEntriesBegin),
151*13dcc95dSJoseph Huber            reinterpret_cast<LegacyEntryTy *>(Desc->HostEntriesEnd))) {
152*13dcc95dSJoseph Huber     llvm::offloading::EntryTy &NewEntry = NewEntries.emplace_back();
153*13dcc95dSJoseph Huber 
154*13dcc95dSJoseph Huber     NewEntry.Address = Entry.Address;
155*13dcc95dSJoseph Huber     NewEntry.Flags = Entry.Flags;
156*13dcc95dSJoseph Huber     NewEntry.Data = Entry.Data;
157*13dcc95dSJoseph Huber     NewEntry.Size = Entry.Size;
158*13dcc95dSJoseph Huber     NewEntry.SymbolName = Entry.SymbolName;
159*13dcc95dSJoseph Huber   }
160*13dcc95dSJoseph Huber 
161*13dcc95dSJoseph Huber   // Create a new image struct so we can update the entries list.
162*13dcc95dSJoseph Huber   llvm::SmallVector<__tgt_device_image, 0> &NewImages =
163*13dcc95dSJoseph Huber       LegacyImages.emplace_back();
164*13dcc95dSJoseph Huber   for (int32_t Image = 0; Image < Desc->NumDeviceImages; ++Image)
165*13dcc95dSJoseph Huber     NewImages.emplace_back(
166*13dcc95dSJoseph Huber         __tgt_device_image{Desc->DeviceImages[Image].ImageStart,
167*13dcc95dSJoseph Huber                            Desc->DeviceImages[Image].ImageEnd,
168*13dcc95dSJoseph Huber                            NewEntries.begin(), NewEntries.end()});
169*13dcc95dSJoseph Huber 
170*13dcc95dSJoseph Huber   // Create the new binary descriptor containing the newly created memory.
171*13dcc95dSJoseph Huber   __tgt_bin_desc &NewDesc = UpgradedDescriptors[Desc];
172*13dcc95dSJoseph Huber   NewDesc.DeviceImages = NewImages.begin();
173*13dcc95dSJoseph Huber   NewDesc.NumDeviceImages = Desc->NumDeviceImages;
174*13dcc95dSJoseph Huber   NewDesc.HostEntriesBegin = NewEntries.begin();
175*13dcc95dSJoseph Huber   NewDesc.HostEntriesEnd = NewEntries.end();
176*13dcc95dSJoseph Huber 
177*13dcc95dSJoseph Huber   return &NewDesc;
178*13dcc95dSJoseph Huber }
179*13dcc95dSJoseph Huber 
180330d8983SJohannes Doerfert void PluginManager::registerLib(__tgt_bin_desc *Desc) {
181330d8983SJohannes Doerfert   PM->RTLsMtx.lock();
182330d8983SJohannes Doerfert 
183*13dcc95dSJoseph Huber   // Upgrade the entries from the legacy implementation if necessary.
184*13dcc95dSJoseph Huber   Desc = upgradeLegacyEntries(Desc);
185*13dcc95dSJoseph Huber 
186330d8983SJohannes Doerfert   // Add in all the OpenMP requirements associated with this binary.
1876518b121SJoseph Huber   for (llvm::offloading::EntryTy &Entry :
188330d8983SJohannes Doerfert        llvm::make_range(Desc->HostEntriesBegin, Desc->HostEntriesEnd))
1896518b121SJoseph Huber     if (Entry.Flags == OMP_REGISTER_REQUIRES)
1906518b121SJoseph Huber       PM->addRequirements(Entry.Data);
191330d8983SJohannes Doerfert 
192330d8983SJohannes Doerfert   // Extract the exectuable image and extra information if availible.
193330d8983SJohannes Doerfert   for (int32_t i = 0; i < Desc->NumDeviceImages; ++i)
194330d8983SJohannes Doerfert     PM->addDeviceImage(*Desc, Desc->DeviceImages[i]);
195330d8983SJohannes Doerfert 
196330d8983SJohannes Doerfert   // Register the images with the RTLs that understand them, if any.
197330d8983SJohannes Doerfert   for (DeviceImageTy &DI : PM->deviceImages()) {
198330d8983SJohannes Doerfert     // Obtain the image and information that was previously extracted.
199330d8983SJohannes Doerfert     __tgt_device_image *Img = &DI.getExecutableImage();
200330d8983SJohannes Doerfert 
201fa9e90f5SJoseph Huber     GenericPluginTy *FoundRTL = nullptr;
202330d8983SJohannes Doerfert 
203330d8983SJohannes Doerfert     // Scan the RTLs that have associated images until we find one that supports
204330d8983SJohannes Doerfert     // the current image.
2057102592aSJohannes Doerfert     for (auto &R : plugins()) {
206435aa766SJoseph Huber       if (!R.is_plugin_compatible(Img))
207fa9e90f5SJoseph Huber         continue;
208fa9e90f5SJoseph Huber 
2097102592aSJohannes Doerfert       if (!initializePlugin(R))
210435aa766SJoseph Huber         continue;
211435aa766SJoseph Huber 
212435aa766SJoseph Huber       if (!R.number_of_devices()) {
213435aa766SJoseph Huber         DP("Skipping plugin %s with no visible devices\n", R.getName());
214330d8983SJohannes Doerfert         continue;
215330d8983SJohannes Doerfert       }
216330d8983SJohannes Doerfert 
217435aa766SJoseph Huber       for (int32_t DeviceId = 0; DeviceId < R.number_of_devices(); ++DeviceId) {
218435aa766SJoseph Huber         if (!R.is_device_compatible(DeviceId, Img))
219435aa766SJoseph Huber           continue;
220330d8983SJohannes Doerfert 
221435aa766SJoseph Huber         DP("Image " DPxMOD " is compatible with RTL %s device %d!\n",
222435aa766SJoseph Huber            DPxPTR(Img->ImageStart), R.getName(), DeviceId);
223435aa766SJoseph Huber 
2247102592aSJohannes Doerfert         if (!initializeDevice(R, DeviceId))
225435aa766SJoseph Huber           continue;
226330d8983SJohannes Doerfert 
227330d8983SJohannes Doerfert         // Initialize (if necessary) translation table for this library.
228330d8983SJohannes Doerfert         PM->TrlTblMtx.lock();
229330d8983SJohannes Doerfert         if (!PM->HostEntriesBeginToTransTable.count(Desc->HostEntriesBegin)) {
230435aa766SJoseph Huber           PM->HostEntriesBeginRegistrationOrder.push_back(
231435aa766SJoseph Huber               Desc->HostEntriesBegin);
232435aa766SJoseph Huber           TranslationTable &TT =
233330d8983SJohannes Doerfert               (PM->HostEntriesBeginToTransTable)[Desc->HostEntriesBegin];
234435aa766SJoseph Huber           TT.HostTable.EntriesBegin = Desc->HostEntriesBegin;
235435aa766SJoseph Huber           TT.HostTable.EntriesEnd = Desc->HostEntriesEnd;
236330d8983SJohannes Doerfert         }
237330d8983SJohannes Doerfert 
238330d8983SJohannes Doerfert         // Retrieve translation table for this library.
239435aa766SJoseph Huber         TranslationTable &TT =
240330d8983SJohannes Doerfert             (PM->HostEntriesBeginToTransTable)[Desc->HostEntriesBegin];
241330d8983SJohannes Doerfert 
242435aa766SJoseph Huber         DP("Registering image " DPxMOD " with RTL %s!\n",
243435aa766SJoseph Huber            DPxPTR(Img->ImageStart), R.getName());
244330d8983SJohannes Doerfert 
245435aa766SJoseph Huber         auto UserId = PM->DeviceIds[std::make_pair(&R, DeviceId)];
246435aa766SJoseph Huber         if (TT.TargetsTable.size() < static_cast<size_t>(UserId + 1)) {
247435aa766SJoseph Huber           TT.DeviceTables.resize(UserId + 1, {});
248435aa766SJoseph Huber           TT.TargetsImages.resize(UserId + 1, nullptr);
249435aa766SJoseph Huber           TT.TargetsEntries.resize(UserId + 1, {});
250435aa766SJoseph Huber           TT.TargetsTable.resize(UserId + 1, nullptr);
251435aa766SJoseph Huber         }
252435aa766SJoseph Huber 
253435aa766SJoseph Huber         // Register the image for this target type and invalidate the table.
254435aa766SJoseph Huber         TT.TargetsImages[UserId] = Img;
255435aa766SJoseph Huber         TT.TargetsTable[UserId] = nullptr;
256435aa766SJoseph Huber 
257330d8983SJohannes Doerfert         PM->UsedImages.insert(Img);
258330d8983SJohannes Doerfert         FoundRTL = &R;
259330d8983SJohannes Doerfert 
260435aa766SJoseph Huber         PM->TrlTblMtx.unlock();
261330d8983SJohannes Doerfert       }
262435aa766SJoseph Huber     }
263435aa766SJoseph Huber     if (!FoundRTL)
264330d8983SJohannes Doerfert       DP("No RTL found for image " DPxMOD "!\n", DPxPTR(Img->ImageStart));
265330d8983SJohannes Doerfert   }
266330d8983SJohannes Doerfert   PM->RTLsMtx.unlock();
267330d8983SJohannes Doerfert 
268435aa766SJoseph Huber   bool UseAutoZeroCopy = Plugins.size() > 0;
269435aa766SJoseph Huber 
270435aa766SJoseph Huber   auto ExclusiveDevicesAccessor = getExclusiveDevicesAccessor();
271435aa766SJoseph Huber   for (const auto &Device : *ExclusiveDevicesAccessor)
272435aa766SJoseph Huber     UseAutoZeroCopy &= Device->useAutoZeroCopy();
273435aa766SJoseph Huber 
274435aa766SJoseph Huber   // Auto Zero-Copy can only be currently triggered when the system is an
275435aa766SJoseph Huber   // homogeneous APU architecture without attached discrete GPUs.
276435aa766SJoseph Huber   // If all devices suggest to use it, change requirment flags to trigger
277435aa766SJoseph Huber   // zero-copy behavior when mapping memory.
278435aa766SJoseph Huber   if (UseAutoZeroCopy)
279435aa766SJoseph Huber     addRequirements(OMPX_REQ_AUTO_ZERO_COPY);
280435aa766SJoseph Huber 
281330d8983SJohannes Doerfert   DP("Done registering entries!\n");
282330d8983SJohannes Doerfert }
283330d8983SJohannes Doerfert 
284330d8983SJohannes Doerfert // Temporary forward declaration, old style CTor/DTor handling is going away.
285330d8983SJohannes Doerfert int target(ident_t *Loc, DeviceTy &Device, void *HostPtr,
286330d8983SJohannes Doerfert            KernelArgsTy &KernelArgs, AsyncInfoTy &AsyncInfo);
287330d8983SJohannes Doerfert 
288330d8983SJohannes Doerfert void PluginManager::unregisterLib(__tgt_bin_desc *Desc) {
289330d8983SJohannes Doerfert   DP("Unloading target library!\n");
290330d8983SJohannes Doerfert 
291*13dcc95dSJoseph Huber   Desc = upgradeLegacyEntries(Desc);
292*13dcc95dSJoseph Huber 
293330d8983SJohannes Doerfert   PM->RTLsMtx.lock();
294330d8983SJohannes Doerfert   // Find which RTL understands each image, if any.
295330d8983SJohannes Doerfert   for (DeviceImageTy &DI : PM->deviceImages()) {
296330d8983SJohannes Doerfert     // Obtain the image and information that was previously extracted.
297330d8983SJohannes Doerfert     __tgt_device_image *Img = &DI.getExecutableImage();
298330d8983SJohannes Doerfert 
299fa9e90f5SJoseph Huber     GenericPluginTy *FoundRTL = NULL;
300330d8983SJohannes Doerfert 
301330d8983SJohannes Doerfert     // Scan the RTLs that have associated images until we find one that supports
302330d8983SJohannes Doerfert     // the current image. We only need to scan RTLs that are already being used.
3037102592aSJohannes Doerfert     for (auto &R : plugins()) {
304435aa766SJoseph Huber       if (R.is_initialized())
305330d8983SJohannes Doerfert         continue;
306330d8983SJohannes Doerfert 
307330d8983SJohannes Doerfert       // Ensure that we do not use any unused images associated with this RTL.
308330d8983SJohannes Doerfert       if (!UsedImages.contains(Img))
309330d8983SJohannes Doerfert         continue;
310330d8983SJohannes Doerfert 
311330d8983SJohannes Doerfert       FoundRTL = &R;
312330d8983SJohannes Doerfert 
313fa9e90f5SJoseph Huber       DP("Unregistered image " DPxMOD " from RTL\n", DPxPTR(Img->ImageStart));
314330d8983SJohannes Doerfert 
315330d8983SJohannes Doerfert       break;
316330d8983SJohannes Doerfert     }
317330d8983SJohannes Doerfert 
318330d8983SJohannes Doerfert     // if no RTL was found proceed to unregister the next image
319330d8983SJohannes Doerfert     if (!FoundRTL) {
320330d8983SJohannes Doerfert       DP("No RTLs in use support the image " DPxMOD "!\n",
321330d8983SJohannes Doerfert          DPxPTR(Img->ImageStart));
322330d8983SJohannes Doerfert     }
323330d8983SJohannes Doerfert   }
324330d8983SJohannes Doerfert   PM->RTLsMtx.unlock();
325330d8983SJohannes Doerfert   DP("Done unregistering images!\n");
326330d8983SJohannes Doerfert 
327330d8983SJohannes Doerfert   // Remove entries from PM->HostPtrToTableMap
328330d8983SJohannes Doerfert   PM->TblMapMtx.lock();
3296518b121SJoseph Huber   for (llvm::offloading::EntryTy *Cur = Desc->HostEntriesBegin;
330330d8983SJohannes Doerfert        Cur < Desc->HostEntriesEnd; ++Cur) {
3316518b121SJoseph Huber     PM->HostPtrToTableMap.erase(Cur->Address);
332330d8983SJohannes Doerfert   }
333330d8983SJohannes Doerfert 
334330d8983SJohannes Doerfert   // Remove translation table for this descriptor.
335330d8983SJohannes Doerfert   auto TransTable =
336330d8983SJohannes Doerfert       PM->HostEntriesBeginToTransTable.find(Desc->HostEntriesBegin);
337330d8983SJohannes Doerfert   if (TransTable != PM->HostEntriesBeginToTransTable.end()) {
338330d8983SJohannes Doerfert     DP("Removing translation table for descriptor " DPxMOD "\n",
339330d8983SJohannes Doerfert        DPxPTR(Desc->HostEntriesBegin));
340330d8983SJohannes Doerfert     PM->HostEntriesBeginToTransTable.erase(TransTable);
341330d8983SJohannes Doerfert   } else {
342330d8983SJohannes Doerfert     DP("Translation table for descriptor " DPxMOD " cannot be found, probably "
343330d8983SJohannes Doerfert        "it has been already removed.\n",
344330d8983SJohannes Doerfert        DPxPTR(Desc->HostEntriesBegin));
345330d8983SJohannes Doerfert   }
346330d8983SJohannes Doerfert 
347330d8983SJohannes Doerfert   PM->TblMapMtx.unlock();
348330d8983SJohannes Doerfert 
349330d8983SJohannes Doerfert   DP("Done unregistering library!\n");
350330d8983SJohannes Doerfert }
351330d8983SJohannes Doerfert 
352ff12c006SJohannes Doerfert /// Map global data and execute pending ctors
353ff12c006SJohannes Doerfert static int loadImagesOntoDevice(DeviceTy &Device) {
354ff12c006SJohannes Doerfert   /*
355ff12c006SJohannes Doerfert    * Map global data
356ff12c006SJohannes Doerfert    */
357ff12c006SJohannes Doerfert   int32_t DeviceId = Device.DeviceID;
358ff12c006SJohannes Doerfert   int Rc = OFFLOAD_SUCCESS;
359ff12c006SJohannes Doerfert   {
360ff12c006SJohannes Doerfert     std::lock_guard<decltype(PM->TrlTblMtx)> LG(PM->TrlTblMtx);
361ff12c006SJohannes Doerfert     for (auto *HostEntriesBegin : PM->HostEntriesBeginRegistrationOrder) {
362ff12c006SJohannes Doerfert       TranslationTable *TransTable =
363ff12c006SJohannes Doerfert           &PM->HostEntriesBeginToTransTable[HostEntriesBegin];
364ff12c006SJohannes Doerfert       DP("Trans table %p : %p\n", TransTable->HostTable.EntriesBegin,
365ff12c006SJohannes Doerfert          TransTable->HostTable.EntriesEnd);
366ff12c006SJohannes Doerfert       if (TransTable->HostTable.EntriesBegin ==
367ff12c006SJohannes Doerfert           TransTable->HostTable.EntriesEnd) {
368ff12c006SJohannes Doerfert         // No host entry so no need to proceed
369ff12c006SJohannes Doerfert         continue;
370ff12c006SJohannes Doerfert       }
371ff12c006SJohannes Doerfert 
372ff12c006SJohannes Doerfert       if (TransTable->TargetsTable[DeviceId] != 0) {
373ff12c006SJohannes Doerfert         // Library entries have already been processed
374ff12c006SJohannes Doerfert         continue;
375ff12c006SJohannes Doerfert       }
376ff12c006SJohannes Doerfert 
377ff12c006SJohannes Doerfert       // 1) get image.
378ff12c006SJohannes Doerfert       assert(TransTable->TargetsImages.size() > (size_t)DeviceId &&
379ff12c006SJohannes Doerfert              "Not expecting a device ID outside the table's bounds!");
380ff12c006SJohannes Doerfert       __tgt_device_image *Img = TransTable->TargetsImages[DeviceId];
381ff12c006SJohannes Doerfert       if (!Img) {
382ff12c006SJohannes Doerfert         REPORT("No image loaded for device id %d.\n", DeviceId);
383ff12c006SJohannes Doerfert         Rc = OFFLOAD_FAIL;
384ff12c006SJohannes Doerfert         break;
385ff12c006SJohannes Doerfert       }
386ff12c006SJohannes Doerfert 
387ff12c006SJohannes Doerfert       // 2) Load the image onto the given device.
388ff12c006SJohannes Doerfert       auto BinaryOrErr = Device.loadBinary(Img);
389ff12c006SJohannes Doerfert       if (llvm::Error Err = BinaryOrErr.takeError()) {
390ff12c006SJohannes Doerfert         REPORT("Failed to load image %s\n",
391ff12c006SJohannes Doerfert                llvm::toString(std::move(Err)).c_str());
392ff12c006SJohannes Doerfert         Rc = OFFLOAD_FAIL;
393ff12c006SJohannes Doerfert         break;
394ff12c006SJohannes Doerfert       }
395ff12c006SJohannes Doerfert 
396ff12c006SJohannes Doerfert       // 3) Create the translation table.
3976518b121SJoseph Huber       llvm::SmallVector<llvm::offloading::EntryTy> &DeviceEntries =
398ff12c006SJohannes Doerfert           TransTable->TargetsEntries[DeviceId];
3996518b121SJoseph Huber       for (llvm::offloading::EntryTy &Entry :
400ff12c006SJohannes Doerfert            llvm::make_range(Img->EntriesBegin, Img->EntriesEnd)) {
401ff12c006SJohannes Doerfert         __tgt_device_binary &Binary = *BinaryOrErr;
402ff12c006SJohannes Doerfert 
4036518b121SJoseph Huber         llvm::offloading::EntryTy DeviceEntry = Entry;
4046518b121SJoseph Huber         if (Entry.Size) {
4056518b121SJoseph Huber           if (Device.RTL->get_global(Binary, Entry.Size, Entry.SymbolName,
4066518b121SJoseph Huber                                      &DeviceEntry.Address) != OFFLOAD_SUCCESS)
4076518b121SJoseph Huber             REPORT("Failed to load symbol %s\n", Entry.SymbolName);
408ff12c006SJohannes Doerfert 
409ff12c006SJohannes Doerfert           // If unified memory is active, the corresponding global is a device
410ff12c006SJohannes Doerfert           // reference to the host global. We need to initialize the pointer on
411ff12c006SJohannes Doerfert           // the device to point to the memory on the host.
412ff12c006SJohannes Doerfert           if ((PM->getRequirements() & OMP_REQ_UNIFIED_SHARED_MEMORY) ||
413ff12c006SJohannes Doerfert               (PM->getRequirements() & OMPX_REQ_AUTO_ZERO_COPY)) {
4146518b121SJoseph Huber             if (Device.RTL->data_submit(DeviceId, DeviceEntry.Address,
4156518b121SJoseph Huber                                         Entry.Address,
4166518b121SJoseph Huber                                         Entry.Size) != OFFLOAD_SUCCESS)
4176518b121SJoseph Huber               REPORT("Failed to write symbol for USM %s\n", Entry.SymbolName);
418ff12c006SJohannes Doerfert           }
4196518b121SJoseph Huber         } else if (Entry.Address) {
4206518b121SJoseph Huber           if (Device.RTL->get_function(Binary, Entry.SymbolName,
4216518b121SJoseph Huber                                        &DeviceEntry.Address) != OFFLOAD_SUCCESS)
4226518b121SJoseph Huber             REPORT("Failed to load kernel %s\n", Entry.SymbolName);
423ff12c006SJohannes Doerfert         }
424ff12c006SJohannes Doerfert         DP("Entry point " DPxMOD " maps to%s %s (" DPxMOD ")\n",
4256518b121SJoseph Huber            DPxPTR(Entry.Address), (Entry.Size) ? " global" : "",
4266518b121SJoseph Huber            Entry.SymbolName, DPxPTR(DeviceEntry.Address));
427ff12c006SJohannes Doerfert 
428ff12c006SJohannes Doerfert         DeviceEntries.emplace_back(DeviceEntry);
429ff12c006SJohannes Doerfert       }
430ff12c006SJohannes Doerfert 
431ff12c006SJohannes Doerfert       // Set the storage for the table and get a pointer to it.
432ff12c006SJohannes Doerfert       __tgt_target_table DeviceTable{&DeviceEntries[0],
433ff12c006SJohannes Doerfert                                      &DeviceEntries[0] + DeviceEntries.size()};
434ff12c006SJohannes Doerfert       TransTable->DeviceTables[DeviceId] = DeviceTable;
435ff12c006SJohannes Doerfert       __tgt_target_table *TargetTable = TransTable->TargetsTable[DeviceId] =
436ff12c006SJohannes Doerfert           &TransTable->DeviceTables[DeviceId];
437ff12c006SJohannes Doerfert 
438ff12c006SJohannes Doerfert       // 4) Verify whether the two table sizes match.
439ff12c006SJohannes Doerfert       size_t Hsize =
440ff12c006SJohannes Doerfert           TransTable->HostTable.EntriesEnd - TransTable->HostTable.EntriesBegin;
441ff12c006SJohannes Doerfert       size_t Tsize = TargetTable->EntriesEnd - TargetTable->EntriesBegin;
442ff12c006SJohannes Doerfert 
443ff12c006SJohannes Doerfert       // Invalid image for these host entries!
444ff12c006SJohannes Doerfert       if (Hsize != Tsize) {
445ff12c006SJohannes Doerfert         REPORT(
446ff12c006SJohannes Doerfert             "Host and Target tables mismatch for device id %d [%zx != %zx].\n",
447ff12c006SJohannes Doerfert             DeviceId, Hsize, Tsize);
448ff12c006SJohannes Doerfert         TransTable->TargetsImages[DeviceId] = 0;
449ff12c006SJohannes Doerfert         TransTable->TargetsTable[DeviceId] = 0;
450ff12c006SJohannes Doerfert         Rc = OFFLOAD_FAIL;
451ff12c006SJohannes Doerfert         break;
452ff12c006SJohannes Doerfert       }
453ff12c006SJohannes Doerfert 
454ff12c006SJohannes Doerfert       MappingInfoTy::HDTTMapAccessorTy HDTTMap =
455ff12c006SJohannes Doerfert           Device.getMappingInfo().HostDataToTargetMap.getExclusiveAccessor();
456ff12c006SJohannes Doerfert 
457ff12c006SJohannes Doerfert       __tgt_target_table *HostTable = &TransTable->HostTable;
4586518b121SJoseph Huber       for (llvm::offloading::EntryTy *
4596518b121SJoseph Huber                CurrDeviceEntry = TargetTable->EntriesBegin,
460ff12c006SJohannes Doerfert               *CurrHostEntry = HostTable->EntriesBegin,
461ff12c006SJohannes Doerfert               *EntryDeviceEnd = TargetTable->EntriesEnd;
462ff12c006SJohannes Doerfert            CurrDeviceEntry != EntryDeviceEnd;
463ff12c006SJohannes Doerfert            CurrDeviceEntry++, CurrHostEntry++) {
4646518b121SJoseph Huber         if (CurrDeviceEntry->Size == 0)
465ff12c006SJohannes Doerfert           continue;
466ff12c006SJohannes Doerfert 
4676518b121SJoseph Huber         assert(CurrDeviceEntry->Size == CurrHostEntry->Size &&
468ff12c006SJohannes Doerfert                "data size mismatch");
469ff12c006SJohannes Doerfert 
470ff12c006SJohannes Doerfert         // Fortran may use multiple weak declarations for the same symbol,
471ff12c006SJohannes Doerfert         // therefore we must allow for multiple weak symbols to be loaded from
472ff12c006SJohannes Doerfert         // the fat binary. Treat these mappings as any other "regular"
473ff12c006SJohannes Doerfert         // mapping. Add entry to map.
4746518b121SJoseph Huber         if (Device.getMappingInfo().getTgtPtrBegin(
4756518b121SJoseph Huber                 HDTTMap, CurrHostEntry->Address, CurrHostEntry->Size))
476ff12c006SJohannes Doerfert           continue;
477ff12c006SJohannes Doerfert 
4786518b121SJoseph Huber         void *CurrDeviceEntryAddr = CurrDeviceEntry->Address;
479ff12c006SJohannes Doerfert 
480ff12c006SJohannes Doerfert         // For indirect mapping, follow the indirection and map the actual
481ff12c006SJohannes Doerfert         // target.
4826518b121SJoseph Huber         if (CurrDeviceEntry->Flags & OMP_DECLARE_TARGET_INDIRECT) {
483ff12c006SJohannes Doerfert           AsyncInfoTy AsyncInfo(Device);
484ff12c006SJohannes Doerfert           void *DevPtr;
485ff12c006SJohannes Doerfert           Device.retrieveData(&DevPtr, CurrDeviceEntryAddr, sizeof(void *),
486ff12c006SJohannes Doerfert                               AsyncInfo, /*Entry=*/nullptr, &HDTTMap);
487ff12c006SJohannes Doerfert           if (AsyncInfo.synchronize() != OFFLOAD_SUCCESS)
488ff12c006SJohannes Doerfert             return OFFLOAD_FAIL;
489ff12c006SJohannes Doerfert           CurrDeviceEntryAddr = DevPtr;
490ff12c006SJohannes Doerfert         }
491ff12c006SJohannes Doerfert 
492ff12c006SJohannes Doerfert         DP("Add mapping from host " DPxMOD " to device " DPxMOD " with size %zu"
493ff12c006SJohannes Doerfert            ", name \"%s\"\n",
4946518b121SJoseph Huber            DPxPTR(CurrHostEntry->Address), DPxPTR(CurrDeviceEntry->Address),
4956518b121SJoseph Huber            CurrDeviceEntry->Size, CurrDeviceEntry->SymbolName);
496ff12c006SJohannes Doerfert         HDTTMap->emplace(new HostDataToTargetTy(
4976518b121SJoseph Huber             (uintptr_t)CurrHostEntry->Address /*HstPtrBase*/,
4986518b121SJoseph Huber             (uintptr_t)CurrHostEntry->Address /*HstPtrBegin*/,
4996518b121SJoseph Huber             (uintptr_t)CurrHostEntry->Address +
5006518b121SJoseph Huber                 CurrHostEntry->Size /*HstPtrEnd*/,
501ff12c006SJohannes Doerfert             (uintptr_t)CurrDeviceEntryAddr /*TgtAllocBegin*/,
502ff12c006SJohannes Doerfert             (uintptr_t)CurrDeviceEntryAddr /*TgtPtrBegin*/,
5036518b121SJoseph Huber             false /*UseHoldRefCount*/, CurrHostEntry->SymbolName,
504ff12c006SJohannes Doerfert             true /*IsRefCountINF*/));
505ff12c006SJohannes Doerfert 
506ff12c006SJohannes Doerfert         // Notify about the new mapping.
5076518b121SJoseph Huber         if (Device.notifyDataMapped(CurrHostEntry->Address,
5086518b121SJoseph Huber                                     CurrHostEntry->Size))
509ff12c006SJohannes Doerfert           return OFFLOAD_FAIL;
510ff12c006SJohannes Doerfert       }
511ff12c006SJohannes Doerfert     }
512ff12c006SJohannes Doerfert     Device.setHasPendingImages(false);
513ff12c006SJohannes Doerfert   }
514ff12c006SJohannes Doerfert 
515ff12c006SJohannes Doerfert   if (Rc != OFFLOAD_SUCCESS)
516ff12c006SJohannes Doerfert     return Rc;
517ff12c006SJohannes Doerfert 
518ff12c006SJohannes Doerfert   static Int32Envar DumpOffloadEntries =
519ff12c006SJohannes Doerfert       Int32Envar("OMPTARGET_DUMP_OFFLOAD_ENTRIES", -1);
520ff12c006SJohannes Doerfert   if (DumpOffloadEntries.get() == DeviceId)
521ff12c006SJohannes Doerfert     Device.dumpOffloadEntries();
522ff12c006SJohannes Doerfert 
523ff12c006SJohannes Doerfert   return OFFLOAD_SUCCESS;
524ff12c006SJohannes Doerfert }
525ff12c006SJohannes Doerfert 
526330d8983SJohannes Doerfert Expected<DeviceTy &> PluginManager::getDevice(uint32_t DeviceNo) {
527ff12c006SJohannes Doerfert   DeviceTy *DevicePtr;
528ff12c006SJohannes Doerfert   {
529330d8983SJohannes Doerfert     auto ExclusiveDevicesAccessor = getExclusiveDevicesAccessor();
530330d8983SJohannes Doerfert     if (DeviceNo >= ExclusiveDevicesAccessor->size())
531330d8983SJohannes Doerfert       return createStringError(
532330d8983SJohannes Doerfert           inconvertibleErrorCode(),
533ff12c006SJohannes Doerfert           "Device number '%i' out of range, only %i devices available",
534ff12c006SJohannes Doerfert           DeviceNo, ExclusiveDevicesAccessor->size());
535330d8983SJohannes Doerfert 
536ff12c006SJohannes Doerfert     DevicePtr = &*(*ExclusiveDevicesAccessor)[DeviceNo];
537ff12c006SJohannes Doerfert   }
538ff12c006SJohannes Doerfert 
539ff12c006SJohannes Doerfert   // Check whether global data has been mapped for this device
540ff12c006SJohannes Doerfert   if (DevicePtr->hasPendingImages())
541ff12c006SJohannes Doerfert     if (loadImagesOntoDevice(*DevicePtr) != OFFLOAD_SUCCESS)
542ff12c006SJohannes Doerfert       return createStringError(inconvertibleErrorCode(),
543ff12c006SJohannes Doerfert                                "Failed to load images on device '%i'",
544ff12c006SJohannes Doerfert                                DeviceNo);
545ff12c006SJohannes Doerfert   return *DevicePtr;
546330d8983SJohannes Doerfert }
547