Skip to content

Commit 5b25c31

Browse files
authored
[OpenACC] Implement loop 'gang' clause. (#112006)
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.
1 parent 3f156ef commit 5b25c31

22 files changed

+1336
-126
lines changed

clang/include/clang/AST/OpenACCClause.h

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -119,32 +119,6 @@ class OpenACCSeqClause : public OpenACCClause {
119119
}
120120
};
121121

122-
// Not yet implemented, but the type name is necessary for 'seq' diagnostics, so
123-
// this provides a basic, do-nothing implementation. We still need to add this
124-
// type to the visitors/etc, as well as get it to take its proper arguments.
125-
class OpenACCGangClause : public OpenACCClause {
126-
protected:
127-
OpenACCGangClause(SourceLocation BeginLoc, SourceLocation EndLoc)
128-
: OpenACCClause(OpenACCClauseKind::Gang, BeginLoc, EndLoc) {
129-
llvm_unreachable("Not yet implemented");
130-
}
131-
132-
public:
133-
static bool classof(const OpenACCClause *C) {
134-
return C->getClauseKind() == OpenACCClauseKind::Gang;
135-
}
136-
137-
static OpenACCGangClause *
138-
Create(const ASTContext &Ctx, SourceLocation BeginLoc, SourceLocation EndLoc);
139-
140-
child_range children() {
141-
return child_range(child_iterator(), child_iterator());
142-
}
143-
const_child_range children() const {
144-
return const_child_range(const_child_iterator(), const_child_iterator());
145-
}
146-
};
147-
148122
// Not yet implemented, but the type name is necessary for 'seq' diagnostics, so
149123
// this provides a basic, do-nothing implementation. We still need to add this
150124
// type to the visitors/etc, as well as get it to take its proper arguments.
@@ -177,7 +151,7 @@ class OpenACCVectorClause : public OpenACCClause {
177151
class OpenACCWorkerClause : public OpenACCClause {
178152
protected:
179153
OpenACCWorkerClause(SourceLocation BeginLoc, SourceLocation EndLoc)
180-
: OpenACCClause(OpenACCClauseKind::Gang, BeginLoc, EndLoc) {
154+
: OpenACCClause(OpenACCClauseKind::Worker, BeginLoc, EndLoc) {
181155
llvm_unreachable("Not yet implemented");
182156
}
183157

@@ -535,6 +509,38 @@ class OpenACCClauseWithSingleIntExpr : public OpenACCClauseWithExprs {
535509
Expr *getIntExpr() { return hasIntExpr() ? getExprs()[0] : nullptr; };
536510
};
537511

512+
class OpenACCGangClause final
513+
: public OpenACCClauseWithExprs,
514+
public llvm::TrailingObjects<OpenACCGangClause, Expr *, OpenACCGangKind> {
515+
protected:
516+
OpenACCGangClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
517+
ArrayRef<OpenACCGangKind> GangKinds,
518+
ArrayRef<Expr *> IntExprs, SourceLocation EndLoc);
519+
520+
OpenACCGangKind getGangKind(unsigned I) const {
521+
return getTrailingObjects<OpenACCGangKind>()[I];
522+
}
523+
524+
public:
525+
static bool classof(const OpenACCClause *C) {
526+
return C->getClauseKind() == OpenACCClauseKind::Gang;
527+
}
528+
529+
size_t numTrailingObjects(OverloadToken<Expr *>) const {
530+
return getNumExprs();
531+
}
532+
533+
unsigned getNumExprs() const { return getExprs().size(); }
534+
std::pair<OpenACCGangKind, const Expr *> getExpr(unsigned I) const {
535+
return {getGangKind(I), getExprs()[I]};
536+
}
537+
538+
static OpenACCGangClause *
539+
Create(const ASTContext &Ctx, SourceLocation BeginLoc,
540+
SourceLocation LParenLoc, ArrayRef<OpenACCGangKind> GangKinds,
541+
ArrayRef<Expr *> IntExprs, SourceLocation EndLoc);
542+
};
543+
538544
class OpenACCNumWorkersClause : public OpenACCClauseWithSingleIntExpr {
539545
OpenACCNumWorkersClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
540546
Expr *IntExpr, SourceLocation EndLoc);

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12576,6 +12576,7 @@ def err_acc_duplicate_clause_disallowed
1257612576
: Error<"OpenACC '%1' clause cannot appear more than once on a '%0' "
1257712577
"directive">;
1257812578
def note_acc_previous_clause_here : Note<"previous clause is here">;
12579+
def note_acc_previous_expr_here : Note<"previous expression is here">;
1257912580
def err_acc_branch_in_out_compute_construct
1258012581
: Error<"invalid %select{branch|return|throw}0 %select{out of|into}1 "
1258112582
"OpenACC Compute Construct">;
@@ -12682,6 +12683,24 @@ def err_acc_insufficient_loops
1268212683
def err_acc_intervening_code
1268312684
: Error<"inner loops must be tightly nested inside a '%0' clause on "
1268412685
"a 'loop' construct">;
12686+
def err_acc_gang_multiple_elt
12687+
: Error<"OpenACC 'gang' clause may have at most one %select{unnamed or "
12688+
"'num'|'dim'|'static'}0 argument">;
12689+
def err_acc_gang_arg_invalid
12690+
: Error<"'%0' argument on 'gang' clause is not permitted on a%select{n "
12691+
"orphaned|||}1 'loop' construct %select{|associated with a "
12692+
"'parallel' compute construct|associated with a 'kernels' compute "
12693+
"construct|associated with a 'serial' compute construct}1">;
12694+
def err_acc_gang_dim_value
12695+
: Error<"argument to 'gang' clause dimension must be %select{a constant "
12696+
"expression|1, 2, or 3: evaluated to %1}0">;
12697+
def err_acc_gang_num_gangs_conflict
12698+
: Error<"'num' argument to 'gang' clause not allowed on a 'loop' construct "
12699+
"associated with a 'kernels' construct that has a 'num_gangs' "
12700+
"clause">;
12701+
def err_acc_gang_inside_gang
12702+
: Error<"loop with a 'gang' clause may not exist in the region of a 'gang' "
12703+
"clause on a 'kernels' compute construct">;
1268512704

1268612705
// AMDGCN builtins diagnostics
1268712706
def err_amdgcn_global_load_lds_size_invalid_value : Error<"invalid size value">;

clang/include/clang/Basic/OpenACCClauses.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ VISIT_CLAUSE(DevicePtr)
4242
VISIT_CLAUSE(DeviceType)
4343
CLAUSE_ALIAS(DType, DeviceType, false)
4444
VISIT_CLAUSE(FirstPrivate)
45+
VISIT_CLAUSE(Gang)
4546
VISIT_CLAUSE(If)
4647
VISIT_CLAUSE(Independent)
4748
VISIT_CLAUSE(NoCreate)

clang/include/clang/Basic/OpenACCKinds.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,35 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Out,
550550
OpenACCReductionOperator Op) {
551551
return printOpenACCReductionOperator(Out, Op);
552552
}
553+
554+
enum class OpenACCGangKind : uint8_t {
555+
/// num:
556+
Num,
557+
/// dim:
558+
Dim,
559+
/// static:
560+
Static
561+
};
562+
563+
template <typename StreamTy>
564+
inline StreamTy &printOpenACCGangKind(StreamTy &Out, OpenACCGangKind GK) {
565+
switch (GK) {
566+
case OpenACCGangKind::Num:
567+
return Out << "num";
568+
case OpenACCGangKind::Dim:
569+
return Out << "dim";
570+
case OpenACCGangKind::Static:
571+
return Out << "static";
572+
}
573+
}
574+
inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out,
575+
OpenACCGangKind Op) {
576+
return printOpenACCGangKind(Out, Op);
577+
}
578+
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Out,
579+
OpenACCGangKind Op) {
580+
return printOpenACCGangKind(Out, Op);
581+
}
553582
} // namespace clang
554583

555584
#endif // LLVM_CLANG_BASIC_OPENACCKINDS_H

clang/include/clang/Parse/Parser.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3797,9 +3797,15 @@ class Parser : public CodeCompletionHandler {
37973797
bool ParseOpenACCSizeExprList(OpenACCClauseKind CK,
37983798
llvm::SmallVectorImpl<Expr *> &SizeExprs);
37993799
/// Parses a 'gang-arg-list', used for the 'gang' clause.
3800-
bool ParseOpenACCGangArgList(SourceLocation GangLoc);
3801-
/// Parses a 'gang-arg', used for the 'gang' clause.
3802-
bool ParseOpenACCGangArg(SourceLocation GangLoc);
3800+
bool ParseOpenACCGangArgList(SourceLocation GangLoc,
3801+
llvm::SmallVectorImpl<OpenACCGangKind> &GKs,
3802+
llvm::SmallVectorImpl<Expr *> &IntExprs);
3803+
3804+
using OpenACCGangArgRes = std::pair<OpenACCGangKind, ExprResult>;
3805+
/// Parses a 'gang-arg', used for the 'gang' clause. Returns a pair of the
3806+
/// ExprResult (which contains the validity of the expression), plus the gang
3807+
/// kind for the current argument.
3808+
OpenACCGangArgRes ParseOpenACCGangArg(SourceLocation GangLoc);
38033809
/// Parses a 'condition' expr, ensuring it results in a
38043810
ExprResult ParseOpenACCConditionExpr();
38053811

clang/include/clang/Sema/SemaOpenACC.h

Lines changed: 73 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,20 @@ class SemaOpenACC : public SemaBase {
3838
/// haven't had their 'parent' compute construct set yet. Entires will only be
3939
/// made to this list in the case where we know the loop isn't an orphan.
4040
llvm::SmallVector<OpenACCLoopConstruct *> ParentlessLoopConstructs;
41-
/// Whether we are inside of a compute construct, and should add loops to the
42-
/// above collection.
43-
bool InsideComputeConstruct = false;
41+
42+
struct ComputeConstructInfo {
43+
/// Which type of compute construct we are inside of, which we can use to
44+
/// determine whether we should add loops to the above collection. We can
45+
/// also use it to diagnose loop construct clauses.
46+
OpenACCDirectiveKind Kind = OpenACCDirectiveKind::Invalid;
47+
// If we have an active compute construct, stores the list of clauses we've
48+
// prepared for it, so that we can diagnose limitations on child constructs.
49+
ArrayRef<OpenACCClause *> Clauses;
50+
} ActiveComputeConstructInfo;
51+
52+
bool isInComputeConstruct() const {
53+
return ActiveComputeConstructInfo.Kind != OpenACCDirectiveKind::Invalid;
54+
}
4455

4556
/// Certain clauses care about the same things that aren't specific to the
4657
/// individual clause, but can be shared by a few, so store them here. All
@@ -99,6 +110,15 @@ class SemaOpenACC : public SemaBase {
99110
} TileInfo;
100111

101112
public:
113+
ComputeConstructInfo &getActiveComputeConstructInfo() {
114+
return ActiveComputeConstructInfo;
115+
}
116+
117+
/// If there is a current 'active' loop construct with a 'gang' clause on a
118+
/// 'kernel' construct, this will have the source location for it. This
119+
/// permits us to implement the restriction of no further 'gang' clauses.
120+
SourceLocation LoopGangClauseOnKernelLoc;
121+
102122
// Redeclaration of the version in OpenACCClause.h.
103123
using DeviceTypeArgument = std::pair<IdentifierInfo *, SourceLocation>;
104124

@@ -149,9 +169,14 @@ class SemaOpenACC : public SemaBase {
149169
Expr *LoopCount;
150170
};
151171

172+
struct GangDetails {
173+
SmallVector<OpenACCGangKind> GangKinds;
174+
SmallVector<Expr *> IntExprs;
175+
};
176+
152177
std::variant<std::monostate, DefaultDetails, ConditionDetails,
153178
IntExprDetails, VarListDetails, WaitDetails, DeviceTypeDetails,
154-
ReductionDetails, CollapseDetails>
179+
ReductionDetails, CollapseDetails, GangDetails>
155180
Details = std::monostate{};
156181

157182
public:
@@ -245,9 +270,18 @@ class SemaOpenACC : public SemaBase {
245270
ClauseKind == OpenACCClauseKind::NumWorkers ||
246271
ClauseKind == OpenACCClauseKind::Async ||
247272
ClauseKind == OpenACCClauseKind::Tile ||
273+
ClauseKind == OpenACCClauseKind::Gang ||
248274
ClauseKind == OpenACCClauseKind::VectorLength) &&
249275
"Parsed clause kind does not have a int exprs");
250276

277+
if (ClauseKind == OpenACCClauseKind::Gang) {
278+
// There might not be any gang int exprs, as this is an optional
279+
// argument.
280+
if (std::holds_alternative<std::monostate>(Details))
281+
return {};
282+
return std::get<GangDetails>(Details).IntExprs;
283+
}
284+
251285
return std::get<IntExprDetails>(Details).IntExprs;
252286
}
253287

@@ -259,6 +293,16 @@ class SemaOpenACC : public SemaBase {
259293
return std::get<ReductionDetails>(Details).Op;
260294
}
261295

296+
ArrayRef<OpenACCGangKind> getGangKinds() const {
297+
assert(ClauseKind == OpenACCClauseKind::Gang &&
298+
"Parsed clause kind does not have gang kind");
299+
// The args on gang are optional, so this might not actually hold
300+
// anything.
301+
if (std::holds_alternative<std::monostate>(Details))
302+
return {};
303+
return std::get<GangDetails>(Details).GangKinds;
304+
}
305+
262306
ArrayRef<Expr *> getVarList() {
263307
assert((ClauseKind == OpenACCClauseKind::Private ||
264308
ClauseKind == OpenACCClauseKind::NoCreate ||
@@ -371,6 +415,25 @@ class SemaOpenACC : public SemaBase {
371415
Details = IntExprDetails{std::move(IntExprs)};
372416
}
373417

418+
void setGangDetails(ArrayRef<OpenACCGangKind> GKs,
419+
ArrayRef<Expr *> IntExprs) {
420+
assert(ClauseKind == OpenACCClauseKind::Gang &&
421+
"Parsed Clause kind does not have gang details");
422+
assert(GKs.size() == IntExprs.size() && "Mismatched kind/size?");
423+
424+
Details = GangDetails{{GKs.begin(), GKs.end()},
425+
{IntExprs.begin(), IntExprs.end()}};
426+
}
427+
428+
void setGangDetails(llvm::SmallVector<OpenACCGangKind> &&GKs,
429+
llvm::SmallVector<Expr *> &&IntExprs) {
430+
assert(ClauseKind == OpenACCClauseKind::Gang &&
431+
"Parsed Clause kind does not have gang details");
432+
assert(GKs.size() == IntExprs.size() && "Mismatched kind/size?");
433+
434+
Details = GangDetails{std::move(GKs), std::move(IntExprs)};
435+
}
436+
374437
void setVarListDetails(ArrayRef<Expr *> VarList, bool IsReadOnly,
375438
bool IsZero) {
376439
assert((ClauseKind == OpenACCClauseKind::Private ||
@@ -545,10 +608,12 @@ class SemaOpenACC : public SemaBase {
545608
SourceLocation RBLoc);
546609
/// Checks the loop depth value for a collapse clause.
547610
ExprResult CheckCollapseLoopCount(Expr *LoopCount);
548-
/// Checks a single size expr for a tile clause. 'gang' could possibly call
549-
/// this, but has slightly stricter rules as to valid values.
611+
/// Checks a single size expr for a tile clause.
550612
ExprResult CheckTileSizeExpr(Expr *SizeExpr);
551613

614+
// Check a single expression on a gang clause.
615+
ExprResult CheckGangExpr(OpenACCGangKind GK, Expr *E);
616+
552617
ExprResult BuildOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc);
553618
ExprResult ActOnOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc);
554619

@@ -595,8 +660,9 @@ class SemaOpenACC : public SemaBase {
595660
/// Loop needing its parent construct.
596661
class AssociatedStmtRAII {
597662
SemaOpenACC &SemaRef;
598-
bool WasInsideComputeConstruct;
663+
ComputeConstructInfo OldActiveComputeConstructInfo;
599664
OpenACCDirectiveKind DirKind;
665+
SourceLocation OldLoopGangClauseOnKernelLoc;
600666
llvm::SmallVector<OpenACCLoopConstruct *> ParentlessLoopConstructs;
601667
LoopInConstructRAII LoopRAII;
602668

clang/lib/AST/OpenACCClause.cpp

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ bool OpenACCClauseWithExprs::classof(const OpenACCClause *C) {
2626
return OpenACCWaitClause::classof(C) || OpenACCNumGangsClause::classof(C) ||
2727
OpenACCTileClause::classof(C) ||
2828
OpenACCClauseWithSingleIntExpr::classof(C) ||
29-
OpenACCClauseWithVarList::classof(C);
29+
OpenACCGangClause::classof(C) || OpenACCClauseWithVarList::classof(C);
3030
}
3131
bool OpenACCClauseWithVarList::classof(const OpenACCClause *C) {
3232
return OpenACCPrivateClause::classof(C) ||
@@ -125,6 +125,21 @@ OpenACCNumWorkersClause::OpenACCNumWorkersClause(SourceLocation BeginLoc,
125125
"Condition expression type not scalar/dependent");
126126
}
127127

128+
OpenACCGangClause::OpenACCGangClause(SourceLocation BeginLoc,
129+
SourceLocation LParenLoc,
130+
ArrayRef<OpenACCGangKind> GangKinds,
131+
ArrayRef<Expr *> IntExprs,
132+
SourceLocation EndLoc)
133+
: OpenACCClauseWithExprs(OpenACCClauseKind::Gang, BeginLoc, LParenLoc,
134+
EndLoc) {
135+
assert(GangKinds.size() == IntExprs.size() && "Mismatch exprs/kind?");
136+
std::uninitialized_copy(IntExprs.begin(), IntExprs.end(),
137+
getTrailingObjects<Expr *>());
138+
setExprs(MutableArrayRef(getTrailingObjects<Expr *>(), IntExprs.size()));
139+
std::uninitialized_copy(GangKinds.begin(), GangKinds.end(),
140+
getTrailingObjects<OpenACCGangKind>());
141+
}
142+
128143
OpenACCNumWorkersClause *
129144
OpenACCNumWorkersClause::Create(const ASTContext &C, SourceLocation BeginLoc,
130145
SourceLocation LParenLoc, Expr *IntExpr,
@@ -376,11 +391,16 @@ OpenACCSeqClause *OpenACCSeqClause::Create(const ASTContext &C,
376391
return new (Mem) OpenACCSeqClause(BeginLoc, EndLoc);
377392
}
378393

379-
OpenACCGangClause *OpenACCGangClause::Create(const ASTContext &C,
380-
SourceLocation BeginLoc,
381-
SourceLocation EndLoc) {
382-
void *Mem = C.Allocate(sizeof(OpenACCGangClause));
383-
return new (Mem) OpenACCGangClause(BeginLoc, EndLoc);
394+
OpenACCGangClause *
395+
OpenACCGangClause::Create(const ASTContext &C, SourceLocation BeginLoc,
396+
SourceLocation LParenLoc,
397+
ArrayRef<OpenACCGangKind> GangKinds,
398+
ArrayRef<Expr *> IntExprs, SourceLocation EndLoc) {
399+
void *Mem =
400+
C.Allocate(OpenACCGangClause::totalSizeToAlloc<Expr *, OpenACCGangKind>(
401+
IntExprs.size(), GangKinds.size()));
402+
return new (Mem)
403+
OpenACCGangClause(BeginLoc, LParenLoc, GangKinds, IntExprs, EndLoc);
384404
}
385405

386406
OpenACCWorkerClause *OpenACCWorkerClause::Create(const ASTContext &C,
@@ -600,3 +620,21 @@ void OpenACCClausePrinter::VisitCollapseClause(const OpenACCCollapseClause &C) {
600620
printExpr(C.getLoopCount());
601621
OS << ")";
602622
}
623+
624+
void OpenACCClausePrinter::VisitGangClause(const OpenACCGangClause &C) {
625+
OS << "gang";
626+
627+
if (C.getNumExprs() > 0) {
628+
OS << "(";
629+
bool first = true;
630+
for (unsigned I = 0; I < C.getNumExprs(); ++I) {
631+
if (!first)
632+
OS << ", ";
633+
first = false;
634+
635+
OS << C.getExpr(I).first << ": ";
636+
printExpr(C.getExpr(I).second);
637+
}
638+
OS << ")";
639+
}
640+
}

0 commit comments

Comments
 (0)