[llvm] fd54aa9 - [instcombine][x86]: simplifyx86fpmaxmin - allow negzero for single operand (#180418)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 16 09:30:09 PST 2026
Author: Madhur Kumar
Date: 2026-02-16T17:30:03Z
New Revision: fd54aa9e3aab8f682129dfc5f82dc8f8775c66bc
URL: https://github.com/llvm/llvm-project/commit/fd54aa9e3aab8f682129dfc5f82dc8f8775c66bc
DIFF: https://github.com/llvm/llvm-project/commit/fd54aa9e3aab8f682129dfc5f82dc8f8775c66bc.diff
LOG: [instcombine][x86]: simplifyx86fpmaxmin - allow negzero for single operand (#180418)
Fixes #175552
Added:
llvm/test/Transforms/InstCombine/X86/x86-fp-minmax-negzero.ll
Modified:
llvm/lib/Target/X86/X86InstCombineIntrinsic.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/X86/X86InstCombineIntrinsic.cpp b/llvm/lib/Target/X86/X86InstCombineIntrinsic.cpp
index d46dbf178bcff..028d568fb0fb2 100644
--- a/llvm/lib/Target/X86/X86InstCombineIntrinsic.cpp
+++ b/llvm/lib/Target/X86/X86InstCombineIntrinsic.cpp
@@ -1745,15 +1745,23 @@ static Value *simplifyX86FPMaxMin(const IntrinsicInst &II, InstCombiner &IC,
APInt DemandedElts =
IsScalar ? APInt::getOneBitSet(VWidth, 0) : APInt::getAllOnes(VWidth);
- // Verify that the inputs are not one of (NaN, Inf, Subnormal, NegZero),
- // otherwise we cannot safely generalize to MAXNUM/MINNUM.
- FPClassTest Forbidden = fcNan | fcInf | fcSubnormal | fcNegZero;
+ FPClassTest Forbidden0 = fcNan | fcInf | fcSubnormal;
+ FPClassTest Forbidden1 = fcNan | fcInf | fcSubnormal;
+ if (NewIID == Intrinsic::maxnum) {
+ // For maxnum, only forbid NegZero in the second operand.
+ Forbidden1 |= fcNegZero;
+ } else {
+ assert(NewIID == Intrinsic::minnum && "Unknown intrinsic");
+ // For minnum, only forbid NegZero in the first operand.
+ Forbidden0 |= fcNegZero;
+ }
KnownFPClass KnownArg0 =
- computeKnownFPClass(Arg0, DemandedElts, Forbidden, SQ);
+ computeKnownFPClass(Arg0, DemandedElts, Forbidden0, SQ);
KnownFPClass KnownArg1 =
- computeKnownFPClass(Arg1, DemandedElts, Forbidden, SQ);
+ computeKnownFPClass(Arg1, DemandedElts, Forbidden1, SQ);
- if (KnownArg0.isKnownNever(Forbidden) && KnownArg1.isKnownNever(Forbidden)) {
+ if (KnownArg0.isKnownNever(Forbidden0) &&
+ KnownArg1.isKnownNever(Forbidden1)) {
if (IsScalar) {
// It performs the operation on the first element and puts it back into
// the vector.
diff --git a/llvm/test/Transforms/InstCombine/X86/x86-fp-minmax-negzero.ll b/llvm/test/Transforms/InstCombine/X86/x86-fp-minmax-negzero.ll
new file mode 100644
index 0000000000000..2ec4ed308ad25
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/X86/x86-fp-minmax-negzero.ll
@@ -0,0 +1,103 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=instcombine -mtriple=x86_64-unknown-unknown < %s -S | FileCheck %s
+
+; Test relaxed negzero handling for X86 max/min intrinsics.
+
+declare <4 x float> @llvm.x86.sse.max.ps(<4 x float>, <4 x float>)
+declare <4 x float> @llvm.x86.sse.min.ps(<4 x float>, <4 x float>)
+declare <4 x float> @llvm.x86.sse.max.ss(<4 x float>, <4 x float>)
+declare <4 x float> @llvm.x86.sse.min.ss(<4 x float>, <4 x float>)
+
+; For maxnum, allow -0.0 in the first operand only.
+
+define <4 x float> @test_max_allow_negzero_first() {
+; CHECK-LABEL: define <4 x float> @test_max_allow_negzero_first() {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: ret <4 x float> splat (float 1.000000e+00)
+;
+entry:
+ %r = call <4 x float> @llvm.x86.sse.max.ps(<4 x float> <float -0.0, float -0.0, float -0.0, float -0.0>, <4 x float> <float 1.0, float 1.0, float 1.0, float 1.0>)
+ ret <4 x float> %r
+}
+
+; For minnum, allow -0.0 in the second operand only.
+
+define <4 x float> @test_min_allow_negzero_second() {
+; CHECK-LABEL: define <4 x float> @test_min_allow_negzero_second() {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: ret <4 x float> splat (float -0.000000e+00)
+;
+entry:
+ %r = call <4 x float> @llvm.x86.sse.min.ps(<4 x float> <float 1.0, float 1.0, float 1.0, float 1.0>, <4 x float> <float -0.0, float -0.0, float -0.0, float -0.0>)
+ ret <4 x float> %r
+}
+
+; Negative test: max should not fold when -0.0 is in the second operand.
+
+define <4 x float> @test_max_disallow_negzero_second() {
+; CHECK-LABEL: define <4 x float> @test_max_disallow_negzero_second() {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[R:%.*]] = call <4 x float> @llvm.x86.sse.max.ps(<4 x float> splat (float 1.000000e+00), <4 x float> splat (float -0.000000e+00))
+; CHECK-NEXT: ret <4 x float> [[R]]
+;
+entry:
+ %r = call <4 x float> @llvm.x86.sse.max.ps(<4 x float> <float 1.0, float 1.0, float 1.0, float 1.0>, <4 x float> <float -0.0, float -0.0, float -0.0, float -0.0>)
+ ret <4 x float> %r
+}
+
+; Negative test: min should not fold when -0.0 is in the first operand.
+
+define <4 x float> @test_min_disallow_negzero_first() {
+; CHECK-LABEL: define <4 x float> @test_min_disallow_negzero_first() {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[R:%.*]] = call <4 x float> @llvm.x86.sse.min.ps(<4 x float> splat (float -0.000000e+00), <4 x float> splat (float 1.000000e+00))
+; CHECK-NEXT: ret <4 x float> [[R]]
+;
+entry:
+ %r = call <4 x float> @llvm.x86.sse.min.ps(<4 x float> <float -0.0, float -0.0, float -0.0, float -0.0>, <4 x float> <float 1.0, float 1.0, float 1.0, float 1.0>)
+ ret <4 x float> %r
+}
+
+; Scalar: only lane 0 is semantically constrained.
+
+define <4 x float> @test_max_ss_allow_negzero_first() {
+; CHECK-LABEL: define <4 x float> @test_max_ss_allow_negzero_first() {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: ret <4 x float> <float 1.000000e+00, float 0x7FF8000000000000, float 0x7FF8000000000000, float 0x7FF8000000000000>
+;
+entry:
+ %r = call <4 x float> @llvm.x86.sse.max.ss(<4 x float> <float -0.0, float 0x7FF8000000000000, float 0x7FF8000000000000, float 0x7FF8000000000000>, <4 x float> <float 1.0, float 0x7FF8000000000000, float 0x7FF8000000000000, float 0x7FF8000000000000>)
+ ret <4 x float> %r
+}
+
+define <4 x float> @test_max_ss_disallow_negzero_second() {
+; CHECK-LABEL: define <4 x float> @test_max_ss_disallow_negzero_second() {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[R:%.*]] = call <4 x float> @llvm.x86.sse.max.ss(<4 x float> <float 1.000000e+00, float 0x7FF8000000000000, float 0x7FF8000000000000, float 0x7FF8000000000000>, <4 x float> <float -0.000000e+00, float poison, float poison, float poison>)
+; CHECK-NEXT: ret <4 x float> [[R]]
+;
+entry:
+ %r = call <4 x float> @llvm.x86.sse.max.ss(<4 x float> <float 1.0, float 0x7FF8000000000000, float 0x7FF8000000000000, float 0x7FF8000000000000>, <4 x float> <float -0.0, float 0x7FF8000000000000, float 0x7FF8000000000000, float 0x7FF8000000000000>)
+ ret <4 x float> %r
+}
+
+define <4 x float> @test_min_ss_allow_negzero_second() {
+; CHECK-LABEL: define <4 x float> @test_min_ss_allow_negzero_second() {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: ret <4 x float> <float -0.000000e+00, float 0x7FF8000000000000, float 0x7FF8000000000000, float 0x7FF8000000000000>
+;
+entry:
+ %r = call <4 x float> @llvm.x86.sse.min.ss(<4 x float> <float 1.0, float 0x7FF8000000000000, float 0x7FF8000000000000, float 0x7FF8000000000000>, <4 x float> <float -0.0, float 0x7FF8000000000000, float 0x7FF8000000000000, float 0x7FF8000000000000>)
+ ret <4 x float> %r
+}
+
+define <4 x float> @test_min_ss_disallow_negzero_first() {
+; CHECK-LABEL: define <4 x float> @test_min_ss_disallow_negzero_first() {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[R:%.*]] = call <4 x float> @llvm.x86.sse.min.ss(<4 x float> <float -0.000000e+00, float 0x7FF8000000000000, float 0x7FF8000000000000, float 0x7FF8000000000000>, <4 x float> <float 1.000000e+00, float poison, float poison, float poison>)
+; CHECK-NEXT: ret <4 x float> [[R]]
+;
+entry:
+ %r = call <4 x float> @llvm.x86.sse.min.ss(<4 x float> <float -0.0, float 0x7FF8000000000000, float 0x7FF8000000000000, float 0x7FF8000000000000>, <4 x float> <float 1.0, float 0x7FF8000000000000, float 0x7FF8000000000000, float 0x7FF8000000000000>)
+ ret <4 x float> %r
+}
\ No newline at end of file
More information about the llvm-commits
mailing list