Skip to content

Commit b0cfbfd

Browse files
authoredNov 8, 2024··
[OpenACC] Implement loop restrictions on for loops. (#115370)
OpenACC restricts the contents of a 'for' loop affected by a 'loop' construct without a 'seq'. The loop variable must be integer, pointer, or random-access-iterator, it must monotonically increase/decrease, and the trip count must be computable at runtime before the function. This patch tries to implement some of these limitations to the best of our ability, though it causes us to be perhaps overly restrictive at the moment. I expect we'll revisit some of these rules/add additional supported forms of loop-variable and 'monotonically increasing' here, but the currently enforced rules are heavily inspired by the OMP implementation here.
1 parent 32c744a commit b0cfbfd

File tree

50 files changed

+3553
-1821
lines changed

Some content is hidden

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

50 files changed

+3553
-1821
lines changed
 

‎clang/include/clang/Basic/DiagnosticSemaKinds.td

+13
Original file line numberDiff line numberDiff line change
@@ -12747,6 +12747,19 @@ def err_acc_gang_reduction_numgangs_conflict
1274712747
def err_reduction_op_mismatch
1274812748
: Error<"OpenACC 'reduction' variable must have the same operator in all "
1274912749
"nested constructs (%0 vs %1)">;
12750+
def err_acc_loop_variable_type
12751+
: Error<"loop variable of loop associated with an OpenACC 'loop' construct "
12752+
"must be of integer, pointer, or random-access-iterator type (is "
12753+
"%0)">;
12754+
def err_acc_loop_variable
12755+
: Error<"OpenACC 'loop' construct must have initialization clause in "
12756+
"canonical form ('var = init' or 'T var = init')">;
12757+
def err_acc_loop_terminating_condition
12758+
: Error<"OpenACC 'loop' construct must have a terminating condition">;
12759+
def err_acc_loop_not_monotonic
12760+
: Error<"OpenACC 'loop' variable must monotonically increase or decrease "
12761+
"('++', '--', or compound assignment)">;
12762+
1275012763
// AMDGCN builtins diagnostics
1275112764
def err_amdgcn_global_load_lds_size_invalid_value : Error<"invalid size value">;
1275212765
def note_amdgcn_global_load_lds_size_valid_value : Note<"size must be 1, 2, or 4">;

‎clang/include/clang/Sema/SemaOpenACC.h

+59-3
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,43 @@ class SemaOpenACC : public SemaBase {
118118
/// 'loop' clause enforcement, where this is 'blocked' by a compute construct.
119119
llvm::SmallVector<OpenACCReductionClause *> ActiveReductionClauses;
120120

121+
// Type to check the info about the 'for stmt'.
122+
struct ForStmtBeginChecker {
123+
SemaOpenACC &SemaRef;
124+
SourceLocation ForLoc;
125+
bool IsRangeFor = false;
126+
std::optional<const CXXForRangeStmt *> RangeFor = nullptr;
127+
const Stmt *Init = nullptr;
128+
bool InitChanged = false;
129+
std::optional<const Stmt *> Cond = nullptr;
130+
std::optional<const Stmt *> Inc = nullptr;
131+
// Prevent us from checking 2x, which can happen with collapse & tile.
132+
bool AlreadyChecked = false;
133+
134+
ForStmtBeginChecker(SemaOpenACC &SemaRef, SourceLocation ForLoc,
135+
std::optional<const CXXForRangeStmt *> S)
136+
: SemaRef(SemaRef), ForLoc(ForLoc), IsRangeFor(true), RangeFor(S) {}
137+
138+
ForStmtBeginChecker(SemaOpenACC &SemaRef, SourceLocation ForLoc,
139+
const Stmt *I, bool InitChanged,
140+
std::optional<const Stmt *> C,
141+
std::optional<const Stmt *> Inc)
142+
: SemaRef(SemaRef), ForLoc(ForLoc), IsRangeFor(false), Init(I),
143+
InitChanged(InitChanged), Cond(C), Inc(Inc) {}
144+
// Do the checking for the For/Range-For. Currently this implements the 'not
145+
// seq' restrictions only, and should be called either if we know we are a
146+
// top-level 'for' (the one associated via associated-stmt), or extended via
147+
// 'collapse'.
148+
void check();
149+
150+
const ValueDecl *checkInit();
151+
void checkCond();
152+
void checkInc(const ValueDecl *Init);
153+
};
154+
155+
/// Helper function for checking the 'for' and 'range for' stmts.
156+
void ForStmtBeginHelper(SourceLocation ForLoc, ForStmtBeginChecker &C);
157+
121158
public:
122159
ComputeConstructInfo &getActiveComputeConstructInfo() {
123160
return ActiveComputeConstructInfo;
@@ -137,6 +174,11 @@ class SemaOpenACC : public SemaBase {
137174
/// permits us to implement the restriction of no further 'gang', 'vector', or
138175
/// 'worker' clauses.
139176
SourceLocation LoopVectorClauseLoc;
177+
/// If there is a current 'active' loop construct that does NOT have a 'seq'
178+
/// clause on it, this has that source location. This permits us to implement
179+
/// the 'loop' restrictions on the loop variable. This can be extended via
180+
/// 'collapse', so we need to keep this around for a while.
181+
SourceLocation LoopWithoutSeqLoc;
140182

141183
// Redeclaration of the version in OpenACCClause.h.
142184
using DeviceTypeArgument = std::pair<IdentifierInfo *, SourceLocation>;
@@ -568,8 +610,19 @@ class SemaOpenACC : public SemaBase {
568610
void ActOnWhileStmt(SourceLocation WhileLoc);
569611
// Called when we encounter a 'do' statement, before looking at its 'body'.
570612
void ActOnDoStmt(SourceLocation DoLoc);
613+
// Called when we encounter a 'for' statement, before looking at its 'body',
614+
// for the 'range-for'. 'ActOnForStmtEnd' is used after the body.
615+
void ActOnRangeForStmtBegin(SourceLocation ForLoc, const Stmt *OldRangeFor,
616+
const Stmt *RangeFor);
617+
void ActOnRangeForStmtBegin(SourceLocation ForLoc, const Stmt *RangeFor);
571618
// Called when we encounter a 'for' statement, before looking at its 'body'.
572-
void ActOnForStmtBegin(SourceLocation ForLoc);
619+
// 'ActOnForStmtEnd' is used after the body.
620+
void ActOnForStmtBegin(SourceLocation ForLoc, const Stmt *First,
621+
const Stmt *Second, const Stmt *Third);
622+
void ActOnForStmtBegin(SourceLocation ForLoc, const Stmt *OldFirst,
623+
const Stmt *First, const Stmt *OldSecond,
624+
const Stmt *Second, const Stmt *OldThird,
625+
const Stmt *Third);
573626
// Called when we encounter a 'for' statement, after we've consumed/checked
574627
// the body. This is necessary for a number of checks on the contents of the
575628
// 'for' statement.
@@ -598,7 +651,9 @@ class SemaOpenACC : public SemaBase {
598651
/// Called when we encounter an associated statement for our construct, this
599652
/// should check legality of the statement as it appertains to this Construct.
600653
StmtResult ActOnAssociatedStmt(SourceLocation DirectiveLoc,
601-
OpenACCDirectiveKind K, StmtResult AssocStmt);
654+
OpenACCDirectiveKind K,
655+
ArrayRef<const OpenACCClause *> Clauses,
656+
StmtResult AssocStmt);
602657

603658
/// Called after the directive has been completely parsed, including the
604659
/// declaration group or associated statement.
@@ -712,12 +767,13 @@ class SemaOpenACC : public SemaBase {
712767
SourceLocation OldLoopGangClauseOnKernelLoc;
713768
SourceLocation OldLoopWorkerClauseLoc;
714769
SourceLocation OldLoopVectorClauseLoc;
770+
SourceLocation OldLoopWithoutSeqLoc;
715771
llvm::SmallVector<OpenACCLoopConstruct *> ParentlessLoopConstructs;
716772
llvm::SmallVector<OpenACCReductionClause *> ActiveReductionClauses;
717773
LoopInConstructRAII LoopRAII;
718774

719775
public:
720-
AssociatedStmtRAII(SemaOpenACC &, OpenACCDirectiveKind,
776+
AssociatedStmtRAII(SemaOpenACC &, OpenACCDirectiveKind, SourceLocation,
721777
ArrayRef<const OpenACCClause *>,
722778
ArrayRef<OpenACCClause *>);
723779
void SetCollapseInfoBeforeAssociatedStmt(

0 commit comments

Comments
 (0)
Please sign in to comment.