[flang-commits] [flang] [Flang][OpenMP] Add Semantics support for Nested OpenMPLoopConstructs (PR #145917)

Tom Eccles via flang-commits flang-commits at lists.llvm.org
Thu Jun 26 09:17:36 PDT 2025


================
@@ -135,31 +142,74 @@ class CanonicalizationOfOmp {
       if (auto *doCons{GetConstructIf<parser::DoConstruct>(*nextIt)}) {
         if (doCons->GetLoopControl()) {
           // move DoConstruct
-          std::get<std::optional<parser::DoConstruct>>(x.t) =
+          std::get<std::optional<std::variant<parser::DoConstruct,
+              common::Indirection<parser::OpenMPLoopConstruct>>>>(x.t) =
               std::move(*doCons);
           nextIt = block.erase(nextIt);
           // try to match OmpEndLoopDirective
-          if (nextIt != block.end()) {
+          if (auto *endDir{
+                  GetConstructIf<parser::OmpEndLoopDirective>(*nextIt)}) {
+            std::get<std::optional<parser::OmpEndLoopDirective>>(x.t) =
+                std::move(*endDir);
+            nextIt = block.erase(nextIt);
+          }
+        } else {
+          messages_.Say(dir.source,
+              "DO loop after the %s directive must have loop control"_err_en_US,
+              parser::ToUpperCaseLetters(dir.source.ToString()));
+        }
+      } else if (auto *ompLoopCons{
+                     GetOmpIf<parser::OpenMPLoopConstruct>(*nextIt)}) {
+        // We should allow UNROLL and TILE constructs to be inserted between an
+        // OpenMP Loop Construct and the DO loop itself
+        auto &beginDirective =
+            std::get<parser::OmpBeginLoopDirective>(ompLoopCons->t);
+        auto &beginLoopDirective =
+            std::get<parser::OmpLoopDirective>(beginDirective.t);
+        if ((beginLoopDirective.v == llvm::omp::Directive::OMPD_unroll ||
+                beginLoopDirective.v == llvm::omp::Directive::OMPD_tile)) {
+          // iterate through the remaining block items to find the end directive
+          // for the unroll/tile directive.
+          parser::Block::iterator endIt;
+          endIt = nextIt;
+          while (endIt != block.end()) {
             if (auto *endDir{
-                    GetConstructIf<parser::OmpEndLoopDirective>(*nextIt)}) {
-              std::get<std::optional<parser::OmpEndLoopDirective>>(x.t) =
-                  std::move(*endDir);
-              block.erase(nextIt);
+                    GetConstructIf<parser::OmpEndLoopDirective>(*endIt)}) {
+              auto &endLoopDirective =
+                  std::get<parser::OmpLoopDirective>(endDir->t);
+              if (endLoopDirective.v == dir.v) {
+                std::get<std::optional<parser::OmpEndLoopDirective>>(x.t) =
+                    std::move(*endDir);
+                endIt = block.erase(endIt);
+                continue;
+              }
             }
+            ++endIt;
           }
+          RewriteOpenMPLoopConstruct(*ompLoopCons, block, nextIt);
+          auto &ompLoop =
+              std::get<std::optional<std::variant<parser::DoConstruct,
+                  common::Indirection<parser::OpenMPLoopConstruct>>>>(x.t);
+          ompLoop = std::optional<std::variant<parser::DoConstruct,
+              common::Indirection<parser::OpenMPLoopConstruct>>>{
+              std::variant<parser::DoConstruct,
+                  common::Indirection<parser::OpenMPLoopConstruct>>{
+                  common::Indirection{std::move(*ompLoopCons)}}};
+          nextIt = block.erase(nextIt);
         } else {
           messages_.Say(dir.source,
-              "DO loop after the %s directive must have loop control"_err_en_US,
+              "Only OpenMP Loop Transformation Constructs can be nested within OpenMPLoopConstruct's"_err_en_US,
----------------
tblah wrote:

I don't think this would be a clear compiler error for end users. Maybe "only loop transformation constructs or loop nests can be nested within loop constructs"

https://github.com/llvm/llvm-project/pull/145917


More information about the flang-commits mailing list