Skip to content

Commit

Permalink
[AArch64] Use isKnownNonZero to optimize to cmn instead of cmp
Browse files Browse the repository at this point in the history
  • Loading branch information
AreaZR committed Jun 30, 2024
1 parent ecce392 commit 613c0ff
Show file tree
Hide file tree
Showing 4 changed files with 221 additions and 149 deletions.
51 changes: 42 additions & 9 deletions llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3396,9 +3396,11 @@ static bool isLegalArithImmed(uint64_t C) {
// So, finally, the only LLVM-native comparisons that don't mention C and V
// are SETEQ and SETNE. They're the only ones we can safely use CMN for in
// the absence of information about op2.
static bool isCMN(SDValue Op, ISD::CondCode CC) {
static bool isCMN(SDValue Op, SDValue CheckedVal, ISD::CondCode CC,
SelectionDAG &DAG) {
return Op.getOpcode() == ISD::SUB && isNullConstant(Op.getOperand(0)) &&
(CC == ISD::SETEQ || CC == ISD::SETNE);
(CC == ISD::SETEQ || CC == ISD::SETNE ||
DAG.isKnownNeverZero(CheckedVal));
}

static SDValue emitStrictFPComparison(SDValue LHS, SDValue RHS, const SDLoc &dl,
Expand Down Expand Up @@ -3443,15 +3445,27 @@ static SDValue emitComparison(SDValue LHS, SDValue RHS, ISD::CondCode CC,
// register to WZR/XZR if it ends up being unused.
unsigned Opcode = AArch64ISD::SUBS;

if (isCMN(RHS, CC)) {
if (isCMN(RHS, RHS.getOperand(1), CC, DAG)) {
// Can we combine a (CMP op1, (sub 0, op2) into a CMN instruction ?
Opcode = AArch64ISD::ADDS;
RHS = RHS.getOperand(1);
} else if (isCMN(LHS, CC)) {
} else if (isCMN(LHS, RHS, CC, DAG) &&
(!isUnsignedIntSetCC(CC) ||
isCMN(LHS, LHS.getOperand(1), CC, DAG))) {
// As we are looking for EQ/NE compares, the operands can be commuted ; can
// we combine a (CMP (sub 0, op1), op2) into a CMN instruction ?
// Not swapping operands, but negation requires inversion
CC = ISD::getSetCCSwappedOperands(CC);
Opcode = AArch64ISD::ADDS;
LHS = LHS.getOperand(1);
} else if (isCMN(LHS, LHS.getOperand(1), CC, DAG) &&
(!isUnsignedIntSetCC(CC) || isCMN(LHS, RHS, CC, DAG))) {
// As we are looking for EQ/NE compares, the operands can be commuted ; can
// we combine a (CMP (sub 0, op1), op2) into a CMN instruction ?
std::swap(LHS, RHS);
CC = ISD::getSetCCSwappedOperands(CC);
Opcode = AArch64ISD::ADDS;
RHS = RHS.getOperand(1);
} else if (isNullConstant(RHS) && !isUnsignedIntSetCC(CC)) {
if (LHS.getOpcode() == ISD::AND) {
// Similarly, (CMP (and X, Y), 0) can be implemented with a TST
Expand Down Expand Up @@ -3551,8 +3565,21 @@ static SDValue emitConditionalComparison(SDValue LHS, SDValue RHS,
}
} else if (RHS.getOpcode() == ISD::SUB) {
SDValue SubOp0 = RHS.getOperand(0);
if (isNullConstant(SubOp0) && (CC == ISD::SETEQ || CC == ISD::SETNE)) {
if (isNullConstant(SubOp0) && (CC == ISD::SETEQ || CC == ISD::SETNE ||
DAG.isKnownNeverZero(RHS.getOperand(1)))) {
// See emitComparison() on why we can only do this for SETEQ and SETNE.
Opcode = AArch64ISD::CCMN;
RHS = RHS.getOperand(1);
}
} else if (LHS.getOpcode() == ISD::SUB) {
SDValue SubOp0 = LHS.getOperand(0);
if (isNullConstant(SubOp0) &&
(CC == ISD::SETEQ || CC == ISD::SETNE ||
(DAG.isKnownNeverZero(LHS.getOperand(1)) &&
(!isUnsignedIntSetCC(CC) || DAG.isKnownNeverZero(RHS))))) {
// See emitComparison() on why we can only do this for SETEQ and SETNE.
std::swap(LHS, RHS);
CC = ISD::getSetCCSwappedOperands(CC);
Opcode = AArch64ISD::CCMN;
RHS = RHS.getOperand(1);
}
Expand Down Expand Up @@ -3871,10 +3898,16 @@ static SDValue getAArch64Cmp(SDValue LHS, SDValue RHS, ISD::CondCode CC,
// cmp w13, w12
// can be turned into:
// cmp w12, w11, lsl #1
if (!isa<ConstantSDNode>(RHS) || !isLegalArithImmed(RHS->getAsZExtVal())) {
SDValue TheLHS = isCMN(LHS, CC) ? LHS.getOperand(1) : LHS;

if (getCmpOperandFoldingProfit(TheLHS) > getCmpOperandFoldingProfit(RHS)) {
if (!isa<ConstantSDNode>(RHS) || (!isLegalArithImmed(RHS->getAsZExtVal()) &&
!isLegalArithImmed(-RHS->getAsZExtVal()))) {
SDValue TheLHS =
isCMN(LHS, LHS.getOperand(1), CC, DAG) ? LHS.getOperand(1) : LHS;
SDValue TheRHS =
(!isa<ConstantSDNode>(RHS) && isCMN(RHS, RHS.getOperand(1), CC, DAG))
? RHS.getOperand(1)
: RHS;
if (getCmpOperandFoldingProfit(TheLHS) >
getCmpOperandFoldingProfit(TheRHS)) {
std::swap(LHS, RHS);
CC = ISD::getSetCCSwappedOperands(CC);
}
Expand Down
3 changes: 1 addition & 2 deletions llvm/test/CodeGen/AArch64/cmp-chains.ll
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,7 @@ define i32 @neg_range_int_cmn(i32 %a, i32 %b, i32 %c) {
; SDISEL-LABEL: neg_range_int_cmn:
; SDISEL: // %bb.0:
; SDISEL-NEXT: orr w8, w2, #0x1
; SDISEL-NEXT: neg w8, w8
; SDISEL-NEXT: cmp w8, w0
; SDISEL-NEXT: cmn w0, w8
; SDISEL-NEXT: ccmn w1, #3, #0, le
; SDISEL-NEXT: csel w0, w1, w0, gt
; SDISEL-NEXT: ret
Expand Down
3 changes: 1 addition & 2 deletions llvm/test/CodeGen/AArch64/cmp-select-sign.ll
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,7 @@ define i32 @or_neg(i32 %x, i32 %y) {
; CHECK-LABEL: or_neg:
; CHECK: // %bb.0:
; CHECK-NEXT: orr w8, w0, #0x1
; CHECK-NEXT: neg w8, w8
; CHECK-NEXT: cmp w8, w1
; CHECK-NEXT: cmn w1, w8
; CHECK-NEXT: cset w0, gt
; CHECK-NEXT: ret
%3 = or i32 %x, 1
Expand Down
Loading

0 comments on commit 613c0ff

Please sign in to comment.