[llvm-commits] [PATCH][Fastmath, Instcombine] Enhancement of Fdiv

Shuxin Yang shuxin.llvm at gmail.com
Fri Jan 11 14:41:39 PST 2013


Hi,

     The attached two patches are about fdiv enhancement. The 
transformation will be disabled
if constant-folding yields a special value or a denormal. (Steve figured 
out a smart way in
dealing with denormal value, which will be implemented in the near future).

     1) reciprocal.patch:
         implement reciprocal rule:
          1.1   X/C => X *(1/C) if 1/C is neither special value nor 
denormal.

        This rule could incur noticeable rounding errors (sometimes up 
to 0.001% -- one testing case
       in pollybench suite see a diff between 1.003 and 1.004, and the 
"huge" difference is caused
       by a single transformation X/1000 => X * 0.001).

    2. fdiv.patch implement a slew of fdiv related rules:

       2.1). (X/C1) / C2 => X * (1/(C2*C1))
       2.2). X*C1 / C2 => X * (C1/C2)
       2.3). (X/Y)/Z = > X/(Y*Z)  (at least one of Y and Z is symbolic 
value)
       2.4). Z/(X/Y) = > (Z*Y)/X
       2.5). C1/(X*C2) => (C1/C2) / X
       2.6). C1/(X/C2) => (C1*C2) / X
       2.7) C1/(C2/X) => (C1/C2) * X


  Thank you for review!
Shuxin

-------------- next part --------------
Index: lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
===================================================================
--- lib/Transforms/InstCombine/InstCombineMulDivRem.cpp	(revision 172167)
+++ lib/Transforms/InstCombine/InstCombineMulDivRem.cpp	(working copy)
@@ -796,9 +796,19 @@
     // If the divisor has an exact multiplicative inverse we can turn the fdiv
     // into a cheaper fmul.
     APFloat Reciprocal(Op1F.getSemantics());
-    if (Op1F.getExactInverse(&Reciprocal)) {
+    bool Convert = Op1F.getExactInverse(&Reciprocal);
+    
+    if (!Convert && I.hasAllowReciprocal() && Op1F.isNormal()) {
+      Reciprocal = APFloat(Op1F.getSemantics(), 1.0f);
+      (void)Reciprocal.divide(Op1F, APFloat::rmNearestTiesToEven);
+      Convert = !Reciprocal.isDenormal();
+    }
+
+    if (Convert) {
       ConstantFP *RFP = ConstantFP::get(Builder->getContext(), Reciprocal);
-      return BinaryOperator::CreateFMul(Op0, RFP);
+      Instruction *Mul = BinaryOperator::CreateFMul(Op0, RFP);
+      Mul->setFastMathFlags(I.getFastMathFlags());
+      return Mul;
     }
   }
 
-------------- next part --------------
Index: test/Transforms/InstCombine/fast-math.ll
===================================================================
--- test/Transforms/InstCombine/fast-math.ll	(revision 172167)
+++ test/Transforms/InstCombine/fast-math.ll	(working copy)
@@ -256,3 +256,99 @@
 ; CHECK: @fneg1
 ; CHECK: fmul float %f1, %f2
 }
+
+; =========================================================================
+;
+;   Testing-cases about div
+;
+; =========================================================================
+; X/C1 / C2 => X * (1/(C2*C1))
+
+define float @fdiv1(float %x) {
+  %div = fdiv float %x, 0x3FF3333340000000
+  %div1 = fdiv fast float %div, 0x4002666660000000
+  ret float %div1
+; 0x3FF3333340000000 = 1.2f
+; 0x4002666660000000 = 2.3f
+; 0x3FD7303B60000000 = 0.36231884057971014492
+; CHECK: @fdiv1
+; CHECK: fmul fast float %x, 0x3FD7303B60000000
+}
+
+; X*C1 / C2 => X * (C1/C2)
+define float @fdiv2(float %x) {
+  %mul = fmul float %x, 0x3FF3333340000000
+  %div1 = fdiv fast float %mul, 0x4002666660000000
+  ret float %div1
+
+; 0x3FF3333340000000 = 1.2f
+; 0x4002666660000000 = 2.3f
+; 0x3FE0B21660000000 = 0.52173918485641479492
+; CHECK: @fdiv2
+; CHECK: fmul fast float %x, 0x3FE0B21660000000
+}
+
+; "X/C1 / C2 => X * (1/(C2*C1))" is disabled (for now) is C2/C1 is a denormal
+; 
+define float @fdiv3(float %x) {
+  %div = fdiv float %x, 0x47EFFFFFE0000000
+  %div1 = fdiv fast float %div, 0x4002666660000000
+  ret float %div1
+; CHECK: @fdiv3
+; CHECK: fdiv float %x, 0x47EFFFFFE0000000
+}
+
+; "X*C1 / C2 => X * (C1/C2)" is disabled if C1/C2 is a denormal
+define float @fdiv4(float %x) {
+  %mul = fmul float %x, 0x47EFFFFFE0000000
+  %div = fdiv float %mul, 0x3FC99999A0000000
+  ret float %div
+; CHECK: @fdiv4
+; CHECK: fmul float %x, 0x47EFFFFFE0000000
+}
+
+; (X/Y)/Z = > X/(Y*Z)
+define float @fdiv5(float %f1, float %f2, float %f3) {
+  %t1 = fdiv float %f1, %f2
+  %t2 = fdiv fast float %t1, %f3
+  ret float %t2
+; CHECK: @fdiv5
+; CHECK: fmul float %f2, %f3
+}
+
+; Z/(X/Y) = > (Z*Y)/X
+define float @fdiv6(float %f1, float %f2, float %f3) {
+  %t1 = fdiv float %f1, %f2
+  %t2 = fdiv fast float %f3, %t1
+  ret float %t2
+; CHECK: @fdiv6
+; CHECK: fmul float %f3, %f2
+}
+
+; C1/(X*C2) => (C1/C2) / X
+define float @fdiv7(float %x) {
+  %t1 = fmul float %x, 3.0e0
+  %t2 = fdiv fast float 15.0e0, %t1
+  ret float %t2
+; CHECK: @fdiv7
+; CHECK: fdiv fast float 5.000000e+00, %x
+}
+
+; C1/(X/C2) => (C1*C2) / X
+define float @fdiv8(float %x) {
+  %t1 = fdiv float %x, 3.0e0
+  %t2 = fdiv fast float 15.0e0, %t1
+  ret float %t2
+; CHECK: @fdiv8
+; CHECK: fdiv fast float 4.500000e+01, %x
+}
+
+; C1/(C2/X) => (C1/C2) * X
+define float @fdiv9(float %x) {
+  %t1 = fdiv float 3.0e0, %x
+  %t2 = fdiv fast float 15.0e0, %t1
+  ret float %t2
+; CHECK: @fdiv9
+; CHECK: fmul fast float %x, 5.000000e+00
+}
+
Index: lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
===================================================================
--- lib/Transforms/InstCombine/InstCombineMulDivRem.cpp	(revision 172167)
+++ lib/Transforms/InstCombine/InstCombineMulDivRem.cpp	(working copy)
@@ -800,8 +800,101 @@
       ConstantFP *RFP = ConstantFP::get(Builder->getContext(), Reciprocal);
       return BinaryOperator::CreateFMul(Op0, RFP);
     }
+
+    if (I.hasUnsafeAlgebra()) {
+      // (X/C1)/C2 => X * (1/(C2*C1))
+      // (X*C1)/C2 => X * (C1/C2)
+      //
+      ConstantFP *C1 = 0;
+      ConstantFP *C2 = Op1C;
+      Value *X;
+      bool isOp0Mpy = false;
+
+      if ((isOp0Mpy = match(Op0, m_FMul(m_Value(X), m_ConstantFP(C1)))) ||
+          match(Op0, m_FDiv(m_Value(X), m_ConstantFP(C1)))) {
+        if (C1->getValueAPF().isNormal() && C2->getValueAPF().isNormal()) {
+          Constant *C;
+          if (isOp0Mpy)
+            C = ConstantExpr::getFDiv(C1, C2);
+          else {
+            C = ConstantExpr::getFMul(C1, C2);
+            C = ConstantExpr::getFDiv(ConstantFP::get(I.getType(), 1.0f), C);
+          }
+
+          const APFloat &C3 = cast<ConstantFP>(C)->getValueAPF();
+          if (C3.isNormal() && !C3.isDenormal()) {
+            Instruction *T = BinaryOperator::CreateFMul(X, C);
+            T->setFastMathFlags(I.getFastMathFlags());
+            return T;
+          }
+          return 0;
+        }
+      }
+    }
   }
 
+  if (I.hasUnsafeAlgebra() && isa<ConstantFP>(Op0)) {
+    ConstantFP *C1 = cast<ConstantFP>(Op0), *C2;
+    Constant *Fold = 0;
+    Value *X;
+    bool CreateDiv = true;
+
+    // C1 / (X*C2) => (C1/C2) / X
+    if (match(Op1, m_FMul(m_Value(X), m_ConstantFP(C2)))) {
+      Fold = ConstantExpr::getFDiv(C1, C2);
+    } else if (match(Op1, m_FDiv(m_Value(X), m_ConstantFP(C2)))) {
+      // C1 / (X/C2) => (C1*C2) / X
+      Fold = ConstantExpr::getFMul(C1, C2);
+    } else if (match(Op1, m_FDiv(m_Value(X), m_ConstantFP(C2)))) {
+      // C1 / (C2/X) => (C1/C2) * X
+      Fold = ConstantExpr::getFDiv(C1, C2);
+      CreateDiv = false;
+    }
+
+    if (Fold) {
+      const APFloat &FoldC = cast<ConstantFP>(Fold)->getValueAPF();
+      if (FoldC.isNormal() && !FoldC.isDenormal()) {
+        Instruction *R = CreateDiv ? 
+                         BinaryOperator::CreateFDiv(Fold, X) :
+                         BinaryOperator::CreateFMul(X, Fold);
+        R->setFastMathFlags(I.getFastMathFlags());
+        return R;
+      }
+
+      return 0;
+    }
+  }
+
+  if (I.hasUnsafeAlgebra()) {
+    Value *X, *Y;
+    Value *NewInst = 0;
+    Instruction *SimpR = 0;
+
+    if (Op0->hasOneUse() && match(Op0, m_FDiv(m_Value(X), m_Value(Y)))) {
+      // (X/Y) / Z => X / (Y*Z)
+      //
+      if (!isa<ConstantFP>(Y) || !isa<ConstantFP>(Op1)) {
+        NewInst = Builder->CreateFMul(Y, Op1);
+        SimpR = BinaryOperator::CreateFDiv(X, NewInst);
+      }
+    } else if (Op1->hasOneUse() && match(Op1, m_FDiv(m_Value(X), m_Value(Y)))) {
+      // Z / (X/Y) => Z*Y / X
+      //
+      if (!isa<ConstantFP>(Y) || !isa<ConstantFP>(Op0)) {
+        NewInst = Builder->CreateFMul(Op0, Y);
+        SimpR = BinaryOperator::CreateFDiv(NewInst, X);
+      }
+    }
+
+    if (NewInst) {
+      if (Instruction *T = dyn_cast<Instruction>(NewInst))
+        T->setDebugLoc(I.getDebugLoc());
+      SimpR->setFastMathFlags(I.getFastMathFlags());
+      return SimpR;
+    }
+  }
+
   return 0;
 }
 


More information about the llvm-commits mailing list