[llvm] [AArch64][GlobalISel] Fold (icmp op, (sub 0, y)) into a register CCMN before immediate / plain CCMP forms. (PR #192878)

via llvm-commits llvm-commits at lists.llvm.org
Sun Apr 19 15:22:52 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-aarch64

Author: SiliconA-Z

<details>
<summary>Changes</summary>

Now with parity with SelectionDAG.

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


2 Files Affected:

- (modified) llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp (+20-7) 
- (added) llvm/test/CodeGen/AArch64/GlobalISel/ccmp-cmn-sub.ll (+32) 


``````````diff
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
index 2fa0fca176c88..8d590f23acca3 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
@@ -4783,13 +4783,26 @@ MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
   std::optional<ValueAndVReg> C;
   if (CmpInst::isIntPredicate(CC)) {
     assert(OpTy.getSizeInBits() == 32 || OpTy.getSizeInBits() == 64);
-    C = getIConstantVRegValWithLookThrough(RHS, MRI);
-    if (!C || C->Value.sgt(31) || C->Value.slt(-31))
-      CCmpOpc = OpTy.getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
-    else if (C->Value.ule(31))
-      CCmpOpc = OpTy.getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
-    else
-      CCmpOpc = OpTy.getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
+    const bool Is32Bit = OpTy.getSizeInBits() == 32;
+    // Fold (icmp op, (sub 0, y)) into a register CCMN before immediate / plain
+    // CCMP forms.
+    if (MachineInstr *RHSDef = getDefIgnoringCopies(RHS, MRI);
+        isCMN(RHSDef, CC, MRI)) {
+      CCmpOpc = Is32Bit ? AArch64::CCMNWr : AArch64::CCMNXr;
+      RHS = RHSDef->getOperand(2).getReg();
+    } else if (MachineInstr *LHSDef = getDefIgnoringCopies(LHS, MRI);
+               CmpInst::isEquality(CC) && isCMN(LHSDef, CC, MRI)) {
+      CCmpOpc = Is32Bit ? AArch64::CCMNWr : AArch64::CCMNXr;
+      LHS = LHSDef->getOperand(2).getReg();
+    } else {
+      C = getIConstantVRegValWithLookThrough(RHS, MRI);
+      if (!C || C->Value.sgt(31) || C->Value.slt(-31))
+        CCmpOpc = Is32Bit ? AArch64::CCMPWr : AArch64::CCMPXr;
+      else if (C->Value.ule(31))
+        CCmpOpc = Is32Bit ? AArch64::CCMPWi : AArch64::CCMPXi;
+      else
+        CCmpOpc = Is32Bit ? AArch64::CCMNWi : AArch64::CCMNXi;
+    }
   } else {
     assert(OpTy.getSizeInBits() == 16 || OpTy.getSizeInBits() == 32 ||
            OpTy.getSizeInBits() == 64);
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/ccmp-cmn-sub.ll b/llvm/test/CodeGen/AArch64/GlobalISel/ccmp-cmn-sub.ll
new file mode 100644
index 0000000000000..d794717d4202b
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/ccmp-cmn-sub.ll
@@ -0,0 +1,32 @@
+; NOTE: Assertions may be updated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=aarch64-- -global-isel -verify-machineinstrs %s -o - | FileCheck %s
+
+define i32 @ccmp_cmn_rhs(i32 %a, i32 %b, i32 %c, i32 %x, i32 %y) {
+; CHECK-LABEL: ccmp_cmn_rhs:
+; CHECK-DAG: cmp w0, #5
+; CHECK: ccmn w2, w1, #0, eq
+; CHECK-NEXT: csel
+entry:
+  %neg = sub nsw i32 0, %b
+  %cmp_sub = icmp eq i32 %c, %neg
+  %cmp_simple = icmp eq i32 %a, 5
+  %and = and i1 %cmp_sub, %cmp_simple
+  %s = select i1 %and, i32 %x, i32 %y
+  ret i32 %s
+}
+
+; LHS of icmp is (sub 0, %a) with equality: commute to CCMN.
+
+define i32 @ccmp_cmn_lhs_eq(i32 %a, i32 %b, i32 %c, i32 %x, i32 %y) {
+; CHECK-LABEL: ccmp_cmn_lhs_eq:
+; CHECK-DAG: cmp w2, #7
+; CHECK: ccmn w0, w1, #0, eq
+; CHECK-NEXT: csel
+entry:
+  %neg = sub nsw i32 0, %a
+  %cmp_sub = icmp eq i32 %neg, %b
+  %cmp_simple = icmp eq i32 %c, 7
+  %and = and i1 %cmp_sub, %cmp_simple
+  %s = select i1 %and, i32 %x, i32 %y
+  ret i32 %s
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/192878


More information about the llvm-commits mailing list