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

0 commit comments

Comments
 (0)