[llvm-branch-commits] [llvm] InstCombine: Handle rounding intrinsics in SimplifyDemandedFPClass (PR #174842)

Matt Arsenault via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sun Jan 11 03:08:40 PST 2026


https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/174842

>From d96b09c6e485cbc3d078e4efd7d1eb49d6154c77 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Mon, 29 Dec 2025 19:46:09 +0100
Subject: [PATCH 1/8] InstCombine: Handle rounding intrinsics in
 SimplifyDemandedFPClass

---
 llvm/include/llvm/Support/KnownFPClass.h      |   7 +
 llvm/lib/Analysis/ValueTracking.cpp           |  22 +--
 llvm/lib/Support/KnownFPClass.cpp             |  28 ++++
 .../InstCombineSimplifyDemanded.cpp           |  66 ++++++++
 ...fy-demanded-fpclass-rounding-intrinsics.ll | 144 +++++++-----------
 5 files changed, 158 insertions(+), 109 deletions(-)

diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h
index 5a3ed677bd762..193a3511b9f8e 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -299,6 +299,13 @@ struct KnownFPClass {
                                      const fltSemantics &DstTy,
                                      const fltSemantics &SrcTy);
 
+  /// Propagate known class for rounding intrinsics (trunc, floor, ceil, rint,
+  /// nearbyint, round, roundeven). This is trunc if \p IsTrunc. \p
+  /// IsMultiUnitFPType if this is for a multi-unit floating-point type.
+  static LLVM_ABI KnownFPClass roundToIntegral(const KnownFPClass &Src,
+                                               bool IsTrunc,
+                                               bool IsMultiUnitFPType);
+
   void resetAll() { *this = KnownFPClass(); }
 };
 
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 90e23bf81d99e..1e16647e6ccc1 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5220,26 +5220,8 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
       computeKnownFPClass(II->getArgOperand(0), DemandedElts, InterestedSrcs,
                           KnownSrc, Q, Depth + 1);
 
-      // Integer results cannot be subnormal.
-      Known.knownNot(fcSubnormal);
-
-      Known.propagateNaN(KnownSrc, true);
-
-      // Pass through infinities, except PPC_FP128 is a special case for
-      // intrinsics other than trunc.
-      if (IID == Intrinsic::trunc || !V->getType()->isMultiUnitFPType()) {
-        if (KnownSrc.isKnownNeverPosInfinity())
-          Known.knownNot(fcPosInf);
-        if (KnownSrc.isKnownNeverNegInfinity())
-          Known.knownNot(fcNegInf);
-      }
-
-      // Negative round ups to 0 produce -0
-      if (KnownSrc.isKnownNever(fcPosFinite))
-        Known.knownNot(fcPosFinite);
-      if (KnownSrc.isKnownNever(fcNegFinite))
-        Known.knownNot(fcNegFinite);
-
+      Known = KnownFPClass::roundToIntegral(KnownSrc, IID == Intrinsic::trunc,
+                                            V->getType()->isMultiUnitFPType());
       break;
     }
     case Intrinsic::exp:
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index e621da9e39ed7..8f7f4e93d1c15 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -375,3 +375,31 @@ KnownFPClass KnownFPClass::fpext(const KnownFPClass &KnownSrc,
 
   return Known;
 }
+
+KnownFPClass KnownFPClass::roundToIntegral(const KnownFPClass &KnownSrc,
+                                           bool IsTrunc,
+                                           bool IsMultiUnitFPType) {
+  KnownFPClass Known;
+
+  // Integer results cannot be subnormal.
+  Known.knownNot(fcSubnormal);
+
+  Known.propagateNaN(KnownSrc, true);
+
+  // Pass through infinities, except PPC_FP128 is a special case for
+  // intrinsics other than trunc.
+  if (IsTrunc || !IsMultiUnitFPType) {
+    if (KnownSrc.isKnownNeverPosInfinity())
+      Known.knownNot(fcPosInf);
+    if (KnownSrc.isKnownNeverNegInfinity())
+      Known.knownNot(fcNegInf);
+  }
+
+  // Negative round ups to 0 produce -0
+  if (KnownSrc.isKnownNever(fcPosFinite))
+    Known.knownNot(fcPosFinite);
+  if (KnownSrc.isKnownNever(fcNegFinite))
+    Known.knownNot(fcNegFinite);
+
+  return Known;
+}
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 22064638bb229..f88997fb6619f 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -2638,6 +2638,72 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Instruction *I,
 
       return getFPClassConstant(VTy, ValidResults, /*IsCanonicalizing=*/true);
     }
+    case Intrinsic::trunc:
+    case Intrinsic::floor:
+    case Intrinsic::ceil:
+    case Intrinsic::rint:
+    case Intrinsic::nearbyint:
+    case Intrinsic::round:
+    case Intrinsic::roundeven: {
+      FPClassTest DemandedSrcMask = DemandedMask;
+
+      // Zero results imply valid subnormal sources.
+      if (DemandedMask & fcNegZero)
+        DemandedSrcMask |= fcNegSubnormal;
+
+      if (DemandedMask & fcPosZero)
+        DemandedSrcMask |= fcPosSubnormal;
+
+      KnownFPClass KnownSrc;
+      if (SimplifyDemandedFPClass(CI, 0, DemandedSrcMask, KnownSrc, Depth + 1))
+        return I;
+
+      // Note: Possibly dropping snan quiet.
+      if (KnownSrc.isKnownAlways(fcInf | fcNan))
+        return CI->getArgOperand(0);
+
+      // Propagate nnan-ness to source to simplify source checks.
+      if ((DemandedMask & fcNan) == fcNone)
+        KnownSrc.knownNot(fcNan);
+
+      bool IsRoundNearest =
+          IID == Intrinsic::round || IID == Intrinsic::roundeven ||
+          IID == Intrinsic::nearbyint || IID == Intrinsic::rint;
+
+      // Ignore denormals-as-zero, as canonicalization is not mandated.
+      if ((IID == Intrinsic::trunc || IID == Intrinsic::floor ||
+           IsRoundNearest) &&
+          (KnownSrc.isKnownAlways(fcPosZero | fcPosSubnormal)))
+        return ConstantFP::getZero(VTy);
+
+      if ((IID == Intrinsic::trunc || IsRoundNearest) &&
+          KnownSrc.isKnownAlways(fcNegZero | fcNegSubnormal))
+        return ConstantFP::getZero(VTy, true);
+
+      if (IID == Intrinsic::floor && KnownSrc.isKnownAlways(fcNegSubnormal))
+        return ConstantFP::get(VTy, -1.0);
+
+      if (IID == Intrinsic::ceil && KnownSrc.isKnownAlways(fcPosSubnormal))
+        return ConstantFP::get(VTy, 1.0);
+
+      Known = KnownFPClass::roundToIntegral(KnownSrc, IID == Intrinsic::trunc,
+                                            VTy->isMultiUnitFPType());
+
+      FPClassTest ValidResults = DemandedMask & Known.KnownFPClasses;
+      if (Constant *SingleVal =
+              getFPClassConstant(VTy, ValidResults, /*IsCanonicalizing=*/true))
+        return SingleVal;
+
+      if ((IID == Intrinsic::trunc || IsRoundNearest) &&
+          KnownSrc.isKnownAlways(fcZero | fcSubnormal)) {
+        Value *Copysign = Builder.CreateCopySign(ConstantFP::getZero(VTy),
+                                                 CI->getArgOperand(0));
+        Copysign->takeName(CI);
+        return Copysign;
+      }
+
+      return nullptr;
+    }
     case Intrinsic::canonicalize: {
       Type *EltTy = VTy->getScalarType();
 
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-rounding-intrinsics.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-rounding-intrinsics.ll
index 59e1a2215d838..1903bbe851ae2 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-rounding-intrinsics.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-rounding-intrinsics.ll
@@ -14,8 +14,7 @@ define nofpclass(snan) float @ret_no_snan__floor_no_snan(float nofpclass(nan) %x
 define nofpclass(inf norm sub zero) float @ret_only_nan__floor(float %x) {
 ; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_only_nan__floor(
 ; CHECK-SAME: float [[X:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.floor.f32(float [[X]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float 0x7FF8000000000000
 ;
   %result = call float @llvm.floor.f32(float %x)
   ret float %result
@@ -24,8 +23,7 @@ define nofpclass(inf norm sub zero) float @ret_only_nan__floor(float %x) {
 define nofpclass(inf norm sub zero) <2 x float> @ret_only_nan__floor_vec(<2 x float> %x) {
 ; CHECK-LABEL: define nofpclass(inf zero sub norm) <2 x float> @ret_only_nan__floor_vec(
 ; CHECK-SAME: <2 x float> [[X:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call <2 x float> @llvm.floor.v2f32(<2 x float> [[X]])
-; CHECK-NEXT:    ret <2 x float> [[RESULT]]
+; CHECK-NEXT:    ret <2 x float> splat (float 0x7FF8000000000000)
 ;
   %result = call <2 x float> @llvm.floor.v2f32(<2 x float> %x)
   ret <2 x float> %result
@@ -140,8 +138,7 @@ define nofpclass(nan inf) float @ret_no_nans_no_infs__floor(float %x) {
 define nofpclass(nan) float @ret_no_nans__simplify_select_nan__floor(i1 %cond, float nofpclass(inf norm sub zero) %is.nan, float %unknown) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nans__simplify_select_nan__floor(
 ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(inf zero sub norm) [[IS_NAN:%.*]], float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[IS_NAN]], float [[UNKNOWN]]
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.floor.f32(float [[SELECT]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.floor.f32(float [[UNKNOWN]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %select = select i1 %cond, float %is.nan, float %unknown
@@ -152,8 +149,7 @@ define nofpclass(nan) float @ret_no_nans__simplify_select_nan__floor(i1 %cond, f
 define nofpclass(inf) float @ret_no_infs__simplify_select_inf__floor(i1 %cond, float nofpclass(nan norm sub zero) %is.inf, float %unknown) {
 ; CHECK-LABEL: define nofpclass(inf) float @ret_no_infs__simplify_select_inf__floor(
 ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(nan zero sub norm) [[IS_INF:%.*]], float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[IS_INF]], float [[UNKNOWN]]
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.floor.f32(float [[SELECT]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.floor.f32(float [[UNKNOWN]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %select = select i1 %cond, float %is.inf, float %unknown
@@ -164,8 +160,7 @@ define nofpclass(inf) float @ret_no_infs__simplify_select_inf__floor(i1 %cond, f
 define nofpclass(nan inf) float @ret_no_inf_no_nan__simplify_select_inf_or_nan__floor(i1 %cond, float nofpclass(norm sub zero) %is.inf.or.nan, float %unknown) {
 ; CHECK-LABEL: define nofpclass(nan inf) float @ret_no_inf_no_nan__simplify_select_inf_or_nan__floor(
 ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(zero sub norm) [[IS_INF_OR_NAN:%.*]], float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[IS_INF_OR_NAN]], float [[UNKNOWN]]
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.floor.f32(float [[SELECT]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.floor.f32(float [[UNKNOWN]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %select = select i1 %cond, float %is.inf.or.nan, float %unknown
@@ -228,8 +223,7 @@ define nofpclass(snan) <2 x float> @source_known_sub_or_zero_or_nan__floor_vec(<
 define nofpclass(snan) float @source_known_psub_or_pzero__floor(float nofpclass(nan inf norm nsub nzero) %psub.or.pzero) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_psub_or_pzero__floor(
 ; CHECK-SAME: float nofpclass(nan inf nzero nsub norm) [[PSUB_OR_PZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.floor.f32(float [[PSUB_OR_PZERO]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float 0.000000e+00
 ;
   %result = call float @llvm.floor.f32(float %psub.or.pzero)
   ret float %result
@@ -268,8 +262,7 @@ define nofpclass(snan) float @source_known_nsub_or_nzero_or_nan__floor(float nof
 define nofpclass(snan) float @source_known_inf__floor(float nofpclass(nan norm sub zero) %inf) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_inf__floor(
 ; CHECK-SAME: float nofpclass(nan zero sub norm) [[INF:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.floor.f32(float [[INF]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float [[INF]]
 ;
   %result = call float @llvm.floor.f32(float %inf)
   ret float %result
@@ -278,8 +271,7 @@ define nofpclass(snan) float @source_known_inf__floor(float nofpclass(nan norm s
 define nofpclass(snan) float @source_known_inf_or_nan__floor(float nofpclass(norm sub zero) %inf.or.nan) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_inf_or_nan__floor(
 ; CHECK-SAME: float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.floor.f32(float [[INF_OR_NAN]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float [[INF_OR_NAN]]
 ;
   %result = call float @llvm.floor.f32(float %inf.or.nan)
   ret float %result
@@ -288,8 +280,7 @@ define nofpclass(snan) float @source_known_inf_or_nan__floor(float nofpclass(nor
 define nofpclass(snan) float @source_known_inf_or_nan_or_zero__floor(float nofpclass(norm sub) %inf.or.nan.or.zero) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_inf_or_nan_or_zero__floor(
 ; CHECK-SAME: float nofpclass(sub norm) [[INF_OR_NAN_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.floor.f32(float [[INF_OR_NAN_OR_ZERO]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float [[INF_OR_NAN_OR_ZERO]]
 ;
   %result = call float @llvm.floor.f32(float %inf.or.nan.or.zero)
   ret float %result
@@ -308,8 +299,7 @@ define nofpclass(snan) float @source_known_inf_or_nan_or_zero_or_sub__floor(floa
 define nofpclass(snan) float @source_known_inf_or_zero__floor(float nofpclass(nan norm sub) %inf.or.zero) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_inf_or_zero__floor(
 ; CHECK-SAME: float nofpclass(nan sub norm) [[INF_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.floor.f32(float [[INF_OR_ZERO]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float [[INF_OR_ZERO]]
 ;
   %result = call float @llvm.floor.f32(float %inf.or.zero)
   ret float %result
@@ -328,8 +318,7 @@ define nofpclass(snan) float @source_known_sub__floor(float nofpclass(inf nan no
 define nofpclass(snan) float @source_known_psub__floor(float nofpclass(inf nan norm nsub zero) %psub) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_psub__floor(
 ; CHECK-SAME: float nofpclass(nan inf zero nsub norm) [[PSUB:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.floor.f32(float [[PSUB]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float 0.000000e+00
 ;
   %result = call float @llvm.floor.f32(float %psub)
   ret float %result
@@ -338,8 +327,7 @@ define nofpclass(snan) float @source_known_psub__floor(float nofpclass(inf nan n
 define nofpclass(snan) float @source_known_nsub__floor(float nofpclass(inf nan norm psub zero) %nsub) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_nsub__floor(
 ; CHECK-SAME: float nofpclass(nan inf zero psub norm) [[NSUB:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.floor.f32(float [[NSUB]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float -1.000000e+00
 ;
   %result = call float @llvm.floor.f32(float %nsub)
   ret float %result
@@ -357,8 +345,7 @@ define nofpclass(snan) float @source_known_pinf__floor(float nofpclass(nan ninf
 define nofpclass(snan) float @source_known_pinf_or_nan__floor(float nofpclass(ninf norm sub zero) %pinf.or.nan) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_pinf_or_nan__floor(
 ; CHECK-SAME: float nofpclass(ninf zero sub norm) [[PINF_OR_NAN:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.floor.f32(float [[PINF_OR_NAN]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float [[PINF_OR_NAN]]
 ;
   %result = call float @llvm.floor.f32(float %pinf.or.nan)
   ret float %result
@@ -376,8 +363,7 @@ define nofpclass(snan) float @source_known_ninf__floor(float nofpclass(nan pinf
 define nofpclass(snan) float @source_known_ninf_or_nan__floor(float nofpclass(pinf norm sub zero) %ninf.or.nan) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_ninf_or_nan__floor(
 ; CHECK-SAME: float nofpclass(pinf zero sub norm) [[NINF_OR_NAN:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.floor.f32(float [[NINF_OR_NAN]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float [[NINF_OR_NAN]]
 ;
   %result = call float @llvm.floor.f32(float %ninf.or.nan)
   ret float %result
@@ -436,8 +422,7 @@ define nofpclass(snan) ppc_fp128 @source_known_not_ninf__floor_ppcf128(ppc_fp128
 define nofpclass(nan) float @ret_no_nans__simplify_select_nan__trunc(i1 %cond, float nofpclass(inf norm sub zero) %is.nan, float %unknown) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nans__simplify_select_nan__trunc(
 ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(inf zero sub norm) [[IS_NAN:%.*]], float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[IS_NAN]], float [[UNKNOWN]]
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.trunc.f32(float [[SELECT]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.trunc.f32(float [[UNKNOWN]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %select = select i1 %cond, float %is.nan, float %unknown
@@ -448,8 +433,7 @@ define nofpclass(nan) float @ret_no_nans__simplify_select_nan__trunc(i1 %cond, f
 define nofpclass(nan) float @ret_no_nans__simplify_select_nan__ceil(i1 %cond, float nofpclass(inf norm sub zero) %is.nan, float %unknown) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nans__simplify_select_nan__ceil(
 ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(inf zero sub norm) [[IS_NAN:%.*]], float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[IS_NAN]], float [[UNKNOWN]]
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.ceil.f32(float [[SELECT]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.ceil.f32(float [[UNKNOWN]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %select = select i1 %cond, float %is.nan, float %unknown
@@ -460,8 +444,7 @@ define nofpclass(nan) float @ret_no_nans__simplify_select_nan__ceil(i1 %cond, fl
 define nofpclass(nan) float @ret_no_nans__simplify_select_nan__rint(i1 %cond, float nofpclass(inf norm sub zero) %is.nan, float %unknown) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nans__simplify_select_nan__rint(
 ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(inf zero sub norm) [[IS_NAN:%.*]], float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[IS_NAN]], float [[UNKNOWN]]
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.rint.f32(float [[SELECT]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.rint.f32(float [[UNKNOWN]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %select = select i1 %cond, float %is.nan, float %unknown
@@ -472,8 +455,7 @@ define nofpclass(nan) float @ret_no_nans__simplify_select_nan__rint(i1 %cond, fl
 define nofpclass(nan) float @ret_no_nans__simplify_select_nan__nearbyint(i1 %cond, float nofpclass(inf norm sub zero) %is.nan, float %unknown) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nans__simplify_select_nan__nearbyint(
 ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(inf zero sub norm) [[IS_NAN:%.*]], float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[IS_NAN]], float [[UNKNOWN]]
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.nearbyint.f32(float [[SELECT]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.nearbyint.f32(float [[UNKNOWN]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %select = select i1 %cond, float %is.nan, float %unknown
@@ -484,8 +466,7 @@ define nofpclass(nan) float @ret_no_nans__simplify_select_nan__nearbyint(i1 %con
 define nofpclass(nan) float @ret_no_nans__simplify_select_nan__round(i1 %cond, float nofpclass(inf norm sub zero) %is.nan, float %unknown) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nans__simplify_select_nan__round(
 ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(inf zero sub norm) [[IS_NAN:%.*]], float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[IS_NAN]], float [[UNKNOWN]]
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.round.f32(float [[SELECT]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.round.f32(float [[UNKNOWN]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %select = select i1 %cond, float %is.nan, float %unknown
@@ -496,8 +477,7 @@ define nofpclass(nan) float @ret_no_nans__simplify_select_nan__round(i1 %cond, f
 define nofpclass(nan) float @ret_no_nans__simplify_select_nan__roundeven(i1 %cond, float nofpclass(inf norm sub zero) %is.nan, float %unknown) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nans__simplify_select_nan__roundeven(
 ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(inf zero sub norm) [[IS_NAN:%.*]], float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[IS_NAN]], float [[UNKNOWN]]
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.roundeven.f32(float [[SELECT]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.roundeven.f32(float [[UNKNOWN]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %select = select i1 %cond, float %is.nan, float %unknown
@@ -508,7 +488,7 @@ define nofpclass(nan) float @ret_no_nans__simplify_select_nan__roundeven(i1 %con
 define nofpclass(snan) float @source_known_sub_or_zero__trunc(float nofpclass(nan inf norm) %sub.or.zero) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_sub_or_zero__trunc(
 ; CHECK-SAME: float nofpclass(nan inf norm) [[SUB_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.trunc.f32(float [[SUB_OR_ZERO]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[SUB_OR_ZERO]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %result = call float @llvm.trunc.f32(float %sub.or.zero)
@@ -518,8 +498,7 @@ define nofpclass(snan) float @source_known_sub_or_zero__trunc(float nofpclass(na
 define nofpclass(snan) float @source_known_psub_or_pzero__trunc(float nofpclass(nan inf norm nsub nzero) %psub.or.pzero) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_psub_or_pzero__trunc(
 ; CHECK-SAME: float nofpclass(nan inf nzero nsub norm) [[PSUB_OR_PZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.trunc.f32(float [[PSUB_OR_PZERO]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float 0.000000e+00
 ;
   %result = call float @llvm.trunc.f32(float %psub.or.pzero)
   ret float %result
@@ -528,8 +507,7 @@ define nofpclass(snan) float @source_known_psub_or_pzero__trunc(float nofpclass(
 define nofpclass(snan) float @source_known_nsub_or_nzero__trunc(float nofpclass(nan inf norm psub pzero) %nsub.or.nzero) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_nsub_or_nzero__trunc(
 ; CHECK-SAME: float nofpclass(nan inf pzero psub norm) [[NSUB_OR_NZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.trunc.f32(float [[NSUB_OR_NZERO]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float -0.000000e+00
 ;
   %result = call float @llvm.trunc.f32(float %nsub.or.nzero)
   ret float %result
@@ -538,8 +516,7 @@ define nofpclass(snan) float @source_known_nsub_or_nzero__trunc(float nofpclass(
 define nofpclass(snan) float @source_known_inf_or_nan_or_zero__trunc(float nofpclass(norm sub) %inf.or.nan.or.zero) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_inf_or_nan_or_zero__trunc(
 ; CHECK-SAME: float nofpclass(sub norm) [[INF_OR_NAN_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.trunc.f32(float [[INF_OR_NAN_OR_ZERO]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float [[INF_OR_NAN_OR_ZERO]]
 ;
   %result = call float @llvm.trunc.f32(float %inf.or.nan.or.zero)
   ret float %result
@@ -558,8 +535,7 @@ define nofpclass(snan) float @source_known_inf_or_nan_or_zero_or_sub__trunc(floa
 define nofpclass(snan) float @source_known_inf_or_zero__trunc(float nofpclass(nan norm sub) %inf.or.zero) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_inf_or_zero__trunc(
 ; CHECK-SAME: float nofpclass(nan sub norm) [[INF_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.trunc.f32(float [[INF_OR_ZERO]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float [[INF_OR_ZERO]]
 ;
   %result = call float @llvm.trunc.f32(float %inf.or.zero)
   ret float %result
@@ -568,7 +544,7 @@ define nofpclass(snan) float @source_known_inf_or_zero__trunc(float nofpclass(na
 define nofpclass(snan) float @source_known_sub__trunc(float nofpclass(inf nan norm zero) %sub) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_sub__trunc(
 ; CHECK-SAME: float nofpclass(nan inf zero norm) [[SUB:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.trunc.f32(float [[SUB]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[SUB]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %result = call float @llvm.trunc.f32(float %sub)
@@ -578,8 +554,7 @@ define nofpclass(snan) float @source_known_sub__trunc(float nofpclass(inf nan no
 define nofpclass(snan) float @source_known_psub__trunc(float nofpclass(inf nan norm nsub zero) %psub) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_psub__trunc(
 ; CHECK-SAME: float nofpclass(nan inf zero nsub norm) [[PSUB:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.trunc.f32(float [[PSUB]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float 0.000000e+00
 ;
   %result = call float @llvm.trunc.f32(float %psub)
   ret float %result
@@ -588,8 +563,7 @@ define nofpclass(snan) float @source_known_psub__trunc(float nofpclass(inf nan n
 define nofpclass(snan) float @source_known_nsub__trunc(float nofpclass(inf nan norm psub zero) %nsub) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_nsub__trunc(
 ; CHECK-SAME: float nofpclass(nan inf zero psub norm) [[NSUB:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.trunc.f32(float [[NSUB]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float -0.000000e+00
 ;
   %result = call float @llvm.trunc.f32(float %nsub)
   ret float %result
@@ -628,7 +602,7 @@ define nofpclass(snan) float @source_known_nsub_or_nzero__ceil(float nofpclass(n
 define nofpclass(snan) float @source_known_sub_or_zero__rint(float nofpclass(nan inf norm) %sub.or.zero) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_sub_or_zero__rint(
 ; CHECK-SAME: float nofpclass(nan inf norm) [[SUB_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.rint.f32(float [[SUB_OR_ZERO]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[SUB_OR_ZERO]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %result = call float @llvm.rint.f32(float %sub.or.zero)
@@ -638,8 +612,7 @@ define nofpclass(snan) float @source_known_sub_or_zero__rint(float nofpclass(nan
 define nofpclass(snan) float @source_known_psub_or_pzero__rint(float nofpclass(nan inf norm nsub nzero) %psub.or.pzero) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_psub_or_pzero__rint(
 ; CHECK-SAME: float nofpclass(nan inf nzero nsub norm) [[PSUB_OR_PZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.rint.f32(float [[PSUB_OR_PZERO]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float 0.000000e+00
 ;
   %result = call float @llvm.rint.f32(float %psub.or.pzero)
   ret float %result
@@ -648,8 +621,7 @@ define nofpclass(snan) float @source_known_psub_or_pzero__rint(float nofpclass(n
 define nofpclass(snan) float @source_known_nsub_or_nzero__rint(float nofpclass(nan inf norm psub pzero) %nsub.or.nzero) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_nsub_or_nzero__rint(
 ; CHECK-SAME: float nofpclass(nan inf pzero psub norm) [[NSUB_OR_NZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.rint.f32(float [[NSUB_OR_NZERO]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float -0.000000e+00
 ;
   %result = call float @llvm.rint.f32(float %nsub.or.nzero)
   ret float %result
@@ -658,7 +630,7 @@ define nofpclass(snan) float @source_known_nsub_or_nzero__rint(float nofpclass(n
 define nofpclass(snan) float @source_known_sub_or_zero__nearbyint(float nofpclass(nan inf norm) %sub.or.zero) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_sub_or_zero__nearbyint(
 ; CHECK-SAME: float nofpclass(nan inf norm) [[SUB_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.nearbyint.f32(float [[SUB_OR_ZERO]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[SUB_OR_ZERO]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %result = call float @llvm.nearbyint.f32(float %sub.or.zero)
@@ -668,8 +640,7 @@ define nofpclass(snan) float @source_known_sub_or_zero__nearbyint(float nofpclas
 define nofpclass(snan) float @source_known_psub_or_pzero__nearbyint(float nofpclass(nan inf norm nsub nzero) %psub.or.pzero) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_psub_or_pzero__nearbyint(
 ; CHECK-SAME: float nofpclass(nan inf nzero nsub norm) [[PSUB_OR_PZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.nearbyint.f32(float [[PSUB_OR_PZERO]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float 0.000000e+00
 ;
   %result = call float @llvm.nearbyint.f32(float %psub.or.pzero)
   ret float %result
@@ -678,8 +649,7 @@ define nofpclass(snan) float @source_known_psub_or_pzero__nearbyint(float nofpcl
 define nofpclass(snan) float @source_known_nsub_or_nzero__nearbyint(float nofpclass(nan inf norm psub pzero) %nsub.or.nzero) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_nsub_or_nzero__nearbyint(
 ; CHECK-SAME: float nofpclass(nan inf pzero psub norm) [[NSUB_OR_NZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.nearbyint.f32(float [[NSUB_OR_NZERO]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float -0.000000e+00
 ;
   %result = call float @llvm.nearbyint.f32(float %nsub.or.nzero)
   ret float %result
@@ -688,7 +658,7 @@ define nofpclass(snan) float @source_known_nsub_or_nzero__nearbyint(float nofpcl
 define nofpclass(snan) float @source_known_sub_or_zero__round(float nofpclass(nan inf norm) %sub.or.zero) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_sub_or_zero__round(
 ; CHECK-SAME: float nofpclass(nan inf norm) [[SUB_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.round.f32(float [[SUB_OR_ZERO]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[SUB_OR_ZERO]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %result = call float @llvm.round.f32(float %sub.or.zero)
@@ -698,8 +668,7 @@ define nofpclass(snan) float @source_known_sub_or_zero__round(float nofpclass(na
 define nofpclass(snan) float @source_known_psub_or_pzero__round(float nofpclass(nan inf norm nsub nzero) %psub.or.pzero) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_psub_or_pzero__round(
 ; CHECK-SAME: float nofpclass(nan inf nzero nsub norm) [[PSUB_OR_PZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.round.f32(float [[PSUB_OR_PZERO]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float 0.000000e+00
 ;
   %result = call float @llvm.round.f32(float %psub.or.pzero)
   ret float %result
@@ -708,8 +677,7 @@ define nofpclass(snan) float @source_known_psub_or_pzero__round(float nofpclass(
 define nofpclass(snan) float @source_known_nsub_or_nzero__round(float nofpclass(nan inf norm psub pzero) %nsub.or.nzero) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_nsub_or_nzero__round(
 ; CHECK-SAME: float nofpclass(nan inf pzero psub norm) [[NSUB_OR_NZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.round.f32(float [[NSUB_OR_NZERO]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float -0.000000e+00
 ;
   %result = call float @llvm.round.f32(float %nsub.or.nzero)
   ret float %result
@@ -718,7 +686,7 @@ define nofpclass(snan) float @source_known_nsub_or_nzero__round(float nofpclass(
 define nofpclass(snan) float @source_known_sub_or_zero__roundeven(float nofpclass(nan inf norm) %sub.or.zero) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_sub_or_zero__roundeven(
 ; CHECK-SAME: float nofpclass(nan inf norm) [[SUB_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.roundeven.f32(float [[SUB_OR_ZERO]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[SUB_OR_ZERO]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %result = call float @llvm.roundeven.f32(float %sub.or.zero)
@@ -728,8 +696,7 @@ define nofpclass(snan) float @source_known_sub_or_zero__roundeven(float nofpclas
 define nofpclass(snan) float @source_known_psub_or_pzero__roundeven(float nofpclass(nan inf norm nsub nzero) %psub.or.pzero) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_psub_or_pzero__roundeven(
 ; CHECK-SAME: float nofpclass(nan inf nzero nsub norm) [[PSUB_OR_PZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.roundeven.f32(float [[PSUB_OR_PZERO]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float 0.000000e+00
 ;
   %result = call float @llvm.roundeven.f32(float %psub.or.pzero)
   ret float %result
@@ -738,8 +705,7 @@ define nofpclass(snan) float @source_known_psub_or_pzero__roundeven(float nofpcl
 define nofpclass(snan) float @source_known_nsub_or_nzero__roundeven(float nofpclass(nan inf norm psub pzero) %nsub.or.nzero) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_nsub_or_nzero__roundeven(
 ; CHECK-SAME: float nofpclass(nan inf pzero psub norm) [[NSUB_OR_NZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.roundeven.f32(float [[NSUB_OR_NZERO]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float -0.000000e+00
 ;
   %result = call float @llvm.roundeven.f32(float %nsub.or.nzero)
   ret float %result
@@ -778,7 +744,7 @@ define nofpclass(nan) float @ret_no_nans_source_known_nsub_or_zero_or_nan__floor
 define nofpclass(nan) float @ret_no_nans_source_known_sub_or_zero_or_nan__trunc(float nofpclass(inf norm) %sub.or.zero) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nans_source_known_sub_or_zero_or_nan__trunc(
 ; CHECK-SAME: float nofpclass(inf norm) [[SUB_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.trunc.f32(float [[SUB_OR_ZERO]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[SUB_OR_ZERO]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %result = call float @llvm.trunc.f32(float %sub.or.zero)
@@ -788,7 +754,7 @@ define nofpclass(nan) float @ret_no_nans_source_known_sub_or_zero_or_nan__trunc(
 define nofpclass(nan) float @ret_no_nans_source_known_psub_or_zero_or_nan__trunc(float nofpclass(inf norm nsub) %psub.or.zero) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nans_source_known_psub_or_zero_or_nan__trunc(
 ; CHECK-SAME: float nofpclass(inf nsub norm) [[PSUB_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.trunc.f32(float [[PSUB_OR_ZERO]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[PSUB_OR_ZERO]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %result = call float @llvm.trunc.f32(float %psub.or.zero)
@@ -798,7 +764,7 @@ define nofpclass(nan) float @ret_no_nans_source_known_psub_or_zero_or_nan__trunc
 define nofpclass(nan) float @ret_no_nans_source_known_nsub_or_zero_or_nan__trunc(float nofpclass(inf norm psub) %nsub.or.zero) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nans_source_known_nsub_or_zero_or_nan__trunc(
 ; CHECK-SAME: float nofpclass(inf psub norm) [[NSUB_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.trunc.f32(float [[NSUB_OR_ZERO]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[NSUB_OR_ZERO]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %result = call float @llvm.trunc.f32(float %nsub.or.zero)
@@ -838,7 +804,7 @@ define nofpclass(nan) float @ret_no_nans_source_known_nsub_or_zero_or_nan__ceil(
 define nofpclass(nan) float @ret_no_nans_source_known_sub_or_zero_or_nan__rint(float nofpclass(inf norm) %sub.or.zero) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nans_source_known_sub_or_zero_or_nan__rint(
 ; CHECK-SAME: float nofpclass(inf norm) [[SUB_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.rint.f32(float [[SUB_OR_ZERO]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[SUB_OR_ZERO]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %result = call float @llvm.rint.f32(float %sub.or.zero)
@@ -848,7 +814,7 @@ define nofpclass(nan) float @ret_no_nans_source_known_sub_or_zero_or_nan__rint(f
 define nofpclass(nan) float @ret_no_nans_source_known_psub_or_zero_or_nan__rint(float nofpclass(inf norm nsub) %psub.or.zero) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nans_source_known_psub_or_zero_or_nan__rint(
 ; CHECK-SAME: float nofpclass(inf nsub norm) [[PSUB_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.rint.f32(float [[PSUB_OR_ZERO]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[PSUB_OR_ZERO]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %result = call float @llvm.rint.f32(float %psub.or.zero)
@@ -858,7 +824,7 @@ define nofpclass(nan) float @ret_no_nans_source_known_psub_or_zero_or_nan__rint(
 define nofpclass(nan) float @ret_no_nans_source_known_nsub_or_zero_or_nan__rint(float nofpclass(inf norm psub) %nsub.or.zero) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nans_source_known_nsub_or_zero_or_nan__rint(
 ; CHECK-SAME: float nofpclass(inf psub norm) [[NSUB_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.rint.f32(float [[NSUB_OR_ZERO]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[NSUB_OR_ZERO]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %result = call float @llvm.rint.f32(float %nsub.or.zero)
@@ -868,7 +834,7 @@ define nofpclass(nan) float @ret_no_nans_source_known_nsub_or_zero_or_nan__rint(
 define nofpclass(nan) float @ret_no_nans_source_known_sub_or_zero_or_nan__nearbyint(float nofpclass(inf norm) %sub.or.zero) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nans_source_known_sub_or_zero_or_nan__nearbyint(
 ; CHECK-SAME: float nofpclass(inf norm) [[SUB_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.nearbyint.f32(float [[SUB_OR_ZERO]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[SUB_OR_ZERO]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %result = call float @llvm.nearbyint.f32(float %sub.or.zero)
@@ -878,7 +844,7 @@ define nofpclass(nan) float @ret_no_nans_source_known_sub_or_zero_or_nan__nearby
 define nofpclass(nan) float @ret_no_nans_source_known_psub_or_zero_or_nan__nearbyint(float nofpclass(inf norm nsub) %psub.or.zero) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nans_source_known_psub_or_zero_or_nan__nearbyint(
 ; CHECK-SAME: float nofpclass(inf nsub norm) [[PSUB_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.nearbyint.f32(float [[PSUB_OR_ZERO]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[PSUB_OR_ZERO]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %result = call float @llvm.nearbyint.f32(float %psub.or.zero)
@@ -888,7 +854,7 @@ define nofpclass(nan) float @ret_no_nans_source_known_psub_or_zero_or_nan__nearb
 define nofpclass(nan) float @ret_no_nans_source_known_nsub_or_zero_or_nan__nearbyint(float nofpclass(inf norm psub) %nsub.or.zero) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nans_source_known_nsub_or_zero_or_nan__nearbyint(
 ; CHECK-SAME: float nofpclass(inf psub norm) [[NSUB_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.nearbyint.f32(float [[NSUB_OR_ZERO]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[NSUB_OR_ZERO]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %result = call float @llvm.nearbyint.f32(float %nsub.or.zero)
@@ -898,7 +864,7 @@ define nofpclass(nan) float @ret_no_nans_source_known_nsub_or_zero_or_nan__nearb
 define nofpclass(nan) float @ret_no_nans_source_known_sub_or_zero_or_nan__round(float nofpclass(inf norm) %sub.or.zero) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nans_source_known_sub_or_zero_or_nan__round(
 ; CHECK-SAME: float nofpclass(inf norm) [[SUB_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.round.f32(float [[SUB_OR_ZERO]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[SUB_OR_ZERO]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %result = call float @llvm.round.f32(float %sub.or.zero)
@@ -908,7 +874,7 @@ define nofpclass(nan) float @ret_no_nans_source_known_sub_or_zero_or_nan__round(
 define nofpclass(nan) float @ret_no_nans_source_known_psub_or_zero_or_nan__round(float nofpclass(inf norm nsub) %psub.or.zero) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nans_source_known_psub_or_zero_or_nan__round(
 ; CHECK-SAME: float nofpclass(inf nsub norm) [[PSUB_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.round.f32(float [[PSUB_OR_ZERO]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[PSUB_OR_ZERO]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %result = call float @llvm.round.f32(float %psub.or.zero)
@@ -918,7 +884,7 @@ define nofpclass(nan) float @ret_no_nans_source_known_psub_or_zero_or_nan__round
 define nofpclass(nan) float @ret_no_nans_source_known_nsub_or_zero_or_nan__round(float nofpclass(inf norm psub) %nsub.or.zero) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nans_source_known_nsub_or_zero_or_nan__round(
 ; CHECK-SAME: float nofpclass(inf psub norm) [[NSUB_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.round.f32(float [[NSUB_OR_ZERO]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[NSUB_OR_ZERO]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %result = call float @llvm.round.f32(float %nsub.or.zero)
@@ -928,7 +894,7 @@ define nofpclass(nan) float @ret_no_nans_source_known_nsub_or_zero_or_nan__round
 define nofpclass(nan) float @ret_no_nans_source_known_sub_or_zero_or_nan__roundeven(float nofpclass(inf norm) %sub.or.zero) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nans_source_known_sub_or_zero_or_nan__roundeven(
 ; CHECK-SAME: float nofpclass(inf norm) [[SUB_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.roundeven.f32(float [[SUB_OR_ZERO]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[SUB_OR_ZERO]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %result = call float @llvm.roundeven.f32(float %sub.or.zero)
@@ -938,7 +904,7 @@ define nofpclass(nan) float @ret_no_nans_source_known_sub_or_zero_or_nan__rounde
 define nofpclass(nan) float @ret_no_nans_source_known_psub_or_zero_or_nan__roundeven(float nofpclass(inf norm nsub) %psub.or.zero) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nans_source_known_psub_or_zero_or_nan__roundeven(
 ; CHECK-SAME: float nofpclass(inf nsub norm) [[PSUB_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.roundeven.f32(float [[PSUB_OR_ZERO]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[PSUB_OR_ZERO]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %result = call float @llvm.roundeven.f32(float %psub.or.zero)
@@ -948,7 +914,7 @@ define nofpclass(nan) float @ret_no_nans_source_known_psub_or_zero_or_nan__round
 define nofpclass(nan) float @ret_no_nans_source_known_nsub_or_zero_or_nan__roundeven(float nofpclass(inf norm psub) %nsub.or.zero) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_no_nans_source_known_nsub_or_zero_or_nan__roundeven(
 ; CHECK-SAME: float nofpclass(inf psub norm) [[NSUB_OR_ZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.roundeven.f32(float [[NSUB_OR_ZERO]])
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[NSUB_OR_ZERO]])
 ; CHECK-NEXT:    ret float [[RESULT]]
 ;
   %result = call float @llvm.roundeven.f32(float %nsub.or.zero)

>From 6a568ce2f446b72c591b20e418ade31eeb432a3a Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Thu, 8 Jan 2026 18:45:32 +0100
Subject: [PATCH 2/8] VTy->getScalarType()->isMultiUnitFPType()

---
 llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index f88997fb6619f..a7c6b1796bd73 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -2687,7 +2687,7 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Instruction *I,
         return ConstantFP::get(VTy, 1.0);
 
       Known = KnownFPClass::roundToIntegral(KnownSrc, IID == Intrinsic::trunc,
-                                            VTy->isMultiUnitFPType());
+                                            VTy->getScalarType()->isMultiUnitFPType());
 
       FPClassTest ValidResults = DemandedMask & Known.KnownFPClasses;
       if (Constant *SingleVal =

>From 633a6bb3a680c3f495bd3142bf3ec0c411c6a929 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Thu, 8 Jan 2026 18:46:44 +0100
Subject: [PATCH 3/8] also zero

---
 llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index a7c6b1796bd73..608d91868c2ed 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -2659,7 +2659,7 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Instruction *I,
         return I;
 
       // Note: Possibly dropping snan quiet.
-      if (KnownSrc.isKnownAlways(fcInf | fcNan))
+      if (KnownSrc.isKnownAlways(fcInf | fcNan | fcZero))
         return CI->getArgOperand(0);
 
       // Propagate nnan-ness to source to simplify source checks.

>From 69b5dd123f53a1bf4b0d37388697f2e561251a2e Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Thu, 8 Jan 2026 19:29:06 +0100
Subject: [PATCH 4/8] format

---
 .../Transforms/InstCombine/InstCombineSimplifyDemanded.cpp   | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 608d91868c2ed..4db0d4f8321ef 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -2686,8 +2686,9 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Instruction *I,
       if (IID == Intrinsic::ceil && KnownSrc.isKnownAlways(fcPosSubnormal))
         return ConstantFP::get(VTy, 1.0);
 
-      Known = KnownFPClass::roundToIntegral(KnownSrc, IID == Intrinsic::trunc,
-                                            VTy->getScalarType()->isMultiUnitFPType());
+      Known = KnownFPClass::roundToIntegral(
+          KnownSrc, IID == Intrinsic::trunc,
+          VTy->getScalarType()->isMultiUnitFPType());
 
       FPClassTest ValidResults = DemandedMask & Known.KnownFPClasses;
       if (Constant *SingleVal =

>From 0c338529a7ad8fc6fa0049daf5969a4e54785d59 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Sun, 11 Jan 2026 09:34:29 +0100
Subject: [PATCH 5/8] Remove parentheses

---
 llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 4db0d4f8321ef..48bd2279e3211 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -2673,7 +2673,7 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Instruction *I,
       // Ignore denormals-as-zero, as canonicalization is not mandated.
       if ((IID == Intrinsic::trunc || IID == Intrinsic::floor ||
            IsRoundNearest) &&
-          (KnownSrc.isKnownAlways(fcPosZero | fcPosSubnormal)))
+          KnownSrc.isKnownAlways(fcPosZero | fcPosSubnormal))
         return ConstantFP::getZero(VTy);
 
       if ((IID == Intrinsic::trunc || IsRoundNearest) &&

>From da9e43306f9a5997737bd258d13a1c1e0991eb83 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Sun, 11 Jan 2026 09:37:12 +0100
Subject: [PATCH 6/8] getScalarType()->isMultiUnitFPType()

---
 llvm/lib/Analysis/ValueTracking.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 1e16647e6ccc1..859cfe75daa37 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5220,8 +5220,9 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
       computeKnownFPClass(II->getArgOperand(0), DemandedElts, InterestedSrcs,
                           KnownSrc, Q, Depth + 1);
 
-      Known = KnownFPClass::roundToIntegral(KnownSrc, IID == Intrinsic::trunc,
-                                            V->getType()->isMultiUnitFPType());
+      Known = KnownFPClass::roundToIntegral(
+          KnownSrc, IID == Intrinsic::trunc,
+          V->getType()->getScalarType()->isMultiUnitFPType());
       break;
     }
     case Intrinsic::exp:

>From 9eac606963ed3ff5f596570fd76cb0440db909d5 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Sun, 11 Jan 2026 09:40:55 +0100
Subject: [PATCH 7/8] ceil to -0

---
 .../lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp | 3 ++-
 .../simplify-demanded-fpclass-rounding-intrinsics.ll           | 3 +--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 48bd2279e3211..985ca67051d78 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -2676,7 +2676,8 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Instruction *I,
           KnownSrc.isKnownAlways(fcPosZero | fcPosSubnormal))
         return ConstantFP::getZero(VTy);
 
-      if ((IID == Intrinsic::trunc || IsRoundNearest) &&
+      if ((IID == Intrinsic::trunc || IID == Intrinsic::ceil ||
+           IsRoundNearest) &&
           KnownSrc.isKnownAlways(fcNegZero | fcNegSubnormal))
         return ConstantFP::getZero(VTy, true);
 
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-rounding-intrinsics.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-rounding-intrinsics.ll
index 1903bbe851ae2..37018feb43adb 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-rounding-intrinsics.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-rounding-intrinsics.ll
@@ -592,8 +592,7 @@ define nofpclass(snan) float @source_known_psub_or_pzero__ceil(float nofpclass(n
 define nofpclass(snan) float @source_known_nsub_or_nzero__ceil(float nofpclass(nan inf norm psub pzero) %nsub.or.nzero) {
 ; CHECK-LABEL: define nofpclass(snan) float @source_known_nsub_or_nzero__ceil(
 ; CHECK-SAME: float nofpclass(nan inf pzero psub norm) [[NSUB_OR_NZERO:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.ceil.f32(float [[NSUB_OR_NZERO]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    ret float -0.000000e+00
 ;
   %result = call float @llvm.ceil.f32(float %nsub.or.nzero)
   ret float %result

>From bf5cc664fe1e9add67c1376ac079071bd5f9da3e Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Sun, 11 Jan 2026 09:46:37 +0100
Subject: [PATCH 8/8] Zero implies normal

---
 .../Transforms/InstCombine/InstCombineSimplifyDemanded.cpp    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 985ca67051d78..2ff71b6f25086 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -2649,10 +2649,10 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Instruction *I,
 
       // Zero results imply valid subnormal sources.
       if (DemandedMask & fcNegZero)
-        DemandedSrcMask |= fcNegSubnormal;
+        DemandedSrcMask |= fcNegSubnormal | fcNegNormal;
 
       if (DemandedMask & fcPosZero)
-        DemandedSrcMask |= fcPosSubnormal;
+        DemandedSrcMask |= fcPosSubnormal | fcPosNormal;
 
       KnownFPClass KnownSrc;
       if (SimplifyDemandedFPClass(CI, 0, DemandedSrcMask, KnownSrc, Depth + 1))



More information about the llvm-branch-commits mailing list