diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp | 6525 |
1 files changed, 4843 insertions, 1682 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp index 0d51ee1..b7ac485 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp @@ -15,12 +15,14 @@ #include "TreeTransform.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclOpenMP.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtOpenMP.h" #include "clang/AST/StmtVisitor.h" +#include "clang/AST/TypeOrdering.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" @@ -43,111 +45,91 @@ enum DefaultDataSharingAttributes { DSA_shared = 1 << 1 /// \brief Default data sharing attribute 'shared'. }; -template <class T> struct MatchesAny { - explicit MatchesAny(ArrayRef<T> Arr) : Arr(std::move(Arr)) {} - bool operator()(T Kind) { - for (auto KindEl : Arr) - if (KindEl == Kind) - return true; - return false; - } - -private: - ArrayRef<T> Arr; -}; -struct MatchesAlways { - MatchesAlways() {} - template <class T> bool operator()(T) { return true; } -}; - -typedef MatchesAny<OpenMPClauseKind> MatchesAnyClause; -typedef MatchesAny<OpenMPDirectiveKind> MatchesAnyDirective; - /// \brief Stack for tracking declarations used in OpenMP directives and /// clauses and their data-sharing attributes. -class DSAStackTy { +class DSAStackTy final { public: - struct DSAVarData { - OpenMPDirectiveKind DKind; - OpenMPClauseKind CKind; - DeclRefExpr *RefExpr; + struct DSAVarData final { + OpenMPDirectiveKind DKind = OMPD_unknown; + OpenMPClauseKind CKind = OMPC_unknown; + Expr *RefExpr = nullptr; + DeclRefExpr *PrivateCopy = nullptr; SourceLocation ImplicitDSALoc; - DSAVarData() - : DKind(OMPD_unknown), CKind(OMPC_unknown), RefExpr(nullptr), - ImplicitDSALoc() {} - }; - -public: - struct MapInfo { - Expr *RefExpr; + DSAVarData() {} }; + typedef llvm::SmallVector<std::pair<Expr *, OverloadedOperatorKind>, 4> + OperatorOffsetTy; private: - struct DSAInfo { - OpenMPClauseKind Attributes; - DeclRefExpr *RefExpr; + struct DSAInfo final { + OpenMPClauseKind Attributes = OMPC_unknown; + /// Pointer to a reference expression and a flag which shows that the + /// variable is marked as lastprivate(true) or not (false). + llvm::PointerIntPair<Expr *, 1, bool> RefExpr; + DeclRefExpr *PrivateCopy = nullptr; }; - typedef llvm::SmallDenseMap<VarDecl *, DSAInfo, 64> DeclSAMapTy; - typedef llvm::SmallDenseMap<VarDecl *, DeclRefExpr *, 64> AlignedMapTy; - typedef llvm::DenseMap<VarDecl *, unsigned> LoopControlVariablesMapTy; - typedef llvm::SmallDenseMap<VarDecl *, MapInfo, 64> MappedDeclsTy; + typedef llvm::DenseMap<ValueDecl *, DSAInfo> DeclSAMapTy; + typedef llvm::DenseMap<ValueDecl *, Expr *> AlignedMapTy; + typedef std::pair<unsigned, VarDecl *> LCDeclInfo; + typedef llvm::DenseMap<ValueDecl *, LCDeclInfo> LoopControlVariablesMapTy; + typedef llvm::DenseMap< + ValueDecl *, OMPClauseMappableExprCommon::MappableExprComponentLists> + MappedExprComponentsTy; typedef llvm::StringMap<std::pair<OMPCriticalDirective *, llvm::APSInt>> CriticalsWithHintsTy; + typedef llvm::DenseMap<OMPDependClause *, OperatorOffsetTy> + DoacrossDependMapTy; - struct SharingMapTy { + struct SharingMapTy final { DeclSAMapTy SharingMap; AlignedMapTy AlignedMap; - MappedDeclsTy MappedDecls; + MappedExprComponentsTy MappedExprComponents; LoopControlVariablesMapTy LCVMap; - DefaultDataSharingAttributes DefaultAttr; + DefaultDataSharingAttributes DefaultAttr = DSA_unspecified; SourceLocation DefaultAttrLoc; - OpenMPDirectiveKind Directive; + OpenMPDirectiveKind Directive = OMPD_unknown; DeclarationNameInfo DirectiveName; - Scope *CurScope; + Scope *CurScope = nullptr; SourceLocation ConstructLoc; + /// Set of 'depend' clauses with 'sink|source' dependence kind. Required to + /// get the data (loop counters etc.) about enclosing loop-based construct. + /// This data is required during codegen. + DoacrossDependMapTy DoacrossDepends; /// \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; - bool CancelRegion; - unsigned AssociatedLoops; + bool NowaitRegion = false; + bool CancelRegion = false; + unsigned AssociatedLoops = 1; SourceLocation InnerTeamsRegionLoc; SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name, Scope *CurScope, SourceLocation Loc) - : SharingMap(), AlignedMap(), LCVMap(), DefaultAttr(DSA_unspecified), - Directive(DKind), DirectiveName(std::move(Name)), CurScope(CurScope), - ConstructLoc(Loc), OrderedRegion(), NowaitRegion(false), - CancelRegion(false), AssociatedLoops(1), InnerTeamsRegionLoc() {} - SharingMapTy() - : SharingMap(), AlignedMap(), LCVMap(), DefaultAttr(DSA_unspecified), - Directive(OMPD_unknown), DirectiveName(), CurScope(nullptr), - ConstructLoc(), OrderedRegion(), NowaitRegion(false), - CancelRegion(false), AssociatedLoops(1), InnerTeamsRegionLoc() {} + : Directive(DKind), DirectiveName(Name), CurScope(CurScope), + ConstructLoc(Loc) {} + SharingMapTy() {} }; - typedef SmallVector<SharingMapTy, 64> StackTy; + typedef SmallVector<SharingMapTy, 4> StackTy; /// \brief Stack of used declaration and their data-sharing attributes. StackTy Stack; /// \brief true, if check for DSA must be from parent directive, false, if /// from current directive. - OpenMPClauseKind ClauseKindMode; + OpenMPClauseKind ClauseKindMode = OMPC_unknown; Sema &SemaRef; - bool ForceCapturing; + bool ForceCapturing = false; CriticalsWithHintsTy Criticals; typedef SmallVector<SharingMapTy, 8>::reverse_iterator reverse_iterator; - DSAVarData getDSA(StackTy::reverse_iterator Iter, VarDecl *D); + DSAVarData getDSA(StackTy::reverse_iterator& Iter, ValueDecl *D); /// \brief Checks if the variable is a local for OpenMP region. bool isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter); public: - explicit DSAStackTy(Sema &S) - : Stack(1), ClauseKindMode(OMPC_unknown), SemaRef(S), - ForceCapturing(false) {} + explicit DSAStackTy(Sema &S) : Stack(1), SemaRef(S) {} bool isClauseParsingMode() const { return ClauseKindMode != OMPC_unknown; } void setClauseParsingMode(OpenMPClauseKind K) { ClauseKindMode = K; } @@ -179,51 +161,54 @@ public: /// \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. - DeclRefExpr *addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE); + Expr *addUniqueAligned(ValueDecl *D, Expr *NewDE); /// \brief Register specified variable as loop control variable. - void addLoopControlVariable(VarDecl *D); + void addLoopControlVariable(ValueDecl *D, VarDecl *Capture); /// \brief Check if the specified variable is a loop control variable for /// current region. /// \return The index of the loop control variable in the list of associated /// for-loops (from outer to inner). - unsigned isLoopControlVariable(VarDecl *D); + LCDeclInfo isLoopControlVariable(ValueDecl *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); + LCDeclInfo isParentLoopControlVariable(ValueDecl *D); /// \brief Get the loop control variable for the I-th loop (or nullptr) in /// parent directive. - VarDecl *getParentLoopControlVariable(unsigned I); + ValueDecl *getParentLoopControlVariable(unsigned I); /// \brief Adds explicit data sharing attribute to the specified declaration. - void addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A); + void addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A, + DeclRefExpr *PrivateCopy = nullptr); /// \brief Returns data sharing attributes from top of the stack for the /// specified declaration. - DSAVarData getTopDSA(VarDecl *D, bool FromParent); + DSAVarData getTopDSA(ValueDecl *D, bool FromParent); /// \brief Returns data-sharing attributes for the specified declaration. - DSAVarData getImplicitDSA(VarDecl *D, bool FromParent); + DSAVarData getImplicitDSA(ValueDecl *D, bool FromParent); /// \brief Checks if the specified variables has data-sharing attributes which /// match specified \a CPred predicate in any directive which matches \a DPred /// predicate. - template <class ClausesPredicate, class DirectivesPredicate> - DSAVarData hasDSA(VarDecl *D, ClausesPredicate CPred, - DirectivesPredicate DPred, bool FromParent); + DSAVarData hasDSA(ValueDecl *D, + const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, + const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred, + bool FromParent); /// \brief Checks if the specified variables has data-sharing attributes which /// match specified \a CPred predicate in any innermost directive which /// matches \a DPred predicate. - template <class ClausesPredicate, class DirectivesPredicate> - DSAVarData hasInnermostDSA(VarDecl *D, ClausesPredicate CPred, - DirectivesPredicate DPred, - bool FromParent); + DSAVarData + hasInnermostDSA(ValueDecl *D, + const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, + const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred, + bool FromParent); /// \brief Checks if the specified variables has explicit data-sharing /// attributes which match specified \a CPred predicate at the specified /// OpenMP region. - bool hasExplicitDSA(VarDecl *D, + bool hasExplicitDSA(ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, - unsigned Level); + unsigned Level, bool NotLastprivate = false); /// \brief Returns true if the directive at level \Level matches in the /// specified \a DPred predicate. @@ -232,8 +217,10 @@ public: unsigned Level); /// \brief Finds a directive which matches specified \a DPred predicate. - template <class NamedDirectivesPredicate> - bool hasDirective(NamedDirectivesPredicate DPred, bool FromParent); + bool hasDirective(const llvm::function_ref<bool(OpenMPDirectiveKind, + const DeclarationNameInfo &, + SourceLocation)> &DPred, + bool FromParent); /// \brief Returns currently analyzed directive. OpenMPDirectiveKind getCurrentDirective() const { @@ -245,8 +232,6 @@ 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) { @@ -338,42 +323,92 @@ public: 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; - } + // Do the check specified in \a Check to all component lists and return true + // if any issue is found. + bool checkMappableExprComponentListsForDecl( + ValueDecl *VD, bool CurrentRegionOnly, + const llvm::function_ref<bool( + OMPClauseMappableExprCommon::MappableExprComponentListRef)> &Check) { + auto SI = Stack.rbegin(); + auto SE = Stack.rend(); + + if (SI == SE) + return false; + + if (CurrentRegionOnly) { + SE = std::next(SI); + } else { + ++SI; } - return VarMI; - } - void addMapInfoForVar(VarDecl *VD, MapInfo MI) { - if (Stack.size() > 1) { - Stack.back().MappedDecls[VD] = MI; + for (; SI != SE; ++SI) { + auto MI = SI->MappedExprComponents.find(VD); + if (MI != SI->MappedExprComponents.end()) + for (auto &L : MI->second) + if (Check(L)) + return true; } + return false; } - 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]; + // Create a new mappable expression component list associated with a given + // declaration and initialize it with the provided list of components. + void addMappableExpressionComponents( + ValueDecl *VD, + OMPClauseMappableExprCommon::MappableExprComponentListRef Components) { + assert(Stack.size() > 1 && + "Not expecting to retrieve components from a empty stack!"); + auto &MEC = Stack.back().MappedExprComponents[VD]; + // Create new entry and append the new components there. + MEC.resize(MEC.size() + 1); + MEC.back().append(Components.begin(), Components.end()); + } + + unsigned getNestingLevel() const { + assert(Stack.size() > 1); + return Stack.size() - 2; + } + void addDoacrossDependClause(OMPDependClause *C, OperatorOffsetTy &OpsOffs) { + assert(Stack.size() > 2); + assert(isOpenMPWorksharingDirective(Stack[Stack.size() - 2].Directive)); + Stack[Stack.size() - 2].DoacrossDepends.insert({C, OpsOffs}); + } + llvm::iterator_range<DoacrossDependMapTy::const_iterator> + getDoacrossDependClauses() const { + assert(Stack.size() > 1); + if (isOpenMPWorksharingDirective(Stack[Stack.size() - 1].Directive)) { + auto &Ref = Stack[Stack.size() - 1].DoacrossDepends; + return llvm::make_range(Ref.begin(), Ref.end()); } - return VarMI; + return llvm::make_range(Stack[0].DoacrossDepends.end(), + Stack[0].DoacrossDepends.end()); } }; bool isParallelOrTaskRegion(OpenMPDirectiveKind DKind) { - return isOpenMPParallelDirective(DKind) || DKind == OMPD_task || - isOpenMPTeamsDirective(DKind) || DKind == OMPD_unknown || - isOpenMPTaskLoopDirective(DKind); + return isOpenMPParallelDirective(DKind) || isOpenMPTaskingDirective(DKind) || + isOpenMPTeamsDirective(DKind) || DKind == OMPD_unknown; } } // namespace -DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, - VarDecl *D) { - D = D->getCanonicalDecl(); +static ValueDecl *getCanonicalDecl(ValueDecl *D) { + auto *VD = dyn_cast<VarDecl>(D); + auto *FD = dyn_cast<FieldDecl>(D); + if (VD != nullptr) { + VD = VD->getCanonicalDecl(); + D = VD; + } else { + assert(FD); + FD = FD->getCanonicalDecl(); + D = FD; + } + return D; +} + +DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator& Iter, + ValueDecl *D) { + D = getCanonicalDecl(D); + auto *VD = dyn_cast<VarDecl>(D); + auto *FD = dyn_cast<FieldDecl>(D); DSAVarData DVar; if (Iter == std::prev(Stack.rend())) { // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced @@ -381,14 +416,18 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, // File-scope or namespace-scope variables referenced in called routines // in the region are shared unless they appear in a threadprivate // directive. - if (!D->isFunctionOrMethodVarDecl() && !isa<ParmVarDecl>(D)) + if (VD && !VD->isFunctionOrMethodVarDecl() && !isa<ParmVarDecl>(D)) DVar.CKind = OMPC_shared; // OpenMP [2.9.1.2, Data-sharing Attribute Rules for Variables Referenced // in a region but not in construct] // Variables with static storage duration that are declared in called // routines in the region are shared. - if (D->hasGlobalStorage()) + if (VD && VD->hasGlobalStorage()) + DVar.CKind = OMPC_shared; + + // Non-static data members are shared by default. + if (FD) DVar.CKind = OMPC_shared; return DVar; @@ -399,8 +438,8 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, // in a Construct, C/C++, predetermined, p.1] // Variables with automatic storage duration that are declared in a scope // inside the construct are private. - if (isOpenMPLocal(D, Iter) && D->isLocalVarDecl() && - (D->getStorageClass() == SC_Auto || D->getStorageClass() == SC_None)) { + if (VD && isOpenMPLocal(VD, Iter) && VD->isLocalVarDecl() && + (VD->getStorageClass() == SC_Auto || VD->getStorageClass() == SC_None)) { DVar.CKind = OMPC_private; return DVar; } @@ -408,7 +447,8 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, // Explicitly specified attributes and local variables with predetermined // attributes. if (Iter->SharingMap.count(D)) { - DVar.RefExpr = Iter->SharingMap[D].RefExpr; + DVar.RefExpr = Iter->SharingMap[D].RefExpr.getPointer(); + DVar.PrivateCopy = Iter->SharingMap[D].PrivateCopy; DVar.CKind = Iter->SharingMap[D].Attributes; DVar.ImplicitDSALoc = Iter->DefaultAttrLoc; return DVar; @@ -442,27 +482,24 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, // In a task construct, if no default clause is present, a variable that in // the enclosing context is determined to be shared by all implicit tasks // bound to the current team is shared. - if (DVar.DKind == OMPD_task) { + if (isOpenMPTaskingDirective(DVar.DKind)) { DSAVarData DVarTemp; for (StackTy::reverse_iterator I = std::next(Iter), EE = Stack.rend(); I != EE; ++I) { // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables - // Referenced - // in a Construct, implicitly determined, p.6] + // Referenced in a Construct, implicitly determined, p.6] // In a task construct, if no default clause is present, a variable // whose data-sharing attribute is not determined by the rules above is // firstprivate. DVarTemp = getDSA(I, D); if (DVarTemp.CKind != OMPC_shared) { DVar.RefExpr = nullptr; - DVar.DKind = OMPD_task; DVar.CKind = OMPC_firstprivate; return DVar; } if (isParallelOrTaskRegion(I->Directive)) break; } - DVar.DKind = OMPD_task; DVar.CKind = (DVarTemp.CKind == OMPC_unknown) ? OMPC_firstprivate : OMPC_shared; return DVar; @@ -473,12 +510,12 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, // For constructs other than task, if no default clause is present, these // variables inherit their data-sharing attributes from the enclosing // context. - return getDSA(std::next(Iter), D); + return getDSA(++Iter, D); } -DeclRefExpr *DSAStackTy::addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE) { +Expr *DSAStackTy::addUniqueAligned(ValueDecl *D, Expr *NewDE) { assert(Stack.size() > 1 && "Data sharing attributes stack is empty"); - D = D->getCanonicalDecl(); + D = getCanonicalDecl(D); auto It = Stack.back().AlignedMap.find(D); if (It == Stack.back().AlignedMap.end()) { assert(NewDE && "Unexpected nullptr expr to be added into aligned map"); @@ -491,46 +528,69 @@ DeclRefExpr *DSAStackTy::addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE) { return nullptr; } -void DSAStackTy::addLoopControlVariable(VarDecl *D) { +void DSAStackTy::addLoopControlVariable(ValueDecl *D, VarDecl *Capture) { assert(Stack.size() > 1 && "Data-sharing attributes stack is empty"); - D = D->getCanonicalDecl(); - Stack.back().LCVMap.insert(std::make_pair(D, Stack.back().LCVMap.size() + 1)); + D = getCanonicalDecl(D); + Stack.back().LCVMap.insert( + std::make_pair(D, LCDeclInfo(Stack.back().LCVMap.size() + 1, Capture))); } -unsigned DSAStackTy::isLoopControlVariable(VarDecl *D) { +DSAStackTy::LCDeclInfo DSAStackTy::isLoopControlVariable(ValueDecl *D) { assert(Stack.size() > 1 && "Data-sharing attributes stack is empty"); - D = D->getCanonicalDecl(); - return Stack.back().LCVMap.count(D) > 0 ? Stack.back().LCVMap[D] : 0; + D = getCanonicalDecl(D); + return Stack.back().LCVMap.count(D) > 0 ? Stack.back().LCVMap[D] + : LCDeclInfo(0, nullptr); } -unsigned DSAStackTy::isParentLoopControlVariable(VarDecl *D) { +DSAStackTy::LCDeclInfo DSAStackTy::isParentLoopControlVariable(ValueDecl *D) { assert(Stack.size() > 2 && "Data-sharing attributes stack is empty"); - D = D->getCanonicalDecl(); + D = getCanonicalDecl(D); return Stack[Stack.size() - 2].LCVMap.count(D) > 0 ? Stack[Stack.size() - 2].LCVMap[D] - : 0; + : LCDeclInfo(0, nullptr); } -VarDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) { +ValueDecl *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) + if (Pair.second.first == I) return Pair.first; } return nullptr; } -void DSAStackTy::addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A) { - D = D->getCanonicalDecl(); +void DSAStackTy::addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A, + DeclRefExpr *PrivateCopy) { + D = getCanonicalDecl(D); if (A == OMPC_threadprivate) { - Stack[0].SharingMap[D].Attributes = A; - Stack[0].SharingMap[D].RefExpr = E; + auto &Data = Stack[0].SharingMap[D]; + Data.Attributes = A; + Data.RefExpr.setPointer(E); + Data.PrivateCopy = nullptr; } else { assert(Stack.size() > 1 && "Data-sharing attributes stack is empty"); - Stack.back().SharingMap[D].Attributes = A; - Stack.back().SharingMap[D].RefExpr = E; + auto &Data = Stack.back().SharingMap[D]; + assert(Data.Attributes == OMPC_unknown || (A == Data.Attributes) || + (A == OMPC_firstprivate && Data.Attributes == OMPC_lastprivate) || + (A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) || + (isLoopControlVariable(D).first && A == OMPC_private)); + if (A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) { + Data.RefExpr.setInt(/*IntVal=*/true); + return; + } + const bool IsLastprivate = + A == OMPC_lastprivate || Data.Attributes == OMPC_lastprivate; + Data.Attributes = A; + Data.RefExpr.setPointerAndInt(E, IsLastprivate); + Data.PrivateCopy = PrivateCopy; + if (PrivateCopy) { + auto &Data = Stack.back().SharingMap[PrivateCopy->getDecl()]; + Data.Attributes = A; + Data.RefExpr.setPointerAndInt(PrivateCopy, IsLastprivate); + Data.PrivateCopy = nullptr; + } } } @@ -581,29 +641,35 @@ static DeclRefExpr *buildDeclRefExpr(Sema &S, VarDecl *D, QualType Ty, VK_LValue); } -DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { - D = D->getCanonicalDecl(); +DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) { + D = getCanonicalDecl(D); DSAVarData DVar; // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.1] // Variables appearing in threadprivate directives are threadprivate. - if ((D->getTLSKind() != VarDecl::TLS_None && - !(D->hasAttr<OMPThreadPrivateDeclAttr>() && + auto *VD = dyn_cast<VarDecl>(D); + if ((VD && VD->getTLSKind() != VarDecl::TLS_None && + !(VD->hasAttr<OMPThreadPrivateDeclAttr>() && SemaRef.getLangOpts().OpenMPUseTLS && SemaRef.getASTContext().getTargetInfo().isTLSSupported())) || - (D->getStorageClass() == SC_Register && D->hasAttr<AsmLabelAttr>() && - !D->isLocalVarDecl())) { - addDSA(D, buildDeclRefExpr(SemaRef, D, D->getType().getNonReferenceType(), + (VD && VD->getStorageClass() == SC_Register && + VD->hasAttr<AsmLabelAttr>() && !VD->isLocalVarDecl())) { + addDSA(D, buildDeclRefExpr(SemaRef, VD, D->getType().getNonReferenceType(), D->getLocation()), OMPC_threadprivate); } if (Stack[0].SharingMap.count(D)) { - DVar.RefExpr = Stack[0].SharingMap[D].RefExpr; + DVar.RefExpr = Stack[0].SharingMap[D].RefExpr.getPointer(); DVar.CKind = OMPC_threadprivate; return DVar; } + if (Stack.size() == 1) { + // Not in OpenMP execution region and top scope was already checked. + 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. @@ -611,9 +677,9 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { // 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); + auto &&MatchesAlways = [](OpenMPDirectiveKind) -> bool { return true; }; + if (VD && VD->isStaticDataMember()) { + DSAVarData DVarTemp = hasDSA(D, isOpenMPPrivate, MatchesAlways, FromParent); if (DVarTemp.CKind != OMPC_unknown && DVarTemp.RefExpr) return DVar; @@ -638,8 +704,9 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { RD->hasMutableFields())) { // Variables with const-qualified type having no mutable member may be // listed in a firstprivate clause, even if they are static data members. - DSAVarData DVarTemp = hasDSA(D, MatchesAnyClause(OMPC_firstprivate), - MatchesAlways(), FromParent); + DSAVarData DVarTemp = hasDSA( + D, [](OpenMPClauseKind C) -> bool { return C == OMPC_firstprivate; }, + MatchesAlways, FromParent); if (DVarTemp.CKind == OMPC_firstprivate && DVarTemp.RefExpr) return DVar; @@ -656,7 +723,8 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { } auto I = std::prev(StartI); if (I->SharingMap.count(D)) { - DVar.RefExpr = I->SharingMap[D].RefExpr; + DVar.RefExpr = I->SharingMap[D].RefExpr.getPointer(); + DVar.PrivateCopy = I->SharingMap[D].PrivateCopy; DVar.CKind = I->SharingMap[D].Attributes; DVar.ImplicitDSALoc = I->DefaultAttrLoc; } @@ -664,8 +732,9 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { return DVar; } -DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(VarDecl *D, bool FromParent) { - D = D->getCanonicalDecl(); +DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D, + bool FromParent) { + D = getCanonicalDecl(D); auto StartI = Stack.rbegin(); auto EndI = std::prev(Stack.rend()); if (FromParent && StartI != EndI) { @@ -674,13 +743,14 @@ DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(VarDecl *D, bool FromParent) { return getDSA(StartI, D); } -template <class ClausesPredicate, class DirectivesPredicate> -DSAStackTy::DSAVarData DSAStackTy::hasDSA(VarDecl *D, ClausesPredicate CPred, - DirectivesPredicate DPred, - bool FromParent) { - D = D->getCanonicalDecl(); +DSAStackTy::DSAVarData +DSAStackTy::hasDSA(ValueDecl *D, + const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, + const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred, + bool FromParent) { + D = getCanonicalDecl(D); auto StartI = std::next(Stack.rbegin()); - auto EndI = std::prev(Stack.rend()); + auto EndI = Stack.rend(); if (FromParent && StartI != EndI) { StartI = std::next(StartI); } @@ -694,13 +764,13 @@ DSAStackTy::DSAVarData DSAStackTy::hasDSA(VarDecl *D, ClausesPredicate CPred, return DSAVarData(); } -template <class ClausesPredicate, class DirectivesPredicate> -DSAStackTy::DSAVarData -DSAStackTy::hasInnermostDSA(VarDecl *D, ClausesPredicate CPred, - DirectivesPredicate DPred, bool FromParent) { - D = D->getCanonicalDecl(); +DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA( + ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, + const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred, + bool FromParent) { + D = getCanonicalDecl(D); auto StartI = std::next(Stack.rbegin()); - auto EndI = std::prev(Stack.rend()); + auto EndI = Stack.rend(); if (FromParent && StartI != EndI) { StartI = std::next(StartI); } @@ -716,37 +786,41 @@ DSAStackTy::hasInnermostDSA(VarDecl *D, ClausesPredicate CPred, } bool DSAStackTy::hasExplicitDSA( - VarDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, - unsigned Level) { + ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, + unsigned Level, bool NotLastprivate) { if (CPred(ClauseKindMode)) return true; - if (isClauseParsingMode()) - ++Level; - D = D->getCanonicalDecl(); - auto StartI = Stack.rbegin(); - auto EndI = std::prev(Stack.rend()); + D = getCanonicalDecl(D); + auto StartI = std::next(Stack.begin()); + auto EndI = Stack.end(); if (std::distance(StartI, EndI) <= (int)Level) return false; std::advance(StartI, Level); - return (StartI->SharingMap.count(D) > 0) && StartI->SharingMap[D].RefExpr && - CPred(StartI->SharingMap[D].Attributes); + return (StartI->SharingMap.count(D) > 0) && + StartI->SharingMap[D].RefExpr.getPointer() && + CPred(StartI->SharingMap[D].Attributes) && + (!NotLastprivate || !StartI->SharingMap[D].RefExpr.getInt()); } 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()); + auto StartI = std::next(Stack.begin()); + auto EndI = Stack.end(); 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) { +bool DSAStackTy::hasDirective( + const llvm::function_ref<bool(OpenMPDirectiveKind, + const DeclarationNameInfo &, SourceLocation)> + &DPred, + bool FromParent) { + // We look only in the enclosing region. + if (Stack.size() < 2) + return false; auto StartI = std::next(Stack.rbegin()); auto EndI = std::prev(Stack.rend()); if (FromParent && StartI != EndI) { @@ -759,31 +833,22 @@ 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) { +bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level) { 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(); + auto Ty = D->getType(); - if (isOpenMPTargetDirective(DKind)) { + if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, Level)) { // This table summarizes how a given variable should be passed to the device // given its type and the clauses where it appears. This table is based on // the description in OpenMP 4.5 [2.10.4, target Construct] and @@ -838,31 +903,83 @@ bool Sema::IsOpenMPCapturedByRef(VarDecl *VD, // 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(); + + // Locate map clauses and see if the variable being captured is referred to + // in any of those clauses. Here we only care about variables, not fields, + // because fields are part of aggregates. + bool IsVariableUsedInMapClause = false; + bool IsVariableAssociatedWithSection = false; + + DSAStack->checkMappableExprComponentListsForDecl( + D, /*CurrentRegionOnly=*/true, + [&](OMPClauseMappableExprCommon::MappableExprComponentListRef + MapExprComponents) { + + auto EI = MapExprComponents.rbegin(); + auto EE = MapExprComponents.rend(); + + assert(EI != EE && "Invalid map expression!"); + + if (isa<DeclRefExpr>(EI->getAssociatedExpression())) + IsVariableUsedInMapClause |= EI->getAssociatedDeclaration() == D; + + ++EI; + if (EI == EE) + return false; + + if (isa<ArraySubscriptExpr>(EI->getAssociatedExpression()) || + isa<OMPArraySectionExpr>(EI->getAssociatedExpression()) || + isa<MemberExpr>(EI->getAssociatedExpression())) { + IsVariableAssociatedWithSection = true; + // There is nothing more we need to know about this variable. + return true; + } + + // Keep looking for more map info. + return false; + }); + + if (IsVariableUsedInMapClause) { + // If variable is identified in a map clause it is always captured by + // reference except if it is a pointer that is dereferenced somehow. + IsByRef = !(Ty->isPointerType() && IsVariableAssociatedWithSection); + } else { + // By default, all the data that has a scalar type is mapped by copy. + IsByRef = !Ty->isScalarType(); + } } - // When passing data by value, we need to make sure it fits the uintptr size + if (IsByRef && Ty.getNonReferenceType()->isScalarType()) { + IsByRef = !DSAStack->hasExplicitDSA( + D, [](OpenMPClauseKind K) -> bool { return K == OMPC_firstprivate; }, + Level, /*NotLastprivate=*/true); + } + + // When passing data by copy, 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()))) + Ctx.getDeclAlign(D) > Ctx.getTypeAlignInChars(Ctx.getUIntPtrType()))) { IsByRef = true; + } return IsByRef; } -bool Sema::IsOpenMPCapturedVar(VarDecl *VD) { +unsigned Sema::getOpenMPNestingLevel() const { + assert(getLangOpts().OpenMP); + return DSAStack->getNestingLevel(); +} + +VarDecl *Sema::IsOpenMPCapturedDecl(ValueDecl *D) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); - VD = VD->getCanonicalDecl(); + D = getCanonicalDecl(D); // 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. @@ -871,52 +988,55 @@ bool Sema::IsOpenMPCapturedVar(VarDecl *VD) { // 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()) { + auto *VD = dyn_cast<VarDecl>(D); + if (VD && !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); + !DSAStack->isClauseParsingMode()) + return VD; + if (DSAStack->hasDirective( + [](OpenMPDirectiveKind K, const DeclarationNameInfo &, + SourceLocation) -> bool { + return isOpenMPTargetExecutionDirective(K); }, - false)) { - return true; - } + false)) + return VD; } if (DSAStack->getCurrentDirective() != OMPD_unknown && (!DSAStack->isClauseParsingMode() || DSAStack->getParentDirective() != OMPD_unknown)) { - if (DSAStack->isLoopControlVariable(VD) || - (VD->hasLocalStorage() && + auto &&Info = DSAStack->isLoopControlVariable(D); + if (Info.first || + (VD && VD->hasLocalStorage() && isParallelOrTaskRegion(DSAStack->getCurrentDirective())) || - DSAStack->isForceVarCapturing()) - return true; - auto DVarPrivate = DSAStack->getTopDSA(VD, DSAStack->isClauseParsingMode()); + (VD && DSAStack->isForceVarCapturing())) + return VD ? VD : Info.second; + auto DVarPrivate = DSAStack->getTopDSA(D, DSAStack->isClauseParsingMode()); if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind)) - return true; - DVarPrivate = DSAStack->hasDSA(VD, isOpenMPPrivate, MatchesAlways(), - DSAStack->isClauseParsingMode()); - return DVarPrivate.CKind != OMPC_unknown; + return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl()); + DVarPrivate = DSAStack->hasDSA( + D, isOpenMPPrivate, [](OpenMPDirectiveKind) -> bool { return true; }, + DSAStack->isClauseParsingMode()); + if (DVarPrivate.CKind != OMPC_unknown) + return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl()); } - return false; + return nullptr; } -bool Sema::isOpenMPPrivateVar(VarDecl *VD, unsigned Level) { +bool Sema::isOpenMPPrivateDecl(ValueDecl *D, unsigned Level) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); return DSAStack->hasExplicitDSA( - VD, [](OpenMPClauseKind K) -> bool { return K == OMPC_private; }, Level); + D, [](OpenMPClauseKind K) -> bool { return K == OMPC_private; }, Level); } -bool Sema::isOpenMPTargetCapturedVar(VarDecl *VD, unsigned Level) { +bool Sema::isOpenMPTargetCapturedDecl(ValueDecl *D, 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); + auto *VD = dyn_cast<VarDecl>(D); + return VD && !VD->hasLocalStorage() && + DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, + Level); } void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; } @@ -951,7 +1071,8 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { PrivateCopies.push_back(nullptr); continue; } - auto *VD = cast<VarDecl>(cast<DeclRefExpr>(DE)->getDecl()); + auto *DRE = cast<DeclRefExpr>(DE->IgnoreParens()); + VarDecl *VD = cast<VarDecl>(DRE->getDecl()); QualType Type = VD->getType().getNonReferenceType(); auto DVar = DSAStack->getTopDSA(VD, false); if (DVar.CKind == OMPC_lastprivate) { @@ -975,9 +1096,8 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { } } // Set initializers to private copies if no errors were found. - if (PrivateCopies.size() == Clause->varlist_size()) { + if (PrivateCopies.size() == Clause->varlist_size()) Clause->setPrivateCopies(PrivateCopies); - } } } } @@ -989,7 +1109,7 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, Expr *NumIterations, Sema &SemaRef, - Scope *S); + Scope *S, DSAStackTy *Stack); namespace { @@ -1009,6 +1129,23 @@ public: return false; } }; + +class VarOrFuncDeclFilterCCC : public CorrectionCandidateCallback { +private: + Sema &SemaRef; + +public: + explicit VarOrFuncDeclFilterCCC(Sema &S) : SemaRef(S) {} + bool ValidateCandidate(const TypoCorrection &Candidate) override { + NamedDecl *ND = Candidate.getCorrectionDecl(); + if (isa<VarDecl>(ND) || isa<FunctionDecl>(ND)) { + return SemaRef.isDeclInScope(ND, SemaRef.getCurLexicalContext(), + SemaRef.getCurScope()); + } + return false; + } +}; + } // namespace ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, @@ -1131,8 +1268,10 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, } QualType ExprType = VD->getType().getNonReferenceType(); - ExprResult DE = buildDeclRefExpr(*this, VD, ExprType, Id.getLoc()); - return DE; + return DeclRefExpr::Create(Context, NestedNameSpecifierLoc(), + SourceLocation(), VD, + /*RefersToEnclosingVariableOrCapture=*/false, + Id.getLoc(), ExprType, VK_LValue); } Sema::DeclGroupPtrTy @@ -1142,7 +1281,7 @@ Sema::ActOnOpenMPThreadprivateDirective(SourceLocation Loc, CurContext->addDecl(D); return DeclGroupPtrTy::make(DeclGroupRef(D)); } - return DeclGroupPtrTy(); + return nullptr; } namespace { @@ -1182,6 +1321,10 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) { VarDecl *VD = cast<VarDecl>(DE->getDecl()); SourceLocation ILoc = DE->getExprLoc(); + // Mark variable as used. + VD->setReferenced(); + VD->markUsed(Context); + QualType QType = VD->getType(); if (QType->isDependentType() || QType->isInstantiationDependentType()) { // It will be analyzed later. @@ -1252,7 +1395,7 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) { } static void ReportOriginalDSA(Sema &SemaRef, DSAStackTy *Stack, - const VarDecl *VD, DSAStackTy::DSAVarData DVar, + const ValueDecl *D, DSAStackTy::DSAVarData DVar, bool IsLoopIterVar = false) { if (DVar.RefExpr) { SemaRef.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa) @@ -1272,7 +1415,8 @@ static void ReportOriginalDSA(Sema &SemaRef, DSAStackTy *Stack, PDSA_Implicit } Reason = PDSA_Implicit; bool ReportHint = false; - auto ReportLoc = VD->getLocation(); + auto ReportLoc = D->getLocation(); + auto *VD = dyn_cast<VarDecl>(D); if (IsLoopIterVar) { if (DVar.CKind == OMPC_private) Reason = PDSA_LoopIterVarPrivate; @@ -1280,18 +1424,19 @@ static void ReportOriginalDSA(Sema &SemaRef, DSAStackTy *Stack, Reason = PDSA_LoopIterVarLastprivate; else Reason = PDSA_LoopIterVarLinear; - } else if (DVar.DKind == OMPD_task && DVar.CKind == OMPC_firstprivate) { + } else if (isOpenMPTaskingDirective(DVar.DKind) && + DVar.CKind == OMPC_firstprivate) { Reason = PDSA_TaskVarFirstprivate; ReportLoc = DVar.ImplicitDSALoc; - } else if (VD->isStaticLocal()) + } else if (VD && VD->isStaticLocal()) Reason = PDSA_StaticLocalVarShared; - else if (VD->isStaticDataMember()) + else if (VD && VD->isStaticDataMember()) Reason = PDSA_StaticMemberShared; - else if (VD->isFileVarDecl()) + else if (VD && VD->isFileVarDecl()) Reason = PDSA_GlobalVarShared; - else if (VD->getType().isConstant(SemaRef.getASTContext())) + else if (D->getType().isConstant(SemaRef.getASTContext())) Reason = PDSA_ConstVarShared; - else if (VD->isLocalVarDecl() && DVar.CKind == OMPC_private) { + else if (VD && VD->isLocalVarDecl() && DVar.CKind == OMPC_private) { ReportHint = true; Reason = PDSA_LocalVarPrivate; } @@ -1312,10 +1457,13 @@ class DSAAttrChecker : public StmtVisitor<DSAAttrChecker, void> { bool ErrorFound; CapturedStmt *CS; llvm::SmallVector<Expr *, 8> ImplicitFirstprivate; - llvm::DenseMap<VarDecl *, Expr *> VarsWithInheritedDSA; + llvm::DenseMap<ValueDecl *, Expr *> VarsWithInheritedDSA; public: void VisitDeclRefExpr(DeclRefExpr *E) { + if (E->isTypeDependent() || E->isValueDependent() || + E->containsUnexpandedParameterPack() || E->isInstantiationDependent()) + return; if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) { // Skip internally declared variables. if (VD->isLocalVarDecl() && !CS->capturesVariable(VD)) @@ -1342,14 +1490,14 @@ public: // A list item that appears in a reduction clause of the innermost // enclosing worksharing or parallel construct may not be accessed in an // explicit task. - DVar = Stack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_reduction), - [](OpenMPDirectiveKind K) -> bool { - return isOpenMPParallelDirective(K) || - isOpenMPWorksharingDirective(K) || - isOpenMPTeamsDirective(K); - }, - false); - if (DKind == OMPD_task && DVar.CKind == OMPC_reduction) { + DVar = Stack->hasInnermostDSA( + VD, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; }, + [](OpenMPDirectiveKind K) -> bool { + return isOpenMPParallelDirective(K) || + isOpenMPWorksharingDirective(K) || isOpenMPTeamsDirective(K); + }, + false); + if (isOpenMPTaskingDirective(DKind) && DVar.CKind == OMPC_reduction) { ErrorFound = true; SemaRef.Diag(ELoc, diag::err_omp_reduction_in_task); ReportOriginalDSA(SemaRef, Stack, VD, DVar); @@ -1358,10 +1506,52 @@ public: // Define implicit data-sharing attributes for task. DVar = Stack->getImplicitDSA(VD, false); - if (DKind == OMPD_task && DVar.CKind != OMPC_shared) + if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared && + !Stack->isLoopControlVariable(VD).first) ImplicitFirstprivate.push_back(E); } } + void VisitMemberExpr(MemberExpr *E) { + if (E->isTypeDependent() || E->isValueDependent() || + E->containsUnexpandedParameterPack() || E->isInstantiationDependent()) + return; + if (isa<CXXThisExpr>(E->getBase()->IgnoreParens())) { + if (auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) { + auto DVar = Stack->getTopDSA(FD, false); + // Check if the variable has explicit DSA set and stop analysis if it + // so. + if (DVar.RefExpr) + return; + + auto ELoc = E->getExprLoc(); + auto DKind = Stack->getCurrentDirective(); + // OpenMP [2.9.3.6, Restrictions, p.2] + // A list item that appears in a reduction clause of the innermost + // enclosing worksharing or parallel construct may not be accessed in + // an explicit task. + DVar = Stack->hasInnermostDSA( + FD, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; }, + [](OpenMPDirectiveKind K) -> bool { + return isOpenMPParallelDirective(K) || + isOpenMPWorksharingDirective(K) || + isOpenMPTeamsDirective(K); + }, + false); + if (isOpenMPTaskingDirective(DKind) && DVar.CKind == OMPC_reduction) { + ErrorFound = true; + SemaRef.Diag(ELoc, diag::err_omp_reduction_in_task); + ReportOriginalDSA(SemaRef, Stack, FD, DVar); + return; + } + + // Define implicit data-sharing attributes for task. + DVar = Stack->getImplicitDSA(FD, false); + if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared && + !Stack->isLoopControlVariable(FD).first) + ImplicitFirstprivate.push_back(E); + } + } + } void VisitOMPExecutableDirective(OMPExecutableDirective *S) { for (auto *C : S->clauses()) { // Skip analysis of arguments of implicitly defined firstprivate clause @@ -1382,7 +1572,7 @@ public: bool isErrorFound() { return ErrorFound; } ArrayRef<Expr *> getImplicitFirstprivate() { return ImplicitFirstprivate; } - llvm::DenseMap<VarDecl *, Expr *> &getVarsWithInheritedDSA() { + llvm::DenseMap<ValueDecl *, Expr *> &getVarsWithInheritedDSA() { return VarsWithInheritedDSA; } @@ -1393,84 +1583,11 @@ public: void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { switch (DKind) { - case OMPD_parallel: { - QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); - QualType KmpInt32PtrTy = - Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); - Sema::CapturedParamNameType Params[] = { - std::make_pair(".global_tid.", KmpInt32PtrTy), - std::make_pair(".bound_tid.", KmpInt32PtrTy), - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_simd: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_for: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_for_simd: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_sections: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_section: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_single: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_master: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_critical: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_parallel_for: { + case OMPD_parallel: + case OMPD_parallel_for: + case OMPD_parallel_for_simd: + case OMPD_parallel_sections: + case OMPD_teams: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); @@ -1483,46 +1600,78 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { Params); break; } - case OMPD_parallel_for_simd: { - QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); - QualType KmpInt32PtrTy = - Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); + case OMPD_simd: + case OMPD_for: + case OMPD_for_simd: + case OMPD_sections: + case OMPD_section: + case OMPD_single: + case OMPD_master: + case OMPD_critical: + case OMPD_taskgroup: + case OMPD_distribute: + case OMPD_ordered: + case OMPD_atomic: + case OMPD_target_data: + case OMPD_target: + case OMPD_target_parallel: + case OMPD_target_parallel_for: + case OMPD_target_parallel_for_simd: { Sema::CapturedParamNameType Params[] = { - std::make_pair(".global_tid.", KmpInt32PtrTy), - std::make_pair(".bound_tid.", KmpInt32PtrTy), std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); break; } - case OMPD_parallel_sections: { + case OMPD_task: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); - QualType KmpInt32PtrTy = - Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); + QualType Args[] = {Context.VoidPtrTy.withConst().withRestrict()}; + FunctionProtoType::ExtProtoInfo EPI; + EPI.Variadic = true; + QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI); Sema::CapturedParamNameType Params[] = { - std::make_pair(".global_tid.", KmpInt32PtrTy), - std::make_pair(".bound_tid.", KmpInt32PtrTy), + std::make_pair(".global_tid.", KmpInt32Ty), + std::make_pair(".part_id.", Context.getPointerType(KmpInt32Ty)), + std::make_pair(".privates.", Context.VoidPtrTy.withConst()), + std::make_pair(".copy_fn.", + Context.getPointerType(CopyFnType).withConst()), + std::make_pair(".task_t.", Context.VoidPtrTy.withConst()), std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); + // Mark this captured region as inlined, because we don't use outlined + // function directly. + getCurCapturedRegion()->TheCapturedDecl->addAttr( + AlwaysInlineAttr::CreateImplicit( + Context, AlwaysInlineAttr::Keyword_forceinline, SourceRange())); break; } - case OMPD_task: { - QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); + case OMPD_taskloop: + case OMPD_taskloop_simd: { + QualType KmpInt32Ty = + Context.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1); + QualType KmpUInt64Ty = + Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0); + QualType KmpInt64Ty = + Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1); QualType Args[] = {Context.VoidPtrTy.withConst().withRestrict()}; FunctionProtoType::ExtProtoInfo EPI; EPI.Variadic = true; QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI); Sema::CapturedParamNameType Params[] = { std::make_pair(".global_tid.", KmpInt32Ty), - std::make_pair(".part_id.", KmpInt32Ty), + std::make_pair(".part_id.", Context.getPointerType(KmpInt32Ty)), std::make_pair(".privates.", Context.VoidPtrTy.withConst().withRestrict()), std::make_pair( ".copy_fn.", Context.getPointerType(CopyFnType).withConst().withRestrict()), + std::make_pair(".task_t.", Context.VoidPtrTy.withConst()), + std::make_pair(".lb.", KmpUInt64Ty), + std::make_pair(".ub.", KmpUInt64Ty), std::make_pair(".st.", KmpInt64Ty), + std::make_pair(".liter.", KmpInt32Ty), std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, @@ -1534,70 +1683,17 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { Context, AlwaysInlineAttr::Keyword_forceinline, SourceRange())); break; } - case OMPD_ordered: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_atomic: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_target_data: - case OMPD_target: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_teams: { + case OMPD_distribute_parallel_for_simd: + case OMPD_distribute_simd: + case OMPD_distribute_parallel_for: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); Sema::CapturedParamNameType Params[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), std::make_pair(".bound_tid.", KmpInt32PtrTy), - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_taskgroup: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - 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(".previous.lb.", Context.getSizeType()), + std::make_pair(".previous.ub.", Context.getSizeType()), std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, @@ -1611,12 +1707,78 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_cancellation_point: case OMPD_cancel: case OMPD_flush: + case OMPD_target_enter_data: + case OMPD_target_exit_data: + case OMPD_declare_reduction: + case OMPD_declare_simd: + case OMPD_declare_target: + case OMPD_end_declare_target: + case OMPD_target_update: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); } } +static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id, + Expr *CaptureExpr, bool WithInit, + bool AsExpression) { + assert(CaptureExpr); + ASTContext &C = S.getASTContext(); + Expr *Init = AsExpression ? CaptureExpr : CaptureExpr->IgnoreImpCasts(); + QualType Ty = Init->getType(); + if (CaptureExpr->getObjectKind() == OK_Ordinary && CaptureExpr->isGLValue()) { + if (S.getLangOpts().CPlusPlus) + Ty = C.getLValueReferenceType(Ty); + else { + Ty = C.getPointerType(Ty); + ExprResult Res = + S.CreateBuiltinUnaryOp(CaptureExpr->getExprLoc(), UO_AddrOf, Init); + if (!Res.isUsable()) + return nullptr; + Init = Res.get(); + } + WithInit = true; + } + auto *CED = OMPCapturedExprDecl::Create(C, S.CurContext, Id, Ty); + if (!WithInit) + CED->addAttr(OMPCaptureNoInitAttr::CreateImplicit(C, SourceRange())); + S.CurContext->addHiddenDecl(CED); + S.AddInitializerToDecl(CED, Init, /*DirectInit=*/false, + /*TypeMayContainAuto=*/true); + return CED; +} + +static DeclRefExpr *buildCapture(Sema &S, ValueDecl *D, Expr *CaptureExpr, + bool WithInit) { + OMPCapturedExprDecl *CD; + if (auto *VD = S.IsOpenMPCapturedDecl(D)) + CD = cast<OMPCapturedExprDecl>(VD); + else + CD = buildCaptureDecl(S, D->getIdentifier(), CaptureExpr, WithInit, + /*AsExpression=*/false); + return buildDeclRefExpr(S, CD, CD->getType().getNonReferenceType(), + CaptureExpr->getExprLoc()); +} + +static ExprResult buildCapture(Sema &S, Expr *CaptureExpr, DeclRefExpr *&Ref) { + if (!Ref) { + auto *CD = + buildCaptureDecl(S, &S.getASTContext().Idents.get(".capture_expr."), + CaptureExpr, /*WithInit=*/true, /*AsExpression=*/true); + Ref = buildDeclRefExpr(S, CD, CD->getType().getNonReferenceType(), + CaptureExpr->getExprLoc()); + } + ExprResult Res = Ref; + if (!S.getLangOpts().CPlusPlus && + CaptureExpr->getObjectKind() == OK_Ordinary && CaptureExpr->isGLValue() && + Ref->getType()->isPointerType()) + Res = S.CreateBuiltinUnaryOp(CaptureExpr->getExprLoc(), UO_Deref, Ref); + if (!Res.isUsable()) + return ExprError(); + return CaptureExpr->isGLValue() ? Res : S.DefaultLvalueConversion(Res.get()); +} + StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, ArrayRef<OMPClause *> Clauses) { if (!S.isUsable()) { @@ -1642,14 +1804,20 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, } } DSAStack->setForceVarCapturing(/*V=*/false); - } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective()) && - Clause->getClauseKind() == OMPC_schedule) { + } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective())) { // Mark all variables in private list clauses as used in inner region. // 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); + if (auto *C = OMPClauseWithPreInit::get(Clause)) { + if (auto *DS = cast_or_null<DeclStmt>(C->getPreInitStmt())) { + for (auto *D : DS->decls()) + MarkVariableReferenced(D->getLocation(), cast<VarDecl>(D)); + } + } + if (auto *C = OMPClauseWithPostUpdate::get(Clause)) { + if (auto *E = C->getPostUpdateExpr()) + MarkDeclarationsReferencedInExpr(E); + } } if (Clause->getClauseKind() == OMPC_schedule) SC = cast<OMPScheduleClause>(Clause); @@ -1725,13 +1893,25 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | parallel | ordered | + | // | parallel | atomic | * | // | parallel | target | * | + // | parallel | target parallel | * | + // | parallel | target parallel | * | + // | | for | | + // | parallel | target enter | * | + // | | data | | + // | parallel | target exit | * | + // | | data | | // | parallel | teams | + | // | parallel | cancellation | | // | | point | ! | // | parallel | cancel | ! | // | parallel | taskloop | * | // | parallel | taskloop simd | * | - // | parallel | distribute | | + // | parallel | distribute | + | + // | parallel | distribute | + | + // | | parallel for | | + // | parallel | distribute | + | + // | |parallel for simd| | + // | parallel | distribute simd | + | // +------------------+-----------------+------------------------------------+ // | for | parallel | * | // | for | for | + | @@ -1754,13 +1934,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | for | ordered | * (if construct is ordered) | // | for | atomic | * | // | for | target | * | + // | for | target parallel | * | + // | for | target parallel | * | + // | | for | | + // | for | target enter | * | + // | | data | | + // | for | target exit | * | + // | | data | | // | for | teams | + | // | for | cancellation | | // | | point | ! | // | for | cancel | ! | // | for | taskloop | * | // | for | taskloop simd | * | - // | for | distribute | | + // | for | distribute | + | + // | for | distribute | + | + // | | parallel for | | + // | for | distribute | + | + // | |parallel for simd| | + // | for | distribute simd | + | + // | for | target parallel | + | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | master | parallel | * | // | master | for | + | @@ -1783,13 +1977,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | master | ordered | + | // | master | atomic | * | // | master | target | * | + // | master | target parallel | * | + // | master | target parallel | * | + // | | for | | + // | master | target enter | * | + // | | data | | + // | master | target exit | * | + // | | data | | // | master | teams | + | // | master | cancellation | | // | | point | | // | master | cancel | | // | master | taskloop | * | // | master | taskloop simd | * | - // | master | distribute | | + // | master | distribute | + | + // | master | distribute | + | + // | | parallel for | | + // | master | distribute | + | + // | |parallel for simd| | + // | master | distribute simd | + | + // | master | target parallel | + | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | critical | parallel | * | // | critical | for | + | @@ -1811,20 +2019,34 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | critical | ordered | + | // | critical | atomic | * | // | critical | target | * | + // | critical | target parallel | * | + // | critical | target parallel | * | + // | | for | | + // | critical | target enter | * | + // | | data | | + // | critical | target exit | * | + // | | data | | // | critical | teams | + | // | critical | cancellation | | // | | point | | // | critical | cancel | | // | critical | taskloop | * | // | critical | taskloop simd | * | - // | critical | distribute | | + // | critical | distribute | + | + // | critical | distribute | + | + // | | parallel for | | + // | critical | distribute | + | + // | |parallel for simd| | + // | critical | distribute simd | + | + // | critical | target parallel | + | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | simd | parallel | | // | simd | for | | // | simd | for simd | | // | simd | master | | // | simd | critical | | - // | simd | simd | | + // | simd | simd | * | // | simd | sections | | // | simd | section | | // | simd | single | | @@ -1840,6 +2062,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | simd | ordered | + (with simd clause) | // | simd | atomic | | // | simd | target | | + // | simd | target parallel | | + // | simd | target parallel | | + // | | for | | + // | simd | target enter | | + // | | data | | + // | simd | target exit | | + // | | data | | // | simd | teams | | // | simd | cancellation | | // | | point | | @@ -1847,13 +2076,20 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | simd | taskloop | | // | simd | taskloop simd | | // | simd | distribute | | + // | simd | distribute | | + // | | parallel for | | + // | simd | distribute | | + // | |parallel for simd| | + // | simd | distribute simd | | + // | simd | target parallel | | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | for simd | parallel | | // | for simd | for | | // | for simd | for simd | | // | for simd | master | | // | for simd | critical | | - // | for simd | simd | | + // | for simd | simd | * | // | for simd | sections | | // | for simd | section | | // | for simd | single | | @@ -1869,6 +2105,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | for simd | ordered | + (with simd clause) | // | for simd | atomic | | // | for simd | target | | + // | for simd | target parallel | | + // | for simd | target parallel | | + // | | for | | + // | for simd | target enter | | + // | | data | | + // | for simd | target exit | | + // | | data | | // | for simd | teams | | // | for simd | cancellation | | // | | point | | @@ -1876,13 +2119,20 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | for simd | taskloop | | // | for simd | taskloop simd | | // | for simd | distribute | | + // | for simd | distribute | | + // | | parallel for | | + // | for simd | distribute | | + // | |parallel for simd| | + // | for simd | distribute simd | | + // | for simd | target parallel | | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | parallel for simd| parallel | | // | parallel for simd| for | | // | parallel for simd| for simd | | // | parallel for simd| master | | // | parallel for simd| critical | | - // | parallel for simd| simd | | + // | parallel for simd| simd | * | // | parallel for simd| sections | | // | parallel for simd| section | | // | parallel for simd| single | | @@ -1898,6 +2148,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | parallel for simd| ordered | + (with simd clause) | // | parallel for simd| atomic | | // | parallel for simd| target | | + // | parallel for simd| target parallel | | + // | parallel for simd| target parallel | | + // | | for | | + // | parallel for simd| target enter | | + // | | data | | + // | parallel for simd| target exit | | + // | | data | | // | parallel for simd| teams | | // | parallel for simd| cancellation | | // | | point | | @@ -1905,6 +2162,12 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | parallel for simd| taskloop | | // | parallel for simd| taskloop simd | | // | parallel for simd| distribute | | + // | parallel for simd| distribute | | + // | | parallel for | | + // | parallel for simd| distribute | | + // | |parallel for simd| | + // | parallel for simd| distribute simd | | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | sections | parallel | * | // | sections | for | + | @@ -1927,13 +2190,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | sections | ordered | + | // | sections | atomic | * | // | sections | target | * | + // | sections | target parallel | * | + // | sections | target parallel | * | + // | | for | | + // | sections | target enter | * | + // | | data | | + // | sections | target exit | * | + // | | data | | // | sections | teams | + | // | sections | cancellation | | // | | point | ! | // | sections | cancel | ! | // | sections | taskloop | * | // | sections | taskloop simd | * | - // | sections | distribute | | + // | sections | distribute | + | + // | sections | distribute | + | + // | | parallel for | | + // | sections | distribute | + | + // | |parallel for simd| | + // | sections | distribute simd | + | + // | sections | target parallel | + | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | section | parallel | * | // | section | for | + | @@ -1956,13 +2233,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | section | ordered | + | // | section | atomic | * | // | section | target | * | + // | section | target parallel | * | + // | section | target parallel | * | + // | | for | | + // | section | target enter | * | + // | | data | | + // | section | target exit | * | + // | | data | | // | section | teams | + | // | section | cancellation | | // | | point | ! | // | section | cancel | ! | // | section | taskloop | * | // | section | taskloop simd | * | - // | section | distribute | | + // | section | distribute | + | + // | section | distribute | + | + // | | parallel for | | + // | section | distribute | + | + // | |parallel for simd| | + // | section | distribute simd | + | + // | section | target parallel | + | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | single | parallel | * | // | single | for | + | @@ -1985,13 +2276,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | single | ordered | + | // | single | atomic | * | // | single | target | * | + // | single | target parallel | * | + // | single | target parallel | * | + // | | for | | + // | single | target enter | * | + // | | data | | + // | single | target exit | * | + // | | data | | // | single | teams | + | // | single | cancellation | | // | | point | | // | single | cancel | | // | single | taskloop | * | // | single | taskloop simd | * | - // | single | distribute | | + // | single | distribute | + | + // | single | distribute | + | + // | | parallel for | | + // | single | distribute | + | + // | |parallel for simd| | + // | single | distribute simd | + | + // | single | target parallel | + | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | parallel for | parallel | * | // | parallel for | for | + | @@ -2014,13 +2319,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | parallel for | ordered | * (if construct is ordered) | // | parallel for | atomic | * | // | parallel for | target | * | + // | parallel for | target parallel | * | + // | parallel for | target parallel | * | + // | | for | | + // | parallel for | target enter | * | + // | | data | | + // | parallel for | target exit | * | + // | | data | | // | parallel for | teams | + | // | parallel for | cancellation | | // | | point | ! | // | parallel for | cancel | ! | // | parallel for | taskloop | * | // | parallel for | taskloop simd | * | - // | parallel for | distribute | | + // | parallel for | distribute | + | + // | parallel for | distribute | + | + // | | parallel for | | + // | parallel for | distribute | + | + // | |parallel for simd| | + // | parallel for | distribute simd | + | + // | parallel for | target parallel | + | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | parallel sections| parallel | * | // | parallel sections| for | + | @@ -2043,13 +2362,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | parallel sections| ordered | + | // | parallel sections| atomic | * | // | parallel sections| target | * | + // | parallel sections| target parallel | * | + // | parallel sections| target parallel | * | + // | | for | | + // | parallel sections| target enter | * | + // | | data | | + // | parallel sections| target exit | * | + // | | data | | // | parallel sections| teams | + | // | parallel sections| cancellation | | // | | point | ! | // | parallel sections| cancel | ! | // | parallel sections| taskloop | * | // | parallel sections| taskloop simd | * | - // | parallel sections| distribute | | + // | parallel sections| distribute | + | + // | parallel sections| distribute | + | + // | | parallel for | | + // | parallel sections| distribute | + | + // | |parallel for simd| | + // | parallel sections| distribute simd | + | + // | parallel sections| target parallel | + | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | task | parallel | * | // | task | for | + | @@ -2072,13 +2405,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | task | ordered | + | // | task | atomic | * | // | task | target | * | + // | task | target parallel | * | + // | task | target parallel | * | + // | | for | | + // | task | target enter | * | + // | | data | | + // | task | target exit | * | + // | | data | | // | task | teams | + | // | task | cancellation | | // | | point | ! | // | task | cancel | ! | // | task | taskloop | * | // | task | taskloop simd | * | - // | task | distribute | | + // | task | distribute | + | + // | task | distribute | + | + // | | parallel for | | + // | task | distribute | + | + // | |parallel for simd| | + // | task | distribute simd | + | + // | task | target parallel | + | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | ordered | parallel | * | // | ordered | for | + | @@ -2101,13 +2448,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | ordered | ordered | + | // | ordered | atomic | * | // | ordered | target | * | + // | ordered | target parallel | * | + // | ordered | target parallel | * | + // | | for | | + // | ordered | target enter | * | + // | | data | | + // | ordered | target exit | * | + // | | data | | // | ordered | teams | + | // | ordered | cancellation | | // | | point | | // | ordered | cancel | | // | ordered | taskloop | * | // | ordered | taskloop simd | * | - // | ordered | distribute | | + // | ordered | distribute | + | + // | ordered | distribute | + | + // | | parallel for | | + // | ordered | distribute | + | + // | |parallel for simd| | + // | ordered | distribute simd | + | + // | ordered | target parallel | + | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | atomic | parallel | | // | atomic | for | | @@ -2130,13 +2491,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | atomic | ordered | | // | atomic | atomic | | // | atomic | target | | + // | atomic | target parallel | | + // | atomic | target parallel | | + // | | for | | + // | atomic | target enter | | + // | | data | | + // | atomic | target exit | | + // | | data | | // | atomic | teams | | // | atomic | cancellation | | // | | point | | // | atomic | cancel | | // | atomic | taskloop | | // | atomic | taskloop simd | | - // | atomic | distribute | | + // | atomic | distribute | | + // | atomic | distribute | | + // | | parallel for | | + // | atomic | distribute | | + // | |parallel for simd| | + // | atomic | distribute simd | | + // | atomic | target parallel | | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | target | parallel | * | // | target | for | * | @@ -2158,14 +2533,142 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | target | flush | * | // | target | ordered | * | // | target | atomic | * | - // | target | target | * | + // | target | target | | + // | target | target parallel | | + // | target | target parallel | | + // | | for | | + // | target | target enter | | + // | | data | | + // | target | target exit | | + // | | data | | // | target | teams | * | // | target | cancellation | | // | | point | | // | target | cancel | | // | target | taskloop | * | // | target | taskloop simd | * | - // | target | distribute | | + // | target | distribute | + | + // | target | distribute | + | + // | | parallel for | | + // | target | distribute | + | + // | |parallel for simd| | + // | target | distribute simd | + | + // | target | target parallel | | + // | | for simd | | + // +------------------+-----------------+------------------------------------+ + // | target parallel | parallel | * | + // | target parallel | for | * | + // | target parallel | for simd | * | + // | target parallel | master | * | + // | target parallel | critical | * | + // | target parallel | simd | * | + // | target parallel | sections | * | + // | target parallel | section | * | + // | target parallel | single | * | + // | target parallel | parallel for | * | + // | target parallel |parallel for simd| * | + // | target parallel |parallel sections| * | + // | target parallel | task | * | + // | target parallel | taskyield | * | + // | target parallel | barrier | * | + // | target parallel | taskwait | * | + // | target parallel | taskgroup | * | + // | target parallel | flush | * | + // | target parallel | ordered | * | + // | target parallel | atomic | * | + // | target parallel | target | | + // | target parallel | target parallel | | + // | target parallel | target parallel | | + // | | for | | + // | target parallel | target enter | | + // | | data | | + // | target parallel | target exit | | + // | | data | | + // | target parallel | teams | | + // | target parallel | cancellation | | + // | | point | ! | + // | target parallel | cancel | ! | + // | target parallel | taskloop | * | + // | target parallel | taskloop simd | * | + // | target parallel | distribute | | + // | target parallel | distribute | | + // | | parallel for | | + // | target parallel | distribute | | + // | |parallel for simd| | + // | target parallel | distribute simd | | + // | target parallel | target parallel | | + // | | for simd | | + // +------------------+-----------------+------------------------------------+ + // | target parallel | parallel | * | + // | for | | | + // | target parallel | for | * | + // | for | | | + // | target parallel | for simd | * | + // | for | | | + // | target parallel | master | * | + // | for | | | + // | target parallel | critical | * | + // | for | | | + // | target parallel | simd | * | + // | for | | | + // | target parallel | sections | * | + // | for | | | + // | target parallel | section | * | + // | for | | | + // | target parallel | single | * | + // | for | | | + // | target parallel | parallel for | * | + // | for | | | + // | target parallel |parallel for simd| * | + // | for | | | + // | target parallel |parallel sections| * | + // | for | | | + // | target parallel | task | * | + // | for | | | + // | target parallel | taskyield | * | + // | for | | | + // | target parallel | barrier | * | + // | for | | | + // | target parallel | taskwait | * | + // | for | | | + // | target parallel | taskgroup | * | + // | for | | | + // | target parallel | flush | * | + // | for | | | + // | target parallel | ordered | * | + // | for | | | + // | target parallel | atomic | * | + // | for | | | + // | target parallel | target | | + // | for | | | + // | target parallel | target parallel | | + // | for | | | + // | target parallel | target parallel | | + // | for | for | | + // | target parallel | target enter | | + // | for | data | | + // | target parallel | target exit | | + // | for | data | | + // | target parallel | teams | | + // | for | | | + // | target parallel | cancellation | | + // | for | point | ! | + // | target parallel | cancel | ! | + // | for | | | + // | target parallel | taskloop | * | + // | for | | | + // | target parallel | taskloop simd | * | + // | for | | | + // | target parallel | distribute | | + // | for | | | + // | target parallel | distribute | | + // | for | parallel for | | + // | target parallel | distribute | | + // | for |parallel for simd| | + // | target parallel | distribute simd | | + // | for | | | + // | target parallel | target parallel | | + // | for | for simd | | // +------------------+-----------------+------------------------------------+ // | teams | parallel | * | // | teams | for | + | @@ -2188,6 +2691,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | teams | ordered | + | // | teams | atomic | + | // | teams | target | + | + // | teams | target parallel | + | + // | teams | target parallel | + | + // | | for | | + // | teams | target enter | + | + // | | data | | + // | teams | target exit | + | + // | | data | | // | teams | teams | + | // | teams | cancellation | | // | | point | | @@ -2195,6 +2705,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | teams | taskloop | + | // | teams | taskloop simd | + | // | teams | distribute | ! | + // | teams | distribute | ! | + // | | parallel for | | + // | teams | distribute | ! | + // | |parallel for simd| | + // | teams | distribute simd | ! | + // | teams | target parallel | + | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | taskloop | parallel | * | // | taskloop | for | + | @@ -2217,19 +2734,33 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | taskloop | ordered | + | // | taskloop | atomic | * | // | taskloop | target | * | + // | taskloop | target parallel | * | + // | taskloop | target parallel | * | + // | | for | | + // | taskloop | target enter | * | + // | | data | | + // | taskloop | target exit | * | + // | | data | | // | taskloop | teams | + | // | taskloop | cancellation | | // | | point | | // | taskloop | cancel | | // | taskloop | taskloop | * | - // | taskloop | distribute | | + // | taskloop | distribute | + | + // | taskloop | distribute | + | + // | | parallel for | | + // | taskloop | distribute | + | + // | |parallel for simd| | + // | taskloop | distribute simd | + | + // | taskloop | target parallel | * | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | taskloop simd | parallel | | // | taskloop simd | for | | // | taskloop simd | for simd | | // | taskloop simd | master | | // | taskloop simd | critical | | - // | taskloop simd | simd | | + // | taskloop simd | simd | * | // | taskloop simd | sections | | // | taskloop simd | section | | // | taskloop simd | single | | @@ -2245,6 +2776,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | taskloop simd | ordered | + (with simd clause) | // | taskloop simd | atomic | | // | taskloop simd | target | | + // | taskloop simd | target parallel | | + // | taskloop simd | target parallel | | + // | | for | | + // | taskloop simd | target enter | | + // | | data | | + // | taskloop simd | target exit | | + // | | data | | // | taskloop simd | teams | | // | taskloop simd | cancellation | | // | | point | | @@ -2252,6 +2790,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | taskloop simd | taskloop | | // | taskloop simd | taskloop simd | | // | taskloop simd | distribute | | + // | taskloop simd | distribute | | + // | | parallel for | | + // | taskloop simd | distribute | | + // | |parallel for simd| | + // | taskloop simd | distribute simd | | + // | taskloop simd | target parallel | | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | distribute | parallel | * | // | distribute | for | * | @@ -2274,6 +2819,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | distribute | ordered | + | // | distribute | atomic | * | // | distribute | target | | + // | distribute | target parallel | | + // | distribute | target parallel | | + // | | for | | + // | distribute | target enter | | + // | | data | | + // | distribute | target exit | | + // | | data | | // | distribute | teams | | // | distribute | cancellation | + | // | | point | | @@ -2281,9 +2833,274 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | distribute | taskloop | * | // | distribute | taskloop simd | * | // | distribute | distribute | | + // | distribute | distribute | | + // | | parallel for | | + // | distribute | distribute | | + // | |parallel for simd| | + // | distribute | distribute simd | | + // | distribute | target parallel | | + // | | for simd | | + // +------------------+-----------------+------------------------------------+ + // | distribute | parallel | * | + // | parallel for | | | + // | distribute | for | * | + // | parallel for | | | + // | distribute | for simd | * | + // | parallel for | | | + // | distribute | master | * | + // | parallel for | | | + // | distribute | critical | * | + // | parallel for | | | + // | distribute | simd | * | + // | parallel for | | | + // | distribute | sections | * | + // | parallel for | | | + // | distribute | section | * | + // | parallel for | | | + // | distribute | single | * | + // | parallel for | | | + // | distribute | parallel for | * | + // | parallel for | | | + // | distribute |parallel for simd| * | + // | parallel for | | | + // | distribute |parallel sections| * | + // | parallel for | | | + // | distribute | task | * | + // | parallel for | | | + // | parallel for | | | + // | distribute | taskyield | * | + // | parallel for | | | + // | distribute | barrier | * | + // | parallel for | | | + // | distribute | taskwait | * | + // | parallel for | | | + // | distribute | taskgroup | * | + // | parallel for | | | + // | distribute | flush | * | + // | parallel for | | | + // | distribute | ordered | + | + // | parallel for | | | + // | distribute | atomic | * | + // | parallel for | | | + // | distribute | target | | + // | parallel for | | | + // | distribute | target parallel | | + // | parallel for | | | + // | distribute | target parallel | | + // | parallel for | for | | + // | distribute | target enter | | + // | parallel for | data | | + // | distribute | target exit | | + // | parallel for | data | | + // | distribute | teams | | + // | parallel for | | | + // | distribute | cancellation | + | + // | parallel for | point | | + // | distribute | cancel | + | + // | parallel for | | | + // | distribute | taskloop | * | + // | parallel for | | | + // | distribute | taskloop simd | * | + // | parallel for | | | + // | distribute | distribute | | + // | parallel for | | | + // | distribute | distribute | | + // | parallel for | parallel for | | + // | distribute | distribute | | + // | parallel for |parallel for simd| | + // | distribute | distribute simd | | + // | parallel for | | | + // | distribute | target parallel | | + // | parallel for | for simd | | + // +------------------+-----------------+------------------------------------+ + // | distribute | parallel | * | + // | parallel for simd| | | + // | distribute | for | * | + // | parallel for simd| | | + // | distribute | for simd | * | + // | parallel for simd| | | + // | distribute | master | * | + // | parallel for simd| | | + // | distribute | critical | * | + // | parallel for simd| | | + // | distribute | simd | * | + // | parallel for simd| | | + // | distribute | sections | * | + // | parallel for simd| | | + // | distribute | section | * | + // | parallel for simd| | | + // | distribute | single | * | + // | parallel for simd| | | + // | distribute | parallel for | * | + // | parallel for simd| | | + // | distribute |parallel for simd| * | + // | parallel for simd| | | + // | distribute |parallel sections| * | + // | parallel for simd| | | + // | distribute | task | * | + // | parallel for simd| | | + // | distribute | taskyield | * | + // | parallel for simd| | | + // | distribute | barrier | * | + // | parallel for simd| | | + // | distribute | taskwait | * | + // | parallel for simd| | | + // | distribute | taskgroup | * | + // | parallel for simd| | | + // | distribute | flush | * | + // | parallel for simd| | | + // | distribute | ordered | + | + // | parallel for simd| | | + // | distribute | atomic | * | + // | parallel for simd| | | + // | distribute | target | | + // | parallel for simd| | | + // | distribute | target parallel | | + // | parallel for simd| | | + // | distribute | target parallel | | + // | parallel for simd| for | | + // | distribute | target enter | | + // | parallel for simd| data | | + // | distribute | target exit | | + // | parallel for simd| data | | + // | distribute | teams | | + // | parallel for simd| | | + // | distribute | cancellation | + | + // | parallel for simd| point | | + // | distribute | cancel | + | + // | parallel for simd| | | + // | distribute | taskloop | * | + // | parallel for simd| | | + // | distribute | taskloop simd | * | + // | parallel for simd| | | + // | distribute | distribute | | + // | parallel for simd| | | + // | distribute | distribute | * | + // | parallel for simd| parallel for | | + // | distribute | distribute | * | + // | parallel for simd|parallel for simd| | + // | distribute | distribute simd | * | + // | parallel for simd| | | + // | distribute | target parallel | | + // | parallel for simd| for simd | | + // +------------------+-----------------+------------------------------------+ + // | distribute simd | parallel | * | + // | distribute simd | for | * | + // | distribute simd | for simd | * | + // | distribute simd | master | * | + // | distribute simd | critical | * | + // | distribute simd | simd | * | + // | distribute simd | sections | * | + // | distribute simd | section | * | + // | distribute simd | single | * | + // | distribute simd | parallel for | * | + // | distribute simd |parallel for simd| * | + // | distribute simd |parallel sections| * | + // | distribute simd | task | * | + // | distribute simd | taskyield | * | + // | distribute simd | barrier | * | + // | distribute simd | taskwait | * | + // | distribute simd | taskgroup | * | + // | distribute simd | flush | * | + // | distribute simd | ordered | + | + // | distribute simd | atomic | * | + // | distribute simd | target | * | + // | distribute simd | target parallel | * | + // | distribute simd | target parallel | * | + // | | for | | + // | distribute simd | target enter | * | + // | | data | | + // | distribute simd | target exit | * | + // | | data | | + // | distribute simd | teams | * | + // | distribute simd | cancellation | + | + // | | point | | + // | distribute simd | cancel | + | + // | distribute simd | taskloop | * | + // | distribute simd | taskloop simd | * | + // | distribute simd | distribute | | + // | distribute simd | distribute | * | + // | | parallel for | | + // | distribute simd | distribute | * | + // | |parallel for simd| | + // | distribute simd | distribute simd | * | + // | distribute simd | target parallel | * | + // | | for simd | | + // +------------------+-----------------+------------------------------------+ + // | target parallel | parallel | * | + // | for simd | | | + // | target parallel | for | * | + // | for simd | | | + // | target parallel | for simd | * | + // | for simd | | | + // | target parallel | master | * | + // | for simd | | | + // | target parallel | critical | * | + // | for simd | | | + // | target parallel | simd | ! | + // | for simd | | | + // | target parallel | sections | * | + // | for simd | | | + // | target parallel | section | * | + // | for simd | | | + // | target parallel | single | * | + // | for simd | | | + // | target parallel | parallel for | * | + // | for simd | | | + // | target parallel |parallel for simd| * | + // | for simd | | | + // | target parallel |parallel sections| * | + // | for simd | | | + // | target parallel | task | * | + // | for simd | | | + // | target parallel | taskyield | * | + // | for simd | | | + // | target parallel | barrier | * | + // | for simd | | | + // | target parallel | taskwait | * | + // | for simd | | | + // | target parallel | taskgroup | * | + // | for simd | | | + // | target parallel | flush | * | + // | for simd | | | + // | target parallel | ordered | + (with simd clause) | + // | for simd | | | + // | target parallel | atomic | * | + // | for simd | | | + // | target parallel | target | * | + // | for simd | | | + // | target parallel | target parallel | * | + // | for simd | | | + // | target parallel | target parallel | * | + // | for simd | for | | + // | target parallel | target enter | * | + // | for simd | data | | + // | target parallel | target exit | * | + // | for simd | data | | + // | target parallel | teams | * | + // | for simd | | | + // | target parallel | cancellation | * | + // | for simd | point | | + // | target parallel | cancel | * | + // | for simd | | | + // | target parallel | taskloop | * | + // | for simd | | | + // | target parallel | taskloop simd | * | + // | for simd | | | + // | target parallel | distribute | * | + // | for simd | | | + // | target parallel | distribute | * | + // | for simd | parallel for | | + // | target parallel | distribute | * | + // | for simd |parallel for simd| | + // | target parallel | distribute simd | * | + // | for simd | | | + // | target parallel | target parallel | * | + // | for simd | for simd | | // +------------------+-----------------+------------------------------------+ if (Stack->getCurScope()) { auto ParentRegion = Stack->getParentDirective(); + auto OffendingRegion = ParentRegion; bool NestingProhibited = false; bool CloseNesting = true; enum { @@ -2297,10 +3114,15 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // 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; + // An ordered construct with the simd clause is the only OpenMP + // construct that can appear in the simd region. + // Allowing a SIMD consruct nested in another SIMD construct is an + // extension. The OpenMP 4.5 spec does not allow it. Issue a warning + // message. + SemaRef.Diag(StartLoc, (CurrentRegion != OMPD_simd) + ? diag::err_omp_prohibited_region_simd + : diag::warn_omp_nesting_simd); + return CurrentRegion != OMPD_simd; } if (ParentRegion == OMPD_atomic) { // OpenMP [2.16, Nesting of Regions] @@ -2340,9 +3162,12 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // OpenMP construct that matches the type specified in // construct-type-clause. NestingProhibited = - !((CancelRegion == OMPD_parallel && ParentRegion == OMPD_parallel) || + !((CancelRegion == OMPD_parallel && + (ParentRegion == OMPD_parallel || + ParentRegion == OMPD_target_parallel)) || (CancelRegion == OMPD_for && - (ParentRegion == OMPD_for || ParentRegion == OMPD_parallel_for)) || + (ParentRegion == OMPD_for || ParentRegion == OMPD_parallel_for || + ParentRegion == OMPD_target_parallel_for)) || (CancelRegion == OMPD_taskgroup && ParentRegion == OMPD_task) || (CancelRegion == OMPD_sections && (ParentRegion == OMPD_section || ParentRegion == OMPD_sections || @@ -2352,8 +3177,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // A master region may not be closely nested inside a worksharing, // atomic, or explicit task region. NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || - ParentRegion == OMPD_task || - isOpenMPTaskLoopDirective(ParentRegion); + isOpenMPTaskingDirective(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 @@ -2387,21 +3211,21 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // OpenMP [2.16, Nesting of Regions] // A barrier region may not be closely nested inside a worksharing, // explicit task, critical, ordered, atomic, or master region. - NestingProhibited = - isOpenMPWorksharingDirective(ParentRegion) || - ParentRegion == OMPD_task || ParentRegion == OMPD_master || - ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered || - isOpenMPTaskLoopDirective(ParentRegion); + NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || + isOpenMPTaskingDirective(ParentRegion) || + ParentRegion == OMPD_master || + ParentRegion == OMPD_critical || + ParentRegion == OMPD_ordered; } else if (isOpenMPWorksharingDirective(CurrentRegion) && !isOpenMPParallelDirective(CurrentRegion)) { // OpenMP [2.16, Nesting of Regions] // A worksharing region may not be closely nested inside a worksharing, // explicit task, critical, ordered, atomic, or master region. - NestingProhibited = - isOpenMPWorksharingDirective(ParentRegion) || - ParentRegion == OMPD_task || ParentRegion == OMPD_master || - ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered || - isOpenMPTaskLoopDirective(ParentRegion); + NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || + isOpenMPTaskingDirective(ParentRegion) || + ParentRegion == OMPD_master || + ParentRegion == OMPD_critical || + ParentRegion == OMPD_ordered; Recommend = ShouldBeInParallelRegion; } else if (CurrentRegion == OMPD_ordered) { // OpenMP [2.16, Nesting of Regions] @@ -2413,8 +3237,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // 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 || - isOpenMPTaskLoopDirective(ParentRegion) || + isOpenMPTaskingDirective(ParentRegion) || !(isOpenMPSimdDirective(ParentRegion) || Stack->isParentOrderedRegion()); Recommend = ShouldBeInOrderedRegion; @@ -2442,10 +3265,29 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, NestingProhibited = !isOpenMPTeamsDirective(ParentRegion); Recommend = ShouldBeInTeamsRegion; } + if (!NestingProhibited && + (isOpenMPTargetExecutionDirective(CurrentRegion) || + isOpenMPTargetDataManagementDirective(CurrentRegion))) { + // OpenMP 4.5 [2.17 Nesting of Regions] + // If a target, target update, target data, target enter data, or + // target exit data construct is encountered during execution of a + // target region, the behavior is unspecified. + NestingProhibited = Stack->hasDirective( + [&OffendingRegion](OpenMPDirectiveKind K, const DeclarationNameInfo &, + SourceLocation) -> bool { + if (isOpenMPTargetExecutionDirective(K)) { + OffendingRegion = K; + return true; + } else + return false; + }, + false /* don't skip top directive */); + CloseNesting = false; + } if (NestingProhibited) { SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region) - << CloseNesting << getOpenMPDirectiveName(ParentRegion) << Recommend - << getOpenMPDirectiveName(CurrentRegion); + << CloseNesting << getOpenMPDirectiveName(OffendingRegion) + << Recommend << getOpenMPDirectiveName(CurrentRegion); return true; } } @@ -2544,7 +3386,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( return StmtError(); llvm::SmallVector<OMPClause *, 8> ClausesWithImplicit; - llvm::DenseMap<VarDecl *, Expr *> VarsWithInheritedDSA; + llvm::DenseMap<ValueDecl *, Expr *> VarsWithInheritedDSA; bool ErrorFound = false; ClausesWithImplicit.append(Clauses.begin(), Clauses.end()); if (AStmt) { @@ -2679,6 +3521,18 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( EndLoc); AllowedNameModifiers.push_back(OMPD_target); break; + case OMPD_target_parallel: + Res = ActOnOpenMPTargetParallelDirective(ClausesWithImplicit, AStmt, + StartLoc, EndLoc); + AllowedNameModifiers.push_back(OMPD_target); + AllowedNameModifiers.push_back(OMPD_parallel); + break; + case OMPD_target_parallel_for: + Res = ActOnOpenMPTargetParallelForDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_target); + AllowedNameModifiers.push_back(OMPD_parallel); + break; case OMPD_cancellation_point: assert(ClausesWithImplicit.empty() && "No clauses are allowed for 'omp cancellation point' directive"); @@ -2698,6 +3552,16 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( EndLoc); AllowedNameModifiers.push_back(OMPD_target_data); break; + case OMPD_target_enter_data: + Res = ActOnOpenMPTargetEnterDataDirective(ClausesWithImplicit, StartLoc, + EndLoc); + AllowedNameModifiers.push_back(OMPD_target_enter_data); + break; + case OMPD_target_exit_data: + Res = ActOnOpenMPTargetExitDataDirective(ClausesWithImplicit, StartLoc, + EndLoc); + AllowedNameModifiers.push_back(OMPD_target_exit_data); + break; case OMPD_taskloop: Res = ActOnOpenMPTaskLoopDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); @@ -2712,7 +3576,37 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( Res = ActOnOpenMPDistributeDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); break; + case OMPD_target_update: + assert(!AStmt && "Statement is not allowed for target update"); + Res = + ActOnOpenMPTargetUpdateDirective(ClausesWithImplicit, StartLoc, EndLoc); + AllowedNameModifiers.push_back(OMPD_target_update); + break; + case OMPD_distribute_parallel_for: + Res = ActOnOpenMPDistributeParallelForDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_parallel); + break; + case OMPD_distribute_parallel_for_simd: + Res = ActOnOpenMPDistributeParallelForSimdDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_parallel); + break; + case OMPD_distribute_simd: + Res = ActOnOpenMPDistributeSimdDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + break; + case OMPD_target_parallel_for_simd: + Res = ActOnOpenMPTargetParallelForSimdDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_target); + AllowedNameModifiers.push_back(OMPD_parallel); + break; + case OMPD_declare_target: + case OMPD_end_declare_target: case OMPD_threadprivate: + case OMPD_declare_reduction: + case OMPD_declare_simd: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); @@ -2733,6 +3627,252 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( return Res; } +Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( + DeclGroupPtrTy DG, OMPDeclareSimdDeclAttr::BranchStateTy BS, Expr *Simdlen, + ArrayRef<Expr *> Uniforms, ArrayRef<Expr *> Aligneds, + ArrayRef<Expr *> Alignments, ArrayRef<Expr *> Linears, + ArrayRef<unsigned> LinModifiers, ArrayRef<Expr *> Steps, SourceRange SR) { + assert(Aligneds.size() == Alignments.size()); + assert(Linears.size() == LinModifiers.size()); + assert(Linears.size() == Steps.size()); + if (!DG || DG.get().isNull()) + return DeclGroupPtrTy(); + + if (!DG.get().isSingleDecl()) { + Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd); + return DG; + } + auto *ADecl = DG.get().getSingleDecl(); + if (auto *FTD = dyn_cast<FunctionTemplateDecl>(ADecl)) + ADecl = FTD->getTemplatedDecl(); + + auto *FD = dyn_cast<FunctionDecl>(ADecl); + if (!FD) { + Diag(ADecl->getLocation(), diag::err_omp_function_expected); + return DeclGroupPtrTy(); + } + + // OpenMP [2.8.2, declare simd construct, Description] + // The parameter of the simdlen clause must be a constant positive integer + // expression. + ExprResult SL; + if (Simdlen) + SL = VerifyPositiveIntegerConstantInClause(Simdlen, OMPC_simdlen); + // OpenMP [2.8.2, declare simd construct, Description] + // The special this pointer can be used as if was one of the arguments to the + // function in any of the linear, aligned, or uniform clauses. + // The uniform clause declares one or more arguments to have an invariant + // value for all concurrent invocations of the function in the execution of a + // single SIMD loop. + llvm::DenseMap<Decl *, Expr *> UniformedArgs; + Expr *UniformedLinearThis = nullptr; + for (auto *E : Uniforms) { + E = E->IgnoreParenImpCasts(); + if (auto *DRE = dyn_cast<DeclRefExpr>(E)) + if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) + if (FD->getNumParams() > PVD->getFunctionScopeIndex() && + FD->getParamDecl(PVD->getFunctionScopeIndex()) + ->getCanonicalDecl() == PVD->getCanonicalDecl()) { + UniformedArgs.insert(std::make_pair(PVD->getCanonicalDecl(), E)); + continue; + } + if (isa<CXXThisExpr>(E)) { + UniformedLinearThis = E; + continue; + } + Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause) + << FD->getDeclName() << (isa<CXXMethodDecl>(ADecl) ? 1 : 0); + } + // OpenMP [2.8.2, declare simd construct, Description] + // The aligned clause declares that the object to which each list item points + // is aligned to the number of bytes expressed in the optional parameter of + // the aligned clause. + // The special this pointer can be used as if was one of the arguments to the + // function in any of the linear, aligned, or uniform clauses. + // The type of list items appearing in the aligned clause must be array, + // pointer, reference to array, or reference to pointer. + llvm::DenseMap<Decl *, Expr *> AlignedArgs; + Expr *AlignedThis = nullptr; + for (auto *E : Aligneds) { + E = E->IgnoreParenImpCasts(); + if (auto *DRE = dyn_cast<DeclRefExpr>(E)) + if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) { + auto *CanonPVD = PVD->getCanonicalDecl(); + if (FD->getNumParams() > PVD->getFunctionScopeIndex() && + FD->getParamDecl(PVD->getFunctionScopeIndex()) + ->getCanonicalDecl() == CanonPVD) { + // OpenMP [2.8.1, simd construct, Restrictions] + // A list-item cannot appear in more than one aligned clause. + if (AlignedArgs.count(CanonPVD) > 0) { + Diag(E->getExprLoc(), diag::err_omp_aligned_twice) + << 1 << E->getSourceRange(); + Diag(AlignedArgs[CanonPVD]->getExprLoc(), + diag::note_omp_explicit_dsa) + << getOpenMPClauseName(OMPC_aligned); + continue; + } + AlignedArgs[CanonPVD] = E; + QualType QTy = PVD->getType() + .getNonReferenceType() + .getUnqualifiedType() + .getCanonicalType(); + const Type *Ty = QTy.getTypePtrOrNull(); + if (!Ty || (!Ty->isArrayType() && !Ty->isPointerType())) { + Diag(E->getExprLoc(), diag::err_omp_aligned_expected_array_or_ptr) + << QTy << getLangOpts().CPlusPlus << E->getSourceRange(); + Diag(PVD->getLocation(), diag::note_previous_decl) << PVD; + } + continue; + } + } + if (isa<CXXThisExpr>(E)) { + if (AlignedThis) { + Diag(E->getExprLoc(), diag::err_omp_aligned_twice) + << 2 << E->getSourceRange(); + Diag(AlignedThis->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(OMPC_aligned); + } + AlignedThis = E; + continue; + } + Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause) + << FD->getDeclName() << (isa<CXXMethodDecl>(ADecl) ? 1 : 0); + } + // The optional parameter of the aligned clause, alignment, must be a constant + // positive integer expression. If no optional parameter is specified, + // implementation-defined default alignments for SIMD instructions on the + // target platforms are assumed. + SmallVector<Expr *, 4> NewAligns; + for (auto *E : Alignments) { + ExprResult Align; + if (E) + Align = VerifyPositiveIntegerConstantInClause(E, OMPC_aligned); + NewAligns.push_back(Align.get()); + } + // OpenMP [2.8.2, declare simd construct, Description] + // The linear clause declares one or more list items to be private to a SIMD + // lane and to have a linear relationship with respect to the iteration space + // of a loop. + // The special this pointer can be used as if was one of the arguments to the + // function in any of the linear, aligned, or uniform clauses. + // When a linear-step expression is specified in a linear clause it must be + // either a constant integer expression or an integer-typed parameter that is + // specified in a uniform clause on the directive. + llvm::DenseMap<Decl *, Expr *> LinearArgs; + const bool IsUniformedThis = UniformedLinearThis != nullptr; + auto MI = LinModifiers.begin(); + for (auto *E : Linears) { + auto LinKind = static_cast<OpenMPLinearClauseKind>(*MI); + ++MI; + E = E->IgnoreParenImpCasts(); + if (auto *DRE = dyn_cast<DeclRefExpr>(E)) + if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) { + auto *CanonPVD = PVD->getCanonicalDecl(); + if (FD->getNumParams() > PVD->getFunctionScopeIndex() && + FD->getParamDecl(PVD->getFunctionScopeIndex()) + ->getCanonicalDecl() == CanonPVD) { + // OpenMP [2.15.3.7, linear Clause, Restrictions] + // A list-item cannot appear in more than one linear clause. + if (LinearArgs.count(CanonPVD) > 0) { + Diag(E->getExprLoc(), diag::err_omp_wrong_dsa) + << getOpenMPClauseName(OMPC_linear) + << getOpenMPClauseName(OMPC_linear) << E->getSourceRange(); + Diag(LinearArgs[CanonPVD]->getExprLoc(), + diag::note_omp_explicit_dsa) + << getOpenMPClauseName(OMPC_linear); + continue; + } + // Each argument can appear in at most one uniform or linear clause. + if (UniformedArgs.count(CanonPVD) > 0) { + Diag(E->getExprLoc(), diag::err_omp_wrong_dsa) + << getOpenMPClauseName(OMPC_linear) + << getOpenMPClauseName(OMPC_uniform) << E->getSourceRange(); + Diag(UniformedArgs[CanonPVD]->getExprLoc(), + diag::note_omp_explicit_dsa) + << getOpenMPClauseName(OMPC_uniform); + continue; + } + LinearArgs[CanonPVD] = E; + if (E->isValueDependent() || E->isTypeDependent() || + E->isInstantiationDependent() || + E->containsUnexpandedParameterPack()) + continue; + (void)CheckOpenMPLinearDecl(CanonPVD, E->getExprLoc(), LinKind, + PVD->getOriginalType()); + continue; + } + } + if (isa<CXXThisExpr>(E)) { + if (UniformedLinearThis) { + Diag(E->getExprLoc(), diag::err_omp_wrong_dsa) + << getOpenMPClauseName(OMPC_linear) + << getOpenMPClauseName(IsUniformedThis ? OMPC_uniform : OMPC_linear) + << E->getSourceRange(); + Diag(UniformedLinearThis->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(IsUniformedThis ? OMPC_uniform + : OMPC_linear); + continue; + } + UniformedLinearThis = E; + if (E->isValueDependent() || E->isTypeDependent() || + E->isInstantiationDependent() || E->containsUnexpandedParameterPack()) + continue; + (void)CheckOpenMPLinearDecl(/*D=*/nullptr, E->getExprLoc(), LinKind, + E->getType()); + continue; + } + Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause) + << FD->getDeclName() << (isa<CXXMethodDecl>(ADecl) ? 1 : 0); + } + Expr *Step = nullptr; + Expr *NewStep = nullptr; + SmallVector<Expr *, 4> NewSteps; + for (auto *E : Steps) { + // Skip the same step expression, it was checked already. + if (Step == E || !E) { + NewSteps.push_back(E ? NewStep : nullptr); + continue; + } + Step = E; + if (auto *DRE = dyn_cast<DeclRefExpr>(Step)) + if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) { + auto *CanonPVD = PVD->getCanonicalDecl(); + if (UniformedArgs.count(CanonPVD) == 0) { + Diag(Step->getExprLoc(), diag::err_omp_expected_uniform_param) + << Step->getSourceRange(); + } else if (E->isValueDependent() || E->isTypeDependent() || + E->isInstantiationDependent() || + E->containsUnexpandedParameterPack() || + CanonPVD->getType()->hasIntegerRepresentation()) + NewSteps.push_back(Step); + else { + Diag(Step->getExprLoc(), diag::err_omp_expected_int_param) + << Step->getSourceRange(); + } + continue; + } + NewStep = Step; + if (Step && !Step->isValueDependent() && !Step->isTypeDependent() && + !Step->isInstantiationDependent() && + !Step->containsUnexpandedParameterPack()) { + NewStep = PerformOpenMPImplicitIntegerConversion(Step->getExprLoc(), Step) + .get(); + if (NewStep) + NewStep = VerifyIntegerConstantExpression(NewStep).get(); + } + NewSteps.push_back(NewStep); + } + auto *NewAttr = OMPDeclareSimdDeclAttr::CreateImplicit( + Context, BS, SL.get(), const_cast<Expr **>(Uniforms.data()), + Uniforms.size(), const_cast<Expr **>(Aligneds.data()), Aligneds.size(), + const_cast<Expr **>(NewAligns.data()), NewAligns.size(), + const_cast<Expr **>(Linears.data()), Linears.size(), + const_cast<unsigned *>(LinModifiers.data()), LinModifiers.size(), + NewSteps.data(), NewSteps.size(), SR); + ADecl->addAttr(NewAttr); + return ConvertDeclToDeclGroup(ADecl); +} + StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, @@ -2772,33 +3912,29 @@ class OpenMPIterationSpaceChecker { /// \brief A source location for referring to increment later. SourceRange IncrementSrcRange; /// \brief Loop variable. - VarDecl *Var; + ValueDecl *LCDecl = nullptr; /// \brief Reference to loop variable. - DeclRefExpr *VarRef; + Expr *LCRef = nullptr; /// \brief Lower bound (initializer for the var). - Expr *LB; + Expr *LB = nullptr; /// \brief Upper bound. - Expr *UB; + Expr *UB = nullptr; /// \brief Loop step (increment). - Expr *Step; + Expr *Step = nullptr; /// \brief This flag is true when condition is one of: /// Var < UB /// Var <= UB /// UB > Var /// UB >= Var - bool TestIsLessOp; + bool TestIsLessOp = false; /// \brief This flag is true when condition is strict ( < or > ). - bool TestIsStrictOp; + bool TestIsStrictOp = false; /// \brief This flag is true when step is subtracted on each iteration. - bool SubtractStep; + bool SubtractStep = false; public: OpenMPIterationSpaceChecker(Sema &SemaRef, SourceLocation DefaultLoc) - : SemaRef(SemaRef), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc), - InitSrcRange(SourceRange()), ConditionSrcRange(SourceRange()), - IncrementSrcRange(SourceRange()), Var(nullptr), VarRef(nullptr), - LB(nullptr), UB(nullptr), Step(nullptr), TestIsLessOp(false), - TestIsStrictOp(false), SubtractStep(false) {} + : SemaRef(SemaRef), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc) {} /// \brief Check init-expr for canonical loop form and save loop counter /// variable - #Var and its initialization value - #LB. bool CheckInit(Stmt *S, bool EmitDiags = true); @@ -2809,9 +3945,9 @@ public: /// does not conform, otherwise save loop step (#Step). bool CheckInc(Expr *S); /// \brief Return the loop counter variable. - VarDecl *GetLoopVar() const { return Var; } + ValueDecl *GetLoopDecl() const { return LCDecl; } /// \brief Return the reference expression to loop counter variable. - DeclRefExpr *GetLoopVarRefExpr() const { return VarRef; } + Expr *GetLoopDeclRefExpr() const { return LCRef; } /// \brief Source range of the loop init. SourceRange GetInitSrcRange() const { return InitSrcRange; } /// \brief Source range of the loop condition. @@ -2821,11 +3957,15 @@ public: /// \brief True if the step should be subtracted. bool ShouldSubtractStep() const { return SubtractStep; } /// \brief Build the expression to calculate the number of iterations. - Expr *BuildNumIterations(Scope *S, const bool LimitedType) const; + Expr * + BuildNumIterations(Scope *S, const bool LimitedType, + llvm::MapVector<Expr *, DeclRefExpr *> &Captures) const; /// \brief Build the precondition expression for the loops. - Expr *BuildPreCond(Scope *S, Expr *Cond) const; + Expr *BuildPreCond(Scope *S, Expr *Cond, + llvm::MapVector<Expr *, DeclRefExpr *> &Captures) const; /// \brief Build reference expression to the counter be used for codegen. - Expr *BuildCounterVar() const; + DeclRefExpr *BuildCounterVar(llvm::MapVector<Expr *, DeclRefExpr *> &Captures, + DSAStackTy &DSA) const; /// \brief Build reference expression to the private counter be used for /// codegen. Expr *BuildPrivateCounterVar() const; @@ -2841,7 +3981,7 @@ private: /// expression. bool CheckIncRHS(Expr *RHS); /// \brief Helper to set loop counter variable and its initializer. - bool SetVarAndLB(VarDecl *NewVar, DeclRefExpr *NewVarRefExpr, Expr *NewLB); + bool SetLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB); /// \brief Helper to set upper bound. bool SetUB(Expr *NewUB, bool LessOp, bool StrictOp, SourceRange SR, SourceLocation SL); @@ -2850,16 +3990,16 @@ private: }; bool OpenMPIterationSpaceChecker::Dependent() const { - if (!Var) { + if (!LCDecl) { assert(!LB && !UB && !Step); return false; } - return Var->getType()->isDependentType() || (LB && LB->isValueDependent()) || - (UB && UB->isValueDependent()) || (Step && Step->isValueDependent()); + return LCDecl->getType()->isDependentType() || + (LB && LB->isValueDependent()) || (UB && UB->isValueDependent()) || + (Step && Step->isValueDependent()); } -template <typename T> -static T *getExprAsWritten(T *E) { +static Expr *getExprAsWritten(Expr *E) { if (auto *ExprTemp = dyn_cast<ExprWithCleanups>(E)) E = ExprTemp->getSubExpr(); @@ -2874,16 +4014,16 @@ static T *getExprAsWritten(T *E) { return E->IgnoreParens(); } -bool OpenMPIterationSpaceChecker::SetVarAndLB(VarDecl *NewVar, - DeclRefExpr *NewVarRefExpr, - Expr *NewLB) { +bool OpenMPIterationSpaceChecker::SetLCDeclAndLB(ValueDecl *NewLCDecl, + Expr *NewLCRefExpr, + Expr *NewLB) { // State consistency checking to ensure correct usage. - assert(Var == nullptr && LB == nullptr && VarRef == nullptr && + assert(LCDecl == nullptr && LB == nullptr && LCRef == nullptr && UB == nullptr && Step == nullptr && !TestIsLessOp && !TestIsStrictOp); - if (!NewVar || !NewLB) + if (!NewLCDecl || !NewLB) return true; - Var = NewVar; - VarRef = NewVarRefExpr; + LCDecl = getCanonicalDecl(NewLCDecl); + LCRef = NewLCRefExpr; if (auto *CE = dyn_cast_or_null<CXXConstructExpr>(NewLB)) if (const CXXConstructorDecl *Ctor = CE->getConstructor()) if ((Ctor->isCopyOrMoveConstructor() || @@ -2897,8 +4037,8 @@ bool OpenMPIterationSpaceChecker::SetVarAndLB(VarDecl *NewVar, bool OpenMPIterationSpaceChecker::SetUB(Expr *NewUB, bool LessOp, bool StrictOp, SourceRange SR, SourceLocation SL) { // State consistency checking to ensure correct usage. - assert(Var != nullptr && LB != nullptr && UB == nullptr && Step == nullptr && - !TestIsLessOp && !TestIsStrictOp); + assert(LCDecl != nullptr && LB != nullptr && UB == nullptr && + Step == nullptr && !TestIsLessOp && !TestIsStrictOp); if (!NewUB) return true; UB = NewUB; @@ -2911,7 +4051,7 @@ bool OpenMPIterationSpaceChecker::SetUB(Expr *NewUB, bool LessOp, bool StrictOp, bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) { // State consistency checking to ensure correct usage. - assert(Var != nullptr && LB != nullptr && Step == nullptr); + assert(LCDecl != nullptr && LB != nullptr && Step == nullptr); if (!NewStep) return true; if (!NewStep->isValueDependent()) { @@ -2947,7 +4087,7 @@ bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) { : (IsConstPos || (IsUnsigned && !Subtract))))) { SemaRef.Diag(NewStep->getExprLoc(), diag::err_omp_loop_incr_not_compatible) - << Var << TestIsLessOp << NewStep->getSourceRange(); + << LCDecl << TestIsLessOp << NewStep->getSourceRange(); SemaRef.Diag(ConditionLoc, diag::note_omp_loop_cond_requres_compatible_incr) << TestIsLessOp << ConditionSrcRange; @@ -2980,14 +4120,28 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) { } return true; } + if (auto *ExprTemp = dyn_cast<ExprWithCleanups>(S)) + if (!ExprTemp->cleanupsHaveSideEffects()) + S = ExprTemp->getSubExpr(); + InitSrcRange = S->getSourceRange(); if (Expr *E = dyn_cast<Expr>(S)) S = E->IgnoreParens(); if (auto BO = dyn_cast<BinaryOperator>(S)) { - if (BO->getOpcode() == BO_Assign) - if (auto DRE = dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParens())) - return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), DRE, - BO->getRHS()); + if (BO->getOpcode() == BO_Assign) { + auto *LHS = BO->getLHS()->IgnoreParens(); + if (auto *DRE = dyn_cast<DeclRefExpr>(LHS)) { + if (auto *CED = dyn_cast<OMPCapturedExprDecl>(DRE->getDecl())) + if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit()))) + return SetLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); + return SetLCDeclAndLB(DRE->getDecl(), DRE, BO->getRHS()); + } + if (auto *ME = dyn_cast<MemberExpr>(LHS)) { + if (ME->isArrow() && + isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts())) + return SetLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); + } + } } else if (auto DS = dyn_cast<DeclStmt>(S)) { if (DS->isSingleDecl()) { if (auto Var = dyn_cast_or_null<VarDecl>(DS->getSingleDecl())) { @@ -2997,16 +4151,29 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) { SemaRef.Diag(S->getLocStart(), diag::ext_omp_loop_not_canonical_init) << S->getSourceRange(); - return SetVarAndLB(Var, nullptr, Var->getInit()); + return SetLCDeclAndLB(Var, nullptr, Var->getInit()); } } } - } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(S)) - if (CE->getOperator() == OO_Equal) - if (auto DRE = dyn_cast<DeclRefExpr>(CE->getArg(0))) - return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), DRE, - CE->getArg(1)); + } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(S)) { + if (CE->getOperator() == OO_Equal) { + auto *LHS = CE->getArg(0); + if (auto DRE = dyn_cast<DeclRefExpr>(LHS)) { + if (auto *CED = dyn_cast<OMPCapturedExprDecl>(DRE->getDecl())) + if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit()))) + return SetLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); + return SetLCDeclAndLB(DRE->getDecl(), DRE, CE->getArg(1)); + } + if (auto *ME = dyn_cast<MemberExpr>(LHS)) { + if (ME->isArrow() && + isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts())) + return SetLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); + } + } + } + if (Dependent() || SemaRef.CurContext->isDependentContext()) + return false; if (EmitDiags) { SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_init) << S->getSourceRange(); @@ -3016,7 +4183,7 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) { /// \brief Ignore parenthesizes, implicit casts, copy constructor and return the /// variable (which may be the loop variable) if possible. -static const VarDecl *GetInitVarDecl(const Expr *E) { +static const ValueDecl *GetInitLCDecl(Expr *E) { if (!E) return nullptr; E = getExprAsWritten(E); @@ -3026,10 +4193,18 @@ static const VarDecl *GetInitVarDecl(const Expr *E) { Ctor->isConvertingConstructor(/*AllowExplicit=*/false)) && CE->getNumArgs() > 0 && CE->getArg(0) != nullptr) E = CE->getArg(0)->IgnoreParenImpCasts(); - auto DRE = dyn_cast_or_null<DeclRefExpr>(E); - if (!DRE) - return nullptr; - return dyn_cast<VarDecl>(DRE->getDecl()); + if (auto *DRE = dyn_cast_or_null<DeclRefExpr>(E)) { + if (auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) { + if (auto *CED = dyn_cast<OMPCapturedExprDecl>(VD)) + if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit()))) + return getCanonicalDecl(ME->getMemberDecl()); + return getCanonicalDecl(VD); + } + } + if (auto *ME = dyn_cast_or_null<MemberExpr>(E)) + if (ME->isArrow() && isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts())) + return getCanonicalDecl(ME->getMemberDecl()); + return nullptr; } bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) { @@ -3040,19 +4215,19 @@ bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) { // b relational-op var // if (!S) { - SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) << Var; + SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) << LCDecl; return true; } S = getExprAsWritten(S); SourceLocation CondLoc = S->getLocStart(); if (auto BO = dyn_cast<BinaryOperator>(S)) { if (BO->isRelationalOp()) { - if (GetInitVarDecl(BO->getLHS()) == Var) + if (GetInitLCDecl(BO->getLHS()) == LCDecl) return SetUB(BO->getRHS(), (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_LE), (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT), BO->getSourceRange(), BO->getOperatorLoc()); - if (GetInitVarDecl(BO->getRHS()) == Var) + if (GetInitLCDecl(BO->getRHS()) == LCDecl) return SetUB(BO->getLHS(), (BO->getOpcode() == BO_GT || BO->getOpcode() == BO_GE), (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT), @@ -3066,11 +4241,11 @@ bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) { case OO_GreaterEqual: case OO_Less: case OO_LessEqual: - if (GetInitVarDecl(CE->getArg(0)) == Var) + if (GetInitLCDecl(CE->getArg(0)) == LCDecl) return SetUB(CE->getArg(1), Op == OO_Less || Op == OO_LessEqual, Op == OO_Less || Op == OO_Greater, CE->getSourceRange(), CE->getOperatorLoc()); - if (GetInitVarDecl(CE->getArg(1)) == Var) + if (GetInitLCDecl(CE->getArg(1)) == LCDecl) return SetUB(CE->getArg(0), Op == OO_Greater || Op == OO_GreaterEqual, Op == OO_Less || Op == OO_Greater, CE->getSourceRange(), CE->getOperatorLoc()); @@ -3080,8 +4255,10 @@ bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) { } } } + if (Dependent() || SemaRef.CurContext->isDependentContext()) + return false; SemaRef.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond) - << S->getSourceRange() << Var; + << S->getSourceRange() << LCDecl; return true; } @@ -3095,22 +4272,24 @@ bool OpenMPIterationSpaceChecker::CheckIncRHS(Expr *RHS) { if (auto BO = dyn_cast<BinaryOperator>(RHS)) { if (BO->isAdditiveOp()) { bool IsAdd = BO->getOpcode() == BO_Add; - if (GetInitVarDecl(BO->getLHS()) == Var) + if (GetInitLCDecl(BO->getLHS()) == LCDecl) return SetStep(BO->getRHS(), !IsAdd); - if (IsAdd && GetInitVarDecl(BO->getRHS()) == Var) + if (IsAdd && GetInitLCDecl(BO->getRHS()) == LCDecl) return SetStep(BO->getLHS(), false); } } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(RHS)) { bool IsAdd = CE->getOperator() == OO_Plus; if ((IsAdd || CE->getOperator() == OO_Minus) && CE->getNumArgs() == 2) { - if (GetInitVarDecl(CE->getArg(0)) == Var) + if (GetInitLCDecl(CE->getArg(0)) == LCDecl) return SetStep(CE->getArg(1), !IsAdd); - if (IsAdd && GetInitVarDecl(CE->getArg(1)) == Var) + if (IsAdd && GetInitLCDecl(CE->getArg(1)) == LCDecl) return SetStep(CE->getArg(0), false); } } + if (Dependent() || SemaRef.CurContext->isDependentContext()) + return false; SemaRef.Diag(RHS->getLocStart(), diag::err_omp_loop_not_canonical_incr) - << RHS->getSourceRange() << Var; + << RHS->getSourceRange() << LCDecl; return true; } @@ -3129,13 +4308,18 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { // var = var - incr // if (!S) { - SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_incr) << Var; + SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_incr) << LCDecl; return true; } + if (auto *ExprTemp = dyn_cast<ExprWithCleanups>(S)) + if (!ExprTemp->cleanupsHaveSideEffects()) + S = ExprTemp->getSubExpr(); + IncrementSrcRange = S->getSourceRange(); S = S->IgnoreParens(); if (auto UO = dyn_cast<UnaryOperator>(S)) { - if (UO->isIncrementDecrementOp() && GetInitVarDecl(UO->getSubExpr()) == Var) + if (UO->isIncrementDecrementOp() && + GetInitLCDecl(UO->getSubExpr()) == LCDecl) return SetStep( SemaRef.ActOnIntegerConstant(UO->getLocStart(), (UO->isDecrementOp() ? -1 : 1)).get(), @@ -3144,11 +4328,11 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { switch (BO->getOpcode()) { case BO_AddAssign: case BO_SubAssign: - if (GetInitVarDecl(BO->getLHS()) == Var) + if (GetInitLCDecl(BO->getLHS()) == LCDecl) return SetStep(BO->getRHS(), BO->getOpcode() == BO_SubAssign); break; case BO_Assign: - if (GetInitVarDecl(BO->getLHS()) == Var) + if (GetInitLCDecl(BO->getLHS()) == LCDecl) return CheckIncRHS(BO->getRHS()); break; default: @@ -3158,7 +4342,7 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { switch (CE->getOperator()) { case OO_PlusPlus: case OO_MinusMinus: - if (GetInitVarDecl(CE->getArg(0)) == Var) + if (GetInitLCDecl(CE->getArg(0)) == LCDecl) return SetStep( SemaRef.ActOnIntegerConstant( CE->getLocStart(), @@ -3167,103 +4351,55 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { break; case OO_PlusEqual: case OO_MinusEqual: - if (GetInitVarDecl(CE->getArg(0)) == Var) + if (GetInitLCDecl(CE->getArg(0)) == LCDecl) return SetStep(CE->getArg(1), CE->getOperator() == OO_MinusEqual); break; case OO_Equal: - if (GetInitVarDecl(CE->getArg(0)) == Var) + if (GetInitLCDecl(CE->getArg(0)) == LCDecl) return CheckIncRHS(CE->getArg(1)); break; default: break; } } + if (Dependent() || SemaRef.CurContext->isDependentContext()) + return false; SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_incr) - << S->getSourceRange() << Var; + << S->getSourceRange() << LCDecl; return true; } -namespace { -// Transform variables declared in GNU statement expressions to new ones to -// avoid crash on codegen. -class TransformToNewDefs : public TreeTransform<TransformToNewDefs> { - typedef TreeTransform<TransformToNewDefs> BaseTransform; - -public: - TransformToNewDefs(Sema &SemaRef) : BaseTransform(SemaRef) {} - - Decl *TransformDefinition(SourceLocation Loc, Decl *D) { - if (auto *VD = cast<VarDecl>(D)) - if (!isa<ParmVarDecl>(D) && !isa<VarTemplateSpecializationDecl>(D) && - !isa<ImplicitParamDecl>(D)) { - auto *NewVD = VarDecl::Create( - SemaRef.Context, VD->getDeclContext(), VD->getLocStart(), - VD->getLocation(), VD->getIdentifier(), VD->getType(), - VD->getTypeSourceInfo(), VD->getStorageClass()); - NewVD->setTSCSpec(VD->getTSCSpec()); - NewVD->setInit(VD->getInit()); - NewVD->setInitStyle(VD->getInitStyle()); - NewVD->setExceptionVariable(VD->isExceptionVariable()); - NewVD->setNRVOVariable(VD->isNRVOVariable()); - NewVD->setCXXForRangeDecl(VD->isCXXForRangeDecl()); - NewVD->setConstexpr(VD->isConstexpr()); - NewVD->setInitCapture(VD->isInitCapture()); - NewVD->setPreviousDeclInSameBlockScope( - VD->isPreviousDeclInSameBlockScope()); - VD->getDeclContext()->addHiddenDecl(NewVD); - if (VD->hasAttrs()) - NewVD->setAttrs(VD->getAttrs()); - transformedLocalDecl(VD, NewVD); - return NewVD; - } - return BaseTransform::TransformDefinition(Loc, D); - } - - ExprResult TransformDeclRefExpr(DeclRefExpr *E) { - if (auto *NewD = TransformDecl(E->getExprLoc(), E->getDecl())) - if (E->getDecl() != NewD) { - NewD->setReferenced(); - NewD->markUsed(SemaRef.Context); - return DeclRefExpr::Create( - SemaRef.Context, E->getQualifierLoc(), E->getTemplateKeywordLoc(), - cast<ValueDecl>(NewD), E->refersToEnclosingVariableOrCapture(), - E->getNameInfo(), E->getType(), E->getValueKind()); - } - return BaseTransform::TransformDeclRefExpr(E); - } -}; +static ExprResult +tryBuildCapture(Sema &SemaRef, Expr *Capture, + llvm::MapVector<Expr *, DeclRefExpr *> &Captures) { + if (SemaRef.CurContext->isDependentContext()) + return ExprResult(Capture); + if (Capture->isEvaluatable(SemaRef.Context, Expr::SE_AllowSideEffects)) + return SemaRef.PerformImplicitConversion( + Capture->IgnoreImpCasts(), Capture->getType(), Sema::AA_Converting, + /*AllowExplicit=*/true); + auto I = Captures.find(Capture); + if (I != Captures.end()) + return buildCapture(SemaRef, Capture, I->second); + DeclRefExpr *Ref = nullptr; + ExprResult Res = buildCapture(SemaRef, Capture, Ref); + Captures[Capture] = Ref; + return Res; } /// \brief Build the expression to calculate the number of iterations. -Expr * -OpenMPIterationSpaceChecker::BuildNumIterations(Scope *S, - const bool LimitedType) const { - TransformToNewDefs Transform(SemaRef); +Expr *OpenMPIterationSpaceChecker::BuildNumIterations( + Scope *S, const bool LimitedType, + llvm::MapVector<Expr *, DeclRefExpr *> &Captures) const { ExprResult Diff; - auto VarType = Var->getType().getNonReferenceType(); + auto VarType = LCDecl->getType().getNonReferenceType(); if (VarType->isIntegerType() || VarType->isPointerType() || SemaRef.getLangOpts().CPlusPlus) { // Upper - Lower auto *UBExpr = TestIsLessOp ? UB : LB; auto *LBExpr = TestIsLessOp ? LB : UB; - Expr *Upper = Transform.TransformExpr(UBExpr).get(); - Expr *Lower = Transform.TransformExpr(LBExpr).get(); - if (!Upper || !Lower) - return nullptr; - if (!SemaRef.Context.hasSameType(Upper->getType(), UBExpr->getType())) { - Upper = SemaRef - .PerformImplicitConversion(Upper, UBExpr->getType(), - Sema::AA_Converting, - /*AllowExplicit=*/true) - .get(); - } - if (!SemaRef.Context.hasSameType(Lower->getType(), LBExpr->getType())) { - Lower = SemaRef - .PerformImplicitConversion(Lower, LBExpr->getType(), - Sema::AA_Converting, - /*AllowExplicit=*/true) - .get(); - } + Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get(); + Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get(); if (!Upper || !Lower) return nullptr; @@ -3290,18 +4426,9 @@ OpenMPIterationSpaceChecker::BuildNumIterations(Scope *S, return nullptr; // Upper - Lower [- 1] + Step - auto *StepNoImp = Step->IgnoreImplicit(); - auto NewStep = Transform.TransformExpr(StepNoImp); - if (NewStep.isInvalid()) + auto NewStep = tryBuildCapture(SemaRef, Step, Captures); + if (!NewStep.isUsable()) return nullptr; - if (!SemaRef.Context.hasSameType(NewStep.get()->getType(), - StepNoImp->getType())) { - NewStep = SemaRef.PerformImplicitConversion( - NewStep.get(), StepNoImp->getType(), Sema::AA_Converting, - /*AllowExplicit=*/true); - if (NewStep.isInvalid()) - return nullptr; - } Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Diff.get(), NewStep.get()); if (!Diff.isUsable()) return nullptr; @@ -3312,17 +4439,6 @@ OpenMPIterationSpaceChecker::BuildNumIterations(Scope *S, return nullptr; // (Upper - Lower [- 1] + Step) / Step - NewStep = Transform.TransformExpr(StepNoImp); - if (NewStep.isInvalid()) - return nullptr; - if (!SemaRef.Context.hasSameType(NewStep.get()->getType(), - StepNoImp->getType())) { - NewStep = SemaRef.PerformImplicitConversion( - NewStep.get(), StepNoImp->getType(), Sema::AA_Converting, - /*AllowExplicit=*/true); - if (NewStep.isInvalid()) - return nullptr; - } Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get()); if (!Diff.isUsable()) return nullptr; @@ -3368,35 +4484,25 @@ OpenMPIterationSpaceChecker::BuildNumIterations(Scope *S, return Diff.get(); } -Expr *OpenMPIterationSpaceChecker::BuildPreCond(Scope *S, Expr *Cond) const { +Expr *OpenMPIterationSpaceChecker::BuildPreCond( + Scope *S, Expr *Cond, + llvm::MapVector<Expr *, DeclRefExpr *> &Captures) const { // Try to build LB <op> UB, where <op> is <, >, <=, or >=. bool Suppress = SemaRef.getDiagnostics().getSuppressAllDiagnostics(); SemaRef.getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true); - TransformToNewDefs Transform(SemaRef); - - auto NewLB = Transform.TransformExpr(LB); - auto NewUB = Transform.TransformExpr(UB); - if (NewLB.isInvalid() || NewUB.isInvalid()) - return Cond; - if (!SemaRef.Context.hasSameType(NewLB.get()->getType(), LB->getType())) { - NewLB = SemaRef.PerformImplicitConversion(NewLB.get(), LB->getType(), - Sema::AA_Converting, - /*AllowExplicit=*/true); - } - if (!SemaRef.Context.hasSameType(NewUB.get()->getType(), UB->getType())) { - NewUB = SemaRef.PerformImplicitConversion(NewUB.get(), UB->getType(), - Sema::AA_Converting, - /*AllowExplicit=*/true); - } - if (NewLB.isInvalid() || NewUB.isInvalid()) - return Cond; + + auto NewLB = tryBuildCapture(SemaRef, LB, Captures); + auto NewUB = tryBuildCapture(SemaRef, UB, Captures); + if (!NewLB.isUsable() || !NewUB.isUsable()) + return nullptr; + auto CondExpr = SemaRef.BuildBinOp( S, DefaultLoc, TestIsLessOp ? (TestIsStrictOp ? BO_LT : BO_LE) : (TestIsStrictOp ? BO_GT : BO_GE), NewLB.get(), NewUB.get()); if (CondExpr.isUsable()) { - if (!SemaRef.Context.hasSameType(CondExpr.get()->getType(), - SemaRef.Context.BoolTy)) + if (!SemaRef.Context.hasSameUnqualifiedType(CondExpr.get()->getType(), + SemaRef.Context.BoolTy)) CondExpr = SemaRef.PerformImplicitConversion( CondExpr.get(), SemaRef.Context.BoolTy, /*Action=*/Sema::AA_Casting, /*AllowExplicit=*/true); @@ -3407,17 +4513,30 @@ 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().getNonReferenceType(), +DeclRefExpr *OpenMPIterationSpaceChecker::BuildCounterVar( + llvm::MapVector<Expr *, DeclRefExpr *> &Captures, DSAStackTy &DSA) const { + auto *VD = dyn_cast<VarDecl>(LCDecl); + if (!VD) { + VD = SemaRef.IsOpenMPCapturedDecl(LCDecl); + auto *Ref = buildDeclRefExpr( + SemaRef, VD, VD->getType().getNonReferenceType(), DefaultLoc); + DSAStackTy::DSAVarData Data = DSA.getTopDSA(LCDecl, /*FromParent=*/false); + // If the loop control decl is explicitly marked as private, do not mark it + // as captured again. + if (!isOpenMPPrivate(Data.CKind) || !Data.RefExpr) + Captures.insert(std::make_pair(LCRef, Ref)); + return Ref; + } + return buildDeclRefExpr(SemaRef, VD, VD->getType().getNonReferenceType(), DefaultLoc); } Expr *OpenMPIterationSpaceChecker::BuildPrivateCounterVar() const { - if (Var && !Var->isInvalidDecl()) { - auto Type = Var->getType().getNonReferenceType(); + if (LCDecl && !LCDecl->isInvalidDecl()) { + auto Type = LCDecl->getType().getNonReferenceType(); auto *PrivateVar = - buildVarDecl(SemaRef, DefaultLoc, Type, Var->getName(), - Var->hasAttrs() ? &Var->getAttrs() : nullptr); + buildVarDecl(SemaRef, DefaultLoc, Type, LCDecl->getName(), + LCDecl->hasAttrs() ? &LCDecl->getAttrs() : nullptr); if (PrivateVar->isInvalidDecl()) return nullptr; return buildDeclRefExpr(SemaRef, PrivateVar, Type, DefaultLoc); @@ -3432,23 +4551,23 @@ Expr *OpenMPIterationSpaceChecker::BuildCounterInit() const { return LB; } Expr *OpenMPIterationSpaceChecker::BuildCounterStep() const { return Step; } /// \brief Iteration space of a single for loop. -struct LoopIterationSpace { +struct LoopIterationSpace final { /// \brief Condition of the loop. - Expr *PreCond; + Expr *PreCond = nullptr; /// \brief This expression calculates the number of iterations in the loop. /// It is always possible to calculate it before starting the loop. - Expr *NumIterations; + Expr *NumIterations = nullptr; /// \brief The loop counter variable. - Expr *CounterVar; + Expr *CounterVar = nullptr; /// \brief Private loop counter variable. - Expr *PrivateCounterVar; + Expr *PrivateCounterVar = nullptr; /// \brief This is initializer for the initial value of #CounterVar. - Expr *CounterInit; + Expr *CounterInit = nullptr; /// \brief This is step for the #CounterVar used to generate its update: /// #CounterVar = #CounterInit + #CounterStep * CurrentIteration. - Expr *CounterStep; + Expr *CounterStep = nullptr; /// \brief Should step be subtracted? - bool Subtract; + bool Subtract = false; /// \brief Source range of the loop init. SourceRange InitSrcRange; /// \brief Source range of the loop condition. @@ -3466,8 +4585,21 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { if (AssociatedLoops > 0 && isOpenMPLoopDirective(DSAStack->getCurrentDirective())) { OpenMPIterationSpaceChecker ISC(*this, ForLoc); - if (!ISC.CheckInit(Init, /*EmitDiags=*/false)) - DSAStack->addLoopControlVariable(ISC.GetLoopVar()); + if (!ISC.CheckInit(Init, /*EmitDiags=*/false)) { + if (auto *D = ISC.GetLoopDecl()) { + auto *VD = dyn_cast<VarDecl>(D); + if (!VD) { + if (auto *Private = IsOpenMPCapturedDecl(D)) + VD = Private; + else { + auto *Ref = buildCapture(*this, D, ISC.GetLoopDeclRefExpr(), + /*WithInit=*/false); + VD = cast<VarDecl>(Ref->getDecl()); + } + } + DSAStack->addLoopControlVariable(D, VD); + } + } DSAStack->setAssociatedLoops(AssociatedLoops - 1); } } @@ -3478,8 +4610,9 @@ static bool CheckOpenMPIterationSpace( OpenMPDirectiveKind DKind, Stmt *S, Sema &SemaRef, DSAStackTy &DSA, unsigned CurrentNestedLoopCount, unsigned NestedLoopCount, Expr *CollapseLoopCountExpr, Expr *OrderedLoopCountExpr, - llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA, - LoopIterationSpace &ResultIterSpace) { + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA, + LoopIterationSpace &ResultIterSpace, + llvm::MapVector<Expr *, DeclRefExpr *> &Captures) { // OpenMP [2.6, Canonical Loop Form] // for (init-expr; test-expr; incr-expr) structured-block auto For = dyn_cast_or_null<ForStmt>(S); @@ -3511,98 +4644,102 @@ static bool CheckOpenMPIterationSpace( // Check init. auto Init = For->getInit(); - if (ISC.CheckInit(Init)) { + if (ISC.CheckInit(Init)) return true; - } bool HasErrors = false; // Check loop variable's type. - auto Var = ISC.GetLoopVar(); + if (auto *LCDecl = ISC.GetLoopDecl()) { + auto *LoopDeclRefExpr = ISC.GetLoopDeclRefExpr(); + + // OpenMP [2.6, Canonical Loop Form] + // Var is one of the following: + // 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 = LCDecl->getType().getNonReferenceType(); + if (!VarType->isDependentType() && !VarType->isIntegerType() && + !VarType->isPointerType() && + !(SemaRef.getLangOpts().CPlusPlus && VarType->isOverloadableType())) { + SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_variable_type) + << SemaRef.getLangOpts().CPlusPlus; + HasErrors = true; + } - // OpenMP [2.6, Canonical Loop Form] - // Var is one of the following: - // 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().getNonReferenceType(); - if (!VarType->isDependentType() && !VarType->isIntegerType() && - !VarType->isPointerType() && - !(SemaRef.getLangOpts().CPlusPlus && VarType->isOverloadableType())) { - SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_variable_type) - << SemaRef.getLangOpts().CPlusPlus; - HasErrors = true; - } - - // OpenMP, 2.14.1.1 Data-sharing Attribute Rules for Variables Referenced in a - // Construct - // The loop iteration variable(s) in the associated for-loop(s) of a for or - // parallel for construct is (are) private. - // The loop iteration variable in the associated for-loop of a simd construct - // with just one associated for-loop is linear with a constant-linear-step - // that is the increment of the associated for-loop. - // Exclude loop var from the list of variables with implicitly defined data - // sharing attributes. - VarsWithImplicitDSA.erase(Var); - - // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced in - // a Construct, C/C++]. - // The loop iteration variable in the associated for-loop of a simd construct - // with just one associated for-loop may be listed in a linear clause with a - // constant-linear-step that is the increment of the associated for-loop. - // The loop iteration variable(s) in the associated for-loop(s) of a for or - // parallel for construct may be listed in a private or lastprivate clause. - DSAStackTy::DSAVarData DVar = DSA.getTopDSA(Var, false); - auto LoopVarRefExpr = ISC.GetLoopVarRefExpr(); - // If LoopVarRefExpr is nullptr it means the corresponding loop variable is - // declared in the loop and it is predetermined as a private. - auto PredeterminedCKind = - isOpenMPSimdDirective(DKind) - ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate) - : OMPC_private; - if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && - 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); - if (DVar.RefExpr == nullptr) - DVar.CKind = PredeterminedCKind; - ReportOriginalDSA(SemaRef, &DSA, Var, DVar, /*IsLoopIterVar=*/true); - HasErrors = true; - } 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 or ordered - // loops). - if (DVar.CKind == OMPC_unknown) - DVar = DSA.hasDSA(Var, isOpenMPPrivate, MatchesAlways(), - /*FromParent=*/false); - DSA.addDSA(Var, LoopVarRefExpr, PredeterminedCKind); - } - - assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars"); - - // Check test-expr. - HasErrors |= ISC.CheckCond(For->getCond()); - - // Check incr-expr. - HasErrors |= ISC.CheckInc(For->getInc()); + // OpenMP, 2.14.1.1 Data-sharing Attribute Rules for Variables Referenced in + // a Construct + // The loop iteration variable(s) in the associated for-loop(s) of a for or + // parallel for construct is (are) private. + // The loop iteration variable in the associated for-loop of a simd + // construct with just one associated for-loop is linear with a + // constant-linear-step that is the increment of the associated for-loop. + // Exclude loop var from the list of variables with implicitly defined data + // sharing attributes. + VarsWithImplicitDSA.erase(LCDecl); + + // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced + // in a Construct, C/C++]. + // The loop iteration variable in the associated for-loop of a simd + // construct with just one associated for-loop may be listed in a linear + // clause with a constant-linear-step that is the increment of the + // associated for-loop. + // The loop iteration variable(s) in the associated for-loop(s) of a for or + // parallel for construct may be listed in a private or lastprivate clause. + DSAStackTy::DSAVarData DVar = DSA.getTopDSA(LCDecl, false); + // If LoopVarRefExpr is nullptr it means the corresponding loop variable is + // declared in the loop and it is predetermined as a private. + auto PredeterminedCKind = + isOpenMPSimdDirective(DKind) + ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate) + : OMPC_private; + if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && + 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); + if (DVar.RefExpr == nullptr) + DVar.CKind = PredeterminedCKind; + ReportOriginalDSA(SemaRef, &DSA, LCDecl, DVar, /*IsLoopIterVar=*/true); + HasErrors = true; + } else if (LoopDeclRefExpr != nullptr) { + // Make the loop iteration variable private (for worksharing constructs), + // linear (for simd directives with the only one associated loop) or + // lastprivate (for simd directives with several collapsed or ordered + // loops). + if (DVar.CKind == OMPC_unknown) + DVar = DSA.hasDSA(LCDecl, isOpenMPPrivate, + [](OpenMPDirectiveKind) -> bool { return true; }, + /*FromParent=*/false); + DSA.addDSA(LCDecl, LoopDeclRefExpr, PredeterminedCKind); + } + + assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars"); + + // Check test-expr. + HasErrors |= ISC.CheckCond(For->getCond()); + + // Check incr-expr. + HasErrors |= ISC.CheckInc(For->getInc()); + } if (ISC.Dependent() || SemaRef.CurContext->isDependentContext() || HasErrors) return HasErrors; // Build the loop's iteration space representation. - ResultIterSpace.PreCond = ISC.BuildPreCond(DSA.getCurScope(), For->getCond()); + ResultIterSpace.PreCond = + ISC.BuildPreCond(DSA.getCurScope(), For->getCond(), Captures); ResultIterSpace.NumIterations = ISC.BuildNumIterations( - DSA.getCurScope(), (isOpenMPWorksharingDirective(DKind) || - isOpenMPTaskLoopDirective(DKind) || - isOpenMPDistributeDirective(DKind))); - ResultIterSpace.CounterVar = ISC.BuildCounterVar(); + DSA.getCurScope(), + (isOpenMPWorksharingDirective(DKind) || + isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)), + Captures); + ResultIterSpace.CounterVar = ISC.BuildCounterVar(Captures, DSA); ResultIterSpace.PrivateCounterVar = ISC.BuildPrivateCounterVar(); ResultIterSpace.CounterInit = ISC.BuildCounterInit(); ResultIterSpace.CounterStep = ISC.BuildCounterStep(); @@ -3622,23 +4759,15 @@ static bool CheckOpenMPIterationSpace( } /// \brief Build 'VarRef = Start. -static ExprResult BuildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, - ExprResult VarRef, ExprResult Start) { - TransformToNewDefs Transform(SemaRef); +static ExprResult +BuildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef, + ExprResult Start, + llvm::MapVector<Expr *, DeclRefExpr *> &Captures) { // Build 'VarRef = Start. - auto *StartNoImp = Start.get()->IgnoreImplicit(); - auto NewStart = Transform.TransformExpr(StartNoImp); - if (NewStart.isInvalid()) + auto NewStart = tryBuildCapture(SemaRef, Start.get(), Captures); + if (!NewStart.isUsable()) return ExprError(); if (!SemaRef.Context.hasSameType(NewStart.get()->getType(), - StartNoImp->getType())) { - NewStart = SemaRef.PerformImplicitConversion( - NewStart.get(), StartNoImp->getType(), Sema::AA_Converting, - /*AllowExplicit=*/true); - if (NewStart.isInvalid()) - return ExprError(); - } - if (!SemaRef.Context.hasSameType(NewStart.get()->getType(), VarRef.get()->getType())) { NewStart = SemaRef.PerformImplicitConversion( NewStart.get(), VarRef.get()->getType(), Sema::AA_Converting, @@ -3653,58 +4782,74 @@ static ExprResult BuildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, } /// \brief Build 'VarRef = Start + Iter * Step'. -static ExprResult BuildCounterUpdate(Sema &SemaRef, Scope *S, - SourceLocation Loc, ExprResult VarRef, - ExprResult Start, ExprResult Iter, - ExprResult Step, bool Subtract) { +static ExprResult +BuildCounterUpdate(Sema &SemaRef, Scope *S, SourceLocation Loc, + ExprResult VarRef, ExprResult Start, ExprResult Iter, + ExprResult Step, bool Subtract, + llvm::MapVector<Expr *, DeclRefExpr *> *Captures = nullptr) { // Add parentheses (for debugging purposes only). Iter = SemaRef.ActOnParenExpr(Loc, Loc, Iter.get()); if (!VarRef.isUsable() || !Start.isUsable() || !Iter.isUsable() || !Step.isUsable()) return ExprError(); - auto *StepNoImp = Step.get()->IgnoreImplicit(); - TransformToNewDefs Transform(SemaRef); - auto NewStep = Transform.TransformExpr(StepNoImp); + ExprResult NewStep = Step; + if (Captures) + NewStep = tryBuildCapture(SemaRef, Step.get(), *Captures); if (NewStep.isInvalid()) return ExprError(); - if (!SemaRef.Context.hasSameType(NewStep.get()->getType(), - StepNoImp->getType())) { - NewStep = SemaRef.PerformImplicitConversion( - NewStep.get(), StepNoImp->getType(), Sema::AA_Converting, - /*AllowExplicit=*/true); - if (NewStep.isInvalid()) - return ExprError(); - } ExprResult Update = SemaRef.BuildBinOp(S, Loc, BO_Mul, Iter.get(), NewStep.get()); if (!Update.isUsable()) return ExprError(); - // Build 'VarRef = Start + Iter * Step'. - auto *StartNoImp = Start.get()->IgnoreImplicit(); - auto NewStart = Transform.TransformExpr(StartNoImp); + // Try to build 'VarRef = Start, VarRef (+|-)= Iter * Step' or + // 'VarRef = Start (+|-) Iter * Step'. + ExprResult NewStart = Start; + if (Captures) + NewStart = tryBuildCapture(SemaRef, Start.get(), *Captures); if (NewStart.isInvalid()) return ExprError(); - if (!SemaRef.Context.hasSameType(NewStart.get()->getType(), - StartNoImp->getType())) { - NewStart = SemaRef.PerformImplicitConversion( - NewStart.get(), StartNoImp->getType(), Sema::AA_Converting, - /*AllowExplicit=*/true); - if (NewStart.isInvalid()) - return ExprError(); + + // First attempt: try to build 'VarRef = Start, VarRef += Iter * Step'. + ExprResult SavedUpdate = Update; + ExprResult UpdateVal; + if (VarRef.get()->getType()->isOverloadableType() || + NewStart.get()->getType()->isOverloadableType() || + Update.get()->getType()->isOverloadableType()) { + bool Suppress = SemaRef.getDiagnostics().getSuppressAllDiagnostics(); + SemaRef.getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true); + Update = + SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), NewStart.get()); + if (Update.isUsable()) { + UpdateVal = + SemaRef.BuildBinOp(S, Loc, Subtract ? BO_SubAssign : BO_AddAssign, + VarRef.get(), SavedUpdate.get()); + if (UpdateVal.isUsable()) { + Update = SemaRef.CreateBuiltinBinOp(Loc, BO_Comma, Update.get(), + UpdateVal.get()); + } + } + SemaRef.getDiagnostics().setSuppressAllDiagnostics(Suppress); } - Update = SemaRef.BuildBinOp(S, Loc, (Subtract ? BO_Sub : BO_Add), - NewStart.get(), Update.get()); - if (!Update.isUsable()) - return ExprError(); - Update = SemaRef.PerformImplicitConversion( - Update.get(), VarRef.get()->getType(), Sema::AA_Converting, true); - if (!Update.isUsable()) - return ExprError(); + // Second attempt: try to build 'VarRef = Start (+|-) Iter * Step'. + if (!Update.isUsable() || !UpdateVal.isUsable()) { + Update = SemaRef.BuildBinOp(S, Loc, Subtract ? BO_Sub : BO_Add, + NewStart.get(), SavedUpdate.get()); + if (!Update.isUsable()) + return ExprError(); - Update = SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), Update.get()); + if (!SemaRef.Context.hasSameType(Update.get()->getType(), + VarRef.get()->getType())) { + Update = SemaRef.PerformImplicitConversion( + Update.get(), VarRef.get()->getType(), Sema::AA_Converting, true); + if (!Update.isUsable()) + return ExprError(); + } + + Update = SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), Update.get()); + } return Update; } @@ -3736,6 +4881,49 @@ static bool FitsInto(unsigned Bits, bool Signed, Expr *E, Sema &SemaRef) { return false; } +/// Build preinits statement for the given declarations. +static Stmt *buildPreInits(ASTContext &Context, + SmallVectorImpl<Decl *> &PreInits) { + if (!PreInits.empty()) { + return new (Context) DeclStmt( + DeclGroupRef::Create(Context, PreInits.begin(), PreInits.size()), + SourceLocation(), SourceLocation()); + } + return nullptr; +} + +/// Build preinits statement for the given declarations. +static Stmt *buildPreInits(ASTContext &Context, + llvm::MapVector<Expr *, DeclRefExpr *> &Captures) { + if (!Captures.empty()) { + SmallVector<Decl *, 16> PreInits; + for (auto &Pair : Captures) + PreInits.push_back(Pair.second->getDecl()); + return buildPreInits(Context, PreInits); + } + return nullptr; +} + +/// Build postupdate expression for the given list of postupdates expressions. +static Expr *buildPostUpdate(Sema &S, ArrayRef<Expr *> PostUpdates) { + Expr *PostUpdate = nullptr; + if (!PostUpdates.empty()) { + for (auto *E : PostUpdates) { + Expr *ConvE = S.BuildCStyleCastExpr( + E->getExprLoc(), + S.Context.getTrivialTypeSourceInfo(S.Context.VoidTy), + E->getExprLoc(), E) + .get(); + PostUpdate = PostUpdate + ? S.CreateBuiltinBinOp(ConvE->getExprLoc(), BO_Comma, + PostUpdate, ConvE) + .get() + : ConvE; + } + } + return PostUpdate; +} + /// \brief Called on a for stmt to check itself and nested loops (if any). /// \return Returns 0 if one of the collapsed stmts is not canonical for loop, /// number of collapsed loops otherwise. @@ -3743,7 +4931,7 @@ static unsigned CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Expr *OrderedLoopCountExpr, Stmt *AStmt, Sema &SemaRef, DSAStackTy &DSA, - llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA, + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA, OMPLoopDirective::HelperExprs &Built) { unsigned NestedLoopCount = 1; if (CollapseLoopCountExpr) { @@ -3769,6 +4957,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, } // This is helper routine for loop directives (e.g., 'for', 'simd', // 'for simd', etc.). + llvm::MapVector<Expr *, DeclRefExpr *> Captures; SmallVector<LoopIterationSpace, 4> IterSpaces; IterSpaces.resize(NestedLoopCount); Stmt *CurStmt = AStmt->IgnoreContainers(/* IgnoreCaptured */ true); @@ -3776,7 +4965,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, if (CheckOpenMPIterationSpace(DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount, CollapseLoopCountExpr, OrderedLoopCountExpr, VarsWithImplicitDSA, - IterSpaces[Cnt])) + IterSpaces[Cnt], Captures)) return 0; // Move on to the next nested for loop, or to the loop body. // OpenMP [2.8.1, simd construct, Restrictions] @@ -3877,6 +5066,15 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, LastIteration32.get()->getType()->hasSignedIntegerRepresentation(), LastIteration64.get(), SemaRef))) LastIteration = LastIteration32; + QualType VType = LastIteration.get()->getType(); + QualType RealVType = VType; + QualType StrideVType = VType; + if (isOpenMPTaskLoopDirective(DKind)) { + VType = + SemaRef.Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0); + StrideVType = + SemaRef.Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1); + } if (!LastIteration.isUsable()) return 0; @@ -3898,19 +5096,13 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, LastIteration.get()->isIntegerConstantExpr(Result, SemaRef.Context); ExprResult CalcLastIteration; if (!IsConstant) { - SourceLocation SaveLoc; - VarDecl *SaveVar = - buildVarDecl(SemaRef, SaveLoc, LastIteration.get()->getType(), - ".omp.last.iteration"); - ExprResult SaveRef = buildDeclRefExpr( - SemaRef, SaveVar, LastIteration.get()->getType(), SaveLoc); - CalcLastIteration = SemaRef.BuildBinOp(CurScope, SaveLoc, BO_Assign, - SaveRef.get(), LastIteration.get()); + ExprResult SaveRef = + tryBuildCapture(SemaRef, LastIteration.get(), Captures); LastIteration = SaveRef; // Prepare SaveRef + 1. NumIterations = SemaRef.BuildBinOp( - CurScope, SaveLoc, BO_Add, SaveRef.get(), + CurScope, SourceLocation(), BO_Add, SaveRef.get(), SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); if (!NumIterations.isUsable()) return 0; @@ -3918,9 +5110,8 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, SourceLocation InitLoc = IterSpaces[0].InitSrcRange.getBegin(); - QualType VType = LastIteration.get()->getType(); // Build variables passed into runtime, nesessary for worksharing directives. - ExprResult LB, UB, IL, ST, EUB; + ExprResult LB, UB, IL, ST, EUB, PrevLB, PrevUB; if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)) { // Lower bound variable, initialized with zero. @@ -3947,8 +5138,9 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, /*DirectInit*/ false, /*TypeMayContainAuto*/ false); // Stride variable returned by runtime (we initialize it to 1 by default). - VarDecl *STDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.stride"); - ST = buildDeclRefExpr(SemaRef, STDecl, VType, InitLoc); + VarDecl *STDecl = + buildVarDecl(SemaRef, InitLoc, StrideVType, ".omp.stride"); + ST = buildDeclRefExpr(SemaRef, STDecl, StrideVType, InitLoc); SemaRef.AddInitializerToDecl( STDecl, SemaRef.ActOnIntegerConstant(InitLoc, 1).get(), /*DirectInit*/ false, /*TypeMayContainAuto*/ false); @@ -3962,14 +5154,39 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, EUB = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, UB.get(), CondOp.get()); EUB = SemaRef.ActOnFinishFullExpr(EUB.get()); + + // If we have a combined directive that combines 'distribute', 'for' or + // 'simd' we need to be able to access the bounds of the schedule of the + // enclosing region. E.g. in 'distribute parallel for' the bounds obtained + // by scheduling 'distribute' have to be passed to the schedule of 'for'. + if (isOpenMPLoopBoundSharingDirective(DKind)) { + auto *CD = cast<CapturedStmt>(AStmt)->getCapturedDecl(); + + // We expect to have at least 2 more parameters than the 'parallel' + // directive does - the lower and upper bounds of the previous schedule. + assert(CD->getNumParams() >= 4 && + "Unexpected number of parameters in loop combined directive"); + + // Set the proper type for the bounds given what we learned from the + // enclosed loops. + auto *PrevLBDecl = CD->getParam(/*PrevLB=*/2); + auto *PrevUBDecl = CD->getParam(/*PrevUB=*/3); + + // Previous lower and upper bounds are obtained from the region + // parameters. + PrevLB = + buildDeclRefExpr(SemaRef, PrevLBDecl, PrevLBDecl->getType(), InitLoc); + PrevUB = + buildDeclRefExpr(SemaRef, PrevUBDecl, PrevUBDecl->getType(), InitLoc); + } } // Build the iteration variable and its initialization before loop. ExprResult IV; ExprResult Init; { - VarDecl *IVDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.iv"); - IV = buildDeclRefExpr(SemaRef, IVDecl, VType, InitLoc); + VarDecl *IVDecl = buildVarDecl(SemaRef, InitLoc, RealVType, ".omp.iv"); + IV = buildDeclRefExpr(SemaRef, IVDecl, RealVType, InitLoc); Expr *RHS = (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)) @@ -4033,6 +5250,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Built.Inits.resize(NestedLoopCount); Built.Updates.resize(NestedLoopCount); Built.Finals.resize(NestedLoopCount); + SmallVector<Expr *, 4> LoopMultipliers; { ExprResult Div; // Go from inner nested loop to outer. @@ -4060,19 +5278,19 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, } // Build update: IS.CounterVar(Private) = IS.Start + Iter * IS.Step - auto *CounterVar = buildDeclRefExpr( - SemaRef, cast<VarDecl>(cast<DeclRefExpr>(IS.CounterVar)->getDecl()), - IS.CounterVar->getType(), IS.CounterVar->getExprLoc(), - /*RefersToCapture=*/true); + auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IS.CounterVar)->getDecl()); + auto *CounterVar = buildDeclRefExpr(SemaRef, VD, IS.CounterVar->getType(), + IS.CounterVar->getExprLoc(), + /*RefersToCapture=*/true); ExprResult Init = BuildCounterInit(SemaRef, CurScope, UpdLoc, CounterVar, - IS.CounterInit); + IS.CounterInit, Captures); if (!Init.isUsable()) { HasErrors = true; break; } - ExprResult Update = - BuildCounterUpdate(SemaRef, CurScope, UpdLoc, CounterVar, - IS.CounterInit, Iter, IS.CounterStep, IS.Subtract); + ExprResult Update = BuildCounterUpdate( + SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, Iter, + IS.CounterStep, IS.Subtract, &Captures); if (!Update.isUsable()) { HasErrors = true; break; @@ -4081,7 +5299,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, // Build final: IS.CounterVar = IS.Start + IS.NumIters * IS.Step ExprResult Final = BuildCounterUpdate( SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, - IS.NumIterations, IS.CounterStep, IS.Subtract); + IS.NumIterations, IS.CounterStep, IS.Subtract, &Captures); if (!Final.isUsable()) { HasErrors = true; break; @@ -4097,11 +5315,12 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, // Add parentheses (for debugging purposes only). if (Div.isUsable()) - Div = SemaRef.ActOnParenExpr(UpdLoc, UpdLoc, Div.get()); + Div = tryBuildCapture(SemaRef, Div.get(), Captures); if (!Div.isUsable()) { HasErrors = true; break; } + LoopMultipliers.push_back(Div.get()); } if (!Update.isUsable() || !Final.isUsable()) { HasErrors = true; @@ -4126,6 +5345,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Built.CalcLastIteration = SemaRef.ActOnFinishFullExpr(CalcLastIteration.get()).get(); Built.PreCond = PreCond.get(); + Built.PreInits = buildPreInits(C, Captures); Built.Cond = Cond.get(); Built.Init = Init.get(); Built.Inc = Inc.get(); @@ -4136,6 +5356,56 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Built.EUB = EUB.get(); Built.NLB = NextLB.get(); Built.NUB = NextUB.get(); + Built.PrevLB = PrevLB.get(); + Built.PrevUB = PrevUB.get(); + + Expr *CounterVal = SemaRef.DefaultLvalueConversion(IV.get()).get(); + // Fill data for doacross depend clauses. + for (auto Pair : DSA.getDoacrossDependClauses()) { + if (Pair.first->getDependencyKind() == OMPC_DEPEND_source) + Pair.first->setCounterValue(CounterVal); + else { + if (NestedLoopCount != Pair.second.size() || + NestedLoopCount != LoopMultipliers.size() + 1) { + // Erroneous case - clause has some problems. + Pair.first->setCounterValue(CounterVal); + continue; + } + assert(Pair.first->getDependencyKind() == OMPC_DEPEND_sink); + auto I = Pair.second.rbegin(); + auto IS = IterSpaces.rbegin(); + auto ILM = LoopMultipliers.rbegin(); + Expr *UpCounterVal = CounterVal; + Expr *Multiplier = nullptr; + for (int Cnt = NestedLoopCount - 1; Cnt >= 0; --Cnt) { + if (I->first) { + assert(IS->CounterStep); + Expr *NormalizedOffset = + SemaRef + .BuildBinOp(CurScope, I->first->getExprLoc(), BO_Div, + I->first, IS->CounterStep) + .get(); + if (Multiplier) { + NormalizedOffset = + SemaRef + .BuildBinOp(CurScope, I->first->getExprLoc(), BO_Mul, + NormalizedOffset, Multiplier) + .get(); + } + assert(I->second == OO_Plus || I->second == OO_Minus); + BinaryOperatorKind BOK = (I->second == OO_Plus) ? BO_Add : BO_Sub; + UpCounterVal = + SemaRef.BuildBinOp(CurScope, I->first->getExprLoc(), BOK, + UpCounterVal, NormalizedOffset).get(); + } + Multiplier = *ILM; + ++I; + ++IS; + ++ILM; + } + Pair.first->setCounterValue(UpCounterVal); + } + } return NestedLoopCount; } @@ -4156,26 +5426,44 @@ static Expr *getOrderedNumberExpr(ArrayRef<OMPClause *> Clauses) { 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; +static bool checkSimdlenSafelenSpecified(Sema &S, + const ArrayRef<OMPClause *> Clauses) { + 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) { + llvm::APSInt SimdlenRes, SafelenRes; + auto SimdlenLength = Simdlen->getSimdlen(); + auto SafelenLength = Safelen->getSafelen(); + if (SimdlenLength->isValueDependent() || SimdlenLength->isTypeDependent() || + SimdlenLength->isInstantiationDependent() || + SimdlenLength->containsUnexpandedParameterPack()) + return false; + if (SafelenLength->isValueDependent() || SafelenLength->isTypeDependent() || + SafelenLength->isInstantiationDependent() || + SafelenLength->containsUnexpandedParameterPack()) + return false; + SimdlenLength->EvaluateAsInt(SimdlenRes, S.Context); + SafelenLength->EvaluateAsInt(SafelenRes, S.Context); + // OpenMP 4.5 [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(SimdlenLength->getExprLoc(), + diag::err_omp_wrong_simdlen_safelen_values) + << SimdlenLength->getSourceRange() << SafelenLength->getSourceRange(); + return true; + } } return false; } @@ -4183,7 +5471,7 @@ static bool checkSimdlenSafelenValues(Sema &S, const Expr *Simdlen, StmtResult Sema::ActOnOpenMPSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, - llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -4205,27 +5493,13 @@ StmtResult Sema::ActOnOpenMPSimdDirective( for (auto C : Clauses) { if (auto LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), - B.NumIterations, *this, CurScope)) + B.NumIterations, *this, CurScope, + DSAStack)) return StmtError(); } } - // 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())) + if (checkSimdlenSafelenSpecified(*this, Clauses)) return StmtError(); getCurFunction()->setHasBranchProtectedScope(); @@ -4236,7 +5510,7 @@ StmtResult Sema::ActOnOpenMPSimdDirective( StmtResult Sema::ActOnOpenMPForDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, - llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -4258,7 +5532,8 @@ StmtResult Sema::ActOnOpenMPForDirective( for (auto C : Clauses) { if (auto LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), - B.NumIterations, *this, CurScope)) + B.NumIterations, *this, CurScope, + DSAStack)) return StmtError(); } } @@ -4271,7 +5546,7 @@ StmtResult Sema::ActOnOpenMPForDirective( StmtResult Sema::ActOnOpenMPForSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, - llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -4294,27 +5569,13 @@ StmtResult Sema::ActOnOpenMPForSimdDirective( for (auto C : Clauses) { if (auto LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), - B.NumIterations, *this, CurScope)) + B.NumIterations, *this, CurScope, + DSAStack)) return StmtError(); } } - // 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())) + if (checkSimdlenSafelenSpecified(*this, Clauses)) return StmtError(); getCurFunction()->setHasBranchProtectedScope(); @@ -4480,7 +5741,7 @@ StmtResult Sema::ActOnOpenMPCriticalDirective( StmtResult Sema::ActOnOpenMPParallelForDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, - llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -4510,7 +5771,8 @@ StmtResult Sema::ActOnOpenMPParallelForDirective( for (auto C : Clauses) { if (auto LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), - B.NumIterations, *this, CurScope)) + B.NumIterations, *this, CurScope, + DSAStack)) return StmtError(); } } @@ -4524,7 +5786,7 @@ StmtResult Sema::ActOnOpenMPParallelForDirective( StmtResult Sema::ActOnOpenMPParallelForSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, - llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -4551,27 +5813,13 @@ StmtResult Sema::ActOnOpenMPParallelForSimdDirective( for (auto C : Clauses) { if (auto LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), - B.NumIterations, *this, CurScope)) + B.NumIterations, *this, CurScope, + DSAStack)) return StmtError(); } } - // 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())) + if (checkSimdlenSafelenSpecified(*this, Clauses)) return StmtError(); getCurFunction()->setHasBranchProtectedScope(); @@ -5453,6 +6701,9 @@ StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses, } assert(I != CS->body_end() && "Not found statement"); S = *I; + } else { + auto *OED = dyn_cast<OMPExecutableDirective>(S); + OMPTeamsFound = OED && isOpenMPTeamsDirective(OED->getDirectiveKind()); } if (!OMPTeamsFound) { Diag(StartLoc, diag::err_omp_target_contains_not_only_teams); @@ -5469,6 +6720,84 @@ StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses, return OMPTargetDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); } +StmtResult +Sema::ActOnOpenMPTargetParallelDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc) { + 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(); + + getCurFunction()->setHasBranchProtectedScope(); + + return OMPTargetParallelDirective::Create(Context, StartLoc, EndLoc, Clauses, + AStmt); +} + +StmtResult Sema::ActOnOpenMPTargetParallelForDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + 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(); + + 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_target_parallel_for, getCollapseNumberExpr(Clauses), + getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack, + VarsWithImplicitDSA, B); + if (NestedLoopCount == 0) + return StmtError(); + + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp target 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, + DSAStack)) + return StmtError(); + } + } + + getCurFunction()->setHasBranchProtectedScope(); + return OMPTargetParallelForDirective::Create(Context, StartLoc, EndLoc, + NestedLoopCount, Clauses, AStmt, + B, DSAStack->isCancelRegion()); +} + +/// \brief Check for existence of a map clause in the list of clauses. +static bool HasMapClause(ArrayRef<OMPClause *> Clauses) { + for (ArrayRef<OMPClause *>::iterator I = Clauses.begin(), E = Clauses.end(); + I != E; ++I) { + if (*I != nullptr && (*I)->getClauseKind() == OMPC_map) { + return true; + } + } + + return false; +} + StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, @@ -5478,12 +6807,66 @@ StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses, assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); + // OpenMP [2.10.1, Restrictions, p. 97] + // At least one map clause must appear on the directive. + if (!HasMapClause(Clauses)) { + Diag(StartLoc, diag::err_omp_no_map_for_directive) << + getOpenMPDirectiveName(OMPD_target_data); + return StmtError(); + } + getCurFunction()->setHasBranchProtectedScope(); return OMPTargetDataDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); } +StmtResult +Sema::ActOnOpenMPTargetEnterDataDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc) { + // OpenMP [2.10.2, Restrictions, p. 99] + // At least one map clause must appear on the directive. + if (!HasMapClause(Clauses)) { + Diag(StartLoc, diag::err_omp_no_map_for_directive) + << getOpenMPDirectiveName(OMPD_target_enter_data); + return StmtError(); + } + + return OMPTargetEnterDataDirective::Create(Context, StartLoc, EndLoc, + Clauses); +} + +StmtResult +Sema::ActOnOpenMPTargetExitDataDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc) { + // OpenMP [2.10.3, Restrictions, p. 102] + // At least one map clause must appear on the directive. + if (!HasMapClause(Clauses)) { + Diag(StartLoc, diag::err_omp_no_map_for_directive) + << getOpenMPDirectiveName(OMPD_target_exit_data); + return StmtError(); + } + + return OMPTargetExitDataDirective::Create(Context, StartLoc, EndLoc, Clauses); +} + +StmtResult Sema::ActOnOpenMPTargetUpdateDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc) { + bool seenMotionClause = false; + for (auto *C : Clauses) { + if (C->getClauseKind() == OMPC_to || C->getClauseKind() == OMPC_from) + seenMotionClause = true; + } + if (!seenMotionClause) { + Diag(StartLoc, diag::err_omp_at_least_one_motion_clause_required); + return StmtError(); + } + return OMPTargetUpdateDirective::Create(Context, StartLoc, EndLoc, Clauses); +} + StmtResult Sema::ActOnOpenMPTeamsDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { @@ -5575,7 +6958,7 @@ static bool checkGrainsizeNumTasksClauses(Sema &S, StmtResult Sema::ActOnOpenMPTaskLoopDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, - llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -5607,7 +6990,7 @@ StmtResult Sema::ActOnOpenMPTaskLoopDirective( StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, - llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -5625,6 +7008,17 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective( 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, + DSAStack)) + return StmtError(); + } + } + // OpenMP, [2.9.2 taskloop Construct, Restrictions] // The grainsize clause and num_tasks clause are mutually exclusive and may // not appear on the same taskloop directive. @@ -5639,7 +7033,7 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective( StmtResult Sema::ActOnOpenMPDistributeDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, - llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -5662,6 +7056,157 @@ StmtResult Sema::ActOnOpenMPDistributeDirective( NestedLoopCount, Clauses, AStmt, B); } +StmtResult Sema::ActOnOpenMPDistributeParallelForDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + 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(); + + OMPLoopDirective::HelperExprs B; + // In presence of clause 'collapse' with number of loops, it will + // define the nested loops number. + unsigned NestedLoopCount = CheckOpenMPLoop( + OMPD_distribute_parallel_for, 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 OMPDistributeParallelForDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); +} + +StmtResult Sema::ActOnOpenMPDistributeParallelForSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + 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(); + + OMPLoopDirective::HelperExprs B; + // In presence of clause 'collapse' with number of loops, it will + // define the nested loops number. + unsigned NestedLoopCount = CheckOpenMPLoop( + OMPD_distribute_parallel_for_simd, 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"); + + if (checkSimdlenSafelenSpecified(*this, Clauses)) + return StmtError(); + + getCurFunction()->setHasBranchProtectedScope(); + return OMPDistributeParallelForSimdDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); +} + +StmtResult Sema::ActOnOpenMPDistributeSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + 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(); + + OMPLoopDirective::HelperExprs B; + // In presence of clause 'collapse' with number of loops, it will + // define the nested loops number. + unsigned NestedLoopCount = + CheckOpenMPLoop(OMPD_distribute_simd, 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"); + + if (checkSimdlenSafelenSpecified(*this, Clauses)) + return StmtError(); + + getCurFunction()->setHasBranchProtectedScope(); + return OMPDistributeSimdDirective::Create(Context, StartLoc, EndLoc, + NestedLoopCount, Clauses, AStmt, B); +} + +StmtResult Sema::ActOnOpenMPTargetParallelForSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + 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(); + + 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_target_parallel_for_simd, getCollapseNumberExpr(Clauses), + getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack, + VarsWithImplicitDSA, B); + if (NestedLoopCount == 0) + return StmtError(); + + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp target parallel for simd 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, + DSAStack)) + return StmtError(); + } + } + if (checkSimdlenSafelenSpecified(*this, Clauses)) + return StmtError(); + + getCurFunction()->setHasBranchProtectedScope(); + return OMPTargetParallelForSimdDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); +} + OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -5735,7 +7280,14 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_simd: case OMPC_map: case OMPC_nogroup: + case OMPC_dist_schedule: + case OMPC_defaultmap: case OMPC_unknown: + case OMPC_uniform: + case OMPC_to: + case OMPC_from: + case OMPC_use_device_ptr: + case OMPC_is_device_ptr: llvm_unreachable("Clause is not allowed."); } return Res; @@ -5751,12 +7303,11 @@ OMPClause *Sema::ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier, if (!Condition->isValueDependent() && !Condition->isTypeDependent() && !Condition->isInstantiationDependent() && !Condition->containsUnexpandedParameterPack()) { - ExprResult Val = ActOnBooleanCondition(DSAStack->getCurScope(), - Condition->getExprLoc(), Condition); + ExprResult Val = CheckBooleanCondition(StartLoc, Condition); if (Val.isInvalid()) return nullptr; - ValExpr = Val.get(); + ValExpr = MakeFullExpr(Val.get()).get(); } return new (Context) OMPIfClause(NameModifier, ValExpr, StartLoc, LParenLoc, @@ -5771,12 +7322,11 @@ OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition, if (!Condition->isValueDependent() && !Condition->isTypeDependent() && !Condition->isInstantiationDependent() && !Condition->containsUnexpandedParameterPack()) { - ExprResult Val = ActOnBooleanCondition(DSAStack->getCurScope(), - Condition->getExprLoc(), Condition); + ExprResult Val = CheckBooleanCondition(StartLoc, Condition); if (Val.isInvalid()) return nullptr; - ValExpr = Val.get(); + ValExpr = MakeFullExpr(Val.get()).get(); } return new (Context) OMPFinalClause(ValExpr, StartLoc, LParenLoc, EndLoc); @@ -6018,7 +7568,14 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_nogroup: case OMPC_num_tasks: case OMPC_hint: + case OMPC_dist_schedule: + case OMPC_defaultmap: case OMPC_unknown: + case OMPC_uniform: + case OMPC_to: + case OMPC_from: + case OMPC_use_device_ptr: + case OMPC_is_device_ptr: llvm_unreachable("Clause is not allowed."); } return Res; @@ -6116,6 +7673,19 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( Expr, StartLoc, LParenLoc, ArgumentLoc.back(), DelimLoc, EndLoc); break; + case OMPC_dist_schedule: + Res = ActOnOpenMPDistScheduleClause( + static_cast<OpenMPDistScheduleClauseKind>(Argument.back()), Expr, + StartLoc, LParenLoc, ArgumentLoc.back(), DelimLoc, EndLoc); + break; + case OMPC_defaultmap: + enum { Modifier, DefaultmapKind }; + Res = ActOnOpenMPDefaultmapClause( + static_cast<OpenMPDefaultmapClauseModifier>(Argument[Modifier]), + static_cast<OpenMPDefaultmapClauseKind>(Argument[DefaultmapKind]), + StartLoc, LParenLoc, ArgumentLoc[Modifier], + ArgumentLoc[DefaultmapKind], EndLoc); + break; case OMPC_final: case OMPC_num_threads: case OMPC_safelen: @@ -6156,6 +7726,11 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_num_tasks: case OMPC_hint: case OMPC_unknown: + case OMPC_uniform: + case OMPC_to: + case OMPC_from: + case OMPC_use_device_ptr: + case OMPC_is_device_ptr: llvm_unreachable("Clause is not allowed."); } return Res; @@ -6230,7 +7805,7 @@ OMPClause *Sema::ActOnOpenMPScheduleClause( return nullptr; } Expr *ValExpr = ChunkSize; - Expr *HelperValExpr = nullptr; + Stmt *HelperValStmt = nullptr; if (ChunkSize) { if (!ChunkSize->isValueDependent() && !ChunkSize->isTypeDependent() && !ChunkSize->isInstantiationDependent() && @@ -6253,20 +7828,18 @@ OMPClause *Sema::ActOnOpenMPScheduleClause( << "schedule" << 1 << ChunkSize->getSourceRange(); return nullptr; } - } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective())) { - auto *ImpVar = buildVarDecl(*this, ChunkSize->getExprLoc(), - ChunkSize->getType(), ".chunk."); - auto *ImpVarRef = buildDeclRefExpr(*this, ImpVar, ChunkSize->getType(), - ChunkSize->getExprLoc(), - /*RefersToCapture=*/true); - HelperValExpr = ImpVarRef; + } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective()) && + !CurContext->isDependentContext()) { + llvm::MapVector<Expr *, DeclRefExpr *> Captures; + ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); + HelperValStmt = buildPreInits(Context, Captures); } } } return new (Context) OMPScheduleClause(StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc, Kind, - ValExpr, HelperValExpr, M1, M1Loc, M2, M2Loc); + ValExpr, HelperValStmt, M1, M1Loc, M2, M2Loc); } OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, @@ -6339,7 +7912,14 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_grainsize: case OMPC_num_tasks: case OMPC_hint: + case OMPC_dist_schedule: + case OMPC_defaultmap: case OMPC_unknown: + case OMPC_uniform: + case OMPC_to: + case OMPC_from: + case OMPC_use_device_ptr: + case OMPC_is_device_ptr: llvm_unreachable("Clause is not allowed."); } return Res; @@ -6406,8 +7986,9 @@ OMPClause *Sema::ActOnOpenMPVarListClause( SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, OpenMPDependClauseKind DepKind, - OpenMPLinearClauseKind LinKind, OpenMPMapClauseKind MapTypeModifier, - OpenMPMapClauseKind MapType, SourceLocation DepLinMapLoc) { + OpenMPLinearClauseKind LinKind, OpenMPMapClauseKind MapTypeModifier, + OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, + SourceLocation DepLinMapLoc) { OMPClause *Res = nullptr; switch (Kind) { case OMPC_private: @@ -6448,8 +8029,21 @@ OMPClause *Sema::ActOnOpenMPVarListClause( StartLoc, LParenLoc, EndLoc); break; case OMPC_map: - Res = ActOnOpenMPMapClause(MapTypeModifier, MapType, DepLinMapLoc, ColonLoc, - VarList, StartLoc, LParenLoc, EndLoc); + Res = ActOnOpenMPMapClause(MapTypeModifier, MapType, IsMapTypeImplicit, + DepLinMapLoc, ColonLoc, VarList, StartLoc, + LParenLoc, EndLoc); + break; + case OMPC_to: + Res = ActOnOpenMPToClause(VarList, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_from: + Res = ActOnOpenMPFromClause(VarList, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_use_device_ptr: + Res = ActOnOpenMPUseDevicePtrClause(VarList, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_is_device_ptr: + Res = ActOnOpenMPIsDevicePtrClause(VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_if: case OMPC_final: @@ -6480,12 +8074,93 @@ OMPClause *Sema::ActOnOpenMPVarListClause( case OMPC_nogroup: case OMPC_num_tasks: case OMPC_hint: + case OMPC_dist_schedule: + case OMPC_defaultmap: case OMPC_unknown: + case OMPC_uniform: llvm_unreachable("Clause is not allowed."); } return Res; } +ExprResult Sema::getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK, + ExprObjectKind OK, SourceLocation Loc) { + ExprResult Res = BuildDeclRefExpr( + Capture, Capture->getType().getNonReferenceType(), VK_LValue, Loc); + if (!Res.isUsable()) + return ExprError(); + if (OK == OK_Ordinary && !getLangOpts().CPlusPlus) { + Res = CreateBuiltinUnaryOp(Loc, UO_Deref, Res.get()); + if (!Res.isUsable()) + return ExprError(); + } + if (VK != VK_LValue && Res.get()->isGLValue()) { + Res = DefaultLvalueConversion(Res.get()); + if (!Res.isUsable()) + return ExprError(); + } + return Res; +} + +static std::pair<ValueDecl *, bool> +getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc, + SourceRange &ERange, bool AllowArraySection = false) { + if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() || + RefExpr->containsUnexpandedParameterPack()) + return std::make_pair(nullptr, true); + + // OpenMP [3.1, C/C++] + // A list item is a variable name. + // OpenMP [2.9.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. + RefExpr = RefExpr->IgnoreParens(); + enum { + NoArrayExpr = -1, + ArraySubscript = 0, + OMPArraySection = 1 + } IsArrayExpr = NoArrayExpr; + if (AllowArraySection) { + if (auto *ASE = dyn_cast_or_null<ArraySubscriptExpr>(RefExpr)) { + auto *Base = ASE->getBase()->IgnoreParenImpCasts(); + while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base)) + Base = TempASE->getBase()->IgnoreParenImpCasts(); + RefExpr = Base; + IsArrayExpr = ArraySubscript; + } else if (auto *OASE = dyn_cast_or_null<OMPArraySectionExpr>(RefExpr)) { + 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(); + RefExpr = Base; + IsArrayExpr = OMPArraySection; + } + } + ELoc = RefExpr->getExprLoc(); + ERange = RefExpr->getSourceRange(); + RefExpr = RefExpr->IgnoreParenImpCasts(); + auto *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr); + auto *ME = dyn_cast_or_null<MemberExpr>(RefExpr); + if ((!DE || !isa<VarDecl>(DE->getDecl())) && + (S.getCurrentThisType().isNull() || !ME || + !isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()) || + !isa<FieldDecl>(ME->getMemberDecl()))) { + if (IsArrayExpr != NoArrayExpr) + S.Diag(ELoc, diag::err_omp_expected_base_var_name) << IsArrayExpr + << ERange; + else { + S.Diag(ELoc, + AllowArraySection + ? diag::err_omp_expected_var_name_member_expr_or_array_item + : diag::err_omp_expected_var_name_member_expr) + << (S.getCurrentThisType().isNull() ? 0 : 1) << ERange; + } + return std::make_pair(nullptr, false); + } + return std::make_pair(DE ? DE->getDecl() : ME->getMemberDecl(), false); +} + OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -6494,42 +8169,27 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, SmallVector<Expr *, 8> PrivateCopies; for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP private clause."); - if (isa<DependentScopeDeclRefExpr>(RefExpr)) { + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange); + if (Res.second) { // It will be analyzed later. Vars.push_back(RefExpr); PrivateCopies.push_back(nullptr); - continue; } - - SourceLocation ELoc = RefExpr->getExprLoc(); - // OpenMP [2.1, C/C++] - // A list item is a variable name. - // OpenMP [2.9.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. - DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr); - if (!DE || !isa<VarDecl>(DE->getDecl())) { - Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); + ValueDecl *D = Res.first; + if (!D) continue; - } - Decl *D = DE->getDecl(); - VarDecl *VD = cast<VarDecl>(D); - QualType Type = VD->getType(); - if (Type->isDependentType() || Type->isInstantiationDependentType()) { - // It will be analyzed later. - Vars.push_back(DE); - PrivateCopies.push_back(nullptr); - continue; - } + QualType Type = D->getType(); + auto *VD = dyn_cast<VarDecl>(D); // 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. - if (RequireCompleteType(ELoc, Type, - diag::err_omp_private_incomplete_type)) { + if (RequireCompleteType(ELoc, Type, diag::err_omp_private_incomplete_type)) continue; - } Type = Type.getNonReferenceType(); // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced @@ -6539,28 +8199,45 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, // listed below. For these exceptions only, listing a predetermined // variable in a data-sharing attribute clause is allowed and overrides // the variable's predetermined data-sharing attributes. - DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false); + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false); if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_private) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_private); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } // Variably modified types are not supported for tasks. if (!Type->isAnyPointerType() && Type->isVariablyModifiedType() && - DSAStack->getCurrentDirective() == OMPD_task) { + isOpenMPTaskingDirective(DSAStack->getCurrentDirective())) { Diag(ELoc, diag::err_omp_variably_modified_type_not_supported) << getOpenMPClauseName(OMPC_private) << Type << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); bool IsDecl = + !VD || VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), + Diag(D->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; + << D; continue; } + // OpenMP 4.5 [2.15.5.1, Restrictions, p.3] + // A list item cannot appear in both a map clause and a data-sharing + // attribute clause on the same construct + if (DSAStack->getCurrentDirective() == OMPD_target) { + if (DSAStack->checkMappableExprComponentListsForDecl( + VD, /* CurrentRegionOnly = */ true, + [&](OMPClauseMappableExprCommon::MappableExprComponentListRef) + -> bool { return true; })) { + Diag(ELoc, diag::err_omp_variable_in_map_and_dsa) + << getOpenMPClauseName(OMPC_private) + << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); + ReportOriginalDSA(*this, DSAStack, D, DVar); + continue; + } + } + // OpenMP [2.9.3.3, Restrictions, C/C++, p.1] // A variable of class type (or array thereof) that appears in a private // clause requires an accessible, unambiguous default constructor for the @@ -6571,16 +8248,21 @@ 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(), - VD->hasAttrs() ? &VD->getAttrs() : nullptr); + auto VDPrivate = buildVarDecl(*this, ELoc, Type, D->getName(), + D->hasAttrs() ? &D->getAttrs() : nullptr); ActOnUninitializedDecl(VDPrivate, /*TypeMayContainAuto=*/false); if (VDPrivate->isInvalidDecl()) continue; auto VDPrivateRefExpr = buildDeclRefExpr( - *this, VDPrivate, DE->getType().getUnqualifiedType(), DE->getExprLoc()); - - DSAStack->addDSA(VD, DE, OMPC_private); - Vars.push_back(DE); + *this, VDPrivate, RefExpr->getType().getUnqualifiedType(), ELoc); + + DeclRefExpr *Ref = nullptr; + if (!VD && !CurContext->isDependentContext()) + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false); + DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_private, Ref); + Vars.push_back((VD || CurContext->isDependentContext()) + ? RefExpr->IgnoreParens() + : Ref); PrivateCopies.push_back(VDPrivateRefExpr); } @@ -6621,51 +8303,37 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, SmallVector<Expr *, 8> Vars; SmallVector<Expr *, 8> PrivateCopies; SmallVector<Expr *, 8> Inits; + SmallVector<Decl *, 4> ExprCaptures; bool IsImplicitClause = StartLoc.isInvalid() && LParenLoc.isInvalid() && EndLoc.isInvalid(); auto ImplicitClauseLoc = DSAStack->getConstructLoc(); for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP firstprivate clause."); - if (isa<DependentScopeDeclRefExpr>(RefExpr)) { + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange); + if (Res.second) { // It will be analyzed later. Vars.push_back(RefExpr); PrivateCopies.push_back(nullptr); Inits.push_back(nullptr); - continue; } - - SourceLocation ELoc = - IsImplicitClause ? ImplicitClauseLoc : RefExpr->getExprLoc(); - // OpenMP [2.1, C/C++] - // A list item is a variable name. - // OpenMP [2.9.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. - DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr); - if (!DE || !isa<VarDecl>(DE->getDecl())) { - Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); + ValueDecl *D = Res.first; + if (!D) continue; - } - Decl *D = DE->getDecl(); - VarDecl *VD = cast<VarDecl>(D); - QualType Type = VD->getType(); - if (Type->isDependentType() || Type->isInstantiationDependentType()) { - // It will be analyzed later. - Vars.push_back(DE); - PrivateCopies.push_back(nullptr); - Inits.push_back(nullptr); - continue; - } + ELoc = IsImplicitClause ? ImplicitClauseLoc : ELoc; + QualType Type = D->getType(); + auto *VD = dyn_cast<VarDecl>(D); // 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. if (RequireCompleteType(ELoc, Type, - diag::err_omp_firstprivate_incomplete_type)) { + diag::err_omp_firstprivate_incomplete_type)) continue; - } Type = Type.getNonReferenceType(); // OpenMP [2.9.3.4, Restrictions, C/C++, p.1] @@ -6675,8 +8343,10 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, auto ElemType = Context.getBaseElementType(Type).getNonReferenceType(); // If an implicit firstprivate variable found it was checked already. + DSAStackTy::DSAVarData TopDVar; if (!IsImplicitClause) { - DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false); + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false); + TopDVar = DVar; bool IsConstant = ElemType.isConstant(Context); // OpenMP [2.4.13, Data-sharing Attribute Clauses] // A list item that specifies a given variable may not appear in more @@ -6687,7 +8357,7 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_firstprivate); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } @@ -6702,12 +8372,12 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // in a Construct, C/C++, p.2] // Variables with const-qualified type having no mutable member may be // listed in a firstprivate clause, even if they are static data members. - if (!(IsConstant || VD->isStaticDataMember()) && !DVar.RefExpr && + if (!(IsConstant || (VD && VD->isStaticDataMember())) && !DVar.RefExpr && DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_firstprivate); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } @@ -6719,14 +8389,14 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // to any of the parallel regions arising from the parallel construct. if (isOpenMPWorksharingDirective(CurrDir) && !isOpenMPParallelDirective(CurrDir)) { - DVar = DSAStack->getImplicitDSA(VD, true); + DVar = DSAStack->getImplicitDSA(D, true); if (DVar.CKind != OMPC_shared && (isOpenMPParallelDirective(DVar.DKind) || DVar.DKind == OMPD_unknown)) { Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseName(OMPC_firstprivate) << getOpenMPClauseName(OMPC_shared); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } } @@ -6741,20 +8411,20 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // construct must not appear in a firstprivate clause in a task construct // encountered during execution of any of the worksharing regions arising // from the worksharing construct. - if (CurrDir == OMPD_task) { - DVar = - DSAStack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_reduction), - [](OpenMPDirectiveKind K) -> bool { - return isOpenMPParallelDirective(K) || - isOpenMPWorksharingDirective(K); - }, - false); + if (isOpenMPTaskingDirective(CurrDir)) { + DVar = DSAStack->hasInnermostDSA( + D, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; }, + [](OpenMPDirectiveKind K) -> bool { + return isOpenMPParallelDirective(K) || + isOpenMPWorksharingDirective(K); + }, + false); if (DVar.CKind == OMPC_reduction && (isOpenMPParallelDirective(DVar.DKind) || isOpenMPWorksharingDirective(DVar.DKind))) { Diag(ELoc, diag::err_omp_parallel_reduction_in_task_firstprivate) << getOpenMPDirectiveName(DVar.DKind); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } } @@ -6773,31 +8443,48 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // 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); + DVar = DSAStack->hasInnermostDSA( + D, [](OpenMPClauseKind C) -> bool { return C == 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); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } - DVar = DSAStack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_reduction), - [](OpenMPDirectiveKind K) -> bool { - return isOpenMPTeamsDirective(K); - }, - false); + DVar = DSAStack->hasInnermostDSA( + D, [](OpenMPClauseKind C) -> bool { return C == 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); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } - DVar = DSAStack->getTopDSA(VD, false); + DVar = DSAStack->getTopDSA(D, false); if (DVar.CKind == OMPC_lastprivate) { Diag(ELoc, diag::err_omp_firstprivate_and_lastprivate_in_distribute); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); + continue; + } + } + // OpenMP 4.5 [2.15.5.1, Restrictions, p.3] + // A list item cannot appear in both a map clause and a data-sharing + // attribute clause on the same construct + if (CurrDir == OMPD_target) { + if (DSAStack->checkMappableExprComponentListsForDecl( + VD, /* CurrentRegionOnly = */ true, + [&](OMPClauseMappableExprCommon::MappableExprComponentListRef) + -> bool { return true; })) { + Diag(ELoc, diag::err_omp_variable_in_map_and_dsa) + << getOpenMPClauseName(OMPC_firstprivate) + << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } } @@ -6805,21 +8492,22 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // Variably modified types are not supported for tasks. if (!Type->isAnyPointerType() && Type->isVariablyModifiedType() && - DSAStack->getCurrentDirective() == OMPD_task) { + isOpenMPTaskingDirective(DSAStack->getCurrentDirective())) { Diag(ELoc, diag::err_omp_variably_modified_type_not_supported) << getOpenMPClauseName(OMPC_firstprivate) << Type << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); bool IsDecl = + !VD || VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), + Diag(D->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; + << D; continue; } Type = Type.getUnqualifiedType(); - auto VDPrivate = buildVarDecl(*this, ELoc, Type, VD->getName(), - VD->hasAttrs() ? &VD->getAttrs() : nullptr); + auto VDPrivate = buildVarDecl(*this, ELoc, Type, D->getName(), + D->hasAttrs() ? &D->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 @@ -6830,11 +8518,11 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // original array element in CodeGen. if (Type->isArrayType()) { auto VDInit = - buildVarDecl(*this, DE->getExprLoc(), ElemType, VD->getName()); + buildVarDecl(*this, RefExpr->getExprLoc(), ElemType, D->getName()); VDInitRefExpr = buildDeclRefExpr(*this, VDInit, ElemType, ELoc); auto Init = DefaultLvalueConversion(VDInitRefExpr).get(); ElemType = ElemType.getUnqualifiedType(); - auto *VDInitTemp = buildVarDecl(*this, DE->getLocStart(), ElemType, + auto *VDInitTemp = buildVarDecl(*this, RefExpr->getExprLoc(), ElemType, ".firstprivate.temp"); InitializedEntity Entity = InitializedEntity::InitializeVariable(VDInitTemp); @@ -6849,26 +8537,39 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // Remove temp variable declaration. Context.Deallocate(VDInitTemp); } else { - auto *VDInit = - buildVarDecl(*this, DE->getLocStart(), Type, ".firstprivate.temp"); - VDInitRefExpr = - buildDeclRefExpr(*this, VDInit, DE->getType(), DE->getExprLoc()); + auto *VDInit = buildVarDecl(*this, RefExpr->getExprLoc(), Type, + ".firstprivate.temp"); + VDInitRefExpr = buildDeclRefExpr(*this, VDInit, RefExpr->getType(), + RefExpr->getExprLoc()); AddInitializerToDecl(VDPrivate, DefaultLvalueConversion(VDInitRefExpr).get(), /*DirectInit=*/false, /*TypeMayContainAuto=*/false); } if (VDPrivate->isInvalidDecl()) { if (IsImplicitClause) { - Diag(DE->getExprLoc(), + Diag(RefExpr->getExprLoc(), diag::note_omp_task_predetermined_firstprivate_here); } continue; } CurContext->addDecl(VDPrivate); auto VDPrivateRefExpr = buildDeclRefExpr( - *this, VDPrivate, DE->getType().getUnqualifiedType(), DE->getExprLoc()); - DSAStack->addDSA(VD, DE, OMPC_firstprivate); - Vars.push_back(DE); + *this, VDPrivate, RefExpr->getType().getUnqualifiedType(), + RefExpr->getExprLoc()); + DeclRefExpr *Ref = nullptr; + if (!VD && !CurContext->isDependentContext()) { + if (TopDVar.CKind == OMPC_lastprivate) + Ref = TopDVar.PrivateCopy; + else { + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true); + if (!IsOpenMPCapturedDecl(D)) + ExprCaptures.push_back(Ref->getDecl()); + } + } + DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_firstprivate, Ref); + Vars.push_back((VD || CurContext->isDependentContext()) + ? RefExpr->IgnoreParens() + : Ref); PrivateCopies.push_back(VDPrivateRefExpr); Inits.push_back(VDInitRefExpr); } @@ -6877,7 +8578,8 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, return nullptr; return OMPFirstprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, - Vars, PrivateCopies, Inits); + Vars, PrivateCopies, Inits, + buildPreInits(Context, ExprCaptures)); } OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, @@ -6888,48 +8590,34 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, SmallVector<Expr *, 8> SrcExprs; SmallVector<Expr *, 8> DstExprs; SmallVector<Expr *, 8> AssignmentOps; + SmallVector<Decl *, 4> ExprCaptures; + SmallVector<Expr *, 4> ExprPostUpdates; for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP lastprivate clause."); - if (isa<DependentScopeDeclRefExpr>(RefExpr)) { + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange); + if (Res.second) { // It will be analyzed later. Vars.push_back(RefExpr); SrcExprs.push_back(nullptr); DstExprs.push_back(nullptr); AssignmentOps.push_back(nullptr); - continue; } - - SourceLocation ELoc = RefExpr->getExprLoc(); - // OpenMP [2.1, C/C++] - // A list item is a variable name. - // OpenMP [2.14.3.5, Restrictions, p.1] - // A variable that is part of another variable (as an array or structure - // element) cannot appear in a lastprivate clause. - DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr); - if (!DE || !isa<VarDecl>(DE->getDecl())) { - Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); + ValueDecl *D = Res.first; + if (!D) continue; - } - Decl *D = DE->getDecl(); - VarDecl *VD = cast<VarDecl>(D); - QualType Type = VD->getType(); - if (Type->isDependentType() || Type->isInstantiationDependentType()) { - // It will be analyzed later. - Vars.push_back(DE); - SrcExprs.push_back(nullptr); - DstExprs.push_back(nullptr); - AssignmentOps.push_back(nullptr); - continue; - } + QualType Type = D->getType(); + auto *VD = dyn_cast<VarDecl>(D); // OpenMP [2.14.3.5, Restrictions, C/C++, p.2] // A variable that appears in a lastprivate clause must not have an // incomplete type or a reference type. if (RequireCompleteType(ELoc, Type, - diag::err_omp_lastprivate_incomplete_type)) { + diag::err_omp_lastprivate_incomplete_type)) continue; - } Type = Type.getNonReferenceType(); // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced @@ -6937,14 +8625,14 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, // Variables with the predetermined data-sharing attributes may not be // listed in data-sharing attributes clauses, except for the cases // listed below. - DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false); + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false); if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_lastprivate && DVar.CKind != OMPC_firstprivate && (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_lastprivate); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } @@ -6958,15 +8646,28 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, DSAStackTy::DSAVarData TopDVar = DVar; if (isOpenMPWorksharingDirective(CurrDir) && !isOpenMPParallelDirective(CurrDir)) { - DVar = DSAStack->getImplicitDSA(VD, true); + DVar = DSAStack->getImplicitDSA(D, true); if (DVar.CKind != OMPC_shared) { Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseName(OMPC_lastprivate) << getOpenMPClauseName(OMPC_shared); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); 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(D, false); + if (DVar.CKind == OMPC_firstprivate) { + Diag(ELoc, diag::err_omp_firstprivate_and_lastprivate_in_distribute); + ReportOriginalDSA(*this, DSAStack, D, DVar); + continue; + } + } + // OpenMP [2.14.3.5, Restrictions, C++, p.1,2] // A variable of class type (or array thereof) that appears in a // lastprivate clause requires an accessible, unambiguous default @@ -6976,42 +8677,54 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, // lastprivate clause requires an accessible, unambiguous copy assignment // operator for the class type. Type = Context.getBaseElementType(Type).getNonReferenceType(); - auto *SrcVD = buildVarDecl(*this, DE->getLocStart(), + auto *SrcVD = buildVarDecl(*this, ERange.getBegin(), Type.getUnqualifiedType(), ".lastprivate.src", - VD->hasAttrs() ? &VD->getAttrs() : nullptr); - auto *PseudoSrcExpr = buildDeclRefExpr( - *this, SrcVD, Type.getUnqualifiedType(), DE->getExprLoc()); + D->hasAttrs() ? &D->getAttrs() : nullptr); + auto *PseudoSrcExpr = + buildDeclRefExpr(*this, SrcVD, Type.getUnqualifiedType(), ELoc); auto *DstVD = - buildVarDecl(*this, DE->getLocStart(), Type, ".lastprivate.dst", - VD->hasAttrs() ? &VD->getAttrs() : nullptr); - auto *PseudoDstExpr = - buildDeclRefExpr(*this, DstVD, Type, DE->getExprLoc()); + buildVarDecl(*this, ERange.getBegin(), Type, ".lastprivate.dst", + D->hasAttrs() ? &D->getAttrs() : nullptr); + auto *PseudoDstExpr = buildDeclRefExpr(*this, DstVD, Type, ELoc); // For arrays generate assignment operation for single element and replace // it by the original array element in CodeGen. - auto AssignmentOp = BuildBinOp(/*S=*/nullptr, DE->getExprLoc(), BO_Assign, + auto AssignmentOp = BuildBinOp(/*S=*/nullptr, ELoc, BO_Assign, PseudoDstExpr, PseudoSrcExpr); if (AssignmentOp.isInvalid()) continue; - AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), DE->getExprLoc(), + AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), ELoc, /*DiscardedValue=*/true); 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; + DeclRefExpr *Ref = nullptr; + if (!VD && !CurContext->isDependentContext()) { + if (TopDVar.CKind == OMPC_firstprivate) + Ref = TopDVar.PrivateCopy; + else { + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false); + if (!IsOpenMPCapturedDecl(D)) + ExprCaptures.push_back(Ref->getDecl()); + } + if (TopDVar.CKind == OMPC_firstprivate || + (!IsOpenMPCapturedDecl(D) && + Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>())) { + ExprResult RefRes = DefaultLvalueConversion(Ref); + if (!RefRes.isUsable()) + continue; + ExprResult PostUpdateRes = + BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, SimpleRefExpr, + RefRes.get()); + if (!PostUpdateRes.isUsable()) + continue; + ExprPostUpdates.push_back( + IgnoredValueConversions(PostUpdateRes.get()).get()); } } - - if (TopDVar.CKind != OMPC_firstprivate) - DSAStack->addDSA(VD, DE, OMPC_lastprivate); - Vars.push_back(DE); + DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_lastprivate, Ref); + Vars.push_back((VD || CurContext->isDependentContext()) + ? RefExpr->IgnoreParens() + : Ref); SrcExprs.push_back(PseudoSrcExpr); DstExprs.push_back(PseudoDstExpr); AssignmentOps.push_back(AssignmentOp.get()); @@ -7021,7 +8734,9 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, return nullptr; return OMPLastprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, - Vars, SrcExprs, DstExprs, AssignmentOps); + Vars, SrcExprs, DstExprs, AssignmentOps, + buildPreInits(Context, ExprCaptures), + buildPostUpdate(*this, ExprPostUpdates)); } OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList, @@ -7030,35 +8745,20 @@ OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; for (auto &RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP shared clause."); - if (isa<DependentScopeDeclRefExpr>(RefExpr)) { + assert(RefExpr && "NULL expr in OpenMP lastprivate clause."); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange); + if (Res.second) { // It will be analyzed later. Vars.push_back(RefExpr); - continue; - } - - SourceLocation ELoc = RefExpr->getExprLoc(); - // OpenMP [2.1, C/C++] - // A list item is a variable name. - // OpenMP [2.14.3.2, Restrictions, p.1] - // A variable that is part of another variable (as an array or structure - // element) cannot appear in a shared unless it is a static data member - // of a C++ class. - DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr); - if (!DE || !isa<VarDecl>(DE->getDecl())) { - Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); - continue; } - Decl *D = DE->getDecl(); - VarDecl *VD = cast<VarDecl>(D); - - QualType Type = VD->getType(); - if (Type->isDependentType() || Type->isInstantiationDependentType()) { - // It will be analyzed later. - Vars.push_back(DE); + ValueDecl *D = Res.first; + if (!D) continue; - } + auto *VD = dyn_cast<VarDecl>(D); // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct] // Variables with the predetermined data-sharing attributes may not be @@ -7066,17 +8766,22 @@ OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList, // listed below. For these exceptions only, listing a predetermined // variable in a data-sharing attribute clause is allowed and overrides // the variable's predetermined data-sharing attributes. - DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false); + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false); if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared && DVar.RefExpr) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_shared); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } - DSAStack->addDSA(VD, DE, OMPC_shared); - Vars.push_back(DE); + DeclRefExpr *Ref = nullptr; + if (!VD && IsOpenMPCapturedDecl(D) && !CurContext->isDependentContext()) + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true); + DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_shared, Ref); + Vars.push_back((VD || !Ref || CurContext->isDependentContext()) + ? RefExpr->IgnoreParens() + : Ref); } if (Vars.empty()) @@ -7097,8 +8802,9 @@ public: return false; if (DVar.CKind != OMPC_unknown) return true; - DSAStackTy::DSAVarData DVarPrivate = - Stack->hasDSA(VD, isOpenMPPrivate, MatchesAlways(), false); + DSAStackTy::DSAVarData DVarPrivate = Stack->hasDSA( + VD, isOpenMPPrivate, [](OpenMPDirectiveKind) -> bool { return true; }, + false); if (DVarPrivate.CKind != OMPC_unknown) return true; return false; @@ -7116,16 +8822,137 @@ public: }; } // namespace +namespace { +// Transform MemberExpression for specified FieldDecl of current class to +// DeclRefExpr to specified OMPCapturedExprDecl. +class TransformExprToCaptures : public TreeTransform<TransformExprToCaptures> { + typedef TreeTransform<TransformExprToCaptures> BaseTransform; + ValueDecl *Field; + DeclRefExpr *CapturedExpr; + +public: + TransformExprToCaptures(Sema &SemaRef, ValueDecl *FieldDecl) + : BaseTransform(SemaRef), Field(FieldDecl), CapturedExpr(nullptr) {} + + ExprResult TransformMemberExpr(MemberExpr *E) { + if (isa<CXXThisExpr>(E->getBase()->IgnoreParenImpCasts()) && + E->getMemberDecl() == Field) { + CapturedExpr = buildCapture(SemaRef, Field, E, /*WithInit=*/false); + return CapturedExpr; + } + return BaseTransform::TransformMemberExpr(E); + } + DeclRefExpr *getCapturedExpr() { return CapturedExpr; } +}; +} // namespace + +template <typename T> +static T filterLookupForUDR(SmallVectorImpl<UnresolvedSet<8>> &Lookups, + const llvm::function_ref<T(ValueDecl *)> &Gen) { + for (auto &Set : Lookups) { + for (auto *D : Set) { + if (auto Res = Gen(cast<ValueDecl>(D))) + return Res; + } + } + return T(); +} + +static ExprResult +buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range, + Scope *S, CXXScopeSpec &ReductionIdScopeSpec, + const DeclarationNameInfo &ReductionId, QualType Ty, + CXXCastPath &BasePath, Expr *UnresolvedReduction) { + if (ReductionIdScopeSpec.isInvalid()) + return ExprError(); + SmallVector<UnresolvedSet<8>, 4> Lookups; + if (S) { + LookupResult Lookup(SemaRef, ReductionId, Sema::LookupOMPReductionName); + Lookup.suppressDiagnostics(); + while (S && SemaRef.LookupParsedName(Lookup, S, &ReductionIdScopeSpec)) { + auto *D = Lookup.getRepresentativeDecl(); + do { + S = S->getParent(); + } while (S && !S->isDeclScope(D)); + if (S) + S = S->getParent(); + Lookups.push_back(UnresolvedSet<8>()); + Lookups.back().append(Lookup.begin(), Lookup.end()); + Lookup.clear(); + } + } else if (auto *ULE = + cast_or_null<UnresolvedLookupExpr>(UnresolvedReduction)) { + Lookups.push_back(UnresolvedSet<8>()); + Decl *PrevD = nullptr; + for(auto *D : ULE->decls()) { + if (D == PrevD) + Lookups.push_back(UnresolvedSet<8>()); + else if (auto *DRD = cast<OMPDeclareReductionDecl>(D)) + Lookups.back().addDecl(DRD); + PrevD = D; + } + } + if (Ty->isDependentType() || Ty->isInstantiationDependentType() || + Ty->containsUnexpandedParameterPack() || + filterLookupForUDR<bool>(Lookups, [](ValueDecl *D) -> bool { + return !D->isInvalidDecl() && + (D->getType()->isDependentType() || + D->getType()->isInstantiationDependentType() || + D->getType()->containsUnexpandedParameterPack()); + })) { + UnresolvedSet<8> ResSet; + for (auto &Set : Lookups) { + ResSet.append(Set.begin(), Set.end()); + // The last item marks the end of all declarations at the specified scope. + ResSet.addDecl(Set[Set.size() - 1]); + } + return UnresolvedLookupExpr::Create( + SemaRef.Context, /*NamingClass=*/nullptr, + ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), ReductionId, + /*ADL=*/true, /*Overloaded=*/true, ResSet.begin(), ResSet.end()); + } + if (auto *VD = filterLookupForUDR<ValueDecl *>( + Lookups, [&SemaRef, Ty](ValueDecl *D) -> ValueDecl * { + if (!D->isInvalidDecl() && + SemaRef.Context.hasSameType(D->getType(), Ty)) + return D; + return nullptr; + })) + return SemaRef.BuildDeclRefExpr(VD, Ty, VK_LValue, Loc); + if (auto *VD = filterLookupForUDR<ValueDecl *>( + Lookups, [&SemaRef, Ty, Loc](ValueDecl *D) -> ValueDecl * { + if (!D->isInvalidDecl() && + SemaRef.IsDerivedFrom(Loc, Ty, D->getType()) && + !Ty.isMoreQualifiedThan(D->getType())) + return D; + return nullptr; + })) { + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/false); + if (SemaRef.IsDerivedFrom(Loc, Ty, VD->getType(), Paths)) { + if (!Paths.isAmbiguous(SemaRef.Context.getCanonicalType( + VD->getType().getUnqualifiedType()))) { + if (SemaRef.CheckBaseClassAccess(Loc, VD->getType(), Ty, Paths.front(), + /*DiagID=*/0) != + Sema::AR_inaccessible) { + SemaRef.BuildBasePathArray(Paths, BasePath); + return SemaRef.BuildDeclRefExpr(VD, Ty, VK_LValue, Loc); + } + } + } + } + if (ReductionIdScopeSpec.isSet()) { + SemaRef.Diag(Loc, diag::err_omp_not_resolved_reduction_identifier) << Range; + return ExprError(); + } + return ExprEmpty(); +} + OMPClause *Sema::ActOnOpenMPReductionClause( ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, - CXXScopeSpec &ReductionIdScopeSpec, - const DeclarationNameInfo &ReductionId) { - // TODO: Allow scope specification search when 'declare reduction' is - // supported. - assert(ReductionIdScopeSpec.isEmpty() && - "No support for scoped reduction identifiers yet."); - + CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, + ArrayRef<Expr *> UnresolvedReductions) { auto DN = ReductionId.getName(); auto OOK = DN.getCXXOverloadedOperator(); BinaryOperatorKind BOK = BO_Comma; @@ -7209,48 +9036,21 @@ OMPClause *Sema::ActOnOpenMPReductionClause( break; } SourceRange ReductionIdRange; - if (ReductionIdScopeSpec.isValid()) { + if (ReductionIdScopeSpec.isValid()) ReductionIdRange.setBegin(ReductionIdScopeSpec.getBeginLoc()); - } ReductionIdRange.setEnd(ReductionId.getEndLoc()); - if (BOK == BO_Comma) { - // Not allowed reduction identifier is found. - Diag(ReductionId.getLocStart(), diag::err_omp_unknown_reduction_identifier) - << ReductionIdRange; - return nullptr; - } SmallVector<Expr *, 8> Vars; SmallVector<Expr *, 8> Privates; SmallVector<Expr *, 8> LHSs; SmallVector<Expr *, 8> RHSs; SmallVector<Expr *, 8> ReductionOps; + SmallVector<Decl *, 4> ExprCaptures; + SmallVector<Expr *, 4> ExprPostUpdates; + auto IR = UnresolvedReductions.begin(), ER = UnresolvedReductions.end(); + bool FirstIter = true; for (auto RefExpr : VarList) { assert(RefExpr && "nullptr expr in OpenMP reduction clause."); - 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); - continue; - } - - if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() || - RefExpr->isInstantiationDependent() || - 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); - continue; - } - - auto ELoc = RefExpr->getExprLoc(); - auto ERange = RefExpr->getSourceRange(); // OpenMP [2.1, C/C++] // A list item is a variable or array section, subject to the restrictions // specified in Section 2.4 on page 42 and in each of the sections @@ -7258,52 +9058,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); - 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; + if (!FirstIter && IR != ER) + ++IR; + FirstIter = false; + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/true); + if (Res.second) { + // It will be analyzed later. + Vars.push_back(RefExpr); + Privates.push_back(nullptr); + LHSs.push_back(nullptr); + RHSs.push_back(nullptr); + // Try to find 'declare reduction' corresponding construct before using + // builtin/overloaded operators. + QualType Type = Context.DependentTy; + CXXCastPath BasePath; + ExprResult DeclareReductionRef = buildDeclareReductionRef( + *this, ELoc, ERange, DSAStack->getCurScope(), ReductionIdScopeSpec, + ReductionId, Type, BasePath, IR == ER ? nullptr : *IR); + if (CurContext->isDependentContext() && + (DeclareReductionRef.isUnset() || + isa<UnresolvedLookupExpr>(DeclareReductionRef.get()))) + ReductionOps.push_back(DeclareReductionRef.get()); + else + ReductionOps.push_back(nullptr); } + ValueDecl *D = Res.first; + if (!D) + continue; + 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 *ASE = dyn_cast<ArraySubscriptExpr>(RefExpr->IgnoreParens()); + auto *OASE = dyn_cast<OMPArraySectionExpr>(RefExpr->IgnoreParens()); + if (ASE) + Type = ASE->getType().getNonReferenceType(); + 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; - } - } + Type = Type.getNonReferenceType(); + } else + Type = Context.getBaseElementType(D->getType().getNonReferenceType()); + auto *VD = dyn_cast<VarDecl>(D); // OpenMP [2.9.3.3, Restrictions, C/C++, p.3] // A variable that appears in a private clause must not have an incomplete @@ -7312,39 +9113,27 @@ OMPClause *Sema::ActOnOpenMPReductionClause( diag::err_omp_reduction_incomplete_type)) continue; // OpenMP [2.14.3.6, reduction clause, Restrictions] - // Arrays may not appear in a reduction clause. - if (Type.getNonReferenceType()->isArrayType()) { - Diag(ELoc, diag::err_omp_reduction_type_array) << Type << ERange; - 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_reduction_list_item) << getOpenMPClauseName(OMPC_reduction) << Type << ERange; if (!ASE && !OASE) { - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), + bool IsDecl = !VD || + VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(D->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; + << D; } 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. - if (!ASE && !OASE) { + if (!ASE && !OASE && VD) { VarDecl *VDDef = VD->getDefinition(); - if (Type->isReferenceType() && VDDef) { + if (VD->getType()->isReferenceType() && VDDef && VDDef->hasInit()) { DSARefChecker Check(DSAStack); if (Check.Visit(VDDef->getInit())) { Diag(ELoc, diag::err_omp_reduction_ref_type_arg) << ERange; @@ -7353,40 +9142,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause( } } } - // OpenMP [2.14.3.6, reduction clause, Restrictions] - // The type of a list item that appears in a reduction clause must be valid - // for the reduction-identifier. For a max or min reduction in C, the type - // of the list item must be an allowed arithmetic data type: char, int, - // float, double, or _Bool, possibly modified with long, short, signed, or - // unsigned. For a max or min reduction in C++, the type of the list item - // must be an allowed arithmetic data type: char, wchar_t, int, float, - // double, or bool, possibly modified with long, short, signed, or unsigned. - if ((BOK == BO_GT || BOK == BO_LT) && - !(Type->isScalarType() || - (getLangOpts().CPlusPlus && Type->isArithmeticType()))) { - Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg) - << getLangOpts().CPlusPlus; - 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); - 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 // in a Construct] // Variables with the predetermined data-sharing attributes may not be @@ -7399,18 +9155,17 @@ OMPClause *Sema::ActOnOpenMPReductionClause( // but a list item can appear only once in the reduction clauses for that // directive. DSAStackTy::DSAVarData DVar; - DVar = DSAStack->getTopDSA(VD, false); + DVar = DSAStack->getTopDSA(D, false); if (DVar.CKind == OMPC_reduction) { Diag(ELoc, diag::err_omp_once_referenced) << getOpenMPClauseName(OMPC_reduction); - if (DVar.RefExpr) { + if (DVar.RefExpr) Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced); - } } else if (DVar.CKind != OMPC_unknown) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_reduction); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } @@ -7421,24 +9176,91 @@ OMPClause *Sema::ActOnOpenMPReductionClause( OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective(); if (isOpenMPWorksharingDirective(CurrDir) && !isOpenMPParallelDirective(CurrDir)) { - DVar = DSAStack->getImplicitDSA(VD, true); + DVar = DSAStack->getImplicitDSA(D, true); if (DVar.CKind != OMPC_shared) { Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseName(OMPC_reduction) << getOpenMPClauseName(OMPC_shared); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); + continue; + } + } + + // Try to find 'declare reduction' corresponding construct before using + // builtin/overloaded operators. + CXXCastPath BasePath; + ExprResult DeclareReductionRef = buildDeclareReductionRef( + *this, ELoc, ERange, DSAStack->getCurScope(), ReductionIdScopeSpec, + ReductionId, Type, BasePath, IR == ER ? nullptr : *IR); + if (DeclareReductionRef.isInvalid()) + continue; + if (CurContext->isDependentContext() && + (DeclareReductionRef.isUnset() || + isa<UnresolvedLookupExpr>(DeclareReductionRef.get()))) { + Vars.push_back(RefExpr); + Privates.push_back(nullptr); + LHSs.push_back(nullptr); + RHSs.push_back(nullptr); + ReductionOps.push_back(DeclareReductionRef.get()); + continue; + } + if (BOK == BO_Comma && DeclareReductionRef.isUnset()) { + // Not allowed reduction identifier is found. + Diag(ReductionId.getLocStart(), + diag::err_omp_unknown_reduction_identifier) + << Type << ReductionIdRange; + continue; + } + + // OpenMP [2.14.3.6, reduction clause, Restrictions] + // The type of a list item that appears in a reduction clause must be valid + // for the reduction-identifier. For a max or min reduction in C, the type + // of the list item must be an allowed arithmetic data type: char, int, + // float, double, or _Bool, possibly modified with long, short, signed, or + // unsigned. For a max or min reduction in C++, the type of the list item + // must be an allowed arithmetic data type: char, wchar_t, int, float, + // double, or bool, possibly modified with long, short, signed, or unsigned. + if (DeclareReductionRef.isUnset()) { + if ((BOK == BO_GT || BOK == BO_LT) && + !(Type->isScalarType() || + (getLangOpts().CPlusPlus && Type->isArithmeticType()))) { + Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg) + << getLangOpts().CPlusPlus; + if (!ASE && !OASE) { + bool IsDecl = !VD || + VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(D->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << D; + } + continue; + } + if ((BOK == BO_OrAssign || BOK == BO_AndAssign || BOK == BO_XorAssign) && + !getLangOpts().CPlusPlus && Type->isFloatingType()) { + Diag(ELoc, diag::err_omp_clause_floating_type_arg); + if (!ASE && !OASE) { + bool IsDecl = !VD || + VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(D->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << D; + } continue; } } Type = Type.getNonLValueExprType(Context).getUnqualifiedType(); 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); + D->hasAttrs() ? &D->getAttrs() : nullptr); + auto *RHSVD = buildVarDecl(*this, ELoc, Type, D->getName(), + D->hasAttrs() ? &D->getAttrs() : nullptr); auto PrivateTy = Type; - if (OASE) { - // For array sections only: + if (OASE || + (!ASE && + D->getType().getNonReferenceType()->isVariablyModifiedType())) { + // For arays/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 @@ -7447,162 +9269,227 @@ OMPClause *Sema::ActOnOpenMPReductionClause( Type, new (Context) OpaqueValueExpr(SourceLocation(), Context.getSizeType(), VK_RValue), ArrayType::Normal, /*IndexTypeQuals=*/0, SourceRange()); - } + } else if (!ASE && !OASE && + Context.getAsArrayType(D->getType().getNonReferenceType())) + PrivateTy = D->getType().getNonReferenceType(); // Private copy. - auto *PrivateVD = buildVarDecl(*this, ELoc, PrivateTy, VD->getName(), - VD->hasAttrs() ? &VD->getAttrs() : nullptr); + auto *PrivateVD = buildVarDecl(*this, ELoc, PrivateTy, D->getName(), + D->hasAttrs() ? &D->getAttrs() : nullptr); // Add initializer for private variable. Expr *Init = nullptr; - switch (BOK) { - case BO_Add: - case BO_Xor: - case BO_Or: - case BO_LOr: - // '+', '-', '^', '|', '||' reduction ops - initializer is '0'. - if (Type->isScalarType() || Type->isAnyComplexType()) { - Init = ActOnIntegerConstant(ELoc, /*Val=*/0).get(); - } - break; - case BO_Mul: - case BO_LAnd: - if (Type->isScalarType() || Type->isAnyComplexType()) { - // '*' and '&&' reduction ops - initializer is '1'. - Init = ActOnIntegerConstant(ELoc, /*Val=*/1).get(); - } - break; - case BO_And: { - // '&' reduction op - initializer is '~0'. - QualType OrigType = Type; - if (auto *ComplexTy = OrigType->getAs<ComplexType>()) { - Type = ComplexTy->getElementType(); - } - if (Type->isRealFloatingType()) { - llvm::APFloat InitValue = - llvm::APFloat::getAllOnesValue(Context.getTypeSize(Type), - /*isIEEE=*/true); - Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true, - Type, ELoc); - } else if (Type->isScalarType()) { - auto Size = Context.getTypeSize(Type); - QualType IntTy = Context.getIntTypeForBitwidth(Size, /*Signed=*/0); - llvm::APInt InitValue = llvm::APInt::getAllOnesValue(Size); - Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc); + auto *LHSDRE = buildDeclRefExpr(*this, LHSVD, Type, ELoc); + auto *RHSDRE = buildDeclRefExpr(*this, RHSVD, Type, ELoc); + if (DeclareReductionRef.isUsable()) { + auto *DRDRef = DeclareReductionRef.getAs<DeclRefExpr>(); + auto *DRD = cast<OMPDeclareReductionDecl>(DRDRef->getDecl()); + if (DRD->getInitializer()) { + Init = DRDRef; + RHSVD->setInit(DRDRef); + RHSVD->setInitStyle(VarDecl::CallInit); } - if (Init && OrigType->isAnyComplexType()) { - // Init = 0xFFFF + 0xFFFFi; - auto *Im = new (Context) ImaginaryLiteral(Init, OrigType); - Init = CreateBuiltinBinOp(ELoc, BO_Add, Init, Im).get(); + } else { + switch (BOK) { + case BO_Add: + case BO_Xor: + case BO_Or: + case BO_LOr: + // '+', '-', '^', '|', '||' reduction ops - initializer is '0'. + if (Type->isScalarType() || Type->isAnyComplexType()) + Init = ActOnIntegerConstant(ELoc, /*Val=*/0).get(); + break; + case BO_Mul: + case BO_LAnd: + if (Type->isScalarType() || Type->isAnyComplexType()) { + // '*' and '&&' reduction ops - initializer is '1'. + Init = ActOnIntegerConstant(ELoc, /*Val=*/1).get(); + } + break; + case BO_And: { + // '&' reduction op - initializer is '~0'. + QualType OrigType = Type; + if (auto *ComplexTy = OrigType->getAs<ComplexType>()) + Type = ComplexTy->getElementType(); + if (Type->isRealFloatingType()) { + llvm::APFloat InitValue = + llvm::APFloat::getAllOnesValue(Context.getTypeSize(Type), + /*isIEEE=*/true); + Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true, + Type, ELoc); + } else if (Type->isScalarType()) { + auto Size = Context.getTypeSize(Type); + QualType IntTy = Context.getIntTypeForBitwidth(Size, /*Signed=*/0); + llvm::APInt InitValue = llvm::APInt::getAllOnesValue(Size); + Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc); + } + if (Init && OrigType->isAnyComplexType()) { + // Init = 0xFFFF + 0xFFFFi; + auto *Im = new (Context) ImaginaryLiteral(Init, OrigType); + Init = CreateBuiltinBinOp(ELoc, BO_Add, Init, Im).get(); + } + Type = OrigType; + break; } - Type = OrigType; - break; - } - case BO_LT: - case BO_GT: { - // 'min' reduction op - initializer is 'Largest representable number in - // the reduction list item type'. - // 'max' reduction op - initializer is 'Least representable number in - // the reduction list item type'. - if (Type->isIntegerType() || Type->isPointerType()) { - bool IsSigned = Type->hasSignedIntegerRepresentation(); - auto Size = Context.getTypeSize(Type); - QualType IntTy = - Context.getIntTypeForBitwidth(Size, /*Signed=*/IsSigned); - llvm::APInt InitValue = - (BOK != BO_LT) - ? IsSigned ? llvm::APInt::getSignedMinValue(Size) - : llvm::APInt::getMinValue(Size) - : IsSigned ? llvm::APInt::getSignedMaxValue(Size) - : llvm::APInt::getMaxValue(Size); - Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc); - if (Type->isPointerType()) { - // Cast to pointer type. - auto CastExpr = BuildCStyleCastExpr( - SourceLocation(), Context.getTrivialTypeSourceInfo(Type, ELoc), - SourceLocation(), Init); - if (CastExpr.isInvalid()) - continue; - Init = CastExpr.get(); + case BO_LT: + case BO_GT: { + // 'min' reduction op - initializer is 'Largest representable number in + // the reduction list item type'. + // 'max' reduction op - initializer is 'Least representable number in + // the reduction list item type'. + if (Type->isIntegerType() || Type->isPointerType()) { + bool IsSigned = Type->hasSignedIntegerRepresentation(); + auto Size = Context.getTypeSize(Type); + QualType IntTy = + Context.getIntTypeForBitwidth(Size, /*Signed=*/IsSigned); + llvm::APInt InitValue = + (BOK != BO_LT) + ? IsSigned ? llvm::APInt::getSignedMinValue(Size) + : llvm::APInt::getMinValue(Size) + : IsSigned ? llvm::APInt::getSignedMaxValue(Size) + : llvm::APInt::getMaxValue(Size); + Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc); + if (Type->isPointerType()) { + // Cast to pointer type. + auto CastExpr = BuildCStyleCastExpr( + SourceLocation(), Context.getTrivialTypeSourceInfo(Type, ELoc), + SourceLocation(), Init); + if (CastExpr.isInvalid()) + continue; + Init = CastExpr.get(); + } + } else if (Type->isRealFloatingType()) { + llvm::APFloat InitValue = llvm::APFloat::getLargest( + Context.getFloatTypeSemantics(Type), BOK != BO_LT); + Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true, + Type, ELoc); } - } else if (Type->isRealFloatingType()) { - llvm::APFloat InitValue = llvm::APFloat::getLargest( - Context.getFloatTypeSemantics(Type), BOK != BO_LT); - Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true, - Type, ELoc); + break; + } + case BO_PtrMemD: + case BO_PtrMemI: + case BO_MulAssign: + case BO_Div: + case BO_Rem: + case BO_Sub: + case BO_Shl: + case BO_Shr: + case BO_LE: + case BO_GE: + case BO_EQ: + case BO_NE: + case BO_AndAssign: + case BO_XorAssign: + case BO_OrAssign: + case BO_Assign: + case BO_AddAssign: + case BO_SubAssign: + case BO_DivAssign: + case BO_RemAssign: + case BO_ShlAssign: + case BO_ShrAssign: + case BO_Comma: + llvm_unreachable("Unexpected reduction operation"); } - break; } - case BO_PtrMemD: - case BO_PtrMemI: - case BO_MulAssign: - case BO_Div: - case BO_Rem: - case BO_Sub: - case BO_Shl: - case BO_Shr: - case BO_LE: - case BO_GE: - case BO_EQ: - case BO_NE: - case BO_AndAssign: - case BO_XorAssign: - case BO_OrAssign: - case BO_Assign: - case BO_AddAssign: - case BO_SubAssign: - case BO_DivAssign: - case BO_RemAssign: - case BO_ShlAssign: - case BO_ShrAssign: - case BO_Comma: - llvm_unreachable("Unexpected reduction operation"); - } - if (Init) { + if (Init && DeclareReductionRef.isUnset()) { AddInitializerToDecl(RHSVD, Init, /*DirectInit=*/false, /*TypeMayContainAuto=*/false); - } else + } else if (!Init) ActOnUninitializedDecl(RHSVD, /*TypeMayContainAuto=*/false); - if (!RHSVD->hasInit()) { + if (RHSVD->isInvalidDecl()) + continue; + if (!RHSVD->hasInit() && DeclareReductionRef.isUnset()) { Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type << ReductionIdRange; - if (VD) { - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - } + bool IsDecl = + !VD || + VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; + Diag(D->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << D; 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); - if (ReductionOp.isUsable()) { - if (BOK != BO_LT && BOK != BO_GT) { - ReductionOp = - BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), - BO_Assign, LHSDRE, ReductionOp.get()); - } else { - auto *ConditionalOp = new (Context) ConditionalOperator( - ReductionOp.get(), SourceLocation(), LHSDRE, SourceLocation(), - RHSDRE, Type, VK_LValue, OK_Ordinary); - ReductionOp = - BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), - BO_Assign, LHSDRE, ConditionalOp); + ExprResult ReductionOp; + if (DeclareReductionRef.isUsable()) { + QualType RedTy = DeclareReductionRef.get()->getType(); + QualType PtrRedTy = Context.getPointerType(RedTy); + ExprResult LHS = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, LHSDRE); + ExprResult RHS = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, RHSDRE); + if (!BasePath.empty()) { + LHS = DefaultLvalueConversion(LHS.get()); + RHS = DefaultLvalueConversion(RHS.get()); + LHS = ImplicitCastExpr::Create(Context, PtrRedTy, + CK_UncheckedDerivedToBase, LHS.get(), + &BasePath, LHS.get()->getValueKind()); + RHS = ImplicitCastExpr::Create(Context, PtrRedTy, + CK_UncheckedDerivedToBase, RHS.get(), + &BasePath, RHS.get()->getValueKind()); } - ReductionOp = ActOnFinishFullExpr(ReductionOp.get()); + FunctionProtoType::ExtProtoInfo EPI; + QualType Params[] = {PtrRedTy, PtrRedTy}; + QualType FnTy = Context.getFunctionType(Context.VoidTy, Params, EPI); + auto *OVE = new (Context) OpaqueValueExpr( + ELoc, Context.getPointerType(FnTy), VK_RValue, OK_Ordinary, + DefaultLvalueConversion(DeclareReductionRef.get()).get()); + Expr *Args[] = {LHS.get(), RHS.get()}; + ReductionOp = new (Context) + CallExpr(Context, OVE, Args, Context.VoidTy, VK_RValue, ELoc); + } else { + ReductionOp = BuildBinOp(DSAStack->getCurScope(), + ReductionId.getLocStart(), BOK, LHSDRE, RHSDRE); + if (ReductionOp.isUsable()) { + if (BOK != BO_LT && BOK != BO_GT) { + ReductionOp = + BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), + BO_Assign, LHSDRE, ReductionOp.get()); + } else { + auto *ConditionalOp = new (Context) ConditionalOperator( + ReductionOp.get(), SourceLocation(), LHSDRE, SourceLocation(), + RHSDRE, Type, VK_LValue, OK_Ordinary); + ReductionOp = + BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), + BO_Assign, LHSDRE, ConditionalOp); + } + ReductionOp = ActOnFinishFullExpr(ReductionOp.get()); + } + if (ReductionOp.isInvalid()) + continue; } - if (ReductionOp.isInvalid()) - continue; - DSAStack->addDSA(VD, DE, OMPC_reduction); - Vars.push_back(RefExpr); + DeclRefExpr *Ref = nullptr; + Expr *VarsExpr = RefExpr->IgnoreParens(); + if (!VD && !CurContext->isDependentContext()) { + if (ASE || OASE) { + TransformExprToCaptures RebuildToCapture(*this, D); + VarsExpr = + RebuildToCapture.TransformExpr(RefExpr->IgnoreParens()).get(); + Ref = RebuildToCapture.getCapturedExpr(); + } else { + VarsExpr = Ref = + buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false); + } + if (!IsOpenMPCapturedDecl(D)) { + ExprCaptures.push_back(Ref->getDecl()); + if (Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>()) { + ExprResult RefRes = DefaultLvalueConversion(Ref); + if (!RefRes.isUsable()) + continue; + ExprResult PostUpdateRes = + BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, + SimpleRefExpr, RefRes.get()); + if (!PostUpdateRes.isUsable()) + continue; + ExprPostUpdates.push_back( + IgnoredValueConversions(PostUpdateRes.get()).get()); + } + } + } + DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref); + Vars.push_back(VarsExpr); Privates.push_back(PrivateDRE); LHSs.push_back(LHSDRE); RHSs.push_back(RHSDRE); @@ -7615,7 +9502,67 @@ OMPClause *Sema::ActOnOpenMPReductionClause( return OMPReductionClause::Create( Context, StartLoc, LParenLoc, ColonLoc, EndLoc, Vars, ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, Privates, - LHSs, RHSs, ReductionOps); + LHSs, RHSs, ReductionOps, buildPreInits(Context, ExprCaptures), + buildPostUpdate(*this, ExprPostUpdates)); +} + +bool Sema::CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind, + SourceLocation LinLoc) { + if ((!LangOpts.CPlusPlus && LinKind != OMPC_LINEAR_val) || + LinKind == OMPC_LINEAR_unknown) { + Diag(LinLoc, diag::err_omp_wrong_linear_modifier) << LangOpts.CPlusPlus; + return true; + } + return false; +} + +bool Sema::CheckOpenMPLinearDecl(ValueDecl *D, SourceLocation ELoc, + OpenMPLinearClauseKind LinKind, + QualType Type) { + auto *VD = dyn_cast_or_null<VarDecl>(D); + // A variable must not have an incomplete type or a reference type. + if (RequireCompleteType(ELoc, Type, diag::err_omp_linear_incomplete_type)) + return true; + if ((LinKind == OMPC_LINEAR_uval || LinKind == OMPC_LINEAR_ref) && + !Type->isReferenceType()) { + Diag(ELoc, diag::err_omp_wrong_linear_modifier_non_reference) + << Type << getOpenMPSimpleClauseTypeName(OMPC_linear, LinKind); + return true; + } + Type = Type.getNonReferenceType(); + + // A list item must not be const-qualified. + if (Type.isConstant(Context)) { + Diag(ELoc, diag::err_omp_const_variable) + << getOpenMPClauseName(OMPC_linear); + if (D) { + bool IsDecl = + !VD || + VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; + Diag(D->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << D; + } + return true; + } + + // A list item must be of integral or pointer type. + Type = Type.getUnqualifiedType().getCanonicalType(); + const auto *Ty = Type.getTypePtrOrNull(); + if (!Ty || (!Ty->isDependentType() && !Ty->isIntegralType(Context) && + !Ty->isPointerType())) { + Diag(ELoc, diag::err_omp_linear_expected_int_or_ptr) << Type; + if (D) { + bool IsDecl = + !VD || + VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; + Diag(D->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << D; + } + return true; + } + return false; } OMPClause *Sema::ActOnOpenMPLinearClause( @@ -7625,121 +9572,84 @@ OMPClause *Sema::ActOnOpenMPLinearClause( 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; + SmallVector<Decl *, 4> ExprCaptures; + SmallVector<Expr *, 4> ExprPostUpdates; + if (CheckOpenMPLinearModifier(LinKind, LinLoc)) LinKind = OMPC_LINEAR_val; - } for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP linear clause."); - if (isa<DependentScopeDeclRefExpr>(RefExpr)) { + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/false); + if (Res.second) { // It will be analyzed later. Vars.push_back(RefExpr); Privates.push_back(nullptr); Inits.push_back(nullptr); - continue; } - - // OpenMP [2.14.3.7, linear clause] - // A list item that appears in a linear clause is subject to the private - // clause semantics described in Section 2.14.3.3 on page 159 except as - // noted. In addition, the value of the new list item on each iteration - // of the associated loop(s) corresponds to the value of the original - // list item before entering the construct plus the logical number of - // the iteration times linear-step. - - SourceLocation ELoc = RefExpr->getExprLoc(); - // OpenMP [2.1, C/C++] - // A list item is a variable name. - // 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. - DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr); - if (!DE || !isa<VarDecl>(DE->getDecl())) { - Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); + ValueDecl *D = Res.first; + if (!D) continue; - } - VarDecl *VD = cast<VarDecl>(DE->getDecl()); + QualType Type = D->getType(); + auto *VD = dyn_cast<VarDecl>(D); // OpenMP [2.14.3.7, linear clause] // A list-item cannot appear in more than one linear clause. // A list-item that appears in a linear clause cannot appear in any // other data-sharing attribute clause. - DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false); + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false); if (DVar.RefExpr) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_linear); - ReportOriginalDSA(*this, DSAStack, VD, DVar); - continue; - } - - QualType QType = VD->getType(); - if (QType->isDependentType() || QType->isInstantiationDependentType()) { - // It will be analyzed later. - Vars.push_back(DE); - Privates.push_back(nullptr); - Inits.push_back(nullptr); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } - // A variable must not have an incomplete type or a reference type. - if (RequireCompleteType(ELoc, QType, - diag::err_omp_linear_incomplete_type)) { + if (CheckOpenMPLinearDecl(D, ELoc, LinKind, Type)) continue; - } - 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)) { - Diag(ELoc, diag::err_omp_const_variable) - << getOpenMPClauseName(OMPC_linear); - bool IsDecl = - VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - continue; - } - - // A list item must be of integral or pointer type. - QType = QType.getUnqualifiedType().getCanonicalType(); - const Type *Ty = QType.getTypePtrOrNull(); - if (!Ty || (!Ty->isDependentType() && !Ty->isIntegralType(Context) && - !Ty->isPointerType())) { - Diag(ELoc, diag::err_omp_linear_expected_int_or_ptr) << QType; - bool IsDecl = - VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - continue; - } + Type = Type.getNonReferenceType().getUnqualifiedType().getCanonicalType(); // 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()); + auto *Private = buildVarDecl(*this, ELoc, Type, D->getName(), + D->hasAttrs() ? &D->getAttrs() : nullptr); + auto *PrivateRef = buildDeclRefExpr(*this, Private, Type, ELoc); // Build var to save initial value. - VarDecl *Init = buildVarDecl(*this, ELoc, QType, ".linear.start"); + VarDecl *Init = buildVarDecl(*this, ELoc, Type, ".linear.start"); Expr *InitExpr; + DeclRefExpr *Ref = nullptr; + if (!VD && !CurContext->isDependentContext()) { + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false); + if (!IsOpenMPCapturedDecl(D)) { + ExprCaptures.push_back(Ref->getDecl()); + if (Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>()) { + ExprResult RefRes = DefaultLvalueConversion(Ref); + if (!RefRes.isUsable()) + continue; + ExprResult PostUpdateRes = + BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, + SimpleRefExpr, RefRes.get()); + if (!PostUpdateRes.isUsable()) + continue; + ExprPostUpdates.push_back( + IgnoredValueConversions(PostUpdateRes.get()).get()); + } + } + } if (LinKind == OMPC_LINEAR_uval) - InitExpr = VD->getInit(); + InitExpr = VD ? VD->getInit() : SimpleRefExpr; else - InitExpr = DE; + InitExpr = VD ? SimpleRefExpr : Ref; 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); + /*DirectInit=*/false, /*TypeMayContainAuto=*/false); + auto InitRef = buildDeclRefExpr(*this, Init, Type, ELoc); + + DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_linear, Ref); + Vars.push_back((VD || CurContext->isDependentContext()) + ? RefExpr->IgnoreParens() + : Ref); Privates.push_back(PrivateRef); Inits.push_back(InitRef); } @@ -7783,12 +9693,14 @@ OMPClause *Sema::ActOnOpenMPLinearClause( return OMPLinearClause::Create(Context, StartLoc, LParenLoc, LinKind, LinLoc, ColonLoc, EndLoc, Vars, Privates, Inits, - StepExpr, CalcStepExpr); + StepExpr, CalcStepExpr, + buildPreInits(Context, ExprCaptures), + buildPostUpdate(*this, ExprPostUpdates)); } static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, Expr *NumIterations, Sema &SemaRef, - Scope *S) { + Scope *S, DSAStackTy *Stack) { // Walk the vars and build update/final expressions for the CodeGen. SmallVector<Expr *, 8> Updates; SmallVector<Expr *, 8> Finals; @@ -7798,17 +9710,35 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, // If linear-step is not specified it is assumed to be 1. if (Step == nullptr) Step = SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get(); - else if (CalcStep) + else if (CalcStep) { 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()) { + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(SemaRef, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/false); + ValueDecl *D = Res.first; + if (Res.second || !D) { + Updates.push_back(nullptr); + Finals.push_back(nullptr); + HasErrors = true; + continue; + } + if (auto *CED = dyn_cast<OMPCapturedExprDecl>(D)) { + D = cast<MemberExpr>(CED->getInit()->IgnoreParenImpCasts()) + ->getMemberDecl(); + } + auto &&Info = Stack->isLoopControlVariable(D); Expr *InitExpr = *CurInit; // Build privatized reference to the current linear var. - auto DE = cast<DeclRefExpr>(RefExpr); + auto DE = cast<DeclRefExpr>(SimpleRefExpr); Expr *CapturedRef; if (LinKind == OMPC_LINEAR_uval) CapturedRef = cast<VarDecl>(DE->getDecl())->getInit(); @@ -7819,18 +9749,27 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, /*RefersToCapture=*/true); // Build update: Var = InitExpr + IV * Step - ExprResult Update = - BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), *CurPrivate, - InitExpr, IV, Step, /* Subtract */ false); + ExprResult Update; + if (!Info.first) { + Update = + BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), *CurPrivate, + InitExpr, IV, Step, /* Subtract */ false); + } else + Update = *CurPrivate; Update = SemaRef.ActOnFinishFullExpr(Update.get(), DE->getLocStart(), /*DiscardedValue=*/true); // Build final: Var = InitExpr + NumIterations * Step - ExprResult Final = - BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), CapturedRef, - InitExpr, NumIterations, Step, /* Subtract */ false); + ExprResult Final; + if (!Info.first) { + Final = BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), CapturedRef, + InitExpr, NumIterations, Step, + /* Subtract */ false); + } else + Final = *CurPrivate; Final = SemaRef.ActOnFinishFullExpr(Final.get(), DE->getLocStart(), /*DiscardedValue=*/true); + if (!Update.isUsable() || !Final.isUsable()) { Updates.push_back(nullptr); Finals.push_back(nullptr); @@ -7839,7 +9778,8 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, Updates.push_back(Update.get()); Finals.push_back(Final.get()); } - ++CurInit, ++CurPrivate; + ++CurInit; + ++CurPrivate; } Clause.setUpdates(Updates); Clause.setFinals(Finals); @@ -7852,52 +9792,55 @@ OMPClause *Sema::ActOnOpenMPAlignedClause( SmallVector<Expr *, 8> Vars; for (auto &RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP aligned clause."); - if (isa<DependentScopeDeclRefExpr>(RefExpr)) { + assert(RefExpr && "NULL expr in OpenMP linear clause."); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/false); + if (Res.second) { // It will be analyzed later. Vars.push_back(RefExpr); - continue; } - - SourceLocation ELoc = RefExpr->getExprLoc(); - // OpenMP [2.1, C/C++] - // A list item is a variable name. - DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr); - if (!DE || !isa<VarDecl>(DE->getDecl())) { - Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); + ValueDecl *D = Res.first; + if (!D) continue; - } - VarDecl *VD = cast<VarDecl>(DE->getDecl()); + QualType QType = D->getType(); + auto *VD = dyn_cast<VarDecl>(D); // OpenMP [2.8.1, simd construct, Restrictions] // The type of list items appearing in the aligned clause must be // array, pointer, reference to array, or reference to pointer. - QualType QType = VD->getType(); QType = QType.getNonReferenceType().getUnqualifiedType().getCanonicalType(); const Type *Ty = QType.getTypePtrOrNull(); - if (!Ty || (!Ty->isDependentType() && !Ty->isArrayType() && - !Ty->isPointerType())) { + if (!Ty || (!Ty->isArrayType() && !Ty->isPointerType())) { Diag(ELoc, diag::err_omp_aligned_expected_array_or_ptr) - << QType << getLangOpts().CPlusPlus << RefExpr->getSourceRange(); + << QType << getLangOpts().CPlusPlus << ERange; bool IsDecl = + !VD || VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), + Diag(D->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; + << D; continue; } // OpenMP [2.8.1, simd construct, Restrictions] // A list-item cannot appear in more than one aligned clause. - if (DeclRefExpr *PrevRef = DSAStack->addUniqueAligned(VD, DE)) { - Diag(ELoc, diag::err_omp_aligned_twice) << RefExpr->getSourceRange(); + if (Expr *PrevRef = DSAStack->addUniqueAligned(D, SimpleRefExpr)) { + Diag(ELoc, diag::err_omp_aligned_twice) << 0 << ERange; Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) << getOpenMPClauseName(OMPC_aligned); continue; } - Vars.push_back(DE); + DeclRefExpr *Ref = nullptr; + if (!VD && IsOpenMPCapturedDecl(D)) + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true); + Vars.push_back(DefaultFunctionArrayConversion( + (VD || !Ref) ? RefExpr->IgnoreParens() : Ref) + .get()); } // OpenMP [2.8.1, simd construct, Description] @@ -7945,7 +9888,8 @@ OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList, // A list item that appears in a copyin clause must be threadprivate. DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr); if (!DE || !isa<VarDecl>(DE->getDecl())) { - Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); + Diag(ELoc, diag::err_omp_expected_var_name_member_expr) + << 0 << RefExpr->getSourceRange(); continue; } @@ -8020,51 +9964,37 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, SmallVector<Expr *, 8> DstExprs; SmallVector<Expr *, 8> AssignmentOps; for (auto &RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP copyprivate clause."); - if (isa<DependentScopeDeclRefExpr>(RefExpr)) { + assert(RefExpr && "NULL expr in OpenMP linear clause."); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/false); + if (Res.second) { // It will be analyzed later. Vars.push_back(RefExpr); SrcExprs.push_back(nullptr); DstExprs.push_back(nullptr); AssignmentOps.push_back(nullptr); - continue; } - - SourceLocation ELoc = RefExpr->getExprLoc(); - // OpenMP [2.1, C/C++] - // A list item is a variable name. - // OpenMP [2.14.4.1, Restrictions, p.1] - // A list item that appears in a copyin clause must be threadprivate. - DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr); - if (!DE || !isa<VarDecl>(DE->getDecl())) { - Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); + ValueDecl *D = Res.first; + if (!D) continue; - } - - Decl *D = DE->getDecl(); - VarDecl *VD = cast<VarDecl>(D); - QualType Type = VD->getType(); - if (Type->isDependentType() || Type->isInstantiationDependentType()) { - // It will be analyzed later. - Vars.push_back(DE); - SrcExprs.push_back(nullptr); - DstExprs.push_back(nullptr); - AssignmentOps.push_back(nullptr); - continue; - } + QualType Type = D->getType(); + auto *VD = dyn_cast<VarDecl>(D); // OpenMP [2.14.4.2, Restrictions, p.2] // A list item that appears in a copyprivate clause may not appear in a // private or firstprivate clause on the single construct. - if (!DSAStack->isThreadPrivate(VD)) { - auto DVar = DSAStack->getTopDSA(VD, false); + if (!VD || !DSAStack->isThreadPrivate(VD)) { + auto DVar = DSAStack->getTopDSA(D, false); if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_copyprivate && DVar.RefExpr) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_copyprivate); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } @@ -8072,12 +10002,12 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, // All list items that appear in a copyprivate clause must be either // threadprivate or private in the enclosing context. if (DVar.CKind == OMPC_unknown) { - DVar = DSAStack->getImplicitDSA(VD, false); + DVar = DSAStack->getImplicitDSA(D, false); if (DVar.CKind == OMPC_shared) { Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseName(OMPC_copyprivate) << "threadprivate or private in the enclosing context"; - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } } @@ -8089,10 +10019,11 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, << getOpenMPClauseName(OMPC_copyprivate) << Type << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); bool IsDecl = + !VD || VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), + Diag(D->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; + << D; continue; } @@ -8103,27 +10034,29 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, Type = Context.getBaseElementType(Type.getNonReferenceType()) .getUnqualifiedType(); auto *SrcVD = - buildVarDecl(*this, DE->getLocStart(), Type, ".copyprivate.src", - VD->hasAttrs() ? &VD->getAttrs() : nullptr); - auto *PseudoSrcExpr = - buildDeclRefExpr(*this, SrcVD, Type, DE->getExprLoc()); + buildVarDecl(*this, RefExpr->getLocStart(), Type, ".copyprivate.src", + D->hasAttrs() ? &D->getAttrs() : nullptr); + auto *PseudoSrcExpr = buildDeclRefExpr(*this, SrcVD, Type, ELoc); auto *DstVD = - buildVarDecl(*this, DE->getLocStart(), Type, ".copyprivate.dst", - VD->hasAttrs() ? &VD->getAttrs() : nullptr); + buildVarDecl(*this, RefExpr->getLocStart(), Type, ".copyprivate.dst", + D->hasAttrs() ? &D->getAttrs() : nullptr); auto *PseudoDstExpr = - buildDeclRefExpr(*this, DstVD, Type, DE->getExprLoc()); - auto AssignmentOp = BuildBinOp(/*S=*/nullptr, DE->getExprLoc(), BO_Assign, + buildDeclRefExpr(*this, DstVD, Type, ELoc); + auto AssignmentOp = BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, PseudoDstExpr, PseudoSrcExpr); if (AssignmentOp.isInvalid()) continue; - AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), DE->getExprLoc(), + AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), ELoc, /*DiscardedValue=*/true); if (AssignmentOp.isInvalid()) continue; // No need to mark vars as copyprivate, they are already threadprivate or // implicitly private. - Vars.push_back(DE); + assert(VD || IsOpenMPCapturedDecl(D)); + Vars.push_back( + VD ? RefExpr->IgnoreParens() + : buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false)); SrcExprs.push_back(PseudoSrcExpr); DstExprs.push_back(PseudoDstExpr); AssignmentOps.push_back(AssignmentOp.get()); @@ -8168,6 +10101,7 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, return nullptr; } SmallVector<Expr *, 8> Vars; + DSAStackTy::OperatorOffsetTy OpsOffs; llvm::APSInt DepCounter(/*BitWidth=*/32); llvm::APSInt TotalDepCount(/*BitWidth=*/32); if (DepKind == OMPC_DEPEND_sink) { @@ -8180,8 +10114,7 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, DSAStack->getParentOrderedRegionParam()) { for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP shared clause."); - if (isa<DependentScopeDeclRefExpr>(RefExpr) || - (DepKind == OMPC_DEPEND_sink && CurContext->isDependentContext())) { + if (isa<DependentScopeDeclRefExpr>(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); continue; @@ -8203,61 +10136,66 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, // 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. + if (CurContext->isDependentContext()) { + // It will be analyzed later. + Vars.push_back(RefExpr); + continue; + } 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( + OverloadedOperatorKind OOK = OO_None; + SourceLocation OOLoc; + Expr *LHS = SimpleExpr; + Expr *RHS = nullptr; + 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(); + } + SourceLocation ELoc; + SourceRange ERange; + auto Res = getPrivateItem(*this, LHS, ELoc, ERange, + /*AllowArraySection=*/false); + if (Res.second) { + // It will be analyzed later. + Vars.push_back(RefExpr); + } + ValueDecl *D = Res.first; + if (!D) + continue; + + if (OOK != OO_Plus && OOK != OO_Minus && (RHS || OOK != OO_None)) { + Diag(OOLoc, diag::err_omp_depend_sink_expected_plus_minus); + continue; + } + if (RHS) { + ExprResult RHSRes = VerifyPositiveIntegerConstantInClause( RHS, OMPC_depend, /*StrictlyPositive=*/false); - if (Res.isInvalid()) + if (RHSRes.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) + DepCounter != DSAStack->isParentLoopControlVariable(D).first) { + Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration) << DSAStack->getParentLoopControlVariable( - DepCounter.getZExtValue()); + DepCounter.getZExtValue()); continue; } + OpsOffs.push_back({RHS, OOK}); } else { // OpenMP [2.11.1.1, Restrictions, p.3] // A variable that is part of another variable (such as a field of a @@ -8268,14 +10206,17 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, 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(); + (ASE && + !ASE->getBase() + ->getType() + .getNonReferenceType() + ->isPointerType() && + !ASE->getBase()->getType().getNonReferenceType()->isArrayType())) { + Diag(ELoc, diag::err_omp_expected_var_name_member_expr_or_array_item) + << 0 << RefExpr->getSourceRange(); continue; } } - Vars.push_back(RefExpr->IgnoreParenImpCasts()); } @@ -8289,9 +10230,11 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, Vars.empty()) return nullptr; } - - return OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc, DepKind, - DepLoc, ColonLoc, Vars); + auto *C = OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc, + DepKind, DepLoc, ColonLoc, Vars); + if (DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source) + DSAStack->addDoacrossDependClause(C, OpsOffs); + return C; } OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc, @@ -8366,125 +10309,969 @@ static bool CheckTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef, 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; +/// \brief Return true if it can be proven that the provided array expression +/// (array section or array subscript) does NOT specify the whole size of the +/// array whose base type is \a BaseQTy. +static bool CheckArrayExpressionDoesNotReferToWholeSize(Sema &SemaRef, + const Expr *E, + QualType BaseQTy) { + auto *OASE = dyn_cast<OMPArraySectionExpr>(E); + + // If this is an array subscript, it refers to the whole size if the size of + // the dimension is constant and equals 1. Also, an array section assumes the + // format of an array subscript if no colon is used. + if (isa<ArraySubscriptExpr>(E) || (OASE && OASE->getColonLoc().isInvalid())) { + if (auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr())) + return ATy->getSize().getSExtValue() != 1; + // Size can't be evaluated statically. + return false; + } - for (auto &RE : VarList) { - assert(RE && "Null expr in omp map"); - if (isa<DependentScopeDeclRefExpr>(RE)) { - // It will be analyzed later. - Vars.push_back(RE); + assert(OASE && "Expecting array section if not an array subscript."); + auto *LowerBound = OASE->getLowerBound(); + auto *Length = OASE->getLength(); + + // If there is a lower bound that does not evaluates to zero, we are not + // convering the whole dimension. + if (LowerBound) { + llvm::APSInt ConstLowerBound; + if (!LowerBound->EvaluateAsInt(ConstLowerBound, SemaRef.getASTContext())) + return false; // Can't get the integer value as a constant. + if (ConstLowerBound.getSExtValue()) + return true; + } + + // If we don't have a length we covering the whole dimension. + if (!Length) + return false; + + // If the base is a pointer, we don't have a way to get the size of the + // pointee. + if (BaseQTy->isPointerType()) + return false; + + // We can only check if the length is the same as the size of the dimension + // if we have a constant array. + auto *CATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr()); + if (!CATy) + return false; + + llvm::APSInt ConstLength; + if (!Length->EvaluateAsInt(ConstLength, SemaRef.getASTContext())) + return false; // Can't get the integer value as a constant. + + return CATy->getSize().getSExtValue() != ConstLength.getSExtValue(); +} + +// Return true if it can be proven that the provided array expression (array +// section or array subscript) does NOT specify a single element of the array +// whose base type is \a BaseQTy. +static bool CheckArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef, + const Expr *E, + QualType BaseQTy) { + auto *OASE = dyn_cast<OMPArraySectionExpr>(E); + + // An array subscript always refer to a single element. Also, an array section + // assumes the format of an array subscript if no colon is used. + if (isa<ArraySubscriptExpr>(E) || (OASE && OASE->getColonLoc().isInvalid())) + return false; + + assert(OASE && "Expecting array section if not an array subscript."); + auto *Length = OASE->getLength(); + + // If we don't have a length we have to check if the array has unitary size + // for this dimension. Also, we should always expect a length if the base type + // is pointer. + if (!Length) { + if (auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr())) + return ATy->getSize().getSExtValue() != 1; + // We cannot assume anything. + return false; + } + + // Check if the length evaluates to 1. + llvm::APSInt ConstLength; + if (!Length->EvaluateAsInt(ConstLength, SemaRef.getASTContext())) + return false; // Can't get the integer value as a constant. + + return ConstLength.getSExtValue() != 1; +} + +// Return the expression of the base of the mappable expression or null if it +// cannot be determined and do all the necessary checks to see if the expression +// is valid as a standalone mappable expression. In the process, record all the +// components of the expression. +static Expr *CheckMapClauseExpressionBase( + Sema &SemaRef, Expr *E, + OMPClauseMappableExprCommon::MappableExprComponentList &CurComponents, + OpenMPClauseKind CKind) { + SourceLocation ELoc = E->getExprLoc(); + SourceRange ERange = E->getSourceRange(); + + // The base of elements of list in a map clause have to be either: + // - a reference to variable or field. + // - a member expression. + // - an array expression. + // + // E.g. if we have the expression 'r.S.Arr[:12]', we want to retrieve the + // reference to 'r'. + // + // If we have: + // + // struct SS { + // Bla S; + // foo() { + // #pragma omp target map (S.Arr[:12]); + // } + // } + // + // We want to retrieve the member expression 'this->S'; + + Expr *RelevantExpr = nullptr; + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.2] + // If a list item is an array section, it must specify contiguous storage. + // + // For this restriction it is sufficient that we make sure only references + // to variables or fields and array expressions, and that no array sections + // exist except in the rightmost expression (unless they cover the whole + // dimension of the array). E.g. these would be invalid: + // + // r.ArrS[3:5].Arr[6:7] + // + // r.ArrS[3:5].x + // + // but these would be valid: + // r.ArrS[3].Arr[6:7] + // + // r.ArrS[3].x + + bool AllowUnitySizeArraySection = true; + bool AllowWholeSizeArraySection = true; + + while (!RelevantExpr) { + E = E->IgnoreParenImpCasts(); + + if (auto *CurE = dyn_cast<DeclRefExpr>(E)) { + if (!isa<VarDecl>(CurE->getDecl())) + break; + + RelevantExpr = CurE; + + // If we got a reference to a declaration, we should not expect any array + // section before that. + AllowUnitySizeArraySection = false; + AllowWholeSizeArraySection = false; + + // Record the component. + CurComponents.push_back(OMPClauseMappableExprCommon::MappableComponent( + CurE, CurE->getDecl())); + continue; + } + + if (auto *CurE = dyn_cast<MemberExpr>(E)) { + auto *BaseE = CurE->getBase()->IgnoreParenImpCasts(); + + if (isa<CXXThisExpr>(BaseE)) + // We found a base expression: this->Val. + RelevantExpr = CurE; + else + E = BaseE; + + if (!isa<FieldDecl>(CurE->getMemberDecl())) { + SemaRef.Diag(ELoc, diag::err_omp_expected_access_to_data_field) + << CurE->getSourceRange(); + break; + } + + auto *FD = cast<FieldDecl>(CurE->getMemberDecl()); + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.3] + // A bit-field cannot appear in a map clause. + // + if (FD->isBitField()) { + SemaRef.Diag(ELoc, diag::err_omp_bit_fields_forbidden_in_clause) + << CurE->getSourceRange() << getOpenMPClauseName(CKind); + break; + } + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1] + // If the type of a list item is a reference to a type T then the type + // will be considered to be T for all purposes of this clause. + QualType CurType = BaseE->getType().getNonReferenceType(); + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.2] + // A list item cannot be a variable that is a member of a structure with + // a union type. + // + if (auto *RT = CurType->getAs<RecordType>()) + if (RT->isUnionType()) { + SemaRef.Diag(ELoc, diag::err_omp_union_type_not_allowed) + << CurE->getSourceRange(); + break; + } + + // If we got a member expression, we should not expect any array section + // before that: + // + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.7] + // If a list item is an element of a structure, only the rightmost symbol + // of the variable reference can be an array section. + // + AllowUnitySizeArraySection = false; + AllowWholeSizeArraySection = false; + + // Record the component. + CurComponents.push_back( + OMPClauseMappableExprCommon::MappableComponent(CurE, FD)); + continue; + } + + if (auto *CurE = dyn_cast<ArraySubscriptExpr>(E)) { + E = CurE->getBase()->IgnoreParenImpCasts(); + + if (!E->getType()->isAnyPointerType() && !E->getType()->isArrayType()) { + SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name) + << 0 << CurE->getSourceRange(); + break; + } + + // If we got an array subscript that express the whole dimension we + // can have any array expressions before. If it only expressing part of + // the dimension, we can only have unitary-size array expressions. + if (CheckArrayExpressionDoesNotReferToWholeSize(SemaRef, CurE, + E->getType())) + AllowWholeSizeArraySection = false; + + // Record the component - we don't have any declaration associated. + CurComponents.push_back( + OMPClauseMappableExprCommon::MappableComponent(CurE, nullptr)); + continue; + } + + if (auto *CurE = dyn_cast<OMPArraySectionExpr>(E)) { + E = CurE->getBase()->IgnoreParenImpCasts(); + + auto CurType = + OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType(); + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1] + // If the type of a list item is a reference to a type T then the type + // will be considered to be T for all purposes of this clause. + if (CurType->isReferenceType()) + CurType = CurType->getPointeeType(); + + bool IsPointer = CurType->isAnyPointerType(); + + if (!IsPointer && !CurType->isArrayType()) { + SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name) + << 0 << CurE->getSourceRange(); + break; + } + + bool NotWhole = + CheckArrayExpressionDoesNotReferToWholeSize(SemaRef, CurE, CurType); + bool NotUnity = + CheckArrayExpressionDoesNotReferToUnitySize(SemaRef, CurE, CurType); + + if (AllowWholeSizeArraySection && AllowUnitySizeArraySection) { + // Any array section is currently allowed. + // + // If this array section refers to the whole dimension we can still + // accept other array sections before this one, except if the base is a + // pointer. Otherwise, only unitary sections are accepted. + if (NotWhole || IsPointer) + AllowWholeSizeArraySection = false; + } else if ((AllowUnitySizeArraySection && NotUnity) || + (AllowWholeSizeArraySection && NotWhole)) { + // A unity or whole array section is not allowed and that is not + // compatible with the properties of the current array section. + SemaRef.Diag( + ELoc, diag::err_array_section_does_not_specify_contiguous_storage) + << CurE->getSourceRange(); + break; + } + + // Record the component - we don't have any declaration associated. + CurComponents.push_back( + OMPClauseMappableExprCommon::MappableComponent(CurE, nullptr)); continue; } + + // If nothing else worked, this is not a valid map clause expression. + SemaRef.Diag(ELoc, + diag::err_omp_expected_named_var_member_or_array_expression) + << ERange; + break; + } + + return RelevantExpr; +} + +// Return true if expression E associated with value VD has conflicts with other +// map information. +static bool CheckMapConflicts( + Sema &SemaRef, DSAStackTy *DSAS, ValueDecl *VD, Expr *E, + bool CurrentRegionOnly, + OMPClauseMappableExprCommon::MappableExprComponentListRef CurComponents, + OpenMPClauseKind CKind) { + assert(VD && E); + SourceLocation ELoc = E->getExprLoc(); + SourceRange ERange = E->getSourceRange(); + + // In order to easily check the conflicts we need to match each component of + // the expression under test with the components of the expressions that are + // already in the stack. + + assert(!CurComponents.empty() && "Map clause expression with no components!"); + assert(CurComponents.back().getAssociatedDeclaration() == VD && + "Map clause expression with unexpected base!"); + + // Variables to help detecting enclosing problems in data environment nests. + bool IsEnclosedByDataEnvironmentExpr = false; + const Expr *EnclosingExpr = nullptr; + + bool FoundError = DSAS->checkMappableExprComponentListsForDecl( + VD, CurrentRegionOnly, + [&](OMPClauseMappableExprCommon::MappableExprComponentListRef + StackComponents) -> bool { + + assert(!StackComponents.empty() && + "Map clause expression with no components!"); + assert(StackComponents.back().getAssociatedDeclaration() == VD && + "Map clause expression with unexpected base!"); + + // The whole expression in the stack. + auto *RE = StackComponents.front().getAssociatedExpression(); + + // Expressions must start from the same base. Here we detect at which + // point both expressions diverge from each other and see if we can + // detect if the memory referred to both expressions is contiguous and + // do not overlap. + auto CI = CurComponents.rbegin(); + auto CE = CurComponents.rend(); + auto SI = StackComponents.rbegin(); + auto SE = StackComponents.rend(); + for (; CI != CE && SI != SE; ++CI, ++SI) { + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.3] + // At most one list item can be an array item derived from a given + // variable in map clauses of the same construct. + if (CurrentRegionOnly && + (isa<ArraySubscriptExpr>(CI->getAssociatedExpression()) || + isa<OMPArraySectionExpr>(CI->getAssociatedExpression())) && + (isa<ArraySubscriptExpr>(SI->getAssociatedExpression()) || + isa<OMPArraySectionExpr>(SI->getAssociatedExpression()))) { + SemaRef.Diag(CI->getAssociatedExpression()->getExprLoc(), + diag::err_omp_multiple_array_items_in_map_clause) + << CI->getAssociatedExpression()->getSourceRange(); + SemaRef.Diag(SI->getAssociatedExpression()->getExprLoc(), + diag::note_used_here) + << SI->getAssociatedExpression()->getSourceRange(); + return true; + } + + // Do both expressions have the same kind? + if (CI->getAssociatedExpression()->getStmtClass() != + SI->getAssociatedExpression()->getStmtClass()) + break; + + // Are we dealing with different variables/fields? + if (CI->getAssociatedDeclaration() != SI->getAssociatedDeclaration()) + break; + } + // Check if the extra components of the expressions in the enclosing + // data environment are redundant for the current base declaration. + // If they are, the maps completely overlap, which is legal. + for (; SI != SE; ++SI) { + QualType Type; + if (auto *ASE = + dyn_cast<ArraySubscriptExpr>(SI->getAssociatedExpression())) { + Type = ASE->getBase()->IgnoreParenImpCasts()->getType(); + } else if (auto *OASE = + dyn_cast<OMPArraySectionExpr>(SI->getAssociatedExpression())) { + auto *E = OASE->getBase()->IgnoreParenImpCasts(); + Type = + OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType(); + } + if (Type.isNull() || Type->isAnyPointerType() || + CheckArrayExpressionDoesNotReferToWholeSize( + SemaRef, SI->getAssociatedExpression(), Type)) + break; + } + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.4] + // List items of map clauses in the same construct must not share + // original storage. + // + // If the expressions are exactly the same or one is a subset of the + // other, it means they are sharing storage. + if (CI == CE && SI == SE) { + if (CurrentRegionOnly) { + if (CKind == OMPC_map) + SemaRef.Diag(ELoc, diag::err_omp_map_shared_storage) << ERange; + else { + assert(CKind == OMPC_to || CKind == OMPC_from); + SemaRef.Diag(ELoc, diag::err_omp_once_referenced_in_target_update) + << ERange; + } + SemaRef.Diag(RE->getExprLoc(), diag::note_used_here) + << RE->getSourceRange(); + return true; + } else { + // If we find the same expression in the enclosing data environment, + // that is legal. + IsEnclosedByDataEnvironmentExpr = true; + return false; + } + } + + QualType DerivedType = + std::prev(CI)->getAssociatedDeclaration()->getType(); + SourceLocation DerivedLoc = + std::prev(CI)->getAssociatedExpression()->getExprLoc(); + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1] + // If the type of a list item is a reference to a type T then the type + // will be considered to be T for all purposes of this clause. + DerivedType = DerivedType.getNonReferenceType(); + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.1] + // A variable for which the type is pointer and an array section + // derived from that variable must not appear as list items of map + // clauses of the same construct. + // + // Also, cover one of the cases in: + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.5] + // If any part of the original storage of a list item has corresponding + // storage in the device data environment, all of the original storage + // must have corresponding storage in the device data environment. + // + if (DerivedType->isAnyPointerType()) { + if (CI == CE || SI == SE) { + SemaRef.Diag( + DerivedLoc, + diag::err_omp_pointer_mapped_along_with_derived_section) + << DerivedLoc; + } else { + assert(CI != CE && SI != SE); + SemaRef.Diag(DerivedLoc, diag::err_omp_same_pointer_derreferenced) + << DerivedLoc; + } + SemaRef.Diag(RE->getExprLoc(), diag::note_used_here) + << RE->getSourceRange(); + return true; + } + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.4] + // List items of map clauses in the same construct must not share + // original storage. + // + // An expression is a subset of the other. + if (CurrentRegionOnly && (CI == CE || SI == SE)) { + if (CKind == OMPC_map) + SemaRef.Diag(ELoc, diag::err_omp_map_shared_storage) << ERange; + else { + assert(CKind == OMPC_to || CKind == OMPC_from); + SemaRef.Diag(ELoc, diag::err_omp_once_referenced_in_target_update) + << ERange; + } + SemaRef.Diag(RE->getExprLoc(), diag::note_used_here) + << RE->getSourceRange(); + return true; + } + + // The current expression uses the same base as other expression in the + // data environment but does not contain it completely. + if (!CurrentRegionOnly && SI != SE) + EnclosingExpr = RE; + + // The current expression is a subset of the expression in the data + // environment. + IsEnclosedByDataEnvironmentExpr |= + (!CurrentRegionOnly && CI != CE && SI == SE); + + return false; + }); + + if (CurrentRegionOnly) + return FoundError; + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.5] + // If any part of the original storage of a list item has corresponding + // storage in the device data environment, all of the original storage must + // have corresponding storage in the device data environment. + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.6] + // If a list item is an element of a structure, and a different element of + // the structure has a corresponding list item in the device data environment + // prior to a task encountering the construct associated with the map clause, + // then the list item must also have a corresponding list item in the device + // data environment prior to the task encountering the construct. + // + if (EnclosingExpr && !IsEnclosedByDataEnvironmentExpr) { + SemaRef.Diag(ELoc, + diag::err_omp_original_storage_is_shared_and_does_not_contain) + << ERange; + SemaRef.Diag(EnclosingExpr->getExprLoc(), diag::note_used_here) + << EnclosingExpr->getSourceRange(); + return true; + } + + return FoundError; +} + +namespace { +// Utility struct that gathers all the related lists associated with a mappable +// expression. +struct MappableVarListInfo final { + // The list of expressions. + ArrayRef<Expr *> VarList; + // The list of processed expressions. + SmallVector<Expr *, 16> ProcessedVarList; + // The mappble components for each expression. + OMPClauseMappableExprCommon::MappableExprComponentLists VarComponents; + // The base declaration of the variable. + SmallVector<ValueDecl *, 16> VarBaseDeclarations; + + MappableVarListInfo(ArrayRef<Expr *> VarList) : VarList(VarList) { + // We have a list of components and base declarations for each entry in the + // variable list. + VarComponents.reserve(VarList.size()); + VarBaseDeclarations.reserve(VarList.size()); + } +}; +} + +// Check the validity of the provided variable list for the provided clause kind +// \a CKind. In the check process the valid expressions, and mappable expression +// components and variables are extracted and used to fill \a Vars, +// \a ClauseComponents, and \a ClauseBaseDeclarations. \a MapType and +// \a IsMapTypeImplicit are expected to be valid if the clause kind is 'map'. +static void +checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, + OpenMPClauseKind CKind, MappableVarListInfo &MVLI, + SourceLocation StartLoc, + OpenMPMapClauseKind MapType = OMPC_MAP_unknown, + bool IsMapTypeImplicit = false) { + // We only expect mappable expressions in 'to', 'from', and 'map' clauses. + assert((CKind == OMPC_map || CKind == OMPC_to || CKind == OMPC_from) && + "Unexpected clause kind with mappable expressions!"); + + // Keep track of the mappable components and base declarations in this clause. + // Each entry in the list is going to have a list of components associated. We + // record each set of the components so that we can build the clause later on. + // In the end we should have the same amount of declarations and component + // lists. + + for (auto &RE : MVLI.VarList) { + assert(RE && "Null expr in omp to/from/map clause"); SourceLocation ELoc = RE->getExprLoc(); - // 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 map clause. auto *VE = RE->IgnoreParenLValueCasts(); if (VE->isValueDependent() || VE->isTypeDependent() || VE->isInstantiationDependent() || VE->containsUnexpandedParameterPack()) { - // It will be analyzed later. - Vars.push_back(RE); + // We can only analyze this information once the missing information is + // resolved. + MVLI.ProcessedVarList.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) - << RE->getSourceRange(); + + if (!RE->IgnoreParenImpCasts()->isLValue()) { + SemaRef.Diag(ELoc, + diag::err_omp_expected_named_var_member_or_array_expression) + << RE->getSourceRange(); continue; } - 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); + OMPClauseMappableExprCommon::MappableExprComponentList CurComponents; + ValueDecl *CurDeclaration = nullptr; - // OpenMP [2.14.5, Restrictions, p.8] + // Obtain the array or member expression bases if required. Also, fill the + // components array with all the components identified in the process. + auto *BE = + CheckMapClauseExpressionBase(SemaRef, SimpleExpr, CurComponents, CKind); + if (!BE) + continue; + + assert(!CurComponents.empty() && + "Invalid mappable expression information."); + + // For the following checks, we rely on the base declaration which is + // expected to be associated with the last component. The declaration is + // expected to be a variable or a field (if 'this' is being mapped). + CurDeclaration = CurComponents.back().getAssociatedDeclaration(); + assert(CurDeclaration && "Null decl on map clause."); + assert( + CurDeclaration->isCanonicalDecl() && + "Expecting components to have associated only canonical declarations."); + + auto *VD = dyn_cast<VarDecl>(CurDeclaration); + auto *FD = dyn_cast<FieldDecl>(CurDeclaration); + + assert((VD || FD) && "Only variables or fields are expected here!"); + (void)FD; + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.10] // 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); + // OpenMP 4.5 [2.10.5, target update Construct] + // threadprivate variables cannot appear in a from clause. + if (VD && DSAS->isThreadPrivate(VD)) { + auto DVar = DSAS->getTopDSA(VD, false); + SemaRef.Diag(ELoc, diag::err_omp_threadprivate_in_clause) + << getOpenMPClauseName(CKind); + ReportOriginalDSA(SemaRef, DSAS, 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(); + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.9] + // A list item cannot appear in both a map clause and a data-sharing + // attribute clause on the same construct. + + // Check conflicts with other map clause expressions. We check the conflicts + // with the current construct separately from the enclosing data + // environment, because the restrictions are different. We only have to + // check conflicts across regions for the map clauses. + if (CheckMapConflicts(SemaRef, DSAS, CurDeclaration, SimpleExpr, + /*CurrentRegionOnly=*/true, CurComponents, CKind)) + break; + if (CKind == OMPC_map && + CheckMapConflicts(SemaRef, DSAS, CurDeclaration, SimpleExpr, + /*CurrentRegionOnly=*/false, CurComponents, CKind)) + break; + + // OpenMP 4.5 [2.10.5, target update Construct] + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1] + // If the type of a list item is a reference to a type T then the type will + // be considered to be T for all purposes of this clause. + QualType Type = CurDeclaration->getType().getNonReferenceType(); + + // OpenMP 4.5 [2.10.5, target update Construct, Restrictions, p.4] + // A list item in a to or from clause must have a mappable type. + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.9] + // A list item must have a mappable type. + if (!CheckTypeMappable(VE->getExprLoc(), VE->getSourceRange(), SemaRef, + DSAS, Type)) continue; + + if (CKind == OMPC_map) { + // target enter data + // OpenMP [2.10.2, Restrictions, p. 99] + // A map-type must be specified in all map clauses and must be either + // to or alloc. + OpenMPDirectiveKind DKind = DSAS->getCurrentDirective(); + if (DKind == OMPD_target_enter_data && + !(MapType == OMPC_MAP_to || MapType == OMPC_MAP_alloc)) { + SemaRef.Diag(StartLoc, diag::err_omp_invalid_map_type_for_directive) + << (IsMapTypeImplicit ? 1 : 0) + << getOpenMPSimpleClauseTypeName(OMPC_map, MapType) + << getOpenMPDirectiveName(DKind); + continue; + } + + // target exit_data + // OpenMP [2.10.3, Restrictions, p. 102] + // A map-type must be specified in all map clauses and must be either + // from, release, or delete. + if (DKind == OMPD_target_exit_data && + !(MapType == OMPC_MAP_from || MapType == OMPC_MAP_release || + MapType == OMPC_MAP_delete)) { + SemaRef.Diag(StartLoc, diag::err_omp_invalid_map_type_for_directive) + << (IsMapTypeImplicit ? 1 : 0) + << getOpenMPSimpleClauseTypeName(OMPC_map, MapType) + << getOpenMPDirectiveName(DKind); + continue; + } + + // OpenMP 4.5 [2.15.5.1, Restrictions, p.3] + // A list item cannot appear in both a map clause and a data-sharing + // attribute clause on the same construct + if (DKind == OMPD_target && VD) { + auto DVar = DSAS->getTopDSA(VD, false); + if (isOpenMPPrivate(DVar.CKind)) { + SemaRef.Diag(ELoc, diag::err_omp_variable_in_map_and_dsa) + << getOpenMPClauseName(DVar.CKind) + << getOpenMPDirectiveName(DSAS->getCurrentDirective()); + ReportOriginalDSA(SemaRef, DSAS, CurDeclaration, DVar); + 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; + // Save the current expression. + MVLI.ProcessedVarList.push_back(RE); + + // Store the components in the stack so that they can be used to check + // against other clauses later on. + DSAS->addMappableExpressionComponents(CurDeclaration, CurComponents); + + // Save the components and declaration to create the clause. For purposes of + // the clause creation, any component list that has has base 'this' uses + // null as base declaration. + MVLI.VarComponents.resize(MVLI.VarComponents.size() + 1); + MVLI.VarComponents.back().append(CurComponents.begin(), + CurComponents.end()); + MVLI.VarBaseDeclarations.push_back(isa<MemberExpr>(BE) ? nullptr + : CurDeclaration); + } +} + +OMPClause * +Sema::ActOnOpenMPMapClause(OpenMPMapClauseKind MapTypeModifier, + OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, + SourceLocation MapLoc, SourceLocation ColonLoc, + ArrayRef<Expr *> VarList, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) { + MappableVarListInfo MVLI(VarList); + checkMappableExpressionList(*this, DSAStack, OMPC_map, MVLI, StartLoc, + MapType, IsMapTypeImplicit); + + // We need to produce a map clause even if we don't have variables so that + // other diagnostics related with non-existing map clauses are accurate. + return OMPMapClause::Create(Context, StartLoc, LParenLoc, EndLoc, + MVLI.ProcessedVarList, MVLI.VarBaseDeclarations, + MVLI.VarComponents, MapTypeModifier, MapType, + IsMapTypeImplicit, MapLoc); +} + +QualType Sema::ActOnOpenMPDeclareReductionType(SourceLocation TyLoc, + TypeResult ParsedType) { + assert(ParsedType.isUsable()); + + QualType ReductionType = GetTypeFromParser(ParsedType.get()); + if (ReductionType.isNull()) + return QualType(); + + // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions, C\C++ + // A type name in a declare reduction directive cannot be a function type, an + // array type, a reference type, or a type qualified with const, volatile or + // restrict. + if (ReductionType.hasQualifiers()) { + Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 0; + return QualType(); + } + + if (ReductionType->isFunctionType()) { + Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 1; + return QualType(); + } + if (ReductionType->isReferenceType()) { + Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 2; + return QualType(); + } + if (ReductionType->isArrayType()) { + Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 3; + return QualType(); + } + return ReductionType; +} + +Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveStart( + Scope *S, DeclContext *DC, DeclarationName Name, + ArrayRef<std::pair<QualType, SourceLocation>> ReductionTypes, + AccessSpecifier AS, Decl *PrevDeclInScope) { + SmallVector<Decl *, 8> Decls; + Decls.reserve(ReductionTypes.size()); + + LookupResult Lookup(*this, Name, SourceLocation(), LookupOMPReductionName, + ForRedeclaration); + // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions + // A reduction-identifier may not be re-declared in the current scope for the + // same type or for a type that is compatible according to the base language + // rules. + llvm::DenseMap<QualType, SourceLocation> PreviousRedeclTypes; + OMPDeclareReductionDecl *PrevDRD = nullptr; + bool InCompoundScope = true; + if (S != nullptr) { + // Find previous declaration with the same name not referenced in other + // declarations. + FunctionScopeInfo *ParentFn = getEnclosingFunction(); + InCompoundScope = + (ParentFn != nullptr) && !ParentFn->CompoundScopes.empty(); + LookupName(Lookup, S); + FilterLookupForScope(Lookup, DC, S, /*ConsiderLinkage=*/false, + /*AllowInlineNamespace=*/false); + llvm::DenseMap<OMPDeclareReductionDecl *, bool> UsedAsPrevious; + auto Filter = Lookup.makeFilter(); + while (Filter.hasNext()) { + auto *PrevDecl = cast<OMPDeclareReductionDecl>(Filter.next()); + if (InCompoundScope) { + auto I = UsedAsPrevious.find(PrevDecl); + if (I == UsedAsPrevious.end()) + UsedAsPrevious[PrevDecl] = false; + if (auto *D = PrevDecl->getPrevDeclInScope()) + UsedAsPrevious[D] = true; + } + PreviousRedeclTypes[PrevDecl->getType().getCanonicalType()] = + PrevDecl->getLocation(); + } + Filter.done(); + if (InCompoundScope) { + for (auto &PrevData : UsedAsPrevious) { + if (!PrevData.second) { + PrevDRD = PrevData.first; + break; + } + } } + } else if (PrevDeclInScope != nullptr) { + auto *PrevDRDInScope = PrevDRD = + cast<OMPDeclareReductionDecl>(PrevDeclInScope); + do { + PreviousRedeclTypes[PrevDRDInScope->getType().getCanonicalType()] = + PrevDRDInScope->getLocation(); + PrevDRDInScope = PrevDRDInScope->getPrevDeclInScope(); + } while (PrevDRDInScope != nullptr); + } + for (auto &TyData : ReductionTypes) { + auto I = PreviousRedeclTypes.find(TyData.first.getCanonicalType()); + bool Invalid = false; + if (I != PreviousRedeclTypes.end()) { + Diag(TyData.second, diag::err_omp_declare_reduction_redefinition) + << TyData.first; + Diag(I->second, diag::note_previous_definition); + Invalid = true; + } + PreviousRedeclTypes[TyData.first.getCanonicalType()] = TyData.second; + auto *DRD = OMPDeclareReductionDecl::Create(Context, DC, TyData.second, + Name, TyData.first, PrevDRD); + DC->addDecl(DRD); + DRD->setAccess(AS); + Decls.push_back(DRD); + if (Invalid) + DRD->setInvalidDecl(); + else + PrevDRD = DRD; + } - // 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; + return DeclGroupPtrTy::make( + DeclGroupRef::Create(Context, Decls.begin(), Decls.size())); +} + +void Sema::ActOnOpenMPDeclareReductionCombinerStart(Scope *S, Decl *D) { + auto *DRD = cast<OMPDeclareReductionDecl>(D); + + // Enter new function scope. + PushFunctionScope(); + getCurFunction()->setHasBranchProtectedScope(); + getCurFunction()->setHasOMPDeclareReductionCombiner(); + + if (S != nullptr) + PushDeclContext(S, DRD); + else + CurContext = DRD; + + PushExpressionEvaluationContext(PotentiallyEvaluated); - Vars.push_back(RE); - MI.RefExpr = RE; - DSAStack->addMapInfoForVar(VD, MI); + QualType ReductionType = DRD->getType(); + // Create 'T* omp_parm;T omp_in;'. All references to 'omp_in' will + // be replaced by '*omp_parm' during codegen. This required because 'omp_in' + // uses semantics of argument handles by value, but it should be passed by + // reference. C lang does not support references, so pass all parameters as + // pointers. + // Create 'T omp_in;' variable. + auto *OmpInParm = + buildVarDecl(*this, D->getLocation(), ReductionType, "omp_in"); + // Create 'T* omp_parm;T omp_out;'. All references to 'omp_out' will + // be replaced by '*omp_parm' during codegen. This required because 'omp_out' + // uses semantics of argument handles by value, but it should be passed by + // reference. C lang does not support references, so pass all parameters as + // pointers. + // Create 'T omp_out;' variable. + auto *OmpOutParm = + buildVarDecl(*this, D->getLocation(), ReductionType, "omp_out"); + if (S != nullptr) { + PushOnScopeChains(OmpInParm, S); + PushOnScopeChains(OmpOutParm, S); + } else { + DRD->addDecl(OmpInParm); + DRD->addDecl(OmpOutParm); } - if (Vars.empty()) - return nullptr; +} + +void Sema::ActOnOpenMPDeclareReductionCombinerEnd(Decl *D, Expr *Combiner) { + auto *DRD = cast<OMPDeclareReductionDecl>(D); + DiscardCleanupsInEvaluationContext(); + PopExpressionEvaluationContext(); + + PopDeclContext(); + PopFunctionScopeInfo(); + + if (Combiner != nullptr) + DRD->setCombiner(Combiner); + else + DRD->setInvalidDecl(); +} + +void Sema::ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D) { + auto *DRD = cast<OMPDeclareReductionDecl>(D); + + // Enter new function scope. + PushFunctionScope(); + getCurFunction()->setHasBranchProtectedScope(); + + if (S != nullptr) + PushDeclContext(S, DRD); + else + CurContext = DRD; + + PushExpressionEvaluationContext(PotentiallyEvaluated); + + QualType ReductionType = DRD->getType(); + // Create 'T* omp_parm;T omp_priv;'. All references to 'omp_priv' will + // be replaced by '*omp_parm' during codegen. This required because 'omp_priv' + // uses semantics of argument handles by value, but it should be passed by + // reference. C lang does not support references, so pass all parameters as + // pointers. + // Create 'T omp_priv;' variable. + auto *OmpPrivParm = + buildVarDecl(*this, D->getLocation(), ReductionType, "omp_priv"); + // Create 'T* omp_parm;T omp_orig;'. All references to 'omp_orig' will + // be replaced by '*omp_parm' during codegen. This required because 'omp_orig' + // uses semantics of argument handles by value, but it should be passed by + // reference. C lang does not support references, so pass all parameters as + // pointers. + // Create 'T omp_orig;' variable. + auto *OmpOrigParm = + buildVarDecl(*this, D->getLocation(), ReductionType, "omp_orig"); + if (S != nullptr) { + PushOnScopeChains(OmpPrivParm, S); + PushOnScopeChains(OmpOrigParm, S); + } else { + DRD->addDecl(OmpPrivParm); + DRD->addDecl(OmpOrigParm); + } +} + +void Sema::ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, + Expr *Initializer) { + auto *DRD = cast<OMPDeclareReductionDecl>(D); + DiscardCleanupsInEvaluationContext(); + PopExpressionEvaluationContext(); - return OMPMapClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars, - MapTypeModifier, MapType, MapLoc); + PopDeclContext(); + PopFunctionScopeInfo(); + + if (Initializer != nullptr) + DRD->setInitializer(Initializer); + else + DRD->setInvalidDecl(); +} + +Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveEnd( + Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid) { + for (auto *D : DeclReductions.get()) { + if (IsValid) { + auto *DRD = cast<OMPDeclareReductionDecl>(D); + if (S != nullptr) + PushOnScopeChains(DRD, S, /*AddToContext=*/false); + } else + D->setInvalidDecl(); + } + return DeclReductions; } OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams, @@ -8578,3 +11365,377 @@ OMPClause *Sema::ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc, OMPHintClause(HintExpr.get(), StartLoc, LParenLoc, EndLoc); } +OMPClause *Sema::ActOnOpenMPDistScheduleClause( + OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc, + SourceLocation EndLoc) { + if (Kind == OMPC_DIST_SCHEDULE_unknown) { + std::string Values; + Values += "'"; + Values += getOpenMPSimpleClauseTypeName(OMPC_dist_schedule, 0); + Values += "'"; + Diag(KindLoc, diag::err_omp_unexpected_clause_value) + << Values << getOpenMPClauseName(OMPC_dist_schedule); + return nullptr; + } + Expr *ValExpr = ChunkSize; + Stmt *HelperValStmt = nullptr; + if (ChunkSize) { + if (!ChunkSize->isValueDependent() && !ChunkSize->isTypeDependent() && + !ChunkSize->isInstantiationDependent() && + !ChunkSize->containsUnexpandedParameterPack()) { + SourceLocation ChunkSizeLoc = ChunkSize->getLocStart(); + ExprResult Val = + PerformOpenMPImplicitIntegerConversion(ChunkSizeLoc, ChunkSize); + if (Val.isInvalid()) + return nullptr; + + ValExpr = Val.get(); + + // OpenMP [2.7.1, Restrictions] + // chunk_size must be a loop invariant integer expression with a positive + // value. + llvm::APSInt Result; + if (ValExpr->isIntegerConstantExpr(Result, Context)) { + if (Result.isSigned() && !Result.isStrictlyPositive()) { + Diag(ChunkSizeLoc, diag::err_omp_negative_expression_in_clause) + << "dist_schedule" << ChunkSize->getSourceRange(); + return nullptr; + } + } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective()) && + !CurContext->isDependentContext()) { + llvm::MapVector<Expr *, DeclRefExpr *> Captures; + ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); + HelperValStmt = buildPreInits(Context, Captures); + } + } + } + + return new (Context) + OMPDistScheduleClause(StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc, + Kind, ValExpr, HelperValStmt); +} + +OMPClause *Sema::ActOnOpenMPDefaultmapClause( + OpenMPDefaultmapClauseModifier M, OpenMPDefaultmapClauseKind Kind, + SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation MLoc, + SourceLocation KindLoc, SourceLocation EndLoc) { + // OpenMP 4.5 only supports 'defaultmap(tofrom: scalar)' + if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom || + Kind != OMPC_DEFAULTMAP_scalar) { + std::string Value; + SourceLocation Loc; + Value += "'"; + if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom) { + Value += getOpenMPSimpleClauseTypeName(OMPC_defaultmap, + OMPC_DEFAULTMAP_MODIFIER_tofrom); + Loc = MLoc; + } else { + Value += getOpenMPSimpleClauseTypeName(OMPC_defaultmap, + OMPC_DEFAULTMAP_scalar); + Loc = KindLoc; + } + Value += "'"; + Diag(Loc, diag::err_omp_unexpected_clause_value) + << Value << getOpenMPClauseName(OMPC_defaultmap); + return nullptr; + } + + return new (Context) + OMPDefaultmapClause(StartLoc, LParenLoc, MLoc, KindLoc, EndLoc, Kind, M); +} + +bool Sema::ActOnStartOpenMPDeclareTargetDirective(SourceLocation Loc) { + DeclContext *CurLexicalContext = getCurLexicalContext(); + if (!CurLexicalContext->isFileContext() && + !CurLexicalContext->isExternCContext() && + !CurLexicalContext->isExternCXXContext()) { + Diag(Loc, diag::err_omp_region_not_file_context); + return false; + } + if (IsInOpenMPDeclareTargetContext) { + Diag(Loc, diag::err_omp_enclosed_declare_target); + return false; + } + + IsInOpenMPDeclareTargetContext = true; + return true; +} + +void Sema::ActOnFinishOpenMPDeclareTargetDirective() { + assert(IsInOpenMPDeclareTargetContext && + "Unexpected ActOnFinishOpenMPDeclareTargetDirective"); + + IsInOpenMPDeclareTargetContext = false; +} + +void +Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope, CXXScopeSpec &ScopeSpec, + const DeclarationNameInfo &Id, + OMPDeclareTargetDeclAttr::MapTypeTy MT, + NamedDeclSetType &SameDirectiveDecls) { + LookupResult Lookup(*this, Id, LookupOrdinaryName); + LookupParsedName(Lookup, CurScope, &ScopeSpec, true); + + if (Lookup.isAmbiguous()) + return; + Lookup.suppressDiagnostics(); + + if (!Lookup.isSingleResult()) { + if (TypoCorrection Corrected = + CorrectTypo(Id, LookupOrdinaryName, CurScope, nullptr, + llvm::make_unique<VarOrFuncDeclFilterCCC>(*this), + CTK_ErrorRecovery)) { + diagnoseTypo(Corrected, PDiag(diag::err_undeclared_var_use_suggest) + << Id.getName()); + checkDeclIsAllowedInOpenMPTarget(nullptr, Corrected.getCorrectionDecl()); + return; + } + + Diag(Id.getLoc(), diag::err_undeclared_var_use) << Id.getName(); + return; + } + + NamedDecl *ND = Lookup.getAsSingle<NamedDecl>(); + if (isa<VarDecl>(ND) || isa<FunctionDecl>(ND)) { + if (!SameDirectiveDecls.insert(cast<NamedDecl>(ND->getCanonicalDecl()))) + Diag(Id.getLoc(), diag::err_omp_declare_target_multiple) << Id.getName(); + + if (!ND->hasAttr<OMPDeclareTargetDeclAttr>()) { + Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit(Context, MT); + ND->addAttr(A); + if (ASTMutationListener *ML = Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPDeclareTarget(ND, A); + checkDeclIsAllowedInOpenMPTarget(nullptr, ND); + } else if (ND->getAttr<OMPDeclareTargetDeclAttr>()->getMapType() != MT) { + Diag(Id.getLoc(), diag::err_omp_declare_target_to_and_link) + << Id.getName(); + } + } else + Diag(Id.getLoc(), diag::err_omp_invalid_target_decl) << Id.getName(); +} + +static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR, + Sema &SemaRef, Decl *D) { + if (!D) + return; + Decl *LD = nullptr; + if (isa<TagDecl>(D)) { + LD = cast<TagDecl>(D)->getDefinition(); + } else if (isa<VarDecl>(D)) { + LD = cast<VarDecl>(D)->getDefinition(); + + // If this is an implicit variable that is legal and we do not need to do + // anything. + if (cast<VarDecl>(D)->isImplicit()) { + Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit( + SemaRef.Context, OMPDeclareTargetDeclAttr::MT_To); + D->addAttr(A); + if (ASTMutationListener *ML = SemaRef.Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPDeclareTarget(D, A); + return; + } + + } else if (isa<FunctionDecl>(D)) { + const FunctionDecl *FD = nullptr; + if (cast<FunctionDecl>(D)->hasBody(FD)) + LD = const_cast<FunctionDecl *>(FD); + + // If the definition is associated with the current declaration in the + // target region (it can be e.g. a lambda) that is legal and we do not need + // to do anything else. + if (LD == D) { + Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit( + SemaRef.Context, OMPDeclareTargetDeclAttr::MT_To); + D->addAttr(A); + if (ASTMutationListener *ML = SemaRef.Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPDeclareTarget(D, A); + return; + } + } + if (!LD) + LD = D; + if (LD && !LD->hasAttr<OMPDeclareTargetDeclAttr>() && + (isa<VarDecl>(LD) || isa<FunctionDecl>(LD))) { + // Outlined declaration is not declared target. + if (LD->isOutOfLine()) { + SemaRef.Diag(LD->getLocation(), diag::warn_omp_not_in_target_context); + SemaRef.Diag(SL, diag::note_used_here) << SR; + } else { + DeclContext *DC = LD->getDeclContext(); + while (DC) { + if (isa<FunctionDecl>(DC) && + cast<FunctionDecl>(DC)->hasAttr<OMPDeclareTargetDeclAttr>()) + break; + DC = DC->getParent(); + } + if (DC) + return; + + // Is not declared in target context. + SemaRef.Diag(LD->getLocation(), diag::warn_omp_not_in_target_context); + SemaRef.Diag(SL, diag::note_used_here) << SR; + } + // Mark decl as declared target to prevent further diagnostic. + Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit( + SemaRef.Context, OMPDeclareTargetDeclAttr::MT_To); + D->addAttr(A); + if (ASTMutationListener *ML = SemaRef.Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPDeclareTarget(D, A); + } +} + +static bool checkValueDeclInTarget(SourceLocation SL, SourceRange SR, + Sema &SemaRef, DSAStackTy *Stack, + ValueDecl *VD) { + if (VD->hasAttr<OMPDeclareTargetDeclAttr>()) + return true; + if (!CheckTypeMappable(SL, SR, SemaRef, Stack, VD->getType())) + return false; + return true; +} + +void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D) { + if (!D || D->isInvalidDecl()) + return; + SourceRange SR = E ? E->getSourceRange() : D->getSourceRange(); + SourceLocation SL = E ? E->getLocStart() : D->getLocation(); + // 2.10.6: threadprivate variable cannot appear in a declare target directive. + if (VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (DSAStack->isThreadPrivate(VD)) { + Diag(SL, diag::err_omp_threadprivate_in_target); + ReportOriginalDSA(*this, DSAStack, VD, DSAStack->getTopDSA(VD, false)); + return; + } + } + if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) { + // Problem if any with var declared with incomplete type will be reported + // as normal, so no need to check it here. + if ((E || !VD->getType()->isIncompleteType()) && + !checkValueDeclInTarget(SL, SR, *this, DSAStack, VD)) { + // Mark decl as declared target to prevent further diagnostic. + if (isa<VarDecl>(VD) || isa<FunctionDecl>(VD)) { + Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit( + Context, OMPDeclareTargetDeclAttr::MT_To); + VD->addAttr(A); + if (ASTMutationListener *ML = Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPDeclareTarget(VD, A); + } + return; + } + } + if (!E) { + // Checking declaration inside declare target region. + if (!D->hasAttr<OMPDeclareTargetDeclAttr>() && + (isa<VarDecl>(D) || isa<FunctionDecl>(D))) { + Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit( + Context, OMPDeclareTargetDeclAttr::MT_To); + D->addAttr(A); + if (ASTMutationListener *ML = Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPDeclareTarget(D, A); + } + return; + } + checkDeclInTargetContext(E->getExprLoc(), E->getSourceRange(), *this, D); +} + +OMPClause *Sema::ActOnOpenMPToClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + MappableVarListInfo MVLI(VarList); + checkMappableExpressionList(*this, DSAStack, OMPC_to, MVLI, StartLoc); + if (MVLI.ProcessedVarList.empty()) + return nullptr; + + return OMPToClause::Create(Context, StartLoc, LParenLoc, EndLoc, + MVLI.ProcessedVarList, MVLI.VarBaseDeclarations, + MVLI.VarComponents); +} + +OMPClause *Sema::ActOnOpenMPFromClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + MappableVarListInfo MVLI(VarList); + checkMappableExpressionList(*this, DSAStack, OMPC_from, MVLI, StartLoc); + if (MVLI.ProcessedVarList.empty()) + return nullptr; + + return OMPFromClause::Create(Context, StartLoc, LParenLoc, EndLoc, + MVLI.ProcessedVarList, MVLI.VarBaseDeclarations, + MVLI.VarComponents); +} + +OMPClause *Sema::ActOnOpenMPUseDevicePtrClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + SmallVector<Expr *, 8> Vars; + for (auto &RefExpr : VarList) { + assert(RefExpr && "NULL expr in OpenMP use_device_ptr clause."); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange); + if (Res.second) { + // It will be analyzed later. + Vars.push_back(RefExpr); + } + ValueDecl *D = Res.first; + if (!D) + continue; + + QualType Type = D->getType(); + // item should be a pointer or reference to pointer + if (!Type.getNonReferenceType()->isPointerType()) { + Diag(ELoc, diag::err_omp_usedeviceptr_not_a_pointer) + << 0 << RefExpr->getSourceRange(); + continue; + } + Vars.push_back(RefExpr->IgnoreParens()); + } + + if (Vars.empty()) + return nullptr; + + return OMPUseDevicePtrClause::Create(Context, StartLoc, LParenLoc, EndLoc, + Vars); +} + +OMPClause *Sema::ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + SmallVector<Expr *, 8> Vars; + for (auto &RefExpr : VarList) { + assert(RefExpr && "NULL expr in OpenMP use_device_ptr clause."); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange); + if (Res.second) { + // It will be analyzed later. + Vars.push_back(RefExpr); + } + ValueDecl *D = Res.first; + if (!D) + continue; + + QualType Type = D->getType(); + // item should be a pointer or array or reference to pointer or array + if (!Type.getNonReferenceType()->isPointerType() && + !Type.getNonReferenceType()->isArrayType()) { + Diag(ELoc, diag::err_omp_argument_type_isdeviceptr) + << 0 << RefExpr->getSourceRange(); + continue; + } + Vars.push_back(RefExpr->IgnoreParens()); + } + + if (Vars.empty()) + return nullptr; + + return OMPIsDevicePtrClause::Create(Context, StartLoc, LParenLoc, EndLoc, + Vars); +} |