[flang-commits] [flang] 085845a - [OMP5.2] Initial support for doacross clause.
Jennifer Yu via flang-commits
flang-commits at lists.llvm.org
Thu Jun 29 12:07:38 PDT 2023
Author: Jennifer Yu
Date: 2023-06-29T11:58:17-07:00
New Revision: 085845a2acbefd26d5c229338225dfd76e2c2df3
URL: https://github.com/llvm/llvm-project/commit/085845a2acbefd26d5c229338225dfd76e2c2df3
DIFF: https://github.com/llvm/llvm-project/commit/085845a2acbefd26d5c229338225dfd76e2c2df3.diff
LOG: [OMP5.2] Initial support for doacross clause.
Added:
Modified:
clang/include/clang/AST/OpenMPClause.h
clang/include/clang/AST/RecursiveASTVisitor.h
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Basic/OpenMPKinds.def
clang/include/clang/Basic/OpenMPKinds.h
clang/include/clang/Sema/Sema.h
clang/lib/AST/OpenMPClause.cpp
clang/lib/AST/StmtProfile.cpp
clang/lib/Basic/OpenMPKinds.cpp
clang/lib/Parse/ParseOpenMP.cpp
clang/lib/Sema/SemaOpenMP.cpp
clang/lib/Sema/TreeTransform.h
clang/lib/Serialization/ASTReader.cpp
clang/lib/Serialization/ASTWriter.cpp
clang/test/OpenMP/ordered_ast_print.cpp
clang/test/OpenMP/ordered_messages.cpp
clang/tools/libclang/CIndex.cpp
flang/lib/Semantics/check-omp-structure.cpp
llvm/include/llvm/Frontend/OpenMP/OMP.td
Removed:
################################################################################
diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h
index 627e9025c11289..0bea21270692cf 100644
--- a/clang/include/clang/AST/OpenMPClause.h
+++ b/clang/include/clang/AST/OpenMPClause.h
@@ -9046,6 +9046,132 @@ class OMPXDynCGroupMemClause
Expr *getSize() const { return getStmtAs<Expr>(); }
};
+/// 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<OMPDoacrossClause>,
+ private llvm::TrailingObjects<OMPDoacrossClause, Expr *> {
+ 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<OMPDoacrossClause>(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<OMPDoacrossClause>(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<Expr *> 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<Stmt **>(varlist_begin()),
+ reinterpret_cast<Stmt **>(varlist_end()));
+ }
+
+ const_child_range children() const {
+ auto Children = const_cast<OMPDoacrossClause *>(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 751249b57f9f1c..95b04fe3dd59b6 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -3864,6 +3864,13 @@ bool RecursiveASTVisitor<Derived>::VisitOMPXDynCGroupMemClause(
return true;
}
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::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 c2b8bd4ce9cd96..edfa30abf594a2 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 64c488caa6a9f4..eb5037c629dbf7 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 6491ee27782cbd..f5fc7a8ce5bb3c 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 55d1dcf6ee0c26..4bf05b33bfb3ec 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11032,10 +11032,7 @@ class Sema final {
/// 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 @@ class Sema final {
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 @@ class Sema final {
SourceLocation LParenLoc,
SourceLocation EndLoc);
+ /// Called on well-formed 'doacross' clause.
+ OMPClause *
+ ActOnOpenMPDoacrossClause(OpenMPDoacrossClauseModifier DepType,
+ SourceLocation DepLoc, SourceLocation ColonLoc,
+ ArrayRef<Expr *> 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 2e88c08ae78986..4fc63093a87133 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<Expr *> VL, unsigned NumLoops) {
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(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<Expr *>(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 4d49f053e1f9ed..a9c4e14e87eff3 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 36bce7e44afbe5..48c9c2189a938a 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<OpenMPDoacrossClauseModifier>(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<OpenMPLinearClauseKind>(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 8c57dc9e071f95..8c4cf306bde2c4 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 e22425b208ccf6..2d7d6cf81732a9 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -88,8 +88,7 @@ class DSAStackTy {
};
using OperatorOffsetTy =
llvm::SmallVector<std::pair<Expr *, OverloadedOperatorKind>, 4>;
- using DoacrossDependMapTy =
- llvm::DenseMap<OMPDependClause *, OperatorOffsetTy>;
+ using DoacrossClauseMapTy = llvm::DenseMap<OMPClause *, OperatorOffsetTy>;
/// Kind of the declaration used in the uses_allocators clauses.
enum class UsesAllocatorsDeclKind {
/// Predefined allocator
@@ -170,7 +169,7 @@ class DSAStackTy {
/// 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 @@ class DSAStackTy {
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<DoacrossDependMapTy::const_iterator>
+ llvm::iterator_range<DoacrossClauseMapTy::const_iterator>
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<OMPDependClause>(Pair.first);
+ auto *DoacrossC = dyn_cast<OMPDoacrossClause>(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<OMPClause *> 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<OMPDependClause>(C)) {
- DependFound = C;
- if (DC->getDependencyKind() == OMPC_DEPEND_source) {
- if (DependSourceClause) {
+ auto DOC = dyn_cast<OMPDoacrossClause>(C);
+ auto DC = dyn_cast<OMPDependClause>(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<OMPThreadsClause>(C);
@@ -11316,13 +11343,19 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> 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<OMPClause *> 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<OMPClause *> 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<OpenMPDoacrossClauseModifier>(ExtraModifier),
+ ExtraModifierLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc);
+ break;
case OMPC_if:
case OMPC_depobj:
case OMPC_final:
@@ -20525,71 +20563,35 @@ OMPClause *Sema::ActOnOpenMPDepobjClause(Expr *Depobj, SourceLocation StartLoc,
return OMPDepobjClause::Create(Context, StartLoc, LParenLoc, EndLoc, Depobj);
}
-OMPClause *
-Sema::ActOnOpenMPDependClause(const OMPDependClause::DependDataTy &Data,
- Expr *DepModifier, ArrayRef<Expr *> 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<unsigned, 6> 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<Expr *, 8> 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<Expr *> VarList, DSAStackTy *Stack,
+ SourceLocation EndLoc) {
SmallVector<Expr *, 8> 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<DependentScopeDeclRefExpr>(RefExpr)) {
// It will be analyzed later.
Vars.push_back(RefExpr);
@@ -20598,10 +20600,10 @@ Sema::ActOnOpenMPDependClause(const OMPDependClause::DependDataTy &Data,
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 @@ Sema::ActOnOpenMPDependClause(const OMPDependClause::DependDataTy &Data,
// 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 @@ Sema::ActOnOpenMPDependClause(const OMPDependClause::DependDataTy &Data,
}
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,129 +20656,213 @@ Sema::ActOnOpenMPDependClause(const OMPDependClause::DependDataTy &Data,
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 {
- bool OMPDependTFound = LangOpts.OpenMP >= 50;
- if (OMPDependTFound)
- OMPDependTFound = findOMPDependT(*this, StartLoc, DSAStack,
- DepKind == OMPC_DEPEND_depobj);
- if (DepKind == OMPC_DEPEND_depobj) {
- // OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++
- // List items used in depend clauses with the depobj dependence type
- // must be expressions of the omp_depend_t type.
- if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() &&
- !RefExpr->isInstantiationDependent() &&
- !RefExpr->containsUnexpandedParameterPack() &&
- (OMPDependTFound &&
- !Context.hasSameUnqualifiedType(DSAStack->getOMPDependT(),
- RefExpr->getType()))) {
- Diag(ELoc, diag::err_omp_expected_omp_depend_t_lvalue)
- << 0 << RefExpr->getType() << RefExpr->getSourceRange();
- continue;
- }
- if (!RefExpr->isLValue()) {
- Diag(ELoc, diag::err_omp_expected_omp_depend_t_lvalue)
- << 1 << RefExpr->getType() << RefExpr->getSourceRange();
- continue;
- }
- } else {
- // OpenMP 5.0 [2.17.11, Restrictions]
- // List items used in depend clauses cannot be zero-length array
- // sections.
- QualType ExprTy = RefExpr->getType().getNonReferenceType();
- const auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr);
- if (OASE) {
- QualType BaseType =
- OMPArraySectionExpr::getBaseOriginalType(OASE->getBase());
- if (const auto *ATy = BaseType->getAsArrayTypeUnsafe())
- ExprTy = ATy->getElementType();
- else
- ExprTy = BaseType->getPointeeType();
- ExprTy = ExprTy.getNonReferenceType();
- const Expr *Length = OASE->getLength();
- Expr::EvalResult Result;
- if (Length && !Length->isValueDependent() &&
- Length->EvaluateAsInt(Result, Context) &&
- Result.Val.getInt().isZero()) {
- Diag(ELoc,
- diag::err_omp_depend_zero_length_array_section_not_allowed)
- << SimpleExpr->getSourceRange();
+ }
+ 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<Expr *> 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<unsigned, 6> 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<Expr *, 8> 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<DependentScopeDeclRefExpr>(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,
+ DepKind == OMPC_DEPEND_depobj);
+ if (DepKind == OMPC_DEPEND_depobj) {
+ // OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++
+ // List items used in depend clauses with the depobj dependence type
+ // must be expressions of the omp_depend_t type.
+ if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() &&
+ !RefExpr->isInstantiationDependent() &&
+ !RefExpr->containsUnexpandedParameterPack() &&
+ (OMPDependTFound &&
+ !Context.hasSameUnqualifiedType(DSAStack->getOMPDependT(),
+ RefExpr->getType()))) {
+ Diag(ELoc, diag::err_omp_expected_omp_depend_t_lvalue)
+ << 0 << RefExpr->getType() << RefExpr->getSourceRange();
continue;
}
- }
+ if (!RefExpr->isLValue()) {
+ Diag(ELoc, diag::err_omp_expected_omp_depend_t_lvalue)
+ << 1 << RefExpr->getType() << RefExpr->getSourceRange();
+ continue;
+ }
+ } else {
+ // OpenMP 5.0 [2.17.11, Restrictions]
+ // List items used in depend clauses cannot be zero-length array
+ // sections.
+ QualType ExprTy = RefExpr->getType().getNonReferenceType();
+ const auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr);
+ if (OASE) {
+ QualType BaseType =
+ OMPArraySectionExpr::getBaseOriginalType(OASE->getBase());
+ if (const auto *ATy = BaseType->getAsArrayTypeUnsafe())
+ ExprTy = ATy->getElementType();
+ else
+ ExprTy = BaseType->getPointeeType();
+ ExprTy = ExprTy.getNonReferenceType();
+ const Expr *Length = OASE->getLength();
+ Expr::EvalResult Result;
+ if (Length && !Length->isValueDependent() &&
+ Length->EvaluateAsInt(Result, Context) &&
+ Result.Val.getInt().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;
- }
+ // 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<ArraySubscriptExpr>(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;
- }
+ auto *ASE = dyn_cast<ArraySubscriptExpr>(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<OMPArraySectionExpr>(SimpleExpr) &&
- !isa<OMPArrayShapingExpr>(SimpleExpr)) {
- Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
- << (LangOpts.OpenMP >= 50 ? 1 : 0)
- << (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange();
- continue;
+ ExprResult Res;
+ {
+ Sema::TentativeAnalysisScope Trap(*this);
+ Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf,
+ RefExpr->IgnoreParenImpCasts());
+ }
+ if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr) &&
+ !isa<OMPArrayShapingExpr>(SimpleExpr)) {
+ Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
+ << (LangOpts.OpenMP >= 50 ? 1 : 0)
+ << (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange();
+ continue;
+ }
}
}
+ Vars.push_back(RefExpr->IgnoreParenImpCasts());
}
- 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<Expr *> 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<Expr *, 8> 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 f0401f080dd9f8..10b3587885e39f 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -2422,6 +2422,19 @@ class TreeTransform {
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
diff erent behavior.
+ OMPClause *
+ RebuildOMPDoacrossClause(OpenMPDoacrossClauseModifier DepType,
+ SourceLocation DepLoc, SourceLocation ColonLoc,
+ ArrayRef<Expr *> 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<Derived>::TransformOMPXDynCGroupMemClause(
Size.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
}
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPDoacrossClause(OMPDoacrossClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(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 cba6791783e8b4..a9f25ec2ecb75b 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<OpenMPDoacrossClauseModifier>(Record.readInt()));
+ C->setDependenceLoc(Record.readSourceLocation());
+ C->setColonLoc(Record.readSourceLocation());
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> 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 ff5bab7c99f788..ca0db085d94cc9 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 f36afab8b2075c..298d52132e9744 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<int, 3>(argc);
diff --git a/clang/test/OpenMP/ordered_messages.cpp b/clang/test/OpenMP/ordered_messages.cpp
index 8a3a86443eb8c8..3711693688c519 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 at -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 at -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 25118c702f1be6..fb6cc96cac55d7 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 eb8de20a6b8ba0..c84ad3ffcbbdc2 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 0f8a9d58acc439..c67b54acc47c0d 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<OMPC_Depend>
+ VersionedClause<OMPC_Depend>,
+ VersionedClause<OMPC_Doacross, 52>
];
let allowedOnceClauses = [
VersionedClause<OMPC_Threads>,
More information about the flang-commits
mailing list