Skip to content

[CodeGen] Fix ShrinkWrap crash when FindIDom receives empty predecessor/successor list#198995

Merged
Michael-Chen-NJU merged 2 commits into
llvm:mainfrom
Michael-Chen-NJU:fix-shrinkwrap-empty-predecessors
Jun 3, 2026
Merged

[CodeGen] Fix ShrinkWrap crash when FindIDom receives empty predecessor/successor list#198995
Michael-Chen-NJU merged 2 commits into
llvm:mainfrom
Michael-Chen-NJU:fix-shrinkwrap-empty-predecessors

Conversation

@Michael-Chen-NJU
Copy link
Copy Markdown
Contributor

When using -msave-restore with -ffixed-x5 on RISC-V, canUseAsPrologue returns false for all blocks because the save-restore prologue requires t0 (x5) which is reserved. This causes the shrink-wrap loop to keep searching for a valid save point, eventually reaching the entry block. On the next iteration, it calls FindIDom with the entry block's empty predecessor list, triggering an assertion in findNearestCommonDominator.

Fix by returning nullptr from FindIDom when the block list is empty, which signals the caller to stop searching and give up the optimization.

Fixes #166759

@llvmorg-github-actions
Copy link
Copy Markdown

@llvm/pr-subscribers-backend-risc-v

Author: 陈子昂 (Michael-Chen-NJU)

Changes

When using -msave-restore with -ffixed-x5 on RISC-V, canUseAsPrologue returns false for all blocks because the save-restore prologue requires t0 (x5) which is reserved. This causes the shrink-wrap loop to keep searching for a valid save point, eventually reaching the entry block. On the next iteration, it calls FindIDom with the entry block's empty predecessor list, triggering an assertion in findNearestCommonDominator.

Fix by returning nullptr from FindIDom when the block list is empty, which signals the caller to stop searching and give up the optimization.

Fixes #166759


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

2 Files Affected:

  • (modified) llvm/lib/CodeGen/ShrinkWrap.cpp (+2)
  • (added) llvm/test/CodeGen/RISCV/shrinkwrap-save-restore-fixed-reg.ll (+38)
diff --git a/llvm/lib/CodeGen/ShrinkWrap.cpp b/llvm/lib/CodeGen/ShrinkWrap.cpp
index ff71bb07dab05..faa93f5abac3d 100644
--- a/llvm/lib/CodeGen/ShrinkWrap.cpp
+++ b/llvm/lib/CodeGen/ShrinkWrap.cpp
@@ -384,6 +384,8 @@ bool ShrinkWrapImpl::useOrDefCSROrFI(const MachineInstr &MI, RegScavenger *RS,
 template <typename ListOfBBs, typename DominanceAnalysis>
 static MachineBasicBlock *FindIDom(MachineBasicBlock &Block, ListOfBBs BBs,
                                    DominanceAnalysis &Dom, bool Strict = true) {
+  if (BBs.begin() == BBs.end())
+    return nullptr;
   MachineBasicBlock *IDom = Dom.findNearestCommonDominator(iterator_range(BBs));
   if (Strict && IDom == &Block)
     return nullptr;
diff --git a/llvm/test/CodeGen/RISCV/shrinkwrap-save-restore-fixed-reg.ll b/llvm/test/CodeGen/RISCV/shrinkwrap-save-restore-fixed-reg.ll
new file mode 100644
index 0000000000000..2f51014c36742
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/shrinkwrap-save-restore-fixed-reg.ll
@@ -0,0 +1,38 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv64 -mattr=+save-restore,+reserve-x5 -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s
+
+; This test verifies that the shrink-wrap pass does not crash when the save
+; point reaches the entry block (which has no predecessors) while trying to find
+; a cheaper save point via FindIDom.
+
+@a = global i32 0, align 4
+
+define signext i32 @shrinkwrap_entry_no_preds() {
+; CHECK-LABEL: shrinkwrap_entry_no_preds:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    call t0, __riscv_save_0
+; CHECK-NEXT:    .cfi_def_cfa_offset 16
+; CHECK-NEXT:    .cfi_offset ra, -8
+; CHECK-NEXT:    lui a0, %hi(a)
+; CHECK-NEXT:    lw a0, %lo(a)(a0)
+; CHECK-NEXT:    beqz a0, .LBB0_2
+; CHECK-NEXT:  # %bb.1: # %if.then
+; CHECK-NEXT:    call b
+; CHECK-NEXT:  .LBB0_2: # %if.end
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    tail __riscv_restore_0
+entry:
+  %0 = load i32, ptr @a, align 4
+  %tobool.not = icmp eq i32 %0, 0
+  br i1 %tobool.not, label %if.end, label %if.then
+
+if.then:
+  tail call void @b()
+  br label %if.end
+
+if.end:
+  ret i32 0
+}
+
+declare void @b()

@Michael-Chen-NJU
Copy link
Copy Markdown
Contributor Author

ping.

@wangpc-pp wangpc-pp requested review from enoskova-sc, lenary, mgudim and svs-quic and removed request for enoskova-sc May 29, 2026 06:24
Comment thread llvm/lib/CodeGen/ShrinkWrap.cpp
…or/successor list

When using -msave-restore with -ffixed-x5 on RISC-V, canUseAsPrologue
returns false for all blocks because the save-restore prologue requires
t0 (x5) which is reserved. This causes the shrink-wrap loop to keep
searching for a valid save point, eventually reaching the entry block.
On the next iteration, it calls FindIDom with the entry block's empty
predecessor list, triggering an assertion in findNearestCommonDominator.

Fix by returning nullptr from FindIDom when the block list is empty,
which signals the caller to stop searching and give up the optimization.

Fixes llvm#166759
@Michael-Chen-NJU Michael-Chen-NJU force-pushed the fix-shrinkwrap-empty-predecessors branch from fd37907 to 1f475b8 Compare June 2, 2026 02:38
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 2, 2026

🪟 Windows x64 Test Results

  • 135308 tests passed
  • 3345 tests skipped

✅ The build succeeded and all tests passed.

Copy link
Copy Markdown
Contributor

@enoskova-sc enoskova-sc left a comment

Choose a reason for hiding this comment

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

LGTM.

@Michael-Chen-NJU Michael-Chen-NJU merged commit fb6153a into llvm:main Jun 3, 2026
10 checks passed
@Michael-Chen-NJU Michael-Chen-NJU deleted the fix-shrinkwrap-empty-predecessors branch June 3, 2026 10:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[RISCV] Crashed at -O1: Assertion `!Nodes.empty() && "Nodes list is empty!"' failed.

2 participants