[llvm] [InstCombine] optimize powi(X,Y)/X with Ofast (PR #67236)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 20 05:29:17 PDT 2023
https://github.com/vfdff updated https://github.com/llvm/llvm-project/pull/67236
>From f0eb3072d1e197781a524dfa7a326f342e8e1408 Mon Sep 17 00:00:00 2001
From: zhongyunde 00443407 <zhongyunde at huawei.com>
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 20fe25c50a3ffc0..a596bba7b0e2150 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 ae454ef0b99fde772051deb0641c86f9534811da Mon Sep 17 00:00:00 2001
From: zhongyunde 00443407 <zhongyunde at huawei.com>
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 | 16 ++++++++++++++++
llvm/test/Transforms/InstCombine/powi.ll | 6 ++----
2 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 518f8aa51c0cd29..b15dcda18ab9b6b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1780,6 +1780,22 @@ 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<Intrinsic::powi>(m_Specific(Op1),
+ m_Value(Y)))) &&
+ computeOverflowForSignedSub(Y, ConstantInt::get(Y->getType(), 1),
+ &I) == OverflowResult::NeverOverflows) {
+ 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 a596bba7b0e2150..89efbb6f4536113 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)
More information about the llvm-commits
mailing list