forked from OSchip/llvm-project
[InstCombine] fix propagation of FMF through select-of-fnegs
The existing code was unquestionably wrong - it looked at one fneg and ignored the other 2 instructions. It was also untested, so it didn't make the list of bugs flagged by Alive2. This is an unusual propagation, but Alive2 agress that we can intersect the fnegs and union that with the select, then apply the results to both new instructions: https://alive2.llvm.org/ce/z/SF8_dt
This commit is contained in:
parent
22efb9d364
commit
5d7d689edf
|
@ -319,8 +319,16 @@ Instruction *InstCombinerImpl::foldSelectOpOp(SelectInst &SI, Instruction *TI,
|
|||
Value *X, *Y;
|
||||
if (match(TI, m_FNeg(m_Value(X))) && match(FI, m_FNeg(m_Value(Y))) &&
|
||||
(TI->hasOneUse() || FI->hasOneUse())) {
|
||||
// Intersect FMF from the fneg instructions and union those with the select.
|
||||
FastMathFlags FMF = TI->getFastMathFlags();
|
||||
FMF &= FI->getFastMathFlags();
|
||||
FMF |= SI.getFastMathFlags();
|
||||
Value *NewSel = Builder.CreateSelect(Cond, X, Y, SI.getName() + ".v", &SI);
|
||||
return UnaryOperator::CreateFNegFMF(NewSel, TI);
|
||||
if (auto *NewSelI = dyn_cast<Instruction>(NewSel))
|
||||
NewSelI->setFastMathFlags(FMF);
|
||||
Instruction *NewFNeg = UnaryOperator::CreateFNeg(NewSel);
|
||||
NewFNeg->setFastMathFlags(FMF);
|
||||
return NewFNeg;
|
||||
}
|
||||
|
||||
// Min/max intrinsic with a common operand can have the common operand pulled
|
||||
|
|
|
@ -441,7 +441,7 @@ define float @fneg_fneg_sel_extra_use3(float %x, float %y, i1 %cond) {
|
|||
define double @fneg_fneg_sel_fmf1(double %x, double %y, i1 %cond) {
|
||||
; CHECK-LABEL: @fneg_fneg_sel_fmf1(
|
||||
; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[COND:%.*]], double [[X:%.*]], double [[Y:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = fneg nnan double [[SEL_V]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = fneg double [[SEL_V]]
|
||||
; CHECK-NEXT: ret double [[SEL]]
|
||||
;
|
||||
%n1 = fneg nnan double %x
|
||||
|
@ -452,8 +452,8 @@ define double @fneg_fneg_sel_fmf1(double %x, double %y, i1 %cond) {
|
|||
|
||||
define double @fneg_fneg_sel_fmf2(double %x, double %y, i1 %cond) {
|
||||
; CHECK-LABEL: @fneg_fneg_sel_fmf2(
|
||||
; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[COND:%.*]], double [[X:%.*]], double [[Y:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = fneg nnan ninf double [[SEL_V]]
|
||||
; CHECK-NEXT: [[SEL_V:%.*]] = select ninf i1 [[COND:%.*]], double [[X:%.*]], double [[Y:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = fneg ninf double [[SEL_V]]
|
||||
; CHECK-NEXT: ret double [[SEL]]
|
||||
;
|
||||
%n1 = fneg nnan ninf double %x
|
||||
|
@ -464,8 +464,8 @@ define double @fneg_fneg_sel_fmf2(double %x, double %y, i1 %cond) {
|
|||
|
||||
define double @fneg_fneg_sel_fmf3(double %x, double %y, i1 %cond) {
|
||||
; CHECK-LABEL: @fneg_fneg_sel_fmf3(
|
||||
; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[COND:%.*]], double [[X:%.*]], double [[Y:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = fneg nnan ninf double [[SEL_V]]
|
||||
; CHECK-NEXT: [[SEL_V:%.*]] = select ninf i1 [[COND:%.*]], double [[X:%.*]], double [[Y:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = fneg ninf double [[SEL_V]]
|
||||
; CHECK-NEXT: ret double [[SEL]]
|
||||
;
|
||||
%n1 = fneg nnan ninf double %x
|
||||
|
@ -476,8 +476,8 @@ define double @fneg_fneg_sel_fmf3(double %x, double %y, i1 %cond) {
|
|||
|
||||
define double @fneg_fneg_sel_fmf4(double %x, double %y, i1 %cond) {
|
||||
; CHECK-LABEL: @fneg_fneg_sel_fmf4(
|
||||
; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[COND:%.*]], double [[X:%.*]], double [[Y:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = fneg nnan double [[SEL_V]]
|
||||
; CHECK-NEXT: [[SEL_V:%.*]] = select nnan ninf nsz i1 [[COND:%.*]], double [[X:%.*]], double [[Y:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = fneg nnan ninf nsz double [[SEL_V]]
|
||||
; CHECK-NEXT: ret double [[SEL]]
|
||||
;
|
||||
%n1 = fneg nnan double %x
|
||||
|
|
Loading…
Reference in New Issue