[llvm-branch-commits] [llvm] InstCombine: Consider not-inf/nan context when simplifying fmul (PR #174024)
Matt Arsenault via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Dec 30 13:47:18 PST 2025
https://github.com/arsenm created https://github.com/llvm/llvm-project/pull/174024
Consider if the result can be nan, or if the inputs cannot
be infinity from the flag when trying to simplify fmul into
copysign.
>From dd4394b8c5839335e8bfde51f2aed1ffac53f301 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Tue, 30 Dec 2025 21:04:37 +0100
Subject: [PATCH] InstCombine: Consider not-inf/nan context when simplifying
fmul
Consider if the result can be nan, or if the inputs cannot
be infinity from the flag when trying to simplify fmul into
copysign.
---
.../InstCombineSimplifyDemanded.cpp | 24 +++++++++++----
.../simplify-demanded-fpclass-fmul.ll | 30 +++++++++++--------
2 files changed, 36 insertions(+), 18 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 0b5854f169440..73cddec73c45b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -2061,11 +2061,16 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Value *V,
if (!I->hasOneUse())
return nullptr;
+ bool NoInfsFlag = false;
+
if (auto *FPOp = dyn_cast<FPMathOperator>(I)) {
if (FPOp->hasNoNaNs())
DemandedMask &= ~fcNan;
- if (FPOp->hasNoInfs())
+
+ if (FPOp->hasNoInfs()) {
DemandedMask &= ~fcInf;
+ NoInfsFlag = true;
+ }
}
switch (I->getOpcode()) {
case Instruction::FNeg: {
@@ -2355,8 +2360,15 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Value *V,
KnownRHS.knownNot(fcNan);
}
- // TODO: Apply knowledge of no-infinity returns to sources.
- if (KnownLHS.isKnownNeverInfOrNaN() &&
+ if (NoInfsFlag) {
+ // Flag implies inputs cannot be infinity.
+ KnownLHS.knownNot(fcInf);
+ KnownRHS.knownNot(fcInf);
+ }
+
+ bool NonNanResult = (DemandedMask & fcNan) == fcNone;
+
+ if ((NonNanResult || KnownLHS.isKnownNeverInfOrNaN()) &&
KnownRHS.isKnownAlways(fcPosZero | fcNan)) {
// => copysign(+0, lhs)
// Note: Dropping canonicalize
@@ -2366,7 +2378,7 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Value *V,
}
if (KnownLHS.isKnownAlways(fcPosZero | fcNan) &&
- KnownRHS.isKnownNeverInfOrNaN()) {
+ (NonNanResult || KnownRHS.isKnownNeverInfOrNaN())) {
// => copysign(+0, rhs)
// Note: Dropping canonicalize
Value *Copysign = Builder.CreateCopySign(X, Y);
@@ -2374,7 +2386,7 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Value *V,
return Copysign;
}
- if (KnownLHS.isKnownNeverInfOrNaN() &&
+ if ((NonNanResult || KnownLHS.isKnownNeverInfOrNaN()) &&
KnownRHS.isKnownAlways(fcNegZero | fcNan)) {
// => copysign(0, fneg(lhs))
// Note: Dropping canonicalize
@@ -2384,7 +2396,7 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Value *V,
}
if (KnownLHS.isKnownAlways(fcNegZero | fcNan) &&
- KnownRHS.isKnownNeverInfOrNaN()) {
+ (NonNanResult || KnownRHS.isKnownNeverInfOrNaN())) {
// => copysign(+0, fneg(rhs))
// Note: Dropping canonicalize
Value *Copysign = Builder.CreateCopySign(X, Builder.CreateFNegFMF(Y, I));
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll
index cb83fdc3e7a6b..b81a8bc162546 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll
@@ -609,7 +609,7 @@ define nofpclass(nan) float @ret_no_nan_result__known_negative_non0__fmul__known
define nofpclass(inf nan) float @ret_noinf_nonan__known_pzero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float %unknown) {
; CHECK-LABEL: define nofpclass(nan inf) float @ret_noinf_nonan__known_pzero_or_nan__fmul__not_inf_or_nan(
; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN]], 0.000000e+00
+; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[UNKNOWN]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %pzero.or.nan, %unknown
@@ -620,7 +620,7 @@ define nofpclass(inf nan) float @ret_noinf_nonan__known_pzero_or_nan__fmul__not_
define nofpclass(inf nan) float @ret_noinf_nonan__not_inf_or_nan__fmul__known_pzero_or_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float %unknown) {
; CHECK-LABEL: define nofpclass(nan inf) float @ret_noinf_nonan__not_inf_or_nan__fmul__known_pzero_or_nan(
; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[UNKNOWN]], 0.000000e+00
+; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[UNKNOWN]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %pzero.or.nan, %unknown
@@ -869,7 +869,7 @@ define nofpclass(nan) float @ret_no_nan__fmul_pzero__unknown(float %unknown) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_pzero__unknown(
; CHECK-SAME: float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[PZERO:%.*]] = call float @returns_pzero()
-; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[UNKNOWN]], 0.000000e+00
+; CHECK-NEXT: [[FMUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[UNKNOWN]])
; CHECK-NEXT: ret float [[FMUL]]
;
%pzero = call float @returns_pzero()
@@ -881,7 +881,7 @@ define nofpclass(nan) float @ret_no_nan__fmul_unknown__pzero(float %unknown) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_unknown__pzero(
; CHECK-SAME: float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[PZERO:%.*]] = call float @returns_pzero()
-; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[UNKNOWN]], 0.000000e+00
+; CHECK-NEXT: [[FMUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[UNKNOWN]])
; CHECK-NEXT: ret float [[FMUL]]
;
%pzero = call float @returns_pzero()
@@ -893,7 +893,8 @@ define nofpclass(nan) float @ret_no_nan__fmul_nzero__unknown(float %unknown) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_nzero__unknown(
; CHECK-SAME: float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[NZERO:%.*]] = call float @returns_nzero()
-; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[UNKNOWN]], -0.000000e+00
+; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[UNKNOWN]]
+; CHECK-NEXT: [[FMUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]])
; CHECK-NEXT: ret float [[FMUL]]
;
%nzero = call float @returns_nzero()
@@ -905,7 +906,8 @@ define nofpclass(nan) float @ret_no_nan__fmul_unknown__nzero(float %unknown) {
; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_unknown__nzero(
; CHECK-SAME: float [[UNKNOWN:%.*]]) {
; CHECK-NEXT: [[NZERO:%.*]] = call float @returns_nzero()
-; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[UNKNOWN]], -0.000000e+00
+; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[UNKNOWN]]
+; CHECK-NEXT: [[FMUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]])
; CHECK-NEXT: ret float [[FMUL]]
;
%nzero = call float @returns_nzero()
@@ -1031,7 +1033,8 @@ define nofpclass(inf) float @ret_noinf__not_inf_or_nan__fmul__nzero_or_nan(float
define nofpclass(nan) float @ret_nonan__nzero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm pzero) %nzero.or.nan, float nofpclass(nan) %not.nan) {
; CHECK-LABEL: define nofpclass(nan) float @ret_nonan__nzero_or_nan__fmul__not_inf_or_nan(
; CHECK-SAME: float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NOT_NAN]], -0.000000e+00
+; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[NOT_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %nzero.or.nan, %not.nan
@@ -1042,7 +1045,8 @@ define nofpclass(nan) float @ret_nonan__nzero_or_nan__fmul__not_inf_or_nan(float
define nofpclass(nan) float @ret_nonan__not_inf_or_nan__fmul__nzero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(inf sub norm pzero) %nzero.or.nan) {
; CHECK-LABEL: define nofpclass(nan) float @ret_nonan__not_inf_or_nan__fmul__nzero_or_nan(
; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NOT_NAN]], -0.000000e+00
+; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[NOT_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul float %not.nan, %nzero.or.nan
@@ -1053,7 +1057,8 @@ define nofpclass(nan) float @ret_nonan__not_inf_or_nan__fmul__nzero_or_nan(float
define nofpclass(snan) float @ret__nzero_or_nan__fmul_ninf__not_inf_or_nan(float nofpclass(inf sub norm pzero) %nzero.or.nan, float nofpclass(nan) %not.nan) {
; CHECK-LABEL: define nofpclass(snan) float @ret__nzero_or_nan__fmul_ninf__not_inf_or_nan(
; CHECK-SAME: float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul ninf float [[NZERO_OR_NAN]], [[NOT_NAN]]
+; CHECK-NEXT: [[TMP1:%.*]] = fneg ninf float [[NOT_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float [[NZERO_OR_NAN]], float [[TMP1]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul ninf float %nzero.or.nan, %not.nan
@@ -1064,7 +1069,8 @@ define nofpclass(snan) float @ret__nzero_or_nan__fmul_ninf__not_inf_or_nan(float
define nofpclass(snan) float @ret_not_inf_or_nan__fmul_ninf__nzero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(inf sub norm pzero) %nzero.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @ret_not_inf_or_nan__fmul_ninf__nzero_or_nan(
; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul ninf float [[NOT_NAN]], [[NZERO_OR_NAN]]
+; CHECK-NEXT: [[TMP1:%.*]] = fneg ninf float [[NOT_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float [[NZERO_OR_NAN]], float [[TMP1]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul ninf float %not.nan, %nzero.or.nan
@@ -1187,7 +1193,7 @@ define nofpclass(inf) float @ret_noinf__not_inf_or_nan__fmul__pzero_or_nan(float
define nofpclass(snan) float @ret__pzero_or_nan__fmul_ninf__not_inf_or_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float nofpclass(nan) %not.nan) {
; CHECK-LABEL: define nofpclass(snan) float @ret__pzero_or_nan__fmul_ninf__not_inf_or_nan(
; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul ninf float [[PZERO_OR_NAN]], [[NOT_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float [[PZERO_OR_NAN]], float [[NOT_NAN]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul ninf float %pzero.or.nan, %not.nan
@@ -1198,7 +1204,7 @@ define nofpclass(snan) float @ret__pzero_or_nan__fmul_ninf__not_inf_or_nan(float
define nofpclass(snan) float @ret_not_inf_or_nan__fmul_ninf__pzero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(inf sub norm nzero) %pzero.or.nan) {
; CHECK-LABEL: define nofpclass(snan) float @ret_not_inf_or_nan__fmul_ninf__pzero_or_nan(
; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[MUL:%.*]] = fmul ninf float [[NOT_NAN]], [[PZERO_OR_NAN]]
+; CHECK-NEXT: [[MUL:%.*]] = call float @llvm.copysign.f32(float [[PZERO_OR_NAN]], float [[NOT_NAN]])
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul ninf float %not.nan, %pzero.or.nan
More information about the llvm-branch-commits
mailing list