Index: clang/include/clang/AST/OpenMPClause.h =================================================================== --- clang/include/clang/AST/OpenMPClause.h +++ clang/include/clang/AST/OpenMPClause.h @@ -9046,6 +9046,132 @@ Expr *getSize() const { return getStmtAs(); } }; +/// This represents the 'doacross' clause for the '#pragma omp ordered' +/// directive. +/// +/// \code +/// #pragma omp ordered doacross(sink: i-1, j-1) +/// \endcode +/// In this example directive '#pragma omp ordered' with clause 'doacross' with +/// a dependence-type 'sink' and loop-iteration vector expressions i-1 and j-1. +class OMPDoacrossClause final + : public OMPVarListClause, + private llvm::TrailingObjects { + friend class OMPClauseReader; + friend OMPVarListClause; + friend TrailingObjects; + + /// Dependence type (sink or source). + OpenMPDoacrossClauseModifier DepType = OMPC_DOACROSS_unknown; + + /// Dependence type location. + SourceLocation DepLoc; + + /// Colon location. + SourceLocation ColonLoc; + + /// Number of loops, associated with the doacross clause. + unsigned NumLoops = 0; + + /// Build clause with number of expressions \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param N Number of expressions in the clause. + /// \param NumLoops Number of loops associated with the clause. + OMPDoacrossClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, unsigned N, unsigned NumLoops) + : OMPVarListClause(llvm::omp::OMPC_doacross, StartLoc, + LParenLoc, EndLoc, N), + NumLoops(NumLoops) {} + + /// Build an empty clause. + /// + /// \param N Number of expressions in the clause. + /// \param NumLoops Number of loops associated with the clause. + explicit OMPDoacrossClause(unsigned N, unsigned NumLoops) + : OMPVarListClause(llvm::omp::OMPC_doacross, + SourceLocation(), SourceLocation(), + SourceLocation(), N), + NumLoops(NumLoops) {} + + /// Set dependence type. + void setDependenceType(OpenMPDoacrossClauseModifier M) { DepType = M; } + + /// Set dependence type location. + void setDependenceLoc(SourceLocation Loc) { DepLoc = Loc; } + + /// Set colon location. + void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; } + +public: + /// Creates clause with a list of expressions \a VL. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param DepType The dependence type. + /// \param DepLoc Location of the dependence type. + /// \param ColonLoc Location of ':'. + /// \param VL List of references to the expressions. + /// \param NumLoops Number of loops that associated with the clause. + static OMPDoacrossClause * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, OpenMPDoacrossClauseModifier DepType, + SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef VL, + unsigned NumLoops); + + /// Creates an empty clause with \a N expressions. + /// + /// \param C AST context. + /// \param N The number of expressions. + /// \param NumLoops Number of loops that is associated with this clause. + static OMPDoacrossClause *CreateEmpty(const ASTContext &C, unsigned N, + unsigned NumLoops); + + /// Get dependence type. + OpenMPDoacrossClauseModifier getDependenceType() const { return DepType; } + + /// Get dependence type location. + SourceLocation getDependenceLoc() const { return DepLoc; } + + /// Get colon location. + SourceLocation getColonLoc() const { return ColonLoc; } + + /// Get number of loops associated with the clause. + unsigned getNumLoops() const { return NumLoops; } + + /// Set the loop data. + void setLoopData(unsigned NumLoop, Expr *Cnt); + + /// Get the loop data. + Expr *getLoopData(unsigned NumLoop); + const Expr *getLoopData(unsigned NumLoop) const; + + child_range children() { + return child_range(reinterpret_cast(varlist_begin()), + reinterpret_cast(varlist_end())); + } + + const_child_range children() const { + auto Children = const_cast(this)->children(); + return const_child_range(Children.begin(), Children.end()); + } + + child_range used_children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range used_children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == llvm::omp::OMPC_doacross; + } +}; + } // namespace clang #endif // LLVM_CLANG_AST_OPENMPCLAUSE_H Index: clang/include/clang/AST/RecursiveASTVisitor.h =================================================================== --- clang/include/clang/AST/RecursiveASTVisitor.h +++ clang/include/clang/AST/RecursiveASTVisitor.h @@ -3864,6 +3864,13 @@ return true; } +template +bool RecursiveASTVisitor::VisitOMPDoacrossClause( + OMPDoacrossClause *C) { + TRY_TO(VisitOMPClauseList(C)); + return true; +} + // FIXME: look at the following tricky-seeming exprs to see if we // need to recurse on anything. These are ones that have methods // returning decls or qualtypes or nestednamespecifier -- though I'm Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10871,7 +10871,7 @@ def err_omp_ordered_directive_with_param : Error< "'ordered' directive %select{without any clauses|with 'threads' clause}0 cannot be closely nested inside ordered region with specified parameter">; def err_omp_ordered_directive_without_param : Error< - "'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter">; + "'ordered' directive with '%0' clause cannot be closely nested inside ordered region without specified parameter">; def note_omp_ordered_param : Note< "'ordered' clause%select{| with specified parameter}0">; def err_omp_expected_base_var_name : Error< @@ -10903,7 +10903,7 @@ def note_omp_critical_no_hint : Note< "%select{|previous }0directive with no 'hint' clause specified">; def err_omp_depend_clause_thread_simd : Error< - "'depend' clauses cannot be mixed with '%0' clause">; + "'%0' clauses cannot be mixed with '%1' clause">; def err_omp_depend_sink_expected_loop_iteration : Error< "expected%select{| %1}0 loop iteration variable">; def err_omp_depend_sink_unexpected_expr : Error< @@ -10912,8 +10912,8 @@ "expected '+' or '-' operation">; def err_omp_taskwait_depend_mutexinoutset_not_allowed : Error< "'mutexinoutset' modifier not allowed in 'depend' clause on 'taskwait' directive">; -def err_omp_depend_sink_source_not_allowed : Error< - "'depend(%select{source|sink:vec}0)' clause%select{|s}0 cannot be mixed with 'depend(%select{sink:vec|source}0)' clause%select{s|}0">; +def err_omp_sink_and_source_not_allowed : Error< + "'%0(%select{source|sink:vec}1)' clause%select{|s}1 cannot be mixed with '%0(%select{sink:vec|source}1)' clause%select{s|}1">; def err_omp_depend_zero_length_array_section_not_allowed : Error< "zero-length array section is not allowed in 'depend' clause">; def err_omp_depend_sink_source_with_modifier : Error< Index: clang/include/clang/Basic/OpenMPKinds.h =================================================================== --- clang/include/clang/Basic/OpenMPKinds.h +++ clang/include/clang/Basic/OpenMPKinds.h @@ -215,6 +215,13 @@ OMPC_NUMTASKS_unknown }; +/// OpenMP dependence types for 'doacross' clause. +enum OpenMPDoacrossClauseModifier { +#define OPENMP_DOACROSS_MODIFIER(Name) OMPC_DOACROSS_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPC_DOACROSS_unknown +}; + /// Contains 'interop' data for 'append_args' and 'init' clauses. class Expr; struct OMPInteropInfo final { Index: clang/include/clang/Basic/OpenMPKinds.def =================================================================== --- clang/include/clang/Basic/OpenMPKinds.def +++ clang/include/clang/Basic/OpenMPKinds.def @@ -80,6 +80,9 @@ #ifndef OPENMP_NUMTASKS_MODIFIER #define OPENMP_NUMTASKS_MODIFIER(Name) #endif +#ifndef OPENMP_DOACROSS_MODIFIER +#define OPENMP_DOACROSS_MODIFIER(Name) +#endif // Static attributes for 'schedule' clause. OPENMP_SCHEDULE_KIND(static) @@ -201,6 +204,10 @@ // Modifiers for the 'num_tasks' clause. OPENMP_NUMTASKS_MODIFIER(strict) +// Modifiers for the 'doacross' clause. +OPENMP_DOACROSS_MODIFIER(source) +OPENMP_DOACROSS_MODIFIER(sink) + #undef OPENMP_NUMTASKS_MODIFIER #undef OPENMP_GRAINSIZE_MODIFIER #undef OPENMP_BIND_KIND @@ -224,4 +231,5 @@ #undef OPENMP_DIST_SCHEDULE_KIND #undef OPENMP_DEFAULTMAP_KIND #undef OPENMP_DEFAULTMAP_MODIFIER +#undef OPENMP_DOACROSS_MODIFIER Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -11032,10 +11032,7 @@ /// Initialization of data-sharing attributes stack. void InitDataSharingAttributesStack(); void DestroyDataSharingAttributesStack(); - ExprResult - VerifyPositiveIntegerConstantInClause(Expr *Op, OpenMPClauseKind CKind, - bool StrictlyPositive = true, - bool SuppressExprDiags = false); + /// Returns OpenMP nesting level for current directive. unsigned getOpenMPNestingLevel() const; @@ -11121,6 +11118,11 @@ return !OMPDeclareVariantScopes.empty(); } + ExprResult + VerifyPositiveIntegerConstantInClause(Expr *Op, OpenMPClauseKind CKind, + bool StrictlyPositive = true, + bool SuppressExprDiags = false); + /// Given the potential call expression \p Call, determine if there is a /// specialization via the OpenMP declare variant mechanism available. If /// there is, return the specialized call expression, otherwise return the @@ -12281,6 +12283,13 @@ SourceLocation LParenLoc, SourceLocation EndLoc); + /// Called on well-formed 'doacross' clause. + OMPClause * + ActOnOpenMPDoacrossClause(OpenMPDoacrossClauseModifier DepType, + SourceLocation DepLoc, SourceLocation ColonLoc, + ArrayRef VarList, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc); + /// The kind of conversion being performed. enum CheckedConversionKind { /// An implicit conversion. Index: clang/lib/AST/OpenMPClause.cpp =================================================================== --- clang/lib/AST/OpenMPClause.cpp +++ clang/lib/AST/OpenMPClause.cpp @@ -1669,6 +1669,52 @@ OMPBindClause *OMPBindClause::CreateEmpty(const ASTContext &C) { return new (C) OMPBindClause(); } + +OMPDoacrossClause * +OMPDoacrossClause::Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc, + OpenMPDoacrossClauseModifier DepType, + SourceLocation DepLoc, SourceLocation ColonLoc, + ArrayRef VL, unsigned NumLoops) { + void *Mem = C.Allocate(totalSizeToAlloc(VL.size() + NumLoops), + alignof(OMPDoacrossClause)); + OMPDoacrossClause *Clause = new (Mem) + OMPDoacrossClause(StartLoc, LParenLoc, EndLoc, VL.size(), NumLoops); + Clause->setDependenceType(DepType); + Clause->setDependenceLoc(DepLoc); + Clause->setColonLoc(ColonLoc); + Clause->setVarRefs(VL); + for (unsigned I = 0; I < NumLoops; ++I) + Clause->setLoopData(I, nullptr); + return Clause; +} + +OMPDoacrossClause *OMPDoacrossClause::CreateEmpty(const ASTContext &C, + unsigned N, + unsigned NumLoops) { + void *Mem = C.Allocate(totalSizeToAlloc(N + NumLoops), + alignof(OMPDoacrossClause)); + return new (Mem) OMPDoacrossClause(N, NumLoops); +} + +void OMPDoacrossClause::setLoopData(unsigned NumLoop, Expr *Cnt) { + assert(NumLoop < NumLoops && "Loop index must be less number of loops."); + auto *It = std::next(getVarRefs().end(), NumLoop); + *It = Cnt; +} + +Expr *OMPDoacrossClause::getLoopData(unsigned NumLoop) { + assert(NumLoop < NumLoops && "Loop index must be less number of loops."); + auto *It = std::next(getVarRefs().end(), NumLoop); + return *It; +} + +const Expr *OMPDoacrossClause::getLoopData(unsigned NumLoop) const { + assert(NumLoop < NumLoops && "Loop index must be less number of loops."); + const auto *It = std::next(getVarRefs().end(), NumLoop); + return *It; +} + //===----------------------------------------------------------------------===// // OpenMP clauses printing methods //===----------------------------------------------------------------------===// @@ -2464,6 +2510,14 @@ OS << ")"; } +void OMPClausePrinter::VisitOMPDoacrossClause(OMPDoacrossClause *Node) { + OS << "doacross("; + OpenMPDoacrossClauseModifier DepType = Node->getDependenceType(); + OS << (DepType == OMPC_DOACROSS_source ? "source:" : "sink:"); + VisitOMPClauseList(Node, ' '); + OS << ")"; +} + void OMPTraitInfo::getAsVariantMatchInfo(ASTContext &ASTCtx, VariantMatchInfo &VMI) const { for (const OMPTraitSet &Set : Sets) { Index: clang/lib/AST/StmtProfile.cpp =================================================================== --- clang/lib/AST/StmtProfile.cpp +++ clang/lib/AST/StmtProfile.cpp @@ -920,6 +920,9 @@ if (Expr *Size = C->getSize()) Profiler->VisitStmt(Size); } +void OMPClauseProfiler::VisitOMPDoacrossClause(const OMPDoacrossClause *C) { + VisitOMPClauseList(C); +} } // namespace void Index: clang/lib/Basic/OpenMPKinds.cpp =================================================================== --- clang/lib/Basic/OpenMPKinds.cpp +++ clang/lib/Basic/OpenMPKinds.cpp @@ -50,6 +50,11 @@ return OMPC_DEPEND_unknown; return Type; } + case OMPC_doacross: + return llvm::StringSwitch(Str) +#define OPENMP_DOACROSS_MODIFIER(Name) .Case(#Name, OMPC_DOACROSS_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_DOACROSS_unknown); case OMPC_linear: return llvm::StringSwitch(Str) #define OPENMP_LINEAR_KIND(Name) .Case(#Name, OMPC_LINEAR_##Name) @@ -282,6 +287,16 @@ #include "clang/Basic/OpenMPKinds.def" } llvm_unreachable("Invalid OpenMP 'depend' clause type"); + case OMPC_doacross: + switch (Type) { + case OMPC_DOACROSS_unknown: + return "unknown"; +#define OPENMP_DOACROSS_MODIFIER(Name) \ + case OMPC_DOACROSS_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'doacross' clause type"); case OMPC_linear: switch (Type) { case OMPC_LINEAR_unknown: Index: clang/lib/Parse/ParseOpenMP.cpp =================================================================== --- clang/lib/Parse/ParseOpenMP.cpp +++ clang/lib/Parse/ParseOpenMP.cpp @@ -2924,17 +2924,20 @@ // Consume final annot_pragma_openmp_end. ConsumeAnnotationToken(); - // OpenMP [2.13.8, ordered Construct, Syntax] - // If the depend clause is specified, the ordered construct is a stand-alone - // directive. - if (DKind == OMPD_ordered && FirstClauses[unsigned(OMPC_depend)].getInt()) { - if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == - ParsedStmtContext()) { - Diag(Loc, diag::err_omp_immediate_directive) - << getOpenMPDirectiveName(DKind) << 1 - << getOpenMPClauseName(OMPC_depend); + if (DKind == OMPD_ordered) { + // If the depend or doacross clause is specified, the ordered construct + // is a stand-alone directive. + for (auto CK : {OMPC_depend, OMPC_doacross}) { + if (FirstClauses[unsigned(CK)].getInt()) { + if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == + ParsedStmtContext()) { + Diag(Loc, diag::err_omp_immediate_directive) + << getOpenMPDirectiveName(DKind) << 1 + << getOpenMPClauseName(CK); + } + HasAssociatedStatement = false; + } } - HasAssociatedStatement = false; } if (DKind == OMPD_tile && !FirstClauses[unsigned(OMPC_sizes)].getInt()) { @@ -3363,6 +3366,7 @@ case OMPC_inclusive: case OMPC_exclusive: case OMPC_affinity: + case OMPC_doacross: Clause = ParseOpenMPVarListClause(DKind, CKind, WrongDirective); break; case OMPC_sizes: @@ -4366,7 +4370,7 @@ if (!InvalidReductionId) Data.ReductionOrMapperId = Actions.GetNameFromUnqualifiedId(UnqualifiedReductionId); - } else if (Kind == OMPC_depend) { + } else if (Kind == OMPC_depend || Kind == OMPC_doacross) { if (getLangOpts().OpenMP >= 50) { if (Tok.is(tok::identifier) && PP.getSpelling(Tok) == "iterator") { // Handle optional dependence modifier. @@ -4389,13 +4393,16 @@ Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "", getLangOpts()); Data.ExtraModifierLoc = Tok.getLocation(); - if (Data.ExtraModifier == OMPC_DEPEND_unknown) { + if ((Kind == OMPC_depend && Data.ExtraModifier == OMPC_DEPEND_unknown) || + (Kind == OMPC_doacross && + Data.ExtraModifier == OMPC_DOACROSS_unknown)) { SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); } else { ConsumeToken(); // Special processing for depend(source) clause. - if (DKind == OMPD_ordered && Data.ExtraModifier == OMPC_DEPEND_source) { + if (DKind == OMPD_ordered && Kind == OMPC_depend && + Data.ExtraModifier == OMPC_DEPEND_source) { // Parse ')'. T.consumeClose(); return false; @@ -4406,7 +4413,13 @@ } else { Diag(Tok, DKind == OMPD_ordered ? diag::warn_pragma_expected_colon_r_paren : diag::warn_pragma_expected_colon) - << "dependency type"; + << (Kind == OMPC_depend ? "dependency type" : "dependence-type"); + } + // Special processing for doacross(source) clause. + if (Kind == OMPC_doacross && Data.ExtraModifier == OMPC_DOACROSS_source) { + // Parse ')'. + T.consumeClose(); + return false; } } else if (Kind == OMPC_linear) { // Try to parse modifier if any. @@ -4585,10 +4598,12 @@ bool IsComma = (Kind != OMPC_reduction && Kind != OMPC_task_reduction && - Kind != OMPC_in_reduction && Kind != OMPC_depend && Kind != OMPC_map) || + Kind != OMPC_in_reduction && Kind != OMPC_depend && + Kind != OMPC_doacross && Kind != OMPC_map) || (Kind == OMPC_reduction && !InvalidReductionId) || (Kind == OMPC_map && Data.ExtraModifier != OMPC_MAP_unknown) || (Kind == OMPC_depend && Data.ExtraModifier != OMPC_DEPEND_unknown) || + (Kind == OMPC_doacross && Data.ExtraModifier != OMPC_DOACROSS_unknown) || (Kind == OMPC_adjust_args && Data.ExtraModifier != OMPC_ADJUST_ARGS_unknown); const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned); @@ -4646,7 +4661,8 @@ // Exit from scope when the iterator is used in depend clause. if (HasIterator) ExitScope(); - return (Kind != OMPC_depend && Kind != OMPC_map && Vars.empty()) || + return (Kind != OMPC_depend && Kind != OMPC_doacross && Kind != OMPC_map && + Vars.empty()) || (MustHaveTail && !Data.DepModOrTailExpr) || InvalidReductionId || IsInvalidMapperModifier || InvalidIterator; } Index: clang/lib/Sema/SemaOpenMP.cpp =================================================================== --- clang/lib/Sema/SemaOpenMP.cpp +++ clang/lib/Sema/SemaOpenMP.cpp @@ -88,8 +88,7 @@ }; using OperatorOffsetTy = llvm::SmallVector, 4>; - using DoacrossDependMapTy = - llvm::DenseMap; + using DoacrossClauseMapTy = llvm::DenseMap; /// Kind of the declaration used in the uses_allocators clauses. enum class UsesAllocatorsDeclKind { /// Predefined allocator @@ -170,7 +169,7 @@ /// Set of 'depend' clauses with 'sink|source' dependence kind. Required to /// get the data (loop counters etc.) about enclosing loop-based construct. /// This data is required during codegen. - DoacrossDependMapTy DoacrossDepends; + DoacrossClauseMapTy DoacrossDepends; /// First argument (Expr *) contains optional argument of the /// 'ordered' clause, the second one is true if the regions has 'ordered' /// clause, false otherwise. @@ -1055,17 +1054,16 @@ assert(!isStackEmpty()); return getStackSize() - 1; } - void addDoacrossDependClause(OMPDependClause *C, - const OperatorOffsetTy &OpsOffs) { + void addDoacrossDependClause(OMPClause *C, const OperatorOffsetTy &OpsOffs) { SharingMapTy *Parent = getSecondOnStackOrNull(); assert(Parent && isOpenMPWorksharingDirective(Parent->Directive)); Parent->DoacrossDepends.try_emplace(C, OpsOffs); } - llvm::iterator_range + llvm::iterator_range getDoacrossDependClauses() const { const SharingMapTy &StackElem = getTopOfStack(); if (isOpenMPWorksharingDirective(StackElem.Directive)) { - const DoacrossDependMapTy &Ref = StackElem.DoacrossDepends; + const DoacrossClauseMapTy &Ref = StackElem.DoacrossDepends; return llvm::make_range(Ref.begin(), Ref.end()); } return llvm::make_range(StackElem.DoacrossDepends.end(), @@ -9335,30 +9333,45 @@ } } for (auto &Pair : DSA.getDoacrossDependClauses()) { - if (CurrentNestedLoopCount >= Pair.first->getNumLoops()) { + auto *DependC = dyn_cast(Pair.first); + auto *DoacrossC = dyn_cast(Pair.first); + unsigned NumLoops = + DependC ? DependC->getNumLoops() : DoacrossC->getNumLoops(); + if (CurrentNestedLoopCount >= NumLoops) { // Erroneous case - clause has some problems. continue; } - if (Pair.first->getDependencyKind() == OMPC_DEPEND_sink && + if (DependC && DependC->getDependencyKind() == OMPC_DEPEND_sink && Pair.second.size() <= CurrentNestedLoopCount) { // Erroneous case - clause has some problems. - Pair.first->setLoopData(CurrentNestedLoopCount, nullptr); + DependC->setLoopData(CurrentNestedLoopCount, nullptr); + continue; + } + if (DoacrossC && DoacrossC->getDependenceType() == OMPC_DOACROSS_sink && + Pair.second.size() <= CurrentNestedLoopCount) { + // Erroneous case - clause has some problems. + DoacrossC->setLoopData(CurrentNestedLoopCount, nullptr); continue; } Expr *CntValue; - if (Pair.first->getDependencyKind() == OMPC_DEPEND_source) + SourceLocation DepLoc = + DependC ? DependC->getDependencyLoc() : DoacrossC->getDependenceLoc(); + if ((DependC && DependC->getDependencyKind() == OMPC_DEPEND_source) || + (DoacrossC && DoacrossC->getDependenceType() == OMPC_DOACROSS_source)) CntValue = ISC.buildOrderedLoopData( DSA.getCurScope(), ResultIterSpaces[CurrentNestedLoopCount].CounterVar, Captures, - Pair.first->getDependencyLoc()); + DepLoc); else CntValue = ISC.buildOrderedLoopData( DSA.getCurScope(), ResultIterSpaces[CurrentNestedLoopCount].CounterVar, Captures, - Pair.first->getDependencyLoc(), - Pair.second[CurrentNestedLoopCount].first, + DepLoc, Pair.second[CurrentNestedLoopCount].first, Pair.second[CurrentNestedLoopCount].second); - Pair.first->setLoopData(CurrentNestedLoopCount, CntValue); + if (DependC) + DependC->setLoopData(CurrentNestedLoopCount, CntValue); + else + DoacrossC->setLoopData(CurrentNestedLoopCount, CntValue); } } @@ -11274,33 +11287,47 @@ const OMPClause *DependFound = nullptr; const OMPClause *DependSourceClause = nullptr; const OMPClause *DependSinkClause = nullptr; + const OMPClause *DoacrossFound = nullptr; + const OMPClause *DoacrossSourceClause = nullptr; + const OMPClause *DoacrossSinkClause = nullptr; bool ErrorFound = false; const OMPThreadsClause *TC = nullptr; const OMPSIMDClause *SC = nullptr; for (const OMPClause *C : Clauses) { - if (auto *DC = dyn_cast(C)) { - DependFound = C; - if (DC->getDependencyKind() == OMPC_DEPEND_source) { - if (DependSourceClause) { + auto DOC = dyn_cast(C); + auto DC = dyn_cast(C); + if (DC || DOC) { + DependFound = DC ? C : nullptr; + DoacrossFound = DOC ? C : nullptr; + if ((DC && DC->getDependencyKind() == OMPC_DEPEND_source) || + (DOC && DOC->getDependenceType() == OMPC_DOACROSS_source)) { + if ((DC && DependSourceClause) || (DOC && DoacrossSourceClause)) { Diag(C->getBeginLoc(), diag::err_omp_more_one_clause) << getOpenMPDirectiveName(OMPD_ordered) - << getOpenMPClauseName(OMPC_depend) << 2; + << getOpenMPClauseName(DC ? OMPC_depend : OMPC_doacross) << 2; ErrorFound = true; } else { - DependSourceClause = C; + if (DC) + DependSourceClause = C; + else + DoacrossSourceClause = C; } - if (DependSinkClause) { - Diag(C->getBeginLoc(), diag::err_omp_depend_sink_source_not_allowed) - << 0; + if ((DC && DependSinkClause) || (DOC && DoacrossSinkClause)) { + Diag(C->getBeginLoc(), diag::err_omp_sink_and_source_not_allowed) + << (DC ? "depend" : "doacross") << 0; ErrorFound = true; } - } else if (DC->getDependencyKind() == OMPC_DEPEND_sink) { - if (DependSourceClause) { - Diag(C->getBeginLoc(), diag::err_omp_depend_sink_source_not_allowed) - << 1; + } else if ((DC && DC->getDependencyKind() == OMPC_DEPEND_sink) || + (DOC && DOC->getDependenceType() == OMPC_DOACROSS_sink)) { + if (DependSourceClause || DoacrossSourceClause) { + Diag(C->getBeginLoc(), diag::err_omp_sink_and_source_not_allowed) + << (DC ? "depend" : "doacross") << 1; ErrorFound = true; } - DependSinkClause = C; + if (DC) + DependSinkClause = C; + else + DoacrossSinkClause = C; } } else if (C->getClauseKind() == OMPC_threads) { TC = cast(C); @@ -11316,13 +11343,19 @@ Diag(StartLoc, diag::err_omp_prohibited_region_simd) << (LangOpts.OpenMP >= 50 ? 1 : 0); ErrorFound = true; - } else if (DependFound && (TC || SC)) { - Diag(DependFound->getBeginLoc(), diag::err_omp_depend_clause_thread_simd) + } else if ((DependFound || DoacrossFound) && (TC || SC)) { + SourceLocation Loc = + DependFound ? DependFound->getBeginLoc() : DoacrossFound->getBeginLoc(); + Diag(Loc, diag::err_omp_depend_clause_thread_simd) + << getOpenMPClauseName(DependFound ? OMPC_depend : OMPC_doacross) << getOpenMPClauseName(TC ? TC->getClauseKind() : SC->getClauseKind()); ErrorFound = true; - } else if (DependFound && !DSAStack->getParentOrderedRegionParam().first) { - Diag(DependFound->getBeginLoc(), - diag::err_omp_ordered_directive_without_param); + } else if ((DependFound || DoacrossFound) && + !DSAStack->getParentOrderedRegionParam().first) { + SourceLocation Loc = + DependFound ? DependFound->getBeginLoc() : DoacrossFound->getBeginLoc(); + Diag(Loc, diag::err_omp_ordered_directive_without_param) + << getOpenMPClauseName(DependFound ? OMPC_depend : OMPC_doacross); ErrorFound = true; } else if (TC || Clauses.empty()) { if (const Expr *Param = DSAStack->getParentOrderedRegionParam().first) { @@ -11333,7 +11366,7 @@ ErrorFound = true; } } - if ((!AStmt && !DependFound) || ErrorFound) + if ((!AStmt && !DependFound && !DoacrossFound) || ErrorFound) return StmtError(); // OpenMP 5.0, 2.17.9, ordered Construct, Restrictions. @@ -11341,7 +11374,7 @@ // 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 (!DependFound && !DoacrossFound) { if (DSAStack->doesParentHasOrderedDirective()) { Diag(StartLoc, diag::err_omp_several_directives_in_region) << "ordered"; Diag(DSAStack->getParentOrderedDirectiveLoc(), @@ -17904,6 +17937,11 @@ Res = ActOnOpenMPAffinityClause(StartLoc, LParenLoc, ColonLoc, EndLoc, Data.DepModOrTailExpr, VarList); break; + case OMPC_doacross: + Res = ActOnOpenMPDoacrossClause( + static_cast(ExtraModifier), + ExtraModifierLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc); + break; case OMPC_if: case OMPC_depobj: case OMPC_final: @@ -20525,71 +20563,35 @@ return OMPDepobjClause::Create(Context, StartLoc, LParenLoc, EndLoc, Depobj); } -OMPClause * -Sema::ActOnOpenMPDependClause(const OMPDependClause::DependDataTy &Data, - Expr *DepModifier, ArrayRef VarList, - SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc) { - OpenMPDependClauseKind DepKind = Data.DepKind; - SourceLocation DepLoc = Data.DepLoc; - if (DSAStack->getCurrentDirective() == OMPD_ordered && - DepKind != OMPC_DEPEND_source && DepKind != OMPC_DEPEND_sink) { - Diag(DepLoc, diag::err_omp_unexpected_clause_value) - << "'source' or 'sink'" << getOpenMPClauseName(OMPC_depend); - return nullptr; - } - if (DSAStack->getCurrentDirective() == OMPD_taskwait && - DepKind == OMPC_DEPEND_mutexinoutset) { - Diag(DepLoc, diag::err_omp_taskwait_depend_mutexinoutset_not_allowed); - return nullptr; - } - if ((DSAStack->getCurrentDirective() != OMPD_ordered || - DSAStack->getCurrentDirective() == OMPD_depobj) && - (DepKind == OMPC_DEPEND_unknown || DepKind == OMPC_DEPEND_source || - DepKind == OMPC_DEPEND_sink || - ((LangOpts.OpenMP < 50 || - DSAStack->getCurrentDirective() == OMPD_depobj) && - DepKind == OMPC_DEPEND_depobj))) { - SmallVector Except = {OMPC_DEPEND_source, OMPC_DEPEND_sink, - OMPC_DEPEND_outallmemory, - OMPC_DEPEND_inoutallmemory}; - if (LangOpts.OpenMP < 50 || DSAStack->getCurrentDirective() == OMPD_depobj) - Except.push_back(OMPC_DEPEND_depobj); - if (LangOpts.OpenMP < 51) - Except.push_back(OMPC_DEPEND_inoutset); - std::string Expected = (LangOpts.OpenMP >= 50 && !DepModifier) - ? "depend modifier(iterator) or " - : ""; - Diag(DepLoc, diag::err_omp_unexpected_clause_value) - << 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); +namespace { +// Utility struct that gathers the related info for doacross clause. +struct DoacrossDataInfoTy { + // The list of expressions. + SmallVector Vars; + // The OperatorOffset for doacross loop. + DSAStackTy::OperatorOffsetTy OpsOffs; + // The depended loop count. + llvm::APSInt TotalDepCount; +}; +} // namespace +static DoacrossDataInfoTy +ProcessOpenMPDoacrossClauseCommon(Sema &SemaRef, bool IsSource, + ArrayRef VarList, DSAStackTy *Stack, + SourceLocation EndLoc) { SmallVector Vars; DSAStackTy::OperatorOffsetTy OpsOffs; llvm::APSInt DepCounter(/*BitWidth=*/32); llvm::APSInt TotalDepCount(/*BitWidth=*/32); - if (DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source) { - if (const Expr *OrderedCountExpr = - DSAStack->getParentOrderedRegionParam().first) { - TotalDepCount = OrderedCountExpr->EvaluateKnownConstInt(Context); - TotalDepCount.setIsUnsigned(/*Val=*/true); - } + + if (const Expr *OrderedCountExpr = + Stack->getParentOrderedRegionParam().first) { + TotalDepCount = OrderedCountExpr->EvaluateKnownConstInt(SemaRef.Context); + TotalDepCount.setIsUnsigned(/*Val=*/true); } + for (Expr *RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP shared clause."); + assert(RefExpr && "NULL expr in OpenMP doacross clause."); if (isa(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); @@ -20598,10 +20600,10 @@ SourceLocation ELoc = RefExpr->getExprLoc(); Expr *SimpleExpr = RefExpr->IgnoreParenCasts(); - if (DepKind == OMPC_DEPEND_sink) { - if (DSAStack->getParentOrderedRegionParam().first && + if (!IsSource) { + if (Stack->getParentOrderedRegionParam().first && DepCounter >= TotalDepCount) { - Diag(ELoc, diag::err_omp_depend_sink_unexpected_expr); + SemaRef.Diag(ELoc, diag::err_omp_depend_sink_unexpected_expr); continue; } ++DepCounter; @@ -20613,7 +20615,7 @@ // directive, xi denotes the loop iteration variable of the i-th nested // loop associated with the loop directive, and di is a constant // non-negative integer. - if (CurContext->isDependentContext()) { + if (SemaRef.CurContext->isDependentContext()) { // It will be analyzed later. Vars.push_back(RefExpr); continue; @@ -20644,7 +20646,7 @@ } SourceLocation ELoc; SourceRange ERange; - auto Res = getPrivateItem(*this, LHS, ELoc, ERange); + auto Res = getPrivateItem(SemaRef, LHS, ELoc, ERange); if (Res.second) { // It will be analyzed later. Vars.push_back(RefExpr); @@ -20654,29 +20656,116 @@ continue; if (OOK != OO_Plus && OOK != OO_Minus && (RHS || OOK != OO_None)) { - Diag(OOLoc, diag::err_omp_depend_sink_expected_plus_minus); + SemaRef.Diag(OOLoc, diag::err_omp_depend_sink_expected_plus_minus); continue; } if (RHS) { - ExprResult RHSRes = VerifyPositiveIntegerConstantInClause( + ExprResult RHSRes = SemaRef.VerifyPositiveIntegerConstantInClause( RHS, OMPC_depend, /*StrictlyPositive=*/false); if (RHSRes.isInvalid()) continue; } - if (!CurContext->isDependentContext() && - DSAStack->getParentOrderedRegionParam().first && - DepCounter != DSAStack->isParentLoopControlVariable(D).first) { + if (!SemaRef.CurContext->isDependentContext() && + Stack->getParentOrderedRegionParam().first && + DepCounter != Stack->isParentLoopControlVariable(D).first) { const ValueDecl *VD = - DSAStack->getParentLoopControlVariable(DepCounter.getZExtValue()); + Stack->getParentLoopControlVariable(DepCounter.getZExtValue()); if (VD) - Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration) + SemaRef.Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration) << 1 << VD; else - Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration) << 0; + SemaRef.Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration) + << 0; continue; } OpsOffs.emplace_back(RHS, OOK); - } else { + } + Vars.push_back(RefExpr->IgnoreParenImpCasts()); + } + if (!SemaRef.CurContext->isDependentContext() && !IsSource && + TotalDepCount > VarList.size() && + Stack->getParentOrderedRegionParam().first && + Stack->getParentLoopControlVariable(VarList.size() + 1)) { + SemaRef.Diag(EndLoc, diag::err_omp_depend_sink_expected_loop_iteration) + << 1 << Stack->getParentLoopControlVariable(VarList.size() + 1); + } + return {Vars, OpsOffs, TotalDepCount}; +} + +OMPClause * +Sema::ActOnOpenMPDependClause(const OMPDependClause::DependDataTy &Data, + Expr *DepModifier, ArrayRef VarList, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc) { + OpenMPDependClauseKind DepKind = Data.DepKind; + SourceLocation DepLoc = Data.DepLoc; + if (DSAStack->getCurrentDirective() == OMPD_ordered && + DepKind != OMPC_DEPEND_source && DepKind != OMPC_DEPEND_sink) { + Diag(DepLoc, diag::err_omp_unexpected_clause_value) + << "'source' or 'sink'" << getOpenMPClauseName(OMPC_depend); + return nullptr; + } + if (DSAStack->getCurrentDirective() == OMPD_taskwait && + DepKind == OMPC_DEPEND_mutexinoutset) { + Diag(DepLoc, diag::err_omp_taskwait_depend_mutexinoutset_not_allowed); + return nullptr; + } + if ((DSAStack->getCurrentDirective() != OMPD_ordered || + DSAStack->getCurrentDirective() == OMPD_depobj) && + (DepKind == OMPC_DEPEND_unknown || DepKind == OMPC_DEPEND_source || + DepKind == OMPC_DEPEND_sink || + ((LangOpts.OpenMP < 50 || + DSAStack->getCurrentDirective() == OMPD_depobj) && + DepKind == OMPC_DEPEND_depobj))) { + SmallVector Except = {OMPC_DEPEND_source, OMPC_DEPEND_sink, + OMPC_DEPEND_outallmemory, + OMPC_DEPEND_inoutallmemory}; + if (LangOpts.OpenMP < 50 || DSAStack->getCurrentDirective() == OMPD_depobj) + Except.push_back(OMPC_DEPEND_depobj); + if (LangOpts.OpenMP < 51) + Except.push_back(OMPC_DEPEND_inoutset); + std::string Expected = (LangOpts.OpenMP >= 50 && !DepModifier) + ? "depend modifier(iterator) or " + : ""; + Diag(DepLoc, diag::err_omp_unexpected_clause_value) + << 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 Vars; + DSAStackTy::OperatorOffsetTy OpsOffs; + llvm::APSInt TotalDepCount(/*BitWidth=*/32); + + if (DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source) { + DoacrossDataInfoTy VarOffset = ProcessOpenMPDoacrossClauseCommon( + *this, DepKind == OMPC_DEPEND_source, VarList, DSAStack, EndLoc); + Vars = VarOffset.Vars; + OpsOffs = VarOffset.OpsOffs; + TotalDepCount = VarOffset.TotalDepCount; + } else + for (Expr *RefExpr : VarList) { + assert(RefExpr && "NULL expr in OpenMP shared clause."); + if (isa(RefExpr)) { + // It will be analyzed later. + Vars.push_back(RefExpr); + continue; + } + + SourceLocation ELoc = RefExpr->getExprLoc(); + Expr *SimpleExpr = RefExpr->IgnoreParenCasts(); + if (DepKind != OMPC_DEPEND_sink && DepKind != OMPC_DEPEND_source) { bool OMPDependTFound = LangOpts.OpenMP >= 50; if (OMPDependTFound) OMPDependTFound = findOMPDependT(*this, StartLoc, DSAStack, @@ -20770,13 +20859,6 @@ Vars.push_back(RefExpr->IgnoreParenImpCasts()); } - if (!CurContext->isDependentContext() && DepKind == OMPC_DEPEND_sink && - TotalDepCount > VarList.size() && - DSAStack->getParentOrderedRegionParam().first && - DSAStack->getParentLoopControlVariable(VarList.size() + 1)) { - Diag(EndLoc, diag::err_omp_depend_sink_expected_loop_iteration) - << 1 << DSAStack->getParentLoopControlVariable(VarList.size() + 1); - } if (DepKind != OMPC_DEPEND_source && DepKind != OMPC_DEPEND_sink && DepKind != OMPC_DEPEND_outallmemory && DepKind != OMPC_DEPEND_inoutallmemory && Vars.empty()) @@ -23947,3 +24029,31 @@ return new (Context) OMPXDynCGroupMemClause( ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc); } + +OMPClause *Sema::ActOnOpenMPDoacrossClause( + OpenMPDoacrossClauseModifier DepType, SourceLocation DepLoc, + SourceLocation ColonLoc, ArrayRef VarList, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) { + + if (DSAStack->getCurrentDirective() == OMPD_ordered && + DepType != OMPC_DOACROSS_source && DepType != OMPC_DOACROSS_sink) { + Diag(DepLoc, diag::err_omp_unexpected_clause_value) + << "'source' or 'sink'" << getOpenMPClauseName(OMPC_doacross); + return nullptr; + } + + SmallVector Vars; + DSAStackTy::OperatorOffsetTy OpsOffs; + llvm::APSInt TotalDepCount(/*BitWidth=*/32); + DoacrossDataInfoTy VarOffset = ProcessOpenMPDoacrossClauseCommon( + *this, DepType == OMPC_DOACROSS_source, VarList, DSAStack, EndLoc); + Vars = VarOffset.Vars; + OpsOffs = VarOffset.OpsOffs; + TotalDepCount = VarOffset.TotalDepCount; + auto *C = OMPDoacrossClause::Create(Context, StartLoc, LParenLoc, EndLoc, + DepType, DepLoc, ColonLoc, Vars, + TotalDepCount.getZExtValue()); + if (DSAStack->isParentOrderedRegion()) + DSAStack->addDoacrossDependClause(C, OpsOffs); + return C; +} Index: clang/lib/Sema/TreeTransform.h =================================================================== --- clang/lib/Sema/TreeTransform.h +++ clang/lib/Sema/TreeTransform.h @@ -2422,6 +2422,19 @@ return getSema().ActOnOpenMPMessageClause(MS, StartLoc, LParenLoc, EndLoc); } + /// Build a new OpenMP 'doacross' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause * + RebuildOMPDoacrossClause(OpenMPDoacrossClauseModifier DepType, + SourceLocation DepLoc, SourceLocation ColonLoc, + ArrayRef VarList, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) { + return getSema().ActOnOpenMPDoacrossClause( + DepType, DepLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc); + } + /// Rebuild the operand to an Objective-C \@synchronized statement. /// /// By default, performs semantic analysis to build the new statement. @@ -10727,6 +10740,22 @@ Size.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } +template +OMPClause * +TreeTransform::TransformOMPDoacrossClause(OMPDoacrossClause *C) { + llvm::SmallVector Vars; + Vars.reserve(C->varlist_size()); + for (auto *VE : C->varlists()) { + ExprResult EVar = getDerived().TransformExpr(cast(VE)); + if (EVar.isInvalid()) + return nullptr; + Vars.push_back(EVar.get()); + } + return getDerived().RebuildOMPDoacrossClause( + C->getDependenceType(), C->getDependenceLoc(), C->getColonLoc(), Vars, + C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); +} + //===----------------------------------------------------------------------===// // Expression transformation //===----------------------------------------------------------------------===// Index: clang/lib/Serialization/ASTReader.cpp =================================================================== --- clang/lib/Serialization/ASTReader.cpp +++ clang/lib/Serialization/ASTReader.cpp @@ -10362,6 +10362,12 @@ case llvm::omp::OMPC_ompx_dyn_cgroup_mem: C = new (Context) OMPXDynCGroupMemClause(); break; + case llvm::omp::OMPC_doacross: { + unsigned NumVars = Record.readInt(); + unsigned NumLoops = Record.readInt(); + C = OMPDoacrossClause::CreateEmpty(Context, NumVars, NumLoops); + break; + } #define OMP_CLAUSE_NO_CLASS(Enum, Str) \ case llvm::omp::Enum: \ break; @@ -11438,6 +11444,22 @@ C->setLParenLoc(Record.readSourceLocation()); } +void OMPClauseReader::VisitOMPDoacrossClause(OMPDoacrossClause *C) { + C->setLParenLoc(Record.readSourceLocation()); + C->setDependenceType( + static_cast(Record.readInt())); + C->setDependenceLoc(Record.readSourceLocation()); + C->setColonLoc(Record.readSourceLocation()); + unsigned NumVars = C->varlist_size(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned I = 0; I != NumVars; ++I) + Vars.push_back(Record.readSubExpr()); + C->setVarRefs(Vars); + for (unsigned I = 0, E = C->getNumLoops(); I < E; ++I) + C->setLoopData(I, Record.readSubExpr()); +} + OMPTraitInfo *ASTRecordReader::readOMPTraitInfo() { OMPTraitInfo &TI = getContext().getNewOMPTraitInfo(); TI.Sets.resize(readUInt32()); Index: clang/lib/Serialization/ASTWriter.cpp =================================================================== --- clang/lib/Serialization/ASTWriter.cpp +++ clang/lib/Serialization/ASTWriter.cpp @@ -7155,6 +7155,19 @@ Record.AddSourceLocation(C->getLParenLoc()); } +void OMPClauseWriter::VisitOMPDoacrossClause(OMPDoacrossClause *C) { + Record.push_back(C->varlist_size()); + Record.push_back(C->getNumLoops()); + Record.AddSourceLocation(C->getLParenLoc()); + Record.push_back(C->getDependenceType()); + Record.AddSourceLocation(C->getDependenceLoc()); + Record.AddSourceLocation(C->getColonLoc()); + for (auto *VE : C->varlists()) + Record.AddStmt(VE); + for (unsigned I = 0, E = C->getNumLoops(); I < E; ++I) + Record.AddStmt(C->getLoopData(I)); +} + void ASTRecordWriter::writeOMPTraitInfo(const OMPTraitInfo *TI) { writeUInt32(TI->Sets.size()); for (const auto &Set : TI->Sets) { Index: clang/test/OpenMP/ordered_ast_print.cpp =================================================================== --- clang/test/OpenMP/ordered_ast_print.cpp +++ clang/test/OpenMP/ordered_ast_print.cpp @@ -1,10 +1,14 @@ -// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck -check-prefixes CHECK,OMP51 %s // RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s -// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck -check-prefixes CHECK,OMP51 %s -// RUN: %clang_cc1 -verify -fopenmp-simd -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp-version=52 -fopenmp -ast-print %s | FileCheck -check-prefixes CHECK,OMP52 %s +// RUN: %clang_cc1 -fopenmp -fopenmp-version=52 -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -fopenmp-version=52 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck -check-prefixes CHECK,OMP52 %s + +// RUN: %clang_cc1 -verify -fopenmp-simd -ast-print %s | FileCheck -check-prefixes CHECK,OMP51 %s // RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++11 -emit-pch -o %t %s -// RUN: %clang_cc1 -fopenmp-simd -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// RUN: %clang_cc1 -fopenmp-simd -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck -check-prefixes CHECK,OMP51 %s // expected-no-diagnostics #ifndef HEADER @@ -48,8 +52,13 @@ } #pragma omp parallel for ordered(1) for (int i =0 ; i < argc; ++i) { +#if _OPENMP >= 202111 + #pragma omp ordered doacross(source:) + #pragma omp ordered doacross(sink:i+N) +#else #pragma omp ordered depend(source) #pragma omp ordered depend(sink:i+N) +#endif a = 2; } return (0); @@ -88,8 +97,13 @@ // CHECK-NEXT: } // CHECK-NEXT: #pragma omp parallel for ordered(1) // CHECK-NEXT: for (int i = 0; i < argc; ++i) { -// CHECK-NEXT: #pragma omp ordered depend(source) -// CHECK-NEXT: #pragma omp ordered depend(sink : i + N) +#if _OPENMP >= 202111 +// OMP52: #pragma omp ordered doacross(source:) +// OMP52-NEXT: #pragma omp ordered doacross(sink: i + N) +#else +// OMP51: #pragma omp ordered depend(source) +// OMP51-NEXT: #pragma omp ordered depend(sink : i + N) +#endif // CHECK-NEXT: a = 2; // CHECK-NEXT: } // CHECK: static int a; @@ -125,8 +139,13 @@ // CHECK-NEXT: } // CHECK-NEXT: #pragma omp parallel for ordered(1) // CHECK-NEXT: for (int i = 0; i < argc; ++i) { -// CHECK-NEXT: #pragma omp ordered depend(source) -// CHECK-NEXT: #pragma omp ordered depend(sink : i + 3) +#if _OPENMP >= 202111 +// OMP52: #pragma omp ordered doacross(source:) +// OMP52-NEXT: #pragma omp ordered doacross(sink: i + 3) +#else +// OMP51: #pragma omp ordered depend(source) +// OMP51-NEXT: #pragma omp ordered depend(sink : i + 3) +#endif // CHECK-NEXT: a = 2; // CHECK-NEXT: } @@ -167,8 +186,13 @@ } #pragma omp parallel for ordered(1) for (int i =0 ; i < argc; ++i) { +#if _OPENMP >= 202111 + #pragma omp ordered doacross(source:) + #pragma omp ordered doacross(sink: i - 5) +#else #pragma omp ordered depend(source) #pragma omp ordered depend(sink: i - 5) +#endif a = 2; } // CHECK-NEXT: #pragma omp for ordered @@ -203,8 +227,13 @@ // CHECK-NEXT: } // CHECK-NEXT: #pragma omp parallel for ordered(1) // CHECK-NEXT: for (int i = 0; i < argc; ++i) { -// CHECK-NEXT: #pragma omp ordered depend(source) -// CHECK-NEXT: #pragma omp ordered depend(sink : i - 5) +#if _OPENMP >= 202111 +// OMP52: #pragma omp ordered doacross(source:) +// OMP52-NEXT: #pragma omp ordered doacross(sink: i - 5) +#else +// OMP51: #pragma omp ordered depend(source) +// OMP51-NEXT: #pragma omp ordered depend(sink : i - 5) +#endif // CHECK-NEXT: a = 2; // CHECK-NEXT: } return tmain(argc); Index: clang/test/OpenMP/ordered_messages.cpp =================================================================== --- clang/test/OpenMP/ordered_messages.cpp +++ clang/test/OpenMP/ordered_messages.cpp @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -o - %s -Wuninitialized // RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -std=c++98 -o - %s -Wuninitialized // RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -std=c++11 -o - %s -Wuninitialized +// RUN: %clang_cc1 -verify=expected,omp52 -fopenmp -fopenmp-version=52 -ferror-limit 100 -o - %s -Wuninitialized // RUN: %clang_cc1 -verify -fopenmp-simd -ferror-limit 100 -o - %s -Wuninitialized // RUN: %clang_cc1 -verify -fopenmp-simd -ferror-limit 100 -std=c++98 -o - %s -Wuninitialized @@ -135,12 +136,48 @@ } #pragma omp parallel for ordered for (int i = 0; i < 10; ++i) { +#if _OPENMP >= 202111 + #pragma omp ordered doacross(source:) // omp52-error {{'ordered' directive with 'doacross' clause cannot be closely nested inside ordered region without specified parameter}} + #pragma omp ordered doacross(sink : i) // omp52-error {{'ordered' directive with 'doacross' clause cannot be closely nested inside ordered region without specified parameter}} +#else #pragma omp ordered depend(source) // expected-error {{'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter}} #pragma omp ordered depend(sink : i) // expected-error {{'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter}} +#endif } #pragma omp parallel for ordered(2) // expected-note 3 {{'ordered' clause with specified parameter}} for (int i = 0; i < 10; ++i) { for (int j = 0; j < 10; ++j) { +#if _OPENMP >= 202111 +#pragma omp ordered doacross // omp52-error {{expected '(' after 'doacross'}} omp52-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}} +#pragma omp ordered doacross( // omp52-error {{expected ')'}} omp52-error {{expected 'source' or 'sink' in OpenMP clause 'doacross'}} omp52-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}} omp52-warning {{missing ':' or ')' after dependence-type - ignoring}} omp52-note {{to match this '('}} +#pragma omp ordered doacross(source // omp52-warning {{missing ':' or ')' after dependence-type - ignoring}} omp52-error {{expected ')'}} omp52-note {{to match this '('}} +#pragma omp ordered doacross(sink // omp52-error {{expected expression}} omp52-warning {{missing ':' or ')' after dependence-type - ignoring}} omp52-error {{expected ')'}} omp52-note {{to match this '('}} omp52-error {{expected 'i' loop iteration variable}} +#pragma omp ordered doacross(sink : // omp52-error {{expected ')'}} omp52-note {{to match this '('}} omp52-error {{expected expression}} omp52-error {{expected 'i' loop iteration variable}} +#pragma omp ordered doacross(sink : i // omp52-error {{expected ')'}} omp52-note {{to match this '('}} omp52-error {{expected 'j' loop iteration variable}} +#pragma omp ordered doacross(sink : i) // omp52-error {{expected 'j' loop iteration variable}} +#pragma omp ordered doacross(source:) + if (i == j) +#pragma omp ordered doacross(source:) // omp52-error {{'#pragma omp ordered' with 'doacross' clause cannot be an immediate substatement}} + ; + if (i == j) +#pragma omp ordered doacross(sink : i, j) // omp52-error {{'#pragma omp ordered' with 'doacross' clause cannot be an immediate substatement}} + ; +#pragma omp ordered doacross(source:) threads // omp52-error {{'doacross' clauses cannot be mixed with 'threads' clause}} +#pragma omp ordered simd doacross(source:) // omp52-error {{'doacross' clauses cannot be mixed with 'simd' clause}} +#pragma omp ordered doacross(source:) doacross(source:) // omp52-error {{directive '#pragma omp ordered' cannot contain more than one 'doacross' clause with 'source' dependence}} +#pragma omp ordered doacross(in : i) // omp52-error {{expected 'source' or 'sink' in OpenMP clause 'doacross'}} omp52-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}} +#pragma omp ordered doacross(sink : i, j) +#pragma omp ordered doacross(sink : j, i) // omp52-error {{expected 'i' loop iteration variable}} omp52-error {{expected 'j' loop iteration variable}} +#pragma omp ordered doacross(sink : i, j, k) // omp52-error {{unexpected expression: number of expressions is larger than the number of associated loops}} +#pragma omp ordered doacross(sink : i+foo(), j/4) // omp52-error {{integral constant expression}} omp52-error {{expected '+' or '-' operation}} +#if __cplusplus >= 201103L +// omp52-note@-2 {{non-constexpr function 'foo' cannot be used in a constant expression}} +#endif +#pragma omp ordered doacross(sink : i*0, j-4)// omp52-error {{expected '+' or '-' operation}} +#pragma omp ordered doacross(sink : i-0, j+sizeof(T)) doacross(sink : i-0, j+sizeof(T)) +#pragma omp ordered doacross(sink : i-0, j+sizeof(T)) doacross(source:) // omp52-error {{'doacross(source)' clause cannot be mixed with 'doacross(sink:vec)' clauses}} +#pragma omp ordered doacross(source:) doacross(sink : i-0, j+sizeof(T)) // omp52-error {{'doacross(sink:vec)' clauses cannot be mixed with 'doacross(source)' clause}} +#else #pragma omp ordered depend // expected-error {{expected '(' after 'depend'}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}} #pragma omp ordered depend( // expected-error {{expected ')'}} expected-error {{expected 'source' or 'sink' in OpenMP clause 'depend'}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}} expected-warning {{missing ':' or ')' after dependency type - ignoring}} expected-note {{to match this '('}} #pragma omp ordered depend(source // expected-error {{expected ')'}} expected-note {{to match this '('}} @@ -170,10 +207,14 @@ #pragma omp ordered depend(sink : i-0, j+sizeof(T)) depend(sink : i-0, j+sizeof(T)) #pragma omp ordered depend(sink : i-0, j+sizeof(T)) depend(source) // expected-error {{'depend(source)' clause cannot be mixed with 'depend(sink:vec)' clauses}} #pragma omp ordered depend(source) depend(sink : i-0, j+sizeof(T)) // expected-error {{'depend(sink:vec)' clauses cannot be mixed with 'depend(source)' clause}} +#endif } } +#if _OPENMP >= 202111 +#else #pragma omp ordered depend(source) // expected-error {{'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter}} #pragma omp ordered depend(sink:k) // expected-error {{'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter}} +#endif return T(); } @@ -272,12 +313,46 @@ } #pragma omp parallel for ordered for (int i = 0; i < 10; ++i) { +#if _OPENMP >= 202111 +#else #pragma omp ordered depend(source) // expected-error {{'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter}} #pragma omp ordered depend(sink : i) // expected-error {{'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter}} +#endif } #pragma omp parallel for ordered(2) // expected-note 3 {{'ordered' clause with specified parameter}} for (int i = 0; i < 10; ++i) { for (int j = 0; j < 10; ++j) { +#if _OPENMP >= 202111 +#pragma omp ordered doacross // omp52-error {{expected '(' after 'doacross'}} omp52-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}} +#pragma omp ordered doacross( // omp52-error {{expected ')'}} omp52-error {{expected 'source' or 'sink' in OpenMP clause 'doacross'}} omp52-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}} omp52-warning {{missing ':' or ')' after dependence-type - ignoring}} omp52-note {{to match this '('}} +#pragma omp ordered doacross(source // omp52-warning {{missing ':' or ')' after dependence-type - ignoring}} omp52-error {{expected ')'}} omp52-note {{to match this '('}} +#pragma omp ordered doacross(sink // omp52-error {{expected expression}} omp52-warning {{missing ':' or ')' after dependence-type - ignoring}} omp52-error {{expected ')'}} omp52-note {{to match this '('}} omp52-error {{expected 'i' loop iteration variable}} +#pragma omp ordered doacross(sink : // omp52-error {{expected ')'}} omp52-note {{to match this '('}} omp52-error {{expected expression}} omp52-error {{expected 'i' loop iteration variable}} +#pragma omp ordered doacross(sink : i // omp52-error {{expected ')'}} omp52-note {{to match this '('}} omp52-error {{expected 'j' loop iteration variable}} +#pragma omp ordered doacross(sink : i) // omp52-error {{expected 'j' loop iteration variable}} +#pragma omp ordered doacross(source:) + if (i == j) +#pragma omp ordered doacross(source:) // omp52-error {{'#pragma omp ordered' with 'doacross' clause cannot be an immediate substatement}} + ; + if (i == j) +#pragma omp ordered doacross(sink : i, j) // omp52-error {{'#pragma omp ordered' with 'doacross' clause cannot be an immediate substatement}} + ; +#pragma omp ordered doacross(source:) threads // omp52-error {{'doacross' clauses cannot be mixed with 'threads' clause}} +#pragma omp ordered simd doacross(source:) // omp52-error {{'doacross' clauses cannot be mixed with 'simd' clause}} +#pragma omp ordered doacross(source:) doacross(source:) // omp52-error {{directive '#pragma omp ordered' cannot contain more than one 'doacross' clause with 'source' dependence}} +#pragma omp ordered doacross(in : i) // omp52-error {{expected 'source' or 'sink' in OpenMP clause 'doacross'}} omp52-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}} +#pragma omp ordered doacross(sink : i, j) allocate(i) // omp52-error {{unexpected OpenMP clause 'allocate' in directive '#pragma omp ordered'}} +#pragma omp ordered doacross(sink : j, i) // omp52-error {{expected 'i' loop iteration variable}} omp52-error {{expected 'j' loop iteration variable}} +#pragma omp ordered doacross(sink : i, j, k) // omp52-error {{unexpected expression: number of expressions is larger than the number of associated loops}} +#pragma omp ordered doacross(sink : i+foo(), j/4) // omp52-error {{integral constant expression}} omp52-error {{expected '+' or '-' operation}} +#if __cplusplus >= 201103L +// omp52-note@-2 {{non-constexpr function 'foo' cannot be used in a constant expression}} +#endif +#pragma omp ordered doacross(sink : i*0, j-4)// omp52-error {{expected '+' or '-' operation}} +#pragma omp ordered doacross(sink : i-0, j+sizeof(int)) doacross(sink : i-0, j+sizeof(int)) +#pragma omp ordered doacross(sink : i-0, j+sizeof(int)) doacross(source:) // omp52-error {{'doacross(source)' clause cannot be mixed with 'doacross(sink:vec)' clauses}} +#pragma omp ordered doacross(source:) doacross(sink : i-0, j+sizeof(int)) // omp52-error {{'doacross(sink:vec)' clauses cannot be mixed with 'doacross(source)' clause}} +#else #pragma omp ordered depend // expected-error {{expected '(' after 'depend'}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}} #pragma omp ordered depend( // expected-error {{expected ')'}} expected-error {{expected 'source' or 'sink' in OpenMP clause 'depend'}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}} expected-warning {{missing ':' or ')' after dependency type - ignoring}} expected-note {{to match this '('}} #pragma omp ordered depend(source // expected-error {{expected ')'}} expected-note {{to match this '('}} @@ -307,14 +382,21 @@ #pragma omp ordered depend(sink : i-0, j+sizeof(int)) depend(sink : i-0, j+sizeof(int)) #pragma omp ordered depend(sink : i-0, j+sizeof(int)) depend(source) // expected-error {{'depend(source)' clause cannot be mixed with 'depend(sink:vec)' clauses}} #pragma omp ordered depend(source) depend(sink : i-0, j+sizeof(int)) // expected-error {{'depend(sink:vec)' clauses cannot be mixed with 'depend(source)' clause}} +#endif } } #pragma omp for ordered(2) // expected-note {{as specified in 'ordered' clause}} for (int i = 0; i < 10; ++i) { // expected-error {{expected 2 for loops after '#pragma omp for', but found only 1}} +#if _OPENMP >= 202111 +#pragma omp ordered doacross(sink : i) + int j; +#pragma omp ordered doacross(sink : i, j) // omp52-error {{expected loop iteration variable}} +#else #pragma omp ordered depend(sink : i) int j; #pragma omp ordered depend(sink : i, j) // expected-error {{expected loop iteration variable}} +#endif foo(); } Index: clang/tools/libclang/CIndex.cpp =================================================================== --- clang/tools/libclang/CIndex.cpp +++ clang/tools/libclang/CIndex.cpp @@ -2717,6 +2717,9 @@ VisitOMPClauseWithPreInit(C); Visitor->AddStmt(C->getSize()); } +void OMPClauseEnqueue::VisitOMPDoacrossClause(const OMPDoacrossClause *C) { + VisitOMPClauseList(C); +} } // namespace Index: flang/lib/Semantics/check-omp-structure.cpp =================================================================== --- flang/lib/Semantics/check-omp-structure.cpp +++ flang/lib/Semantics/check-omp-structure.cpp @@ -1937,6 +1937,7 @@ CHECK_SIMPLE_CLAUSE(Align, OMPC_align) CHECK_SIMPLE_CLAUSE(Compare, OMPC_compare) CHECK_SIMPLE_CLAUSE(CancellationConstructType, OMPC_cancellation_construct_type) +CHECK_SIMPLE_CLAUSE(Doacross, OMPC_doacross) CHECK_REQ_SCALAR_INT_CLAUSE(Grainsize, OMPC_grainsize) CHECK_REQ_SCALAR_INT_CLAUSE(NumTasks, OMPC_num_tasks) Index: llvm/include/llvm/Frontend/OpenMP/OMP.td =================================================================== --- llvm/include/llvm/Frontend/OpenMP/OMP.td +++ llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -444,6 +444,10 @@ let flangClass = "ScalarIntExpr"; } +def OMPC_Doacross : Clause<"doacross"> { + let clangClass = "OMPDoacrossClause"; +} + //===----------------------------------------------------------------------===// // Definition of OpenMP directives //===----------------------------------------------------------------------===// @@ -604,7 +608,8 @@ } def OMP_Ordered : Directive<"ordered"> { let allowedClauses = [ - VersionedClause + VersionedClause, + VersionedClause ]; let allowedOnceClauses = [ VersionedClause,