[clang] [llvm] [OpenMP] OpenMP 5.1 "assume" directive parsing support (PR #92731)
Julian Brown via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 30 10:43:31 PDT 2024
https://github.com/jtb20 updated https://github.com/llvm/llvm-project/pull/92731
>From a00ae52b9d7200b2a6c90515bf7b251d6b7f0137 Mon Sep 17 00:00:00 2001
From: Julian Brown <julian.brown at amd.com>
Date: Wed, 1 May 2024 06:35:59 -0500
Subject: [PATCH] [OpenMP] OpenMP 5.1 "assume" directive parsing support
This patch supports parsing of "omp assume" directives. These are meant
to be hints to a compiler's optimisers: as such, it is legitimate
(if not very useful) to ignore them. This version of the patch
implements new AST nodes for the "assume" directive and the various
clauses it accepts as arguments, and adds new (C++ module) tests for
serialization/deserialization of said nodes.
The patch now uses tail allocation for the directive kind list.
Unlike the "omp [begin/end] assumes" directives, "omp assume" is
associated with a compound statement, i.e. it can appear within a
function. The "holds" assumption could (theoretically) be mapped onto
the existing builtin "__builtin_assume", though the latter applies to a
single point in the program, and the former to a range (i.e. the whole
of the associated compound statement).
The "assume" directive appears to be distinct from the [[omp::assume]]
annotation.
This patch fixes sollve's OpenMP 5.1 "omp assume"-based tests.
---
clang/include/clang-c/Index.h | 4 +
clang/include/clang/AST/OpenMPClause.h | 229 ++++++++++++++++++
clang/include/clang/AST/RecursiveASTVisitor.h | 35 +++
clang/include/clang/AST/StmtOpenMP.h | 30 +++
clang/include/clang/Basic/OpenMPKinds.h | 2 +
clang/include/clang/Basic/StmtNodes.td | 1 +
clang/include/clang/Parse/Parser.h | 4 +
clang/include/clang/Sema/SemaOpenMP.h | 19 ++
.../include/clang/Serialization/ASTBitCodes.h | 1 +
clang/lib/AST/OpenMPClause.cpp | 78 ++++++
clang/lib/AST/StmtOpenMP.cpp | 17 ++
clang/lib/AST/StmtPrinter.cpp | 5 +
clang/lib/AST/StmtProfile.cpp | 18 ++
clang/lib/Basic/OpenMPKinds.cpp | 8 +
clang/lib/CodeGen/CGStmt.cpp | 3 +
clang/lib/CodeGen/CGStmtOpenMP.cpp | 7 +-
clang/lib/CodeGen/CodeGenFunction.h | 1 +
clang/lib/Parse/ParseOpenMP.cpp | 127 ++++++++++
clang/lib/Sema/SemaOpenMP.cpp | 69 ++++++
clang/lib/Sema/TreeTransform.h | 127 ++++++++++
clang/lib/Serialization/ASTReader.cpp | 56 +++++
clang/lib/Serialization/ASTReaderStmt.cpp | 11 +
clang/lib/Serialization/ASTWriter.cpp | 28 +++
clang/lib/Serialization/ASTWriterStmt.cpp | 6 +
clang/test/OpenMP/assume_lambda.cpp | 31 +++
clang/test/OpenMP/assume_messages.c | 30 +++
clang/test/OpenMP/assume_messages_attr.c | 30 +++
.../OpenMP/assume_serialize_deserialize.cpp | 31 +++
.../assume_serialize_deserialize_tmpl.cpp | 72 ++++++
clang/test/OpenMP/assume_template.cpp | 42 ++++
clang/tools/libclang/CIndex.cpp | 21 ++
llvm/include/llvm/Frontend/OpenMP/OMP.td | 33 +++
32 files changed, 1175 insertions(+), 1 deletion(-)
create mode 100644 clang/test/OpenMP/assume_lambda.cpp
create mode 100644 clang/test/OpenMP/assume_messages.c
create mode 100644 clang/test/OpenMP/assume_messages_attr.c
create mode 100644 clang/test/OpenMP/assume_serialize_deserialize.cpp
create mode 100644 clang/test/OpenMP/assume_serialize_deserialize_tmpl.cpp
create mode 100644 clang/test/OpenMP/assume_template.cpp
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index 115f5ab090f96..4b4adbfb236e7 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -2154,6 +2154,10 @@ enum CXCursorKind {
*/
CXCursor_OMPInterchangeDirective = 308,
+ /** OpenMP assume directive.
+ */
+ CXCursor_OMPAssumeDirective = 309,
+
/** OpenACC Compute Construct.
*/
CXCursor_OpenACCComputeConstruct = 320,
diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h
index b029c72fa7d8f..b970437f6e162 100644
--- a/clang/include/clang/AST/OpenMPClause.h
+++ b/clang/include/clang/AST/OpenMPClause.h
@@ -342,6 +342,57 @@ template <class T> class OMPVarListClause : public OMPClause {
}
};
+template <class T> class OMPDirectiveListClause : public OMPClause {
+ /// Location of '('.
+ SourceLocation LParenLoc;
+
+protected:
+ /// Number of directive kinds listed in the clause
+ unsigned NumKinds;
+
+public:
+ OMPDirectiveListClause(OpenMPClauseKind K, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc,
+ unsigned NumKinds)
+ : OMPClause(K, StartLoc, EndLoc), LParenLoc(LParenLoc),
+ NumKinds(NumKinds) {}
+
+ child_range children() {
+ return child_range(child_iterator(), child_iterator());
+ }
+
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
+
+ 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());
+ }
+
+ MutableArrayRef<OpenMPDirectiveKind> getDirectiveKinds() {
+ return MutableArrayRef<OpenMPDirectiveKind>(
+ static_cast<T *>(this)
+ ->template getTrailingObjects<OpenMPDirectiveKind>(),
+ NumKinds);
+ }
+
+ void setDirectiveKinds(ArrayRef<OpenMPDirectiveKind> DK) {
+ assert(
+ DK.size() == NumKinds &&
+ "Number of directive kinds is not the same as the preallocated buffer");
+ std::copy(DK.begin(), DK.end(),
+ static_cast<T *>(this)
+ ->template getTrailingObjects<OpenMPDirectiveKind>());
+ }
+
+ SourceLocation getLParenLoc() { return LParenLoc; }
+
+ void setLParenLoc(SourceLocation S) { LParenLoc = S; }
+};
+
/// This represents 'allocator' clause in the '#pragma omp ...'
/// directive.
///
@@ -2013,6 +2064,184 @@ class OMPMergeableClause : public OMPClause {
}
};
+/// This represents the 'absent' clause in the '#pragma omp assume'
+/// directive.
+///
+/// \code
+/// #pragma omp assume absent(<directive-name list>)
+/// \endcode
+/// In this example directive '#pragma omp assume' has an 'absent' clause.
+class OMPAbsentClause final
+ : public OMPDirectiveListClause<OMPAbsentClause>,
+ private llvm::TrailingObjects<OMPAbsentClause, OpenMPDirectiveKind> {
+ friend OMPDirectiveListClause;
+ friend TrailingObjects;
+
+public:
+ /// Build 'absent' clause.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param EndLoc Ending location of the clause.
+ /// \param NumKinds Number of directive kinds listed in the clause.
+ OMPAbsentClause(SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc, unsigned NumKinds)
+ : OMPDirectiveListClause<OMPAbsentClause>(
+ llvm::omp::OMPC_absent, StartLoc, LParenLoc, EndLoc, NumKinds) {}
+
+ /// Build an empty clause.
+ OMPAbsentClause(unsigned NumKinds)
+ : OMPDirectiveListClause<OMPAbsentClause>(
+ llvm::omp::OMPC_absent, SourceLocation(), SourceLocation(),
+ SourceLocation(), NumKinds) {}
+
+ static OMPAbsentClause *Create(const ASTContext &C,
+ ArrayRef<OpenMPDirectiveKind> DKVec,
+ SourceLocation Loc, SourceLocation LLoc,
+ SourceLocation RLoc);
+
+ static OMPAbsentClause *CreateEmpty(const ASTContext &C, unsigned NumKinds);
+
+ static bool classof(const OMPClause *C) {
+ return C->getClauseKind() == llvm::omp::OMPC_absent;
+ }
+};
+
+/// This represents the 'contains' clause in the '#pragma omp assume'
+/// directive.
+///
+/// \code
+/// #pragma omp assume contains(<directive-name list>)
+/// \endcode
+/// In this example directive '#pragma omp assume' has a 'contains' clause.
+class OMPContainsClause final
+ : public OMPDirectiveListClause<OMPContainsClause>,
+ private llvm::TrailingObjects<OMPContainsClause, OpenMPDirectiveKind> {
+ friend OMPDirectiveListClause;
+ friend TrailingObjects;
+
+public:
+ /// Build 'contains' clause.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param EndLoc Ending location of the clause.
+ /// \param NumKinds Number of directive kinds listed in the clause.
+ OMPContainsClause(SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc, unsigned NumKinds)
+ : OMPDirectiveListClause<OMPContainsClause>(
+ llvm::omp::OMPC_contains, StartLoc, LParenLoc, EndLoc, NumKinds) {}
+
+ /// Build an empty clause.
+ OMPContainsClause(unsigned NumKinds)
+ : OMPDirectiveListClause<OMPContainsClause>(
+ llvm::omp::OMPC_contains, SourceLocation(), SourceLocation(),
+ SourceLocation(), NumKinds) {}
+
+ static OMPContainsClause *Create(const ASTContext &C,
+ ArrayRef<OpenMPDirectiveKind> DKVec,
+ SourceLocation Loc, SourceLocation LLoc,
+ SourceLocation RLoc);
+
+ static OMPContainsClause *CreateEmpty(const ASTContext &C, unsigned NumKinds);
+
+ static bool classof(const OMPClause *C) {
+ return C->getClauseKind() == llvm::omp::OMPC_contains;
+ }
+};
+
+/// This represents the 'holds' clause in the '#pragma omp assume'
+/// directive.
+///
+/// \code
+/// #pragma omp assume holds(<expr>)
+/// \endcode
+/// In this example directive '#pragma omp assume' has a 'holds' clause.
+class OMPHoldsClause final
+ : public OMPOneStmtClause<llvm::omp::OMPC_holds, OMPClause> {
+ friend class OMPClauseReader;
+
+public:
+ /// Build 'holds' clause.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param EndLoc Ending location of the clause.
+ OMPHoldsClause(Expr *E, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc)
+ : OMPOneStmtClause(E, StartLoc, LParenLoc, EndLoc) {}
+
+ /// Build an empty clause.
+ OMPHoldsClause() : OMPOneStmtClause() {}
+
+ Expr *getExpr() const { return getStmtAs<Expr>(); }
+ void setExpr(Expr *E) { setStmt(E); }
+};
+
+/// This represents the 'no_openmp' clause in the '#pragma omp assume'
+/// directive.
+///
+/// \code
+/// #pragma omp assume no_openmp
+/// \endcode
+/// In this example directive '#pragma omp assume' has a 'no_openmp' clause.
+class OMPNoOpenMPClause final
+ : public OMPNoChildClause<llvm::omp::OMPC_no_openmp> {
+public:
+ /// Build 'no_openmp' clause.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param EndLoc Ending location of the clause.
+ OMPNoOpenMPClause(SourceLocation StartLoc, SourceLocation EndLoc)
+ : OMPNoChildClause(StartLoc, EndLoc) {}
+
+ /// Build an empty clause.
+ OMPNoOpenMPClause() : OMPNoChildClause() {}
+};
+
+/// This represents the 'no_openmp_routines' clause in the '#pragma omp assume'
+/// directive.
+///
+/// \code
+/// #pragma omp assume no_openmp_routines
+/// \endcode
+/// In this example directive '#pragma omp assume' has a 'no_openmp_routines'
+/// clause.
+class OMPNoOpenMPRoutinesClause final
+ : public OMPNoChildClause<llvm::omp::OMPC_no_openmp_routines> {
+public:
+ /// Build 'no_openmp_routines' clause.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param EndLoc Ending location of the clause.
+ OMPNoOpenMPRoutinesClause(SourceLocation StartLoc, SourceLocation EndLoc)
+ : OMPNoChildClause(StartLoc, EndLoc) {}
+
+ /// Build an empty clause.
+ OMPNoOpenMPRoutinesClause() : OMPNoChildClause() {}
+};
+
+/// This represents the 'no_parallelism' clause in the '#pragma omp assume'
+/// directive.
+///
+/// \code
+/// #pragma omp assume no_parallelism
+/// \endcode
+/// In this example directive '#pragma omp assume' has a 'no_parallelism'
+/// clause.
+class OMPNoParallelismClause final
+ : public OMPNoChildClause<llvm::omp::OMPC_no_parallelism> {
+public:
+ /// Build 'no_parallelism' clause.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param EndLoc Ending location of the clause.
+ OMPNoParallelismClause(SourceLocation StartLoc, SourceLocation EndLoc)
+ : OMPNoChildClause(StartLoc, EndLoc) {}
+
+ /// Build an empty clause.
+ OMPNoParallelismClause() : OMPNoChildClause() {}
+};
+
/// This represents 'read' clause in the '#pragma omp atomic' directive.
///
/// \code
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index dcf5dbf449f8b..f469cd9094558 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -3238,6 +3238,9 @@ DEF_TRAVERSE_STMT(OMPParallelGenericLoopDirective,
DEF_TRAVERSE_STMT(OMPTargetParallelGenericLoopDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
+DEF_TRAVERSE_STMT(OMPAssumeDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
DEF_TRAVERSE_STMT(OMPErrorDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
@@ -3480,6 +3483,38 @@ bool RecursiveASTVisitor<Derived>::VisitOMPAcqRelClause(OMPAcqRelClause *) {
return true;
}
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPAbsentClause(OMPAbsentClause *) {
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPHoldsClause(OMPHoldsClause *) {
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPContainsClause(OMPContainsClause *) {
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPNoOpenMPClause(OMPNoOpenMPClause *) {
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPNoOpenMPRoutinesClause(
+ OMPNoOpenMPRoutinesClause *) {
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPNoParallelismClause(
+ OMPNoParallelismClause *) {
+ return true;
+}
+
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPAcquireClause(OMPAcquireClause *) {
return true;
diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h
index f313c480f9a08..0ca3732a1ac3a 100644
--- a/clang/include/clang/AST/StmtOpenMP.h
+++ b/clang/include/clang/AST/StmtOpenMP.h
@@ -6468,6 +6468,36 @@ class OMPErrorDirective final : public OMPExecutableDirective {
return T->getStmtClass() == OMPErrorDirectiveClass;
}
};
+
+// It's not really an executable directive, but it seems convenient to use
+// that as the parent class.
+class OMPAssumeDirective : public OMPExecutableDirective {
+ friend class ASTStmtReader;
+ friend class OMPExecutableDirective;
+
+private:
+ OMPAssumeDirective(SourceLocation StartLoc, SourceLocation EndLoc)
+ : OMPExecutableDirective(OMPAssumeDirectiveClass, llvm::omp::OMPD_assume,
+ StartLoc, EndLoc) {}
+
+ explicit OMPAssumeDirective()
+ : OMPExecutableDirective(OMPAssumeDirectiveClass, llvm::omp::OMPD_assume,
+ SourceLocation(), SourceLocation()) {}
+
+public:
+ static OMPAssumeDirective *Create(const ASTContext &Ctx,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt);
+
+ static OMPAssumeDirective *CreateEmpty(const ASTContext &C,
+ unsigned NumClauses, EmptyShell);
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == OMPAssumeDirectiveClass;
+ }
+};
+
} // end namespace clang
#endif
diff --git a/clang/include/clang/Basic/OpenMPKinds.h b/clang/include/clang/Basic/OpenMPKinds.h
index 1d7192c4bdf9d..e8775fa3358e7 100644
--- a/clang/include/clang/Basic/OpenMPKinds.h
+++ b/clang/include/clang/Basic/OpenMPKinds.h
@@ -377,6 +377,8 @@ bool checkFailClauseParameter(OpenMPClauseKind FailClauseParameter);
/// otherwise - false.
bool isOpenMPExecutableDirective(OpenMPDirectiveKind DKind);
+bool isOpenMPInformationalDirective(OpenMPDirectiveKind DKind);
+
/// Checks if the specified directive can capture variables.
/// \param DKind Specified directive.
/// \return true - if the above condition is met for this directive
diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td
index 9bf23fae50a9e..e4e4343ec6f92 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -298,6 +298,7 @@ def OMPTeamsGenericLoopDirective : StmtNode<OMPLoopDirective>;
def OMPTargetTeamsGenericLoopDirective : StmtNode<OMPLoopDirective>;
def OMPParallelGenericLoopDirective : StmtNode<OMPLoopDirective>;
def OMPTargetParallelGenericLoopDirective : StmtNode<OMPLoopDirective>;
+def OMPAssumeDirective : StmtNode<OMPExecutableDirective>;
def OMPErrorDirective : StmtNode<OMPExecutableDirective>;
// OpenACC Constructs.
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index ba7d6866ebacd..154ac5fe839c5 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -3532,6 +3532,10 @@ class Parser : public CodeCompletionHandler {
OpenMPDirectiveKind DKind, SourceLocation Loc,
bool ReadDirectiveWithinMetadirective);
+ StmtResult ParseOpenMPInformationalDirective(
+ ParsedStmtContext StmtCtx, OpenMPDirectiveKind DKind, SourceLocation Loc,
+ bool ReadDirectiveWithinMetadirective);
+
/// Parses clause of kind \a CKind for directive of a kind \a Kind.
///
/// \param DKind Kind of current directive.
diff --git a/clang/include/clang/Sema/SemaOpenMP.h b/clang/include/clang/Sema/SemaOpenMP.h
index aa61dae9415e2..e59152ecc78f0 100644
--- a/clang/include/clang/Sema/SemaOpenMP.h
+++ b/clang/include/clang/Sema/SemaOpenMP.h
@@ -399,6 +399,14 @@ class SemaOpenMP : public SemaBase {
OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName,
OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc);
+ StmtResult ActOnOpenMPInformationalDirective(
+ OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName,
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc);
+ StmtResult ActOnOpenMPAssumeDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc);
+
/// Called on well-formed '\#pragma omp parallel' after parsing
/// of the associated statement.
StmtResult ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
@@ -940,6 +948,17 @@ class SemaOpenMP : public SemaBase {
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc);
+ /// Called on well-formed 'holds' clause.
+ OMPClause *ActOnOpenMPHoldsClause(Expr *E, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc);
+ /// Called on well-formed 'absent' or 'contains' clauses.
+ OMPClause *ActOnOpenMPDirectivePresenceClause(
+ OpenMPClauseKind CK, llvm::ArrayRef<OpenMPDirectiveKind> DKVec,
+ SourceLocation Loc, SourceLocation LLoc, SourceLocation RLoc);
+ OMPClause *ActOnOpenMPNullaryAssumptionClause(OpenMPClauseKind CK,
+ SourceLocation Loc,
+ SourceLocation RLoc);
OMPClause *ActOnOpenMPSingleExprWithArgClause(
OpenMPClauseKind Kind, ArrayRef<unsigned> Arguments, Expr *Expr,
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index 5dd0ba33f8a9c..24ae6b768d379 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1964,6 +1964,7 @@ enum StmtCode {
STMT_OMP_TARGET_TEAMS_GENERIC_LOOP_DIRECTIVE,
STMT_OMP_PARALLEL_GENERIC_LOOP_DIRECTIVE,
STMT_OMP_TARGET_PARALLEL_GENERIC_LOOP_DIRECTIVE,
+ STMT_OMP_ASSUME_DIRECTIVE,
EXPR_ARRAY_SECTION,
EXPR_OMP_ARRAY_SHAPING,
EXPR_OMP_ITERATOR,
diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp
index 042a5df5906ca..7268070e3a27d 100644
--- a/clang/lib/AST/OpenMPClause.cpp
+++ b/clang/lib/AST/OpenMPClause.cpp
@@ -1720,6 +1720,41 @@ const Expr *OMPDoacrossClause::getLoopData(unsigned NumLoop) const {
return *It;
}
+OMPAbsentClause *OMPAbsentClause::Create(const ASTContext &C,
+ ArrayRef<OpenMPDirectiveKind> DKVec,
+ SourceLocation Loc,
+ SourceLocation LLoc,
+ SourceLocation RLoc) {
+ void *Mem = C.Allocate(totalSizeToAlloc<OpenMPDirectiveKind>(DKVec.size()),
+ alignof(OMPAbsentClause));
+ auto *AC = new (Mem) OMPAbsentClause(Loc, LLoc, RLoc, DKVec.size());
+ AC->setDirectiveKinds(DKVec);
+ return AC;
+}
+
+OMPAbsentClause *OMPAbsentClause::CreateEmpty(const ASTContext &C, unsigned K) {
+ void *Mem = C.Allocate(totalSizeToAlloc<OpenMPDirectiveKind>(K),
+ alignof(OMPAbsentClause));
+ return new (Mem) OMPAbsentClause(K);
+}
+
+OMPContainsClause *OMPContainsClause::Create(
+ const ASTContext &C, ArrayRef<OpenMPDirectiveKind> DKVec,
+ SourceLocation Loc, SourceLocation LLoc, SourceLocation RLoc) {
+ void *Mem = C.Allocate(totalSizeToAlloc<OpenMPDirectiveKind>(DKVec.size()),
+ alignof(OMPContainsClause));
+ auto *CC = new (Mem) OMPContainsClause(Loc, LLoc, RLoc, DKVec.size());
+ CC->setDirectiveKinds(DKVec);
+ return CC;
+}
+
+OMPContainsClause *OMPContainsClause::CreateEmpty(const ASTContext &C,
+ unsigned K) {
+ void *Mem = C.Allocate(totalSizeToAlloc<OpenMPDirectiveKind>(K),
+ alignof(OMPContainsClause));
+ return new (Mem) OMPContainsClause(K);
+}
+
//===----------------------------------------------------------------------===//
// OpenMP clauses printing methods
//===----------------------------------------------------------------------===//
@@ -1937,6 +1972,49 @@ void OMPClausePrinter::VisitOMPFailClause(OMPFailClause *Node) {
}
}
+void OMPClausePrinter::VisitOMPAbsentClause(OMPAbsentClause *Node) {
+ OS << "absent(";
+ bool First = true;
+ for (auto &D : Node->getDirectiveKinds()) {
+ if (!First)
+ OS << ", ";
+ OS << getOpenMPDirectiveName(D);
+ First = false;
+ }
+ OS << ")";
+}
+
+void OMPClausePrinter::VisitOMPHoldsClause(OMPHoldsClause *Node) {
+ OS << "holds(";
+ Node->getExpr()->printPretty(OS, nullptr, Policy, 0);
+ OS << ")";
+}
+
+void OMPClausePrinter::VisitOMPContainsClause(OMPContainsClause *Node) {
+ OS << "contains";
+ bool First = true;
+ for (auto &D : Node->getDirectiveKinds()) {
+ if (!First)
+ OS << ", ";
+ OS << getOpenMPDirectiveName(D);
+ First = false;
+ }
+ OS << ")";
+}
+
+void OMPClausePrinter::VisitOMPNoOpenMPClause(OMPNoOpenMPClause *) {
+ OS << "no_openmp";
+}
+
+void OMPClausePrinter::VisitOMPNoOpenMPRoutinesClause(
+ OMPNoOpenMPRoutinesClause *) {
+ OS << "no_openmp_routines";
+}
+
+void OMPClausePrinter::VisitOMPNoParallelismClause(OMPNoParallelismClause *) {
+ OS << "no_parallelism";
+}
+
void OMPClausePrinter::VisitOMPSeqCstClause(OMPSeqCstClause *) {
OS << "seq_cst";
}
diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp
index 451a9fe9fe3d2..5adfd91957460 100644
--- a/clang/lib/AST/StmtOpenMP.cpp
+++ b/clang/lib/AST/StmtOpenMP.cpp
@@ -799,6 +799,23 @@ OMPTaskyieldDirective *OMPTaskyieldDirective::CreateEmpty(const ASTContext &C,
return new (C) OMPTaskyieldDirective();
}
+OMPAssumeDirective *OMPAssumeDirective::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt) {
+ return createDirective<OMPAssumeDirective>(C, Clauses, AStmt,
+ /*NumChildren=*/0, StartLoc,
+ EndLoc);
+}
+
+OMPAssumeDirective *OMPAssumeDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ EmptyShell) {
+ return createEmptyDirective<OMPAssumeDirective>(C, NumClauses,
+ /*HasAssociatedStmt=*/true);
+}
+
OMPErrorDirective *OMPErrorDirective::Create(const ASTContext &C,
SourceLocation StartLoc,
SourceLocation EndLoc,
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 69e0b763e8ddc..014d02220d291 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -867,6 +867,11 @@ void StmtPrinter::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *Node) {
PrintOMPExecutableDirective(Node);
}
+void StmtPrinter::VisitOMPAssumeDirective(OMPAssumeDirective *Node) {
+ Indent() << "#pragma omp assume";
+ PrintOMPExecutableDirective(Node);
+}
+
void StmtPrinter::VisitOMPErrorDirective(OMPErrorDirective *Node) {
Indent() << "#pragma omp error";
PrintOMPExecutableDirective(Node);
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index f1e723b4242ee..09562aadc728a 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -584,6 +584,20 @@ void OMPClauseProfiler::VisitOMPCompareClause(const OMPCompareClause *) {}
void OMPClauseProfiler::VisitOMPFailClause(const OMPFailClause *) {}
+void OMPClauseProfiler::VisitOMPAbsentClause(const OMPAbsentClause *) {}
+
+void OMPClauseProfiler::VisitOMPHoldsClause(const OMPHoldsClause *) {}
+
+void OMPClauseProfiler::VisitOMPContainsClause(const OMPContainsClause *) {}
+
+void OMPClauseProfiler::VisitOMPNoOpenMPClause(const OMPNoOpenMPClause *) {}
+
+void OMPClauseProfiler::VisitOMPNoOpenMPRoutinesClause(
+ const OMPNoOpenMPRoutinesClause *) {}
+
+void OMPClauseProfiler::VisitOMPNoParallelismClause(
+ const OMPNoParallelismClause *) {}
+
void OMPClauseProfiler::VisitOMPSeqCstClause(const OMPSeqCstClause *) {}
void OMPClauseProfiler::VisitOMPAcqRelClause(const OMPAcqRelClause *) {}
@@ -1068,6 +1082,10 @@ void StmtProfiler::VisitOMPTaskwaitDirective(const OMPTaskwaitDirective *S) {
VisitOMPExecutableDirective(S);
}
+void StmtProfiler::VisitOMPAssumeDirective(const OMPAssumeDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
void StmtProfiler::VisitOMPErrorDirective(const OMPErrorDirective *S) {
VisitOMPExecutableDirective(S);
}
diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp
index b141e48e77e3c..2910f4ed642d1 100644
--- a/clang/lib/Basic/OpenMPKinds.cpp
+++ b/clang/lib/Basic/OpenMPKinds.cpp
@@ -710,6 +710,13 @@ bool clang::isOpenMPExecutableDirective(OpenMPDirectiveKind DKind) {
return Cat == Category::Executable || Cat == Category::Subsidiary;
}
+bool clang::isOpenMPInformationalDirective(OpenMPDirectiveKind DKind) {
+ if (DKind == OMPD_error)
+ return true;
+ Category Cat = getDirectiveCategory(DKind);
+ return Cat == Category::Informational;
+}
+
bool clang::isOpenMPCapturingDirective(OpenMPDirectiveKind DKind) {
if (isOpenMPExecutableDirective(DKind)) {
switch (DKind) {
@@ -726,6 +733,7 @@ bool clang::isOpenMPCapturingDirective(OpenMPDirectiveKind DKind) {
case OMPD_section:
case OMPD_taskwait:
case OMPD_taskyield:
+ case OMPD_assume:
return false;
default:
return !isOpenMPLoopTransformationDirective(DKind);
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index e16aa3cdd5506..f618b9fb7f942 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -446,6 +446,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
case Stmt::OMPParallelMaskedDirectiveClass:
EmitOMPParallelMaskedDirective(cast<OMPParallelMaskedDirective>(*S));
break;
+ case Stmt::OMPAssumeDirectiveClass:
+ EmitOMPAssumeDirective(cast<OMPAssumeDirective>(*S));
+ break;
case Stmt::OpenACCComputeConstructClass:
EmitOpenACCComputeConstruct(cast<OpenACCComputeConstruct>(*S));
break;
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index b1ac9361957ff..96012af7be001 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -8288,7 +8288,8 @@ void CodeGenFunction::EmitSimpleOMPExecutableDirective(
D.getDirectiveKind() == OMPD_section ||
D.getDirectiveKind() == OMPD_master ||
D.getDirectiveKind() == OMPD_masked ||
- D.getDirectiveKind() == OMPD_unroll) {
+ D.getDirectiveKind() == OMPD_unroll ||
+ D.getDirectiveKind() == OMPD_assume) {
EmitStmt(D.getAssociatedStmt());
} else {
auto LPCRegion =
@@ -8303,3 +8304,7 @@ void CodeGenFunction::EmitSimpleOMPExecutableDirective(
// Check for outer lastprivate conditional update.
checkForLastprivateConditionalUpdate(*this, D);
}
+
+void CodeGenFunction::EmitOMPAssumeDirective(const OMPAssumeDirective &S) {
+ EmitStmt(S.getAssociatedStmt());
+}
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 89cc819c43bb5..28409994b0336 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3901,6 +3901,7 @@ class CodeGenFunction : public CodeGenTypeCache {
void EmitOMPTeamsGenericLoopDirective(const OMPTeamsGenericLoopDirective &S);
void EmitOMPInteropDirective(const OMPInteropDirective &S);
void EmitOMPParallelMaskedDirective(const OMPParallelMaskedDirective &S);
+ void EmitOMPAssumeDirective(const OMPAssumeDirective &S);
/// Emit device code for the target directive.
static void EmitOMPTargetDeviceFunction(CodeGenModule &CGM,
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index e975e96c5c7e4..0602d8666684c 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -2371,6 +2371,11 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
ParseOMPEndDeclareTargetDirective(DTCI.Kind, DKind, DTCI.Loc);
return nullptr;
}
+ case OMPD_assume: {
+ Diag(Tok, diag::err_omp_unexpected_directive)
+ << 1 << getOpenMPDirectiveName(DKind);
+ break;
+ }
case OMPD_unknown:
Diag(Tok, diag::err_omp_unknown_directive);
break;
@@ -2572,6 +2577,71 @@ StmtResult Parser::ParseOpenMPExecutableDirective(
return Directive;
}
+StmtResult Parser::ParseOpenMPInformationalDirective(
+ ParsedStmtContext StmtCtx, OpenMPDirectiveKind DKind, SourceLocation Loc,
+ bool ReadDirectiveWithinMetadirective) {
+ assert(isOpenMPInformationalDirective(DKind) &&
+ "Unexpected directive category");
+
+ bool HasAssociatedStatement = true;
+ Association Assoc = getDirectiveAssociation(DKind);
+
+ SmallVector<OMPClause *, 5> Clauses;
+ llvm::SmallBitVector SeenClauses(llvm::omp::Clause_enumSize + 1);
+ DeclarationNameInfo DirName;
+ unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope;
+ ParseScope OMPDirectiveScope(this, ScopeFlags);
+
+ Actions.OpenMP().StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(),
+ Loc);
+
+ while (Tok.isNot(tok::annot_pragma_openmp_end)) {
+ if (ReadDirectiveWithinMetadirective && Tok.is(tok::r_paren)) {
+ while (Tok.isNot(tok::annot_pragma_openmp_end))
+ ConsumeAnyToken();
+ break;
+ }
+
+ OpenMPClauseKind CKind = Tok.isAnnotation()
+ ? OMPC_unknown
+ : getOpenMPClauseKind(PP.getSpelling(Tok));
+ Actions.OpenMP().StartOpenMPClause(CKind);
+ OMPClause *Clause =
+ ParseOpenMPClause(DKind, CKind, !SeenClauses[unsigned(CKind)]);
+ SeenClauses[unsigned(CKind)] = true;
+ if (Clause)
+ Clauses.push_back(Clause);
+
+ if (Tok.is(tok::comma))
+ ConsumeToken();
+ Actions.OpenMP().EndOpenMPClause();
+ }
+
+ SourceLocation EndLoc = Tok.getLocation();
+ ConsumeAnnotationToken();
+
+ StmtResult AssociatedStmt;
+ if (HasAssociatedStatement) {
+ Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope());
+ ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false);
+ {
+ Sema::CompoundScopeRAII Scope(Actions);
+ AssociatedStmt = ParseStatement();
+ }
+ AssociatedStmt =
+ Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses);
+ }
+
+ StmtResult Directive = Actions.OpenMP().ActOnOpenMPInformationalDirective(
+ DKind, DirName, Clauses, AssociatedStmt.get(), Loc, EndLoc);
+
+ Actions.OpenMP().EndOpenMPDSABlock(Directive.get());
+ OMPDirectiveScope.Exit();
+
+ return Directive;
+}
+
/// Parsing of declarative or executable OpenMP directives.
///
/// threadprivate-directive:
@@ -2920,6 +2990,14 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
<< 1 << getOpenMPDirectiveName(DKind);
SkipUntil(tok::annot_pragma_openmp_end);
break;
+ case OMPD_assume: {
+ ConsumeToken();
+ Directive = ParseOpenMPInformationalDirective(
+ StmtCtx, DKind, Loc, ReadDirectiveWithinMetadirective);
+ assert(!Directive.isUnset() &&
+ "Informational directive remains unprocessed");
+ return Directive;
+ }
case OMPD_unknown:
default:
Diag(Tok, diag::err_omp_unknown_directive);
@@ -3206,6 +3284,9 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
case OMPC_if:
Clause = ParseOpenMPSingleExprWithArgClause(DKind, CKind, WrongDirective);
break;
+ case OMPC_holds:
+ Clause = ParseOpenMPSingleExprClause(CKind, WrongDirective);
+ break;
case OMPC_nowait:
case OMPC_untied:
case OMPC_mergeable:
@@ -3323,6 +3404,49 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
<< getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);
SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch);
break;
+ case OMPC_absent:
+ case OMPC_contains: {
+ SourceLocation Loc = ConsumeToken();
+ SourceLocation LLoc = Tok.getLocation();
+ SourceLocation RLoc;
+ llvm::SmallVector<OpenMPDirectiveKind, 4> DKVec;
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
+ do {
+ OpenMPDirectiveKind DK = getOpenMPDirectiveKind(PP.getSpelling(Tok));
+ if (DK == OMPD_unknown) {
+ skipUntilPragmaOpenMPEnd(OMPD_assume);
+ Diag(Tok, diag::err_omp_unexpected_clause)
+ << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);
+ break;
+ }
+ if (isOpenMPExecutableDirective(DK)) {
+ DKVec.push_back(DK);
+ ConsumeToken();
+ } else {
+ Diag(Tok, diag::err_omp_unexpected_clause)
+ << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);
+ }
+ } while (TryConsumeToken(tok::comma));
+ RLoc = Tok.getLocation();
+ T.consumeClose();
+ Clause = Actions.OpenMP().ActOnOpenMPDirectivePresenceClause(
+ CKind, DKVec, Loc, LLoc, RLoc);
+ break;
+ }
+ case OMPC_no_openmp:
+ case OMPC_no_openmp_routines:
+ case OMPC_no_parallelism: {
+ if (!FirstClause) {
+ Diag(Tok, diag::err_omp_more_one_clause)
+ << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;
+ ErrorFound = true;
+ }
+ SourceLocation Loc = ConsumeToken();
+ Clause = Actions.OpenMP().ActOnOpenMPNullaryAssumptionClause(
+ CKind, Loc, Tok.getLocation());
+ break;
+ }
case OMPC_ompx_attribute:
Clause = ParseOpenMPOMPXAttributesClause(WrongDirective);
break;
@@ -3408,6 +3532,9 @@ ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName,
/// align-clause
/// 'align' '(' positive-integer-constant ')'
///
+/// holds-clause
+/// 'holds' '(' expression ')'
+///
OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind,
bool ParseOnly) {
SourceLocation Loc = ConsumeToken();
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 4f50efda155fb..ff580983898cb 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -3563,6 +3563,17 @@ void SemaOpenMP::ActOnOpenMPEndAssumesDirective() {
OMPAssumeScoped.pop_back();
}
+StmtResult SemaOpenMP::ActOnOpenMPAssumeDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ if (!AStmt)
+ return StmtError();
+
+ return OMPAssumeDirective::Create(getASTContext(), StartLoc, EndLoc, Clauses,
+ AStmt);
+}
+
OMPRequiresDecl *
SemaOpenMP::CheckOMPRequiresDecl(SourceLocation Loc,
ArrayRef<OMPClause *> ClauseList) {
@@ -4387,6 +4398,7 @@ void SemaOpenMP::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind,
case OMPD_unroll:
case OMPD_reverse:
case OMPD_interchange:
+ case OMPD_assume:
break;
default:
processCapturedRegions(SemaRef, DKind, CurScope,
@@ -6931,6 +6943,26 @@ SemaOpenMP::DeclGroupPtrTy SemaOpenMP::ActOnOpenMPDeclareSimdDirective(
return DG;
}
+StmtResult SemaOpenMP::ActOnOpenMPInformationalDirective(
+ OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName,
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ assert(isOpenMPInformationalDirective(Kind) &&
+ "Unexpected directive category");
+
+ StmtResult Res = StmtError();
+
+ switch (Kind) {
+ case OMPD_assume:
+ Res = ActOnOpenMPAssumeDirective(Clauses, AStmt, StartLoc, EndLoc);
+ break;
+ default:
+ llvm_unreachable("Unknown OpenMP directive");
+ }
+
+ return Res;
+}
+
static void setPrototype(Sema &S, FunctionDecl *FD, FunctionDecl *FDWithProto,
QualType NewType) {
assert(NewType->isFunctionProtoType() &&
@@ -14964,6 +14996,9 @@ OMPClause *SemaOpenMP::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
case OMPC_ompx_dyn_cgroup_mem:
Res = ActOnOpenMPXDynCGroupMemClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_holds:
+ Res = ActOnOpenMPHoldsClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
case OMPC_grainsize:
case OMPC_num_tasks:
case OMPC_device:
@@ -23126,6 +23161,40 @@ OMPClause *SemaOpenMP::ActOnOpenMPXBareClause(SourceLocation StartLoc,
return new (getASTContext()) OMPXBareClause(StartLoc, EndLoc);
}
+OMPClause *SemaOpenMP::ActOnOpenMPHoldsClause(Expr *E, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return new (getASTContext()) OMPHoldsClause(E, StartLoc, LParenLoc, EndLoc);
+}
+
+OMPClause *SemaOpenMP::ActOnOpenMPDirectivePresenceClause(
+ OpenMPClauseKind CK, llvm::ArrayRef<OpenMPDirectiveKind> DKVec,
+ SourceLocation Loc, SourceLocation LLoc, SourceLocation RLoc) {
+ switch (CK) {
+ case OMPC_absent:
+ return OMPAbsentClause::Create(getASTContext(), DKVec, Loc, LLoc, RLoc);
+ case OMPC_contains:
+ return OMPContainsClause::Create(getASTContext(), DKVec, Loc, LLoc, RLoc);
+ default:
+ llvm_unreachable("Unexpected OpenMP clause");
+ }
+}
+
+OMPClause *SemaOpenMP::ActOnOpenMPNullaryAssumptionClause(OpenMPClauseKind CK,
+ SourceLocation Loc,
+ SourceLocation RLoc) {
+ switch (CK) {
+ case OMPC_no_openmp:
+ return new (getASTContext()) OMPNoOpenMPClause(Loc, RLoc);
+ case OMPC_no_openmp_routines:
+ return new (getASTContext()) OMPNoOpenMPRoutinesClause(Loc, RLoc);
+ case OMPC_no_parallelism:
+ return new (getASTContext()) OMPNoParallelismClause(Loc, RLoc);
+ default:
+ llvm_unreachable("Unexpected OpenMP clause");
+ }
+}
+
ExprResult SemaOpenMP::ActOnOMPArraySectionExpr(
Expr *Base, SourceLocation LBLoc, Expr *LowerBound,
SourceLocation ColonLocFirst, SourceLocation ColonLocSecond, Expr *Length,
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 8d3e1edf7a45d..40e549463103b 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -803,6 +803,8 @@ class TreeTransform {
StmtResult TransformOMPExecutableDirective(OMPExecutableDirective *S);
+ StmtResult TransformOMPInformationalDirective(OMPExecutableDirective *S);
+
// FIXME: We use LLVM_ATTRIBUTE_NOINLINE because inlining causes a ridiculous
// amount of stack usage with clang.
#define STMT(Node, Parent) \
@@ -1678,6 +1680,18 @@ class TreeTransform {
Kind, DirName, CancelRegion, Clauses, AStmt, StartLoc, EndLoc);
}
+ /// Build a new OpenMP informational directive.
+ StmtResult RebuildOMPInformationalDirective(OpenMPDirectiveKind Kind,
+ DeclarationNameInfo DirName,
+ ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+
+ return getSema().OpenMP().ActOnOpenMPInformationalDirective(
+ Kind, DirName, Clauses, AStmt, StartLoc, EndLoc);
+ }
+
/// Build a new OpenMP 'if' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
@@ -2486,6 +2500,14 @@ class TreeTransform {
DepType, DepLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc);
}
+ /// Build a new OpenMP 'holds' clause.
+ OMPClause *RebuildOMPHoldsClause(Expr *A, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().OpenMP().ActOnOpenMPHoldsClause(A, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
/// Rebuild the operand to an Objective-C \@synchronized statement.
///
/// By default, performs semantic analysis to build the new statement.
@@ -9185,6 +9207,63 @@ StmtResult TreeTransform<Derived>::TransformOMPExecutableDirective(
AssociatedStmt.get(), D->getBeginLoc(), D->getEndLoc());
}
+/// This is mostly the same as above, but allows 'informational' class
+/// directives when rebuilding the stmt. It still takes an
+/// OMPExecutableDirective-type argument because we're reusing that as the
+/// superclass for the 'assume' directive at present, instead of defining a
+/// mostly-identical OMPInformationalDirective parent class.
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPInformationalDirective(
+ OMPExecutableDirective *D) {
+
+ // Transform the clauses
+ llvm::SmallVector<OMPClause *, 16> TClauses;
+ ArrayRef<OMPClause *> Clauses = D->clauses();
+ TClauses.reserve(Clauses.size());
+ for (ArrayRef<OMPClause *>::iterator I = Clauses.begin(), E = Clauses.end();
+ I != E; ++I) {
+ if (*I) {
+ getDerived().getSema().OpenMP().StartOpenMPClause((*I)->getClauseKind());
+ OMPClause *Clause = getDerived().TransformOMPClause(*I);
+ getDerived().getSema().OpenMP().EndOpenMPClause();
+ if (Clause)
+ TClauses.push_back(Clause);
+ } else {
+ TClauses.push_back(nullptr);
+ }
+ }
+ StmtResult AssociatedStmt;
+ if (D->hasAssociatedStmt() && D->getAssociatedStmt()) {
+ getDerived().getSema().OpenMP().ActOnOpenMPRegionStart(
+ D->getDirectiveKind(),
+ /*CurScope=*/nullptr);
+ StmtResult Body;
+ {
+ Sema::CompoundScopeRAII CompoundScope(getSema());
+ Stmt *CS = nullptr;
+ if (D->getDirectiveKind() == OMPD_assume)
+ CS = D->getAssociatedStmt();
+ else
+ llvm_unreachable("Unexpected informational directive");
+ Body = getDerived().TransformStmt(CS);
+ }
+ AssociatedStmt =
+ getDerived().getSema().OpenMP().ActOnOpenMPRegionEnd(Body, TClauses);
+ if (AssociatedStmt.isInvalid()) {
+ return StmtError();
+ }
+ }
+ if (TClauses.size() != Clauses.size()) {
+ return StmtError();
+ }
+
+ DeclarationNameInfo DirName;
+
+ return getDerived().RebuildOMPInformationalDirective(
+ D->getDirectiveKind(), DirName, TClauses, AssociatedStmt.get(),
+ D->getBeginLoc(), D->getEndLoc());
+}
+
template <typename Derived>
StmtResult
TreeTransform<Derived>::TransformOMPMetaDirective(OMPMetaDirective *D) {
@@ -9446,6 +9525,17 @@ TreeTransform<Derived>::TransformOMPTaskwaitDirective(OMPTaskwaitDirective *D) {
return Res;
}
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPAssumeDirective(OMPAssumeDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().OpenMP().StartOpenMPDSABlock(
+ OMPD_assume, DirName, nullptr, D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPInformationalDirective(D);
+ getDerived().getSema().OpenMP().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
template <typename Derived>
StmtResult
TreeTransform<Derived>::TransformOMPErrorDirective(OMPErrorDirective *D) {
@@ -10240,6 +10330,43 @@ OMPClause *TreeTransform<Derived>::TransformOMPFailClause(OMPFailClause *C) {
return C;
}
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPAbsentClause(OMPAbsentClause *C) {
+ return C;
+}
+
+template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPHoldsClause(OMPHoldsClause *C) {
+ ExprResult E = getDerived().TransformExpr(C->getExpr());
+ if (E.isInvalid())
+ return nullptr;
+ return getDerived().RebuildOMPHoldsClause(E.get(), C->getBeginLoc(),
+ C->getLParenLoc(), C->getEndLoc());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPContainsClause(OMPContainsClause *C) {
+ return C;
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPNoOpenMPClause(OMPNoOpenMPClause *C) {
+ return C;
+}
+template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPNoOpenMPRoutinesClause(
+ OMPNoOpenMPRoutinesClause *C) {
+ return C;
+}
+template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPNoParallelismClause(
+ OMPNoParallelismClause *C) {
+ return C;
+}
+
template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPSeqCstClause(OMPSeqCstClause *C) {
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 3cb96df12e4da..0f81f31fac9f3 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -10456,6 +10456,28 @@ OMPClause *OMPClauseReader::readClause() {
case llvm::omp::OMPC_acq_rel:
C = new (Context) OMPAcqRelClause();
break;
+ case llvm::omp::OMPC_absent: {
+ unsigned NumKinds = Record.readInt();
+ C = OMPAbsentClause::CreateEmpty(Context, NumKinds);
+ break;
+ }
+ case llvm::omp::OMPC_holds:
+ C = new (Context) OMPHoldsClause();
+ break;
+ case llvm::omp::OMPC_contains: {
+ unsigned NumKinds = Record.readInt();
+ C = OMPContainsClause::CreateEmpty(Context, NumKinds);
+ break;
+ }
+ case llvm::omp::OMPC_no_openmp:
+ C = new (Context) OMPNoOpenMPClause();
+ break;
+ case llvm::omp::OMPC_no_openmp_routines:
+ C = new (Context) OMPNoOpenMPRoutinesClause();
+ break;
+ case llvm::omp::OMPC_no_parallelism:
+ C = new (Context) OMPNoParallelismClause();
+ break;
case llvm::omp::OMPC_acquire:
C = new (Context) OMPAcquireClause();
break;
@@ -10856,6 +10878,40 @@ void OMPClauseReader::VisitOMPFailClause(OMPFailClause *C) {
C->setFailParameter(CKind);
}
+void OMPClauseReader::VisitOMPAbsentClause(OMPAbsentClause *C) {
+ unsigned Count = C->getDirectiveKinds().size();
+ C->setLParenLoc(Record.readSourceLocation());
+ llvm::SmallVector<OpenMPDirectiveKind, 4> DKVec;
+ DKVec.reserve(Count);
+ for (unsigned I = 0; I < Count; I++) {
+ DKVec.push_back(Record.readEnum<OpenMPDirectiveKind>());
+ }
+ C->setDirectiveKinds(DKVec);
+}
+
+void OMPClauseReader::VisitOMPHoldsClause(OMPHoldsClause *C) {
+ C->setExpr(Record.readExpr());
+ C->setLParenLoc(Record.readSourceLocation());
+}
+
+void OMPClauseReader::VisitOMPContainsClause(OMPContainsClause *C) {
+ unsigned Count = C->getDirectiveKinds().size();
+ C->setLParenLoc(Record.readSourceLocation());
+ llvm::SmallVector<OpenMPDirectiveKind, 4> DKVec;
+ DKVec.reserve(Count);
+ for (unsigned I = 0; I < Count; I++) {
+ DKVec.push_back(Record.readEnum<OpenMPDirectiveKind>());
+ }
+ C->setDirectiveKinds(DKVec);
+}
+
+void OMPClauseReader::VisitOMPNoOpenMPClause(OMPNoOpenMPClause *) {}
+
+void OMPClauseReader::VisitOMPNoOpenMPRoutinesClause(
+ OMPNoOpenMPRoutinesClause *) {}
+
+void OMPClauseReader::VisitOMPNoParallelismClause(OMPNoParallelismClause *) {}
+
void OMPClauseReader::VisitOMPSeqCstClause(OMPSeqCstClause *) {}
void OMPClauseReader::VisitOMPAcqRelClause(OMPAcqRelClause *) {}
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index e1cba9e612be3..a33f2a41a6549 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2536,6 +2536,11 @@ void ASTStmtReader::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *D) {
VisitOMPExecutableDirective(D);
}
+void ASTStmtReader::VisitOMPAssumeDirective(OMPAssumeDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+}
+
void ASTStmtReader::VisitOMPErrorDirective(OMPErrorDirective *D) {
VisitStmt(D);
// The NumClauses field was read in ReadStmtFromStream.
@@ -3913,6 +3918,12 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
}
+ case STMT_OMP_ASSUME_DIRECTIVE: {
+ unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
+ S = OMPAssumeDirective::CreateEmpty(Context, NumClauses, Empty);
+ break;
+ }
+
case EXPR_CXX_OPERATOR_CALL: {
auto NumArgs = Record[ASTStmtReader::NumExprFields];
BitsUnpacker CallExprBits(Record[ASTStmtReader::NumExprFields + 1]);
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index f0f9d397f1717..8aa23865d75aa 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -7204,6 +7204,34 @@ void OMPClauseWriter::VisitOMPSeqCstClause(OMPSeqCstClause *) {}
void OMPClauseWriter::VisitOMPAcqRelClause(OMPAcqRelClause *) {}
+void OMPClauseWriter::VisitOMPAbsentClause(OMPAbsentClause *C) {
+ Record.push_back(static_cast<uint64_t>(C->getDirectiveKinds().size()));
+ Record.AddSourceLocation(C->getLParenLoc());
+ for (auto K : C->getDirectiveKinds()) {
+ Record.writeEnum(K);
+ }
+}
+
+void OMPClauseWriter::VisitOMPHoldsClause(OMPHoldsClause *C) {
+ Record.AddStmt(C->getExpr());
+ Record.AddSourceLocation(C->getLParenLoc());
+}
+
+void OMPClauseWriter::VisitOMPContainsClause(OMPContainsClause *C) {
+ Record.push_back(static_cast<uint64_t>(C->getDirectiveKinds().size()));
+ Record.AddSourceLocation(C->getLParenLoc());
+ for (auto K : C->getDirectiveKinds()) {
+ Record.writeEnum(K);
+ }
+}
+
+void OMPClauseWriter::VisitOMPNoOpenMPClause(OMPNoOpenMPClause *) {}
+
+void OMPClauseWriter::VisitOMPNoOpenMPRoutinesClause(
+ OMPNoOpenMPRoutinesClause *) {}
+
+void OMPClauseWriter::VisitOMPNoParallelismClause(OMPNoParallelismClause *) {}
+
void OMPClauseWriter::VisitOMPAcquireClause(OMPAcquireClause *) {}
void OMPClauseWriter::VisitOMPReleaseClause(OMPReleaseClause *) {}
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index ec667b58337ff..038616a675b72 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -2606,6 +2606,12 @@ void ASTStmtWriter::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *D) {
Code = serialization::STMT_OMP_TASKWAIT_DIRECTIVE;
}
+void ASTStmtWriter::VisitOMPAssumeDirective(OMPAssumeDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_ASSUME_DIRECTIVE;
+}
+
void ASTStmtWriter::VisitOMPErrorDirective(OMPErrorDirective *D) {
VisitStmt(D);
Record.push_back(D->getNumClauses());
diff --git a/clang/test/OpenMP/assume_lambda.cpp b/clang/test/OpenMP/assume_lambda.cpp
new file mode 100644
index 0000000000000..4000dc1600b23
--- /dev/null
+++ b/clang/test/OpenMP/assume_lambda.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -ast-print %s | FileCheck %s
+// expected-no-diagnostics
+
+extern int bar(int);
+
+int foo(int arg)
+{
+ #pragma omp assume no_openmp_routines
+ {
+ auto fn = [](int x) { return bar(x); };
+// CHECK: auto fn = [](int x) {
+ return fn(5);
+ }
+}
+
+class C {
+public:
+ int foo(int a);
+};
+
+// We're really just checking that this parses. All the assumptions are thrown
+// away immediately for now.
+int C::foo(int a)
+{
+ #pragma omp assume holds(sizeof(void*) == 8) absent(parallel)
+ {
+ auto fn = [](int x) { return bar(x); };
+// CHECK: auto fn = [](int x) {
+ return fn(5);
+ }
+}
diff --git a/clang/test/OpenMP/assume_messages.c b/clang/test/OpenMP/assume_messages.c
new file mode 100644
index 0000000000000..65b003863c089
--- /dev/null
+++ b/clang/test/OpenMP/assume_messages.c
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -triple=x86_64-linux-gnu -verify -fopenmp -x c -std=c99 %s
+// RUN: %clang_cc1 -triple=x86_64-linux-gnu -verify -fopenmp-simd -x c -std=c99 %s
+
+#pragma omp assume no_openmp // expected-error {{unexpected OpenMP directive '#pragma omp assume'}}
+
+void foo(void) {
+ #pragma omp assume hold(1==1) // expected-warning {{extra tokens at the end of '#pragma omp assume' are ignored}}
+ {}
+}
+
+void bar(void) {
+ #pragma omp assume absent(target)
+} // expected-error {{expected statement}}
+
+void qux(void) {
+ #pragma omp assume extra_bits // expected-warning {{extra tokens at the end of '#pragma omp assume' are ignored}}
+ {}
+}
+
+void quux(void) {
+ // This form of spelling for assumption clauses is supported for
+ // "omp assumes" (as a non-standard extension), but not here.
+ #pragma omp assume ext_spelled_like_this // expected-warning {{extra tokens at the end of '#pragma omp assume' are ignored}}
+ {}
+}
+
+void dups(void) {
+ #pragma omp assume no_openmp no_openmp // // expected-error {{directive '#pragma omp assume' cannot contain more than one 'no_openmp' clause}}
+ {}
+}
diff --git a/clang/test/OpenMP/assume_messages_attr.c b/clang/test/OpenMP/assume_messages_attr.c
new file mode 100644
index 0000000000000..a2e61a8cf412f
--- /dev/null
+++ b/clang/test/OpenMP/assume_messages_attr.c
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -triple=x86_64-linux-gnu -verify -fopenmp -x c -std=c99 %s
+// RUN: %clang_cc1 -triple=x86_64-linux-gnu -verify -fopenmp-simd -x c -std=c99 %s
+
+[[omp::directive(assume no_openmp)]] // expected-error {{unexpected OpenMP directive '#pragma omp assume'}}
+
+void foo(void) {
+ [[omp::directive(assume hold(1==1))]] // expected-warning {{extra tokens at the end of '#pragma omp assume' are ignored}}
+ {}
+}
+
+void bar(void) {
+ [[omp::directive(assume absent(target))]]
+} // expected-error {{expected statement}}
+
+void qux(void) {
+ [[omp::directive(assume extra_bits)]] // expected-warning {{extra tokens at the end of '#pragma omp assume' are ignored}}
+ {}
+}
+
+void quux(void) {
+ // This form of spelling for assumption clauses is supported for
+ // "omp assumes" (as a non-standard extension), but not here.
+ [[omp::directive(assume ext_spelled_like_this)]] // expected-warning {{extra tokens at the end of '#pragma omp assume' are ignored}}
+ {}
+}
+
+void dups(void) {
+ [[omp::directive(assume no_openmp no_openmp)]] // expected-error {{directive '#pragma omp assume' cannot contain more than one 'no_openmp' clause}}
+ {}
+}
diff --git a/clang/test/OpenMP/assume_serialize_deserialize.cpp b/clang/test/OpenMP/assume_serialize_deserialize.cpp
new file mode 100644
index 0000000000000..d74de48047bd1
--- /dev/null
+++ b/clang/test/OpenMP/assume_serialize_deserialize.cpp
@@ -0,0 +1,31 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: cd %t
+
+// RUN: %clang_cc1 -std=c++20 -fopenmp -triple x86_64-unknown-linux-gnu %t/AssumeMod.cppm -emit-module-interface -o %t/AssumeMod.pcm
+// RUN: %clang_cc1 -std=c++20 -fopenmp -triple x86_64-unknown-linux-gnu %t/UseAssumeMod.cpp -fmodule-file=AssumeMod=%t/AssumeMod.pcm -ast-dump-all | FileCheck %t/AssumeMod.cppm
+
+// expected-no-diagnostics
+
+//--- AssumeMod.cppm
+module;
+export module AssumeMod;
+export int foo(int y) {
+ int x = -1;
+#pragma omp assume holds(y == 5)
+// CHECK: OMPAssumeDirective 0x{{.*}} <line:5:1, col:33>
+// CHECK-NEXT: OMPHoldsClause 0x{{.*}} <col:20, col:32>
+ {
+ x = y;
+ }
+ return x;
+}
+//--- UseAssumeMod.cpp
+import AssumeMod;
+
+extern "C" int printf(const char* fmt, ...);
+
+int main() {
+ printf ("foo(5)=%d\n", foo (5));
+ return 0;
+}
diff --git a/clang/test/OpenMP/assume_serialize_deserialize_tmpl.cpp b/clang/test/OpenMP/assume_serialize_deserialize_tmpl.cpp
new file mode 100644
index 0000000000000..db0b47210bd41
--- /dev/null
+++ b/clang/test/OpenMP/assume_serialize_deserialize_tmpl.cpp
@@ -0,0 +1,72 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: cd %t
+
+// RUN: %clang_cc1 -std=c++20 -fopenmp -triple x86_64-unknown-linux-gnu %t/AssumeMod.cppm -emit-module-interface -o %t/AssumeMod.pcm
+// RUN: %clang_cc1 -std=c++20 -fopenmp -triple x86_64-unknown-linux-gnu %t/UseAssumeMod.cpp -fmodule-file=AssumeMod=%t/AssumeMod.pcm -ast-dump-all | FileCheck %t/AssumeMod.cppm
+
+// expected-no-diagnostics
+
+//--- AssumeMod.cppm
+module;
+export module AssumeMod;
+export template<int N> int foo(int y) {
+ int x = -1;
+#pragma omp assume holds(y == N)
+ {
+ x = y;
+ }
+ return x;
+}
+
+export template<bool B> void bar(int *z) {
+ if constexpr (B) {
+#pragma omp assume no_openmp
+ {
+ z[0]++;
+ }
+ } else {
+#pragma omp assume contains(target, parallel) absent(loop)
+ {
+ z[1] += 2;
+ }
+ }
+}
+
+// CHECK: FunctionTemplateDecl 0x{{.*}}
+// CHECK: OMPAssumeDirective 0x{{.*}} <line:5:1, col:33>
+// CHECK-NEXT: OMPHoldsClause 0x{{.*}} <col:20, col:32>
+
+// CHECK: FunctionDecl 0x{{.*}} implicit_instantiation
+// CHECK: OMPAssumeDirective 0x{{.*}} <line:5:1, col:33>
+// CHECK-NEXT: OMPHoldsClause 0x{{.*}} <col:20, col:32>
+
+// CHECK: FunctionTemplateDecl 0x{{.*}}
+// CHECK: OMPAssumeDirective 0x{{.*}} <line:14:1, col:29>
+// CHECK-NEXT: OMPNo_openmpClause 0x{{.*}} <col:20, col:29>
+// CHECK: OMPAssumeDirective 0x{{.*}} <line:19:1, col:59>
+// CHECK-NEXT: OMPContainsClause 0x{{.*}} <col:20, col:45>
+// CHECK-NEXT: OMPAbsentClause 0x{{.*}} <col:47, col:58>
+
+// CHECK: FunctionDecl 0x{{.*}} implicit_instantiation
+// CHECK: OMPAssumeDirective 0x{{.*}} <line:14:1, col:29>
+// CHECK-NEXT: OMPNo_openmpClause 0x{{.*}} <col:20, col:29>
+
+// CHECK: FunctionDecl 0x{{.*}} implicit_instantiation
+// CHECK: OMPAssumeDirective 0x{{.*}} <line:19:1, col:59>
+// CHECK-NEXT: OMPContainsClause 0x{{.*}} <col:20, col:45>
+// CHECK-NEXT: OMPAbsentClause 0x{{.*}} <col:47, col:58>
+
+//--- UseAssumeMod.cpp
+import AssumeMod;
+
+extern "C" int printf(const char* fmt, ...);
+
+int main() {
+ printf ("foo(5)=%d\n", foo<5> (5));
+ int arr[2] = { 0, 0 };
+ bar<true>(arr);
+ bar<false>(arr);
+ printf ("arr[0]=%d, arr[1]=%d\n", arr[0], arr[1]);
+ return 0;
+}
diff --git a/clang/test/OpenMP/assume_template.cpp b/clang/test/OpenMP/assume_template.cpp
new file mode 100644
index 0000000000000..20d1c5d437145
--- /dev/null
+++ b/clang/test/OpenMP/assume_template.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %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 -verify %s -ast-print | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+extern int qux(int);
+
+template<typename T>
+int foo(T arg)
+{
+ #pragma omp assume no_openmp_routines
+ {
+ auto fn = [](int x) { return qux(x); };
+// CHECK: auto fn = [](int x) {
+ return fn(5);
+ }
+}
+
+template<typename T>
+class C {
+ T m;
+
+public:
+ T bar(T a);
+};
+
+// We're really just checking this parses. All the assumptions are thrown
+// away immediately for now.
+template<typename T>
+T C<T>::bar(T a)
+{
+ #pragma omp assume holds(sizeof(T) == 8) absent(parallel)
+ {
+ return (T)qux((int)a);
+// CHECK: return (T)qux((int)a);
+ }
+}
+
+#endif
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 937d7ff09e4ee..40c74d49e41e9 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -2200,6 +2200,7 @@ class EnqueueVisitor : public ConstStmtVisitor<EnqueueVisitor, void>,
void VisitOMPTaskyieldDirective(const OMPTaskyieldDirective *D);
void VisitOMPBarrierDirective(const OMPBarrierDirective *D);
void VisitOMPTaskwaitDirective(const OMPTaskwaitDirective *D);
+ void VisitOMPAssumeDirective(const OMPAssumeDirective *D);
void VisitOMPErrorDirective(const OMPErrorDirective *D);
void VisitOMPTaskgroupDirective(const OMPTaskgroupDirective *D);
void
@@ -2425,6 +2426,20 @@ void OMPClauseEnqueue::VisitOMPCompareClause(const OMPCompareClause *) {}
void OMPClauseEnqueue::VisitOMPFailClause(const OMPFailClause *) {}
+void OMPClauseEnqueue::VisitOMPAbsentClause(const OMPAbsentClause *) {}
+
+void OMPClauseEnqueue::VisitOMPHoldsClause(const OMPHoldsClause *) {}
+
+void OMPClauseEnqueue::VisitOMPContainsClause(const OMPContainsClause *) {}
+
+void OMPClauseEnqueue::VisitOMPNoOpenMPClause(const OMPNoOpenMPClause *) {}
+
+void OMPClauseEnqueue::VisitOMPNoOpenMPRoutinesClause(
+ const OMPNoOpenMPRoutinesClause *) {}
+
+void OMPClauseEnqueue::VisitOMPNoParallelismClause(
+ const OMPNoParallelismClause *) {}
+
void OMPClauseEnqueue::VisitOMPSeqCstClause(const OMPSeqCstClause *) {}
void OMPClauseEnqueue::VisitOMPAcqRelClause(const OMPAcqRelClause *) {}
@@ -3310,6 +3325,10 @@ void EnqueueVisitor::VisitOMPTaskwaitDirective(const OMPTaskwaitDirective *D) {
VisitOMPExecutableDirective(D);
}
+void EnqueueVisitor::VisitOMPAssumeDirective(const OMPAssumeDirective *D) {
+ VisitOMPAssumeDirective(D);
+}
+
void EnqueueVisitor::VisitOMPErrorDirective(const OMPErrorDirective *D) {
VisitOMPExecutableDirective(D);
}
@@ -6146,6 +6165,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("OMPBarrierDirective");
case CXCursor_OMPTaskwaitDirective:
return cxstring::createRef("OMPTaskwaitDirective");
+ case CXCursor_OMPAssumeDirective:
+ return cxstring::createRef("OMPAssumeDirective");
case CXCursor_OMPErrorDirective:
return cxstring::createRef("OMPErrorDirective");
case CXCursor_OMPTaskgroupDirective:
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index 99cef340f40df..5a5c1af43db69 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -32,6 +32,9 @@ def OpenMP : DirectiveLanguage {
// Sorted alphabetically wrt clause spelling.
//===----------------------------------------------------------------------===//
+def OMPC_Absent : Clause<"absent"> {
+ let clangClass = "OMPAbsentClause";
+}
def OMPC_Acquire : Clause<"acquire"> {
let clangClass = "OMPAcquireClause";
}
@@ -87,6 +90,9 @@ def OMPC_CancellationConstructType : Clause<"cancellation_construct_type"> {
OMP_CANCELLATION_CONSTRUCT_None
];
}
+def OMPC_Contains : Clause<"contains"> {
+ let clangClass = "OMPContainsClause";
+}
def OMPC_Capture : Clause<"capture"> {
let clangClass = "OMPCaptureClause";
}
@@ -134,6 +140,9 @@ def OMPC_Device : Clause<"device"> {
def OMPC_DeviceType : Clause<"device_type"> {
let flangClass = "OmpDeviceTypeClause";
}
+//def OMPC_DirectiveKind : Clause<"__directive_kind__"> {
+// let clangClass = "OMPDirectiveKindClause";
+//}
def OMPC_DistSchedule : Clause<"dist_schedule"> {
let clangClass = "OMPDistScheduleClause";
let flangClass = "ScalarIntExpr";
@@ -196,6 +205,9 @@ def OMPC_Hint : Clause<"hint"> {
let clangClass = "OMPHintClause";
let flangClass = "ConstantExpr";
}
+def OMPC_Holds : Clause<"holds"> {
+ let clangClass = "OMPHoldsClause";
+}
def OMPC_If : Clause<"if"> {
let clangClass = "OMPIfClause";
let flangClass = "OmpIfClause";
@@ -260,6 +272,15 @@ def OMPC_Mergeable : Clause<"mergeable"> {
def OMPC_Message : Clause<"message"> {
let clangClass = "OMPMessageClause";
}
+def OMPC_NoOpenMP : Clause<"no_openmp"> {
+ let clangClass = "OMPNoOpenMPClause";
+}
+def OMPC_NoOpenMPRoutines : Clause<"no_openmp_routines"> {
+ let clangClass = "OMPNoOpenMPRoutinesClause";
+}
+def OMPC_NoParallelism : Clause<"no_parallelism"> {
+ let clangClass = "OMPNoParallelismClause";
+}
def OMPC_Nocontext : Clause<"nocontext"> {
let clangClass = "OMPNocontextClause";
let flangClass = "ScalarLogicalExpr";
@@ -510,6 +531,18 @@ def OMP_EndAssumes : Directive<"end assumes"> {
let association = AS_Delimited;
let category = OMP_Assumes.category;
}
+def OMP_Assume : Directive<"assume"> {
+ let association = AS_Block;
+ let category = CA_Informational;
+ let allowedOnceClauses = [
+ VersionedClause<OMPC_Absent, 51>,
+ VersionedClause<OMPC_Contains, 51>,
+ VersionedClause<OMPC_Holds, 51>,
+ VersionedClause<OMPC_NoOpenMP, 51>,
+ VersionedClause<OMPC_NoOpenMPRoutines, 51>,
+ VersionedClause<OMPC_NoParallelism, 51>
+ ];
+}
def OMP_Atomic : Directive<"atomic"> {
let allowedClauses = [
VersionedClause<OMPC_Capture>,
More information about the cfe-commits
mailing list