diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-07-31 21:22:58 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-07-31 21:22:58 +0000 |
commit | 5ffd83dbcc34f10e07f6d3e968ae6365869615f4 (patch) | |
tree | 0e9f5cf729dde39f949698fddef45a34e2bc7f44 /contrib/llvm-project/clang/lib/Sema/SemaOpenMP.cpp | |
parent | 1799696096df87b52968b8996d00c91e0a5de8d9 (diff) | |
parent | cfca06d7963fa0909f90483b42a6d7d194d01e08 (diff) |
Notes
Diffstat (limited to 'contrib/llvm-project/clang/lib/Sema/SemaOpenMP.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Sema/SemaOpenMP.cpp | 3883 |
1 files changed, 2882 insertions, 1001 deletions
diff --git a/contrib/llvm-project/clang/lib/Sema/SemaOpenMP.cpp b/contrib/llvm-project/clang/lib/Sema/SemaOpenMP.cpp index 3fce0e27e9b3..920463da4027 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaOpenMP.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaOpenMP.cpp @@ -18,12 +18,15 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclOpenMP.h" +#include "clang/AST/OpenMPClause.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtOpenMP.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/TypeOrdering.h" +#include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" @@ -31,7 +34,10 @@ #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/IndexedMap.h" #include "llvm/ADT/PointerEmbeddedInt.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" +#include <set> + using namespace clang; using namespace llvm::omp; @@ -47,9 +53,10 @@ static const Expr *checkMapClauseExpressionBase( namespace { /// Default data sharing attributes, which can be applied to directive. enum DefaultDataSharingAttributes { - DSA_unspecified = 0, /// Data sharing attribute not specified. - DSA_none = 1 << 0, /// Default data sharing attribute 'none'. - DSA_shared = 1 << 1, /// Default data sharing attribute 'shared'. + DSA_unspecified = 0, /// Data sharing attribute not specified. + DSA_none = 1 << 0, /// Default data sharing attribute 'none'. + DSA_shared = 1 << 1, /// Default data sharing attribute 'shared'. + DSA_firstprivate = 1 << 2, /// Default data sharing attribute 'firstprivate'. }; /// Stack for tracking declarations used in OpenMP directives and @@ -59,24 +66,35 @@ public: struct DSAVarData { OpenMPDirectiveKind DKind = OMPD_unknown; OpenMPClauseKind CKind = OMPC_unknown; + unsigned Modifier = 0; const Expr *RefExpr = nullptr; DeclRefExpr *PrivateCopy = nullptr; SourceLocation ImplicitDSALoc; DSAVarData() = default; DSAVarData(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, const Expr *RefExpr, DeclRefExpr *PrivateCopy, - SourceLocation ImplicitDSALoc) - : DKind(DKind), CKind(CKind), RefExpr(RefExpr), + SourceLocation ImplicitDSALoc, unsigned Modifier) + : DKind(DKind), CKind(CKind), Modifier(Modifier), RefExpr(RefExpr), PrivateCopy(PrivateCopy), ImplicitDSALoc(ImplicitDSALoc) {} }; using OperatorOffsetTy = llvm::SmallVector<std::pair<Expr *, OverloadedOperatorKind>, 4>; using DoacrossDependMapTy = llvm::DenseMap<OMPDependClause *, OperatorOffsetTy>; + /// Kind of the declaration used in the uses_allocators clauses. + enum class UsesAllocatorsDeclKind { + /// Predefined allocator + PredefinedAllocator, + /// User-defined allocator + UserDefinedAllocator, + /// The declaration that represent allocator trait + AllocatorTrait, + }; private: struct DSAInfo { OpenMPClauseKind Attributes = OMPC_unknown; + unsigned Modifier = 0; /// Pointer to a reference expression and a flag which shows that the /// variable is marked as lastprivate(true) or not (false). llvm::PointerIntPair<const Expr *, 1, bool> RefExpr; @@ -151,13 +169,21 @@ private: bool CancelRegion = false; bool LoopStart = false; bool BodyComplete = false; + SourceLocation PrevScanLocation; + SourceLocation PrevOrderedLocation; SourceLocation InnerTeamsRegionLoc; /// Reference to the taskgroup task_reduction reference expression. Expr *TaskgroupReductionRef = nullptr; llvm::DenseSet<QualType> MappedClassesQualTypes; + SmallVector<Expr *, 4> InnerUsedAllocators; + llvm::DenseSet<CanonicalDeclPtr<Decl>> ImplicitTaskFirstprivates; /// List of globals marked as declare target link in this target region /// (isOpenMPTargetExecutionDirective(Directive) == true). llvm::SmallVector<DeclRefExpr *, 4> DeclareTargetLinkVarDecls; + /// List of decls used in inclusive/exclusive clauses of the scan directive. + llvm::DenseSet<CanonicalDeclPtr<Decl>> UsedInScanDirective; + llvm::DenseMap<CanonicalDeclPtr<const Decl>, UsesAllocatorsDeclKind> + UsesAllocatorsDecls; SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name, Scope *CurScope, SourceLocation Loc) : Directive(DKind), DirectiveName(Name), CurScope(CurScope), @@ -263,11 +289,18 @@ private: SmallVector<const OMPRequiresDecl *, 2> RequiresDecls; /// omp_allocator_handle_t type. QualType OMPAllocatorHandleT; + /// omp_depend_t type. + QualType OMPDependT; + /// omp_event_handle_t type. + QualType OMPEventHandleT; + /// omp_alloctrait_t type. + QualType OMPAlloctraitT; /// Expression for the predefined allocators. Expr *OMPPredefinedAllocators[OMPAllocateDeclAttr::OMPUserDefinedMemAlloc] = { nullptr}; /// Vector of previously encountered target directives SmallVector<SourceLocation, 2> TargetLocations; + SourceLocation AtomicLocation; public: explicit DSAStackTy(Sema &S) : SemaRef(S) {} @@ -276,6 +309,10 @@ public: void setOMPAllocatorHandleT(QualType Ty) { OMPAllocatorHandleT = Ty; } /// Gets omp_allocator_handle_t type. QualType getOMPAllocatorHandleT() const { return OMPAllocatorHandleT; } + /// Sets omp_alloctrait_t type. + void setOMPAlloctraitT(QualType Ty) { OMPAlloctraitT = Ty; } + /// Gets omp_alloctrait_t type. + QualType getOMPAlloctraitT() const { return OMPAlloctraitT; } /// Sets the given default allocator. void setAllocator(OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind, Expr *Allocator) { @@ -285,6 +322,15 @@ public: Expr *getAllocator(OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind) const { return OMPPredefinedAllocators[AllocatorKind]; } + /// Sets omp_depend_t type. + void setOMPDependT(QualType Ty) { OMPDependT = Ty; } + /// Gets omp_depend_t type. + QualType getOMPDependT() const { return OMPDependT; } + + /// Sets omp_event_handle_t type. + void setOMPEventHandleT(QualType Ty) { OMPEventHandleT = Ty; } + /// Gets omp_event_handle_t type. + QualType getOMPEventHandleT() const { return OMPEventHandleT; } bool isClauseParsingMode() const { return ClauseKindMode != OMPC_unknown; } OpenMPClauseKind getClauseParsingMode() const { @@ -439,13 +485,32 @@ public: /// \return The index of the loop control variable in the list of associated /// for-loops (from outer to inner). const LCDeclInfo isParentLoopControlVariable(const ValueDecl *D) const; + /// 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). + const LCDeclInfo isLoopControlVariable(const ValueDecl *D, + unsigned Level) const; /// Get the loop control variable for the I-th loop (or nullptr) in /// parent directive. const ValueDecl *getParentLoopControlVariable(unsigned I) const; + /// Marks the specified decl \p D as used in scan directive. + void markDeclAsUsedInScanDirective(ValueDecl *D) { + if (SharingMapTy *Stack = getSecondOnStackOrNull()) + Stack->UsedInScanDirective.insert(D); + } + + /// Checks if the specified declaration was used in the inner scan directive. + bool isUsedInScanDirective(ValueDecl *D) const { + if (const SharingMapTy *Stack = getTopOfStackOrNull()) + return Stack->UsedInScanDirective.count(D) > 0; + return false; + } + /// Adds explicit data sharing attribute to the specified declaration. void addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A, - DeclRefExpr *PrivateCopy = nullptr); + DeclRefExpr *PrivateCopy = nullptr, unsigned Modifier = 0); /// Adds additional information for the reduction items with the reduction id /// represented as an operator. @@ -467,11 +532,15 @@ public: getTopMostTaskgroupReductionData(const ValueDecl *D, SourceRange &SR, const Expr *&ReductionRef, Expr *&TaskgroupDescriptor) const; - /// Return reduction reference expression for the current taskgroup. + /// Return reduction reference expression for the current taskgroup or + /// parallel/worksharing directives with task reductions. Expr *getTaskgroupReductionRef() const { - assert(getTopOfStack().Directive == OMPD_taskgroup && - "taskgroup reference expression requested for non taskgroup " - "directive."); + assert((getTopOfStack().Directive == OMPD_taskgroup || + ((isOpenMPParallelDirective(getTopOfStack().Directive) || + isOpenMPWorksharingDirective(getTopOfStack().Directive)) && + !isOpenMPSimdDirective(getTopOfStack().Directive))) && + "taskgroup reference expression requested for non taskgroup or " + "parallel/worksharing directive."); return getTopOfStack().TaskgroupReductionRef; } /// Checks if the given \p VD declaration is actually a taskgroup reduction @@ -487,6 +556,8 @@ public: const DSAVarData getTopDSA(ValueDecl *D, bool FromParent); /// Returns data-sharing attributes for the specified declaration. const DSAVarData getImplicitDSA(ValueDecl *D, bool FromParent) const; + /// Returns data-sharing attributes for the specified declaration. + const DSAVarData getImplicitDSA(ValueDecl *D, unsigned Level) const; /// Checks if the specified variables has data-sharing attributes which /// match specified \a CPred predicate in any directive which matches \a DPred /// predicate. @@ -552,7 +623,7 @@ public: /// Checks if the defined 'requires' directive has specified type of clause. template <typename ClauseType> - bool hasRequiresDeclWithClause() { + bool hasRequiresDeclWithClause() const { return llvm::any_of(RequiresDecls, [](const OMPRequiresDecl *D) { return llvm::any_of(D->clauselists(), [](const OMPClause *C) { return isa<ClauseType>(C); @@ -587,6 +658,18 @@ public: TargetLocations.push_back(LocStart); } + /// Add location for the first encountered atomicc directive. + void addAtomicDirectiveLoc(SourceLocation Loc) { + if (AtomicLocation.isInvalid()) + AtomicLocation = Loc; + } + + /// Returns the location of the first encountered atomic directive in the + /// module. + SourceLocation getAtomicDirectiveLoc() const { + return AtomicLocation; + } + // Return previously encountered target region locations. ArrayRef<SourceLocation> getEncounteredTargetLocs() const { return TargetLocations; @@ -602,6 +685,11 @@ public: getTopOfStack().DefaultAttr = DSA_shared; getTopOfStack().DefaultAttrLoc = Loc; } + /// Set default data sharing attribute to firstprivate. + void setDefaultDSAFirstPrivate(SourceLocation Loc) { + getTopOfStack().DefaultAttr = DSA_firstprivate; + getTopOfStack().DefaultAttrLoc = Loc; + } /// Set default data mapping attribute to Modifier:Kind void setDefaultDMAAttr(OpenMPDefaultmapClauseModifier M, OpenMPDefaultmapClauseKind Kind, @@ -612,10 +700,24 @@ public: } /// Check whether the implicit-behavior has been set in defaultmap bool checkDefaultmapCategory(OpenMPDefaultmapClauseKind VariableCategory) { + if (VariableCategory == OMPC_DEFAULTMAP_unknown) + return getTopOfStack() + .DefaultmapMap[OMPC_DEFAULTMAP_aggregate] + .ImplicitBehavior != OMPC_DEFAULTMAP_MODIFIER_unknown || + getTopOfStack() + .DefaultmapMap[OMPC_DEFAULTMAP_scalar] + .ImplicitBehavior != OMPC_DEFAULTMAP_MODIFIER_unknown || + getTopOfStack() + .DefaultmapMap[OMPC_DEFAULTMAP_pointer] + .ImplicitBehavior != OMPC_DEFAULTMAP_MODIFIER_unknown; return getTopOfStack().DefaultmapMap[VariableCategory].ImplicitBehavior != OMPC_DEFAULTMAP_MODIFIER_unknown; } + DefaultDataSharingAttributes getDefaultDSA(unsigned Level) const { + return getStackSize() <= Level ? DSA_unspecified + : getStackElemAtLevel(Level).DefaultAttr; + } DefaultDataSharingAttributes getDefaultDSA() const { return isStackEmpty() ? DSA_unspecified : getTopOfStack().DefaultAttr; @@ -738,6 +840,37 @@ public: return Top ? Top->CancelRegion : false; } + /// Mark that parent region already has scan directive. + void setParentHasScanDirective(SourceLocation Loc) { + if (SharingMapTy *Parent = getSecondOnStackOrNull()) + Parent->PrevScanLocation = Loc; + } + /// Return true if current region has inner cancel construct. + bool doesParentHasScanDirective() const { + const SharingMapTy *Top = getSecondOnStackOrNull(); + return Top ? Top->PrevScanLocation.isValid() : false; + } + /// Return true if current region has inner cancel construct. + SourceLocation getParentScanDirectiveLoc() const { + const SharingMapTy *Top = getSecondOnStackOrNull(); + return Top ? Top->PrevScanLocation : SourceLocation(); + } + /// Mark that parent region already has ordered directive. + void setParentHasOrderedDirective(SourceLocation Loc) { + if (SharingMapTy *Parent = getSecondOnStackOrNull()) + Parent->PrevOrderedLocation = Loc; + } + /// Return true if current region has inner ordered construct. + bool doesParentHasOrderedDirective() const { + const SharingMapTy *Top = getSecondOnStackOrNull(); + return Top ? Top->PrevOrderedLocation.isValid() : false; + } + /// Returns the location of the previously specified ordered directive. + SourceLocation getParentOrderedDirectiveLoc() const { + const SharingMapTy *Top = getSecondOnStackOrNull(); + return Top ? Top->PrevOrderedLocation : SourceLocation(); + } + /// Set collapse value for the region. void setAssociatedLoops(unsigned Val) { getTopOfStack().AssociatedLoops = Val; @@ -899,6 +1032,46 @@ public: "Expected target executable directive."); return getTopOfStack().DeclareTargetLinkVarDecls; } + + /// Adds list of allocators expressions. + void addInnerAllocatorExpr(Expr *E) { + getTopOfStack().InnerUsedAllocators.push_back(E); + } + /// Return list of used allocators. + ArrayRef<Expr *> getInnerAllocators() const { + return getTopOfStack().InnerUsedAllocators; + } + /// Marks the declaration as implicitly firstprivate nin the task-based + /// regions. + void addImplicitTaskFirstprivate(unsigned Level, Decl *D) { + getStackElemAtLevel(Level).ImplicitTaskFirstprivates.insert(D); + } + /// Checks if the decl is implicitly firstprivate in the task-based region. + bool isImplicitTaskFirstprivate(Decl *D) const { + return getTopOfStack().ImplicitTaskFirstprivates.count(D) > 0; + } + + /// Marks decl as used in uses_allocators clause as the allocator. + void addUsesAllocatorsDecl(const Decl *D, UsesAllocatorsDeclKind Kind) { + getTopOfStack().UsesAllocatorsDecls.try_emplace(D, Kind); + } + /// Checks if specified decl is used in uses allocator clause as the + /// allocator. + Optional<UsesAllocatorsDeclKind> isUsesAllocatorsDecl(unsigned Level, + const Decl *D) const { + const SharingMapTy &StackElem = getTopOfStack(); + auto I = StackElem.UsesAllocatorsDecls.find(D); + if (I == StackElem.UsesAllocatorsDecls.end()) + return None; + return I->getSecond(); + } + Optional<UsesAllocatorsDeclKind> isUsesAllocatorsDecl(const Decl *D) const { + const SharingMapTy &StackElem = getTopOfStack(); + auto I = StackElem.UsesAllocatorsDecls.find(D); + if (I == StackElem.UsesAllocatorsDecls.end()) + return None; + return I->getSecond(); + } }; bool isImplicitTaskingRegion(OpenMPDirectiveKind DKind) { @@ -1001,6 +1174,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(const_iterator &Iter, DVar.PrivateCopy = Data.PrivateCopy; DVar.CKind = Data.Attributes; DVar.ImplicitDSALoc = Iter->DefaultAttrLoc; + DVar.Modifier = Data.Modifier; return DVar; } @@ -1015,6 +1189,15 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(const_iterator &Iter, return DVar; case DSA_none: return DVar; + case DSA_firstprivate: + if (VD->getStorageDuration() == SD_Static && + VD->getDeclContext()->isFileContext()) { + DVar.CKind = OMPC_unknown; + } else { + DVar.CKind = OMPC_firstprivate; + } + DVar.ImplicitDSALoc = Iter->DefaultAttrLoc; + return DVar; case DSA_unspecified: // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, implicitly determined, p.2] @@ -1113,6 +1296,19 @@ DSAStackTy::isLoopControlVariable(const ValueDecl *D) const { } const DSAStackTy::LCDeclInfo +DSAStackTy::isLoopControlVariable(const ValueDecl *D, unsigned Level) const { + assert(!isStackEmpty() && "Data-sharing attributes stack is empty"); + D = getCanonicalDecl(D); + for (unsigned I = Level + 1; I > 0; --I) { + const SharingMapTy &StackElem = getStackElemAtLevel(I - 1); + auto It = StackElem.LCVMap.find(D); + if (It != StackElem.LCVMap.end()) + return It->second; + } + return {0, nullptr}; +} + +const DSAStackTy::LCDeclInfo DSAStackTy::isParentLoopControlVariable(const ValueDecl *D) const { const SharingMapTy *Parent = getSecondOnStackOrNull(); assert(Parent && "Data-sharing attributes stack is empty"); @@ -1135,19 +1331,21 @@ const ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) const { } void DSAStackTy::addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A, - DeclRefExpr *PrivateCopy) { + DeclRefExpr *PrivateCopy, unsigned Modifier) { D = getCanonicalDecl(D); if (A == OMPC_threadprivate) { DSAInfo &Data = Threadprivates[D]; Data.Attributes = A; Data.RefExpr.setPointer(E); Data.PrivateCopy = nullptr; + Data.Modifier = Modifier; } else { DSAInfo &Data = getTopOfStack().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)); + Data.Modifier = Modifier; if (A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) { Data.RefExpr.setInt(/*IntVal=*/true); return; @@ -1159,6 +1357,7 @@ void DSAStackTy::addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A, Data.PrivateCopy = PrivateCopy; if (PrivateCopy) { DSAInfo &Data = getTopOfStack().SharingMap[PrivateCopy->getDecl()]; + Data.Modifier = Modifier; Data.Attributes = A; Data.RefExpr.setPointerAndInt(PrivateCopy, IsLastprivate); Data.PrivateCopy = nullptr; @@ -1207,7 +1406,10 @@ void DSAStackTy::addTaskgroupReductionData(const ValueDecl *D, SourceRange SR, "Additional reduction info may be specified only for reduction items."); ReductionData &ReductionData = getTopOfStack().ReductionMap[D]; assert(ReductionData.ReductionRange.isInvalid() && - getTopOfStack().Directive == OMPD_taskgroup && + (getTopOfStack().Directive == OMPD_taskgroup || + ((isOpenMPParallelDirective(getTopOfStack().Directive) || + isOpenMPWorksharingDirective(getTopOfStack().Directive)) && + !isOpenMPSimdDirective(getTopOfStack().Directive))) && "Additional reduction info may be specified only once for reduction " "items."); ReductionData.set(BOK, SR); @@ -1230,7 +1432,10 @@ void DSAStackTy::addTaskgroupReductionData(const ValueDecl *D, SourceRange SR, "Additional reduction info may be specified only for reduction items."); ReductionData &ReductionData = getTopOfStack().ReductionMap[D]; assert(ReductionData.ReductionRange.isInvalid() && - getTopOfStack().Directive == OMPD_taskgroup && + (getTopOfStack().Directive == OMPD_taskgroup || + ((isOpenMPParallelDirective(getTopOfStack().Directive) || + isOpenMPWorksharingDirective(getTopOfStack().Directive)) && + !isOpenMPSimdDirective(getTopOfStack().Directive))) && "Additional reduction info may be specified only once for reduction " "items."); ReductionData.set(ReductionRef, SR); @@ -1251,7 +1456,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData( assert(!isStackEmpty() && "Data-sharing attributes stack is empty."); for (const_iterator I = begin() + 1, E = end(); I != E; ++I) { const DSAInfo &Data = I->SharingMap.lookup(D); - if (Data.Attributes != OMPC_reduction || I->Directive != OMPD_taskgroup) + if (Data.Attributes != OMPC_reduction || + Data.Modifier != OMPC_REDUCTION_task) continue; const ReductionData &ReductionData = I->ReductionMap.lookup(D); if (!ReductionData.ReductionOp || @@ -1263,8 +1469,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData( "expression for the descriptor is not " "set."); TaskgroupDescriptor = I->TaskgroupReductionRef; - return DSAVarData(OMPD_taskgroup, OMPC_reduction, Data.RefExpr.getPointer(), - Data.PrivateCopy, I->DefaultAttrLoc); + return DSAVarData(I->Directive, OMPC_reduction, Data.RefExpr.getPointer(), + Data.PrivateCopy, I->DefaultAttrLoc, OMPC_REDUCTION_task); } return DSAVarData(); } @@ -1276,7 +1482,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData( assert(!isStackEmpty() && "Data-sharing attributes stack is empty."); for (const_iterator I = begin() + 1, E = end(); I != E; ++I) { const DSAInfo &Data = I->SharingMap.lookup(D); - if (Data.Attributes != OMPC_reduction || I->Directive != OMPD_taskgroup) + if (Data.Attributes != OMPC_reduction || + Data.Modifier != OMPC_REDUCTION_task) continue; const ReductionData &ReductionData = I->ReductionMap.lookup(D); if (!ReductionData.ReductionOp || @@ -1288,8 +1495,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData( "expression for the descriptor is not " "set."); TaskgroupDescriptor = I->TaskgroupReductionRef; - return DSAVarData(OMPD_taskgroup, OMPC_reduction, Data.RefExpr.getPointer(), - Data.PrivateCopy, I->DefaultAttrLoc); + return DSAVarData(I->Directive, OMPC_reduction, Data.RefExpr.getPointer(), + Data.PrivateCopy, I->DefaultAttrLoc, OMPC_REDUCTION_task); } return DSAVarData(); } @@ -1364,6 +1571,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, if (TI != Threadprivates.end()) { DVar.RefExpr = TI->getSecond().RefExpr.getPointer(); DVar.CKind = OMPC_threadprivate; + DVar.Modifier = TI->getSecond().Modifier; return DVar; } if (VD && VD->hasAttr<OMPThreadPrivateDeclAttr>()) { @@ -1447,15 +1655,18 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, const_iterator EndI = end(); if (FromParent && I != EndI) ++I; - auto It = I->SharingMap.find(D); - if (It != I->SharingMap.end()) { - const DSAInfo &Data = It->getSecond(); - DVar.RefExpr = Data.RefExpr.getPointer(); - DVar.PrivateCopy = Data.PrivateCopy; - DVar.CKind = Data.Attributes; - DVar.ImplicitDSALoc = I->DefaultAttrLoc; - DVar.DKind = I->Directive; - return DVar; + if (I != EndI) { + auto It = I->SharingMap.find(D); + if (It != I->SharingMap.end()) { + const DSAInfo &Data = It->getSecond(); + DVar.RefExpr = Data.RefExpr.getPointer(); + DVar.PrivateCopy = Data.PrivateCopy; + DVar.CKind = Data.Attributes; + DVar.ImplicitDSALoc = I->DefaultAttrLoc; + DVar.DKind = I->Directive; + DVar.Modifier = Data.Modifier; + return DVar; + } } DVar.CKind = OMPC_shared; @@ -1493,6 +1704,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, const_iterator EndI = end(); if (FromParent && I != EndI) ++I; + if (I == EndI) + return DVar; auto It = I->SharingMap.find(D); if (It != I->SharingMap.end()) { const DSAInfo &Data = It->getSecond(); @@ -1501,6 +1714,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, DVar.CKind = Data.Attributes; DVar.ImplicitDSALoc = I->DefaultAttrLoc; DVar.DKind = I->Directive; + DVar.Modifier = Data.Modifier; } return DVar; @@ -1520,6 +1734,15 @@ const DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D, return getDSA(StartI, D); } +const DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D, + unsigned Level) const { + if (getStackSize() <= Level) + return DSAVarData(); + D = getCanonicalDecl(D); + const_iterator StartI = std::next(begin(), getStackSize() - 1 - Level); + return getDSA(StartI, D); +} + const DSAStackTy::DSAVarData DSAStackTy::hasDSA(ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> CPred, @@ -1640,23 +1863,28 @@ Sema::DeviceDiagBuilder Sema::diagIfOpenMPDeviceCode(SourceLocation Loc, unsigned DiagID) { assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice && "Expected OpenMP device compilation."); - FunctionEmissionStatus FES = getEmissionStatus(getCurFunctionDecl()); + + FunctionDecl *FD = getCurFunctionDecl(); DeviceDiagBuilder::Kind Kind = DeviceDiagBuilder::K_Nop; - switch (FES) { - case FunctionEmissionStatus::Emitted: - Kind = DeviceDiagBuilder::K_Immediate; - break; - case FunctionEmissionStatus::Unknown: - Kind = isOpenMPDeviceDelayedContext(*this) ? DeviceDiagBuilder::K_Deferred - : DeviceDiagBuilder::K_Immediate; - break; - case FunctionEmissionStatus::TemplateDiscarded: - case FunctionEmissionStatus::OMPDiscarded: - Kind = DeviceDiagBuilder::K_Nop; - break; - case FunctionEmissionStatus::CUDADiscarded: - llvm_unreachable("CUDADiscarded unexpected in OpenMP device compilation"); - break; + if (FD) { + FunctionEmissionStatus FES = getEmissionStatus(FD); + switch (FES) { + case FunctionEmissionStatus::Emitted: + Kind = DeviceDiagBuilder::K_Immediate; + break; + case FunctionEmissionStatus::Unknown: + Kind = isOpenMPDeviceDelayedContext(*this) + ? DeviceDiagBuilder::K_Deferred + : DeviceDiagBuilder::K_Immediate; + break; + case FunctionEmissionStatus::TemplateDiscarded: + case FunctionEmissionStatus::OMPDiscarded: + Kind = DeviceDiagBuilder::K_Nop; + break; + case FunctionEmissionStatus::CUDADiscarded: + llvm_unreachable("CUDADiscarded unexpected in OpenMP device compilation"); + break; + } } return DeviceDiagBuilder(Kind, Loc, DiagID, getCurFunctionDecl(), *this); @@ -1685,107 +1913,6 @@ Sema::DeviceDiagBuilder Sema::diagIfOpenMPHostCode(SourceLocation Loc, return DeviceDiagBuilder(Kind, Loc, DiagID, getCurFunctionDecl(), *this); } -void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee, - bool CheckForDelayedContext) { - assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice && - "Expected OpenMP device compilation."); - assert(Callee && "Callee may not be null."); - Callee = Callee->getMostRecentDecl(); - FunctionDecl *Caller = getCurFunctionDecl(); - - // host only function are not available on the device. - if (Caller) { - FunctionEmissionStatus CallerS = getEmissionStatus(Caller); - FunctionEmissionStatus CalleeS = getEmissionStatus(Callee); - assert(CallerS != FunctionEmissionStatus::CUDADiscarded && - CalleeS != FunctionEmissionStatus::CUDADiscarded && - "CUDADiscarded unexpected in OpenMP device function check"); - if ((CallerS == FunctionEmissionStatus::Emitted || - (!isOpenMPDeviceDelayedContext(*this) && - CallerS == FunctionEmissionStatus::Unknown)) && - CalleeS == FunctionEmissionStatus::OMPDiscarded) { - StringRef HostDevTy = getOpenMPSimpleClauseTypeName( - OMPC_device_type, OMPC_DEVICE_TYPE_host); - Diag(Loc, diag::err_omp_wrong_device_function_call) << HostDevTy << 0; - Diag(Callee->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(), - diag::note_omp_marked_device_type_here) - << HostDevTy; - return; - } - } - // If the caller is known-emitted, mark the callee as known-emitted. - // Otherwise, mark the call in our call graph so we can traverse it later. - if ((CheckForDelayedContext && !isOpenMPDeviceDelayedContext(*this)) || - (!Caller && !CheckForDelayedContext) || - (Caller && getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted)) - markKnownEmitted(*this, Caller, Callee, Loc, - [CheckForDelayedContext](Sema &S, FunctionDecl *FD) { - return CheckForDelayedContext && - S.getEmissionStatus(FD) == - FunctionEmissionStatus::Emitted; - }); - else if (Caller) - DeviceCallGraph[Caller].insert({Callee, Loc}); -} - -void Sema::checkOpenMPHostFunction(SourceLocation Loc, FunctionDecl *Callee, - bool CheckCaller) { - assert(LangOpts.OpenMP && !LangOpts.OpenMPIsDevice && - "Expected OpenMP host compilation."); - assert(Callee && "Callee may not be null."); - Callee = Callee->getMostRecentDecl(); - FunctionDecl *Caller = getCurFunctionDecl(); - - // device only function are not available on the host. - if (Caller) { - FunctionEmissionStatus CallerS = getEmissionStatus(Caller); - FunctionEmissionStatus CalleeS = getEmissionStatus(Callee); - assert( - (LangOpts.CUDA || (CallerS != FunctionEmissionStatus::CUDADiscarded && - CalleeS != FunctionEmissionStatus::CUDADiscarded)) && - "CUDADiscarded unexpected in OpenMP host function check"); - if (CallerS == FunctionEmissionStatus::Emitted && - CalleeS == FunctionEmissionStatus::OMPDiscarded) { - StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName( - OMPC_device_type, OMPC_DEVICE_TYPE_nohost); - Diag(Loc, diag::err_omp_wrong_device_function_call) << NoHostDevTy << 1; - Diag(Callee->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(), - diag::note_omp_marked_device_type_here) - << NoHostDevTy; - return; - } - } - // If the caller is known-emitted, mark the callee as known-emitted. - // Otherwise, mark the call in our call graph so we can traverse it later. - if (!shouldIgnoreInHostDeviceCheck(Callee)) { - if ((!CheckCaller && !Caller) || - (Caller && - getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted)) - markKnownEmitted( - *this, Caller, Callee, Loc, [CheckCaller](Sema &S, FunctionDecl *FD) { - return CheckCaller && - S.getEmissionStatus(FD) == FunctionEmissionStatus::Emitted; - }); - else if (Caller) - DeviceCallGraph[Caller].insert({Callee, Loc}); - } -} - -void Sema::checkOpenMPDeviceExpr(const Expr *E) { - assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice && - "OpenMP device compilation mode is expected."); - QualType Ty = E->getType(); - if ((Ty->isFloat16Type() && !Context.getTargetInfo().hasFloat16Type()) || - ((Ty->isFloat128Type() || - (Ty->isRealFloatingType() && Context.getTypeSize(Ty) == 128)) && - !Context.getTargetInfo().hasFloat128Type()) || - (Ty->isIntegerType() && Context.getTypeSize(Ty) == 128 && - !Context.getTargetInfo().hasInt128Type())) - targetDiag(E->getExprLoc(), diag::err_omp_unsupported_type) - << static_cast<unsigned>(Context.getTypeSize(Ty)) << Ty - << Context.getTargetInfo().getTriple().str() << E->getSourceRange(); -} - static OpenMPDefaultmapClauseKind getVariableCategoryFromDecl(const LangOptions &LO, const ValueDecl *VD) { if (LO.OpenMP <= 45) { @@ -1901,7 +2028,8 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level, if (isa<ArraySubscriptExpr>(EI->getAssociatedExpression()) || isa<OMPArraySectionExpr>(EI->getAssociatedExpression()) || - isa<MemberExpr>(EI->getAssociatedExpression())) { + isa<MemberExpr>(EI->getAssociatedExpression()) || + isa<OMPArrayShapingExpr>(EI->getAssociatedExpression())) { IsVariableAssociatedWithSection = true; // There is nothing more we need to know about this variable. return true; @@ -1935,14 +2063,23 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level, ((IsVariableUsedInMapClause && DSAStack->getCaptureRegion(Level, OpenMPCaptureLevel) == OMPD_target) || - !DSAStack->hasExplicitDSA( - D, - [](OpenMPClauseKind K) -> bool { return K == OMPC_firstprivate; }, - Level, /*NotLastprivate=*/true)) && + !(DSAStack->hasExplicitDSA( + D, + [](OpenMPClauseKind K) -> bool { + return K == OMPC_firstprivate; + }, + Level, /*NotLastprivate=*/true) || + DSAStack->isUsesAllocatorsDecl(Level, D))) && // If the variable is artificial and must be captured by value - try to // capture by value. !(isa<OMPCapturedExprDecl>(D) && !D->hasAttr<OMPCaptureNoInitAttr>() && - !cast<OMPCapturedExprDecl>(D)->getInit()->isGLValue()); + !cast<OMPCapturedExprDecl>(D)->getInit()->isGLValue()) && + // If the variable is implicitly firstprivate and scalar - capture by + // copy + !(DSAStack->getDefaultDSA() == DSA_firstprivate && + !DSAStack->hasExplicitDSA( + D, [](OpenMPClauseKind K) { return K != OMPC_unknown; }, Level) && + !DSAStack->isLoopControlVariable(D, Level).first); } // When passing data by copy, we need to make sure it fits the uintptr size @@ -2010,7 +2147,23 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo, // if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD)) return nullptr; - return VD; + CapturedRegionScopeInfo *CSI = nullptr; + for (FunctionScopeInfo *FSI : llvm::drop_begin( + llvm::reverse(FunctionScopes), + CheckScopeInfo ? (FunctionScopes.size() - (StopAt + 1)) : 0)) { + if (!isa<CapturingScopeInfo>(FSI)) + return nullptr; + if (auto *RSI = dyn_cast<CapturedRegionScopeInfo>(FSI)) + if (RSI->CapRegionKind == CR_OpenMP) { + CSI = RSI; + break; + } + } + SmallVector<OpenMPDirectiveKind, 4> Regions; + getOpenMPCaptureRegions(Regions, + DSAStack->getDirective(CSI->OpenMPLevel)); + if (Regions[CSI->OpenMPCaptureLevel] != OMPD_task) + return VD; } } @@ -2039,20 +2192,27 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo, isImplicitOrExplicitTaskingRegion(DSAStack->getCurrentDirective())) || (VD && DSAStack->isForceVarCapturing())) return VD ? VD : Info.second; - DSAStackTy::DSAVarData DVarPrivate = + DSAStackTy::DSAVarData DVarTop = DSAStack->getTopDSA(D, DSAStack->isClauseParsingMode()); - if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind)) - return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl()); + if (DVarTop.CKind != OMPC_unknown && isOpenMPPrivate(DVarTop.CKind)) + return VD ? VD : cast<VarDecl>(DVarTop.PrivateCopy->getDecl()); // Threadprivate variables must not be captured. - if (isOpenMPThreadPrivate(DVarPrivate.CKind)) + if (isOpenMPThreadPrivate(DVarTop.CKind)) return nullptr; // The variable is not private or it is the variable in the directive with // default(none) clause and not used in any clause. - DVarPrivate = DSAStack->hasDSA(D, isOpenMPPrivate, - [](OpenMPDirectiveKind) { return true; }, - DSAStack->isClauseParsingMode()); + DSAStackTy::DSAVarData DVarPrivate = DSAStack->hasDSA( + D, isOpenMPPrivate, [](OpenMPDirectiveKind) { return true; }, + DSAStack->isClauseParsingMode()); + // Global shared must not be captured. + if (VD && !VD->hasLocalStorage() && DVarPrivate.CKind == OMPC_unknown && + ((DSAStack->getDefaultDSA() != DSA_none && + DSAStack->getDefaultDSA() != DSA_firstprivate) || + DVarTop.CKind == OMPC_shared)) + return nullptr; if (DVarPrivate.CKind != OMPC_unknown || - (VD && DSAStack->getDefaultDSA() == DSA_none)) + (VD && (DSAStack->getDefaultDSA() == DSA_none || + DSAStack->getDefaultDSA() == DSA_firstprivate))) return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl()); } return nullptr; @@ -2060,9 +2220,7 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo, void Sema::adjustOpenMPTargetScopeIndex(unsigned &FunctionScopesIndex, unsigned Level) const { - SmallVector<OpenMPDirectiveKind, 4> Regions; - getOpenMPCaptureRegions(Regions, DSAStack->getDirective(Level)); - FunctionScopesIndex -= Regions.size(); + FunctionScopesIndex -= getOpenMPCaptureLevels(DSAStack->getDirective(Level)); } void Sema::startOpenMPLoop() { @@ -2079,39 +2237,77 @@ void Sema::startOpenMPCXXRangeFor() { } } -bool Sema::isOpenMPPrivateDecl(const ValueDecl *D, unsigned Level) const { +OpenMPClauseKind Sema::isOpenMPPrivateDecl(ValueDecl *D, unsigned Level, + unsigned CapLevel) const { assert(LangOpts.OpenMP && "OpenMP is not allowed"); + if (DSAStack->hasExplicitDirective( + [](OpenMPDirectiveKind K) { return isOpenMPTaskingDirective(K); }, + Level)) { + bool IsTriviallyCopyable = + D->getType().getNonReferenceType().isTriviallyCopyableType(Context); + OpenMPDirectiveKind DKind = DSAStack->getDirective(Level); + SmallVector<OpenMPDirectiveKind, 4> CaptureRegions; + getOpenMPCaptureRegions(CaptureRegions, DKind); + if (isOpenMPTaskingDirective(CaptureRegions[CapLevel]) && + (IsTriviallyCopyable || + !isOpenMPTaskLoopDirective(CaptureRegions[CapLevel]))) { + if (DSAStack->hasExplicitDSA( + D, [](OpenMPClauseKind K) { return K == OMPC_firstprivate; }, + Level, /*NotLastprivate=*/true)) + return OMPC_firstprivate; + DSAStackTy::DSAVarData DVar = DSAStack->getImplicitDSA(D, Level); + if (DVar.CKind != OMPC_shared && + !DSAStack->isLoopControlVariable(D, Level).first && !DVar.RefExpr) { + DSAStack->addImplicitTaskFirstprivate(Level, D); + return OMPC_firstprivate; + } + } + } if (isOpenMPLoopDirective(DSAStack->getCurrentDirective())) { if (DSAStack->getAssociatedLoops() > 0 && !DSAStack->isLoopStarted()) { DSAStack->resetPossibleLoopCounter(D); DSAStack->loopStart(); - return true; + return OMPC_private; } if ((DSAStack->getPossiblyLoopCunter() == D->getCanonicalDecl() || DSAStack->isLoopControlVariable(D).first) && !DSAStack->hasExplicitDSA( D, [](OpenMPClauseKind K) { return K != OMPC_private; }, Level) && !isOpenMPSimdDirective(DSAStack->getCurrentDirective())) - return true; + return OMPC_private; } if (const auto *VD = dyn_cast<VarDecl>(D)) { if (DSAStack->isThreadPrivate(const_cast<VarDecl *>(VD)) && DSAStack->isForceVarCapturing() && !DSAStack->hasExplicitDSA( D, [](OpenMPClauseKind K) { return K == OMPC_copyin; }, Level)) - return true; - } - return DSAStack->hasExplicitDSA( - D, [](OpenMPClauseKind K) { return K == OMPC_private; }, Level) || - (DSAStack->isClauseParsingMode() && - DSAStack->getClauseParsingMode() == OMPC_private) || - // Consider taskgroup reduction descriptor variable a private to avoid - // possible capture in the region. - (DSAStack->hasExplicitDirective( - [](OpenMPDirectiveKind K) { return K == OMPD_taskgroup; }, - Level) && - DSAStack->isTaskgroupReductionRef(D, Level)); + return OMPC_private; + } + // User-defined allocators are private since they must be defined in the + // context of target region. + if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, Level) && + DSAStack->isUsesAllocatorsDecl(Level, D).getValueOr( + DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait) == + DSAStackTy::UsesAllocatorsDeclKind::UserDefinedAllocator) + return OMPC_private; + return (DSAStack->hasExplicitDSA( + D, [](OpenMPClauseKind K) { return K == OMPC_private; }, Level) || + (DSAStack->isClauseParsingMode() && + DSAStack->getClauseParsingMode() == OMPC_private) || + // Consider taskgroup reduction descriptor variable a private + // to avoid possible capture in the region. + (DSAStack->hasExplicitDirective( + [](OpenMPDirectiveKind K) { + return K == OMPD_taskgroup || + ((isOpenMPParallelDirective(K) || + isOpenMPWorksharingDirective(K)) && + !isOpenMPSimdDirective(K)); + }, + Level) && + DSAStack->isTaskgroupReductionRef(D, Level))) + ? OMPC_private + : OMPC_unknown; } void Sema::setOpenMPCaptureKind(FieldDecl *FD, const ValueDecl *D, @@ -2148,68 +2344,101 @@ void Sema::setOpenMPCaptureKind(FieldDecl *FD, const ValueDecl *D, } } if (OMPC != OMPC_unknown) - FD->addAttr(OMPCaptureKindAttr::CreateImplicit(Context, OMPC)); + FD->addAttr(OMPCaptureKindAttr::CreateImplicit(Context, unsigned(OMPC))); } -bool Sema::isOpenMPTargetCapturedDecl(const ValueDecl *D, - unsigned Level) const { +bool Sema::isOpenMPTargetCapturedDecl(const ValueDecl *D, unsigned Level, + unsigned CaptureLevel) const { assert(LangOpts.OpenMP && "OpenMP is not allowed"); // Return true if the current level is no longer enclosed in a target region. + SmallVector<OpenMPDirectiveKind, 4> Regions; + getOpenMPCaptureRegions(Regions, DSAStack->getDirective(Level)); const auto *VD = dyn_cast<VarDecl>(D); return VD && !VD->hasLocalStorage() && DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, - Level); + Level) && + Regions[CaptureLevel] != OMPD_task; +} + +bool Sema::isOpenMPGlobalCapturedDecl(ValueDecl *D, unsigned Level, + unsigned CaptureLevel) const { + assert(LangOpts.OpenMP && "OpenMP is not allowed"); + // Return true if the current level is no longer enclosed in a target region. + + if (const auto *VD = dyn_cast<VarDecl>(D)) { + if (!VD->hasLocalStorage()) { + DSAStackTy::DSAVarData TopDVar = + DSAStack->getTopDSA(D, /*FromParent=*/false); + unsigned NumLevels = + getOpenMPCaptureLevels(DSAStack->getDirective(Level)); + if (Level == 0) + return (NumLevels == CaptureLevel + 1) && TopDVar.CKind != OMPC_shared; + DSAStackTy::DSAVarData DVar = DSAStack->getImplicitDSA(D, Level - 1); + return DVar.CKind != OMPC_shared || + isOpenMPGlobalCapturedDecl( + D, Level - 1, + getOpenMPCaptureLevels(DSAStack->getDirective(Level - 1)) - 1); + } + } + return true; } void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; } -void Sema::finalizeOpenMPDelayedAnalysis() { +void Sema::ActOnOpenMPBeginDeclareVariant(SourceLocation Loc, + OMPTraitInfo &TI) { + if (!OMPDeclareVariantScopes.empty()) { + Diag(Loc, diag::warn_nested_declare_variant); + return; + } + OMPDeclareVariantScopes.push_back(OMPDeclareVariantScope(TI)); +} + +void Sema::ActOnOpenMPEndDeclareVariant() { + assert(isInOpenMPDeclareVariantScope() && + "Not in OpenMP declare variant scope!"); + + OMPDeclareVariantScopes.pop_back(); +} + +void Sema::finalizeOpenMPDelayedAnalysis(const FunctionDecl *Caller, + const FunctionDecl *Callee, + SourceLocation Loc) { assert(LangOpts.OpenMP && "Expected OpenMP compilation mode."); - // Diagnose implicit declare target functions and their callees. - for (const auto &CallerCallees : DeviceCallGraph) { - Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = - OMPDeclareTargetDeclAttr::getDeviceType( - CallerCallees.getFirst()->getMostRecentDecl()); - // Ignore host functions during device analyzis. - if (LangOpts.OpenMPIsDevice && DevTy && - *DevTy == OMPDeclareTargetDeclAttr::DT_Host) - continue; - // Ignore nohost functions during host analyzis. - if (!LangOpts.OpenMPIsDevice && DevTy && - *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) - continue; - for (const std::pair<CanonicalDeclPtr<FunctionDecl>, SourceLocation> - &Callee : CallerCallees.getSecond()) { - const FunctionDecl *FD = Callee.first->getMostRecentDecl(); - Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = - OMPDeclareTargetDeclAttr::getDeviceType(FD); - if (LangOpts.OpenMPIsDevice && DevTy && - *DevTy == OMPDeclareTargetDeclAttr::DT_Host) { - // Diagnose host function called during device codegen. - StringRef HostDevTy = getOpenMPSimpleClauseTypeName( - OMPC_device_type, OMPC_DEVICE_TYPE_host); - Diag(Callee.second, diag::err_omp_wrong_device_function_call) - << HostDevTy << 0; - Diag(FD->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(), - diag::note_omp_marked_device_type_here) - << HostDevTy; - continue; - } + Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = + OMPDeclareTargetDeclAttr::getDeviceType(Caller->getMostRecentDecl()); + // Ignore host functions during device analyzis. + if (LangOpts.OpenMPIsDevice && DevTy && + *DevTy == OMPDeclareTargetDeclAttr::DT_Host) + return; + // Ignore nohost functions during host analyzis. + if (!LangOpts.OpenMPIsDevice && DevTy && + *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) + return; + const FunctionDecl *FD = Callee->getMostRecentDecl(); + DevTy = OMPDeclareTargetDeclAttr::getDeviceType(FD); + if (LangOpts.OpenMPIsDevice && DevTy && + *DevTy == OMPDeclareTargetDeclAttr::DT_Host) { + // Diagnose host function called during device codegen. + StringRef HostDevTy = + getOpenMPSimpleClauseTypeName(OMPC_device_type, OMPC_DEVICE_TYPE_host); + Diag(Loc, diag::err_omp_wrong_device_function_call) << HostDevTy << 0; + Diag(FD->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(), + diag::note_omp_marked_device_type_here) + << HostDevTy; + return; + } if (!LangOpts.OpenMPIsDevice && DevTy && *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) { // Diagnose nohost function called during host codegen. StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName( OMPC_device_type, OMPC_DEVICE_TYPE_nohost); - Diag(Callee.second, diag::err_omp_wrong_device_function_call) - << NoHostDevTy << 1; + Diag(Loc, diag::err_omp_wrong_device_function_call) << NoHostDevTy << 1; Diag(FD->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(), diag::note_omp_marked_device_type_here) << NoHostDevTy; - continue; } - } - } } void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind, @@ -2228,14 +2457,86 @@ void Sema::EndOpenMPClause() { DSAStack->setClauseParsingMode(/*K=*/OMPC_unknown); } -static void checkAllocateClauses(Sema &S, DSAStackTy *Stack, - ArrayRef<OMPClause *> Clauses); static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc, SourceRange &ERange, bool AllowArraySection = false); + +/// Check consistency of the reduction clauses. +static void checkReductionClauses(Sema &S, DSAStackTy *Stack, + ArrayRef<OMPClause *> Clauses) { + bool InscanFound = false; + SourceLocation InscanLoc; + // OpenMP 5.0, 2.19.5.4 reduction Clause, Restrictions. + // A reduction clause without the inscan reduction-modifier may not appear on + // a construct on which a reduction clause with the inscan reduction-modifier + // appears. + for (OMPClause *C : Clauses) { + if (C->getClauseKind() != OMPC_reduction) + continue; + auto *RC = cast<OMPReductionClause>(C); + if (RC->getModifier() == OMPC_REDUCTION_inscan) { + InscanFound = true; + InscanLoc = RC->getModifierLoc(); + continue; + } + if (RC->getModifier() == OMPC_REDUCTION_task) { + // OpenMP 5.0, 2.19.5.4 reduction Clause. + // A reduction clause with the task reduction-modifier may only appear on + // a parallel construct, a worksharing construct or a combined or + // composite construct for which any of the aforementioned constructs is a + // constituent construct and simd or loop are not constituent constructs. + OpenMPDirectiveKind CurDir = Stack->getCurrentDirective(); + if (!(isOpenMPParallelDirective(CurDir) || + isOpenMPWorksharingDirective(CurDir)) || + isOpenMPSimdDirective(CurDir)) + S.Diag(RC->getModifierLoc(), + diag::err_omp_reduction_task_not_parallel_or_worksharing); + continue; + } + } + if (InscanFound) { + for (OMPClause *C : Clauses) { + if (C->getClauseKind() != OMPC_reduction) + continue; + auto *RC = cast<OMPReductionClause>(C); + if (RC->getModifier() != OMPC_REDUCTION_inscan) { + S.Diag(RC->getModifier() == OMPC_REDUCTION_unknown + ? RC->getBeginLoc() + : RC->getModifierLoc(), + diag::err_omp_inscan_reduction_expected); + S.Diag(InscanLoc, diag::note_omp_previous_inscan_reduction); + continue; + } + for (Expr *Ref : RC->varlists()) { + assert(Ref && "NULL expr in OpenMP nontemporal clause."); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = Ref; + auto Res = getPrivateItem(S, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/true); + ValueDecl *D = Res.first; + if (!D) + continue; + if (!Stack->isUsedInScanDirective(getCanonicalDecl(D))) { + S.Diag(Ref->getExprLoc(), + diag::err_omp_reduction_not_inclusive_exclusive) + << Ref->getSourceRange(); + } + } + } + } +} + +static void checkAllocateClauses(Sema &S, DSAStackTy *Stack, + ArrayRef<OMPClause *> Clauses); static DeclRefExpr *buildCapture(Sema &S, ValueDecl *D, Expr *CaptureExpr, bool WithInit); +static void reportOriginalDsa(Sema &SemaRef, const DSAStackTy *Stack, + const ValueDecl *D, + const DSAStackTy::DSAVarData &DVar, + bool IsLoopIterVar = false); + void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { // OpenMP [2.14.3.5, Restrictions, C/C++, p.1] // A variable of class type (or array thereof) that appears in a lastprivate @@ -2305,10 +2606,56 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { Clause->setPrivateRefs(PrivateRefs); continue; } + if (auto *Clause = dyn_cast<OMPUsesAllocatorsClause>(C)) { + for (unsigned I = 0, E = Clause->getNumberOfAllocators(); I < E; ++I) { + OMPUsesAllocatorsClause::Data D = Clause->getAllocatorData(I); + auto *DRE = dyn_cast<DeclRefExpr>(D.Allocator->IgnoreParenImpCasts()); + if (!DRE) + continue; + ValueDecl *VD = DRE->getDecl(); + if (!VD || !isa<VarDecl>(VD)) + continue; + DSAStackTy::DSAVarData DVar = + DSAStack->getTopDSA(VD, /*FromParent=*/false); + // OpenMP [2.12.5, target Construct] + // Memory allocators that appear in a uses_allocators clause cannot + // appear in other data-sharing attribute clauses or data-mapping + // attribute clauses in the same construct. + Expr *MapExpr = nullptr; + if (DVar.RefExpr || + DSAStack->checkMappableExprComponentListsForDecl( + VD, /*CurrentRegionOnly=*/true, + [VD, &MapExpr]( + OMPClauseMappableExprCommon::MappableExprComponentListRef + MapExprComponents, + OpenMPClauseKind C) { + auto MI = MapExprComponents.rbegin(); + auto ME = MapExprComponents.rend(); + if (MI != ME && + MI->getAssociatedDeclaration()->getCanonicalDecl() == + VD->getCanonicalDecl()) { + MapExpr = MI->getAssociatedExpression(); + return true; + } + return false; + })) { + Diag(D.Allocator->getExprLoc(), + diag::err_omp_allocator_used_in_clauses) + << D.Allocator->getSourceRange(); + if (DVar.RefExpr) + reportOriginalDsa(*this, DSAStack, VD, DVar); + else + Diag(MapExpr->getExprLoc(), diag::note_used_here) + << MapExpr->getSourceRange(); + } + } + continue; + } } // Check allocate clauses. if (!CurContext->isDependentContext()) checkAllocateClauses(*this, DSAStack, D->clauses()); + checkReductionClauses(*this, DSAStack, D->clauses()); } DSAStack->pop(); @@ -2618,15 +2965,14 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) { static OMPAllocateDeclAttr::AllocatorTypeTy getAllocatorKind(Sema &S, DSAStackTy *Stack, Expr *Allocator) { if (!Allocator) - return OMPAllocateDeclAttr::OMPDefaultMemAlloc; + return OMPAllocateDeclAttr::OMPNullMemAlloc; if (Allocator->isTypeDependent() || Allocator->isValueDependent() || Allocator->isInstantiationDependent() || Allocator->containsUnexpandedParameterPack()) return OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; auto AllocatorKindRes = OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; const Expr *AE = Allocator->IgnoreParenImpCasts(); - for (int I = OMPAllocateDeclAttr::OMPDefaultMemAlloc; - I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) { + for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) { auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I); const Expr *DefAllocator = Stack->getAllocator(AllocatorKind); llvm::FoldingSetNodeID AEId, DAEId; @@ -2799,18 +3145,26 @@ OMPRequiresDecl *Sema::CheckOMPRequiresDecl(SourceLocation Loc, /// current compilation unit. ArrayRef<SourceLocation> TargetLocations = DSAStack->getEncounteredTargetLocs(); - if (!TargetLocations.empty()) { + SourceLocation AtomicLoc = DSAStack->getAtomicDirectiveLoc(); + if (!TargetLocations.empty() || !AtomicLoc.isInvalid()) { for (const OMPClause *CNew : ClauseList) { // Check if any of the requires clauses affect target regions. if (isa<OMPUnifiedSharedMemoryClause>(CNew) || isa<OMPUnifiedAddressClause>(CNew) || isa<OMPReverseOffloadClause>(CNew) || isa<OMPDynamicAllocatorsClause>(CNew)) { - Diag(Loc, diag::err_omp_target_before_requires) - << getOpenMPClauseName(CNew->getClauseKind()); + Diag(Loc, diag::err_omp_directive_before_requires) + << "target" << getOpenMPClauseName(CNew->getClauseKind()); for (SourceLocation TargetLoc : TargetLocations) { - Diag(TargetLoc, diag::note_omp_requires_encountered_target); + Diag(TargetLoc, diag::note_omp_requires_encountered_directive) + << "target"; } + } else if (!AtomicLoc.isInvalid() && + isa<OMPAtomicDefaultMemOrderClause>(CNew)) { + Diag(Loc, diag::err_omp_directive_before_requires) + << "atomic" << getOpenMPClauseName(CNew->getClauseKind()); + Diag(AtomicLoc, diag::note_omp_requires_encountered_directive) + << "atomic"; } } } @@ -2824,7 +3178,7 @@ OMPRequiresDecl *Sema::CheckOMPRequiresDecl(SourceLocation Loc, static void reportOriginalDsa(Sema &SemaRef, const DSAStackTy *Stack, const ValueDecl *D, const DSAStackTy::DSAVarData &DVar, - bool IsLoopIterVar = false) { + bool IsLoopIterVar) { if (DVar.RefExpr) { SemaRef.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa) << getOpenMPClauseName(DVar.CKind); @@ -2944,6 +3298,16 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> { Visit(S->getInnermostCapturedStmt()->getCapturedStmt()); TryCaptureCXXThisMembers = SavedTryCaptureCXXThisMembers; } + // In tasks firstprivates are not captured anymore, need to analyze them + // explicitly. + if (isOpenMPTaskingDirective(S->getDirectiveKind()) && + !isOpenMPTaskLoopDirective(S->getDirectiveKind())) { + for (OMPClause *C : S->clauses()) + if (auto *FC = dyn_cast<OMPFirstprivateClause>(C)) { + for (Expr *Ref : FC->varlists()) + Visit(Ref); + } + } } public: @@ -2966,7 +3330,11 @@ public: return; VD = VD->getCanonicalDecl(); // Skip internally declared variables. - if (VD->hasLocalStorage() && CS && !CS->capturesVariable(VD)) + if (VD->hasLocalStorage() && CS && !CS->capturesVariable(VD) && + !Stack->isImplicitTaskFirstprivate(VD)) + return; + // Skip allocators in uses_allocators clauses. + if (Stack->isUsesAllocatorsDecl(VD).hasValue()) return; DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD, /*FromParent=*/false); @@ -2979,7 +3347,8 @@ public: OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD); if (VD->hasGlobalStorage() && CS && !CS->capturesVariable(VD) && (Stack->hasRequiresDeclWithClause<OMPUnifiedSharedMemoryClause>() || - !Res || *Res != OMPDeclareTargetDeclAttr::MT_Link)) + !Res || *Res != OMPDeclareTargetDeclAttr::MT_Link) && + !Stack->isImplicitTaskFirstprivate(VD)) return; SourceLocation ELoc = E->getExprLoc(); @@ -2988,10 +3357,19 @@ public: // in the construct, and does not have a predetermined data-sharing // attribute, must have its data-sharing attribute explicitly determined // by being listed in a data-sharing attribute clause. - if (DVar.CKind == OMPC_unknown && Stack->getDefaultDSA() == DSA_none && + if (DVar.CKind == OMPC_unknown && + (Stack->getDefaultDSA() == DSA_none || + Stack->getDefaultDSA() == DSA_firstprivate) && isImplicitOrExplicitTaskingRegion(DKind) && VarsWithInheritedDSA.count(VD) == 0) { - VarsWithInheritedDSA[VD] = E; + bool InheritedDSA = Stack->getDefaultDSA() == DSA_none; + if (!InheritedDSA && Stack->getDefaultDSA() == DSA_firstprivate) { + DSAStackTy::DSAVarData DVar = + Stack->getImplicitDSA(VD, /*FromParent=*/false); + InheritedDSA = DVar.CKind == OMPC_unknown; + } + if (InheritedDSA) + VarsWithInheritedDSA[VD] = E; return; } @@ -3036,7 +3414,7 @@ public: StackComponents, OpenMPClauseKind) { // Variable is used if it has been marked as an array, array - // section or the variable iself. + // section, array shaping or the variable iself. return StackComponents.size() == 1 || std::all_of( std::next(StackComponents.rbegin()), @@ -3047,6 +3425,8 @@ public: nullptr && (isa<OMPArraySectionExpr>( MC.getAssociatedExpression()) || + isa<OMPArrayShapingExpr>( + MC.getAssociatedExpression()) || isa<ArraySubscriptExpr>( MC.getAssociatedExpression())); }); @@ -3091,7 +3471,9 @@ public: // Define implicit data-sharing attributes for task. DVar = Stack->getImplicitDSA(VD, /*FromParent=*/false); - if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared && + if (((isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared) || + (Stack->getDefaultDSA() == DSA_firstprivate && + DVar.CKind == OMPC_firstprivate && !DVar.RefExpr)) && !Stack->isLoopControlVariable(VD).first) { ImplicitFirstprivate.push_back(E); return; @@ -3112,7 +3494,7 @@ public: return; auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl()); OpenMPDirectiveKind DKind = Stack->getCurrentDirective(); - if (auto *TE = dyn_cast<CXXThisExpr>(E->getBase()->IgnoreParens())) { + if (auto *TE = dyn_cast<CXXThisExpr>(E->getBase()->IgnoreParenCasts())) { if (!FD) return; DSAStackTy::DSAVarData DVar = Stack->getTopDSA(FD, /*FromParent=*/false); @@ -3204,8 +3586,10 @@ public: // Do both expressions have the same kind? if (CCI->getAssociatedExpression()->getStmtClass() != SC.getAssociatedExpression()->getStmtClass()) - if (!(isa<OMPArraySectionExpr>( - SC.getAssociatedExpression()) && + if (!((isa<OMPArraySectionExpr>( + SC.getAssociatedExpression()) || + isa<OMPArrayShapingExpr>( + SC.getAssociatedExpression())) && isa<ArraySubscriptExpr>( CCI->getAssociatedExpression()))) return false; @@ -3516,7 +3900,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { }; // Start a captured region for 'parallel'. ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - ParamsParallel, /*OpenMPCaptureLevel=*/1); + ParamsParallel, /*OpenMPCaptureLevel=*/0); QualType Args[] = {VoidPtrTy}; FunctionProtoType::ExtProtoInfo EPI; EPI.Variadic = true; @@ -3537,7 +3921,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params, /*OpenMPCaptureLevel=*/2); + Params, /*OpenMPCaptureLevel=*/1); // Mark this captured region as inlined, because we don't use outlined // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( @@ -3688,6 +4072,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_cancellation_point: case OMPD_cancel: case OMPD_flush: + case OMPD_depobj: + case OMPD_scan: case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: @@ -3695,8 +4081,11 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_end_declare_target: case OMPD_requires: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: + default: llvm_unreachable("Unknown OpenMP directive"); } } @@ -3841,6 +4230,36 @@ void Sema::tryCaptureOpenMPLambdas(ValueDecl *V) { } } +static bool checkOrderedOrderSpecified(Sema &S, + const ArrayRef<OMPClause *> Clauses) { + const OMPOrderedClause *Ordered = nullptr; + const OMPOrderClause *Order = nullptr; + + for (const OMPClause *Clause : Clauses) { + if (Clause->getClauseKind() == OMPC_ordered) + Ordered = cast<OMPOrderedClause>(Clause); + else if (Clause->getClauseKind() == OMPC_order) { + Order = cast<OMPOrderClause>(Clause); + if (Order->getKind() != OMPC_ORDER_concurrent) + Order = nullptr; + } + if (Ordered && Order) + break; + } + + if (Ordered && Order) { + S.Diag(Order->getKindKwLoc(), + diag::err_omp_simple_clause_incompatible_with_ordered) + << getOpenMPClauseName(OMPC_order) + << getOpenMPSimpleClauseTypeName(OMPC_order, OMPC_ORDER_concurrent) + << SourceRange(Order->getBeginLoc(), Order->getEndLoc()); + S.Diag(Ordered->getBeginLoc(), diag::note_omp_ordered_param) + << 0 << SourceRange(Ordered->getBeginLoc(), Ordered->getEndLoc()); + return true; + } + return false; +} + StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, ArrayRef<OMPClause *> Clauses) { bool ErrorFound = false; @@ -3859,7 +4278,8 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, SmallVector<const OMPClauseWithPreInit *, 4> PICs; // This is required for proper codegen. for (OMPClause *Clause : Clauses) { - if (isOpenMPTaskingDirective(DSAStack->getCurrentDirective()) && + if (!LangOpts.OpenMPSimd && + isOpenMPTaskingDirective(DSAStack->getCurrentDirective()) && Clause->getClauseKind() == OMPC_in_reduction) { // Capture taskgroup task_reduction descriptors inside the tasking regions // with the corresponding in_reduction items. @@ -3897,6 +4317,9 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, else if (Clause->getClauseKind() == OMPC_linear) LCs.push_back(cast<OMPLinearClause>(Clause)); } + // Capture allocator expressions if used. + for (Expr *E : DSAStack->getInnerAllocators()) + MarkDeclarationsReferencedInExpr(E); // OpenMP, 2.7.1 Loop Construct, Restrictions // The nonmonotonic modifier cannot be specified if an ordered clause is // specified. @@ -3908,10 +4331,18 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, Diag(SC->getFirstScheduleModifier() == OMPC_SCHEDULE_MODIFIER_nonmonotonic ? SC->getFirstScheduleModifierLoc() : SC->getSecondScheduleModifierLoc(), - diag::err_omp_schedule_nonmonotonic_ordered) + diag::err_omp_simple_clause_incompatible_with_ordered) + << getOpenMPClauseName(OMPC_schedule) + << getOpenMPSimpleClauseTypeName(OMPC_schedule, + OMPC_SCHEDULE_MODIFIER_nonmonotonic) << SourceRange(OC->getBeginLoc(), OC->getEndLoc()); ErrorFound = true; } + // OpenMP 5.0, 2.9.2 Worksharing-Loop Construct, Restrictions. + // If an order(concurrent) clause is present, an ordered clause may not appear + // on the same directive. + if (checkOrderedOrderSpecified(*this, Clauses)) + ErrorFound = true; if (!LCs.empty() && OC && OC->getNumForLoops()) { for (const OMPLinearClause *C : LCs) { Diag(C->getBeginLoc(), diag::err_omp_linear_ordered) @@ -3952,6 +4383,21 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, } } } + if (ThisCaptureRegion == OMPD_target) { + // Capture allocator traits in the target region. They are used implicitly + // and, thus, are not captured by default. + for (OMPClause *C : Clauses) { + if (const auto *UAC = dyn_cast<OMPUsesAllocatorsClause>(C)) { + for (unsigned I = 0, End = UAC->getNumberOfAllocators(); I < End; + ++I) { + OMPUsesAllocatorsClause::Data D = UAC->getAllocatorData(I); + if (Expr *E = D.AllocatorTraits) + MarkDeclarationsReferencedInExpr(E); + } + continue; + } + } + } if (++CompletedRegions == CaptureRegions.size()) DSAStack->setBodyComplete(); SR = ActOnCapturedRegionEnd(SR.get()); @@ -3991,12 +4437,14 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, ShouldBeInParallelRegion, ShouldBeInOrderedRegion, ShouldBeInTargetRegion, - ShouldBeInTeamsRegion + ShouldBeInTeamsRegion, + ShouldBeInLoopSimdRegion, } Recommend = NoRecommend; if (isOpenMPSimdDirective(ParentRegion) && ((SemaRef.LangOpts.OpenMP <= 45 && CurrentRegion != OMPD_ordered) || (SemaRef.LangOpts.OpenMP >= 50 && CurrentRegion != OMPD_ordered && - CurrentRegion != OMPD_simd && CurrentRegion != OMPD_atomic))) { + CurrentRegion != OMPD_simd && CurrentRegion != OMPD_atomic && + CurrentRegion != OMPD_scan))) { // OpenMP [2.16, Nesting of Regions] // OpenMP constructs may not be nested inside a simd region. // OpenMP [2.8.1,simd Construct, Restrictions] @@ -4041,7 +4489,7 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, if (ParentRegion == OMPD_unknown && !isOpenMPNestingTeamsDirective(CurrentRegion) && CurrentRegion != OMPD_cancellation_point && - CurrentRegion != OMPD_cancel) + CurrentRegion != OMPD_cancel && CurrentRegion != OMPD_scan) return false; if (CurrentRegion == OMPD_cancellation_point || CurrentRegion == OMPD_cancel) { @@ -4066,7 +4514,12 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, ParentRegion == OMPD_distribute_parallel_for || ParentRegion == OMPD_teams_distribute_parallel_for || ParentRegion == OMPD_target_teams_distribute_parallel_for)) || - (CancelRegion == OMPD_taskgroup && ParentRegion == OMPD_task) || + (CancelRegion == OMPD_taskgroup && + (ParentRegion == OMPD_task || + (SemaRef.getLangOpts().OpenMP >= 50 && + (ParentRegion == OMPD_taskloop || + ParentRegion == OMPD_master_taskloop || + ParentRegion == OMPD_parallel_master_taskloop)))) || (CancelRegion == OMPD_sections && (ParentRegion == OMPD_section || ParentRegion == OMPD_sections || ParentRegion == OMPD_parallel_sections))); @@ -4150,6 +4603,17 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, ParentRegion != OMPD_target); OrphanSeen = ParentRegion == OMPD_unknown; Recommend = ShouldBeInTargetRegion; + } else if (CurrentRegion == OMPD_scan) { + // OpenMP [2.16, Nesting of Regions] + // If specified, a teams construct must be contained within a target + // construct. + NestingProhibited = + SemaRef.LangOpts.OpenMP < 50 || + (ParentRegion != OMPD_simd && ParentRegion != OMPD_for && + ParentRegion != OMPD_for_simd && ParentRegion != OMPD_parallel_for && + ParentRegion != OMPD_parallel_for_simd); + OrphanSeen = ParentRegion == OMPD_unknown; + Recommend = ShouldBeInLoopSimdRegion; } if (!NestingProhibited && !isOpenMPTargetExecutionDirective(CurrentRegion) && @@ -4216,7 +4680,7 @@ static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind, bool ErrorFound = false; unsigned NamedModifiersNumber = 0; llvm::IndexedMap<const OMPIfClause *, Kind2Unsigned> FoundNameModifiers; - FoundNameModifiers.resize(unsigned(OMPD_unknown) + 1); + FoundNameModifiers.resize(llvm::omp::Directive_enumSize + 1); SmallVector<SourceLocation, 4> NameModifierLoc; for (const OMPClause *C : Clauses) { if (const auto *IC = dyn_cast_or_null<OMPIfClause>(C)) { @@ -4353,6 +4817,30 @@ static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr, getCanonicalDecl(DE ? DE->getDecl() : ME->getMemberDecl()), false); } +namespace { +/// Checks if the allocator is used in uses_allocators clause to be allowed in +/// target regions. +class AllocatorChecker final : public ConstStmtVisitor<AllocatorChecker, bool> { + DSAStackTy *S = nullptr; + +public: + bool VisitDeclRefExpr(const DeclRefExpr *E) { + return S->isUsesAllocatorsDecl(E->getDecl()) + .getValueOr( + DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait) == + DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait; + } + bool VisitStmt(const Stmt *S) { + for (const Stmt *Child : S->children()) { + if (Child && Visit(Child)) + return true; + } + return false; + } + explicit AllocatorChecker(DSAStackTy *S) : S(S) {} +}; +} // namespace + static void checkAllocateClauses(Sema &S, DSAStackTy *Stack, ArrayRef<OMPClause *> Clauses) { assert(!S.CurContext->isDependentContext() && @@ -4421,6 +4909,22 @@ static void checkAllocateClauses(Sema &S, DSAStackTy *Stack, } for (OMPClause *C : AllocateRange) { auto *AC = cast<OMPAllocateClause>(C); + if (S.getLangOpts().OpenMP >= 50 && + !Stack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>() && + isOpenMPTargetExecutionDirective(Stack->getCurrentDirective()) && + AC->getAllocator()) { + Expr *Allocator = AC->getAllocator(); + // OpenMP, 2.12.5 target Construct + // Memory allocators that do not appear in a uses_allocators clause cannot + // appear as an allocator in an allocate clause or be used in the target + // region unless a requires directive with the dynamic_allocators clause + // is present in the same compilation unit. + AllocatorChecker Checker(Stack); + if (Checker.Visit(Allocator)) + S.Diag(Allocator->getExprLoc(), + diag::err_omp_allocator_not_in_uses_allocators) + << Allocator->getSourceRange(); + } OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind = getAllocatorKind(S, Stack, AC->getAllocator()); // OpenMP, 2.11.4 allocate Clause, Restrictions. @@ -4513,6 +5017,11 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( if (E) ImplicitFirstprivates.emplace_back(E); } + // OpenMP 5.0, 2.10.1 task Construct + // [detach clause]... The event-handle will be considered as if it was + // specified on a firstprivate clause. + if (auto *DC = dyn_cast<OMPDetachClause>(C)) + ImplicitFirstprivates.push_back(DC->getEventHandler()); } if (!ImplicitFirstprivates.empty()) { if (OMPClause *Implicit = ActOnOpenMPFirstprivateClause( @@ -4648,6 +5157,16 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( "No associated statement allowed for 'omp flush' directive"); Res = ActOnOpenMPFlushDirective(ClausesWithImplicit, StartLoc, EndLoc); break; + case OMPD_depobj: + assert(AStmt == nullptr && + "No associated statement allowed for 'omp depobj' directive"); + Res = ActOnOpenMPDepobjDirective(ClausesWithImplicit, StartLoc, EndLoc); + break; + case OMPD_scan: + assert(AStmt == nullptr && + "No associated statement allowed for 'omp scan' directive"); + Res = ActOnOpenMPScanDirective(ClausesWithImplicit, StartLoc, EndLoc); + break; case OMPD_ordered: Res = ActOnOpenMPOrderedDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); @@ -4848,15 +5367,20 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPD_declare_simd: case OMPD_requires: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: + default: llvm_unreachable("Unknown OpenMP directive"); } ErrorFound = Res.isInvalid() || ErrorFound; - // Check variables in the clauses if default(none) was specified. - if (DSAStack->getDefaultDSA() == DSA_none) { + // Check variables in the clauses if default(none) or + // default(firstprivate) was specified. + if (DSAStack->getDefaultDSA() == DSA_none || + DSAStack->getDefaultDSA() == DSA_firstprivate) { DSAAttrChecker DSAChecker(DSAStack, *this, nullptr); for (OMPClause *C : Clauses) { switch (C->getClauseKind()) { @@ -4876,6 +5400,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( break; continue; case OMPC_schedule: + case OMPC_detach: break; case OMPC_grainsize: case OMPC_num_tasks: @@ -4915,6 +5440,10 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPC_update: case OMPC_capture: case OMPC_seq_cst: + case OMPC_acq_rel: + case OMPC_acquire: + case OMPC_release: + case OMPC_relaxed: case OMPC_depend: case OMPC_threads: case OMPC_simd: @@ -4924,11 +5453,19 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_nontemporal: + case OMPC_order: + case OMPC_destroy: + case OMPC_inclusive: + case OMPC_exclusive: + case OMPC_uses_allocators: + case OMPC_affinity: continue; case OMPC_allocator: case OMPC_flush: + case OMPC_depobj: case OMPC_threadprivate: case OMPC_uniform: case OMPC_unknown: @@ -4939,6 +5476,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPC_atomic_default_mem_order: case OMPC_device_type: case OMPC_match: + default: llvm_unreachable("Unexpected clause"); } for (Stmt *CC : C->children()) { @@ -4946,14 +5484,15 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( DSAChecker.Visit(CC); } } - for (auto &P : DSAChecker.getVarsWithInheritedDSA()) + for (const auto &P : DSAChecker.getVarsWithInheritedDSA()) VarsWithInheritedDSA[P.getFirst()] = P.getSecond(); } for (const auto &P : VarsWithInheritedDSA) { if (P.getFirst()->isImplicit() || isa<OMPCapturedExprDecl>(P.getFirst())) continue; ErrorFound = true; - if (DSAStack->getDefaultDSA() == DSA_none) { + if (DSAStack->getDefaultDSA() == DSA_none || + DSAStack->getDefaultDSA() == DSA_firstprivate) { Diag(P.second->getExprLoc(), diag::err_omp_no_dsa_for_variable) << P.first << P.second->getSourceRange(); Diag(DSAStack->getDefaultDSALocation(), diag::note_omp_default_dsa_none); @@ -4973,12 +5512,6 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( if (ErrorFound) return StmtError(); - if (!(Res.getAs<OMPExecutableDirective>()->isStandaloneDirective())) { - Res.getAs<OMPExecutableDirective>() - ->getStructuredBlock() - ->setIsOMPStructuredBlock(true); - } - if (!CurContext->isDependentContext() && isOpenMPTargetExecutionDirective(Kind) && !(DSAStack->hasRequiresDeclWithClause<OMPUnifiedSharedMemoryClause>() || @@ -5166,7 +5699,8 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( E->containsUnexpandedParameterPack()) continue; (void)CheckOpenMPLinearDecl(CanonPVD, E->getExprLoc(), LinKind, - PVD->getOriginalType()); + PVD->getOriginalType(), + /*IsDeclareSimd=*/true); continue; } } @@ -5186,7 +5720,7 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( E->isInstantiationDependent() || E->containsUnexpandedParameterPack()) continue; (void)CheckOpenMPLinearDecl(/*D=*/nullptr, E->getExprLoc(), LinKind, - E->getType()); + E->getType(), /*IsDeclareSimd=*/true); continue; } Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause) @@ -5264,9 +5798,170 @@ static void setPrototype(Sema &S, FunctionDecl *FD, FunctionDecl *FDWithProto, FD->setParams(Params); } +Sema::OMPDeclareVariantScope::OMPDeclareVariantScope(OMPTraitInfo &TI) + : TI(&TI), NameSuffix(TI.getMangledName()) {} + +FunctionDecl * +Sema::ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope(Scope *S, + Declarator &D) { + IdentifierInfo *BaseII = D.getIdentifier(); + LookupResult Lookup(*this, DeclarationName(BaseII), D.getIdentifierLoc(), + LookupOrdinaryName); + LookupParsedName(Lookup, S, &D.getCXXScopeSpec()); + + TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); + QualType FType = TInfo->getType(); + + bool IsConstexpr = D.getDeclSpec().getConstexprSpecifier() == CSK_constexpr; + bool IsConsteval = D.getDeclSpec().getConstexprSpecifier() == CSK_consteval; + + FunctionDecl *BaseFD = nullptr; + for (auto *Candidate : Lookup) { + auto *UDecl = dyn_cast<FunctionDecl>(Candidate->getUnderlyingDecl()); + if (!UDecl) + continue; + + // Don't specialize constexpr/consteval functions with + // non-constexpr/consteval functions. + if (UDecl->isConstexpr() && !IsConstexpr) + continue; + if (UDecl->isConsteval() && !IsConsteval) + continue; + + QualType NewType = Context.mergeFunctionTypes( + FType, UDecl->getType(), /* OfBlockPointer */ false, + /* Unqualified */ false, /* AllowCXX */ true); + if (NewType.isNull()) + continue; + + // Found a base! + BaseFD = UDecl; + break; + } + if (!BaseFD) { + BaseFD = cast<FunctionDecl>(ActOnDeclarator(S, D)); + BaseFD->setImplicit(true); + } + + OMPDeclareVariantScope &DVScope = OMPDeclareVariantScopes.back(); + std::string MangledName; + MangledName += D.getIdentifier()->getName(); + MangledName += getOpenMPVariantManglingSeparatorStr(); + MangledName += DVScope.NameSuffix; + IdentifierInfo &VariantII = Context.Idents.get(MangledName); + + VariantII.setMangledOpenMPVariantName(true); + D.SetIdentifier(&VariantII, D.getBeginLoc()); + return BaseFD; +} + +void Sema::ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope( + FunctionDecl *FD, FunctionDecl *BaseFD) { + // Do not mark function as is used to prevent its emission if this is the + // only place where it is used. + EnterExpressionEvaluationContext Unevaluated( + *this, Sema::ExpressionEvaluationContext::Unevaluated); + + Expr *VariantFuncRef = DeclRefExpr::Create( + Context, NestedNameSpecifierLoc(), SourceLocation(), FD, + /* RefersToEnclosingVariableOrCapture */ false, + /* NameLoc */ FD->getLocation(), FD->getType(), ExprValueKind::VK_RValue); + + OMPDeclareVariantScope &DVScope = OMPDeclareVariantScopes.back(); + auto *OMPDeclareVariantA = OMPDeclareVariantAttr::CreateImplicit( + Context, VariantFuncRef, DVScope.TI); + BaseFD->addAttr(OMPDeclareVariantA); +} + +ExprResult Sema::ActOnOpenMPCall(ExprResult Call, Scope *Scope, + SourceLocation LParenLoc, + MultiExprArg ArgExprs, + SourceLocation RParenLoc, Expr *ExecConfig) { + // The common case is a regular call we do not want to specialize at all. Try + // to make that case fast by bailing early. + CallExpr *CE = dyn_cast<CallExpr>(Call.get()); + if (!CE) + return Call; + + FunctionDecl *CalleeFnDecl = CE->getDirectCallee(); + if (!CalleeFnDecl) + return Call; + + if (!CalleeFnDecl->hasAttr<OMPDeclareVariantAttr>()) + return Call; + + ASTContext &Context = getASTContext(); + OMPContext OMPCtx(getLangOpts().OpenMPIsDevice, + Context.getTargetInfo().getTriple()); + + SmallVector<Expr *, 4> Exprs; + SmallVector<VariantMatchInfo, 4> VMIs; + while (CalleeFnDecl) { + for (OMPDeclareVariantAttr *A : + CalleeFnDecl->specific_attrs<OMPDeclareVariantAttr>()) { + Expr *VariantRef = A->getVariantFuncRef(); + + VariantMatchInfo VMI; + OMPTraitInfo &TI = A->getTraitInfo(); + TI.getAsVariantMatchInfo(Context, VMI); + if (!isVariantApplicableInContext(VMI, OMPCtx, /* DeviceSetOnly */ false)) + continue; + + VMIs.push_back(VMI); + Exprs.push_back(VariantRef); + } + + CalleeFnDecl = CalleeFnDecl->getPreviousDecl(); + } + + ExprResult NewCall; + do { + int BestIdx = getBestVariantMatchForContext(VMIs, OMPCtx); + if (BestIdx < 0) + return Call; + Expr *BestExpr = cast<DeclRefExpr>(Exprs[BestIdx]); + Decl *BestDecl = cast<DeclRefExpr>(BestExpr)->getDecl(); + + { + // Try to build a (member) call expression for the current best applicable + // variant expression. We allow this to fail in which case we continue + // with the next best variant expression. The fail case is part of the + // implementation defined behavior in the OpenMP standard when it talks + // about what differences in the function prototypes: "Any differences + // that the specific OpenMP context requires in the prototype of the + // variant from the base function prototype are implementation defined." + // This wording is there to allow the specialized variant to have a + // different type than the base function. This is intended and OK but if + // we cannot create a call the difference is not in the "implementation + // defined range" we allow. + Sema::TentativeAnalysisScope Trap(*this); + + if (auto *SpecializedMethod = dyn_cast<CXXMethodDecl>(BestDecl)) { + auto *MemberCall = dyn_cast<CXXMemberCallExpr>(CE); + BestExpr = MemberExpr::CreateImplicit( + Context, MemberCall->getImplicitObjectArgument(), + /* IsArrow */ false, SpecializedMethod, Context.BoundMemberTy, + MemberCall->getValueKind(), MemberCall->getObjectKind()); + } + NewCall = BuildCallExpr(Scope, BestExpr, LParenLoc, ArgExprs, RParenLoc, + ExecConfig); + if (NewCall.isUsable()) + break; + } + + VMIs.erase(VMIs.begin() + BestIdx); + Exprs.erase(Exprs.begin() + BestIdx); + } while (!VMIs.empty()); + + if (!NewCall.isUsable()) + return Call; + return PseudoObjectExpr::Create(Context, CE, {NewCall.get()}, 0); +} + Optional<std::pair<FunctionDecl *, Expr *>> Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, - Expr *VariantRef, SourceRange SR) { + Expr *VariantRef, OMPTraitInfo &TI, + SourceRange SR) { if (!DG || DG.get().isNull()) return None; @@ -5319,12 +6014,41 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, return None; } + auto ShouldDelayChecks = [](Expr *&E, bool) { + return E && (E->isTypeDependent() || E->isValueDependent() || + E->containsUnexpandedParameterPack() || + E->isInstantiationDependent()); + }; // Do not check templates, wait until instantiation. - if (VariantRef->isTypeDependent() || VariantRef->isValueDependent() || - VariantRef->containsUnexpandedParameterPack() || - VariantRef->isInstantiationDependent() || FD->isDependentContext()) + if (FD->isDependentContext() || ShouldDelayChecks(VariantRef, false) || + TI.anyScoreOrCondition(ShouldDelayChecks)) return std::make_pair(FD, VariantRef); + // Deal with non-constant score and user condition expressions. + auto HandleNonConstantScoresAndConditions = [this](Expr *&E, + bool IsScore) -> bool { + llvm::APSInt Result; + if (!E || E->isIntegerConstantExpr(Result, Context)) + return false; + + if (IsScore) { + // We warn on non-constant scores and pretend they were not present. + Diag(E->getExprLoc(), diag::warn_omp_declare_variant_score_not_constant) + << E; + E = nullptr; + } else { + // We could replace a non-constant user condition with "false" but we + // will soon need to handle these anyway for the dynamic version of + // OpenMP context selectors. + Diag(E->getExprLoc(), + diag::err_omp_declare_variant_user_condition_not_constant) + << E; + } + return true; + }; + if (TI.anyScoreOrCondition(HandleNonConstantScoresAndConditions)) + return None; + // Convert VariantRef expression to the type of the original function to // resolve possible conflicts. ExprResult VariantRefCast; @@ -5355,7 +6079,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, ImplicitConversionSequence ICS = TryImplicitConversion(VariantRef, FnPtrType.getUnqualifiedType(), /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, + AllowedExplicit::None, /*InOverloadResolution=*/false, /*CStyle=*/false, /*AllowObjCWritebackConversion=*/false); @@ -5497,94 +6221,13 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, return std::make_pair(FD, cast<Expr>(DRE)); } -void Sema::ActOnOpenMPDeclareVariantDirective( - FunctionDecl *FD, Expr *VariantRef, SourceRange SR, - ArrayRef<OMPCtxSelectorData> Data) { - if (Data.empty()) - return; - SmallVector<Expr *, 4> CtxScores; - SmallVector<unsigned, 4> CtxSets; - SmallVector<unsigned, 4> Ctxs; - SmallVector<StringRef, 4> ImplVendors, DeviceKinds; - bool IsError = false; - for (const OMPCtxSelectorData &D : Data) { - OpenMPContextSelectorSetKind CtxSet = D.CtxSet; - OpenMPContextSelectorKind Ctx = D.Ctx; - if (CtxSet == OMP_CTX_SET_unknown || Ctx == OMP_CTX_unknown) - return; - Expr *Score = nullptr; - if (D.Score.isUsable()) { - Score = D.Score.get(); - if (!Score->isTypeDependent() && !Score->isValueDependent() && - !Score->isInstantiationDependent() && - !Score->containsUnexpandedParameterPack()) { - Score = - PerformOpenMPImplicitIntegerConversion(Score->getExprLoc(), Score) - .get(); - if (Score) - Score = VerifyIntegerConstantExpression(Score).get(); - } - } else { - // OpenMP 5.0, 2.3.3 Matching and Scoring Context Selectors. - // The kind, arch, and isa selectors are given the values 2^l, 2^(l+1) and - // 2^(l+2), respectively, where l is the number of traits in the construct - // set. - // TODO: implement correct logic for isa and arch traits. - // TODO: take the construct context set into account when it is - // implemented. - int L = 0; // Currently set the number of traits in construct set to 0, - // since the construct trait set in not supported yet. - if (CtxSet == OMP_CTX_SET_device && Ctx == OMP_CTX_kind) - Score = ActOnIntegerConstant(SourceLocation(), std::pow(2, L)).get(); - else - Score = ActOnIntegerConstant(SourceLocation(), 0).get(); - } - switch (Ctx) { - case OMP_CTX_vendor: - assert(CtxSet == OMP_CTX_SET_implementation && - "Expected implementation context selector set."); - ImplVendors.append(D.Names.begin(), D.Names.end()); - break; - case OMP_CTX_kind: - assert(CtxSet == OMP_CTX_SET_device && - "Expected device context selector set."); - DeviceKinds.append(D.Names.begin(), D.Names.end()); - break; - case OMP_CTX_unknown: - llvm_unreachable("Unknown context selector kind."); - } - IsError = IsError || !Score; - CtxSets.push_back(CtxSet); - Ctxs.push_back(Ctx); - CtxScores.push_back(Score); - } - if (!IsError) { - auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit( - Context, VariantRef, CtxScores.begin(), CtxScores.size(), - CtxSets.begin(), CtxSets.size(), Ctxs.begin(), Ctxs.size(), - ImplVendors.begin(), ImplVendors.size(), DeviceKinds.begin(), - DeviceKinds.size(), SR); - FD->addAttr(NewAttr); - } -} - -void Sema::markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc, - FunctionDecl *Func, - bool MightBeOdrUse) { - assert(LangOpts.OpenMP && "Expected OpenMP mode."); - - if (!Func->isDependentContext() && Func->hasAttrs()) { - for (OMPDeclareVariantAttr *A : - Func->specific_attrs<OMPDeclareVariantAttr>()) { - // TODO: add checks for active OpenMP context where possible. - Expr *VariantRef = A->getVariantFuncRef(); - auto *DRE = cast<DeclRefExpr>(VariantRef->IgnoreParenImpCasts()); - auto *F = cast<FunctionDecl>(DRE->getDecl()); - if (!F->isDefined() && F->isTemplateInstantiation()) - InstantiateFunctionDefinition(Loc, F->getFirstDecl()); - MarkFunctionReferenced(Loc, F, MightBeOdrUse); - } - } +void Sema::ActOnOpenMPDeclareVariantDirective(FunctionDecl *FD, + Expr *VariantRef, + OMPTraitInfo &TI, + SourceRange SR) { + auto *NewAttr = + OMPDeclareVariantAttr::CreateImplicit(Context, VariantRef, &TI, SR); + FD->addAttr(NewAttr); } StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses, @@ -5605,6 +6248,7 @@ StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses, setFunctionHasBranchProtectedScope(); return OMPParallelDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, + DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); } @@ -6300,8 +6944,8 @@ bool OpenMPIterationSpaceChecker::checkAndSetInc(Expr *S) { static ExprResult tryBuildCapture(Sema &SemaRef, Expr *Capture, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) { - if (SemaRef.CurContext->isDependentContext()) - return ExprResult(Capture); + if (SemaRef.CurContext->isDependentContext() || Capture->containsErrors()) + return Capture; if (Capture->isEvaluatable(SemaRef.Context, Expr::SE_AllowSideEffects)) return SemaRef.PerformImplicitConversion( Capture->IgnoreImpCasts(), Capture->getType(), Sema::AA_Converting, @@ -6315,221 +6959,344 @@ tryBuildCapture(Sema &SemaRef, Expr *Capture, return Res; } -/// Build the expression to calculate the number of iterations. -Expr *OpenMPIterationSpaceChecker::buildNumIterations( - Scope *S, ArrayRef<LoopIterationSpace> ResultIterSpaces, bool LimitedType, - llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const { - ExprResult Diff; - QualType VarType = LCDecl->getType().getNonReferenceType(); - if (VarType->isIntegerType() || VarType->isPointerType() || - SemaRef.getLangOpts().CPlusPlus) { - Expr *LBVal = LB; - Expr *UBVal = UB; - // LB = TestIsLessOp.getValue() ? min(LB(MinVal), LB(MaxVal)) : - // max(LB(MinVal), LB(MaxVal)) - if (InitDependOnLC) { - const LoopIterationSpace &IS = - ResultIterSpaces[ResultIterSpaces.size() - 1 - - InitDependOnLC.getValueOr( - CondDependOnLC.getValueOr(0))]; - if (!IS.MinValue || !IS.MaxValue) - return nullptr; - // OuterVar = Min - ExprResult MinValue = - SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue); - if (!MinValue.isUsable()) - return nullptr; - - ExprResult LBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, - IS.CounterVar, MinValue.get()); - if (!LBMinVal.isUsable()) - return nullptr; - // OuterVar = Min, LBVal - LBMinVal = - SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMinVal.get(), LBVal); - if (!LBMinVal.isUsable()) - return nullptr; - // (OuterVar = Min, LBVal) - LBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMinVal.get()); - if (!LBMinVal.isUsable()) - return nullptr; - - // OuterVar = Max - ExprResult MaxValue = - SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue); - if (!MaxValue.isUsable()) - return nullptr; - - ExprResult LBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, - IS.CounterVar, MaxValue.get()); - if (!LBMaxVal.isUsable()) - return nullptr; - // OuterVar = Max, LBVal - LBMaxVal = - SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMaxVal.get(), LBVal); - if (!LBMaxVal.isUsable()) - return nullptr; - // (OuterVar = Max, LBVal) - LBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMaxVal.get()); - if (!LBMaxVal.isUsable()) - return nullptr; - - Expr *LBMin = tryBuildCapture(SemaRef, LBMinVal.get(), Captures).get(); - Expr *LBMax = tryBuildCapture(SemaRef, LBMaxVal.get(), Captures).get(); - if (!LBMin || !LBMax) - return nullptr; - // LB(MinVal) < LB(MaxVal) - ExprResult MinLessMaxRes = - SemaRef.BuildBinOp(S, DefaultLoc, BO_LT, LBMin, LBMax); - if (!MinLessMaxRes.isUsable()) - return nullptr; - Expr *MinLessMax = - tryBuildCapture(SemaRef, MinLessMaxRes.get(), Captures).get(); - if (!MinLessMax) - return nullptr; - if (TestIsLessOp.getValue()) { - // LB(MinVal) < LB(MaxVal) ? LB(MinVal) : LB(MaxVal) - min(LB(MinVal), - // LB(MaxVal)) - ExprResult MinLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc, - MinLessMax, LBMin, LBMax); - if (!MinLB.isUsable()) - return nullptr; - LBVal = MinLB.get(); - } else { - // LB(MinVal) < LB(MaxVal) ? LB(MaxVal) : LB(MinVal) - max(LB(MinVal), - // LB(MaxVal)) - ExprResult MaxLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc, - MinLessMax, LBMax, LBMin); - if (!MaxLB.isUsable()) - return nullptr; - LBVal = MaxLB.get(); - } +/// Calculate number of iterations, transforming to unsigned, if number of +/// iterations may be larger than the original type. +static Expr * +calculateNumIters(Sema &SemaRef, Scope *S, SourceLocation DefaultLoc, + Expr *Lower, Expr *Upper, Expr *Step, QualType LCTy, + bool TestIsStrictOp, bool RoundToStep, + llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) { + ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures); + if (!NewStep.isUsable()) + return nullptr; + llvm::APSInt LRes, URes, SRes; + bool IsLowerConst = Lower->isIntegerConstantExpr(LRes, SemaRef.Context); + bool IsStepConst = Step->isIntegerConstantExpr(SRes, SemaRef.Context); + bool NoNeedToConvert = IsLowerConst && !RoundToStep && + ((!TestIsStrictOp && LRes.isNonNegative()) || + (TestIsStrictOp && LRes.isStrictlyPositive())); + bool NeedToReorganize = false; + // Check if any subexpressions in Lower -Step [+ 1] lead to overflow. + if (!NoNeedToConvert && IsLowerConst && + (TestIsStrictOp || (RoundToStep && IsStepConst))) { + NoNeedToConvert = true; + if (RoundToStep) { + unsigned BW = LRes.getBitWidth() > SRes.getBitWidth() + ? LRes.getBitWidth() + : SRes.getBitWidth(); + LRes = LRes.extend(BW + 1); + LRes.setIsSigned(true); + SRes = SRes.extend(BW + 1); + SRes.setIsSigned(true); + LRes -= SRes; + NoNeedToConvert = LRes.trunc(BW).extend(BW + 1) == LRes; + LRes = LRes.trunc(BW); + } + if (TestIsStrictOp) { + unsigned BW = LRes.getBitWidth(); + LRes = LRes.extend(BW + 1); + LRes.setIsSigned(true); + ++LRes; + NoNeedToConvert = + NoNeedToConvert && LRes.trunc(BW).extend(BW + 1) == LRes; + // truncate to the original bitwidth. + LRes = LRes.trunc(BW); + } + NeedToReorganize = NoNeedToConvert; + } + bool IsUpperConst = Upper->isIntegerConstantExpr(URes, SemaRef.Context); + if (NoNeedToConvert && IsLowerConst && IsUpperConst && + (!RoundToStep || IsStepConst)) { + unsigned BW = LRes.getBitWidth() > URes.getBitWidth() ? LRes.getBitWidth() + : URes.getBitWidth(); + LRes = LRes.extend(BW + 1); + LRes.setIsSigned(true); + URes = URes.extend(BW + 1); + URes.setIsSigned(true); + URes -= LRes; + NoNeedToConvert = URes.trunc(BW).extend(BW + 1) == URes; + NeedToReorganize = NoNeedToConvert; + } + // If the boundaries are not constant or (Lower - Step [+ 1]) is not constant + // or less than zero (Upper - (Lower - Step [+ 1]) may overflow) - promote to + // unsigned. + if ((!NoNeedToConvert || (LRes.isNegative() && !IsUpperConst)) && + !LCTy->isDependentType() && LCTy->isIntegerType()) { + QualType LowerTy = Lower->getType(); + QualType UpperTy = Upper->getType(); + uint64_t LowerSize = SemaRef.Context.getTypeSize(LowerTy); + uint64_t UpperSize = SemaRef.Context.getTypeSize(UpperTy); + if ((LowerSize <= UpperSize && UpperTy->hasSignedIntegerRepresentation()) || + (LowerSize > UpperSize && LowerTy->hasSignedIntegerRepresentation())) { + QualType CastType = SemaRef.Context.getIntTypeForBitwidth( + LowerSize > UpperSize ? LowerSize : UpperSize, /*Signed=*/0); + Upper = + SemaRef + .PerformImplicitConversion( + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Upper).get(), + CastType, Sema::AA_Converting) + .get(); + Lower = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Lower).get(); + NewStep = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, NewStep.get()); } - // UB = TestIsLessOp.getValue() ? max(UB(MinVal), UB(MaxVal)) : - // min(UB(MinVal), UB(MaxVal)) - if (CondDependOnLC) { - const LoopIterationSpace &IS = - ResultIterSpaces[ResultIterSpaces.size() - 1 - - InitDependOnLC.getValueOr( - CondDependOnLC.getValueOr(0))]; - if (!IS.MinValue || !IS.MaxValue) - return nullptr; - // OuterVar = Min - ExprResult MinValue = - SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue); - if (!MinValue.isUsable()) - return nullptr; - - ExprResult UBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, - IS.CounterVar, MinValue.get()); - if (!UBMinVal.isUsable()) - return nullptr; - // OuterVar = Min, UBVal - UBMinVal = - SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMinVal.get(), UBVal); - if (!UBMinVal.isUsable()) - return nullptr; - // (OuterVar = Min, UBVal) - UBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMinVal.get()); - if (!UBMinVal.isUsable()) - return nullptr; + } + if (!Lower || !Upper || NewStep.isInvalid()) + return nullptr; - // OuterVar = Max - ExprResult MaxValue = - SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue); - if (!MaxValue.isUsable()) + ExprResult Diff; + // If need to reorganize, then calculate the form as Upper - (Lower - Step [+ + // 1]). + if (NeedToReorganize) { + Diff = Lower; + + if (RoundToStep) { + // Lower - Step + Diff = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Diff.get(), NewStep.get()); + if (!Diff.isUsable()) return nullptr; + } - ExprResult UBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, - IS.CounterVar, MaxValue.get()); - if (!UBMaxVal.isUsable()) - return nullptr; - // OuterVar = Max, UBVal - UBMaxVal = - SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMaxVal.get(), UBVal); - if (!UBMaxVal.isUsable()) - return nullptr; - // (OuterVar = Max, UBVal) - UBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMaxVal.get()); - if (!UBMaxVal.isUsable()) - return nullptr; + // Lower - Step [+ 1] + if (TestIsStrictOp) + Diff = SemaRef.BuildBinOp( + S, DefaultLoc, BO_Add, Diff.get(), + SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); + if (!Diff.isUsable()) + return nullptr; - Expr *UBMin = tryBuildCapture(SemaRef, UBMinVal.get(), Captures).get(); - Expr *UBMax = tryBuildCapture(SemaRef, UBMaxVal.get(), Captures).get(); - if (!UBMin || !UBMax) - return nullptr; - // UB(MinVal) > UB(MaxVal) - ExprResult MinGreaterMaxRes = - SemaRef.BuildBinOp(S, DefaultLoc, BO_GT, UBMin, UBMax); - if (!MinGreaterMaxRes.isUsable()) - return nullptr; - Expr *MinGreaterMax = - tryBuildCapture(SemaRef, MinGreaterMaxRes.get(), Captures).get(); - if (!MinGreaterMax) - return nullptr; - if (TestIsLessOp.getValue()) { - // UB(MinVal) > UB(MaxVal) ? UB(MinVal) : UB(MaxVal) - max(UB(MinVal), - // UB(MaxVal)) - ExprResult MaxUB = SemaRef.ActOnConditionalOp( - DefaultLoc, DefaultLoc, MinGreaterMax, UBMin, UBMax); - if (!MaxUB.isUsable()) - return nullptr; - UBVal = MaxUB.get(); - } else { - // UB(MinVal) > UB(MaxVal) ? UB(MaxVal) : UB(MinVal) - min(UB(MinVal), - // UB(MaxVal)) - ExprResult MinUB = SemaRef.ActOnConditionalOp( - DefaultLoc, DefaultLoc, MinGreaterMax, UBMax, UBMin); - if (!MinUB.isUsable()) - return nullptr; - UBVal = MinUB.get(); - } - } - // Upper - Lower - Expr *UBExpr = TestIsLessOp.getValue() ? UBVal : LBVal; - Expr *LBExpr = TestIsLessOp.getValue() ? LBVal : UBVal; - Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get(); - Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get(); - if (!Upper || !Lower) + Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); + if (!Diff.isUsable()) return nullptr; + // Upper - (Lower - Step [+ 1]). + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Diff.get()); + if (!Diff.isUsable()) + return nullptr; + } else { Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower); - if (!Diff.isUsable() && VarType->getAsCXXRecordDecl()) { + if (!Diff.isUsable() && LCTy->getAsCXXRecordDecl()) { // BuildBinOp already emitted error, this one is to point user to upper // and lower bound, and to tell what is passed to 'operator-'. SemaRef.Diag(Upper->getBeginLoc(), diag::err_omp_loop_diff_cxx) << Upper->getSourceRange() << Lower->getSourceRange(); return nullptr; } + + if (!Diff.isUsable()) + return nullptr; + + // Upper - Lower [- 1] + if (TestIsStrictOp) + Diff = SemaRef.BuildBinOp( + S, DefaultLoc, BO_Sub, Diff.get(), + SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); + if (!Diff.isUsable()) + return nullptr; + + if (RoundToStep) { + // Upper - Lower [- 1] + Step + Diff = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Diff.get(), NewStep.get()); + if (!Diff.isUsable()) + return nullptr; + } } + // Parentheses (for dumping/debugging purposes only). + Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); if (!Diff.isUsable()) return nullptr; - // Upper - Lower [- 1] - if (TestIsStrictOp) - Diff = SemaRef.BuildBinOp( - S, DefaultLoc, BO_Sub, Diff.get(), - SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); + // (Upper - Lower [- 1] + Step) / Step or (Upper - Lower) / Step + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get()); if (!Diff.isUsable()) return nullptr; - // Upper - Lower [- 1] + Step - ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures); - if (!NewStep.isUsable()) - return nullptr; - Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Diff.get(), NewStep.get()); - if (!Diff.isUsable()) + return Diff.get(); +} + +/// Build the expression to calculate the number of iterations. +Expr *OpenMPIterationSpaceChecker::buildNumIterations( + Scope *S, ArrayRef<LoopIterationSpace> ResultIterSpaces, bool LimitedType, + llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const { + QualType VarType = LCDecl->getType().getNonReferenceType(); + if (!VarType->isIntegerType() && !VarType->isPointerType() && + !SemaRef.getLangOpts().CPlusPlus) return nullptr; + Expr *LBVal = LB; + Expr *UBVal = UB; + // LB = TestIsLessOp.getValue() ? min(LB(MinVal), LB(MaxVal)) : + // max(LB(MinVal), LB(MaxVal)) + if (InitDependOnLC) { + const LoopIterationSpace &IS = + ResultIterSpaces[ResultIterSpaces.size() - 1 - + InitDependOnLC.getValueOr( + CondDependOnLC.getValueOr(0))]; + if (!IS.MinValue || !IS.MaxValue) + return nullptr; + // OuterVar = Min + ExprResult MinValue = + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue); + if (!MinValue.isUsable()) + return nullptr; - // Parentheses (for dumping/debugging purposes only). - Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); - if (!Diff.isUsable()) + ExprResult LBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, + IS.CounterVar, MinValue.get()); + if (!LBMinVal.isUsable()) + return nullptr; + // OuterVar = Min, LBVal + LBMinVal = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMinVal.get(), LBVal); + if (!LBMinVal.isUsable()) + return nullptr; + // (OuterVar = Min, LBVal) + LBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMinVal.get()); + if (!LBMinVal.isUsable()) + return nullptr; + + // OuterVar = Max + ExprResult MaxValue = + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue); + if (!MaxValue.isUsable()) + return nullptr; + + ExprResult LBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, + IS.CounterVar, MaxValue.get()); + if (!LBMaxVal.isUsable()) + return nullptr; + // OuterVar = Max, LBVal + LBMaxVal = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMaxVal.get(), LBVal); + if (!LBMaxVal.isUsable()) + return nullptr; + // (OuterVar = Max, LBVal) + LBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMaxVal.get()); + if (!LBMaxVal.isUsable()) + return nullptr; + + Expr *LBMin = tryBuildCapture(SemaRef, LBMinVal.get(), Captures).get(); + Expr *LBMax = tryBuildCapture(SemaRef, LBMaxVal.get(), Captures).get(); + if (!LBMin || !LBMax) + return nullptr; + // LB(MinVal) < LB(MaxVal) + ExprResult MinLessMaxRes = + SemaRef.BuildBinOp(S, DefaultLoc, BO_LT, LBMin, LBMax); + if (!MinLessMaxRes.isUsable()) + return nullptr; + Expr *MinLessMax = + tryBuildCapture(SemaRef, MinLessMaxRes.get(), Captures).get(); + if (!MinLessMax) + return nullptr; + if (TestIsLessOp.getValue()) { + // LB(MinVal) < LB(MaxVal) ? LB(MinVal) : LB(MaxVal) - min(LB(MinVal), + // LB(MaxVal)) + ExprResult MinLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc, + MinLessMax, LBMin, LBMax); + if (!MinLB.isUsable()) + return nullptr; + LBVal = MinLB.get(); + } else { + // LB(MinVal) < LB(MaxVal) ? LB(MaxVal) : LB(MinVal) - max(LB(MinVal), + // LB(MaxVal)) + ExprResult MaxLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc, + MinLessMax, LBMax, LBMin); + if (!MaxLB.isUsable()) + return nullptr; + LBVal = MaxLB.get(); + } + } + // UB = TestIsLessOp.getValue() ? max(UB(MinVal), UB(MaxVal)) : + // min(UB(MinVal), UB(MaxVal)) + if (CondDependOnLC) { + const LoopIterationSpace &IS = + ResultIterSpaces[ResultIterSpaces.size() - 1 - + InitDependOnLC.getValueOr( + CondDependOnLC.getValueOr(0))]; + if (!IS.MinValue || !IS.MaxValue) + return nullptr; + // OuterVar = Min + ExprResult MinValue = + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue); + if (!MinValue.isUsable()) + return nullptr; + + ExprResult UBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, + IS.CounterVar, MinValue.get()); + if (!UBMinVal.isUsable()) + return nullptr; + // OuterVar = Min, UBVal + UBMinVal = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMinVal.get(), UBVal); + if (!UBMinVal.isUsable()) + return nullptr; + // (OuterVar = Min, UBVal) + UBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMinVal.get()); + if (!UBMinVal.isUsable()) + return nullptr; + + // OuterVar = Max + ExprResult MaxValue = + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue); + if (!MaxValue.isUsable()) + return nullptr; + + ExprResult UBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, + IS.CounterVar, MaxValue.get()); + if (!UBMaxVal.isUsable()) + return nullptr; + // OuterVar = Max, UBVal + UBMaxVal = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMaxVal.get(), UBVal); + if (!UBMaxVal.isUsable()) + return nullptr; + // (OuterVar = Max, UBVal) + UBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMaxVal.get()); + if (!UBMaxVal.isUsable()) + return nullptr; + + Expr *UBMin = tryBuildCapture(SemaRef, UBMinVal.get(), Captures).get(); + Expr *UBMax = tryBuildCapture(SemaRef, UBMaxVal.get(), Captures).get(); + if (!UBMin || !UBMax) + return nullptr; + // UB(MinVal) > UB(MaxVal) + ExprResult MinGreaterMaxRes = + SemaRef.BuildBinOp(S, DefaultLoc, BO_GT, UBMin, UBMax); + if (!MinGreaterMaxRes.isUsable()) + return nullptr; + Expr *MinGreaterMax = + tryBuildCapture(SemaRef, MinGreaterMaxRes.get(), Captures).get(); + if (!MinGreaterMax) + return nullptr; + if (TestIsLessOp.getValue()) { + // UB(MinVal) > UB(MaxVal) ? UB(MinVal) : UB(MaxVal) - max(UB(MinVal), + // UB(MaxVal)) + ExprResult MaxUB = SemaRef.ActOnConditionalOp( + DefaultLoc, DefaultLoc, MinGreaterMax, UBMin, UBMax); + if (!MaxUB.isUsable()) + return nullptr; + UBVal = MaxUB.get(); + } else { + // UB(MinVal) > UB(MaxVal) ? UB(MaxVal) : UB(MinVal) - min(UB(MinVal), + // UB(MaxVal)) + ExprResult MinUB = SemaRef.ActOnConditionalOp( + DefaultLoc, DefaultLoc, MinGreaterMax, UBMax, UBMin); + if (!MinUB.isUsable()) + return nullptr; + UBVal = MinUB.get(); + } + } + Expr *UBExpr = TestIsLessOp.getValue() ? UBVal : LBVal; + Expr *LBExpr = TestIsLessOp.getValue() ? LBVal : UBVal; + Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get(); + Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get(); + if (!Upper || !Lower) return nullptr; - // (Upper - Lower [- 1] + Step) / Step - Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get()); + ExprResult Diff = + calculateNumIters(SemaRef, S, DefaultLoc, Lower, Upper, Step, VarType, + TestIsStrictOp, /*RoundToStep=*/true, Captures); if (!Diff.isUsable()) return nullptr; @@ -6603,55 +7370,37 @@ std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues( MaxExpr = Upper; // Build minimum/maximum value based on number of iterations. - ExprResult Diff; QualType VarType = LCDecl->getType().getNonReferenceType(); - Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower); + ExprResult Diff = + calculateNumIters(SemaRef, S, DefaultLoc, Lower, Upper, Step, VarType, + TestIsStrictOp, /*RoundToStep=*/false, Captures); if (!Diff.isUsable()) return std::make_pair(nullptr, nullptr); - // Upper - Lower [- 1] - if (TestIsStrictOp) - Diff = SemaRef.BuildBinOp( - S, DefaultLoc, BO_Sub, Diff.get(), - SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); + // ((Upper - Lower [- 1]) / Step) * Step + // Parentheses (for dumping/debugging purposes only). + Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); if (!Diff.isUsable()) return std::make_pair(nullptr, nullptr); - // Upper - Lower [- 1] + Step ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures); if (!NewStep.isUsable()) return std::make_pair(nullptr, nullptr); - - // Parentheses (for dumping/debugging purposes only). - Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); - if (!Diff.isUsable()) - return std::make_pair(nullptr, nullptr); - - // (Upper - Lower [- 1]) / Step - Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get()); + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Mul, Diff.get(), NewStep.get()); if (!Diff.isUsable()) return std::make_pair(nullptr, nullptr); - // ((Upper - Lower [- 1]) / Step) * Step // Parentheses (for dumping/debugging purposes only). Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); if (!Diff.isUsable()) return std::make_pair(nullptr, nullptr); - Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Mul, Diff.get(), NewStep.get()); - if (!Diff.isUsable()) - return std::make_pair(nullptr, nullptr); - - // Convert to the original type or ptrdiff_t, if original type is pointer. - if (!VarType->isAnyPointerType() && - !SemaRef.Context.hasSameType(Diff.get()->getType(), VarType)) { - Diff = SemaRef.PerformImplicitConversion( - Diff.get(), VarType, Sema::AA_Converting, /*AllowExplicit=*/true); - } else if (VarType->isAnyPointerType() && - !SemaRef.Context.hasSameType( - Diff.get()->getType(), - SemaRef.Context.getUnsignedPointerDiffType())) { + // Convert to the ptrdiff_t, if original type is pointer. + if (VarType->isAnyPointerType() && + !SemaRef.Context.hasSameType( + Diff.get()->getType(), + SemaRef.Context.getUnsignedPointerDiffType())) { Diff = SemaRef.PerformImplicitConversion( Diff.get(), SemaRef.Context.getUnsignedPointerDiffType(), Sema::AA_Converting, /*AllowExplicit=*/true); @@ -6659,33 +7408,43 @@ std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues( if (!Diff.isUsable()) return std::make_pair(nullptr, nullptr); - // Parentheses (for dumping/debugging purposes only). - Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); - if (!Diff.isUsable()) - return std::make_pair(nullptr, nullptr); - if (TestIsLessOp.getValue()) { // MinExpr = Lower; // MaxExpr = Lower + (((Upper - Lower [- 1]) / Step) * Step) - Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Lower, Diff.get()); - if (!Diff.isUsable()) - return std::make_pair(nullptr, nullptr); - Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue*/ false); + Diff = SemaRef.BuildBinOp( + S, DefaultLoc, BO_Add, + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Lower).get(), + Diff.get()); if (!Diff.isUsable()) return std::make_pair(nullptr, nullptr); - MaxExpr = Diff.get(); } else { // MaxExpr = Upper; // MinExpr = Upper - (((Upper - Lower [- 1]) / Step) * Step) - Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Diff.get()); - if (!Diff.isUsable()) - return std::make_pair(nullptr, nullptr); - Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue*/ false); + Diff = SemaRef.BuildBinOp( + S, DefaultLoc, BO_Sub, + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Upper).get(), + Diff.get()); if (!Diff.isUsable()) return std::make_pair(nullptr, nullptr); - MinExpr = Diff.get(); } + // Convert to the original type. + if (SemaRef.Context.hasSameType(Diff.get()->getType(), VarType)) + Diff = SemaRef.PerformImplicitConversion(Diff.get(), VarType, + Sema::AA_Converting, + /*AllowExplicit=*/true); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue=*/false); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + if (TestIsLessOp.getValue()) + MaxExpr = Diff.get(); + else + MinExpr = Diff.get(); + return std::make_pair(MinExpr, MaxExpr); } @@ -6791,44 +7550,23 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData( if (!Cnt) return nullptr; } - ExprResult Diff; QualType VarType = LCDecl->getType().getNonReferenceType(); - if (VarType->isIntegerType() || VarType->isPointerType() || - SemaRef.getLangOpts().CPlusPlus) { - // Upper - Lower - Expr *Upper = TestIsLessOp.getValue() - ? Cnt - : tryBuildCapture(SemaRef, UB, Captures).get(); - Expr *Lower = TestIsLessOp.getValue() - ? tryBuildCapture(SemaRef, LB, Captures).get() - : Cnt; - if (!Upper || !Lower) - return nullptr; - - Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower); - - if (!Diff.isUsable() && VarType->getAsCXXRecordDecl()) { - // BuildBinOp already emitted error, this one is to point user to upper - // and lower bound, and to tell what is passed to 'operator-'. - SemaRef.Diag(Upper->getBeginLoc(), diag::err_omp_loop_diff_cxx) - << Upper->getSourceRange() << Lower->getSourceRange(); - return nullptr; - } - } - - if (!Diff.isUsable()) + if (!VarType->isIntegerType() && !VarType->isPointerType() && + !SemaRef.getLangOpts().CPlusPlus) return nullptr; - - // Parentheses (for dumping/debugging purposes only). - Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); - if (!Diff.isUsable()) + // Upper - Lower + Expr *Upper = TestIsLessOp.getValue() + ? Cnt + : tryBuildCapture(SemaRef, LB, Captures).get(); + Expr *Lower = TestIsLessOp.getValue() + ? tryBuildCapture(SemaRef, LB, Captures).get() + : Cnt; + if (!Upper || !Lower) return nullptr; - ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures); - if (!NewStep.isUsable()) - return nullptr; - // (Upper - Lower) / Step - Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get()); + ExprResult Diff = calculateNumIters(SemaRef, S, DefaultLoc, Lower, Upper, + Step, VarType, /*TestIsStrictOp=*/false, + /*RoundToStep=*/false, Captures); if (!Diff.isUsable()) return nullptr; @@ -8088,8 +8826,9 @@ Sema::ActOnOpenMPForDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, } setFunctionHasBranchProtectedScope(); - return OMPForDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, - Clauses, AStmt, B, DSAStack->isCancelRegion()); + return OMPForDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, + DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPForSimdDirective( @@ -8166,6 +8905,7 @@ StmtResult Sema::ActOnOpenMPSectionsDirective(ArrayRef<OMPClause *> Clauses, setFunctionHasBranchProtectedScope(); return OMPSectionsDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, + DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); } @@ -8326,9 +9066,9 @@ StmtResult Sema::ActOnOpenMPParallelForDirective( } setFunctionHasBranchProtectedScope(); - return OMPParallelForDirective::Create(Context, StartLoc, EndLoc, - NestedLoopCount, Clauses, AStmt, B, - DSAStack->isCancelRegion()); + return OMPParallelForDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, + DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPParallelForSimdDirective( @@ -8392,8 +9132,9 @@ Sema::ActOnOpenMPParallelMasterDirective(ArrayRef<OMPClause *> Clauses, setFunctionHasBranchProtectedScope(); - return OMPParallelMasterDirective::Create(Context, StartLoc, EndLoc, Clauses, - AStmt); + return OMPParallelMasterDirective::Create( + Context, StartLoc, EndLoc, Clauses, AStmt, + DSAStack->getTaskgroupReductionRef()); } StmtResult @@ -8432,7 +9173,31 @@ Sema::ActOnOpenMPParallelSectionsDirective(ArrayRef<OMPClause *> Clauses, setFunctionHasBranchProtectedScope(); return OMPParallelSectionsDirective::Create( - Context, StartLoc, EndLoc, Clauses, AStmt, DSAStack->isCancelRegion()); + Context, StartLoc, EndLoc, Clauses, AStmt, + DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); +} + +/// detach and mergeable clauses are mutially exclusive, check for it. +static bool checkDetachMergeableClauses(Sema &S, + ArrayRef<OMPClause *> Clauses) { + const OMPClause *PrevClause = nullptr; + bool ErrorFound = false; + for (const OMPClause *C : Clauses) { + if (C->getClauseKind() == OMPC_detach || + C->getClauseKind() == OMPC_mergeable) { + if (!PrevClause) { + PrevClause = C; + } else if (PrevClause->getClauseKind() != C->getClauseKind()) { + S.Diag(C->getBeginLoc(), diag::err_omp_clauses_mutually_exclusive) + << getOpenMPClauseName(C->getClauseKind()) + << getOpenMPClauseName(PrevClause->getClauseKind()); + S.Diag(PrevClause->getBeginLoc(), diag::note_omp_previous_clause) + << getOpenMPClauseName(PrevClause->getClauseKind()); + ErrorFound = true; + } + } + } + return ErrorFound; } StmtResult Sema::ActOnOpenMPTaskDirective(ArrayRef<OMPClause *> Clauses, @@ -8441,6 +9206,12 @@ StmtResult Sema::ActOnOpenMPTaskDirective(ArrayRef<OMPClause *> Clauses, if (!AStmt) return StmtError(); + // OpenMP 5.0, 2.10.1 task Construct + // If a detach clause appears on the directive, then a mergeable clause cannot + // appear on the same directive. + if (checkDetachMergeableClauses(*this, Clauses)) + return StmtError(); + auto *CS = cast<CapturedStmt>(AStmt); // 1.2.2 OpenMP Language Terminology // Structured block - An executable statement with a single entry at the @@ -8489,10 +9260,94 @@ StmtResult Sema::ActOnOpenMPTaskgroupDirective(ArrayRef<OMPClause *> Clauses, StmtResult Sema::ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses, SourceLocation StartLoc, SourceLocation EndLoc) { - assert(Clauses.size() <= 1 && "Extra clauses in flush directive"); + OMPFlushClause *FC = nullptr; + OMPClause *OrderClause = nullptr; + for (OMPClause *C : Clauses) { + if (C->getClauseKind() == OMPC_flush) + FC = cast<OMPFlushClause>(C); + else + OrderClause = C; + } + OpenMPClauseKind MemOrderKind = OMPC_unknown; + SourceLocation MemOrderLoc; + for (const OMPClause *C : Clauses) { + if (C->getClauseKind() == OMPC_acq_rel || + C->getClauseKind() == OMPC_acquire || + C->getClauseKind() == OMPC_release) { + if (MemOrderKind != OMPC_unknown) { + Diag(C->getBeginLoc(), diag::err_omp_several_mem_order_clauses) + << getOpenMPDirectiveName(OMPD_flush) << 1 + << SourceRange(C->getBeginLoc(), C->getEndLoc()); + Diag(MemOrderLoc, diag::note_omp_previous_mem_order_clause) + << getOpenMPClauseName(MemOrderKind); + } else { + MemOrderKind = C->getClauseKind(); + MemOrderLoc = C->getBeginLoc(); + } + } + } + if (FC && OrderClause) { + Diag(FC->getLParenLoc(), diag::err_omp_flush_order_clause_and_list) + << getOpenMPClauseName(OrderClause->getClauseKind()); + Diag(OrderClause->getBeginLoc(), diag::note_omp_flush_order_clause_here) + << getOpenMPClauseName(OrderClause->getClauseKind()); + return StmtError(); + } return OMPFlushDirective::Create(Context, StartLoc, EndLoc, Clauses); } +StmtResult Sema::ActOnOpenMPDepobjDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc) { + if (Clauses.empty()) { + Diag(StartLoc, diag::err_omp_depobj_expected); + return StmtError(); + } else if (Clauses[0]->getClauseKind() != OMPC_depobj) { + Diag(Clauses[0]->getBeginLoc(), diag::err_omp_depobj_expected); + return StmtError(); + } + // Only depobj expression and another single clause is allowed. + if (Clauses.size() > 2) { + Diag(Clauses[2]->getBeginLoc(), + diag::err_omp_depobj_single_clause_expected); + return StmtError(); + } else if (Clauses.size() < 1) { + Diag(Clauses[0]->getEndLoc(), diag::err_omp_depobj_single_clause_expected); + return StmtError(); + } + return OMPDepobjDirective::Create(Context, StartLoc, EndLoc, Clauses); +} + +StmtResult Sema::ActOnOpenMPScanDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc) { + // Check that exactly one clause is specified. + if (Clauses.size() != 1) { + Diag(Clauses.empty() ? EndLoc : Clauses[1]->getBeginLoc(), + diag::err_omp_scan_single_clause_expected); + return StmtError(); + } + // Check that scan directive is used in the scopeof the OpenMP loop body. + if (Scope *S = DSAStack->getCurScope()) { + Scope *ParentS = S->getParent(); + if (!ParentS || ParentS->getParent() != ParentS->getBreakParent() || + !ParentS->getBreakParent()->isOpenMPLoopScope()) + return StmtError(Diag(StartLoc, diag::err_omp_orphaned_device_directive) + << getOpenMPDirectiveName(OMPD_scan) << 5); + } + // Check that only one instance of scan directives is used in the same outer + // region. + if (DSAStack->doesParentHasScanDirective()) { + Diag(StartLoc, diag::err_omp_several_directives_in_region) << "scan"; + Diag(DSAStack->getParentScanDirectiveLoc(), + diag::note_omp_previous_directive) + << "scan"; + return StmtError(); + } + DSAStack->setParentHasScanDirective(StartLoc); + return OMPScanDirective::Create(Context, StartLoc, EndLoc, Clauses); +} + StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, @@ -8555,13 +9410,29 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses, SourceLocation ErrLoc = TC ? TC->getBeginLoc() : StartLoc; Diag(ErrLoc, diag::err_omp_ordered_directive_with_param) << (TC != nullptr); - Diag(Param->getBeginLoc(), diag::note_omp_ordered_param); + Diag(Param->getBeginLoc(), diag::note_omp_ordered_param) << 1; ErrorFound = true; } } if ((!AStmt && !DependFound) || ErrorFound) return StmtError(); + // OpenMP 5.0, 2.17.9, ordered Construct, Restrictions. + // During execution of an iteration of a worksharing-loop or a loop nest + // within a worksharing-loop, simd, or worksharing-loop SIMD region, a thread + // must not execute more than one ordered region corresponding to an ordered + // construct without a depend clause. + if (!DependFound) { + if (DSAStack->doesParentHasOrderedDirective()) { + Diag(StartLoc, diag::err_omp_several_directives_in_region) << "ordered"; + Diag(DSAStack->getParentOrderedDirectiveLoc(), + diag::note_omp_previous_directive) + << "ordered"; + return StmtError(); + } + DSAStack->setParentHasOrderedDirective(StartLoc); + } + if (AStmt) { assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); @@ -8817,6 +9688,8 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { + // Register location of the first atomic directive. + DSAStack->addAtomicDirectiveLoc(StartLoc); if (!AStmt) return StmtError(); @@ -8828,6 +9701,8 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, // longjmp() and throw() must not violate the entry/exit criteria. OpenMPClauseKind AtomicKind = OMPC_unknown; SourceLocation AtomicKindLoc; + OpenMPClauseKind MemOrderKind = OMPC_unknown; + SourceLocation MemOrderLoc; for (const OMPClause *C : Clauses) { if (C->getClauseKind() == OMPC_read || C->getClauseKind() == OMPC_write || C->getClauseKind() == OMPC_update || @@ -8835,13 +9710,51 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, if (AtomicKind != OMPC_unknown) { Diag(C->getBeginLoc(), diag::err_omp_atomic_several_clauses) << SourceRange(C->getBeginLoc(), C->getEndLoc()); - Diag(AtomicKindLoc, diag::note_omp_atomic_previous_clause) + Diag(AtomicKindLoc, diag::note_omp_previous_mem_order_clause) << getOpenMPClauseName(AtomicKind); } else { AtomicKind = C->getClauseKind(); AtomicKindLoc = C->getBeginLoc(); } } + if (C->getClauseKind() == OMPC_seq_cst || + C->getClauseKind() == OMPC_acq_rel || + C->getClauseKind() == OMPC_acquire || + C->getClauseKind() == OMPC_release || + C->getClauseKind() == OMPC_relaxed) { + if (MemOrderKind != OMPC_unknown) { + Diag(C->getBeginLoc(), diag::err_omp_several_mem_order_clauses) + << getOpenMPDirectiveName(OMPD_atomic) << 0 + << SourceRange(C->getBeginLoc(), C->getEndLoc()); + Diag(MemOrderLoc, diag::note_omp_previous_mem_order_clause) + << getOpenMPClauseName(MemOrderKind); + } else { + MemOrderKind = C->getClauseKind(); + MemOrderLoc = C->getBeginLoc(); + } + } + } + // OpenMP 5.0, 2.17.7 atomic Construct, Restrictions + // If atomic-clause is read then memory-order-clause must not be acq_rel or + // release. + // If atomic-clause is write then memory-order-clause must not be acq_rel or + // acquire. + // If atomic-clause is update or not present then memory-order-clause must not + // be acq_rel or acquire. + if ((AtomicKind == OMPC_read && + (MemOrderKind == OMPC_acq_rel || MemOrderKind == OMPC_release)) || + ((AtomicKind == OMPC_write || AtomicKind == OMPC_update || + AtomicKind == OMPC_unknown) && + (MemOrderKind == OMPC_acq_rel || MemOrderKind == OMPC_acquire))) { + SourceLocation Loc = AtomicKindLoc; + if (AtomicKind == OMPC_unknown) + Loc = StartLoc; + Diag(Loc, diag::err_omp_atomic_incompatible_mem_order_clause) + << getOpenMPClauseName(AtomicKind) + << (AtomicKind == OMPC_unknown ? 1 : 0) + << getOpenMPClauseName(MemOrderKind); + Diag(MemOrderLoc, diag::note_omp_previous_mem_order_clause) + << getOpenMPClauseName(MemOrderKind); } Stmt *Body = CS->getCapturedStmt(); @@ -9338,8 +10251,9 @@ Sema::ActOnOpenMPTargetParallelDirective(ArrayRef<OMPClause *> Clauses, setFunctionHasBranchProtectedScope(); - return OMPTargetParallelDirective::Create(Context, StartLoc, EndLoc, Clauses, - AStmt); + return OMPTargetParallelDirective::Create( + Context, StartLoc, EndLoc, Clauses, AStmt, + DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPTargetParallelForDirective( @@ -9391,9 +10305,9 @@ StmtResult Sema::ActOnOpenMPTargetParallelForDirective( } setFunctionHasBranchProtectedScope(); - return OMPTargetParallelForDirective::Create(Context, StartLoc, EndLoc, - NestedLoopCount, Clauses, AStmt, - B, DSAStack->isCancelRegion()); + return OMPTargetParallelForDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, + DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); } /// Check for existence of a map clause in the list of clauses. @@ -9418,12 +10332,18 @@ 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 (!hasClauses(Clauses, OMPC_map, OMPC_use_device_ptr)) { + // OpenMP [2.12.2, target data Construct, Restrictions] + // At least one map, use_device_addr or use_device_ptr clause must appear on + // the directive. + if (!hasClauses(Clauses, OMPC_map, OMPC_use_device_ptr) && + (LangOpts.OpenMP < 50 || !hasClauses(Clauses, OMPC_use_device_addr))) { + StringRef Expected; + if (LangOpts.OpenMP < 50) + Expected = "'map' or 'use_device_ptr'"; + else + Expected = "'map', 'use_device_ptr', or 'use_device_addr'"; Diag(StartLoc, diag::err_omp_no_clause_for_directive) - << "'map' or 'use_device_ptr'" - << getOpenMPDirectiveName(OMPD_target_data); + << Expected << getOpenMPDirectiveName(OMPD_target_data); return StmtError(); } @@ -9604,12 +10524,10 @@ static bool checkGrainsizeNumTasksClauses(Sema &S, if (!PrevClause) PrevClause = C; else if (PrevClause->getClauseKind() != C->getClauseKind()) { - S.Diag(C->getBeginLoc(), - diag::err_omp_grainsize_num_tasks_mutually_exclusive) + S.Diag(C->getBeginLoc(), diag::err_omp_clauses_mutually_exclusive) << getOpenMPClauseName(C->getClauseKind()) << getOpenMPClauseName(PrevClause->getClauseKind()); - S.Diag(PrevClause->getBeginLoc(), - diag::note_omp_previous_grainsize_num_tasks) + S.Diag(PrevClause->getBeginLoc(), diag::note_omp_previous_clause) << getOpenMPClauseName(PrevClause->getClauseKind()); ErrorFound = true; } @@ -9678,7 +10596,8 @@ StmtResult Sema::ActOnOpenMPTaskLoopDirective( setFunctionHasBranchProtectedScope(); return OMPTaskLoopDirective::Create(Context, StartLoc, EndLoc, - NestedLoopCount, Clauses, AStmt, B); + NestedLoopCount, Clauses, AStmt, B, + DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective( @@ -9763,7 +10682,8 @@ StmtResult Sema::ActOnOpenMPMasterTaskLoopDirective( setFunctionHasBranchProtectedScope(); return OMPMasterTaskLoopDirective::Create(Context, StartLoc, EndLoc, - NestedLoopCount, Clauses, AStmt, B); + NestedLoopCount, Clauses, AStmt, B, + DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPMasterTaskLoopSimdDirective( @@ -9867,7 +10787,8 @@ StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopDirective( setFunctionHasBranchProtectedScope(); return OMPParallelMasterTaskLoopDirective::Create( - Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, + DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopSimdDirective( @@ -10004,7 +10925,7 @@ StmtResult Sema::ActOnOpenMPDistributeParallelForDirective( setFunctionHasBranchProtectedScope(); return OMPDistributeParallelForDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, - DSAStack->isCancelRegion()); + DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPDistributeParallelForSimdDirective( @@ -10301,7 +11222,6 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeSimdDirective( CS->getCapturedDecl()->setNothrow(); } - OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. @@ -10446,7 +11366,7 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForDirective( return OMPTeamsDistributeParallelForDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, - DSAStack->isCancelRegion()); + DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPTargetTeamsDirective(ArrayRef<OMPClause *> Clauses, @@ -10575,7 +11495,7 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForDirective( setFunctionHasBranchProtectedScope(); return OMPTargetTeamsDistributeParallelForDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, - DSAStack->isCancelRegion()); + DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective( @@ -10721,9 +11641,6 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_ordered: Res = ActOnOpenMPOrderedClause(StartLoc, EndLoc, LParenLoc, Expr); break; - case OMPC_device: - Res = ActOnOpenMPDeviceClause(Expr, StartLoc, LParenLoc, EndLoc); - break; case OMPC_num_teams: Res = ActOnOpenMPNumTeamsClause(Expr, StartLoc, LParenLoc, EndLoc); break; @@ -10742,6 +11659,13 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_hint: Res = ActOnOpenMPHintClause(Expr, StartLoc, LParenLoc, EndLoc); break; + case OMPC_depobj: + Res = ActOnOpenMPDepobjClause(Expr, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_detach: + Res = ActOnOpenMPDetachClause(Expr, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_device: case OMPC_if: case OMPC_default: case OMPC_proc_bind: @@ -10768,6 +11692,10 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_update: case OMPC_capture: case OMPC_seq_cst: + case OMPC_acq_rel: + case OMPC_acquire: + case OMPC_release: + case OMPC_relaxed: case OMPC_depend: case OMPC_threads: case OMPC_simd: @@ -10780,6 +11708,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_unified_address: case OMPC_unified_shared_memory: @@ -10789,6 +11718,13 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_device_type: case OMPC_match: case OMPC_nontemporal: + case OMPC_order: + case OMPC_destroy: + case OMPC_inclusive: + case OMPC_exclusive: + case OMPC_uses_allocators: + case OMPC_affinity: + default: llvm_unreachable("Clause is not allowed."); } return Res; @@ -10918,10 +11854,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: + case OMPD_depobj: + case OMPD_scan: case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_teams: @@ -10939,6 +11879,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_requires: llvm_unreachable("Unexpected OpenMP directive with if-clause"); case OMPD_unknown: + default: llvm_unreachable("Unknown OpenMP directive"); } break; @@ -10988,10 +11929,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: + case OMPD_depobj: + case OMPD_scan: case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_teams: @@ -11013,6 +11958,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_requires: llvm_unreachable("Unexpected OpenMP directive with num_threads-clause"); case OMPD_unknown: + default: llvm_unreachable("Unknown OpenMP directive"); } break; @@ -11063,10 +12009,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: + case OMPD_depobj: + case OMPD_scan: case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -11085,6 +12035,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_requires: llvm_unreachable("Unexpected OpenMP directive with num_teams-clause"); case OMPD_unknown: + default: llvm_unreachable("Unknown OpenMP directive"); } break; @@ -11135,10 +12086,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: + case OMPD_depobj: + case OMPD_scan: case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -11157,6 +12112,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_requires: llvm_unreachable("Unexpected OpenMP directive with thread_limit-clause"); case OMPD_unknown: + default: llvm_unreachable("Unknown OpenMP directive"); } break; @@ -11208,10 +12164,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: + case OMPD_depobj: + case OMPD_scan: case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -11229,6 +12189,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_requires: llvm_unreachable("Unexpected OpenMP directive with schedule clause"); case OMPD_unknown: + default: llvm_unreachable("Unknown OpenMP directive"); } break; @@ -11280,10 +12241,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: + case OMPD_depobj: + case OMPD_scan: case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -11301,6 +12266,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_requires: llvm_unreachable("Unexpected OpenMP directive with schedule clause"); case OMPD_unknown: + default: llvm_unreachable("Unknown OpenMP directive"); } break; @@ -11351,10 +12317,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: + case OMPD_depobj: + case OMPD_scan: case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -11373,6 +12343,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_requires: llvm_unreachable("Unexpected OpenMP directive with num_teams-clause"); case OMPD_unknown: + default: llvm_unreachable("Unknown OpenMP directive"); } break; @@ -11425,10 +12396,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: + case OMPD_depobj: + case OMPD_scan: case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -11447,6 +12422,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_requires: llvm_unreachable("Unexpected OpenMP directive with grainsize-clause"); case OMPD_unknown: + default: llvm_unreachable("Unknown OpenMP directive"); } break; @@ -11474,11 +12450,16 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_threadprivate: case OMPC_allocate: case OMPC_flush: + case OMPC_depobj: case OMPC_read: case OMPC_write: case OMPC_update: case OMPC_capture: case OMPC_seq_cst: + case OMPC_acq_rel: + case OMPC_acquire: + case OMPC_release: + case OMPC_relaxed: case OMPC_depend: case OMPC_threads: case OMPC_simd: @@ -11491,6 +12472,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_unified_address: case OMPC_unified_shared_memory: @@ -11500,6 +12482,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_device_type: case OMPC_match: case OMPC_nontemporal: + case OMPC_order: + case OMPC_destroy: + case OMPC_detach: + case OMPC_inclusive: + case OMPC_exclusive: + case OMPC_uses_allocators: + case OMPC_affinity: + default: llvm_unreachable("Unexpected OpenMP clause."); } return CaptureRegion; @@ -11747,8 +12737,7 @@ static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc, return true; // Build the predefined allocator expressions. bool ErrorFound = false; - for (int I = OMPAllocateDeclAttr::OMPDefaultMemAlloc; - I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) { + for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) { auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I); StringRef Allocator = OMPAllocateDeclAttr::ConvertAllocatorTypeTyToStr(AllocatorKind); @@ -11775,7 +12764,8 @@ static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc, Stack->setAllocator(AllocatorKind, Res.get()); } if (ErrorFound) { - S.Diag(Loc, diag::err_implied_omp_allocator_handle_t_not_found); + S.Diag(Loc, diag::err_omp_implied_type_not_found) + << "omp_allocator_handle_t"; return false; } OMPAllocatorHandleT.addConst(); @@ -11852,9 +12842,8 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( OMPClause *Res = nullptr; switch (Kind) { case OMPC_default: - Res = - ActOnOpenMPDefaultClause(static_cast<OpenMPDefaultClauseKind>(Argument), - ArgumentLoc, StartLoc, LParenLoc, EndLoc); + Res = ActOnOpenMPDefaultClause(static_cast<DefaultKind>(Argument), + ArgumentLoc, StartLoc, LParenLoc, EndLoc); break; case OMPC_proc_bind: Res = ActOnOpenMPProcBindClause(static_cast<ProcBindKind>(Argument), @@ -11865,6 +12854,14 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( static_cast<OpenMPAtomicDefaultMemOrderClauseKind>(Argument), ArgumentLoc, StartLoc, LParenLoc, EndLoc); break; + case OMPC_order: + Res = ActOnOpenMPOrderClause(static_cast<OpenMPOrderClauseKind>(Argument), + ArgumentLoc, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_update: + Res = ActOnOpenMPUpdateClause(static_cast<OpenMPDependClauseKind>(Argument), + ArgumentLoc, StartLoc, LParenLoc, EndLoc); + break; case OMPC_if: case OMPC_final: case OMPC_num_threads: @@ -11891,11 +12888,15 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_threadprivate: case OMPC_allocate: case OMPC_flush: + case OMPC_depobj: case OMPC_read: case OMPC_write: - case OMPC_update: case OMPC_capture: case OMPC_seq_cst: + case OMPC_acq_rel: + case OMPC_acquire: + case OMPC_release: + case OMPC_relaxed: case OMPC_depend: case OMPC_device: case OMPC_threads: @@ -11915,6 +12916,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_unified_address: case OMPC_unified_shared_memory: @@ -11923,6 +12925,13 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_device_type: case OMPC_match: case OMPC_nontemporal: + case OMPC_destroy: + case OMPC_detach: + case OMPC_inclusive: + case OMPC_exclusive: + case OMPC_uses_allocators: + case OMPC_affinity: + default: llvm_unreachable("Clause is not allowed."); } return Res; @@ -11946,34 +12955,36 @@ getListOfPossibleValues(OpenMPClauseKind K, unsigned First, unsigned Last, else if (I + Skipped + 1 != Last) Out << ", "; } - return Out.str(); + return std::string(Out.str()); } -OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind, +OMPClause *Sema::ActOnOpenMPDefaultClause(DefaultKind Kind, SourceLocation KindKwLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { - if (Kind == OMPC_DEFAULT_unknown) { - static_assert(OMPC_DEFAULT_unknown > 0, - "OMPC_DEFAULT_unknown not greater than 0"); + if (Kind == OMP_DEFAULT_unknown) { Diag(KindKwLoc, diag::err_omp_unexpected_clause_value) << getListOfPossibleValues(OMPC_default, /*First=*/0, - /*Last=*/OMPC_DEFAULT_unknown) + /*Last=*/unsigned(OMP_DEFAULT_unknown)) << getOpenMPClauseName(OMPC_default); return nullptr; } + switch (Kind) { - case OMPC_DEFAULT_none: + case OMP_DEFAULT_none: DSAStack->setDefaultDSANone(KindKwLoc); break; - case OMPC_DEFAULT_shared: + case OMP_DEFAULT_shared: DSAStack->setDefaultDSAShared(KindKwLoc); break; - case OMPC_DEFAULT_unknown: - llvm_unreachable("Clause kind is not allowed."); + case OMP_DEFAULT_firstprivate: + DSAStack->setDefaultDSAFirstPrivate(KindKwLoc); break; + default: + llvm_unreachable("DSA unexpected in OpenMP default clause"); } + return new (Context) OMPDefaultClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc); } @@ -12010,6 +13021,43 @@ OMPClause *Sema::ActOnOpenMPAtomicDefaultMemOrderClause( LParenLoc, EndLoc); } +OMPClause *Sema::ActOnOpenMPOrderClause(OpenMPOrderClauseKind Kind, + SourceLocation KindKwLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + if (Kind == OMPC_ORDER_unknown) { + static_assert(OMPC_ORDER_unknown > 0, + "OMPC_ORDER_unknown not greater than 0"); + Diag(KindKwLoc, diag::err_omp_unexpected_clause_value) + << getListOfPossibleValues(OMPC_order, /*First=*/0, + /*Last=*/OMPC_ORDER_unknown) + << getOpenMPClauseName(OMPC_order); + return nullptr; + } + return new (Context) + OMPOrderClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPUpdateClause(OpenMPDependClauseKind Kind, + SourceLocation KindKwLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + if (Kind == OMPC_DEPEND_unknown || Kind == OMPC_DEPEND_source || + Kind == OMPC_DEPEND_sink || Kind == OMPC_DEPEND_depobj) { + unsigned Except[] = {OMPC_DEPEND_source, OMPC_DEPEND_sink, + OMPC_DEPEND_depobj}; + Diag(KindKwLoc, diag::err_omp_unexpected_clause_value) + << getListOfPossibleValues(OMPC_depend, /*First=*/0, + /*Last=*/OMPC_DEPEND_unknown, Except) + << getOpenMPClauseName(OMPC_update); + return nullptr; + } + return OMPUpdateClause::Create(Context, StartLoc, LParenLoc, KindKwLoc, Kind, + EndLoc); +} + OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( OpenMPClauseKind Kind, ArrayRef<unsigned> Argument, Expr *Expr, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -12047,6 +13095,12 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( StartLoc, LParenLoc, ArgumentLoc[Modifier], ArgumentLoc[DefaultmapKind], EndLoc); break; + case OMPC_device: + assert(Argument.size() == 1 && ArgumentLoc.size() == 1); + Res = ActOnOpenMPDeviceClause( + static_cast<OpenMPDeviceClauseModifier>(Argument.back()), Expr, + StartLoc, LParenLoc, ArgumentLoc.back(), EndLoc); + break; case OMPC_final: case OMPC_num_threads: case OMPC_safelen: @@ -12073,13 +13127,17 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_threadprivate: case OMPC_allocate: case OMPC_flush: + case OMPC_depobj: case OMPC_read: case OMPC_write: case OMPC_update: case OMPC_capture: case OMPC_seq_cst: + case OMPC_acq_rel: + case OMPC_acquire: + case OMPC_release: + case OMPC_relaxed: case OMPC_depend: - case OMPC_device: case OMPC_threads: case OMPC_simd: case OMPC_map: @@ -12095,6 +13153,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_unified_address: case OMPC_unified_shared_memory: @@ -12104,6 +13163,14 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_device_type: case OMPC_match: case OMPC_nontemporal: + case OMPC_order: + case OMPC_destroy: + case OMPC_detach: + case OMPC_inclusive: + case OMPC_exclusive: + case OMPC_uses_allocators: + case OMPC_affinity: + default: llvm_unreachable("Clause is not allowed."); } return Res; @@ -12170,7 +13237,9 @@ OMPClause *Sema::ActOnOpenMPScheduleClause( // OpenMP, 2.7.1, Loop Construct, Restrictions // The nonmonotonic modifier can only be specified with schedule(dynamic) or // schedule(guided). - if ((M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic || + // OpenMP 5.0 does not have this restriction. + if (LangOpts.OpenMP < 50 && + (M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic || M2 == OMPC_SCHEDULE_MODIFIER_nonmonotonic) && Kind != OMPC_SCHEDULE_dynamic && Kind != OMPC_SCHEDULE_guided) { Diag(M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic ? M1Loc : M2Loc, @@ -12250,6 +13319,18 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_seq_cst: Res = ActOnOpenMPSeqCstClause(StartLoc, EndLoc); break; + case OMPC_acq_rel: + Res = ActOnOpenMPAcqRelClause(StartLoc, EndLoc); + break; + case OMPC_acquire: + Res = ActOnOpenMPAcquireClause(StartLoc, EndLoc); + break; + case OMPC_release: + Res = ActOnOpenMPReleaseClause(StartLoc, EndLoc); + break; + case OMPC_relaxed: + Res = ActOnOpenMPRelaxedClause(StartLoc, EndLoc); + break; case OMPC_threads: Res = ActOnOpenMPThreadsClause(StartLoc, EndLoc); break; @@ -12271,6 +13352,9 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_dynamic_allocators: Res = ActOnOpenMPDynamicAllocatorsClause(StartLoc, EndLoc); break; + case OMPC_destroy: + Res = ActOnOpenMPDestroyClause(StartLoc, EndLoc); + break; case OMPC_if: case OMPC_final: case OMPC_num_threads: @@ -12295,6 +13379,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_threadprivate: case OMPC_allocate: case OMPC_flush: + case OMPC_depobj: case OMPC_depend: case OMPC_device: case OMPC_map: @@ -12311,11 +13396,19 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_atomic_default_mem_order: case OMPC_device_type: case OMPC_match: case OMPC_nontemporal: + case OMPC_order: + case OMPC_detach: + case OMPC_inclusive: + case OMPC_exclusive: + case OMPC_uses_allocators: + case OMPC_affinity: + default: llvm_unreachable("Clause is not allowed."); } return Res; @@ -12349,7 +13442,7 @@ OMPClause *Sema::ActOnOpenMPWriteClause(SourceLocation StartLoc, OMPClause *Sema::ActOnOpenMPUpdateClause(SourceLocation StartLoc, SourceLocation EndLoc) { - return new (Context) OMPUpdateClause(StartLoc, EndLoc); + return OMPUpdateClause::Create(Context, StartLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPCaptureClause(SourceLocation StartLoc, @@ -12362,6 +13455,26 @@ OMPClause *Sema::ActOnOpenMPSeqCstClause(SourceLocation StartLoc, return new (Context) OMPSeqCstClause(StartLoc, EndLoc); } +OMPClause *Sema::ActOnOpenMPAcqRelClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPAcqRelClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPAcquireClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPAcquireClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPReleaseClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPReleaseClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPRelaxedClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPRelaxedClause(StartLoc, EndLoc); +} + OMPClause *Sema::ActOnOpenMPThreadsClause(SourceLocation StartLoc, SourceLocation EndLoc) { return new (Context) OMPThreadsClause(StartLoc, EndLoc); @@ -12397,14 +13510,19 @@ OMPClause *Sema::ActOnOpenMPDynamicAllocatorsClause(SourceLocation StartLoc, return new (Context) OMPDynamicAllocatorsClause(StartLoc, EndLoc); } +OMPClause *Sema::ActOnOpenMPDestroyClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPDestroyClause(StartLoc, EndLoc); +} + OMPClause *Sema::ActOnOpenMPVarListClause( - OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr, + OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *DepModOrTailExpr, const OMPVarListLocTy &Locs, SourceLocation ColonLoc, CXXScopeSpec &ReductionOrMapperIdScopeSpec, DeclarationNameInfo &ReductionOrMapperId, int ExtraModifier, ArrayRef<OpenMPMapModifierKind> MapTypeModifiers, ArrayRef<SourceLocation> MapTypeModifiersLoc, bool IsMapTypeImplicit, - SourceLocation DepLinMapLastLoc) { + SourceLocation ExtraModifierLoc) { SourceLocation StartLoc = Locs.StartLoc; SourceLocation LParenLoc = Locs.LParenLoc; SourceLocation EndLoc = Locs.EndLoc; @@ -12421,15 +13539,18 @@ OMPClause *Sema::ActOnOpenMPVarListClause( "Unexpected lastprivate modifier."); Res = ActOnOpenMPLastprivateClause( VarList, static_cast<OpenMPLastprivateModifier>(ExtraModifier), - DepLinMapLastLoc, ColonLoc, StartLoc, LParenLoc, EndLoc); + ExtraModifierLoc, ColonLoc, StartLoc, LParenLoc, EndLoc); break; case OMPC_shared: Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_reduction: - Res = ActOnOpenMPReductionClause(VarList, StartLoc, LParenLoc, ColonLoc, - EndLoc, ReductionOrMapperIdScopeSpec, - ReductionOrMapperId); + assert(0 <= ExtraModifier && ExtraModifier <= OMPC_REDUCTION_unknown && + "Unexpected lastprivate modifier."); + Res = ActOnOpenMPReductionClause( + VarList, static_cast<OpenMPReductionClauseModifier>(ExtraModifier), + StartLoc, LParenLoc, ExtraModifierLoc, ColonLoc, EndLoc, + ReductionOrMapperIdScopeSpec, ReductionOrMapperId); break; case OMPC_task_reduction: Res = ActOnOpenMPTaskReductionClause(VarList, StartLoc, LParenLoc, ColonLoc, @@ -12445,13 +13566,13 @@ OMPClause *Sema::ActOnOpenMPVarListClause( assert(0 <= ExtraModifier && ExtraModifier <= OMPC_LINEAR_unknown && "Unexpected linear modifier."); Res = ActOnOpenMPLinearClause( - VarList, TailExpr, StartLoc, LParenLoc, - static_cast<OpenMPLinearClauseKind>(ExtraModifier), DepLinMapLastLoc, + VarList, DepModOrTailExpr, StartLoc, LParenLoc, + static_cast<OpenMPLinearClauseKind>(ExtraModifier), ExtraModifierLoc, ColonLoc, EndLoc); break; case OMPC_aligned: - Res = ActOnOpenMPAlignedClause(VarList, TailExpr, StartLoc, LParenLoc, - ColonLoc, EndLoc); + Res = ActOnOpenMPAlignedClause(VarList, DepModOrTailExpr, StartLoc, + LParenLoc, ColonLoc, EndLoc); break; case OMPC_copyin: Res = ActOnOpenMPCopyinClause(VarList, StartLoc, LParenLoc, EndLoc); @@ -12466,8 +13587,8 @@ OMPClause *Sema::ActOnOpenMPVarListClause( assert(0 <= ExtraModifier && ExtraModifier <= OMPC_DEPEND_unknown && "Unexpected depend modifier."); Res = ActOnOpenMPDependClause( - static_cast<OpenMPDependClauseKind>(ExtraModifier), DepLinMapLastLoc, - ColonLoc, VarList, StartLoc, LParenLoc, EndLoc); + DepModOrTailExpr, static_cast<OpenMPDependClauseKind>(ExtraModifier), + ExtraModifierLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_map: assert(0 <= ExtraModifier && ExtraModifier <= OMPC_MAP_unknown && @@ -12475,7 +13596,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause( Res = ActOnOpenMPMapClause( MapTypeModifiers, MapTypeModifiersLoc, ReductionOrMapperIdScopeSpec, ReductionOrMapperId, static_cast<OpenMPMapClauseKind>(ExtraModifier), - IsMapTypeImplicit, DepLinMapLastLoc, ColonLoc, VarList, Locs); + IsMapTypeImplicit, ExtraModifierLoc, ColonLoc, VarList, Locs); break; case OMPC_to: Res = ActOnOpenMPToClause(VarList, ReductionOrMapperIdScopeSpec, @@ -12488,17 +13609,31 @@ OMPClause *Sema::ActOnOpenMPVarListClause( case OMPC_use_device_ptr: Res = ActOnOpenMPUseDevicePtrClause(VarList, Locs); break; + case OMPC_use_device_addr: + Res = ActOnOpenMPUseDeviceAddrClause(VarList, Locs); + break; case OMPC_is_device_ptr: Res = ActOnOpenMPIsDevicePtrClause(VarList, Locs); break; case OMPC_allocate: - Res = ActOnOpenMPAllocateClause(TailExpr, VarList, StartLoc, LParenLoc, - ColonLoc, EndLoc); + Res = ActOnOpenMPAllocateClause(DepModOrTailExpr, VarList, StartLoc, + LParenLoc, ColonLoc, EndLoc); break; case OMPC_nontemporal: Res = ActOnOpenMPNontemporalClause(VarList, StartLoc, LParenLoc, EndLoc); break; + case OMPC_inclusive: + Res = ActOnOpenMPInclusiveClause(VarList, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_exclusive: + Res = ActOnOpenMPExclusiveClause(VarList, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_affinity: + Res = ActOnOpenMPAffinityClause(StartLoc, LParenLoc, ColonLoc, EndLoc, + DepModOrTailExpr, VarList); + break; case OMPC_if: + case OMPC_depobj: case OMPC_final: case OMPC_num_threads: case OMPC_safelen: @@ -12518,6 +13653,10 @@ OMPClause *Sema::ActOnOpenMPVarListClause( case OMPC_update: case OMPC_capture: case OMPC_seq_cst: + case OMPC_acq_rel: + case OMPC_acquire: + case OMPC_release: + case OMPC_relaxed: case OMPC_device: case OMPC_threads: case OMPC_simd: @@ -12539,6 +13678,11 @@ OMPClause *Sema::ActOnOpenMPVarListClause( case OMPC_atomic_default_mem_order: case OMPC_device_type: case OMPC_match: + case OMPC_order: + case OMPC_destroy: + case OMPC_detach: + case OMPC_uses_allocators: + default: llvm_unreachable("Clause is not allowed."); } return Res; @@ -12985,7 +14129,8 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, ExprCaptures.push_back(Ref->getDecl()); } } - DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_firstprivate, Ref); + if (!IsImplicitClause) + DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_firstprivate, Ref); Vars.push_back((VD || CurContext->isDependentContext()) ? RefExpr->IgnoreParens() : Ref); @@ -13518,6 +14663,12 @@ struct ReductionData { SmallVector<Expr *, 8> RHSs; /// Reduction operation expression. SmallVector<Expr *, 8> ReductionOps; + /// inscan copy operation expressions. + SmallVector<Expr *, 8> InscanCopyOps; + /// inscan copy temp array expressions for prefix sums. + SmallVector<Expr *, 8> InscanCopyArrayTemps; + /// inscan copy temp array element expressions for prefix sums. + SmallVector<Expr *, 8> InscanCopyArrayElems; /// Taskgroup descriptors for the corresponding reduction items in /// in_reduction clauses. SmallVector<Expr *, 8> TaskgroupDescriptors; @@ -13525,14 +14676,21 @@ struct ReductionData { SmallVector<Decl *, 4> ExprCaptures; /// List of postupdate expressions. SmallVector<Expr *, 4> ExprPostUpdates; + /// Reduction modifier. + unsigned RedModifier = 0; ReductionData() = delete; /// Reserves required memory for the reduction data. - ReductionData(unsigned Size) { + ReductionData(unsigned Size, unsigned Modifier = 0) : RedModifier(Modifier) { Vars.reserve(Size); Privates.reserve(Size); LHSs.reserve(Size); RHSs.reserve(Size); ReductionOps.reserve(Size); + if (RedModifier == OMPC_REDUCTION_inscan) { + InscanCopyOps.reserve(Size); + InscanCopyArrayTemps.reserve(Size); + InscanCopyArrayElems.reserve(Size); + } TaskgroupDescriptors.reserve(Size); ExprCaptures.reserve(Size); ExprPostUpdates.reserve(Size); @@ -13546,16 +14704,31 @@ struct ReductionData { RHSs.emplace_back(nullptr); ReductionOps.emplace_back(ReductionOp); TaskgroupDescriptors.emplace_back(nullptr); + if (RedModifier == OMPC_REDUCTION_inscan) { + InscanCopyOps.push_back(nullptr); + InscanCopyArrayTemps.push_back(nullptr); + InscanCopyArrayElems.push_back(nullptr); + } } /// Stores reduction data. void push(Expr *Item, Expr *Private, Expr *LHS, Expr *RHS, Expr *ReductionOp, - Expr *TaskgroupDescriptor) { + Expr *TaskgroupDescriptor, Expr *CopyOp, Expr *CopyArrayTemp, + Expr *CopyArrayElem) { Vars.emplace_back(Item); Privates.emplace_back(Private); LHSs.emplace_back(LHS); RHSs.emplace_back(RHS); ReductionOps.emplace_back(ReductionOp); TaskgroupDescriptors.emplace_back(TaskgroupDescriptor); + if (RedModifier == OMPC_REDUCTION_inscan) { + InscanCopyOps.push_back(CopyOp); + InscanCopyArrayTemps.push_back(CopyArrayTemp); + InscanCopyArrayElems.push_back(CopyArrayElem); + } else { + assert(CopyOp == nullptr && CopyArrayTemp == nullptr && + CopyArrayElem == nullptr && + "Copy operation must be used for inscan reductions only."); + } } }; } // namespace @@ -13567,7 +14740,7 @@ static bool checkOMPArraySectionConstantForReduction( if (Length == nullptr) { // For array sections of the form [1:] or [:], we would need to analyze // the lower bound... - if (OASE->getColonLoc().isValid()) + if (OASE->getColonLocFirst().isValid()) return false; // This is an array subscript which has implicit length 1! @@ -13593,7 +14766,7 @@ static bool checkOMPArraySectionConstantForReduction( if (Length == nullptr) { // For array sections of the form [1:] or [:], we would need to analyze // the lower bound... - if (OASE->getColonLoc().isValid()) + if (OASE->getColonLocFirst().isValid()) return false; // This is an array subscript which has implicit length 1! @@ -13948,11 +15121,11 @@ static bool actOnOMPReductionKindClause( if (isOpenMPTargetExecutionDirective(Stack->getCurrentDirective())) { S.Diag(ELoc, diag::err_omp_reduction_vla_unsupported) << !!OASE; S.Diag(ELoc, diag::note_vla_unsupported); + continue; } else { S.targetDiag(ELoc, diag::err_omp_reduction_vla_unsupported) << !!OASE; S.targetDiag(ELoc, diag::note_vla_unsupported); } - continue; } // For arrays/array sections only: // Create pseudo array type for private copy. The size for this array will @@ -14007,9 +15180,9 @@ static bool actOnOMPReductionKindClause( if (auto *ComplexTy = OrigType->getAs<ComplexType>()) Type = ComplexTy->getElementType(); if (Type->isRealFloatingType()) { - llvm::APFloat InitValue = - llvm::APFloat::getAllOnesValue(Context.getTypeSize(Type), - /*isIEEE=*/true); + llvm::APFloat InitValue = llvm::APFloat::getAllOnesValue( + Context.getFloatTypeSemantics(Type), + Context.getTypeSize(Type)); Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true, Type, ELoc); } else if (Type->isScalarType()) { @@ -14157,6 +15330,53 @@ static bool actOnOMPReductionKindClause( continue; } + // Add copy operations for inscan reductions. + // LHS = RHS; + ExprResult CopyOpRes, TempArrayRes, TempArrayElem; + if (ClauseKind == OMPC_reduction && + RD.RedModifier == OMPC_REDUCTION_inscan) { + ExprResult RHS = S.DefaultLvalueConversion(RHSDRE); + CopyOpRes = S.BuildBinOp(Stack->getCurScope(), ELoc, BO_Assign, LHSDRE, + RHS.get()); + if (!CopyOpRes.isUsable()) + continue; + CopyOpRes = + S.ActOnFinishFullExpr(CopyOpRes.get(), /*DiscardedValue=*/true); + if (!CopyOpRes.isUsable()) + continue; + // For simd directive and simd-based directives in simd mode no need to + // construct temp array, need just a single temp element. + if (Stack->getCurrentDirective() == OMPD_simd || + (S.getLangOpts().OpenMPSimd && + isOpenMPSimdDirective(Stack->getCurrentDirective()))) { + VarDecl *TempArrayVD = + buildVarDecl(S, ELoc, PrivateTy, D->getName(), + D->hasAttrs() ? &D->getAttrs() : nullptr); + // Add a constructor to the temp decl. + S.ActOnUninitializedDecl(TempArrayVD); + TempArrayRes = buildDeclRefExpr(S, TempArrayVD, PrivateTy, ELoc); + } else { + // Build temp array for prefix sum. + auto *Dim = new (S.Context) + OpaqueValueExpr(ELoc, S.Context.getSizeType(), VK_RValue); + QualType ArrayTy = + S.Context.getVariableArrayType(PrivateTy, Dim, ArrayType::Normal, + /*IndexTypeQuals=*/0, {ELoc, ELoc}); + VarDecl *TempArrayVD = + buildVarDecl(S, ELoc, ArrayTy, D->getName(), + D->hasAttrs() ? &D->getAttrs() : nullptr); + // Add a constructor to the temp decl. + S.ActOnUninitializedDecl(TempArrayVD); + TempArrayRes = buildDeclRefExpr(S, TempArrayVD, ArrayTy, ELoc); + TempArrayElem = + S.DefaultFunctionArrayLvalueConversion(TempArrayRes.get()); + auto *Idx = new (S.Context) + OpaqueValueExpr(ELoc, S.Context.getSizeType(), VK_RValue); + TempArrayElem = S.CreateBuiltinArraySubscriptExpr(TempArrayElem.get(), + ELoc, Idx, ELoc); + } + } + // OpenMP [2.15.4.6, Restrictions, p.2] // A list item that appears in an in_reduction clause of a task construct // must appear in a task_reduction clause of a construct associated with a @@ -14167,8 +15387,8 @@ static bool actOnOMPReductionKindClause( if (ClauseKind == OMPC_in_reduction) { SourceRange ParentSR; BinaryOperatorKind ParentBOK; - const Expr *ParentReductionOp; - Expr *ParentBOKTD, *ParentReductionOpTD; + const Expr *ParentReductionOp = nullptr; + Expr *ParentBOKTD = nullptr, *ParentReductionOpTD = nullptr; DSAStackTy::DSAVarData ParentBOKDSA = Stack->getTopMostTaskgroupReductionData(D, ParentSR, ParentBOK, ParentBOKTD); @@ -14177,13 +15397,9 @@ static bool actOnOMPReductionKindClause( D, ParentSR, ParentReductionOp, ParentReductionOpTD); bool IsParentBOK = ParentBOKDSA.DKind != OMPD_unknown; bool IsParentReductionOp = ParentReductionOpDSA.DKind != OMPD_unknown; - if (!IsParentBOK && !IsParentReductionOp) { - S.Diag(ELoc, diag::err_omp_in_reduction_not_task_reduction); - continue; - } if ((DeclareReductionRef.isUnset() && IsParentReductionOp) || - (DeclareReductionRef.isUsable() && IsParentBOK) || BOK != ParentBOK || - IsParentReductionOp) { + (DeclareReductionRef.isUsable() && IsParentBOK) || + (IsParentBOK && BOK != ParentBOK) || IsParentReductionOp) { bool EmitError = true; if (IsParentReductionOp && DeclareReductionRef.isUsable()) { llvm::FoldingSetNodeID RedId, ParentRedId; @@ -14206,7 +15422,6 @@ static bool actOnOMPReductionKindClause( } } TaskgroupDescriptor = IsParentBOK ? ParentBOKTD : ParentReductionOpTD; - assert(TaskgroupDescriptor && "Taskgroup descriptor must be defined."); } DeclRefExpr *Ref = nullptr; @@ -14245,8 +15460,17 @@ static bool actOnOMPReductionKindClause( } // All reduction items are still marked as reduction (to do not increase // code base size). - Stack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref); - if (CurrDir == OMPD_taskgroup) { + unsigned Modifier = RD.RedModifier; + // Consider task_reductions as reductions with task modifier. Required for + // correct analysis of in_reduction clauses. + if (CurrDir == OMPD_taskgroup && ClauseKind == OMPC_task_reduction) + Modifier = OMPC_REDUCTION_task; + Stack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref, Modifier); + if (Modifier == OMPC_REDUCTION_task && + (CurrDir == OMPD_taskgroup || + ((isOpenMPParallelDirective(CurrDir) || + isOpenMPWorksharingDirective(CurrDir)) && + !isOpenMPSimdDirective(CurrDir)))) { if (DeclareReductionRef.isUsable()) Stack->addTaskgroupReductionData(D, ReductionIdRange, DeclareReductionRef.get()); @@ -14254,17 +15478,41 @@ static bool actOnOMPReductionKindClause( Stack->addTaskgroupReductionData(D, ReductionIdRange, BOK); } RD.push(VarsExpr, PrivateDRE, LHSDRE, RHSDRE, ReductionOp.get(), - TaskgroupDescriptor); + TaskgroupDescriptor, CopyOpRes.get(), TempArrayRes.get(), + TempArrayElem.get()); } return RD.Vars.empty(); } OMPClause *Sema::ActOnOpenMPReductionClause( - ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation ColonLoc, SourceLocation EndLoc, + ArrayRef<Expr *> VarList, OpenMPReductionClauseModifier Modifier, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ModifierLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef<Expr *> UnresolvedReductions) { - ReductionData RD(VarList.size()); + if (ModifierLoc.isValid() && Modifier == OMPC_REDUCTION_unknown) { + Diag(LParenLoc, diag::err_omp_unexpected_clause_value) + << getListOfPossibleValues(OMPC_reduction, /*First=*/0, + /*Last=*/OMPC_REDUCTION_unknown) + << getOpenMPClauseName(OMPC_reduction); + return nullptr; + } + // OpenMP 5.0, 2.19.5.4 reduction Clause, Restrictions + // A reduction clause with the inscan reduction-modifier may only appear on a + // worksharing-loop construct, a worksharing-loop SIMD construct, a simd + // construct, a parallel worksharing-loop construct or a parallel + // worksharing-loop SIMD construct. + if (Modifier == OMPC_REDUCTION_inscan && + (DSAStack->getCurrentDirective() != OMPD_for && + DSAStack->getCurrentDirective() != OMPD_for_simd && + DSAStack->getCurrentDirective() != OMPD_simd && + DSAStack->getCurrentDirective() != OMPD_parallel_for && + DSAStack->getCurrentDirective() != OMPD_parallel_for_simd)) { + Diag(ModifierLoc, diag::err_omp_wrong_inscan_reduction); + return nullptr; + } + + ReductionData RD(VarList.size(), Modifier); if (actOnOMPReductionKindClause(*this, DSAStack, OMPC_reduction, VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec, ReductionId, @@ -14272,9 +15520,10 @@ OMPClause *Sema::ActOnOpenMPReductionClause( return nullptr; return OMPReductionClause::Create( - Context, StartLoc, LParenLoc, ColonLoc, EndLoc, RD.Vars, - ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, - RD.Privates, RD.LHSs, RD.RHSs, RD.ReductionOps, + Context, StartLoc, LParenLoc, ModifierLoc, ColonLoc, EndLoc, Modifier, + RD.Vars, ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, + RD.Privates, RD.LHSs, RD.RHSs, RD.ReductionOps, RD.InscanCopyOps, + RD.InscanCopyArrayTemps, RD.InscanCopyArrayElems, buildPreInits(Context, RD.ExprCaptures), buildPostUpdate(*this, RD.ExprPostUpdates)); } @@ -14330,8 +15579,8 @@ bool Sema::CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind, } bool Sema::CheckOpenMPLinearDecl(const ValueDecl *D, SourceLocation ELoc, - OpenMPLinearClauseKind LinKind, - QualType Type) { + OpenMPLinearClauseKind LinKind, QualType Type, + bool IsDeclareSimd) { const 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)) @@ -14347,8 +15596,10 @@ bool Sema::CheckOpenMPLinearDecl(const ValueDecl *D, SourceLocation ELoc, // OpenMP 5.0 [2.19.3, List Item Privatization, Restrictions] // A variable that is privatized must not have a const-qualified type // unless it is of class type with a mutable member. This restriction does - // not apply to the firstprivate clause. - if (rejectConstNotMutableType(*this, D, Type, OMPC_linear, ELoc)) + // not apply to the firstprivate clause, nor to the linear clause on + // declarative directives (like declare simd). + if (!IsDeclareSimd && + rejectConstNotMutableType(*this, D, Type, OMPC_linear, ELoc)) return true; // A list item must be of integral or pointer type. @@ -14900,8 +16151,53 @@ OMPClause *Sema::ActOnOpenMPFlushClause(ArrayRef<Expr *> VarList, return OMPFlushClause::Create(Context, StartLoc, LParenLoc, EndLoc, VarList); } +/// Tries to find omp_depend_t. type. +static bool findOMPDependT(Sema &S, SourceLocation Loc, DSAStackTy *Stack, + bool Diagnose = true) { + QualType OMPDependT = Stack->getOMPDependT(); + if (!OMPDependT.isNull()) + return true; + IdentifierInfo *II = &S.PP.getIdentifierTable().get("omp_depend_t"); + ParsedType PT = S.getTypeName(*II, Loc, S.getCurScope()); + if (!PT.getAsOpaquePtr() || PT.get().isNull()) { + if (Diagnose) + S.Diag(Loc, diag::err_omp_implied_type_not_found) << "omp_depend_t"; + return false; + } + Stack->setOMPDependT(PT.get()); + return true; +} + +OMPClause *Sema::ActOnOpenMPDepobjClause(Expr *Depobj, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + if (!Depobj) + return nullptr; + + bool OMPDependTFound = findOMPDependT(*this, StartLoc, DSAStack); + + // OpenMP 5.0, 2.17.10.1 depobj Construct + // depobj is an lvalue expression of type omp_depend_t. + if (!Depobj->isTypeDependent() && !Depobj->isValueDependent() && + !Depobj->isInstantiationDependent() && + !Depobj->containsUnexpandedParameterPack() && + (OMPDependTFound && + !Context.typesAreCompatible(DSAStack->getOMPDependT(), Depobj->getType(), + /*CompareUnqualified=*/true))) { + Diag(Depobj->getExprLoc(), diag::err_omp_expected_omp_depend_t_lvalue) + << 0 << Depobj->getType() << Depobj->getSourceRange(); + } + + if (!Depobj->isLValue()) { + Diag(Depobj->getExprLoc(), diag::err_omp_expected_omp_depend_t_lvalue) + << 1 << Depobj->getSourceRange(); + } + + return OMPDepobjClause::Create(Context, StartLoc, LParenLoc, EndLoc, Depobj); +} + OMPClause * -Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, +Sema::ActOnOpenMPDependClause(Expr *DepModifier, OpenMPDependClauseKind DepKind, SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { @@ -14911,16 +16207,38 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, << "'source' or 'sink'" << getOpenMPClauseName(OMPC_depend); return nullptr; } - if (DSAStack->getCurrentDirective() != OMPD_ordered && + if ((DSAStack->getCurrentDirective() != OMPD_ordered || + DSAStack->getCurrentDirective() == OMPD_depobj) && (DepKind == OMPC_DEPEND_unknown || DepKind == OMPC_DEPEND_source || - DepKind == OMPC_DEPEND_sink)) { - unsigned Except[] = {OMPC_DEPEND_source, OMPC_DEPEND_sink}; + DepKind == OMPC_DEPEND_sink || + ((LangOpts.OpenMP < 50 || + DSAStack->getCurrentDirective() == OMPD_depobj) && + DepKind == OMPC_DEPEND_depobj))) { + SmallVector<unsigned, 3> Except; + Except.push_back(OMPC_DEPEND_source); + Except.push_back(OMPC_DEPEND_sink); + if (LangOpts.OpenMP < 50 || DSAStack->getCurrentDirective() == OMPD_depobj) + Except.push_back(OMPC_DEPEND_depobj); + std::string Expected = (LangOpts.OpenMP >= 50 && !DepModifier) + ? "depend modifier(iterator) or " + : ""; Diag(DepLoc, diag::err_omp_unexpected_clause_value) - << getListOfPossibleValues(OMPC_depend, /*First=*/0, - /*Last=*/OMPC_DEPEND_unknown, Except) + << Expected + getListOfPossibleValues(OMPC_depend, /*First=*/0, + /*Last=*/OMPC_DEPEND_unknown, + Except) << getOpenMPClauseName(OMPC_depend); return nullptr; } + if (DepModifier && + (DepKind == OMPC_DEPEND_source || DepKind == OMPC_DEPEND_sink)) { + Diag(DepModifier->getExprLoc(), + diag::err_omp_depend_sink_source_with_modifier); + return nullptr; + } + if (DepModifier && + !DepModifier->getType()->isSpecificBuiltinType(BuiltinType::OMPIterator)) + Diag(DepModifier->getExprLoc(), diag::err_omp_depend_modifier_not_iterator); + SmallVector<Expr *, 8> Vars; DSAStackTy::OperatorOffsetTy OpsOffs; llvm::APSInt DepCounter(/*BitWidth=*/32); @@ -15021,42 +16339,97 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, } OpsOffs.emplace_back(RHS, OOK); } else { - // OpenMP 5.0 [2.17.11, Restrictions] - // List items used in depend clauses cannot be zero-length array sections. - const auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr); - if (OASE) { - const Expr *Length = OASE->getLength(); - Expr::EvalResult Result; - if (Length && !Length->isValueDependent() && - Length->EvaluateAsInt(Result, Context) && - Result.Val.getInt().isNullValue()) { - Diag(ELoc, - diag::err_omp_depend_zero_length_array_section_not_allowed) - << SimpleExpr->getSourceRange(); + bool OMPDependTFound = LangOpts.OpenMP >= 50; + if (OMPDependTFound) + OMPDependTFound = findOMPDependT(*this, StartLoc, DSAStack, + DepKind == OMPC_DEPEND_depobj); + if (DepKind == OMPC_DEPEND_depobj) { + // OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++ + // List items used in depend clauses with the depobj dependence type + // must be expressions of the omp_depend_t type. + if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() && + !RefExpr->isInstantiationDependent() && + !RefExpr->containsUnexpandedParameterPack() && + (OMPDependTFound && + !Context.hasSameUnqualifiedType(DSAStack->getOMPDependT(), + RefExpr->getType()))) { + Diag(ELoc, diag::err_omp_expected_omp_depend_t_lvalue) + << 0 << RefExpr->getType() << RefExpr->getSourceRange(); continue; } - } + if (!RefExpr->isLValue()) { + Diag(ELoc, diag::err_omp_expected_omp_depend_t_lvalue) + << 1 << RefExpr->getType() << RefExpr->getSourceRange(); + continue; + } + } else { + // OpenMP 5.0 [2.17.11, Restrictions] + // List items used in depend clauses cannot be zero-length array + // sections. + QualType ExprTy = RefExpr->getType().getNonReferenceType(); + const auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr); + if (OASE) { + QualType BaseType = + OMPArraySectionExpr::getBaseOriginalType(OASE->getBase()); + if (const auto *ATy = BaseType->getAsArrayTypeUnsafe()) + ExprTy = ATy->getElementType(); + else + ExprTy = BaseType->getPointeeType(); + ExprTy = ExprTy.getNonReferenceType(); + const Expr *Length = OASE->getLength(); + Expr::EvalResult Result; + if (Length && !Length->isValueDependent() && + Length->EvaluateAsInt(Result, Context) && + Result.Val.getInt().isNullValue()) { + Diag(ELoc, + diag::err_omp_depend_zero_length_array_section_not_allowed) + << SimpleExpr->getSourceRange(); + continue; + } + } - auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr); - if (!RefExpr->IgnoreParenImpCasts()->isLValue() || - (ASE && - !ASE->getBase()->getType().getNonReferenceType()->isPointerType() && - !ASE->getBase()->getType().getNonReferenceType()->isArrayType())) { - Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) - << RefExpr->getSourceRange(); - continue; - } + // OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++ + // List items used in depend clauses with the in, out, inout or + // mutexinoutset dependence types cannot be expressions of the + // omp_depend_t type. + if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() && + !RefExpr->isInstantiationDependent() && + !RefExpr->containsUnexpandedParameterPack() && + (OMPDependTFound && + DSAStack->getOMPDependT().getTypePtr() == ExprTy.getTypePtr())) { + Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) + << (LangOpts.OpenMP >= 50 ? 1 : 0) << 1 + << RefExpr->getSourceRange(); + continue; + } - ExprResult Res; - { - Sema::TentativeAnalysisScope Trap(*this); - Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, - RefExpr->IgnoreParenImpCasts()); - } - if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr)) { - Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) - << RefExpr->getSourceRange(); - continue; + auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr); + if (!RefExpr->IgnoreParenImpCasts()->isLValue() || + (ASE && !ASE->getBase()->isTypeDependent() && + !ASE->getBase() + ->getType() + .getNonReferenceType() + ->isPointerType() && + !ASE->getBase()->getType().getNonReferenceType()->isArrayType())) { + Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) + << (LangOpts.OpenMP >= 50 ? 1 : 0) + << (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange(); + continue; + } + + ExprResult Res; + { + Sema::TentativeAnalysisScope Trap(*this); + Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, + RefExpr->IgnoreParenImpCasts()); + } + if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr) && + !isa<OMPArrayShapingExpr>(SimpleExpr)) { + Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) + << (LangOpts.OpenMP >= 50 ? 1 : 0) + << (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange(); + continue; + } } } Vars.push_back(RefExpr->IgnoreParenImpCasts()); @@ -15074,24 +16447,40 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, return nullptr; auto *C = OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc, - DepKind, DepLoc, ColonLoc, Vars, - TotalDepCount.getZExtValue()); + DepModifier, DepKind, DepLoc, ColonLoc, + Vars, TotalDepCount.getZExtValue()); if ((DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source) && DSAStack->isParentOrderedRegion()) DSAStack->addDoacrossDependClause(C, OpsOffs); return C; } -OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc, +OMPClause *Sema::ActOnOpenMPDeviceClause(OpenMPDeviceClauseModifier Modifier, + Expr *Device, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ModifierLoc, SourceLocation EndLoc) { + assert((ModifierLoc.isInvalid() || LangOpts.OpenMP >= 50) && + "Unexpected device modifier in OpenMP < 50."); + + bool ErrorFound = false; + if (ModifierLoc.isValid() && Modifier == OMPC_DEVICE_unknown) { + std::string Values = + getListOfPossibleValues(OMPC_device, /*First=*/0, OMPC_DEVICE_unknown); + Diag(ModifierLoc, diag::err_omp_unexpected_clause_value) + << Values << getOpenMPClauseName(OMPC_device); + ErrorFound = true; + } + Expr *ValExpr = Device; Stmt *HelperValStmt = nullptr; // OpenMP [2.9.1, Restrictions] // The device expression must evaluate to a non-negative integer value. - if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_device, - /*StrictlyPositive=*/false)) + ErrorFound = !isNonNegativeIntegerValue(ValExpr, *this, OMPC_device, + /*StrictlyPositive=*/false) || + ErrorFound; + if (ErrorFound) return nullptr; OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); @@ -15104,8 +16493,9 @@ OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc, HelperValStmt = buildPreInits(Context, Captures); } - return new (Context) OMPDeviceClause(ValExpr, HelperValStmt, CaptureRegion, - StartLoc, LParenLoc, EndLoc); + return new (Context) + OMPDeviceClause(Modifier, ValExpr, HelperValStmt, CaptureRegion, StartLoc, + LParenLoc, ModifierLoc, EndLoc); } static bool checkTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef, @@ -15133,7 +16523,8 @@ static bool checkArrayExpressionDoesNotReferToWholeSize(Sema &SemaRef, // 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 (isa<ArraySubscriptExpr>(E) || + (OASE && OASE->getColonLocFirst().isInvalid())) { if (const auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr())) return ATy->getSize().getSExtValue() != 1; // Size can't be evaluated statically. @@ -15189,7 +16580,8 @@ static bool checkArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef, // 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())) + if (isa<ArraySubscriptExpr>(E) || + (OASE && OASE->getColonLocFirst().isInvalid())) return false; assert(OASE && "Expecting array section if not an array subscript."); @@ -15214,256 +16606,338 @@ static bool checkArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef, 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 const Expr *checkMapClauseExpressionBase( - Sema &SemaRef, Expr *E, - OMPClauseMappableExprCommon::MappableExprComponentList &CurComponents, - OpenMPClauseKind CKind, bool NoDiagnose) { - 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'; +// 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'; +// OpenMP 5.0 [2.19.7.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 +namespace { +class MapBaseChecker final : public StmtVisitor<MapBaseChecker, bool> { + Sema &SemaRef; + OpenMPClauseKind CKind = OMPC_unknown; + OMPClauseMappableExprCommon::MappableExprComponentList &Components; + bool NoDiagnose = false; const 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; + SourceLocation ELoc; + SourceRange ERange; - while (!RelevantExpr) { - E = E->IgnoreParenImpCasts(); + void emitErrorMsg() { + // If nothing else worked, this is not a valid map clause expression. + if (SemaRef.getLangOpts().OpenMP < 50) { + SemaRef.Diag(ELoc, + diag::err_omp_expected_named_var_member_or_array_expression) + << ERange; + } else { + SemaRef.Diag(ELoc, diag::err_omp_non_lvalue_in_map_or_motion_clauses) + << getOpenMPClauseName(CKind) << ERange; + } + } - if (auto *CurE = dyn_cast<DeclRefExpr>(E)) { - if (!isa<VarDecl>(CurE->getDecl())) - return nullptr; +public: + bool VisitDeclRefExpr(DeclRefExpr *DRE) { + if (!isa<VarDecl>(DRE->getDecl())) { + emitErrorMsg(); + return false; + } + assert(!RelevantExpr && "RelevantExpr is expected to be nullptr"); + RelevantExpr = DRE; + // Record the component. + Components.emplace_back(DRE, DRE->getDecl()); + return true; + } - RelevantExpr = CurE; + bool VisitMemberExpr(MemberExpr *ME) { + Expr *E = ME; + Expr *BaseE = ME->getBase()->IgnoreParenCasts(); - // If we got a reference to a declaration, we should not expect any array - // section before that. - AllowUnitySizeArraySection = false; - AllowWholeSizeArraySection = false; + if (isa<CXXThisExpr>(BaseE)) { + assert(!RelevantExpr && "RelevantExpr is expected to be nullptr"); + // We found a base expression: this->Val. + RelevantExpr = ME; + } else { + E = BaseE; + } - // Record the component. - CurComponents.emplace_back(CurE, CurE->getDecl()); - } else if (auto *CurE = dyn_cast<MemberExpr>(E)) { - Expr *BaseE = CurE->getBase()->IgnoreParenImpCasts(); + if (!isa<FieldDecl>(ME->getMemberDecl())) { + if (!NoDiagnose) { + SemaRef.Diag(ELoc, diag::err_omp_expected_access_to_data_field) + << ME->getSourceRange(); + return false; + } + if (RelevantExpr) + return false; + return Visit(E); + } - if (isa<CXXThisExpr>(BaseE)) - // We found a base expression: this->Val. - RelevantExpr = CurE; - else - E = BaseE; + auto *FD = cast<FieldDecl>(ME->getMemberDecl()); - if (!isa<FieldDecl>(CurE->getMemberDecl())) { - if (!NoDiagnose) { - SemaRef.Diag(ELoc, diag::err_omp_expected_access_to_data_field) - << CurE->getSourceRange(); - return nullptr; - } - if (RelevantExpr) - return nullptr; - continue; + // 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()) { + if (!NoDiagnose) { + SemaRef.Diag(ELoc, diag::err_omp_bit_fields_forbidden_in_clause) + << ME->getSourceRange() << getOpenMPClauseName(CKind); + return false; } + if (RelevantExpr) + return false; + return Visit(E); + } - auto *FD = cast<FieldDecl>(CurE->getMemberDecl()); + // 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.3] - // A bit-field cannot appear in a map clause. - // - if (FD->isBitField()) { - if (!NoDiagnose) { - SemaRef.Diag(ELoc, diag::err_omp_bit_fields_forbidden_in_clause) - << CurE->getSourceRange() << getOpenMPClauseName(CKind); - return nullptr; - } - if (RelevantExpr) - return nullptr; - continue; + // 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 (CurType->isUnionType()) { + if (!NoDiagnose) { + SemaRef.Diag(ELoc, diag::err_omp_union_type_not_allowed) + << ME->getSourceRange(); + return false; } + return RelevantExpr || Visit(E); + } - // 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(); + // 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; - // 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 (CurType->isUnionType()) { - if (!NoDiagnose) { - SemaRef.Diag(ELoc, diag::err_omp_union_type_not_allowed) - << CurE->getSourceRange(); - return nullptr; - } - continue; + // Record the component. + Components.emplace_back(ME, FD); + return RelevantExpr || Visit(E); + } + + bool VisitArraySubscriptExpr(ArraySubscriptExpr *AE) { + Expr *E = AE->getBase()->IgnoreParenImpCasts(); + + if (!E->getType()->isAnyPointerType() && !E->getType()->isArrayType()) { + if (!NoDiagnose) { + SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name) + << 0 << AE->getSourceRange(); + return false; } + return RelevantExpr || Visit(E); + } - // 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; + // 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, AE, + E->getType())) AllowWholeSizeArraySection = false; - // Record the component. - CurComponents.emplace_back(CurE, FD); - } else if (auto *CurE = dyn_cast<ArraySubscriptExpr>(E)) { - E = CurE->getBase()->IgnoreParenImpCasts(); - - if (!E->getType()->isAnyPointerType() && !E->getType()->isArrayType()) { - if (!NoDiagnose) { - SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name) - << 0 << CurE->getSourceRange(); - return nullptr; - } - continue; + if (const auto *TE = dyn_cast<CXXThisExpr>(E->IgnoreParenCasts())) { + Expr::EvalResult Result; + if (!AE->getIdx()->isValueDependent() && + AE->getIdx()->EvaluateAsInt(Result, SemaRef.getASTContext()) && + !Result.Val.getInt().isNullValue()) { + SemaRef.Diag(AE->getIdx()->getExprLoc(), + diag::err_omp_invalid_map_this_expr); + SemaRef.Diag(AE->getIdx()->getExprLoc(), + diag::note_omp_invalid_subscript_on_this_ptr_map); } + assert(!RelevantExpr && "RelevantExpr is expected to be nullptr"); + RelevantExpr = TE; + } - // 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. + Components.emplace_back(AE, nullptr); - if (const auto *TE = dyn_cast<CXXThisExpr>(E)) { - Expr::EvalResult Result; - if (CurE->getIdx()->EvaluateAsInt(Result, SemaRef.getASTContext())) { - if (!Result.Val.getInt().isNullValue()) { - SemaRef.Diag(CurE->getIdx()->getExprLoc(), - diag::err_omp_invalid_map_this_expr); - SemaRef.Diag(CurE->getIdx()->getExprLoc(), - diag::note_omp_invalid_subscript_on_this_ptr_map); - } - } - RelevantExpr = TE; - } + return RelevantExpr || Visit(E); + } - // Record the component - we don't have any declaration associated. - CurComponents.emplace_back(CurE, nullptr); - } else if (auto *CurE = dyn_cast<OMPArraySectionExpr>(E)) { - assert(!NoDiagnose && "Array sections cannot be implicitly mapped."); - E = CurE->getBase()->IgnoreParenImpCasts(); + bool VisitOMPArraySectionExpr(OMPArraySectionExpr *OASE) { + assert(!NoDiagnose && "Array sections cannot be implicitly mapped."); + Expr *E = OASE->getBase()->IgnoreParenImpCasts(); + QualType CurType = + OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType(); - QualType 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(); - // 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(); - bool IsPointer = CurType->isAnyPointerType(); + if (!IsPointer && !CurType->isArrayType()) { + SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name) + << 0 << OASE->getSourceRange(); + return false; + } - if (!IsPointer && !CurType->isArrayType()) { - SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name) - << 0 << CurE->getSourceRange(); - return nullptr; - } + bool NotWhole = + checkArrayExpressionDoesNotReferToWholeSize(SemaRef, OASE, CurType); + bool NotUnity = + checkArrayExpressionDoesNotReferToUnitySize(SemaRef, OASE, CurType); - bool NotWhole = - checkArrayExpressionDoesNotReferToWholeSize(SemaRef, CurE, CurType); - bool NotUnity = - checkArrayExpressionDoesNotReferToUnitySize(SemaRef, CurE, CurType); + if (AllowWholeSizeArraySection) { + // Any array section is currently allowed. Allowing a whole size array + // section implies allowing a unity array section as well. + // + // 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) { + // 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) + << OASE->getSourceRange(); + return false; + } - if (AllowWholeSizeArraySection) { - // Any array section is currently allowed. Allowing a whole size array - // section implies allowing a unity array section as well. - // - // 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) { - // 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(); - return nullptr; + if (const auto *TE = dyn_cast<CXXThisExpr>(E)) { + Expr::EvalResult ResultR; + Expr::EvalResult ResultL; + if (!OASE->getLength()->isValueDependent() && + OASE->getLength()->EvaluateAsInt(ResultR, SemaRef.getASTContext()) && + !ResultR.Val.getInt().isOneValue()) { + SemaRef.Diag(OASE->getLength()->getExprLoc(), + diag::err_omp_invalid_map_this_expr); + SemaRef.Diag(OASE->getLength()->getExprLoc(), + diag::note_omp_invalid_length_on_this_ptr_mapping); } - - if (const auto *TE = dyn_cast<CXXThisExpr>(E)) { - Expr::EvalResult ResultR; - Expr::EvalResult ResultL; - if (CurE->getLength()->EvaluateAsInt(ResultR, - SemaRef.getASTContext())) { - if (!ResultR.Val.getInt().isOneValue()) { - SemaRef.Diag(CurE->getLength()->getExprLoc(), - diag::err_omp_invalid_map_this_expr); - SemaRef.Diag(CurE->getLength()->getExprLoc(), - diag::note_omp_invalid_length_on_this_ptr_mapping); - } - } - if (CurE->getLowerBound() && CurE->getLowerBound()->EvaluateAsInt( - ResultL, SemaRef.getASTContext())) { - if (!ResultL.Val.getInt().isNullValue()) { - SemaRef.Diag(CurE->getLowerBound()->getExprLoc(), - diag::err_omp_invalid_map_this_expr); - SemaRef.Diag(CurE->getLowerBound()->getExprLoc(), - diag::note_omp_invalid_lower_bound_on_this_ptr_mapping); - } - } - RelevantExpr = TE; + if (OASE->getLowerBound() && !OASE->getLowerBound()->isValueDependent() && + OASE->getLowerBound()->EvaluateAsInt(ResultL, + SemaRef.getASTContext()) && + !ResultL.Val.getInt().isNullValue()) { + SemaRef.Diag(OASE->getLowerBound()->getExprLoc(), + diag::err_omp_invalid_map_this_expr); + SemaRef.Diag(OASE->getLowerBound()->getExprLoc(), + diag::note_omp_invalid_lower_bound_on_this_ptr_mapping); } + assert(!RelevantExpr && "RelevantExpr is expected to be nullptr"); + RelevantExpr = TE; + } - // Record the component - we don't have any declaration associated. - CurComponents.emplace_back(CurE, nullptr); - } else { - if (!NoDiagnose) { - // 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; - } - return nullptr; + // Record the component - we don't have any declaration associated. + Components.emplace_back(OASE, nullptr); + return RelevantExpr || Visit(E); + } + bool VisitOMPArrayShapingExpr(OMPArrayShapingExpr *E) { + Expr *Base = E->getBase(); + + // Record the component - we don't have any declaration associated. + Components.emplace_back(E, nullptr); + + return Visit(Base->IgnoreParenImpCasts()); + } + + bool VisitUnaryOperator(UnaryOperator *UO) { + if (SemaRef.getLangOpts().OpenMP < 50 || !UO->isLValue() || + UO->getOpcode() != UO_Deref) { + emitErrorMsg(); + return false; } + if (!RelevantExpr) { + // Record the component if haven't found base decl. + Components.emplace_back(UO, nullptr); + } + return RelevantExpr || Visit(UO->getSubExpr()->IgnoreParenImpCasts()); } + bool VisitBinaryOperator(BinaryOperator *BO) { + if (SemaRef.getLangOpts().OpenMP < 50 || !BO->getType()->isPointerType()) { + emitErrorMsg(); + return false; + } + + // Pointer arithmetic is the only thing we expect to happen here so after we + // make sure the binary operator is a pointer type, the we only thing need + // to to is to visit the subtree that has the same type as root (so that we + // know the other subtree is just an offset) + Expr *LE = BO->getLHS()->IgnoreParenImpCasts(); + Expr *RE = BO->getRHS()->IgnoreParenImpCasts(); + Components.emplace_back(BO, nullptr); + assert((LE->getType().getTypePtr() == BO->getType().getTypePtr() || + RE->getType().getTypePtr() == BO->getType().getTypePtr()) && + "Either LHS or RHS have base decl inside"); + if (BO->getType().getTypePtr() == LE->getType().getTypePtr()) + return RelevantExpr || Visit(LE); + return RelevantExpr || Visit(RE); + } + bool VisitCXXThisExpr(CXXThisExpr *CTE) { + assert(!RelevantExpr && "RelevantExpr is expected to be nullptr"); + RelevantExpr = CTE; + Components.emplace_back(CTE, nullptr); + return true; + } + bool VisitStmt(Stmt *) { + emitErrorMsg(); + return false; + } + const Expr *getFoundBase() const { + return RelevantExpr; + } + explicit MapBaseChecker( + Sema &SemaRef, OpenMPClauseKind CKind, + OMPClauseMappableExprCommon::MappableExprComponentList &Components, + bool NoDiagnose, SourceLocation &ELoc, SourceRange &ERange) + : SemaRef(SemaRef), CKind(CKind), Components(Components), + NoDiagnose(NoDiagnose), ELoc(ELoc), ERange(ERange) {} +}; +} // namespace - return RelevantExpr; +/// 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 const Expr *checkMapClauseExpressionBase( + Sema &SemaRef, Expr *E, + OMPClauseMappableExprCommon::MappableExprComponentList &CurComponents, + OpenMPClauseKind CKind, bool NoDiagnose) { + SourceLocation ELoc = E->getExprLoc(); + SourceRange ERange = E->getSourceRange(); + MapBaseChecker Checker(SemaRef, CKind, CurComponents, NoDiagnose, ELoc, + ERange); + if (Checker.Visit(E->IgnoreParens())) + return Checker.getFoundBase(); + return nullptr; } // Return true if expression E associated with value VD has conflicts with other @@ -15520,9 +16994,11 @@ static bool checkMapConflicts( // variable in map clauses of the same construct. if (CurrentRegionOnly && (isa<ArraySubscriptExpr>(CI->getAssociatedExpression()) || - isa<OMPArraySectionExpr>(CI->getAssociatedExpression())) && + isa<OMPArraySectionExpr>(CI->getAssociatedExpression()) || + isa<OMPArrayShapingExpr>(CI->getAssociatedExpression())) && (isa<ArraySubscriptExpr>(SI->getAssociatedExpression()) || - isa<OMPArraySectionExpr>(SI->getAssociatedExpression()))) { + isa<OMPArraySectionExpr>(SI->getAssociatedExpression()) || + isa<OMPArrayShapingExpr>(SI->getAssociatedExpression()))) { SemaRef.Diag(CI->getAssociatedExpression()->getExprLoc(), diag::err_omp_multiple_array_items_in_map_clause) << CI->getAssociatedExpression()->getSourceRange(); @@ -15554,6 +17030,9 @@ static bool checkMapConflicts( const Expr *E = OASE->getBase()->IgnoreParenImpCasts(); Type = OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType(); + } else if (const auto *OASE = dyn_cast<OMPArrayShapingExpr>( + SI->getAssociatedExpression())) { + Type = OASE->getBase()->getType()->getPointeeType(); } if (Type.isNull() || Type->isAnyPointerType() || checkArrayExpressionDoesNotReferToWholeSize( @@ -15916,10 +17395,15 @@ static void checkMappableExpressionList( Expr *SimpleExpr = RE->IgnoreParenCasts(); - if (!RE->IgnoreParenImpCasts()->isLValue()) { - SemaRef.Diag(ELoc, - diag::err_omp_expected_named_var_member_or_array_expression) - << RE->getSourceRange(); + if (!RE->isLValue()) { + if (SemaRef.getLangOpts().OpenMP < 50) { + SemaRef.Diag( + ELoc, diag::err_omp_expected_named_var_member_or_array_expression) + << RE->getSourceRange(); + } else { + SemaRef.Diag(ELoc, diag::err_omp_non_lvalue_in_map_or_motion_clauses) + << getOpenMPClauseName(CKind) << RE->getSourceRange(); + } continue; } @@ -16011,6 +17495,7 @@ static void checkMappableExpressionList( QualType Type; auto *ASE = dyn_cast<ArraySubscriptExpr>(VE->IgnoreParens()); auto *OASE = dyn_cast<OMPArraySectionExpr>(VE->IgnoreParens()); + auto *OAShE = dyn_cast<OMPArrayShapingExpr>(VE->IgnoreParens()); if (ASE) { Type = ASE->getType().getNonReferenceType(); } else if (OASE) { @@ -16021,6 +17506,8 @@ static void checkMappableExpressionList( else Type = BaseType->getPointeeType(); Type = Type.getNonReferenceType(); + } else if (OAShE) { + Type = OAShE->getBase()->getType()->getPointeeType(); } else { Type = VE->getType(); } @@ -16064,6 +17551,21 @@ static void checkMappableExpressionList( continue; } + // target, target data + // OpenMP 5.0 [2.12.2, Restrictions, p. 163] + // OpenMP 5.0 [2.12.5, Restrictions, p. 174] + // A map-type in a map clause must be to, from, tofrom or alloc + if ((DKind == OMPD_target_data || + isOpenMPTargetExecutionDirective(DKind)) && + !(MapType == OMPC_MAP_to || MapType == OMPC_MAP_from || + MapType == OMPC_MAP_tofrom || 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; + } + // 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 @@ -16124,7 +17626,7 @@ OMPClause *Sema::ActOnOpenMPMapClause( OpenMPMapModifierKind Modifiers[] = {OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown}; - SourceLocation ModifiersLoc[OMPMapClause::NumberOfModifiers]; + SourceLocation ModifiersLoc[NumberOfOMPMapClauseModifiers]; // Process map-type-modifiers, flag errors for duplicate modifiers. unsigned Count = 0; @@ -16134,7 +17636,7 @@ OMPClause *Sema::ActOnOpenMPMapClause( Diag(MapTypeModifiersLoc[I], diag::err_omp_duplicate_map_type_modifier); continue; } - assert(Count < OMPMapClause::NumberOfModifiers && + assert(Count < NumberOfOMPMapClauseModifiers && "Modifiers exceed the allowed number of map type modifiers"); Modifiers[Count] = MapTypeModifiers[I]; ModifiersLoc[Count] = MapTypeModifiersLoc[I]; @@ -16678,6 +18180,69 @@ OMPClause *Sema::ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc, OMPHintClause(HintExpr.get(), StartLoc, LParenLoc, EndLoc); } +/// Tries to find omp_event_handle_t type. +static bool findOMPEventHandleT(Sema &S, SourceLocation Loc, + DSAStackTy *Stack) { + QualType OMPEventHandleT = Stack->getOMPEventHandleT(); + if (!OMPEventHandleT.isNull()) + return true; + IdentifierInfo *II = &S.PP.getIdentifierTable().get("omp_event_handle_t"); + ParsedType PT = S.getTypeName(*II, Loc, S.getCurScope()); + if (!PT.getAsOpaquePtr() || PT.get().isNull()) { + S.Diag(Loc, diag::err_omp_implied_type_not_found) << "omp_event_handle_t"; + return false; + } + Stack->setOMPEventHandleT(PT.get()); + return true; +} + +OMPClause *Sema::ActOnOpenMPDetachClause(Expr *Evt, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + if (!Evt->isValueDependent() && !Evt->isTypeDependent() && + !Evt->isInstantiationDependent() && + !Evt->containsUnexpandedParameterPack()) { + if (!findOMPEventHandleT(*this, Evt->getExprLoc(), DSAStack)) + return nullptr; + // OpenMP 5.0, 2.10.1 task Construct. + // event-handle is a variable of the omp_event_handle_t type. + auto *Ref = dyn_cast<DeclRefExpr>(Evt->IgnoreParenImpCasts()); + if (!Ref) { + Diag(Evt->getExprLoc(), diag::err_omp_var_expected) + << "omp_event_handle_t" << 0 << Evt->getSourceRange(); + return nullptr; + } + auto *VD = dyn_cast_or_null<VarDecl>(Ref->getDecl()); + if (!VD) { + Diag(Evt->getExprLoc(), diag::err_omp_var_expected) + << "omp_event_handle_t" << 0 << Evt->getSourceRange(); + return nullptr; + } + if (!Context.hasSameUnqualifiedType(DSAStack->getOMPEventHandleT(), + VD->getType()) || + VD->getType().isConstant(Context)) { + Diag(Evt->getExprLoc(), diag::err_omp_var_expected) + << "omp_event_handle_t" << 1 << VD->getType() + << Evt->getSourceRange(); + return nullptr; + } + // OpenMP 5.0, 2.10.1 task Construct + // [detach clause]... The event-handle will be considered as if it was + // specified on a firstprivate clause. + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, /*FromParent=*/false); + if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_firstprivate && + DVar.RefExpr) { + Diag(Evt->getExprLoc(), diag::err_omp_wrong_dsa) + << getOpenMPClauseName(DVar.CKind) + << getOpenMPClauseName(OMPC_firstprivate); + reportOriginalDsa(*this, DSAStack, VD, DVar); + return nullptr; + } + } + + return new (Context) OMPDetachClause(Evt, StartLoc, LParenLoc, EndLoc); +} + OMPClause *Sema::ActOnOpenMPDistScheduleClause( OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc, @@ -16758,7 +18323,8 @@ OMPClause *Sema::ActOnOpenMPDefaultmapClause( } } else { bool isDefaultmapModifier = (M != OMPC_DEFAULTMAP_MODIFIER_unknown); - bool isDefaultmapKind = (Kind != OMPC_DEFAULTMAP_unknown); + bool isDefaultmapKind = (Kind != OMPC_DEFAULTMAP_unknown) || + (LangOpts.OpenMP >= 50 && KindLoc.isInvalid()); if (!isDefaultmapKind || !isDefaultmapModifier) { std::string ModifierValue = "'alloc', 'from', 'to', 'tofrom', " "'firstprivate', 'none', 'default'"; @@ -16786,7 +18352,14 @@ OMPClause *Sema::ActOnOpenMPDefaultmapClause( return nullptr; } } - DSAStack->setDefaultDMAAttr(M, Kind, StartLoc); + if (Kind == OMPC_DEFAULTMAP_unknown) { + // Variable category is not specified - mark all categories. + DSAStack->setDefaultDMAAttr(M, OMPC_DEFAULTMAP_aggregate, StartLoc); + DSAStack->setDefaultDMAAttr(M, OMPC_DEFAULTMAP_scalar, StartLoc); + DSAStack->setDefaultDMAAttr(M, OMPC_DEFAULTMAP_pointer, StartLoc); + } else { + DSAStack->setDefaultDMAAttr(M, Kind, StartLoc); + } return new (Context) OMPDefaultmapClause(StartLoc, LParenLoc, MLoc, KindLoc, EndLoc, Kind, M); @@ -16955,15 +18528,6 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, Diag(FD->getLocation(), diag::note_defined_here) << FD; return; } - // Mark the function as must be emitted for the device. - Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = - OMPDeclareTargetDeclAttr::getDeviceType(FD); - if (LangOpts.OpenMPIsDevice && Res.hasValue() && IdLoc.isValid() && - *DevTy != OMPDeclareTargetDeclAttr::DT_Host) - checkOpenMPDeviceFunction(IdLoc, FD, /*CheckForDelayedContext=*/false); - if (!LangOpts.OpenMPIsDevice && Res.hasValue() && IdLoc.isValid() && - *DevTy != OMPDeclareTargetDeclAttr::DT_NoHost) - checkOpenMPHostFunction(IdLoc, FD, /*CheckCaller=*/false); } if (auto *VD = dyn_cast<ValueDecl>(D)) { // Problem if any with var declared with incomplete type will be reported @@ -17109,6 +18673,58 @@ OMPClause *Sema::ActOnOpenMPUseDevicePtrClause(ArrayRef<Expr *> VarList, MVLI.VarBaseDeclarations, MVLI.VarComponents); } +OMPClause *Sema::ActOnOpenMPUseDeviceAddrClause(ArrayRef<Expr *> VarList, + const OMPVarListLocTy &Locs) { + MappableVarListInfo MVLI(VarList); + + for (Expr *RefExpr : VarList) { + assert(RefExpr && "NULL expr in OpenMP use_device_addr clause."); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/true); + if (Res.second) { + // It will be analyzed later. + MVLI.ProcessedVarList.push_back(RefExpr); + } + ValueDecl *D = Res.first; + if (!D) + continue; + auto *VD = dyn_cast<VarDecl>(D); + + // If required, build a capture to implement the privatization initialized + // with the current list item value. + DeclRefExpr *Ref = nullptr; + if (!VD) + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true); + MVLI.ProcessedVarList.push_back(VD ? RefExpr->IgnoreParens() : Ref); + + // We need to add a data sharing attribute for this variable to make sure it + // is correctly captured. A variable that shows up in a use_device_addr has + // similar properties of a first private variable. + DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_firstprivate, Ref); + + // Create a mappable component for the list item. List items in this clause + // only need a component. + MVLI.VarBaseDeclarations.push_back(D); + MVLI.VarComponents.emplace_back(); + Expr *Component = SimpleRefExpr; + if (VD && (isa<OMPArraySectionExpr>(RefExpr->IgnoreParenImpCasts()) || + isa<ArraySubscriptExpr>(RefExpr->IgnoreParenImpCasts()))) + Component = DefaultFunctionArrayLvalueConversion(SimpleRefExpr).get(); + MVLI.VarComponents.back().push_back( + OMPClauseMappableExprCommon::MappableComponent(Component, D)); + } + + if (MVLI.ProcessedVarList.empty()) + return nullptr; + + return OMPUseDeviceAddrClause::Create(Context, Locs, MVLI.ProcessedVarList, + MVLI.VarBaseDeclarations, + MVLI.VarComponents); +} + OMPClause *Sema::ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList, const OMPVarListLocTy &Locs) { MappableVarListInfo MVLI(VarList); @@ -17248,6 +18864,8 @@ OMPClause *Sema::ActOnOpenMPAllocateClause( if (Vars.empty()) return nullptr; + if (Allocator) + DSAStack->addInnerAllocatorExpr(Allocator); return OMPAllocateClause::Create(Context, StartLoc, LParenLoc, Allocator, ColonLoc, EndLoc, Vars); } @@ -17290,3 +18908,266 @@ OMPClause *Sema::ActOnOpenMPNontemporalClause(ArrayRef<Expr *> VarList, return OMPNontemporalClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); } + +OMPClause *Sema::ActOnOpenMPInclusiveClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + SmallVector<Expr *, 8> Vars; + for (Expr *RefExpr : VarList) { + assert(RefExpr && "NULL expr in OpenMP nontemporal clause."); + 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); + ValueDecl *D = Res.first; + if (!D) + continue; + + const DSAStackTy::DSAVarData DVar = + DSAStack->getTopDSA(D, /*FromParent=*/true); + // OpenMP 5.0, 2.9.6, scan Directive, Restrictions. + // A list item that appears in the inclusive or exclusive clause must appear + // in a reduction clause with the inscan modifier on the enclosing + // worksharing-loop, worksharing-loop SIMD, or simd construct. + if (DVar.CKind != OMPC_reduction || + DVar.Modifier != OMPC_REDUCTION_inscan) + Diag(ELoc, diag::err_omp_inclusive_exclusive_not_reduction) + << RefExpr->getSourceRange(); + + if (DSAStack->getParentDirective() != OMPD_unknown) + DSAStack->markDeclAsUsedInScanDirective(D); + Vars.push_back(RefExpr); + } + + if (Vars.empty()) + return nullptr; + + return OMPInclusiveClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); +} + +OMPClause *Sema::ActOnOpenMPExclusiveClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + SmallVector<Expr *, 8> Vars; + for (Expr *RefExpr : VarList) { + assert(RefExpr && "NULL expr in OpenMP nontemporal clause."); + 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); + ValueDecl *D = Res.first; + if (!D) + continue; + + OpenMPDirectiveKind ParentDirective = DSAStack->getParentDirective(); + DSAStackTy::DSAVarData DVar; + if (ParentDirective != OMPD_unknown) + DVar = DSAStack->getTopDSA(D, /*FromParent=*/true); + // OpenMP 5.0, 2.9.6, scan Directive, Restrictions. + // A list item that appears in the inclusive or exclusive clause must appear + // in a reduction clause with the inscan modifier on the enclosing + // worksharing-loop, worksharing-loop SIMD, or simd construct. + if (ParentDirective == OMPD_unknown || DVar.CKind != OMPC_reduction || + DVar.Modifier != OMPC_REDUCTION_inscan) { + Diag(ELoc, diag::err_omp_inclusive_exclusive_not_reduction) + << RefExpr->getSourceRange(); + } else { + DSAStack->markDeclAsUsedInScanDirective(D); + } + Vars.push_back(RefExpr); + } + + if (Vars.empty()) + return nullptr; + + return OMPExclusiveClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); +} + +/// Tries to find omp_alloctrait_t type. +static bool findOMPAlloctraitT(Sema &S, SourceLocation Loc, DSAStackTy *Stack) { + QualType OMPAlloctraitT = Stack->getOMPAlloctraitT(); + if (!OMPAlloctraitT.isNull()) + return true; + IdentifierInfo &II = S.PP.getIdentifierTable().get("omp_alloctrait_t"); + ParsedType PT = S.getTypeName(II, Loc, S.getCurScope()); + if (!PT.getAsOpaquePtr() || PT.get().isNull()) { + S.Diag(Loc, diag::err_omp_implied_type_not_found) << "omp_alloctrait_t"; + return false; + } + Stack->setOMPAlloctraitT(PT.get()); + return true; +} + +OMPClause *Sema::ActOnOpenMPUsesAllocatorClause( + SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, + ArrayRef<UsesAllocatorsData> Data) { + // OpenMP [2.12.5, target Construct] + // allocator is an identifier of omp_allocator_handle_t type. + if (!findOMPAllocatorHandleT(*this, StartLoc, DSAStack)) + return nullptr; + // OpenMP [2.12.5, target Construct] + // allocator-traits-array is an identifier of const omp_alloctrait_t * type. + if (llvm::any_of( + Data, + [](const UsesAllocatorsData &D) { return D.AllocatorTraits; }) && + !findOMPAlloctraitT(*this, StartLoc, DSAStack)) + return nullptr; + llvm::SmallSet<CanonicalDeclPtr<Decl>, 4> PredefinedAllocators; + for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) { + auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I); + StringRef Allocator = + OMPAllocateDeclAttr::ConvertAllocatorTypeTyToStr(AllocatorKind); + DeclarationName AllocatorName = &Context.Idents.get(Allocator); + PredefinedAllocators.insert(LookupSingleName( + TUScope, AllocatorName, StartLoc, Sema::LookupAnyName)); + } + + SmallVector<OMPUsesAllocatorsClause::Data, 4> NewData; + for (const UsesAllocatorsData &D : Data) { + Expr *AllocatorExpr = nullptr; + // Check allocator expression. + if (D.Allocator->isTypeDependent()) { + AllocatorExpr = D.Allocator; + } else { + // Traits were specified - need to assign new allocator to the specified + // allocator, so it must be an lvalue. + AllocatorExpr = D.Allocator->IgnoreParenImpCasts(); + auto *DRE = dyn_cast<DeclRefExpr>(AllocatorExpr); + bool IsPredefinedAllocator = false; + if (DRE) + IsPredefinedAllocator = PredefinedAllocators.count(DRE->getDecl()); + if (!DRE || + !(Context.hasSameUnqualifiedType( + AllocatorExpr->getType(), DSAStack->getOMPAllocatorHandleT()) || + Context.typesAreCompatible(AllocatorExpr->getType(), + DSAStack->getOMPAllocatorHandleT(), + /*CompareUnqualified=*/true)) || + (!IsPredefinedAllocator && + (AllocatorExpr->getType().isConstant(Context) || + !AllocatorExpr->isLValue()))) { + Diag(D.Allocator->getExprLoc(), diag::err_omp_var_expected) + << "omp_allocator_handle_t" << (DRE ? 1 : 0) + << AllocatorExpr->getType() << D.Allocator->getSourceRange(); + continue; + } + // OpenMP [2.12.5, target Construct] + // Predefined allocators appearing in a uses_allocators clause cannot have + // traits specified. + if (IsPredefinedAllocator && D.AllocatorTraits) { + Diag(D.AllocatorTraits->getExprLoc(), + diag::err_omp_predefined_allocator_with_traits) + << D.AllocatorTraits->getSourceRange(); + Diag(D.Allocator->getExprLoc(), diag::note_omp_predefined_allocator) + << cast<NamedDecl>(DRE->getDecl())->getName() + << D.Allocator->getSourceRange(); + continue; + } + // OpenMP [2.12.5, target Construct] + // Non-predefined allocators appearing in a uses_allocators clause must + // have traits specified. + if (!IsPredefinedAllocator && !D.AllocatorTraits) { + Diag(D.Allocator->getExprLoc(), + diag::err_omp_nonpredefined_allocator_without_traits); + continue; + } + // No allocator traits - just convert it to rvalue. + if (!D.AllocatorTraits) + AllocatorExpr = DefaultLvalueConversion(AllocatorExpr).get(); + DSAStack->addUsesAllocatorsDecl( + DRE->getDecl(), + IsPredefinedAllocator + ? DSAStackTy::UsesAllocatorsDeclKind::PredefinedAllocator + : DSAStackTy::UsesAllocatorsDeclKind::UserDefinedAllocator); + } + Expr *AllocatorTraitsExpr = nullptr; + if (D.AllocatorTraits) { + if (D.AllocatorTraits->isTypeDependent()) { + AllocatorTraitsExpr = D.AllocatorTraits; + } else { + // OpenMP [2.12.5, target Construct] + // Arrays that contain allocator traits that appear in a uses_allocators + // clause must be constant arrays, have constant values and be defined + // in the same scope as the construct in which the clause appears. + AllocatorTraitsExpr = D.AllocatorTraits->IgnoreParenImpCasts(); + // Check that traits expr is a constant array. + QualType TraitTy; + if (const ArrayType *Ty = + AllocatorTraitsExpr->getType()->getAsArrayTypeUnsafe()) + if (const auto *ConstArrayTy = dyn_cast<ConstantArrayType>(Ty)) + TraitTy = ConstArrayTy->getElementType(); + if (TraitTy.isNull() || + !(Context.hasSameUnqualifiedType(TraitTy, + DSAStack->getOMPAlloctraitT()) || + Context.typesAreCompatible(TraitTy, DSAStack->getOMPAlloctraitT(), + /*CompareUnqualified=*/true))) { + Diag(D.AllocatorTraits->getExprLoc(), + diag::err_omp_expected_array_alloctraits) + << AllocatorTraitsExpr->getType(); + continue; + } + // Do not map by default allocator traits if it is a standalone + // variable. + if (auto *DRE = dyn_cast<DeclRefExpr>(AllocatorTraitsExpr)) + DSAStack->addUsesAllocatorsDecl( + DRE->getDecl(), + DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait); + } + } + OMPUsesAllocatorsClause::Data &NewD = NewData.emplace_back(); + NewD.Allocator = AllocatorExpr; + NewD.AllocatorTraits = AllocatorTraitsExpr; + NewD.LParenLoc = D.LParenLoc; + NewD.RParenLoc = D.RParenLoc; + } + return OMPUsesAllocatorsClause::Create(Context, StartLoc, LParenLoc, EndLoc, + NewData); +} + +OMPClause *Sema::ActOnOpenMPAffinityClause( + SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, + SourceLocation EndLoc, Expr *Modifier, ArrayRef<Expr *> Locators) { + SmallVector<Expr *, 8> Vars; + for (Expr *RefExpr : Locators) { + assert(RefExpr && "NULL expr in OpenMP shared clause."); + if (isa<DependentScopeDeclRefExpr>(RefExpr) || RefExpr->isTypeDependent()) { + // It will be analyzed later. + Vars.push_back(RefExpr); + continue; + } + + SourceLocation ELoc = RefExpr->getExprLoc(); + Expr *SimpleExpr = RefExpr->IgnoreParenImpCasts(); + + if (!SimpleExpr->isLValue()) { + Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) + << 1 << 0 << RefExpr->getSourceRange(); + continue; + } + + ExprResult Res; + { + Sema::TentativeAnalysisScope Trap(*this); + Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, SimpleExpr); + } + if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr) && + !isa<OMPArrayShapingExpr>(SimpleExpr)) { + Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) + << 1 << 0 << RefExpr->getSourceRange(); + continue; + } + Vars.push_back(SimpleExpr); + } + + return OMPAffinityClause::Create(Context, StartLoc, LParenLoc, ColonLoc, + EndLoc, Modifier, Vars); +} |