From 0f0564bb9a3ca4527eb2333eba34643e05c315ca Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Tue, 17 Mar 2020 09:17:42 -0400 Subject: [PATCH] [OPENMP50]Initial support for detach clause in task directive. Added parsing/sema/serialization support for detach clause. --- clang/include/clang/AST/OpenMPClause.h | 62 +++++++++++ clang/include/clang/AST/RecursiveASTVisitor.h | 6 ++ .../clang/Basic/DiagnosticSemaKinds.td | 6 +- clang/include/clang/Basic/OpenMPKinds.def | 2 + clang/include/clang/Sema/Sema.h | 4 + clang/lib/AST/OpenMPClause.cpp | 8 ++ clang/lib/AST/StmtProfile.cpp | 5 + clang/lib/Basic/OpenMPKinds.cpp | 4 + clang/lib/CodeGen/CGStmtOpenMP.cpp | 1 + clang/lib/Parse/ParseOpenMP.cpp | 11 +- clang/lib/Sema/SemaOpenMP.cpp | 101 +++++++++++++++++- clang/lib/Sema/TreeTransform.h | 23 ++++ clang/lib/Serialization/ASTReader.cpp | 8 ++ clang/lib/Serialization/ASTWriter.cpp | 5 + clang/test/OpenMP/task_ast_print.cpp | 23 ++-- clang/test/OpenMP/task_messages.cpp | 41 ++++++- clang/tools/libclang/CIndex.cpp | 4 + 17 files changed, 296 insertions(+), 18 deletions(-) diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h index 086c6a232de7..79f43fc8ab88 100644 --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -6827,6 +6827,68 @@ public: } }; +/// This represents 'detach' clause in the '#pragma omp task' directive. +/// +/// \code +/// #pragma omp task detach(evt) +/// \endcode +/// In this example directive '#pragma omp detach' has simple 'detach' clause +/// with the variable 'evt'. +class OMPDetachClause final : public OMPClause { + friend class OMPClauseReader; + + /// Location of '('. + SourceLocation LParenLoc; + + /// Expression of the 'detach' clause. + Stmt *Evt = nullptr; + + /// Set condition. + void setEventHandler(Expr *E) { Evt = E; } + + /// Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + +public: + /// Build 'detach' clause with event-handler \a Evt. + /// + /// \param Evt Event handler expression. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + OMPDetachClause(Expr *Evt, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc) + : OMPClause(OMPC_detach, StartLoc, EndLoc), LParenLoc(LParenLoc), + Evt(Evt) {} + + /// Build an empty clause. + OMPDetachClause() + : OMPClause(OMPC_detach, SourceLocation(), SourceLocation()) {} + + /// Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// Returns event-handler expression. + Expr *getEventHandler() const { return cast_or_null(Evt); } + + child_range children() { return child_range(&Evt, &Evt + 1); } + + const_child_range children() const { + return const_child_range(&Evt, &Evt + 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() == OMPC_detach; + } +}; + /// 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 index ce66eeef7a82..27a0bc774184 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -3488,6 +3488,12 @@ bool RecursiveASTVisitor::VisitOMPOrderClause(OMPOrderClause *) { return true; } +template +bool RecursiveASTVisitor::VisitOMPDetachClause(OMPDetachClause *C) { + TRY_TO(TraverseStmt(C->getEventHandler())); + return true; +} + // FIXME: look at the following tricky-seeming exprs to see if we // need to recurse on anything. These are ones that have methods // returning decls or qualtypes or nestednamespecifier -- though I'm diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 77df05fbaf05..a11365130734 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9976,9 +9976,9 @@ def err_omp_wrong_ordered_loop_count : Error< "the parameter of the 'ordered' clause must be greater than or equal to the parameter of the 'collapse' clause">; def note_collapse_loop_count : Note< "parameter of the 'collapse' clause">; -def err_omp_grainsize_num_tasks_mutually_exclusive : Error< +def err_omp_clauses_mutually_exclusive : Error< "'%0' and '%1' clause are mutually exclusive and may not appear on the same directive">; -def note_omp_previous_grainsize_num_tasks : Note< +def note_omp_previous_clause : Note< "'%0' clause is specified here">; def err_omp_hint_clause_no_name : Error< "the name of the construct must be specified in presence of 'hint' clause">; @@ -10150,6 +10150,8 @@ def note_omp_flush_order_clause_here : Note< def err_omp_non_lvalue_in_map_or_motion_clauses: Error< "expected addressable lvalue in '%0' clause" >; +def err_omp_event_var_expected : Error< + "expected variable of the 'omp_event_handle_t' type%select{|, not %1}0">; } // end of OpenMP category let CategoryName = "Related Result Type Issue" in { diff --git a/clang/include/clang/Basic/OpenMPKinds.def b/clang/include/clang/Basic/OpenMPKinds.def index 70f962427e36..e6a4aa1d1f58 100644 --- a/clang/include/clang/Basic/OpenMPKinds.def +++ b/clang/include/clang/Basic/OpenMPKinds.def @@ -277,6 +277,7 @@ OPENMP_CLAUSE(nontemporal, OMPNontemporalClause) OPENMP_CLAUSE(order, OMPOrderClause) OPENMP_CLAUSE(depobj, OMPDepobjClause) OPENMP_CLAUSE(destroy, OMPDestroyClause) +OPENMP_CLAUSE(detach, OMPDetachClause) // Clauses allowed for OpenMP directive 'parallel'. OPENMP_PARALLEL_CLAUSE(if) @@ -471,6 +472,7 @@ OPENMP_TASK_CLAUSE(depend) OPENMP_TASK_CLAUSE(priority) OPENMP_TASK_CLAUSE(in_reduction) OPENMP_TASK_CLAUSE(allocate) +OPENMP_TASK_CLAUSE(detach) // Clauses allowed for OpenMP directive 'atomic'. OPENMP_ATOMIC_CLAUSE(read) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 121ceb7e5d36..f29e4f3c227c 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -10364,6 +10364,10 @@ public: OMPClause *ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); + /// Called on well-formed 'detach' clause. + OMPClause *ActOnOpenMPDetachClause(Expr *Evt, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); OMPClause *ActOnOpenMPSimpleClause(OpenMPClauseKind Kind, unsigned Argument, diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index e68a5d6820a9..b01aae433763 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -145,6 +145,7 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) { case OMPC_nontemporal: case OMPC_order: case OMPC_destroy: + case OMPC_detach: break; } @@ -231,6 +232,7 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C) case OMPC_nontemporal: case OMPC_order: case OMPC_destroy: + case OMPC_detach: break; } @@ -1294,6 +1296,12 @@ void OMPClausePrinter::VisitOMPCollapseClause(OMPCollapseClause *Node) { OS << ")"; } +void OMPClausePrinter::VisitOMPDetachClause(OMPDetachClause *Node) { + OS << "detach("; + Node->getEventHandler()->printPretty(OS, nullptr, Policy, 0); + OS << ")"; +} + void OMPClausePrinter::VisitOMPDefaultClause(OMPDefaultClause *Node) { OS << "default(" << getOpenMPSimpleClauseTypeName(OMPC_default, diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 9f1198370235..8d43491ea8f4 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -472,6 +472,11 @@ void OMPClauseProfiler::VisitOMPCollapseClause(const OMPCollapseClause *C) { Profiler->VisitStmt(C->getNumForLoops()); } +void OMPClauseProfiler::VisitOMPDetachClause(const OMPDetachClause *C) { + if (Expr *Evt = C->getEventHandler()) + Profiler->VisitStmt(Evt); +} + void OMPClauseProfiler::VisitOMPDefaultClause(const OMPDefaultClause *C) { } void OMPClauseProfiler::VisitOMPProcBindClause(const OMPProcBindClause *C) { } diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index 5ecc24647e7c..a6e2b9dbf1a1 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -207,6 +207,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, case OMPC_match: case OMPC_nontemporal: case OMPC_destroy: + case OMPC_detach: break; } llvm_unreachable("Invalid OpenMP simple clause kind"); @@ -432,6 +433,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, case OMPC_match: case OMPC_nontemporal: case OMPC_destroy: + case OMPC_detach: break; } llvm_unreachable("Invalid OpenMP simple clause kind"); @@ -554,6 +556,8 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, } break; case OMPD_task: + if (OpenMPVersion < 50 && CKind == OMPC_detach) + return false; switch (CKind) { #define OPENMP_TASK_CLAUSE(Name) \ case OMPC_##Name: \ diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index e3dd49021644..74fabb1ba04e 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -4615,6 +4615,7 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind, case OMPC_nontemporal: case OMPC_order: case OMPC_destroy: + case OMPC_detach: llvm_unreachable("Clause is not allowed in 'omp atomic'."); } } diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 1da884f657a0..86c5996683bd 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -2340,7 +2340,7 @@ bool Parser::ParseOpenMPSimpleVarList( /// from-clause | is_device_ptr-clause | task_reduction-clause | /// in_reduction-clause | allocator-clause | allocate-clause | /// acq_rel-clause | acquire-clause | release-clause | relaxed-clause | -/// depobj-clause | destroy-clause +/// depobj-clause | destroy-clause | detach-clause /// OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, bool FirstClause) { @@ -2372,6 +2372,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_hint: case OMPC_allocator: case OMPC_depobj: + case OMPC_detach: // OpenMP [2.5, Restrictions] // At most one num_threads clause can appear on the directive. // OpenMP [2.8.1, simd construct, Restrictions] @@ -2394,6 +2395,8 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, // At most one num_tasks clause can appear on the directive. // OpenMP [2.11.3, allocate Directive, Restrictions] // At most one allocator clause can appear on the directive. + // OpenMP 5.0, 2.10.1 task Construct, Restrictions. + // At most one detach clause can appear on the directive. if (!FirstClause) { Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0; @@ -2552,7 +2555,8 @@ ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName, /// Parsing of OpenMP clauses with single expressions like 'final', /// 'collapse', 'safelen', 'num_threads', 'simdlen', 'num_teams', -/// 'thread_limit', 'simdlen', 'priority', 'grainsize', 'num_tasks' or 'hint'. +/// 'thread_limit', 'simdlen', 'priority', 'grainsize', 'num_tasks', 'hint' or +/// 'detach'. /// /// final-clause: /// 'final' '(' expression ')' @@ -2584,6 +2588,9 @@ ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName, /// allocator-clause: /// 'allocator' '(' expression ')' /// +/// detach-clause: +/// 'detach' '(' event-handler-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 898f658fcf9c..825dac9f14c8 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -270,6 +270,8 @@ private: QualType OMPAllocatorHandleT; /// omp_depend_t type. QualType OMPDependT; + /// omp_event_handle_t type. + QualType OMPEventHandleT; /// Expression for the predefined allocators. Expr *OMPPredefinedAllocators[OMPAllocateDeclAttr::OMPUserDefinedMemAlloc] = { nullptr}; @@ -298,6 +300,11 @@ public: /// Gets omp_depend_t type. QualType getOMPDependT() const { return OMPDependT; } + /// Sets omp_event_handle_t type. + void setOMPEventHandleT(QualType Ty) { OMPEventHandleT = Ty; } + /// Gets omp_event_handle_t type. + QualType getOMPEventHandleT() const { return OMPEventHandleT; } + bool isClauseParsingMode() const { return ClauseKindMode != OMPC_unknown; } OpenMPClauseKind getClauseParsingMode() const { assert(isClauseParsingMode() && "Must be in clause parsing mode."); @@ -5090,6 +5097,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( break; continue; case OMPC_schedule: + case OMPC_detach: break; case OMPC_grainsize: case OMPC_num_tasks: @@ -8619,12 +8627,41 @@ Sema::ActOnOpenMPParallelSectionsDirective(ArrayRef Clauses, Context, StartLoc, EndLoc, Clauses, AStmt, DSAStack->isCancelRegion()); } +/// detach and mergeable clauses are mutially exclusive, check for it. +static bool checkDetachMergeableClauses(Sema &S, + ArrayRef Clauses) { + const OMPClause *PrevClause = nullptr; + bool ErrorFound = false; + for (const OMPClause *C : Clauses) { + if (C->getClauseKind() == OMPC_detach || + C->getClauseKind() == OMPC_mergeable) { + if (!PrevClause) { + PrevClause = C; + } else if (PrevClause->getClauseKind() != C->getClauseKind()) { + S.Diag(C->getBeginLoc(), diag::err_omp_clauses_mutually_exclusive) + << getOpenMPClauseName(C->getClauseKind()) + << getOpenMPClauseName(PrevClause->getClauseKind()); + S.Diag(PrevClause->getBeginLoc(), diag::note_omp_previous_clause) + << getOpenMPClauseName(PrevClause->getClauseKind()); + ErrorFound = true; + } + } + } + return ErrorFound; +} + StmtResult Sema::ActOnOpenMPTaskDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { if (!AStmt) return StmtError(); + // OpenMP 5.0, 2.10.1 task Construct + // If a detach clause appears on the directive, then a mergeable clause cannot + // appear on the same directive. + if (checkDetachMergeableClauses(*this, Clauses)) + return StmtError(); + auto *CS = cast(AStmt); // 1.2.2 OpenMP Language Terminology // Structured block - An executable statement with a single entry at the @@ -9884,12 +9921,10 @@ static bool checkGrainsizeNumTasksClauses(Sema &S, if (!PrevClause) PrevClause = C; else if (PrevClause->getClauseKind() != C->getClauseKind()) { - S.Diag(C->getBeginLoc(), - diag::err_omp_grainsize_num_tasks_mutually_exclusive) + S.Diag(C->getBeginLoc(), diag::err_omp_clauses_mutually_exclusive) << getOpenMPClauseName(C->getClauseKind()) << getOpenMPClauseName(PrevClause->getClauseKind()); - S.Diag(PrevClause->getBeginLoc(), - diag::note_omp_previous_grainsize_num_tasks) + S.Diag(PrevClause->getBeginLoc(), diag::note_omp_previous_clause) << getOpenMPClauseName(PrevClause->getClauseKind()); ErrorFound = true; } @@ -11027,6 +11062,9 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_depobj: Res = ActOnOpenMPDepobjClause(Expr, StartLoc, LParenLoc, EndLoc); break; + case OMPC_detach: + Res = ActOnOpenMPDetachClause(Expr, StartLoc, LParenLoc, EndLoc); + break; case OMPC_if: case OMPC_default: case OMPC_proc_bind: @@ -11806,6 +11844,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_nontemporal: case OMPC_order: case OMPC_destroy: + case OMPC_detach: llvm_unreachable("Unexpected OpenMP clause."); } return CaptureRegion; @@ -12242,6 +12281,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_match: case OMPC_nontemporal: case OMPC_destroy: + case OMPC_detach: llvm_unreachable("Clause is not allowed."); } return Res; @@ -12459,6 +12499,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_nontemporal: case OMPC_order: case OMPC_destroy: + case OMPC_detach: llvm_unreachable("Clause is not allowed."); } return Res; @@ -12688,6 +12729,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_match: case OMPC_nontemporal: case OMPC_order: + case OMPC_detach: llvm_unreachable("Clause is not allowed."); } return Res; @@ -12943,6 +12985,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause( case OMPC_match: case OMPC_order: case OMPC_destroy: + case OMPC_detach: llvm_unreachable("Clause is not allowed."); } return Res; @@ -17266,6 +17309,56 @@ OMPClause *Sema::ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc, OMPHintClause(HintExpr.get(), StartLoc, LParenLoc, EndLoc); } +/// Tries to find omp_event_handle_t type. +static bool findOMPEventHandleT(Sema &S, SourceLocation Loc, + DSAStackTy *Stack) { + QualType OMPEventHandleT = Stack->getOMPEventHandleT(); + if (!OMPEventHandleT.isNull()) + return true; + IdentifierInfo *II = &S.PP.getIdentifierTable().get("omp_event_handle_t"); + ParsedType PT = S.getTypeName(*II, Loc, S.getCurScope()); + if (!PT.getAsOpaquePtr() || PT.get().isNull()) { + S.Diag(Loc, diag::err_omp_implied_type_not_found) << "omp_event_handle_t"; + return false; + } + Stack->setOMPEventHandleT(PT.get()); + return true; +} + +OMPClause *Sema::ActOnOpenMPDetachClause(Expr *Evt, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + if (!Evt->isValueDependent() && !Evt->isTypeDependent() && + !Evt->isInstantiationDependent() && + !Evt->containsUnexpandedParameterPack()) { + if (!findOMPEventHandleT(*this, Evt->getExprLoc(), DSAStack)) + return nullptr; + // OpenMP 5.0, 2.10.1 task Construct. + // event-handle is a variable of the omp_event_handle_t type. + auto *Ref = dyn_cast(Evt->IgnoreParenImpCasts()); + if (!Ref) { + Diag(Evt->getExprLoc(), diag::err_omp_event_var_expected) + << 0 << Evt->getSourceRange(); + return nullptr; + } + auto *VD = dyn_cast_or_null(Ref->getDecl()); + if (!VD) { + Diag(Evt->getExprLoc(), diag::err_omp_event_var_expected) + << 0 << Evt->getSourceRange(); + return nullptr; + } + if (!Context.hasSameUnqualifiedType(DSAStack->getOMPEventHandleT(), + VD->getType()) || + VD->getType().isConstant(Context)) { + Diag(Evt->getExprLoc(), diag::err_omp_event_var_expected) + << 1 << VD->getType() << Evt->getSourceRange(); + return nullptr; + } + } + + return new (Context) OMPDetachClause(Evt, StartLoc, LParenLoc, EndLoc); +} + OMPClause *Sema::ActOnOpenMPDistScheduleClause( OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 97600dcc7a84..c7e90ad982ef 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -1950,6 +1950,16 @@ public: return getSema().ActOnOpenMPHintClause(Hint, StartLoc, LParenLoc, EndLoc); } + /// Build a new OpenMP 'detach' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPDetachClause(Expr *Evt, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPDetachClause(Evt, StartLoc, LParenLoc, EndLoc); + } + /// Build a new OpenMP 'dist_schedule' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. @@ -8779,6 +8789,19 @@ TreeTransform::TransformOMPOrderedClause(OMPOrderedClause *C) { C->getLParenLoc(), E.get()); } +template +OMPClause * +TreeTransform::TransformOMPDetachClause(OMPDetachClause *C) { + ExprResult E; + if (Expr *Evt = C->getEventHandler()) { + E = getDerived().TransformExpr(Evt); + if (E.isInvalid()) + return nullptr; + } + return getDerived().RebuildOMPDetachClause(E.get(), C->getBeginLoc(), + C->getLParenLoc(), C->getEndLoc()); +} + template OMPClause * TreeTransform::TransformOMPNowaitClause(OMPNowaitClause *C) { diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 096a741e7bb9..9f6bfebeabcb 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -11830,6 +11830,9 @@ OMPClause *OMPClauseReader::readClause() { case OMPC_destroy: C = new (Context) OMPDestroyClause(); break; + case OMPC_detach: + C = new (Context) OMPDetachClause(); + break; } assert(C && "Unknown OMPClause type"); @@ -11928,6 +11931,11 @@ void OMPClauseReader::VisitOMPOrderedClause(OMPOrderedClause *C) { C->setLParenLoc(Record.readSourceLocation()); } +void OMPClauseReader::VisitOMPDetachClause(OMPDetachClause *C) { + C->setEventHandler(Record.readSubExpr()); + C->setLParenLoc(Record.readSourceLocation()); +} + void OMPClauseReader::VisitOMPNowaitClause(OMPNowaitClause *) {} void OMPClauseReader::VisitOMPUntiedClause(OMPUntiedClause *) {} diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 1278841a15a2..b549fe9df016 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -6096,6 +6096,11 @@ void OMPClauseWriter::VisitOMPCollapseClause(OMPCollapseClause *C) { Record.AddSourceLocation(C->getLParenLoc()); } +void OMPClauseWriter::VisitOMPDetachClause(OMPDetachClause *C) { + Record.AddStmt(C->getEventHandler()); + Record.AddSourceLocation(C->getLParenLoc()); +} + void OMPClauseWriter::VisitOMPDefaultClause(OMPDefaultClause *C) { Record.push_back(unsigned(C->getDefaultKind())); Record.AddSourceLocation(C->getLParenLoc()); diff --git a/clang/test/OpenMP/task_ast_print.cpp b/clang/test/OpenMP/task_ast_print.cpp index f8a669523a5a..73323c6c2ae5 100644 --- a/clang/test/OpenMP/task_ast_print.cpp +++ b/clang/test/OpenMP/task_ast_print.cpp @@ -11,6 +11,7 @@ #define HEADER typedef void *omp_depend_t; +typedef unsigned long omp_event_handle_t; void foo() {} @@ -31,8 +32,9 @@ protected: public: S7(typename T::type v) : a(v) { omp_depend_t x; + omp_event_handle_t evt; #pragma omp taskgroup allocate(b) task_reduction(+:b) -#pragma omp task private(a) private(this->a) private(T::a) in_reduction(+:this->b) allocate(b) depend(depobj:x) +#pragma omp task private(a) private(this->a) private(T::a) in_reduction(+:this->b) allocate(b) depend(depobj:x) detach(evt) for (int k = 0; k < a.a; ++k) ++this->a.a; } @@ -45,7 +47,7 @@ public: }; // CHECK: #pragma omp taskgroup allocate(this->b) task_reduction(+: this->b) -// CHECK: #pragma omp task private(this->a) private(this->a) private(T::a) in_reduction(+: this->b) allocate(this->b) depend(depobj : x){{$}} +// CHECK: #pragma omp task private(this->a) private(this->a) private(T::a) in_reduction(+: this->b) allocate(this->b) depend(depobj : x) detach(evt){{$}} // CHECK: #pragma omp task private(this->a) private(this->a) // CHECK: #pragma omp task private(this->a) private(this->a) private(this->S1::a) @@ -96,7 +98,8 @@ T tmain(T argc, T *argv) { S s; T arr[argc]; omp_depend_t x; -#pragma omp task untied depend(in : argc, argv[b:argc], arr[:]) if (task : argc > 0) depend(depobj: x) + omp_event_handle_t evt; +#pragma omp task untied depend(in : argc, argv[b:argc], arr[:]) if (task : argc > 0) depend(depobj: x) detach(evt) a = 2; #pragma omp task default(none), private(argc, b) firstprivate(argv) shared(d) if (argc > 0) final(S::TS > 0) priority(argc) foo(); @@ -112,7 +115,8 @@ T tmain(T argc, T *argv) { // CHECK-NEXT: S s; // CHECK-NEXT: T arr[argc]; // CHECK-NEXT: omp_depend_t x; -// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc],arr[:]) if(task: argc > 0) depend(depobj : x) +// CHECK-NEXT: omp_event_handle_t evt; +// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc],arr[:]) if(task: argc > 0) depend(depobj : x) detach(evt) // CHECK-NEXT: a = 2; // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S::TS > 0) priority(argc) // CHECK-NEXT: foo() @@ -125,7 +129,8 @@ T tmain(T argc, T *argv) { // CHECK-NEXT: S s; // CHECK-NEXT: int arr[argc]; // CHECK-NEXT: omp_depend_t x; -// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc],arr[:]) if(task: argc > 0) depend(depobj : x) +// CHECK-NEXT: omp_event_handle_t evt; +// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc],arr[:]) if(task: argc > 0) depend(depobj : x) detach(evt) // CHECK-NEXT: a = 2; // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S::TS > 0) priority(argc) // CHECK-NEXT: foo() @@ -138,7 +143,8 @@ T tmain(T argc, T *argv) { // CHECK-NEXT: S s; // CHECK-NEXT: long arr[argc]; // CHECK-NEXT: omp_depend_t x; -// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc],arr[:]) if(task: argc > 0) depend(depobj : x) +// CHECK-NEXT: omp_event_handle_t evt; +// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc],arr[:]) if(task: argc > 0) depend(depobj : x) detach(evt) // CHECK-NEXT: a = 2; // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S::TS > 0) priority(argc) // CHECK-NEXT: foo() @@ -154,6 +160,7 @@ int main(int argc, char **argv) { static int a; int arr[10], arr1[argc]; omp_depend_t y; + omp_event_handle_t evt; #pragma omp threadprivate(a) Enum ee; // CHECK: Enum ee; @@ -162,9 +169,9 @@ int main(int argc, char **argv) { a = 2; // CHECK-NEXT: a = 2; #pragma omp taskgroup task_reduction(min: arr1) -#pragma omp task default(none), private(argc, b) firstprivate(argv) if (argc > 0) final(a > 0) depend(inout : a, argv[:argc],arr[:a]) priority(23) in_reduction(min: arr1) +#pragma omp task default(none), private(argc, b) firstprivate(argv, evt) if (argc > 0) final(a > 0) depend(inout : a, argv[:argc],arr[:a]) priority(23) in_reduction(min: arr1), detach(evt) // CHECK-NEXT: #pragma omp taskgroup task_reduction(min: arr1) - // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) if(argc > 0) final(a > 0) depend(inout : a,argv[:argc],arr[:a]) priority(23) in_reduction(min: arr1) + // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv,evt) if(argc > 0) final(a > 0) depend(inout : a,argv[:argc],arr[:a]) priority(23) in_reduction(min: arr1) detach(evt) foo(); // CHECK-NEXT: foo(); #pragma omp taskgroup task_reduction(min: arr1) diff --git a/clang/test/OpenMP/task_messages.cpp b/clang/test/OpenMP/task_messages.cpp index 062125f5f6ea..cec3bc0c1980 100644 --- a/clang/test/OpenMP/task_messages.cpp +++ b/clang/test/OpenMP/task_messages.cpp @@ -1,6 +1,8 @@ -// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -std=c++11 -o - %s -Wuninitialized +// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp-version=45 -fopenmp -ferror-limit 100 -std=c++11 -o - %s -Wuninitialized +// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp-version=50 -fopenmp -ferror-limit 100 -std=c++11 -o - %s -Wuninitialized -// RUN: %clang_cc1 -verify -fopenmp-simd -ferror-limit 100 -std=c++11 -o - %s -Wuninitialized +// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp-version=45 -fopenmp-simd -ferror-limit 100 -std=c++11 -o - %s -Wuninitialized +// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp-version=50 -fopenmp-simd -ferror-limit 100 -std=c++11 -o - %s -Wuninitialized void xxx(int argc) { int x; // expected-note {{initialize the variable 'x' to silence this warning}} @@ -9,8 +11,12 @@ void xxx(int argc) { } void foo() { +#pragma omp task detach(0) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} omp50-error {{'omp_event_handle_t' type not found; include }} + ; } +typedef unsigned long omp_event_handle_t; + #pragma omp task // expected-error {{unexpected OpenMP directive '#pragma omp task'}} class S { @@ -125,6 +131,22 @@ int foo() { // expected-error@+1 {{directive '#pragma omp task' cannot contain more than one 'mergeable' clause}} #pragma omp task mergeable mergeable ++r; + volatile omp_event_handle_t evt; + const omp_event_handle_t cevt = 0; + omp_event_handle_t sevt; + omp_event_handle_t &revt = sevt; +#pragma omp task detach // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} expected-error {{expected '(' after 'detach'}} +#pragma omp task detach( // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp task detach() // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} expected-error {{expected expression}} +#pragma omp task detach(a) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} omp50-error {{expected variable of the 'omp_event_handle_t' type, not 'int'}} omp50-error {{expected variable of the 'omp_event_handle_t' type, not 'S'}} + ; +#pragma omp task detach(evt) detach(evt) // omp45-error 2 {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} expected-error {{directive '#pragma omp task' cannot contain more than one 'detach' clause}} +#pragma omp task detach(cevt) detach(revt) // omp45-error 2 {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} expected-error {{directive '#pragma omp task' cannot contain more than one 'detach' clause}} omp50-error {{expected variable of the 'omp_event_handle_t' type, not 'const omp_event_handle_t' (aka 'const unsigned long')}} omp50-error {{expected variable of the 'omp_event_handle_t' type, not 'omp_event_handle_t &' (aka 'unsigned long &')}} +#pragma omp task detach(evt) mergeable // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} omp50-error {{'mergeable' and 'detach' clause are mutually exclusive and may not appear on the same directive}} omp50-note {{'detach' clause is specified here}} + ; +#pragma omp task mergeable detach(evt) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} omp50-error {{'detach' and 'mergeable' clause are mutually exclusive and may not appear on the same directive}} omp50-note {{'mergeable' clause is specified here}} +#pragma omp task detach(-evt) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} omp50-error {{expected variable of the 'omp_event_handle_t' type}} + ; return a + b; } @@ -290,6 +312,21 @@ L2: // expected-error@+1 {{directive '#pragma omp task' cannot contain more than one 'mergeable' clause}} #pragma omp task mergeable mergeable ++r; + volatile omp_event_handle_t evt; + omp_event_handle_t sevt; + const omp_event_handle_t cevt = evt; + omp_event_handle_t &revt = sevt; +#pragma omp task detach // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} expected-error {{expected '(' after 'detach'}} +#pragma omp task detach( // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp task detach() // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} expected-error {{expected expression}} +#pragma omp task detach(a) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} omp50-error {{expected variable of the 'omp_event_handle_t' type, not 'int'}} +#pragma omp task detach(evt) detach(evt) // omp45-error 2 {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} expected-error {{directive '#pragma omp task' cannot contain more than one 'detach' clause}} +#pragma omp task detach(cevt) detach(revt) // omp45-error 2 {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} expected-error {{directive '#pragma omp task' cannot contain more than one 'detach' clause}} omp50-error {{expected variable of the 'omp_event_handle_t' type, not 'const omp_event_handle_t' (aka 'const unsigned long')}} omp50-error {{expected variable of the 'omp_event_handle_t' type, not 'omp_event_handle_t &' (aka 'unsigned long &')}} +#pragma omp task detach(evt) mergeable // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} omp50-error {{'mergeable' and 'detach' clause are mutually exclusive and may not appear on the same directive}} omp50-note {{'detach' clause is specified here}} + ; +#pragma omp task mergeable detach(evt) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} omp50-error {{'detach' and 'mergeable' clause are mutually exclusive and may not appear on the same directive}} omp50-note {{'mergeable' clause is specified here}} +#pragma omp task detach(-evt) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} omp50-error {{expected variable of the 'omp_event_handle_t' type}} + ; // expected-note@+2 {{in instantiation of function template specialization 'foo' requested here}} // expected-note@+1 {{in instantiation of function template specialization 'foo' requested here}} return foo() + foo(); diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 62dc0e2b8f92..df5530c73c6d 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -2220,6 +2220,10 @@ void OMPClauseEnqueue::VisitOMPOrderedClause(const OMPOrderedClause *C) { Visitor->AddStmt(C->getNumForLoops()); } +void OMPClauseEnqueue::VisitOMPDetachClause(const OMPDetachClause *C) { + Visitor->AddStmt(C->getEventHandler()); +} + void OMPClauseEnqueue::VisitOMPNowaitClause(const OMPNowaitClause *) {} void OMPClauseEnqueue::VisitOMPUntiedClause(const OMPUntiedClause *) {}