simplifyBinaryIntrinsic: Return nan if snan is passed maxnum/minnum#158470
Closed
simplifyBinaryIntrinsic: Return nan if snan is passed maxnum/minnum#158470
Conversation
Member
|
@llvm/pr-subscribers-backend-amdgpu @llvm/pr-subscribers-llvm-ir Author: YunQiang Su (wzssyqa) ChangesFixes: #138303 Full diff: https://github.com/llvm/llvm-project/pull/158470.diff 3 Files Affected:
diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h
index 2cb78904dd799..10cf451091198 100644
--- a/llvm/include/llvm/IR/PatternMatch.h
+++ b/llvm/include/llvm/IR/PatternMatch.h
@@ -707,9 +707,13 @@ m_SpecificInt_ICMP(ICmpInst::Predicate Predicate, const APInt &Threshold) {
struct is_nan {
bool isValue(const APFloat &C) const { return C.isNaN(); }
};
+struct is_snan {
+ bool isValue(const APFloat &C) const { return C.isSignaling(); }
+};
/// Match an arbitrary NaN constant. This includes quiet and signalling nans.
/// For vectors, this includes constants with undefined elements.
inline cstfp_pred_ty<is_nan> m_NaN() { return cstfp_pred_ty<is_nan>(); }
+inline cstfp_pred_ty<is_snan> m_SNaN() { return cstfp_pred_ty<is_snan>(); }
struct is_nonnan {
bool isValue(const APFloat &C) const { return !C.isNaN(); }
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 7bff13d59528c..cff8f6dfe8117 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -6735,12 +6735,17 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
bool PropagateNaN = IID == Intrinsic::minimum || IID == Intrinsic::maximum;
bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum;
- // minnum(X, nan) -> X
- // maxnum(X, nan) -> X
+ // minnum(X, qnan) -> X
+ // maxnum(X, qnan) -> X
+ // minnum(X, snan) -> nan
+ // maxnum(X, snan) -> nan
// minimum(X, nan) -> nan
// maximum(X, nan) -> nan
- if (match(Op1, m_NaN()))
- return PropagateNaN ? propagateNaN(cast<Constant>(Op1)) : Op0;
+ if (match(Op1, m_NaN())) {
+ if (PropagateNaN || match(Op1, m_SNaN()))
+ return propagateNaN(cast<Constant>(Op1));
+ return Op0;
+ }
// In the following folds, inf can be replaced with the largest finite
// float, if the ninf flag is set.
diff --git a/llvm/test/Transforms/EarlyCSE/commute.ll b/llvm/test/Transforms/EarlyCSE/commute.ll
index edafeccd3c8cc..3e1f9abb8bd99 100644
--- a/llvm/test/Transforms/EarlyCSE/commute.ll
+++ b/llvm/test/Transforms/EarlyCSE/commute.ll
@@ -830,6 +830,39 @@ define float @maxnum(float %a, float %b) {
ret float %r
}
+define float @maxnum_const_snan(float %x) {
+; CHECK-LABEL: @maxnum_const_snan(
+; CHECK-NEXT: ret float 0x7FFC000000000000
+;
+ %r = call float @llvm.minnum.f32(float %x, float 0x7FF4000000000000)
+ ret float %r
+}
+
+define double @minnum_const_snan(double %x) {
+; CHECK-LABEL: @minnum_const_snan(
+; CHECK-NEXT: ret double 0x7FFC000000000000
+;
+ %r = call double @llvm.minnum.f64(double %x, double 0x7FF4000000000000)
+ ret double %r
+}
+
+define float @maxnum_const_qnan(float %x) {
+; CHECK-LABEL: @maxnum_const_qnan(
+; CHECK-NEXT: ret float [[X:%.*]]
+;
+ %r = call float @llvm.minnum.f32(float %x, float 0x7FF8000000000000)
+ ret float %r
+}
+
+define double @minnum_const_qnan(double %x) {
+; CHECK-LABEL: @minnum_const_qnan(
+; CHECK-NEXT: ret double [[X:%.*]]
+;
+ %r = call double @llvm.minnum.f64(double %x, double 0x7FF8000000000000)
+ ret double %r
+}
+
+
define <2 x float> @minnum(<2 x float> %a, <2 x float> %b) {
; CHECK-LABEL: @minnum(
; CHECK-NEXT: [[X:%.*]] = call fast <2 x float> @llvm.minnum.v2f32(<2 x float> [[A:%.*]], <2 x float> [[B:%.*]])
|
Member
|
@llvm/pr-subscribers-llvm-transforms Author: YunQiang Su (wzssyqa) ChangesFixes: #138303 Full diff: https://github.com/llvm/llvm-project/pull/158470.diff 3 Files Affected:
diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h
index 2cb78904dd799..10cf451091198 100644
--- a/llvm/include/llvm/IR/PatternMatch.h
+++ b/llvm/include/llvm/IR/PatternMatch.h
@@ -707,9 +707,13 @@ m_SpecificInt_ICMP(ICmpInst::Predicate Predicate, const APInt &Threshold) {
struct is_nan {
bool isValue(const APFloat &C) const { return C.isNaN(); }
};
+struct is_snan {
+ bool isValue(const APFloat &C) const { return C.isSignaling(); }
+};
/// Match an arbitrary NaN constant. This includes quiet and signalling nans.
/// For vectors, this includes constants with undefined elements.
inline cstfp_pred_ty<is_nan> m_NaN() { return cstfp_pred_ty<is_nan>(); }
+inline cstfp_pred_ty<is_snan> m_SNaN() { return cstfp_pred_ty<is_snan>(); }
struct is_nonnan {
bool isValue(const APFloat &C) const { return !C.isNaN(); }
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 7bff13d59528c..cff8f6dfe8117 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -6735,12 +6735,17 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
bool PropagateNaN = IID == Intrinsic::minimum || IID == Intrinsic::maximum;
bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum;
- // minnum(X, nan) -> X
- // maxnum(X, nan) -> X
+ // minnum(X, qnan) -> X
+ // maxnum(X, qnan) -> X
+ // minnum(X, snan) -> nan
+ // maxnum(X, snan) -> nan
// minimum(X, nan) -> nan
// maximum(X, nan) -> nan
- if (match(Op1, m_NaN()))
- return PropagateNaN ? propagateNaN(cast<Constant>(Op1)) : Op0;
+ if (match(Op1, m_NaN())) {
+ if (PropagateNaN || match(Op1, m_SNaN()))
+ return propagateNaN(cast<Constant>(Op1));
+ return Op0;
+ }
// In the following folds, inf can be replaced with the largest finite
// float, if the ninf flag is set.
diff --git a/llvm/test/Transforms/EarlyCSE/commute.ll b/llvm/test/Transforms/EarlyCSE/commute.ll
index edafeccd3c8cc..3e1f9abb8bd99 100644
--- a/llvm/test/Transforms/EarlyCSE/commute.ll
+++ b/llvm/test/Transforms/EarlyCSE/commute.ll
@@ -830,6 +830,39 @@ define float @maxnum(float %a, float %b) {
ret float %r
}
+define float @maxnum_const_snan(float %x) {
+; CHECK-LABEL: @maxnum_const_snan(
+; CHECK-NEXT: ret float 0x7FFC000000000000
+;
+ %r = call float @llvm.minnum.f32(float %x, float 0x7FF4000000000000)
+ ret float %r
+}
+
+define double @minnum_const_snan(double %x) {
+; CHECK-LABEL: @minnum_const_snan(
+; CHECK-NEXT: ret double 0x7FFC000000000000
+;
+ %r = call double @llvm.minnum.f64(double %x, double 0x7FF4000000000000)
+ ret double %r
+}
+
+define float @maxnum_const_qnan(float %x) {
+; CHECK-LABEL: @maxnum_const_qnan(
+; CHECK-NEXT: ret float [[X:%.*]]
+;
+ %r = call float @llvm.minnum.f32(float %x, float 0x7FF8000000000000)
+ ret float %r
+}
+
+define double @minnum_const_qnan(double %x) {
+; CHECK-LABEL: @minnum_const_qnan(
+; CHECK-NEXT: ret double [[X:%.*]]
+;
+ %r = call double @llvm.minnum.f64(double %x, double 0x7FF8000000000000)
+ ret double %r
+}
+
+
define <2 x float> @minnum(<2 x float> %a, <2 x float> %b) {
; CHECK-LABEL: @minnum(
; CHECK-NEXT: [[X:%.*]] = call fast <2 x float> @llvm.minnum.v2f32(<2 x float> [[A:%.*]], <2 x float> [[B:%.*]])
|
Member
|
@llvm/pr-subscribers-llvm-analysis Author: YunQiang Su (wzssyqa) ChangesFixes: #138303 Full diff: https://github.com/llvm/llvm-project/pull/158470.diff 3 Files Affected:
diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h
index 2cb78904dd799..10cf451091198 100644
--- a/llvm/include/llvm/IR/PatternMatch.h
+++ b/llvm/include/llvm/IR/PatternMatch.h
@@ -707,9 +707,13 @@ m_SpecificInt_ICMP(ICmpInst::Predicate Predicate, const APInt &Threshold) {
struct is_nan {
bool isValue(const APFloat &C) const { return C.isNaN(); }
};
+struct is_snan {
+ bool isValue(const APFloat &C) const { return C.isSignaling(); }
+};
/// Match an arbitrary NaN constant. This includes quiet and signalling nans.
/// For vectors, this includes constants with undefined elements.
inline cstfp_pred_ty<is_nan> m_NaN() { return cstfp_pred_ty<is_nan>(); }
+inline cstfp_pred_ty<is_snan> m_SNaN() { return cstfp_pred_ty<is_snan>(); }
struct is_nonnan {
bool isValue(const APFloat &C) const { return !C.isNaN(); }
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 7bff13d59528c..cff8f6dfe8117 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -6735,12 +6735,17 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
bool PropagateNaN = IID == Intrinsic::minimum || IID == Intrinsic::maximum;
bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum;
- // minnum(X, nan) -> X
- // maxnum(X, nan) -> X
+ // minnum(X, qnan) -> X
+ // maxnum(X, qnan) -> X
+ // minnum(X, snan) -> nan
+ // maxnum(X, snan) -> nan
// minimum(X, nan) -> nan
// maximum(X, nan) -> nan
- if (match(Op1, m_NaN()))
- return PropagateNaN ? propagateNaN(cast<Constant>(Op1)) : Op0;
+ if (match(Op1, m_NaN())) {
+ if (PropagateNaN || match(Op1, m_SNaN()))
+ return propagateNaN(cast<Constant>(Op1));
+ return Op0;
+ }
// In the following folds, inf can be replaced with the largest finite
// float, if the ninf flag is set.
diff --git a/llvm/test/Transforms/EarlyCSE/commute.ll b/llvm/test/Transforms/EarlyCSE/commute.ll
index edafeccd3c8cc..3e1f9abb8bd99 100644
--- a/llvm/test/Transforms/EarlyCSE/commute.ll
+++ b/llvm/test/Transforms/EarlyCSE/commute.ll
@@ -830,6 +830,39 @@ define float @maxnum(float %a, float %b) {
ret float %r
}
+define float @maxnum_const_snan(float %x) {
+; CHECK-LABEL: @maxnum_const_snan(
+; CHECK-NEXT: ret float 0x7FFC000000000000
+;
+ %r = call float @llvm.minnum.f32(float %x, float 0x7FF4000000000000)
+ ret float %r
+}
+
+define double @minnum_const_snan(double %x) {
+; CHECK-LABEL: @minnum_const_snan(
+; CHECK-NEXT: ret double 0x7FFC000000000000
+;
+ %r = call double @llvm.minnum.f64(double %x, double 0x7FF4000000000000)
+ ret double %r
+}
+
+define float @maxnum_const_qnan(float %x) {
+; CHECK-LABEL: @maxnum_const_qnan(
+; CHECK-NEXT: ret float [[X:%.*]]
+;
+ %r = call float @llvm.minnum.f32(float %x, float 0x7FF8000000000000)
+ ret float %r
+}
+
+define double @minnum_const_qnan(double %x) {
+; CHECK-LABEL: @minnum_const_qnan(
+; CHECK-NEXT: ret double [[X:%.*]]
+;
+ %r = call double @llvm.minnum.f64(double %x, double 0x7FF8000000000000)
+ ret double %r
+}
+
+
define <2 x float> @minnum(<2 x float> %a, <2 x float> %b) {
; CHECK-LABEL: @minnum(
; CHECK-NEXT: [[X:%.*]] = call fast <2 x float> @llvm.minnum.v2f32(<2 x float> [[A:%.*]], <2 x float> [[B:%.*]])
|
arsenm
reviewed
Sep 15, 2025
Contributor
Author
|
@arsenm ping. |
arsenm
reviewed
Oct 10, 2025
| if (match(Op1, m_NaN())) | ||
| if (match(Op1, m_QNaN())) | ||
| return PropagateNaN ? propagateNaN(cast<Constant>(Op1)) : Op0; | ||
| else if (match(Op1, m_SNaN())) |
Contributor
There was a problem hiding this comment.
Can you add a todo about the mixed non-splat case
Contributor
Author
|
See #168838 |
Contributor
|
Some version of this should be brought back |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes: #138303