diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -1601,71 +1601,79 @@ return CGM.CreateRuntimeFunction(FnTy, Name); } -/// Obtain information that uniquely identifies a target entry. This -/// consists of the file and device IDs as well as line number associated with -/// the relevant entry source location. -static llvm::TargetRegionEntryInfo -getTargetEntryUniqueInfo(ASTContext &C, SourceLocation Loc, - StringRef ParentName = "") { - SourceManager &SM = C.getSourceManager(); - - // The loc should be always valid and have a file ID (the user cannot use - // #pragma directives in macros) - - assert(Loc.isValid() && "Source location is expected to be always valid."); - - PresumedLoc PLoc = SM.getPresumedLoc(Loc); - assert(PLoc.isValid() && "Source location is expected to be always valid."); +llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseKind +convertDeviceClause(const VarDecl *VD) { + std::optional DevTy = + OMPDeclareTargetDeclAttr::getDeviceType(VD); + if (!DevTy) + return llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseNone; - llvm::sys::fs::UniqueID ID; - if (auto EC = llvm::sys::fs::getUniqueID(PLoc.getFilename(), ID)) { - PLoc = SM.getPresumedLoc(Loc, /*UseLineDirectives=*/false); - assert(PLoc.isValid() && "Source location is expected to be always valid."); - if (auto EC = llvm::sys::fs::getUniqueID(PLoc.getFilename(), ID)) - SM.getDiagnostics().Report(diag::err_cannot_open_file) - << PLoc.getFilename() << EC.message(); + switch (*DevTy) { + case OMPDeclareTargetDeclAttr::DT_Host: + return llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseHost; + break; + case OMPDeclareTargetDeclAttr::DT_NoHost: + return llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseNoHost; + break; + case OMPDeclareTargetDeclAttr::DT_Any: + return llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseAny; + break; + default: + return llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseNone; + break; } +} - return llvm::TargetRegionEntryInfo(ParentName, ID.getDevice(), ID.getFile(), - PLoc.getLine()); +llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryKind +convertCaptureClause(const VarDecl *VD) { + std::optional MapType = + OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD); + if (!MapType) + return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryNone; + switch (*MapType) { + case OMPDeclareTargetDeclAttr::MapTypeTy::MT_To: + return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryTo; + break; + case OMPDeclareTargetDeclAttr::MapTypeTy::MT_Enter: + return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryEnter; + break; + case OMPDeclareTargetDeclAttr::MapTypeTy::MT_Link: + return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryLink; + break; + default: + return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryNone; + break; + } } Address CGOpenMPRuntime::getAddrOfDeclareTargetVar(const VarDecl *VD) { - if (CGM.getLangOpts().OpenMPSimd) - return Address::invalid(); - std::optional Res = - OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD); - if (Res && (*Res == OMPDeclareTargetDeclAttr::MT_Link || - ((*Res == OMPDeclareTargetDeclAttr::MT_To || - *Res == OMPDeclareTargetDeclAttr::MT_Enter) && - HasRequiresUnifiedSharedMemory))) { - SmallString<64> PtrName; - { - llvm::raw_svector_ostream OS(PtrName); - OS << CGM.getMangledName(GlobalDecl(VD)); - if (!VD->isExternallyVisible()) { - auto EntryInfo = getTargetEntryUniqueInfo( - CGM.getContext(), VD->getCanonicalDecl()->getBeginLoc()); - OS << llvm::format("_%x", EntryInfo.FileID); - } - OS << "_decl_tgt_ref_ptr"; - } - llvm::Value *Ptr = CGM.getModule().getNamedValue(PtrName); - QualType PtrTy = CGM.getContext().getPointerType(VD->getType()); - llvm::Type *LlvmPtrTy = CGM.getTypes().ConvertTypeForMem(PtrTy); - if (!Ptr) { - Ptr = OMPBuilder.getOrCreateInternalVariable(LlvmPtrTy, PtrName); + auto AddrOfGlobal = [&VD, this]() { return CGM.GetAddrOfGlobal(VD); }; - auto *GV = cast(Ptr); - GV->setLinkage(llvm::GlobalValue::WeakAnyLinkage); + auto LinkageForVariable = [&VD, this]() { + return CGM.getLLVMLinkageVarDefinition(VD, /*IsConstant=*/false); + }; - if (!CGM.getLangOpts().OpenMPIsDevice) - GV->setInitializer(CGM.GetAddrOfGlobal(VD)); - registerTargetGlobalVariable(VD, cast(Ptr)); - } - return Address(Ptr, LlvmPtrTy, CGM.getContext().getDeclAlign(VD)); - } - return Address::invalid(); + std::vector GeneratedRefs; + auto PLoc = CGM.getContext().getSourceManager().getPresumedLoc( + VD->getCanonicalDecl()->getBeginLoc()); + if (PLoc.isInvalid()) + PLoc = CGM.getContext().getSourceManager().getPresumedLoc( + VD->getCanonicalDecl()->getBeginLoc(), /*UseLineDirectives=*/false); + + llvm::Type *LlvmPtrTy = CGM.getTypes().ConvertTypeForMem( + CGM.getContext().getPointerType(VD->getType())); + llvm::Constant *addr = OMPBuilder.getAddrOfDeclareTargetVar( + convertCaptureClause(VD), convertDeviceClause(VD), + VD->hasDefinition(CGM.getContext()) == VarDecl::DeclarationOnly, + VD->isExternallyVisible(), + OMPBuilder.getTargetEntryUniqueInfo(PLoc.getFilename(), PLoc.getLine()), + CGM.getMangledName(VD), &CGM.getModule(), GeneratedRefs, + CGM.getLangOpts().OpenMPSimd, CGM.getLangOpts().OMPTargetTriples, + LlvmPtrTy, AddrOfGlobal, LinkageForVariable); + + if (!addr) + return Address::invalid(); + return Address(addr, LlvmPtrTy, CGM.getContext().getDeclAlign(VD)); } llvm::Constant * @@ -1866,8 +1874,12 @@ // Produce the unique prefix to identify the new target regions. We use // the source location of the variable declaration which we know to not // conflict with any target region. - auto EntryInfo = - getTargetEntryUniqueInfo(CGM.getContext(), Loc, VD->getName()); + auto PLoc = CGM.getContext().getSourceManager().getPresumedLoc(Loc); + if (PLoc.isInvalid()) + PLoc = CGM.getContext().getSourceManager().getPresumedLoc( + Loc, /*UseLineDirectives=*/false); + auto EntryInfo = OMPBuilder. + getTargetEntryUniqueInfo(PLoc.getFilename(), PLoc.getLine(), VD->getName()); SmallString<128> Buffer, Out; OMPBuilder.OffloadInfoManager.getTargetRegionEntryFnName(Buffer, EntryInfo); @@ -6106,8 +6118,13 @@ llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID, bool IsOffloadEntry, const RegionCodeGenTy &CodeGen) { - auto EntryInfo = - getTargetEntryUniqueInfo(CGM.getContext(), D.getBeginLoc(), ParentName); + auto PLoc = + CGM.getContext().getSourceManager().getPresumedLoc(D.getBeginLoc()); + if (PLoc.isInvalid()) + PLoc = CGM.getContext().getSourceManager().getPresumedLoc( + D.getBeginLoc(), /*UseLineDirectives=*/false); + auto EntryInfo = OMPBuilder.getTargetEntryUniqueInfo( + PLoc.getFilename(), PLoc.getLine(), ParentName); CodeGenFunction CGF(CGM, true); llvm::OpenMPIRBuilder::FunctionGenCallback &&GenerateOutlinedFunction = @@ -10148,8 +10165,14 @@ if (RequiresDeviceCodegen) { const auto &E = *cast(S); - auto EntryInfo = - getTargetEntryUniqueInfo(CGM.getContext(), E.getBeginLoc(), ParentName); + + auto PLoc = + CGM.getContext().getSourceManager().getPresumedLoc(E.getBeginLoc()); + if (PLoc.isInvalid()) + PLoc = CGM.getContext().getSourceManager().getPresumedLoc( + E.getBeginLoc(), /*UseLineDirectives=*/false); + auto EntryInfo = OMPBuilder.getTargetEntryUniqueInfo( + PLoc.getFilename(), PLoc.getLine(), ParentName); // Is this a target region that should not be emitted as an entry point? If // so just signal we are done with this target region. @@ -10367,12 +10390,6 @@ !CGM.getLangOpts().OpenMPIsDevice) return; - // If we have host/nohost variables, they do not need to be registered. - std::optional DevTy = - OMPDeclareTargetDeclAttr::getDeviceType(VD); - if (DevTy && *DevTy != OMPDeclareTargetDeclAttr::DT_Any) - return; - std::optional Res = OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD); if (!Res) { @@ -10384,68 +10401,34 @@ } return; } - // Register declare target variables. - llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryKind Flags; - StringRef VarName; - int64_t VarSize; - llvm::GlobalValue::LinkageTypes Linkage; - - if ((*Res == OMPDeclareTargetDeclAttr::MT_To || - *Res == OMPDeclareTargetDeclAttr::MT_Enter) && - !HasRequiresUnifiedSharedMemory) { - Flags = llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryTo; - VarName = CGM.getMangledName(VD); - if (VD->hasDefinition(CGM.getContext()) != VarDecl::DeclarationOnly) { - VarSize = - CGM.getContext().getTypeSizeInChars(VD->getType()).getQuantity(); - assert(VarSize != 0 && "Expected non-zero size of the variable"); - } else { - VarSize = 0; - } - Linkage = CGM.getLLVMLinkageVarDefinition(VD, /*IsConstant=*/false); - // Temp solution to prevent optimizations of the internal variables. - if (CGM.getLangOpts().OpenMPIsDevice && - (!VD->isExternallyVisible() || - Linkage == llvm::GlobalValue::LinkOnceODRLinkage)) { - // Do not create a "ref-variable" if the original is not also available - // on the host. - if (!OMPBuilder.OffloadInfoManager.hasDeviceGlobalVarEntryInfo(VarName)) - return; - std::string RefName = getName({VarName, "ref"}); - if (!CGM.GetGlobalValue(RefName)) { - llvm::Constant *AddrRef = - OMPBuilder.getOrCreateInternalVariable(Addr->getType(), RefName); - auto *GVAddrRef = cast(AddrRef); - GVAddrRef->setConstant(/*Val=*/true); - GVAddrRef->setLinkage(llvm::GlobalValue::InternalLinkage); - GVAddrRef->setInitializer(Addr); - CGM.addCompilerUsedGlobal(GVAddrRef); - } - } - } else { - assert(((*Res == OMPDeclareTargetDeclAttr::MT_Link) || - ((*Res == OMPDeclareTargetDeclAttr::MT_To || - *Res == OMPDeclareTargetDeclAttr::MT_Enter) && - HasRequiresUnifiedSharedMemory)) && - "Declare target attribute must link or to with unified memory."); - if (*Res == OMPDeclareTargetDeclAttr::MT_Link) - Flags = llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryLink; - else - Flags = llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryTo; - if (CGM.getLangOpts().OpenMPIsDevice) { - VarName = Addr->getName(); - Addr = nullptr; - } else { - VarName = getAddrOfDeclareTargetVar(VD).getName(); - Addr = cast(getAddrOfDeclareTargetVar(VD).getPointer()); - } - VarSize = CGM.getPointerSize().getQuantity(); - Linkage = llvm::GlobalValue::WeakAnyLinkage; - } + auto AddrOfGlobal = [&VD, this]() { return CGM.GetAddrOfGlobal(VD); }; + auto LinkageForVariable = [&VD, this]() { + return CGM.getLLVMLinkageVarDefinition(VD, /*IsConstant=*/false); + }; - OMPBuilder.OffloadInfoManager.registerDeviceGlobalVarEntryInfo( - VarName, Addr, VarSize, Flags, Linkage); + std::vector GeneratedRefs; + auto PLoc = + CGM.getContext().getSourceManager().getPresumedLoc(VD->getCanonicalDecl()->getBeginLoc()); + if (PLoc.isInvalid()) + PLoc = CGM.getContext().getSourceManager().getPresumedLoc( + VD->getCanonicalDecl()->getBeginLoc(), /*UseLineDirectives=*/false); + OMPBuilder.registerTargetGlobalVariable( + convertCaptureClause(VD), convertDeviceClause(VD), + VD->hasDefinition(CGM.getContext()) == VarDecl::DeclarationOnly, + VD->isExternallyVisible(), + OMPBuilder.getTargetEntryUniqueInfo(PLoc.getFilename(), PLoc.getLine()), + CGM.getMangledName(VD), &CGM.getModule(), GeneratedRefs, + CGM.getLangOpts().OpenMPSimd, CGM.getLangOpts().OMPTargetTriples, + AddrOfGlobal, LinkageForVariable, + CGM.getTypes().ConvertTypeForMem( + CGM.getContext().getPointerType(VD->getType())), + Addr); + + for (auto *ref : GeneratedRefs) + CGM.addCompilerUsedGlobal(ref); + + return; } bool CGOpenMPRuntime::emitTargetGlobal(GlobalDecl GD) { diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h --- a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h +++ b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h @@ -323,6 +323,26 @@ OMPTargetGlobalVarEntryTo = 0x0, /// Mark the entry as a to declare target link. OMPTargetGlobalVarEntryLink = 0x1, + /// Mark the entry as a declare target enter. + OMPTargetGlobalVarEntryEnter = 0x2, + /// Mark the entry as having no declare target entry kind. + OMPTargetGlobalVarEntryNone = 0x3, + }; + + /// Kind of device clause for declare target variables + /// and functions + /// NOTE: Currently not used as a part of a variable entry + /// used for Flang and Clang to interface with the variable + /// related registration functions + enum OMPTargetDeviceClauseKind : uint32_t { + /// The target is marked for all devices + OMPTargetDeviceClauseAny = 0x0, + /// The target is marked for non-host devices + OMPTargetDeviceClauseNoHost = 0x1, + /// The target is marked for host devices + OMPTargetDeviceClauseHost = 0x2, + /// The target is marked as having no clause + OMPTargetDeviceClauseNone = 0x3 }; /// Device global variable entries info. @@ -755,6 +775,99 @@ static unsigned getOpenMPDefaultSimdAlign(const Triple &TargetTriple, const StringMap &Features); + /// Retrieve (or create if non-existent) the address of a declare + /// target variable, used in conjunction with registerTargetGlobalVariable + /// to create declare target global variables. + /// + /// \param CaptureClause - enumerator corresponding to the OpenMP capture + /// clause used in conjunction with the variable being registered (link, + /// to, enter). + /// \param DeviceClause - enumerator corresponding to the OpenMP capture + /// clause used in conjunction with the variable being registered (nohost, + /// host, any) + /// \param IsDeclaration - boolean stating if the variable being registered + /// is a declaration-only and not a definition + /// \param IsExternallyVisible - boolean stating if the variable is externally + /// visible + /// \param EntryInfo - Unique entry information for the value generated + /// using getTargetEntryUniqueInfo, used to name generated pointer references + /// to the declare target variable + /// \param MangledName - the mangled name of the variable being registered + /// \param LlvmModule - the llvm module being built that the variable is a + /// part of + /// \param GeneratedRefs - references generated by invocations of + /// registerTargetGlobalVariable invoked from getAddrOfDeclareTargetVar, + /// these are required by Clang for book keeping. + /// \param OpenMPSIMD - if OpenMP SIMD mode is currently enabled + /// \param TargetTriple - The OpenMP device target triple we are compiling + /// for + /// \param LlvmPtrTy - The type of the variable we are generating or + /// retrieving an address for + /// \param GlobalInitializer - a lambda function which creates a constant + /// used for initializing a pointer reference to the variable in certain + /// cases. If a nullptr is passed, it will default to utilising the original + /// variable to initialize the pointer reference. + /// \param VariableLinkage - a lambda function which returns the variables + /// linkage type, if unspecified and a nullptr is given, it will instead + /// utilise the linkage stored on the existing global variable in the + /// LLVMModule. + Constant *getAddrOfDeclareTargetVar( + OffloadEntriesInfoManager::OMPTargetGlobalVarEntryKind CaptureClause, + OffloadEntriesInfoManager::OMPTargetDeviceClauseKind DeviceClause, + bool IsDeclaration, bool IsExternallyVisible, + TargetRegionEntryInfo EntryInfo, StringRef MangledName, + Module *LlvmModule, std::vector &GeneratedRefs, + bool OpenMPSIMD, std::vector TargetTriple, Type *LlvmPtrTy, + std::function GlobalInitializer, + std::function VariableLinkage); + + /// Registers a target variable for device or host. + /// + /// \param CaptureClause - enumerator corresponding to the OpenMP capture + /// clause used in conjunction with the variable being registered (link, + /// to, enter). + /// \param DeviceClause - enumerator corresponding to the OpenMP capture + /// clause used in conjunction with the variable being registered (nohost, + /// host, any) + /// \param IsDeclaration - boolean stating if the variable being registered + /// is a declaration-only and not a definition + /// \param IsExternallyVisible - boolean stating if the variable is externally + /// visible + /// \param EntryInfo - Unique entry information for the value generated + /// using getTargetEntryUniqueInfo, used to name generated pointer references + /// to the declare target variable + /// \param MangledName - the mangled name of the variable being registered + /// \param LlvmModule - the llvm module being built that the variable is a + /// part of + /// \param GeneratedRefs - references generated by invocations of + /// registerTargetGlobalVariable these are required by Clang for book + /// keeping. + /// \param OpenMPSIMD - if OpenMP SIMD mode is currently enabled + /// \param TargetTriple - The OpenMP device target triple we are compiling + /// for + /// \param GlobalInitializer - a lambda function which creates a constant + /// used for initializing a pointer reference to the variable in certain + /// cases. If a nullptr is passed, it will default to utilising the original + /// variable to initialize the pointer reference. + /// \param VariableLinkage - a lambda function which returns the variables + /// linkage type, if unspecified and a nullptr is given, it will instead + /// utilise the linkage stored on the existing global variable in the + /// LLVMModule. + /// \param LlvmPtrTy - The type of the variable we are generating or + /// retrieving an address for + /// \param Addr - the original llvm value (addr) of the variable to be + /// registered + void registerTargetGlobalVariable( + OffloadEntriesInfoManager::OMPTargetGlobalVarEntryKind CaptureClause, + OffloadEntriesInfoManager::OMPTargetDeviceClauseKind DeviceClause, + bool IsDeclaration, bool IsExternallyVisible, + TargetRegionEntryInfo EntryInfo, StringRef MangledName, + Module *LlvmModule, std::vector &GeneratedRefs, + bool OpenMPSIMD, std::vector TargetTriple, + std::function GlobalInitializer, + std::function VariableLinkage, + Type *LlvmPtrTy, Constant *Addr); + private: /// Modifies the canonical loop to be a statically-scheduled workshare loop. /// @@ -1040,6 +1153,17 @@ InsertPointTy AllocaIP, BodyGenCallbackTy BodyGenCB); + /// Creates a unique info for a target entry when provided a filename and + /// line number from. + /// + /// \param FileName The name of the file the target entry resides in + /// \param Line The line number where the target entry resides + /// \param ParentName The name of the parent the target entry resides in, if + /// any. + static TargetRegionEntryInfo + getTargetEntryUniqueInfo(StringRef FileName, uint64_t Line, + llvm::StringRef ParentName = ""); + /// Functions used to generate reductions. Such functions take two Values /// representing LHS and RHS of the reduction, respectively, and a reference /// to the value that is updated to refer to the reduction result. diff --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp --- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp +++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp @@ -32,6 +32,7 @@ #include "llvm/IR/Value.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" @@ -4999,7 +5000,8 @@ static_cast( CE->getFlags()); switch (Flags) { - case OffloadEntriesInfoManager::OMPTargetGlobalVarEntryTo: { + case OffloadEntriesInfoManager::OMPTargetGlobalVarEntryEnter: + case OffloadEntriesInfoManager::OMPTargetGlobalVarEntryTo: if (Config.isEmbedded() && Config.hasRequiresUnifiedSharedMemory()) continue; if (!CE->getAddress()) { @@ -5010,7 +5012,6 @@ if (CE->getVarSize() == 0) continue; break; - } case OffloadEntriesInfoManager::OMPTargetGlobalVarEntryLink: assert(((Config.isEmbedded() && !CE->getAddress()) || (!Config.isEmbedded() && CE->getAddress())) && @@ -5022,6 +5023,8 @@ continue; } break; + default: + break; } // Hidden or internal symbols on the device are not externally visible. @@ -5058,6 +5061,163 @@ EntryInfo.Line, NewCount); } +TargetRegionEntryInfo +OpenMPIRBuilder::getTargetEntryUniqueInfo(StringRef FileName, uint64_t Line, + StringRef ParentName) { + llvm::sys::fs::UniqueID ID; + if (auto EC = llvm::sys::fs::getUniqueID(FileName, ID)) { + assert(EC && + "Unable to get unique ID for file, during getTargetEntryUniqueInfo"); + } + return llvm::TargetRegionEntryInfo(ParentName, ID.getDevice(), ID.getFile(), + Line); +} + + +Constant *OpenMPIRBuilder::getAddrOfDeclareTargetVar( + OffloadEntriesInfoManager::OMPTargetGlobalVarEntryKind CaptureClause, + OffloadEntriesInfoManager::OMPTargetDeviceClauseKind DeviceClause, + bool IsDeclaration, bool IsExternallyVisible, + TargetRegionEntryInfo EntryInfo, StringRef MangledName, Module *LlvmModule, + std::vector &GeneratedRefs, bool OpenMPSIMD, + std::vector TargetTriple, + Type *LlvmPtrTy, std::function GlobalInitializer, + std::function VariableLinkage) { + // TODO: convert this to utilise the IRBuilder Config rather than + // a passed down argument. + if (OpenMPSIMD) + return nullptr; + + if (CaptureClause == + OffloadEntriesInfoManager::OMPTargetGlobalVarEntryLink || + ((CaptureClause == + OffloadEntriesInfoManager::OMPTargetGlobalVarEntryTo || + CaptureClause == + OffloadEntriesInfoManager::OMPTargetGlobalVarEntryEnter) && + Config.hasRequiresUnifiedSharedMemory())) { + SmallString<64> PtrName; + { + llvm::raw_svector_ostream OS(PtrName); + OS << MangledName; + if (!IsExternallyVisible) + OS << llvm::format("_%x", EntryInfo.FileID); + OS << "_decl_tgt_ref_ptr"; + } + + llvm::Value *Ptr = LlvmModule->getNamedValue(PtrName); + + if (!Ptr) { + llvm::GlobalValue *GlobalValue = LlvmModule->getNamedValue(MangledName); + Ptr = getOrCreateInternalVariable(LlvmPtrTy, PtrName); + + auto *GV = cast(Ptr); + GV->setLinkage(llvm::GlobalValue::WeakAnyLinkage); + + if (!Config.isEmbedded()) { + if (GlobalInitializer) + GV->setInitializer(GlobalInitializer()); + else + GV->setInitializer(GlobalValue); + } + + registerTargetGlobalVariable( + CaptureClause, DeviceClause, IsDeclaration, IsExternallyVisible, + EntryInfo, MangledName, LlvmModule, GeneratedRefs, OpenMPSIMD, + TargetTriple, GlobalInitializer, VariableLinkage, + LlvmPtrTy, cast(Ptr)); + } + + return cast(Ptr); + } + + return nullptr; +} + +void OpenMPIRBuilder::registerTargetGlobalVariable( + OffloadEntriesInfoManager::OMPTargetGlobalVarEntryKind CaptureClause, + OffloadEntriesInfoManager::OMPTargetDeviceClauseKind DeviceClause, + bool IsDeclaration, bool IsExternallyVisible, + TargetRegionEntryInfo EntryInfo, llvm::StringRef MangledName, + llvm::Module *LlvmModule, + std::vector &GeneratedRefs, bool OpenMPSIMD, + std::vector TargetTriple, + std::function GlobalInitializer, + std::function VariableLinkage, + llvm::Type *LlvmPtrTy, llvm::Constant *Addr) { + if (DeviceClause != + OffloadEntriesInfoManager::OMPTargetDeviceClauseAny || + (TargetTriple.empty() && !Config.isEmbedded())) + return; + + llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryKind Flags; + StringRef VarName; + int64_t VarSize; + llvm::GlobalValue::LinkageTypes Linkage; + + if ((CaptureClause == + OffloadEntriesInfoManager::OMPTargetGlobalVarEntryTo || + CaptureClause == + OffloadEntriesInfoManager::OMPTargetGlobalVarEntryEnter) && + !Config.hasRequiresUnifiedSharedMemory()) { + Flags = llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryTo; + VarName = MangledName; + llvm::GlobalValue *LlvmVal = LlvmModule->getNamedValue(VarName); + + if (!IsDeclaration) + VarSize = llvm::divideCeil(LlvmModule->getDataLayout().getTypeSizeInBits( + LlvmVal->getValueType()), + 8); + else + VarSize = 0; + Linkage = (VariableLinkage) ? VariableLinkage() : LlvmVal->getLinkage(); + + // This is a workaround carried over from Clang which prevents undesired + // optimisation of internal variables. + if (Config.isEmbedded() && (!IsExternallyVisible || + Linkage == llvm::GlobalValue::LinkOnceODRLinkage)) { + // Do not create a "ref-variable" if the original is not also available + // on the host. + if (!OffloadInfoManager.hasDeviceGlobalVarEntryInfo(VarName)) + return; + + std::string RefName = createPlatformSpecificName({VarName, "ref"}); + + if (!LlvmModule->getNamedValue(RefName)) { + llvm::Constant *AddrRef = + getOrCreateInternalVariable(Addr->getType(), RefName); + auto *GvAddrRef = cast(AddrRef); + GvAddrRef->setConstant(true); + GvAddrRef->setLinkage(llvm::GlobalValue::InternalLinkage); + GvAddrRef->setInitializer(Addr); + GeneratedRefs.push_back(GvAddrRef); + } + } + } else { + if (CaptureClause == + OffloadEntriesInfoManager::OMPTargetGlobalVarEntryLink) + Flags = llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryLink; + else + Flags = llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryTo; + + if (Config.isEmbedded()) { + VarName = (Addr) ? Addr->getName() : ""; + Addr = nullptr; + } else { + Addr = getAddrOfDeclareTargetVar( + CaptureClause, DeviceClause, IsDeclaration, IsExternallyVisible, + EntryInfo, MangledName, LlvmModule, GeneratedRefs, OpenMPSIMD, + TargetTriple, LlvmPtrTy, GlobalInitializer, + VariableLinkage); + VarName = (Addr) ? Addr->getName() : ""; + } + VarSize = LlvmModule->getDataLayout().getPointerSize(); + Linkage = llvm::GlobalValue::WeakAnyLinkage; + } + + OffloadInfoManager.registerDeviceGlobalVarEntryInfo(VarName, Addr, VarSize, + Flags, Linkage); +} + /// Loads all the offload entries information from the host IR /// metadata. void OpenMPIRBuilder::loadOffloadInfoMetadata(Module &M) {