[llvm] [NFC][AArch64] Improve semantics of findSuitableCompare in ConditionOptimizer (PR #183532)

Hussam Alhassan via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 2 03:40:34 PST 2026


https://github.com/hussam-alhassan updated https://github.com/llvm/llvm-project/pull/183532

>From 497eb2467cf285d031b78c6eb6412b42071fba41 Mon Sep 17 00:00:00 2001
From: Hussam Alhassan <hsm.link at proton.me>
Date: Thu, 26 Feb 2026 14:05:59 +0000
Subject: [PATCH] [NFC][AArch64] AArch64ConditionOptimizer Improve semantics of
 findSuitableCompare

Improve the semantics of the "findSuitableCompare" method and improve
logic sharing between the cross- and intra-block paths.

Add the "getBccTerminator" helper and rename the above function to
"findAdjustableCmp" which now takes a conditional instruction and
returns its controlling compare.
---
 .../AArch64/AArch64ConditionOptimizer.cpp     | 131 +++++++++---------
 1 file changed, 62 insertions(+), 69 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64ConditionOptimizer.cpp b/llvm/lib/Target/AArch64/AArch64ConditionOptimizer.cpp
index 2e8e3a1a8e845..ef86f1b431418 100644
--- a/llvm/lib/Target/AArch64/AArch64ConditionOptimizer.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ConditionOptimizer.cpp
@@ -118,12 +118,12 @@ class AArch64ConditionOptimizer : public MachineFunctionPass {
   bool canAdjustCmp(MachineInstr &CmpMI);
   bool registersMatch(MachineInstr *FirstMI, MachineInstr *SecondMI);
   bool nzcvLivesOut(MachineBasicBlock *MBB);
-  MachineInstr *findSuitableCompare(MachineBasicBlock *MBB);
+  MachineInstr *getBccTerminator(MachineBasicBlock *MBB);
+  MachineInstr *findAdjustableCmp(MachineInstr *CondMI);
   CmpInfo adjustCmp(MachineInstr *CmpMI, AArch64CC::CondCode Cmp);
   void modifyCmp(MachineInstr *CmpMI, const CmpInfo &Info);
   bool adjustTo(MachineInstr *CmpMI, AArch64CC::CondCode Cmp, MachineInstr *To,
                 int ToImm);
-  bool isPureCmp(MachineInstr &CmpMI);
   bool optimizeIntraBlock(MachineBasicBlock &MBB);
   bool optimizeCrossBlock(MachineBasicBlock &HBB);
   bool runOnMachineFunction(MachineFunction &MF) override;
@@ -221,28 +221,43 @@ 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.
-MachineInstr *AArch64ConditionOptimizer::findSuitableCompare(
-    MachineBasicBlock *MBB) {
+// Returns the Bcc terminator if present, otherwise nullptr.
+MachineInstr *
+AArch64ConditionOptimizer::getBccTerminator(MachineBasicBlock *MBB) {
   MachineBasicBlock::iterator Term = MBB->getFirstTerminator();
-  if (Term == MBB->end())
+  if (Term == MBB->end()) {
+    LLVM_DEBUG(dbgs() << "No terminator in " << printMBBReference(*MBB)
+                      << '\n');
     return nullptr;
+  }
 
-  if (Term->getOpcode() != AArch64::Bcc)
+  if (Term->getOpcode() != AArch64::Bcc) {
+    LLVM_DEBUG(dbgs() << "Non-Bcc terminator in " << printMBBReference(*MBB)
+                      << ": " << *Term);
     return nullptr;
+  }
 
-  // Since we may modify cmp of this MBB, make sure NZCV does not live out.
-  if (nzcvLivesOut(MBB))
-    return nullptr;
+  return &*Term;
+}
 
-  // Now find the instruction controlling the terminator.
-  for (MachineBasicBlock::iterator B = MBB->begin(), It = Term; It != B;) {
+// Find the CMP instruction controlling the given conditional instruction and
+// ensure it can be adjusted for CSE optimization. Searches backward from
+// CondMI, ensuring no NZCV interference. Returns nullptr if no suitable CMP
+// is found or if adjustments are not safe.
+MachineInstr *
+AArch64ConditionOptimizer::findAdjustableCmp(MachineInstr *CondMI) {
+  assert(CondMI && "CondMI cannot be null");
+  MachineBasicBlock *MBB = CondMI->getParent();
+
+  // Search backward from the conditional to find the instruction controlling
+  // it.
+  for (MachineBasicBlock::iterator B = MBB->begin(),
+                                   It = MachineBasicBlock::iterator(CondMI);
+       It != B;) {
     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.
+    // Ensure there is no use of NZCV between CMP and conditional.
     if (I.readsRegister(AArch64::NZCV, /*TRI=*/nullptr))
       return nullptr;
 
@@ -396,23 +411,6 @@ bool AArch64ConditionOptimizer::adjustTo(MachineInstr *CmpMI,
   return false;
 }
 
-bool AArch64ConditionOptimizer::isPureCmp(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;
-}
-
 static bool isGreaterThan(AArch64CC::CondCode Cmp) {
   return Cmp == AArch64CC::GT || Cmp == AArch64CC::HI;
 }
@@ -439,37 +437,22 @@ static bool isLessThan(AArch64CC::CondCode Cmp) {
 // The second CMP is eliminated, enabling CSE to remove the redundant
 // comparison.
 bool AArch64ConditionOptimizer::optimizeIntraBlock(MachineBasicBlock &MBB) {
-  MachineInstr *FirstCmp = nullptr;
   MachineInstr *FirstCSINC = nullptr;
-  MachineInstr *SecondCmp = nullptr;
   MachineInstr *SecondCSINC = nullptr;
 
-  // Find two CMP + CSINC pairs
+  // Find two CSINC instructions
   for (MachineInstr &MI : MBB) {
-    if (isCmpInstruction(MI.getOpcode())) {
-      if (!FirstCmp) {
-        FirstCmp = &MI;
-      } else if (FirstCSINC && !SecondCmp) {
-        SecondCmp = &MI;
-      }
-      continue;
-    }
-
     if (isCSINCInstruction(MI.getOpcode())) {
-      // Found a CSINC, ensure it comes after the corresponding comparison
-      if (FirstCmp && !FirstCSINC) {
+      if (!FirstCSINC) {
         FirstCSINC = &MI;
-      } else if (SecondCmp && !SecondCSINC) {
+      } else if (!SecondCSINC) {
         SecondCSINC = &MI;
+        break; // Found both
       }
     }
-
-    if (SecondCSINC)
-      break;
   }
 
-  if (!SecondCmp || !SecondCSINC) {
-    LLVM_DEBUG(dbgs() << "Didn't find two CMP+CSINC pairs\n");
+  if (!FirstCSINC || !SecondCSINC) {
     return false;
   }
 
@@ -477,19 +460,26 @@ bool AArch64ConditionOptimizer::optimizeIntraBlock(MachineBasicBlock &MBB) {
   if (nzcvLivesOut(&MBB))
     return false;
 
-  if (!registersMatch(FirstCmp, SecondCmp))
+  // Find the CMPs controlling each CSINC
+  MachineInstr *FirstCmpMI = findAdjustableCmp(FirstCSINC);
+  MachineInstr *SecondCmpMI = findAdjustableCmp(SecondCSINC);
+  if (!FirstCmpMI || !SecondCmpMI)
     return false;
 
-  if (!isPureCmp(*FirstCmp) || !isPureCmp(*SecondCmp)) {
-    LLVM_DEBUG(dbgs() << "One or both CMPs are not pure\n");
+  // Ensure we have two distinct CMPs
+  if (FirstCmpMI == SecondCmpMI) {
+    LLVM_DEBUG(dbgs() << "Both CSINCs already controlled by same CMP\n");
     return false;
   }
 
+  if (!registersMatch(FirstCmpMI, SecondCmpMI))
+    return false;
+
   // Check that nothing else modifies the flags between the first CMP and second
   // conditional
-  for (auto It = std::next(MachineBasicBlock::iterator(FirstCmp));
+  for (auto It = std::next(MachineBasicBlock::iterator(FirstCmpMI));
        It != std::next(MachineBasicBlock::iterator(SecondCSINC)); ++It) {
-    if (&*It != SecondCmp &&
+    if (&*It != SecondCmpMI &&
         It->modifiesRegister(AArch64::NZCV, /*TRI=*/nullptr)) {
       LLVM_DEBUG(dbgs() << "Flags modified between CMPs by: " << *It << '\n');
       return false;
@@ -511,8 +501,8 @@ bool AArch64ConditionOptimizer::optimizeIntraBlock(MachineBasicBlock &MBB) {
   AArch64CC::CondCode SecondCond =
       (AArch64CC::CondCode)(int)SecondCSINC->getOperand(3).getImm();
 
-  const int FirstImm = (int)FirstCmp->getOperand(2).getImm();
-  const int SecondImm = (int)SecondCmp->getOperand(2).getImm();
+  const int FirstImm = (int)FirstCmpMI->getOperand(2).getImm();
+  const int SecondImm = (int)SecondCmpMI->getOperand(2).getImm();
 
   LLVM_DEBUG(dbgs() << "Comparing intra-block CSINCs: "
                     << AArch64CC::getCondCodeName(FirstCond) << " #" << FirstImm
@@ -532,7 +522,7 @@ bool AArch64ConditionOptimizer::optimizeIntraBlock(MachineBasicBlock &MBB) {
       adjustFirst = !adjustFirst;
     }
 
-    MachineInstr *CmpToAdjust = adjustFirst ? FirstCmp : SecondCmp;
+    MachineInstr *CmpToAdjust = adjustFirst ? FirstCmpMI : SecondCmpMI;
     MachineInstr *CSINCToAdjust = adjustFirst ? FirstCSINC : SecondCSINC;
     AArch64CC::CondCode CondToAdjust = adjustFirst ? FirstCond : SecondCond;
     int TargetImm = adjustFirst ? SecondImm : FirstImm;
@@ -541,7 +531,7 @@ bool AArch64ConditionOptimizer::optimizeIntraBlock(MachineBasicBlock &MBB) {
 
     if (std::get<0>(AdjustedInfo) == TargetImm &&
         std::get<1>(AdjustedInfo) ==
-            (adjustFirst ? SecondCmp : FirstCmp)->getOpcode()) {
+            (adjustFirst ? SecondCmpMI : FirstCmpMI)->getOpcode()) {
       LLVM_DEBUG(dbgs() << "Successfully optimizing intra-block CSINC pair\n");
 
       // Modify the selected CMP and CSINC
@@ -575,19 +565,22 @@ bool AArch64ConditionOptimizer::optimizeCrossBlock(MachineBasicBlock &HBB) {
     return false;
   }
 
-  MachineInstr *HeadCmpMI = findSuitableCompare(&HBB);
-  if (!HeadCmpMI) {
+  MachineInstr *HeadBrMI = getBccTerminator(&HBB);
+  MachineInstr *TrueBrMI = getBccTerminator(TBB);
+  if (!HeadBrMI || !TrueBrMI)
     return false;
-  }
 
-  MachineInstr *TrueCmpMI = findSuitableCompare(TBB);
-  if (!TrueCmpMI) {
+  // Since we may modify cmps in these blocks, make sure NZCV does not live out.
+  if (nzcvLivesOut(&HBB) || nzcvLivesOut(TBB))
     return false;
-  }
 
-  if (!registersMatch(HeadCmpMI, TrueCmpMI)) {
+  MachineInstr *HeadCmpMI = findAdjustableCmp(HeadBrMI);
+  MachineInstr *TrueCmpMI = findAdjustableCmp(TrueBrMI);
+  if (!HeadCmpMI || !TrueCmpMI)
+    return false;
+
+  if (!registersMatch(HeadCmpMI, TrueCmpMI))
     return false;
-  }
 
   AArch64CC::CondCode HeadCmp;
   if (HeadCond.empty() || !parseCond(HeadCond, HeadCmp)) {



More information about the llvm-commits mailing list