Bug type: hang
Component: InstCombine
Bug location: llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp: InstCombinerImpl::foldSelectValueEquivalence
Issue title: [InstCombine] Infinite loop at -O3
Labels: llvm:instcombine
hang
generated by fuzzer
Reported by: dtcxzyw

Reproducer: https://godbolt.org/z/aYWhfr6Y9
```
; bin/opt -passes=instcombine test.ll -S
define i32 @test(i32 noundef %0) {
entry:
  %cond.i = call i32 @llvm.smax.i32(i32 %0, i32 0)
  %conv.i = trunc i32 %cond.i to i16
  %conv21 = zext i16 %conv.i to i32
  %cmp22 = icmp eq i32 %0, %conv21
  %conv23 = zext i1 %cmp22 to i32
  %narrow.i = mul i32 %cond.i, %conv23
  %1 = and i32 %narrow.i, 1
  ret i32 %1
}
```



Fix patch:
commit 5e2dcfe42cd4af14d6e6155314aa5d4167710b65
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Wed Jun 4 19:42:56 2025 +0800

    [InstCombine] Avoid infinite loop in `foldSelectValueEquivalence` (#142754)
    
    Before this patch, InstCombine hung because it replaced a value with a
    more complex one:
    ```
    %sel = select i1 %cmp, i32 %smax, i32 0 ->
    %sel = select i1 %cmp, i32 %masked, i32 0 ->
    %sel = select i1 %cmp, i32 %smax, i32 0 ->
    ...
    ```
    This patch makes this replacement more conservative. It only performs
    the replacement iff the new value is one of the operands of the original
    value.
    
    Closes https://github.com/llvm/llvm-project/issues/142405.

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index d7d0431a5b8d..257dc943bd5c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1312,7 +1312,11 @@ Instruction *InstCombinerImpl::foldSelectValueEquivalence(SelectInst &Sel,
 
       // If NewOp is a constant and OldOp is not replace iff NewOp doesn't
       // contain and undef elements.
-      if (match(NewOp, m_ImmConstant()) || NewOp == V) {
+      // Make sure that V is always simpler than TrueVal, otherwise we might
+      // end up in an infinite loop.
+      if (match(NewOp, m_ImmConstant()) ||
+          (isa<Instruction>(TrueVal) &&
+           is_contained(cast<Instruction>(TrueVal)->operands(), V))) {
         if (isGuaranteedNotToBeUndef(NewOp, SQ.AC, &Sel, &DT))
           return replaceOperand(Sel, Swapped ? 2 : 1, V);
         return nullptr;


Regression tests:
file: llvm/test/Transforms/InstCombine/select-cmp-eq-op-fold.ll
commands: opt < %s -passes=instcombine -S
tests: test_name: replace_with_y_for_simple_binop_fail
test_body: define i8 @replace_with_y_for_simple_binop_fail(i8 %x, i8 noundef %y, i8 %z, i8 %q) {
  %cmp = icmp eq i8 %x, %y
  %mul = mul nsw i8 %x, %q
  %sel = select i1 %cmp, i8 %mul, i8 %z
  ret i8 %sel
}

test_name: pr142405
test_body: define i32 @pr142405(i32 noundef %x) {
entry:
  %smax = call i32 @llvm.smax.i32(i32 %x, i32 0)
  %masked = and i32 %smax, 65535
  %cmp = icmp eq i32 %x, %masked
  %sel = select i1 %cmp, i32 %smax, i32 0
  %and = and i32 %sel, 1
  ret i32 %and
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.smax.i32(i32, i32) #0

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }