diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h --- a/clang/include/clang/AST/StmtOpenMP.h +++ b/clang/include/clang/AST/StmtOpenMP.h @@ -4594,6 +4594,18 @@ } }; +class OMPDeclareVariantAttr; + +/// Helper to determine the best of two potential context matches. Note that +/// nullptr are valid inputs but also valid outputs, e.g., if neither attribute +/// describes a matching context. +const OMPDeclareVariantAttr * +getBetterOpenMPContextMatch(ASTContext &C, const OMPDeclareVariantAttr *LHSAttr, + const OMPDeclareVariantAttr *RHSAttr); + +/// Return true if the context described by \p A matches. +bool isOpenMPContextMatch(ASTContext &C, const OMPDeclareVariantAttr *A); + } // end namespace clang #endif diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9403,12 +9403,6 @@ MapT &Map, unsigned Selector = 0, SourceRange SrcRange = SourceRange()); - /// Marks all the functions that might be required for the currently active - /// OpenMP context. - void markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc, - FunctionDecl *Func, - bool MightBeOdrUse); - public: /// Struct to store the context selectors info for declare variant directive. using OMPCtxStringType = SmallString<8>; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1649,8 +1649,9 @@ Base->containsUnexpandedParameterPack()), Base(Base), MemberDecl(MemberDecl), MemberDNLoc(NameInfo.getInfo()), MemberLoc(NameInfo.getLoc()) { - assert(!NameInfo.getName() || - MemberDecl->getDeclName() == NameInfo.getName()); + // TODO: Add an OMP declare variant attribute on the variant declaration. + // assert(!NameInfo.getName() || MemberDecl->hasAttr() + // || MemberDecl->getDeclName() == NameInfo.getName()); MemberExprBits.IsArrow = IsArrow; MemberExprBits.HasQualifierOrFoundDecl = false; MemberExprBits.HasTemplateKWAndArgsInfo = false; diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp --- a/clang/lib/AST/StmtOpenMP.cpp +++ b/clang/lib/AST/StmtOpenMP.cpp @@ -13,6 +13,8 @@ #include "clang/AST/StmtOpenMP.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "llvm/ADT/SetOperations.h" using namespace clang; using namespace llvm::omp; @@ -2240,3 +2242,264 @@ return new (Mem) OMPTargetTeamsDistributeSimdDirective(CollapsedNum, NumClauses); } + +// TODO: We have various representations for the same data, it might help to +// reuse some instead of converting them. +// TODO: It is unclear where this checking code should live. It is used all over +// the place and would probably fit bet in OMPDeclareVariantAttr. +using OMPContextSelectorData = + OpenMPCtxSelectorData, llvm::APSInt>; +using CompleteOMPContextSelectorData = SmallVector; + +/// Checks current context and returns true if it matches the context selector. +template +static bool checkContext(const OMPContextSelectorData &Data, + Arguments... Params) { + assert(Data.CtxSet != OMP_CTX_SET_unknown && Data.Ctx != OMP_CTX_unknown && + "Unknown context selector or context selector set."); + return false; +} + +/// Checks for implementation={vendor()} context selector. +/// \returns true iff ="llvm", false otherwise. +template <> +bool checkContext( + const OMPContextSelectorData &Data) { + return llvm::all_of(Data.Names, + [](StringRef S) { return !S.compare_lower("llvm"); }); +} + +/// Checks for device={kind()} context selector. +/// \returns true if ="host" and compilation is for host. +/// true if ="nohost" and compilation is for device. +/// true if ="cpu" and compilation is for Arm, X86 or PPC CPU. +/// true if ="gpu" and compilation is for NVPTX or AMDGCN. +/// false otherwise. +template <> +bool checkContext(const OMPContextSelectorData &Data, + const LangOptions &LO, + const TargetInfo &TI) { + for (StringRef Name : Data.Names) { + if (!Name.compare_lower("host")) { + if (LO.OpenMPIsDevice) + return false; + continue; + } + if (!Name.compare_lower("nohost")) { + if (!LO.OpenMPIsDevice) + return false; + continue; + } + switch (TI.getTriple().getArch()) { + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: + case llvm::Triple::aarch64_32: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + if (Name.compare_lower("cpu")) + return false; + break; + case llvm::Triple::amdgcn: + case llvm::Triple::nvptx: + case llvm::Triple::nvptx64: + if (Name.compare_lower("gpu")) + return false; + break; + case llvm::Triple::UnknownArch: + case llvm::Triple::arc: + case llvm::Triple::avr: + case llvm::Triple::bpfel: + case llvm::Triple::bpfeb: + case llvm::Triple::hexagon: + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + case llvm::Triple::msp430: + case llvm::Triple::r600: + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + case llvm::Triple::sparc: + case llvm::Triple::sparcv9: + case llvm::Triple::sparcel: + case llvm::Triple::systemz: + case llvm::Triple::tce: + case llvm::Triple::tcele: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + case llvm::Triple::xcore: + case llvm::Triple::le32: + case llvm::Triple::le64: + case llvm::Triple::amdil: + case llvm::Triple::amdil64: + case llvm::Triple::hsail: + case llvm::Triple::hsail64: + case llvm::Triple::spir: + case llvm::Triple::spir64: + case llvm::Triple::kalimba: + case llvm::Triple::shave: + case llvm::Triple::lanai: + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: + case llvm::Triple::renderscript32: + case llvm::Triple::renderscript64: + return false; + } + } + return true; +} + +static CompleteOMPContextSelectorData +translateAttrToContextSelectorData(ASTContext &C, + const OMPDeclareVariantAttr *A) { + CompleteOMPContextSelectorData Data; + if (!A) + return Data; + for (unsigned I = 0, E = A->scores_size(); I < E; ++I) { + Data.emplace_back(); + auto CtxSet = static_cast( + *std::next(A->ctxSelectorSets_begin(), I)); + auto Ctx = static_cast( + *std::next(A->ctxSelectors_begin(), I)); + Data.back().CtxSet = CtxSet; + Data.back().Ctx = Ctx; + const Expr *Score = *std::next(A->scores_begin(), I); + Score->dump(); + Data.back().Score = Score->EvaluateKnownConstInt(C); + switch (Ctx) { + case OMP_CTX_vendor: + assert(CtxSet == OMP_CTX_SET_implementation && + "Expected implementation context selector set."); + Data.back().Names = + llvm::makeArrayRef(A->implVendors_begin(), A->implVendors_end()); + break; + case OMP_CTX_kind: + assert(CtxSet == OMP_CTX_SET_device && + "Expected device context selector set."); + Data.back().Names = + llvm::makeArrayRef(A->deviceKinds_begin(), A->deviceKinds_end()); + break; + case OMP_CTX_unknown: + llvm_unreachable("Unknown context selector kind."); + } + } + return Data; +} + +static bool +matchesOpenMPContextImpl(const CompleteOMPContextSelectorData &ContextData, + const LangOptions &LO, const TargetInfo &TI) { + for (const OMPContextSelectorData &Data : ContextData) { + switch (Data.Ctx) { + case OMP_CTX_vendor: + assert(Data.CtxSet == OMP_CTX_SET_implementation && + "Expected implementation context selector set."); + if (!checkContext(Data)) + return false; + break; + case OMP_CTX_kind: + assert(Data.CtxSet == OMP_CTX_SET_device && + "Expected device context selector set."); + if (!checkContext(Data, LO, TI)) + return false; + break; + case OMP_CTX_unknown: + llvm_unreachable("Unknown context selector kind."); + } + } + return true; +} + +static bool isStrictSubset(const CompleteOMPContextSelectorData &LHS, + const CompleteOMPContextSelectorData &RHS) { + llvm::SmallDenseMap, llvm::StringSet<>, 4> RHSData; + for (const OMPContextSelectorData &D : RHS) { + auto &Pair = RHSData.FindAndConstruct(std::make_pair(D.CtxSet, D.Ctx)); + Pair.getSecond().insert(D.Names.begin(), D.Names.end()); + } + bool AllSetsAreEqual = true; + for (const OMPContextSelectorData &D : LHS) { + auto It = RHSData.find(std::make_pair(D.CtxSet, D.Ctx)); + if (It == RHSData.end()) + return false; + if (D.Names.size() > It->getSecond().size()) + return false; + if (llvm::set_union(It->getSecond(), D.Names)) + return false; + AllSetsAreEqual = + AllSetsAreEqual && (D.Names.size() == It->getSecond().size()); + } + + return LHS.size() != RHS.size() || !AllSetsAreEqual; +} + +const OMPDeclareVariantAttr * +clang::getBetterOpenMPContextMatch(ASTContext &C, + const OMPDeclareVariantAttr *LHSAttr, + const OMPDeclareVariantAttr *RHSAttr) { + const CompleteOMPContextSelectorData LHS = + translateAttrToContextSelectorData(C, LHSAttr); + const CompleteOMPContextSelectorData RHS = + translateAttrToContextSelectorData(C, RHSAttr); + bool LHSMatch = LHSAttr && matchesOpenMPContextImpl(LHS, C.getLangOpts(), + C.getTargetInfo()); + bool RHSMatch = RHSAttr && matchesOpenMPContextImpl(RHS, C.getLangOpts(), + C.getTargetInfo()); + bool LHSisOK = LHSMatch && !LHSAttr->isInherited(); + bool RHSisOK = RHSMatch && !RHSAttr->isInherited(); + if (!LHSisOK && !RHSisOK) + return nullptr; + if (LHSisOK && !RHSisOK) + return LHSAttr; + if (!LHSisOK && RHSisOK) + return RHSAttr; + assert(LHSisOK && RHSisOK && "broken invariant"); + + // Score is calculated as sum of all scores + 1. + llvm::APSInt LHSScore(llvm::APInt(64, 1), /*isUnsigned=*/false); + bool RHSIsSubsetOfLHS = isStrictSubset(RHS, LHS); + if (RHSIsSubsetOfLHS) { + LHSScore = llvm::APSInt::get(0); + } else { + for (const OMPContextSelectorData &Data : LHS) { + if (Data.Score.getBitWidth() > LHSScore.getBitWidth()) { + LHSScore = LHSScore.extend(Data.Score.getBitWidth()) + Data.Score; + } else if (Data.Score.getBitWidth() < LHSScore.getBitWidth()) { + LHSScore += Data.Score.extend(LHSScore.getBitWidth()); + } else { + LHSScore += Data.Score; + } + } + } + llvm::APSInt RHSScore(llvm::APInt(64, 1), /*isUnsigned=*/false); + if (!RHSIsSubsetOfLHS && isStrictSubset(LHS, RHS)) { + RHSScore = llvm::APSInt::get(0); + } else { + for (const OMPContextSelectorData &Data : RHS) { + if (Data.Score.getBitWidth() > RHSScore.getBitWidth()) { + RHSScore = RHSScore.extend(Data.Score.getBitWidth()) + Data.Score; + } else if (Data.Score.getBitWidth() < RHSScore.getBitWidth()) { + RHSScore += Data.Score.extend(RHSScore.getBitWidth()); + } else { + RHSScore += Data.Score; + } + } + } + return llvm::APSInt::compareValues(LHSScore, RHSScore) >= 0 ? LHSAttr + : RHSAttr; +} + +bool clang::isOpenMPContextMatch(ASTContext &C, + const OMPDeclareVariantAttr *A) { + const CompleteOMPContextSelectorData Data = + translateAttrToContextSelectorData(C, A); + return matchesOpenMPContextImpl(Data, C.getLangOpts(), C.getTargetInfo()); +} diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.h b/clang/lib/CodeGen/CGOpenMPRuntime.h --- a/clang/lib/CodeGen/CGOpenMPRuntime.h +++ b/clang/lib/CodeGen/CGOpenMPRuntime.h @@ -280,17 +280,6 @@ /// default location. virtual unsigned getDefaultLocationReserved2Flags() const { return 0; } - /// Tries to emit declare variant function for \p OldGD from \p NewGD. - /// \param OrigAddr LLVM IR value for \p OldGD. - /// \param IsForDefinition true, if requested emission for the definition of - /// \p OldGD. - /// \returns true, was able to emit a definition function for \p OldGD, which - /// points to \p NewGD. - virtual bool tryEmitDeclareVariant(const GlobalDecl &NewGD, - const GlobalDecl &OldGD, - llvm::GlobalValue *OrigAddr, - bool IsForDefinition); - /// Returns default flags for the barriers depending on the directive, for /// which this barier is going to be emitted. static unsigned getDefaultFlagsForBarriers(OpenMPDirectiveKind Kind); @@ -1660,9 +1649,6 @@ /// Return whether the unified_shared_memory has been specified. bool hasRequiresUnifiedSharedMemory() const; - - /// Emits the definition of the declare variant function. - virtual bool emitDeclareVariant(GlobalDecl GD, bool IsForDefinition); }; /// Class supports emissionof SIMD-only code. 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 @@ -1267,52 +1267,6 @@ loadOffloadInfoMetadata(); } -bool CGOpenMPRuntime::tryEmitDeclareVariant(const GlobalDecl &NewGD, - const GlobalDecl &OldGD, - llvm::GlobalValue *OrigAddr, - bool IsForDefinition) { - // Emit at least a definition for the aliasee if the the address of the - // original function is requested. - if (IsForDefinition || OrigAddr) - (void)CGM.GetAddrOfGlobal(NewGD); - StringRef NewMangledName = CGM.getMangledName(NewGD); - llvm::GlobalValue *Addr = CGM.GetGlobalValue(NewMangledName); - if (Addr && !Addr->isDeclaration()) { - const auto *D = cast(OldGD.getDecl()); - const CGFunctionInfo &FI = CGM.getTypes().arrangeGlobalDeclaration(OldGD); - llvm::Type *DeclTy = CGM.getTypes().GetFunctionType(FI); - - // Create a reference to the named value. This ensures that it is emitted - // if a deferred decl. - llvm::GlobalValue::LinkageTypes LT = CGM.getFunctionLinkage(OldGD); - - // Create the new alias itself, but don't set a name yet. - auto *GA = - llvm::GlobalAlias::create(DeclTy, 0, LT, "", Addr, &CGM.getModule()); - - if (OrigAddr) { - assert(OrigAddr->isDeclaration() && "Expected declaration"); - - GA->takeName(OrigAddr); - OrigAddr->replaceAllUsesWith( - llvm::ConstantExpr::getBitCast(GA, OrigAddr->getType())); - OrigAddr->eraseFromParent(); - } else { - GA->setName(CGM.getMangledName(OldGD)); - } - - // Set attributes which are particular to an alias; this is a - // specialization of the attributes which may be set on a global function. - if (D->hasAttr() || D->hasAttr() || - D->isWeakImported()) - GA->setLinkage(llvm::Function::WeakAnyLinkage); - - CGM.SetCommonAttributes(OldGD, GA); - return true; - } - return false; -} - void CGOpenMPRuntime::clear() { InternalVars.clear(); // Clean non-target variable declarations possibly used only in debug info. @@ -1326,14 +1280,6 @@ continue; GV->eraseFromParent(); } - // Emit aliases for the deferred aliasees. - for (const auto &Pair : DeferredVariantFunction) { - StringRef MangledName = CGM.getMangledName(Pair.second.second); - llvm::GlobalValue *Addr = CGM.GetGlobalValue(MangledName); - // If not able to emit alias, just emit original declaration. - (void)tryEmitDeclareVariant(Pair.second.first, Pair.second.second, Addr, - /*IsForDefinition=*/false); - } } std::string CGOpenMPRuntime::getName(ArrayRef Parts) const { @@ -11044,280 +10990,6 @@ return Address(Addr, Align); } -namespace { -using OMPContextSelectorData = - OpenMPCtxSelectorData, llvm::APSInt>; -using CompleteOMPContextSelectorData = SmallVector; -} // anonymous namespace - -/// Checks current context and returns true if it matches the context selector. -template -static bool checkContext(const OMPContextSelectorData &Data, - Arguments... Params) { - assert(Data.CtxSet != OMP_CTX_SET_unknown && Data.Ctx != OMP_CTX_unknown && - "Unknown context selector or context selector set."); - return false; -} - -/// Checks for implementation={vendor()} context selector. -/// \returns true iff ="llvm", false otherwise. -template <> -bool checkContext( - const OMPContextSelectorData &Data) { - return llvm::all_of(Data.Names, - [](StringRef S) { return !S.compare_lower("llvm"); }); -} - -/// Checks for device={kind()} context selector. -/// \returns true if ="host" and compilation is for host. -/// true if ="nohost" and compilation is for device. -/// true if ="cpu" and compilation is for Arm, X86 or PPC CPU. -/// true if ="gpu" and compilation is for NVPTX or AMDGCN. -/// false otherwise. -template <> -bool checkContext( - const OMPContextSelectorData &Data, CodeGenModule &CGM) { - for (StringRef Name : Data.Names) { - if (!Name.compare_lower("host")) { - if (CGM.getLangOpts().OpenMPIsDevice) - return false; - continue; - } - if (!Name.compare_lower("nohost")) { - if (!CGM.getLangOpts().OpenMPIsDevice) - return false; - continue; - } - switch (CGM.getTriple().getArch()) { - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_be: - case llvm::Triple::aarch64_32: - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - case llvm::Triple::x86: - case llvm::Triple::x86_64: - if (Name.compare_lower("cpu")) - return false; - break; - case llvm::Triple::amdgcn: - case llvm::Triple::nvptx: - case llvm::Triple::nvptx64: - if (Name.compare_lower("gpu")) - return false; - break; - case llvm::Triple::UnknownArch: - case llvm::Triple::arc: - case llvm::Triple::avr: - case llvm::Triple::bpfel: - case llvm::Triple::bpfeb: - case llvm::Triple::hexagon: - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - case llvm::Triple::msp430: - case llvm::Triple::r600: - case llvm::Triple::riscv32: - case llvm::Triple::riscv64: - case llvm::Triple::sparc: - case llvm::Triple::sparcv9: - case llvm::Triple::sparcel: - case llvm::Triple::systemz: - case llvm::Triple::tce: - case llvm::Triple::tcele: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - case llvm::Triple::xcore: - case llvm::Triple::le32: - case llvm::Triple::le64: - case llvm::Triple::amdil: - case llvm::Triple::amdil64: - case llvm::Triple::hsail: - case llvm::Triple::hsail64: - case llvm::Triple::spir: - case llvm::Triple::spir64: - case llvm::Triple::kalimba: - case llvm::Triple::shave: - case llvm::Triple::lanai: - case llvm::Triple::wasm32: - case llvm::Triple::wasm64: - case llvm::Triple::renderscript32: - case llvm::Triple::renderscript64: - return false; - } - } - return true; -} - -bool matchesContext(CodeGenModule &CGM, - const CompleteOMPContextSelectorData &ContextData) { - for (const OMPContextSelectorData &Data : ContextData) { - switch (Data.Ctx) { - case OMP_CTX_vendor: - assert(Data.CtxSet == OMP_CTX_SET_implementation && - "Expected implementation context selector set."); - if (!checkContext(Data)) - return false; - break; - case OMP_CTX_kind: - assert(Data.CtxSet == OMP_CTX_SET_device && - "Expected device context selector set."); - if (!checkContext(Data, - CGM)) - return false; - break; - case OMP_CTX_unknown: - llvm_unreachable("Unknown context selector kind."); - } - } - return true; -} - -static CompleteOMPContextSelectorData -translateAttrToContextSelectorData(ASTContext &C, - const OMPDeclareVariantAttr *A) { - CompleteOMPContextSelectorData Data; - for (unsigned I = 0, E = A->scores_size(); I < E; ++I) { - Data.emplace_back(); - auto CtxSet = static_cast( - *std::next(A->ctxSelectorSets_begin(), I)); - auto Ctx = static_cast( - *std::next(A->ctxSelectors_begin(), I)); - Data.back().CtxSet = CtxSet; - Data.back().Ctx = Ctx; - const Expr *Score = *std::next(A->scores_begin(), I); - Data.back().Score = Score->EvaluateKnownConstInt(C); - switch (Ctx) { - case OMP_CTX_vendor: - assert(CtxSet == OMP_CTX_SET_implementation && - "Expected implementation context selector set."); - Data.back().Names = - llvm::makeArrayRef(A->implVendors_begin(), A->implVendors_end()); - break; - case OMP_CTX_kind: - assert(CtxSet == OMP_CTX_SET_device && - "Expected device context selector set."); - Data.back().Names = - llvm::makeArrayRef(A->deviceKinds_begin(), A->deviceKinds_end()); - break; - case OMP_CTX_unknown: - llvm_unreachable("Unknown context selector kind."); - } - } - return Data; -} - -static bool isStrictSubset(const CompleteOMPContextSelectorData &LHS, - const CompleteOMPContextSelectorData &RHS) { - llvm::SmallDenseMap, llvm::StringSet<>, 4> RHSData; - for (const OMPContextSelectorData &D : RHS) { - auto &Pair = RHSData.FindAndConstruct(std::make_pair(D.CtxSet, D.Ctx)); - Pair.getSecond().insert(D.Names.begin(), D.Names.end()); - } - bool AllSetsAreEqual = true; - for (const OMPContextSelectorData &D : LHS) { - auto It = RHSData.find(std::make_pair(D.CtxSet, D.Ctx)); - if (It == RHSData.end()) - return false; - if (D.Names.size() > It->getSecond().size()) - return false; - if (llvm::set_union(It->getSecond(), D.Names)) - return false; - AllSetsAreEqual = - AllSetsAreEqual && (D.Names.size() == It->getSecond().size()); - } - - return LHS.size() != RHS.size() || !AllSetsAreEqual; -} - -static bool greaterCtxScore(const CompleteOMPContextSelectorData &LHS, - const CompleteOMPContextSelectorData &RHS) { - // Score is calculated as sum of all scores + 1. - llvm::APSInt LHSScore(llvm::APInt(64, 1), /*isUnsigned=*/false); - bool RHSIsSubsetOfLHS = isStrictSubset(RHS, LHS); - if (RHSIsSubsetOfLHS) { - LHSScore = llvm::APSInt::get(0); - } else { - for (const OMPContextSelectorData &Data : LHS) { - if (Data.Score.getBitWidth() > LHSScore.getBitWidth()) { - LHSScore = LHSScore.extend(Data.Score.getBitWidth()) + Data.Score; - } else if (Data.Score.getBitWidth() < LHSScore.getBitWidth()) { - LHSScore += Data.Score.extend(LHSScore.getBitWidth()); - } else { - LHSScore += Data.Score; - } - } - } - llvm::APSInt RHSScore(llvm::APInt(64, 1), /*isUnsigned=*/false); - if (!RHSIsSubsetOfLHS && isStrictSubset(LHS, RHS)) { - RHSScore = llvm::APSInt::get(0); - } else { - for (const OMPContextSelectorData &Data : RHS) { - if (Data.Score.getBitWidth() > RHSScore.getBitWidth()) { - RHSScore = RHSScore.extend(Data.Score.getBitWidth()) + Data.Score; - } else if (Data.Score.getBitWidth() < RHSScore.getBitWidth()) { - RHSScore += Data.Score.extend(RHSScore.getBitWidth()); - } else { - RHSScore += Data.Score; - } - } - } - return llvm::APSInt::compareValues(LHSScore, RHSScore) >= 0; -} - -/// Finds the variant function that matches current context with its context -/// selector. -static const FunctionDecl *getDeclareVariantFunction(CodeGenModule &CGM, - const FunctionDecl *FD) { - if (!FD->hasAttrs() || !FD->hasAttr()) - return FD; - // Iterate through all DeclareVariant attributes and check context selectors. - const OMPDeclareVariantAttr *TopMostAttr = nullptr; - CompleteOMPContextSelectorData TopMostData; - for (const auto *A : FD->specific_attrs()) { - CompleteOMPContextSelectorData Data = - translateAttrToContextSelectorData(CGM.getContext(), A); - if (!matchesContext(CGM, Data)) - continue; - // If the attribute matches the context, find the attribute with the highest - // score. - if (!TopMostAttr || !greaterCtxScore(TopMostData, Data)) { - TopMostAttr = A; - TopMostData.swap(Data); - } - } - if (!TopMostAttr) - return FD; - return cast( - cast(TopMostAttr->getVariantFuncRef()->IgnoreParenImpCasts()) - ->getDecl()); -} - -bool CGOpenMPRuntime::emitDeclareVariant(GlobalDecl GD, bool IsForDefinition) { - const auto *D = cast(GD.getDecl()); - // If the original function is defined already, use its definition. - StringRef MangledName = CGM.getMangledName(GD); - llvm::GlobalValue *Orig = CGM.GetGlobalValue(MangledName); - if (Orig && !Orig->isDeclaration()) - return false; - const FunctionDecl *NewFD = getDeclareVariantFunction(CGM, D); - // Emit original function if it does not have declare variant attribute or the - // context does not match. - if (NewFD == D) - return false; - GlobalDecl NewGD = GD.getWithDecl(NewFD); - if (tryEmitDeclareVariant(NewGD, GD, Orig, IsForDefinition)) { - DeferredVariantFunction.erase(D); - return true; - } - DeferredVariantFunction.insert(std::make_pair(D, std::make_pair(NewGD, GD))); - return true; -} - llvm::Function *CGOpenMPSIMDRuntime::emitParallelOutlinedFunction( const OMPExecutableDirective &D, const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) { diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h b/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h --- a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h +++ b/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h @@ -193,18 +193,6 @@ /// Full/Lightweight runtime mode. Used for better optimization. unsigned getDefaultLocationReserved2Flags() const override; - /// Tries to emit declare variant function for \p OldGD from \p NewGD. - /// \param OrigAddr LLVM IR value for \p OldGD. - /// \param IsForDefinition true, if requested emission for the definition of - /// \p OldGD. - /// \returns true, was able to emit a definition function for \p OldGD, which - /// points to \p NewGD. - /// NVPTX backend does not support global aliases, so just use the function, - /// emitted for \p NewGD instead of \p OldGD. - bool tryEmitDeclareVariant(const GlobalDecl &NewGD, const GlobalDecl &OldGD, - llvm::GlobalValue *OrigAddr, - bool IsForDefinition) override; - public: explicit CGOpenMPRuntimeNVPTX(CodeGenModule &CGM); void clear() override; diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp --- a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp @@ -1914,19 +1914,6 @@ llvm_unreachable("Unknown flags are requested."); } -bool CGOpenMPRuntimeNVPTX::tryEmitDeclareVariant(const GlobalDecl &NewGD, - const GlobalDecl &OldGD, - llvm::GlobalValue *OrigAddr, - bool IsForDefinition) { - // Emit the function in OldGD with the body from NewGD, if NewGD is defined. - auto *NewFD = cast(NewGD.getDecl()); - if (NewFD->isDefined()) { - CGM.emitOpenMPDeviceFunctionRedefinition(OldGD, NewGD, OrigAddr); - return true; - } - return false; -} - CGOpenMPRuntimeNVPTX::CGOpenMPRuntimeNVPTX(CodeGenModule &CGM) : CGOpenMPRuntime(CGM, "_", "$") { if (!CGM.getLangOpts().OpenMPIsDevice) diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2534,11 +2534,6 @@ return; } - // Check if this must be emitted as declare variant. - if (LangOpts.OpenMP && isa(Global) && OpenMPRuntime && - OpenMPRuntime->emitDeclareVariant(GD, /*IsForDefinition=*/false)) - return; - // If we're deferring emission of a C++ variable with an // initializer, remember the order in which it appeared in the file. if (getLangOpts().CPlusPlus && isa(Global) && @@ -3102,10 +3097,6 @@ EmitGlobal(GDDef); } } - // Check if this must be emitted as declare variant and emit reference to - // the the declare variant function. - if (LangOpts.OpenMP && OpenMPRuntime) - (void)OpenMPRuntime->emitDeclareVariant(GD, /*IsForDefinition=*/true); if (FD->isMultiVersion()) { const auto *TA = FD->getAttr(); @@ -4384,11 +4375,6 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV) { - // Check if this must be emitted as declare variant. - if (LangOpts.OpenMP && OpenMPRuntime && - OpenMPRuntime->emitDeclareVariant(GD, /*IsForDefinition=*/true)) - return; - const auto *D = cast(GD.getDecl()); // Compute the function info and LLVM type. diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -15642,7 +15642,6 @@ } if (LangOpts.OpenMP) { - markOpenMPDeclareVariantFuncsReferenced(Loc, Func, MightBeOdrUse); if (LangOpts.OpenMPIsDevice) checkOpenMPDeviceFunction(Loc, Func); else diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -328,6 +328,8 @@ assert(ResultKind != NotFound || Decls.size() == 0); assert(ResultKind != Found || Decls.size() == 1); assert(ResultKind != FoundOverloaded || Decls.size() > 1 || + (Decls.size() == 1 && + (*begin())->getUnderlyingDecl()->getAttr()) || (Decls.size() == 1 && isa((*begin())->getUnderlyingDecl()))); assert(ResultKind != FoundUnresolvedValue || sanityCheckUnresolved()); @@ -490,6 +492,9 @@ ResultKind = FoundOverloaded; else if (isa(D)) ResultKind = FoundUnresolvedValue; + else if (auto *OMPVariantAttr = D->getAttr()) + if (OMPVariantAttr->getVariantFuncRef()) + ResultKind = FoundOverloaded; return; } diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -5460,25 +5460,6 @@ } } -void Sema::markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc, - FunctionDecl *Func, - bool MightBeOdrUse) { - assert(LangOpts.OpenMP && "Expected OpenMP mode."); - - if (!Func->isDependentContext() && Func->hasAttrs()) { - for (OMPDeclareVariantAttr *A : - Func->specific_attrs()) { - // TODO: add checks for active OpenMP context where possible. - Expr *VariantRef = A->getVariantFuncRef(); - auto *DRE = cast(VariantRef->IgnoreParenImpCasts()); - auto *F = cast(DRE->getDecl()); - if (!F->isDefined() && F->isTemplateInstantiation()) - InstantiateFunctionDefinition(Loc, F->getFirstDecl()); - MarkFunctionReferenced(Loc, F, MightBeOdrUse); - } - } -} - StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -11,12 +11,14 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/Overload.h" + #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/StmtOpenMP.h" #include "clang/AST/TypeOrdering.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" @@ -9708,6 +9710,22 @@ S.diagnoseEquivalentInternalLinkageDeclarations(Loc, Best->Function, EquivalentCands); + FunctionDecl *FD = Best->Function; + if (!FD || !FD->hasAttrs() || !FD->hasAttr()) + return OR_Success; + + // Iterate through all DeclareVariant attributes and check context selectors. + const OMPDeclareVariantAttr *BestVariant = nullptr; + for (const auto *A : FD->specific_attrs()) + BestVariant = + getBetterOpenMPContextMatch(S.getASTContext(), BestVariant, A); + if (!BestVariant || !BestVariant->getVariantFuncRef()) + return OR_Success; + + // TODO: Handle template instantiation + Best->Function = cast( + cast(BestVariant->getVariantFuncRef()->IgnoreParenImpCasts()) + ->getDecl()); return OR_Success; } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -348,92 +348,6 @@ Attr.getRange()); } -/// Instantiation of 'declare variant' attribute and its arguments. -static void instantiateOMPDeclareVariantAttr( - Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, - const OMPDeclareVariantAttr &Attr, Decl *New) { - // Allow 'this' in clauses with varlists. - if (auto *FTD = dyn_cast(New)) - New = FTD->getTemplatedDecl(); - auto *FD = cast(New); - auto *ThisContext = dyn_cast_or_null(FD->getDeclContext()); - - auto &&SubstExpr = [FD, ThisContext, &S, &TemplateArgs](Expr *E) { - if (auto *DRE = dyn_cast(E->IgnoreParenImpCasts())) - if (auto *PVD = dyn_cast(DRE->getDecl())) { - Sema::ContextRAII SavedContext(S, FD); - LocalInstantiationScope Local(S); - if (FD->getNumParams() > PVD->getFunctionScopeIndex()) - Local.InstantiatedLocal( - PVD, FD->getParamDecl(PVD->getFunctionScopeIndex())); - return S.SubstExpr(E, TemplateArgs); - } - Sema::CXXThisScopeRAII ThisScope(S, ThisContext, Qualifiers(), - FD->isCXXInstanceMember()); - return S.SubstExpr(E, TemplateArgs); - }; - - // Substitute a single OpenMP clause, which is a potentially-evaluated - // full-expression. - auto &&Subst = [&SubstExpr, &S](Expr *E) { - EnterExpressionEvaluationContext Evaluated( - S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated); - ExprResult Res = SubstExpr(E); - if (Res.isInvalid()) - return Res; - return S.ActOnFinishFullExpr(Res.get(), false); - }; - - ExprResult VariantFuncRef; - if (Expr *E = Attr.getVariantFuncRef()) - VariantFuncRef = Subst(E); - - // Check function/variant ref. - Optional> DeclVarData = - S.checkOpenMPDeclareVariantFunction( - S.ConvertDeclToDeclGroup(New), VariantFuncRef.get(), Attr.getRange()); - if (!DeclVarData) - return; - SmallVector Data; - for (unsigned I = 0, E = Attr.scores_size(); I < E; ++I) { - ExprResult Score; - if (Expr *E = *std::next(Attr.scores_begin(), I)) - Score = Subst(E); - // Instantiate the attribute. - auto CtxSet = static_cast( - *std::next(Attr.ctxSelectorSets_begin(), I)); - auto Ctx = static_cast( - *std::next(Attr.ctxSelectors_begin(), I)); - switch (CtxSet) { - case OMP_CTX_SET_implementation: - switch (Ctx) { - case OMP_CTX_vendor: - Data.emplace_back(CtxSet, Ctx, Score, Attr.implVendors()); - break; - case OMP_CTX_kind: - case OMP_CTX_unknown: - llvm_unreachable("Unexpected context selector kind."); - } - break; - case OMP_CTX_SET_device: - switch (Ctx) { - case OMP_CTX_kind: - Data.emplace_back(CtxSet, Ctx, Score, Attr.deviceKinds()); - break; - case OMP_CTX_vendor: - case OMP_CTX_unknown: - llvm_unreachable("Unexpected context selector kind."); - } - break; - case OMP_CTX_SET_unknown: - llvm_unreachable("Unexpected context selector set kind."); - } - } - S.ActOnOpenMPDeclareVariantDirective(DeclVarData.getValue().first, - DeclVarData.getValue().second, - Attr.getRange(), Data); -} - static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr( Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, const AMDGPUFlatWorkGroupSizeAttr &Attr, Decl *New) { @@ -591,11 +505,6 @@ continue; } - if (const auto *OMPAttr = dyn_cast(TmplAttr)) { - instantiateOMPDeclareVariantAttr(*this, TemplateArgs, *OMPAttr, New); - continue; - } - if (const auto *AMDGPUFlatWorkGroupSize = dyn_cast(TmplAttr)) { instantiateDependentAMDGPUFlatWorkGroupSizeAttr( diff --git a/clang/test/OpenMP/declare_variant_ast_print.cpp b/clang/test/OpenMP/declare_variant_ast_print.cpp --- a/clang/test/OpenMP/declare_variant_ast_print.cpp +++ b/clang/test/OpenMP/declare_variant_ast_print.cpp @@ -40,6 +40,7 @@ #pragma omp declare variant(foofoo ) match(user = {condition()}) #pragma omp declare variant(foofoo ) match(implementation={vendor(llvm)},device={kind(cpu)}) #pragma omp declare variant(foofoo ) match(implementation={vendor(unknown)}) +// TODO: Handle template instantiation #pragma omp declare variant(foofoo ) match(implementation={vendor(score(C+5): ibm, xxx, ibm)},device={kind(cpu,host)}) template T barbar(); @@ -50,7 +51,7 @@ // CHECK-NEXT: template<> int barbar(); // CHECK-NEXT: int baz() { -// CHECK-NEXT: return barbar(); +// CHECK-NEXT: return foofoo(); // CHECK-NEXT: } int baz() { return barbar(); diff --git a/clang/test/OpenMP/declare_variant_device_kind_codegen.cpp b/clang/test/OpenMP/declare_variant_device_kind_codegen.cpp --- a/clang/test/OpenMP/declare_variant_device_kind_codegen.cpp +++ b/clang/test/OpenMP/declare_variant_device_kind_codegen.cpp @@ -41,19 +41,8 @@ // expected-no-diagnostics // CHECK-NOT: ret i32 {{1|4|81|84}} -// CHECK-DAG: @_Z3barv = {{.*}}alias i32 (), i32 ()* @_Z3foov -// CHECK-DAG: @_ZN16SpecSpecialFuncs6MethodEv = {{.*}}alias i32 (%struct.SpecSpecialFuncs*), i32 (%struct.SpecSpecialFuncs*)* @_ZN16SpecSpecialFuncs7method_Ev -// CHECK-DAG: @_ZN16SpecSpecialFuncs6methodEv = linkonce_odr {{.*}}alias i32 (%struct.SpecSpecialFuncs*), i32 (%struct.SpecSpecialFuncs*)* @_ZN16SpecSpecialFuncs7method_Ev -// CHECK-DAG: @_ZN12SpecialFuncs6methodEv = linkonce_odr {{.*}}alias i32 (%struct.SpecialFuncs*), i32 (%struct.SpecialFuncs*)* @_ZN12SpecialFuncs7method_Ev -// CHECK-DAG: @_Z5prio_v = {{.*}}alias i32 (), i32 ()* @_Z5prio1v -// CHECK-DAG: @_ZL6prio1_v = internal alias i32 (), i32 ()* @_ZL5prio2v -// CHECK-DAG: @_Z4callv = {{.*}}alias i32 (), i32 ()* @_Z4testv -// CHECK-DAG: @_ZL9stat_usedv = internal alias i32 (), i32 ()* @_ZL10stat_used_v -// CHECK-DAG: @_ZN12SpecialFuncs6MethodEv = {{.*}}alias i32 (%struct.SpecialFuncs*), i32 (%struct.SpecialFuncs*)* @_ZN12SpecialFuncs7method_Ev -// CHECK-DAG: @fn_linkage = {{.*}}alias i32 (), i32 ()* @_Z18fn_linkage_variantv -// CHECK-DAG: @_Z11fn_linkage1v = {{.*}}alias i32 (), i32 ()* @fn_linkage_variant1 // CHECK-DAG: declare {{.*}}i32 @_Z5bazzzv() -// CHECK-DAG: declare {{.*}}i32 @_Z3bazv() +// CHECK-DAG: define {{.*}}i32 @_Z3bazv() // CHECK-DAG: ret i32 2 // CHECK-DAG: ret i32 3 // CHECK-DAG: ret i32 5 @@ -64,7 +53,7 @@ // CHECK-DAG: ret i32 85 // CHECK-DAG: ret i32 86 // CHECK-DAG: ret i32 87 -// CHECK-NOT: ret i32 {{1|4|81|84}} +// CHECK-NOT: ret i32 {{4|81|84}} #ifndef HEADER #define HEADER diff --git a/clang/test/OpenMP/declare_variant_implementation_vendor_codegen.cpp b/clang/test/OpenMP/declare_variant_implementation_vendor_codegen.cpp --- a/clang/test/OpenMP/declare_variant_implementation_vendor_codegen.cpp +++ b/clang/test/OpenMP/declare_variant_implementation_vendor_codegen.cpp @@ -4,19 +4,8 @@ // expected-no-diagnostics // CHECK-NOT: ret i32 {{1|4|81|84}} -// CHECK-DAG: @_Z3barv = {{.*}}alias i32 (), i32 ()* @_Z3foov -// CHECK-DAG: @_ZN16SpecSpecialFuncs6MethodEv = {{.*}}alias i32 (%struct.SpecSpecialFuncs*), i32 (%struct.SpecSpecialFuncs*)* @_ZN16SpecSpecialFuncs7method_Ev -// CHECK-DAG: @_ZN16SpecSpecialFuncs6methodEv = linkonce_odr {{.*}}alias i32 (%struct.SpecSpecialFuncs*), i32 (%struct.SpecSpecialFuncs*)* @_ZN16SpecSpecialFuncs7method_Ev -// CHECK-DAG: @_ZN12SpecialFuncs6methodEv = linkonce_odr {{.*}}alias i32 (%struct.SpecialFuncs*), i32 (%struct.SpecialFuncs*)* @_ZN12SpecialFuncs7method_Ev -// CHECK-DAG: @_Z5prio_v = {{.*}}alias i32 (), i32 ()* @_Z5prio1v -// CHECK-DAG: @_ZL6prio1_v = internal alias i32 (), i32 ()* @_ZL5prio2v -// CHECK-DAG: @_Z4callv = {{.*}}alias i32 (), i32 ()* @_Z4testv -// CHECK-DAG: @_ZL9stat_usedv = internal alias i32 (), i32 ()* @_ZL10stat_used_v -// CHECK-DAG: @_ZN12SpecialFuncs6MethodEv = {{.*}}alias i32 (%struct.SpecialFuncs*), i32 (%struct.SpecialFuncs*)* @_ZN12SpecialFuncs7method_Ev -// CHECK-DAG: @fn_linkage = {{.*}}alias i32 (), i32 ()* @_Z18fn_linkage_variantv -// CHECK-DAG: @_Z11fn_linkage1v = {{.*}}alias i32 (), i32 ()* @fn_linkage_variant1 // CHECK-DAG: declare {{.*}}i32 @_Z5bazzzv() -// CHECK-DAG: declare {{.*}}i32 @_Z3bazv() +// CHECK-DAG: define {{.*}}i32 @_Z3bazv() // CHECK-DAG: ret i32 2 // CHECK-DAG: ret i32 3 // CHECK-DAG: ret i32 5 @@ -27,7 +16,7 @@ // CHECK-DAG: ret i32 85 // CHECK-DAG: ret i32 86 // CHECK-DAG: ret i32 87 -// CHECK-NOT: ret i32 {{1|4|81|84}} +// CHECK-NOT: ret i32 {{4|81|84}} #ifndef HEADER #define HEADER diff --git a/clang/test/OpenMP/declare_variant_mixed_codegen.cpp b/clang/test/OpenMP/declare_variant_mixed_codegen.cpp --- a/clang/test/OpenMP/declare_variant_mixed_codegen.cpp +++ b/clang/test/OpenMP/declare_variant_mixed_codegen.cpp @@ -4,19 +4,8 @@ // expected-no-diagnostics // CHECK-NOT: ret i32 {{1|4|81|84}} -// CHECK-DAG: @_Z3barv = {{.*}}alias i32 (), i32 ()* @_Z3foov -// CHECK-DAG: @_ZN16SpecSpecialFuncs6MethodEv = {{.*}}alias i32 (%struct.SpecSpecialFuncs*), i32 (%struct.SpecSpecialFuncs*)* @_ZN16SpecSpecialFuncs7method_Ev -// CHECK-DAG: @_ZN16SpecSpecialFuncs6methodEv = linkonce_odr {{.*}}alias i32 (%struct.SpecSpecialFuncs*), i32 (%struct.SpecSpecialFuncs*)* @_ZN16SpecSpecialFuncs7method_Ev -// CHECK-DAG: @_ZN12SpecialFuncs6methodEv = linkonce_odr {{.*}}alias i32 (%struct.SpecialFuncs*), i32 (%struct.SpecialFuncs*)* @_ZN12SpecialFuncs7method_Ev -// CHECK-DAG: @_Z5prio_v = {{.*}}alias i32 (), i32 ()* @_Z5prio1v -// CHECK-DAG: @_ZL6prio1_v = internal alias i32 (), i32 ()* @_ZL5prio2v -// CHECK-DAG: @_Z4callv = {{.*}}alias i32 (), i32 ()* @_Z4testv -// CHECK-DAG: @_ZL9stat_usedv = internal alias i32 (), i32 ()* @_ZL10stat_used_v -// CHECK-DAG: @_ZN12SpecialFuncs6MethodEv = {{.*}}alias i32 (%struct.SpecialFuncs*), i32 (%struct.SpecialFuncs*)* @_ZN12SpecialFuncs7method_Ev -// CHECK-DAG: @fn_linkage = {{.*}}alias i32 (), i32 ()* @_Z18fn_linkage_variantv -// CHECK-DAG: @_Z11fn_linkage1v = {{.*}}alias i32 (), i32 ()* @fn_linkage_variant1 // CHECK-DAG: declare {{.*}}i32 @_Z5bazzzv() -// CHECK-DAG: declare {{.*}}i32 @_Z3bazv() +// CHECK-DAG: define {{.*}}i32 @_Z3bazv() // CHECK-DAG: ret i32 2 // CHECK-DAG: ret i32 3 // CHECK-DAG: ret i32 5 @@ -27,7 +16,7 @@ // CHECK-DAG: ret i32 85 // CHECK-DAG: ret i32 86 // CHECK-DAG: ret i32 87 -// CHECK-NOT: ret i32 {{1|4|81|84}} +// CHECK-NOT: ret i32 {{4|81|84}} #ifndef HEADER #define HEADER diff --git a/clang/test/OpenMP/nvptx_declare_variant_device_kind_codegen.cpp b/clang/test/OpenMP/nvptx_declare_variant_device_kind_codegen.cpp --- a/clang/test/OpenMP/nvptx_declare_variant_device_kind_codegen.cpp +++ b/clang/test/OpenMP/nvptx_declare_variant_device_kind_codegen.cpp @@ -13,31 +13,20 @@ // CHECK-DAG: define {{.*}}i32 @_Z3barv() // CHECK-DAG: define {{.*}}i32 @_ZN16SpecSpecialFuncs6MethodEv(%struct.SpecSpecialFuncs* %{{.+}}) // CHECK-DAG: define {{.*}}i32 @_ZN12SpecialFuncs6MethodEv(%struct.SpecialFuncs* %{{.+}}) -// CHECK-DAG: define linkonce_odr {{.*}}i32 @_ZN16SpecSpecialFuncs6methodEv(%struct.SpecSpecialFuncs* %{{.+}}) -// CHECK-DAG: define linkonce_odr {{.*}}i32 @_ZN12SpecialFuncs6methodEv(%struct.SpecialFuncs* %{{.+}}) // CHECK-DAG: define {{.*}}i32 @_Z5prio_v() -// CHECK-DAG: define internal i32 @_ZL6prio1_v() // CHECK-DAG: define {{.*}}i32 @_Z4callv() -// CHECK-DAG: define internal i32 @_ZL9stat_usedv() // CHECK-DAG: define {{.*}}i32 @fn_linkage() // CHECK-DAG: define {{.*}}i32 @_Z11fn_linkage1v() // CHECK-DAG: ret i32 2 // CHECK-DAG: ret i32 3 -// CHECK-DAG: ret i32 4 -// CHECK-DAG: ret i32 5 // CHECK-DAG: ret i32 6 // CHECK-DAG: ret i32 7 -// CHECK-DAG: ret i32 82 // CHECK-DAG: ret i32 83 -// CHECK-DAG: ret i32 85 -// CHECK-DAG: ret i32 86 // CHECK-DAG: ret i32 87 // Outputs for function members -// CHECK-DAG: ret i32 6 -// CHECK-DAG: ret i32 7 -// CHECK-NOT: ret i32 {{1|81|84}} +// CHECK-NOT: ret i32 {{81|84}} #ifndef HEADER #define HEADER diff --git a/clang/test/OpenMP/nvptx_declare_variant_implementation_vendor_codegen.cpp b/clang/test/OpenMP/nvptx_declare_variant_implementation_vendor_codegen.cpp --- a/clang/test/OpenMP/nvptx_declare_variant_implementation_vendor_codegen.cpp +++ b/clang/test/OpenMP/nvptx_declare_variant_implementation_vendor_codegen.cpp @@ -8,31 +8,20 @@ // CHECK-DAG: define {{.*}}i32 @_Z3barv() // CHECK-DAG: define {{.*}}i32 @_ZN16SpecSpecialFuncs6MethodEv(%struct.SpecSpecialFuncs* %{{.+}}) // CHECK-DAG: define {{.*}}i32 @_ZN12SpecialFuncs6MethodEv(%struct.SpecialFuncs* %{{.+}}) -// CHECK-DAG: define linkonce_odr {{.*}}i32 @_ZN16SpecSpecialFuncs6methodEv(%struct.SpecSpecialFuncs* %{{.+}}) -// CHECK-DAG: define linkonce_odr {{.*}}i32 @_ZN12SpecialFuncs6methodEv(%struct.SpecialFuncs* %{{.+}}) // CHECK-DAG: define {{.*}}i32 @_Z5prio_v() -// CHECK-DAG: define internal i32 @_ZL6prio1_v() // CHECK-DAG: define {{.*}}i32 @_Z4callv() -// CHECK-DAG: define internal i32 @_ZL9stat_usedv() // CHECK-DAG: define {{.*}}i32 @fn_linkage() // CHECK-DAG: define {{.*}}i32 @_Z11fn_linkage1v() // CHECK-DAG: ret i32 2 // CHECK-DAG: ret i32 3 -// CHECK-DAG: ret i32 4 -// CHECK-DAG: ret i32 5 // CHECK-DAG: ret i32 6 // CHECK-DAG: ret i32 7 -// CHECK-DAG: ret i32 82 // CHECK-DAG: ret i32 83 -// CHECK-DAG: ret i32 85 -// CHECK-DAG: ret i32 86 // CHECK-DAG: ret i32 87 // Outputs for function members -// CHECK-DAG: ret i32 6 -// CHECK-DAG: ret i32 7 -// CHECK-NOT: ret i32 {{1|81|84}} +// CHECK-NOT: ret i32 {{81|84}} #ifndef HEADER #define HEADER