Skip to content

Commit 6cfd343

Browse files
authored
APFloat: Fix signed zero handling in minnum/maxnum (#83376)
Follow the 2019 rules and order -0 as less than +0 and +0 as greater than -0. As currently defined this isn't required for the intrinsics, but is a better QoI. This will avoid the workaround in libc added by #83158
1 parent ee297a7 commit 6cfd343

File tree

7 files changed

+91
-11
lines changed

7 files changed

+91
-11
lines changed

llvm/include/llvm/ADT/APFloat.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,25 +1389,31 @@ inline APFloat neg(APFloat X) {
13891389
return X;
13901390
}
13911391

1392-
/// Implements IEEE minNum semantics. Returns the smaller of the 2 arguments if
1393-
/// both are not NaN. If either argument is a NaN, returns the other argument.
1392+
/// Implements IEEE-754 2019 minimumNumber semantics. Returns the smaller of the
1393+
/// 2 arguments if both are not NaN. If either argument is a NaN, returns the
1394+
/// other argument. -0 is treated as ordered less than +0.
13941395
LLVM_READONLY
13951396
inline APFloat minnum(const APFloat &A, const APFloat &B) {
13961397
if (A.isNaN())
13971398
return B;
13981399
if (B.isNaN())
13991400
return A;
1401+
if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative()))
1402+
return A.isNegative() ? A : B;
14001403
return B < A ? B : A;
14011404
}
14021405

1403-
/// Implements IEEE maxNum semantics. Returns the larger of the 2 arguments if
1404-
/// both are not NaN. If either argument is a NaN, returns the other argument.
1406+
/// Implements IEEE-754 2019 maximumNumber semantics. Returns the larger of the
1407+
/// 2 arguments if both are not NaN. If either argument is a NaN, returns the
1408+
/// other argument. +0 is treated as ordered greater than -0.
14051409
LLVM_READONLY
14061410
inline APFloat maxnum(const APFloat &A, const APFloat &B) {
14071411
if (A.isNaN())
14081412
return B;
14091413
if (B.isNaN())
14101414
return A;
1415+
if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative()))
1416+
return A.isNegative() ? B : A;
14111417
return A < B ? B : A;
14121418
}
14131419

llvm/test/CodeGen/AMDGPU/fmaxnum.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ define amdgpu_kernel void @constant_fold_fmax_f32_p0_n0(ptr addrspace(1) %out) #
152152

153153
; GCN-LABEL: {{^}}constant_fold_fmax_f32_n0_p0:
154154
; GCN-NOT: v_max_f32_e32
155-
; GCN: v_bfrev_b32_e32 [[REG:v[0-9]+]], 1{{$}}
155+
; GCN: v_mov_b32_e32 [[REG:v[0-9]+]], 0{{$}}
156156
; GCN: buffer_store_dword [[REG]]
157157
define amdgpu_kernel void @constant_fold_fmax_f32_n0_p0(ptr addrspace(1) %out) #0 {
158158
%val = call float @llvm.maxnum.f32(float -0.0, float 0.0)

llvm/test/CodeGen/AMDGPU/fminnum.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ define amdgpu_kernel void @constant_fold_fmin_f32_p0_p0(ptr addrspace(1) %out) #
150150

151151
; GCN-LABEL: {{^}}constant_fold_fmin_f32_p0_n0:
152152
; GCN-NOT: v_min_f32_e32
153-
; GCN: v_mov_b32_e32 [[REG:v[0-9]+]], 0
153+
; GCN: v_bfrev_b32_e32 [[REG:v[0-9]+]], 1{{$}}
154154
; GCN: buffer_store_dword [[REG]]
155155
define amdgpu_kernel void @constant_fold_fmin_f32_p0_n0(ptr addrspace(1) %out) #0 {
156156
%val = call float @llvm.minnum.f32(float 0.0, float -0.0)

llvm/test/Transforms/InstCombine/maxnum.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ define float @constant_fold_maxnum_f32_p0_n0() {
6666

6767
define float @constant_fold_maxnum_f32_n0_p0() {
6868
; CHECK-LABEL: @constant_fold_maxnum_f32_n0_p0(
69-
; CHECK-NEXT: ret float -0.000000e+00
69+
; CHECK-NEXT: ret float 0.000000e+00
7070
;
7171
%x = call float @llvm.maxnum.f32(float -0.0, float 0.0)
7272
ret float %x

llvm/test/Transforms/InstCombine/minnum.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ define float @constant_fold_minnum_f32_p0_p0() {
6060

6161
define float @constant_fold_minnum_f32_p0_n0() {
6262
; CHECK-LABEL: @constant_fold_minnum_f32_p0_n0(
63-
; CHECK-NEXT: ret float 0.000000e+00
63+
; CHECK-NEXT: ret float -0.000000e+00
6464
;
6565
%x = call float @llvm.minnum.f32(float 0.0, float -0.0)
6666
ret float %x
@@ -199,7 +199,7 @@ define float @minnum_f32_1_minnum_p0_val_fmf3(float %x) {
199199

200200
define float @minnum_f32_p0_minnum_val_n0(float %x) {
201201
; CHECK-LABEL: @minnum_f32_p0_minnum_val_n0(
202-
; CHECK-NEXT: [[Z:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float 0.000000e+00)
202+
; CHECK-NEXT: [[Z:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float -0.000000e+00)
203203
; CHECK-NEXT: ret float [[Z]]
204204
;
205205
%y = call float @llvm.minnum.f32(float %x, float -0.0)

llvm/test/Transforms/InstSimplify/ConstProp/min-max.ll

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,38 @@ define float @minnum_float() {
4949
ret float %1
5050
}
5151

52+
define float @minnum_float_p0_n0() {
53+
; CHECK-LABEL: @minnum_float_p0_n0(
54+
; CHECK-NEXT: ret float -0.000000e+00
55+
;
56+
%min = call float @llvm.minnum.f32(float 0.0, float -0.0)
57+
ret float %min
58+
}
59+
60+
define float @minnum_float_n0_p0() {
61+
; CHECK-LABEL: @minnum_float_n0_p0(
62+
; CHECK-NEXT: ret float -0.000000e+00
63+
;
64+
%min = call float @llvm.minnum.f32(float -0.0, float 0.0)
65+
ret float %min
66+
}
67+
68+
define float @minnum_float_p0_qnan() {
69+
; CHECK-LABEL: @minnum_float_p0_qnan(
70+
; CHECK-NEXT: ret float 0.000000e+00
71+
;
72+
%min = call float @llvm.minnum.f32(float 0.0, float 0x7FF8000000000000)
73+
ret float %min
74+
}
75+
76+
define float @minnum_float_qnan_p0() {
77+
; CHECK-LABEL: @minnum_float_qnan_p0(
78+
; CHECK-NEXT: ret float 0.000000e+00
79+
;
80+
%min = call float @llvm.minnum.f32(float 0x7FF8000000000000, float 0.0)
81+
ret float %min
82+
}
83+
5284
define bfloat @minnum_bfloat() {
5385
; CHECK-LABEL: @minnum_bfloat(
5486
; CHECK-NEXT: ret bfloat 0xR40A0
@@ -95,7 +127,7 @@ define <4 x half> @minnum_half_vec() {
95127

96128
define <4 x float> @minnum_float_zeros_vec() {
97129
; CHECK-LABEL: @minnum_float_zeros_vec(
98-
; CHECK-NEXT: ret <4 x float> <float 0.000000e+00, float -0.000000e+00, float 0.000000e+00, float -0.000000e+00>
130+
; CHECK-NEXT: ret <4 x float> <float 0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>
99131
;
100132
%1 = call <4 x float> @llvm.minnum.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>)
101133
ret <4 x float> %1
@@ -109,6 +141,38 @@ define float @maxnum_float() {
109141
ret float %1
110142
}
111143

144+
define float @maxnum_float_p0_n0() {
145+
; CHECK-LABEL: @maxnum_float_p0_n0(
146+
; CHECK-NEXT: ret float 0.000000e+00
147+
;
148+
%max = call float @llvm.maxnum.f32(float 0.0, float -0.0)
149+
ret float %max
150+
}
151+
152+
define float @maxnum_float_n0_p0() {
153+
; CHECK-LABEL: @maxnum_float_n0_p0(
154+
; CHECK-NEXT: ret float 0.000000e+00
155+
;
156+
%max = call float @llvm.maxnum.f32(float -0.0, float 0.0)
157+
ret float %max
158+
}
159+
160+
define float @maxnum_float_p0_qnan() {
161+
; CHECK-LABEL: @maxnum_float_p0_qnan(
162+
; CHECK-NEXT: ret float 0.000000e+00
163+
;
164+
%max = call float @llvm.maxnum.f32(float 0.0, float 0x7FF8000000000000)
165+
ret float %max
166+
}
167+
168+
define float @maxnum_float_qnan_p0() {
169+
; CHECK-LABEL: @maxnum_float_qnan_p0(
170+
; CHECK-NEXT: ret float 0.000000e+00
171+
;
172+
%max = call float @llvm.maxnum.f32(float 0x7FF8000000000000, float 0.0)
173+
ret float %max
174+
}
175+
112176
define bfloat @maxnum_bfloat() {
113177
; CHECK-LABEL: @maxnum_bfloat(
114178
; CHECK-NEXT: ret bfloat 0xR4228
@@ -155,7 +219,7 @@ define <4 x half> @maxnum_half_vec() {
155219

156220
define <4 x float> @maxnum_float_zeros_vec() {
157221
; CHECK-LABEL: @maxnum_float_zeros_vec(
158-
; CHECK-NEXT: ret <4 x float> <float 0.000000e+00, float -0.000000e+00, float 0.000000e+00, float -0.000000e+00>
222+
; CHECK-NEXT: ret <4 x float> <float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float -0.000000e+00>
159223
;
160224
%1 = call <4 x float> @llvm.maxnum.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>)
161225
ret <4 x float> %1

llvm/unittests/ADT/APFloatTest.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,11 @@ TEST(APFloatTest, MinNum) {
578578
EXPECT_EQ(1.0, minnum(f2, f1).convertToDouble());
579579
EXPECT_EQ(1.0, minnum(f1, nan).convertToDouble());
580580
EXPECT_EQ(1.0, minnum(nan, f1).convertToDouble());
581+
582+
APFloat zp(0.0);
583+
APFloat zn(-0.0);
584+
EXPECT_EQ(-0.0, minnum(zp, zn).convertToDouble());
585+
EXPECT_EQ(-0.0, minnum(zn, zp).convertToDouble());
581586
}
582587

583588
TEST(APFloatTest, MaxNum) {
@@ -589,6 +594,11 @@ TEST(APFloatTest, MaxNum) {
589594
EXPECT_EQ(2.0, maxnum(f2, f1).convertToDouble());
590595
EXPECT_EQ(1.0, maxnum(f1, nan).convertToDouble());
591596
EXPECT_EQ(1.0, maxnum(nan, f1).convertToDouble());
597+
598+
APFloat zp(0.0);
599+
APFloat zn(-0.0);
600+
EXPECT_EQ(0.0, maxnum(zp, zn).convertToDouble());
601+
EXPECT_EQ(0.0, maxnum(zn, zp).convertToDouble());
592602
}
593603

594604
TEST(APFloatTest, Minimum) {

0 commit comments

Comments
 (0)