Index: llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -462,6 +462,27 @@ 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(m_Value(X), m_Value(Y)))) + if (match(Op1, + m_Intrinsic(m_Specific(X), m_Value(Z)))) { + auto *Expo = Builder.CreateFAdd(Y, Z); + auto *NewPow = Builder.CreateBinaryIntrinsic(Intrinsic::pow, X, Expo); + return replaceInstUsesWith(I, NewPow); + } + } + // Reassociate constant RHS with another constant to form constant // expression. if (match(Op1, m_Constant(C)) && C->isFiniteNonZeroFP()) { 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 +}