[llvm] a7d8b88 - [InstCombine] Add check for flag propagation in `foldSelectIntoOp` (#173735)

via llvm-commits llvm-commits at lists.llvm.org
Sun Dec 28 02:33:27 PST 2025


Author: Yunbo Ni
Date: 2025-12-28T18:33:23+08:00
New Revision: a7d8b88d1818d9eeb4e21de80f09719ca7ecb51a

URL: https://github.com/llvm/llvm-project/commit/a7d8b88d1818d9eeb4e21de80f09719ca7ecb51a
DIFF: https://github.com/llvm/llvm-project/commit/a7d8b88d1818d9eeb4e21de80f09719ca7ecb51a.diff

LOG: [InstCombine] Add check for flag propagation in `foldSelectIntoOp` (#173735)

Fixes
https://github.com/llvm/llvm-project/pull/162003#issuecomment-3693943568.

The current flag propagation assumes that if a select has both `ninf`
and `nnan`, then the operands of the folded operation must be finite.
While this assumption holds for `fadd`, `fsub`, and `fmul`, it does not
hold for `fdiv`.

For example, assume we have: 

```
A = 1.0, B = +Inf
A / B = 0.0  (finite, non-NaN)
```

The current transform would turn `fdiv A, B; select ninf nnan cond, A/B,
A;` into `A / (select ninf nnan cond, B, 1.0)`. If `cond` is true, the
inner select returns `B = +Inf`, and due to the propagated `ninf`, this
becomes poison.

This patch add check for operators before flag propagation to avoid
`fdiv` cases.

Alive2: https://alive2.llvm.org/ce/z/o0MJmS

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
    llvm/test/Transforms/InstCombine/select-binop-foldable-floating-point.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index f52bac5e600cb..67d1845832725 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -555,8 +555,15 @@ Instruction *InstCombinerImpl::foldSelectIntoOp(SelectInst &SI, Value *TrueVal,
       // Examples: -inf + +inf = NaN, -inf - -inf = NaN, 0 * inf = NaN
       // Specifically, if the original select has both ninf and nnan, we can
       // safely propagate the flag.
+      // Note: This property holds for fadd, fsub, and fmul, but does not
+      // hold for fdiv (e.g. A / Inf == 0.0).
+      bool CanInferFiniteOperandsFromResult =
+          TVI->getOpcode() == Instruction::FAdd ||
+          TVI->getOpcode() == Instruction::FSub ||
+          TVI->getOpcode() == Instruction::FMul;
       NewSelFMF.setNoInfs(TVI->hasNoInfs() ||
-                          (NewSelFMF.noInfs() && NewSelFMF.noNaNs()));
+                          (CanInferFiniteOperandsFromResult &&
+                           NewSelFMF.noInfs() && NewSelFMF.noNaNs()));
       cast<Instruction>(NewSel)->setFastMathFlags(NewSelFMF);
     }
     NewSel->takeName(TVI);

diff  --git a/llvm/test/Transforms/InstCombine/select-binop-foldable-floating-point.ll b/llvm/test/Transforms/InstCombine/select-binop-foldable-floating-point.ll
index c14dd469f1a6e..83fa28a406f75 100644
--- a/llvm/test/Transforms/InstCombine/select-binop-foldable-floating-point.ll
+++ b/llvm/test/Transforms/InstCombine/select-binop-foldable-floating-point.ll
@@ -409,3 +409,14 @@ define float @select_nnan_fdiv_invalid(i1 %cond, float %A, float %B) {
   %D = select nnan i1 %cond, float %C, float %A
   ret float %D
 }
+
+define float @select_fpclass_fdiv_nnan_ninf(i1 %cond, float %A, float %B) {
+; CHECK-LABEL: @select_fpclass_fdiv_nnan_ninf(
+; CHECK-NEXT:    [[C:%.*]] = select nnan i1 [[COND:%.*]], float [[B:%.*]], float 1.000000e+00
+; CHECK-NEXT:    [[D:%.*]] = fdiv float [[A:%.*]], [[C]]
+; CHECK-NEXT:    ret float [[D]]
+;
+  %C = fdiv float %A, %B
+  %D = select ninf nnan i1 %cond, float %C, float %A
+  ret float %D
+}


        


More information about the llvm-commits mailing list