Skip to content

Commit 42f4e50

Browse files
authored
[OpenACC] Loop construct basic Sema and AST work (#93742)
This patch implements the 'loop' construct AST, as well as the basic appertainment rule. Additionally, it sets up the 'parent' compute construct, which is necessary for codegen/other diagnostics. A 'loop' can apply to a for or range-for loop, otherwise it has no other restrictions (though some of its clauses do).
1 parent 2d9b837 commit 42f4e50

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+886
-304
lines changed

clang/include/clang-c/Index.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2150,7 +2150,11 @@ enum CXCursorKind {
21502150
*/
21512151
CXCursor_OpenACCComputeConstruct = 320,
21522152

2153-
CXCursor_LastStmt = CXCursor_OpenACCComputeConstruct,
2153+
/** OpenACC Loop Construct.
2154+
*/
2155+
CXCursor_OpenACCLoopConstruct = 321,
2156+
2157+
CXCursor_LastStmt = CXCursor_OpenACCLoopConstruct,
21542158

21552159
/**
21562160
* Cursor that represents the translation unit itself.

clang/include/clang/AST/RecursiveASTVisitor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4000,6 +4000,8 @@ bool RecursiveASTVisitor<Derived>::VisitOpenACCClauseList(
40004000

40014001
DEF_TRAVERSE_STMT(OpenACCComputeConstruct,
40024002
{ TRY_TO(TraverseOpenACCAssociatedStmtConstruct(S)); })
4003+
DEF_TRAVERSE_STMT(OpenACCLoopConstruct,
4004+
{ TRY_TO(TraverseOpenACCAssociatedStmtConstruct(S)); })
40034005

40044006
// FIXME: look at the following tricky-seeming exprs to see if we
40054007
// need to recurse on anything. These are ones that have methods

clang/include/clang/AST/StmtOpenACC.h

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ class OpenACCAssociatedStmtConstruct : public OpenACCConstructStmt {
113113
return const_cast<OpenACCAssociatedStmtConstruct *>(this)->children();
114114
}
115115
};
116+
117+
class OpenACCLoopConstruct;
116118
/// This class represents a compute construct, representing a 'Kind' of
117119
/// `parallel', 'serial', or 'kernel'. These constructs are associated with a
118120
/// 'structured block', defined as:
@@ -165,6 +167,11 @@ class OpenACCComputeConstruct final
165167
}
166168

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

169176
public:
170177
static bool classof(const Stmt *T) {
@@ -176,12 +183,74 @@ class OpenACCComputeConstruct final
176183
static OpenACCComputeConstruct *
177184
Create(const ASTContext &C, OpenACCDirectiveKind K, SourceLocation BeginLoc,
178185
SourceLocation DirectiveLoc, SourceLocation EndLoc,
179-
ArrayRef<const OpenACCClause *> Clauses, Stmt *StructuredBlock);
186+
ArrayRef<const OpenACCClause *> Clauses, Stmt *StructuredBlock,
187+
ArrayRef<OpenACCLoopConstruct *> AssociatedLoopConstructs);
180188

181189
Stmt *getStructuredBlock() { return getAssociatedStmt(); }
182190
const Stmt *getStructuredBlock() const {
183191
return const_cast<OpenACCComputeConstruct *>(this)->getStructuredBlock();
184192
}
185193
};
194+
/// This class represents a 'loop' construct. The 'loop' construct applies to a
195+
/// 'for' loop (or range-for loop), and is optionally associated with a Compute
196+
/// Construct.
197+
class OpenACCLoopConstruct final
198+
: public OpenACCAssociatedStmtConstruct,
199+
public llvm::TrailingObjects<OpenACCLoopConstruct,
200+
const OpenACCClause *> {
201+
// The compute construct this loop is associated with, or nullptr if this is
202+
// an orphaned loop construct, or if it hasn't been set yet. Because we
203+
// construct the directives at the end of their statement, the 'parent'
204+
// construct is not yet available at the time of construction, so this needs
205+
// to be set 'later'.
206+
const OpenACCComputeConstruct *ParentComputeConstruct = nullptr;
207+
208+
friend class ASTStmtWriter;
209+
friend class ASTStmtReader;
210+
friend class ASTContext;
211+
friend class OpenACCComputeConstruct;
212+
213+
OpenACCLoopConstruct(unsigned NumClauses);
214+
215+
OpenACCLoopConstruct(SourceLocation Start, SourceLocation DirLoc,
216+
SourceLocation End,
217+
ArrayRef<const OpenACCClause *> Clauses, Stmt *Loop);
218+
void setLoop(Stmt *Loop);
219+
220+
void setParentComputeConstruct(OpenACCComputeConstruct *CC) {
221+
assert(!ParentComputeConstruct && "Parent already set?");
222+
ParentComputeConstruct = CC;
223+
}
224+
225+
public:
226+
static bool classof(const Stmt *T) {
227+
return T->getStmtClass() == OpenACCLoopConstructClass;
228+
}
229+
230+
static OpenACCLoopConstruct *CreateEmpty(const ASTContext &C,
231+
unsigned NumClauses);
232+
233+
static OpenACCLoopConstruct *
234+
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation DirLoc,
235+
SourceLocation EndLoc, ArrayRef<const OpenACCClause *> Clauses,
236+
Stmt *Loop);
237+
238+
Stmt *getLoop() { return getAssociatedStmt(); }
239+
const Stmt *getLoop() const {
240+
return const_cast<OpenACCLoopConstruct *>(this)->getLoop();
241+
}
242+
243+
/// OpenACC 3.3 2.9:
244+
/// An orphaned loop construct is a loop construct that is not lexically
245+
/// enclosed within a compute construct. The parent compute construct of a
246+
/// loop construct is the nearest compute construct that lexically contains
247+
/// the loop construct.
248+
bool isOrphanedLoopConstruct() const {
249+
return ParentComputeConstruct == nullptr;
250+
}
251+
const OpenACCComputeConstruct *getParentComputeConstruct() const {
252+
return ParentComputeConstruct;
253+
}
254+
};
186255
} // namespace clang
187256
#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
@@ -408,6 +408,7 @@ class TextNodeDumper
408408
VisitLifetimeExtendedTemporaryDecl(const LifetimeExtendedTemporaryDecl *D);
409409
void VisitHLSLBufferDecl(const HLSLBufferDecl *D);
410410
void VisitOpenACCConstructStmt(const OpenACCConstructStmt *S);
411+
void VisitOpenACCLoopConstruct(const OpenACCLoopConstruct *S);
411412
};
412413

413414
} // namespace clang

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12413,6 +12413,9 @@ def err_acc_reduction_composite_type
1241312413
def err_acc_reduction_composite_member_type :Error<
1241412414
"OpenACC 'reduction' composite variable must not have non-scalar field">;
1241512415
def note_acc_reduction_composite_member_loc : Note<"invalid field is here">;
12416+
def err_acc_loop_not_for_loop
12417+
: Error<"OpenACC 'loop' construct can only be applied to a 'for' loop">;
12418+
def note_acc_construct_here : Note<"'%0' construct is here">;
1241612419

1241712420
// AMDGCN builtins diagnostics
1241812421
def err_amdgcn_global_load_lds_size_invalid_value : Error<"invalid size value">;

clang/include/clang/Basic/StmtNodes.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,3 +302,4 @@ def OpenACCConstructStmt : StmtNode<Stmt, /*abstract=*/1>;
302302
def OpenACCAssociatedStmtConstruct
303303
: StmtNode<OpenACCConstructStmt, /*abstract=*/1>;
304304
def OpenACCComputeConstruct : StmtNode<OpenACCAssociatedStmtConstruct>;
305+
def OpenACCLoopConstruct : StmtNode<OpenACCAssociatedStmtConstruct>;

clang/include/clang/Sema/SemaOpenACC.h

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#define LLVM_CLANG_SEMA_SEMAOPENACC_H
1616

1717
#include "clang/AST/DeclGroup.h"
18+
#include "clang/AST/StmtOpenACC.h"
1819
#include "clang/Basic/OpenACCKinds.h"
1920
#include "clang/Basic/SourceLocation.h"
2021
#include "clang/Sema/Ownership.h"
@@ -25,6 +26,15 @@ namespace clang {
2526
class OpenACCClause;
2627

2728
class SemaOpenACC : public SemaBase {
29+
private:
30+
/// A collection of loop constructs in the compute construct scope that
31+
/// haven't had their 'parent' compute construct set yet. Entires will only be
32+
/// made to this list in the case where we know the loop isn't an orphan.
33+
llvm::SmallVector<OpenACCLoopConstruct *> ParentlessLoopConstructs;
34+
/// Whether we are inside of a compute construct, and should add loops to the
35+
/// above collection.
36+
bool InsideComputeConstruct = false;
37+
2838
public:
2939
// Redeclaration of the version in OpenACCClause.h.
3040
using DeviceTypeArgument = std::pair<IdentifierInfo *, SourceLocation>;
@@ -394,7 +404,8 @@ class SemaOpenACC : public SemaBase {
394404
bool ActOnStartDeclDirective(OpenACCDirectiveKind K, SourceLocation StartLoc);
395405
/// Called when we encounter an associated statement for our construct, this
396406
/// should check legality of the statement as it appertains to this Construct.
397-
StmtResult ActOnAssociatedStmt(OpenACCDirectiveKind K, StmtResult AssocStmt);
407+
StmtResult ActOnAssociatedStmt(SourceLocation DirectiveLoc,
408+
OpenACCDirectiveKind K, StmtResult AssocStmt);
398409

399410
/// Called after the directive has been completely parsed, including the
400411
/// declaration group or associated statement.
@@ -431,6 +442,20 @@ class SemaOpenACC : public SemaBase {
431442
Expr *LowerBound,
432443
SourceLocation ColonLocFirst, Expr *Length,
433444
SourceLocation RBLoc);
445+
446+
/// Helper type for the registration/assignment of constructs that need to
447+
/// 'know' about their parent constructs and hold a reference to them, such as
448+
/// Loop needing its parent construct.
449+
class AssociatedStmtRAII {
450+
SemaOpenACC &SemaRef;
451+
bool WasInsideComputeConstruct;
452+
OpenACCDirectiveKind DirKind;
453+
llvm::SmallVector<OpenACCLoopConstruct *> ParentlessLoopConstructs;
454+
455+
public:
456+
AssociatedStmtRAII(SemaOpenACC &, OpenACCDirectiveKind);
457+
~AssociatedStmtRAII();
458+
};
434459
};
435460

436461
} // namespace clang

clang/include/clang/Serialization/ASTBitCodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1946,6 +1946,7 @@ enum StmtCode {
19461946

19471947
// OpenACC Constructs
19481948
STMT_OPENACC_COMPUTE_CONSTRUCT,
1949+
STMT_OPENACC_LOOP_CONSTRUCT,
19491950
};
19501951

19511952
/// The kinds of designators that can occur in a

clang/lib/AST/StmtOpenACC.cpp

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
#include "clang/AST/StmtOpenACC.h"
1414
#include "clang/AST/ASTContext.h"
15+
#include "clang/AST/RecursiveASTVisitor.h"
16+
#include "clang/AST/StmtCXX.h"
1517
using namespace clang;
1618

1719
OpenACCComputeConstruct *
@@ -26,11 +28,98 @@ OpenACCComputeConstruct::CreateEmpty(const ASTContext &C, unsigned NumClauses) {
2628
OpenACCComputeConstruct *OpenACCComputeConstruct::Create(
2729
const ASTContext &C, OpenACCDirectiveKind K, SourceLocation BeginLoc,
2830
SourceLocation DirLoc, SourceLocation EndLoc,
29-
ArrayRef<const OpenACCClause *> Clauses, Stmt *StructuredBlock) {
31+
ArrayRef<const OpenACCClause *> Clauses, Stmt *StructuredBlock,
32+
ArrayRef<OpenACCLoopConstruct *> AssociatedLoopConstructs) {
3033
void *Mem = C.Allocate(
3134
OpenACCComputeConstruct::totalSizeToAlloc<const OpenACCClause *>(
3235
Clauses.size()));
3336
auto *Inst = new (Mem) OpenACCComputeConstruct(K, BeginLoc, DirLoc, EndLoc,
3437
Clauses, StructuredBlock);
38+
39+
llvm::for_each(AssociatedLoopConstructs, [&](OpenACCLoopConstruct *C) {
40+
C->setParentComputeConstruct(Inst);
41+
});
42+
43+
return Inst;
44+
}
45+
46+
void OpenACCComputeConstruct::findAndSetChildLoops() {
47+
struct LoopConstructFinder : RecursiveASTVisitor<LoopConstructFinder> {
48+
OpenACCComputeConstruct *Construct = nullptr;
49+
50+
LoopConstructFinder(OpenACCComputeConstruct *Construct)
51+
: Construct(Construct) {}
52+
53+
bool TraverseOpenACCComputeConstruct(OpenACCComputeConstruct *C) {
54+
// Stop searching if we find a compute construct.
55+
return true;
56+
}
57+
bool TraverseOpenACCLoopConstruct(OpenACCLoopConstruct *C) {
58+
// Stop searching if we find a loop construct, after taking ownership of
59+
// it.
60+
C->setParentComputeConstruct(Construct);
61+
return true;
62+
}
63+
};
64+
65+
LoopConstructFinder f(this);
66+
f.TraverseStmt(getAssociatedStmt());
67+
}
68+
69+
OpenACCLoopConstruct::OpenACCLoopConstruct(unsigned NumClauses)
70+
: OpenACCAssociatedStmtConstruct(
71+
OpenACCLoopConstructClass, OpenACCDirectiveKind::Loop,
72+
SourceLocation{}, SourceLocation{}, SourceLocation{},
73+
/*AssociatedStmt=*/nullptr) {
74+
std::uninitialized_value_construct(
75+
getTrailingObjects<const OpenACCClause *>(),
76+
getTrailingObjects<const OpenACCClause *>() + NumClauses);
77+
setClauseList(
78+
MutableArrayRef(getTrailingObjects<const OpenACCClause *>(), NumClauses));
79+
}
80+
81+
OpenACCLoopConstruct::OpenACCLoopConstruct(
82+
SourceLocation Start, SourceLocation DirLoc, SourceLocation End,
83+
ArrayRef<const OpenACCClause *> Clauses, Stmt *Loop)
84+
: OpenACCAssociatedStmtConstruct(OpenACCLoopConstructClass,
85+
OpenACCDirectiveKind::Loop, Start, DirLoc,
86+
End, Loop) {
87+
// accept 'nullptr' for the loop. This is diagnosed somewhere, but this gives
88+
// us some level of AST fidelity in the error case.
89+
assert((Loop == nullptr || isa<ForStmt, CXXForRangeStmt>(Loop)) &&
90+
"Associated Loop not a for loop?");
91+
// Initialize the trailing storage.
92+
std::uninitialized_copy(Clauses.begin(), Clauses.end(),
93+
getTrailingObjects<const OpenACCClause *>());
94+
95+
setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
96+
Clauses.size()));
97+
}
98+
99+
void OpenACCLoopConstruct::setLoop(Stmt *Loop) {
100+
assert((isa<ForStmt, CXXForRangeStmt>(Loop)) &&
101+
"Associated Loop not a for loop?");
102+
setAssociatedStmt(Loop);
103+
}
104+
105+
OpenACCLoopConstruct *OpenACCLoopConstruct::CreateEmpty(const ASTContext &C,
106+
unsigned NumClauses) {
107+
void *Mem =
108+
C.Allocate(OpenACCLoopConstruct::totalSizeToAlloc<const OpenACCClause *>(
109+
NumClauses));
110+
auto *Inst = new (Mem) OpenACCLoopConstruct(NumClauses);
111+
return Inst;
112+
}
113+
114+
OpenACCLoopConstruct *
115+
OpenACCLoopConstruct::Create(const ASTContext &C, SourceLocation BeginLoc,
116+
SourceLocation DirLoc, SourceLocation EndLoc,
117+
ArrayRef<const OpenACCClause *> Clauses,
118+
Stmt *Loop) {
119+
void *Mem =
120+
C.Allocate(OpenACCLoopConstruct::totalSizeToAlloc<const OpenACCClause *>(
121+
Clauses.size()));
122+
auto *Inst =
123+
new (Mem) OpenACCLoopConstruct(BeginLoc, DirLoc, EndLoc, Clauses, Loop);
35124
return Inst;
36125
}

clang/lib/AST/StmtPrinter.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,6 +1156,19 @@ void StmtPrinter::VisitOpenACCComputeConstruct(OpenACCComputeConstruct *S) {
11561156
PrintStmt(S->getStructuredBlock());
11571157
}
11581158

1159+
void StmtPrinter::VisitOpenACCLoopConstruct(OpenACCLoopConstruct *S) {
1160+
Indent() << "#pragma acc loop";
1161+
1162+
if (!S->clauses().empty()) {
1163+
OS << ' ';
1164+
OpenACCClausePrinter Printer(OS, Policy);
1165+
Printer.VisitClauseList(S->clauses());
1166+
}
1167+
OS << '\n';
1168+
1169+
PrintStmt(S->getLoop());
1170+
}
1171+
11591172
//===----------------------------------------------------------------------===//
11601173
// Expr printing methods.
11611174
//===----------------------------------------------------------------------===//

clang/lib/AST/StmtProfile.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2605,6 +2605,14 @@ void StmtProfiler::VisitOpenACCComputeConstruct(
26052605
P.VisitOpenACCClauseList(S->clauses());
26062606
}
26072607

2608+
void StmtProfiler::VisitOpenACCLoopConstruct(const OpenACCLoopConstruct *S) {
2609+
// VisitStmt handles children, so the Loop is handled.
2610+
VisitStmt(S);
2611+
2612+
OpenACCClauseProfiler P{*this};
2613+
P.VisitOpenACCClauseList(S->clauses());
2614+
}
2615+
26082616
void Stmt::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
26092617
bool Canonical, bool ProfileLambdaExpr) const {
26102618
StmtProfilerWithPointers Profiler(ID, Context, Canonical, ProfileLambdaExpr);

clang/lib/AST/TextNodeDumper.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2869,3 +2869,10 @@ void TextNodeDumper::VisitHLSLBufferDecl(const HLSLBufferDecl *D) {
28692869
void TextNodeDumper::VisitOpenACCConstructStmt(const OpenACCConstructStmt *S) {
28702870
OS << " " << S->getDirectiveKind();
28712871
}
2872+
void TextNodeDumper::VisitOpenACCLoopConstruct(const OpenACCLoopConstruct *S) {
2873+
2874+
if (S->isOrphanedLoopConstruct())
2875+
OS << " <orphan>";
2876+
else
2877+
OS << " parent: " << S->getParentComputeConstruct();
2878+
}

clang/lib/CodeGen/CGStmt.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
442442
case Stmt::OpenACCComputeConstructClass:
443443
EmitOpenACCComputeConstruct(cast<OpenACCComputeConstruct>(*S));
444444
break;
445+
case Stmt::OpenACCLoopConstructClass:
446+
EmitOpenACCLoopConstruct(cast<OpenACCLoopConstruct>(*S));
447+
break;
445448
}
446449
}
447450

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4062,6 +4062,13 @@ class CodeGenFunction : public CodeGenTypeCache {
40624062
EmitStmt(S.getStructuredBlock());
40634063
}
40644064

4065+
void EmitOpenACCLoopConstruct(const OpenACCLoopConstruct &S) {
4066+
// TODO OpenACC: Implement this. It is currently implemented as a 'no-op',
4067+
// simply emitting its loop, but in the future we will implement
4068+
// some sort of IR.
4069+
EmitStmt(S.getLoop());
4070+
}
4071+
40654072
//===--------------------------------------------------------------------===//
40664073
// LValue Expression Emission
40674074
//===--------------------------------------------------------------------===//

0 commit comments

Comments
 (0)