summaryrefslogtreecommitdiff
path: root/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp')
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp1486
1 files changed, 1090 insertions, 396 deletions
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 615bea2a4905..b104e995019f 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -461,8 +461,7 @@ namespace {
SDValue visitAssertExt(SDNode *N);
SDValue visitAssertAlign(SDNode *N);
SDValue visitSIGN_EXTEND_INREG(SDNode *N);
- SDValue visitSIGN_EXTEND_VECTOR_INREG(SDNode *N);
- SDValue visitZERO_EXTEND_VECTOR_INREG(SDNode *N);
+ SDValue visitEXTEND_VECTOR_INREG(SDNode *N);
SDValue visitTRUNCATE(SDNode *N);
SDValue visitBITCAST(SDNode *N);
SDValue visitFREEZE(SDNode *N);
@@ -547,8 +546,11 @@ namespace {
SDValue foldSignChangeInBitcast(SDNode *N);
SDValue foldSelectCCToShiftAnd(const SDLoc &DL, SDValue N0, SDValue N1,
SDValue N2, SDValue N3, ISD::CondCode CC);
+ SDValue foldSelectOfBinops(SDNode *N);
+ SDValue foldSextSetcc(SDNode *N);
SDValue foldLogicOfSetCCs(bool IsAnd, SDValue N0, SDValue N1,
const SDLoc &DL);
+ SDValue foldSubToUSubSat(EVT DstVT, SDNode *N);
SDValue unfoldMaskedMerge(SDNode *N);
SDValue unfoldExtremeBitClearingToShifts(SDNode *N);
SDValue SimplifySetCC(EVT VT, SDValue N0, SDValue N1, ISD::CondCode Cond,
@@ -1673,8 +1675,8 @@ SDValue DAGCombiner::visit(SDNode *N) {
case ISD::AssertZext: return visitAssertExt(N);
case ISD::AssertAlign: return visitAssertAlign(N);
case ISD::SIGN_EXTEND_INREG: return visitSIGN_EXTEND_INREG(N);
- case ISD::SIGN_EXTEND_VECTOR_INREG: return visitSIGN_EXTEND_VECTOR_INREG(N);
- case ISD::ZERO_EXTEND_VECTOR_INREG: return visitZERO_EXTEND_VECTOR_INREG(N);
+ case ISD::SIGN_EXTEND_VECTOR_INREG:
+ case ISD::ZERO_EXTEND_VECTOR_INREG: return visitEXTEND_VECTOR_INREG(N);
case ISD::TRUNCATE: return visitTRUNCATE(N);
case ISD::BITCAST: return visitBITCAST(N);
case ISD::BUILD_PAIR: return visitBUILD_PAIR(N);
@@ -2259,9 +2261,9 @@ SDValue DAGCombiner::visitADDLike(SDNode *N) {
return FoldedVOp;
// fold (add x, 0) -> x, vector edition
- if (ISD::isBuildVectorAllZeros(N1.getNode()))
+ if (ISD::isConstantSplatVectorAllZeros(N1.getNode()))
return N0;
- if (ISD::isBuildVectorAllZeros(N0.getNode()))
+ if (ISD::isConstantSplatVectorAllZeros(N0.getNode()))
return N1;
}
@@ -2337,6 +2339,23 @@ SDValue DAGCombiner::visitADDLike(SDNode *N) {
if (!reassociationCanBreakAddressingModePattern(ISD::ADD, DL, N0, N1)) {
if (SDValue RADD = reassociateOps(ISD::ADD, DL, N0, N1, N->getFlags()))
return RADD;
+
+ // Reassociate (add (or x, c), y) -> (add add(x, y), c)) if (or x, c) is
+ // equivalent to (add x, c).
+ auto ReassociateAddOr = [&](SDValue N0, SDValue N1) {
+ if (N0.getOpcode() == ISD::OR && N0.hasOneUse() &&
+ isConstantOrConstantVector(N0.getOperand(1), /* NoOpaque */ true) &&
+ DAG.haveNoCommonBitsSet(N0.getOperand(0), N0.getOperand(1))) {
+ return DAG.getNode(ISD::ADD, DL, VT,
+ DAG.getNode(ISD::ADD, DL, VT, N1, N0.getOperand(0)),
+ N0.getOperand(1));
+ }
+ return SDValue();
+ };
+ if (SDValue Add = ReassociateAddOr(N0, N1))
+ return Add;
+ if (SDValue Add = ReassociateAddOr(N1, N0))
+ return Add;
}
// fold ((0-A) + B) -> B-A
if (N0.getOpcode() == ISD::SUB && isNullOrNullSplat(N0.getOperand(0)))
@@ -2502,6 +2521,26 @@ SDValue DAGCombiner::visitADD(SDNode *N) {
return DAG.getNode(ISD::ADD, DL, VT, N0.getOperand(0), VS);
}
+ // Fold (add step_vector(c1), step_vector(c2) to step_vector(c1+c2))
+ if (N0.getOpcode() == ISD::STEP_VECTOR &&
+ N1.getOpcode() == ISD::STEP_VECTOR) {
+ const APInt &C0 = N0->getConstantOperandAPInt(0);
+ const APInt &C1 = N1->getConstantOperandAPInt(0);
+ APInt NewStep = C0 + C1;
+ return DAG.getStepVector(DL, VT, NewStep);
+ }
+
+ // Fold a + step_vector(c1) + step_vector(c2) to a + step_vector(c1+c2)
+ if ((N0.getOpcode() == ISD::ADD) &&
+ (N0.getOperand(1).getOpcode() == ISD::STEP_VECTOR) &&
+ (N1.getOpcode() == ISD::STEP_VECTOR)) {
+ const APInt &SV0 = N0.getOperand(1)->getConstantOperandAPInt(0);
+ const APInt &SV1 = N1->getConstantOperandAPInt(0);
+ APInt NewStep = SV0 + SV1;
+ SDValue SV = DAG.getStepVector(DL, VT, NewStep);
+ return DAG.getNode(ISD::ADD, DL, VT, N0.getOperand(0), SV);
+ }
+
return SDValue();
}
@@ -2517,9 +2556,9 @@ SDValue DAGCombiner::visitADDSAT(SDNode *N) {
// TODO SimplifyVBinOp
// fold (add_sat x, 0) -> x, vector edition
- if (ISD::isBuildVectorAllZeros(N1.getNode()))
+ if (ISD::isConstantSplatVectorAllZeros(N1.getNode()))
return N0;
- if (ISD::isBuildVectorAllZeros(N0.getNode()))
+ if (ISD::isConstantSplatVectorAllZeros(N0.getNode()))
return N1;
}
@@ -3125,6 +3164,82 @@ SDValue DAGCombiner::visitADDCARRYLike(SDValue N0, SDValue N1, SDValue CarryIn,
return SDValue();
}
+// Attempt to create a USUBSAT(LHS, RHS) node with DstVT, performing a
+// clamp/truncation if necessary.
+static SDValue getTruncatedUSUBSAT(EVT DstVT, EVT SrcVT, SDValue LHS,
+ SDValue RHS, SelectionDAG &DAG,
+ const SDLoc &DL) {
+ assert(DstVT.getScalarSizeInBits() <= SrcVT.getScalarSizeInBits() &&
+ "Illegal truncation");
+
+ if (DstVT == SrcVT)
+ return DAG.getNode(ISD::USUBSAT, DL, DstVT, LHS, RHS);
+
+ // If the LHS is zero-extended then we can perform the USUBSAT as DstVT by
+ // clamping RHS.
+ APInt UpperBits = APInt::getBitsSetFrom(SrcVT.getScalarSizeInBits(),
+ DstVT.getScalarSizeInBits());
+ if (!DAG.MaskedValueIsZero(LHS, UpperBits))
+ return SDValue();
+
+ SDValue SatLimit =
+ DAG.getConstant(APInt::getLowBitsSet(SrcVT.getScalarSizeInBits(),
+ DstVT.getScalarSizeInBits()),
+ DL, SrcVT);
+ RHS = DAG.getNode(ISD::UMIN, DL, SrcVT, RHS, SatLimit);
+ RHS = DAG.getNode(ISD::TRUNCATE, DL, DstVT, RHS);
+ LHS = DAG.getNode(ISD::TRUNCATE, DL, DstVT, LHS);
+ return DAG.getNode(ISD::USUBSAT, DL, DstVT, LHS, RHS);
+}
+
+// Try to find umax(a,b) - b or a - umin(a,b) patterns that may be converted to
+// usubsat(a,b), optionally as a truncated type.
+SDValue DAGCombiner::foldSubToUSubSat(EVT DstVT, SDNode *N) {
+ if (N->getOpcode() != ISD::SUB ||
+ !(!LegalOperations || hasOperation(ISD::USUBSAT, DstVT)))
+ return SDValue();
+
+ EVT SubVT = N->getValueType(0);
+ SDValue Op0 = N->getOperand(0);
+ SDValue Op1 = N->getOperand(1);
+
+ // Try to find umax(a,b) - b or a - umin(a,b) patterns
+ // they may be converted to usubsat(a,b).
+ if (Op0.getOpcode() == ISD::UMAX && Op0.hasOneUse()) {
+ SDValue MaxLHS = Op0.getOperand(0);
+ SDValue MaxRHS = Op0.getOperand(1);
+ if (MaxLHS == Op1)
+ return getTruncatedUSUBSAT(DstVT, SubVT, MaxRHS, Op1, DAG, SDLoc(N));
+ if (MaxRHS == Op1)
+ return getTruncatedUSUBSAT(DstVT, SubVT, MaxLHS, Op1, DAG, SDLoc(N));
+ }
+
+ if (Op1.getOpcode() == ISD::UMIN && Op1.hasOneUse()) {
+ SDValue MinLHS = Op1.getOperand(0);
+ SDValue MinRHS = Op1.getOperand(1);
+ if (MinLHS == Op0)
+ return getTruncatedUSUBSAT(DstVT, SubVT, Op0, MinRHS, DAG, SDLoc(N));
+ if (MinRHS == Op0)
+ return getTruncatedUSUBSAT(DstVT, SubVT, Op0, MinLHS, DAG, SDLoc(N));
+ }
+
+ // sub(a,trunc(umin(zext(a),b))) -> usubsat(a,trunc(umin(b,SatLimit)))
+ if (Op1.getOpcode() == ISD::TRUNCATE &&
+ Op1.getOperand(0).getOpcode() == ISD::UMIN &&
+ Op1.getOperand(0).hasOneUse()) {
+ SDValue MinLHS = Op1.getOperand(0).getOperand(0);
+ SDValue MinRHS = Op1.getOperand(0).getOperand(1);
+ if (MinLHS.getOpcode() == ISD::ZERO_EXTEND && MinLHS.getOperand(0) == Op0)
+ return getTruncatedUSUBSAT(DstVT, MinLHS.getValueType(), MinLHS, MinRHS,
+ DAG, SDLoc(N));
+ if (MinRHS.getOpcode() == ISD::ZERO_EXTEND && MinRHS.getOperand(0) == Op0)
+ return getTruncatedUSUBSAT(DstVT, MinLHS.getValueType(), MinRHS, MinLHS,
+ DAG, SDLoc(N));
+ }
+
+ return SDValue();
+}
+
// Since it may not be valid to emit a fold to zero for vector initializers
// check if we can before folding.
static SDValue tryFoldToZero(const SDLoc &DL, const TargetLowering &TLI, EVT VT,
@@ -3148,7 +3263,7 @@ SDValue DAGCombiner::visitSUB(SDNode *N) {
return FoldedVOp;
// fold (sub x, 0) -> x, vector edition
- if (ISD::isBuildVectorAllZeros(N1.getNode()))
+ if (ISD::isConstantSplatVectorAllZeros(N1.getNode()))
return N0;
}
@@ -3207,6 +3322,17 @@ SDValue DAGCombiner::visitSUB(SDNode *N) {
!TLI.isOperationLegalOrCustom(ISD::ABS, VT) &&
TLI.expandABS(N1.getNode(), Result, DAG, true))
return Result;
+
+ // Fold neg(splat(neg(x)) -> splat(x)
+ if (VT.isVector()) {
+ SDValue N1S = DAG.getSplatValue(N1, true);
+ if (N1S && N1S.getOpcode() == ISD::SUB &&
+ isNullConstant(N1S.getOperand(0))) {
+ if (VT.isScalableVector())
+ return DAG.getSplatVector(VT, DL, N1S.getOperand(1));
+ return DAG.getSplatBuildVector(VT, DL, N1S.getOperand(1));
+ }
+ }
}
// Canonicalize (sub -1, x) -> ~x, i.e. (xor x, -1)
@@ -3343,6 +3469,9 @@ SDValue DAGCombiner::visitSUB(SDNode *N) {
if (SDValue V = foldAddSubMasked1(false, N0, N1, DAG, SDLoc(N)))
return V;
+ if (SDValue V = foldSubToUSubSat(VT, N))
+ return V;
+
// (x - y) - 1 -> add (xor y, -1), x
if (N0.hasOneUse() && N0.getOpcode() == ISD::SUB && isOneOrOneSplat(N1)) {
SDValue Xor = DAG.getNode(ISD::XOR, DL, VT, N0.getOperand(1),
@@ -3434,12 +3563,19 @@ SDValue DAGCombiner::visitSUB(SDNode *N) {
}
}
- // canonicalize (sub X, (vscale * C)) to (add X, (vscale * -C))
+ // canonicalize (sub X, (vscale * C)) to (add X, (vscale * -C))
if (N1.getOpcode() == ISD::VSCALE) {
const APInt &IntVal = N1.getConstantOperandAPInt(0);
return DAG.getNode(ISD::ADD, DL, VT, N0, DAG.getVScale(DL, VT, -IntVal));
}
+ // canonicalize (sub X, step_vector(C)) to (add X, step_vector(-C))
+ if (N1.getOpcode() == ISD::STEP_VECTOR && N1.hasOneUse()) {
+ APInt NewStep = -N1.getConstantOperandAPInt(0);
+ return DAG.getNode(ISD::ADD, DL, VT, N0,
+ DAG.getStepVector(DL, VT, NewStep));
+ }
+
// Prefer an add for more folding potential and possibly better codegen:
// sub N0, (lshr N10, width-1) --> add N0, (ashr N10, width-1)
if (!LegalOperations && N1.getOpcode() == ISD::SRL && N1.hasOneUse()) {
@@ -3478,7 +3614,7 @@ SDValue DAGCombiner::visitSUBSAT(SDNode *N) {
// TODO SimplifyVBinOp
// fold (sub_sat x, 0) -> x, vector edition
- if (ISD::isBuildVectorAllZeros(N1.getNode()))
+ if (ISD::isConstantSplatVectorAllZeros(N1.getNode()))
return N0;
}
@@ -3814,6 +3950,15 @@ SDValue DAGCombiner::visitMUL(SDNode *N) {
return DAG.getVScale(SDLoc(N), VT, C0 * C1);
}
+ // Fold (mul step_vector(C0), C1) to (step_vector(C0 * C1)).
+ APInt MulVal;
+ if (N0.getOpcode() == ISD::STEP_VECTOR)
+ if (ISD::isConstantSplatVector(N1.getNode(), MulVal)) {
+ const APInt &C0 = N0.getConstantOperandAPInt(0);
+ APInt NewStep = C0 * MulVal;
+ return DAG.getStepVector(SDLoc(N), VT, NewStep);
+ }
+
// Fold ((mul x, 0/undef) -> 0,
// (mul x, 1) -> x) -> x)
// -> and(x, mask)
@@ -4323,11 +4468,15 @@ SDValue DAGCombiner::visitMULHS(SDNode *N) {
if (VT.isVector()) {
// fold (mulhs x, 0) -> 0
// do not return N0/N1, because undef node may exist.
- if (ISD::isBuildVectorAllZeros(N0.getNode()) ||
- ISD::isBuildVectorAllZeros(N1.getNode()))
+ if (ISD::isConstantSplatVectorAllZeros(N0.getNode()) ||
+ ISD::isConstantSplatVectorAllZeros(N1.getNode()))
return DAG.getConstant(0, DL, VT);
}
+ // fold (mulhs c1, c2)
+ if (SDValue C = DAG.FoldConstantArithmetic(ISD::MULHS, DL, VT, {N0, N1}))
+ return C;
+
// fold (mulhs x, 0) -> 0
if (isNullConstant(N1))
return N1;
@@ -4371,11 +4520,15 @@ SDValue DAGCombiner::visitMULHU(SDNode *N) {
if (VT.isVector()) {
// fold (mulhu x, 0) -> 0
// do not return N0/N1, because undef node may exist.
- if (ISD::isBuildVectorAllZeros(N0.getNode()) ||
- ISD::isBuildVectorAllZeros(N1.getNode()))
+ if (ISD::isConstantSplatVectorAllZeros(N0.getNode()) ||
+ ISD::isConstantSplatVectorAllZeros(N1.getNode()))
return DAG.getConstant(0, DL, VT);
}
+ // fold (mulhu c1, c2)
+ if (SDValue C = DAG.FoldConstantArithmetic(ISD::MULHU, DL, VT, {N0, N1}))
+ return C;
+
// fold (mulhu x, 0) -> 0
if (isNullConstant(N1))
return N1;
@@ -4551,6 +4704,21 @@ SDValue DAGCombiner::visitMULO(SDNode *N) {
EVT CarryVT = N->getValueType(1);
SDLoc DL(N);
+ ConstantSDNode *N0C = isConstOrConstSplat(N0);
+ ConstantSDNode *N1C = isConstOrConstSplat(N1);
+
+ // fold operation with constant operands.
+ // TODO: Move this to FoldConstantArithmetic when it supports nodes with
+ // multiple results.
+ if (N0C && N1C) {
+ bool Overflow;
+ APInt Result =
+ IsSigned ? N0C->getAPIntValue().smul_ov(N1C->getAPIntValue(), Overflow)
+ : N0C->getAPIntValue().umul_ov(N1C->getAPIntValue(), Overflow);
+ return CombineTo(N, DAG.getConstant(Result, DL, VT),
+ DAG.getBoolConstant(Overflow, DL, CarryVT, CarryVT));
+ }
+
// canonicalize constant to RHS.
if (DAG.isConstantIntBuildVectorOrConstantInt(N0) &&
!DAG.isConstantIntBuildVectorOrConstantInt(N1))
@@ -4562,10 +4730,37 @@ SDValue DAGCombiner::visitMULO(SDNode *N) {
DAG.getConstant(0, DL, CarryVT));
// (mulo x, 2) -> (addo x, x)
- if (ConstantSDNode *C2 = isConstOrConstSplat(N1))
- if (C2->getAPIntValue() == 2)
- return DAG.getNode(IsSigned ? ISD::SADDO : ISD::UADDO, DL,
- N->getVTList(), N0, N0);
+ if (N1C && N1C->getAPIntValue() == 2)
+ return DAG.getNode(IsSigned ? ISD::SADDO : ISD::UADDO, DL,
+ N->getVTList(), N0, N0);
+
+ if (IsSigned) {
+ // A 1 bit SMULO overflows if both inputs are 1.
+ if (VT.getScalarSizeInBits() == 1) {
+ SDValue And = DAG.getNode(ISD::AND, DL, VT, N0, N1);
+ return CombineTo(N, And,
+ DAG.getSetCC(DL, CarryVT, And,
+ DAG.getConstant(0, DL, VT), ISD::SETNE));
+ }
+
+ // Multiplying n * m significant bits yields a result of n + m significant
+ // bits. If the total number of significant bits does not exceed the
+ // result bit width (minus 1), there is no overflow.
+ unsigned SignBits = DAG.ComputeNumSignBits(N0);
+ if (SignBits > 1)
+ SignBits += DAG.ComputeNumSignBits(N1);
+ if (SignBits > VT.getScalarSizeInBits() + 1)
+ return CombineTo(N, DAG.getNode(ISD::MUL, DL, VT, N0, N1),
+ DAG.getConstant(0, DL, CarryVT));
+ } else {
+ KnownBits N1Known = DAG.computeKnownBits(N1);
+ KnownBits N0Known = DAG.computeKnownBits(N0);
+ bool Overflow;
+ (void)N0Known.getMaxValue().umul_ov(N1Known.getMaxValue(), Overflow);
+ if (!Overflow)
+ return CombineTo(N, DAG.getNode(ISD::MUL, DL, VT, N0, N1),
+ DAG.getConstant(0, DL, CarryVT));
+ }
return SDValue();
}
@@ -4883,20 +5078,20 @@ SDValue DAGCombiner::foldLogicOfSetCCs(bool IsAnd, SDValue N0, SDValue N1,
ConstantSDNode *C0 = isConstOrConstSplat(LR);
ConstantSDNode *C1 = isConstOrConstSplat(RR);
if (LL == RL && C0 && C1 && !C0->isOpaque() && !C1->isOpaque()) {
- // Canonicalize larger constant as C0.
- if (C1->getAPIntValue().ugt(C0->getAPIntValue()))
- std::swap(C0, C1);
-
+ const APInt &CMax =
+ APIntOps::umax(C0->getAPIntValue(), C1->getAPIntValue());
+ const APInt &CMin =
+ APIntOps::umin(C0->getAPIntValue(), C1->getAPIntValue());
// The difference of the constants must be a single bit.
- const APInt &C0Val = C0->getAPIntValue();
- const APInt &C1Val = C1->getAPIntValue();
- if ((C0Val - C1Val).isPowerOf2()) {
- // and/or (setcc X, C0, ne), (setcc X, C1, ne/eq) -->
- // setcc ((add X, -C1), ~(C0 - C1)), 0, ne/eq
- SDValue OffsetC = DAG.getConstant(-C1Val, DL, OpVT);
- SDValue Add = DAG.getNode(ISD::ADD, DL, OpVT, LL, OffsetC);
- SDValue MaskC = DAG.getConstant(~(C0Val - C1Val), DL, OpVT);
- SDValue And = DAG.getNode(ISD::AND, DL, OpVT, Add, MaskC);
+ if ((CMax - CMin).isPowerOf2()) {
+ // and/or (setcc X, CMax, ne), (setcc X, CMin, ne/eq) -->
+ // setcc ((sub X, CMin), ~(CMax - CMin)), 0, ne/eq
+ SDValue Max = DAG.getNode(ISD::UMAX, DL, OpVT, LR, RR);
+ SDValue Min = DAG.getNode(ISD::UMIN, DL, OpVT, LR, RR);
+ SDValue Offset = DAG.getNode(ISD::SUB, DL, OpVT, LL, Min);
+ SDValue Diff = DAG.getNode(ISD::SUB, DL, OpVT, Max, Min);
+ SDValue Mask = DAG.getNOT(DL, Diff, OpVT);
+ SDValue And = DAG.getNode(ISD::AND, DL, OpVT, Offset, Mask);
SDValue Zero = DAG.getConstant(0, DL, OpVT);
return DAG.getSetCC(DL, VT, And, Zero, CC0);
}
@@ -5428,19 +5623,19 @@ SDValue DAGCombiner::visitAND(SDNode *N) {
return FoldedVOp;
// fold (and x, 0) -> 0, vector edition
- if (ISD::isBuildVectorAllZeros(N0.getNode()))
+ if (ISD::isConstantSplatVectorAllZeros(N0.getNode()))
// do not return N0, because undef node may exist in N0
return DAG.getConstant(APInt::getNullValue(N0.getScalarValueSizeInBits()),
SDLoc(N), N0.getValueType());
- if (ISD::isBuildVectorAllZeros(N1.getNode()))
+ if (ISD::isConstantSplatVectorAllZeros(N1.getNode()))
// do not return N1, because undef node may exist in N1
return DAG.getConstant(APInt::getNullValue(N1.getScalarValueSizeInBits()),
SDLoc(N), N1.getValueType());
// fold (and x, -1) -> x, vector edition
- if (ISD::isBuildVectorAllOnes(N0.getNode()))
+ if (ISD::isConstantSplatVectorAllOnes(N0.getNode()))
return N1;
- if (ISD::isBuildVectorAllOnes(N1.getNode()))
+ if (ISD::isConstantSplatVectorAllOnes(N1.getNode()))
return N0;
// fold (and (masked_load) (build_vec (x, ...))) to zext_masked_load
@@ -6194,16 +6389,16 @@ SDValue DAGCombiner::visitOR(SDNode *N) {
return FoldedVOp;
// fold (or x, 0) -> x, vector edition
- if (ISD::isBuildVectorAllZeros(N0.getNode()))
+ if (ISD::isConstantSplatVectorAllZeros(N0.getNode()))
return N1;
- if (ISD::isBuildVectorAllZeros(N1.getNode()))
+ if (ISD::isConstantSplatVectorAllZeros(N1.getNode()))
return N0;
// fold (or x, -1) -> -1, vector edition
- if (ISD::isBuildVectorAllOnes(N0.getNode()))
+ if (ISD::isConstantSplatVectorAllOnes(N0.getNode()))
// do not return N0, because undef node may exist in N0
return DAG.getAllOnesConstant(SDLoc(N), N0.getValueType());
- if (ISD::isBuildVectorAllOnes(N1.getNode()))
+ if (ISD::isConstantSplatVectorAllOnes(N1.getNode()))
// do not return N1, because undef node may exist in N1
return DAG.getAllOnesConstant(SDLoc(N), N1.getValueType());
@@ -6517,8 +6712,11 @@ static SDValue extractShiftForRotate(SelectionDAG &DAG, SDValue OppShift,
// reduces to a rotate in direction shift2 by Pos or (equivalently) a rotate
// in direction shift1 by Neg. The range [0, EltSize) means that we only need
// to consider shift amounts with defined behavior.
+//
+// The IsRotate flag should be set when the LHS of both shifts is the same.
+// Otherwise if matching a general funnel shift, it should be clear.
static bool matchRotateSub(SDValue Pos, SDValue Neg, unsigned EltSize,
- SelectionDAG &DAG) {
+ SelectionDAG &DAG, bool IsRotate) {
// If EltSize is a power of 2 then:
//
// (a) (Pos == 0 ? 0 : EltSize - Pos) == (EltSize - Pos) & (EltSize - 1)
@@ -6550,8 +6748,11 @@ static bool matchRotateSub(SDValue Pos, SDValue Neg, unsigned EltSize,
// always invokes undefined behavior for 32-bit X.
//
// Below, Mask == EltSize - 1 when using [A] and is all-ones otherwise.
+ //
+ // NOTE: We can only do this when matching an AND and not a general
+ // funnel shift.
unsigned MaskLoBits = 0;
- if (Neg.getOpcode() == ISD::AND && isPowerOf2_64(EltSize)) {
+ if (IsRotate && Neg.getOpcode() == ISD::AND && isPowerOf2_64(EltSize)) {
if (ConstantSDNode *NegC = isConstOrConstSplat(Neg.getOperand(1))) {
KnownBits Known = DAG.computeKnownBits(Neg.getOperand(0));
unsigned Bits = Log2_64(EltSize);
@@ -6641,7 +6842,8 @@ SDValue DAGCombiner::MatchRotatePosNeg(SDValue Shifted, SDValue Pos,
// (srl x, (*ext y))) ->
// (rotr x, y) or (rotl x, (sub 32, y))
EVT VT = Shifted.getValueType();
- if (matchRotateSub(InnerPos, InnerNeg, VT.getScalarSizeInBits(), DAG)) {
+ if (matchRotateSub(InnerPos, InnerNeg, VT.getScalarSizeInBits(), DAG,
+ /*IsRotate*/ true)) {
bool HasPos = TLI.isOperationLegalOrCustom(PosOpcode, VT);
return DAG.getNode(HasPos ? PosOpcode : NegOpcode, DL, VT, Shifted,
HasPos ? Pos : Neg);
@@ -6670,7 +6872,7 @@ SDValue DAGCombiner::MatchFunnelPosNeg(SDValue N0, SDValue N1, SDValue Pos,
// fold (or (shl x0, (*ext (sub 32, y))),
// (srl x1, (*ext y))) ->
// (fshr x0, x1, y) or (fshl x0, x1, (sub 32, y))
- if (matchRotateSub(InnerPos, InnerNeg, EltBits, DAG)) {
+ if (matchRotateSub(InnerPos, InnerNeg, EltBits, DAG, /*IsRotate*/ N0 == N1)) {
bool HasPos = TLI.isOperationLegalOrCustom(PosOpcode, VT);
return DAG.getNode(HasPos ? PosOpcode : NegOpcode, DL, VT, N0, N1,
HasPos ? Pos : Neg);
@@ -7098,14 +7300,22 @@ SDValue DAGCombiner::mergeTruncStores(StoreSDNode *N) {
if (LegalOperations)
return SDValue();
- // Collect all the stores in the chain.
- SDValue Chain;
- SmallVector<StoreSDNode *, 8> Stores;
- for (StoreSDNode *Store = N; Store; Store = dyn_cast<StoreSDNode>(Chain)) {
- // TODO: Allow unordered atomics when wider type is legal (see D66309)
- EVT MemVT = Store->getMemoryVT();
- if (!(MemVT == MVT::i8 || MemVT == MVT::i16 || MemVT == MVT::i32) ||
- !Store->isSimple() || Store->isIndexed())
+ // We only handle merging simple stores of 1-4 bytes.
+ // TODO: Allow unordered atomics when wider type is legal (see D66309)
+ EVT MemVT = N->getMemoryVT();
+ if (!(MemVT == MVT::i8 || MemVT == MVT::i16 || MemVT == MVT::i32) ||
+ !N->isSimple() || N->isIndexed())
+ return SDValue();
+
+ // Collect all of the stores in the chain.
+ SDValue Chain = N->getChain();
+ SmallVector<StoreSDNode *, 8> Stores = {N};
+ while (auto *Store = dyn_cast<StoreSDNode>(Chain)) {
+ // All stores must be the same size to ensure that we are writing all of the
+ // bytes in the wide value.
+ // TODO: We could allow multiple sizes by tracking each stored byte.
+ if (Store->getMemoryVT() != MemVT || !Store->isSimple() ||
+ Store->isIndexed())
return SDValue();
Stores.push_back(Store);
Chain = Store->getChain();
@@ -7548,9 +7758,9 @@ SDValue DAGCombiner::visitXOR(SDNode *N) {
return FoldedVOp;
// fold (xor x, 0) -> x, vector edition
- if (ISD::isBuildVectorAllZeros(N0.getNode()))
+ if (ISD::isConstantSplatVectorAllZeros(N0.getNode()))
return N1;
- if (ISD::isBuildVectorAllZeros(N1.getNode()))
+ if (ISD::isConstantSplatVectorAllZeros(N1.getNode()))
return N0;
}
@@ -8253,6 +8463,17 @@ SDValue DAGCombiner::visitSHL(SDNode *N) {
return DAG.getVScale(SDLoc(N), VT, C0 << C1);
}
+ // Fold (shl step_vector(C0), C1) to (step_vector(C0 << C1)).
+ APInt ShlVal;
+ if (N0.getOpcode() == ISD::STEP_VECTOR)
+ if (ISD::isConstantSplatVector(N1.getNode(), ShlVal)) {
+ const APInt &C0 = N0.getConstantOperandAPInt(0);
+ if (ShlVal.ult(C0.getBitWidth())) {
+ APInt NewStep = C0 << ShlVal;
+ return DAG.getStepVector(SDLoc(N), VT, NewStep);
+ }
+ }
+
return SDValue();
}
@@ -8361,13 +8582,17 @@ SDValue DAGCombiner::visitSRA(SDNode *N) {
unsigned LowBits = OpSizeInBits - (unsigned)N1C->getZExtValue();
EVT ExtVT = EVT::getIntegerVT(*DAG.getContext(), LowBits);
if (VT.isVector())
- ExtVT = EVT::getVectorVT(*DAG.getContext(),
- ExtVT, VT.getVectorNumElements());
+ ExtVT = EVT::getVectorVT(*DAG.getContext(), ExtVT,
+ VT.getVectorElementCount());
if (!LegalOperations ||
TLI.getOperationAction(ISD::SIGN_EXTEND_INREG, ExtVT) ==
TargetLowering::Legal)
return DAG.getNode(ISD::SIGN_EXTEND_INREG, SDLoc(N), VT,
N0.getOperand(0), DAG.getValueType(ExtVT));
+ // Even if we can't convert to sext_inreg, we might be able to remove
+ // this shift pair if the input is already sign extended.
+ if (DAG.ComputeNumSignBits(N0.getOperand(0)) > N1C->getZExtValue())
+ return N0.getOperand(0);
}
// fold (sra (sra x, c1), c2) -> (sra x, (add c1, c2))
@@ -8390,9 +8615,14 @@ SDValue DAGCombiner::visitSRA(SDNode *N) {
};
if (ISD::matchBinaryPredicate(N1, N0.getOperand(1), SumOfShifts)) {
SDValue ShiftValue;
- if (VT.isVector())
+ if (N1.getOpcode() == ISD::BUILD_VECTOR)
ShiftValue = DAG.getBuildVector(ShiftVT, DL, ShiftValues);
- else
+ else if (N1.getOpcode() == ISD::SPLAT_VECTOR) {
+ assert(ShiftValues.size() == 1 &&
+ "Expected matchBinaryPredicate to return one element for "
+ "SPLAT_VECTORs");
+ ShiftValue = DAG.getSplatVector(ShiftVT, DL, ShiftValues[0]);
+ } else
ShiftValue = ShiftValues[0];
return DAG.getNode(ISD::SRA, DL, VT, N0.getOperand(0), ShiftValue);
}
@@ -8412,7 +8642,7 @@ SDValue DAGCombiner::visitSRA(SDNode *N) {
EVT TruncVT = EVT::getIntegerVT(Ctx, OpSizeInBits - N1C->getZExtValue());
if (VT.isVector())
- TruncVT = EVT::getVectorVT(Ctx, TruncVT, VT.getVectorNumElements());
+ TruncVT = EVT::getVectorVT(Ctx, TruncVT, VT.getVectorElementCount());
// Determine the residual right-shift amount.
int ShiftAmt = N1C->getZExtValue() - N01C->getZExtValue();
@@ -8452,7 +8682,7 @@ SDValue DAGCombiner::visitSRA(SDNode *N) {
unsigned ShiftAmt = N1C->getZExtValue();
EVT TruncVT = EVT::getIntegerVT(Ctx, OpSizeInBits - ShiftAmt);
if (VT.isVector())
- TruncVT = EVT::getVectorVT(Ctx, TruncVT, VT.getVectorNumElements());
+ TruncVT = EVT::getVectorVT(Ctx, TruncVT, VT.getVectorElementCount());
// TODO: The simple type check probably belongs in the default hook
// implementation and/or target-specific overrides (because
@@ -8865,6 +9095,40 @@ SDValue DAGCombiner::visitFunnelShift(SDNode *N) {
return SDValue();
}
+// Given a ABS node, detect the following pattern:
+// (ABS (SUB (EXTEND a), (EXTEND b))).
+// Generates UABD/SABD instruction.
+static SDValue combineABSToABD(SDNode *N, SelectionDAG &DAG,
+ const TargetLowering &TLI) {
+ SDValue AbsOp1 = N->getOperand(0);
+ SDValue Op0, Op1;
+
+ if (AbsOp1.getOpcode() != ISD::SUB)
+ return SDValue();
+
+ Op0 = AbsOp1.getOperand(0);
+ Op1 = AbsOp1.getOperand(1);
+
+ unsigned Opc0 = Op0.getOpcode();
+ // Check if the operands of the sub are (zero|sign)-extended.
+ if (Opc0 != Op1.getOpcode() ||
+ (Opc0 != ISD::ZERO_EXTEND && Opc0 != ISD::SIGN_EXTEND))
+ return SDValue();
+
+ EVT VT1 = Op0.getOperand(0).getValueType();
+ EVT VT2 = Op1.getOperand(0).getValueType();
+ // Check if the operands are of same type and valid size.
+ unsigned ABDOpcode = (Opc0 == ISD::SIGN_EXTEND) ? ISD::ABDS : ISD::ABDU;
+ if (VT1 != VT2 || !TLI.isOperationLegalOrCustom(ABDOpcode, VT1))
+ return SDValue();
+
+ Op0 = Op0.getOperand(0);
+ Op1 = Op1.getOperand(0);
+ SDValue ABD =
+ DAG.getNode(ABDOpcode, SDLoc(N), Op0->getValueType(0), Op0, Op1);
+ return DAG.getNode(ISD::ZERO_EXTEND, SDLoc(N), N->getValueType(0), ABD);
+}
+
SDValue DAGCombiner::visitABS(SDNode *N) {
SDValue N0 = N->getOperand(0);
EVT VT = N->getValueType(0);
@@ -8878,6 +9142,10 @@ SDValue DAGCombiner::visitABS(SDNode *N) {
// fold (abs x) -> x iff not-negative
if (DAG.SignBitIsZero(N0))
return N0;
+
+ if (SDValue ABD = combineABSToABD(N, DAG, TLI))
+ return ABD;
+
return SDValue();
}
@@ -9038,8 +9306,8 @@ static SDValue foldSelectOfConstantsUsingSra(SDNode *N, SelectionDAG &DAG) {
SDValue Cond = N->getOperand(0);
SDValue C1 = N->getOperand(1);
SDValue C2 = N->getOperand(2);
- assert(isConstantOrConstantVector(C1) && isConstantOrConstantVector(C2) &&
- "Expected select-of-constants");
+ if (!isConstantOrConstantVector(C1) || !isConstantOrConstantVector(C2))
+ return SDValue();
EVT VT = N->getValueType(0);
if (Cond.getOpcode() != ISD::SETCC || !Cond.hasOneUse() ||
@@ -9177,6 +9445,40 @@ SDValue DAGCombiner::foldSelectOfConstants(SDNode *N) {
return SDValue();
}
+static SDValue foldBoolSelectToLogic(SDNode *N, SelectionDAG &DAG) {
+ assert((N->getOpcode() == ISD::SELECT || N->getOpcode() == ISD::VSELECT) &&
+ "Expected a (v)select");
+ SDValue Cond = N->getOperand(0);
+ SDValue T = N->getOperand(1), F = N->getOperand(2);
+ EVT VT = N->getValueType(0);
+ if (VT != Cond.getValueType() || VT.getScalarSizeInBits() != 1)
+ return SDValue();
+
+ // select Cond, Cond, F --> or Cond, F
+ // select Cond, 1, F --> or Cond, F
+ if (Cond == T || isOneOrOneSplat(T, /* AllowUndefs */ true))
+ return DAG.getNode(ISD::OR, SDLoc(N), VT, Cond, F);
+
+ // select Cond, T, Cond --> and Cond, T
+ // select Cond, T, 0 --> and Cond, T
+ if (Cond == F || isNullOrNullSplat(F, /* AllowUndefs */ true))
+ return DAG.getNode(ISD::AND, SDLoc(N), VT, Cond, T);
+
+ // select Cond, T, 1 --> or (not Cond), T
+ if (isOneOrOneSplat(F, /* AllowUndefs */ true)) {
+ SDValue NotCond = DAG.getNOT(SDLoc(N), Cond, VT);
+ return DAG.getNode(ISD::OR, SDLoc(N), VT, NotCond, T);
+ }
+
+ // select Cond, 0, F --> and (not Cond), F
+ if (isNullOrNullSplat(T, /* AllowUndefs */ true)) {
+ SDValue NotCond = DAG.getNOT(SDLoc(N), Cond, VT);
+ return DAG.getNode(ISD::AND, SDLoc(N), VT, NotCond, F);
+ }
+
+ return SDValue();
+}
+
SDValue DAGCombiner::visitSELECT(SDNode *N) {
SDValue N0 = N->getOperand(0);
SDValue N1 = N->getOperand(1);
@@ -9189,30 +9491,11 @@ SDValue DAGCombiner::visitSELECT(SDNode *N) {
if (SDValue V = DAG.simplifySelect(N0, N1, N2))
return V;
- // fold (select X, X, Y) -> (or X, Y)
- // fold (select X, 1, Y) -> (or C, Y)
- if (VT == VT0 && VT == MVT::i1 && (N0 == N1 || isOneConstant(N1)))
- return DAG.getNode(ISD::OR, DL, VT, N0, N2);
-
if (SDValue V = foldSelectOfConstants(N))
return V;
- // fold (select C, 0, X) -> (and (not C), X)
- if (VT == VT0 && VT == MVT::i1 && isNullConstant(N1)) {
- SDValue NOTNode = DAG.getNOT(SDLoc(N0), N0, VT);
- AddToWorklist(NOTNode.getNode());
- return DAG.getNode(ISD::AND, DL, VT, NOTNode, N2);
- }
- // fold (select C, X, 1) -> (or (not C), X)
- if (VT == VT0 && VT == MVT::i1 && isOneConstant(N2)) {
- SDValue NOTNode = DAG.getNOT(SDLoc(N0), N0, VT);
- AddToWorklist(NOTNode.getNode());
- return DAG.getNode(ISD::OR, DL, VT, NOTNode, N1);
- }
- // fold (select X, Y, X) -> (and X, Y)
- // fold (select X, Y, 0) -> (and X, Y)
- if (VT == VT0 && VT == MVT::i1 && (N0 == N2 || isNullConstant(N2)))
- return DAG.getNode(ISD::AND, DL, VT, N0, N1);
+ if (SDValue V = foldBoolSelectToLogic(N, DAG))
+ return V;
// If we can fold this based on the true/false value, do so.
if (SimplifySelectOps(N, N1, N2))
@@ -9358,9 +9641,14 @@ SDValue DAGCombiner::visitSELECT(SDNode *N) {
return SelectNode;
}
- return SimplifySelect(DL, N0, N1, N2);
+ if (SDValue NewSel = SimplifySelect(DL, N0, N1, N2))
+ return NewSel;
}
+ if (!VT.isVector())
+ if (SDValue BinOp = foldSelectOfBinops(N))
+ return BinOp;
+
return SDValue();
}
@@ -9471,20 +9759,20 @@ SDValue DAGCombiner::visitMSCATTER(SDNode *N) {
SDLoc DL(N);
// Zap scatters with a zero mask.
- if (ISD::isBuildVectorAllZeros(Mask.getNode()))
+ if (ISD::isConstantSplatVectorAllZeros(Mask.getNode()))
return Chain;
if (refineUniformBase(BasePtr, Index, DAG)) {
SDValue Ops[] = {Chain, StoreVal, Mask, BasePtr, Index, Scale};
return DAG.getMaskedScatter(
- DAG.getVTList(MVT::Other), StoreVal.getValueType(), DL, Ops,
+ DAG.getVTList(MVT::Other), MSC->getMemoryVT(), DL, Ops,
MSC->getMemOperand(), MSC->getIndexType(), MSC->isTruncatingStore());
}
if (refineIndexType(MSC, Index, MSC->isIndexScaled(), DAG)) {
SDValue Ops[] = {Chain, StoreVal, Mask, BasePtr, Index, Scale};
return DAG.getMaskedScatter(
- DAG.getVTList(MVT::Other), StoreVal.getValueType(), DL, Ops,
+ DAG.getVTList(MVT::Other), MSC->getMemoryVT(), DL, Ops,
MSC->getMemOperand(), MSC->getIndexType(), MSC->isTruncatingStore());
}
@@ -9498,12 +9786,12 @@ SDValue DAGCombiner::visitMSTORE(SDNode *N) {
SDLoc DL(N);
// Zap masked stores with a zero mask.
- if (ISD::isBuildVectorAllZeros(Mask.getNode()))
+ if (ISD::isConstantSplatVectorAllZeros(Mask.getNode()))
return Chain;
// If this is a masked load with an all ones mask, we can use a unmasked load.
// FIXME: Can we do this for indexed, compressing, or truncating stores?
- if (ISD::isBuildVectorAllOnes(Mask.getNode()) &&
+ if (ISD::isConstantSplatVectorAllOnes(Mask.getNode()) &&
MST->isUnindexed() && !MST->isCompressingStore() &&
!MST->isTruncatingStore())
return DAG.getStore(MST->getChain(), SDLoc(N), MST->getValue(),
@@ -9527,13 +9815,13 @@ SDValue DAGCombiner::visitMGATHER(SDNode *N) {
SDLoc DL(N);
// Zap gathers with a zero mask.
- if (ISD::isBuildVectorAllZeros(Mask.getNode()))
+ if (ISD::isConstantSplatVectorAllZeros(Mask.getNode()))
return CombineTo(N, PassThru, MGT->getChain());
if (refineUniformBase(BasePtr, Index, DAG)) {
SDValue Ops[] = {Chain, PassThru, Mask, BasePtr, Index, Scale};
return DAG.getMaskedGather(DAG.getVTList(N->getValueType(0), MVT::Other),
- PassThru.getValueType(), DL, Ops,
+ MGT->getMemoryVT(), DL, Ops,
MGT->getMemOperand(), MGT->getIndexType(),
MGT->getExtensionType());
}
@@ -9541,7 +9829,7 @@ SDValue DAGCombiner::visitMGATHER(SDNode *N) {
if (refineIndexType(MGT, Index, MGT->isIndexScaled(), DAG)) {
SDValue Ops[] = {Chain, PassThru, Mask, BasePtr, Index, Scale};
return DAG.getMaskedGather(DAG.getVTList(N->getValueType(0), MVT::Other),
- PassThru.getValueType(), DL, Ops,
+ MGT->getMemoryVT(), DL, Ops,
MGT->getMemOperand(), MGT->getIndexType(),
MGT->getExtensionType());
}
@@ -9555,12 +9843,12 @@ SDValue DAGCombiner::visitMLOAD(SDNode *N) {
SDLoc DL(N);
// Zap masked loads with a zero mask.
- if (ISD::isBuildVectorAllZeros(Mask.getNode()))
+ if (ISD::isConstantSplatVectorAllZeros(Mask.getNode()))
return CombineTo(N, MLD->getPassThru(), MLD->getChain());
// If this is a masked load with an all ones mask, we can use a unmasked load.
// FIXME: Can we do this for indexed, expanding, or extending loads?
- if (ISD::isBuildVectorAllOnes(Mask.getNode()) &&
+ if (ISD::isConstantSplatVectorAllOnes(Mask.getNode()) &&
MLD->isUnindexed() && !MLD->isExpandingLoad() &&
MLD->getExtensionType() == ISD::NON_EXTLOAD) {
SDValue NewLd = DAG.getLoad(N->getValueType(0), SDLoc(N), MLD->getChain(),
@@ -9650,6 +9938,9 @@ SDValue DAGCombiner::visitVSELECT(SDNode *N) {
if (SDValue V = DAG.simplifySelect(N0, N1, N2))
return V;
+ if (SDValue V = foldBoolSelectToLogic(N, DAG))
+ return V;
+
// vselect (not Cond), N1, N2 -> vselect Cond, N2, N1
if (SDValue F = extractBooleanFlip(N0, DAG, TLI, false))
return DAG.getSelect(DL, VT, F, N2, N1);
@@ -9734,10 +10025,10 @@ SDValue DAGCombiner::visitVSELECT(SDNode *N) {
// If it's on the left side invert the predicate to simplify logic below.
SDValue Other;
ISD::CondCode SatCC = CC;
- if (ISD::isBuildVectorAllOnes(N1.getNode())) {
+ if (ISD::isConstantSplatVectorAllOnes(N1.getNode())) {
Other = N2;
SatCC = ISD::getSetCCInverse(SatCC, VT.getScalarType());
- } else if (ISD::isBuildVectorAllOnes(N2.getNode())) {
+ } else if (ISD::isConstantSplatVectorAllOnes(N2.getNode())) {
Other = N1;
}
@@ -9758,7 +10049,9 @@ SDValue DAGCombiner::visitVSELECT(SDNode *N) {
(OpLHS == CondLHS || OpRHS == CondLHS))
return DAG.getNode(ISD::UADDSAT, DL, VT, OpLHS, OpRHS);
- if (isa<BuildVectorSDNode>(OpRHS) && isa<BuildVectorSDNode>(CondRHS) &&
+ if (OpRHS.getOpcode() == CondRHS.getOpcode() &&
+ (OpRHS.getOpcode() == ISD::BUILD_VECTOR ||
+ OpRHS.getOpcode() == ISD::SPLAT_VECTOR) &&
CondLHS == OpLHS) {
// If the RHS is a constant we have to reverse the const
// canonicalization.
@@ -9779,54 +10072,71 @@ SDValue DAGCombiner::visitVSELECT(SDNode *N) {
// the left side invert the predicate to simplify logic below.
SDValue Other;
ISD::CondCode SatCC = CC;
- if (ISD::isBuildVectorAllZeros(N1.getNode())) {
+ if (ISD::isConstantSplatVectorAllZeros(N1.getNode())) {
Other = N2;
SatCC = ISD::getSetCCInverse(SatCC, VT.getScalarType());
- } else if (ISD::isBuildVectorAllZeros(N2.getNode())) {
+ } else if (ISD::isConstantSplatVectorAllZeros(N2.getNode())) {
Other = N1;
}
- if (Other && Other.getNumOperands() == 2 && Other.getOperand(0) == LHS) {
+ if (Other && Other.getNumOperands() == 2) {
SDValue CondRHS = RHS;
SDValue OpLHS = Other.getOperand(0), OpRHS = Other.getOperand(1);
- // Look for a general sub with unsigned saturation first.
- // x >= y ? x-y : 0 --> usubsat x, y
- // x > y ? x-y : 0 --> usubsat x, y
- if ((SatCC == ISD::SETUGE || SatCC == ISD::SETUGT) &&
- Other.getOpcode() == ISD::SUB && OpRHS == CondRHS)
- return DAG.getNode(ISD::USUBSAT, DL, VT, OpLHS, OpRHS);
+ if (Other.getOpcode() == ISD::SUB &&
+ LHS.getOpcode() == ISD::ZERO_EXTEND && LHS.getOperand(0) == OpLHS &&
+ OpRHS.getOpcode() == ISD::TRUNCATE && OpRHS.getOperand(0) == RHS) {
+ // Look for a general sub with unsigned saturation first.
+ // zext(x) >= y ? x - trunc(y) : 0
+ // --> usubsat(x,trunc(umin(y,SatLimit)))
+ // zext(x) > y ? x - trunc(y) : 0
+ // --> usubsat(x,trunc(umin(y,SatLimit)))
+ if (SatCC == ISD::SETUGE || SatCC == ISD::SETUGT)
+ return getTruncatedUSUBSAT(VT, LHS.getValueType(), LHS, RHS, DAG,
+ DL);
+ }
- if (auto *OpRHSBV = dyn_cast<BuildVectorSDNode>(OpRHS)) {
- if (isa<BuildVectorSDNode>(CondRHS)) {
- // If the RHS is a constant we have to reverse the const
- // canonicalization.
- // x > C-1 ? x+-C : 0 --> usubsat x, C
- auto MatchUSUBSAT = [](ConstantSDNode *Op, ConstantSDNode *Cond) {
- return (!Op && !Cond) ||
- (Op && Cond &&
- Cond->getAPIntValue() == (-Op->getAPIntValue() - 1));
- };
- if (SatCC == ISD::SETUGT && Other.getOpcode() == ISD::ADD &&
- ISD::matchBinaryPredicate(OpRHS, CondRHS, MatchUSUBSAT,
- /*AllowUndefs*/ true)) {
- OpRHS = DAG.getNode(ISD::SUB, DL, VT, DAG.getConstant(0, DL, VT),
- OpRHS);
- return DAG.getNode(ISD::USUBSAT, DL, VT, OpLHS, OpRHS);
- }
+ if (OpLHS == LHS) {
+ // Look for a general sub with unsigned saturation first.
+ // x >= y ? x-y : 0 --> usubsat x, y
+ // x > y ? x-y : 0 --> usubsat x, y
+ if ((SatCC == ISD::SETUGE || SatCC == ISD::SETUGT) &&
+ Other.getOpcode() == ISD::SUB && OpRHS == CondRHS)
+ return DAG.getNode(ISD::USUBSAT, DL, VT, OpLHS, OpRHS);
- // Another special case: If C was a sign bit, the sub has been
- // canonicalized into a xor.
- // FIXME: Would it be better to use computeKnownBits to determine
- // whether it's safe to decanonicalize the xor?
- // x s< 0 ? x^C : 0 --> usubsat x, C
- if (auto *OpRHSConst = OpRHSBV->getConstantSplatNode()) {
+ if (OpRHS.getOpcode() == ISD::BUILD_VECTOR ||
+ OpRHS.getOpcode() == ISD::SPLAT_VECTOR) {
+ if (CondRHS.getOpcode() == ISD::BUILD_VECTOR ||
+ CondRHS.getOpcode() == ISD::SPLAT_VECTOR) {
+ // If the RHS is a constant we have to reverse the const
+ // canonicalization.
+ // x > C-1 ? x+-C : 0 --> usubsat x, C
+ auto MatchUSUBSAT = [](ConstantSDNode *Op, ConstantSDNode *Cond) {
+ return (!Op && !Cond) ||
+ (Op && Cond &&
+ Cond->getAPIntValue() == (-Op->getAPIntValue() - 1));
+ };
+ if (SatCC == ISD::SETUGT && Other.getOpcode() == ISD::ADD &&
+ ISD::matchBinaryPredicate(OpRHS, CondRHS, MatchUSUBSAT,
+ /*AllowUndefs*/ true)) {
+ OpRHS = DAG.getNode(ISD::SUB, DL, VT,
+ DAG.getConstant(0, DL, VT), OpRHS);
+ return DAG.getNode(ISD::USUBSAT, DL, VT, OpLHS, OpRHS);
+ }
+
+ // Another special case: If C was a sign bit, the sub has been
+ // canonicalized into a xor.
+ // FIXME: Would it be better to use computeKnownBits to determine
+ // whether it's safe to decanonicalize the xor?
+ // x s< 0 ? x^C : 0 --> usubsat x, C
+ APInt SplatValue;
if (SatCC == ISD::SETLT && Other.getOpcode() == ISD::XOR &&
- ISD::isBuildVectorAllZeros(CondRHS.getNode()) &&
- OpRHSConst->getAPIntValue().isSignMask()) {
- // Note that we have to rebuild the RHS constant here to ensure
- // we don't rely on particular values of undef lanes.
- OpRHS = DAG.getConstant(OpRHSConst->getAPIntValue(), DL, VT);
+ ISD::isConstantSplatVector(OpRHS.getNode(), SplatValue) &&
+ ISD::isConstantSplatVectorAllZeros(CondRHS.getNode()) &&
+ SplatValue.isSignMask()) {
+ // Note that we have to rebuild the RHS constant here to
+ // ensure we don't rely on particular values of undef lanes.
+ OpRHS = DAG.getConstant(SplatValue, DL, VT);
return DAG.getNode(ISD::USUBSAT, DL, VT, OpLHS, OpRHS);
}
}
@@ -9839,11 +10149,11 @@ SDValue DAGCombiner::visitVSELECT(SDNode *N) {
if (SimplifySelectOps(N, N1, N2))
return SDValue(N, 0); // Don't revisit N.
- // Fold (vselect (build_vector all_ones), N1, N2) -> N1
- if (ISD::isBuildVectorAllOnes(N0.getNode()))
+ // Fold (vselect all_ones, N1, N2) -> N1
+ if (ISD::isConstantSplatVectorAllOnes(N0.getNode()))
return N1;
- // Fold (vselect (build_vector all_zeros), N1, N2) -> N2
- if (ISD::isBuildVectorAllZeros(N0.getNode()))
+ // Fold (vselect all_zeros, N1, N2) -> N2
+ if (ISD::isConstantSplatVectorAllZeros(N0.getNode()))
return N2;
// The ConvertSelectToConcatVector function is assuming both the above
@@ -9913,9 +10223,62 @@ SDValue DAGCombiner::visitSETCC(SDNode *N) {
bool PreferSetCC =
N->hasOneUse() && N->use_begin()->getOpcode() == ISD::BRCOND;
- SDValue Combined = SimplifySetCC(
- N->getValueType(0), N->getOperand(0), N->getOperand(1),
- cast<CondCodeSDNode>(N->getOperand(2))->get(), SDLoc(N), !PreferSetCC);
+ ISD::CondCode Cond = cast<CondCodeSDNode>(N->getOperand(2))->get();
+ EVT VT = N->getValueType(0);
+
+ // SETCC(FREEZE(X), CONST, Cond)
+ // =>
+ // FREEZE(SETCC(X, CONST, Cond))
+ // This is correct if FREEZE(X) has one use and SETCC(FREEZE(X), CONST, Cond)
+ // isn't equivalent to true or false.
+ // For example, SETCC(FREEZE(X), -128, SETULT) cannot be folded to
+ // FREEZE(SETCC(X, -128, SETULT)) because X can be poison.
+ //
+ // This transformation is beneficial because visitBRCOND can fold
+ // BRCOND(FREEZE(X)) to BRCOND(X).
+
+ // Conservatively optimize integer comparisons only.
+ if (PreferSetCC) {
+ // Do this only when SETCC is going to be used by BRCOND.
+
+ SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
+ ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0);
+ ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1);
+ bool Updated = false;
+
+ // Is 'X Cond C' always true or false?
+ auto IsAlwaysTrueOrFalse = [](ISD::CondCode Cond, ConstantSDNode *C) {
+ bool False = (Cond == ISD::SETULT && C->isNullValue()) ||
+ (Cond == ISD::SETLT && C->isMinSignedValue()) ||
+ (Cond == ISD::SETUGT && C->isAllOnesValue()) ||
+ (Cond == ISD::SETGT && C->isMaxSignedValue());
+ bool True = (Cond == ISD::SETULE && C->isAllOnesValue()) ||
+ (Cond == ISD::SETLE && C->isMaxSignedValue()) ||
+ (Cond == ISD::SETUGE && C->isNullValue()) ||
+ (Cond == ISD::SETGE && C->isMinSignedValue());
+ return True || False;
+ };
+
+ if (N0->getOpcode() == ISD::FREEZE && N0.hasOneUse() && N1C) {
+ if (!IsAlwaysTrueOrFalse(Cond, N1C)) {
+ N0 = N0->getOperand(0);
+ Updated = true;
+ }
+ }
+ if (N1->getOpcode() == ISD::FREEZE && N1.hasOneUse() && N0C) {
+ if (!IsAlwaysTrueOrFalse(ISD::getSetCCSwappedOperands(Cond),
+ N0C)) {
+ N1 = N1->getOperand(0);
+ Updated = true;
+ }
+ }
+
+ if (Updated)
+ return DAG.getFreeze(DAG.getSetCC(SDLoc(N), VT, N0, N1, Cond));
+ }
+
+ SDValue Combined = SimplifySetCC(VT, N->getOperand(0), N->getOperand(1), Cond,
+ SDLoc(N), !PreferSetCC);
if (!Combined)
return SDValue();
@@ -9949,6 +10312,77 @@ SDValue DAGCombiner::visitSETCCCARRY(SDNode *N) {
return SDValue();
}
+/// Check if N satisfies:
+/// N is used once.
+/// N is a Load.
+/// The load is compatible with ExtOpcode. It means
+/// If load has explicit zero/sign extension, ExpOpcode must have the same
+/// extension.
+/// Otherwise returns true.
+static bool isCompatibleLoad(SDValue N, unsigned ExtOpcode) {
+ if (!N.hasOneUse())
+ return false;
+
+ if (!isa<LoadSDNode>(N))
+ return false;
+
+ LoadSDNode *Load = cast<LoadSDNode>(N);
+ ISD::LoadExtType LoadExt = Load->getExtensionType();
+ if (LoadExt == ISD::NON_EXTLOAD || LoadExt == ISD::EXTLOAD)
+ return true;
+
+ // Now LoadExt is either SEXTLOAD or ZEXTLOAD, ExtOpcode must have the same
+ // extension.
+ if ((LoadExt == ISD::SEXTLOAD && ExtOpcode != ISD::SIGN_EXTEND) ||
+ (LoadExt == ISD::ZEXTLOAD && ExtOpcode != ISD::ZERO_EXTEND))
+ return false;
+
+ return true;
+}
+
+/// Fold
+/// (sext (select c, load x, load y)) -> (select c, sextload x, sextload y)
+/// (zext (select c, load x, load y)) -> (select c, zextload x, zextload y)
+/// (aext (select c, load x, load y)) -> (select c, extload x, extload y)
+/// This function is called by the DAGCombiner when visiting sext/zext/aext
+/// dag nodes (see for example method DAGCombiner::visitSIGN_EXTEND).
+static SDValue tryToFoldExtendSelectLoad(SDNode *N, const TargetLowering &TLI,
+ SelectionDAG &DAG) {
+ unsigned Opcode = N->getOpcode();
+ SDValue N0 = N->getOperand(0);
+ EVT VT = N->getValueType(0);
+ SDLoc DL(N);
+
+ assert((Opcode == ISD::SIGN_EXTEND || Opcode == ISD::ZERO_EXTEND ||
+ Opcode == ISD::ANY_EXTEND) &&
+ "Expected EXTEND dag node in input!");
+
+ if (!(N0->getOpcode() == ISD::SELECT || N0->getOpcode() == ISD::VSELECT) ||
+ !N0.hasOneUse())
+ return SDValue();
+
+ SDValue Op1 = N0->getOperand(1);
+ SDValue Op2 = N0->getOperand(2);
+ if (!isCompatibleLoad(Op1, Opcode) || !isCompatibleLoad(Op2, Opcode))
+ return SDValue();
+
+ auto ExtLoadOpcode = ISD::EXTLOAD;
+ if (Opcode == ISD::SIGN_EXTEND)
+ ExtLoadOpcode = ISD::SEXTLOAD;
+ else if (Opcode == ISD::ZERO_EXTEND)
+ ExtLoadOpcode = ISD::ZEXTLOAD;
+
+ LoadSDNode *Load1 = cast<LoadSDNode>(Op1);
+ LoadSDNode *Load2 = cast<LoadSDNode>(Op2);
+ if (!TLI.isLoadExtLegal(ExtLoadOpcode, VT, Load1->getMemoryVT()) ||
+ !TLI.isLoadExtLegal(ExtLoadOpcode, VT, Load2->getMemoryVT()))
+ return SDValue();
+
+ SDValue Ext1 = DAG.getNode(Opcode, DL, VT, Op1);
+ SDValue Ext2 = DAG.getNode(Opcode, DL, VT, Op2);
+ return DAG.getSelect(DL, VT, N0->getOperand(0), Ext1, Ext2);
+}
+
/// Try to fold a sext/zext/aext dag node into a ConstantSDNode or
/// a build_vector of constants.
/// This function is called by the DAGCombiner when visiting sext/zext/aext
@@ -10481,6 +10915,128 @@ static SDValue foldExtendedSignBitTest(SDNode *N, SelectionDAG &DAG,
return SDValue();
}
+SDValue DAGCombiner::foldSextSetcc(SDNode *N) {
+ SDValue N0 = N->getOperand(0);
+ if (N0.getOpcode() != ISD::SETCC)
+ return SDValue();
+
+ SDValue N00 = N0.getOperand(0);
+ SDValue N01 = N0.getOperand(1);
+ ISD::CondCode CC = cast<CondCodeSDNode>(N0.getOperand(2))->get();
+ EVT VT = N->getValueType(0);
+ EVT N00VT = N00.getValueType();
+ SDLoc DL(N);
+
+ // On some architectures (such as SSE/NEON/etc) the SETCC result type is
+ // the same size as the compared operands. Try to optimize sext(setcc())
+ // if this is the case.
+ if (VT.isVector() && !LegalOperations &&
+ TLI.getBooleanContents(N00VT) ==
+ TargetLowering::ZeroOrNegativeOneBooleanContent) {
+ EVT SVT = getSetCCResultType(N00VT);
+
+ // If we already have the desired type, don't change it.
+ if (SVT != N0.getValueType()) {
+ // We know that the # elements of the results is the same as the
+ // # elements of the compare (and the # elements of the compare result
+ // for that matter). Check to see that they are the same size. If so,
+ // we know that the element size of the sext'd result matches the
+ // element size of the compare operands.
+ if (VT.getSizeInBits() == SVT.getSizeInBits())
+ return DAG.getSetCC(DL, VT, N00, N01, CC);
+
+ // If the desired elements are smaller or larger than the source
+ // elements, we can use a matching integer vector type and then
+ // truncate/sign extend.
+ EVT MatchingVecType = N00VT.changeVectorElementTypeToInteger();
+ if (SVT == MatchingVecType) {
+ SDValue VsetCC = DAG.getSetCC(DL, MatchingVecType, N00, N01, CC);
+ return DAG.getSExtOrTrunc(VsetCC, DL, VT);
+ }
+ }
+
+ // Try to eliminate the sext of a setcc by zexting the compare operands.
+ if (N0.hasOneUse() && TLI.isOperationLegalOrCustom(ISD::SETCC, VT) &&
+ !TLI.isOperationLegalOrCustom(ISD::SETCC, SVT)) {
+ bool IsSignedCmp = ISD::isSignedIntSetCC(CC);
+ unsigned LoadOpcode = IsSignedCmp ? ISD::SEXTLOAD : ISD::ZEXTLOAD;
+ unsigned ExtOpcode = IsSignedCmp ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND;
+
+ // We have an unsupported narrow vector compare op that would be legal
+ // if extended to the destination type. See if the compare operands
+ // can be freely extended to the destination type.
+ auto IsFreeToExtend = [&](SDValue V) {
+ if (isConstantOrConstantVector(V, /*NoOpaques*/ true))
+ return true;
+ // Match a simple, non-extended load that can be converted to a
+ // legal {z/s}ext-load.
+ // TODO: Allow widening of an existing {z/s}ext-load?
+ if (!(ISD::isNON_EXTLoad(V.getNode()) &&
+ ISD::isUNINDEXEDLoad(V.getNode()) &&
+ cast<LoadSDNode>(V)->isSimple() &&
+ TLI.isLoadExtLegal(LoadOpcode, VT, V.getValueType())))
+ return false;
+
+ // Non-chain users of this value must either be the setcc in this
+ // sequence or extends that can be folded into the new {z/s}ext-load.
+ for (SDNode::use_iterator UI = V->use_begin(), UE = V->use_end();
+ UI != UE; ++UI) {
+ // Skip uses of the chain and the setcc.
+ SDNode *User = *UI;
+ if (UI.getUse().getResNo() != 0 || User == N0.getNode())
+ continue;
+ // Extra users must have exactly the same cast we are about to create.
+ // TODO: This restriction could be eased if ExtendUsesToFormExtLoad()
+ // is enhanced similarly.
+ if (User->getOpcode() != ExtOpcode || User->getValueType(0) != VT)
+ return false;
+ }
+ return true;
+ };
+
+ if (IsFreeToExtend(N00) && IsFreeToExtend(N01)) {
+ SDValue Ext0 = DAG.getNode(ExtOpcode, DL, VT, N00);
+ SDValue Ext1 = DAG.getNode(ExtOpcode, DL, VT, N01);
+ return DAG.getSetCC(DL, VT, Ext0, Ext1, CC);
+ }
+ }
+ }
+
+ // sext(setcc x, y, cc) -> (select (setcc x, y, cc), T, 0)
+ // Here, T can be 1 or -1, depending on the type of the setcc and
+ // getBooleanContents().
+ unsigned SetCCWidth = N0.getScalarValueSizeInBits();
+
+ // To determine the "true" side of the select, we need to know the high bit
+ // of the value returned by the setcc if it evaluates to true.
+ // If the type of the setcc is i1, then the true case of the select is just
+ // sext(i1 1), that is, -1.
+ // If the type of the setcc is larger (say, i8) then the value of the high
+ // bit depends on getBooleanContents(), so ask TLI for a real "true" value
+ // of the appropriate width.
+ SDValue ExtTrueVal = (SetCCWidth == 1)
+ ? DAG.getAllOnesConstant(DL, VT)
+ : DAG.getBoolConstant(true, DL, VT, N00VT);
+ SDValue Zero = DAG.getConstant(0, DL, VT);
+ if (SDValue SCC = SimplifySelectCC(DL, N00, N01, ExtTrueVal, Zero, CC, true))
+ return SCC;
+
+ if (!VT.isVector() && !TLI.convertSelectOfConstantsToMath(VT)) {
+ EVT SetCCVT = getSetCCResultType(N00VT);
+ // Don't do this transform for i1 because there's a select transform
+ // that would reverse it.
+ // TODO: We should not do this transform at all without a target hook
+ // because a sext is likely cheaper than a select?
+ if (SetCCVT.getScalarSizeInBits() != 1 &&
+ (!LegalOperations || TLI.isOperationLegal(ISD::SETCC, N00VT))) {
+ SDValue SetCC = DAG.getSetCC(DL, SetCCVT, N00, N01, CC);
+ return DAG.getSelect(DL, VT, SetCC, ExtTrueVal, Zero);
+ }
+ }
+
+ return SDValue();
+}
+
SDValue DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
SDValue N0 = N->getOperand(0);
EVT VT = N->getValueType(0);
@@ -10612,76 +11168,8 @@ SDValue DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
if (SDValue V = foldExtendedSignBitTest(N, DAG, LegalOperations))
return V;
- if (N0.getOpcode() == ISD::SETCC) {
- SDValue N00 = N0.getOperand(0);
- SDValue N01 = N0.getOperand(1);
- ISD::CondCode CC = cast<CondCodeSDNode>(N0.getOperand(2))->get();
- EVT N00VT = N00.getValueType();
-
- // sext(setcc) -> sext_in_reg(vsetcc) for vectors.
- // Only do this before legalize for now.
- if (VT.isVector() && !LegalOperations &&
- TLI.getBooleanContents(N00VT) ==
- TargetLowering::ZeroOrNegativeOneBooleanContent) {
- // On some architectures (such as SSE/NEON/etc) the SETCC result type is
- // of the same size as the compared operands. Only optimize sext(setcc())
- // if this is the case.
- EVT SVT = getSetCCResultType(N00VT);
-
- // If we already have the desired type, don't change it.
- if (SVT != N0.getValueType()) {
- // We know that the # elements of the results is the same as the
- // # elements of the compare (and the # elements of the compare result
- // for that matter). Check to see that they are the same size. If so,
- // we know that the element size of the sext'd result matches the
- // element size of the compare operands.
- if (VT.getSizeInBits() == SVT.getSizeInBits())
- return DAG.getSetCC(DL, VT, N00, N01, CC);
-
- // If the desired elements are smaller or larger than the source
- // elements, we can use a matching integer vector type and then
- // truncate/sign extend.
- EVT MatchingVecType = N00VT.changeVectorElementTypeToInteger();
- if (SVT == MatchingVecType) {
- SDValue VsetCC = DAG.getSetCC(DL, MatchingVecType, N00, N01, CC);
- return DAG.getSExtOrTrunc(VsetCC, DL, VT);
- }
- }
- }
-
- // sext(setcc x, y, cc) -> (select (setcc x, y, cc), T, 0)
- // Here, T can be 1 or -1, depending on the type of the setcc and
- // getBooleanContents().
- unsigned SetCCWidth = N0.getScalarValueSizeInBits();
-
- // To determine the "true" side of the select, we need to know the high bit
- // of the value returned by the setcc if it evaluates to true.
- // If the type of the setcc is i1, then the true case of the select is just
- // sext(i1 1), that is, -1.
- // If the type of the setcc is larger (say, i8) then the value of the high
- // bit depends on getBooleanContents(), so ask TLI for a real "true" value
- // of the appropriate width.
- SDValue ExtTrueVal = (SetCCWidth == 1)
- ? DAG.getAllOnesConstant(DL, VT)
- : DAG.getBoolConstant(true, DL, VT, N00VT);
- SDValue Zero = DAG.getConstant(0, DL, VT);
- if (SDValue SCC =
- SimplifySelectCC(DL, N00, N01, ExtTrueVal, Zero, CC, true))
- return SCC;
-
- if (!VT.isVector() && !TLI.convertSelectOfConstantsToMath(VT)) {
- EVT SetCCVT = getSetCCResultType(N00VT);
- // Don't do this transform for i1 because there's a select transform
- // that would reverse it.
- // TODO: We should not do this transform at all without a target hook
- // because a sext is likely cheaper than a select?
- if (SetCCVT.getScalarSizeInBits() != 1 &&
- (!LegalOperations || TLI.isOperationLegal(ISD::SETCC, N00VT))) {
- SDValue SetCC = DAG.getSetCC(DL, SetCCVT, N00, N01, CC);
- return DAG.getSelect(DL, VT, SetCC, ExtTrueVal, Zero);
- }
- }
- }
+ if (SDValue V = foldSextSetcc(N))
+ return V;
// fold (sext x) -> (zext x) if the sign bit is known zero.
if ((!LegalOperations || TLI.isOperationLegal(ISD::ZERO_EXTEND, VT)) &&
@@ -10733,6 +11221,9 @@ SDValue DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
return DAG.getNode(ISD::ADD, DL, VT, Zext, DAG.getAllOnesConstant(DL, VT));
}
+ if (SDValue Res = tryToFoldExtendSelectLoad(N, TLI, DAG))
+ return Res;
+
return SDValue();
}
@@ -11045,6 +11536,9 @@ SDValue DAGCombiner::visitZERO_EXTEND(SDNode *N) {
if (SDValue NewCtPop = widenCtPop(N, DAG))
return NewCtPop;
+ if (SDValue Res = tryToFoldExtendSelectLoad(N, TLI, DAG))
+ return Res;
+
return SDValue();
}
@@ -11197,6 +11691,9 @@ SDValue DAGCombiner::visitANY_EXTEND(SDNode *N) {
if (SDValue NewCtPop = widenCtPop(N, DAG))
return NewCtPop;
+ if (SDValue Res = tryToFoldExtendSelectLoad(N, TLI, DAG))
+ return Res;
+
return SDValue();
}
@@ -11542,14 +12039,24 @@ SDValue DAGCombiner::visitSIGN_EXTEND_INREG(SDNode *N) {
}
// fold (sext_in_reg (*_extend_vector_inreg x)) -> (sext_vector_inreg x)
- if ((N0.getOpcode() == ISD::ANY_EXTEND_VECTOR_INREG ||
- N0.getOpcode() == ISD::SIGN_EXTEND_VECTOR_INREG ||
- N0.getOpcode() == ISD::ZERO_EXTEND_VECTOR_INREG) &&
- N0.getOperand(0).getScalarValueSizeInBits() == ExtVTBits) {
- if (!LegalOperations ||
- TLI.isOperationLegal(ISD::SIGN_EXTEND_VECTOR_INREG, VT))
- return DAG.getNode(ISD::SIGN_EXTEND_VECTOR_INREG, SDLoc(N), VT,
- N0.getOperand(0));
+ // if x is small enough or if we know that x has more than 1 sign bit and the
+ // sign_extend_inreg is extending from one of them.
+ if (N0.getOpcode() == ISD::ANY_EXTEND_VECTOR_INREG ||
+ N0.getOpcode() == ISD::SIGN_EXTEND_VECTOR_INREG ||
+ N0.getOpcode() == ISD::ZERO_EXTEND_VECTOR_INREG) {
+ SDValue N00 = N0.getOperand(0);
+ unsigned N00Bits = N00.getScalarValueSizeInBits();
+ unsigned DstElts = N0.getValueType().getVectorMinNumElements();
+ unsigned SrcElts = N00.getValueType().getVectorMinNumElements();
+ bool IsZext = N0.getOpcode() == ISD::ZERO_EXTEND_VECTOR_INREG;
+ APInt DemandedSrcElts = APInt::getLowBitsSet(SrcElts, DstElts);
+ if ((N00Bits == ExtVTBits ||
+ (!IsZext && (N00Bits < ExtVTBits ||
+ (N00Bits - DAG.ComputeNumSignBits(N00, DemandedSrcElts)) <
+ ExtVTBits))) &&
+ (!LegalOperations ||
+ TLI.isOperationLegal(ISD::SIGN_EXTEND_VECTOR_INREG, VT)))
+ return DAG.getNode(ISD::SIGN_EXTEND_VECTOR_INREG, SDLoc(N), VT, N00);
}
// fold (sext_in_reg (zext x)) -> (sext x)
@@ -11610,6 +12117,7 @@ SDValue DAGCombiner::visitSIGN_EXTEND_INREG(SDNode *N) {
AddToWorklist(ExtLoad.getNode());
return SDValue(N, 0); // Return N so it doesn't get rechecked!
}
+
// fold (sext_inreg (zextload x)) -> (sextload x) iff load has one use
if (ISD::isZEXTLoad(N0.getNode()) && ISD::isUNINDEXEDLoad(N0.getNode()) &&
N0.hasOneUse() &&
@@ -11671,28 +12179,11 @@ SDValue DAGCombiner::visitSIGN_EXTEND_INREG(SDNode *N) {
return SDValue();
}
-SDValue DAGCombiner::visitSIGN_EXTEND_VECTOR_INREG(SDNode *N) {
- SDValue N0 = N->getOperand(0);
- EVT VT = N->getValueType(0);
-
- // sext_vector_inreg(undef) = 0 because the top bit will all be the same.
- if (N0.isUndef())
- return DAG.getConstant(0, SDLoc(N), VT);
-
- if (SDValue Res = tryToFoldExtendOfConstant(N, TLI, DAG, LegalTypes))
- return Res;
-
- if (SimplifyDemandedVectorElts(SDValue(N, 0)))
- return SDValue(N, 0);
-
- return SDValue();
-}
-
-SDValue DAGCombiner::visitZERO_EXTEND_VECTOR_INREG(SDNode *N) {
+SDValue DAGCombiner::visitEXTEND_VECTOR_INREG(SDNode *N) {
SDValue N0 = N->getOperand(0);
EVT VT = N->getValueType(0);
- // zext_vector_inreg(undef) = 0 because the top bits will be zero.
+ // {s/z}ext_vector_inreg(undef) = 0 because the top bits must be the same.
if (N0.isUndef())
return DAG.getConstant(0, SDLoc(N), VT);
@@ -11812,6 +12303,9 @@ SDValue DAGCombiner::visitTRUNCATE(SDNode *N) {
}
}
+ if (SDValue V = foldSubToUSubSat(VT, N0.getNode()))
+ return V;
+
// Attempt to pre-truncate BUILD_VECTOR sources.
if (N0.getOpcode() == ISD::BUILD_VECTOR && !LegalOperations &&
TLI.isTruncateFree(SrcVT.getScalarType(), VT.getScalarType()) &&
@@ -12013,6 +12507,20 @@ SDValue DAGCombiner::visitTRUNCATE(SDNode *N) {
return DAG.getNode(N0.getOpcode(), DL, VT, NarrowL, NarrowR);
}
}
+ break;
+ case ISD::USUBSAT:
+ // Truncate the USUBSAT only if LHS is a known zero-extension, its not
+ // enough to know that the upper bits are zero we must ensure that we don't
+ // introduce an extra truncate.
+ if (!LegalOperations && N0.hasOneUse() &&
+ N0.getOperand(0).getOpcode() == ISD::ZERO_EXTEND &&
+ N0.getOperand(0).getOperand(0).getScalarValueSizeInBits() <=
+ VT.getScalarSizeInBits() &&
+ hasOperation(N0.getOpcode(), VT)) {
+ return getTruncatedUSUBSAT(VT, SrcVT, N0.getOperand(0), N0.getOperand(1),
+ DAG, SDLoc(N));
+ }
+ break;
}
return SDValue();
@@ -12141,7 +12649,7 @@ SDValue DAGCombiner::visitBITCAST(SDNode *N) {
VT.getVectorElementType());
// If the input is a constant, let getNode fold it.
- if (isa<ConstantSDNode>(N0) || isa<ConstantFPSDNode>(N0)) {
+ if (isIntOrFPConstant(N0)) {
// If we can't allow illegal operations, we need to check that this is just
// a fp -> int or int -> conversion and that the resulting operation will
// be legal.
@@ -12374,12 +12882,7 @@ SDValue DAGCombiner::visitBUILD_PAIR(SDNode *N) {
SDValue DAGCombiner::visitFREEZE(SDNode *N) {
SDValue N0 = N->getOperand(0);
- // (freeze (freeze x)) -> (freeze x)
- if (N0.getOpcode() == ISD::FREEZE)
- return N0;
-
- // If the input is a constant, return it.
- if (isa<ConstantSDNode>(N0) || isa<ConstantFPSDNode>(N0))
+ if (DAG.isGuaranteedNotToBeUndefOrPoison(N0, /*PoisonOnly*/ false))
return N0;
return SDValue();
@@ -12500,11 +13003,6 @@ ConstantFoldBITCASTofBUILD_VECTOR(SDNode *BV, EVT DstEltVT) {
return DAG.getBuildVector(VT, DL, Ops);
}
-static bool isContractable(SDNode *N) {
- SDNodeFlags F = N->getFlags();
- return F.hasAllowContract() || F.hasAllowReassociation();
-}
-
/// Try to perform FMA combining on a given FADD node.
SDValue DAGCombiner::visitFADDForFMACombine(SDNode *N) {
SDValue N0 = N->getOperand(0);
@@ -12526,16 +13024,15 @@ SDValue DAGCombiner::visitFADDForFMACombine(SDNode *N) {
if (!HasFMAD && !HasFMA)
return SDValue();
- bool CanFuse = Options.UnsafeFPMath || isContractable(N);
bool CanReassociate =
Options.UnsafeFPMath || N->getFlags().hasAllowReassociation();
bool AllowFusionGlobally = (Options.AllowFPOpFusion == FPOpFusion::Fast ||
- CanFuse || HasFMAD);
+ Options.UnsafeFPMath || HasFMAD);
// If the addition is not contractable, do not combine.
- if (!AllowFusionGlobally && !isContractable(N))
+ if (!AllowFusionGlobally && !N->getFlags().hasAllowContract())
return SDValue();
- if (STI && STI->generateFMAsInMachineCombiner(OptLevel))
+ if (TLI.generateFMAsInMachineCombiner(VT, OptLevel))
return SDValue();
// Always prefer FMAD to FMA for precision.
@@ -12547,7 +13044,7 @@ SDValue DAGCombiner::visitFADDForFMACombine(SDNode *N) {
auto isContractableFMUL = [AllowFusionGlobally](SDValue N) {
if (N.getOpcode() != ISD::FMUL)
return false;
- return AllowFusionGlobally || isContractable(N.getNode());
+ return AllowFusionGlobally || N->getFlags().hasAllowContract();
};
// If we have two choices trying to fold (fadd (fmul u, v), (fmul x, y)),
// prefer to fold the multiply with fewer uses.
@@ -12736,15 +13233,14 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
return SDValue();
const SDNodeFlags Flags = N->getFlags();
- bool CanFuse = Options.UnsafeFPMath || isContractable(N);
bool AllowFusionGlobally = (Options.AllowFPOpFusion == FPOpFusion::Fast ||
- CanFuse || HasFMAD);
+ Options.UnsafeFPMath || HasFMAD);
// If the subtraction is not contractable, do not combine.
- if (!AllowFusionGlobally && !isContractable(N))
+ if (!AllowFusionGlobally && !N->getFlags().hasAllowContract())
return SDValue();
- if (STI && STI->generateFMAsInMachineCombiner(OptLevel))
+ if (TLI.generateFMAsInMachineCombiner(VT, OptLevel))
return SDValue();
// Always prefer FMAD to FMA for precision.
@@ -12757,7 +13253,7 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
auto isContractableFMUL = [AllowFusionGlobally](SDValue N) {
if (N.getOpcode() != ISD::FMUL)
return false;
- return AllowFusionGlobally || isContractable(N.getNode());
+ return AllowFusionGlobally || N->getFlags().hasAllowContract();
};
// fold (fsub (fmul x, y), z) -> (fma x, y, (fneg z))
@@ -12887,13 +13383,23 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
}
}
+ auto isReassociable = [Options](SDNode *N) {
+ return Options.UnsafeFPMath || N->getFlags().hasAllowReassociation();
+ };
+
+ auto isContractableAndReassociableFMUL = [isContractableFMUL,
+ isReassociable](SDValue N) {
+ return isContractableFMUL(N) && isReassociable(N.getNode());
+ };
+
// More folding opportunities when target permits.
- if (Aggressive) {
+ if (Aggressive && isReassociable(N)) {
+ bool CanFuse = Options.UnsafeFPMath || N->getFlags().hasAllowContract();
// fold (fsub (fma x, y, (fmul u, v)), z)
// -> (fma x, y (fma u, v, (fneg z)))
if (CanFuse && N0.getOpcode() == PreferredFusedOpcode &&
- isContractableFMUL(N0.getOperand(2)) && N0->hasOneUse() &&
- N0.getOperand(2)->hasOneUse()) {
+ isContractableAndReassociableFMUL(N0.getOperand(2)) &&
+ N0->hasOneUse() && N0.getOperand(2)->hasOneUse()) {
return DAG.getNode(PreferredFusedOpcode, SL, VT, N0.getOperand(0),
N0.getOperand(1),
DAG.getNode(PreferredFusedOpcode, SL, VT,
@@ -12905,7 +13411,7 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
// fold (fsub x, (fma y, z, (fmul u, v)))
// -> (fma (fneg y), z, (fma (fneg u), v, x))
if (CanFuse && N1.getOpcode() == PreferredFusedOpcode &&
- isContractableFMUL(N1.getOperand(2)) &&
+ isContractableAndReassociableFMUL(N1.getOperand(2)) &&
N1->hasOneUse() && NoSignedZero) {
SDValue N20 = N1.getOperand(2).getOperand(0);
SDValue N21 = N1.getOperand(2).getOperand(1);
@@ -12916,7 +13422,6 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
DAG.getNode(ISD::FNEG, SL, VT, N20), N21, N0));
}
-
// fold (fsub (fma x, y, (fpext (fmul u, v))), z)
// -> (fma x, y (fma (fpext u), (fpext v), (fneg z)))
if (N0.getOpcode() == PreferredFusedOpcode &&
@@ -12924,7 +13429,7 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
SDValue N02 = N0.getOperand(2);
if (N02.getOpcode() == ISD::FP_EXTEND) {
SDValue N020 = N02.getOperand(0);
- if (isContractableFMUL(N020) &&
+ if (isContractableAndReassociableFMUL(N020) &&
TLI.isFPExtFoldable(DAG, PreferredFusedOpcode, VT,
N020.getValueType())) {
return DAG.getNode(
@@ -12948,7 +13453,7 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
SDValue N00 = N0.getOperand(0);
if (N00.getOpcode() == PreferredFusedOpcode) {
SDValue N002 = N00.getOperand(2);
- if (isContractableFMUL(N002) &&
+ if (isContractableAndReassociableFMUL(N002) &&
TLI.isFPExtFoldable(DAG, PreferredFusedOpcode, VT,
N00.getValueType())) {
return DAG.getNode(
@@ -12970,7 +13475,7 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
N1.getOperand(2).getOpcode() == ISD::FP_EXTEND &&
N1->hasOneUse()) {
SDValue N120 = N1.getOperand(2).getOperand(0);
- if (isContractableFMUL(N120) &&
+ if (isContractableAndReassociableFMUL(N120) &&
TLI.isFPExtFoldable(DAG, PreferredFusedOpcode, VT,
N120.getValueType())) {
SDValue N1200 = N120.getOperand(0);
@@ -12997,7 +13502,7 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
SDValue N100 = CvtSrc.getOperand(0);
SDValue N101 = CvtSrc.getOperand(1);
SDValue N102 = CvtSrc.getOperand(2);
- if (isContractableFMUL(N102) &&
+ if (isContractableAndReassociableFMUL(N102) &&
TLI.isFPExtFoldable(DAG, PreferredFusedOpcode, VT,
CvtSrc.getValueType())) {
SDValue N1020 = N102.getOperand(0);
@@ -13933,13 +14438,25 @@ static inline bool CanCombineFCOPYSIGN_EXTEND_ROUND(SDNode *N) {
SDValue N1 = N->getOperand(1);
if ((N1.getOpcode() == ISD::FP_EXTEND ||
N1.getOpcode() == ISD::FP_ROUND)) {
+ EVT N1VT = N1->getValueType(0);
+ EVT N1Op0VT = N1->getOperand(0).getValueType();
+
+ // Always fold no-op FP casts.
+ if (N1VT == N1Op0VT)
+ return true;
+
// Do not optimize out type conversion of f128 type yet.
// For some targets like x86_64, configuration is changed to keep one f128
// value in one SSE register, but instruction selection cannot handle
// FCOPYSIGN on SSE registers yet.
- EVT N1VT = N1->getValueType(0);
- EVT N1Op0VT = N1->getOperand(0).getValueType();
- return (N1VT == N1Op0VT || N1Op0VT != MVT::f128);
+ if (N1Op0VT == MVT::f128)
+ return false;
+
+ // Avoid mismatched vector operand types, for better instruction selection.
+ if (N1Op0VT.isVector())
+ return false;
+
+ return true;
}
return false;
}
@@ -15971,12 +16488,9 @@ bool DAGCombiner::SliceUpLoad(SDNode *N) {
// Prepare the argument for the new token factor for all the slices.
SmallVector<SDValue, 8> ArgChains;
- for (SmallVectorImpl<LoadedSlice>::const_iterator
- LSIt = LoadedSlices.begin(),
- LSItEnd = LoadedSlices.end();
- LSIt != LSItEnd; ++LSIt) {
- SDValue SliceInst = LSIt->loadSlice();
- CombineTo(LSIt->Inst, SliceInst, true);
+ for (const LoadedSlice &LS : LoadedSlices) {
+ SDValue SliceInst = LS.loadSlice();
+ CombineTo(LS.Inst, SliceInst, true);
if (SliceInst.getOpcode() != ISD::LOAD)
SliceInst = SliceInst.getOperand(0);
assert(SliceInst->getOpcode() == ISD::LOAD &&
@@ -16408,6 +16922,9 @@ bool DAGCombiner::mergeStoresOfConstantsOrVecElts(
if (NumStores < 2)
return false;
+ assert((!UseTrunc || !UseVector) &&
+ "This optimization cannot emit a vector truncating store");
+
// The latest Node in the DAG.
SDLoc DL(StoreNodes[0].MemNode);
@@ -16631,7 +17148,7 @@ void DAGCombiner::getStoreMergeCandidates(
case StoreSource::Constant:
if (NoTypeMatch)
return false;
- if (!(isa<ConstantSDNode>(OtherBC) || isa<ConstantFPSDNode>(OtherBC)))
+ if (!isIntOrFPConstant(OtherBC))
return false;
break;
case StoreSource::Extract:
@@ -16903,6 +17420,7 @@ bool DAGCombiner::tryStoreMergeOfConstants(
bool UseVector = (LastLegalVectorType > LastLegalType) && AllowVectors;
unsigned NumElem = (UseVector) ? LastLegalVectorType : LastLegalType;
+ bool UseTrunc = LastIntegerTrunc && !UseVector;
// Check if we found a legal integer type that creates a meaningful
// merge.
@@ -16933,8 +17451,9 @@ bool DAGCombiner::tryStoreMergeOfConstants(
continue;
}
- MadeChange |= mergeStoresOfConstantsOrVecElts(
- StoreNodes, MemVT, NumElem, true, UseVector, LastIntegerTrunc);
+ MadeChange |= mergeStoresOfConstantsOrVecElts(StoreNodes, MemVT, NumElem,
+ /*IsConstantSrc*/ true,
+ UseVector, UseTrunc);
// Remove merged stores for next iteration.
StoreNodes.erase(StoreNodes.begin(), StoreNodes.begin() + NumElem);
@@ -17003,7 +17522,8 @@ bool DAGCombiner::tryStoreMergeOfExtracts(
}
MadeChange |= mergeStoresOfConstantsOrVecElts(
- StoreNodes, MemVT, NumStoresToMerge, false, true, false);
+ StoreNodes, MemVT, NumStoresToMerge, /*IsConstantSrc*/ false,
+ /*UseVector*/ true, /*UseTrunc*/ false);
StoreNodes.erase(StoreNodes.begin(), StoreNodes.begin() + NumStoresToMerge);
NumConsecutiveStores -= NumStoresToMerge;
@@ -17022,8 +17542,6 @@ bool DAGCombiner::tryStoreMergeOfLoads(SmallVectorImpl<MemOpLink> &StoreNodes,
unsigned NumMemElts = MemVT.isVector() ? MemVT.getVectorNumElements() : 1;
bool MadeChange = false;
- int64_t StartAddress = StoreNodes[0].OffsetFromBase;
-
// Look for load nodes which are used by the stored values.
SmallVector<MemOpLink, 8> LoadNodes;
@@ -17091,7 +17609,7 @@ bool DAGCombiner::tryStoreMergeOfLoads(SmallVectorImpl<MemOpLink> &StoreNodes,
unsigned LastLegalIntegerType = 1;
bool isDereferenceable = true;
bool DoIntegerTruncate = false;
- StartAddress = LoadNodes[0].OffsetFromBase;
+ int64_t StartAddress = LoadNodes[0].OffsetFromBase;
SDValue LoadChain = FirstLoad->getChain();
for (unsigned i = 1; i < LoadNodes.size(); ++i) {
// All loads must share the same chain.
@@ -17582,6 +18100,7 @@ SDValue DAGCombiner::visitSTORE(SDNode *N) {
if (LoadSDNode *Ld = dyn_cast<LoadSDNode>(Value)) {
if (Ld->getBasePtr() == Ptr && ST->getMemoryVT() == Ld->getMemoryVT() &&
ST->isUnindexed() && ST->isSimple() &&
+ Ld->getAddressSpace() == ST->getAddressSpace() &&
// There can't be any side effects between the load and store, such as
// a call or store.
Chain.reachesChainWithoutSideEffects(SDValue(Ld, 1))) {
@@ -17595,7 +18114,8 @@ SDValue DAGCombiner::visitSTORE(SDNode *N) {
if (ST->isUnindexed() && ST->isSimple() &&
ST1->isUnindexed() && ST1->isSimple()) {
if (ST1->getBasePtr() == Ptr && ST1->getValue() == Value &&
- ST->getMemoryVT() == ST1->getMemoryVT()) {
+ ST->getMemoryVT() == ST1->getMemoryVT() &&
+ ST->getAddressSpace() == ST1->getAddressSpace()) {
// If this is a store followed by a store with the same value to the
// same location, then the store is dead/noop.
return Chain;
@@ -17606,7 +18126,8 @@ SDValue DAGCombiner::visitSTORE(SDNode *N) {
// BaseIndexOffset and the code below requires knowing the size
// of a vector, so bail out if MemoryVT is scalable.
!ST->getMemoryVT().isScalableVector() &&
- !ST1->getMemoryVT().isScalableVector()) {
+ !ST1->getMemoryVT().isScalableVector() &&
+ ST->getAddressSpace() == ST1->getAddressSpace()) {
const BaseIndexOffset STBase = BaseIndexOffset::match(ST, DAG);
const BaseIndexOffset ChainBase = BaseIndexOffset::match(ST1, DAG);
unsigned STBitSize = ST->getMemoryVT().getFixedSizeInBits();
@@ -17625,10 +18146,11 @@ SDValue DAGCombiner::visitSTORE(SDNode *N) {
// If this is an FP_ROUND or TRUNC followed by a store, fold this into a
// truncating store. We can do this even if this is already a truncstore.
- if ((Value.getOpcode() == ISD::FP_ROUND || Value.getOpcode() == ISD::TRUNCATE)
- && Value.getNode()->hasOneUse() && ST->isUnindexed() &&
- TLI.isTruncStoreLegal(Value.getOperand(0).getValueType(),
- ST->getMemoryVT())) {
+ if ((Value.getOpcode() == ISD::FP_ROUND ||
+ Value.getOpcode() == ISD::TRUNCATE) &&
+ Value.getNode()->hasOneUse() && ST->isUnindexed() &&
+ TLI.canCombineTruncStore(Value.getOperand(0).getValueType(),
+ ST->getMemoryVT(), LegalOperations)) {
return DAG.getTruncStore(Chain, SDLoc(N), Value.getOperand(0),
Ptr, ST->getMemoryVT(), ST->getMemOperand());
}
@@ -18086,26 +18608,19 @@ SDValue DAGCombiner::scalarizeExtractedVectorLoad(SDNode *EVE, EVT InVecVT,
Alignment = NewAlign;
- SDValue NewPtr = OriginalLoad->getBasePtr();
- SDValue Offset;
- EVT PtrType = NewPtr.getValueType();
MachinePointerInfo MPI;
SDLoc DL(EVE);
if (auto *ConstEltNo = dyn_cast<ConstantSDNode>(EltNo)) {
int Elt = ConstEltNo->getZExtValue();
unsigned PtrOff = VecEltVT.getSizeInBits() * Elt / 8;
- Offset = DAG.getConstant(PtrOff, DL, PtrType);
MPI = OriginalLoad->getPointerInfo().getWithOffset(PtrOff);
} else {
- Offset = DAG.getZExtOrTrunc(EltNo, DL, PtrType);
- Offset = DAG.getNode(
- ISD::MUL, DL, PtrType, Offset,
- DAG.getConstant(VecEltVT.getStoreSize(), DL, PtrType));
// Discard the pointer info except the address space because the memory
// operand can't represent this new access since the offset is variable.
MPI = MachinePointerInfo(OriginalLoad->getPointerInfo().getAddrSpace());
}
- NewPtr = DAG.getMemBasePlusOffset(NewPtr, Offset, DL);
+ SDValue NewPtr = TLI.getVectorElementPointer(DAG, OriginalLoad->getBasePtr(),
+ InVecVT, EltNo);
// The replacement we need to do here is a little tricky: we need to
// replace an extractelement of a load with a load.
@@ -18710,6 +19225,9 @@ SDValue DAGCombiner::createBuildVecShuffle(const SDLoc &DL, SDNode *N,
uint64_t InVT1Size = InVT1.getFixedSizeInBits();
uint64_t InVT2Size = InVT2.getFixedSizeInBits();
+ assert(InVT2Size <= InVT1Size &&
+ "Inputs must be sorted to be in non-increasing vector size order.");
+
// We can't generate a shuffle node with mismatched input and output types.
// Try to make the types match the type of the output.
if (InVT1 != VT || InVT2 != VT) {
@@ -18736,7 +19254,10 @@ SDValue DAGCombiner::createBuildVecShuffle(const SDLoc &DL, SDNode *N,
// Since we now have shorter input vectors, adjust the offset of the
// second vector's start.
Vec2Offset = NumElems;
- } else if (InVT2Size <= InVT1Size) {
+ } else {
+ assert(InVT2Size <= InVT1Size &&
+ "Second input is not going to be larger than the first one.");
+
// VecIn1 is wider than the output, and we have another, possibly
// smaller input. Pad the smaller input with undefs, shuffle at the
// input vector width, and extract the output.
@@ -18755,11 +19276,6 @@ SDValue DAGCombiner::createBuildVecShuffle(const SDLoc &DL, SDNode *N,
DAG.getUNDEF(InVT1), VecIn2, ZeroIdx);
}
ShuffleNumElems = NumElems * 2;
- } else {
- // Both VecIn1 and VecIn2 are wider than the output, and VecIn2 is wider
- // than VecIn1. We can't handle this for now - this case will disappear
- // when we start sorting the vectors by type.
- return SDValue();
}
} else if (InVT2Size * 2 == VTSize && InVT1Size == VTSize) {
SmallVector<SDValue, 2> ConcatOps(2, DAG.getUNDEF(InVT2));
@@ -18884,6 +19400,15 @@ static SDValue reduceBuildVecToShuffleWithZero(SDNode *BV, SelectionDAG &DAG) {
return DAG.getBitcast(VT, Shuf);
}
+// FIXME: promote to STLExtras.
+template <typename R, typename T>
+static auto getFirstIndexOf(R &&Range, const T &Val) {
+ auto I = find(Range, Val);
+ if (I == Range.end())
+ return static_cast<decltype(std::distance(Range.begin(), I))>(-1);
+ return std::distance(Range.begin(), I);
+}
+
// Check to see if this is a BUILD_VECTOR of a bunch of EXTRACT_VECTOR_ELT
// operations. If the types of the vectors we're extracting from allow it,
// turn this into a vector_shuffle node.
@@ -18952,9 +19477,11 @@ SDValue DAGCombiner::reduceBuildVecToShuffle(SDNode *N) {
// Have we seen this input vector before?
// The vectors are expected to be tiny (usually 1 or 2 elements), so using
// a map back from SDValues to numbers isn't worth it.
- unsigned Idx = std::distance(VecIn.begin(), find(VecIn, ExtractedFromVec));
- if (Idx == VecIn.size())
+ int Idx = getFirstIndexOf(VecIn, ExtractedFromVec);
+ if (Idx == -1) { // A new source vector?
+ Idx = VecIn.size();
VecIn.push_back(ExtractedFromVec);
+ }
VectorMask[i] = Idx;
}
@@ -18989,7 +19516,9 @@ SDValue DAGCombiner::reduceBuildVecToShuffle(SDNode *N) {
unsigned SplitSize = NearestPow2 / 2;
EVT SplitVT = EVT::getVectorVT(*DAG.getContext(),
InVT.getVectorElementType(), SplitSize);
- if (TLI.isTypeLegal(SplitVT)) {
+ if (TLI.isTypeLegal(SplitVT) &&
+ SplitSize + SplitVT.getVectorNumElements() <=
+ InVT.getVectorNumElements()) {
SDValue VecIn2 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, SplitVT, Vec,
DAG.getVectorIdxConstant(SplitSize, DL));
SDValue VecIn1 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, SplitVT, Vec,
@@ -19008,9 +19537,28 @@ SDValue DAGCombiner::reduceBuildVecToShuffle(SDNode *N) {
}
}
- // TODO: We want to sort the vectors by descending length, so that adjacent
- // pairs have similar length, and the longer vector is always first in the
- // pair.
+ // Sort input vectors by decreasing vector element count,
+ // while preserving the relative order of equally-sized vectors.
+ // Note that we keep the first "implicit zero vector as-is.
+ SmallVector<SDValue, 8> SortedVecIn(VecIn);
+ llvm::stable_sort(MutableArrayRef<SDValue>(SortedVecIn).drop_front(),
+ [](const SDValue &a, const SDValue &b) {
+ return a.getValueType().getVectorNumElements() >
+ b.getValueType().getVectorNumElements();
+ });
+
+ // We now also need to rebuild the VectorMask, because it referenced element
+ // order in VecIn, and we just sorted them.
+ for (int &SourceVectorIndex : VectorMask) {
+ if (SourceVectorIndex <= 0)
+ continue;
+ unsigned Idx = getFirstIndexOf(SortedVecIn, VecIn[SourceVectorIndex]);
+ assert(Idx > 0 && Idx < SortedVecIn.size() &&
+ VecIn[SourceVectorIndex] == SortedVecIn[Idx] && "Remapping failure");
+ SourceVectorIndex = Idx;
+ }
+
+ VecIn = std::move(SortedVecIn);
// TODO: Should this fire if some of the input vectors has illegal type (like
// it does now), or should we let legalization run its course first?
@@ -19183,13 +19731,6 @@ SDValue DAGCombiner::visitBUILD_VECTOR(SDNode *N) {
}
}
- // A splat of a single element is a SPLAT_VECTOR if supported on the target.
- if (TLI.getOperationAction(ISD::SPLAT_VECTOR, VT) != TargetLowering::Expand)
- if (SDValue V = cast<BuildVectorSDNode>(N)->getSplatValue()) {
- assert(!V.isUndef() && "Splat of undef should have been handled earlier");
- return DAG.getNode(ISD::SPLAT_VECTOR, SDLoc(N), VT, V);
- }
-
// Check if we can express BUILD VECTOR via subvector extract.
if (!LegalTypes && (N->getNumOperands() > 1)) {
SDValue Op0 = N->getOperand(0);
@@ -19231,6 +19772,14 @@ SDValue DAGCombiner::visitBUILD_VECTOR(SDNode *N) {
if (SDValue V = reduceBuildVecToShuffle(N))
return V;
+ // A splat of a single element is a SPLAT_VECTOR if supported on the target.
+ // Do this late as some of the above may replace the splat.
+ if (TLI.getOperationAction(ISD::SPLAT_VECTOR, VT) != TargetLowering::Expand)
+ if (SDValue V = cast<BuildVectorSDNode>(N)->getSplatValue()) {
+ assert(!V.isUndef() && "Splat of undef should have been handled earlier");
+ return DAG.getNode(ISD::SPLAT_VECTOR, SDLoc(N), VT, V);
+ }
+
return SDValue();
}
@@ -19879,7 +20428,8 @@ SDValue DAGCombiner::visitEXTRACT_SUBVECTOR(SDNode *N) {
// Try to move vector bitcast after extract_subv by scaling extraction index:
// extract_subv (bitcast X), Index --> bitcast (extract_subv X, Index')
if (V.getOpcode() == ISD::BITCAST &&
- V.getOperand(0).getValueType().isVector()) {
+ V.getOperand(0).getValueType().isVector() &&
+ (!LegalOperations || TLI.isOperationLegal(ISD::BITCAST, NVT))) {
SDValue SrcOp = V.getOperand(0);
EVT SrcVT = SrcOp.getValueType();
unsigned SrcNumElts = SrcVT.getVectorMinNumElements();
@@ -20052,6 +20602,9 @@ static SDValue foldShuffleOfConcatUndefs(ShuffleVectorSDNode *Shuf,
for (unsigned i = 0; i != NumElts; ++i) {
if (Mask[i] == -1)
continue;
+ // If we reference the upper (undef) subvector then the element is undef.
+ if ((Mask[i] % NumElts) >= HalfNumElts)
+ continue;
int M = Mask[i] < (int)NumElts ? Mask[i] : Mask[i] - (int)HalfNumElts;
if (i < HalfNumElts)
Mask0[i] = M;
@@ -20213,7 +20766,7 @@ static SDValue combineShuffleOfScalars(ShuffleVectorSDNode *SVN,
// generating a splat; semantically, this is fine, but it's likely to
// generate low-quality code if the target can't reconstruct an appropriate
// shuffle.
- if (!Op.isUndef() && !isa<ConstantSDNode>(Op) && !isa<ConstantFPSDNode>(Op))
+ if (!Op.isUndef() && !isIntOrFPConstant(Op))
if (!IsSplat && !DuplicateOps.insert(Op).second)
return SDValue();
@@ -20798,44 +21351,15 @@ SDValue DAGCombiner::visitVECTOR_SHUFFLE(SDNode *N) {
}
}
- if (Level < AfterLegalizeDAG && TLI.isTypeLegal(VT)) {
- // Canonicalize shuffles according to rules:
- // shuffle(A, shuffle(A, B)) -> shuffle(shuffle(A,B), A)
- // shuffle(B, shuffle(A, B)) -> shuffle(shuffle(A,B), B)
- // shuffle(B, shuffle(A, Undef)) -> shuffle(shuffle(A, Undef), B)
- if (N1.getOpcode() == ISD::VECTOR_SHUFFLE &&
- N0.getOpcode() != ISD::VECTOR_SHUFFLE) {
- // The incoming shuffle must be of the same type as the result of the
- // current shuffle.
- assert(N1->getOperand(0).getValueType() == VT &&
- "Shuffle types don't match");
-
- SDValue SV0 = N1->getOperand(0);
- SDValue SV1 = N1->getOperand(1);
- bool HasSameOp0 = N0 == SV0;
- bool IsSV1Undef = SV1.isUndef();
- if (HasSameOp0 || IsSV1Undef || N0 == SV1)
- // Commute the operands of this shuffle so merging below will trigger.
- return DAG.getCommutedVectorShuffle(*SVN);
- }
-
- // Canonicalize splat shuffles to the RHS to improve merging below.
- // shuffle(splat(A,u), shuffle(C,D)) -> shuffle'(shuffle(C,D), splat(A,u))
- if (N0.getOpcode() == ISD::VECTOR_SHUFFLE &&
- N1.getOpcode() == ISD::VECTOR_SHUFFLE &&
- cast<ShuffleVectorSDNode>(N0)->isSplat() &&
- !cast<ShuffleVectorSDNode>(N1)->isSplat()) {
- return DAG.getCommutedVectorShuffle(*SVN);
- }
- }
-
// Compute the combined shuffle mask for a shuffle with SV0 as the first
// operand, and SV1 as the second operand.
- // i.e. Merge SVN(OtherSVN, N1) -> shuffle(SV0, SV1, Mask).
- auto MergeInnerShuffle = [NumElts](ShuffleVectorSDNode *SVN,
- ShuffleVectorSDNode *OtherSVN, SDValue N1,
- SDValue &SV0, SDValue &SV1,
- SmallVectorImpl<int> &Mask) -> bool {
+ // i.e. Merge SVN(OtherSVN, N1) -> shuffle(SV0, SV1, Mask) iff Commute = false
+ // Merge SVN(N1, OtherSVN) -> shuffle(SV0, SV1, Mask') iff Commute = true
+ auto MergeInnerShuffle =
+ [NumElts, &VT](bool Commute, ShuffleVectorSDNode *SVN,
+ ShuffleVectorSDNode *OtherSVN, SDValue N1,
+ const TargetLowering &TLI, SDValue &SV0, SDValue &SV1,
+ SmallVectorImpl<int> &Mask) -> bool {
// Don't try to fold splats; they're likely to simplify somehow, or they
// might be free.
if (OtherSVN->isSplat())
@@ -20852,6 +21376,9 @@ SDValue DAGCombiner::visitVECTOR_SHUFFLE(SDNode *N) {
continue;
}
+ if (Commute)
+ Idx = (Idx < (int)NumElts) ? (Idx + NumElts) : (Idx - NumElts);
+
SDValue CurrentVec;
if (Idx < (int)NumElts) {
// This shuffle index refers to the inner shuffle N0. Lookup the inner
@@ -20922,44 +21449,161 @@ SDValue DAGCombiner::visitVECTOR_SHUFFLE(SDNode *N) {
// Bail out if we cannot convert the shuffle pair into a single shuffle.
return false;
}
- return true;
+
+ if (llvm::all_of(Mask, [](int M) { return M < 0; }))
+ return true;
+
+ // Avoid introducing shuffles with illegal mask.
+ // shuffle(shuffle(A, B, M0), C, M1) -> shuffle(A, B, M2)
+ // shuffle(shuffle(A, B, M0), C, M1) -> shuffle(A, C, M2)
+ // shuffle(shuffle(A, B, M0), C, M1) -> shuffle(B, C, M2)
+ // shuffle(shuffle(A, B, M0), C, M1) -> shuffle(B, A, M2)
+ // shuffle(shuffle(A, B, M0), C, M1) -> shuffle(C, A, M2)
+ // shuffle(shuffle(A, B, M0), C, M1) -> shuffle(C, B, M2)
+ if (TLI.isShuffleMaskLegal(Mask, VT))
+ return true;
+
+ std::swap(SV0, SV1);
+ ShuffleVectorSDNode::commuteMask(Mask);
+ return TLI.isShuffleMaskLegal(Mask, VT);
};
- // Try to fold according to rules:
- // shuffle(shuffle(A, B, M0), C, M1) -> shuffle(A, B, M2)
- // shuffle(shuffle(A, B, M0), C, M1) -> shuffle(A, C, M2)
- // shuffle(shuffle(A, B, M0), C, M1) -> shuffle(B, C, M2)
- // Don't try to fold shuffles with illegal type.
- // Only fold if this shuffle is the only user of the other shuffle.
- if (N0.getOpcode() == ISD::VECTOR_SHUFFLE && N->isOnlyUserOf(N0.getNode()) &&
- Level < AfterLegalizeDAG && TLI.isTypeLegal(VT)) {
- ShuffleVectorSDNode *OtherSV = cast<ShuffleVectorSDNode>(N0);
+ if (Level < AfterLegalizeDAG && TLI.isTypeLegal(VT)) {
+ // Canonicalize shuffles according to rules:
+ // shuffle(A, shuffle(A, B)) -> shuffle(shuffle(A,B), A)
+ // shuffle(B, shuffle(A, B)) -> shuffle(shuffle(A,B), B)
+ // shuffle(B, shuffle(A, Undef)) -> shuffle(shuffle(A, Undef), B)
+ if (N1.getOpcode() == ISD::VECTOR_SHUFFLE &&
+ N0.getOpcode() != ISD::VECTOR_SHUFFLE) {
+ // The incoming shuffle must be of the same type as the result of the
+ // current shuffle.
+ assert(N1->getOperand(0).getValueType() == VT &&
+ "Shuffle types don't match");
+
+ SDValue SV0 = N1->getOperand(0);
+ SDValue SV1 = N1->getOperand(1);
+ bool HasSameOp0 = N0 == SV0;
+ bool IsSV1Undef = SV1.isUndef();
+ if (HasSameOp0 || IsSV1Undef || N0 == SV1)
+ // Commute the operands of this shuffle so merging below will trigger.
+ return DAG.getCommutedVectorShuffle(*SVN);
+ }
- // The incoming shuffle must be of the same type as the result of the
- // current shuffle.
- assert(OtherSV->getOperand(0).getValueType() == VT &&
- "Shuffle types don't match");
+ // Canonicalize splat shuffles to the RHS to improve merging below.
+ // shuffle(splat(A,u), shuffle(C,D)) -> shuffle'(shuffle(C,D), splat(A,u))
+ if (N0.getOpcode() == ISD::VECTOR_SHUFFLE &&
+ N1.getOpcode() == ISD::VECTOR_SHUFFLE &&
+ cast<ShuffleVectorSDNode>(N0)->isSplat() &&
+ !cast<ShuffleVectorSDNode>(N1)->isSplat()) {
+ return DAG.getCommutedVectorShuffle(*SVN);
+ }
- SDValue SV0, SV1;
- SmallVector<int, 4> Mask;
- if (MergeInnerShuffle(SVN, OtherSV, N1, SV0, SV1, Mask)) {
- // Check if all indices in Mask are Undef. In case, propagate Undef.
- if (llvm::all_of(Mask, [](int M) { return M < 0; }))
- return DAG.getUNDEF(VT);
+ // Try to fold according to rules:
+ // shuffle(shuffle(A, B, M0), C, M1) -> shuffle(A, B, M2)
+ // shuffle(shuffle(A, B, M0), C, M1) -> shuffle(A, C, M2)
+ // shuffle(shuffle(A, B, M0), C, M1) -> shuffle(B, C, M2)
+ // Don't try to fold shuffles with illegal type.
+ // Only fold if this shuffle is the only user of the other shuffle.
+ // Try matching shuffle(C,shuffle(A,B)) commutted patterns as well.
+ for (int i = 0; i != 2; ++i) {
+ if (N->getOperand(i).getOpcode() == ISD::VECTOR_SHUFFLE &&
+ N->isOnlyUserOf(N->getOperand(i).getNode())) {
+ // The incoming shuffle must be of the same type as the result of the
+ // current shuffle.
+ auto *OtherSV = cast<ShuffleVectorSDNode>(N->getOperand(i));
+ assert(OtherSV->getOperand(0).getValueType() == VT &&
+ "Shuffle types don't match");
- if (!SV0.getNode())
- SV0 = DAG.getUNDEF(VT);
- if (!SV1.getNode())
- SV1 = DAG.getUNDEF(VT);
+ SDValue SV0, SV1;
+ SmallVector<int, 4> Mask;
+ if (MergeInnerShuffle(i != 0, SVN, OtherSV, N->getOperand(1 - i), TLI,
+ SV0, SV1, Mask)) {
+ // Check if all indices in Mask are Undef. In case, propagate Undef.
+ if (llvm::all_of(Mask, [](int M) { return M < 0; }))
+ return DAG.getUNDEF(VT);
- // Avoid introducing shuffles with illegal mask.
- // shuffle(shuffle(A, B, M0), C, M1) -> shuffle(A, B, M2)
- // shuffle(shuffle(A, B, M0), C, M1) -> shuffle(A, C, M2)
- // shuffle(shuffle(A, B, M0), C, M1) -> shuffle(B, C, M2)
- // shuffle(shuffle(A, B, M0), C, M1) -> shuffle(B, A, M2)
- // shuffle(shuffle(A, B, M0), C, M1) -> shuffle(C, A, M2)
- // shuffle(shuffle(A, B, M0), C, M1) -> shuffle(C, B, M2)
- return TLI.buildLegalVectorShuffle(VT, SDLoc(N), SV0, SV1, Mask, DAG);
+ return DAG.getVectorShuffle(VT, SDLoc(N),
+ SV0 ? SV0 : DAG.getUNDEF(VT),
+ SV1 ? SV1 : DAG.getUNDEF(VT), Mask);
+ }
+ }
+ }
+
+ // Merge shuffles through binops if we are able to merge it with at least
+ // one other shuffles.
+ // shuffle(bop(shuffle(x,y),shuffle(z,w)),undef)
+ // shuffle(bop(shuffle(x,y),shuffle(z,w)),bop(shuffle(a,b),shuffle(c,d)))
+ unsigned SrcOpcode = N0.getOpcode();
+ if (TLI.isBinOp(SrcOpcode) && N->isOnlyUserOf(N0.getNode()) &&
+ (N1.isUndef() ||
+ (SrcOpcode == N1.getOpcode() && N->isOnlyUserOf(N1.getNode())))) {
+ // Get binop source ops, or just pass on the undef.
+ SDValue Op00 = N0.getOperand(0);
+ SDValue Op01 = N0.getOperand(1);
+ SDValue Op10 = N1.isUndef() ? N1 : N1.getOperand(0);
+ SDValue Op11 = N1.isUndef() ? N1 : N1.getOperand(1);
+ // TODO: We might be able to relax the VT check but we don't currently
+ // have any isBinOp() that has different result/ops VTs so play safe until
+ // we have test coverage.
+ if (Op00.getValueType() == VT && Op10.getValueType() == VT &&
+ Op01.getValueType() == VT && Op11.getValueType() == VT &&
+ (Op00.getOpcode() == ISD::VECTOR_SHUFFLE ||
+ Op10.getOpcode() == ISD::VECTOR_SHUFFLE ||
+ Op01.getOpcode() == ISD::VECTOR_SHUFFLE ||
+ Op11.getOpcode() == ISD::VECTOR_SHUFFLE)) {
+ auto CanMergeInnerShuffle = [&](SDValue &SV0, SDValue &SV1,
+ SmallVectorImpl<int> &Mask, bool LeftOp,
+ bool Commute) {
+ SDValue InnerN = Commute ? N1 : N0;
+ SDValue Op0 = LeftOp ? Op00 : Op01;
+ SDValue Op1 = LeftOp ? Op10 : Op11;
+ if (Commute)
+ std::swap(Op0, Op1);
+ // Only accept the merged shuffle if we don't introduce undef elements,
+ // or the inner shuffle already contained undef elements.
+ auto *SVN0 = dyn_cast<ShuffleVectorSDNode>(Op0);
+ return SVN0 && InnerN->isOnlyUserOf(SVN0) &&
+ MergeInnerShuffle(Commute, SVN, SVN0, Op1, TLI, SV0, SV1,
+ Mask) &&
+ (llvm::any_of(SVN0->getMask(), [](int M) { return M < 0; }) ||
+ llvm::none_of(Mask, [](int M) { return M < 0; }));
+ };
+
+ // Ensure we don't increase the number of shuffles - we must merge a
+ // shuffle from at least one of the LHS and RHS ops.
+ bool MergedLeft = false;
+ SDValue LeftSV0, LeftSV1;
+ SmallVector<int, 4> LeftMask;
+ if (CanMergeInnerShuffle(LeftSV0, LeftSV1, LeftMask, true, false) ||
+ CanMergeInnerShuffle(LeftSV0, LeftSV1, LeftMask, true, true)) {
+ MergedLeft = true;
+ } else {
+ LeftMask.assign(SVN->getMask().begin(), SVN->getMask().end());
+ LeftSV0 = Op00, LeftSV1 = Op10;
+ }
+
+ bool MergedRight = false;
+ SDValue RightSV0, RightSV1;
+ SmallVector<int, 4> RightMask;
+ if (CanMergeInnerShuffle(RightSV0, RightSV1, RightMask, false, false) ||
+ CanMergeInnerShuffle(RightSV0, RightSV1, RightMask, false, true)) {
+ MergedRight = true;
+ } else {
+ RightMask.assign(SVN->getMask().begin(), SVN->getMask().end());
+ RightSV0 = Op01, RightSV1 = Op11;
+ }
+
+ if (MergedLeft || MergedRight) {
+ SDLoc DL(N);
+ SDValue LHS = DAG.getVectorShuffle(
+ VT, DL, LeftSV0 ? LeftSV0 : DAG.getUNDEF(VT),
+ LeftSV1 ? LeftSV1 : DAG.getUNDEF(VT), LeftMask);
+ SDValue RHS = DAG.getVectorShuffle(
+ VT, DL, RightSV0 ? RightSV0 : DAG.getUNDEF(VT),
+ RightSV1 ? RightSV1 : DAG.getUNDEF(VT), RightMask);
+ return DAG.getNode(SrcOpcode, DL, VT, LHS, RHS);
+ }
+ }
}
}
@@ -21174,7 +21818,7 @@ SDValue DAGCombiner::visitFP16_TO_FP(SDNode *N) {
SDValue N0 = N->getOperand(0);
// fold fp16_to_fp(op & 0xffff) -> fp16_to_fp(op)
- if (N0->getOpcode() == ISD::AND) {
+ if (!TLI.shouldKeepZExtForFP16Conv() && N0->getOpcode() == ISD::AND) {
ConstantSDNode *AndConst = getAsNonOpaqueConstant(N0.getOperand(1));
if (AndConst && AndConst->getAPIntValue() == 0xffff) {
return DAG.getNode(ISD::FP16_TO_FP, SDLoc(N), N->getValueType(0),
@@ -21775,6 +22419,50 @@ SDValue DAGCombiner::foldSelectCCToShiftAnd(const SDLoc &DL, SDValue N0,
return DAG.getNode(ISD::AND, DL, AType, Shift, N2);
}
+// Fold select(cc, binop(), binop()) -> binop(select(), select()) etc.
+SDValue DAGCombiner::foldSelectOfBinops(SDNode *N) {
+ SDValue N0 = N->getOperand(0);
+ SDValue N1 = N->getOperand(1);
+ SDValue N2 = N->getOperand(2);
+ EVT VT = N->getValueType(0);
+ SDLoc DL(N);
+
+ unsigned BinOpc = N1.getOpcode();
+ if (!TLI.isBinOp(BinOpc) || (N2.getOpcode() != BinOpc))
+ return SDValue();
+
+ if (!N->isOnlyUserOf(N0.getNode()) || !N->isOnlyUserOf(N1.getNode()))
+ return SDValue();
+
+ // Fold select(cond, binop(x, y), binop(z, y))
+ // --> binop(select(cond, x, z), y)
+ if (N1.getOperand(1) == N2.getOperand(1)) {
+ SDValue NewSel =
+ DAG.getSelect(DL, VT, N0, N1.getOperand(0), N2.getOperand(0));
+ SDValue NewBinOp = DAG.getNode(BinOpc, DL, VT, NewSel, N1.getOperand(1));
+ NewBinOp->setFlags(N1->getFlags());
+ NewBinOp->intersectFlagsWith(N2->getFlags());
+ return NewBinOp;
+ }
+
+ // Fold select(cond, binop(x, y), binop(x, z))
+ // --> binop(x, select(cond, y, z))
+ // Second op VT might be different (e.g. shift amount type)
+ if (N1.getOperand(0) == N2.getOperand(0) &&
+ VT == N1.getOperand(1).getValueType() &&
+ VT == N2.getOperand(1).getValueType()) {
+ SDValue NewSel =
+ DAG.getSelect(DL, VT, N0, N1.getOperand(1), N2.getOperand(1));
+ SDValue NewBinOp = DAG.getNode(BinOpc, DL, VT, N1.getOperand(0), NewSel);
+ NewBinOp->setFlags(N1->getFlags());
+ NewBinOp->intersectFlagsWith(N2->getFlags());
+ return NewBinOp;
+ }
+
+ // TODO: Handle isCommutativeBinOp patterns as well?
+ return SDValue();
+}
+
// Transform (fneg/fabs (bitconvert x)) to avoid loading constant pool values.
SDValue DAGCombiner::foldSignChangeInBitcast(SDNode *N) {
SDValue N0 = N->getOperand(0);
@@ -22426,12 +23114,11 @@ bool DAGCombiner::isAlias(SDNode *Op0, SDNode *Op1) const {
int64_t MinOffset = std::min(SrcValOffset0, SrcValOffset1);
int64_t Overlap0 = *Size0 + SrcValOffset0 - MinOffset;
int64_t Overlap1 = *Size1 + SrcValOffset1 - MinOffset;
- AliasResult AAResult = AA->alias(
- MemoryLocation(MUC0.MMO->getValue(), Overlap0,
- UseTBAA ? MUC0.MMO->getAAInfo() : AAMDNodes()),
- MemoryLocation(MUC1.MMO->getValue(), Overlap1,
- UseTBAA ? MUC1.MMO->getAAInfo() : AAMDNodes()));
- if (AAResult == NoAlias)
+ if (AA->isNoAlias(
+ MemoryLocation(MUC0.MMO->getValue(), Overlap0,
+ UseTBAA ? MUC0.MMO->getAAInfo() : AAMDNodes()),
+ MemoryLocation(MUC1.MMO->getValue(), Overlap1,
+ UseTBAA ? MUC1.MMO->getAAInfo() : AAMDNodes())))
return false;
}
@@ -22614,6 +23301,10 @@ bool DAGCombiner::parallelizeChainedStores(StoreSDNode *St) {
if (BasePtr.getBase().isUndef())
return false;
+ // Do not handle stores to opaque types
+ if (St->getMemoryVT().isZeroSized())
+ return false;
+
// BaseIndexOffset assumes that offsets are fixed-size, which
// is not valid for scalable vectors where the offsets are
// scaled by `vscale`, so bail out early.
@@ -22624,6 +23315,9 @@ bool DAGCombiner::parallelizeChainedStores(StoreSDNode *St) {
Intervals.insert(0, (St->getMemoryVT().getSizeInBits() + 7) / 8, Unit);
while (StoreSDNode *Chain = dyn_cast<StoreSDNode>(STChain->getChain())) {
+ if (Chain->getMemoryVT().isScalableVector())
+ return false;
+
// If the chain has more than one use, then we can't reorder the mem ops.
if (!SDValue(Chain, 0)->hasOneUse())
break;