[llvm] [AArch64] Fold swapped sub/SUBS conditions (PR #121412)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 31 11:08:01 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-aarch64
Author: David Green (davemgreen)
<details>
<summary>Changes</summary>
This fold already exists in a couple places (DAG and CGP), where an icmps operands are swapped to allow CSE with a sub. They do not handle constants though. This patch adds an AArch64 version that can be more precise.
---
Full diff: https://github.com/llvm/llvm-project/pull/121412.diff
3 Files Affected:
- (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.cpp (+24)
- (modified) llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h (+30)
- (modified) llvm/test/CodeGen/AArch64/csel-subs-swapped.ll (+20-32)
``````````diff
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 24e1ebd8421fbf..970250d8fb766f 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -24854,6 +24854,30 @@ static SDValue performCSELCombine(SDNode *N,
if (SDValue Folded = foldCSELofCTTZ(N, DAG))
return Folded;
+ // CSEL a, b, cc, SUBS(x, y) -> CSEL a, b, swapped(cc), SUBS(y, x)
+ // if SUB(y, x) already exists and we can produce a swapped predicate for cc.
+ SDValue Cond = N->getOperand(3);
+ if (DCI.isAfterLegalizeDAG() && Cond.getOpcode() == AArch64ISD::SUBS &&
+ Cond.hasOneUse() && Cond->hasNUsesOfValue(0, 0) &&
+ DAG.doesNodeExist(ISD::SUB, N->getVTList(),
+ {Cond.getOperand(1), Cond.getOperand(0)}) &&
+ !DAG.doesNodeExist(ISD::SUB, N->getVTList(),
+ {Cond.getOperand(0), Cond.getOperand(1)}) &&
+ !isNullConstant(Cond.getOperand(1))) {
+ AArch64CC::CondCode OldCond =
+ static_cast<AArch64CC::CondCode>(N->getConstantOperandVal(2));
+ AArch64CC::CondCode NewCond = getSwappedCondition(OldCond);
+ if (NewCond != AArch64CC::AL) {
+ SDLoc DL(N);
+ SDValue Sub = DAG.getNode(AArch64ISD::SUBS, DL, Cond->getVTList(),
+ Cond.getOperand(1), Cond.getOperand(0));
+ return DAG.getNode(AArch64ISD::CSEL, DL, N->getVTList(), N->getOperand(0),
+ N->getOperand(1),
+ DAG.getConstant(NewCond, DL, MVT::i32),
+ Sub.getValue(1));
+ }
+ }
+
return performCONDCombine(N, DCI, DAG, 2, 3);
}
diff --git a/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h b/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h
index e0ccba4d6a59e8..39d83e61705f00 100644
--- a/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h
+++ b/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h
@@ -306,6 +306,36 @@ inline static CondCode getInvertedCondCode(CondCode Code) {
return static_cast<CondCode>(static_cast<unsigned>(Code) ^ 0x1);
}
+/// getSwappedCondition - assume the flags are set by MI(a,b), return
+/// the condition code if we modify the instructions such that flags are
+/// set by MI(b,a).
+inline static CondCode getSwappedCondition(CondCode CC) {
+ switch (CC) {
+ default:
+ return AL;
+ case EQ:
+ return EQ;
+ case NE:
+ return NE;
+ case HS:
+ return LS;
+ case LO:
+ return HI;
+ case HI:
+ return LO;
+ case LS:
+ return HS;
+ case GE:
+ return LE;
+ case LT:
+ return GT;
+ case GT:
+ return LT;
+ case LE:
+ return GE;
+ }
+}
+
/// Given a condition code, return NZCV flags that would satisfy that condition.
/// The flag bits are in the format expected by the ccmp instructions.
/// Note that many different flag settings can satisfy a given condition code,
diff --git a/llvm/test/CodeGen/AArch64/csel-subs-swapped.ll b/llvm/test/CodeGen/AArch64/csel-subs-swapped.ll
index 7c628cf1683d6f..3971da27cdddca 100644
--- a/llvm/test/CodeGen/AArch64/csel-subs-swapped.ll
+++ b/llvm/test/CodeGen/AArch64/csel-subs-swapped.ll
@@ -5,8 +5,7 @@ define i32 @eq_i32(i32 %x) {
; CHECK-LABEL: eq_i32:
; CHECK: // %bb.0:
; CHECK-NEXT: mov w8, #-2097152 // =0xffe00000
-; CHECK-NEXT: cmn w0, #512, lsl #12 // =2097152
-; CHECK-NEXT: sub w8, w8, w0
+; CHECK-NEXT: subs w8, w8, w0
; CHECK-NEXT: csel w0, w0, w8, eq
; CHECK-NEXT: ret
%cmp = icmp eq i32 %x, -2097152
@@ -19,8 +18,7 @@ define i32 @ne_i32(i32 %x) {
; CHECK-LABEL: ne_i32:
; CHECK: // %bb.0:
; CHECK-NEXT: mov w8, #-2097152 // =0xffe00000
-; CHECK-NEXT: cmn w0, #512, lsl #12 // =2097152
-; CHECK-NEXT: sub w8, w8, w0
+; CHECK-NEXT: subs w8, w8, w0
; CHECK-NEXT: csel w0, w0, w8, ne
; CHECK-NEXT: ret
%cmp = icmp ne i32 %x, -2097152
@@ -33,9 +31,8 @@ define i32 @sgt_i32(i32 %x) {
; CHECK-LABEL: sgt_i32:
; CHECK: // %bb.0:
; CHECK-NEXT: mov w8, #-2097152 // =0xffe00000
-; CHECK-NEXT: cmn w0, #512, lsl #12 // =2097152
-; CHECK-NEXT: sub w8, w8, w0
-; CHECK-NEXT: csel w0, w0, w8, gt
+; CHECK-NEXT: subs w8, w8, w0
+; CHECK-NEXT: csel w0, w0, w8, lt
; CHECK-NEXT: ret
%cmp = icmp sgt i32 %x, -2097152
%sub = sub i32 -2097152, %x
@@ -62,9 +59,8 @@ define i32 @slt_i32(i32 %x) {
; CHECK-LABEL: slt_i32:
; CHECK: // %bb.0:
; CHECK-NEXT: mov w8, #-2097152 // =0xffe00000
-; CHECK-NEXT: cmn w0, #512, lsl #12 // =2097152
-; CHECK-NEXT: sub w8, w8, w0
-; CHECK-NEXT: csel w0, w0, w8, lt
+; CHECK-NEXT: subs w8, w8, w0
+; CHECK-NEXT: csel w0, w0, w8, gt
; CHECK-NEXT: ret
%cmp = icmp slt i32 %x, -2097152
%sub = sub i32 -2097152, %x
@@ -91,9 +87,8 @@ define i32 @ugt_i32(i32 %x) {
; CHECK-LABEL: ugt_i32:
; CHECK: // %bb.0:
; CHECK-NEXT: mov w8, #-2097152 // =0xffe00000
-; CHECK-NEXT: cmn w0, #512, lsl #12 // =2097152
-; CHECK-NEXT: sub w8, w8, w0
-; CHECK-NEXT: csel w0, w0, w8, hi
+; CHECK-NEXT: subs w8, w8, w0
+; CHECK-NEXT: csel w0, w0, w8, lo
; CHECK-NEXT: ret
%cmp = icmp ugt i32 %x, -2097152
%sub = sub i32 -2097152, %x
@@ -120,9 +115,8 @@ define i32 @ult_i32(i32 %x) {
; CHECK-LABEL: ult_i32:
; CHECK: // %bb.0:
; CHECK-NEXT: mov w8, #-2097152 // =0xffe00000
-; CHECK-NEXT: cmn w0, #512, lsl #12 // =2097152
-; CHECK-NEXT: sub w8, w8, w0
-; CHECK-NEXT: csel w0, w0, w8, lo
+; CHECK-NEXT: subs w8, w8, w0
+; CHECK-NEXT: csel w0, w0, w8, hi
; CHECK-NEXT: ret
%cmp = icmp ult i32 %x, -2097152
%sub = sub i32 -2097152, %x
@@ -150,8 +144,7 @@ define i64 @eq_i64(i64 %x) {
; CHECK-LABEL: eq_i64:
; CHECK: // %bb.0:
; CHECK-NEXT: mov w8, #100 // =0x64
-; CHECK-NEXT: cmp x0, #100
-; CHECK-NEXT: sub x8, x8, x0
+; CHECK-NEXT: subs x8, x8, x0
; CHECK-NEXT: csel x0, x0, x8, eq
; CHECK-NEXT: ret
%cmp = icmp eq i64 %x, 100
@@ -164,8 +157,7 @@ define i64 @ne_i64(i64 %x) {
; CHECK-LABEL: ne_i64:
; CHECK: // %bb.0:
; CHECK-NEXT: mov w8, #100 // =0x64
-; CHECK-NEXT: cmp x0, #100
-; CHECK-NEXT: sub x8, x8, x0
+; CHECK-NEXT: subs x8, x8, x0
; CHECK-NEXT: csel x0, x0, x8, ne
; CHECK-NEXT: ret
%cmp = icmp ne i64 %x, 100
@@ -178,9 +170,8 @@ define i64 @sgt_i64(i64 %x) {
; CHECK-LABEL: sgt_i64:
; CHECK: // %bb.0:
; CHECK-NEXT: mov w8, #100 // =0x64
-; CHECK-NEXT: cmp x0, #100
-; CHECK-NEXT: sub x8, x8, x0
-; CHECK-NEXT: csel x0, x0, x8, gt
+; CHECK-NEXT: subs x8, x8, x0
+; CHECK-NEXT: csel x0, x0, x8, lt
; CHECK-NEXT: ret
%cmp = icmp sgt i64 %x, 100
%sub = sub i64 100, %x
@@ -206,9 +197,8 @@ define i64 @slt_i64(i64 %x) {
; CHECK-LABEL: slt_i64:
; CHECK: // %bb.0:
; CHECK-NEXT: mov w8, #100 // =0x64
-; CHECK-NEXT: cmp x0, #100
-; CHECK-NEXT: sub x8, x8, x0
-; CHECK-NEXT: csel x0, x0, x8, lt
+; CHECK-NEXT: subs x8, x8, x0
+; CHECK-NEXT: csel x0, x0, x8, gt
; CHECK-NEXT: ret
%cmp = icmp slt i64 %x, 100
%sub = sub i64 100, %x
@@ -234,9 +224,8 @@ define i64 @ugt_i64(i64 %x) {
; CHECK-LABEL: ugt_i64:
; CHECK: // %bb.0:
; CHECK-NEXT: mov w8, #100 // =0x64
-; CHECK-NEXT: cmp x0, #100
-; CHECK-NEXT: sub x8, x8, x0
-; CHECK-NEXT: csel x0, x0, x8, hi
+; CHECK-NEXT: subs x8, x8, x0
+; CHECK-NEXT: csel x0, x0, x8, lo
; CHECK-NEXT: ret
%cmp = icmp ugt i64 %x, 100
%sub = sub i64 100, %x
@@ -262,9 +251,8 @@ define i64 @ult_i64(i64 %x) {
; CHECK-LABEL: ult_i64:
; CHECK: // %bb.0:
; CHECK-NEXT: mov w8, #100 // =0x64
-; CHECK-NEXT: cmp x0, #100
-; CHECK-NEXT: sub x8, x8, x0
-; CHECK-NEXT: csel x0, x0, x8, lo
+; CHECK-NEXT: subs x8, x8, x0
+; CHECK-NEXT: csel x0, x0, x8, hi
; CHECK-NEXT: ret
%cmp = icmp ult i64 %x, 100
%sub = sub i64 100, %x
``````````
</details>
https://github.com/llvm/llvm-project/pull/121412
More information about the llvm-commits
mailing list