[llvm] [KnownFPClass] Refine powi KnownFPClass deductions (PR #218581)

via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 24 21:03:43 PDT 2026


https://github.com/ZERICO2005 created https://github.com/llvm/llvm-project/pull/218581

Adds deductions for when the `base` is known never negative-normal nor negative-subnormal. Similar to the deductions added for `pow` https://github.com/llvm/llvm-project/pull/215592.



>From aecee7d74233b7e69a329f093ebcb42d440be37d Mon Sep 17 00:00:00 2001
From: zerico <zerico2005 at gmail.com>
Date: Sun, 23 Aug 2026 16:07:26 -0600
Subject: [PATCH] [KnownFPClass] Refine powi KnownFPClass deductions

---
 llvm/lib/Support/KnownFPClass.cpp             |  48 ++-
 .../Transforms/Attributor/nofpclass-powi.ll   | 322 +++++++++++++++---
 .../simplify-demanded-fpclass-powi.ll         |  72 ++++
 llvm/unittests/Analysis/ValueTrackingTest.cpp |  12 +-
 4 files changed, 379 insertions(+), 75 deletions(-)
 create mode 100644 llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-powi.ll

diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 37a6160b316ff..476c18ed76c13 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -903,6 +903,38 @@ KnownFPClass KnownFPClass::powi(const KnownFPClass &KnownSrc,
     return Known;
   }
 
+  // Given that exp is an integer, here are the
+  // ways that powi can return a negative value:
+  //
+  //   powi(x, exp)    --> negative if exp is odd and x is negative.
+  //   powi(-0, exp)   --> -inf if exp is negative odd.
+  //   powi(-0, exp)   --> -0 if exp is positive odd.
+  //   powi(-inf, exp) --> -0 if exp is negative odd.
+  //   powi(-inf, exp) --> -inf if exp is positive odd.
+  if (KnownSrc.isKnownNever(fcNegative) || ExponentKnownBits.isEven()) {
+    Known.knownNot(fcNegative);
+  } else if (KnownSrc.isKnownNever(fcNegNormal | fcNegSubnormal)) {
+    Known.knownNot(fcNegNormal | fcNegSubnormal);
+    // See if we can also rule out -0.0 or -inf.
+    // Here at least one of -0.0 or -inf is a possible base.
+
+    // We already know that ExponentKnownBits.isEven() is false here.
+    const bool IsKnownNeverOddPositive = ExponentKnownBits.isNegative();
+    const bool IsKnownNeverOddNegative = ExponentKnownBits.isNonNegative();
+
+    // powi(-0.0, odd-positive) = -0.0
+    // powi(-inf, odd-negative) = -0.0
+    if ((KnownSrc.isKnownNever(fcNegZero) || IsKnownNeverOddPositive) &&
+        (KnownSrc.isKnownNever(fcNegInf) || IsKnownNeverOddNegative))
+      Known.knownNot(fcNegZero);
+
+    // powi(-0.0, odd-negative) = -inf
+    // powi(-inf, odd-positive) = -inf
+    if ((KnownSrc.isKnownNever(fcNegZero) || IsKnownNeverOddNegative) &&
+        (KnownSrc.isKnownNever(fcNegInf) || IsKnownNeverOddPositive))
+      Known.knownNot(fcNegInf);
+  }
+
   // powi(x, exp) --> inf
   // when:
   //   * powi(inf, exp), exp > 0
@@ -938,21 +970,5 @@ KnownFPClass KnownFPClass::powi(const KnownFPClass &KnownSrc,
       Known.knownNot(fcInf);
   }
 
-  if (ExponentKnownBits.isEven()) {
-    Known.knownNot(fcNegative);
-    return Known;
-  }
-
-  // Given that exp is an integer, here are the
-  // ways that pow can return a negative value:
-  //
-  //   pow(-x, exp)   --> negative if exp is odd and x is negative.
-  //   pow(-0, exp)   --> -inf if exp is negative odd.
-  //   pow(-0, exp)   --> -0 if exp is positive odd.
-  //   pow(-inf, exp) --> -0 if exp is negative odd.
-  //   pow(-inf, exp) --> -inf if exp is positive odd.
-  if (KnownSrc.isKnownNever(fcNegative))
-    Known.knownNot(fcNegative);
-
   return Known;
 }
diff --git a/llvm/test/Transforms/Attributor/nofpclass-powi.ll b/llvm/test/Transforms/Attributor/nofpclass-powi.ll
index 49b32d6181589..e92a49dfe8413 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-powi.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-powi.ll
@@ -10,7 +10,7 @@ declare <4 x float> @llvm.powi.v4f32.i32(<4 x float>, i32)
 define float @ret_powi_f32(float %arg0, i32 %arg1) #0 {
 ; CHECK-LABEL: define float @ret_powi_f32
 ; CHECK-SAME: (float [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1:[0-9]+]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.powi.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR6:[0-9]+]]
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.powi.f32.i32(float [[ARG0]], i32 [[ARG1]]) #[[ATTR9:[0-9]+]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -20,7 +20,7 @@ define float @ret_powi_f32(float %arg0, i32 %arg1) #0 {
 define float @ret_powi_f32_i64(float %arg0, i64 %arg1) #0 {
 ; CHECK-LABEL: define float @ret_powi_f32_i64
 ; CHECK-SAME: (float [[ARG0:%.*]], i64 [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.powi.f32.i64(float [[ARG0]], i64 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.powi.f32.i64(float [[ARG0]], i64 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i64(float %arg0, i64 %arg1)
@@ -30,7 +30,7 @@ define float @ret_powi_f32_i64(float %arg0, i64 %arg1) #0 {
 define <2 x float> @ret_powi_v2f32(<2 x float> %arg0, i32 %arg1) #0 {
 ; CHECK-LABEL: define <2 x float> @ret_powi_v2f32
 ; CHECK-SAME: (<2 x float> [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call <2 x float> @llvm.powi.v2f32.i32(<2 x float> [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call <2 x float> @llvm.powi.v2f32.i32(<2 x float> [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret <2 x float> [[CALL]]
 ;
   %call = call <2 x float> @llvm.powi.v2f32.i32(<2 x float> %arg0, i32 %arg1)
@@ -40,7 +40,7 @@ define <2 x float> @ret_powi_v2f32(<2 x float> %arg0, i32 %arg1) #0 {
 define float @ret_powi_f32_odd_constant(float %arg0) #0 {
 ; CHECK-LABEL: define float @ret_powi_f32_odd_constant
 ; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.powi.f32.i32(float [[ARG0]], i32 noundef 3) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.powi.f32.i32(float [[ARG0]], i32 noundef 3) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 3)
@@ -50,7 +50,7 @@ define float @ret_powi_f32_odd_constant(float %arg0) #0 {
 define float @ret_powi_f32_even_constant(float %arg0) #0 {
 ; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_powi_f32_even_constant
 ; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.powi.f32.i32(float [[ARG0]], i32 noundef 4) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.powi.f32.i32(float [[ARG0]], i32 noundef 4) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 4)
@@ -60,7 +60,7 @@ define float @ret_powi_f32_even_constant(float %arg0) #0 {
 define float @ret_powi_f32_0(float %arg0) #0 {
 ; CHECK-LABEL: define nofpclass(inf zero sub nnorm) float @ret_powi_f32_0
 ; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(inf zero sub nnorm) float @llvm.powi.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(inf zero sub nnorm) float @llvm.powi.f32.i32(float [[ARG0]], i32 noundef 0) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 0)
@@ -70,7 +70,7 @@ define float @ret_powi_f32_0(float %arg0) #0 {
 define float @ret_powi_f32_0_no_snan(float nofpclass(snan) %arg0) #0 {
 ; CHECK-LABEL: define nofpclass(nan inf zero sub nnorm) float @ret_powi_f32_0_no_snan
 ; CHECK-SAME: (float nofpclass(snan) [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan inf zero sub nnorm) float @llvm.powi.f32.i32(float nofpclass(snan) [[ARG0]], i32 noundef 0) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan inf zero sub nnorm) float @llvm.powi.f32.i32(float nofpclass(snan) [[ARG0]], i32 noundef 0) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 0)
@@ -80,7 +80,7 @@ define float @ret_powi_f32_0_no_snan(float nofpclass(snan) %arg0) #0 {
 define float @ret_powi_f32_0_no_qnan(float nofpclass(qnan) %arg0) #0 {
 ; CHECK-LABEL: define nofpclass(inf zero sub nnorm) float @ret_powi_f32_0_no_qnan
 ; CHECK-SAME: (float nofpclass(qnan) [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(inf zero sub nnorm) float @llvm.powi.f32.i32(float nofpclass(qnan) [[ARG0]], i32 noundef 0) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(inf zero sub nnorm) float @llvm.powi.f32.i32(float nofpclass(qnan) [[ARG0]], i32 noundef 0) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 0)
@@ -90,7 +90,7 @@ define float @ret_powi_f32_0_no_qnan(float nofpclass(qnan) %arg0) #0 {
 define float @ret_powi_f32_0_no_nan(float nofpclass(nan) %arg0) #0 {
 ; CHECK-LABEL: define nofpclass(nan inf zero sub nnorm) float @ret_powi_f32_0_no_nan
 ; CHECK-SAME: (float nofpclass(nan) [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan inf zero sub nnorm) float @llvm.powi.f32.i32(float nofpclass(nan) [[ARG0]], i32 noundef 0) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan inf zero sub nnorm) float @llvm.powi.f32.i32(float nofpclass(nan) [[ARG0]], i32 noundef 0) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 0)
@@ -100,7 +100,7 @@ define float @ret_powi_f32_0_no_nan(float nofpclass(nan) %arg0) #0 {
 define float @ret_powi_f32_1(float nofpclass(snan) %arg0) #0 {
 ; CHECK-LABEL: define nofpclass(snan) float @ret_powi_f32_1
 ; CHECK-SAME: (float nofpclass(snan) [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(snan) float @llvm.powi.f32.i32(float nofpclass(snan) [[ARG0]], i32 noundef 1) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(snan) float @llvm.powi.f32.i32(float nofpclass(snan) [[ARG0]], i32 noundef 1) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 1)
@@ -110,7 +110,7 @@ define float @ret_powi_f32_1(float nofpclass(snan) %arg0) #0 {
 define float @ret_powi_f32_neg1(float nofpclass(snan) %arg0) #0 {
 ; CHECK-LABEL: define nofpclass(snan) float @ret_powi_f32_neg1
 ; CHECK-SAME: (float nofpclass(snan) [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(snan) float @llvm.powi.f32.i32(float nofpclass(snan) [[ARG0]], i32 noundef -1) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(snan) float @llvm.powi.f32.i32(float nofpclass(snan) [[ARG0]], i32 noundef -1) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 -1)
@@ -120,7 +120,7 @@ define float @ret_powi_f32_neg1(float nofpclass(snan) %arg0) #0 {
 define float @ret_powi_f32_no_snan(float nofpclass(snan) %arg0, i32 %arg1) #0 {
 ; CHECK-LABEL: define nofpclass(snan) float @ret_powi_f32_no_snan
 ; CHECK-SAME: (float nofpclass(snan) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(snan) float @llvm.powi.f32.i32(float nofpclass(snan) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(snan) float @llvm.powi.f32.i32(float nofpclass(snan) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -130,7 +130,7 @@ define float @ret_powi_f32_no_snan(float nofpclass(snan) %arg0, i32 %arg1) #0 {
 define float @ret_powi_f32_no_qnan(float nofpclass(qnan) %arg0, i32 %arg1) #0 {
 ; CHECK-LABEL: define float @ret_powi_f32_no_qnan
 ; CHECK-SAME: (float nofpclass(qnan) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.powi.f32.i32(float nofpclass(qnan) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.powi.f32.i32(float nofpclass(qnan) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -140,7 +140,7 @@ define float @ret_powi_f32_no_qnan(float nofpclass(qnan) %arg0, i32 %arg1) #0 {
 define float @ret_powi_f32_no_nan(float nofpclass(nan) %arg0, i32 %arg1) #0 {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_powi_f32_no_nan
 ; CHECK-SAME: (float nofpclass(nan) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan) float @llvm.powi.f32.i32(float nofpclass(nan) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan) float @llvm.powi.f32.i32(float nofpclass(nan) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -150,7 +150,7 @@ define float @ret_powi_f32_no_nan(float nofpclass(nan) %arg0, i32 %arg1) #0 {
 define float @ret_powi_f32_no_inf(float nofpclass(inf) %arg0, i32 %arg1) #0 {
 ; CHECK-LABEL: define float @ret_powi_f32_no_inf
 ; CHECK-SAME: (float nofpclass(inf) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.powi.f32.i32(float nofpclass(inf) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.powi.f32.i32(float nofpclass(inf) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -160,7 +160,7 @@ define float @ret_powi_f32_no_inf(float nofpclass(inf) %arg0, i32 %arg1) #0 {
 define float @ret_powi_f32_finite_exp_one(float nofpclass(inf) %arg0) #0 {
 ; CHECK-LABEL: define nofpclass(inf) float @ret_powi_f32_finite_exp_one
 ; CHECK-SAME: (float nofpclass(inf) [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(inf) float @llvm.powi.f32.i32(float nofpclass(inf) [[ARG0]], i32 noundef 1) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(inf) float @llvm.powi.f32.i32(float nofpclass(inf) [[ARG0]], i32 noundef 1) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 1)
@@ -170,7 +170,7 @@ define float @ret_powi_f32_finite_exp_one(float nofpclass(inf) %arg0) #0 {
 define float @ret_powi_f32_finite_exp_two(float nofpclass(nan inf) %arg0) #0 {
 ; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_powi_f32_finite_exp_two
 ; CHECK-SAME: (float nofpclass(nan inf) [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan ninf nzero nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(nan inf) [[ARG0]], i32 noundef 2) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan ninf nzero nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(nan inf) [[ARG0]], i32 noundef 2) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 2)
@@ -180,7 +180,7 @@ define float @ret_powi_f32_finite_exp_two(float nofpclass(nan inf) %arg0) #0 {
 define float @ret_powi_f32_normal_exp_neg_one(float nofpclass(inf zero sub) %arg0) #0 {
 ; CHECK-LABEL: define nofpclass(inf) float @ret_powi_f32_normal_exp_neg_one
 ; CHECK-SAME: (float nofpclass(inf zero sub) [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(inf) float @llvm.powi.f32.i32(float nofpclass(inf zero sub) [[ARG0]], i32 noundef -1) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(inf) float @llvm.powi.f32.i32(float nofpclass(inf zero sub) [[ARG0]], i32 noundef -1) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 -1)
@@ -188,9 +188,9 @@ define float @ret_powi_f32_normal_exp_neg_one(float nofpclass(inf zero sub) %arg
 }
 
 define float @ret_powi_f32_inf_or_nan_exp_neg_one(float nofpclass(zero norm sub) %arg0) #0 {
-; CHECK-LABEL: define nofpclass(inf) float @ret_powi_f32_inf_or_nan_exp_neg_one
+; CHECK-LABEL: define nofpclass(inf nsub nnorm) float @ret_powi_f32_inf_or_nan_exp_neg_one
 ; CHECK-SAME: (float nofpclass(zero sub norm) [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(inf) float @llvm.powi.f32.i32(float nofpclass(zero sub norm) [[ARG0]], i32 noundef -1) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(inf nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(zero sub norm) [[ARG0]], i32 noundef -1) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 -1)
@@ -198,10 +198,10 @@ define float @ret_powi_f32_inf_or_nan_exp_neg_one(float nofpclass(zero norm sub)
 }
 
 define float @ret_powi_f32_zero_or_nan_exp_nonnegative(float nofpclass(inf norm sub) %arg0, i32 %arg1) #0 {
-; CHECK-LABEL: define nofpclass(inf) float @ret_powi_f32_zero_or_nan_exp_nonnegative
+; CHECK-LABEL: define nofpclass(inf nsub nnorm) float @ret_powi_f32_zero_or_nan_exp_nonnegative
 ; CHECK-SAME: (float nofpclass(inf sub norm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] {
 ; CHECK-NEXT:    [[NONNEG:%.*]] = and i32 [[ARG1]], 2147483647
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(inf) float @llvm.powi.f32.i32(float nofpclass(inf sub norm) [[ARG0]], i32 [[NONNEG]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(inf nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(inf sub norm) [[ARG0]], i32 [[NONNEG]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %nonneg = and i32 %arg1, 2147483647
@@ -212,7 +212,7 @@ define float @ret_powi_f32_zero_or_nan_exp_nonnegative(float nofpclass(inf norm
 define float @ret_powi_f32_no_nan_inf(float nofpclass(nan inf) %arg0, i32 %arg1) #0 {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_powi_f32_no_nan_inf
 ; CHECK-SAME: (float nofpclass(nan inf) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan) float @llvm.powi.f32.i32(float nofpclass(nan inf) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan) float @llvm.powi.f32.i32(float nofpclass(nan inf) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -222,7 +222,7 @@ define float @ret_powi_f32_no_nan_inf(float nofpclass(nan inf) %arg0, i32 %arg1)
 define float @ret_powi_f32_no_nan__arg1_non0(float nofpclass(nan) %arg0, i32 range(i32 1, 256) %arg1) #0 {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_powi_f32_no_nan__arg1_non0
 ; CHECK-SAME: (float nofpclass(nan) [[ARG0:%.*]], i32 range(i32 1, 256) [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan) float @llvm.powi.f32.i32(float nofpclass(nan) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan) float @llvm.powi.f32.i32(float nofpclass(nan) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -232,7 +232,7 @@ define float @ret_powi_f32_no_nan__arg1_non0(float nofpclass(nan) %arg0, i32 ran
 define float @ret_powi_f32_no_nan_no_zero__arg1_non0(float nofpclass(nan zero) %arg0, i32 range(i32 1, 256) %arg1) #0 {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_powi_f32_no_nan_no_zero__arg1_non0
 ; CHECK-SAME: (float nofpclass(nan zero) [[ARG0:%.*]], i32 range(i32 1, 256) [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan) float @llvm.powi.f32.i32(float nofpclass(nan zero) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan) float @llvm.powi.f32.i32(float nofpclass(nan zero) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -242,7 +242,7 @@ define float @ret_powi_f32_no_nan_no_zero__arg1_non0(float nofpclass(nan zero) %
 define float @ret_powi_f32_no_nan_no_zero__arg1__ieee(float nofpclass(nan zero) %arg0, i32 %arg1) #0 {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_powi_f32_no_nan_no_zero__arg1__ieee
 ; CHECK-SAME: (float nofpclass(nan zero) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan) float @llvm.powi.f32.i32(float nofpclass(nan zero) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan) float @llvm.powi.f32.i32(float nofpclass(nan zero) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -252,7 +252,7 @@ define float @ret_powi_f32_no_nan_no_zero__arg1__ieee(float nofpclass(nan zero)
 define float @ret_powi_f32_no_nan_no_zero__arg1__daz(float nofpclass(nan zero) %arg0, i32 %arg1) #1 {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_powi_f32_no_nan_no_zero__arg1__daz
 ; CHECK-SAME: (float nofpclass(nan zero) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR2:[0-9]+]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan) float @llvm.powi.f32.i32(float nofpclass(nan zero) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan) float @llvm.powi.f32.i32(float nofpclass(nan zero) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -262,7 +262,7 @@ define float @ret_powi_f32_no_nan_no_zero__arg1__daz(float nofpclass(nan zero) %
 define float @ret_powi_f32_no_nan_no_zero_nosub__arg1__daz(float nofpclass(nan zero sub) %arg0, i32 %arg1) #1 {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_powi_f32_no_nan_no_zero_nosub__arg1__daz
 ; CHECK-SAME: (float nofpclass(nan zero sub) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR2]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan) float @llvm.powi.f32.i32(float nofpclass(nan zero sub) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan) float @llvm.powi.f32.i32(float nofpclass(nan zero sub) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -272,7 +272,7 @@ define float @ret_powi_f32_no_nan_no_zero_nosub__arg1__daz(float nofpclass(nan z
 define <2 x float> @ret_powi_v2f32_even_constant(<2 x float> %arg0) #0 {
 ; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) <2 x float> @ret_powi_v2f32_even_constant
 ; CHECK-SAME: (<2 x float> [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) <2 x float> @llvm.powi.v2f32.i32(<2 x float> [[ARG0]], i32 noundef 4) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) <2 x float> @llvm.powi.v2f32.i32(<2 x float> [[ARG0]], i32 noundef 4) #[[ATTR9]]
 ; CHECK-NEXT:    ret <2 x float> [[CALL]]
 ;
   %call = call <2 x float> @llvm.powi.v2f32.i32(<2 x float> %arg0, i32 4)
@@ -282,7 +282,7 @@ define <2 x float> @ret_powi_v2f32_even_constant(<2 x float> %arg0) #0 {
 define <2 x float> @ret_powi_v2f32_odd_constant(<2 x float> %arg0) #0 {
 ; CHECK-LABEL: define <2 x float> @ret_powi_v2f32_odd_constant
 ; CHECK-SAME: (<2 x float> [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call <2 x float> @llvm.powi.v2f32.i32(<2 x float> [[ARG0]], i32 noundef 3) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call <2 x float> @llvm.powi.v2f32.i32(<2 x float> [[ARG0]], i32 noundef 3) #[[ATTR9]]
 ; CHECK-NEXT:    ret <2 x float> [[CALL]]
 ;
   %call = call <2 x float> @llvm.powi.v2f32.i32(<2 x float> %arg0, i32 3)
@@ -293,7 +293,7 @@ define float @ret_powi_f32_masked_to_even(float %arg0, i32 %arg1) #0 {
 ; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_powi_f32_masked_to_even
 ; CHECK-SAME: (float [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] {
 ; CHECK-NEXT:    [[KNOWN_EVEN:%.*]] = and i32 [[ARG1]], -2
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.powi.f32.i32(float [[ARG0]], i32 [[KNOWN_EVEN]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.powi.f32.i32(float [[ARG0]], i32 [[KNOWN_EVEN]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %known.even = and i32 %arg1, -2
@@ -305,7 +305,7 @@ define float @ret_powi_f32_masked_to_even_extrabits(float %arg0, i32 %arg1) #0 {
 ; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_powi_f32_masked_to_even_extrabits
 ; CHECK-SAME: (float [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] {
 ; CHECK-NEXT:    [[KNOWN_EVEN:%.*]] = and i32 [[ARG1]], -4
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.powi.f32.i32(float [[ARG0]], i32 [[KNOWN_EVEN]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.powi.f32.i32(float [[ARG0]], i32 [[KNOWN_EVEN]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %known.even = and i32 %arg1, -4
@@ -317,7 +317,7 @@ define <2 x float> @ret_powi_v2f32_masked_to_even(<2 x float> %arg0, i32 %arg1)
 ; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) <2 x float> @ret_powi_v2f32_masked_to_even
 ; CHECK-SAME: (<2 x float> [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] {
 ; CHECK-NEXT:    [[KNOWN_EVEN:%.*]] = and i32 [[ARG1]], -2
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) <2 x float> @llvm.powi.v2f32.i32(<2 x float> [[ARG0]], i32 [[KNOWN_EVEN]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) <2 x float> @llvm.powi.v2f32.i32(<2 x float> [[ARG0]], i32 [[KNOWN_EVEN]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret <2 x float> [[CALL]]
 ;
   %known.even = and i32 %arg1, -2
@@ -326,9 +326,9 @@ define <2 x float> @ret_powi_v2f32_masked_to_even(<2 x float> %arg0, i32 %arg1)
 }
 
 define float @ret_powi_f32_noneg(float nofpclass(ninf nsub nnorm) %arg0, i32 %arg1) #0 {
-; CHECK-LABEL: define float @ret_powi_f32_noneg
+; CHECK-LABEL: define nofpclass(nsub nnorm) float @ret_powi_f32_noneg
 ; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.powi.f32.i32(float nofpclass(ninf nsub nnorm) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(ninf nsub nnorm) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -338,7 +338,7 @@ define float @ret_powi_f32_noneg(float nofpclass(ninf nsub nnorm) %arg0, i32 %ar
 define float @ret_powi_f32_noneg_nonzero(float nofpclass(ninf nsub nnorm nzero) %arg0, i32 %arg1) #0 {
 ; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_powi_f32_noneg_nonzero
 ; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(ninf nzero nsub nnorm) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(ninf nzero nsub nnorm) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -346,9 +346,9 @@ define float @ret_powi_f32_noneg_nonzero(float nofpclass(ninf nsub nnorm nzero)
 }
 
 define float @ret_powi_f32_noneg_nozero(float nofpclass(ninf nsub nnorm) %arg0, i32 %arg1) #0 {
-; CHECK-LABEL: define float @ret_powi_f32_noneg_nozero
+; CHECK-LABEL: define nofpclass(nsub nnorm) float @ret_powi_f32_noneg_nozero
 ; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.powi.f32.i32(float nofpclass(ninf nsub nnorm) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(ninf nsub nnorm) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -358,7 +358,7 @@ define float @ret_powi_f32_noneg_nozero(float nofpclass(ninf nsub nnorm) %arg0,
 define float @ret_powi_f32_nonzero(float nofpclass(nzero) %arg0, i32 %arg1) #0 {
 ; CHECK-LABEL: define float @ret_powi_f32_nonzero
 ; CHECK-SAME: (float nofpclass(nzero) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.powi.f32.i32(float nofpclass(nzero) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.powi.f32.i32(float nofpclass(nzero) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -368,7 +368,7 @@ define float @ret_powi_f32_nonzero(float nofpclass(nzero) %arg0, i32 %arg1) #0 {
 define float @ret_powi_f32_nopzero(float nofpclass(pzero) %arg0, i32 %arg1) #0 {
 ; CHECK-LABEL: define float @ret_powi_f32_nopzero
 ; CHECK-SAME: (float nofpclass(pzero) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.powi.f32.i32(float nofpclass(pzero) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.powi.f32.i32(float nofpclass(pzero) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -376,9 +376,9 @@ define float @ret_powi_f32_nopzero(float nofpclass(pzero) %arg0, i32 %arg1) #0 {
 }
 
 define float @ret_powi_f32_noneg_ftz_daz(float nofpclass(ninf nsub nnorm) %arg0, i32 %arg1) #1 {
-; CHECK-LABEL: define float @ret_powi_f32_noneg_ftz_daz
+; CHECK-LABEL: define nofpclass(nsub nnorm) float @ret_powi_f32_noneg_ftz_daz
 ; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR2]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.powi.f32.i32(float nofpclass(ninf nsub nnorm) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(ninf nsub nnorm) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -388,7 +388,7 @@ define float @ret_powi_f32_noneg_ftz_daz(float nofpclass(ninf nsub nnorm) %arg0,
 define float @ret_powi_f32_noneg_nonzero_ftz_daz(float nofpclass(ninf nsub nnorm nzero) %arg0, i32 %arg1) #1 {
 ; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_powi_f32_noneg_nonzero_ftz_daz
 ; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR2]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(ninf nzero nsub nnorm) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(ninf nzero nsub nnorm) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -398,7 +398,7 @@ define float @ret_powi_f32_noneg_nonzero_ftz_daz(float nofpclass(ninf nsub nnorm
 define float @ret_powi_f32_noneg_nonzero_ftpz_dapz(float nofpclass(ninf nsub nnorm nzero) %arg0, i32 %arg1) #2 {
 ; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_powi_f32_noneg_nonzero_ftpz_dapz
 ; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR3:[0-9]+]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(ninf nzero nsub nnorm) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(ninf nzero nsub nnorm) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -408,7 +408,7 @@ define float @ret_powi_f32_noneg_nonzero_ftpz_dapz(float nofpclass(ninf nsub nno
 define float @ret_powi_f32_noninf_nonnorm(float nofpclass(ninf nnorm) %arg0, i32 %arg1) #0 {
 ; CHECK-LABEL: define float @ret_powi_f32_noninf_nonnorm
 ; CHECK-SAME: (float nofpclass(ninf nnorm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.powi.f32.i32(float nofpclass(ninf nnorm) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.powi.f32.i32(float nofpclass(ninf nnorm) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -418,7 +418,7 @@ define float @ret_powi_f32_noninf_nonnorm(float nofpclass(ninf nnorm) %arg0, i32
 define float @ret_powi_f32_noninf_nonnorm_ftz_daz(float nofpclass(ninf nnorm) %arg0, i32 %arg1) #1 {
 ; CHECK-LABEL: define float @ret_powi_f32_noninf_nonnorm_ftz_daz
 ; CHECK-SAME: (float nofpclass(ninf nnorm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR2]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.powi.f32.i32(float nofpclass(ninf nnorm) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.powi.f32.i32(float nofpclass(ninf nnorm) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -426,9 +426,9 @@ define float @ret_powi_f32_noninf_nonnorm_ftz_daz(float nofpclass(ninf nnorm) %a
 }
 
 define float @ret_powi_f32_noneg_ftz_ieee(float nofpclass(ninf nsub nnorm) %arg0, i32 %arg1) #3 {
-; CHECK-LABEL: define float @ret_powi_f32_noneg_ftz_ieee
+; CHECK-LABEL: define nofpclass(nsub nnorm) float @ret_powi_f32_noneg_ftz_ieee
 ; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR4:[0-9]+]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.powi.f32.i32(float nofpclass(ninf nsub nnorm) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(ninf nsub nnorm) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -438,7 +438,7 @@ define float @ret_powi_f32_noneg_ftz_ieee(float nofpclass(ninf nsub nnorm) %arg0
 define float @ret_powi_f32_noneg_nonzero_ftz_ieee(float nofpclass(ninf nsub nnorm nzero) %arg0, i32 %arg1) #3 {
 ; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_powi_f32_noneg_nonzero_ftz_ieee
 ; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR4]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(ninf nzero nsub nnorm) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(ninf nzero nsub nnorm) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.powi.f32.i32(float %arg0, i32 %arg1)
@@ -448,7 +448,7 @@ define float @ret_powi_f32_noneg_nonzero_ftz_ieee(float nofpclass(ninf nsub nnor
 define <4 x float> @powi_v4f32_i32(<4 x float> %arg0, i32 %arg1) {
 ; CHECK-LABEL: define <4 x float> @powi_v4f32_i32
 ; CHECK-SAME: (<4 x float> [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR5:[0-9]+]] {
-; CHECK-NEXT:    [[POWI:%.*]] = call <4 x float> @llvm.powi.v4f32.i32(<4 x float> [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[POWI:%.*]] = call <4 x float> @llvm.powi.v4f32.i32(<4 x float> [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret <4 x float> [[POWI]]
 ;
   %powi = call <4 x float> @llvm.powi.v4f32.i32(<4 x float> %arg0, i32 %arg1)
@@ -458,7 +458,7 @@ define <4 x float> @powi_v4f32_i32(<4 x float> %arg0, i32 %arg1) {
 define <4 x float> @powi_v4f32_i32_nozero(<4 x float> nofpclass(zero) %arg0, i32 %arg1) {
 ; CHECK-LABEL: define <4 x float> @powi_v4f32_i32_nozero
 ; CHECK-SAME: (<4 x float> nofpclass(zero) [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR5]] {
-; CHECK-NEXT:    [[POWI:%.*]] = call <4 x float> @llvm.powi.v4f32.i32(<4 x float> nofpclass(zero) [[ARG0]], i32 [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT:    [[POWI:%.*]] = call <4 x float> @llvm.powi.v4f32.i32(<4 x float> nofpclass(zero) [[ARG0]], i32 [[ARG1]]) #[[ATTR9]]
 ; CHECK-NEXT:    ret <4 x float> [[POWI]]
 ;
   %powi = call <4 x float> @llvm.powi.v4f32.i32(<4 x float> %arg0, i32 %arg1)
@@ -468,7 +468,7 @@ define <4 x float> @powi_v4f32_i32_nozero(<4 x float> nofpclass(zero) %arg0, i32
 define <4 x float> @powi_v4f32_i32_constint_even(<4 x float> %arg) {
 ; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) <4 x float> @powi_v4f32_i32_constint_even
 ; CHECK-SAME: (<4 x float> [[ARG:%.*]]) #[[ATTR5]] {
-; CHECK-NEXT:    [[POWI:%.*]] = call nofpclass(ninf nzero nsub nnorm) <4 x float> @llvm.powi.v4f32.i32(<4 x float> [[ARG]], i32 noundef 4) #[[ATTR6]]
+; CHECK-NEXT:    [[POWI:%.*]] = call nofpclass(ninf nzero nsub nnorm) <4 x float> @llvm.powi.v4f32.i32(<4 x float> [[ARG]], i32 noundef 4) #[[ATTR9]]
 ; CHECK-NEXT:    ret <4 x float> [[POWI]]
 ;
   %powi = call <4 x float> @llvm.powi.v4f32.i32(<4 x float> %arg, i32 4)
@@ -478,7 +478,7 @@ define <4 x float> @powi_v4f32_i32_constint_even(<4 x float> %arg) {
 define <4 x float> @powi_v4f32_i32_constint_odd(<4 x float> %arg) {
 ; CHECK-LABEL: define <4 x float> @powi_v4f32_i32_constint_odd
 ; CHECK-SAME: (<4 x float> [[ARG:%.*]]) #[[ATTR5]] {
-; CHECK-NEXT:    [[POWI:%.*]] = call <4 x float> @llvm.powi.v4f32.i32(<4 x float> [[ARG]], i32 noundef 3) #[[ATTR6]]
+; CHECK-NEXT:    [[POWI:%.*]] = call <4 x float> @llvm.powi.v4f32.i32(<4 x float> [[ARG]], i32 noundef 3) #[[ATTR9]]
 ; CHECK-NEXT:    ret <4 x float> [[POWI]]
 ;
   %powi = call <4 x float> @llvm.powi.v4f32.i32(<4 x float> %arg, i32 3)
@@ -488,7 +488,7 @@ define <4 x float> @powi_v4f32_i32_constint_odd(<4 x float> %arg) {
 define <4 x float> @powi_v4f32_i32_regression(<4 x float> %arg) {
 ; CHECK-LABEL: define nofpclass(nzero) <4 x float> @powi_v4f32_i32_regression
 ; CHECK-SAME: (<4 x float> [[ARG:%.*]]) #[[ATTR5]] {
-; CHECK-NEXT:    [[POWI:%.*]] = call <4 x float> @llvm.powi.v4f32.i32(<4 x float> [[ARG]], i32 noundef 4) #[[ATTR6]]
+; CHECK-NEXT:    [[POWI:%.*]] = call <4 x float> @llvm.powi.v4f32.i32(<4 x float> [[ARG]], i32 noundef 4) #[[ATTR9]]
 ; CHECK-NEXT:    [[USER:%.*]] = fsub <4 x float> [[POWI]], splat (float 1.000000e+00)
 ; CHECK-NEXT:    ret <4 x float> [[USER]]
 ;
@@ -497,6 +497,220 @@ define <4 x float> @powi_v4f32_i32_regression(<4 x float> %arg) {
   ret <4 x float> %user
 }
 
+define float @ret_powi_nzero_or_positive_negative_exp(float nofpclass(nan ninf nsub nnorm) %base, i32 %exp) {
+; CHECK-LABEL: define nofpclass(nan nzero nsub nnorm) float @ret_powi_nzero_or_positive_negative_exp
+; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[BASE:%.*]], i32 [[EXP:%.*]]) #[[ATTR5]] {
+; CHECK-NEXT:    [[NEG_EXP:%.*]] = or i32 [[EXP]], -2147483648
+; CHECK-NEXT:    [[POWI:%.*]] = call nofpclass(nan nzero nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(nan ninf nsub nnorm) [[BASE]], i32 [[NEG_EXP]]) #[[ATTR9]]
+; CHECK-NEXT:    ret float [[POWI]]
+;
+  %neg.exp = or i32 %exp, -2147483648
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %neg.exp)
+  ret float %powi
+}
+
+define float @ret_powi_nzero_or_positive_nonnegative_exp(float nofpclass(nan ninf nsub nnorm) %base, i32 %exp) {
+; CHECK-LABEL: define nofpclass(nan ninf nsub nnorm) float @ret_powi_nzero_or_positive_nonnegative_exp
+; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[BASE:%.*]], i32 [[EXP:%.*]]) #[[ATTR5]] {
+; CHECK-NEXT:    [[NONNEG_EXP:%.*]] = and i32 [[EXP]], 2147483647
+; CHECK-NEXT:    [[POWI:%.*]] = call nofpclass(nan ninf nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(nan ninf nsub nnorm) [[BASE]], i32 [[NONNEG_EXP]]) #[[ATTR9]]
+; CHECK-NEXT:    ret float [[POWI]]
+;
+  %nonneg.exp = and i32 %exp, 2147483647
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %nonneg.exp)
+  ret float %powi
+}
+
+define float @ret_powi_ninf_or_positive_negative_exp(float nofpclass(nan nzero nsub nnorm) %base, i32 %exp) {
+; CHECK-LABEL: define nofpclass(nan ninf nsub nnorm) float @ret_powi_ninf_or_positive_negative_exp
+; CHECK-SAME: (float nofpclass(nan nzero nsub nnorm) [[BASE:%.*]], i32 [[EXP:%.*]]) #[[ATTR5]] {
+; CHECK-NEXT:    [[NEG_EXP:%.*]] = or i32 [[EXP]], -2147483648
+; CHECK-NEXT:    [[POWI:%.*]] = call nofpclass(nan ninf nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(nan nzero nsub nnorm) [[BASE]], i32 [[NEG_EXP]]) #[[ATTR9]]
+; CHECK-NEXT:    ret float [[POWI]]
+;
+  %neg.exp = or i32 %exp, -2147483648
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %neg.exp)
+  ret float %powi
+}
+
+define float @ret_powi_ninf_or_positive_nonnegative_exp(float nofpclass(nan nzero nsub nnorm) %base, i32 %exp) {
+; CHECK-LABEL: define nofpclass(nan nzero nsub nnorm) float @ret_powi_ninf_or_positive_nonnegative_exp
+; CHECK-SAME: (float nofpclass(nan nzero nsub nnorm) [[BASE:%.*]], i32 [[EXP:%.*]]) #[[ATTR5]] {
+; CHECK-NEXT:    [[NONNEG_EXP:%.*]] = and i32 [[EXP]], 2147483647
+; CHECK-NEXT:    [[POWI:%.*]] = call nofpclass(nan nzero nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(nan nzero nsub nnorm) [[BASE]], i32 [[NONNEG_EXP]]) #[[ATTR9]]
+; CHECK-NEXT:    ret float [[POWI]]
+;
+  %nonneg.exp = and i32 %exp, 2147483647
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %nonneg.exp)
+  ret float %powi
+}
+
+define float @ret_powi_nzero_or_positive_negative_exp_daz(float nofpclass(nan ninf nsub nnorm) %base, i32 %exp) denormal_fpenv(ieee|preservesign) {
+; CHECK-LABEL: define nofpclass(nan nzero nsub nnorm) float @ret_powi_nzero_or_positive_negative_exp_daz
+; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[BASE:%.*]], i32 [[EXP:%.*]]) #[[ATTR6:[0-9]+]] {
+; CHECK-NEXT:    [[NEG_EXP:%.*]] = or i32 [[EXP]], -2147483648
+; CHECK-NEXT:    [[POWI:%.*]] = call nofpclass(nan nzero nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(nan ninf nsub nnorm) [[BASE]], i32 [[NEG_EXP]]) #[[ATTR9]]
+; CHECK-NEXT:    ret float [[POWI]]
+;
+  %neg.exp = or i32 %exp, -2147483648
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %neg.exp)
+  ret float %powi
+}
+
+define float @ret_powi_nzero_or_positive_nonnegative_exp_daz(float nofpclass(nan ninf nsub nnorm) %base, i32 %exp) denormal_fpenv(ieee|preservesign) {
+; CHECK-LABEL: define nofpclass(nan ninf nsub nnorm) float @ret_powi_nzero_or_positive_nonnegative_exp_daz
+; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[BASE:%.*]], i32 [[EXP:%.*]]) #[[ATTR6]] {
+; CHECK-NEXT:    [[NONNEG_EXP:%.*]] = and i32 [[EXP]], 2147483647
+; CHECK-NEXT:    [[POWI:%.*]] = call nofpclass(nan ninf nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(nan ninf nsub nnorm) [[BASE]], i32 [[NONNEG_EXP]]) #[[ATTR9]]
+; CHECK-NEXT:    ret float [[POWI]]
+;
+  %nonneg.exp = and i32 %exp, 2147483647
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %nonneg.exp)
+  ret float %powi
+}
+
+define float @ret_powi_ninf_or_positive_negative_exp_daz(float nofpclass(nan nzero nsub nnorm) %base, i32 %exp) denormal_fpenv(ieee|preservesign) {
+; CHECK-LABEL: define nofpclass(nan ninf nsub nnorm) float @ret_powi_ninf_or_positive_negative_exp_daz
+; CHECK-SAME: (float nofpclass(nan nzero nsub nnorm) [[BASE:%.*]], i32 [[EXP:%.*]]) #[[ATTR6]] {
+; CHECK-NEXT:    [[NEG_EXP:%.*]] = or i32 [[EXP]], -2147483648
+; CHECK-NEXT:    [[POWI:%.*]] = call nofpclass(nan ninf nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(nan nzero nsub nnorm) [[BASE]], i32 [[NEG_EXP]]) #[[ATTR9]]
+; CHECK-NEXT:    ret float [[POWI]]
+;
+  %neg.exp = or i32 %exp, -2147483648
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %neg.exp)
+  ret float %powi
+}
+
+define float @ret_powi_ninf_or_positive_nonnegative_exp_daz(float nofpclass(nan nzero nsub nnorm) %base, i32 %exp) denormal_fpenv(ieee|preservesign) {
+; CHECK-LABEL: define nofpclass(nan nzero nsub nnorm) float @ret_powi_ninf_or_positive_nonnegative_exp_daz
+; CHECK-SAME: (float nofpclass(nan nzero nsub nnorm) [[BASE:%.*]], i32 [[EXP:%.*]]) #[[ATTR6]] {
+; CHECK-NEXT:    [[NONNEG_EXP:%.*]] = and i32 [[EXP]], 2147483647
+; CHECK-NEXT:    [[POWI:%.*]] = call nofpclass(nan nzero nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(nan nzero nsub nnorm) [[BASE]], i32 [[NONNEG_EXP]]) #[[ATTR9]]
+; CHECK-NEXT:    ret float [[POWI]]
+;
+  %nonneg.exp = and i32 %exp, 2147483647
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %nonneg.exp)
+  ret float %powi
+}
+
+define float @ret_powi_nzero_or_positive_negative_exp_dapz(float nofpclass(nan ninf nsub nnorm) %base, i32 %exp) denormal_fpenv(ieee|positivezero) {
+; CHECK-LABEL: define nofpclass(nan nzero nsub nnorm) float @ret_powi_nzero_or_positive_negative_exp_dapz
+; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[BASE:%.*]], i32 [[EXP:%.*]]) #[[ATTR7:[0-9]+]] {
+; CHECK-NEXT:    [[NEG_EXP:%.*]] = or i32 [[EXP]], -2147483648
+; CHECK-NEXT:    [[POWI:%.*]] = call nofpclass(nan nzero nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(nan ninf nsub nnorm) [[BASE]], i32 [[NEG_EXP]]) #[[ATTR9]]
+; CHECK-NEXT:    ret float [[POWI]]
+;
+  %neg.exp = or i32 %exp, -2147483648
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %neg.exp)
+  ret float %powi
+}
+
+define float @ret_powi_nzero_or_positive_nonnegative_exp_dapz(float nofpclass(nan ninf nsub nnorm) %base, i32 %exp) denormal_fpenv(ieee|positivezero) {
+; CHECK-LABEL: define nofpclass(nan ninf nsub nnorm) float @ret_powi_nzero_or_positive_nonnegative_exp_dapz
+; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[BASE:%.*]], i32 [[EXP:%.*]]) #[[ATTR7]] {
+; CHECK-NEXT:    [[NONNEG_EXP:%.*]] = and i32 [[EXP]], 2147483647
+; CHECK-NEXT:    [[POWI:%.*]] = call nofpclass(nan ninf nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(nan ninf nsub nnorm) [[BASE]], i32 [[NONNEG_EXP]]) #[[ATTR9]]
+; CHECK-NEXT:    ret float [[POWI]]
+;
+  %nonneg.exp = and i32 %exp, 2147483647
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %nonneg.exp)
+  ret float %powi
+}
+
+define float @ret_powi_ninf_or_positive_negative_exp_dapz(float nofpclass(nan nzero nsub nnorm) %base, i32 %exp) denormal_fpenv(ieee|positivezero) {
+; CHECK-LABEL: define nofpclass(nan ninf nsub nnorm) float @ret_powi_ninf_or_positive_negative_exp_dapz
+; CHECK-SAME: (float nofpclass(nan nzero nsub nnorm) [[BASE:%.*]], i32 [[EXP:%.*]]) #[[ATTR7]] {
+; CHECK-NEXT:    [[NEG_EXP:%.*]] = or i32 [[EXP]], -2147483648
+; CHECK-NEXT:    [[POWI:%.*]] = call nofpclass(nan ninf nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(nan nzero nsub nnorm) [[BASE]], i32 [[NEG_EXP]]) #[[ATTR9]]
+; CHECK-NEXT:    ret float [[POWI]]
+;
+  %neg.exp = or i32 %exp, -2147483648
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %neg.exp)
+  ret float %powi
+}
+
+define float @ret_powi_ninf_or_positive_nonnegative_exp_dapz(float nofpclass(nan nzero nsub nnorm) %base, i32 %exp) denormal_fpenv(ieee|positivezero) {
+; CHECK-LABEL: define nofpclass(nan nzero nsub nnorm) float @ret_powi_ninf_or_positive_nonnegative_exp_dapz
+; CHECK-SAME: (float nofpclass(nan nzero nsub nnorm) [[BASE:%.*]], i32 [[EXP:%.*]]) #[[ATTR7]] {
+; CHECK-NEXT:    [[NONNEG_EXP:%.*]] = and i32 [[EXP]], 2147483647
+; CHECK-NEXT:    [[POWI:%.*]] = call nofpclass(nan nzero nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(nan nzero nsub nnorm) [[BASE]], i32 [[NONNEG_EXP]]) #[[ATTR9]]
+; CHECK-NEXT:    ret float [[POWI]]
+;
+  %nonneg.exp = and i32 %exp, 2147483647
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %nonneg.exp)
+  ret float %powi
+}
+
+define float @ret_powi_nzero_or_positive_negative_exp_dynamic(float nofpclass(nan ninf nsub nnorm) %base, i32 %exp) denormal_fpenv(dynamic) {
+; CHECK-LABEL: define nofpclass(nan nzero nsub nnorm) float @ret_powi_nzero_or_positive_negative_exp_dynamic
+; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[BASE:%.*]], i32 [[EXP:%.*]]) #[[ATTR8:[0-9]+]] {
+; CHECK-NEXT:    [[NEG_EXP:%.*]] = or i32 [[EXP]], -2147483648
+; CHECK-NEXT:    [[POWI:%.*]] = call nofpclass(nan nzero nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(nan ninf nsub nnorm) [[BASE]], i32 [[NEG_EXP]]) #[[ATTR9]]
+; CHECK-NEXT:    ret float [[POWI]]
+;
+  %neg.exp = or i32 %exp, -2147483648
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %neg.exp)
+  ret float %powi
+}
+
+define float @ret_powi_nzero_or_positive_nonnegative_exp_dynamic(float nofpclass(nan ninf nsub nnorm) %base, i32 %exp) denormal_fpenv(dynamic) {
+; CHECK-LABEL: define nofpclass(nan ninf nsub nnorm) float @ret_powi_nzero_or_positive_nonnegative_exp_dynamic
+; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[BASE:%.*]], i32 [[EXP:%.*]]) #[[ATTR8]] {
+; CHECK-NEXT:    [[NONNEG_EXP:%.*]] = and i32 [[EXP]], 2147483647
+; CHECK-NEXT:    [[POWI:%.*]] = call nofpclass(nan ninf nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(nan ninf nsub nnorm) [[BASE]], i32 [[NONNEG_EXP]]) #[[ATTR9]]
+; CHECK-NEXT:    ret float [[POWI]]
+;
+  %nonneg.exp = and i32 %exp, 2147483647
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %nonneg.exp)
+  ret float %powi
+}
+
+define float @ret_powi_ninf_or_positive_negative_exp_dynamic(float nofpclass(nan nzero nsub nnorm) %base, i32 %exp) denormal_fpenv(dynamic) {
+; CHECK-LABEL: define nofpclass(nan ninf nsub nnorm) float @ret_powi_ninf_or_positive_negative_exp_dynamic
+; CHECK-SAME: (float nofpclass(nan nzero nsub nnorm) [[BASE:%.*]], i32 [[EXP:%.*]]) #[[ATTR8]] {
+; CHECK-NEXT:    [[NEG_EXP:%.*]] = or i32 [[EXP]], -2147483648
+; CHECK-NEXT:    [[POWI:%.*]] = call nofpclass(nan ninf nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(nan nzero nsub nnorm) [[BASE]], i32 [[NEG_EXP]]) #[[ATTR9]]
+; CHECK-NEXT:    ret float [[POWI]]
+;
+  %neg.exp = or i32 %exp, -2147483648
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %neg.exp)
+  ret float %powi
+}
+
+define float @ret_powi_ninf_or_positive_nonnegative_exp_dynamic(float nofpclass(nan nzero nsub nnorm) %base, i32 %exp) denormal_fpenv(dynamic) {
+; CHECK-LABEL: define nofpclass(nan nzero nsub nnorm) float @ret_powi_ninf_or_positive_nonnegative_exp_dynamic
+; CHECK-SAME: (float nofpclass(nan nzero nsub nnorm) [[BASE:%.*]], i32 [[EXP:%.*]]) #[[ATTR8]] {
+; CHECK-NEXT:    [[NONNEG_EXP:%.*]] = and i32 [[EXP]], 2147483647
+; CHECK-NEXT:    [[POWI:%.*]] = call nofpclass(nan nzero nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(nan nzero nsub nnorm) [[BASE]], i32 [[NONNEG_EXP]]) #[[ATTR9]]
+; CHECK-NEXT:    ret float [[POWI]]
+;
+  %nonneg.exp = and i32 %exp, 2147483647
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %nonneg.exp)
+  ret float %powi
+}
+
+define float @ret_powi_negative_special_base(float nofpclass(nan pinf pzero sub norm) %base, i32 %exp) {
+; CHECK-LABEL: define nofpclass(nan nsub nnorm) float @ret_powi_negative_special_base
+; CHECK-SAME: (float nofpclass(nan pinf pzero sub norm) [[BASE:%.*]], i32 [[EXP:%.*]]) #[[ATTR5]] {
+; CHECK-NEXT:    [[POWI:%.*]] = call nofpclass(nan nsub nnorm) float @llvm.powi.f32.i32(float nofpclass(nan pinf pzero sub norm) [[BASE]], i32 [[EXP]]) #[[ATTR9]]
+; CHECK-NEXT:    ret float [[POWI]]
+;
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %exp)
+  ret float %powi
+}
+
+define <2 x float> @ret_powi_v2_nzero_or_positive_negative_exp(<2 x float> nofpclass(nan ninf nsub nnorm) %base, i32 %exp) {
+; CHECK-LABEL: define nofpclass(nan nzero nsub nnorm) <2 x float> @ret_powi_v2_nzero_or_positive_negative_exp
+; CHECK-SAME: (<2 x float> nofpclass(nan ninf nsub nnorm) [[BASE:%.*]], i32 [[EXP:%.*]]) #[[ATTR5]] {
+; CHECK-NEXT:    [[NEG_EXP:%.*]] = or i32 [[EXP]], -2147483648
+; CHECK-NEXT:    [[POWI:%.*]] = call nofpclass(nan nzero nsub nnorm) <2 x float> @llvm.powi.v2f32.i32(<2 x float> nofpclass(nan ninf nsub nnorm) [[BASE]], i32 [[NEG_EXP]]) #[[ATTR9]]
+; CHECK-NEXT:    ret <2 x float> [[POWI]]
+;
+  %neg.exp = or i32 %exp, -2147483648
+  %powi = call <2 x float> @llvm.powi.v2f32.i32(<2 x float> %base, i32 %neg.exp)
+  ret <2 x float> %powi
+}
+
 attributes #0 = { denormal_fpenv(ieee|ieee) }
 attributes #1 = { denormal_fpenv(preservesign) }
 attributes #2 = { denormal_fpenv(positivezero|positivezero) }
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-powi.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-powi.ll
new file mode 100644
index 0000000000000..18ea46d900852
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-powi.ll
@@ -0,0 +1,72 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+declare float @llvm.powi.f32.i32(float, i32)
+declare i1 @llvm.is.fpclass.f32(float, i32 immarg)
+
+define i1 @powi_negative_special_is_negative_finite(float nofpclass(nan pinf pzero sub norm) %base, i32 %exp) {
+; CHECK-LABEL: define i1 @powi_negative_special_is_negative_finite(
+; CHECK-SAME: float nofpclass(nan pinf pzero sub norm) [[BASE:%.*]], i32 [[EXP:%.*]]) {
+; CHECK-NEXT:    ret i1 false
+;
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %exp)
+  %class = call i1 @llvm.is.fpclass.f32(float %powi, i32 24)
+  ret i1 %class
+}
+
+define i1 @powi_nzero_or_positive_negative_is_negzero(float nofpclass(nan ninf nsub nnorm) %base, i32 %exp) {
+; CHECK-LABEL: define i1 @powi_nzero_or_positive_negative_is_negzero(
+; CHECK-SAME: float nofpclass(nan ninf nsub nnorm) [[BASE:%.*]], i32 [[EXP:%.*]]) {
+; CHECK-NEXT:    ret i1 false
+;
+  %neg.exp = or i32 %exp, -2147483648
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %neg.exp)
+  %class = call i1 @llvm.is.fpclass.f32(float %powi, i32 32)
+  ret i1 %class
+}
+
+define i1 @powi_nzero_or_positive_nonnegative_is_neginf(float nofpclass(nan ninf nsub nnorm) %base, i32 %exp) {
+; CHECK-LABEL: define i1 @powi_nzero_or_positive_nonnegative_is_neginf(
+; CHECK-SAME: float nofpclass(nan ninf nsub nnorm) [[BASE:%.*]], i32 [[EXP:%.*]]) {
+; CHECK-NEXT:    ret i1 false
+;
+  %nonneg.exp = and i32 %exp, 2147483647
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %nonneg.exp)
+  %class = call i1 @llvm.is.fpclass.f32(float %powi, i32 4)
+  ret i1 %class
+}
+
+define i1 @powi_ninf_or_positive_negative_is_neginf(float nofpclass(nan nzero nsub nnorm) %base, i32 %exp) {
+; CHECK-LABEL: define i1 @powi_ninf_or_positive_negative_is_neginf(
+; CHECK-SAME: float nofpclass(nan nzero nsub nnorm) [[BASE:%.*]], i32 [[EXP:%.*]]) {
+; CHECK-NEXT:    ret i1 false
+;
+  %neg.exp = or i32 %exp, -2147483648
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %neg.exp)
+  %class = call i1 @llvm.is.fpclass.f32(float %powi, i32 4)
+  ret i1 %class
+}
+
+define i1 @powi_ninf_or_positive_nonnegative_is_negzero(float nofpclass(nan nzero nsub nnorm) %base, i32 %exp) {
+; CHECK-LABEL: define i1 @powi_ninf_or_positive_nonnegative_is_negzero(
+; CHECK-SAME: float nofpclass(nan nzero nsub nnorm) [[BASE:%.*]], i32 [[EXP:%.*]]) {
+; CHECK-NEXT:    ret i1 false
+;
+  %nonneg.exp = and i32 %exp, 2147483647
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %nonneg.exp)
+  %class = call i1 @llvm.is.fpclass.f32(float %powi, i32 32)
+  ret i1 %class
+}
+
+; A negative-zero base may produce -0.0 for a positive odd exponent.
+define i1 @powi_nzero_unknown_may_be_negzero(float nofpclass(nan inf pzero sub norm) %base, i32 %exp) {
+; CHECK-LABEL: define i1 @powi_nzero_unknown_may_be_negzero(
+; CHECK-SAME: float nofpclass(nan inf pzero sub norm) [[BASE:%.*]], i32 [[EXP:%.*]]) {
+; CHECK-NEXT:    [[POWI:%.*]] = call float @llvm.powi.f32.i32(float [[BASE]], i32 [[EXP]])
+; CHECK-NEXT:    [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[POWI]], /* (nzero) */ i32 32)
+; CHECK-NEXT:    ret i1 [[CLASS]]
+;
+  %powi = call float @llvm.powi.f32.i32(float %base, i32 %exp)
+  %class = call i1 @llvm.is.fpclass.f32(float %powi, i32 32)
+  ret i1 %class
+}
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index 382cf0f2b57ed..6b42f6f1cf8b3 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -1937,7 +1937,7 @@ TEST_F(ComputeKnownFPClassTest, PowiInfFirst) {
   expectKnownFPClass(~fcInf, std::nullopt, A4);
   expectKnownFPClass(fcAllFlags, std::nullopt, A5);
   expectKnownFPClass(fcAllFlags, std::nullopt, A6);
-  expectKnownFPClass(~fcInf, std::nullopt, A7);
+  expectKnownFPClass(~(fcInf | fcNegNormal | fcNegSubnormal), std::nullopt, A7);
 
   auto ExpectKnownNeverInf = [&](Instruction *I, bool Expected) {
     KnownFPClass Known = computeKnownFPClass(I, M->getDataLayout(), fcInf);
@@ -1973,11 +1973,13 @@ TEST_F(ComputeKnownFPClassTest, PowiInfSecond) {
       "}\n");
   expectKnownFPClass(fcPosNormal | fcNan, std::nullopt, A);
   expectKnownFPClass(fcPositive | fcNan, std::nullopt, A2);
-  expectKnownFPClass(fcAllFlags, std::nullopt, A3);
-  expectKnownFPClass(~fcInf, std::nullopt, A4);
-  expectKnownFPClass(~fcInf, std::nullopt, A5);
+  expectKnownFPClass(~(fcNegNormal | fcNegSubnormal | fcNegZero), std::nullopt,
+                     A3);
+  expectKnownFPClass(~(fcInf | fcNegNormal | fcNegSubnormal), std::nullopt, A4);
+  expectKnownFPClass(~(fcInf | fcNegNormal | fcNegSubnormal), std::nullopt, A5);
   expectKnownFPClass(fcAllFlags, std::nullopt, A6);
-  expectKnownFPClass(fcAllFlags, std::nullopt, A7);
+  expectKnownFPClass(~(fcNegNormal | fcNegSubnormal | fcNegZero), std::nullopt,
+                     A7);
 }
 
 TEST_F(ComputeKnownFPClassTest, Phi) {



More information about the llvm-commits mailing list