Index: lib/Transforms/InstCombine/InstCombineMulDivRem.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -461,6 +461,40 @@ return replaceInstUsesWith(I, Exp2); } + // pow(X, Y) * X -> pow(X, Y+1) + if (match(Op0, m_Intrinsic(m_Specific(Op1), m_Value(Y)))) { + Value *One = ConstantFP::get(Op0->getType(), 1.0); + Value *YIncr = Builder.CreateFAddFMF(Y, One, &I); + Value *Pow = Builder.CreateBinaryIntrinsic(Intrinsic::pow, Op1, YIncr, &I); + return replaceInstUsesWith(I, Pow); + } + + // (1/X) * pow(X, Y) -> pow(X, Y-1) + if (match(Op0, m_OneUse(m_FDiv(m_SpecificFP(1.0), m_Value(X)))) && + match(Op1, m_Intrinsic(m_Specific(X), m_Value(Y)))) { + Value *One = ConstantFP::get(Op0->getType(), 1.0); + Value *YDecr = Builder.CreateFSubFMF(Y, One, &I); + Value *Pow = Builder.CreateBinaryIntrinsic(Intrinsic::pow, X, YDecr, &I); + return replaceInstUsesWith(I, Pow); + } + + Value *Z; + // pow(X, Y) * pow(Z, Y) -> pow(X*Z, Y) + if (match(Op0, m_Intrinsic(m_Value(X), m_Value(Y))) && + match(Op1, m_Intrinsic(m_Value(Z), m_Specific(Y)))) { + Value *XZ = Builder.CreateFMulFMF(X, Z, &I); + Value *Pow = Builder.CreateBinaryIntrinsic(Intrinsic::pow, XZ, Y, &I); + return replaceInstUsesWith(I, Pow); + } + + // 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)))) { + Value *YZ = Builder.CreateFAddFMF(Y, Z, &I); + Value *Pow = Builder.CreateBinaryIntrinsic(Intrinsic::pow, X, YZ, &I); + return replaceInstUsesWith(I, Pow); + } + // (X*Y) * X => (X*X) * Y where Y != X // The purpose is two-fold: // 1) to form a power expression (of X). Index: test/Transforms/InstCombine/fmul-pow.ll =================================================================== --- test/Transforms/InstCombine/fmul-pow.ll +++ test/Transforms/InstCombine/fmul-pow.ll @@ -16,9 +16,9 @@ define double @pow_ab_a_reassoc(double %a, double %b) { ; CHECK-LABEL: @pow_ab_a_reassoc( -; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.pow.f64(double [[A:%.*]], double [[B:%.*]]) -; CHECK-NEXT: [[MUL:%.*]] = fmul reassoc double [[TMP1]], [[A]] -; CHECK-NEXT: ret double [[MUL]] +; CHECK-NEXT: [[TMP1:%.*]] = fadd reassoc double [[B:%.*]], 1.000000e+00 +; CHECK-NEXT: [[TMP2:%.*]] = call reassoc 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, %a @@ -27,10 +27,9 @@ define double @pow_ab_a_reassoc_commute(double %a, double %b) { ; CHECK-LABEL: @pow_ab_a_reassoc_commute( -; CHECK-NEXT: [[TMP1:%.*]] = fdiv double 1.000000e+00, [[A:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.pow.f64(double [[A]], double [[B:%.*]]) -; CHECK-NEXT: [[MUL:%.*]] = fmul reassoc double [[TMP1]], [[TMP2]] -; CHECK-NEXT: ret double [[MUL]] +; CHECK-NEXT: [[TMP1:%.*]] = fadd reassoc double [[B:%.*]], -1.000000e+00 +; CHECK-NEXT: [[TMP2:%.*]] = call reassoc double @llvm.pow.f64(double [[A:%.*]], double [[TMP1]]) +; CHECK-NEXT: ret double [[TMP2]] ; %1 = fdiv double 1.0, %a %2 = call double @llvm.pow.f64(double %a, double %b) @@ -53,10 +52,9 @@ define double @pow_ab_pow_cb_reassoc(double %a, double %b, double %c) { ; CHECK-LABEL: @pow_ab_pow_cb_reassoc( -; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.pow.f64(double [[A:%.*]], double [[B:%.*]]) -; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.pow.f64(double [[C:%.*]], double [[B]]) -; CHECK-NEXT: [[MUL:%.*]] = fmul reassoc double [[TMP2]], [[TMP1]] -; CHECK-NEXT: ret double [[MUL]] +; CHECK-NEXT: [[TMP1:%.*]] = fmul reassoc double [[C:%.*]], [[A:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = call reassoc double @llvm.pow.f64(double [[TMP1]], double [[B:%.*]]) +; CHECK-NEXT: ret double [[TMP2]] ; %1 = call double @llvm.pow.f64(double %a, double %b) %2 = call double @llvm.pow.f64(double %c, double %b) @@ -79,10 +77,9 @@ 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 reassoc double [[C:%.*]], [[B:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = call reassoc 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)