[flang-commits] [flang] [flang][OpenMP] Implement loop construct iterator range (PR #170734)

Krzysztof Parzyszek via flang-commits flang-commits at lists.llvm.org
Mon Dec 8 08:52:21 PST 2025


https://github.com/kparzysz updated https://github.com/llvm/llvm-project/pull/170734

>From ca0b4a3ae509f29aaaaa9a67140533e3ceca544b Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Tue, 2 Dec 2025 14:34:45 -0600
Subject: [PATCH 1/3] [flang][OpenMP] Implement loop construct iterator range

Since we're trying to preserve compiler directives in loop constructs,
not every element of the associated parser::Block needs to be a loop
or an OpenMP loop construct. Implement a helper class `LoopRange` to
make it easy to iterate over elements of parser::Block that are loops
or loop constructs.
---
 flang/include/flang/Parser/openmp-utils.h | 74 +++++++++++++++++++++++
 flang/lib/Parser/openmp-utils.cpp         | 37 ++++++++++++
 2 files changed, 111 insertions(+)

diff --git a/flang/include/flang/Parser/openmp-utils.h b/flang/include/flang/Parser/openmp-utils.h
index e164f63aa189b..27e4aa6db0f0b 100644
--- a/flang/include/flang/Parser/openmp-utils.h
+++ b/flang/include/flang/Parser/openmp-utils.h
@@ -237,6 +237,80 @@ struct OmpAllocateInfo {
 
 OmpAllocateInfo SplitOmpAllocate(const OmpAllocateDirective &x);
 
+namespace detail {
+template <bool IsConst, typename T>
+struct ConstIf {
+  using type = std::conditional_t<IsConst, std::add_const_t<T>, T>;
+};
+
+template <bool IsConst, typename T>
+using ConstIfT = typename ConstIf<IsConst, T>::type;
+}
+
+template <bool IsConst> struct LoopRange {
+  using QualBlock = detail::ConstIfT<IsConst, Block>;
+  using QualReference = decltype(std::declval<QualBlock>().front());
+  using QualPointer = std::remove_reference_t<QualReference> *;
+
+  LoopRange(QualBlock &x) { Initialize(x); }
+  LoopRange(QualReference x);
+
+  LoopRange(detail::ConstIfT<IsConst, OpenMPLoopConstruct> &x)
+      : LoopRange(std::get<Block>(x.t)) {}
+  LoopRange(detail::ConstIfT<IsConst, DoConstruct> &x)
+      : LoopRange(std::get<Block>(x.t)) {}
+
+  size_t size() const { return items.size(); }
+
+  struct iterator;
+
+  iterator begin();
+  iterator end();
+
+private:
+  void Initialize(QualBlock &body);
+
+  std::vector<QualPointer> items;
+};
+
+template <typename T> LoopRange(T &x) -> LoopRange<std::is_const_v<T>>;
+
+template <bool IsConst> struct LoopRange<IsConst>::iterator {
+  QualReference operator*() { return **at; }
+
+  bool operator==(const iterator &other) const { return at == other.at; }
+  bool operator!=(const iterator &other) const { return at != other.at; }
+
+  iterator &operator++() {
+    ++at;
+    return *this;
+  }
+  iterator &operator--() {
+    --at;
+    return *this;
+  }
+  iterator &operator++(int);
+  iterator &operator--(int);
+
+private:
+  friend struct LoopRange;
+  typename decltype(LoopRange::items)::iterator at;
+};
+
+template <bool IsConst> inline auto LoopRange<IsConst>::begin() -> iterator {
+  iterator x;
+  x.at = items.begin();
+  return x;
+}
+
+template <bool IsConst> inline auto LoopRange<IsConst>::end() -> iterator {
+  iterator x;
+  x.at = items.end();
+  return x;
+}
+
+using ConstLoopRange = LoopRange<true>;
+
 } // namespace Fortran::parser::omp
 
 #endif // FORTRAN_PARSER_OPENMP_UTILS_H
diff --git a/flang/lib/Parser/openmp-utils.cpp b/flang/lib/Parser/openmp-utils.cpp
index 4c38917e87d29..099c7faf328c3 100644
--- a/flang/lib/Parser/openmp-utils.cpp
+++ b/flang/lib/Parser/openmp-utils.cpp
@@ -205,4 +205,41 @@ OmpAllocateInfo SplitOmpAllocate(const OmpAllocateDirective &x) {
   return info;
 }
 
+template <bool IsConst>
+LoopRange<IsConst>::LoopRange(QualReference x) {
+  if (auto *doLoop{Unwrap<DoConstruct>(x)}) {
+    Initialize(std::get<Block>(doLoop->t));
+  } else if (auto *omp{Unwrap<OpenMPLoopConstruct>(x)}) {
+    Initialize(std::get<Block>(omp->t));
+  }
+}
+
+template <bool IsConst>
+void LoopRange<IsConst>::Initialize(QualBlock &body) {
+  using QualIterator = decltype(std::declval<QualBlock>().begin());
+  auto makeRange{[](auto &container) {
+    return llvm::make_range(container.begin(), container.end());
+  }};
+
+  std::vector<llvm::iterator_range<QualIterator>> nest{makeRange(body)};
+  do {
+    auto at{nest.back().begin()};
+    auto end{nest.back().end()};
+    nest.pop_back();
+    while (at != end) {
+      if (auto *block{Unwrap<BlockConstruct>(*at)}) {
+        nest.push_back(llvm::make_range(std::next(at), end));
+        nest.push_back(makeRange(std::get<Block>(block->t)));
+        break;
+      } else if (Unwrap<DoConstruct>(*at) || Unwrap<OpenMPLoopConstruct>(*at)) {
+        items.push_back(&*at);
+      }
+      ++at;
+    }
+  } while (!nest.empty());
+}
+
+template struct LoopRange<false>;
+template struct LoopRange<true>;
+
 } // namespace Fortran::parser::omp

>From 713e9446c145e323651a8908c617f83b7389a757 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Thu, 4 Dec 2025 14:20:46 -0600
Subject: [PATCH 2/3] format

---
 flang/include/flang/Parser/openmp-utils.h | 5 ++---
 flang/lib/Parser/openmp-utils.cpp         | 6 ++----
 2 files changed, 4 insertions(+), 7 deletions(-)

diff --git a/flang/include/flang/Parser/openmp-utils.h b/flang/include/flang/Parser/openmp-utils.h
index 27e4aa6db0f0b..c47cdb295da4a 100644
--- a/flang/include/flang/Parser/openmp-utils.h
+++ b/flang/include/flang/Parser/openmp-utils.h
@@ -238,14 +238,13 @@ struct OmpAllocateInfo {
 OmpAllocateInfo SplitOmpAllocate(const OmpAllocateDirective &x);
 
 namespace detail {
-template <bool IsConst, typename T>
-struct ConstIf {
+template <bool IsConst, typename T> struct ConstIf {
   using type = std::conditional_t<IsConst, std::add_const_t<T>, T>;
 };
 
 template <bool IsConst, typename T>
 using ConstIfT = typename ConstIf<IsConst, T>::type;
-}
+} // namespace detail
 
 template <bool IsConst> struct LoopRange {
   using QualBlock = detail::ConstIfT<IsConst, Block>;
diff --git a/flang/lib/Parser/openmp-utils.cpp b/flang/lib/Parser/openmp-utils.cpp
index 099c7faf328c3..1593b19d6b372 100644
--- a/flang/lib/Parser/openmp-utils.cpp
+++ b/flang/lib/Parser/openmp-utils.cpp
@@ -205,8 +205,7 @@ OmpAllocateInfo SplitOmpAllocate(const OmpAllocateDirective &x) {
   return info;
 }
 
-template <bool IsConst>
-LoopRange<IsConst>::LoopRange(QualReference x) {
+template <bool IsConst> LoopRange<IsConst>::LoopRange(QualReference x) {
   if (auto *doLoop{Unwrap<DoConstruct>(x)}) {
     Initialize(std::get<Block>(doLoop->t));
   } else if (auto *omp{Unwrap<OpenMPLoopConstruct>(x)}) {
@@ -214,8 +213,7 @@ LoopRange<IsConst>::LoopRange(QualReference x) {
   }
 }
 
-template <bool IsConst>
-void LoopRange<IsConst>::Initialize(QualBlock &body) {
+template <bool IsConst> void LoopRange<IsConst>::Initialize(QualBlock &body) {
   using QualIterator = decltype(std::declval<QualBlock>().begin());
   auto makeRange{[](auto &container) {
     return llvm::make_range(container.begin(), container.end());

>From c7022e36fe3506aaa18a4a9f8595080fd12f3c88 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Mon, 8 Dec 2025 10:52:02 -0600
Subject: [PATCH 3/3] Add empty

---
 flang/include/flang/Parser/openmp-utils.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/flang/include/flang/Parser/openmp-utils.h b/flang/include/flang/Parser/openmp-utils.h
index c47cdb295da4a..6dac64ecbaf08 100644
--- a/flang/include/flang/Parser/openmp-utils.h
+++ b/flang/include/flang/Parser/openmp-utils.h
@@ -260,6 +260,7 @@ template <bool IsConst> struct LoopRange {
       : LoopRange(std::get<Block>(x.t)) {}
 
   size_t size() const { return items.size(); }
+  bool empty() const { return items.size() == 0; }
 
   struct iterator;
 



More information about the flang-commits mailing list