[llvm] [ValueTracking][KnownFPClass] Cover known no-infinity cases for powi (PR #191736)
Max Graey via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 13 09:50:29 PDT 2026
https://github.com/MaxGraey updated https://github.com/llvm/llvm-project/pull/191736
>From ae2adeff45221ad79e4cd01c432e5d3d968850ef Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Mon, 13 Apr 2026 00:51:22 +0300
Subject: [PATCH 1/9] init
---
llvm/lib/Support/KnownFPClass.cpp | 28 +++++++++-
llvm/unittests/Analysis/ValueTrackingTest.cpp | 55 +++++++++++++++++++
2 files changed, 82 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 96a1b26daf04d..8bc3741149f24 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,33 @@ 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) --> overflow, |exp| > 1 or powi(subnormal, -1)
+ {
+ 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) --> overflow, |exp| > 1 or powi(subnormal, -1)
+ bool MayFinite = !KnownSrc.isKnownNever(fcNormal | fcSubnormal);
+ bool MayAbsExpGT1 = MinExp.slt(-1) || MaxExp.sgt(1);
+ bool MayBeNegOne = ExponentKnownBits.Zero.isZero();
+ bool MaySubnormInv = !KnownSrc.isKnownNever(fcSubnormal) && MayBeNegOne;
+ bool MayOverflow = (MayFinite && MayAbsExpGT1) || MaySubnormInv;
+
+ if (!MayInfSrc && !MayDivByZero && !MayOverflow)
+ Known.knownNot(fcInf);
+ }
+
if (ExponentKnownBits.isEven()) {
Known.knownNot(fcNegative);
return Known;
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index de481e39307cb..632279b8e6b8f 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -1913,6 +1913,61 @@ TEST_F(ComputeKnownFPClassTest, MaximumNumSignBit) {
expectKnownFPClass(fcPositive, false, A7);
}
+TEST_F(ComputeKnownFPClassTest, PowiInfBasic) {
+ 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);
+}
+
+TEST_F(ComputeKnownFPClassTest, PowiInfSpecial) {
+ 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(fcAllFlags, 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"
>From 862ab9f6e91a7039e314a8c9228c8c7dce5e328f Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Mon, 13 Apr 2026 01:04:05 +0300
Subject: [PATCH 2/9] refactor & add TODO
---
llvm/lib/Support/KnownFPClass.cpp | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 8bc3741149f24..6a33569ef9717 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -883,7 +883,11 @@ KnownFPClass KnownFPClass::powi(const KnownFPClass &KnownSrc,
// when:
// * powi(inf, exp), exp > 0
// * powi(+/-0, exp), exp < 0
- // * powi(finite, exp) --> overflow, |exp| > 1 or powi(subnormal, -1)
+ // * powi(finite, exp), |exp| > 1
+ // * powi(subnormal, -1)
+ // TODO:
+ // This simple all or nothing approach. We can do better
+ // and cover sign/parity and exp > 1 vs exp < -1 separately.
{
APInt MinExp = ExponentKnownBits.getSignedMinValue();
APInt MaxExp = ExponentKnownBits.getSignedMaxValue();
@@ -895,14 +899,16 @@ KnownFPClass KnownFPClass::powi(const KnownFPClass &KnownSrc,
// powi(+/-0, exp), exp < 0
bool MayDivByZero = !KnownSrc.isKnownNever(fcZero) && MinExp.isNegative();
- // powi(finite, exp) --> overflow, |exp| > 1 or powi(subnormal, -1)
+ // 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;
- bool MayOverflow = (MayFinite && MayAbsExpGT1) || MaySubnormInv;
- if (!MayInfSrc && !MayDivByZero && !MayOverflow)
+ if (!MayInfSrc && !MayDivByZero && !MayFiniteOverflow && !MaySubnormInv)
Known.knownNot(fcInf);
}
>From ec8784e49b8827e12805ded6297bbb9f5165566d Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Mon, 13 Apr 2026 01:41:45 +0300
Subject: [PATCH 3/9] fix expected in one test
---
llvm/unittests/Analysis/ValueTrackingTest.cpp | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index 632279b8e6b8f..1546d8e6fafd7 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -1939,6 +1939,19 @@ TEST_F(ComputeKnownFPClassTest, PowiInfBasic) {
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, PowiInfSpecial) {
@@ -1960,7 +1973,7 @@ TEST_F(ComputeKnownFPClassTest, PowiInfSpecial) {
" ret float %A\n"
"}\n");
expectKnownFPClass(fcPosNormal | fcNan, std::nullopt, A);
- expectKnownFPClass(fcAllFlags, std::nullopt, A2);
+ expectKnownFPClass(fcPositive | fcNan, std::nullopt, A2);
expectKnownFPClass(fcAllFlags, std::nullopt, A3);
expectKnownFPClass(~fcInf, std::nullopt, A4);
expectKnownFPClass(~fcInf, std::nullopt, A5);
>From 599d5da7b2dea22a525559148a0be93e2535bf81 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Mon, 13 Apr 2026 13:00:45 +0300
Subject: [PATCH 4/9] prepare InterestedClasses in value tracking
---
llvm/lib/Analysis/ValueTracking.cpp | 17 +++++++++---
llvm/unittests/Analysis/ValueTrackingTest.cpp | 26 +++++++++----------
2 files changed, 26 insertions(+), 17 deletions(-)
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/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index 1546d8e6fafd7..4034e2982df7f 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -1913,7 +1913,7 @@ TEST_F(ComputeKnownFPClassTest, MaximumNumSignBit) {
expectKnownFPClass(fcPositive, false, A7);
}
-TEST_F(ComputeKnownFPClassTest, PowiInfBasic) {
+TEST_F(ComputeKnownFPClassTest, PowiInfFirst) {
parseAssembly(
"declare float @llvm.powi.f32.i32(float, i32)\n"
"define float @test(i1 %cond, i32 %x, float %unknown,\n"
@@ -1940,21 +1940,21 @@ TEST_F(ComputeKnownFPClassTest, PowiInfBasic) {
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());
- // };
+ 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);
+ ExpectKnownNeverInf(A, true);
+ ExpectKnownNeverInf(A2, false);
+ ExpectKnownNeverInf(A3, true);
+ ExpectKnownNeverInf(A4, true);
+ ExpectKnownNeverInf(A5, false);
+ ExpectKnownNeverInf(A6, false);
+ ExpectKnownNeverInf(A7, true);
}
-TEST_F(ComputeKnownFPClassTest, PowiInfSpecial) {
+TEST_F(ComputeKnownFPClassTest, PowiInfSecond) {
parseAssembly(
"declare float @llvm.powi.f32.i32(float, i32)\n"
"define float @test(i32 %x, float %unknown,\n"
>From 49a218de7e6820f18bdff655ad160f1044cf9d89 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Mon, 13 Apr 2026 13:05:09 +0300
Subject: [PATCH 5/9] fix format
---
llvm/unittests/Analysis/ValueTrackingTest.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index 4034e2982df7f..1d3c9a2724c45 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -1945,7 +1945,7 @@ TEST_F(ComputeKnownFPClassTest, PowiInfFirst) {
EXPECT_EQ(Expected, Known.isKnownNeverInfinity());
};
- ExpectKnownNeverInf(A, true);
+ ExpectKnownNeverInf(A, true);
ExpectKnownNeverInf(A2, false);
ExpectKnownNeverInf(A3, true);
ExpectKnownNeverInf(A4, true);
>From 3c401281f9ff5d49eb5677ace1325ccd5b078e45 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Mon, 13 Apr 2026 14:39:31 +0300
Subject: [PATCH 6/9] add lit tests for nofpclass-powi.lll
---
.../Transforms/Attributor/nofpclass-powi.ll | 42 +++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/llvm/test/Transforms/Attributor/nofpclass-powi.ll b/llvm/test/Transforms/Attributor/nofpclass-powi.ll
index 476f2da040fda..66513435cd4bc 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-powi.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-powi.ll
@@ -157,6 +157,48 @@ 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_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]] {
>From bb6bf2ce9d432b5a0b8ae4583feb552c27670062 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Mon, 13 Apr 2026 17:03:00 +0300
Subject: [PATCH 7/9] add ret_powi_f32_finite_exp_two test
---
llvm/test/Transforms/Attributor/nofpclass-powi.ll | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/llvm/test/Transforms/Attributor/nofpclass-powi.ll b/llvm/test/Transforms/Attributor/nofpclass-powi.ll
index 66513435cd4bc..cdc16e76c912f 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-powi.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-powi.ll
@@ -167,6 +167,16 @@ define float @ret_powi_f32_finite_exp_one(float nofpclass(inf) %arg0) #0 {
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]] {
>From 6ebab47b309b994e38f9220ff311012a04504bdf Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Mon, 13 Apr 2026 19:34:49 +0300
Subject: [PATCH 8/9] update G_FPOWI case for GISelValueTracking. Narrow fp
class for according unit test
---
.../CodeGen/GlobalISel/GISelValueTracking.cpp | 27 ++++++++++++-------
.../CodeGen/GlobalISel/KnownFPClassTest.cpp | 2 +-
2 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index a00e17cb3e441..be670bf962f21 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -1417,7 +1417,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();
@@ -1425,9 +1425,22 @@ void GISelValueTracking::computeKnownFPClass(Register R,
KnownBits ExponentKnownBits = getKnownBits(
Exp, ExpTy.isVector() ? DemandedElts : APInt(1, 1), Depth + 1);
- if (ExponentKnownBits.Zero[0]) { // Is even
- Known.knownNot(fcNegative);
- break;
+ FPClassTest InterestedSrcs = fcNone;
+ if ((InterestedClasses & fcNan) != fcNone)
+ InterestedSrcs |= fcNan;
+ if (!ExponentKnownBits.isZero()) {
+ if ((InterestedClasses & fcInf) != fcNone)
+ InterestedSrcs |= fcFinite | fcInf;
+ if ((InterestedClasses & fcNegative) != fcNone &&
+ !ExponentKnownBits.isEven())
+ InterestedSrcs |= fcNegative;
+ }
+
+ KnownFPClass KnownSrc;
+ if (InterestedSrcs != fcNone) {
+ Register Val = MI.getOperand(1).getReg();
+ computeKnownFPClass(Val, DemandedElts, InterestedSrcs, KnownSrc,
+ Depth + 1);
}
// Given that exp is an integer, here are the
@@ -1438,11 +1451,7 @@ void GISelValueTracking::computeKnownFPClass(Register R,
// 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.
- Register Val = MI.getOperand(1).getReg();
- KnownFPClass KnownSrc;
- computeKnownFPClass(Val, DemandedElts, fcNegative, KnownSrc, Depth + 1);
- if (KnownSrc.isKnownNever(fcNegative))
- Known.knownNot(fcNegative);
+ Known = KnownFPClass::powi(KnownSrc, ExponentKnownBits);
break;
}
case TargetOpcode::G_FLDEXP:
diff --git a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
index e47e53968b090..2e39bcd5527d7 100644
--- a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
+++ b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
@@ -1047,7 +1047,7 @@ TEST_F(AArch64GISelMITest, TestFPClassFPowIPos) {
KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
- EXPECT_EQ(fcPositive | fcNan, Known.KnownFPClasses);
+ EXPECT_EQ(fcPositive, Known.KnownFPClasses);
EXPECT_EQ(std::nullopt, Known.SignBit);
}
>From b500604abd2c4599b4bb69ad121a4926b15c4623 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Mon, 13 Apr 2026 19:50:10 +0300
Subject: [PATCH 9/9] minor refactoring
---
llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index d42b60c4704df..ef85b4135a0e3 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -1388,13 +1388,12 @@ void GISelValueTracking::computeKnownFPClass(Register R,
Exp, ExpTy.isVector() ? DemandedElts : APInt(1, 1), Depth + 1);
FPClassTest InterestedSrcs = fcNone;
- if ((InterestedClasses & fcNan) != fcNone)
+ if (InterestedClasses & fcNan)
InterestedSrcs |= fcNan;
if (!ExponentKnownBits.isZero()) {
- if ((InterestedClasses & fcInf) != fcNone)
+ if (InterestedClasses & fcInf)
InterestedSrcs |= fcFinite | fcInf;
- if ((InterestedClasses & fcNegative) != fcNone &&
- !ExponentKnownBits.isEven())
+ if ((InterestedClasses & fcNegative) && !ExponentKnownBits.isEven())
InterestedSrcs |= fcNegative;
}
More information about the llvm-commits
mailing list