[llvm] [InstCombine] Don't sink freeze when the operand has other uses (PR #219110)

via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 26 21:52:41 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: junfengd-nv

<details>
<summary>Changes</summary>

Fixes #<!-- -->219102

InstCombine can infinite-loop on a `freeze` whose operand has other uses.
`tryToSinkInstruction` sinks the freeze into a unique-successor user block,
then `visitFreeze` -> `freezeOtherUses` moves it back to the operand
definition. If those extra uses are never rewritten (the freeze still does
not dominate them), the two transforms ping-pong forever.
`opt -debug-only=instcombine` shows the same instruction repeatedly:


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


2 Files Affected:

- (modified) llvm/lib/Transforms/InstCombine/InstructionCombining.cpp (+7) 
- (added) llvm/test/Transforms/InstCombine/freeze-sink.ll (+46) 


``````````diff
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index b877f79a000cf..189c75edaadd2 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -5575,6 +5575,13 @@ bool InstCombinerImpl::tryToSinkInstruction(Instruction *I,
   if (isa<AllocaInst>(I))
     return false;
 
+  // Don't sink a freeze if its operand has other uses. freezeOtherUses moves
+  // the freeze up to the operand definition so it can replace those uses;
+  // sinking it back down fights that and can infinite-loop when some uses
+  // (e.g. a phi of an invoke result on the normal edge) are never replaced.
+  if (isa<FreezeInst>(I) && !I->getOperand(0)->hasOneUse())
+    return false;
+
   // Do not sink into catchswitch blocks.
   if (isa<CatchSwitchInst>(DestBlock->getTerminator()))
     return false;
diff --git a/llvm/test/Transforms/InstCombine/freeze-sink.ll b/llvm/test/Transforms/InstCombine/freeze-sink.ll
new file mode 100644
index 0000000000000..c8a867e915fac
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/freeze-sink.ll
@@ -0,0 +1,46 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+declare ptr @get()
+declare void @escape(ptr)
+declare i32 @__gxx_personality_v0(...)
+
+; The invoke result is used by a phi on the normal destination. freezeOtherUses
+; cannot replace that use (the freeze sits after the phis), but sinking would
+; still move the freeze into %use. Those two transforms ping-ponged forever.
+define void @dont_sink_freeze_of_invoke_used_by_phi(i1 %c, ptr %other) personality ptr @__gxx_personality_v0 {
+; CHECK-LABEL: define void @dont_sink_freeze_of_invoke_used_by_phi(
+; CHECK-SAME: i1 [[C:%.*]], ptr [[OTHER:%.*]]) personality ptr @__gxx_personality_v0 {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[P:%.*]] = invoke ptr @get()
+; CHECK-NEXT:            to label %[[JOIN:.*]] unwind label %[[LPAD:.*]]
+; CHECK:       [[JOIN]]:
+; CHECK-NEXT:    [[PHI:%.*]] = phi ptr [ [[P]], %[[ENTRY]] ], [ [[OTHER]], %[[JOIN]] ]
+; CHECK-NEXT:    [[FR:%.*]] = freeze ptr [[P]]
+; CHECK-NEXT:    br i1 [[C]], label %[[USE:.*]], label %[[JOIN]]
+; CHECK:       [[USE]]:
+; CHECK-NEXT:    call void @escape(ptr [[FR]])
+; CHECK-NEXT:    call void @escape(ptr [[PHI]])
+; CHECK-NEXT:    ret void
+; CHECK:       [[LPAD]]:
+; CHECK-NEXT:    [[LP:%.*]] = landingpad { ptr, i32 }
+; CHECK-NEXT:            cleanup
+; CHECK-NEXT:    ret void
+;
+entry:
+  %p = invoke ptr @get() to label %join unwind label %lpad
+
+join:
+  %phi = phi ptr [ %p, %entry ], [ %other, %join ]
+  %fr = freeze ptr %p
+  br i1 %c, label %use, label %join
+
+use:
+  call void @escape(ptr %fr)
+  call void @escape(ptr %phi)
+  ret void
+
+lpad:
+  %lp = landingpad { ptr, i32 } cleanup
+  ret void
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/219110


More information about the llvm-commits mailing list