Skip to content

Conversation

@arsenm
Copy link
Contributor

@arsenm arsenm commented Dec 21, 2025

Doesn't try to handle PositiveZero flushing mode, but I
don't believe it is incorrect with it.

Copy link
Contributor Author

arsenm commented Dec 21, 2025

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@arsenm arsenm added floating-point Floating-point math llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes labels Dec 21, 2025 — with Graphite App
@arsenm arsenm marked this pull request as ready for review December 21, 2025 13:21
@arsenm arsenm requested a review from nikic as a code owner December 21, 2025 13:21
@llvmbot llvmbot added llvm:support llvm:analysis Includes value tracking, cost tables and constant folding llvm:transforms labels Dec 21, 2025
@llvmbot
Copy link
Member

llvmbot commented Dec 21, 2025

@llvm/pr-subscribers-llvm-support
@llvm/pr-subscribers-llvm-analysis

@llvm/pr-subscribers-llvm-transforms

Author: Matt Arsenault (arsenm)

Changes

Doesn't try to handle PositiveZero flushing mode, but I
don't believe it is incorrect with it.


Patch is 25.52 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/173189.diff

5 Files Affected:

  • (modified) llvm/include/llvm/Support/KnownFPClass.h (+5)
  • (modified) llvm/lib/Analysis/ValueTracking.cpp (+6-49)
  • (modified) llvm/lib/Support/KnownFPClass.cpp (+48)
  • (modified) llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp (+73)
  • (modified) llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-canonicalize.ll (+26-53)
diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h
index b3c18bcf6b34b..e50b97ac7f00d 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -155,6 +155,11 @@ struct KnownFPClass {
     signBitMustBeZero();
   }
 
+  /// Apply the canonicalize intrinsic to this value. This is essentially a
+  /// stronger form of propagateCanonicalizingSrc.
+  LLVM_ABI void
+  canonicalize(DenormalMode DenormMode = DenormalMode::getDynamic());
+
   /// Return true if the sign bit must be 0, ignoring the sign of nans.
   bool signBitIsZeroOrNaN() const { return isKnownNever(fcNegative); }
 
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 0321c08f55776..f7fdf9f1c0985 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5269,58 +5269,15 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
       break;
     }
     case Intrinsic::canonicalize: {
-      KnownFPClass KnownSrc;
       computeKnownFPClass(II->getArgOperand(0), DemandedElts, InterestedClasses,
-                          KnownSrc, Q, Depth + 1);
-
-      // This is essentially a stronger form of
-      // propagateCanonicalizingSrc. Other "canonicalizing" operations don't
-      // actually have an IR canonicalization guarantee.
-
-      // Canonicalize may flush denormals to zero, so we have to consider the
-      // denormal mode to preserve known-not-0 knowledge.
-      Known.KnownFPClasses = KnownSrc.KnownFPClasses | fcZero | fcQNan;
-
-      // Stronger version of propagateNaN
-      // Canonicalize is guaranteed to quiet signaling nans.
-      if (KnownSrc.isKnownNeverNaN())
-        Known.knownNot(fcNan);
-      else
-        Known.knownNot(fcSNan);
+                          Known, Q, Depth + 1);
 
       const Function *F = II->getFunction();
-      if (!F)
-        break;
-
-      // If the parent function flushes denormals, the canonical output cannot
-      // be a denormal.
-      const fltSemantics &FPType =
-          II->getType()->getScalarType()->getFltSemantics();
-      DenormalMode DenormMode = F->getDenormalMode(FPType);
-      if (DenormMode == DenormalMode::getIEEE()) {
-        if (KnownSrc.isKnownNever(fcPosZero))
-          Known.knownNot(fcPosZero);
-        if (KnownSrc.isKnownNever(fcNegZero))
-          Known.knownNot(fcNegZero);
-        break;
-      }
-
-      if (DenormMode.inputsAreZero() || DenormMode.outputsAreZero())
-        Known.knownNot(fcSubnormal);
-
-      if (DenormMode == DenormalMode::getPreserveSign()) {
-        if (KnownSrc.isKnownNever(fcPosZero | fcPosSubnormal))
-          Known.knownNot(fcPosZero);
-        if (KnownSrc.isKnownNever(fcNegZero | fcNegSubnormal))
-          Known.knownNot(fcNegZero);
-        break;
-      }
-
-      if (DenormMode.Input == DenormalMode::PositiveZero ||
-          (DenormMode.Output == DenormalMode::PositiveZero &&
-           DenormMode.Input == DenormalMode::IEEE))
-        Known.knownNot(fcNegZero);
-
+      DenormalMode DenormMode =
+          F ? F->getDenormalMode(
+                  II->getType()->getScalarType()->getFltSemantics())
+            : DenormalMode::getDynamic();
+      Known.canonicalize(DenormMode);
       break;
     }
     case Intrinsic::vector_reduce_fmax:
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 43fb2e7108d2b..cb9563e0e52c3 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -87,6 +87,54 @@ void KnownFPClass::propagateDenormal(const KnownFPClass &Src,
   }
 }
 
+void KnownFPClass::canonicalize(DenormalMode DenormMode) {
+  KnownFPClass KnownSrc = *this;
+  *this = KnownFPClass();
+
+  // This is essentially a stronger form of
+  // propagateCanonicalizingSrc. Other "canonicalizing" operations don't
+  // actually have an IR canonicalization guarantee.
+
+  // Canonicalize may flush denormals to zero, so we have to consider the
+  // denormal mode to preserve known-not-0 knowledge.
+  KnownFPClasses = KnownSrc.KnownFPClasses | fcZero | fcQNan;
+
+  // Stronger version of propagateNaN
+  // Canonicalize is guaranteed to quiet signaling nans.
+  if (KnownSrc.isKnownNeverNaN())
+    knownNot(fcNan);
+  else
+    knownNot(fcSNan);
+
+  // FIXME: Missing check of IEEE like types.
+
+  // If the parent function flushes denormals, the canonical output cannot be a
+  // denormal.
+  if (DenormMode == DenormalMode::getIEEE()) {
+    if (KnownSrc.isKnownNever(fcPosZero))
+      knownNot(fcPosZero);
+    if (KnownSrc.isKnownNever(fcNegZero))
+      knownNot(fcNegZero);
+    return;
+  }
+
+  if (DenormMode.inputsAreZero() || DenormMode.outputsAreZero())
+    knownNot(fcSubnormal);
+
+  if (DenormMode == DenormalMode::getPreserveSign()) {
+    if (KnownSrc.isKnownNever(fcPosZero | fcPosSubnormal))
+      knownNot(fcPosZero);
+    if (KnownSrc.isKnownNever(fcNegZero | fcNegSubnormal))
+      knownNot(fcNegZero);
+    return;
+  }
+
+  if (DenormMode.Input == DenormalMode::PositiveZero ||
+      (DenormMode.Output == DenormalMode::PositiveZero &&
+       DenormMode.Input == DenormalMode::IEEE))
+    knownNot(fcNegZero);
+}
+
 void KnownFPClass::propagateCanonicalizingSrc(const KnownFPClass &Src,
                                               DenormalMode Mode) {
   propagateDenormal(Src, Mode);
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 550dfc57a348b..3df89c930967e 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -2106,6 +2106,79 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Value *V,
       Known.copysign(KnownSign);
       break;
     }
+    case Intrinsic::canonicalize: {
+      Type *EltTy = VTy->getScalarType();
+
+      // TODO: This could have more refined support for PositiveZero denormal
+      // mode.
+      if (EltTy->isIEEELikeFPTy()) {
+        DenormalMode Mode = F.getDenormalMode(EltTy->getFltSemantics());
+
+        FPClassTest SrcDemandedMask = DemandedMask;
+
+        // A demanded quiet nan result may have come from a signaling nan, so we
+        // need to expand the demanded mask.
+        if ((DemandedMask & fcQNan) != fcNone)
+          SrcDemandedMask |= fcSNan;
+
+        // This cannot have produced a signaling nan, so we can trim any snan
+        // inputs.
+        if ((DemandedMask & fcSNan) != fcNone)
+          SrcDemandedMask &= ~fcSNan;
+
+        if (Mode != DenormalMode::getIEEE()) {
+          // Any zero results may have come from flushed denormals.
+          if (DemandedMask & fcPosZero)
+            SrcDemandedMask |= fcPosSubnormal;
+          if (DemandedMask & fcNegZero)
+            SrcDemandedMask |= fcNegSubnormal;
+        }
+
+        if (Mode == DenormalMode::getPreserveSign()) {
+          // If a denormal input will be flushed, and we don't need zeros, we
+          // don't need denormals either.
+          if ((DemandedMask & fcPosZero) == fcNone)
+            SrcDemandedMask &= ~fcPosSubnormal;
+
+          if ((DemandedMask & fcNegZero) == fcNone)
+            SrcDemandedMask &= ~fcNegSubnormal;
+        }
+
+        KnownFPClass KnownSrc;
+
+        // Simplify upstream operations before trying to simplify this call.
+        if (SimplifyDemandedFPClass(I, 0, SrcDemandedMask, KnownSrc, Depth + 1))
+          return I;
+
+        Known = KnownSrc;
+
+        // Perform the canonicalization to see if this folded to a constant.
+        Known.canonicalize(Mode);
+
+        if (Constant *SingleVal =
+                getFPClassConstant(VTy, DemandedMask & Known.KnownFPClasses))
+          return SingleVal;
+
+        if (Mode == DenormalMode::getIEEE()) {
+          // For IEEE handling, there is only a bit change for nan inputs, so we
+          // can drop it if we do not demand nan results or we know the input
+          // isn't a nan.
+          if (KnownSrc.isKnownNeverNaN() || (DemandedMask & fcNan) == fcNone)
+            return CI->getArgOperand(0);
+        } else {
+          // Nan handling is the same as the IEEE case, but we also need to
+          // avoid denormal inputs to drop the canonicalize.
+          if ((KnownSrc.isKnownNeverNaN() ||
+               (DemandedMask & fcNan) == fcNone) &&
+              KnownSrc.isKnownNeverSubnormal())
+            return CI->getArgOperand(0);
+        }
+
+        return nullptr;
+      }
+
+      [[fallthrough]];
+    }
     default:
       Known = computeKnownFPClass(I, ~DemandedMask, CxtI, Depth + 1);
       break;
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-canonicalize.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-canonicalize.ll
index 20de837d14367..0c305762d5c36 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-canonicalize.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-canonicalize.ll
@@ -71,8 +71,7 @@ define nofpclass(nan pzero) float @ret_nofpclass_nan_pzero__canonicalize_select_
 ; CHECK-LABEL: define nofpclass(nan pzero) float @ret_nofpclass_nan_pzero__canonicalize_select_psub_daz(
 ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[PSUB:%.*]] = call float @returns_psub()
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[PSUB]]
-; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]])
+; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]])
 ; CHECK-NEXT:    ret float [[CANON]]
 ;
   %psub = call float @returns_psub()
@@ -85,8 +84,7 @@ define nofpclass(nan nzero) float @ret_nofpclass_nan_nzero__canonicalize_select_
 ; CHECK-LABEL: define nofpclass(nan nzero) float @ret_nofpclass_nan_nzero__canonicalize_select_nsub_daz(
 ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[NSUB:%.*]] = call float @returns_nsub()
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[NSUB]]
-; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]])
+; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]])
 ; CHECK-NEXT:    ret float [[CANON]]
 ;
   %nsub = call float @returns_nsub()
@@ -99,8 +97,7 @@ define nofpclass(nan zero) float @ret_nofpclass_nan_zero__canonicalize_select_su
 ; CHECK-LABEL: define nofpclass(nan zero) float @ret_nofpclass_nan_zero__canonicalize_select_sub_daz(
 ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[SUB:%.*]] = call float @returns_sub()
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[SUB]]
-; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]])
+; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]])
 ; CHECK-NEXT:    ret float [[CANON]]
 ;
   %sub = call float @returns_sub()
@@ -112,8 +109,7 @@ define nofpclass(nan zero) float @ret_nofpclass_nan_zero__canonicalize_select_su
 define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_psub_ieee() {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_psub_ieee() {
 ; CHECK-NEXT:    [[PSUB:%.*]] = call float @returns_psub()
-; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[PSUB]])
-; CHECK-NEXT:    ret float [[CANON]]
+; CHECK-NEXT:    ret float [[PSUB]]
 ;
   %psub = call float @returns_psub()
   %canon = call float @llvm.canonicalize.f32(float %psub)
@@ -123,8 +119,7 @@ define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_psub_ieee() {
 define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_nsub_ieee() {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_nsub_ieee() {
 ; CHECK-NEXT:    [[NSUB:%.*]] = call float @returns_nsub()
-; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[NSUB]])
-; CHECK-NEXT:    ret float [[CANON]]
+; CHECK-NEXT:    ret float [[NSUB]]
 ;
   %nsub = call float @returns_nsub()
   %canon = call float @llvm.canonicalize.f32(float %nsub)
@@ -134,8 +129,7 @@ define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_nsub_ieee() {
 define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_sub_ieee() {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_sub_ieee() {
 ; CHECK-NEXT:    [[SUB:%.*]] = call float @returns_sub()
-; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SUB]])
-; CHECK-NEXT:    ret float [[CANON]]
+; CHECK-NEXT:    ret float [[SUB]]
 ;
   %sub = call float @returns_sub()
   %canon = call float @llvm.canonicalize.f32(float %sub)
@@ -146,8 +140,7 @@ define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_psub_daz() #0
 ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_psub_daz(
 ; CHECK-SAME: ) #[[ATTR0]] {
 ; CHECK-NEXT:    [[PSUB:%.*]] = call float @returns_psub()
-; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[PSUB]])
-; CHECK-NEXT:    ret float [[CANON]]
+; CHECK-NEXT:    ret float 0.000000e+00
 ;
   %psub = call float @returns_psub()
   %canon = call float @llvm.canonicalize.f32(float %psub)
@@ -158,8 +151,7 @@ define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_nsub_daz() #0
 ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_nsub_daz(
 ; CHECK-SAME: ) #[[ATTR0]] {
 ; CHECK-NEXT:    [[NSUB:%.*]] = call float @returns_nsub()
-; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[NSUB]])
-; CHECK-NEXT:    ret float [[CANON]]
+; CHECK-NEXT:    ret float -0.000000e+00
 ;
   %nsub = call float @returns_nsub()
   %canon = call float @llvm.canonicalize.f32(float %nsub)
@@ -182,8 +174,7 @@ define nofpclass(zero) <2 x float> @ret_nofpclass_zero__canonicalize_daz_vec(<2
 ; CHECK-LABEL: define nofpclass(zero) <2 x float> @ret_nofpclass_zero__canonicalize_daz_vec(
 ; CHECK-SAME: <2 x float> [[X:%.*]], <2 x i1> [[COND:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[SUB:%.*]] = call <2 x float> @returns_sub_vec()
-; CHECK-NEXT:    [[SELECT:%.*]] = select <2 x i1> [[COND]], <2 x float> [[X]], <2 x float> [[SUB]]
-; CHECK-NEXT:    [[CANON:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> [[SELECT]])
+; CHECK-NEXT:    [[CANON:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> [[X]])
 ; CHECK-NEXT:    ret <2 x float> [[CANON]]
 ;
   %sub = call <2 x float> @returns_sub_vec()
@@ -196,8 +187,7 @@ define nofpclass(zero sub) float @ret_nofpclass_sub_zero__canonicalize_daz(float
 ; CHECK-LABEL: define nofpclass(zero sub) float @ret_nofpclass_sub_zero__canonicalize_daz(
 ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[SUB_OR_ZERO:%.*]] = call float @returns_sub_zero()
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[SUB_OR_ZERO]]
-; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]])
+; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]])
 ; CHECK-NEXT:    ret float [[CANON]]
 ;
   %sub_or_zero = call float @returns_sub_zero()
@@ -209,8 +199,7 @@ define nofpclass(zero sub) float @ret_nofpclass_sub_zero__canonicalize_daz(float
 define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_ieee(float %unknown) {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_ieee(
 ; CHECK-SAME: float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[UNKNOWN]])
-; CHECK-NEXT:    ret float [[CANON]]
+; CHECK-NEXT:    ret float [[UNKNOWN]]
 ;
   %canon = call float @llvm.canonicalize.f32(float %unknown)
   ret float %canon
@@ -310,8 +299,7 @@ define nofpclass(qnan) float @ret_nofpclass_qnan__canonicalize_select_unknown_or
 ; CHECK-LABEL: define nofpclass(qnan) float @ret_nofpclass_qnan__canonicalize_select_unknown_or_snan(
 ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) {
 ; CHECK-NEXT:    [[SNAN:%.*]] = call float @returns_snan()
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[SNAN]]
-; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]])
+; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]])
 ; CHECK-NEXT:    ret float [[CANON]]
 ;
   %snan = call float @returns_snan()
@@ -325,9 +313,7 @@ define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_select_unknown_or_s
 ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_select_unknown_or_snan(
 ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) {
 ; CHECK-NEXT:    [[SNAN:%.*]] = call float @returns_snan()
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[SNAN]]
-; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]])
-; CHECK-NEXT:    ret float [[CANON]]
+; CHECK-NEXT:    ret float [[X]]
 ;
   %snan = call float @returns_snan()
   %select = select i1 %cond, float %x, float %snan
@@ -339,8 +325,7 @@ define nofpclass(zero) float @ret_nofpclass_zero_nnan_flag__canonicalize_select_
 ; CHECK-LABEL: define nofpclass(zero) float @ret_nofpclass_zero_nnan_flag__canonicalize_select_unknown_or_snan(
 ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) {
 ; CHECK-NEXT:    [[SNAN:%.*]] = call float @returns_snan()
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[SNAN]]
-; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]])
+; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]])
 ; CHECK-NEXT:    ret float [[CANON]]
 ;
   %snan = call float @returns_snan()
@@ -356,8 +341,7 @@ define nofpclass(zero) float @ret_nofpclass_zero_nnan_flag__canonicalize_select_
 define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_nnan_src_ieee(float nofpclass(nan) %x, i1 %cond) {
 ; CHECK-LABEL: define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_nnan_src_ieee(
 ; CHECK-SAME: float nofpclass(nan) [[X:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]])
-; CHECK-NEXT:    ret float [[CANON]]
+; CHECK-NEXT:    ret float [[X]]
 ;
   %canon = call float @llvm.canonicalize.f32(float %x)
   ret float %canon
@@ -387,8 +371,7 @@ define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_no_sub_src_daz(fl
 define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_no_sub_no_nan_src_daz(float nofpclass(nan sub) %x, i1 %cond) #0 {
 ; CHECK-LABEL: define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_no_sub_no_nan_src_daz(
 ; CHECK-SAME: float nofpclass(nan sub) [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]])
-; CHECK-NEXT:    ret float [[CANON]]
+; CHECK-NEXT:    ret float [[X]]
 ;
   %canon = call float @llvm.canonicalize.f32(float %x)
   ret float %canon
@@ -397,8 +380,7 @@ define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_no_sub_no_nan_src
 define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_no_sub_no_nan_src_dynamic(float nofpclass(nan sub) %x, i1 %cond) #1 {
 ; CHECK-LABEL: define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_no_sub_no_nan_src_dynamic(
 ; CHECK-SAME: float nofpclass(nan sub) [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]])
-; CHECK-NEXT:    ret float [[CANON]]
+; CHECK-NEXT:    ret float [[X]]
 ;
   %canon = call float @llvm.canonicalize.f32(float %x)
   ret float %canon
@@ -408,8 +390,7 @@ define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_no_sub_no_nan_src
 define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_no_sub_src_daz(float nofpclass(sub) %x, i1 %cond) #0 {
 ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_no_sub_src_daz(
 ; CHECK-SAME: float nofpclass(sub) [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]])
-; CHECK-NEXT:    ret float [[CANON]]
+; CHECK-NEXT:    ret float [[X]]
 ;
   %canon = call float @llvm.canonicalize.f32(float %x)
   ret float %canon
@@ -440,8 +421,7 @@ define nofpclass(snan) float @ret_nofpclass_snan__canonicalize_no_sub_src_daz(fl
 define nofpclass(nan) flo...
[truncated]

Doesn't try to handle PositiveZero flushing mode, but I
don't believe it is incorrect with it.
@arsenm arsenm force-pushed the users/arsenm/instcombine/add-baseline-test-simplify-demanded-fpclass-canonicalize branch from 06ef509 to fa6f411 Compare December 21, 2025 14:07
@arsenm arsenm force-pushed the users/arsenm/instcombine/implement-simplifydemandedfpclass-canonicalize branch from 01cb854 to 9ed4b6d Compare December 21, 2025 14:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

floating-point Floating-point math llvm:analysis Includes value tracking, cost tables and constant folding llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:support llvm:transforms

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants