[clang] a42e515 - [OpenMP] OpenMP 5.1 "assume" directive parsing support (#92731)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 5 04:37:13 PDT 2024
Author: Julian Brown
Date: 2024-08-05T07:37:07-04:00
New Revision: a42e515e3a9f3bb4e44389c097b89104d95b9b29
URL: https://github.com/llvm/llvm-project/commit/a42e515e3a9f3bb4e44389c097b89104d95b9b29
DIFF: https://github.com/llvm/llvm-project/commit/a42e515e3a9f3bb4e44389c097b89104d95b9b29.diff
LOG: [OpenMP] OpenMP 5.1 "assume" directive parsing support (#92731)
This is a minimal patch to support parsing for "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. The patch builds on top
of the existing support for "omp assumes" directives (note spelling!).
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).
This patch fixes sollve's OpenMP 5.1 "omp assume"-based tests.
Added:
clang/test/OpenMP/assume_lambda.cpp
clang/test/OpenMP/assume_messages.c
clang/test/OpenMP/assume_messages_attr.c
clang/test/OpenMP/assume_nesting.cpp
clang/test/OpenMP/assume_nesting_tmpl.cpp
clang/test/OpenMP/assume_serialize_deserialize.cpp
clang/test/OpenMP/assume_serialize_deserialize_tmpl.cpp
clang/test/OpenMP/assume_template.cpp
Modified:
clang/docs/OpenMPSupport.rst
clang/docs/ReleaseNotes.rst
clang/include/clang-c/Index.h
clang/include/clang/AST/OpenMPClause.h
clang/include/clang/AST/RecursiveASTVisitor.h
clang/include/clang/AST/StmtOpenMP.h
clang/include/clang/Basic/OpenMPKinds.h
clang/include/clang/Basic/StmtNodes.td
clang/include/clang/Parse/Parser.h
clang/include/clang/Sema/SemaOpenMP.h
clang/include/clang/Serialization/ASTBitCodes.h
clang/lib/AST/OpenMPClause.cpp
clang/lib/AST/StmtOpenMP.cpp
clang/lib/AST/StmtPrinter.cpp
clang/lib/AST/StmtProfile.cpp
clang/lib/Basic/OpenMPKinds.cpp
clang/lib/CodeGen/CGStmt.cpp
clang/lib/CodeGen/CGStmtOpenMP.cpp
clang/lib/CodeGen/CodeGenFunction.h
clang/lib/Parse/ParseOpenMP.cpp
clang/lib/Sema/SemaOpenMP.cpp
clang/lib/Sema/TreeTransform.h
clang/lib/Serialization/ASTReader.cpp
clang/lib/Serialization/ASTReaderStmt.cpp
clang/lib/Serialization/ASTWriter.cpp
clang/lib/Serialization/ASTWriterStmt.cpp
clang/tools/libclang/CIndex.cpp
llvm/include/llvm/Frontend/OpenMP/OMP.td
Removed:
################################################################################
diff --git a/clang/docs/OpenMPSupport.rst b/clang/docs/OpenMPSupport.rst
index da25c3880970a..0e72b3c6e09c9 100644
--- a/clang/docs/OpenMPSupport.rst
+++ b/clang/docs/OpenMPSupport.rst
@@ -314,7 +314,7 @@ implementation.
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| misc | assumes directives | :part:`worked on` | |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
-| misc | assume directive | :part:`worked on` | |
+| misc | assume directive | :good:`done` | |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| misc | nothing directive | :good:`done` | D123286 |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 6f50ab07f1fc0..0f1a4c1851911 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -323,6 +323,7 @@ Python Binding Changes
OpenMP Support
--------------
+- Added support for 'omp assume' directive.
Improvements
^^^^^^^^^^^^
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..3a8337abfe687 100644
--- a/clang/include/clang/AST/OpenMPClause.h
+++ b/clang/include/clang/AST/OpenMPClause.h
@@ -342,6 +342,66 @@ template <class T> class OMPVarListClause : public OMPClause {
}
};
+/// Class that represents a list of directive kinds (parallel, target, etc.)
+/// as used in \c absent, \c contains clauses.
+template <class T> class OMPDirectiveListClause : public OMPClause {
+ /// Location of '('.
+ SourceLocation LParenLoc;
+
+protected:
+ /// Number of directive kinds listed in the clause
+ unsigned NumKinds;
+
+public:
+ /// Build a clause with \a NumKinds directive kinds.
+ ///
+ /// \param K The clause kind.
+ /// \param StartLoc Starting location of the clause (the clause keyword).
+ /// \param LParenLoc Location of '('.
+ /// \param EndLoc Ending location of the clause.
+ /// \param NumKinds Number of directive kinds listed in the clause.
+ 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 +2073,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;
+
+ /// 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) {}
+
+public:
+ 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;
+
+ /// 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) {}
+
+public:
+ 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..930670d17f2d1 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 final : 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..16bb967f89d53 100644
--- a/clang/include/clang/Basic/OpenMPKinds.h
+++ b/clang/include/clang/Basic/OpenMPKinds.h
@@ -377,6 +377,11 @@ bool checkFailClauseParameter(OpenMPClauseKind FailClauseParameter);
/// otherwise - false.
bool isOpenMPExecutableDirective(OpenMPDirectiveKind DKind);
+/// Checks if the specified directive is considered as "informational".
+/// \param DKind Specified directive.
+/// \return true if it is an informational directive, false otherwise.
+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..39c5f588167ed 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -3532,6 +3532,17 @@ class Parser : public CodeCompletionHandler {
OpenMPDirectiveKind DKind, SourceLocation Loc,
bool ReadDirectiveWithinMetadirective);
+ /// Parses informational directive.
+ ///
+ /// \param StmtCtx The context in which we're parsing the directive.
+ /// \param DKind The kind of the informational directive.
+ /// \param Loc Source location of the beginning of the directive.
+ /// \param ReadDirectiveWithinMetadirective true if directive is within a
+ /// metadirective and therefore ends on the closing paren.
+ 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..e23c0cdd5a089 100644
--- a/clang/include/clang/Sema/SemaOpenMP.h
+++ b/clang/include/clang/Sema/SemaOpenMP.h
@@ -399,6 +399,28 @@ class SemaOpenMP : public SemaBase {
OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName,
OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc);
+ /// Process an OpenMP informational directive.
+ ///
+ /// \param Kind The directive kind.
+ /// \param DirName Declaration name info.
+ /// \param Clauses Array of clauses for directive.
+ /// \param AStmt The associated statement.
+ /// \param StartLoc The start location.
+ /// \param EndLoc The end location.
+ StmtResult ActOnOpenMPInformationalDirective(
+ OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName,
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc);
+ /// Process an OpenMP assume directive.
+ ///
+ /// \param Clauses Array of clauses for directive.
+ /// \param AStmt The associated statement.
+ /// \param StartLoc The start location.
+ /// \param EndLoc The end location.
+ 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 +962,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..ae4fc11404763 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 30b6fce5d016a..68386957bc2d9 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 8b9c17a3f4a24..1c0a0e117e560 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3904,6 +3904,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 71a36786554b2..9b60afd9b211f 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) {
@@ -3728,6 +3739,7 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
S->getDirectiveKind() == OMPD_master ||
S->getDirectiveKind() == OMPD_masked ||
S->getDirectiveKind() == OMPD_scope ||
+ S->getDirectiveKind() == OMPD_assume ||
isOpenMPLoopTransformationDirective(S->getDirectiveKind())) {
Visit(S->getAssociatedStmt());
return;
@@ -4387,6 +4399,7 @@ void SemaOpenMP::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind,
case OMPD_unroll:
case OMPD_reverse:
case OMPD_interchange:
+ case OMPD_assume:
break;
default:
processCapturedRegions(SemaRef, DKind, CurScope,
@@ -6928,6 +6941,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() &&
@@ -14961,6 +14994,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:
@@ -23337,6 +23373,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 540e1e0cb8df0..bf38e59eae7fd 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,58 @@ 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 (OMPClause *C : Clauses) {
+ if (C) {
+ getDerived().getSema().OpenMP().StartOpenMPClause(C->getClauseKind());
+ OMPClause *Clause = getDerived().TransformOMPClause(C);
+ 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());
+ assert(D->getDirectiveKind() == OMPD_assume &&
+ "Unexpected informational directive");
+ Stmt *CS = D->getAssociatedStmt();
+ 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 +9520,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 +10325,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 85ff3ab8974ee..657ea305f52cf 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -10463,6 +10463,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;
@@ -10863,6 +10885,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 bd9b150c265c1..c167bb8623c13 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_nesting.cpp b/clang/test/OpenMP/assume_nesting.cpp
new file mode 100644
index 0000000000000..2a86a5d6b7456
--- /dev/null
+++ b/clang/test/OpenMP/assume_nesting.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -ast-print %s | FileCheck %s
+// expected-no-diagnostics
+
+extern void bar();
+
+void foo()
+{
+ #pragma omp assume no_openmp_routines
+ // CHECK: omp assume no_openmp_routines
+ {
+ #pragma omp assume no_parallelism
+ // CHECK: omp assume no_parallelism
+ {}
+ }
+
+ #pragma omp target
+ // CHECK: omp target
+ {
+ #pragma omp assume holds(1==1)
+ // CHECK: omp assume holds(1 == 1)
+ {}
+ }
+
+ #pragma omp assume no_parallelism
+ // CHECK: omp assume no_parallelism
+ {
+ #pragma omp target
+ // CHECK: omp target
+ {}
+ }
+
+ #pragma omp assume absent(parallel)
+ // CHECK: omp assume absent(parallel)
+ {
+ #pragma omp assume contains(target, loop)
+ // CHECK: omp assume contains(target, loop)
+ {
+ #pragma omp assume holds(1==1)
+ // CHECK: omp assume holds(1 == 1)
+ {
+ #pragma omp assume absent(teams)
+ // CHECK: omp assume absent(teams)
+ {
+ #pragma omp assume no_openmp_routines
+ // CHECK: omp assume no_openmp_routines
+ {
+ bar();
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/clang/test/OpenMP/assume_nesting_tmpl.cpp b/clang/test/OpenMP/assume_nesting_tmpl.cpp
new file mode 100644
index 0000000000000..59ef603f5874d
--- /dev/null
+++ b/clang/test/OpenMP/assume_nesting_tmpl.cpp
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -ast-print %s | FileCheck %s
+// expected-no-diagnostics
+
+extern void bar();
+
+template<int N>
+void foo()
+{
+ #pragma omp assume no_openmp_routines
+ // CHECK: omp assume no_openmp_routines
+ {
+ #pragma omp assume no_parallelism
+ // CHECK: omp assume no_parallelism
+ {}
+ }
+
+ #pragma omp target
+ // CHECK: omp target
+ {
+ #pragma omp assume holds(1==N)
+ // CHECK: omp assume holds(1 == N)
+ {}
+ }
+
+ #pragma omp assume no_parallelism
+ // CHECK: omp assume no_parallelism
+ {
+ #pragma omp target
+ // CHECK: omp target
+ {}
+ }
+
+ #pragma omp assume absent(parallel)
+ // CHECK: omp assume absent(parallel)
+ {
+ #pragma omp assume contains(target, loop)
+ // CHECK: omp assume contains(target, loop)
+ {
+ #pragma omp assume holds(1==N)
+ // CHECK: omp assume holds(1 == N)
+ {
+ #pragma omp assume absent(teams)
+ // CHECK: omp assume absent(teams)
+ {
+ #pragma omp assume no_openmp_routines
+ // CHECK: omp assume no_openmp_routines
+ {
+ bar();
+ }
+ }
+ }
+ }
+ }
+}
+
+int main() {
+ foo<5>();
+ return 0;
+}
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..2cbcbd883fb2e 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";
}
@@ -196,6 +202,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 +269,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 +528,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