diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -2584,7 +2584,11 @@ */ CXCursor_OMPDispatchDirective = 291, - CXCursor_LastStmt = CXCursor_OMPDispatchDirective, + /** OpenMP masked directive. + */ + CXCursor_OMPMaskedDirective = 292, + + CXCursor_LastStmt = CXCursor_OMPMaskedDirective, /** * Cursor that represents the translation unit itself. diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -8225,6 +8225,77 @@ } }; +/// This represents 'filter' clause in the '#pragma omp ...' directive. +/// +/// \code +/// #pragma omp masked filter(tid) +/// \endcode +/// In this example directive '#pragma omp masked' has 'filter' clause with +/// thread id. +class OMPFilterClause final : public OMPClause, public OMPClauseWithPreInit { + friend class OMPClauseReader; + + /// Location of '('. + SourceLocation LParenLoc; + + /// Express of the 'filter' clause. + Stmt *ThreadID = nullptr; + + /// Sets the thread identifier. + void setThreadID(Expr *TID) { ThreadID = TID; } + + /// Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + +public: + /// Build 'filter' clause with thread-id \a ThreadID. + /// + /// \param ThreadID Thread identifier. + /// \param HelperE Helper expression associated with this clause. + /// \param CaptureRegion Innermost OpenMP region where expressions in this + /// clause must be captured. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + OMPFilterClause(Expr *ThreadID, Stmt *HelperE, + OpenMPDirectiveKind CaptureRegion, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) + : OMPClause(llvm::omp::OMPC_filter, StartLoc, EndLoc), + OMPClauseWithPreInit(this), LParenLoc(LParenLoc), ThreadID(ThreadID) { + setPreInitStmt(HelperE, CaptureRegion); + } + + /// Build an empty clause. + OMPFilterClause() + : OMPClause(llvm::omp::OMPC_filter, SourceLocation(), SourceLocation()), + OMPClauseWithPreInit(this) {} + /// Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// Return thread identifier. + Expr *getThreadID() { return cast(ThreadID); } + + /// Return thread identifier. + Expr *getThreadID() const { return cast(ThreadID); } + + child_range children() { return child_range(&ThreadID, &ThreadID + 1); } + + const_child_range children() const { + return const_child_range(&ThreadID, &ThreadID + 1); + } + + child_range used_children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range used_children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == llvm::omp::OMPC_filter; + } +}; + /// This class implements a simple visitor for OMPClause /// subclasses. template class Ptr, typename RetTy> diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2974,6 +2974,9 @@ DEF_TRAVERSE_STMT(OMPDispatchDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); }) +DEF_TRAVERSE_STMT(OMPMaskedDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + // OpenMP clauses. template bool RecursiveASTVisitor::TraverseOMPClause(OMPClause *C) { @@ -3609,6 +3612,13 @@ return true; } +template +bool RecursiveASTVisitor::VisitOMPFilterClause(OMPFilterClause *C) { + TRY_TO(VisitOMPClauseWithPreInit(C)); + TRY_TO(TraverseStmt(C->getThreadID())); + return true; +} + // FIXME: look at the following tricky-seeming exprs to see if we // need to recurse on anything. These are ones that have methods // returning decls or qualtypes or nestednamespecifier -- though I'm diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h --- a/clang/include/clang/AST/StmtOpenMP.h +++ b/clang/include/clang/AST/StmtOpenMP.h @@ -5205,6 +5205,56 @@ } }; +/// This represents '#pragma omp masked' directive. +/// \code +/// #pragma omp masked filter(tid) +/// \endcode +/// This example shows a directive '#pragma omp masked' with a filter clause +/// with variable 'tid'. +/// +class OMPMaskedDirective final : public OMPExecutableDirective { + friend class ASTStmtReader; + friend class OMPExecutableDirective; + + /// Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// + OMPMaskedDirective(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPExecutableDirective(OMPMaskedDirectiveClass, llvm::omp::OMPD_masked, + StartLoc, EndLoc) {} + + /// Build an empty directive. + /// + explicit OMPMaskedDirective() + : OMPExecutableDirective(OMPMaskedDirectiveClass, llvm::omp::OMPD_masked, + SourceLocation(), SourceLocation()) {} + +public: + /// Creates directive. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPMaskedDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt); + + /// Creates an empty directive. + /// + /// \param C AST context. + /// + static OMPMaskedDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPMaskedDirectiveClass; + } +}; + } // end namespace clang #endif diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -277,3 +277,4 @@ def OMPTargetTeamsDistributeSimdDirective : StmtNode; def OMPInteropDirective : StmtNode; def OMPDispatchDirective : StmtNode; +def OMPMaskedDirective : StmtNode; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -10803,6 +10803,11 @@ StmtResult ActOnOpenMPDispatchDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp masked' after parsing of the + // /associated statement. + StmtResult ActOnOpenMPMaskedDirective(ArrayRef Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); /// Checks correctness of linear modifiers. bool CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind, @@ -11021,6 +11026,10 @@ SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); + /// Called on well-formed 'filter' clause. + OMPClause *ActOnOpenMPFilterClause(Expr *ThreadID, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); /// Called on well-formed 'threads' clause. OMPClause *ActOnOpenMPThreadsClause(SourceLocation StartLoc, SourceLocation EndLoc); diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1942,6 +1942,7 @@ STMT_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD_DIRECTIVE, STMT_OMP_INTEROP_DIRECTIVE, STMT_OMP_DISPATCH_DIRECTIVE, + STMT_OMP_MASKED_DIRECTIVE, EXPR_OMP_ARRAY_SECTION, EXPR_OMP_ARRAY_SHAPING, EXPR_OMP_ITERATOR, diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -100,6 +100,8 @@ return static_cast(C); case OMPC_nocontext: return static_cast(C); + case OMPC_filter: + return static_cast(C); case OMPC_default: case OMPC_proc_bind: case OMPC_safelen: @@ -2245,6 +2247,12 @@ OS << ")"; } +void OMPClausePrinter::VisitOMPFilterClause(OMPFilterClause *Node) { + OS << "filter("; + Node->getThreadID()->printPretty(OS, nullptr, Policy, 0); + OS << ")"; +} + void OMPTraitInfo::getAsVariantMatchInfo(ASTContext &ASTCtx, VariantMatchInfo &VMI) const { for (const OMPTraitSet &Set : Sets) { diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp --- a/clang/lib/AST/StmtOpenMP.cpp +++ b/clang/lib/AST/StmtOpenMP.cpp @@ -1977,3 +1977,20 @@ /*HasAssociatedStmt=*/true, /*NumChildren=*/0); } + +OMPMaskedDirective *OMPMaskedDirective::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef Clauses, + Stmt *AssociatedStmt) { + return createDirective(C, Clauses, AssociatedStmt, + /*NumChildren=*/0, StartLoc, + EndLoc); +} + +OMPMaskedDirective *OMPMaskedDirective::CreateEmpty(const ASTContext &C, + unsigned NumClauses, + EmptyShell) { + return createEmptyDirective(C, NumClauses, + /*HasAssociatedStmt=*/true); +} diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -972,6 +972,11 @@ PrintOMPExecutableDirective(Node); } +void StmtPrinter::VisitOMPMaskedDirective(OMPMaskedDirective *Node) { + Indent() << "#pragma omp masked"; + PrintOMPExecutableDirective(Node); +} + //===----------------------------------------------------------------------===// // Expr printing methods. //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -569,6 +569,12 @@ Profiler->VisitStmt(C->getInteropVar()); } +void OMPClauseProfiler::VisitOMPFilterClause(const OMPFilterClause *C) { + VistOMPClauseWithPreInit(C); + if (C->getThreadID()) + Profiler->VisitStmt(C->getThreadID()); +} + template void OMPClauseProfiler::VisitOMPClauseList(T *Node) { for (auto *E : Node->varlists()) { @@ -1160,6 +1166,10 @@ VisitOMPExecutableDirective(S); } +void StmtProfiler::VisitOMPMaskedDirective(const OMPMaskedDirective *S) { + VisitOMPExecutableDirective(S); +} + void StmtProfiler::VisitExpr(const Expr *S) { VisitStmt(S); } diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -381,6 +381,9 @@ case Stmt::OMPDispatchDirectiveClass: llvm_unreachable("Dispatch directive not supported yet."); break; + case Stmt::OMPMaskedDirectiveClass: + llvm_unreachable("Masked directive not supported yet."); + break; } } diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -5614,6 +5614,7 @@ case OMPC_use: case OMPC_novariants: case OMPC_nocontext: + case OMPC_filter: llvm_unreachable("Clause is not allowed in 'omp atomic'."); } } diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -2208,6 +2208,7 @@ case OMPD_target_teams_distribute_parallel_for_simd: case OMPD_target_teams_distribute_simd: case OMPD_dispatch: + case OMPD_masked: Diag(Tok, diag::err_omp_unexpected_directive) << 1 << getOpenMPDirectiveName(DKind); break; @@ -2257,7 +2258,7 @@ /// simd' | 'teams distribute parallel for simd' | 'teams distribute /// parallel for' | 'target teams' | 'target teams distribute' | 'target /// teams distribute parallel for' | 'target teams distribute parallel -/// for simd' | 'target teams distribute simd' {clause} +/// for simd' | 'target teams distribute simd' | 'masked' {clause} /// annot_pragma_openmp_end /// StmtResult @@ -2432,7 +2433,8 @@ case OMPD_target_teams_distribute_parallel_for: case OMPD_target_teams_distribute_parallel_for_simd: case OMPD_target_teams_distribute_simd: - case OMPD_dispatch: { + case OMPD_dispatch: + case OMPD_masked: { // Special processing for flush and depobj clauses. Token ImplicitTok; bool ImplicitClauseAllowed = false; @@ -2778,6 +2780,7 @@ case OMPC_detach: case OMPC_novariants: case OMPC_nocontext: + case OMPC_filter: // OpenMP [2.5, Restrictions] // At most one num_threads clause can appear on the directive. // OpenMP [2.8.1, simd construct, Restrictions] diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1488,6 +1488,7 @@ case Stmt::OMPTeamsDistributeSimdDirectiveClass: case Stmt::OMPInteropDirectiveClass: case Stmt::OMPDispatchDirectiveClass: + case Stmt::OMPMaskedDirectiveClass: case Stmt::ReturnStmtClass: case Stmt::SEHExceptStmtClass: case Stmt::SEHFinallyStmtClass: diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -3425,6 +3425,7 @@ S->getDirectiveKind() == OMPD_critical || S->getDirectiveKind() == OMPD_section || S->getDirectiveKind() == OMPD_master || + S->getDirectiveKind() == OMPD_masked || isOpenMPLoopTransformationDirective(S->getDirectiveKind())) { Visit(S->getAssociatedStmt()); return; @@ -3968,6 +3969,7 @@ case OMPD_critical: case OMPD_section: case OMPD_master: + case OMPD_masked: case OMPD_tile: break; case OMPD_simd: @@ -4450,7 +4452,8 @@ if (DSAStack->getCurrentDirective() == OMPD_atomic || DSAStack->getCurrentDirective() == OMPD_critical || DSAStack->getCurrentDirective() == OMPD_section || - DSAStack->getCurrentDirective() == OMPD_master) + DSAStack->getCurrentDirective() == OMPD_master || + DSAStack->getCurrentDirective() == OMPD_masked) return S; bool ErrorFound = false; @@ -4719,10 +4722,10 @@ (ParentRegion == OMPD_section || ParentRegion == OMPD_sections || ParentRegion == OMPD_parallel_sections))); OrphanSeen = ParentRegion == OMPD_unknown; - } else if (CurrentRegion == OMPD_master) { - // OpenMP [2.16, Nesting of Regions] - // A master region may not be closely nested inside a worksharing, - // atomic, or explicit task region. + } else if (CurrentRegion == OMPD_master || CurrentRegion == OMPD_masked) { + // OpenMP 5.1 [2.22, Nesting of Regions] + // A masked region may not be closely nested inside a worksharing, loop, + // atomic, task, or taskloop region. NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || isOpenMPTaskingDirective(ParentRegion); } else if (CurrentRegion == OMPD_critical && CurrentName.getName()) { @@ -4752,27 +4755,28 @@ return true; } } else if (CurrentRegion == OMPD_barrier) { - // OpenMP [2.16, Nesting of Regions] - // A barrier region may not be closely nested inside a worksharing, - // explicit task, critical, ordered, atomic, or master region. - NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || - isOpenMPTaskingDirective(ParentRegion) || - ParentRegion == OMPD_master || - ParentRegion == OMPD_parallel_master || - ParentRegion == OMPD_critical || - ParentRegion == OMPD_ordered; + // OpenMP 5.1 [2.22, Nesting of Regions] + // A barrier region may not be closely nested inside a worksharing, loop, + // task, taskloop, critical, ordered, atomic, or masked region. + NestingProhibited = + isOpenMPWorksharingDirective(ParentRegion) || + isOpenMPTaskingDirective(ParentRegion) || + ParentRegion == OMPD_master || ParentRegion == OMPD_masked || + ParentRegion == OMPD_parallel_master || + ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered; } else if (isOpenMPWorksharingDirective(CurrentRegion) && !isOpenMPParallelDirective(CurrentRegion) && !isOpenMPTeamsDirective(CurrentRegion)) { - // OpenMP [2.16, Nesting of Regions] - // A worksharing region may not be closely nested inside a worksharing, - // explicit task, critical, ordered, atomic, or master region. - NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || - isOpenMPTaskingDirective(ParentRegion) || - ParentRegion == OMPD_master || - ParentRegion == OMPD_parallel_master || - ParentRegion == OMPD_critical || - ParentRegion == OMPD_ordered; + // OpenMP 5.1 [2.22, Nesting of Regions] + // A loop region that binds to a parallel region or a worksharing region + // may not be closely nested inside a worksharing, loop, task, taskloop, + // critical, ordered, atomic, or masked region. + NestingProhibited = + isOpenMPWorksharingDirective(ParentRegion) || + isOpenMPTaskingDirective(ParentRegion) || + ParentRegion == OMPD_master || ParentRegion == OMPD_masked || + ParentRegion == OMPD_parallel_master || + ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered; Recommend = ShouldBeInParallelRegion; } else if (CurrentRegion == OMPD_ordered) { // OpenMP [2.16, Nesting of Regions] @@ -5699,7 +5703,7 @@ ClausesWithImplicit.append(Clauses.begin(), Clauses.end()); if (AStmt && !CurContext->isDependentContext() && Kind != OMPD_atomic && Kind != OMPD_critical && Kind != OMPD_section && Kind != OMPD_master && - !isOpenMPLoopTransformationDirective(Kind)) { + Kind != OMPD_masked && !isOpenMPLoopTransformationDirective(Kind)) { assert(isa(AStmt) && "Captured statement expected"); // Check default data sharing attributes for referenced variables. @@ -5854,6 +5858,10 @@ "No clauses are allowed for 'omp master' directive"); Res = ActOnOpenMPMasterDirective(AStmt, StartLoc, EndLoc); break; + case OMPD_masked: + Res = ActOnOpenMPMaskedDirective(ClausesWithImplicit, AStmt, StartLoc, + EndLoc); + break; case OMPD_critical: Res = ActOnOpenMPCriticalDirective(DirName, ClausesWithImplicit, AStmt, StartLoc, EndLoc); @@ -9865,6 +9873,18 @@ return OMPMasterDirective::Create(Context, StartLoc, EndLoc, AStmt); } +StmtResult Sema::ActOnOpenMPMaskedDirective(ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + if (!AStmt) + return StmtError(); + + setFunctionHasBranchProtectedScope(); + + return OMPMaskedDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); +} + StmtResult Sema::ActOnOpenMPCriticalDirective( const DeclarationNameInfo &DirName, ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { @@ -12793,6 +12813,9 @@ case OMPC_nocontext: Res = ActOnOpenMPNocontextClause(Expr, StartLoc, LParenLoc, EndLoc); break; + case OMPC_filter: + Res = ActOnOpenMPFilterClause(Expr, StartLoc, LParenLoc, EndLoc); + break; case OMPC_device: case OMPC_if: case OMPC_default: @@ -13000,6 +13023,7 @@ case OMPD_section: case OMPD_single: case OMPD_master: + case OMPD_masked: case OMPD_critical: case OMPD_taskgroup: case OMPD_distribute: @@ -13078,6 +13102,7 @@ case OMPD_section: case OMPD_single: case OMPD_master: + case OMPD_masked: case OMPD_critical: case OMPD_taskgroup: case OMPD_distribute: @@ -13158,6 +13183,7 @@ case OMPD_section: case OMPD_single: case OMPD_master: + case OMPD_masked: case OMPD_critical: case OMPD_taskgroup: case OMPD_distribute: @@ -13236,6 +13262,7 @@ case OMPD_section: case OMPD_single: case OMPD_master: + case OMPD_masked: case OMPD_critical: case OMPD_taskgroup: case OMPD_distribute: @@ -13313,6 +13340,7 @@ case OMPD_section: case OMPD_single: case OMPD_master: + case OMPD_masked: case OMPD_critical: case OMPD_taskgroup: case OMPD_distribute: @@ -13393,6 +13421,7 @@ case OMPD_section: case OMPD_single: case OMPD_master: + case OMPD_masked: case OMPD_critical: case OMPD_taskgroup: case OMPD_ordered: @@ -13472,6 +13501,7 @@ case OMPD_section: case OMPD_single: case OMPD_master: + case OMPD_masked: case OMPD_critical: case OMPD_taskgroup: case OMPD_distribute: @@ -13552,6 +13582,7 @@ case OMPD_section: case OMPD_single: case OMPD_master: + case OMPD_masked: case OMPD_critical: case OMPD_taskgroup: case OMPD_distribute: @@ -13575,6 +13606,9 @@ llvm_unreachable("Unexpected OpenMP directive"); } break; + case OMPC_filter: + // Do not capture filter-clause expressions. + break; case OMPC_firstprivate: case OMPC_lastprivate: case OMPC_reduction: @@ -14945,6 +14979,27 @@ StartLoc, LParenLoc, EndLoc); } +OMPClause *Sema::ActOnOpenMPFilterClause(Expr *ThreadID, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + Expr *ValExpr = ThreadID; + Stmt *HelperValStmt = nullptr; + + OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); + OpenMPDirectiveKind CaptureRegion = + getOpenMPCaptureRegionForClause(DKind, OMPC_filter, LangOpts.OpenMP); + if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) { + ValExpr = MakeFullExpr(ValExpr).get(); + llvm::MapVector Captures; + ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); + HelperValStmt = buildPreInits(Context, Captures); + } + + return new (Context) OMPFilterClause(ValExpr, HelperValStmt, CaptureRegion, + StartLoc, LParenLoc, EndLoc); +} + OMPClause *Sema::ActOnOpenMPVarListClause( OpenMPClauseKind Kind, ArrayRef VarList, Expr *DepModOrTailExpr, const OMPVarListLocTy &Locs, SourceLocation ColonLoc, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2231,6 +2231,17 @@ EndLoc); } + /// Build a new OpenMP 'filter' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPFilterClause(Expr *ThreadID, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPFilterClause(ThreadID, StartLoc, LParenLoc, + EndLoc); + } + /// Rebuild the operand to an Objective-C \@synchronized statement. /// /// By default, performs semantic analysis to build the new statement. @@ -9103,6 +9114,17 @@ return Res; } +template +StmtResult +TreeTransform::TransformOMPMaskedDirective(OMPMaskedDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_masked, DirName, nullptr, + D->getBeginLoc()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + //===----------------------------------------------------------------------===// // OpenMP clause transformation //===----------------------------------------------------------------------===// @@ -9420,6 +9442,16 @@ Cond.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } +template +OMPClause * +TreeTransform::TransformOMPFilterClause(OMPFilterClause *C) { + ExprResult ThreadID = getDerived().TransformExpr(C->getThreadID()); + if (ThreadID.isInvalid()) + return nullptr; + return getDerived().RebuildOMPFilterClause(ThreadID.get(), C->getBeginLoc(), + C->getLParenLoc(), C->getEndLoc()); +} + template OMPClause *TreeTransform::TransformOMPUnifiedAddressClause( OMPUnifiedAddressClause *C) { diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -11993,6 +11993,9 @@ case llvm::omp::OMPC_affinity: C = OMPAffinityClause::CreateEmpty(Context, Record.readInt()); break; + case llvm::omp::OMPC_filter: + C = new (Context) OMPFilterClause(); + break; #define OMP_CLAUSE_NO_CLASS(Enum, Str) \ case llvm::omp::Enum: \ break; @@ -12964,6 +12967,12 @@ C->setKindKwLoc(Record.readSourceLocation()); } +void OMPClauseReader::VisitOMPFilterClause(OMPFilterClause *C) { + VisitOMPClauseWithPreInit(C); + C->setThreadID(Record.readSubExpr()); + C->setLParenLoc(Record.readSourceLocation()); +} + OMPTraitInfo *ASTRecordReader::readOMPTraitInfo() { OMPTraitInfo &TI = getContext().getNewOMPTraitInfo(); TI.Sets.resize(readUInt32()); diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -2599,6 +2599,11 @@ D->setTargetCallLoc(Record.readSourceLocation()); } +void ASTStmtReader::VisitOMPMaskedDirective(OMPMaskedDirective *D) { + VisitStmt(D); + VisitOMPExecutableDirective(D); +} + //===----------------------------------------------------------------------===// // ASTReader Implementation //===----------------------------------------------------------------------===// @@ -3524,6 +3529,11 @@ Context, Record[ASTStmtReader::NumStmtFields], Empty); break; + case STMT_OMP_MASKED_DIRECTIVE: + S = OMPMaskedDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + case EXPR_CXX_OPERATOR_CALL: S = CXXOperatorCallExpr::CreateEmpty( Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields], diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -6249,6 +6249,12 @@ Record.AddSourceLocation(C->getLParenLoc()); } +void OMPClauseWriter::VisitOMPFilterClause(OMPFilterClause *C) { + VisitOMPClauseWithPreInit(C); + Record.AddStmt(C->getThreadID()); + Record.AddSourceLocation(C->getLParenLoc()); +} + void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -2554,6 +2554,12 @@ Code = serialization::STMT_OMP_DISPATCH_DIRECTIVE; } +void ASTStmtWriter::VisitOMPMaskedDirective(OMPMaskedDirective *D) { + VisitStmt(D); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_MASKED_DIRECTIVE; +} + //===----------------------------------------------------------------------===// // ASTWriter Implementation //===----------------------------------------------------------------------===// diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1296,6 +1296,7 @@ case Stmt::OMPTileDirectiveClass: case Stmt::OMPInteropDirectiveClass: case Stmt::OMPDispatchDirectiveClass: + case Stmt::OMPMaskedDirectiveClass: case Stmt::CapturedStmtClass: { const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState()); Engine.addAbortedBlock(node, currBldrCtx->getBlock()); diff --git a/clang/test/OpenMP/masked_ast_print.cpp b/clang/test/OpenMP/masked_ast_print.cpp new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/masked_ast_print.cpp @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=51 -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -fopenmp-version=51 -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -fopenmp-version=51 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s + +// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=51 -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=51 -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=51 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + static int a; +// CHECK: static int a; +#pragma omp parallel +{ +#pragma omp masked +{ + a=2; +} + +#pragma omp masked filter(1) +{ + a=3; +} + +#pragma omp masked filter(a) +{ + a=4; +} +} +// CHECK-NEXT: #pragma omp parallel +// CHECK-NEXT: { +// CHECK-NEXT: #pragma omp masked{{$}} +// CHECK-NEXT: { +// CHECK-NEXT: a = 2; +// CHECK-NEXT: } +// CHECK-NEXT: #pragma omp masked filter(1){{$}} +// CHECK-NEXT: { +// CHECK-NEXT: a = 3; +// CHECK-NEXT: } +// CHECK-NEXT: #pragma omp masked filter(a){{$}} +// CHECK-NEXT: { +// CHECK-NEXT: a = 4; +// CHECK-NEXT: } +// CHECK-NEXT: } + return (0); +} + +#endif diff --git a/clang/test/OpenMP/masked_messages.cpp b/clang/test/OpenMP/masked_messages.cpp new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/masked_messages.cpp @@ -0,0 +1,86 @@ +// RUN: %clang_cc1 -verify -fopenmp %s -Wuninitialized + +// RUN: %clang_cc1 -verify -fopenmp-simd %s -Wuninitialized + +void xxx(int argc) { + int x; // expected-note {{initialize the variable 'x' to silence this warning}} +#pragma omp masked + argc = x; // expected-warning {{variable 'x' is uninitialized when used here}} +} + +void yyy(int argc) { + int x; // expected-note {{initialize the variable 'x' to silence this warning}} +#pragma omp masked filter(1) + argc = x; // expected-warning {{variable 'x' is uninitialized when used here}} +} + +int foo(); + +int main() { + #pragma omp masked + ; + #pragma omp masked filter(1) filter(2) // expected-error {{directive '#pragma omp masked' cannot contain more than one 'filter' clause}} + ; + int x,y,z; + #pragma omp masked filter(x) filter(y) filter(z) // expected-error 2 {{directive '#pragma omp masked' cannot contain more than one 'filter' clause}} + ; + #pragma omp masked nowait // expected-error {{unexpected OpenMP clause 'nowait' in directive '#pragma omp masked'}} + #pragma omp masked unknown // expected-warning {{extra tokens at the end of '#pragma omp masked' are ignored}} + foo(); + { + #pragma omp masked + } // expected-error {{expected statement}} + { + #pragma omp masked filter(2) + } // expected-error {{expected statement}} + #pragma omp for + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp masked filter(1) // expected-error {{region cannot be closely nested inside 'for' region}} + foo(); + } + #pragma omp sections + { + foo(); + #pragma omp masked // expected-error {{region cannot be closely nested inside 'sections' region}} + foo(); + } + #pragma omp single + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp masked allocate(i) // expected-error {{region cannot be closely nested inside 'single' region}} expected-error {{unexpected OpenMP clause 'allocate' in directive '#pragma omp masked'}} + foo(); + } + #pragma omp masked + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp masked + foo(); + } + #pragma omp for ordered + for (int i = 0; i < 10; ++i) + #pragma omp masked // expected-error {{region cannot be closely nested inside 'for' region}} + { + foo(); + } + + return 0; +} + +int foo() { + L1: // expected-note {{jump exits scope of OpenMP structured block}} + foo(); + #pragma omp masked filter(0) + { + foo(); + goto L1; // expected-error {{cannot jump from this goto statement to its label}} + } + goto L2; // expected-error {{cannot jump from this goto statement to its label}} + #pragma omp masked filter(-2) + { // expected-note {{jump bypasses OpenMP structured block}} + L2: + foo(); + } + + return 0; +} diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -2299,6 +2299,11 @@ Visitor->AddStmt(C->getCondition()); } +void OMPClauseEnqueue::VisitOMPFilterClause(const OMPFilterClause *C) { + VisitOMPClauseWithPreInit(C); + Visitor->AddStmt(C->getThreadID()); +} + void OMPClauseEnqueue::VisitOMPUnifiedAddressClause( const OMPUnifiedAddressClause *) {} @@ -5678,6 +5683,8 @@ return cxstring::createRef("OMPInteropDirective"); case CXCursor_OMPDispatchDirective: return cxstring::createRef("OMPDispatchDirective"); + case CXCursor_OMPMaskedDirective: + return cxstring::createRef("OMPMaskedDirective"); case CXCursor_OverloadCandidate: return cxstring::createRef("OverloadCandidate"); case CXCursor_TypeAliasTemplateDecl: diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -813,6 +813,9 @@ case Stmt::OMPDispatchDirectiveClass: K = CXCursor_OMPDispatchDirective; break; + case Stmt::OMPMaskedDirectiveClass: + K = CXCursor_OMPMaskedDirective; + break; case Stmt::BuiltinBitCastExprClass: K = CXCursor_BuiltinBitCastExpr; } diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -772,6 +772,7 @@ CHECK_SIMPLE_CLAUSE(Use, OMPC_use) CHECK_SIMPLE_CLAUSE(Novariants, OMPC_novariants) CHECK_SIMPLE_CLAUSE(Nocontext, OMPC_nocontext) +CHECK_SIMPLE_CLAUSE(Filter, OMPC_filter) CHECK_REQ_SCALAR_INT_CLAUSE(Allocator, OMPC_allocator) CHECK_REQ_SCALAR_INT_CLAUSE(Grainsize, OMPC_grainsize) diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td --- a/llvm/include/llvm/Frontend/OpenMP/OMP.td +++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -331,6 +331,10 @@ } def OMPC_Inbranch : Clause<"inbranch"> {} def OMPC_Notinbranch : Clause<"notinbranch"> {} +def OMPC_Filter : Clause<"filter"> { + let clangClass = "OMPFilterClause"; + let flangClass = "ScalarIntExpr"; +} //===----------------------------------------------------------------------===// // Definition of OpenMP directives @@ -1675,6 +1679,11 @@ VersionedClause ]; } +def OMP_masked : Directive<"masked"> { + let allowedOnceClauses = [ + VersionedClause + ]; +} def OMP_Unknown : Directive<"unknown"> { let isDefault = true; }