diff options
Diffstat (limited to 'lib/Sema/SemaOpenMP.cpp')
-rw-r--r-- | lib/Sema/SemaOpenMP.cpp | 1880 |
1 files changed, 1597 insertions, 283 deletions
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index bd68011c18b2..c7e0d2aee036 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -139,6 +139,7 @@ private: /// clause, false otherwise. llvm::Optional<std::pair<const Expr *, OMPOrderedClause *>> OrderedRegion; unsigned AssociatedLoops = 1; + bool HasMutipleLoops = false; const Decl *PossiblyLoopCounter = nullptr; bool NowaitRegion = false; bool CancelRegion = false; @@ -169,7 +170,7 @@ private: OpenMPClauseKind ClauseKindMode = OMPC_unknown; Sema &SemaRef; bool ForceCapturing = false; - /// true if all the vaiables in the target executable directives must be + /// true if all the variables in the target executable directives must be /// captured by reference. bool ForceCaptureByReferenceInTargetExecutable = false; CriticalsWithHintsTy Criticals; @@ -521,6 +522,13 @@ public: assert(!isStackEmpty() && "No directive at specified level."); return getStackElemAtLevel(Level).Directive; } + /// Returns the capture region at the specified level. + OpenMPDirectiveKind getCaptureRegion(unsigned Level, + unsigned OpenMPCaptureLevel) const { + SmallVector<OpenMPDirectiveKind, 4> CaptureRegions; + getOpenMPCaptureRegions(CaptureRegions, getDirective(Level)); + return CaptureRegions[OpenMPCaptureLevel]; + } /// Returns parent directive. OpenMPDirectiveKind getParentDirective() const { const SharingMapTy *Parent = getSecondOnStackOrNull(); @@ -678,12 +686,19 @@ public: /// Set collapse value for the region. void setAssociatedLoops(unsigned Val) { getTopOfStack().AssociatedLoops = Val; + if (Val > 1) + getTopOfStack().HasMutipleLoops = true; } /// Return collapse value for region. unsigned getAssociatedLoops() const { const SharingMapTy *Top = getTopOfStackOrNull(); return Top ? Top->AssociatedLoops : 0; } + /// Returns true if the construct is associated with multiple loops. + bool hasMutipleLoops() const { + const SharingMapTy *Top = getTopOfStackOrNull(); + return Top ? Top->HasMutipleLoops : false; + } /// Marks current target region as one with closely nested teams /// region. @@ -951,7 +966,8 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(const_iterator &Iter, // In a parallel construct, if no default clause is present, these // variables are shared. DVar.ImplicitDSALoc = Iter->DefaultAttrLoc; - if (isOpenMPParallelDirective(DVar.DKind) || + if ((isOpenMPParallelDirective(DVar.DKind) && + !isOpenMPTaskLoopDirective(DVar.DKind)) || isOpenMPTeamsDirective(DVar.DKind)) { DVar.CKind = OMPC_shared; return DVar; @@ -1332,7 +1348,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, } const_iterator End = end(); if (!SemaRef.isOpenMPCapturedByRef( - D, std::distance(ParentIterTarget, End))) { + D, std::distance(ParentIterTarget, End), + /*OpenMPCaptureLevel=*/0)) { DVar.RefExpr = buildDeclRefExpr(SemaRef, VD, D->getType().getNonReferenceType(), IterTarget->ConstructLoc); @@ -1540,49 +1557,150 @@ static bool isOpenMPDeviceDelayedContext(Sema &S) { !S.isInOpenMPDeclareTargetContext(); } -/// Do we know that we will eventually codegen the given function? -static bool isKnownEmitted(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; - - if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration( - FD->getCanonicalDecl())) - return true; - - // Otherwise, the function is known-emitted if it's in our set of - // known-emitted functions. - return S.DeviceKnownEmittedFns.count(FD) > 0; -} +namespace { +/// Status of the function emission on the host/device. +enum class FunctionEmissionStatus { + Emitted, + Discarded, + Unknown, +}; +} // anonymous namespace 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 = getEmissionStatus(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::TemplateDiscarded: + case FunctionEmissionStatus::OMPDiscarded: + Kind = DeviceDiagBuilder::K_Nop; + break; + case FunctionEmissionStatus::CUDADiscarded: + llvm_unreachable("CUDADiscarded unexpected in OpenMP device compilation"); + break; + } + + return DeviceDiagBuilder(Kind, Loc, DiagID, getCurFunctionDecl(), *this); } -void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) { +Sema::DeviceDiagBuilder Sema::diagIfOpenMPHostCode(SourceLocation Loc, + unsigned DiagID) { + assert(LangOpts.OpenMP && !LangOpts.OpenMPIsDevice && + "Expected OpenMP host compilation."); + FunctionEmissionStatus FES = getEmissionStatus(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::TemplateDiscarded: + case FunctionEmissionStatus::OMPDiscarded: + case FunctionEmissionStatus::CUDADiscarded: + Kind = DeviceDiagBuilder::K_Nop; + break; + } + + return DeviceDiagBuilder(Kind, Loc, DiagID, getCurFunctionDecl(), *this); +} + +void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee, + bool CheckForDelayedContext) { 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) { + FunctionEmissionStatus CallerS = getEmissionStatus(Caller); + FunctionEmissionStatus CalleeS = getEmissionStatus(Callee); + assert(CallerS != FunctionEmissionStatus::CUDADiscarded && + CalleeS != FunctionEmissionStatus::CUDADiscarded && + "CUDADiscarded unexpected in OpenMP device function check"); + if ((CallerS == FunctionEmissionStatus::Emitted || + (!isOpenMPDeviceDelayedContext(*this) && + CallerS == FunctionEmissionStatus::Unknown)) && + CalleeS == FunctionEmissionStatus::OMPDiscarded) { + 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 (!isOpenMPDeviceDelayedContext(*this) || - (Caller && isKnownEmitted(*this, Caller))) - markKnownEmitted(*this, Caller, Callee, Loc, isKnownEmitted); + if ((CheckForDelayedContext && !isOpenMPDeviceDelayedContext(*this)) || + (!Caller && !CheckForDelayedContext) || + (Caller && getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted)) + markKnownEmitted(*this, Caller, Callee, Loc, + [CheckForDelayedContext](Sema &S, FunctionDecl *FD) { + return CheckForDelayedContext && + S.getEmissionStatus(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) { + FunctionEmissionStatus CallerS = getEmissionStatus(Caller); + FunctionEmissionStatus CalleeS = getEmissionStatus(Callee); + assert( + (LangOpts.CUDA || (CallerS != FunctionEmissionStatus::CUDADiscarded && + CalleeS != FunctionEmissionStatus::CUDADiscarded)) && + "CUDADiscarded unexpected in OpenMP host function check"); + if (CallerS == FunctionEmissionStatus::Emitted && + CalleeS == FunctionEmissionStatus::OMPDiscarded) { + 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 (!shouldIgnoreInHostDeviceCheck(Callee)) { + if ((!CheckCaller && !Caller) || + (Caller && + getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted)) + markKnownEmitted( + *this, Caller, Callee, Loc, [CheckCaller](Sema &S, FunctionDecl *FD) { + return CheckCaller && + S.getEmissionStatus(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."); @@ -1598,7 +1716,8 @@ void Sema::checkOpenMPDeviceExpr(const Expr *E) { << Context.getTargetInfo().getTriple().str() << E->getSourceRange(); } -bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const { +bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level, + unsigned OpenMPCaptureLevel) const { assert(LangOpts.OpenMP && "OpenMP is not allowed"); ASTContext &Ctx = getASTContext(); @@ -1608,6 +1727,7 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const { D = cast<ValueDecl>(D->getCanonicalDecl()); QualType Ty = D->getType(); + bool IsVariableUsedInMapClause = false; if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, Level)) { // This table summarizes how a given variable should be passed to the device // given its type and the clauses where it appears. This table is based on @@ -1669,7 +1789,6 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const { // Locate map clauses and see if the variable being captured is referred to // in any of those clauses. Here we only care about variables, not fields, // because fields are part of aggregates. - bool IsVariableUsedInMapClause = false; bool IsVariableAssociatedWithSection = false; DSAStack->checkMappableExprComponentListsForDeclAtLevel( @@ -1727,10 +1846,13 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const { if (IsByRef && Ty.getNonReferenceType()->isScalarType()) { IsByRef = - !DSAStack->hasExplicitDSA( - D, - [](OpenMPClauseKind K) -> bool { return K == OMPC_firstprivate; }, - Level, /*NotLastprivate=*/true) && + ((IsVariableUsedInMapClause && + DSAStack->getCaptureRegion(Level, OpenMPCaptureLevel) == + OMPD_target) || + !DSAStack->hasExplicitDSA( + D, + [](OpenMPClauseKind K) -> bool { return K == OMPC_firstprivate; }, + Level, /*NotLastprivate=*/true)) && // If the variable is artificial and must be captured by value - try to // capture by value. !(isa<OMPCapturedExprDecl>(D) && !D->hasAttr<OMPCaptureNoInitAttr>() && @@ -1788,7 +1910,8 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo, if (isInOpenMPDeclareTargetContext()) { // Try to mark variable as declare target if it is used in capturing // regions. - if (!OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD)) + if (LangOpts.OpenMP <= 45 && + !OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD)) checkDeclIsAllowedInOpenMPTarget(nullptr, VD); return nullptr; } else if (isInOpenMPTargetExecutionDirective()) { @@ -1858,6 +1981,14 @@ void Sema::startOpenMPLoop() { DSAStack->loopInit(); } +void Sema::startOpenMPCXXRangeFor() { + assert(LangOpts.OpenMP && "OpenMP must be enabled."); + if (isOpenMPLoopDirective(DSAStack->getCurrentDirective())) { + DSAStack->resetPossibleLoopCounter(); + DSAStack->loopStart(); + } +} + bool Sema::isOpenMPPrivateDecl(const ValueDecl *D, unsigned Level) const { assert(LangOpts.OpenMP && "OpenMP is not allowed"); if (isOpenMPLoopDirective(DSAStack->getCurrentDirective())) { @@ -1874,6 +2005,13 @@ bool Sema::isOpenMPPrivateDecl(const ValueDecl *D, unsigned Level) const { !isOpenMPSimdDirective(DSAStack->getCurrentDirective())) return true; } + if (const auto *VD = dyn_cast<VarDecl>(D)) { + if (DSAStack->isThreadPrivate(const_cast<VarDecl *>(VD)) && + DSAStack->isForceVarCapturing() && + !DSAStack->hasExplicitDSA( + D, [](OpenMPClauseKind K) { return K == OMPC_copyin; }, Level)) + return true; + } return DSAStack->hasExplicitDSA( D, [](OpenMPClauseKind K) { return K == OMPC_private; }, Level) || (DSAStack->isClauseParsingMode() && @@ -1937,6 +2075,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) { @@ -2034,7 +2220,7 @@ public: } std::unique_ptr<CorrectionCandidateCallback> clone() override { - return llvm::make_unique<VarDeclFilterCCC>(*this); + return std::make_unique<VarDeclFilterCCC>(*this); } }; @@ -2056,7 +2242,7 @@ public: } std::unique_ptr<CorrectionCandidateCallback> clone() override { - return llvm::make_unique<VarOrFuncDeclFilterCCC>(*this); + return std::make_unique<VarOrFuncDeclFilterCCC>(*this); } }; @@ -2944,18 +3130,19 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); + Params, /*OpenMPCaptureLevel=*/0); // Mark this captured region as inlined, because we don't use outlined // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( - Context, AlwaysInlineAttr::Keyword_forceinline)); + Context, {}, AttributeCommonInfo::AS_Keyword, + AlwaysInlineAttr::Keyword_forceinline)); Sema::CapturedParamNameType ParamsTarget[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; // Start a captured region for 'target' with no implicit parameters. ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - ParamsTarget); + ParamsTarget, /*OpenMPCaptureLevel=*/1); Sema::CapturedParamNameType ParamsTeamsOrParallel[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), std::make_pair(".bound_tid.", KmpInt32PtrTy), @@ -2964,7 +3151,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { // Start a captured region for 'teams' or 'parallel'. Both regions have // the same implicit parameters. ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - ParamsTeamsOrParallel); + ParamsTeamsOrParallel, /*OpenMPCaptureLevel=*/2); break; } case OMPD_target: @@ -2988,14 +3175,16 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); + Params, /*OpenMPCaptureLevel=*/0); // Mark this captured region as inlined, because we don't use outlined // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( - Context, AlwaysInlineAttr::Keyword_forceinline)); + Context, {}, AttributeCommonInfo::AS_Keyword, + AlwaysInlineAttr::Keyword_forceinline)); ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - std::make_pair(StringRef(), QualType())); + std::make_pair(StringRef(), QualType()), + /*OpenMPCaptureLevel=*/1); break; } case OMPD_simd: @@ -3044,11 +3233,14 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( - Context, AlwaysInlineAttr::Keyword_forceinline)); + Context, {}, AttributeCommonInfo::AS_Keyword, + AlwaysInlineAttr::Keyword_forceinline)); break; } case OMPD_taskloop: - case OMPD_taskloop_simd: { + case OMPD_taskloop_simd: + case OMPD_master_taskloop: + case OMPD_master_taskloop_simd: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1) .withConst(); @@ -3086,7 +3278,58 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( - Context, AlwaysInlineAttr::Keyword_forceinline)); + Context, {}, AttributeCommonInfo::AS_Keyword, + AlwaysInlineAttr::Keyword_forceinline)); + break; + } + case OMPD_parallel_master_taskloop: { + QualType KmpInt32Ty = + Context.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1) + .withConst(); + QualType KmpUInt64Ty = + Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0) + .withConst(); + QualType KmpInt64Ty = + Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1) + .withConst(); + QualType VoidPtrTy = Context.VoidPtrTy.withConst().withRestrict(); + QualType KmpInt32PtrTy = + Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); + Sema::CapturedParamNameType ParamsParallel[] = { + std::make_pair(".global_tid.", KmpInt32PtrTy), + std::make_pair(".bound_tid.", KmpInt32PtrTy), + std::make_pair(StringRef(), QualType()) // __context with shared vars + }; + // Start a captured region for 'parallel'. + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + ParamsParallel, /*OpenMPCaptureLevel=*/1); + QualType Args[] = {VoidPtrTy}; + FunctionProtoType::ExtProtoInfo EPI; + EPI.Variadic = true; + QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI); + Sema::CapturedParamNameType Params[] = { + std::make_pair(".global_tid.", KmpInt32Ty), + std::make_pair(".part_id.", KmpInt32PtrTy), + std::make_pair(".privates.", VoidPtrTy), + std::make_pair( + ".copy_fn.", + Context.getPointerType(CopyFnType).withConst().withRestrict()), + std::make_pair(".task_t.", Context.VoidPtrTy.withConst()), + std::make_pair(".lb.", KmpUInt64Ty), + std::make_pair(".ub.", KmpUInt64Ty), + std::make_pair(".st.", KmpInt64Ty), + std::make_pair(".liter.", KmpInt32Ty), + std::make_pair(".reductions.", VoidPtrTy), + std::make_pair(StringRef(), QualType()) // __context with shared vars + }; + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + Params, /*OpenMPCaptureLevel=*/2); + // Mark this captured region as inlined, because we don't use outlined + // function directly. + getCurCapturedRegion()->TheCapturedDecl->addAttr( + AlwaysInlineAttr::CreateImplicit( + Context, {}, AttributeCommonInfo::AS_Keyword, + AlwaysInlineAttr::Keyword_forceinline)); break; } case OMPD_distribute_parallel_for_simd: @@ -3127,18 +3370,19 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); + Params, /*OpenMPCaptureLevel=*/0); // Mark this captured region as inlined, because we don't use outlined // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( - Context, AlwaysInlineAttr::Keyword_forceinline)); + Context, {}, AttributeCommonInfo::AS_Keyword, + AlwaysInlineAttr::Keyword_forceinline)); Sema::CapturedParamNameType ParamsTarget[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; // Start a captured region for 'target' with no implicit parameters. ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - ParamsTarget); + ParamsTarget, /*OpenMPCaptureLevel=*/1); Sema::CapturedParamNameType ParamsTeams[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), @@ -3147,7 +3391,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { }; // Start a captured region for 'target' with no implicit parameters. ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - ParamsTeams); + ParamsTeams, /*OpenMPCaptureLevel=*/2); Sema::CapturedParamNameType ParamsParallel[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), @@ -3159,7 +3403,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { // Start a captured region for 'teams' or 'parallel'. Both regions have // the same implicit parameters. ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - ParamsParallel); + ParamsParallel, /*OpenMPCaptureLevel=*/3); break; } @@ -3176,7 +3420,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { }; // Start a captured region for 'target' with no implicit parameters. ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - ParamsTeams); + ParamsTeams, /*OpenMPCaptureLevel=*/0); Sema::CapturedParamNameType ParamsParallel[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), @@ -3188,7 +3432,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { // Start a captured region for 'teams' or 'parallel'. Both regions have // the same implicit parameters. ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - ParamsParallel); + ParamsParallel, /*OpenMPCaptureLevel=*/1); break; } case OMPD_target_update: @@ -3218,7 +3462,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( - Context, AlwaysInlineAttr::Keyword_forceinline)); + Context, {}, AttributeCommonInfo::AS_Keyword, + AlwaysInlineAttr::Keyword_forceinline)); break; } case OMPD_threadprivate: @@ -3235,12 +3480,17 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_requires: + case OMPD_declare_variant: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); } } +int Sema::getNumberOfConstructScopes(unsigned Level) const { + return getOpenMPCaptureLevels(DSAStack->getDirective(Level)); +} + int Sema::getOpenMPCaptureLevels(OpenMPDirectiveKind DKind) { SmallVector<OpenMPDirectiveKind, 4> CaptureRegions; getOpenMPCaptureRegions(CaptureRegions, DKind); @@ -3670,7 +3920,10 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, // OpenMP [2.16, Nesting of Regions] // If specified, a teams construct must be contained within a target // construct. - NestingProhibited = ParentRegion != OMPD_target; + NestingProhibited = + (SemaRef.LangOpts.OpenMP <= 45 && ParentRegion != OMPD_target) || + (SemaRef.LangOpts.OpenMP >= 50 && ParentRegion != OMPD_unknown && + ParentRegion != OMPD_target); OrphanSeen = ParentRegion == OMPD_unknown; Recommend = ShouldBeInTargetRegion; } @@ -4214,6 +4467,22 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( EndLoc, VarsWithInheritedDSA); AllowedNameModifiers.push_back(OMPD_taskloop); break; + case OMPD_master_taskloop: + Res = ActOnOpenMPMasterTaskLoopDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_taskloop); + break; + case OMPD_master_taskloop_simd: + Res = ActOnOpenMPMasterTaskLoopSimdDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_taskloop); + break; + case OMPD_parallel_master_taskloop: + Res = ActOnOpenMPParallelMasterTaskLoopDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_taskloop); + AllowedNameModifiers.push_back(OMPD_parallel); + break; case OMPD_distribute: Res = ActOnOpenMPDistributeDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); @@ -4301,6 +4570,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_requires: + case OMPD_declare_variant: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); @@ -4326,18 +4596,22 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( continue; case OMPC_schedule: break; + case OMPC_grainsize: + case OMPC_num_tasks: + case OMPC_final: + case OMPC_priority: + // Do not analyze if no parent parallel directive. + if (isOpenMPParallelDirective(DSAStack->getCurrentDirective())) + break; + continue; case OMPC_ordered: case OMPC_device: case OMPC_num_teams: case OMPC_thread_limit: - case OMPC_priority: - case OMPC_grainsize: - case OMPC_num_tasks: case OMPC_hint: case OMPC_collapse: case OMPC_safelen: case OMPC_simdlen: - case OMPC_final: case OMPC_default: case OMPC_proc_bind: case OMPC_private: @@ -4381,6 +4655,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPC_reverse_offload: case OMPC_dynamic_allocators: case OMPC_atomic_default_mem_order: + case OMPC_device_type: + case OMPC_match: llvm_unreachable("Unexpected clause"); } for (Stmt *CC : C->children()) { @@ -4437,8 +4713,10 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( if (!DG || DG.get().isNull()) return DeclGroupPtrTy(); + const int SimdId = 0; if (!DG.get().isSingleDecl()) { - Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd); + Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd_variant) + << SimdId; return DG; } Decl *ADecl = DG.get().getSingleDecl(); @@ -4447,7 +4725,7 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( auto *FD = dyn_cast<FunctionDecl>(ADecl); if (!FD) { - Diag(ADecl->getLocation(), diag::err_omp_function_expected); + Diag(ADecl->getLocation(), diag::err_omp_function_expected) << SimdId; return DeclGroupPtrTy(); } @@ -4669,7 +4947,266 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( const_cast<unsigned *>(LinModifiers.data()), LinModifiers.size(), NewSteps.data(), NewSteps.size(), SR); ADecl->addAttr(NewAttr); - return ConvertDeclToDeclGroup(ADecl); + return DG; +} + +Optional<std::pair<FunctionDecl *, Expr *>> +Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, + Expr *VariantRef, SourceRange SR) { + if (!DG || DG.get().isNull()) + return None; + + const int VariantId = 1; + // Must be applied only to single decl. + if (!DG.get().isSingleDecl()) { + Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd_variant) + << VariantId << SR; + return None; + } + Decl *ADecl = DG.get().getSingleDecl(); + if (auto *FTD = dyn_cast<FunctionTemplateDecl>(ADecl)) + ADecl = FTD->getTemplatedDecl(); + + // Decl must be a function. + auto *FD = dyn_cast<FunctionDecl>(ADecl); + if (!FD) { + Diag(ADecl->getLocation(), diag::err_omp_function_expected) + << VariantId << SR; + return None; + } + + auto &&HasMultiVersionAttributes = [](const FunctionDecl *FD) { + return FD->hasAttrs() && + (FD->hasAttr<CPUDispatchAttr>() || FD->hasAttr<CPUSpecificAttr>() || + FD->hasAttr<TargetAttr>()); + }; + // OpenMP is not compatible with CPU-specific attributes. + if (HasMultiVersionAttributes(FD)) { + Diag(FD->getLocation(), diag::err_omp_declare_variant_incompat_attributes) + << SR; + return None; + } + + // Allow #pragma omp declare variant only if the function is not used. + if (FD->isUsed(false)) + Diag(SR.getBegin(), diag::warn_omp_declare_variant_after_used) + << FD->getLocation(); + + // Check if the function was emitted already. + const FunctionDecl *Definition; + if (!FD->isThisDeclarationADefinition() && FD->isDefined(Definition) && + (LangOpts.EmitAllDecls || Context.DeclMustBeEmitted(Definition))) + Diag(SR.getBegin(), diag::warn_omp_declare_variant_after_emitted) + << FD->getLocation(); + + // The VariantRef must point to function. + if (!VariantRef) { + Diag(SR.getBegin(), diag::err_omp_function_expected) << VariantId; + return None; + } + + // Do not check templates, wait until instantiation. + if (VariantRef->isTypeDependent() || VariantRef->isValueDependent() || + VariantRef->containsUnexpandedParameterPack() || + VariantRef->isInstantiationDependent() || FD->isDependentContext()) + return std::make_pair(FD, VariantRef); + + // Convert VariantRef expression to the type of the original function to + // resolve possible conflicts. + ExprResult VariantRefCast; + if (LangOpts.CPlusPlus) { + QualType FnPtrType; + auto *Method = dyn_cast<CXXMethodDecl>(FD); + if (Method && !Method->isStatic()) { + const Type *ClassType = + Context.getTypeDeclType(Method->getParent()).getTypePtr(); + FnPtrType = Context.getMemberPointerType(FD->getType(), ClassType); + ExprResult ER; + { + // Build adrr_of unary op to correctly handle type checks for member + // functions. + Sema::TentativeAnalysisScope Trap(*this); + ER = CreateBuiltinUnaryOp(VariantRef->getBeginLoc(), UO_AddrOf, + VariantRef); + } + if (!ER.isUsable()) { + Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected) + << VariantId << VariantRef->getSourceRange(); + return None; + } + VariantRef = ER.get(); + } else { + FnPtrType = Context.getPointerType(FD->getType()); + } + ImplicitConversionSequence ICS = + TryImplicitConversion(VariantRef, FnPtrType.getUnqualifiedType(), + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*InOverloadResolution=*/false, + /*CStyle=*/false, + /*AllowObjCWritebackConversion=*/false); + if (ICS.isFailure()) { + Diag(VariantRef->getExprLoc(), + diag::err_omp_declare_variant_incompat_types) + << VariantRef->getType() << FnPtrType << VariantRef->getSourceRange(); + return None; + } + VariantRefCast = PerformImplicitConversion( + VariantRef, FnPtrType.getUnqualifiedType(), AA_Converting); + if (!VariantRefCast.isUsable()) + return None; + // Drop previously built artificial addr_of unary op for member functions. + if (Method && !Method->isStatic()) { + Expr *PossibleAddrOfVariantRef = VariantRefCast.get(); + if (auto *UO = dyn_cast<UnaryOperator>( + PossibleAddrOfVariantRef->IgnoreImplicit())) + VariantRefCast = UO->getSubExpr(); + } + } else { + VariantRefCast = VariantRef; + } + + ExprResult ER = CheckPlaceholderExpr(VariantRefCast.get()); + if (!ER.isUsable() || + !ER.get()->IgnoreParenImpCasts()->getType()->isFunctionType()) { + Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected) + << VariantId << VariantRef->getSourceRange(); + return None; + } + + // The VariantRef must point to function. + auto *DRE = dyn_cast<DeclRefExpr>(ER.get()->IgnoreParenImpCasts()); + if (!DRE) { + Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected) + << VariantId << VariantRef->getSourceRange(); + return None; + } + auto *NewFD = dyn_cast_or_null<FunctionDecl>(DRE->getDecl()); + if (!NewFD) { + Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected) + << VariantId << VariantRef->getSourceRange(); + return None; + } + + // Check if variant function is not marked with declare variant directive. + if (NewFD->hasAttrs() && NewFD->hasAttr<OMPDeclareVariantAttr>()) { + Diag(VariantRef->getExprLoc(), + diag::warn_omp_declare_variant_marked_as_declare_variant) + << VariantRef->getSourceRange(); + SourceRange SR = + NewFD->specific_attr_begin<OMPDeclareVariantAttr>()->getRange(); + Diag(SR.getBegin(), diag::note_omp_marked_declare_variant_here) << SR; + return None; + } + + enum DoesntSupport { + VirtFuncs = 1, + Constructors = 3, + Destructors = 4, + DeletedFuncs = 5, + DefaultedFuncs = 6, + ConstexprFuncs = 7, + ConstevalFuncs = 8, + }; + if (const auto *CXXFD = dyn_cast<CXXMethodDecl>(FD)) { + if (CXXFD->isVirtual()) { + Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) + << VirtFuncs; + return None; + } + + if (isa<CXXConstructorDecl>(FD)) { + Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) + << Constructors; + return None; + } + + if (isa<CXXDestructorDecl>(FD)) { + Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) + << Destructors; + return None; + } + } + + if (FD->isDeleted()) { + Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) + << DeletedFuncs; + return None; + } + + if (FD->isDefaulted()) { + Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) + << DefaultedFuncs; + return None; + } + + if (FD->isConstexpr()) { + Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) + << (NewFD->isConsteval() ? ConstevalFuncs : ConstexprFuncs); + return None; + } + + // Check general compatibility. + if (areMultiversionVariantFunctionsCompatible( + FD, NewFD, PDiag(diag::err_omp_declare_variant_noproto), + PartialDiagnosticAt( + SR.getBegin(), + PDiag(diag::note_omp_declare_variant_specified_here) << SR), + PartialDiagnosticAt( + VariantRef->getExprLoc(), + PDiag(diag::err_omp_declare_variant_doesnt_support)), + PartialDiagnosticAt(VariantRef->getExprLoc(), + PDiag(diag::err_omp_declare_variant_diff) + << FD->getLocation()), + /*TemplatesSupported=*/true, /*ConstexprSupported=*/false, + /*CLinkageMayDiffer=*/true)) + return None; + return std::make_pair(FD, cast<Expr>(DRE)); +} + +void Sema::ActOnOpenMPDeclareVariantDirective( + FunctionDecl *FD, Expr *VariantRef, SourceRange SR, + const Sema::OpenMPDeclareVariantCtsSelectorData &Data) { + if (Data.CtxSet == OMPDeclareVariantAttr::CtxSetUnknown || + Data.Ctx == OMPDeclareVariantAttr::CtxUnknown) + return; + Expr *Score = nullptr; + OMPDeclareVariantAttr::ScoreType ST = OMPDeclareVariantAttr::ScoreUnknown; + if (Data.CtxScore.isUsable()) { + ST = OMPDeclareVariantAttr::ScoreSpecified; + Score = Data.CtxScore.get(); + if (!Score->isTypeDependent() && !Score->isValueDependent() && + !Score->isInstantiationDependent() && + !Score->containsUnexpandedParameterPack()) { + llvm::APSInt Result; + ExprResult ICE = VerifyIntegerConstantExpression(Score, &Result); + if (ICE.isInvalid()) + return; + } + } + auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit( + Context, VariantRef, Score, Data.CtxSet, ST, Data.Ctx, + Data.ImplVendors.begin(), Data.ImplVendors.size(), SR); + FD->addAttr(NewAttr); +} + +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<OMPDeclareVariantAttr>()) { + // TODO: add checks for active OpenMP context where possible. + Expr *VariantRef = A->getVariantFuncRef(); + auto *DRE = dyn_cast<DeclRefExpr>(VariantRef->IgnoreParenImpCasts()); + auto *F = cast<FunctionDecl>(DRE->getDecl()); + if (!F->isDefined() && F->isTemplateInstantiation()) + InstantiateFunctionDefinition(Loc, F->getFirstDecl()); + MarkFunctionReferenced(Loc, F, MightBeOdrUse); + } + } } StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses, @@ -4694,6 +5231,54 @@ StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses, } namespace { +/// Iteration space of a single for loop. +struct LoopIterationSpace final { + /// True if the condition operator is the strict compare operator (<, > or + /// !=). + bool IsStrictCompare = false; + /// Condition of the loop. + Expr *PreCond = nullptr; + /// This expression calculates the number of iterations in the loop. + /// It is always possible to calculate it before starting the loop. + Expr *NumIterations = nullptr; + /// The loop counter variable. + Expr *CounterVar = nullptr; + /// Private loop counter variable. + Expr *PrivateCounterVar = nullptr; + /// This is initializer for the initial value of #CounterVar. + Expr *CounterInit = nullptr; + /// This is step for the #CounterVar used to generate its update: + /// #CounterVar = #CounterInit + #CounterStep * CurrentIteration. + Expr *CounterStep = nullptr; + /// Should step be subtracted? + bool Subtract = false; + /// Source range of the loop init. + SourceRange InitSrcRange; + /// Source range of the loop condition. + SourceRange CondSrcRange; + /// Source range of the loop increment. + SourceRange IncSrcRange; + /// Minimum value that can have the loop control variable. Used to support + /// non-rectangular loops. Applied only for LCV with the non-iterator types, + /// since only such variables can be used in non-loop invariant expressions. + Expr *MinValue = nullptr; + /// Maximum value that can have the loop control variable. Used to support + /// non-rectangular loops. Applied only for LCV with the non-iterator type, + /// since only such variables can be used in non-loop invariant expressions. + Expr *MaxValue = nullptr; + /// true, if the lower bound depends on the outer loop control var. + bool IsNonRectangularLB = false; + /// true, if the upper bound depends on the outer loop control var. + bool IsNonRectangularUB = false; + /// Index of the loop this loop depends on and forms non-rectangular loop + /// nest. + unsigned LoopDependentIdx = 0; + /// Final condition for the non-rectangular loop nest support. It is used to + /// check that the number of iterations for this particular counter must be + /// finished. + Expr *FinalCondition = nullptr; +}; + /// Helper class for checking canonical form of the OpenMP loops and /// extracting iteration space of each loop in the loop nest, that will be used /// for IR generation. @@ -4743,6 +5328,9 @@ class OpenMPIterationSpaceChecker { Optional<unsigned> CondDependOnLC; /// Checks if the provide statement depends on the loop counter. Optional<unsigned> doesDependOnLoopCounter(const Stmt *S, bool IsInitializer); + /// Original condition required for checking of the exit condition for + /// non-rectangular loop. + Expr *Condition = nullptr; public: OpenMPIterationSpaceChecker(Sema &SemaRef, DSAStackTy &Stack, @@ -4774,7 +5362,7 @@ public: bool isStrictTestOp() const { return TestIsStrictOp; } /// Build the expression to calculate the number of iterations. Expr *buildNumIterations( - Scope *S, const bool LimitedType, + Scope *S, ArrayRef<LoopIterationSpace> ResultIterSpaces, bool LimitedType, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const; /// Build the precondition expression for the loops. Expr * @@ -4798,8 +5386,21 @@ public: llvm::MapVector<const Expr *, DeclRefExpr *> &Captures, SourceLocation Loc, Expr *Inc = nullptr, OverloadedOperatorKind OOK = OO_Amp); + /// Builds the minimum value for the loop counter. + std::pair<Expr *, Expr *> buildMinMaxValues( + Scope *S, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const; + /// Builds final condition for the non-rectangular loops. + Expr *buildFinalCondition(Scope *S) const; /// Return true if any expression is dependent. bool dependent() const; + /// Returns true if the initializer forms non-rectangular loop. + bool doesInitDependOnLC() const { return InitDependOnLC.hasValue(); } + /// Returns true if the condition forms non-rectangular loop. + bool doesCondDependOnLC() const { return CondDependOnLC.hasValue(); } + /// Returns index of the loop we depend on (starting from 1), or 0 otherwise. + unsigned getLoopDependentIdx() const { + return InitDependOnLC.getValueOr(CondDependOnLC.getValueOr(0)); + } private: /// Check the right-hand side of an assignment in the increment @@ -4998,9 +5599,9 @@ public: return false; } bool VisitStmt(const Stmt *S) { - bool Res = true; + bool Res = false; for (const Stmt *Child : S->children()) - Res = Child && Visit(Child) && Res; + Res = (Child && Visit(Child)) || Res; return Res; } explicit LoopCounterRefChecker(Sema &SemaRef, DSAStackTy &Stack, @@ -5142,14 +5743,17 @@ static const ValueDecl *getInitLCDecl(const Expr *E) { bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) { // Check test-expr for canonical form, save upper-bound UB, flags for // less/greater and for strict/non-strict comparison. - // OpenMP [2.6] Canonical loop form. Test-expr may be one of the following: + // OpenMP [2.9] Canonical loop form. Test-expr may be one of the following: // var relational-op b // b relational-op var // + bool IneqCondIsCanonical = SemaRef.getLangOpts().OpenMP >= 50; if (!S) { - SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) << LCDecl; + SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) + << (IneqCondIsCanonical ? 1 : 0) << LCDecl; return true; } + Condition = S; S = getExprAsWritten(S); SourceLocation CondLoc = S->getBeginLoc(); if (auto *BO = dyn_cast<BinaryOperator>(S)) { @@ -5164,12 +5768,11 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) { (BO->getOpcode() == BO_GT || BO->getOpcode() == BO_GE), (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT), BO->getSourceRange(), BO->getOperatorLoc()); - } else if (BO->getOpcode() == BO_NE) - return setUB(getInitLCDecl(BO->getLHS()) == LCDecl ? - BO->getRHS() : BO->getLHS(), - /*LessOp=*/llvm::None, - /*StrictOp=*/true, - BO->getSourceRange(), BO->getOperatorLoc()); + } else if (IneqCondIsCanonical && BO->getOpcode() == BO_NE) + return setUB( + getInitLCDecl(BO->getLHS()) == LCDecl ? BO->getRHS() : BO->getLHS(), + /*LessOp=*/llvm::None, + /*StrictOp=*/true, BO->getSourceRange(), BO->getOperatorLoc()); } else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(S)) { if (CE->getNumArgs() == 2) { auto Op = CE->getOperator(); @@ -5188,12 +5791,12 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) { CE->getOperatorLoc()); break; case OO_ExclaimEqual: - return setUB(getInitLCDecl(CE->getArg(0)) == LCDecl ? - CE->getArg(1) : CE->getArg(0), - /*LessOp=*/llvm::None, - /*StrictOp=*/true, - CE->getSourceRange(), - CE->getOperatorLoc()); + if (IneqCondIsCanonical) + return setUB(getInitLCDecl(CE->getArg(0)) == LCDecl ? CE->getArg(1) + : CE->getArg(0), + /*LessOp=*/llvm::None, + /*StrictOp=*/true, CE->getSourceRange(), + CE->getOperatorLoc()); break; default: break; @@ -5203,7 +5806,7 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) { if (dependent() || SemaRef.CurContext->isDependentContext()) return false; SemaRef.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond) - << S->getSourceRange() << LCDecl; + << (IneqCondIsCanonical ? 1 : 0) << S->getSourceRange() << LCDecl; return true; } @@ -5336,15 +5939,177 @@ tryBuildCapture(Sema &SemaRef, Expr *Capture, /// Build the expression to calculate the number of iterations. Expr *OpenMPIterationSpaceChecker::buildNumIterations( - Scope *S, const bool LimitedType, + Scope *S, ArrayRef<LoopIterationSpace> ResultIterSpaces, bool LimitedType, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const { ExprResult Diff; QualType VarType = LCDecl->getType().getNonReferenceType(); if (VarType->isIntegerType() || VarType->isPointerType() || SemaRef.getLangOpts().CPlusPlus) { + Expr *LBVal = LB; + Expr *UBVal = UB; + // LB = TestIsLessOp.getValue() ? min(LB(MinVal), LB(MaxVal)) : + // max(LB(MinVal), LB(MaxVal)) + if (InitDependOnLC) { + const LoopIterationSpace &IS = + ResultIterSpaces[ResultIterSpaces.size() - 1 - + InitDependOnLC.getValueOr( + CondDependOnLC.getValueOr(0))]; + if (!IS.MinValue || !IS.MaxValue) + return nullptr; + // OuterVar = Min + ExprResult MinValue = + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue); + if (!MinValue.isUsable()) + return nullptr; + + ExprResult LBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, + IS.CounterVar, MinValue.get()); + if (!LBMinVal.isUsable()) + return nullptr; + // OuterVar = Min, LBVal + LBMinVal = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMinVal.get(), LBVal); + if (!LBMinVal.isUsable()) + return nullptr; + // (OuterVar = Min, LBVal) + LBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMinVal.get()); + if (!LBMinVal.isUsable()) + return nullptr; + + // OuterVar = Max + ExprResult MaxValue = + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue); + if (!MaxValue.isUsable()) + return nullptr; + + ExprResult LBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, + IS.CounterVar, MaxValue.get()); + if (!LBMaxVal.isUsable()) + return nullptr; + // OuterVar = Max, LBVal + LBMaxVal = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMaxVal.get(), LBVal); + if (!LBMaxVal.isUsable()) + return nullptr; + // (OuterVar = Max, LBVal) + LBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMaxVal.get()); + if (!LBMaxVal.isUsable()) + return nullptr; + + Expr *LBMin = tryBuildCapture(SemaRef, LBMinVal.get(), Captures).get(); + Expr *LBMax = tryBuildCapture(SemaRef, LBMaxVal.get(), Captures).get(); + if (!LBMin || !LBMax) + return nullptr; + // LB(MinVal) < LB(MaxVal) + ExprResult MinLessMaxRes = + SemaRef.BuildBinOp(S, DefaultLoc, BO_LT, LBMin, LBMax); + if (!MinLessMaxRes.isUsable()) + return nullptr; + Expr *MinLessMax = + tryBuildCapture(SemaRef, MinLessMaxRes.get(), Captures).get(); + if (!MinLessMax) + return nullptr; + if (TestIsLessOp.getValue()) { + // LB(MinVal) < LB(MaxVal) ? LB(MinVal) : LB(MaxVal) - min(LB(MinVal), + // LB(MaxVal)) + ExprResult MinLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc, + MinLessMax, LBMin, LBMax); + if (!MinLB.isUsable()) + return nullptr; + LBVal = MinLB.get(); + } else { + // LB(MinVal) < LB(MaxVal) ? LB(MaxVal) : LB(MinVal) - max(LB(MinVal), + // LB(MaxVal)) + ExprResult MaxLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc, + MinLessMax, LBMax, LBMin); + if (!MaxLB.isUsable()) + return nullptr; + LBVal = MaxLB.get(); + } + } + // UB = TestIsLessOp.getValue() ? max(UB(MinVal), UB(MaxVal)) : + // min(UB(MinVal), UB(MaxVal)) + if (CondDependOnLC) { + const LoopIterationSpace &IS = + ResultIterSpaces[ResultIterSpaces.size() - 1 - + InitDependOnLC.getValueOr( + CondDependOnLC.getValueOr(0))]; + if (!IS.MinValue || !IS.MaxValue) + return nullptr; + // OuterVar = Min + ExprResult MinValue = + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue); + if (!MinValue.isUsable()) + return nullptr; + + ExprResult UBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, + IS.CounterVar, MinValue.get()); + if (!UBMinVal.isUsable()) + return nullptr; + // OuterVar = Min, UBVal + UBMinVal = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMinVal.get(), UBVal); + if (!UBMinVal.isUsable()) + return nullptr; + // (OuterVar = Min, UBVal) + UBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMinVal.get()); + if (!UBMinVal.isUsable()) + return nullptr; + + // OuterVar = Max + ExprResult MaxValue = + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue); + if (!MaxValue.isUsable()) + return nullptr; + + ExprResult UBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, + IS.CounterVar, MaxValue.get()); + if (!UBMaxVal.isUsable()) + return nullptr; + // OuterVar = Max, UBVal + UBMaxVal = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMaxVal.get(), UBVal); + if (!UBMaxVal.isUsable()) + return nullptr; + // (OuterVar = Max, UBVal) + UBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMaxVal.get()); + if (!UBMaxVal.isUsable()) + return nullptr; + + Expr *UBMin = tryBuildCapture(SemaRef, UBMinVal.get(), Captures).get(); + Expr *UBMax = tryBuildCapture(SemaRef, UBMaxVal.get(), Captures).get(); + if (!UBMin || !UBMax) + return nullptr; + // UB(MinVal) > UB(MaxVal) + ExprResult MinGreaterMaxRes = + SemaRef.BuildBinOp(S, DefaultLoc, BO_GT, UBMin, UBMax); + if (!MinGreaterMaxRes.isUsable()) + return nullptr; + Expr *MinGreaterMax = + tryBuildCapture(SemaRef, MinGreaterMaxRes.get(), Captures).get(); + if (!MinGreaterMax) + return nullptr; + if (TestIsLessOp.getValue()) { + // UB(MinVal) > UB(MaxVal) ? UB(MinVal) : UB(MaxVal) - max(UB(MinVal), + // UB(MaxVal)) + ExprResult MaxUB = SemaRef.ActOnConditionalOp( + DefaultLoc, DefaultLoc, MinGreaterMax, UBMin, UBMax); + if (!MaxUB.isUsable()) + return nullptr; + UBVal = MaxUB.get(); + } else { + // UB(MinVal) > UB(MaxVal) ? UB(MaxVal) : UB(MinVal) - min(UB(MinVal), + // UB(MaxVal)) + ExprResult MinUB = SemaRef.ActOnConditionalOp( + DefaultLoc, DefaultLoc, MinGreaterMax, UBMax, UBMin); + if (!MinUB.isUsable()) + return nullptr; + UBVal = MinUB.get(); + } + } // Upper - Lower - Expr *UBExpr = TestIsLessOp.getValue() ? UB : LB; - Expr *LBExpr = TestIsLessOp.getValue() ? LB : UB; + Expr *UBExpr = TestIsLessOp.getValue() ? UBVal : LBVal; + Expr *LBExpr = TestIsLessOp.getValue() ? LBVal : UBVal; Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get(); Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get(); if (!Upper || !Lower) @@ -5431,12 +6196,142 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations( return Diff.get(); } +std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues( + Scope *S, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const { + // Do not build for iterators, they cannot be used in non-rectangular loop + // nests. + if (LCDecl->getType()->isRecordType()) + return std::make_pair(nullptr, nullptr); + // If we subtract, the min is in the condition, otherwise the min is in the + // init value. + Expr *MinExpr = nullptr; + Expr *MaxExpr = nullptr; + Expr *LBExpr = TestIsLessOp.getValue() ? LB : UB; + Expr *UBExpr = TestIsLessOp.getValue() ? UB : LB; + bool LBNonRect = TestIsLessOp.getValue() ? InitDependOnLC.hasValue() + : CondDependOnLC.hasValue(); + bool UBNonRect = TestIsLessOp.getValue() ? CondDependOnLC.hasValue() + : InitDependOnLC.hasValue(); + Expr *Lower = + LBNonRect ? LBExpr : tryBuildCapture(SemaRef, LBExpr, Captures).get(); + Expr *Upper = + UBNonRect ? UBExpr : tryBuildCapture(SemaRef, UBExpr, Captures).get(); + if (!Upper || !Lower) + return std::make_pair(nullptr, nullptr); + + if (TestIsLessOp.getValue()) + MinExpr = Lower; + else + MaxExpr = Upper; + + // Build minimum/maximum value based on number of iterations. + ExprResult Diff; + QualType VarType = LCDecl->getType().getNonReferenceType(); + + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + // Upper - Lower [- 1] + if (TestIsStrictOp) + Diff = SemaRef.BuildBinOp( + S, DefaultLoc, BO_Sub, Diff.get(), + SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + // Upper - Lower [- 1] + Step + ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures); + if (!NewStep.isUsable()) + return std::make_pair(nullptr, nullptr); + + // Parentheses (for dumping/debugging purposes only). + Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + // (Upper - Lower [- 1]) / Step + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + // ((Upper - Lower [- 1]) / Step) * Step + // Parentheses (for dumping/debugging purposes only). + Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Mul, Diff.get(), NewStep.get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + // Convert to the original type or ptrdiff_t, if original type is pointer. + if (!VarType->isAnyPointerType() && + !SemaRef.Context.hasSameType(Diff.get()->getType(), VarType)) { + Diff = SemaRef.PerformImplicitConversion( + Diff.get(), VarType, Sema::AA_Converting, /*AllowExplicit=*/true); + } else if (VarType->isAnyPointerType() && + !SemaRef.Context.hasSameType( + Diff.get()->getType(), + SemaRef.Context.getUnsignedPointerDiffType())) { + Diff = SemaRef.PerformImplicitConversion( + Diff.get(), SemaRef.Context.getUnsignedPointerDiffType(), + Sema::AA_Converting, /*AllowExplicit=*/true); + } + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + // Parentheses (for dumping/debugging purposes only). + Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + if (TestIsLessOp.getValue()) { + // MinExpr = Lower; + // MaxExpr = Lower + (((Upper - Lower [- 1]) / Step) * Step) + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Lower, Diff.get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue*/ false); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + MaxExpr = Diff.get(); + } else { + // MaxExpr = Upper; + // MinExpr = Upper - (((Upper - Lower [- 1]) / Step) * Step) + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Diff.get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue*/ false); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + MinExpr = Diff.get(); + } + + return std::make_pair(MinExpr, MaxExpr); +} + +Expr *OpenMPIterationSpaceChecker::buildFinalCondition(Scope *S) const { + if (InitDependOnLC || CondDependOnLC) + return Condition; + return nullptr; +} + Expr *OpenMPIterationSpaceChecker::buildPreCond( Scope *S, Expr *Cond, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const { + // Do not build a precondition when the condition/initialization is dependent + // to prevent pessimistic early loop exit. + // TODO: this can be improved by calculating min/max values but not sure that + // it will be very effective. + if (CondDependOnLC || InitDependOnLC) + return SemaRef.PerformImplicitConversion( + SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get(), + SemaRef.Context.BoolTy, /*Action=*/Sema::AA_Casting, + /*AllowExplicit=*/true).get(); + // Try to build LB <op> UB, where <op> is <, >, <=, or >=. - bool Suppress = SemaRef.getDiagnostics().getSuppressAllDiagnostics(); - SemaRef.getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true); + Sema::TentativeAnalysisScope Trap(SemaRef); ExprResult NewLB = tryBuildCapture(SemaRef, LB, Captures); ExprResult NewUB = tryBuildCapture(SemaRef, UB, Captures); @@ -5456,7 +6351,7 @@ Expr *OpenMPIterationSpaceChecker::buildPreCond( CondExpr.get(), SemaRef.Context.BoolTy, /*Action=*/Sema::AA_Casting, /*AllowExplicit=*/true); } - SemaRef.getDiagnostics().setSuppressAllDiagnostics(Suppress); + // Otherwise use original loop condition and evaluate it in runtime. return CondExpr.isUsable() ? CondExpr.get() : Cond; } @@ -5561,36 +6456,6 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData( return Diff.get(); } - -/// Iteration space of a single for loop. -struct LoopIterationSpace final { - /// True if the condition operator is the strict compare operator (<, > or - /// !=). - bool IsStrictCompare = false; - /// Condition of the loop. - Expr *PreCond = nullptr; - /// This expression calculates the number of iterations in the loop. - /// It is always possible to calculate it before starting the loop. - Expr *NumIterations = nullptr; - /// The loop counter variable. - Expr *CounterVar = nullptr; - /// Private loop counter variable. - Expr *PrivateCounterVar = nullptr; - /// This is initializer for the initial value of #CounterVar. - Expr *CounterInit = nullptr; - /// This is step for the #CounterVar used to generate its update: - /// #CounterVar = #CounterInit + #CounterStep * CurrentIteration. - Expr *CounterStep = nullptr; - /// Should step be subtracted? - bool Subtract = false; - /// Source range of the loop init. - SourceRange InitSrcRange; - /// Source range of the loop condition. - SourceRange CondSrcRange; - /// Source range of the loop increment. - SourceRange IncSrcRange; -}; - } // namespace void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { @@ -5604,13 +6469,14 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { if (!ISC.checkAndSetInit(Init, /*EmitDiags=*/false)) { if (ValueDecl *D = ISC.getLoopDecl()) { auto *VD = dyn_cast<VarDecl>(D); + DeclRefExpr *PrivateRef = nullptr; if (!VD) { if (VarDecl *Private = isOpenMPCapturedDecl(D)) { VD = Private; } else { - DeclRefExpr *Ref = buildCapture(*this, D, ISC.getLoopDeclRefExpr(), - /*WithInit=*/false); - VD = cast<VarDecl>(Ref->getDecl()); + PrivateRef = buildCapture(*this, D, ISC.getLoopDeclRefExpr(), + /*WithInit=*/false); + VD = cast<VarDecl>(PrivateRef->getDecl()); } } DSAStack->addLoopControlVariable(D, VD); @@ -5623,6 +6489,51 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { Var->getType().getNonLValueExprType(Context), ForLoc, /*RefersToCapture=*/true)); } + OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); + // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables + // Referenced in a Construct, C/C++]. The loop iteration variable in the + // associated for-loop of a simd construct with just one associated + // for-loop may be listed in a linear clause with a constant-linear-step + // that is the increment of the associated for-loop. The loop iteration + // variable(s) in the associated for-loop(s) of a for or parallel for + // construct may be listed in a private or lastprivate clause. + DSAStackTy::DSAVarData DVar = + DSAStack->getTopDSA(D, /*FromParent=*/false); + // If LoopVarRefExpr is nullptr it means the corresponding loop variable + // is declared in the loop and it is predetermined as a private. + Expr *LoopDeclRefExpr = ISC.getLoopDeclRefExpr(); + OpenMPClauseKind PredeterminedCKind = + isOpenMPSimdDirective(DKind) + ? (DSAStack->hasMutipleLoops() ? OMPC_lastprivate : OMPC_linear) + : OMPC_private; + if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && + DVar.CKind != PredeterminedCKind && DVar.RefExpr && + (LangOpts.OpenMP <= 45 || (DVar.CKind != OMPC_lastprivate && + DVar.CKind != OMPC_private))) || + ((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop || + DKind == OMPD_master_taskloop || + DKind == OMPD_parallel_master_taskloop || + isOpenMPDistributeDirective(DKind)) && + !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && + DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) && + (DVar.CKind != OMPC_private || DVar.RefExpr)) { + Diag(Init->getBeginLoc(), diag::err_omp_loop_var_dsa) + << getOpenMPClauseName(DVar.CKind) + << getOpenMPDirectiveName(DKind) + << getOpenMPClauseName(PredeterminedCKind); + if (DVar.RefExpr == nullptr) + DVar.CKind = PredeterminedCKind; + reportOriginalDsa(*this, DSAStack, D, DVar, + /*IsLoopIterVar=*/true); + } else if (LoopDeclRefExpr) { + // Make the loop iteration variable private (for worksharing + // constructs), linear (for simd directives with the only one + // associated loop) or lastprivate (for simd directives with several + // collapsed or ordered loops). + if (DVar.CKind == OMPC_unknown) + DSAStack->addDSA(D, LoopDeclRefExpr, PredeterminedCKind, + PrivateRef); + } } } DSAStack->setAssociatedLoops(AssociatedLoops - 1); @@ -5637,12 +6548,15 @@ static bool checkOpenMPIterationSpace( unsigned TotalNestedLoopCount, Expr *CollapseLoopCountExpr, Expr *OrderedLoopCountExpr, Sema::VarsWithInheritedDSAType &VarsWithImplicitDSA, - LoopIterationSpace &ResultIterSpace, + llvm::MutableArrayRef<LoopIterationSpace> ResultIterSpaces, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) { - // OpenMP [2.6, Canonical Loop Form] + // OpenMP [2.9.1, Canonical Loop Form] // for (init-expr; test-expr; incr-expr) structured-block + // for (range-decl: range-expr) structured-block auto *For = dyn_cast_or_null<ForStmt>(S); - if (!For) { + auto *CXXFor = dyn_cast_or_null<CXXForRangeStmt>(S); + // Ranged for is supported only in OpenMP 5.0. + if (!For && (SemaRef.LangOpts.OpenMP <= 45 || !CXXFor)) { SemaRef.Diag(S->getBeginLoc(), diag::err_omp_not_for) << (CollapseLoopCountExpr != nullptr || OrderedLoopCountExpr != nullptr) << getOpenMPDirectiveName(DKind) << TotalNestedLoopCount @@ -5664,12 +6578,14 @@ static bool checkOpenMPIterationSpace( } return true; } - assert(For->getBody()); + assert(((For && For->getBody()) || (CXXFor && CXXFor->getBody())) && + "No loop body."); - OpenMPIterationSpaceChecker ISC(SemaRef, DSA, For->getForLoc()); + OpenMPIterationSpaceChecker ISC(SemaRef, DSA, + For ? For->getForLoc() : CXXFor->getForLoc()); // Check init. - Stmt *Init = For->getInit(); + Stmt *Init = For ? For->getInit() : CXXFor->getBeginStmt(); if (ISC.checkAndSetInit(Init)) return true; @@ -5677,8 +6593,6 @@ static bool checkOpenMPIterationSpace( // Check loop variable's type. if (ValueDecl *LCDecl = ISC.getLoopDecl()) { - Expr *LoopDeclRefExpr = ISC.getLoopDeclRefExpr(); - // OpenMP [2.6, Canonical Loop Form] // Var is one of the following: // A variable of signed or unsigned integer type. @@ -5704,90 +6618,70 @@ static bool checkOpenMPIterationSpace( // sharing attributes. VarsWithImplicitDSA.erase(LCDecl); - // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced - // in a Construct, C/C++]. - // The loop iteration variable in the associated for-loop of a simd - // construct with just one associated for-loop may be listed in a linear - // clause with a constant-linear-step that is the increment of the - // associated for-loop. - // The loop iteration variable(s) in the associated for-loop(s) of a for or - // parallel for construct may be listed in a private or lastprivate clause. - DSAStackTy::DSAVarData DVar = DSA.getTopDSA(LCDecl, false); - // If LoopVarRefExpr is nullptr it means the corresponding loop variable is - // declared in the loop and it is predetermined as a private. - OpenMPClauseKind PredeterminedCKind = - isOpenMPSimdDirective(DKind) - ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate) - : OMPC_private; - if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && - DVar.CKind != PredeterminedCKind && DVar.RefExpr && - (SemaRef.getLangOpts().OpenMP <= 45 || - (DVar.CKind != OMPC_lastprivate && DVar.CKind != OMPC_private))) || - ((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop || - isOpenMPDistributeDirective(DKind)) && - !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && - DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) && - (DVar.CKind != OMPC_private || DVar.RefExpr)) { - SemaRef.Diag(Init->getBeginLoc(), diag::err_omp_loop_var_dsa) - << getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind) - << getOpenMPClauseName(PredeterminedCKind); - if (DVar.RefExpr == nullptr) - DVar.CKind = PredeterminedCKind; - reportOriginalDsa(SemaRef, &DSA, LCDecl, DVar, /*IsLoopIterVar=*/true); - HasErrors = true; - } else if (LoopDeclRefExpr != nullptr) { - // Make the loop iteration variable private (for worksharing constructs), - // linear (for simd directives with the only one associated loop) or - // lastprivate (for simd directives with several collapsed or ordered - // loops). - if (DVar.CKind == OMPC_unknown) - DSA.addDSA(LCDecl, LoopDeclRefExpr, PredeterminedCKind); - } - assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars"); // Check test-expr. - HasErrors |= ISC.checkAndSetCond(For->getCond()); + HasErrors |= ISC.checkAndSetCond(For ? For->getCond() : CXXFor->getCond()); // Check incr-expr. - HasErrors |= ISC.checkAndSetInc(For->getInc()); + HasErrors |= ISC.checkAndSetInc(For ? For->getInc() : CXXFor->getInc()); } if (ISC.dependent() || SemaRef.CurContext->isDependentContext() || HasErrors) return HasErrors; // Build the loop's iteration space representation. - ResultIterSpace.PreCond = - ISC.buildPreCond(DSA.getCurScope(), For->getCond(), Captures); - ResultIterSpace.NumIterations = ISC.buildNumIterations( - DSA.getCurScope(), - (isOpenMPWorksharingDirective(DKind) || - isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)), - Captures); - ResultIterSpace.CounterVar = ISC.buildCounterVar(Captures, DSA); - ResultIterSpace.PrivateCounterVar = ISC.buildPrivateCounterVar(); - ResultIterSpace.CounterInit = ISC.buildCounterInit(); - ResultIterSpace.CounterStep = ISC.buildCounterStep(); - ResultIterSpace.InitSrcRange = ISC.getInitSrcRange(); - ResultIterSpace.CondSrcRange = ISC.getConditionSrcRange(); - ResultIterSpace.IncSrcRange = ISC.getIncrementSrcRange(); - ResultIterSpace.Subtract = ISC.shouldSubtractStep(); - ResultIterSpace.IsStrictCompare = ISC.isStrictTestOp(); - - HasErrors |= (ResultIterSpace.PreCond == nullptr || - ResultIterSpace.NumIterations == nullptr || - ResultIterSpace.CounterVar == nullptr || - ResultIterSpace.PrivateCounterVar == nullptr || - ResultIterSpace.CounterInit == nullptr || - ResultIterSpace.CounterStep == nullptr); + ResultIterSpaces[CurrentNestedLoopCount].PreCond = ISC.buildPreCond( + DSA.getCurScope(), For ? For->getCond() : CXXFor->getCond(), Captures); + ResultIterSpaces[CurrentNestedLoopCount].NumIterations = + ISC.buildNumIterations(DSA.getCurScope(), ResultIterSpaces, + (isOpenMPWorksharingDirective(DKind) || + isOpenMPTaskLoopDirective(DKind) || + isOpenMPDistributeDirective(DKind)), + Captures); + ResultIterSpaces[CurrentNestedLoopCount].CounterVar = + ISC.buildCounterVar(Captures, DSA); + ResultIterSpaces[CurrentNestedLoopCount].PrivateCounterVar = + ISC.buildPrivateCounterVar(); + ResultIterSpaces[CurrentNestedLoopCount].CounterInit = ISC.buildCounterInit(); + ResultIterSpaces[CurrentNestedLoopCount].CounterStep = ISC.buildCounterStep(); + ResultIterSpaces[CurrentNestedLoopCount].InitSrcRange = ISC.getInitSrcRange(); + ResultIterSpaces[CurrentNestedLoopCount].CondSrcRange = + ISC.getConditionSrcRange(); + ResultIterSpaces[CurrentNestedLoopCount].IncSrcRange = + ISC.getIncrementSrcRange(); + ResultIterSpaces[CurrentNestedLoopCount].Subtract = ISC.shouldSubtractStep(); + ResultIterSpaces[CurrentNestedLoopCount].IsStrictCompare = + ISC.isStrictTestOp(); + std::tie(ResultIterSpaces[CurrentNestedLoopCount].MinValue, + ResultIterSpaces[CurrentNestedLoopCount].MaxValue) = + ISC.buildMinMaxValues(DSA.getCurScope(), Captures); + ResultIterSpaces[CurrentNestedLoopCount].FinalCondition = + ISC.buildFinalCondition(DSA.getCurScope()); + ResultIterSpaces[CurrentNestedLoopCount].IsNonRectangularLB = + ISC.doesInitDependOnLC(); + ResultIterSpaces[CurrentNestedLoopCount].IsNonRectangularUB = + ISC.doesCondDependOnLC(); + ResultIterSpaces[CurrentNestedLoopCount].LoopDependentIdx = + ISC.getLoopDependentIdx(); + + HasErrors |= + (ResultIterSpaces[CurrentNestedLoopCount].PreCond == nullptr || + ResultIterSpaces[CurrentNestedLoopCount].NumIterations == nullptr || + ResultIterSpaces[CurrentNestedLoopCount].CounterVar == nullptr || + ResultIterSpaces[CurrentNestedLoopCount].PrivateCounterVar == nullptr || + ResultIterSpaces[CurrentNestedLoopCount].CounterInit == nullptr || + ResultIterSpaces[CurrentNestedLoopCount].CounterStep == nullptr); if (!HasErrors && DSA.isOrderedRegion()) { if (DSA.getOrderedRegionParam().second->getNumForLoops()) { if (CurrentNestedLoopCount < DSA.getOrderedRegionParam().second->getLoopNumIterations().size()) { DSA.getOrderedRegionParam().second->setLoopNumIterations( - CurrentNestedLoopCount, ResultIterSpace.NumIterations); + CurrentNestedLoopCount, + ResultIterSpaces[CurrentNestedLoopCount].NumIterations); DSA.getOrderedRegionParam().second->setLoopCounter( - CurrentNestedLoopCount, ResultIterSpace.CounterVar); + CurrentNestedLoopCount, + ResultIterSpaces[CurrentNestedLoopCount].CounterVar); } } for (auto &Pair : DSA.getDoacrossDependClauses()) { @@ -5804,11 +6698,13 @@ static bool checkOpenMPIterationSpace( Expr *CntValue; if (Pair.first->getDependencyKind() == OMPC_DEPEND_source) CntValue = ISC.buildOrderedLoopData( - DSA.getCurScope(), ResultIterSpace.CounterVar, Captures, + DSA.getCurScope(), + ResultIterSpaces[CurrentNestedLoopCount].CounterVar, Captures, Pair.first->getDependencyLoc()); else CntValue = ISC.buildOrderedLoopData( - DSA.getCurScope(), ResultIterSpace.CounterVar, Captures, + DSA.getCurScope(), + ResultIterSpaces[CurrentNestedLoopCount].CounterVar, Captures, Pair.first->getDependencyLoc(), Pair.second[CurrentNestedLoopCount].first, Pair.second[CurrentNestedLoopCount].second); @@ -5822,10 +6718,12 @@ static bool checkOpenMPIterationSpace( /// Build 'VarRef = Start. static ExprResult buildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef, - ExprResult Start, + ExprResult Start, bool IsNonRectangularLB, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) { // Build 'VarRef = Start. - ExprResult NewStart = tryBuildCapture(SemaRef, Start.get(), Captures); + ExprResult NewStart = IsNonRectangularLB + ? Start.get() + : tryBuildCapture(SemaRef, Start.get(), Captures); if (!NewStart.isUsable()) return ExprError(); if (!SemaRef.Context.hasSameType(NewStart.get()->getType(), @@ -5846,6 +6744,7 @@ buildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef, static ExprResult buildCounterUpdate( Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef, ExprResult Start, ExprResult Iter, ExprResult Step, bool Subtract, + bool IsNonRectangularLB, llvm::MapVector<const Expr *, DeclRefExpr *> *Captures = nullptr) { // Add parentheses (for debugging purposes only). Iter = SemaRef.ActOnParenExpr(Loc, Loc, Iter.get()); @@ -5865,8 +6764,12 @@ static ExprResult buildCounterUpdate( // Try to build 'VarRef = Start, VarRef (+|-)= Iter * Step' or // 'VarRef = Start (+|-) Iter * Step'. - ExprResult NewStart = Start; - if (Captures) + if (!Start.isUsable()) + return ExprError(); + ExprResult NewStart = SemaRef.ActOnParenExpr(Loc, Loc, Start.get()); + if (!NewStart.isUsable()) + return ExprError(); + if (Captures && !IsNonRectangularLB) NewStart = tryBuildCapture(SemaRef, Start.get(), *Captures); if (NewStart.isInvalid()) return ExprError(); @@ -5877,8 +6780,8 @@ static ExprResult buildCounterUpdate( if (VarRef.get()->getType()->isOverloadableType() || NewStart.get()->getType()->isOverloadableType() || Update.get()->getType()->isOverloadableType()) { - bool Suppress = SemaRef.getDiagnostics().getSuppressAllDiagnostics(); - SemaRef.getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true); + Sema::TentativeAnalysisScope Trap(SemaRef); + Update = SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), NewStart.get()); if (Update.isUsable()) { @@ -5890,7 +6793,6 @@ static ExprResult buildCounterUpdate( UpdateVal.get()); } } - SemaRef.getDiagnostics().setSuppressAllDiagnostics(Suppress); } // Second attempt: try to build 'VarRef = Start (+|-) Iter * Step'. @@ -6037,22 +6939,27 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, if (checkOpenMPIterationSpace( DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount, std::max(OrderedLoopCount, NestedLoopCount), CollapseLoopCountExpr, - OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces[Cnt], - Captures)) + OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces, Captures)) return 0; // Move on to the next nested for loop, or to the loop body. // OpenMP [2.8.1, simd construct, Restrictions] // All loops associated with the construct must be perfectly nested; that // is, there must be no intervening code nor any OpenMP directive between // any two loops. - CurStmt = cast<ForStmt>(CurStmt)->getBody()->IgnoreContainers(); + if (auto *For = dyn_cast<ForStmt>(CurStmt)) { + CurStmt = For->getBody(); + } else { + assert(isa<CXXForRangeStmt>(CurStmt) && + "Expected canonical for or range-based for loops."); + CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody(); + } + CurStmt = CurStmt->IgnoreContainers(); } for (unsigned Cnt = NestedLoopCount; Cnt < OrderedLoopCount; ++Cnt) { if (checkOpenMPIterationSpace( DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount, std::max(OrderedLoopCount, NestedLoopCount), CollapseLoopCountExpr, - OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces[Cnt], - Captures)) + OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces, Captures)) return 0; if (Cnt > 0 && IterSpaces[Cnt].CounterVar) { // Handle initialization of captured loop iterator variables. @@ -6066,7 +6973,14 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, // All loops associated with the construct must be perfectly nested; that // is, there must be no intervening code nor any OpenMP directive between // any two loops. - CurStmt = cast<ForStmt>(CurStmt)->getBody()->IgnoreContainers(); + if (auto *For = dyn_cast<ForStmt>(CurStmt)) { + CurStmt = For->getBody(); + } else { + assert(isa<CXXForRangeStmt>(CurStmt) && + "Expected canonical for or range-based for loops."); + CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody(); + } + CurStmt = CurStmt->IgnoreContainers(); } Built.clear(/* size */ NestedLoopCount); @@ -6513,6 +7427,9 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Built.Inits.resize(NestedLoopCount); Built.Updates.resize(NestedLoopCount); Built.Finals.resize(NestedLoopCount); + Built.DependentCounters.resize(NestedLoopCount); + Built.DependentInits.resize(NestedLoopCount); + Built.FinalsConditions.resize(NestedLoopCount); { // We implement the following algorithm for obtaining the // original loop iteration variable values based on the @@ -6572,24 +7489,26 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, DeclRefExpr *CounterVar = buildDeclRefExpr( SemaRef, VD, IS.CounterVar->getType(), IS.CounterVar->getExprLoc(), /*RefersToCapture=*/true); - ExprResult Init = buildCounterInit(SemaRef, CurScope, UpdLoc, CounterVar, - IS.CounterInit, Captures); + ExprResult Init = + buildCounterInit(SemaRef, CurScope, UpdLoc, CounterVar, + IS.CounterInit, IS.IsNonRectangularLB, Captures); if (!Init.isUsable()) { HasErrors = true; break; } ExprResult Update = buildCounterUpdate( SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, Iter, - IS.CounterStep, IS.Subtract, &Captures); + IS.CounterStep, IS.Subtract, IS.IsNonRectangularLB, &Captures); if (!Update.isUsable()) { HasErrors = true; break; } // Build final: IS.CounterVar = IS.Start + IS.NumIters * IS.Step - ExprResult Final = buildCounterUpdate( - SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, - IS.NumIterations, IS.CounterStep, IS.Subtract, &Captures); + ExprResult Final = + buildCounterUpdate(SemaRef, CurScope, UpdLoc, CounterVar, + IS.CounterInit, IS.NumIterations, IS.CounterStep, + IS.Subtract, IS.IsNonRectangularLB, &Captures); if (!Final.isUsable()) { HasErrors = true; break; @@ -6605,6 +7524,16 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Built.Inits[Cnt] = Init.get(); Built.Updates[Cnt] = Update.get(); Built.Finals[Cnt] = Final.get(); + Built.DependentCounters[Cnt] = nullptr; + Built.DependentInits[Cnt] = nullptr; + Built.FinalsConditions[Cnt] = nullptr; + if (IS.IsNonRectangularLB || IS.IsNonRectangularUB) { + Built.DependentCounters[Cnt] = + Built.Counters[NestedLoopCount - 1 - IS.LoopDependentIdx]; + Built.DependentInits[Cnt] = + Built.Inits[NestedLoopCount - 1 - IS.LoopDependentIdx]; + Built.FinalsConditions[Cnt] = IS.FinalCondition; + } } } @@ -6617,7 +7546,7 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Built.NumIterations = NumIterations.get(); Built.CalcLastIteration = SemaRef .ActOnFinishFullExpr(CalcLastIteration.get(), - /*DiscardedValue*/ false) + /*DiscardedValue=*/false) .get(); Built.PreCond = PreCond.get(); Built.PreInits = buildPreInits(C, Captures); @@ -8398,6 +9327,146 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective( NestedLoopCount, Clauses, AStmt, B); } +StmtResult Sema::ActOnOpenMPMasterTaskLoopDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { + if (!AStmt) + return StmtError(); + + assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); + OMPLoopDirective::HelperExprs B; + // In presence of clause 'collapse' or 'ordered' with number of loops, it will + // define the nested loops number. + unsigned NestedLoopCount = + checkOpenMPLoop(OMPD_master_taskloop, getCollapseNumberExpr(Clauses), + /*OrderedLoopCountExpr=*/nullptr, AStmt, *this, *DSAStack, + VarsWithImplicitDSA, B); + if (NestedLoopCount == 0) + return StmtError(); + + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp for loop exprs were not built"); + + // OpenMP, [2.9.2 taskloop Construct, Restrictions] + // The grainsize clause and num_tasks clause are mutually exclusive and may + // not appear on the same taskloop directive. + if (checkGrainsizeNumTasksClauses(*this, Clauses)) + return StmtError(); + // OpenMP, [2.9.2 taskloop Construct, Restrictions] + // If a reduction clause is present on the taskloop directive, the nogroup + // clause must not be specified. + if (checkReductionClauseWithNogroup(*this, Clauses)) + return StmtError(); + + setFunctionHasBranchProtectedScope(); + return OMPMasterTaskLoopDirective::Create(Context, StartLoc, EndLoc, + NestedLoopCount, Clauses, AStmt, B); +} + +StmtResult Sema::ActOnOpenMPMasterTaskLoopSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { + if (!AStmt) + return StmtError(); + + assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); + OMPLoopDirective::HelperExprs B; + // In presence of clause 'collapse' or 'ordered' with number of loops, it will + // define the nested loops number. + unsigned NestedLoopCount = + checkOpenMPLoop(OMPD_master_taskloop_simd, getCollapseNumberExpr(Clauses), + /*OrderedLoopCountExpr=*/nullptr, AStmt, *this, *DSAStack, + VarsWithImplicitDSA, B); + if (NestedLoopCount == 0) + return StmtError(); + + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp for loop exprs were not built"); + + if (!CurContext->isDependentContext()) { + // Finalize the clauses that need pre-built expressions for CodeGen. + for (OMPClause *C : Clauses) { + if (auto *LC = dyn_cast<OMPLinearClause>(C)) + if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), + B.NumIterations, *this, CurScope, + DSAStack)) + return StmtError(); + } + } + + // OpenMP, [2.9.2 taskloop Construct, Restrictions] + // The grainsize clause and num_tasks clause are mutually exclusive and may + // not appear on the same taskloop directive. + if (checkGrainsizeNumTasksClauses(*this, Clauses)) + return StmtError(); + // OpenMP, [2.9.2 taskloop Construct, Restrictions] + // If a reduction clause is present on the taskloop directive, the nogroup + // clause must not be specified. + if (checkReductionClauseWithNogroup(*this, Clauses)) + return StmtError(); + if (checkSimdlenSafelenSpecified(*this, Clauses)) + return StmtError(); + + setFunctionHasBranchProtectedScope(); + return OMPMasterTaskLoopSimdDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); +} + +StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { + if (!AStmt) + return StmtError(); + + assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); + auto *CS = cast<CapturedStmt>(AStmt); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = + getOpenMPCaptureLevels(OMPD_parallel_master_taskloop); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + } + + OMPLoopDirective::HelperExprs B; + // In presence of clause 'collapse' or 'ordered' with number of loops, it will + // define the nested loops number. + unsigned NestedLoopCount = checkOpenMPLoop( + OMPD_parallel_master_taskloop, getCollapseNumberExpr(Clauses), + /*OrderedLoopCountExpr=*/nullptr, CS, *this, *DSAStack, + VarsWithImplicitDSA, B); + if (NestedLoopCount == 0) + return StmtError(); + + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp for loop exprs were not built"); + + // OpenMP, [2.9.2 taskloop Construct, Restrictions] + // The grainsize clause and num_tasks clause are mutually exclusive and may + // not appear on the same taskloop directive. + if (checkGrainsizeNumTasksClauses(*this, Clauses)) + return StmtError(); + // OpenMP, [2.9.2 taskloop Construct, Restrictions] + // If a reduction clause is present on the taskloop directive, the nogroup + // clause must not be specified. + if (checkReductionClauseWithNogroup(*this, Clauses)) + return StmtError(); + + setFunctionHasBranchProtectedScope(); + return OMPParallelMasterTaskLoopDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); +} + StmtResult Sema::ActOnOpenMPDistributeDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { @@ -9246,6 +10315,8 @@ 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: + case OMPC_match: llvm_unreachable("Clause is not allowed."); } return Res; @@ -9287,6 +10358,10 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_target_exit_data: CaptureRegion = OMPD_task; break; + case OMPD_parallel_master_taskloop: + if (NameModifier == OMPD_unknown || NameModifier == OMPD_taskloop) + CaptureRegion = OMPD_parallel; + break; case OMPD_cancel: case OMPD_parallel: case OMPD_parallel_sections: @@ -9302,6 +10377,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_task: case OMPD_taskloop: case OMPD_taskloop_simd: + case OMPD_master_taskloop: + case OMPD_master_taskloop_simd: case OMPD_target_data: // Do not capture if-clause expressions. break; @@ -9315,6 +10392,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_teams: @@ -9358,6 +10436,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_parallel_for_simd: case OMPD_distribute_parallel_for: case OMPD_distribute_parallel_for_simd: + case OMPD_parallel_master_taskloop: // Do not capture num_threads-clause expressions. break; case OMPD_target_data: @@ -9373,6 +10452,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_task: case OMPD_taskloop: case OMPD_taskloop_simd: + case OMPD_master_taskloop: + case OMPD_master_taskloop_simd: case OMPD_threadprivate: case OMPD_allocate: case OMPD_taskyield: @@ -9383,6 +10464,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_teams: @@ -9428,6 +10510,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_task: case OMPD_taskloop: case OMPD_taskloop_simd: + case OMPD_master_taskloop: + case OMPD_master_taskloop_simd: + case OMPD_parallel_master_taskloop: case OMPD_target_data: case OMPD_target_enter_data: case OMPD_target_exit_data: @@ -9452,6 +10537,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -9494,6 +10580,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_task: case OMPD_taskloop: case OMPD_taskloop_simd: + case OMPD_master_taskloop: + case OMPD_master_taskloop_simd: + case OMPD_parallel_master_taskloop: case OMPD_target_data: case OMPD_target_enter_data: case OMPD_target_exit_data: @@ -9518,6 +10607,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -9560,6 +10650,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_task: case OMPD_taskloop: case OMPD_taskloop_simd: + case OMPD_master_taskloop: + case OMPD_master_taskloop_simd: + case OMPD_parallel_master_taskloop: case OMPD_target_data: case OMPD_target_enter_data: case OMPD_target_exit_data: @@ -9585,6 +10678,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -9630,6 +10724,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_task: case OMPD_taskloop: case OMPD_taskloop_simd: + case OMPD_master_taskloop: + case OMPD_master_taskloop_simd: + case OMPD_parallel_master_taskloop: case OMPD_target_data: case OMPD_target_enter_data: case OMPD_target_exit_data: @@ -9651,6 +10748,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -9701,6 +10799,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_task: case OMPD_taskloop: case OMPD_taskloop_simd: + case OMPD_master_taskloop: + case OMPD_master_taskloop_simd: + case OMPD_parallel_master_taskloop: case OMPD_cancel: case OMPD_parallel: case OMPD_parallel_sections: @@ -9716,6 +10817,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -9737,6 +10839,78 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( llvm_unreachable("Unknown OpenMP directive"); } break; + case OMPC_grainsize: + case OMPC_num_tasks: + case OMPC_final: + case OMPC_priority: + switch (DKind) { + case OMPD_task: + case OMPD_taskloop: + case OMPD_taskloop_simd: + case OMPD_master_taskloop: + case OMPD_master_taskloop_simd: + break; + case OMPD_parallel_master_taskloop: + CaptureRegion = OMPD_parallel; + break; + case OMPD_target_update: + case OMPD_target_enter_data: + case OMPD_target_exit_data: + case OMPD_target: + case OMPD_target_simd: + case OMPD_target_teams: + case OMPD_target_parallel: + case OMPD_target_teams_distribute: + case OMPD_target_teams_distribute_simd: + case OMPD_target_parallel_for: + case OMPD_target_parallel_for_simd: + case OMPD_target_teams_distribute_parallel_for: + case OMPD_target_teams_distribute_parallel_for_simd: + case OMPD_target_data: + case OMPD_teams_distribute_parallel_for: + case OMPD_teams_distribute_parallel_for_simd: + case OMPD_teams: + case OMPD_teams_distribute: + case OMPD_teams_distribute_simd: + case OMPD_distribute_parallel_for: + case OMPD_distribute_parallel_for_simd: + case OMPD_cancel: + case OMPD_parallel: + case OMPD_parallel_sections: + case OMPD_parallel_for: + case OMPD_parallel_for_simd: + case OMPD_threadprivate: + case OMPD_allocate: + case OMPD_taskyield: + case OMPD_barrier: + case OMPD_taskwait: + case OMPD_cancellation_point: + case OMPD_flush: + case OMPD_declare_reduction: + case OMPD_declare_mapper: + case OMPD_declare_simd: + case OMPD_declare_variant: + case OMPD_declare_target: + case OMPD_end_declare_target: + case OMPD_simd: + case OMPD_for: + case OMPD_for_simd: + case OMPD_sections: + case OMPD_section: + case OMPD_single: + case OMPD_master: + case OMPD_critical: + case OMPD_taskgroup: + case OMPD_distribute: + case OMPD_ordered: + case OMPD_atomic: + case OMPD_distribute_simd: + case OMPD_requires: + llvm_unreachable("Unexpected OpenMP directive with grainsize-clause"); + case OMPD_unknown: + llvm_unreachable("Unknown OpenMP directive"); + } + break; case OMPC_firstprivate: case OMPC_lastprivate: case OMPC_reduction: @@ -9745,7 +10919,6 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_linear: case OMPC_default: case OMPC_proc_bind: - case OMPC_final: case OMPC_safelen: case OMPC_simdlen: case OMPC_allocator: @@ -9771,10 +10944,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_threads: case OMPC_simd: case OMPC_map: - case OMPC_priority: - case OMPC_grainsize: case OMPC_nogroup: - case OMPC_num_tasks: case OMPC_hint: case OMPC_defaultmap: case OMPC_unknown: @@ -9788,6 +10958,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_reverse_offload: case OMPC_dynamic_allocators: case OMPC_atomic_default_mem_order: + case OMPC_device_type: + case OMPC_match: llvm_unreachable("Unexpected OpenMP clause."); } return CaptureRegion; @@ -9832,6 +11004,8 @@ OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition, SourceLocation LParenLoc, SourceLocation EndLoc) { Expr *ValExpr = Condition; + Stmt *HelperValStmt = nullptr; + OpenMPDirectiveKind CaptureRegion = OMPD_unknown; if (!Condition->isValueDependent() && !Condition->isTypeDependent() && !Condition->isInstantiationDependent() && !Condition->containsUnexpandedParameterPack()) { @@ -9840,10 +11014,21 @@ OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition, return nullptr; ValExpr = MakeFullExpr(Val.get()).get(); + + OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); + CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_final); + if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) { + ValExpr = MakeFullExpr(ValExpr).get(); + llvm::MapVector<const Expr *, DeclRefExpr *> Captures; + ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); + HelperValStmt = buildPreInits(Context, Captures); + } } - return new (Context) OMPFinalClause(ValExpr, StartLoc, LParenLoc, EndLoc); + return new (Context) OMPFinalClause(ValExpr, HelperValStmt, CaptureRegion, + StartLoc, LParenLoc, EndLoc); } + ExprResult Sema::PerformOpenMPImplicitIntegerConversion(SourceLocation Loc, Expr *Op) { if (!Op) @@ -9888,9 +11073,12 @@ ExprResult Sema::PerformOpenMPImplicitIntegerConversion(SourceLocation Loc, return PerformContextualImplicitConversion(Loc, Op, ConvertDiagnoser); } -static bool isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef, - OpenMPClauseKind CKind, - bool StrictlyPositive) { +static bool +isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef, OpenMPClauseKind CKind, + bool StrictlyPositive, bool BuildCapture = false, + OpenMPDirectiveKind DKind = OMPD_unknown, + OpenMPDirectiveKind *CaptureRegion = nullptr, + Stmt **HelperValStmt = nullptr) { if (!ValExpr->isTypeDependent() && !ValExpr->isValueDependent() && !ValExpr->isInstantiationDependent()) { SourceLocation Loc = ValExpr->getExprLoc(); @@ -9911,6 +11099,16 @@ static bool isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef, << ValExpr->getSourceRange(); return false; } + if (!BuildCapture) + return true; + *CaptureRegion = getOpenMPCaptureRegionForClause(DKind, CKind); + if (*CaptureRegion != OMPD_unknown && + !SemaRef.CurContext->isDependentContext()) { + ValExpr = SemaRef.MakeFullExpr(ValExpr).get(); + llvm::MapVector<const Expr *, DeclRefExpr *> Captures; + ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures).get(); + *HelperValStmt = buildPreInits(SemaRef.Context, Captures); + } } return true; } @@ -10181,6 +11379,8 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_unified_shared_memory: case OMPC_reverse_offload: case OMPC_dynamic_allocators: + case OMPC_device_type: + case OMPC_match: llvm_unreachable("Clause is not allowed."); } return Res; @@ -10359,6 +11559,8 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_reverse_offload: case OMPC_dynamic_allocators: case OMPC_atomic_default_mem_order: + case OMPC_device_type: + case OMPC_match: llvm_unreachable("Clause is not allowed."); } return Res; @@ -10568,6 +11770,8 @@ 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: + case OMPC_match: llvm_unreachable("Clause is not allowed."); } return Res; @@ -10774,6 +11978,8 @@ OMPClause *Sema::ActOnOpenMPVarListClause( case OMPC_reverse_offload: case OMPC_dynamic_allocators: case OMPC_atomic_default_mem_order: + case OMPC_device_type: + case OMPC_match: llvm_unreachable("Clause is not allowed."); } return Res; @@ -10874,7 +12080,13 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, // OpenMP 4.5 [2.15.5.1, Restrictions, p.3] // A list item cannot appear in both a map clause and a data-sharing // attribute clause on the same construct - if (isOpenMPTargetExecutionDirective(CurrDir)) { + // + // OpenMP 5.0 [2.19.7.1, Restrictions, p.7] + // A list item cannot appear in both a map clause and a data-sharing + // attribute clause on the same construct unless the construct is a + // combined construct. + if ((LangOpts.OpenMP <= 45 && isOpenMPTargetExecutionDirective(CurrDir)) || + CurrDir == OMPD_target) { OpenMPClauseKind ConflictKind; if (DSAStack->checkMappableExprComponentListsForDecl( VD, /*CurrentRegionOnly=*/true, @@ -11109,7 +12321,14 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // OpenMP 4.5 [2.15.5.1, Restrictions, p.3] // A list item cannot appear in both a map clause and a data-sharing // attribute clause on the same construct - if (isOpenMPTargetExecutionDirective(CurrDir)) { + // + // OpenMP 5.0 [2.19.7.1, Restrictions, p.7] + // A list item cannot appear in both a map clause and a data-sharing + // attribute clause on the same construct unless the construct is a + // combined construct. + if ((LangOpts.OpenMP <= 45 && + isOpenMPTargetExecutionDirective(CurrDir)) || + CurrDir == OMPD_target) { OpenMPClauseKind ConflictKind; if (DSAStack->checkMappableExprComponentListsForDecl( VD, /*CurrentRegionOnly=*/true, @@ -12133,8 +13352,9 @@ static bool actOnOMPReductionKindClause( // If we don't have a single element, we must emit a constant array type. if (ConstantLengthOASE && !SingleElement) { for (llvm::APSInt &Size : ArraySizes) - PrivateTy = Context.getConstantArrayType( - PrivateTy, Size, ArrayType::Normal, /*IndexTypeQuals=*/0); + PrivateTy = Context.getConstantArrayType(PrivateTy, Size, nullptr, + ArrayType::Normal, + /*IndexTypeQuals=*/0); } } @@ -12707,6 +13927,7 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, // Walk the vars and build update/final expressions for the CodeGen. SmallVector<Expr *, 8> Updates; SmallVector<Expr *, 8> Finals; + SmallVector<Expr *, 8> UsedExprs; Expr *Step = Clause.getStep(); Expr *CalcStep = Clause.getCalcStep(); // OpenMP [2.14.3.7, linear clause] @@ -12760,9 +13981,9 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, // Build update: Var = InitExpr + IV * Step ExprResult Update; if (!Info.first) - Update = - buildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), *CurPrivate, - InitExpr, IV, Step, /* Subtract */ false); + Update = buildCounterUpdate( + SemaRef, S, RefExpr->getExprLoc(), *CurPrivate, InitExpr, IV, Step, + /*Subtract=*/false, /*IsNonRectangularLB=*/false); else Update = *CurPrivate; Update = SemaRef.ActOnFinishFullExpr(Update.get(), DE->getBeginLoc(), @@ -12773,7 +13994,8 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, if (!Info.first) Final = buildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), CapturedRef, - InitExpr, NumIterations, Step, /*Subtract=*/false); + InitExpr, NumIterations, Step, /*Subtract=*/false, + /*IsNonRectangularLB=*/false); else Final = *CurPrivate; Final = SemaRef.ActOnFinishFullExpr(Final.get(), DE->getBeginLoc(), @@ -12782,16 +14004,24 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, if (!Update.isUsable() || !Final.isUsable()) { Updates.push_back(nullptr); Finals.push_back(nullptr); + UsedExprs.push_back(nullptr); HasErrors = true; } else { Updates.push_back(Update.get()); Finals.push_back(Final.get()); + if (!Info.first) + UsedExprs.push_back(SimpleRefExpr); } ++CurInit; ++CurPrivate; } + if (Expr *S = Clause.getStep()) + UsedExprs.push_back(S); + // Fill the remaining part with the nullptr. + UsedExprs.append(Clause.varlist_size() + 1 - UsedExprs.size(), nullptr); Clause.setUpdates(Updates); Clause.setFinals(Finals); + Clause.setUsedExprs(UsedExprs); return HasErrors; } @@ -13216,11 +14446,13 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, << RefExpr->getSourceRange(); continue; } - bool Suppress = getDiagnostics().getSuppressAllDiagnostics(); - getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true); - ExprResult Res = - CreateBuiltinUnaryOp(ELoc, UO_AddrOf, RefExpr->IgnoreParenImpCasts()); - getDiagnostics().setSuppressAllDiagnostics(Suppress); + + ExprResult Res; + { + Sema::TentativeAnalysisScope Trap(*this); + Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, + RefExpr->IgnoreParenImpCasts()); + } if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr)) { Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) << RefExpr->getSourceRange(); @@ -13884,6 +15116,11 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S, Expr *UnresolvedMapper) { if (MapperIdScopeSpec.isInvalid()) return ExprError(); + // Get the actual type for the array type. + if (Type->isArrayType()) { + assert(Type->getAsArrayTypeUnsafe() && "Expect to get a valid array type"); + Type = Type->getAsArrayTypeUnsafe()->getElementType().getCanonicalType(); + } // Find all user-defined mappers with the given MapperId. SmallVector<UnresolvedSet<8>, 4> Lookups; LookupResult Lookup(SemaRef, MapperId, Sema::LookupOMPMapperName); @@ -13930,11 +15167,14 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S, MapperIdScopeSpec.getWithLocInContext(SemaRef.Context), MapperId, /*ADL=*/false, /*Overloaded=*/true, URS.begin(), URS.end()); } + SourceLocation Loc = MapperId.getLoc(); // [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions // The type must be of struct, union or class type in C and C++ - if (!Type->isStructureOrClassType() && !Type->isUnionType()) - return ExprEmpty(); - SourceLocation Loc = MapperId.getLoc(); + if (!Type->isStructureOrClassType() && !Type->isUnionType() && + (MapperIdScopeSpec.isSet() || MapperId.getAsString() != "default")) { + SemaRef.Diag(Loc, diag::err_omp_mapper_wrong_type); + return ExprError(); + } // Perform argument dependent lookup. if (SemaRef.getLangOpts().CPlusPlus && !MapperIdScopeSpec.isSet()) argumentDependentLookup(SemaRef, MapperId, Loc, Type, Lookups); @@ -14211,7 +15451,14 @@ static void checkMappableExpressionList( // OpenMP 4.5 [2.15.5.1, Restrictions, p.3] // A list item cannot appear in both a map clause and a data-sharing // attribute clause on the same construct - if (VD && isOpenMPTargetExecutionDirective(DKind)) { + // + // OpenMP 5.0 [2.19.7.1, Restrictions, p.7] + // A list item cannot appear in both a map clause and a data-sharing + // attribute clause on the same construct unless the construct is a + // combined construct. + if (VD && ((SemaRef.LangOpts.OpenMP <= 45 && + isOpenMPTargetExecutionDirective(DKind)) || + DKind == OMPD_target)) { DSAStackTy::DSAVarData DVar = DSAS->getTopDSA(VD, /*FromParent=*/false); if (isOpenMPPrivate(DVar.CKind)) { SemaRef.Diag(ELoc, diag::err_omp_variable_in_given_clause_and_dsa) @@ -14745,14 +15992,19 @@ OMPClause *Sema::ActOnOpenMPPriorityClause(Expr *Priority, SourceLocation LParenLoc, SourceLocation EndLoc) { Expr *ValExpr = Priority; + Stmt *HelperValStmt = nullptr; + OpenMPDirectiveKind CaptureRegion = OMPD_unknown; // OpenMP [2.9.1, task Constrcut] // The priority-value is a non-negative numerical scalar expression. - if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_priority, - /*StrictlyPositive=*/false)) + if (!isNonNegativeIntegerValue( + ValExpr, *this, OMPC_priority, + /*StrictlyPositive=*/false, /*BuildCapture=*/true, + DSAStack->getCurrentDirective(), &CaptureRegion, &HelperValStmt)) return nullptr; - return new (Context) OMPPriorityClause(ValExpr, StartLoc, LParenLoc, EndLoc); + return new (Context) OMPPriorityClause(ValExpr, HelperValStmt, CaptureRegion, + StartLoc, LParenLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPGrainsizeClause(Expr *Grainsize, @@ -14760,15 +16012,20 @@ OMPClause *Sema::ActOnOpenMPGrainsizeClause(Expr *Grainsize, SourceLocation LParenLoc, SourceLocation EndLoc) { Expr *ValExpr = Grainsize; + Stmt *HelperValStmt = nullptr; + OpenMPDirectiveKind CaptureRegion = OMPD_unknown; // OpenMP [2.9.2, taskloop Constrcut] // The parameter of the grainsize clause must be a positive integer // expression. - if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_grainsize, - /*StrictlyPositive=*/true)) + if (!isNonNegativeIntegerValue( + ValExpr, *this, OMPC_grainsize, + /*StrictlyPositive=*/true, /*BuildCapture=*/true, + DSAStack->getCurrentDirective(), &CaptureRegion, &HelperValStmt)) return nullptr; - return new (Context) OMPGrainsizeClause(ValExpr, StartLoc, LParenLoc, EndLoc); + return new (Context) OMPGrainsizeClause(ValExpr, HelperValStmt, CaptureRegion, + StartLoc, LParenLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPNumTasksClause(Expr *NumTasks, @@ -14776,15 +16033,20 @@ OMPClause *Sema::ActOnOpenMPNumTasksClause(Expr *NumTasks, SourceLocation LParenLoc, SourceLocation EndLoc) { Expr *ValExpr = NumTasks; + Stmt *HelperValStmt = nullptr; + OpenMPDirectiveKind CaptureRegion = OMPD_unknown; // OpenMP [2.9.2, taskloop Constrcut] // The parameter of the num_tasks clause must be a positive integer // expression. - if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_num_tasks, - /*StrictlyPositive=*/true)) + if (!isNonNegativeIntegerValue( + ValExpr, *this, OMPC_num_tasks, + /*StrictlyPositive=*/true, /*BuildCapture=*/true, + DSAStack->getCurrentDirective(), &CaptureRegion, &HelperValStmt)) return nullptr; - return new (Context) OMPNumTasksClause(ValExpr, StartLoc, LParenLoc, EndLoc); + return new (Context) OMPNumTasksClause(ValExpr, HelperValStmt, CaptureRegion, + StartLoc, LParenLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc, @@ -14905,16 +16167,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()) { @@ -14925,33 +16186,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; } } @@ -14960,7 +16244,28 @@ static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR, if (!D || !isa<VarDecl>(D)) return; auto *VD = cast<VarDecl>(D); - if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD)) + Optional<OMPDeclareTargetDeclAttr::MapTypeTy> MapTy = + OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD); + if (SemaRef.LangOpts.OpenMP >= 50 && + (SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true) || + SemaRef.getCurBlock() || SemaRef.getCurCapturedRegion()) && + VD->hasGlobalStorage()) { + llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> MapTy = + OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD); + if (!MapTy || *MapTy != OMPDeclareTargetDeclAttr::MT_To) { + // OpenMP 5.0, 2.12.7 declare target Directive, Restrictions + // If a lambda declaration and definition appears between a + // declare target directive and the matching end declare target + // directive, all variables that are captured by the lambda + // expression must also appear in a to clause. + SemaRef.Diag(VD->getLocation(), + diag::err_omp_lambda_capture_in_declare_target_not_to); + SemaRef.Diag(SL, diag::note_var_explicitly_captured_here) + << VD << 0 << SR; + return; + } + } + if (MapTy.hasValue()) return; SemaRef.Diag(VD->getLocation(), diag::warn_omp_not_in_target_context); SemaRef.Diag(SL, diag::note_used_here) << SR; @@ -14969,7 +16274,7 @@ static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR, static bool checkValueDeclInTarget(SourceLocation SL, SourceRange SR, Sema &SemaRef, DSAStackTy *Stack, ValueDecl *VD) { - return VD->hasAttr<OMPDeclareTargetDeclAttr>() || + return OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD) || checkTypeMappable(SL, SR, SemaRef, Stack, VD->getType(), /*FullCheck=*/false); } @@ -14995,15 +16300,23 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, } if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(D)) D = FTD->getTemplatedDecl(); - if (const auto *FD = dyn_cast<FunctionDecl>(D)) { + if (auto *FD = dyn_cast<FunctionDecl>(D)) { llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res = OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(FD); - if (Res && *Res == OMPDeclareTargetDeclAttr::MT_Link) { - assert(IdLoc.isValid() && "Source location is expected"); + if (IdLoc.isValid() && Res && *Res == OMPDeclareTargetDeclAttr::MT_Link) { Diag(IdLoc, diag::err_omp_function_in_link_clause); Diag(FD->getLocation(), diag::note_defined_here) << FD; return; } + // Mark the function as must be emitted for the device. + 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 @@ -15016,7 +16329,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); |