Skip to content

Commit 39351f8

Browse files
committed
[OpenACC] Implement AST/Sema for combined constructs
Combined constructs (OpenACC 3.3 section 2.11) are a short-cut for writing a `loop` construct immediately inside of a `compute` construct. However, this interaction requires we do additional work to ensure that we get the semantics between the two correct, as well as diagnostics. This patch adds the semantic analysis for the constructs (but no clauses), as well as the AST nodes.
1 parent 7387338 commit 39351f8

35 files changed

+1630
-194
lines changed

clang/include/clang-c/Index.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2166,7 +2166,9 @@ enum CXCursorKind {
21662166
*/
21672167
CXCursor_OpenACCLoopConstruct = 321,
21682168

2169-
CXCursor_LastStmt = CXCursor_OpenACCLoopConstruct,
2169+
CXCursor_OpenACCCombinedConstruct = 322,
2170+
2171+
CXCursor_LastStmt = CXCursor_OpenACCCombinedConstruct,
21702172

21712173
/**
21722174
* Cursor that represents the translation unit itself.

clang/include/clang/AST/RecursiveASTVisitor.h

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4049,22 +4049,15 @@ bool RecursiveASTVisitor<Derived>::VisitOpenACCClauseList(
40494049

40504050
for (const auto *C : Clauses)
40514051
TRY_TO(VisitOpenACCClause(C));
4052-
// if (const auto *WithCond = dyn_cast<OopenACCClauseWithCondition>(C);
4053-
// WithCond && WIthCond->hasConditionExpr()) {
4054-
// TRY_TO(TraverseStmt(WithCond->getConditionExpr());
4055-
// } else if (const auto *
4056-
// }
4057-
// OpenACCClauseWithCondition::getConditionExpr/hasConditionExpr
4058-
//OpenACCClauseWithExprs::children (might be null?)
4059-
// TODO OpenACC: When we have Clauses with expressions, we should visit them
4060-
// here.
40614052
return true;
40624053
}
40634054

40644055
DEF_TRAVERSE_STMT(OpenACCComputeConstruct,
40654056
{ TRY_TO(TraverseOpenACCAssociatedStmtConstruct(S)); })
40664057
DEF_TRAVERSE_STMT(OpenACCLoopConstruct,
40674058
{ TRY_TO(TraverseOpenACCAssociatedStmtConstruct(S)); })
4059+
DEF_TRAVERSE_STMT(OpenACCCombinedConstruct,
4060+
{ TRY_TO(TraverseOpenACCAssociatedStmtConstruct(S)); })
40684061

40694062
// Traverse HLSL: Out argument expression
40704063
DEF_TRAVERSE_STMT(HLSLOutArgExpr, {})

clang/include/clang/AST/StmtOpenACC.h

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -166,11 +166,6 @@ class OpenACCComputeConstruct final
166166
}
167167

168168
void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); }
169-
// Serialization helper function that searches the structured block for 'loop'
170-
// constructs that should be associated with this, and sets their parent
171-
// compute construct to this one. This isn't necessary normally, since we have
172-
// the ability to record the state during parsing.
173-
void findAndSetChildLoops();
174169

175170
public:
176171
static bool classof(const Stmt *T) {
@@ -204,6 +199,8 @@ class OpenACCLoopConstruct final
204199
friend class ASTStmtWriter;
205200
friend class ASTStmtReader;
206201
friend class ASTContext;
202+
friend class OpenACCAssociatedStmtConstruct;
203+
friend class OpenACCCombinedConstruct;
207204
friend class OpenACCComputeConstruct;
208205

209206
OpenACCLoopConstruct(unsigned NumClauses);
@@ -243,5 +240,57 @@ class OpenACCLoopConstruct final
243240
return ParentComputeConstructKind;
244241
}
245242
};
243+
244+
// This class represents a 'combined' construct, which has a bunch of rules
245+
// shared with both loop and compute constructs.
246+
class OpenACCCombinedConstruct final
247+
: public OpenACCAssociatedStmtConstruct,
248+
public llvm::TrailingObjects<OpenACCCombinedConstruct,
249+
const OpenACCClause *> {
250+
OpenACCCombinedConstruct(unsigned NumClauses)
251+
: OpenACCAssociatedStmtConstruct(
252+
OpenACCCombinedConstructClass, OpenACCDirectiveKind::Invalid,
253+
SourceLocation{}, SourceLocation{}, SourceLocation{},
254+
/*AssociatedStmt=*/nullptr) {
255+
std::uninitialized_value_construct(
256+
getTrailingObjects<const OpenACCClause *>(),
257+
getTrailingObjects<const OpenACCClause *>() + NumClauses);
258+
setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
259+
NumClauses));
260+
}
261+
262+
OpenACCCombinedConstruct(OpenACCDirectiveKind K, SourceLocation Start,
263+
SourceLocation DirectiveLoc, SourceLocation End,
264+
ArrayRef<const OpenACCClause *> Clauses,
265+
Stmt *StructuredBlock)
266+
: OpenACCAssociatedStmtConstruct(OpenACCCombinedConstructClass, K, Start,
267+
DirectiveLoc, End, StructuredBlock) {
268+
assert(isOpenACCCombinedDirectiveKind(K) &&
269+
"Only parallel loop, serial loop, and kernels loop constructs "
270+
"should be represented by this type");
271+
272+
std::uninitialized_copy(Clauses.begin(), Clauses.end(),
273+
getTrailingObjects<const OpenACCClause *>());
274+
setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
275+
Clauses.size()));
276+
}
277+
void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); }
278+
279+
public:
280+
static bool classof(const Stmt *T) {
281+
return T->getStmtClass() == OpenACCCombinedConstructClass;
282+
}
283+
284+
static OpenACCCombinedConstruct *CreateEmpty(const ASTContext &C,
285+
unsigned NumClauses);
286+
static OpenACCCombinedConstruct *
287+
Create(const ASTContext &C, OpenACCDirectiveKind K, SourceLocation Start,
288+
SourceLocation DirectiveLoc, SourceLocation End,
289+
ArrayRef<const OpenACCClause *> Clauses, Stmt *StructuredBlock);
290+
Stmt *getLoop() { return getAssociatedStmt(); }
291+
const Stmt *getLoop() const {
292+
return const_cast<OpenACCCombinedConstruct *>(this)->getLoop();
293+
}
294+
};
246295
} // namespace clang
247296
#endif // LLVM_CLANG_AST_STMTOPENACC_H

clang/include/clang/AST/TextNodeDumper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,7 @@ class TextNodeDumper
410410
void VisitHLSLOutArgExpr(const HLSLOutArgExpr *E);
411411
void VisitOpenACCConstructStmt(const OpenACCConstructStmt *S);
412412
void VisitOpenACCLoopConstruct(const OpenACCLoopConstruct *S);
413+
void VisitOpenACCCombinedConstruct(const OpenACCCombinedConstruct *S);
413414
void VisitOpenACCAsteriskSizeExpr(const OpenACCAsteriskSizeExpr *S);
414415
void VisitEmbedExpr(const EmbedExpr *S);
415416
void VisitAtomicExpr(const AtomicExpr *AE);

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12613,11 +12613,11 @@ def note_acc_previous_clause_here : Note<"previous clause is here">;
1261312613
def note_acc_previous_expr_here : Note<"previous expression is here">;
1261412614
def err_acc_branch_in_out_compute_construct
1261512615
: Error<"invalid %select{branch|return|throw}0 %select{out of|into}1 "
12616-
"OpenACC Compute Construct">;
12616+
"OpenACC Compute/Combined Construct">;
1261712617
def note_acc_branch_into_compute_construct
12618-
: Note<"invalid branch into OpenACC Compute Construct">;
12618+
: Note<"invalid branch into OpenACC Compute/Combined Construct">;
1261912619
def note_acc_branch_out_of_compute_construct
12620-
: Note<"invalid branch out of OpenACC Compute Construct">;
12620+
: Note<"invalid branch out of OpenACC Compute/Combined Construct">;
1262112621
def warn_acc_if_self_conflict
1262212622
: Warning<"OpenACC construct 'self' has no effect when an 'if' clause "
1262312623
"evaluates to true">,
@@ -12691,7 +12691,7 @@ def err_acc_reduction_composite_member_type :Error<
1269112691
"OpenACC 'reduction' composite variable must not have non-scalar field">;
1269212692
def note_acc_reduction_composite_member_loc : Note<"invalid field is here">;
1269312693
def err_acc_loop_not_for_loop
12694-
: Error<"OpenACC 'loop' construct can only be applied to a 'for' loop">;
12694+
: Error<"OpenACC '%0' construct can only be applied to a 'for' loop">;
1269512695
def note_acc_construct_here : Note<"'%0' construct is here">;
1269612696
def err_acc_loop_spec_conflict
1269712697
: Error<"OpenACC clause '%0' on '%1' construct conflicts with previous "
@@ -12749,16 +12749,16 @@ def err_reduction_op_mismatch
1274912749
: Error<"OpenACC 'reduction' variable must have the same operator in all "
1275012750
"nested constructs (%0 vs %1)">;
1275112751
def err_acc_loop_variable_type
12752-
: Error<"loop variable of loop associated with an OpenACC 'loop' construct "
12752+
: Error<"loop variable of loop associated with an OpenACC '%0' construct "
1275312753
"must be of integer, pointer, or random-access-iterator type (is "
12754-
"%0)">;
12754+
"%1)">;
1275512755
def err_acc_loop_variable
12756-
: Error<"OpenACC 'loop' construct must have initialization clause in "
12756+
: Error<"OpenACC '%0' construct must have initialization clause in "
1275712757
"canonical form ('var = init' or 'T var = init')">;
1275812758
def err_acc_loop_terminating_condition
12759-
: Error<"OpenACC 'loop' construct must have a terminating condition">;
12759+
: Error<"OpenACC '%0' construct must have a terminating condition">;
1276012760
def err_acc_loop_not_monotonic
12761-
: Error<"OpenACC 'loop' variable must monotonically increase or decrease "
12761+
: Error<"OpenACC '%0' variable must monotonically increase or decrease "
1276212762
"('++', '--', or compound assignment)">;
1276312763

1276412764
// AMDGCN builtins diagnostics

clang/include/clang/Basic/OpenACCKinds.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,12 @@ inline bool isOpenACCComputeDirectiveKind(OpenACCDirectiveKind K) {
152152
K == OpenACCDirectiveKind::Kernels;
153153
}
154154

155+
inline bool isOpenACCCombinedDirectiveKind(OpenACCDirectiveKind K) {
156+
return K == OpenACCDirectiveKind::ParallelLoop ||
157+
K == OpenACCDirectiveKind::SerialLoop ||
158+
K == OpenACCDirectiveKind::KernelsLoop;
159+
}
160+
155161
enum class OpenACCAtomicKind : uint8_t {
156162
Read,
157163
Write,

clang/include/clang/Basic/StmtNodes.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ def OpenACCAssociatedStmtConstruct
307307
: StmtNode<OpenACCConstructStmt, /*abstract=*/1>;
308308
def OpenACCComputeConstruct : StmtNode<OpenACCAssociatedStmtConstruct>;
309309
def OpenACCLoopConstruct : StmtNode<OpenACCAssociatedStmtConstruct>;
310+
def OpenACCCombinedConstruct : StmtNode<OpenACCAssociatedStmtConstruct>;
310311

311312
// OpenACC Additional Expressions.
312313
def OpenACCAsteriskSizeExpr : StmtNode<Expr>;

clang/include/clang/Sema/Scope.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,8 @@ class Scope {
154154
/// depth of recursion.
155155
LambdaScope = 0x8000000,
156156
/// This is the scope of an OpenACC Compute Construct, which restricts
157-
/// jumping into/out of it.
157+
/// jumping into/out of it. We also use this to represent 'combined'
158+
/// constructs, since they have the same behavior.
158159
OpenACCComputeConstructScope = 0x10000000,
159160

160161
/// This is a scope of type alias declaration.

clang/include/clang/Sema/SemaOpenACC.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,14 @@ class SemaOpenACC : public SemaBase {
170170
/// 'worker' clauses.
171171
SourceLocation LoopVectorClauseLoc;
172172
/// If there is a current 'active' loop construct that does NOT have a 'seq'
173-
/// clause on it, this has that source location. This permits us to implement
174-
/// the 'loop' restrictions on the loop variable. This can be extended via
175-
/// 'collapse', so we need to keep this around for a while.
176-
SourceLocation LoopWithoutSeqLoc;
173+
/// clause on it, this has that source location and loop Directive 'kind'.
174+
/// This permits us to implement the 'loop' restrictions on the loop variable.
175+
/// This can be extended via 'collapse', so we need to keep this around for a
176+
/// while.
177+
struct LoopWithoutSeqCheckingInfo {
178+
OpenACCDirectiveKind Kind = OpenACCDirectiveKind::Invalid;
179+
SourceLocation Loc;
180+
} LoopWithoutSeqInfo;
177181

178182
// Redeclaration of the version in OpenACCClause.h.
179183
using DeviceTypeArgument = std::pair<IdentifierInfo *, SourceLocation>;
@@ -762,7 +766,7 @@ class SemaOpenACC : public SemaBase {
762766
SourceLocation OldLoopGangClauseOnKernelLoc;
763767
SourceLocation OldLoopWorkerClauseLoc;
764768
SourceLocation OldLoopVectorClauseLoc;
765-
SourceLocation OldLoopWithoutSeqLoc;
769+
LoopWithoutSeqCheckingInfo OldLoopWithoutSeqInfo;
766770
llvm::SmallVector<OpenACCReductionClause *> ActiveReductionClauses;
767771
LoopInConstructRAII LoopRAII;
768772

clang/include/clang/Serialization/ASTBitCodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2005,6 +2005,7 @@ enum StmtCode {
20052005
// OpenACC Constructs/Exprs
20062006
STMT_OPENACC_COMPUTE_CONSTRUCT,
20072007
STMT_OPENACC_LOOP_CONSTRUCT,
2008+
STMT_OPENACC_COMBINED_CONSTRUCT,
20082009
EXPR_OPENACC_ASTERISK_SIZE,
20092010

20102011
// HLSL Constructs

clang/lib/AST/StmtOpenACC.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,25 @@ OpenACCLoopConstruct *OpenACCLoopConstruct::Create(
8989
OpenACCLoopConstruct(ParentKind, BeginLoc, DirLoc, EndLoc, Clauses, Loop);
9090
return Inst;
9191
}
92+
93+
OpenACCCombinedConstruct *
94+
OpenACCCombinedConstruct::CreateEmpty(const ASTContext &C,
95+
unsigned NumClauses) {
96+
void *Mem = C.Allocate(
97+
OpenACCCombinedConstruct::totalSizeToAlloc<const OpenACCClause *>(
98+
NumClauses));
99+
auto *Inst = new (Mem) OpenACCCombinedConstruct(NumClauses);
100+
return Inst;
101+
}
102+
103+
OpenACCCombinedConstruct *OpenACCCombinedConstruct::Create(
104+
const ASTContext &C, OpenACCDirectiveKind DK, SourceLocation BeginLoc,
105+
SourceLocation DirLoc, SourceLocation EndLoc,
106+
ArrayRef<const OpenACCClause *> Clauses, Stmt *Loop) {
107+
void *Mem = C.Allocate(
108+
OpenACCCombinedConstruct::totalSizeToAlloc<const OpenACCClause *>(
109+
Clauses.size()));
110+
auto *Inst = new (Mem)
111+
OpenACCCombinedConstruct(DK, BeginLoc, DirLoc, EndLoc, Clauses, Loop);
112+
return Inst;
113+
}

clang/lib/AST/StmtPrinter.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,18 @@ void StmtPrinter::VisitOpenACCLoopConstruct(OpenACCLoopConstruct *S) {
11841184
PrintStmt(S->getLoop());
11851185
}
11861186

1187+
void StmtPrinter::VisitOpenACCCombinedConstruct(OpenACCCombinedConstruct *S) {
1188+
Indent() << "#pragma acc " << S->getDirectiveKind();
1189+
if (!S->clauses().empty()) {
1190+
OS << ' ';
1191+
OpenACCClausePrinter Printer(OS, Policy);
1192+
Printer.VisitClauseList(S->clauses());
1193+
}
1194+
OS << '\n';
1195+
1196+
PrintStmt(S->getLoop());
1197+
}
1198+
11871199
//===----------------------------------------------------------------------===//
11881200
// Expr printing methods.
11891201
//===----------------------------------------------------------------------===//

clang/lib/AST/StmtProfile.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2688,6 +2688,15 @@ void StmtProfiler::VisitOpenACCLoopConstruct(const OpenACCLoopConstruct *S) {
26882688
P.VisitOpenACCClauseList(S->clauses());
26892689
}
26902690

2691+
void StmtProfiler::VisitOpenACCCombinedConstruct(
2692+
const OpenACCCombinedConstruct *S) {
2693+
// VisitStmt handles children, so the Loop is handled.
2694+
VisitStmt(S);
2695+
2696+
OpenACCClauseProfiler P{*this};
2697+
P.VisitOpenACCClauseList(S->clauses());
2698+
}
2699+
26912700
void StmtProfiler::VisitHLSLOutArgExpr(const HLSLOutArgExpr *S) {
26922701
VisitStmt(S);
26932702
}

clang/lib/AST/TextNodeDumper.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2931,6 +2931,11 @@ void TextNodeDumper::VisitOpenACCLoopConstruct(const OpenACCLoopConstruct *S) {
29312931
OS << " parent: " << S->getParentComputeConstructKind();
29322932
}
29332933

2934+
void TextNodeDumper::VisitOpenACCCombinedConstruct(
2935+
const OpenACCCombinedConstruct *S) {
2936+
OS << " " << S->getDirectiveKind();
2937+
}
2938+
29342939
void TextNodeDumper::VisitEmbedExpr(const EmbedExpr *S) {
29352940
AddChild("begin", [=] { OS << S->getStartingElementPos(); });
29362941
AddChild("number of elements", [=] { OS << S->getDataElementCount(); });

clang/lib/CodeGen/CGStmt.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
455455
case Stmt::OpenACCLoopConstructClass:
456456
EmitOpenACCLoopConstruct(cast<OpenACCLoopConstruct>(*S));
457457
break;
458+
case Stmt::OpenACCCombinedConstructClass:
459+
EmitOpenACCCombinedConstruct(cast<OpenACCCombinedConstruct>(*S));
460+
break;
458461
}
459462
}
460463

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4087,6 +4087,13 @@ class CodeGenFunction : public CodeGenTypeCache {
40874087
EmitStmt(S.getLoop());
40884088
}
40894089

4090+
void EmitOpenACCCombinedConstruct(const OpenACCCombinedConstruct &S) {
4091+
// TODO OpenACC: Implement this. It is currently implemented as a 'no-op',
4092+
// simply emitting its loop, but in the future we will implement
4093+
// some sort of IR.
4094+
EmitStmt(S.getLoop());
4095+
}
4096+
40904097
//===--------------------------------------------------------------------===//
40914098
// LValue Expression Emission
40924099
//===--------------------------------------------------------------------===//

clang/lib/Parse/ParseOpenACC.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,9 @@ bool doesDirectiveHaveAssociatedStmt(OpenACCDirectiveKind DirKind) {
571571
case OpenACCDirectiveKind::Parallel:
572572
case OpenACCDirectiveKind::Serial:
573573
case OpenACCDirectiveKind::Kernels:
574+
case OpenACCDirectiveKind::ParallelLoop:
575+
case OpenACCDirectiveKind::SerialLoop:
576+
case OpenACCDirectiveKind::KernelsLoop:
574577
case OpenACCDirectiveKind::Loop:
575578
return true;
576579
}
@@ -582,6 +585,9 @@ unsigned getOpenACCScopeFlags(OpenACCDirectiveKind DirKind) {
582585
case OpenACCDirectiveKind::Parallel:
583586
case OpenACCDirectiveKind::Serial:
584587
case OpenACCDirectiveKind::Kernels:
588+
case OpenACCDirectiveKind::ParallelLoop:
589+
case OpenACCDirectiveKind::SerialLoop:
590+
case OpenACCDirectiveKind::KernelsLoop:
585591
// Mark this as a BreakScope/ContinueScope as well as a compute construct
586592
// so that we can diagnose trying to 'break'/'continue' inside of one.
587593
return Scope::BreakScope | Scope::ContinueScope |

clang/lib/Sema/JumpDiagnostics.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,16 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S,
616616
return;
617617
}
618618

619+
case Stmt::OpenACCCombinedConstructClass: {
620+
unsigned NewParentScope = Scopes.size();
621+
OpenACCCombinedConstruct *CC = cast<OpenACCCombinedConstruct>(S);
622+
Scopes.push_back(GotoScope(
623+
ParentScope, diag::note_acc_branch_into_compute_construct,
624+
diag::note_acc_branch_out_of_compute_construct, CC->getBeginLoc()));
625+
BuildScopeInformation(CC->getLoop(), NewParentScope);
626+
return;
627+
}
628+
619629
default:
620630
if (auto *ED = dyn_cast<OMPExecutableDirective>(S)) {
621631
if (!ED->isStandaloneDirective()) {

clang/lib/Sema/SemaExceptionSpec.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,6 +1406,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
14061406
// Most statements can throw if any substatement can throw.
14071407
case Stmt::OpenACCComputeConstructClass:
14081408
case Stmt::OpenACCLoopConstructClass:
1409+
case Stmt::OpenACCCombinedConstructClass:
14091410
case Stmt::AttributedStmtClass:
14101411
case Stmt::BreakStmtClass:
14111412
case Stmt::CapturedStmtClass:

0 commit comments

Comments
 (0)