[clang] b1b4652 - [OpenACC] 'wait' clause for compute construct sema
via cfe-commits
cfe-commits at lists.llvm.org
Thu May 9 06:44:19 PDT 2024
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 at +1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
#pragma acc parallel wait
{}
- // expected-error at +2{{invalid OpenACC clause 'clause'}}
- // expected-warning at +1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
+ // expected-error at +1{{invalid OpenACC clause 'clause'}}
#pragma acc parallel wait clause-list
{}
@@ -17,12 +15,10 @@ void func() {
#pragma acc parallel wait (
{}
- // expected-warning at +1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
#pragma acc parallel wait ()
{}
- // expected-error at +2{{invalid OpenACC clause 'clause'}}
- // expected-warning at +1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
+ // expected-error at +1{{invalid OpenACC clause 'clause'}}
#pragma acc parallel wait () clause-list
{}
@@ -61,12 +57,10 @@ void func() {
#pragma acc parallel wait (queues:
{}
- // expected-warning at +1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
#pragma acc parallel wait (queues:)
{}
- // expected-error at +2{{invalid OpenACC clause 'clause'}}
- // expected-warning at +1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
+ // expected-error at +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 at +1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
#pragma acc parallel wait (devnum: i + j:queues:)
{}
- // expected-error at +2{{invalid OpenACC clause 'clause'}}
- // expected-warning at +1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
+ // expected-error at +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 at +2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
- // expected-warning at +1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
+ // expected-error at +1{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
#pragma acc parallel wait(i, j, 1+1, 3.3)
{}
- // expected-error at +3{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
- // expected-error at +2{{invalid OpenACC clause 'clause'}}
- // expected-warning at +1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
+ // expected-error at +2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
+ // expected-error at +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 at +2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
- // expected-warning at +1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
+ // expected-error at +1{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
#pragma acc parallel wait(queues:i, j, 1+1, 3.3)
{}
- // expected-error at +3{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
- // expected-error at +2{{invalid OpenACC clause 'clause'}}
- // expected-warning at +1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
+ // expected-error at +2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
+ // expected-error at +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 at +1{{to match this '('}}
#pragma acc parallel wait(devnum:3:i, j, 1+1, 3.3
{}
- // expected-error at +2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
- // expected-warning at +1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
+ // expected-error at +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 at +3{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
- // expected-error at +2{{invalid OpenACC clause 'clause'}}
- // expected-warning at +1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
+ // expected-error at +2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
+ // expected-error at +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 at +1{{to match this '('}}
#pragma acc parallel wait(devnum:3:queues:i, j, 1+1, 3.3
{}
- // expected-error at +2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
- // expected-warning at +1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
+ // expected-error at +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 at +3{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
- // expected-error at +2{{invalid OpenACC clause 'clause'}}
- // expected-warning at +1{{OpenACC clause 'wait' not yet implemented, clause ignored}}
+ // expected-error at +2{{OpenACC clause 'wait' requires expression of integer type ('double' invalid)}}
+ // expected-error at +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 at +1{{OpenACC clause 'wait' requires expression of integer type ('struct NotConvertible' invalid)}}
+#pragma acc parallel wait(devnum:NC : 5)
+ while(1);
+
+ // expected-error at +1{{OpenACC clause 'wait' requires expression of integer type ('struct NotConvertible' invalid)}}
+#pragma acc parallel wait(devnum:5 : NC)
+ while(1);
+
+ // expected-error at +3{{OpenACC clause 'wait' requires expression of integer type ('int[5]' invalid)}}
+ // expected-error at +2{{OpenACC clause 'wait' requires expression of integer type ('int[5]' invalid)}}
+ // expected-error at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
+ // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
+ // expected-error at +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 at +5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
+ // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
+ // expected-error at +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 at +5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
+ // expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
+ // expected-error at +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 at +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) {
More information about the cfe-commits
mailing list