[llvm-branch-commits] [llvm] [InstCombine] Fold exp2(uitofp x) to ldexp(1.0, x) with ninf (PR #227380)

Harrison Hao via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Sep 30 01:12:15 PDT 2026


https://github.com/harrisonGPU updated https://github.com/llvm/llvm-project/pull/227380

>From 3cc13c858ff059c20847267add210aba25514033 Mon Sep 17 00:00:00 2001
From: Harrison Hao <tsworld1314 at gmail.com>
Date: Tue, 29 Sep 2026 23:42:45 +0800
Subject: [PATCH] [InstCombine] Fold exp2(uitofp x) to ldexp(1.0, x) with ninf

`exp2(uitofp iN x) -> ldexp(1.0, zext x)` currently requires N to be
narrower than `int`, because `ldexp` takes a signed `int` exponent.
When N equals the width of `int`, the fold is still correct under `ninf`.
Every LLVM FP type has $E_{\max} \le 16383 < 2^{15} \le 2^{N-1}$, so:

- $x < 2^{N-1}$: signed and unsigned $x$ agree, so $\operatorname{ldexp}(1.0, x) = 2^{x} = \operatorname{exp2}(x)$.
- $x \ge 2^{N-1}$: $\operatorname{exp2}(x) \ge 2^{2^{N-1}} > 2^{E_{\max}}$ overflows to $+\infty$, which is poison under `ninf`.

This only applies to the intrinsic, since the `exp2` libcall may set
`errno` on overflow.

This also enables `pow(2.0, uitofp x) -> ldexp` via the existing
`pow(2^n, x) -> exp2(n * x)` fold.
---
 .../lib/Transforms/Utils/SimplifyLibCalls.cpp | 51 ++++++++++------
 llvm/test/Transforms/InstCombine/exp2-1.ll    | 20 +++----
 .../Transforms/InstCombine/exp2-to-ldexp.ll   | 59 +++++++++----------
 .../Transforms/InstCombine/pow-to-ldexp.ll    |  8 +--
 .../test/Transforms/InstCombine/pow_fp_int.ll |  7 +--
 .../Transforms/InstCombine/pow_fp_int16.ll    |  7 +--
 6 files changed, 78 insertions(+), 74 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
index f6235b5b98fcb..e7ec4e33567d9 100644
--- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -2633,28 +2633,43 @@ Value *LibCallSimplifier::optimizeExp2(CallInst *CI, IRBuilderBase &B) {
 
   // exp2(sitofp(x)) -> ldexp(1.0, sext(x))  if sizeof(x) <= IntSize
   // exp2(uitofp(x)) -> ldexp(1.0, zext(x))  if sizeof(x) < IntSize
+  // exp2(uitofp(x)) -> ldexp(1.0, umin(x, C)) if sizeof(x) == IntSize
   Value *Op = CI->getArgOperand(0);
-  if ((isa<SIToFPInst>(Op) || isa<UIToFPInst>(Op)) &&
-      (UseIntrinsic ||
-       hasFloatFn(M, TLI, Ty, LibFunc_ldexp, LibFunc_ldexpf, LibFunc_ldexpl))) {
-    if (Value *Exp = getIntToFPVal(Op, B, TLI->getIntSize())) {
-      Constant *One = ConstantFP::get(Ty, 1.0);
+  if (!isa<SIToFPInst, UIToFPInst>(Op) ||
+      (!UseIntrinsic &&
+       !hasFloatFn(M, TLI, Ty, LibFunc_ldexp, LibFunc_ldexpf, LibFunc_ldexpl)))
+    return Ret;
 
-      if (UseIntrinsic) {
-        return copyFlags(*CI, B.CreateIntrinsic(Intrinsic::ldexp,
-                                                {Ty, Exp->getType()},
-                                                {One, Exp}, CI));
-      }
+  unsigned IntSize = TLI->getIntSize();
+  Value *Exp = getIntToFPVal(Op, B, IntSize);
+  Value *UIntOp = nullptr;
+  // A uitofp source as wide as int may exceed INT_MAX, so clamp it for ldexp.
+  if (!Exp && UseIntrinsic && match(Op, m_UIToFP(m_Value(UIntOp))) &&
+      UIntOp->getType()->getScalarSizeInBits() == IntSize) {
+    const fltSemantics &Sem = Ty->getScalarType()->getFltSemantics();
+    // exp2(x) and ldexp(1.0, Clamp) both overflow for every x >= Clamp.
+    int Clamp = llvm::ilogb(APFloat::getLargest(Sem)) + 1;
+    assert(isIntN(IntSize, Clamp) && "Emax + 1 must fit in int");
+    Exp = UIntOp;
+    if (!CI->hasNoInfs())
+      Exp = B.CreateBinaryIntrinsic(Intrinsic::umin, UIntOp,
+                                    ConstantInt::get(UIntOp->getType(), Clamp));
+  }
+
+  if (!Exp)
+    return Ret;
 
-      IRBuilderBase::FastMathFlagGuard Guard(B);
-      B.setFastMathFlags(CI->getFastMathFlags());
-      return copyFlags(*CI, emitBinaryFloatFnCall(
-                                One, Exp, TLI, LibFunc_ldexp, LibFunc_ldexpf,
-                                LibFunc_ldexpl, B, AttributeList()));
-    }
-  }
+  Constant *One = ConstantFP::get(Ty, 1.0);
+  if (UseIntrinsic)
+    return copyFlags(*CI,
+                     B.CreateIntrinsic(Intrinsic::ldexp, {Ty, Exp->getType()},
+                                       {One, Exp}, CI));
 
-  return Ret;
+  IRBuilderBase::FastMathFlagGuard Guard(B);
+  B.setFastMathFlags(CI->getFastMathFlags());
+  return copyFlags(*CI, emitBinaryFloatFnCall(One, Exp, TLI, LibFunc_ldexp,
+                                              LibFunc_ldexpf, LibFunc_ldexpl, B,
+                                              AttributeList()));
 }
 
 Value *LibCallSimplifier::optimizeFMinFMax(CallInst *CI, IRBuilderBase &B,
diff --git a/llvm/test/Transforms/InstCombine/exp2-1.ll b/llvm/test/Transforms/InstCombine/exp2-1.ll
index 2369bc4f8c447..a7ea4cd3b1deb 100644
--- a/llvm/test/Transforms/InstCombine/exp2-1.ll
+++ b/llvm/test/Transforms/InstCombine/exp2-1.ll
@@ -306,8 +306,7 @@ define float @test_readonly_exp2f_f32_of_uitofp_flags(i32 %x) {
 
 define float @uitofp_i32_scalar_intrinsic_with_ninf(i32 %x) {
 ; LDEXP32-LABEL: @uitofp_i32_scalar_intrinsic_with_ninf(
-; LDEXP32-NEXT:    [[U:%.*]] = uitofp i32 [[X:%.*]] to float
-; LDEXP32-NEXT:    [[R:%.*]] = tail call ninf float @llvm.exp2.f32(float [[U]])
+; LDEXP32-NEXT:    [[R:%.*]] = tail call ninf float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[X:%.*]])
 ; LDEXP32-NEXT:    ret float [[R]]
 ;
 ; LDEXP16-LABEL: @uitofp_i32_scalar_intrinsic_with_ninf(
@@ -316,13 +315,11 @@ define float @uitofp_i32_scalar_intrinsic_with_ninf(i32 %x) {
 ; LDEXP16-NEXT:    ret float [[R]]
 ;
 ; NOLDEXPF-LABEL: @uitofp_i32_scalar_intrinsic_with_ninf(
-; NOLDEXPF-NEXT:    [[U:%.*]] = uitofp i32 [[X:%.*]] to float
-; NOLDEXPF-NEXT:    [[R:%.*]] = tail call ninf float @llvm.exp2.f32(float [[U]])
+; NOLDEXPF-NEXT:    [[R:%.*]] = tail call ninf float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[X:%.*]])
 ; NOLDEXPF-NEXT:    ret float [[R]]
 ;
 ; NOLDEXP-LABEL: @uitofp_i32_scalar_intrinsic_with_ninf(
-; NOLDEXP-NEXT:    [[U:%.*]] = uitofp i32 [[X:%.*]] to float
-; NOLDEXP-NEXT:    [[R:%.*]] = tail call ninf float @llvm.exp2.f32(float [[U]])
+; NOLDEXP-NEXT:    [[R:%.*]] = tail call ninf float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[X:%.*]])
 ; NOLDEXP-NEXT:    ret float [[R]]
 ;
   %u = uitofp i32 %x to float
@@ -337,8 +334,7 @@ define float @uitofp_i16_scalar_intrinsic_with_ninf(i16 %x) {
 ; LDEXP32-NEXT:    ret float [[R]]
 ;
 ; LDEXP16-LABEL: @uitofp_i16_scalar_intrinsic_with_ninf(
-; LDEXP16-NEXT:    [[U:%.*]] = uitofp i16 [[X:%.*]] to float
-; LDEXP16-NEXT:    [[R:%.*]] = tail call ninf float @llvm.exp2.f32(float [[U]])
+; LDEXP16-NEXT:    [[R:%.*]] = tail call ninf float @llvm.ldexp.f32.i16(float 1.000000e+00, i16 [[X:%.*]])
 ; LDEXP16-NEXT:    ret float [[R]]
 ;
 ; NOLDEXPF-LABEL: @uitofp_i16_scalar_intrinsic_with_ninf(
@@ -363,8 +359,8 @@ define float @uitofp_i16_scalar_intrinsic(i16 %x) {
 ; LDEXP32-NEXT:    ret float [[R]]
 ;
 ; LDEXP16-LABEL: @uitofp_i16_scalar_intrinsic(
-; LDEXP16-NEXT:    [[U:%.*]] = uitofp i16 [[X:%.*]] to float
-; LDEXP16-NEXT:    [[R:%.*]] = tail call float @llvm.exp2.f32(float [[U]])
+; LDEXP16-NEXT:    [[TMP1:%.*]] = call i16 @llvm.umin.i16(i16 [[X:%.*]], i16 128)
+; LDEXP16-NEXT:    [[R:%.*]] = tail call float @llvm.ldexp.f32.i16(float 1.000000e+00, i16 [[TMP1]])
 ; LDEXP16-NEXT:    ret float [[R]]
 ;
 ; NOLDEXPF-LABEL: @uitofp_i16_scalar_intrinsic(
@@ -389,8 +385,8 @@ define fp128 @uitofp_i16_scalar_intrinsic_fp128(i16 %x) {
 ; LDEXP32-NEXT:    ret fp128 [[R]]
 ;
 ; LDEXP16-LABEL: @uitofp_i16_scalar_intrinsic_fp128(
-; LDEXP16-NEXT:    [[U:%.*]] = uitofp i16 [[X:%.*]] to fp128
-; LDEXP16-NEXT:    [[R:%.*]] = tail call fp128 @llvm.exp2.f128(fp128 [[U]])
+; LDEXP16-NEXT:    [[TMP1:%.*]] = call i16 @llvm.umin.i16(i16 [[X:%.*]], i16 16384)
+; LDEXP16-NEXT:    [[R:%.*]] = tail call fp128 @llvm.ldexp.f128.i16(fp128 1.000000e+00, i16 [[TMP1]])
 ; LDEXP16-NEXT:    ret fp128 [[R]]
 ;
 ; NOLDEXPF-LABEL: @uitofp_i16_scalar_intrinsic_fp128(
diff --git a/llvm/test/Transforms/InstCombine/exp2-to-ldexp.ll b/llvm/test/Transforms/InstCombine/exp2-to-ldexp.ll
index 6acd1590a9e51..8d65672b009b7 100644
--- a/llvm/test/Transforms/InstCombine/exp2-to-ldexp.ll
+++ b/llvm/test/Transforms/InstCombine/exp2-to-ldexp.ll
@@ -98,13 +98,12 @@ define <vscale x 4 x float> @exp2_nxv4f32_sitofp_i8(<vscale x 4 x i8> %x) {
   ret <vscale x 4 x float> %exp2
 }
 
-; exp2(uitofp i32 x) -> ldexp(1.0, x) is only valid with ninf.
+; exp2(uitofp i32 x) -> ldexp(1.0, x) with ninf.
 
 define float @exp2_f32_uitofp_i32_ninf(i32 %x) {
 ; CHECK-LABEL: define float @exp2_f32_uitofp_i32_ninf(
 ; CHECK-SAME: i32 [[X:%.*]]) {
-; CHECK-NEXT:    [[ITOFP:%.*]] = uitofp i32 [[X]] to float
-; CHECK-NEXT:    [[EXP2:%.*]] = call ninf float @llvm.exp2.f32(float [[ITOFP]])
+; CHECK-NEXT:    [[EXP2:%.*]] = call ninf float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[X]])
 ; CHECK-NEXT:    ret float [[EXP2]]
 ;
   %itofp = uitofp i32 %x to float
@@ -115,8 +114,7 @@ define float @exp2_f32_uitofp_i32_ninf(i32 %x) {
 define float @exp2_f32_uitofp_i32_flags(i32 %x) {
 ; CHECK-LABEL: define float @exp2_f32_uitofp_i32_flags(
 ; CHECK-SAME: i32 [[X:%.*]]) {
-; CHECK-NEXT:    [[ITOFP:%.*]] = uitofp i32 [[X]] to float
-; CHECK-NEXT:    [[EXP2:%.*]] = call nnan ninf float @llvm.exp2.f32(float [[ITOFP]])
+; CHECK-NEXT:    [[EXP2:%.*]] = call nnan ninf float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[X]])
 ; CHECK-NEXT:    ret float [[EXP2]]
 ;
   %itofp = uitofp i32 %x to float
@@ -127,8 +125,7 @@ define float @exp2_f32_uitofp_i32_flags(i32 %x) {
 define <2 x float> @exp2_v2f32_uitofp_v2i32_ninf(<2 x i32> %x) {
 ; CHECK-LABEL: define <2 x float> @exp2_v2f32_uitofp_v2i32_ninf(
 ; CHECK-SAME: <2 x i32> [[X:%.*]]) {
-; CHECK-NEXT:    [[ITOFP:%.*]] = uitofp <2 x i32> [[X]] to <2 x float>
-; CHECK-NEXT:    [[EXP2:%.*]] = call ninf <2 x float> @llvm.exp2.v2f32(<2 x float> [[ITOFP]])
+; CHECK-NEXT:    [[EXP2:%.*]] = call ninf <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> splat (float 1.000000e+00), <2 x i32> [[X]])
 ; CHECK-NEXT:    ret <2 x float> [[EXP2]]
 ;
   %itofp = uitofp <2 x i32> %x to <2 x float>
@@ -139,8 +136,7 @@ define <2 x float> @exp2_v2f32_uitofp_v2i32_ninf(<2 x i32> %x) {
 define <vscale x 4 x float> @exp2_nxv4f32_uitofp_i32_ninf(<vscale x 4 x i32> %x) {
 ; CHECK-LABEL: define <vscale x 4 x float> @exp2_nxv4f32_uitofp_i32_ninf(
 ; CHECK-SAME: <vscale x 4 x i32> [[X:%.*]]) {
-; CHECK-NEXT:    [[ITOFP:%.*]] = uitofp <vscale x 4 x i32> [[X]] to <vscale x 4 x float>
-; CHECK-NEXT:    [[EXP2:%.*]] = call ninf <vscale x 4 x float> @llvm.exp2.nxv4f32(<vscale x 4 x float> [[ITOFP]])
+; CHECK-NEXT:    [[EXP2:%.*]] = call ninf <vscale x 4 x float> @llvm.ldexp.nxv4f32.nxv4i32(<vscale x 4 x float> splat (float 1.000000e+00), <vscale x 4 x i32> [[X]])
 ; CHECK-NEXT:    ret <vscale x 4 x float> [[EXP2]]
 ;
   %itofp = uitofp <vscale x 4 x i32> %x to <vscale x 4 x float>
@@ -151,8 +147,7 @@ define <vscale x 4 x float> @exp2_nxv4f32_uitofp_i32_ninf(<vscale x 4 x i32> %x)
 define half @exp2_f16_uitofp_i32_ninf(i32 %x) {
 ; CHECK-LABEL: define half @exp2_f16_uitofp_i32_ninf(
 ; CHECK-SAME: i32 [[X:%.*]]) {
-; CHECK-NEXT:    [[ITOFP:%.*]] = uitofp i32 [[X]] to half
-; CHECK-NEXT:    [[EXP2:%.*]] = call ninf half @llvm.exp2.f16(half [[ITOFP]])
+; CHECK-NEXT:    [[EXP2:%.*]] = call ninf half @llvm.ldexp.f16.i32(half 1.000000e+00, i32 [[X]])
 ; CHECK-NEXT:    ret half [[EXP2]]
 ;
   %itofp = uitofp i32 %x to half
@@ -163,8 +158,7 @@ define half @exp2_f16_uitofp_i32_ninf(i32 %x) {
 define double @exp2_f64_uitofp_i32_ninf(i32 %x) {
 ; CHECK-LABEL: define double @exp2_f64_uitofp_i32_ninf(
 ; CHECK-SAME: i32 [[X:%.*]]) {
-; CHECK-NEXT:    [[ITOFP:%.*]] = uitofp i32 [[X]] to double
-; CHECK-NEXT:    [[EXP2:%.*]] = call ninf double @llvm.exp2.f64(double [[ITOFP]])
+; CHECK-NEXT:    [[EXP2:%.*]] = call ninf double @llvm.ldexp.f64.i32(double 1.000000e+00, i32 [[X]])
 ; CHECK-NEXT:    ret double [[EXP2]]
 ;
   %itofp = uitofp i32 %x to double
@@ -175,8 +169,7 @@ define double @exp2_f64_uitofp_i32_ninf(i32 %x) {
 define fp128 @exp2_fp128_uitofp_i32_ninf(i32 %x) {
 ; CHECK-LABEL: define fp128 @exp2_fp128_uitofp_i32_ninf(
 ; CHECK-SAME: i32 [[X:%.*]]) {
-; CHECK-NEXT:    [[ITOFP:%.*]] = uitofp i32 [[X]] to fp128
-; CHECK-NEXT:    [[EXP2:%.*]] = call ninf fp128 @llvm.exp2.f128(fp128 [[ITOFP]])
+; CHECK-NEXT:    [[EXP2:%.*]] = call ninf fp128 @llvm.ldexp.f128.i32(fp128 1.000000e+00, i32 [[X]])
 ; CHECK-NEXT:    ret fp128 [[EXP2]]
 ;
   %itofp = uitofp i32 %x to fp128
@@ -184,13 +177,13 @@ define fp128 @exp2_fp128_uitofp_i32_ninf(i32 %x) {
   ret fp128 %exp2
 }
 
-; Negative tests
+; Without ninf, clamp x to Emax + 1.
 
 define float @exp2_f32_uitofp_i32(i32 %x) {
 ; CHECK-LABEL: define float @exp2_f32_uitofp_i32(
 ; CHECK-SAME: i32 [[X:%.*]]) {
-; CHECK-NEXT:    [[ITOFP:%.*]] = uitofp i32 [[X]] to float
-; CHECK-NEXT:    [[EXP2:%.*]] = call float @llvm.exp2.f32(float [[ITOFP]])
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 128)
+; CHECK-NEXT:    [[EXP2:%.*]] = call float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[TMP1]])
 ; CHECK-NEXT:    ret float [[EXP2]]
 ;
   %itofp = uitofp i32 %x to float
@@ -201,8 +194,8 @@ define float @exp2_f32_uitofp_i32(i32 %x) {
 define float @exp2_f32_uitofp_i32_nnan(i32 %x) {
 ; CHECK-LABEL: define float @exp2_f32_uitofp_i32_nnan(
 ; CHECK-SAME: i32 [[X:%.*]]) {
-; CHECK-NEXT:    [[ITOFP:%.*]] = uitofp i32 [[X]] to float
-; CHECK-NEXT:    [[EXP2:%.*]] = call nnan float @llvm.exp2.f32(float [[ITOFP]])
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 128)
+; CHECK-NEXT:    [[EXP2:%.*]] = call nnan float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[TMP1]])
 ; CHECK-NEXT:    ret float [[EXP2]]
 ;
   %itofp = uitofp i32 %x to float
@@ -213,8 +206,8 @@ define float @exp2_f32_uitofp_i32_nnan(i32 %x) {
 define <2 x float> @exp2_v2f32_uitofp_v2i32(<2 x i32> %x) {
 ; CHECK-LABEL: define <2 x float> @exp2_v2f32_uitofp_v2i32(
 ; CHECK-SAME: <2 x i32> [[X:%.*]]) {
-; CHECK-NEXT:    [[ITOFP:%.*]] = uitofp <2 x i32> [[X]] to <2 x float>
-; CHECK-NEXT:    [[EXP2:%.*]] = call <2 x float> @llvm.exp2.v2f32(<2 x float> [[ITOFP]])
+; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x i32> @llvm.umin.v2i32(<2 x i32> [[X]], <2 x i32> splat (i32 128))
+; CHECK-NEXT:    [[EXP2:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> splat (float 1.000000e+00), <2 x i32> [[TMP1]])
 ; CHECK-NEXT:    ret <2 x float> [[EXP2]]
 ;
   %itofp = uitofp <2 x i32> %x to <2 x float>
@@ -225,8 +218,8 @@ define <2 x float> @exp2_v2f32_uitofp_v2i32(<2 x i32> %x) {
 define <vscale x 4 x float> @exp2_nxv4f32_uitofp_i32(<vscale x 4 x i32> %x) {
 ; CHECK-LABEL: define <vscale x 4 x float> @exp2_nxv4f32_uitofp_i32(
 ; CHECK-SAME: <vscale x 4 x i32> [[X:%.*]]) {
-; CHECK-NEXT:    [[ITOFP:%.*]] = uitofp <vscale x 4 x i32> [[X]] to <vscale x 4 x float>
-; CHECK-NEXT:    [[EXP2:%.*]] = call <vscale x 4 x float> @llvm.exp2.nxv4f32(<vscale x 4 x float> [[ITOFP]])
+; CHECK-NEXT:    [[TMP1:%.*]] = call <vscale x 4 x i32> @llvm.umin.nxv4i32(<vscale x 4 x i32> [[X]], <vscale x 4 x i32> splat (i32 128))
+; CHECK-NEXT:    [[EXP2:%.*]] = call <vscale x 4 x float> @llvm.ldexp.nxv4f32.nxv4i32(<vscale x 4 x float> splat (float 1.000000e+00), <vscale x 4 x i32> [[TMP1]])
 ; CHECK-NEXT:    ret <vscale x 4 x float> [[EXP2]]
 ;
   %itofp = uitofp <vscale x 4 x i32> %x to <vscale x 4 x float>
@@ -237,8 +230,8 @@ define <vscale x 4 x float> @exp2_nxv4f32_uitofp_i32(<vscale x 4 x i32> %x) {
 define half @exp2_f16_uitofp_i32(i32 %x) {
 ; CHECK-LABEL: define half @exp2_f16_uitofp_i32(
 ; CHECK-SAME: i32 [[X:%.*]]) {
-; CHECK-NEXT:    [[ITOFP:%.*]] = uitofp i32 [[X]] to half
-; CHECK-NEXT:    [[EXP2:%.*]] = call half @llvm.exp2.f16(half [[ITOFP]])
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 16)
+; CHECK-NEXT:    [[EXP2:%.*]] = call half @llvm.ldexp.f16.i32(half 1.000000e+00, i32 [[TMP1]])
 ; CHECK-NEXT:    ret half [[EXP2]]
 ;
   %itofp = uitofp i32 %x to half
@@ -249,8 +242,8 @@ define half @exp2_f16_uitofp_i32(i32 %x) {
 define double @exp2_f64_uitofp_i32(i32 %x) {
 ; CHECK-LABEL: define double @exp2_f64_uitofp_i32(
 ; CHECK-SAME: i32 [[X:%.*]]) {
-; CHECK-NEXT:    [[ITOFP:%.*]] = uitofp i32 [[X]] to double
-; CHECK-NEXT:    [[EXP2:%.*]] = call double @llvm.exp2.f64(double [[ITOFP]])
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 1024)
+; CHECK-NEXT:    [[EXP2:%.*]] = call double @llvm.ldexp.f64.i32(double 1.000000e+00, i32 [[TMP1]])
 ; CHECK-NEXT:    ret double [[EXP2]]
 ;
   %itofp = uitofp i32 %x to double
@@ -261,8 +254,8 @@ define double @exp2_f64_uitofp_i32(i32 %x) {
 define fp128 @exp2_fp128_uitofp_i32(i32 %x) {
 ; CHECK-LABEL: define fp128 @exp2_fp128_uitofp_i32(
 ; CHECK-SAME: i32 [[X:%.*]]) {
-; CHECK-NEXT:    [[ITOFP:%.*]] = uitofp i32 [[X]] to fp128
-; CHECK-NEXT:    [[EXP2:%.*]] = call fp128 @llvm.exp2.f128(fp128 [[ITOFP]])
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 16384)
+; CHECK-NEXT:    [[EXP2:%.*]] = call fp128 @llvm.ldexp.f128.i32(fp128 1.000000e+00, i32 [[TMP1]])
 ; CHECK-NEXT:    ret fp128 [[EXP2]]
 ;
   %itofp = uitofp i32 %x to fp128
@@ -273,8 +266,8 @@ define fp128 @exp2_fp128_uitofp_i32(i32 %x) {
 define ppc_fp128 @exp2_ppcf128_uitofp_i32(i32 %x) {
 ; CHECK-LABEL: define ppc_fp128 @exp2_ppcf128_uitofp_i32(
 ; CHECK-SAME: i32 [[X:%.*]]) {
-; CHECK-NEXT:    [[ITOFP:%.*]] = uitofp i32 [[X]] to ppc_fp128
-; CHECK-NEXT:    [[EXP2:%.*]] = call ppc_fp128 @llvm.exp2.ppcf128(ppc_fp128 [[ITOFP]])
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 1024)
+; CHECK-NEXT:    [[EXP2:%.*]] = call ppc_fp128 @llvm.ldexp.ppcf128.i32(ppc_fp128 1.000000e+00, i32 [[TMP1]])
 ; CHECK-NEXT:    ret ppc_fp128 [[EXP2]]
 ;
   %itofp = uitofp i32 %x to ppc_fp128
@@ -282,6 +275,8 @@ define ppc_fp128 @exp2_ppcf128_uitofp_i32(i32 %x) {
   ret ppc_fp128 %exp2
 }
 
+; Negative tests
+
 define float @exp2_f32_uitofp_i64_ninf(i64 %x) {
 ; CHECK-LABEL: define float @exp2_f32_uitofp_i64_ninf(
 ; CHECK-SAME: i64 [[X:%.*]]) {
diff --git a/llvm/test/Transforms/InstCombine/pow-to-ldexp.ll b/llvm/test/Transforms/InstCombine/pow-to-ldexp.ll
index d2b1f6e0a4337..24ec96e2ed216 100644
--- a/llvm/test/Transforms/InstCombine/pow-to-ldexp.ll
+++ b/llvm/test/Transforms/InstCombine/pow-to-ldexp.ll
@@ -29,8 +29,8 @@ define float @pow_sitofp_f32_const_base_2__flags(i32 %x) {
 define float @pow_uitofp_f32_const_base_2(i32 %x) {
 ; LDEXP-EXP2-LABEL: define float @pow_uitofp_f32_const_base_2(
 ; LDEXP-EXP2-SAME: i32 [[X:%.*]]) {
-; LDEXP-EXP2-NEXT:    [[ITOFP:%.*]] = uitofp i32 [[X]] to float
-; LDEXP-EXP2-NEXT:    [[EXP2:%.*]] = tail call float @llvm.exp2.f32(float [[ITOFP]])
+; LDEXP-EXP2-NEXT:    [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 128)
+; LDEXP-EXP2-NEXT:    [[EXP2:%.*]] = tail call float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[TMP1]])
 ; LDEXP-EXP2-NEXT:    ret float [[EXP2]]
 ;
 ; LDEXP-NOEXP2-LABEL: define float @pow_uitofp_f32_const_base_2(
@@ -41,8 +41,8 @@ define float @pow_uitofp_f32_const_base_2(i32 %x) {
 ;
 ; NOLDEXP-LABEL: define float @pow_uitofp_f32_const_base_2(
 ; NOLDEXP-SAME: i32 [[X:%.*]]) {
-; NOLDEXP-NEXT:    [[ITOFP:%.*]] = uitofp i32 [[X]] to float
-; NOLDEXP-NEXT:    [[EXP2:%.*]] = tail call float @llvm.exp2.f32(float [[ITOFP]])
+; NOLDEXP-NEXT:    [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 128)
+; NOLDEXP-NEXT:    [[EXP2:%.*]] = tail call float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[TMP1]])
 ; NOLDEXP-NEXT:    ret float [[EXP2]]
 ;
   %itofp = uitofp i32 %x to float
diff --git a/llvm/test/Transforms/InstCombine/pow_fp_int.ll b/llvm/test/Transforms/InstCombine/pow_fp_int.ll
index 13c2d3ca8070c..94025fd6c8c80 100644
--- a/llvm/test/Transforms/InstCombine/pow_fp_int.ll
+++ b/llvm/test/Transforms/InstCombine/pow_fp_int.ll
@@ -259,8 +259,7 @@ define double @pow_uitofp_const_base_fast_i32(i32 %x) {
 define double @pow_uitofp_const_base_2_fast_i32(i32 %x) {
 ; CHECK-LABEL: define double @pow_uitofp_const_base_2_fast_i32(
 ; CHECK-SAME: i32 [[X:%.*]]) {
-; CHECK-NEXT:    [[SUBFP:%.*]] = uitofp i32 [[X]] to float
-; CHECK-NEXT:    [[EXP2:%.*]] = tail call fast float @llvm.exp2.f32(float [[SUBFP]])
+; CHECK-NEXT:    [[EXP2:%.*]] = tail call fast float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[X]])
 ; CHECK-NEXT:    [[RES:%.*]] = fpext float [[EXP2]] to double
 ; CHECK-NEXT:    ret double [[RES]]
 ;
@@ -401,8 +400,8 @@ define double @pow_sitofp_const_base_power_of_2_no_fast(i32 %x) {
 define double @pow_uitofp_const_base_2_no_fast(i32 %x) {
 ; CHECK-LABEL: define double @pow_uitofp_const_base_2_no_fast(
 ; CHECK-SAME: i32 [[X:%.*]]) {
-; CHECK-NEXT:    [[SUBFP:%.*]] = uitofp i32 [[X]] to float
-; CHECK-NEXT:    [[EXP2:%.*]] = tail call float @llvm.exp2.f32(float [[SUBFP]])
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 128)
+; CHECK-NEXT:    [[EXP2:%.*]] = tail call float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[TMP1]])
 ; CHECK-NEXT:    [[RES:%.*]] = fpext float [[EXP2]] to double
 ; CHECK-NEXT:    ret double [[RES]]
 ;
diff --git a/llvm/test/Transforms/InstCombine/pow_fp_int16.ll b/llvm/test/Transforms/InstCombine/pow_fp_int16.ll
index db836258daa1c..c768b1fa4d62b 100644
--- a/llvm/test/Transforms/InstCombine/pow_fp_int16.ll
+++ b/llvm/test/Transforms/InstCombine/pow_fp_int16.ll
@@ -256,8 +256,7 @@ define double @pow_uitofp_const_base_fast_i16(i16 %x) {
 define double @pow_uitofp_const_base_2_fast_i16(i16 %x) {
 ; CHECK-LABEL: define double @pow_uitofp_const_base_2_fast_i16(
 ; CHECK-SAME: i16 [[X:%.*]]) {
-; CHECK-NEXT:    [[SUBFP:%.*]] = uitofp i16 [[X]] to float
-; CHECK-NEXT:    [[EXP2:%.*]] = tail call fast float @llvm.exp2.f32(float [[SUBFP]])
+; CHECK-NEXT:    [[EXP2:%.*]] = tail call fast float @llvm.ldexp.f32.i16(float 1.000000e+00, i16 [[X]])
 ; CHECK-NEXT:    [[RES:%.*]] = fpext float [[EXP2]] to double
 ; CHECK-NEXT:    ret double [[RES]]
 ;
@@ -367,8 +366,8 @@ define double @pow_sitofp_const_base_power_of_2_no_fast(i16 %x) {
 define double @pow_uitofp_const_base_2_no_fast(i16 %x) {
 ; CHECK-LABEL: define double @pow_uitofp_const_base_2_no_fast(
 ; CHECK-SAME: i16 [[X:%.*]]) {
-; CHECK-NEXT:    [[SUBFP:%.*]] = uitofp i16 [[X]] to float
-; CHECK-NEXT:    [[EXP2:%.*]] = tail call float @llvm.exp2.f32(float [[SUBFP]])
+; CHECK-NEXT:    [[TMP1:%.*]] = call i16 @llvm.umin.i16(i16 [[X]], i16 128)
+; CHECK-NEXT:    [[EXP2:%.*]] = tail call float @llvm.ldexp.f32.i16(float 1.000000e+00, i16 [[TMP1]])
 ; CHECK-NEXT:    [[RES:%.*]] = fpext float [[EXP2]] to double
 ; CHECK-NEXT:    ret double [[RES]]
 ;



More information about the llvm-branch-commits mailing list