Skip to content

Commit e6836ce

Browse files
michele-scandalechencha3
authored andcommitted
[InstCombine] Fix for folding select into floating point binary operators. (llvm#83200)
Folding a `select` into a floating point binary operators can only be done if the result is preserved for both case. In particular, if the other operand of the `select` can be a NaN, then the transformation won't preserve the result value.
1 parent c2b28f8 commit e6836ce

File tree

10 files changed

+217
-185
lines changed

10 files changed

+217
-185
lines changed

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -536,19 +536,29 @@ Instruction *InstCombinerImpl::foldSelectIntoOp(SelectInst &SI, Value *TrueVal,
536536
// between 0, 1 and -1.
537537
const APInt *OOpC;
538538
bool OOpIsAPInt = match(OOp, m_APInt(OOpC));
539-
if (!isa<Constant>(OOp) ||
540-
(OOpIsAPInt && isSelect01(C->getUniqueInteger(), *OOpC))) {
541-
Value *NewSel = Builder.CreateSelect(SI.getCondition(), Swapped ? C : OOp,
542-
Swapped ? OOp : C, "", &SI);
543-
if (isa<FPMathOperator>(&SI))
544-
cast<Instruction>(NewSel)->setFastMathFlags(FMF);
545-
NewSel->takeName(TVI);
546-
BinaryOperator *BO =
547-
BinaryOperator::Create(TVI->getOpcode(), FalseVal, NewSel);
548-
BO->copyIRFlags(TVI);
549-
return BO;
550-
}
551-
return nullptr;
539+
if (isa<Constant>(OOp) &&
540+
(!OOpIsAPInt || !isSelect01(C->getUniqueInteger(), *OOpC)))
541+
return nullptr;
542+
543+
// If the false value is a NaN then we have that the floating point math
544+
// operation in the transformed code may not preserve the exact NaN
545+
// bit-pattern -- e.g. `fadd sNaN, 0.0 -> qNaN`.
546+
// This makes the transformation incorrect since the original program would
547+
// have preserved the exact NaN bit-pattern.
548+
// Avoid the folding if the false value might be a NaN.
549+
if (isa<FPMathOperator>(&SI) &&
550+
!computeKnownFPClass(FalseVal, FMF, fcNan, &SI).isKnownNeverNaN())
551+
return nullptr;
552+
553+
Value *NewSel = Builder.CreateSelect(SI.getCondition(), Swapped ? C : OOp,
554+
Swapped ? OOp : C, "", &SI);
555+
if (isa<FPMathOperator>(&SI))
556+
cast<Instruction>(NewSel)->setFastMathFlags(FMF);
557+
NewSel->takeName(TVI);
558+
BinaryOperator *BO =
559+
BinaryOperator::Create(TVI->getOpcode(), FalseVal, NewSel);
560+
BO->copyIRFlags(TVI);
561+
return BO;
552562
};
553563

554564
if (Instruction *R = TryFoldSelectIntoOp(SI, TrueVal, FalseVal, false))

llvm/test/Transforms/InstCombine/fold-select-fmul-if-zero.ll

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -427,28 +427,28 @@ define float @fmul_by_snan_if_0_oeq_zero_f32(float %x) {
427427
define float @fmul_by_var_if_0_oeq_zero_f32(float %x, float %y) {
428428
; CHECK-LABEL: @fmul_by_var_if_0_oeq_zero_f32(
429429
; CHECK-NEXT: [[X_IS_ZERO:%.*]] = fcmp oeq float [[X:%.*]], 0.000000e+00
430-
; CHECK-NEXT: [[SCALED_X:%.*]] = select i1 [[X_IS_ZERO]], float [[Y:%.*]], float 1.000000e+00
430+
; CHECK-NEXT: [[SCALED_X:%.*]] = select nnan i1 [[X_IS_ZERO]], float [[Y:%.*]], float 1.000000e+00
431431
; CHECK-NEXT: [[SCALED_IF_DENORMAL:%.*]] = fmul float [[SCALED_X]], [[X]]
432432
; CHECK-NEXT: ret float [[SCALED_IF_DENORMAL]]
433433
;
434434
%x.is.zero = fcmp oeq float %x, 0.0
435435
%scaled.x = fmul float %x, %y
436-
%scaled.if.denormal = select i1 %x.is.zero, float %scaled.x, float %x
436+
%scaled.if.denormal = select nnan i1 %x.is.zero, float %scaled.x, float %x
437437
ret float %scaled.if.denormal
438438
}
439439

440440
define float @fmul_by_fabs_var_if_0_oeq_zero_f32(float %x, float %y) {
441441
; CHECK-LABEL: @fmul_by_fabs_var_if_0_oeq_zero_f32(
442442
; CHECK-NEXT: [[Y_FABS:%.*]] = call float @llvm.fabs.f32(float [[Y:%.*]])
443443
; CHECK-NEXT: [[X_IS_ZERO:%.*]] = fcmp oeq float [[X:%.*]], 0.000000e+00
444-
; CHECK-NEXT: [[SCALED_X:%.*]] = select i1 [[X_IS_ZERO]], float [[Y_FABS]], float 1.000000e+00
444+
; CHECK-NEXT: [[SCALED_X:%.*]] = select nnan i1 [[X_IS_ZERO]], float [[Y_FABS]], float 1.000000e+00
445445
; CHECK-NEXT: [[SCALED_IF_DENORMAL:%.*]] = fmul float [[SCALED_X]], [[X]]
446446
; CHECK-NEXT: ret float [[SCALED_IF_DENORMAL]]
447447
;
448448
%y.fabs = call float @llvm.fabs.f32(float %y)
449449
%x.is.zero = fcmp oeq float %x, 0.0
450450
%scaled.x = fmul float %x, %y.fabs
451-
%scaled.if.denormal = select i1 %x.is.zero, float %scaled.x, float %x
451+
%scaled.if.denormal = select nnan i1 %x.is.zero, float %scaled.x, float %x
452452
ret float %scaled.if.denormal
453453
}
454454

@@ -467,55 +467,55 @@ define float @fmul_by_fabs_nnan_ninf_var_if_0_oeq_zero_f32(float %x, float %y) {
467467
define float @fmul_by_var_if_0_oeq_zero_f32_nsz_fmul(float %x, float %y) {
468468
; CHECK-LABEL: @fmul_by_var_if_0_oeq_zero_f32_nsz_fmul(
469469
; CHECK-NEXT: [[X_IS_ZERO:%.*]] = fcmp oeq float [[X:%.*]], 0.000000e+00
470-
; CHECK-NEXT: [[SCALED_X:%.*]] = select i1 [[X_IS_ZERO]], float [[Y:%.*]], float 1.000000e+00
470+
; CHECK-NEXT: [[SCALED_X:%.*]] = select nnan i1 [[X_IS_ZERO]], float [[Y:%.*]], float 1.000000e+00
471471
; CHECK-NEXT: [[SCALED_IF_DENORMAL:%.*]] = fmul nsz float [[SCALED_X]], [[X]]
472472
; CHECK-NEXT: ret float [[SCALED_IF_DENORMAL]]
473473
;
474474
%x.is.zero = fcmp oeq float %x, 0.0
475475
%scaled.x = fmul nsz float %x, %y
476-
%scaled.if.denormal = select i1 %x.is.zero, float %scaled.x, float %x
476+
%scaled.if.denormal = select nnan i1 %x.is.zero, float %scaled.x, float %x
477477
ret float %scaled.if.denormal
478478
}
479479

480480
; nsz ninf is not sufficient
481481
define float @fmul_by_var_if_0_oeq_zero_f32_nsz_ninf_fmul(float %x, float %y) {
482482
; CHECK-LABEL: @fmul_by_var_if_0_oeq_zero_f32_nsz_ninf_fmul(
483483
; CHECK-NEXT: [[X_IS_ZERO:%.*]] = fcmp oeq float [[X:%.*]], 0.000000e+00
484-
; CHECK-NEXT: [[SCALED_X:%.*]] = select i1 [[X_IS_ZERO]], float [[Y:%.*]], float 1.000000e+00
484+
; CHECK-NEXT: [[SCALED_X:%.*]] = select nnan i1 [[X_IS_ZERO]], float [[Y:%.*]], float 1.000000e+00
485485
; CHECK-NEXT: [[SCALED_IF_DENORMAL:%.*]] = fmul ninf nsz float [[SCALED_X]], [[X]]
486486
; CHECK-NEXT: ret float [[SCALED_IF_DENORMAL]]
487487
;
488488
%x.is.zero = fcmp oeq float %x, 0.0
489489
%scaled.x = fmul nsz ninf float %x, %y
490-
%scaled.if.denormal = select i1 %x.is.zero, float %scaled.x, float %x
490+
%scaled.if.denormal = select nnan i1 %x.is.zero, float %scaled.x, float %x
491491
ret float %scaled.if.denormal
492492
}
493493

494494
; nsz nnan is not sufficient
495495
define float @fmul_by_var_if_0_oeq_zero_f32_nsz_nnan_fmul(float %x, float %y) {
496496
; CHECK-LABEL: @fmul_by_var_if_0_oeq_zero_f32_nsz_nnan_fmul(
497497
; CHECK-NEXT: [[X_IS_ZERO:%.*]] = fcmp oeq float [[X:%.*]], 0.000000e+00
498-
; CHECK-NEXT: [[SCALED_X:%.*]] = select i1 [[X_IS_ZERO]], float [[Y:%.*]], float 1.000000e+00
498+
; CHECK-NEXT: [[SCALED_X:%.*]] = select nnan i1 [[X_IS_ZERO]], float [[Y:%.*]], float 1.000000e+00
499499
; CHECK-NEXT: [[SCALED_IF_DENORMAL:%.*]] = fmul nnan nsz float [[SCALED_X]], [[X]]
500500
; CHECK-NEXT: ret float [[SCALED_IF_DENORMAL]]
501501
;
502502
%x.is.zero = fcmp oeq float %x, 0.0
503503
%scaled.x = fmul nsz nnan float %x, %y
504-
%scaled.if.denormal = select i1 %x.is.zero, float %scaled.x, float %x
504+
%scaled.if.denormal = select nnan i1 %x.is.zero, float %scaled.x, float %x
505505
ret float %scaled.if.denormal
506506
}
507507

508508
; nnan ninf is not sufficient
509509
define float @fmul_by_var_if_0_oeq_zero_f32_nnan_ninf_fmul(float %x, float %y) {
510510
; CHECK-LABEL: @fmul_by_var_if_0_oeq_zero_f32_nnan_ninf_fmul(
511511
; CHECK-NEXT: [[X_IS_ZERO:%.*]] = fcmp oeq float [[X:%.*]], 0.000000e+00
512-
; CHECK-NEXT: [[SCALED_X:%.*]] = select i1 [[X_IS_ZERO]], float [[Y:%.*]], float 1.000000e+00
512+
; CHECK-NEXT: [[SCALED_X:%.*]] = select nnan i1 [[X_IS_ZERO]], float [[Y:%.*]], float 1.000000e+00
513513
; CHECK-NEXT: [[SCALED_IF_DENORMAL:%.*]] = fmul nnan ninf float [[SCALED_X]], [[X]]
514514
; CHECK-NEXT: ret float [[SCALED_IF_DENORMAL]]
515515
;
516516
%x.is.zero = fcmp oeq float %x, 0.0
517517
%scaled.x = fmul nnan ninf float %x, %y
518-
%scaled.if.denormal = select i1 %x.is.zero, float %scaled.x, float %x
518+
%scaled.if.denormal = select nnan i1 %x.is.zero, float %scaled.x, float %x
519519
ret float %scaled.if.denormal
520520
}
521521

@@ -558,53 +558,53 @@ define float @fmul_by_var_if_0_oeq_zero_f32_fmul_nnan_ninf_select_nsz_inverted(f
558558
define float @fmul_by_var_if_0_oeq_zero_f32_fmul_nnan_ninf_nsz(float %x, float %y) {
559559
; CHECK-LABEL: @fmul_by_var_if_0_oeq_zero_f32_fmul_nnan_ninf_nsz(
560560
; CHECK-NEXT: [[X_IS_ZERO:%.*]] = fcmp oeq float [[X:%.*]], 0.000000e+00
561-
; CHECK-NEXT: [[SCALED_X:%.*]] = select i1 [[X_IS_ZERO]], float [[Y:%.*]], float 1.000000e+00
561+
; CHECK-NEXT: [[SCALED_X:%.*]] = select nnan i1 [[X_IS_ZERO]], float [[Y:%.*]], float 1.000000e+00
562562
; CHECK-NEXT: [[SCALED_IF_DENORMAL:%.*]] = fmul nnan ninf nsz float [[SCALED_X]], [[X]]
563563
; CHECK-NEXT: ret float [[SCALED_IF_DENORMAL]]
564564
;
565565
%x.is.zero = fcmp oeq float %x, 0.0
566566
%scaled.x = fmul nnan ninf nsz float %x, %y
567-
%scaled.if.denormal = select i1 %x.is.zero, float %scaled.x, float %x
567+
%scaled.if.denormal = select nnan i1 %x.is.zero, float %scaled.x, float %x
568568
ret float %scaled.if.denormal
569569
}
570570

571571
define float @fmul_by_var_if_0_oeq_zero_f32_fmul_nnan_ninf_nsz_commuted(float %x, float %y) {
572572
; CHECK-LABEL: @fmul_by_var_if_0_oeq_zero_f32_fmul_nnan_ninf_nsz_commuted(
573573
; CHECK-NEXT: [[X_IS_ZERO:%.*]] = fcmp oeq float [[X:%.*]], 0.000000e+00
574-
; CHECK-NEXT: [[SCALED_X:%.*]] = select i1 [[X_IS_ZERO]], float [[Y:%.*]], float 1.000000e+00
574+
; CHECK-NEXT: [[SCALED_X:%.*]] = select nnan i1 [[X_IS_ZERO]], float [[Y:%.*]], float 1.000000e+00
575575
; CHECK-NEXT: [[SCALED_IF_DENORMAL:%.*]] = fmul nnan ninf nsz float [[SCALED_X]], [[X]]
576576
; CHECK-NEXT: ret float [[SCALED_IF_DENORMAL]]
577577
;
578578
%x.is.zero = fcmp oeq float %x, 0.0
579579
%scaled.x = fmul nnan ninf nsz float %y, %x
580-
%scaled.if.denormal = select i1 %x.is.zero, float %scaled.x, float %x
580+
%scaled.if.denormal = select nnan i1 %x.is.zero, float %scaled.x, float %x
581581
ret float %scaled.if.denormal
582582
}
583583

584584
; test computeKnownFPClass is checked
585585
define float @fmul_by_var_if_0_oeq_zero_f32_fmul_nnan_ninf_select_known_never_negzero(float %x, float nofpclass(nzero) %y) {
586586
; CHECK-LABEL: @fmul_by_var_if_0_oeq_zero_f32_fmul_nnan_ninf_select_known_never_negzero(
587587
; CHECK-NEXT: [[X_IS_ZERO:%.*]] = fcmp oeq float [[X:%.*]], 0.000000e+00
588-
; CHECK-NEXT: [[SCALED_X:%.*]] = select i1 [[X_IS_ZERO]], float [[Y:%.*]], float 1.000000e+00
588+
; CHECK-NEXT: [[SCALED_X:%.*]] = select nnan i1 [[X_IS_ZERO]], float [[Y:%.*]], float 1.000000e+00
589589
; CHECK-NEXT: [[SCALED_IF_DENORMAL:%.*]] = fmul nnan ninf float [[SCALED_X]], [[X]]
590590
; CHECK-NEXT: ret float [[SCALED_IF_DENORMAL]]
591591
;
592592
%x.is.zero = fcmp oeq float %x, 0.0
593593
%scaled.x = fmul nnan ninf float %x, %y
594-
%scaled.if.denormal = select i1 %x.is.zero, float %scaled.x, float %x
594+
%scaled.if.denormal = select nnan i1 %x.is.zero, float %scaled.x, float %x
595595
ret float %scaled.if.denormal
596596
}
597597

598598
define float @fmul_by_var_if_0_oeq_zero_f32_fmul_nnan_ninf_select_known_never_negzero_negsub(float %x, float nofpclass(nzero nsub) %y) {
599599
; CHECK-LABEL: @fmul_by_var_if_0_oeq_zero_f32_fmul_nnan_ninf_select_known_never_negzero_negsub(
600600
; CHECK-NEXT: [[X_IS_ZERO:%.*]] = fcmp oeq float [[X:%.*]], 0.000000e+00
601-
; CHECK-NEXT: [[SCALED_X:%.*]] = select i1 [[X_IS_ZERO]], float [[Y:%.*]], float 1.000000e+00
601+
; CHECK-NEXT: [[SCALED_X:%.*]] = select nnan i1 [[X_IS_ZERO]], float [[Y:%.*]], float 1.000000e+00
602602
; CHECK-NEXT: [[SCALED_IF_DENORMAL:%.*]] = fmul nnan ninf float [[SCALED_X]], [[X]]
603603
; CHECK-NEXT: ret float [[SCALED_IF_DENORMAL]]
604604
;
605605
%x.is.zero = fcmp oeq float %x, 0.0
606606
%scaled.x = fmul nnan ninf float %x, %y
607-
%scaled.if.denormal = select i1 %x.is.zero, float %scaled.x, float %x
607+
%scaled.if.denormal = select nnan i1 %x.is.zero, float %scaled.x, float %x
608608
ret float %scaled.if.denormal
609609
}
610610

@@ -622,26 +622,26 @@ define float @fmul_by_var_if_0_oeq_zero_f32_known_never_nan_inf_select_nsz(float
622622
define float @fmul_by_var_if_0_oeq_zero_f32_fmul_known_never_nan_inf_negzero(float %x, float nofpclass(nan inf nzero) %y) {
623623
; CHECK-LABEL: @fmul_by_var_if_0_oeq_zero_f32_fmul_known_never_nan_inf_negzero(
624624
; CHECK-NEXT: [[X_IS_ZERO:%.*]] = fcmp oeq float [[X:%.*]], 0.000000e+00
625-
; CHECK-NEXT: [[SCALED_X:%.*]] = select i1 [[X_IS_ZERO]], float [[Y:%.*]], float 1.000000e+00
625+
; CHECK-NEXT: [[SCALED_X:%.*]] = select nnan i1 [[X_IS_ZERO]], float [[Y:%.*]], float 1.000000e+00
626626
; CHECK-NEXT: [[SCALED_IF_DENORMAL:%.*]] = fmul float [[SCALED_X]], [[X]]
627627
; CHECK-NEXT: ret float [[SCALED_IF_DENORMAL]]
628628
;
629629
%x.is.zero = fcmp oeq float %x, 0.0
630630
%scaled.x = fmul float %x, %y
631-
%scaled.if.denormal = select i1 %x.is.zero, float %scaled.x, float %x
631+
%scaled.if.denormal = select nnan i1 %x.is.zero, float %scaled.x, float %x
632632
ret float %scaled.if.denormal
633633
}
634634

635635
define float @fmul_by_var_if_0_oeq_zero_f32_fmul_known_never_nan_inf_negzero_nsub(float %x, float nofpclass(nan inf nzero nsub) %y) {
636636
; CHECK-LABEL: @fmul_by_var_if_0_oeq_zero_f32_fmul_known_never_nan_inf_negzero_nsub(
637637
; CHECK-NEXT: [[X_IS_ZERO:%.*]] = fcmp oeq float [[X:%.*]], 0.000000e+00
638-
; CHECK-NEXT: [[SCALED_X:%.*]] = select i1 [[X_IS_ZERO]], float [[Y:%.*]], float 1.000000e+00
638+
; CHECK-NEXT: [[SCALED_X:%.*]] = select nnan i1 [[X_IS_ZERO]], float [[Y:%.*]], float 1.000000e+00
639639
; CHECK-NEXT: [[SCALED_IF_DENORMAL:%.*]] = fmul float [[SCALED_X]], [[X]]
640640
; CHECK-NEXT: ret float [[SCALED_IF_DENORMAL]]
641641
;
642642
%x.is.zero = fcmp oeq float %x, 0.0
643643
%scaled.x = fmul float %x, %y
644-
%scaled.if.denormal = select i1 %x.is.zero, float %scaled.x, float %x
644+
%scaled.if.denormal = select nnan i1 %x.is.zero, float %scaled.x, float %x
645645
ret float %scaled.if.denormal
646646
}
647647

@@ -692,26 +692,26 @@ define float @fmul_by_var_if_not_one_0_zero_f32_assume_finite_fmul_nsz(float %x,
692692
define float @fmul_by_self_if_0_oeq_zero_f32(float %x) {
693693
; CHECK-LABEL: @fmul_by_self_if_0_oeq_zero_f32(
694694
; CHECK-NEXT: [[X_IS_ZERO:%.*]] = fcmp oeq float [[X:%.*]], 0.000000e+00
695-
; CHECK-NEXT: [[SCALED_X:%.*]] = select i1 [[X_IS_ZERO]], float [[X]], float 1.000000e+00
695+
; CHECK-NEXT: [[SCALED_X:%.*]] = select nnan i1 [[X_IS_ZERO]], float [[X]], float 1.000000e+00
696696
; CHECK-NEXT: [[SCALED_IF_DENORMAL:%.*]] = fmul float [[SCALED_X]], [[X]]
697697
; CHECK-NEXT: ret float [[SCALED_IF_DENORMAL]]
698698
;
699699
%x.is.zero = fcmp oeq float %x, 0.0
700700
%scaled.x = fmul float %x, %x
701-
%scaled.if.denormal = select i1 %x.is.zero, float %scaled.x, float %x
701+
%scaled.if.denormal = select nnan i1 %x.is.zero, float %scaled.x, float %x
702702
ret float %scaled.if.denormal
703703
}
704704

705705
define float @fmul_by_self_if_0_oeq_zero_f32_fmul_nnan_ninf_nsz(float %x) {
706706
; CHECK-LABEL: @fmul_by_self_if_0_oeq_zero_f32_fmul_nnan_ninf_nsz(
707707
; CHECK-NEXT: [[X_IS_ZERO:%.*]] = fcmp oeq float [[X:%.*]], 0.000000e+00
708-
; CHECK-NEXT: [[SCALED_X:%.*]] = select i1 [[X_IS_ZERO]], float [[X]], float 1.000000e+00
708+
; CHECK-NEXT: [[SCALED_X:%.*]] = select nnan i1 [[X_IS_ZERO]], float [[X]], float 1.000000e+00
709709
; CHECK-NEXT: [[SCALED_IF_DENORMAL:%.*]] = fmul nnan ninf nsz float [[SCALED_X]], [[X]]
710710
; CHECK-NEXT: ret float [[SCALED_IF_DENORMAL]]
711711
;
712712
%x.is.zero = fcmp oeq float %x, 0.0
713713
%scaled.x = fmul nnan ninf nsz float %x, %x
714-
%scaled.if.denormal = select i1 %x.is.zero, float %scaled.x, float %x
714+
%scaled.if.denormal = select nnan i1 %x.is.zero, float %scaled.x, float %x
715715
ret float %scaled.if.denormal
716716
}
717717

0 commit comments

Comments
 (0)