diff --git a/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h b/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h --- a/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h +++ b/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h @@ -193,7 +193,7 @@ LoopStandardAnalysisResults &AR, LPMUpdater &U, PassInstrumentation &PI); - PreservedAnalyses runWithLoopNestPasses(Loop &L, LoopAnalysisManager &AM, + PreservedAnalyses runWithLoopNestPasses(Loop *L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR, LPMUpdater &U); PreservedAnalyses runWithoutLoopNestPasses(Loop &L, LoopAnalysisManager &AM, diff --git a/llvm/lib/Transforms/Scalar/LoopPassManager.cpp b/llvm/lib/Transforms/Scalar/LoopPassManager.cpp --- a/llvm/lib/Transforms/Scalar/LoopPassManager.cpp +++ b/llvm/lib/Transforms/Scalar/LoopPassManager.cpp @@ -28,7 +28,7 @@ LoopStandardAnalysisResults &AR, LPMUpdater &U) { // Runs loop-nest passes only when the current loop is a top-level one. PreservedAnalyses PA = (L.isOutermost() && !LoopNestPasses.empty()) - ? runWithLoopNestPasses(L, AM, AR, U) + ? runWithLoopNestPasses(&L, AM, AR, U) : runWithoutLoopNestPasses(L, AM, AR, U); // Invalidation for the current loop should be handled above, and other loop @@ -65,16 +65,16 @@ // Run both loop passes and loop-nest passes on top-level loop \p L. PreservedAnalyses -LoopPassManager::runWithLoopNestPasses(Loop &L, LoopAnalysisManager &AM, +LoopPassManager::runWithLoopNestPasses(Loop *L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR, LPMUpdater &U) { - assert(L.isOutermost() && + assert(L->isOutermost() && "Loop-nest passes should only run on top-level loops."); PreservedAnalyses PA = PreservedAnalyses::all(); // Request PassInstrumentation from analysis manager, will use it to run // instrumenting callbacks for the passes later. - PassInstrumentation PI = AM.getResult(L, AR); + PassInstrumentation PI = AM.getResult(*L, AR); unsigned LoopPassIndex = 0, LoopNestPassIndex = 0; @@ -86,11 +86,17 @@ bool IsLoopNestPtrValid = false; for (size_t I = 0, E = IsLoopNestPass.size(); I != E; ++I) { + // A loop nest should be constructed with the outermost loop. In case L is + // no longer the outermost loop after transformation, we obtain the current + // outermost loop. + while (Loop *Parent = L->getParentLoop()) + L = Parent; + Optional PassPA; if (!IsLoopNestPass[I]) { // The `I`-th pass is a loop pass. auto &Pass = LoopPasses[LoopPassIndex++]; - PassPA = runSinglePass(L, Pass, AM, AR, U, PI); + PassPA = runSinglePass(*L, Pass, AM, AR, U, PI); } else { // The `I`-th pass is a loop-nest pass. auto &Pass = LoopNestPasses[LoopNestPassIndex++]; @@ -98,7 +104,7 @@ // If the loop-nest object calculated before is no longer valid, // re-calculate it here before running the loop-nest pass. if (!IsLoopNestPtrValid) { - LoopNestPtr = LoopNest::getLoopNest(L, AR.SE); + LoopNestPtr = LoopNest::getLoopNest(*L, AR.SE); IsLoopNestPtrValid = true; } PassPA = runSinglePass(*LoopNestPtr, Pass, AM, AR, U, PI); @@ -118,7 +124,7 @@ // Update the analysis manager as each pass runs and potentially // invalidates analyses. - AM.invalidate(L, *PassPA); + AM.invalidate(*L, *PassPA); // Finally, we intersect the final preserved analyses to compute the // aggregate preserved set for this pass manager. @@ -130,7 +136,7 @@ // After running the loop pass, the parent loop might change and we need to // notify the updater, otherwise U.ParentL might gets outdated and triggers // assertion failures in addSiblingLoops and addChildLoops. - U.setParentLoop(L.getParentLoop()); + U.setParentLoop(L->getParentLoop()); } return PA; } diff --git a/llvm/test/Transforms/LoopInterchange/interchanged-loop-nest-4.ll b/llvm/test/Transforms/LoopInterchange/interchanged-loop-nest-4.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/LoopInterchange/interchanged-loop-nest-4.ll @@ -0,0 +1,53 @@ +; REQUIRES: asserts +; RUN: opt < %s -passes="loop(loop-interchange,loop-interchange)" -cache-line-size=8 -verify-dom-info -verify-loop-info \ +; RUN: -debug-only=loop-interchange 2>&1 | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +@g_75 = external global i32, align 1 +@g_78 = external global [6 x ptr], align 1 + +; Loop interchange as a loopnest pass should always construct the loop nest from +; the outermost loop. This test case runs loop interchange twice. In the loop pass +; manager, it might occur that after the first loop interchange transformation +; the original outermost loop becomes a inner loop hence the loop nest constructed +; afterwards for the second loop interchange pass turns out to be a loop list of size +; 2 and is not valid. This causes functional issues. +; +; Make sure we always construct the valid and correct loop nest at the beginning +; of execution of a loopnest pass. + +; CHECK: Processing LoopList of size = 3 +; CHECK: Processing LoopList of size = 3 +define void @loopnest_01() { +entry: + br label %for.cond5.preheader.i.i.i + +for.cond5.preheader.i.i.i: ; preds = %for.end16.i.i.i, %entry + %storemerge11.i.i.i = phi i32 [ 4, %entry ], [ %sub18.i.i.i, %for.end16.i.i.i ] + br label %for.cond8.preheader.i.i.i + +for.cond8.preheader.i.i.i: ; preds = %for.inc14.i.i.i, %for.cond5.preheader.i.i.i + %l_105.18.i.i.i = phi i16 [ 0, %for.cond5.preheader.i.i.i ], [ %add15.i.i.i, %for.inc14.i.i.i ] + br label %for.body10.i.i.i + +for.body10.i.i.i: ; preds = %for.body10.i.i.i, %for.cond8.preheader.i.i.i + %storemerge56.i.i.i = phi i16 [ 5, %for.cond8.preheader.i.i.i ], [ %sub.i.i.i, %for.body10.i.i.i ] + %arrayidx.i.i.i = getelementptr [6 x ptr], ptr @g_78, i16 0, i16 %storemerge56.i.i.i + store ptr @g_75, ptr %arrayidx.i.i.i, align 1 + %sub.i.i.i = add nsw i16 %storemerge56.i.i.i, -1 + br i1 true, label %for.inc14.i.i.i, label %for.body10.i.i.i + +for.inc14.i.i.i: ; preds = %for.body10.i.i.i + %add15.i.i.i = add nuw nsw i16 %l_105.18.i.i.i, 1 + %exitcond.not.i.i.i = icmp eq i16 %add15.i.i.i, 6 + br i1 %exitcond.not.i.i.i, label %for.end16.i.i.i, label %for.cond8.preheader.i.i.i + +for.end16.i.i.i: ; preds = %for.inc14.i.i.i + %sub18.i.i.i = add nsw i32 %storemerge11.i.i.i, -1 + %cmp.i10.not.i.i = icmp eq i32 %storemerge11.i.i.i, 0 + br i1 %cmp.i10.not.i.i, label %func_4.exit.i, label %for.cond5.preheader.i.i.i + +func_4.exit.i: ; preds = %for.end16.i.i.i + unreachable +}