[llvm] 7f7d78d - [AArch64] Add register check to ConditionOptimizer cross-block logic (#176528)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jan 22 07:31:57 PST 2026
Author: Hussam A.
Date: 2026-01-22T15:31:52Z
New Revision: 7f7d78d05c3558b6dd201cb735ec0f16e3636ba8
URL: https://github.com/llvm/llvm-project/commit/7f7d78d05c3558b6dd201cb735ec0f16e3636ba8
DIFF: https://github.com/llvm/llvm-project/commit/7f7d78d05c3558b6dd201cb735ec0f16e3636ba8.diff
LOG: [AArch64] Add register check to ConditionOptimizer cross-block logic (#176528)
This patch adds a missing guard to the AArch64 ConditionOptimizer pass
Previously, the cross-block optimization would not check for register
equivalence before modifying the two comparison instructions.
This means that two cmp instructions with suitable cond codes and
immediates would be modified, even if their registers were different,
which would not trigger CSE afterwards. This doesn't affect correctness
but is unhelpful.
A negative ll test and mir tests has also been added to confirm this
fix.
Added:
llvm/test/CodeGen/AArch64/aarch64-condopt-cross-block-different-regs.mir
Modified:
llvm/lib/Target/AArch64/AArch64ConditionOptimizer.cpp
llvm/test/CodeGen/AArch64/combine-comparisons-by-cse.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/AArch64/AArch64ConditionOptimizer.cpp b/llvm/lib/Target/AArch64/AArch64ConditionOptimizer.cpp
index 6cf676fde752a..f428252e143ba 100644
--- a/llvm/lib/Target/AArch64/AArch64ConditionOptimizer.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ConditionOptimizer.cpp
@@ -80,6 +80,7 @@
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
+#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
@@ -100,6 +101,7 @@ namespace {
class AArch64ConditionOptimizer : public MachineFunctionPass {
const TargetInstrInfo *TII;
+ const TargetRegisterInfo *TRI;
MachineDominatorTree *DomTree;
const MachineRegisterInfo *MRI;
@@ -506,6 +508,18 @@ bool AArch64ConditionOptimizer::optimizeCrossBlock(MachineBasicBlock &HBB) {
return false;
}
+ // Ensure both compares use the same register, tracing through copies.
+ Register HeadReg = HeadCmpMI->getOperand(1).getReg();
+ Register TrueReg = TrueCmpMI->getOperand(1).getReg();
+ Register HeadCmpReg =
+ HeadReg.isVirtual() ? TRI->lookThruCopyLike(HeadReg, MRI) : HeadReg;
+ Register TrueCmpReg =
+ TrueReg.isVirtual() ? TRI->lookThruCopyLike(TrueReg, MRI) : TrueReg;
+ if (HeadCmpReg != TrueCmpReg) {
+ LLVM_DEBUG(dbgs() << "CMPs compare
diff erent registers\n");
+ return false;
+ }
+
AArch64CC::CondCode HeadCmp;
if (HeadCond.empty() || !parseCond(HeadCond, HeadCmp)) {
return false;
@@ -589,6 +603,7 @@ bool AArch64ConditionOptimizer::runOnMachineFunction(MachineFunction &MF) {
return false;
TII = MF.getSubtarget().getInstrInfo();
+ TRI = MF.getSubtarget().getRegisterInfo();
DomTree = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
MRI = &MF.getRegInfo();
diff --git a/llvm/test/CodeGen/AArch64/aarch64-condopt-cross-block-
diff erent-regs.mir b/llvm/test/CodeGen/AArch64/aarch64-condopt-cross-block-
diff erent-regs.mir
new file mode 100644
index 0000000000000..5ddb478ce4e8a
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/aarch64-condopt-cross-block-
diff erent-regs.mir
@@ -0,0 +1,128 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=aarch64-linux-gnu -run-pass=aarch64-condopt -verify-machineinstrs %s -o - | FileCheck %s
+
+# Test that the cross-block condition optimisation in aarch64-condopt does not
+# modify compares that use
diff erent registers.
+#
+# This MIR test uses virtual registers that trace back to
diff erent physical
+# registers via COPY, exercising the lookThruCopyLike() logic.
+
+---
+# Negative test: cross-block compares with
diff erent source registers should
+# NOT be optimised. %0 traces to $w0, %1 traces to $w1.
+name: cross_block_
diff erent_regs
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gpr32sp }
+ - { id: 1, class: gpr32sp }
+body: |
+ ; CHECK-LABEL: name: cross_block_
diff erent_regs
+ ; CHECK: bb.0:
+ ; CHECK-NEXT: successors: %bb.1(0x40000000), %bb.2(0x40000000)
+ ; CHECK-NEXT: liveins: $w0, $w1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr32sp = COPY $w0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr32sp = COPY $w1
+ ; CHECK-NEXT: dead $wzr = SUBSWri [[COPY]], 11, 0, implicit-def $nzcv
+ ; CHECK-NEXT: Bcc 11, %bb.1, implicit $nzcv
+ ; CHECK-NEXT: B %bb.2
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.1:
+ ; CHECK-NEXT: successors: %bb.2(0x40000000), %bb.3(0x40000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: dead $wzr = SUBSWri [[COPY1]], 10, 0, implicit-def $nzcv
+ ; CHECK-NEXT: Bcc 11, %bb.3, implicit $nzcv
+ ; CHECK-NEXT: B %bb.2
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.2:
+ ; CHECK-NEXT: $w0 = MOVi32imm 0
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.3:
+ ; CHECK-NEXT: $w0 = MOVi32imm 1
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ bb.0:
+ liveins: $w0, $w1
+ successors: %bb.1, %bb.2
+
+ %0:gpr32sp = COPY $w0
+ %1:gpr32sp = COPY $w1
+ dead $wzr = SUBSWri %0, 11, 0, implicit-def $nzcv
+ Bcc 11, %bb.1, implicit $nzcv
+ B %bb.2
+
+ bb.1:
+ successors: %bb.2, %bb.3
+
+ dead $wzr = SUBSWri %1, 10, 0, implicit-def $nzcv
+ Bcc 11, %bb.3, implicit $nzcv
+ B %bb.2
+
+ bb.2:
+ $w0 = MOVi32imm 0
+ RET_ReallyLR implicit $w0
+
+ bb.3:
+ $w0 = MOVi32imm 1
+ RET_ReallyLR implicit $w0
+...
+
+---
+# Positive test: cross-block compares with the SAME source register SHOULD be
+# optimised. Both %0 and %1 trace back to $w0.
+name: cross_block_same_reg
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gpr32sp }
+ - { id: 1, class: gpr32sp }
+body: |
+ ; CHECK-LABEL: name: cross_block_same_reg
+ ; CHECK: bb.0:
+ ; CHECK-NEXT: successors: %bb.1(0x40000000), %bb.2(0x40000000)
+ ; CHECK-NEXT: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr32sp = COPY $w0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr32sp = COPY $w0
+ ; CHECK-NEXT: dead $wzr = SUBSWri [[COPY]], 10, 0, implicit-def $nzcv
+ ; CHECK-NEXT: Bcc 13, %bb.1, implicit $nzcv
+ ; CHECK-NEXT: B %bb.2
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.1:
+ ; CHECK-NEXT: successors: %bb.2(0x40000000), %bb.3(0x40000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: dead $wzr = SUBSWri [[COPY1]], 10, 0, implicit-def $nzcv
+ ; CHECK-NEXT: Bcc 11, %bb.3, implicit $nzcv
+ ; CHECK-NEXT: B %bb.2
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.2:
+ ; CHECK-NEXT: $w0 = MOVi32imm 0
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.3:
+ ; CHECK-NEXT: $w0 = MOVi32imm 1
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ bb.0:
+ liveins: $w0
+ successors: %bb.1, %bb.2
+
+ %0:gpr32sp = COPY $w0
+ %1:gpr32sp = COPY $w0
+ dead $wzr = SUBSWri %0, 11, 0, implicit-def $nzcv
+ Bcc 11, %bb.1, implicit $nzcv
+ B %bb.2
+
+ bb.1:
+ successors: %bb.2, %bb.3
+
+ dead $wzr = SUBSWri %1, 10, 0, implicit-def $nzcv
+ Bcc 11, %bb.3, implicit $nzcv
+ B %bb.2
+
+ bb.2:
+ $w0 = MOVi32imm 0
+ RET_ReallyLR implicit $w0
+
+ bb.3:
+ $w0 = MOVi32imm 1
+ RET_ReallyLR implicit $w0
+...
diff --git a/llvm/test/CodeGen/AArch64/combine-comparisons-by-cse.ll b/llvm/test/CodeGen/AArch64/combine-comparisons-by-cse.ll
index 4449c2b9193a4..c261013303aa8 100644
--- a/llvm/test/CodeGen/AArch64/combine-comparisons-by-cse.ll
+++ b/llvm/test/CodeGen/AArch64/combine-comparisons-by-cse.ll
@@ -949,6 +949,75 @@ return: ; preds = %if.end, %land.lhs.t
ret i32 %retval.0
}
+; Negative test: cross-block with
diff erent registers should not be optimized.
+; Identical to combine_gt_ge_10, but lor.lhs.false compares @b instead of @a.
+; (a > 10 && b == c) || (b >= 10 && b == d)
+define i32 @combine_gt_ge_
diff erent_regs() #0 {
+; CHECK-LABEL: combine_gt_ge_
diff erent_regs:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: adrp x8, :got:a
+; CHECK-NEXT: ldr x8, [x8, :got_lo12:a]
+; CHECK-NEXT: ldr w10, [x8]
+; CHECK-NEXT: adrp x8, :got:b
+; CHECK-NEXT: ldr x8, [x8, :got_lo12:b]
+; CHECK-NEXT: cmp w10, #11
+; CHECK-NEXT: ldr w9, [x8]
+; CHECK-NEXT: b.lt .LBB15_3
+; CHECK-NEXT: // %bb.1: // %land.lhs.true
+; CHECK-NEXT: adrp x10, :got:c
+; CHECK-NEXT: ldr x10, [x10, :got_lo12:c]
+; CHECK-NEXT: ldr w10, [x10]
+; CHECK-NEXT: cmp w9, w10
+; CHECK-NEXT: b.ne .LBB15_4
+; CHECK-NEXT: // %bb.2:
+; CHECK-NEXT: mov w0, #1 // =0x1
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB15_3: // %lor.lhs.false
+; CHECK-NEXT: cmp w9, #10
+; CHECK-NEXT: b.lt .LBB15_6
+; CHECK-NEXT: .LBB15_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 .LBB15_6
+; CHECK-NEXT: // %bb.5:
+; CHECK-NEXT: mov w0, #1 // =0x1
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB15_6: // %if.end
+; CHECK-NEXT: mov w0, wzr
+; CHECK-NEXT: ret
+entry:
+ %0 = load i32, ptr @a, align 4
+ %cmp = icmp sgt i32 %0, 10
+ br i1 %cmp, label %land.lhs.true, label %lor.lhs.false
+
+land.lhs.true: ; preds = %entry
+ %1 = load i32, ptr @b, align 4
+ %2 = load i32, ptr @c, align 4
+ %cmp1 = icmp eq i32 %1, %2
+ br i1 %cmp1, label %return, label %land.lhs.true3
+
+lor.lhs.false: ; preds = %entry
+ %3 = load i32, ptr @b, align 4
+ %cmp2 = icmp sgt i32 %3, 9
+ br i1 %cmp2, label %land.lhs.true3, label %if.end
+
+land.lhs.true3: ; preds = %lor.lhs.false, %land.lhs.true
+ %4 = load i32, ptr @b, align 4
+ %5 = load i32, ptr @d, align 4
+ %cmp4 = icmp eq i32 %4, %5
+ br i1 %cmp4, label %return, label %if.end
+
+if.end: ; preds = %land.lhs.true3, %lor.lhs.false
+ br label %return
+
+return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true
+ %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ]
+ ret i32 %retval.0
+}
+
declare i32 @zoo(i32)
declare double @yoo(i32)
More information about the llvm-commits
mailing list