!isConstantFPBuildVectorOrConstantFP(NewCF))
return SDValue();
- return DAG.getSelect(DL, VT, Sel.getOperand(0), NewCT, NewCF);
+ SDValue SelectOp = DAG.getSelect(DL, VT, Sel.getOperand(0), NewCT, NewCF);
+ SelectOp->setFlags(BO->getFlags());
+ return SelectOp;
}
static SDValue foldAddSubBoolOfMaskedVal(SDNode *N, SelectionDAG &DAG) {
EVT VT = N->getValueType(0);
EVT VT0 = N0.getValueType();
SDLoc DL(N);
+ SDNodeFlags Flags = N->getFlags();
if (SDValue V = DAG.simplifySelect(N0, N1, N2))
return V;
SDValue Cond0 = N0->getOperand(0);
SDValue Cond1 = N0->getOperand(1);
SDValue InnerSelect =
- DAG.getNode(ISD::SELECT, DL, N1.getValueType(), Cond1, N1, N2);
+ DAG.getNode(ISD::SELECT, DL, N1.getValueType(), Cond1, N1, N2, Flags);
if (normalizeToSequence || !InnerSelect.use_empty())
return DAG.getNode(ISD::SELECT, DL, N1.getValueType(), Cond0,
- InnerSelect, N2);
+ InnerSelect, N2, Flags);
// Cleanup on failure.
if (InnerSelect.use_empty())
recursivelyDeleteUnusedNodes(InnerSelect.getNode());
if (N0->getOpcode() == ISD::OR && N0->hasOneUse()) {
SDValue Cond0 = N0->getOperand(0);
SDValue Cond1 = N0->getOperand(1);
- SDValue InnerSelect =
- DAG.getNode(ISD::SELECT, DL, N1.getValueType(), Cond1, N1, N2);
+ SDValue InnerSelect = DAG.getNode(ISD::SELECT, DL, N1.getValueType(),
+ Cond1, N1, N2, Flags);
if (normalizeToSequence || !InnerSelect.use_empty())
return DAG.getNode(ISD::SELECT, DL, N1.getValueType(), Cond0, N1,
- InnerSelect);
+ InnerSelect, Flags);
// Cleanup on failure.
if (InnerSelect.use_empty())
recursivelyDeleteUnusedNodes(InnerSelect.getNode());
// Create the actual and node if we can generate good code for it.
if (!normalizeToSequence) {
SDValue And = DAG.getNode(ISD::AND, DL, N0.getValueType(), N0, N1_0);
- return DAG.getNode(ISD::SELECT, DL, N1.getValueType(), And, N1_1, N2);
+ return DAG.getNode(ISD::SELECT, DL, N1.getValueType(), And, N1_1,
+ N2, Flags);
}
// Otherwise see if we can optimize the "and" to a better pattern.
- if (SDValue Combined = visitANDLike(N0, N1_0, N))
+ if (SDValue Combined = visitANDLike(N0, N1_0, N)) {
return DAG.getNode(ISD::SELECT, DL, N1.getValueType(), Combined, N1_1,
- N2);
+ N2, Flags);
+ }
}
}
// select Cond0, X, (select Cond1, X, Y) -> select (or Cond0, Cond1), X, Y
// Create the actual or node if we can generate good code for it.
if (!normalizeToSequence) {
SDValue Or = DAG.getNode(ISD::OR, DL, N0.getValueType(), N0, N2_0);
- return DAG.getNode(ISD::SELECT, DL, N1.getValueType(), Or, N1, N2_2);
+ return DAG.getNode(ISD::SELECT, DL, N1.getValueType(), Or, N1,
+ N2_2, Flags);
}
// Otherwise see if we can optimize to a better pattern.
if (SDValue Combined = visitORLike(N0, N2_0, N))
return DAG.getNode(ISD::SELECT, DL, N1.getValueType(), Combined, N1,
- N2_2);
+ N2_2, Flags);
}
}
}
// select (not Cond), N1, N2 -> select Cond, N2, N1
- if (SDValue F = extractBooleanFlip(N0, TLI))
- return DAG.getSelect(DL, VT, F, N2, N1);
+ if (SDValue F = extractBooleanFlip(N0, TLI)) {
+ SDValue SelectOp = DAG.getSelect(DL, VT, F, N2, N1);
+ SelectOp->setFlags(Flags);
+ return SelectOp;
+ }
// Fold selects based on a setcc into other things, such as min/max/abs.
if (N0.getOpcode() == ISD::SETCC) {
TLI.isOperationLegalOrCustom(ISD::SELECT_CC, VT))) {
// Any flags available in a select/setcc fold will be on the setcc as they
// migrated from fcmp
- const SDNodeFlags Flags = N0.getNode()->getFlags();
+ Flags = N0.getNode()->getFlags();
SDValue SelectNode = DAG.getNode(ISD::SELECT_CC, DL, VT, Cond0, Cond1, N1,
N2, N0.getOperand(2));
SelectNode->setFlags(Flags);
return N2;
} else if (SCC.getOpcode() == ISD::SETCC) {
// Fold to a simpler select_cc
- return DAG.getNode(ISD::SELECT_CC, SDLoc(N), N2.getValueType(),
- SCC.getOperand(0), SCC.getOperand(1), N2, N3,
- SCC.getOperand(2));
+ SDValue SelectOp = DAG.getNode(
+ ISD::SELECT_CC, SDLoc(N), N2.getValueType(), SCC.getOperand(0),
+ SCC.getOperand(1), N2, N3, SCC.getOperand(2));
+ SelectOp->setFlags(SCC->getFlags());
+ return SelectOp;
}
}
// Check to see if we got a select_cc back (to turn into setcc/select).
// Otherwise, just return whatever node we got back, like fabs.
if (SCC.getOpcode() == ISD::SELECT_CC) {
+ const SDNodeFlags Flags = N0.getNode()->getFlags();
SDValue SETCC = DAG.getNode(ISD::SETCC, SDLoc(N0),
N0.getValueType(),
SCC.getOperand(0), SCC.getOperand(1),
- SCC.getOperand(4));
+ SCC.getOperand(4), Flags);
AddToWorklist(SETCC.getNode());
- return DAG.getSelect(SDLoc(SCC), SCC.getValueType(), SETCC,
- SCC.getOperand(2), SCC.getOperand(3));
+ SDValue SelectNode = DAG.getSelect(SDLoc(SCC), SCC.getValueType(), SETCC,
+ SCC.getOperand(2), SCC.getOperand(3));
+ SelectNode->setFlags(Flags);
+ return SelectNode;
}
return SCC;
--- /dev/null
+; RUN: llc < %s -mtriple=arm64-- | FileCheck %s
+
+; This test provides fmf coverage for DAG combining of selects
+
+; CHECK-LABEL: select_select_fold_select_and
+; CHECK: fminnm s1, s1, s2
+; CHECK-NEXT: fmaxnm s2, s0, s3
+; CHECK-NEXT: fmov
+; CHECK-NEXT: fccmp s1, s0, #4, lt
+; CHECK-NEXT: fcsel s2, s2, s0, gt
+
+; select Cond0, (select Cond1, X, Y), Y -> select (and Cond0, Cond1), X, Y
+define float @select_select_fold_select_and(float %w, float %x, float %y, float %z) {
+ %tmp21 = fcmp fast olt float %x, %y
+ %tmp22 = select fast i1 %tmp21, float %x, float %y
+ %tmp24 = fcmp fast ogt float %tmp22, %w
+ %tmp78 = fcmp fast ogt float %w, %z
+ %select0 = select fast i1 %tmp78, float %w, float %z
+ %select1 = select fast i1 %tmp21, float %select0, float %w
+ %select2 = select fast i1 %tmp24, float %select1, float %w
+ %tmp82 = fadd fast float %w, 5.000000e-01
+ %tmp102 = fadd fast float %tmp82, %select2
+ %cmp.i155.i.i = fcmp fast ogt float %tmp102, %tmp82
+ br i1 %cmp.i155.i.i, label %if.then.i157.i.i, label %if.end.i159.i.i
+
+if.then.i157.i.i: ; preds = %0
+ %add.i156.i.i = fadd fast float %select2, 1.000000e+00
+ br label %exit
+
+if.end.i159.i.i: ; preds = %0
+ %sub.i158.i.i = fadd fast float %w, 0xBFD99999A0000000
+ %sub15.i.i.i = fadd fast float %z, 0xBFD6666660000000
+ %tmp191 = fcmp fast ogt float %tmp82, 0.000000e+00
+ %select3 = select fast i1 %tmp191, float %sub.i158.i.i, float %sub15.i.i.i
+ br label %exit
+
+exit: ; preds = %if.end.i159.i.i, %if.then.i157.i.i
+ %phi1 = phi float [ %add.i156.i.i, %if.then.i157.i.i ], [ %select3, %if.end.i159.i.i ]
+ ret float %phi1
+}
+
+; CHECK-LABEL: select_select_fold_select_or
+; CHECK: fcmp s1, s2
+; CHECK-NEXT: fminnm s1, s1, s2
+; CHECK-NEXT: fmaxnm s2, s0, s3
+; CHECK-NEXT: fmov
+; CHECK-NEXT: fccmp s1, s0, #0, ge
+; CHECK-NEXT: fcsel s2, s0, s2, gt
+
+; select Cond0, X, (select Cond1, X, Y) -> select (or Cond0, Cond1), X, Y
+define float @select_select_fold_select_or(float %w, float %x, float %y, float %z) {
+ %tmp21 = fcmp fast olt float %x, %y
+ %tmp22 = select fast i1 %tmp21, float %x, float %y
+ %tmp24 = fcmp fast ogt float %tmp22, %w
+ %tmp78 = fcmp fast ogt float %w, %z
+ %select0 = select fast i1 %tmp78, float %w, float %z
+ %select1 = select fast i1 %tmp21, float %w, float %select0
+ %select2 = select fast i1 %tmp24, float %w, float %select1
+ %tmp82 = fadd fast float %w, 5.000000e-01
+ %tmp102 = fadd fast float %tmp82, %select2
+ %cmp.i155.i.i = fcmp fast ogt float %tmp102, %tmp82
+ br i1 %cmp.i155.i.i, label %if.then.i157.i.i, label %if.end.i159.i.i
+
+if.then.i157.i.i: ; preds = %0
+ %add.i156.i.i = fadd fast float %select2, 1.000000e+00
+ br label %exit
+
+if.end.i159.i.i: ; preds = %0
+ %sub.i158.i.i = fadd fast float %w, 0xBFD99999A0000000
+ %sub15.i.i.i = fadd fast float %z, 0xBFD6666660000000
+ %tmp191 = fcmp fast ogt float %tmp82, 0.000000e+00
+ %select3 = select fast i1 %tmp191, float %sub.i158.i.i, float %sub15.i.i.i
+ br label %exit
+
+exit: ; preds = %if.end.i159.i.i, %if.then.i157.i.i
+ %phi1 = phi float [ %add.i156.i.i, %if.then.i157.i.i ], [ %select3, %if.end.i159.i.i ]
+ ret float %phi1
+}