[llvm] [KnownFPClass] Refine fdiv and fdiv_self class propagation + some minor fixes for propagateXorSign (PR #215014)
Max Graey via llvm-commits
llvm-commits at lists.llvm.org
Sat Aug 8 12:48:08 PDT 2026
https://github.com/MaxGraey created https://github.com/llvm/llvm-project/pull/215014
- **`fdiv`** now better handle subnormals. The quotient can be subnormal only when the divisor is normal and can be zero only when the dividend is zero, when divisor is infinite or division underflows. When either operand can only be zero, inf or nan, quotient narrows to two classes.
- **`fdiv_self`**. `x / x` is exactly +1.0 for a finite nonzero `x` and NaN for everything else.
- Fix **`propagateXorSign`** under a positive-zero input mode a negative subnormal operand is read as `+0.0`, so it no longer counts as negative. The same minor bug affected `fmul`.
>From 874bfdffd1837238f0a9e8cc3ab2db72df0921f7 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Sat, 8 Aug 2026 22:30:30 +0300
Subject: [PATCH 1/2] Refine fdiv and fdiv_self class propagation + fix
propagateXorSign under positive-zero input mode
---
llvm/include/llvm/Support/KnownFPClass.h | 26 +-
llvm/lib/Support/KnownFPClass.cpp | 49 +++-
.../Transforms/Attributor/nofpclass-fdiv.ll | 246 ++++++++++++++++--
.../simplify-demanded-fpclass-fdiv.ll | 29 +--
4 files changed, 293 insertions(+), 57 deletions(-)
diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h
index 956141b9449a2..00e031a54c02b 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -100,6 +100,10 @@ struct KnownFPClass {
/// zero.
LLVM_ABI bool isKnownNeverLogicalPosZero(DenormalMode Mode) const;
+ /// Return true if it's known this can never be interpreted as a finite
+ /// nonzero value, accounting for denormals the mode reads as zero.
+ LLVM_ABI bool isKnownNeverLogicalFiniteNonZero(DenormalMode Mode) const;
+
static constexpr FPClassTest OrderedLessThanZeroMask =
fcNegSubnormal | fcNegNormal | fcNegInf;
static constexpr FPClassTest OrderedGreaterThanZeroMask =
@@ -395,13 +399,25 @@ struct KnownFPClass {
// Propagate knowledge for operations whose result sign is the xor of the
// operand signs, such as multiply and divide. This only rules out possible
// non-NaN sign classes. NaNs do not have a constrained sign class here.
- void propagateXorSign(const KnownFPClass &LHS, const KnownFPClass &RHS) {
- if ((LHS.isKnownNever(fcNegative) && RHS.isKnownNever(fcNegative)) ||
- (LHS.isKnownNever(fcPositive) && RHS.isKnownNever(fcPositive)))
+ //
+ // A negative subnormal is read as +0.0 under a positive-zero input mode, so
+ // it counts towards the positive side and not the negative one.
+ void propagateXorSign(const KnownFPClass &LHS, const KnownFPClass &RHS,
+ DenormalMode Mode) {
+ bool MustFlushNegSub = Mode.Input == DenormalMode::PositiveZero;
+ bool MayFlushNegSub = Mode.inputsMayBePositiveZero();
+
+ FPClassTest NegMask =
+ MustFlushNegSub ? fcNegative & ~fcNegSubnormal : fcNegative;
+ FPClassTest PosMask =
+ MayFlushNegSub ? fcPositive | fcNegSubnormal : fcPositive;
+
+ if ((LHS.isKnownNever(NegMask) && RHS.isKnownNever(NegMask)) ||
+ (LHS.isKnownNever(PosMask) && RHS.isKnownNever(PosMask)))
knownNot(fcNegative);
- if ((LHS.isKnownNever(fcPositive) && RHS.isKnownNever(fcNegative)) ||
- (LHS.isKnownNever(fcNegative) && RHS.isKnownNever(fcPositive)))
+ if ((LHS.isKnownNever(PosMask) && RHS.isKnownNever(NegMask)) ||
+ (LHS.isKnownNever(NegMask) && RHS.isKnownNever(PosMask)))
knownNot(fcPositive);
}
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index eccd83451a05f..1cd08315ff2fd 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -65,6 +65,11 @@ bool KnownFPClass::isKnownNeverLogicalPosZero(DenormalMode Mode) const {
llvm_unreachable("covered switch over denormal mode");
}
+bool KnownFPClass::isKnownNeverLogicalFiniteNonZero(DenormalMode Mode) const {
+ return isKnownNever(fcNormal) &&
+ (isKnownNeverSubnormal() || Mode.inputsAreZero());
+}
+
void KnownFPClass::propagateDenormal(const KnownFPClass &Src,
DenormalMode Mode) {
KnownFPClasses = Src.KnownFPClasses;
@@ -362,7 +367,7 @@ KnownFPClass KnownFPClass::fmul(const KnownFPClass &KnownLHS,
// +X * +Y or -X * -Y => +Q
// +X * -Y or -X * +Y => -Q
- Known.propagateXorSign(KnownLHS, KnownRHS);
+ Known.propagateXorSign(KnownLHS, KnownRHS, Mode);
// Inf * Y => Inf or NaN
if (KnownLHS.isKnownAlways(fcInf | fcNan) ||
@@ -432,14 +437,35 @@ KnownFPClass KnownFPClass::fdiv(const KnownFPClass &KnownLHS,
// X / -0.0 => -Inf (or NaN)
// +X / +Y or -X / -Y => +Q
// +X / -Y or -X / +Y => -Q
- Known.propagateXorSign(KnownLHS, KnownRHS);
+ Known.propagateXorSign(KnownLHS, KnownRHS, Mode);
- // 0 / X => 0 or NaN
- if (KnownLHS.isKnownAlways(fcZero))
+ // {0, Inf, NaN} / Y => {0, Inf, NaN}
+ if (KnownLHS.isKnownNeverLogicalFiniteNonZero(Mode))
+ Known.knownNot(fcNormal | fcSubnormal);
+
+ // X / 0 => Inf
+ // X / Sub => Normal or Inf
+ // X / Inf => 0
+ if (KnownRHS.isKnownNever(fcNormal) || Mode.outputsAreZero())
+ Known.knownNot(fcSubnormal);
+
+ // 0 / Y => 0
+ // X / Inf => 0
+ // X / Normal => 0 on underflow
+ if (KnownLHS.isKnownNeverLogicalZero(Mode) &&
+ KnownRHS.isKnownNever(fcNormal | fcInf))
+ Known.knownNot(fcZero);
+
+ // {0, NaN} / Y => 0 or NaN
+ // X / {Inf, NaN} => 0 or NaN
+ if (KnownLHS.isKnownAlways(fcZero | fcNan) ||
+ KnownRHS.isKnownAlways(fcInf | fcNan))
Known.knownNot(fcSubnormal | fcNormal | fcInf);
- // X / 0 => NaN or Inf
- if (KnownRHS.isKnownAlways(fcZero))
+ // {Inf, NaN} / Y => Inf or NaN
+ // X / {0, NaN} => Inf or NaN
+ if (KnownLHS.isKnownAlways(fcInf | fcNan) ||
+ KnownRHS.isKnownAlways(fcZero | fcNan))
Known.knownNot(fcFinite);
return Known;
@@ -447,16 +473,23 @@ KnownFPClass KnownFPClass::fdiv(const KnownFPClass &KnownLHS,
KnownFPClass KnownFPClass::fdiv_self(const KnownFPClass &KnownSrc,
DenormalMode Mode) {
- // X / X is always exactly 1.0 or a NaN.
+ // X / X is always exactly +1.0 or NaN.
KnownFPClass Known(fcNan | fcPosNormal);
+ // X / X => +1.0 only for finite nonzero X
+ if (KnownSrc.isKnownNeverLogicalFiniteNonZero(Mode))
+ Known.knownNot(fcPosNormal);
+
+ // X / X => NaN only for 0, Inf and NaN
if (KnownSrc.isKnownNeverInfOrNaN() && KnownSrc.isKnownNeverLogicalZero(Mode))
Known.knownNot(fcNan);
- else if (KnownSrc.isKnownNever(fcSNan))
+
+ if (KnownSrc.isKnownNever(fcSNan))
Known.knownNot(fcSNan);
return Known;
}
+
KnownFPClass KnownFPClass::frem_self(const KnownFPClass &KnownSrc,
DenormalMode Mode) {
// X % X is always exactly [+-]0.0 or a NaN.
diff --git a/llvm/test/Transforms/Attributor/nofpclass-fdiv.ll b/llvm/test/Transforms/Attributor/nofpclass-fdiv.ll
index fef871a1e85f7..432a12bb1e86b 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-fdiv.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-fdiv.ll
@@ -589,7 +589,7 @@ define float @ret_fdiv_f32_known_zero_or_nan_lhs(float nofpclass(inf norm sub) %
}
define float @ret_fdiv_f32_known_zero_or_nan_rhs(float %arg0, float nofpclass(inf norm sub) %arg1) {
-; CHECK-LABEL: define float @ret_fdiv_f32_known_zero_or_nan_rhs
+; CHECK-LABEL: define nofpclass(zero sub norm) float @ret_fdiv_f32_known_zero_or_nan_rhs
; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(inf sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FDIV]]
@@ -629,7 +629,7 @@ define float @ret_fdiv_f32_known_pzero_or_nan_lhs(float nofpclass(inf norm sub n
}
define float @ret_fdiv_f32_known_pzero_or_nan_rhs(float %arg0, float nofpclass(inf norm sub nzero) %arg1) {
-; CHECK-LABEL: define float @ret_fdiv_f32_known_pzero_or_nan_rhs
+; CHECK-LABEL: define nofpclass(zero sub norm) float @ret_fdiv_f32_known_pzero_or_nan_rhs
; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(inf nzero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FDIV]]
@@ -669,7 +669,7 @@ define float @ret_fdiv_f32_known_nzero_or_nan_lhs(float nofpclass(inf norm sub p
}
define float @ret_fdiv_f32_known_nzero_or_nan_rhs(float %arg0, float nofpclass(inf norm sub pzero) %arg1) {
-; CHECK-LABEL: define float @ret_fdiv_f32_known_nzero_or_nan_rhs
+; CHECK-LABEL: define nofpclass(zero sub norm) float @ret_fdiv_f32_known_nzero_or_nan_rhs
; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(inf pzero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FDIV]]
@@ -709,7 +709,7 @@ define float @ret_fdiv_f32_known_inf_or_nan_lhs(float nofpclass(zero norm sub) %
}
define float @ret_fdiv_f32_known_inf_or_nan_rhs(float %arg0, float nofpclass(zero norm sub) %arg1) {
-; CHECK-LABEL: define float @ret_fdiv_f32_known_inf_or_nan_rhs
+; CHECK-LABEL: define nofpclass(inf sub norm) float @ret_fdiv_f32_known_inf_or_nan_rhs
; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(zero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FDIV]]
@@ -729,7 +729,7 @@ define float @ret_fdiv_f32_known_inf_lhs(float nofpclass(nan zero norm sub) %arg
}
define float @ret_fdiv_f32_known_inf_rhs(float %arg0, float nofpclass(nan zero norm sub) %arg1) {
-; CHECK-LABEL: define float @ret_fdiv_f32_known_inf_rhs
+; CHECK-LABEL: define nofpclass(inf sub norm) float @ret_fdiv_f32_known_inf_rhs
; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(nan zero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FDIV]]
@@ -749,7 +749,7 @@ define float @ret_fdiv_f32_known_pinf_or_nan_lhs(float nofpclass(ninf zero norm
}
define float @ret_fdiv_f32_known_pinf_or_nan_rhs(float %arg0, float nofpclass(ninf zero norm sub) %arg1) {
-; CHECK-LABEL: define float @ret_fdiv_f32_known_pinf_or_nan_rhs
+; CHECK-LABEL: define nofpclass(inf sub norm) float @ret_fdiv_f32_known_pinf_or_nan_rhs
; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(ninf zero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FDIV]]
@@ -769,7 +769,7 @@ define float @ret_fdiv_f32_known_ninf_or_nan_lhs(float nofpclass(pinf zero norm
}
define float @ret_fdiv_f32_known_ninf_or_nan_rhs(float %arg0, float nofpclass(pinf zero norm sub) %arg1) {
-; CHECK-LABEL: define float @ret_fdiv_f32_known_ninf_or_nan_rhs
+; CHECK-LABEL: define nofpclass(inf sub norm) float @ret_fdiv_f32_known_ninf_or_nan_rhs
; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(pinf zero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FDIV]]
@@ -802,7 +802,7 @@ define float @ret_known_inf_or_nan_fdiv_known_zero(float nofpclass(norm sub zero
; -> nan
define float @ret_known_inf_fdiv_known_zero_or_nan(float nofpclass(nan norm sub zero) %arg0, float nofpclass(inf norm sub) %arg1) {
-; CHECK-LABEL: define float @ret_known_inf_fdiv_known_zero_or_nan
+; CHECK-LABEL: define nofpclass(zero sub norm) float @ret_known_inf_fdiv_known_zero_or_nan
; CHECK-SAME: (float nofpclass(nan zero sub norm) [[ARG0:%.*]], float nofpclass(inf sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FDIV]]
@@ -846,7 +846,7 @@ define float @ret_known_zero_fdiv_known_inf(float nofpclass(nan inf norm sub) %a
; -> zero
define float @ret_known_zero_fdiv_known_inf_or_nan(float nofpclass(nan inf norm sub) %arg0, float nofpclass(norm sub zero) %arg1) {
-; CHECK-LABEL: define float @ret_known_zero_fdiv_known_inf_or_nan
+; CHECK-LABEL: define nofpclass(inf sub norm) float @ret_known_zero_fdiv_known_inf_or_nan
; CHECK-SAME: (float nofpclass(nan inf sub norm) [[ARG0:%.*]], float nofpclass(zero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FDIV]]
@@ -857,7 +857,7 @@ define float @ret_known_zero_fdiv_known_inf_or_nan(float nofpclass(nan inf norm
; -> zero or nan
define float @ret_known_zero_or_nan_fdiv_known_inf(float nofpclass(inf norm sub) %arg0, float nofpclass(nan norm sub zero) %arg1) {
-; CHECK-LABEL: define float @ret_known_zero_or_nan_fdiv_known_inf
+; CHECK-LABEL: define nofpclass(inf sub norm) float @ret_known_zero_or_nan_fdiv_known_inf
; CHECK-SAME: (float nofpclass(inf sub norm) [[ARG0:%.*]], float nofpclass(nan zero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FDIV]]
@@ -870,7 +870,7 @@ define float @ret_known_zero_or_nan_fdiv_known_inf(float nofpclass(inf norm sub)
define float @ret_fdiv_lhs_known_positive_or_nan(float %lhs, float %rhs) {
; CHECK-LABEL: define float @ret_fdiv_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]]) #[[ATTR8:[0-9]+]]
; CHECK-NEXT: [[MUL:%.*]] = fdiv float [[LHS_FABS]], [[RHS]]
; CHECK-NEXT: ret float [[MUL]]
;
@@ -883,7 +883,7 @@ define float @ret_fdiv_lhs_known_positive_or_nan(float %lhs, float %rhs) {
define float @ret_fdiv_rhs_known_positive_or_nan(float %lhs, float %rhs) {
; CHECK-LABEL: define float @ret_fdiv_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]]) #[[ATTR8]]
; CHECK-NEXT: [[MUL:%.*]] = fdiv float [[LHS]], [[RHS_FABS]]
; CHECK-NEXT: ret float [[MUL]]
;
@@ -896,8 +896,8 @@ define float @ret_fdiv_rhs_known_positive_or_nan(float %lhs, float %rhs) {
define float @ret_fdiv_both_signs_positive_or_nan(float %lhs, float %rhs) {
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_fdiv_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]]) #[[ATTR8]]
+; CHECK-NEXT: [[RHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[RHS]]) #[[ATTR8]]
; CHECK-NEXT: [[MUL:%.*]] = fdiv float [[LHS_FABS]], [[RHS_FABS]]
; CHECK-NEXT: ret float [[MUL]]
;
@@ -911,8 +911,8 @@ define float @ret_fdiv_both_signs_positive_or_nan(float %lhs, float %rhs) {
define float @ret_fdiv_both_signs_negative_or_nan(float %lhs, float %rhs) {
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_fdiv_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]]) #[[ATTR8]]
+; CHECK-NEXT: [[RHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[RHS]]) #[[ATTR8]]
; CHECK-NEXT: [[LHS_NEG_FABS:%.*]] = fneg float [[LHS_FABS]]
; CHECK-NEXT: [[RHS_NEG_FABS:%.*]] = fneg float [[RHS_FABS]]
; CHECK-NEXT: [[MUL:%.*]] = fdiv float [[LHS_NEG_FABS]], [[RHS_NEG_FABS]]
@@ -930,8 +930,8 @@ define float @ret_fdiv_both_signs_negative_or_nan(float %lhs, float %rhs) {
define float @ret_fdiv_lhs_negative_rhs_positive(float %lhs, float %rhs) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_fdiv_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]]) #[[ATTR8]]
+; CHECK-NEXT: [[RHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[RHS]]) #[[ATTR8]]
; CHECK-NEXT: [[LHS_NEG_FABS:%.*]] = fneg float [[LHS_FABS]]
; CHECK-NEXT: [[MUL:%.*]] = fdiv float [[LHS_NEG_FABS]], [[RHS_FABS]]
; CHECK-NEXT: ret float [[MUL]]
@@ -947,8 +947,8 @@ define float @ret_fdiv_lhs_negative_rhs_positive(float %lhs, float %rhs) {
define float @ret_fdiv_rhs_negative_lhs_positive(float %lhs, float %rhs) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_fdiv_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]]) #[[ATTR8]]
+; CHECK-NEXT: [[RHS_FABS:%.*]] = call float @llvm.fabs.f32(float [[RHS]]) #[[ATTR8]]
; CHECK-NEXT: [[RHS_NEG_FABS:%.*]] = fneg float [[RHS_FABS]]
; CHECK-NEXT: [[MUL:%.*]] = fdiv float [[LHS_FABS]], [[RHS_NEG_FABS]]
; CHECK-NEXT: ret float [[MUL]]
@@ -962,7 +962,7 @@ define float @ret_fdiv_rhs_negative_lhs_positive(float %lhs, float %rhs) {
; Could be inf of either sign
define float @ret_known_inf_fdiv_known_inf(float nofpclass(norm sub zero nan) %arg0, float nofpclass(norm sub zero nan) %arg1) {
-; CHECK-LABEL: define float @ret_known_inf_fdiv_known_inf
+; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_known_inf_fdiv_known_inf
; CHECK-SAME: (float nofpclass(nan zero sub norm) [[ARG0:%.*]], float nofpclass(nan zero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FDIV]]
@@ -973,7 +973,7 @@ define float @ret_known_inf_fdiv_known_inf(float nofpclass(norm sub zero nan) %a
; Could be inf of either sign, or nan
define float @ret_known_inf_fdiv_known_inf_or_nan(float nofpclass(norm sub zero nan) %arg0, float nofpclass(norm sub zero) %arg1) {
-; CHECK-LABEL: define float @ret_known_inf_fdiv_known_inf_or_nan
+; CHECK-LABEL: define nofpclass(inf sub norm) float @ret_known_inf_fdiv_known_inf_or_nan
; CHECK-SAME: (float nofpclass(nan zero sub norm) [[ARG0:%.*]], float nofpclass(zero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FDIV]]
@@ -984,7 +984,7 @@ define float @ret_known_inf_fdiv_known_inf_or_nan(float nofpclass(norm sub zero
; Could be inf of either sign, or nan
define float @ret_known_inf_or_nan_fdiv_known_inf(float nofpclass(norm sub zero) %arg0, float nofpclass(norm sub zero nan) %arg1) {
-; CHECK-LABEL: define float @ret_known_inf_or_nan_fdiv_known_inf
+; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_known_inf_or_nan_fdiv_known_inf
; CHECK-SAME: (float nofpclass(zero sub norm) [[ARG0:%.*]], float nofpclass(nan zero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FDIV]]
@@ -1006,7 +1006,7 @@ define float @ret_known_zero_fdiv_known_zero(float nofpclass(inf norm sub nan) %
; Could be zero of either sign, or nan
define float @ret_known_zero_fdiv_known_zero_or_nan(float nofpclass(inf norm sub nan) %arg0, float nofpclass(inf norm sub) %arg1) {
-; CHECK-LABEL: define float @ret_known_zero_fdiv_known_zero_or_nan
+; CHECK-LABEL: define nofpclass(zero sub norm) float @ret_known_zero_fdiv_known_zero_or_nan
; CHECK-SAME: (float nofpclass(nan inf sub norm) [[ARG0:%.*]], float nofpclass(inf sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FDIV]]
@@ -1017,7 +1017,7 @@ define float @ret_known_zero_fdiv_known_zero_or_nan(float nofpclass(inf norm sub
; Could be zero of either sign, or nan
define float @ret_known_zero_or_nan_fdiv_known_zero(float nofpclass(inf norm sub) %arg0, float nofpclass(inf norm sub nan) %arg1) {
-; CHECK-LABEL: define nofpclass(zero sub norm) float @ret_known_zero_or_nan_fdiv_known_zero
+; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_known_zero_or_nan_fdiv_known_zero
; CHECK-SAME: (float nofpclass(inf sub norm) [[ARG0:%.*]], float nofpclass(nan inf sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FDIV]]
@@ -1037,7 +1037,7 @@ define float @ret_known_inf_or_nan_fdiv_unknown(float nofpclass(norm sub zero) %
}
define float @ret_unknown_fdiv_known_inf_or_nan(float %arg0, float nofpclass(norm sub zero) %arg1) {
-; CHECK-LABEL: define float @ret_unknown_fdiv_known_inf_or_nan
+; CHECK-LABEL: define nofpclass(inf sub norm) float @ret_unknown_fdiv_known_inf_or_nan
; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(zero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FDIV]]
@@ -1047,7 +1047,7 @@ define float @ret_unknown_fdiv_known_inf_or_nan(float %arg0, float nofpclass(nor
}
define float @ret_known_inf_or_nan_fdiv_known_inf_or_nan(float nofpclass(norm sub zero) %arg0, float nofpclass(norm sub zero) %arg1) {
-; CHECK-LABEL: define float @ret_known_inf_or_nan_fdiv_known_inf_or_nan
+; CHECK-LABEL: define nofpclass(inf sub norm) float @ret_known_inf_or_nan_fdiv_known_inf_or_nan
; CHECK-SAME: (float nofpclass(zero sub norm) [[ARG0:%.*]], float nofpclass(zero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FDIV]]
@@ -1056,9 +1056,201 @@ define float @ret_known_inf_or_nan_fdiv_known_inf_or_nan(float nofpclass(norm su
ret float %fdiv
}
+define float @ret_fdiv_ieee_all_nonorm(float %arg0, float nofpclass(norm) %arg1) #0 {
+; CHECK-LABEL: define nofpclass(sub) float @ret_fdiv_ieee_all_nonorm
+; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(norm) [[ARG1:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, %arg1
+ ret float %fdiv
+}
+
+define float @ret_fdiv_ftz_all_all(float %arg0, float %arg1) #4 {
+; CHECK-LABEL: define nofpclass(sub) float @ret_fdiv_ftz_all_all
+; CHECK-SAME: (float [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR5:[0-9]+]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, %arg1
+ ret float %fdiv
+}
+
+define float @ret_fdiv_dynout_all_all(float %arg0, float %arg1) #5 {
+; CHECK-LABEL: define float @ret_fdiv_dynout_all_all
+; CHECK-SAME: (float [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR6:[0-9]+]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, %arg1
+ ret float %fdiv
+}
+
+define float @ret_fdiv_ieee_nosub_nonorm_nonan(float nofpclass(sub norm) %arg0, float nofpclass(nan) %arg1) #0 {
+; CHECK-LABEL: define nofpclass(sub norm) float @ret_fdiv_ieee_nosub_nonorm_nonan
+; CHECK-SAME: (float nofpclass(sub norm) [[ARG0:%.*]], float nofpclass(nan) [[ARG1:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, %arg1
+ ret float %fdiv
+}
+
+define float @ret_fdiv_ieee_nonorm_nonan(float nofpclass(norm) %arg0, float nofpclass(nan) %arg1) #0 {
+; CHECK-LABEL: define float @ret_fdiv_ieee_nonorm_nonan
+; CHECK-SAME: (float nofpclass(norm) [[ARG0:%.*]], float nofpclass(nan) [[ARG1:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, %arg1
+ ret float %fdiv
+}
+
+define float @ret_fdiv_daz_nonorm_nonan(float nofpclass(norm) %arg0, float nofpclass(nan) %arg1) #1 {
+; CHECK-LABEL: define nofpclass(sub norm) float @ret_fdiv_daz_nonorm_nonan
+; CHECK-SAME: (float nofpclass(norm) [[ARG0:%.*]], float nofpclass(nan) [[ARG1:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, %arg1
+ ret float %fdiv
+}
+
+define float @ret_fdiv_ieee_nozero_nosub_nonan_noinf_nonorm(float nofpclass(zero sub) %arg0, float nofpclass(nan inf norm) %arg1) #0 {
+; CHECK-LABEL: define nofpclass(zero sub) float @ret_fdiv_ieee_nozero_nosub_nonan_noinf_nonorm
+; CHECK-SAME: (float nofpclass(zero sub) [[ARG0:%.*]], float nofpclass(nan inf norm) [[ARG1:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, %arg1
+ ret float %fdiv
+}
+
+define float @ret_fdiv_ieee_nozero_nonan_noinf_nonorm(float nofpclass(zero) %arg0, float nofpclass(nan inf norm) %arg1) #0 {
+; CHECK-LABEL: define nofpclass(zero sub) float @ret_fdiv_ieee_nozero_nonan_noinf_nonorm
+; CHECK-SAME: (float nofpclass(zero) [[ARG0:%.*]], float nofpclass(nan inf norm) [[ARG1:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, %arg1
+ ret float %fdiv
+}
+
+define float @ret_fdiv_daz_nozero_nonan_noinf_nonorm(float nofpclass(zero) %arg0, float nofpclass(nan inf norm) %arg1) #1 {
+; CHECK-LABEL: define nofpclass(sub) float @ret_fdiv_daz_nozero_nonan_noinf_nonorm
+; CHECK-SAME: (float nofpclass(zero) [[ARG0:%.*]], float nofpclass(nan inf norm) [[ARG1:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, %arg1
+ ret float %fdiv
+}
+
+define float @ret_fdiv_ieee_nozero_nosub_nonan_noinf(float nofpclass(zero sub) %arg0, float nofpclass(nan inf) %arg1) #0 {
+; CHECK-LABEL: define float @ret_fdiv_ieee_nozero_nosub_nonan_noinf
+; CHECK-SAME: (float nofpclass(zero sub) [[ARG0:%.*]], float nofpclass(nan inf) [[ARG1:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, %arg1
+ ret float %fdiv
+}
+
+define float @ret_fdiv_ieee_no_pos_no_neg(float nofpclass(pinf pzero psub pnorm) %arg0, float nofpclass(ninf nzero nsub nnorm) %arg1) #0 {
+; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_fdiv_ieee_no_pos_no_neg
+; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nsub nnorm) [[ARG1:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, %arg1
+ ret float %fdiv
+}
+
+define float @ret_fdiv_daz_no_pos_no_neg(float nofpclass(pinf pzero psub pnorm) %arg0, float nofpclass(ninf nzero nsub nnorm) %arg1) #1 {
+; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_fdiv_daz_no_pos_no_neg
+; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nsub nnorm) [[ARG1:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, %arg1
+ ret float %fdiv
+}
+
+define float @ret_fdiv_dapz_no_pos_no_neg(float nofpclass(pinf pzero psub pnorm) %arg0, float nofpclass(ninf nzero nsub nnorm) %arg1) #2 {
+; CHECK-LABEL: define float @ret_fdiv_dapz_no_pos_no_neg
+; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nsub nnorm) [[ARG1:%.*]]) #[[ATTR2]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, %arg1
+ ret float %fdiv
+}
+
+define float @ret_fdiv_dynamic_no_pos_no_neg(float nofpclass(pinf pzero psub pnorm) %arg0, float nofpclass(ninf nzero nsub nnorm) %arg1) #3 {
+; CHECK-LABEL: define float @ret_fdiv_dynamic_no_pos_no_neg
+; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nsub nnorm) [[ARG1:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, %arg1
+ ret float %fdiv
+}
+
+define float @ret_fdiv_dapz_no_pos_nonsub_no_neg(float nofpclass(pinf pzero psub pnorm nsub) %arg0, float nofpclass(ninf nzero nsub nnorm) %arg1) #2 {
+; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_fdiv_dapz_no_pos_nonsub_no_neg
+; CHECK-SAME: (float nofpclass(pinf pzero sub pnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nsub nnorm) [[ARG1:%.*]]) #[[ATTR2]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, %arg1
+ ret float %fdiv
+}
+
+define float @ret_fdiv_same_operands_nosub_nonorm(float noundef nofpclass(sub norm) %arg) #0 {
+; CHECK-LABEL: define noundef nofpclass(inf zero sub norm) float @ret_fdiv_same_operands_nosub_nonorm
+; CHECK-SAME: (float noundef nofpclass(sub norm) [[ARG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG]], [[ARG]]
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg, %arg
+ ret float %fdiv
+}
+
+define float @ret_fdiv_same_operands_nonorm(float noundef nofpclass(norm) %arg) #0 {
+; CHECK-LABEL: define noundef nofpclass(inf zero sub nnorm) float @ret_fdiv_same_operands_nonorm
+; CHECK-SAME: (float noundef nofpclass(norm) [[ARG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG]], [[ARG]]
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg, %arg
+ ret float %fdiv
+}
+
+define float @ret_fdiv_same_operands_nonorm_daz(float noundef nofpclass(norm) %arg) #1 {
+; CHECK-LABEL: define noundef nofpclass(inf zero sub norm) float @ret_fdiv_same_operands_nonorm_daz
+; CHECK-SAME: (float noundef nofpclass(norm) [[ARG:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG]], [[ARG]]
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg, %arg
+ ret float %fdiv
+}
+
+define float @ret_fdiv_same_operands_nonorm_dynamic(float noundef nofpclass(norm) %arg) #3 {
+; CHECK-LABEL: define noundef nofpclass(inf zero sub nnorm) float @ret_fdiv_same_operands_nonorm_dynamic
+; CHECK-SAME: (float noundef nofpclass(norm) [[ARG:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG]], [[ARG]]
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg, %arg
+ ret float %fdiv
+}
+
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(preservesign|ieee) }
+attributes #5 = { denormal_fpenv(dynamic|ieee) }
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; TUNIT: {{.*}}
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fdiv.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fdiv.ll
index 957a8ec082e8c..af300be6ac806 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fdiv.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fdiv.ll
@@ -665,7 +665,7 @@ define nofpclass(ninf nnorm nsub nzero nan) half @ret_only_positive_results_know
define nofpclass(nsub) half @ret__known_zero_or_nan__fdiv__not_inf(half nofpclass(inf sub norm) %zero.or.nan, half nofpclass(inf) %not.inf) {
; CHECK-LABEL: define nofpclass(nsub) half @ret__known_zero_or_nan__fdiv__not_inf(
; CHECK-SAME: half nofpclass(inf sub norm) [[ZERO_OR_NAN:%.*]], half nofpclass(inf) [[NOT_INF:%.*]]) {
-; CHECK-NEXT: [[DIV:%.*]] = fdiv half [[ZERO_OR_NAN]], [[NOT_INF]]
+; CHECK-NEXT: [[DIV:%.*]] = fdiv ninf half [[ZERO_OR_NAN]], [[NOT_INF]]
; CHECK-NEXT: ret half [[DIV]]
;
%div = fdiv half %zero.or.nan, %not.inf
@@ -676,7 +676,7 @@ define nofpclass(nsub) half @ret__known_zero_or_nan__fdiv__not_inf(half nofpclas
define nofpclass(nsub) half @ret__known_zero_or_nan__fdiv__not_inf_or_nan(half nofpclass(inf sub norm) %zero.or.nan, half nofpclass(inf nan) %not.inf.or.nan) {
; CHECK-LABEL: define nofpclass(nsub) half @ret__known_zero_or_nan__fdiv__not_inf_or_nan(
; CHECK-SAME: half nofpclass(inf sub norm) [[ZERO_OR_NAN:%.*]], half nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[DIV:%.*]] = fdiv half [[ZERO_OR_NAN]], [[NOT_INF_OR_NAN]]
+; CHECK-NEXT: [[DIV:%.*]] = fdiv ninf half [[ZERO_OR_NAN]], [[NOT_INF_OR_NAN]]
; CHECK-NEXT: ret half [[DIV]]
;
%div = fdiv half %zero.or.nan, %not.inf.or.nan
@@ -698,7 +698,7 @@ define nofpclass(nsub) half @ret__not_inf_or_nan__fdiv__known_zero_or_nan(half n
define nofpclass(nsub) half @ret__known_pzero_or_nan__fdiv__not_inf_or_nan(half nofpclass(inf sub norm nzero) %pzero.or.nan, half nofpclass(inf nan) %not.inf.or.nan) {
; CHECK-LABEL: define nofpclass(nsub) half @ret__known_pzero_or_nan__fdiv__not_inf_or_nan(
; CHECK-SAME: half nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], half nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[DIV:%.*]] = fdiv half [[PZERO_OR_NAN]], [[NOT_INF_OR_NAN]]
+; CHECK-NEXT: [[DIV:%.*]] = fdiv ninf half [[PZERO_OR_NAN]], [[NOT_INF_OR_NAN]]
; CHECK-NEXT: ret half [[DIV]]
;
%div = fdiv half %pzero.or.nan, %not.inf.or.nan
@@ -1217,7 +1217,7 @@ define nofpclass(ninf) half @ret_ninf__fdiv_nnan_unknown__zero(half %unknown) {
define nofpclass(snan) half @known__nzero_or_nan__fdiv__not_inf_or_nan(half nofpclass(inf sub norm pzero) %nzero.or.nan, half nofpclass(inf nan) %not.inf.or.nan) {
; CHECK-LABEL: define nofpclass(snan) half @known__nzero_or_nan__fdiv__not_inf_or_nan(
; CHECK-SAME: half nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]], half nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[DIV:%.*]] = fdiv contract half [[NZERO_OR_NAN]], [[NOT_INF_OR_NAN]]
+; CHECK-NEXT: [[DIV:%.*]] = fdiv ninf contract half [[NZERO_OR_NAN]], [[NOT_INF_OR_NAN]]
; CHECK-NEXT: ret half [[DIV]]
;
%div = fdiv contract half %nzero.or.nan, %not.inf.or.nan
@@ -1239,7 +1239,7 @@ define nofpclass(snan) half @known__not_inf_or_nan__fdiv__nzero_or_nan(half nofp
define nofpclass(snan) half @known__nzero_or_nan__fdiv__not_inf(half nofpclass(inf sub norm pzero) %nzero.or.nan, half nofpclass(inf) %not.inf) {
; CHECK-LABEL: define nofpclass(snan) half @known__nzero_or_nan__fdiv__not_inf(
; CHECK-SAME: half nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]], half nofpclass(inf) [[NOT_INF:%.*]]) {
-; CHECK-NEXT: [[DIV:%.*]] = fdiv half [[NZERO_OR_NAN]], [[NOT_INF]]
+; CHECK-NEXT: [[DIV:%.*]] = fdiv ninf half [[NZERO_OR_NAN]], [[NOT_INF]]
; CHECK-NEXT: ret half [[DIV]]
;
%div = fdiv half %nzero.or.nan, %not.inf
@@ -1294,8 +1294,7 @@ define nofpclass(inf) half @ret_noinf__nzero_or_nan__fdiv__not_inf_or_nan(half n
define nofpclass(inf) half @ret_noinf__not_inf_or_nan__fdiv__nzero_or_nan(half nofpclass(nan) %not.nan, half nofpclass(inf sub norm pzero) %nzero.or.nan) {
; CHECK-LABEL: define nofpclass(inf) half @ret_noinf__not_inf_or_nan__fdiv__nzero_or_nan(
; CHECK-SAME: half nofpclass(nan) [[NOT_NAN:%.*]], half nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[DIV:%.*]] = fdiv half [[NOT_NAN]], [[NZERO_OR_NAN]]
-; CHECK-NEXT: ret half [[DIV]]
+; CHECK-NEXT: ret half +qnan
;
%div = fdiv half %not.nan, %nzero.or.nan
ret half %div
@@ -1338,8 +1337,7 @@ define nofpclass(snan) half @ret__nzero_or_nan__fdiv_ninf__not_inf_or_nan(half n
define nofpclass(snan) half @ret_not_inf_or_nan__fdiv_ninf__nzero_or_nan(half nofpclass(nan) %not.nan, half nofpclass(inf sub norm pzero) %nzero.or.nan) {
; CHECK-LABEL: define nofpclass(snan) half @ret_not_inf_or_nan__fdiv_ninf__nzero_or_nan(
; CHECK-SAME: half nofpclass(nan) [[NOT_NAN:%.*]], half nofpclass(inf pzero sub norm) [[NZERO_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[DIV:%.*]] = fdiv ninf half [[NOT_NAN]], [[NZERO_OR_NAN]]
-; CHECK-NEXT: ret half [[DIV]]
+; CHECK-NEXT: ret half +qnan
;
%div = fdiv ninf half %not.nan, %nzero.or.nan
ret half %div
@@ -1371,7 +1369,7 @@ define nofpclass(snan) half @not_inf_or_nan__fdiv_nnan__nzero_or_nan(half %unkno
define nofpclass(snan) half @known__pzero_or_nan__fdiv__not_inf_or_nan(half nofpclass(inf sub norm nzero) %pzero.or.nan, half nofpclass(inf nan) %not.inf.or.nan) {
; CHECK-LABEL: define nofpclass(snan) half @known__pzero_or_nan__fdiv__not_inf_or_nan(
; CHECK-SAME: half nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], half nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[DIV:%.*]] = fdiv contract half [[PZERO_OR_NAN]], [[NOT_INF_OR_NAN]]
+; CHECK-NEXT: [[DIV:%.*]] = fdiv ninf contract half [[PZERO_OR_NAN]], [[NOT_INF_OR_NAN]]
; CHECK-NEXT: ret half [[DIV]]
;
%div = fdiv contract half %pzero.or.nan, %not.inf.or.nan
@@ -1393,7 +1391,7 @@ define nofpclass(snan) half @known__not_inf_or_nan__fdiv__pzero_or_nan(half nofp
define nofpclass(snan) half @known__pzero_or_nan__fdiv__not_inf(half nofpclass(inf sub norm nzero) %pzero.or.nan, half nofpclass(inf) %not.inf) {
; CHECK-LABEL: define nofpclass(snan) half @known__pzero_or_nan__fdiv__not_inf(
; CHECK-SAME: half nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], half nofpclass(inf) [[NOT_INF:%.*]]) {
-; CHECK-NEXT: [[DIV:%.*]] = fdiv half [[PZERO_OR_NAN]], [[NOT_INF]]
+; CHECK-NEXT: [[DIV:%.*]] = fdiv ninf half [[PZERO_OR_NAN]], [[NOT_INF]]
; CHECK-NEXT: ret half [[DIV]]
;
%div = fdiv half %pzero.or.nan, %not.inf
@@ -1448,8 +1446,7 @@ define nofpclass(inf) half @ret_noinf__pzero_or_nan__fdiv__not_inf_or_nan(half n
define nofpclass(inf) half @ret_noinf__not_inf_or_nan__fdiv__pzero_or_nan(half nofpclass(nan) %not.nan, half nofpclass(inf sub norm nzero) %pzero.or.nan) {
; CHECK-LABEL: define nofpclass(inf) half @ret_noinf__not_inf_or_nan__fdiv__pzero_or_nan(
; CHECK-SAME: half nofpclass(nan) [[NOT_NAN:%.*]], half nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[DIV:%.*]] = fdiv half [[NOT_NAN]], [[PZERO_OR_NAN]]
-; CHECK-NEXT: ret half [[DIV]]
+; CHECK-NEXT: ret half +qnan
;
%div = fdiv half %not.nan, %pzero.or.nan
ret half %div
@@ -1470,8 +1467,7 @@ define nofpclass(snan) half @ret__pzero_or_nan__fdiv_ninf__not_inf_or_nan(half n
define nofpclass(snan) half @ret_not_inf_or_nan__fdiv_ninf__pzero_or_nan(half nofpclass(nan) %not.nan, half nofpclass(inf sub norm nzero) %pzero.or.nan) {
; CHECK-LABEL: define nofpclass(snan) half @ret_not_inf_or_nan__fdiv_ninf__pzero_or_nan(
; CHECK-SAME: half nofpclass(nan) [[NOT_NAN:%.*]], half nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[DIV:%.*]] = fdiv ninf half [[NOT_NAN]], [[PZERO_OR_NAN]]
-; CHECK-NEXT: ret half [[DIV]]
+; CHECK-NEXT: ret half +qnan
;
%div = fdiv ninf half %not.nan, %pzero.or.nan
ret half %div
@@ -2346,8 +2342,7 @@ define nofpclass(nan) half @ret_nonan__unknown__fdiv__zero_or_nan(half %unknown,
define nofpclass(inf) half @ret_noinf__unknown__fdiv__zero_or_nan(half %unknown, half nofpclass(inf sub norm) %zero.or.nan) {
; CHECK-LABEL: define nofpclass(inf) half @ret_noinf__unknown__fdiv__zero_or_nan(
; CHECK-SAME: half [[UNKNOWN:%.*]], half nofpclass(inf sub norm) [[ZERO_OR_NAN:%.*]]) {
-; CHECK-NEXT: [[DIV:%.*]] = fdiv half [[UNKNOWN]], [[ZERO_OR_NAN]]
-; CHECK-NEXT: ret half [[DIV]]
+; CHECK-NEXT: ret half +qnan
;
%div = fdiv half %unknown, %zero.or.nan
ret half %div
>From cb77b54ddcedbb2ac43b8bb729bc3825851b4bdd Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Sat, 8 Aug 2026 22:35:48 +0300
Subject: [PATCH 2/2] add TODO comment
---
llvm/include/llvm/Support/KnownFPClass.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h
index 00e031a54c02b..e4217eddb261f 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -402,6 +402,10 @@ struct KnownFPClass {
//
// A negative subnormal is read as +0.0 under a positive-zero input mode, so
// it counts towards the positive side and not the negative one.
+ //
+ // TODO: With a positive-zero output mode a -sub result is flushed to +0.0, so
+ // the result can be positive after all. Fix it in fmul and fdiv by adding
+ // fcPosZero back and dropping SignBit before they rule out fcSubnormal.
void propagateXorSign(const KnownFPClass &LHS, const KnownFPClass &RHS,
DenormalMode Mode) {
bool MustFlushNegSub = Mode.Input == DenormalMode::PositiveZero;
More information about the llvm-commits
mailing list