[llvm-branch-commits] [llvm] InstCombine: Handle fpext in SimplifyDemandedFPClass (PR #174849)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Jan 7 11:31:07 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Matt Arsenault (arsenm)
<details>
<summary>Changes</summary>
---
Full diff: https://github.com/llvm/llvm-project/pull/174849.diff
5 Files Affected:
- (modified) llvm/include/llvm/Support/KnownFPClass.h (+6)
- (modified) llvm/lib/Analysis/ValueTracking.cpp (+3-14)
- (modified) llvm/lib/Support/KnownFPClass.cpp (+22)
- (modified) llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp (+22)
- (modified) llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fpext.ll (+9-18)
``````````diff
diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h
index a3a485a961877..4d2f42202301a 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -20,6 +20,7 @@
namespace llvm {
class APFloat;
+struct fltSemantics;
struct KnownFPClass {
/// Floating-point classes the value could be one of.
@@ -283,6 +284,11 @@ struct KnownFPClass {
static LLVM_ABI KnownFPClass
log(const KnownFPClass &Src, DenormalMode Mode = DenormalMode::getDynamic());
+ /// Propagate known class for fpext.
+ static LLVM_ABI KnownFPClass fpext(const KnownFPClass &KnownSrc,
+ const fltSemantics &DstTy,
+ const fltSemantics &SrcTy);
+
void resetAll() { *this = KnownFPClass(); }
};
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index dbe74f463b57c..44b8713ede471 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5750,27 +5750,16 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
break;
}
case Instruction::FPExt: {
- // Infinity, nan and zero propagate from source.
+ KnownFPClass KnownSrc;
computeKnownFPClass(Op->getOperand(0), DemandedElts, InterestedClasses,
- Known, Q, Depth + 1);
+ KnownSrc, Q, Depth + 1);
const fltSemantics &DstTy =
Op->getType()->getScalarType()->getFltSemantics();
const fltSemantics &SrcTy =
Op->getOperand(0)->getType()->getScalarType()->getFltSemantics();
- // All subnormal inputs should be in the normal range in the result type.
- if (APFloat::isRepresentableAsNormalIn(SrcTy, DstTy)) {
- if (Known.KnownFPClasses & fcPosSubnormal)
- Known.KnownFPClasses |= fcPosNormal;
- if (Known.KnownFPClasses & fcNegSubnormal)
- Known.KnownFPClasses |= fcNegNormal;
- Known.knownNot(fcSubnormal);
- }
-
- // Sign bit of a nan isn't guaranteed.
- if (!Known.isKnownNeverNaN())
- Known.SignBit = std::nullopt;
+ Known = KnownFPClass::fpext(KnownSrc, DstTy, SrcTy);
break;
}
case Instruction::FPTrunc: {
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index a352f1267be27..7a60221f7e8f8 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -329,3 +329,25 @@ KnownFPClass KnownFPClass::log(const KnownFPClass &KnownSrc,
return Known;
}
+
+KnownFPClass KnownFPClass::fpext(const KnownFPClass &KnownSrc,
+ const fltSemantics &DstTy,
+ const fltSemantics &SrcTy) {
+ // Infinity, nan and zero propagate from source.
+ KnownFPClass Known = KnownSrc;
+
+ // All subnormal inputs should be in the normal range in the result type.
+ if (APFloat::isRepresentableAsNormalIn(SrcTy, DstTy)) {
+ if (Known.KnownFPClasses & fcPosSubnormal)
+ Known.KnownFPClasses |= fcPosNormal;
+ if (Known.KnownFPClasses & fcNegSubnormal)
+ Known.KnownFPClasses |= fcNegNormal;
+ Known.knownNot(fcSubnormal);
+ }
+
+ // Sign bit of a nan isn't guaranteed.
+ if (!Known.isKnownNeverNaN())
+ Known.SignBit = std::nullopt;
+
+ return Known;
+}
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index c628f53f28cbb..1a575ae7b4bfd 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -2241,6 +2241,28 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Value *V,
FPClassTest ValidResults = DemandedMask & Known.KnownFPClasses;
return getFPClassConstant(VTy, ValidResults, /*IsCanonicalizing=*/true);
}
+ case Instruction::FPExt: {
+ FPClassTest SrcDemandedMask = DemandedMask;
+
+ // No subnormal result does not imply not-subnormal in the source type.
+ if ((DemandedMask & fcNegSubnormal) == fcNone)
+ SrcDemandedMask |= fcNegSubnormal;
+ if ((DemandedMask & fcPosSubnormal) == fcNone)
+ SrcDemandedMask |= fcPosSubnormal;
+
+ KnownFPClass KnownSrc;
+ if (SimplifyDemandedFPClass(I, 0, SrcDemandedMask, KnownSrc, Depth + 1))
+ return I;
+
+ const fltSemantics &DstTy = VTy->getScalarType()->getFltSemantics();
+ const fltSemantics &SrcTy =
+ I->getOperand(0)->getType()->getScalarType()->getFltSemantics();
+
+ Known = KnownFPClass::fpext(KnownSrc, DstTy, SrcTy);
+ FPClassTest ValidResults = DemandedMask & Known.KnownFPClasses;
+
+ return getFPClassConstant(VTy, ValidResults, /*IsCanonicalizing=*/true);
+ }
case Instruction::Call: {
CallInst *CI = cast<CallInst>(I);
const Intrinsic::ID IID = CI->getIntrinsicID();
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fpext.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fpext.ll
index 4996a206a7e8f..a1f4b1e9428ac 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fpext.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fpext.ll
@@ -46,8 +46,7 @@ define nofpclass(inf norm sub zero snan) float @ret_only_qnan__fpext(half %x) {
define nofpclass(inf norm sub zero) float @ret_only_nan__fpext(half %x) {
; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_only_nan__fpext(
; CHECK-SAME: half [[X:%.*]]) {
-; CHECK-NEXT: [[RESULT:%.*]] = fpext half [[X]] to float
-; CHECK-NEXT: ret float [[RESULT]]
+; CHECK-NEXT: ret float 0x7FF8000000000000
;
%result = fpext half %x to float
ret float %result
@@ -114,8 +113,7 @@ define nofpclass(nan) float @ret_no_nan__fpext__select_nan_or_unknown(i1 %cond,
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fpext__select_nan_or_unknown(
; CHECK-SAME: i1 [[COND:%.*]], half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[NAN:%.*]] = call half @returns_nan_f16()
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], half [[NAN]], half [[UNKNOWN]]
-; CHECK-NEXT: [[RESULT:%.*]] = fpext half [[SELECT]] to float
+; CHECK-NEXT: [[RESULT:%.*]] = fpext half [[UNKNOWN]] to float
; CHECK-NEXT: ret float [[RESULT]]
;
%nan = call half @returns_nan_f16()
@@ -129,8 +127,7 @@ define nofpclass(pinf) float @ret_no_pinf__fpext__select_pinf_or_unknown(i1 %con
; CHECK-LABEL: define nofpclass(pinf) float @ret_no_pinf__fpext__select_pinf_or_unknown(
; CHECK-SAME: i1 [[COND:%.*]], half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[PINF:%.*]] = call half @returns_pinf_f16()
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], half [[PINF]], half [[UNKNOWN]]
-; CHECK-NEXT: [[RESULT:%.*]] = fpext half [[SELECT]] to float
+; CHECK-NEXT: [[RESULT:%.*]] = fpext half [[UNKNOWN]] to float
; CHECK-NEXT: ret float [[RESULT]]
;
%pinf = call half @returns_pinf_f16()
@@ -144,8 +141,7 @@ define nofpclass(ninf) float @ret_no_ninf__fpext__select_ninf_or_unknown(i1 %con
; CHECK-LABEL: define nofpclass(ninf) float @ret_no_ninf__fpext__select_ninf_or_unknown(
; CHECK-SAME: i1 [[COND:%.*]], half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[NINF:%.*]] = call half @returns_ninf_f16()
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], half [[NINF]], half [[UNKNOWN]]
-; CHECK-NEXT: [[RESULT:%.*]] = fpext half [[SELECT]] to float
+; CHECK-NEXT: [[RESULT:%.*]] = fpext half [[UNKNOWN]] to float
; CHECK-NEXT: ret float [[RESULT]]
;
%ninf = call half @returns_ninf_f16()
@@ -159,8 +155,7 @@ define nofpclass(inf) float @ret_no_inf__fpext__select_inf_or_unknown(i1 %cond,
; CHECK-LABEL: define nofpclass(inf) float @ret_no_inf__fpext__select_inf_or_unknown(
; CHECK-SAME: i1 [[COND:%.*]], half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[INF:%.*]] = call half @returns_inf_f16()
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], half [[INF]], half [[UNKNOWN]]
-; CHECK-NEXT: [[RESULT:%.*]] = fpext half [[SELECT]] to float
+; CHECK-NEXT: [[RESULT:%.*]] = fpext half [[UNKNOWN]] to float
; CHECK-NEXT: ret float [[RESULT]]
;
%inf = call half @returns_inf_f16()
@@ -174,8 +169,7 @@ define nofpclass(nan inf) float @ret_no_inf_no_nan__fpext__select_inf_or_nan_or_
; CHECK-LABEL: define nofpclass(nan inf) float @ret_no_inf_no_nan__fpext__select_inf_or_nan_or_unknown(
; CHECK-SAME: i1 [[COND:%.*]], half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[INF_OR_NAN:%.*]] = call half @returns_inf_or_nan_f16()
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], half [[INF_OR_NAN]], half [[UNKNOWN]]
-; CHECK-NEXT: [[RESULT:%.*]] = fpext half [[SELECT]] to float
+; CHECK-NEXT: [[RESULT:%.*]] = fpext half [[UNKNOWN]] to float
; CHECK-NEXT: ret float [[RESULT]]
;
%inf.or.nan = call half @returns_inf_or_nan_f16()
@@ -447,8 +441,7 @@ define nofpclass(nzero) float @ret_no_nzero__fpext__select_nzero_or_unknown(i1 %
; CHECK-LABEL: define nofpclass(nzero) float @ret_no_nzero__fpext__select_nzero_or_unknown(
; CHECK-SAME: i1 [[COND:%.*]], half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[NZERO:%.*]] = call half @returns_nzero_f16()
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], half [[NZERO]], half [[UNKNOWN]]
-; CHECK-NEXT: [[RESULT:%.*]] = fpext half [[SELECT]] to float
+; CHECK-NEXT: [[RESULT:%.*]] = fpext half [[UNKNOWN]] to float
; CHECK-NEXT: ret float [[RESULT]]
;
%nzero = call half @returns_nzero_f16()
@@ -461,8 +454,7 @@ define nofpclass(pzero) float @ret_no_pzero__fpext__select_pzero_or_unknown(i1 %
; CHECK-LABEL: define nofpclass(pzero) float @ret_no_pzero__fpext__select_pzero_or_unknown(
; CHECK-SAME: i1 [[COND:%.*]], half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[PZERO:%.*]] = call half @returns_pzero_f16()
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], half [[PZERO]], half [[UNKNOWN]]
-; CHECK-NEXT: [[RESULT:%.*]] = fpext half [[SELECT]] to float
+; CHECK-NEXT: [[RESULT:%.*]] = fpext half [[UNKNOWN]] to float
; CHECK-NEXT: ret float [[RESULT]]
;
%pzero = call half @returns_pzero_f16()
@@ -475,8 +467,7 @@ define nofpclass(zero) float @ret_no_zero__fpext__select_zero_or_unknown(i1 %con
; CHECK-LABEL: define nofpclass(zero) float @ret_no_zero__fpext__select_zero_or_unknown(
; CHECK-SAME: i1 [[COND:%.*]], half [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[ZERO:%.*]] = call half @returns_zero_f16()
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], half [[ZERO]], half [[UNKNOWN]]
-; CHECK-NEXT: [[RESULT:%.*]] = fpext half [[SELECT]] to float
+; CHECK-NEXT: [[RESULT:%.*]] = fpext half [[UNKNOWN]] to float
; CHECK-NEXT: ret float [[RESULT]]
;
%zero = call half @returns_zero_f16()
``````````
</details>
https://github.com/llvm/llvm-project/pull/174849
More information about the llvm-branch-commits
mailing list