From a2891f255bc73915bb85b7516f4a6ad4e400bb09 Mon Sep 17 00:00:00 2001 From: Alexey Bataev <a.bataev@hotmail.com> Date: Tue, 23 Jun 2015 14:25:19 +0000 Subject: [PATCH] [OPENMP] Initial support for 'depend' clause (4.0). Parsing and sema analysis (without support for array sections in arguments) for 'depend' clause (used in 'task' directive, OpenMP 4.0). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@240409 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DataRecursiveASTVisitor.h | 6 ++ include/clang/AST/OpenMPClause.h | 88 +++++++++++++++++++++ include/clang/AST/RecursiveASTVisitor.h | 6 ++ include/clang/Basic/DiagnosticSemaKinds.td | 2 + include/clang/Basic/OpenMPKinds.def | 11 +++ include/clang/Basic/OpenMPKinds.h | 8 ++ include/clang/Sema/Sema.h | 20 +++-- lib/AST/Stmt.cpp | 24 ++++++ lib/AST/StmtPrinter.cpp | 11 +++ lib/AST/StmtProfile.cpp | 3 + lib/Basic/OpenMPKinds.cpp | 14 ++++ lib/CodeGen/CGStmtOpenMP.cpp | 1 + lib/Parse/ParseOpenMP.cpp | 35 +++++++- lib/Sema/SemaOpenMP.cpp | 74 ++++++++++++++++- lib/Sema/TreeTransform.h | 29 +++++++ lib/Serialization/ASTReaderStmt.cpp | 16 ++++ lib/Serialization/ASTWriterStmt.cpp | 10 +++ test/OpenMP/task_ast_print.cpp | 16 ++-- test/OpenMP/task_depend_messages.cpp | 39 +++++++++ tools/libclang/CIndex.cpp | 3 + 20 files changed, 397 insertions(+), 19 deletions(-) create mode 100644 test/OpenMP/task_depend_messages.cpp diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h index ef881765933..a78fe44ff2d 100644 --- a/include/clang/AST/DataRecursiveASTVisitor.h +++ b/include/clang/AST/DataRecursiveASTVisitor.h @@ -2622,6 +2622,12 @@ bool RecursiveASTVisitor<Derived>::VisitOMPFlushClause(OMPFlushClause *C) { return true; } +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPDependClause(OMPDependClause *C) { + TRY_TO(VisitOMPClauseList(C)); + 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/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h index 386c8dd3ee9..fcfa1dd4753 100644 --- a/include/clang/AST/OpenMPClause.h +++ b/include/clang/AST/OpenMPClause.h @@ -2212,6 +2212,94 @@ public: } }; +/// \brief This represents implicit clause 'depend' for the '#pragma omp task' +/// directive. +/// +/// \code +/// #pragma omp task depend(in:a,b) +/// \endcode +/// In this example directive '#pragma omp task' with clause 'depend' with the +/// variables 'a' and 'b' with dependency 'in'. +/// +class OMPDependClause : public OMPVarListClause<OMPDependClause> { + friend class OMPClauseReader; + /// \brief Dependency type (one of in, out, inout). + OpenMPDependClauseKind DepKind; + /// \brief Dependency type location. + SourceLocation DepLoc; + /// \brief Colon location. + SourceLocation ColonLoc; + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + OMPDependClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, unsigned N) + : OMPVarListClause<OMPDependClause>(OMPC_depend, StartLoc, LParenLoc, + EndLoc, N), + DepKind(OMPC_DEPEND_unknown) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPDependClause(unsigned N) + : OMPVarListClause<OMPDependClause>(OMPC_depend, SourceLocation(), + SourceLocation(), SourceLocation(), + N), + DepKind(OMPC_DEPEND_unknown) {} + /// \brief Set dependency kind. + void setDependencyKind(OpenMPDependClauseKind K) { DepKind = K; } + + /// \brief Set dependency kind and its location. + void setDependencyLoc(SourceLocation Loc) { DepLoc = Loc; } + + /// \brief Set colon location. + void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; } + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param DepKind Dependency type. + /// \param DepLoc Location of the dependency type. + /// \param ColonLoc Colon location. + /// \param VL List of references to the variables. + /// + static OMPDependClause * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, OpenMPDependClauseKind DepKind, + SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL); + /// \brief Creates an empty clause with \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPDependClause *CreateEmpty(const ASTContext &C, unsigned N); + + /// \brief Get dependency type. + OpenMPDependClauseKind getDependencyKind() const { return DepKind; } + /// \brief Get dependency type location. + SourceLocation getDependencyLoc() const { return DepLoc; } + /// \brief Get colon location. + SourceLocation getColonLoc() const { return ColonLoc; } + + StmtRange children() { + return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()), + reinterpret_cast<Stmt **>(varlist_end())); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_depend; + } +}; + } // end namespace clang #endif diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 95d77307318..b01d17bb325 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -2655,6 +2655,12 @@ bool RecursiveASTVisitor<Derived>::VisitOMPFlushClause(OMPFlushClause *C) { return true; } +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPDependClause(OMPDependClause *C) { + TRY_TO(VisitOMPClauseList(C)); + 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/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 779f43ea1f1..de18e725daa 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -7413,6 +7413,8 @@ def err_omp_unexpected_clause_value : Error< "expected %0 in OpenMP clause '%1'">; def err_omp_expected_var_name : Error< "expected variable name">; +def err_omp_expected_var_name_or_array_item : Error< + "expected variable name, array element or array section">; def note_omp_task_predetermined_firstprivate_here : Note< "predetermined as a firstprivate in a task construct here">; def err_omp_clause_ref_type_arg : Error< diff --git a/include/clang/Basic/OpenMPKinds.def b/include/clang/Basic/OpenMPKinds.def index b09f012c431..c63c05b01cc 100644 --- a/include/clang/Basic/OpenMPKinds.def +++ b/include/clang/Basic/OpenMPKinds.def @@ -69,6 +69,9 @@ #ifndef OPENMP_SCHEDULE_KIND #define OPENMP_SCHEDULE_KIND(Name) #endif +#ifndef OPENMP_DEPEND_KIND +#define OPENMP_DEPEND_KIND(Name) +#endif // OpenMP directives. OPENMP_DIRECTIVE(threadprivate) @@ -123,6 +126,7 @@ OPENMP_CLAUSE(write, OMPWriteClause) OPENMP_CLAUSE(update, OMPUpdateClause) OPENMP_CLAUSE(capture, OMPCaptureClause) OPENMP_CLAUSE(seq_cst, OMPSeqCstClause) +OPENMP_CLAUSE(depend, OMPDependClause) // Clauses allowed for OpenMP directive 'parallel'. OPENMP_PARALLEL_CLAUSE(if) @@ -195,6 +199,11 @@ OPENMP_SCHEDULE_KIND(guided) OPENMP_SCHEDULE_KIND(auto) OPENMP_SCHEDULE_KIND(runtime) +// Static attributes for 'depend' clause. +OPENMP_DEPEND_KIND(in) +OPENMP_DEPEND_KIND(out) +OPENMP_DEPEND_KIND(inout) + // Clauses allowed for OpenMP directive 'parallel for'. OPENMP_PARALLEL_FOR_CLAUSE(if) OPENMP_PARALLEL_FOR_CLAUSE(num_threads) @@ -248,6 +257,7 @@ OPENMP_TASK_CLAUSE(firstprivate) OPENMP_TASK_CLAUSE(shared) OPENMP_TASK_CLAUSE(untied) OPENMP_TASK_CLAUSE(mergeable) +OPENMP_TASK_CLAUSE(depend) // Clauses allowed for OpenMP directive 'atomic'. OPENMP_ATOMIC_CLAUSE(read) @@ -268,6 +278,7 @@ OPENMP_TEAMS_CLAUSE(firstprivate) OPENMP_TEAMS_CLAUSE(shared) OPENMP_TEAMS_CLAUSE(reduction) +#undef OPENMP_DEPEND_KIND #undef OPENMP_SCHEDULE_KIND #undef OPENMP_PROC_BIND_KIND #undef OPENMP_DEFAULT_KIND diff --git a/include/clang/Basic/OpenMPKinds.h b/include/clang/Basic/OpenMPKinds.h index e2f115113e2..83939bb079a 100644 --- a/include/clang/Basic/OpenMPKinds.h +++ b/include/clang/Basic/OpenMPKinds.h @@ -62,6 +62,14 @@ enum OpenMPScheduleClauseKind { OMPC_SCHEDULE_unknown }; +/// \brief OpenMP attributes for 'depend' clause. +enum OpenMPDependClauseKind { +#define OPENMP_DEPEND_KIND(Name) \ + OMPC_DEPEND_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPC_DEPEND_unknown +}; + OpenMPDirectiveKind getOpenMPDirectiveKind(llvm::StringRef Str); const char *getOpenMPDirectiveName(OpenMPDirectiveKind Kind); diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 84318c3b942..47b9ee10526 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -7859,13 +7859,13 @@ public: OMPClause *ActOnOpenMPSeqCstClause(SourceLocation StartLoc, SourceLocation EndLoc); - OMPClause * - ActOnOpenMPVarListClause(OpenMPClauseKind Kind, ArrayRef<Expr *> Vars, - Expr *TailExpr, SourceLocation StartLoc, - SourceLocation LParenLoc, SourceLocation ColonLoc, - SourceLocation EndLoc, - CXXScopeSpec &ReductionIdScopeSpec, - const DeclarationNameInfo &ReductionId); + OMPClause *ActOnOpenMPVarListClause( + OpenMPClauseKind Kind, ArrayRef<Expr *> Vars, Expr *TailExpr, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation EndLoc, + CXXScopeSpec &ReductionIdScopeSpec, + const DeclarationNameInfo &ReductionId, OpenMPDependClauseKind DepKind, + SourceLocation DepLoc); /// \brief Called on well-formed 'private' clause. OMPClause *ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, @@ -7922,6 +7922,12 @@ public: SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); + /// \brief Called on well-formed 'depend' clause. + OMPClause * + ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, SourceLocation DepLoc, + SourceLocation ColonLoc, ArrayRef<Expr *> VarList, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc); /// \brief The kind of conversion being performed. enum CheckedConversionKind { diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 6f4a89fee39..8694cf3e22c 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -1579,6 +1579,30 @@ OMPFlushClause *OMPFlushClause::CreateEmpty(const ASTContext &C, unsigned N) { return new (Mem) OMPFlushClause(N); } +OMPDependClause * +OMPDependClause::Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc, + OpenMPDependClauseKind DepKind, SourceLocation DepLoc, + SourceLocation ColonLoc, ArrayRef<Expr *> VL) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPDependClause), + llvm::alignOf<Expr *>()) + + sizeof(Expr *) * VL.size()); + OMPDependClause *Clause = + new (Mem) OMPDependClause(StartLoc, LParenLoc, EndLoc, VL.size()); + Clause->setVarRefs(VL); + Clause->setDependencyKind(DepKind); + Clause->setDependencyLoc(DepLoc); + Clause->setColonLoc(ColonLoc); + return Clause; +} + +OMPDependClause *OMPDependClause::CreateEmpty(const ASTContext &C, unsigned N) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPDependClause), + llvm::alignOf<Expr *>()) + + sizeof(Expr *) * N); + return new (Mem) OMPDependClause(N); +} + const OMPClause * OMPExecutableDirective::getSingleClause(OpenMPClauseKind K) const { auto &&I = getClausesOfKind(K); diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 658e3dfdeed..a82d104d7aa 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -799,6 +799,17 @@ void OMPClausePrinter::VisitOMPFlushClause(OMPFlushClause *Node) { OS << ")"; } } + +void OMPClausePrinter::VisitOMPDependClause(OMPDependClause *Node) { + if (!Node->varlist_empty()) { + OS << "depend("; + OS << getOpenMPSimpleClauseTypeName(Node->getClauseKind(), + Node->getDependencyKind()) + << " :"; + VisitOMPClauseList(Node, ' '); + OS << ")"; + } +} } //===----------------------------------------------------------------------===// diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 23f8d0c8be7..8a48ee267f0 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -425,6 +425,9 @@ OMPClauseProfiler::VisitOMPCopyprivateClause(const OMPCopyprivateClause *C) { void OMPClauseProfiler::VisitOMPFlushClause(const OMPFlushClause *C) { VisitOMPClauseList(C); } +void OMPClauseProfiler::VisitOMPDependClause(const OMPDependClause *C) { + VisitOMPClauseList(C); +} } void diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp index b2798b7f0fd..e4694b46cd3 100644 --- a/lib/Basic/OpenMPKinds.cpp +++ b/lib/Basic/OpenMPKinds.cpp @@ -91,6 +91,11 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, #define OPENMP_SCHEDULE_KIND(Name) .Case(#Name, OMPC_SCHEDULE_##Name) #include "clang/Basic/OpenMPKinds.def" .Default(OMPC_SCHEDULE_unknown); + case OMPC_depend: + return llvm::StringSwitch<OpenMPDependClauseKind>(Str) +#define OPENMP_DEPEND_KIND(Name) .Case(#Name, OMPC_DEPEND_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_DEPEND_unknown); case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: @@ -152,6 +157,15 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, #define OPENMP_SCHEDULE_KIND(Name) \ case OMPC_SCHEDULE_##Name: \ return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + case OMPC_depend: + switch (Type) { + case OMPC_DEPEND_unknown: + return "unknown"; +#define OPENMP_DEPEND_KIND(Name) \ + case OMPC_DEPEND_##Name: \ + return #Name; #include "clang/Basic/OpenMPKinds.def" } llvm_unreachable("Invalid OpenMP 'schedule' clause type"); diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp index 5e94d56feb5..5d7683d31cd 100644 --- a/lib/CodeGen/CGStmtOpenMP.cpp +++ b/lib/CodeGen/CGStmtOpenMP.cpp @@ -2041,6 +2041,7 @@ static void EmitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind, case OMPC_nowait: case OMPC_untied: case OMPC_threadprivate: + case OMPC_depend: case OMPC_mergeable: llvm_unreachable("Clause is not allowed in 'omp atomic'."); } diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp index a721fcca01c..38efed89264 100644 --- a/lib/Parse/ParseOpenMP.cpp +++ b/lib/Parse/ParseOpenMP.cpp @@ -453,6 +453,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_copyin: case OMPC_copyprivate: case OMPC_flush: + case OMPC_depend: Clause = ParseOpenMPVarListClause(CKind); break; case OMPC_unknown: @@ -674,6 +675,8 @@ static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec, /// 'copyprivate' '(' list ')' /// flush-clause: /// 'flush' '(' list ')' +/// depend-clause: +/// 'depend' '(' in | out | inout : list ')' /// OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) { SourceLocation Loc = Tok.getLocation(); @@ -683,6 +686,9 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) { CXXScopeSpec ReductionIdScopeSpec; UnqualifiedId ReductionId; bool InvalidReductionId = false; + OpenMPDependClauseKind DepKind = OMPC_DEPEND_unknown; + SourceLocation DepLoc; + // Parse '('. BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); if (T.expectAndConsume(diag::err_expected_lparen_after, @@ -706,10 +712,30 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) { } else { Diag(Tok, diag::warn_pragma_expected_colon) << "reduction identifier"; } + } else if (Kind == OMPC_depend) { + // Handle dependency type for depend clause. + ColonProtectionRAIIObject ColonRAII(*this); + DepKind = static_cast<OpenMPDependClauseKind>(getOpenMPSimpleClauseType( + Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "")); + DepLoc = Tok.getLocation(); + + if (DepKind == OMPC_DEPEND_unknown) { + SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + } else { + ConsumeToken(); + } + if (Tok.is(tok::colon)) { + ColonLoc = ConsumeToken(); + } else { + Diag(Tok, diag::warn_pragma_expected_colon) << "dependency type"; + } } SmallVector<Expr *, 5> Vars; - bool IsComma = !InvalidReductionId; + bool IsComma = ((Kind != OMPC_reduction) && (Kind != OMPC_depend)) || + ((Kind == OMPC_reduction) && !InvalidReductionId) || + ((Kind == OMPC_depend) && DepKind != OMPC_DEPEND_unknown); const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned); while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) && Tok.isNot(tok::annot_pragma_openmp_end))) { @@ -753,13 +779,16 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) { // Parse ')'. T.consumeClose(); - if (Vars.empty() || (MustHaveTail && !TailExpr) || InvalidReductionId) + if ((Kind == OMPC_depend && DepKind != OMPC_DEPEND_unknown && Vars.empty()) || + (Kind != OMPC_depend && Vars.empty()) || (MustHaveTail && !TailExpr) || + InvalidReductionId) return nullptr; return Actions.ActOnOpenMPVarListClause( Kind, Vars, TailExpr, Loc, LOpen, ColonLoc, Tok.getLocation(), ReductionIdScopeSpec, ReductionId.isValid() ? Actions.GetNameFromUnqualifiedId(ReductionId) - : DeclarationNameInfo()); + : DeclarationNameInfo(), + DepKind, DepLoc); } diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index 4e45705ca1d..7c1746f90e2 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -4248,6 +4248,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_update: case OMPC_capture: case OMPC_seq_cst: + case OMPC_depend: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } @@ -4462,6 +4463,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_update: case OMPC_capture: case OMPC_seq_cst: + case OMPC_depend: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } @@ -4582,6 +4584,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_update: case OMPC_capture: case OMPC_seq_cst: + case OMPC_depend: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } @@ -4704,6 +4707,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_proc_bind: case OMPC_threadprivate: case OMPC_flush: + case OMPC_depend: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } @@ -4760,7 +4764,8 @@ OMPClause *Sema::ActOnOpenMPVarListClause( OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, - const DeclarationNameInfo &ReductionId) { + const DeclarationNameInfo &ReductionId, OpenMPDependClauseKind DepKind, + SourceLocation DepLoc) { OMPClause *Res = nullptr; switch (Kind) { case OMPC_private: @@ -4796,6 +4801,10 @@ OMPClause *Sema::ActOnOpenMPVarListClause( case OMPC_flush: Res = ActOnOpenMPFlushClause(VarList, StartLoc, LParenLoc, EndLoc); break; + case OMPC_depend: + Res = ActOnOpenMPDependClause(DepKind, DepLoc, ColonLoc, VarList, StartLoc, + LParenLoc, EndLoc); + break; case OMPC_if: case OMPC_final: case OMPC_num_threads: @@ -6346,3 +6355,66 @@ OMPClause *Sema::ActOnOpenMPFlushClause(ArrayRef<Expr *> VarList, return OMPFlushClause::Create(Context, StartLoc, LParenLoc, EndLoc, VarList); } +OMPClause * +Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, + SourceLocation DepLoc, SourceLocation ColonLoc, + ArrayRef<Expr *> VarList, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) { + if (DepKind == OMPC_DEPEND_unknown) { + std::string Values; + std::string Sep(", "); + for (unsigned i = 0; i < OMPC_DEPEND_unknown; ++i) { + Values += "'"; + Values += getOpenMPSimpleClauseTypeName(OMPC_depend, i); + Values += "'"; + switch (i) { + case OMPC_DEPEND_unknown - 2: + Values += " or "; + break; + case OMPC_DEPEND_unknown - 1: + break; + default: + Values += Sep; + break; + } + } + Diag(DepLoc, diag::err_omp_unexpected_clause_value) + << Values << getOpenMPClauseName(OMPC_depend); + return nullptr; + } + SmallVector<Expr *, 8> Vars; + for (auto &RefExpr : VarList) { + assert(RefExpr && "NULL expr in OpenMP shared clause."); + if (isa<DependentScopeDeclRefExpr>(RefExpr)) { + // It will be analyzed later. + Vars.push_back(RefExpr); + continue; + } + + SourceLocation ELoc = RefExpr->getExprLoc(); + // OpenMP [2.11.1.1, Restrictions, p.3] + // A variable that is part of another variable (such as a field of a + // structure) but is not an array element or an array section cannot appear + // in a depend clause. + auto *SimpleExpr = RefExpr->IgnoreParenCasts(); + DeclRefExpr *DE = dyn_cast<DeclRefExpr>(SimpleExpr); + ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr); + if (!RefExpr->IgnoreParenImpCasts()->isLValue() || (!ASE && !DE) || + (DE && !isa<VarDecl>(DE->getDecl())) || + (ASE && !ASE->getBase()->getType()->isAnyPointerType() && + !ASE->getBase()->getType()->isArrayType())) { + Diag(ELoc, diag::err_omp_expected_var_name_or_array_item) + << RefExpr->getSourceRange(); + continue; + } + + Vars.push_back(RefExpr->IgnoreParenImpCasts()); + } + + if (Vars.empty()) + return nullptr; + + return OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc, DepKind, + DepLoc, ColonLoc, Vars); +} + diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 322cb6ccb58..996dd2b0783 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1551,6 +1551,19 @@ public: EndLoc); } + /// \brief Build a new OpenMP 'depend' pseudo clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause * + RebuildOMPDependClause(OpenMPDependClauseKind DepKind, SourceLocation DepLoc, + SourceLocation ColonLoc, ArrayRef<Expr *> VarList, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPDependClause(DepKind, DepLoc, ColonLoc, VarList, + StartLoc, LParenLoc, EndLoc); + } + /// \brief Rebuild the operand to an Objective-C \@synchronized statement. /// /// By default, performs semantic analysis to build the new statement. @@ -7255,6 +7268,22 @@ OMPClause *TreeTransform<Derived>::TransformOMPFlushClause(OMPFlushClause *C) { C->getLParenLoc(), C->getLocEnd()); } +template <typename Derived> +OMPClause * +TreeTransform<Derived>::TransformOMPDependClause(OMPDependClause *C) { + llvm::SmallVector<Expr *, 16> Vars; + Vars.reserve(C->varlist_size()); + for (auto *VE : C->varlists()) { + ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE)); + if (EVar.isInvalid()) + return nullptr; + Vars.push_back(EVar.get()); + } + return getDerived().RebuildOMPDependClause( + C->getDependencyKind(), C->getDependencyLoc(), C->getColonLoc(), Vars, + C->getLocStart(), C->getLParenLoc(), C->getLocEnd()); +} + //===----------------------------------------------------------------------===// // Expression transformation //===----------------------------------------------------------------------===// diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index c15f6b0b552..f64d856a628 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -1785,6 +1785,9 @@ OMPClause *OMPClauseReader::readClause() { case OMPC_flush: C = OMPFlushClause::CreateEmpty(Context, Record[Idx++]); break; + case OMPC_depend: + C = OMPDependClause::CreateEmpty(Context, Record[Idx++]); + break; } Visit(C); C->setLocStart(Reader->ReadSourceLocation(Record, Idx)); @@ -2049,6 +2052,19 @@ void OMPClauseReader::VisitOMPFlushClause(OMPFlushClause *C) { C->setVarRefs(Vars); } +void OMPClauseReader::VisitOMPDependClause(OMPDependClause *C) { + C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); + C->setDependencyKind(static_cast<OpenMPDependClauseKind>(Record[Idx++])); + C->setDependencyLoc(Reader->ReadSourceLocation(Record, Idx)); + C->setColonLoc(Reader->ReadSourceLocation(Record, Idx)); + unsigned NumVars = C->varlist_size(); + SmallVector<Expr *, 16> Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader->Reader.ReadSubExpr()); + C->setVarRefs(Vars); +} + //===----------------------------------------------------------------------===// // OpenMP Directives. //===----------------------------------------------------------------------===// diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index a461d3f6639..0f35f0ce8a3 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -1906,6 +1906,16 @@ void OMPClauseWriter::VisitOMPFlushClause(OMPFlushClause *C) { Writer->Writer.AddStmt(VE); } +void OMPClauseWriter::VisitOMPDependClause(OMPDependClause *C) { + Record.push_back(C->varlist_size()); + Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); + Record.push_back(C->getDependencyKind()); + Writer->Writer.AddSourceLocation(C->getDependencyLoc(), Record); + Writer->Writer.AddSourceLocation(C->getColonLoc(), Record); + for (auto *VE : C->varlists()) + Writer->Writer.AddStmt(VE); +} + //===----------------------------------------------------------------------===// // OpenMP Directives. //===----------------------------------------------------------------------===// diff --git a/test/OpenMP/task_ast_print.cpp b/test/OpenMP/task_ast_print.cpp index 55407c10baa..5fd41038ad2 100644 --- a/test/OpenMP/task_ast_print.cpp +++ b/test/OpenMP/task_ast_print.cpp @@ -33,7 +33,7 @@ T tmain(T argc, T *argv) { T b = argc, c, d, e, f, g; static T a; S<T> s; -#pragma omp task untied +#pragma omp task untied depend(in : argc) a = 2; #pragma omp task default(none), private(argc, b) firstprivate(argv) shared(d) if (argc > 0) final(S<T>::TS > 0) foo(); @@ -46,7 +46,7 @@ T tmain(T argc, T *argv) { // CHECK-NEXT: int b = argc, c, d, e, f, g; // CHECK-NEXT: static int a; // CHECK-NEXT: S<int> s; -// CHECK-NEXT: #pragma omp task untied +// CHECK-NEXT: #pragma omp task untied depend(in : argc) // CHECK-NEXT: a = 2; // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<int>::TS > 0) // CHECK-NEXT: foo() @@ -56,7 +56,7 @@ T tmain(T argc, T *argv) { // CHECK-NEXT: long b = argc, c, d, e, f, g; // CHECK-NEXT: static long a; // CHECK-NEXT: S<long> s; -// CHECK-NEXT: #pragma omp task untied +// CHECK-NEXT: #pragma omp task untied depend(in : argc) // CHECK-NEXT: a = 2; // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<long>::TS > 0) // CHECK-NEXT: foo() @@ -66,7 +66,7 @@ T tmain(T argc, T *argv) { // CHECK-NEXT: T b = argc, c, d, e, f, g; // CHECK-NEXT: static T a; // CHECK-NEXT: S<T> s; -// CHECK-NEXT: #pragma omp task untied +// CHECK-NEXT: #pragma omp task untied depend(in : argc) // CHECK-NEXT: a = 2; // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<T>::TS > 0) // CHECK-NEXT: foo() @@ -82,12 +82,12 @@ int main(int argc, char **argv) { #pragma omp threadprivate(a) Enum ee; // CHECK: Enum ee; -#pragma omp task untied mergeable - // CHECK-NEXT: #pragma omp task untied mergeable +#pragma omp task untied mergeable depend(out:argv[1]) + // CHECK-NEXT: #pragma omp task untied mergeable depend(out : argv[1]) a = 2; // CHECK-NEXT: a = 2; -#pragma omp task default(none), private(argc, b) firstprivate(argv) if (argc > 0) final(a > 0) - // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) if(argc > 0) final(a > 0) +#pragma omp task default(none), private(argc, b) firstprivate(argv) if (argc > 0) final(a > 0) depend(inout : a) + // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) if(argc > 0) final(a > 0) depend(inout : a) foo(); // CHECK-NEXT: foo(); return tmain<int, 5>(b, &b) + tmain<long, 1>(x, &x); diff --git a/test/OpenMP/task_depend_messages.cpp b/test/OpenMP/task_depend_messages.cpp new file mode 100644 index 00000000000..152350cca93 --- /dev/null +++ b/test/OpenMP/task_depend_messages.cpp @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} + +class vector { + public: + int operator[](int index) { return 0; } +}; + +int main(int argc, char **argv) { + vector vec; + typedef float V __attribute__((vector_size(16))); + V a; + + #pragma omp task depend // expected-error {{expected '(' after 'depend'}} + #pragma omp task depend ( // expected-error {{expected 'in', 'out' or 'inout' in OpenMP clause 'depend'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-warning {{missing ':' after dependency type - ignoring}} + #pragma omp task depend () // expected-error {{expected 'in', 'out' or 'inout' in OpenMP clause 'depend'}} expected-warning {{missing ':' after dependency type - ignoring}} + #pragma omp task depend (argc // expected-error {{expected 'in', 'out' or 'inout' in OpenMP clause 'depend'}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp task depend (in : argc)) // expected-warning {{extra tokens at the end of '#pragma omp task' are ignored}} + #pragma omp task depend (out: ) // expected-error {{expected expression}} + #pragma omp task depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected variable name, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}} + #pragma omp task depend (out :S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp task depend(in : argv[1][1] = '2') // expected-error {{expected variable name, array element or array section}} + #pragma omp task depend (in : vec[1]) // expected-error {{expected variable name, array element or array section}} + #pragma omp task depend (in : argv[0]) + #pragma omp task depend (in : ) // expected-error {{expected expression}} + #pragma omp task depend (in : main) // expected-error {{expected variable name, array element or array section}} + #pragma omp task depend(in : a[0]) // expected-error{{expected variable name, array element or array section}} + foo(); + + return 0; +} diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index adf8d977c93..6a17f576484 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -2098,6 +2098,9 @@ OMPClauseEnqueue::VisitOMPCopyprivateClause(const OMPCopyprivateClause *C) { void OMPClauseEnqueue::VisitOMPFlushClause(const OMPFlushClause *C) { VisitOMPClauseList(C); } +void OMPClauseEnqueue::VisitOMPDependClause(const OMPDependClause *C) { + VisitOMPClauseList(C); +} } void EnqueueVisitor::EnqueueChildren(const OMPClause *S) { -- GitLab