llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-modules Author: Erich Keane (erichkeane) <details> <summary>Changes</summary> The 'gang' clause is used to specify parallel execution of loops, thus has some complicated rules depending on the 'loop's associated compute construct. This patch implements all of those. --- Patch is 75.19 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/112006.diff 22 Files Affected: - (modified) clang/include/clang/AST/OpenACCClause.h (+33-27) - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+19) - (modified) clang/include/clang/Basic/OpenACCClauses.def (+1) - (modified) clang/include/clang/Basic/OpenACCKinds.h (+29) - (modified) clang/include/clang/Parse/Parser.h (+9-3) - (modified) clang/include/clang/Sema/SemaOpenACC.h (+73-7) - (modified) clang/lib/AST/OpenACCClause.cpp (+44-6) - (modified) clang/lib/AST/StmtProfile.cpp (+6) - (modified) clang/lib/AST/TextNodeDumper.cpp (+11) - (modified) clang/lib/Parse/ParseOpenACC.cpp (+35-15) - (modified) clang/lib/Sema/SemaOpenACC.cpp (+252-24) - (modified) clang/lib/Sema/TreeTransform.h (+23) - (modified) clang/lib/Serialization/ASTReader.cpp (+12-1) - (modified) clang/lib/Serialization/ASTWriter.cpp (+10-1) - (modified) clang/test/AST/ast-print-openacc-loop-construct.cpp (+82) - (modified) clang/test/ParserOpenACC/parse-clauses.c (+22-28) - (modified) clang/test/SemaOpenACC/compute-construct-device_type-clause.c (+1-2) - (modified) clang/test/SemaOpenACC/loop-construct-auto_seq_independent-clauses.c (+4-11) - (modified) clang/test/SemaOpenACC/loop-construct-device_type-clause.c (-1) - (added) clang/test/SemaOpenACC/loop-construct-gang-ast.cpp (+330) - (added) clang/test/SemaOpenACC/loop-construct-gang-clause.cpp (+335) - (modified) clang/tools/libclang/CIndex.cpp (+5) ``````````diff diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h index b500acc768e55a..f3a09eb651458d 100644 --- a/clang/include/clang/AST/OpenACCClause.h +++ b/clang/include/clang/AST/OpenACCClause.h @@ -119,32 +119,6 @@ class OpenACCSeqClause : public OpenACCClause { } }; -// Not yet implemented, but the type name is necessary for 'seq' diagnostics, so -// this provides a basic, do-nothing implementation. We still need to add this -// type to the visitors/etc, as well as get it to take its proper arguments. -class OpenACCGangClause : public OpenACCClause { -protected: - OpenACCGangClause(SourceLocation BeginLoc, SourceLocation EndLoc) - : OpenACCClause(OpenACCClauseKind::Gang, BeginLoc, EndLoc) { - llvm_unreachable("Not yet implemented"); - } - -public: - static bool classof(const OpenACCClause *C) { - return C->getClauseKind() == OpenACCClauseKind::Gang; - } - - static OpenACCGangClause * - Create(const ASTContext &Ctx, SourceLocation BeginLoc, SourceLocation EndLoc); - - child_range children() { - return child_range(child_iterator(), child_iterator()); - } - const_child_range children() const { - return const_child_range(const_child_iterator(), const_child_iterator()); - } -}; - // Not yet implemented, but the type name is necessary for 'seq' diagnostics, so // this provides a basic, do-nothing implementation. We still need to add this // type to the visitors/etc, as well as get it to take its proper arguments. @@ -177,7 +151,7 @@ class OpenACCVectorClause : public OpenACCClause { class OpenACCWorkerClause : public OpenACCClause { protected: OpenACCWorkerClause(SourceLocation BeginLoc, SourceLocation EndLoc) - : OpenACCClause(OpenACCClauseKind::Gang, BeginLoc, EndLoc) { + : OpenACCClause(OpenACCClauseKind::Worker, BeginLoc, EndLoc) { llvm_unreachable("Not yet implemented"); } @@ -535,6 +509,38 @@ class OpenACCClauseWithSingleIntExpr : public OpenACCClauseWithExprs { Expr *getIntExpr() { return hasIntExpr() ? getExprs()[0] : nullptr; }; }; +class OpenACCGangClause final + : public OpenACCClauseWithExprs, + public llvm::TrailingObjects<OpenACCGangClause, Expr *, OpenACCGangKind> { +protected: + OpenACCGangClause(SourceLocation BeginLoc, SourceLocation LParenLoc, + ArrayRef<OpenACCGangKind> GangKinds, + ArrayRef<Expr *> IntExprs, SourceLocation EndLoc); + + OpenACCGangKind getGangKind(unsigned I) const { + return getTrailingObjects<OpenACCGangKind>()[I]; + } + +public: + static bool classof(const OpenACCClause *C) { + return C->getClauseKind() == OpenACCClauseKind::Gang; + } + + size_t numTrailingObjects(OverloadToken<Expr *>) const { + return getNumExprs(); + } + + unsigned getNumExprs() const { return getExprs().size(); } + std::pair<OpenACCGangKind, const Expr *> getExpr(unsigned I) const { + return {getGangKind(I), getExprs()[I]}; + } + + static OpenACCGangClause * + Create(const ASTContext &Ctx, SourceLocation BeginLoc, + SourceLocation LParenLoc, ArrayRef<OpenACCGangKind> GangKinds, + ArrayRef<Expr *> IntExprs, SourceLocation EndLoc); +}; + class OpenACCNumWorkersClause : public OpenACCClauseWithSingleIntExpr { OpenACCNumWorkersClause(SourceLocation BeginLoc, SourceLocation LParenLoc, Expr *IntExpr, SourceLocation EndLoc); diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 41cdd09e971651..3c62a017005e59 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12576,6 +12576,7 @@ def err_acc_duplicate_clause_disallowed : Error<"OpenACC '%1' clause cannot appear more than once on a '%0' " "directive">; def note_acc_previous_clause_here : Note<"previous clause is here">; +def note_acc_previous_expr_here : Note<"previous expression is here">; def err_acc_branch_in_out_compute_construct : Error<"invalid %select{branch|return|throw}0 %select{out of|into}1 " "OpenACC Compute Construct">; @@ -12682,6 +12683,24 @@ def err_acc_insufficient_loops def err_acc_intervening_code : Error<"inner loops must be tightly nested inside a '%0' clause on " "a 'loop' construct">; +def err_acc_gang_multiple_elt + : Error<"OpenACC 'gang' clause may have at most one %select{unnamed or " + "'num'|'dim'|'static'}0 argument">; +def err_acc_gang_arg_invalid + : Error<"'%0' argument on 'gang' clause is not permitted on a%select{n " + "orphaned|||}1 'loop' construct %select{|associated with a " + "'parallel' compute construct|associated with a 'kernels' compute " + "construct|associated with a 'serial' compute construct}1">; +def err_acc_gang_dim_value + : Error<"argument to 'gang' clause dimension must be %select{a constant " + "expression|1, 2, or 3: evaluated to %1}0">; +def err_acc_gang_num_gangs_conflict + : Error<"'num' argument to 'gang' clause not allowed on a 'loop' construct " + "associated with a 'kernels' construct that has a 'num_gangs' " + "clause">; +def err_acc_gang_inside_gang + : Error<"loop with a 'gang' clause may not exist in the region of a 'gang' " + "clause on a 'kernels' compute construct">; // AMDGCN builtins diagnostics def err_amdgcn_global_load_lds_size_invalid_value : Error<"invalid size value">; diff --git a/clang/include/clang/Basic/OpenACCClauses.def b/clang/include/clang/Basic/OpenACCClauses.def index a380e5ae69c418..2a098de31eb618 100644 --- a/clang/include/clang/Basic/OpenACCClauses.def +++ b/clang/include/clang/Basic/OpenACCClauses.def @@ -42,6 +42,7 @@ VISIT_CLAUSE(DevicePtr) VISIT_CLAUSE(DeviceType) CLAUSE_ALIAS(DType, DeviceType, false) VISIT_CLAUSE(FirstPrivate) +VISIT_CLAUSE(Gang) VISIT_CLAUSE(If) VISIT_CLAUSE(Independent) VISIT_CLAUSE(NoCreate) diff --git a/clang/include/clang/Basic/OpenACCKinds.h b/clang/include/clang/Basic/OpenACCKinds.h index c4dfe3bedc13a7..3f48ebca708a42 100644 --- a/clang/include/clang/Basic/OpenACCKinds.h +++ b/clang/include/clang/Basic/OpenACCKinds.h @@ -550,6 +550,35 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Out, OpenACCReductionOperator Op) { return printOpenACCReductionOperator(Out, Op); } + +enum class OpenACCGangKind : uint8_t { + /// num: + Num, + /// dim: + Dim, + /// static: + Static +}; + +template <typename StreamTy> +inline StreamTy &printOpenACCGangKind(StreamTy &Out, OpenACCGangKind GK) { + switch (GK) { + case OpenACCGangKind::Num: + return Out << "num"; + case OpenACCGangKind::Dim: + return Out << "dim"; + case OpenACCGangKind::Static: + return Out << "static"; + } +} +inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out, + OpenACCGangKind Op) { + return printOpenACCGangKind(Out, Op); +} +inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Out, + OpenACCGangKind Op) { + return printOpenACCGangKind(Out, Op); +} } // namespace clang #endif // LLVM_CLANG_BASIC_OPENACCKINDS_H diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index dbcb545058a026..045ee754a242b3 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3797,9 +3797,15 @@ class Parser : public CodeCompletionHandler { bool ParseOpenACCSizeExprList(OpenACCClauseKind CK, llvm::SmallVectorImpl<Expr *> &SizeExprs); /// Parses a 'gang-arg-list', used for the 'gang' clause. - bool ParseOpenACCGangArgList(SourceLocation GangLoc); - /// Parses a 'gang-arg', used for the 'gang' clause. - bool ParseOpenACCGangArg(SourceLocation GangLoc); + bool ParseOpenACCGangArgList(SourceLocation GangLoc, + llvm::SmallVectorImpl<OpenACCGangKind> &GKs, + llvm::SmallVectorImpl<Expr *> &IntExprs); + + using OpenACCGangArgRes = std::pair<OpenACCGangKind, ExprResult>; + /// Parses a 'gang-arg', used for the 'gang' clause. Returns a pair of the + /// ExprResult (which contains the validity of the expression), plus the gang + /// kind for the current argument. + OpenACCGangArgRes ParseOpenACCGangArg(SourceLocation GangLoc); /// Parses a 'condition' expr, ensuring it results in a ExprResult ParseOpenACCConditionExpr(); diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h index 97386d2378b758..59a9648d5f9380 100644 --- a/clang/include/clang/Sema/SemaOpenACC.h +++ b/clang/include/clang/Sema/SemaOpenACC.h @@ -38,9 +38,20 @@ class SemaOpenACC : public SemaBase { /// haven't had their 'parent' compute construct set yet. Entires will only be /// made to this list in the case where we know the loop isn't an orphan. llvm::SmallVector<OpenACCLoopConstruct *> ParentlessLoopConstructs; - /// Whether we are inside of a compute construct, and should add loops to the - /// above collection. - bool InsideComputeConstruct = false; + + struct ComputeConstructInfo { + /// Which type of compute construct we are inside of, which we can use to + /// determine whether we should add loops to the above collection. We can + /// also use it to diagnose loop construct clauses. + OpenACCDirectiveKind Kind = OpenACCDirectiveKind::Invalid; + // If we have an active compute construct, stores the list of clauses we've + // prepared for it, so that we can diagnose limitations on child constructs. + ArrayRef<OpenACCClause *> Clauses; + } ActiveComputeConstructInfo; + + bool isInComputeConstruct() const { + return ActiveComputeConstructInfo.Kind != OpenACCDirectiveKind::Invalid; + } /// Certain clauses care about the same things that aren't specific to the /// individual clause, but can be shared by a few, so store them here. All @@ -99,6 +110,15 @@ class SemaOpenACC : public SemaBase { } TileInfo; public: + ComputeConstructInfo &getActiveComputeConstructInfo() { + return ActiveComputeConstructInfo; + } + + /// If there is a current 'active' loop construct with a 'gang' clause on a + /// 'kernel' construct, this will have the source location for it. This + /// permits us to implement the restriction of no further 'gang' clauses. + SourceLocation LoopGangClauseOnKernelLoc; + // Redeclaration of the version in OpenACCClause.h. using DeviceTypeArgument = std::pair<IdentifierInfo *, SourceLocation>; @@ -149,9 +169,14 @@ class SemaOpenACC : public SemaBase { Expr *LoopCount; }; + struct GangDetails { + SmallVector<OpenACCGangKind> GangKinds; + SmallVector<Expr *> IntExprs; + }; + std::variant<std::monostate, DefaultDetails, ConditionDetails, IntExprDetails, VarListDetails, WaitDetails, DeviceTypeDetails, - ReductionDetails, CollapseDetails> + ReductionDetails, CollapseDetails, GangDetails> Details = std::monostate{}; public: @@ -245,9 +270,18 @@ class SemaOpenACC : public SemaBase { ClauseKind == OpenACCClauseKind::NumWorkers || ClauseKind == OpenACCClauseKind::Async || ClauseKind == OpenACCClauseKind::Tile || + ClauseKind == OpenACCClauseKind::Gang || ClauseKind == OpenACCClauseKind::VectorLength) && "Parsed clause kind does not have a int exprs"); + if (ClauseKind == OpenACCClauseKind::Gang) { + // There might not be any gang int exprs, as this is an optional + // argument. + if (std::holds_alternative<std::monostate>(Details)) + return {}; + return std::get<GangDetails>(Details).IntExprs; + } + return std::get<IntExprDetails>(Details).IntExprs; } @@ -259,6 +293,16 @@ class SemaOpenACC : public SemaBase { return std::get<ReductionDetails>(Details).Op; } + ArrayRef<OpenACCGangKind> getGangKinds() const { + assert(ClauseKind == OpenACCClauseKind::Gang && + "Parsed clause kind does not have gang kind"); + // The args on gang are optional, so this might not actually hold + // anything. + if (std::holds_alternative<std::monostate>(Details)) + return {}; + return std::get<GangDetails>(Details).GangKinds; + } + ArrayRef<Expr *> getVarList() { assert((ClauseKind == OpenACCClauseKind::Private || ClauseKind == OpenACCClauseKind::NoCreate || @@ -371,6 +415,25 @@ class SemaOpenACC : public SemaBase { Details = IntExprDetails{std::move(IntExprs)}; } + void setGangDetails(ArrayRef<OpenACCGangKind> GKs, + ArrayRef<Expr *> IntExprs) { + assert(ClauseKind == OpenACCClauseKind::Gang && + "Parsed Clause kind does not have gang details"); + assert(GKs.size() == IntExprs.size() && "Mismatched kind/size?"); + + Details = GangDetails{{GKs.begin(), GKs.end()}, + {IntExprs.begin(), IntExprs.end()}}; + } + + void setGangDetails(llvm::SmallVector<OpenACCGangKind> &&GKs, + llvm::SmallVector<Expr *> &&IntExprs) { + assert(ClauseKind == OpenACCClauseKind::Gang && + "Parsed Clause kind does not have gang details"); + assert(GKs.size() == IntExprs.size() && "Mismatched kind/size?"); + + Details = GangDetails{std::move(GKs), std::move(IntExprs)}; + } + void setVarListDetails(ArrayRef<Expr *> VarList, bool IsReadOnly, bool IsZero) { assert((ClauseKind == OpenACCClauseKind::Private || @@ -545,10 +608,12 @@ class SemaOpenACC : public SemaBase { SourceLocation RBLoc); /// Checks the loop depth value for a collapse clause. ExprResult CheckCollapseLoopCount(Expr *LoopCount); - /// Checks a single size expr for a tile clause. 'gang' could possibly call - /// this, but has slightly stricter rules as to valid values. + /// Checks a single size expr for a tile clause. ExprResult CheckTileSizeExpr(Expr *SizeExpr); + // Check a single expression on a gang clause. + ExprResult CheckGangExpr(OpenACCGangKind GK, Expr *E); + ExprResult BuildOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc); ExprResult ActOnOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc); @@ -595,8 +660,9 @@ class SemaOpenACC : public SemaBase { /// Loop needing its parent construct. class AssociatedStmtRAII { SemaOpenACC &SemaRef; - bool WasInsideComputeConstruct; + ComputeConstructInfo OldActiveComputeConstructInfo; OpenACCDirectiveKind DirKind; + SourceLocation OldLoopGangClauseOnKernelLoc; llvm::SmallVector<OpenACCLoopConstruct *> ParentlessLoopConstructs; LoopInConstructRAII LoopRAII; diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp index 0b34ed6189593e..6fb8fe0b8cfeef 100644 --- a/clang/lib/AST/OpenACCClause.cpp +++ b/clang/lib/AST/OpenACCClause.cpp @@ -26,7 +26,7 @@ bool OpenACCClauseWithExprs::classof(const OpenACCClause *C) { return OpenACCWaitClause::classof(C) || OpenACCNumGangsClause::classof(C) || OpenACCTileClause::classof(C) || OpenACCClauseWithSingleIntExpr::classof(C) || - OpenACCClauseWithVarList::classof(C); + OpenACCGangClause::classof(C) || OpenACCClauseWithVarList::classof(C); } bool OpenACCClauseWithVarList::classof(const OpenACCClause *C) { return OpenACCPrivateClause::classof(C) || @@ -125,6 +125,21 @@ OpenACCNumWorkersClause::OpenACCNumWorkersClause(SourceLocation BeginLoc, "Condition expression type not scalar/dependent"); } +OpenACCGangClause::OpenACCGangClause(SourceLocation BeginLoc, + SourceLocation LParenLoc, + ArrayRef<OpenACCGangKind> GangKinds, + ArrayRef<Expr *> IntExprs, + SourceLocation EndLoc) + : OpenACCClauseWithExprs(OpenACCClauseKind::Gang, BeginLoc, LParenLoc, + EndLoc) { + assert(GangKinds.size() == IntExprs.size() && "Mismatch exprs/kind?"); + std::uninitialized_copy(IntExprs.begin(), IntExprs.end(), + getTrailingObjects<Expr *>()); + setExprs(MutableArrayRef(getTrailingObjects<Expr *>(), IntExprs.size())); + std::uninitialized_copy(GangKinds.begin(), GangKinds.end(), + getTrailingObjects<OpenACCGangKind>()); +} + OpenACCNumWorkersClause * OpenACCNumWorkersClause::Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc, Expr *IntExpr, @@ -376,11 +391,16 @@ OpenACCSeqClause *OpenACCSeqClause::Create(const ASTContext &C, return new (Mem) OpenACCSeqClause(BeginLoc, EndLoc); } -OpenACCGangClause *OpenACCGangClause::Create(const ASTContext &C, - SourceLocation BeginLoc, - SourceLocation EndLoc) { - void *Mem = C.Allocate(sizeof(OpenACCGangClause)); - return new (Mem) OpenACCGangClause(BeginLoc, EndLoc); +OpenACCGangClause * +OpenACCGangClause::Create(const ASTContext &C, SourceLocation BeginLoc, + SourceLocation LParenLoc, + ArrayRef<OpenACCGangKind> GangKinds, + ArrayRef<Expr *> IntExprs, SourceLocation EndLoc) { + void *Mem = + C.Allocate(OpenACCGangClause::totalSizeToAlloc<Expr *, OpenACCGangKind>( + IntExprs.size(), GangKinds.size())); + return new (Mem) + OpenACCGangClause(BeginLoc, LParenLoc, GangKinds, IntExprs, EndLoc); } OpenACCWorkerClause *OpenACCWorkerClause::Create(const ASTContext &C, @@ -600,3 +620,21 @@ void OpenACCClausePrinter::VisitCollapseClause(const OpenACCCollapseClause &C) { printExpr(C.getLoopCount()); OS << ")"; } + +void OpenACCClausePrinter::VisitGangClause(const OpenACCGangClause &C) { + OS << "gang"; + + if (C.getNumExprs() > 0) { + OS << "("; + bool first = true; + for (unsigned I = 0; I < C.getNumExprs(); ++I) { + if (!first) + OS << ", "; + first = false; + + OS << C.getExpr(I).first << ": "; + printExpr(C.getExpr(I).second); + } + OS << ")"; + } +} diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 4d177fd6c5968c..6161b1403ed35d 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2646,6 +2646,12 @@ void OpenACCClauseProfiler::VisitIndependentClause( void OpenACCClauseProfiler::VisitSeqClause(const OpenACCSeqClause &Clause) {} +void OpenACCClauseProfiler::VisitGangClause(const OpenACCGangClause &Clause) { + for (unsigned I = 0; I < Clause.getNumExprs(); ++I) { + Profiler.VisitStmt(Clause.getExpr(I).second); + } +} + void OpenACCClauseProfiler::VisitReductionClause( const OpenACCReductionClause &Clause) { for (auto *E : Clause.getVarList()) diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 15b23d60c3ffab..ac8c196777f9b8 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -425,6 +425,17 @@ void TextNodeDumper::Visit(const OpenACCClause *C) { // but print 'clause' here so it is clear what is happening from the dump. OS << " clause"; break; + case OpenACCClauseKind::Gang: { + OS << " clause"; + // print the list of all GangKinds, so that there is some sort of + // relationship to the expressions listed afterwards. + auto *GC = cast<OpenACCGangClause>(C); + + for (unsigned I = 0; I < GC->getNumExprs(); ++I) { + OS << " " << GC->getExpr(I).first; + } + break; + } case OpenACCClauseKind::Collapse: OS << " clause"; if (cast<OpenACCCollapseClause>(C)->hasForce()) diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index b27e50b147f4a8..635039b724e6a0 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -797,23 +797,26 @@ bool Parser::ParseOpenACCSizeExprList( /// [num:]int-expr /// dim:int-expr /// static:size-expr -bool Parser::ParseOpenACCGangArg(SourceLocation GangLoc) { +Parser::OpenACCGangArgRes Parser::ParseOpenACCGangArg(SourceL... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/112006 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits