diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTTypeTraits.cpp | 1 | ||||
-rw-r--r-- | clang/lib/AST/OpenMPClause.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Basic/OpenMPKinds.cpp | 18 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGOpenMPRuntime.cpp | 18 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGStmtOpenMP.cpp | 1 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.cpp | 18 | ||||
-rw-r--r-- | clang/lib/Parse/ParseOpenMP.cpp | 140 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 9 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 8 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOpenMP.cpp | 290 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReaderDecl.cpp | 11 |
11 files changed, 434 insertions, 83 deletions
diff --git a/clang/lib/AST/ASTTypeTraits.cpp b/clang/lib/AST/ASTTypeTraits.cpp index ba65c13859d..8615dee4e79 100644 --- a/clang/lib/AST/ASTTypeTraits.cpp +++ b/clang/lib/AST/ASTTypeTraits.cpp @@ -116,6 +116,7 @@ ASTNodeKind ASTNodeKind::getFromNode(const OMPClause &C) { #include "clang/Basic/OpenMPKinds.def" case OMPC_threadprivate: case OMPC_uniform: + case OMPC_device_type: case OMPC_unknown: llvm_unreachable("unexpected OpenMP clause kind"); } diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index 7cba4d7039a..0312fe6b769 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -43,6 +43,7 @@ OMPClause::child_range OMPClause::used_children() { #include "clang/Basic/OpenMPKinds.def" case OMPC_threadprivate: case OMPC_uniform: + case OMPC_device_type: case OMPC_unknown: break; } @@ -127,6 +128,7 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) { case OMPC_reverse_offload: case OMPC_dynamic_allocators: case OMPC_atomic_default_mem_order: + case OMPC_device_type: break; } @@ -203,6 +205,7 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C) case OMPC_reverse_offload: case OMPC_dynamic_allocators: case OMPC_atomic_default_mem_order: + case OMPC_device_type: break; } diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index 82e193efef3..761df3b55db 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -55,6 +55,7 @@ OpenMPClauseKind clang::getOpenMPClauseKind(StringRef Str) { #define OPENMP_CLAUSE(Name, Class) .Case(#Name, OMPC_##Name) #include "clang/Basic/OpenMPKinds.def" .Case("uniform", OMPC_uniform) + .Case("device_type", OMPC_device_type) .Default(OMPC_unknown); } @@ -71,6 +72,8 @@ const char *clang::getOpenMPClauseName(OpenMPClauseKind Kind) { return "uniform"; case OMPC_threadprivate: return "threadprivate or thread local"; + case OMPC_device_type: + return "device_type"; } llvm_unreachable("Invalid OpenMP clause kind"); } @@ -145,6 +148,11 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, .Case(#Name, OMPC_ATOMIC_DEFAULT_MEM_ORDER_##Name) #include "clang/Basic/OpenMPKinds.def" .Default(OMPC_ATOMIC_DEFAULT_MEM_ORDER_unknown); + case OMPC_device_type: + return llvm::StringSwitch<OpenMPDeviceType>(Str) +#define OPENMP_DEVICE_TYPE_KIND(Name) .Case(#Name, OMPC_DEVICE_TYPE_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_DEVICE_TYPE_unknown); case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: @@ -328,6 +336,16 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, #include "clang/Basic/OpenMPKinds.def" } llvm_unreachable("Invalid OpenMP 'atomic_default_mem_order' clause type"); + case OMPC_device_type: + switch (Type) { + case OMPC_DEVICE_TYPE_unknown: + return "unknown"; +#define OPENMP_DEVICE_TYPE_KIND(Name) \ + case OMPC_DEVICE_TYPE_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'device_type' clause type"); case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 8b04d2eb09a..84211e33b87 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -9604,14 +9604,28 @@ void CGOpenMPRuntime::scanForTargetRegionsFunctions(const Stmt *S, bool CGOpenMPRuntime::emitTargetFunctions(GlobalDecl GD) { // If emitting code for the host, we do not process FD here. Instead we do // the normal code generation. - if (!CGM.getLangOpts().OpenMPIsDevice) + if (!CGM.getLangOpts().OpenMPIsDevice) { + if (const auto *FD = dyn_cast<FunctionDecl>(GD.getDecl())) { + Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = + OMPDeclareTargetDeclAttr::getDeviceType(FD); + // Do not emit device_type(nohost) functions for the host. + if (DevTy && *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) + return true; + } return false; + } const ValueDecl *VD = cast<ValueDecl>(GD.getDecl()); StringRef Name = CGM.getMangledName(GD); // Try to detect target regions in the function. - if (const auto *FD = dyn_cast<FunctionDecl>(VD)) + if (const auto *FD = dyn_cast<FunctionDecl>(VD)) { scanForTargetRegionsFunctions(FD->getBody(), Name); + Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = + OMPDeclareTargetDeclAttr::getDeviceType(FD); + // Do not emit device_type(nohost) functions for the host. + if (DevTy && *DevTy == OMPDeclareTargetDeclAttr::DT_Host) + return true; + } // Do not to emit function if it is not marked as declare target. return !OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD) && diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index 2ca7ebc6b0d..473c6f7950a 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -4021,6 +4021,7 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind, case OMPC_reverse_offload: case OMPC_dynamic_allocators: case OMPC_atomic_default_mem_order: + case OMPC_device_type: llvm_unreachable("Clause is not allowed in 'omp atomic'."); } } diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 3dc40a84868..eedf70b8d50 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2122,6 +2122,10 @@ void CodeGenModule::EmitDeferred() { if (!GV->isDeclaration()) continue; + // If this is OpenMP, check if it is legal to emit this global normally. + if (LangOpts.OpenMP && OpenMPRuntime && OpenMPRuntime->emitTargetGlobal(D)) + continue; + // Otherwise, emit the definition and move on to the next one. EmitGlobalDefinition(D, GV); @@ -2318,11 +2322,20 @@ bool CodeGenModule::MustBeEmitted(const ValueDecl *Global) { } bool CodeGenModule::MayBeEmittedEagerly(const ValueDecl *Global) { - if (const auto *FD = dyn_cast<FunctionDecl>(Global)) + if (const auto *FD = dyn_cast<FunctionDecl>(Global)) { if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) // Implicit template instantiations may change linkage if they are later // explicitly instantiated, so they should not be emitted eagerly. return false; + // In OpenMP 5.0 function may be marked as device_type(nohost) and we should + // not emit them eagerly unless we sure that the function must be emitted on + // the host. + if (LangOpts.OpenMP >= 50 && !LangOpts.OpenMPSimd && + !LangOpts.OpenMPIsDevice && + !OMPDeclareTargetDeclAttr::getDeviceType(FD) && + !FD->isUsed(/*CheckUsedAttr=*/false) && !FD->isReferenced()) + return false; + } if (const auto *VD = dyn_cast<VarDecl>(Global)) if (Context.getInlineVariableDefinitionKind(VD) == ASTContext::InlineVariableDefinitionKind::WeakUnknown) @@ -2445,8 +2458,7 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { } if (LangOpts.OpenMP) { - // If this is OpenMP device, check if it is legal to emit this global - // normally. + // If this is OpenMP, check if it is legal to emit this global normally. if (OpenMPRuntime && OpenMPRuntime->emitTargetGlobal(GD)) return; if (auto *DRD = dyn_cast<OMPDeclareReductionDecl>(Global)) { diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 52a68f6d693..6bd96051f9e 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -782,25 +782,114 @@ Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr, LinModifiers, Steps, SourceRange(Loc, EndLoc)); } +/// Parsing of simple OpenMP clauses like 'default' or 'proc_bind'. +/// +/// default-clause: +/// 'default' '(' 'none' | 'shared' ') +/// +/// proc_bind-clause: +/// 'proc_bind' '(' 'master' | 'close' | 'spread' ') +/// +/// device_type-clause: +/// 'device_type' '(' 'host' | 'nohost' | 'any' )' +namespace { + struct SimpleClauseData { + unsigned Type; + SourceLocation Loc; + SourceLocation LOpen; + SourceLocation TypeLoc; + SourceLocation RLoc; + SimpleClauseData(unsigned Type, SourceLocation Loc, SourceLocation LOpen, + SourceLocation TypeLoc, SourceLocation RLoc) + : Type(Type), Loc(Loc), LOpen(LOpen), TypeLoc(TypeLoc), RLoc(RLoc) {} + }; +} // anonymous namespace + +static Optional<SimpleClauseData> +parseOpenMPSimpleClause(Parser &P, OpenMPClauseKind Kind) { + const Token &Tok = P.getCurToken(); + SourceLocation Loc = Tok.getLocation(); + SourceLocation LOpen = P.ConsumeToken(); + // Parse '('. + BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPClauseName(Kind))) + return llvm::None; + + unsigned Type = getOpenMPSimpleClauseType( + Kind, Tok.isAnnotation() ? "" : P.getPreprocessor().getSpelling(Tok)); + SourceLocation TypeLoc = Tok.getLocation(); + if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && + Tok.isNot(tok::annot_pragma_openmp_end)) + P.ConsumeAnyToken(); + + // Parse ')'. + SourceLocation RLoc = Tok.getLocation(); + if (!T.consumeClose()) + RLoc = T.getCloseLocation(); + + return SimpleClauseData(Type, Loc, LOpen, TypeLoc, RLoc); +} + Parser::DeclGroupPtrTy Parser::ParseOMPDeclareTargetClauses() { // OpenMP 4.5 syntax with list of entities. Sema::NamedDeclSetType SameDirectiveDecls; + SmallVector<std::tuple<OMPDeclareTargetDeclAttr::MapTypeTy, SourceLocation, + NamedDecl *>, + 4> + DeclareTargetDecls; + OMPDeclareTargetDeclAttr::DevTypeTy DT = OMPDeclareTargetDeclAttr::DT_Any; + SourceLocation DeviceTypeLoc; while (Tok.isNot(tok::annot_pragma_openmp_end)) { OMPDeclareTargetDeclAttr::MapTypeTy MT = OMPDeclareTargetDeclAttr::MT_To; if (Tok.is(tok::identifier)) { IdentifierInfo *II = Tok.getIdentifierInfo(); StringRef ClauseName = II->getName(); - // Parse 'to|link' clauses. - if (!OMPDeclareTargetDeclAttr::ConvertStrToMapTypeTy(ClauseName, MT)) { - Diag(Tok, diag::err_omp_declare_target_unexpected_clause) << ClauseName; + bool IsDeviceTypeClause = + getLangOpts().OpenMP >= 50 && + getOpenMPClauseKind(ClauseName) == OMPC_device_type; + // Parse 'to|link|device_type' clauses. + if (!OMPDeclareTargetDeclAttr::ConvertStrToMapTypeTy(ClauseName, MT) && + !IsDeviceTypeClause) { + Diag(Tok, diag::err_omp_declare_target_unexpected_clause) + << ClauseName << (getLangOpts().OpenMP >= 50 ? 1 : 0); break; } + // Parse 'device_type' clause and go to next clause if any. + if (IsDeviceTypeClause) { + Optional<SimpleClauseData> DevTypeData = + parseOpenMPSimpleClause(*this, OMPC_device_type); + if (DevTypeData.hasValue()) { + if (DeviceTypeLoc.isValid()) { + // We already saw another device_type clause, diagnose it. + Diag(DevTypeData.getValue().Loc, + diag::warn_omp_more_one_device_type_clause); + } + switch(static_cast<OpenMPDeviceType>(DevTypeData.getValue().Type)) { + case OMPC_DEVICE_TYPE_any: + DT = OMPDeclareTargetDeclAttr::DT_Any; + break; + case OMPC_DEVICE_TYPE_host: + DT = OMPDeclareTargetDeclAttr::DT_Host; + break; + case OMPC_DEVICE_TYPE_nohost: + DT = OMPDeclareTargetDeclAttr::DT_NoHost; + break; + case OMPC_DEVICE_TYPE_unknown: + llvm_unreachable("Unexpected device_type"); + } + DeviceTypeLoc = DevTypeData.getValue().Loc; + } + continue; + } ConsumeToken(); } - auto &&Callback = [this, MT, &SameDirectiveDecls]( - CXXScopeSpec &SS, DeclarationNameInfo NameInfo) { - Actions.ActOnOpenMPDeclareTargetName(getCurScope(), SS, NameInfo, MT, - SameDirectiveDecls); + auto &&Callback = [this, MT, &DeclareTargetDecls, &SameDirectiveDecls]( + CXXScopeSpec &SS, DeclarationNameInfo NameInfo) { + NamedDecl *ND = Actions.lookupOpenMPDeclareTargetName( + getCurScope(), SS, NameInfo, SameDirectiveDecls); + if (ND) + DeclareTargetDecls.emplace_back(MT, NameInfo.getLoc(), ND); }; if (ParseOpenMPSimpleVarList(OMPD_declare_target, Callback, /*AllowScopeSpecifier=*/true)) @@ -812,6 +901,15 @@ Parser::DeclGroupPtrTy Parser::ParseOMPDeclareTargetClauses() { } SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); ConsumeAnyToken(); + for (auto &MTLocDecl : DeclareTargetDecls) { + OMPDeclareTargetDeclAttr::MapTypeTy MT; + SourceLocation Loc; + NamedDecl *ND; + std::tie(MT, Loc, ND) = MTLocDecl; + // device_type clause is applied only to functions. + Actions.ActOnOpenMPDeclareTargetName( + ND, Loc, MT, isa<VarDecl>(ND) ? OMPDeclareTargetDeclAttr::DT_Any : DT); + } SmallVector<Decl *, 4> Decls(SameDirectiveDecls.begin(), SameDirectiveDecls.end()); if (Decls.empty()) @@ -1712,6 +1810,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_allocate: Clause = ParseOpenMPVarListClause(DKind, CKind, WrongDirective); break; + case OMPC_device_type: case OMPC_unknown: Diag(Tok, diag::warn_omp_extra_tokens_at_eol) << getOpenMPDirectiveName(DKind); @@ -1811,29 +1910,12 @@ OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind, /// OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind, bool ParseOnly) { - SourceLocation Loc = Tok.getLocation(); - SourceLocation LOpen = ConsumeToken(); - // Parse '('. - BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); - if (T.expectAndConsume(diag::err_expected_lparen_after, - getOpenMPClauseName(Kind))) - return nullptr; - - unsigned Type = getOpenMPSimpleClauseType( - Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok)); - SourceLocation TypeLoc = Tok.getLocation(); - if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && - Tok.isNot(tok::annot_pragma_openmp_end)) - ConsumeAnyToken(); - - // Parse ')'. - SourceLocation RLoc = Tok.getLocation(); - if (!T.consumeClose()) - RLoc = T.getCloseLocation(); - - if (ParseOnly) + llvm::Optional<SimpleClauseData> Val = parseOpenMPSimpleClause(*this, Kind); + if (!Val || ParseOnly) return nullptr; - return Actions.ActOnOpenMPSimpleClause(Kind, Type, TypeLoc, LOpen, Loc, RLoc); + return Actions.ActOnOpenMPSimpleClause( + Kind, Val.getValue().Type, Val.getValue().TypeLoc, Val.getValue().LOpen, + Val.getValue().Loc, Val.getValue().RLoc); } /// Parsing of OpenMP clauses like 'ordered'. diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index eb8cae6b68a..17b414556ca 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -913,6 +913,10 @@ void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) { PerformPendingInstantiations(); } + // Finalize analysis of OpenMP-specific constructs. + if (LangOpts.OpenMP) + finalizeOpenMPDelayedAnalysis(); + assert(LateParsedInstantiations.empty() && "end of TU template instantiation should not create more " "late-parsed templates"); @@ -1542,8 +1546,9 @@ void Sema::markKnownEmitted( } Sema::DeviceDiagBuilder Sema::targetDiag(SourceLocation Loc, unsigned DiagID) { - if (LangOpts.OpenMP && LangOpts.OpenMPIsDevice) - return diagIfOpenMPDeviceCode(Loc, DiagID); + if (LangOpts.OpenMP) + return LangOpts.OpenMPIsDevice ? diagIfOpenMPDeviceCode(Loc, DiagID) + : diagIfOpenMPHostCode(Loc, DiagID); if (getLangOpts().CUDA) return getLangOpts().CUDAIsDevice ? CUDADiagIfDeviceCode(Loc, DiagID) : CUDADiagIfHostCode(Loc, DiagID); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 03f968e7d22..ea72bcb259f 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -15350,9 +15350,13 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, CheckCompleteParameterTypesForMangler(*this, Func, Loc); Func->markUsed(Context); + } - if (LangOpts.OpenMP && LangOpts.OpenMPIsDevice) + if (LangOpts.OpenMP) { + if (LangOpts.OpenMPIsDevice) checkOpenMPDeviceFunction(Loc, Func); + else + checkOpenMPHostFunction(Loc, Func); } } @@ -17745,4 +17749,4 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr( return new (Context) ObjCAvailabilityCheckExpr(Version, AtLoc, RParen, Context.BoolTy); -}
\ No newline at end of file +} diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 16956831c8c..9d3d3a50775 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -1556,32 +1556,102 @@ static bool isOpenMPDeviceDelayedContext(Sema &S) { !S.isInOpenMPDeclareTargetContext(); } +namespace { +/// Status of the function emission on the host/device. +enum class FunctionEmissionStatus { + Emitted, + Discarded, + Unknown, +}; +} // anonymous namespace + /// Do we know that we will eventually codegen the given function? -static bool isKnownEmitted(Sema &S, FunctionDecl *FD) { +static FunctionEmissionStatus isKnownDeviceEmitted(Sema &S, FunctionDecl *FD) { assert(S.LangOpts.OpenMP && S.LangOpts.OpenMPIsDevice && "Expected OpenMP device compilation."); // Templates are emitted when they're instantiated. if (FD->isDependentContext()) - return false; + return FunctionEmissionStatus::Discarded; - if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration( - FD->getCanonicalDecl())) - return true; + Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = + OMPDeclareTargetDeclAttr::getDeviceType(FD->getCanonicalDecl()); + if (DevTy.hasValue()) + return (*DevTy == OMPDeclareTargetDeclAttr::DT_Host) + ? FunctionEmissionStatus::Discarded + : FunctionEmissionStatus::Emitted; // Otherwise, the function is known-emitted if it's in our set of // known-emitted functions. - return S.DeviceKnownEmittedFns.count(FD) > 0; + return (S.DeviceKnownEmittedFns.count(FD) > 0) + ? FunctionEmissionStatus::Emitted + : FunctionEmissionStatus::Unknown; } Sema::DeviceDiagBuilder Sema::diagIfOpenMPDeviceCode(SourceLocation Loc, unsigned DiagID) { assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice && "Expected OpenMP device compilation."); - return DeviceDiagBuilder((isOpenMPDeviceDelayedContext(*this) && - !isKnownEmitted(*this, getCurFunctionDecl())) - ? DeviceDiagBuilder::K_Deferred - : DeviceDiagBuilder::K_Immediate, - Loc, DiagID, getCurFunctionDecl(), *this); + FunctionEmissionStatus FES = + isKnownDeviceEmitted(*this, getCurFunctionDecl()); + DeviceDiagBuilder::Kind Kind = DeviceDiagBuilder::K_Nop; + switch (FES) { + case FunctionEmissionStatus::Emitted: + Kind = DeviceDiagBuilder::K_Immediate; + break; + case FunctionEmissionStatus::Unknown: + Kind = isOpenMPDeviceDelayedContext(*this) ? DeviceDiagBuilder::K_Deferred + : DeviceDiagBuilder::K_Immediate; + break; + case FunctionEmissionStatus::Discarded: + Kind = DeviceDiagBuilder::K_Nop; + break; + } + + return DeviceDiagBuilder(Kind, Loc, DiagID, getCurFunctionDecl(), *this); +} + +/// Do we know that we will eventually codegen the given function? +static FunctionEmissionStatus isKnownHostEmitted(Sema &S, FunctionDecl *FD) { + assert(S.LangOpts.OpenMP && !S.LangOpts.OpenMPIsDevice && + "Expected OpenMP host compilation."); + // In OpenMP 4.5 all the functions are host functions. + if (S.LangOpts.OpenMP <= 45) + return FunctionEmissionStatus::Emitted; + + Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = + OMPDeclareTargetDeclAttr::getDeviceType(FD->getCanonicalDecl()); + if (DevTy.hasValue()) + return (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) + ? FunctionEmissionStatus::Discarded + : FunctionEmissionStatus::Emitted; + + // Otherwise, the function is known-emitted if it's in our set of + // known-emitted functions. + return (S.DeviceKnownEmittedFns.count(FD) > 0) + ? FunctionEmissionStatus::Emitted + : FunctionEmissionStatus::Unknown; +} + +Sema::DeviceDiagBuilder Sema::diagIfOpenMPHostCode(SourceLocation Loc, + unsigned DiagID) { + assert(LangOpts.OpenMP && !LangOpts.OpenMPIsDevice && + "Expected OpenMP host compilation."); + FunctionEmissionStatus FES = + isKnownHostEmitted(*this, getCurFunctionDecl()); + DeviceDiagBuilder::Kind Kind = DeviceDiagBuilder::K_Nop; + switch (FES) { + case FunctionEmissionStatus::Emitted: + Kind = DeviceDiagBuilder::K_Immediate; + break; + case FunctionEmissionStatus::Unknown: + Kind = DeviceDiagBuilder::K_Deferred; + break; + case FunctionEmissionStatus::Discarded: + Kind = DeviceDiagBuilder::K_Nop; + break; + } + + return DeviceDiagBuilder(Kind, Loc, DiagID, getCurFunctionDecl(), *this); } void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee, @@ -1589,21 +1659,75 @@ void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee, assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice && "Expected OpenMP device compilation."); assert(Callee && "Callee may not be null."); + Callee = Callee->getMostRecentDecl(); FunctionDecl *Caller = getCurFunctionDecl(); + // host only function are not available on the device. + if (Caller && + (isKnownDeviceEmitted(*this, Caller) == FunctionEmissionStatus::Emitted || + (!isOpenMPDeviceDelayedContext(*this) && + isKnownDeviceEmitted(*this, Caller) == + FunctionEmissionStatus::Unknown)) && + isKnownDeviceEmitted(*this, Callee) == + FunctionEmissionStatus::Discarded) { + StringRef HostDevTy = + getOpenMPSimpleClauseTypeName(OMPC_device_type, OMPC_DEVICE_TYPE_host); + Diag(Loc, diag::err_omp_wrong_device_function_call) << HostDevTy << 0; + Diag(Callee->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(), + diag::note_omp_marked_device_type_here) + << HostDevTy; + return; + } // If the caller is known-emitted, mark the callee as known-emitted. // Otherwise, mark the call in our call graph so we can traverse it later. if ((CheckForDelayedContext && !isOpenMPDeviceDelayedContext(*this)) || (!Caller && !CheckForDelayedContext) || - (Caller && isKnownEmitted(*this, Caller))) + (Caller && + isKnownDeviceEmitted(*this, Caller) == FunctionEmissionStatus::Emitted)) markKnownEmitted(*this, Caller, Callee, Loc, [CheckForDelayedContext](Sema &S, FunctionDecl *FD) { - return CheckForDelayedContext && isKnownEmitted(S, FD); + return CheckForDelayedContext && + isKnownDeviceEmitted(S, FD) == + FunctionEmissionStatus::Emitted; }); else if (Caller) DeviceCallGraph[Caller].insert({Callee, Loc}); } +void Sema::checkOpenMPHostFunction(SourceLocation Loc, FunctionDecl *Callee, + bool CheckCaller) { + assert(LangOpts.OpenMP && !LangOpts.OpenMPIsDevice && + "Expected OpenMP host compilation."); + assert(Callee && "Callee may not be null."); + Callee = Callee->getMostRecentDecl(); + FunctionDecl *Caller = getCurFunctionDecl(); + + // device only function are not available on the host. + if (Caller && + isKnownHostEmitted(*this, Caller) == FunctionEmissionStatus::Emitted && + isKnownHostEmitted(*this, Callee) == FunctionEmissionStatus::Discarded) { + StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName( + OMPC_device_type, OMPC_DEVICE_TYPE_nohost); + Diag(Loc, diag::err_omp_wrong_device_function_call) << NoHostDevTy << 1; + Diag(Callee->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(), + diag::note_omp_marked_device_type_here) + << NoHostDevTy; + return; + } + // If the caller is known-emitted, mark the callee as known-emitted. + // Otherwise, mark the call in our call graph so we can traverse it later. + if ((!CheckCaller && !Caller) || + (Caller && + isKnownHostEmitted(*this, Caller) == FunctionEmissionStatus::Emitted)) + markKnownEmitted( + *this, Caller, Callee, Loc, [CheckCaller](Sema &S, FunctionDecl *FD) { + return CheckCaller && + isKnownHostEmitted(S, FD) == FunctionEmissionStatus::Emitted; + }); + else if (Caller) + DeviceCallGraph[Caller].insert({Callee, Loc}); +} + void Sema::checkOpenMPDeviceExpr(const Expr *E) { assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice && "OpenMP device compilation mode is expected."); @@ -1970,6 +2094,54 @@ bool Sema::isOpenMPTargetCapturedDecl(const ValueDecl *D, void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; } +void Sema::finalizeOpenMPDelayedAnalysis() { + assert(LangOpts.OpenMP && "Expected OpenMP compilation mode."); + // Diagnose implicit declare target functions and their callees. + for (const auto &CallerCallees : DeviceCallGraph) { + Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = + OMPDeclareTargetDeclAttr::getDeviceType( + CallerCallees.getFirst()->getMostRecentDecl()); + // Ignore host functions during device analyzis. + if (LangOpts.OpenMPIsDevice && DevTy && + *DevTy == OMPDeclareTargetDeclAttr::DT_Host) + continue; + // Ignore nohost functions during host analyzis. + if (!LangOpts.OpenMPIsDevice && DevTy && + *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) + continue; + for (const std::pair<CanonicalDeclPtr<FunctionDecl>, SourceLocation> + &Callee : CallerCallees.getSecond()) { + const FunctionDecl *FD = Callee.first->getMostRecentDecl(); + Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = + OMPDeclareTargetDeclAttr::getDeviceType(FD); + if (LangOpts.OpenMPIsDevice && DevTy && + *DevTy == OMPDeclareTargetDeclAttr::DT_Host) { + // Diagnose host function called during device codegen. + StringRef HostDevTy = getOpenMPSimpleClauseTypeName( + OMPC_device_type, OMPC_DEVICE_TYPE_host); + Diag(Callee.second, diag::err_omp_wrong_device_function_call) + << HostDevTy << 0; + Diag(FD->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(), + diag::note_omp_marked_device_type_here) + << HostDevTy; + continue; + } + if (!LangOpts.OpenMPIsDevice && DevTy && + *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) { + // Diagnose nohost function called during host codegen. + StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName( + OMPC_device_type, OMPC_DEVICE_TYPE_nohost); + Diag(Callee.second, diag::err_omp_wrong_device_function_call) + << NoHostDevTy << 1; + Diag(FD->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(), + diag::note_omp_marked_device_type_here) + << NoHostDevTy; + continue; + } + } + } +} + void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName, Scope *CurScope, SourceLocation Loc) { @@ -4415,6 +4587,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPC_reverse_offload: case OMPC_dynamic_allocators: case OMPC_atomic_default_mem_order: + case OMPC_device_type: llvm_unreachable("Unexpected clause"); } for (Stmt *CC : C->children()) { @@ -9642,6 +9815,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_reverse_offload: case OMPC_dynamic_allocators: case OMPC_atomic_default_mem_order: + case OMPC_device_type: llvm_unreachable("Clause is not allowed."); } return Res; @@ -10184,6 +10358,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_reverse_offload: case OMPC_dynamic_allocators: case OMPC_atomic_default_mem_order: + case OMPC_device_type: llvm_unreachable("Unexpected OpenMP clause."); } return CaptureRegion; @@ -10577,6 +10752,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_unified_shared_memory: case OMPC_reverse_offload: case OMPC_dynamic_allocators: + case OMPC_device_type: llvm_unreachable("Clause is not allowed."); } return Res; @@ -10755,6 +10931,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_reverse_offload: case OMPC_dynamic_allocators: case OMPC_atomic_default_mem_order: + case OMPC_device_type: llvm_unreachable("Clause is not allowed."); } return Res; @@ -10964,6 +11141,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_use_device_ptr: case OMPC_is_device_ptr: case OMPC_atomic_default_mem_order: + case OMPC_device_type: llvm_unreachable("Clause is not allowed."); } return Res; @@ -11170,6 +11348,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause( case OMPC_reverse_offload: case OMPC_dynamic_allocators: case OMPC_atomic_default_mem_order: + case OMPC_device_type: llvm_unreachable("Clause is not allowed."); } return Res; @@ -15333,16 +15512,15 @@ void Sema::ActOnFinishOpenMPDeclareTargetDirective() { --DeclareTargetNestingLevel; } -void Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope, - CXXScopeSpec &ScopeSpec, - const DeclarationNameInfo &Id, - OMPDeclareTargetDeclAttr::MapTypeTy MT, - NamedDeclSetType &SameDirectiveDecls) { +NamedDecl * +Sema::lookupOpenMPDeclareTargetName(Scope *CurScope, CXXScopeSpec &ScopeSpec, + const DeclarationNameInfo &Id, + NamedDeclSetType &SameDirectiveDecls) { LookupResult Lookup(*this, Id, LookupOrdinaryName); LookupParsedName(Lookup, CurScope, &ScopeSpec, true); if (Lookup.isAmbiguous()) - return; + return nullptr; Lookup.suppressDiagnostics(); if (!Lookup.isSingleResult()) { @@ -15353,33 +15531,56 @@ void Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope, diagnoseTypo(Corrected, PDiag(diag::err_undeclared_var_use_suggest) << Id.getName()); checkDeclIsAllowedInOpenMPTarget(nullptr, Corrected.getCorrectionDecl()); - return; + return nullptr; } Diag(Id.getLoc(), diag::err_undeclared_var_use) << Id.getName(); - return; + return nullptr; } NamedDecl *ND = Lookup.getAsSingle<NamedDecl>(); - if (isa<VarDecl>(ND) || isa<FunctionDecl>(ND) || - isa<FunctionTemplateDecl>(ND)) { - if (!SameDirectiveDecls.insert(cast<NamedDecl>(ND->getCanonicalDecl()))) - Diag(Id.getLoc(), diag::err_omp_declare_target_multiple) << Id.getName(); - llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res = - OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration( - cast<ValueDecl>(ND)); - if (!Res) { - auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(Context, MT); - ND->addAttr(A); - if (ASTMutationListener *ML = Context.getASTMutationListener()) - ML->DeclarationMarkedOpenMPDeclareTarget(ND, A); - checkDeclIsAllowedInOpenMPTarget(nullptr, ND, Id.getLoc()); - } else if (*Res != MT) { - Diag(Id.getLoc(), diag::err_omp_declare_target_to_and_link) - << Id.getName(); - } - } else { + if (!isa<VarDecl>(ND) && !isa<FunctionDecl>(ND) && + !isa<FunctionTemplateDecl>(ND)) { Diag(Id.getLoc(), diag::err_omp_invalid_target_decl) << Id.getName(); + return nullptr; + } + if (!SameDirectiveDecls.insert(cast<NamedDecl>(ND->getCanonicalDecl()))) + Diag(Id.getLoc(), diag::err_omp_declare_target_multiple) << Id.getName(); + return ND; +} + +void Sema::ActOnOpenMPDeclareTargetName( + NamedDecl *ND, SourceLocation Loc, OMPDeclareTargetDeclAttr::MapTypeTy MT, + OMPDeclareTargetDeclAttr::DevTypeTy DT) { + assert((isa<VarDecl>(ND) || isa<FunctionDecl>(ND) || + isa<FunctionTemplateDecl>(ND)) && + "Expected variable, function or function template."); + + // Diagnose marking after use as it may lead to incorrect diagnosis and + // codegen. + if (LangOpts.OpenMP >= 50 && + (ND->isUsed(/*CheckUsedAttr=*/false) || ND->isReferenced())) + Diag(Loc, diag::warn_omp_declare_target_after_first_use); + + Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = + OMPDeclareTargetDeclAttr::getDeviceType(cast<ValueDecl>(ND)); + if (DevTy.hasValue() && *DevTy != DT) { + Diag(Loc, diag::err_omp_device_type_mismatch) + << OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(DT) + << OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(*DevTy); + return; + } + Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res = + OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(cast<ValueDecl>(ND)); + if (!Res) { + auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(Context, MT, DT, + SourceRange(Loc, Loc)); + ND->addAttr(A); + if (ASTMutationListener *ML = Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPDeclareTarget(ND, A); + checkDeclIsAllowedInOpenMPTarget(nullptr, ND, Loc); + } else if (*Res != MT) { + Diag(Loc, diag::err_omp_declare_target_to_and_link) << ND; } } @@ -15453,8 +15654,14 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, return; } // Mark the function as must be emitted for the device. - if (LangOpts.OpenMPIsDevice && Res.hasValue() && IdLoc.isValid()) + Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = + OMPDeclareTargetDeclAttr::getDeviceType(FD); + if (LangOpts.OpenMPIsDevice && Res.hasValue() && IdLoc.isValid() && + *DevTy != OMPDeclareTargetDeclAttr::DT_Host) checkOpenMPDeviceFunction(IdLoc, FD, /*CheckForDelayedContext=*/false); + if (!LangOpts.OpenMPIsDevice && Res.hasValue() && IdLoc.isValid() && + *DevTy != OMPDeclareTargetDeclAttr::DT_NoHost) + checkOpenMPHostFunction(IdLoc, FD, /*CheckCaller=*/false); } if (auto *VD = dyn_cast<ValueDecl>(D)) { // Problem if any with var declared with incomplete type will be reported @@ -15467,7 +15674,8 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, if (isa<VarDecl>(D) || isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) { auto *A = OMPDeclareTargetDeclAttr::CreateImplicit( - Context, OMPDeclareTargetDeclAttr::MT_To); + Context, OMPDeclareTargetDeclAttr::MT_To, + OMPDeclareTargetDeclAttr::DT_Any, SourceRange(IdLoc, IdLoc)); D->addAttr(A); if (ASTMutationListener *ML = Context.getASTMutationListener()) ML->DeclarationMarkedOpenMPDeclareTarget(D, A); diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index b40e3cf8926..15797ba3488 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -4571,12 +4571,15 @@ void ASTDeclReader::UpdateDecl(Decl *D, break; } - case UPD_DECL_MARKED_OPENMP_DECLARETARGET: + case UPD_DECL_MARKED_OPENMP_DECLARETARGET: { + OMPDeclareTargetDeclAttr::MapTypeTy MapType = + static_cast<OMPDeclareTargetDeclAttr::MapTypeTy>(Record.readInt()); + OMPDeclareTargetDeclAttr::DevTypeTy DevType = + static_cast<OMPDeclareTargetDeclAttr::DevTypeTy>(Record.readInt()); D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit( - Reader.getContext(), - static_cast<OMPDeclareTargetDeclAttr::MapTypeTy>(Record.readInt()), - ReadSourceRange())); + Reader.getContext(), MapType, DevType, ReadSourceRange())); break; + } case UPD_ADDED_ATTR_TO_RECORD: AttrVec Attrs; |