Bug type: miscompilation
Component: InstCombine
Bug location: llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp: InstCombinerImpl::foldSelectIntoOp
Issue title: Wrong folding of `select` into floating number ops
Labels: miscompilation
llvm:instcombine
floating-point
Reported by: bongjunj

https://github.com/llvm/llvm-project/blob/ae618d360456c5ccf6c8cf2294e708ac6625950e/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp#L559-L568

The compiler explorer's alive2 times out for this case.
But I post a proof that the optimization actually happens: https://alive2.llvm.org/ce/z/7MRSu5


This is the Alive2 report on my machine:
```llvm
----------------------------------------
define float @fmul_by_self_if_0_oeq_zero_f32_fmul_nnan_ninf_nsz.2(float %x) {
#0:
  %#1 = fcmp ule float %x, 0.000000
  %scaled.x = fmul nnan ninf nsz float %x, %x
  %scaled.if.denormal = select nnan i1 %#1, float %x, float %scaled.x
  ret float %scaled.if.denormal
}
=>
define float @fmul_by_self_if_0_oeq_zero_f32_fmul_nnan_ninf_nsz.2(float %x) {
#0:
  %#1 = fcmp ule float %x, 0.000000
  %scaled.x = select nnan i1 %#1, float 1.000000, float %x
  %scaled.if.denormal = fmul nnan ninf nsz float %scaled.x, %x
  ret float %scaled.if.denormal
}
Transformation doesn't verify!

ERROR: Target is more poisonous than source

Example:
float %x = #xff800000 (-oo)

Source:
i1 %#1 = #x1 (1)
float %scaled.x = poison
float %scaled.if.denormal = #xff800000 (-oo)

Target:
i1 %#1 = #x1 (1)
float %scaled.x = #x3f800000 (1)
float %scaled.if.denormal = poison
Source value: #xff800000 (-oo)
Target value: poison

Summary:
  0 correct transformations
  1 incorrect transformations
  0 failed-to-prove transformations
  0 Alive2 errors
```


Fix patch:
commit cf1963afad335cf74a9411f106d1f2fe80dbed2f
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Thu Oct 31 23:26:45 2024 +0800

    [InstCombine] Fix FMF propagation in `foldSelectIntoOp` (#114356)
    
    Closes https://github.com/llvm/llvm-project/issues/113423.

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index c5f39a4c381e..9e193e7faa8a 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -529,9 +529,6 @@ Instruction *InstCombinerImpl::foldSelectIntoOp(SelectInst &SI, Value *TrueVal,
     if (!OpToFold)
       return nullptr;
 
-    // TODO: We probably ought to revisit cases where the select and FP
-    // instructions have different flags and add tests to ensure the
-    // behaviour is correct.
     FastMathFlags FMF;
     if (isa<FPMathOperator>(&SI))
       FMF = SI.getFastMathFlags();
@@ -564,6 +561,8 @@ Instruction *InstCombinerImpl::foldSelectIntoOp(SelectInst &SI, Value *TrueVal,
     BinaryOperator *BO =
         BinaryOperator::Create(TVI->getOpcode(), FalseVal, NewSel);
     BO->copyIRFlags(TVI);
+    if (isa<FPMathOperator>(&SI))
+      BO->andIRFlags(NewSel);
     return BO;
   };
 


Regression tests:
file: llvm/test/Transforms/InstCombine/fold-select-fmul-if-zero.ll
commands: opt -S -passes=instcombine < %s
tests: test_name: fmul_by_self_if_0_oeq_zero_f32_fmul_nnan_ninf_nsz
test_body: define float @fmul_by_self_if_0_oeq_zero_f32_fmul_nnan_ninf_nsz(float %x) {
  %x.is.zero = fcmp oeq float %x, 0.000000e+00
  %scaled.x = fmul nnan ninf nsz float %x, %x
  %scaled.if.denormal = select nnan i1 %x.is.zero, float %scaled.x, float %x
  ret float %scaled.if.denormal
}