Author: erichkeane Date: 2024-05-09T06:44:12-07:00 New Revision: b1b465218d1fd3e1abe9332ed9ec535c49061425
URL: https://github.com/llvm/llvm-project/commit/b1b465218d1fd3e1abe9332ed9ec535c49061425 DIFF: https://github.com/llvm/llvm-project/commit/b1b465218d1fd3e1abe9332ed9ec535c49061425.diff LOG: [OpenACC] 'wait' clause for compute construct sema 'wait' takes a few int-exprs (well, a series of async-arguments, but those are effectively just an int-expr), plus a pair of tags. This patch adds the support for this to the AST, and does the appropriate semantic analysis for them. Added: clang/test/SemaOpenACC/compute-construct-wait-clause.c clang/test/SemaOpenACC/compute-construct-wait-clause.cpp Modified: clang/include/clang/AST/OpenACCClause.h clang/include/clang/Basic/OpenACCClauses.def clang/include/clang/Parse/Parser.h clang/include/clang/Sema/SemaOpenACC.h clang/include/clang/Serialization/ASTRecordReader.h clang/include/clang/Serialization/ASTRecordWriter.h clang/lib/AST/OpenACCClause.cpp clang/lib/AST/StmtProfile.cpp clang/lib/AST/TextNodeDumper.cpp clang/lib/Parse/ParseOpenACC.cpp clang/lib/Sema/SemaOpenACC.cpp clang/lib/Sema/TreeTransform.h clang/lib/Serialization/ASTReader.cpp clang/lib/Serialization/ASTWriter.cpp clang/test/AST/ast-print-openacc-compute-construct.cpp clang/test/ParserOpenACC/parse-wait-clause.c clang/test/SemaOpenACC/compute-construct-intexpr-clause-ast.cpp clang/tools/libclang/CIndex.cpp Removed: ################################################################################ diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h index 125c2af793308..d8332816a4999 100644 --- a/clang/include/clang/AST/OpenACCClause.h +++ b/clang/include/clang/AST/OpenACCClause.h @@ -192,6 +192,46 @@ class OpenACCClauseWithExprs : public OpenACCClauseWithParams { } }; +// Represents the 'devnum' and expressions lists for the 'wait' clause. +class OpenACCWaitClause final + : public OpenACCClauseWithExprs, + public llvm::TrailingObjects<OpenACCWaitClause, Expr *> { + SourceLocation QueuesLoc; + OpenACCWaitClause(SourceLocation BeginLoc, SourceLocation LParenLoc, + Expr *DevNumExpr, SourceLocation QueuesLoc, + ArrayRef<Expr *> QueueIdExprs, SourceLocation EndLoc) + : OpenACCClauseWithExprs(OpenACCClauseKind::Wait, BeginLoc, LParenLoc, + EndLoc), + QueuesLoc(QueuesLoc) { + // The first element of the trailing storage is always the devnum expr, + // whether it is used or not. + std::uninitialized_copy(&DevNumExpr, &DevNumExpr + 1, + getTrailingObjects<Expr *>()); + std::uninitialized_copy(QueueIdExprs.begin(), QueueIdExprs.end(), + getTrailingObjects<Expr *>() + 1); + setExprs( + MutableArrayRef(getTrailingObjects<Expr *>(), QueueIdExprs.size() + 1)); + } + +public: + static OpenACCWaitClause *Create(const ASTContext &C, SourceLocation BeginLoc, + SourceLocation LParenLoc, Expr *DevNumExpr, + SourceLocation QueuesLoc, + ArrayRef<Expr *> QueueIdExprs, + SourceLocation EndLoc); + + bool hasQueuesTag() const { return !QueuesLoc.isInvalid(); } + SourceLocation getQueuesLoc() const { return QueuesLoc; } + bool hasDevNumExpr() const { return getExprs()[0]; } + Expr *getDevNumExpr() const { return getExprs()[0]; } + llvm::ArrayRef<Expr *> getQueueIdExprs() { + return OpenACCClauseWithExprs::getExprs().drop_front(); + } + llvm::ArrayRef<Expr *> getQueueIdExprs() const { + return OpenACCClauseWithExprs::getExprs().drop_front(); + } +}; + class OpenACCNumGangsClause final : public OpenACCClauseWithExprs, public llvm::TrailingObjects<OpenACCNumGangsClause, Expr *> { diff --git a/clang/include/clang/Basic/OpenACCClauses.def b/clang/include/clang/Basic/OpenACCClauses.def index 8933e09b44f9b..afb7b30b7465c 100644 --- a/clang/include/clang/Basic/OpenACCClauses.def +++ b/clang/include/clang/Basic/OpenACCClauses.def @@ -46,6 +46,7 @@ VISIT_CLAUSE(Present) VISIT_CLAUSE(Private) VISIT_CLAUSE(Self) VISIT_CLAUSE(VectorLength) +VISIT_CLAUSE(Wait) #undef VISIT_CLAUSE #undef CLAUSE_ALIAS diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 532b5c125ef59..60d59732269bc 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3632,6 +3632,13 @@ class Parser : public CodeCompletionHandler { // Wait constructs, we likely want to put that information in here as well. }; + struct OpenACCWaitParseInfo { + bool Failed = false; + Expr *DevNumExpr = nullptr; + SourceLocation QueuesLoc; + SmallVector<Expr *> QueueIdExprs; + }; + /// Represents the 'error' state of parsing an OpenACC Clause, and stores /// whether we can continue parsing, or should give up on the directive. enum class OpenACCParseCanContinue { Cannot = 0, Can = 1 }; @@ -3674,7 +3681,8 @@ class Parser : public CodeCompletionHandler { /// Parses the clause-list for an OpenACC directive. SmallVector<OpenACCClause *> ParseOpenACCClauseList(OpenACCDirectiveKind DirKind); - bool ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective); + OpenACCWaitParseInfo ParseOpenACCWaitArgument(SourceLocation Loc, + bool IsDirective); /// Parses the clause of the 'bind' argument, which can be a string literal or /// an ID expression. ExprResult ParseOpenACCBindClauseArgument(); diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h index 2cec2b73e918c..e684ee6b2be12 100644 --- a/clang/include/clang/Sema/SemaOpenACC.h +++ b/clang/include/clang/Sema/SemaOpenACC.h @@ -54,8 +54,14 @@ class SemaOpenACC : public SemaBase { bool IsZero; }; + struct WaitDetails { + Expr *DevNumExpr; + SourceLocation QueuesLoc; + SmallVector<Expr *> QueueIdExprs; + }; + std::variant<std::monostate, DefaultDetails, ConditionDetails, - IntExprDetails, VarListDetails> + IntExprDetails, VarListDetails, WaitDetails> Details = std::monostate{}; public: @@ -104,14 +110,45 @@ class SemaOpenACC : public SemaBase { ClauseKind == OpenACCClauseKind::Async || ClauseKind == OpenACCClauseKind::VectorLength) && "Parsed clause kind does not have a int exprs"); - // - // 'async' has an optional IntExpr, so be tolerant of that. - if (ClauseKind == OpenACCClauseKind::Async && + + // 'async' and 'wait' have an optional IntExpr, so be tolerant of that. + if ((ClauseKind == OpenACCClauseKind::Async || + ClauseKind == OpenACCClauseKind::Wait) && std::holds_alternative<std::monostate>(Details)) return 0; return std::get<IntExprDetails>(Details).IntExprs.size(); } + SourceLocation getQueuesLoc() const { + assert(ClauseKind == OpenACCClauseKind::Wait && + "Parsed clause kind does not have a queues location"); + + if (std::holds_alternative<std::monostate>(Details)) + return SourceLocation{}; + + return std::get<WaitDetails>(Details).QueuesLoc; + } + + Expr *getDevNumExpr() const { + assert(ClauseKind == OpenACCClauseKind::Wait && + "Parsed clause kind does not have a device number expr"); + + if (std::holds_alternative<std::monostate>(Details)) + return nullptr; + + return std::get<WaitDetails>(Details).DevNumExpr; + } + + ArrayRef<Expr *> getQueueIdExprs() const { + assert(ClauseKind == OpenACCClauseKind::Wait && + "Parsed clause kind does not have a queue id expr list"); + + if (std::holds_alternative<std::monostate>(Details)) + return ArrayRef<Expr *>{std::nullopt}; + + return std::get<WaitDetails>(Details).QueueIdExprs; + } + ArrayRef<Expr *> getIntExprs() { assert((ClauseKind == OpenACCClauseKind::NumGangs || ClauseKind == OpenACCClauseKind::NumWorkers || @@ -282,6 +319,13 @@ class SemaOpenACC : public SemaBase { "zero: tag only valid on copyout/create"); Details = VarListDetails{std::move(VarList), IsReadOnly, IsZero}; } + + void setWaitDetails(Expr *DevNum, SourceLocation QueuesLoc, + llvm::SmallVector<Expr *> &&IntExprs) { + assert(ClauseKind == OpenACCClauseKind::Wait && + "Parsed clause kind does not have a wait-details"); + Details = WaitDetails{DevNum, QueuesLoc, std::move(IntExprs)}; + } }; SemaOpenACC(Sema &S); diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h index 1e11d2d5e42f9..d00fb182f05f4 100644 --- a/clang/include/clang/Serialization/ASTRecordReader.h +++ b/clang/include/clang/Serialization/ASTRecordReader.h @@ -272,6 +272,9 @@ class ASTRecordReader /// Read a list of Exprs used for a var-list. llvm::SmallVector<Expr *> readOpenACCVarList(); + /// Read a list of Exprs used for a int-expr-list. + llvm::SmallVector<Expr *> readOpenACCIntExprList(); + /// Read an OpenACC clause, advancing Idx. OpenACCClause *readOpenACCClause(); diff --git a/clang/include/clang/Serialization/ASTRecordWriter.h b/clang/include/clang/Serialization/ASTRecordWriter.h index 8b1da49bd4c57..0c8ac75fc40f4 100644 --- a/clang/include/clang/Serialization/ASTRecordWriter.h +++ b/clang/include/clang/Serialization/ASTRecordWriter.h @@ -296,6 +296,8 @@ class ASTRecordWriter void writeOpenACCVarList(const OpenACCClauseWithVarList *C); + void writeOpenACCIntExprList(ArrayRef<Expr *> Exprs); + /// Writes out a single OpenACC Clause. void writeOpenACCClause(const OpenACCClause *C); diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp index ffa90884cef5b..be079556a87a8 100644 --- a/clang/lib/AST/OpenACCClause.cpp +++ b/clang/lib/AST/OpenACCClause.cpp @@ -147,6 +147,18 @@ OpenACCAsyncClause *OpenACCAsyncClause::Create(const ASTContext &C, return new (Mem) OpenACCAsyncClause(BeginLoc, LParenLoc, IntExpr, EndLoc); } +OpenACCWaitClause *OpenACCWaitClause::Create( + const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc, + Expr *DevNumExpr, SourceLocation QueuesLoc, ArrayRef<Expr *> QueueIdExprs, + SourceLocation EndLoc) { + // Allocates enough room in trailing storage for all the int-exprs, plus a + // placeholder for the devnum. + void *Mem = C.Allocate( + OpenACCWaitClause::totalSizeToAlloc<Expr *>(QueueIdExprs.size() + 1)); + return new (Mem) OpenACCWaitClause(BeginLoc, LParenLoc, DevNumExpr, QueuesLoc, + QueueIdExprs, EndLoc); +} + OpenACCNumGangsClause *OpenACCNumGangsClause::Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc, @@ -393,3 +405,22 @@ void OpenACCClausePrinter::VisitCreateClause(const OpenACCCreateClause &C) { [&](const Expr *E) { printExpr(E); }); OS << ")"; } + +void OpenACCClausePrinter::VisitWaitClause(const OpenACCWaitClause &C) { + OS << "wait"; + if (!C.getLParenLoc().isInvalid()) { + OS << "("; + if (C.hasDevNumExpr()) { + OS << "devnum: "; + printExpr(C.getDevNumExpr()); + OS << " : "; + } + + if (C.hasQueuesTag()) + OS << "queues: "; + + llvm::interleaveComma(C.getQueueIdExprs(), OS, + [&](const Expr *E) { printExpr(E); }); + OS << ")"; + } +} diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 0910471098c9c..8fb8940142eb0 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2578,6 +2578,13 @@ void OpenACCClauseProfiler::VisitAsyncClause(const OpenACCAsyncClause &Clause) { if (Clause.hasIntExpr()) Profiler.VisitStmt(Clause.getIntExpr()); } + +void OpenACCClauseProfiler::VisitWaitClause(const OpenACCWaitClause &Clause) { + if (Clause.hasDevNumExpr()) + Profiler.VisitStmt(Clause.getDevNumExpr()); + for (auto *E : Clause.getQueueIdExprs()) + Profiler.VisitStmt(E); +} } // namespace void StmtProfiler::VisitOpenACCComputeConstruct( diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index bf02d9545f844..12aa5858b7983 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -437,6 +437,13 @@ void TextNodeDumper::Visit(const OpenACCClause *C) { if (cast<OpenACCCreateClause>(C)->isZero()) OS << " : zero"; break; + case OpenACCClauseKind::Wait: + OS << " clause"; + if (cast<OpenACCWaitClause>(C)->hasDevNumExpr()) + OS << " has devnum"; + if (cast<OpenACCWaitClause>(C)->hasQueuesTag()) + OS << " has queues tag"; + break; default: // Nothing to do here. break; diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index 727854db9be1f..90dfea6f5f5c4 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -867,7 +867,6 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams( SemaOpenACC::OpenACCParsedClause ParsedClause(DirKind, ClauseKind, ClauseLoc); if (ClauseHasRequiredParens(DirKind, ClauseKind)) { - ParsedClause.setLParenLoc(getCurToken().getLocation()); if (Parens.expectAndConsume()) { // We are missing a paren, so assume that the person just forgot the // parameter. Return 'false' so we try to continue on and parse the next @@ -876,6 +875,7 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams( Parser::StopBeforeMatch); return OpenACCCanContinue(); } + ParsedClause.setLParenLoc(Parens.getOpenLocation()); switch (ClauseKind) { case OpenACCClauseKind::Default: { @@ -1048,8 +1048,8 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams( return OpenACCCannotContinue(); } else if (ClauseHasOptionalParens(DirKind, ClauseKind)) { - ParsedClause.setLParenLoc(getCurToken().getLocation()); if (!Parens.consumeOpen()) { + ParsedClause.setLParenLoc(Parens.getOpenLocation()); switch (ClauseKind) { case OpenACCClauseKind::Self: { assert(DirKind != OpenACCDirectiveKind::Update); @@ -1099,13 +1099,19 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams( return OpenACCCanContinue(); } break; - case OpenACCClauseKind::Wait: - if (ParseOpenACCWaitArgument(ClauseLoc, - /*IsDirective=*/false)) { + case OpenACCClauseKind::Wait: { + OpenACCWaitParseInfo Info = + ParseOpenACCWaitArgument(ClauseLoc, + /*IsDirective=*/false); + if (Info.Failed) { Parens.skipToEnd(); return OpenACCCanContinue(); } + + ParsedClause.setWaitDetails(Info.DevNumExpr, Info.QueuesLoc, + std::move(Info.QueueIdExprs)); break; + } default: llvm_unreachable("Not an optional parens type?"); } @@ -1139,7 +1145,9 @@ Parser::ParseOpenACCAsyncArgument(OpenACCDirectiveKind DK, OpenACCClauseKind CK, /// In this section and throughout the specification, the term wait-argument /// means: /// [ devnum : int-expr : ] [ queues : ] async-argument-list -bool Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) { +Parser::OpenACCWaitParseInfo +Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) { + OpenACCWaitParseInfo Result; // [devnum : int-expr : ] if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::DevNum, Tok) && NextToken().is(tok::colon)) { @@ -1153,18 +1161,25 @@ bool Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) { : OpenACCDirectiveKind::Invalid, IsDirective ? OpenACCClauseKind::Invalid : OpenACCClauseKind::Wait, Loc); - if (Res.first.isInvalid() && Res.second == OpenACCParseCanContinue::Cannot) - return true; + if (Res.first.isInvalid() && + Res.second == OpenACCParseCanContinue::Cannot) { + Result.Failed = true; + return Result; + } - if (ExpectAndConsume(tok::colon)) - return true; + if (ExpectAndConsume(tok::colon)) { + Result.Failed = true; + return Result; + } + + Result.DevNumExpr = Res.first.get(); } // [ queues : ] if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Queues, Tok) && NextToken().is(tok::colon)) { // Consume queues. - ConsumeToken(); + Result.QueuesLoc = ConsumeToken(); // Consume colon. ConsumeToken(); } @@ -1176,8 +1191,10 @@ bool Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) { bool FirstArg = true; while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) { if (!FirstArg) { - if (ExpectAndConsume(tok::comma)) - return true; + if (ExpectAndConsume(tok::comma)) { + Result.Failed = true; + return Result; + } } FirstArg = false; @@ -1187,11 +1204,16 @@ bool Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) { IsDirective ? OpenACCClauseKind::Invalid : OpenACCClauseKind::Wait, Loc); - if (Res.first.isInvalid() && Res.second == OpenACCParseCanContinue::Cannot) - return true; + if (Res.first.isInvalid() && + Res.second == OpenACCParseCanContinue::Cannot) { + Result.Failed = true; + return Result; + } + + Result.QueueIdExprs.push_back(Res.first.get()); } - return false; + return Result; } ExprResult Parser::ParseOpenACCIDExpression() { @@ -1360,7 +1382,7 @@ Parser::OpenACCDirectiveParseInfo Parser::ParseOpenACCDirective() { break; case OpenACCDirectiveKind::Wait: // OpenACC has an optional paren-wrapped 'wait-argument'. - if (ParseOpenACCWaitArgument(StartLoc, /*IsDirective=*/true)) + if (ParseOpenACCWaitArgument(StartLoc, /*IsDirective=*/true).Failed) T.skipToEnd(); else T.consumeClose(); diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index b1086baa3ae2e..656d30947a8d1 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -216,6 +216,22 @@ bool doesClauseApplyToDirective(OpenACCDirectiveKind DirectiveKind, default: return false; } + case OpenACCClauseKind::Wait: + switch (DirectiveKind) { + case OpenACCDirectiveKind::Parallel: + case OpenACCDirectiveKind::Serial: + case OpenACCDirectiveKind::Kernels: + case OpenACCDirectiveKind::Data: + case OpenACCDirectiveKind::EnterData: + case OpenACCDirectiveKind::ExitData: + case OpenACCDirectiveKind::Update: + case OpenACCDirectiveKind::ParallelLoop: + case OpenACCDirectiveKind::SerialLoop: + case OpenACCDirectiveKind::KernelsLoop: + return true; + default: + return false; + } default: // Do nothing so we can go to the 'unimplemented' diagnostic instead. @@ -623,6 +639,18 @@ SemaOpenACC::ActOnClause(ArrayRef<const OpenACCClause *> ExistingClauses, getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getVarList(), Clause.getEndLoc()); } + case OpenACCClauseKind::Wait: { + // Restrictions only properly implemented on 'compute' constructs, and + // 'compute' constructs are the only construct that can do anything with + // this yet, so skip/treat as unimplemented in this case. + if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind())) + break; + + return OpenACCWaitClause::Create( + getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(), + Clause.getDevNumExpr(), Clause.getQueuesLoc(), Clause.getQueueIdExprs(), + Clause.getEndLoc()); + } default: break; } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 2d6d6dae680cc..0b3cf566e3a7b 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -11425,6 +11425,51 @@ void OpenACCClauseTransform<Derived>::VisitAsyncClause( : nullptr, ParsedClause.getEndLoc()); } +template <typename Derived> +void OpenACCClauseTransform<Derived>::VisitWaitClause( + const OpenACCWaitClause &C) { + if (!C.getLParenLoc().isInvalid()) { + Expr *DevNumExpr = nullptr; + llvm::SmallVector<Expr *> InstantiatedQueueIdExprs; + + // Instantiate devnum expr if it exists. + if (C.getDevNumExpr()) { + ExprResult Res = Self.TransformExpr(C.getDevNumExpr()); + if (!Res.isUsable()) + return; + Res = Self.getSema().OpenACC().ActOnIntExpr(OpenACCDirectiveKind::Invalid, + C.getClauseKind(), + C.getBeginLoc(), Res.get()); + if (!Res.isUsable()) + return; + + DevNumExpr = Res.get(); + } + + // Instantiate queue ids. + for (Expr *CurQueueIdExpr : C.getQueueIdExprs()) { + ExprResult Res = Self.TransformExpr(CurQueueIdExpr); + if (!Res.isUsable()) + return; + Res = Self.getSema().OpenACC().ActOnIntExpr(OpenACCDirectiveKind::Invalid, + C.getClauseKind(), + C.getBeginLoc(), Res.get()); + if (!Res.isUsable()) + return; + + InstantiatedQueueIdExprs.push_back(Res.get()); + } + + ParsedClause.setWaitDetails(DevNumExpr, C.getQueuesLoc(), + std::move(InstantiatedQueueIdExprs)); + } + + NewClause = OpenACCWaitClause::Create( + Self.getSema().getASTContext(), ParsedClause.getBeginLoc(), + ParsedClause.getLParenLoc(), ParsedClause.getDevNumExpr(), + ParsedClause.getQueuesLoc(), ParsedClause.getQueueIdExprs(), + ParsedClause.getEndLoc()); +} } // namespace template <typename Derived> OpenACCClause *TreeTransform<Derived>::TransformOpenACCClause( diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 856c743086c51..78e4df440641e 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -11766,6 +11766,14 @@ SmallVector<Expr *> ASTRecordReader::readOpenACCVarList() { return VarList; } +SmallVector<Expr *> ASTRecordReader::readOpenACCIntExprList() { + unsigned NumExprs = readInt(); + llvm::SmallVector<Expr *> ExprList; + for (unsigned I = 0; I < NumExprs; ++I) + ExprList.push_back(readSubExpr()); + return ExprList; +} + OpenACCClause *ASTRecordReader::readOpenACCClause() { OpenACCClauseKind ClauseKind = readEnum<OpenACCClauseKind>(); SourceLocation BeginLoc = readSourceLocation(); @@ -11888,6 +11896,15 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() { return OpenACCAsyncClause::Create(getContext(), BeginLoc, LParenLoc, AsyncExpr, EndLoc); } + case OpenACCClauseKind::Wait: { + SourceLocation LParenLoc = readSourceLocation(); + Expr *DevNumExpr = readBool() ? readSubExpr() : nullptr; + SourceLocation QueuesLoc = readSourceLocation(); + llvm::SmallVector<Expr *> QueueIdExprs = readOpenACCIntExprList(); + return OpenACCWaitClause::Create(getContext(), BeginLoc, LParenLoc, + DevNumExpr, QueuesLoc, QueueIdExprs, + EndLoc); + } case OpenACCClauseKind::Finalize: case OpenACCClauseKind::IfPresent: @@ -11913,7 +11930,6 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() { case OpenACCClauseKind::DType: case OpenACCClauseKind::Tile: case OpenACCClauseKind::Gang: - case OpenACCClauseKind::Wait: case OpenACCClauseKind::Invalid: llvm_unreachable("Clause serialization not yet implemented"); } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index ce2ea4e3d614b..e7b9050165bb7 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -7791,6 +7791,12 @@ void ASTRecordWriter::writeOpenACCVarList(const OpenACCClauseWithVarList *C) { AddStmt(E); } +void ASTRecordWriter::writeOpenACCIntExprList(ArrayRef<Expr *> Exprs) { + writeUInt32(Exprs.size()); + for (Expr *E : Exprs) + AddStmt(E); +} + void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { writeEnum(C->getClauseKind()); writeSourceLocation(C->getBeginLoc()); @@ -7916,6 +7922,17 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { AddStmt(const_cast<Expr *>(AC->getIntExpr())); return; } + case OpenACCClauseKind::Wait: { + const auto *WC = cast<OpenACCWaitClause>(C); + writeSourceLocation(WC->getLParenLoc()); + writeBool(WC->getDevNumExpr()); + if (const Expr *DNE = WC->getDevNumExpr()) + AddStmt(const_cast<Expr *>(DNE)); + writeSourceLocation(WC->getQueuesLoc()); + + writeOpenACCIntExprList(WC->getQueueIdExprs()); + return; + } case OpenACCClauseKind::Finalize: case OpenACCClauseKind::IfPresent: @@ -7941,7 +7958,6 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { case OpenACCClauseKind::DType: case OpenACCClauseKind::Tile: case OpenACCClauseKind::Gang: - case OpenACCClauseKind::Wait: case OpenACCClauseKind::Invalid: llvm_unreachable("Clause serialization not yet implemented"); } diff --git a/clang/test/AST/ast-print-openacc-compute-construct.cpp b/clang/test/AST/ast-print-openacc-compute-construct.cpp index 13597543e9b6d..0bfb90bcb5871 100644 --- a/clang/test/AST/ast-print-openacc-compute-construct.cpp +++ b/clang/test/AST/ast-print-openacc-compute-construct.cpp @@ -83,5 +83,29 @@ void foo() { // CHECK: #pragma acc kernels async #pragma acc kernels async while(true); + +// CHECK: #pragma acc parallel wait +#pragma acc parallel wait + while(true); + +// CHECK: #pragma acc parallel wait() +#pragma acc parallel wait() + while(true); + +// CHECK: #pragma acc parallel wait(*iPtr, i) +#pragma acc parallel wait(*iPtr, i) + while(true); + +// CHECK: #pragma acc parallel wait(queues: *iPtr, i) +#pragma acc parallel wait(queues:*iPtr, i) + while(true); + +// CHECK: #pragma acc parallel wait(devnum: i : *iPtr, i) +#pragma acc parallel wait(devnum:i:*iPtr, i) + while(true); + +// CHECK: #pragma acc parallel wait(devnum: i : queues: *iPtr, i) +#pragma acc parallel wait(devnum:i:queues:*iPtr, i) + while(true); } diff --git a/clang/test/ParserOpenACC/parse-wait-clause.c b/clang/test/ParserOpenACC/parse-wait-clause.c index 64f5b9c8fd735..9c7faa5c02eb3 100644 --- a/clang/test/ParserOpenACC/parse-wait-clause.c +++ b/clang/test/ParserOpenACC/parse-wait-clause.c @@ -3,12 +3,10 @@ void func() { int i, j; - // expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}} #pragma acc parallel wait {} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc parallel wait clause-list {} @@ -17,12 +15,10 @@ void func() { #pragma acc parallel wait ( {} - // expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}} #pragma acc parallel wait () {} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc parallel wait () clause-list {} @@ -61,12 +57,10 @@ void func() { #pragma acc parallel wait (queues: {} - // expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}} #pragma acc parallel wait (queues:) {} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc parallel wait (queues:) clause-list {} @@ -75,12 +69,10 @@ void func() { #pragma acc parallel wait (devnum: i + j:queues: {} - // expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}} #pragma acc parallel wait (devnum: i + j:queues:) {} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc parallel wait (devnum: i + j:queues:) clause-list {} @@ -108,13 +100,11 @@ void func() { #pragma acc parallel wait(i, j, 1+1, 3.3 {} - // expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}} - // expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}} + // expected-error@+1{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}} #pragma acc parallel wait(i, j, 1+1, 3.3) {} - // expected-error@+3{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}} + // expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc parallel wait(i, j, 1+1, 3.3) clause-list {} @@ -146,14 +136,12 @@ void func() { #pragma acc parallel wait(queues:i, j, 1+1, 3.3, {} - // expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}} - // expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}} + // expected-error@+1{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}} #pragma acc parallel wait(queues:i, j, 1+1, 3.3) {} - // expected-error@+3{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}} + // expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc parallel wait(queues:i, j, 1+1, 3.3) clause-list {} @@ -162,13 +150,11 @@ void func() { // expected-note@+1{{to match this '('}} #pragma acc parallel wait(devnum:3:i, j, 1+1, 3.3 {} - // expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}} - // expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}} + // expected-error@+1{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}} #pragma acc parallel wait(devnum:3:i, j, 1+1, 3.3) {} - // expected-error@+3{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}} + // expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc parallel wait(devnum:3:i, j, 1+1, 3.3) clause-list {} @@ -177,13 +163,11 @@ void func() { // expected-note@+1{{to match this '('}} #pragma acc parallel wait(devnum:3:queues:i, j, 1+1, 3.3 {} - // expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}} - // expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}} + // expected-error@+1{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}} #pragma acc parallel wait(devnum:3:queues:i, j, 1+1, 3.3) {} - // expected-error@+3{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC clause 'wait' not yet implemented, clause ignored}} + // expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc parallel wait(devnum:3:queues:i, j, 1+1, 3.3) clause-list {} } diff --git a/clang/test/SemaOpenACC/compute-construct-intexpr-clause-ast.cpp b/clang/test/SemaOpenACC/compute-construct-intexpr-clause-ast.cpp index b85de56c7ae9c..56c3512dec3b9 100644 --- a/clang/test/SemaOpenACC/compute-construct-intexpr-clause-ast.cpp +++ b/clang/test/SemaOpenACC/compute-construct-intexpr-clause-ast.cpp @@ -135,6 +135,93 @@ void NormalUses() { // CHECK-NEXT: WhileStmt // CHECK-NEXT: CXXBoolLiteralExpr // CHECK-NEXT: CompoundStmt + +#pragma acc parallel wait + while (true){} + // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel + // CHECK-NEXT: wait clause + // CHECK-NEXT: <<<NULL>>> + // CHECK-NEXT: WhileStmt + // CHECK-NEXT: CXXBoolLiteralExpr + // CHECK-NEXT: CompoundStmt +#pragma acc parallel wait() + while (true){} + // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel + // CHECK-NEXT: wait clause + // CHECK-NEXT: <<<NULL>>> + // CHECK-NEXT: WhileStmt + // CHECK-NEXT: CXXBoolLiteralExpr + // CHECK-NEXT: CompoundStmt +#pragma acc parallel wait(some_int(), some_long()) + while (true){} + // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel + // CHECK-NEXT: wait clause + // CHECK-NEXT: <<<NULL>>> + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'long ()' lvalue Function{{.*}} 'some_long' 'long ()' + // CHECK-NEXT: WhileStmt + // CHECK-NEXT: CXXBoolLiteralExpr + // CHECK-NEXT: CompoundStmt +#pragma acc parallel wait(queues:some_int(), some_long()) + while (true){} + // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel + // CHECK-NEXT: wait clause has queues tag + // CHECK-NEXT: <<<NULL>>> + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'long ()' lvalue Function{{.*}} 'some_long' 'long ()' + // CHECK-NEXT: WhileStmt + // CHECK-NEXT: CXXBoolLiteralExpr + // CHECK-NEXT: CompoundStmt +#pragma acc parallel wait(devnum: some_int() :some_int(), some_long()) + while (true){} + // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel + // CHECK-NEXT: wait clause has devnum + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()' + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'long ()' lvalue Function{{.*}} 'some_long' 'long ()' + // CHECK-NEXT: WhileStmt + // CHECK-NEXT: CXXBoolLiteralExpr + // CHECK-NEXT: CompoundStmt +#pragma acc parallel wait(devnum: some_int() : queues :some_int(), some_long()) wait(devnum: some_int() : queues :some_int(), some_long()) + while (true){} + // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel + // CHECK-NEXT: wait clause has devnum has queues tag + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()' + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'long ()' lvalue Function{{.*}} 'some_long' 'long ()' + // CHECK-NEXT: wait clause has devnum has queues tag + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()' + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'long ()' lvalue Function{{.*}} 'some_long' 'long ()' + // CHECK-NEXT: WhileStmt + // CHECK-NEXT: CXXBoolLiteralExpr + // CHECK-NEXT: CompoundStmt } @@ -282,6 +369,72 @@ void TemplUses(T t, U u) { // CHECK-NEXT: CXXBoolLiteralExpr // CHECK-NEXT: CompoundStmt +#pragma acc parallel wait + while (true){} + // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel + // CHECK-NEXT: wait clause + // CHECK-NEXT: <<<NULL>>> + // CHECK-NEXT: WhileStmt + // CHECK-NEXT: CXXBoolLiteralExpr + // CHECK-NEXT: CompoundStmt + +#pragma acc parallel wait() + while (true){} + // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel + // CHECK-NEXT: wait clause + // CHECK-NEXT: <<<NULL>>> + // CHECK-NEXT: WhileStmt + // CHECK-NEXT: CXXBoolLiteralExpr + // CHECK-NEXT: CompoundStmt + +#pragma acc parallel wait(U::value, u) + while (true){} + // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel + // CHECK-NEXT: wait clause + // CHECK-NEXT: <<<NULL>>> + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'U' + // CHECK-NEXT: DeclRefExpr{{.*}} 'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: WhileStmt + // CHECK-NEXT: CXXBoolLiteralExpr + // CHECK-NEXT: CompoundStmt + +#pragma acc parallel wait(queues: U::value, u) + while (true){} + // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel + // CHECK-NEXT: wait clause has queues tag + // CHECK-NEXT: <<<NULL>>> + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'U' + // CHECK-NEXT: DeclRefExpr{{.*}} 'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: WhileStmt + // CHECK-NEXT: CXXBoolLiteralExpr + // CHECK-NEXT: CompoundStmt + +#pragma acc parallel wait(devnum:u:queues: U::value, u) + while (true){} + // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel + // CHECK-NEXT: wait clause has devnum has queues tag + // CHECK-NEXT: DeclRefExpr{{.*}} 'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'U' + // CHECK-NEXT: DeclRefExpr{{.*}} 'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: WhileStmt + // CHECK-NEXT: CXXBoolLiteralExpr + // CHECK-NEXT: CompoundStmt + +#pragma acc parallel wait(devnum:u: U::value, u) + while (true){} + // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel + // CHECK-NEXT: wait clause has devnum + // CHECK-NEXT: DeclRefExpr{{.*}} 'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'U' + // CHECK-NEXT: DeclRefExpr{{.*}} 'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: WhileStmt + // CHECK-NEXT: CXXBoolLiteralExpr + // CHECK-NEXT: CompoundStmt + // CHECK-NEXT: DeclStmt // CHECK-NEXT: VarDecl{{.*}}EndMarker @@ -437,6 +590,82 @@ void TemplUses(T t, U u) { // CHECK-NEXT: CXXBoolLiteralExpr // CHECK-NEXT: CompoundStmt + // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel + // CHECK-NEXT: wait clause + // CHECK-NEXT: <<<NULL>>> + // CHECK-NEXT: WhileStmt + // CHECK-NEXT: CXXBoolLiteralExpr + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel + // CHECK-NEXT: wait clause + // CHECK-NEXT: <<<NULL>>> + // CHECK-NEXT: WhileStmt + // CHECK-NEXT: CXXBoolLiteralExpr + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel + // CHECK-NEXT: wait clause + // CHECK-NEXT: <<<NULL>>> + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' <LValueToRValue> + // CHECK-NEXT: DeclRefExpr{{.*}} 'const int' lvalue Var{{.*}} 'value' 'const int' + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'HasInt' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' <UserDefinedConversion> + // CHECK-NEXT: CXXMemberCallExpr{{.*}}'char' + // CHECK-NEXT: MemberExpr{{.*}} '<bound member function type>' .operator char + // CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar + // CHECK-NEXT: WhileStmt + // CHECK-NEXT: CXXBoolLiteralExpr + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel + // CHECK-NEXT: wait clause has queues tag + // CHECK-NEXT: <<<NULL>>> + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' <LValueToRValue> + // CHECK-NEXT: DeclRefExpr{{.*}} 'const int' lvalue Var{{.*}} 'value' 'const int' + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'HasInt' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' <UserDefinedConversion> + // CHECK-NEXT: CXXMemberCallExpr{{.*}}'char' + // CHECK-NEXT: MemberExpr{{.*}} '<bound member function type>' .operator char + // CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar + // CHECK-NEXT: WhileStmt + // CHECK-NEXT: CXXBoolLiteralExpr + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel + // CHECK-NEXT: wait clause has devnum has queues tag + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' <UserDefinedConversion> + // CHECK-NEXT: CXXMemberCallExpr{{.*}}'char' + // CHECK-NEXT: MemberExpr{{.*}} '<bound member function type>' .operator char + // CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' <LValueToRValue> + // CHECK-NEXT: DeclRefExpr{{.*}} 'const int' lvalue Var{{.*}} 'value' 'const int' + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'HasInt' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' <UserDefinedConversion> + // CHECK-NEXT: CXXMemberCallExpr{{.*}}'char' + // CHECK-NEXT: MemberExpr{{.*}} '<bound member function type>' .operator char + // CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar + // CHECK-NEXT: WhileStmt + // CHECK-NEXT: CXXBoolLiteralExpr + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel + // CHECK-NEXT: wait clause has devnum + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' <UserDefinedConversion> + // CHECK-NEXT: CXXMemberCallExpr{{.*}}'char' + // CHECK-NEXT: MemberExpr{{.*}} '<bound member function type>' .operator char + // CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' <LValueToRValue> + // CHECK-NEXT: DeclRefExpr{{.*}} 'const int' lvalue Var{{.*}} 'value' 'const int' + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'HasInt' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' <UserDefinedConversion> + // CHECK-NEXT: CXXMemberCallExpr{{.*}}'char' + // CHECK-NEXT: MemberExpr{{.*}} '<bound member function type>' .operator char + // CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar + // CHECK-NEXT: WhileStmt + // CHECK-NEXT: CXXBoolLiteralExpr + // CHECK-NEXT: CompoundStmt + // CHECK-NEXT: DeclStmt // CHECK-NEXT: VarDecl{{.*}}EndMarker } diff --git a/clang/test/SemaOpenACC/compute-construct-wait-clause.c b/clang/test/SemaOpenACC/compute-construct-wait-clause.c new file mode 100644 index 0000000000000..254aba8442fee --- /dev/null +++ b/clang/test/SemaOpenACC/compute-construct-wait-clause.c @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +struct NotConvertible{} NC; +short getS(); +int getI(); + +void uses() { + int arr[5]; + +#pragma acc parallel wait + while(1); + +#pragma acc serial wait() + while(1); + +#pragma acc kernels wait(getS(), getI()) + while(1); + +#pragma acc parallel wait(devnum:getS(): getI()) + while(1); + +#pragma acc parallel wait(devnum:getS(): queues: getI()) wait(devnum:getI(): queues: getS(), getI(), 5) + while(1); + + // expected-error@+1{{OpenACC clause 'wait' requires expression of integer type ('struct NotConvertible' invalid)}} +#pragma acc parallel wait(devnum:NC : 5) + while(1); + + // expected-error@+1{{OpenACC clause 'wait' requires expression of integer type ('struct NotConvertible' invalid)}} +#pragma acc parallel wait(devnum:5 : NC) + while(1); + + // expected-error@+3{{OpenACC clause 'wait' requires expression of integer type ('int[5]' invalid)}} + // expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('int[5]' invalid)}} + // expected-error@+1{{OpenACC clause 'wait' requires expression of integer type ('struct NotConvertible' invalid)}} +#pragma acc parallel wait(devnum:arr : queues: arr, NC, 5) + while(1); +} diff --git a/clang/test/SemaOpenACC/compute-construct-wait-clause.cpp b/clang/test/SemaOpenACC/compute-construct-wait-clause.cpp new file mode 100644 index 0000000000000..94f669be0f672 --- /dev/null +++ b/clang/test/SemaOpenACC/compute-construct-wait-clause.cpp @@ -0,0 +1,104 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +struct ExplicitConvertOnly { + explicit operator int() const; // #EXPL_CONV +} Explicit; + +struct AmbiguousConvert{ + operator int(); // #AMBIG_INT + operator short(); // #AMBIG_SHORT + operator float(); +} Ambiguous; + +void Test() { + + // expected-error@+3{{multiple conversions from expression type 'struct AmbiguousConvert' to an integral type}} + // expected-note@#AMBIG_INT{{conversion to integral type 'int'}} + // expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}} +#pragma acc parallel wait(Ambiguous) + while (true); + + // expected-error@+2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} +#pragma acc parallel wait(4, Explicit, 5) + while (true); + + // expected-error@+3{{multiple conversions from expression type 'struct AmbiguousConvert' to an integral type}} + // expected-note@#AMBIG_INT{{conversion to integral type 'int'}} + // expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}} +#pragma acc parallel wait(queues: Ambiguous, 5) + while (true); + + // expected-error@+2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} +#pragma acc parallel wait(devnum: Explicit: 5) + while (true); + + // expected-error@+2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} +#pragma acc parallel wait(devnum: Explicit:queues: 5) + while (true); + + // expected-error@+1{{use of undeclared identifier 'queues'}} +#pragma acc parallel wait(devnum: queues: 5) + while (true); +} + +struct HasInt { + using IntTy = int; + using ShortTy = short; + static constexpr int value = 1; + static constexpr AmbiguousConvert ACValue; + static constexpr ExplicitConvertOnly EXValue; + + operator char(); +}; + +template<typename T> +void TestInst() { + +#pragma acc parallel wait(T{}) + while (true); + +#pragma acc parallel wait(devnum:typename T::ShortTy{}:queues:typename T::IntTy{}) + while (true); + + // expected-error@+4{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}} + // expected-note@#INST{{in instantiation of function template specialization}} + // expected-note@#AMBIG_INT{{conversion to integral type 'int'}} + // expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}} +#pragma acc parallel wait(devnum:T::value :queues:T::ACValue) + while (true); + + // expected-error@+5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} + // expected-error@+3{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}} + // expected-note@#AMBIG_INT{{conversion to integral type 'int'}} + // expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}} +#pragma acc parallel wait(devnum:T::EXValue :queues:T::ACValue) + while (true); + + // expected-error@+5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} + // expected-error@+3{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}} + // expected-note@#AMBIG_INT{{conversion to integral type 'int'}} + // expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}} +#pragma acc parallel wait(T::EXValue, T::ACValue) + while (true); + + // expected-error@+5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} + // expected-error@+3{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}} + // expected-note@#AMBIG_INT{{conversion to integral type 'int'}} + // expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}} +#pragma acc parallel wait(queues: T::EXValue, T::ACValue) + while (true); + + // expected-error@+1{{no member named 'Invalid' in 'HasInt'}} +#pragma acc parallel wait(queues: T::Invalid, T::Invalid2) + while (true); +} + +void Inst() { + TestInst<HasInt>(); // #INST +} diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index b845a381d63be..ae6659fe95e89 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -2851,6 +2851,12 @@ void OpenACCClauseEnqueue::VisitAsyncClause(const OpenACCAsyncClause &C) { if (C.hasIntExpr()) Visitor.AddStmt(C.getIntExpr()); } +void OpenACCClauseEnqueue::VisitWaitClause(const OpenACCWaitClause &C) { + if (const Expr *DevNumExpr = C.getDevNumExpr()) + Visitor.AddStmt(DevNumExpr); + for (Expr *QE : C.getQueueIdExprs()) + Visitor.AddStmt(QE); +} } // namespace void EnqueueVisitor::EnqueueChildren(const OpenACCClause *C) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits