[InstCombine] allow more fast-math-flags to propagate in fneg-of-select fold
authorSanjay Patel <spatel@rotateright.com>
Fri, 9 Dec 2022 15:58:27 +0000 (10:58 -0500)
committerSanjay Patel <spatel@rotateright.com>
Fri, 9 Dec 2022 16:07:24 +0000 (11:07 -0500)
We were conservatively intersecting flags, but we can take the union here
because forbidden special values (nsz/nnan/ninf) are not altered by fneg.
So if they were guaranteed not present on the select or fneg, then they
are guaranteed not present on the new select. Alive2 appears to agree on
the test diffs (reduced to not include irrelevant flags like reassoc):
https://alive2.llvm.org/ce/z/ViqqrO

This prevents a potential regression if we tighten up the FMF behavior
for fabs with NAN as suggested in issue #59279.

llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
llvm/test/Transforms/InstCombine/fneg.ll

index 6f1b0b9..9c6624f 100644 (file)
@@ -2408,14 +2408,18 @@ Instruction *InstCombinerImpl::visitFNeg(UnaryOperator &I) {
   Value *Cond;
   if (match(Op, m_OneUse(m_Select(m_Value(Cond), m_Value(X), m_Value(Y))))) {
     // Unlike most transforms, this one is not safe to propagate nsz unless
-    // it is present on the original select. (We are conservatively intersecting
-    // the nsz flags from the select and root fneg instruction.)
+    // it is present on the original select. We union the flags from the select
+    // and fneg and then remove nsz if needed.
     auto propagateSelectFMF = [&](SelectInst *S, bool CommonOperand) {
       S->copyFastMathFlags(&I);
-      if (auto *OldSel = dyn_cast<SelectInst>(Op))
+      if (auto *OldSel = dyn_cast<SelectInst>(Op)) {
+        FastMathFlags FMF = I.getFastMathFlags();
+        FMF |= OldSel->getFastMathFlags();
+        S->setFastMathFlags(FMF);
         if (!OldSel->hasNoSignedZeros() && !CommonOperand &&
             !isGuaranteedNotToBeUndefOrPoison(OldSel->getCondition()))
           S->setHasNoSignedZeros(false);
+      }
     };
     // -(Cond ? -P : Y) --> Cond ? P : -Y
     Value *P;
index 41b2146..2c47b33 100644 (file)
@@ -629,7 +629,7 @@ define float @select_fneg_true(float %x, float %y, i1 %b) {
 define <2 x float> @select_fneg_false(<2 x float> %x, <2 x float> %y, <2 x i1> %b) {
 ; CHECK-LABEL: @select_fneg_false(
 ; CHECK-NEXT:    [[X_NEG:%.*]] = fneg nnan nsz <2 x float> [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = select nnan <2 x i1> [[B:%.*]], <2 x float> [[X_NEG]], <2 x float> [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = select nnan ninf <2 x i1> [[B:%.*]], <2 x float> [[X_NEG]], <2 x float> [[Y:%.*]]
 ; CHECK-NEXT:    ret <2 x float> [[R]]
 ;
   %ny = fneg nnan <2 x float> %y
@@ -772,7 +772,7 @@ define float @select_fneg_use1(float %x, float %y, i1 %b) {
 ; CHECK-NEXT:    [[NX:%.*]] = fneg ninf float [[X:%.*]]
 ; CHECK-NEXT:    call void @use(float [[NX]])
 ; CHECK-NEXT:    [[Y_NEG:%.*]] = fneg float [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = select i1 [[B:%.*]], float [[X]], float [[Y_NEG]]
+; CHECK-NEXT:    [[R:%.*]] = select fast i1 [[B:%.*]], float [[X]], float [[Y_NEG]]
 ; CHECK-NEXT:    ret float [[R]]
 ;
   %nx = fneg ninf float %x