diff --git a/llvm/include/llvm/Support/GenericDomTree.h b/llvm/include/llvm/Support/GenericDomTree.h index 832b6e02daf5..920983e7bd80 100644 --- a/llvm/include/llvm/Support/GenericDomTree.h +++ b/llvm/include/llvm/Support/GenericDomTree.h @@ -384,11 +384,15 @@ protected: private: std::optional getNodeIndex(const NodeT *BB) const { if constexpr (GraphHasNodeNumbers) { - // BB can be nullptr, map nullptr to index 0. assert(BlockNumberEpoch == GraphTraits::getNumberEpoch(Parent) && "dominator tree used with outdated block numbers"); - return BB ? GraphTraits::getNumber(BB) + 1 : 0; + if constexpr (IsPostDom) { + if (!BB) + return 0; // BB may be nullptr for post-dominator tree, map to 0. + } else + assert(BB && "dominator tree block must be non-null"); + return GraphTraits::getNumber(BB) + 1; } else { if (auto It = NodeNumberMap.find(BB); It != NodeNumberMap.end()) return It->second; diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp index 66850055ce21..da23af9c456a 100644 --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -12463,9 +12463,10 @@ bool ScalarEvolution::isImpliedCondOperandsViaAddRecStart( // Make sure AR varies in the context block. if (auto *AR = dyn_cast(FoundLHS)) { const Loop *L = AR->getLoop(); + const auto *Latch = L->getLoopLatch(); // Make sure that context belongs to the loop and executes on 1st iteration // (if it ever executes at all). - if (!L->contains(ContextBB) || !DT.dominates(ContextBB, L->getLoopLatch())) + if (!L->contains(ContextBB) || !Latch || !DT.dominates(ContextBB, Latch)) return false; if (!isAvailableAtLoopEntry(FoundRHS, AR->getLoop())) return false; @@ -12474,9 +12475,10 @@ bool ScalarEvolution::isImpliedCondOperandsViaAddRecStart( if (auto *AR = dyn_cast(FoundRHS)) { const Loop *L = AR->getLoop(); + const auto *Latch = L->getLoopLatch(); // Make sure that context belongs to the loop and executes on 1st iteration // (if it ever executes at all). - if (!L->contains(ContextBB) || !DT.dominates(ContextBB, L->getLoopLatch())) + if (!L->contains(ContextBB) || !Latch || !DT.dominates(ContextBB, Latch)) return false; if (!isAvailableAtLoopEntry(FoundLHS, AR->getLoop())) return false; diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp index 2383a0aa5c1f..97866783f62a 100644 --- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp +++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp @@ -28343,6 +28343,8 @@ bool SLPVectorizerPass::vectorizeGEPIndices(BasicBlock *BB, BoUpSLP &R) { const SCEV *SCEVI = SE->getSCEV(GEPList[I]); for (int J = I + 1; J < E && Candidates.size() > 1; ++J) { auto *GEPJ = GEPList[J]; + if (!Candidates.count(GEPJ)) + continue; const SCEV *SCEVJ = SE->getSCEV(GEPList[J]); if (isa(SE->getMinusSCEV(SCEVI, SCEVJ))) { Candidates.remove(GEPI); diff --git a/llvm/test/Analysis/ScalarEvolution/two-loop-latches.ll b/llvm/test/Analysis/ScalarEvolution/two-loop-latches.ll new file mode 100644 index 000000000000..a73ec292ea69 --- /dev/null +++ b/llvm/test/Analysis/ScalarEvolution/two-loop-latches.ll @@ -0,0 +1,58 @@ +; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 6 +; RUN: opt -disable-output -passes='print' < %s 2>&1 | FileCheck %s + +; Test where the outermost loop doesn't contain exactly one latch; +; ScalarEvolution shouldn't crash in this case. + +define void @f(ptr %a0) { +; CHECK-LABEL: 'f' +; CHECK-NEXT: Classifying expressions for: @f +; CHECK-NEXT: %phi1 = phi ptr [ null, %entry ], [ %inc, %b3 ], [ %inc, %b4 ] +; CHECK-NEXT: --> {null,+,-32}<%b1> U: [0,-31) S: [-9223372036854775808,9223372036854775777) Exits: <> LoopDispositions: { %b1: Computable, %b3: Invariant } +; CHECK-NEXT: %inc = getelementptr i8, ptr %phi1, i64 -32 +; CHECK-NEXT: --> {(-32 + null),+,-32}<%b1> U: [0,-31) S: [-9223372036854775808,9223372036854775777) Exits: <> LoopDispositions: { %b1: Computable, %b3: Invariant } +; CHECK-NEXT: %phi2 = phi ptr [ %a0, %b2 ], [ %inc2, %b5 ] +; CHECK-NEXT: --> {%a0,+,1}<%b3> U: full-set S: full-set Exits: ((-1 * (ptrtoint ptr %a0 to i64)) + %a0) LoopDispositions: { %b3: Computable, %b1: Variant } +; CHECK-NEXT: %ld1 = load i8, ptr %phi2, align 1 +; CHECK-NEXT: --> %ld1 U: full-set S: full-set Exits: <> LoopDispositions: { %b3: Variant, %b1: Variant } +; CHECK-NEXT: %ld2 = load i8, ptr null, align 1 +; CHECK-NEXT: --> %ld2 U: full-set S: full-set Exits: <> LoopDispositions: { %b3: Variant, %b1: Variant } +; CHECK-NEXT: %inc2 = getelementptr i8, ptr %phi2, i64 1 +; CHECK-NEXT: --> {(1 + %a0),+,1}<%b3> U: full-set S: full-set Exits: (1 + (-1 * (ptrtoint ptr %a0 to i64)) + %a0) LoopDispositions: { %b3: Computable, %b1: Variant } +; CHECK-NEXT: Determining loop execution counts for: @f +; CHECK-NEXT: Loop %b3: backedge-taken count is (-1 * (ptrtoint ptr %a0 to i64)) +; CHECK-NEXT: exit count for b3: (-1 * (ptrtoint ptr %a0 to i64)) +; CHECK-NEXT: exit count for b4: ***COULDNOTCOMPUTE*** +; CHECK-NEXT: Loop %b3: constant max backedge-taken count is i64 -1 +; CHECK-NEXT: Loop %b3: symbolic max backedge-taken count is (-1 * (ptrtoint ptr %a0 to i64)) +; CHECK-NEXT: symbolic max exit count for b3: (-1 * (ptrtoint ptr %a0 to i64)) +; CHECK-NEXT: symbolic max exit count for b4: ***COULDNOTCOMPUTE*** +; CHECK-NEXT: Loop %b3: Trip multiple is 1 +; CHECK-NEXT: Loop %b1: Unpredictable backedge-taken count. +; CHECK-NEXT: Loop %b1: Unpredictable constant max backedge-taken count. +; CHECK-NEXT: Loop %b1: Unpredictable symbolic max backedge-taken count. +; +entry: + br label %b1 +b1: + %phi1 = phi ptr [ null, %entry ], [ %inc, %b3 ], [ %inc, %b4 ] + %cmp1 = icmp eq ptr %phi1, null + br i1 %cmp1, label %ret, label %b2 +b2: + %inc = getelementptr i8, ptr %phi1, i64 -32 + br label %b3 +b3: + %phi2 = phi ptr [ %a0, %b2 ], [ %inc2, %b5 ] + %cmp2 = icmp eq ptr %phi2, null + br i1 %cmp2, label %b1, label %b4 +b4: + %ld1 = load i8, ptr %phi2, align 1 + %ld2 = load i8, ptr null, align 1 + %cmp3 = icmp slt i8 %ld1, %ld2 + br i1 false, label %b1, label %b5 +b5: + %inc2 = getelementptr i8, ptr %phi2, i64 1 + br label %b3 +ret: + ret void +} diff --git a/polly/lib/Analysis/ScopBuilder.cpp b/polly/lib/Analysis/ScopBuilder.cpp index 1ea9a554f761..f4d654fa74cb 100644 --- a/polly/lib/Analysis/ScopBuilder.cpp +++ b/polly/lib/Analysis/ScopBuilder.cpp @@ -637,7 +637,7 @@ void ScopBuilder::propagateDomainConstraintsToRegionExit( auto *RI = scop->getRegion().getRegionInfo(); auto *BBReg = RI ? RI->getRegionFor(BB) : nullptr; auto *ExitBB = BBReg ? BBReg->getExit() : nullptr; - if (!BBReg || BBReg->getEntry() != BB || !scop->contains(ExitBB)) + if (!BBReg || BBReg->getEntry() != BB || !ExitBB || !scop->contains(ExitBB)) return; // Do not propagate the domain if there is a loop backedge inside the region