[llvm] [NFC][AArch64] AArch64ConditionOptimizer extract shared instruction finding logic (PR #182244)

Hussam Alhassan via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 19 02:53:23 PST 2026


https://github.com/hussam-alhassan created https://github.com/llvm/llvm-project/pull/182244

Extract cmp/cond instruction finding logic from cross- and intra-block code into shared functions

>From 9b7346532e01de4b5a11632ed23855ccddc720c8 Mon Sep 17 00:00:00 2001
From: Hussam Alhassan <hsm.link at proton.me>
Date: Thu, 19 Feb 2026 10:48:12 +0000
Subject: [PATCH] [NFC][AArch64] AArch64ConditionOptimizer extract shared
 instruction finding logic

Extract cmp/cond instruction finding logic from cross- and intra-block code
into shared functions
---
 .../AArch64/AArch64ConditionOptimizer.cpp     | 77 +++++++++++--------
 1 file changed, 47 insertions(+), 30 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64ConditionOptimizer.cpp b/llvm/lib/Target/AArch64/AArch64ConditionOptimizer.cpp
index 311cb1800cc39..17b0e120ae95b 100644
--- a/llvm/lib/Target/AArch64/AArch64ConditionOptimizer.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ConditionOptimizer.cpp
@@ -115,6 +115,7 @@ class AArch64ConditionOptimizer : public MachineFunctionPass {
   AArch64ConditionOptimizer() : MachineFunctionPass(ID) {}
 
   void getAnalysisUsage(AnalysisUsage &AU) const override;
+  bool canAdjustCmp(MachineInstr &CmpMI);
   bool registersMatch(MachineInstr *FirstMI, MachineInstr *SecondMI);
   bool nzcvLivesOut(MachineBasicBlock *MBB);
   MachineInstr *findSuitableCompare(MachineBasicBlock *MBB);
@@ -152,6 +153,25 @@ void AArch64ConditionOptimizer::getAnalysisUsage(AnalysisUsage &AU) const {
   MachineFunctionPass::getAnalysisUsage(AU);
 }
 
+// Verify that the MI's immediate is adjustable and it only sets flags (pure
+// cmp)
+bool AArch64ConditionOptimizer::canAdjustCmp(MachineInstr &CmpMI) {
+  unsigned ShiftAmt = AArch64_AM::getShiftValue(CmpMI.getOperand(3).getImm());
+  if (!CmpMI.getOperand(2).isImm()) {
+    LLVM_DEBUG(dbgs() << "Immediate of cmp is symbolic, " << CmpMI << '\n');
+    return false;
+  } else if (CmpMI.getOperand(2).getImm() << ShiftAmt >= 0xfff) {
+    LLVM_DEBUG(dbgs() << "Immediate of cmp may be out of range, " << CmpMI
+                      << '\n');
+    return false;
+  } else if (!MRI->use_nodbg_empty(CmpMI.getOperand(0).getReg())) {
+    LLVM_DEBUG(dbgs() << "Destination of cmp is not dead, " << CmpMI << '\n');
+    return false;
+  }
+
+  return true;
+}
+
 // Ensure both compare MIs use the same register, tracing through copies.
 bool AArch64ConditionOptimizer::registersMatch(MachineInstr *FirstMI,
                                                MachineInstr *SecondMI) {
@@ -182,6 +202,25 @@ bool AArch64ConditionOptimizer::nzcvLivesOut(MachineBasicBlock *MBB) {
   return false;
 }
 
+// Returns true if the opcode is a comparison instruction (CMP/CMN).
+static bool isCmpInstruction(unsigned Opc) {
+  switch (Opc) {
+  // cmp is an alias for SUBS with a dead destination register.
+  case AArch64::SUBSWri:
+  case AArch64::SUBSXri:
+  // cmp is an alias for ADDS with a dead destination register.
+  case AArch64::ADDSWri:
+  case AArch64::ADDSXri:
+    return true;
+  default:
+    return false;
+  }
+}
+
+static bool isCSINCInstruction(unsigned Opc) {
+  return Opc == AArch64::CSINCWr || Opc == AArch64::CSINCXr;
+}
+
 // Finds compare instruction that corresponds to supported types of branching.
 // Returns the instruction or nullptr on failures or detecting unsupported
 // instructions.
@@ -203,31 +242,18 @@ MachineInstr *AArch64ConditionOptimizer::findSuitableCompare(
     It = prev_nodbg(It, B);
     MachineInstr &I = *It;
     assert(!I.isTerminator() && "Spurious terminator");
+
     // Check if there is any use of NZCV between CMP and Bcc.
     if (I.readsRegister(AArch64::NZCV, /*TRI=*/nullptr))
       return nullptr;
-    switch (I.getOpcode()) {
-    // cmp is an alias for subs with a dead destination register.
-    case AArch64::SUBSWri:
-    case AArch64::SUBSXri:
-    // cmn is an alias for adds with a dead destination register.
-    case AArch64::ADDSWri:
-    case AArch64::ADDSXri: {
-      unsigned ShiftAmt = AArch64_AM::getShiftValue(I.getOperand(3).getImm());
-      if (!I.getOperand(2).isImm()) {
-        LLVM_DEBUG(dbgs() << "Immediate of cmp is symbolic, " << I << '\n');
-        return nullptr;
-      } else if (I.getOperand(2).getImm() << ShiftAmt >= 0xfff) {
-        LLVM_DEBUG(dbgs() << "Immediate of cmp may be out of range, " << I
-                          << '\n');
-        return nullptr;
-      } else if (!MRI->use_nodbg_empty(I.getOperand(0).getReg())) {
-        LLVM_DEBUG(dbgs() << "Destination of cmp is not dead, " << I << '\n');
+
+    if (isCmpInstruction(I.getOpcode())) {
+      if (!canAdjustCmp(I)) {
         return nullptr;
       }
       return &I;
     }
-    }
+
     if (I.modifiesRegister(AArch64::NZCV, /*TRI=*/nullptr))
       return nullptr;
   }
@@ -389,31 +415,22 @@ bool AArch64ConditionOptimizer::optimizeIntraBlock(MachineBasicBlock &MBB) {
 
   // Find two CMP + CSINC pairs
   for (MachineInstr &MI : MBB) {
-    switch (MI.getOpcode()) {
-    // cmp is an alias for subs with a dead destination register.
-    case AArch64::SUBSWri:
-    case AArch64::SUBSXri:
-    // cmn is an alias for adds with a dead destination register.
-    case AArch64::ADDSWri:
-    case AArch64::ADDSXri: {
+    if (isCmpInstruction(MI.getOpcode())) {
       if (!FirstCmp) {
         FirstCmp = &MI;
       } else if (FirstCSINC && !SecondCmp) {
         SecondCmp = &MI;
       }
-      break;
+      continue;
     }
 
-    case AArch64::CSINCWr:
-    case AArch64::CSINCXr: {
+    if (isCSINCInstruction(MI.getOpcode())) {
       // Found a CSINC, ensure it comes after the corresponding comparison
       if (FirstCmp && !FirstCSINC) {
         FirstCSINC = &MI;
       } else if (SecondCmp && !SecondCSINC) {
         SecondCSINC = &MI;
       }
-      break;
-    }
     }
 
     if (SecondCSINC)



More information about the llvm-commits mailing list