Author: erichkeane Date: 2024-12-18T15:06:01-08:00 New Revision: e34cc7c99375c43e1698c78ec9150fa40c88d486
URL: https://github.com/llvm/llvm-project/commit/e34cc7c99375c43e1698c78ec9150fa40c88d486 DIFF: https://github.com/llvm/llvm-project/commit/e34cc7c99375c43e1698c78ec9150fa40c88d486.diff LOG: [OpenACC] Implement 'wait' construct The arguments to this are the same as for the 'wait' clause, so this reuses all of that infrastructure. So all this has to do is support a pair of clauses that are already implemented (if and async), plus create an AST node. This patch does so, and adds proper testing. Added: clang/test/AST/ast-print-openacc-wait-construct.cpp clang/test/SemaOpenACC/wait-construct-ast.cpp clang/test/SemaOpenACC/wait-construct.cpp Modified: clang/include/clang-c/Index.h clang/include/clang/AST/ASTNodeTraverser.h clang/include/clang/AST/RecursiveASTVisitor.h clang/include/clang/AST/StmtOpenACC.h clang/include/clang/AST/TextNodeDumper.h clang/include/clang/Basic/StmtNodes.td clang/include/clang/Parse/Parser.h clang/include/clang/Sema/SemaOpenACC.h clang/include/clang/Serialization/ASTBitCodes.h clang/lib/AST/StmtOpenACC.cpp clang/lib/AST/StmtPrinter.cpp clang/lib/AST/StmtProfile.cpp clang/lib/AST/TextNodeDumper.cpp clang/lib/CodeGen/CGStmt.cpp clang/lib/CodeGen/CodeGenFunction.h clang/lib/Parse/ParseOpenACC.cpp clang/lib/Sema/SemaExceptionSpec.cpp clang/lib/Sema/SemaOpenACC.cpp clang/lib/Sema/TreeTransform.h clang/lib/Serialization/ASTReaderStmt.cpp clang/lib/Serialization/ASTWriterStmt.cpp clang/lib/StaticAnalyzer/Core/ExprEngine.cpp clang/test/ParserOpenACC/parse-wait-construct.c clang/test/SemaOpenACC/combined-construct-default-clause.c clang/test/SemaOpenACC/compute-construct-default-clause.c clang/test/SemaOpenACC/unimplemented-construct.c clang/tools/libclang/CIndex.cpp clang/tools/libclang/CXCursor.cpp Removed: ################################################################################ diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 29858f00fad74e..122118b8f37638 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -2186,7 +2186,11 @@ enum CXCursorKind { */ CXCursor_OpenACCHostDataConstruct = 326, - CXCursor_LastStmt = CXCursor_OpenACCHostDataConstruct, + /** OpenACC wait Construct. + */ + CXCursor_OpenACCWaitConstruct = 327, + + CXCursor_LastStmt = CXCursor_OpenACCWaitConstruct, /** * Cursor that represents the translation unit itself. diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h index 3d63d581a9be60..f5652b295de168 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -159,7 +159,7 @@ class ASTNodeTraverser // Some statements have custom mechanisms for dumping their children. if (isa<DeclStmt>(S) || isa<GenericSelectionExpr>(S) || - isa<RequiresExpr>(S)) + isa<RequiresExpr>(S) || isa<OpenACCWaitConstruct>(S)) return; if (Traversal == TK_IgnoreUnlessSpelledInSource && @@ -825,6 +825,16 @@ class ASTNodeTraverser Visit(C); } + void VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *Node) { + // Needs custom child checking to put clauses AFTER the children, which are + // the expressions in the 'wait' construct. Others likely need this as well, + // and might need to do the associated statement after it. + for (const Stmt *S : Node->children()) + Visit(S); + for (const auto *C : Node->clauses()) + Visit(C); + } + void VisitInitListExpr(const InitListExpr *ILE) { if (auto *Filler = ILE->getArrayFiller()) { Visit(Filler, "array_filler"); diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 5d5c91ff91d553..d9a87b30062df8 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -4063,10 +4063,19 @@ DEF_TRAVERSE_STMT(OpenACCCombinedConstruct, { TRY_TO(TraverseOpenACCAssociatedStmtConstruct(S)); }) DEF_TRAVERSE_STMT(OpenACCDataConstruct, { TRY_TO(TraverseOpenACCAssociatedStmtConstruct(S)); }) -DEF_TRAVERSE_STMT(OpenACCEnterDataConstruct, {}) -DEF_TRAVERSE_STMT(OpenACCExitDataConstruct, {}) +DEF_TRAVERSE_STMT(OpenACCEnterDataConstruct, + { TRY_TO(VisitOpenACCClauseList(S->clauses())); }) +DEF_TRAVERSE_STMT(OpenACCExitDataConstruct, + { TRY_TO(VisitOpenACCClauseList(S->clauses())); }) DEF_TRAVERSE_STMT(OpenACCHostDataConstruct, { TRY_TO(TraverseOpenACCAssociatedStmtConstruct(S)); }) +DEF_TRAVERSE_STMT(OpenACCWaitConstruct, { + if (S->hasDevNumExpr()) + TRY_TO(TraverseStmt(S->getDevNumExpr())); + for (auto *E : S->getQueueIdExprs()) + TRY_TO(TraverseStmt(E)); + TRY_TO(VisitOpenACCClauseList(S->clauses())); +}) // Traverse HLSL: Out argument expression DEF_TRAVERSE_STMT(HLSLOutArgExpr, {}) diff --git a/clang/include/clang/AST/StmtOpenACC.h b/clang/include/clang/AST/StmtOpenACC.h index a1903cd9e3a23a..093393a81be9c7 100644 --- a/clang/include/clang/AST/StmtOpenACC.h +++ b/clang/include/clang/AST/StmtOpenACC.h @@ -469,5 +469,128 @@ class OpenACCHostDataConstruct final return const_cast<OpenACCHostDataConstruct *>(this)->getStructuredBlock(); } }; + +// This class represents a 'wait' construct, which has some expressions plus a +// clause list. +class OpenACCWaitConstruct final + : public OpenACCConstructStmt, + private llvm::TrailingObjects<OpenACCWaitConstruct, Expr *, + OpenACCClause *> { + // FIXME: We should be storing a `const OpenACCClause *` to be consistent with + // the rest of the constructs, but TrailingObjects doesn't allow for mixing + // constness in its implementation of `getTrailingObjects`. + + friend TrailingObjects; + friend class ASTStmtWriter; + friend class ASTStmtReader; + // Locations of the left and right parens of the 'wait-argument' + // expression-list. + SourceLocation LParenLoc, RParenLoc; + // Location of the 'queues' keyword, if present. + SourceLocation QueuesLoc; + + // Number of the expressions being represented. Index '0' is always the + // 'devnum' expression, even if it not present. + unsigned NumExprs = 0; + + OpenACCWaitConstruct(unsigned NumExprs, unsigned NumClauses) + : OpenACCConstructStmt(OpenACCWaitConstructClass, + OpenACCDirectiveKind::Wait, SourceLocation{}, + SourceLocation{}, SourceLocation{}), + NumExprs(NumExprs) { + assert(NumExprs >= 1 && + "NumExprs should always be >= 1 because the 'devnum' " + "expr is represented by a null if necessary"); + std::uninitialized_value_construct(getExprPtr(), + getExprPtr() + NumExprs); + std::uninitialized_value_construct(getTrailingObjects<OpenACCClause *>(), + getTrailingObjects<OpenACCClause *>() + + NumClauses); + setClauseList(MutableArrayRef(const_cast<const OpenACCClause **>( + getTrailingObjects<OpenACCClause *>()), + NumClauses)); + } + + OpenACCWaitConstruct(SourceLocation Start, SourceLocation DirectiveLoc, + SourceLocation LParenLoc, Expr *DevNumExpr, + SourceLocation QueuesLoc, ArrayRef<Expr *> QueueIdExprs, + SourceLocation RParenLoc, SourceLocation End, + ArrayRef<const OpenACCClause *> Clauses) + : OpenACCConstructStmt(OpenACCWaitConstructClass, + OpenACCDirectiveKind::Wait, Start, DirectiveLoc, + End), + LParenLoc(LParenLoc), RParenLoc(RParenLoc), QueuesLoc(QueuesLoc), + NumExprs(QueueIdExprs.size() + 1) { + assert(NumExprs >= 1 && + "NumExprs should always be >= 1 because the 'devnum' " + "expr is represented by a null if necessary"); + + std::uninitialized_copy(&DevNumExpr, &DevNumExpr + 1, + getExprPtr()); + std::uninitialized_copy(QueueIdExprs.begin(), QueueIdExprs.end(), + getExprPtr() + 1); + + std::uninitialized_copy(const_cast<OpenACCClause **>(Clauses.begin()), + const_cast<OpenACCClause **>(Clauses.end()), + getTrailingObjects<OpenACCClause *>()); + setClauseList(MutableArrayRef(const_cast<const OpenACCClause **>( + getTrailingObjects<OpenACCClause *>()), + Clauses.size())); + } + + size_t numTrailingObjects(OverloadToken<Expr *>) const { return NumExprs; } + size_t numTrailingObjects(OverloadToken<const OpenACCClause *>) const { + return clauses().size(); + } + + Expr **getExprPtr() const { + return const_cast<Expr**>(getTrailingObjects<Expr *>()); + } + + llvm::ArrayRef<Expr *> getExprs() const { + return llvm::ArrayRef<Expr *>(getExprPtr(), NumExprs); + } + + llvm::ArrayRef<Expr *> getExprs() { + return llvm::ArrayRef<Expr *>(getExprPtr(), NumExprs); + } + +public: + static bool classof(const Stmt *T) { + return T->getStmtClass() == OpenACCWaitConstructClass; + } + + static OpenACCWaitConstruct * + CreateEmpty(const ASTContext &C, unsigned NumExprs, unsigned NumClauses); + + static OpenACCWaitConstruct * + Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, + SourceLocation LParenLoc, Expr *DevNumExpr, SourceLocation QueuesLoc, + ArrayRef<Expr *> QueueIdExprs, SourceLocation RParenLoc, + SourceLocation End, ArrayRef<const OpenACCClause *> Clauses); + + SourceLocation getLParenLoc() const { return LParenLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + 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 getExprs().drop_front(); } + llvm::ArrayRef<Expr *> getQueueIdExprs() const { + return getExprs().drop_front(); + } + + child_range children() { + Stmt **Begin = reinterpret_cast<Stmt **>(getExprPtr()); + return child_range(Begin, Begin + NumExprs); + } + + const_child_range children() const { + Stmt *const *Begin = + reinterpret_cast<Stmt *const *>(getExprPtr()); + return const_child_range(Begin, Begin + NumExprs); + } +}; } // namespace clang #endif // LLVM_CLANG_AST_STMTOPENACC_H diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index e54e7e527b8a36..b6f16be7a5b98f 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -415,6 +415,7 @@ class TextNodeDumper void VisitOpenACCEnterDataConstruct(const OpenACCEnterDataConstruct *S); void VisitOpenACCExitDataConstruct(const OpenACCExitDataConstruct *S); void VisitOpenACCHostDataConstruct(const OpenACCHostDataConstruct *S); + void VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *S); void VisitOpenACCAsteriskSizeExpr(const OpenACCAsteriskSizeExpr *S); void VisitEmbedExpr(const EmbedExpr *S); void VisitAtomicExpr(const AtomicExpr *AE); diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index 0c3c580c218fd7..6c7314b06d858a 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -312,6 +312,7 @@ def OpenACCDataConstruct : StmtNode<OpenACCAssociatedStmtConstruct>; def OpenACCEnterDataConstruct : StmtNode<OpenACCConstructStmt>; def OpenACCExitDataConstruct : StmtNode<OpenACCConstructStmt>; def OpenACCHostDataConstruct : StmtNode<OpenACCAssociatedStmtConstruct>; +def OpenACCWaitConstruct : StmtNode<OpenACCConstructStmt>; // OpenACC Additional Expressions. def OpenACCAsteriskSizeExpr : StmtNode<Expr>; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index d3838a4cc8418c..e99d2cf2eaa409 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3706,10 +3706,14 @@ class Parser : public CodeCompletionHandler { OpenACCDirectiveKind DirKind; SourceLocation StartLoc; SourceLocation DirLoc; + SourceLocation LParenLoc; + SourceLocation RParenLoc; SourceLocation EndLoc; + SourceLocation MiscLoc; + SmallVector<Expr *> Exprs; SmallVector<OpenACCClause *> Clauses; - // TODO OpenACC: As we implement support for the Atomic, Routine, Cache, and - // Wait constructs, we likely want to put that information in here as well. + // TODO OpenACC: As we implement support for the Atomic, Routine, and Cache + // constructs, we likely want to put that information in here as well. }; struct OpenACCWaitParseInfo { @@ -3717,6 +3721,13 @@ class Parser : public CodeCompletionHandler { Expr *DevNumExpr = nullptr; SourceLocation QueuesLoc; SmallVector<Expr *> QueueIdExprs; + + SmallVector<Expr *> getAllExprs() { + SmallVector<Expr *> Out; + Out.push_back(DevNumExpr); + Out.insert(Out.end(), QueueIdExprs.begin(), QueueIdExprs.end()); + return Out; + } }; /// Represents the 'error' state of parsing an OpenACC Clause, and stores diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h index 4b92af507af4ea..04ab1ac429a2dd 100644 --- a/clang/include/clang/Sema/SemaOpenACC.h +++ b/clang/include/clang/Sema/SemaOpenACC.h @@ -679,12 +679,18 @@ class SemaOpenACC : public SemaBase { /// Called after the directive has been completely parsed, including the /// declaration group or associated statement. - StmtResult ActOnEndStmtDirective(OpenACCDirectiveKind K, - SourceLocation StartLoc, - SourceLocation DirLoc, - SourceLocation EndLoc, - ArrayRef<OpenACCClause *> Clauses, - StmtResult AssocStmt); + /// LParenLoc: Location of the left paren, if it exists (not on all + /// constructs). + /// MiscLoc: First misc location, if necessary (not all constructs). + /// Exprs: List of expressions on the construct itself, if necessary (not all + /// constructs). + /// RParenLoc: Location of the right paren, if it exists (not on all + /// constructs). + StmtResult ActOnEndStmtDirective( + OpenACCDirectiveKind K, SourceLocation StartLoc, SourceLocation DirLoc, + SourceLocation LParenLoc, SourceLocation MiscLoc, ArrayRef<Expr *> Exprs, + SourceLocation RParenLoc, SourceLocation EndLoc, + ArrayRef<OpenACCClause *> Clauses, StmtResult AssocStmt); /// Called after the directive has been completely parsed, including the /// declaration group or associated statement. diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index da0e5fdb117aa0..57e27c373bffa1 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -2021,6 +2021,7 @@ enum StmtCode { STMT_OPENACC_ENTER_DATA_CONSTRUCT, STMT_OPENACC_EXIT_DATA_CONSTRUCT, STMT_OPENACC_HOST_DATA_CONSTRUCT, + STMT_OPENACC_WAIT_CONSTRUCT, // HLSL Constructs EXPR_HLSL_OUT_ARG, diff --git a/clang/lib/AST/StmtOpenACC.cpp b/clang/lib/AST/StmtOpenACC.cpp index fb73dfb3fa9dee..6d9f267702e37d 100644 --- a/clang/lib/AST/StmtOpenACC.cpp +++ b/clang/lib/AST/StmtOpenACC.cpp @@ -196,3 +196,32 @@ OpenACCHostDataConstruct *OpenACCHostDataConstruct::Create( Clauses, StructuredBlock); return Inst; } + +OpenACCWaitConstruct *OpenACCWaitConstruct::CreateEmpty(const ASTContext &C, + unsigned NumExprs, + unsigned NumClauses) { + void *Mem = C.Allocate( + OpenACCWaitConstruct::totalSizeToAlloc<Expr *, OpenACCClause *>( + NumExprs, NumClauses)); + + auto *Inst = new (Mem) OpenACCWaitConstruct(NumExprs, NumClauses); + return Inst; +} + +OpenACCWaitConstruct *OpenACCWaitConstruct::Create( + const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, + SourceLocation LParenLoc, Expr *DevNumExpr, SourceLocation QueuesLoc, + ArrayRef<Expr *> QueueIdExprs, SourceLocation RParenLoc, SourceLocation End, + ArrayRef<const OpenACCClause *> Clauses) { + + assert(llvm::all_of(QueueIdExprs, [](Expr *E) { return E != nullptr; })); + + void *Mem = C.Allocate( + OpenACCWaitConstruct::totalSizeToAlloc<Expr *, OpenACCClause *>( + QueueIdExprs.size() + 1, Clauses.size())); + + auto *Inst = new (Mem) + OpenACCWaitConstruct(Start, DirectiveLoc, LParenLoc, DevNumExpr, + QueuesLoc, QueueIdExprs, RParenLoc, End, Clauses); + return Inst; +} diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 488419add5e79e..ecc9b6e35db72d 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1238,6 +1238,34 @@ void StmtPrinter::VisitOpenACCHostDataConstruct(OpenACCHostDataConstruct *S) { PrintStmt(S->getStructuredBlock()); } +void StmtPrinter::VisitOpenACCWaitConstruct(OpenACCWaitConstruct *S) { + Indent() << "#pragma acc wait"; + if (!S->getLParenLoc().isInvalid()) { + OS << "("; + if (S->hasDevNumExpr()) { + OS << "devnum: "; + S->getDevNumExpr()->printPretty(OS, nullptr, Policy); + OS << " : "; + } + + if (S->hasQueuesTag()) + OS << "queues: "; + + llvm::interleaveComma(S->getQueueIdExprs(), OS, [&](const Expr *E) { + E->printPretty(OS, nullptr, Policy); + }); + + OS << ")"; + } + + if (!S->clauses().empty()) { + OS << ' '; + OpenACCClausePrinter Printer(OS, Policy); + Printer.VisitClauseList(S->clauses()); + } + OS << '\n'; +} + //===----------------------------------------------------------------------===// // Expr printing methods. //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 1fb238720ffb13..fccd97dca23af2 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2743,6 +2743,14 @@ void StmtProfiler::VisitOpenACCHostDataConstruct( P.VisitOpenACCClauseList(S->clauses()); } +void StmtProfiler::VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *S) { + // VisitStmt covers 'children', so the exprs inside of it are covered. + VisitStmt(S); + + OpenACCClauseProfiler P{*this}; + P.VisitOpenACCClauseList(S->clauses()); +} + void StmtProfiler::VisitHLSLOutArgExpr(const HLSLOutArgExpr *S) { VisitStmt(S); } diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index b5af10dd00b77c..7cdffbe20e575a 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -2960,6 +2960,10 @@ void TextNodeDumper::VisitOpenACCHostDataConstruct( OS << " " << S->getDirectiveKind(); } +void TextNodeDumper::VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *S) { + OS << " " << S->getDirectiveKind(); +} + void TextNodeDumper::VisitEmbedExpr(const EmbedExpr *S) { AddChild("begin", [=] { OS << S->getStartingElementPos(); }); AddChild("number of elements", [=] { OS << S->getDataElementCount(); }); diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 6c7a594fb10c4c..6c604f44e283be 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -470,6 +470,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) { case Stmt::OpenACCHostDataConstructClass: EmitOpenACCHostDataConstruct(cast<OpenACCHostDataConstruct>(*S)); break; + case Stmt::OpenACCWaitConstructClass: + EmitOpenACCWaitConstruct(cast<OpenACCWaitConstruct>(*S)); + break; } } diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 092d55355a0a17..847999cf1f28a0 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4118,6 +4118,11 @@ class CodeGenFunction : public CodeGenTypeCache { EmitStmt(S.getStructuredBlock()); } + void EmitOpenACCWaitConstruct(const OpenACCWaitConstruct &S) { + // TODO OpenACC: Implement this. It is currently implemented as a 'no-op', + // but in the future we will implement some sort of IR. + } + //===--------------------------------------------------------------------===// // LValue Expression Emission //===--------------------------------------------------------------------===// diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index af175a465eb79a..5da34a2f5db923 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -573,6 +573,7 @@ bool doesDirectiveHaveAssociatedStmt(OpenACCDirectiveKind DirKind) { default: case OpenACCDirectiveKind::EnterData: case OpenACCDirectiveKind::ExitData: + case OpenACCDirectiveKind::Wait: return false; case OpenACCDirectiveKind::Parallel: case OpenACCDirectiveKind::Serial: @@ -604,6 +605,7 @@ unsigned getOpenACCScopeFlags(OpenACCDirectiveKind DirKind) { case OpenACCDirectiveKind::EnterData: case OpenACCDirectiveKind::ExitData: case OpenACCDirectiveKind::HostData: + case OpenACCDirectiveKind::Wait: return 0; case OpenACCDirectiveKind::Invalid: llvm_unreachable("Shouldn't be creating a scope for an invalid construct"); @@ -1288,7 +1290,8 @@ Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) { return Result; } - Result.QueueIdExprs.push_back(Res.first.get()); + if (Res.first.isUsable()) + Result.QueueIdExprs.push_back(Res.first.get()); } return Result; @@ -1422,6 +1425,7 @@ Parser::ParseOpenACCDirective() { SourceLocation StartLoc = ConsumeAnnotationToken(); SourceLocation DirLoc = getCurToken().getLocation(); OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(*this); + Parser::OpenACCWaitParseInfo WaitInfo; getActions().OpenACC().ActOnConstruct(DirKind, DirLoc); @@ -1462,7 +1466,8 @@ Parser::ParseOpenACCDirective() { break; case OpenACCDirectiveKind::Wait: // OpenACC has an optional paren-wrapped 'wait-argument'. - if (ParseOpenACCWaitArgument(DirLoc, /*IsDirective=*/true).Failed) + WaitInfo = ParseOpenACCWaitArgument(DirLoc, /*IsDirective=*/true); + if (WaitInfo.Failed) T.skipToEnd(); else T.consumeClose(); @@ -1476,8 +1481,14 @@ Parser::ParseOpenACCDirective() { } // Parses the list of clauses, if present, plus set up return value. - OpenACCDirectiveParseInfo ParseInfo{DirKind, StartLoc, DirLoc, - SourceLocation{}, + OpenACCDirectiveParseInfo ParseInfo{DirKind, + StartLoc, + DirLoc, + T.getOpenLocation(), + T.getCloseLocation(), + /*EndLoc=*/SourceLocation{}, + WaitInfo.QueuesLoc, + WaitInfo.getAllExprs(), ParseOpenACCClauseList(DirKind)}; assert(Tok.is(tok::annot_pragma_openacc_end) && @@ -1529,6 +1540,7 @@ StmtResult Parser::ParseOpenACCDirectiveStmt() { } return getActions().OpenACC().ActOnEndStmtDirective( - DirInfo.DirKind, DirInfo.StartLoc, DirInfo.DirLoc, DirInfo.EndLoc, + DirInfo.DirKind, DirInfo.StartLoc, DirInfo.DirLoc, DirInfo.LParenLoc, + DirInfo.MiscLoc, DirInfo.Exprs, DirInfo.RParenLoc, DirInfo.EndLoc, DirInfo.Clauses, AssocStmt); } diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 2be6af293ed543..505cc5e153fa70 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1398,6 +1398,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Expr::HLSLOutArgExprClass: case Stmt::OpenACCEnterDataConstructClass: case Stmt::OpenACCExitDataConstructClass: + case Stmt::OpenACCWaitConstructClass: // These expressions can never throw. return CT_Cannot; diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index 11c18358a3aa01..aa9097bfa17436 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -41,6 +41,7 @@ bool diagnoseConstructAppertainment(SemaOpenACC &S, OpenACCDirectiveKind K, case OpenACCDirectiveKind::EnterData: case OpenACCDirectiveKind::ExitData: case OpenACCDirectiveKind::HostData: + case OpenACCDirectiveKind::Wait: if (!IsStmt) return S.Diag(StartLoc, diag::err_acc_construct_appertainment) << K; break; @@ -566,6 +567,16 @@ bool checkValidAfterDeviceType( return true; } +// A temporary function that helps implement the 'not implemented' check at the +// top of each clause checking function. This should only be used in conjunction +// with the one being currently implemented/only updated after the entire +// construct has been implemented. +bool isDirectiveKindImplemented(OpenACCDirectiveKind DK) { + return isOpenACCComputeDirectiveKind(DK) || + isOpenACCCombinedDirectiveKind(DK) || isOpenACCDataDirectiveKind(DK) || + DK == OpenACCDirectiveKind::Loop || DK == OpenACCDirectiveKind::Wait; +} + class SemaOpenACCClauseVisitor { SemaOpenACC &SemaRef; ASTContext &Ctx; @@ -680,9 +691,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitIfClause( // constructs, and 'compute'/'combined'/'data' constructs are the only // constructs that can do anything with this yet, so skip/treat as // unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCDataDirectiveKind(Clause.getDirectiveKind())) + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // There is no prose in the standard that says duplicates aren't allowed, @@ -717,8 +726,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitSelfClause( // 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()) && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // TODO OpenACC: When we implement this for 'update', this takes a @@ -915,9 +923,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitAsyncClause( // constructs, and 'compute'/'combined'/'data' constructs are the only // construct that can do anything with this yet, so skip/treat as // unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCDataDirectiveKind(Clause.getDirectiveKind())) + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // There is no prose in the standard that says duplicates aren't allowed, @@ -973,9 +979,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitPresentClause( // constructs, and 'compute'/'combined'/'data' constructs are the only // construct that can do anything with this yet, so skip/treat as // unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCDataDirectiveKind(Clause.getDirectiveKind())) + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // ActOnVar ensured that everything is a valid variable reference, so there // really isn't anything to do here. GCC does some duplicate-finding, though @@ -992,9 +996,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyClause( // constructs, and 'compute'/'combined'/'data' constructs are the only // construct that can do anything with this yet, so skip/treat as // unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCDataDirectiveKind(Clause.getDirectiveKind())) + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // ActOnVar ensured that everything is a valid variable reference, so there // really isn't anything to do here. GCC does some duplicate-finding, though @@ -1011,9 +1013,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyInClause( // constructs, and 'compute'/'combined'/'data' constructs are the only // construct that can do anything with this yet, so skip/treat as // unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCDataDirectiveKind(Clause.getDirectiveKind())) + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // ActOnVar ensured that everything is a valid variable reference, so there // really isn't anything to do here. GCC does some duplicate-finding, though @@ -1030,9 +1030,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyOutClause( // constructs, and 'compute'/'combined'/'data' constructs are the only // construct that can do anything with this yet, so skip/treat as // unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCDataDirectiveKind(Clause.getDirectiveKind())) + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // ActOnVar ensured that everything is a valid variable reference, so there // really isn't anything to do here. GCC does some duplicate-finding, though @@ -1109,9 +1107,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitDevicePtrClause( // constructs, and 'compute'/'combined'/'data' constructs are the only // construct that can do anything with this yet, so skip/treat as // unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCDataDirectiveKind(Clause.getDirectiveKind())) + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // ActOnVar ensured that everything is a valid variable reference, but we @@ -1134,9 +1130,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitWaitClause( // constructs, and 'compute'/'combined'/'data' constructs are the only // construct that can do anything with this yet, so skip/treat as // unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCDataDirectiveKind(Clause.getDirectiveKind())) + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); return OpenACCWaitClause::Create( @@ -1150,10 +1144,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitDeviceTypeClause( // 'loop' constructs, and 'compute'/'combined'/'data'/'loop' constructs are // the only construct that can do anything with this yet, so skip/treat as // unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop && - Clause.getDirectiveKind() != OpenACCDirectiveKind::Data && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // TODO OpenACC: Once we get enough of the CodeGen implemented that we have @@ -1347,8 +1338,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitVectorClause( // Restrictions only properly implemented on 'loop'/'combined' constructs, and // it is the only construct that can do anything with this, so skip/treat as // unimplemented for the routine constructs. - if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); Expr *IntExpr = @@ -1446,8 +1436,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitWorkerClause( // Restrictions only properly implemented on 'loop'/'combined' constructs, and // it is the only construct that can do anything with this, so skip/treat as // unimplemented for the routine constructs. - if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); Expr *IntExpr = @@ -1559,8 +1548,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitGangClause( // Restrictions only properly implemented on 'loop' constructs, and it is // the only construct that can do anything with this, so skip/treat as // unimplemented for the combined constructs. - if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // OpenACC 3.3 Section 2.9.11: A reduction clause may not appear on a loop @@ -1691,7 +1679,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitFinalizeClause( OpenACCClause *SemaOpenACCClauseVisitor::VisitIfPresentClause( SemaOpenACC::OpenACCParsedClause &Clause) { - if (Clause.getDirectiveKind() != OpenACCDirectiveKind::HostData) + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // There isn't anything to do here, this is only valid on one construct, and // has no associated rules. @@ -1704,7 +1692,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitSeqClause( // Restrictions only properly implemented on 'loop' constructs and combined , // and it is the only construct that can do anything with this, so skip/treat // as unimplemented for the routine constructs. - if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Routine) + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // OpenACC 3.3 2.9: @@ -1879,6 +1867,7 @@ bool PreserveLoopRAIIDepthInAssociatedStmtRAII(OpenACCDirectiveKind DK) { return true; case OpenACCDirectiveKind::EnterData: case OpenACCDirectiveKind::ExitData: + case OpenACCDirectiveKind::Wait: llvm_unreachable("Doesn't have an associated stmt"); default: case OpenACCDirectiveKind::Invalid: @@ -2308,6 +2297,10 @@ void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K, // Nothing to do here, there is no real legalization that needs to happen // here as these constructs do not take any arguments. break; + case OpenACCDirectiveKind::Wait: + // Nothing really to do here, the arguments to the 'wait' should have + // already been handled by the time we get here. + break; default: Diag(DirLoc, diag::warn_acc_construct_unimplemented) << K; break; @@ -3637,12 +3630,11 @@ bool SemaOpenACC::ActOnStartStmtDirective( return diagnoseConstructAppertainment(*this, K, StartLoc, /*IsStmt=*/true); } -StmtResult SemaOpenACC::ActOnEndStmtDirective(OpenACCDirectiveKind K, - SourceLocation StartLoc, - SourceLocation DirLoc, - SourceLocation EndLoc, - ArrayRef<OpenACCClause *> Clauses, - StmtResult AssocStmt) { +StmtResult SemaOpenACC::ActOnEndStmtDirective( + OpenACCDirectiveKind K, SourceLocation StartLoc, SourceLocation DirLoc, + SourceLocation LParenLoc, SourceLocation MiscLoc, ArrayRef<Expr *> Exprs, + SourceLocation RParenLoc, SourceLocation EndLoc, + ArrayRef<OpenACCClause *> Clauses, StmtResult AssocStmt) { switch (K) { default: return StmtEmpty(); @@ -3685,6 +3677,11 @@ StmtResult SemaOpenACC::ActOnEndStmtDirective(OpenACCDirectiveKind K, getASTContext(), StartLoc, DirLoc, EndLoc, Clauses, AssocStmt.isUsable() ? AssocStmt.get() : nullptr); } + case OpenACCDirectiveKind::Wait: { + return OpenACCWaitConstruct::Create( + getASTContext(), StartLoc, DirLoc, LParenLoc, Exprs.front(), MiscLoc, + Exprs.drop_front(), RParenLoc, EndLoc, Clauses); + } } llvm_unreachable("Unhandled case in directive handling?"); } @@ -3697,6 +3694,7 @@ StmtResult SemaOpenACC::ActOnAssociatedStmt( llvm_unreachable("Unimplemented associated statement application"); case OpenACCDirectiveKind::EnterData: case OpenACCDirectiveKind::ExitData: + case OpenACCDirectiveKind::Wait: llvm_unreachable( "these don't have associated statements, so shouldn't get here"); case OpenACCDirectiveKind::Parallel: diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 04167e71d33f8a..c097465374cba8 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -4087,8 +4087,9 @@ class TreeTransform { SourceLocation EndLoc, ArrayRef<OpenACCClause *> Clauses, StmtResult StrBlock) { - return getSema().OpenACC().ActOnEndStmtDirective(K, BeginLoc, DirLoc, - EndLoc, Clauses, StrBlock); + return getSema().OpenACC().ActOnEndStmtDirective( + K, BeginLoc, DirLoc, SourceLocation{}, SourceLocation{}, {}, + SourceLocation{}, EndLoc, Clauses, StrBlock); } StmtResult RebuildOpenACCLoopConstruct(SourceLocation BeginLoc, @@ -4097,7 +4098,8 @@ class TreeTransform { ArrayRef<OpenACCClause *> Clauses, StmtResult Loop) { return getSema().OpenACC().ActOnEndStmtDirective( - OpenACCDirectiveKind::Loop, BeginLoc, DirLoc, EndLoc, Clauses, Loop); + OpenACCDirectiveKind::Loop, BeginLoc, DirLoc, SourceLocation{}, + SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, Loop); } StmtResult RebuildOpenACCCombinedConstruct(OpenACCDirectiveKind K, @@ -4106,8 +4108,9 @@ class TreeTransform { SourceLocation EndLoc, ArrayRef<OpenACCClause *> Clauses, StmtResult Loop) { - return getSema().OpenACC().ActOnEndStmtDirective(K, BeginLoc, DirLoc, - EndLoc, Clauses, Loop); + return getSema().OpenACC().ActOnEndStmtDirective( + K, BeginLoc, DirLoc, SourceLocation{}, SourceLocation{}, {}, + SourceLocation{}, EndLoc, Clauses, Loop); } StmtResult RebuildOpenACCDataConstruct(SourceLocation BeginLoc, @@ -4115,9 +4118,9 @@ class TreeTransform { SourceLocation EndLoc, ArrayRef<OpenACCClause *> Clauses, StmtResult StrBlock) { - return getSema().OpenACC().ActOnEndStmtDirective(OpenACCDirectiveKind::Data, - BeginLoc, DirLoc, EndLoc, - Clauses, StrBlock); + return getSema().OpenACC().ActOnEndStmtDirective( + OpenACCDirectiveKind::Data, BeginLoc, DirLoc, SourceLocation{}, + SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, StrBlock); } StmtResult @@ -4125,7 +4128,8 @@ class TreeTransform { SourceLocation DirLoc, SourceLocation EndLoc, ArrayRef<OpenACCClause *> Clauses) { return getSema().OpenACC().ActOnEndStmtDirective( - OpenACCDirectiveKind::EnterData, BeginLoc, DirLoc, EndLoc, Clauses, {}); + OpenACCDirectiveKind::EnterData, BeginLoc, DirLoc, SourceLocation{}, + SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, {}); } StmtResult @@ -4133,7 +4137,8 @@ class TreeTransform { SourceLocation DirLoc, SourceLocation EndLoc, ArrayRef<OpenACCClause *> Clauses) { return getSema().OpenACC().ActOnEndStmtDirective( - OpenACCDirectiveKind::ExitData, BeginLoc, DirLoc, EndLoc, Clauses, {}); + OpenACCDirectiveKind::ExitData, BeginLoc, DirLoc, SourceLocation{}, + SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, {}); } StmtResult RebuildOpenACCHostDataConstruct(SourceLocation BeginLoc, @@ -4142,8 +4147,21 @@ class TreeTransform { ArrayRef<OpenACCClause *> Clauses, StmtResult StrBlock) { return getSema().OpenACC().ActOnEndStmtDirective( - OpenACCDirectiveKind::HostData, BeginLoc, DirLoc, EndLoc, Clauses, - StrBlock); + OpenACCDirectiveKind::HostData, BeginLoc, DirLoc, SourceLocation{}, + SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, StrBlock); + } + + StmtResult RebuildOpenACCWaitConstruct( + SourceLocation BeginLoc, SourceLocation DirLoc, SourceLocation LParenLoc, + Expr *DevNumExpr, SourceLocation QueuesLoc, ArrayRef<Expr *> QueueIdExprs, + SourceLocation RParenLoc, SourceLocation EndLoc, + ArrayRef<OpenACCClause *> Clauses) { + llvm::SmallVector<Expr *> Exprs; + Exprs.push_back(DevNumExpr); + Exprs.insert(Exprs.end(), QueueIdExprs.begin(), QueueIdExprs.end()); + return getSema().OpenACC().ActOnEndStmtDirective( + OpenACCDirectiveKind::Wait, BeginLoc, DirLoc, LParenLoc, QueuesLoc, + Exprs, RParenLoc, EndLoc, Clauses, {}); } ExprResult RebuildOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc) { @@ -12330,6 +12348,50 @@ StmtResult TreeTransform<Derived>::TransformOpenACCHostDataConstruct( TransformedClauses, StrBlock); } +template <typename Derived> +StmtResult +TreeTransform<Derived>::TransformOpenACCWaitConstruct(OpenACCWaitConstruct *C) { + getSema().OpenACC().ActOnConstruct(C->getDirectiveKind(), C->getBeginLoc()); + + ExprResult DevNumExpr; + if (C->hasDevNumExpr()) { + DevNumExpr = getDerived().TransformExpr(C->getDevNumExpr()); + + if (DevNumExpr.isUsable()) + DevNumExpr = getSema().OpenACC().ActOnIntExpr( + OpenACCDirectiveKind::Wait, OpenACCClauseKind::Invalid, + C->getBeginLoc(), DevNumExpr.get()); + } + + llvm::SmallVector<Expr *> QueueIdExprs; + + for (Expr *QE : C->getQueueIdExprs()) { + assert(QE && "Null queue id expr?"); + ExprResult NewEQ = getDerived().TransformExpr(QE); + + if (!NewEQ.isUsable()) + break; + NewEQ = getSema().OpenACC().ActOnIntExpr(OpenACCDirectiveKind::Wait, + OpenACCClauseKind::Invalid, + C->getBeginLoc(), NewEQ.get()); + if (NewEQ.isUsable()) + QueueIdExprs.push_back(NewEQ.get()); + } + + llvm::SmallVector<OpenACCClause *> TransformedClauses = + getDerived().TransformOpenACCClauseList(C->getDirectiveKind(), + C->clauses()); + + if (getSema().OpenACC().ActOnStartStmtDirective( + C->getDirectiveKind(), C->getBeginLoc(), TransformedClauses)) + return StmtError(); + + return getDerived().RebuildOpenACCWaitConstruct( + C->getBeginLoc(), C->getDirectiveLoc(), C->getLParenLoc(), + DevNumExpr.isUsable() ? DevNumExpr.get() : nullptr, C->getQueuesLoc(), + QueueIdExprs, C->getRParenLoc(), C->getEndLoc(), TransformedClauses); +} + template <typename Derived> ExprResult TreeTransform<Derived>::TransformOpenACCAsteriskSizeExpr( OpenACCAsteriskSizeExpr *E) { diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 21ad6c5a9faa33..8fe0412706ce3e 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -2870,6 +2870,22 @@ void ASTStmtReader::VisitOpenACCHostDataConstruct(OpenACCHostDataConstruct *S) { VisitOpenACCAssociatedStmtConstruct(S); } +void ASTStmtReader::VisitOpenACCWaitConstruct(OpenACCWaitConstruct *S) { + VisitStmt(S); + // Consume the count of Expressions. + (void)Record.readInt(); + VisitOpenACCConstructStmt(S); + S->LParenLoc = Record.readSourceLocation(); + S->RParenLoc = Record.readSourceLocation(); + S->QueuesLoc = Record.readSourceLocation(); + + for (unsigned I = 0; I < S->NumExprs; ++I) { + S->getExprPtr()[I] = cast_if_present<Expr>(Record.readSubStmt()); + assert((I == 0 || S->getExprPtr()[I] != nullptr) && + "Only first expression should be null"); + } +} + //===----------------------------------------------------------------------===// // HLSL Constructs/Directives. //===----------------------------------------------------------------------===// @@ -4365,6 +4381,12 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { S = OpenACCHostDataConstruct::CreateEmpty(Context, NumClauses); break; } + case STMT_OPENACC_WAIT_CONSTRUCT: { + unsigned NumExprs = Record[ASTStmtReader::NumStmtFields]; + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields + 1]; + S = OpenACCWaitConstruct::CreateEmpty(Context, NumExprs, NumClauses); + break; + } case EXPR_REQUIRES: { unsigned numLocalParameters = Record[ASTStmtReader::NumExprFields]; unsigned numRequirement = Record[ASTStmtReader::NumExprFields + 1]; diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index e55cbe1f6ecce6..f13443d18b612a 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -2951,6 +2951,20 @@ void ASTStmtWriter::VisitOpenACCHostDataConstruct(OpenACCHostDataConstruct *S) { Code = serialization::STMT_OPENACC_HOST_DATA_CONSTRUCT; } +void ASTStmtWriter::VisitOpenACCWaitConstruct(OpenACCWaitConstruct *S) { + VisitStmt(S); + Record.push_back(S->getExprs().size()); + VisitOpenACCConstructStmt(S); + Record.AddSourceLocation(S->LParenLoc); + Record.AddSourceLocation(S->RParenLoc); + Record.AddSourceLocation(S->QueuesLoc); + + for(Expr *E : S->getExprs()) + Record.AddStmt(E); + + Code = serialization::STMT_OPENACC_WAIT_CONSTRUCT; +} + //===----------------------------------------------------------------------===// // HLSL Constructs/Directives. //===----------------------------------------------------------------------===// diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index ae43c59511bfa7..0a74a80a6a62f9 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1829,6 +1829,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::OpenACCEnterDataConstructClass: case Stmt::OpenACCExitDataConstructClass: case Stmt::OpenACCHostDataConstructClass: + case Stmt::OpenACCWaitConstructClass: case Stmt::OMPUnrollDirectiveClass: case Stmt::OMPMetaDirectiveClass: case Stmt::HLSLOutArgExprClass: { diff --git a/clang/test/AST/ast-print-openacc-wait-construct.cpp b/clang/test/AST/ast-print-openacc-wait-construct.cpp new file mode 100644 index 00000000000000..35354596be8d03 --- /dev/null +++ b/clang/test/AST/ast-print-openacc-wait-construct.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -fopenacc -ast-print %s -o - | FileCheck %s + +void uses() { + int *iPtr; + int I; + float array[5]; + +// CHECK: #pragma acc wait() if(I == array[I]) +#pragma acc wait() if(I == array[I]) + +// CHECK: #pragma acc wait(*iPtr, I) async +#pragma acc wait(*iPtr, I) async + +// CHECK: #pragma acc wait(queues: *iPtr, I) async(*iPtr) +#pragma acc wait(queues:*iPtr, I) async(*iPtr) + +// CHECK: #pragma acc wait(devnum: I : *iPtr, I) async(I) +#pragma acc wait(devnum:I:*iPtr, I) async(I) + +// CHECK: #pragma acc wait(devnum: I : queues: *iPtr, I) if(I == array[I]) async(I) +#pragma acc wait(devnum:I:queues:*iPtr, I) if(I == array[I]) async(I) +} diff --git a/clang/test/ParserOpenACC/parse-wait-construct.c b/clang/test/ParserOpenACC/parse-wait-construct.c index 8f7ea8efd57668..17b7ecbde7856d 100644 --- a/clang/test/ParserOpenACC/parse-wait-construct.c +++ b/clang/test/ParserOpenACC/parse-wait-construct.c @@ -3,171 +3,135 @@ void func() { int i, j; - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} #pragma acc wait - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait clause-list - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait ( - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} #pragma acc wait () - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait () clause-list - // expected-error@+4{{expected expression}} - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+3{{expected expression}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait (devnum: - // expected-error@+2{{expected expression}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+1{{expected expression}} #pragma acc wait (devnum:) - // expected-error@+3{{expected expression}} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+2{{expected expression}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait (devnum:) clause-list - // expected-error@+4{{expected ':'}} - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+3{{expected ':'}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait (devnum: i + j - // expected-error@+2{{expected ':'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+1{{expected ':'}} #pragma acc wait (devnum: i + j) - // expected-error@+3{{expected ':'}} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+2{{expected ':'}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait (devnum: i + j) clause-list - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait (queues: - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} #pragma acc wait (queues:) - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait (queues:) clause-list - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait (devnum: i + j:queues: - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} #pragma acc wait (devnum: i + j:queues:) - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait (devnum: i + j:queues:) clause-list - // expected-error@+5{{use of undeclared identifier 'devnum'}} - // expected-error@+4{{expected ','}} - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+4{{use of undeclared identifier 'devnum'}} + // expected-error@+3{{expected ','}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait (queues:devnum: i + j - // expected-error@+3{{use of undeclared identifier 'devnum'}} - // expected-error@+2{{expected ','}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+2{{use of undeclared identifier 'devnum'}} + // expected-error@+1{{expected ','}} #pragma acc wait (queues:devnum: i + j) - // expected-error@+4{{use of undeclared identifier 'devnum'}} - // expected-error@+3{{expected ','}} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+3{{use of undeclared identifier 'devnum'}} + // expected-error@+2{{expected ','}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait (queues:devnum: i + j) clause-list - // expected-error@+4{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait(i, j, 1+1, 3.3 - // expected-error@+2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+1{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} #pragma acc wait(i, j, 1+1, 3.3) - // expected-error@+3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait(i, j, 1+1, 3.3) clause-list - // expected-error@+4{{expected expression}} - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+3{{expected expression}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait(, - // expected-error@+2{{expected expression}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+1{{expected expression}} #pragma acc wait(,) - // expected-error@+3{{expected expression}} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+2{{expected expression}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait(,) clause-list - // expected-error@+4{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait(queues:i, j, 1+1, 3.3 - // expected-error@+5{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-error@+4{{expected expression}} - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+4{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} + // expected-error@+3{{expected expression}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait(queues:i, j, 1+1, 3.3, - // expected-error@+2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+1{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} #pragma acc wait(queues:i, j, 1+1, 3.3) - // expected-error@+3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait(queues:i, j, 1+1, 3.3) clause-list - // expected-error@+4{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait(devnum:3:i, j, 1+1, 3.3 - // expected-error@+2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+1{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} #pragma acc wait(devnum:3:i, j, 1+1, 3.3) - // expected-error@+3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait(devnum:3:i, j, 1+1, 3.3) clause-list - // expected-error@+4{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait(devnum:3:queues:i, j, 1+1, 3.3 - // expected-error@+2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+1{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} #pragma acc wait(devnum:3:queues:i, j, 1+1, 3.3) - // expected-error@+3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait(devnum:3:queues:i, j, 1+1, 3.3) clause-list } diff --git a/clang/test/SemaOpenACC/combined-construct-default-clause.c b/clang/test/SemaOpenACC/combined-construct-default-clause.c index 43c2883f131845..2d77faa442a62f 100644 --- a/clang/test/SemaOpenACC/combined-construct-default-clause.c +++ b/clang/test/SemaOpenACC/combined-construct-default-clause.c @@ -35,7 +35,6 @@ void SingleOnly() { #pragma acc loop default(none) for(int i = 5; i < 10;++i); - // expected-warning@+2{{OpenACC construct 'wait' not yet implemented}} // expected-error@+1{{OpenACC 'default' clause is not valid on 'wait' directive}} #pragma acc wait default(none) while(0); diff --git a/clang/test/SemaOpenACC/compute-construct-default-clause.c b/clang/test/SemaOpenACC/compute-construct-default-clause.c index dfa5cd3f1c0d3e..86a758779fdf6d 100644 --- a/clang/test/SemaOpenACC/compute-construct-default-clause.c +++ b/clang/test/SemaOpenACC/compute-construct-default-clause.c @@ -35,7 +35,6 @@ void SingleOnly() { #pragma acc loop default(none) for(int i = 5; i < 10;++i); - // expected-warning@+2{{OpenACC construct 'wait' not yet implemented}} // expected-error@+1{{OpenACC 'default' clause is not valid on 'wait' directive}} #pragma acc wait default(none) while(0); diff --git a/clang/test/SemaOpenACC/unimplemented-construct.c b/clang/test/SemaOpenACC/unimplemented-construct.c index 3f4bc375cff800..42737eb08d93fe 100644 --- a/clang/test/SemaOpenACC/unimplemented-construct.c +++ b/clang/test/SemaOpenACC/unimplemented-construct.c @@ -4,8 +4,8 @@ #pragma acc routine struct S { -// expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} -#pragma acc wait +// expected-warning@+1{{OpenACC construct 'set' not yet implemented, pragma ignored}} +#pragma acc set int foo; }; diff --git a/clang/test/SemaOpenACC/wait-construct-ast.cpp b/clang/test/SemaOpenACC/wait-construct-ast.cpp new file mode 100644 index 00000000000000..58214f1f7c8867 --- /dev/null +++ b/clang/test/SemaOpenACC/wait-construct-ast.cpp @@ -0,0 +1,225 @@ +// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s + +#ifndef PCH_HELPER +#define PCH_HELPER + +int some_int(); +long some_long(); + +void NormalFunc() { + // CHECK-LABEL: NormalFunc + // CHECK-NEXT: CompoundStmt + +#pragma acc wait async(some_int()) + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<<NULL>> + // CHECK-NEXT: async clause + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' +#pragma acc wait() async + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<<NULL>> + // CHECK-NEXT: async clause +#pragma acc wait(some_int(), some_long()) if (some_int() < some_long()) + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<<NULL>> + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'some_long' + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '<' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'long' + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'some_long' +#pragma acc wait(queues:some_int(), some_long()) + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<<NULL>> + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'some_long' +#pragma acc wait(devnum:some_int() : queues:some_int(), some_long()) + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'some_long' +#pragma acc wait(devnum:some_int() : some_int(), some_long()) + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'some_long' +} + +template<typename T> +void TemplFunc(T t) { + // CHECK-LABEL: FunctionTemplateDecl {{.*}}TemplFunc + // CHECK-NEXT: TemplateTypeParmDecl + // CHECK-NEXT: FunctionDecl{{.*}}TemplFunc + // CHECK-NEXT: ParmVarDecl{{.*}} t 'T' + // CHECK-NEXT: CompoundStmt + +#pragma acc wait async(T::value) + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<<NULL>> + // CHECK-NEXT: async clause + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' + // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T' +#pragma acc wait() async + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<<NULL>> + // CHECK-NEXT: async clause +#pragma acc wait(t, T::value) if (T::value > t) + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<<NULL>> + // CHECK-NEXT: DeclRefExpr{{.*}} 'T' lvalue ParmVar{{.*}} 't' 'T' + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' + // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T' + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} '<dependent type>' '>' + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' + // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T' + // CHECK-NEXT: DeclRefExpr{{.*}} 'T' lvalue ParmVar{{.*}} 't' 'T' +#pragma acc wait(queues:typename T::IntTy{}, T::value) if (typename T::IntTy{} < typename T::ShortTy{}) + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<<NULL>> + // CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}}'typename T::IntTy' list + // CHECK-NEXT: InitListExpr + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' + // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T' + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} '<dependent type>' '<' + // CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}}'typename T::IntTy' list + // CHECK-NEXT: InitListExpr + // CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}}'typename T::ShortTy' list + // CHECK-NEXT: InitListExpr +#pragma acc wait(devnum:typename T::ShortTy{} : queues:some_int(), T::value) + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}}'typename T::ShortTy' list + // CHECK-NEXT: InitListExpr + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' + // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T' +#pragma acc wait(devnum:typename T::ShortTy{} : T::value, some_long()) + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}}'typename T::ShortTy' list + // CHECK-NEXT: InitListExpr + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' + // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'some_long' + + // Instantiation: + // CHECK-NEXT: FunctionDecl{{.*}} TemplFunc 'void (HasInt)' implicit_instantiation + // CHECK-NEXT: TemplateArgument type 'HasInt' + // CHECK-NEXT: RecordType{{.*}} 'HasInt' + // CHECK-NEXT: CXXRecord{{.*}} 'HasInt' + // CHECK-NEXT: ParmVarDecl{{.*}} t 'HasInt' + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<<NULL>> + // CHECK-NEXT: async clause + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const int' + // CHECK-NEXT: NestedNameSpecifier {{.*}}'HasInt' + // + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<<NULL>> + // CHECK-NEXT: async clause + // + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<<NULL>> + // CHECK-NEXT: ImplicitCastExpr{{.*}}'char' <UserDefinedConversion> + // CHECK-NEXT: CXXMemberCallExpr{{.*}}'char' + // CHECK-NEXT: MemberExpr{{.*}}.operator char + // CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar{{.*}} 't' 'HasInt' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const int' + // CHECK-NEXT: NestedNameSpecifier {{.*}}'HasInt' + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '>' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const int' + // CHECK-NEXT: NestedNameSpecifier {{.*}}'HasInt' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int' <IntegralCast> + // CHECK-NEXT: ImplicitCastExpr{{.*}}'char' <UserDefinedConversion> + // CHECK-NEXT: CXXMemberCallExpr{{.*}}'char' + // CHECK-NEXT: MemberExpr{{.*}}.operator char + // CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar{{.*}} 't' 'HasInt' + // + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<<NULL>> + // CHECK-NEXT: CXXFunctionalCastExpr{{.*}}'typename HasInt::IntTy':'int' + // CHECK-NEXT: InitListExpr{{.*}}'typename HasInt::IntTy':'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const int' + // CHECK-NEXT: NestedNameSpecifier {{.*}}'HasInt' + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '<' + // CHECK-NEXT: CXXFunctionalCastExpr{{.*}}'typename HasInt::IntTy':'int' + // CHECK-NEXT: InitListExpr{{.*}}'typename HasInt::IntTy':'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int' + // CHECK-NEXT: CXXFunctionalCastExpr{{.*}}'typename HasInt::ShortTy':'short' + // CHECK-NEXT: InitListExpr{{.*}}'typename HasInt::ShortTy':'short' + // + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: CXXFunctionalCastExpr{{.*}}'typename HasInt::ShortTy':'short' + // CHECK-NEXT: InitListExpr{{.*}}'typename HasInt::ShortTy':'short' + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const int' + // CHECK-NEXT: NestedNameSpecifier {{.*}}'HasInt' + // + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: CXXFunctionalCastExpr{{.*}}'typename HasInt::ShortTy':'short' + // CHECK-NEXT: InitListExpr{{.*}}'typename HasInt::ShortTy':'short' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const int' + // CHECK-NEXT: NestedNameSpecifier {{.*}}'HasInt' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay> + // CHECK-NEXT: DeclRefExpr{{.*}}'some_long' +} + +struct HasInt { + using IntTy = int; + using ShortTy = short; + static constexpr int value = 1; + + operator char(); +}; +void use() { + TemplFunc(HasInt{}); +} +#endif diff --git a/clang/test/SemaOpenACC/wait-construct.cpp b/clang/test/SemaOpenACC/wait-construct.cpp new file mode 100644 index 00000000000000..a68fc54b6e8f27 --- /dev/null +++ b/clang/test/SemaOpenACC/wait-construct.cpp @@ -0,0 +1,95 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +struct NotConvertible{} NC; +short getS(); +int getI(); + +struct AmbiguousConvert{ + operator int(); // #AMBIG_INT + operator short(); // #AMBIG_SHORT + operator float(); +} Ambiguous; + +struct ExplicitConvertOnly { + explicit operator int() const; // #EXPL_CONV +} Explicit; + +void uses() { + int arr[5]; +#pragma acc wait(getS(), getI()) +#pragma acc wait(devnum:getS(): getI()) +#pragma acc wait(devnum:getS(): queues: getI(), getS()) +#pragma acc wait(devnum:getS(): getI(), getS()) + + // expected-error@+1{{OpenACC directive 'wait' requires expression of integer type ('struct NotConvertible' invalid)}} +#pragma acc wait(devnum:NC : 5) + // expected-error@+1{{OpenACC directive 'wait' requires expression of integer type ('struct NotConvertible' invalid)}} +#pragma acc wait(devnum:5 : NC) + // expected-error@+3{{OpenACC directive 'wait' requires expression of integer type ('int[5]' invalid)}} + // expected-error@+2{{OpenACC directive 'wait' requires expression of integer type ('int[5]' invalid)}} + // expected-error@+1{{OpenACC directive 'wait' requires expression of integer type ('struct NotConvertible' invalid)}} +#pragma acc wait(devnum:arr : queues: arr, NC, 5) + + // 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 wait(Ambiguous) + + // 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 wait(4, Explicit, 5) + + // expected-error@+1{{use of undeclared identifier 'queues'}} +#pragma acc wait(devnum: queues: 5) + +#pragma acc wait async +#pragma acc wait async(getI()) + // expected-error@+1{{OpenACC clause 'async' requires expression of integer type ('struct NotConvertible' invalid)}} +#pragma acc wait async(NC) + +#pragma acc wait if(getI() < getS()) + // expected-error@+1{{value of type 'struct NotConvertible' is not contextually convertible to 'bool'}} +#pragma acc wait if(NC) + +} + +template<typename T> +void TestInst() { + // 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 wait(devnum:T::value :queues:T::ACValue) + + // 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 wait(devnum:T::EXValue :queues:T::ACValue) + + // expected-error@+1{{no member named 'Invalid' in 'HasInt'}} +#pragma acc wait(queues: T::Invalid, T::Invalid2) + + // 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 wait async(T::ACValue) + +#pragma acc wait if(T::value < T{}) + // expected-error@+1{{value of type 'const ExplicitConvertOnly' is not contextually convertible to 'bool'}} +#pragma acc wait if(T::EXValue) +} + +struct HasInt { + using IntTy = int; + using ShortTy = short; + static constexpr int value = 1; + static constexpr AmbiguousConvert ACValue; + static constexpr ExplicitConvertOnly EXValue; + + operator char(); +}; +void Inst() { + TestInst<HasInt>(); // #INST +} diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 701582138e053d..9bdc4c9f8ce238 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -2189,6 +2189,7 @@ class EnqueueVisitor : public ConstStmtVisitor<EnqueueVisitor, void>, void VisitOpenACCEnterDataConstruct(const OpenACCEnterDataConstruct *D); void VisitOpenACCExitDataConstruct(const OpenACCExitDataConstruct *D); void VisitOpenACCHostDataConstruct(const OpenACCHostDataConstruct *D); + void VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *D); void VisitOMPExecutableDirective(const OMPExecutableDirective *D); void VisitOMPLoopBasedDirective(const OMPLoopBasedDirective *D); void VisitOMPLoopDirective(const OMPLoopDirective *D); @@ -3632,6 +3633,12 @@ void EnqueueVisitor::VisitOpenACCHostDataConstruct( EnqueueChildren(Clause); } +void EnqueueVisitor::VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *C) { + EnqueueChildren(C); + for (auto *Clause : C->clauses()) + EnqueueChildren(Clause); +} + void EnqueueVisitor::VisitAnnotateAttr(const AnnotateAttr *A) { EnqueueChildren(A); } @@ -6394,6 +6401,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return cxstring::createRef("OpenACCExitDataConstruct"); case CXCursor_OpenACCHostDataConstruct: return cxstring::createRef("OpenACCHostDataConstruct"); + case CXCursor_OpenACCWaitConstruct: + return cxstring::createRef("OpenACCWaitConstruct"); } llvm_unreachable("Unhandled CXCursorKind"); diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp index 26935c45ce5f83..b9fd3b4c7f3645 100644 --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -900,6 +900,9 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, case Stmt::OpenACCHostDataConstructClass: K = CXCursor_OpenACCHostDataConstruct; break; + case Stmt::OpenACCWaitConstructClass: + K = CXCursor_OpenACCWaitConstruct; + break; case Stmt::OMPTargetParallelGenericLoopDirectiveClass: K = CXCursor_OMPTargetParallelGenericLoopDirective; break; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits