Skip to content

Commit d27a76c

Browse files
authored
Merge branch 'main' into spacey-sooty-patch-1
2 parents 0204803 + da4b972 commit d27a76c

File tree

11 files changed

+462
-25
lines changed

11 files changed

+462
-25
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12617,6 +12617,11 @@ def err_acc_loop_spec_conflict
1261712617
def err_acc_collapse_loop_count
1261812618
: Error<"OpenACC 'collapse' clause loop count must be a %select{constant "
1261912619
"expression|positive integer value, evaluated to %1}0">;
12620+
def err_acc_invalid_in_collapse_loop
12621+
: Error<"%select{OpenACC '%1' construct|while loop|do loop}0 cannot appear "
12622+
"in intervening code of a 'loop' with a 'collapse' clause">;
12623+
def note_acc_collapse_clause_here
12624+
: Note<"active 'collapse' clause defined here">;
1262012625

1262112626
// AMDGCN builtins diagnostics
1262212627
def err_amdgcn_global_load_lds_size_invalid_value : Error<"invalid size value">;

clang/include/clang/Sema/SemaOpenACC.h

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "clang/Sema/Ownership.h"
2323
#include "clang/Sema/SemaBase.h"
2424
#include "llvm/ADT/SmallVector.h"
25+
#include "llvm/Support/Compiler.h"
2526
#include <cassert>
2627
#include <optional>
2728
#include <utility>
@@ -41,6 +42,30 @@ class SemaOpenACC : public SemaBase {
4142
/// above collection.
4243
bool InsideComputeConstruct = false;
4344

45+
/// The 'collapse' clause requires quite a bit of checking while
46+
/// parsing/instantiating its body, so this structure/object keeps all of the
47+
/// necessary information as we do checking. This should rarely be directly
48+
/// modified, and typically should be controlled by the RAII objects.
49+
///
50+
/// Collapse has an 'N' count that makes it apply to a number of loops 'below'
51+
/// it.
52+
struct CollapseCheckingInfo {
53+
OpenACCCollapseClause *ActiveCollapse = nullptr;
54+
55+
/// This is a value that maintains the current value of the 'N' on the
56+
/// current collapse, minus the depth that has already been traversed. When
57+
/// there is not an active collapse, or a collapse whose depth we don't know
58+
/// (for example, if it is a dependent value), this should be `nullopt`,
59+
/// else it should be 'N' minus the current depth traversed.
60+
std::optional<llvm::APSInt> CurCollapseCount;
61+
62+
/// Records whether we've seen the top level 'for'. We already diagnose
63+
/// later that the 'top level' is a for loop, so we use this to suppress the
64+
/// 'collapse inner loop not a 'for' loop' diagnostic.
65+
LLVM_PREFERRED_TYPE(bool)
66+
unsigned TopLevelLoopSeen : 1;
67+
} CollapseInfo{nullptr, std::nullopt, false};
68+
4469
public:
4570
// Redeclaration of the version in OpenACCClause.h.
4671
using DeviceTypeArgument = std::pair<IdentifierInfo *, SourceLocation>;
@@ -411,6 +436,17 @@ class SemaOpenACC : public SemaBase {
411436

412437
SemaOpenACC(Sema &S);
413438

439+
// Called when we encounter a 'while' statement, before looking at its 'body'.
440+
void ActOnWhileStmt(SourceLocation WhileLoc);
441+
// Called when we encounter a 'do' statement, before looking at its 'body'.
442+
void ActOnDoStmt(SourceLocation DoLoc);
443+
// Called when we encounter a 'for' statement, before looking at its 'body'.
444+
void ActOnForStmtBegin(SourceLocation ForLoc);
445+
// Called when we encounter a 'for' statement, after we've consumed/checked
446+
// the body. This is necessary for a number of checks on the contents of the
447+
// 'for' statement.
448+
void ActOnForStmtEnd(SourceLocation ForLoc, StmtResult Body);
449+
414450
/// Called after parsing an OpenACC Clause so that it can be checked.
415451
OpenACCClause *ActOnClause(ArrayRef<const OpenACCClause *> ExistingClauses,
416452
OpenACCParsedClause &Clause);
@@ -474,6 +510,18 @@ class SemaOpenACC : public SemaBase {
474510
/// Checks the loop depth value for a collapse clause.
475511
ExprResult CheckCollapseLoopCount(Expr *LoopCount);
476512

513+
/// Helper type to restore the state of various 'loop' constructs when we run
514+
/// into a loop (for, etc) inside the construct.
515+
class LoopInConstructRAII {
516+
SemaOpenACC &SemaRef;
517+
CollapseCheckingInfo OldCollapseInfo;
518+
519+
public:
520+
LoopInConstructRAII(SemaOpenACC &SemaRef)
521+
: SemaRef(SemaRef), OldCollapseInfo(SemaRef.CollapseInfo) {}
522+
~LoopInConstructRAII() { SemaRef.CollapseInfo = OldCollapseInfo; }
523+
};
524+
477525
/// Helper type for the registration/assignment of constructs that need to
478526
/// 'know' about their parent constructs and hold a reference to them, such as
479527
/// Loop needing its parent construct.
@@ -482,9 +530,15 @@ class SemaOpenACC : public SemaBase {
482530
bool WasInsideComputeConstruct;
483531
OpenACCDirectiveKind DirKind;
484532
llvm::SmallVector<OpenACCLoopConstruct *> ParentlessLoopConstructs;
533+
LoopInConstructRAII LoopRAII;
485534

486535
public:
487-
AssociatedStmtRAII(SemaOpenACC &, OpenACCDirectiveKind);
536+
AssociatedStmtRAII(SemaOpenACC &, OpenACCDirectiveKind,
537+
ArrayRef<const OpenACCClause *>,
538+
ArrayRef<OpenACCClause *>);
539+
void SetCollapseInfoBeforeAssociatedStmt(
540+
ArrayRef<const OpenACCClause *> UnInstClauses,
541+
ArrayRef<OpenACCClause *> Clauses);
488542
~AssociatedStmtRAII();
489543
};
490544
};

clang/lib/Parse/ParseOpenACC.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1461,8 +1461,8 @@ StmtResult Parser::ParseOpenACCDirectiveStmt() {
14611461
return StmtError();
14621462

14631463
StmtResult AssocStmt;
1464-
SemaOpenACC::AssociatedStmtRAII AssocStmtRAII(getActions().OpenACC(),
1465-
DirInfo.DirKind);
1464+
SemaOpenACC::AssociatedStmtRAII AssocStmtRAII(
1465+
getActions().OpenACC(), DirInfo.DirKind, {}, DirInfo.Clauses);
14661466
if (doesDirectiveHaveAssociatedStmt(DirInfo.DirKind)) {
14671467
ParsingOpenACCDirectiveRAII DirScope(*this, /*Value=*/false);
14681468
ParseScope ACCScope(this, getOpenACCScopeFlags(DirInfo.DirKind));

clang/lib/Parse/ParseStmt.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "clang/Sema/Scope.h"
2525
#include "clang/Sema/SemaCodeCompletion.h"
2626
#include "clang/Sema/SemaObjC.h"
27+
#include "clang/Sema/SemaOpenACC.h"
2728
#include "clang/Sema/SemaOpenMP.h"
2829
#include "clang/Sema/TypoCorrection.h"
2930
#include "llvm/ADT/STLExtras.h"
@@ -1854,6 +1855,11 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) {
18541855
Sema::ConditionKind::Boolean, LParen, RParen))
18551856
return StmtError();
18561857

1858+
// OpenACC Restricts a while-loop inside of certain construct/clause
1859+
// combinations, so diagnose that here in OpenACC mode.
1860+
SemaOpenACC::LoopInConstructRAII LCR{getActions().OpenACC()};
1861+
getActions().OpenACC().ActOnWhileStmt(WhileLoc);
1862+
18571863
// C99 6.8.5p5 - In C99, the body of the while statement is a scope, even if
18581864
// there is no compound stmt. C90 does not have this clause. We only do this
18591865
// if the body isn't a compound statement to avoid push/pop in common cases.
@@ -1902,6 +1908,11 @@ StmtResult Parser::ParseDoStatement() {
19021908

19031909
ParseScope DoScope(this, ScopeFlags);
19041910

1911+
// OpenACC Restricts a do-while-loop inside of certain construct/clause
1912+
// combinations, so diagnose that here in OpenACC mode.
1913+
SemaOpenACC::LoopInConstructRAII LCR{getActions().OpenACC()};
1914+
getActions().OpenACC().ActOnDoStmt(DoLoc);
1915+
19051916
// C99 6.8.5p5 - In C99, the body of the do statement is a scope, even if
19061917
// there is no compound stmt. C90 does not have this clause. We only do this
19071918
// if the body isn't a compound statement to avoid push/pop in common cases.
@@ -2326,6 +2337,11 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
23262337
}
23272338
}
23282339

2340+
// OpenACC Restricts a for-loop inside of certain construct/clause
2341+
// combinations, so diagnose that here in OpenACC mode.
2342+
SemaOpenACC::LoopInConstructRAII LCR{getActions().OpenACC()};
2343+
getActions().OpenACC().ActOnForStmtBegin(ForLoc);
2344+
23292345
// C99 6.8.5p5 - In C99, the body of the for statement is a scope, even if
23302346
// there is no compound stmt. C90 does not have this clause. We only do this
23312347
// if the body isn't a compound statement to avoid push/pop in common cases.
@@ -2358,6 +2374,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
23582374
// Pop the body scope if needed.
23592375
InnerScope.Exit();
23602376

2377+
getActions().OpenACC().ActOnForStmtEnd(ForLoc, Body);
2378+
23612379
// Leave the for-scope.
23622380
ForScope.Exit();
23632381

clang/lib/Sema/SemaOpenACC.cpp

Lines changed: 117 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,19 +1073,62 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitCollapseClause(
10731073

10741074
SemaOpenACC::SemaOpenACC(Sema &S) : SemaBase(S) {}
10751075

1076-
SemaOpenACC::AssociatedStmtRAII::AssociatedStmtRAII(SemaOpenACC &S,
1077-
OpenACCDirectiveKind DK)
1076+
SemaOpenACC::AssociatedStmtRAII::AssociatedStmtRAII(
1077+
SemaOpenACC &S, OpenACCDirectiveKind DK,
1078+
ArrayRef<const OpenACCClause *> UnInstClauses,
1079+
ArrayRef<OpenACCClause *> Clauses)
10781080
: SemaRef(S), WasInsideComputeConstruct(S.InsideComputeConstruct),
1079-
DirKind(DK) {
1081+
DirKind(DK), LoopRAII(SemaRef) {
10801082
// Compute constructs end up taking their 'loop'.
10811083
if (DirKind == OpenACCDirectiveKind::Parallel ||
10821084
DirKind == OpenACCDirectiveKind::Serial ||
10831085
DirKind == OpenACCDirectiveKind::Kernels) {
10841086
SemaRef.InsideComputeConstruct = true;
10851087
SemaRef.ParentlessLoopConstructs.swap(ParentlessLoopConstructs);
1088+
} else if (DirKind == OpenACCDirectiveKind::Loop) {
1089+
SetCollapseInfoBeforeAssociatedStmt(UnInstClauses, Clauses);
10861090
}
10871091
}
10881092

1093+
void SemaOpenACC::AssociatedStmtRAII::SetCollapseInfoBeforeAssociatedStmt(
1094+
ArrayRef<const OpenACCClause *> UnInstClauses,
1095+
ArrayRef<OpenACCClause *> Clauses) {
1096+
// We make sure to take an optional list of uninstantiated clauses, so that
1097+
// we can check to make sure we don't 'double diagnose' in the event that
1098+
// the value of 'N' was not dependent in a template. We also ensure during
1099+
// Sema that there is only 1 collapse on each construct, so we can count on
1100+
// the fact that if both find a 'collapse', that they are the same one.
1101+
auto *CollapseClauseItr =
1102+
llvm::find_if(Clauses, llvm::IsaPred<OpenACCCollapseClause>);
1103+
auto *UnInstCollapseClauseItr =
1104+
llvm::find_if(UnInstClauses, llvm::IsaPred<OpenACCCollapseClause>);
1105+
1106+
if (Clauses.end() == CollapseClauseItr)
1107+
return;
1108+
1109+
OpenACCCollapseClause *CollapseClause =
1110+
cast<OpenACCCollapseClause>(*CollapseClauseItr);
1111+
1112+
SemaRef.CollapseInfo.ActiveCollapse = CollapseClause;
1113+
Expr *LoopCount = CollapseClause->getLoopCount();
1114+
1115+
// If the loop count is still instantiation dependent, setting the depth
1116+
// counter isn't necessary, so return here.
1117+
if (!LoopCount || LoopCount->isInstantiationDependent())
1118+
return;
1119+
1120+
// Suppress diagnostics if we've done a 'transform' where the previous version
1121+
// wasn't dependent, meaning we already diagnosed it.
1122+
if (UnInstCollapseClauseItr != UnInstClauses.end() &&
1123+
!cast<OpenACCCollapseClause>(*UnInstCollapseClauseItr)
1124+
->getLoopCount()
1125+
->isInstantiationDependent())
1126+
return;
1127+
1128+
SemaRef.CollapseInfo.CurCollapseCount =
1129+
cast<ConstantExpr>(LoopCount)->getResultAsAPSInt();
1130+
}
1131+
10891132
SemaOpenACC::AssociatedStmtRAII::~AssociatedStmtRAII() {
10901133
SemaRef.InsideComputeConstruct = WasInsideComputeConstruct;
10911134
if (DirKind == OpenACCDirectiveKind::Parallel ||
@@ -1094,6 +1137,9 @@ SemaOpenACC::AssociatedStmtRAII::~AssociatedStmtRAII() {
10941137
assert(SemaRef.ParentlessLoopConstructs.empty() &&
10951138
"Didn't consume loop construct list?");
10961139
SemaRef.ParentlessLoopConstructs.swap(ParentlessLoopConstructs);
1140+
} else if (DirKind == OpenACCDirectiveKind::Loop) {
1141+
// Nothing really to do here, the LoopInConstruct should handle restorations
1142+
// correctly.
10971143
}
10981144
}
10991145

@@ -1646,10 +1692,78 @@ ExprResult SemaOpenACC::CheckCollapseLoopCount(Expr *LoopCount) {
16461692
ConstantExpr::Create(getASTContext(), LoopCount, APValue{*ICE})};
16471693
}
16481694

1695+
void SemaOpenACC::ActOnWhileStmt(SourceLocation WhileLoc) {
1696+
if (!getLangOpts().OpenACC)
1697+
return;
1698+
1699+
if (!CollapseInfo.TopLevelLoopSeen)
1700+
return;
1701+
1702+
if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0) {
1703+
Diag(WhileLoc, diag::err_acc_invalid_in_collapse_loop) << /*while loop*/ 1;
1704+
assert(CollapseInfo.ActiveCollapse && "Collapse count without object?");
1705+
Diag(CollapseInfo.ActiveCollapse->getBeginLoc(),
1706+
diag::note_acc_collapse_clause_here);
1707+
1708+
// Remove the value so that we don't get cascading errors in the body. The
1709+
// caller RAII object will restore this.
1710+
CollapseInfo.CurCollapseCount = std::nullopt;
1711+
}
1712+
}
1713+
1714+
void SemaOpenACC::ActOnDoStmt(SourceLocation DoLoc) {
1715+
if (!getLangOpts().OpenACC)
1716+
return;
1717+
1718+
if (!CollapseInfo.TopLevelLoopSeen)
1719+
return;
1720+
1721+
if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0) {
1722+
Diag(DoLoc, diag::err_acc_invalid_in_collapse_loop) << /*do loop*/ 2;
1723+
assert(CollapseInfo.ActiveCollapse && "Collapse count without object?");
1724+
Diag(CollapseInfo.ActiveCollapse->getBeginLoc(),
1725+
diag::note_acc_collapse_clause_here);
1726+
1727+
// Remove the value so that we don't get cascading errors in the body. The
1728+
// caller RAII object will restore this.
1729+
CollapseInfo.CurCollapseCount = std::nullopt;
1730+
}
1731+
}
1732+
1733+
void SemaOpenACC::ActOnForStmtBegin(SourceLocation ForLoc) {
1734+
if (!getLangOpts().OpenACC)
1735+
return;
1736+
1737+
// Enable the while/do-while checking.
1738+
CollapseInfo.TopLevelLoopSeen = true;
1739+
1740+
if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0)
1741+
--(*CollapseInfo.CurCollapseCount);
1742+
}
1743+
1744+
void SemaOpenACC::ActOnForStmtEnd(SourceLocation ForLoc, StmtResult Body) {
1745+
if (!getLangOpts().OpenACC)
1746+
return;
1747+
}
1748+
16491749
bool SemaOpenACC::ActOnStartStmtDirective(OpenACCDirectiveKind K,
16501750
SourceLocation StartLoc) {
16511751
SemaRef.DiscardCleanupsInEvaluationContext();
16521752
SemaRef.PopExpressionEvaluationContext();
1753+
1754+
// OpenACC 3.3 2.9.1:
1755+
// Intervening code must not contain other OpenACC directives or calls to API
1756+
// routines.
1757+
//
1758+
// ALL constructs are ill-formed if there is an active 'collapse'
1759+
if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0) {
1760+
Diag(StartLoc, diag::err_acc_invalid_in_collapse_loop)
1761+
<< /*OpenACC Construct*/ 0 << K;
1762+
assert(CollapseInfo.ActiveCollapse && "Collapse count without object?");
1763+
Diag(CollapseInfo.ActiveCollapse->getBeginLoc(),
1764+
diag::note_acc_collapse_clause_here);
1765+
}
1766+
16531767
return diagnoseConstructAppertainment(*this, K, StartLoc, /*IsStmt=*/true);
16541768
}
16551769

0 commit comments

Comments
 (0)