[llvm] ARM: Avoid relying on kill flags for determining CPSR liveness (PR #222873)

via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 11 00:53:55 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-arm

Author: Matt Arsenault (arsenm)

<details>
<summary>Changes</summary>

When forming CBZ/CBNZ in ARMConstantIslands, check if CPSR is live-out
of the block instead of relying on the kill flag. Kill flags have been
soft deprecated for over a decade.

Co-authored-by: Claude claude-opus-4.8 <noreply@<!-- -->anthropic.com>

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


2 Files Affected:

- (modified) llvm/lib/Target/ARM/ARMConstantIslandPass.cpp (+8-4) 
- (added) llvm/test/CodeGen/ARM/cbz-no-kill-flag.mir (+132) 


``````````diff
diff --git a/llvm/lib/Target/ARM/ARMConstantIslandPass.cpp b/llvm/lib/Target/ARM/ARMConstantIslandPass.cpp
index 97db51129cff2..f3961ba260d7b 100644
--- a/llvm/lib/Target/ARM/ARMConstantIslandPass.cpp
+++ b/llvm/lib/Target/ARM/ARMConstantIslandPass.cpp
@@ -1908,10 +1908,14 @@ bool ARMConstantIslands::optimizeThumb2Branches() {
     ImmCmp.MI = nullptr;
     ImmCmp.NewOpc = 0;
 
-    // If the conditional branch doesn't kill CPSR, then CPSR can be liveout
-    // so this transformation is not safe.
-    if (!Br.MI->killsRegister(ARM::CPSR, /*TRI=*/nullptr))
-      return false;
+    // Folding the compare into a CBZ/CBNZ clobbers the comparison, so it is not
+    // safe if CPSR is live past the branch.
+    //
+    // TODO: This could be safe if it's only live into this branch's target.
+    for (const MachineBasicBlock *Succ : Br.MI->getParent()->successors()) {
+      if (Succ->isLiveIn(ARM::CPSR))
+        return false;
+    }
 
     Register PredReg;
     unsigned NewOpc = 0;
diff --git a/llvm/test/CodeGen/ARM/cbz-no-kill-flag.mir b/llvm/test/CodeGen/ARM/cbz-no-kill-flag.mir
new file mode 100644
index 0000000000000..2957d9c642694
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/cbz-no-kill-flag.mir
@@ -0,0 +1,132 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=thumbv8m.base -run-pass=arm-cp-islands -o - %s | FileCheck %s
+
+# ARMConstantIslands forms a CBZ/CBNZ from a tCMPi8 + conditional
+# branch only when CPSR is not live past the branch. Determine this
+# from block liveness rather than a kill flag on the branch
+
+---
+name:            cbz_no_kill_flag
+tracksRegLiveness: true
+body:             |
+  ; CHECK-LABEL: name: cbz_no_kill_flag
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.2(0x40000000), %bb.1(0x40000000)
+  ; CHECK-NEXT:   liveins: $r0
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   tCBZ renamable $r0, %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.2(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   renamable $r0, dead $cpsr = tMOVi8 3, 14 /* CC::al */, $noreg
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.entry:
+  ; CHECK-NEXT:   liveins: $r0
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   tBX_RET 14 /* CC::al */, $noreg, implicit $r0
+  bb.0.entry:
+    successors: %bb.2, %bb.1
+    liveins: $r0
+
+    tCMPi8 renamable $r0, 0, 14 /* CC::al */, $noreg, implicit-def $cpsr
+    tBcc %bb.2, 0 /* CC::eq */, $cpsr
+
+  bb.1:
+    successors: %bb.2
+
+    renamable $r0, dead $cpsr = tMOVi8 3, 14 /* CC::al */, $noreg
+
+  bb.2.entry:
+    liveins: $r0
+
+    tBX_RET 14 /* CC::al */, $noreg, implicit $r0
+...
+
+# Negative test: CPSR is live out of the branch's block so the compare
+# must not be folded into a CBZ/CBNZ.
+---
+name:            cpsr_live_out
+tracksRegLiveness: true
+body:             |
+  ; CHECK-LABEL: name: cpsr_live_out
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.2(0x40000000), %bb.1(0x40000000)
+  ; CHECK-NEXT:   liveins: $r0, $r1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   tCMPi8 renamable $r0, 0, 14 /* CC::al */, $noreg, implicit-def $cpsr
+  ; CHECK-NEXT:   tBcc %bb.2, 0 /* CC::eq */, $cpsr
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.2(0x80000000)
+  ; CHECK-NEXT:   liveins: $r0, $r1, $cpsr
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   renamable $r0, dead $cpsr = tADC renamable $r0, renamable $r1, 14 /* CC::al */, $noreg, implicit $cpsr
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.entry:
+  ; CHECK-NEXT:   liveins: $r0
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   tBX_RET 14 /* CC::al */, $noreg, implicit $r0
+  bb.0.entry:
+    successors: %bb.2, %bb.1
+    liveins: $r0, $r1
+
+    tCMPi8 renamable $r0, 0, 14 /* CC::al */, $noreg, implicit-def $cpsr
+    tBcc %bb.2, 0 /* CC::eq */, $cpsr
+
+  bb.1:
+    successors: %bb.2
+    liveins: $r0, $r1, $cpsr
+
+    renamable $r0, dead $cpsr = tADC renamable $r0, renamable $r1, 14 /* CC::al */, $noreg, implicit $cpsr
+
+  bb.2.entry:
+    liveins: $r0
+
+    tBX_RET 14 /* CC::al */, $noreg, implicit $r0
+...
+
+# Negative test: CPSR is live out through the tBcc's branch, but not
+# the other successor.
+#
+# TODO: This is a missed optimization.
+---
+name:            cpsr_live_out_branch_target
+tracksRegLiveness: true
+body:             |
+  ; CHECK-LABEL: name: cpsr_live_out_branch_target
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.2(0x40000000), %bb.1(0x40000000)
+  ; CHECK-NEXT:   liveins: $r0, $r1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   tCMPi8 renamable $r0, 0, 14 /* CC::al */, $noreg, implicit-def $cpsr
+  ; CHECK-NEXT:   tBcc %bb.2, 0 /* CC::eq */, $cpsr
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   liveins: $r0
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   tBX_RET 14 /* CC::al */, $noreg, implicit $r0
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.entry:
+  ; CHECK-NEXT:   liveins: $r0, $r1, $cpsr
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   renamable $r0, dead $cpsr = tADC renamable $r0, renamable $r1, 14 /* CC::al */, $noreg, implicit $cpsr
+  ; CHECK-NEXT:   tBX_RET 14 /* CC::al */, $noreg, implicit $r0
+  bb.0.entry:
+    successors: %bb.2, %bb.1
+    liveins: $r0, $r1
+
+    tCMPi8 renamable $r0, 0, 14 /* CC::al */, $noreg, implicit-def $cpsr
+    tBcc %bb.2, 0 /* CC::eq */, $cpsr
+
+  bb.1:
+    liveins: $r0
+
+    tBX_RET 14 /* CC::al */, $noreg, implicit $r0
+
+  bb.2.entry:
+    liveins: $r0, $r1, $cpsr
+
+    renamable $r0, dead $cpsr = tADC renamable $r0, renamable $r1, 14 /* CC::al */, $noreg, implicit $cpsr
+    tBX_RET 14 /* CC::al */, $noreg, implicit $r0
+...

``````````

</details>


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


More information about the llvm-commits mailing list