[llvm-branch-commits] [llvm] RegisterPressure: Detect dead physreg defs from LiveIntervals with lane masks (PR #233215)

Matt Arsenault via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sun Oct 18 02:41:50 PDT 2026


https://github.com/arsenm created https://github.com/llvm/llvm-project/pull/233215

Extend the fix from #225079 to the lane mask tracking path used by
targets with subregister liveness. adjustLaneLiveness also needs to
force the physreg unit ranges to be computed to identify dead defs,
rather than taking the conservative default when they are not cached.

Without this, an overlapping physreg def missing a dead flag is
counted as a live def. Conservatively assuming it is live doesn't work
because PressureDiff disagrees with the tracker and fails the
EXPENSIVE_CHECKS consistency assert.

This avoids an ll asm test failing when LiveVariables removed; #233202
fixes the missing dead flag for that case. I had additional patches
which nearly eliminate all missing dead flags. Unless the verifier
enforces accurate dead flags, we still need to handle this edge case.

Co-authored-by: Claude Opus 5.5 <noreply at anthropic.com>

>From e3b7c6a087a3f3824ebd3fcc50a7e4bcb5ae3340 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Sun, 18 Oct 2026 11:01:14 +0200
Subject: [PATCH] RegisterPressure: Detect dead physreg defs from LiveIntervals
 with lane masks

Extend the fix from #225079 to the lane mask tracking path used by
targets with subregister liveness. adjustLaneLiveness also needs to
force the physreg unit ranges to be computed to identify dead defs,
rather than taking the conservative default when they are not cached.

Without this, an overlapping physreg def missing a dead flag is
counted as a live def. Conservatively assuming it is live doesn't work
because PressureDiff disagrees with the tracker and fails the
EXPENSIVE_CHECKS consistency assert.

This avoids an ll asm test failing when LiveVariables removed; #233202
fixes the missing dead flag for that case. I had additional patches
which nearly eliminate all missing dead flags. Unless the verifier
enforces accurate dead flags, we still need to handle this edge case.

Co-authored-by: Claude Opus 5.5 <noreply at anthropic.com>
---
 llvm/lib/CodeGen/RegisterPressure.cpp         | 10 ++++---
 .../AMDGPU/debug-value-scheduler-crash.mir    |  2 +-
 ...le-pressure-unflagged-dead-physreg-def.mir | 30 +++++++++++++++++++
 3 files changed, 37 insertions(+), 5 deletions(-)
 create mode 100644 llvm/test/CodeGen/AMDGPU/schedule-pressure-unflagged-dead-physreg-def.mir

diff --git a/llvm/lib/CodeGen/RegisterPressure.cpp b/llvm/lib/CodeGen/RegisterPressure.cpp
index f6fac16b01b641..b935b4c29ea69d 100644
--- a/llvm/lib/CodeGen/RegisterPressure.cpp
+++ b/llvm/lib/CodeGen/RegisterPressure.cpp
@@ -593,8 +593,9 @@ void RegisterOperands::adjustLaneLiveness(LiveIntervals &LIS,
                                           const MachineRegisterInfo &MRI,
                                           SlotIndex Pos) {
   for (auto *I = Defs.begin(); I != Defs.end(); /*empty*/) {
-    LaneBitmask LiveAfter = getLiveLanesAt(LIS, MRI, /*TrackLaneMasks=*/true,
-                                           I->VRegOrUnit, Pos.getDeadSlot());
+    LaneBitmask LiveAfter =
+        getLiveLanesAt(LIS, MRI, /*TrackLaneMasks=*/true, I->VRegOrUnit,
+                       Pos.getDeadSlot(), /*ComputePhysRegs=*/true);
     I = adjustDef(*I, LiveAfter);
   }
   adjustUses(LIS, MRI, Pos.getBaseIndex());
@@ -605,8 +606,9 @@ void RegisterOperands::adjustLaneLiveness(LiveIntervals &LIS,
                                           MachineInstr &MI) {
   SlotIndex Pos = LIS.getInstructionIndex(MI);
   for (auto *I = Defs.begin(); I != Defs.end(); /*empty*/) {
-    LaneBitmask LiveAfter = getLiveLanesAt(LIS, MRI, /*TrackLaneMasks=*/true,
-                                           I->VRegOrUnit, Pos.getDeadSlot());
+    LaneBitmask LiveAfter =
+        getLiveLanesAt(LIS, MRI, /*TrackLaneMasks=*/true, I->VRegOrUnit,
+                       Pos.getDeadSlot(), /*ComputePhysRegs=*/true);
     // If the def is all that is live after the instruction, then in case
     // of a subregister def we need a read-undef flag.
     VirtRegOrUnit VRegOrUnit = I->VRegOrUnit;
diff --git a/llvm/test/CodeGen/AMDGPU/debug-value-scheduler-crash.mir b/llvm/test/CodeGen/AMDGPU/debug-value-scheduler-crash.mir
index 1120d125a05e4d..04d17bd456b251 100644
--- a/llvm/test/CodeGen/AMDGPU/debug-value-scheduler-crash.mir
+++ b/llvm/test/CodeGen/AMDGPU/debug-value-scheduler-crash.mir
@@ -71,7 +71,7 @@ body:             |
   ; CHECK-NEXT:   $vgpr0 = COPY [[V_MUL_F32_e32_1]]
   ; CHECK-NEXT:   $vgpr1 = COPY [[V_MUL_F32_e32_2]]
   ; CHECK-NEXT:   $vgpr2 = COPY [[V_MUL_F32_e32_3]]
-  ; CHECK-NEXT:   dead $sgpr30_sgpr31 = SI_CALL [[DEF13]], @foo, csr_amdgpu, implicit undef $sgpr0_sgpr1_sgpr2_sgpr3, implicit killed $sgpr4, implicit $vgpr0, implicit $vgpr1, implicit $vgpr2, implicit-def $vgpr0
+  ; CHECK-NEXT:   dead $sgpr30_sgpr31 = SI_CALL [[DEF13]], @foo, csr_amdgpu, implicit undef $sgpr0_sgpr1_sgpr2_sgpr3, implicit $sgpr4, implicit $vgpr0, implicit $vgpr1, implicit $vgpr2, implicit-def $vgpr0
   ; CHECK-NEXT:   [[V_ADD_F32_e32_1:%[0-9]+]]:vgpr_32 = nofpexcept V_ADD_F32_e32 [[V_MUL_F32_e32_]], [[DEF7]], implicit $mode, implicit $exec
   ; CHECK-NEXT:   [[V_ADD_F32_e32_1:%[0-9]+]]:vgpr_32 = nofpexcept V_MAC_F32_e32 [[DEF11]], [[DEF8]], [[V_ADD_F32_e32_1]], implicit $mode, implicit $exec
   ; CHECK-NEXT:   dead [[V_MAD_F32_e64_:%[0-9]+]]:vgpr_32 = nofpexcept V_MAD_F32_e64 0, [[V_ADD_F32_e32_1]], 0, [[DEF3]], 0, [[DEF]], 0, 0, implicit $mode, implicit $exec
diff --git a/llvm/test/CodeGen/AMDGPU/schedule-pressure-unflagged-dead-physreg-def.mir b/llvm/test/CodeGen/AMDGPU/schedule-pressure-unflagged-dead-physreg-def.mir
new file mode 100644
index 00000000000000..a1158c53302b83
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/schedule-pressure-unflagged-dead-physreg-def.mir
@@ -0,0 +1,30 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# REQUIRES: expensive_checks
+# RUN: llc -mtriple=amdgpu9.00-amd-amdhsa -passes=machine-scheduler %s -o - | FileCheck %s
+
+# The clobber is dead except for $vgpr1 but has no dead flag. Its dead
+# lanes must be found from LiveIntervals with lane mask tracking.
+
+---
+name:            unflagged_dead_clobber
+tracksRegLiveness: true
+machineFunctionInfo:
+  occupancy:       6
+body:             |
+  bb.0:
+    ; CHECK-LABEL: name: unflagged_dead_clobber
+    ; CHECK: [[DEF:%[0-9]+]]:vreg_128 = IMPLICIT_DEF
+    ; CHECK-NEXT: [[DEF1:%[0-9]+]]:vreg_128 = IMPLICIT_DEF
+    ; CHECK-NEXT: INLINEASM &"; copy", sideeffect attdialect, regdef, implicit-def $vgpr1, reguse:VReg_128, [[DEF]], clobber, implicit-def early-clobber $vgpr0_vgpr1_vgpr2_vgpr3
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:vgpr_32 = COPY $vgpr1
+    ; CHECK-NEXT: $vgpr0_vgpr1_vgpr2_vgpr3 = COPY [[DEF1]]
+    ; CHECK-NEXT: INLINEASM &"; use", sideeffect attdialect, reguse:VGPR_32, [[COPY]], reguse, $vgpr0_vgpr1_vgpr2_vgpr3
+    ; CHECK-NEXT: SI_RETURN
+    %0:vreg_128 = IMPLICIT_DEF
+    %1:vreg_128 = IMPLICIT_DEF
+    INLINEASM &"; copy", sideeffect attdialect, regdef, implicit-def $vgpr1, reguse:VReg_128, %0, clobber, implicit-def early-clobber $vgpr0_vgpr1_vgpr2_vgpr3
+    %2:vgpr_32 = COPY killed $vgpr1
+    $vgpr0_vgpr1_vgpr2_vgpr3 = COPY %1
+    INLINEASM &"; use", sideeffect attdialect, reguse:VGPR_32, %2, reguse, $vgpr0_vgpr1_vgpr2_vgpr3
+    SI_RETURN
+...



More information about the llvm-branch-commits mailing list