[llvm-branch-commits] [flang] [flang][OpenM] Check if loop nest/sequence is well-formed (PR #188025)
Stylie777 wrote: nit: Commit message should be [Flang][OpenMP] https://github.com/llvm/llvm-project/pull/188025 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [flang][OpenM] Check if loop nest/sequence is well-formed (PR #188025)
@@ -268,93 +258,83 @@ void OmpStructureChecker::CheckNestedConstruct(
// Check constructs contained in the body of the loop construct.
auto &body{std::get(x.t)};
+
for (auto &stmt : BlockRange(body, BlockRange::Step::Over)) {
if (auto *d{parser::Unwrap(stmt)}) {
context_.Say(d->source,
"Compiler directives are not allowed inside OpenMP loop
constructs"_warn_en_US);
-} else if (auto *omp{parser::Unwrap(stmt)}) {
- if (!IsLoopTransforming(omp->BeginDir().DirId())) {
-context_.Say(omp->source,
-"Only loop-transforming OpenMP constructs are allowed inside
OpenMP loop constructs"_err_en_US);
- }
- if (IsFullUnroll(*omp)) {
-context_.Say(x.source,
-"OpenMP loop construct cannot apply to a fully unrolled
loop"_err_en_US);
- }
-} else if (!parser::Unwrap(stmt)) {
- parser::CharBlock source{parser::GetSource(stmt).value_or(x.source)};
- context_.Say(source,
- "OpenMP loop construct can only contain DO loops or
loop-nest-generating OpenMP constructs"_err_en_US);
}
}
LoopSequence sequence(body, version, true);
- // Check if a loop-nest-associated construct has only one top-level loop
- // in it.
+ auto assoc{llvm::omp::getDirectiveAssociation(dir)};
auto needRange{GetAffectedLoopRangeWithReason(beginSpec, version)};
+ auto haveLength{sequence.length()};
- if (auto haveLength{sequence.length()}) {
-if (*haveLength.value == 0) {
+ if (assoc == llvm::omp::Association::LoopNest) {
+if (sequence.children().size() == 0) {
context_.Say(beginSource,
- "This construct should contain a DO-loop or a loop-nest-generating
OpenMP construct"_err_en_US);
-} else {
- auto assoc{llvm::omp::getDirectiveAssociation(dir)};
- if (*haveLength.value > 1 && assoc == llvm::omp::Association::LoopNest) {
-auto &msg{context_.Say(beginSource,
-"This construct applies to a loop nest, but has a loop sequence of
"
-"length %" PRId64 ""_err_en_US,
-*haveLength.value)};
-haveLength.reason.AttachTo(msg);
- }
- if (assoc == llvm::omp::Association::LoopSeq) {
-if (auto requiredCount{GetRequiredCount(needRange.value)}) {
- if (*requiredCount > 0 && *haveLength.value < *requiredCount) {
-auto &msg{context_.Say(beginSource,
-"This construct requires a sequence of %" PRId64
-" loops, but the loop sequence has a length of %" PRId64
-""_err_en_US,
-*requiredCount, *haveLength.value)};
-haveLength.reason.AttachTo(msg);
-needRange.reason.AttachTo(msg);
- }
-}
- }
+ "This construct should contain a DO-loop or a loop-nest-generating
construct"_err_en_US);
+} else if (haveLength.value > 1) {
+ auto &msg{context_.Say(beginSource,
+ "This construct applies to a loop nest, but has a loop sequence of "
+ "length %" PRId64 ""_err_en_US,
+ *haveLength.value)};
+ haveLength.reason.AttachTo(msg);
+}
+auto [isWellFormed, whyNot]{sequence.isWellFormedNest()};
+if (isWellFormed && !*isWellFormed) {
+ auto &msg{context_.Say(beginSource,
+ "This construct requires a canonical loop nest"_err_en_US)};
+ whyNot.AttachTo(msg);
}
- }
- // Check requirements on nest depth.
- auto [needDepth, needPerfect]{
- GetAffectedNestDepthWithReason(beginSpec, version)};
- auto &[haveSema, havePerf]{sequence.depth()};
+// Check requirements on nest depth.
+auto [needDepth, needPerfect]{
+GetAffectedNestDepthWithReason(beginSpec, version)};
+auto &[haveSema, havePerf]{sequence.depth()};
+
+auto haveDepth{needPerfect ? havePerf : haveSema};
+std::string_view perfectTxt{needPerfect ? " perfect" : ""};
- if (dir != llvm::omp::Directive::OMPD_fuse) {
-auto haveDepth = needPerfect ? havePerf : haveSema;
// If the present depth is 0, it's likely that the construct doesn't
// have any loops in it, which would be diagnosed above.
if (needDepth && haveDepth.value > 0) {
if (*needDepth.value > *haveDepth.value) {
-if (needPerfect) {
+auto &msg{context_.Say(beginSource,
+"This construct requires a%s nest of depth %" PRId64
+", but the associated nest is a%s nest of depth %" PRId64
+""_err_en_US,
+perfectTxt, *needDepth.value, perfectTxt, *haveDepth.value)};
+haveDepth.reason.AttachTo(msg);
+needDepth.reason.AttachTo(msg);
+ }
+}
+
+ } else if (assoc == llvm::omp::Association::LoopSeq) {
+if (haveLength.value == 0) {
+ context_.Say(beginSource,
+ "This construct should contain a DO-loop or a
loop-sequence-generating construct"_err_en_US);
Stylie777 wrote:
This looks to be repeated, to reduce maintenance can we put this in a lambd
[llvm-branch-commits] [flang] [flang][OpenM] Check if loop nest/sequence is well-formed (PR #188025)
@@ -268,93 +258,83 @@ void OmpStructureChecker::CheckNestedConstruct(
// Check constructs contained in the body of the loop construct.
auto &body{std::get(x.t)};
+
Stylie777 wrote:
nit: unnecessary change
https://github.com/llvm/llvm-project/pull/188025
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [flang][OpenM] Check if loop nest/sequence is well-formed (PR #188025)
@@ -268,93 +258,83 @@ void OmpStructureChecker::CheckNestedConstruct(
// Check constructs contained in the body of the loop construct.
auto &body{std::get(x.t)};
+
for (auto &stmt : BlockRange(body, BlockRange::Step::Over)) {
if (auto *d{parser::Unwrap(stmt)}) {
context_.Say(d->source,
"Compiler directives are not allowed inside OpenMP loop
constructs"_warn_en_US);
-} else if (auto *omp{parser::Unwrap(stmt)}) {
- if (!IsLoopTransforming(omp->BeginDir().DirId())) {
-context_.Say(omp->source,
-"Only loop-transforming OpenMP constructs are allowed inside
OpenMP loop constructs"_err_en_US);
- }
- if (IsFullUnroll(*omp)) {
-context_.Say(x.source,
-"OpenMP loop construct cannot apply to a fully unrolled
loop"_err_en_US);
- }
-} else if (!parser::Unwrap(stmt)) {
- parser::CharBlock source{parser::GetSource(stmt).value_or(x.source)};
- context_.Say(source,
- "OpenMP loop construct can only contain DO loops or
loop-nest-generating OpenMP constructs"_err_en_US);
}
}
LoopSequence sequence(body, version, true);
- // Check if a loop-nest-associated construct has only one top-level loop
- // in it.
+ auto assoc{llvm::omp::getDirectiveAssociation(dir)};
auto needRange{GetAffectedLoopRangeWithReason(beginSpec, version)};
+ auto haveLength{sequence.length()};
- if (auto haveLength{sequence.length()}) {
-if (*haveLength.value == 0) {
+ if (assoc == llvm::omp::Association::LoopNest) {
Stylie777 wrote:
Is there a risk here that things may be missed if we are now checking only for
loop nest associated directives?
https://github.com/llvm/llvm-project/pull/188025
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [flang][OpenM] Check if loop nest/sequence is well-formed (PR #188025)
https://github.com/kparzysz updated
https://github.com/llvm/llvm-project/pull/188025
>From fba1271b9b74d00f153d5f1eaa0887e61c64e02d Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek
Date: Fri, 20 Mar 2026 11:33:45 -0500
Subject: [PATCH] [flang][OpenM] Check if loop nest/sequence is well-formed
Check if the code associated with a nest or sequence construct is well
formed. Emit diagnostic messages if not.
Make a clearer separation for checks of loop-nest-associated and loop-
sequence-associated constructs.
Unify structure of some of the more common messages.
Issue: https://github.com/llvm/llvm-project/issues/185287
---
flang/include/flang/Semantics/openmp-utils.h | 3 +
flang/lib/Semantics/check-omp-loop.cpp| 126 ++
flang/lib/Semantics/openmp-utils.cpp | 162 +-
flang/lib/Semantics/resolve-directives.cpp| 5 -
flang/test/Parser/OpenMP/interchange-fail.f90 | 31
flang/test/Parser/OpenMP/tile-fail.f90| 31
flang/test/Semantics/OpenMP/do-collapse.f90 | 3 +-
.../OpenMP/do-concurrent-collapse.f90 | 11 +-
flang/test/Semantics/OpenMP/do09.f90 | 6 +-
flang/test/Semantics/OpenMP/do13.f90 | 10 +-
flang/test/Semantics/OpenMP/do21.f90 | 10 +-
flang/test/Semantics/OpenMP/fuse1.f90 | 2 +-
.../Semantics/OpenMP/interchange-fail.f90 | 18 ++
flang/test/Semantics/OpenMP/interchange01.f90 | 8 +-
.../Semantics/OpenMP/loop-association.f90 | 15 +-
.../loop-transformation-construct01.f90 | 17 +-
.../loop-transformation-construct02.f90 | 11 +-
.../loop-transformation-construct04.f90 | 4 +-
flang/test/Semantics/OpenMP/tile-fail.f90 | 18 ++
flang/test/Semantics/OpenMP/tile02.f90| 3 +-
flang/test/Semantics/OpenMP/tile03.f90| 3 +-
flang/test/Semantics/OpenMP/tile08.f90| 4 +-
flang/test/Semantics/OpenMP/tile09.f90| 3 +-
23 files changed, 269 insertions(+), 235 deletions(-)
delete mode 100644 flang/test/Parser/OpenMP/interchange-fail.f90
delete mode 100644 flang/test/Parser/OpenMP/tile-fail.f90
create mode 100644 flang/test/Semantics/OpenMP/interchange-fail.f90
create mode 100644 flang/test/Semantics/OpenMP/tile-fail.f90
diff --git a/flang/include/flang/Semantics/openmp-utils.h
b/flang/include/flang/Semantics/openmp-utils.h
index 7c95edf81ada2..bf35598177e17 100644
--- a/flang/include/flang/Semantics/openmp-utils.h
+++ b/flang/include/flang/Semantics/openmp-utils.h
@@ -202,6 +202,9 @@ struct LoopSequence {
const Depth &depth() const { return depth_; }
const std::vector &children() const { return children_; }
+ WithReason isWellFormedSequence() const;
+ WithReason isWellFormedNest() const;
+
private:
using Construct = ExecutionPartIterator::Construct;
diff --git a/flang/lib/Semantics/check-omp-loop.cpp
b/flang/lib/Semantics/check-omp-loop.cpp
index df9797ac8e56a..962537496e580 100644
--- a/flang/lib/Semantics/check-omp-loop.cpp
+++ b/flang/lib/Semantics/check-omp-loop.cpp
@@ -61,16 +61,6 @@ class AssociatedLoopChecker {
constructNamesAndLevels_.emplace(
constructName.value().ToString(), level_);
}
-if (level_ >= 0) {
- if (dc.IsDoWhile()) {
-context_.Say(doStmt.source,
-"The associated loop of a loop-associated directive cannot be a DO
WHILE."_err_en_US);
- }
- if (!dc.GetLoopControl()) {
-context_.Say(doStmt.source,
-"The associated loop of a loop-associated directive cannot be a DO
without control."_err_en_US);
- }
-}
return true;
}
@@ -268,93 +258,83 @@ void OmpStructureChecker::CheckNestedConstruct(
// Check constructs contained in the body of the loop construct.
auto &body{std::get(x.t)};
+
for (auto &stmt : BlockRange(body, BlockRange::Step::Over)) {
if (auto *d{parser::Unwrap(stmt)}) {
context_.Say(d->source,
"Compiler directives are not allowed inside OpenMP loop
constructs"_warn_en_US);
-} else if (auto *omp{parser::Unwrap(stmt)}) {
- if (!IsLoopTransforming(omp->BeginDir().DirId())) {
-context_.Say(omp->source,
-"Only loop-transforming OpenMP constructs are allowed inside
OpenMP loop constructs"_err_en_US);
- }
- if (IsFullUnroll(*omp)) {
-context_.Say(x.source,
-"OpenMP loop construct cannot apply to a fully unrolled
loop"_err_en_US);
- }
-} else if (!parser::Unwrap(stmt)) {
- parser::CharBlock source{parser::GetSource(stmt).value_or(x.source)};
- context_.Say(source,
- "OpenMP loop construct can only contain DO loops or
loop-nest-generating OpenMP constructs"_err_en_US);
}
}
LoopSequence sequence(body, version, true);
- // Check if a loop-nest-associated construct has only one top-level loop
- // in it.
+ auto assoc{llvm::omp::getDirectiveAssociation(dir)};
auto needRange{GetAffectedLoopRangeWithReason(beginSpec, version)};
+ aut
[llvm-branch-commits] [flang] [flang][OpenM] Check if loop nest/sequence is well-formed (PR #188025)
llvmbot wrote:
@llvm/pr-subscribers-flang-openmp
Author: Krzysztof Parzyszek (kparzysz)
Changes
Check if the code associated with a nest or sequence construct is well formed.
Emit diagnostic messages if not.
Make a clearer separation for checks of loop-nest-associated and loop-
sequence-associated constructs.
Unify structure of some of the more common messages.
Issue: https://github.com/llvm/llvm-project/issues/185287
---
Patch is 41.74 KiB, truncated to 20.00 KiB below, full version:
https://github.com/llvm/llvm-project/pull/188025.diff
23 Files Affected:
- (modified) flang/include/flang/Semantics/openmp-utils.h (+3)
- (modified) flang/lib/Semantics/check-omp-loop.cpp (+53-73)
- (modified) flang/lib/Semantics/openmp-utils.cpp (+115-47)
- (modified) flang/lib/Semantics/resolve-directives.cpp (-5)
- (removed) flang/test/Parser/OpenMP/interchange-fail.f90 (-31)
- (removed) flang/test/Parser/OpenMP/tile-fail.f90 (-31)
- (modified) flang/test/Semantics/OpenMP/do-collapse.f90 (+1-2)
- (modified) flang/test/Semantics/OpenMP/do-concurrent-collapse.f90 (+6-5)
- (modified) flang/test/Semantics/OpenMP/do09.f90 (+4-2)
- (modified) flang/test/Semantics/OpenMP/do13.f90 (+5-5)
- (modified) flang/test/Semantics/OpenMP/do21.f90 (+5-5)
- (modified) flang/test/Semantics/OpenMP/fuse1.f90 (+1-1)
- (added) flang/test/Semantics/OpenMP/interchange-fail.f90 (+18)
- (modified) flang/test/Semantics/OpenMP/interchange01.f90 (+5-3)
- (modified) flang/test/Semantics/OpenMP/loop-association.f90 (+9-6)
- (modified) flang/test/Semantics/OpenMP/loop-transformation-construct01.f90
(+10-7)
- (modified) flang/test/Semantics/OpenMP/loop-transformation-construct02.f90
(+6-5)
- (modified) flang/test/Semantics/OpenMP/loop-transformation-construct04.f90
(+2-2)
- (added) flang/test/Semantics/OpenMP/tile-fail.f90 (+18)
- (modified) flang/test/Semantics/OpenMP/tile02.f90 (+2-1)
- (modified) flang/test/Semantics/OpenMP/tile03.f90 (+2-1)
- (modified) flang/test/Semantics/OpenMP/tile08.f90 (+2-2)
- (modified) flang/test/Semantics/OpenMP/tile09.f90 (+2-1)
``diff
diff --git a/flang/include/flang/Semantics/openmp-utils.h
b/flang/include/flang/Semantics/openmp-utils.h
index 7c95edf81ada2..bf35598177e17 100644
--- a/flang/include/flang/Semantics/openmp-utils.h
+++ b/flang/include/flang/Semantics/openmp-utils.h
@@ -202,6 +202,9 @@ struct LoopSequence {
const Depth &depth() const { return depth_; }
const std::vector &children() const { return children_; }
+ WithReason isWellFormedSequence() const;
+ WithReason isWellFormedNest() const;
+
private:
using Construct = ExecutionPartIterator::Construct;
diff --git a/flang/lib/Semantics/check-omp-loop.cpp
b/flang/lib/Semantics/check-omp-loop.cpp
index df9797ac8e56a..962537496e580 100644
--- a/flang/lib/Semantics/check-omp-loop.cpp
+++ b/flang/lib/Semantics/check-omp-loop.cpp
@@ -61,16 +61,6 @@ class AssociatedLoopChecker {
constructNamesAndLevels_.emplace(
constructName.value().ToString(), level_);
}
-if (level_ >= 0) {
- if (dc.IsDoWhile()) {
-context_.Say(doStmt.source,
-"The associated loop of a loop-associated directive cannot be a DO
WHILE."_err_en_US);
- }
- if (!dc.GetLoopControl()) {
-context_.Say(doStmt.source,
-"The associated loop of a loop-associated directive cannot be a DO
without control."_err_en_US);
- }
-}
return true;
}
@@ -268,93 +258,83 @@ void OmpStructureChecker::CheckNestedConstruct(
// Check constructs contained in the body of the loop construct.
auto &body{std::get(x.t)};
+
for (auto &stmt : BlockRange(body, BlockRange::Step::Over)) {
if (auto *d{parser::Unwrap(stmt)}) {
context_.Say(d->source,
"Compiler directives are not allowed inside OpenMP loop
constructs"_warn_en_US);
-} else if (auto *omp{parser::Unwrap(stmt)}) {
- if (!IsLoopTransforming(omp->BeginDir().DirId())) {
-context_.Say(omp->source,
-"Only loop-transforming OpenMP constructs are allowed inside
OpenMP loop constructs"_err_en_US);
- }
- if (IsFullUnroll(*omp)) {
-context_.Say(x.source,
-"OpenMP loop construct cannot apply to a fully unrolled
loop"_err_en_US);
- }
-} else if (!parser::Unwrap(stmt)) {
- parser::CharBlock source{parser::GetSource(stmt).value_or(x.source)};
- context_.Say(source,
- "OpenMP loop construct can only contain DO loops or
loop-nest-generating OpenMP constructs"_err_en_US);
}
}
LoopSequence sequence(body, version, true);
- // Check if a loop-nest-associated construct has only one top-level loop
- // in it.
+ auto assoc{llvm::omp::getDirectiveAssociation(dir)};
auto needRange{GetAffectedLoopRangeWithReason(beginSpec, version)};
+ auto haveLength{sequence.length()};
- if (auto haveLength{sequence.length()}) {
-if (*haveLength.value == 0) {
+ if (assoc == llvm::omp::Association::Lo
[llvm-branch-commits] [flang] [flang][OpenM] Check if loop nest/sequence is well-formed (PR #188025)
llvmbot wrote:
@llvm/pr-subscribers-flang-semantics
Author: Krzysztof Parzyszek (kparzysz)
Changes
Check if the code associated with a nest or sequence construct is well formed.
Emit diagnostic messages if not.
Make a clearer separation for checks of loop-nest-associated and loop-
sequence-associated constructs.
Unify structure of some of the more common messages.
Issue: https://github.com/llvm/llvm-project/issues/185287
---
Patch is 41.74 KiB, truncated to 20.00 KiB below, full version:
https://github.com/llvm/llvm-project/pull/188025.diff
23 Files Affected:
- (modified) flang/include/flang/Semantics/openmp-utils.h (+3)
- (modified) flang/lib/Semantics/check-omp-loop.cpp (+53-73)
- (modified) flang/lib/Semantics/openmp-utils.cpp (+115-47)
- (modified) flang/lib/Semantics/resolve-directives.cpp (-5)
- (removed) flang/test/Parser/OpenMP/interchange-fail.f90 (-31)
- (removed) flang/test/Parser/OpenMP/tile-fail.f90 (-31)
- (modified) flang/test/Semantics/OpenMP/do-collapse.f90 (+1-2)
- (modified) flang/test/Semantics/OpenMP/do-concurrent-collapse.f90 (+6-5)
- (modified) flang/test/Semantics/OpenMP/do09.f90 (+4-2)
- (modified) flang/test/Semantics/OpenMP/do13.f90 (+5-5)
- (modified) flang/test/Semantics/OpenMP/do21.f90 (+5-5)
- (modified) flang/test/Semantics/OpenMP/fuse1.f90 (+1-1)
- (added) flang/test/Semantics/OpenMP/interchange-fail.f90 (+18)
- (modified) flang/test/Semantics/OpenMP/interchange01.f90 (+5-3)
- (modified) flang/test/Semantics/OpenMP/loop-association.f90 (+9-6)
- (modified) flang/test/Semantics/OpenMP/loop-transformation-construct01.f90
(+10-7)
- (modified) flang/test/Semantics/OpenMP/loop-transformation-construct02.f90
(+6-5)
- (modified) flang/test/Semantics/OpenMP/loop-transformation-construct04.f90
(+2-2)
- (added) flang/test/Semantics/OpenMP/tile-fail.f90 (+18)
- (modified) flang/test/Semantics/OpenMP/tile02.f90 (+2-1)
- (modified) flang/test/Semantics/OpenMP/tile03.f90 (+2-1)
- (modified) flang/test/Semantics/OpenMP/tile08.f90 (+2-2)
- (modified) flang/test/Semantics/OpenMP/tile09.f90 (+2-1)
``diff
diff --git a/flang/include/flang/Semantics/openmp-utils.h
b/flang/include/flang/Semantics/openmp-utils.h
index 7c95edf81ada2..bf35598177e17 100644
--- a/flang/include/flang/Semantics/openmp-utils.h
+++ b/flang/include/flang/Semantics/openmp-utils.h
@@ -202,6 +202,9 @@ struct LoopSequence {
const Depth &depth() const { return depth_; }
const std::vector &children() const { return children_; }
+ WithReason isWellFormedSequence() const;
+ WithReason isWellFormedNest() const;
+
private:
using Construct = ExecutionPartIterator::Construct;
diff --git a/flang/lib/Semantics/check-omp-loop.cpp
b/flang/lib/Semantics/check-omp-loop.cpp
index df9797ac8e56a..962537496e580 100644
--- a/flang/lib/Semantics/check-omp-loop.cpp
+++ b/flang/lib/Semantics/check-omp-loop.cpp
@@ -61,16 +61,6 @@ class AssociatedLoopChecker {
constructNamesAndLevels_.emplace(
constructName.value().ToString(), level_);
}
-if (level_ >= 0) {
- if (dc.IsDoWhile()) {
-context_.Say(doStmt.source,
-"The associated loop of a loop-associated directive cannot be a DO
WHILE."_err_en_US);
- }
- if (!dc.GetLoopControl()) {
-context_.Say(doStmt.source,
-"The associated loop of a loop-associated directive cannot be a DO
without control."_err_en_US);
- }
-}
return true;
}
@@ -268,93 +258,83 @@ void OmpStructureChecker::CheckNestedConstruct(
// Check constructs contained in the body of the loop construct.
auto &body{std::get(x.t)};
+
for (auto &stmt : BlockRange(body, BlockRange::Step::Over)) {
if (auto *d{parser::Unwrap(stmt)}) {
context_.Say(d->source,
"Compiler directives are not allowed inside OpenMP loop
constructs"_warn_en_US);
-} else if (auto *omp{parser::Unwrap(stmt)}) {
- if (!IsLoopTransforming(omp->BeginDir().DirId())) {
-context_.Say(omp->source,
-"Only loop-transforming OpenMP constructs are allowed inside
OpenMP loop constructs"_err_en_US);
- }
- if (IsFullUnroll(*omp)) {
-context_.Say(x.source,
-"OpenMP loop construct cannot apply to a fully unrolled
loop"_err_en_US);
- }
-} else if (!parser::Unwrap(stmt)) {
- parser::CharBlock source{parser::GetSource(stmt).value_or(x.source)};
- context_.Say(source,
- "OpenMP loop construct can only contain DO loops or
loop-nest-generating OpenMP constructs"_err_en_US);
}
}
LoopSequence sequence(body, version, true);
- // Check if a loop-nest-associated construct has only one top-level loop
- // in it.
+ auto assoc{llvm::omp::getDirectiveAssociation(dir)};
auto needRange{GetAffectedLoopRangeWithReason(beginSpec, version)};
+ auto haveLength{sequence.length()};
- if (auto haveLength{sequence.length()}) {
-if (*haveLength.value == 0) {
+ if (assoc == llvm::omp::Association:
[llvm-branch-commits] [flang] [flang][OpenM] Check if loop nest/sequence is well-formed (PR #188025)
https://github.com/kparzysz created
https://github.com/llvm/llvm-project/pull/188025
Check if the code associated with a nest or sequence construct is well formed.
Emit diagnostic messages if not.
Make a clearer separation for checks of loop-nest-associated and loop-
sequence-associated constructs.
Unify structure of some of the more common messages.
Issue: https://github.com/llvm/llvm-project/issues/185287
>From fba1271b9b74d00f153d5f1eaa0887e61c64e02d Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek
Date: Fri, 20 Mar 2026 11:33:45 -0500
Subject: [PATCH] [flang][OpenM] Check if loop nest/sequence is well-formed
Check if the code associated with a nest or sequence construct is well
formed. Emit diagnostic messages if not.
Make a clearer separation for checks of loop-nest-associated and loop-
sequence-associated constructs.
Unify structure of some of the more common messages.
Issue: https://github.com/llvm/llvm-project/issues/185287
---
flang/include/flang/Semantics/openmp-utils.h | 3 +
flang/lib/Semantics/check-omp-loop.cpp| 126 ++
flang/lib/Semantics/openmp-utils.cpp | 162 +-
flang/lib/Semantics/resolve-directives.cpp| 5 -
flang/test/Parser/OpenMP/interchange-fail.f90 | 31
flang/test/Parser/OpenMP/tile-fail.f90| 31
flang/test/Semantics/OpenMP/do-collapse.f90 | 3 +-
.../OpenMP/do-concurrent-collapse.f90 | 11 +-
flang/test/Semantics/OpenMP/do09.f90 | 6 +-
flang/test/Semantics/OpenMP/do13.f90 | 10 +-
flang/test/Semantics/OpenMP/do21.f90 | 10 +-
flang/test/Semantics/OpenMP/fuse1.f90 | 2 +-
.../Semantics/OpenMP/interchange-fail.f90 | 18 ++
flang/test/Semantics/OpenMP/interchange01.f90 | 8 +-
.../Semantics/OpenMP/loop-association.f90 | 15 +-
.../loop-transformation-construct01.f90 | 17 +-
.../loop-transformation-construct02.f90 | 11 +-
.../loop-transformation-construct04.f90 | 4 +-
flang/test/Semantics/OpenMP/tile-fail.f90 | 18 ++
flang/test/Semantics/OpenMP/tile02.f90| 3 +-
flang/test/Semantics/OpenMP/tile03.f90| 3 +-
flang/test/Semantics/OpenMP/tile08.f90| 4 +-
flang/test/Semantics/OpenMP/tile09.f90| 3 +-
23 files changed, 269 insertions(+), 235 deletions(-)
delete mode 100644 flang/test/Parser/OpenMP/interchange-fail.f90
delete mode 100644 flang/test/Parser/OpenMP/tile-fail.f90
create mode 100644 flang/test/Semantics/OpenMP/interchange-fail.f90
create mode 100644 flang/test/Semantics/OpenMP/tile-fail.f90
diff --git a/flang/include/flang/Semantics/openmp-utils.h
b/flang/include/flang/Semantics/openmp-utils.h
index 7c95edf81ada2..bf35598177e17 100644
--- a/flang/include/flang/Semantics/openmp-utils.h
+++ b/flang/include/flang/Semantics/openmp-utils.h
@@ -202,6 +202,9 @@ struct LoopSequence {
const Depth &depth() const { return depth_; }
const std::vector &children() const { return children_; }
+ WithReason isWellFormedSequence() const;
+ WithReason isWellFormedNest() const;
+
private:
using Construct = ExecutionPartIterator::Construct;
diff --git a/flang/lib/Semantics/check-omp-loop.cpp
b/flang/lib/Semantics/check-omp-loop.cpp
index df9797ac8e56a..962537496e580 100644
--- a/flang/lib/Semantics/check-omp-loop.cpp
+++ b/flang/lib/Semantics/check-omp-loop.cpp
@@ -61,16 +61,6 @@ class AssociatedLoopChecker {
constructNamesAndLevels_.emplace(
constructName.value().ToString(), level_);
}
-if (level_ >= 0) {
- if (dc.IsDoWhile()) {
-context_.Say(doStmt.source,
-"The associated loop of a loop-associated directive cannot be a DO
WHILE."_err_en_US);
- }
- if (!dc.GetLoopControl()) {
-context_.Say(doStmt.source,
-"The associated loop of a loop-associated directive cannot be a DO
without control."_err_en_US);
- }
-}
return true;
}
@@ -268,93 +258,83 @@ void OmpStructureChecker::CheckNestedConstruct(
// Check constructs contained in the body of the loop construct.
auto &body{std::get(x.t)};
+
for (auto &stmt : BlockRange(body, BlockRange::Step::Over)) {
if (auto *d{parser::Unwrap(stmt)}) {
context_.Say(d->source,
"Compiler directives are not allowed inside OpenMP loop
constructs"_warn_en_US);
-} else if (auto *omp{parser::Unwrap(stmt)}) {
- if (!IsLoopTransforming(omp->BeginDir().DirId())) {
-context_.Say(omp->source,
-"Only loop-transforming OpenMP constructs are allowed inside
OpenMP loop constructs"_err_en_US);
- }
- if (IsFullUnroll(*omp)) {
-context_.Say(x.source,
-"OpenMP loop construct cannot apply to a fully unrolled
loop"_err_en_US);
- }
-} else if (!parser::Unwrap(stmt)) {
- parser::CharBlock source{parser::GetSource(stmt).value_or(x.source)};
- context_.Say(source,
- "OpenMP loop construct can only contain DO loops or
loop-
