[llvm] [InstCombine] optimize exp(exp(x)) / exp(x) with fast-math (PR #66177)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 13 00:13:29 PDT 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
<details>
<summary>Changes</summary>
This patch enables us to replace exp(exp(x)) / exp(x) to exp(exp(x) - x) making us avoid the div instruction
Closes #65608
--
Full diff: https://github.com/llvm/llvm-project/pull/66177.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp (+12)
- (added) llvm/test/Transforms/InstCombine/fdiv-exp.ll (+55)
<pre>
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 86cacf979839126..692fcf01455835a 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1748,6 +1748,18 @@ Instruction *InstCombinerImpl::visitFDiv(BinaryOperator &I) {
if (Instruction *Mul = foldFDivPowDivisor(I, Builder))
return Mul;
+ Value *ExpX;
+ // exp(exp(X)) / exp(X) -> exp(exp(X) - X)
+ if (match(Op0, m_Intrinsic<Intrinsic::exp>(m_Value(ExpX))) &&
+ match(Op1, m_Intrinsic<Intrinsic::exp>(m_Value(X))) &&
+ match(ExpX, m_Intrinsic<Intrinsic::exp>(m_Specific(X)))) {
+ // check that exp(x) is only used in the div expression.
+ if (Op1->hasNUses(2)) {
+ Value *XY = Builder.CreateFSubFMF(ExpX, X, &I);
+ auto *NewPow = Builder.CreateUnaryIntrinsic(Intrinsic::exp, XY, &I);
+ return replaceInstUsesWith(I, NewPow);
+ }
+ }
// pow(X, Y) / X --> pow(X, Y-1)
if (I.hasAllowReassoc() &&
diff --git a/llvm/test/Transforms/InstCombine/fdiv-exp.ll b/llvm/test/Transforms/InstCombine/fdiv-exp.ll
new file mode 100644
index 000000000000000..3ea281cd4bb3af5
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/fdiv-exp.ll
@@ -0,0 +1,55 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+
+define double @fdiv_exp(double %x) {
+; CHECK-LABEL: define double @fdiv_exp
+; CHECK-SAME: (double [[X:%.*]]) {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[EXP_X:%.*]] = call fast double @llvm.exp.f64(double [[X]])
+; CHECK-NEXT: [[TMP0:%.*]] = fsub fast double [[EXP_X]], [[X]]
+; CHECK-NEXT: [[DIV:%.*]] = call fast double @llvm.exp.f64(double [[TMP0]])
+; CHECK-NEXT: ret double [[DIV]]
+;
+entry:
+ %exp_x = call fast double @llvm.exp.f64(double %x)
+ %exp_exp_x = call fast double @llvm.exp.f64(double %exp_x)
+ %div = fdiv fast double %exp_exp_x, %exp_x
+ ret double %div
+}
+
+define double @fdiv_exp_multiple_uses(double %x) {
+; CHECK-LABEL: define double @fdiv_exp_multiple_uses
+; CHECK-SAME: (double [[X:%.*]]) {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[EXP_X:%.*]] = call fast double @llvm.exp.f64(double [[X]])
+; CHECK-NEXT: [[EXP_EXP_X:%.*]] = call fast double @llvm.exp.f64(double [[EXP_X]])
+; CHECK-NEXT: [[DIV:%.*]] = fdiv fast double [[EXP_EXP_X]], [[EXP_X]]
+; CHECK-NEXT: call void @use(double [[EXP_X]])
+; CHECK-NEXT: ret double [[DIV]]
+;
+entry:
+ %exp_x = call fast double @llvm.exp.f64(double %x)
+ %exp_exp_x = call fast double @llvm.exp.f64(double %exp_x)
+ %div = fdiv fast double %exp_exp_x, %exp_x
+ call void @use(double %exp_x)
+ ret double %div
+}
+
+define double @fdiv_exp_swapped(double %x) {
+; CHECK-LABEL: define double @fdiv_exp_swapped
+; CHECK-SAME: (double [[X:%.*]]) {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[EXP_X:%.*]] = call fast double @llvm.exp.f64(double [[X]])
+; CHECK-NEXT: [[TMP0:%.*]] = fsub fast double [[X]], [[EXP_X]]
+; CHECK-NEXT: [[DIV:%.*]] = call fast double @llvm.exp.f64(double [[TMP0]])
+; CHECK-NEXT: ret double [[DIV]]
+;
+entry:
+ %exp_x = call fast double @llvm.exp.f64(double %x)
+ %exp_exp_x = call fast double @llvm.exp.f64(double %exp_x)
+ %div = fdiv fast double %exp_x, %exp_exp_x
+ ret double %div
+}
+
+declare double @llvm.exp.f64(double)
+declare void @use(double)
</pre>
</details>
https://github.com/llvm/llvm-project/pull/66177
More information about the llvm-commits
mailing list