[llvm-branch-commits] [flang] [flang][OpenM] Check if loop nest/sequence is well-formed (PR #188025)
Jack Styles via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Mar 23 08:49:49 PDT 2026
================
@@ -268,93 +258,83 @@ void OmpStructureChecker::CheckNestedConstruct(
// Check constructs contained in the body of the loop construct.
auto &body{std::get<parser::Block>(x.t)};
+
for (auto &stmt : BlockRange(body, BlockRange::Step::Over)) {
if (auto *d{parser::Unwrap<parser::CompilerDirective>(stmt)}) {
context_.Say(d->source,
"Compiler directives are not allowed inside OpenMP loop constructs"_warn_en_US);
- } else if (auto *omp{parser::Unwrap<parser::OpenMPLoopConstruct>(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<parser::DoConstruct>(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 lambda function taking the source as an argument? This also applies to other error messages in this function.
https://github.com/llvm/llvm-project/pull/188025
More information about the llvm-branch-commits
mailing list