Skip to content

[OpenACC] Implement loop restrictions on for loops. #115370

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -12735,6 +12735,19 @@ def err_acc_gang_reduction_numgangs_conflict
def err_reduction_op_mismatch
: Error<"OpenACC 'reduction' variable must have the same operator in all "
"nested constructs (%0 vs %1)">;
def err_acc_loop_variable_type
: Error<"loop variable of loop associated with an OpenACC 'loop' construct "
"must be of integer, pointer, or random-access-iterator type (is "
"%0)">;
def err_acc_loop_variable
: Error<"OpenACC 'loop' construct must have initialization clause in "
"canonical form ('var = init' or 'T var = init')">;
def err_acc_loop_terminating_condition
: Error<"OpenACC 'loop' construct must have a terminating condition">;
def err_acc_loop_not_monotonic
: Error<"OpenACC 'loop' variable must monotonically increase or decrease "
"('++', '--', or compound assignment)">;

// AMDGCN builtins diagnostics
def err_amdgcn_global_load_lds_size_invalid_value : Error<"invalid size value">;
def note_amdgcn_global_load_lds_size_valid_value : Note<"size must be 1, 2, or 4">;
Expand Down
62 changes: 59 additions & 3 deletions clang/include/clang/Sema/SemaOpenACC.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,43 @@ class SemaOpenACC : public SemaBase {
/// 'loop' clause enforcement, where this is 'blocked' by a compute construct.
llvm::SmallVector<OpenACCReductionClause *> ActiveReductionClauses;

// Type to check the info about the 'for stmt'.
struct ForStmtBeginChecker {
SemaOpenACC &SemaRef;
SourceLocation ForLoc;
bool IsRangeFor = false;
std::optional<const CXXForRangeStmt *> RangeFor = nullptr;
const Stmt *Init = nullptr;
bool InitChanged = false;
std::optional<const Stmt *> Cond = nullptr;
std::optional<const Stmt *> Inc = nullptr;
// Prevent us from checking 2x, which can happen with collapse & tile.
bool AlreadyChecked = false;

ForStmtBeginChecker(SemaOpenACC &SemaRef, SourceLocation ForLoc,
std::optional<const CXXForRangeStmt *> S)
: SemaRef(SemaRef), ForLoc(ForLoc), IsRangeFor(true), RangeFor(S) {}

ForStmtBeginChecker(SemaOpenACC &SemaRef, SourceLocation ForLoc,
const Stmt *I, bool InitChanged,
std::optional<const Stmt *> C,
std::optional<const Stmt *> Inc)
: SemaRef(SemaRef), ForLoc(ForLoc), IsRangeFor(false), Init(I),
InitChanged(InitChanged), Cond(C), Inc(Inc) {}
// Do the checking for the For/Range-For. Currently this implements the 'not
// seq' restrictions only, and should be called either if we know we are a
// top-level 'for' (the one associated via associated-stmt), or extended via
// 'collapse'.
void check();

const ValueDecl *checkInit();
void checkCond();
void checkInc(const ValueDecl *Init);
};

/// Helper function for checking the 'for' and 'range for' stmts.
void ForStmtBeginHelper(SourceLocation ForLoc, ForStmtBeginChecker &C);

public:
ComputeConstructInfo &getActiveComputeConstructInfo() {
return ActiveComputeConstructInfo;
Expand All @@ -137,6 +174,11 @@ class SemaOpenACC : public SemaBase {
/// permits us to implement the restriction of no further 'gang', 'vector', or
/// 'worker' clauses.
SourceLocation LoopVectorClauseLoc;
/// If there is a current 'active' loop construct that does NOT have a 'seq'
/// clause on it, this has that source location. This permits us to implement
/// the 'loop' restrictions on the loop variable. This can be extended via
/// 'collapse', so we need to keep this around for a while.
SourceLocation LoopWithoutSeqLoc;

// Redeclaration of the version in OpenACCClause.h.
using DeviceTypeArgument = std::pair<IdentifierInfo *, SourceLocation>;
Expand Down Expand Up @@ -568,8 +610,19 @@ class SemaOpenACC : public SemaBase {
void ActOnWhileStmt(SourceLocation WhileLoc);
// Called when we encounter a 'do' statement, before looking at its 'body'.
void ActOnDoStmt(SourceLocation DoLoc);
// Called when we encounter a 'for' statement, before looking at its 'body',
// for the 'range-for'. 'ActOnForStmtEnd' is used after the body.
void ActOnRangeForStmtBegin(SourceLocation ForLoc, const Stmt *OldRangeFor,
const Stmt *RangeFor);
void ActOnRangeForStmtBegin(SourceLocation ForLoc, const Stmt *RangeFor);
// Called when we encounter a 'for' statement, before looking at its 'body'.
void ActOnForStmtBegin(SourceLocation ForLoc);
// 'ActOnForStmtEnd' is used after the body.
void ActOnForStmtBegin(SourceLocation ForLoc, const Stmt *First,
const Stmt *Second, const Stmt *Third);
void ActOnForStmtBegin(SourceLocation ForLoc, const Stmt *OldFirst,
const Stmt *First, const Stmt *OldSecond,
const Stmt *Second, const Stmt *OldThird,
const Stmt *Third);
// Called when we encounter a 'for' statement, after we've consumed/checked
// the body. This is necessary for a number of checks on the contents of the
// 'for' statement.
Expand Down Expand Up @@ -598,7 +651,9 @@ class SemaOpenACC : public SemaBase {
/// Called when we encounter an associated statement for our construct, this
/// should check legality of the statement as it appertains to this Construct.
StmtResult ActOnAssociatedStmt(SourceLocation DirectiveLoc,
OpenACCDirectiveKind K, StmtResult AssocStmt);
OpenACCDirectiveKind K,
ArrayRef<const OpenACCClause *> Clauses,
StmtResult AssocStmt);

/// Called after the directive has been completely parsed, including the
/// declaration group or associated statement.
Expand Down Expand Up @@ -712,12 +767,13 @@ class SemaOpenACC : public SemaBase {
SourceLocation OldLoopGangClauseOnKernelLoc;
SourceLocation OldLoopWorkerClauseLoc;
SourceLocation OldLoopVectorClauseLoc;
SourceLocation OldLoopWithoutSeqLoc;
llvm::SmallVector<OpenACCLoopConstruct *> ParentlessLoopConstructs;
llvm::SmallVector<OpenACCReductionClause *> ActiveReductionClauses;
LoopInConstructRAII LoopRAII;

public:
AssociatedStmtRAII(SemaOpenACC &, OpenACCDirectiveKind,
AssociatedStmtRAII(SemaOpenACC &, OpenACCDirectiveKind, SourceLocation,
ArrayRef<const OpenACCClause *>,
ArrayRef<OpenACCClause *>);
void SetCollapseInfoBeforeAssociatedStmt(
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/Parse/ParseOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1498,14 +1498,15 @@ StmtResult Parser::ParseOpenACCDirectiveStmt() {
return StmtError();

StmtResult AssocStmt;
SemaOpenACC::AssociatedStmtRAII AssocStmtRAII(
getActions().OpenACC(), DirInfo.DirKind, {}, DirInfo.Clauses);
SemaOpenACC::AssociatedStmtRAII AssocStmtRAII(getActions().OpenACC(),
DirInfo.DirKind, DirInfo.DirLoc,
{}, DirInfo.Clauses);
if (doesDirectiveHaveAssociatedStmt(DirInfo.DirKind)) {
ParsingOpenACCDirectiveRAII DirScope(*this, /*Value=*/false);
ParseScope ACCScope(this, getOpenACCScopeFlags(DirInfo.DirKind));

AssocStmt = getActions().OpenACC().ActOnAssociatedStmt(
DirInfo.StartLoc, DirInfo.DirKind, ParseStatement());
DirInfo.StartLoc, DirInfo.DirKind, DirInfo.Clauses, ParseStatement());
}

return getActions().OpenACC().ActOnEndStmtDirective(
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Parse/ParseStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2360,7 +2360,11 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
// OpenACC Restricts a for-loop inside of certain construct/clause
// combinations, so diagnose that here in OpenACC mode.
SemaOpenACC::LoopInConstructRAII LCR{getActions().OpenACC()};
getActions().OpenACC().ActOnForStmtBegin(ForLoc);
if (ForRangeInfo.ParsedForRangeDecl())
getActions().OpenACC().ActOnRangeForStmtBegin(ForLoc, ForRangeStmt.get());
else
getActions().OpenACC().ActOnForStmtBegin(
ForLoc, FirstPart.get(), SecondPart.get().second, ThirdPart.get());

// C99 6.8.5p5 - In C99, the body of the for statement is a scope, even if
// there is no compound stmt. C90 does not have this clause. We only do this
Expand Down
Loading
Loading