Skip to content

Commit b176fd6

Browse files
committed
Move constant XOR AND ANDNOT optimization to generic DAG combiner
This moves the optimization from X86-specific code to the generic reassociateOpsCommutative function in DAGCombiner.cpp. The optimization transforms (Constant XOR a) & b & ~c -> (Constant XOR a) & (b & ~c) to allow ANDNOT operations to be done in parallel with XOR operations. This benefits all targets that have ANDNOT instructions (X86 BMI, ARM BIC, RISC-V, etc.) rather than being limited to X86 only. - Remove X86-specific combineConstantXorAndAndNot function - Add generic optimization to reassociateOpsCommutative with TLI.hasAndNot check - Update test expectations for the new optimized output
1 parent af5dcb5 commit b176fd6

File tree

3 files changed

+37
-64
lines changed

3 files changed

+37
-64
lines changed

llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,6 +1262,41 @@ SDValue DAGCombiner::reassociateOpsCommutative(unsigned Opc, const SDLoc &DL,
12621262
if (N1 == N00 || N1 == N01)
12631263
return N0;
12641264
}
1265+
1266+
// Optimize (Constant XOR a) & b & ~c -> (Constant XOR a) & (b & ~c)
1267+
// This allows the andn operation to be done in parallel with the xor
1268+
if (Opc == ISD::AND && TLI.hasAndNot(N1)) {
1269+
// Look for pattern: AND(AND(XOR(Constant, a), b), NOT(c))
1270+
// Transform to: AND(XOR(Constant, a), AND(b, NOT(c)))
1271+
1272+
// Check if N1 is NOT(c) - i.e., XOR(c, -1)
1273+
if (N1.getOpcode() == ISD::XOR &&
1274+
DAG.isConstantIntBuildVectorOrConstantInt(N1.getOperand(1)) &&
1275+
isAllOnesConstant(N1.getOperand(1))) {
1276+
1277+
// Check if one operand of N0 is XOR(Constant, a)
1278+
SDValue XorOp, OtherOp;
1279+
if (N00.getOpcode() == ISD::XOR) {
1280+
XorOp = N00;
1281+
OtherOp = N01;
1282+
} else if (N01.getOpcode() == ISD::XOR) {
1283+
XorOp = N01;
1284+
OtherOp = N00;
1285+
} else {
1286+
return SDValue();
1287+
}
1288+
1289+
// Check if XOR has a constant operand
1290+
if (DAG.isConstantIntBuildVectorOrConstantInt(XorOp.getOperand(0)) ||
1291+
DAG.isConstantIntBuildVectorOrConstantInt(XorOp.getOperand(1))) {
1292+
// Transform: AND(AND(XOR(Constant, a), b), NOT(c))
1293+
// To: AND(XOR(Constant, a), AND(b, NOT(c)))
1294+
// This allows the andn (b & ~c) to be done in parallel with the xor
1295+
SDValue NewAnd = DAG.getNode(ISD::AND, DL, VT, OtherOp, N1);
1296+
return DAG.getNode(ISD::AND, DL, VT, XorOp, NewAnd);
1297+
}
1298+
}
1299+
}
12651300
if (Opc == ISD::XOR) {
12661301
// (N00 ^ N01) ^ N00 --> N01
12671302
if (N1 == N00)

llvm/lib/Target/X86/X86ISelLowering.cpp

Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -51541,63 +51541,6 @@ 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-
}
5160151544

5160251545
/// Fold AND(Y, XOR(X, NEG(X))) -> ANDN(Y, BLSMSK(X)) if BMI is available.
5160351546
static SDValue combineAndXorSubWithBMI(SDNode *And, const SDLoc &DL,
@@ -51891,11 +51834,6 @@ static SDValue combineAnd(SDNode *N, SelectionDAG &DAG,
5189151834
if (SDValue R = combineAndNotOrIntoAndNotAnd(N, dl, DAG))
5189251835
return R;
5189351836

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-
5189951837
// fold (and (mul x, c1), c2) -> (mul x, (and c1, c2))
5190051838
// iff c2 is all/no bits mask - i.e. a select-with-zero mask.
5190151839
// TODO: Handle PMULDQ/PMULUDQ/VPMADDWD/VPMADDUBSW?

llvm/test/CodeGen/X86/constant-xor-and-andnot.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ define i64 @test_constant_xor_and_andnot_final_swapped(i64 %a, i64 %b, i64 %c) {
5252
; CHECK-LABEL: test_constant_xor_and_andnot_final_swapped:
5353
; CHECK: # %bb.0:
5454
; CHECK-NEXT: xorq $1234, %rdi # imm = 0x4D2
55-
; CHECK-NEXT: andq %rsi, %rdi
56-
; CHECK-NEXT: andnq %rdi, %rdx, %rax
55+
; CHECK-NEXT: andnq %rsi, %rdx, %rax
56+
; CHECK-NEXT: andq %rdi, %rax
5757
; CHECK-NEXT: retq
5858
%xor = xor i64 %a, 1234
5959
%and1 = and i64 %xor, %b

0 commit comments

Comments
 (0)