return SDValue();
}
-/// CanFoldXORWithAllOnes - Test whether the XOR operand is a AllOnes vector
-/// so it can be folded inside ANDNP.
-static bool CanFoldXORWithAllOnes(const SDNode *N) {
+// Try to fold: (and (xor X, -1), Y) -> (andnp X, Y).
+static SDValue combineANDXORWithAllOnesIntoANDNP(SDNode *N, SelectionDAG &DAG) {
+ assert(N->getOpcode() == ISD::AND);
+
EVT VT = N->getValueType(0);
+ SDValue N0 = N->getOperand(0);
+ SDValue N1 = N->getOperand(1);
+ SDLoc DL(N);
- // Match direct AllOnes for 128 and 256-bit vectors
- if (ISD::isBuildVectorAllOnes(N))
- return true;
+ if (VT != MVT::v2i64 && VT != MVT::v4i64)
+ return SDValue();
- // Look through a bit convert.
- if (N->getOpcode() == ISD::BITCAST)
- N = N->getOperand(0).getNode();
-
- // Sometimes the operand may come from a insert_subvector building a 256-bit
- // allones vector
- if (VT.is256BitVector() &&
- N->getOpcode() == ISD::INSERT_SUBVECTOR) {
- SDValue V1 = N->getOperand(0);
- SDValue V2 = N->getOperand(1);
-
- if (V1.getOpcode() == ISD::INSERT_SUBVECTOR &&
- V1.getOperand(0).getOpcode() == ISD::UNDEF &&
- ISD::isBuildVectorAllOnes(V1.getOperand(1).getNode()) &&
- ISD::isBuildVectorAllOnes(V2.getNode()))
- return true;
- }
+ // Canonicalize XOR to the left.
+ if (N1.getOpcode() == ISD::XOR)
+ std::swap(N0, N1);
- return false;
+ if (N0.getOpcode() != ISD::XOR)
+ return SDValue();
+
+ SDValue N00 = N0->getOperand(0);
+ SDValue N01 = N0->getOperand(1);
+
+ // Look through a bitcast.
+ if (N01->getOpcode() == ISD::BITCAST)
+ N01 = N01->getOperand(0);
+
+ // Either match a direct AllOnes for 128 and 256-bit vectors, or an
+ // insert_subvector building a 256-bit AllOnes vector.
+ if (!ISD::isBuildVectorAllOnes(N01.getNode())) {
+ if (!VT.is256BitVector() || N01->getOpcode() != ISD::INSERT_SUBVECTOR)
+ return SDValue();
+
+ SDValue V1 = N01->getOperand(0);
+ SDValue V2 = N01->getOperand(1);
+ if (V1.getOpcode() != ISD::INSERT_SUBVECTOR ||
+ V1.getOperand(0).getOpcode() != ISD::UNDEF ||
+ !ISD::isBuildVectorAllOnes(V1.getOperand(1).getNode()) ||
+ !ISD::isBuildVectorAllOnes(V2.getNode()))
+ return SDValue();
+ }
+ return DAG.getNode(X86ISD::ANDNP, DL, VT, N00, N1);
}
// On AVX/AVX2 the type v8i1 is legalized to v8i16, which is an XMM sized
if (SDValue FPLogic = convertIntLogicToFPLogic(N, DAG, Subtarget))
return FPLogic;
+ if (SDValue R = combineANDXORWithAllOnesIntoANDNP(N, DAG))
+ return R;
+
EVT VT = N->getValueType(0);
SDValue N0 = N->getOperand(0);
SDValue N1 = N->getOperand(1);
// Create BEXTR instructions
// BEXTR is ((X >> imm) & (2**size-1))
- if (VT == MVT::i32 || VT == MVT::i64) {
- // Check for BEXTR.
- if ((Subtarget.hasBMI() || Subtarget.hasTBM()) &&
- (N0.getOpcode() == ISD::SRA || N0.getOpcode() == ISD::SRL)) {
- ConstantSDNode *MaskNode = dyn_cast<ConstantSDNode>(N1);
- ConstantSDNode *ShiftNode = dyn_cast<ConstantSDNode>(N0.getOperand(1));
- if (MaskNode && ShiftNode) {
- uint64_t Mask = MaskNode->getZExtValue();
- uint64_t Shift = ShiftNode->getZExtValue();
- if (isMask_64(Mask)) {
- uint64_t MaskSize = countPopulation(Mask);
- if (Shift + MaskSize <= VT.getSizeInBits())
- return DAG.getNode(X86ISD::BEXTR, DL, VT, N0.getOperand(0),
- DAG.getConstant(Shift | (MaskSize << 8), DL,
- VT));
- }
- }
- } // BEXTR
-
+ if (VT != MVT::i32 && VT != MVT::i64)
return SDValue();
- }
- // Want to form ANDNP nodes:
- // 1) In the hopes of then easily combining them with OR and AND nodes
- // to form PBLEND/PSIGN.
- // 2) To match ANDN packed intrinsics
- if (VT != MVT::v2i64 && VT != MVT::v4i64)
+ if (!Subtarget.hasBMI() && !Subtarget.hasTBM())
+ return SDValue();
+ if (N0.getOpcode() != ISD::SRA && N0.getOpcode() != ISD::SRL)
return SDValue();
- // Check LHS for vnot
- if (N0.getOpcode() == ISD::XOR &&
- //ISD::isBuildVectorAllOnes(N0.getOperand(1).getNode()))
- CanFoldXORWithAllOnes(N0.getOperand(1).getNode()))
- return DAG.getNode(X86ISD::ANDNP, DL, VT, N0.getOperand(0), N1);
-
- // Check RHS for vnot
- if (N1.getOpcode() == ISD::XOR &&
- //ISD::isBuildVectorAllOnes(N1.getOperand(1).getNode()))
- CanFoldXORWithAllOnes(N1.getOperand(1).getNode()))
- return DAG.getNode(X86ISD::ANDNP, DL, VT, N1.getOperand(0), N0);
-
+ ConstantSDNode *MaskNode = dyn_cast<ConstantSDNode>(N1);
+ ConstantSDNode *ShiftNode = dyn_cast<ConstantSDNode>(N0.getOperand(1));
+ if (MaskNode && ShiftNode) {
+ uint64_t Mask = MaskNode->getZExtValue();
+ uint64_t Shift = ShiftNode->getZExtValue();
+ if (isMask_64(Mask)) {
+ uint64_t MaskSize = countPopulation(Mask);
+ if (Shift + MaskSize <= VT.getSizeInBits())
+ return DAG.getNode(X86ISD::BEXTR, DL, VT, N0.getOperand(0),
+ DAG.getConstant(Shift | (MaskSize << 8), DL,
+ VT));
+ }
+ }
return SDValue();
}