[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