[llvm] cb961d3 - [ValueTracking][KnownFPClass] Cover known no-infinity cases for powi (#191736)

via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 15 08:51:50 PDT 2026


Author: Max Graey
Date: 2026-04-15T23:51:44+08:00
New Revision: cb961d331f40368d1856ad2dc00fde7ef3deb9e2

URL: https://github.com/llvm/llvm-project/commit/cb961d331f40368d1856ad2dc00fde7ef3deb9e2
DIFF: https://github.com/llvm/llvm-project/commit/cb961d331f40368d1856ad2dc00fde7ef3deb9e2.diff

LOG: [ValueTracking][KnownFPClass] Cover known no-infinity cases for powi (#191736)

Teach `computeKnownFPClass` to infer non-infinity cass for `powi`.

Rules out `inf` for `powi(x, exp)` when:
- `x ?= inf` && `exp > 0`
- `x ?= +/-0` && `exp < 0`
- `x ?= finite` && `|exp| > 1`
- `x ?= subnormal` && `exp ?= -1` (special asym case after |exp| > 1)

where `?=` is maybe equal.

It's a bit conservative, and we could refine it further, but I'd take an
iterative improvement.

Added: 
    

Modified: 
    llvm/lib/Analysis/ValueTracking.cpp
    llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
    llvm/lib/Support/KnownFPClass.cpp
    llvm/test/Transforms/Attributor/nofpclass-powi.ll
    llvm/unittests/Analysis/ValueTrackingTest.cpp
    llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 5b52efb9e1dc6..54e04eccc6613 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5459,7 +5459,7 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
       break;
     }
     case Intrinsic::powi: {
-      if ((InterestedClasses & fcNegative) == fcNone)
+      if ((InterestedClasses & (fcNan | fcInf | fcNegative)) == fcNone)
         break;
 
       const Value *Exp = II->getArgOperand(1);
@@ -5469,11 +5469,20 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
       computeKnownBits(Exp, isa<VectorType>(ExpTy) ? DemandedElts : APInt(1, 1),
                        ExponentKnownBits, Q, Depth + 1);
 
+      FPClassTest InterestedSrcs = fcNone;
+      if (InterestedClasses & fcNan)
+        InterestedSrcs |= fcNan;
+      if (!ExponentKnownBits.isZero()) {
+        if (InterestedClasses & fcInf)
+          InterestedSrcs |= fcFinite | fcInf;
+        if ((InterestedClasses & fcNegative) && !ExponentKnownBits.isEven())
+          InterestedSrcs |= fcNegative;
+      }
+
       KnownFPClass KnownSrc;
-      if (ExponentKnownBits.isZero() || !ExponentKnownBits.isEven()) {
-        computeKnownFPClass(II->getArgOperand(0), DemandedElts, fcNegative,
+      if (InterestedSrcs != fcNone)
+        computeKnownFPClass(II->getArgOperand(0), DemandedElts, InterestedSrcs,
                             KnownSrc, Q, Depth + 1);
-      }
 
       Known = KnownFPClass::powi(KnownSrc, ExponentKnownBits);
       break;

diff  --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index 0a58b611c0eca..ef85b4135a0e3 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -1379,7 +1379,7 @@ void GISelValueTracking::computeKnownFPClass(Register R,
     break;
   }
   case TargetOpcode::G_FPOWI: {
-    if ((InterestedClasses & fcNegative) == fcNone)
+    if ((InterestedClasses & (fcNan | fcInf | fcNegative)) == fcNone)
       break;
 
     Register Exp = MI.getOperand(2).getReg();
@@ -1387,10 +1387,22 @@ void GISelValueTracking::computeKnownFPClass(Register R,
     KnownBits ExponentKnownBits = getKnownBits(
         Exp, ExpTy.isVector() ? DemandedElts : APInt(1, 1), Depth + 1);
 
-    Register Val = MI.getOperand(1).getReg();
+    FPClassTest InterestedSrcs = fcNone;
+    if (InterestedClasses & fcNan)
+      InterestedSrcs |= fcNan;
+    if (!ExponentKnownBits.isZero()) {
+      if (InterestedClasses & fcInf)
+        InterestedSrcs |= fcFinite | fcInf;
+      if ((InterestedClasses & fcNegative) && !ExponentKnownBits.isEven())
+        InterestedSrcs |= fcNegative;
+    }
+
     KnownFPClass KnownSrc;
-    if (ExponentKnownBits.isZero() || !ExponentKnownBits.isEven())
-      computeKnownFPClass(Val, DemandedElts, fcNegative, KnownSrc, Depth + 1);
+    if (InterestedSrcs != fcNone) {
+      Register Val = MI.getOperand(1).getReg();
+      computeKnownFPClass(Val, DemandedElts, InterestedSrcs, KnownSrc,
+                          Depth + 1);
+    }
 
     Known = KnownFPClass::powi(KnownSrc, ExponentKnownBits);
     break;

diff  --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 96a1b26daf04d..856d227961c0a 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -862,7 +862,6 @@ KnownFPClass KnownFPClass::ldexp(const KnownFPClass &KnownSrc,
   return Known;
 }
 
-// TODO: Detect no-infinity cases
 KnownFPClass KnownFPClass::powi(const KnownFPClass &KnownSrc,
                                 const KnownBits &ExponentKnownBits) {
   KnownFPClass Known;
@@ -880,6 +879,41 @@ KnownFPClass KnownFPClass::powi(const KnownFPClass &KnownSrc,
     return Known;
   }
 
+  // powi(x, exp) --> inf
+  // when:
+  //   * powi(inf, exp), exp > 0
+  //   * powi(+/-0, exp), exp < 0
+  //   * powi(finite, exp), |exp| > 1
+  //   * powi(subnormal, -1)
+  // TODO:
+  //   1. This simple all or nothing approach. We can do better
+  //      and cover sign/parity and exp > 1 vs exp < -1 separately.
+  //   2. powi(0/nan, exp), exp > 0 can be refinable
+  //      to fcNan | fcZero | fcPosNormal.
+  {
+    APInt MinExp = ExponentKnownBits.getSignedMinValue();
+    APInt MaxExp = ExponentKnownBits.getSignedMaxValue();
+
+    // powi(inf, exp), exp > 0
+    bool MayInfSrc =
+        !KnownSrc.isKnownNever(fcInf) && MaxExp.isStrictlyPositive();
+
+    // powi(+/-0, exp), exp < 0
+    bool MayDivByZero = !KnownSrc.isKnownNever(fcZero) && MinExp.isNegative();
+
+    // powi(finite, exp), |exp| > 1
+    bool MayFinite = !KnownSrc.isKnownNever(fcNormal | fcSubnormal);
+    bool MayAbsExpGT1 = MinExp.slt(-1) || MaxExp.sgt(1);
+    bool MayFiniteOverflow = MayFinite && MayAbsExpGT1;
+
+    // powi(subnormal, -1)
+    bool MayBeNegOne = ExponentKnownBits.Zero.isZero();
+    bool MaySubnormInv = !KnownSrc.isKnownNever(fcSubnormal) && MayBeNegOne;
+
+    if (!MayInfSrc && !MayDivByZero && !MayFiniteOverflow && !MaySubnormInv)
+      Known.knownNot(fcInf);
+  }
+
   if (ExponentKnownBits.isEven()) {
     Known.knownNot(fcNegative);
     return Known;

diff  --git a/llvm/test/Transforms/Attributor/nofpclass-powi.ll b/llvm/test/Transforms/Attributor/nofpclass-powi.ll
index 476f2da040fda..cdc16e76c912f 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-powi.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-powi.ll
@@ -157,6 +157,58 @@ define float @ret_powi_f32_no_inf(float nofpclass(inf) %arg0, i32 %arg1) #0 {
   ret float %call
 }
 
+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:    ret float [[CALL]]
+;
+  %call = call float @llvm.powi.f32.i32(float %arg0, i32 1)
+  ret float %call
+}
+
+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:    ret float [[CALL]]
+;
+  %call = call float @llvm.powi.f32.i32(float %arg0, i32 2)
+  ret float %call
+}
+
+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:    ret float [[CALL]]
+;
+  %call = call float @llvm.powi.f32.i32(float %arg0, i32 -1)
+  ret float %call
+}
+
+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-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:    ret float [[CALL]]
+;
+  %call = call float @llvm.powi.f32.i32(float %arg0, i32 -1)
+  ret float %call
+}
+
+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-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:    ret float [[CALL]]
+;
+  %nonneg = and i32 %arg1, 2147483647
+  %call = call float @llvm.powi.f32.i32(float %arg0, i32 %nonneg)
+  ret float %call
+}
+
 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]] {

diff  --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index de481e39307cb..1d3c9a2724c45 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -1913,6 +1913,74 @@ TEST_F(ComputeKnownFPClassTest, MaximumNumSignBit) {
   expectKnownFPClass(fcPositive, false, A7);
 }
 
+TEST_F(ComputeKnownFPClassTest, PowiInfFirst) {
+  parseAssembly(
+      "declare float @llvm.powi.f32.i32(float, i32)\n"
+      "define float @test(i1 %cond, i32 %x, float %unknown,\n"
+      "                   float nofpclass(inf) %finite,\n"
+      "                   float nofpclass(zero sub inf) %normal,\n"
+      "                   float nofpclass(zero inf) %finite.may.sub,\n"
+      "                   float nofpclass(inf norm sub) %zero.or.nan) {\n"
+      "  %small = zext i1 %cond to i32\n"
+      "  %nonneg = and i32 %x, 2147483647\n"
+      "  %A = call float @llvm.powi.f32.i32(float %finite, i32 1)\n"
+      "  %A2 = call float @llvm.powi.f32.i32(float %finite, i32 2)\n"
+      "  %A3 = call float @llvm.powi.f32.i32(float %normal, i32 -1)\n"
+      "  %A4 = call float @llvm.powi.f32.i32(float %finite, i32 %small)\n"
+      "  %A5 = call float @llvm.powi.f32.i32(float %unknown, i32 %small)\n"
+      "  %A6 = call float @llvm.powi.f32.i32(float %finite.may.sub, i32 -1)\n"
+      "  %A7 = call float @llvm.powi.f32.i32(float %zero.or.nan, i32 %nonneg)\n"
+      "  ret float %A\n"
+      "}\n");
+  expectKnownFPClass(~fcInf, std::nullopt, A);
+  expectKnownFPClass(fcPositive | fcNan, std::nullopt, A2);
+  expectKnownFPClass(~fcInf, std::nullopt, A3);
+  expectKnownFPClass(~fcInf, std::nullopt, A4);
+  expectKnownFPClass(fcAllFlags, std::nullopt, A5);
+  expectKnownFPClass(fcAllFlags, std::nullopt, A6);
+  expectKnownFPClass(~fcInf, std::nullopt, A7);
+
+  auto ExpectKnownNeverInf = [&](Instruction *I, bool Expected) {
+    KnownFPClass Known = computeKnownFPClass(I, M->getDataLayout(), fcInf);
+    EXPECT_EQ(Expected, Known.isKnownNeverInfinity());
+  };
+
+  ExpectKnownNeverInf(A, true);
+  ExpectKnownNeverInf(A2, false);
+  ExpectKnownNeverInf(A3, true);
+  ExpectKnownNeverInf(A4, true);
+  ExpectKnownNeverInf(A5, false);
+  ExpectKnownNeverInf(A6, false);
+  ExpectKnownNeverInf(A7, true);
+}
+
+TEST_F(ComputeKnownFPClassTest, PowiInfSecond) {
+  parseAssembly(
+      "declare float @llvm.powi.f32.i32(float, i32)\n"
+      "define float @test(i32 %x, float %unknown,\n"
+      "                   float nofpclass(inf) %finite,\n"
+      "                   float nofpclass(inf norm sub) %zero.or.nan,\n"
+      "                   float nofpclass(zero norm sub) %inf.or.nan) {\n"
+      "  %neg = or i32 %x, -2147483648\n"
+      "  %nonneg = and i32 %x, 2147483647\n"
+      "  %A = call float @llvm.powi.f32.i32(float %unknown, i32 0)\n"
+      "  %A2 = call float @llvm.powi.f32.i32(float %finite, i32 -2)\n"
+      "  %A3 = call float @llvm.powi.f32.i32(float %zero.or.nan, i32 -1)\n"
+      "  %A4 = call float @llvm.powi.f32.i32(float %inf.or.nan, i32 -1)\n"
+      "  %A5 = call float @llvm.powi.f32.i32(float %inf.or.nan, i32 %neg)\n"
+      "  %A6 = call float @llvm.powi.f32.i32(float %finite, i32 %nonneg)\n"
+      "  %A7 = call float @llvm.powi.f32.i32(float %zero.or.nan, i32 %neg)\n"
+      "  ret float %A\n"
+      "}\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(fcAllFlags, std::nullopt, A6);
+  expectKnownFPClass(fcAllFlags, std::nullopt, A7);
+}
+
 TEST_F(ComputeKnownFPClassTest, Phi) {
   parseAssembly(
       "define float @test(i1 %cond, float nofpclass(nan inf) %arg0, float nofpclass(nan) %arg1) {\n"

diff  --git a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
index b10fd4621b0fd..8d888d8c50f4a 100644
--- a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
+++ b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
@@ -729,7 +729,7 @@ TEST_F(AArch64GISelMITest, TestFPClassFAdd) {
 TEST_F(AArch64GISelMITest, TestFPClassFAdd_Zero) {
   StringRef MIRString = R"(
     %ptr:_(p0) = G_IMPLICIT_DEF
-    %lhs:_(s32) = G_LOAD %ptr(p0) :: (load (s32))    
+    %lhs:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
     %rhs:_(s32) = G_FCONSTANT float 0.0
     %fadd:_(s32) = G_FADD %lhs, %rhs
     %copy_fadd:_(s32) = COPY %fadd
@@ -754,7 +754,7 @@ TEST_F(AArch64GISelMITest, TestFPClassFAdd_Zero) {
 TEST_F(AArch64GISelMITest, TestFPClassFAdd_NegZero) {
   StringRef MIRString = R"(
     %ptr:_(p0) = G_IMPLICIT_DEF
-    %lhs:_(s32) = G_LOAD %ptr(p0) :: (load (s32))    
+    %lhs:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
     %rhs:_(s32) = G_FCONSTANT float -0.0
     %fadd:_(s32) = G_FADD %lhs, %rhs
     %copy_fadd:_(s32) = COPY %fadd
@@ -779,7 +779,7 @@ TEST_F(AArch64GISelMITest, TestFPClassFAdd_NegZero) {
 TEST_F(AArch64GISelMITest, TestFPClassFstrictAdd_Zero) {
   StringRef MIRString = R"(
     %ptr:_(p0) = G_IMPLICIT_DEF
-    %lhs:_(s32) = G_LOAD %ptr(p0) :: (load (s32))    
+    %lhs:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
     %rhs:_(s32) = G_FCONSTANT float 0.0
     %fadd:_(s32) = G_STRICT_FADD %lhs, %rhs
     %copy_fadd:_(s32) = COPY %fadd
@@ -955,7 +955,7 @@ TEST_F(AArch64GISelMITest, TestFPClassSelectIsFPClass) {
     %lhs:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
     %rhs:_(s32) = G_FCONSTANT float 0.0
     %cond:_(s1) = G_IS_FPCLASS %lhs, 96
-    %sel:_(s32) = G_SELECT %cond, %lhs, %rhs 
+    %sel:_(s32) = G_SELECT %cond, %lhs, %rhs
     %copy_sel:_(s32) = COPY %sel
 )";
 
@@ -1052,6 +1052,76 @@ TEST_F(AArch64GISelMITest, TestFPClassFPowIPos) {
   EXPECT_EQ(false, Known.SignBit);
 }
 
+TEST_F(AArch64GISelMITest, TestFPClassFPowIInf) {
+  StringRef MIRString = R"(
+    %ptr:_(p0) = G_IMPLICIT_DEF
+    %load:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %val:_(s32) = G_FREEZE %load
+    %x:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %finite:_(s32) = ninf G_FNEG %val
+    %normal:_(s32) = G_FCONSTANT float 2.0
+    %zero_or_nan:_(s32) = G_FREM %val, %val
+    %nonneg_mask:_(s32) = G_CONSTANT i32 2147483647
+    %nonneg:_(s32) = G_AND %x, %nonneg_mask
+    %one:_(s32) = G_CONSTANT i32 1
+    %two:_(s32) = G_CONSTANT i32 2
+    %negone:_(s32) = G_CONSTANT i32 -1
+    %fpowi0:_(s32) = G_FPOWI %finite, %one
+    %copy_fpowi0:_(s32) = COPY %fpowi0
+    %fpowi1:_(s32) = G_FPOWI %finite, %two
+    %copy_fpowi1:_(s32) = COPY %fpowi1
+    %fpowi2:_(s32) = G_FPOWI %normal, %negone
+    %copy_fpowi2:_(s32) = COPY %fpowi2
+    %fpowi3:_(s32) = G_FPOWI %zero_or_nan, %nonneg
+    %copy_fpowi3:_(s32) = COPY %fpowi3
+)";
+
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+
+  GISelValueTracking Info(*MF);
+
+  // powi(finite, 1)  -->  ~fcInf
+  Register CopyReg0 = Copies[Copies.size() - 4];
+  MachineInstr *FinalCopy0 = MRI->getVRegDef(CopyReg0);
+  Register SrcReg0 = FinalCopy0->getOperand(1).getReg();
+  KnownFPClass Known0 = Info.computeKnownFPClass(SrcReg0, fcAllFlags);
+  KnownFPClass KnownInf0 = Info.computeKnownFPClass(SrcReg0, fcInf);
+  EXPECT_EQ(~fcInf, Known0.KnownFPClasses);
+  EXPECT_EQ(std::nullopt, Known0.SignBit);
+  EXPECT_TRUE(KnownInf0.isKnownNeverInfinity());
+
+  // powi(finite, 2)  -->  fcPositive | fcNan
+  Register CopyReg1 = Copies[Copies.size() - 3];
+  MachineInstr *FinalCopy1 = MRI->getVRegDef(CopyReg1);
+  Register SrcReg1 = FinalCopy1->getOperand(1).getReg();
+  KnownFPClass Known1 = Info.computeKnownFPClass(SrcReg1, fcAllFlags);
+  KnownFPClass KnownInf1 = Info.computeKnownFPClass(SrcReg1, fcInf);
+  EXPECT_EQ(fcPositive | fcNan, Known1.KnownFPClasses);
+  EXPECT_EQ(std::nullopt, Known1.SignBit);
+  EXPECT_FALSE(KnownInf1.isKnownNeverInfinity());
+
+  // powi(normal, -1)  -->  fcPosFinite
+  Register CopyReg2 = Copies[Copies.size() - 2];
+  MachineInstr *FinalCopy2 = MRI->getVRegDef(CopyReg2);
+  Register SrcReg2 = FinalCopy2->getOperand(1).getReg();
+  KnownFPClass Known2 = Info.computeKnownFPClass(SrcReg2, fcAllFlags);
+  KnownFPClass KnownInf2 = Info.computeKnownFPClass(SrcReg2, fcInf);
+  EXPECT_EQ(fcPosFinite, Known2.KnownFPClasses);
+  EXPECT_EQ(false, Known2.SignBit);
+  EXPECT_TRUE(KnownInf2.isKnownNeverInfinity());
+
+  // powi(zero_or_nan, nonneg)  -->  ~fcInf
+  Register CopyReg3 = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy3 = MRI->getVRegDef(CopyReg3);
+  Register SrcReg3 = FinalCopy3->getOperand(1).getReg();
+  KnownFPClass KnownInf3 = Info.computeKnownFPClass(SrcReg3, fcInf);
+  EXPECT_TRUE(KnownInf3.isKnownNeverInfinity());
+
+  // TODO: Add powi(0/nan, exp), exp > 0  -->  fcNan | fcZero | fcPosNormal
+}
+
 TEST_F(AArch64GISelMITest, TestFPClassFDiv) {
   StringRef MIRString = R"(
     %ptr:_(p0) = G_IMPLICIT_DEF


        


More information about the llvm-commits mailing list