[llvm] [mlir] [MLIR][OpenMP] add interchange operation in the OpenMP mlir dialect (PR #186381)

Michael Kruse via llvm-commits llvm-commits at lists.llvm.org
Fri Mar 27 05:03:31 PDT 2026


================
@@ -6785,6 +6783,89 @@ void OpenMPIRBuilder::unrollLoopHeuristic(DebugLoc, CanonicalLoopInfo *Loop) {
             });
 }
 
+std::vector<CanonicalLoopInfo *>
+OpenMPIRBuilder::interchangeLoops(DebugLoc DL,
+                                  ArrayRef<CanonicalLoopInfo *> Loops,
+                                  std::vector<int> Permutation) {
+  assert(Permutation.size() == Loops.size() &&
+         "The permutation must have every input loop");
+  int NumLoops = Loops.size();
+  assert(NumLoops >= 2 && "At least two loops to interchange required");
+
+  CanonicalLoopInfo *OutermostLoop = Loops.front();
+  CanonicalLoopInfo *InnermostLoop = Loops.back();
+  Function *F = OutermostLoop->getBody()->getParent();
+
+  // Loop control blocks that may become orphaned later.
+  SmallVector<BasicBlock *> OldControlBBs;
+  for (CanonicalLoopInfo *Loop : Loops)
+    Loop->collectControlBlocks(OldControlBBs);
+
+  // Create the new loop nest structure
+  std::vector<CanonicalLoopInfo *> Result;
+
+  BasicBlock *Enter = OutermostLoop->getPreheader();
+  BasicBlock *Continue = OutermostLoop->getAfter();
+  BasicBlock *OutroInsertBefore = InnermostLoop->getExit();
+
+  for (int i = 0; i < NumLoops; i++) {
+    int loop_n = Permutation[i] - 1;
+    assert(Loops[loop_n]->isValid() &&
+           "All input loops must be valid canonical loops");
+
+    CanonicalLoopInfo *newLoop = createLoopSkeleton(
+        DL, Loops[loop_n]->getTripCount(), F, InnermostLoop->getBody(),
+        OutroInsertBefore, "interchange" + Twine(i));
+    redirectAllPredecessorsTo(Loops[i]->getPreheader(), newLoop->getPreheader(),
+                              DL);
+    redirectTo(Enter, newLoop->getPreheader(), DL);
+    redirectTo(newLoop->getAfter(), Continue, DL);
+
+    // Setup the position where the next loop connects to this loop.
+    Enter = newLoop->getBody();
+    Continue = newLoop->getLatch();
+    OutroInsertBefore = newLoop->getLatch();
+
+    Result.push_back(newLoop);
+  }
+
+  // Detach the original loops
+  for (int i = 0; i < NumLoops - 1; i++) {
+    BasicBlock *body = Loops[i]->getBody();
+    BasicBlock *region =
+        cast<UncondBrInst>(body->getTerminator())->getSuccessor(0);
+    BasicBlock *cont = Loops[i]->getLatch()->getUniquePredecessor();
----------------
Meinersbur wrote:

```suggestion
    BasicBlock *Body = Loops[i]->getBody();
    BasicBlock *Region =
        cast<UncondBrInst>(Body->getTerminator())->getSuccessor(0);
    BasicBlock *Cont = Loops[i]->getLatch()->getUniquePredecessor();
```
[style] [Variable names should be nouns (as they represent state). The name should be camel case, and start with an upper-case letter (e.g. Leader or Boats).](https://llvm.org/docs/CodingStandards.html#name-types-functions-variables-and-enumerators-properly)

By defintions of CanonicalLoopInfo, Latch does not necessarily have a single predecessor (https://github.com/llvm/llvm-project/blob/c0e8eb972b3934f2dfa7b6a413a2bf6ef09da0dc/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h#L4086), not does the body have to end with a branch (`Cond` does).

Did you consider collecting these blocks before making changes to the CanonicalLoopInfo CFG?

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


More information about the llvm-commits mailing list