[llvm] 1314012 - [InstCombine] Relax constraints of uses for exp(X) * exp(Y) -> exp(X + Y)

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 1 05:34:11 PDT 2021


Author: Daniil Seredkin
Date: 2021-06-01T08:33:23-04:00
New Revision: 13140120dcca64c35508880e10e14bcee3c54a58

URL: https://github.com/llvm/llvm-project/commit/13140120dcca64c35508880e10e14bcee3c54a58
DIFF: https://github.com/llvm/llvm-project/commit/13140120dcca64c35508880e10e14bcee3c54a58.diff

LOG: [InstCombine] Relax constraints of uses for exp(X) * exp(Y) -> exp(X + Y)

InstCombine didn't perform the transformations when fmul's operands were
the same instruction because it required to have one use for each of them
which is false in the case. This patch fixes this + adds tests for them
and introduces a new function isOnlyUserOfAnyOperand to check these cases
in a single place.

This patch is a result of discussion in D102574.

Differential Revision: https://reviews.llvm.org/D102698

Added: 
    

Modified: 
    llvm/include/llvm/IR/Instruction.h
    llvm/lib/IR/Instruction.cpp
    llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
    llvm/test/Transforms/InstCombine/fmul-exp.ll
    llvm/test/Transforms/InstCombine/fmul-exp2.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/IR/Instruction.h b/llvm/include/llvm/IR/Instruction.h
index 3e6402994bab..391fb32c9ca4 100644
--- a/llvm/include/llvm/IR/Instruction.h
+++ b/llvm/include/llvm/IR/Instruction.h
@@ -170,6 +170,11 @@ class Instruction : public User,
   bool isExceptionalTerminator() const {
     return isExceptionalTerminator(getOpcode());
   }
+
+  /// It checks if this instruction is the only user of at least one of
+  /// its operands.
+  bool isOnlyUserOfAnyOperand();
+
   bool isIndirectTerminator() const {
     return isIndirectTerminator(getOpcode());
   }

diff  --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp
index 8e0678f1cf58..a6fba2a7a240 100644
--- a/llvm/lib/IR/Instruction.cpp
+++ b/llvm/lib/IR/Instruction.cpp
@@ -117,6 +117,10 @@ bool Instruction::comesBefore(const Instruction *Other) const {
   return Order < Other->Order;
 }
 
+bool Instruction::isOnlyUserOfAnyOperand() {
+  return any_of(operands(), [](Value *V) { return V->hasOneUser(); });
+}
+
 void Instruction::setHasNoUnsignedWrap(bool b) {
   cast<OverflowingBinaryOperator>(this)->setHasNoUnsignedWrap(b);
 }

diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index e164a6122b70..bb962e639c61 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -556,20 +556,18 @@ Instruction *InstCombinerImpl::visitFMul(BinaryOperator &I) {
     }
 
     // exp(X) * exp(Y) -> exp(X + Y)
-    // Match as long as at least one of exp has only one use.
     if (match(Op0, m_Intrinsic<Intrinsic::exp>(m_Value(X))) &&
         match(Op1, m_Intrinsic<Intrinsic::exp>(m_Value(Y))) &&
-        (Op0->hasOneUse() || Op1->hasOneUse())) {
+        I.isOnlyUserOfAnyOperand()) {
       Value *XY = Builder.CreateFAddFMF(X, Y, &I);
       Value *Exp = Builder.CreateUnaryIntrinsic(Intrinsic::exp, XY, &I);
       return replaceInstUsesWith(I, Exp);
     }
 
     // exp2(X) * exp2(Y) -> exp2(X + Y)
-    // Match as long as at least one of exp2 has only one use.
     if (match(Op0, m_Intrinsic<Intrinsic::exp2>(m_Value(X))) &&
         match(Op1, m_Intrinsic<Intrinsic::exp2>(m_Value(Y))) &&
-        (Op0->hasOneUse() || Op1->hasOneUse())) {
+        I.isOnlyUserOfAnyOperand()) {
       Value *XY = Builder.CreateFAddFMF(X, Y, &I);
       Value *Exp2 = Builder.CreateUnaryIntrinsic(Intrinsic::exp2, XY, &I);
       return replaceInstUsesWith(I, Exp2);

diff  --git a/llvm/test/Transforms/InstCombine/fmul-exp.ll b/llvm/test/Transforms/InstCombine/fmul-exp.ll
index 8e10ebf81234..625681519b22 100644
--- a/llvm/test/Transforms/InstCombine/fmul-exp.ll
+++ b/llvm/test/Transforms/InstCombine/fmul-exp.ll
@@ -65,19 +65,19 @@ define double @exp_a_exp_b_reassoc(double %a, double %b) {
   ret double %mul
 }
 
-; TODO: Multiple uses, but only 1 user.
-
 define double @exp_a_a(double %a) {
 ; CHECK-LABEL: @exp_a_a(
-; CHECK-NEXT:    [[T:%.*]] = call double @llvm.exp.f64(double [[A:%.*]])
-; CHECK-NEXT:    [[M:%.*]] = fmul reassoc double [[T]], [[T]]
-; CHECK-NEXT:    ret double [[M]]
+; CHECK-NEXT:    [[T:%.*]] = fadd reassoc double [[A:%.*]], [[A]]
+; CHECK-NEXT:    [[E:%.*]] = call reassoc double @llvm.exp.f64(double [[T]])
+; CHECK-NEXT:    ret double [[E]]
 ;
   %t = call double @llvm.exp.f64(double %a)
   %m = fmul reassoc double %t, %t
   ret double %m
 }
 
+; negative test
+
 define double @exp_a_a_extra_use(double %a) {
 ; CHECK-LABEL: @exp_a_a_extra_use(
 ; CHECK-NEXT:    [[T:%.*]] = call double @llvm.exp.f64(double [[A:%.*]])

diff  --git a/llvm/test/Transforms/InstCombine/fmul-exp2.ll b/llvm/test/Transforms/InstCombine/fmul-exp2.ll
index e2365105c432..e2dc867f1801 100644
--- a/llvm/test/Transforms/InstCombine/fmul-exp2.ll
+++ b/llvm/test/Transforms/InstCombine/fmul-exp2.ll
@@ -34,13 +34,11 @@ define double @exp2_a_exp2_b_multiple_uses(double %a, double %b) {
   ret double %mul
 }
 
-; TODO: Multiple uses, but only 1 user.
-
 define double @exp2_a_a(double %a) {
 ; CHECK-LABEL: @exp2_a_a(
-; CHECK-NEXT:    [[T:%.*]] = call double @llvm.exp2.f64(double [[A:%.*]])
-; CHECK-NEXT:    [[M:%.*]] = fmul reassoc double [[T]], [[T]]
-; CHECK-NEXT:    ret double [[M]]
+; CHECK-NEXT:    [[T:%.*]] = fadd reassoc double [[A:%.*]], [[A]]
+; CHECK-NEXT:    [[E:%.*]] = call reassoc double @llvm.exp2.f64(double [[T]])
+; CHECK-NEXT:    ret double [[E]]
 ;
   %t = call double @llvm.exp2.f64(double %a)
   %m = fmul reassoc double %t, %t


        


More information about the llvm-commits mailing list