diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp index 278be6233f4b8..55d89c6108f03 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -683,6 +683,18 @@ Instruction *InstCombinerImpl::foldFMulReassoc(BinaryOperator &I) { return replaceInstUsesWith(I, Pow); } + // powi(X, Y) * X --> powi(X, Y+1) + // X * powi(X, Y) --> powi(X, Y+1) + if (match(&I, m_c_FMul(m_OneUse(m_Intrinsic(m_Value(X), + m_Value(Y))), + m_Deferred(X))) && + willNotOverflowSignedAdd(Y, ConstantInt::get(Y->getType(), 1), I)) { + auto *Y1 = Builder.CreateAdd(Y, ConstantInt::get(Y->getType(), 1)); + auto *NewPow = Builder.CreateIntrinsic( + Intrinsic::powi, {X->getType(), Y1->getType()}, {X, Y1}, &I); + return replaceInstUsesWith(I, NewPow); + } + if (I.isOnlyUserOfAnyOperand()) { // pow(X, Y) * pow(X, Z) -> pow(X, Y + Z) if (match(Op0, m_Intrinsic(m_Value(X), m_Value(Y))) && diff --git a/llvm/test/Transforms/InstCombine/powi.ll b/llvm/test/Transforms/InstCombine/powi.ll index 89efbb6f45361..95722d09a17ad 100644 --- a/llvm/test/Transforms/InstCombine/powi.ll +++ b/llvm/test/Transforms/InstCombine/powi.ll @@ -341,3 +341,52 @@ define double @fdiv_pow_powi_negative_variable(double %x, i32 %y) { %div = fdiv reassoc nnan double %p1, %x ret double %div } + +; powi(X, Y) * X --> powi(X, Y+1) +define double @powi_fmul_powi_x(double noundef %x) { +; CHECK-LABEL: @powi_fmul_powi_x( +; CHECK-NEXT: [[MUL:%.*]] = call reassoc double @llvm.powi.f64.i32(double [[X:%.*]], i32 4) +; CHECK-NEXT: ret double [[MUL]] +; + %p1 = tail call double @llvm.powi.f64.i32(double %x, i32 3) + %mul = fmul reassoc double %p1, %x + ret double %mul +} + +; Negative test: Multi-use +define double @powi_fmul_powi_x_multi_use(double noundef %x) { +; CHECK-LABEL: @powi_fmul_powi_x_multi_use( +; CHECK-NEXT: [[P1:%.*]] = tail call double @llvm.powi.f64.i32(double [[X:%.*]], i32 3) +; CHECK-NEXT: tail call void @use(double [[P1]]) +; CHECK-NEXT: [[MUL:%.*]] = fmul reassoc double [[P1]], [[X]] +; CHECK-NEXT: ret double [[MUL]] +; + %p1 = tail call double @llvm.powi.f64.i32(double %x, i32 3) + tail call void @use(double %p1) + %mul = fmul reassoc double %p1, %x + ret double %mul +} + +; Negative test: Miss fmf flag +define double @powi_fmul_powi_x_missing_reassoc(double noundef %x) { +; CHECK-LABEL: @powi_fmul_powi_x_missing_reassoc( +; CHECK-NEXT: [[P1:%.*]] = tail call double @llvm.powi.f64.i32(double [[X:%.*]], i32 3) +; CHECK-NEXT: [[MUL:%.*]] = fmul double [[P1]], [[X]] +; CHECK-NEXT: ret double [[MUL]] +; + %p1 = tail call double @llvm.powi.f64.i32(double %x, i32 3) + %mul = fmul double %p1, %x + ret double %mul +} + +; Negative test: overflow +define double @powi_fmul_powi_x_overflow(double noundef %x) { +; CHECK-LABEL: @powi_fmul_powi_x_overflow( +; CHECK-NEXT: [[P1:%.*]] = tail call double @llvm.powi.f64.i32(double [[X:%.*]], i32 2147483647) +; CHECK-NEXT: [[MUL:%.*]] = fmul reassoc double [[P1]], [[X]] +; CHECK-NEXT: ret double [[MUL]] +; + %p1 = tail call double @llvm.powi.f64.i32(double %x, i32 2147483647) ; INT_MAX + %mul = fmul reassoc double %p1, %x + ret double %mul +}