[llvm] [ConstantFolding] Fold fmaximumnum and fminimumnum (PR #138700)
via llvm-commits
llvm-commits at lists.llvm.org
Tue May 6 07:56:08 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Lewis Crawford (LewisCrawford)
<details>
<summary>Changes</summary>
Add 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:
- (modified) llvm/lib/Analysis/ConstantFolding.cpp (+8)
- (modified) llvm/test/Transforms/InstSimplify/ConstProp/fp-undef.ll (+34)
- (modified) llvm/test/Transforms/InstSimplify/ConstProp/min-max.ll (+326)
``````````diff
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
``````````
</details>
https://github.com/llvm/llvm-project/pull/138700
More information about the llvm-commits
mailing list