Index: llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -555,22 +555,30 @@ } } - // exp(X) * exp(Y) -> exp(X + Y) - if (match(Op0, m_Intrinsic(m_Value(X))) && - match(Op1, m_Intrinsic(m_Value(Y))) && - I.isOnlyUserOfAnyOperand()) { - Value *XY = Builder.CreateFAddFMF(X, Y, &I); - Value *Exp = Builder.CreateUnaryIntrinsic(Intrinsic::exp, XY, &I); - return replaceInstUsesWith(I, Exp); - } + if (I.isOnlyUserOfAnyOperand()) { + // pow(x, y) * pow(x, z) -> pow(x, y + z) + if (match(Op0, m_Intrinsic(m_Value(X), m_Value(Y))) && + match(Op1, m_Intrinsic(m_Specific(X), m_Value(Z)))) { + auto *YZ = Builder.CreateFAddFMF(Y, Z, &I); + auto *NewPow = Builder.CreateBinaryIntrinsic(Intrinsic::pow, X, YZ, &I); + return replaceInstUsesWith(I, NewPow); + } - // exp2(X) * exp2(Y) -> exp2(X + Y) - if (match(Op0, m_Intrinsic(m_Value(X))) && - match(Op1, m_Intrinsic(m_Value(Y))) && - I.isOnlyUserOfAnyOperand()) { - Value *XY = Builder.CreateFAddFMF(X, Y, &I); - Value *Exp2 = Builder.CreateUnaryIntrinsic(Intrinsic::exp2, XY, &I); - return replaceInstUsesWith(I, Exp2); + // exp(X) * exp(Y) -> exp(X + Y) + if (match(Op0, m_Intrinsic(m_Value(X))) && + match(Op1, m_Intrinsic(m_Value(Y)))) { + 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) + if (match(Op0, m_Intrinsic(m_Value(X))) && + match(Op1, m_Intrinsic(m_Value(Y)))) { + Value *XY = Builder.CreateFAddFMF(X, Y, &I); + Value *Exp2 = Builder.CreateUnaryIntrinsic(Intrinsic::exp2, XY, &I); + return replaceInstUsesWith(I, Exp2); + } } // (X*Y) * X => (X*X) * Y where Y != X Index: llvm/test/Transforms/InstCombine/fmul-pow.ll =================================================================== --- llvm/test/Transforms/InstCombine/fmul-pow.ll +++ llvm/test/Transforms/InstCombine/fmul-pow.ll @@ -2,6 +2,7 @@ ; RUN: opt -S -instcombine < %s | FileCheck %s declare double @llvm.pow.f64(double, double) +declare void @use(double) define double @pow_ab_a(double %a, double %b) { ; CHECK-LABEL: @pow_ab_a( @@ -78,13 +79,68 @@ 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: [[T1:%.*]] = fadd reassoc double [[C:%.*]], [[B:%.*]] +; CHECK-NEXT: [[T2:%.*]] = call reassoc double @llvm.pow.f64(double [[A:%.*]], double [[T1]]) +; CHECK-NEXT: ret double [[T2]] ; %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: [[T1:%.*]] = fadd reassoc double [[B:%.*]], [[B]] +; CHECK-NEXT: [[T2:%.*]] = call reassoc double @llvm.pow.f64(double [[A:%.*]], double [[T1]]) +; CHECK-NEXT: ret double [[T2]] +; + %1 = call double @llvm.pow.f64(double %a, double %b) + %mul = fmul reassoc double %1, %1 + ret double %mul +} + +define double @pow_ab_reassoc_extra_use(double %a, double %b) { +; CHECK-LABEL: @pow_ab_reassoc_extra_use( +; CHECK-NEXT: [[T1:%.*]] = call double @llvm.pow.f64(double [[A:%.*]], double [[B:%.*]]) +; CHECK-NEXT: [[M:%.*]] = fmul reassoc double [[T1]], [[T1]] +; CHECK-NEXT: call void @use(double [[T1]]) +; CHECK-NEXT: ret double [[M]] +; + %1 = call double @llvm.pow.f64(double %a, double %b) + %mul = fmul reassoc double %1, %1 + call void @use(double %1) + ret double %mul +} + +define double @pow_ab_x_pow_ac_reassoc_extra_use(double %a, double %b, double %c) { +; CHECK-LABEL: @pow_ab_x_pow_ac_reassoc_extra_use( +; CHECK-NEXT: [[T1:%.*]] = call double @llvm.pow.f64(double [[A:%.*]], double [[B:%.*]]) +; CHECK-NEXT: [[T2:%.*]] = fadd reassoc double [[B]], [[C:%.*]] +; CHECK-NEXT: [[T3:%.*]] = call reassoc double @llvm.pow.f64(double [[A]], double [[T2]]) +; CHECK-NEXT: call void @use(double [[T1]]) +; CHECK-NEXT: ret double [[T3]] +; + %1 = call double @llvm.pow.f64(double %a, double %b) + %2 = call double @llvm.pow.f64(double %a, double %c) + %mul = fmul reassoc double %1, %2 + call void @use(double %1) + ret double %mul +} + +define double @pow_ab_x_pow_ac_reassoc_multiple_uses(double %a, double %b, double %c) { +; CHECK-LABEL: @pow_ab_x_pow_ac_reassoc_multiple_uses( +; CHECK-NEXT: [[T1:%.*]] = call double @llvm.pow.f64(double [[A:%.*]], double [[B:%.*]]) +; CHECK-NEXT: [[T2:%.*]] = call double @llvm.pow.f64(double [[A]], double [[C:%.*]]) +; CHECK-NEXT: %mul = fmul reassoc double [[T1]], [[T2]] +; CHECK-NEXT: call void @use(double [[T1]]) +; CHECK-NEXT: call void @use(double [[T2]]) +; CHECK-NEXT: ret double %mul +; + %1 = call double @llvm.pow.f64(double %a, double %b) + %2 = call double @llvm.pow.f64(double %a, double %c) + %mul = fmul reassoc double %1, %2 + call void @use(double %1) + call void @use(double %2) + ret double %mul +} \ No newline at end of file