[llvm] d3c6c3f - ValueTracking: Sign handling for minnum/maxnum
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Tue May 2 16:10:43 PDT 2023
Author: Matt Arsenault
Date: 2023-05-02T19:10:37-04:00
New Revision: d3c6c3f63c1276b4506d892fecadc0d155b35e2b
URL: https://github.com/llvm/llvm-project/commit/d3c6c3f63c1276b4506d892fecadc0d155b35e2b
DIFF: https://github.com/llvm/llvm-project/commit/d3c6c3f63c1276b4506d892fecadc0d155b35e2b.diff
LOG: ValueTracking: Sign handling for minnum/maxnum
If we know one operand is positive for maxnum, or one is negative
for minnum, the result will have the same sign.
Added:
Modified:
llvm/include/llvm/Analysis/ValueTracking.h
llvm/lib/Analysis/ValueTracking.cpp
llvm/test/Transforms/Attributor/nofpclass-minimum-maximum.ll
llvm/test/Transforms/Attributor/nofpclass-minnum-maxnum.ll
Removed:
################################################################################
diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index 4e95791aaa14..9630a7bc24ca 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -293,6 +293,11 @@ struct KnownFPClass {
/// floating-point mode for the function interprets denormals as zero.
bool isKnownNeverLogicalZero(const Function &F, Type *Ty) const;
+ static constexpr FPClassTest OrderedLessThanZeroMask =
+ fcNegSubnormal | fcNegNormal | fcNegInf;
+ static constexpr FPClassTest OrderedGreaterThanZeroMask =
+ fcPosSubnormal | fcPosNormal | fcPosInf;
+
/// Return true if we can prove that the analyzed floating-point value is
/// either NaN or never less than -0.0.
///
@@ -302,8 +307,18 @@ struct KnownFPClass {
/// x > +0 --> true
/// x < -0 --> false
bool cannotBeOrderedLessThanZero() const {
- const FPClassTest OrderedNegMask = fcNegSubnormal | fcNegNormal | fcNegInf;
- return (KnownFPClasses & OrderedNegMask) == fcNone;
+ return isKnownNever(OrderedLessThanZeroMask);
+ }
+
+ /// Return true if we can prove that the analyzed floating-point value is
+ /// either NaN or never greater than -0.0.
+ /// NaN --> true
+ /// +0 --> true
+ /// -0 --> true
+ /// x > +0 --> false
+ /// x < -0 --> true
+ bool cannotBeOrderedGreaterThanZero() const {
+ return isKnownNever(OrderedGreaterThanZeroMask);
}
KnownFPClass &operator|=(const KnownFPClass &RHS) {
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 50796d143e0b..ec05fa99b1b3 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -4727,23 +4727,55 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
Known.knownNot(fcNan);
break;
}
- case Intrinsic::minnum:
+
case Intrinsic::maxnum:
+ case Intrinsic::minnum:
case Intrinsic::minimum:
case Intrinsic::maximum: {
- KnownFPClass Known2;
- computeKnownFPClass(II->getArgOperand(0), DemandedElts, InterestedClasses,
- Known, Depth + 1, Q, TLI);
- computeKnownFPClass(II->getArgOperand(1), DemandedElts, InterestedClasses,
- Known2, Depth + 1, Q, TLI);
+ KnownFPClass KnownLHS, KnownRHS;
+ computeKnownFPClass(II->getArgOperand(0), DemandedElts,
+ InterestedClasses, KnownLHS, Depth + 1, Q, TLI);
+ computeKnownFPClass(II->getArgOperand(1), DemandedElts,
+ InterestedClasses, KnownRHS, Depth + 1, Q, TLI);
- bool NeverNaN = Known.isKnownNeverNaN() || Known2.isKnownNeverNaN();
- Known |= Known2;
+ bool NeverNaN =
+ KnownLHS.isKnownNeverNaN() || KnownRHS.isKnownNeverNaN();
+ Known = KnownLHS | KnownRHS;
// If either operand is not NaN, the result is not NaN.
if (NeverNaN && (IID == Intrinsic::minnum || IID == Intrinsic::maxnum))
Known.knownNot(fcNan);
+ if (IID == Intrinsic::maxnum) {
+ // If at least one operand is known to be positive, the result must be
+ // positive.
+ if ((KnownLHS.cannotBeOrderedLessThanZero() &&
+ KnownLHS.isKnownNeverNaN()) ||
+ (KnownRHS.cannotBeOrderedLessThanZero() &&
+ KnownRHS.isKnownNeverNaN()))
+ Known.knownNot(KnownFPClass::OrderedLessThanZeroMask);
+ } else if (IID == Intrinsic::maximum) {
+ // If at least one operand is known to be positive, the result must be
+ // positive.
+ if (KnownLHS.cannotBeOrderedLessThanZero() ||
+ KnownRHS.cannotBeOrderedLessThanZero())
+ Known.knownNot(KnownFPClass::OrderedLessThanZeroMask);
+ } else if (IID == Intrinsic::minnum) {
+ // If at least one operand is known to be negative, the result must be
+ // negative.
+ if ((KnownLHS.cannotBeOrderedGreaterThanZero() &&
+ KnownLHS.isKnownNeverNaN()) ||
+ (KnownRHS.cannotBeOrderedGreaterThanZero() &&
+ KnownRHS.isKnownNeverNaN()))
+ Known.knownNot(KnownFPClass::OrderedGreaterThanZeroMask);
+ } else {
+ // If at least one operand is known to be negative, the result must be
+ // negative.
+ if (KnownLHS.cannotBeOrderedGreaterThanZero() ||
+ KnownRHS.cannotBeOrderedGreaterThanZero())
+ Known.knownNot(KnownFPClass::OrderedGreaterThanZeroMask);
+ }
+
// Fixup zero handling if denormals could be returned as a zero.
//
// As there's no spec for denormal flushing, be conservative with the
diff --git a/llvm/test/Transforms/Attributor/nofpclass-minimum-maximum.ll b/llvm/test/Transforms/Attributor/nofpclass-minimum-maximum.ll
index 22a37facb0ff..09c7c4b3fb85 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-minimum-maximum.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-minimum-maximum.ll
@@ -365,9 +365,9 @@ define float @ret_minimum_any__noneg_nan(float %arg0, float nofpclass(ninf nsub
}
define float @ret_minimum_nopos_nan__any(float nofpclass(pinf psub pnorm nan) %arg0, float %arg1) #3 {
-; CHECK-LABEL: define float @ret_minimum_nopos_nan__any
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @ret_minimum_nopos_nan__any
; CHECK-SAME: (float nofpclass(nan pinf psub pnorm) [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR4]] {
-; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.minimum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(pinf psub pnorm) float @llvm.minimum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.minimum.f32(float %arg0, float %arg1)
@@ -375,9 +375,9 @@ define float @ret_minimum_nopos_nan__any(float nofpclass(pinf psub pnorm nan) %a
}
define float @ret_minimum_any__nopos_nan(float %arg0, float nofpclass(pinf psub pnorm nan) %arg1) #3 {
-; CHECK-LABEL: define float @ret_minimum_any__nopos_nan
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @ret_minimum_any__nopos_nan
; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(nan pinf psub pnorm) [[ARG1:%.*]]) #[[ATTR4]] {
-; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.minimum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(pinf psub pnorm) float @llvm.minimum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.minimum.f32(float %arg0, float %arg1)
@@ -405,9 +405,9 @@ define float @ret_minimum_any__noneg(float %arg0, float nofpclass(ninf nsub nnor
}
define float @ret_minimum_nopos__any(float nofpclass(pinf psub pnorm) %arg0, float %arg1) #3 {
-; CHECK-LABEL: define float @ret_minimum_nopos__any
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @ret_minimum_nopos__any
; CHECK-SAME: (float nofpclass(pinf psub pnorm) [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR4]] {
-; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.minimum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(pinf psub pnorm) float @llvm.minimum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.minimum.f32(float %arg0, float %arg1)
@@ -415,9 +415,9 @@ define float @ret_minimum_nopos__any(float nofpclass(pinf psub pnorm) %arg0, flo
}
define float @ret_minimum_any__nopos(float %arg0, float nofpclass(pinf psub pnorm) %arg1) #3 {
-; CHECK-LABEL: define float @ret_minimum_any__nopos
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @ret_minimum_any__nopos
; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(pinf psub pnorm) [[ARG1:%.*]]) #[[ATTR4]] {
-; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.minimum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(pinf psub pnorm) float @llvm.minimum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.minimum.f32(float %arg0, float %arg1)
@@ -425,9 +425,9 @@ define float @ret_minimum_any__nopos(float %arg0, float nofpclass(pinf psub pnor
}
define float @ret_maximum_noneg_nan__any(float nofpclass(ninf nsub nnorm nan) %arg0, float %arg1) #3 {
-; CHECK-LABEL: define float @ret_maximum_noneg_nan__any
+; CHECK-LABEL: define nofpclass(ninf nsub nnorm) float @ret_maximum_noneg_nan__any
; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR4]] {
-; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.maximum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nsub nnorm) float @llvm.maximum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.maximum.f32(float %arg0, float %arg1)
@@ -435,9 +435,9 @@ define float @ret_maximum_noneg_nan__any(float nofpclass(ninf nsub nnorm nan) %a
}
define float @ret_maximum_any__noneg_nan(float %arg0, float nofpclass(ninf nsub nnorm nan) %arg1) #3 {
-; CHECK-LABEL: define float @ret_maximum_any__noneg_nan
+; CHECK-LABEL: define nofpclass(ninf nsub nnorm) float @ret_maximum_any__noneg_nan
; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(nan ninf nsub nnorm) [[ARG1:%.*]]) #[[ATTR4]] {
-; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.maximum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nsub nnorm) float @llvm.maximum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.maximum.f32(float %arg0, float %arg1)
@@ -465,9 +465,9 @@ define float @ret_maximum_any__nopos_nan(float %arg0, float nofpclass(pinf psub
}
define float @ret_maximum_noneg__any(float nofpclass(ninf nsub nnorm) %arg0, float %arg1) #3 {
-; CHECK-LABEL: define float @ret_maximum_noneg__any
+; CHECK-LABEL: define nofpclass(ninf nsub nnorm) float @ret_maximum_noneg__any
; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR4]] {
-; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.maximum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nsub nnorm) float @llvm.maximum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.maximum.f32(float %arg0, float %arg1)
@@ -475,9 +475,9 @@ define float @ret_maximum_noneg__any(float nofpclass(ninf nsub nnorm) %arg0, flo
}
define float @ret_maximum_any__noneg(float %arg0, float nofpclass(ninf nsub nnorm) %arg1) #3 {
-; CHECK-LABEL: define float @ret_maximum_any__noneg
+; CHECK-LABEL: define nofpclass(ninf nsub nnorm) float @ret_maximum_any__noneg
; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(ninf nsub nnorm) [[ARG1:%.*]]) #[[ATTR4]] {
-; CHECK-NEXT: [[CALL:%.*]] = call float @llvm.maximum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nsub nnorm) float @llvm.maximum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.maximum.f32(float %arg0, float %arg1)
diff --git a/llvm/test/Transforms/Attributor/nofpclass-minnum-maxnum.ll b/llvm/test/Transforms/Attributor/nofpclass-minnum-maxnum.ll
index 049672b4a448..8be3d59a9b3b 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-minnum-maxnum.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-minnum-maxnum.ll
@@ -365,9 +365,9 @@ define float @ret_minnum_any__noneg_nan(float %arg0, float nofpclass(ninf nsub n
}
define float @ret_minnum_nopos_nan__any(float nofpclass(pinf psub pnorm nan) %arg0, float %arg1) #3 {
-; CHECK-LABEL: define nofpclass(nan) float @ret_minnum_nopos_nan__any
+; CHECK-LABEL: define nofpclass(nan pinf psub pnorm) float @ret_minnum_nopos_nan__any
; CHECK-SAME: (float nofpclass(nan pinf psub pnorm) [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR4]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan) float @llvm.minnum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan pinf psub pnorm) float @llvm.minnum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.minnum.f32(float %arg0, float %arg1)
@@ -375,9 +375,9 @@ define float @ret_minnum_nopos_nan__any(float nofpclass(pinf psub pnorm nan) %ar
}
define float @ret_minnum_any__nopos_nan(float %arg0, float nofpclass(pinf psub pnorm nan) %arg1) #3 {
-; CHECK-LABEL: define nofpclass(nan) float @ret_minnum_any__nopos_nan
+; CHECK-LABEL: define nofpclass(nan pinf psub pnorm) float @ret_minnum_any__nopos_nan
; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(nan pinf psub pnorm) [[ARG1:%.*]]) #[[ATTR4]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan) float @llvm.minnum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan pinf psub pnorm) float @llvm.minnum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.minnum.f32(float %arg0, float %arg1)
@@ -425,9 +425,9 @@ define float @ret_minnum_any__nopos(float %arg0, float nofpclass(pinf psub pnorm
}
define float @ret_maxnum_noneg_nan__any(float nofpclass(ninf nsub nnorm nan) %arg0, float %arg1) #3 {
-; CHECK-LABEL: define nofpclass(nan) float @ret_maxnum_noneg_nan__any
+; CHECK-LABEL: define nofpclass(nan ninf nsub nnorm) float @ret_maxnum_noneg_nan__any
; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR4]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan) float @llvm.maxnum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan ninf nsub nnorm) float @llvm.maxnum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.maxnum.f32(float %arg0, float %arg1)
@@ -435,9 +435,9 @@ define float @ret_maxnum_noneg_nan__any(float nofpclass(ninf nsub nnorm nan) %ar
}
define float @ret_maxnum_any__noneg_nan(float %arg0, float nofpclass(ninf nsub nnorm nan) %arg1) #3 {
-; CHECK-LABEL: define nofpclass(nan) float @ret_maxnum_any__noneg_nan
+; CHECK-LABEL: define nofpclass(nan ninf nsub nnorm) float @ret_maxnum_any__noneg_nan
; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(nan ninf nsub nnorm) [[ARG1:%.*]]) #[[ATTR4]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan) float @llvm.maxnum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan ninf nsub nnorm) float @llvm.maxnum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR9]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.maxnum.f32(float %arg0, float %arg1)
More information about the llvm-commits
mailing list