[llvm] [AArch64] Factor in the possible cmn commute by emitComparison (PR #144234)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jun 27 10:00:32 PDT 2025
https://github.com/AZero13 updated https://github.com/llvm/llvm-project/pull/144234
>From 3b5745cb8a38569b4c2b041ecf3d9477677ff6cd Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Sat, 14 Jun 2025 13:40:14 -0400
Subject: [PATCH] [AArch64] Commute operands if the sign can be flipped
a > -b means -a > b, if -a and -b are not INT_MIN in the signed case, or 0 in the unsigned case.
---
.../Target/AArch64/AArch64ISelLowering.cpp | 32 +++++++++++++++++--
llvm/test/CodeGen/AArch64/cmp-to-cmn.ll | 8 ++---
2 files changed, 33 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index c8b1eafd35495..7a4afb5009d03 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -3409,7 +3409,23 @@ static bool isCMN(SDValue Op, ISD::CondCode CC, SelectionDAG &DAG) {
(isSignedIntSetCC(CC) && isSafeSignedCMN(Op, DAG)));
}
-static SDValue emitStrictFPComparison(SDValue LHS, SDValue RHS, const SDLoc &DL,
+static bool canBeCommutedToCMN(SDValue LHS, SDValue RHS, ISD::CondCode CC,
+ SelectionDAG &DAG) {
+
+ // Commuting cmn is based on the fact that adds is communative.
+ // cmn x1, x2 is the same as cmn x2, x1. In theory, this should work, but
+ // we have to realize that this is doing now: cmp x2, -x1, which means -x1 has
+ // to not be 0 if unsigned, or INT_MIN if signed. However, a > -b and -b > a
+ // works assuming no wrap.
+
+ return isCMN(LHS, CC, DAG) &&
+ (isIntEqualitySetCC(CC) ||
+ (isUnsignedIntSetCC(CC) && DAG.isKnownNeverZero(RHS)) ||
+ (isSignedIntSetCC(CC) &&
+ !DAG.computeKnownBits(RHS).getSignedMinValue().isMinSignedValue()));
+}
+
+static SDValue emitStrictFPComparison(SDValue LHS, SDValue RHS, const SDLoc &Dl,
SelectionDAG &DAG, SDValue Chain,
bool IsSignaling) {
EVT VT = LHS.getValueType();
@@ -3453,8 +3469,7 @@ static SDValue emitComparison(SDValue LHS, SDValue RHS, ISD::CondCode CC,
// Can we combine a (CMP op1, (sub 0, op2) into a CMN instruction ?
Opcode = AArch64ISD::ADDS;
RHS = RHS.getOperand(1);
- } else if (LHS.getOpcode() == ISD::SUB && isNullConstant(LHS.getOperand(0)) &&
- isIntEqualitySetCC(CC)) {
+ } else if (canBeCommutedToCMN(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 ?
Opcode = AArch64ISD::ADDS;
@@ -3909,6 +3924,17 @@ static SDValue getAArch64Cmp(SDValue LHS, SDValue RHS, ISD::CondCode CC,
SDValue TheLHS = LHSIsCMN ? LHS.getOperand(1) : LHS;
SDValue TheRHS = RHSIsCMN ? RHS.getOperand(1) : RHS;
+ // Do not count twice. If the CMN can be commuted, hence OR.
+ // TODO: Is it possible for us to choose between two CMN? If so,
+ // this should be changed to an add. This is an or because as far as I can
+ // tell, emitComparison only changes the subs to an adds and not back, so
+ // this reflects the fact There can be at most one removal of a neg
+ // instruction.
+
+ // So, do not count twice if the CMN can be commuted, hence OR.
+ LHSIsCMN |= canBeCommutedToCMN(RHS, LHS, CC, DAG);
+ RHSIsCMN |= canBeCommutedToCMN(LHS, RHS, CC, DAG);
+
if (getCmpOperandFoldingProfit(TheLHS) + (LHSIsCMN ? 1 : 0) >
getCmpOperandFoldingProfit(TheRHS) + (RHSIsCMN ? 1 : 0)) {
std::swap(LHS, RHS);
diff --git a/llvm/test/CodeGen/AArch64/cmp-to-cmn.ll b/llvm/test/CodeGen/AArch64/cmp-to-cmn.ll
index 5765e0acae269..73b7f5b6ebf8e 100644
--- a/llvm/test/CodeGen/AArch64/cmp-to-cmn.ll
+++ b/llvm/test/CodeGen/AArch64/cmp-to-cmn.ll
@@ -6,7 +6,7 @@ target triple = "arm64"
define i1 @test_EQ_IllEbT(i64 %a, i64 %b) {
; CHECK-LABEL: test_EQ_IllEbT:
; CHECK: // %bb.0: // %entry
-; CHECK-NEXT: cmn x0, x1
+; CHECK-NEXT: cmn x1, x0
; CHECK-NEXT: cset w0, eq
; CHECK-NEXT: ret
entry:
@@ -70,7 +70,7 @@ entry:
define i1 @test_EQ_IiiEbT(i32 %a, i32 %b) {
; CHECK-LABEL: test_EQ_IiiEbT:
; CHECK: // %bb.0: // %entry
-; CHECK-NEXT: cmn w0, w1
+; CHECK-NEXT: cmn w1, w0
; CHECK-NEXT: cset w0, eq
; CHECK-NEXT: ret
entry:
@@ -220,7 +220,7 @@ entry:
define i1 @test_NE_IllEbT(i64 %a, i64 %b) {
; CHECK-LABEL: test_NE_IllEbT:
; CHECK: // %bb.0: // %entry
-; CHECK-NEXT: cmn x0, x1
+; CHECK-NEXT: cmn x1, x0
; CHECK-NEXT: cset w0, ne
; CHECK-NEXT: ret
entry:
@@ -284,7 +284,7 @@ entry:
define i1 @test_NE_IiiEbT(i32 %a, i32 %b) {
; CHECK-LABEL: test_NE_IiiEbT:
; CHECK: // %bb.0: // %entry
-; CHECK-NEXT: cmn w0, w1
+; CHECK-NEXT: cmn w1, w0
; CHECK-NEXT: cset w0, ne
; CHECK-NEXT: ret
entry:
More information about the llvm-commits
mailing list