[LoopSimplifyCFG] Add check for missing loop preheader (#149743)

Closes #147869
Closes #149679

Adds a check for a missing loop preheader during analysis. This fixes a
nullptr dereference that happened whenever LoopSimplify was unable to
generate a preheader because the loop was entered by an indirectbr
instruction (as stated in the LoopSimplify.cpp doc comment).

(cherry picked from commit 04107209856bb39e041aa38cf40de0afa90a6b2d)
This commit is contained in:
Justus Klausecker 2025-07-22 16:01:49 +02:00 committed by Tobias Hieta
parent 233fdcb395
commit f66e874504
2 changed files with 49 additions and 0 deletions

View File

@ -128,6 +128,8 @@ private:
// from any other block. So this variable set to true means that loop's latch
// has become unreachable from loop header.
bool DeleteCurrentLoop = false;
// Whether or not we enter the loop through an indirectbr.
bool HasIndirectEntry = false;
// The blocks of the original loop that will still be reachable from entry
// after the constant folding.
@ -216,6 +218,19 @@ private:
return;
}
// We need a loop preheader to split in handleDeadExits(). If LoopSimplify
// wasn't able to form one because the loop can be entered through an
// indirectbr we cannot continue.
if (!L.getLoopPreheader()) {
assert(any_of(predecessors(L.getHeader()),
[&](BasicBlock *Pred) {
return isa<IndirectBrInst>(Pred->getTerminator());
}) &&
"Loop should have preheader if it is not entered indirectly");
HasIndirectEntry = true;
return;
}
// Collect live and dead loop blocks and exits.
LiveLoopBlocks.insert(L.getHeader());
for (auto I = DFS.beginRPO(), E = DFS.endRPO(); I != E; ++I) {
@ -546,6 +561,12 @@ public:
return false;
}
if (HasIndirectEntry) {
LLVM_DEBUG(dbgs() << "Loops which can be entered indirectly are not"
" supported!\n");
return false;
}
// Nothing to constant-fold.
if (FoldCandidates.empty()) {
LLVM_DEBUG(

View File

@ -0,0 +1,28 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -S -enable-loop-simplifycfg-term-folding=true -passes='require<domtree>,loop(loop-simplifycfg)' -verify-loop-info -verify-dom-info -verify-loop-lcssa < %s | FileCheck %s
define void @test(ptr %addr) {
; CHECK-LABEL: define void @test(
; CHECK-SAME: ptr [[ADDR:%.*]]) {
; CHECK-NEXT: indirectbr ptr [[ADDR]], [label %[[A:.*]], label %C]
; CHECK: [[A]]:
; CHECK-NEXT: br i1 true, label %[[B:.*]], label %[[C_LOOPEXIT:.*]]
; CHECK: [[B]]:
; CHECK-NEXT: br i1 true, label %[[A]], label %[[C_LOOPEXIT]]
; CHECK: [[C_LOOPEXIT]]:
; CHECK-NEXT: br label %[[C:.*]]
; CHECK: [[C]]:
; CHECK-NEXT: unreachable
;
indirectbr ptr %addr, [label %A, label %C]
A:
br i1 true, label %B, label %C
B:
br i1 true, label %A, label %C
C:
unreachable
}