[llvm] [InstCombine] Fold afn powi(2.0, x) to ldexp(1.0, x) (PR #202114)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 8 02:38:30 PDT 2026
https://github.com/jjppp updated https://github.com/llvm/llvm-project/pull/202114
>From 735adc3512e3e7d581c4e683b1be6bf069c1059c Mon Sep 17 00:00:00 2001
From: jpwang <jpwang at smail.nju.edu.cn>
Date: Sun, 7 Jun 2026 16:39:21 +0800
Subject: [PATCH 1/4] [InstCombine] Fold afn powi(2.0, x) to ldexp(1.0, x)
---
.../lib/Transforms/InstCombine/InstCombineCalls.cpp | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 7bcaa930511ee..e17b78a0a825c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -2493,7 +2493,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
if (auto *SkippedBarrier = simplifyInvariantGroupIntrinsic(*II, *this))
return replaceInstUsesWith(*II, SkippedBarrier);
break;
- case Intrinsic::powi:
+ case Intrinsic::powi: {
if (ConstantInt *Power = dyn_cast<ConstantInt>(II->getArgOperand(1))) {
// 0 and 1 are handled in instsimplify
// powi(x, -1) -> 1/x
@@ -2518,7 +2518,18 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
return replaceOperand(*II, 0, X);
}
}
+ if (ConstantFP *Base = dyn_cast<ConstantFP>(II->getArgOperand(0))) {
+ Value *Exp = II->getArgOperand(1);
+ // powi(2.0, p) -> ldexp(1.0, p)
+ if (Base->isExactlyValue(2.f) && II->hasApproxFunc()) {
+ ConstantFP *One = ConstantFP::get(Base->getType(), 1.0);
+ Value *Ldexp = Builder.CreateIntrinsic(
+ Intrinsic::ldexp, {II->getType(), Exp->getType()}, {One, Exp}, II);
+ return replaceInstUsesWith(*II, Ldexp);
+ }
+ }
break;
+ }
case Intrinsic::cttz:
case Intrinsic::ctlz:
>From 76bcbe925beda3e255ba049279aeaf71b24069f3 Mon Sep 17 00:00:00 2001
From: jpwang <jpwang at smail.nju.edu.cn>
Date: Mon, 8 Jun 2026 11:58:24 +0800
Subject: [PATCH 2/4] [InstCombine] Add tests
---
llvm/test/Transforms/InstCombine/powi.ll | 29 ++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/powi.ll b/llvm/test/Transforms/InstCombine/powi.ll
index aa78209270ae8..aca275fb49418 100644
--- a/llvm/test/Transforms/InstCombine/powi.ll
+++ b/llvm/test/Transforms/InstCombine/powi.ll
@@ -646,3 +646,32 @@ define <3 x float> @powi_unary_shuffle_ops_use(<3 x float> %x, i32 %power, ptr %
%r = call <3 x float> @llvm.powi(<3 x float> %sx, i32 %power)
ret <3 x float> %r
}
+
+; Negative test: Missing afn flag on call
+define float @pow_i_2_ldexp_1_no_afn(i32 %i) {
+; CHECK-LABEL: @pow_i_2_ldexp_1_no_afn(
+; CHECK-NEXT: [[TMP1:%.*]] = tail call float @llvm.powi.f32.i32(float 2.000000e+00, i32 [[I:%.*]])
+; CHECK-NEXT: ret float [[TMP1]]
+;
+ %1 = tail call float @llvm.powi.f32.i32(float 2.000000e+00, i32 %i)
+ ret float %1
+}
+
+define float @pow_i_2_ldexp_1_afn(i32 %i) {
+; CHECK-LABEL: @pow_i_2_ldexp_1_afn(
+; CHECK-NEXT: [[TMP1:%.*]] = call afn float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[I:%.*]])
+; CHECK-NEXT: ret float [[TMP1]]
+;
+ %1 = tail call afn float @llvm.powi.f32.i32(float 2.000000e+00, i32 %i)
+ ret float %1
+}
+
+define float @a_fmul_pow_i_2_ldexp_a_afn(float %a, i32 %i) {
+; CHECK-LABEL: @a_fmul_pow_i_2_ldexp_a_afn(
+; CHECK-NEXT: [[TMP1:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[A:%.*]], i32 [[I:%.*]])
+; CHECK-NEXT: ret float [[TMP1]]
+;
+ %1 = tail call afn reassoc float @llvm.powi.f32.i32(float 2.000000e+00, i32 %i)
+ %2 = fmul reassoc float %a, %1
+ ret float %2
+}
>From 1105f702ec915020a1e49d77cb2ff310d2929c3c Mon Sep 17 00:00:00 2001
From: jpwang <jpwang at smail.nju.edu.cn>
Date: Mon, 8 Jun 2026 17:18:56 +0800
Subject: [PATCH 3/4] [InstCombine] Update tests for f64
---
llvm/test/Transforms/InstCombine/powi.ll | 31 +++++++++++++++++++-----
1 file changed, 25 insertions(+), 6 deletions(-)
diff --git a/llvm/test/Transforms/InstCombine/powi.ll b/llvm/test/Transforms/InstCombine/powi.ll
index aca275fb49418..291066528cf35 100644
--- a/llvm/test/Transforms/InstCombine/powi.ll
+++ b/llvm/test/Transforms/InstCombine/powi.ll
@@ -648,8 +648,8 @@ define <3 x float> @powi_unary_shuffle_ops_use(<3 x float> %x, i32 %power, ptr %
}
; Negative test: Missing afn flag on call
-define float @pow_i_2_ldexp_1_no_afn(i32 %i) {
-; CHECK-LABEL: @pow_i_2_ldexp_1_no_afn(
+define float @pow_i_2_ldexp_1_no_afn_f32(i32 %i) {
+; CHECK-LABEL: @pow_i_2_ldexp_1_no_afn_f32(
; CHECK-NEXT: [[TMP1:%.*]] = tail call float @llvm.powi.f32.i32(float 2.000000e+00, i32 [[I:%.*]])
; CHECK-NEXT: ret float [[TMP1]]
;
@@ -657,8 +657,8 @@ define float @pow_i_2_ldexp_1_no_afn(i32 %i) {
ret float %1
}
-define float @pow_i_2_ldexp_1_afn(i32 %i) {
-; CHECK-LABEL: @pow_i_2_ldexp_1_afn(
+define float @pow_i_2_ldexp_1_afn_f32(i32 %i) {
+; CHECK-LABEL: @pow_i_2_ldexp_1_afn_f32(
; CHECK-NEXT: [[TMP1:%.*]] = call afn float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[I:%.*]])
; CHECK-NEXT: ret float [[TMP1]]
;
@@ -666,8 +666,8 @@ define float @pow_i_2_ldexp_1_afn(i32 %i) {
ret float %1
}
-define float @a_fmul_pow_i_2_ldexp_a_afn(float %a, i32 %i) {
-; CHECK-LABEL: @a_fmul_pow_i_2_ldexp_a_afn(
+define float @a_fmul_pow_i_2_ldexp_a_afn_f32(float %a, i32 %i) {
+; CHECK-LABEL: @a_fmul_pow_i_2_ldexp_a_afn_f32(
; CHECK-NEXT: [[TMP1:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[A:%.*]], i32 [[I:%.*]])
; CHECK-NEXT: ret float [[TMP1]]
;
@@ -675,3 +675,22 @@ define float @a_fmul_pow_i_2_ldexp_a_afn(float %a, i32 %i) {
%2 = fmul reassoc float %a, %1
ret float %2
}
+
+define double @pow_i_2_ldexp_1_afn_f64(i32 %i) {
+; CHECK-LABEL: @pow_i_2_ldexp_1_afn_f64(
+; CHECK-NEXT: [[TMP1:%.*]] = call afn double @llvm.ldexp.f64.i32(double 1.000000e+00, i32 [[I:%.*]])
+; CHECK-NEXT: ret double [[TMP1]]
+;
+ %1 = tail call afn double @llvm.powi.f64.i32(double 2.000000e+00, i32 %i)
+ ret double %1
+}
+
+define double @a_fmul_pow_i_2_ldexp_a_afn_f64(double %a, i32 %i) {
+; CHECK-LABEL: @a_fmul_pow_i_2_ldexp_a_afn_f64(
+; CHECK-NEXT: [[TMP1:%.*]] = call reassoc double @llvm.ldexp.f64.i32(double [[A:%.*]], i32 [[I:%.*]])
+; CHECK-NEXT: ret double [[TMP1]]
+;
+ %1 = tail call afn reassoc double @llvm.powi.f64.i32(double 2.000000e+00, i32 %i)
+ %2 = fmul reassoc double %a, %1
+ ret double %2
+}
>From 6bf85ceaa0f66ceb7c3be614bb8c20b613d8651e Mon Sep 17 00:00:00 2001
From: jpwang <jpwang at smail.nju.edu.cn>
Date: Mon, 8 Jun 2026 17:38:13 +0800
Subject: [PATCH 4/4] [InstCombine] Rename tests for better readability
---
llvm/test/Transforms/InstCombine/powi.ll | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/llvm/test/Transforms/InstCombine/powi.ll b/llvm/test/Transforms/InstCombine/powi.ll
index 291066528cf35..f8f965125d915 100644
--- a/llvm/test/Transforms/InstCombine/powi.ll
+++ b/llvm/test/Transforms/InstCombine/powi.ll
@@ -648,8 +648,8 @@ define <3 x float> @powi_unary_shuffle_ops_use(<3 x float> %x, i32 %power, ptr %
}
; Negative test: Missing afn flag on call
-define float @pow_i_2_ldexp_1_no_afn_f32(i32 %i) {
-; CHECK-LABEL: @pow_i_2_ldexp_1_no_afn_f32(
+define float @pow_2_i_ldexp_1_i_no_afn_f32(i32 %i) {
+; CHECK-LABEL: @pow_2_i_ldexp_1_i_no_afn_f32(
; CHECK-NEXT: [[TMP1:%.*]] = tail call float @llvm.powi.f32.i32(float 2.000000e+00, i32 [[I:%.*]])
; CHECK-NEXT: ret float [[TMP1]]
;
@@ -657,8 +657,8 @@ define float @pow_i_2_ldexp_1_no_afn_f32(i32 %i) {
ret float %1
}
-define float @pow_i_2_ldexp_1_afn_f32(i32 %i) {
-; CHECK-LABEL: @pow_i_2_ldexp_1_afn_f32(
+define float @pow_2_i_ldexp_1_i_afn_f32(i32 %i) {
+; CHECK-LABEL: @pow_2_i_ldexp_1_i_afn_f32(
; CHECK-NEXT: [[TMP1:%.*]] = call afn float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[I:%.*]])
; CHECK-NEXT: ret float [[TMP1]]
;
@@ -666,8 +666,8 @@ define float @pow_i_2_ldexp_1_afn_f32(i32 %i) {
ret float %1
}
-define float @a_fmul_pow_i_2_ldexp_a_afn_f32(float %a, i32 %i) {
-; CHECK-LABEL: @a_fmul_pow_i_2_ldexp_a_afn_f32(
+define float @fmul_a_pow_2_i_ldexp_1_a_afn_f32(float %a, i32 %i) {
+; CHECK-LABEL: @fmul_a_pow_2_i_ldexp_1_a_afn_f32(
; CHECK-NEXT: [[TMP1:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[A:%.*]], i32 [[I:%.*]])
; CHECK-NEXT: ret float [[TMP1]]
;
@@ -676,8 +676,8 @@ define float @a_fmul_pow_i_2_ldexp_a_afn_f32(float %a, i32 %i) {
ret float %2
}
-define double @pow_i_2_ldexp_1_afn_f64(i32 %i) {
-; CHECK-LABEL: @pow_i_2_ldexp_1_afn_f64(
+define double @pow_2_i_ldexp_1_a_afn_f64(i32 %i) {
+; CHECK-LABEL: @pow_2_i_ldexp_1_a_afn_f64(
; CHECK-NEXT: [[TMP1:%.*]] = call afn double @llvm.ldexp.f64.i32(double 1.000000e+00, i32 [[I:%.*]])
; CHECK-NEXT: ret double [[TMP1]]
;
@@ -685,8 +685,8 @@ define double @pow_i_2_ldexp_1_afn_f64(i32 %i) {
ret double %1
}
-define double @a_fmul_pow_i_2_ldexp_a_afn_f64(double %a, i32 %i) {
-; CHECK-LABEL: @a_fmul_pow_i_2_ldexp_a_afn_f64(
+define double @fmul_a_pow_2_i_ldexp_1_a_afn_f64(double %a, i32 %i) {
+; CHECK-LABEL: @fmul_a_pow_2_i_ldexp_1_a_afn_f64(
; CHECK-NEXT: [[TMP1:%.*]] = call reassoc double @llvm.ldexp.f64.i32(double [[A:%.*]], i32 [[I:%.*]])
; CHECK-NEXT: ret double [[TMP1]]
;
More information about the llvm-commits
mailing list