Skip to content

[LoopSimplifyCFG] Add check for missing loop preheader #149743

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 22, 2025

Conversation

Justus2308
Copy link
Contributor

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).

Copy link

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot
Copy link
Member

llvmbot commented Jul 20, 2025

@llvm/pr-subscribers-llvm-transforms

Author: Justus Klausecker (Justus2308)

Changes

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).


Full diff: https://github.com/llvm/llvm-project/pull/149743.diff

2 Files Affected:

  • (modified) llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp (+19)
  • (added) llvm/test/Transforms/LoopSimplifyCFG/enter-through-indirectbr.ll (+16)
diff --git a/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp b/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp
index 221094f170ac7..c63578c63e8be 100644
--- a/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp
@@ -128,6 +128,8 @@ class ConstantTerminatorFoldingImpl {
   // 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,17 @@ class ConstantTerminatorFoldingImpl {
       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 +559,12 @@ class ConstantTerminatorFoldingImpl {
       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(
diff --git a/llvm/test/Transforms/LoopSimplifyCFG/enter-through-indirectbr.ll b/llvm/test/Transforms/LoopSimplifyCFG/enter-through-indirectbr.ll
new file mode 100644
index 0000000000000..bf1b6a70e6c35
--- /dev/null
+++ b/llvm/test/Transforms/LoopSimplifyCFG/enter-through-indirectbr.ll
@@ -0,0 +1,16 @@
+; 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() {
+; CHECK-LABEL: @test(
+
+  indirectbr ptr null, [label %A, label %C]
+
+A:
+  br i1 true, label %B, label %C
+
+B:
+  br i1 true, label %A, label %C
+
+C:
+  unreachable
+}

@Justus2308
Copy link
Contributor Author

Requesting review from @nikic
Thanks in advance!

@Justus2308
Copy link
Contributor Author

Related: ziglang/zig#24383

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Justus2308 Justus2308 requested a review from nikic July 21, 2025 16:18
Copy link

github-actions bot commented Jul 21, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

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).
@Justus2308 Justus2308 force-pushed the loop-simplifycfg-preheader-null-deref branch from b97c1d1 to 53a43f8 Compare July 22, 2025 11:53
@Justus2308
Copy link
Contributor Author

Justus2308 commented Jul 22, 2025

I rebased on top of a more recent commit with passing ci, hopefully this will fix the test failures. I don't really know what I'm looking at in the logs, some lldb tests are triggering an assertion in llvm/include/llvm/Support/YAMLTraits.h that seems to be unrelated to my changes. If this doesn't work I'll ask for help on discord.

@nikic nikic merged commit 0410720 into llvm:main Jul 22, 2025
9 checks passed
@nikic nikic added this to the LLVM 21.x Release milestone Jul 22, 2025
@github-project-automation github-project-automation bot moved this to Needs Triage in LLVM Release Status Jul 22, 2025
Copy link

@Justus2308 Congratulations on having your first Pull Request (PR) merged into the LLVM Project!

Your changes will be combined with recent changes from other authors, then tested by our build bots. If there is a problem with a build, you may receive a report in an email or a comment on this PR.

Please check whether problems have been caused by your change specifically, as the builds can include changes from many authors. It is not uncommon for your change to be included in a build that fails due to someone else's changes, or infrastructure issues.

How to do this, and the rest of the post-merge process, is covered in detail here.

If your change does cause a problem, it may be reverted, or you can revert it yourself. This is a normal part of LLVM development. You can fix your changes and open a new PR to merge them again.

If you don't get any reports, no action is required from you. Your changes are working as expected, well done!

@nikic
Copy link
Contributor

nikic commented Jul 22, 2025

/cherry-pick 0410720

@llvmbot
Copy link
Member

llvmbot commented Jul 22, 2025

/pull-request #150026

@llvmbot llvmbot moved this from Needs Triage to Done in LLVM Release Status Jul 22, 2025
tru pushed a commit to llvmbot/llvm-project that referenced this pull request Jul 24, 2025
Closes llvm#147869
Closes llvm#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 0410720)
mahesh-attarde pushed a commit to mahesh-attarde/llvm-project that referenced this pull request Jul 28, 2025
Closes llvm#147869
Closes llvm#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).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

Successfully merging this pull request may close these issues.

[LoopSimplifyCFG] null Preheader deref loop-simplifycfg optimisation pass segfault
3 participants