Skip to content

Commit 4a2e546

Browse files
committed
changed combiner logic to account for infinite loops
1 parent b176fd6 commit 4a2e546

File tree

1 file changed

+63
-0
lines changed

1 file changed

+63
-0
lines changed

llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)