https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/176917
>From d0144874fc665842e469799678feefe462d8a1f9 Mon Sep 17 00:00:00 2001 From: Matt Arsenault <[email protected]> Date: Tue, 20 Jan 2026 13:20:09 +0100 Subject: [PATCH 1/2] 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 2ce4fcbe34bba..6409a7e44a116 100644 --- a/llvm/include/llvm/Support/KnownFPClass.h +++ b/llvm/include/llvm/Support/KnownFPClass.h @@ -327,6 +327,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 630016fe58a19..5e14c47cf14c5 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp @@ -2775,7 +2775,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) { @@ -2791,7 +2793,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), @@ -2818,7 +2821,7 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Instruction *I, return I; } - Known.copysign(KnownSign); + Known = KnownFPClass::copysign(KnownMag, KnownSign); Known.knownNot(~DemandedMask); break; } @@ -3432,6 +3435,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 7825d380d6e50..1c3ccf734b6a3 100644 --- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll +++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll @@ -2181,7 +2181,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 @@ -2204,7 +2204,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 @@ -2273,7 +2273,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 @@ -2431,7 +2431,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 @@ -2500,7 +2500,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 @@ -2524,7 +2524,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 @@ -2548,7 +2548,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 >From 995b3400e5978fabcd2970fab65b73e90006e93d Mon Sep 17 00:00:00 2001 From: Matt Arsenault <[email protected]> Date: Fri, 30 Jan 2026 14:26:52 +0100 Subject: [PATCH 2/2] Fix using Known as input --- .../Transforms/InstCombine/InstCombineSimplifyDemanded.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp index 5e14c47cf14c5..f6c3198cd6d5e 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp @@ -2799,9 +2799,8 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Instruction *I, KnownFPClass KnownSign = computeKnownFPClass(CI->getArgOperand(1), fcAllFlags, CxtI, Depth + 1); - - if (Known.SignBit && KnownSign.SignBit && - *Known.SignBit == *KnownSign.SignBit) + if (KnownMag.SignBit && KnownSign.SignBit && + *KnownMag.SignBit == *KnownSign.SignBit) return CI->getOperand(0); // TODO: Call argument attribute not considered _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
