Bug type: crash
Component: LoopUnrollRuntime
Bug location: llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp: probOfNextInRemainder
Issue title: lld crash: Running pass "loop-unroll<O2>" on function "svt_dav1d_highbd_inv_txfm_add_avx2"
Labels: crash-on-valid
llvm:transforms
Reported by: Andarwinux

PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace and instructions to reproduce the bug.
Stack dump:
0.      Running pass "function<eager-inv>(drop-unnecessary-assumes,float2int,lower-constant-intrinsics,loop(loop-rotate<header-duplication;no-prepare-for-lto>,loop-deletion),loop-distribute,inject-tli-mappings,loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,infer-alignment,loop-load-elim,instcombine<max-iterations=1;no-verify-fixpoint>,simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-arithmetic;switch-to-lookup;no-keep-loops;hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,vector-combine,instcombine<max-iterations=1;no-verify-fixpoint>,loop-unroll<O2>,transform-warning,sroa<preserve-cfg>,infer-alignment,instcombine<max-iterations=1;no-verify-fixpoint>,loop-mssa(licm<allowspeculation>),alignment-from-assumptions,loop-sink,instsimplify,div-rem-pairs,tailcallelim,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;switch-to-arithmetic;no-switch-to-lookup;keep-loops;no-hoist-common-insts;hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;speculate-unpredictables>)" on module "build/packages/svtav1-psy-prefix/src/svtav1-psy-build/libSvtAv1Enc.ahighbd_inv_txfm_avx2.c.obj18483466"
1.      Running pass "loop-unroll<O2>" on function "svt_dav1d_highbd_inv_txfm_add_avx2"
#0 0x000059ef412cccae PrintStackTraceSignalHandler(void*) (.llvm.12027265274519014927) Signals.cpp:0:0
Floating point exception   (core dumped) /build/install/llvmbin/lld-link @response.txt

[crash.zip](https://github.com/user-attachments/files/23283657/crash.zip)

Comments: author: Andarwinux
body: [crash2.zip](https://github.com/user-attachments/files/23289213/crash2.zip)

still crash with -mllvm -pgso=false -mllvm -unroll-runtime-multi-exit after https://github.com/llvm/llvm-project/pull/165938
author: Andarwinux
body: [crash3.tar.7z.zip](https://github.com/user-attachments/files/23289408/crash3.tar.7z.zip) (rename to 7z)
still crash with -mllvm -pgso=false after https://github.com/llvm/llvm-project/pull/165938
author: Andarwinux
body: https://github.com/llvm/llvm-project/issues/166092 seems to be caused by the same reason, but has a simpler reproducer.
author: jdenny-ornl
body: How do I reproduce this bug? I didn't find any instructions.
author: jdenny-ornl
body: Never mind.  I found the cause and will post a fix today.
author: Andarwinux
body: > How do I reproduce this bug? I didn't find any instructions.

To reproduce this issue, unzip the reproducer, then enter the directory same as response.txt and run lld-link @response.txt.

> Never mind. I found the cause and will post a fix today.

Thanks!
author: jdenny-ornl
body: PR #166258 fixes it for me.
author: Andarwinux
body: > PR [#166258](https://github.com/llvm/llvm-project/pull/166258) fixes it for me.

Thanks! I can confirm the problem has been fixed.

Fix patch:
commit 1aa86ca521b8fea5ff728945d5ea5cdef97a6250
Author: Joel E. Denny <jdenny.ornl@gmail.com>
Date:   Tue Nov 4 12:49:33 2025 -0500

    [LoopUnroll] Fix division by zero (#166258)
    
    PR #159163's probability computation for epilogue loops does not handle
    the possibility of an original loop probability of one. Runtime loop
    unrolling does not make sense for such an infinite loop, and a division
    by zero results. This patch works around that case.
    
    Issue #165998.

diff --git a/llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp b/llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp
index 1e8f6cc76900..6c9467bf4a00 100644
--- a/llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp
+++ b/llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp
@@ -202,6 +202,27 @@ static void ConnectProlog(Loop *L, Value *BECount, unsigned Count,
 /// probability of executing at least one more iteration?
 static BranchProbability
 probOfNextInRemainder(BranchProbability OriginalLoopProb, unsigned N) {
+  // OriginalLoopProb == 1 would produce a division by zero in the calculation
+  // below.  The problem is that case indicates an always infinite loop, but a
+  // remainder loop cannot be calculated at run time if the original loop is
+  // infinite as infinity % UnrollCount is undefined.  We then choose
+  // probabilities indicating that all remainder loop iterations will always
+  // execute.
+  //
+  // Currently, the remainder loop here is an epilogue, which cannot be reached
+  // if the original loop is infinite, so the aforementioned choice is
+  // arbitrary.
+  //
+  // FIXME: Branch weights still need to be fixed in the case of prologues
+  // (issue #135812).  In that case, the aforementioned choice seems reasonable
+  // for the goal of maintaining the original loop's block frequencies.  That
+  // is, an infinite loop's initial iterations are not skipped, and the prologue
+  // loop body might have unique blocks that execute a finite number of times
+  // if, for example, the original loop body contains conditionals like i <
+  // UnrollCount.
+  if (OriginalLoopProb == BranchProbability::getOne())
+    return BranchProbability::getOne();
+
   // Each of these variables holds the original loop's probability that the
   // number of iterations it will execute is some m in the specified range.
   BranchProbability ProbOne = OriginalLoopProb;                // 1 <= m


Regression tests:
file: llvm/test/Transforms/LoopUnroll/loop-probability-one.ll
commands: opt < %s -unroll-count=3 -passes=loop-unroll -unroll-runtime -unroll-runtime-epilog=true -S
opt < %s -unroll-count=3 -passes=loop-unroll -unroll-runtime -unroll-runtime-epilog=false -S
tests: test_name: <module>
test_body: ; Check that a loop probability of one (indicating an always infinite loop) does
; not crash or otherwise break LoopUnroll behavior when it tries to compute new
; probabilities from it.
;
; That case indicates an always infinite loop.  A remainder loop cannot be
; calculated at run time when the original loop is infinite as infinity %
; UnrollCount is undefined, so consistent remainder loop probabilities are
; difficult or impossible to reason about.  The implementation chooses
; probabilities indicating that all remainder loop iterations will always
; execute.

; DEFINE: %{unroll} = opt < %s -unroll-count=3 -passes=loop-unroll -S
; DEFINE: %{rt} = %{unroll} -unroll-runtime


define void @test(i32 %n) {
entry:
  br label %loop

loop:
  %i = phi i32 [ 0, %entry ], [ %inc, %loop ]
  %inc = add i32 %i, 1
  %c = icmp slt i32 %inc, %n
  br i1 %c, label %loop, label %end, !prof !0

end:
  ret void
}


!0 = !{!"branch_weights", i32 1, i32 0}

; UNROLL: define void @test(i32 %n) {
; UNROLL: entry:
; UNROLL:   br label %loop
; UNROLL: loop:
; UNROLL:   br i1 %c, label %loop.1, label %end, !prof !0
; UNROLL: loop.1:
; UNROLL:   br i1 %c.1, label %loop.2, label %end, !prof !0
; UNROLL: loop.2:
; UNROLL:   br i1 %c.2, label %loop, label %end, !prof !0, !llvm.loop !1
; UNROLL-NOT: loop.3
; UNROLL: end:
; UNROLL:   ret void
; UNROLL: }
;
; Infinite unrolled loop.
; UNROLL: !0 = !{!"branch_weights", i32 1, i32 0}

; EPILOG: define void @test(i32 %n) {
; EPILOG: entry:
; EPILOG:   br i1 %{{.*}}, label %loop.epil.preheader, label %entry.new, !prof !0
; EPILOG: entry.new:
; EPILOG:   br label %loop
; EPILOG: loop:
; EPILOG:   br i1 %{{.*}}, label %loop, label %end.unr-lcssa, !prof !1
; EPILOG: end.unr-lcssa:
; EPILOG:   br i1 %{{.*}}, label %loop.epil.preheader, label %end, !prof !1
; EPILOG: loop.epil.preheader:
; EPILOG:   br label %loop.epil
; EPILOG: loop.epil:
; EPILOG:   br i1 %{{.*}}, label %loop.epil, label %end.epilog-lcssa, !prof !4
; EPILOG: end.epilog-lcssa:
; EPILOG:   br label %end
; EPILOG: end:
; EPILOG:   ret void
; EPILOG: }
;
; Unrolled loop guard: Unrolled loop is always entered.
; EPILOG: !0 = !{!"branch_weights", i32 0, i32 -2147483648}
;
; Unrolled loop latch: Unrolled loop is infinite.
; Epilogue loop guard: Epilogue loop is always entered if unrolled loop exits.
; EPILOG: !1 = !{!"branch_weights", i32 -2147483648, i32 0}
;
; Epilogue loop latch: Epilogue loop executes both of its 2 iterations.
; EPILOG: !4 = !{!"branch_weights", i32 1073741824, i32 1073741824}

; PROLOG: define void @test(i32 %n) {
; PROLOG: entry:
; PROLOG:   br i1 %{{.*}}, label %loop.prol.preheader, label %loop.prol.loopexit, !prof !0
; PROLOG: loop.prol.preheader:
; PROLOG:   br label %loop.prol
; PROLOG: loop.prol:
; PROLOG:   br i1 %{{.*}}, label %loop.prol, label %loop.prol.loopexit.unr-lcssa, !prof !1
; PROLOG: loop.prol.loopexit.unr-lcssa:
; PROLOG:   br label %loop.prol.loopexit
; PROLOG: loop.prol.loopexit:
; PROLOG:   br i1 %{{.*}}, label %end, label %entry.new, !prof !0
; PROLOG: entry.new:
; PROLOG:   br label %loop
; PROLOG: loop:
; PROLOG:   br i1 %{{.*}}, label %loop, label %end.unr-lcssa, !prof !4
; PROLOG: end.unr-lcssa:
; PROLOG:   br label %end
; PROLOG: end:
; PROLOG:   ret void
; PROLOG: }
;
; FIXME: Branch weights still need to be fixed in the case of prologues (issue
; #135812), so !0 and !1 do not yet match their comments below.  When we do
; fix it, this test will hopefully catch any bug like issue #165998, which
; impacted the case of epilogues.
;
; Prologue loop guard: Prologue loop is always entered.
; Unrolled loop guard: Unrolled loop is always entered.
; PROLOG: !0 = !{!"branch_weights", i32 1, i32 127}
;
; Prologue loop latch: Prologue loop executes both of its 2 iterations.
; PROLOG: !1 = !{!"branch_weights", i32 0, i32 1}
;
; Unrolled loop latch: Unrolled loop is infinite.
; PROLOG: !4 = !{!"branch_weights", i32 1, i32 0}