[llvm] [LiveRegUnits] Exclude runtime defined liveins when computing liveouts (PR #154325)

Benjamin Maxwell via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 20 03:19:07 PDT 2025


https://github.com/MacDue updated https://github.com/llvm/llvm-project/pull/154325

>From e809e3b10da959b63d5905f8503b0d1a61e3ee4c Mon Sep 17 00:00:00 2001
From: Benjamin Maxwell <benjamin.maxwell at arm.com>
Date: Tue, 19 Aug 2025 12:47:30 +0000
Subject: [PATCH 1/3] [AArch64][SME] Exclude runtime defined liveins when
 computing liveouts

These liveins are not defined by predecessors, so attempting to preserve
them results in generating invalid MIR (as the registers may not be
defined). This takes a similar approach to: https://github.com/llvm/llvm-project/commit/c1dc267258e06bb69e1ca217d1d8ce2d15b8757f
---
 llvm/include/llvm/CodeGen/LiveRegUnits.h      |  8 +-
 llvm/lib/CodeGen/LiveRegUnits.cpp             | 26 +++++-
 llvm/lib/Target/AArch64/MachineSMEABIPass.cpp |  2 +-
 .../CodeGen/AArch64/sme-abi-eh-liveins.mir    | 82 +++++++++++++++++++
 .../test/CodeGen/AArch64/sme-za-exceptions.ll |  9 +-
 5 files changed, 113 insertions(+), 14 deletions(-)
 create mode 100644 llvm/test/CodeGen/AArch64/sme-abi-eh-liveins.mir

diff --git a/llvm/include/llvm/CodeGen/LiveRegUnits.h b/llvm/include/llvm/CodeGen/LiveRegUnits.h
index 37c31cc6f4ac5..f58188377b520 100644
--- a/llvm/include/llvm/CodeGen/LiveRegUnits.h
+++ b/llvm/include/llvm/CodeGen/LiveRegUnits.h
@@ -26,6 +26,7 @@ namespace llvm {
 
 class MachineInstr;
 class MachineBasicBlock;
+class TargetLowering;
 
 /// A set of register units used to track register liveness.
 class LiveRegUnits {
@@ -135,8 +136,11 @@ class LiveRegUnits {
   /// Adds registers living out of block \p MBB.
   /// Live out registers are the union of the live-in registers of the successor
   /// blocks and pristine registers. Live out registers of the end block are the
-  /// callee saved registers.
-  LLVM_ABI void addLiveOuts(const MachineBasicBlock &MBB);
+  /// callee saved registers. If the target lowering information \p TLI is
+  /// provided, runtime-defined live ins of successors will be excluded from the
+  /// live outs.
+  LLVM_ABI void addLiveOuts(const MachineBasicBlock &MBB,
+                            const TargetLowering *TLI = nullptr);
 
   /// Adds registers living into block \p MBB.
   LLVM_ABI void addLiveIns(const MachineBasicBlock &MBB);
diff --git a/llvm/lib/CodeGen/LiveRegUnits.cpp b/llvm/lib/CodeGen/LiveRegUnits.cpp
index 34de09dd2944b..c034d5f3925fc 100644
--- a/llvm/lib/CodeGen/LiveRegUnits.cpp
+++ b/llvm/lib/CodeGen/LiveRegUnits.cpp
@@ -16,6 +16,7 @@
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineOperand.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/TargetLowering.h"
 
 using namespace llvm;
 
@@ -86,9 +87,15 @@ void LiveRegUnits::accumulate(const MachineInstr &MI) {
 
 /// Add live-in registers of basic block \p MBB to \p LiveUnits.
 static void addBlockLiveIns(LiveRegUnits &LiveUnits,
-                            const MachineBasicBlock &MBB) {
-  for (const auto &LI : MBB.liveins())
+                            const MachineBasicBlock &MBB,
+                            MCPhysReg ExceptionPointer = {},
+                            MCPhysReg ExceptionSelector = {}) {
+  for (const auto &LI : MBB.liveins()) {
+    if (MBB.isEHPad() &&
+        (LI.PhysReg == ExceptionPointer || LI.PhysReg == ExceptionSelector))
+      continue;
     LiveUnits.addRegMasked(LI.PhysReg, LI.LaneMask);
+  }
 }
 
 /// Adds all callee saved registers to \p LiveUnits.
@@ -135,14 +142,25 @@ void LiveRegUnits::addPristines(const MachineFunction &MF) {
   addUnits(Pristine.getBitVector());
 }
 
-void LiveRegUnits::addLiveOuts(const MachineBasicBlock &MBB) {
+void LiveRegUnits::addLiveOuts(const MachineBasicBlock &MBB,
+                               const TargetLowering *TLI) {
   const MachineFunction &MF = *MBB.getParent();
 
   addPristines(MF);
 
+  MCPhysReg ExceptionPointer;
+  MCPhysReg ExceptionSelector;
+
+  // Remove live-ins from successors that are defined by the runtime.
+  if (TLI && MF.getFunction().hasPersonalityFn()) {
+    auto PersonalityFn = MF.getFunction().getPersonalityFn();
+    ExceptionPointer = TLI->getExceptionPointerRegister(PersonalityFn);
+    ExceptionSelector = TLI->getExceptionSelectorRegister(PersonalityFn);
+  }
+
   // To get the live-outs we simply merge the live-ins of all successors.
   for (const MachineBasicBlock *Succ : MBB.successors())
-    addBlockLiveIns(*this, *Succ);
+    addBlockLiveIns(*this, *Succ, ExceptionPointer, ExceptionSelector);
 
   // For the return block: Add all callee saved registers.
   if (MBB.isReturnBlock()) {
diff --git a/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp b/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp
index b58dfdf32e4ab..2f00977e9a1cc 100644
--- a/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp
+++ b/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp
@@ -277,7 +277,7 @@ void MachineSMEABI::collectNeededZAStates(SMEAttrs SMEFnAttrs) {
     }
 
     LiveRegUnits LiveUnits(*TRI);
-    LiveUnits.addLiveOuts(MBB);
+    LiveUnits.addLiveOuts(MBB, Subtarget->getTargetLowering());
 
     auto GetPhysLiveRegs = [&] {
       LiveRegs PhysLiveRegs = LiveRegs::None;
diff --git a/llvm/test/CodeGen/AArch64/sme-abi-eh-liveins.mir b/llvm/test/CodeGen/AArch64/sme-abi-eh-liveins.mir
new file mode 100644
index 0000000000000..711745e528bbf
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/sme-abi-eh-liveins.mir
@@ -0,0 +1,82 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
+# RUN: llc -mtriple=aarch64 -mattr=+sve -mattr=+sme -run-pass=aarch64-machine-sme-abi -verify-machineinstrs %s -o - | FileCheck %s
+
+# This test verifies that runtime defined live-ins are not included in the live
+# outs of predecessors in the MachineSMEABIPass, as including them would result
+# in copies of undefined registers.
+
+--- |
+  define void @sme_abi_eh_liveins() "aarch64_inout_za" personality ptr @__gxx_personality_v0 { entry: unreachable }
+
+  declare i32 @__gxx_personality_v0(...)
+...
+---
+name:            sme_abi_eh_liveins
+tracksRegLiveness: true
+isSSA:           true
+noVRegs:         false
+
+body:             |
+  ; CHECK-LABEL: name: sme_abi_eh_liveins
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.2(0x00000000), %bb.1(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[RDSVLI_XI:%[0-9]+]]:gpr64 = RDSVLI_XI 1, implicit $vg
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr64 = COPY $sp
+  ; CHECK-NEXT:   [[MSUBXrrr:%[0-9]+]]:gpr64 = MSUBXrrr [[RDSVLI_XI]], [[RDSVLI_XI]], [[COPY]]
+  ; CHECK-NEXT:   $sp = COPY [[MSUBXrrr]]
+  ; CHECK-NEXT:   STPXi [[MSUBXrrr]], [[RDSVLI_XI]], %stack.0, 0
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def dead $sp, implicit $sp
+  ; CHECK-NEXT:   InOutZAUsePseudo
+  ; CHECK-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def dead $sp, implicit $sp
+  ; CHECK-NEXT:   [[ADDXri:%[0-9]+]]:gpr64sp = ADDXri %stack.0, 0, 0
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr64 = COPY [[ADDXri]]
+  ; CHECK-NEXT:   MSR 56965, [[COPY1]]
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def dead $sp, implicit $sp
+  ; CHECK-NEXT:   RequiresZASavePseudo
+  ; CHECK-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def dead $sp, implicit $sp
+  ; CHECK-NEXT:   MSRpstatesvcrImm1 2, 1, implicit-def $nzcv
+  ; CHECK-NEXT:   [[MRS:%[0-9]+]]:gpr64 = MRS 56965, implicit-def $nzcv
+  ; CHECK-NEXT:   $x0 = ADDXri %stack.0, 0, 0
+  ; CHECK-NEXT:   RestoreZAPseudo [[MRS]], $x0, &__arm_tpidr2_restore, csr_aarch64_sme_abi_support_routines_preservemost_from_x0
+  ; CHECK-NEXT:   MSR 56965, $xzr
+  ; CHECK-NEXT:   B %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1 (landing-pad):
+  ; CHECK-NEXT:   successors: %bb.2(0x80000000)
+  ; CHECK-NEXT:   liveins: $x0, $x1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   MSRpstatesvcrImm1 2, 1, implicit-def $nzcv
+  ; CHECK-NEXT:   [[MRS1:%[0-9]+]]:gpr64 = MRS 56965, implicit-def $nzcv
+  ; CHECK-NEXT:   $x0 = ADDXri %stack.0, 0, 0
+  ; CHECK-NEXT:   RestoreZAPseudo [[MRS1]], $x0, &__arm_tpidr2_restore, csr_aarch64_sme_abi_support_routines_preservemost_from_x0
+  ; CHECK-NEXT:   MSR 56965, $xzr
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def dead $sp, implicit $sp
+  ; CHECK-NEXT:   InOutZAUsePseudo
+  ; CHECK-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def dead $sp, implicit $sp
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  bb.0:
+    successors: %bb.2(0x00000000), %bb.1(0x80000000)
+
+    ; Simulate shared ZA call
+    ADJCALLSTACKDOWN 0, 0, implicit-def dead $sp, implicit $sp
+    InOutZAUsePseudo
+    ADJCALLSTACKUP 0, 0, implicit-def dead $sp, implicit $sp
+
+    ; Simulate private ZA call at the end of the block
+    ADJCALLSTACKDOWN 0, 0, implicit-def dead $sp, implicit $sp
+    RequiresZASavePseudo
+    ADJCALLSTACKUP 0, 0, implicit-def dead $sp, implicit $sp
+
+    B %bb.2
+
+  bb.1 (landing-pad):
+    liveins: $x0, $x1
+
+    ; Simulate shared ZA call
+    ADJCALLSTACKDOWN 0, 0, implicit-def dead $sp, implicit $sp
+    InOutZAUsePseudo
+    ADJCALLSTACKUP 0, 0, implicit-def dead $sp, implicit $sp
+
+  bb.2:
diff --git a/llvm/test/CodeGen/AArch64/sme-za-exceptions.ll b/llvm/test/CodeGen/AArch64/sme-za-exceptions.ll
index 7a3e246b530b0..bb88142efa592 100644
--- a/llvm/test/CodeGen/AArch64/sme-za-exceptions.ll
+++ b/llvm/test/CodeGen/AArch64/sme-za-exceptions.ll
@@ -1,9 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
 ; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sme -aarch64-new-sme-abi -verify-machineinstrs < %s | FileCheck %s
 
-; FIXME: XFAILs until https://github.com/llvm/llvm-project/pull/154325
-; XFAIL: *
-
 ; A simple EH test case that corresponds to the following C++ source:
 ;
 ; struct ZAResource {
@@ -65,16 +62,14 @@ define void @za_with_raii(i1 %fail) "aarch64_inout_za" personality ptr @__gxx_pe
 ; CHECK-NEXT:    ldr x1, [x1, :got_lo12:typeinfo_for_char_const_ptr]
 ; CHECK-NEXT:    bl __cxa_throw
 ; CHECK-NEXT:  .Ltmp1:
-; CHECK-NEXT:    mov x8, x0
 ; CHECK-NEXT:    smstart za
-; CHECK-NEXT:    mrs x9, TPIDR2_EL0
+; CHECK-NEXT:    mrs x8, TPIDR2_EL0
 ; CHECK-NEXT:    sub x0, x29, #16
-; CHECK-NEXT:    cbnz x9, .LBB0_4
+; CHECK-NEXT:    cbnz x8, .LBB0_4
 ; CHECK-NEXT:  // %bb.3: // %throw_exception
 ; CHECK-NEXT:    bl __arm_tpidr2_restore
 ; CHECK-NEXT:  .LBB0_4: // %throw_exception
 ; CHECK-NEXT:    msr TPIDR2_EL0, xzr
-; CHECK-NEXT:    // kill: def $x0 killed $x8
 ; CHECK-NEXT:  // %bb.5: // %throw_fail
 ; CHECK-NEXT:  .LBB0_6: // %unwind_dtors
 ; CHECK-NEXT:  .Ltmp2:

>From 9f64b69c76724cc4437fb27e479d78c7d12b0c56 Mon Sep 17 00:00:00 2001
From: Benjamin Maxwell <benjamin.maxwell at arm.com>
Date: Wed, 20 Aug 2025 09:23:20 +0000
Subject: [PATCH 2/3] Use MBB.liveouts()

---
 llvm/include/llvm/CodeGen/LiveRegUnits.h      |  7 ++--
 llvm/include/llvm/CodeGen/MachineBasicBlock.h |  4 +--
 llvm/lib/CodeGen/LiveRegUnits.cpp             | 36 ++++++-------------
 llvm/lib/CodeGen/MachineBasicBlock.cpp        |  3 --
 llvm/lib/Target/AArch64/MachineSMEABIPass.cpp |  2 +-
 5 files changed, 16 insertions(+), 36 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/LiveRegUnits.h b/llvm/include/llvm/CodeGen/LiveRegUnits.h
index f58188377b520..cf0b3521754ef 100644
--- a/llvm/include/llvm/CodeGen/LiveRegUnits.h
+++ b/llvm/include/llvm/CodeGen/LiveRegUnits.h
@@ -136,11 +136,8 @@ class LiveRegUnits {
   /// Adds registers living out of block \p MBB.
   /// Live out registers are the union of the live-in registers of the successor
   /// blocks and pristine registers. Live out registers of the end block are the
-  /// callee saved registers. If the target lowering information \p TLI is
-  /// provided, runtime-defined live ins of successors will be excluded from the
-  /// live outs.
-  LLVM_ABI void addLiveOuts(const MachineBasicBlock &MBB,
-                            const TargetLowering *TLI = nullptr);
+  /// callee saved registers.
+  LLVM_ABI void addLiveOuts(const MachineBasicBlock &MBB);
 
   /// Adds registers living into block \p MBB.
   LLVM_ABI void addLiveIns(const MachineBasicBlock &MBB);
diff --git a/llvm/include/llvm/CodeGen/MachineBasicBlock.h b/llvm/include/llvm/CodeGen/MachineBasicBlock.h
index 9e3d9196cc184..94139b64a3e30 100644
--- a/llvm/include/llvm/CodeGen/MachineBasicBlock.h
+++ b/llvm/include/llvm/CodeGen/MachineBasicBlock.h
@@ -553,8 +553,8 @@ class MachineBasicBlock
         LiveRegI = (*BlockI)->livein_begin();
         if (!advanceToValidPosition())
           return;
-        if (LiveRegI->PhysReg == ExceptionPointer ||
-            LiveRegI->PhysReg == ExceptionSelector)
+        if ((*BlockI)->isEHPad() && (LiveRegI->PhysReg == ExceptionPointer ||
+                                     LiveRegI->PhysReg == ExceptionSelector))
           ++(*this);
       }
     }
diff --git a/llvm/lib/CodeGen/LiveRegUnits.cpp b/llvm/lib/CodeGen/LiveRegUnits.cpp
index c034d5f3925fc..21c11ce795e6c 100644
--- a/llvm/lib/CodeGen/LiveRegUnits.cpp
+++ b/llvm/lib/CodeGen/LiveRegUnits.cpp
@@ -87,15 +87,16 @@ void LiveRegUnits::accumulate(const MachineInstr &MI) {
 
 /// Add live-in registers of basic block \p MBB to \p LiveUnits.
 static void addBlockLiveIns(LiveRegUnits &LiveUnits,
-                            const MachineBasicBlock &MBB,
-                            MCPhysReg ExceptionPointer = {},
-                            MCPhysReg ExceptionSelector = {}) {
-  for (const auto &LI : MBB.liveins()) {
-    if (MBB.isEHPad() &&
-        (LI.PhysReg == ExceptionPointer || LI.PhysReg == ExceptionSelector))
-      continue;
+                            const MachineBasicBlock &MBB) {
+  for (const auto &LI : MBB.liveins())
+    LiveUnits.addRegMasked(LI.PhysReg, LI.LaneMask);
+}
+
+/// Add live-out registers of basic block \p MBB to \p LiveUnits.
+static void addBlockLiveOuts(LiveRegUnits &LiveUnits,
+                             const MachineBasicBlock &MBB) {
+  for (const auto &LI : MBB.liveouts())
     LiveUnits.addRegMasked(LI.PhysReg, LI.LaneMask);
-  }
 }
 
 /// Adds all callee saved registers to \p LiveUnits.
@@ -142,25 +143,10 @@ void LiveRegUnits::addPristines(const MachineFunction &MF) {
   addUnits(Pristine.getBitVector());
 }
 
-void LiveRegUnits::addLiveOuts(const MachineBasicBlock &MBB,
-                               const TargetLowering *TLI) {
+void LiveRegUnits::addLiveOuts(const MachineBasicBlock &MBB) {
   const MachineFunction &MF = *MBB.getParent();
-
   addPristines(MF);
-
-  MCPhysReg ExceptionPointer;
-  MCPhysReg ExceptionSelector;
-
-  // Remove live-ins from successors that are defined by the runtime.
-  if (TLI && MF.getFunction().hasPersonalityFn()) {
-    auto PersonalityFn = MF.getFunction().getPersonalityFn();
-    ExceptionPointer = TLI->getExceptionPointerRegister(PersonalityFn);
-    ExceptionSelector = TLI->getExceptionSelectorRegister(PersonalityFn);
-  }
-
-  // To get the live-outs we simply merge the live-ins of all successors.
-  for (const MachineBasicBlock *Succ : MBB.successors())
-    addBlockLiveIns(*this, *Succ, ExceptionPointer, ExceptionSelector);
+  addBlockLiveOuts(*this, MBB);
 
   // For the return block: Add all callee saved registers.
   if (MBB.isReturnBlock()) {
diff --git a/llvm/lib/CodeGen/MachineBasicBlock.cpp b/llvm/lib/CodeGen/MachineBasicBlock.cpp
index c3c5a0f5102d7..08a51b9b0242a 100644
--- a/llvm/lib/CodeGen/MachineBasicBlock.cpp
+++ b/llvm/lib/CodeGen/MachineBasicBlock.cpp
@@ -1781,9 +1781,6 @@ MachineBasicBlock::livein_iterator MachineBasicBlock::livein_begin() const {
 
 MachineBasicBlock::liveout_iterator MachineBasicBlock::liveout_begin() const {
   const MachineFunction &MF = *getParent();
-  assert(MF.getProperties().hasTracksLiveness() &&
-         "Liveness information is accurate");
-
   const TargetLowering &TLI = *MF.getSubtarget().getTargetLowering();
   MCRegister ExceptionPointer, ExceptionSelector;
   if (MF.getFunction().hasPersonalityFn()) {
diff --git a/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp b/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp
index 2f00977e9a1cc..b58dfdf32e4ab 100644
--- a/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp
+++ b/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp
@@ -277,7 +277,7 @@ void MachineSMEABI::collectNeededZAStates(SMEAttrs SMEFnAttrs) {
     }
 
     LiveRegUnits LiveUnits(*TRI);
-    LiveUnits.addLiveOuts(MBB, Subtarget->getTargetLowering());
+    LiveUnits.addLiveOuts(MBB);
 
     auto GetPhysLiveRegs = [&] {
       LiveRegs PhysLiveRegs = LiveRegs::None;

>From d970c1098874dece8d9a18381ad54639463436ff Mon Sep 17 00:00:00 2001
From: Benjamin Maxwell <benjamin.maxwell at arm.com>
Date: Wed, 20 Aug 2025 10:18:47 +0000
Subject: [PATCH 3/3] Remove decl

---
 llvm/include/llvm/CodeGen/LiveRegUnits.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/include/llvm/CodeGen/LiveRegUnits.h b/llvm/include/llvm/CodeGen/LiveRegUnits.h
index cf0b3521754ef..37c31cc6f4ac5 100644
--- a/llvm/include/llvm/CodeGen/LiveRegUnits.h
+++ b/llvm/include/llvm/CodeGen/LiveRegUnits.h
@@ -26,7 +26,6 @@ namespace llvm {
 
 class MachineInstr;
 class MachineBasicBlock;
-class TargetLowering;
 
 /// A set of register units used to track register liveness.
 class LiveRegUnits {



More information about the llvm-commits mailing list