@@ -7498,6 +7498,69 @@ SDValue DAGCombiner::visitAND(SDNode *N) {
74987498 if (SDValue NewSel = foldBinOpIntoSelect(N))
74997499 return NewSel;
75007500
7501+ // Optimize (Constant XOR a) & b & ~c -> (Constant XOR a) & (b & ~c)
7502+ // This allows the andn operation to be done in parallel with the xor
7503+ if (TLI.hasAndNot(N1) || TLI.hasAndNot(N0)) {
7504+ // Look for pattern: AND(AND(XOR(Constant, a), b), NOT(c))
7505+ // Transform to: AND(XOR(Constant, a), AND(b, NOT(c)))
7506+
7507+ // Handle both operand orders: N0=AND, N1=NOT and N0=NOT, N1=AND
7508+ SDValue AndOp, NotOp;
7509+ if (N0.getOpcode() == ISD::AND &&
7510+ N1.getOpcode() == ISD::XOR &&
7511+ DAG.isConstantIntBuildVectorOrConstantInt(N1.getOperand(1)) &&
7512+ isAllOnesConstant(N1.getOperand(1))) {
7513+ AndOp = N0;
7514+ NotOp = N1;
7515+ } else if (N1.getOpcode() == ISD::AND &&
7516+ N0.getOpcode() == ISD::XOR &&
7517+ DAG.isConstantIntBuildVectorOrConstantInt(N0.getOperand(1)) &&
7518+ isAllOnesConstant(N0.getOperand(1))) {
7519+ AndOp = N1;
7520+ NotOp = N0;
7521+ } else {
7522+ goto skip_optimization;
7523+ }
7524+
7525+ // Prevent infinite loops: only apply if the AND node has one use
7526+ if (!AndOp.hasOneUse())
7527+ goto skip_optimization;
7528+
7529+ SDValue AndOp0 = AndOp.getOperand(0);
7530+ SDValue AndOp1 = AndOp.getOperand(1);
7531+
7532+ // Check if one operand of AndOp is XOR(Constant, a)
7533+ SDValue XorOp, OtherOp;
7534+ if (AndOp0.getOpcode() == ISD::XOR) {
7535+ XorOp = AndOp0;
7536+ OtherOp = AndOp1;
7537+ } else if (AndOp1.getOpcode() == ISD::XOR) {
7538+ XorOp = AndOp1;
7539+ OtherOp = AndOp0;
7540+ } else {
7541+ goto skip_optimization;
7542+ }
7543+
7544+ // Check if XOR has a constant operand (and not all-ones constant to avoid NOT)
7545+ if ((DAG.isConstantIntBuildVectorOrConstantInt(XorOp.getOperand(0)) &&
7546+ !isAllOnesConstant(XorOp.getOperand(0))) ||
7547+ (DAG.isConstantIntBuildVectorOrConstantInt(XorOp.getOperand(1)) &&
7548+ !isAllOnesConstant(XorOp.getOperand(1)))) {
7549+ // Prevent infinite loops: only apply if OtherOp is not also a NOT
7550+ if (OtherOp.getOpcode() == ISD::XOR &&
7551+ DAG.isConstantIntBuildVectorOrConstantInt(OtherOp.getOperand(1)) &&
7552+ isAllOnesConstant(OtherOp.getOperand(1))) {
7553+ goto skip_optimization;
7554+ }
7555+ // Transform: AND(AND(XOR(Constant, a), b), NOT(c))
7556+ // To: AND(XOR(Constant, a), AND(b, NOT(c)))
7557+ // This allows the andn (b & ~c) to be done in parallel with the xor
7558+ SDValue NewAnd = DAG.getNode(ISD::AND, DL, VT, OtherOp, NotOp);
7559+ return DAG.getNode(ISD::AND, DL, VT, XorOp, NewAnd);
7560+ }
7561+ }
7562+ skip_optimization:
7563+
75017564 // reassociate and
75027565 if (SDValue RAND = reassociateOps(ISD::AND, DL, N0, N1, N->getFlags()))
75037566 return RAND;
0 commit comments