From 6cbcbecf53a83e7a9b3b9fc2fd1a1d8a82a04892 Mon Sep 17 00:00:00 2001 From: zhongyunde 00443407 Date: Sun, 24 Sep 2023 02:34:09 -0400 Subject: [PATCH 1/2] [InstCombine] Precommit tests for PR67216 --- llvm/test/Transforms/InstCombine/powi.ll | 85 ++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/llvm/test/Transforms/InstCombine/powi.ll b/llvm/test/Transforms/InstCombine/powi.ll index 20fe25c50a3ff..a596bba7b0e21 100644 --- a/llvm/test/Transforms/InstCombine/powi.ll +++ b/llvm/test/Transforms/InstCombine/powi.ll @@ -2,6 +2,7 @@ ; RUN: opt -passes=instcombine -S < %s | FileCheck %s declare double @llvm.powi.f64.i32(double, i32) +declare float @llvm.powi.f32.i32(float, i32) declare double @llvm.powi.f64.i64(double, i64) declare double @llvm.fabs.f64(double) declare double @llvm.copysign.f64(double, double) @@ -258,3 +259,87 @@ define double @different_types_powi(double %x, i32 %y, i64 %z) { %mul = fmul reassoc double %p2, %p1 ret double %mul } + +define double @fdiv_pow_powi(double %x) { +; CHECK-LABEL: @fdiv_pow_powi( +; CHECK-NEXT: [[P1:%.*]] = call double @llvm.powi.f64.i32(double [[X:%.*]], i32 3) +; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc nnan double [[P1]], [[X]] +; CHECK-NEXT: ret double [[DIV]] +; + %p1 = call double @llvm.powi.f64.i32(double %x, i32 3) + %div = fdiv reassoc nnan double %p1, %x + ret double %div +} + +define float @fdiv_powf_powi(float %x) { +; CHECK-LABEL: @fdiv_powf_powi( +; CHECK-NEXT: [[P1:%.*]] = call float @llvm.powi.f32.i32(float [[X:%.*]], i32 100) +; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc nnan float [[P1]], [[X]] +; CHECK-NEXT: ret float [[DIV]] +; + %p1 = call float @llvm.powi.f32.i32(float %x, i32 100) + %div = fdiv reassoc nnan float %p1, %x + ret float %div +} + +; TODO: Multi-use may be also better off creating Powi(x,y-1) then creating +; (mul, Powi(x,y-1),x) to replace the Powi(x,y). +define double @fdiv_pow_powi_multi_use(double %x) { +; CHECK-LABEL: @fdiv_pow_powi_multi_use( +; CHECK-NEXT: [[P1:%.*]] = call double @llvm.powi.f64.i32(double [[X:%.*]], i32 3) +; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc nnan double [[P1]], [[X]] +; CHECK-NEXT: tail call void @use(double [[P1]]) +; CHECK-NEXT: ret double [[DIV]] +; + %p1 = call double @llvm.powi.f64.i32(double %x, i32 3) + %div = fdiv reassoc nnan double %p1, %x + tail call void @use(double %p1) + ret double %div +} + +; Negative test: Miss part of the fmf flag for the fdiv instruction +define float @fdiv_powf_powi_missing_reassoc(float %x) { +; CHECK-LABEL: @fdiv_powf_powi_missing_reassoc( +; CHECK-NEXT: [[P1:%.*]] = call float @llvm.powi.f32.i32(float [[X:%.*]], i32 100) +; CHECK-NEXT: [[DIV:%.*]] = fdiv nnan float [[P1]], [[X]] +; CHECK-NEXT: ret float [[DIV]] +; + %p1 = call float @llvm.powi.f32.i32(float %x, i32 100) + %div = fdiv nnan float %p1, %x + ret float %div +} + +define float @fdiv_powf_powi_missing_nnan(float %x) { +; CHECK-LABEL: @fdiv_powf_powi_missing_nnan( +; CHECK-NEXT: [[P1:%.*]] = call float @llvm.powi.f32.i32(float [[X:%.*]], i32 100) +; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc float [[P1]], [[X]] +; CHECK-NEXT: ret float [[DIV]] +; + %p1 = call float @llvm.powi.f32.i32(float %x, i32 100) + %div = fdiv reassoc float %p1, %x + ret float %div +} + +; Negative test: Illegal because (Y - 1) wraparound +define double @fdiv_pow_powi_negative(double %x) { +; CHECK-LABEL: @fdiv_pow_powi_negative( +; CHECK-NEXT: [[P1:%.*]] = call double @llvm.powi.f64.i32(double [[X:%.*]], i32 -2147483648) +; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc nnan double [[P1]], [[X]] +; CHECK-NEXT: ret double [[DIV]] +; + %p1 = call double @llvm.powi.f64.i32(double %x, i32 -2147483648) ; INT_MIN + %div = fdiv reassoc nnan double %p1, %x + ret double %div +} + +; Negative test: The 2nd powi argument is a variable +define double @fdiv_pow_powi_negative_variable(double %x, i32 %y) { +; CHECK-LABEL: @fdiv_pow_powi_negative_variable( +; CHECK-NEXT: [[P1:%.*]] = call double @llvm.powi.f64.i32(double [[X:%.*]], i32 [[Y:%.*]]) +; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc nnan double [[P1]], [[X]] +; CHECK-NEXT: ret double [[DIV]] +; + %p1 = call double @llvm.powi.f64.i32(double %x, i32 %y) + %div = fdiv reassoc nnan double %p1, %x + ret double %div +} From fd7383846ff89ec97b9466e9657fbe02abadc782 Mon Sep 17 00:00:00 2001 From: zhongyunde 00443407 Date: Sun, 8 Oct 2023 02:56:55 -0400 Subject: [PATCH 2/2] [InstCombine] optimize powi(X,Y)/X with Ofast Try to transform the powi(X, Y) / X into powi(X, Y-1) with Ofast. For this case, when the Y is 3, then powi(X, 2) is replaced by X * X in the further step. Fixes https://github.com/llvm/llvm-project/pull/67216 --- .../InstCombine/InstCombineMulDivRem.cpp | 15 +++++++++++++++ llvm/test/Transforms/InstCombine/powi.ll | 6 ++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp index 518f8aa51c0cd..bc784390c23be 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -1780,6 +1780,21 @@ Instruction *InstCombinerImpl::visitFDiv(BinaryOperator &I) { return replaceInstUsesWith(I, Pow); } + // powi(X, Y) / X --> powi(X, Y-1) + // This is legal when (Y - 1) can't wraparound, in which case reassoc and nnan + // are required. + // TODO: Multi-use may be also better off creating Powi(x,y-1) + if (I.hasAllowReassoc() && I.hasNoNaNs() && + match(Op0, m_OneUse(m_Intrinsic(m_Specific(Op1), + m_Value(Y)))) && + willNotOverflowSignedSub(Y, ConstantInt::get(Y->getType(), 1), I)) { + Constant *NegOne = ConstantInt::getAllOnesValue(Y->getType()); + Value *Y1 = Builder.CreateAdd(Y, NegOne); + Type *Types[] = {Op1->getType(), Y1->getType()}; + Value *Pow = Builder.CreateIntrinsic(Intrinsic::powi, Types, {Op1, Y1}, &I); + return replaceInstUsesWith(I, Pow); + } + return nullptr; } diff --git a/llvm/test/Transforms/InstCombine/powi.ll b/llvm/test/Transforms/InstCombine/powi.ll index a596bba7b0e21..89efbb6f45361 100644 --- a/llvm/test/Transforms/InstCombine/powi.ll +++ b/llvm/test/Transforms/InstCombine/powi.ll @@ -262,8 +262,7 @@ define double @different_types_powi(double %x, i32 %y, i64 %z) { define double @fdiv_pow_powi(double %x) { ; CHECK-LABEL: @fdiv_pow_powi( -; CHECK-NEXT: [[P1:%.*]] = call double @llvm.powi.f64.i32(double [[X:%.*]], i32 3) -; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc nnan double [[P1]], [[X]] +; CHECK-NEXT: [[DIV:%.*]] = fmul reassoc nnan double [[X:%.*]], [[X]] ; CHECK-NEXT: ret double [[DIV]] ; %p1 = call double @llvm.powi.f64.i32(double %x, i32 3) @@ -273,8 +272,7 @@ define double @fdiv_pow_powi(double %x) { define float @fdiv_powf_powi(float %x) { ; CHECK-LABEL: @fdiv_powf_powi( -; CHECK-NEXT: [[P1:%.*]] = call float @llvm.powi.f32.i32(float [[X:%.*]], i32 100) -; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc nnan float [[P1]], [[X]] +; CHECK-NEXT: [[DIV:%.*]] = call reassoc nnan float @llvm.powi.f32.i32(float [[X:%.*]], i32 99) ; CHECK-NEXT: ret float [[DIV]] ; %p1 = call float @llvm.powi.f32.i32(float %x, i32 100)