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