[llvm] [CodeGen] Fix fixupKills incorrectly killing sub-registers via super-register implicit defs (PR #181518)

via llvm-commits llvm-commits at lists.llvm.org
Sat Feb 14 17:00:51 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-hexagon

Author: Brian Cain (androm3da)

<details>
<summary>Changes</summary>



fixupKills() walks backward through instructions, removing defined registers from a LiveRegUnits set, then checking which used registers are "available" (dead) to set kill flags. When an instruction defines a sub-register (e.g. $r1) and has an implicit-def of its super-register ($d0), removeReg($d0) clears the register units of all sub-registers — including siblings like $r0 that may still be live. This causes available($r0) to incorrectly return true, setting a wrong kill flag.

Skip removeReg for implicit defs of super-registers when a sub-register is also defined by the same instruction. The implicit def is an annotation of partial modification, not a full redefinition of the super-register.

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


2 Files Affected:

- (modified) llvm/lib/CodeGen/ScheduleDAGInstrs.cpp (+20) 
- (added) llvm/test/CodeGen/Hexagon/post-ra-kill-superreg-def.mir (+36) 


``````````diff
diff --git a/llvm/lib/CodeGen/ScheduleDAGInstrs.cpp b/llvm/lib/CodeGen/ScheduleDAGInstrs.cpp
index 9662511e584c0..4dbb348ca5c22 100644
--- a/llvm/lib/CodeGen/ScheduleDAGInstrs.cpp
+++ b/llvm/lib/CodeGen/ScheduleDAGInstrs.cpp
@@ -1163,6 +1163,26 @@ void ScheduleDAGInstrs::fixupKills(MachineBasicBlock &MBB) {
         Register Reg = MO.getReg();
         if (!Reg)
           continue;
+        // Skip implicit defs of super-registers when a sub-register is
+        // also defined by this instruction. The implicit def indicates a
+        // partial modification of the super-register, not a full
+        // redefinition. Removing the super-register from the live set
+        // would incorrectly clear the liveness of sibling sub-registers
+        // that may still be live, causing toggleKills to set wrong kill
+        // flags on their uses.
+        if (MO.isImplicit()) {
+          bool HasSubRegDef = false;
+          for (ConstMIBundleOperands O2(MI); O2.isValid(); ++O2) {
+            if (!O2->isReg() || !O2->isDef() || !O2->getReg())
+              continue;
+            if (O2->getReg() != Reg && TRI->isSubRegister(Reg, O2->getReg())) {
+              HasSubRegDef = true;
+              break;
+            }
+          }
+          if (HasSubRegDef)
+            continue;
+        }
         LiveRegs.removeReg(Reg);
       } else if (MO.isRegMask()) {
         LiveRegs.removeRegsNotPreserved(MO.getRegMask());
diff --git a/llvm/test/CodeGen/Hexagon/post-ra-kill-superreg-def.mir b/llvm/test/CodeGen/Hexagon/post-ra-kill-superreg-def.mir
new file mode 100644
index 0000000000000..1d899fcdacf30
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/post-ra-kill-superreg-def.mir
@@ -0,0 +1,36 @@
+# RUN: llc -mtriple=hexagon -mcpu=hexagonv60 -run-pass post-RA-sched \
+# RUN:   -verify-machineinstrs -o - %s | FileCheck %s
+
+# The fixupKills() function in ScheduleDAGInstrs walks backward through
+# instructions, maintaining a LiveRegUnits bitvector. When an instruction
+# defines a sub-register ($r1) and has an implicit-def of a super-register
+# ($d0), the def processing calls removeReg($d0), which clears the register
+# units of all sub-registers of $d0 — including $r0. If $r0 is live (used
+# by a subsequent instruction), its liveness is incorrectly cleared, causing
+# available($r0) to return true and a wrong kill flag to be set.
+#
+# In this test, A2_abs defines $r1 with an implicit-def of $d0. The
+# subsequent A2_add uses both $r0 and $r1, so $r0 must not be killed
+# on the A2_abs instruction.
+
+# CHECK-LABEL: name: test_kill_superreg_def
+# CHECK: $r1 = A2_abs $r0, implicit-def $d0
+# CHECK-NEXT: $r0 = A2_add killed $r0, killed $r1
+
+--- |
+  define void @test_kill_superreg_def() {
+    ret void
+  }
+...
+
+---
+name: test_kill_superreg_def
+tracksRegLiveness: true
+body: |
+  bb.0:
+    liveins: $r0
+
+    $r1 = A2_abs $r0, implicit-def $d0
+    $r0 = A2_add $r0, $r1
+    PS_jmpret $r31, implicit-def dead $pc, implicit $r0
+...

``````````

</details>


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


More information about the llvm-commits mailing list