[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