diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/CodeGen/CGOpenMPRuntime.cpp | 193 | ||||
-rw-r--r-- | clang/lib/Parse/ParseOpenMP.cpp | 89 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOpenMP.cpp | 30 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 11 |
4 files changed, 297 insertions, 26 deletions
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index df5e2d05d9a..347606fc746 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -20,6 +20,7 @@ #include "clang/AST/StmtOpenMP.h" #include "clang/Basic/BitmaskEnum.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SetOperations.h" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/GlobalValue.h" @@ -11032,8 +11033,10 @@ using CompleteOMPContextSelectorData = SmallVector<OMPContextSelectorData, 4>; } // anonymous namespace /// Checks current context and returns true if it matches the context selector. -template <OpenMPContextSelectorSetKind CtxSet, OpenMPContextSelectorKind Ctx> -static bool checkContext(const OMPContextSelectorData &Data) { +template <OpenMPContextSelectorSetKind CtxSet, OpenMPContextSelectorKind Ctx, + typename... Arguments> +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; @@ -11048,7 +11051,92 @@ bool checkContext<OMP_CTX_SET_implementation, OMP_CTX_vendor>( [](StringRef S) { return !S.compare_lower("llvm"); }); } -bool matchesContext(const CompleteOMPContextSelectorData &ContextData) { +/// Checks for device={kind(<kind>)} context selector. +/// \returns true if <kind>="host" and compilation is for host. +/// true if <kind>="nohost" and compilation is for device. +/// true if <kind>="cpu" and compilation is for Arm, X86 or PPC CPU. +/// true if <kind>="gpu" and compilation is for NVPTX or AMDGCN. +/// false otherwise. +template <> +bool checkContext<OMP_CTX_SET_device, OMP_CTX_kind, CodeGenModule &>( + 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.CtxSet) { case OMP_CTX_SET_implementation: @@ -11057,8 +11145,22 @@ bool matchesContext(const CompleteOMPContextSelectorData &ContextData) { if (!checkContext<OMP_CTX_SET_implementation, OMP_CTX_vendor>(Data)) return false; break; + case OMP_CTX_kind: case OMP_CTX_unknown: - llvm_unreachable("Unexpected context selector kind."); + llvm_unreachable( + "Unexpected context selector kind in implementation set."); + } + break; + case OMP_CTX_SET_device: + switch (Data.Ctx) { + case OMP_CTX_kind: + if (!checkContext<OMP_CTX_SET_device, OMP_CTX_kind, CodeGenModule &>( + Data, CGM)) + return false; + break; + case OMP_CTX_vendor: + case OMP_CTX_unknown: + llvm_unreachable("Unexpected context selector kind in device set."); } break; case OMP_CTX_SET_unknown: @@ -11089,8 +11191,21 @@ translateAttrToContextSelectorData(ASTContext &C, Data.back().Names = llvm::makeArrayRef(A->implVendors_begin(), A->implVendors_end()); break; + case OMP_CTX_kind: + case OMP_CTX_unknown: + llvm_unreachable( + "Unexpected context selector kind in implementation set."); + } + break; + case OMP_CTX_SET_device: + switch (Ctx) { + case OMP_CTX_kind: + Data.back().Names = + llvm::makeArrayRef(A->deviceKinds_begin(), A->deviceKinds_end()); + break; + case OMP_CTX_vendor: case OMP_CTX_unknown: - llvm_unreachable("Unexpected context selector kind."); + llvm_unreachable("Unexpected context selector kind in device set."); } break; case OMP_CTX_SET_unknown: @@ -11100,27 +11215,59 @@ translateAttrToContextSelectorData(ASTContext &C, return Data; } +static bool isStrictSubset(const CompleteOMPContextSelectorData &LHS, + const CompleteOMPContextSelectorData &RHS) { + llvm::SmallDenseMap<std::pair<int, int>, 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); - 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; + 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); - 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; + 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; @@ -11128,7 +11275,7 @@ static bool greaterCtxScore(const CompleteOMPContextSelectorData &LHS, /// Finds the variant function that matches current context with its context /// selector. -static const FunctionDecl *getDeclareVariantFunction(ASTContext &Ctx, +static const FunctionDecl *getDeclareVariantFunction(CodeGenModule &CGM, const FunctionDecl *FD) { if (!FD->hasAttrs() || !FD->hasAttr<OMPDeclareVariantAttr>()) return FD; @@ -11137,8 +11284,8 @@ static const FunctionDecl *getDeclareVariantFunction(ASTContext &Ctx, CompleteOMPContextSelectorData TopMostData; for (const auto *A : FD->specific_attrs<OMPDeclareVariantAttr>()) { CompleteOMPContextSelectorData Data = - translateAttrToContextSelectorData(Ctx, A); - if (!matchesContext(Data)) + translateAttrToContextSelectorData(CGM.getContext(), A); + if (!matchesContext(CGM, Data)) continue; // If the attribute matches the context, find the attribute with the highest // score. @@ -11161,7 +11308,7 @@ bool CGOpenMPRuntime::emitDeclareVariant(GlobalDecl GD, bool IsForDefinition) { llvm::GlobalValue *Orig = CGM.GetGlobalValue(MangledName); if (Orig && !Orig->isDeclaration()) return false; - const FunctionDecl *NewFD = getDeclareVariantFunction(CGM.getContext(), D); + 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) diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 208e3247a8b..3cf338008aa 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -874,6 +874,7 @@ parseImplementationSelector(Parser &P, SourceLocation Loc, Data.emplace_back(OMP_CTX_SET_implementation, CSKind, Score, Vendors); break; } + case OMP_CTX_kind: case OMP_CTX_unknown: P.Diag(Tok.getLocation(), diag::warn_omp_declare_variant_cs_name_expected) << "implementation"; @@ -885,6 +886,91 @@ parseImplementationSelector(Parser &P, SourceLocation Loc, } } +/// Parse context selector for 'device' selector set: +/// 'kind' '(' <kind> { ',' <kind> } ')' +static void +parseDeviceSelector(Parser &P, SourceLocation Loc, + llvm::StringMap<SourceLocation> &UsedCtx, + SmallVectorImpl<Sema::OMPCtxSelectorData> &Data) { + const Token &Tok = P.getCurToken(); + // Parse inner context selector set name, if any. + if (!Tok.is(tok::identifier)) { + P.Diag(Tok.getLocation(), diag::warn_omp_declare_variant_cs_name_expected) + << "device"; + // Skip until either '}', ')', or end of directive. + while (!P.SkipUntil(tok::r_brace, tok::r_paren, + tok::annot_pragma_openmp_end, Parser::StopBeforeMatch)) + ; + return; + } + Sema::OMPCtxStringType Buffer; + StringRef CtxSelectorName = P.getPreprocessor().getSpelling(Tok, Buffer); + auto Res = UsedCtx.try_emplace(CtxSelectorName, Tok.getLocation()); + if (!Res.second) { + // OpenMP 5.0, 2.3.2 Context Selectors, Restrictions. + // Each trait-selector-name can only be specified once. + P.Diag(Tok.getLocation(), diag::err_omp_declare_variant_ctx_mutiple_use) + << CtxSelectorName << "device"; + P.Diag(Res.first->getValue(), diag::note_omp_declare_variant_ctx_used_here) + << CtxSelectorName; + } + OpenMPContextSelectorKind CSKind = getOpenMPContextSelector(CtxSelectorName); + (void)P.ConsumeToken(); + switch (CSKind) { + case OMP_CTX_kind: { + // Parse '('. + BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end); + (void)T.expectAndConsume(diag::err_expected_lparen_after, + CtxSelectorName.data()); + llvm::UniqueVector<Sema::OMPCtxStringType> Kinds; + do { + // Parse <kind>. + StringRef KindName; + if (Tok.is(tok::identifier)) { + Buffer.clear(); + KindName = P.getPreprocessor().getSpelling(P.getCurToken(), Buffer); + SourceLocation SLoc = P.getCurToken().getLocation(); + (void)P.ConsumeToken(); + if (llvm::StringSwitch<bool>(KindName) + .Case("host", false) + .Case("nohost", false) + .Case("cpu", false) + .Case("gpu", false) + .Case("fpga", false) + .Default(true)) { + P.Diag(SLoc, diag::err_omp_wrong_device_kind_trait) << KindName; + } else { + Kinds.insert(KindName); + } + } else { + P.Diag(Tok.getLocation(), diag::err_omp_declare_variant_item_expected) + << "'host', 'nohost', 'cpu', 'gpu', or 'fpga'" + << "kind" + << "device"; + } + if (!P.TryConsumeToken(tok::comma) && Tok.isNot(tok::r_paren)) { + P.Diag(Tok, diag::err_expected_punc) + << (KindName.empty() ? "kind of device" : KindName); + } + } while (Tok.is(tok::identifier)); + // Parse ')'. + (void)T.consumeClose(); + if (!Kinds.empty()) + Data.emplace_back(OMP_CTX_SET_device, CSKind, ExprResult(), Kinds); + break; + } + case OMP_CTX_vendor: + case OMP_CTX_unknown: + P.Diag(Tok.getLocation(), diag::warn_omp_declare_variant_cs_name_expected) + << "device"; + // Skip until either '}', ')', or end of directive. + while (!P.SkipUntil(tok::r_brace, tok::r_paren, + tok::annot_pragma_openmp_end, Parser::StopBeforeMatch)) + ; + return; + } +} + /// Parses clauses for 'declare variant' directive. /// clause: /// <selector_set_name> '=' '{' <context_selectors> '}' @@ -935,6 +1021,9 @@ bool Parser::parseOpenMPContextSelectors( case OMP_CTX_SET_implementation: parseImplementationSelector(*this, Loc, UsedCtx, Data); break; + case OMP_CTX_SET_device: + parseDeviceSelector(*this, Loc, UsedCtx, Data); + break; case OMP_CTX_SET_unknown: // Skip until either '}', ')', or end of directive. while (!SkipUntil(tok::r_brace, tok::r_paren, diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index d603d2139a0..45cac595004 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -5364,7 +5364,7 @@ void Sema::ActOnOpenMPDeclareVariantDirective( SmallVector<Expr *, 4> CtxScores; SmallVector<unsigned, 4> CtxSets; SmallVector<unsigned, 4> Ctxs; - SmallVector<StringRef, 4> ImplVendors; + SmallVector<StringRef, 4> ImplVendors, DeviceKinds; bool IsError = false; for (const OMPCtxSelectorData &D : Data) { OpenMPContextSelectorSetKind CtxSet = D.CtxSet; @@ -5384,7 +5384,19 @@ void Sema::ActOnOpenMPDeclareVariantDirective( Score = VerifyIntegerConstantExpression(Score).get(); } } else { - Score = ActOnIntegerConstant(SourceLocation(), 0).get(); + // OpenMP 5.0, 2.3.3 Matching and Scoring Context Selectors. + // The kind, arch, and isa selectors are given the values 2^l, 2^(l+1) and + // 2^(l+2), respectively, where l is the number of traits in the construct + // set. + // TODO: implement correct logic for isa and arch traits. + // TODO: take the construct context set into account when it is + // implemented. + int L = 0; // Currently set the number of traits in construct set to 0, + // since the construct trait set in not supported yet. + if (CtxSet == OMP_CTX_SET_device && Ctx == OMP_CTX_kind) + Score = ActOnIntegerConstant(SourceLocation(), std::pow(2, L)).get(); + else + Score = ActOnIntegerConstant(SourceLocation(), 0).get(); } switch (CtxSet) { case OMP_CTX_SET_implementation: @@ -5392,6 +5404,17 @@ void Sema::ActOnOpenMPDeclareVariantDirective( case OMP_CTX_vendor: ImplVendors.append(D.Names.begin(), D.Names.end()); 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: + DeviceKinds.append(D.Names.begin(), D.Names.end()); + break; + case OMP_CTX_vendor: case OMP_CTX_unknown: llvm_unreachable("Unexpected context selector kind."); } @@ -5408,7 +5431,8 @@ void Sema::ActOnOpenMPDeclareVariantDirective( auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit( Context, VariantRef, CtxScores.begin(), CtxScores.size(), CtxSets.begin(), CtxSets.size(), Ctxs.begin(), Ctxs.size(), - ImplVendors.begin(), ImplVendors.size(), SR); + ImplVendors.begin(), ImplVendors.size(), DeviceKinds.begin(), + DeviceKinds.size(), SR); FD->addAttr(NewAttr); } } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 600265e2d85..63777d5272b 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -410,6 +410,17 @@ static void instantiateOMPDeclareVariantAttr( 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."); } |