[llvm] [KnownFPClass] Add KnownFPClass deductions for `pow` (PR #215592)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 18 22:20:20 PDT 2026
https://github.com/ZERICO2005 updated https://github.com/llvm/llvm-project/pull/215592
>From 3104be008bdb532e4838e8843c5873cc15168858 Mon Sep 17 00:00:00 2001
From: zerico <zerico2005 at gmail.com>
Date: Mon, 10 Aug 2026 23:30:26 -0600
Subject: [PATCH] [KnownFPClass] Add KnownFPClass deductions for pow
---
llvm/include/llvm/Support/KnownFPClass.h | 4 +
llvm/lib/Analysis/ValueTracking.cpp | 56 +++++
.../CodeGen/GlobalISel/GISelValueTracking.cpp | 56 +++++
llvm/lib/Support/KnownFPClass.cpp | 42 ++++
.../Transforms/Attributor/nofpclass-pow.ll | 226 ++++++++++++++++++
.../simplify-demanded-fpclass-pow.ll | 65 +++++
llvm/test/Transforms/InstSimplify/pow.ll | 101 ++++++++
llvm/unittests/Analysis/ValueTrackingTest.cpp | 14 ++
.../CodeGen/GlobalISel/KnownFPClassTest.cpp | 106 ++++++++
9 files changed, 670 insertions(+)
create mode 100644 llvm/test/Transforms/Attributor/nofpclass-pow.ll
create mode 100644 llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-pow.ll
create mode 100644 llvm/test/Transforms/InstSimplify/pow.ll
diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h
index dadf4133d826b..389128969ac4c 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -479,6 +479,10 @@ struct KnownFPClass {
const KnownFPClass &Src, const KnownBits &ExpBits,
const fltSemantics &Flt, DenormalMode Mode = DenormalMode::getDynamic());
+ /// Propagate known class for pow
+ LLVM_ABI static KnownFPClass pow(const KnownFPClass &LHS,
+ const KnownFPClass &RHS);
+
/// Propagate known class for powi
static LLVM_ABI KnownFPClass powi(const KnownFPClass &Src,
const KnownBits &N);
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 55f6696fe4914..d297fe8a8895c 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5562,6 +5562,62 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
break;
}
+ case Intrinsic::pow: {
+ const bool WantNaN = (InterestedClasses & fcNan) != fcNone;
+ const bool WantNegNonZeroFinite =
+ (InterestedClasses & (fcNegNormal | fcNegSubnormal)) != fcNone;
+ const bool WantNegZero = (InterestedClasses & fcNegZero) != fcNone;
+ const bool WantNegInf = (InterestedClasses & fcNegInf) != fcNone;
+ if (!WantNaN && !WantNegNonZeroFinite && !WantNegZero && !WantNegInf)
+ break;
+
+ FPClassTest InterestedLHS = fcNone;
+ FPClassTest InterestedRHS = fcNone;
+ if (WantNaN) {
+ // pow may return NaN if one of the arguments is NaN. NaN may also be
+ // produced from a negative, non-zero finite base and a non-integer
+ // exponent.
+ InterestedLHS |= fcNan | fcNegNormal | fcNegSubnormal;
+ InterestedRHS |= fcNan;
+ }
+ if (WantNegNonZeroFinite)
+ InterestedLHS |= fcNegNormal | fcNegSubnormal;
+ if (WantNegZero || WantNegInf)
+ InterestedLHS |= fcNegative;
+
+ KnownFPClass KnownLHS;
+ computeKnownFPClass(II->getArgOperand(0), DemandedElts, InterestedLHS,
+ KnownLHS, Q, Depth + 1);
+
+ // If the LHS is unknown, querying the RHS is only useful for rare edge
+ // cases.
+ if (KnownLHS.isUnknown())
+ break;
+
+ // If only one negative special value remains possible for the LHS,
+ // request only the sign of normal RHS needed for each interested result.
+ if (!KnownLHS.isKnownNever(fcNegative) &&
+ KnownLHS.isKnownNever(fcNegNormal | fcNegSubnormal)) {
+ if (KnownLHS.isKnownNever(fcNegInf)) {
+ if (WantNegZero)
+ InterestedRHS |= fcPosNormal;
+ if (WantNegInf)
+ InterestedRHS |= fcNegNormal;
+ } else if (KnownLHS.isKnownNever(fcNegZero)) {
+ if (WantNegZero)
+ InterestedRHS |= fcNegNormal;
+ if (WantNegInf)
+ InterestedRHS |= fcPosNormal;
+ }
+ }
+
+ KnownFPClass KnownRHS;
+ if (InterestedRHS != fcNone)
+ computeKnownFPClass(II->getArgOperand(1), DemandedElts, InterestedRHS,
+ KnownRHS, Q, Depth + 1);
+ Known = KnownFPClass::pow(KnownLHS, KnownRHS);
+ break;
+ }
case Intrinsic::powi: {
if ((InterestedClasses & (fcNan | fcInf | fcNegative)) == fcNone)
break;
diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index f5b8cb3a0fbd7..2f5188d479007 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -1630,6 +1630,61 @@ void GISelValueTracking::computeKnownFPClass(Register R,
Known = KnownFPClass::log(KnownSrc, Mode);
break;
}
+ case TargetOpcode::G_FPOW: {
+ const bool WantNaN = (InterestedClasses & fcNan) != fcNone;
+ const bool WantNegNonZeroFinite =
+ (InterestedClasses & (fcNegNormal | fcNegSubnormal)) != fcNone;
+ const bool WantNegZero = (InterestedClasses & fcNegZero) != fcNone;
+ const bool WantNegInf = (InterestedClasses & fcNegInf) != fcNone;
+ if (!WantNaN && !WantNegNonZeroFinite && !WantNegZero && !WantNegInf)
+ break;
+
+ FPClassTest InterestedLHS = fcNone;
+ FPClassTest InterestedRHS = fcNone;
+ if (WantNaN) {
+ // pow may return NaN if one of the arguments is NaN. NaN may be produced
+ // from a non-zero-finite-negative base and a non-integer exponent.
+ InterestedLHS |= fcNan | fcNegNormal | fcNegSubnormal;
+ InterestedRHS |= fcNan;
+ }
+ if (WantNegNonZeroFinite)
+ InterestedLHS |= fcNegNormal | fcNegSubnormal;
+ if (WantNegZero || WantNegInf)
+ InterestedLHS |= fcNegative;
+
+ KnownFPClass KnownLHS;
+ computeKnownFPClass(MI.getOperand(1).getReg(), DemandedElts, InterestedLHS,
+ KnownLHS, Depth + 1);
+
+ // If the LHS is unknown, querying the RHS is only useful for rare edge
+ // cases.
+ if (KnownLHS.isUnknown())
+ break;
+
+ // If only one negative special value remains possible for the LHS,
+ // request only the sign of normal RHS needed for each interested result.
+ if (!KnownLHS.isKnownNever(fcNegative) &&
+ KnownLHS.isKnownNever(fcNegNormal | fcNegSubnormal)) {
+ if (KnownLHS.isKnownNever(fcNegInf)) {
+ if (WantNegZero)
+ InterestedRHS |= fcPosNormal;
+ if (WantNegInf)
+ InterestedRHS |= fcNegNormal;
+ } else if (KnownLHS.isKnownNever(fcNegZero)) {
+ if (WantNegZero)
+ InterestedRHS |= fcNegNormal;
+ if (WantNegInf)
+ InterestedRHS |= fcPosNormal;
+ }
+ }
+
+ KnownFPClass KnownRHS;
+ if (InterestedRHS != fcNone)
+ computeKnownFPClass(MI.getOperand(2).getReg(), DemandedElts,
+ InterestedRHS, KnownRHS, Depth + 1);
+ Known = KnownFPClass::pow(KnownLHS, KnownRHS);
+ break;
+ }
case TargetOpcode::G_FPOWI: {
if ((InterestedClasses & (fcNan | fcInf | fcNegative)) == fcNone)
break;
@@ -2219,6 +2274,7 @@ bool GISelValueTracking::isKnownNeverNaN(Register Val, bool SNaN) {
case TargetOpcode::G_FLOG:
case TargetOpcode::G_FLOG2:
case TargetOpcode::G_FLOG10:
+ case TargetOpcode::G_FPOW:
case TargetOpcode::G_FPOWI:
case TargetOpcode::G_FLDEXP:
case TargetOpcode::G_STRICT_FLDEXP:
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index ac9406ecd0280..b581cea83a322 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -853,6 +853,48 @@ KnownFPClass KnownFPClass::ldexp(const KnownFPClass &KnownSrc,
ExpBits.getSignedMaxValue(), Flt, Mode);
}
+KnownFPClass KnownFPClass::pow(const KnownFPClass &KnownLHS,
+ const KnownFPClass &KnownRHS) {
+ KnownFPClass Known;
+
+ Known.propagateNonSNaN(KnownLHS, KnownRHS);
+
+ // pow may return NaN if one of the arguments is NaN. NaN may be produced from
+ // a non-zero-finite-negative base and a non-integer exponent.
+ if (KnownLHS.isKnownNever(fcNan | fcNegNormal | fcNegSubnormal) &&
+ KnownRHS.isKnownNeverNaN())
+ Known.knownNot(fcNan);
+
+ // We could rule out negative and subnormal results when exponent is known to
+ // never be a normal value, but having either argument being known to never be
+ // normal is unlikely and not worth considering.
+
+ // Only a negative base raised to an odd power returns a negative value.
+ if (KnownLHS.isKnownNever(fcNegative)) {
+ Known.knownNot(fcNegative);
+ } else if (KnownLHS.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.
+
+ // pow(-0.0, odd-positive) = -0.0
+ // pow(-inf, odd-negative) = -0.0
+ if ((KnownLHS.isKnownNever(fcNegZero) ||
+ KnownRHS.isKnownNever(fcPosNormal)) &&
+ (KnownLHS.isKnownNever(fcNegInf) || KnownRHS.isKnownNever(fcNegNormal)))
+ Known.knownNot(fcNegZero);
+
+ // pow(-0.0, odd-negative) = -inf
+ // pow(-inf, odd-positive) = -inf
+ if ((KnownLHS.isKnownNever(fcNegZero) ||
+ KnownRHS.isKnownNever(fcNegNormal)) &&
+ (KnownLHS.isKnownNever(fcNegInf) || KnownRHS.isKnownNever(fcPosNormal)))
+ Known.knownNot(fcNegInf);
+ }
+
+ return Known;
+}
+
KnownFPClass KnownFPClass::powi(const KnownFPClass &KnownSrc,
const KnownBits &ExponentKnownBits) {
KnownFPClass Known;
diff --git a/llvm/test/Transforms/Attributor/nofpclass-pow.ll b/llvm/test/Transforms/Attributor/nofpclass-pow.ll
new file mode 100644
index 0000000000000..395e0cd5131e9
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/nofpclass-pow.ll
@@ -0,0 +1,226 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal < %s | FileCheck %s
+
+declare float @llvm.pow.f32(float, float)
+declare <2 x float> @llvm.pow.v2f32(<2 x float>, <2 x float>)
+declare float @llvm.fabs.f32(float)
+
+define float @ret_pow_nonneg_base(float nofpclass(ninf nzero nsub nnorm) %base, float %exp) {
+; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_pow_nonneg_base(
+; CHECK-SAME: float nofpclass(ninf nzero nsub nnorm) [[BASE:%.*]], float [[EXP:%.*]]) #[[ATTR1:[0-9]+]] {
+; CHECK-NEXT: [[POW:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.pow.f32(float nofpclass(ninf nzero nsub nnorm) [[BASE]], float [[EXP]]) #[[ATTR2:[0-9]+]]
+; CHECK-NEXT: ret float [[POW]]
+;
+ %pow = call float @llvm.pow.f32(float %base, float %exp)
+ ret float %pow
+}
+
+; It is rare that the exponent is known never normal, so we will not go out of
+; our way to perform this deduction.
+define float @ret_pow_nonnormal_exponent(float %base, float nofpclass(norm) %exp) {
+; CHECK-LABEL: define float @ret_pow_nonnormal_exponent(
+; CHECK-SAME: float [[BASE:%.*]], float nofpclass(norm) [[EXP:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[POW:%.*]] = call float @llvm.pow.f32(float [[BASE]], float nofpclass(norm) [[EXP]]) #[[ATTR2]]
+; CHECK-NEXT: ret float [[POW]]
+;
+ %pow = call float @llvm.pow.f32(float %base, float %exp)
+ ret float %pow
+}
+
+define float @ret_pow_nonneg_nonan(float nofpclass(nan ninf nzero nsub nnorm) %base, float nofpclass(nan) %exp) {
+; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_pow_nonneg_nonan(
+; CHECK-SAME: float nofpclass(nan ninf nzero nsub nnorm) [[BASE:%.*]], float nofpclass(nan) [[EXP:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[POW:%.*]] = call nofpclass(nan ninf nzero nsub nnorm) float @llvm.pow.f32(float nofpclass(nan ninf nzero nsub nnorm) [[BASE]], float nofpclass(nan) [[EXP]]) #[[ATTR2]]
+; CHECK-NEXT: ret float [[POW]]
+;
+ %pow = call float @llvm.pow.f32(float %base, float %exp)
+ ret float %pow
+}
+
+define float @ret_pow_base_no_nsub_nnorm_exponent_any(float nofpclass(nsub nnorm) %base, float %exp) {
+; CHECK-LABEL: define nofpclass(nsub nnorm) float @ret_pow_base_no_nsub_nnorm_exponent_any(
+; CHECK-SAME: float nofpclass(nsub nnorm) [[BASE:%.*]], float [[EXP:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[POW:%.*]] = call nofpclass(nsub nnorm) float @llvm.pow.f32(float nofpclass(nsub nnorm) [[BASE]], float [[EXP]]) #[[ATTR2]]
+; CHECK-NEXT: ret float [[POW]]
+;
+ %pow = call float @llvm.pow.f32(float %base, float %exp)
+ ret float %pow
+}
+
+define float @ret_pow_base_no_nan_nsub_nnorm_exponent_no_nan(float nofpclass(nan nsub nnorm) %base, float nofpclass(nan) %exp) {
+; CHECK-LABEL: define nofpclass(nan nsub nnorm) float @ret_pow_base_no_nan_nsub_nnorm_exponent_no_nan(
+; CHECK-SAME: float nofpclass(nan nsub nnorm) [[BASE:%.*]], float nofpclass(nan) [[EXP:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[POW:%.*]] = call nofpclass(nan nsub nnorm) float @llvm.pow.f32(float nofpclass(nan nsub nnorm) [[BASE]], float nofpclass(nan) [[EXP]]) #[[ATTR2]]
+; CHECK-NEXT: ret float [[POW]]
+;
+ %pow = call float @llvm.pow.f32(float %base, float %exp)
+ ret float %pow
+}
+
+; Attributor also requests NaN information, so ValueTracking queries the RHS
+; after obtaining useful LHS information. The RHS's nofpclass(norm) attribute
+; then rules out -0.0 and -Inf as well. A negative-only query would not inspect
+; the RHS.
+define float @ret_pow_base_no_nsub_nnorm_exponent_no_norm(float nofpclass(nsub nnorm) %base, float nofpclass(norm) %exp) {
+; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_pow_base_no_nsub_nnorm_exponent_no_norm(
+; CHECK-SAME: float nofpclass(nsub nnorm) [[BASE:%.*]], float nofpclass(norm) [[EXP:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[POW:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.pow.f32(float nofpclass(nsub nnorm) [[BASE]], float nofpclass(norm) [[EXP]]) #[[ATTR2]]
+; CHECK-NEXT: ret float [[POW]]
+;
+ %pow = call float @llvm.pow.f32(float %base, float %exp)
+ ret float %pow
+}
+
+define float @ret_pow_base_no_nan_nsub_nnorm_exponent_no_nan_norm(float nofpclass(nan nsub nnorm) %base, float nofpclass(nan norm) %exp) {
+; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_pow_base_no_nan_nsub_nnorm_exponent_no_nan_norm(
+; CHECK-SAME: float nofpclass(nan nsub nnorm) [[BASE:%.*]], float nofpclass(nan norm) [[EXP:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[POW:%.*]] = call nofpclass(nan ninf nzero nsub nnorm) float @llvm.pow.f32(float nofpclass(nan nsub nnorm) [[BASE]], float nofpclass(nan norm) [[EXP]]) #[[ATTR2]]
+; CHECK-NEXT: ret float [[POW]]
+;
+ %pow = call float @llvm.pow.f32(float %base, float %exp)
+ ret float %pow
+}
+
+; qNaN may be produced when a negative base is raised to a non-integer exponent.
+define float @ret_pow_neg_base_nonan(float nofpclass(nan inf zero sub pnorm) %base, float nofpclass(nan) %exp) {
+; CHECK-LABEL: define nofpclass(snan) float @ret_pow_neg_base_nonan(
+; CHECK-SAME: float nofpclass(nan inf zero sub pnorm) [[BASE:%.*]], float nofpclass(nan) [[EXP:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[POW:%.*]] = call nofpclass(snan) float @llvm.pow.f32(float nofpclass(nan inf zero sub pnorm) [[BASE]], float nofpclass(nan) [[EXP]]) #[[ATTR2]]
+; CHECK-NEXT: ret float [[POW]]
+;
+ %pow = call float @llvm.pow.f32(float %base, float %exp)
+ ret float %pow
+}
+
+define float @ret_pow_non_snan_inputs(float nofpclass(snan) %base, float nofpclass(snan) %exp) {
+; CHECK-LABEL: define nofpclass(snan) float @ret_pow_non_snan_inputs(
+; CHECK-SAME: float nofpclass(snan) [[BASE:%.*]], float nofpclass(snan) [[EXP:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[POW:%.*]] = call nofpclass(snan) float @llvm.pow.f32(float nofpclass(snan) [[BASE]], float nofpclass(snan) [[EXP]]) #[[ATTR2]]
+; CHECK-NEXT: ret float [[POW]]
+;
+ %pow = call float @llvm.pow.f32(float %base, float %exp)
+ ret float %pow
+}
+
+define float @ret_pow_subnormal_posnormal(float nofpclass(nan inf norm zero) %base, float nofpclass(nan inf sub nnorm zero) %exp) {
+; CHECK-LABEL: define nofpclass(snan) float @ret_pow_subnormal_posnormal(
+; CHECK-SAME: float nofpclass(nan inf zero norm) [[BASE:%.*]], float nofpclass(nan inf zero sub nnorm) [[EXP:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[POW:%.*]] = call nofpclass(snan) float @llvm.pow.f32(float nofpclass(nan inf zero norm) [[BASE]], float nofpclass(nan inf zero sub nnorm) [[EXP]]) #[[ATTR2]]
+; CHECK-NEXT: ret float [[POW]]
+;
+ %pow = call float @llvm.pow.f32(float %base, float %exp)
+ ret float %pow
+}
+
+define float @ret_pow_subnormal_possubnormal(float nofpclass(nan inf norm zero) %base, float nofpclass(nan inf nsub norm zero) %exp) {
+; CHECK-LABEL: define nofpclass(snan) float @ret_pow_subnormal_possubnormal(
+; CHECK-SAME: float nofpclass(nan inf zero norm) [[BASE:%.*]], float nofpclass(nan inf zero nsub norm) [[EXP:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[POW:%.*]] = call nofpclass(snan) float @llvm.pow.f32(float nofpclass(nan inf zero norm) [[BASE]], float nofpclass(nan inf zero nsub norm) [[EXP]]) #[[ATTR2]]
+; CHECK-NEXT: ret float [[POW]]
+;
+ %pow = call float @llvm.pow.f32(float %base, float %exp)
+ ret float %pow
+}
+
+define float @ret_pow_subnormal_negsubnormal(float nofpclass(nan inf norm zero) %base, float nofpclass(nan inf psub norm zero) %exp) {
+; CHECK-LABEL: define nofpclass(snan) float @ret_pow_subnormal_negsubnormal(
+; CHECK-SAME: float nofpclass(nan inf zero norm) [[BASE:%.*]], float nofpclass(nan inf zero psub norm) [[EXP:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[POW:%.*]] = call nofpclass(snan) float @llvm.pow.f32(float nofpclass(nan inf zero norm) [[BASE]], float nofpclass(nan inf zero psub norm) [[EXP]]) #[[ATTR2]]
+; CHECK-NEXT: ret float [[POW]]
+;
+ %pow = call float @llvm.pow.f32(float %base, float %exp)
+ ret float %pow
+}
+
+define float @ret_pow_subnormal_negnormal(float nofpclass(nan inf norm zero) %base, float nofpclass(nan inf sub pnorm zero) %exp) {
+; CHECK-LABEL: define nofpclass(snan) float @ret_pow_subnormal_negnormal(
+; CHECK-SAME: float nofpclass(nan inf zero norm) [[BASE:%.*]], float nofpclass(nan inf zero sub pnorm) [[EXP:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[POW:%.*]] = call nofpclass(snan) float @llvm.pow.f32(float nofpclass(nan inf zero norm) [[BASE]], float nofpclass(nan inf zero sub pnorm) [[EXP]]) #[[ATTR2]]
+; CHECK-NEXT: ret float [[POW]]
+;
+ %pow = call float @llvm.pow.f32(float %base, float %exp)
+ ret float %pow
+}
+
+; Negative subnormal exponents cannot be odd integers.
+define float @ret_pow_neg_negsubnormal(float nofpclass(nan pinf psub pnorm pzero) %base, float nofpclass(nan inf psub norm zero) %exp) {
+; CHECK-LABEL: define nofpclass(snan) float @ret_pow_neg_negsubnormal(
+; CHECK-SAME: float nofpclass(nan pinf pzero psub pnorm) [[BASE:%.*]], float nofpclass(nan inf zero psub norm) [[EXP:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[POW:%.*]] = call nofpclass(snan) float @llvm.pow.f32(float nofpclass(nan pinf pzero psub pnorm) [[BASE]], float nofpclass(nan inf zero psub norm) [[EXP]]) #[[ATTR2]]
+; CHECK-NEXT: ret float [[POW]]
+;
+ %pow = call float @llvm.pow.f32(float %base, float %exp)
+ ret float %pow
+}
+
+define float @ret_pow_negnormalsubnormal_negsubnormal(float nofpclass(nan inf psub pnorm zero) %base, float nofpclass(nan inf psub norm zero) %exp) {
+; CHECK-LABEL: define nofpclass(snan) float @ret_pow_negnormalsubnormal_negsubnormal(
+; CHECK-SAME: float nofpclass(nan inf zero psub pnorm) [[BASE:%.*]], float nofpclass(nan inf zero psub norm) [[EXP:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[POW:%.*]] = call nofpclass(snan) float @llvm.pow.f32(float nofpclass(nan inf zero psub pnorm) [[BASE]], float nofpclass(nan inf zero psub norm) [[EXP]]) #[[ATTR2]]
+; CHECK-NEXT: ret float [[POW]]
+;
+ %pow = call float @llvm.pow.f32(float %base, float %exp)
+ ret float %pow
+}
+
+define float @ret_pow_negzero_negative(float nofpclass(nan inf pzero sub norm) %base, float %exp) {
+; CHECK-LABEL: define nofpclass(nzero nsub nnorm) float @ret_pow_negzero_negative(
+; CHECK-SAME: float nofpclass(nan inf pzero sub norm) [[BASE:%.*]], float [[EXP:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[POS:%.*]] = call float @llvm.fabs.f32(float [[EXP]]) #[[ATTR2]]
+; CHECK-NEXT: [[NEG:%.*]] = fneg float [[POS]]
+; CHECK-NEXT: [[POW:%.*]] = call nofpclass(nzero nsub nnorm) float @llvm.pow.f32(float nofpclass(nan inf pzero sub norm) [[BASE]], float [[NEG]]) #[[ATTR2]]
+; CHECK-NEXT: ret float [[POW]]
+;
+ %pos = call float @llvm.fabs.f32(float %exp)
+ %neg = fneg float %pos
+ %pow = call float @llvm.pow.f32(float %base, float %neg)
+ ret float %pow
+}
+
+define float @ret_pow_negzero_positive(float nofpclass(nan inf pzero sub norm) %base, float %exp) {
+; CHECK-LABEL: define nofpclass(ninf nsub nnorm) float @ret_pow_negzero_positive(
+; CHECK-SAME: float nofpclass(nan inf pzero sub norm) [[BASE:%.*]], float [[EXP:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[POS:%.*]] = call float @llvm.fabs.f32(float [[EXP]]) #[[ATTR2]]
+; CHECK-NEXT: [[POW:%.*]] = call nofpclass(ninf nsub nnorm) float @llvm.pow.f32(float nofpclass(nan inf pzero sub norm) [[BASE]], float [[POS]]) #[[ATTR2]]
+; CHECK-NEXT: ret float [[POW]]
+;
+ %pos = call float @llvm.fabs.f32(float %exp)
+ %pow = call float @llvm.pow.f32(float %base, float %pos)
+ ret float %pow
+}
+
+define float @ret_pow_neginf_positive(float nofpclass(nan pinf zero sub norm) %base, float %exp) {
+; CHECK-LABEL: define nofpclass(nzero nsub nnorm) float @ret_pow_neginf_positive(
+; CHECK-SAME: float nofpclass(nan pinf zero sub norm) [[BASE:%.*]], float [[EXP:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[POS:%.*]] = call float @llvm.fabs.f32(float [[EXP]]) #[[ATTR2]]
+; CHECK-NEXT: [[POW:%.*]] = call nofpclass(nzero nsub nnorm) float @llvm.pow.f32(float nofpclass(nan pinf zero sub norm) [[BASE]], float [[POS]]) #[[ATTR2]]
+; CHECK-NEXT: ret float [[POW]]
+;
+ %pos = call float @llvm.fabs.f32(float %exp)
+ %pow = call float @llvm.pow.f32(float %base, float %pos)
+ ret float %pow
+}
+
+define float @ret_pow_neginf_negative(float nofpclass(nan pinf zero sub norm) %base, float %exp) {
+; CHECK-LABEL: define nofpclass(ninf nsub nnorm) float @ret_pow_neginf_negative(
+; CHECK-SAME: float nofpclass(nan pinf zero sub norm) [[BASE:%.*]], float [[EXP:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[POS:%.*]] = call float @llvm.fabs.f32(float [[EXP]]) #[[ATTR2]]
+; CHECK-NEXT: [[NEG:%.*]] = fneg float [[POS]]
+; CHECK-NEXT: [[POW:%.*]] = call nofpclass(ninf nsub nnorm) float @llvm.pow.f32(float nofpclass(nan pinf zero sub norm) [[BASE]], float [[NEG]]) #[[ATTR2]]
+; CHECK-NEXT: ret float [[POW]]
+;
+ %pos = call float @llvm.fabs.f32(float %exp)
+ %neg = fneg float %pos
+ %pow = call float @llvm.pow.f32(float %base, float %neg)
+ ret float %pow
+}
+
+define <2 x float> @ret_pow_nonneg_nonan_v2f32(<2 x float> nofpclass(nan ninf nzero nsub nnorm) %base, <2 x float> nofpclass(nan) %exp) {
+; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) <2 x float> @ret_pow_nonneg_nonan_v2f32(
+; CHECK-SAME: <2 x float> nofpclass(nan ninf nzero nsub nnorm) [[BASE:%.*]], <2 x float> nofpclass(nan) [[EXP:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[POW:%.*]] = call nofpclass(nan ninf nzero nsub nnorm) <2 x float> @llvm.pow.v2f32(<2 x float> nofpclass(nan ninf nzero nsub nnorm) [[BASE]], <2 x float> nofpclass(nan) [[EXP]]) #[[ATTR2]]
+; CHECK-NEXT: ret <2 x float> [[POW]]
+;
+ %pow = call <2 x float> @llvm.pow.v2f32(<2 x float> %base, <2 x float> %exp)
+ ret <2 x float> %pow
+}
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-pow.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-pow.ll
new file mode 100644
index 0000000000000..4d34a2d99bd2c
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-pow.ll
@@ -0,0 +1,65 @@
+; 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.fabs.f32(float)
+declare float @llvm.pow.f32(float, float)
+declare i1 @llvm.is.fpclass.f32(float, i32 immarg)
+
+define i1 @pow_negzero_negative_is_negzero(float %x) strictfp {
+; CHECK-LABEL: define i1 @pow_negzero_negative_is_negzero(
+; CHECK-SAME: float [[X:%.*]]) #[[ATTR1:[0-9]+]] {
+; CHECK-NEXT: ret i1 false
+;
+ %pos = call float @llvm.fabs.f32(float %x)
+ %neg = fneg float %pos
+ %pow = call float @llvm.pow.f32(float f0x80000000, float %neg)
+ %class = call i1 @llvm.is.fpclass.f32(float %pow, i32 32) strictfp
+ ret i1 %class
+}
+
+define i1 @pow_negzero_positive_is_neginf(float %x) strictfp {
+; CHECK-LABEL: define i1 @pow_negzero_positive_is_neginf(
+; CHECK-SAME: float [[X:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: ret i1 false
+;
+ %pos = call float @llvm.fabs.f32(float %x)
+ %pow = call float @llvm.pow.f32(float f0x80000000, float %pos)
+ %class = call i1 @llvm.is.fpclass.f32(float %pow, i32 4) strictfp
+ ret i1 %class
+}
+
+define i1 @pow_neginf_positive_is_negzero(float %x) strictfp {
+; CHECK-LABEL: define i1 @pow_neginf_positive_is_negzero(
+; CHECK-SAME: float [[X:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: ret i1 false
+;
+ %pos = call float @llvm.fabs.f32(float %x)
+ %pow = call float @llvm.pow.f32(float f0xFF800000, float %pos)
+ %class = call i1 @llvm.is.fpclass.f32(float %pow, i32 32) strictfp
+ ret i1 %class
+}
+
+define i1 @pow_neginf_negative_is_neginf(float %x) strictfp {
+; CHECK-LABEL: define i1 @pow_neginf_negative_is_neginf(
+; CHECK-SAME: float [[X:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: ret i1 false
+;
+ %pos = call float @llvm.fabs.f32(float %x)
+ %neg = fneg float %pos
+ %pow = call float @llvm.pow.f32(float f0xFF800000, float %neg)
+ %class = call i1 @llvm.is.fpclass.f32(float %pow, i32 4) strictfp
+ ret i1 %class
+}
+
+; This fold is only possible in special cases, and not worth deducing.
+define i1 @pow_any_nonnormal_may_be_subnormal(float %x, float nofpclass(norm) %exp) strictfp {
+; CHECK-LABEL: define i1 @pow_any_nonnormal_may_be_subnormal(
+; CHECK-SAME: float [[X:%.*]], float nofpclass(norm) [[EXP:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[POW:%.*]] = call float @llvm.pow.f32(float [[X]], float [[EXP]])
+; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[POW]], /* (sub) */ i32 144) #[[ATTR1]]
+; CHECK-NEXT: ret i1 [[CLASS]]
+;
+ %pow = call float @llvm.pow.f32(float %x, float %exp)
+ %class = call i1 @llvm.is.fpclass.f32(float %pow, i32 144) strictfp
+ ret i1 %class
+}
diff --git a/llvm/test/Transforms/InstSimplify/pow.ll b/llvm/test/Transforms/InstSimplify/pow.ll
new file mode 100644
index 0000000000000..dd000d35b3631
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/pow.ll
@@ -0,0 +1,101 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=instsimplify -S < %s | FileCheck %s
+
+declare float @llvm.fabs.f32(float)
+declare float @llvm.pow.f32(float, float)
+declare <2 x float> @llvm.fabs.v2f32(<2 x float>)
+declare <2 x float> @llvm.pow.v2f32(<2 x float>, <2 x float>)
+
+define i1 @pow_fabs_olt_zero(float %base, float %exp) {
+; CHECK-LABEL: define i1 @pow_fabs_olt_zero(
+; CHECK-SAME: float [[BASE:%.*]], float [[EXP:%.*]]) {
+; CHECK-NEXT: ret i1 false
+;
+ %abs = call float @llvm.fabs.f32(float %base)
+ %pow = call float @llvm.pow.f32(float %abs, float %exp)
+ %cmp = fcmp olt float %pow, 0.0
+ ret i1 %cmp
+}
+
+define float @fabs_pow_nonneg_base(float nofpclass(nan) %base, float nofpclass(nan) %exp) {
+; CHECK-LABEL: define float @fabs_pow_nonneg_base(
+; CHECK-SAME: float nofpclass(nan) [[BASE:%.*]], float nofpclass(nan) [[EXP:%.*]]) {
+; CHECK-NEXT: [[ABS_BASE:%.*]] = call float @llvm.fabs.f32(float [[BASE]])
+; CHECK-NEXT: [[POW:%.*]] = call float @llvm.pow.f32(float [[ABS_BASE]], float [[EXP]])
+; CHECK-NEXT: ret float [[POW]]
+;
+ %abs.base = call float @llvm.fabs.f32(float %base)
+ %pow = call float @llvm.pow.f32(float %abs.base, float %exp)
+ %abs.pow = call float @llvm.fabs.f32(float %pow)
+ ret float %abs.pow
+}
+
+define i1 @pow_nonnormal_exponent_olt_zero(float %base, float nofpclass(norm) %exp) {
+; CHECK-LABEL: define i1 @pow_nonnormal_exponent_olt_zero(
+; CHECK-SAME: float [[BASE:%.*]], float nofpclass(norm) [[EXP:%.*]]) {
+; CHECK-NEXT: [[POW:%.*]] = call float @llvm.pow.f32(float [[BASE]], float [[EXP]])
+; CHECK-NEXT: [[CMP:%.*]] = fcmp olt float [[POW]], 0.000000e+00
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %pow = call float @llvm.pow.f32(float %base, float %exp)
+ %cmp = fcmp olt float %pow, 0.0
+ ret i1 %cmp
+}
+
+define i1 @isnan_pow_nonneg_or_negzero_base(float nofpclass(nan ninf nsub nnorm) %base, float nofpclass(nan) %exp) {
+; CHECK-LABEL: define i1 @isnan_pow_nonneg_or_negzero_base(
+; CHECK-SAME: float nofpclass(nan ninf nsub nnorm) [[BASE:%.*]], float nofpclass(nan) [[EXP:%.*]]) {
+; CHECK-NEXT: ret i1 false
+;
+ %pow = call float @llvm.pow.f32(float %base, float %exp)
+ %isnan = fcmp uno float %pow, %pow
+ ret i1 %isnan
+}
+
+; qNaN may be produced when a negative base is raised to a non-integer exponent.
+define i1 @isnan_pow_negative_base(float nofpclass(nan inf zero psub pnorm) %base, float nofpclass(nan) %exp) {
+; CHECK-LABEL: define i1 @isnan_pow_negative_base(
+; CHECK-SAME: float nofpclass(nan inf zero psub pnorm) [[BASE:%.*]], float nofpclass(nan) [[EXP:%.*]]) {
+; CHECK-NEXT: [[POW:%.*]] = call float @llvm.pow.f32(float [[BASE]], float [[EXP]])
+; CHECK-NEXT: [[ISNAN:%.*]] = fcmp uno float [[POW]], [[POW]]
+; CHECK-NEXT: ret i1 [[ISNAN]]
+;
+ %pow = call float @llvm.pow.f32(float %base, float %exp)
+ %isnan = fcmp uno float %pow, %pow
+ ret i1 %isnan
+}
+
+; A negative result is produced when a negative base is raised to an odd integer
+; exponent.
+define float @fabs_pow_negative_base_normal_exponent(float nofpclass(nan inf zero psub pnorm) %base, float nofpclass(nan inf zero sub) %exp) {
+; CHECK-LABEL: define float @fabs_pow_negative_base_normal_exponent(
+; CHECK-SAME: float nofpclass(nan inf zero psub pnorm) [[BASE:%.*]], float nofpclass(nan inf zero sub) [[EXP:%.*]]) {
+; CHECK-NEXT: [[POW:%.*]] = call float @llvm.pow.f32(float [[BASE]], float [[EXP]])
+; CHECK-NEXT: [[ABS_POW:%.*]] = call float @llvm.fabs.f32(float [[POW]])
+; CHECK-NEXT: ret float [[ABS_POW]]
+;
+ %pow = call float @llvm.pow.f32(float %base, float %exp)
+ %abs.pow = call float @llvm.fabs.f32(float %pow)
+ ret float %abs.pow
+}
+
+define <2 x i1> @pow_fabs_olt_zero_v2f32(<2 x float> %base, <2 x float> %exp) {
+; CHECK-LABEL: define <2 x i1> @pow_fabs_olt_zero_v2f32(
+; CHECK-SAME: <2 x float> [[BASE:%.*]], <2 x float> [[EXP:%.*]]) {
+; CHECK-NEXT: ret <2 x i1> zeroinitializer
+;
+ %abs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %base)
+ %pow = call <2 x float> @llvm.pow.v2f32(<2 x float> %abs, <2 x float> %exp)
+ %cmp = fcmp olt <2 x float> %pow, zeroinitializer
+ ret <2 x i1> %cmp
+}
+
+define <2 x i1> @isnan_pow_nonneg_or_negzero_base_v2f32(<2 x float> nofpclass(nan ninf nsub nnorm) %base, <2 x float> nofpclass(nan) %exp) {
+; CHECK-LABEL: define <2 x i1> @isnan_pow_nonneg_or_negzero_base_v2f32(
+; CHECK-SAME: <2 x float> nofpclass(nan ninf nsub nnorm) [[BASE:%.*]], <2 x float> nofpclass(nan) [[EXP:%.*]]) {
+; CHECK-NEXT: ret <2 x i1> zeroinitializer
+;
+ %pow = call <2 x float> @llvm.pow.v2f32(<2 x float> %base, <2 x float> %exp)
+ %isnan = fcmp uno <2 x float> %pow, %pow
+ ret <2 x i1> %isnan
+}
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index 382cf0f2b57ed..bbbf1cc1b9933 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -1912,6 +1912,20 @@ TEST_F(ComputeKnownFPClassTest, MaximumNumSignBit) {
expectKnownFPClass(fcPositive, false, A7);
}
+TEST_F(ComputeKnownFPClassTest, PowIgnoreRHSForNegativeSpecialResults) {
+ parseAssembly(
+ "declare float @llvm.pow.f32(float, float)\n"
+ "define float @test(float nofpclass(nsub nnorm) %base,\n"
+ " float nofpclass(norm) %exp) {\n"
+ " %A = call float @llvm.pow.f32(float %base, float %exp)\n"
+ " ret float %A\n"
+ "}\n");
+
+ KnownFPClass Known = computeKnownFPClass(
+ A, M->getDataLayout(), fcNegInf | fcNegZero);
+ EXPECT_EQ(~(fcNegNormal | fcNegSubnormal), Known.KnownFPClasses);
+}
+
TEST_F(ComputeKnownFPClassTest, PowiInfFirst) {
parseAssembly(
"declare float @llvm.powi.f32.i32(float, i32)\n"
diff --git a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
index d995c1e15f9e5..b74d83bf407c0 100644
--- a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
+++ b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
@@ -1001,6 +1001,112 @@ TEST_F(AArch64GISelMITest, TestFPClassFLDExp) {
EXPECT_EQ(std::nullopt, Known.SignBit);
}
+TEST_F(AArch64GISelMITest, TestFPClassFPowPos) {
+ StringRef MIRString = R"(
+ %ptr:_(p0) = G_IMPLICIT_DEF
+ %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+ %exp:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+ %fabs:_(s32) = G_FABS %val
+ %fpow:_(s32) = G_FPOW %fabs, %exp
+ %copy_fpow:_(s32) = COPY %fpow
+)";
+
+ setUp(MIRString);
+ if (!TM)
+ GTEST_SKIP();
+
+ Register CopyReg = Copies[Copies.size() - 1];
+ MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+ Register SrcReg = FinalCopy->getOperand(1).getReg();
+
+ GISelValueTracking Info(*MF);
+ KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+
+ EXPECT_EQ(fcPositive | fcNan, Known.KnownFPClasses);
+ EXPECT_EQ(std::nullopt, Known.SignBit);
+ EXPECT_TRUE(Info.isKnownNeverNaN(SrcReg, true));
+}
+
+TEST_F(AArch64GISelMITest, TestFPClassFPowPosNNaN) {
+ StringRef MIRString = R"(
+ %ptr:_(p0) = G_IMPLICIT_DEF
+ %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+ %exp:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+ %fabs:_(s32) = nnan G_FABS %val
+ %fabs_exp:_(s32) = nnan G_FABS %exp
+ %fpow:_(s32) = G_FPOW %fabs, %fabs_exp
+ %copy_fpow:_(s32) = COPY %fpow
+)";
+
+ setUp(MIRString);
+ if (!TM)
+ GTEST_SKIP();
+
+ Register CopyReg = Copies[Copies.size() - 1];
+ MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+ Register SrcReg = FinalCopy->getOperand(1).getReg();
+
+ GISelValueTracking Info(*MF);
+ KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+
+ EXPECT_EQ(fcPositive, Known.KnownFPClasses);
+ EXPECT_EQ(false, Known.SignBit);
+}
+
+TEST_F(AArch64GISelMITest, TestFPClassFPowNegativeSpecialBases) {
+ StringRef MIRString = R"(
+ %ptr:_(p0) = G_IMPLICIT_DEF
+ %cond:_(s1) = G_LOAD %ptr(p0) :: (load (s1))
+ %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+ %pos:_(s32) = G_FABS %val
+ %neg:_(s32) = G_FNEG %pos
+ %negzero:_(s32) = G_FCONSTANT float -0.0
+ %neginf:_(s32) = G_FCONSTANT float f0xFF800000
+ %zero:_(s32) = G_FCONSTANT float 0.0
+ %pow_negzero_neg:_(s32) = G_FPOW %negzero, %neg
+ %copy_pow_negzero_neg:_(s32) = COPY %pow_negzero_neg
+ %pow_negzero_pos:_(s32) = G_FPOW %negzero, %pos
+ %copy_pow_negzero_pos:_(s32) = COPY %pow_negzero_pos
+ %pow_neginf_pos:_(s32) = G_FPOW %neginf, %pos
+ %copy_pow_neginf_pos:_(s32) = COPY %pow_neginf_pos
+ %pow_neginf_neg:_(s32) = G_FPOW %neginf, %neg
+ %copy_pow_neginf_neg:_(s32) = COPY %pow_neginf_neg
+ %negspecial:_(s32) = G_SELECT %cond, %negzero, %neginf
+ %pow_negspecial_zero:_(s32) = G_FPOW %negspecial, %zero
+ %copy_pow_negspecial_zero:_(s32) = COPY %pow_negspecial_zero
+)";
+
+ setUp(MIRString);
+ if (!TM)
+ GTEST_SKIP();
+
+ GISelValueTracking Info(*MF);
+ auto ExpectKnownNever = [&](unsigned CopyIndex, FPClassTest Class) {
+ Register CopyReg = Copies[Copies.size() - 5 + CopyIndex];
+ MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+ Register SrcReg = FinalCopy->getOperand(1).getReg();
+ KnownFPClass Known = Info.computeKnownFPClass(SrcReg, Class);
+ EXPECT_TRUE(Known.isKnownNever(Class));
+ };
+
+ // pow(-0.0, RHS) cannot return -0.0 if RHS cannot be positive normal.
+ ExpectKnownNever(0, fcNegZero);
+ // pow(-0.0, RHS) cannot return -Inf if RHS cannot be negative normal.
+ ExpectKnownNever(1, fcNegInf);
+ // pow(-Inf, RHS) cannot return -0.0 if RHS cannot be negative normal.
+ ExpectKnownNever(2, fcNegZero);
+ // pow(-Inf, RHS) cannot return -Inf if RHS cannot be positive normal.
+ ExpectKnownNever(3, fcNegInf);
+
+ // Do not query the RHS when both negative special bases remain possible.
+ Register CopyReg = Copies.back();
+ MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+ Register SrcReg = FinalCopy->getOperand(1).getReg();
+ KnownFPClass Known =
+ Info.computeKnownFPClass(SrcReg, fcNegInf | fcNegZero);
+ EXPECT_EQ(~(fcNegNormal | fcNegSubnormal), Known.KnownFPClasses);
+}
+
TEST_F(AArch64GISelMITest, TestFPClassFPowIEvenExp) {
StringRef MIRString = R"(
%ptr:_(p0) = G_IMPLICIT_DEF
More information about the llvm-commits
mailing list