Skip to content

Commit 8d6dd13

Browse files
committed
[OpenACC] Implement loop 'gang' clause.
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 bae17a2 commit 8d6dd13

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)