Skip to content

Commit c22364a

Browse files
authored
[AArch64] Eliminate Common SUBS by Reassociating Non-Constants (#123344)
Commit 1eed469 added logic to reassociate a (add (add x y) -c) operand to a CSEL instruction with a comparison involving x and c (or a similar constant) in order to obtain a common (SUBS x c) instruction. This commit extends this logic to non-constants. In this way, we also reassociate a (sub (add x y) z) operand of a CSEL instruction to (add (sub x z) y) if the CSEL compares x and z, for example. Alive proof: https://alive2.llvm.org/ce/z/SEVpR
1 parent 4740e09 commit c22364a

File tree

2 files changed

+418
-32
lines changed

2 files changed

+418
-32
lines changed

llvm/lib/Target/AArch64/AArch64ISelLowering.cpp

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24899,16 +24899,31 @@ static SDValue reassociateCSELOperandsForCSE(SDNode *N, SelectionDAG &DAG) {
2489924899
SDValue SubsNode = N->getOperand(3);
2490024900
if (SubsNode.getOpcode() != AArch64ISD::SUBS || !SubsNode.hasOneUse())
2490124901
return SDValue();
24902-
auto *CmpOpConst = dyn_cast<ConstantSDNode>(SubsNode.getOperand(1));
24903-
if (!CmpOpConst)
24904-
return SDValue();
2490524902

24903+
SDValue CmpOpToMatch = SubsNode.getOperand(1);
2490624904
SDValue CmpOpOther = SubsNode.getOperand(0);
2490724905
EVT VT = N->getValueType(0);
2490824906

24907+
unsigned ExpectedOpcode;
24908+
SDValue ExpectedOp;
24909+
SDValue SubsOp;
24910+
auto *CmpOpConst = dyn_cast<ConstantSDNode>(CmpOpToMatch);
24911+
if (CmpOpConst) {
24912+
ExpectedOpcode = ISD::ADD;
24913+
ExpectedOp =
24914+
DAG.getConstant(-CmpOpConst->getAPIntValue(), SDLoc(CmpOpConst),
24915+
CmpOpConst->getValueType(0));
24916+
SubsOp = DAG.getConstant(CmpOpConst->getAPIntValue(), SDLoc(CmpOpConst),
24917+
CmpOpConst->getValueType(0));
24918+
} else {
24919+
ExpectedOpcode = ISD::SUB;
24920+
ExpectedOp = CmpOpToMatch;
24921+
SubsOp = CmpOpToMatch;
24922+
}
24923+
2490924924
// Get the operand that can be reassociated with the SUBS instruction.
24910-
auto GetReassociationOp = [&](SDValue Op, APInt ExpectedConst) {
24911-
if (Op.getOpcode() != ISD::ADD)
24925+
auto GetReassociationOp = [&](SDValue Op, SDValue ExpectedOp) {
24926+
if (Op.getOpcode() != ExpectedOpcode)
2491224927
return SDValue();
2491324928
if (Op.getOperand(0).getOpcode() != ISD::ADD ||
2491424929
!Op.getOperand(0).hasOneUse())
@@ -24919,24 +24934,21 @@ static SDValue reassociateCSELOperandsForCSE(SDNode *N, SelectionDAG &DAG) {
2491924934
std::swap(X, Y);
2492024935
if (X != CmpOpOther)
2492124936
return SDValue();
24922-
auto *AddOpConst = dyn_cast<ConstantSDNode>(Op.getOperand(1));
24923-
if (!AddOpConst || AddOpConst->getAPIntValue() != ExpectedConst)
24937+
if (ExpectedOp != Op.getOperand(1))
2492424938
return SDValue();
2492524939
return Y;
2492624940
};
2492724941

2492824942
// Try the reassociation using the given constant and condition code.
24929-
auto Fold = [&](APInt NewCmpConst, AArch64CC::CondCode NewCC) {
24930-
APInt ExpectedConst = -NewCmpConst;
24931-
SDValue TReassocOp = GetReassociationOp(N->getOperand(0), ExpectedConst);
24932-
SDValue FReassocOp = GetReassociationOp(N->getOperand(1), ExpectedConst);
24943+
auto Fold = [&](AArch64CC::CondCode NewCC, SDValue ExpectedOp,
24944+
SDValue SubsOp) {
24945+
SDValue TReassocOp = GetReassociationOp(N->getOperand(0), ExpectedOp);
24946+
SDValue FReassocOp = GetReassociationOp(N->getOperand(1), ExpectedOp);
2493324947
if (!TReassocOp && !FReassocOp)
2493424948
return SDValue();
2493524949

2493624950
SDValue NewCmp = DAG.getNode(AArch64ISD::SUBS, SDLoc(SubsNode),
24937-
DAG.getVTList(VT, MVT_CC), CmpOpOther,
24938-
DAG.getConstant(NewCmpConst, SDLoc(CmpOpConst),
24939-
CmpOpConst->getValueType(0)));
24951+
DAG.getVTList(VT, MVT_CC), CmpOpOther, SubsOp);
2494024952

2494124953
auto Reassociate = [&](SDValue ReassocOp, unsigned OpNum) {
2494224954
if (!ReassocOp)
@@ -24958,9 +24970,19 @@ static SDValue reassociateCSELOperandsForCSE(SDNode *N, SelectionDAG &DAG) {
2495824970

2495924971
// First, try to eliminate the compare instruction by searching for a
2496024972
// subtraction with the same constant.
24961-
if (SDValue R = Fold(CmpOpConst->getAPIntValue(), CC))
24973+
if (SDValue R = Fold(CC, ExpectedOp, SubsOp))
2496224974
return R;
2496324975

24976+
if (!CmpOpConst) {
24977+
// Try again with the operands of the SUBS instruction and the condition
24978+
// swapped. Due to canonicalization, this only helps for non-constant
24979+
// operands of the SUBS instruction.
24980+
std::swap(CmpOpToMatch, CmpOpOther);
24981+
if (SDValue R = Fold(getSwappedCondition(CC), CmpOpToMatch, CmpOpToMatch))
24982+
return R;
24983+
return SDValue();
24984+
}
24985+
2496424986
if ((CC == AArch64CC::EQ || CC == AArch64CC::NE) && !CmpOpConst->isZero())
2496524987
return SDValue();
2496624988

@@ -24972,7 +24994,11 @@ static SDValue reassociateCSELOperandsForCSE(SDNode *N, SelectionDAG &DAG) {
2497224994
// them here but check for them nevertheless to be on the safe side.
2497324995
auto CheckedFold = [&](bool Check, APInt NewCmpConst,
2497424996
AArch64CC::CondCode NewCC) {
24975-
return Check ? Fold(NewCmpConst, NewCC) : SDValue();
24997+
auto ExpectedOp = DAG.getConstant(-NewCmpConst, SDLoc(CmpOpConst),
24998+
CmpOpConst->getValueType(0));
24999+
auto SubsOp = DAG.getConstant(NewCmpConst, SDLoc(CmpOpConst),
25000+
CmpOpConst->getValueType(0));
25001+
return Check ? Fold(NewCC, ExpectedOp, SubsOp) : SDValue();
2497625002
};
2497725003
switch (CC) {
2497825004
case AArch64CC::EQ:

0 commit comments

Comments
 (0)