[llvm-branch-commits] [flang] [flang][OpenMP] Refactor CountGeneratedNests, NFC (PR #185293)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sun Mar 8 08:41:01 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-semantics
Author: Krzysztof Parzyszek (kparzysz)
<details>
<summary>Changes</summary>
Extract handling of individual constructs into a helper function. Change the base count type to `int64_t` to match the type used in GetIntValue.
Rename the function to GetNumGeneratedNests.
---
Full diff: https://github.com/llvm/llvm-project/pull/185293.diff
3 Files Affected:
- (modified) flang/include/flang/Semantics/openmp-utils.h (+4)
- (modified) flang/lib/Semantics/check-omp-loop.cpp (+18-45)
- (modified) flang/lib/Semantics/openmp-utils.cpp (+58)
``````````diff
diff --git a/flang/include/flang/Semantics/openmp-utils.h b/flang/include/flang/Semantics/openmp-utils.h
index a10d826e4050c..7f6c2824a986a 100644
--- a/flang/include/flang/Semantics/openmp-utils.h
+++ b/flang/include/flang/Semantics/openmp-utils.h
@@ -117,6 +117,10 @@ MaybeExpr MakeEvaluateExpr(const parser::OmpStylizedInstance &inp);
bool IsLoopTransforming(llvm::omp::Directive dir);
bool IsFullUnroll(const parser::OpenMPLoopConstruct &x);
+
+std::optional<int64_t> GetNumGeneratedNestsFrom(
+ const parser::ExecutionPartConstruct &epc,
+ std::optional<int64_t> nestedCount);
} // namespace omp
} // namespace Fortran::semantics
diff --git a/flang/lib/Semantics/check-omp-loop.cpp b/flang/lib/Semantics/check-omp-loop.cpp
index d6e5a3f0aa7fb..45f4798d0c3c6 100644
--- a/flang/lib/Semantics/check-omp-loop.cpp
+++ b/flang/lib/Semantics/check-omp-loop.cpp
@@ -38,9 +38,9 @@
#include <variant>
namespace Fortran::semantics {
-static std::optional<size_t> CountGeneratedNests(
+static std::optional<int64_t> GetNumGeneratedNests(
const parser::ExecutionPartConstruct &epc);
-static std::optional<size_t> CountGeneratedNests(const parser::Block &block);
+static std::optional<int64_t> GetNumGeneratedNests(const parser::Block &block);
} // namespace Fortran::semantics
namespace {
@@ -248,7 +248,7 @@ void OmpStructureChecker::CheckSIMDNest(const parser::OpenMPConstruct &c) {
// Count the number of loop nests generated by `epc`. This is just a helper
// function for counting the number of loop nests in a parser::Block.
-static std::optional<size_t> CountGeneratedNests(
+static std::optional<int64_t> GetNumGeneratedNests(
const parser::ExecutionPartConstruct &epc) {
if (parser::Unwrap<parser::DoConstruct>(epc)) {
return 1;
@@ -258,56 +258,29 @@ static std::optional<size_t> CountGeneratedNests(
const parser::OmpDirectiveSpecification &beginSpec{omp.BeginDir()};
llvm::omp::Directive dir{beginSpec.DirName().v};
- // TODO: Handle split, apply.
- if (IsFullUnroll(omp)) {
- return std::nullopt;
- }
- if (dir == llvm::omp::Directive::OMPD_fuse) {
- auto nestedCount{CountGeneratedNests(std::get<parser::Block>(omp.t))};
- // If there are no loops nested inside of FUSE, then the construct is
- // invalid. This case will be diagnosed when analyzing the body of the FUSE
- // construct itself, not when checking a construct in which the FUSE is
- // nested.
- // Returning std::nullopt prevents error messages caused by the same
- // problem from being emitted for every enclosing loop construct, for
- // example:
- // !$omp do ! error: this should contain a loop (superfluous)
- // !$omp fuse ! error: this should contain a loop
- // !$omp end fuse
- if (!nestedCount || *nestedCount == 0) {
- return std::nullopt;
- }
- auto *clause{
- parser::omp::FindClause(beginSpec, llvm::omp::Clause::OMPC_looprange)};
- if (!clause) {
- return 1;
- }
-
- auto *loopRange{parser::Unwrap<parser::OmpLooprangeClause>(*clause)};
- std::optional<int64_t> count{GetIntValue(std::get<1>(loopRange->t))};
- if (!count || *count <= 0) {
- return std::nullopt;
- }
- if (static_cast<size_t>(*count) <= *nestedCount) {
- return 1 + *nestedCount - static_cast<size_t>(*count);
- }
- return std::nullopt;
+ switch (dir) {
+ case llvm::omp::Directive::OMPD_fuse:
+ case llvm::omp::Directive::OMPD_nothing:
+ return GetNumGeneratedNestsFrom(
+ epc, GetNumGeneratedNests(std::get<parser::Block>(omp.t)));
+ default:
+ break;
}
// For every other loop construct return 1.
return 1;
}
-static std::optional<size_t> CountGeneratedNests(const parser::Block &block) {
+static std::optional<int64_t> GetNumGeneratedNests(const parser::Block &block) {
// Count the number of loops in the associated block. If there are any
// malformed construct in there, getting the number may be meaningless.
// These issues will be diagnosed elsewhere, and we should not emit any
// messages about a potentially incorrect loop count.
// In such cases reset the count to nullopt. Once it becomes nullopt,
// keep it that way.
- std::optional<size_t> numLoops{0};
+ std::optional<int64_t> numLoops{0};
for (auto &epc : LoopRange(block, LoopRange::Step::Over)) {
- if (auto genCount{CountGeneratedNests(epc)}) {
+ if (auto genCount{GetNumGeneratedNests(epc)}) {
*numLoops += *genCount;
} else {
numLoops = std::nullopt;
@@ -363,7 +336,7 @@ void OmpStructureChecker::CheckNestedConstruct(
// Check if a loop-nest-associated construct has only one top-level loop
// in it.
- if (std::optional<size_t> numLoops{CountGeneratedNests(body)}) {
+ if (std::optional<int64_t> numLoops{GetNumGeneratedNests(body)}) {
if (*numLoops == 0) {
context_.Say(beginSpec.DirName().source,
"This construct should contain a DO-loop or a loop-nest-generating OpenMP construct"_err_en_US);
@@ -371,7 +344,7 @@ void OmpStructureChecker::CheckNestedConstruct(
auto assoc{llvm::omp::getDirectiveAssociation(beginSpec.DirName().v)};
if (*numLoops > 1 && assoc == llvm::omp::Association::LoopNest) {
context_.Say(beginSpec.DirName().source,
- "This construct applies to a loop nest, but has a loop sequence of length %zu"_err_en_US,
+ "This construct applies to a loop nest, but has a loop sequence of length %ld"_err_en_US,
*numLoops);
}
}
@@ -585,11 +558,11 @@ void OmpStructureChecker::CheckLooprangeBounds(
if (!first || !count || *first <= 0 || *count <= 0) {
return;
}
- auto requiredCount{static_cast<size_t>(*first + *count - 1)};
- if (auto loopCount{CountGeneratedNests(std::get<parser::Block>(x.t))}) {
+ int64_t requiredCount{*first + *count - 1};
+ if (auto loopCount{GetNumGeneratedNests(std::get<parser::Block>(x.t))}) {
if (*loopCount < requiredCount) {
context_.Say(clause->source,
- "The specified loop range requires %zu loops, but the loop sequence has a length of %zu"_err_en_US,
+ "The specified loop range requires %ld loops, but the loop sequence has a length of %ld"_err_en_US,
requiredCount, *loopCount);
}
}
diff --git a/flang/lib/Semantics/openmp-utils.cpp b/flang/lib/Semantics/openmp-utils.cpp
index dbc7e216c4788..533242287a667 100644
--- a/flang/lib/Semantics/openmp-utils.cpp
+++ b/flang/lib/Semantics/openmp-utils.cpp
@@ -550,4 +550,62 @@ bool IsFullUnroll(const parser::OpenMPLoopConstruct &x) {
}
return false;
}
+
+std::optional<int64_t> GetNumGeneratedNestsFrom(
+ const parser::ExecutionPartConstruct &epc,
+ std::optional<int64_t> nestedCount) {
+ if (parser::Unwrap<parser::DoConstruct>(epc)) {
+ return 1;
+ }
+
+ auto &omp{DEREF(parser::Unwrap<parser::OpenMPLoopConstruct>(epc))};
+ const parser::OmpDirectiveSpecification &beginSpec{omp.BeginDir()};
+ llvm::omp::Directive dir{beginSpec.DirId()};
+ if (!IsLoopTransforming(dir)) {
+ return 0;
+ }
+
+ // TODO: Handle split, apply.
+ if (IsFullUnroll(omp)) {
+ return std::nullopt;
+ }
+
+ if (dir == llvm::omp::Directive::OMPD_fuse) {
+ // If there are no loops nested inside of FUSE, then the construct is
+ // invalid. This case will be diagnosed when analyzing the body of the FUSE
+ // construct itself, not when checking a construct in which the FUSE is
+ // nested.
+ // Returning std::nullopt prevents error messages caused by the same
+ // problem from being emitted for every enclosing loop construct, for
+ // example:
+ // !$omp do ! error: this should contain a loop (superfluous)
+ // !$omp fuse ! error: this should contain a loop
+ // !$omp end fuse
+ if (!nestedCount || *nestedCount == 0) {
+ return std::nullopt;
+ }
+ auto *clause{
+ parser::omp::FindClause(beginSpec, llvm::omp::Clause::OMPC_looprange)};
+ if (!clause) {
+ return 1;
+ }
+
+ auto *loopRange{parser::Unwrap<parser::OmpLooprangeClause>(*clause)};
+ std::optional<int64_t> count{GetIntValue(std::get<1>(loopRange->t))};
+ if (!count || *count <= 0) {
+ return std::nullopt;
+ }
+ if (*count <= *nestedCount) {
+ return 1 + *nestedCount - *count;
+ }
+ return std::nullopt;
+ }
+
+ if (dir == llvm::omp::Directive::OMPD_nothing) {
+ return nestedCount;
+ }
+
+ // For every other loop construct return 1.
+ return 1;
+}
} // namespace Fortran::semantics::omp
``````````
</details>
https://github.com/llvm/llvm-project/pull/185293
More information about the llvm-branch-commits
mailing list