Bug type: miscompilation
Component: ValueTracking
Bug location: llvm/lib/Analysis/ValueTracking.cpp: llvm::matchDecomposedSelectPattern
llvm::matchSelectPattern
Issue title: [InstCombine] Miscompilation `select (fcmp nsz olt X, 0.0), -0.0, X -> select (fcmp nsz ole X, -0.0), -0.0, X`
Labels: miscompilation
floating-point
llvm:analysis
Reported by: dtcxzyw

Reproducer: https://alive2.llvm.org/ce/z/Uydp8F
```
define float @src(float %x) {
  %cmp = fcmp nsz olt float %x, 0.0
  %sel = select i1 %cmp, float -0.0, float %x
  ret float %sel
}

define float @tgt(float %x) {
  %.inv = fcmp nsz ole float %x, -0.000000e+00
  %sel1 = select i1 %.inv, float -0.000000e+00, float %x
  ret float %sel1
}
```
```
Transformation doesn't verify!

ERROR: Target's return value is more undefined

Example:
float %x = #x00000000 (+0.0)

Source:
i1 %cmp = #x0 (0)
float %sel = #x00000000 (+0.0)

Target:
i1 %.inv = #x1 (1)
float %sel1 = #x00000000 (+0.0)
Source value: #x00000000 (+0.0)
Target value: #x00000000 (+0.0)
```



Fix patch:
commit 1984c7539ebeb2697233f8163a051a2ce0d4fa50
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Mon Jun 2 18:21:14 2025 +0800

    [ValueTracking] Do not use FMF from fcmp (#142266)
    
    This patch introduces an FMF parameter for
    `matchDecomposedSelectPattern` to pass FMF flags from select, instead of
    fcmp.
    
    Closes https://github.com/llvm/llvm-project/issues/137998.
    Closes https://github.com/llvm/llvm-project/issues/141017.

diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index d81c3f10bba9..feb7a1fa2cb3 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -889,7 +889,8 @@ inline SelectPatternResult matchSelectPattern(const Value *V, const Value *&LHS,
 /// predicate and given values as its true/false operands would match.
 LLVM_ABI SelectPatternResult matchDecomposedSelectPattern(
     CmpInst *CmpI, Value *TrueVal, Value *FalseVal, Value *&LHS, Value *&RHS,
-    Instruction::CastOps *CastOp = nullptr, unsigned Depth = 0);
+    FastMathFlags FMF = FastMathFlags(), Instruction::CastOps *CastOp = nullptr,
+    unsigned Depth = 0);
 
 /// Determine the pattern for predicate `X Pred Y ? X : Y`.
 LLVM_ABI SelectPatternResult getSelectPattern(
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 3d8bb6249eaf..7f30cd73d57c 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -8898,19 +8898,20 @@ SelectPatternResult llvm::matchSelectPattern(Value *V, Value *&LHS, Value *&RHS,
   Value *TrueVal = SI->getTrueValue();
   Value *FalseVal = SI->getFalseValue();
 
-  return llvm::matchDecomposedSelectPattern(CmpI, TrueVal, FalseVal, LHS, RHS,
-                                            CastOp, Depth);
+  return llvm::matchDecomposedSelectPattern(
+      CmpI, TrueVal, FalseVal, LHS, RHS,
+      isa<FPMathOperator>(SI) ? SI->getFastMathFlags() : FastMathFlags(),
+      CastOp, Depth);
 }
 
 SelectPatternResult llvm::matchDecomposedSelectPattern(
     CmpInst *CmpI, Value *TrueVal, Value *FalseVal, Value *&LHS, Value *&RHS,
-    Instruction::CastOps *CastOp, unsigned Depth) {
+    FastMathFlags FMF, Instruction::CastOps *CastOp, unsigned Depth) {
   CmpInst::Predicate Pred = CmpI->getPredicate();
   Value *CmpLHS = CmpI->getOperand(0);
   Value *CmpRHS = CmpI->getOperand(1);
-  FastMathFlags FMF;
-  if (isa<FPMathOperator>(CmpI))
-    FMF = CmpI->getFastMathFlags();
+  if (isa<FPMathOperator>(CmpI) && CmpI->hasNoNaNs())
+    FMF.setNoNaNs();
 
   // Bail out early.
   if (CmpI->isEquality())


Regression tests:
file: llvm/test/Transforms/InstCombine/unordered-fcmp-select.ll
commands: opt -S -passes=instcombine < %s
tests: test_name: pr141017_select_nsz
test_body: define float @pr141017_select_nsz(float %x) {
  %cmp = fcmp olt float %x, 0.000000e+00
  %sel = select nsz i1 %cmp, float -0.000000e+00, float %x
  ret float %sel
}

test_name: pr141017
test_body: define float @pr141017(float %x) {
  %cmp = fcmp nsz olt float %x, 0.000000e+00
  %sel = select i1 %cmp, float -0.000000e+00, float %x
  ret float %sel
}

test_name: select_min_uge_2_use_cmp
test_body: declare void @foo(i1)

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