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

>From b1b84104191ff7cbb97940bba09181004ffd553a Mon Sep 17 00:00:00 2001
From: Matt Arsenault <[email protected]>
Date: Tue, 20 Jan 2026 13:20:09 +0100
Subject: [PATCH] InstCombine: Handle multiple use copysign

Handle multiple use copysign in SimplifyDemandedFPClass
---
 llvm/include/llvm/Support/KnownFPClass.h      |  7 ++++
 .../InstCombineSimplifyDemanded.cpp           | 39 +++++++++++++++++--
 .../InstCombine/simplify-demanded-fpclass.ll  | 14 +++----
 3 files changed, 50 insertions(+), 10 deletions(-)

diff --git a/llvm/include/llvm/Support/KnownFPClass.h 
b/llvm/include/llvm/Support/KnownFPClass.h
index b222bbe7bad9a..2a198552e098a 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -321,6 +321,13 @@ struct KnownFPClass {
       KnownFPClasses &= (fcPositive | fcNan);
   }
 
+  static KnownFPClass copysign(const KnownFPClass &KnownMag,
+                               const KnownFPClass &KnownSign) {
+    KnownFPClass Known = KnownMag;
+    Known.copysign(KnownSign);
+    return Known;
+  }
+
   // Propagate knowledge that a non-NaN source implies the result can also not
   // be a NaN. For unconstrained operations, signaling nans are not guaranteed
   // to be quieted but cannot be introduced.
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp 
b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 8e12a5d2a1112..c3297c1666716 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -2776,7 +2776,9 @@ Value 
*InstCombinerImpl::SimplifyDemandedUseFPClass(Instruction *I,
     case Intrinsic::copysign: {
       // Flip on more potentially demanded classes
       const FPClassTest DemandedMaskAnySign = llvm::unknown_sign(DemandedMask);
-      if (SimplifyDemandedFPClass(I, 0, DemandedMaskAnySign, Known, Depth + 1))
+      KnownFPClass KnownMag;
+      if (SimplifyDemandedFPClass(CI, 0, DemandedMaskAnySign, KnownMag,
+                                  Depth + 1))
         return I;
 
       if ((DemandedMask & fcNegative) == DemandedMask) {
@@ -2792,7 +2794,8 @@ Value 
*InstCombinerImpl::SimplifyDemandedUseFPClass(Instruction *I,
       }
 
       if (Value *Simplified = simplifyDemandedFPClassCopysignMag(
-              CI->getArgOperand(0), DemandedMask, Known, FMF.noSignedZeros()))
+              CI->getArgOperand(0), DemandedMask, KnownMag,
+              FMF.noSignedZeros()))
         return Simplified;
 
       KnownFPClass KnownSign = computeKnownFPClass(CI->getArgOperand(1),
@@ -2819,7 +2822,7 @@ Value 
*InstCombinerImpl::SimplifyDemandedUseFPClass(Instruction *I,
         return I;
       }
 
-      Known.copysign(KnownSign);
+      Known = KnownFPClass::copysign(KnownMag, KnownSign);
       Known.knownNot(~DemandedMask);
       break;
     }
@@ -3433,6 +3436,36 @@ Value 
*InstCombinerImpl::SimplifyMultipleUseDemandedFPClass(
         return Simplified;
       break;
     }
+    case Intrinsic::copysign: {
+      Value *Mag = CI->getArgOperand(0);
+      Value *Sign = CI->getArgOperand(1);
+      KnownFPClass KnownMag =
+          computeKnownFPClass(Mag, fcAllFlags, CxtI, Depth + 1);
+
+      // Rule out some cases by magnitude, which may help prove the sign bit is
+      // one direction or the other.
+      KnownMag.knownNot(~llvm::unknown_sign(DemandedMask));
+
+      // Cannot use nsz in the multiple use case.
+      if (Value *Simplified = simplifyDemandedFPClassCopysignMag(
+              Mag, DemandedMask, KnownMag, /*NSZ=*/false))
+        return Simplified;
+
+      KnownFPClass KnownSign =
+          computeKnownFPClass(Sign, fcAllFlags, CxtI, Depth + 1);
+
+      if (FMF.noInfs())
+        KnownSign.knownNot(fcInf);
+      if (FMF.noNaNs())
+        KnownSign.knownNot(fcNan);
+
+      if (KnownSign.SignBit && KnownMag.SignBit &&
+          *KnownSign.SignBit == *KnownMag.SignBit)
+        return Mag;
+
+      Known = KnownFPClass::copysign(KnownMag, KnownSign);
+      break;
+    }
     case Intrinsic::maximum:
     case Intrinsic::minimum:
     case Intrinsic::maximumnum:
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll 
b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
index 2c96f4fb8b4f2..7bc5fd05a5658 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
@@ -2132,7 +2132,7 @@ define nofpclass(nan ninf nnorm nsub nzero) float 
@ret_only_positive__copysign_s
 ; CHECK-SAME: (float nofpclass(nan ninf nzero nsub nnorm) 
[[ALWAYS_POSITIVE:%.*]], float [[UNKNOWN:%.*]], ptr [[PTR:%.*]]) {
 ; CHECK-NEXT:    [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float 
[[ALWAYS_POSITIVE]], float [[UNKNOWN]])
 ; CHECK-NEXT:    store float [[COPYSIGN]], ptr [[PTR]], align 4
-; CHECK-NEXT:    ret float [[COPYSIGN]]
+; CHECK-NEXT:    ret float [[ALWAYS_POSITIVE]]
 ;
   %copysign = call float @llvm.copysign.f32(float %always.positive, float 
%unknown)
   store float %copysign, ptr %ptr
@@ -2155,7 +2155,7 @@ define nofpclass(nan pinf pnorm psub pzero) float 
@ret_only_negative__copysign_s
 ; CHECK-SAME: (float nofpclass(nan pinf pzero psub pnorm) 
[[ALWAYS_NEGATIVE:%.*]], float [[UNKNOWN:%.*]], ptr [[PTR:%.*]]) {
 ; CHECK-NEXT:    [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float 
[[ALWAYS_NEGATIVE]], float [[UNKNOWN]])
 ; CHECK-NEXT:    store float [[COPYSIGN]], ptr [[PTR]], align 4
-; CHECK-NEXT:    ret float [[COPYSIGN]]
+; CHECK-NEXT:    ret float [[ALWAYS_NEGATIVE]]
 ;
   %copysign = call float @llvm.copysign.f32(float %always.negative, float 
%unknown)
   store float %copysign, ptr %ptr
@@ -2224,7 +2224,7 @@ define nofpclass(nan nnorm nsub nzero) float 
@ret_only_positive_or_ninf__copysig
 ; CHECK-SAME: (float nofpclass(nan ninf nzero nsub nnorm) 
[[ALWAYS_POSITIVE:%.*]], float [[UNKNOWN:%.*]], ptr [[PTR:%.*]]) {
 ; CHECK-NEXT:    [[COPYSIGN:%.*]] = call ninf float @llvm.copysign.f32(float 
[[ALWAYS_POSITIVE]], float [[UNKNOWN]])
 ; CHECK-NEXT:    store float [[COPYSIGN]], ptr [[PTR]], align 4
-; CHECK-NEXT:    ret float [[COPYSIGN]]
+; CHECK-NEXT:    ret float [[ALWAYS_POSITIVE]]
 ;
   %copysign = call ninf float @llvm.copysign.f32(float %always.positive, float 
%unknown)
   store float %copysign, ptr %ptr
@@ -2382,7 +2382,7 @@ define nofpclass(pinf pnorm psub pzero) float 
@ret_only_negative_or_nan__copysig
 ; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) 
[[ALWAYS_NEGATIVE_OR_NAN:%.*]], float [[UNKNOWN:%.*]], ptr [[PTR:%.*]]) {
 ; CHECK-NEXT:    [[COPYSIGN:%.*]] = call nnan float @llvm.copysign.f32(float 
[[ALWAYS_NEGATIVE_OR_NAN]], float [[UNKNOWN]])
 ; CHECK-NEXT:    store float [[COPYSIGN]], ptr [[PTR]], align 4
-; CHECK-NEXT:    ret float [[COPYSIGN]]
+; CHECK-NEXT:    ret float [[ALWAYS_NEGATIVE_OR_NAN]]
 ;
   %copysign = call nnan float @llvm.copysign.f32(float 
%always.negative.or.nan, float %unknown)
   store float %copysign, ptr %ptr
@@ -2451,7 +2451,7 @@ define nofpclass(pinf pnorm psub pzero) float 
@ret_only_positive_or_nan__copysig
 ; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) 
[[ALWAYS_NEGATIVE_OR_NAN:%.*]], float [[UNKNOWN:%.*]], ptr [[PTR:%.*]]) {
 ; CHECK-NEXT:    [[COPYSIGN:%.*]] = call nnan float @llvm.copysign.f32(float 
[[ALWAYS_NEGATIVE_OR_NAN]], float [[UNKNOWN]])
 ; CHECK-NEXT:    store float [[COPYSIGN]], ptr [[PTR]], align 4
-; CHECK-NEXT:    ret float [[COPYSIGN]]
+; CHECK-NEXT:    ret float [[ALWAYS_NEGATIVE_OR_NAN]]
 ;
   %copysign = call nnan float @llvm.copysign.f32(float 
%always.negative.or.nan, float %unknown)
   store float %copysign, ptr %ptr
@@ -2475,7 +2475,7 @@ define nofpclass(nan) float 
@ret_no_nan__copysign_ninf__src_known_negative_or_na
 ; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) 
[[ALWAYS_NEGATIVE_OR_NAN:%.*]], float nofpclass(nan pzero psub pnorm) 
[[ALWAYS_NEGATIVE_OR_PINF:%.*]], ptr [[PTR:%.*]]) {
 ; CHECK-NEXT:    [[COPYSIGN:%.*]] = call ninf float @llvm.copysign.f32(float 
[[ALWAYS_NEGATIVE_OR_NAN]], float [[ALWAYS_NEGATIVE_OR_PINF]])
 ; CHECK-NEXT:    store float [[COPYSIGN]], ptr [[PTR]], align 4
-; CHECK-NEXT:    ret float [[COPYSIGN]]
+; CHECK-NEXT:    ret float [[ALWAYS_NEGATIVE_OR_NAN]]
 ;
   %copysign = call ninf float @llvm.copysign.f32(float 
%always.negative.or.nan, float %always.negative.or.pinf)
   store float %copysign, ptr %ptr
@@ -2499,7 +2499,7 @@ define nofpclass(nan) float 
@ret_no_nan__copysign_ninf__src_known_negative_or_na
 ; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) 
[[ALWAYS_POSITIVE_OR_NAN:%.*]], float nofpclass(nan nzero nsub nnorm) 
[[ALWAYS_NEGATIVE_OR_PINF:%.*]], ptr [[PTR:%.*]]) {
 ; CHECK-NEXT:    [[COPYSIGN:%.*]] = call ninf float @llvm.copysign.f32(float 
[[ALWAYS_POSITIVE_OR_NAN]], float [[ALWAYS_NEGATIVE_OR_PINF]])
 ; CHECK-NEXT:    store float [[COPYSIGN]], ptr [[PTR]], align 4
-; CHECK-NEXT:    ret float [[COPYSIGN]]
+; CHECK-NEXT:    ret float [[ALWAYS_POSITIVE_OR_NAN]]
 ;
   %copysign = call ninf float @llvm.copysign.f32(float 
%always.positive.or.nan, float %always.negative.or.pinf)
   store float %copysign, ptr %ptr

_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to