Reland "[DomTree] Assert non-null block for pre-dom tree" (#187005)

Reland #186790 with fix for SCEV. A loop can have more than one latch,
in which case getLoopLatch returns null.
This commit is contained in:
Alexis Engelke 2026-03-17 15:10:04 +01:00 committed by GitHub
parent 0f1ec17f29
commit 43ec60eee5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 71 additions and 5 deletions

View File

@ -384,11 +384,15 @@ protected:
private:
std::optional<unsigned> getNodeIndex(const NodeT *BB) const {
if constexpr (GraphHasNodeNumbers<NodeT *>) {
// BB can be nullptr, map nullptr to index 0.
assert(BlockNumberEpoch ==
GraphTraits<ParentPtr>::getNumberEpoch(Parent) &&
"dominator tree used with outdated block numbers");
return BB ? GraphTraits<const NodeT *>::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<const NodeT *>::getNumber(BB) + 1;
} else {
if (auto It = NodeNumberMap.find(BB); It != NodeNumberMap.end())
return It->second;

View File

@ -12463,9 +12463,10 @@ bool ScalarEvolution::isImpliedCondOperandsViaAddRecStart(
// Make sure AR varies in the context block.
if (auto *AR = dyn_cast<SCEVAddRecExpr>(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<SCEVAddRecExpr>(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;

View File

@ -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<SCEVConstant>(SE->getMinusSCEV(SCEVI, SCEVJ))) {
Candidates.remove(GEPI);

View File

@ -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<scalar-evolution>' < %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: <<Unknown>> LoopDispositions: { %b1: Computable, %b3: Invariant }
; CHECK-NEXT: %inc = getelementptr i8, ptr %phi1, i64 -32
; CHECK-NEXT: --> {(-32 + null)<nuw><nsw>,+,-32}<%b1> U: [0,-31) S: [-9223372036854775808,9223372036854775777) Exits: <<Unknown>> 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: <<Unknown>> LoopDispositions: { %b3: Variant, %b1: Variant }
; CHECK-NEXT: %ld2 = load i8, ptr null, align 1
; CHECK-NEXT: --> %ld2 U: full-set S: full-set Exits: <<Unknown>> 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: <multiple exits> 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
}

View File

@ -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