[llvm] [LoopInterchange] Supported partially-perfect Loop Nests (PR #199511)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 28 11:50:22 PDT 2026
================
@@ -674,12 +680,64 @@ struct LoopInterchange {
return processLoopList(LoopList);
}
+ /// Consider below kernel:
+ /// for(int i=0; i<n; i++){ // Loop 1
+ /// for(int j=0; j<m; j++){ // Loop 2
+ /// for(int r=0; r<m; r++){ // Loop 3
+ /// // Do something
+ /// }
+ /// }
+ /// for(int k=0; k<p; k++){ // Loop 4
+ /// for(int l=0; l<p; l++){ // Loop 5
+ /// // Do something
+ /// }
+ /// }
+ /// }
+ /// Then collectPerfectNests() will return:
+ /// - [Loop2, Loop3]
+ /// - [Loop4, Loop5]
+ static SmallVector<SmallVector<Loop *, 8>, 4>
+ collectPerfectNests(LoopNest &LN) {
+ SmallVector<SmallVector<Loop *, 8>, 4> LoopLists;
+ for (Loop *L : LN.getLoops()) {
+ if (!L->isInnermost())
+ continue;
+
+ SmallVector<Loop *, 8> LoopList;
+ Loop *Current = L;
+ while (true) {
+ LoopList.push_back(Current);
+ Loop *Parent = Current->getParentLoop();
+ if (!Parent || Parent->getSubLoops().size() != 1)
+ break;
+ Current = Parent;
+ }
+ std::reverse(LoopList.begin(), LoopList.end());
+ if (LoopList.size() >= 2)
+ LoopLists.push_back(std::move(LoopList));
+ }
+ return LoopLists;
+ }
+
bool run(LoopNest &LN) {
- SmallVector<Loop *, 8> LoopList(LN.getLoops());
- for (unsigned I = 1; I < LoopList.size(); ++I)
- if (LoopList[I]->getParentLoop() != LoopList[I - 1])
- return false;
- return processLoopList(LoopList);
+ SmallVector<SmallVector<Loop *, 8>, 4> LoopLists = collectPerfectNests(LN);
+ if (LoopLists.empty()) {
+ LLVM_DEBUG(dbgs() << "No Valid candidates for loop interchange.\n");
+ return false;
+ }
+ bool Changed = false;
+ for (SmallVector<Loop *, 8> &LoopList : LoopLists) {
+ // Ensure minimum depth of the loop nest to do the interchange.
+ if (!hasSupportedLoopDepth(LoopList, *ORE))
+ continue;
+ // Ensure computable loop nest.
+ if (!isComputableLoopNest(&AR->SE, LoopList)) {
+ LLVM_DEBUG(dbgs() << "Not valid loop candidate for interchange\n");
+ continue;
+ }
+ Changed |= processLoopList(LoopList);
----------------
MattPD wrote:
I'd fix this in this PR. `LoopInfo::verify` ignores sibling order, but `LoopInfo` documents subloops in forward program order, and loop worklists rely on it. In the linked test case, `print<loops>` after LoopInterchange lists the transformed pair behind all nine siblings. Rebuilding `LoopInfo` from the emitted IR lists it before them. Since the pass preserves `LoopAnalysis`, later loop passes can see a different sibling traversal order depending on whether they use the preserved or rebuilt analysis. Detaching `NewOuter` and replacing `NewInner` in place would keep the pair's slot. A `print<loops>` check pinning only the loop headers, in order, would cover it.
https://github.com/llvm/llvm-project/pull/199511
More information about the llvm-commits
mailing list