[llvm] [KnownFPClass] Fix KnownFPClass::frem subnormal handling and improve deductions. (PR #219303)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 27 18:49:15 PDT 2026
https://github.com/ZERICO2005 updated https://github.com/llvm/llvm-project/pull/219303
>From 97d11b9beba35dd35ee8a8537ba4073def8d7f93 Mon Sep 17 00:00:00 2001
From: zerico <zerico2005 at gmail.com>
Date: Thu, 27 Aug 2026 00:49:26 -0600
Subject: [PATCH] [KnownFPClass] Fix KnownFPClass::frem subnormal handling and
improve deductions
---
llvm/lib/Analysis/ValueTracking.cpp | 62 +--
.../CodeGen/GlobalISel/GISelValueTracking.cpp | 61 +--
llvm/lib/Support/KnownFPClass.cpp | 46 +-
.../Transforms/Attributor/nofpclass-frem.ll | 424 ++++++++++++++++--
llvm/unittests/Analysis/ValueTrackingTest.cpp | 17 +
.../CodeGen/GlobalISel/KnownFPClassTest.cpp | 4 +-
6 files changed, 506 insertions(+), 108 deletions(-)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index e028768f3a487..114b12ab0920d 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5977,9 +5977,29 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
break;
}
case Instruction::FRem: {
- const bool WantNan = (InterestedClasses & fcNan) != fcNone;
+ FPClassTest InterestedLHS = fcNone;
+ FPClassTest InterestedRHS = fcNone;
+
+ // NaN is also generated for frem(Inf, x) and frem(x, 0.0).
+ if (InterestedClasses & fcNan) {
+ InterestedLHS |= fcNan | fcInf;
+ InterestedRHS |= fcNan | fcZero | fcSubnormal;
+ }
+
+ // The sign for frem is the same as the first operand.
+ if (InterestedClasses & (fcPosNormal | fcPosSubnormal))
+ InterestedLHS |= fcPosNormal | fcPosSubnormal;
+ if (InterestedClasses & (fcNegNormal | fcNegSubnormal))
+ InterestedLHS |= fcNegNormal | fcNegSubnormal;
- Known.knownNot(fcInf);
+ // A negative zero result requires a negative finite first operand.
+ if (InterestedClasses & fcNegZero)
+ InterestedLHS |= fcNegFinite;
+
+ // A positive zero result can additionally come from a negative finite
+ // result being flushed to positive zero.
+ if (InterestedClasses & fcPosZero)
+ InterestedLHS |= fcPosFinite | fcNegNormal | fcNegSubnormal;
const Function *F = cast<Instruction>(Op)->getFunction();
DenormalMode Mode =
@@ -5990,37 +6010,25 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
if (Op->getOperand(0) == Op->getOperand(1) &&
isGuaranteedNotToBeUndef(Op->getOperand(0), Q.AC, Q.CxtI, Q.DT)) {
// X % X is always exactly [+-]0.0 or a NaN.
- Known.KnownFPClasses = fcNan | fcZero;
-
- if (!WantNan)
- break;
-
+ FPClassTest InterestedSrcs = InterestedLHS | InterestedRHS;
KnownFPClass KnownSrc;
- computeKnownFPClass(Op->getOperand(0), DemandedElts,
- fcNan | fcInf | fcZero | fcSubnormal, KnownSrc, Q,
- Depth + 1);
-
+ if (InterestedSrcs != fcNone)
+ computeKnownFPClass(Op->getOperand(0), DemandedElts, InterestedSrcs,
+ KnownSrc, Q, Depth + 1);
Known = KnownFPClass::frem_self(KnownSrc, Mode);
break;
}
- const bool WantNegative = (InterestedClasses & fcNegative) != fcNone;
- const bool WantPositive = (InterestedClasses & fcPositive) != fcNone;
- if (!WantNan && !WantNegative && !WantPositive)
- break;
-
- KnownFPClass KnownLHS, KnownRHS;
- computeKnownFPClass(Op->getOperand(1), DemandedElts,
- fcNan | fcInf | fcZero | fcNegative, KnownRHS, Q,
- Depth + 1);
-
- bool KnowSomethingUseful = KnownRHS.isKnownNeverNaN() ||
- KnownRHS.isKnownNever(fcNegative) ||
- KnownRHS.isKnownNever(fcPositive);
+ KnownFPClass KnownLHS;
+ if (InterestedLHS != fcNone)
+ computeKnownFPClass(Op->getOperand(0), DemandedElts, InterestedLHS,
+ KnownLHS, Q, Depth + 1);
- if (KnowSomethingUseful || WantPositive)
- computeKnownFPClass(Op->getOperand(0), DemandedElts, fcAllFlags, KnownLHS,
- Q, Depth + 1);
+ KnownFPClass KnownRHS;
+ // RHS is only useful for refining NaN classes.
+ if (InterestedRHS != fcNone && KnownLHS.isKnownNever(fcSNan))
+ computeKnownFPClass(Op->getOperand(1), DemandedElts, InterestedRHS,
+ KnownRHS, Q, Depth + 1);
Known = KnownFPClass::frem(KnownLHS, KnownRHS, Mode);
diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index 8dbb0c5f04ee2..c977e19f04d1f 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -1863,46 +1863,57 @@ void GISelValueTracking::computeKnownFPClass(Register R,
break;
}
case TargetOpcode::G_FREM: {
- const bool WantNan = (InterestedClasses & fcNan) != fcNone;
+ FPClassTest InterestedLHS = fcNone;
+ FPClassTest InterestedRHS = fcNone;
+
+ // NaN is also generated for frem(Inf, x) and frem(x, 0.0).
+ if (InterestedClasses & fcNan) {
+ InterestedLHS |= fcNan | fcInf;
+ InterestedRHS |= fcNan | fcZero | fcSubnormal;
+ }
+
+ // The sign for frem is the same as the first operand.
+ if (InterestedClasses & (fcPosNormal | fcPosSubnormal))
+ InterestedLHS |= fcPosNormal | fcPosSubnormal;
+ if (InterestedClasses & (fcNegNormal | fcNegSubnormal))
+ InterestedLHS |= fcNegNormal | fcNegSubnormal;
+
+ // A negative zero result requires a negative finite first operand.
+ if (InterestedClasses & fcNegZero)
+ InterestedLHS |= fcNegFinite;
+
+ // A positive zero result can additionally come from a negative finite
+ // result being flushed to positive zero.
+ if (InterestedClasses & fcPosZero)
+ InterestedLHS |= fcPosFinite | fcNegNormal | fcNegSubnormal;
Register LHS = MI.getOperand(1).getReg();
Register RHS = MI.getOperand(2).getReg();
- Known.knownNot(fcInf);
-
DenormalMode Mode =
MF->getDenormalMode(getFltSemanticForLLT(DstTy.getScalarType()));
if (LHS == RHS && isGuaranteedNotToBeUndef(LHS, MRI, Depth + 1)) {
// X % X is always exactly [+-]0.0 or a NaN.
- Known.KnownFPClasses = fcZero | fcNan;
-
- if (!WantNan)
- break;
-
+ FPClassTest InterestedSrcs = InterestedLHS | InterestedRHS;
KnownFPClass KnownSrc;
- computeKnownFPClass(LHS, DemandedElts,
- fcNan | fcInf | fcZero | fcSubnormal, KnownSrc,
- Depth + 1);
+ if (InterestedSrcs != fcNone)
+ computeKnownFPClass(LHS, DemandedElts, InterestedSrcs, KnownSrc,
+ Depth + 1);
Known = KnownFPClass::frem_self(KnownSrc, Mode);
break;
}
- const bool WantNegative = (InterestedClasses & fcNegative) != fcNone;
- const bool WantPositive = (InterestedClasses & fcPositive) != fcNone;
- if (!WantNan && !WantNegative && !WantPositive)
- break;
-
- KnownFPClass KnownLHS, KnownRHS;
- computeKnownFPClass(RHS, DemandedElts, fcNan | fcInf | fcZero | fcNegative,
- KnownRHS, Depth + 1);
-
- bool KnowSomethingUseful = KnownRHS.isKnownNeverNaN() ||
- KnownRHS.isKnownNever(fcNegative) ||
- KnownRHS.isKnownNever(fcPositive);
+ KnownFPClass KnownLHS;
+ if (InterestedLHS != fcNone)
+ computeKnownFPClass(LHS, DemandedElts, InterestedLHS, KnownLHS,
+ Depth + 1);
- if (KnowSomethingUseful || WantPositive)
- computeKnownFPClass(LHS, DemandedElts, fcAllFlags, KnownLHS, Depth + 1);
+ KnownFPClass KnownRHS;
+ // RHS is only useful for refining NaN classes.
+ if (InterestedRHS != fcNone && KnownLHS.isKnownNever(fcSNan))
+ computeKnownFPClass(RHS, DemandedElts, InterestedRHS, KnownRHS,
+ Depth + 1);
Known = KnownFPClass::frem(KnownLHS, KnownRHS, Mode);
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 09bb9c5538a34..4bfb2f6e64c58 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -508,26 +508,36 @@ KnownFPClass KnownFPClass::frem(const KnownFPClass &KnownLHS,
DenormalMode Mode) {
KnownFPClass Known;
+ // We are assuming that frem(x, Inf) is already handled elsewhere.
+
Known.knownNot(fcInf);
- // Inf REM x and x REM 0 produce NaN.
- if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() &&
- KnownLHS.isKnownNeverInfinity() &&
+ Known.propagateNonSNaN(KnownLHS, KnownRHS);
+
+ // frem(Inf, x) and frem(x, 0) produce NaN.
+ if (KnownLHS.isKnownNeverInfOrNaN() && KnownRHS.isKnownNeverNaN() &&
KnownRHS.isKnownNeverLogicalZero(Mode)) {
Known.knownNot(fcNan);
}
// The sign for frem is the same as the first operand.
- if (KnownLHS.cannotBeOrderedLessThanZero())
- Known.knownNot(KnownFPClass::OrderedLessThanZeroMask);
- if (KnownLHS.cannotBeOrderedGreaterThanZero())
- Known.knownNot(KnownFPClass::OrderedGreaterThanZeroMask);
+ if (KnownLHS.isKnownNever(fcPosNormal | fcPosSubnormal))
+ Known.knownNot(fcPosNormal | fcPosSubnormal);
+ if (KnownLHS.isKnownNever(fcNegNormal | fcNegSubnormal))
+ Known.knownNot(fcNegNormal | fcNegSubnormal);
- // See if we can be more aggressive about the sign of 0.
- if (KnownLHS.isKnownNever(fcNegative))
- Known.knownNot(fcNegative);
- if (KnownLHS.isKnownNever(fcPositive))
- Known.knownNot(fcPositive);
+ // A negative zero result requires a negative finite first operand.
+ if (KnownLHS.isKnownNever(fcNegFinite))
+ Known.knownNot(fcNegZero);
+
+ // A positive zero result can additionally come from a negative finite
+ // result being flushed to positive zero.
+ if (KnownLHS.isKnownNever(fcPosFinite) &&
+ (!Mode.inputsMayBePositiveZero() ||
+ KnownLHS.isKnownNever(fcNegSubnormal)) &&
+ (!Mode.outputsMayBePositiveZero() ||
+ KnownLHS.isKnownNever(fcNegNormal | fcNegSubnormal)))
+ Known.knownNot(fcPosZero);
return Known;
}
@@ -537,10 +547,18 @@ KnownFPClass KnownFPClass::frem_self(const KnownFPClass &KnownSrc,
// X % X is always exactly [+-]0.0 or a NaN.
KnownFPClass Known(fcNan | fcZero);
+ Known.propagateNonSNaN(KnownSrc);
+
if (KnownSrc.isKnownNeverInfOrNaN() && KnownSrc.isKnownNeverLogicalZero(Mode))
Known.knownNot(fcNan);
- else if (KnownSrc.isKnownNever(fcSNan))
- Known.knownNot(fcSNan);
+
+ // The sign of a zero result is the sign of the finite non-zero input.
+ // We do not have to worry about subnormal values flushing to zero, since
+ // frem(+-0.0, +-0.0) = NaN.
+ if (KnownSrc.isKnownNever(fcPosNormal | fcPosSubnormal))
+ Known.knownNot(fcPosZero);
+ if (KnownSrc.isKnownNever(fcNegNormal | fcNegSubnormal))
+ Known.knownNot(fcNegZero);
return Known;
}
diff --git a/llvm/test/Transforms/Attributor/nofpclass-frem.ll b/llvm/test/Transforms/Attributor/nofpclass-frem.ll
index aab6113eab5c9..67391e22511c3 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-frem.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-frem.ll
@@ -52,7 +52,7 @@ define float @ret_frem_ieee_all__nonan_noinf_nozero(float %arg0, float nofpclass
}
define float @ret_frem_ieee_nonan_noinf_nozero__nonan(float nofpclass(nan inf zero) %arg0, float nofpclass(nan) %arg1) #0 {
-; CHECK-LABEL: define nofpclass(inf) float @ret_frem_ieee_nonan_noinf_nozero__nonan
+; CHECK-LABEL: define nofpclass(snan inf) float @ret_frem_ieee_nonan_noinf_nozero__nonan
; CHECK-SAME: (float nofpclass(nan inf zero) [[ARG0:%.*]], float nofpclass(nan) [[ARG1:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -62,7 +62,7 @@ define float @ret_frem_ieee_nonan_noinf_nozero__nonan(float nofpclass(nan inf ze
}
define float @ret_frem_ieee_nonan__nonan_noinf_nozero(float nofpclass(nan) %arg0, float nofpclass(nan inf zero) %arg1) #0 {
-; CHECK-LABEL: define nofpclass(inf) float @ret_frem_ieee_nonan__nonan_noinf_nozero
+; CHECK-LABEL: define nofpclass(snan inf) float @ret_frem_ieee_nonan__nonan_noinf_nozero
; CHECK-SAME: (float nofpclass(nan) [[ARG0:%.*]], float nofpclass(nan inf zero) [[ARG1:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -72,7 +72,7 @@ define float @ret_frem_ieee_nonan__nonan_noinf_nozero(float nofpclass(nan) %arg0
}
define float @ret_frem_ieee_nonan_nozero__nonan_noinf(float nofpclass(nan zero) %arg0, float nofpclass(nan inf) %arg1) #0 {
-; CHECK-LABEL: define nofpclass(inf) float @ret_frem_ieee_nonan_nozero__nonan_noinf
+; CHECK-LABEL: define nofpclass(snan inf) float @ret_frem_ieee_nonan_nozero__nonan_noinf
; CHECK-SAME: (float nofpclass(nan zero) [[ARG0:%.*]], float nofpclass(nan inf) [[ARG1:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -92,7 +92,7 @@ define float @ret_frem_ieee_nonan_noinf__nonan_nozero(float nofpclass(nan inf) %
}
define float @ret_frem_daz_nonan_nozero__nonan_noinf(float nofpclass(nan zero) %arg0, float nofpclass(nan inf) %arg1) #1 {
-; CHECK-LABEL: define nofpclass(inf) float @ret_frem_daz_nonan_nozero__nonan_noinf
+; CHECK-LABEL: define nofpclass(snan inf) float @ret_frem_daz_nonan_nozero__nonan_noinf
; CHECK-SAME: (float nofpclass(nan zero) [[ARG0:%.*]], float nofpclass(nan inf) [[ARG1:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -102,7 +102,7 @@ define float @ret_frem_daz_nonan_nozero__nonan_noinf(float nofpclass(nan zero) %
}
define float @ret_frem_daz_nonan_noinf__nonan_nozero(float nofpclass(nan inf) %arg0, float nofpclass(nan zero) %arg1) #1 {
-; CHECK-LABEL: define nofpclass(inf) float @ret_frem_daz_nonan_noinf__nonan_nozero
+; CHECK-LABEL: define nofpclass(snan inf) float @ret_frem_daz_nonan_noinf__nonan_nozero
; CHECK-SAME: (float nofpclass(nan inf) [[ARG0:%.*]], float nofpclass(nan zero) [[ARG1:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -112,7 +112,7 @@ define float @ret_frem_daz_nonan_noinf__nonan_nozero(float nofpclass(nan inf) %a
}
define float @ret_frem_daz_nonan_nozero_nosub__nonan_noinf(float nofpclass(nan zero sub) %arg0, float nofpclass(nan inf) %arg1) #1 {
-; CHECK-LABEL: define nofpclass(inf) float @ret_frem_daz_nonan_nozero_nosub__nonan_noinf
+; CHECK-LABEL: define nofpclass(snan inf) float @ret_frem_daz_nonan_nozero_nosub__nonan_noinf
; CHECK-SAME: (float nofpclass(nan zero sub) [[ARG0:%.*]], float nofpclass(nan inf) [[ARG1:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -132,7 +132,7 @@ define float @ret_frem_daz_nonan_noinf__nonan_nozero_nosub(float nofpclass(nan i
}
define float @ret_frem_ieee_nonan_noinf__nonan_noinf(float nofpclass(nan) %arg0, float nofpclass(nan) %arg1) #0 {
-; CHECK-LABEL: define nofpclass(inf) float @ret_frem_ieee_nonan_noinf__nonan_noinf
+; CHECK-LABEL: define nofpclass(snan inf) float @ret_frem_ieee_nonan_noinf__nonan_noinf
; CHECK-SAME: (float nofpclass(nan) [[ARG0:%.*]], float nofpclass(nan) [[ARG1:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -152,7 +152,7 @@ define float @ret_frem_ieee_nonan_noinf_nozero__nonan_noinf_nozero(float nofpcla
}
define float @ret_frem_daz_nonan_noinf_nozero__nonan_noinf_nozero(float nofpclass(nan inf zero) %arg0, float nofpclass(nan inf zero) %arg1) #1 {
-; CHECK-LABEL: define nofpclass(inf) float @ret_frem_daz_nonan_noinf_nozero__nonan_noinf_nozero
+; CHECK-LABEL: define nofpclass(snan inf) float @ret_frem_daz_nonan_noinf_nozero__nonan_noinf_nozero
; CHECK-SAME: (float nofpclass(nan inf zero) [[ARG0:%.*]], float nofpclass(nan inf zero) [[ARG1:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -162,7 +162,7 @@ define float @ret_frem_daz_nonan_noinf_nozero__nonan_noinf_nozero(float nofpclas
}
define float @ret_frem_dapz_nonan_noinf_nozero__nonan_noinf_nozero(float nofpclass(nan inf zero) %arg0, float nofpclass(nan inf zero) %arg1) #2 {
-; CHECK-LABEL: define nofpclass(inf) float @ret_frem_dapz_nonan_noinf_nozero__nonan_noinf_nozero
+; CHECK-LABEL: define nofpclass(snan inf) float @ret_frem_dapz_nonan_noinf_nozero__nonan_noinf_nozero
; CHECK-SAME: (float nofpclass(nan inf zero) [[ARG0:%.*]], float nofpclass(nan inf zero) [[ARG1:%.*]]) #[[ATTR2:[0-9]+]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -172,7 +172,7 @@ define float @ret_frem_dapz_nonan_noinf_nozero__nonan_noinf_nozero(float nofpcla
}
define float @ret_frem_dynamic_nonan_noinf_nozero__nonan_noinf_nozero(float nofpclass(nan inf zero) %arg0, float nofpclass(nan inf zero) %arg1) #3 {
-; CHECK-LABEL: define nofpclass(inf) float @ret_frem_dynamic_nonan_noinf_nozero__nonan_noinf_nozero
+; CHECK-LABEL: define nofpclass(snan inf) float @ret_frem_dynamic_nonan_noinf_nozero__nonan_noinf_nozero
; CHECK-SAME: (float nofpclass(nan inf zero) [[ARG0:%.*]], float nofpclass(nan inf zero) [[ARG1:%.*]]) #[[ATTR3:[0-9]+]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -182,7 +182,7 @@ define float @ret_frem_dynamic_nonan_noinf_nozero__nonan_noinf_nozero(float nofp
}
define float @ret_frem_ieee_nonan_noinf_noinf__nonan_noinf_noinf(float nofpclass(nan inf) %arg0, float nofpclass(nan inf) %arg1) #0 {
-; CHECK-LABEL: define nofpclass(inf) float @ret_frem_ieee_nonan_noinf_noinf__nonan_noinf_noinf
+; CHECK-LABEL: define nofpclass(snan inf) float @ret_frem_ieee_nonan_noinf_noinf__nonan_noinf_noinf
; CHECK-SAME: (float nofpclass(nan inf) [[ARG0:%.*]], float nofpclass(nan inf) [[ARG1:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -192,7 +192,7 @@ define float @ret_frem_ieee_nonan_noinf_noinf__nonan_noinf_noinf(float nofpclass
}
define float @ret_frem_ieee_nonan_noinf_nozero__nonan_noinf_noinf(float nofpclass(nan inf zero) %arg0, float nofpclass(nan inf) %arg1) #0 {
-; CHECK-LABEL: define nofpclass(inf) float @ret_frem_ieee_nonan_noinf_nozero__nonan_noinf_noinf
+; CHECK-LABEL: define nofpclass(snan inf) float @ret_frem_ieee_nonan_noinf_nozero__nonan_noinf_noinf
; CHECK-SAME: (float nofpclass(nan inf zero) [[ARG0:%.*]], float nofpclass(nan inf) [[ARG1:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -212,7 +212,7 @@ define float @ret_frem_ieee_nonan_noinf_noinf__nonan_noinf_nozero(float nofpclas
}
define float @ret_frem_ieee_nonan_noinf_noinf__nonan_noinf_noposzero(float nofpclass(nan inf) %arg0, float nofpclass(nan pzero) %arg1) #0 {
-; CHECK-LABEL: define nofpclass(inf) float @ret_frem_ieee_nonan_noinf_noinf__nonan_noinf_noposzero
+; CHECK-LABEL: define nofpclass(snan inf) float @ret_frem_ieee_nonan_noinf_noinf__nonan_noinf_noposzero
; CHECK-SAME: (float nofpclass(nan inf) [[ARG0:%.*]], float nofpclass(nan pzero) [[ARG1:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -222,7 +222,7 @@ define float @ret_frem_ieee_nonan_noinf_noinf__nonan_noinf_noposzero(float nofpc
}
define float @ret_frem_ieee_nonan_noinf_noposzero__nonan_noinf_noinf(float nofpclass(nan pzero) %arg0, float nofpclass(nan inf) %arg1) #0 {
-; CHECK-LABEL: define nofpclass(inf) float @ret_frem_ieee_nonan_noinf_noposzero__nonan_noinf_noinf
+; CHECK-LABEL: define nofpclass(snan inf) float @ret_frem_ieee_nonan_noinf_noposzero__nonan_noinf_noinf
; CHECK-SAME: (float nofpclass(nan pzero) [[ARG0:%.*]], float nofpclass(nan inf) [[ARG1:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -285,7 +285,7 @@ define float @ret_frem_daz_nonan_noinf_nozero__nonan_noinf_nozero_nosub(float no
; Missing no-subnormal on lhs
define float @ret_frem_daz_nonan_noinf_nozero_nosub__nonan_noinf_nozero(float nofpclass(nan inf zero sub) %arg0, float nofpclass(nan inf zero) %arg1) #1 {
-; CHECK-LABEL: define nofpclass(inf) float @ret_frem_daz_nonan_noinf_nozero_nosub__nonan_noinf_nozero
+; CHECK-LABEL: define nofpclass(snan inf) float @ret_frem_daz_nonan_noinf_nozero_nosub__nonan_noinf_nozero
; CHECK-SAME: (float nofpclass(nan inf zero sub) [[ARG0:%.*]], float nofpclass(nan inf zero) [[ARG1:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -719,7 +719,7 @@ define float @ret_frem_f32_known_nzero_rhs(float %arg0, float nofpclass(nan inf
}
define float @ret_frem_f32_known_inf_or_nan_lhs(float nofpclass(zero norm sub) %arg0, float %arg1) {
-; CHECK-LABEL: define nofpclass(inf) float @ret_frem_f32_known_inf_or_nan_lhs
+; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_frem_f32_known_inf_or_nan_lhs
; CHECK-SAME: (float nofpclass(zero sub norm) [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -739,7 +739,7 @@ define float @ret_frem_f32_known_inf_or_nan_rhs(float %arg0, float nofpclass(zer
}
define float @ret_frem_f32_known_inf_lhs(float nofpclass(nan zero norm sub) %arg0, float %arg1) {
-; CHECK-LABEL: define nofpclass(inf) float @ret_frem_f32_known_inf_lhs
+; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_frem_f32_known_inf_lhs
; CHECK-SAME: (float nofpclass(nan zero sub norm) [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -759,7 +759,7 @@ define float @ret_frem_f32_known_inf_rhs(float %arg0, float nofpclass(nan zero n
}
define float @ret_frem_f32_known_pinf_or_nan_lhs(float nofpclass(ninf zero norm sub) %arg0, float %arg1) {
-; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_frem_f32_known_pinf_or_nan_lhs
+; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_frem_f32_known_pinf_or_nan_lhs
; CHECK-SAME: (float nofpclass(ninf zero sub norm) [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -779,7 +779,7 @@ define float @ret_frem_f32_known_pinf_or_nan_rhs(float %arg0, float nofpclass(ni
}
define float @ret_frem_f32_known_ninf_or_nan_lhs(float nofpclass(pinf zero norm sub) %arg0, float %arg1) {
-; CHECK-LABEL: define nofpclass(inf pzero psub pnorm) float @ret_frem_f32_known_ninf_or_nan_lhs
+; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_frem_f32_known_ninf_or_nan_lhs
; CHECK-SAME: (float nofpclass(pinf zero sub norm) [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -800,7 +800,7 @@ define float @ret_frem_f32_known_ninf_or_nan_rhs(float %arg0, float nofpclass(pi
; -> nan
define float @ret_known_inf_frem_known_zero(float nofpclass(nan norm sub zero) %arg0, float nofpclass(nan inf norm sub) %arg1) {
-; CHECK-LABEL: define nofpclass(inf) float @ret_known_inf_frem_known_zero
+; CHECK-LABEL: define nofpclass(snan inf zero sub norm) float @ret_known_inf_frem_known_zero
; CHECK-SAME: (float nofpclass(nan zero sub norm) [[ARG0:%.*]], float nofpclass(nan inf sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -811,7 +811,7 @@ define float @ret_known_inf_frem_known_zero(float nofpclass(nan norm sub zero) %
; -> nan
define float @ret_known_inf_or_nan_frem_known_zero(float nofpclass(norm sub zero) %arg0, float nofpclass(nan inf norm sub) %arg1) {
-; CHECK-LABEL: define nofpclass(inf) float @ret_known_inf_or_nan_frem_known_zero
+; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_known_inf_or_nan_frem_known_zero
; CHECK-SAME: (float nofpclass(zero sub norm) [[ARG0:%.*]], float nofpclass(nan inf sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -822,7 +822,7 @@ define float @ret_known_inf_or_nan_frem_known_zero(float nofpclass(norm sub zero
; -> nan
define float @ret_known_inf_frem_known_zero_or_nan(float nofpclass(nan norm sub zero) %arg0, float nofpclass(inf norm sub) %arg1) {
-; CHECK-LABEL: define nofpclass(inf) float @ret_known_inf_frem_known_zero_or_nan
+; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_known_inf_frem_known_zero_or_nan
; CHECK-SAME: (float nofpclass(nan zero sub norm) [[ARG0:%.*]], float nofpclass(inf sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -833,7 +833,7 @@ define float @ret_known_inf_frem_known_zero_or_nan(float nofpclass(nan norm sub
; -> nan
define float @ret_known_ninf_frem_known_zero(float nofpclass(nan pinf norm sub zero) %arg0, float nofpclass(nan inf norm sub) %arg1) {
-; CHECK-LABEL: define nofpclass(inf pzero psub pnorm) float @ret_known_ninf_frem_known_zero
+; CHECK-LABEL: define nofpclass(snan inf zero sub norm) float @ret_known_ninf_frem_known_zero
; CHECK-SAME: (float nofpclass(nan pinf zero sub norm) [[ARG0:%.*]], float nofpclass(nan inf sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -844,7 +844,7 @@ define float @ret_known_ninf_frem_known_zero(float nofpclass(nan pinf norm sub z
; -> nan
define float @ret_known_pinf_frem_known_zero(float nofpclass(nan ninf norm sub zero) %arg0, float nofpclass(nan inf norm sub) %arg1) {
-; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_known_pinf_frem_known_zero
+; CHECK-LABEL: define nofpclass(snan inf zero sub norm) float @ret_known_pinf_frem_known_zero
; CHECK-SAME: (float nofpclass(nan ninf zero sub norm) [[ARG0:%.*]], float nofpclass(nan inf sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -889,7 +889,7 @@ define float @ret_known_zero_or_nan_frem_known_inf(float nofpclass(inf norm sub)
define float @ret_frem_lhs_known_positive_or_nan(float %lhs, float %rhs) {
; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_frem_lhs_known_positive_or_nan
; CHECK-SAME: (float [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR4]] {
-; CHECK-NEXT: [[LHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[LHS]]) #[[ATTR6:[0-9]+]]
+; CHECK-NEXT: [[LHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[LHS]]) #[[ATTR14:[0-9]+]]
; CHECK-NEXT: [[MUL:%.*]] = frem float [[LHS_FABS]], [[RHS]]
; CHECK-NEXT: ret float [[MUL]]
;
@@ -901,7 +901,7 @@ define float @ret_frem_lhs_known_positive_or_nan(float %lhs, float %rhs) {
define float @ret_frem_rhs_known_positive_or_nan(float %lhs, float %rhs) {
; CHECK-LABEL: define nofpclass(inf) float @ret_frem_rhs_known_positive_or_nan
; CHECK-SAME: (float [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR4]] {
-; CHECK-NEXT: [[RHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[RHS]]) #[[ATTR6]]
+; CHECK-NEXT: [[RHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[RHS]]) #[[ATTR14]]
; CHECK-NEXT: [[MUL:%.*]] = frem float [[LHS]], [[RHS_FABS]]
; CHECK-NEXT: ret float [[MUL]]
;
@@ -913,8 +913,8 @@ define float @ret_frem_rhs_known_positive_or_nan(float %lhs, float %rhs) {
define float @ret_frem_both_signs_positive_or_nan(float %lhs, float %rhs) {
; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_frem_both_signs_positive_or_nan
; CHECK-SAME: (float [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR4]] {
-; CHECK-NEXT: [[LHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[LHS]]) #[[ATTR6]]
-; CHECK-NEXT: [[RHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[RHS]]) #[[ATTR6]]
+; CHECK-NEXT: [[LHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[LHS]]) #[[ATTR14]]
+; CHECK-NEXT: [[RHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[RHS]]) #[[ATTR14]]
; CHECK-NEXT: [[MUL:%.*]] = frem float [[LHS_FABS]], [[RHS_FABS]]
; CHECK-NEXT: ret float [[MUL]]
;
@@ -927,8 +927,8 @@ define float @ret_frem_both_signs_positive_or_nan(float %lhs, float %rhs) {
define float @ret_frem_both_signs_negative_or_nan(float %lhs, float %rhs) {
; CHECK-LABEL: define nofpclass(inf pzero psub pnorm) float @ret_frem_both_signs_negative_or_nan
; CHECK-SAME: (float [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR4]] {
-; CHECK-NEXT: [[LHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[LHS]]) #[[ATTR6]]
-; CHECK-NEXT: [[RHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[RHS]]) #[[ATTR6]]
+; CHECK-NEXT: [[LHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[LHS]]) #[[ATTR14]]
+; CHECK-NEXT: [[RHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[RHS]]) #[[ATTR14]]
; CHECK-NEXT: [[LHS_NEG_FABS:%.*]] = fneg float [[LHS_FABS]]
; CHECK-NEXT: [[RHS_NEG_FABS:%.*]] = fneg float [[RHS_FABS]]
; CHECK-NEXT: [[MUL:%.*]] = frem float [[LHS_NEG_FABS]], [[RHS_NEG_FABS]]
@@ -945,8 +945,8 @@ define float @ret_frem_both_signs_negative_or_nan(float %lhs, float %rhs) {
define float @ret_frem_lhs_negative_rhs_positive(float %lhs, float %rhs) {
; CHECK-LABEL: define nofpclass(inf pzero psub pnorm) float @ret_frem_lhs_negative_rhs_positive
; CHECK-SAME: (float [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR4]] {
-; CHECK-NEXT: [[LHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[LHS]]) #[[ATTR6]]
-; CHECK-NEXT: [[RHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[RHS]]) #[[ATTR6]]
+; CHECK-NEXT: [[LHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[LHS]]) #[[ATTR14]]
+; CHECK-NEXT: [[RHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[RHS]]) #[[ATTR14]]
; CHECK-NEXT: [[LHS_NEG_FABS:%.*]] = fneg float [[LHS_FABS]]
; CHECK-NEXT: [[MUL:%.*]] = frem float [[LHS_NEG_FABS]], [[RHS_FABS]]
; CHECK-NEXT: ret float [[MUL]]
@@ -961,8 +961,8 @@ define float @ret_frem_lhs_negative_rhs_positive(float %lhs, float %rhs) {
define float @ret_frem_rhs_negative_lhs_positive(float %lhs, float %rhs) {
; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_frem_rhs_negative_lhs_positive
; CHECK-SAME: (float [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR4]] {
-; CHECK-NEXT: [[LHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[LHS]]) #[[ATTR6]]
-; CHECK-NEXT: [[RHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[RHS]]) #[[ATTR6]]
+; CHECK-NEXT: [[LHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[LHS]]) #[[ATTR14]]
+; CHECK-NEXT: [[RHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[RHS]]) #[[ATTR14]]
; CHECK-NEXT: [[RHS_NEG_FABS:%.*]] = fneg float [[RHS_FABS]]
; CHECK-NEXT: [[MUL:%.*]] = frem float [[LHS_FABS]], [[RHS_NEG_FABS]]
; CHECK-NEXT: ret float [[MUL]]
@@ -975,7 +975,7 @@ define float @ret_frem_rhs_negative_lhs_positive(float %lhs, float %rhs) {
}
define float @ret_known_inf_frem_known_inf(float nofpclass(norm sub zero nan) %arg0, float nofpclass(norm sub zero nan) %arg1) {
-; CHECK-LABEL: define nofpclass(inf) float @ret_known_inf_frem_known_inf
+; CHECK-LABEL: define nofpclass(snan inf zero sub norm) float @ret_known_inf_frem_known_inf
; CHECK-SAME: (float nofpclass(nan zero sub norm) [[ARG0:%.*]], float nofpclass(nan zero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -985,7 +985,7 @@ define float @ret_known_inf_frem_known_inf(float nofpclass(norm sub zero nan) %a
}
define float @ret_known_inf_frem_known_inf_or_nan(float nofpclass(norm sub zero nan) %arg0, float nofpclass(norm sub zero) %arg1) {
-; CHECK-LABEL: define nofpclass(inf) float @ret_known_inf_frem_known_inf_or_nan
+; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_known_inf_frem_known_inf_or_nan
; CHECK-SAME: (float nofpclass(nan zero sub norm) [[ARG0:%.*]], float nofpclass(zero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -995,7 +995,7 @@ define float @ret_known_inf_frem_known_inf_or_nan(float nofpclass(norm sub zero
}
define float @ret_known_inf_or_nan_frem_known_inf(float nofpclass(norm sub zero) %arg0, float nofpclass(norm sub zero nan) %arg1) {
-; CHECK-LABEL: define nofpclass(inf) float @ret_known_inf_or_nan_frem_known_inf
+; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_known_inf_or_nan_frem_known_inf
; CHECK-SAME: (float nofpclass(zero sub norm) [[ARG0:%.*]], float nofpclass(nan zero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -1005,7 +1005,7 @@ define float @ret_known_inf_or_nan_frem_known_inf(float nofpclass(norm sub zero)
}
define float @ret_known_zero_frem_known_zero(float nofpclass(inf norm sub nan) %arg0, float nofpclass(inf norm sub nan) %arg1) {
-; CHECK-LABEL: define nofpclass(inf sub norm) float @ret_known_zero_frem_known_zero
+; CHECK-LABEL: define nofpclass(snan inf sub norm) float @ret_known_zero_frem_known_zero
; CHECK-SAME: (float nofpclass(nan inf sub norm) [[ARG0:%.*]], float nofpclass(nan inf sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -1035,7 +1035,7 @@ define float @ret_known_zero_or_nan_frem_known_zero(float nofpclass(inf norm sub
}
define float @ret_known_inf_or_nan_frem_unknown(float nofpclass(norm sub zero) %arg0, float %arg1) {
-; CHECK-LABEL: define nofpclass(inf) float @ret_known_inf_or_nan_frem_unknown
+; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_known_inf_or_nan_frem_unknown
; CHECK-SAME: (float nofpclass(zero sub norm) [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -1055,7 +1055,7 @@ define float @ret_unknown_frem_known_inf_or_nan(float %arg0, float nofpclass(nor
}
define float @ret_known_inf_or_nan_frem_known_inf_or_nan(float nofpclass(norm sub zero) %arg0, float nofpclass(norm sub zero) %arg1) {
-; CHECK-LABEL: define nofpclass(inf) float @ret_known_inf_or_nan_frem_known_inf_or_nan
+; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_known_inf_or_nan_frem_known_inf_or_nan
; CHECK-SAME: (float nofpclass(zero sub norm) [[ARG0:%.*]], float nofpclass(zero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FREM]]
@@ -1064,9 +1064,353 @@ define float @ret_known_inf_or_nan_frem_known_inf_or_nan(float nofpclass(norm su
ret float %frem
}
+; frem(x, y) == x if |x| < |y|, up to the denormal mode.
+
+define float @ret_frem_lhs_poszero_possubnormal_rhs_posnormal(float nofpclass(nan inf nzero nsub norm) %lhs, float nofpclass(nan inf zero sub nnorm) %rhs) {
+; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) float @ret_frem_lhs_poszero_possubnormal_rhs_posnormal
+; CHECK-SAME: (float nofpclass(nan inf nzero nsub norm) [[LHS:%.*]], float nofpclass(nan inf zero sub nnorm) [[RHS:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_lhs_negzero_negsubnormal_rhs_negnormal(float nofpclass(nan inf pzero psub norm) %lhs, float nofpclass(nan inf zero sub pnorm) %rhs) {
+; CHECK-LABEL: define nofpclass(nan inf pzero psub pnorm) float @ret_frem_lhs_negzero_negsubnormal_rhs_negnormal
+; CHECK-SAME: (float nofpclass(nan inf pzero psub norm) [[LHS:%.*]], float nofpclass(nan inf zero sub pnorm) [[RHS:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_lhs_negzero_negsubnormal_rhs_negnormal_mode_ftpz_dapz(float nofpclass(nan inf pzero psub norm) %lhs, float nofpclass(nan inf zero sub pnorm) %rhs) #5 {
+; CHECK-LABEL: define nofpclass(nan inf psub pnorm) float @ret_frem_lhs_negzero_negsubnormal_rhs_negnormal_mode_ftpz_dapz
+; CHECK-SAME: (float nofpclass(nan inf pzero psub norm) [[LHS:%.*]], float nofpclass(nan inf zero sub pnorm) [[RHS:%.*]]) #[[ATTR5:[0-9]+]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_lhs_negzero_negsubnormal_rhs_negnormal_mode_dynamic_dynamic(float nofpclass(nan inf pzero psub norm) %lhs, float nofpclass(nan inf zero sub pnorm) %rhs) #4 {
+; CHECK-LABEL: define nofpclass(nan inf psub pnorm) float @ret_frem_lhs_negzero_negsubnormal_rhs_negnormal_mode_dynamic_dynamic
+; CHECK-SAME: (float nofpclass(nan inf pzero psub norm) [[LHS:%.*]], float nofpclass(nan inf zero sub pnorm) [[RHS:%.*]]) #[[ATTR6:[0-9]+]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_lhs_zero_subnormal_rhs_normal(float nofpclass(nan inf norm) %lhs, float nofpclass(nan inf zero sub) %rhs) {
+; CHECK-LABEL: define nofpclass(nan inf) float @ret_frem_lhs_zero_subnormal_rhs_normal
+; CHECK-SAME: (float nofpclass(nan inf norm) [[LHS:%.*]], float nofpclass(nan inf zero sub) [[RHS:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_lhs_posfinite_rhs_posinf(float nofpclass(nan inf nzero nsub nnorm) %lhs, float nofpclass(nan ninf zero sub norm) %rhs) {
+; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) float @ret_frem_lhs_posfinite_rhs_posinf
+; CHECK-SAME: (float nofpclass(nan inf nzero nsub nnorm) [[LHS:%.*]], float nofpclass(nan ninf zero sub norm) [[RHS:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_lhs_negfinite_rhs_neginf(float nofpclass(nan inf pzero psub pnorm) %lhs, float nofpclass(nan pinf zero sub norm) %rhs) {
+; CHECK-LABEL: define nofpclass(nan inf pzero psub pnorm) float @ret_frem_lhs_negfinite_rhs_neginf
+; CHECK-SAME: (float nofpclass(nan inf pzero psub pnorm) [[LHS:%.*]], float nofpclass(nan pinf zero sub norm) [[RHS:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_lhs_negfinite_rhs_neginf_mode_ftpz_dapz(float nofpclass(nan inf pzero psub pnorm) %lhs, float nofpclass(nan pinf zero sub norm) %rhs) #5 {
+; CHECK-LABEL: define nofpclass(nan inf psub pnorm) float @ret_frem_lhs_negfinite_rhs_neginf_mode_ftpz_dapz
+; CHECK-SAME: (float nofpclass(nan inf pzero psub pnorm) [[LHS:%.*]], float nofpclass(nan pinf zero sub norm) [[RHS:%.*]]) #[[ATTR5]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_lhs_negfinite_rhs_neginf_mode_dynamic_dynamic(float nofpclass(nan inf pzero psub pnorm) %lhs, float nofpclass(nan pinf zero sub norm) %rhs) #4 {
+; CHECK-LABEL: define nofpclass(nan inf psub pnorm) float @ret_frem_lhs_negfinite_rhs_neginf_mode_dynamic_dynamic
+; CHECK-SAME: (float nofpclass(nan inf pzero psub pnorm) [[LHS:%.*]], float nofpclass(nan pinf zero sub norm) [[RHS:%.*]]) #[[ATTR6]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_lhs_finite_rhs_inf(float nofpclass(nan inf) %lhs, float nofpclass(nan zero sub norm) %rhs) {
+; CHECK-LABEL: define nofpclass(nan inf) float @ret_frem_lhs_finite_rhs_inf
+; CHECK-SAME: (float nofpclass(nan inf) [[LHS:%.*]], float nofpclass(nan zero sub norm) [[RHS:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+; Sign preservation
+
+define float @ret_frem_lhs_posnormal_possubnormal_rhs_any(float nofpclass(nan inf zero nsub nnorm) %lhs, float %rhs) {
+; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_frem_lhs_posnormal_possubnormal_rhs_any
+; CHECK-SAME: (float nofpclass(nan inf zero nsub nnorm) [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_lhs_negnormal_negsubnormal_rhs_any(float nofpclass(nan inf zero psub pnorm) %lhs, float %rhs) {
+; CHECK-LABEL: define nofpclass(inf pzero psub pnorm) float @ret_frem_lhs_negnormal_negsubnormal_rhs_any
+; CHECK-SAME: (float nofpclass(nan inf zero psub pnorm) [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_lhs_posfinite_rhs_any(float nofpclass(nan inf nzero nsub nnorm) %lhs, float %rhs) {
+; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_frem_lhs_posfinite_rhs_any
+; CHECK-SAME: (float nofpclass(nan inf nzero nsub nnorm) [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_lhs_posfinite_negzero_rhs_any(float nofpclass(nan inf nsub nnorm) %lhs, float %rhs) {
+; CHECK-LABEL: define nofpclass(inf nsub nnorm) float @ret_frem_lhs_posfinite_negzero_rhs_any
+; CHECK-SAME: (float nofpclass(nan inf nsub nnorm) [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+; TODO: If we can guarantee that subnormals flush to positive zero under DAPZ,
+; then we can rule out negatives here.
+define float @ret_frem_lhs_posfinite_negsubnormal_rhs_any_mode_dynamic_dapz(float nofpclass(nan inf nzero nnorm) %lhs, float %rhs) #8 {
+; CHECK-LABEL: define nofpclass(inf) float @ret_frem_lhs_posfinite_negsubnormal_rhs_any_mode_dynamic_dapz
+; CHECK-SAME: (float nofpclass(nan inf nzero nnorm) [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR7:[0-9]+]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+; We should be able to rule out positive zero no matter the denormal mode here.
+define float @ret_frem_lhs_never_posfinite_negnormal_negsubnormal_rhs_any_mode_dynamic_dynamic(float nofpclass(pzero sub norm) %lhs, float %rhs) #4 {
+; CHECK-LABEL: define nofpclass(inf pzero sub norm) float @ret_frem_lhs_never_posfinite_negnormal_negsubnormal_rhs_any_mode_dynamic_dynamic
+; CHECK-SAME: (float nofpclass(pzero sub norm) [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR6]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+; We can rule out positive zero if denormal outputs cannot be positive zero for
+; these cases:
+
+define float @ret_frem_lhs_never_posfinite_negsubnormal_rhs_any(float nofpclass(pzero sub pnorm) %lhs, float %rhs) {
+; CHECK-LABEL: define nofpclass(inf pzero psub pnorm) float @ret_frem_lhs_never_posfinite_negsubnormal_rhs_any
+; CHECK-SAME: (float nofpclass(pzero sub pnorm) [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_lhs_never_posfinite_negsubnormal_rhs_any_mode_ieee_dynamic(float nofpclass(pzero sub pnorm) %lhs, float %rhs) #3 {
+; CHECK-LABEL: define nofpclass(inf pzero psub pnorm) float @ret_frem_lhs_never_posfinite_negsubnormal_rhs_any_mode_ieee_dynamic
+; CHECK-SAME: (float nofpclass(pzero sub pnorm) [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_lhs_never_posfinite_negsubnormal_rhs_any_mode_ftz_dynamic(float nofpclass(pzero sub pnorm) %lhs, float %rhs) #11 {
+; CHECK-LABEL: define nofpclass(inf pzero psub pnorm) float @ret_frem_lhs_never_posfinite_negsubnormal_rhs_any_mode_ftz_dynamic
+; CHECK-SAME: (float nofpclass(pzero sub pnorm) [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR8:[0-9]+]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_lhs_never_posfinite_negsubnormal_rhs_any_mode_ftpz_dynamic(float nofpclass(pzero sub pnorm) %lhs, float %rhs) #7 {
+; CHECK-LABEL: define nofpclass(inf psub pnorm) float @ret_frem_lhs_never_posfinite_negsubnormal_rhs_any_mode_ftpz_dynamic
+; CHECK-SAME: (float nofpclass(pzero sub pnorm) [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR9:[0-9]+]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_lhs_never_posfinite_negsubnormal_rhs_any_mode_dynamic_dynamic(float nofpclass(pzero sub pnorm) %lhs, float %rhs) #4 {
+; CHECK-LABEL: define nofpclass(inf psub pnorm) float @ret_frem_lhs_never_posfinite_negsubnormal_rhs_any_mode_dynamic_dynamic
+; CHECK-SAME: (float nofpclass(pzero sub pnorm) [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR6]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+; We can rule out positive zero if both the input and output denormal modes are
+; not positive zero.
+
+define float @ret_frem_lhs_never_posfinite_negnormal_rhs_any(float nofpclass(pzero psub norm) %lhs, float %rhs) {
+; CHECK-LABEL: define nofpclass(inf pzero psub pnorm) float @ret_frem_lhs_never_posfinite_negnormal_rhs_any
+; CHECK-SAME: (float nofpclass(pzero psub norm) [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_lhs_never_posfinite_negnormal_rhs_any_mode_ieee_ieee(float nofpclass(pzero psub norm) %lhs, float %rhs) #0 {
+; CHECK-LABEL: define nofpclass(inf pzero psub pnorm) float @ret_frem_lhs_never_posfinite_negnormal_rhs_any_mode_ieee_ieee
+; CHECK-SAME: (float nofpclass(pzero psub norm) [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_lhs_never_posfinite_negnormal_rhs_any_mode_ftz_daz(float nofpclass(pzero psub norm) %lhs, float %rhs) #6 {
+; CHECK-LABEL: define nofpclass(inf pzero psub pnorm) float @ret_frem_lhs_never_posfinite_negnormal_rhs_any_mode_ftz_daz
+; CHECK-SAME: (float nofpclass(pzero psub norm) [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR10:[0-9]+]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_lhs_never_posfinite_negnormal_rhs_any_mode_ieee_dynamic(float nofpclass(pzero psub norm) %lhs, float %rhs) #3 {
+; CHECK-LABEL: define nofpclass(inf psub pnorm) float @ret_frem_lhs_never_posfinite_negnormal_rhs_any_mode_ieee_dynamic
+; CHECK-SAME: (float nofpclass(pzero psub norm) [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_lhs_never_posfinite_negnormal_rhs_any_mode_dynamic_ieee(float nofpclass(pzero psub norm) %lhs, float %rhs) #9 {
+; CHECK-LABEL: define nofpclass(inf psub pnorm) float @ret_frem_lhs_never_posfinite_negnormal_rhs_any_mode_dynamic_ieee
+; CHECK-SAME: (float nofpclass(pzero psub norm) [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR11:[0-9]+]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_lhs_never_posfinite_negnormal_rhs_any_mode_ieee_dapz(float nofpclass(pzero psub norm) %lhs, float %rhs) #2 {
+; CHECK-LABEL: define nofpclass(inf psub pnorm) float @ret_frem_lhs_never_posfinite_negnormal_rhs_any_mode_ieee_dapz
+; CHECK-SAME: (float nofpclass(pzero psub norm) [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR2]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_lhs_never_posfinite_negnormal_rhs_any_mode_ftpz_ieee(float nofpclass(pzero psub norm) %lhs, float %rhs) #10 {
+; CHECK-LABEL: define nofpclass(inf psub pnorm) float @ret_frem_lhs_never_posfinite_negnormal_rhs_any_mode_ftpz_ieee
+; CHECK-SAME: (float nofpclass(pzero psub norm) [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR12:[0-9]+]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+; General FTPZ/DAPZ tests:
+
+define float @ret_frem_negnormal_negsubnormal_both_lhs_rhs_mode_dynamic_dynamic(float nofpclass(nan inf zero psub pnorm) %lhs, float nofpclass(nan inf zero psub pnorm) %rhs) #4 {
+; CHECK-LABEL: define nofpclass(snan inf psub pnorm) float @ret_frem_negnormal_negsubnormal_both_lhs_rhs_mode_dynamic_dynamic
+; CHECK-SAME: (float nofpclass(nan inf zero psub pnorm) [[LHS:%.*]], float nofpclass(nan inf zero psub pnorm) [[RHS:%.*]]) #[[ATTR6]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_negnormal_negsubnormal_both_lhs_rhs_mode_ftpz_dapz(float nofpclass(nan inf zero psub pnorm) %lhs, float nofpclass(nan inf zero psub pnorm) %rhs) #5 {
+; CHECK-LABEL: define nofpclass(snan inf psub pnorm) float @ret_frem_negnormal_negsubnormal_both_lhs_rhs_mode_ftpz_dapz
+; CHECK-SAME: (float nofpclass(nan inf zero psub pnorm) [[LHS:%.*]], float nofpclass(nan inf zero psub pnorm) [[RHS:%.*]]) #[[ATTR5]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %lhs, %rhs
+ ret float %frem
+}
+
+define float @ret_frem_self_negnormal_negsubnormal_mode_dynamic_dynamic(float noundef nofpclass(nan inf zero psub pnorm) %arg) #4 {
+; CHECK-LABEL: define noundef nofpclass(snan inf pzero sub norm) float @ret_frem_self_negnormal_negsubnormal_mode_dynamic_dynamic
+; CHECK-SAME: (float noundef nofpclass(nan inf zero psub pnorm) [[ARG:%.*]]) #[[ATTR6]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG]], [[ARG]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %arg, %arg
+ ret float %frem
+}
+
+define float @ret_frem_self_negnormal_negsubnormal_mode_ftpz_dapz(float noundef nofpclass(nan inf zero psub pnorm) %arg) #5 {
+; CHECK-LABEL: define noundef nofpclass(snan inf pzero sub norm) float @ret_frem_self_negnormal_negsubnormal_mode_ftpz_dapz
+; CHECK-SAME: (float noundef nofpclass(nan inf zero psub pnorm) [[ARG:%.*]]) #[[ATTR5]] {
+; CHECK-NEXT: [[FREM:%.*]] = frem float [[ARG]], [[ARG]]
+; CHECK-NEXT: ret float [[FREM]]
+;
+ %frem = frem float %arg, %arg
+ ret float %frem
+}
+
attributes #0 = { denormal_fpenv(ieee|ieee) }
attributes #1 = { denormal_fpenv(ieee|preservesign) }
attributes #2 = { denormal_fpenv(ieee|positivezero) }
attributes #3 = { denormal_fpenv(ieee|dynamic) }
+attributes #4 = { denormal_fpenv(dynamic|dynamic) }
+attributes #5 = { denormal_fpenv(positivezero|positivezero) }
+attributes #6 = { denormal_fpenv(preservesign|preservesign) }
+attributes #7 = { denormal_fpenv(positivezero|dynamic) }
+attributes #8 = { denormal_fpenv(dynamic|positivezero) }
+attributes #9 = { denormal_fpenv(dynamic|ieee) }
+attributes #10 = { denormal_fpenv(positivezero|ieee) }
+attributes #11 = { denormal_fpenv(preservesign|dynamic) }
+
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; TUNIT: {{.*}}
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index a969b8fdd866f..27bb4558e8e06 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -1912,6 +1912,23 @@ TEST_F(ComputeKnownFPClassTest, MaximumNumSignBit) {
expectKnownFPClass(fcPositive, false, A7);
}
+TEST_F(ComputeKnownFPClassTest, FRemDemandRHSForSNaN) {
+ parseAssembly("define float @test(float nofpclass(snan) %lhs, "
+ "float nofpclass(snan) %rhs) {\n"
+ " %A = frem float %lhs, %rhs\n"
+ " ret float %A\n"
+ "}\n");
+
+ KnownFPClass KnownSNan = computeKnownFPClass(A, M->getDataLayout(), fcSNan);
+ KnownFPClass KnownQNan = computeKnownFPClass(A, M->getDataLayout(), fcQNan);
+
+ EXPECT_TRUE(KnownSNan.isKnownNever(fcSNan));
+ EXPECT_FALSE(KnownSNan.isKnownNever(fcQNan));
+
+ EXPECT_TRUE(KnownQNan.isKnownNever(fcSNan));
+ EXPECT_FALSE(KnownQNan.isKnownNever(fcQNan));
+}
+
TEST_F(ComputeKnownFPClassTest, PowUseRHSToRuleOutNegativeResults) {
parseAssembly("declare float @llvm.pow.f32(float, float)\n"
"define float @test(float nofpclass(ninf nsub nnorm) %base,\n"
diff --git a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
index bdd2b3faf6d5c..f1752f219ab4b 100644
--- a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
+++ b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
@@ -1351,9 +1351,9 @@ TEST_F(AArch64GISelMITest, TestFPClassFRemSelf_KnownFiniteNonZero) {
KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
- // 2.0 % 2.0 = 0.0 exactly — NaN is impossible since 2.0 is finite and
+ // 2.0 % 2.0 = +0.0 exactly. NaN is impossible since 2.0 is finite and
// nonzero.
- EXPECT_EQ(fcZero, Known.KnownFPClasses);
+ EXPECT_EQ(fcPosZero, Known.KnownFPClasses);
}
TEST_F(AArch64GISelMITest, TestFPClassShuffleVec) {
More information about the llvm-commits
mailing list