-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[ConstantFolding] Fold maximumnum and minimumnum #138700
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-llvm-transforms Author: Lewis Crawford (LewisCrawford) ChangesAdd constant-folding support for the fmaximumnum and fminimumnum intrinsics, and extend the tests to show the qnan vs snan behavior differences between maxnum/maximum/maximumnum. Full diff: https://github.com/llvm/llvm-project/pull/138700.diff 3 Files Affected:
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index 5b329e2f898f3..412a0e8979193 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -1642,6 +1642,8 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {
case Intrinsic::maxnum:
case Intrinsic::minimum:
case Intrinsic::maximum:
+ case Intrinsic::minimumnum:
+ case Intrinsic::maximumnum:
case Intrinsic::log:
case Intrinsic::log2:
case Intrinsic::log10:
@@ -2930,6 +2932,8 @@ static Constant *ConstantFoldIntrinsicCall2(Intrinsic::ID IntrinsicID, Type *Ty,
case Intrinsic::minnum:
case Intrinsic::maximum:
case Intrinsic::minimum:
+ case Intrinsic::maximumnum:
+ case Intrinsic::minimumnum:
case Intrinsic::nvvm_fmax_d:
case Intrinsic::nvvm_fmin_d:
// If one argument is undef, return the other argument.
@@ -3030,6 +3034,10 @@ static Constant *ConstantFoldIntrinsicCall2(Intrinsic::ID IntrinsicID, Type *Ty,
return ConstantFP::get(Ty->getContext(), minimum(Op1V, Op2V));
case Intrinsic::maximum:
return ConstantFP::get(Ty->getContext(), maximum(Op1V, Op2V));
+ case Intrinsic::minimumnum:
+ return ConstantFP::get(Ty->getContext(), minimumnum(Op1V, Op2V));
+ case Intrinsic::maximumnum:
+ return ConstantFP::get(Ty->getContext(), maximumnum(Op1V, Op2V));
case Intrinsic::nvvm_fmax_d:
case Intrinsic::nvvm_fmax_f:
diff --git a/llvm/test/Transforms/InstSimplify/ConstProp/fp-undef.ll b/llvm/test/Transforms/InstSimplify/ConstProp/fp-undef.ll
index 6fa57a8a1467a..51988583ab1ac 100644
--- a/llvm/test/Transforms/InstSimplify/ConstProp/fp-undef.ll
+++ b/llvm/test/Transforms/InstSimplify/ConstProp/fp-undef.ll
@@ -5,6 +5,8 @@ declare <2 x double> @llvm.minnum.v2f64(<2 x double>, <2 x double>)
declare <2 x double> @llvm.maxnum.v2f64(<2 x double>, <2 x double>)
declare <2 x double> @llvm.minimum.v2f64(<2 x double>, <2 x double>)
declare <2 x double> @llvm.maximum.v2f64(<2 x double>, <2 x double>)
+declare <2 x double> @llvm.minimumnum.v2f64(<2 x double>, <2 x double>)
+declare <2 x double> @llvm.maximumnum.v2f64(<2 x double>, <2 x double>)
; Constant folding - undef undef.
@@ -538,6 +540,38 @@ define <2 x double> @frem_undef_op0_constant_vec(<2 x double> %x) {
ret <2 x double> %r
}
+define <2 x double> @maximumnum_nan_op0_vec_partial_undef_op1_undef(<2 x double> %x) {
+; CHECK-LABEL: @maximumnum_nan_op0_vec_partial_undef_op1_undef(
+; CHECK-NEXT: ret <2 x double> <double 0x7FF8000000000000, double undef>
+;
+ %r = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> <double 0x7ff8000000000000, double undef>, <2 x double> undef)
+ ret <2 x double> %r
+}
+
+define <2 x double> @maximumnum_nan_op1_vec_partial_undef_op0_undef(<2 x double> %x) {
+; CHECK-LABEL: @maximumnum_nan_op1_vec_partial_undef_op0_undef(
+; CHECK-NEXT: ret <2 x double> <double 0x7FF8000000000000, double undef>
+;
+ %r = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> undef, <2 x double> <double 0x7ff8000000000000, double undef>)
+ ret <2 x double> %r
+}
+
+define <2 x double> @minimumnum_nan_op0_vec_partial_undef_op1_undef(<2 x double> %x) {
+; CHECK-LABEL: @minimumnum_nan_op0_vec_partial_undef_op1_undef(
+; CHECK-NEXT: ret <2 x double> <double 0x7FF8000000000000, double undef>
+;
+ %r = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> <double 0x7ff8000000000000, double undef>, <2 x double> undef)
+ ret <2 x double> %r
+}
+
+define <2 x double> @minimumnum_nan_op1_vec_partial_undef_op0_undef(<2 x double> %x) {
+; CHECK-LABEL: @minimumnum_nan_op1_vec_partial_undef_op0_undef(
+; CHECK-NEXT: ret <2 x double> <double 0x7FF8000000000000, double undef>
+;
+ %r = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> undef, <2 x double> <double 0x7ff8000000000000, double undef>)
+ ret <2 x double> %r
+}
+
define <2 x double> @maximum_nan_op0_vec_partial_undef_op1_undef(<2 x double> %x) {
; CHECK-LABEL: @maximum_nan_op0_vec_partial_undef_op1_undef(
; CHECK-NEXT: ret <2 x double> <double 0x7FF8000000000000, double undef>
diff --git a/llvm/test/Transforms/InstSimplify/ConstProp/min-max.ll b/llvm/test/Transforms/InstSimplify/ConstProp/min-max.ll
index 9120649eb5c4f..a633d29179896 100644
--- a/llvm/test/Transforms/InstSimplify/ConstProp/min-max.ll
+++ b/llvm/test/Transforms/InstSimplify/ConstProp/min-max.ll
@@ -29,6 +29,20 @@ declare <4 x float> @llvm.maximum.v4f32(<4 x float>, <4 x float>)
declare <4 x bfloat> @llvm.maximum.v4bf16(<4 x bfloat>, <4 x bfloat>)
declare <4 x half> @llvm.maximum.v4f16(<4 x half>, <4 x half>)
+declare float @llvm.minimumnum.f32(float, float)
+declare bfloat @llvm.minimumnum.bf16(bfloat, bfloat)
+declare half @llvm.minimumnum.f16(half, half)
+declare <4 x float> @llvm.minimumnum.v4f32(<4 x float>, <4 x float>)
+declare <4 x bfloat> @llvm.minimumnum.v4bf16(<4 x bfloat>, <4 x bfloat>)
+declare <4 x half> @llvm.minimumnum.v4f16(<4 x half>, <4 x half>)
+
+declare float @llvm.maximumnum.f32(float, float)
+declare bfloat @llvm.maximumnum.bf16(bfloat, bfloat)
+declare half @llvm.maximumnum.f16(half, half)
+declare <4 x float> @llvm.maximumnum.v4f32(<4 x float>, <4 x float>)
+declare <4 x bfloat> @llvm.maximumnum.v4bf16(<4 x bfloat>, <4 x bfloat>)
+declare <4 x half> @llvm.maximumnum.v4f16(<4 x half>, <4 x half>)
+
declare i8 @llvm.smax.i8(i8, i8)
declare <5 x i8> @llvm.smax.v5i8(<5 x i8>, <5 x i8>)
@@ -81,6 +95,22 @@ define float @minnum_float_qnan_p0() {
ret float %min
}
+define float @minnum_float_p0_snan() {
+; CHECK-LABEL: @minnum_float_p0_snan(
+; CHECK-NEXT: ret float 0x7FFC000000000000
+;
+ %min = call float @llvm.minnum.f32(float 0.0, float 0x7FF4000000000000)
+ ret float %min
+}
+
+define float @minnum_float_snan_p0() {
+; CHECK-LABEL: @minnum_float_snan_p0(
+; CHECK-NEXT: ret float 0x7FFC000000000000
+;
+ %min = call float @llvm.minnum.f32(float 0x7FF4000000000000, float 0.0)
+ ret float %min
+}
+
define bfloat @minnum_bfloat() {
; CHECK-LABEL: @minnum_bfloat(
; CHECK-NEXT: ret bfloat 0xR40A0
@@ -173,6 +203,22 @@ define float @maxnum_float_qnan_p0() {
ret float %max
}
+define float @maxnum_float_p0_snan() {
+; CHECK-LABEL: @maxnum_float_p0_snan(
+; CHECK-NEXT: ret float 0x7FFC000000000000
+;
+ %max = call float @llvm.maxnum.f32(float 0.0, float 0x7FF4000000000000)
+ ret float %max
+}
+
+define float @maxnum_float_snan_p0() {
+; CHECK-LABEL: @maxnum_float_snan_p0(
+; CHECK-NEXT: ret float 0x7FFC000000000000
+;
+ %max = call float @llvm.maxnum.f32(float 0x7FF4000000000000, float 0.0)
+ ret float %max
+}
+
define bfloat @maxnum_bfloat() {
; CHECK-LABEL: @maxnum_bfloat(
; CHECK-NEXT: ret bfloat 0xR4228
@@ -249,6 +295,38 @@ define half @minimum_half() {
ret half %1
}
+define float @minimum_float_p0_qnan() {
+; CHECK-LABEL: @minimum_float_p0_qnan(
+; CHECK-NEXT: ret float 0x7FF8000000000000
+;
+ %max = call float @llvm.minimum.f32(float 0.0, float 0x7FF8000000000000)
+ ret float %max
+}
+
+define float @minimum_float_qnan_p0() {
+; CHECK-LABEL: @minimum_float_qnan_p0(
+; CHECK-NEXT: ret float 0x7FF8000000000000
+;
+ %max = call float @llvm.minimum.f32(float 0x7FF8000000000000, float 0.0)
+ ret float %max
+}
+
+define float @minimum_float_p0_snan() {
+; CHECK-LABEL: @minimum_float_p0_snan(
+; CHECK-NEXT: ret float 0x7FFC000000000000
+;
+ %max = call float @llvm.minimum.f32(float 0.0, float 0x7FF4000000000000)
+ ret float %max
+}
+
+define float @minimum_float_snan_p0() {
+; CHECK-LABEL: @minimum_float_snan_p0(
+; CHECK-NEXT: ret float 0x7FFC000000000000
+;
+ %max = call float @llvm.minimum.f32(float 0x7FF4000000000000, float 0.0)
+ ret float %max
+}
+
; Check that minimum propagates its NaN or smaller argument
define <4 x float> @minimum_float_vec() {
@@ -309,6 +387,38 @@ define half @maximum_half() {
ret half %1
}
+define float @maximum_float_p0_qnan() {
+; CHECK-LABEL: @maximum_float_p0_qnan(
+; CHECK-NEXT: ret float 0x7FF8000000000000
+;
+ %max = call float @llvm.maximum.f32(float 0.0, float 0x7FF8000000000000)
+ ret float %max
+}
+
+define float @maximum_float_qnan_p0() {
+; CHECK-LABEL: @maximum_float_qnan_p0(
+; CHECK-NEXT: ret float 0x7FF8000000000000
+;
+ %max = call float @llvm.maximum.f32(float 0x7FF8000000000000, float 0.0)
+ ret float %max
+}
+
+define float @maximum_float_p0_snan() {
+; CHECK-LABEL: @maximum_float_p0_snan(
+; CHECK-NEXT: ret float 0x7FFC000000000000
+;
+ %max = call float @llvm.maximum.f32(float 0.0, float 0x7FF4000000000000)
+ ret float %max
+}
+
+define float @maximum_float_snan_p0() {
+; CHECK-LABEL: @maximum_float_snan_p0(
+; CHECK-NEXT: ret float 0x7FFC000000000000
+;
+ %max = call float @llvm.maximum.f32(float 0x7FF4000000000000, float 0.0)
+ ret float %max
+}
+
; Check that maximum propagates its NaN or greater argument
define <4 x float> @maximum_float_vec() {
@@ -345,6 +455,222 @@ define <4 x float> @maximum_float_zeros_vec() {
ret <4 x float> %1
}
+define float @minimumnum_float() {
+; CHECK-LABEL: @minimumnum_float(
+; CHECK-NEXT: ret float 5.000000e+00
+;
+ %1 = call float @llvm.minimumnum.f32(float 5.0, float 42.0)
+ ret float %1
+}
+
+define float @minimumnum_float_p0_n0() {
+; CHECK-LABEL: @minimumnum_float_p0_n0(
+; CHECK-NEXT: ret float -0.000000e+00
+;
+ %min = call float @llvm.minimumnum.f32(float 0.0, float -0.0)
+ ret float %min
+}
+
+define float @minimumnum_float_n0_p0() {
+; CHECK-LABEL: @minimumnum_float_n0_p0(
+; CHECK-NEXT: ret float -0.000000e+00
+;
+ %min = call float @llvm.minimumnum.f32(float -0.0, float 0.0)
+ ret float %min
+}
+
+define float @minimumnum_float_p0_qnan() {
+; CHECK-LABEL: @minimumnum_float_p0_qnan(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %min = call float @llvm.minimumnum.f32(float 0.0, float 0x7FF8000000000000)
+ ret float %min
+}
+
+define float @minimumnum_float_qnan_p0() {
+; CHECK-LABEL: @minimumnum_float_qnan_p0(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %min = call float @llvm.minimumnum.f32(float 0x7FF8000000000000, float 0.0)
+ ret float %min
+}
+
+define float @minimumnum_float_p0_snan() {
+; CHECK-LABEL: @minimumnum_float_p0_snan(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %min = call float @llvm.minimumnum.f32(float 0.0, float 0x7FF4000000000000)
+ ret float %min
+}
+
+define float @minimumnum_float_snan_p0() {
+; CHECK-LABEL: @minimumnum_float_snan_p0(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %min = call float @llvm.minimumnum.f32(float 0x7FF4000000000000, float 0.0)
+ ret float %min
+}
+
+define bfloat @minimumnum_bfloat() {
+; CHECK-LABEL: @minimumnum_bfloat(
+; CHECK-NEXT: ret bfloat 0xR40A0
+;
+ %1 = call bfloat @llvm.minimumnum.bf16(bfloat 5.0, bfloat 42.0)
+ ret bfloat %1
+}
+
+define half @minimumnum_half() {
+; CHECK-LABEL: @minimumnum_half(
+; CHECK-NEXT: ret half 0xH4500
+;
+ %1 = call half @llvm.minimumnum.f16(half 5.0, half 42.0)
+ ret half %1
+}
+
+; Check that minimumnum propagates its non-NaN or smaller argument
+
+define <4 x float> @minimumnum_float_vec() {
+; CHECK-LABEL: @minimumnum_float_vec(
+; CHECK-NEXT: ret <4 x float> <float 0x7FF8000000000000, float 5.000000e+00, float 4.200000e+01, float 5.000000e+00>
+;
+ %1 = call <4 x float> @llvm.minimumnum.v4f32(<4 x float> <float 0x7FF8000000000000, float 0x7FF8000000000000, float 42., float 42.>, <4 x float> <float 0x7FF8000000000000, float 5., float 0x7FF8000000000000, float 5.>)
+ ret <4 x float> %1
+}
+
+define <4 x bfloat> @minimumnum_bfloat_vec() {
+; CHECK-LABEL: @minimumnum_bfloat_vec(
+; CHECK-NEXT: ret <4 x bfloat> <bfloat 0xR7FC0, bfloat 0xR40A0, bfloat 0xR4228, bfloat 0xR40A0>
+;
+ %1 = call <4 x bfloat> @llvm.minimumnum.v4bf16(<4 x bfloat> <bfloat 0x7FF8000000000000, bfloat 0x7FF8000000000000, bfloat 42., bfloat 42.>, <4 x bfloat> <bfloat 0x7FF8000000000000, bfloat 5., bfloat 0x7FF8000000000000, bfloat 5.>)
+ ret <4 x bfloat> %1
+}
+
+define <4 x half> @minimumnum_half_vec() {
+; CHECK-LABEL: @minimumnum_half_vec(
+; CHECK-NEXT: ret <4 x half> <half 0xH7E00, half 0xH4500, half 0xH5140, half 0xH4500>
+;
+ %1 = call <4 x half> @llvm.minimumnum.v4f16(<4 x half> <half 0x7FF8000000000000, half 0x7FF8000000000000, half 42., half 42.>, <4 x half> <half 0x7FF8000000000000, half 5., half 0x7FF8000000000000, half 5.>)
+ ret <4 x half> %1
+}
+
+; Check that minimumnum treats -0.0 as smaller than 0.0 while constant folding
+
+define <4 x float> @minimumnum_float_zeros_vec() {
+; CHECK-LABEL: @minimumnum_float_zeros_vec(
+; CHECK-NEXT: ret <4 x float> <float 0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>
+;
+ %1 = call <4 x float> @llvm.minimumnum.v4f32(<4 x float> <float 0.0, float -0.0, float 0.0, float -0.0>, <4 x float> <float 0.0, float 0.0, float -0.0, float -0.0>)
+ ret <4 x float> %1
+}
+
+define float @maximumnum_float() {
+; CHECK-LABEL: @maximumnum_float(
+; CHECK-NEXT: ret float 4.200000e+01
+;
+ %1 = call float @llvm.maximumnum.f32(float 5.0, float 42.0)
+ ret float %1
+}
+
+define bfloat @maximumnum_bfloat() {
+; CHECK-LABEL: @maximumnum_bfloat(
+; CHECK-NEXT: ret bfloat 0xR4228
+;
+ %1 = call bfloat @llvm.maximumnum.bf16(bfloat 5.0, bfloat 42.0)
+ ret bfloat %1
+}
+
+define half @maximumnum_half() {
+; CHECK-LABEL: @maximumnum_half(
+; CHECK-NEXT: ret half 0xH5140
+;
+ %1 = call half @llvm.maximumnum.f16(half 5.0, half 42.0)
+ ret half %1
+}
+
+define float @maximumnum_float_p0_n0() {
+; CHECK-LABEL: @maximumnum_float_p0_n0(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %max = call float @llvm.maximumnum.f32(float 0.0, float -0.0)
+ ret float %max
+}
+
+define float @maximumnum_float_n0_p0() {
+; CHECK-LABEL: @maximumnum_float_n0_p0(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %max = call float @llvm.maximumnum.f32(float -0.0, float 0.0)
+ ret float %max
+}
+
+define float @maximumnum_float_p0_qnan() {
+; CHECK-LABEL: @maximumnum_float_p0_qnan(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %max = call float @llvm.maximumnum.f32(float 0.0, float 0x7FF8000000000000)
+ ret float %max
+}
+
+define float @maximumnum_float_qnan_p0() {
+; CHECK-LABEL: @maximumnum_float_qnan_p0(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %max = call float @llvm.maximumnum.f32(float 0x7FF8000000000000, float 0.0)
+ ret float %max
+}
+
+define float @maximumnum_float_p0_snan() {
+; CHECK-LABEL: @maximumnum_float_p0_snan(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %max = call float @llvm.maximumnum.f32(float 0.0, float 0x7FF4000000000000)
+ ret float %max
+}
+
+define float @maximumnum_float_snan_p0() {
+; CHECK-LABEL: @maximumnum_float_snan_p0(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %max = call float @llvm.maximumnum.f32(float 0x7FF4000000000000, float 0.0)
+ ret float %max
+}
+
+; Check that maximumnum propagates its non-NaN or greater argument
+
+define <4 x float> @maximumnum_float_vec() {
+; CHECK-LABEL: @maximumnum_float_vec(
+; CHECK-NEXT: ret <4 x float> <float 0x7FF8000000000000, float 5.000000e+00, float 4.200000e+01, float 4.200000e+01>
+;
+ %1 = call <4 x float> @llvm.maximumnum.v4f32(<4 x float> <float 0x7FF8000000000000, float 0x7FF8000000000000, float 42., float 42.>, <4 x float> <float 0x7FF8000000000000, float 5., float 0x7FF8000000000000, float 5.>)
+ ret <4 x float> %1
+}
+
+define <4 x bfloat> @maximumnum_bfloat_vec() {
+; CHECK-LABEL: @maximumnum_bfloat_vec(
+; CHECK-NEXT: ret <4 x bfloat> <bfloat 0xR7FC0, bfloat 0xR40A0, bfloat 0xR4228, bfloat 0xR4228>
+;
+ %1 = call <4 x bfloat> @llvm.maximumnum.v4bf16(<4 x bfloat> <bfloat 0x7FF8000000000000, bfloat 0x7FF8000000000000, bfloat 42., bfloat 42.>, <4 x bfloat> <bfloat 0x7FF8000000000000, bfloat 5., bfloat 0x7FF8000000000000, bfloat 5.>)
+ ret <4 x bfloat> %1
+}
+
+define <4 x half> @maximumnum_half_vec() {
+; CHECK-LABEL: @maximumnum_half_vec(
+; CHECK-NEXT: ret <4 x half> <half 0xH7E00, half 0xH4500, half 0xH5140, half 0xH5140>
+;
+ %1 = call <4 x half> @llvm.maximumnum.v4f16(<4 x half> <half 0x7FF8000000000000, half 0x7FF8000000000000, half 42., half 42.>, <4 x half> <half 0x7FF8000000000000, half 5., half 0x7FF8000000000000, half 5.>)
+ ret <4 x half> %1
+}
+
+; Check that maximumnum treats -0.0 as smaller than 0.0 while constant folding
+
+define <4 x float> @maximumnum_float_zeros_vec() {
+; CHECK-LABEL: @maximumnum_float_zeros_vec(
+; CHECK-NEXT: ret <4 x float> <float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float -0.000000e+00>
+;
+ %1 = call <4 x float> @llvm.maximumnum.v4f32(<4 x float> <float 0.0, float -0.0, float 0.0, float -0.0>, <4 x float> <float 0.0, float 0.0, float -0.0, float -0.0>)
+ ret <4 x float> %1
+}
+
define i8 @smax() {
; CHECK-LABEL: @smax(
; CHECK-NEXT: ret i8 -127
|
@llvm/pr-subscribers-llvm-analysis Author: Lewis Crawford (LewisCrawford) ChangesAdd constant-folding support for the fmaximumnum and fminimumnum intrinsics, and extend the tests to show the qnan vs snan behavior differences between maxnum/maximum/maximumnum. Full diff: https://github.com/llvm/llvm-project/pull/138700.diff 3 Files Affected:
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index 5b329e2f898f3..412a0e8979193 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -1642,6 +1642,8 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {
case Intrinsic::maxnum:
case Intrinsic::minimum:
case Intrinsic::maximum:
+ case Intrinsic::minimumnum:
+ case Intrinsic::maximumnum:
case Intrinsic::log:
case Intrinsic::log2:
case Intrinsic::log10:
@@ -2930,6 +2932,8 @@ static Constant *ConstantFoldIntrinsicCall2(Intrinsic::ID IntrinsicID, Type *Ty,
case Intrinsic::minnum:
case Intrinsic::maximum:
case Intrinsic::minimum:
+ case Intrinsic::maximumnum:
+ case Intrinsic::minimumnum:
case Intrinsic::nvvm_fmax_d:
case Intrinsic::nvvm_fmin_d:
// If one argument is undef, return the other argument.
@@ -3030,6 +3034,10 @@ static Constant *ConstantFoldIntrinsicCall2(Intrinsic::ID IntrinsicID, Type *Ty,
return ConstantFP::get(Ty->getContext(), minimum(Op1V, Op2V));
case Intrinsic::maximum:
return ConstantFP::get(Ty->getContext(), maximum(Op1V, Op2V));
+ case Intrinsic::minimumnum:
+ return ConstantFP::get(Ty->getContext(), minimumnum(Op1V, Op2V));
+ case Intrinsic::maximumnum:
+ return ConstantFP::get(Ty->getContext(), maximumnum(Op1V, Op2V));
case Intrinsic::nvvm_fmax_d:
case Intrinsic::nvvm_fmax_f:
diff --git a/llvm/test/Transforms/InstSimplify/ConstProp/fp-undef.ll b/llvm/test/Transforms/InstSimplify/ConstProp/fp-undef.ll
index 6fa57a8a1467a..51988583ab1ac 100644
--- a/llvm/test/Transforms/InstSimplify/ConstProp/fp-undef.ll
+++ b/llvm/test/Transforms/InstSimplify/ConstProp/fp-undef.ll
@@ -5,6 +5,8 @@ declare <2 x double> @llvm.minnum.v2f64(<2 x double>, <2 x double>)
declare <2 x double> @llvm.maxnum.v2f64(<2 x double>, <2 x double>)
declare <2 x double> @llvm.minimum.v2f64(<2 x double>, <2 x double>)
declare <2 x double> @llvm.maximum.v2f64(<2 x double>, <2 x double>)
+declare <2 x double> @llvm.minimumnum.v2f64(<2 x double>, <2 x double>)
+declare <2 x double> @llvm.maximumnum.v2f64(<2 x double>, <2 x double>)
; Constant folding - undef undef.
@@ -538,6 +540,38 @@ define <2 x double> @frem_undef_op0_constant_vec(<2 x double> %x) {
ret <2 x double> %r
}
+define <2 x double> @maximumnum_nan_op0_vec_partial_undef_op1_undef(<2 x double> %x) {
+; CHECK-LABEL: @maximumnum_nan_op0_vec_partial_undef_op1_undef(
+; CHECK-NEXT: ret <2 x double> <double 0x7FF8000000000000, double undef>
+;
+ %r = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> <double 0x7ff8000000000000, double undef>, <2 x double> undef)
+ ret <2 x double> %r
+}
+
+define <2 x double> @maximumnum_nan_op1_vec_partial_undef_op0_undef(<2 x double> %x) {
+; CHECK-LABEL: @maximumnum_nan_op1_vec_partial_undef_op0_undef(
+; CHECK-NEXT: ret <2 x double> <double 0x7FF8000000000000, double undef>
+;
+ %r = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> undef, <2 x double> <double 0x7ff8000000000000, double undef>)
+ ret <2 x double> %r
+}
+
+define <2 x double> @minimumnum_nan_op0_vec_partial_undef_op1_undef(<2 x double> %x) {
+; CHECK-LABEL: @minimumnum_nan_op0_vec_partial_undef_op1_undef(
+; CHECK-NEXT: ret <2 x double> <double 0x7FF8000000000000, double undef>
+;
+ %r = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> <double 0x7ff8000000000000, double undef>, <2 x double> undef)
+ ret <2 x double> %r
+}
+
+define <2 x double> @minimumnum_nan_op1_vec_partial_undef_op0_undef(<2 x double> %x) {
+; CHECK-LABEL: @minimumnum_nan_op1_vec_partial_undef_op0_undef(
+; CHECK-NEXT: ret <2 x double> <double 0x7FF8000000000000, double undef>
+;
+ %r = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> undef, <2 x double> <double 0x7ff8000000000000, double undef>)
+ ret <2 x double> %r
+}
+
define <2 x double> @maximum_nan_op0_vec_partial_undef_op1_undef(<2 x double> %x) {
; CHECK-LABEL: @maximum_nan_op0_vec_partial_undef_op1_undef(
; CHECK-NEXT: ret <2 x double> <double 0x7FF8000000000000, double undef>
diff --git a/llvm/test/Transforms/InstSimplify/ConstProp/min-max.ll b/llvm/test/Transforms/InstSimplify/ConstProp/min-max.ll
index 9120649eb5c4f..a633d29179896 100644
--- a/llvm/test/Transforms/InstSimplify/ConstProp/min-max.ll
+++ b/llvm/test/Transforms/InstSimplify/ConstProp/min-max.ll
@@ -29,6 +29,20 @@ declare <4 x float> @llvm.maximum.v4f32(<4 x float>, <4 x float>)
declare <4 x bfloat> @llvm.maximum.v4bf16(<4 x bfloat>, <4 x bfloat>)
declare <4 x half> @llvm.maximum.v4f16(<4 x half>, <4 x half>)
+declare float @llvm.minimumnum.f32(float, float)
+declare bfloat @llvm.minimumnum.bf16(bfloat, bfloat)
+declare half @llvm.minimumnum.f16(half, half)
+declare <4 x float> @llvm.minimumnum.v4f32(<4 x float>, <4 x float>)
+declare <4 x bfloat> @llvm.minimumnum.v4bf16(<4 x bfloat>, <4 x bfloat>)
+declare <4 x half> @llvm.minimumnum.v4f16(<4 x half>, <4 x half>)
+
+declare float @llvm.maximumnum.f32(float, float)
+declare bfloat @llvm.maximumnum.bf16(bfloat, bfloat)
+declare half @llvm.maximumnum.f16(half, half)
+declare <4 x float> @llvm.maximumnum.v4f32(<4 x float>, <4 x float>)
+declare <4 x bfloat> @llvm.maximumnum.v4bf16(<4 x bfloat>, <4 x bfloat>)
+declare <4 x half> @llvm.maximumnum.v4f16(<4 x half>, <4 x half>)
+
declare i8 @llvm.smax.i8(i8, i8)
declare <5 x i8> @llvm.smax.v5i8(<5 x i8>, <5 x i8>)
@@ -81,6 +95,22 @@ define float @minnum_float_qnan_p0() {
ret float %min
}
+define float @minnum_float_p0_snan() {
+; CHECK-LABEL: @minnum_float_p0_snan(
+; CHECK-NEXT: ret float 0x7FFC000000000000
+;
+ %min = call float @llvm.minnum.f32(float 0.0, float 0x7FF4000000000000)
+ ret float %min
+}
+
+define float @minnum_float_snan_p0() {
+; CHECK-LABEL: @minnum_float_snan_p0(
+; CHECK-NEXT: ret float 0x7FFC000000000000
+;
+ %min = call float @llvm.minnum.f32(float 0x7FF4000000000000, float 0.0)
+ ret float %min
+}
+
define bfloat @minnum_bfloat() {
; CHECK-LABEL: @minnum_bfloat(
; CHECK-NEXT: ret bfloat 0xR40A0
@@ -173,6 +203,22 @@ define float @maxnum_float_qnan_p0() {
ret float %max
}
+define float @maxnum_float_p0_snan() {
+; CHECK-LABEL: @maxnum_float_p0_snan(
+; CHECK-NEXT: ret float 0x7FFC000000000000
+;
+ %max = call float @llvm.maxnum.f32(float 0.0, float 0x7FF4000000000000)
+ ret float %max
+}
+
+define float @maxnum_float_snan_p0() {
+; CHECK-LABEL: @maxnum_float_snan_p0(
+; CHECK-NEXT: ret float 0x7FFC000000000000
+;
+ %max = call float @llvm.maxnum.f32(float 0x7FF4000000000000, float 0.0)
+ ret float %max
+}
+
define bfloat @maxnum_bfloat() {
; CHECK-LABEL: @maxnum_bfloat(
; CHECK-NEXT: ret bfloat 0xR4228
@@ -249,6 +295,38 @@ define half @minimum_half() {
ret half %1
}
+define float @minimum_float_p0_qnan() {
+; CHECK-LABEL: @minimum_float_p0_qnan(
+; CHECK-NEXT: ret float 0x7FF8000000000000
+;
+ %max = call float @llvm.minimum.f32(float 0.0, float 0x7FF8000000000000)
+ ret float %max
+}
+
+define float @minimum_float_qnan_p0() {
+; CHECK-LABEL: @minimum_float_qnan_p0(
+; CHECK-NEXT: ret float 0x7FF8000000000000
+;
+ %max = call float @llvm.minimum.f32(float 0x7FF8000000000000, float 0.0)
+ ret float %max
+}
+
+define float @minimum_float_p0_snan() {
+; CHECK-LABEL: @minimum_float_p0_snan(
+; CHECK-NEXT: ret float 0x7FFC000000000000
+;
+ %max = call float @llvm.minimum.f32(float 0.0, float 0x7FF4000000000000)
+ ret float %max
+}
+
+define float @minimum_float_snan_p0() {
+; CHECK-LABEL: @minimum_float_snan_p0(
+; CHECK-NEXT: ret float 0x7FFC000000000000
+;
+ %max = call float @llvm.minimum.f32(float 0x7FF4000000000000, float 0.0)
+ ret float %max
+}
+
; Check that minimum propagates its NaN or smaller argument
define <4 x float> @minimum_float_vec() {
@@ -309,6 +387,38 @@ define half @maximum_half() {
ret half %1
}
+define float @maximum_float_p0_qnan() {
+; CHECK-LABEL: @maximum_float_p0_qnan(
+; CHECK-NEXT: ret float 0x7FF8000000000000
+;
+ %max = call float @llvm.maximum.f32(float 0.0, float 0x7FF8000000000000)
+ ret float %max
+}
+
+define float @maximum_float_qnan_p0() {
+; CHECK-LABEL: @maximum_float_qnan_p0(
+; CHECK-NEXT: ret float 0x7FF8000000000000
+;
+ %max = call float @llvm.maximum.f32(float 0x7FF8000000000000, float 0.0)
+ ret float %max
+}
+
+define float @maximum_float_p0_snan() {
+; CHECK-LABEL: @maximum_float_p0_snan(
+; CHECK-NEXT: ret float 0x7FFC000000000000
+;
+ %max = call float @llvm.maximum.f32(float 0.0, float 0x7FF4000000000000)
+ ret float %max
+}
+
+define float @maximum_float_snan_p0() {
+; CHECK-LABEL: @maximum_float_snan_p0(
+; CHECK-NEXT: ret float 0x7FFC000000000000
+;
+ %max = call float @llvm.maximum.f32(float 0x7FF4000000000000, float 0.0)
+ ret float %max
+}
+
; Check that maximum propagates its NaN or greater argument
define <4 x float> @maximum_float_vec() {
@@ -345,6 +455,222 @@ define <4 x float> @maximum_float_zeros_vec() {
ret <4 x float> %1
}
+define float @minimumnum_float() {
+; CHECK-LABEL: @minimumnum_float(
+; CHECK-NEXT: ret float 5.000000e+00
+;
+ %1 = call float @llvm.minimumnum.f32(float 5.0, float 42.0)
+ ret float %1
+}
+
+define float @minimumnum_float_p0_n0() {
+; CHECK-LABEL: @minimumnum_float_p0_n0(
+; CHECK-NEXT: ret float -0.000000e+00
+;
+ %min = call float @llvm.minimumnum.f32(float 0.0, float -0.0)
+ ret float %min
+}
+
+define float @minimumnum_float_n0_p0() {
+; CHECK-LABEL: @minimumnum_float_n0_p0(
+; CHECK-NEXT: ret float -0.000000e+00
+;
+ %min = call float @llvm.minimumnum.f32(float -0.0, float 0.0)
+ ret float %min
+}
+
+define float @minimumnum_float_p0_qnan() {
+; CHECK-LABEL: @minimumnum_float_p0_qnan(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %min = call float @llvm.minimumnum.f32(float 0.0, float 0x7FF8000000000000)
+ ret float %min
+}
+
+define float @minimumnum_float_qnan_p0() {
+; CHECK-LABEL: @minimumnum_float_qnan_p0(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %min = call float @llvm.minimumnum.f32(float 0x7FF8000000000000, float 0.0)
+ ret float %min
+}
+
+define float @minimumnum_float_p0_snan() {
+; CHECK-LABEL: @minimumnum_float_p0_snan(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %min = call float @llvm.minimumnum.f32(float 0.0, float 0x7FF4000000000000)
+ ret float %min
+}
+
+define float @minimumnum_float_snan_p0() {
+; CHECK-LABEL: @minimumnum_float_snan_p0(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %min = call float @llvm.minimumnum.f32(float 0x7FF4000000000000, float 0.0)
+ ret float %min
+}
+
+define bfloat @minimumnum_bfloat() {
+; CHECK-LABEL: @minimumnum_bfloat(
+; CHECK-NEXT: ret bfloat 0xR40A0
+;
+ %1 = call bfloat @llvm.minimumnum.bf16(bfloat 5.0, bfloat 42.0)
+ ret bfloat %1
+}
+
+define half @minimumnum_half() {
+; CHECK-LABEL: @minimumnum_half(
+; CHECK-NEXT: ret half 0xH4500
+;
+ %1 = call half @llvm.minimumnum.f16(half 5.0, half 42.0)
+ ret half %1
+}
+
+; Check that minimumnum propagates its non-NaN or smaller argument
+
+define <4 x float> @minimumnum_float_vec() {
+; CHECK-LABEL: @minimumnum_float_vec(
+; CHECK-NEXT: ret <4 x float> <float 0x7FF8000000000000, float 5.000000e+00, float 4.200000e+01, float 5.000000e+00>
+;
+ %1 = call <4 x float> @llvm.minimumnum.v4f32(<4 x float> <float 0x7FF8000000000000, float 0x7FF8000000000000, float 42., float 42.>, <4 x float> <float 0x7FF8000000000000, float 5., float 0x7FF8000000000000, float 5.>)
+ ret <4 x float> %1
+}
+
+define <4 x bfloat> @minimumnum_bfloat_vec() {
+; CHECK-LABEL: @minimumnum_bfloat_vec(
+; CHECK-NEXT: ret <4 x bfloat> <bfloat 0xR7FC0, bfloat 0xR40A0, bfloat 0xR4228, bfloat 0xR40A0>
+;
+ %1 = call <4 x bfloat> @llvm.minimumnum.v4bf16(<4 x bfloat> <bfloat 0x7FF8000000000000, bfloat 0x7FF8000000000000, bfloat 42., bfloat 42.>, <4 x bfloat> <bfloat 0x7FF8000000000000, bfloat 5., bfloat 0x7FF8000000000000, bfloat 5.>)
+ ret <4 x bfloat> %1
+}
+
+define <4 x half> @minimumnum_half_vec() {
+; CHECK-LABEL: @minimumnum_half_vec(
+; CHECK-NEXT: ret <4 x half> <half 0xH7E00, half 0xH4500, half 0xH5140, half 0xH4500>
+;
+ %1 = call <4 x half> @llvm.minimumnum.v4f16(<4 x half> <half 0x7FF8000000000000, half 0x7FF8000000000000, half 42., half 42.>, <4 x half> <half 0x7FF8000000000000, half 5., half 0x7FF8000000000000, half 5.>)
+ ret <4 x half> %1
+}
+
+; Check that minimumnum treats -0.0 as smaller than 0.0 while constant folding
+
+define <4 x float> @minimumnum_float_zeros_vec() {
+; CHECK-LABEL: @minimumnum_float_zeros_vec(
+; CHECK-NEXT: ret <4 x float> <float 0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>
+;
+ %1 = call <4 x float> @llvm.minimumnum.v4f32(<4 x float> <float 0.0, float -0.0, float 0.0, float -0.0>, <4 x float> <float 0.0, float 0.0, float -0.0, float -0.0>)
+ ret <4 x float> %1
+}
+
+define float @maximumnum_float() {
+; CHECK-LABEL: @maximumnum_float(
+; CHECK-NEXT: ret float 4.200000e+01
+;
+ %1 = call float @llvm.maximumnum.f32(float 5.0, float 42.0)
+ ret float %1
+}
+
+define bfloat @maximumnum_bfloat() {
+; CHECK-LABEL: @maximumnum_bfloat(
+; CHECK-NEXT: ret bfloat 0xR4228
+;
+ %1 = call bfloat @llvm.maximumnum.bf16(bfloat 5.0, bfloat 42.0)
+ ret bfloat %1
+}
+
+define half @maximumnum_half() {
+; CHECK-LABEL: @maximumnum_half(
+; CHECK-NEXT: ret half 0xH5140
+;
+ %1 = call half @llvm.maximumnum.f16(half 5.0, half 42.0)
+ ret half %1
+}
+
+define float @maximumnum_float_p0_n0() {
+; CHECK-LABEL: @maximumnum_float_p0_n0(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %max = call float @llvm.maximumnum.f32(float 0.0, float -0.0)
+ ret float %max
+}
+
+define float @maximumnum_float_n0_p0() {
+; CHECK-LABEL: @maximumnum_float_n0_p0(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %max = call float @llvm.maximumnum.f32(float -0.0, float 0.0)
+ ret float %max
+}
+
+define float @maximumnum_float_p0_qnan() {
+; CHECK-LABEL: @maximumnum_float_p0_qnan(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %max = call float @llvm.maximumnum.f32(float 0.0, float 0x7FF8000000000000)
+ ret float %max
+}
+
+define float @maximumnum_float_qnan_p0() {
+; CHECK-LABEL: @maximumnum_float_qnan_p0(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %max = call float @llvm.maximumnum.f32(float 0x7FF8000000000000, float 0.0)
+ ret float %max
+}
+
+define float @maximumnum_float_p0_snan() {
+; CHECK-LABEL: @maximumnum_float_p0_snan(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %max = call float @llvm.maximumnum.f32(float 0.0, float 0x7FF4000000000000)
+ ret float %max
+}
+
+define float @maximumnum_float_snan_p0() {
+; CHECK-LABEL: @maximumnum_float_snan_p0(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %max = call float @llvm.maximumnum.f32(float 0x7FF4000000000000, float 0.0)
+ ret float %max
+}
+
+; Check that maximumnum propagates its non-NaN or greater argument
+
+define <4 x float> @maximumnum_float_vec() {
+; CHECK-LABEL: @maximumnum_float_vec(
+; CHECK-NEXT: ret <4 x float> <float 0x7FF8000000000000, float 5.000000e+00, float 4.200000e+01, float 4.200000e+01>
+;
+ %1 = call <4 x float> @llvm.maximumnum.v4f32(<4 x float> <float 0x7FF8000000000000, float 0x7FF8000000000000, float 42., float 42.>, <4 x float> <float 0x7FF8000000000000, float 5., float 0x7FF8000000000000, float 5.>)
+ ret <4 x float> %1
+}
+
+define <4 x bfloat> @maximumnum_bfloat_vec() {
+; CHECK-LABEL: @maximumnum_bfloat_vec(
+; CHECK-NEXT: ret <4 x bfloat> <bfloat 0xR7FC0, bfloat 0xR40A0, bfloat 0xR4228, bfloat 0xR4228>
+;
+ %1 = call <4 x bfloat> @llvm.maximumnum.v4bf16(<4 x bfloat> <bfloat 0x7FF8000000000000, bfloat 0x7FF8000000000000, bfloat 42., bfloat 42.>, <4 x bfloat> <bfloat 0x7FF8000000000000, bfloat 5., bfloat 0x7FF8000000000000, bfloat 5.>)
+ ret <4 x bfloat> %1
+}
+
+define <4 x half> @maximumnum_half_vec() {
+; CHECK-LABEL: @maximumnum_half_vec(
+; CHECK-NEXT: ret <4 x half> <half 0xH7E00, half 0xH4500, half 0xH5140, half 0xH5140>
+;
+ %1 = call <4 x half> @llvm.maximumnum.v4f16(<4 x half> <half 0x7FF8000000000000, half 0x7FF8000000000000, half 42., half 42.>, <4 x half> <half 0x7FF8000000000000, half 5., half 0x7FF8000000000000, half 5.>)
+ ret <4 x half> %1
+}
+
+; Check that maximumnum treats -0.0 as smaller than 0.0 while constant folding
+
+define <4 x float> @maximumnum_float_zeros_vec() {
+; CHECK-LABEL: @maximumnum_float_zeros_vec(
+; CHECK-NEXT: ret <4 x float> <float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float -0.000000e+00>
+;
+ %1 = call <4 x float> @llvm.maximumnum.v4f32(<4 x float> <float 0.0, float -0.0, float 0.0, float -0.0>, <4 x float> <float 0.0, float 0.0, float -0.0, float -0.0>)
+ ret <4 x float> %1
+}
+
define i8 @smax() {
; CHECK-LABEL: @smax(
; CHECK-NEXT: ret i8 -127
|
✅ With the latest revision this PR passed the undef deprecator. |
Add constant-folding support for the maximumnum and minimumnum intrinsics, and extend the tests to show the qnan vs snan behavior differences between maxnum/maximum/maximumnum.
7b2bddf
to
4c9bf0f
Compare
Are you working on the generalized InstSimplify handling for these beyond constant folding? |
Yes, I am working on a patch to add more optimization support for maximumnum/minimumnum in InstSimplify and ValueTracking. (Patch here: #139581 ) |
Add constant-folding support for the maximumnum and minimumnum intrinsics, and extend the tests to show the qnan vs snan behavior differences between maxnum/maximum/maximumnum.