Bug type: miscompilation
Component: InstCombine
Bug location: llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp: InstCombinerImpl::visitSelectInst
Issue title: [InstCombine] ninf should not be propagated
Labels: miscompilation
llvm:instcombine
floating-point
Reported by: dtcxzyw

Reproducer: https://alive2.llvm.org/ce/z/cmneUX
```
define half @test_fcmp_select_maxnum(half %x) {
#0:
  %cmp2 = fcmp ogt half %x, 0x5bf8
  %sel2 = select nnan ninf nsz i1 %cmp2, half %x, half 0x5bf8
  ret half %sel2
}
=>
define half @test_fcmp_select_maxnum(half %x) {
#0:
  %sel2 = fmax ninf nsz half %x, 0x5bf8
  ret half %sel2
}
Transformation doesn't verify!

ERROR: Target is more poisonous than source

Example:
half %x = #xfc00 (-oo)

Source:
i1 %cmp2 = #x0 (0)
half %sel2 = #x5bf8 (255)

Target:
half %sel2 = poison
Source value: #x5bf8 (255)
Target value: poison

Summary:
  0 correct transformations
  1 incorrect transformations
  0 failed-to-prove transformations
  0 Alive2 errors
```


Fix patch:
commit a0c4876eede8e68de22dc5296b037556c7cca981
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Mon Apr 28 17:24:46 2025 +0800

    [InstCombine] Fix ninf propagation for fcmp+sel -> minmax (#136433)
    
    Proof: https://alive2.llvm.org/ce/z/nCrvfr
    Closes https://github.com/llvm/llvm-project/issues/136430

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 5a42a5c996da..b5a40892694c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3929,16 +3929,20 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
       if (match(&SI, m_OrdOrUnordFMax(m_Value(X), m_Value(Y)))) {
         Value *BinIntr =
             Builder.CreateBinaryIntrinsic(Intrinsic::maxnum, X, Y, &SI);
-        if (auto *BinIntrInst = dyn_cast<Instruction>(BinIntr))
+        if (auto *BinIntrInst = dyn_cast<Instruction>(BinIntr)) {
           BinIntrInst->setHasNoNaNs(FCmp->hasNoNaNs());
+          BinIntrInst->setHasNoInfs(FCmp->hasNoInfs());
+        }
         return replaceInstUsesWith(SI, BinIntr);
       }
 
       if (match(&SI, m_OrdOrUnordFMin(m_Value(X), m_Value(Y)))) {
         Value *BinIntr =
             Builder.CreateBinaryIntrinsic(Intrinsic::minnum, X, Y, &SI);
-        if (auto *BinIntrInst = dyn_cast<Instruction>(BinIntr))
+        if (auto *BinIntrInst = dyn_cast<Instruction>(BinIntr)) {
           BinIntrInst->setHasNoNaNs(FCmp->hasNoNaNs());
+          BinIntrInst->setHasNoInfs(FCmp->hasNoInfs());
+        }
         return replaceInstUsesWith(SI, BinIntr);
       }
     }


Regression tests:
file: llvm/test/Transforms/InstCombine/fcmp-fadd-select.ll
commands: opt < %s -passes=instcombine -S
tests: test_name: test_fcmp_ogt_fadd_select_rewrite_flags2
test_body: define float @test_fcmp_ogt_fadd_select_rewrite_flags2(float %in) {
  %cmp1 = fcmp ogt float %in, 0.000000e+00
  %add = fadd float %in, 1.000000e+00
  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
  ret float %sel
}

test_name: test_fcmp_ogt_fadd_select_rewrite_and_fastmath
test_body: define float @test_fcmp_ogt_fadd_select_rewrite_and_fastmath(float %in) {
  %cmp1 = fcmp nnan ogt float %in, 0.000000e+00
  %add = fadd nnan ninf nsz float %in, 1.000000e+00
  %sel = select nnan ninf nsz i1 %cmp1, float %add, float 1.000000e+00
  ret float %sel
}

file: llvm/test/Transforms/InstCombine/minmax-fp.ll
commands: opt -S -passes=instcombine < %s
tests: test_name: maxnum_ogt_fmf_on_select
test_body: define float @maxnum_ogt_fmf_on_select(float %a, float %b) {
  %cond = fcmp ogt float %a, %b
  %f = select nnan nsz i1 %cond, float %a, float %b
  ret float %f
}

test_name: maxnum_oge_fmf_on_select
test_body: define <2 x float> @maxnum_oge_fmf_on_select(<2 x float> %a, <2 x float> %b) {
  %cond = fcmp oge <2 x float> %a, %b
  %f = select nnan ninf nsz <2 x i1> %cond, <2 x float> %a, <2 x float> %b
  ret <2 x float> %f
}

test_name: minnum_olt_fmf_on_select_both_ninf
test_body: define float @minnum_olt_fmf_on_select_both_ninf(float %a, float %b) {
  %cond = fcmp ninf olt float %a, %b
  %f = select nnan ninf nsz i1 %cond, float %a, float %b
  ret float %f
}

test_name: minnum_ole_fmf_on_select
test_body: define <2 x float> @minnum_ole_fmf_on_select(<2 x float> %a, <2 x float> %b) {
  %cond = fcmp ole <2 x float> %a, %b
  %f = select nnan ninf nsz <2 x i1> %cond, <2 x float> %a, <2 x float> %b
  ret <2 x float> %f
}

test_name: minnum_olt_fmf_on_select
test_body: define float @minnum_olt_fmf_on_select(float %a, float %b) {
  %cond = fcmp olt float %a, %b
  %f = select nnan nsz i1 %cond, float %a, float %b
  ret float %f
}

test_name: maxnum_no_nnan
test_body: define float @maxnum_no_nnan(float %a, float %b) {
  %cond = fcmp oge float %a, %b
  %f = select nsz i1 %cond, float %a, float %b
  ret float %f
}

file: llvm/test/Transforms/InstCombine/unordered-fcmp-select.ll
commands: opt -S -passes=instcombine < %s
tests: test_name: select_max_ugt_2_use_cmp
test_body: declare void @foo(i1)

define float @select_max_ugt_2_use_cmp(float %a, float %b) {
  %cmp = fcmp ugt float %a, %b
  call void @foo(i1 %cmp)
  %sel = select nnan ninf nsz i1 %cmp, float %a, float %b
  ret float %sel
}