Skip to content

Commit 3e1e406

Browse files
authored
[InstCombine] Preserve signbit semantics of NaN with fold to fabs (#136648)
As per the LangRef and IEEE 754-2008 standard, the sign bit of NaN is preserved if there is no floating-point operation being performed. See also 862e35e for reference. Alive2: https://alive2.llvm.org/ce/z/QYtEGj Closes #136646
1 parent 2ae9a74 commit 3e1e406

File tree

2 files changed

+54
-12
lines changed

2 files changed

+54
-12
lines changed

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

+8-1
Original file line numberDiff line numberDiff line change
@@ -2793,7 +2793,14 @@ static Instruction *foldSelectWithFCmpToFabs(SelectInst &SI,
27932793

27942794
// fold (X <= +/-0.0) ? (0.0 - X) : X to fabs(X), when 'Swap' is false
27952795
// fold (X > +/-0.0) ? X : (0.0 - X) to fabs(X), when 'Swap' is true
2796-
if (match(TrueVal, m_FSub(m_PosZeroFP(), m_Specific(X)))) {
2796+
// Note: We require "nnan" for this fold because fcmp ignores the signbit
2797+
// of NAN, but IEEE-754 specifies the signbit of NAN values with
2798+
// fneg/fabs operations.
2799+
if (match(TrueVal, m_FSub(m_PosZeroFP(), m_Specific(X))) &&
2800+
(cast<FPMathOperator>(CondVal)->hasNoNaNs() || SI.hasNoNaNs() ||
2801+
isKnownNeverNaN(X, /*Depth=*/0,
2802+
IC.getSimplifyQuery().getWithInstruction(
2803+
cast<Instruction>(CondVal))))) {
27972804
if (!Swap && (Pred == FCmpInst::FCMP_OLE || Pred == FCmpInst::FCMP_ULE)) {
27982805
Value *Fabs = IC.Builder.CreateUnaryIntrinsic(Intrinsic::fabs, X, &SI);
27992806
return IC.replaceInstUsesWith(SI, Fabs);

llvm/test/Transforms/InstCombine/fabs.ll

+46-11
Original file line numberDiff line numberDiff line change
@@ -256,19 +256,54 @@ define double @select_fcmp_ole_zero(double %x) {
256256
; CHECK-LABEL: @select_fcmp_ole_zero(
257257
; CHECK-NEXT: [[FABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
258258
; CHECK-NEXT: ret double [[FABS]]
259+
;
260+
%lezero = fcmp nnan ole double %x, 0.0
261+
%negx = fsub double 0.0, %x
262+
%fabs = select i1 %lezero, double %negx, double %x
263+
ret double %fabs
264+
}
265+
266+
define double @select_fcmp_ole_zero_no_nnan(double %x) {
267+
; CHECK-LABEL: @select_fcmp_ole_zero_no_nnan(
268+
; CHECK-NEXT: [[LEZERO:%.*]] = fcmp ole double [[X:%.*]], 0.000000e+00
269+
; CHECK-NEXT: [[NEGX:%.*]] = fsub double 0.000000e+00, [[X]]
270+
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[LEZERO]], double [[NEGX]], double [[X]]
271+
; CHECK-NEXT: ret double [[FABS]]
259272
;
260273
%lezero = fcmp ole double %x, 0.0
261274
%negx = fsub double 0.0, %x
262275
%fabs = select i1 %lezero, double %negx, double %x
263276
ret double %fabs
264277
}
265278

279+
define double @select_fcmp_ole_zero_no_nnan_input_nofpclass_nan(double nofpclass(nan) %x) {
280+
; CHECK-LABEL: @select_fcmp_ole_zero_no_nnan_input_nofpclass_nan(
281+
; CHECK-NEXT: [[FABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
282+
; CHECK-NEXT: ret double [[FABS]]
283+
;
284+
%lezero = fcmp ole double %x, 0.0
285+
%negx = fsub double 0.0, %x
286+
%fabs = select i1 %lezero, double %negx, double %x
287+
ret double %fabs
288+
}
289+
290+
define double @select_fcmp_ole_zero_select_nnan(double %x) {
291+
; CHECK-LABEL: @select_fcmp_ole_zero_select_nnan(
292+
; CHECK-NEXT: [[FABS:%.*]] = call nnan double @llvm.fabs.f64(double [[X:%.*]])
293+
; CHECK-NEXT: ret double [[FABS]]
294+
;
295+
%lezero = fcmp ole double %x, 0.0
296+
%negx = fsub double 0.0, %x
297+
%fabs = select nnan i1 %lezero, double %negx, double %x
298+
ret double %fabs
299+
}
300+
266301
define double @select_fcmp_nnan_ole_zero(double %x) {
267302
; CHECK-LABEL: @select_fcmp_nnan_ole_zero(
268303
; CHECK-NEXT: [[FABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
269304
; CHECK-NEXT: ret double [[FABS]]
270305
;
271-
%lezero = fcmp ole double %x, 0.0
306+
%lezero = fcmp nnan ole double %x, 0.0
272307
%negx = fsub nnan double 0.0, %x
273308
%fabs = select i1 %lezero, double %negx, double %x
274309
ret double %fabs
@@ -279,7 +314,7 @@ define double @select_nnan_fcmp_nnan_ole_zero(double %x) {
279314
; CHECK-NEXT: [[FABS:%.*]] = call nnan double @llvm.fabs.f64(double [[X:%.*]])
280315
; CHECK-NEXT: ret double [[FABS]]
281316
;
282-
%lezero = fcmp ole double %x, 0.0
317+
%lezero = fcmp nnan ole double %x, 0.0
283318
%negx = fsub nnan double 0.0, %x
284319
%fabs = select nnan i1 %lezero, double %negx, double %x
285320
ret double %fabs
@@ -292,7 +327,7 @@ define double @select_fcmp_nnan_ule_zero(double %x) {
292327
; CHECK-NEXT: [[FABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
293328
; CHECK-NEXT: ret double [[FABS]]
294329
;
295-
%lezero = fcmp ule double %x, 0.0
330+
%lezero = fcmp nnan ule double %x, 0.0
296331
%negx = fsub nnan double 0.0, %x
297332
%fabs = select i1 %lezero, double %negx, double %x
298333
ret double %fabs
@@ -320,7 +355,7 @@ define <2 x float> @select_fcmp_nnan_ole_negzero(<2 x float> %x) {
320355
; CHECK-NEXT: [[FABS:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[X:%.*]])
321356
; CHECK-NEXT: ret <2 x float> [[FABS]]
322357
;
323-
%lezero = fcmp ole <2 x float> %x, <float -0.0, float -0.0>
358+
%lezero = fcmp nnan ole <2 x float> %x, <float -0.0, float -0.0>
324359
%negx = fsub nnan <2 x float> <float 0.0, float poison>, %x
325360
%fabs = select <2 x i1> %lezero, <2 x float> %negx, <2 x float> %x
326361
ret <2 x float> %fabs
@@ -331,7 +366,7 @@ define <2 x float> @select_nnan_fcmp_nnan_ole_negzero(<2 x float> %x) {
331366
; CHECK-NEXT: [[FABS:%.*]] = call nnan <2 x float> @llvm.fabs.v2f32(<2 x float> [[X:%.*]])
332367
; CHECK-NEXT: ret <2 x float> [[FABS]]
333368
;
334-
%lezero = fcmp ole <2 x float> %x, <float -0.0, float -0.0>
369+
%lezero = fcmp nnan ole <2 x float> %x, <float -0.0, float -0.0>
335370
%negx = fsub nnan <2 x float> <float 0.0, float poison>, %x
336371
%fabs = select nnan <2 x i1> %lezero, <2 x float> %negx, <2 x float> %x
337372
ret <2 x float> %fabs
@@ -344,7 +379,7 @@ define fp128 @select_fcmp_ogt_zero(fp128 %x) {
344379
; CHECK-NEXT: [[FABS:%.*]] = call fp128 @llvm.fabs.f128(fp128 [[X:%.*]])
345380
; CHECK-NEXT: ret fp128 [[FABS]]
346381
;
347-
%gtzero = fcmp ogt fp128 %x, zeroinitializer
382+
%gtzero = fcmp nnan ogt fp128 %x, zeroinitializer
348383
%negx = fsub fp128 zeroinitializer, %x
349384
%fabs = select i1 %gtzero, fp128 %x, fp128 %negx
350385
ret fp128 %fabs
@@ -382,7 +417,7 @@ define fp128 @select_fcmp_nnan_ogt_zero(fp128 %x) {
382417
; CHECK-NEXT: [[FABS:%.*]] = call fp128 @llvm.fabs.f128(fp128 [[X:%.*]])
383418
; CHECK-NEXT: ret fp128 [[FABS]]
384419
;
385-
%gtzero = fcmp ogt fp128 %x, zeroinitializer
420+
%gtzero = fcmp nnan ogt fp128 %x, zeroinitializer
386421
%negx = fsub nnan fp128 zeroinitializer, %x
387422
%fabs = select i1 %gtzero, fp128 %x, fp128 %negx
388423
ret fp128 %fabs
@@ -393,7 +428,7 @@ define fp128 @select_nnan_fcmp_nnan_ogt_zero(fp128 %x) {
393428
; CHECK-NEXT: [[FABS:%.*]] = call nnan fp128 @llvm.fabs.f128(fp128 [[X:%.*]])
394429
; CHECK-NEXT: ret fp128 [[FABS]]
395430
;
396-
%gtzero = fcmp ogt fp128 %x, zeroinitializer
431+
%gtzero = fcmp nnan ogt fp128 %x, zeroinitializer
397432
%negx = fsub nnan fp128 zeroinitializer, %x
398433
%fabs = select nnan i1 %gtzero, fp128 %x, fp128 %negx
399434
ret fp128 %fabs
@@ -406,7 +441,7 @@ define half @select_fcmp_nnan_ogt_negzero(half %x) {
406441
; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
407442
; CHECK-NEXT: ret half [[FABS]]
408443
;
409-
%gtzero = fcmp ogt half %x, -0.0
444+
%gtzero = fcmp nnan ogt half %x, -0.0
410445
%negx = fsub nnan half 0.0, %x
411446
%fabs = select i1 %gtzero, half %x, half %negx
412447
ret half %fabs
@@ -417,7 +452,7 @@ define half @select_nnan_fcmp_nnan_ogt_negzero(half %x) {
417452
; CHECK-NEXT: [[FABS:%.*]] = call nnan half @llvm.fabs.f16(half [[X:%.*]])
418453
; CHECK-NEXT: ret half [[FABS]]
419454
;
420-
%gtzero = fcmp ogt half %x, -0.0
455+
%gtzero = fcmp nnan ogt half %x, -0.0
421456
%negx = fsub nnan half 0.0, %x
422457
%fabs = select nnan i1 %gtzero, half %x, half %negx
423458
ret half %fabs
@@ -430,7 +465,7 @@ define half @select_fcmp_nnan_ugt_negzero(half %x) {
430465
; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
431466
; CHECK-NEXT: ret half [[FABS]]
432467
;
433-
%gtzero = fcmp ugt half %x, -0.0
468+
%gtzero = fcmp nnan ugt half %x, -0.0
434469
%negx = fsub nnan half 0.0, %x
435470
%fabs = select i1 %gtzero, half %x, half %negx
436471
ret half %fabs

0 commit comments

Comments
 (0)