@@ -615,6 +615,59 @@ SDValue LoongArchTargetLowering::LowerOperation(SDValue Op,
615615 return SDValue ();
616616}
617617
618+ // Helper to attempt to return a cheaper, bit-inverted version of \p V.
619+ static SDValue isNOT (SDValue V, SelectionDAG &DAG) {
620+ // TODO: don't always ignore oneuse constraints.
621+ V = peekThroughBitcasts (V);
622+ EVT VT = V.getValueType ();
623+
624+ // Match not(xor X, -1) -> X.
625+ if (V.getOpcode () == ISD::XOR &&
626+ (ISD::isBuildVectorAllOnes (V.getOperand (1 ).getNode ()) ||
627+ isAllOnesConstant (V.getOperand (1 ))))
628+ return V.getOperand (0 );
629+
630+ // Match not(extract_subvector(not(X)) -> extract_subvector(X).
631+ if (V.getOpcode () == ISD::EXTRACT_SUBVECTOR &&
632+ (isNullConstant (V.getOperand (1 )) || V.getOperand (0 ).hasOneUse ())) {
633+ if (SDValue Not = isNOT (V.getOperand (0 ), DAG)) {
634+ Not = DAG.getBitcast (V.getOperand (0 ).getValueType (), Not);
635+ return DAG.getNode (ISD::EXTRACT_SUBVECTOR, SDLoc (Not), VT, Not,
636+ V.getOperand (1 ));
637+ }
638+ }
639+
640+ // Match not(SplatVector(not(X)) -> SplatVector(X).
641+ if (V.getOpcode () == ISD::BUILD_VECTOR) {
642+ if (SDValue SplatValue =
643+ cast<BuildVectorSDNode>(V.getNode ())->getSplatValue ()) {
644+ if (!V->isOnlyUserOf (SplatValue.getNode ()))
645+ return SDValue ();
646+
647+ if (SDValue Not = isNOT (SplatValue, DAG)) {
648+ Not = DAG.getBitcast (V.getOperand (0 ).getValueType (), Not);
649+ return DAG.getSplat (VT, SDLoc (Not), Not);
650+ }
651+ }
652+ }
653+
654+ // Match not(or(not(X),not(Y))) -> and(X, Y).
655+ if (V.getOpcode () == ISD::OR && DAG.getTargetLoweringInfo ().isTypeLegal (VT) &&
656+ V.getOperand (0 ).hasOneUse () && V.getOperand (1 ).hasOneUse ()) {
657+ // TODO: Handle cases with single NOT operand -> VANDN
658+ if (SDValue Op1 = isNOT (V.getOperand (1 ), DAG))
659+ if (SDValue Op0 = isNOT (V.getOperand (0 ), DAG))
660+ return DAG.getNode (ISD::AND, SDLoc (V), VT, DAG.getBitcast (VT, Op0),
661+ DAG.getBitcast (VT, Op1));
662+ }
663+
664+ // TODO: Add more matching patterns. Such as,
665+ // not(concat_vectors(not(X), not(Y))) -> concat_vectors(X, Y).
666+ // not(slt(C, X)) -> slt(X - 1, C)
667+
668+ return SDValue ();
669+ }
670+
618671SDValue LoongArchTargetLowering::lowerConstantFP (SDValue Op,
619672 SelectionDAG &DAG) const {
620673 EVT VT = Op.getValueType ();
@@ -5057,6 +5110,33 @@ void LoongArchTargetLowering::ReplaceNodeResults(
50575110 }
50585111}
50595112
5113+ // / Try to fold: (and (xor X, -1), Y) -> (vandn X, Y).
5114+ static SDValue combineAndNotIntoVANDN (SDNode *N, const SDLoc &DL,
5115+ SelectionDAG &DAG) {
5116+ assert (N->getOpcode () == ISD::AND && " Unexpected opcode combine into ANDN" );
5117+
5118+ MVT VT = N->getSimpleValueType (0 );
5119+ if (!VT.is128BitVector () && !VT.is256BitVector ())
5120+ return SDValue ();
5121+
5122+ SDValue X, Y;
5123+ SDValue N0 = N->getOperand (0 );
5124+ SDValue N1 = N->getOperand (1 );
5125+
5126+ if (SDValue Not = isNOT (N0, DAG)) {
5127+ X = Not;
5128+ Y = N1;
5129+ } else if (SDValue Not = isNOT (N1, DAG)) {
5130+ X = Not;
5131+ Y = N0;
5132+ } else
5133+ return SDValue ();
5134+
5135+ X = DAG.getBitcast (VT, X);
5136+ Y = DAG.getBitcast (VT, Y);
5137+ return DAG.getNode (LoongArchISD::VANDN, DL, VT, X, Y);
5138+ }
5139+
50605140static SDValue performANDCombine (SDNode *N, SelectionDAG &DAG,
50615141 TargetLowering::DAGCombinerInfo &DCI,
50625142 const LoongArchSubtarget &Subtarget) {
@@ -5074,6 +5154,9 @@ static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG,
50745154 SDValue NewOperand;
50755155 MVT GRLenVT = Subtarget.getGRLenVT ();
50765156
5157+ if (SDValue R = combineAndNotIntoVANDN (N, DL, DAG))
5158+ return R;
5159+
50775160 // BSTRPICK requires the 32S feature.
50785161 if (!Subtarget.has32S ())
50795162 return SDValue ();
@@ -6751,6 +6834,69 @@ performEXTRACT_VECTOR_ELTCombine(SDNode *N, SelectionDAG &DAG,
67516834 return SDValue ();
67526835}
67536836
6837+ // / Do target-specific dag combines on LoongArchISD::VANDN nodes.
6838+ static SDValue performVANDNCombine (SDNode *N, SelectionDAG &DAG,
6839+ TargetLowering::DAGCombinerInfo &DCI,
6840+ const LoongArchSubtarget &Subtarget) {
6841+ SDValue N0 = N->getOperand (0 );
6842+ SDValue N1 = N->getOperand (1 );
6843+ MVT VT = N->getSimpleValueType (0 );
6844+ SDLoc DL (N);
6845+
6846+ // VANDN(undef, x) -> 0
6847+ // VANDN(x, undef) -> 0
6848+ if (N0.isUndef () || N1.isUndef ())
6849+ return DAG.getConstant (0 , DL, VT);
6850+
6851+ // VANDN(0, x) -> x
6852+ if (ISD::isBuildVectorAllZeros (N0.getNode ()))
6853+ return N1;
6854+
6855+ // VANDN(x, 0) -> 0
6856+ if (ISD::isBuildVectorAllZeros (N1.getNode ()))
6857+ return DAG.getConstant (0 , DL, VT);
6858+
6859+ // VANDN(x, -1) -> NOT(x) -> XOR(x, -1)
6860+ if (ISD::isBuildVectorAllOnes (N1.getNode ()))
6861+ return DAG.getNOT (DL, N0, VT);
6862+
6863+ // Turn VANDN back to AND if input is inverted.
6864+ if (SDValue Not = isNOT (N0, DAG))
6865+ return DAG.getNode (ISD::AND, DL, VT, DAG.getBitcast (VT, Not), N1);
6866+
6867+ // Folds for better commutativity:
6868+ if (N1->hasOneUse ()) {
6869+ // VANDN(x,NOT(y)) -> AND(NOT(x),NOT(y)) -> NOT(OR(X,Y)).
6870+ if (SDValue Not = isNOT (N1, DAG))
6871+ return DAG.getNOT (
6872+ DL, DAG.getNode (ISD::OR, DL, VT, N0, DAG.getBitcast (VT, Not)), VT);
6873+
6874+ // VANDN(x, SplatVector(Imm)) -> AND(NOT(x), NOT(SplatVector(~Imm)))
6875+ // -> NOT(OR(x, SplatVector(-Imm))
6876+ // Combination is performed only when VT is v16i8/v32i8, using `vnori.b` to
6877+ // gain benefits.
6878+ if (!DCI.isBeforeLegalizeOps () && (VT == MVT::v16i8 || VT == MVT::v32i8) &&
6879+ N1.getOpcode () == ISD::BUILD_VECTOR) {
6880+ if (SDValue SplatValue =
6881+ cast<BuildVectorSDNode>(N1.getNode ())->getSplatValue ()) {
6882+ if (!N1->isOnlyUserOf (SplatValue.getNode ()))
6883+ return SDValue ();
6884+
6885+ if (auto *C = dyn_cast<ConstantSDNode>(SplatValue)) {
6886+ uint8_t NCVal = static_cast <uint8_t >(~(C->getSExtValue ()));
6887+ SDValue Not =
6888+ DAG.getSplat (VT, DL, DAG.getTargetConstant (NCVal, DL, MVT::i8 ));
6889+ return DAG.getNOT (
6890+ DL, DAG.getNode (ISD::OR, DL, VT, N0, DAG.getBitcast (VT, Not)),
6891+ VT);
6892+ }
6893+ }
6894+ }
6895+ }
6896+
6897+ return SDValue ();
6898+ }
6899+
67546900SDValue LoongArchTargetLowering::PerformDAGCombine (SDNode *N,
67556901 DAGCombinerInfo &DCI) const {
67566902 SelectionDAG &DAG = DCI.DAG ;
@@ -6786,6 +6932,8 @@ SDValue LoongArchTargetLowering::PerformDAGCombine(SDNode *N,
67866932 return performSPLIT_PAIR_F64Combine (N, DAG, DCI, Subtarget);
67876933 case ISD::EXTRACT_VECTOR_ELT:
67886934 return performEXTRACT_VECTOR_ELTCombine (N, DAG, DCI, Subtarget);
6935+ case LoongArchISD::VANDN:
6936+ return performVANDNCombine (N, DAG, DCI, Subtarget);
67896937 }
67906938 return SDValue ();
67916939}
0 commit comments