diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp | 1427 |
1 files changed, 1101 insertions, 326 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp index dcd19c8..01f574b 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp @@ -118,7 +118,9 @@ private: typedef SmallVector<SharingMapTy, 4> StackTy; /// \brief Stack of used declaration and their data-sharing attributes. - StackTy Stack; + DeclSAMapTy Threadprivates; + const FunctionScopeInfo *CurrentNonCapturingFunctionScope = nullptr; + SmallVector<std::pair<StackTy, const FunctionScopeInfo *>, 4> Stack; /// \brief true, if check for DSA must be from parent directive, false, if /// from current directive. OpenMPClauseKind ClauseKindMode = OMPC_unknown; @@ -133,8 +135,14 @@ private: /// \brief Checks if the variable is a local for OpenMP region. bool isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter); + bool isStackEmpty() const { + return Stack.empty() || + Stack.back().second != CurrentNonCapturingFunctionScope || + Stack.back().first.empty(); + } + public: - explicit DSAStackTy(Sema &S) : Stack(1), SemaRef(S) {} + explicit DSAStackTy(Sema &S) : SemaRef(S) {} bool isClauseParsingMode() const { return ClauseKindMode != OMPC_unknown; } void setClauseParsingMode(OpenMPClauseKind K) { ClauseKindMode = K; } @@ -144,13 +152,38 @@ public: void push(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName, Scope *CurScope, SourceLocation Loc) { - Stack.push_back(SharingMapTy(DKind, DirName, CurScope, Loc)); - Stack.back().DefaultAttrLoc = Loc; + if (Stack.empty() || + Stack.back().second != CurrentNonCapturingFunctionScope) + Stack.emplace_back(StackTy(), CurrentNonCapturingFunctionScope); + Stack.back().first.emplace_back(DKind, DirName, CurScope, Loc); + Stack.back().first.back().DefaultAttrLoc = Loc; } void pop() { - assert(Stack.size() > 1 && "Data-sharing attributes stack is empty!"); - Stack.pop_back(); + assert(!Stack.back().first.empty() && + "Data-sharing attributes stack is empty!"); + Stack.back().first.pop_back(); + } + + /// Start new OpenMP region stack in new non-capturing function. + void pushFunction() { + const FunctionScopeInfo *CurFnScope = SemaRef.getCurFunction(); + assert(!isa<CapturingScopeInfo>(CurFnScope)); + CurrentNonCapturingFunctionScope = CurFnScope; + } + /// Pop region stack for non-capturing function. + void popFunction(const FunctionScopeInfo *OldFSI) { + if (!Stack.empty() && Stack.back().second == OldFSI) { + assert(Stack.back().first.empty()); + Stack.pop_back(); + } + CurrentNonCapturingFunctionScope = nullptr; + for (const FunctionScopeInfo *FSI : llvm::reverse(SemaRef.FunctionScopes)) { + if (!isa<CapturingScopeInfo>(FSI)) { + CurrentNonCapturingFunctionScope = FSI; + break; + } + } } void addCriticalWithHint(OMPCriticalDirective *D, llvm::APSInt Hint) { @@ -229,31 +262,35 @@ public: /// \brief Returns currently analyzed directive. OpenMPDirectiveKind getCurrentDirective() const { - return Stack.back().Directive; + return isStackEmpty() ? OMPD_unknown : Stack.back().first.back().Directive; } /// \brief Returns parent directive. OpenMPDirectiveKind getParentDirective() const { - if (Stack.size() > 2) - return Stack[Stack.size() - 2].Directive; - return OMPD_unknown; + if (isStackEmpty() || Stack.back().first.size() == 1) + return OMPD_unknown; + return std::next(Stack.back().first.rbegin())->Directive; } /// \brief Set default data sharing attribute to none. void setDefaultDSANone(SourceLocation Loc) { - Stack.back().DefaultAttr = DSA_none; - Stack.back().DefaultAttrLoc = Loc; + assert(!isStackEmpty()); + Stack.back().first.back().DefaultAttr = DSA_none; + Stack.back().first.back().DefaultAttrLoc = Loc; } /// \brief Set default data sharing attribute to shared. void setDefaultDSAShared(SourceLocation Loc) { - Stack.back().DefaultAttr = DSA_shared; - Stack.back().DefaultAttrLoc = Loc; + assert(!isStackEmpty()); + Stack.back().first.back().DefaultAttr = DSA_shared; + Stack.back().first.back().DefaultAttrLoc = Loc; } DefaultDataSharingAttributes getDefaultDSA() const { - return Stack.back().DefaultAttr; + return isStackEmpty() ? DSA_unspecified + : Stack.back().first.back().DefaultAttr; } SourceLocation getDefaultDSALocation() const { - return Stack.back().DefaultAttrLoc; + return isStackEmpty() ? SourceLocation() + : Stack.back().first.back().DefaultAttrLoc; } /// \brief Checks if the specified variable is a threadprivate. @@ -264,52 +301,64 @@ public: /// \brief Marks current region as ordered (it has an 'ordered' clause). void setOrderedRegion(bool IsOrdered, Expr *Param) { - Stack.back().OrderedRegion.setInt(IsOrdered); - Stack.back().OrderedRegion.setPointer(Param); + assert(!isStackEmpty()); + Stack.back().first.back().OrderedRegion.setInt(IsOrdered); + Stack.back().first.back().OrderedRegion.setPointer(Param); } /// \brief Returns true, if parent region is ordered (has associated /// 'ordered' clause), false - otherwise. bool isParentOrderedRegion() const { - if (Stack.size() > 2) - return Stack[Stack.size() - 2].OrderedRegion.getInt(); - return false; + if (isStackEmpty() || Stack.back().first.size() == 1) + return false; + return std::next(Stack.back().first.rbegin())->OrderedRegion.getInt(); } /// \brief Returns optional parameter for the ordered region. Expr *getParentOrderedRegionParam() const { - if (Stack.size() > 2) - return Stack[Stack.size() - 2].OrderedRegion.getPointer(); - return nullptr; + if (isStackEmpty() || Stack.back().first.size() == 1) + return nullptr; + return std::next(Stack.back().first.rbegin())->OrderedRegion.getPointer(); } /// \brief Marks current region as nowait (it has a 'nowait' clause). void setNowaitRegion(bool IsNowait = true) { - Stack.back().NowaitRegion = IsNowait; + assert(!isStackEmpty()); + Stack.back().first.back().NowaitRegion = IsNowait; } /// \brief Returns true, if parent region is nowait (has associated /// 'nowait' clause), false - otherwise. bool isParentNowaitRegion() const { - if (Stack.size() > 2) - return Stack[Stack.size() - 2].NowaitRegion; - return false; + if (isStackEmpty() || Stack.back().first.size() == 1) + return false; + return std::next(Stack.back().first.rbegin())->NowaitRegion; } /// \brief Marks parent region as cancel region. void setParentCancelRegion(bool Cancel = true) { - if (Stack.size() > 2) - Stack[Stack.size() - 2].CancelRegion = - Stack[Stack.size() - 2].CancelRegion || Cancel; + if (!isStackEmpty() && Stack.back().first.size() > 1) { + auto &StackElemRef = *std::next(Stack.back().first.rbegin()); + StackElemRef.CancelRegion |= StackElemRef.CancelRegion || Cancel; + } } /// \brief Return true if current region has inner cancel construct. - bool isCancelRegion() const { return Stack.back().CancelRegion; } + bool isCancelRegion() const { + return isStackEmpty() ? false : Stack.back().first.back().CancelRegion; + } /// \brief Set collapse value for the region. - void setAssociatedLoops(unsigned Val) { Stack.back().AssociatedLoops = Val; } + void setAssociatedLoops(unsigned Val) { + assert(!isStackEmpty()); + Stack.back().first.back().AssociatedLoops = Val; + } /// \brief Return collapse value for region. - unsigned getAssociatedLoops() const { return Stack.back().AssociatedLoops; } + unsigned getAssociatedLoops() const { + return isStackEmpty() ? 0 : Stack.back().first.back().AssociatedLoops; + } /// \brief Marks current target region as one with closely nested teams /// region. void setParentTeamsRegionLoc(SourceLocation TeamsRegionLoc) { - if (Stack.size() > 2) - Stack[Stack.size() - 2].InnerTeamsRegionLoc = TeamsRegionLoc; + if (!isStackEmpty() && Stack.back().first.size() > 1) { + std::next(Stack.back().first.rbegin())->InnerTeamsRegionLoc = + TeamsRegionLoc; + } } /// \brief Returns true, if current region has closely nested teams region. bool hasInnerTeamsRegion() const { @@ -317,14 +366,20 @@ public: } /// \brief Returns location of the nested teams region (if any). SourceLocation getInnerTeamsRegionLoc() const { - if (Stack.size() > 1) - return Stack.back().InnerTeamsRegionLoc; - return SourceLocation(); + return isStackEmpty() ? SourceLocation() + : Stack.back().first.back().InnerTeamsRegionLoc; } - Scope *getCurScope() const { return Stack.back().CurScope; } - Scope *getCurScope() { return Stack.back().CurScope; } - SourceLocation getConstructLoc() { return Stack.back().ConstructLoc; } + Scope *getCurScope() const { + return isStackEmpty() ? nullptr : Stack.back().first.back().CurScope; + } + Scope *getCurScope() { + return isStackEmpty() ? nullptr : Stack.back().first.back().CurScope; + } + SourceLocation getConstructLoc() { + return isStackEmpty() ? SourceLocation() + : Stack.back().first.back().ConstructLoc; + } /// Do the check specified in \a Check to all component lists and return true /// if any issue is found. @@ -333,8 +388,10 @@ public: const llvm::function_ref< bool(OMPClauseMappableExprCommon::MappableExprComponentListRef, OpenMPClauseKind)> &Check) { - auto SI = Stack.rbegin(); - auto SE = Stack.rend(); + if (isStackEmpty()) + return false; + auto SI = Stack.back().first.rbegin(); + auto SE = Stack.back().first.rend(); if (SI == SE) return false; @@ -355,15 +412,39 @@ public: return false; } + /// Do the check specified in \a Check to all component lists at a given level + /// and return true if any issue is found. + bool checkMappableExprComponentListsForDeclAtLevel( + ValueDecl *VD, unsigned Level, + const llvm::function_ref< + bool(OMPClauseMappableExprCommon::MappableExprComponentListRef, + OpenMPClauseKind)> &Check) { + if (isStackEmpty()) + return false; + + auto StartI = Stack.back().first.begin(); + auto EndI = Stack.back().first.end(); + if (std::distance(StartI, EndI) <= (int)Level) + return false; + std::advance(StartI, Level); + + auto MI = StartI->MappedExprComponents.find(VD); + if (MI != StartI->MappedExprComponents.end()) + for (auto &L : MI->second.Components) + if (Check(L, MI->second.Kind)) + return true; + return false; + } + /// 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, OpenMPClauseKind WhereFoundClauseKind) { - assert(Stack.size() > 1 && + assert(!isStackEmpty() && "Not expecting to retrieve components from a empty stack!"); - auto &MEC = Stack.back().MappedExprComponents[VD]; + auto &MEC = Stack.back().first.back().MappedExprComponents[VD]; // Create new entry and append the new components there. MEC.Components.resize(MEC.Components.size() + 1); MEC.Components.back().append(Components.begin(), Components.end()); @@ -371,23 +452,25 @@ public: } unsigned getNestingLevel() const { - assert(Stack.size() > 1); - return Stack.size() - 2; + assert(!isStackEmpty()); + return Stack.back().first.size() - 1; } 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}); + assert(!isStackEmpty() && Stack.back().first.size() > 1); + auto &StackElem = *std::next(Stack.back().first.rbegin()); + assert(isOpenMPWorksharingDirective(StackElem.Directive)); + StackElem.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; + assert(!isStackEmpty()); + auto &StackElem = Stack.back().first.back(); + if (isOpenMPWorksharingDirective(StackElem.Directive)) { + auto &Ref = StackElem.DoacrossDepends; return llvm::make_range(Ref.begin(), Ref.end()); } - return llvm::make_range(Stack[0].DoacrossDepends.end(), - Stack[0].DoacrossDepends.end()); + return llvm::make_range(StackElem.DoacrossDepends.end(), + StackElem.DoacrossDepends.end()); } }; bool isParallelOrTaskRegion(OpenMPDirectiveKind DKind) { @@ -416,7 +499,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter, auto *VD = dyn_cast<VarDecl>(D); auto *FD = dyn_cast<FieldDecl>(D); DSAVarData DVar; - if (Iter == std::prev(Stack.rend())) { + if (isStackEmpty() || Iter == Stack.back().first.rend()) { // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a region but not in construct] // File-scope or namespace-scope variables referenced in called routines @@ -490,8 +573,9 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter, // bound to the current team is shared. if (isOpenMPTaskingDirective(DVar.DKind)) { DSAVarData DVarTemp; - for (StackTy::reverse_iterator I = std::next(Iter), EE = Stack.rend(); - I != EE; ++I) { + auto I = Iter, E = Stack.back().first.rend(); + do { + ++I; // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables // Referenced in a Construct, implicitly determined, p.6] // In a task construct, if no default clause is present, a variable @@ -503,9 +587,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter, DVar.CKind = OMPC_firstprivate; return DVar; } - if (isParallelOrTaskRegion(I->Directive)) - break; - } + } while (I != E && !isParallelOrTaskRegion(I->Directive)); DVar.CKind = (DVarTemp.CKind == OMPC_unknown) ? OMPC_firstprivate : OMPC_shared; return DVar; @@ -520,12 +602,13 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter, } Expr *DSAStackTy::addUniqueAligned(ValueDecl *D, Expr *NewDE) { - assert(Stack.size() > 1 && "Data sharing attributes stack is empty"); + assert(!isStackEmpty() && "Data sharing attributes stack is empty"); D = getCanonicalDecl(D); - auto It = Stack.back().AlignedMap.find(D); - if (It == Stack.back().AlignedMap.end()) { + auto &StackElem = Stack.back().first.back(); + auto It = StackElem.AlignedMap.find(D); + if (It == StackElem.AlignedMap.end()) { assert(NewDE && "Unexpected nullptr expr to be added into aligned map"); - Stack.back().AlignedMap[D] = NewDE; + StackElem.AlignedMap[D] = NewDE; return nullptr; } else { assert(It->second && "Unexpected nullptr expr in the aligned map"); @@ -535,35 +618,43 @@ Expr *DSAStackTy::addUniqueAligned(ValueDecl *D, Expr *NewDE) { } void DSAStackTy::addLoopControlVariable(ValueDecl *D, VarDecl *Capture) { - assert(Stack.size() > 1 && "Data-sharing attributes stack is empty"); + assert(!isStackEmpty() && "Data-sharing attributes stack is empty"); D = getCanonicalDecl(D); - Stack.back().LCVMap.insert( - std::make_pair(D, LCDeclInfo(Stack.back().LCVMap.size() + 1, Capture))); + auto &StackElem = Stack.back().first.back(); + StackElem.LCVMap.insert( + {D, LCDeclInfo(StackElem.LCVMap.size() + 1, Capture)}); } DSAStackTy::LCDeclInfo DSAStackTy::isLoopControlVariable(ValueDecl *D) { - assert(Stack.size() > 1 && "Data-sharing attributes stack is empty"); + assert(!isStackEmpty() && "Data-sharing attributes stack is empty"); D = getCanonicalDecl(D); - return Stack.back().LCVMap.count(D) > 0 ? Stack.back().LCVMap[D] - : LCDeclInfo(0, nullptr); + auto &StackElem = Stack.back().first.back(); + auto It = StackElem.LCVMap.find(D); + if (It != StackElem.LCVMap.end()) + return It->second; + return {0, nullptr}; } DSAStackTy::LCDeclInfo DSAStackTy::isParentLoopControlVariable(ValueDecl *D) { - assert(Stack.size() > 2 && "Data-sharing attributes stack is empty"); + assert(!isStackEmpty() && Stack.back().first.size() > 1 && + "Data-sharing attributes stack is empty"); D = getCanonicalDecl(D); - return Stack[Stack.size() - 2].LCVMap.count(D) > 0 - ? Stack[Stack.size() - 2].LCVMap[D] - : LCDeclInfo(0, nullptr); + auto &StackElem = *std::next(Stack.back().first.rbegin()); + auto It = StackElem.LCVMap.find(D); + if (It != StackElem.LCVMap.end()) + return It->second; + return {0, nullptr}; } ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) { - assert(Stack.size() > 2 && "Data-sharing attributes stack is empty"); - if (Stack[Stack.size() - 2].LCVMap.size() < I) + assert(!isStackEmpty() && Stack.back().first.size() > 1 && + "Data-sharing attributes stack is empty"); + auto &StackElem = *std::next(Stack.back().first.rbegin()); + if (StackElem.LCVMap.size() < I) return nullptr; - for (auto &Pair : Stack[Stack.size() - 2].LCVMap) { + for (auto &Pair : StackElem.LCVMap) if (Pair.second.first == I) return Pair.first; - } return nullptr; } @@ -571,13 +662,13 @@ void DSAStackTy::addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A, DeclRefExpr *PrivateCopy) { D = getCanonicalDecl(D); if (A == OMPC_threadprivate) { - auto &Data = Stack[0].SharingMap[D]; + auto &Data = Threadprivates[D]; Data.Attributes = A; Data.RefExpr.setPointer(E); Data.PrivateCopy = nullptr; } else { - assert(Stack.size() > 1 && "Data-sharing attributes stack is empty"); - auto &Data = Stack.back().SharingMap[D]; + assert(!isStackEmpty() && "Data-sharing attributes stack is empty"); + auto &Data = Stack.back().first.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) || @@ -592,7 +683,7 @@ void DSAStackTy::addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A, Data.RefExpr.setPointerAndInt(E, IsLastprivate); Data.PrivateCopy = PrivateCopy; if (PrivateCopy) { - auto &Data = Stack.back().SharingMap[PrivateCopy->getDecl()]; + auto &Data = Stack.back().first.back().SharingMap[PrivateCopy->getDecl()]; Data.Attributes = A; Data.RefExpr.setPointerAndInt(PrivateCopy, IsLastprivate); Data.PrivateCopy = nullptr; @@ -602,19 +693,17 @@ void DSAStackTy::addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A, bool DSAStackTy::isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter) { D = D->getCanonicalDecl(); - if (Stack.size() > 2) { - reverse_iterator I = Iter, E = std::prev(Stack.rend()); + if (!isStackEmpty() && Stack.back().first.size() > 1) { + reverse_iterator I = Iter, E = Stack.back().first.rend(); Scope *TopScope = nullptr; - while (I != E && !isParallelOrTaskRegion(I->Directive)) { + while (I != E && !isParallelOrTaskRegion(I->Directive)) ++I; - } if (I == E) return false; TopScope = I->CurScope ? I->CurScope->getParent() : nullptr; Scope *CurScope = getCurScope(); - while (CurScope != TopScope && !CurScope->isDeclScope(D)) { + while (CurScope != TopScope && !CurScope->isDeclScope(D)) CurScope = CurScope->getParent(); - } return CurScope != TopScope; } return false; @@ -665,16 +754,16 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) { D->getLocation()), OMPC_threadprivate); } - if (Stack[0].SharingMap.count(D)) { - DVar.RefExpr = Stack[0].SharingMap[D].RefExpr.getPointer(); + auto TI = Threadprivates.find(D); + if (TI != Threadprivates.end()) { + DVar.RefExpr = TI->getSecond().RefExpr.getPointer(); DVar.CKind = OMPC_threadprivate; return DVar; } - if (Stack.size() == 1) { + if (isStackEmpty()) // 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] @@ -722,11 +811,10 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) { // Explicitly specified attributes and local variables with predetermined // attributes. - auto StartI = std::next(Stack.rbegin()); - auto EndI = std::prev(Stack.rend()); - if (FromParent && StartI != EndI) { + auto StartI = std::next(Stack.back().first.rbegin()); + auto EndI = Stack.back().first.rend(); + if (FromParent && StartI != EndI) StartI = std::next(StartI); - } auto I = std::prev(StartI); if (I->SharingMap.count(D)) { DVar.RefExpr = I->SharingMap[D].RefExpr.getPointer(); @@ -740,12 +828,15 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) { DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D, bool FromParent) { + if (isStackEmpty()) { + StackTy::reverse_iterator I; + return getDSA(I, D); + } D = getCanonicalDecl(D); - auto StartI = Stack.rbegin(); - auto EndI = std::prev(Stack.rend()); - if (FromParent && StartI != EndI) { + auto StartI = Stack.back().first.rbegin(); + auto EndI = Stack.back().first.rend(); + if (FromParent && StartI != EndI) StartI = std::next(StartI); - } return getDSA(StartI, D); } @@ -754,33 +845,37 @@ DSAStackTy::hasDSA(ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred, bool FromParent) { + if (isStackEmpty()) + return {}; D = getCanonicalDecl(D); - auto StartI = std::next(Stack.rbegin()); - auto EndI = Stack.rend(); - if (FromParent && StartI != EndI) { - StartI = std::next(StartI); - } - for (auto I = StartI, EE = EndI; I != EE; ++I) { + auto I = (FromParent && Stack.back().first.size() > 1) + ? std::next(Stack.back().first.rbegin()) + : Stack.back().first.rbegin(); + auto EndI = Stack.back().first.rend(); + while (std::distance(I, EndI) > 1) { + std::advance(I, 1); if (!DPred(I->Directive) && !isParallelOrTaskRegion(I->Directive)) continue; DSAVarData DVar = getDSA(I, D); if (CPred(DVar.CKind)) return DVar; } - return DSAVarData(); + return {}; } DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA( ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred, bool FromParent) { + if (isStackEmpty()) + return {}; D = getCanonicalDecl(D); - auto StartI = std::next(Stack.rbegin()); - auto EndI = Stack.rend(); + auto StartI = std::next(Stack.back().first.rbegin()); + auto EndI = Stack.back().first.rend(); if (FromParent && StartI != EndI) StartI = std::next(StartI); if (StartI == EndI || !DPred(StartI->Directive)) - return DSAVarData(); + return {}; DSAVarData DVar = getDSA(StartI, D); return CPred(DVar.CKind) ? DVar : DSAVarData(); } @@ -790,9 +885,11 @@ bool DSAStackTy::hasExplicitDSA( unsigned Level, bool NotLastprivate) { if (CPred(ClauseKindMode)) return true; + if (isStackEmpty()) + return false; D = getCanonicalDecl(D); - auto StartI = std::next(Stack.begin()); - auto EndI = Stack.end(); + auto StartI = Stack.back().first.begin(); + auto EndI = Stack.back().first.end(); if (std::distance(StartI, EndI) <= (int)Level) return false; std::advance(StartI, Level); @@ -805,8 +902,10 @@ bool DSAStackTy::hasExplicitDSA( bool DSAStackTy::hasExplicitDirective( const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred, unsigned Level) { - auto StartI = std::next(Stack.begin()); - auto EndI = Stack.end(); + if (isStackEmpty()) + return false; + auto StartI = Stack.back().first.begin(); + auto EndI = Stack.back().first.end(); if (std::distance(StartI, EndI) <= (int)Level) return false; std::advance(StartI, Level); @@ -819,13 +918,12 @@ bool DSAStackTy::hasDirective( &DPred, bool FromParent) { // We look only in the enclosing region. - if (Stack.size() < 2) + if (isStackEmpty()) return false; - auto StartI = std::next(Stack.rbegin()); - auto EndI = std::prev(Stack.rend()); - if (FromParent && StartI != EndI) { + auto StartI = std::next(Stack.back().first.rbegin()); + auto EndI = Stack.back().first.rend(); + if (FromParent && StartI != EndI) StartI = std::next(StartI); - } for (auto I = StartI, EE = EndI; I != EE; ++I) { if (DPred(I->Directive, I->DirectiveName, I->ConstructLoc)) return true; @@ -839,6 +937,14 @@ void Sema::InitDataSharingAttributesStack() { #define DSAStack static_cast<DSAStackTy *>(VarDataSharingAttributesStack) +void Sema::pushOpenMPFunctionRegion() { + DSAStack->pushFunction(); +} + +void Sema::popOpenMPFunctionRegion(const FunctionScopeInfo *OldFSI) { + DSAStack->popFunction(OldFSI); +} + bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); @@ -912,9 +1018,8 @@ bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level) { bool IsVariableUsedInMapClause = false; bool IsVariableAssociatedWithSection = false; - DSAStack->checkMappableExprComponentListsForDecl( - D, /*CurrentRegionOnly=*/true, - [&](OMPClauseMappableExprCommon::MappableExprComponentListRef + DSAStack->checkMappableExprComponentListsForDeclAtLevel( + D, Level, [&](OMPClauseMappableExprCommon::MappableExprComponentListRef MapExprComponents, OpenMPClauseKind WhereFoundClauseKind) { // Only the map clause information influences how a variable is @@ -1050,7 +1155,8 @@ void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName, Scope *CurScope, SourceLocation Loc) { DSAStack->push(DKind, DirName, CurScope, Loc); - PushExpressionEvaluationContext(PotentiallyEvaluated); + PushExpressionEvaluationContext( + ExpressionEvaluationContext::PotentiallyEvaluated); } void Sema::StartOpenMPClause(OpenMPClauseKind K) { @@ -1594,8 +1700,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_parallel_for: case OMPD_parallel_for_simd: case OMPD_parallel_sections: - case OMPD_teams: - case OMPD_target_teams: { + case OMPD_teams: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); @@ -1608,6 +1713,28 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { Params); break; } + case OMPD_target_teams: + case OMPD_target_parallel: { + Sema::CapturedParamNameType ParamsTarget[] = { + std::make_pair(StringRef(), QualType()) // __context with shared vars + }; + // Start a captured region for 'target' with no implicit parameters. + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + ParamsTarget); + QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); + QualType KmpInt32PtrTy = + Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); + Sema::CapturedParamNameType ParamsTeamsOrParallel[] = { + std::make_pair(".global_tid.", KmpInt32PtrTy), + std::make_pair(".bound_tid.", KmpInt32PtrTy), + std::make_pair(StringRef(), QualType()) // __context with shared vars + }; + // Start a captured region for 'teams' or 'parallel'. Both regions have + // the same implicit parameters. + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + ParamsTeamsOrParallel); + break; + } case OMPD_simd: case OMPD_for: case OMPD_for_simd: @@ -1622,7 +1749,6 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { 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: case OMPD_target_simd: { @@ -1681,6 +1807,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { std::make_pair(".lb.", KmpUInt64Ty), std::make_pair(".ub.", KmpUInt64Ty), std::make_pair(".st.", KmpInt64Ty), std::make_pair(".liter.", KmpInt32Ty), + std::make_pair(".reductions.", + Context.VoidPtrTy.withConst().withRestrict()), std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, @@ -1737,6 +1865,12 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { } } +int Sema::getOpenMPCaptureLevels(OpenMPDirectiveKind DKind) { + SmallVector<OpenMPDirectiveKind, 4> CaptureRegions; + getOpenMPCaptureRegions(CaptureRegions, DKind); + return CaptureRegions.size(); +} + static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id, Expr *CaptureExpr, bool WithInit, bool AsExpression) { @@ -1796,16 +1930,49 @@ static ExprResult buildCapture(Sema &S, Expr *CaptureExpr, DeclRefExpr *&Ref) { return CaptureExpr->isGLValue() ? Res : S.DefaultLvalueConversion(Res.get()); } +namespace { +// OpenMP directives parsed in this section are represented as a +// CapturedStatement with an associated statement. If a syntax error +// is detected during the parsing of the associated statement, the +// compiler must abort processing and close the CapturedStatement. +// +// Combined directives such as 'target parallel' have more than one +// nested CapturedStatements. This RAII ensures that we unwind out +// of all the nested CapturedStatements when an error is found. +class CaptureRegionUnwinderRAII { +private: + Sema &S; + bool &ErrorFound; + OpenMPDirectiveKind DKind; + +public: + CaptureRegionUnwinderRAII(Sema &S, bool &ErrorFound, + OpenMPDirectiveKind DKind) + : S(S), ErrorFound(ErrorFound), DKind(DKind) {} + ~CaptureRegionUnwinderRAII() { + if (ErrorFound) { + int ThisCaptureLevel = S.getOpenMPCaptureLevels(DKind); + while (--ThisCaptureLevel >= 0) + S.ActOnCapturedRegionError(); + } + } +}; +} // namespace + StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, ArrayRef<OMPClause *> Clauses) { + bool ErrorFound = false; + CaptureRegionUnwinderRAII CaptureRegionUnwinder( + *this, ErrorFound, DSAStack->getCurrentDirective()); if (!S.isUsable()) { - ActOnCapturedRegionError(); + ErrorFound = true; return StmtError(); } OMPOrderedClause *OC = nullptr; OMPScheduleClause *SC = nullptr; SmallVector<OMPLinearClause *, 4> LCs; + SmallVector<OMPClauseWithPreInit *, 8> PICs; // This is required for proper codegen. for (auto *Clause : Clauses) { if (isOpenMPPrivate(Clause->getClauseKind()) || @@ -1822,15 +1989,8 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, } DSAStack->setForceVarCapturing(/*V=*/false); } 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 *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 = OMPClauseWithPreInit::get(Clause)) + PICs.push_back(C); if (auto *C = OMPClauseWithPostUpdate::get(Clause)) { if (auto *E = C->getPostUpdateExpr()) MarkDeclarationsReferencedInExpr(E); @@ -1843,7 +2003,6 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, else if (Clause->getClauseKind() == OMPC_linear) LCs.push_back(cast<OMPLinearClause>(Clause)); } - bool ErrorFound = false; // OpenMP, 2.7.1 Loop Construct, Restrictions // The nonmonotonic modifier cannot be specified if an ordered clause is // specified. @@ -1874,13 +2033,54 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, ErrorFound = true; } if (ErrorFound) { - ActOnCapturedRegionError(); return StmtError(); } - return ActOnCapturedRegionEnd(S.get()); + StmtResult SR = S; + SmallVector<OpenMPDirectiveKind, 4> CaptureRegions; + getOpenMPCaptureRegions(CaptureRegions, DSAStack->getCurrentDirective()); + for (auto ThisCaptureRegion : llvm::reverse(CaptureRegions)) { + // 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 (isParallelOrTaskRegion(DSAStack->getCurrentDirective())) { + for (auto *C : PICs) { + OpenMPDirectiveKind CaptureRegion = C->getCaptureRegion(); + // Find the particular capture region for the clause if the + // directive is a combined one with multiple capture regions. + // If the directive is not a combined one, the capture region + // associated with the clause is OMPD_unknown and is generated + // only once. + if (CaptureRegion == ThisCaptureRegion || + CaptureRegion == OMPD_unknown) { + if (auto *DS = cast_or_null<DeclStmt>(C->getPreInitStmt())) { + for (auto *D : DS->decls()) + MarkVariableReferenced(D->getLocation(), cast<VarDecl>(D)); + } + } + } + } + SR = ActOnCapturedRegionEnd(SR.get()); + } + return SR; +} + +static bool checkCancelRegion(Sema &SemaRef, OpenMPDirectiveKind CurrentRegion, + OpenMPDirectiveKind CancelRegion, + SourceLocation StartLoc) { + // CancelRegion is only needed for cancel and cancellation_point. + if (CurrentRegion != OMPD_cancel && CurrentRegion != OMPD_cancellation_point) + return false; + + if (CancelRegion == OMPD_parallel || CancelRegion == OMPD_for || + CancelRegion == OMPD_sections || CancelRegion == OMPD_taskgroup) + return false; + + SemaRef.Diag(StartLoc, diag::err_omp_wrong_cancel_region) + << getOpenMPDirectiveName(CancelRegion); + return true; } -static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, +static bool checkNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, OpenMPDirectiveKind CurrentRegion, const DeclarationNameInfo &CurrentName, OpenMPDirectiveKind CancelRegion, @@ -2180,7 +2380,9 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { StmtResult Res = StmtError(); - if (CheckNestingOfRegions(*this, DSAStack, Kind, DirName, CancelRegion, + // First check CancelRegion which is then used in checkNestingOfRegions. + if (checkCancelRegion(*this, Kind, CancelRegion, StartLoc) || + checkNestingOfRegions(*this, DSAStack, Kind, DirName, CancelRegion, StartLoc)) return StmtError(); @@ -2193,7 +2395,11 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( // Check default data sharing attributes for referenced variables. DSAAttrChecker DSAChecker(DSAStack, *this, cast<CapturedStmt>(AStmt)); - DSAChecker.Visit(cast<CapturedStmt>(AStmt)->getCapturedStmt()); + int ThisCaptureLevel = getOpenMPCaptureLevels(Kind); + Stmt *S = AStmt; + while (--ThisCaptureLevel >= 0) + S = cast<CapturedStmt>(S)->getCapturedStmt(); + DSAChecker.Visit(S); if (DSAChecker.isErrorFound()) return StmtError(); // Generate list of implicitly defined firstprivate variables. @@ -2294,9 +2500,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( Res = ActOnOpenMPTaskwaitDirective(StartLoc, EndLoc); break; case OMPD_taskgroup: - assert(ClausesWithImplicit.empty() && - "No clauses are allowed for 'omp taskgroup' directive"); - Res = ActOnOpenMPTaskgroupDirective(AStmt, StartLoc, EndLoc); + Res = ActOnOpenMPTaskgroupDirective(ClausesWithImplicit, AStmt, StartLoc, + EndLoc); break; case OMPD_flush: assert(AStmt == nullptr && @@ -3969,7 +4174,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, SourceLocation InitLoc = IterSpaces[0].InitSrcRange.getBegin(); // Build variables passed into runtime, necessary for worksharing directives. - ExprResult LB, UB, IL, ST, EUB, PrevLB, PrevUB; + ExprResult LB, UB, IL, ST, EUB, CombLB, CombUB, PrevLB, PrevUB, CombEUB; if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)) { // Lower bound variable, initialized with zero. @@ -4017,8 +4222,32 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, // 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(); + // Lower bound variable, initialized with zero. + VarDecl *CombLBDecl = + buildVarDecl(SemaRef, InitLoc, VType, ".omp.comb.lb"); + CombLB = buildDeclRefExpr(SemaRef, CombLBDecl, VType, InitLoc); + SemaRef.AddInitializerToDecl( + CombLBDecl, SemaRef.ActOnIntegerConstant(InitLoc, 0).get(), + /*DirectInit*/ false); + + // Upper bound variable, initialized with last iteration number. + VarDecl *CombUBDecl = + buildVarDecl(SemaRef, InitLoc, VType, ".omp.comb.ub"); + CombUB = buildDeclRefExpr(SemaRef, CombUBDecl, VType, InitLoc); + SemaRef.AddInitializerToDecl(CombUBDecl, LastIteration.get(), + /*DirectInit*/ false); + + ExprResult CombIsUBGreater = SemaRef.BuildBinOp( + CurScope, InitLoc, BO_GT, CombUB.get(), LastIteration.get()); + ExprResult CombCondOp = + SemaRef.ActOnConditionalOp(InitLoc, InitLoc, CombIsUBGreater.get(), + LastIteration.get(), CombUB.get()); + CombEUB = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, CombUB.get(), + CombCondOp.get()); + CombEUB = SemaRef.ActOnFinishFullExpr(CombEUB.get()); + + 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 && @@ -4040,7 +4269,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, // Build the iteration variable and its initialization before loop. ExprResult IV; - ExprResult Init; + ExprResult Init, CombInit; { VarDecl *IVDecl = buildVarDecl(SemaRef, InitLoc, RealVType, ".omp.iv"); IV = buildDeclRefExpr(SemaRef, IVDecl, RealVType, InitLoc); @@ -4051,6 +4280,18 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, : SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get(); Init = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, IV.get(), RHS); Init = SemaRef.ActOnFinishFullExpr(Init.get()); + + if (isOpenMPLoopBoundSharingDirective(DKind)) { + Expr *CombRHS = + (isOpenMPWorksharingDirective(DKind) || + isOpenMPTaskLoopDirective(DKind) || + isOpenMPDistributeDirective(DKind)) + ? CombLB.get() + : SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get(); + CombInit = + SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, IV.get(), CombRHS); + CombInit = SemaRef.ActOnFinishFullExpr(CombInit.get()); + } } // Loop condition (IV < NumIterations) or (IV <= UB) for worksharing loops. @@ -4061,7 +4302,11 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, ? SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get()) : SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(), NumIterations.get()); - + ExprResult CombCond; + if (isOpenMPLoopBoundSharingDirective(DKind)) { + CombCond = + SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), CombUB.get()); + } // Loop increment (IV = IV + 1) SourceLocation IncLoc; ExprResult Inc = @@ -4076,7 +4321,9 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, // Increments for worksharing loops (LB = LB + ST; UB = UB + ST). // Used for directives with static scheduling. - ExprResult NextLB, NextUB; + // In combined construct, add combined version that use CombLB and CombUB + // base variables for the update + ExprResult NextLB, NextUB, CombNextLB, CombNextUB; if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)) { // LB + ST @@ -4099,6 +4346,59 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, NextUB = SemaRef.ActOnFinishFullExpr(NextUB.get()); if (!NextUB.isUsable()) return 0; + if (isOpenMPLoopBoundSharingDirective(DKind)) { + CombNextLB = + SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, CombLB.get(), ST.get()); + if (!NextLB.isUsable()) + return 0; + // LB = LB + ST + CombNextLB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, CombLB.get(), + CombNextLB.get()); + CombNextLB = SemaRef.ActOnFinishFullExpr(CombNextLB.get()); + if (!CombNextLB.isUsable()) + return 0; + // UB + ST + CombNextUB = + SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, CombUB.get(), ST.get()); + if (!CombNextUB.isUsable()) + return 0; + // UB = UB + ST + CombNextUB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, CombUB.get(), + CombNextUB.get()); + CombNextUB = SemaRef.ActOnFinishFullExpr(CombNextUB.get()); + if (!CombNextUB.isUsable()) + return 0; + } + } + + // Create increment expression for distribute loop when combined in a same + // directive with for as IV = IV + ST; ensure upper bound expression based + // on PrevUB instead of NumIterations - used to implement 'for' when found + // in combination with 'distribute', like in 'distribute parallel for' + SourceLocation DistIncLoc; + ExprResult DistCond, DistInc, PrevEUB; + if (isOpenMPLoopBoundSharingDirective(DKind)) { + DistCond = SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get()); + assert(DistCond.isUsable() && "distribute cond expr was not built"); + + DistInc = + SemaRef.BuildBinOp(CurScope, DistIncLoc, BO_Add, IV.get(), ST.get()); + assert(DistInc.isUsable() && "distribute inc expr was not built"); + DistInc = SemaRef.BuildBinOp(CurScope, DistIncLoc, BO_Assign, IV.get(), + DistInc.get()); + DistInc = SemaRef.ActOnFinishFullExpr(DistInc.get()); + assert(DistInc.isUsable() && "distribute inc expr was not built"); + + // Build expression: UB = min(UB, prevUB) for #for in composite or combined + // construct + SourceLocation DistEUBLoc; + ExprResult IsUBGreater = + SemaRef.BuildBinOp(CurScope, DistEUBLoc, BO_GT, UB.get(), PrevUB.get()); + ExprResult CondOp = SemaRef.ActOnConditionalOp( + DistEUBLoc, DistEUBLoc, IsUBGreater.get(), PrevUB.get(), UB.get()); + PrevEUB = SemaRef.BuildBinOp(CurScope, DistIncLoc, BO_Assign, UB.get(), + CondOp.get()); + PrevEUB = SemaRef.ActOnFinishFullExpr(PrevEUB.get()); } // Build updates and final values of the loop counters. @@ -4215,6 +4515,15 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Built.NUB = NextUB.get(); Built.PrevLB = PrevLB.get(); Built.PrevUB = PrevUB.get(); + Built.DistInc = DistInc.get(); + Built.PrevEUB = PrevEUB.get(); + Built.DistCombinedFields.LB = CombLB.get(); + Built.DistCombinedFields.UB = CombUB.get(); + Built.DistCombinedFields.EUB = CombEUB.get(); + Built.DistCombinedFields.Init = CombInit.get(); + Built.DistCombinedFields.Cond = CombCond.get(); + Built.DistCombinedFields.NLB = CombNextLB.get(); + Built.DistCombinedFields.NUB = CombNextUB.get(); Expr *CounterVal = SemaRef.DefaultLvalueConversion(IV.get()).get(); // Fill data for doacross depend clauses. @@ -4759,7 +5068,8 @@ StmtResult Sema::ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc, return OMPTaskwaitDirective::Create(Context, StartLoc, EndLoc); } -StmtResult Sema::ActOnOpenMPTaskgroupDirective(Stmt *AStmt, +StmtResult Sema::ActOnOpenMPTaskgroupDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { if (!AStmt) @@ -4769,7 +5079,8 @@ StmtResult Sema::ActOnOpenMPTaskgroupDirective(Stmt *AStmt, getCurFunction()->setHasBranchProtectedScope(); - return OMPTaskgroupDirective::Create(Context, StartLoc, EndLoc, AStmt); + return OMPTaskgroupDirective::Create(Context, StartLoc, EndLoc, Clauses, + AStmt); } StmtResult Sema::ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses, @@ -5644,16 +5955,17 @@ StmtResult Sema::ActOnOpenMPTargetParallelForDirective( 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; - } - } +/// Check for existence of a map clause in the list of clauses. +static bool hasClauses(ArrayRef<OMPClause *> Clauses, + const OpenMPClauseKind K) { + return llvm::any_of( + Clauses, [K](const OMPClause *C) { return C->getClauseKind() == K; }); +} - return false; +template <typename... Params> +static bool hasClauses(ArrayRef<OMPClause *> Clauses, const OpenMPClauseKind K, + const Params... ClauseTypes) { + return hasClauses(Clauses, K) || hasClauses(Clauses, ClauseTypes...); } StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses, @@ -5667,8 +5979,9 @@ StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses, // 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) + if (!hasClauses(Clauses, OMPC_map, OMPC_use_device_ptr)) { + Diag(StartLoc, diag::err_omp_no_clause_for_directive) + << "'map' or 'use_device_ptr'" << getOpenMPDirectiveName(OMPD_target_data); return StmtError(); } @@ -5685,9 +5998,9 @@ Sema::ActOnOpenMPTargetEnterDataDirective(ArrayRef<OMPClause *> Clauses, 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); + if (!hasClauses(Clauses, OMPC_map)) { + Diag(StartLoc, diag::err_omp_no_clause_for_directive) + << "'map'" << getOpenMPDirectiveName(OMPD_target_enter_data); return StmtError(); } @@ -5701,9 +6014,9 @@ Sema::ActOnOpenMPTargetExitDataDirective(ArrayRef<OMPClause *> Clauses, 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); + if (!hasClauses(Clauses, OMPC_map)) { + Diag(StartLoc, diag::err_omp_no_clause_for_directive) + << "'map'" << getOpenMPDirectiveName(OMPD_target_exit_data); return StmtError(); } @@ -5713,12 +6026,7 @@ Sema::ActOnOpenMPTargetExitDataDirective(ArrayRef<OMPClause *> 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) { + if (!hasClauses(Clauses, OMPC_to, OMPC_from)) { Diag(StartLoc, diag::err_omp_at_least_one_motion_clause_required); return StmtError(); } @@ -5748,12 +6056,6 @@ StmtResult Sema::ActOnOpenMPCancellationPointDirective(SourceLocation StartLoc, SourceLocation EndLoc, OpenMPDirectiveKind CancelRegion) { - if (CancelRegion != OMPD_parallel && CancelRegion != OMPD_for && - CancelRegion != OMPD_sections && CancelRegion != OMPD_taskgroup) { - Diag(StartLoc, diag::err_omp_wrong_cancel_region) - << getOpenMPDirectiveName(CancelRegion); - return StmtError(); - } if (DSAStack->isParentNowaitRegion()) { Diag(StartLoc, diag::err_omp_parent_cancel_region_nowait) << 0; return StmtError(); @@ -5770,12 +6072,6 @@ StmtResult Sema::ActOnOpenMPCancelDirective(ArrayRef<OMPClause *> Clauses, SourceLocation StartLoc, SourceLocation EndLoc, OpenMPDirectiveKind CancelRegion) { - if (CancelRegion != OMPD_parallel && CancelRegion != OMPD_for && - CancelRegion != OMPD_sections && CancelRegion != OMPD_taskgroup) { - Diag(StartLoc, diag::err_omp_wrong_cancel_region) - << getOpenMPDirectiveName(CancelRegion); - return StmtError(); - } if (DSAStack->isParentNowaitRegion()) { Diag(StartLoc, diag::err_omp_parent_cancel_region_nowait) << 1; return StmtError(); @@ -5813,6 +6109,33 @@ static bool checkGrainsizeNumTasksClauses(Sema &S, return ErrorFound; } +static bool checkReductionClauseWithNogroup(Sema &S, + ArrayRef<OMPClause *> Clauses) { + OMPClause *ReductionClause = nullptr; + OMPClause *NogroupClause = nullptr; + for (auto *C : Clauses) { + if (C->getClauseKind() == OMPC_reduction) { + ReductionClause = C; + if (NogroupClause) + break; + continue; + } + if (C->getClauseKind() == OMPC_nogroup) { + NogroupClause = C; + if (ReductionClause) + break; + continue; + } + } + if (ReductionClause && NogroupClause) { + S.Diag(ReductionClause->getLocStart(), diag::err_omp_reduction_with_nogroup) + << SourceRange(NogroupClause->getLocStart(), + NogroupClause->getLocEnd()); + return true; + } + return false; +} + StmtResult Sema::ActOnOpenMPTaskLoopDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, @@ -5839,6 +6162,11 @@ StmtResult Sema::ActOnOpenMPTaskLoopDirective( // not appear on the same taskloop directive. if (checkGrainsizeNumTasksClauses(*this, Clauses)) return StmtError(); + // OpenMP, [2.9.2 taskloop Construct, Restrictions] + // If a reduction clause is present on the taskloop directive, the nogroup + // clause must not be specified. + if (checkReductionClauseWithNogroup(*this, Clauses)) + return StmtError(); getCurFunction()->setHasBranchProtectedScope(); return OMPTaskLoopDirective::Create(Context, StartLoc, EndLoc, @@ -5882,6 +6210,11 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective( // not appear on the same taskloop directive. if (checkGrainsizeNumTasksClauses(*this, Clauses)) return StmtError(); + // OpenMP, [2.9.2 taskloop Construct, Restrictions] + // If a reduction clause is present on the taskloop directive, the nogroup + // clause must not be specified. + if (checkReductionClauseWithNogroup(*this, Clauses)) + return StmtError(); getCurFunction()->setHasBranchProtectedScope(); return OMPTaskLoopSimdDirective::Create(Context, StartLoc, EndLoc, @@ -6519,6 +6852,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_lastprivate: case OMPC_shared: case OMPC_reduction: + case OMPC_task_reduction: case OMPC_linear: case OMPC_aligned: case OMPC_copyin: @@ -6551,6 +6885,323 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, return Res; } +// An OpenMP directive such as 'target parallel' has two captured regions: +// for the 'target' and 'parallel' respectively. This function returns +// the region in which to capture expressions associated with a clause. +// A return value of OMPD_unknown signifies that the expression should not +// be captured. +static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( + OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, + OpenMPDirectiveKind NameModifier = OMPD_unknown) { + OpenMPDirectiveKind CaptureRegion = OMPD_unknown; + + switch (CKind) { + case OMPC_if: + switch (DKind) { + case OMPD_target_parallel: + // If this clause applies to the nested 'parallel' region, capture within + // the 'target' region, otherwise do not capture. + if (NameModifier == OMPD_unknown || NameModifier == OMPD_parallel) + CaptureRegion = OMPD_target; + break; + case OMPD_cancel: + case OMPD_parallel: + case OMPD_parallel_sections: + case OMPD_parallel_for: + case OMPD_parallel_for_simd: + case OMPD_target: + case OMPD_target_simd: + case OMPD_target_parallel_for: + case OMPD_target_parallel_for_simd: + case OMPD_target_teams: + case OMPD_target_teams_distribute: + case OMPD_target_teams_distribute_simd: + case OMPD_target_teams_distribute_parallel_for: + case OMPD_target_teams_distribute_parallel_for_simd: + case OMPD_teams_distribute_parallel_for: + case OMPD_teams_distribute_parallel_for_simd: + case OMPD_distribute_parallel_for: + case OMPD_distribute_parallel_for_simd: + case OMPD_task: + case OMPD_taskloop: + case OMPD_taskloop_simd: + case OMPD_target_data: + case OMPD_target_enter_data: + case OMPD_target_exit_data: + case OMPD_target_update: + // Do not capture if-clause expressions. + break; + case OMPD_threadprivate: + case OMPD_taskyield: + case OMPD_barrier: + case OMPD_taskwait: + case OMPD_cancellation_point: + case OMPD_flush: + case OMPD_declare_reduction: + case OMPD_declare_simd: + case OMPD_declare_target: + case OMPD_end_declare_target: + case OMPD_teams: + case OMPD_simd: + case OMPD_for: + case OMPD_for_simd: + case OMPD_sections: + case OMPD_section: + case OMPD_single: + case OMPD_master: + case OMPD_critical: + case OMPD_taskgroup: + case OMPD_distribute: + case OMPD_ordered: + case OMPD_atomic: + case OMPD_distribute_simd: + case OMPD_teams_distribute: + case OMPD_teams_distribute_simd: + llvm_unreachable("Unexpected OpenMP directive with if-clause"); + case OMPD_unknown: + llvm_unreachable("Unknown OpenMP directive"); + } + break; + case OMPC_num_threads: + switch (DKind) { + case OMPD_target_parallel: + CaptureRegion = OMPD_target; + break; + case OMPD_cancel: + case OMPD_parallel: + case OMPD_parallel_sections: + case OMPD_parallel_for: + case OMPD_parallel_for_simd: + case OMPD_target: + case OMPD_target_simd: + case OMPD_target_parallel_for: + case OMPD_target_parallel_for_simd: + case OMPD_target_teams: + case OMPD_target_teams_distribute: + case OMPD_target_teams_distribute_simd: + case OMPD_target_teams_distribute_parallel_for: + case OMPD_target_teams_distribute_parallel_for_simd: + case OMPD_teams_distribute_parallel_for: + case OMPD_teams_distribute_parallel_for_simd: + case OMPD_distribute_parallel_for: + case OMPD_distribute_parallel_for_simd: + case OMPD_task: + case OMPD_taskloop: + case OMPD_taskloop_simd: + case OMPD_target_data: + case OMPD_target_enter_data: + case OMPD_target_exit_data: + case OMPD_target_update: + // Do not capture num_threads-clause expressions. + break; + case OMPD_threadprivate: + case OMPD_taskyield: + case OMPD_barrier: + case OMPD_taskwait: + case OMPD_cancellation_point: + case OMPD_flush: + case OMPD_declare_reduction: + case OMPD_declare_simd: + case OMPD_declare_target: + case OMPD_end_declare_target: + case OMPD_teams: + case OMPD_simd: + case OMPD_for: + case OMPD_for_simd: + case OMPD_sections: + case OMPD_section: + case OMPD_single: + case OMPD_master: + case OMPD_critical: + case OMPD_taskgroup: + case OMPD_distribute: + case OMPD_ordered: + case OMPD_atomic: + case OMPD_distribute_simd: + case OMPD_teams_distribute: + case OMPD_teams_distribute_simd: + llvm_unreachable("Unexpected OpenMP directive with num_threads-clause"); + case OMPD_unknown: + llvm_unreachable("Unknown OpenMP directive"); + } + break; + case OMPC_num_teams: + switch (DKind) { + case OMPD_target_teams: + CaptureRegion = OMPD_target; + break; + case OMPD_cancel: + case OMPD_parallel: + case OMPD_parallel_sections: + case OMPD_parallel_for: + case OMPD_parallel_for_simd: + case OMPD_target: + case OMPD_target_simd: + case OMPD_target_parallel: + case OMPD_target_parallel_for: + case OMPD_target_parallel_for_simd: + case OMPD_target_teams_distribute: + case OMPD_target_teams_distribute_simd: + case OMPD_target_teams_distribute_parallel_for: + case OMPD_target_teams_distribute_parallel_for_simd: + case OMPD_teams_distribute_parallel_for: + case OMPD_teams_distribute_parallel_for_simd: + case OMPD_distribute_parallel_for: + case OMPD_distribute_parallel_for_simd: + case OMPD_task: + case OMPD_taskloop: + case OMPD_taskloop_simd: + case OMPD_target_data: + case OMPD_target_enter_data: + case OMPD_target_exit_data: + case OMPD_target_update: + case OMPD_teams: + case OMPD_teams_distribute: + case OMPD_teams_distribute_simd: + // Do not capture num_teams-clause expressions. + break; + case OMPD_threadprivate: + case OMPD_taskyield: + case OMPD_barrier: + case OMPD_taskwait: + case OMPD_cancellation_point: + case OMPD_flush: + case OMPD_declare_reduction: + case OMPD_declare_simd: + case OMPD_declare_target: + case OMPD_end_declare_target: + case OMPD_simd: + case OMPD_for: + case OMPD_for_simd: + case OMPD_sections: + case OMPD_section: + case OMPD_single: + case OMPD_master: + case OMPD_critical: + case OMPD_taskgroup: + case OMPD_distribute: + case OMPD_ordered: + case OMPD_atomic: + case OMPD_distribute_simd: + llvm_unreachable("Unexpected OpenMP directive with num_teams-clause"); + case OMPD_unknown: + llvm_unreachable("Unknown OpenMP directive"); + } + break; + case OMPC_thread_limit: + switch (DKind) { + case OMPD_target_teams: + CaptureRegion = OMPD_target; + break; + case OMPD_cancel: + case OMPD_parallel: + case OMPD_parallel_sections: + case OMPD_parallel_for: + case OMPD_parallel_for_simd: + case OMPD_target: + case OMPD_target_simd: + case OMPD_target_parallel: + case OMPD_target_parallel_for: + case OMPD_target_parallel_for_simd: + case OMPD_target_teams_distribute: + case OMPD_target_teams_distribute_simd: + case OMPD_target_teams_distribute_parallel_for: + case OMPD_target_teams_distribute_parallel_for_simd: + case OMPD_teams_distribute_parallel_for: + case OMPD_teams_distribute_parallel_for_simd: + case OMPD_distribute_parallel_for: + case OMPD_distribute_parallel_for_simd: + case OMPD_task: + case OMPD_taskloop: + case OMPD_taskloop_simd: + case OMPD_target_data: + case OMPD_target_enter_data: + case OMPD_target_exit_data: + case OMPD_target_update: + case OMPD_teams: + case OMPD_teams_distribute: + case OMPD_teams_distribute_simd: + // Do not capture thread_limit-clause expressions. + break; + case OMPD_threadprivate: + case OMPD_taskyield: + case OMPD_barrier: + case OMPD_taskwait: + case OMPD_cancellation_point: + case OMPD_flush: + case OMPD_declare_reduction: + case OMPD_declare_simd: + case OMPD_declare_target: + case OMPD_end_declare_target: + case OMPD_simd: + case OMPD_for: + case OMPD_for_simd: + case OMPD_sections: + case OMPD_section: + case OMPD_single: + case OMPD_master: + case OMPD_critical: + case OMPD_taskgroup: + case OMPD_distribute: + case OMPD_ordered: + case OMPD_atomic: + case OMPD_distribute_simd: + llvm_unreachable("Unexpected OpenMP directive with thread_limit-clause"); + case OMPD_unknown: + llvm_unreachable("Unknown OpenMP directive"); + } + break; + case OMPC_schedule: + case OMPC_dist_schedule: + case OMPC_firstprivate: + case OMPC_lastprivate: + case OMPC_reduction: + case OMPC_task_reduction: + case OMPC_linear: + case OMPC_default: + case OMPC_proc_bind: + case OMPC_final: + case OMPC_safelen: + case OMPC_simdlen: + case OMPC_collapse: + case OMPC_private: + case OMPC_shared: + case OMPC_aligned: + case OMPC_copyin: + case OMPC_copyprivate: + case OMPC_ordered: + case OMPC_nowait: + case OMPC_untied: + case OMPC_mergeable: + case OMPC_threadprivate: + case OMPC_flush: + case OMPC_read: + case OMPC_write: + case OMPC_update: + case OMPC_capture: + case OMPC_seq_cst: + case OMPC_depend: + case OMPC_device: + case OMPC_threads: + case OMPC_simd: + case OMPC_map: + case OMPC_priority: + case OMPC_grainsize: + case OMPC_nogroup: + case OMPC_num_tasks: + case OMPC_hint: + case OMPC_defaultmap: + case OMPC_unknown: + case OMPC_uniform: + case OMPC_to: + case OMPC_from: + case OMPC_use_device_ptr: + case OMPC_is_device_ptr: + llvm_unreachable("Unexpected OpenMP clause."); + } + return CaptureRegion; +} + OMPClause *Sema::ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier, Expr *Condition, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -6558,6 +7209,8 @@ OMPClause *Sema::ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier, SourceLocation ColonLoc, SourceLocation EndLoc) { Expr *ValExpr = Condition; + Stmt *HelperValStmt = nullptr; + OpenMPDirectiveKind CaptureRegion = OMPD_unknown; if (!Condition->isValueDependent() && !Condition->isTypeDependent() && !Condition->isInstantiationDependent() && !Condition->containsUnexpandedParameterPack()) { @@ -6566,10 +7219,20 @@ OMPClause *Sema::ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier, return nullptr; ValExpr = MakeFullExpr(Val.get()).get(); + + OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); + CaptureRegion = + getOpenMPCaptureRegionForClause(DKind, OMPC_if, NameModifier); + if (CaptureRegion != OMPD_unknown) { + llvm::MapVector<Expr *, DeclRefExpr *> Captures; + ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); + HelperValStmt = buildPreInits(Context, Captures); + } } - return new (Context) OMPIfClause(NameModifier, ValExpr, StartLoc, LParenLoc, - NameModifierLoc, ColonLoc, EndLoc); + return new (Context) + OMPIfClause(NameModifier, ValExpr, HelperValStmt, CaptureRegion, StartLoc, + LParenLoc, NameModifierLoc, ColonLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition, @@ -6665,6 +7328,8 @@ OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads, SourceLocation LParenLoc, SourceLocation EndLoc) { Expr *ValExpr = NumThreads; + Stmt *HelperValStmt = nullptr; + OpenMPDirectiveKind CaptureRegion = OMPD_unknown; // OpenMP [2.5, Restrictions] // The num_threads expression must evaluate to a positive integer value. @@ -6672,8 +7337,16 @@ OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads, /*StrictlyPositive=*/true)) return nullptr; - return new (Context) - OMPNumThreadsClause(ValExpr, StartLoc, LParenLoc, EndLoc); + OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); + CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_num_threads); + if (CaptureRegion != OMPD_unknown) { + llvm::MapVector<Expr *, DeclRefExpr *> Captures; + ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); + HelperValStmt = buildPreInits(Context, Captures); + } + + return new (Context) OMPNumThreadsClause( + ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc); } ExprResult Sema::VerifyPositiveIntegerConstantInClause(Expr *E, @@ -6799,6 +7472,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_lastprivate: case OMPC_shared: case OMPC_reduction: + case OMPC_task_reduction: case OMPC_linear: case OMPC_aligned: case OMPC_copyin: @@ -6956,6 +7630,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_lastprivate: case OMPC_shared: case OMPC_reduction: + case OMPC_task_reduction: case OMPC_linear: case OMPC_aligned: case OMPC_copyin: @@ -7153,6 +7828,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_lastprivate: case OMPC_shared: case OMPC_reduction: + case OMPC_task_reduction: case OMPC_linear: case OMPC_aligned: case OMPC_copyin: @@ -7265,6 +7941,11 @@ OMPClause *Sema::ActOnOpenMPVarListClause( Res = ActOnOpenMPReductionClause(VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec, ReductionId); break; + case OMPC_task_reduction: + Res = ActOnOpenMPTaskReductionClause(VarList, StartLoc, LParenLoc, ColonLoc, + EndLoc, ReductionIdScopeSpec, + ReductionId); + break; case OMPC_linear: Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc, LinKind, DepLinMapLoc, ColonLoc, EndLoc); @@ -8233,15 +8914,66 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range, return ExprEmpty(); } -OMPClause *Sema::ActOnOpenMPReductionClause( +namespace { +/// Data for the reduction-based clauses. +struct ReductionData { + /// List of original reduction items. + SmallVector<Expr *, 8> Vars; + /// List of private copies of the reduction items. + SmallVector<Expr *, 8> Privates; + /// LHS expressions for the reduction_op expressions. + SmallVector<Expr *, 8> LHSs; + /// RHS expressions for the reduction_op expressions. + SmallVector<Expr *, 8> RHSs; + /// Reduction operation expression. + SmallVector<Expr *, 8> ReductionOps; + /// List of captures for clause. + SmallVector<Decl *, 4> ExprCaptures; + /// List of postupdate expressions. + SmallVector<Expr *, 4> ExprPostUpdates; + ReductionData() = delete; + /// Reserves required memory for the reduction data. + ReductionData(unsigned Size) { + Vars.reserve(Size); + Privates.reserve(Size); + LHSs.reserve(Size); + RHSs.reserve(Size); + ReductionOps.reserve(Size); + ExprCaptures.reserve(Size); + ExprPostUpdates.reserve(Size); + } + /// Stores reduction item and reduction operation only (required for dependent + /// reduction item). + void push(Expr *Item, Expr *ReductionOp) { + Vars.emplace_back(Item); + Privates.emplace_back(nullptr); + LHSs.emplace_back(nullptr); + RHSs.emplace_back(nullptr); + ReductionOps.emplace_back(ReductionOp); + } + /// Stores reduction data. + void push(Expr *Item, Expr *Private, Expr *LHS, Expr *RHS, + Expr *ReductionOp) { + Vars.emplace_back(Item); + Privates.emplace_back(Private); + LHSs.emplace_back(LHS); + RHSs.emplace_back(RHS); + ReductionOps.emplace_back(ReductionOp); + } +}; +} // namespace + +static bool ActOnOMPReductionKindClause( + Sema &S, DSAStackTy *Stack, OpenMPClauseKind ClauseKind, ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, - ArrayRef<Expr *> UnresolvedReductions) { + ArrayRef<Expr *> UnresolvedReductions, ReductionData &RD) { auto DN = ReductionId.getName(); auto OOK = DN.getCXXOverloadedOperator(); BinaryOperatorKind BOK = BO_Comma; + ASTContext &Context = S.Context; // OpenMP [2.14.3.6, reduction clause] // C // reduction-identifier is either an identifier or one of the following @@ -8325,13 +9057,6 @@ OMPClause *Sema::ActOnOpenMPReductionClause( ReductionIdRange.setBegin(ReductionIdScopeSpec.getBeginLoc()); ReductionIdRange.setEnd(ReductionId.getEndLoc()); - 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) { @@ -8349,27 +9074,23 @@ OMPClause *Sema::ActOnOpenMPReductionClause( SourceLocation ELoc; SourceRange ERange; Expr *SimpleRefExpr = RefExpr; - auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange, + auto Res = getPrivateItem(S, 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, + S, ELoc, ERange, Stack->getCurScope(), ReductionIdScopeSpec, ReductionId, Type, BasePath, IR == ER ? nullptr : *IR); - if (CurContext->isDependentContext() && + Expr *ReductionOp = nullptr; + if (S.CurContext->isDependentContext() && (DeclareReductionRef.isUnset() || isa<UnresolvedLookupExpr>(DeclareReductionRef.get()))) - ReductionOps.push_back(DeclareReductionRef.get()); - else - ReductionOps.push_back(nullptr); + ReductionOp = DeclareReductionRef.get(); + // It will be analyzed later. + RD.push(RefExpr, ReductionOp); } ValueDecl *D = Res.first; if (!D) @@ -8394,21 +9115,19 @@ OMPClause *Sema::ActOnOpenMPReductionClause( // 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_reduction_incomplete_type)) + if (S.RequireCompleteType(ELoc, Type, + diag::err_omp_reduction_incomplete_type)) 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; + S.Diag(ELoc, diag::err_omp_const_reduction_list_item) << ERange; if (!ASE && !OASE) { - bool IsDecl = !VD || - VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(D->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) + bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + S.Diag(D->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) << D; } continue; @@ -8419,10 +9138,11 @@ OMPClause *Sema::ActOnOpenMPReductionClause( if (!ASE && !OASE && VD) { VarDecl *VDDef = VD->getDefinition(); if (VD->getType()->isReferenceType() && VDDef && VDDef->hasInit()) { - DSARefChecker Check(DSAStack); + DSARefChecker Check(Stack); if (Check.Visit(VDDef->getInit())) { - Diag(ELoc, diag::err_omp_reduction_ref_type_arg) << ERange; - Diag(VDDef->getLocation(), diag::note_defined_here) << VDDef; + S.Diag(ELoc, diag::err_omp_reduction_ref_type_arg) + << getOpenMPClauseName(ClauseKind) << ERange; + S.Diag(VDDef->getLocation(), diag::note_defined_here) << VDDef; continue; } } @@ -8440,17 +9160,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(D, false); + DVar = Stack->getTopDSA(D, false); if (DVar.CKind == OMPC_reduction) { - Diag(ELoc, diag::err_omp_once_referenced) - << getOpenMPClauseName(OMPC_reduction); + S.Diag(ELoc, diag::err_omp_once_referenced) + << getOpenMPClauseName(ClauseKind); if (DVar.RefExpr) - Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced); + S.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced); } else if (DVar.CKind != OMPC_unknown) { - Diag(ELoc, diag::err_omp_wrong_dsa) + S.Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_reduction); - ReportOriginalDSA(*this, DSAStack, D, DVar); + ReportOriginalDSA(S, Stack, D, DVar); continue; } @@ -8458,16 +9178,16 @@ OMPClause *Sema::ActOnOpenMPReductionClause( // A list item that appears in a reduction clause of a worksharing // construct must be shared in the parallel regions to which any of the // worksharing regions arising from the worksharing construct bind. - OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective(); + OpenMPDirectiveKind CurrDir = Stack->getCurrentDirective(); if (isOpenMPWorksharingDirective(CurrDir) && !isOpenMPParallelDirective(CurrDir) && !isOpenMPTeamsDirective(CurrDir)) { - DVar = DSAStack->getImplicitDSA(D, true); + DVar = Stack->getImplicitDSA(D, true); if (DVar.CKind != OMPC_shared) { - Diag(ELoc, diag::err_omp_required_access) + S.Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseName(OMPC_reduction) << getOpenMPClauseName(OMPC_shared); - ReportOriginalDSA(*this, DSAStack, D, DVar); + ReportOriginalDSA(S, Stack, D, DVar); continue; } } @@ -8476,24 +9196,20 @@ OMPClause *Sema::ActOnOpenMPReductionClause( // builtin/overloaded operators. CXXCastPath BasePath; ExprResult DeclareReductionRef = buildDeclareReductionRef( - *this, ELoc, ERange, DSAStack->getCurScope(), ReductionIdScopeSpec, + S, ELoc, ERange, Stack->getCurScope(), ReductionIdScopeSpec, ReductionId, Type, BasePath, IR == ER ? nullptr : *IR); if (DeclareReductionRef.isInvalid()) continue; - if (CurContext->isDependentContext() && + if (S.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()); + RD.push(RefExpr, DeclareReductionRef.get()); continue; } if (BOK == BO_Comma && DeclareReductionRef.isUnset()) { // Not allowed reduction identifier is found. - Diag(ReductionId.getLocStart(), - diag::err_omp_unknown_reduction_identifier) + S.Diag(ReductionId.getLocStart(), + diag::err_omp_unknown_reduction_identifier) << Type << ReductionIdRange; continue; } @@ -8509,28 +9225,27 @@ OMPClause *Sema::ActOnOpenMPReductionClause( 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; + (S.getLangOpts().CPlusPlus && Type->isArithmeticType()))) { + S.Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg) + << getOpenMPClauseName(ClauseKind) << S.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) + bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + S.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); + !S.getLangOpts().CPlusPlus && Type->isFloatingType()) { + S.Diag(ELoc, diag::err_omp_clause_floating_type_arg) + << getOpenMPClauseName(ClauseKind); if (!ASE && !OASE) { - bool IsDecl = !VD || - VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(D->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) + bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + S.Diag(D->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) << D; } continue; @@ -8538,9 +9253,9 @@ OMPClause *Sema::ActOnOpenMPReductionClause( } Type = Type.getNonLValueExprType(Context).getUnqualifiedType(); - auto *LHSVD = buildVarDecl(*this, ELoc, Type, ".reduction.lhs", + auto *LHSVD = buildVarDecl(S, ELoc, Type, ".reduction.lhs", D->hasAttrs() ? &D->getAttrs() : nullptr); - auto *RHSVD = buildVarDecl(*this, ELoc, Type, D->getName(), + auto *RHSVD = buildVarDecl(S, ELoc, Type, D->getName(), D->hasAttrs() ? &D->getAttrs() : nullptr); auto PrivateTy = Type; if (OASE || @@ -8552,19 +9267,20 @@ OMPClause *Sema::ActOnOpenMPReductionClause( // For array subscripts or single variables Private Ty is the same as Type // (type of the variable or single array element). PrivateTy = Context.getVariableArrayType( - Type, new (Context) OpaqueValueExpr(SourceLocation(), - Context.getSizeType(), VK_RValue), + 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, D->getName(), + auto *PrivateVD = buildVarDecl(S, ELoc, PrivateTy, D->getName(), D->hasAttrs() ? &D->getAttrs() : nullptr); // Add initializer for private variable. Expr *Init = nullptr; - auto *LHSDRE = buildDeclRefExpr(*this, LHSVD, Type, ELoc); - auto *RHSDRE = buildDeclRefExpr(*this, RHSVD, Type, ELoc); + auto *LHSDRE = buildDeclRefExpr(S, LHSVD, Type, ELoc); + auto *RHSDRE = buildDeclRefExpr(S, RHSVD, Type, ELoc); if (DeclareReductionRef.isUsable()) { auto *DRDRef = DeclareReductionRef.getAs<DeclRefExpr>(); auto *DRD = cast<OMPDeclareReductionDecl>(DRDRef->getDecl()); @@ -8581,13 +9297,13 @@ OMPClause *Sema::ActOnOpenMPReductionClause( case BO_LOr: // '+', '-', '^', '|', '||' reduction ops - initializer is '0'. if (Type->isScalarType() || Type->isAnyComplexType()) - Init = ActOnIntegerConstant(ELoc, /*Val=*/0).get(); + Init = S.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(); + Init = S.ActOnIntegerConstant(ELoc, /*Val=*/1).get(); } break; case BO_And: { @@ -8610,7 +9326,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause( if (Init && OrigType->isAnyComplexType()) { // Init = 0xFFFF + 0xFFFFi; auto *Im = new (Context) ImaginaryLiteral(Init, OrigType); - Init = CreateBuiltinBinOp(ELoc, BO_Add, Init, Im).get(); + Init = S.CreateBuiltinBinOp(ELoc, BO_Add, Init, Im).get(); } Type = OrigType; break; @@ -8627,15 +9343,14 @@ OMPClause *Sema::ActOnOpenMPReductionClause( 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); + (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( + auto CastExpr = S.BuildCStyleCastExpr( SourceLocation(), Context.getTrivialTypeSourceInfo(Type, ELoc), SourceLocation(), Init); if (CastExpr.isInvalid()) @@ -8676,20 +9391,19 @@ OMPClause *Sema::ActOnOpenMPReductionClause( llvm_unreachable("Unexpected reduction operation"); } } - if (Init && DeclareReductionRef.isUnset()) { - AddInitializerToDecl(RHSVD, Init, /*DirectInit=*/false); - } else if (!Init) - ActOnUninitializedDecl(RHSVD); + if (Init && DeclareReductionRef.isUnset()) + S.AddInitializerToDecl(RHSVD, Init, /*DirectInit=*/false); + else if (!Init) + S.ActOnUninitializedDecl(RHSVD); if (RHSVD->isInvalidDecl()) continue; if (!RHSVD->hasInit() && DeclareReductionRef.isUnset()) { - Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type - << ReductionIdRange; - bool IsDecl = - !VD || - VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(D->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) + S.Diag(ELoc, diag::err_omp_reduction_id_not_compatible) + << Type << ReductionIdRange; + bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + S.Diag(D->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) << D; continue; } @@ -8697,16 +9411,16 @@ OMPClause *Sema::ActOnOpenMPReductionClause( // codegen. PrivateVD->setInit(RHSVD->getInit()); PrivateVD->setInitStyle(RHSVD->getInitStyle()); - auto *PrivateDRE = buildDeclRefExpr(*this, PrivateVD, PrivateTy, ELoc); + auto *PrivateDRE = buildDeclRefExpr(S, PrivateVD, PrivateTy, ELoc); 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); + ExprResult LHS = S.CreateBuiltinUnaryOp(ELoc, UO_AddrOf, LHSDRE); + ExprResult RHS = S.CreateBuiltinUnaryOp(ELoc, UO_AddrOf, RHSDRE); if (!BasePath.empty()) { - LHS = DefaultLvalueConversion(LHS.get()); - RHS = DefaultLvalueConversion(RHS.get()); + LHS = S.DefaultLvalueConversion(LHS.get()); + RHS = S.DefaultLvalueConversion(RHS.get()); LHS = ImplicitCastExpr::Create(Context, PtrRedTy, CK_UncheckedDerivedToBase, LHS.get(), &BasePath, LHS.get()->getValueKind()); @@ -8719,27 +9433,27 @@ OMPClause *Sema::ActOnOpenMPReductionClause( 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()); + S.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); + ReductionOp = S.BuildBinOp( + Stack->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()); + S.BuildBinOp(Stack->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); + S.BuildBinOp(Stack->getCurScope(), ReductionId.getLocStart(), + BO_Assign, LHSDRE, ConditionalOp); } - ReductionOp = ActOnFinishFullExpr(ReductionOp.get()); + ReductionOp = S.ActOnFinishFullExpr(ReductionOp.get()); } if (ReductionOp.isInvalid()) continue; @@ -8747,48 +9461,86 @@ OMPClause *Sema::ActOnOpenMPReductionClause( DeclRefExpr *Ref = nullptr; Expr *VarsExpr = RefExpr->IgnoreParens(); - if (!VD && !CurContext->isDependentContext()) { + if (!VD && !S.CurContext->isDependentContext()) { if (ASE || OASE) { - TransformExprToCaptures RebuildToCapture(*this, D); + TransformExprToCaptures RebuildToCapture(S, D); VarsExpr = RebuildToCapture.TransformExpr(RefExpr->IgnoreParens()).get(); Ref = RebuildToCapture.getCapturedExpr(); } else { - VarsExpr = Ref = - buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false); + VarsExpr = Ref = buildCapture(S, D, SimpleRefExpr, /*WithInit=*/false); } - if (!IsOpenMPCapturedDecl(D)) { - ExprCaptures.push_back(Ref->getDecl()); + if (!S.IsOpenMPCapturedDecl(D)) { + RD.ExprCaptures.emplace_back(Ref->getDecl()); if (Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>()) { - ExprResult RefRes = DefaultLvalueConversion(Ref); + ExprResult RefRes = S.DefaultLvalueConversion(Ref); if (!RefRes.isUsable()) continue; ExprResult PostUpdateRes = - BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, - SimpleRefExpr, RefRes.get()); + S.BuildBinOp(Stack->getCurScope(), ELoc, BO_Assign, SimpleRefExpr, + RefRes.get()); if (!PostUpdateRes.isUsable()) continue; - ExprPostUpdates.push_back( - IgnoredValueConversions(PostUpdateRes.get()).get()); + if (isOpenMPTaskingDirective(Stack->getCurrentDirective()) || + Stack->getCurrentDirective() == OMPD_taskgroup) { + S.Diag(RefExpr->getExprLoc(), + diag::err_omp_reduction_non_addressable_expression) + << RefExpr->getSourceRange(); + continue; + } + RD.ExprPostUpdates.emplace_back( + S.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); - ReductionOps.push_back(ReductionOp.get()); + // All reduction items are still marked as reduction (to do not increase + // code base size). + Stack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref); + RD.push(VarsExpr, PrivateDRE, LHSDRE, RHSDRE, ReductionOp.get()); } + return RD.Vars.empty(); +} - if (Vars.empty()) +OMPClause *Sema::ActOnOpenMPReductionClause( + ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation EndLoc, + CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, + ArrayRef<Expr *> UnresolvedReductions) { + ReductionData RD(VarList.size()); + + if (ActOnOMPReductionKindClause(*this, DSAStack, OMPC_reduction, VarList, + StartLoc, LParenLoc, ColonLoc, EndLoc, + ReductionIdScopeSpec, ReductionId, + UnresolvedReductions, RD)) return nullptr; return OMPReductionClause::Create( - Context, StartLoc, LParenLoc, ColonLoc, EndLoc, Vars, - ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, Privates, - LHSs, RHSs, ReductionOps, buildPreInits(Context, ExprCaptures), - buildPostUpdate(*this, ExprPostUpdates)); + Context, StartLoc, LParenLoc, ColonLoc, EndLoc, RD.Vars, + ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, + RD.Privates, RD.LHSs, RD.RHSs, RD.ReductionOps, + buildPreInits(Context, RD.ExprCaptures), + buildPostUpdate(*this, RD.ExprPostUpdates)); +} + +OMPClause *Sema::ActOnOpenMPTaskReductionClause( + ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation EndLoc, + CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, + ArrayRef<Expr *> UnresolvedReductions) { + ReductionData RD(VarList.size()); + + if (ActOnOMPReductionKindClause(*this, DSAStack, OMPC_task_reduction, + VarList, StartLoc, LParenLoc, ColonLoc, + EndLoc, ReductionIdScopeSpec, ReductionId, + UnresolvedReductions, RD)) + return nullptr; + + return OMPTaskReductionClause::Create( + Context, StartLoc, LParenLoc, ColonLoc, EndLoc, RD.Vars, + ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, + RD.Privates, RD.LHSs, RD.RHSs, RD.ReductionOps, + buildPreInits(Context, RD.ExprCaptures), + buildPostUpdate(*this, RD.ExprPostUpdates)); } bool Sema::CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind, @@ -10451,7 +11203,8 @@ void Sema::ActOnOpenMPDeclareReductionCombinerStart(Scope *S, Decl *D) { else CurContext = DRD; - PushExpressionEvaluationContext(PotentiallyEvaluated); + PushExpressionEvaluationContext( + ExpressionEvaluationContext::PotentiallyEvaluated); QualType ReductionType = DRD->getType(); // Create 'T* omp_parm;T omp_in;'. All references to 'omp_in' will @@ -10505,7 +11258,8 @@ void Sema::ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D) { else CurContext = DRD; - PushExpressionEvaluationContext(PotentiallyEvaluated); + PushExpressionEvaluationContext( + ExpressionEvaluationContext::PotentiallyEvaluated); QualType ReductionType = DRD->getType(); // Create 'T* omp_parm;T omp_priv;'. All references to 'omp_priv' will @@ -10566,6 +11320,8 @@ OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams, SourceLocation LParenLoc, SourceLocation EndLoc) { Expr *ValExpr = NumTeams; + Stmt *HelperValStmt = nullptr; + OpenMPDirectiveKind CaptureRegion = OMPD_unknown; // OpenMP [teams Constrcut, Restrictions] // The num_teams expression must evaluate to a positive integer value. @@ -10573,7 +11329,16 @@ OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams, /*StrictlyPositive=*/true)) return nullptr; - return new (Context) OMPNumTeamsClause(ValExpr, StartLoc, LParenLoc, EndLoc); + OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); + CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_num_teams); + if (CaptureRegion != OMPD_unknown) { + llvm::MapVector<Expr *, DeclRefExpr *> Captures; + ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); + HelperValStmt = buildPreInits(Context, Captures); + } + + return new (Context) OMPNumTeamsClause(ValExpr, HelperValStmt, CaptureRegion, + StartLoc, LParenLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPThreadLimitClause(Expr *ThreadLimit, @@ -10581,6 +11346,8 @@ OMPClause *Sema::ActOnOpenMPThreadLimitClause(Expr *ThreadLimit, SourceLocation LParenLoc, SourceLocation EndLoc) { Expr *ValExpr = ThreadLimit; + Stmt *HelperValStmt = nullptr; + OpenMPDirectiveKind CaptureRegion = OMPD_unknown; // OpenMP [teams Constrcut, Restrictions] // The thread_limit expression must evaluate to a positive integer value. @@ -10588,8 +11355,16 @@ OMPClause *Sema::ActOnOpenMPThreadLimitClause(Expr *ThreadLimit, /*StrictlyPositive=*/true)) return nullptr; - return new (Context) - OMPThreadLimitClause(ValExpr, StartLoc, LParenLoc, EndLoc); + OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); + CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_thread_limit); + if (CaptureRegion != OMPD_unknown) { + llvm::MapVector<Expr *, DeclRefExpr *> Captures; + ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); + HelperValStmt = buildPreInits(Context, Captures); + } + + return new (Context) OMPThreadLimitClause( + ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPPriorityClause(Expr *Priority, |