Skip to content

Commit b241c6f

Browse files
committed
initial commit
1 parent 14b2d2c commit b241c6f

File tree

3 files changed

+91
-23
lines changed

3 files changed

+91
-23
lines changed

flang/lib/Semantics/check-acc-structure.cpp

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -89,30 +89,31 @@ bool AccStructureChecker::CheckAllowedModifier(llvm::acc::Clause clause) {
8989
return false;
9090
}
9191

92-
bool AccStructureChecker::IsComputeConstruct(
93-
llvm::acc::Directive directive) const {
94-
return directive == llvm::acc::ACCD_parallel ||
95-
directive == llvm::acc::ACCD_parallel_loop ||
96-
directive == llvm::acc::ACCD_serial ||
97-
directive == llvm::acc::ACCD_serial_loop ||
98-
directive == llvm::acc::ACCD_kernels ||
99-
directive == llvm::acc::ACCD_kernels_loop;
100-
}
101-
102-
bool AccStructureChecker::IsInsideComputeConstruct() const {
103-
if (dirContext_.size() <= 1) {
92+
bool AccStructureChecker::IsInsideDirectiveContext(
93+
std::function<bool(llvm::acc::Directive)> pred, bool skipFirst) const {
94+
std::size_t contextSize{dirContext_.size()};
95+
std::size_t skipFirstOffset{skipFirst ? 1u : 0u};
96+
// Short circuit if there are no contexts to check.
97+
if (contextSize <= skipFirstOffset) {
10498
return false;
10599
}
106-
107-
// Check all nested context skipping the first one.
108-
for (std::size_t i = dirContext_.size() - 1; i > 0; --i) {
109-
if (IsComputeConstruct(dirContext_[i - 1].directive)) {
100+
// Check contexts from innermost to outermost.
101+
for (std::size_t i{contextSize - skipFirstOffset}; i > 0u; --i) {
102+
if (pred(dirContext_[i - 1].directive)) {
110103
return true;
111104
}
112105
}
113106
return false;
114107
}
115108

109+
bool AccStructureChecker::IsInsideComputeConstruct() const {
110+
return IsInsideDirectiveContext(IsComputeConstruct, /*skipFirst=*/true);
111+
}
112+
113+
bool AccStructureChecker::IsInsideLoopConstruct() const {
114+
return IsInsideDirectiveContext(IsLoopConstruct);
115+
}
116+
116117
void AccStructureChecker::CheckNotInComputeConstruct() {
117118
if (IsInsideComputeConstruct()) {
118119
context_.Say(GetContext().directiveSource,
@@ -363,10 +364,28 @@ void AccStructureChecker::Enter(const parser::OpenACCCacheConstruct &x) {
363364
const auto &verbatim = std::get<parser::Verbatim>(x.t);
364365
PushContextAndClauseSets(verbatim.source, llvm::acc::Directive::ACCD_cache);
365366
SetContextDirectiveSource(verbatim.source);
366-
if (loopNestLevel == 0) {
367+
if (loopNests.size() == 0) {
367368
context_.Say(verbatim.source,
368369
"The CACHE directive must be inside a loop"_err_en_US);
369370
}
371+
372+
for (std::size_t i{0}; i < loopNests.size(); i++) {
373+
if (const parser::DoConstruct *doConstruct{loopNests[i]}) {
374+
if (!doConstruct->GetLoopControl()) {
375+
context_
376+
.Say(std::get<parser::Statement<parser::NonLabelDoStmt>>(
377+
doConstruct->t)
378+
.source,
379+
"DO loop with CACHE directive must have loop control"_err_en_US)
380+
.Attach(verbatim.source,
381+
"This CACHE directive implies a LOOP directive"_because_en_US);
382+
}
383+
// Remove the do construct from the loopNests vector after checking so
384+
// that if there are multiple cache directives the loop isn't checked
385+
// again.
386+
loopNests[i] = nullptr;
387+
}
388+
}
370389
}
371390
void AccStructureChecker::Leave(const parser::OpenACCCacheConstruct &x) {
372391
dirContext_.pop_back();
@@ -814,12 +833,19 @@ void AccStructureChecker::Enter(const parser::SeparateModuleSubprogram &) {
814833
declareSymbols.clear();
815834
}
816835

817-
void AccStructureChecker::Enter(const parser::DoConstruct &) {
818-
++loopNestLevel;
836+
void AccStructureChecker::Enter(const parser::DoConstruct &x) {
837+
// If the current context is alread is an loop construct it has already been
838+
// checked. Otherwise if there is a cache directive in the loop we will check
839+
// to make sure it has a loop control clause.
840+
if (IsInsideLoopConstruct()) {
841+
loopNests.push_back(nullptr);
842+
} else {
843+
loopNests.push_back(&x);
844+
}
819845
}
820846

821-
void AccStructureChecker::Leave(const parser::DoConstruct &) {
822-
--loopNestLevel;
847+
void AccStructureChecker::Leave(const parser::DoConstruct &x) {
848+
loopNests.pop_back();
823849
}
824850

825851
llvm::StringRef AccStructureChecker::getDirectiveName(

flang/lib/Semantics/check-acc-structure.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,18 +81,31 @@ class AccStructureChecker
8181

8282
private:
8383
bool CheckAllowedModifier(llvm::acc::Clause clause);
84-
bool IsComputeConstruct(llvm::acc::Directive directive) const;
8584
bool IsInsideComputeConstruct() const;
85+
bool IsInsideLoopConstruct() const;
86+
bool IsInsideDirectiveContext(std::function<bool(llvm::acc::Directive)> pred,
87+
bool skipFirst = false) const;
8688
void CheckNotInComputeConstruct();
8789
void CheckMultipleOccurrenceInDeclare(
8890
const parser::AccObjectList &, llvm::acc::Clause);
8991
void CheckMultipleOccurrenceInDeclare(
9092
const parser::AccObjectListWithModifier &, llvm::acc::Clause);
93+
static bool IsComputeConstruct(llvm::acc::Directive directive) {
94+
return directive == llvm::acc::ACCD_parallel ||
95+
directive == llvm::acc::ACCD_parallel_loop ||
96+
directive == llvm::acc::ACCD_serial ||
97+
directive == llvm::acc::ACCD_serial_loop ||
98+
directive == llvm::acc::ACCD_kernels ||
99+
directive == llvm::acc::ACCD_kernels_loop;
100+
}
101+
static bool IsLoopConstruct(llvm::acc::Directive directive) {
102+
return directive == llvm::acc::ACCD_loop;
103+
}
91104
llvm::StringRef getClauseName(llvm::acc::Clause clause) override;
92105
llvm::StringRef getDirectiveName(llvm::acc::Directive directive) override;
93106

94107
llvm::SmallDenseMap<Symbol *, llvm::acc::Clause> declareSymbols;
95-
unsigned loopNestLevel = 0;
108+
std::vector<const parser::DoConstruct *> loopNests;
96109
};
97110

98111
} // namespace Fortran::semantics

flang/test/Semantics/OpenACC/acc-cache-validity.f90

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,33 @@ program openacc_cache_validity
4343
!ERROR: The CACHE directive must be inside a loop
4444
!$acc cache(a)
4545

46+
47+
!ERROR: DO loop with CACHE directive must have loop control
48+
do
49+
!BECAUSE: This CACHE directive implies a LOOP directive
50+
!$acc cache(a)
51+
end do
52+
53+
!ERROR: DO loop with CACHE directive must have loop control
54+
do
55+
do i = 1, N
56+
!BECAUSE: This CACHE directive implies a LOOP directive
57+
!$acc cache(a(i))
58+
end do
59+
end do
60+
61+
do i = 1, N
62+
!ERROR: DO loop with CACHE directive must have loop control
63+
do
64+
!BECAUSE: This CACHE directive implies a LOOP directive
65+
!$acc cache(a)
66+
end do
67+
end do
68+
69+
do i = 1, N
70+
!$acc cache(a)
71+
do
72+
end do
73+
end do
74+
4675
end program openacc_cache_validity

0 commit comments

Comments
 (0)