diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp | 2746 |
1 files changed, 2248 insertions, 498 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp index ca67a1c..5dd8354 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp @@ -77,6 +77,11 @@ public: ImplicitDSALoc() {} }; +public: + struct MapInfo { + Expr *RefExpr; + }; + private: struct DSAInfo { OpenMPClauseKind Attributes; @@ -84,33 +89,41 @@ private: }; typedef llvm::SmallDenseMap<VarDecl *, DSAInfo, 64> DeclSAMapTy; typedef llvm::SmallDenseMap<VarDecl *, DeclRefExpr *, 64> AlignedMapTy; - typedef llvm::DenseSet<VarDecl *> LoopControlVariablesSetTy; + typedef llvm::DenseMap<VarDecl *, unsigned> LoopControlVariablesMapTy; + typedef llvm::SmallDenseMap<VarDecl *, MapInfo, 64> MappedDeclsTy; + typedef llvm::StringMap<std::pair<OMPCriticalDirective *, llvm::APSInt>> + CriticalsWithHintsTy; struct SharingMapTy { DeclSAMapTy SharingMap; AlignedMapTy AlignedMap; - LoopControlVariablesSetTy LCVSet; + MappedDeclsTy MappedDecls; + LoopControlVariablesMapTy LCVMap; DefaultDataSharingAttributes DefaultAttr; SourceLocation DefaultAttrLoc; OpenMPDirectiveKind Directive; DeclarationNameInfo DirectiveName; Scope *CurScope; SourceLocation ConstructLoc; - bool OrderedRegion; + /// \brief first argument (Expr *) contains optional argument of the + /// 'ordered' clause, the second one is true if the regions has 'ordered' + /// clause, false otherwise. + llvm::PointerIntPair<Expr *, 1, bool> OrderedRegion; bool NowaitRegion; - unsigned CollapseNumber; + bool CancelRegion; + unsigned AssociatedLoops; SourceLocation InnerTeamsRegionLoc; SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name, Scope *CurScope, SourceLocation Loc) - : SharingMap(), AlignedMap(), LCVSet(), DefaultAttr(DSA_unspecified), + : SharingMap(), AlignedMap(), LCVMap(), DefaultAttr(DSA_unspecified), Directive(DKind), DirectiveName(std::move(Name)), CurScope(CurScope), - ConstructLoc(Loc), OrderedRegion(false), NowaitRegion(false), - CollapseNumber(1), InnerTeamsRegionLoc() {} + ConstructLoc(Loc), OrderedRegion(), NowaitRegion(false), + CancelRegion(false), AssociatedLoops(1), InnerTeamsRegionLoc() {} SharingMapTy() - : SharingMap(), AlignedMap(), LCVSet(), DefaultAttr(DSA_unspecified), + : SharingMap(), AlignedMap(), LCVMap(), DefaultAttr(DSA_unspecified), Directive(OMPD_unknown), DirectiveName(), CurScope(nullptr), - ConstructLoc(), OrderedRegion(false), NowaitRegion(false), - CollapseNumber(1), InnerTeamsRegionLoc() {} + ConstructLoc(), OrderedRegion(), NowaitRegion(false), + CancelRegion(false), AssociatedLoops(1), InnerTeamsRegionLoc() {} }; typedef SmallVector<SharingMapTy, 64> StackTy; @@ -122,6 +135,7 @@ private: OpenMPClauseKind ClauseKindMode; Sema &SemaRef; bool ForceCapturing; + CriticalsWithHintsTy Criticals; typedef SmallVector<SharingMapTy, 8>::reverse_iterator reverse_iterator; @@ -152,6 +166,16 @@ public: Stack.pop_back(); } + void addCriticalWithHint(OMPCriticalDirective *D, llvm::APSInt Hint) { + Criticals[D->getDirectiveName().getAsString()] = std::make_pair(D, Hint); + } + const std::pair<OMPCriticalDirective *, llvm::APSInt> + getCriticalWithHint(const DeclarationNameInfo &Name) const { + auto I = Criticals.find(Name.getAsString()); + if (I != Criticals.end()) + return I->second; + return std::make_pair(nullptr, llvm::APSInt()); + } /// \brief If 'aligned' declaration for given variable \a D was not seen yet, /// add it and return NULL; otherwise return previous occurrence's expression /// for diagnostics. @@ -161,7 +185,17 @@ public: void addLoopControlVariable(VarDecl *D); /// \brief Check if the specified variable is a loop control variable for /// current region. - bool isLoopControlVariable(VarDecl *D); + /// \return The index of the loop control variable in the list of associated + /// for-loops (from outer to inner). + unsigned isLoopControlVariable(VarDecl *D); + /// \brief Check if the specified variable is a loop control variable for + /// parent region. + /// \return The index of the loop control variable in the list of associated + /// for-loops (from outer to inner). + unsigned isParentLoopControlVariable(VarDecl *D); + /// \brief Get the loop control variable for the I-th loop (or nullptr) in + /// parent directive. + VarDecl *getParentLoopControlVariable(unsigned I); /// \brief Adds explicit data sharing attribute to the specified declaration. void addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A); @@ -190,6 +224,13 @@ public: bool hasExplicitDSA(VarDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, unsigned Level); + + /// \brief Returns true if the directive at level \Level matches in the + /// specified \a DPred predicate. + bool hasExplicitDirective( + const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred, + unsigned Level); + /// \brief Finds a directive which matches specified \a DPred predicate. template <class NamedDirectivesPredicate> bool hasDirective(NamedDirectivesPredicate DPred, bool FromParent); @@ -204,6 +245,8 @@ public: return Stack[Stack.size() - 2].Directive; return OMPD_unknown; } + /// \brief Return the directive associated with the provided scope. + OpenMPDirectiveKind getDirectiveForScope(const Scope *S) const; /// \brief Set default data sharing attribute to none. void setDefaultDSANone(SourceLocation Loc) { @@ -230,16 +273,23 @@ public: } /// \brief Marks current region as ordered (it has an 'ordered' clause). - void setOrderedRegion(bool IsOrdered = true) { - Stack.back().OrderedRegion = IsOrdered; + void setOrderedRegion(bool IsOrdered, Expr *Param) { + Stack.back().OrderedRegion.setInt(IsOrdered); + Stack.back().OrderedRegion.setPointer(Param); } /// \brief Returns true, if parent region is ordered (has associated /// 'ordered' clause), false - otherwise. bool isParentOrderedRegion() const { if (Stack.size() > 2) - return Stack[Stack.size() - 2].OrderedRegion; + return Stack[Stack.size() - 2].OrderedRegion.getInt(); return false; } + /// \brief Returns optional parameter for the ordered region. + Expr *getParentOrderedRegionParam() const { + if (Stack.size() > 2) + return Stack[Stack.size() - 2].OrderedRegion.getPointer(); + return nullptr; + } /// \brief Marks current region as nowait (it has a 'nowait' clause). void setNowaitRegion(bool IsNowait = true) { Stack.back().NowaitRegion = IsNowait; @@ -251,13 +301,21 @@ public: return Stack[Stack.size() - 2].NowaitRegion; return false; } + /// \brief Marks parent region as cancel region. + void setParentCancelRegion(bool Cancel = true) { + if (Stack.size() > 2) + Stack[Stack.size() - 2].CancelRegion = + Stack[Stack.size() - 2].CancelRegion || Cancel; + } + /// \brief Return true if current region has inner cancel construct. + bool isCancelRegion() const { + return Stack.back().CancelRegion; + } /// \brief Set collapse value for the region. - void setCollapseNumber(unsigned Val) { Stack.back().CollapseNumber = Val; } + void setAssociatedLoops(unsigned Val) { Stack.back().AssociatedLoops = Val; } /// \brief Return collapse value for region. - unsigned getCollapseNumber() const { - return Stack.back().CollapseNumber; - } + unsigned getAssociatedLoops() const { return Stack.back().AssociatedLoops; } /// \brief Marks current target region as one with closely nested teams /// region. @@ -279,10 +337,37 @@ public: Scope *getCurScope() const { return Stack.back().CurScope; } Scope *getCurScope() { return Stack.back().CurScope; } SourceLocation getConstructLoc() { return Stack.back().ConstructLoc; } + + MapInfo getMapInfoForVar(VarDecl *VD) { + MapInfo VarMI = {0}; + for (auto Cnt = Stack.size() - 1; Cnt > 0; --Cnt) { + if (Stack[Cnt].MappedDecls.count(VD)) { + VarMI = Stack[Cnt].MappedDecls[VD]; + break; + } + } + return VarMI; + } + + void addMapInfoForVar(VarDecl *VD, MapInfo MI) { + if (Stack.size() > 1) { + Stack.back().MappedDecls[VD] = MI; + } + } + + MapInfo IsMappedInCurrentRegion(VarDecl *VD) { + assert(Stack.size() > 1 && "Target level is 0"); + MapInfo VarMI = {0}; + if (Stack.size() > 1 && Stack.back().MappedDecls.count(VD)) { + VarMI = Stack.back().MappedDecls[VD]; + } + return VarMI; + } }; bool isParallelOrTaskRegion(OpenMPDirectiveKind DKind) { return isOpenMPParallelDirective(DKind) || DKind == OMPD_task || - isOpenMPTeamsDirective(DKind) || DKind == OMPD_unknown; + isOpenMPTeamsDirective(DKind) || DKind == OMPD_unknown || + isOpenMPTaskLoopDirective(DKind); } } // namespace @@ -409,13 +494,32 @@ DeclRefExpr *DSAStackTy::addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE) { void DSAStackTy::addLoopControlVariable(VarDecl *D) { assert(Stack.size() > 1 && "Data-sharing attributes stack is empty"); D = D->getCanonicalDecl(); - Stack.back().LCVSet.insert(D); + Stack.back().LCVMap.insert(std::make_pair(D, Stack.back().LCVMap.size() + 1)); } -bool DSAStackTy::isLoopControlVariable(VarDecl *D) { +unsigned DSAStackTy::isLoopControlVariable(VarDecl *D) { assert(Stack.size() > 1 && "Data-sharing attributes stack is empty"); D = D->getCanonicalDecl(); - return Stack.back().LCVSet.count(D) > 0; + return Stack.back().LCVMap.count(D) > 0 ? Stack.back().LCVMap[D] : 0; +} + +unsigned DSAStackTy::isParentLoopControlVariable(VarDecl *D) { + assert(Stack.size() > 2 && "Data-sharing attributes stack is empty"); + D = D->getCanonicalDecl(); + return Stack[Stack.size() - 2].LCVMap.count(D) > 0 + ? Stack[Stack.size() - 2].LCVMap[D] + : 0; +} + +VarDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) { + assert(Stack.size() > 2 && "Data-sharing attributes stack is empty"); + if (Stack[Stack.size() - 2].LCVMap.size() < I) + return nullptr; + for (auto &Pair : Stack[Stack.size() - 2].LCVMap) { + if (Pair.second == I) + return Pair.first; + } + return nullptr; } void DSAStackTy::addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A) { @@ -452,12 +556,17 @@ bool DSAStackTy::isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter) { /// \brief Build a variable declaration for OpenMP loop iteration variable. static VarDecl *buildVarDecl(Sema &SemaRef, SourceLocation Loc, QualType Type, - StringRef Name) { + StringRef Name, const AttrVec *Attrs = nullptr) { DeclContext *DC = SemaRef.CurContext; IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name); TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc); VarDecl *Decl = VarDecl::Create(SemaRef.Context, DC, Loc, Loc, II, Type, TInfo, SC_None); + if (Attrs) { + for (specific_attr_iterator<AlignedAttr> I(Attrs->begin()), E(Attrs->end()); + I != E; ++I) + Decl->addAttr(*I); + } Decl->setImplicit(); return Decl; } @@ -496,41 +605,20 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced - // in a Construct, C/C++, predetermined, p.1] - // Variables with automatic storage duration that are declared in a scope - // inside the construct are private. - OpenMPDirectiveKind Kind = - FromParent ? getParentDirective() : getCurrentDirective(); - auto StartI = std::next(Stack.rbegin()); - auto EndI = std::prev(Stack.rend()); - if (FromParent && StartI != EndI) { - StartI = std::next(StartI); - } - if (!isParallelOrTaskRegion(Kind)) { - if (isOpenMPLocal(D, StartI) && - ((D->isLocalVarDecl() && (D->getStorageClass() == SC_Auto || - D->getStorageClass() == SC_None)) || - isa<ParmVarDecl>(D))) { - DVar.CKind = OMPC_private; + // in a Construct, C/C++, predetermined, p.4] + // Static data members are shared. + // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced + // in a Construct, C/C++, predetermined, p.7] + // Variables with static storage duration that are declared in a scope + // inside the construct are shared. + if (D->isStaticDataMember()) { + DSAVarData DVarTemp = + hasDSA(D, isOpenMPPrivate, MatchesAlways(), FromParent); + if (DVarTemp.CKind != OMPC_unknown && DVarTemp.RefExpr) return DVar; - } - // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced - // in a Construct, C/C++, predetermined, p.4] - // Static data members are shared. - // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced - // in a Construct, C/C++, predetermined, p.7] - // Variables with static storage duration that are declared in a scope - // inside the construct are shared. - if (D->isStaticDataMember() || D->isStaticLocal()) { - DSAVarData DVarTemp = - hasDSA(D, isOpenMPPrivate, MatchesAlways(), FromParent); - if (DVarTemp.CKind != OMPC_unknown && DVarTemp.RefExpr) - return DVar; - - DVar.CKind = OMPC_shared; - return DVar; - } + DVar.CKind = OMPC_shared; + return DVar; } QualType Type = D->getType().getNonReferenceType().getCanonicalType(); @@ -542,6 +630,9 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { // shared. CXXRecordDecl *RD = SemaRef.getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr; + if (auto *CTSD = dyn_cast_or_null<ClassTemplateSpecializationDecl>(RD)) + if (auto *CTD = CTSD->getSpecializedTemplate()) + RD = CTD->getTemplatedDecl(); if (IsConstant && !(SemaRef.getLangOpts().CPlusPlus && RD && RD->hasMutableFields())) { // Variables with const-qualified type having no mutable member may be @@ -557,6 +648,11 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { // Explicitly specified attributes and local variables with predetermined // attributes. + auto StartI = std::next(Stack.rbegin()); + auto EndI = std::prev(Stack.rend()); + if (FromParent && StartI != EndI) { + StartI = std::next(StartI); + } auto I = std::prev(StartI); if (I->SharingMap.count(D)) { DVar.RefExpr = I->SharingMap[D].RefExpr; @@ -635,6 +731,19 @@ bool DSAStackTy::hasExplicitDSA( CPred(StartI->SharingMap[D].Attributes); } +bool DSAStackTy::hasExplicitDirective( + const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred, + unsigned Level) { + if (isClauseParsingMode()) + ++Level; + auto StartI = Stack.rbegin(); + auto EndI = std::prev(Stack.rend()); + if (std::distance(StartI, EndI) <= (int)Level) + return false; + std::advance(StartI, Level); + return DPred(StartI->Directive); +} + template <class NamedDirectivesPredicate> bool DSAStackTy::hasDirective(NamedDirectivesPredicate DPred, bool FromParent) { auto StartI = std::next(Stack.rbegin()); @@ -649,15 +758,134 @@ bool DSAStackTy::hasDirective(NamedDirectivesPredicate DPred, bool FromParent) { return false; } +OpenMPDirectiveKind DSAStackTy::getDirectiveForScope(const Scope *S) const { + for (auto I = Stack.rbegin(), EE = Stack.rend(); I != EE; ++I) + if (I->CurScope == S) + return I->Directive; + return OMPD_unknown; +} + void Sema::InitDataSharingAttributesStack() { VarDataSharingAttributesStack = new DSAStackTy(*this); } #define DSAStack static_cast<DSAStackTy *>(VarDataSharingAttributesStack) +bool Sema::IsOpenMPCapturedByRef(VarDecl *VD, + const CapturedRegionScopeInfo *RSI) { + assert(LangOpts.OpenMP && "OpenMP is not allowed"); + + auto &Ctx = getASTContext(); + bool IsByRef = true; + + // Find the directive that is associated with the provided scope. + auto DKind = DSAStack->getDirectiveForScope(RSI->TheScope); + auto Ty = VD->getType(); + + if (isOpenMPTargetDirective(DKind)) { + // 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 + // the description in OpenMP 4.5 [2.10.4, target Construct] and + // OpenMP 4.5 [2.15.5, Data-mapping Attribute Rules and Clauses]. + // + // ========================================================================= + // | type | defaultmap | pvt | first | is_device_ptr | map | res. | + // | |(tofrom:scalar)| | pvt | | | | + // ========================================================================= + // | scl | | | | - | | bycopy| + // | scl | | - | x | - | - | bycopy| + // | scl | | x | - | - | - | null | + // | scl | x | | | - | | byref | + // | scl | x | - | x | - | - | bycopy| + // | scl | x | x | - | - | - | null | + // | scl | | - | - | - | x | byref | + // | scl | x | - | - | - | x | byref | + // + // | agg | n.a. | | | - | | byref | + // | agg | n.a. | - | x | - | - | byref | + // | agg | n.a. | x | - | - | - | null | + // | agg | n.a. | - | - | - | x | byref | + // | agg | n.a. | - | - | - | x[] | byref | + // + // | ptr | n.a. | | | - | | bycopy| + // | ptr | n.a. | - | x | - | - | bycopy| + // | ptr | n.a. | x | - | - | - | null | + // | ptr | n.a. | - | - | - | x | byref | + // | ptr | n.a. | - | - | - | x[] | bycopy| + // | ptr | n.a. | - | - | x | | bycopy| + // | ptr | n.a. | - | - | x | x | bycopy| + // | ptr | n.a. | - | - | x | x[] | bycopy| + // ========================================================================= + // Legend: + // scl - scalar + // ptr - pointer + // agg - aggregate + // x - applies + // - - invalid in this combination + // [] - mapped with an array section + // byref - should be mapped by reference + // byval - should be mapped by value + // null - initialize a local variable to null on the device + // + // Observations: + // - All scalar declarations that show up in a map clause have to be passed + // by reference, because they may have been mapped in the enclosing data + // environment. + // - If the scalar value does not fit the size of uintptr, it has to be + // passed by reference, regardless the result in the table above. + // - For pointers mapped by value that have either an implicit map or an + // array section, the runtime library may pass the NULL value to the + // device instead of the value passed to it by the compiler. + + // FIXME: Right now, only implicit maps are implemented. Properly mapping + // values requires having the map, private, and firstprivate clauses SEMA + // and parsing in place, which we don't yet. + + if (Ty->isReferenceType()) + Ty = Ty->castAs<ReferenceType>()->getPointeeType(); + IsByRef = !Ty->isScalarType(); + } + + // When passing data by value, we need to make sure it fits the uintptr size + // and alignment, because the runtime library only deals with uintptr types. + // If it does not fit the uintptr size, we need to pass the data by reference + // instead. + if (!IsByRef && + (Ctx.getTypeSizeInChars(Ty) > + Ctx.getTypeSizeInChars(Ctx.getUIntPtrType()) || + Ctx.getDeclAlign(VD) > Ctx.getTypeAlignInChars(Ctx.getUIntPtrType()))) + IsByRef = true; + + return IsByRef; +} + bool Sema::IsOpenMPCapturedVar(VarDecl *VD) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); VD = VD->getCanonicalDecl(); + + // If we are attempting to capture a global variable in a directive with + // 'target' we return true so that this global is also mapped to the device. + // + // FIXME: If the declaration is enclosed in a 'declare target' directive, + // then it should not be captured. Therefore, an extra check has to be + // inserted here once support for 'declare target' is added. + // + if (!VD->hasLocalStorage()) { + if (DSAStack->getCurrentDirective() == OMPD_target && + !DSAStack->isClauseParsingMode()) { + return true; + } + if (DSAStack->getCurScope() && + DSAStack->hasDirective( + [](OpenMPDirectiveKind K, const DeclarationNameInfo &DNI, + SourceLocation Loc) -> bool { + return isOpenMPTargetDirective(K); + }, + false)) { + return true; + } + } + if (DSAStack->getCurrentDirective() != OMPD_unknown && (!DSAStack->isClauseParsingMode() || DSAStack->getParentDirective() != OMPD_unknown)) { @@ -682,6 +910,14 @@ bool Sema::isOpenMPPrivateVar(VarDecl *VD, unsigned Level) { VD, [](OpenMPClauseKind K) -> bool { return K == OMPC_private; }, Level); } +bool Sema::isOpenMPTargetCapturedVar(VarDecl *VD, unsigned Level) { + assert(LangOpts.OpenMP && "OpenMP is not allowed"); + // Return true if the current level is no longer enclosed in a target region. + + return !VD->hasLocalStorage() && + DSAStack->hasExplicitDirective(isOpenMPTargetDirective, Level); +} + void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; } void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind, @@ -715,7 +951,7 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { continue; } auto *VD = cast<VarDecl>(cast<DeclRefExpr>(DE)->getDecl()); - QualType Type = VD->getType(); + QualType Type = VD->getType().getNonReferenceType(); auto DVar = DSAStack->getTopDSA(VD, false); if (DVar.CKind == OMPC_lastprivate) { // Generate helper private variable and initialize it with the @@ -723,9 +959,9 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { // by the address of the new private variable in CodeGen. This new // variable is not added to IdResolver, so the code in the OpenMP // region uses original variable for proper diagnostics. - auto *VDPrivate = - buildVarDecl(*this, DE->getExprLoc(), Type.getUnqualifiedType(), - VD->getName()); + auto *VDPrivate = buildVarDecl( + *this, DE->getExprLoc(), Type.getUnqualifiedType(), + VD->getName(), VD->hasAttrs() ? &VD->getAttrs() : nullptr); ActOnUninitializedDecl(VDPrivate, /*TypeMayContainAuto=*/false); if (VDPrivate->isInvalidDecl()) continue; @@ -1158,7 +1394,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { switch (DKind) { case OMPD_parallel: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); - QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty); + QualType KmpInt32PtrTy = + Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); Sema::CapturedParamNameType Params[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), std::make_pair(".bound_tid.", KmpInt32PtrTy), @@ -1234,7 +1471,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { } case OMPD_parallel_for: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); - QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty); + QualType KmpInt32PtrTy = + Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); Sema::CapturedParamNameType Params[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), std::make_pair(".bound_tid.", KmpInt32PtrTy), @@ -1246,7 +1484,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { } case OMPD_parallel_for_simd: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); - QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty); + QualType KmpInt32PtrTy = + Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); Sema::CapturedParamNameType Params[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), std::make_pair(".bound_tid.", KmpInt32PtrTy), @@ -1258,7 +1497,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { } case OMPD_parallel_sections: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); - QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty); + QualType KmpInt32PtrTy = + Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); Sema::CapturedParamNameType Params[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), std::make_pair(".bound_tid.", KmpInt32PtrTy), @@ -1309,6 +1549,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { Params); break; } + case OMPD_target_data: case OMPD_target: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars @@ -1319,7 +1560,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { } case OMPD_teams: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); - QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty); + QualType KmpInt32PtrTy = + Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); Sema::CapturedParamNameType Params[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), std::make_pair(".bound_tid.", KmpInt32PtrTy), @@ -1337,6 +1579,30 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { Params); break; } + case OMPD_taskloop: { + Sema::CapturedParamNameType Params[] = { + std::make_pair(StringRef(), QualType()) // __context with shared vars + }; + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + Params); + break; + } + case OMPD_taskloop_simd: { + Sema::CapturedParamNameType Params[] = { + std::make_pair(StringRef(), QualType()) // __context with shared vars + }; + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + Params); + break; + } + case OMPD_distribute: { + Sema::CapturedParamNameType Params[] = { + std::make_pair(StringRef(), QualType()) // __context with shared vars + }; + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + Params); + break; + } case OMPD_threadprivate: case OMPD_taskyield: case OMPD_barrier: @@ -1356,6 +1622,10 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, ActOnCapturedRegionError(); return StmtError(); } + + OMPOrderedClause *OC = nullptr; + OMPScheduleClause *SC = nullptr; + SmallVector<OMPLinearClause *, 4> LCs; // This is required for proper codegen. for (auto *Clause : Clauses) { if (isOpenMPPrivate(Clause->getClauseKind()) || @@ -1377,10 +1647,42 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, // Required for proper codegen of combined directives. // TODO: add processing for other clauses. if (auto *E = cast_or_null<Expr>( - cast<OMPScheduleClause>(Clause)->getHelperChunkSize())) { - MarkDeclarationsReferencedInExpr(E); - } + cast<OMPScheduleClause>(Clause)->getHelperChunkSize())) + MarkDeclarationsReferencedInExpr(E); } + if (Clause->getClauseKind() == OMPC_schedule) + SC = cast<OMPScheduleClause>(Clause); + else if (Clause->getClauseKind() == OMPC_ordered) + OC = cast<OMPOrderedClause>(Clause); + else if (Clause->getClauseKind() == OMPC_linear) + LCs.push_back(cast<OMPLinearClause>(Clause)); + } + bool ErrorFound = false; + // OpenMP, 2.7.1 Loop Construct, Restrictions + // The nonmonotonic modifier cannot be specified if an ordered clause is + // specified. + if (SC && + (SC->getFirstScheduleModifier() == OMPC_SCHEDULE_MODIFIER_nonmonotonic || + SC->getSecondScheduleModifier() == + OMPC_SCHEDULE_MODIFIER_nonmonotonic) && + OC) { + Diag(SC->getFirstScheduleModifier() == OMPC_SCHEDULE_MODIFIER_nonmonotonic + ? SC->getFirstScheduleModifierLoc() + : SC->getSecondScheduleModifierLoc(), + diag::err_omp_schedule_nonmonotonic_ordered) + << SourceRange(OC->getLocStart(), OC->getLocEnd()); + ErrorFound = true; + } + if (!LCs.empty() && OC && OC->getNumForLoops()) { + for (auto *C : LCs) { + Diag(C->getLocStart(), diag::err_omp_linear_ordered) + << SourceRange(OC->getLocStart(), OC->getLocEnd()); + } + ErrorFound = true; + } + if (ErrorFound) { + ActOnCapturedRegionError(); + return StmtError(); } return ActOnCapturedRegionEnd(S.get()); } @@ -1419,6 +1721,9 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | parallel | cancellation | | // | | point | ! | // | parallel | cancel | ! | + // | parallel | taskloop | * | + // | parallel | taskloop simd | * | + // | parallel | distribute | | // +------------------+-----------------+------------------------------------+ // | for | parallel | * | // | for | for | + | @@ -1445,6 +1750,9 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | for | cancellation | | // | | point | ! | // | for | cancel | ! | + // | for | taskloop | * | + // | for | taskloop simd | * | + // | for | distribute | | // +------------------+-----------------+------------------------------------+ // | master | parallel | * | // | master | for | + | @@ -1471,6 +1779,9 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | master | cancellation | | // | | point | | // | master | cancel | | + // | master | taskloop | * | + // | master | taskloop simd | * | + // | master | distribute | | // +------------------+-----------------+------------------------------------+ // | critical | parallel | * | // | critical | for | + | @@ -1496,6 +1807,9 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | critical | cancellation | | // | | point | | // | critical | cancel | | + // | critical | taskloop | * | + // | critical | taskloop simd | * | + // | critical | distribute | | // +------------------+-----------------+------------------------------------+ // | simd | parallel | | // | simd | for | | @@ -1515,13 +1829,16 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | simd | taskwait | | // | simd | taskgroup | | // | simd | flush | | - // | simd | ordered | | + // | simd | ordered | + (with simd clause) | // | simd | atomic | | // | simd | target | | // | simd | teams | | // | simd | cancellation | | // | | point | | // | simd | cancel | | + // | simd | taskloop | | + // | simd | taskloop simd | | + // | simd | distribute | | // +------------------+-----------------+------------------------------------+ // | for simd | parallel | | // | for simd | for | | @@ -1541,13 +1858,16 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | for simd | taskwait | | // | for simd | taskgroup | | // | for simd | flush | | - // | for simd | ordered | | + // | for simd | ordered | + (with simd clause) | // | for simd | atomic | | // | for simd | target | | // | for simd | teams | | // | for simd | cancellation | | // | | point | | // | for simd | cancel | | + // | for simd | taskloop | | + // | for simd | taskloop simd | | + // | for simd | distribute | | // +------------------+-----------------+------------------------------------+ // | parallel for simd| parallel | | // | parallel for simd| for | | @@ -1567,13 +1887,16 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | parallel for simd| taskwait | | // | parallel for simd| taskgroup | | // | parallel for simd| flush | | - // | parallel for simd| ordered | | + // | parallel for simd| ordered | + (with simd clause) | // | parallel for simd| atomic | | // | parallel for simd| target | | // | parallel for simd| teams | | // | parallel for simd| cancellation | | // | | point | | // | parallel for simd| cancel | | + // | parallel for simd| taskloop | | + // | parallel for simd| taskloop simd | | + // | parallel for simd| distribute | | // +------------------+-----------------+------------------------------------+ // | sections | parallel | * | // | sections | for | + | @@ -1600,6 +1923,9 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | sections | cancellation | | // | | point | ! | // | sections | cancel | ! | + // | sections | taskloop | * | + // | sections | taskloop simd | * | + // | sections | distribute | | // +------------------+-----------------+------------------------------------+ // | section | parallel | * | // | section | for | + | @@ -1626,6 +1952,9 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | section | cancellation | | // | | point | ! | // | section | cancel | ! | + // | section | taskloop | * | + // | section | taskloop simd | * | + // | section | distribute | | // +------------------+-----------------+------------------------------------+ // | single | parallel | * | // | single | for | + | @@ -1652,6 +1981,9 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | single | cancellation | | // | | point | | // | single | cancel | | + // | single | taskloop | * | + // | single | taskloop simd | * | + // | single | distribute | | // +------------------+-----------------+------------------------------------+ // | parallel for | parallel | * | // | parallel for | for | + | @@ -1678,6 +2010,9 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | parallel for | cancellation | | // | | point | ! | // | parallel for | cancel | ! | + // | parallel for | taskloop | * | + // | parallel for | taskloop simd | * | + // | parallel for | distribute | | // +------------------+-----------------+------------------------------------+ // | parallel sections| parallel | * | // | parallel sections| for | + | @@ -1704,6 +2039,9 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | parallel sections| cancellation | | // | | point | ! | // | parallel sections| cancel | ! | + // | parallel sections| taskloop | * | + // | parallel sections| taskloop simd | * | + // | parallel sections| distribute | | // +------------------+-----------------+------------------------------------+ // | task | parallel | * | // | task | for | + | @@ -1730,6 +2068,9 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | task | cancellation | | // | | point | ! | // | task | cancel | ! | + // | task | taskloop | * | + // | task | taskloop simd | * | + // | task | distribute | | // +------------------+-----------------+------------------------------------+ // | ordered | parallel | * | // | ordered | for | + | @@ -1756,6 +2097,9 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | ordered | cancellation | | // | | point | | // | ordered | cancel | | + // | ordered | taskloop | * | + // | ordered | taskloop simd | * | + // | ordered | distribute | | // +------------------+-----------------+------------------------------------+ // | atomic | parallel | | // | atomic | for | | @@ -1782,6 +2126,9 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | atomic | cancellation | | // | | point | | // | atomic | cancel | | + // | atomic | taskloop | | + // | atomic | taskloop simd | | + // | atomic | distribute | | // +------------------+-----------------+------------------------------------+ // | target | parallel | * | // | target | for | * | @@ -1808,6 +2155,9 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | target | cancellation | | // | | point | | // | target | cancel | | + // | target | taskloop | * | + // | target | taskloop simd | * | + // | target | distribute | | // +------------------+-----------------+------------------------------------+ // | teams | parallel | * | // | teams | for | + | @@ -1834,6 +2184,95 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | teams | cancellation | | // | | point | | // | teams | cancel | | + // | teams | taskloop | + | + // | teams | taskloop simd | + | + // | teams | distribute | ! | + // +------------------+-----------------+------------------------------------+ + // | taskloop | parallel | * | + // | taskloop | for | + | + // | taskloop | for simd | + | + // | taskloop | master | + | + // | taskloop | critical | * | + // | taskloop | simd | * | + // | taskloop | sections | + | + // | taskloop | section | + | + // | taskloop | single | + | + // | taskloop | parallel for | * | + // | taskloop |parallel for simd| * | + // | taskloop |parallel sections| * | + // | taskloop | task | * | + // | taskloop | taskyield | * | + // | taskloop | barrier | + | + // | taskloop | taskwait | * | + // | taskloop | taskgroup | * | + // | taskloop | flush | * | + // | taskloop | ordered | + | + // | taskloop | atomic | * | + // | taskloop | target | * | + // | taskloop | teams | + | + // | taskloop | cancellation | | + // | | point | | + // | taskloop | cancel | | + // | taskloop | taskloop | * | + // | taskloop | distribute | | + // +------------------+-----------------+------------------------------------+ + // | taskloop simd | parallel | | + // | taskloop simd | for | | + // | taskloop simd | for simd | | + // | taskloop simd | master | | + // | taskloop simd | critical | | + // | taskloop simd | simd | | + // | taskloop simd | sections | | + // | taskloop simd | section | | + // | taskloop simd | single | | + // | taskloop simd | parallel for | | + // | taskloop simd |parallel for simd| | + // | taskloop simd |parallel sections| | + // | taskloop simd | task | | + // | taskloop simd | taskyield | | + // | taskloop simd | barrier | | + // | taskloop simd | taskwait | | + // | taskloop simd | taskgroup | | + // | taskloop simd | flush | | + // | taskloop simd | ordered | + (with simd clause) | + // | taskloop simd | atomic | | + // | taskloop simd | target | | + // | taskloop simd | teams | | + // | taskloop simd | cancellation | | + // | | point | | + // | taskloop simd | cancel | | + // | taskloop simd | taskloop | | + // | taskloop simd | taskloop simd | | + // | taskloop simd | distribute | | + // +------------------+-----------------+------------------------------------+ + // | distribute | parallel | * | + // | distribute | for | * | + // | distribute | for simd | * | + // | distribute | master | * | + // | distribute | critical | * | + // | distribute | simd | * | + // | distribute | sections | * | + // | distribute | section | * | + // | distribute | single | * | + // | distribute | parallel for | * | + // | distribute |parallel for simd| * | + // | distribute |parallel sections| * | + // | distribute | task | * | + // | distribute | taskyield | * | + // | distribute | barrier | * | + // | distribute | taskwait | * | + // | distribute | taskgroup | * | + // | distribute | flush | * | + // | distribute | ordered | + | + // | distribute | atomic | * | + // | distribute | target | | + // | distribute | teams | | + // | distribute | cancellation | + | + // | | point | | + // | distribute | cancel | + | + // | distribute | taskloop | * | + // | distribute | taskloop simd | * | + // | distribute | distribute | | // +------------------+-----------------+------------------------------------+ if (Stack->getCurScope()) { auto ParentRegion = Stack->getParentDirective(); @@ -1843,11 +2282,15 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, NoRecommend, ShouldBeInParallelRegion, ShouldBeInOrderedRegion, - ShouldBeInTargetRegion + ShouldBeInTargetRegion, + ShouldBeInTeamsRegion } Recommend = NoRecommend; - if (isOpenMPSimdDirective(ParentRegion)) { + if (isOpenMPSimdDirective(ParentRegion) && CurrentRegion != OMPD_ordered) { // OpenMP [2.16, Nesting of Regions] // OpenMP constructs may not be nested inside a simd region. + // OpenMP [2.8.1,simd Construct, Restrictions] + // An ordered construct with the simd clause is the only OpenMP construct + // that can appear in the simd region. SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region_simd); return true; } @@ -1890,16 +2333,19 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // construct-type-clause. NestingProhibited = !((CancelRegion == OMPD_parallel && ParentRegion == OMPD_parallel) || - (CancelRegion == OMPD_for && ParentRegion == OMPD_for) || + (CancelRegion == OMPD_for && + (ParentRegion == OMPD_for || ParentRegion == OMPD_parallel_for)) || (CancelRegion == OMPD_taskgroup && ParentRegion == OMPD_task) || (CancelRegion == OMPD_sections && - (ParentRegion == OMPD_section || ParentRegion == OMPD_sections))); + (ParentRegion == OMPD_section || ParentRegion == OMPD_sections || + ParentRegion == OMPD_parallel_sections))); } else if (CurrentRegion == OMPD_master) { // OpenMP [2.16, Nesting of Regions] // A master region may not be closely nested inside a worksharing, // atomic, or explicit task region. NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || - ParentRegion == OMPD_task; + ParentRegion == OMPD_task || + isOpenMPTaskLoopDirective(ParentRegion); } else if (CurrentRegion == OMPD_critical && CurrentName.getName()) { // OpenMP [2.16, Nesting of Regions] // A critical region may not be nested (closely or otherwise) inside a @@ -1936,7 +2382,8 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || ParentRegion == OMPD_task || ParentRegion == OMPD_master || - ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered; + ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered || + isOpenMPTaskLoopDirective(ParentRegion); } else if (isOpenMPWorksharingDirective(CurrentRegion) && !isOpenMPParallelDirective(CurrentRegion)) { // OpenMP [2.16, Nesting of Regions] @@ -1945,7 +2392,8 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || ParentRegion == OMPD_task || ParentRegion == OMPD_master || - ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered; + ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered || + isOpenMPTaskLoopDirective(ParentRegion); Recommend = ShouldBeInParallelRegion; } else if (CurrentRegion == OMPD_ordered) { // OpenMP [2.16, Nesting of Regions] @@ -1953,9 +2401,14 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // atomic, or explicit task region. // An ordered region must be closely nested inside a loop region (or // parallel loop region) with an ordered clause. + // OpenMP [2.8.1,simd Construct, Restrictions] + // An ordered construct with the simd clause is the only OpenMP construct + // that can appear in the simd region. NestingProhibited = ParentRegion == OMPD_critical || ParentRegion == OMPD_task || - !Stack->isParentOrderedRegion(); + isOpenMPTaskLoopDirective(ParentRegion) || + !(isOpenMPSimdDirective(ParentRegion) || + Stack->isParentOrderedRegion()); Recommend = ShouldBeInOrderedRegion; } else if (isOpenMPTeamsDirective(CurrentRegion)) { // OpenMP [2.16, Nesting of Regions] @@ -1970,10 +2423,17 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // distribute, parallel, parallel sections, parallel workshare, and the // parallel loop and parallel loop SIMD constructs are the only OpenMP // constructs that can be closely nested in the teams region. - // TODO: add distribute directive. - NestingProhibited = !isOpenMPParallelDirective(CurrentRegion); + NestingProhibited = !isOpenMPParallelDirective(CurrentRegion) && + !isOpenMPDistributeDirective(CurrentRegion); Recommend = ShouldBeInParallelRegion; } + if (!NestingProhibited && isOpenMPDistributeDirective(CurrentRegion)) { + // OpenMP 4.5 [2.17 Nesting of Regions] + // The region associated with the distribute construct must be strictly + // nested inside a teams region + NestingProhibited = !isOpenMPTeamsDirective(ParentRegion); + Recommend = ShouldBeInTeamsRegion; + } if (NestingProhibited) { SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region) << CloseNesting << getOpenMPDirectiveName(ParentRegion) << Recommend @@ -1984,6 +2444,88 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, return false; } +static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind, + ArrayRef<OMPClause *> Clauses, + ArrayRef<OpenMPDirectiveKind> AllowedNameModifiers) { + bool ErrorFound = false; + unsigned NamedModifiersNumber = 0; + SmallVector<const OMPIfClause *, OMPC_unknown + 1> FoundNameModifiers( + OMPD_unknown + 1); + SmallVector<SourceLocation, 4> NameModifierLoc; + for (const auto *C : Clauses) { + if (const auto *IC = dyn_cast_or_null<OMPIfClause>(C)) { + // At most one if clause without a directive-name-modifier can appear on + // the directive. + OpenMPDirectiveKind CurNM = IC->getNameModifier(); + if (FoundNameModifiers[CurNM]) { + S.Diag(C->getLocStart(), diag::err_omp_more_one_clause) + << getOpenMPDirectiveName(Kind) << getOpenMPClauseName(OMPC_if) + << (CurNM != OMPD_unknown) << getOpenMPDirectiveName(CurNM); + ErrorFound = true; + } else if (CurNM != OMPD_unknown) { + NameModifierLoc.push_back(IC->getNameModifierLoc()); + ++NamedModifiersNumber; + } + FoundNameModifiers[CurNM] = IC; + if (CurNM == OMPD_unknown) + continue; + // Check if the specified name modifier is allowed for the current + // directive. + // At most one if clause with the particular directive-name-modifier can + // appear on the directive. + bool MatchFound = false; + for (auto NM : AllowedNameModifiers) { + if (CurNM == NM) { + MatchFound = true; + break; + } + } + if (!MatchFound) { + S.Diag(IC->getNameModifierLoc(), + diag::err_omp_wrong_if_directive_name_modifier) + << getOpenMPDirectiveName(CurNM) << getOpenMPDirectiveName(Kind); + ErrorFound = true; + } + } + } + // If any if clause on the directive includes a directive-name-modifier then + // all if clauses on the directive must include a directive-name-modifier. + if (FoundNameModifiers[OMPD_unknown] && NamedModifiersNumber > 0) { + if (NamedModifiersNumber == AllowedNameModifiers.size()) { + S.Diag(FoundNameModifiers[OMPD_unknown]->getLocStart(), + diag::err_omp_no_more_if_clause); + } else { + std::string Values; + std::string Sep(", "); + unsigned AllowedCnt = 0; + unsigned TotalAllowedNum = + AllowedNameModifiers.size() - NamedModifiersNumber; + for (unsigned Cnt = 0, End = AllowedNameModifiers.size(); Cnt < End; + ++Cnt) { + OpenMPDirectiveKind NM = AllowedNameModifiers[Cnt]; + if (!FoundNameModifiers[NM]) { + Values += "'"; + Values += getOpenMPDirectiveName(NM); + Values += "'"; + if (AllowedCnt + 2 == TotalAllowedNum) + Values += " or "; + else if (AllowedCnt + 1 != TotalAllowedNum) + Values += Sep; + ++AllowedCnt; + } + } + S.Diag(FoundNameModifiers[OMPD_unknown]->getCondition()->getLocStart(), + diag::err_omp_unnamed_if_clause) + << (TotalAllowedNum > 1) << Values; + } + for (auto Loc : NameModifierLoc) { + S.Diag(Loc, diag::note_omp_previous_named_if_clause); + } + ErrorFound = true; + } + return ErrorFound; +} + StmtResult Sema::ActOnOpenMPExecutableDirective( OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName, OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses, @@ -2020,10 +2562,12 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( } } + llvm::SmallVector<OpenMPDirectiveKind, 4> AllowedNameModifiers; switch (Kind) { case OMPD_parallel: Res = ActOnOpenMPParallelDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); + AllowedNameModifiers.push_back(OMPD_parallel); break; case OMPD_simd: Res = ActOnOpenMPSimdDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, @@ -2056,25 +2600,28 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( Res = ActOnOpenMPMasterDirective(AStmt, StartLoc, EndLoc); break; case OMPD_critical: - assert(ClausesWithImplicit.empty() && - "No clauses are allowed for 'omp critical' directive"); - Res = ActOnOpenMPCriticalDirective(DirName, AStmt, StartLoc, EndLoc); + Res = ActOnOpenMPCriticalDirective(DirName, ClausesWithImplicit, AStmt, + StartLoc, EndLoc); break; case OMPD_parallel_for: Res = ActOnOpenMPParallelForDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_parallel); break; case OMPD_parallel_for_simd: Res = ActOnOpenMPParallelForSimdDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_parallel); break; case OMPD_parallel_sections: Res = ActOnOpenMPParallelSectionsDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); + AllowedNameModifiers.push_back(OMPD_parallel); break; case OMPD_task: Res = ActOnOpenMPTaskDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); + AllowedNameModifiers.push_back(OMPD_task); break; case OMPD_taskyield: assert(ClausesWithImplicit.empty() && @@ -2108,9 +2655,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( Res = ActOnOpenMPFlushDirective(ClausesWithImplicit, StartLoc, EndLoc); break; case OMPD_ordered: - assert(ClausesWithImplicit.empty() && - "No clauses are allowed for 'omp ordered' directive"); - Res = ActOnOpenMPOrderedDirective(AStmt, StartLoc, EndLoc); + Res = ActOnOpenMPOrderedDirective(ClausesWithImplicit, AStmt, StartLoc, + EndLoc); break; case OMPD_atomic: Res = ActOnOpenMPAtomicDirective(ClausesWithImplicit, AStmt, StartLoc, @@ -2123,6 +2669,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPD_target: Res = ActOnOpenMPTargetDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); + AllowedNameModifiers.push_back(OMPD_target); break; case OMPD_cancellation_point: assert(ClausesWithImplicit.empty() && @@ -2132,11 +2679,30 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( Res = ActOnOpenMPCancellationPointDirective(StartLoc, EndLoc, CancelRegion); break; case OMPD_cancel: - assert(ClausesWithImplicit.empty() && - "No clauses are allowed for 'omp cancel' directive"); assert(AStmt == nullptr && "No associated statement allowed for 'omp cancel' directive"); - Res = ActOnOpenMPCancelDirective(StartLoc, EndLoc, CancelRegion); + Res = ActOnOpenMPCancelDirective(ClausesWithImplicit, StartLoc, EndLoc, + CancelRegion); + AllowedNameModifiers.push_back(OMPD_cancel); + break; + case OMPD_target_data: + Res = ActOnOpenMPTargetDataDirective(ClausesWithImplicit, AStmt, StartLoc, + EndLoc); + AllowedNameModifiers.push_back(OMPD_target_data); + break; + case OMPD_taskloop: + Res = ActOnOpenMPTaskLoopDirective(ClausesWithImplicit, AStmt, StartLoc, + EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_taskloop); + break; + case OMPD_taskloop_simd: + Res = ActOnOpenMPTaskLoopSimdDirective(ClausesWithImplicit, AStmt, StartLoc, + EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_taskloop); + break; + case OMPD_distribute: + Res = ActOnOpenMPDistributeDirective(ClausesWithImplicit, AStmt, StartLoc, + EndLoc, VarsWithInheritedDSA); break; case OMPD_threadprivate: llvm_unreachable("OpenMP Directive is not allowed"); @@ -2148,8 +2714,11 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( Diag(P.second->getExprLoc(), diag::err_omp_no_dsa_for_variable) << P.first << P.second->getSourceRange(); } - if (!VarsWithInheritedDSA.empty()) - return StmtError(); + ErrorFound = !VarsWithInheritedDSA.empty() || ErrorFound; + + if (!AllowedNameModifiers.empty()) + ErrorFound = checkIfClauses(*this, Kind, Clauses, AllowedNameModifiers) || + ErrorFound; if (ErrorFound) return StmtError(); @@ -2160,7 +2729,9 @@ StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { - assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + if (!AStmt) + return StmtError(); + CapturedStmt *CS = cast<CapturedStmt>(AStmt); // 1.2.2 OpenMP Language Terminology // Structured block - An executable statement with a single entry at the @@ -2171,8 +2742,8 @@ StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses, getCurFunction()->setHasBranchProtectedScope(); - return OMPParallelDirective::Create(Context, StartLoc, EndLoc, Clauses, - AStmt); + return OMPParallelDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, + DSAStack->isCancelRegion()); } namespace { @@ -2247,6 +2818,9 @@ public: Expr *BuildPreCond(Scope *S, Expr *Cond) const; /// \brief Build reference expression to the counter be used for codegen. Expr *BuildCounterVar() const; + /// \brief Build reference expression to the private counter be used for + /// codegen. + Expr *BuildPrivateCounterVar() const; /// \brief Build initization of the counter be used for codegen. Expr *BuildCounterInit() const; /// \brief Build step of the counter be used for codegen. @@ -2261,8 +2835,8 @@ private: /// \brief Helper to set loop counter variable and its initializer. bool SetVarAndLB(VarDecl *NewVar, DeclRefExpr *NewVarRefExpr, Expr *NewLB); /// \brief Helper to set upper bound. - bool SetUB(Expr *NewUB, bool LessOp, bool StrictOp, const SourceRange &SR, - const SourceLocation &SL); + bool SetUB(Expr *NewUB, bool LessOp, bool StrictOp, SourceRange SR, + SourceLocation SL); /// \brief Helper to set loop increment. bool SetStep(Expr *NewStep, bool Subtract); }; @@ -2313,8 +2887,7 @@ bool OpenMPIterationSpaceChecker::SetVarAndLB(VarDecl *NewVar, } bool OpenMPIterationSpaceChecker::SetUB(Expr *NewUB, bool LessOp, bool StrictOp, - const SourceRange &SR, - const SourceLocation &SL) { + SourceRange SR, SourceLocation SL) { // State consistency checking to ensure correct usage. assert(Var != nullptr && LB != nullptr && UB == nullptr && Step == nullptr && !TestIsLessOp && !TestIsStrictOp); @@ -2410,7 +2983,7 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) { } else if (auto DS = dyn_cast<DeclStmt>(S)) { if (DS->isSingleDecl()) { if (auto Var = dyn_cast_or_null<VarDecl>(DS->getSingleDecl())) { - if (Var->hasInit()) { + if (Var->hasInit() && !Var->getType()->isReferenceType()) { // Accept non-canonical init form here but emit ext. warning. if (Var->getInitStyle() != VarDecl::CInit && EmitDiags) SemaRef.Diag(S->getLocStart(), @@ -2630,6 +3203,8 @@ public: NewVD->setPreviousDeclInSameBlockScope( VD->isPreviousDeclInSameBlockScope()); VD->getDeclContext()->addHiddenDecl(NewVD); + if (VD->hasAttrs()) + NewVD->setAttrs(VD->getAttrs()); transformedLocalDecl(VD, NewVD); return NewVD; } @@ -2802,7 +3377,21 @@ Expr *OpenMPIterationSpaceChecker::BuildPreCond(Scope *S, Expr *Cond) const { /// \brief Build reference expression to the counter be used for codegen. Expr *OpenMPIterationSpaceChecker::BuildCounterVar() const { - return buildDeclRefExpr(SemaRef, Var, Var->getType(), DefaultLoc); + return buildDeclRefExpr(SemaRef, Var, Var->getType().getNonReferenceType(), + DefaultLoc); +} + +Expr *OpenMPIterationSpaceChecker::BuildPrivateCounterVar() const { + if (Var && !Var->isInvalidDecl()) { + auto Type = Var->getType().getNonReferenceType(); + auto *PrivateVar = + buildVarDecl(SemaRef, DefaultLoc, Type, Var->getName(), + Var->hasAttrs() ? &Var->getAttrs() : nullptr); + if (PrivateVar->isInvalidDecl()) + return nullptr; + return buildDeclRefExpr(SemaRef, PrivateVar, Type, DefaultLoc); + } + return nullptr; } /// \brief Build initization of the counter be used for codegen. @@ -2820,6 +3409,8 @@ struct LoopIterationSpace { Expr *NumIterations; /// \brief The loop counter variable. Expr *CounterVar; + /// \brief Private loop counter variable. + Expr *PrivateCounterVar; /// \brief This is initializer for the initial value of #CounterVar. Expr *CounterInit; /// \brief This is step for the #CounterVar used to generate its update: @@ -2840,14 +3431,13 @@ struct LoopIterationSpace { void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { assert(getLangOpts().OpenMP && "OpenMP is not active."); assert(Init && "Expected loop in canonical form."); - unsigned CollapseIteration = DSAStack->getCollapseNumber(); - if (CollapseIteration > 0 && + unsigned AssociatedLoops = DSAStack->getAssociatedLoops(); + if (AssociatedLoops > 0 && isOpenMPLoopDirective(DSAStack->getCurrentDirective())) { OpenMPIterationSpaceChecker ISC(*this, ForLoc); - if (!ISC.CheckInit(Init, /*EmitDiags=*/false)) { + if (!ISC.CheckInit(Init, /*EmitDiags=*/false)) DSAStack->addLoopControlVariable(ISC.GetLoopVar()); - } - DSAStack->setCollapseNumber(CollapseIteration - 1); + DSAStack->setAssociatedLoops(AssociatedLoops - 1); } } @@ -2856,7 +3446,7 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { static bool CheckOpenMPIterationSpace( OpenMPDirectiveKind DKind, Stmt *S, Sema &SemaRef, DSAStackTy &DSA, unsigned CurrentNestedLoopCount, unsigned NestedLoopCount, - Expr *NestedLoopCountExpr, + Expr *CollapseLoopCountExpr, Expr *OrderedLoopCountExpr, llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA, LoopIterationSpace &ResultIterSpace) { // OpenMP [2.6, Canonical Loop Form] @@ -2864,13 +3454,24 @@ static bool CheckOpenMPIterationSpace( auto For = dyn_cast_or_null<ForStmt>(S); if (!For) { SemaRef.Diag(S->getLocStart(), diag::err_omp_not_for) - << (NestedLoopCountExpr != nullptr) << getOpenMPDirectiveName(DKind) - << NestedLoopCount << (CurrentNestedLoopCount > 0) - << CurrentNestedLoopCount; - if (NestedLoopCount > 1) - SemaRef.Diag(NestedLoopCountExpr->getExprLoc(), - diag::note_omp_collapse_expr) - << NestedLoopCountExpr->getSourceRange(); + << (CollapseLoopCountExpr != nullptr || OrderedLoopCountExpr != nullptr) + << getOpenMPDirectiveName(DKind) << NestedLoopCount + << (CurrentNestedLoopCount > 0) << CurrentNestedLoopCount; + if (NestedLoopCount > 1) { + if (CollapseLoopCountExpr && OrderedLoopCountExpr) + SemaRef.Diag(DSA.getConstructLoc(), + diag::note_omp_collapse_ordered_expr) + << 2 << CollapseLoopCountExpr->getSourceRange() + << OrderedLoopCountExpr->getSourceRange(); + else if (CollapseLoopCountExpr) + SemaRef.Diag(CollapseLoopCountExpr->getExprLoc(), + diag::note_omp_collapse_ordered_expr) + << 0 << CollapseLoopCountExpr->getSourceRange(); + else + SemaRef.Diag(OrderedLoopCountExpr->getExprLoc(), + diag::note_omp_collapse_ordered_expr) + << 1 << OrderedLoopCountExpr->getSourceRange(); + } return true; } assert(For->getBody()); @@ -2893,7 +3494,7 @@ static bool CheckOpenMPIterationSpace( // A variable of signed or unsigned integer type. // For C++, a variable of a random access iterator type. // For C, a variable of a pointer type. - auto VarType = Var->getType(); + auto VarType = Var->getType().getNonReferenceType(); if (!VarType->isDependentType() && !VarType->isIntegerType() && !VarType->isPointerType() && !(SemaRef.getLangOpts().CPlusPlus && VarType->isOverloadableType())) { @@ -2929,12 +3530,12 @@ static bool CheckOpenMPIterationSpace( ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate) : OMPC_private; if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && - DVar.CKind != OMPC_threadprivate && DVar.CKind != PredeterminedCKind) || - (isOpenMPWorksharingDirective(DKind) && !isOpenMPSimdDirective(DKind) && - DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_private && - DVar.CKind != OMPC_lastprivate && DVar.CKind != OMPC_threadprivate)) && - ((DVar.CKind != OMPC_private && DVar.CKind != OMPC_threadprivate) || - DVar.RefExpr != nullptr)) { + DVar.CKind != PredeterminedCKind) || + ((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 != nullptr)) { SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_var_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(PredeterminedCKind); @@ -2945,7 +3546,8 @@ static bool CheckOpenMPIterationSpace( } else if (LoopVarRefExpr != 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 loops). + // lastprivate (for simd directives with several collapsed or ordered + // loops). if (DVar.CKind == OMPC_unknown) DVar = DSA.hasDSA(Var, isOpenMPPrivate, MatchesAlways(), /*FromParent=*/false); @@ -2966,8 +3568,11 @@ static bool CheckOpenMPIterationSpace( // Build the loop's iteration space representation. ResultIterSpace.PreCond = ISC.BuildPreCond(DSA.getCurScope(), For->getCond()); ResultIterSpace.NumIterations = ISC.BuildNumIterations( - DSA.getCurScope(), /* LimitedType */ isOpenMPWorksharingDirective(DKind)); + DSA.getCurScope(), (isOpenMPWorksharingDirective(DKind) || + isOpenMPTaskLoopDirective(DKind) || + isOpenMPDistributeDirective(DKind))); ResultIterSpace.CounterVar = ISC.BuildCounterVar(); + ResultIterSpace.PrivateCounterVar = ISC.BuildPrivateCounterVar(); ResultIterSpace.CounterInit = ISC.BuildCounterInit(); ResultIterSpace.CounterStep = ISC.BuildCounterStep(); ResultIterSpace.InitSrcRange = ISC.GetInitSrcRange(); @@ -2978,6 +3583,7 @@ static bool CheckOpenMPIterationSpace( HasErrors |= (ResultIterSpace.PreCond == nullptr || ResultIterSpace.NumIterations == nullptr || ResultIterSpace.CounterVar == nullptr || + ResultIterSpace.PrivateCounterVar == nullptr || ResultIterSpace.CounterInit == nullptr || ResultIterSpace.CounterStep == nullptr); @@ -3091,17 +3697,33 @@ static bool FitsInto(unsigned Bits, bool Signed, Expr *E, Sema &SemaRef) { /// \return Returns 0 if one of the collapsed stmts is not canonical for loop, /// number of collapsed loops otherwise. static unsigned -CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, - Stmt *AStmt, Sema &SemaRef, DSAStackTy &DSA, +CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, + Expr *OrderedLoopCountExpr, Stmt *AStmt, Sema &SemaRef, + DSAStackTy &DSA, llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA, OMPLoopDirective::HelperExprs &Built) { unsigned NestedLoopCount = 1; - if (NestedLoopCountExpr) { + if (CollapseLoopCountExpr) { // Found 'collapse' clause - calculate collapse number. llvm::APSInt Result; - if (NestedLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext())) + if (CollapseLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext())) NestedLoopCount = Result.getLimitedValue(); } + if (OrderedLoopCountExpr) { + // Found 'ordered' clause - calculate collapse number. + llvm::APSInt Result; + if (OrderedLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext())) { + if (Result.getLimitedValue() < NestedLoopCount) { + SemaRef.Diag(OrderedLoopCountExpr->getExprLoc(), + diag::err_omp_wrong_ordered_loop_count) + << OrderedLoopCountExpr->getSourceRange(); + SemaRef.Diag(CollapseLoopCountExpr->getExprLoc(), + diag::note_collapse_loop_count) + << CollapseLoopCountExpr->getSourceRange(); + } + NestedLoopCount = Result.getLimitedValue(); + } + } // This is helper routine for loop directives (e.g., 'for', 'simd', // 'for simd', etc.). SmallVector<LoopIterationSpace, 4> IterSpaces; @@ -3109,8 +3731,9 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, Stmt *CurStmt = AStmt->IgnoreContainers(/* IgnoreCaptured */ true); for (unsigned Cnt = 0; Cnt < NestedLoopCount; ++Cnt) { if (CheckOpenMPIterationSpace(DKind, CurStmt, SemaRef, DSA, Cnt, - NestedLoopCount, NestedLoopCountExpr, - VarsWithImplicitDSA, IterSpaces[Cnt])) + NestedLoopCount, CollapseLoopCountExpr, + OrderedLoopCountExpr, VarsWithImplicitDSA, + IterSpaces[Cnt])) return 0; // Move on to the next nested for loop, or to the loop body. // OpenMP [2.8.1, simd construct, Restrictions] @@ -3127,11 +3750,12 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, // An example of what is generated for the following code: // - // #pragma omp simd collapse(2) + // #pragma omp simd collapse(2) ordered(2) // for (i = 0; i < NI; ++i) - // for (j = J0; j < NJ; j+=2) { - // <loop body> - // } + // for (k = 0; k < NK; ++k) + // for (j = J0; j < NJ; j+=2) { + // <loop body> + // } // // We generate the code below. // Note: the loop body may be outlined in CodeGen. @@ -3254,7 +3878,8 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, QualType VType = LastIteration.get()->getType(); // Build variables passed into runtime, nesessary for worksharing directives. ExprResult LB, UB, IL, ST, EUB; - if (isOpenMPWorksharingDirective(DKind)) { + if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || + isOpenMPDistributeDirective(DKind)) { // Lower bound variable, initialized with zero. VarDecl *LBDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.lb"); LB = buildDeclRefExpr(SemaRef, LBDecl, VType, InitLoc); @@ -3302,7 +3927,9 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, { VarDecl *IVDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.iv"); IV = buildDeclRefExpr(SemaRef, IVDecl, VType, InitLoc); - Expr *RHS = isOpenMPWorksharingDirective(DKind) + Expr *RHS = (isOpenMPWorksharingDirective(DKind) || + isOpenMPTaskLoopDirective(DKind) || + isOpenMPDistributeDirective(DKind)) ? LB.get() : SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get(); Init = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, IV.get(), RHS); @@ -3312,7 +3939,8 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, // Loop condition (IV < NumIterations) or (IV <= UB) for worksharing loops. SourceLocation CondLoc; ExprResult Cond = - isOpenMPWorksharingDirective(DKind) + (isOpenMPWorksharingDirective(DKind) || + isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)) ? SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get()) : SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(), NumIterations.get()); @@ -3332,7 +3960,8 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, // Increments for worksharing loops (LB = LB + ST; UB = UB + ST). // Used for directives with static scheduling. ExprResult NextLB, NextUB; - if (isOpenMPWorksharingDirective(DKind)) { + if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || + isOpenMPDistributeDirective(DKind)) { // LB + ST NextLB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, LB.get(), ST.get()); if (!NextLB.isUsable()) @@ -3437,6 +4066,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, } // Save results Built.Counters[Cnt] = IS.CounterVar; + Built.PrivateCounters[Cnt] = IS.PrivateCounterVar; Built.Inits[Cnt] = Init.get(); Built.Updates[Cnt] = Update.get(); Built.Finals[Cnt] = Final.get(); @@ -3467,26 +4097,60 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, return NestedLoopCount; } -static Expr *GetCollapseNumberExpr(ArrayRef<OMPClause *> Clauses) { - auto &&CollapseFilter = [](const OMPClause *C) -> bool { - return C->getClauseKind() == OMPC_collapse; - }; - OMPExecutableDirective::filtered_clause_iterator<decltype(CollapseFilter)> I( - Clauses, std::move(CollapseFilter)); - if (I) - return cast<OMPCollapseClause>(*I)->getNumForLoops(); +static Expr *getCollapseNumberExpr(ArrayRef<OMPClause *> Clauses) { + auto CollapseClauses = + OMPExecutableDirective::getClausesOfKind<OMPCollapseClause>(Clauses); + if (CollapseClauses.begin() != CollapseClauses.end()) + return (*CollapseClauses.begin())->getNumForLoops(); + return nullptr; +} + +static Expr *getOrderedNumberExpr(ArrayRef<OMPClause *> Clauses) { + auto OrderedClauses = + OMPExecutableDirective::getClausesOfKind<OMPOrderedClause>(Clauses); + if (OrderedClauses.begin() != OrderedClauses.end()) + return (*OrderedClauses.begin())->getNumForLoops(); return nullptr; } +static bool checkSimdlenSafelenValues(Sema &S, const Expr *Simdlen, + const Expr *Safelen) { + llvm::APSInt SimdlenRes, SafelenRes; + if (Simdlen->isValueDependent() || Simdlen->isTypeDependent() || + Simdlen->isInstantiationDependent() || + Simdlen->containsUnexpandedParameterPack()) + return false; + if (Safelen->isValueDependent() || Safelen->isTypeDependent() || + Safelen->isInstantiationDependent() || + Safelen->containsUnexpandedParameterPack()) + return false; + Simdlen->EvaluateAsInt(SimdlenRes, S.Context); + Safelen->EvaluateAsInt(SafelenRes, S.Context); + // OpenMP 4.1 [2.8.1, simd Construct, Restrictions] + // If both simdlen and safelen clauses are specified, the value of the simdlen + // parameter must be less than or equal to the value of the safelen parameter. + if (SimdlenRes > SafelenRes) { + S.Diag(Simdlen->getExprLoc(), diag::err_omp_wrong_simdlen_safelen_values) + << Simdlen->getSourceRange() << Safelen->getSourceRange(); + return true; + } + return false; +} + StmtResult Sema::ActOnOpenMPSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + if (!AStmt) + return StmtError(); + + assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); OMPLoopDirective::HelperExprs B; - // In presence of clause 'collapse', it will define the nested loops number. - unsigned NestedLoopCount = - CheckOpenMPLoop(OMPD_simd, GetCollapseNumberExpr(Clauses), AStmt, *this, - *DSAStack, VarsWithImplicitDSA, B); + // In presence of clause 'collapse' or 'ordered' with number of loops, it will + // define the nested loops number. + unsigned NestedLoopCount = CheckOpenMPLoop( + OMPD_simd, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses), + AStmt, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); @@ -3503,6 +4167,24 @@ StmtResult Sema::ActOnOpenMPSimdDirective( } } + // OpenMP 4.1 [2.8.1, simd Construct, Restrictions] + // If both simdlen and safelen clauses are specified, the value of the simdlen + // parameter must be less than or equal to the value of the safelen parameter. + OMPSafelenClause *Safelen = nullptr; + OMPSimdlenClause *Simdlen = nullptr; + for (auto *Clause : Clauses) { + if (Clause->getClauseKind() == OMPC_safelen) + Safelen = cast<OMPSafelenClause>(Clause); + else if (Clause->getClauseKind() == OMPC_simdlen) + Simdlen = cast<OMPSimdlenClause>(Clause); + if (Safelen && Simdlen) + break; + } + if (Simdlen && Safelen && + checkSimdlenSafelenValues(*this, Simdlen->getSimdlen(), + Safelen->getSafelen())) + return StmtError(); + getCurFunction()->setHasBranchProtectedScope(); return OMPSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); @@ -3512,31 +4194,52 @@ StmtResult Sema::ActOnOpenMPForDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + if (!AStmt) + return StmtError(); + + assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); OMPLoopDirective::HelperExprs B; - // In presence of clause 'collapse', it will define the nested loops number. - unsigned NestedLoopCount = - CheckOpenMPLoop(OMPD_for, GetCollapseNumberExpr(Clauses), AStmt, *this, - *DSAStack, VarsWithImplicitDSA, B); + // In presence of clause 'collapse' or 'ordered' with number of loops, it will + // define the nested loops number. + unsigned NestedLoopCount = CheckOpenMPLoop( + OMPD_for, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses), + 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 (auto C : Clauses) { + if (auto LC = dyn_cast<OMPLinearClause>(C)) + if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), + B.NumIterations, *this, CurScope)) + return StmtError(); + } + } + getCurFunction()->setHasBranchProtectedScope(); return OMPForDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, - Clauses, AStmt, B); + Clauses, AStmt, B, DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPForSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + if (!AStmt) + return StmtError(); + + assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); OMPLoopDirective::HelperExprs B; - // In presence of clause 'collapse', it will define the nested loops number. + // In presence of clause 'collapse' or 'ordered' with number of loops, it will + // define the nested loops number. unsigned NestedLoopCount = - CheckOpenMPLoop(OMPD_for_simd, GetCollapseNumberExpr(Clauses), AStmt, - *this, *DSAStack, VarsWithImplicitDSA, B); + CheckOpenMPLoop(OMPD_for_simd, getCollapseNumberExpr(Clauses), + getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack, + VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); @@ -3553,6 +4256,24 @@ StmtResult Sema::ActOnOpenMPForSimdDirective( } } + // OpenMP 4.1 [2.8.1, simd Construct, Restrictions] + // If both simdlen and safelen clauses are specified, the value of the simdlen + // parameter must be less than or equal to the value of the safelen parameter. + OMPSafelenClause *Safelen = nullptr; + OMPSimdlenClause *Simdlen = nullptr; + for (auto *Clause : Clauses) { + if (Clause->getClauseKind() == OMPC_safelen) + Safelen = cast<OMPSafelenClause>(Clause); + else if (Clause->getClauseKind() == OMPC_simdlen) + Simdlen = cast<OMPSimdlenClause>(Clause); + if (Safelen && Simdlen) + break; + } + if (Simdlen && Safelen && + checkSimdlenSafelenValues(*this, Simdlen->getSimdlen(), + Safelen->getSafelen())) + return StmtError(); + getCurFunction()->setHasBranchProtectedScope(); return OMPForSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); @@ -3562,23 +4283,28 @@ StmtResult Sema::ActOnOpenMPSectionsDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { - assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + if (!AStmt) + return StmtError(); + + assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); auto BaseStmt = AStmt; while (CapturedStmt *CS = dyn_cast_or_null<CapturedStmt>(BaseStmt)) BaseStmt = CS->getCapturedStmt(); if (auto C = dyn_cast_or_null<CompoundStmt>(BaseStmt)) { auto S = C->children(); - if (!S) + if (S.begin() == S.end()) return StmtError(); // All associated statements must be '#pragma omp section' except for // the first one. - for (Stmt *SectionStmt : ++S) { + for (Stmt *SectionStmt : llvm::make_range(std::next(S.begin()), S.end())) { if (!SectionStmt || !isa<OMPSectionDirective>(SectionStmt)) { if (SectionStmt) Diag(SectionStmt->getLocStart(), diag::err_omp_sections_substmt_not_section); return StmtError(); } + cast<OMPSectionDirective>(SectionStmt) + ->setHasCancel(DSAStack->isCancelRegion()); } } else { Diag(AStmt->getLocStart(), diag::err_omp_sections_not_compound_stmt); @@ -3587,25 +4313,33 @@ StmtResult Sema::ActOnOpenMPSectionsDirective(ArrayRef<OMPClause *> Clauses, getCurFunction()->setHasBranchProtectedScope(); - return OMPSectionsDirective::Create(Context, StartLoc, EndLoc, Clauses, - AStmt); + return OMPSectionsDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, + DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPSectionDirective(Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { - assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + if (!AStmt) + return StmtError(); + + assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); getCurFunction()->setHasBranchProtectedScope(); + DSAStack->setParentCancelRegion(DSAStack->isCancelRegion()); - return OMPSectionDirective::Create(Context, StartLoc, EndLoc, AStmt); + return OMPSectionDirective::Create(Context, StartLoc, EndLoc, AStmt, + DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPSingleDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { - assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + if (!AStmt) + return StmtError(); + + assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); getCurFunction()->setHasBranchProtectedScope(); @@ -3632,30 +4366,81 @@ StmtResult Sema::ActOnOpenMPSingleDirective(ArrayRef<OMPClause *> Clauses, StmtResult Sema::ActOnOpenMPMasterDirective(Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { - assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + if (!AStmt) + return StmtError(); + + assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); getCurFunction()->setHasBranchProtectedScope(); return OMPMasterDirective::Create(Context, StartLoc, EndLoc, AStmt); } -StmtResult -Sema::ActOnOpenMPCriticalDirective(const DeclarationNameInfo &DirName, - Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc) { - assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); +StmtResult Sema::ActOnOpenMPCriticalDirective( + const DeclarationNameInfo &DirName, ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { + if (!AStmt) + return StmtError(); + + assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); + + bool ErrorFound = false; + llvm::APSInt Hint; + SourceLocation HintLoc; + bool DependentHint = false; + for (auto *C : Clauses) { + if (C->getClauseKind() == OMPC_hint) { + if (!DirName.getName()) { + Diag(C->getLocStart(), diag::err_omp_hint_clause_no_name); + ErrorFound = true; + } + Expr *E = cast<OMPHintClause>(C)->getHint(); + if (E->isTypeDependent() || E->isValueDependent() || + E->isInstantiationDependent()) + DependentHint = true; + else { + Hint = E->EvaluateKnownConstInt(Context); + HintLoc = C->getLocStart(); + } + } + } + if (ErrorFound) + return StmtError(); + auto Pair = DSAStack->getCriticalWithHint(DirName); + if (Pair.first && DirName.getName() && !DependentHint) { + if (llvm::APSInt::compareValues(Hint, Pair.second) != 0) { + Diag(StartLoc, diag::err_omp_critical_with_hint); + if (HintLoc.isValid()) { + Diag(HintLoc, diag::note_omp_critical_hint_here) + << 0 << Hint.toString(/*Radix=*/10, /*Signed=*/false); + } else + Diag(StartLoc, diag::note_omp_critical_no_hint) << 0; + if (auto *C = Pair.first->getSingleClause<OMPHintClause>()) { + Diag(C->getLocStart(), diag::note_omp_critical_hint_here) + << 1 + << C->getHint()->EvaluateKnownConstInt(Context).toString( + /*Radix=*/10, /*Signed=*/false); + } else + Diag(Pair.first->getLocStart(), diag::note_omp_critical_no_hint) << 1; + } + } getCurFunction()->setHasBranchProtectedScope(); - return OMPCriticalDirective::Create(Context, DirName, StartLoc, EndLoc, - AStmt); + auto *Dir = OMPCriticalDirective::Create(Context, DirName, StartLoc, EndLoc, + Clauses, AStmt); + if (!Pair.first && DirName.getName() && !DependentHint) + DSAStack->addCriticalWithHint(Dir, Hint); + return Dir; } StmtResult Sema::ActOnOpenMPParallelForDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { - assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + if (!AStmt) + return StmtError(); + CapturedStmt *CS = cast<CapturedStmt>(AStmt); // 1.2.2 OpenMP Language Terminology // Structured block - An executable statement with a single entry at the @@ -3665,26 +4450,41 @@ StmtResult Sema::ActOnOpenMPParallelForDirective( CS->getCapturedDecl()->setNothrow(); OMPLoopDirective::HelperExprs B; - // In presence of clause 'collapse', it will define the nested loops number. + // In presence of clause 'collapse' or 'ordered' with number of loops, it will + // define the nested loops number. unsigned NestedLoopCount = - CheckOpenMPLoop(OMPD_parallel_for, GetCollapseNumberExpr(Clauses), AStmt, - *this, *DSAStack, VarsWithImplicitDSA, B); + CheckOpenMPLoop(OMPD_parallel_for, getCollapseNumberExpr(Clauses), + getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack, + VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); assert((CurContext->isDependentContext() || B.builtAll()) && "omp parallel for loop exprs were not built"); + if (!CurContext->isDependentContext()) { + // Finalize the clauses that need pre-built expressions for CodeGen. + for (auto C : Clauses) { + if (auto LC = dyn_cast<OMPLinearClause>(C)) + if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), + B.NumIterations, *this, CurScope)) + return StmtError(); + } + } + getCurFunction()->setHasBranchProtectedScope(); return OMPParallelForDirective::Create(Context, StartLoc, EndLoc, - NestedLoopCount, Clauses, AStmt, B); + NestedLoopCount, Clauses, AStmt, B, + DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPParallelForSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { - assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + if (!AStmt) + return StmtError(); + CapturedStmt *CS = cast<CapturedStmt>(AStmt); // 1.2.2 OpenMP Language Terminology // Structured block - An executable statement with a single entry at the @@ -3694,10 +4494,12 @@ StmtResult Sema::ActOnOpenMPParallelForSimdDirective( CS->getCapturedDecl()->setNothrow(); OMPLoopDirective::HelperExprs B; - // In presence of clause 'collapse', it will define the nested loops number. + // In presence of clause 'collapse' or 'ordered' with number of loops, it will + // define the nested loops number. unsigned NestedLoopCount = - CheckOpenMPLoop(OMPD_parallel_for_simd, GetCollapseNumberExpr(Clauses), - AStmt, *this, *DSAStack, VarsWithImplicitDSA, B); + CheckOpenMPLoop(OMPD_parallel_for_simd, getCollapseNumberExpr(Clauses), + getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack, + VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); @@ -3711,6 +4513,24 @@ StmtResult Sema::ActOnOpenMPParallelForSimdDirective( } } + // OpenMP 4.1 [2.8.1, simd Construct, Restrictions] + // If both simdlen and safelen clauses are specified, the value of the simdlen + // parameter must be less than or equal to the value of the safelen parameter. + OMPSafelenClause *Safelen = nullptr; + OMPSimdlenClause *Simdlen = nullptr; + for (auto *Clause : Clauses) { + if (Clause->getClauseKind() == OMPC_safelen) + Safelen = cast<OMPSafelenClause>(Clause); + else if (Clause->getClauseKind() == OMPC_simdlen) + Simdlen = cast<OMPSimdlenClause>(Clause); + if (Safelen && Simdlen) + break; + } + if (Simdlen && Safelen && + checkSimdlenSafelenValues(*this, Simdlen->getSimdlen(), + Safelen->getSafelen())) + return StmtError(); + getCurFunction()->setHasBranchProtectedScope(); return OMPParallelForSimdDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); @@ -3720,23 +4540,28 @@ StmtResult Sema::ActOnOpenMPParallelSectionsDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { - assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + if (!AStmt) + return StmtError(); + + assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); auto BaseStmt = AStmt; while (CapturedStmt *CS = dyn_cast_or_null<CapturedStmt>(BaseStmt)) BaseStmt = CS->getCapturedStmt(); if (auto C = dyn_cast_or_null<CompoundStmt>(BaseStmt)) { auto S = C->children(); - if (!S) + if (S.begin() == S.end()) return StmtError(); // All associated statements must be '#pragma omp section' except for // the first one. - for (Stmt *SectionStmt : ++S) { + for (Stmt *SectionStmt : llvm::make_range(std::next(S.begin()), S.end())) { if (!SectionStmt || !isa<OMPSectionDirective>(SectionStmt)) { if (SectionStmt) Diag(SectionStmt->getLocStart(), diag::err_omp_parallel_sections_substmt_not_section); return StmtError(); } + cast<OMPSectionDirective>(SectionStmt) + ->setHasCancel(DSAStack->isCancelRegion()); } } else { Diag(AStmt->getLocStart(), @@ -3746,14 +4571,16 @@ Sema::ActOnOpenMPParallelSectionsDirective(ArrayRef<OMPClause *> Clauses, getCurFunction()->setHasBranchProtectedScope(); - return OMPParallelSectionsDirective::Create(Context, StartLoc, EndLoc, - Clauses, AStmt); + return OMPParallelSectionsDirective::Create( + Context, StartLoc, EndLoc, Clauses, AStmt, DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPTaskDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { - assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + if (!AStmt) + return StmtError(); + CapturedStmt *CS = cast<CapturedStmt>(AStmt); // 1.2.2 OpenMP Language Terminology // Structured block - An executable statement with a single entry at the @@ -3764,7 +4591,8 @@ StmtResult Sema::ActOnOpenMPTaskDirective(ArrayRef<OMPClause *> Clauses, getCurFunction()->setHasBranchProtectedScope(); - return OMPTaskDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); + return OMPTaskDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, + DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPTaskyieldDirective(SourceLocation StartLoc, @@ -3785,7 +4613,10 @@ StmtResult Sema::ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc, StmtResult Sema::ActOnOpenMPTaskgroupDirective(Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { - assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + if (!AStmt) + return StmtError(); + + assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); getCurFunction()->setHasBranchProtectedScope(); @@ -3799,14 +4630,79 @@ StmtResult Sema::ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses, return OMPFlushDirective::Create(Context, StartLoc, EndLoc, Clauses); } -StmtResult Sema::ActOnOpenMPOrderedDirective(Stmt *AStmt, +StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { - assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + OMPClause *DependFound = nullptr; + OMPClause *DependSourceClause = nullptr; + OMPClause *DependSinkClause = nullptr; + bool ErrorFound = false; + OMPThreadsClause *TC = nullptr; + OMPSIMDClause *SC = nullptr; + for (auto *C : Clauses) { + if (auto *DC = dyn_cast<OMPDependClause>(C)) { + DependFound = C; + if (DC->getDependencyKind() == OMPC_DEPEND_source) { + if (DependSourceClause) { + Diag(C->getLocStart(), diag::err_omp_more_one_clause) + << getOpenMPDirectiveName(OMPD_ordered) + << getOpenMPClauseName(OMPC_depend) << 2; + ErrorFound = true; + } else + DependSourceClause = C; + if (DependSinkClause) { + Diag(C->getLocStart(), diag::err_omp_depend_sink_source_not_allowed) + << 0; + ErrorFound = true; + } + } else if (DC->getDependencyKind() == OMPC_DEPEND_sink) { + if (DependSourceClause) { + Diag(C->getLocStart(), diag::err_omp_depend_sink_source_not_allowed) + << 1; + ErrorFound = true; + } + DependSinkClause = C; + } + } else if (C->getClauseKind() == OMPC_threads) + TC = cast<OMPThreadsClause>(C); + else if (C->getClauseKind() == OMPC_simd) + SC = cast<OMPSIMDClause>(C); + } + if (!ErrorFound && !SC && + isOpenMPSimdDirective(DSAStack->getParentDirective())) { + // OpenMP [2.8.1,simd Construct, Restrictions] + // An ordered construct with the simd clause is the only OpenMP construct + // that can appear in the simd region. + Diag(StartLoc, diag::err_omp_prohibited_region_simd); + ErrorFound = true; + } else if (DependFound && (TC || SC)) { + Diag(DependFound->getLocStart(), diag::err_omp_depend_clause_thread_simd) + << getOpenMPClauseName(TC ? TC->getClauseKind() : SC->getClauseKind()); + ErrorFound = true; + } else if (DependFound && !DSAStack->getParentOrderedRegionParam()) { + Diag(DependFound->getLocStart(), + diag::err_omp_ordered_directive_without_param); + ErrorFound = true; + } else if (TC || Clauses.empty()) { + if (auto *Param = DSAStack->getParentOrderedRegionParam()) { + SourceLocation ErrLoc = TC ? TC->getLocStart() : StartLoc; + Diag(ErrLoc, diag::err_omp_ordered_directive_with_param) + << (TC != nullptr); + Diag(Param->getLocStart(), diag::note_omp_ordered_param); + ErrorFound = true; + } + } + if ((!AStmt && !DependFound) || ErrorFound) + return StmtError(); - getCurFunction()->setHasBranchProtectedScope(); + if (AStmt) { + assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); - return OMPOrderedDirective::Create(Context, StartLoc, EndLoc, AStmt); + getCurFunction()->setHasBranchProtectedScope(); + } + + return OMPOrderedDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); } namespace { @@ -4006,7 +4902,7 @@ bool OpenMPAtomicUpdateChecker::checkStatement(Stmt *S, unsigned DiagId, NoteLoc = AtomicUnaryOp->getOperatorLoc(); NoteRange = SourceRange(NoteLoc, NoteLoc); } - } else { + } else if (!AtomicBody->isInstantiationDependent()) { ErrorFound = NotABinaryOrUnaryExpression; NoteLoc = ErrorLoc = AtomicBody->getExprLoc(); NoteRange = ErrorRange = AtomicBody->getSourceRange(); @@ -4053,7 +4949,9 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { - assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + if (!AStmt) + return StmtError(); + auto CS = cast<CapturedStmt>(AStmt); // 1.2.2 OpenMP Language Terminology // Structured block - An executable statement with a single entry at the @@ -4150,7 +5048,7 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, NoteLoc = NotScalarExpr->getExprLoc(); NoteRange = NotScalarExpr->getSourceRange(); } - } else { + } else if (!AtomicBody->isInstantiationDependent()) { ErrorFound = NotAnAssignmentOp; ErrorLoc = AtomicBody->getExprLoc(); ErrorRange = AtomicBody->getSourceRange(); @@ -4211,7 +5109,7 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, NoteLoc = NotScalarExpr->getExprLoc(); NoteRange = NotScalarExpr->getSourceRange(); } - } else { + } else if (!AtomicBody->isInstantiationDependent()) { ErrorFound = NotAnAssignmentOp; ErrorLoc = AtomicBody->getExprLoc(); ErrorRange = AtomicBody->getSourceRange(); @@ -4289,7 +5187,7 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, UE = Checker.getUpdateExpr(); IsXLHSInRHSPart = Checker.isXLHSInRHSPart(); IsPostfixUpdate = Checker.isPostfixUpdate(); - } else { + } else if (!AtomicBody->isInstantiationDependent()) { ErrorLoc = AtomicBody->getExprLoc(); ErrorRange = AtomicBody->getSourceRange(); NoteLoc = AtomicBinOp ? AtomicBinOp->getOperatorLoc() @@ -4396,46 +5294,54 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, } if (!IsUpdateExprFound) { // { v = x; x = expr; } - auto *FirstBinOp = dyn_cast<BinaryOperator>(First); - if (!FirstBinOp || FirstBinOp->getOpcode() != BO_Assign) { - ErrorFound = NotAnAssignmentOp; - NoteLoc = ErrorLoc = FirstBinOp ? FirstBinOp->getOperatorLoc() - : First->getLocStart(); - NoteRange = ErrorRange = FirstBinOp - ? FirstBinOp->getSourceRange() - : SourceRange(ErrorLoc, ErrorLoc); - } else { - auto *SecondBinOp = dyn_cast<BinaryOperator>(Second); - if (!SecondBinOp || SecondBinOp->getOpcode() != BO_Assign) { + auto *FirstExpr = dyn_cast<Expr>(First); + auto *SecondExpr = dyn_cast<Expr>(Second); + if (!FirstExpr || !SecondExpr || + !(FirstExpr->isInstantiationDependent() || + SecondExpr->isInstantiationDependent())) { + auto *FirstBinOp = dyn_cast<BinaryOperator>(First); + if (!FirstBinOp || FirstBinOp->getOpcode() != BO_Assign) { ErrorFound = NotAnAssignmentOp; - NoteLoc = ErrorLoc = SecondBinOp ? SecondBinOp->getOperatorLoc() - : Second->getLocStart(); - NoteRange = ErrorRange = SecondBinOp - ? SecondBinOp->getSourceRange() + NoteLoc = ErrorLoc = FirstBinOp ? FirstBinOp->getOperatorLoc() + : First->getLocStart(); + NoteRange = ErrorRange = FirstBinOp + ? FirstBinOp->getSourceRange() : SourceRange(ErrorLoc, ErrorLoc); } else { - auto *PossibleXRHSInFirst = - FirstBinOp->getRHS()->IgnoreParenImpCasts(); - auto *PossibleXLHSInSecond = - SecondBinOp->getLHS()->IgnoreParenImpCasts(); - llvm::FoldingSetNodeID X1Id, X2Id; - PossibleXRHSInFirst->Profile(X1Id, Context, /*Canonical=*/true); - PossibleXLHSInSecond->Profile(X2Id, Context, - /*Canonical=*/true); - IsUpdateExprFound = X1Id == X2Id; - if (IsUpdateExprFound) { - V = FirstBinOp->getLHS(); - X = SecondBinOp->getLHS(); - E = SecondBinOp->getRHS(); - UE = nullptr; - IsXLHSInRHSPart = false; - IsPostfixUpdate = true; + auto *SecondBinOp = dyn_cast<BinaryOperator>(Second); + if (!SecondBinOp || SecondBinOp->getOpcode() != BO_Assign) { + ErrorFound = NotAnAssignmentOp; + NoteLoc = ErrorLoc = SecondBinOp + ? SecondBinOp->getOperatorLoc() + : Second->getLocStart(); + NoteRange = ErrorRange = + SecondBinOp ? SecondBinOp->getSourceRange() + : SourceRange(ErrorLoc, ErrorLoc); } else { - ErrorFound = NotASpecificExpression; - ErrorLoc = FirstBinOp->getExprLoc(); - ErrorRange = FirstBinOp->getSourceRange(); - NoteLoc = SecondBinOp->getLHS()->getExprLoc(); - NoteRange = SecondBinOp->getRHS()->getSourceRange(); + auto *PossibleXRHSInFirst = + FirstBinOp->getRHS()->IgnoreParenImpCasts(); + auto *PossibleXLHSInSecond = + SecondBinOp->getLHS()->IgnoreParenImpCasts(); + llvm::FoldingSetNodeID X1Id, X2Id; + PossibleXRHSInFirst->Profile(X1Id, Context, + /*Canonical=*/true); + PossibleXLHSInSecond->Profile(X2Id, Context, + /*Canonical=*/true); + IsUpdateExprFound = X1Id == X2Id; + if (IsUpdateExprFound) { + V = FirstBinOp->getLHS(); + X = SecondBinOp->getLHS(); + E = SecondBinOp->getRHS(); + UE = nullptr; + IsXLHSInRHSPart = false; + IsPostfixUpdate = true; + } else { + ErrorFound = NotASpecificExpression; + ErrorLoc = FirstBinOp->getExprLoc(); + ErrorRange = FirstBinOp->getSourceRange(); + NoteLoc = SecondBinOp->getLHS()->getExprLoc(); + NoteRange = SecondBinOp->getRHS()->getSourceRange(); + } } } } @@ -4474,7 +5380,16 @@ StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { - assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + if (!AStmt) + return StmtError(); + + CapturedStmt *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(); // OpenMP [2.16, Nesting of Regions] // If specified, a teams construct must be contained within a target @@ -4511,10 +5426,27 @@ StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses, return OMPTargetDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); } +StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + if (!AStmt) + return StmtError(); + + assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); + + getCurFunction()->setHasBranchProtectedScope(); + + return OMPTargetDataDirective::Create(Context, StartLoc, EndLoc, Clauses, + AStmt); +} + StmtResult Sema::ActOnOpenMPTeamsDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { - assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + if (!AStmt) + return StmtError(); + CapturedStmt *CS = cast<CapturedStmt>(AStmt); // 1.2.2 OpenMP Language Terminology // Structured block - An executable statement with a single entry at the @@ -4550,7 +5482,8 @@ Sema::ActOnOpenMPCancellationPointDirective(SourceLocation StartLoc, CancelRegion); } -StmtResult Sema::ActOnOpenMPCancelDirective(SourceLocation StartLoc, +StmtResult Sema::ActOnOpenMPCancelDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, SourceLocation EndLoc, OpenMPDirectiveKind CancelRegion) { if (CancelRegion != OMPD_parallel && CancelRegion != OMPD_for && @@ -4567,7 +5500,123 @@ StmtResult Sema::ActOnOpenMPCancelDirective(SourceLocation StartLoc, Diag(StartLoc, diag::err_omp_parent_cancel_region_ordered) << 1; return StmtError(); } - return OMPCancelDirective::Create(Context, StartLoc, EndLoc, CancelRegion); + DSAStack->setParentCancelRegion(/*Cancel=*/true); + return OMPCancelDirective::Create(Context, StartLoc, EndLoc, Clauses, + CancelRegion); +} + +static bool checkGrainsizeNumTasksClauses(Sema &S, + ArrayRef<OMPClause *> Clauses) { + OMPClause *PrevClause = nullptr; + bool ErrorFound = false; + for (auto *C : Clauses) { + if (C->getClauseKind() == OMPC_grainsize || + C->getClauseKind() == OMPC_num_tasks) { + if (!PrevClause) + PrevClause = C; + else if (PrevClause->getClauseKind() != C->getClauseKind()) { + S.Diag(C->getLocStart(), + diag::err_omp_grainsize_num_tasks_mutually_exclusive) + << getOpenMPClauseName(C->getClauseKind()) + << getOpenMPClauseName(PrevClause->getClauseKind()); + S.Diag(PrevClause->getLocStart(), + diag::note_omp_previous_grainsize_num_tasks) + << getOpenMPClauseName(PrevClause->getClauseKind()); + ErrorFound = true; + } + } + } + return ErrorFound; +} + +StmtResult Sema::ActOnOpenMPTaskLoopDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<VarDecl *, Expr *> &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_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(); + + getCurFunction()->setHasBranchProtectedScope(); + return OMPTaskLoopDirective::Create(Context, StartLoc, EndLoc, + NestedLoopCount, Clauses, AStmt, B); +} + +StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<VarDecl *, Expr *> &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_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"); + + // 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(); + + getCurFunction()->setHasBranchProtectedScope(); + return OMPTaskLoopSimdDirective::Create(Context, StartLoc, EndLoc, + NestedLoopCount, Clauses, AStmt, B); +} + +StmtResult Sema::ActOnOpenMPDistributeDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + if (!AStmt) + return StmtError(); + + assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); + OMPLoopDirective::HelperExprs B; + // In presence of clause 'collapse' with number of loops, it will + // define the nested loops number. + unsigned NestedLoopCount = + CheckOpenMPLoop(OMPD_distribute, getCollapseNumberExpr(Clauses), + nullptr /*ordered not a clause on distribute*/, AStmt, + *this, *DSAStack, VarsWithImplicitDSA, B); + if (NestedLoopCount == 0) + return StmtError(); + + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp for loop exprs were not built"); + + getCurFunction()->setHasBranchProtectedScope(); + return OMPDistributeDirective::Create(Context, StartLoc, EndLoc, + NestedLoopCount, Clauses, AStmt, B); } OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, @@ -4576,9 +5625,6 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, SourceLocation EndLoc) { OMPClause *Res = nullptr; switch (Kind) { - case OMPC_if: - Res = ActOnOpenMPIfClause(Expr, StartLoc, LParenLoc, EndLoc); - break; case OMPC_final: Res = ActOnOpenMPFinalClause(Expr, StartLoc, LParenLoc, EndLoc); break; @@ -4588,9 +5634,37 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_safelen: Res = ActOnOpenMPSafelenClause(Expr, StartLoc, LParenLoc, EndLoc); break; + case OMPC_simdlen: + Res = ActOnOpenMPSimdlenClause(Expr, StartLoc, LParenLoc, EndLoc); + break; case OMPC_collapse: Res = ActOnOpenMPCollapseClause(Expr, StartLoc, LParenLoc, EndLoc); break; + case OMPC_ordered: + Res = ActOnOpenMPOrderedClause(StartLoc, EndLoc, LParenLoc, Expr); + break; + case OMPC_device: + Res = ActOnOpenMPDeviceClause(Expr, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_num_teams: + Res = ActOnOpenMPNumTeamsClause(Expr, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_thread_limit: + Res = ActOnOpenMPThreadLimitClause(Expr, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_priority: + Res = ActOnOpenMPPriorityClause(Expr, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_grainsize: + Res = ActOnOpenMPGrainsizeClause(Expr, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_num_tasks: + Res = ActOnOpenMPNumTasksClause(Expr, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_hint: + Res = ActOnOpenMPHintClause(Expr, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_if: case OMPC_default: case OMPC_proc_bind: case OMPC_schedule: @@ -4603,7 +5677,6 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_aligned: case OMPC_copyin: case OMPC_copyprivate: - case OMPC_ordered: case OMPC_nowait: case OMPC_untied: case OMPC_mergeable: @@ -4615,14 +5688,21 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_capture: case OMPC_seq_cst: case OMPC_depend: + case OMPC_threads: + case OMPC_simd: + case OMPC_map: + case OMPC_nogroup: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } return Res; } -OMPClause *Sema::ActOnOpenMPIfClause(Expr *Condition, SourceLocation StartLoc, +OMPClause *Sema::ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier, + Expr *Condition, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation NameModifierLoc, + SourceLocation ColonLoc, SourceLocation EndLoc) { Expr *ValExpr = Condition; if (!Condition->isValueDependent() && !Condition->isTypeDependent() && @@ -4636,7 +5716,8 @@ OMPClause *Sema::ActOnOpenMPIfClause(Expr *Condition, SourceLocation StartLoc, ValExpr = Val.get(); } - return new (Context) OMPIfClause(ValExpr, StartLoc, LParenLoc, EndLoc); + return new (Context) OMPIfClause(NameModifier, ValExpr, StartLoc, LParenLoc, + NameModifierLoc, ColonLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition, @@ -4701,38 +5782,52 @@ ExprResult Sema::PerformOpenMPImplicitIntegerConversion(SourceLocation Loc, return PerformContextualImplicitConversion(Loc, Op, ConvertDiagnoser); } +static bool IsNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef, + OpenMPClauseKind CKind, + bool StrictlyPositive) { + if (!ValExpr->isTypeDependent() && !ValExpr->isValueDependent() && + !ValExpr->isInstantiationDependent()) { + SourceLocation Loc = ValExpr->getExprLoc(); + ExprResult Value = + SemaRef.PerformOpenMPImplicitIntegerConversion(Loc, ValExpr); + if (Value.isInvalid()) + return false; + + ValExpr = Value.get(); + // The expression must evaluate to a non-negative integer value. + llvm::APSInt Result; + if (ValExpr->isIntegerConstantExpr(Result, SemaRef.Context) && + Result.isSigned() && + !((!StrictlyPositive && Result.isNonNegative()) || + (StrictlyPositive && Result.isStrictlyPositive()))) { + SemaRef.Diag(Loc, diag::err_omp_negative_expression_in_clause) + << getOpenMPClauseName(CKind) << (StrictlyPositive ? 1 : 0) + << ValExpr->getSourceRange(); + return false; + } + } + return true; +} + OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { Expr *ValExpr = NumThreads; - if (!NumThreads->isValueDependent() && !NumThreads->isTypeDependent() && - !NumThreads->containsUnexpandedParameterPack()) { - SourceLocation NumThreadsLoc = NumThreads->getLocStart(); - ExprResult Val = - PerformOpenMPImplicitIntegerConversion(NumThreadsLoc, NumThreads); - if (Val.isInvalid()) - return nullptr; - ValExpr = Val.get(); - - // OpenMP [2.5, Restrictions] - // The num_threads expression must evaluate to a positive integer value. - llvm::APSInt Result; - if (ValExpr->isIntegerConstantExpr(Result, Context) && Result.isSigned() && - !Result.isStrictlyPositive()) { - Diag(NumThreadsLoc, diag::err_omp_negative_expression_in_clause) - << "num_threads" << NumThreads->getSourceRange(); - return nullptr; - } - } + // OpenMP [2.5, Restrictions] + // The num_threads expression must evaluate to a positive integer value. + if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_num_threads, + /*StrictlyPositive=*/true)) + return nullptr; return new (Context) OMPNumThreadsClause(ValExpr, StartLoc, LParenLoc, EndLoc); } ExprResult Sema::VerifyPositiveIntegerConstantInClause(Expr *E, - OpenMPClauseKind CKind) { + OpenMPClauseKind CKind, + bool StrictlyPositive) { if (!E) return ExprError(); if (E->isValueDependent() || E->isTypeDependent() || @@ -4742,9 +5837,11 @@ ExprResult Sema::VerifyPositiveIntegerConstantInClause(Expr *E, ExprResult ICE = VerifyIntegerConstantExpression(E, &Result); if (ICE.isInvalid()) return ExprError(); - if (!Result.isStrictlyPositive()) { + if ((StrictlyPositive && !Result.isStrictlyPositive()) || + (!StrictlyPositive && !Result.isNonNegative())) { Diag(E->getExprLoc(), diag::err_omp_negative_expression_in_clause) - << getOpenMPClauseName(CKind) << E->getSourceRange(); + << getOpenMPClauseName(CKind) << (StrictlyPositive ? 1 : 0) + << E->getSourceRange(); return ExprError(); } if (CKind == OMPC_aligned && !Result.isPowerOf2()) { @@ -4752,9 +5849,10 @@ ExprResult Sema::VerifyPositiveIntegerConstantInClause(Expr *E, << E->getSourceRange(); return ExprError(); } - if (CKind == OMPC_collapse) { - DSAStack->setCollapseNumber(Result.getExtValue()); - } + if (CKind == OMPC_collapse && DSAStack->getAssociatedLoops() == 1) + DSAStack->setAssociatedLoops(Result.getExtValue()); + else if (CKind == OMPC_ordered) + DSAStack->setAssociatedLoops(Result.getExtValue()); return ICE; } @@ -4771,6 +5869,19 @@ OMPClause *Sema::ActOnOpenMPSafelenClause(Expr *Len, SourceLocation StartLoc, OMPSafelenClause(Safelen.get(), StartLoc, LParenLoc, EndLoc); } +OMPClause *Sema::ActOnOpenMPSimdlenClause(Expr *Len, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + // OpenMP [2.8.1, simd construct, Description] + // The parameter of the simdlen clause must be a constant + // positive integer expression. + ExprResult Simdlen = VerifyPositiveIntegerConstantInClause(Len, OMPC_simdlen); + if (Simdlen.isInvalid()) + return nullptr; + return new (Context) + OMPSimdlenClause(Simdlen.get(), StartLoc, LParenLoc, EndLoc); +} + OMPClause *Sema::ActOnOpenMPCollapseClause(Expr *NumForLoops, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -4788,6 +5899,28 @@ OMPClause *Sema::ActOnOpenMPCollapseClause(Expr *NumForLoops, OMPCollapseClause(NumForLoopsResult.get(), StartLoc, LParenLoc, EndLoc); } +OMPClause *Sema::ActOnOpenMPOrderedClause(SourceLocation StartLoc, + SourceLocation EndLoc, + SourceLocation LParenLoc, + Expr *NumForLoops) { + // OpenMP [2.7.1, loop construct, Description] + // OpenMP [2.8.1, simd construct, Description] + // OpenMP [2.9.6, distribute construct, Description] + // The parameter of the ordered clause must be a constant + // positive integer expression if any. + if (NumForLoops && LParenLoc.isValid()) { + ExprResult NumForLoopsResult = + VerifyPositiveIntegerConstantInClause(NumForLoops, OMPC_ordered); + if (NumForLoopsResult.isInvalid()) + return nullptr; + NumForLoops = NumForLoopsResult.get(); + } else + NumForLoops = nullptr; + DSAStack->setOrderedRegion(/*IsOrdered=*/true, NumForLoops); + return new (Context) + OMPOrderedClause(NumForLoops, StartLoc, LParenLoc, EndLoc); +} + OMPClause *Sema::ActOnOpenMPSimpleClause( OpenMPClauseKind Kind, unsigned Argument, SourceLocation ArgumentLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { @@ -4807,6 +5940,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_final: case OMPC_num_threads: case OMPC_safelen: + case OMPC_simdlen: case OMPC_collapse: case OMPC_schedule: case OMPC_private: @@ -4830,39 +5964,58 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_capture: case OMPC_seq_cst: case OMPC_depend: + case OMPC_device: + case OMPC_threads: + case OMPC_simd: + case OMPC_map: + case OMPC_num_teams: + case OMPC_thread_limit: + case OMPC_priority: + case OMPC_grainsize: + case OMPC_nogroup: + case OMPC_num_tasks: + case OMPC_hint: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } return Res; } +static std::string +getListOfPossibleValues(OpenMPClauseKind K, unsigned First, unsigned Last, + ArrayRef<unsigned> Exclude = llvm::None) { + std::string Values; + unsigned Bound = Last >= 2 ? Last - 2 : 0; + unsigned Skipped = Exclude.size(); + auto S = Exclude.begin(), E = Exclude.end(); + for (unsigned i = First; i < Last; ++i) { + if (std::find(S, E, i) != E) { + --Skipped; + continue; + } + Values += "'"; + Values += getOpenMPSimpleClauseTypeName(K, i); + Values += "'"; + if (i == Bound - Skipped) + Values += " or "; + else if (i != Bound + 1 - Skipped) + Values += ", "; + } + return Values; +} + OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind, SourceLocation KindKwLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { if (Kind == OMPC_DEFAULT_unknown) { - std::string Values; static_assert(OMPC_DEFAULT_unknown > 0, "OMPC_DEFAULT_unknown not greater than 0"); - std::string Sep(", "); - for (unsigned i = 0; i < OMPC_DEFAULT_unknown; ++i) { - Values += "'"; - Values += getOpenMPSimpleClauseTypeName(OMPC_default, i); - Values += "'"; - switch (i) { - case OMPC_DEFAULT_unknown - 2: - Values += " or "; - break; - case OMPC_DEFAULT_unknown - 1: - break; - default: - Values += Sep; - break; - } - } Diag(KindKwLoc, diag::err_omp_unexpected_clause_value) - << Values << getOpenMPClauseName(OMPC_default); + << getListOfPossibleValues(OMPC_default, /*First=*/0, + /*Last=*/OMPC_DEFAULT_unknown) + << getOpenMPClauseName(OMPC_default); return nullptr; } switch (Kind) { @@ -4886,25 +6039,10 @@ OMPClause *Sema::ActOnOpenMPProcBindClause(OpenMPProcBindClauseKind Kind, SourceLocation LParenLoc, SourceLocation EndLoc) { if (Kind == OMPC_PROC_BIND_unknown) { - std::string Values; - std::string Sep(", "); - for (unsigned i = 0; i < OMPC_PROC_BIND_unknown; ++i) { - Values += "'"; - Values += getOpenMPSimpleClauseTypeName(OMPC_proc_bind, i); - Values += "'"; - switch (i) { - case OMPC_PROC_BIND_unknown - 2: - Values += " or "; - break; - case OMPC_PROC_BIND_unknown - 1: - break; - default: - Values += Sep; - break; - } - } Diag(KindKwLoc, diag::err_omp_unexpected_clause_value) - << Values << getOpenMPClauseName(OMPC_proc_bind); + << getListOfPossibleValues(OMPC_proc_bind, /*First=*/0, + /*Last=*/OMPC_PROC_BIND_unknown) + << getOpenMPClauseName(OMPC_proc_bind); return nullptr; } return new (Context) @@ -4912,21 +6050,33 @@ OMPClause *Sema::ActOnOpenMPProcBindClause(OpenMPProcBindClauseKind Kind, } OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( - OpenMPClauseKind Kind, unsigned Argument, Expr *Expr, + OpenMPClauseKind Kind, ArrayRef<unsigned> Argument, Expr *Expr, SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation ArgumentLoc, SourceLocation CommaLoc, + ArrayRef<SourceLocation> ArgumentLoc, SourceLocation DelimLoc, SourceLocation EndLoc) { OMPClause *Res = nullptr; switch (Kind) { case OMPC_schedule: + enum { Modifier1, Modifier2, ScheduleKind, NumberOfElements }; + assert(Argument.size() == NumberOfElements && + ArgumentLoc.size() == NumberOfElements); Res = ActOnOpenMPScheduleClause( - static_cast<OpenMPScheduleClauseKind>(Argument), Expr, StartLoc, - LParenLoc, ArgumentLoc, CommaLoc, EndLoc); + static_cast<OpenMPScheduleClauseModifier>(Argument[Modifier1]), + static_cast<OpenMPScheduleClauseModifier>(Argument[Modifier2]), + static_cast<OpenMPScheduleClauseKind>(Argument[ScheduleKind]), Expr, + StartLoc, LParenLoc, ArgumentLoc[Modifier1], ArgumentLoc[Modifier2], + ArgumentLoc[ScheduleKind], DelimLoc, EndLoc); break; case OMPC_if: + assert(Argument.size() == 1 && ArgumentLoc.size() == 1); + Res = ActOnOpenMPIfClause(static_cast<OpenMPDirectiveKind>(Argument.back()), + Expr, StartLoc, LParenLoc, ArgumentLoc.back(), + DelimLoc, EndLoc); + break; case OMPC_final: case OMPC_num_threads: case OMPC_safelen: + case OMPC_simdlen: case OMPC_collapse: case OMPC_default: case OMPC_proc_bind: @@ -4951,38 +6101,91 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_capture: case OMPC_seq_cst: case OMPC_depend: + case OMPC_device: + case OMPC_threads: + case OMPC_simd: + case OMPC_map: + case OMPC_num_teams: + case OMPC_thread_limit: + case OMPC_priority: + case OMPC_grainsize: + case OMPC_nogroup: + case OMPC_num_tasks: + case OMPC_hint: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } return Res; } +static bool checkScheduleModifiers(Sema &S, OpenMPScheduleClauseModifier M1, + OpenMPScheduleClauseModifier M2, + SourceLocation M1Loc, SourceLocation M2Loc) { + if (M1 == OMPC_SCHEDULE_MODIFIER_unknown && M1Loc.isValid()) { + SmallVector<unsigned, 2> Excluded; + if (M2 != OMPC_SCHEDULE_MODIFIER_unknown) + Excluded.push_back(M2); + if (M2 == OMPC_SCHEDULE_MODIFIER_nonmonotonic) + Excluded.push_back(OMPC_SCHEDULE_MODIFIER_monotonic); + if (M2 == OMPC_SCHEDULE_MODIFIER_monotonic) + Excluded.push_back(OMPC_SCHEDULE_MODIFIER_nonmonotonic); + S.Diag(M1Loc, diag::err_omp_unexpected_clause_value) + << getListOfPossibleValues(OMPC_schedule, + /*First=*/OMPC_SCHEDULE_MODIFIER_unknown + 1, + /*Last=*/OMPC_SCHEDULE_MODIFIER_last, + Excluded) + << getOpenMPClauseName(OMPC_schedule); + return true; + } + return false; +} + OMPClause *Sema::ActOnOpenMPScheduleClause( + OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2, OpenMPScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, - SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc, - SourceLocation EndLoc) { + SourceLocation LParenLoc, SourceLocation M1Loc, SourceLocation M2Loc, + SourceLocation KindLoc, SourceLocation CommaLoc, SourceLocation EndLoc) { + if (checkScheduleModifiers(*this, M1, M2, M1Loc, M2Loc) || + checkScheduleModifiers(*this, M2, M1, M2Loc, M1Loc)) + return nullptr; + // OpenMP, 2.7.1, Loop Construct, Restrictions + // Either the monotonic modifier or the nonmonotonic modifier can be specified + // but not both. + if ((M1 == M2 && M1 != OMPC_SCHEDULE_MODIFIER_unknown) || + (M1 == OMPC_SCHEDULE_MODIFIER_monotonic && + M2 == OMPC_SCHEDULE_MODIFIER_nonmonotonic) || + (M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic && + M2 == OMPC_SCHEDULE_MODIFIER_monotonic)) { + Diag(M2Loc, diag::err_omp_unexpected_schedule_modifier) + << getOpenMPSimpleClauseTypeName(OMPC_schedule, M2) + << getOpenMPSimpleClauseTypeName(OMPC_schedule, M1); + return nullptr; + } if (Kind == OMPC_SCHEDULE_unknown) { std::string Values; - std::string Sep(", "); - for (unsigned i = 0; i < OMPC_SCHEDULE_unknown; ++i) { - Values += "'"; - Values += getOpenMPSimpleClauseTypeName(OMPC_schedule, i); - Values += "'"; - switch (i) { - case OMPC_SCHEDULE_unknown - 2: - Values += " or "; - break; - case OMPC_SCHEDULE_unknown - 1: - break; - default: - Values += Sep; - break; - } + if (M1Loc.isInvalid() && M2Loc.isInvalid()) { + unsigned Exclude[] = {OMPC_SCHEDULE_unknown}; + Values = getListOfPossibleValues(OMPC_schedule, /*First=*/0, + /*Last=*/OMPC_SCHEDULE_MODIFIER_last, + Exclude); + } else { + Values = getListOfPossibleValues(OMPC_schedule, /*First=*/0, + /*Last=*/OMPC_SCHEDULE_unknown); } Diag(KindLoc, diag::err_omp_unexpected_clause_value) << Values << getOpenMPClauseName(OMPC_schedule); return nullptr; } + // OpenMP, 2.7.1, Loop Construct, Restrictions + // The nonmonotonic modifier can only be specified with schedule(dynamic) or + // schedule(guided). + if ((M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic || + M2 == OMPC_SCHEDULE_MODIFIER_nonmonotonic) && + Kind != OMPC_SCHEDULE_dynamic && Kind != OMPC_SCHEDULE_guided) { + Diag(M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic ? M1Loc : M2Loc, + diag::err_omp_schedule_nonmonotonic_static); + return nullptr; + } Expr *ValExpr = ChunkSize; Expr *HelperValExpr = nullptr; if (ChunkSize) { @@ -5004,7 +6207,7 @@ OMPClause *Sema::ActOnOpenMPScheduleClause( if (ValExpr->isIntegerConstantExpr(Result, Context)) { if (Result.isSigned() && !Result.isStrictlyPositive()) { Diag(ChunkSizeLoc, diag::err_omp_negative_expression_in_clause) - << "schedule" << ChunkSize->getSourceRange(); + << "schedule" << 1 << ChunkSize->getSourceRange(); return nullptr; } } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective())) { @@ -5018,8 +6221,9 @@ OMPClause *Sema::ActOnOpenMPScheduleClause( } } - return new (Context) OMPScheduleClause(StartLoc, LParenLoc, KindLoc, CommaLoc, - EndLoc, Kind, ValExpr, HelperValExpr); + return new (Context) + OMPScheduleClause(StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc, Kind, + ValExpr, HelperValExpr, M1, M1Loc, M2, M2Loc); } OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, @@ -5054,10 +6258,20 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_seq_cst: Res = ActOnOpenMPSeqCstClause(StartLoc, EndLoc); break; + case OMPC_threads: + Res = ActOnOpenMPThreadsClause(StartLoc, EndLoc); + break; + case OMPC_simd: + Res = ActOnOpenMPSIMDClause(StartLoc, EndLoc); + break; + case OMPC_nogroup: + Res = ActOnOpenMPNogroupClause(StartLoc, EndLoc); + break; case OMPC_if: case OMPC_final: case OMPC_num_threads: case OMPC_safelen: + case OMPC_simdlen: case OMPC_collapse: case OMPC_schedule: case OMPC_private: @@ -5074,18 +6288,20 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_threadprivate: case OMPC_flush: case OMPC_depend: + case OMPC_device: + case OMPC_map: + case OMPC_num_teams: + case OMPC_thread_limit: + case OMPC_priority: + case OMPC_grainsize: + case OMPC_num_tasks: + case OMPC_hint: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } return Res; } -OMPClause *Sema::ActOnOpenMPOrderedClause(SourceLocation StartLoc, - SourceLocation EndLoc) { - DSAStack->setOrderedRegion(); - return new (Context) OMPOrderedClause(StartLoc, EndLoc); -} - OMPClause *Sema::ActOnOpenMPNowaitClause(SourceLocation StartLoc, SourceLocation EndLoc) { DSAStack->setNowaitRegion(); @@ -5127,12 +6343,28 @@ OMPClause *Sema::ActOnOpenMPSeqCstClause(SourceLocation StartLoc, return new (Context) OMPSeqCstClause(StartLoc, EndLoc); } +OMPClause *Sema::ActOnOpenMPThreadsClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPThreadsClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPSIMDClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPSIMDClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPNogroupClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPNogroupClause(StartLoc, EndLoc); +} + OMPClause *Sema::ActOnOpenMPVarListClause( OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, OpenMPDependClauseKind DepKind, - SourceLocation DepLoc) { + OpenMPLinearClauseKind LinKind, OpenMPMapClauseKind MapTypeModifier, + OpenMPMapClauseKind MapType, SourceLocation DepLinMapLoc) { OMPClause *Res = nullptr; switch (Kind) { case OMPC_private: @@ -5153,7 +6385,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause( break; case OMPC_linear: Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc, - ColonLoc, EndLoc); + LinKind, DepLinMapLoc, ColonLoc, EndLoc); break; case OMPC_aligned: Res = ActOnOpenMPAlignedClause(VarList, TailExpr, StartLoc, LParenLoc, @@ -5169,13 +6401,18 @@ OMPClause *Sema::ActOnOpenMPVarListClause( Res = ActOnOpenMPFlushClause(VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_depend: - Res = ActOnOpenMPDependClause(DepKind, DepLoc, ColonLoc, VarList, StartLoc, - LParenLoc, EndLoc); + Res = ActOnOpenMPDependClause(DepKind, DepLinMapLoc, ColonLoc, VarList, + StartLoc, LParenLoc, EndLoc); + break; + case OMPC_map: + Res = ActOnOpenMPMapClause(MapTypeModifier, MapType, DepLinMapLoc, ColonLoc, + VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_if: case OMPC_final: case OMPC_num_threads: case OMPC_safelen: + case OMPC_simdlen: case OMPC_collapse: case OMPC_default: case OMPC_proc_bind: @@ -5190,6 +6427,16 @@ OMPClause *Sema::ActOnOpenMPVarListClause( case OMPC_update: case OMPC_capture: case OMPC_seq_cst: + case OMPC_device: + case OMPC_threads: + case OMPC_simd: + case OMPC_num_teams: + case OMPC_thread_limit: + case OMPC_priority: + case OMPC_grainsize: + case OMPC_nogroup: + case OMPC_num_tasks: + case OMPC_hint: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } @@ -5240,16 +6487,7 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, diag::err_omp_private_incomplete_type)) { continue; } - if (Type->isReferenceType()) { - Diag(ELoc, diag::err_omp_clause_ref_type_arg) - << getOpenMPClauseName(OMPC_private) << Type; - bool IsDecl = - VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - continue; - } + Type = Type.getNonReferenceType(); // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct] @@ -5290,7 +6528,8 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, // IdResolver, so the code in the OpenMP region uses original variable for // proper diagnostics. Type = Type.getUnqualifiedType(); - auto VDPrivate = buildVarDecl(*this, DE->getExprLoc(), Type, VD->getName()); + auto VDPrivate = buildVarDecl(*this, DE->getExprLoc(), Type, VD->getName(), + VD->hasAttrs() ? &VD->getAttrs() : nullptr); ActOnUninitializedDecl(VDPrivate, /*TypeMayContainAuto=*/false); if (VDPrivate->isInvalidDecl()) continue; @@ -5384,23 +6623,7 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, diag::err_omp_firstprivate_incomplete_type)) { continue; } - if (Type->isReferenceType()) { - if (IsImplicitClause) { - Diag(ImplicitClauseLoc, - diag::err_omp_task_predetermined_firstprivate_ref_type_arg) - << Type; - Diag(RefExpr->getExprLoc(), diag::note_used_here); - } else { - Diag(ELoc, diag::err_omp_clause_ref_type_arg) - << getOpenMPClauseName(OMPC_firstprivate) << Type; - } - bool IsDecl = - VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - continue; - } + Type = Type.getNonReferenceType(); // OpenMP [2.9.3.4, Restrictions, C/C++, p.1] // A variable of class type (or array thereof) that appears in a private @@ -5492,6 +6715,49 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, continue; } } + + // OpenMP 4.5 [2.15.3.4, Restrictions, p.3] + // A list item that is private within a teams region must not appear in a + // firstprivate clause on a distribute construct if any of the distribute + // regions arising from the distribute construct ever bind to any of the + // teams regions arising from the teams construct. + // OpenMP 4.5 [2.15.3.4, Restrictions, p.3] + // A list item that appears in a reduction clause of a teams construct + // must not appear in a firstprivate clause on a distribute construct if + // any of the distribute regions arising from the distribute construct + // ever bind to any of the teams regions arising from the teams construct. + // OpenMP 4.5 [2.10.8, Distribute Construct, p.3] + // A list item may appear in a firstprivate or lastprivate clause but not + // both. + if (CurrDir == OMPD_distribute) { + DVar = DSAStack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_private), + [](OpenMPDirectiveKind K) -> bool { + return isOpenMPTeamsDirective(K); + }, + false); + if (DVar.CKind == OMPC_private && isOpenMPTeamsDirective(DVar.DKind)) { + Diag(ELoc, diag::err_omp_firstprivate_distribute_private_teams); + ReportOriginalDSA(*this, DSAStack, VD, DVar); + continue; + } + DVar = DSAStack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_reduction), + [](OpenMPDirectiveKind K) -> bool { + return isOpenMPTeamsDirective(K); + }, + false); + if (DVar.CKind == OMPC_reduction && + isOpenMPTeamsDirective(DVar.DKind)) { + Diag(ELoc, diag::err_omp_firstprivate_distribute_in_teams_reduction); + ReportOriginalDSA(*this, DSAStack, VD, DVar); + continue; + } + DVar = DSAStack->getTopDSA(VD, false); + if (DVar.CKind == OMPC_lastprivate) { + Diag(ELoc, diag::err_omp_firstprivate_and_lastprivate_in_distribute); + ReportOriginalDSA(*this, DSAStack, VD, DVar); + continue; + } + } } // Variably modified types are not supported for tasks. @@ -5509,7 +6775,8 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, } Type = Type.getUnqualifiedType(); - auto VDPrivate = buildVarDecl(*this, ELoc, Type, VD->getName()); + auto VDPrivate = buildVarDecl(*this, ELoc, Type, VD->getName(), + VD->hasAttrs() ? &VD->getAttrs() : nullptr); // Generate helper private variable and initialize it with the value of the // original variable. The address of the original variable is replaced by // the address of the new private variable in the CodeGen. This new variable @@ -5536,6 +6803,8 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, VDPrivate->setInvalidDecl(); else VDPrivate->setInit(Result.getAs<Expr>()); + // Remove temp variable declaration. + Context.Deallocate(VDInitTemp); } else { auto *VDInit = buildVarDecl(*this, DE->getLocStart(), Type, ".firstprivate.temp"); @@ -5618,16 +6887,7 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, diag::err_omp_lastprivate_incomplete_type)) { continue; } - if (Type->isReferenceType()) { - Diag(ELoc, diag::err_omp_clause_ref_type_arg) - << getOpenMPClauseName(OMPC_lastprivate) << Type; - bool IsDecl = - VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - continue; - } + Type = Type.getNonReferenceType(); // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct] @@ -5674,11 +6934,13 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, // operator for the class type. Type = Context.getBaseElementType(Type).getNonReferenceType(); auto *SrcVD = buildVarDecl(*this, DE->getLocStart(), - Type.getUnqualifiedType(), ".lastprivate.src"); + Type.getUnqualifiedType(), ".lastprivate.src", + VD->hasAttrs() ? &VD->getAttrs() : nullptr); auto *PseudoSrcExpr = buildDeclRefExpr( *this, SrcVD, Type.getUnqualifiedType(), DE->getExprLoc()); auto *DstVD = - buildVarDecl(*this, DE->getLocStart(), Type, ".lastprivate.dst"); + buildVarDecl(*this, DE->getLocStart(), Type, ".lastprivate.dst", + VD->hasAttrs() ? &VD->getAttrs() : nullptr); auto *PseudoDstExpr = buildDeclRefExpr(*this, DstVD, Type, DE->getExprLoc()); // For arrays generate assignment operation for single element and replace @@ -5692,6 +6954,18 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, if (AssignmentOp.isInvalid()) continue; + // OpenMP 4.5 [2.10.8, Distribute Construct, p.3] + // A list item may appear in a firstprivate or lastprivate clause but not + // both. + if (CurrDir == OMPD_distribute) { + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false); + if (DVar.CKind == OMPC_firstprivate) { + Diag(ELoc, diag::err_omp_firstprivate_and_lastprivate_in_distribute); + ReportOriginalDSA(*this, DSAStack, VD, DVar); + continue; + } + } + if (TopDVar.CKind != OMPC_firstprivate) DSAStack->addDSA(VD, DE, OMPC_lastprivate); Vars.push_back(DE); @@ -5879,6 +7153,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause( case OO_Call: case OO_Subscript: case OO_Conditional: + case OO_Coawait: case NUM_OVERLOADED_OPERATORS: llvm_unreachable("Unexpected reduction identifier"); case OO_None: @@ -5903,6 +7178,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause( } SmallVector<Expr *, 8> Vars; + SmallVector<Expr *, 8> Privates; SmallVector<Expr *, 8> LHSs; SmallVector<Expr *, 8> RHSs; SmallVector<Expr *, 8> ReductionOps; @@ -5911,6 +7187,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause( if (isa<DependentScopeDeclRefExpr>(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); + Privates.push_back(nullptr); LHSs.push_back(nullptr); RHSs.push_back(nullptr); ReductionOps.push_back(nullptr); @@ -5922,6 +7199,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause( RefExpr->containsUnexpandedParameterPack()) { // It will be analyzed later. Vars.push_back(RefExpr); + Privates.push_back(nullptr); LHSs.push_back(nullptr); RHSs.push_back(nullptr); ReductionOps.push_back(nullptr); @@ -5937,14 +7215,53 @@ OMPClause *Sema::ActOnOpenMPReductionClause( // OpenMP [2.14.3.3, Restrictions, p.1] // A variable that is part of another variable (as an array or // structure element) cannot appear in a private clause. - auto DE = dyn_cast<DeclRefExpr>(RefExpr); - if (!DE || !isa<VarDecl>(DE->getDecl())) { - Diag(ELoc, diag::err_omp_expected_var_name) << ERange; + auto *DE = dyn_cast<DeclRefExpr>(RefExpr); + auto *ASE = dyn_cast<ArraySubscriptExpr>(RefExpr); + auto *OASE = dyn_cast<OMPArraySectionExpr>(RefExpr); + if (!ASE && !OASE && (!DE || !isa<VarDecl>(DE->getDecl()))) { + Diag(ELoc, diag::err_omp_expected_var_name_or_array_item) << ERange; continue; } - auto D = DE->getDecl(); - auto VD = cast<VarDecl>(D); - auto Type = VD->getType(); + QualType Type; + VarDecl *VD = nullptr; + if (DE) { + auto D = DE->getDecl(); + VD = cast<VarDecl>(D); + Type = VD->getType(); + } else if (ASE) { + Type = ASE->getType(); + auto *Base = ASE->getBase()->IgnoreParenImpCasts(); + while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base)) + Base = TempASE->getBase()->IgnoreParenImpCasts(); + DE = dyn_cast<DeclRefExpr>(Base); + if (DE) + VD = dyn_cast<VarDecl>(DE->getDecl()); + if (!VD) { + Diag(Base->getExprLoc(), diag::err_omp_expected_base_var_name) + << 0 << Base->getSourceRange(); + continue; + } + } else if (OASE) { + auto BaseType = OMPArraySectionExpr::getBaseOriginalType(OASE->getBase()); + if (auto *ATy = BaseType->getAsArrayTypeUnsafe()) + Type = ATy->getElementType(); + else + Type = BaseType->getPointeeType(); + auto *Base = OASE->getBase()->IgnoreParenImpCasts(); + while (auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base)) + Base = TempOASE->getBase()->IgnoreParenImpCasts(); + while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base)) + Base = TempASE->getBase()->IgnoreParenImpCasts(); + DE = dyn_cast<DeclRefExpr>(Base); + if (DE) + VD = dyn_cast<VarDecl>(DE->getDecl()); + if (!VD) { + Diag(Base->getExprLoc(), diag::err_omp_expected_base_var_name) + << 1 << Base->getSourceRange(); + continue; + } + } + // OpenMP [2.9.3.3, Restrictions, C/C++, p.3] // A variable that appears in a private clause must not have an incomplete // type or a reference type. @@ -5955,36 +7272,42 @@ OMPClause *Sema::ActOnOpenMPReductionClause( // Arrays may not appear in a reduction clause. if (Type.getNonReferenceType()->isArrayType()) { Diag(ELoc, diag::err_omp_reduction_type_array) << Type << ERange; - bool IsDecl = - VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; + if (!ASE && !OASE) { + bool IsDecl = VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; + } continue; } // OpenMP [2.14.3.6, reduction clause, Restrictions] // A list item that appears in a reduction clause must not be // const-qualified. if (Type.getNonReferenceType().isConstant(Context)) { - Diag(ELoc, diag::err_omp_const_variable) + Diag(ELoc, diag::err_omp_const_reduction_list_item) << getOpenMPClauseName(OMPC_reduction) << Type << ERange; - bool IsDecl = - VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; + if (!ASE && !OASE) { + bool IsDecl = VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; + } continue; } // OpenMP [2.9.3.6, Restrictions, C/C++, p.4] // If a list-item is a reference type then it must bind to the same object // for all threads of the team. - VarDecl *VDDef = VD->getDefinition(); - if (Type->isReferenceType() && VDDef) { - DSARefChecker Check(DSAStack); - if (Check.Visit(VDDef->getInit())) { - Diag(ELoc, diag::err_omp_reduction_ref_type_arg) << ERange; - Diag(VDDef->getLocation(), diag::note_defined_here) << VDDef; - continue; + if (!ASE && !OASE) { + VarDecl *VDDef = VD->getDefinition(); + if (Type->isReferenceType() && VDDef) { + DSARefChecker Check(DSAStack); + if (Check.Visit(VDDef->getInit())) { + Diag(ELoc, diag::err_omp_reduction_ref_type_arg) << ERange; + Diag(VDDef->getLocation(), diag::note_defined_here) << VDDef; + continue; + } } } // OpenMP [2.14.3.6, reduction clause, Restrictions] @@ -6000,21 +7323,25 @@ OMPClause *Sema::ActOnOpenMPReductionClause( (getLangOpts().CPlusPlus && Type->isArithmeticType()))) { Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg) << getLangOpts().CPlusPlus; - bool IsDecl = - VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; + if (!ASE && !OASE) { + bool IsDecl = VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; + } continue; } if ((BOK == BO_OrAssign || BOK == BO_AndAssign || BOK == BO_XorAssign) && !getLangOpts().CPlusPlus && Type->isFloatingType()) { Diag(ELoc, diag::err_omp_clause_floating_type_arg); - bool IsDecl = - VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; + if (!ASE && !OASE) { + bool IsDecl = VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; + } continue; } // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced @@ -6028,7 +7355,8 @@ OMPClause *Sema::ActOnOpenMPReductionClause( // Any number of reduction clauses can be specified on the directive, // but a list item can appear only once in the reduction clauses for that // directive. - DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false); + DSAStackTy::DSAVarData DVar; + DVar = DSAStack->getTopDSA(VD, false); if (DVar.CKind == OMPC_reduction) { Diag(ELoc, diag::err_omp_once_referenced) << getOpenMPClauseName(OMPC_reduction); @@ -6059,9 +7387,27 @@ OMPClause *Sema::ActOnOpenMPReductionClause( continue; } } + Type = Type.getNonLValueExprType(Context).getUnqualifiedType(); - auto *LHSVD = buildVarDecl(*this, ELoc, Type, ".reduction.lhs"); - auto *RHSVD = buildVarDecl(*this, ELoc, Type, VD->getName()); + auto *LHSVD = buildVarDecl(*this, ELoc, Type, ".reduction.lhs", + VD->hasAttrs() ? &VD->getAttrs() : nullptr); + auto *RHSVD = buildVarDecl(*this, ELoc, Type, VD->getName(), + VD->hasAttrs() ? &VD->getAttrs() : nullptr); + auto PrivateTy = Type; + if (OASE) { + // For array sections only: + // Create pseudo array type for private copy. The size for this array will + // be generated during codegen. + // For array subscripts or single variables Private Ty is the same as Type + // (type of the variable or single array element). + PrivateTy = Context.getVariableArrayType( + Type, new (Context) OpaqueValueExpr(SourceLocation(), + Context.getSizeType(), VK_RValue), + ArrayType::Normal, /*IndexTypeQuals=*/0, SourceRange()); + } + // Private copy. + auto *PrivateVD = buildVarDecl(*this, ELoc, PrivateTy, VD->getName(), + VD->hasAttrs() ? &VD->getAttrs() : nullptr); // Add initializer for private variable. Expr *Init = nullptr; switch (BOK) { @@ -6170,21 +7516,27 @@ OMPClause *Sema::ActOnOpenMPReductionClause( if (Init) { AddInitializerToDecl(RHSVD, Init, /*DirectInit=*/false, /*TypeMayContainAuto=*/false); - } else { + } else ActOnUninitializedDecl(RHSVD, /*TypeMayContainAuto=*/false); - } if (!RHSVD->hasInit()) { Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type << ReductionIdRange; - bool IsDecl = - VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; + if (VD) { + bool IsDecl = VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; + } continue; } + // Store initializer for single element in private copy. Will be used during + // codegen. + PrivateVD->setInit(RHSVD->getInit()); + PrivateVD->setInitStyle(RHSVD->getInitStyle()); auto *LHSDRE = buildDeclRefExpr(*this, LHSVD, Type, ELoc); auto *RHSDRE = buildDeclRefExpr(*this, RHSVD, Type, ELoc); + auto *PrivateDRE = buildDeclRefExpr(*this, PrivateVD, PrivateTy, ELoc); ExprResult ReductionOp = BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), BOK, LHSDRE, RHSDRE); @@ -6201,15 +7553,14 @@ OMPClause *Sema::ActOnOpenMPReductionClause( BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), BO_Assign, LHSDRE, ConditionalOp); } - if (ReductionOp.isUsable()) { - ReductionOp = ActOnFinishFullExpr(ReductionOp.get()); - } + ReductionOp = ActOnFinishFullExpr(ReductionOp.get()); } if (ReductionOp.isInvalid()) continue; DSAStack->addDSA(VD, DE, OMPC_reduction); - Vars.push_back(DE); + Vars.push_back(RefExpr); + Privates.push_back(PrivateDRE); LHSs.push_back(LHSDRE); RHSs.push_back(RHSDRE); ReductionOps.push_back(ReductionOp.get()); @@ -6220,22 +7571,28 @@ OMPClause *Sema::ActOnOpenMPReductionClause( return OMPReductionClause::Create( Context, StartLoc, LParenLoc, ColonLoc, EndLoc, Vars, - ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, LHSs, - RHSs, ReductionOps); + ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, Privates, + LHSs, RHSs, ReductionOps); } -OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation ColonLoc, - SourceLocation EndLoc) { +OMPClause *Sema::ActOnOpenMPLinearClause( + ArrayRef<Expr *> VarList, Expr *Step, SourceLocation StartLoc, + SourceLocation LParenLoc, OpenMPLinearClauseKind LinKind, + SourceLocation LinLoc, SourceLocation ColonLoc, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; + SmallVector<Expr *, 8> Privates; SmallVector<Expr *, 8> Inits; + if ((!LangOpts.CPlusPlus && LinKind != OMPC_LINEAR_val) || + LinKind == OMPC_LINEAR_unknown) { + Diag(LinLoc, diag::err_omp_wrong_linear_modifier) << LangOpts.CPlusPlus; + LinKind = OMPC_LINEAR_val; + } for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP linear clause."); if (isa<DependentScopeDeclRefExpr>(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); + Privates.push_back(nullptr); Inits.push_back(nullptr); continue; } @@ -6278,6 +7635,7 @@ OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step, if (QType->isDependentType() || QType->isInstantiationDependentType()) { // It will be analyzed later. Vars.push_back(DE); + Privates.push_back(nullptr); Inits.push_back(nullptr); continue; } @@ -6287,16 +7645,13 @@ OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step, diag::err_omp_linear_incomplete_type)) { continue; } - if (QType->isReferenceType()) { - Diag(ELoc, diag::err_omp_clause_ref_type_arg) - << getOpenMPClauseName(OMPC_linear) << QType; - bool IsDecl = - VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; + if ((LinKind == OMPC_LINEAR_uval || LinKind == OMPC_LINEAR_ref) && + !QType->isReferenceType()) { + Diag(ELoc, diag::err_omp_wrong_linear_modifier_non_reference) + << QType << getOpenMPSimpleClauseTypeName(OMPC_linear, LinKind); continue; } + QType = QType.getNonReferenceType(); // A list item must not be const-qualified. if (QType.isConstant(Context)) { @@ -6324,14 +7679,25 @@ OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step, continue; } + // Build private copy of original var. + auto *Private = buildVarDecl(*this, ELoc, QType, VD->getName(), + VD->hasAttrs() ? &VD->getAttrs() : nullptr); + auto *PrivateRef = buildDeclRefExpr( + *this, Private, DE->getType().getUnqualifiedType(), DE->getExprLoc()); // Build var to save initial value. VarDecl *Init = buildVarDecl(*this, ELoc, QType, ".linear.start"); - AddInitializerToDecl(Init, DefaultLvalueConversion(DE).get(), + Expr *InitExpr; + if (LinKind == OMPC_LINEAR_uval) + InitExpr = VD->getInit(); + else + InitExpr = DE; + AddInitializerToDecl(Init, DefaultLvalueConversion(InitExpr).get(), /*DirectInit*/ false, /*TypeMayContainAuto*/ false); auto InitRef = buildDeclRefExpr( *this, Init, DE->getType().getUnqualifiedType(), DE->getExprLoc()); DSAStack->addDSA(VD, DE, OMPC_linear); Vars.push_back(DE); + Privates.push_back(PrivateRef); Inits.push_back(InitRef); } @@ -6356,6 +7722,7 @@ OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step, buildDeclRefExpr(*this, SaveVar, StepExpr->getType(), StepLoc); ExprResult CalcStep = BuildBinOp(CurScope, StepLoc, BO_Assign, SaveRef.get(), StepExpr); + CalcStep = ActOnFinishFullExpr(CalcStep.get()); // Warn about zero linear step (it would be probably better specified as // making corresponding variables 'const'). @@ -6371,8 +7738,9 @@ OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step, } } - return OMPLinearClause::Create(Context, StartLoc, LParenLoc, ColonLoc, EndLoc, - Vars, Inits, StepExpr, CalcStepExpr); + return OMPLinearClause::Create(Context, StartLoc, LParenLoc, LinKind, LinLoc, + ColonLoc, EndLoc, Vars, Privates, Inits, + StepExpr, CalcStepExpr); } static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, @@ -6391,27 +7759,35 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, Step = cast<BinaryOperator>(CalcStep)->getLHS(); bool HasErrors = false; auto CurInit = Clause.inits().begin(); + auto CurPrivate = Clause.privates().begin(); + auto LinKind = Clause.getModifier(); for (auto &RefExpr : Clause.varlists()) { Expr *InitExpr = *CurInit; // Build privatized reference to the current linear var. auto DE = cast<DeclRefExpr>(RefExpr); - auto PrivateRef = - buildDeclRefExpr(SemaRef, cast<VarDecl>(DE->getDecl()), - DE->getType().getUnqualifiedType(), DE->getExprLoc(), - /*RefersToCapture=*/true); + Expr *CapturedRef; + if (LinKind == OMPC_LINEAR_uval) + CapturedRef = cast<VarDecl>(DE->getDecl())->getInit(); + else + CapturedRef = + buildDeclRefExpr(SemaRef, cast<VarDecl>(DE->getDecl()), + DE->getType().getUnqualifiedType(), DE->getExprLoc(), + /*RefersToCapture=*/true); // Build update: Var = InitExpr + IV * Step ExprResult Update = - BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), PrivateRef, + BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), *CurPrivate, InitExpr, IV, Step, /* Subtract */ false); - Update = SemaRef.ActOnFinishFullExpr(Update.get()); + Update = SemaRef.ActOnFinishFullExpr(Update.get(), DE->getLocStart(), + /*DiscardedValue=*/true); // Build final: Var = InitExpr + NumIterations * Step ExprResult Final = - BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), PrivateRef, + BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), CapturedRef, InitExpr, NumIterations, Step, /* Subtract */ false); - Final = SemaRef.ActOnFinishFullExpr(Final.get()); + Final = SemaRef.ActOnFinishFullExpr(Final.get(), DE->getLocStart(), + /*DiscardedValue=*/true); if (!Update.isUsable() || !Final.isUsable()) { Updates.push_back(nullptr); Finals.push_back(nullptr); @@ -6420,7 +7796,7 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, Updates.push_back(Update.get()); Finals.push_back(Final.get()); } - ++CurInit; + ++CurInit, ++CurPrivate; } Clause.setUpdates(Updates); Clause.setFinals(Finals); @@ -6557,12 +7933,14 @@ OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList, // copyin clause requires an accessible, unambiguous copy assignment // operator for the class type. auto ElemType = Context.getBaseElementType(Type).getNonReferenceType(); - auto *SrcVD = buildVarDecl(*this, DE->getLocStart(), - ElemType.getUnqualifiedType(), ".copyin.src"); + auto *SrcVD = + buildVarDecl(*this, DE->getLocStart(), ElemType.getUnqualifiedType(), + ".copyin.src", VD->hasAttrs() ? &VD->getAttrs() : nullptr); auto *PseudoSrcExpr = buildDeclRefExpr( *this, SrcVD, ElemType.getUnqualifiedType(), DE->getExprLoc()); auto *DstVD = - buildVarDecl(*this, DE->getLocStart(), ElemType, ".copyin.dst"); + buildVarDecl(*this, DE->getLocStart(), ElemType, ".copyin.dst", + VD->hasAttrs() ? &VD->getAttrs() : nullptr); auto *PseudoDstExpr = buildDeclRefExpr(*this, DstVD, ElemType, DE->getExprLoc()); // For arrays generate assignment operation for single element and replace @@ -6679,13 +8057,16 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, // A variable of class type (or array thereof) that appears in a // copyin clause requires an accessible, unambiguous copy assignment // operator for the class type. - Type = Context.getBaseElementType(Type).getUnqualifiedType(); + Type = Context.getBaseElementType(Type.getNonReferenceType()) + .getUnqualifiedType(); auto *SrcVD = - buildVarDecl(*this, DE->getLocStart(), Type, ".copyprivate.src"); + buildVarDecl(*this, DE->getLocStart(), Type, ".copyprivate.src", + VD->hasAttrs() ? &VD->getAttrs() : nullptr); auto *PseudoSrcExpr = buildDeclRefExpr(*this, SrcVD, Type, DE->getExprLoc()); auto *DstVD = - buildVarDecl(*this, DE->getLocStart(), Type, ".copyprivate.dst"); + buildVarDecl(*this, DE->getLocStart(), Type, ".copyprivate.dst", + VD->hasAttrs() ? &VD->getAttrs() : nullptr); auto *PseudoDstExpr = buildDeclRefExpr(*this, DstVD, Type, DE->getExprLoc()); auto AssignmentOp = BuildBinOp(/*S=*/nullptr, DE->getExprLoc(), BO_Assign, @@ -6727,61 +8108,430 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { - if (DepKind == OMPC_DEPEND_unknown) { - std::string Values; - std::string Sep(", "); - for (unsigned i = 0; i < OMPC_DEPEND_unknown; ++i) { - Values += "'"; - Values += getOpenMPSimpleClauseTypeName(OMPC_depend, i); - Values += "'"; - switch (i) { - case OMPC_DEPEND_unknown - 2: - Values += " or "; - break; - case OMPC_DEPEND_unknown - 1: - break; - default: - Values += Sep; - break; - } - } + if (DSAStack->getCurrentDirective() == OMPD_ordered && + DepKind != OMPC_DEPEND_source && DepKind != OMPC_DEPEND_sink) { + Diag(DepLoc, diag::err_omp_unexpected_clause_value) + << "'source' or 'sink'" << getOpenMPClauseName(OMPC_depend); + return nullptr; + } + if (DSAStack->getCurrentDirective() != OMPD_ordered && + (DepKind == OMPC_DEPEND_unknown || DepKind == OMPC_DEPEND_source || + DepKind == OMPC_DEPEND_sink)) { + unsigned Except[] = {OMPC_DEPEND_source, OMPC_DEPEND_sink}; Diag(DepLoc, diag::err_omp_unexpected_clause_value) - << Values << getOpenMPClauseName(OMPC_depend); + << getListOfPossibleValues(OMPC_depend, /*First=*/0, + /*Last=*/OMPC_DEPEND_unknown, Except) + << getOpenMPClauseName(OMPC_depend); return nullptr; } SmallVector<Expr *, 8> Vars; - for (auto &RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP shared clause."); - if (isa<DependentScopeDeclRefExpr>(RefExpr)) { + llvm::APSInt DepCounter(/*BitWidth=*/32); + llvm::APSInt TotalDepCount(/*BitWidth=*/32); + if (DepKind == OMPC_DEPEND_sink) { + if (auto *OrderedCountExpr = DSAStack->getParentOrderedRegionParam()) { + TotalDepCount = OrderedCountExpr->EvaluateKnownConstInt(Context); + TotalDepCount.setIsUnsigned(/*Val=*/true); + } + } + if ((DepKind != OMPC_DEPEND_sink && DepKind != OMPC_DEPEND_source) || + DSAStack->getParentOrderedRegionParam()) { + for (auto &RefExpr : VarList) { + assert(RefExpr && "NULL expr in OpenMP shared clause."); + if (isa<DependentScopeDeclRefExpr>(RefExpr) || + (DepKind == OMPC_DEPEND_sink && CurContext->isDependentContext())) { + // It will be analyzed later. + Vars.push_back(RefExpr); + continue; + } + + SourceLocation ELoc = RefExpr->getExprLoc(); + auto *SimpleExpr = RefExpr->IgnoreParenCasts(); + if (DepKind == OMPC_DEPEND_sink) { + if (DepCounter >= TotalDepCount) { + Diag(ELoc, diag::err_omp_depend_sink_unexpected_expr); + continue; + } + ++DepCounter; + // OpenMP [2.13.9, Summary] + // depend(dependence-type : vec), where dependence-type is: + // 'sink' and where vec is the iteration vector, which has the form: + // x1 [+- d1], x2 [+- d2 ], . . . , xn [+- dn] + // where n is the value specified by the ordered clause in the loop + // directive, xi denotes the loop iteration variable of the i-th nested + // loop associated with the loop directive, and di is a constant + // non-negative integer. + SimpleExpr = SimpleExpr->IgnoreImplicit(); + auto *DE = dyn_cast<DeclRefExpr>(SimpleExpr); + if (!DE) { + OverloadedOperatorKind OOK = OO_None; + SourceLocation OOLoc; + Expr *LHS, *RHS; + if (auto *BO = dyn_cast<BinaryOperator>(SimpleExpr)) { + OOK = BinaryOperator::getOverloadedOperator(BO->getOpcode()); + OOLoc = BO->getOperatorLoc(); + LHS = BO->getLHS()->IgnoreParenImpCasts(); + RHS = BO->getRHS()->IgnoreParenImpCasts(); + } else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(SimpleExpr)) { + OOK = OCE->getOperator(); + OOLoc = OCE->getOperatorLoc(); + LHS = OCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts(); + RHS = OCE->getArg(/*Arg=*/1)->IgnoreParenImpCasts(); + } else if (auto *MCE = dyn_cast<CXXMemberCallExpr>(SimpleExpr)) { + OOK = MCE->getMethodDecl() + ->getNameInfo() + .getName() + .getCXXOverloadedOperator(); + OOLoc = MCE->getCallee()->getExprLoc(); + LHS = MCE->getImplicitObjectArgument()->IgnoreParenImpCasts(); + RHS = MCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts(); + } else { + Diag(ELoc, diag::err_omp_depend_sink_wrong_expr); + continue; + } + DE = dyn_cast<DeclRefExpr>(LHS); + if (!DE) { + Diag(LHS->getExprLoc(), + diag::err_omp_depend_sink_expected_loop_iteration) + << DSAStack->getParentLoopControlVariable( + DepCounter.getZExtValue()); + continue; + } + if (OOK != OO_Plus && OOK != OO_Minus) { + Diag(OOLoc, diag::err_omp_depend_sink_expected_plus_minus); + continue; + } + ExprResult Res = VerifyPositiveIntegerConstantInClause( + RHS, OMPC_depend, /*StrictlyPositive=*/false); + if (Res.isInvalid()) + continue; + } + auto *VD = dyn_cast<VarDecl>(DE->getDecl()); + if (!CurContext->isDependentContext() && + DSAStack->getParentOrderedRegionParam() && + (!VD || DepCounter != DSAStack->isParentLoopControlVariable(VD))) { + Diag(DE->getExprLoc(), + diag::err_omp_depend_sink_expected_loop_iteration) + << DSAStack->getParentLoopControlVariable( + DepCounter.getZExtValue()); + continue; + } + } else { + // OpenMP [2.11.1.1, Restrictions, p.3] + // A variable that is part of another variable (such as a field of a + // structure) but is not an array element or an array section cannot + // appear in a depend clause. + auto *DE = dyn_cast<DeclRefExpr>(SimpleExpr); + auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr); + auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr); + if (!RefExpr->IgnoreParenImpCasts()->isLValue() || + (!ASE && !DE && !OASE) || (DE && !isa<VarDecl>(DE->getDecl())) || + (ASE && !ASE->getBase()->getType()->isAnyPointerType() && + !ASE->getBase()->getType()->isArrayType())) { + Diag(ELoc, diag::err_omp_expected_var_name_or_array_item) + << RefExpr->getSourceRange(); + continue; + } + } + + Vars.push_back(RefExpr->IgnoreParenImpCasts()); + } + + if (!CurContext->isDependentContext() && DepKind == OMPC_DEPEND_sink && + TotalDepCount > VarList.size() && + DSAStack->getParentOrderedRegionParam()) { + Diag(EndLoc, diag::err_omp_depend_sink_expected_loop_iteration) + << DSAStack->getParentLoopControlVariable(VarList.size() + 1); + } + if (DepKind != OMPC_DEPEND_source && DepKind != OMPC_DEPEND_sink && + Vars.empty()) + return nullptr; + } + + return OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc, DepKind, + DepLoc, ColonLoc, Vars); +} + +OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + Expr *ValExpr = Device; + + // OpenMP [2.9.1, Restrictions] + // The device expression must evaluate to a non-negative integer value. + if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_device, + /*StrictlyPositive=*/false)) + return nullptr; + + return new (Context) OMPDeviceClause(ValExpr, StartLoc, LParenLoc, EndLoc); +} + +static bool IsCXXRecordForMappable(Sema &SemaRef, SourceLocation Loc, + DSAStackTy *Stack, CXXRecordDecl *RD) { + if (!RD || RD->isInvalidDecl()) + return true; + + if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) + if (auto *CTD = CTSD->getSpecializedTemplate()) + RD = CTD->getTemplatedDecl(); + auto QTy = SemaRef.Context.getRecordType(RD); + if (RD->isDynamicClass()) { + SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy; + SemaRef.Diag(RD->getLocation(), diag::note_omp_polymorphic_in_target); + return false; + } + auto *DC = RD; + bool IsCorrect = true; + for (auto *I : DC->decls()) { + if (I) { + if (auto *MD = dyn_cast<CXXMethodDecl>(I)) { + if (MD->isStatic()) { + SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy; + SemaRef.Diag(MD->getLocation(), + diag::note_omp_static_member_in_target); + IsCorrect = false; + } + } else if (auto *VD = dyn_cast<VarDecl>(I)) { + if (VD->isStaticDataMember()) { + SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy; + SemaRef.Diag(VD->getLocation(), + diag::note_omp_static_member_in_target); + IsCorrect = false; + } + } + } + } + + for (auto &I : RD->bases()) { + if (!IsCXXRecordForMappable(SemaRef, I.getLocStart(), Stack, + I.getType()->getAsCXXRecordDecl())) + IsCorrect = false; + } + return IsCorrect; +} + +static bool CheckTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef, + DSAStackTy *Stack, QualType QTy) { + NamedDecl *ND; + if (QTy->isIncompleteType(&ND)) { + SemaRef.Diag(SL, diag::err_incomplete_type) << QTy << SR; + return false; + } else if (CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(ND)) { + if (!RD->isInvalidDecl() && + !IsCXXRecordForMappable(SemaRef, SL, Stack, RD)) + return false; + } + return true; +} + +OMPClause *Sema::ActOnOpenMPMapClause( + OpenMPMapClauseKind MapTypeModifier, OpenMPMapClauseKind MapType, + SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList, + SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { + SmallVector<Expr *, 4> Vars; + + for (auto &RE : VarList) { + assert(RE && "Null expr in omp map"); + if (isa<DependentScopeDeclRefExpr>(RE)) { // It will be analyzed later. - Vars.push_back(RefExpr); + Vars.push_back(RE); continue; } + SourceLocation ELoc = RE->getExprLoc(); - SourceLocation ELoc = RefExpr->getExprLoc(); - // OpenMP [2.11.1.1, Restrictions, p.3] - // A variable that is part of another variable (such as a field of a + // OpenMP [2.14.5, Restrictions] + // A variable that is part of another variable (such as field of a // structure) but is not an array element or an array section cannot appear - // in a depend clause. - auto *SimpleExpr = RefExpr->IgnoreParenCasts(); - DeclRefExpr *DE = dyn_cast<DeclRefExpr>(SimpleExpr); - ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr); - if (!RefExpr->IgnoreParenImpCasts()->isLValue() || (!ASE && !DE) || + // in a map clause. + auto *VE = RE->IgnoreParenLValueCasts(); + + if (VE->isValueDependent() || VE->isTypeDependent() || + VE->isInstantiationDependent() || + VE->containsUnexpandedParameterPack()) { + // It will be analyzed later. + Vars.push_back(RE); + continue; + } + + auto *SimpleExpr = RE->IgnoreParenCasts(); + auto *DE = dyn_cast<DeclRefExpr>(SimpleExpr); + auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr); + auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr); + + if (!RE->IgnoreParenImpCasts()->isLValue() || + (!OASE && !ASE && !DE) || (DE && !isa<VarDecl>(DE->getDecl())) || (ASE && !ASE->getBase()->getType()->isAnyPointerType() && !ASE->getBase()->getType()->isArrayType())) { Diag(ELoc, diag::err_omp_expected_var_name_or_array_item) - << RefExpr->getSourceRange(); + << RE->getSourceRange(); continue; } - Vars.push_back(RefExpr->IgnoreParenImpCasts()); - } + Decl *D = nullptr; + if (DE) { + D = DE->getDecl(); + } else if (ASE) { + auto *B = ASE->getBase()->IgnoreParenCasts(); + D = dyn_cast<DeclRefExpr>(B)->getDecl(); + } else if (OASE) { + auto *B = OASE->getBase(); + D = dyn_cast<DeclRefExpr>(B)->getDecl(); + } + assert(D && "Null decl on map clause."); + auto *VD = cast<VarDecl>(D); + + // OpenMP [2.14.5, Restrictions, p.8] + // threadprivate variables cannot appear in a map clause. + if (DSAStack->isThreadPrivate(VD)) { + auto DVar = DSAStack->getTopDSA(VD, false); + Diag(ELoc, diag::err_omp_threadprivate_in_map); + ReportOriginalDSA(*this, DSAStack, VD, DVar); + continue; + } + + // OpenMP [2.14.5, Restrictions, p.2] + // At most one list item can be an array item derived from a given variable + // in map clauses of the same construct. + // OpenMP [2.14.5, Restrictions, p.3] + // List items of map clauses in the same construct must not share original + // storage. + // OpenMP [2.14.5, Restrictions, C/C++, p.2] + // A variable for which the type is pointer, reference to array, or + // reference to pointer and an array section derived from that variable + // must not appear as list items of map clauses of the same construct. + DSAStackTy::MapInfo MI = DSAStack->IsMappedInCurrentRegion(VD); + if (MI.RefExpr) { + Diag(ELoc, diag::err_omp_map_shared_storage) << ELoc; + Diag(MI.RefExpr->getExprLoc(), diag::note_used_here) + << MI.RefExpr->getSourceRange(); + continue; + } + + // OpenMP [2.14.5, Restrictions, C/C++, p.3,4] + // A variable for which the type is pointer, reference to array, or + // reference to pointer must not appear as a list item if the enclosing + // device data environment already contains an array section derived from + // that variable. + // An array section derived from a variable for which the type is pointer, + // reference to array, or reference to pointer must not appear as a list + // item if the enclosing device data environment already contains that + // variable. + QualType Type = VD->getType(); + MI = DSAStack->getMapInfoForVar(VD); + if (MI.RefExpr && (isa<DeclRefExpr>(MI.RefExpr->IgnoreParenLValueCasts()) != + isa<DeclRefExpr>(VE)) && + (Type->isPointerType() || Type->isReferenceType())) { + Diag(ELoc, diag::err_omp_map_shared_storage) << ELoc; + Diag(MI.RefExpr->getExprLoc(), diag::note_used_here) + << MI.RefExpr->getSourceRange(); + continue; + } + // OpenMP [2.14.5, Restrictions, C/C++, p.7] + // A list item must have a mappable type. + if (!CheckTypeMappable(VE->getExprLoc(), VE->getSourceRange(), *this, + DSAStack, Type)) + continue; + + Vars.push_back(RE); + MI.RefExpr = RE; + DSAStack->addMapInfoForVar(VD, MI); + } if (Vars.empty()) return nullptr; - return OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc, DepKind, - DepLoc, ColonLoc, Vars); + return OMPMapClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars, + MapTypeModifier, MapType, MapLoc); +} + +OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + Expr *ValExpr = NumTeams; + + // OpenMP [teams Constrcut, Restrictions] + // The num_teams expression must evaluate to a positive integer value. + if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_num_teams, + /*StrictlyPositive=*/true)) + return nullptr; + + return new (Context) OMPNumTeamsClause(ValExpr, StartLoc, LParenLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPThreadLimitClause(Expr *ThreadLimit, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + Expr *ValExpr = ThreadLimit; + + // OpenMP [teams Constrcut, Restrictions] + // The thread_limit expression must evaluate to a positive integer value. + if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_thread_limit, + /*StrictlyPositive=*/true)) + return nullptr; + + return new (Context) OMPThreadLimitClause(ValExpr, StartLoc, LParenLoc, + EndLoc); +} + +OMPClause *Sema::ActOnOpenMPPriorityClause(Expr *Priority, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + Expr *ValExpr = Priority; + + // OpenMP [2.9.1, task Constrcut] + // The priority-value is a non-negative numerical scalar expression. + if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_priority, + /*StrictlyPositive=*/false)) + return nullptr; + + return new (Context) OMPPriorityClause(ValExpr, StartLoc, LParenLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPGrainsizeClause(Expr *Grainsize, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + Expr *ValExpr = Grainsize; + + // 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)) + return nullptr; + + return new (Context) OMPGrainsizeClause(ValExpr, StartLoc, LParenLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPNumTasksClause(Expr *NumTasks, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + Expr *ValExpr = NumTasks; + + // 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)) + return nullptr; + + return new (Context) OMPNumTasksClause(ValExpr, StartLoc, LParenLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + // OpenMP [2.13.2, critical construct, Description] + // ... where hint-expression is an integer constant expression that evaluates + // to a valid lock hint. + ExprResult HintExpr = VerifyPositiveIntegerConstantInClause(Hint, OMPC_hint); + if (HintExpr.isInvalid()) + return nullptr; + return new (Context) + OMPHintClause(HintExpr.get(), StartLoc, LParenLoc, EndLoc); } |