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>, _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits