diff --git a/llvm/include/llvm/IR/Instruction.h b/llvm/include/llvm/IR/Instruction.h --- a/llvm/include/llvm/IR/Instruction.h +++ b/llvm/include/llvm/IR/Instruction.h @@ -170,6 +170,11 @@ 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 --- a/llvm/lib/IR/Instruction.cpp +++ b/llvm/lib/IR/Instruction.cpp @@ -117,6 +117,10 @@ return Order < Other->Order; } +bool Instruction::isOnlyUserOfAnyOperand() { + return any_of(operands(), [](Value *V) { return V->hasOneUser(); }); +} + void Instruction::setHasNoUnsignedWrap(bool b) { cast(this)->setHasNoUnsignedWrap(b); } diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -556,20 +556,18 @@ } // 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(m_Value(X))) && match(Op1, m_Intrinsic(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(m_Value(X))) && match(Op1, m_Intrinsic(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 --- a/llvm/test/Transforms/InstCombine/fmul-exp.ll +++ b/llvm/test/Transforms/InstCombine/fmul-exp.ll @@ -65,19 +65,19 @@ 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 --- a/llvm/test/Transforms/InstCombine/fmul-exp2.ll +++ b/llvm/test/Transforms/InstCombine/fmul-exp2.ll @@ -34,13 +34,11 @@ 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