[PATCH] D102574: [InstCombine] Missed optimization for pow(x, y) * pow(x, z) with fast-math

Daniil Seredkin via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Sun May 16 04:03:21 PDT 2021


vdsered created this revision.
vdsered added reviewers: spatel, Quolyk.
vdsered added a project: LLVM.
Herald added a subscriber: hiraditya.
vdsered requested review of this revision.
Herald added a subscriber: llvm-commits.

If fast-math is set, then LLVM is free to do the following transformation pow(x, y) * pow(x, z) -> pow(x, y + z). This patch adds tests for this transformation and its implementation. See more https://bugs.llvm.org/show_bug.cgi?id=47205

It handles two cases

1. When operands of fmul are different instructions

%4 = call fast float @llvm.pow.f32(float %0, float %1)
%5 = call fast float @llvm.pow.f32(float %0, float %2)
%6 = fmul fast float %5, %4
-->
%3 = fadd fast float %1, %2
%4 = call fast float @llvm.pow.f32(float %0, float %3)

2. When operands of fmul are the same instruction

%4 = call fast float @llvm.pow.f32(float %0, float %1)
%5 = fmul fast float %4, %4

-->
%3 = fadd fast float %1, %1
%4 = call fast float @llvm.pow.f32(float %0, float %3)


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D102574

Files:
  llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
  llvm/test/Transforms/InstCombine/fmul-pow.ll


Index: llvm/test/Transforms/InstCombine/fmul-pow.ll
===================================================================
--- llvm/test/Transforms/InstCombine/fmul-pow.ll
+++ llvm/test/Transforms/InstCombine/fmul-pow.ll
@@ -78,13 +78,23 @@
 
 define double @pow_ab_x_pow_ac_reassoc(double %a, double %b, double %c) {
 ; CHECK-LABEL: @pow_ab_x_pow_ac_reassoc(
-; CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.pow.f64(double [[A:%.*]], double [[B:%.*]])
-; CHECK-NEXT:    [[TMP2:%.*]] = call double @llvm.pow.f64(double [[A]], double [[C:%.*]])
-; CHECK-NEXT:    [[MUL:%.*]] = fmul reassoc double [[TMP2]], [[TMP1]]
-; CHECK-NEXT:    ret double [[MUL]]
+; CHECK-NEXT:    [[TMP1:%.*]] = fadd double [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = call double @llvm.pow.f64(double [[A:%.*]], double [[TMP1]])
+; CHECK-NEXT:    ret double [[TMP2]]
 ;
   %1 = call double @llvm.pow.f64(double %a, double %b)
   %2 = call double @llvm.pow.f64(double %a, double %c)
   %mul = fmul reassoc double %2, %1
   ret double %mul
 }
+
+define double @pow_ab_reassoc(double %a, double %b) {
+; CHECK-LABEL: @pow_ab_reassoc(
+; CHECK-NEXT:    [[TMP1:%.*]] = fadd double [[B:%.*]], [[B]]
+; CHECK-NEXT:    [[TMP2:%.*]] = call double @llvm.pow.f64(double [[A:%.*]], double [[TMP1]])
+; CHECK-NEXT:    ret double [[TMP2]]
+;
+  %1 = call double @llvm.pow.f64(double %a, double %b)
+  %mul = fmul reassoc double %1, %1
+  ret double %mul
+}
Index: llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
===================================================================
--- llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -462,6 +462,28 @@
     return replaceInstUsesWith(I, V);
 
   if (I.hasAllowReassoc()) {
+    // pow(x, y) * pow(x, z) -> pow(x, y + z)
+    // If operands of fmul are equal and they have exactly two uses, then
+    // they have one user. It is useful for a case like the one below
+    //
+    // %2 = pow %0, %1
+    // %3 = fmul %2, %2
+    // -->
+    // %2 = fadd %1, %1
+    // %3 = pow %0, %2
+    if (Op0->hasOneUse() || Op1->hasOneUse() ||
+        (Op1 == Op0 && Op1->hasNUses(2))) {
+      Value *X, *Y, *Z;
+      if (match(Op0, m_Intrinsic<Intrinsic::pow>(m_Value(X), m_Value(Y))))
+        if (match(Op1,
+                  m_Intrinsic<Intrinsic::pow>(m_Specific(X), m_Value(Z)))) {
+          auto NewExpo = Builder.CreateFAdd(Y, Z);
+          auto NewPow = Builder.CreateIntrinsic(Intrinsic::pow, {X->getType()},
+                                                {X, NewExpo});
+          return replaceInstUsesWith(I, NewPow);
+        }
+    }
+
     // Reassociate constant RHS with another constant to form constant
     // expression.
     if (match(Op1, m_Constant(C)) && C->isFiniteNonZeroFP()) {


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D102574.345697.patch
Type: text/x-patch
Size: 2802 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20210516/0a29e118/attachment.bin>


More information about the llvm-commits mailing list