Skip to content

[AArch64] Snap 32 and -32 to 31 and -31 if possible for ccmp and ccmn #144166

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

AZero13
Copy link
Contributor

@AZero13 AZero13 commented Jun 13, 2025

This lets us encode the immediate in the instruction.

@llvmbot
Copy link
Member

llvmbot commented Jun 13, 2025

@llvm/pr-subscribers-backend-aarch64

Author: AZero13 (AZero13)

Changes

This lets us encode the immediate in the instruction.


Full diff: https://github.com/llvm/llvm-project/pull/144166.diff

2 Files Affected:

  • (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.cpp (+49)
  • (modified) llvm/test/CodeGen/AArch64/cmp-chains.ll (+44)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 7519ac5260a64..f4935d0acbac0 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -3716,6 +3716,55 @@ static SDValue emitConjunctionRec(SelectionDAG &DAG, SDValue Val,
     // Produce a normal comparison if we are first in the chain
     if (!CCOp)
       return emitComparison(LHS, RHS, CC, DL, DAG);
+
+    if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(RHS.getNode())) {
+      EVT VT = RHS.getValueType();
+      APInt C = RHSC->getAPIntValue();
+      // shouldBeAdjustedToZero is a special case to better fold with
+      // emitComparison().
+      if (C.getZExtValue() == 32 && (CC == ISD::SETLT || CC == ISD::SETGE ||
+                                     CC == ISD::SETULT || CC == ISD::SETUGE)) {
+        switch (CC) {
+        case ISD::SETLT:
+          CC = ISD::SETLE;
+          break;
+        case ISD::SETGE:
+          CC = ISD::SETGT;
+          break;
+        case ISD::SETULT:
+          CC = ISD::SETULE;
+          break;
+        case ISD::SETUGE:
+          CC = ISD::SETUGT;
+          break;
+        default:
+          llvm_unreachable("Should not happen");
+        }
+        RHS = DAG.getConstant(31, DL, VT);
+        OutCC = changeIntCCToAArch64CC(CC);
+      } else if (C.getSExtValue() == -32 &&
+                 (CC == ISD::SETLE || CC == ISD::SETGT || CC == ISD::SETULE ||
+                  CC == ISD::SETUGT)) {
+        switch (CC) {
+        case ISD::SETLE:
+          CC = ISD::SETLT;
+          break;
+        case ISD::SETGT:
+          CC = ISD::SETGE;
+          break;
+        case ISD::SETULE:
+          CC = ISD::SETULT;
+          break;
+        case ISD::SETUGT:
+          CC = ISD::SETUGE;
+          break;
+        default:
+          llvm_unreachable("Should not happen");
+        }
+        RHS = DAG.getConstant((C + 1).getZExtValue(), DL, VT); // -31
+        OutCC = changeIntCCToAArch64CC(CC);
+      }
+    }
     // Otherwise produce a ccmp.
     return emitConditionalComparison(LHS, RHS, CC, CCOp, Predicate, OutCC, DL,
                                      DAG);
diff --git a/llvm/test/CodeGen/AArch64/cmp-chains.ll b/llvm/test/CodeGen/AArch64/cmp-chains.ll
index 4b816df75a730..81c3f51a2b422 100644
--- a/llvm/test/CodeGen/AArch64/cmp-chains.ll
+++ b/llvm/test/CodeGen/AArch64/cmp-chains.ll
@@ -501,3 +501,47 @@ entry:
   %land.ext = zext i1 %0 to i32
   ret i32 %land.ext
 }
+
+define i32 @compare_with_neg_32(i32 %a, i32 %b, i32 %c) {
+; SDISEL-LABEL: compare_with_neg_32:
+; SDISEL:       // %bb.0:
+; SDISEL-NEXT:    cmp w0, w2
+; SDISEL-NEXT:    ccmn w1, #31, #8, lt
+; SDISEL-NEXT:    csel w0, w1, w0, ge
+; SDISEL-NEXT:    ret
+;
+; GISEL-LABEL: compare_with_neg_32:
+; GISEL:       // %bb.0:
+; GISEL-NEXT:    mov w8, #-32 // =0xffffffe0
+; GISEL-NEXT:    cmp w0, w2
+; GISEL-NEXT:    ccmp w1, w8, #4, lt
+; GISEL-NEXT:    csel w0, w1, w0, gt
+; GISEL-NEXT:    ret
+  %cmp = icmp sgt i32 %b, -32
+  %cmp1 = icmp slt i32 %a, %c
+  %or.cond = and i1 %cmp, %cmp1
+  %cond = select i1 %or.cond, i32 %b, i32 %a
+  ret i32 %cond
+}
+
+define i32 @compare_with_32(i32 %a, i32 %b, i32 %c) {
+; SDISEL-LABEL: compare_with_32:
+; SDISEL:       // %bb.0:
+; SDISEL-NEXT:    cmp w0, w2
+; SDISEL-NEXT:    ccmp w1, #31, #4, lt
+; SDISEL-NEXT:    csel w0, w1, w0, gt
+; SDISEL-NEXT:    ret
+;
+; GISEL-LABEL: compare_with_32:
+; GISEL:       // %bb.0:
+; GISEL-NEXT:    mov w8, #32 // =0x20
+; GISEL-NEXT:    cmp w0, w2
+; GISEL-NEXT:    ccmp w1, w8, #8, lt
+; GISEL-NEXT:    csel w0, w1, w0, ge
+; GISEL-NEXT:    ret
+  %cmp = icmp sge i32 %b, 32
+  %cmp1 = icmp slt i32 %a, %c
+  %or.cond = and i1 %cmp, %cmp1
+  %cond = select i1 %or.cond, i32 %b, i32 %a
+  ret i32 %cond
+}

This lets us encode the immediate in the instruction.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants