@@ -51541,6 +51541,64 @@ static SDValue combineBMILogicOp(SDNode *N, SelectionDAG &DAG,
5154151541 return SDValue();
5154251542}
5154351543
51544+ /// Optimize (Constant XOR a) & b & ~c -> (Constant XOR a) & (b & ~c)
51545+ /// This allows the andn operation to be done in parallel with the xor
51546+ static SDValue combineConstantXorAndAndNot(SDNode *N, const SDLoc &DL,
51547+ SelectionDAG &DAG,
51548+ const X86Subtarget &Subtarget) {
51549+ using namespace llvm::SDPatternMatch;
51550+
51551+ EVT VT = N->getValueType(0);
51552+ // Only handle scalar integer types that support BMI instructions
51553+ if (!Subtarget.hasBMI() || (VT != MVT::i32 && VT != MVT::i64))
51554+ return SDValue();
51555+
51556+ SDValue N0 = N->getOperand(0);
51557+ SDValue N1 = N->getOperand(1);
51558+
51559+ // Check if N0 is AND(XOR(Constant, a), b)
51560+ if (N0.getOpcode() != ISD::AND)
51561+ return SDValue();
51562+
51563+ SDValue AndLHS = N0.getOperand(0);
51564+ SDValue AndRHS = N0.getOperand(1);
51565+
51566+ // Check if one operand is XOR(Constant, a)
51567+ SDValue XorOp, OtherOp;
51568+ if (AndLHS.getOpcode() == ISD::XOR) {
51569+ XorOp = AndLHS;
51570+ OtherOp = AndRHS;
51571+ } else if (AndRHS.getOpcode() == ISD::XOR) {
51572+ XorOp = AndRHS;
51573+ OtherOp = AndLHS;
51574+ } else {
51575+ return SDValue();
51576+ }
51577+
51578+ // Check if XOR has a constant operand
51579+ if (!isa<ConstantSDNode>(XorOp.getOperand(0)) &&
51580+ !isa<ConstantSDNode>(XorOp.getOperand(1))) {
51581+ return SDValue();
51582+ }
51583+
51584+ // Check if N1 is NOT(c) - i.e., XOR(c, -1)
51585+ SDValue NotOp;
51586+ if (N1.getOpcode() == ISD::XOR && isAllOnesConstant(N1.getOperand(1))) {
51587+ NotOp = N1.getOperand(0);
51588+ } else {
51589+ return SDValue();
51590+ }
51591+
51592+ // Transform: AND(AND(XOR(Constant, a), b), NOT(c))
51593+ // To: AND(XOR(Constant, a), AND(b, NOT(c)))
51594+ // This allows the andn (b & ~c) to be done in parallel with the xor
51595+
51596+ // Create AND(b, NOT(c)) - this will become andn
51597+ SDValue NewAnd = DAG.getNode(ISD::AND, DL, VT, OtherOp, N1);
51598+ // Create final AND(XOR(Constant, a), AND(b, NOT(c)))
51599+ return DAG.getNode(ISD::AND, DL, VT, XorOp, NewAnd);
51600+ }
51601+
5154451602/// Fold AND(Y, XOR(X, NEG(X))) -> ANDN(Y, BLSMSK(X)) if BMI is available.
5154551603static SDValue combineAndXorSubWithBMI(SDNode *And, const SDLoc &DL,
5154651604 SelectionDAG &DAG,
@@ -51833,6 +51891,11 @@ static SDValue combineAnd(SDNode *N, SelectionDAG &DAG,
5183351891 if (SDValue R = combineAndNotOrIntoAndNotAnd(N, dl, DAG))
5183451892 return R;
5183551893
51894+ // Optimize (Constant XOR a) & b & ~c -> (Constant XOR a) & (b & ~c)
51895+ // This allows the andn operation to be done in parallel with the xor
51896+ if (SDValue R = combineConstantXorAndAndNot(N, dl, DAG, Subtarget))
51897+ return R;
51898+
5183651899 // fold (and (mul x, c1), c2) -> (mul x, (and c1, c2))
5183751900 // iff c2 is all/no bits mask - i.e. a select-with-zero mask.
5183851901 // TODO: Handle PMULDQ/PMULUDQ/VPMADDWD/VPMADDUBSW?
0 commit comments