[llvm] r328502 - [InstCombine] distribute fmul over fadd/fsub

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 26 08:03:57 PDT 2018


Author: spatel
Date: Mon Mar 26 08:03:57 2018
New Revision: 328502

URL: http://llvm.org/viewvc/llvm-project?rev=328502&view=rev
Log:
[InstCombine] distribute fmul over fadd/fsub

This replaces a large chunk of code that was looking for compound
patterns that include these sub-patterns. Existing tests ensure that
all of the previous examples are still folded as expected.

We still need to loosen the FMF check.

Modified:
    llvm/trunk/lib/Transforms/InstCombine/InstCombineInternal.h
    llvm/trunk/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
    llvm/trunk/test/Transforms/InstCombine/fast-math.ll
    llvm/trunk/test/Transforms/InstCombine/fmul.ll

Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineInternal.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineInternal.h?rev=328502&r1=328501&r2=328502&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineInternal.h (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineInternal.h Mon Mar 26 08:03:57 2018
@@ -289,8 +289,6 @@ public:
   Instruction *visitSub(BinaryOperator &I);
   Instruction *visitFSub(BinaryOperator &I);
   Instruction *visitMul(BinaryOperator &I);
-  Value *foldFMulConst(Instruction *FMulOrDiv, Constant *C,
-                       Instruction *InsertBefore);
   Instruction *visitFMul(BinaryOperator &I);
   Instruction *visitURem(BinaryOperator &I);
   Instruction *visitSRem(BinaryOperator &I);

Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp?rev=328502&r1=328501&r2=328502&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp Mon Mar 26 08:03:57 2018
@@ -447,70 +447,6 @@ Instruction *InstCombiner::visitMul(Bina
   return Changed ? &I : nullptr;
 }
 
-/// Helper function of InstCombiner::visitFMul(). Return true iff the given
-/// value is FMul or FDiv with one and only one operand being a finite-non-zero
-/// constant (i.e. not Zero/NaN/Infinity).
-static bool isFMulOrFDivWithConstant(Value *V) {
-  Constant *C;
-  return (match(V, m_FMul(m_Value(), m_Constant(C))) ||
-          match(V, m_FDiv(m_Value(), m_Constant(C))) ||
-          match(V, m_FDiv(m_Constant(C), m_Value()))) && C->isFiniteNonZeroFP();
-}
-
-/// foldFMulConst() is a helper routine of InstCombiner::visitFMul().
-/// The input \p FMulOrDiv is a FMul/FDiv with one and only one operand
-/// being a constant (i.e. isFMulOrFDivWithConstant(FMulOrDiv) == true).
-/// This function is to simplify "FMulOrDiv * C" and returns the
-/// resulting expression. Note that this function could return NULL in
-/// case the constants cannot be folded into a normal floating-point.
-Value *InstCombiner::foldFMulConst(Instruction *FMulOrDiv, Constant *C,
-                                   Instruction *InsertBefore) {
-  assert(isFMulOrFDivWithConstant(FMulOrDiv) && "V is invalid");
-
-  Value *Opnd0 = FMulOrDiv->getOperand(0);
-  Value *Opnd1 = FMulOrDiv->getOperand(1);
-
-  Constant *C0 = dyn_cast<Constant>(Opnd0);
-  Constant *C1 = dyn_cast<Constant>(Opnd1);
-
-  BinaryOperator *R = nullptr;
-
-  // (X * C0) * C => X * (C0*C)
-  if (FMulOrDiv->getOpcode() == Instruction::FMul) {
-    Constant *F = ConstantExpr::getFMul(C1 ? C1 : C0, C);
-    if (F->isNormalFP())
-      R = BinaryOperator::CreateFMul(C1 ? Opnd0 : Opnd1, F);
-  } else {
-    if (C0) {
-      // (C0 / X) * C => (C0 * C) / X
-      if (FMulOrDiv->hasOneUse()) {
-        // It would otherwise introduce another div.
-        Constant *F = ConstantExpr::getFMul(C0, C);
-        if (F->isNormalFP())
-          R = BinaryOperator::CreateFDiv(F, Opnd1);
-      }
-    } else {
-      // (X / C1) * C => X * (C/C1) if C/C1 is not a denormal
-      Constant *F = ConstantExpr::getFDiv(C, C1);
-      if (F->isNormalFP()) {
-        R = BinaryOperator::CreateFMul(Opnd0, F);
-      } else {
-        // (X / C1) * C => X / (C1/C)
-        Constant *F = ConstantExpr::getFDiv(C1, C);
-        if (F->isNormalFP())
-          R = BinaryOperator::CreateFDiv(Opnd0, F);
-      }
-    }
-  }
-
-  if (R) {
-    R->setFast(true);
-    InsertNewInstWith(R, *InsertBefore);
-  }
-
-  return R;
-}
-
 Instruction *InstCombiner::visitFMul(BinaryOperator &I) {
   bool Changed = SimplifyAssociativeOrCommutative(I);
   Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
@@ -556,6 +492,7 @@ Instruction *InstCombiner::visitFMul(Bin
     return replaceInstUsesWith(I, V);
 
   // Reassociate constant RHS with another constant to form constant expression.
+  // FIXME: These folds do not require all FMF.
   if (I.isFast() && match(Op1, m_Constant(C)) && C->isFiniteNonZeroFP()) {
     Constant *C1;
     if (match(Op0, m_OneUse(m_FDiv(m_Constant(C1), m_Value(X))))) {
@@ -577,40 +514,20 @@ Instruction *InstCombiner::visitFMul(Bin
         return BinaryOperator::CreateFDivFMF(X, C1DivC, &I);
     }
 
-    // Let MDC denote an expression in one of these forms:
-    // X * C, C/X, X/C, where C is a constant.
-    // (MDC +/- C1) * C => (MDC * C) +/- (C1 * C)
-    Instruction *FAddSub = dyn_cast<Instruction>(Op0);
-    if (FAddSub && FAddSub->hasOneUse() &&
-        (FAddSub->getOpcode() == Instruction::FAdd ||
-         FAddSub->getOpcode() == Instruction::FSub)) {
-      Value *Opnd0 = FAddSub->getOperand(0);
-      Value *Opnd1 = FAddSub->getOperand(1);
-      Constant *C0 = dyn_cast<Constant>(Opnd0);
-      Constant *C1 = dyn_cast<Constant>(Opnd1);
-      bool Swap = false;
-      if (C0) {
-        std::swap(C0, C1);
-        std::swap(Opnd0, Opnd1);
-        Swap = true;
-      }
-
-      if (C1 && C1->isFiniteNonZeroFP() && isFMulOrFDivWithConstant(Opnd0)) {
-        Value *M1 = ConstantExpr::getFMul(C1, C);
-        Value *M0 = cast<Constant>(M1)->isNormalFP() ?
-                        foldFMulConst(cast<Instruction>(Opnd0), C, &I) :
-                        nullptr;
-        if (M0 && M1) {
-          if (Swap && FAddSub->getOpcode() == Instruction::FSub)
-            std::swap(M0, M1);
-
-          Instruction *RI = (FAddSub->getOpcode() == Instruction::FAdd)
-                                ? BinaryOperator::CreateFAdd(M0, M1)
-                                : BinaryOperator::CreateFSub(M0, M1);
-          RI->copyFastMathFlags(&I);
-          return RI;
-        }
-      }
+    // 'fadd C, X' and 'fsub X, C' are canonicalized to these patterns, so we do
+    // not need to match those. Distributing the multiply may allow further
+    // folds and (X * C) + C2 is 'fma'.
+    if (match(Op0, m_OneUse(m_FAdd(m_Value(X), m_Constant(C1))))) {
+      // (X + C1) * C --> (X * C) + (C * C1)
+      Constant *CC1 = ConstantExpr::getFMul(C, C1);
+      Value *XC = Builder.CreateFMulFMF(X, C, &I);
+      return BinaryOperator::CreateFAddFMF(XC, CC1, &I);
+    }
+    if (match(Op0, m_OneUse(m_FSub(m_Constant(C1), m_Value(X))))) {
+      // (C1 - X) * C --> (C * C1) - (X * C)
+      Constant *CC1 = ConstantExpr::getFMul(C, C1);
+      Value *XC = Builder.CreateFMulFMF(X, C, &I);
+      return BinaryOperator::CreateFSubFMF(CC1, XC, &I);
     }
   }
 

Modified: llvm/trunk/test/Transforms/InstCombine/fast-math.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fast-math.ll?rev=328502&r1=328501&r2=328502&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fast-math.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/fast-math.ll Mon Mar 26 08:03:57 2018
@@ -134,12 +134,13 @@ define float @fold10(float %f1, float %f
   ret float %t3
 }
 
-; once cause Crash/miscompilation
+; This used to crash/miscompile.
+
 define float @fail1(float %f1, float %f2) {
 ; CHECK-LABEL: @fail1(
-; CHECK-NEXT:    [[CONV3:%.*]] = fadd fast float [[F1:%.*]], -1.000000e+00
-; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast float [[CONV3]], 3.000000e+00
-; CHECK-NEXT:    ret float [[TMP1]]
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast float [[F1:%.*]], 3.000000e+00
+; CHECK-NEXT:    [[TMP2:%.*]] = fadd fast float [[TMP1]], -3.000000e+00
+; CHECK-NEXT:    ret float [[TMP2]]
 ;
   %conv3 = fadd fast float %f1, -1.000000e+00
   %add = fadd fast float %conv3, %conv3

Modified: llvm/trunk/test/Transforms/InstCombine/fmul.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fmul.ll?rev=328502&r1=328501&r2=328502&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fmul.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/fmul.ll Mon Mar 26 08:03:57 2018
@@ -439,13 +439,12 @@ define float @fdiv_constant_denominator_
   ret float %r
 }
 
-; FIXME: Distribute to fma form.
 ; (X + C1) * C2 --> (X * C2) + C1*C2
 
 define float @fmul_fadd_distribute(float %x) {
 ; CHECK-LABEL: @fmul_fadd_distribute(
-; CHECK-NEXT:    [[T2:%.*]] = fadd float [[X:%.*]], 2.000000e+00
-; CHECK-NEXT:    [[T3:%.*]] = fmul fast float [[T2]], 3.000000e+00
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast float [[X:%.*]], 3.000000e+00
+; CHECK-NEXT:    [[T3:%.*]] = fadd fast float [[TMP1]], 6.000000e+00
 ; CHECK-NEXT:    ret float [[T3]]
 ;
   %t2 = fadd float %x, 2.0
@@ -453,13 +452,12 @@ define float @fmul_fadd_distribute(float
   ret float %t3
 }
 
-; FIXME: Distribute to fma form.
 ; (X - C1) * C2 --> (X * C2) - C1*C2
 
 define float @fmul_fsub_distribute1(float %x) {
 ; CHECK-LABEL: @fmul_fsub_distribute1(
-; CHECK-NEXT:    [[T2:%.*]] = fadd float [[X:%.*]], -2.000000e+00
-; CHECK-NEXT:    [[T3:%.*]] = fmul fast float [[T2]], 3.000000e+00
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast float [[X:%.*]], 3.000000e+00
+; CHECK-NEXT:    [[T3:%.*]] = fadd fast float [[TMP1]], -6.000000e+00
 ; CHECK-NEXT:    ret float [[T3]]
 ;
   %t2 = fsub float %x, 2.0
@@ -467,13 +465,12 @@ define float @fmul_fsub_distribute1(floa
   ret float %t3
 }
 
-; FIXME: Distribute to fma form.
 ; (C1 - X) * C2 --> C1*C2 - (X * C2)
 
 define float @fmul_fsub_distribute2(float %x) {
 ; CHECK-LABEL: @fmul_fsub_distribute2(
-; CHECK-NEXT:    [[T2:%.*]] = fsub float 2.000000e+00, [[X:%.*]]
-; CHECK-NEXT:    [[T3:%.*]] = fmul fast float [[T2]], 3.000000e+00
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul fast float [[X:%.*]], 3.000000e+00
+; CHECK-NEXT:    [[T3:%.*]] = fsub fast float 6.000000e+00, [[TMP1]]
 ; CHECK-NEXT:    ret float [[T3]]
 ;
   %t2 = fsub float 2.0, %x




More information about the llvm-commits mailing list