From 085845a2acbefd26d5c229338225dfd76e2c2df3 Mon Sep 17 00:00:00 2001 From: Jennifer Yu Date: Wed, 21 Jun 2023 16:26:35 -0700 Subject: [PATCH] [OMP5.2] Initial support for doacross clause. --- clang/include/clang/AST/OpenMPClause.h | 126 ++++ clang/include/clang/AST/RecursiveASTVisitor.h | 7 + .../clang/Basic/DiagnosticSemaKinds.td | 8 +- clang/include/clang/Basic/OpenMPKinds.def | 8 + clang/include/clang/Basic/OpenMPKinds.h | 7 + clang/include/clang/Sema/Sema.h | 17 +- clang/lib/AST/OpenMPClause.cpp | 54 ++ clang/lib/AST/StmtProfile.cpp | 3 + clang/lib/Basic/OpenMPKinds.cpp | 15 + clang/lib/Parse/ParseOpenMP.cpp | 48 +- clang/lib/Sema/SemaOpenMP.cpp | 554 +++++++++++------- clang/lib/Sema/TreeTransform.h | 29 + clang/lib/Serialization/ASTReader.cpp | 22 + clang/lib/Serialization/ASTWriter.cpp | 13 + clang/test/OpenMP/ordered_ast_print.cpp | 49 +- clang/test/OpenMP/ordered_messages.cpp | 82 +++ clang/tools/libclang/CIndex.cpp | 3 + flang/lib/Semantics/check-omp-structure.cpp | 1 + llvm/include/llvm/Frontend/OpenMP/OMP.td | 7 +- 19 files changed, 798 insertions(+), 255 deletions(-) diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h index 627e9025c112..0bea21270692 100644 --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -9046,6 +9046,132 @@ public: 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 diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 751249b57f9f..95b04fe3dd59 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -3864,6 +3864,13 @@ bool RecursiveASTVisitor::VisitOMPXDynCGroupMemClause( 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 diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index c2b8bd4ce9cd..edfa30abf594 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10868,7 +10868,7 @@ def note_omp_previous_named_if_clause : Note< 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< @@ -10900,7 +10900,7 @@ def note_omp_critical_hint_here : Note< 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< @@ -10909,8 +10909,8 @@ def err_omp_depend_sink_expected_plus_minus : Error< "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< diff --git a/clang/include/clang/Basic/OpenMPKinds.def b/clang/include/clang/Basic/OpenMPKinds.def index 64c488caa6a9..eb5037c629db 100644 --- a/clang/include/clang/Basic/OpenMPKinds.def +++ b/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 @@ OPENMP_GRAINSIZE_MODIFIER(strict) // 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 @@ OPENMP_NUMTASKS_MODIFIER(strict) #undef OPENMP_DIST_SCHEDULE_KIND #undef OPENMP_DEFAULTMAP_KIND #undef OPENMP_DEFAULTMAP_MODIFIER +#undef OPENMP_DOACROSS_MODIFIER diff --git a/clang/include/clang/Basic/OpenMPKinds.h b/clang/include/clang/Basic/OpenMPKinds.h index 6491ee27782c..f5fc7a8ce5bb 100644 --- a/clang/include/clang/Basic/OpenMPKinds.h +++ b/clang/include/clang/Basic/OpenMPKinds.h @@ -215,6 +215,13 @@ enum OpenMPNumTasksClauseModifier { 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 { diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 55d1dcf6ee0c..4bf05b33bfb3 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11032,10 +11032,7 @@ private: /// 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 @@ public: 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 @@ public: 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. diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index 2e88c08ae789..4fc63093a871 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -1669,6 +1669,52 @@ OMPBindClause::Create(const ASTContext &C, OpenMPBindClauseKind K, 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 @@ void OMPClausePrinter::VisitOMPXDynCGroupMemClause( 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) { diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 4d49f053e1f9..a9c4e14e87ef 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -920,6 +920,9 @@ void OMPClauseProfiler::VisitOMPXDynCGroupMemClause( if (Expr *Size = C->getSize()) Profiler->VisitStmt(Size); } +void OMPClauseProfiler::VisitOMPDoacrossClause(const OMPDoacrossClause *C) { + VisitOMPClauseList(C); +} } // namespace void diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index 36bce7e44afb..48c9c2189a93 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -50,6 +50,11 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, StringRef Str, 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 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, #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: diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 8c57dc9e071f..8c4cf306bde2 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -2924,17 +2924,20 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( // 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 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, 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 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, 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 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, 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 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, } 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 Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, 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 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, // 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; } diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index e22425b208cc..2d7d6cf81732 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -88,8 +88,7 @@ public: }; 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 @@ private: /// 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 @@ public: 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 @@ static bool checkOpenMPIterationSpace( } } 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 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef Clauses, 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 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef Clauses, 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 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef Clauses, 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 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef Clauses, // 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 @@ OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind, 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,6 +20563,135 @@ OMPClause *Sema::ActOnOpenMPDepobjClause(Expr *Depobj, SourceLocation StartLoc, return OMPDepobjClause::Create(Context, StartLoc, LParenLoc, EndLoc, Depobj); } +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 (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 doacross clause."); + if (isa(RefExpr)) { + // It will be analyzed later. + Vars.push_back(RefExpr); + continue; + } + + SourceLocation ELoc = RefExpr->getExprLoc(); + Expr *SimpleExpr = RefExpr->IgnoreParenCasts(); + if (!IsSource) { + if (Stack->getParentOrderedRegionParam().first && + DepCounter >= TotalDepCount) { + SemaRef.Diag(ELoc, diag::err_omp_depend_sink_unexpected_expr); + continue; + } + ++DepCounter; + // OpenMP [2.13.9, Summary] + // depend(dependence-type : vec), where dependence-type is: + // 'sink' and where vec is the iteration vector, which has the form: + // x1 [+- d1], x2 [+- d2 ], . . . , xn [+- dn] + // where n is the value specified by the ordered clause in the loop + // directive, xi denotes the loop iteration variable of the i-th nested + // loop associated with the loop directive, and di is a constant + // non-negative integer. + if (SemaRef.CurContext->isDependentContext()) { + // It will be analyzed later. + Vars.push_back(RefExpr); + continue; + } + SimpleExpr = SimpleExpr->IgnoreImplicit(); + OverloadedOperatorKind OOK = OO_None; + SourceLocation OOLoc; + Expr *LHS = SimpleExpr; + Expr *RHS = nullptr; + if (auto *BO = dyn_cast(SimpleExpr)) { + OOK = BinaryOperator::getOverloadedOperator(BO->getOpcode()); + OOLoc = BO->getOperatorLoc(); + LHS = BO->getLHS()->IgnoreParenImpCasts(); + RHS = BO->getRHS()->IgnoreParenImpCasts(); + } else if (auto *OCE = dyn_cast(SimpleExpr)) { + OOK = OCE->getOperator(); + OOLoc = OCE->getOperatorLoc(); + LHS = OCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts(); + RHS = OCE->getArg(/*Arg=*/1)->IgnoreParenImpCasts(); + } else if (auto *MCE = dyn_cast(SimpleExpr)) { + OOK = MCE->getMethodDecl() + ->getNameInfo() + .getName() + .getCXXOverloadedOperator(); + OOLoc = MCE->getCallee()->getExprLoc(); + LHS = MCE->getImplicitObjectArgument()->IgnoreParenImpCasts(); + RHS = MCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts(); + } + SourceLocation ELoc; + SourceRange ERange; + auto Res = getPrivateItem(SemaRef, LHS, ELoc, ERange); + if (Res.second) { + // It will be analyzed later. + Vars.push_back(RefExpr); + } + ValueDecl *D = Res.first; + if (!D) + continue; + + if (OOK != OO_Plus && OOK != OO_Minus && (RHS || OOK != OO_None)) { + SemaRef.Diag(OOLoc, diag::err_omp_depend_sink_expected_plus_minus); + continue; + } + if (RHS) { + ExprResult RHSRes = SemaRef.VerifyPositiveIntegerConstantInClause( + RHS, OMPC_depend, /*StrictlyPositive=*/false); + if (RHSRes.isInvalid()) + continue; + } + if (!SemaRef.CurContext->isDependentContext() && + Stack->getParentOrderedRegionParam().first && + DepCounter != Stack->isParentLoopControlVariable(D).first) { + const ValueDecl *VD = + Stack->getParentLoopControlVariable(DepCounter.getZExtValue()); + if (VD) + SemaRef.Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration) + << 1 << VD; + else + SemaRef.Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration) + << 0; + continue; + } + OpsOffs.emplace_back(RHS, OOK); + } + 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, @@ -20579,204 +20746,123 @@ Sema::ActOnOpenMPDependClause(const OMPDependClause::DependDataTy &Data, 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); - } - } - 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) { - if (DSAStack->getParentOrderedRegionParam().first && - DepCounter >= TotalDepCount) { - Diag(ELoc, diag::err_omp_depend_sink_unexpected_expr); - continue; - } - ++DepCounter; - // OpenMP [2.13.9, Summary] - // depend(dependence-type : vec), where dependence-type is: - // 'sink' and where vec is the iteration vector, which has the form: - // x1 [+- d1], x2 [+- d2 ], . . . , xn [+- dn] - // where n is the value specified by the ordered clause in the loop - // directive, xi denotes the loop iteration variable of the i-th nested - // loop associated with the loop directive, and di is a constant - // non-negative integer. - if (CurContext->isDependentContext()) { + 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; } - SimpleExpr = SimpleExpr->IgnoreImplicit(); - OverloadedOperatorKind OOK = OO_None; - SourceLocation OOLoc; - Expr *LHS = SimpleExpr; - Expr *RHS = nullptr; - if (auto *BO = dyn_cast(SimpleExpr)) { - OOK = BinaryOperator::getOverloadedOperator(BO->getOpcode()); - OOLoc = BO->getOperatorLoc(); - LHS = BO->getLHS()->IgnoreParenImpCasts(); - RHS = BO->getRHS()->IgnoreParenImpCasts(); - } else if (auto *OCE = dyn_cast(SimpleExpr)) { - OOK = OCE->getOperator(); - OOLoc = OCE->getOperatorLoc(); - LHS = OCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts(); - RHS = OCE->getArg(/*Arg=*/1)->IgnoreParenImpCasts(); - } else if (auto *MCE = dyn_cast(SimpleExpr)) { - OOK = MCE->getMethodDecl() - ->getNameInfo() - .getName() - .getCXXOverloadedOperator(); - OOLoc = MCE->getCallee()->getExprLoc(); - LHS = MCE->getImplicitObjectArgument()->IgnoreParenImpCasts(); - RHS = MCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts(); - } - SourceLocation ELoc; - SourceRange ERange; - auto Res = getPrivateItem(*this, LHS, ELoc, ERange); - if (Res.second) { - // It will be analyzed later. - Vars.push_back(RefExpr); - } - ValueDecl *D = Res.first; - if (!D) - continue; - if (OOK != OO_Plus && OOK != OO_Minus && (RHS || OOK != OO_None)) { - Diag(OOLoc, diag::err_omp_depend_sink_expected_plus_minus); - continue; - } - if (RHS) { - ExprResult RHSRes = VerifyPositiveIntegerConstantInClause( - RHS, OMPC_depend, /*StrictlyPositive=*/false); - if (RHSRes.isInvalid()) - continue; - } - if (!CurContext->isDependentContext() && - DSAStack->getParentOrderedRegionParam().first && - DepCounter != DSAStack->isParentLoopControlVariable(D).first) { - const ValueDecl *VD = - DSAStack->getParentLoopControlVariable(DepCounter.getZExtValue()); - if (VD) - Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration) - << 1 << VD; - else - Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration) << 0; - continue; - } - OpsOffs.emplace_back(RHS, OOK); - } else { - 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(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().isZero()) { - Diag(ELoc, - diag::err_omp_depend_zero_length_array_section_not_allowed) - << SimpleExpr->getSourceRange(); + 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, + 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(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().isZero()) { + Diag(ELoc, + diag::err_omp_depend_zero_length_array_section_not_allowed) + << SimpleExpr->getSourceRange(); + continue; + } + } + + // OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++ + // List items used in depend clauses with the in, out, inout, + // inoutset, or mutexinoutset dependence types cannot be + // expressions of the omp_depend_t type. + if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() && + !RefExpr->isInstantiationDependent() && + !RefExpr->containsUnexpandedParameterPack() && + (!RefExpr->IgnoreParenImpCasts()->isLValue() || + (OMPDependTFound && DSAStack->getOMPDependT().getTypePtr() == + ExprTy.getTypePtr()))) { + Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) + << (LangOpts.OpenMP >= 50 ? 1 : 0) + << (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange(); + continue; + } + + auto *ASE = dyn_cast(SimpleExpr); + if (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(SimpleExpr) && + !isa(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; } } - - // OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++ - // List items used in depend clauses with the in, out, inout, - // inoutset, or mutexinoutset dependence types cannot be - // expressions of the omp_depend_t type. - if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() && - !RefExpr->isInstantiationDependent() && - !RefExpr->containsUnexpandedParameterPack() && - (!RefExpr->IgnoreParenImpCasts()->isLValue() || - (OMPDependTFound && - DSAStack->getOMPDependT().getTypePtr() == ExprTy.getTypePtr()))) { - Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) - << (LangOpts.OpenMP >= 50 ? 1 : 0) - << (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange(); - continue; - } - - auto *ASE = dyn_cast(SimpleExpr); - if (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(SimpleExpr) && - !isa(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()); } - 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 +24033,31 @@ OMPClause *Sema::ActOnOpenMPXDynCGroupMemClause(Expr *Size, 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; +} diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index f0401f080dd9..10b3587885e3 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2422,6 +2422,19 @@ public: 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 @@ OMPClause *TreeTransform::TransformOMPXDynCGroupMemClause( 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 //===----------------------------------------------------------------------===// diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index cba6791783e8..a9f25ec2ecb7 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -10362,6 +10362,12 @@ OMPClause *OMPClauseReader::readClause() { 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 @@ void OMPClauseReader::VisitOMPXDynCGroupMemClause(OMPXDynCGroupMemClause *C) { 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()); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index ff5bab7c99f7..ca0db085d94c 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -7155,6 +7155,19 @@ void OMPClauseWriter::VisitOMPXDynCGroupMemClause(OMPXDynCGroupMemClause *C) { 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) { diff --git a/clang/test/OpenMP/ordered_ast_print.cpp b/clang/test/OpenMP/ordered_ast_print.cpp index f36afab8b207..298d52132e97 100644 --- a/clang/test/OpenMP/ordered_ast_print.cpp +++ b/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 @@ T tmain (T argc) { } #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 @@ T tmain (T argc) { // 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 @@ T tmain (T argc) { // 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 @@ int main (int argc, char **argv) { } #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 @@ int main (int argc, char **argv) { // 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); diff --git a/clang/test/OpenMP/ordered_messages.cpp b/clang/test/OpenMP/ordered_messages.cpp index 8a3a86443eb8..3711693688c5 100644 --- a/clang/test/OpenMP/ordered_messages.cpp +++ b/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 @@ T foo() { } #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 @@ T foo() { #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 @@ int k; } #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 @@ int k; #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(); } diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 25118c702f1b..fb6cc96cac55 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -2717,6 +2717,9 @@ void OMPClauseEnqueue::VisitOMPXDynCGroupMemClause( VisitOMPClauseWithPreInit(C); Visitor->AddStmt(C->getSize()); } +void OMPClauseEnqueue::VisitOMPDoacrossClause(const OMPDoacrossClause *C) { + VisitOMPClauseList(C); +} } // namespace diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index eb8de20a6b8b..c84ad3ffcbbd 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -1937,6 +1937,7 @@ CHECK_SIMPLE_CLAUSE(Bind, OMPC_bind) 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) diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td index 0f8a9d58acc4..c67b54acc47c 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMP.td +++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -444,6 +444,10 @@ def OMPC_OMPX_DynCGroupMem : Clause<"ompx_dyn_cgroup_mem"> { let flangClass = "ScalarIntExpr"; } +def OMPC_Doacross : Clause<"doacross"> { + let clangClass = "OMPDoacrossClause"; +} + //===----------------------------------------------------------------------===// // Definition of OpenMP directives //===----------------------------------------------------------------------===// @@ -604,7 +608,8 @@ def OMP_Flush : Directive<"flush"> { } def OMP_Ordered : Directive<"ordered"> { let allowedClauses = [ - VersionedClause + VersionedClause, + VersionedClause ]; let allowedOnceClauses = [ VersionedClause,