[llvm] [AArch64] Add intra-block CSINC optimization to AArch64ConditionOptimizer (PR #173734)
Hussam A. via llvm-commits
llvm-commits at lists.llvm.org
Sat Dec 27 09:07:56 PST 2025
https://github.com/hussam-alhassan created https://github.com/llvm/llvm-project/pull/173734
This patch extends the AArch64ConditionOptimizer pass to handle CSINC instructions within a single basic block, complementing the existing cross-block branch optimization.
The optimization finds two CMP+CSINC pairs comparing the same register with immediates differing by 1, and adjusts one comparison to enable CSE to eliminate the redundant CMP instruction.
Example transformation:
cmp w8, #10
csinc w9, w0, w1, gt ; w9 = (w8 > 10) ? w0 : w1+1
cmp w8, #9 ; Removed by CSE after adjustment
csinc w10, w0, w1, gt ; w10 = (w8 > 9) ? w0 : w1+1
After optimization:
cmp w8, #10
csinc w9, w0, w1, gt ; w9 = (w8 > 10) ? w0 : w1+1
csinc w10, w0, w1, ge ; w10 = (w8 >= 10) ? w0 : w1+1
The existing cross-block logic has also been extracted into its own method.
Any feedback on code quality and better practices is highly welcome.
>From cf750dcc4f480066179a4e1552a3c705d4ba65f8 Mon Sep 17 00:00:00 2001
From: Hussam Alhassan <hsm.link at proton.me>
Date: Sat, 27 Dec 2025 13:31:30 +0000
Subject: [PATCH] [AArch64] Add intra-block CSINC optimization to
AArch64ConditionOptimizer
This patch extends the AArch64ConditionOptimizer pass to handle CSINC
instructions within a single basic block, complementing the existing
cross-block branch optimization.
The optimization finds two CMP+CSINC pairs comparing the same register
with immediates differing by 1, and adjusts one comparison to enable
CSE to eliminate the redundant CMP instruction.
Example transformation:
cmp w8, #10
csinc w9, w0, w1, gt ; w9 = (w8 > 10) ? w0 : w1+1
cmp w8, #9 ; Removed by CSE after adjustment
csinc w10, w0, w1, gt ; w10 = (w8 > 9) ? w0 : w1+1
After optimization:
cmp w8, #10
csinc w9, w0, w1, gt ; w9 = (w8 > 10) ? w0 : w1+1
csinc w10, w0, w1, ge ; w10 = (w8 >= 10) ? w0 : w1+1
The existing cross-block logic has also been extracted into its own method.
---
.../AArch64/AArch64ConditionOptimizer.cpp | 400 +++++++++++++-----
.../AArch64/combine-comparisons-by-cse.ll | 244 ++++++++---
2 files changed, 464 insertions(+), 180 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ConditionOptimizer.cpp b/llvm/lib/Target/AArch64/AArch64ConditionOptimizer.cpp
index 4c9f8c2723493..fef5f5a84d937 100644
--- a/llvm/lib/Target/AArch64/AArch64ConditionOptimizer.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ConditionOptimizer.cpp
@@ -6,15 +6,17 @@
//
//===----------------------------------------------------------------------===//
//
-// This pass tries to make consecutive compares of values use same operands to
-// allow CSE pass to remove duplicated instructions. For this it analyzes
-// branches and adjusts comparisons with immediate values by converting:
-// * GE -> GT
-// * GT -> GE
-// * LT -> LE
-// * LE -> LT
-// and adjusting immediate values appropriately. It basically corrects two
-// immediate values towards each other to make them equal.
+//
+// This pass tries to make consecutive comparisons of values use the same
+// operands to allow the CSE pass to remove duplicate instructions. It adjusts
+// comparisons with immediate values by converting between inclusive and
+// exclusive forms (GE <-> GT, LE <-> LT) and correcting immediate values to
+// make them equal.
+//
+// The pass handles:
+// * Cross-block: SUBS/ADDS followed by conditional branches
+// * Intra-block: CSINC conditional instructions
+//
//
// Consider the following example in C:
//
@@ -49,11 +51,16 @@
// b.le .LBB0_6
// ...
//
-// Currently only SUBS and ADDS followed by b.?? are supported.
+// See optimizeCrossBlock() and optimizeIntraBlock() for implementation details.
//
// TODO: maybe handle TBNZ/TBZ the same way as CMP when used instead for "a < 0"
-// TODO: handle other conditional instructions (e.g. CSET)
-// TODO: allow second branching to be anything if it doesn't require adjusting
+// TODO: For cross-block:
+// - handle other conditional instructions (e.g. CSET)
+// - allow second branching to be anything if it doesn't require adjusting
+// TODO: For intra-block:
+// - handle CINC and CSET (CSINC aliases) as their conditions are inverted
+// compared to CSINC.
+// - handle other non-CSINC conditional instructions
//
//===----------------------------------------------------------------------===//
@@ -111,6 +118,9 @@ class AArch64ConditionOptimizer : public MachineFunctionPass {
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;
StringRef getPassName() const override {
@@ -323,125 +333,295 @@ bool AArch64ConditionOptimizer::adjustTo(MachineInstr *CmpMI,
return false;
}
-bool AArch64ConditionOptimizer::runOnMachineFunction(MachineFunction &MF) {
- LLVM_DEBUG(dbgs() << "********** AArch64 Conditional Compares **********\n"
- << "********** Function: " << MF.getName() << '\n');
- if (skipFunction(MF.getFunction()))
+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;
+ }
- TII = MF.getSubtarget().getInstrInfo();
- DomTree = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
- MRI = &MF.getRegInfo();
-
- bool Changed = false;
+ return true;
+}
- // Visit blocks in dominator tree pre-order. The pre-order enables multiple
- // cmp-conversions from the same head block.
- // Note that updateDomTree() modifies the children of the DomTree node
- // currently being visited. The df_iterator supports that; it doesn't look at
- // child_begin() / child_end() until after a node has been visited.
- for (MachineDomTreeNode *I : depth_first(DomTree)) {
- MachineBasicBlock *HBB = I->getBlock();
+// This function transforms two CMP+CSINC pairs within the same basic block
+// when both conditions are the same (GT/GT or LT/LT) and immediates differ
+// by 1.
+//
+// Example transformation:
+// cmp w8, #10
+// csinc w9, w0, w1, gt ; w9 = (w8 > 10) ? w0 : w1+1
+// cmp w8, #9
+// csinc w10, w0, w1, gt ; w10 = (w8 > 9) ? w0 : w1+1
+//
+// Into:
+// cmp w8, #10
+// csinc w9, w0, w1, gt ; w9 = (w8 > 10) ? w0 : w1+1
+// csinc w10, w0, w1, ge ; w10 = (w8 >= 10) ? w0 : w1+1
+//
+// 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
+ 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 (!FirstCmp) {
+ FirstCmp = &MI;
+ } else if (FirstCSINC && !SecondCmp) {
+ SecondCmp = &MI;
+ }
+ break;
+ }
- SmallVector<MachineOperand, 4> HeadCond;
- MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
- if (TII->analyzeBranch(*HBB, TBB, FBB, HeadCond)) {
- continue;
+ case AArch64::CSINCWr:
+ case AArch64::CSINCXr: {
+ // Found a CSINC, ensure it comes after the corresponding comparison
+ if (FirstCmp && !FirstCSINC) {
+ FirstCSINC = &MI;
+ } else if (SecondCmp && !SecondCSINC) {
+ SecondCSINC = &MI;
+ }
+ break;
+ }
}
- // Equivalence check is to skip loops.
- if (!TBB || TBB == HBB) {
- continue;
+ if (SecondCSINC)
+ break;
+ }
+
+ if (!SecondCmp || !SecondCSINC) {
+ LLVM_DEBUG(dbgs() << "Didn't find two CMP+CSINC pairs\n");
+ return false;
+ }
+
+ if (FirstCmp->getOperand(1).getReg() != SecondCmp->getOperand(1).getReg()) {
+ LLVM_DEBUG(dbgs() << "CMPs compare different registers\n");
+ return false;
+ }
+
+ if (!isPureCmp(*FirstCmp) || !isPureCmp(*SecondCmp)) {
+ LLVM_DEBUG(dbgs() << "One or both CMPs are not pure\n");
+ return false;
+ }
+
+ // Check that nothing else modifies the flags between the first CMP and second
+ // conditional
+ for (auto It = std::next(MachineBasicBlock::iterator(FirstCmp));
+ It != std::next(MachineBasicBlock::iterator(SecondCSINC)); ++It) {
+ if (&*It != SecondCmp &&
+ It->modifiesRegister(AArch64::NZCV, /*TRI=*/nullptr)) {
+ LLVM_DEBUG(dbgs() << "Flags modified between CMPs by: " << *It << '\n');
+ return false;
}
+ }
- SmallVector<MachineOperand, 4> TrueCond;
- MachineBasicBlock *TBB_TBB = nullptr, *TBB_FBB = nullptr;
- if (TII->analyzeBranch(*TBB, TBB_TBB, TBB_FBB, TrueCond)) {
- continue;
+ // Check flags aren't read after second conditional within the same block
+ for (auto It = std::next(MachineBasicBlock::iterator(SecondCSINC));
+ It != MBB.end(); ++It) {
+ if (It->readsRegister(AArch64::NZCV, /*TRI=*/nullptr)) {
+ LLVM_DEBUG(dbgs() << "Flags read after second CSINC by: " << *It << '\n');
+ return false;
}
+ }
- MachineInstr *HeadCmpMI = findSuitableCompare(HBB);
- if (!HeadCmpMI) {
- continue;
+ // Since we may modify a cmp in this MBB, make sure NZCV does not live out.
+ for (auto *SuccBB : MBB.successors())
+ if (SuccBB->isLiveIn(AArch64::NZCV))
+ return false;
+
+ // Extract condition codes from both CSINCs (operand 3)
+ AArch64CC::CondCode FirstCond =
+ (AArch64CC::CondCode)(int)FirstCSINC->getOperand(3).getImm();
+ 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();
+
+ LLVM_DEBUG(dbgs() << "Comparing intra-block CSINCs: "
+ << AArch64CC::getCondCodeName(FirstCond) << " #" << FirstImm
+ << " and " << AArch64CC::getCondCodeName(SecondCond) << " #"
+ << SecondImm << '\n');
+
+ // Check if both conditions are the same and immediates differ by 1
+ if (((FirstCond == AArch64CC::GT && SecondCond == AArch64CC::GT) ||
+ (FirstCond == AArch64CC::LT && SecondCond == AArch64CC::LT)) &&
+ std::abs(SecondImm - FirstImm) == 1) {
+ // Pick which comparison to adjust to match the other
+ // For GT: adjust the one with smaller immediate
+ // For LT: adjust the one with larger immediate
+ bool adjustFirst = (FirstImm < SecondImm);
+ if (FirstCond == AArch64CC::LT) {
+ adjustFirst = !adjustFirst;
}
- MachineInstr *TrueCmpMI = findSuitableCompare(TBB);
- if (!TrueCmpMI) {
- continue;
+ MachineInstr *CmpToAdjust = adjustFirst ? FirstCmp : SecondCmp;
+ MachineInstr *CSINCToAdjust = adjustFirst ? FirstCSINC : SecondCSINC;
+ AArch64CC::CondCode CondToAdjust = adjustFirst ? FirstCond : SecondCond;
+ int TargetImm = adjustFirst ? SecondImm : FirstImm;
+
+ CmpInfo AdjustedInfo = adjustCmp(CmpToAdjust, CondToAdjust);
+
+ if (std::get<0>(AdjustedInfo) == TargetImm &&
+ std::get<1>(AdjustedInfo) ==
+ (adjustFirst ? SecondCmp : FirstCmp)->getOpcode()) {
+ LLVM_DEBUG(dbgs() << "Successfully optimizing intra-block CSINC pair\n");
+
+ // Modify the selected CMP and CSINC
+ CmpToAdjust->getOperand(2).setImm(std::get<0>(AdjustedInfo));
+ CmpToAdjust->setDesc(TII->get(std::get<1>(AdjustedInfo)));
+ CSINCToAdjust->getOperand(3).setImm(std::get<2>(AdjustedInfo));
+
+ return true;
}
+ }
- AArch64CC::CondCode HeadCmp;
- if (HeadCond.empty() || !parseCond(HeadCond, HeadCmp)) {
- continue;
+ return false;
+}
+
+// Optimize across blocks
+bool AArch64ConditionOptimizer::optimizeCrossBlock(MachineBasicBlock &HBB) {
+ SmallVector<MachineOperand, 4> HeadCond;
+ MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
+ if (TII->analyzeBranch(HBB, TBB, FBB, HeadCond)) {
+ return false;
+ }
+
+ // Equivalence check is to skip loops.
+ if (!TBB || TBB == &HBB) {
+ return false;
+ }
+
+ SmallVector<MachineOperand, 4> TrueCond;
+ MachineBasicBlock *TBB_TBB = nullptr, *TBB_FBB = nullptr;
+ if (TII->analyzeBranch(*TBB, TBB_TBB, TBB_FBB, TrueCond)) {
+ return false;
+ }
+
+ MachineInstr *HeadCmpMI = findSuitableCompare(&HBB);
+ if (!HeadCmpMI) {
+ return false;
+ }
+
+ MachineInstr *TrueCmpMI = findSuitableCompare(TBB);
+ if (!TrueCmpMI) {
+ return false;
+ }
+
+ AArch64CC::CondCode HeadCmp;
+ if (HeadCond.empty() || !parseCond(HeadCond, HeadCmp)) {
+ return false;
+ }
+
+ AArch64CC::CondCode TrueCmp;
+ if (TrueCond.empty() || !parseCond(TrueCond, TrueCmp)) {
+ return false;
+ }
+
+ const int HeadImm = (int)HeadCmpMI->getOperand(2).getImm();
+ const int TrueImm = (int)TrueCmpMI->getOperand(2).getImm();
+
+ LLVM_DEBUG(dbgs() << "Head branch:\n");
+ LLVM_DEBUG(dbgs() << "\tcondition: " << AArch64CC::getCondCodeName(HeadCmp)
+ << '\n');
+ LLVM_DEBUG(dbgs() << "\timmediate: " << HeadImm << '\n');
+
+ LLVM_DEBUG(dbgs() << "True branch:\n");
+ LLVM_DEBUG(dbgs() << "\tcondition: " << AArch64CC::getCondCodeName(TrueCmp)
+ << '\n');
+ LLVM_DEBUG(dbgs() << "\timmediate: " << TrueImm << '\n');
+
+ if (((HeadCmp == AArch64CC::GT && TrueCmp == AArch64CC::LT) ||
+ (HeadCmp == AArch64CC::LT && TrueCmp == AArch64CC::GT)) &&
+ std::abs(TrueImm - HeadImm) == 2) {
+ // This branch transforms machine instructions that correspond to
+ //
+ // 1) (a > {TrueImm} && ...) || (a < {HeadImm} && ...)
+ // 2) (a < {TrueImm} && ...) || (a > {HeadImm} && ...)
+ //
+ // into
+ //
+ // 1) (a >= {NewImm} && ...) || (a <= {NewImm} && ...)
+ // 2) (a <= {NewImm} && ...) || (a >= {NewImm} && ...)
+
+ CmpInfo HeadCmpInfo = adjustCmp(HeadCmpMI, HeadCmp);
+ CmpInfo TrueCmpInfo = adjustCmp(TrueCmpMI, TrueCmp);
+ if (std::get<0>(HeadCmpInfo) == std::get<0>(TrueCmpInfo) &&
+ std::get<1>(HeadCmpInfo) == std::get<1>(TrueCmpInfo)) {
+ modifyCmp(HeadCmpMI, HeadCmpInfo);
+ modifyCmp(TrueCmpMI, TrueCmpInfo);
+ return true;
+ }
+ } else if (((HeadCmp == AArch64CC::GT && TrueCmp == AArch64CC::GT) ||
+ (HeadCmp == AArch64CC::LT && TrueCmp == AArch64CC::LT)) &&
+ std::abs(TrueImm - HeadImm) == 1) {
+ // This branch transforms machine instructions that correspond to
+ //
+ // 1) (a > {TrueImm} && ...) || (a > {HeadImm} && ...)
+ // 2) (a < {TrueImm} && ...) || (a < {HeadImm} && ...)
+ //
+ // into
+ //
+ // 1) (a <= {NewImm} && ...) || (a > {NewImm} && ...)
+ // 2) (a < {NewImm} && ...) || (a >= {NewImm} && ...)
+
+ // GT -> GE transformation increases immediate value, so picking the
+ // smaller one; LT -> LE decreases immediate value so invert the choice.
+ bool adjustHeadCond = (HeadImm < TrueImm);
+ if (HeadCmp == AArch64CC::LT) {
+ adjustHeadCond = !adjustHeadCond;
}
- AArch64CC::CondCode TrueCmp;
- if (TrueCond.empty() || !parseCond(TrueCond, TrueCmp)) {
- continue;
+ if (adjustHeadCond) {
+ return adjustTo(HeadCmpMI, HeadCmp, TrueCmpMI, TrueImm);
+ } else {
+ return adjustTo(TrueCmpMI, TrueCmp, HeadCmpMI, HeadImm);
}
+ }
+ // Other transformation cases almost never occur due to generation of < or >
+ // comparisons instead of <= and >=.
- const int HeadImm = (int)HeadCmpMI->getOperand(2).getImm();
- const int TrueImm = (int)TrueCmpMI->getOperand(2).getImm();
+ return false;
+}
- LLVM_DEBUG(dbgs() << "Head branch:\n");
- LLVM_DEBUG(dbgs() << "\tcondition: " << AArch64CC::getCondCodeName(HeadCmp)
- << '\n');
- LLVM_DEBUG(dbgs() << "\timmediate: " << HeadImm << '\n');
+bool AArch64ConditionOptimizer::runOnMachineFunction(MachineFunction &MF) {
+ LLVM_DEBUG(dbgs() << "********** AArch64 Conditional Compares **********\n"
+ << "********** Function: " << MF.getName() << '\n');
+ if (skipFunction(MF.getFunction()))
+ return false;
- LLVM_DEBUG(dbgs() << "True branch:\n");
- LLVM_DEBUG(dbgs() << "\tcondition: " << AArch64CC::getCondCodeName(TrueCmp)
- << '\n');
- LLVM_DEBUG(dbgs() << "\timmediate: " << TrueImm << '\n');
-
- if (((HeadCmp == AArch64CC::GT && TrueCmp == AArch64CC::LT) ||
- (HeadCmp == AArch64CC::LT && TrueCmp == AArch64CC::GT)) &&
- std::abs(TrueImm - HeadImm) == 2) {
- // This branch transforms machine instructions that correspond to
- //
- // 1) (a > {TrueImm} && ...) || (a < {HeadImm} && ...)
- // 2) (a < {TrueImm} && ...) || (a > {HeadImm} && ...)
- //
- // into
- //
- // 1) (a >= {NewImm} && ...) || (a <= {NewImm} && ...)
- // 2) (a <= {NewImm} && ...) || (a >= {NewImm} && ...)
-
- CmpInfo HeadCmpInfo = adjustCmp(HeadCmpMI, HeadCmp);
- CmpInfo TrueCmpInfo = adjustCmp(TrueCmpMI, TrueCmp);
- if (std::get<0>(HeadCmpInfo) == std::get<0>(TrueCmpInfo) &&
- std::get<1>(HeadCmpInfo) == std::get<1>(TrueCmpInfo)) {
- modifyCmp(HeadCmpMI, HeadCmpInfo);
- modifyCmp(TrueCmpMI, TrueCmpInfo);
- Changed = true;
- }
- } else if (((HeadCmp == AArch64CC::GT && TrueCmp == AArch64CC::GT) ||
- (HeadCmp == AArch64CC::LT && TrueCmp == AArch64CC::LT)) &&
- std::abs(TrueImm - HeadImm) == 1) {
- // This branch transforms machine instructions that correspond to
- //
- // 1) (a > {TrueImm} && ...) || (a > {HeadImm} && ...)
- // 2) (a < {TrueImm} && ...) || (a < {HeadImm} && ...)
- //
- // into
- //
- // 1) (a <= {NewImm} && ...) || (a > {NewImm} && ...)
- // 2) (a < {NewImm} && ...) || (a >= {NewImm} && ...)
-
- // GT -> GE transformation increases immediate value, so picking the
- // smaller one; LT -> LE decreases immediate value so invert the choice.
- bool adjustHeadCond = (HeadImm < TrueImm);
- if (HeadCmp == AArch64CC::LT) {
- adjustHeadCond = !adjustHeadCond;
- }
+ TII = MF.getSubtarget().getInstrInfo();
+ DomTree = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
+ MRI = &MF.getRegInfo();
- if (adjustHeadCond) {
- Changed |= adjustTo(HeadCmpMI, HeadCmp, TrueCmpMI, TrueImm);
- } else {
- Changed |= adjustTo(TrueCmpMI, TrueCmp, HeadCmpMI, HeadImm);
- }
- }
- // Other transformation cases almost never occur due to generation of < or >
- // comparisons instead of <= and >=.
+ bool Changed = false;
+
+ // Visit blocks in dominator tree pre-order. The pre-order enables multiple
+ // cmp-conversions from the same head block.
+ // Note that updateDomTree() modifies the children of the DomTree node
+ // currently being visited. The df_iterator supports that; it doesn't look at
+ // child_begin() / child_end() until after a node has been visited.
+ for (MachineDomTreeNode *I : depth_first(DomTree)) {
+ MachineBasicBlock *HBB = I->getBlock();
+ Changed |= optimizeIntraBlock(*HBB);
+ Changed |= optimizeCrossBlock(*HBB);
}
return Changed;
diff --git a/llvm/test/CodeGen/AArch64/combine-comparisons-by-cse.ll b/llvm/test/CodeGen/AArch64/combine-comparisons-by-cse.ll
index 6449c3e11d667..4449c2b9193a4 100644
--- a/llvm/test/CodeGen/AArch64/combine-comparisons-by-cse.ll
+++ b/llvm/test/CodeGen/AArch64/combine-comparisons-by-cse.ll
@@ -7,6 +7,110 @@
@c = external global i32
@d = external global i32
+
+; Test intra-block CSINC optimization with (a > 10) and (a >= 10)
+; Two CSINC instructions should share a single CMP after optimization
+define void @intra_block_csinc(i32 %x, i32 %y, ptr %out1, ptr %out2) #0 {
+; CHECK-LABEL: intra_block_csinc:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: adrp x8, :got:a
+; CHECK-NEXT: ldr x8, [x8, :got_lo12:a]
+; CHECK-NEXT: ldr w8, [x8]
+; CHECK-NEXT: cmp w8, #10
+; CHECK-NEXT: csinc w8, w0, w1, gt
+; CHECK-NEXT: csinc w9, w0, w1, ge
+; CHECK-NEXT: str w8, [x2]
+; CHECK-NEXT: str w9, [x3]
+; CHECK-NEXT: ret
+entry:
+ %val = load i32, ptr @a, align 4
+
+ ; First: result1 = (a > 10) ? x : (y + 1)
+ %cond1 = icmp sgt i32 %val, 10
+ %y_inc1 = add i32 %y, 1
+ %result1 = select i1 %cond1, i32 %x, i32 %y_inc1
+ store i32 %result1, ptr %out1
+
+ ; Second: result2 = (a >= 10) ? x : (y + 1)
+ ; Canonicalizes to (a > 9), then optimizes to reuse first CMP with adjusted condition
+ %cond2 = icmp sge i32 %val, 10
+ %y_inc2 = add i32 %y, 1
+ %result2 = select i1 %cond2, i32 %x, i32 %y_inc2
+ store i32 %result2, ptr %out2
+
+ ret void
+}
+
+; Negative test: different registers should not be optimized
+define void @intra_block_csinc_different_regs(i32 %x, i32 %y, ptr %out1, ptr %out2) #0 {
+; CHECK-LABEL: intra_block_csinc_different_regs:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: adrp x8, :got:a
+; CHECK-NEXT: adrp x9, :got:b
+; CHECK-NEXT: ldr x8, [x8, :got_lo12:a]
+; CHECK-NEXT: ldr x9, [x9, :got_lo12:b]
+; CHECK-NEXT: ldr w8, [x8]
+; CHECK-NEXT: ldr w9, [x9]
+; CHECK-NEXT: cmp w8, #10
+; CHECK-NEXT: csinc w8, w0, w1, gt
+; CHECK-NEXT: cmp w9, #9
+; CHECK-NEXT: str w8, [x2]
+; CHECK-NEXT: csinc w8, w0, w1, gt
+; CHECK-NEXT: str w8, [x3]
+; CHECK-NEXT: ret
+entry:
+ %val1 = load i32, ptr @a, align 4
+ %val2 = load i32, ptr @b, align 4
+
+ ; First: result1 = (a > 10) ? x : (y + 1)
+ %cond1 = icmp sgt i32 %val1, 10
+ %y_inc1 = add i32 %y, 1
+ %result1 = select i1 %cond1, i32 %x, i32 %y_inc1
+ store i32 %result1, ptr %out1
+
+ ; Second: result2 = (b > 9) ? x : (y + 1) - compares DIFFERENT register
+ ; Should NOT optimize - need both CMPs
+ %cond2 = icmp sgt i32 %val2, 9
+ %y_inc2 = add i32 %y, 1
+ %result2 = select i1 %cond2, i32 %x, i32 %y_inc2
+ store i32 %result2, ptr %out2
+
+ ret void
+}
+
+; Test intra-block CSINC optimization with (a < 5) and (a < 6)
+; LT/LT pattern - symmetric to GT/GT case
+define void @intra_block_csinc_lt(i32 %x, i32 %y, ptr %out1, ptr %out2) #0 {
+; CHECK-LABEL: intra_block_csinc_lt:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: adrp x8, :got:a
+; CHECK-NEXT: ldr x8, [x8, :got_lo12:a]
+; CHECK-NEXT: ldr w8, [x8]
+; CHECK-NEXT: cmp w8, #5
+; CHECK-NEXT: csinc w8, w0, w1, lt
+; CHECK-NEXT: csinc w9, w0, w1, le
+; CHECK-NEXT: str w8, [x2]
+; CHECK-NEXT: str w9, [x3]
+; CHECK-NEXT: ret
+entry:
+ %val = load i32, ptr @a, align 4
+
+ ; First: result1 = (a < 5) ? x : (y + 1)
+ %cond1 = icmp slt i32 %val, 5
+ %y_inc1 = add i32 %y, 1
+ %result1 = select i1 %cond1, i32 %x, i32 %y_inc1
+ store i32 %result1, ptr %out1
+
+ ; Second: result2 = (a < 6) ? x : (y + 1)
+ ; Optimizes to reuse first CMP (#5) with adjusted condition (le)
+ %cond2 = icmp slt i32 %val, 6
+ %y_inc2 = add i32 %y, 1
+ %result2 = select i1 %cond2, i32 %x, i32 %y_inc2
+ store i32 %result2, ptr %out2
+
+ ret void
+}
+
; (a > 10 && b == c) || (a >= 10 && b == d)
define i32 @combine_gt_ge_10() #0 {
; CHECK-LABEL: combine_gt_ge_10:
@@ -17,30 +121,30 @@ define i32 @combine_gt_ge_10() #0 {
; CHECK-NEXT: cmp w8, #10
; CHECK-NEXT: adrp x8, :got:b
; CHECK-NEXT: ldr x8, [x8, :got_lo12:b]
-; CHECK-NEXT: b.le .LBB0_3
+; CHECK-NEXT: b.le .LBB3_3
; CHECK-NEXT: // %bb.1: // %land.lhs.true
; CHECK-NEXT: adrp x9, :got:c
; CHECK-NEXT: ldr x9, [x9, :got_lo12:c]
; CHECK-NEXT: ldr w10, [x8]
; CHECK-NEXT: ldr w9, [x9]
; CHECK-NEXT: cmp w10, w9
-; CHECK-NEXT: b.ne .LBB0_4
+; CHECK-NEXT: b.ne .LBB3_4
; CHECK-NEXT: // %bb.2:
; CHECK-NEXT: mov w0, #1 // =0x1
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB0_3: // %lor.lhs.false
-; CHECK-NEXT: b.lt .LBB0_6
-; CHECK-NEXT: .LBB0_4: // %land.lhs.true3
+; CHECK-NEXT: .LBB3_3: // %lor.lhs.false
+; CHECK-NEXT: b.lt .LBB3_6
+; CHECK-NEXT: .LBB3_4: // %land.lhs.true3
; CHECK-NEXT: adrp x9, :got:d
; CHECK-NEXT: ldr x9, [x9, :got_lo12:d]
; CHECK-NEXT: ldr w8, [x8]
; CHECK-NEXT: ldr w9, [x9]
; CHECK-NEXT: cmp w8, w9
-; CHECK-NEXT: b.ne .LBB0_6
+; CHECK-NEXT: b.ne .LBB3_6
; CHECK-NEXT: // %bb.5:
; CHECK-NEXT: mov w0, #1 // =0x1
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB0_6: // %if.end
+; CHECK-NEXT: .LBB3_6: // %if.end
; CHECK-NEXT: mov w0, wzr
; CHECK-NEXT: ret
entry:
@@ -80,7 +184,7 @@ define i32 @combine_gt_lt_5() #0 {
; CHECK-NEXT: ldr x8, [x8, :got_lo12:a]
; CHECK-NEXT: ldr w8, [x8]
; CHECK-NEXT: cmp w8, #5
-; CHECK-NEXT: b.le .LBB1_3
+; CHECK-NEXT: b.le .LBB4_3
; CHECK-NEXT: // %bb.1: // %land.lhs.true
; CHECK-NEXT: adrp x8, :got:b
; CHECK-NEXT: adrp x9, :got:c
@@ -89,12 +193,12 @@ define i32 @combine_gt_lt_5() #0 {
; CHECK-NEXT: ldr w8, [x8]
; CHECK-NEXT: ldr w9, [x9]
; CHECK-NEXT: cmp w8, w9
-; CHECK-NEXT: b.ne .LBB1_6
+; CHECK-NEXT: b.ne .LBB4_6
; CHECK-NEXT: // %bb.2:
; CHECK-NEXT: mov w0, #1 // =0x1
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB1_3: // %lor.lhs.false
-; CHECK-NEXT: b.ge .LBB1_6
+; CHECK-NEXT: .LBB4_3: // %lor.lhs.false
+; CHECK-NEXT: b.ge .LBB4_6
; CHECK-NEXT: // %bb.4: // %land.lhs.true3
; CHECK-NEXT: adrp x8, :got:b
; CHECK-NEXT: adrp x9, :got:d
@@ -103,11 +207,11 @@ define i32 @combine_gt_lt_5() #0 {
; CHECK-NEXT: ldr w8, [x8]
; CHECK-NEXT: ldr w9, [x9]
; CHECK-NEXT: cmp w8, w9
-; CHECK-NEXT: b.ne .LBB1_6
+; CHECK-NEXT: b.ne .LBB4_6
; CHECK-NEXT: // %bb.5:
; CHECK-NEXT: mov w0, #1 // =0x1
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB1_6: // %if.end
+; CHECK-NEXT: .LBB4_6: // %if.end
; CHECK-NEXT: mov w0, wzr
; CHECK-NEXT: ret
entry:
@@ -149,30 +253,30 @@ define i32 @combine_lt_ge_5() #0 {
; CHECK-NEXT: cmp w8, #5
; CHECK-NEXT: adrp x8, :got:b
; CHECK-NEXT: ldr x8, [x8, :got_lo12:b]
-; CHECK-NEXT: b.ge .LBB2_3
+; CHECK-NEXT: b.ge .LBB5_3
; CHECK-NEXT: // %bb.1: // %land.lhs.true
; CHECK-NEXT: adrp x9, :got:c
; CHECK-NEXT: ldr x9, [x9, :got_lo12:c]
; CHECK-NEXT: ldr w10, [x8]
; CHECK-NEXT: ldr w9, [x9]
; CHECK-NEXT: cmp w10, w9
-; CHECK-NEXT: b.ne .LBB2_4
+; CHECK-NEXT: b.ne .LBB5_4
; CHECK-NEXT: // %bb.2:
; CHECK-NEXT: mov w0, #1 // =0x1
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB2_3: // %lor.lhs.false
-; CHECK-NEXT: b.gt .LBB2_6
-; CHECK-NEXT: .LBB2_4: // %land.lhs.true3
+; CHECK-NEXT: .LBB5_3: // %lor.lhs.false
+; CHECK-NEXT: b.gt .LBB5_6
+; CHECK-NEXT: .LBB5_4: // %land.lhs.true3
; CHECK-NEXT: adrp x9, :got:d
; CHECK-NEXT: ldr x9, [x9, :got_lo12:d]
; CHECK-NEXT: ldr w8, [x8]
; CHECK-NEXT: ldr w9, [x9]
; CHECK-NEXT: cmp w8, w9
-; CHECK-NEXT: b.ne .LBB2_6
+; CHECK-NEXT: b.ne .LBB5_6
; CHECK-NEXT: // %bb.5:
; CHECK-NEXT: mov w0, #1 // =0x1
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB2_6: // %if.end
+; CHECK-NEXT: .LBB5_6: // %if.end
; CHECK-NEXT: mov w0, wzr
; CHECK-NEXT: ret
entry:
@@ -212,7 +316,7 @@ define i32 @combine_lt_gt_5() #0 {
; CHECK-NEXT: ldr x8, [x8, :got_lo12:a]
; CHECK-NEXT: ldr w8, [x8]
; CHECK-NEXT: cmp w8, #5
-; CHECK-NEXT: b.ge .LBB3_3
+; CHECK-NEXT: b.ge .LBB6_3
; CHECK-NEXT: // %bb.1: // %land.lhs.true
; CHECK-NEXT: adrp x8, :got:b
; CHECK-NEXT: adrp x9, :got:c
@@ -221,12 +325,12 @@ define i32 @combine_lt_gt_5() #0 {
; CHECK-NEXT: ldr w8, [x8]
; CHECK-NEXT: ldr w9, [x9]
; CHECK-NEXT: cmp w8, w9
-; CHECK-NEXT: b.ne .LBB3_6
+; CHECK-NEXT: b.ne .LBB6_6
; CHECK-NEXT: // %bb.2:
; CHECK-NEXT: mov w0, #1 // =0x1
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB3_3: // %lor.lhs.false
-; CHECK-NEXT: b.le .LBB3_6
+; CHECK-NEXT: .LBB6_3: // %lor.lhs.false
+; CHECK-NEXT: b.le .LBB6_6
; CHECK-NEXT: // %bb.4: // %land.lhs.true3
; CHECK-NEXT: adrp x8, :got:b
; CHECK-NEXT: adrp x9, :got:d
@@ -235,11 +339,11 @@ define i32 @combine_lt_gt_5() #0 {
; CHECK-NEXT: ldr w8, [x8]
; CHECK-NEXT: ldr w9, [x9]
; CHECK-NEXT: cmp w8, w9
-; CHECK-NEXT: b.ne .LBB3_6
+; CHECK-NEXT: b.ne .LBB6_6
; CHECK-NEXT: // %bb.5:
; CHECK-NEXT: mov w0, #1 // =0x1
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB3_6: // %if.end
+; CHECK-NEXT: .LBB6_6: // %if.end
; CHECK-NEXT: mov w0, wzr
; CHECK-NEXT: ret
entry:
@@ -279,7 +383,7 @@ define i32 @combine_gt_lt_n5() #0 {
; CHECK-NEXT: ldr x8, [x8, :got_lo12:a]
; CHECK-NEXT: ldr w8, [x8]
; CHECK-NEXT: cmn w8, #5
-; CHECK-NEXT: b.le .LBB4_3
+; CHECK-NEXT: b.le .LBB7_3
; CHECK-NEXT: // %bb.1: // %land.lhs.true
; CHECK-NEXT: adrp x8, :got:b
; CHECK-NEXT: adrp x9, :got:c
@@ -288,12 +392,12 @@ define i32 @combine_gt_lt_n5() #0 {
; CHECK-NEXT: ldr w8, [x8]
; CHECK-NEXT: ldr w9, [x9]
; CHECK-NEXT: cmp w8, w9
-; CHECK-NEXT: b.ne .LBB4_6
+; CHECK-NEXT: b.ne .LBB7_6
; CHECK-NEXT: // %bb.2:
; CHECK-NEXT: mov w0, #1 // =0x1
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB4_3: // %lor.lhs.false
-; CHECK-NEXT: b.ge .LBB4_6
+; CHECK-NEXT: .LBB7_3: // %lor.lhs.false
+; CHECK-NEXT: b.ge .LBB7_6
; CHECK-NEXT: // %bb.4: // %land.lhs.true3
; CHECK-NEXT: adrp x8, :got:b
; CHECK-NEXT: adrp x9, :got:d
@@ -302,11 +406,11 @@ define i32 @combine_gt_lt_n5() #0 {
; CHECK-NEXT: ldr w8, [x8]
; CHECK-NEXT: ldr w9, [x9]
; CHECK-NEXT: cmp w8, w9
-; CHECK-NEXT: b.ne .LBB4_6
+; CHECK-NEXT: b.ne .LBB7_6
; CHECK-NEXT: // %bb.5:
; CHECK-NEXT: mov w0, #1 // =0x1
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB4_6: // %if.end
+; CHECK-NEXT: .LBB7_6: // %if.end
; CHECK-NEXT: mov w0, wzr
; CHECK-NEXT: ret
entry:
@@ -346,7 +450,7 @@ define i32 @combine_lt_gt_n5() #0 {
; CHECK-NEXT: ldr x8, [x8, :got_lo12:a]
; CHECK-NEXT: ldr w8, [x8]
; CHECK-NEXT: cmn w8, #5
-; CHECK-NEXT: b.ge .LBB5_3
+; CHECK-NEXT: b.ge .LBB8_3
; CHECK-NEXT: // %bb.1: // %land.lhs.true
; CHECK-NEXT: adrp x8, :got:b
; CHECK-NEXT: adrp x9, :got:c
@@ -355,12 +459,12 @@ define i32 @combine_lt_gt_n5() #0 {
; CHECK-NEXT: ldr w8, [x8]
; CHECK-NEXT: ldr w9, [x9]
; CHECK-NEXT: cmp w8, w9
-; CHECK-NEXT: b.ne .LBB5_6
+; CHECK-NEXT: b.ne .LBB8_6
; CHECK-NEXT: // %bb.2:
; CHECK-NEXT: mov w0, #1 // =0x1
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB5_3: // %lor.lhs.false
-; CHECK-NEXT: b.le .LBB5_6
+; CHECK-NEXT: .LBB8_3: // %lor.lhs.false
+; CHECK-NEXT: b.le .LBB8_6
; CHECK-NEXT: // %bb.4: // %land.lhs.true3
; CHECK-NEXT: adrp x8, :got:b
; CHECK-NEXT: adrp x9, :got:d
@@ -369,11 +473,11 @@ define i32 @combine_lt_gt_n5() #0 {
; CHECK-NEXT: ldr w8, [x8]
; CHECK-NEXT: ldr w9, [x9]
; CHECK-NEXT: cmp w8, w9
-; CHECK-NEXT: b.ne .LBB5_6
+; CHECK-NEXT: b.ne .LBB8_6
; CHECK-NEXT: // %bb.5:
; CHECK-NEXT: mov w0, #1 // =0x1
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB5_6: // %if.end
+; CHECK-NEXT: .LBB8_6: // %if.end
; CHECK-NEXT: mov w0, wzr
; CHECK-NEXT: ret
entry:
@@ -428,19 +532,19 @@ define void @combine_non_adjacent_cmp_br(ptr nocapture readonly %hdCall) #0 {
; CHECK-NEXT: mov w19, #24 // =0x18
; CHECK-NEXT: adrp x22, glob
; CHECK-NEXT: add x21, x20, #2
-; CHECK-NEXT: .LBB6_1: // %land.rhs
+; CHECK-NEXT: .LBB9_1: // %land.rhs
; CHECK-NEXT: // =>This Inner Loop Header: Depth=1
; CHECK-NEXT: ldr x8, [x19]
; CHECK-NEXT: cmp x8, #1
-; CHECK-NEXT: b.lt .LBB6_3
+; CHECK-NEXT: b.lt .LBB9_3
; CHECK-NEXT: // %bb.2: // %while.body
-; CHECK-NEXT: // in Loop: Header=BB6_1 Depth=1
+; CHECK-NEXT: // in Loop: Header=BB9_1 Depth=1
; CHECK-NEXT: ldr x0, [x22, :lo12:glob]
; CHECK-NEXT: bl Update
; CHECK-NEXT: sub x21, x21, #2
; CHECK-NEXT: cmp x20, x21
-; CHECK-NEXT: b.lt .LBB6_1
-; CHECK-NEXT: .LBB6_3: // %while.end
+; CHECK-NEXT: b.lt .LBB9_1
+; CHECK-NEXT: .LBB9_3: // %while.end
; CHECK-NEXT: ldp x20, x19, [sp, #32] // 16-byte Folded Reload
; CHECK-NEXT: ldp x22, x21, [sp, #16] // 16-byte Folded Reload
; CHECK-NEXT: ldr x30, [sp], #48 // 8-byte Folded Reload
@@ -488,19 +592,19 @@ define i32 @do_nothing_if_resultant_opcodes_would_differ() #0 {
; CHECK-NEXT: ldr x19, [x19, :got_lo12:a]
; CHECK-NEXT: ldr w8, [x19]
; CHECK-NEXT: cmn w8, #2
-; CHECK-NEXT: b.gt .LBB7_4
+; CHECK-NEXT: b.gt .LBB10_4
; CHECK-NEXT: // %bb.1: // %while.body.preheader
; CHECK-NEXT: sub w20, w8, #1
-; CHECK-NEXT: .LBB7_2: // %while.body
+; CHECK-NEXT: .LBB10_2: // %while.body
; CHECK-NEXT: // =>This Inner Loop Header: Depth=1
; CHECK-NEXT: bl do_something
; CHECK-NEXT: adds w20, w20, #1
-; CHECK-NEXT: b.mi .LBB7_2
+; CHECK-NEXT: b.mi .LBB10_2
; CHECK-NEXT: // %bb.3: // %while.cond.while.end_crit_edge
; CHECK-NEXT: ldr w8, [x19]
-; CHECK-NEXT: .LBB7_4: // %while.end
+; CHECK-NEXT: .LBB10_4: // %while.end
; CHECK-NEXT: cmp w8, #1
-; CHECK-NEXT: b.gt .LBB7_7
+; CHECK-NEXT: b.gt .LBB10_7
; CHECK-NEXT: // %bb.5: // %land.lhs.true
; CHECK-NEXT: adrp x8, :got:b
; CHECK-NEXT: adrp x9, :got:d
@@ -509,13 +613,13 @@ define i32 @do_nothing_if_resultant_opcodes_would_differ() #0 {
; CHECK-NEXT: ldr w8, [x8]
; CHECK-NEXT: ldr w9, [x9]
; CHECK-NEXT: cmp w8, w9
-; CHECK-NEXT: b.ne .LBB7_7
+; CHECK-NEXT: b.ne .LBB10_7
; CHECK-NEXT: // %bb.6:
; CHECK-NEXT: mov w0, #123 // =0x7b
-; CHECK-NEXT: b .LBB7_8
-; CHECK-NEXT: .LBB7_7: // %if.end
+; CHECK-NEXT: b .LBB10_8
+; CHECK-NEXT: .LBB10_7: // %if.end
; CHECK-NEXT: mov w0, wzr
-; CHECK-NEXT: .LBB7_8: // %return
+; CHECK-NEXT: .LBB10_8: // %return
; CHECK-NEXT: ldp x20, x19, [sp, #16] // 16-byte Folded Reload
; CHECK-NEXT: ldr x30, [sp], #32 // 8-byte Folded Reload
; CHECK-NEXT: .cfi_def_cfa_offset 0
@@ -573,20 +677,20 @@ define i32 @do_nothing_if_compares_can_not_be_adjusted_to_each_other() #0 {
; CHECK-NEXT: ldr x8, [x8, :got_lo12:a]
; CHECK-NEXT: ldr w8, [x8]
; CHECK-NEXT: cmp w8, #0
-; CHECK-NEXT: b.gt .LBB8_3
+; CHECK-NEXT: b.gt .LBB11_3
; CHECK-NEXT: // %bb.1: // %while.body.preheader
; CHECK-NEXT: sub w19, w8, #1
-; CHECK-NEXT: .LBB8_2: // %while.body
+; CHECK-NEXT: .LBB11_2: // %while.body
; CHECK-NEXT: // =>This Inner Loop Header: Depth=1
; CHECK-NEXT: bl do_something
; CHECK-NEXT: adds w19, w19, #1
-; CHECK-NEXT: b.mi .LBB8_2
-; CHECK-NEXT: .LBB8_3: // %while.end
+; CHECK-NEXT: b.mi .LBB11_2
+; CHECK-NEXT: .LBB11_3: // %while.end
; CHECK-NEXT: adrp x8, :got:c
; CHECK-NEXT: ldr x8, [x8, :got_lo12:c]
; CHECK-NEXT: ldr w8, [x8]
; CHECK-NEXT: cmn w8, #2
-; CHECK-NEXT: b.lt .LBB8_6
+; CHECK-NEXT: b.lt .LBB11_6
; CHECK-NEXT: // %bb.4: // %land.lhs.true
; CHECK-NEXT: adrp x8, :got:b
; CHECK-NEXT: adrp x9, :got:d
@@ -595,7 +699,7 @@ define i32 @do_nothing_if_compares_can_not_be_adjusted_to_each_other() #0 {
; CHECK-NEXT: ldr w8, [x8]
; CHECK-NEXT: ldr w9, [x9]
; CHECK-NEXT: cmp w8, w9
-; CHECK-NEXT: b.ne .LBB8_6
+; CHECK-NEXT: b.ne .LBB11_6
; CHECK-NEXT: // %bb.5:
; CHECK-NEXT: mov w0, #123 // =0x7b
; CHECK-NEXT: ldp x30, x19, [sp], #16 // 16-byte Folded Reload
@@ -603,7 +707,7 @@ define i32 @do_nothing_if_compares_can_not_be_adjusted_to_each_other() #0 {
; CHECK-NEXT: .cfi_restore w19
; CHECK-NEXT: .cfi_restore w30
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB8_6: // %if.end
+; CHECK-NEXT: .LBB11_6: // %if.end
; CHECK-NEXT: .cfi_restore_state
; CHECK-NEXT: mov w0, wzr
; CHECK-NEXT: ldp x30, x19, [sp], #16 // 16-byte Folded Reload
@@ -659,14 +763,14 @@ define i32 @fcmpri(i32 %argc, ptr nocapture readonly %argv) #0 {
; CHECK-LABEL: fcmpri:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: cmp w0, #2
-; CHECK-NEXT: b.lt .LBB9_3
+; CHECK-NEXT: b.lt .LBB12_3
; CHECK-NEXT: // %bb.1: // %land.lhs.true
; CHECK-NEXT: ldr x8, [x1, #8]
-; CHECK-NEXT: cbz x8, .LBB9_3
+; CHECK-NEXT: cbz x8, .LBB12_3
; CHECK-NEXT: // %bb.2:
; CHECK-NEXT: mov w0, #3 // =0x3
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB9_3: // %if.end
+; CHECK-NEXT: .LBB12_3: // %if.end
; CHECK-NEXT: str d8, [sp, #-32]! // 8-byte Folded Spill
; CHECK-NEXT: .cfi_def_cfa_offset 32
; CHECK-NEXT: stp x30, x19, [sp, #16] // 16-byte Folded Spill
@@ -782,12 +886,12 @@ define i32 @combine_gt_ge_sel(i64 %v, ptr %p) #0 {
; CHECK-NEXT: cmp w8, #0
; CHECK-NEXT: csel x9, x0, xzr, gt
; CHECK-NEXT: str x9, [x1]
-; CHECK-NEXT: b.le .LBB11_2
+; CHECK-NEXT: b.le .LBB14_2
; CHECK-NEXT: // %bb.1: // %lor.lhs.false
; CHECK-NEXT: cmp w8, #2
-; CHECK-NEXT: b.ge .LBB11_4
-; CHECK-NEXT: b .LBB11_6
-; CHECK-NEXT: .LBB11_2: // %land.lhs.true
+; CHECK-NEXT: b.ge .LBB14_4
+; CHECK-NEXT: b .LBB14_6
+; CHECK-NEXT: .LBB14_2: // %land.lhs.true
; CHECK-NEXT: adrp x8, :got:b
; CHECK-NEXT: adrp x9, :got:c
; CHECK-NEXT: ldr x8, [x8, :got_lo12:b]
@@ -795,11 +899,11 @@ define i32 @combine_gt_ge_sel(i64 %v, ptr %p) #0 {
; CHECK-NEXT: ldr w8, [x8]
; CHECK-NEXT: ldr w9, [x9]
; CHECK-NEXT: cmp w8, w9
-; CHECK-NEXT: b.ne .LBB11_4
+; CHECK-NEXT: b.ne .LBB14_4
; CHECK-NEXT: // %bb.3:
; CHECK-NEXT: mov w0, #1 // =0x1
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB11_4: // %land.lhs.true3
+; CHECK-NEXT: .LBB14_4: // %land.lhs.true3
; CHECK-NEXT: adrp x8, :got:b
; CHECK-NEXT: adrp x9, :got:d
; CHECK-NEXT: ldr x8, [x8, :got_lo12:b]
@@ -807,11 +911,11 @@ define i32 @combine_gt_ge_sel(i64 %v, ptr %p) #0 {
; CHECK-NEXT: ldr w8, [x8]
; CHECK-NEXT: ldr w9, [x9]
; CHECK-NEXT: cmp w8, w9
-; CHECK-NEXT: b.ne .LBB11_6
+; CHECK-NEXT: b.ne .LBB14_6
; CHECK-NEXT: // %bb.5:
; CHECK-NEXT: mov w0, #1 // =0x1
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB11_6: // %if.end
+; CHECK-NEXT: .LBB14_6: // %if.end
; CHECK-NEXT: mov w0, wzr
; CHECK-NEXT: ret
entry:
More information about the llvm-commits
mailing list