Bug type: miscompilation
Component: InstCombine
Bug location: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp: InstCombinerImpl::foldLogicOfFCmps
Issue title: [InstCombine] Poison safety violation in `foldLogicOfFCmps`
Labels: miscompilation
llvm:instcombine
Reported by: dtcxzyw

Reproducer: https://alive2.llvm.org/ce/z/Qcvvgi
```
----------------------------------------
define i1 @src(half %x, half %y) {
#0:
  %copysign.x = copysign half %x, %y
  %ord = fcmp ord half %x, 0x0000
  %cmp = fcmp uge half %copysign.x, 0x7c00
  %#1 = select i1 %ord, i1 %cmp, i1 0
  ret i1 %#1
}
=>
define i1 @src(half %x, half %y) nofree willreturn memory(none) {
#0:
  %copysign.x = copysign half %x, %y
  %#1 = fcmp oeq half %copysign.x, 0x7c00
  ret i1 %#1
}
Transformation doesn't verify!

ERROR: Target is more poisonous than source

Example:
half %x = #x7c02 (SNaN)
half %y = poison

Source:
half %copysign.x = poison
i1 %ord = #x0 (0)
i1 %cmp = poison
i1 %#1 = #x0 (0)

Target:
half %copysign.x = poison
i1 %#1 = poison
Source value: #x0 (0)
Target value: poison

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


Fix patch:
commit 8abc917fe04140b6c6088a67e0398f637efde808
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Thu Apr 24 00:12:30 2025 +0800

    [InstCombine] Do not fold logical is_finite test (#136851)
    
    This patch disables the fold for logical is_finite test (i.e., `and
    (fcmp ord x, 0), (fcmp u* x, inf) -> fcmp o* x, inf`).
    It is still possible to allow this fold for several logical cases (e.g.,
    `stripSignOnlyFPOps(RHS0)` does not strip any operations). Since this
    patch has no real-world impact, I decided to disable this fold for all
    logical cases.
    
    Alive2: https://alive2.llvm.org/ce/z/aH4LC7
    Closes https://github.com/llvm/llvm-project/issues/136650.

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index f1b225c0f238..979a9cbedf2e 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -1480,7 +1480,9 @@ Value *InstCombinerImpl::foldLogicOfFCmps(FCmpInst *LHS, FCmpInst *RHS,
     }
   }
 
-  if (IsAnd && stripSignOnlyFPOps(LHS0) == stripSignOnlyFPOps(RHS0)) {
+  // This transform is not valid for a logical select.
+  if (!IsLogicalSelect && IsAnd &&
+      stripSignOnlyFPOps(LHS0) == stripSignOnlyFPOps(RHS0)) {
     // and (fcmp ord x, 0), (fcmp u* x, inf) -> fcmp o* x, inf
     // and (fcmp ord x, 0), (fcmp u* fabs(x), inf) -> fcmp o* x, inf
     if (Value *Left = matchIsFiniteTest(Builder, LHS, RHS))


Regression tests:
file: llvm/test/Transforms/InstCombine/and-fcmp.ll
commands: opt < %s -passes=instcombine -S
tests: test_name: clang_builtin_isnormal_inf_check_fabs_nnan_logical_select
test_body: define i1 @clang_builtin_isnormal_inf_check_fabs_nnan_logical_select(half %x) {
  %copysign.x = call nnan half @llvm.fabs.f16(half %x)
  %ord = fcmp ord half %x, 0xH0000
  %cmp = fcmp uge half %copysign.x, 0xH7C00
  %and = select i1 %ord, i1 %cmp, i1 false
  ret i1 %and
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare half @llvm.fabs.f16(half) #0

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

test_name: clang_builtin_isnormal_inf_check_copysign_logical_select
test_body: define i1 @clang_builtin_isnormal_inf_check_copysign_logical_select(half %x, half %y) {
  %copysign.x = call half @llvm.copysign.f16(half %x, half %y)
  %ord = fcmp ord half %x, 0xH0000
  %cmp = fcmp uge half %copysign.x, 0xH7C00
  %and = select i1 %ord, i1 %cmp, i1 false
  ret i1 %and
}

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

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

test_name: isnormal_logical_select_0
test_body: define i1 @isnormal_logical_select_0(half %x) {
  %fabs.x = call half @llvm.fabs.f16(half %x)
  %ord = fcmp ord half %fabs.x, 0xH0000
  %cmp.inf = fcmp uge half %fabs.x, 0xH7C00
  %and = select i1 %ord, i1 %cmp.inf, i1 false
  ret i1 %and
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare half @llvm.fabs.f16(half) #0

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

test_name: clang_builtin_isnormal_inf_check_copysign
test_body: define i1 @clang_builtin_isnormal_inf_check_copysign(half %x, half %y) {
  %copysign.x = call half @llvm.copysign.f16(half %x, half %y)
  %ord = fcmp ord half %x, 0xH0000
  %cmp = fcmp uge half %copysign.x, 0xH7C00
  %and = and i1 %ord, %cmp
  ret i1 %and
}

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

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